aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/hwmon/tmp10227
-rw-r--r--drivers/hwmon/Kconfig10
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/tmp102.c297
4 files changed, 335 insertions, 0 deletions
diff --git a/Documentation/hwmon/tmp102 b/Documentation/hwmon/tmp102
new file mode 100644
index 000000000000..239dded8539f
--- /dev/null
+++ b/Documentation/hwmon/tmp102
@@ -0,0 +1,27 @@
1Kernel driver tmp102
2====================
3
4Supported chips:
5 * Texas Instruments TMP102
6 Prefix: 'tmp102'
7 Addresses scanned: I2C 0x48 0x49 0x4a 0x4b
8 Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp102.html
9
10Author:
11 Steven King <sfking@fdwdc.com>
12
13Description
14-----------
15
16The Texas Instruments TMP102 implements one temperature sensor. Limits can be
17set through the Overtemperature Shutdown register and Hysteresis register. The
18sensor is accurate to 0.5 degrees over the range of -25 to +85 C, and to 1.0
19degrees from -40 to +125 C. Resolution of the sensor is 0.0625 degree. The
20operating temperature has a minimum of -55 C and a maximum of +150 C.
21
22The TMP102 has a programmable update rate that can select between 8, 4, 1, and
230.5 Hz. (Currently the driver only supports the default of 4 Hz).
24
25The driver provides the common sysfs-interface for temperatures (see
26/Documentation/hwmon/sysfs-interface under Temperatures).
27
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 6dddad81281e..6d87892a6639 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -842,6 +842,16 @@ config SENSORS_THMC50
842 This driver can also be built as a module. If so, the module 842 This driver can also be built as a module. If so, the module
843 will be called thmc50. 843 will be called thmc50.
844 844
845config SENSORS_TMP102
846 tristate "Texas Instruments TMP102 and compatibles"
847 depends on I2C && EXPERIMENTAL
848 help
849 If you say yes here you get support for Texas Instruments TMP102
850 sensor chips.
851
852 This driver can also be built as a module. If so, the module
853 will be called tmp102.
854
845config SENSORS_TMP401 855config SENSORS_TMP401
846 tristate "Texas Instruments TMP401 and compatibles" 856 tristate "Texas Instruments TMP401 and compatibles"
847 depends on I2C && EXPERIMENTAL 857 depends on I2C && EXPERIMENTAL
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 9b1364a4bd85..2138ceb1a713 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -91,6 +91,7 @@ obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
91obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o 91obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
92obj-$(CONFIG_SENSORS_AMC6821) += amc6821.o 92obj-$(CONFIG_SENSORS_AMC6821) += amc6821.o
93obj-$(CONFIG_SENSORS_THMC50) += thmc50.o 93obj-$(CONFIG_SENSORS_THMC50) += thmc50.o
94obj-$(CONFIG_SENSORS_TMP102) += tmp102.o
94obj-$(CONFIG_SENSORS_TMP401) += tmp401.o 95obj-$(CONFIG_SENSORS_TMP401) += tmp401.o
95obj-$(CONFIG_SENSORS_TMP421) += tmp421.o 96obj-$(CONFIG_SENSORS_TMP421) += tmp421.o
96obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o 97obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o
diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c
new file mode 100644
index 000000000000..e4def62c0ebf
--- /dev/null
+++ b/drivers/hwmon/tmp102.c
@@ -0,0 +1,297 @@
1/* Texas Instruments TMP102 SMBUS temperature sensor driver
2 *
3 * Copyright 2010 Steven King <sfking@fdwdc.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20
21
22#include <linux/module.h>
23#include <linux/init.h>
24#include <linux/slab.h>
25#include <linux/i2c.h>
26#include <linux/hwmon.h>
27#include <linux/hwmon-sysfs.h>
28#include <linux/err.h>
29#include <linux/mutex.h>
30#include <linux/delay.h>
31
32#define DRIVER_NAME "tmp102"
33
34#define TMP102_TEMP_REG 0x00
35#define TMP102_CONF_REG 0x01
36/* note: these bit definitions are byte swapped */
37#define TMP102_CONF_SD 0x0100
38#define TMP102_CONF_TM 0x0200
39#define TMP102_CONF_POL 0x0400
40#define TMP102_CONF_F0 0x0800
41#define TMP102_CONF_F1 0x1000
42#define TMP102_CONF_R0 0x2000
43#define TMP102_CONF_R1 0x4000
44#define TMP102_CONF_OS 0x8000
45#define TMP102_CONF_EM 0x0010
46#define TMP102_CONF_AL 0x0020
47#define TMP102_CONF_CR0 0x0040
48#define TMP102_CONF_CR1 0x0080
49#define TMP102_TLOW_REG 0x02
50#define TMP102_THIGH_REG 0x03
51
52struct tmp102 {
53 struct device *hwmon_dev;
54 struct mutex lock;
55 unsigned long last_update;
56 int temp[3];
57};
58
59/* the TMP102 registers are big endian so we have to swab16 the values */
60static int tmp102_read_reg(struct i2c_client *client, u8 reg)
61{
62 int result = i2c_smbus_read_word_data(client, reg);
63 return result < 0 ? result : swab16(result);
64}
65
66static int tmp102_write_reg(struct i2c_client *client, u8 reg, u16 val)
67{
68 return i2c_smbus_write_word_data(client, reg, swab16(val));
69}
70
71/* convert left adjusted 13bit TMP102 register value to miliCelsius */
72static int tmp102_reg_to_mC(s16 val)
73{
74 return (val * 1000) / 128;
75}
76
77/* convert miliCelsius to left adjusted 13bit TMP102 register value */
78static u16 tmp102_mC_to_reg(int val)
79{
80 return (val * 128) / 1000;
81}
82
83static const u8 tmp102_reg[] = {
84 TMP102_TEMP_REG,
85 TMP102_TLOW_REG,
86 TMP102_THIGH_REG,
87};
88
89static struct tmp102 *tmp102_update_device(struct i2c_client *client)
90{
91 struct tmp102 *tmp102 = i2c_get_clientdata(client);
92
93 mutex_lock(&tmp102->lock);
94 if (time_after(jiffies, tmp102->last_update + HZ / 4)) {
95 int i;
96 for (i = 0; i < ARRAY_SIZE(tmp102->temp); ++i) {
97 int status = tmp102_read_reg(client, tmp102_reg[i]);
98 if (status > -1)
99 tmp102->temp[i] = tmp102_reg_to_mC(status);
100 }
101 tmp102->last_update = jiffies;
102 }
103 mutex_unlock(&tmp102->lock);
104 return tmp102;
105}
106
107static ssize_t tmp102_show_temp(struct device *dev,
108 struct device_attribute *attr,
109 char *buf)
110{
111 struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
112 struct tmp102 *tmp102 = tmp102_update_device(to_i2c_client(dev));
113
114 return sprintf(buf, "%d\n", tmp102->temp[sda->index]);
115}
116
117static ssize_t tmp102_set_temp(struct device *dev,
118 struct device_attribute *attr,
119 const char *buf, size_t count)
120{
121 struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
122 struct i2c_client *client = to_i2c_client(dev);
123 struct tmp102 *tmp102 = i2c_get_clientdata(client);
124 long val;
125 int status = 0;
126
127 if ((strict_strtol(buf, 10, &val) < 0) || (abs(val) > 150000))
128 return -EINVAL;
129 mutex_lock(&tmp102->lock);
130 if (tmp102->temp[sda->index] != val) {
131 tmp102->temp[sda->index] = val;
132 status = tmp102_write_reg(client, tmp102_reg[sda->index],
133 tmp102_mC_to_reg(val));
134 }
135 mutex_unlock(&tmp102->lock);
136 return status ? : count;
137}
138
139static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, tmp102_show_temp, NULL , 0);
140
141static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, tmp102_show_temp,
142 tmp102_set_temp, 1);
143
144static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, tmp102_show_temp,
145 tmp102_set_temp, 2);
146
147static struct attribute *tmp102_attributes[] = {
148 &sensor_dev_attr_temp1_input.dev_attr.attr,
149 &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
150 &sensor_dev_attr_temp1_max.dev_attr.attr,
151 NULL
152};
153
154static const struct attribute_group tmp102_attr_group = {
155 .attrs = tmp102_attributes,
156};
157
158#define TMP102_CONFIG (TMP102_CONF_TM | TMP102_CONF_EM | TMP102_CONF_CR1)
159#define TMP102_CONFIG_RD_ONLY (TMP102_CONF_R0 | TMP102_CONF_R1 | TMP102_CONF_AL)
160
161static int __devinit tmp102_probe(struct i2c_client *client,
162 const struct i2c_device_id *id)
163{
164 struct tmp102 *tmp102;
165 int status;
166
167 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
168 I2C_FUNC_SMBUS_WORD_DATA)) {
169 dev_dbg(&client->dev, "adapter doesnt support SMBUS\n");
170 return -ENODEV;
171 }
172
173 tmp102 = kzalloc(sizeof(*tmp102), GFP_KERNEL);
174 if (!tmp102) {
175 dev_dbg(&client->dev, "kzalloc failed\n");
176 return -ENOMEM;
177 }
178 i2c_set_clientdata(client, tmp102);
179
180 tmp102_write_reg(client, TMP102_CONF_REG, TMP102_CONFIG);
181 status = tmp102_read_reg(client, TMP102_CONF_REG);
182 if (status < 0) {
183 dev_dbg(&client->dev, "error reading config register\n");
184 goto fail0;
185 }
186 status &= ~TMP102_CONFIG_RD_ONLY;
187 if (status != TMP102_CONFIG) {
188 dev_dbg(&client->dev, "could not verify config settings\n");
189 status = -EIO;
190 goto fail0;
191 }
192 tmp102->last_update = jiffies - HZ;
193 mutex_init(&tmp102->lock);
194
195 status = sysfs_create_group(&client->dev.kobj, &tmp102_attr_group);
196 if (status) {
197 dev_dbg(&client->dev, "could not create sysfs files\n");
198 goto fail0;
199 }
200 tmp102->hwmon_dev = hwmon_device_register(&client->dev);
201 if (IS_ERR(tmp102->hwmon_dev)) {
202 dev_dbg(&client->dev, "unable to register hwmon device\n");
203 status = PTR_ERR(tmp102->hwmon_dev);
204 goto fail1;
205 }
206
207 dev_info(&client->dev, "initialized\n");
208
209 return 0;
210fail1:
211 sysfs_remove_group(&client->dev.kobj, &tmp102_attr_group);
212fail0:
213 i2c_set_clientdata(client, NULL);
214 kfree(tmp102);
215
216 return 0;
217}
218
219static int __devexit tmp102_remove(struct i2c_client *client)
220{
221 struct tmp102 *tmp102 = i2c_get_clientdata(client);
222
223 /* shutdown the chip */
224 tmp102_write_reg(client, TMP102_CONF_REG, TMP102_CONF_SD);
225
226 hwmon_device_unregister(tmp102->hwmon_dev);
227 sysfs_remove_group(&client->dev.kobj, &tmp102_attr_group);
228 i2c_set_clientdata(client, NULL);
229 kfree(tmp102);
230
231 return 0;
232}
233
234#ifdef CONFIG_PM
235static int tmp102_suspend(struct device *dev)
236{
237 struct i2c_client *client = to_i2c_client(dev);
238
239 tmp102_write_reg(client, TMP102_CONF_REG, TMP102_CONF_SD);
240
241 return 0;
242}
243
244static int tmp102_resume(struct device *dev)
245{
246 struct i2c_client *client = to_i2c_client(dev);
247
248 tmp102_write_reg(client, TMP102_CONF_REG, TMP102_CONFIG);
249
250 return 0;
251}
252
253static const struct dev_pm_ops tmp102_dev_pm_ops = {
254 .suspend = tmp102_suspend,
255 .resume = tmp102_resume,
256};
257
258#define TMP102_DEV_PM_OPS (&tmp102_dev_pm_ops)
259#else
260#define TMP102_DEV_PM_OPS NULL
261#endif /* CONFIG_PM */
262
263static const unsigned short normal_i2c[] = {
264 0x48, 0x49, 0x4a, 0x4b, I2C_CLIENT_END
265};
266
267static const struct i2c_device_id tmp102_id[] = {
268 { DRIVER_NAME, 0 },
269 { }
270};
271
272static struct i2c_driver tmp102_driver = {
273 .driver.name = DRIVER_NAME,
274 .driver.pm = TMP102_DEV_PM_OPS,
275 .class = I2C_CLASS_HWMON,
276 .probe = tmp102_probe,
277 .remove = __devexit_p(tmp102_remove),
278 .id_table = tmp102_id,
279 .address_list = normal_i2c,
280};
281
282static int __init tmp102_init(void)
283{
284 return i2c_add_driver(&tmp102_driver);
285}
286module_init(tmp102_init);
287
288static void __exit tmp102_exit(void)
289{
290 i2c_del_driver(&tmp102_driver);
291}
292module_exit(tmp102_exit);
293
294
295MODULE_AUTHOR("Steven King <sfking@fdwdc.com>");
296MODULE_DESCRIPTION("Texas Instruments TMP102 temperature sensor driver");
297MODULE_LICENSE("GPL");