diff options
Diffstat (limited to 'drivers/hwmon')
-rw-r--r-- | drivers/hwmon/adt7461.c | 823 | ||||
-rw-r--r-- | drivers/hwmon/ina219.c | 414 | ||||
-rw-r--r-- | drivers/hwmon/ina230.c | 561 | ||||
-rw-r--r-- | drivers/hwmon/tegra-tsensor.c | 1949 |
4 files changed, 3747 insertions, 0 deletions
diff --git a/drivers/hwmon/adt7461.c b/drivers/hwmon/adt7461.c new file mode 100644 index 00000000000..10ea2eb8066 --- /dev/null +++ b/drivers/hwmon/adt7461.c | |||
@@ -0,0 +1,823 @@ | |||
1 | /* | ||
2 | * adt7461.c - Linux kernel modules for hardware | ||
3 | * monitoring | ||
4 | * Copyright (C) 2003-2010 Jean Delvare <khali@linux-fr.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/jiffies.h> | ||
25 | #include <linux/regulator/consumer.h> | ||
26 | #include <linux/i2c.h> | ||
27 | #include <linux/hwmon-sysfs.h> | ||
28 | #include <linux/hwmon.h> | ||
29 | #include <linux/err.h> | ||
30 | #include <linux/mutex.h> | ||
31 | #include <linux/sysfs.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include <linux/gpio.h> | ||
34 | #include <linux/interrupt.h> | ||
35 | #include <linux/adt7461.h> | ||
36 | |||
37 | #define DRIVER_NAME "adt7461" | ||
38 | |||
39 | /* | ||
40 | * The ADT7461 registers | ||
41 | */ | ||
42 | |||
43 | #define ADT7461_REG_R_MAN_ID 0xFE | ||
44 | #define ADT7461_REG_R_CHIP_ID 0xFF | ||
45 | #define ADT7461_REG_R_CONFIG1 0x03 | ||
46 | #define ADT7461_REG_W_CONFIG1 0x09 | ||
47 | #define ADT7461_REG_R_CONVRATE 0x04 | ||
48 | #define ADT7461_REG_W_CONVRATE 0x0A | ||
49 | #define ADT7461_REG_R_STATUS 0x02 | ||
50 | #define ADT7461_REG_R_LOCAL_TEMP 0x00 | ||
51 | #define ADT7461_REG_R_LOCAL_HIGH 0x05 | ||
52 | #define ADT7461_REG_W_LOCAL_HIGH 0x0B | ||
53 | #define ADT7461_REG_R_LOCAL_LOW 0x06 | ||
54 | #define ADT7461_REG_W_LOCAL_LOW 0x0C | ||
55 | #define ADT7461_REG_R_LOCAL_CRIT 0x20 | ||
56 | #define ADT7461_REG_W_LOCAL_CRIT 0x20 | ||
57 | #define ADT7461_REG_R_REMOTE_TEMPH 0x01 | ||
58 | #define ADT7461_REG_R_REMOTE_TEMPL 0x10 | ||
59 | #define ADT7461_REG_R_REMOTE_OFFSH 0x11 | ||
60 | #define ADT7461_REG_W_REMOTE_OFFSH 0x11 | ||
61 | #define ADT7461_REG_R_REMOTE_OFFSL 0x12 | ||
62 | #define ADT7461_REG_W_REMOTE_OFFSL 0x12 | ||
63 | #define ADT7461_REG_R_REMOTE_HIGHH 0x07 | ||
64 | #define ADT7461_REG_W_REMOTE_HIGHH 0x0D | ||
65 | #define ADT7461_REG_R_REMOTE_HIGHL 0x13 | ||
66 | #define ADT7461_REG_W_REMOTE_HIGHL 0x13 | ||
67 | #define ADT7461_REG_R_REMOTE_LOWH 0x08 | ||
68 | #define ADT7461_REG_W_REMOTE_LOWH 0x0E | ||
69 | #define ADT7461_REG_R_REMOTE_LOWL 0x14 | ||
70 | #define ADT7461_REG_W_REMOTE_LOWL 0x14 | ||
71 | #define ADT7461_REG_R_REMOTE_CRIT 0x19 | ||
72 | #define ADT7461_REG_W_REMOTE_CRIT 0x19 | ||
73 | #define ADT7461_REG_R_TCRIT_HYST 0x21 | ||
74 | #define ADT7461_REG_W_TCRIT_HYST 0x21 | ||
75 | |||
76 | /* Configuration Register Bits */ | ||
77 | #define EXTENDED_RANGE_BIT BIT(2) | ||
78 | #define THERM2_BIT BIT(5) | ||
79 | #define STANDBY_BIT BIT(6) | ||
80 | #define ALERT_BIT BIT(7) | ||
81 | |||
82 | /* Max Temperature Measurements */ | ||
83 | #define EXTENDED_RANGE_OFFSET 64U | ||
84 | #define STANDARD_RANGE_MAX 127U | ||
85 | #define EXTENDED_RANGE_MAX (150U + EXTENDED_RANGE_OFFSET) | ||
86 | |||
87 | /* | ||
88 | * Device flags | ||
89 | */ | ||
90 | #define ADT7461_FLAG_ADT7461_EXT 0x01 /* ADT7461 extended mode */ | ||
91 | #define ADT7461_FLAG_THERM2 0x02 /* Pin 6 as Therm2 */ | ||
92 | |||
93 | /* | ||
94 | * Client data | ||
95 | */ | ||
96 | |||
97 | struct adt7461_data { | ||
98 | struct work_struct work; | ||
99 | struct i2c_client *client; | ||
100 | struct device *hwmon_dev; | ||
101 | struct mutex update_lock; | ||
102 | struct regulator *regulator; | ||
103 | char valid; /* zero until following fields are valid */ | ||
104 | unsigned long last_updated; /* in jiffies */ | ||
105 | int flags; | ||
106 | |||
107 | u8 config; /* configuration register value */ | ||
108 | u8 alert_alarms; /* Which alarm bits trigger ALERT# */ | ||
109 | |||
110 | /* registers values */ | ||
111 | s8 temp8[4]; /* 0: local low limit | ||
112 | 1: local high limit | ||
113 | 2: local critical limit | ||
114 | 3: remote critical limit */ | ||
115 | s16 temp11[5]; /* 0: remote input | ||
116 | 1: remote low limit | ||
117 | 2: remote high limit | ||
118 | 3: remote offset | ||
119 | 4: local input */ | ||
120 | u8 temp_hyst; | ||
121 | u8 alarms; /* bitvector */ | ||
122 | void (*alarm_fn)(bool raised); | ||
123 | int irq_gpio; | ||
124 | }; | ||
125 | |||
126 | /* | ||
127 | * Conversions | ||
128 | */ | ||
129 | |||
130 | static inline int temp_from_s8(s8 val) | ||
131 | { | ||
132 | return val * 1000; | ||
133 | } | ||
134 | |||
135 | static u8 hyst_to_reg(long val) | ||
136 | { | ||
137 | if (val <= 0) | ||
138 | return 0; | ||
139 | if (val >= 30500) | ||
140 | return 31; | ||
141 | return (val + 500) / 1000; | ||
142 | } | ||
143 | |||
144 | /* | ||
145 | * ADT7461 attempts to write values that are outside the range | ||
146 | * 0 < temp < 127 are treated as the boundary value. | ||
147 | * | ||
148 | * ADT7461 in "extended mode" operation uses unsigned integers offset by | ||
149 | * 64 (e.g., 0 -> -64 degC). The range is restricted to -64..191 degC. | ||
150 | */ | ||
151 | static inline int temp_from_u8(struct adt7461_data *data, u8 val) | ||
152 | { | ||
153 | if (data->flags & ADT7461_FLAG_ADT7461_EXT) | ||
154 | return (val - 64) * 1000; | ||
155 | else | ||
156 | return temp_from_s8(val); | ||
157 | } | ||
158 | |||
159 | static inline int temp_from_u16(struct adt7461_data *data, u16 val) | ||
160 | { | ||
161 | if (data->flags & ADT7461_FLAG_ADT7461_EXT) | ||
162 | return (val - 0x4000) / 64 * 250; | ||
163 | else | ||
164 | return val / 32 * 125; | ||
165 | } | ||
166 | |||
167 | static u8 temp_to_u8(struct adt7461_data *data, long val) | ||
168 | { | ||
169 | if (data->flags & ADT7461_FLAG_ADT7461_EXT) { | ||
170 | if (val <= -64000) | ||
171 | return 0; | ||
172 | if (val >= 191000) | ||
173 | return 0xFF; | ||
174 | return (val + 500 + 64000) / 1000; | ||
175 | } else { | ||
176 | if (val <= 0) | ||
177 | return 0; | ||
178 | if (val >= 127000) | ||
179 | return 127; | ||
180 | return (val + 500) / 1000; | ||
181 | } | ||
182 | } | ||
183 | |||
184 | static u16 temp_to_u16(struct adt7461_data *data, long val) | ||
185 | { | ||
186 | if (data->flags & ADT7461_FLAG_ADT7461_EXT) { | ||
187 | if (val <= -64000) | ||
188 | return 0; | ||
189 | if (val >= 191750) | ||
190 | return 0xFFC0; | ||
191 | return (val + 64000 + 125) / 250 * 64; | ||
192 | } else { | ||
193 | if (val <= 0) | ||
194 | return 0; | ||
195 | if (val >= 127750) | ||
196 | return 0x7FC0; | ||
197 | return (val + 125) / 250 * 64; | ||
198 | } | ||
199 | } | ||
200 | |||
201 | static int adt7461_read_reg(struct i2c_client* client, u8 reg, u8 *value) | ||
202 | { | ||
203 | int err; | ||
204 | |||
205 | err = i2c_smbus_read_byte_data(client, reg); | ||
206 | if (err < 0) { | ||
207 | pr_err("adt7461_read_reg:Register %#02x read failed (%d)\n", | ||
208 | reg, err); | ||
209 | return err; | ||
210 | } | ||
211 | *value = err; | ||
212 | |||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static int adt7461_read16(struct i2c_client *client, u8 regh, u8 regl, | ||
217 | u16 *value) | ||
218 | { | ||
219 | int err; | ||
220 | u8 oldh, newh, l; | ||
221 | |||
222 | /* | ||
223 | * There is a trick here. We have to read two registers to have the | ||
224 | * sensor temperature, but we have to beware a conversion could occur | ||
225 | * inbetween the readings. The datasheet says we should either use | ||
226 | * the one-shot conversion register, which we don't want to do | ||
227 | * (disables hardware monitoring) or monitor the busy bit, which is | ||
228 | * impossible (we can't read the values and monitor that bit at the | ||
229 | * exact same time). So the solution used here is to read the high | ||
230 | * byte once, then the low byte, then the high byte again. If the new | ||
231 | * high byte matches the old one, then we have a valid reading. Else | ||
232 | * we have to read the low byte again, and now we believe we have a | ||
233 | * correct reading. | ||
234 | */ | ||
235 | if ((err = adt7461_read_reg(client, regh, &oldh)) | ||
236 | || (err = adt7461_read_reg(client, regl, &l)) | ||
237 | || (err = adt7461_read_reg(client, regh, &newh))) | ||
238 | return err; | ||
239 | if (oldh != newh) { | ||
240 | err = adt7461_read_reg(client, regl, &l); | ||
241 | if (err) | ||
242 | return err; | ||
243 | } | ||
244 | *value = (newh << 8) | l; | ||
245 | |||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | static struct adt7461_data *adt7461_update_device(struct device *dev) | ||
250 | { | ||
251 | struct i2c_client *client = to_i2c_client(dev); | ||
252 | struct adt7461_data *data = i2c_get_clientdata(client); | ||
253 | |||
254 | mutex_lock(&data->update_lock); | ||
255 | |||
256 | if (time_after(jiffies, data->last_updated + HZ / 2 + HZ / 10) | ||
257 | || !data->valid) { | ||
258 | u8 h, l; | ||
259 | |||
260 | adt7461_read_reg(client, ADT7461_REG_R_LOCAL_LOW, &data->temp8[0]); | ||
261 | adt7461_read_reg(client, ADT7461_REG_R_LOCAL_HIGH, &data->temp8[1]); | ||
262 | adt7461_read_reg(client, ADT7461_REG_R_LOCAL_CRIT, &data->temp8[2]); | ||
263 | adt7461_read_reg(client, ADT7461_REG_R_REMOTE_CRIT, &data->temp8[3]); | ||
264 | adt7461_read_reg(client, ADT7461_REG_R_TCRIT_HYST, &data->temp_hyst); | ||
265 | |||
266 | if (adt7461_read_reg(client, ADT7461_REG_R_LOCAL_TEMP, &h) == 0) | ||
267 | data->temp11[4] = h << 8; | ||
268 | |||
269 | adt7461_read16(client, ADT7461_REG_R_REMOTE_TEMPH, | ||
270 | ADT7461_REG_R_REMOTE_TEMPL, &data->temp11[0]); | ||
271 | |||
272 | if (adt7461_read_reg(client, ADT7461_REG_R_REMOTE_LOWH, &h) == 0) { | ||
273 | data->temp11[1] = h << 8; | ||
274 | if (adt7461_read_reg(client, ADT7461_REG_R_REMOTE_LOWL, &l) == 0) | ||
275 | data->temp11[1] |= l; | ||
276 | } | ||
277 | if (adt7461_read_reg(client, ADT7461_REG_R_REMOTE_HIGHH, &h) == 0) { | ||
278 | data->temp11[2] = h << 8; | ||
279 | if (adt7461_read_reg(client, ADT7461_REG_R_REMOTE_HIGHL, &l) == 0) | ||
280 | data->temp11[2] |= l; | ||
281 | } | ||
282 | |||
283 | if (adt7461_read_reg(client, ADT7461_REG_R_REMOTE_OFFSH, | ||
284 | &h) == 0 | ||
285 | && adt7461_read_reg(client, ADT7461_REG_R_REMOTE_OFFSL, | ||
286 | &l) == 0) | ||
287 | data->temp11[3] = (h << 8) | l; | ||
288 | adt7461_read_reg(client, ADT7461_REG_R_STATUS, &data->alarms); | ||
289 | |||
290 | /* Re-enable ALERT# output if relevant alarms are all clear */ | ||
291 | if (!(data->flags & ADT7461_FLAG_THERM2) | ||
292 | && (data->alarms & data->alert_alarms) == 0) { | ||
293 | u8 config; | ||
294 | |||
295 | adt7461_read_reg(client, ADT7461_REG_R_CONFIG1, &config); | ||
296 | if (config & 0x80) { | ||
297 | pr_err("adt7461_update_device:Re-enabling ALERT#\n"); | ||
298 | i2c_smbus_write_byte_data(client, | ||
299 | ADT7461_REG_W_CONFIG1, | ||
300 | config & ~ALERT_BIT); | ||
301 | } | ||
302 | } | ||
303 | |||
304 | data->last_updated = jiffies; | ||
305 | data->valid = 1; | ||
306 | } | ||
307 | |||
308 | mutex_unlock(&data->update_lock); | ||
309 | |||
310 | return data; | ||
311 | } | ||
312 | |||
313 | /* | ||
314 | * Sysfs stuff | ||
315 | */ | ||
316 | |||
317 | static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr, | ||
318 | char *buf) | ||
319 | { | ||
320 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
321 | struct adt7461_data *data = adt7461_update_device(dev); | ||
322 | int temp; | ||
323 | |||
324 | temp = temp_from_u8(data, data->temp8[attr->index]); | ||
325 | |||
326 | return sprintf(buf, "%d\n", temp); | ||
327 | } | ||
328 | |||
329 | static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr, | ||
330 | const char *buf, size_t count) | ||
331 | { | ||
332 | static const u8 reg[4] = { | ||
333 | ADT7461_REG_W_LOCAL_LOW, | ||
334 | ADT7461_REG_W_LOCAL_HIGH, | ||
335 | ADT7461_REG_W_LOCAL_CRIT, | ||
336 | ADT7461_REG_W_REMOTE_CRIT, | ||
337 | }; | ||
338 | |||
339 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
340 | struct i2c_client *client = to_i2c_client(dev); | ||
341 | struct adt7461_data *data = i2c_get_clientdata(client); | ||
342 | long val = simple_strtol(buf, NULL, 10); | ||
343 | int nr = attr->index; | ||
344 | |||
345 | mutex_lock(&data->update_lock); | ||
346 | data->temp8[nr] = temp_to_u8(data, val); | ||
347 | i2c_smbus_write_byte_data(client, reg[nr], data->temp8[nr]); | ||
348 | mutex_unlock(&data->update_lock); | ||
349 | return count; | ||
350 | } | ||
351 | |||
352 | static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr, | ||
353 | char *buf) | ||
354 | { | ||
355 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
356 | struct adt7461_data *data = adt7461_update_device(dev); | ||
357 | int temp; | ||
358 | |||
359 | temp = temp_from_u16(data, data->temp11[attr->index]); | ||
360 | |||
361 | return sprintf(buf, "%d\n", temp); | ||
362 | } | ||
363 | |||
364 | static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, | ||
365 | const char *buf, size_t count) | ||
366 | { | ||
367 | static const u8 reg[6] = { | ||
368 | ADT7461_REG_W_REMOTE_LOWH, | ||
369 | ADT7461_REG_W_REMOTE_LOWL, | ||
370 | ADT7461_REG_W_REMOTE_HIGHH, | ||
371 | ADT7461_REG_W_REMOTE_HIGHL, | ||
372 | ADT7461_REG_W_REMOTE_OFFSH, | ||
373 | ADT7461_REG_W_REMOTE_OFFSL, | ||
374 | }; | ||
375 | |||
376 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
377 | struct i2c_client *client = to_i2c_client(dev); | ||
378 | struct adt7461_data *data = i2c_get_clientdata(client); | ||
379 | long val = simple_strtol(buf, NULL, 10); | ||
380 | int nr = attr->index; | ||
381 | |||
382 | mutex_lock(&data->update_lock); | ||
383 | data->temp11[nr] = temp_to_u16(data, val); | ||
384 | |||
385 | i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2], | ||
386 | data->temp11[nr] >> 8); | ||
387 | i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1], | ||
388 | data->temp11[nr] & 0xff); | ||
389 | mutex_unlock(&data->update_lock); | ||
390 | return count; | ||
391 | } | ||
392 | |||
393 | static ssize_t show_temphyst(struct device *dev, | ||
394 | struct device_attribute *devattr, | ||
395 | char *buf) | ||
396 | { | ||
397 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
398 | struct adt7461_data *data = adt7461_update_device(dev); | ||
399 | int temp; | ||
400 | |||
401 | temp = temp_from_u8(data, data->temp8[attr->index]); | ||
402 | |||
403 | return sprintf(buf, "%d\n", temp - temp_from_s8(data->temp_hyst)); | ||
404 | } | ||
405 | |||
406 | static ssize_t set_temphyst(struct device *dev, struct device_attribute *dummy, | ||
407 | const char *buf, size_t count) | ||
408 | { | ||
409 | struct i2c_client *client = to_i2c_client(dev); | ||
410 | struct adt7461_data *data = i2c_get_clientdata(client); | ||
411 | long val = simple_strtol(buf, NULL, 10); | ||
412 | int temp; | ||
413 | |||
414 | mutex_lock(&data->update_lock); | ||
415 | temp = temp_from_u8(data, data->temp8[2]); | ||
416 | data->temp_hyst = hyst_to_reg(temp - val); | ||
417 | i2c_smbus_write_byte_data(client, ADT7461_REG_W_TCRIT_HYST, | ||
418 | data->temp_hyst); | ||
419 | mutex_unlock(&data->update_lock); | ||
420 | return count; | ||
421 | } | ||
422 | |||
423 | static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, | ||
424 | char *buf) | ||
425 | { | ||
426 | struct adt7461_data *data = adt7461_update_device(dev); | ||
427 | return sprintf(buf, "%d\n", data->alarms); | ||
428 | } | ||
429 | |||
430 | static ssize_t show_alarm(struct device *dev, struct device_attribute | ||
431 | *devattr, char *buf) | ||
432 | { | ||
433 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
434 | struct adt7461_data *data = adt7461_update_device(dev); | ||
435 | int bitnr = attr->index; | ||
436 | |||
437 | return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1); | ||
438 | } | ||
439 | |||
440 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp11, NULL, 4); | ||
441 | static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0); | ||
442 | static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8, | ||
443 | set_temp8, 0); | ||
444 | static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11, | ||
445 | set_temp11, 1); | ||
446 | static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8, | ||
447 | set_temp8, 1); | ||
448 | static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11, | ||
449 | set_temp11, 2); | ||
450 | static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp8, | ||
451 | set_temp8, 2); | ||
452 | static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp8, | ||
453 | set_temp8, 3); | ||
454 | static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst, | ||
455 | set_temphyst, 2); | ||
456 | static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 3); | ||
457 | static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_temp11, | ||
458 | set_temp11, 3); | ||
459 | |||
460 | /* Individual alarm files */ | ||
461 | static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0); | ||
462 | static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1); | ||
463 | static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2); | ||
464 | static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3); | ||
465 | static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4); | ||
466 | static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 5); | ||
467 | static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6); | ||
468 | /* Raw alarm file for compatibility */ | ||
469 | static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); | ||
470 | |||
471 | static struct attribute *adt7461_attributes[] = { | ||
472 | &sensor_dev_attr_temp1_input.dev_attr.attr, | ||
473 | &sensor_dev_attr_temp2_input.dev_attr.attr, | ||
474 | &sensor_dev_attr_temp1_min.dev_attr.attr, | ||
475 | &sensor_dev_attr_temp2_min.dev_attr.attr, | ||
476 | &sensor_dev_attr_temp1_max.dev_attr.attr, | ||
477 | &sensor_dev_attr_temp2_max.dev_attr.attr, | ||
478 | &sensor_dev_attr_temp1_crit.dev_attr.attr, | ||
479 | &sensor_dev_attr_temp2_crit.dev_attr.attr, | ||
480 | &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, | ||
481 | &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr, | ||
482 | |||
483 | &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, | ||
484 | &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, | ||
485 | &sensor_dev_attr_temp2_fault.dev_attr.attr, | ||
486 | &sensor_dev_attr_temp2_min_alarm.dev_attr.attr, | ||
487 | &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, | ||
488 | &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, | ||
489 | &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, | ||
490 | &dev_attr_alarms.attr, | ||
491 | NULL | ||
492 | }; | ||
493 | |||
494 | static const struct attribute_group adt7461_group = { | ||
495 | .attrs = adt7461_attributes, | ||
496 | }; | ||
497 | |||
498 | static void adt7461_work_func(struct work_struct *work) | ||
499 | { | ||
500 | struct adt7461_data *data = | ||
501 | container_of(work, struct adt7461_data, work); | ||
502 | |||
503 | if (data->alarm_fn) { | ||
504 | /* Therm2 line is active low */ | ||
505 | data->alarm_fn(!gpio_get_value(data->irq_gpio)); | ||
506 | } | ||
507 | } | ||
508 | |||
509 | static irqreturn_t adt7461_irq(int irq, void *dev_id) | ||
510 | { | ||
511 | struct adt7461_data *data = dev_id; | ||
512 | schedule_work(&data->work); | ||
513 | |||
514 | return IRQ_HANDLED; | ||
515 | } | ||
516 | |||
517 | static void adt7461_regulator_enable(struct i2c_client *client) | ||
518 | { | ||
519 | struct adt7461_data *data = i2c_get_clientdata(client); | ||
520 | |||
521 | data->regulator = regulator_get(NULL, "vdd_vcore_temp"); | ||
522 | if (IS_ERR_OR_NULL(data->regulator)) { | ||
523 | pr_err("adt7461_regulator_enable:Couldn't get regulator vdd_vcore_temp\n"); | ||
524 | data->regulator = NULL; | ||
525 | } else { | ||
526 | regulator_enable(data->regulator); | ||
527 | /* Optimal time to get the regulator turned on | ||
528 | * before initializing adt7461 chip*/ | ||
529 | mdelay(5); | ||
530 | } | ||
531 | } | ||
532 | |||
533 | static void adt7461_regulator_disable(struct i2c_client *client) | ||
534 | { | ||
535 | struct adt7461_data *data = i2c_get_clientdata(client); | ||
536 | struct regulator *adt7461_reg = data->regulator; | ||
537 | int ret; | ||
538 | |||
539 | if (adt7461_reg) { | ||
540 | ret = regulator_is_enabled(adt7461_reg); | ||
541 | if (ret > 0) | ||
542 | regulator_disable(adt7461_reg); | ||
543 | regulator_put(adt7461_reg); | ||
544 | } | ||
545 | data->regulator = NULL; | ||
546 | } | ||
547 | |||
548 | static void adt7461_enable(struct i2c_client *client) | ||
549 | { | ||
550 | struct adt7461_data *data = i2c_get_clientdata(client); | ||
551 | |||
552 | i2c_smbus_write_byte_data(client, ADT7461_REG_W_CONFIG1, | ||
553 | data->config & ~STANDBY_BIT); | ||
554 | } | ||
555 | |||
556 | static void adt7461_disable(struct i2c_client *client) | ||
557 | { | ||
558 | struct adt7461_data *data = i2c_get_clientdata(client); | ||
559 | |||
560 | i2c_smbus_write_byte_data(client, ADT7461_REG_W_CONFIG1, | ||
561 | data->config | STANDBY_BIT); | ||
562 | } | ||
563 | |||
564 | static int adt7461_init_client(struct i2c_client *client) | ||
565 | { | ||
566 | struct adt7461_data *data = i2c_get_clientdata(client); | ||
567 | struct adt7461_platform_data *pdata = client->dev.platform_data; | ||
568 | u8 config = 0; | ||
569 | u8 value; | ||
570 | int err; | ||
571 | |||
572 | if (!pdata || !pdata->supported_hwrev) | ||
573 | return -ENODEV; | ||
574 | |||
575 | data->irq_gpio = -1; | ||
576 | |||
577 | if (pdata->therm2) { | ||
578 | data->flags |= ADT7461_FLAG_THERM2; | ||
579 | |||
580 | if (gpio_is_valid(pdata->irq_gpio)) { | ||
581 | if (!IS_ERR(gpio_request(pdata->irq_gpio, "adt7461"))) { | ||
582 | gpio_direction_input(pdata->irq_gpio); | ||
583 | data->irq_gpio = pdata->irq_gpio; | ||
584 | } | ||
585 | } | ||
586 | } | ||
587 | |||
588 | if (pdata->ext_range) | ||
589 | data->flags |= ADT7461_FLAG_ADT7461_EXT; | ||
590 | |||
591 | adt7461_regulator_enable(client); | ||
592 | |||
593 | /* Start the conversions. */ | ||
594 | err = i2c_smbus_write_byte_data(client, ADT7461_REG_W_CONVRATE, | ||
595 | pdata->conv_rate); | ||
596 | if (err < 0) | ||
597 | goto error; | ||
598 | |||
599 | /* External temperature h/w shutdown limit */ | ||
600 | value = temp_to_u8(data, pdata->shutdown_ext_limit * 1000); | ||
601 | err = i2c_smbus_write_byte_data(client, | ||
602 | ADT7461_REG_W_REMOTE_CRIT, value); | ||
603 | if (err < 0) | ||
604 | goto error; | ||
605 | |||
606 | /* Local temperature h/w shutdown limit */ | ||
607 | value = temp_to_u8(data, pdata->shutdown_local_limit * 1000); | ||
608 | err = i2c_smbus_write_byte_data(client, ADT7461_REG_W_LOCAL_CRIT, | ||
609 | value); | ||
610 | if (err < 0) | ||
611 | goto error; | ||
612 | |||
613 | /* External Temperature Throttling limit */ | ||
614 | value = temp_to_u8(data, pdata->throttling_ext_limit * 1000); | ||
615 | err = i2c_smbus_write_byte_data(client, ADT7461_REG_W_REMOTE_HIGHH, | ||
616 | value); | ||
617 | if (err < 0) | ||
618 | goto error; | ||
619 | |||
620 | /* Local Temperature Throttling limit */ | ||
621 | value = (data->flags & ADT7461_FLAG_ADT7461_EXT) ? | ||
622 | EXTENDED_RANGE_MAX : STANDARD_RANGE_MAX; | ||
623 | err = i2c_smbus_write_byte_data(client, ADT7461_REG_W_LOCAL_HIGH, | ||
624 | value); | ||
625 | if (err < 0) | ||
626 | goto error; | ||
627 | |||
628 | /* Remote channel offset */ | ||
629 | err = i2c_smbus_write_byte_data(client, ADT7461_REG_W_REMOTE_OFFSH, | ||
630 | pdata->offset); | ||
631 | if (err < 0) | ||
632 | goto error; | ||
633 | |||
634 | /* THERM hysteresis */ | ||
635 | err = i2c_smbus_write_byte_data(client, ADT7461_REG_W_TCRIT_HYST, | ||
636 | pdata->hysteresis); | ||
637 | if (err < 0) | ||
638 | goto error; | ||
639 | |||
640 | if (data->flags & ADT7461_FLAG_THERM2) { | ||
641 | data->alarm_fn = pdata->alarm_fn; | ||
642 | config = (THERM2_BIT | STANDBY_BIT); | ||
643 | } else { | ||
644 | config = (~ALERT_BIT & ~THERM2_BIT & STANDBY_BIT); | ||
645 | } | ||
646 | |||
647 | err = i2c_smbus_write_byte_data(client, ADT7461_REG_W_CONFIG1, config); | ||
648 | if (err < 0) | ||
649 | goto error; | ||
650 | |||
651 | data->config = config; | ||
652 | return 0; | ||
653 | |||
654 | error: | ||
655 | pr_err("adt7461_init_client:Initialization failed!\n"); | ||
656 | return err; | ||
657 | } | ||
658 | |||
659 | static int adt7461_init_irq(struct adt7461_data *data) | ||
660 | { | ||
661 | INIT_WORK(&data->work, adt7461_work_func); | ||
662 | |||
663 | return request_irq(data->client->irq, adt7461_irq, IRQF_TRIGGER_RISING | | ||
664 | IRQF_TRIGGER_FALLING, DRIVER_NAME, data); | ||
665 | } | ||
666 | |||
667 | static int adt7461_probe(struct i2c_client *new_client, | ||
668 | const struct i2c_device_id *id) | ||
669 | { | ||
670 | struct adt7461_data *data; | ||
671 | int err; | ||
672 | |||
673 | data = kzalloc(sizeof(struct adt7461_data), GFP_KERNEL); | ||
674 | if (!data) | ||
675 | return -ENOMEM; | ||
676 | |||
677 | data->client = new_client; | ||
678 | i2c_set_clientdata(new_client, data); | ||
679 | mutex_init(&data->update_lock); | ||
680 | |||
681 | data->alert_alarms = 0x7c; | ||
682 | |||
683 | /* Initialize the ADT7461 chip */ | ||
684 | err = adt7461_init_client(new_client); | ||
685 | if (err < 0) | ||
686 | goto exit_free; | ||
687 | |||
688 | if (data->flags & ADT7461_FLAG_THERM2) { | ||
689 | err = adt7461_init_irq(data); | ||
690 | if (err < 0) | ||
691 | goto exit_free; | ||
692 | } | ||
693 | |||
694 | /* Register sysfs hooks */ | ||
695 | if ((err = sysfs_create_group(&new_client->dev.kobj, &adt7461_group))) | ||
696 | goto exit_free; | ||
697 | if ((err = device_create_file(&new_client->dev, | ||
698 | &sensor_dev_attr_temp2_offset.dev_attr))) | ||
699 | goto exit_remove_files; | ||
700 | |||
701 | data->hwmon_dev = hwmon_device_register(&new_client->dev); | ||
702 | if (IS_ERR(data->hwmon_dev)) { | ||
703 | err = PTR_ERR(data->hwmon_dev); | ||
704 | goto exit_remove_files; | ||
705 | } | ||
706 | |||
707 | adt7461_enable(new_client); | ||
708 | return 0; | ||
709 | |||
710 | exit_remove_files: | ||
711 | sysfs_remove_group(&new_client->dev.kobj, &adt7461_group); | ||
712 | exit_free: | ||
713 | kfree(data); | ||
714 | return err; | ||
715 | } | ||
716 | |||
717 | static int adt7461_remove(struct i2c_client *client) | ||
718 | { | ||
719 | struct adt7461_data *data = i2c_get_clientdata(client); | ||
720 | |||
721 | if (data->flags & ADT7461_FLAG_THERM2) { | ||
722 | free_irq(client->irq, data); | ||
723 | cancel_work_sync(&data->work); | ||
724 | } | ||
725 | if (gpio_is_valid(data->irq_gpio)) | ||
726 | gpio_free(data->irq_gpio); | ||
727 | hwmon_device_unregister(data->hwmon_dev); | ||
728 | sysfs_remove_group(&client->dev.kobj, &adt7461_group); | ||
729 | device_remove_file(&client->dev, | ||
730 | &sensor_dev_attr_temp2_offset.dev_attr); | ||
731 | adt7461_regulator_disable(client); | ||
732 | |||
733 | kfree(data); | ||
734 | return 0; | ||
735 | } | ||
736 | |||
737 | static void adt7461_alert(struct i2c_client *client, unsigned int flag) | ||
738 | { | ||
739 | struct adt7461_data *data = i2c_get_clientdata(client); | ||
740 | u8 config, alarms; | ||
741 | |||
742 | adt7461_read_reg(client, ADT7461_REG_R_STATUS, &alarms); | ||
743 | if ((alarms & 0x7f) == 0) { | ||
744 | pr_err("adt7461_alert:Everything OK\n"); | ||
745 | } else { | ||
746 | if (alarms & 0x61) | ||
747 | pr_err("adt7461_alert:temp%d out of range, please check!\n", 1); | ||
748 | if (alarms & 0x1a) | ||
749 | pr_err("adt7461_alert:temp%d out of range, please check!\n", 2); | ||
750 | if (alarms & 0x04) | ||
751 | pr_err("adt7461_alert:temp%d diode open, please check!\n", 2); | ||
752 | |||
753 | /* Disable ALERT# output, because these chips don't implement | ||
754 | SMBus alert correctly; they should only hold the alert line | ||
755 | low briefly. */ | ||
756 | if (!(data->flags & ADT7461_FLAG_THERM2) | ||
757 | && (alarms & data->alert_alarms)) { | ||
758 | pr_err("adt7461_alert:Disabling ALERT#\n"); | ||
759 | adt7461_read_reg(client, ADT7461_REG_R_CONFIG1, &config); | ||
760 | i2c_smbus_write_byte_data(client, ADT7461_REG_W_CONFIG1, | ||
761 | config | ALERT_BIT); | ||
762 | } | ||
763 | } | ||
764 | } | ||
765 | |||
766 | #ifdef CONFIG_PM | ||
767 | static int adt7461_suspend(struct i2c_client *client, pm_message_t state) | ||
768 | { | ||
769 | disable_irq(client->irq); | ||
770 | adt7461_disable(client); | ||
771 | |||
772 | return 0; | ||
773 | } | ||
774 | |||
775 | static int adt7461_resume(struct i2c_client *client) | ||
776 | { | ||
777 | adt7461_enable(client); | ||
778 | enable_irq(client->irq); | ||
779 | |||
780 | return 0; | ||
781 | } | ||
782 | #endif | ||
783 | |||
784 | /* | ||
785 | * Driver data | ||
786 | */ | ||
787 | static const struct i2c_device_id adt7461_id[] = { | ||
788 | { DRIVER_NAME, 0 }, | ||
789 | }; | ||
790 | |||
791 | MODULE_DEVICE_TABLE(i2c, adt7461_id); | ||
792 | |||
793 | static struct i2c_driver adt7461_driver = { | ||
794 | .class = I2C_CLASS_HWMON, | ||
795 | .driver = { | ||
796 | .name = DRIVER_NAME, | ||
797 | }, | ||
798 | .probe = adt7461_probe, | ||
799 | .remove = adt7461_remove, | ||
800 | .alert = adt7461_alert, | ||
801 | .id_table = adt7461_id, | ||
802 | #ifdef CONFIG_PM | ||
803 | .suspend = adt7461_suspend, | ||
804 | .resume = adt7461_resume, | ||
805 | #endif | ||
806 | }; | ||
807 | |||
808 | static int __init sensors_adt7461_init(void) | ||
809 | { | ||
810 | return i2c_add_driver(&adt7461_driver); | ||
811 | } | ||
812 | |||
813 | static void __exit sensors_adt7461_exit(void) | ||
814 | { | ||
815 | i2c_del_driver(&adt7461_driver); | ||
816 | } | ||
817 | |||
818 | MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>"); | ||
819 | MODULE_DESCRIPTION("ADT7461 driver"); | ||
820 | MODULE_LICENSE("GPL"); | ||
821 | |||
822 | module_init(sensors_adt7461_init); | ||
823 | module_exit(sensors_adt7461_exit); | ||
diff --git a/drivers/hwmon/ina219.c b/drivers/hwmon/ina219.c new file mode 100644 index 00000000000..cc5b85fdcf8 --- /dev/null +++ b/drivers/hwmon/ina219.c | |||
@@ -0,0 +1,414 @@ | |||
1 | /* | ||
2 | * ina219.c - driver for TI INA219 current / power monitor sensor | ||
3 | * | ||
4 | * Copyright (c) 2011, NVIDIA Corporation. | ||
5 | * | ||
6 | * The INA219 is a sensor chip made by Texas Instruments. It measures | ||
7 | * power, voltage and current on a power rail. | ||
8 | * Complete datasheet can be obtained from website: | ||
9 | * http://focus.ti.com/lit/ds/symlink/ina219.pdf | ||
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. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
16 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
18 | * more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License along | ||
21 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
22 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
23 | */ | ||
24 | |||
25 | #include <linux/module.h> | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/spinlock.h> | ||
28 | #include <linux/sysfs.h> | ||
29 | #include <linux/kobject.h> | ||
30 | #include <linux/hrtimer.h> | ||
31 | #include <linux/slab.h> | ||
32 | #include <linux/interrupt.h> | ||
33 | #include <linux/mutex.h> | ||
34 | #include <linux/i2c.h> | ||
35 | #include <linux/slab.h> | ||
36 | #include <linux/err.h> | ||
37 | #include <linux/gpio.h> | ||
38 | #include <linux/device.h> | ||
39 | #include <linux/sysdev.h> | ||
40 | #include "linux/ina219.h" | ||
41 | #include <linux/init.h> | ||
42 | #include <linux/hwmon-sysfs.h> | ||
43 | #include <linux/hwmon.h> | ||
44 | |||
45 | #define DRIVER_NAME "ina219" | ||
46 | |||
47 | /* INA219 register offsets */ | ||
48 | #define INA219_CONFIG 0 | ||
49 | #define INA219_SHUNT 1 | ||
50 | #define INA219_VOLTAGE 2 | ||
51 | #define INA219_POWER 3 | ||
52 | #define INA219_CURRENT 4 | ||
53 | #define INA219_CAL 5 | ||
54 | |||
55 | /* | ||
56 | INA219 Sensor defines | ||
57 | Config info for ina219s | ||
58 | D15 D14 D13 D12 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0 | ||
59 | rst BRNG PG1 PG0 BADC4 .-.BADC1 SADC4 - SADC1 MODE3 - MODE1 | ||
60 | reset D15 | ||
61 | bus_range=0 (d13) | ||
62 | pga_gain=0 (D12:D11) | ||
63 | bus_adc_setting=0x3 (d10:D7) 12-bit w/o oversampling (532uS) | ||
64 | shunt_adc_setting=0xb (D6:D3) 8x oversampling (4.26ms) | ||
65 | mode=0x7 (D2:D0) continuous shunt & bus | ||
66 | */ | ||
67 | #define INA219_CONFIG_DATA 0x1df | ||
68 | #define INA219_RESET 0x8000 | ||
69 | |||
70 | struct power_mon_data { | ||
71 | s32 voltage; | ||
72 | s32 currentInMillis; | ||
73 | s32 power; | ||
74 | }; | ||
75 | |||
76 | struct ina219_data { | ||
77 | struct device *hwmon_dev; | ||
78 | struct i2c_client *client; | ||
79 | struct ina219_platform_data *pInfo; | ||
80 | struct power_mon_data pm_data; | ||
81 | struct mutex mutex; | ||
82 | }; | ||
83 | |||
84 | /* Set non-zero to enable debug prints */ | ||
85 | #define INA219_DEBUG_PRINTS 0 | ||
86 | |||
87 | #if INA219_DEBUG_PRINTS | ||
88 | #define DEBUG_INA219(x) printk x | ||
89 | #else | ||
90 | #define DEBUG_INA219(x) | ||
91 | #endif | ||
92 | |||
93 | static s16 reorder_bytes(s16 a) | ||
94 | { | ||
95 | s16 ret = ((a >> 8) & 0xff) | ((a & 0xff) << 8); | ||
96 | return ret; | ||
97 | } | ||
98 | |||
99 | /* set ina219 to power down mode */ | ||
100 | static s32 power_down_INA219(struct i2c_client *client) | ||
101 | { | ||
102 | s32 retval; | ||
103 | retval = i2c_smbus_write_word_data(client, INA219_CONFIG, 0); | ||
104 | if (retval < 0) | ||
105 | dev_err(&client->dev, "power down failure sts: 0x%x\n", retval); | ||
106 | return retval; | ||
107 | } | ||
108 | |||
109 | static s32 show_rail_name(struct device *dev, | ||
110 | struct device_attribute *attr, | ||
111 | char *buf) | ||
112 | { | ||
113 | struct i2c_client *client = to_i2c_client(dev); | ||
114 | struct ina219_data *data = i2c_get_clientdata(client); | ||
115 | return sprintf(buf, "%s\n", data->pInfo->rail_name); | ||
116 | } | ||
117 | |||
118 | static s32 show_voltage(struct device *dev, | ||
119 | struct device_attribute *attr, | ||
120 | char *buf) | ||
121 | { | ||
122 | struct i2c_client *client = to_i2c_client(dev); | ||
123 | struct ina219_data *data = i2c_get_clientdata(client); | ||
124 | s32 retval; | ||
125 | s32 voltage_mV; | ||
126 | |||
127 | /* fill config data */ | ||
128 | retval = i2c_smbus_write_word_data(client, INA219_CONFIG, | ||
129 | reorder_bytes(INA219_CONFIG_DATA)); | ||
130 | if (retval < 0) { | ||
131 | dev_err(dev, "config data write failed sts: 0x%x\n", retval); | ||
132 | goto error; | ||
133 | } | ||
134 | |||
135 | /* fill calibration data */ | ||
136 | retval = i2c_smbus_write_word_data(client, INA219_CAL, | ||
137 | reorder_bytes(data->pInfo->calibration_data)); | ||
138 | if (retval < 0) { | ||
139 | dev_err(dev, "calib data write failed sts: 0x%x\n", retval); | ||
140 | goto error; | ||
141 | } | ||
142 | |||
143 | /* getting voltage readings in milli volts*/ | ||
144 | voltage_mV = | ||
145 | reorder_bytes(i2c_smbus_read_word_data(client, | ||
146 | INA219_VOLTAGE)); | ||
147 | DEBUG_INA219(("Ina219 voltage reg Value: 0x%x\n", voltage_mV)); | ||
148 | if (voltage_mV < 0) | ||
149 | goto error; | ||
150 | voltage_mV = voltage_mV >> 1; | ||
151 | DEBUG_INA219(("Ina219 voltage in mv: %d\n", voltage_mV)); | ||
152 | |||
153 | /* set ina219 to power down mode */ | ||
154 | retval = power_down_INA219(client); | ||
155 | if (retval < 0) | ||
156 | goto error; | ||
157 | |||
158 | DEBUG_INA219(("%s volt = %d\n", __func__, voltage_mV)); | ||
159 | return sprintf(buf, "%d mV\n", voltage_mV); | ||
160 | error: | ||
161 | dev_err(dev, "%s: failed\n", __func__); | ||
162 | return retval; | ||
163 | } | ||
164 | |||
165 | |||
166 | static s32 show_power(struct device *dev, | ||
167 | struct device_attribute *attr, | ||
168 | char *buf) | ||
169 | { | ||
170 | struct i2c_client *client = to_i2c_client(dev); | ||
171 | struct ina219_data *data = i2c_get_clientdata(client); | ||
172 | s32 retval; | ||
173 | s32 power_mW; | ||
174 | s32 voltage_mV; | ||
175 | s32 overflow, conversion; | ||
176 | |||
177 | /* fill config data */ | ||
178 | retval = i2c_smbus_write_word_data(client, INA219_CONFIG, | ||
179 | reorder_bytes(INA219_CONFIG_DATA)); | ||
180 | if (retval < 0) { | ||
181 | dev_err(dev, "config data write failed sts: 0x%x\n", retval); | ||
182 | goto error; | ||
183 | } | ||
184 | |||
185 | /* fill calib data */ | ||
186 | retval = i2c_smbus_write_word_data(client, INA219_CAL, | ||
187 | reorder_bytes(data->pInfo->calibration_data)); | ||
188 | if (retval < 0) { | ||
189 | dev_err(dev, "calibration data write failed sts: 0x%x\n", | ||
190 | retval); | ||
191 | goto error; | ||
192 | } | ||
193 | |||
194 | /* check if the readings are valid */ | ||
195 | do { | ||
196 | /* read power register to clear conversion bit */ | ||
197 | retval = reorder_bytes(i2c_smbus_read_word_data(client, | ||
198 | INA219_POWER)); | ||
199 | if (retval < 0) { | ||
200 | dev_err(dev, "CNVR bit clearing failure sts: 0x%x\n", | ||
201 | retval); | ||
202 | goto error; | ||
203 | } | ||
204 | |||
205 | voltage_mV = | ||
206 | reorder_bytes(i2c_smbus_read_word_data(client, | ||
207 | INA219_VOLTAGE)); | ||
208 | DEBUG_INA219(("Ina219 voltage reg Value: 0x%x\n", voltage_mV)); | ||
209 | overflow = voltage_mV & 1; | ||
210 | if (overflow) { | ||
211 | dev_err(dev, "overflow error\n"); | ||
212 | return 0; | ||
213 | } | ||
214 | conversion = (voltage_mV >> 1) & 1; | ||
215 | DEBUG_INA219(("\n ina219 CNVR value:%d", conversion)); | ||
216 | } while (!conversion); | ||
217 | |||
218 | /* getting power readings in milli watts*/ | ||
219 | power_mW = reorder_bytes(i2c_smbus_read_word_data(client, | ||
220 | INA219_POWER)); | ||
221 | DEBUG_INA219(("Ina219 power Reg: 0x%x\n", power_mW)); | ||
222 | power_mW *= data->pInfo->power_lsb; | ||
223 | DEBUG_INA219(("Ina219 power Val: %d\n", power_mW)); | ||
224 | if (power_mW < 0) | ||
225 | goto error; | ||
226 | |||
227 | /* set ina219 to power down mode */ | ||
228 | retval = power_down_INA219(client); | ||
229 | if (retval < 0) | ||
230 | goto error; | ||
231 | |||
232 | DEBUG_INA219(("%s pow = %d\n", __func__, power_mW)); | ||
233 | return sprintf(buf, "%d mW\n", power_mW); | ||
234 | error: | ||
235 | dev_err(dev, "%s: failed\n", __func__); | ||
236 | return retval; | ||
237 | } | ||
238 | |||
239 | static s32 show_current(struct device *dev, | ||
240 | struct device_attribute *attr, | ||
241 | char *buf) | ||
242 | { | ||
243 | struct i2c_client *client = to_i2c_client(dev); | ||
244 | struct ina219_data *data = i2c_get_clientdata(client); | ||
245 | s32 retval; | ||
246 | s32 current_mA; | ||
247 | s32 voltage_mV; | ||
248 | s32 overflow, conversion; | ||
249 | |||
250 | /* fill config data */ | ||
251 | retval = i2c_smbus_write_word_data(client, INA219_CONFIG, | ||
252 | reorder_bytes(INA219_CONFIG_DATA)); | ||
253 | if (retval < 0) { | ||
254 | dev_err(dev, "config data write failed sts: 0x%x\n", retval); | ||
255 | goto error; | ||
256 | } | ||
257 | |||
258 | /* fill calib data */ | ||
259 | retval = i2c_smbus_write_word_data(client, INA219_CAL, | ||
260 | reorder_bytes(data->pInfo->calibration_data)); | ||
261 | if (retval < 0) { | ||
262 | dev_err(dev, "calibration data write failed sts: 0x%x\n", | ||
263 | retval); | ||
264 | goto error; | ||
265 | } | ||
266 | |||
267 | /* check if the readings are valid */ | ||
268 | do { | ||
269 | /* read power register to clear conversion bit */ | ||
270 | retval = reorder_bytes(i2c_smbus_read_word_data(client, | ||
271 | INA219_POWER)); | ||
272 | if (retval < 0) { | ||
273 | dev_err(dev, "CNVR bit clearing failure sts: 0x%x\n", | ||
274 | retval); | ||
275 | goto error; | ||
276 | } | ||
277 | |||
278 | voltage_mV = | ||
279 | reorder_bytes(i2c_smbus_read_word_data(client, | ||
280 | INA219_VOLTAGE)); | ||
281 | DEBUG_INA219(("Ina219 voltage reg Value: 0x%x\n", voltage_mV)); | ||
282 | overflow = voltage_mV & 1; | ||
283 | if (overflow) { | ||
284 | dev_err(dev, "overflow error\n"); | ||
285 | return 0; | ||
286 | } | ||
287 | conversion = (voltage_mV >> 1) & 1; | ||
288 | DEBUG_INA219(("\n ina219 CNVR value:%d", conversion)); | ||
289 | } while (!conversion); | ||
290 | |||
291 | /* getting current readings in milli amps*/ | ||
292 | current_mA = reorder_bytes(i2c_smbus_read_word_data(client, | ||
293 | INA219_CURRENT)); | ||
294 | DEBUG_INA219(("Ina219 current Reg: 0x%x\n", current_mA)); | ||
295 | if (current_mA < 0) | ||
296 | goto error; | ||
297 | current_mA = | ||
298 | (current_mA * data->pInfo->power_lsb) / data->pInfo->divisor; | ||
299 | DEBUG_INA219(("Ina219 current Value: %d\n", current_mA)); | ||
300 | |||
301 | /* set ina219 to power down mode */ | ||
302 | retval = power_down_INA219(client); | ||
303 | if (retval < 0) | ||
304 | goto error; | ||
305 | |||
306 | |||
307 | DEBUG_INA219(("%s current = %d\n", __func__, current_mA)); | ||
308 | return sprintf(buf, "%d mA\n", current_mA); | ||
309 | error: | ||
310 | dev_err(dev, "%s: failed\n", __func__); | ||
311 | return retval; | ||
312 | } | ||
313 | |||
314 | static struct sensor_device_attribute ina219[] = { | ||
315 | SENSOR_ATTR(rail_name, S_IRUGO, show_rail_name, NULL, 0), | ||
316 | SENSOR_ATTR(in1_input, S_IRUGO, show_voltage, NULL, 0), | ||
317 | SENSOR_ATTR(curr1_input, S_IRUGO, show_current, NULL, 0), | ||
318 | SENSOR_ATTR(power1_input, S_IRUGO, show_power, NULL, 0), | ||
319 | }; | ||
320 | |||
321 | static int __devinit ina219_probe(struct i2c_client *client, | ||
322 | const struct i2c_device_id *id) | ||
323 | { | ||
324 | struct ina219_data *data; | ||
325 | int err; | ||
326 | u8 i; | ||
327 | data = kzalloc(sizeof(struct ina219_data), GFP_KERNEL); | ||
328 | if (!data) { | ||
329 | err = -ENOMEM; | ||
330 | goto exit; | ||
331 | } | ||
332 | |||
333 | i2c_set_clientdata(client, data); | ||
334 | data->pInfo = client->dev.platform_data; | ||
335 | mutex_init(&data->mutex); | ||
336 | /* reset ina219 */ | ||
337 | err = i2c_smbus_write_word_data(client, INA219_CONFIG, | ||
338 | reorder_bytes(INA219_RESET)); | ||
339 | if (err < 0) { | ||
340 | dev_err(&client->dev, "ina219 reset failure status: 0x%x\n", | ||
341 | err); | ||
342 | goto exit_free; | ||
343 | } | ||
344 | |||
345 | for (i = 0; i < ARRAY_SIZE(ina219); i++) { | ||
346 | err = device_create_file(&client->dev, &ina219[i].dev_attr); | ||
347 | if (err) { | ||
348 | dev_err(&client->dev, "device_create_file failed.\n"); | ||
349 | goto exit_free; | ||
350 | } | ||
351 | } | ||
352 | |||
353 | data->hwmon_dev = hwmon_device_register(&client->dev); | ||
354 | if (IS_ERR(data->hwmon_dev)) { | ||
355 | err = PTR_ERR(data->hwmon_dev); | ||
356 | goto exit_remove; | ||
357 | } | ||
358 | |||
359 | /* set ina219 to power down mode */ | ||
360 | err = power_down_INA219(client); | ||
361 | if (err < 0) | ||
362 | goto exit_remove; | ||
363 | |||
364 | return 0; | ||
365 | |||
366 | exit_remove: | ||
367 | for (i = 0; i < ARRAY_SIZE(ina219); i++) | ||
368 | device_remove_file(&client->dev, &ina219[i].dev_attr); | ||
369 | exit_free: | ||
370 | kfree(data); | ||
371 | exit: | ||
372 | return err; | ||
373 | } | ||
374 | |||
375 | static int __devexit ina219_remove(struct i2c_client *client) | ||
376 | { | ||
377 | u8 i; | ||
378 | struct ina219_data *data = i2c_get_clientdata(client); | ||
379 | hwmon_device_unregister(data->hwmon_dev); | ||
380 | for (i = 0; i < ARRAY_SIZE(ina219); i++) | ||
381 | device_remove_file(&client->dev, &ina219[i].dev_attr); | ||
382 | kfree(data); | ||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | static const struct i2c_device_id ina219_id[] = { | ||
387 | {DRIVER_NAME, 0 }, | ||
388 | {} | ||
389 | }; | ||
390 | MODULE_DEVICE_TABLE(i2c, ina219_id); | ||
391 | |||
392 | static struct i2c_driver ina219_driver = { | ||
393 | .class = I2C_CLASS_HWMON, | ||
394 | .driver = { | ||
395 | .name = DRIVER_NAME, | ||
396 | }, | ||
397 | .probe = ina219_probe, | ||
398 | .remove = __devexit_p(ina219_remove), | ||
399 | .id_table = ina219_id, | ||
400 | }; | ||
401 | |||
402 | static int __init ina219_init(void) | ||
403 | { | ||
404 | return i2c_add_driver(&ina219_driver); | ||
405 | } | ||
406 | |||
407 | static void __exit ina219_exit(void) | ||
408 | { | ||
409 | i2c_del_driver(&ina219_driver); | ||
410 | } | ||
411 | |||
412 | module_init(ina219_init); | ||
413 | module_exit(ina219_exit); | ||
414 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/hwmon/ina230.c b/drivers/hwmon/ina230.c new file mode 100644 index 00000000000..3591a946310 --- /dev/null +++ b/drivers/hwmon/ina230.c | |||
@@ -0,0 +1,561 @@ | |||
1 | /* | ||
2 | * ina230.c - driver for TI INA230 current / power monitor sensor | ||
3 | * (also compatible with TI INA226) | ||
4 | * | ||
5 | * | ||
6 | * Copyright (c) 2011, NVIDIA Corporation. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; version 2 of the License. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * The INA230(/INA226) is a sensor chip made by Texas Instruments. It measures | ||
23 | * power, voltage and current on a power rail and provides an alert on | ||
24 | * over voltage/power | ||
25 | * Complete datasheet can be obtained from ti.com | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | #include <linux/module.h> | ||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/spinlock.h> | ||
32 | #include <linux/sysfs.h> | ||
33 | #include <linux/kobject.h> | ||
34 | #include <linux/hrtimer.h> | ||
35 | #include <linux/slab.h> | ||
36 | #include <linux/interrupt.h> | ||
37 | #include <linux/mutex.h> | ||
38 | #include <linux/i2c.h> | ||
39 | #include <linux/slab.h> | ||
40 | #include <linux/err.h> | ||
41 | #include <linux/gpio.h> | ||
42 | #include <linux/device.h> | ||
43 | #include <linux/sysdev.h> | ||
44 | #include <linux/platform_data/ina230.h> | ||
45 | #include <linux/init.h> | ||
46 | #include <linux/hwmon-sysfs.h> | ||
47 | #include <linux/hwmon.h> | ||
48 | #include <linux/cpu.h> | ||
49 | |||
50 | |||
51 | #define DRIVER_NAME "ina230" | ||
52 | #define MEASURE_BUS_VOLT 0 | ||
53 | |||
54 | /* ina230 (/ ina226)register offsets */ | ||
55 | #define INA230_CONFIG 0 | ||
56 | #define INA230_SHUNT 1 | ||
57 | #define INA230_VOLTAGE 2 | ||
58 | #define INA230_POWER 3 | ||
59 | #define INA230_CURRENT 4 | ||
60 | #define INA230_CAL 5 | ||
61 | #define INA230_MASK 6 | ||
62 | #define INA230_ALERT 7 | ||
63 | |||
64 | /* | ||
65 | Config register for ina230 (/ ina226): | ||
66 | D15|D14 D13 D12|D11 D10 D09|D08 D07 D06|D05 D04 D03|D02 D01 D00 | ||
67 | rst|- - - |AVG |Vbus_CT |Vsh_CT |MODE | ||
68 | */ | ||
69 | #define INA230_RESET (1 << 15) | ||
70 | #define INA230_AVG (0 << 9) /* 0 Averages */ | ||
71 | #define INA230_VBUS_CT (0 << 6) /* Vbus 140us conversion time */ | ||
72 | #define INA230_VSH_CT (0 << 3) /* Vshunt 140us conversion time */ | ||
73 | |||
74 | #if MEASURE_BUS_VOLT | ||
75 | #define INA230_CONT_MODE 5 /* Continuous Shunt measurement */ | ||
76 | #define INA230_TRIG_MODE 1 /* Triggered Shunt measurement */ | ||
77 | #else | ||
78 | #define INA230_CONT_MODE 7 /* Continuous Bus and shunt measure */ | ||
79 | #define INA230_TRIG_MODE 3 /* Triggered Bus and shunt measure */ | ||
80 | #endif | ||
81 | |||
82 | #define INA230_POWER_DOWN 0 | ||
83 | #define INA230_CONT_CONFIG (INA230_AVG | INA230_VBUS_CT | \ | ||
84 | INA230_VSH_CT | INA230_CONT_MODE) | ||
85 | #define INA230_TRIG_CONFIG (INA230_AVG | INA230_VBUS_CT | \ | ||
86 | INA230_VSH_CT | INA230_TRIG_MODE) | ||
87 | |||
88 | /* | ||
89 | Mask register for ina230 (/ina 226): | ||
90 | D15|D14|D13|D12|D11 D10 D09 D08 D07 D06 D05 D04 D03 D02 D01 D00 | ||
91 | SOL|SUL|BOL|BUL|POL|CVR|- - - - - |AFF|CVF|OVF|APO|LEN | ||
92 | */ | ||
93 | #define INA230_MASK_SOL (1 << 15) | ||
94 | #define INA230_MASK_SUL (1 << 14) | ||
95 | |||
96 | |||
97 | struct ina230_data { | ||
98 | struct device *hwmon_dev; | ||
99 | struct i2c_client *client; | ||
100 | struct ina230_platform_data *pdata; | ||
101 | struct mutex mutex; | ||
102 | bool running; | ||
103 | struct notifier_block nb; | ||
104 | }; | ||
105 | |||
106 | |||
107 | /* bus voltage resolution: 1.25mv */ | ||
108 | #define busv_register_to_mv(x) (((x) * 5) >> 2) | ||
109 | |||
110 | /* shunt voltage resolution: 2.5uv */ | ||
111 | #define shuntv_register_to_uv(x) (((x) * 5) >> 1) | ||
112 | #define uv_to_alert_register(x) (((x) << 1) / 5) | ||
113 | |||
114 | |||
115 | |||
116 | static s32 ensure_enabled_start(struct i2c_client *client) | ||
117 | { | ||
118 | struct ina230_data *data = i2c_get_clientdata(client); | ||
119 | int retval; | ||
120 | |||
121 | if (data->running) | ||
122 | return 0; | ||
123 | |||
124 | retval = i2c_smbus_write_word_data(client, INA230_CONFIG, | ||
125 | __constant_cpu_to_be16(INA230_TRIG_CONFIG)); | ||
126 | if (retval < 0) | ||
127 | dev_err(&client->dev, "config data write failed sts: 0x%x\n", | ||
128 | retval); | ||
129 | |||
130 | return retval; | ||
131 | } | ||
132 | |||
133 | |||
134 | static void ensure_enabled_end(struct i2c_client *client) | ||
135 | { | ||
136 | struct ina230_data *data = i2c_get_clientdata(client); | ||
137 | int retval; | ||
138 | |||
139 | if (data->running) | ||
140 | return; | ||
141 | |||
142 | retval = i2c_smbus_write_word_data(client, INA230_CONFIG, | ||
143 | __constant_cpu_to_be16(INA230_POWER_DOWN)); | ||
144 | if (retval < 0) | ||
145 | dev_err(&client->dev, "power down failure sts: 0x%x\n", | ||
146 | retval); | ||
147 | } | ||
148 | |||
149 | |||
150 | static s32 __locked_power_down_ina230(struct i2c_client *client) | ||
151 | { | ||
152 | s32 retval; | ||
153 | struct ina230_data *data = i2c_get_clientdata(client); | ||
154 | |||
155 | if (!data->running) | ||
156 | return 0; | ||
157 | |||
158 | retval = i2c_smbus_write_word_data(client, INA230_MASK, 0); | ||
159 | if (retval < 0) | ||
160 | dev_err(&client->dev, "mask write failure sts: 0x%x\n", | ||
161 | retval); | ||
162 | |||
163 | retval = i2c_smbus_write_word_data(client, INA230_CONFIG, | ||
164 | __constant_cpu_to_be16(INA230_POWER_DOWN)); | ||
165 | if (retval < 0) | ||
166 | dev_err(&client->dev, "power down failure sts: 0x%x\n", | ||
167 | retval); | ||
168 | |||
169 | data->running = false; | ||
170 | |||
171 | return retval; | ||
172 | } | ||
173 | |||
174 | |||
175 | static s32 power_down_ina230(struct i2c_client *client) | ||
176 | { | ||
177 | s32 retval; | ||
178 | struct ina230_data *data = i2c_get_clientdata(client); | ||
179 | |||
180 | mutex_lock(&data->mutex); | ||
181 | retval = __locked_power_down_ina230(client); | ||
182 | mutex_unlock(&data->mutex); | ||
183 | |||
184 | return retval; | ||
185 | } | ||
186 | |||
187 | |||
188 | static s32 __locked_start_current_mon(struct i2c_client *client) | ||
189 | { | ||
190 | s32 retval; | ||
191 | s16 shunt_limit; | ||
192 | s16 alert_mask; | ||
193 | struct ina230_data *data = i2c_get_clientdata(client); | ||
194 | |||
195 | if (!data->pdata->current_threshold) { | ||
196 | dev_err(&client->dev, "no current threshold specified\n"); | ||
197 | return -EINVAL; | ||
198 | } | ||
199 | |||
200 | retval = i2c_smbus_write_word_data(client, INA230_CONFIG, | ||
201 | __constant_cpu_to_be16(INA230_CONT_CONFIG)); | ||
202 | if (retval < 0) { | ||
203 | dev_err(&client->dev, "config data write failed sts: 0x%x\n", | ||
204 | retval); | ||
205 | return retval; | ||
206 | } | ||
207 | |||
208 | shunt_limit = uv_to_alert_register(data->pdata->resistor * | ||
209 | data->pdata->current_threshold); | ||
210 | |||
211 | retval = i2c_smbus_write_word_data(client, INA230_ALERT, | ||
212 | cpu_to_be16(shunt_limit)); | ||
213 | if (retval < 0) { | ||
214 | dev_err(&client->dev, "alert data write failed sts: 0x%x\n", | ||
215 | retval); | ||
216 | return retval; | ||
217 | } | ||
218 | |||
219 | alert_mask = shunt_limit >= 0 ? INA230_MASK_SOL : INA230_MASK_SUL; | ||
220 | retval = i2c_smbus_write_word_data(client, INA230_MASK, | ||
221 | cpu_to_be16(alert_mask)); | ||
222 | if (retval < 0) { | ||
223 | dev_err(&client->dev, "mask data write failed sts: 0x%x\n", | ||
224 | retval); | ||
225 | return retval; | ||
226 | } | ||
227 | |||
228 | data->running = true; | ||
229 | |||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | |||
234 | static void __locked_evaluate_state(struct i2c_client *client) | ||
235 | { | ||
236 | struct ina230_data *data = i2c_get_clientdata(client); | ||
237 | int cpus = num_online_cpus(); | ||
238 | |||
239 | if (data->running) { | ||
240 | if (cpus < data->pdata->min_cores_online || | ||
241 | !data->pdata->current_threshold) | ||
242 | __locked_power_down_ina230(client); | ||
243 | } else { | ||
244 | if (cpus >= data->pdata->min_cores_online && | ||
245 | data->pdata->current_threshold) | ||
246 | __locked_start_current_mon(client); | ||
247 | } | ||
248 | } | ||
249 | |||
250 | |||
251 | static void evaluate_state(struct i2c_client *client) | ||
252 | { | ||
253 | struct ina230_data *data = i2c_get_clientdata(client); | ||
254 | |||
255 | mutex_lock(&data->mutex); | ||
256 | __locked_evaluate_state(client); | ||
257 | mutex_unlock(&data->mutex); | ||
258 | } | ||
259 | |||
260 | |||
261 | static s32 show_rail_name(struct device *dev, | ||
262 | struct device_attribute *attr, | ||
263 | char *buf) | ||
264 | { | ||
265 | struct i2c_client *client = to_i2c_client(dev); | ||
266 | struct ina230_data *data = i2c_get_clientdata(client); | ||
267 | return sprintf(buf, "%s\n", data->pdata->rail_name); | ||
268 | } | ||
269 | |||
270 | |||
271 | static s32 show_current_threshold(struct device *dev, | ||
272 | struct device_attribute *attr, | ||
273 | char *buf) | ||
274 | { | ||
275 | struct i2c_client *client = to_i2c_client(dev); | ||
276 | struct ina230_data *data = i2c_get_clientdata(client); | ||
277 | return sprintf(buf, "%d mA\n", data->pdata->current_threshold); | ||
278 | } | ||
279 | |||
280 | |||
281 | static s32 set_current_threshold(struct device *dev, | ||
282 | struct device_attribute *attr, | ||
283 | const char *buf, size_t count) | ||
284 | { | ||
285 | struct i2c_client *client = to_i2c_client(dev); | ||
286 | struct ina230_data *data = i2c_get_clientdata(client); | ||
287 | s32 retval; | ||
288 | |||
289 | mutex_lock(&data->mutex); | ||
290 | |||
291 | if (strict_strtol(buf, 10, (long *)&(data->pdata->current_threshold))) { | ||
292 | retval = -EINVAL; | ||
293 | goto out; | ||
294 | } | ||
295 | |||
296 | if (data->pdata->current_threshold) { | ||
297 | if (data->running) { | ||
298 | /* force restart */ | ||
299 | retval = __locked_start_current_mon(client); | ||
300 | } else { | ||
301 | __locked_evaluate_state(client); | ||
302 | retval = 0; | ||
303 | } | ||
304 | } else { | ||
305 | retval = __locked_power_down_ina230(client); | ||
306 | } | ||
307 | |||
308 | out: | ||
309 | mutex_unlock(&data->mutex); | ||
310 | if (retval >= 0) | ||
311 | return count; | ||
312 | return retval; | ||
313 | } | ||
314 | |||
315 | |||
316 | |||
317 | |||
318 | #if MEASURE_BUS_VOLT | ||
319 | static s32 show_bus_voltage(struct device *dev, | ||
320 | struct device_attribute *attr, | ||
321 | char *buf) | ||
322 | { | ||
323 | struct i2c_client *client = to_i2c_client(dev); | ||
324 | struct ina230_data *data = i2c_get_clientdata(client); | ||
325 | s32 voltage_mV; | ||
326 | int retval; | ||
327 | |||
328 | mutex_lock(&data->mutex); | ||
329 | retval = ensure_enabled_start(client); | ||
330 | if (retval < 0) { | ||
331 | mutex_unlock(&data->mutex); | ||
332 | return retval; | ||
333 | } | ||
334 | |||
335 | /* getting voltage readings in milli volts*/ | ||
336 | voltage_mV = | ||
337 | (s16)be16_to_cpu(i2c_smbus_read_word_data(client, | ||
338 | INA230_VOLTAGE)); | ||
339 | |||
340 | ensure_enabled_end(client); | ||
341 | mutex_unlock(&data->mutex); | ||
342 | |||
343 | if (voltage_mV < 0) { | ||
344 | dev_err(dev, "%s: failed\n", __func__); | ||
345 | return -1; | ||
346 | } | ||
347 | |||
348 | voltage_mV = busv_register_to_mv(voltage_mV); | ||
349 | |||
350 | return sprintf(buf, "%d mV\n", voltage_mV); | ||
351 | } | ||
352 | #endif | ||
353 | |||
354 | |||
355 | |||
356 | |||
357 | static s32 show_shunt_voltage(struct device *dev, | ||
358 | struct device_attribute *attr, | ||
359 | char *buf) | ||
360 | { | ||
361 | struct i2c_client *client = to_i2c_client(dev); | ||
362 | struct ina230_data *data = i2c_get_clientdata(client); | ||
363 | s32 voltage_uV; | ||
364 | int retval; | ||
365 | |||
366 | mutex_lock(&data->mutex); | ||
367 | retval = ensure_enabled_start(client); | ||
368 | if (retval < 0) { | ||
369 | mutex_unlock(&data->mutex); | ||
370 | return retval; | ||
371 | } | ||
372 | |||
373 | voltage_uV = | ||
374 | (s16)be16_to_cpu(i2c_smbus_read_word_data(client, | ||
375 | INA230_SHUNT)); | ||
376 | |||
377 | ensure_enabled_end(client); | ||
378 | mutex_unlock(&data->mutex); | ||
379 | |||
380 | voltage_uV = shuntv_register_to_uv(voltage_uV); | ||
381 | |||
382 | return sprintf(buf, "%d uV\n", voltage_uV); | ||
383 | } | ||
384 | |||
385 | |||
386 | static s32 show_current(struct device *dev, | ||
387 | struct device_attribute *attr, | ||
388 | char *buf) | ||
389 | { | ||
390 | struct i2c_client *client = to_i2c_client(dev); | ||
391 | struct ina230_data *data = i2c_get_clientdata(client); | ||
392 | s32 voltage_uV; | ||
393 | s32 current_mA; | ||
394 | int retval; | ||
395 | |||
396 | mutex_lock(&data->mutex); | ||
397 | retval = ensure_enabled_start(client); | ||
398 | if (retval < 0) { | ||
399 | mutex_unlock(&data->mutex); | ||
400 | return retval; | ||
401 | } | ||
402 | |||
403 | voltage_uV = | ||
404 | (s16)be16_to_cpu(i2c_smbus_read_word_data(client, | ||
405 | INA230_SHUNT)); | ||
406 | |||
407 | ensure_enabled_end(client); | ||
408 | mutex_unlock(&data->mutex); | ||
409 | |||
410 | voltage_uV = shuntv_register_to_uv(voltage_uV); | ||
411 | current_mA = voltage_uV / data->pdata->resistor; | ||
412 | |||
413 | return sprintf(buf, "%d mA\n", current_mA); | ||
414 | } | ||
415 | |||
416 | |||
417 | static int ina230_hotplug_notify(struct notifier_block *nb, unsigned long event, | ||
418 | void *hcpu) | ||
419 | { | ||
420 | struct ina230_data *data = container_of(nb, struct ina230_data, | ||
421 | nb); | ||
422 | struct i2c_client *client = data->client; | ||
423 | |||
424 | if (event == CPU_ONLINE || event == CPU_DEAD) | ||
425 | evaluate_state(client); | ||
426 | |||
427 | return 0; | ||
428 | } | ||
429 | |||
430 | |||
431 | |||
432 | static struct sensor_device_attribute ina230[] = { | ||
433 | SENSOR_ATTR(rail_name, S_IRUGO, show_rail_name, NULL, 0), | ||
434 | SENSOR_ATTR(current_threshold, S_IWUSR | S_IRUGO, | ||
435 | show_current_threshold, set_current_threshold, 0), | ||
436 | SENSOR_ATTR(shuntvolt1_input, S_IRUGO, show_shunt_voltage, NULL, 0), | ||
437 | SENSOR_ATTR(current1_input, S_IRUGO, show_current, NULL, 0), | ||
438 | #if MEASURE_BUS_VOLT | ||
439 | SENSOR_ATTR(busvolt1_input, S_IRUGO, show_bus_voltage, NULL, 0), | ||
440 | #endif | ||
441 | }; | ||
442 | |||
443 | |||
444 | static int __devinit ina230_probe(struct i2c_client *client, | ||
445 | const struct i2c_device_id *id) | ||
446 | { | ||
447 | struct ina230_data *data; | ||
448 | int err; | ||
449 | u8 i; | ||
450 | |||
451 | data = devm_kzalloc(&client->dev, sizeof(struct ina230_data), | ||
452 | GFP_KERNEL); | ||
453 | if (!data) { | ||
454 | err = -ENOMEM; | ||
455 | goto exit; | ||
456 | } | ||
457 | |||
458 | i2c_set_clientdata(client, data); | ||
459 | data->pdata = client->dev.platform_data; | ||
460 | data->running = false; | ||
461 | data->nb.notifier_call = ina230_hotplug_notify; | ||
462 | data->client = client; | ||
463 | mutex_init(&data->mutex); | ||
464 | |||
465 | err = i2c_smbus_write_word_data(client, INA230_CONFIG, | ||
466 | __constant_cpu_to_be16(INA230_RESET)); | ||
467 | if (err < 0) { | ||
468 | dev_err(&client->dev, "ina230 reset failure status: 0x%x\n", | ||
469 | err); | ||
470 | goto exit; | ||
471 | } | ||
472 | |||
473 | for (i = 0; i < ARRAY_SIZE(ina230); i++) { | ||
474 | err = device_create_file(&client->dev, &ina230[i].dev_attr); | ||
475 | if (err) { | ||
476 | dev_err(&client->dev, "device_create_file failed.\n"); | ||
477 | goto exit_remove; | ||
478 | } | ||
479 | } | ||
480 | |||
481 | data->hwmon_dev = hwmon_device_register(&client->dev); | ||
482 | if (IS_ERR(data->hwmon_dev)) { | ||
483 | err = PTR_ERR(data->hwmon_dev); | ||
484 | goto exit_remove; | ||
485 | } | ||
486 | |||
487 | register_hotcpu_notifier(&(data->nb)); | ||
488 | |||
489 | evaluate_state(client); | ||
490 | |||
491 | return 0; | ||
492 | |||
493 | exit_remove: | ||
494 | for (i = 0; i < ARRAY_SIZE(ina230); i++) | ||
495 | device_remove_file(&client->dev, &ina230[i].dev_attr); | ||
496 | exit: | ||
497 | return err; | ||
498 | } | ||
499 | |||
500 | |||
501 | static int __devexit ina230_remove(struct i2c_client *client) | ||
502 | { | ||
503 | u8 i; | ||
504 | struct ina230_data *data = i2c_get_clientdata(client); | ||
505 | unregister_hotcpu_notifier(&(data->nb)); | ||
506 | power_down_ina230(client); | ||
507 | hwmon_device_unregister(data->hwmon_dev); | ||
508 | for (i = 0; i < ARRAY_SIZE(ina230); i++) | ||
509 | device_remove_file(&client->dev, &ina230[i].dev_attr); | ||
510 | return 0; | ||
511 | } | ||
512 | |||
513 | |||
514 | static int ina230_suspend(struct i2c_client *client) | ||
515 | { | ||
516 | return power_down_ina230(client); | ||
517 | } | ||
518 | |||
519 | |||
520 | static int ina230_resume(struct i2c_client *client) | ||
521 | { | ||
522 | evaluate_state(client); | ||
523 | return 0; | ||
524 | } | ||
525 | |||
526 | |||
527 | static const struct i2c_device_id ina230_id[] = { | ||
528 | {DRIVER_NAME, 0 }, | ||
529 | {} | ||
530 | }; | ||
531 | MODULE_DEVICE_TABLE(i2c, ina230_id); | ||
532 | |||
533 | |||
534 | static struct i2c_driver ina230_driver = { | ||
535 | .class = I2C_CLASS_HWMON, | ||
536 | .driver = { | ||
537 | .name = DRIVER_NAME, | ||
538 | }, | ||
539 | .probe = ina230_probe, | ||
540 | .remove = __devexit_p(ina230_remove), | ||
541 | .suspend = ina230_suspend, | ||
542 | .resume = ina230_resume, | ||
543 | .id_table = ina230_id, | ||
544 | }; | ||
545 | |||
546 | |||
547 | static int __init ina230_init(void) | ||
548 | { | ||
549 | return i2c_add_driver(&ina230_driver); | ||
550 | } | ||
551 | |||
552 | |||
553 | static void __exit ina230_exit(void) | ||
554 | { | ||
555 | i2c_del_driver(&ina230_driver); | ||
556 | } | ||
557 | |||
558 | |||
559 | module_init(ina230_init); | ||
560 | module_exit(ina230_exit); | ||
561 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/hwmon/tegra-tsensor.c b/drivers/hwmon/tegra-tsensor.c new file mode 100644 index 00000000000..b4660338600 --- /dev/null +++ b/drivers/hwmon/tegra-tsensor.c | |||
@@ -0,0 +1,1949 @@ | |||
1 | /* | ||
2 | * NVIDIA Tegra SOC - temperature sensor driver | ||
3 | * | ||
4 | * Copyright (C) 2011 NVIDIA Corporation | ||
5 | * | ||
6 | * This software is licensed under the terms of the GNU General Public | ||
7 | * License version 2, as published by the Free Software Foundation, and | ||
8 | * may be copied, distributed, and modified under those terms. | ||
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 | |||
17 | #include <linux/slab.h> | ||
18 | #include <linux/mutex.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/hwmon.h> | ||
21 | #include <linux/clk.h> | ||
22 | #include <linux/io.h> | ||
23 | #include <linux/irq.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/irqreturn.h> | ||
26 | #include <linux/err.h> | ||
27 | #include <linux/spinlock.h> | ||
28 | #include <linux/hwmon-sysfs.h> | ||
29 | #include <linux/hwmon.h> | ||
30 | #include <linux/regulator/consumer.h> | ||
31 | #include <linux/delay.h> | ||
32 | |||
33 | #include <mach/iomap.h> | ||
34 | #include <mach/clk.h> | ||
35 | #include <mach/delay.h> | ||
36 | #include <mach/tsensor.h> | ||
37 | #include <mach/tegra_fuse.h> | ||
38 | |||
39 | /* macro to enable tsensor hw reset */ | ||
40 | /* FIXME: till tsensor temperature is reliable this should be 0 */ | ||
41 | #define ENABLE_TSENSOR_HW_RESET 0 | ||
42 | |||
43 | /* tsensor instance used for temperature calculation */ | ||
44 | #define TSENSOR_FUSE_REV1 8 | ||
45 | #define TSENSOR_FUSE_REV2 21 | ||
46 | |||
47 | /* version where tsensor temperature reading is accurate */ | ||
48 | #define STABLE_TSENSOR_FUSE_REV TSENSOR_FUSE_REV2 | ||
49 | |||
50 | /* We have multiple tsensor instances with following registers */ | ||
51 | #define SENSOR_CFG0 0x40 | ||
52 | #define SENSOR_CFG1 0x48 | ||
53 | #define SENSOR_CFG2 0x4c | ||
54 | #define SENSOR_STATUS0 0x58 | ||
55 | #define SENSOR_TS_STATUS1 0x5c | ||
56 | #define SENSOR_TS_STATUS2 0x60 | ||
57 | |||
58 | /* interrupt mask in tsensor status register */ | ||
59 | #define TSENSOR_SENSOR_X_STATUS0_0_INTR_MASK (1 << 8) | ||
60 | |||
61 | #define SENSOR_CFG0_M_MASK 0xffff | ||
62 | #define SENSOR_CFG0_M_SHIFT 8 | ||
63 | #define SENSOR_CFG0_N_MASK 0xff | ||
64 | #define SENSOR_CFG0_N_SHIFT 24 | ||
65 | #define SENSOR_CFG0_RST_INTR_SHIFT 6 | ||
66 | #define SENSOR_CFG0_HW_DIV2_INTR_SHIFT 5 | ||
67 | #define SENSOR_CFG0_OVERFLOW_INTR 4 | ||
68 | #define SENSOR_CFG0_DVFS_INTR_SHIFT 3 | ||
69 | #define SENSOR_CFG0_RST_ENABLE_SHIFT 2 | ||
70 | #define SENSOR_CFG0_HW_DIV2_ENABLE_SHIFT 1 | ||
71 | #define SENSOR_CFG0_STOP_SHIFT 0 | ||
72 | |||
73 | #define SENSOR_CFG_X_TH_X_MASK 0xffff | ||
74 | #define SENSOR_CFG1_TH2_SHIFT 16 | ||
75 | #define SENSOR_CFG1_TH1_SHIFT 0 | ||
76 | #define SENSOR_CFG2_TH3_SHIFT 0 | ||
77 | #define SENSOR_CFG2_TH0_SHIFT 16 | ||
78 | |||
79 | #define SENSOR_STATUS_AVG_VALID_SHIFT 10 | ||
80 | #define SENSOR_STATUS_CURR_VALID_SHIFT 9 | ||
81 | |||
82 | #define STATE_MASK 0x7 | ||
83 | #define STATUS0_STATE_SHIFT 0 | ||
84 | #define STATUS0_PREV_STATE_SHIFT 4 | ||
85 | |||
86 | #define LOCAL_STR_SIZE1 60 | ||
87 | #define MAX_STR_LINE 100 | ||
88 | #define MAX_TSENSOR_LOOP1 (1000 * 2) | ||
89 | |||
90 | #define TSENSOR_COUNTER_TOLERANCE 100 | ||
91 | |||
92 | #define SENSOR_CTRL_RST_SHIFT 1 | ||
93 | #define RST_SRC_MASK 0x7 | ||
94 | #define RST_SRC_SENSOR 2 | ||
95 | #define TEGRA_REV_REG_OFFSET 0x804 | ||
96 | #define CCLK_G_BURST_POLICY_REG_REL_OFFSET 0x368 | ||
97 | #define TSENSOR_SLOWDOWN_BIT 23 | ||
98 | |||
99 | /* macros used for temperature calculations */ | ||
100 | #define get_temperature_int(X) ((X) / 100) | ||
101 | #define get_temperature_fraction(X) (((int)(abs(X))) % 100) | ||
102 | #define get_temperature_round(X) DIV_ROUND_CLOSEST(X, 100) | ||
103 | |||
104 | #define MILLICELSIUS_TO_CELSIUS(i) ((i) / 1000) | ||
105 | #define CELSIUS_TO_MILLICELSIUS(i) ((i) * 1000) | ||
106 | |||
107 | #define get_ts_state(data) tsensor_get_reg_field(data,\ | ||
108 | ((data->instance << 16) | SENSOR_STATUS0), \ | ||
109 | STATUS0_STATE_SHIFT, STATE_MASK) | ||
110 | |||
111 | /* tsensor states */ | ||
112 | enum ts_state { | ||
113 | TS_INVALID = 0, | ||
114 | TS_LEVEL0, | ||
115 | TS_LEVEL1, | ||
116 | TS_LEVEL2, | ||
117 | TS_LEVEL3, | ||
118 | TS_OVERFLOW, | ||
119 | TS_MAX_STATE = TS_OVERFLOW | ||
120 | }; | ||
121 | |||
122 | enum { | ||
123 | /* temperature is sensed from 2 points on tegra */ | ||
124 | TSENSOR_COUNT = 2, | ||
125 | TSENSOR_INSTANCE1 = 0, | ||
126 | TSENSOR_INSTANCE2 = 1, | ||
127 | /* divide by 2 temperature threshold */ | ||
128 | DIV2_CELSIUS_TEMP_THRESHOLD_DEFAULT = 70, | ||
129 | /* reset chip temperature threshold */ | ||
130 | RESET_CELSIUS_TEMP_THRESHOLD_DEFAULT = 75, | ||
131 | /* tsensor frequency in Hz for clk src CLK_M and divisor=24 */ | ||
132 | DEFAULT_TSENSOR_CLK_HZ = 500000, | ||
133 | DEFAULT_TSENSOR_N = 255, | ||
134 | DEFAULT_TSENSOR_M = 12500, | ||
135 | /* tsensor instance offset */ | ||
136 | TSENSOR_INSTANCE_OFFSET = 0x40, | ||
137 | MIN_THRESHOLD = 0x0, | ||
138 | MAX_THRESHOLD = 0xffff, | ||
139 | DEFAULT_THRESHOLD_TH0 = MAX_THRESHOLD, | ||
140 | DEFAULT_THRESHOLD_TH1 = MAX_THRESHOLD, | ||
141 | DEFAULT_THRESHOLD_TH2 = MAX_THRESHOLD, | ||
142 | DEFAULT_THRESHOLD_TH3 = MAX_THRESHOLD, | ||
143 | }; | ||
144 | |||
145 | /* constants used to implement sysfs interface */ | ||
146 | enum tsensor_params { | ||
147 | TSENSOR_PARAM_TH1 = 0, | ||
148 | TSENSOR_PARAM_TH2, | ||
149 | TSENSOR_PARAM_TH3, | ||
150 | TSENSOR_TEMPERATURE, | ||
151 | TSENSOR_STATE, | ||
152 | TSENSOR_LIMITS, | ||
153 | }; | ||
154 | |||
155 | enum tsensor_thresholds { | ||
156 | TSENSOR_TH0 = 0, | ||
157 | TSENSOR_TH1, | ||
158 | TSENSOR_TH2, | ||
159 | TSENSOR_TH3 | ||
160 | }; | ||
161 | |||
162 | /* | ||
163 | * For each registered chip, we need to keep some data in memory. | ||
164 | * The structure is dynamically allocated. | ||
165 | */ | ||
166 | struct tegra_tsensor_data { | ||
167 | struct delayed_work work; | ||
168 | struct workqueue_struct *workqueue; | ||
169 | struct mutex mutex; | ||
170 | struct device *hwmon_dev; | ||
171 | spinlock_t tsensor_lock; | ||
172 | struct clk *dev_clk; | ||
173 | /* tsensor register space */ | ||
174 | void __iomem *base; | ||
175 | unsigned long phys; | ||
176 | unsigned long phys_end; | ||
177 | /* pmc register space */ | ||
178 | void __iomem *pmc_rst_base; | ||
179 | unsigned long pmc_phys; | ||
180 | unsigned long pmc_phys_end; | ||
181 | /* clk register space */ | ||
182 | void __iomem *clk_rst_base; | ||
183 | int irq; | ||
184 | |||
185 | /* save configuration before suspend and restore after resume */ | ||
186 | unsigned int config0[TSENSOR_COUNT]; | ||
187 | unsigned int config1[TSENSOR_COUNT]; | ||
188 | unsigned int config2[TSENSOR_COUNT]; | ||
189 | /* temperature readings from instance tsensor - 0/1 */ | ||
190 | unsigned int instance; | ||
191 | int A_e_minus6; | ||
192 | int B_e_minus2; | ||
193 | unsigned int fuse_T1; | ||
194 | unsigned int fuse_F1; | ||
195 | unsigned int fuse_T2; | ||
196 | unsigned int fuse_F2; | ||
197 | /* Quadratic fit coefficients: m=-0.003512 n=1.528943 p=-11.1 */ | ||
198 | int m_e_minus6; | ||
199 | int n_e_minus6; | ||
200 | int p_e_minus2; | ||
201 | |||
202 | long current_hi_limit; | ||
203 | long current_lo_limit; | ||
204 | |||
205 | bool is_edp_supported; | ||
206 | |||
207 | void (*alert_func)(void *); | ||
208 | void *alert_data; | ||
209 | }; | ||
210 | |||
211 | enum { | ||
212 | TSENSOR_COEFF_SET1 = 0, | ||
213 | TSENSOR_COEFF_SET2, | ||
214 | TSENSOR_COEFF_END | ||
215 | }; | ||
216 | |||
217 | struct tegra_tsensor_coeff { | ||
218 | int e_minus6_m; | ||
219 | int e_minus6_n; | ||
220 | int e_minus2_p; | ||
221 | }; | ||
222 | |||
223 | static struct tegra_tsensor_coeff coeff_table[] = { | ||
224 | /* Quadratic fit coefficients: m=-0.002775 n=1.338811 p=-7.30 */ | ||
225 | [TSENSOR_COEFF_SET1] = { | ||
226 | -2775, | ||
227 | 1338811, | ||
228 | -730 | ||
229 | }, | ||
230 | /* Quadratic fit coefficients: m=-0.003512 n=1.528943 p=-11.1 */ | ||
231 | [TSENSOR_COEFF_SET2] = { | ||
232 | -3512, | ||
233 | 1528943, | ||
234 | -1110 | ||
235 | } | ||
236 | /* FIXME: add tsensor coefficients after chip characterization */ | ||
237 | }; | ||
238 | |||
239 | /* pTemperature returned in 100 * Celsius */ | ||
240 | static int tsensor_count_2_temp(struct tegra_tsensor_data *data, | ||
241 | unsigned int count, int *p_temperature); | ||
242 | static unsigned int tsensor_get_threshold_counter( | ||
243 | struct tegra_tsensor_data *data, int temp); | ||
244 | |||
245 | /* tsensor register access functions */ | ||
246 | |||
247 | static void tsensor_writel(struct tegra_tsensor_data *data, u32 val, | ||
248 | unsigned long reg) | ||
249 | { | ||
250 | unsigned int reg_offset = reg & 0xffff; | ||
251 | unsigned char inst = (reg >> 16) & 0xffff; | ||
252 | writel(val, data->base + (inst * TSENSOR_INSTANCE_OFFSET) + | ||
253 | reg_offset); | ||
254 | return; | ||
255 | } | ||
256 | |||
257 | static unsigned int tsensor_readl(struct tegra_tsensor_data *data, | ||
258 | unsigned long reg) | ||
259 | { | ||
260 | unsigned int reg_offset = reg & 0xffff; | ||
261 | unsigned char inst = (reg >> 16) & 0xffff; | ||
262 | return readl(data->base + | ||
263 | (inst * TSENSOR_INSTANCE_OFFSET) + reg_offset); | ||
264 | } | ||
265 | |||
266 | static unsigned int tsensor_get_reg_field( | ||
267 | struct tegra_tsensor_data *data, unsigned int reg, | ||
268 | unsigned int shift, unsigned int mask) | ||
269 | { | ||
270 | unsigned int reg_val; | ||
271 | reg_val = tsensor_readl(data, reg); | ||
272 | return (reg_val & (mask << shift)) >> shift; | ||
273 | } | ||
274 | |||
275 | static int tsensor_set_reg_field( | ||
276 | struct tegra_tsensor_data *data, unsigned int value, | ||
277 | unsigned int reg, unsigned int shift, unsigned int mask) | ||
278 | { | ||
279 | unsigned int reg_val; | ||
280 | unsigned int rd_val; | ||
281 | reg_val = tsensor_readl(data, reg); | ||
282 | reg_val &= ~(mask << shift); | ||
283 | reg_val |= ((value & mask) << shift); | ||
284 | tsensor_writel(data, reg_val, reg); | ||
285 | rd_val = tsensor_readl(data, reg); | ||
286 | if (rd_val == reg_val) | ||
287 | return 0; | ||
288 | else | ||
289 | return -EINVAL; | ||
290 | } | ||
291 | |||
292 | /* enable argument is true to enable reset, false disables pmc reset */ | ||
293 | static void pmc_rst_enable(struct tegra_tsensor_data *data, bool enable) | ||
294 | { | ||
295 | unsigned int val; | ||
296 | /* mapped first pmc reg is SENSOR_CTRL */ | ||
297 | val = readl(data->pmc_rst_base); | ||
298 | if (enable) | ||
299 | val |= (1 << SENSOR_CTRL_RST_SHIFT); | ||
300 | else | ||
301 | val &= ~(1 << SENSOR_CTRL_RST_SHIFT); | ||
302 | writel(val, data->pmc_rst_base); | ||
303 | } | ||
304 | |||
305 | /* true returned when pmc reset source is tsensor */ | ||
306 | static bool pmc_check_rst_sensor(struct tegra_tsensor_data *data) | ||
307 | { | ||
308 | unsigned int val; | ||
309 | unsigned char src; | ||
310 | val = readl(data->pmc_rst_base + 4); | ||
311 | src = (unsigned char)(val & RST_SRC_MASK); | ||
312 | if (src == RST_SRC_SENSOR) | ||
313 | return true; | ||
314 | else | ||
315 | return false; | ||
316 | } | ||
317 | |||
318 | /* function to get chip revision */ | ||
319 | static void get_chip_rev(unsigned short *p_id, unsigned short *p_major, | ||
320 | unsigned short *p_minor) | ||
321 | { | ||
322 | unsigned int reg; | ||
323 | |||
324 | reg = readl(IO_TO_VIRT(TEGRA_APB_MISC_BASE) + | ||
325 | TEGRA_REV_REG_OFFSET); | ||
326 | *p_id = (reg >> 8) & 0xff; | ||
327 | *p_major = (reg >> 4) & 0xf; | ||
328 | *p_minor = (reg >> 16) & 0xf; | ||
329 | pr_info("Tegra chip revision for tsensor detected as: " | ||
330 | "Chip Id=%x, Major=%d, Minor=%d\n", (int)*p_id, | ||
331 | (int)*p_major, (int)*p_minor); | ||
332 | } | ||
333 | |||
334 | /* | ||
335 | * function to get chip revision specific tsensor coefficients | ||
336 | * obtained after chip characterization | ||
337 | */ | ||
338 | static void get_chip_tsensor_coeff(struct tegra_tsensor_data *data) | ||
339 | { | ||
340 | unsigned short chip_id, major_rev, minor_rev; | ||
341 | unsigned short coeff_index; | ||
342 | |||
343 | get_chip_rev(&chip_id, &major_rev, &minor_rev); | ||
344 | switch (minor_rev) { | ||
345 | default: | ||
346 | pr_info("Warning: tsensor coefficient for chip pending\n"); | ||
347 | case 1: | ||
348 | coeff_index = TSENSOR_COEFF_SET1; | ||
349 | break; | ||
350 | } | ||
351 | if (data->instance == TSENSOR_INSTANCE1) | ||
352 | coeff_index = TSENSOR_COEFF_SET2; | ||
353 | data->m_e_minus6 = coeff_table[coeff_index].e_minus6_m; | ||
354 | data->n_e_minus6 = coeff_table[coeff_index].e_minus6_n; | ||
355 | data->p_e_minus2 = coeff_table[coeff_index].e_minus2_p; | ||
356 | } | ||
357 | |||
358 | /* tsensor counter read function */ | ||
359 | static int tsensor_read_counter( | ||
360 | struct tegra_tsensor_data *data, | ||
361 | unsigned int *p_counter) | ||
362 | { | ||
363 | unsigned int status_reg; | ||
364 | unsigned int config0; | ||
365 | int iter_count = 0; | ||
366 | const int max_loop = 50; | ||
367 | |||
368 | do { | ||
369 | config0 = tsensor_readl(data, ((data->instance << 16) | | ||
370 | SENSOR_CFG0)); | ||
371 | if (config0 & (1 << SENSOR_CFG0_STOP_SHIFT)) { | ||
372 | dev_dbg(data->hwmon_dev, "Error: tsensor " | ||
373 | "counter read with STOP bit not supported\n"); | ||
374 | *p_counter = 0; | ||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | status_reg = tsensor_readl(data, | ||
379 | (data->instance << 16) | SENSOR_STATUS0); | ||
380 | if (status_reg & (1 << | ||
381 | SENSOR_STATUS_CURR_VALID_SHIFT)) { | ||
382 | *p_counter = tsensor_readl(data, (data->instance | ||
383 | << 16) | SENSOR_TS_STATUS1); | ||
384 | break; | ||
385 | } | ||
386 | if (!(iter_count % 10)) | ||
387 | dev_dbg(data->hwmon_dev, "retry %d\n", iter_count); | ||
388 | |||
389 | msleep(21); | ||
390 | iter_count++; | ||
391 | } while (iter_count < max_loop); | ||
392 | |||
393 | if (iter_count == max_loop) | ||
394 | return -ENODEV; | ||
395 | |||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | /* tsensor threshold print function */ | ||
400 | static void dump_threshold(struct tegra_tsensor_data *data) | ||
401 | { | ||
402 | unsigned int TH_2_1, TH_0_3; | ||
403 | unsigned int curr_avg; | ||
404 | int err; | ||
405 | |||
406 | TH_2_1 = tsensor_readl(data, (data->instance << 16) | SENSOR_CFG1); | ||
407 | TH_0_3 = tsensor_readl(data, (data->instance << 16) | SENSOR_CFG2); | ||
408 | dev_dbg(data->hwmon_dev, "Tsensor: TH_2_1=0x%x, " | ||
409 | "TH_0_3=0x%x\n", TH_2_1, TH_0_3); | ||
410 | err = tsensor_read_counter(data, &curr_avg); | ||
411 | if (err < 0) | ||
412 | pr_err("Error: tsensor counter read, " | ||
413 | "err=%d\n", err); | ||
414 | else | ||
415 | dev_dbg(data->hwmon_dev, "Tsensor: " | ||
416 | "curr_avg=0x%x\n", curr_avg); | ||
417 | } | ||
418 | |||
419 | static int tsensor_get_temperature( | ||
420 | struct tegra_tsensor_data *data, | ||
421 | int *pTemp, unsigned int *pCounter) | ||
422 | { | ||
423 | int err = 0; | ||
424 | unsigned int curr_avg; | ||
425 | |||
426 | err = tsensor_read_counter(data, &curr_avg); | ||
427 | if (err < 0) | ||
428 | goto error; | ||
429 | |||
430 | *pCounter = ((curr_avg & 0xFFFF0000) >> 16); | ||
431 | err = tsensor_count_2_temp(data, *pCounter, pTemp); | ||
432 | |||
433 | error: | ||
434 | return err; | ||
435 | } | ||
436 | |||
437 | static ssize_t tsensor_show_state(struct device *dev, | ||
438 | struct device_attribute *da, char *buf) | ||
439 | { | ||
440 | int state; | ||
441 | struct tegra_tsensor_data *data = dev_get_drvdata(dev); | ||
442 | |||
443 | state = get_ts_state(data); | ||
444 | |||
445 | return snprintf(buf, 50, "%d\n", state); | ||
446 | } | ||
447 | |||
448 | static ssize_t tsensor_show_limits(struct device *dev, | ||
449 | struct device_attribute *da, char *buf) | ||
450 | { | ||
451 | struct tegra_tsensor_data *data = dev_get_drvdata(dev); | ||
452 | return snprintf(buf, 50, "%ld %ld\n", | ||
453 | data->current_lo_limit, data->current_hi_limit); | ||
454 | } | ||
455 | |||
456 | /* tsensor temperature show function */ | ||
457 | static ssize_t tsensor_show_counters(struct device *dev, | ||
458 | struct device_attribute *da, char *buf) | ||
459 | { | ||
460 | unsigned int curr_avg; | ||
461 | char err_str[] = "error-sysfs-counter-read\n"; | ||
462 | char fixed_str[MAX_STR_LINE]; | ||
463 | struct tegra_tsensor_data *data = dev_get_drvdata(dev); | ||
464 | struct sensor_device_attribute *attr = to_sensor_dev_attr(da); | ||
465 | int err; | ||
466 | int temp; | ||
467 | |||
468 | if (attr->index == TSENSOR_TEMPERATURE) { | ||
469 | /* use current counter value to calculate temperature */ | ||
470 | err = tsensor_read_counter(data, &curr_avg); | ||
471 | if (err < 0) | ||
472 | goto error; | ||
473 | err = tsensor_count_2_temp(data, | ||
474 | ((curr_avg & 0xFFFF0000) >> 16), &temp); | ||
475 | if (err < 0) | ||
476 | goto error; | ||
477 | |||
478 | dev_vdbg(data->hwmon_dev, "%s has curr_avg=0x%x, " | ||
479 | "temp0=%d\n", __func__, curr_avg, temp); | ||
480 | |||
481 | snprintf(buf, (((LOCAL_STR_SIZE1 << 1) + 3) + | ||
482 | strlen(fixed_str)), | ||
483 | "%d.%02dC\n", | ||
484 | get_temperature_int(temp), | ||
485 | get_temperature_fraction(temp)); | ||
486 | } | ||
487 | return strlen(buf); | ||
488 | error: | ||
489 | return snprintf(buf, strlen(err_str), "%s", err_str); | ||
490 | } | ||
491 | |||
492 | /* utility function to check hw clock divide by 2 condition */ | ||
493 | static bool cclkg_check_hwdiv2_sensor(struct tegra_tsensor_data *data) | ||
494 | { | ||
495 | unsigned int val; | ||
496 | val = readl(IO_ADDRESS(TEGRA_CLK_RESET_BASE + | ||
497 | CCLK_G_BURST_POLICY_REG_REL_OFFSET)); | ||
498 | if ((1 << TSENSOR_SLOWDOWN_BIT) & val) { | ||
499 | dev_err(data->hwmon_dev, "Warning: ***** tsensor " | ||
500 | "slowdown bit detected\n"); | ||
501 | return true; | ||
502 | } else { | ||
503 | return false; | ||
504 | } | ||
505 | } | ||
506 | |||
507 | /* | ||
508 | * function with table to return register, field shift and mask | ||
509 | * values for supported parameters | ||
510 | */ | ||
511 | static int get_param_values( | ||
512 | struct tegra_tsensor_data *data, unsigned int indx, | ||
513 | unsigned int *p_reg, unsigned int *p_sft, unsigned int *p_msk, | ||
514 | char *info, size_t info_len) | ||
515 | { | ||
516 | switch (indx) { | ||
517 | case TSENSOR_PARAM_TH1: | ||
518 | *p_reg = ((data->instance << 16) | SENSOR_CFG1); | ||
519 | *p_sft = SENSOR_CFG1_TH1_SHIFT; | ||
520 | *p_msk = SENSOR_CFG_X_TH_X_MASK; | ||
521 | snprintf(info, info_len, "TH1[%d]: ", | ||
522 | data->instance); | ||
523 | break; | ||
524 | case TSENSOR_PARAM_TH2: | ||
525 | *p_reg = ((data->instance << 16) | SENSOR_CFG1); | ||
526 | *p_sft = SENSOR_CFG1_TH2_SHIFT; | ||
527 | *p_msk = SENSOR_CFG_X_TH_X_MASK; | ||
528 | snprintf(info, info_len, "TH2[%d]: ", | ||
529 | data->instance); | ||
530 | break; | ||
531 | case TSENSOR_PARAM_TH3: | ||
532 | *p_reg = ((data->instance << 16) | SENSOR_CFG2); | ||
533 | *p_sft = SENSOR_CFG2_TH3_SHIFT; | ||
534 | *p_msk = SENSOR_CFG_X_TH_X_MASK; | ||
535 | snprintf(info, info_len, "TH3[%d]: ", | ||
536 | data->instance); | ||
537 | break; | ||
538 | default: | ||
539 | return -ENOENT; | ||
540 | } | ||
541 | return 0; | ||
542 | } | ||
543 | |||
544 | /* tsensor driver sysfs show function */ | ||
545 | static ssize_t show_tsensor_param(struct device *dev, | ||
546 | struct device_attribute *da, | ||
547 | char *buf) | ||
548 | { | ||
549 | unsigned int val; | ||
550 | struct tegra_tsensor_data *data = dev_get_drvdata(dev); | ||
551 | struct sensor_device_attribute *attr = to_sensor_dev_attr(da); | ||
552 | unsigned int reg; | ||
553 | unsigned int sft; | ||
554 | unsigned int msk; | ||
555 | int err; | ||
556 | int temp; | ||
557 | char info[LOCAL_STR_SIZE1]; | ||
558 | |||
559 | err = get_param_values(data, attr->index, ®, &sft, &msk, | ||
560 | info, sizeof(info)); | ||
561 | if (err < 0) | ||
562 | goto labelErr; | ||
563 | val = tsensor_get_reg_field(data, reg, sft, msk); | ||
564 | if (val == MAX_THRESHOLD) | ||
565 | snprintf(buf, PAGE_SIZE, "%s un-initialized threshold\n", info); | ||
566 | else { | ||
567 | err = tsensor_count_2_temp(data, val, &temp); | ||
568 | if (err != 0) | ||
569 | goto labelErr; | ||
570 | snprintf(buf, PAGE_SIZE, "%s threshold: %d.%d Celsius\n", info, | ||
571 | get_temperature_int(temp), | ||
572 | get_temperature_fraction(temp)); | ||
573 | } | ||
574 | return strlen(buf); | ||
575 | |||
576 | labelErr: | ||
577 | snprintf(buf, PAGE_SIZE, "ERROR:"); | ||
578 | return strlen(buf); | ||
579 | } | ||
580 | |||
581 | /* tsensor driver sysfs store function */ | ||
582 | static ssize_t set_tsensor_param(struct device *dev, | ||
583 | struct device_attribute *da, | ||
584 | const char *buf, size_t count) | ||
585 | { | ||
586 | int num; | ||
587 | struct tegra_tsensor_data *data = dev_get_drvdata(dev); | ||
588 | struct sensor_device_attribute *attr = to_sensor_dev_attr(da); | ||
589 | unsigned int reg; | ||
590 | unsigned int sft; | ||
591 | unsigned int msk; | ||
592 | int err; | ||
593 | unsigned int counter; | ||
594 | unsigned int val; | ||
595 | char info[LOCAL_STR_SIZE1]; | ||
596 | |||
597 | if (kstrtoint(buf, 0, &num)) { | ||
598 | dev_err(dev, "file: %s, line=%d return %s()\n", | ||
599 | __FILE__, __LINE__, __func__); | ||
600 | return -EINVAL; | ||
601 | } | ||
602 | |||
603 | counter = tsensor_get_threshold_counter(data, num); | ||
604 | |||
605 | err = get_param_values(data, attr->index, ®, &sft, &msk, | ||
606 | info, sizeof(info)); | ||
607 | if (err < 0) | ||
608 | goto labelErr; | ||
609 | |||
610 | err = tsensor_set_reg_field(data, counter, reg, sft, msk); | ||
611 | if (err < 0) | ||
612 | goto labelErr; | ||
613 | |||
614 | /* TH2 clk divide check */ | ||
615 | if (attr->index == TSENSOR_PARAM_TH2) { | ||
616 | msleep(21); | ||
617 | (void)cclkg_check_hwdiv2_sensor(data); | ||
618 | } | ||
619 | val = tsensor_get_reg_field(data, reg, sft, msk); | ||
620 | dev_dbg(dev, "%s 0x%x\n", info, val); | ||
621 | return count; | ||
622 | labelErr: | ||
623 | dev_err(dev, "file: %s, line=%d, %s(), error=0x%x\n", __FILE__, | ||
624 | __LINE__, __func__, err); | ||
625 | return 0; | ||
626 | } | ||
627 | |||
628 | static struct sensor_device_attribute tsensor_nodes[] = { | ||
629 | SENSOR_ATTR(tsensor_TH1, S_IRUGO | S_IWUSR, | ||
630 | show_tsensor_param, set_tsensor_param, TSENSOR_PARAM_TH1), | ||
631 | SENSOR_ATTR(tsensor_TH2, S_IRUGO | S_IWUSR, | ||
632 | show_tsensor_param, set_tsensor_param, TSENSOR_PARAM_TH2), | ||
633 | SENSOR_ATTR(tsensor_TH3, S_IRUGO | S_IWUSR, | ||
634 | show_tsensor_param, set_tsensor_param, TSENSOR_PARAM_TH3), | ||
635 | SENSOR_ATTR(tsensor_temperature, S_IRUGO | S_IWUSR, | ||
636 | tsensor_show_counters, NULL, TSENSOR_TEMPERATURE), | ||
637 | SENSOR_ATTR(tsensor_state, S_IRUGO | S_IWUSR, | ||
638 | tsensor_show_state, NULL, TSENSOR_STATE), | ||
639 | SENSOR_ATTR(tsensor_limits, S_IRUGO | S_IWUSR, | ||
640 | tsensor_show_limits, NULL, TSENSOR_LIMITS), | ||
641 | }; | ||
642 | |||
643 | int tsensor_thermal_get_temp_low(struct tegra_tsensor_data *data, | ||
644 | long *milli_temp) | ||
645 | { | ||
646 | /* temp to counter below 20C seems to be inaccurate */ | ||
647 | *milli_temp = 20000; | ||
648 | return 0; | ||
649 | } | ||
650 | |||
651 | int tsensor_thermal_get_temp(struct tegra_tsensor_data *data, | ||
652 | long *milli_temp) | ||
653 | { | ||
654 | int counter, temp, err; | ||
655 | int temp_state, ts_state; | ||
656 | |||
657 | err = tsensor_get_temperature(data, | ||
658 | &temp, | ||
659 | &counter); | ||
660 | if (err) | ||
661 | return err; | ||
662 | |||
663 | temp *= 10; | ||
664 | |||
665 | mutex_lock(&data->mutex); | ||
666 | |||
667 | /* This section of logic is done in order to make sure that | ||
668 | * the temperature read corresponds to the current hw state. | ||
669 | * If it is not, return the nearest temperature | ||
670 | */ | ||
671 | if ((data->current_lo_limit != 0) || | ||
672 | (data->current_hi_limit)) { | ||
673 | |||
674 | if (temp <= data->current_lo_limit) | ||
675 | temp_state = TS_LEVEL0; | ||
676 | else if (temp < data->current_hi_limit) | ||
677 | temp_state = TS_LEVEL1; | ||
678 | else | ||
679 | temp_state = TS_LEVEL2; | ||
680 | |||
681 | ts_state = get_ts_state(data); | ||
682 | |||
683 | if (ts_state != temp_state) { | ||
684 | |||
685 | switch (ts_state) { | ||
686 | case TS_LEVEL0: | ||
687 | temp = data->current_lo_limit - 1; | ||
688 | break; | ||
689 | case TS_LEVEL1: | ||
690 | if (temp_state == TS_LEVEL0) | ||
691 | temp = data->current_lo_limit + 1; | ||
692 | else | ||
693 | temp = data->current_hi_limit - 1; | ||
694 | break; | ||
695 | case TS_LEVEL2: | ||
696 | temp = data->current_hi_limit + 1; | ||
697 | break; | ||
698 | } | ||
699 | |||
700 | } | ||
701 | |||
702 | } | ||
703 | |||
704 | mutex_unlock(&data->mutex); | ||
705 | |||
706 | *milli_temp = temp; | ||
707 | |||
708 | return 0; | ||
709 | } | ||
710 | |||
711 | /* tsensor driver interrupt handler */ | ||
712 | static irqreturn_t tegra_tsensor_isr(int irq, void *arg_data) | ||
713 | { | ||
714 | struct tegra_tsensor_data *data = | ||
715 | (struct tegra_tsensor_data *)arg_data; | ||
716 | unsigned long flags; | ||
717 | unsigned int val; | ||
718 | int new_state; | ||
719 | |||
720 | spin_lock_irqsave(&data->tsensor_lock, flags); | ||
721 | |||
722 | val = tsensor_readl(data, (data->instance << 16) | SENSOR_STATUS0); | ||
723 | if (val & TSENSOR_SENSOR_X_STATUS0_0_INTR_MASK) { | ||
724 | new_state = get_ts_state(data); | ||
725 | |||
726 | /* counter overflow check */ | ||
727 | if (new_state == TS_OVERFLOW) | ||
728 | dev_err(data->hwmon_dev, "Warning: " | ||
729 | "***** OVERFLOW tsensor\n"); | ||
730 | |||
731 | /* We only care if we go above hi or below low thresholds */ | ||
732 | if (data->is_edp_supported && new_state != TS_LEVEL1) | ||
733 | queue_delayed_work(data->workqueue, &data->work, 0); | ||
734 | } | ||
735 | |||
736 | tsensor_writel(data, val, (data->instance << 16) | SENSOR_STATUS0); | ||
737 | |||
738 | spin_unlock_irqrestore(&data->tsensor_lock, flags); | ||
739 | |||
740 | return IRQ_HANDLED; | ||
741 | } | ||
742 | |||
743 | /* | ||
744 | * function to read fuse registers and give - T1, T2, F1 and F2 | ||
745 | */ | ||
746 | static int read_tsensor_fuse_regs(struct tegra_tsensor_data *data) | ||
747 | { | ||
748 | unsigned int reg1; | ||
749 | unsigned int T1 = 0, T2 = 0; | ||
750 | unsigned int spare_bits; | ||
751 | int err; | ||
752 | |||
753 | /* read tsensor calibration register */ | ||
754 | /* | ||
755 | * High (~90 DegC) Temperature Calibration value (upper 16 bits of | ||
756 | * FUSE_TSENSOR_CALIB_0) - F2 | ||
757 | * Low (~25 deg C) Temperature Calibration value (lower 16 bits of | ||
758 | * FUSE_TSENSOR_CALIB_0) - F1 | ||
759 | */ | ||
760 | err = tegra_fuse_get_tsensor_calibration_data(®1); | ||
761 | if (err) | ||
762 | goto errLabel; | ||
763 | data->fuse_F1 = reg1 & 0xFFFF; | ||
764 | data->fuse_F2 = (reg1 >> 16) & 0xFFFF; | ||
765 | |||
766 | err = tegra_fuse_get_tsensor_spare_bits(&spare_bits); | ||
767 | if (err) { | ||
768 | pr_err("tsensor spare bit fuse read error=%d\n", err); | ||
769 | goto errLabel; | ||
770 | } | ||
771 | |||
772 | /* | ||
773 | * FUSE_TJ_ADT_LOWT = T1, FUSE_TJ_ADJ = T2 | ||
774 | */ | ||
775 | |||
776 | /* | ||
777 | * Low temp is: | ||
778 | * FUSE_TJ_ADT_LOWT = bits [20:14] or’ed with bits [27:21] | ||
779 | */ | ||
780 | T1 = ((spare_bits >> 14) & 0x7F) | | ||
781 | ((spare_bits >> 21) & 0x7F); | ||
782 | dev_vdbg(data->hwmon_dev, "Tsensor low temp (T1) fuse :\n"); | ||
783 | |||
784 | /* | ||
785 | * High temp is: | ||
786 | * FUSE_TJ_ADJ = bits [6:0] or’ed with bits [13:7] | ||
787 | */ | ||
788 | dev_vdbg(data->hwmon_dev, "Tsensor low temp (T2) fuse :\n"); | ||
789 | T2 = (spare_bits & 0x7F) | ((spare_bits >> 7) & 0x7F); | ||
790 | pr_info("Tsensor fuse calibration F1=%d, F2=%d, T1=%d, T2=%d\n" | ||
791 | , data->fuse_F1, data->fuse_F2, T1, T2); | ||
792 | data->fuse_T1 = T1; | ||
793 | data->fuse_T2 = T2; | ||
794 | return 0; | ||
795 | errLabel: | ||
796 | return err; | ||
797 | } | ||
798 | |||
799 | /* function to calculate interim temperature */ | ||
800 | static int calc_interim_temp(struct tegra_tsensor_data *data, | ||
801 | unsigned int counter, int *p_interim_temp) | ||
802 | { | ||
803 | int val1; | ||
804 | /* | ||
805 | * T-int = A * Counter + B | ||
806 | * (Counter is the sensor frequency output) | ||
807 | */ | ||
808 | if ((data->fuse_F2 - data->fuse_F1) <= (data->fuse_T2 - | ||
809 | data->fuse_T1)) { | ||
810 | dev_err(data->hwmon_dev, "Error: F2=%d, F1=%d " | ||
811 | "difference unexpectedly low. " | ||
812 | "Aborting temperature processing\n", data->fuse_F2, | ||
813 | data->fuse_F1); | ||
814 | return -EINVAL; | ||
815 | } else { | ||
816 | /* expression modified after assuming s_A is 10^6 times, | ||
817 | * s_B is 10^2 times and want end result to be 10^2 times | ||
818 | * actual value | ||
819 | */ | ||
820 | val1 = DIV_ROUND_CLOSEST((data->A_e_minus6 * counter) , 10000); | ||
821 | dev_vdbg(data->hwmon_dev, "A*counter / 100 = %d\n", | ||
822 | val1); | ||
823 | *p_interim_temp = (val1 + data->B_e_minus2); | ||
824 | } | ||
825 | dev_dbg(data->hwmon_dev, "tsensor: counter=0x%x, interim " | ||
826 | "temp*100=%d\n", | ||
827 | counter, *p_interim_temp); | ||
828 | return 0; | ||
829 | } | ||
830 | |||
831 | /* | ||
832 | * function to calculate final temperature, given | ||
833 | * interim temperature | ||
834 | */ | ||
835 | static void calc_final_temp(struct tegra_tsensor_data *data, | ||
836 | int interim_temp, int *p_final_temp) | ||
837 | { | ||
838 | int temp1, temp2, temp; | ||
839 | /* | ||
840 | * T-final = m * T-int ^2 + n * T-int + p | ||
841 | * m = -0.002775 | ||
842 | * n = 1.338811 | ||
843 | * p = -7.3 | ||
844 | */ | ||
845 | |||
846 | dev_vdbg(data->hwmon_dev, "interim_temp=%d\n", interim_temp); | ||
847 | temp1 = (DIV_ROUND_CLOSEST((interim_temp * interim_temp) , 100)); | ||
848 | dev_vdbg(data->hwmon_dev, "temp1=%d\n", temp1); | ||
849 | temp1 *= (DIV_ROUND_CLOSEST(data->m_e_minus6 , 10)); | ||
850 | dev_vdbg(data->hwmon_dev, "m*T-int^2=%d\n", temp1); | ||
851 | temp1 = (DIV_ROUND_CLOSEST(temp1, 10000)); | ||
852 | /* we want to keep 3 decimal point digits */ | ||
853 | dev_vdbg(data->hwmon_dev, "m*T-int^2 / 10000=%d\n", temp1); | ||
854 | dev_dbg(data->hwmon_dev, "temp1*100=%d\n", temp1); | ||
855 | |||
856 | temp2 = (DIV_ROUND_CLOSEST(interim_temp * ( | ||
857 | DIV_ROUND_CLOSEST(data->n_e_minus6, 100) | ||
858 | ), 1000)); /* 1000 times actual */ | ||
859 | dev_vdbg(data->hwmon_dev, "n*T-int =%d\n", temp2); | ||
860 | |||
861 | temp = temp1 + temp2; | ||
862 | dev_vdbg(data->hwmon_dev, "m*T-int^2 + n*T-int =%d\n", temp); | ||
863 | temp += (data->p_e_minus2 * 10); | ||
864 | temp = DIV_ROUND_CLOSEST(temp, 10); | ||
865 | /* final temperature(temp) is 100 times actual value | ||
866 | * to preserve 2 decimal digits and enable fixed point | ||
867 | * computation | ||
868 | */ | ||
869 | dev_vdbg(data->hwmon_dev, "m*T-int^2 + n*T-int + p =%d\n", | ||
870 | temp); | ||
871 | dev_dbg(data->hwmon_dev, "Final temp=%d.%d\n", | ||
872 | get_temperature_int(temp), get_temperature_fraction(temp)); | ||
873 | *p_final_temp = (int)(temp); | ||
874 | } | ||
875 | |||
876 | /* | ||
877 | * Function to compute constants A and B needed for temperature | ||
878 | * calculation | ||
879 | * A = (T2-T1) / (F2-F1) | ||
880 | * B = T1 – A * F1 | ||
881 | */ | ||
882 | static int tsensor_get_const_AB(struct tegra_tsensor_data *data) | ||
883 | { | ||
884 | int err; | ||
885 | |||
886 | /* | ||
887 | * 1. Find fusing registers for 25C (T1, F1) and 90C (T2, F2); | ||
888 | */ | ||
889 | err = read_tsensor_fuse_regs(data); | ||
890 | if (err) { | ||
891 | dev_err(data->hwmon_dev, "Fuse register read required " | ||
892 | "for internal tsensor returns err=%d\n", err); | ||
893 | return err; | ||
894 | } | ||
895 | |||
896 | if (data->fuse_F2 != data->fuse_F1) { | ||
897 | if ((data->fuse_F2 - data->fuse_F1) <= (data->fuse_T2 - | ||
898 | data->fuse_T1)) { | ||
899 | dev_err(data->hwmon_dev, "Error: F2=%d, " | ||
900 | "F1=%d, difference" | ||
901 | " unexpectedly low. Aborting temperature" | ||
902 | "computation\n", data->fuse_F2, data->fuse_F1); | ||
903 | return -EINVAL; | ||
904 | } else { | ||
905 | data->A_e_minus6 = ((data->fuse_T2 - data->fuse_T1) * | ||
906 | 1000000); | ||
907 | data->A_e_minus6 /= (data->fuse_F2 - data->fuse_F1); | ||
908 | data->B_e_minus2 = (data->fuse_T1 * 100) - ( | ||
909 | DIV_ROUND_CLOSEST((data->A_e_minus6 * | ||
910 | data->fuse_F1), 10000)); | ||
911 | /* B is 100 times now */ | ||
912 | } | ||
913 | } | ||
914 | dev_dbg(data->hwmon_dev, "A_e_minus6 = %d\n", data->A_e_minus6); | ||
915 | dev_dbg(data->hwmon_dev, "B_e_minus2 = %d\n", data->B_e_minus2); | ||
916 | return 0; | ||
917 | } | ||
918 | |||
919 | /* | ||
920 | * function calculates expected temperature corresponding to | ||
921 | * given tsensor counter value | ||
922 | * Value returned is 100 times calculated temperature since the | ||
923 | * calculations are using fixed point arithmetic instead of floating point | ||
924 | */ | ||
925 | static int tsensor_count_2_temp(struct tegra_tsensor_data *data, | ||
926 | unsigned int count, int *p_temperature) | ||
927 | { | ||
928 | int interim_temp; | ||
929 | int err; | ||
930 | |||
931 | /* | ||
932 | * | ||
933 | * 2. Calculate interim temperature: | ||
934 | */ | ||
935 | err = calc_interim_temp(data, count, &interim_temp); | ||
936 | if (err < 0) { | ||
937 | dev_err(data->hwmon_dev, "tsensor: cannot read temperature\n"); | ||
938 | *p_temperature = -1; | ||
939 | return err; | ||
940 | } | ||
941 | |||
942 | /* | ||
943 | * | ||
944 | * 3. Calculate final temperature: | ||
945 | */ | ||
946 | calc_final_temp(data, interim_temp, p_temperature); | ||
947 | return 0; | ||
948 | } | ||
949 | |||
950 | /* | ||
951 | * utility function implements ceil to power of 10 - | ||
952 | * e.g. given 987 it returns 1000 | ||
953 | */ | ||
954 | static int my_ceil_pow10(int num) | ||
955 | { | ||
956 | int tmp; | ||
957 | int val = 1; | ||
958 | tmp = (num < 0) ? -num : num; | ||
959 | if (tmp == 0) | ||
960 | return 0; | ||
961 | while (tmp > 1) { | ||
962 | val *= 10; | ||
963 | tmp /= 10; | ||
964 | } | ||
965 | return val; | ||
966 | } | ||
967 | |||
968 | /* | ||
969 | * function to solve quadratic roots of equation | ||
970 | * used to get counter corresponding to given temperature | ||
971 | */ | ||
972 | static void get_quadratic_roots(struct tegra_tsensor_data *data, | ||
973 | int temp, unsigned int *p_counter1, | ||
974 | unsigned int *p_counter2) | ||
975 | { | ||
976 | /* expr1 = 2 * m * B + n */ | ||
977 | int expr1_e_minus6; | ||
978 | /* expr2 = expr1^2 */ | ||
979 | int expr2_e_minus6; | ||
980 | /* expr3 = m * B^2 + n * B + p */ | ||
981 | int expr3_e_minus4_1; | ||
982 | int expr3_e_minus4_2; | ||
983 | int expr3_e_minus4; | ||
984 | int expr4_e_minus6; | ||
985 | int expr4_e_minus2_1; | ||
986 | int expr4_e_minus6_2; | ||
987 | int expr4_e_minus6_3; | ||
988 | int expr5_e_minus6, expr5_e_minus6_1, expr6, expr7; | ||
989 | int expr8_e_minus6, expr9_e_minus6; | ||
990 | int multiplier; | ||
991 | const int multiplier2 = 1000000; | ||
992 | int expr10_e_minus6, expr11_e_minus6; | ||
993 | int expr12, expr13; | ||
994 | |||
995 | dev_vdbg(data->hwmon_dev, "A_e_minus6=%d, B_e_minus2=%d, " | ||
996 | "m_e_minus6=%d, n_e_minus6=%d, p_e_minus2=%d, " | ||
997 | "temp=%d\n", data->A_e_minus6, data->B_e_minus2, | ||
998 | data->m_e_minus6, | ||
999 | data->n_e_minus6, data->p_e_minus2, (int)temp); | ||
1000 | expr1_e_minus6 = (DIV_ROUND_CLOSEST((2 * data->m_e_minus6 * | ||
1001 | data->B_e_minus2), 100) + data->n_e_minus6); | ||
1002 | dev_vdbg(data->hwmon_dev, "2_m_B_plun_e_minus6=%d\n", | ||
1003 | expr1_e_minus6); | ||
1004 | expr2_e_minus6 = (DIV_ROUND_CLOSEST(expr1_e_minus6, 1000)) * | ||
1005 | (DIV_ROUND_CLOSEST(expr1_e_minus6, 1000)); | ||
1006 | dev_vdbg(data->hwmon_dev, "expr1^2=%d\n", expr2_e_minus6); | ||
1007 | expr3_e_minus4_1 = (DIV_ROUND_CLOSEST(( | ||
1008 | (DIV_ROUND_CLOSEST((data->m_e_minus6 * data->B_e_minus2), | ||
1009 | 1000)) * (DIV_ROUND_CLOSEST(data->B_e_minus2, 10))), 100)); | ||
1010 | dev_vdbg(data->hwmon_dev, "expr3_e_minus4_1=%d\n", | ||
1011 | expr3_e_minus4_1); | ||
1012 | expr3_e_minus4_2 = DIV_ROUND_CLOSEST( | ||
1013 | (DIV_ROUND_CLOSEST(data->n_e_minus6, 100) * data->B_e_minus2), | ||
1014 | 100); | ||
1015 | dev_vdbg(data->hwmon_dev, "expr3_e_minus4_2=%d\n", | ||
1016 | expr3_e_minus4_2); | ||
1017 | expr3_e_minus4 = expr3_e_minus4_1 + expr3_e_minus4_2; | ||
1018 | dev_vdbg(data->hwmon_dev, "expr3=%d\n", expr3_e_minus4); | ||
1019 | expr4_e_minus2_1 = DIV_ROUND_CLOSEST((expr3_e_minus4 + | ||
1020 | (data->p_e_minus2 * 100)), 100); | ||
1021 | dev_vdbg(data->hwmon_dev, "expr4_e_minus2_1=%d\n", | ||
1022 | expr4_e_minus2_1); | ||
1023 | expr4_e_minus6_2 = (4 * data->m_e_minus6); | ||
1024 | dev_vdbg(data->hwmon_dev, "expr4_e_minus6_2=%d\n", | ||
1025 | expr4_e_minus6_2); | ||
1026 | expr4_e_minus6 = DIV_ROUND_CLOSEST((expr4_e_minus2_1 * | ||
1027 | expr4_e_minus6_2), 100); | ||
1028 | dev_vdbg(data->hwmon_dev, "expr4_minus6=%d\n", expr4_e_minus6); | ||
1029 | expr5_e_minus6_1 = expr2_e_minus6 - expr4_e_minus6; | ||
1030 | dev_vdbg(data->hwmon_dev, "expr5_e_minus6_1=%d\n", | ||
1031 | expr5_e_minus6_1); | ||
1032 | expr4_e_minus6_3 = (expr4_e_minus6_2 * temp); | ||
1033 | dev_vdbg(data->hwmon_dev, "expr4_e_minus6_3=%d\n", | ||
1034 | expr4_e_minus6_3); | ||
1035 | expr5_e_minus6 = (expr5_e_minus6_1 + expr4_e_minus6_3); | ||
1036 | dev_vdbg(data->hwmon_dev, "expr5_e_minus6=%d\n", | ||
1037 | expr5_e_minus6); | ||
1038 | multiplier = my_ceil_pow10(expr5_e_minus6); | ||
1039 | dev_vdbg(data->hwmon_dev, "multiplier=%d\n", multiplier); | ||
1040 | expr6 = int_sqrt(expr5_e_minus6); | ||
1041 | dev_vdbg(data->hwmon_dev, "sqrt top=%d\n", expr6); | ||
1042 | expr7 = int_sqrt(multiplier); | ||
1043 | dev_vdbg(data->hwmon_dev, "sqrt bot=%d\n", expr7); | ||
1044 | if (expr7 == 0) { | ||
1045 | pr_err("Error: %s line=%d, expr7=%d\n", | ||
1046 | __func__, __LINE__, expr7); | ||
1047 | return; | ||
1048 | } else { | ||
1049 | expr8_e_minus6 = (expr6 * multiplier2) / expr7; | ||
1050 | } | ||
1051 | dev_vdbg(data->hwmon_dev, "sqrt final=%d\n", expr8_e_minus6); | ||
1052 | dev_vdbg(data->hwmon_dev, "2_m_B_plus_n_e_minus6=%d\n", | ||
1053 | expr1_e_minus6); | ||
1054 | expr9_e_minus6 = DIV_ROUND_CLOSEST((2 * data->m_e_minus6 * | ||
1055 | data->A_e_minus6), 1000000); | ||
1056 | dev_vdbg(data->hwmon_dev, "denominator=%d\n", expr9_e_minus6); | ||
1057 | if (expr9_e_minus6 == 0) { | ||
1058 | pr_err("Error: %s line=%d, expr9_e_minus6=%d\n", | ||
1059 | __func__, __LINE__, expr9_e_minus6); | ||
1060 | return; | ||
1061 | } | ||
1062 | expr10_e_minus6 = -expr1_e_minus6 - expr8_e_minus6; | ||
1063 | dev_vdbg(data->hwmon_dev, "expr10_e_minus6=%d\n", | ||
1064 | expr10_e_minus6); | ||
1065 | expr11_e_minus6 = -expr1_e_minus6 + expr8_e_minus6; | ||
1066 | dev_vdbg(data->hwmon_dev, "expr11_e_minus6=%d\n", | ||
1067 | expr11_e_minus6); | ||
1068 | expr12 = (expr10_e_minus6 / expr9_e_minus6); | ||
1069 | dev_vdbg(data->hwmon_dev, "counter1=%d\n", expr12); | ||
1070 | expr13 = (expr11_e_minus6 / expr9_e_minus6); | ||
1071 | dev_vdbg(data->hwmon_dev, "counter2=%d\n", expr13); | ||
1072 | *p_counter1 = expr12; | ||
1073 | *p_counter2 = expr13; | ||
1074 | } | ||
1075 | |||
1076 | /* | ||
1077 | * function returns tsensor expected counter corresponding to input | ||
1078 | * temperature in degree Celsius. | ||
1079 | * e.g. for temperature of 35C, temp=35 | ||
1080 | */ | ||
1081 | static void tsensor_temp_2_count(struct tegra_tsensor_data *data, | ||
1082 | int temp, | ||
1083 | unsigned int *p_counter1, | ||
1084 | unsigned int *p_counter2) | ||
1085 | { | ||
1086 | if (temp > 0) { | ||
1087 | dev_dbg(data->hwmon_dev, "Trying to calculate counter" | ||
1088 | " for requested temperature" | ||
1089 | " threshold=%d\n", temp); | ||
1090 | /* | ||
1091 | * calculate the constants needed to get roots of | ||
1092 | * following quadratic eqn: | ||
1093 | * m * A^2 * Counter^2 + | ||
1094 | * A * (2 * m * B + n) * Counter + | ||
1095 | * (m * B^2 + n * B + p - Temperature) = 0 | ||
1096 | */ | ||
1097 | get_quadratic_roots(data, temp, p_counter1, p_counter2); | ||
1098 | /* | ||
1099 | * checked at current temperature=35 the counter=11418 | ||
1100 | * for 50 deg temperature: counter1=22731, counter2=11817 | ||
1101 | * at 35 deg temperature: counter1=23137, counter2=11411 | ||
1102 | * hence, for above values we are assuming counter2 has | ||
1103 | * the correct value | ||
1104 | */ | ||
1105 | } else { | ||
1106 | *p_counter1 = DEFAULT_THRESHOLD_TH3; | ||
1107 | *p_counter2 = DEFAULT_THRESHOLD_TH3; | ||
1108 | } | ||
1109 | } | ||
1110 | |||
1111 | /* | ||
1112 | * function to compare computed and expected values with | ||
1113 | * certain tolerance setting hard coded here | ||
1114 | */ | ||
1115 | static bool cmp_counter( | ||
1116 | struct tegra_tsensor_data *data, | ||
1117 | unsigned int actual, unsigned int exp) | ||
1118 | { | ||
1119 | unsigned int smaller; | ||
1120 | unsigned int larger; | ||
1121 | smaller = (actual > exp) ? exp : actual; | ||
1122 | larger = (smaller == actual) ? exp : actual; | ||
1123 | if ((larger - smaller) > TSENSOR_COUNTER_TOLERANCE) { | ||
1124 | dev_dbg(data->hwmon_dev, "actual=%d, exp=%d, larger=%d, " | ||
1125 | "smaller=%d, tolerance=%d\n", actual, exp, larger, smaller, | ||
1126 | TSENSOR_COUNTER_TOLERANCE); | ||
1127 | return false; | ||
1128 | } | ||
1129 | return true; | ||
1130 | } | ||
1131 | |||
1132 | /* function to print chart of temperature to counter values */ | ||
1133 | static void print_temperature_2_counter_table( | ||
1134 | struct tegra_tsensor_data *data) | ||
1135 | { | ||
1136 | int i; | ||
1137 | /* static list of temperature tested */ | ||
1138 | int temp_list[] = { | ||
1139 | 30, | ||
1140 | 35, | ||
1141 | 40, | ||
1142 | 45, | ||
1143 | 50, | ||
1144 | 55, | ||
1145 | 60, | ||
1146 | 61, | ||
1147 | 62, | ||
1148 | 63, | ||
1149 | 64, | ||
1150 | 65, | ||
1151 | 70, | ||
1152 | 75, | ||
1153 | 80, | ||
1154 | 85, | ||
1155 | 90, | ||
1156 | 95, | ||
1157 | 100, | ||
1158 | 105, | ||
1159 | 110, | ||
1160 | 115, | ||
1161 | 120 | ||
1162 | }; | ||
1163 | unsigned int counter1, counter2; | ||
1164 | dev_dbg(data->hwmon_dev, "Temperature and counter1 and " | ||
1165 | "counter2 chart **********\n"); | ||
1166 | for (i = 0; i < ARRAY_SIZE(temp_list); i++) { | ||
1167 | tsensor_temp_2_count(data, temp_list[i], | ||
1168 | &counter1, &counter2); | ||
1169 | dev_dbg(data->hwmon_dev, "temperature[%d]=%d, " | ||
1170 | "counter1=0x%x, counter2=0x%x\n", | ||
1171 | i, temp_list[i], counter1, counter2); | ||
1172 | } | ||
1173 | dev_dbg(data->hwmon_dev, "\n\n"); | ||
1174 | } | ||
1175 | |||
1176 | static void dump_a_tsensor_reg(struct tegra_tsensor_data *data, | ||
1177 | unsigned int addr) | ||
1178 | { | ||
1179 | dev_dbg(data->hwmon_dev, "tsensor[%d][0x%x]: 0x%x\n", (addr >> 16), | ||
1180 | addr & 0xFFFF, tsensor_readl(data, addr)); | ||
1181 | } | ||
1182 | |||
1183 | static void dump_tsensor_regs(struct tegra_tsensor_data *data) | ||
1184 | { | ||
1185 | int i; | ||
1186 | for (i = 0; i < TSENSOR_COUNT; i++) { | ||
1187 | /* if STOP bit is set skip this check */ | ||
1188 | dump_a_tsensor_reg(data, ((i << 16) | SENSOR_CFG0)); | ||
1189 | dump_a_tsensor_reg(data, ((i << 16) | SENSOR_CFG1)); | ||
1190 | dump_a_tsensor_reg(data, ((i << 16) | SENSOR_CFG2)); | ||
1191 | dump_a_tsensor_reg(data, ((i << 16) | SENSOR_STATUS0)); | ||
1192 | dump_a_tsensor_reg(data, ((i << 16) | SENSOR_TS_STATUS1)); | ||
1193 | dump_a_tsensor_reg(data, ((i << 16) | SENSOR_TS_STATUS2)); | ||
1194 | dump_a_tsensor_reg(data, ((i << 16) | 0x0)); | ||
1195 | dump_a_tsensor_reg(data, ((i << 16) | 0x44)); | ||
1196 | dump_a_tsensor_reg(data, ((i << 16) | 0x50)); | ||
1197 | dump_a_tsensor_reg(data, ((i << 16) | 0x54)); | ||
1198 | dump_a_tsensor_reg(data, ((i << 16) | 0x64)); | ||
1199 | dump_a_tsensor_reg(data, ((i << 16) | 0x68)); | ||
1200 | } | ||
1201 | } | ||
1202 | |||
1203 | /* | ||
1204 | * function to test if conversion of counter to temperature | ||
1205 | * and vice-versa is working | ||
1206 | */ | ||
1207 | static int test_temperature_algo(struct tegra_tsensor_data *data) | ||
1208 | { | ||
1209 | unsigned int actual_counter; | ||
1210 | unsigned int curr_avg; | ||
1211 | unsigned int counter1, counter2; | ||
1212 | int T1; | ||
1213 | int err = 0; | ||
1214 | bool result1, result2; | ||
1215 | bool result = false; | ||
1216 | |||
1217 | /* read actual counter */ | ||
1218 | err = tsensor_read_counter(data, &curr_avg); | ||
1219 | if (err < 0) { | ||
1220 | pr_err("Error: tsensor0 counter read, err=%d\n", err); | ||
1221 | goto endLabel; | ||
1222 | } | ||
1223 | actual_counter = ((curr_avg & 0xFFFF0000) >> 16); | ||
1224 | dev_dbg(data->hwmon_dev, "counter read=0x%x\n", actual_counter); | ||
1225 | |||
1226 | /* calculate temperature */ | ||
1227 | err = tsensor_count_2_temp(data, actual_counter, &T1); | ||
1228 | dev_dbg(data->hwmon_dev, "%s actual counter=0x%x, calculated " | ||
1229 | "temperature=%d.%d\n", __func__, | ||
1230 | actual_counter, get_temperature_int(T1), | ||
1231 | get_temperature_fraction(T1)); | ||
1232 | if (err < 0) { | ||
1233 | pr_err("Error: calculate temperature step\n"); | ||
1234 | goto endLabel; | ||
1235 | } | ||
1236 | |||
1237 | /* calculate counter corresponding to read temperature */ | ||
1238 | tsensor_temp_2_count(data, get_temperature_round(T1), | ||
1239 | &counter1, &counter2); | ||
1240 | dev_dbg(data->hwmon_dev, "given temperature=%d, counter1=0x%x," | ||
1241 | " counter2=0x%x\n", | ||
1242 | get_temperature_round(T1), counter1, counter2); | ||
1243 | |||
1244 | err = tsensor_count_2_temp(data, actual_counter, &T1); | ||
1245 | dev_dbg(data->hwmon_dev, "%s 2nd time actual counter=0x%x, " | ||
1246 | "calculated temperature=%d.%d\n", __func__, | ||
1247 | actual_counter, get_temperature_int(T1), | ||
1248 | get_temperature_fraction(T1)); | ||
1249 | if (err < 0) { | ||
1250 | pr_err("Error: calculate temperature step\n"); | ||
1251 | goto endLabel; | ||
1252 | } | ||
1253 | |||
1254 | /* compare counter calculated with actual original counter */ | ||
1255 | result1 = cmp_counter(data, actual_counter, counter1); | ||
1256 | result2 = cmp_counter(data, actual_counter, counter2); | ||
1257 | if (result1) { | ||
1258 | dev_dbg(data->hwmon_dev, "counter1 matches: actual=%d," | ||
1259 | " calc=%d\n", actual_counter, counter1); | ||
1260 | result = true; | ||
1261 | } | ||
1262 | if (result2) { | ||
1263 | dev_dbg(data->hwmon_dev, "counter2 matches: actual=%d," | ||
1264 | " calc=%d\n", actual_counter, counter2); | ||
1265 | result = true; | ||
1266 | } | ||
1267 | if (!result) { | ||
1268 | pr_info("NO Match: actual=%d," | ||
1269 | " calc counter2=%d, counter1=%d\n", actual_counter, | ||
1270 | counter2, counter1); | ||
1271 | err = -EIO; | ||
1272 | } | ||
1273 | |||
1274 | endLabel: | ||
1275 | return err; | ||
1276 | } | ||
1277 | |||
1278 | /* tsensor threshold temperature to threshold counter conversion function */ | ||
1279 | static unsigned int tsensor_get_threshold_counter( | ||
1280 | struct tegra_tsensor_data *data, | ||
1281 | int temp_threshold) | ||
1282 | { | ||
1283 | unsigned int counter1, counter2; | ||
1284 | unsigned int counter; | ||
1285 | |||
1286 | if (temp_threshold < 0) | ||
1287 | return MAX_THRESHOLD; | ||
1288 | |||
1289 | tsensor_temp_2_count(data, temp_threshold, &counter1, &counter2); | ||
1290 | |||
1291 | counter = counter2; | ||
1292 | |||
1293 | return counter; | ||
1294 | } | ||
1295 | |||
1296 | /* tsensor temperature threshold setup function */ | ||
1297 | static void tsensor_threshold_setup(struct tegra_tsensor_data *data, | ||
1298 | unsigned char index) | ||
1299 | { | ||
1300 | unsigned long config0; | ||
1301 | unsigned char i = index; | ||
1302 | unsigned int th2_count = DEFAULT_THRESHOLD_TH2; | ||
1303 | unsigned int th3_count = DEFAULT_THRESHOLD_TH3; | ||
1304 | unsigned int th1_count = DEFAULT_THRESHOLD_TH1; | ||
1305 | int th0_diff = 0; | ||
1306 | |||
1307 | dev_dbg(data->hwmon_dev, "started tsensor_threshold_setup %d\n", | ||
1308 | index); | ||
1309 | config0 = tsensor_readl(data, ((i << 16) | SENSOR_CFG0)); | ||
1310 | |||
1311 | dev_dbg(data->hwmon_dev, "before threshold program TH dump:\n"); | ||
1312 | dump_threshold(data); | ||
1313 | dev_dbg(data->hwmon_dev, "th3=0x%x, th2=0x%x, th1=0x%x, th0=0x%x\n", | ||
1314 | th3_count, th2_count, th1_count, th0_diff); | ||
1315 | config0 = (((th2_count & SENSOR_CFG_X_TH_X_MASK) | ||
1316 | << SENSOR_CFG1_TH2_SHIFT) | | ||
1317 | ((th1_count & SENSOR_CFG_X_TH_X_MASK) << | ||
1318 | SENSOR_CFG1_TH1_SHIFT)); | ||
1319 | tsensor_writel(data, config0, ((i << 16) | SENSOR_CFG1)); | ||
1320 | config0 = (((th0_diff & SENSOR_CFG_X_TH_X_MASK) | ||
1321 | << SENSOR_CFG2_TH0_SHIFT) | | ||
1322 | ((th3_count & SENSOR_CFG_X_TH_X_MASK) << | ||
1323 | SENSOR_CFG2_TH3_SHIFT)); | ||
1324 | tsensor_writel(data, config0, ((i << 16) | SENSOR_CFG2)); | ||
1325 | dev_dbg(data->hwmon_dev, "after threshold program TH dump:\n"); | ||
1326 | dump_threshold(data); | ||
1327 | } | ||
1328 | |||
1329 | /* tsensor config programming function */ | ||
1330 | static int tsensor_config_setup(struct tegra_tsensor_data *data) | ||
1331 | { | ||
1332 | unsigned int config0; | ||
1333 | unsigned int i; | ||
1334 | int err = 0; | ||
1335 | |||
1336 | for (i = 0; i < TSENSOR_COUNT; i++) { | ||
1337 | /* | ||
1338 | * Pre-read setup: | ||
1339 | * Set M and N values | ||
1340 | * Enable HW features HW_FREQ_DIV_EN, THERMAL_RST_EN | ||
1341 | */ | ||
1342 | config0 = tsensor_readl(data, ((i << 16) | SENSOR_CFG0)); | ||
1343 | config0 &= ~((SENSOR_CFG0_M_MASK << SENSOR_CFG0_M_SHIFT) | | ||
1344 | (SENSOR_CFG0_N_MASK << SENSOR_CFG0_N_SHIFT) | | ||
1345 | (1 << SENSOR_CFG0_OVERFLOW_INTR) | | ||
1346 | (1 << SENSOR_CFG0_RST_INTR_SHIFT) | | ||
1347 | (1 << SENSOR_CFG0_DVFS_INTR_SHIFT) | | ||
1348 | (1 << SENSOR_CFG0_HW_DIV2_INTR_SHIFT) | | ||
1349 | (1 << SENSOR_CFG0_RST_ENABLE_SHIFT) | | ||
1350 | (1 << SENSOR_CFG0_HW_DIV2_ENABLE_SHIFT) | ||
1351 | ); | ||
1352 | /* Set STOP bit */ | ||
1353 | /* Set M and N values */ | ||
1354 | /* Enable HW features HW_FREQ_DIV_EN, THERMAL_RST_EN */ | ||
1355 | config0 |= ( | ||
1356 | ((DEFAULT_TSENSOR_M & SENSOR_CFG0_M_MASK) << | ||
1357 | SENSOR_CFG0_M_SHIFT) | | ||
1358 | ((DEFAULT_TSENSOR_N & SENSOR_CFG0_N_MASK) << | ||
1359 | SENSOR_CFG0_N_SHIFT) | | ||
1360 | (1 << SENSOR_CFG0_OVERFLOW_INTR) | | ||
1361 | (1 << SENSOR_CFG0_DVFS_INTR_SHIFT) | | ||
1362 | (1 << SENSOR_CFG0_HW_DIV2_INTR_SHIFT) | | ||
1363 | #if ENABLE_TSENSOR_HW_RESET | ||
1364 | (1 << SENSOR_CFG0_RST_ENABLE_SHIFT) | | ||
1365 | #endif | ||
1366 | (1 << SENSOR_CFG0_STOP_SHIFT)); | ||
1367 | |||
1368 | tsensor_writel(data, config0, ((i << 16) | SENSOR_CFG0)); | ||
1369 | tsensor_threshold_setup(data, i); | ||
1370 | } | ||
1371 | |||
1372 | /* Disable sensor stop bit */ | ||
1373 | config0 = tsensor_readl(data, (data->instance << 16) | SENSOR_CFG0); | ||
1374 | config0 &= ~(1 << SENSOR_CFG0_STOP_SHIFT); | ||
1375 | tsensor_writel(data, config0, (data->instance << 16) | SENSOR_CFG0); | ||
1376 | |||
1377 | /* initialize tsensor chip coefficients */ | ||
1378 | get_chip_tsensor_coeff(data); | ||
1379 | |||
1380 | return err; | ||
1381 | } | ||
1382 | |||
1383 | /* function to enable tsensor clock */ | ||
1384 | static int tsensor_clk_enable( | ||
1385 | struct tegra_tsensor_data *data, | ||
1386 | bool enable) | ||
1387 | { | ||
1388 | int err = 0; | ||
1389 | unsigned long rate; | ||
1390 | struct clk *clk_m; | ||
1391 | |||
1392 | if (enable) { | ||
1393 | clk_enable(data->dev_clk); | ||
1394 | rate = clk_get_rate(data->dev_clk); | ||
1395 | clk_m = clk_get_sys(NULL, "clk_m"); | ||
1396 | if (clk_get_parent(data->dev_clk) != clk_m) { | ||
1397 | err = clk_set_parent(data->dev_clk, clk_m); | ||
1398 | if (err < 0) | ||
1399 | goto fail; | ||
1400 | } | ||
1401 | rate = DEFAULT_TSENSOR_CLK_HZ; | ||
1402 | if (rate != clk_get_rate(clk_m)) { | ||
1403 | err = clk_set_rate(data->dev_clk, rate); | ||
1404 | if (err < 0) | ||
1405 | goto fail; | ||
1406 | } | ||
1407 | } else { | ||
1408 | clk_disable(data->dev_clk); | ||
1409 | clk_put(data->dev_clk); | ||
1410 | } | ||
1411 | fail: | ||
1412 | return err; | ||
1413 | } | ||
1414 | |||
1415 | /* | ||
1416 | * function to set counter threshold corresponding to | ||
1417 | * given temperature | ||
1418 | */ | ||
1419 | static void tsensor_set_limits( | ||
1420 | struct tegra_tsensor_data *data, | ||
1421 | int temp, | ||
1422 | int threshold_index) | ||
1423 | { | ||
1424 | unsigned int th_count; | ||
1425 | unsigned int config; | ||
1426 | unsigned short sft, offset; | ||
1427 | unsigned int th1_count; | ||
1428 | |||
1429 | th_count = tsensor_get_threshold_counter(data, temp); | ||
1430 | dev_dbg(data->hwmon_dev, "%s : input temp=%d, counter=0x%x\n", __func__, | ||
1431 | temp, th_count); | ||
1432 | switch (threshold_index) { | ||
1433 | case TSENSOR_TH0: | ||
1434 | sft = 16; | ||
1435 | offset = SENSOR_CFG2; | ||
1436 | /* assumed TH1 set before TH0, else we program | ||
1437 | * TH0 as TH1 which means hysteresis will be | ||
1438 | * same as TH1. Also, caller expected to pass | ||
1439 | * (TH1 - hysteresis) as temp argument for this case */ | ||
1440 | th1_count = tsensor_readl(data, | ||
1441 | ((data->instance << 16) | | ||
1442 | SENSOR_CFG1)); | ||
1443 | th_count = (th1_count > th_count) ? | ||
1444 | (th1_count - th_count) : | ||
1445 | th1_count; | ||
1446 | break; | ||
1447 | case TSENSOR_TH1: | ||
1448 | default: | ||
1449 | sft = 0; | ||
1450 | offset = SENSOR_CFG1; | ||
1451 | break; | ||
1452 | case TSENSOR_TH2: | ||
1453 | sft = 16; | ||
1454 | offset = SENSOR_CFG1; | ||
1455 | break; | ||
1456 | case TSENSOR_TH3: | ||
1457 | sft = 0; | ||
1458 | offset = SENSOR_CFG2; | ||
1459 | break; | ||
1460 | } | ||
1461 | config = tsensor_readl(data, ((data->instance << 16) | offset)); | ||
1462 | dev_dbg(data->hwmon_dev, "%s: old config=0x%x, sft=%d, offset=0x%x\n", | ||
1463 | __func__, config, sft, offset); | ||
1464 | config &= ~(SENSOR_CFG_X_TH_X_MASK << sft); | ||
1465 | config |= ((th_count & SENSOR_CFG_X_TH_X_MASK) << sft); | ||
1466 | dev_dbg(data->hwmon_dev, "new config=0x%x\n", config); | ||
1467 | tsensor_writel(data, config, ((data->instance << 16) | offset)); | ||
1468 | } | ||
1469 | |||
1470 | int tsensor_thermal_set_limits(struct tegra_tsensor_data *data, | ||
1471 | long lo_limit_milli, | ||
1472 | long hi_limit_milli) | ||
1473 | { | ||
1474 | long lo_limit = MILLICELSIUS_TO_CELSIUS(lo_limit_milli); | ||
1475 | long hi_limit = MILLICELSIUS_TO_CELSIUS(hi_limit_milli); | ||
1476 | int i, j, hi_limit_first; | ||
1477 | |||
1478 | if (lo_limit_milli == hi_limit_milli) | ||
1479 | return -EINVAL; | ||
1480 | |||
1481 | mutex_lock(&data->mutex); | ||
1482 | |||
1483 | if (data->current_lo_limit == lo_limit_milli && | ||
1484 | data->current_hi_limit == hi_limit_milli) { | ||
1485 | goto done; | ||
1486 | } | ||
1487 | |||
1488 | /* If going up, change hi limit first. If going down, change lo | ||
1489 | limit first */ | ||
1490 | hi_limit_first = hi_limit_milli > data->current_hi_limit; | ||
1491 | |||
1492 | for (i = 0; i < 2; i++) { | ||
1493 | j = (i + hi_limit_first) % 2; | ||
1494 | |||
1495 | switch (j) { | ||
1496 | case 0: | ||
1497 | tsensor_set_limits(data, hi_limit, TSENSOR_TH2); | ||
1498 | data->current_hi_limit = hi_limit_milli; | ||
1499 | break; | ||
1500 | case 1: | ||
1501 | tsensor_set_limits(data, lo_limit, TSENSOR_TH1); | ||
1502 | data->current_lo_limit = lo_limit_milli; | ||
1503 | break; | ||
1504 | } | ||
1505 | } | ||
1506 | |||
1507 | |||
1508 | done: | ||
1509 | mutex_unlock(&data->mutex); | ||
1510 | return 0; | ||
1511 | } | ||
1512 | |||
1513 | int tsensor_thermal_set_alert(struct tegra_tsensor_data *data, | ||
1514 | void (*alert_func)(void *), | ||
1515 | void *alert_data) | ||
1516 | { | ||
1517 | mutex_lock(&data->mutex); | ||
1518 | |||
1519 | data->alert_data = alert_data; | ||
1520 | data->alert_func = alert_func; | ||
1521 | |||
1522 | mutex_unlock(&data->mutex); | ||
1523 | |||
1524 | return 0; | ||
1525 | } | ||
1526 | |||
1527 | int tsensor_thermal_set_shutdown_temp(struct tegra_tsensor_data *data, | ||
1528 | long shutdown_temp_milli) | ||
1529 | { | ||
1530 | long shutdown_temp = MILLICELSIUS_TO_CELSIUS(shutdown_temp_milli); | ||
1531 | tsensor_set_limits(data, shutdown_temp, TSENSOR_TH3); | ||
1532 | |||
1533 | return 0; | ||
1534 | } | ||
1535 | |||
1536 | static int tsensor_within_limits(struct tegra_tsensor_data *data) | ||
1537 | { | ||
1538 | int ts_state = get_ts_state(data); | ||
1539 | |||
1540 | return (ts_state == TS_LEVEL1); | ||
1541 | } | ||
1542 | |||
1543 | static void tsensor_work_func(struct work_struct *work) | ||
1544 | { | ||
1545 | struct tegra_tsensor_data *data = container_of(work, | ||
1546 | struct tegra_tsensor_data, work); | ||
1547 | |||
1548 | if (!data->alert_func) | ||
1549 | return; | ||
1550 | |||
1551 | if (!tsensor_within_limits(data)) { | ||
1552 | data->alert_func(data->alert_data); | ||
1553 | |||
1554 | if (!tsensor_within_limits(data)) | ||
1555 | queue_delayed_work(data->workqueue, &data->work, | ||
1556 | HZ * DEFAULT_TSENSOR_M / | ||
1557 | DEFAULT_TSENSOR_CLK_HZ); | ||
1558 | } | ||
1559 | } | ||
1560 | |||
1561 | /* | ||
1562 | * This function enables the tsensor using default configuration | ||
1563 | * 1. We would need some configuration APIs to calibrate | ||
1564 | * the tsensor counters to right temperature | ||
1565 | * 2. hardware triggered divide cpu clock by 2 as well pmu reset is enabled | ||
1566 | * implementation. No software actions are enabled at this point | ||
1567 | */ | ||
1568 | static int tegra_tsensor_setup(struct platform_device *pdev) | ||
1569 | { | ||
1570 | struct tegra_tsensor_data *data = platform_get_drvdata(pdev); | ||
1571 | struct resource *r; | ||
1572 | int err = 0; | ||
1573 | struct tegra_tsensor_platform_data *tsensor_data; | ||
1574 | unsigned int reg; | ||
1575 | |||
1576 | data->dev_clk = clk_get(&pdev->dev, NULL); | ||
1577 | if ((!data->dev_clk) || ((int)data->dev_clk == -(ENOENT))) { | ||
1578 | dev_err(&pdev->dev, "Couldn't get the clock\n"); | ||
1579 | err = PTR_ERR(data->dev_clk); | ||
1580 | goto fail; | ||
1581 | } | ||
1582 | |||
1583 | /* Enable tsensor clock */ | ||
1584 | err = tsensor_clk_enable(data, true); | ||
1585 | if (err < 0) | ||
1586 | goto err_irq; | ||
1587 | |||
1588 | /* Reset tsensor */ | ||
1589 | dev_dbg(&pdev->dev, "before tsensor reset %s\n", __func__); | ||
1590 | tegra_periph_reset_assert(data->dev_clk); | ||
1591 | udelay(100); | ||
1592 | tegra_periph_reset_deassert(data->dev_clk); | ||
1593 | udelay(100); | ||
1594 | |||
1595 | dev_dbg(&pdev->dev, "before tsensor chk pmc reset %s\n", | ||
1596 | __func__); | ||
1597 | /* Check for previous resets in pmc */ | ||
1598 | if (pmc_check_rst_sensor(data)) { | ||
1599 | dev_err(data->hwmon_dev, "Warning: ***** Last PMC " | ||
1600 | "Reset source: tsensor detected\n"); | ||
1601 | } | ||
1602 | |||
1603 | dev_dbg(&pdev->dev, "before tsensor pmc reset enable %s\n", | ||
1604 | __func__); | ||
1605 | /* Enable the sensor reset in PMC */ | ||
1606 | pmc_rst_enable(data, true); | ||
1607 | |||
1608 | dev_dbg(&pdev->dev, "before tsensor get platform data %s\n", | ||
1609 | __func__); | ||
1610 | dev_dbg(&pdev->dev, "tsensor platform_data=0x%x\n", | ||
1611 | (unsigned int)pdev->dev.platform_data); | ||
1612 | tsensor_data = pdev->dev.platform_data; | ||
1613 | |||
1614 | /* register interrupt */ | ||
1615 | r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
1616 | if (!r) { | ||
1617 | dev_err(&pdev->dev, "Failed to get IRQ\n"); | ||
1618 | err = -ENXIO; | ||
1619 | goto err_irq; | ||
1620 | } | ||
1621 | data->irq = r->start; | ||
1622 | err = request_irq(data->irq, tegra_tsensor_isr, | ||
1623 | IRQF_DISABLED, pdev->name, data); | ||
1624 | if (err < 0) { | ||
1625 | dev_err(&pdev->dev, "Failed to register IRQ\n"); | ||
1626 | goto err_irq; | ||
1627 | } | ||
1628 | |||
1629 | dev_dbg(&pdev->dev, "tsensor platform_data=0x%x\n", | ||
1630 | (unsigned int)pdev->dev.platform_data); | ||
1631 | |||
1632 | dev_dbg(&pdev->dev, "before tsensor_config_setup\n"); | ||
1633 | err = tsensor_config_setup(data); | ||
1634 | if (err) { | ||
1635 | dev_err(&pdev->dev, "[%s,line=%d]: tsensor counters dead!\n", | ||
1636 | __func__, __LINE__); | ||
1637 | goto err_setup; | ||
1638 | } | ||
1639 | dev_dbg(&pdev->dev, "before tsensor_get_const_AB\n"); | ||
1640 | /* calculate constants needed for temperature conversion */ | ||
1641 | err = tsensor_get_const_AB(data); | ||
1642 | if (err < 0) { | ||
1643 | dev_err(&pdev->dev, "Failed to extract temperature\n" | ||
1644 | "const\n"); | ||
1645 | goto err_setup; | ||
1646 | } | ||
1647 | |||
1648 | /* test if counter-to-temperature and temperature-to-counter | ||
1649 | * are matching */ | ||
1650 | err = test_temperature_algo(data); | ||
1651 | if (err) { | ||
1652 | dev_err(&pdev->dev, "Error: read temperature\n" | ||
1653 | "algorithm broken\n"); | ||
1654 | goto err_setup; | ||
1655 | } | ||
1656 | |||
1657 | print_temperature_2_counter_table(data); | ||
1658 | |||
1659 | /* EDP and throttling support using tsensor enabled | ||
1660 | * based on fuse revision */ | ||
1661 | err = tegra_fuse_get_revision(®); | ||
1662 | if (err) | ||
1663 | goto err_setup; | ||
1664 | |||
1665 | data->is_edp_supported = (reg >= STABLE_TSENSOR_FUSE_REV); | ||
1666 | |||
1667 | if (data->is_edp_supported) { | ||
1668 | data->workqueue = create_singlethread_workqueue("tsensor"); | ||
1669 | INIT_DELAYED_WORK(&data->work, tsensor_work_func); | ||
1670 | } | ||
1671 | |||
1672 | return 0; | ||
1673 | err_setup: | ||
1674 | free_irq(data->irq, data); | ||
1675 | err_irq: | ||
1676 | tsensor_clk_enable(data, false); | ||
1677 | fail: | ||
1678 | dev_err(&pdev->dev, "%s error=%d returned\n", __func__, err); | ||
1679 | return err; | ||
1680 | } | ||
1681 | |||
1682 | static int __devinit tegra_tsensor_probe(struct platform_device *pdev) | ||
1683 | { | ||
1684 | struct tegra_tsensor_data *data; | ||
1685 | struct resource *r; | ||
1686 | int err; | ||
1687 | unsigned int reg; | ||
1688 | u8 i; | ||
1689 | struct tegra_tsensor_platform_data *tsensor_data; | ||
1690 | |||
1691 | data = kzalloc(sizeof(struct tegra_tsensor_data), GFP_KERNEL); | ||
1692 | if (!data) { | ||
1693 | dev_err(&pdev->dev, "[%s,line=%d]: Failed to allocate " | ||
1694 | "memory\n", __func__, __LINE__); | ||
1695 | err = -ENOMEM; | ||
1696 | goto exit; | ||
1697 | } | ||
1698 | mutex_init(&data->mutex); | ||
1699 | platform_set_drvdata(pdev, data); | ||
1700 | |||
1701 | /* Register sysfs hooks */ | ||
1702 | for (i = 0; i < ARRAY_SIZE(tsensor_nodes); i++) { | ||
1703 | err = device_create_file(&pdev->dev, | ||
1704 | &tsensor_nodes[i].dev_attr); | ||
1705 | if (err) { | ||
1706 | dev_err(&pdev->dev, "device_create_file failed.\n"); | ||
1707 | goto err0; | ||
1708 | } | ||
1709 | } | ||
1710 | |||
1711 | data->hwmon_dev = hwmon_device_register(&pdev->dev); | ||
1712 | if (IS_ERR(data->hwmon_dev)) { | ||
1713 | err = PTR_ERR(data->hwmon_dev); | ||
1714 | goto err1; | ||
1715 | } | ||
1716 | |||
1717 | dev_set_drvdata(data->hwmon_dev, data); | ||
1718 | |||
1719 | spin_lock_init(&data->tsensor_lock); | ||
1720 | |||
1721 | /* map tsensor register space */ | ||
1722 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1723 | if (r == NULL) { | ||
1724 | dev_err(&pdev->dev, "[%s,line=%d]: Failed to get io " | ||
1725 | "resource\n", __func__, __LINE__); | ||
1726 | err = -ENODEV; | ||
1727 | goto err2; | ||
1728 | } | ||
1729 | |||
1730 | if (!request_mem_region(r->start, (r->end - r->start) + 1, | ||
1731 | dev_name(&pdev->dev))) { | ||
1732 | dev_err(&pdev->dev, "[%s,line=%d]: Error mem busy\n", | ||
1733 | __func__, __LINE__); | ||
1734 | err = -EBUSY; | ||
1735 | goto err2; | ||
1736 | } | ||
1737 | |||
1738 | data->phys = r->start; | ||
1739 | data->phys_end = r->end; | ||
1740 | data->base = ioremap(r->start, r->end - r->start + 1); | ||
1741 | if (!data->base) { | ||
1742 | dev_err(&pdev->dev, "[%s, line=%d]: can't ioremap " | ||
1743 | "tsensor iomem\n", __FILE__, __LINE__); | ||
1744 | err = -ENOMEM; | ||
1745 | goto err3; | ||
1746 | } | ||
1747 | |||
1748 | /* map pmc rst_status register */ | ||
1749 | r = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
1750 | if (r == NULL) { | ||
1751 | dev_err(&pdev->dev, "[%s,line=%d]: Failed to get io " | ||
1752 | "resource\n", __func__, __LINE__); | ||
1753 | err = -ENODEV; | ||
1754 | goto err4; | ||
1755 | } | ||
1756 | |||
1757 | if (!request_mem_region(r->start, (r->end - r->start) + 1, | ||
1758 | dev_name(&pdev->dev))) { | ||
1759 | dev_err(&pdev->dev, "[%s, line=%d]: Error mem busy\n", | ||
1760 | __func__, __LINE__); | ||
1761 | err = -EBUSY; | ||
1762 | goto err4; | ||
1763 | } | ||
1764 | |||
1765 | data->pmc_phys = r->start; | ||
1766 | data->pmc_phys_end = r->end; | ||
1767 | data->pmc_rst_base = ioremap(r->start, r->end - r->start + 1); | ||
1768 | if (!data->pmc_rst_base) { | ||
1769 | dev_err(&pdev->dev, "[%s, line=%d]: can't ioremap " | ||
1770 | "pmc iomem\n", __FILE__, __LINE__); | ||
1771 | err = -ENOMEM; | ||
1772 | goto err5; | ||
1773 | } | ||
1774 | |||
1775 | /* fuse revisions less than TSENSOR_FUSE_REV1 | ||
1776 | bypass tsensor driver init */ | ||
1777 | /* tsensor active instance decided based on fuse revision */ | ||
1778 | err = tegra_fuse_get_revision(®); | ||
1779 | if (err) | ||
1780 | goto err6; | ||
1781 | /* check for higher revision done first */ | ||
1782 | /* instance 0 is used for fuse revision TSENSOR_FUSE_REV2 onwards */ | ||
1783 | if (reg >= TSENSOR_FUSE_REV2) | ||
1784 | data->instance = TSENSOR_INSTANCE1; | ||
1785 | /* instance 1 is used for fuse revision TSENSOR_FUSE_REV1 till | ||
1786 | TSENSOR_FUSE_REV2 */ | ||
1787 | else if (reg >= TSENSOR_FUSE_REV1) | ||
1788 | data->instance = TSENSOR_INSTANCE2; | ||
1789 | pr_info("tsensor active instance=%d\n", data->instance); | ||
1790 | |||
1791 | /* tegra tsensor - setup and init */ | ||
1792 | err = tegra_tsensor_setup(pdev); | ||
1793 | if (err) | ||
1794 | goto err6; | ||
1795 | |||
1796 | dump_tsensor_regs(data); | ||
1797 | dev_dbg(&pdev->dev, "end tegra_tsensor_probe\n"); | ||
1798 | |||
1799 | tsensor_data = pdev->dev.platform_data; | ||
1800 | if (tsensor_data->probe_callback) | ||
1801 | tsensor_data->probe_callback(data); | ||
1802 | |||
1803 | return 0; | ||
1804 | err6: | ||
1805 | iounmap(data->pmc_rst_base); | ||
1806 | err5: | ||
1807 | release_mem_region(data->pmc_phys, (data->pmc_phys_end - | ||
1808 | data->pmc_phys) + 1); | ||
1809 | err4: | ||
1810 | iounmap(data->base); | ||
1811 | err3: | ||
1812 | release_mem_region(data->phys, (data->phys_end - | ||
1813 | data->phys) + 1); | ||
1814 | err2: | ||
1815 | hwmon_device_unregister(data->hwmon_dev); | ||
1816 | err1: | ||
1817 | for (i = 0; i < ARRAY_SIZE(tsensor_nodes); i++) | ||
1818 | device_remove_file(&pdev->dev, &tsensor_nodes[i].dev_attr); | ||
1819 | err0: | ||
1820 | kfree(data); | ||
1821 | exit: | ||
1822 | dev_err(&pdev->dev, "%s error=%d returned\n", __func__, err); | ||
1823 | return err; | ||
1824 | } | ||
1825 | |||
1826 | static int __devexit tegra_tsensor_remove(struct platform_device *pdev) | ||
1827 | { | ||
1828 | struct tegra_tsensor_data *data = platform_get_drvdata(pdev); | ||
1829 | u8 i; | ||
1830 | |||
1831 | hwmon_device_unregister(data->hwmon_dev); | ||
1832 | for (i = 0; i < ARRAY_SIZE(tsensor_nodes); i++) | ||
1833 | device_remove_file(&pdev->dev, &tsensor_nodes[i].dev_attr); | ||
1834 | |||
1835 | if (data->is_edp_supported) { | ||
1836 | cancel_delayed_work_sync(&data->work); | ||
1837 | destroy_workqueue(data->workqueue); | ||
1838 | data->workqueue = NULL; | ||
1839 | } | ||
1840 | |||
1841 | free_irq(data->irq, data); | ||
1842 | |||
1843 | iounmap(data->pmc_rst_base); | ||
1844 | release_mem_region(data->pmc_phys, (data->pmc_phys_end - | ||
1845 | data->pmc_phys) + 1); | ||
1846 | iounmap(data->base); | ||
1847 | release_mem_region(data->phys, (data->phys_end - | ||
1848 | data->phys) + 1); | ||
1849 | |||
1850 | kfree(data); | ||
1851 | |||
1852 | return 0; | ||
1853 | } | ||
1854 | |||
1855 | static void save_tsensor_regs(struct tegra_tsensor_data *data) | ||
1856 | { | ||
1857 | int i; | ||
1858 | for (i = 0; i < TSENSOR_COUNT; i++) { | ||
1859 | data->config0[i] = tsensor_readl(data, | ||
1860 | ((i << 16) | SENSOR_CFG0)); | ||
1861 | data->config1[i] = tsensor_readl(data, | ||
1862 | ((i << 16) | SENSOR_CFG1)); | ||
1863 | data->config2[i] = tsensor_readl(data, | ||
1864 | ((i << 16) | SENSOR_CFG2)); | ||
1865 | } | ||
1866 | } | ||
1867 | |||
1868 | static void restore_tsensor_regs(struct tegra_tsensor_data *data) | ||
1869 | { | ||
1870 | int i; | ||
1871 | for (i = 0; i < TSENSOR_COUNT; i++) { | ||
1872 | tsensor_writel(data, data->config0[i], | ||
1873 | ((i << 16) | SENSOR_CFG0)); | ||
1874 | tsensor_writel(data, data->config1[i], | ||
1875 | ((i << 16) | SENSOR_CFG1)); | ||
1876 | tsensor_writel(data, data->config2[i], | ||
1877 | ((i << 16) | SENSOR_CFG2)); | ||
1878 | } | ||
1879 | } | ||
1880 | |||
1881 | #ifdef CONFIG_PM | ||
1882 | static int tsensor_suspend(struct platform_device *pdev, | ||
1883 | pm_message_t state) | ||
1884 | { | ||
1885 | struct tegra_tsensor_data *data = platform_get_drvdata(pdev); | ||
1886 | unsigned int config0; | ||
1887 | |||
1888 | /* set STOP bit, else OVERFLOW interrupt seen in LP1 */ | ||
1889 | config0 = tsensor_readl(data, ((data->instance << 16) | SENSOR_CFG0)); | ||
1890 | config0 |= (1 << SENSOR_CFG0_STOP_SHIFT); | ||
1891 | tsensor_writel(data, config0, ((data->instance << 16) | SENSOR_CFG0)); | ||
1892 | |||
1893 | /* save current settings before suspend, when STOP bit is set */ | ||
1894 | save_tsensor_regs(data); | ||
1895 | tsensor_clk_enable(data, false); | ||
1896 | |||
1897 | return 0; | ||
1898 | } | ||
1899 | |||
1900 | static int tsensor_resume(struct platform_device *pdev) | ||
1901 | { | ||
1902 | struct tegra_tsensor_data *data = platform_get_drvdata(pdev); | ||
1903 | unsigned int config0; | ||
1904 | |||
1905 | tsensor_clk_enable(data, true); | ||
1906 | /* restore current settings before suspend, no need | ||
1907 | * to clear STOP bit */ | ||
1908 | restore_tsensor_regs(data); | ||
1909 | |||
1910 | /* clear STOP bit, after restoring regs */ | ||
1911 | config0 = tsensor_readl(data, ((data->instance << 16) | SENSOR_CFG0)); | ||
1912 | config0 &= ~(1 << SENSOR_CFG0_STOP_SHIFT); | ||
1913 | tsensor_writel(data, config0, ((data->instance << 16) | SENSOR_CFG0)); | ||
1914 | |||
1915 | if (data->is_edp_supported) | ||
1916 | schedule_delayed_work(&data->work, 0); | ||
1917 | |||
1918 | return 0; | ||
1919 | } | ||
1920 | #endif | ||
1921 | |||
1922 | static struct platform_driver tegra_tsensor_driver = { | ||
1923 | .driver = { | ||
1924 | .owner = THIS_MODULE, | ||
1925 | .name = "tegra-tsensor", | ||
1926 | }, | ||
1927 | .probe = tegra_tsensor_probe, | ||
1928 | .remove = __devexit_p(tegra_tsensor_remove), | ||
1929 | #ifdef CONFIG_PM | ||
1930 | .suspend = tsensor_suspend, | ||
1931 | .resume = tsensor_resume, | ||
1932 | #endif | ||
1933 | }; | ||
1934 | |||
1935 | static int __init tegra_tsensor_init(void) | ||
1936 | { | ||
1937 | return platform_driver_register(&tegra_tsensor_driver); | ||
1938 | } | ||
1939 | module_init(tegra_tsensor_init); | ||
1940 | |||
1941 | static void __exit tegra_tsensor_exit(void) | ||
1942 | { | ||
1943 | platform_driver_unregister(&tegra_tsensor_driver); | ||
1944 | } | ||
1945 | module_exit(tegra_tsensor_exit); | ||
1946 | |||
1947 | MODULE_AUTHOR("nvidia"); | ||
1948 | MODULE_DESCRIPTION("Nvidia Tegra Temperature Sensor driver"); | ||
1949 | MODULE_LICENSE("GPL"); | ||