blob: 8470036a3378cba40d787f1e45fcb0410bd5d676 [file] [log] [blame]
Sonic Zhang79244252010-10-27 21:43:59 -04001/*
2 * AD7816 digital temperature sensor driver supporting AD7816/7/8
3 *
4 * Copyright 2010 Analog Devices Inc.
5 *
6 * Licensed under the GPL-2 or later.
7 */
8
9#include <linux/interrupt.h>
10#include <linux/gpio.h>
Sonic Zhang79244252010-10-27 21:43:59 -040011#include <linux/device.h>
12#include <linux/kernel.h>
13#include <linux/slab.h>
14#include <linux/sysfs.h>
15#include <linux/list.h>
16#include <linux/spi/spi.h>
Paul Gortmaker99c97852011-07-03 15:49:50 -040017#include <linux/module.h>
Sonic Zhang79244252010-10-27 21:43:59 -040018
Jonathan Cameron06458e22012-04-25 15:54:58 +010019#include <linux/iio/iio.h>
20#include <linux/iio/sysfs.h>
21#include <linux/iio/events.h>
Sonic Zhang79244252010-10-27 21:43:59 -040022
23/*
24 * AD7816 config masks
25 */
26#define AD7816_FULL 0x1
27#define AD7816_PD 0x2
28#define AD7816_CS_MASK 0x7
29#define AD7816_CS_MAX 0x4
30
31/*
32 * AD7816 temperature masks
33 */
34#define AD7816_VALUE_OFFSET 6
35#define AD7816_BOUND_VALUE_BASE 0x8
36#define AD7816_BOUND_VALUE_MIN -95
37#define AD7816_BOUND_VALUE_MAX 152
38#define AD7816_TEMP_FLOAT_OFFSET 2
39#define AD7816_TEMP_FLOAT_MASK 0x3
40
41
42/*
43 * struct ad7816_chip_info - chip specifc information
44 */
45
46struct ad7816_chip_info {
Sonic Zhang79244252010-10-27 21:43:59 -040047 struct spi_device *spi_dev;
Sonic Zhang79244252010-10-27 21:43:59 -040048 u16 rdwr_pin;
49 u16 convert_pin;
50 u16 busy_pin;
51 u8 oti_data[AD7816_CS_MAX+1];
52 u8 channel_id; /* 0 always be temperature */
53 u8 mode;
54};
55
56/*
57 * ad7816 data access by SPI
58 */
59static int ad7816_spi_read(struct ad7816_chip_info *chip, u16 *data)
60{
61 struct spi_device *spi_dev = chip->spi_dev;
62 int ret = 0;
63
64 gpio_set_value(chip->rdwr_pin, 1);
65 gpio_set_value(chip->rdwr_pin, 0);
66 ret = spi_write(spi_dev, &chip->channel_id, sizeof(chip->channel_id));
67 if (ret < 0) {
68 dev_err(&spi_dev->dev, "SPI channel setting error\n");
69 return ret;
70 }
71 gpio_set_value(chip->rdwr_pin, 1);
72
73
74 if (chip->mode == AD7816_PD) { /* operating mode 2 */
75 gpio_set_value(chip->convert_pin, 1);
76 gpio_set_value(chip->convert_pin, 0);
77 } else { /* operating mode 1 */
78 gpio_set_value(chip->convert_pin, 0);
79 gpio_set_value(chip->convert_pin, 1);
80 }
81
82 while (gpio_get_value(chip->busy_pin))
83 cpu_relax();
84
85 gpio_set_value(chip->rdwr_pin, 0);
86 gpio_set_value(chip->rdwr_pin, 1);
87 ret = spi_read(spi_dev, (u8 *)data, sizeof(*data));
88 if (ret < 0) {
89 dev_err(&spi_dev->dev, "SPI data read error\n");
90 return ret;
91 }
92
93 *data = be16_to_cpu(*data);
94
95 return ret;
96}
97
98static int ad7816_spi_write(struct ad7816_chip_info *chip, u8 data)
99{
100 struct spi_device *spi_dev = chip->spi_dev;
101 int ret = 0;
102
103 gpio_set_value(chip->rdwr_pin, 1);
104 gpio_set_value(chip->rdwr_pin, 0);
105 ret = spi_write(spi_dev, &data, sizeof(data));
106 if (ret < 0)
107 dev_err(&spi_dev->dev, "SPI oti data write error\n");
108
109 return ret;
110}
111
112static ssize_t ad7816_show_mode(struct device *dev,
113 struct device_attribute *attr,
114 char *buf)
115{
Lars-Peter Clausen62c51832012-05-12 15:39:42 +0200116 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
Jonathan Cameron84f79ec2011-10-06 17:14:37 +0100117 struct ad7816_chip_info *chip = iio_priv(indio_dev);
Sonic Zhang79244252010-10-27 21:43:59 -0400118
119 if (chip->mode)
120 return sprintf(buf, "power-save\n");
121 else
122 return sprintf(buf, "full\n");
123}
124
125static ssize_t ad7816_store_mode(struct device *dev,
126 struct device_attribute *attr,
127 const char *buf,
128 size_t len)
129{
Lars-Peter Clausen62c51832012-05-12 15:39:42 +0200130 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
Jonathan Cameron84f79ec2011-10-06 17:14:37 +0100131 struct ad7816_chip_info *chip = iio_priv(indio_dev);
Sonic Zhang79244252010-10-27 21:43:59 -0400132
133 if (strcmp(buf, "full")) {
134 gpio_set_value(chip->rdwr_pin, 1);
135 chip->mode = AD7816_FULL;
136 } else {
137 gpio_set_value(chip->rdwr_pin, 0);
138 chip->mode = AD7816_PD;
139 }
140
141 return len;
142}
143
144static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
145 ad7816_show_mode,
146 ad7816_store_mode,
147 0);
148
149static ssize_t ad7816_show_available_modes(struct device *dev,
150 struct device_attribute *attr,
151 char *buf)
152{
153 return sprintf(buf, "full\npower-save\n");
154}
155
156static IIO_DEVICE_ATTR(available_modes, S_IRUGO, ad7816_show_available_modes, NULL, 0);
157
158static ssize_t ad7816_show_channel(struct device *dev,
159 struct device_attribute *attr,
160 char *buf)
161{
Lars-Peter Clausen62c51832012-05-12 15:39:42 +0200162 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
Jonathan Cameron84f79ec2011-10-06 17:14:37 +0100163 struct ad7816_chip_info *chip = iio_priv(indio_dev);
Sonic Zhang79244252010-10-27 21:43:59 -0400164
165 return sprintf(buf, "%d\n", chip->channel_id);
166}
167
168static ssize_t ad7816_store_channel(struct device *dev,
169 struct device_attribute *attr,
170 const char *buf,
171 size_t len)
172{
Lars-Peter Clausen62c51832012-05-12 15:39:42 +0200173 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
Jonathan Cameron84f79ec2011-10-06 17:14:37 +0100174 struct ad7816_chip_info *chip = iio_priv(indio_dev);
Sonic Zhang79244252010-10-27 21:43:59 -0400175 unsigned long data;
176 int ret;
177
Aida Mynzhasovaf86f8362013-05-07 00:04:41 +0400178 ret = kstrtoul(buf, 10, &data);
Sonic Zhang79244252010-10-27 21:43:59 -0400179 if (ret)
Aida Mynzhasovaf86f8362013-05-07 00:04:41 +0400180 return ret;
Sonic Zhang79244252010-10-27 21:43:59 -0400181
182 if (data > AD7816_CS_MAX && data != AD7816_CS_MASK) {
183 dev_err(&chip->spi_dev->dev, "Invalid channel id %lu for %s.\n",
Jonathan Cameron84f79ec2011-10-06 17:14:37 +0100184 data, indio_dev->name);
Sonic Zhang79244252010-10-27 21:43:59 -0400185 return -EINVAL;
Jonathan Cameron84f79ec2011-10-06 17:14:37 +0100186 } else if (strcmp(indio_dev->name, "ad7818") == 0 && data > 1) {
Sonic Zhang79244252010-10-27 21:43:59 -0400187 dev_err(&chip->spi_dev->dev,
188 "Invalid channel id %lu for ad7818.\n", data);
189 return -EINVAL;
Jonathan Cameron84f79ec2011-10-06 17:14:37 +0100190 } else if (strcmp(indio_dev->name, "ad7816") == 0 && data > 0) {
Sonic Zhang79244252010-10-27 21:43:59 -0400191 dev_err(&chip->spi_dev->dev,
192 "Invalid channel id %lu for ad7816.\n", data);
193 return -EINVAL;
194 }
195
196 chip->channel_id = data;
197
198 return len;
199}
200
201static IIO_DEVICE_ATTR(channel, S_IRUGO | S_IWUSR,
202 ad7816_show_channel,
203 ad7816_store_channel,
204 0);
205
206
207static ssize_t ad7816_show_value(struct device *dev,
208 struct device_attribute *attr,
209 char *buf)
210{
Lars-Peter Clausen62c51832012-05-12 15:39:42 +0200211 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
Jonathan Cameron84f79ec2011-10-06 17:14:37 +0100212 struct ad7816_chip_info *chip = iio_priv(indio_dev);
Sonic Zhang79244252010-10-27 21:43:59 -0400213 u16 data;
214 s8 value;
215 int ret;
216
217 ret = ad7816_spi_read(chip, &data);
218 if (ret)
219 return -EIO;
220
221 data >>= AD7816_VALUE_OFFSET;
222
223 if (chip->channel_id == 0) {
224 value = (s8)((data >> AD7816_TEMP_FLOAT_OFFSET) - 103);
225 data &= AD7816_TEMP_FLOAT_MASK;
226 if (value < 0)
227 data = (1 << AD7816_TEMP_FLOAT_OFFSET) - data;
228 return sprintf(buf, "%d.%.2d\n", value, data * 25);
229 } else
230 return sprintf(buf, "%u\n", data);
231}
232
233static IIO_DEVICE_ATTR(value, S_IRUGO, ad7816_show_value, NULL, 0);
234
Sonic Zhang79244252010-10-27 21:43:59 -0400235static struct attribute *ad7816_attributes[] = {
236 &iio_dev_attr_available_modes.dev_attr.attr,
237 &iio_dev_attr_mode.dev_attr.attr,
238 &iio_dev_attr_channel.dev_attr.attr,
239 &iio_dev_attr_value.dev_attr.attr,
Sonic Zhang79244252010-10-27 21:43:59 -0400240 NULL,
241};
242
243static const struct attribute_group ad7816_attribute_group = {
244 .attrs = ad7816_attributes,
245};
246
247/*
248 * temperature bound events
249 */
250
Jonathan Cameronc4b14d92011-08-12 17:56:04 +0100251#define IIO_EVENT_CODE_AD7816_OTI IIO_UNMOD_EVENT_CODE(IIO_TEMP, \
Jonathan Cameron0bb8be62011-05-18 14:42:14 +0100252 0, \
253 IIO_EV_TYPE_THRESH, \
254 IIO_EV_DIR_FALLING)
Sonic Zhang79244252010-10-27 21:43:59 -0400255
Jonathan Camerondb9afe22011-05-18 14:41:07 +0100256static irqreturn_t ad7816_event_handler(int irq, void *private)
Sonic Zhang79244252010-10-27 21:43:59 -0400257{
Jonathan Cameron5aa96182011-08-30 12:41:06 +0100258 iio_push_event(private, IIO_EVENT_CODE_AD7816_OTI, iio_get_time_ns());
Jonathan Camerondb9afe22011-05-18 14:41:07 +0100259 return IRQ_HANDLED;
Sonic Zhang79244252010-10-27 21:43:59 -0400260}
261
Sonic Zhang79244252010-10-27 21:43:59 -0400262static ssize_t ad7816_show_oti(struct device *dev,
263 struct device_attribute *attr,
264 char *buf)
265{
Lars-Peter Clausen62c51832012-05-12 15:39:42 +0200266 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
Jonathan Cameron84f79ec2011-10-06 17:14:37 +0100267 struct ad7816_chip_info *chip = iio_priv(indio_dev);
Sonic Zhang79244252010-10-27 21:43:59 -0400268 int value;
269
270 if (chip->channel_id > AD7816_CS_MAX) {
271 dev_err(dev, "Invalid oti channel id %d.\n", chip->channel_id);
272 return -EINVAL;
273 } else if (chip->channel_id == 0) {
274 value = AD7816_BOUND_VALUE_MIN +
275 (chip->oti_data[chip->channel_id] -
276 AD7816_BOUND_VALUE_BASE);
277 return sprintf(buf, "%d\n", value);
278 } else
279 return sprintf(buf, "%u\n", chip->oti_data[chip->channel_id]);
280}
281
282static inline ssize_t ad7816_set_oti(struct device *dev,
283 struct device_attribute *attr,
284 const char *buf,
285 size_t len)
286{
Lars-Peter Clausen62c51832012-05-12 15:39:42 +0200287 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
Jonathan Cameron84f79ec2011-10-06 17:14:37 +0100288 struct ad7816_chip_info *chip = iio_priv(indio_dev);
Sonic Zhang79244252010-10-27 21:43:59 -0400289 long value;
290 u8 data;
291 int ret;
292
Aida Mynzhasovaf86f8362013-05-07 00:04:41 +0400293 ret = kstrtol(buf, 10, &value);
294 if (ret)
295 return ret;
Sonic Zhang79244252010-10-27 21:43:59 -0400296
297 if (chip->channel_id > AD7816_CS_MAX) {
298 dev_err(dev, "Invalid oti channel id %d.\n", chip->channel_id);
299 return -EINVAL;
300 } else if (chip->channel_id == 0) {
301 if (ret || value < AD7816_BOUND_VALUE_MIN ||
302 value > AD7816_BOUND_VALUE_MAX)
303 return -EINVAL;
304
305 data = (u8)(value - AD7816_BOUND_VALUE_MIN +
306 AD7816_BOUND_VALUE_BASE);
307 } else {
308 if (ret || value < AD7816_BOUND_VALUE_BASE || value > 255)
309 return -EINVAL;
310
311 data = (u8)value;
312 }
313
314 ret = ad7816_spi_write(chip, data);
315 if (ret)
316 return -EIO;
317
318 chip->oti_data[chip->channel_id] = data;
319
320 return len;
321}
322
Jonathan Camerondb9afe22011-05-18 14:41:07 +0100323static IIO_DEVICE_ATTR(oti, S_IRUGO | S_IWUSR,
324 ad7816_show_oti, ad7816_set_oti, 0);
Sonic Zhang79244252010-10-27 21:43:59 -0400325
326static struct attribute *ad7816_event_attributes[] = {
Jonathan Camerondb9afe22011-05-18 14:41:07 +0100327 &iio_dev_attr_oti.dev_attr.attr,
Sonic Zhang79244252010-10-27 21:43:59 -0400328 NULL,
329};
330
331static struct attribute_group ad7816_event_attribute_group = {
332 .attrs = ad7816_event_attributes,
Jonathan Cameron8e7d9672011-08-30 12:32:45 +0100333 .name = "events",
Sonic Zhang79244252010-10-27 21:43:59 -0400334};
335
Jonathan Cameron6fe81352011-05-18 14:42:37 +0100336static const struct iio_info ad7816_info = {
337 .attrs = &ad7816_attribute_group,
Jonathan Cameron6fe81352011-05-18 14:42:37 +0100338 .event_attrs = &ad7816_event_attribute_group,
339 .driver_module = THIS_MODULE,
340};
341
Sonic Zhang79244252010-10-27 21:43:59 -0400342/*
343 * device probe and remove
344 */
345
Bill Pemberton4ae1c612012-11-19 13:21:57 -0500346static int ad7816_probe(struct spi_device *spi_dev)
Sonic Zhang79244252010-10-27 21:43:59 -0400347{
348 struct ad7816_chip_info *chip;
Jonathan Cameronb0011d62011-06-27 13:07:26 +0100349 struct iio_dev *indio_dev;
Sonic Zhang79244252010-10-27 21:43:59 -0400350 unsigned short *pins = spi_dev->dev.platform_data;
351 int ret = 0;
352 int i;
353
354 if (!pins) {
355 dev_err(&spi_dev->dev, "No necessary GPIO platform data.\n");
356 return -EINVAL;
357 }
358
Lars-Peter Clausen7cbb7532012-04-26 13:35:01 +0200359 indio_dev = iio_device_alloc(sizeof(*chip));
Jonathan Cameronb0011d62011-06-27 13:07:26 +0100360 if (indio_dev == NULL) {
361 ret = -ENOMEM;
362 goto error_ret;
363 }
364 chip = iio_priv(indio_dev);
Sonic Zhang79244252010-10-27 21:43:59 -0400365 /* this is only used for device removal purposes */
Jonathan Cameronb0011d62011-06-27 13:07:26 +0100366 dev_set_drvdata(&spi_dev->dev, indio_dev);
Sonic Zhang79244252010-10-27 21:43:59 -0400367
368 chip->spi_dev = spi_dev;
Sonic Zhang79244252010-10-27 21:43:59 -0400369 for (i = 0; i <= AD7816_CS_MAX; i++)
370 chip->oti_data[i] = 203;
371 chip->rdwr_pin = pins[0];
372 chip->convert_pin = pins[1];
373 chip->busy_pin = pins[2];
374
Jonathan Cameron845bd122011-05-18 14:41:44 +0100375 ret = gpio_request(chip->rdwr_pin, spi_get_device_id(spi_dev)->name);
Sonic Zhang79244252010-10-27 21:43:59 -0400376 if (ret) {
377 dev_err(&spi_dev->dev, "Fail to request rdwr gpio PIN %d.\n",
378 chip->rdwr_pin);
Jonathan Cameronb0011d62011-06-27 13:07:26 +0100379 goto error_free_device;
Sonic Zhang79244252010-10-27 21:43:59 -0400380 }
381 gpio_direction_input(chip->rdwr_pin);
Jonathan Cameron845bd122011-05-18 14:41:44 +0100382 ret = gpio_request(chip->convert_pin, spi_get_device_id(spi_dev)->name);
Sonic Zhang79244252010-10-27 21:43:59 -0400383 if (ret) {
384 dev_err(&spi_dev->dev, "Fail to request convert gpio PIN %d.\n",
385 chip->convert_pin);
386 goto error_free_gpio_rdwr;
387 }
388 gpio_direction_input(chip->convert_pin);
Jonathan Cameron845bd122011-05-18 14:41:44 +0100389 ret = gpio_request(chip->busy_pin, spi_get_device_id(spi_dev)->name);
Sonic Zhang79244252010-10-27 21:43:59 -0400390 if (ret) {
391 dev_err(&spi_dev->dev, "Fail to request busy gpio PIN %d.\n",
392 chip->busy_pin);
393 goto error_free_gpio_convert;
394 }
395 gpio_direction_input(chip->busy_pin);
396
Jonathan Cameronb0011d62011-06-27 13:07:26 +0100397 indio_dev->name = spi_get_device_id(spi_dev)->name;
398 indio_dev->dev.parent = &spi_dev->dev;
399 indio_dev->info = &ad7816_info;
400 indio_dev->modes = INDIO_DIRECT_MODE;
Sonic Zhang79244252010-10-27 21:43:59 -0400401
Sonic Zhang79244252010-10-27 21:43:59 -0400402 if (spi_dev->irq) {
403 /* Only low trigger is supported in ad7816/7/8 */
Jonathan Camerondb9afe22011-05-18 14:41:07 +0100404 ret = request_threaded_irq(spi_dev->irq,
405 NULL,
406 &ad7816_event_handler,
Lars-Peter Clausena91aff12012-07-02 10:54:45 +0200407 IRQF_TRIGGER_LOW | IRQF_ONESHOT,
Jonathan Cameronb0011d62011-06-27 13:07:26 +0100408 indio_dev->name,
409 indio_dev);
Sonic Zhang79244252010-10-27 21:43:59 -0400410 if (ret)
Jonathan Cameron26d25ae2011-09-02 17:14:40 +0100411 goto error_free_gpio;
Sonic Zhang79244252010-10-27 21:43:59 -0400412 }
413
Jonathan Cameron26d25ae2011-09-02 17:14:40 +0100414 ret = iio_device_register(indio_dev);
415 if (ret)
416 goto error_free_irq;
417
Sonic Zhang79244252010-10-27 21:43:59 -0400418 dev_info(&spi_dev->dev, "%s temperature sensor and ADC registered.\n",
Jonathan Cameronb0011d62011-06-27 13:07:26 +0100419 indio_dev->name);
Sonic Zhang79244252010-10-27 21:43:59 -0400420
421 return 0;
Jonathan Cameron26d25ae2011-09-02 17:14:40 +0100422error_free_irq:
423 free_irq(spi_dev->irq, indio_dev);
Sonic Zhang79244252010-10-27 21:43:59 -0400424error_free_gpio:
425 gpio_free(chip->busy_pin);
426error_free_gpio_convert:
427 gpio_free(chip->convert_pin);
428error_free_gpio_rdwr:
429 gpio_free(chip->rdwr_pin);
Jonathan Cameronb0011d62011-06-27 13:07:26 +0100430error_free_device:
Lars-Peter Clausen7cbb7532012-04-26 13:35:01 +0200431 iio_device_free(indio_dev);
Jonathan Cameronb0011d62011-06-27 13:07:26 +0100432error_ret:
Sonic Zhang79244252010-10-27 21:43:59 -0400433 return ret;
434}
435
Bill Pemberton447d4f22012-11-19 13:26:37 -0500436static int ad7816_remove(struct spi_device *spi_dev)
Sonic Zhang79244252010-10-27 21:43:59 -0400437{
Jonathan Cameronb0011d62011-06-27 13:07:26 +0100438 struct iio_dev *indio_dev = dev_get_drvdata(&spi_dev->dev);
439 struct ad7816_chip_info *chip = iio_priv(indio_dev);
Sonic Zhang79244252010-10-27 21:43:59 -0400440
Jonathan Camerond2fffd62011-10-14 14:46:58 +0100441 iio_device_unregister(indio_dev);
Sonic Zhang79244252010-10-27 21:43:59 -0400442 dev_set_drvdata(&spi_dev->dev, NULL);
443 if (spi_dev->irq)
Jonathan Camerondb9afe22011-05-18 14:41:07 +0100444 free_irq(spi_dev->irq, indio_dev);
Sonic Zhang79244252010-10-27 21:43:59 -0400445 gpio_free(chip->busy_pin);
446 gpio_free(chip->convert_pin);
447 gpio_free(chip->rdwr_pin);
Lars-Peter Clausen7cbb7532012-04-26 13:35:01 +0200448 iio_device_free(indio_dev);
Sonic Zhang79244252010-10-27 21:43:59 -0400449
450 return 0;
451}
452
453static const struct spi_device_id ad7816_id[] = {
454 { "ad7816", 0 },
455 { "ad7817", 0 },
456 { "ad7818", 0 },
457 {}
458};
459
460MODULE_DEVICE_TABLE(spi, ad7816_id);
461
462static struct spi_driver ad7816_driver = {
463 .driver = {
464 .name = "ad7816",
Sonic Zhang79244252010-10-27 21:43:59 -0400465 .owner = THIS_MODULE,
466 },
467 .probe = ad7816_probe,
Bill Pembertone543acf2012-11-19 13:21:38 -0500468 .remove = ad7816_remove,
Sonic Zhang79244252010-10-27 21:43:59 -0400469 .id_table = ad7816_id,
470};
Lars-Peter Clausenae6ae6f2011-11-16 10:13:39 +0100471module_spi_driver(ad7816_driver);
Sonic Zhang79244252010-10-27 21:43:59 -0400472
473MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
474MODULE_DESCRIPTION("Analog Devices AD7816/7/8 digital"
475 " temperature sensor driver");
476MODULE_LICENSE("GPL v2");