Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
adt7410.c
Go to the documentation of this file.
1 /*
2  * adt7410.c - Part of lm_sensors, Linux kernel modules for hardware
3  * monitoring
4  * This driver handles the ADT7410 and compatible digital temperature sensors.
5  * Hartmut Knaack <[email protected]> 2012-07-22
6  * based on lm75.c by Frodo Looijaard <[email protected]>
7  * and adt7410.c from iio-staging by Sonic Zhang <[email protected]>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  */
23 
24 #include <linux/module.h>
25 #include <linux/init.h>
26 #include <linux/slab.h>
27 #include <linux/jiffies.h>
28 #include <linux/i2c.h>
29 #include <linux/hwmon.h>
30 #include <linux/hwmon-sysfs.h>
31 #include <linux/err.h>
32 #include <linux/mutex.h>
33 #include <linux/delay.h>
34 
35 /*
36  * ADT7410 registers definition
37  */
38 
39 #define ADT7410_TEMPERATURE 0
40 #define ADT7410_STATUS 2
41 #define ADT7410_CONFIG 3
42 #define ADT7410_T_ALARM_HIGH 4
43 #define ADT7410_T_ALARM_LOW 6
44 #define ADT7410_T_CRIT 8
45 #define ADT7410_T_HYST 0xA
46 
47 /*
48  * ADT7410 status
49  */
50 #define ADT7410_STAT_T_LOW (1 << 4)
51 #define ADT7410_STAT_T_HIGH (1 << 5)
52 #define ADT7410_STAT_T_CRIT (1 << 6)
53 #define ADT7410_STAT_NOT_RDY (1 << 7)
54 
55 /*
56  * ADT7410 config
57  */
58 #define ADT7410_FAULT_QUEUE_MASK (1 << 0 | 1 << 1)
59 #define ADT7410_CT_POLARITY (1 << 2)
60 #define ADT7410_INT_POLARITY (1 << 3)
61 #define ADT7410_EVENT_MODE (1 << 4)
62 #define ADT7410_MODE_MASK (1 << 5 | 1 << 6)
63 #define ADT7410_FULL (0 << 5 | 0 << 6)
64 #define ADT7410_PD (1 << 5 | 1 << 6)
65 #define ADT7410_RESOLUTION (1 << 7)
66 
67 /*
68  * ADT7410 masks
69  */
70 #define ADT7410_T13_VALUE_MASK 0xFFF8
71 #define ADT7410_T_HYST_MASK 0xF
72 
73 /* straight from the datasheet */
74 #define ADT7410_TEMP_MIN (-55000)
75 #define ADT7410_TEMP_MAX 150000
76 
77 enum adt7410_type { /* keep sorted in alphabetical order */
79 };
80 
81 /* Addresses scanned */
82 static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
84 
85 static const u8 ADT7410_REG_TEMP[4] = {
86  ADT7410_TEMPERATURE, /* input */
87  ADT7410_T_ALARM_HIGH, /* high */
88  ADT7410_T_ALARM_LOW, /* low */
89  ADT7410_T_CRIT, /* critical */
90 };
91 
92 /* Each client has this additional data */
93 struct adt7410_data {
94  struct device *hwmon_dev;
98  bool valid; /* true if registers valid */
99  unsigned long last_updated; /* In jiffies */
100  s16 temp[4]; /* Register values,
101  0 = input
102  1 = high
103  2 = low
104  3 = critical */
105  u8 hyst; /* hysteresis offset */
106 };
107 
108 /*
109  * adt7410 register access by I2C
110  */
111 static int adt7410_temp_ready(struct i2c_client *client)
112 {
113  int i, status;
114 
115  for (i = 0; i < 6; i++) {
116  status = i2c_smbus_read_byte_data(client, ADT7410_STATUS);
117  if (status < 0)
118  return status;
119  if (!(status & ADT7410_STAT_NOT_RDY))
120  return 0;
121  msleep(60);
122  }
123  return -ETIMEDOUT;
124 }
125 
126 static struct adt7410_data *adt7410_update_device(struct device *dev)
127 {
128  struct i2c_client *client = to_i2c_client(dev);
129  struct adt7410_data *data = i2c_get_clientdata(client);
130  struct adt7410_data *ret = data;
131  mutex_lock(&data->update_lock);
132 
133  if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
134  || !data->valid) {
135  int i, status;
136 
137  dev_dbg(&client->dev, "Starting update\n");
138 
139  status = adt7410_temp_ready(client); /* check for new value */
140  if (unlikely(status)) {
141  ret = ERR_PTR(status);
142  goto abort;
143  }
144  for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
145  status = i2c_smbus_read_word_swapped(client,
146  ADT7410_REG_TEMP[i]);
147  if (unlikely(status < 0)) {
148  dev_dbg(dev,
149  "Failed to read value: reg %d, error %d\n",
150  ADT7410_REG_TEMP[i], status);
151  ret = ERR_PTR(status);
152  goto abort;
153  }
154  data->temp[i] = status;
155  }
156  status = i2c_smbus_read_byte_data(client, ADT7410_T_HYST);
157  if (unlikely(status < 0)) {
158  dev_dbg(dev,
159  "Failed to read value: reg %d, error %d\n",
160  ADT7410_T_HYST, status);
161  ret = ERR_PTR(status);
162  goto abort;
163  }
164  data->hyst = status;
165  data->last_updated = jiffies;
166  data->valid = true;
167  }
168 
169 abort:
170  mutex_unlock(&data->update_lock);
171  return ret;
172 }
173 
174 static s16 ADT7410_TEMP_TO_REG(long temp)
175 {
176  return DIV_ROUND_CLOSEST(SENSORS_LIMIT(temp, ADT7410_TEMP_MIN,
177  ADT7410_TEMP_MAX) * 128, 1000);
178 }
179 
180 static int ADT7410_REG_TO_TEMP(struct adt7410_data *data, s16 reg)
181 {
182  /* in 13 bit mode, bits 0-2 are status flags - mask them out */
183  if (!(data->config & ADT7410_RESOLUTION))
184  reg &= ADT7410_T13_VALUE_MASK;
185  /*
186  * temperature is stored in twos complement format, in steps of
187  * 1/128°C
188  */
189  return DIV_ROUND_CLOSEST(reg * 1000, 128);
190 }
191 
192 /*-----------------------------------------------------------------------*/
193 
194 /* sysfs attributes for hwmon */
195 
196 static ssize_t adt7410_show_temp(struct device *dev,
197  struct device_attribute *da, char *buf)
198 {
200  struct adt7410_data *data = adt7410_update_device(dev);
201 
202  if (IS_ERR(data))
203  return PTR_ERR(data);
204 
205  return sprintf(buf, "%d\n", ADT7410_REG_TO_TEMP(data,
206  data->temp[attr->index]));
207 }
208 
209 static ssize_t adt7410_set_temp(struct device *dev,
210  struct device_attribute *da,
211  const char *buf, size_t count)
212 {
213  struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
214  struct i2c_client *client = to_i2c_client(dev);
215  struct adt7410_data *data = i2c_get_clientdata(client);
216  int nr = attr->index;
217  long temp;
218  int ret;
219 
220  ret = kstrtol(buf, 10, &temp);
221  if (ret)
222  return ret;
223 
224  mutex_lock(&data->update_lock);
225  data->temp[nr] = ADT7410_TEMP_TO_REG(temp);
226  ret = i2c_smbus_write_word_swapped(client, ADT7410_REG_TEMP[nr],
227  data->temp[nr]);
228  if (ret)
229  count = ret;
230  mutex_unlock(&data->update_lock);
231  return count;
232 }
233 
234 static ssize_t adt7410_show_t_hyst(struct device *dev,
235  struct device_attribute *da,
236  char *buf)
237 {
238  struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
239  struct adt7410_data *data;
240  int nr = attr->index;
241  int hyst;
242 
243  data = adt7410_update_device(dev);
244  if (IS_ERR(data))
245  return PTR_ERR(data);
246  hyst = (data->hyst & ADT7410_T_HYST_MASK) * 1000;
247 
248  /*
249  * hysteresis is stored as a 4 bit offset in the device, convert it
250  * to an absolute value
251  */
252  if (nr == 2) /* min has positive offset, others have negative */
253  hyst = -hyst;
254  return sprintf(buf, "%d\n",
255  ADT7410_REG_TO_TEMP(data, data->temp[nr]) - hyst);
256 }
257 
258 static ssize_t adt7410_set_t_hyst(struct device *dev,
259  struct device_attribute *da,
260  const char *buf, size_t count)
261 {
262  struct i2c_client *client = to_i2c_client(dev);
263  struct adt7410_data *data = i2c_get_clientdata(client);
264  int limit, ret;
265  long hyst;
266 
267  ret = kstrtol(buf, 10, &hyst);
268  if (ret)
269  return ret;
270  /* convert absolute hysteresis value to a 4 bit delta value */
271  limit = ADT7410_REG_TO_TEMP(data, data->temp[1]);
272  hyst = SENSORS_LIMIT(hyst, ADT7410_TEMP_MIN, ADT7410_TEMP_MAX);
273  data->hyst = SENSORS_LIMIT(DIV_ROUND_CLOSEST(limit - hyst, 1000),
275  ret = i2c_smbus_write_byte_data(client, ADT7410_T_HYST, data->hyst);
276  if (ret)
277  return ret;
278 
279  return count;
280 }
281 
282 static ssize_t adt7410_show_alarm(struct device *dev,
283  struct device_attribute *da,
284  char *buf)
285 {
286  struct i2c_client *client = to_i2c_client(dev);
287  struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
288  int ret;
289 
291  if (ret < 0)
292  return ret;
293 
294  return sprintf(buf, "%d\n", !!(ret & attr->index));
295 }
296 
297 static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adt7410_show_temp, NULL, 0);
298 static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
299  adt7410_show_temp, adt7410_set_temp, 1);
300 static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
301  adt7410_show_temp, adt7410_set_temp, 2);
302 static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
303  adt7410_show_temp, adt7410_set_temp, 3);
304 static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
305  adt7410_show_t_hyst, adt7410_set_t_hyst, 1);
306 static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
307  adt7410_show_t_hyst, NULL, 2);
308 static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
309  adt7410_show_t_hyst, NULL, 3);
310 static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, adt7410_show_alarm,
312 static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adt7410_show_alarm,
314 static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, adt7410_show_alarm,
316 
317 static struct attribute *adt7410_attributes[] = {
318  &sensor_dev_attr_temp1_input.dev_attr.attr,
319  &sensor_dev_attr_temp1_max.dev_attr.attr,
320  &sensor_dev_attr_temp1_min.dev_attr.attr,
321  &sensor_dev_attr_temp1_crit.dev_attr.attr,
322  &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
323  &sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
324  &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
325  &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
326  &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
327  &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
328  NULL
329 };
330 
331 static const struct attribute_group adt7410_group = {
332  .attrs = adt7410_attributes,
333 };
334 
335 /*-----------------------------------------------------------------------*/
336 
337 /* device probe and removal */
338 
339 static int adt7410_probe(struct i2c_client *client,
340  const struct i2c_device_id *id)
341 {
342  struct adt7410_data *data;
343  int ret;
344 
345  if (!i2c_check_functionality(client->adapter,
347  return -ENODEV;
348 
349  data = devm_kzalloc(&client->dev, sizeof(struct adt7410_data),
350  GFP_KERNEL);
351  if (!data)
352  return -ENOMEM;
353 
354  i2c_set_clientdata(client, data);
355  mutex_init(&data->update_lock);
356 
357  /* configure as specified */
359  if (ret < 0) {
360  dev_dbg(&client->dev, "Can't read config? %d\n", ret);
361  return ret;
362  }
363  data->oldconfig = ret;
364  /*
365  * Set to 16 bit resolution, continous conversion and comparator mode.
366  */
367  data->config = ret | ADT7410_FULL | ADT7410_RESOLUTION |
369  if (data->config != data->oldconfig) {
371  data->config);
372  if (ret)
373  return ret;
374  }
375  dev_dbg(&client->dev, "Config %02x\n", data->config);
376 
377  /* Register sysfs hooks */
378  ret = sysfs_create_group(&client->dev.kobj, &adt7410_group);
379  if (ret)
380  goto exit_restore;
381 
382  data->hwmon_dev = hwmon_device_register(&client->dev);
383  if (IS_ERR(data->hwmon_dev)) {
384  ret = PTR_ERR(data->hwmon_dev);
385  goto exit_remove;
386  }
387 
388  dev_info(&client->dev, "sensor '%s'\n", client->name);
389 
390  return 0;
391 
392 exit_remove:
393  sysfs_remove_group(&client->dev.kobj, &adt7410_group);
394 exit_restore:
396  return ret;
397 }
398 
399 static int adt7410_remove(struct i2c_client *client)
400 {
401  struct adt7410_data *data = i2c_get_clientdata(client);
402 
404  sysfs_remove_group(&client->dev.kobj, &adt7410_group);
405  if (data->oldconfig != data->config)
407  data->oldconfig);
408  return 0;
409 }
410 
411 static const struct i2c_device_id adt7410_ids[] = {
412  { "adt7410", adt7410, },
413  { /* LIST END */ }
414 };
415 MODULE_DEVICE_TABLE(i2c, adt7410_ids);
416 
417 #ifdef CONFIG_PM
418 static int adt7410_suspend(struct device *dev)
419 {
420  int ret;
421  struct i2c_client *client = to_i2c_client(dev);
422  struct adt7410_data *data = i2c_get_clientdata(client);
423 
425  data->config | ADT7410_PD);
426  return ret;
427 }
428 
429 static int adt7410_resume(struct device *dev)
430 {
431  int ret;
432  struct i2c_client *client = to_i2c_client(dev);
433  struct adt7410_data *data = i2c_get_clientdata(client);
434 
435  ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG, data->config);
436  return ret;
437 }
438 
439 static const struct dev_pm_ops adt7410_dev_pm_ops = {
440  .suspend = adt7410_suspend,
441  .resume = adt7410_resume,
442 };
443 #define ADT7410_DEV_PM_OPS (&adt7410_dev_pm_ops)
444 #else
445 #define ADT7410_DEV_PM_OPS NULL
446 #endif /* CONFIG_PM */
447 
448 static struct i2c_driver adt7410_driver = {
449  .class = I2C_CLASS_HWMON,
450  .driver = {
451  .name = "adt7410",
452  .pm = ADT7410_DEV_PM_OPS,
453  },
454  .probe = adt7410_probe,
455  .remove = adt7410_remove,
456  .id_table = adt7410_ids,
457  .address_list = normal_i2c,
458 };
459 
460 module_i2c_driver(adt7410_driver);
461 
462 MODULE_AUTHOR("Hartmut Knaack");
463 MODULE_DESCRIPTION("ADT7410 driver");
464 MODULE_LICENSE("GPL");