aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/nct1008.c
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
commitfcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch)
treea57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/misc/nct1008.c
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'drivers/misc/nct1008.c')
-rw-r--r--drivers/misc/nct1008.c944
1 files changed, 944 insertions, 0 deletions
diff --git a/drivers/misc/nct1008.c b/drivers/misc/nct1008.c
new file mode 100644
index 00000000000..3a8aa6b9dbd
--- /dev/null
+++ b/drivers/misc/nct1008.c
@@ -0,0 +1,944 @@
1/*
2 * drivers/misc/nct1008.c
3 *
4 * Driver for NCT1008, temperature monitoring device from ON Semiconductors
5 *
6 * Copyright (c) 2010-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; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22
23
24#include <linux/interrupt.h>
25#include <linux/module.h>
26#include <linux/i2c.h>
27#include <linux/slab.h>
28#include <linux/err.h>
29#include <linux/gpio.h>
30#include <linux/device.h>
31#include <linux/nct1008.h>
32#include <linux/delay.h>
33#include <linux/regulator/consumer.h>
34
35#define DRIVER_NAME "nct1008"
36
37/* Register Addresses */
38#define LOCAL_TEMP_RD 0x00
39#define EXT_TEMP_RD_HI 0x01
40#define EXT_TEMP_RD_LO 0x10
41#define STATUS_RD 0x02
42#define CONFIG_RD 0x03
43
44#define LOCAL_TEMP_HI_LIMIT_RD 0x05
45#define LOCAL_TEMP_LO_LIMIT_RD 0x06
46
47#define EXT_TEMP_HI_LIMIT_HI_BYTE_RD 0x07
48#define EXT_TEMP_LO_LIMIT_HI_BYTE_RD 0x08
49
50#define CONFIG_WR 0x09
51#define CONV_RATE_WR 0x0A
52#define LOCAL_TEMP_HI_LIMIT_WR 0x0B
53#define LOCAL_TEMP_LO_LIMIT_WR 0x0C
54#define EXT_TEMP_HI_LIMIT_HI_BYTE_WR 0x0D
55#define EXT_TEMP_LO_LIMIT_HI_BYTE_WR 0x0E
56#define ONE_SHOT 0x0F
57#define OFFSET_WR 0x11
58#define OFFSET_QUARTER_WR 0x12
59#define EXT_THERM_LIMIT_WR 0x19
60#define LOCAL_THERM_LIMIT_WR 0x20
61#define THERM_HYSTERESIS_WR 0x21
62
63/* Configuration Register Bits */
64#define EXTENDED_RANGE_BIT BIT(2)
65#define THERM2_BIT BIT(5)
66#define STANDBY_BIT BIT(6)
67#define ALERT_BIT BIT(7)
68
69/* Max Temperature Measurements */
70#define EXTENDED_RANGE_OFFSET 64U
71#define STANDARD_RANGE_MAX 127U
72#define EXTENDED_RANGE_MAX (150U + EXTENDED_RANGE_OFFSET)
73
74#define NCT1008_MIN_TEMP -64
75#define NCT1008_MAX_TEMP 191
76
77#define MAX_STR_PRINT 50
78
79#define MAX_CONV_TIME_ONESHOT_MS (52)
80#define CELSIUS_TO_MILLICELSIUS(x) ((x)*1000)
81#define MILLICELSIUS_TO_CELSIUS(x) ((x)/1000)
82
83
84static int conv_period_ms_table[] =
85 {16000, 8000, 4000, 2000, 1000, 500, 250, 125, 63, 32, 16};
86
87static inline s8 value_to_temperature(bool extended, u8 value)
88{
89 return extended ? (s8)(value - EXTENDED_RANGE_OFFSET) : (s8)value;
90}
91
92static inline u8 temperature_to_value(bool extended, s8 temp)
93{
94 return extended ? (u8)(temp + EXTENDED_RANGE_OFFSET) : (u8)temp;
95}
96
97static int nct1008_get_temp(struct device *dev, long *pTemp)
98{
99 struct i2c_client *client = to_i2c_client(dev);
100 struct nct1008_platform_data *pdata = client->dev.platform_data;
101 s8 temp_local;
102 u8 temp_ext_lo;
103 s8 temp_ext_hi;
104 long temp_ext_milli;
105 long temp_local_milli;
106 u8 value;
107
108 /* Read Local Temp */
109 value = i2c_smbus_read_byte_data(client, LOCAL_TEMP_RD);
110 if (value < 0)
111 goto error;
112 temp_local = value_to_temperature(pdata->ext_range, value);
113 temp_local_milli = CELSIUS_TO_MILLICELSIUS(temp_local);
114
115 /* Read External Temp */
116 value = i2c_smbus_read_byte_data(client, EXT_TEMP_RD_LO);
117 if (value < 0)
118 goto error;
119 temp_ext_lo = (value >> 6);
120
121 value = i2c_smbus_read_byte_data(client, EXT_TEMP_RD_HI);
122 if (value < 0)
123 goto error;
124 temp_ext_hi = value_to_temperature(pdata->ext_range, value);
125
126 temp_ext_milli = CELSIUS_TO_MILLICELSIUS(temp_ext_hi) +
127 temp_ext_lo * 250;
128
129 /* Return max between Local and External Temp */
130 *pTemp = max(temp_local_milli, temp_ext_milli);
131
132 dev_dbg(dev, "\n %s: ret temp=%ldC ", __func__, *pTemp);
133 return 0;
134error:
135 dev_err(&client->dev, "\n error in file=: %s %s() line=%d: "
136 "error=%d ", __FILE__, __func__, __LINE__, value);
137 return value;
138}
139
140static ssize_t nct1008_show_temp(struct device *dev,
141 struct device_attribute *attr, char *buf)
142{
143 struct i2c_client *client = to_i2c_client(dev);
144 struct nct1008_platform_data *pdata = client->dev.platform_data;
145 s8 temp1 = 0;
146 s8 temp = 0;
147 u8 temp2 = 0;
148 int value = 0;
149
150 if (!dev || !buf || !attr)
151 return -EINVAL;
152
153 value = i2c_smbus_read_byte_data(client, LOCAL_TEMP_RD);
154 if (value < 0)
155 goto error;
156 temp1 = value_to_temperature(pdata->ext_range, value);
157
158 value = i2c_smbus_read_byte_data(client, EXT_TEMP_RD_LO);
159 if (value < 0)
160 goto error;
161 temp2 = (value >> 6);
162 value = i2c_smbus_read_byte_data(client, EXT_TEMP_RD_HI);
163 if (value < 0)
164 goto error;
165 temp = value_to_temperature(pdata->ext_range, value);
166
167 return snprintf(buf, MAX_STR_PRINT, "%d %d.%d\n",
168 temp1, temp, temp2 * 25);
169
170error:
171 return snprintf(buf, MAX_STR_PRINT,
172 "Error read local/ext temperature\n");
173}
174
175static ssize_t nct1008_show_temp_overheat(struct device *dev,
176 struct device_attribute *attr,
177 char *buf)
178{
179 struct i2c_client *client = to_i2c_client(dev);
180 struct nct1008_platform_data *pdata = client->dev.platform_data;
181 int value;
182 s8 temp, temp2;
183
184 /* Local temperature h/w shutdown limit */
185 value = i2c_smbus_read_byte_data(client, LOCAL_THERM_LIMIT_WR);
186 if (value < 0)
187 goto error;
188 temp = value_to_temperature(pdata->ext_range, value);
189
190 /* External temperature h/w shutdown limit */
191 value = i2c_smbus_read_byte_data(client, EXT_THERM_LIMIT_WR);
192 if (value < 0)
193 goto error;
194 temp2 = value_to_temperature(pdata->ext_range, value);
195
196 return snprintf(buf, MAX_STR_PRINT, "%d %d\n", temp, temp2);
197error:
198 dev_err(dev, "%s: failed to read temperature-overheat "
199 "\n", __func__);
200 return snprintf(buf, MAX_STR_PRINT, " Rd overheat Error\n");
201}
202
203static ssize_t nct1008_set_temp_overheat(struct device *dev,
204 struct device_attribute *attr,
205 const char *buf, size_t count)
206{
207 long int num;
208 int err;
209 u8 temp;
210 long currTemp;
211 struct i2c_client *client = to_i2c_client(dev);
212 struct nct1008_platform_data *pdata = client->dev.platform_data;
213 char bufTemp[MAX_STR_PRINT];
214 char bufOverheat[MAX_STR_PRINT];
215 unsigned int ret;
216
217 if (strict_strtol(buf, 0, &num)) {
218 dev_err(dev, "\n file: %s, line=%d return %s() ", __FILE__,
219 __LINE__, __func__);
220 return -EINVAL;
221 }
222 if (((int)num < NCT1008_MIN_TEMP) || ((int)num >= NCT1008_MAX_TEMP)) {
223 dev_err(dev, "\n file: %s, line=%d return %s() ", __FILE__,
224 __LINE__, __func__);
225 return -EINVAL;
226 }
227 /* check for system power down */
228 err = nct1008_get_temp(dev, &currTemp);
229 if (err)
230 goto error;
231
232 currTemp = MILLICELSIUS_TO_CELSIUS(currTemp);
233
234 if (currTemp >= (int)num) {
235 ret = nct1008_show_temp(dev, attr, bufTemp);
236 ret = nct1008_show_temp_overheat(dev, attr, bufOverheat);
237 dev_err(dev, "\nCurrent temp: %s ", bufTemp);
238 dev_err(dev, "\nOld overheat limit: %s ", bufOverheat);
239 dev_err(dev, "\nReset from overheat: curr temp=%ld, "
240 "new overheat temp=%d\n\n", currTemp, (int)num);
241 }
242
243 /* External temperature h/w shutdown limit */
244 temp = temperature_to_value(pdata->ext_range, (s8)num);
245 err = i2c_smbus_write_byte_data(client, EXT_THERM_LIMIT_WR, temp);
246 if (err < 0)
247 goto error;
248
249 /* Local temperature h/w shutdown limit */
250 temp = temperature_to_value(pdata->ext_range, (s8)num);
251 err = i2c_smbus_write_byte_data(client, LOCAL_THERM_LIMIT_WR, temp);
252 if (err < 0)
253 goto error;
254 return count;
255error:
256 dev_err(dev, " %s: failed to set temperature-overheat\n", __func__);
257 return err;
258}
259
260static ssize_t nct1008_show_temp_alert(struct device *dev,
261 struct device_attribute *attr,
262 char *buf)
263{
264 struct i2c_client *client = to_i2c_client(dev);
265 struct nct1008_platform_data *pdata = client->dev.platform_data;
266 int value;
267 s8 temp_hi, temp_lo;
268 /* External Temperature Throttling hi-limit */
269 value = i2c_smbus_read_byte_data(client, EXT_TEMP_HI_LIMIT_HI_BYTE_RD);
270 if (value < 0)
271 goto error;
272 temp_hi = value_to_temperature(pdata->ext_range, value);
273
274 /* External Temperature Throttling lo-limit */
275 value = i2c_smbus_read_byte_data(client, EXT_TEMP_LO_LIMIT_HI_BYTE_RD);
276 if (value < 0)
277 goto error;
278 temp_lo = value_to_temperature(pdata->ext_range, value);
279
280 return snprintf(buf, MAX_STR_PRINT, "lo:%d hi:%d\n", temp_lo, temp_hi);
281error:
282 dev_err(dev, "%s: failed to read temperature-alert\n", __func__);
283 return snprintf(buf, MAX_STR_PRINT, " Rd alert Error\n");
284}
285
286static ssize_t nct1008_set_temp_alert(struct device *dev,
287 struct device_attribute *attr,
288 const char *buf, size_t count)
289{
290 long int num;
291 int value;
292 int err;
293 struct i2c_client *client = to_i2c_client(dev);
294 struct nct1008_platform_data *pdata = client->dev.platform_data;
295
296 if (strict_strtol(buf, 0, &num)) {
297 dev_err(dev, "\n file: %s, line=%d return %s() ", __FILE__,
298 __LINE__, __func__);
299 return -EINVAL;
300 }
301 if (((int)num < NCT1008_MIN_TEMP) || ((int)num >= NCT1008_MAX_TEMP)) {
302 dev_err(dev, "\n file: %s, line=%d return %s() ", __FILE__,
303 __LINE__, __func__);
304 return -EINVAL;
305 }
306
307 /* External Temperature Throttling limit */
308 value = temperature_to_value(pdata->ext_range, (s8)num);
309 err = i2c_smbus_write_byte_data(client, EXT_TEMP_HI_LIMIT_HI_BYTE_WR,
310 value);
311 if (err < 0)
312 goto error;
313
314 /* Local Temperature Throttling limit */
315 err = i2c_smbus_write_byte_data(client, LOCAL_TEMP_HI_LIMIT_WR,
316 value);
317 if (err < 0)
318 goto error;
319
320 return count;
321error:
322 dev_err(dev, "%s: failed to set temperature-alert "
323 "\n", __func__);
324 return err;
325}
326
327static ssize_t nct1008_show_ext_temp(struct device *dev,
328 struct device_attribute *attr, char *buf)
329{
330 struct i2c_client *client = to_i2c_client(dev);
331 struct nct1008_platform_data *pdata = client->dev.platform_data;
332 s8 temp_value;
333 int data = 0;
334 int data_lo;
335
336 if (!dev || !buf || !attr)
337 return -EINVAL;
338
339 /* When reading the full external temperature value, read the
340 * LSB first. This causes the MSB to be locked (that is, the
341 * ADC does not write to it) until it is read */
342 data_lo = i2c_smbus_read_byte_data(client, EXT_TEMP_RD_LO);
343 if (data_lo < 0) {
344 dev_err(&client->dev, "%s: failed to read "
345 "ext_temperature, i2c error=%d\n", __func__, data_lo);
346 goto error;
347 }
348
349 data = i2c_smbus_read_byte_data(client, EXT_TEMP_RD_HI);
350 if (data < 0) {
351 dev_err(&client->dev, "%s: failed to read "
352 "ext_temperature, i2c error=%d\n", __func__, data);
353 goto error;
354 }
355
356 temp_value = value_to_temperature(pdata->ext_range, data);
357
358 return snprintf(buf, MAX_STR_PRINT, "%d.%d\n", temp_value,
359 (25 * (data_lo >> 6)));
360error:
361 return snprintf(buf, MAX_STR_PRINT, "Error read ext temperature\n");
362}
363
364static DEVICE_ATTR(temperature, S_IRUGO, nct1008_show_temp, NULL);
365static DEVICE_ATTR(temperature_overheat, (S_IRUGO | (S_IWUSR | S_IWGRP)),
366 nct1008_show_temp_overheat, nct1008_set_temp_overheat);
367static DEVICE_ATTR(temperature_alert, (S_IRUGO | (S_IWUSR | S_IWGRP)),
368 nct1008_show_temp_alert, nct1008_set_temp_alert);
369static DEVICE_ATTR(ext_temperature, S_IRUGO, nct1008_show_ext_temp, NULL);
370
371static struct attribute *nct1008_attributes[] = {
372 &dev_attr_temperature.attr,
373 &dev_attr_temperature_overheat.attr,
374 &dev_attr_temperature_alert.attr,
375 &dev_attr_ext_temperature.attr,
376 NULL
377};
378
379static const struct attribute_group nct1008_attr_group = {
380 .attrs = nct1008_attributes,
381};
382
383#ifdef CONFIG_DEBUG_FS
384#include <linux/debugfs.h>
385#include <linux/seq_file.h>
386static void print_reg(const char *reg_name, struct seq_file *s,
387 int offset)
388{
389 struct nct1008_data *nct_data = s->private;
390 int ret;
391
392 ret = i2c_smbus_read_byte_data(nct_data->client,
393 offset);
394 if (ret >= 0)
395 seq_printf(s, "Reg %s Addr = 0x%02x Reg 0x%02x "
396 "Value 0x%02x\n", reg_name,
397 nct_data->client->addr,
398 offset, ret);
399 else
400 seq_printf(s, "%s: line=%d, i2c read error=%d\n",
401 __func__, __LINE__, ret);
402}
403
404static int dbg_nct1008_show(struct seq_file *s, void *unused)
405{
406 seq_printf(s, "nct1008 Registers\n");
407 seq_printf(s, "------------------\n");
408 print_reg("Local Temp Value ", s, 0x00);
409 print_reg("Ext Temp Value Hi ", s, 0x01);
410 print_reg("Status ", s, 0x02);
411 print_reg("Configuration ", s, 0x03);
412 print_reg("Conversion Rate ", s, 0x04);
413 print_reg("Local Temp Hi Limit ", s, 0x05);
414 print_reg("Local Temp Lo Limit ", s, 0x06);
415 print_reg("Ext Temp Hi Limit Hi", s, 0x07);
416 print_reg("Ext Temp Hi Limit Lo", s, 0x13);
417 print_reg("Ext Temp Lo Limit Hi", s, 0x08);
418 print_reg("Ext Temp Lo Limit Lo", s, 0x14);
419 print_reg("Ext Temp Value Lo ", s, 0x10);
420 print_reg("Ext Temp Offset Hi ", s, 0x11);
421 print_reg("Ext Temp Offset Lo ", s, 0x12);
422 print_reg("Ext THERM Limit ", s, 0x19);
423 print_reg("Local THERM Limit ", s, 0x20);
424 print_reg("THERM Hysteresis ", s, 0x21);
425 print_reg("Consecutive ALERT ", s, 0x22);
426 return 0;
427}
428
429static int dbg_nct1008_open(struct inode *inode, struct file *file)
430{
431 return single_open(file, dbg_nct1008_show, inode->i_private);
432}
433
434static const struct file_operations debug_fops = {
435 .open = dbg_nct1008_open,
436 .read = seq_read,
437 .llseek = seq_lseek,
438 .release = single_release,
439};
440
441static int __init nct1008_debuginit(struct nct1008_data *nct)
442{
443 int err = 0;
444 struct dentry *d;
445 d = debugfs_create_file("nct1008", S_IRUGO, NULL,
446 (void *)nct, &debug_fops);
447 if ((!d) || IS_ERR(d)) {
448 dev_err(&nct->client->dev, "Error: %s debugfs_create_file"
449 " returned an error\n", __func__);
450 err = -ENOENT;
451 goto end;
452 }
453 if (d == ERR_PTR(-ENODEV)) {
454 dev_err(&nct->client->dev, "Error: %s debugfs not supported "
455 "error=-ENODEV\n", __func__);
456 err = -ENODEV;
457 } else {
458 nct->dent = d;
459 }
460end:
461 return err;
462}
463#else
464static int __init nct1008_debuginit(struct nct1008_data *nct)
465{
466 return 0;
467}
468#endif
469
470static int nct1008_enable(struct i2c_client *client)
471{
472 struct nct1008_data *data = i2c_get_clientdata(client);
473 int err;
474
475 err = i2c_smbus_write_byte_data(client, CONFIG_WR,
476 data->config & ~STANDBY_BIT);
477 if (err < 0)
478 dev_err(&client->dev, "%s, line=%d, i2c write error=%d\n",
479 __func__, __LINE__, err);
480 return err;
481}
482
483static int nct1008_disable(struct i2c_client *client)
484{
485 struct nct1008_data *data = i2c_get_clientdata(client);
486 int err;
487
488 err = i2c_smbus_write_byte_data(client, CONFIG_WR,
489 data->config | STANDBY_BIT);
490 if (err < 0)
491 dev_err(&client->dev, "%s, line=%d, i2c write error=%d\n",
492 __func__, __LINE__, err);
493 return err;
494}
495
496static int nct1008_within_limits(struct nct1008_data *data)
497{
498 int intr_status;
499
500 intr_status = i2c_smbus_read_byte_data(data->client, STATUS_RD);
501
502 return !(intr_status & (BIT(3) | BIT(4)));
503}
504
505static void nct1008_work_func(struct work_struct *work)
506{
507 struct nct1008_data *data = container_of(work, struct nct1008_data,
508 work);
509 int intr_status;
510 struct timespec ts;
511
512 nct1008_disable(data->client);
513
514 if (data->alert_func)
515 if (!nct1008_within_limits(data))
516 data->alert_func(data->alert_data);
517
518 /* Initiate one-shot conversion */
519 i2c_smbus_write_byte_data(data->client, ONE_SHOT, 0x1);
520
521 /* Give hardware necessary time to finish conversion */
522 ts = ns_to_timespec(MAX_CONV_TIME_ONESHOT_MS * 1000 * 1000);
523 hrtimer_nanosleep(&ts, NULL, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
524
525 intr_status = i2c_smbus_read_byte_data(data->client, STATUS_RD);
526
527 nct1008_enable(data->client);
528
529 enable_irq(data->client->irq);
530}
531
532static irqreturn_t nct1008_irq(int irq, void *dev_id)
533{
534 struct nct1008_data *data = dev_id;
535
536 disable_irq_nosync(irq);
537 queue_work(data->workqueue, &data->work);
538
539 return IRQ_HANDLED;
540}
541
542static void nct1008_power_control(struct nct1008_data *data, bool is_enable)
543{
544 int ret;
545 if (!data->nct_reg) {
546 data->nct_reg = regulator_get(&data->client->dev, "vdd");
547 if (IS_ERR_OR_NULL(data->nct_reg)) {
548 dev_warn(&data->client->dev, "Error [%d] in"
549 "getting the regulator handle for vdd "
550 "of %s\n", (int)data->nct_reg,
551 dev_name(&data->client->dev));
552 data->nct_reg = NULL;
553 return;
554 }
555 }
556 if (is_enable)
557 ret = regulator_enable(data->nct_reg);
558 else
559 ret = regulator_disable(data->nct_reg);
560
561 if (ret < 0)
562 dev_err(&data->client->dev, "Error in %s rail vdd_nct1008, "
563 "error %d\n", (is_enable) ? "enabling" : "disabling",
564 ret);
565 else
566 dev_info(&data->client->dev, "success in %s rail vdd_nct1008\n",
567 (is_enable) ? "enabling" : "disabling");
568}
569
570static int __devinit nct1008_configure_sensor(struct nct1008_data* data)
571{
572 struct i2c_client *client = data->client;
573 struct nct1008_platform_data *pdata = client->dev.platform_data;
574 u8 value;
575 s8 temp;
576 u8 temp2;
577 int err;
578
579 if (!pdata || !pdata->supported_hwrev)
580 return -ENODEV;
581
582 /* Place in Standby */
583 data->config = STANDBY_BIT;
584 err = i2c_smbus_write_byte_data(client, CONFIG_WR, data->config);
585 if (err)
586 goto error;
587
588 /* External temperature h/w shutdown limit */
589 value = temperature_to_value(pdata->ext_range, NCT1008_MAX_TEMP);
590 err = i2c_smbus_write_byte_data(client, EXT_THERM_LIMIT_WR, value);
591 if (err)
592 goto error;
593
594 /* Local temperature h/w shutdown limit */
595 value = temperature_to_value(pdata->ext_range, NCT1008_MAX_TEMP);
596 err = i2c_smbus_write_byte_data(client, LOCAL_THERM_LIMIT_WR, value);
597 if (err)
598 goto error;
599
600 /* set extended range mode if needed */
601 if (pdata->ext_range)
602 data->config |= EXTENDED_RANGE_BIT;
603 data->config &= ~(THERM2_BIT | ALERT_BIT);
604
605 err = i2c_smbus_write_byte_data(client, CONFIG_WR, data->config);
606 if (err)
607 goto error;
608
609 /* Temperature conversion rate */
610 err = i2c_smbus_write_byte_data(client, CONV_RATE_WR, pdata->conv_rate);
611 if (err)
612 goto error;
613
614 data->conv_period_ms = conv_period_ms_table[pdata->conv_rate];
615
616 /* Setup local hi and lo limits */
617 err = i2c_smbus_write_byte_data(client,
618 LOCAL_TEMP_HI_LIMIT_WR, NCT1008_MAX_TEMP);
619 if (err)
620 goto error;
621
622 err = i2c_smbus_write_byte_data(client,
623 LOCAL_TEMP_LO_LIMIT_WR, 0);
624 if (err)
625 goto error;
626
627 /* Setup external hi and lo limits */
628 err = i2c_smbus_write_byte_data(client,
629 EXT_TEMP_LO_LIMIT_HI_BYTE_WR, 0);
630 if (err)
631 goto error;
632 err = i2c_smbus_write_byte_data(client, EXT_TEMP_HI_LIMIT_HI_BYTE_WR,
633 NCT1008_MAX_TEMP);
634 if (err)
635 goto error;
636
637 /* read initial temperature */
638 value = i2c_smbus_read_byte_data(client, LOCAL_TEMP_RD);
639 if (value < 0) {
640 err = value;
641 goto error;
642 }
643 temp = value_to_temperature(pdata->ext_range, value);
644 dev_dbg(&client->dev, "\n initial local temp = %d ", temp);
645
646 value = i2c_smbus_read_byte_data(client, EXT_TEMP_RD_LO);
647 if (value < 0) {
648 err = value;
649 goto error;
650 }
651 temp2 = (value >> 6);
652 value = i2c_smbus_read_byte_data(client, EXT_TEMP_RD_HI);
653 if (value < 0) {
654 err = value;
655 goto error;
656 }
657 temp = value_to_temperature(pdata->ext_range, value);
658
659 if (temp2 > 0)
660 dev_dbg(&client->dev, "\n initial ext temp = %d.%d deg",
661 temp, temp2 * 25);
662 else
663 dev_dbg(&client->dev, "\n initial ext temp = %d.0 deg", temp);
664
665 /* Remote channel offset */
666 err = i2c_smbus_write_byte_data(client, OFFSET_WR, pdata->offset / 4);
667 if (err < 0)
668 goto error;
669
670 /* Remote channel offset fraction (quarters) */
671 err = i2c_smbus_write_byte_data(client, OFFSET_QUARTER_WR,
672 (pdata->offset % 4) << 6);
673 if (err < 0)
674 goto error;
675
676 /* register sysfs hooks */
677 err = sysfs_create_group(&client->dev.kobj, &nct1008_attr_group);
678 if (err < 0) {
679 dev_err(&client->dev, "\n sysfs create err=%d ", err);
680 goto error;
681 }
682
683 return 0;
684error:
685 dev_err(&client->dev, "\n exit %s, err=%d ", __func__, err);
686 return err;
687}
688
689static int __devinit nct1008_configure_irq(struct nct1008_data *data)
690{
691 data->workqueue = create_singlethread_workqueue("nct1008");
692
693 INIT_WORK(&data->work, nct1008_work_func);
694
695 if (data->client->irq < 0)
696 return 0;
697 else
698 return request_irq(data->client->irq, nct1008_irq,
699 IRQF_TRIGGER_LOW,
700 DRIVER_NAME, data);
701}
702
703int nct1008_thermal_get_temp(struct nct1008_data *data, long *temp)
704{
705 return nct1008_get_temp(&data->client->dev, temp);
706}
707
708int nct1008_thermal_get_temp_low(struct nct1008_data *data, long *temp)
709{
710 *temp = 0;
711 return 0;
712}
713
714int nct1008_thermal_set_limits(struct nct1008_data *data,
715 long lo_limit_milli,
716 long hi_limit_milli)
717{
718 int err;
719 u8 value;
720 bool extended_range = data->plat_data.ext_range;
721 long lo_limit = MILLICELSIUS_TO_CELSIUS(lo_limit_milli);
722 long hi_limit = MILLICELSIUS_TO_CELSIUS(hi_limit_milli);
723
724 if (lo_limit >= hi_limit)
725 return -EINVAL;
726
727 if (data->current_lo_limit != lo_limit) {
728 value = temperature_to_value(extended_range, lo_limit);
729 pr_debug("%s: set lo_limit %ld\n", __func__, lo_limit);
730 err = i2c_smbus_write_byte_data(data->client,
731 EXT_TEMP_LO_LIMIT_HI_BYTE_WR, value);
732 if (err)
733 return err;
734
735 data->current_lo_limit = lo_limit;
736 }
737
738 if (data->current_hi_limit != hi_limit) {
739 value = temperature_to_value(extended_range, hi_limit);
740 pr_debug("%s: set hi_limit %ld\n", __func__, hi_limit);
741 err = i2c_smbus_write_byte_data(data->client,
742 EXT_TEMP_HI_LIMIT_HI_BYTE_WR, value);
743 if (err)
744 return err;
745
746 data->current_hi_limit = hi_limit;
747 }
748
749 return 0;
750}
751
752int nct1008_thermal_set_alert(struct nct1008_data *data,
753 void (*alert_func)(void *),
754 void *alert_data)
755{
756 data->alert_data = alert_data;
757 data->alert_func = alert_func;
758
759 return 0;
760}
761
762int nct1008_thermal_set_shutdown_temp(struct nct1008_data *data,
763 long shutdown_temp_milli)
764{
765 struct i2c_client *client = data->client;
766 struct nct1008_platform_data *pdata = client->dev.platform_data;
767 int err;
768 u8 value;
769 long shutdown_temp;
770
771 shutdown_temp = MILLICELSIUS_TO_CELSIUS(shutdown_temp_milli);
772
773 /* External temperature h/w shutdown limit */
774 value = temperature_to_value(pdata->ext_range, shutdown_temp);
775 err = i2c_smbus_write_byte_data(client, EXT_THERM_LIMIT_WR, value);
776 if (err)
777 return err;
778
779 /* Local temperature h/w shutdown limit */
780 value = temperature_to_value(pdata->ext_range, shutdown_temp);
781 err = i2c_smbus_write_byte_data(client, LOCAL_THERM_LIMIT_WR, value);
782 if (err)
783 return err;
784
785 return 0;
786}
787
788/*
789 * Manufacturer(OnSemi) recommended sequence for
790 * Extended Range mode is as follows
791 * 1. Place in Standby
792 * 2. Scale the THERM and ALERT limits
793 * appropriately(for Extended Range mode).
794 * 3. Enable Extended Range mode.
795 * ALERT mask/THERM2 mode may be done here
796 * as these are not critical
797 * 4. Set Conversion Rate as required
798 * 5. Take device out of Standby
799 */
800
801/*
802 * function nct1008_probe takes care of initial configuration
803 */
804static int __devinit nct1008_probe(struct i2c_client *client,
805 const struct i2c_device_id *id)
806{
807 struct nct1008_data *data;
808 int err;
809 unsigned int delay;
810
811 data = kzalloc(sizeof(struct nct1008_data), GFP_KERNEL);
812 if (!data)
813 return -ENOMEM;
814
815 data->client = client;
816 memcpy(&data->plat_data, client->dev.platform_data,
817 sizeof(struct nct1008_platform_data));
818 i2c_set_clientdata(client, data);
819
820 nct1008_power_control(data, true);
821 /* extended range recommended steps 1 through 4 taken care
822 * in nct1008_configure_sensor function */
823 err = nct1008_configure_sensor(data); /* sensor is in standby */
824 if (err < 0) {
825 dev_err(&client->dev, "\n error file: %s : %s(), line=%d ",
826 __FILE__, __func__, __LINE__);
827 goto error;
828 }
829
830 err = nct1008_configure_irq(data);
831 if (err < 0) {
832 dev_err(&client->dev, "\n error file: %s : %s(), line=%d ",
833 __FILE__, __func__, __LINE__);
834 goto error;
835 }
836 dev_info(&client->dev, "%s: initialized\n", __func__);
837
838 /* extended range recommended step 5 is in nct1008_enable function */
839 err = nct1008_enable(client); /* sensor is running */
840 if (err < 0) {
841 dev_err(&client->dev, "Error: %s, line=%d, error=%d\n",
842 __func__, __LINE__, err);
843 goto error;
844 }
845
846 err = nct1008_debuginit(data);
847 if (err < 0)
848 err = 0; /* without debugfs we may continue */
849
850 /* notify callback that probe is done */
851 if (data->plat_data.probe_callback)
852 data->plat_data.probe_callback(data);
853
854 return 0;
855
856error:
857 dev_err(&client->dev, "\n exit %s, err=%d ", __func__, err);
858 nct1008_power_control(data, false);
859 if (data->nct_reg)
860 regulator_put(data->nct_reg);
861 kfree(data);
862 return err;
863}
864
865static int __devexit nct1008_remove(struct i2c_client *client)
866{
867 struct nct1008_data *data = i2c_get_clientdata(client);
868
869 if (data->dent)
870 debugfs_remove(data->dent);
871
872 free_irq(data->client->irq, data);
873 cancel_work_sync(&data->work);
874 sysfs_remove_group(&client->dev.kobj, &nct1008_attr_group);
875 nct1008_power_control(data, false);
876 if (data->nct_reg)
877 regulator_put(data->nct_reg);
878
879 kfree(data);
880
881 return 0;
882}
883
884#ifdef CONFIG_PM
885static int nct1008_suspend(struct i2c_client *client, pm_message_t state)
886{
887 int err;
888
889 disable_irq(client->irq);
890 err = nct1008_disable(client);
891 return err;
892}
893
894static int nct1008_resume(struct i2c_client *client)
895{
896 struct nct1008_data *data = i2c_get_clientdata(client);
897 int err;
898
899 err = nct1008_enable(client);
900 if (err < 0) {
901 dev_err(&client->dev, "Error: %s, error=%d\n",
902 __func__, err);
903 return err;
904 }
905 enable_irq(client->irq);
906
907 return 0;
908}
909#endif
910
911static const struct i2c_device_id nct1008_id[] = {
912 { DRIVER_NAME, 0 },
913 { }
914};
915MODULE_DEVICE_TABLE(i2c, nct1008_id);
916
917static struct i2c_driver nct1008_driver = {
918 .driver = {
919 .name = DRIVER_NAME,
920 },
921 .probe = nct1008_probe,
922 .remove = __devexit_p(nct1008_remove),
923 .id_table = nct1008_id,
924#ifdef CONFIG_PM
925 .suspend = nct1008_suspend,
926 .resume = nct1008_resume,
927#endif
928};
929
930static int __init nct1008_init(void)
931{
932 return i2c_add_driver(&nct1008_driver);
933}
934
935static void __exit nct1008_exit(void)
936{
937 i2c_del_driver(&nct1008_driver);
938}
939
940MODULE_DESCRIPTION("Temperature sensor driver for OnSemi NCT1008");
941MODULE_LICENSE("GPL");
942
943module_init(nct1008_init);
944module_exit(nct1008_exit);