tc74.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * An hwmon driver for the Microchip TC74
  4. *
  5. * Copyright 2015 Maciej Szmigiero <mail@maciej.szmigiero.name>
  6. *
  7. * Based on ad7414.c:
  8. * Copyright 2006 Stefan Roese, DENX Software Engineering
  9. * Copyright 2008 Sean MacLennan, PIKA Technologies
  10. * Copyright 2008 Frank Edelhaeuser, Spansion Inc.
  11. */
  12. #include <linux/bitops.h>
  13. #include <linux/err.h>
  14. #include <linux/hwmon.h>
  15. #include <linux/hwmon-sysfs.h>
  16. #include <linux/i2c.h>
  17. #include <linux/jiffies.h>
  18. #include <linux/module.h>
  19. #include <linux/mutex.h>
  20. #include <linux/slab.h>
  21. #include <linux/sysfs.h>
  22. /* TC74 registers */
  23. #define TC74_REG_TEMP 0x00
  24. #define TC74_REG_CONFIG 0x01
  25. struct tc74_data {
  26. struct i2c_client *client;
  27. struct mutex lock; /* atomic read data updates */
  28. bool valid; /* validity of fields below */
  29. unsigned long next_update; /* In jiffies */
  30. s8 temp_input; /* Temp value in dC */
  31. };
  32. static int tc74_update_device(struct device *dev)
  33. {
  34. struct tc74_data *data = dev_get_drvdata(dev);
  35. struct i2c_client *client = data->client;
  36. int ret;
  37. ret = mutex_lock_interruptible(&data->lock);
  38. if (ret)
  39. return ret;
  40. if (time_after(jiffies, data->next_update) || !data->valid) {
  41. s32 value;
  42. value = i2c_smbus_read_byte_data(client, TC74_REG_CONFIG);
  43. if (value < 0) {
  44. dev_dbg(&client->dev, "TC74_REG_CONFIG read err %d\n",
  45. (int)value);
  46. ret = value;
  47. goto ret_unlock;
  48. }
  49. if (!(value & BIT(6))) {
  50. /* not ready yet */
  51. ret = -EAGAIN;
  52. goto ret_unlock;
  53. }
  54. value = i2c_smbus_read_byte_data(client, TC74_REG_TEMP);
  55. if (value < 0) {
  56. dev_dbg(&client->dev, "TC74_REG_TEMP read err %d\n",
  57. (int)value);
  58. ret = value;
  59. goto ret_unlock;
  60. }
  61. data->temp_input = value;
  62. data->next_update = jiffies + HZ / 4;
  63. data->valid = true;
  64. }
  65. ret_unlock:
  66. mutex_unlock(&data->lock);
  67. return ret;
  68. }
  69. static ssize_t temp_input_show(struct device *dev,
  70. struct device_attribute *attr, char *buf)
  71. {
  72. struct tc74_data *data = dev_get_drvdata(dev);
  73. int ret;
  74. ret = tc74_update_device(dev);
  75. if (ret)
  76. return ret;
  77. return sprintf(buf, "%d\n", data->temp_input * 1000);
  78. }
  79. static SENSOR_DEVICE_ATTR_RO(temp1_input, temp_input, 0);
  80. static struct attribute *tc74_attrs[] = {
  81. &sensor_dev_attr_temp1_input.dev_attr.attr,
  82. NULL
  83. };
  84. ATTRIBUTE_GROUPS(tc74);
  85. static int tc74_probe(struct i2c_client *client)
  86. {
  87. struct device *dev = &client->dev;
  88. struct tc74_data *data;
  89. struct device *hwmon_dev;
  90. s32 conf;
  91. if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
  92. return -EOPNOTSUPP;
  93. data = devm_kzalloc(dev, sizeof(struct tc74_data), GFP_KERNEL);
  94. if (!data)
  95. return -ENOMEM;
  96. data->client = client;
  97. mutex_init(&data->lock);
  98. /* Make sure the chip is powered up. */
  99. conf = i2c_smbus_read_byte_data(client, TC74_REG_CONFIG);
  100. if (conf < 0) {
  101. dev_err(dev, "unable to read config register\n");
  102. return conf;
  103. }
  104. if (conf & 0x3f) {
  105. dev_err(dev, "invalid config register value\n");
  106. return -ENODEV;
  107. }
  108. if (conf & BIT(7)) {
  109. s32 ret;
  110. conf &= ~BIT(7);
  111. ret = i2c_smbus_write_byte_data(client, TC74_REG_CONFIG, conf);
  112. if (ret)
  113. dev_warn(dev, "unable to disable STANDBY\n");
  114. }
  115. hwmon_dev = devm_hwmon_device_register_with_groups(dev,
  116. client->name,
  117. data, tc74_groups);
  118. return PTR_ERR_OR_ZERO(hwmon_dev);
  119. }
  120. static const struct i2c_device_id tc74_id[] = {
  121. { "tc74", 0 },
  122. {}
  123. };
  124. MODULE_DEVICE_TABLE(i2c, tc74_id);
  125. static struct i2c_driver tc74_driver = {
  126. .driver = {
  127. .name = "tc74",
  128. },
  129. .probe_new = tc74_probe,
  130. .id_table = tc74_id,
  131. };
  132. module_i2c_driver(tc74_driver);
  133. MODULE_AUTHOR("Maciej Szmigiero <mail@maciej.szmigiero.name>");
  134. MODULE_DESCRIPTION("TC74 driver");
  135. MODULE_LICENSE("GPL");