tc74.c 3.9 KB

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