diff options
author | John Muir <john@jmuir.com> | 2016-12-01 21:32:41 -0500 |
---|---|---|
committer | Guenter Roeck <linux@roeck-us.net> | 2016-12-10 00:54:25 -0500 |
commit | 66e1c91713396734f8cf778a2fc5212876c04bc0 (patch) | |
tree | bcc4661fa3206bb761cc5391f99d862505fabea3 | |
parent | 3a412d5e4a1c831723d0aaf305f1cf9a78ad9c90 (diff) |
hwmon: Add Texas Instruments TMP108 temperature sensor driver.
Add support for the TI TMP108 temperature sensor with some device
configuration parameters.
Signed-off-by: John Muir <john@jmuir.com>
[groeck: Initialize of_match_table]
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
-rw-r--r-- | Documentation/hwmon/tmp108 | 36 | ||||
-rw-r--r-- | drivers/hwmon/Kconfig | 11 | ||||
-rw-r--r-- | drivers/hwmon/Makefile | 1 | ||||
-rw-r--r-- | drivers/hwmon/tmp108.c | 469 |
4 files changed, 517 insertions, 0 deletions
diff --git a/Documentation/hwmon/tmp108 b/Documentation/hwmon/tmp108 new file mode 100644 index 000000000000..25802df23010 --- /dev/null +++ b/Documentation/hwmon/tmp108 | |||
@@ -0,0 +1,36 @@ | |||
1 | Kernel driver tmp108 | ||
2 | ==================== | ||
3 | |||
4 | Supported chips: | ||
5 | * Texas Instruments TMP108 | ||
6 | Prefix: 'tmp108' | ||
7 | Addresses scanned: none | ||
8 | Datasheet: http://www.ti.com/product/tmp108 | ||
9 | |||
10 | Author: | ||
11 | John Muir <john@jmuir.com> | ||
12 | |||
13 | Description | ||
14 | ----------- | ||
15 | |||
16 | The Texas Instruments TMP108 implements one temperature sensor. An alert pin | ||
17 | can be set when temperatures exceed minimum or maximum values plus or minus a | ||
18 | hysteresis value. (This driver does not support interrupts for the alert pin, | ||
19 | and the device runs in comparator mode.) | ||
20 | |||
21 | The sensor is accurate to 0.75C over the range of -25 to +85 C, and to 1.0 | ||
22 | degree from -40 to +125 C. Resolution of the sensor is 0.0625 degree. The | ||
23 | operating temperature has a minimum of -55 C and a maximum of +150 C. | ||
24 | Hysteresis values can be set to 0, 1, 2, or 4C. | ||
25 | |||
26 | The TMP108 has a programmable update rate that can select between 8, 4, 1, and | ||
27 | 0.5 Hz. | ||
28 | |||
29 | By default the TMP108 reads the temperature continuously. To conserve power, | ||
30 | the TMP108 has a one-shot mode where the device is normally shut-down. When a | ||
31 | one shot is requested the temperature is read, the result can be retrieved, | ||
32 | and then the device is shut down automatically. (This driver only supports | ||
33 | continuous mode.) | ||
34 | |||
35 | The driver provides the common sysfs-interface for temperatures (see | ||
36 | Documentation/hwmon/sysfs-interface under Temperatures). | ||
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 1adda8a5adce..190d270b20a2 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -1602,6 +1602,17 @@ config SENSORS_TMP103 | |||
1602 | This driver can also be built as a module. If so, the module | 1602 | This driver can also be built as a module. If so, the module |
1603 | will be called tmp103. | 1603 | will be called tmp103. |
1604 | 1604 | ||
1605 | config SENSORS_TMP108 | ||
1606 | tristate "Texas Instruments TMP108" | ||
1607 | depends on I2C | ||
1608 | select REGMAP_I2C | ||
1609 | help | ||
1610 | If you say yes here you get support for Texas Instruments TMP108 | ||
1611 | sensor chips. | ||
1612 | |||
1613 | This driver can also be built as a module. If so, the module | ||
1614 | will be called tmp108. | ||
1615 | |||
1605 | config SENSORS_TMP401 | 1616 | config SENSORS_TMP401 |
1606 | tristate "Texas Instruments TMP401 and compatibles" | 1617 | tristate "Texas Instruments TMP401 and compatibles" |
1607 | depends on I2C | 1618 | depends on I2C |
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index c651f0f1d047..d2cb7e804a0f 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile | |||
@@ -153,6 +153,7 @@ obj-$(CONFIG_SENSORS_TC74) += tc74.o | |||
153 | obj-$(CONFIG_SENSORS_THMC50) += thmc50.o | 153 | obj-$(CONFIG_SENSORS_THMC50) += thmc50.o |
154 | obj-$(CONFIG_SENSORS_TMP102) += tmp102.o | 154 | obj-$(CONFIG_SENSORS_TMP102) += tmp102.o |
155 | obj-$(CONFIG_SENSORS_TMP103) += tmp103.o | 155 | obj-$(CONFIG_SENSORS_TMP103) += tmp103.o |
156 | obj-$(CONFIG_SENSORS_TMP108) += tmp108.o | ||
156 | obj-$(CONFIG_SENSORS_TMP401) += tmp401.o | 157 | obj-$(CONFIG_SENSORS_TMP401) += tmp401.o |
157 | obj-$(CONFIG_SENSORS_TMP421) += tmp421.o | 158 | obj-$(CONFIG_SENSORS_TMP421) += tmp421.o |
158 | obj-$(CONFIG_SENSORS_TWL4030_MADC)+= twl4030-madc-hwmon.o | 159 | obj-$(CONFIG_SENSORS_TWL4030_MADC)+= twl4030-madc-hwmon.o |
diff --git a/drivers/hwmon/tmp108.c b/drivers/hwmon/tmp108.c new file mode 100644 index 000000000000..91bb94639286 --- /dev/null +++ b/drivers/hwmon/tmp108.c | |||
@@ -0,0 +1,469 @@ | |||
1 | /* Texas Instruments TMP108 SMBus temperature sensor driver | ||
2 | * | ||
3 | * Copyright (C) 2016 John Muir <john@jmuir.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 | |||
16 | #include <linux/delay.h> | ||
17 | #include <linux/device.h> | ||
18 | #include <linux/err.h> | ||
19 | #include <linux/hwmon.h> | ||
20 | #include <linux/hwmon-sysfs.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/mutex.h> | ||
23 | #include <linux/of.h> | ||
24 | #include <linux/i2c.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/jiffies.h> | ||
27 | #include <linux/regmap.h> | ||
28 | #include <linux/slab.h> | ||
29 | |||
30 | #define DRIVER_NAME "tmp108" | ||
31 | |||
32 | #define TMP108_REG_TEMP 0x00 | ||
33 | #define TMP108_REG_CONF 0x01 | ||
34 | #define TMP108_REG_TLOW 0x02 | ||
35 | #define TMP108_REG_THIGH 0x03 | ||
36 | |||
37 | #define TMP108_TEMP_MIN_MC -50000 /* Minimum millicelcius. */ | ||
38 | #define TMP108_TEMP_MAX_MC 127937 /* Maximum millicelcius. */ | ||
39 | |||
40 | /* Configuration register bits. | ||
41 | * Note: these bit definitions are byte swapped. | ||
42 | */ | ||
43 | #define TMP108_CONF_M0 0x0100 /* Sensor mode. */ | ||
44 | #define TMP108_CONF_M1 0x0200 | ||
45 | #define TMP108_CONF_TM 0x0400 /* Thermostat mode. */ | ||
46 | #define TMP108_CONF_FL 0x0800 /* Watchdog flag - TLOW */ | ||
47 | #define TMP108_CONF_FH 0x1000 /* Watchdog flag - THIGH */ | ||
48 | #define TMP108_CONF_CR0 0x2000 /* Conversion rate. */ | ||
49 | #define TMP108_CONF_CR1 0x4000 | ||
50 | #define TMP108_CONF_ID 0x8000 | ||
51 | #define TMP108_CONF_HYS0 0x0010 /* Hysteresis. */ | ||
52 | #define TMP108_CONF_HYS1 0x0020 | ||
53 | #define TMP108_CONF_POL 0x0080 /* Polarity of alert. */ | ||
54 | |||
55 | /* Defaults set by the hardware upon reset. */ | ||
56 | #define TMP108_CONF_DEFAULTS (TMP108_CONF_CR0 | TMP108_CONF_TM |\ | ||
57 | TMP108_CONF_HYS0 | TMP108_CONF_M1) | ||
58 | /* These bits are read-only. */ | ||
59 | #define TMP108_CONF_READ_ONLY (TMP108_CONF_FL | TMP108_CONF_FH |\ | ||
60 | TMP108_CONF_ID) | ||
61 | |||
62 | #define TMP108_CONF_MODE_MASK (TMP108_CONF_M0|TMP108_CONF_M1) | ||
63 | #define TMP108_MODE_SHUTDOWN 0x0000 | ||
64 | #define TMP108_MODE_ONE_SHOT TMP108_CONF_M0 | ||
65 | #define TMP108_MODE_CONTINUOUS TMP108_CONF_M1 /* Default */ | ||
66 | /* When M1 is set, M0 is ignored. */ | ||
67 | |||
68 | #define TMP108_CONF_CONVRATE_MASK (TMP108_CONF_CR0|TMP108_CONF_CR1) | ||
69 | #define TMP108_CONVRATE_0P25HZ 0x0000 | ||
70 | #define TMP108_CONVRATE_1HZ TMP108_CONF_CR0 /* Default */ | ||
71 | #define TMP108_CONVRATE_4HZ TMP108_CONF_CR1 | ||
72 | #define TMP108_CONVRATE_16HZ (TMP108_CONF_CR0|TMP108_CONF_CR1) | ||
73 | |||
74 | #define TMP108_CONF_HYSTERESIS_MASK (TMP108_CONF_HYS0|TMP108_CONF_HYS1) | ||
75 | #define TMP108_HYSTERESIS_0C 0x0000 | ||
76 | #define TMP108_HYSTERESIS_1C TMP108_CONF_HYS0 /* Default */ | ||
77 | #define TMP108_HYSTERESIS_2C TMP108_CONF_HYS1 | ||
78 | #define TMP108_HYSTERESIS_4C (TMP108_CONF_HYS0|TMP108_CONF_HYS1) | ||
79 | |||
80 | #define TMP108_CONVERSION_TIME_MS 30 /* in milli-seconds */ | ||
81 | |||
82 | struct tmp108 { | ||
83 | struct regmap *regmap; | ||
84 | u16 orig_config; | ||
85 | unsigned long ready_time; | ||
86 | }; | ||
87 | |||
88 | /* convert 12-bit TMP108 register value to milliCelsius */ | ||
89 | static inline int tmp108_temp_reg_to_mC(s16 val) | ||
90 | { | ||
91 | return (val & ~0x0f) * 1000 / 256; | ||
92 | } | ||
93 | |||
94 | /* convert milliCelsius to left adjusted 12-bit TMP108 register value */ | ||
95 | static inline u16 tmp108_mC_to_temp_reg(int val) | ||
96 | { | ||
97 | return (val * 256) / 1000; | ||
98 | } | ||
99 | |||
100 | static int tmp108_read(struct device *dev, enum hwmon_sensor_types type, | ||
101 | u32 attr, int channel, long *temp) | ||
102 | { | ||
103 | struct tmp108 *tmp108 = dev_get_drvdata(dev); | ||
104 | unsigned int regval; | ||
105 | int err, hyst; | ||
106 | |||
107 | if (type == hwmon_chip) { | ||
108 | if (attr == hwmon_chip_update_interval) { | ||
109 | err = regmap_read(tmp108->regmap, TMP108_REG_CONF, | ||
110 | ®val); | ||
111 | if (err < 0) | ||
112 | return err; | ||
113 | switch (regval & TMP108_CONF_CONVRATE_MASK) { | ||
114 | case TMP108_CONVRATE_0P25HZ: | ||
115 | default: | ||
116 | *temp = 4000; | ||
117 | break; | ||
118 | case TMP108_CONVRATE_1HZ: | ||
119 | *temp = 1000; | ||
120 | break; | ||
121 | case TMP108_CONVRATE_4HZ: | ||
122 | *temp = 250; | ||
123 | break; | ||
124 | case TMP108_CONVRATE_16HZ: | ||
125 | *temp = 63; | ||
126 | break; | ||
127 | } | ||
128 | return 0; | ||
129 | } | ||
130 | return -EOPNOTSUPP; | ||
131 | } | ||
132 | |||
133 | switch (attr) { | ||
134 | case hwmon_temp_input: | ||
135 | /* Is it too early to return a conversion ? */ | ||
136 | if (time_before(jiffies, tmp108->ready_time)) { | ||
137 | dev_dbg(dev, "%s: Conversion not ready yet..\n", | ||
138 | __func__); | ||
139 | return -EAGAIN; | ||
140 | } | ||
141 | err = regmap_read(tmp108->regmap, TMP108_REG_TEMP, ®val); | ||
142 | if (err < 0) | ||
143 | return err; | ||
144 | *temp = tmp108_temp_reg_to_mC(regval); | ||
145 | break; | ||
146 | case hwmon_temp_min: | ||
147 | case hwmon_temp_max: | ||
148 | err = regmap_read(tmp108->regmap, attr == hwmon_temp_min ? | ||
149 | TMP108_REG_TLOW : TMP108_REG_THIGH, ®val); | ||
150 | if (err < 0) | ||
151 | return err; | ||
152 | *temp = tmp108_temp_reg_to_mC(regval); | ||
153 | break; | ||
154 | case hwmon_temp_min_alarm: | ||
155 | case hwmon_temp_max_alarm: | ||
156 | err = regmap_read(tmp108->regmap, TMP108_REG_CONF, ®val); | ||
157 | if (err < 0) | ||
158 | return err; | ||
159 | *temp = !!(regval & (attr == hwmon_temp_min_alarm ? | ||
160 | TMP108_CONF_FL : TMP108_CONF_FH)); | ||
161 | break; | ||
162 | case hwmon_temp_min_hyst: | ||
163 | case hwmon_temp_max_hyst: | ||
164 | err = regmap_read(tmp108->regmap, TMP108_REG_CONF, ®val); | ||
165 | if (err < 0) | ||
166 | return err; | ||
167 | switch (regval & TMP108_CONF_HYSTERESIS_MASK) { | ||
168 | case TMP108_HYSTERESIS_0C: | ||
169 | default: | ||
170 | hyst = 0; | ||
171 | break; | ||
172 | case TMP108_HYSTERESIS_1C: | ||
173 | hyst = 1000; | ||
174 | break; | ||
175 | case TMP108_HYSTERESIS_2C: | ||
176 | hyst = 2000; | ||
177 | break; | ||
178 | case TMP108_HYSTERESIS_4C: | ||
179 | hyst = 4000; | ||
180 | break; | ||
181 | } | ||
182 | err = regmap_read(tmp108->regmap, attr == hwmon_temp_min_hyst ? | ||
183 | TMP108_REG_TLOW : TMP108_REG_THIGH, ®val); | ||
184 | if (err < 0) | ||
185 | return err; | ||
186 | *temp = tmp108_temp_reg_to_mC(regval); | ||
187 | if (attr == hwmon_temp_min_hyst) | ||
188 | *temp += hyst; | ||
189 | else | ||
190 | *temp -= hyst; | ||
191 | break; | ||
192 | default: | ||
193 | return -EOPNOTSUPP; | ||
194 | } | ||
195 | |||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | static int tmp108_write(struct device *dev, enum hwmon_sensor_types type, | ||
200 | u32 attr, int channel, long temp) | ||
201 | { | ||
202 | struct tmp108 *tmp108 = dev_get_drvdata(dev); | ||
203 | u32 regval, mask; | ||
204 | int err; | ||
205 | |||
206 | if (type == hwmon_chip) { | ||
207 | if (attr == hwmon_chip_update_interval) { | ||
208 | if (temp < 156) | ||
209 | mask = TMP108_CONVRATE_16HZ; | ||
210 | else if (temp < 625) | ||
211 | mask = TMP108_CONVRATE_4HZ; | ||
212 | else if (temp < 2500) | ||
213 | mask = TMP108_CONVRATE_1HZ; | ||
214 | else | ||
215 | mask = TMP108_CONVRATE_0P25HZ; | ||
216 | return regmap_update_bits(tmp108->regmap, | ||
217 | TMP108_REG_CONF, | ||
218 | TMP108_CONF_CONVRATE_MASK, | ||
219 | mask); | ||
220 | } | ||
221 | return -EOPNOTSUPP; | ||
222 | } | ||
223 | |||
224 | switch (attr) { | ||
225 | case hwmon_temp_min: | ||
226 | case hwmon_temp_max: | ||
227 | temp = clamp_val(temp, TMP108_TEMP_MIN_MC, TMP108_TEMP_MAX_MC); | ||
228 | return regmap_write(tmp108->regmap, | ||
229 | attr == hwmon_temp_min ? | ||
230 | TMP108_REG_TLOW : TMP108_REG_THIGH, | ||
231 | tmp108_mC_to_temp_reg(temp)); | ||
232 | case hwmon_temp_min_hyst: | ||
233 | case hwmon_temp_max_hyst: | ||
234 | temp = clamp_val(temp, TMP108_TEMP_MIN_MC, TMP108_TEMP_MAX_MC); | ||
235 | err = regmap_read(tmp108->regmap, | ||
236 | attr == hwmon_temp_min_hyst ? | ||
237 | TMP108_REG_TLOW : TMP108_REG_THIGH, | ||
238 | ®val); | ||
239 | if (err < 0) | ||
240 | return err; | ||
241 | if (attr == hwmon_temp_min_hyst) | ||
242 | temp -= tmp108_temp_reg_to_mC(regval); | ||
243 | else | ||
244 | temp = tmp108_temp_reg_to_mC(regval) - temp; | ||
245 | if (temp < 500) | ||
246 | mask = TMP108_HYSTERESIS_0C; | ||
247 | else if (temp < 1500) | ||
248 | mask = TMP108_HYSTERESIS_1C; | ||
249 | else if (temp < 3000) | ||
250 | mask = TMP108_HYSTERESIS_2C; | ||
251 | else | ||
252 | mask = TMP108_HYSTERESIS_4C; | ||
253 | return regmap_update_bits(tmp108->regmap, TMP108_REG_CONF, | ||
254 | TMP108_CONF_HYSTERESIS_MASK, mask); | ||
255 | default: | ||
256 | return -EOPNOTSUPP; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | static umode_t tmp108_is_visible(const void *data, enum hwmon_sensor_types type, | ||
261 | u32 attr, int channel) | ||
262 | { | ||
263 | if (type == hwmon_chip && attr == hwmon_chip_update_interval) | ||
264 | return 0644; | ||
265 | |||
266 | if (type != hwmon_temp) | ||
267 | return 0; | ||
268 | |||
269 | switch (attr) { | ||
270 | case hwmon_temp_input: | ||
271 | case hwmon_temp_min_alarm: | ||
272 | case hwmon_temp_max_alarm: | ||
273 | return 0444; | ||
274 | case hwmon_temp_min: | ||
275 | case hwmon_temp_max: | ||
276 | case hwmon_temp_min_hyst: | ||
277 | case hwmon_temp_max_hyst: | ||
278 | return 0644; | ||
279 | default: | ||
280 | return 0; | ||
281 | } | ||
282 | } | ||
283 | |||
284 | static u32 tmp108_chip_config[] = { | ||
285 | HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL, | ||
286 | 0 | ||
287 | }; | ||
288 | |||
289 | static const struct hwmon_channel_info tmp108_chip = { | ||
290 | .type = hwmon_chip, | ||
291 | .config = tmp108_chip_config, | ||
292 | }; | ||
293 | |||
294 | static u32 tmp108_temp_config[] = { | ||
295 | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | HWMON_T_MIN_HYST | ||
296 | | HWMON_T_MAX_HYST | HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM, | ||
297 | 0 | ||
298 | }; | ||
299 | |||
300 | static const struct hwmon_channel_info tmp108_temp = { | ||
301 | .type = hwmon_temp, | ||
302 | .config = tmp108_temp_config, | ||
303 | }; | ||
304 | |||
305 | static const struct hwmon_channel_info *tmp108_info[] = { | ||
306 | &tmp108_chip, | ||
307 | &tmp108_temp, | ||
308 | NULL | ||
309 | }; | ||
310 | |||
311 | static const struct hwmon_ops tmp108_hwmon_ops = { | ||
312 | .is_visible = tmp108_is_visible, | ||
313 | .read = tmp108_read, | ||
314 | .write = tmp108_write, | ||
315 | }; | ||
316 | |||
317 | static const struct hwmon_chip_info tmp108_chip_info = { | ||
318 | .ops = &tmp108_hwmon_ops, | ||
319 | .info = tmp108_info, | ||
320 | }; | ||
321 | |||
322 | static void tmp108_restore_config(void *data) | ||
323 | { | ||
324 | struct tmp108 *tmp108 = data; | ||
325 | |||
326 | regmap_write(tmp108->regmap, TMP108_REG_CONF, tmp108->orig_config); | ||
327 | } | ||
328 | |||
329 | static bool tmp108_is_writeable_reg(struct device *dev, unsigned int reg) | ||
330 | { | ||
331 | return reg != TMP108_REG_TEMP; | ||
332 | } | ||
333 | |||
334 | static bool tmp108_is_volatile_reg(struct device *dev, unsigned int reg) | ||
335 | { | ||
336 | /* Configuration register must be volatile to enable FL and FH. */ | ||
337 | return reg == TMP108_REG_TEMP || reg == TMP108_REG_CONF; | ||
338 | } | ||
339 | |||
340 | static const struct regmap_config tmp108_regmap_config = { | ||
341 | .reg_bits = 8, | ||
342 | .val_bits = 16, | ||
343 | .max_register = TMP108_REG_THIGH, | ||
344 | .writeable_reg = tmp108_is_writeable_reg, | ||
345 | .volatile_reg = tmp108_is_volatile_reg, | ||
346 | .val_format_endian = REGMAP_ENDIAN_BIG, | ||
347 | .cache_type = REGCACHE_RBTREE, | ||
348 | .use_single_rw = true, | ||
349 | }; | ||
350 | |||
351 | static int tmp108_probe(struct i2c_client *client, | ||
352 | const struct i2c_device_id *id) | ||
353 | { | ||
354 | struct device *dev = &client->dev; | ||
355 | struct device *hwmon_dev; | ||
356 | struct tmp108 *tmp108; | ||
357 | int err; | ||
358 | u32 config; | ||
359 | |||
360 | if (!i2c_check_functionality(client->adapter, | ||
361 | I2C_FUNC_SMBUS_WORD_DATA)) { | ||
362 | dev_err(dev, | ||
363 | "adapter doesn't support SMBus word transactions\n"); | ||
364 | return -ENODEV; | ||
365 | } | ||
366 | |||
367 | tmp108 = devm_kzalloc(dev, sizeof(*tmp108), GFP_KERNEL); | ||
368 | if (!tmp108) | ||
369 | return -ENOMEM; | ||
370 | |||
371 | dev_set_drvdata(dev, tmp108); | ||
372 | |||
373 | tmp108->regmap = devm_regmap_init_i2c(client, &tmp108_regmap_config); | ||
374 | if (IS_ERR(tmp108->regmap)) { | ||
375 | err = PTR_ERR(tmp108->regmap); | ||
376 | dev_err(dev, "regmap init failed: %d", err); | ||
377 | return err; | ||
378 | } | ||
379 | |||
380 | err = regmap_read(tmp108->regmap, TMP108_REG_CONF, &config); | ||
381 | if (err < 0) { | ||
382 | dev_err(dev, "error reading config register: %d", err); | ||
383 | return err; | ||
384 | } | ||
385 | tmp108->orig_config = config; | ||
386 | |||
387 | /* Only continuous mode is supported. */ | ||
388 | config &= ~TMP108_CONF_MODE_MASK; | ||
389 | config |= TMP108_MODE_CONTINUOUS; | ||
390 | |||
391 | /* Only comparator mode is supported. */ | ||
392 | config &= ~TMP108_CONF_TM; | ||
393 | |||
394 | err = regmap_write(tmp108->regmap, TMP108_REG_CONF, config); | ||
395 | if (err < 0) { | ||
396 | dev_err(dev, "error writing config register: %d", err); | ||
397 | return err; | ||
398 | } | ||
399 | |||
400 | tmp108->ready_time = jiffies; | ||
401 | if ((tmp108->orig_config & TMP108_CONF_MODE_MASK) == | ||
402 | TMP108_MODE_SHUTDOWN) | ||
403 | tmp108->ready_time += | ||
404 | msecs_to_jiffies(TMP108_CONVERSION_TIME_MS); | ||
405 | |||
406 | err = devm_add_action_or_reset(dev, tmp108_restore_config, tmp108); | ||
407 | if (err) { | ||
408 | dev_err(dev, "add action or reset failed: %d", err); | ||
409 | return err; | ||
410 | } | ||
411 | |||
412 | hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, | ||
413 | tmp108, | ||
414 | &tmp108_chip_info, | ||
415 | NULL); | ||
416 | return PTR_ERR_OR_ZERO(hwmon_dev); | ||
417 | } | ||
418 | |||
419 | static int __maybe_unused tmp108_suspend(struct device *dev) | ||
420 | { | ||
421 | struct tmp108 *tmp108 = dev_get_drvdata(dev); | ||
422 | |||
423 | return regmap_update_bits(tmp108->regmap, TMP108_REG_CONF, | ||
424 | TMP108_CONF_MODE_MASK, TMP108_MODE_SHUTDOWN); | ||
425 | } | ||
426 | |||
427 | static int __maybe_unused tmp108_resume(struct device *dev) | ||
428 | { | ||
429 | struct tmp108 *tmp108 = dev_get_drvdata(dev); | ||
430 | int err; | ||
431 | |||
432 | err = regmap_update_bits(tmp108->regmap, TMP108_REG_CONF, | ||
433 | TMP108_CONF_MODE_MASK, TMP108_MODE_CONTINUOUS); | ||
434 | tmp108->ready_time = jiffies + | ||
435 | msecs_to_jiffies(TMP108_CONVERSION_TIME_MS); | ||
436 | return err; | ||
437 | } | ||
438 | |||
439 | static SIMPLE_DEV_PM_OPS(tmp108_dev_pm_ops, tmp108_suspend, tmp108_resume); | ||
440 | |||
441 | static const struct i2c_device_id tmp108_i2c_ids[] = { | ||
442 | { "tmp108", 0 }, | ||
443 | { } | ||
444 | }; | ||
445 | MODULE_DEVICE_TABLE(i2c, tmp108_i2c_ids); | ||
446 | |||
447 | #ifdef CONFIG_OF | ||
448 | static const struct of_device_id tmp108_of_ids[] = { | ||
449 | { .compatible = "ti,tmp108", }, | ||
450 | {} | ||
451 | }; | ||
452 | MODULE_DEVICE_TABLE(of, tmp108_of_ids); | ||
453 | #endif | ||
454 | |||
455 | static struct i2c_driver tmp108_driver = { | ||
456 | .driver = { | ||
457 | .name = DRIVER_NAME, | ||
458 | .pm = &tmp108_dev_pm_ops, | ||
459 | .of_match_table = of_match_ptr(tmp108_of_ids), | ||
460 | }, | ||
461 | .probe = tmp108_probe, | ||
462 | .id_table = tmp108_i2c_ids, | ||
463 | }; | ||
464 | |||
465 | module_i2c_driver(tmp108_driver); | ||
466 | |||
467 | MODULE_AUTHOR("John Muir <john@jmuir.com>"); | ||
468 | MODULE_DESCRIPTION("Texas Instruments TMP108 temperature sensor driver"); | ||
469 | MODULE_LICENSE("GPL"); | ||