diff options
author | andrea.merello <andrea.merello@gmail.com> | 2017-02-02 02:44:03 -0500 |
---|---|---|
committer | Guenter Roeck <linux@roeck-us.net> | 2017-02-03 08:32:59 -0500 |
commit | 7f07ec0fa17ae6b4acf031d4c20a7da4f3fbc407 (patch) | |
tree | 08ba615f973301f7b34bcbf27fdc5069f557cedf | |
parent | 319fe159889a06b47a2621a1201c813502b7a842 (diff) |
hwmon: new driver for ST stts751 thermal sensor
This patch adds a HWMON driver for ST Microelectronics STTS751
temperature sensors.
Thanks-to: LABBE Corentin [for suggestions]
Thanks-to: Guenter Roeck [for suggestion and discussions]
Signed-off-by: Andrea Merello <andrea.merello@gmail.com>
Cc: LABBE Corentin <clabbe.montjoie@gmail.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
-rw-r--r-- | drivers/hwmon/Kconfig | 10 | ||||
-rw-r--r-- | drivers/hwmon/Makefile | 1 | ||||
-rw-r--r-- | drivers/hwmon/stts751.c | 834 |
3 files changed, 845 insertions, 0 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 190d270b20a2..0649d53f3d16 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -1459,6 +1459,16 @@ config SENSORS_SCH5636 | |||
1459 | This driver can also be built as a module. If so, the module | 1459 | This driver can also be built as a module. If so, the module |
1460 | will be called sch5636. | 1460 | will be called sch5636. |
1461 | 1461 | ||
1462 | config SENSORS_STTS751 | ||
1463 | tristate "ST Microelectronics STTS751" | ||
1464 | depends on I2C | ||
1465 | help | ||
1466 | If you say yes here you get support for STTS751 | ||
1467 | temperature sensor chips. | ||
1468 | |||
1469 | This driver can also be built as a module. If so, the module | ||
1470 | will be called stts751. | ||
1471 | |||
1462 | config SENSORS_SMM665 | 1472 | config SENSORS_SMM665 |
1463 | tristate "Summit Microelectronics SMM665" | 1473 | tristate "Summit Microelectronics SMM665" |
1464 | depends on I2C | 1474 | depends on I2C |
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index d2cb7e804a0f..5509edf6186a 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile | |||
@@ -148,6 +148,7 @@ obj-$(CONFIG_SENSORS_SMM665) += smm665.o | |||
148 | obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o | 148 | obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o |
149 | obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o | 149 | obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o |
150 | obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o | 150 | obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o |
151 | obj-$(CONFIG_SENSORS_STTS751) += stts751.o | ||
151 | obj-$(CONFIG_SENSORS_AMC6821) += amc6821.o | 152 | obj-$(CONFIG_SENSORS_AMC6821) += amc6821.o |
152 | obj-$(CONFIG_SENSORS_TC74) += tc74.o | 153 | obj-$(CONFIG_SENSORS_TC74) += tc74.o |
153 | obj-$(CONFIG_SENSORS_THMC50) += thmc50.o | 154 | obj-$(CONFIG_SENSORS_THMC50) += thmc50.o |
diff --git a/drivers/hwmon/stts751.c b/drivers/hwmon/stts751.c new file mode 100644 index 000000000000..55450680fb58 --- /dev/null +++ b/drivers/hwmon/stts751.c | |||
@@ -0,0 +1,834 @@ | |||
1 | /* | ||
2 | * STTS751 sensor driver | ||
3 | * | ||
4 | * Copyright (C) 2016-2017 Istituto Italiano di Tecnologia - RBCS - EDL | ||
5 | * Robotics, Brain and Cognitive Sciences department | ||
6 | * Electronic Design Laboratory | ||
7 | * | ||
8 | * Written by Andrea Merello <andrea.merello@gmail.com> | ||
9 | * | ||
10 | * Based on LM95241 driver and LM90 driver | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | */ | ||
22 | |||
23 | #include <linux/bitops.h> | ||
24 | #include <linux/err.h> | ||
25 | #include <linux/hwmon.h> | ||
26 | #include <linux/hwmon-sysfs.h> | ||
27 | #include <linux/i2c.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/jiffies.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <linux/mutex.h> | ||
33 | #include <linux/property.h> | ||
34 | #include <linux/slab.h> | ||
35 | #include <linux/sysfs.h> | ||
36 | #include <linux/util_macros.h> | ||
37 | |||
38 | #define DEVNAME "stts751" | ||
39 | |||
40 | static const unsigned short normal_i2c[] = { | ||
41 | 0x48, 0x49, 0x38, 0x39, /* STTS751-0 */ | ||
42 | 0x4A, 0x4B, 0x3A, 0x3B, /* STTS751-1 */ | ||
43 | I2C_CLIENT_END }; | ||
44 | |||
45 | #define STTS751_REG_TEMP_H 0x00 | ||
46 | #define STTS751_REG_STATUS 0x01 | ||
47 | #define STTS751_STATUS_TRIPT BIT(0) | ||
48 | #define STTS751_STATUS_TRIPL BIT(5) | ||
49 | #define STTS751_STATUS_TRIPH BIT(6) | ||
50 | #define STTS751_REG_TEMP_L 0x02 | ||
51 | #define STTS751_REG_CONF 0x03 | ||
52 | #define STTS751_CONF_RES_MASK 0x0C | ||
53 | #define STTS751_CONF_RES_SHIFT 2 | ||
54 | #define STTS751_CONF_EVENT_DIS BIT(7) | ||
55 | #define STTS751_CONF_STOP BIT(6) | ||
56 | #define STTS751_REG_RATE 0x04 | ||
57 | #define STTS751_REG_HLIM_H 0x05 | ||
58 | #define STTS751_REG_HLIM_L 0x06 | ||
59 | #define STTS751_REG_LLIM_H 0x07 | ||
60 | #define STTS751_REG_LLIM_L 0x08 | ||
61 | #define STTS751_REG_TLIM 0x20 | ||
62 | #define STTS751_REG_HYST 0x21 | ||
63 | #define STTS751_REG_SMBUS_TO 0x22 | ||
64 | |||
65 | #define STTS751_REG_PROD_ID 0xFD | ||
66 | #define STTS751_REG_MAN_ID 0xFE | ||
67 | #define STTS751_REG_REV_ID 0xFF | ||
68 | |||
69 | #define STTS751_0_PROD_ID 0x00 | ||
70 | #define STTS751_1_PROD_ID 0x01 | ||
71 | #define ST_MAN_ID 0x53 | ||
72 | |||
73 | /* | ||
74 | * Possible update intervals are (in mS): | ||
75 | * 16000, 8000, 4000, 2000, 1000, 500, 250, 125, 62.5, 31.25 | ||
76 | * However we are not going to complicate things too much and we stick to the | ||
77 | * approx value in mS. | ||
78 | */ | ||
79 | static const int stts751_intervals[] = { | ||
80 | 16000, 8000, 4000, 2000, 1000, 500, 250, 125, 63, 31 | ||
81 | }; | ||
82 | |||
83 | static const struct i2c_device_id stts751_id[] = { | ||
84 | { "stts751", 0 }, | ||
85 | { } | ||
86 | }; | ||
87 | |||
88 | struct stts751_priv { | ||
89 | struct device *dev; | ||
90 | struct i2c_client *client; | ||
91 | struct mutex access_lock; | ||
92 | u8 interval; | ||
93 | int res; | ||
94 | int event_max, event_min; | ||
95 | int therm; | ||
96 | int hyst; | ||
97 | bool smbus_timeout; | ||
98 | int temp; | ||
99 | unsigned long last_update, last_alert_update; | ||
100 | u8 config; | ||
101 | bool min_alert, max_alert, therm_trip; | ||
102 | bool data_valid, alert_valid; | ||
103 | bool notify_max, notify_min; | ||
104 | }; | ||
105 | |||
106 | /* | ||
107 | * These functions converts temperature from HW format to integer format and | ||
108 | * vice-vers. They are (mostly) taken from lm90 driver. Unit is in mC. | ||
109 | */ | ||
110 | static int stts751_to_deg(s16 hw_val) | ||
111 | { | ||
112 | return hw_val * 125 / 32; | ||
113 | } | ||
114 | |||
115 | static s32 stts751_to_hw(int val) | ||
116 | { | ||
117 | return DIV_ROUND_CLOSEST(val, 125) * 32; | ||
118 | } | ||
119 | |||
120 | static int stts751_adjust_resolution(struct stts751_priv *priv) | ||
121 | { | ||
122 | u8 res; | ||
123 | |||
124 | switch (priv->interval) { | ||
125 | case 9: | ||
126 | /* 10 bits */ | ||
127 | res = 0; | ||
128 | break; | ||
129 | case 8: | ||
130 | /* 11 bits */ | ||
131 | res = 1; | ||
132 | break; | ||
133 | default: | ||
134 | /* 12 bits */ | ||
135 | res = 3; | ||
136 | break; | ||
137 | } | ||
138 | |||
139 | if (priv->res == res) | ||
140 | return 0; | ||
141 | |||
142 | priv->config &= ~STTS751_CONF_RES_MASK; | ||
143 | priv->config |= res << STTS751_CONF_RES_SHIFT; | ||
144 | dev_dbg(&priv->client->dev, "setting res %d. config %x", | ||
145 | res, priv->config); | ||
146 | priv->res = res; | ||
147 | |||
148 | return i2c_smbus_write_byte_data(priv->client, | ||
149 | STTS751_REG_CONF, priv->config); | ||
150 | } | ||
151 | |||
152 | static int stts751_update_temp(struct stts751_priv *priv) | ||
153 | { | ||
154 | s32 integer1, integer2, frac; | ||
155 | |||
156 | /* | ||
157 | * There is a trick here, like in the lm90 driver. We have to read two | ||
158 | * registers to get the sensor temperature, but we have to beware a | ||
159 | * conversion could occur between the readings. We could use the | ||
160 | * one-shot conversion register, but we don't want to do this (disables | ||
161 | * hardware monitoring). So the solution used here is to read the high | ||
162 | * byte once, then the low byte, then the high byte again. If the new | ||
163 | * high byte matches the old one, then we have a valid reading. Else we | ||
164 | * have to read the low byte again, and now we believe we have a correct | ||
165 | * reading. | ||
166 | */ | ||
167 | integer1 = i2c_smbus_read_byte_data(priv->client, STTS751_REG_TEMP_H); | ||
168 | if (integer1 < 0) { | ||
169 | dev_dbg(&priv->client->dev, | ||
170 | "I2C read failed (temp H). ret: %x\n", integer1); | ||
171 | return integer1; | ||
172 | } | ||
173 | |||
174 | frac = i2c_smbus_read_byte_data(priv->client, STTS751_REG_TEMP_L); | ||
175 | if (frac < 0) { | ||
176 | dev_dbg(&priv->client->dev, | ||
177 | "I2C read failed (temp L). ret: %x\n", frac); | ||
178 | return frac; | ||
179 | } | ||
180 | |||
181 | integer2 = i2c_smbus_read_byte_data(priv->client, STTS751_REG_TEMP_H); | ||
182 | if (integer2 < 0) { | ||
183 | dev_dbg(&priv->client->dev, | ||
184 | "I2C 2nd read failed (temp H). ret: %x\n", integer2); | ||
185 | return integer2; | ||
186 | } | ||
187 | |||
188 | if (integer1 != integer2) { | ||
189 | frac = i2c_smbus_read_byte_data(priv->client, | ||
190 | STTS751_REG_TEMP_L); | ||
191 | if (frac < 0) { | ||
192 | dev_dbg(&priv->client->dev, | ||
193 | "I2C 2nd read failed (temp L). ret: %x\n", | ||
194 | frac); | ||
195 | return frac; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | priv->temp = stts751_to_deg((integer1 << 8) | frac); | ||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | static int stts751_set_temp_reg16(struct stts751_priv *priv, int temp, | ||
204 | u8 hreg, u8 lreg) | ||
205 | { | ||
206 | s32 hwval; | ||
207 | int ret; | ||
208 | |||
209 | hwval = stts751_to_hw(temp); | ||
210 | |||
211 | ret = i2c_smbus_write_byte_data(priv->client, hreg, hwval >> 8); | ||
212 | if (ret) | ||
213 | return ret; | ||
214 | |||
215 | return i2c_smbus_write_byte_data(priv->client, lreg, hwval & 0xff); | ||
216 | } | ||
217 | |||
218 | static int stts751_set_temp_reg8(struct stts751_priv *priv, int temp, u8 reg) | ||
219 | { | ||
220 | s32 hwval; | ||
221 | |||
222 | hwval = stts751_to_hw(temp); | ||
223 | return i2c_smbus_write_byte_data(priv->client, reg, hwval >> 8); | ||
224 | } | ||
225 | |||
226 | static int stts751_read_reg16(struct stts751_priv *priv, int *temp, | ||
227 | u8 hreg, u8 lreg) | ||
228 | { | ||
229 | int integer, frac; | ||
230 | |||
231 | integer = i2c_smbus_read_byte_data(priv->client, hreg); | ||
232 | if (integer < 0) | ||
233 | return integer; | ||
234 | |||
235 | frac = i2c_smbus_read_byte_data(priv->client, lreg); | ||
236 | if (frac < 0) | ||
237 | return frac; | ||
238 | |||
239 | *temp = stts751_to_deg((integer << 8) | frac); | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | static int stts751_read_reg8(struct stts751_priv *priv, int *temp, u8 reg) | ||
245 | { | ||
246 | int integer; | ||
247 | |||
248 | integer = i2c_smbus_read_byte_data(priv->client, reg); | ||
249 | if (integer < 0) | ||
250 | return integer; | ||
251 | |||
252 | *temp = stts751_to_deg(integer << 8); | ||
253 | |||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | /* | ||
258 | * Update alert flags without waiting for cache to expire. We detects alerts | ||
259 | * immediately for the sake of the alert handler; we still need to deal with | ||
260 | * caching to workaround the fact that alarm flags int the status register, | ||
261 | * despite what the datasheet claims, gets always cleared on read. | ||
262 | */ | ||
263 | static int stts751_update_alert(struct stts751_priv *priv) | ||
264 | { | ||
265 | int ret; | ||
266 | bool conv_done; | ||
267 | int cache_time = msecs_to_jiffies(stts751_intervals[priv->interval]); | ||
268 | |||
269 | /* | ||
270 | * Add another 10% because if we run faster than the HW conversion | ||
271 | * rate we will end up in reporting incorrectly alarms. | ||
272 | */ | ||
273 | cache_time += cache_time / 10; | ||
274 | |||
275 | ret = i2c_smbus_read_byte_data(priv->client, STTS751_REG_STATUS); | ||
276 | if (ret < 0) | ||
277 | return ret; | ||
278 | |||
279 | dev_dbg(&priv->client->dev, "status reg %x\n", ret); | ||
280 | conv_done = ret & (STTS751_STATUS_TRIPH | STTS751_STATUS_TRIPL); | ||
281 | /* | ||
282 | * Reset the cache if the cache time expired, or if we are sure | ||
283 | * we have valid data from a device conversion, or if we know | ||
284 | * our cache has been never written. | ||
285 | * | ||
286 | * Note that when the cache has been never written the point is | ||
287 | * to correctly initialize the timestamp, rather than clearing | ||
288 | * the cache values. | ||
289 | * | ||
290 | * Note that updating the cache timestamp when we get an alarm flag | ||
291 | * is required, otherwise we could incorrectly report alarms to be zero. | ||
292 | */ | ||
293 | if (time_after(jiffies, priv->last_alert_update + cache_time) || | ||
294 | conv_done || !priv->alert_valid) { | ||
295 | priv->max_alert = false; | ||
296 | priv->min_alert = false; | ||
297 | priv->alert_valid = true; | ||
298 | priv->last_alert_update = jiffies; | ||
299 | dev_dbg(&priv->client->dev, "invalidating alert cache\n"); | ||
300 | } | ||
301 | |||
302 | priv->max_alert |= !!(ret & STTS751_STATUS_TRIPH); | ||
303 | priv->min_alert |= !!(ret & STTS751_STATUS_TRIPL); | ||
304 | priv->therm_trip = !!(ret & STTS751_STATUS_TRIPT); | ||
305 | |||
306 | dev_dbg(&priv->client->dev, "max_alert: %d, min_alert: %d, therm_trip: %d\n", | ||
307 | priv->max_alert, priv->min_alert, priv->therm_trip); | ||
308 | |||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | static void stts751_alert(struct i2c_client *client, | ||
313 | enum i2c_alert_protocol type, unsigned int data) | ||
314 | { | ||
315 | int ret; | ||
316 | struct stts751_priv *priv = i2c_get_clientdata(client); | ||
317 | |||
318 | if (type != I2C_PROTOCOL_SMBUS_ALERT) | ||
319 | return; | ||
320 | |||
321 | dev_dbg(&client->dev, "alert!"); | ||
322 | |||
323 | mutex_lock(&priv->access_lock); | ||
324 | ret = stts751_update_alert(priv); | ||
325 | if (ret < 0) { | ||
326 | /* default to worst case */ | ||
327 | priv->max_alert = true; | ||
328 | priv->min_alert = true; | ||
329 | |||
330 | dev_warn(priv->dev, | ||
331 | "Alert received, but can't communicate to the device. Triggering all alarms!"); | ||
332 | } | ||
333 | |||
334 | if (priv->max_alert) { | ||
335 | if (priv->notify_max) | ||
336 | dev_notice(priv->dev, "got alert for HIGH temperature"); | ||
337 | priv->notify_max = false; | ||
338 | |||
339 | /* unblock alert poll */ | ||
340 | sysfs_notify(&priv->dev->kobj, NULL, "temp1_max_alarm"); | ||
341 | } | ||
342 | |||
343 | if (priv->min_alert) { | ||
344 | if (priv->notify_min) | ||
345 | dev_notice(priv->dev, "got alert for LOW temperature"); | ||
346 | priv->notify_min = false; | ||
347 | |||
348 | /* unblock alert poll */ | ||
349 | sysfs_notify(&priv->dev->kobj, NULL, "temp1_min_alarm"); | ||
350 | } | ||
351 | |||
352 | if (priv->min_alert || priv->max_alert) | ||
353 | kobject_uevent(&priv->dev->kobj, KOBJ_CHANGE); | ||
354 | |||
355 | mutex_unlock(&priv->access_lock); | ||
356 | } | ||
357 | |||
358 | static int stts751_update(struct stts751_priv *priv) | ||
359 | { | ||
360 | int ret; | ||
361 | int cache_time = msecs_to_jiffies(stts751_intervals[priv->interval]); | ||
362 | |||
363 | if (time_after(jiffies, priv->last_update + cache_time) || | ||
364 | !priv->data_valid) { | ||
365 | ret = stts751_update_temp(priv); | ||
366 | if (ret) | ||
367 | return ret; | ||
368 | |||
369 | ret = stts751_update_alert(priv); | ||
370 | if (ret) | ||
371 | return ret; | ||
372 | priv->data_valid = true; | ||
373 | priv->last_update = jiffies; | ||
374 | } | ||
375 | |||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | static ssize_t show_max_alarm(struct device *dev, struct device_attribute *attr, | ||
380 | char *buf) | ||
381 | { | ||
382 | int ret; | ||
383 | struct stts751_priv *priv = dev_get_drvdata(dev); | ||
384 | |||
385 | mutex_lock(&priv->access_lock); | ||
386 | ret = stts751_update(priv); | ||
387 | if (!ret) | ||
388 | priv->notify_max = true; | ||
389 | mutex_unlock(&priv->access_lock); | ||
390 | if (ret < 0) | ||
391 | return ret; | ||
392 | |||
393 | return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->max_alert); | ||
394 | } | ||
395 | |||
396 | static ssize_t show_min_alarm(struct device *dev, struct device_attribute *attr, | ||
397 | char *buf) | ||
398 | { | ||
399 | int ret; | ||
400 | struct stts751_priv *priv = dev_get_drvdata(dev); | ||
401 | |||
402 | mutex_lock(&priv->access_lock); | ||
403 | ret = stts751_update(priv); | ||
404 | if (!ret) | ||
405 | priv->notify_min = true; | ||
406 | mutex_unlock(&priv->access_lock); | ||
407 | if (ret < 0) | ||
408 | return ret; | ||
409 | |||
410 | return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->min_alert); | ||
411 | } | ||
412 | |||
413 | static ssize_t show_input(struct device *dev, struct device_attribute *attr, | ||
414 | char *buf) | ||
415 | { | ||
416 | int ret; | ||
417 | struct stts751_priv *priv = dev_get_drvdata(dev); | ||
418 | |||
419 | mutex_lock(&priv->access_lock); | ||
420 | ret = stts751_update(priv); | ||
421 | mutex_unlock(&priv->access_lock); | ||
422 | if (ret < 0) | ||
423 | return ret; | ||
424 | |||
425 | return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->temp); | ||
426 | } | ||
427 | |||
428 | static ssize_t show_therm(struct device *dev, struct device_attribute *attr, | ||
429 | char *buf) | ||
430 | { | ||
431 | struct stts751_priv *priv = dev_get_drvdata(dev); | ||
432 | |||
433 | return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->therm); | ||
434 | } | ||
435 | |||
436 | static ssize_t set_therm(struct device *dev, struct device_attribute *attr, | ||
437 | const char *buf, size_t count) | ||
438 | { | ||
439 | int ret; | ||
440 | long temp; | ||
441 | struct stts751_priv *priv = dev_get_drvdata(dev); | ||
442 | |||
443 | if (kstrtol(buf, 10, &temp) < 0) | ||
444 | return -EINVAL; | ||
445 | |||
446 | /* HW works in range -64C to +127.937C */ | ||
447 | temp = clamp_val(temp, -64000, 127937); | ||
448 | mutex_lock(&priv->access_lock); | ||
449 | ret = stts751_set_temp_reg8(priv, temp, STTS751_REG_TLIM); | ||
450 | if (ret) | ||
451 | goto exit; | ||
452 | |||
453 | dev_dbg(&priv->client->dev, "setting therm %ld", temp); | ||
454 | |||
455 | /* | ||
456 | * hysteresis reg is relative to therm, so the HW does not need to be | ||
457 | * adjusted, we need to update our local copy only. | ||
458 | */ | ||
459 | priv->hyst = temp - (priv->therm - priv->hyst); | ||
460 | priv->therm = temp; | ||
461 | |||
462 | exit: | ||
463 | mutex_unlock(&priv->access_lock); | ||
464 | if (ret) | ||
465 | return ret; | ||
466 | |||
467 | return count; | ||
468 | } | ||
469 | |||
470 | static ssize_t show_hyst(struct device *dev, struct device_attribute *attr, | ||
471 | char *buf) | ||
472 | { | ||
473 | struct stts751_priv *priv = dev_get_drvdata(dev); | ||
474 | |||
475 | return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->hyst); | ||
476 | } | ||
477 | |||
478 | static ssize_t set_hyst(struct device *dev, struct device_attribute *attr, | ||
479 | const char *buf, size_t count) | ||
480 | { | ||
481 | int ret; | ||
482 | long temp; | ||
483 | |||
484 | struct stts751_priv *priv = dev_get_drvdata(dev); | ||
485 | |||
486 | if (kstrtol(buf, 10, &temp) < 0) | ||
487 | return -EINVAL; | ||
488 | |||
489 | mutex_lock(&priv->access_lock); | ||
490 | /* HW works in range -64C to +127.937C */ | ||
491 | temp = clamp_val(temp, -64000, priv->therm); | ||
492 | priv->hyst = temp; | ||
493 | dev_dbg(&priv->client->dev, "setting hyst %ld", temp); | ||
494 | temp = priv->therm - temp; | ||
495 | ret = stts751_set_temp_reg8(priv, temp, STTS751_REG_HYST); | ||
496 | mutex_unlock(&priv->access_lock); | ||
497 | if (ret) | ||
498 | return ret; | ||
499 | |||
500 | return count; | ||
501 | } | ||
502 | |||
503 | static ssize_t show_therm_trip(struct device *dev, | ||
504 | struct device_attribute *attr, char *buf) | ||
505 | { | ||
506 | int ret; | ||
507 | struct stts751_priv *priv = dev_get_drvdata(dev); | ||
508 | |||
509 | mutex_lock(&priv->access_lock); | ||
510 | ret = stts751_update(priv); | ||
511 | mutex_unlock(&priv->access_lock); | ||
512 | if (ret < 0) | ||
513 | return ret; | ||
514 | |||
515 | return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->therm_trip); | ||
516 | } | ||
517 | |||
518 | static ssize_t show_max(struct device *dev, struct device_attribute *attr, | ||
519 | char *buf) | ||
520 | { | ||
521 | struct stts751_priv *priv = dev_get_drvdata(dev); | ||
522 | |||
523 | return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->event_max); | ||
524 | } | ||
525 | |||
526 | static ssize_t set_max(struct device *dev, struct device_attribute *attr, | ||
527 | const char *buf, size_t count) | ||
528 | { | ||
529 | int ret; | ||
530 | long temp; | ||
531 | struct stts751_priv *priv = dev_get_drvdata(dev); | ||
532 | |||
533 | if (kstrtol(buf, 10, &temp) < 0) | ||
534 | return -EINVAL; | ||
535 | |||
536 | mutex_lock(&priv->access_lock); | ||
537 | /* HW works in range -64C to +127.937C */ | ||
538 | temp = clamp_val(temp, priv->event_min, 127937); | ||
539 | ret = stts751_set_temp_reg16(priv, temp, | ||
540 | STTS751_REG_HLIM_H, STTS751_REG_HLIM_L); | ||
541 | if (ret) | ||
542 | goto exit; | ||
543 | |||
544 | dev_dbg(&priv->client->dev, "setting event max %ld", temp); | ||
545 | priv->event_max = temp; | ||
546 | ret = count; | ||
547 | exit: | ||
548 | mutex_unlock(&priv->access_lock); | ||
549 | return ret; | ||
550 | } | ||
551 | |||
552 | static ssize_t show_min(struct device *dev, struct device_attribute *attr, | ||
553 | char *buf) | ||
554 | { | ||
555 | struct stts751_priv *priv = dev_get_drvdata(dev); | ||
556 | |||
557 | return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->event_min); | ||
558 | } | ||
559 | |||
560 | static ssize_t set_min(struct device *dev, struct device_attribute *attr, | ||
561 | const char *buf, size_t count) | ||
562 | { | ||
563 | int ret; | ||
564 | long temp; | ||
565 | struct stts751_priv *priv = dev_get_drvdata(dev); | ||
566 | |||
567 | if (kstrtol(buf, 10, &temp) < 0) | ||
568 | return -EINVAL; | ||
569 | |||
570 | mutex_lock(&priv->access_lock); | ||
571 | /* HW works in range -64C to +127.937C */ | ||
572 | temp = clamp_val(temp, -64000, priv->event_max); | ||
573 | ret = stts751_set_temp_reg16(priv, temp, | ||
574 | STTS751_REG_LLIM_H, STTS751_REG_LLIM_L); | ||
575 | if (ret) | ||
576 | goto exit; | ||
577 | |||
578 | dev_dbg(&priv->client->dev, "setting event min %ld", temp); | ||
579 | priv->event_min = temp; | ||
580 | ret = count; | ||
581 | exit: | ||
582 | mutex_unlock(&priv->access_lock); | ||
583 | return ret; | ||
584 | } | ||
585 | |||
586 | static ssize_t show_interval(struct device *dev, struct device_attribute *attr, | ||
587 | char *buf) | ||
588 | { | ||
589 | struct stts751_priv *priv = dev_get_drvdata(dev); | ||
590 | |||
591 | return snprintf(buf, PAGE_SIZE - 1, "%d\n", | ||
592 | stts751_intervals[priv->interval]); | ||
593 | } | ||
594 | |||
595 | static ssize_t set_interval(struct device *dev, struct device_attribute *attr, | ||
596 | const char *buf, size_t count) | ||
597 | { | ||
598 | unsigned long val; | ||
599 | int idx; | ||
600 | int ret = count; | ||
601 | struct stts751_priv *priv = dev_get_drvdata(dev); | ||
602 | |||
603 | if (kstrtoul(buf, 10, &val) < 0) | ||
604 | return -EINVAL; | ||
605 | |||
606 | idx = find_closest_descending(val, stts751_intervals, | ||
607 | ARRAY_SIZE(stts751_intervals)); | ||
608 | |||
609 | dev_dbg(&priv->client->dev, "setting interval. req:%lu, idx: %d, val: %d", | ||
610 | val, idx, stts751_intervals[idx]); | ||
611 | |||
612 | mutex_lock(&priv->access_lock); | ||
613 | if (priv->interval == idx) | ||
614 | goto exit; | ||
615 | |||
616 | /* | ||
617 | * In early development stages I've become suspicious about the chip | ||
618 | * starting to misbehave if I ever set, even briefly, an invalid | ||
619 | * configuration. While I'm not sure this is really needed, be | ||
620 | * conservative and set rate/resolution in such an order that avoids | ||
621 | * passing through an invalid configuration. | ||
622 | */ | ||
623 | |||
624 | /* speed up: lower the resolution, then modify convrate */ | ||
625 | if (priv->interval < idx) { | ||
626 | dev_dbg(&priv->client->dev, "lower resolution, then modify convrate"); | ||
627 | priv->interval = idx; | ||
628 | ret = stts751_adjust_resolution(priv); | ||
629 | if (ret) | ||
630 | goto exit; | ||
631 | } | ||
632 | |||
633 | ret = i2c_smbus_write_byte_data(priv->client, STTS751_REG_RATE, idx); | ||
634 | if (ret) | ||
635 | goto exit; | ||
636 | /* slow down: modify convrate, then raise resolution */ | ||
637 | if (priv->interval != idx) { | ||
638 | dev_dbg(&priv->client->dev, "modify convrate, then raise resolution"); | ||
639 | priv->interval = idx; | ||
640 | ret = stts751_adjust_resolution(priv); | ||
641 | if (ret) | ||
642 | goto exit; | ||
643 | } | ||
644 | ret = count; | ||
645 | exit: | ||
646 | mutex_unlock(&priv->access_lock); | ||
647 | |||
648 | return ret; | ||
649 | } | ||
650 | |||
651 | static int stts751_detect(struct i2c_client *new_client, | ||
652 | struct i2c_board_info *info) | ||
653 | { | ||
654 | struct i2c_adapter *adapter = new_client->adapter; | ||
655 | const char *name; | ||
656 | int tmp; | ||
657 | |||
658 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
659 | return -ENODEV; | ||
660 | |||
661 | tmp = i2c_smbus_read_byte_data(new_client, STTS751_REG_MAN_ID); | ||
662 | if (tmp != ST_MAN_ID) | ||
663 | return -ENODEV; | ||
664 | |||
665 | /* lower temperaure registers always have bits 0-3 set to zero */ | ||
666 | tmp = i2c_smbus_read_byte_data(new_client, STTS751_REG_TEMP_L); | ||
667 | if (tmp & 0xf) | ||
668 | return -ENODEV; | ||
669 | |||
670 | tmp = i2c_smbus_read_byte_data(new_client, STTS751_REG_HLIM_L); | ||
671 | if (tmp & 0xf) | ||
672 | return -ENODEV; | ||
673 | |||
674 | tmp = i2c_smbus_read_byte_data(new_client, STTS751_REG_LLIM_L); | ||
675 | if (tmp & 0xf) | ||
676 | return -ENODEV; | ||
677 | |||
678 | /* smbus timeout register always have bits 0-7 set to zero */ | ||
679 | tmp = i2c_smbus_read_byte_data(new_client, STTS751_REG_SMBUS_TO); | ||
680 | if (tmp & 0x7f) | ||
681 | return -ENODEV; | ||
682 | |||
683 | tmp = i2c_smbus_read_byte_data(new_client, STTS751_REG_PROD_ID); | ||
684 | |||
685 | switch (tmp) { | ||
686 | case STTS751_0_PROD_ID: | ||
687 | name = "STTS751-0"; | ||
688 | break; | ||
689 | case STTS751_1_PROD_ID: | ||
690 | name = "STTS751-1"; | ||
691 | break; | ||
692 | default: | ||
693 | return -ENODEV; | ||
694 | } | ||
695 | dev_dbg(&new_client->dev, "Chip %s detected", name); | ||
696 | |||
697 | strlcpy(info->type, stts751_id[0].name, I2C_NAME_SIZE); | ||
698 | return 0; | ||
699 | } | ||
700 | |||
701 | static int stts751_read_chip_config(struct stts751_priv *priv) | ||
702 | { | ||
703 | int ret; | ||
704 | int tmp; | ||
705 | |||
706 | ret = i2c_smbus_read_byte_data(priv->client, STTS751_REG_CONF); | ||
707 | if (ret < 0) | ||
708 | return ret; | ||
709 | priv->config = ret; | ||
710 | priv->res = (ret & STTS751_CONF_RES_MASK) >> STTS751_CONF_RES_SHIFT; | ||
711 | |||
712 | ret = i2c_smbus_read_byte_data(priv->client, STTS751_REG_RATE); | ||
713 | if (ret < 0) | ||
714 | return ret; | ||
715 | priv->interval = ret; | ||
716 | |||
717 | ret = stts751_read_reg16(priv, &priv->event_max, | ||
718 | STTS751_REG_HLIM_H, STTS751_REG_HLIM_L); | ||
719 | if (ret) | ||
720 | return ret; | ||
721 | |||
722 | ret = stts751_read_reg16(priv, &priv->event_min, | ||
723 | STTS751_REG_LLIM_H, STTS751_REG_LLIM_L); | ||
724 | if (ret) | ||
725 | return ret; | ||
726 | |||
727 | ret = stts751_read_reg8(priv, &priv->therm, STTS751_REG_TLIM); | ||
728 | if (ret) | ||
729 | return ret; | ||
730 | |||
731 | ret = stts751_read_reg8(priv, &tmp, STTS751_REG_HYST); | ||
732 | if (ret) | ||
733 | return ret; | ||
734 | priv->hyst = priv->therm - tmp; | ||
735 | |||
736 | return 0; | ||
737 | } | ||
738 | |||
739 | static SENSOR_DEVICE_ATTR(temp1_input, 0444, show_input, NULL, 0); | ||
740 | static SENSOR_DEVICE_ATTR(temp1_min, 0644, show_min, set_min, 0); | ||
741 | static SENSOR_DEVICE_ATTR(temp1_max, 0644, show_max, set_max, 0); | ||
742 | static SENSOR_DEVICE_ATTR(temp1_min_alarm, 0444, show_min_alarm, NULL, 0); | ||
743 | static SENSOR_DEVICE_ATTR(temp1_max_alarm, 0444, show_max_alarm, NULL, 0); | ||
744 | static SENSOR_DEVICE_ATTR(temp1_crit, 0644, show_therm, set_therm, 0); | ||
745 | static SENSOR_DEVICE_ATTR(temp1_crit_hyst, 0644, show_hyst, set_hyst, 0); | ||
746 | static SENSOR_DEVICE_ATTR(temp1_crit_alarm, 0444, show_therm_trip, NULL, 0); | ||
747 | static SENSOR_DEVICE_ATTR(update_interval, 0644, | ||
748 | show_interval, set_interval, 0); | ||
749 | |||
750 | static struct attribute *stts751_attrs[] = { | ||
751 | &sensor_dev_attr_temp1_input.dev_attr.attr, | ||
752 | &sensor_dev_attr_temp1_min.dev_attr.attr, | ||
753 | &sensor_dev_attr_temp1_max.dev_attr.attr, | ||
754 | &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, | ||
755 | &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, | ||
756 | &sensor_dev_attr_temp1_crit.dev_attr.attr, | ||
757 | &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, | ||
758 | &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, | ||
759 | &sensor_dev_attr_update_interval.dev_attr.attr, | ||
760 | NULL | ||
761 | }; | ||
762 | ATTRIBUTE_GROUPS(stts751); | ||
763 | |||
764 | static int stts751_probe(struct i2c_client *client, | ||
765 | const struct i2c_device_id *id) | ||
766 | { | ||
767 | struct stts751_priv *priv; | ||
768 | int ret; | ||
769 | bool smbus_nto; | ||
770 | int rev_id; | ||
771 | |||
772 | priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); | ||
773 | if (!priv) | ||
774 | return -ENOMEM; | ||
775 | |||
776 | priv->client = client; | ||
777 | priv->notify_max = true; | ||
778 | priv->notify_min = true; | ||
779 | i2c_set_clientdata(client, priv); | ||
780 | mutex_init(&priv->access_lock); | ||
781 | |||
782 | if (device_property_present(&client->dev, | ||
783 | "smbus-timeout-disable")) { | ||
784 | smbus_nto = device_property_read_bool(&client->dev, | ||
785 | "smbus-timeout-disable"); | ||
786 | |||
787 | ret = i2c_smbus_write_byte_data(client, STTS751_REG_SMBUS_TO, | ||
788 | smbus_nto ? 0 : 0x80); | ||
789 | if (ret) | ||
790 | return ret; | ||
791 | } | ||
792 | |||
793 | rev_id = i2c_smbus_read_byte_data(client, STTS751_REG_REV_ID); | ||
794 | if (rev_id < 0) | ||
795 | return -ENODEV; | ||
796 | if (rev_id != 0x1) { | ||
797 | dev_dbg(&client->dev, "Chip revision 0x%x is untested\n", | ||
798 | rev_id); | ||
799 | } | ||
800 | |||
801 | ret = stts751_read_chip_config(priv); | ||
802 | if (ret) | ||
803 | return ret; | ||
804 | |||
805 | priv->config &= ~(STTS751_CONF_STOP | STTS751_CONF_EVENT_DIS); | ||
806 | ret = i2c_smbus_write_byte_data(client, STTS751_REG_CONF, priv->config); | ||
807 | if (ret) | ||
808 | return ret; | ||
809 | |||
810 | priv->dev = devm_hwmon_device_register_with_groups(&client->dev, | ||
811 | client->name, priv, | ||
812 | stts751_groups); | ||
813 | return PTR_ERR_OR_ZERO(priv->dev); | ||
814 | } | ||
815 | |||
816 | MODULE_DEVICE_TABLE(i2c, stts751_id); | ||
817 | |||
818 | static struct i2c_driver stts751_driver = { | ||
819 | .class = I2C_CLASS_HWMON, | ||
820 | .driver = { | ||
821 | .name = DEVNAME, | ||
822 | }, | ||
823 | .probe = stts751_probe, | ||
824 | .id_table = stts751_id, | ||
825 | .detect = stts751_detect, | ||
826 | .alert = stts751_alert, | ||
827 | .address_list = normal_i2c, | ||
828 | }; | ||
829 | |||
830 | module_i2c_driver(stts751_driver); | ||
831 | |||
832 | MODULE_AUTHOR("Andrea Merello <andrea.merello@gmail.com>"); | ||
833 | MODULE_DESCRIPTION("STTS751 sensor driver"); | ||
834 | MODULE_LICENSE("GPL"); | ||