aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaciej S. Szmigiero <mail@maciej.szmigiero.name>2015-06-21 09:54:44 -0400
committerGuenter Roeck <linux@roeck-us.net>2015-06-22 01:54:53 -0400
commit761c1770f2bf36a323ab97e2e1780db4f9b8a6fe (patch)
tree5fdfb189a1d4980916069a418015573ab736957b
parentf6725ae2f1ae266589ab177461e308bb2f86f9ee (diff)
hwmon: add driver for Microchip TC74
Add hwmon driver for the Microchip TC74. The TC74 is a single-input 8-bit I2C temperature sensor, with +-2 degrees centigrade accuracy. Signed-off-by: Maciej Szmigiero <mail@maciej.szmigiero.name> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
-rw-r--r--Documentation/hwmon/tc7420
-rw-r--r--drivers/hwmon/Kconfig10
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/tc74.c177
4 files changed, 208 insertions, 0 deletions
diff --git a/Documentation/hwmon/tc74 b/Documentation/hwmon/tc74
new file mode 100644
index 000000000000..43027aad5f8e
--- /dev/null
+++ b/Documentation/hwmon/tc74
@@ -0,0 +1,20 @@
1Kernel driver tc74
2====================
3
4Supported chips:
5 * Microchip TC74
6 Prefix: 'tc74'
7 Datasheet: Publicly available at Microchip website.
8
9Description
10-----------
11
12Driver supports the above part.
13
14The tc74 has an 8-bit sensor, with 1 degree centigrade resolution
15and +- 2 degrees centigrade accuracy.
16
17Notes
18-----
19
20Currently entering low power standby mode is not supported.
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 9c9d38b1e92e..54075a07d2a1 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1452,6 +1452,16 @@ config SENSORS_INA2XX
1452 This driver can also be built as a module. If so, the module 1452 This driver can also be built as a module. If so, the module
1453 will be called ina2xx. 1453 will be called ina2xx.
1454 1454
1455config SENSORS_TC74
1456 tristate "Microchip TC74"
1457 depends on I2C
1458 help
1459 If you say yes here you get support for Microchip TC74 single
1460 input temperature sensor chips.
1461
1462 This driver can also be built as a module. If so, the module
1463 will be called tc74.
1464
1455config SENSORS_THMC50 1465config SENSORS_THMC50
1456 tristate "Texas Instruments THMC50 / Analog Devices ADM1022" 1466 tristate "Texas Instruments THMC50 / Analog Devices ADM1022"
1457 depends on I2C 1467 depends on I2C
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index b4a40f17e2aa..ab904027f074 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -140,6 +140,7 @@ obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
140obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o 140obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
141obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o 141obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
142obj-$(CONFIG_SENSORS_AMC6821) += amc6821.o 142obj-$(CONFIG_SENSORS_AMC6821) += amc6821.o
143obj-$(CONFIG_SENSORS_TC74) += tc74.o
143obj-$(CONFIG_SENSORS_THMC50) += thmc50.o 144obj-$(CONFIG_SENSORS_THMC50) += thmc50.o
144obj-$(CONFIG_SENSORS_TMP102) += tmp102.o 145obj-$(CONFIG_SENSORS_TMP102) += tmp102.o
145obj-$(CONFIG_SENSORS_TMP103) += tmp103.o 146obj-$(CONFIG_SENSORS_TMP103) += tmp103.o
diff --git a/drivers/hwmon/tc74.c b/drivers/hwmon/tc74.c
new file mode 100644
index 000000000000..d95165158800
--- /dev/null
+++ b/drivers/hwmon/tc74.c
@@ -0,0 +1,177 @@
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
17#include <linux/bitops.h>
18#include <linux/err.h>
19#include <linux/hwmon.h>
20#include <linux/hwmon-sysfs.h>
21#include <linux/i2c.h>
22#include <linux/jiffies.h>
23#include <linux/module.h>
24#include <linux/mutex.h>
25#include <linux/slab.h>
26#include <linux/sysfs.h>
27
28/* TC74 registers */
29#define TC74_REG_TEMP 0x00
30#define TC74_REG_CONFIG 0x01
31
32struct tc74_data {
33 struct i2c_client *client;
34 struct mutex lock; /* atomic read data updates */
35 bool valid; /* validity of fields below */
36 unsigned long next_update; /* In jiffies */
37 s8 temp_input; /* Temp value in dC */
38};
39
40static int tc74_update_device(struct device *dev)
41{
42 struct tc74_data *data = dev_get_drvdata(dev);
43 struct i2c_client *client = data->client;
44 int ret;
45
46 ret = mutex_lock_interruptible(&data->lock);
47 if (ret)
48 return ret;
49
50 if (time_after(jiffies, data->next_update) || !data->valid) {
51 s32 value;
52
53 value = i2c_smbus_read_byte_data(client, TC74_REG_CONFIG);
54 if (value < 0) {
55 dev_dbg(&client->dev, "TC74_REG_CONFIG read err %d\n",
56 (int)value);
57
58 ret = value;
59 goto ret_unlock;
60 }
61
62 if (!(value & BIT(6))) {
63 /* not ready yet */
64
65 ret = -EAGAIN;
66 goto ret_unlock;
67 }
68
69 value = i2c_smbus_read_byte_data(client, TC74_REG_TEMP);
70 if (value < 0) {
71 dev_dbg(&client->dev, "TC74_REG_TEMP read err %d\n",
72 (int)value);
73
74 ret = value;
75 goto ret_unlock;
76 }
77
78 data->temp_input = value;
79 data->next_update = jiffies + HZ / 4;
80 data->valid = true;
81 }
82
83ret_unlock:
84 mutex_unlock(&data->lock);
85
86 return ret;
87}
88
89static ssize_t show_temp_input(struct device *dev,
90 struct device_attribute *attr, char *buf)
91{
92 struct tc74_data *data = dev_get_drvdata(dev);
93 int ret;
94
95 ret = tc74_update_device(dev);
96 if (ret)
97 return ret;
98
99 return sprintf(buf, "%d\n", data->temp_input * 1000);
100}
101static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL, 0);
102
103static struct attribute *tc74_attrs[] = {
104 &sensor_dev_attr_temp1_input.dev_attr.attr,
105 NULL
106};
107
108ATTRIBUTE_GROUPS(tc74);
109
110static int tc74_probe(struct i2c_client *client,
111 const struct i2c_device_id *dev_id)
112{
113 struct device *dev = &client->dev;
114 struct tc74_data *data;
115 struct device *hwmon_dev;
116 s32 conf;
117
118 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
119 return -EOPNOTSUPP;
120
121 data = devm_kzalloc(dev, sizeof(struct tc74_data), GFP_KERNEL);
122 if (!data)
123 return -ENOMEM;
124
125 data->client = client;
126 mutex_init(&data->lock);
127
128 /* Make sure the chip is powered up. */
129 conf = i2c_smbus_read_byte_data(client, TC74_REG_CONFIG);
130 if (conf < 0) {
131 dev_err(dev, "unable to read config register\n");
132
133 return conf;
134 }
135
136 if (conf & 0x3f) {
137 dev_err(dev, "invalid config register value\n");
138
139 return -ENODEV;
140 }
141
142 if (conf & BIT(7)) {
143 s32 ret;
144
145 conf &= ~BIT(7);
146
147 ret = i2c_smbus_write_byte_data(client, TC74_REG_CONFIG, conf);
148 if (ret)
149 dev_warn(dev, "unable to disable STANDBY\n");
150 }
151
152 hwmon_dev = devm_hwmon_device_register_with_groups(dev,
153 client->name,
154 data, tc74_groups);
155 return PTR_ERR_OR_ZERO(hwmon_dev);
156}
157
158static const struct i2c_device_id tc74_id[] = {
159 { "tc74", 0 },
160 {}
161};
162MODULE_DEVICE_TABLE(i2c, tc74_id);
163
164static struct i2c_driver tc74_driver = {
165 .driver = {
166 .name = "tc74",
167 },
168 .probe = tc74_probe,
169 .id_table = tc74_id,
170};
171
172module_i2c_driver(tc74_driver);
173
174MODULE_AUTHOR("Maciej Szmigiero <mail@maciej.szmigiero.name>");
175
176MODULE_DESCRIPTION("TC74 driver");
177MODULE_LICENSE("GPL");