Merge branch 'for-linus' of git://git.kernel.dk/linux-block
[pandora-kernel.git] / drivers / staging / iio / adc / ad7314.c
1 /*
2  * AD7314 digital temperature sensor driver for AD7314, ADT7301 and ADT7302
3  *
4  * Copyright 2010 Analog Devices Inc.
5  *
6  * Licensed under the GPL-2 or later.
7  */
8
9 #include <linux/device.h>
10 #include <linux/kernel.h>
11 #include <linux/slab.h>
12 #include <linux/sysfs.h>
13 #include <linux/spi/spi.h>
14
15 #include "../iio.h"
16 #include "../sysfs.h"
17
18 /*
19  * AD7314 power mode
20  */
21 #define AD7314_PD               0x2000
22
23 /*
24  * AD7314 temperature masks
25  */
26 #define AD7314_TEMP_SIGN                0x200
27 #define AD7314_TEMP_MASK                0x7FE0
28 #define AD7314_TEMP_OFFSET              5
29 #define AD7314_TEMP_FLOAT_OFFSET        2
30 #define AD7314_TEMP_FLOAT_MASK          0x3
31
32 /*
33  * ADT7301 and ADT7302 temperature masks
34  */
35 #define ADT7301_TEMP_SIGN               0x2000
36 #define ADT7301_TEMP_MASK               0x2FFF
37 #define ADT7301_TEMP_FLOAT_OFFSET       5
38 #define ADT7301_TEMP_FLOAT_MASK         0x1F
39
40 /*
41  * struct ad7314_chip_info - chip specifc information
42  */
43
44 struct ad7314_chip_info {
45         struct spi_device *spi_dev;
46         s64 last_timestamp;
47         u8  mode;
48 };
49
50 /*
51  * ad7314 register access by SPI
52  */
53
54 static int ad7314_spi_read(struct ad7314_chip_info *chip, u16 *data)
55 {
56         struct spi_device *spi_dev = chip->spi_dev;
57         int ret = 0;
58         u16 value;
59
60         ret = spi_read(spi_dev, (u8 *)&value, sizeof(value));
61         if (ret < 0) {
62                 dev_err(&spi_dev->dev, "SPI read error\n");
63                 return ret;
64         }
65
66         *data = be16_to_cpu((u16)value);
67
68         return ret;
69 }
70
71 static int ad7314_spi_write(struct ad7314_chip_info *chip, u16 data)
72 {
73         struct spi_device *spi_dev = chip->spi_dev;
74         int ret = 0;
75         u16 value = cpu_to_be16(data);
76
77         ret = spi_write(spi_dev, (u8 *)&value, sizeof(value));
78         if (ret < 0)
79                 dev_err(&spi_dev->dev, "SPI write error\n");
80
81         return ret;
82 }
83
84 static ssize_t ad7314_show_mode(struct device *dev,
85                 struct device_attribute *attr,
86                 char *buf)
87 {
88         struct iio_dev *dev_info = dev_get_drvdata(dev);
89         struct ad7314_chip_info *chip = iio_priv(dev_info);
90
91         if (chip->mode)
92                 return sprintf(buf, "power-save\n");
93         else
94                 return sprintf(buf, "full\n");
95 }
96
97 static ssize_t ad7314_store_mode(struct device *dev,
98                 struct device_attribute *attr,
99                 const char *buf,
100                 size_t len)
101 {
102         struct iio_dev *dev_info = dev_get_drvdata(dev);
103         struct ad7314_chip_info *chip = iio_priv(dev_info);
104         u16 mode = 0;
105         int ret;
106
107         if (!strcmp(buf, "full"))
108                 mode = AD7314_PD;
109
110         ret = ad7314_spi_write(chip, mode);
111         if (ret)
112                 return -EIO;
113
114         chip->mode = mode;
115
116         return len;
117 }
118
119 static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
120                 ad7314_show_mode,
121                 ad7314_store_mode,
122                 0);
123
124 static ssize_t ad7314_show_available_modes(struct device *dev,
125                 struct device_attribute *attr,
126                 char *buf)
127 {
128         return sprintf(buf, "full\npower-save\n");
129 }
130
131 static IIO_DEVICE_ATTR(available_modes, S_IRUGO, ad7314_show_available_modes, NULL, 0);
132
133 static ssize_t ad7314_show_temperature(struct device *dev,
134                 struct device_attribute *attr,
135                 char *buf)
136 {
137         struct iio_dev *dev_info = dev_get_drvdata(dev);
138         struct ad7314_chip_info *chip = iio_priv(dev_info);
139         u16 data;
140         char sign = ' ';
141         int ret;
142
143         if (chip->mode) {
144                 ret = ad7314_spi_write(chip, 0);
145                 if (ret)
146                         return -EIO;
147         }
148
149         ret = ad7314_spi_read(chip, &data);
150         if (ret)
151                 return -EIO;
152
153         if (chip->mode)
154                 ad7314_spi_write(chip, chip->mode);
155
156         if (strcmp(dev_info->name, "ad7314")) {
157                 data = (data & AD7314_TEMP_MASK) >>
158                         AD7314_TEMP_OFFSET;
159                 if (data & AD7314_TEMP_SIGN) {
160                         data = (AD7314_TEMP_SIGN << 1) - data;
161                         sign = '-';
162                 }
163
164                 return sprintf(buf, "%c%d.%.2d\n", sign,
165                                 data >> AD7314_TEMP_FLOAT_OFFSET,
166                                 (data & AD7314_TEMP_FLOAT_MASK) * 25);
167         } else {
168                 data &= ADT7301_TEMP_MASK;
169                 if (data & ADT7301_TEMP_SIGN) {
170                         data = (ADT7301_TEMP_SIGN << 1) - data;
171                         sign = '-';
172                 }
173
174                 return sprintf(buf, "%c%d.%.5d\n", sign,
175                                 data >> ADT7301_TEMP_FLOAT_OFFSET,
176                                 (data & ADT7301_TEMP_FLOAT_MASK) * 3125);
177         }
178 }
179
180 static IIO_DEVICE_ATTR(temperature, S_IRUGO, ad7314_show_temperature, NULL, 0);
181
182 static struct attribute *ad7314_attributes[] = {
183         &iio_dev_attr_available_modes.dev_attr.attr,
184         &iio_dev_attr_mode.dev_attr.attr,
185         &iio_dev_attr_temperature.dev_attr.attr,
186         NULL,
187 };
188
189 static const struct attribute_group ad7314_attribute_group = {
190         .attrs = ad7314_attributes,
191 };
192
193 static const struct iio_info ad7314_info = {
194         .attrs = &ad7314_attribute_group,
195         .driver_module = THIS_MODULE,
196 };
197 /*
198  * device probe and remove
199  */
200
201 static int __devinit ad7314_probe(struct spi_device *spi_dev)
202 {
203         struct ad7314_chip_info *chip;
204         struct iio_dev *indio_dev;
205         int ret = 0;
206
207         indio_dev = iio_allocate_device(sizeof(*chip));
208         if (indio_dev == NULL) {
209                 ret = -ENOMEM;
210                 goto error_ret;
211         }
212         chip = iio_priv(indio_dev);
213         /* this is only used for device removal purposes */
214         dev_set_drvdata(&spi_dev->dev, chip);
215
216         chip->spi_dev = spi_dev;
217
218         indio_dev->name = spi_get_device_id(spi_dev)->name;
219         indio_dev->dev.parent = &spi_dev->dev;
220         indio_dev->info = &ad7314_info;
221
222         ret = iio_device_register(indio_dev);
223         if (ret)
224                 goto error_free_dev;
225
226         dev_info(&spi_dev->dev, "%s temperature sensor registered.\n",
227                          indio_dev->name);
228
229         return 0;
230 error_free_dev:
231         iio_free_device(indio_dev);
232 error_ret:
233         return ret;
234 }
235
236 static int __devexit ad7314_remove(struct spi_device *spi_dev)
237 {
238         struct iio_dev *indio_dev = dev_get_drvdata(&spi_dev->dev);
239
240         dev_set_drvdata(&spi_dev->dev, NULL);
241         iio_device_unregister(indio_dev);
242         iio_free_device(indio_dev);
243
244         return 0;
245 }
246
247 static const struct spi_device_id ad7314_id[] = {
248         { "adt7301", 0 },
249         { "adt7302", 0 },
250         { "ad7314", 0 },
251         {}
252 };
253
254 static struct spi_driver ad7314_driver = {
255         .driver = {
256                 .name = "ad7314",
257                 .bus = &spi_bus_type,
258                 .owner = THIS_MODULE,
259         },
260         .probe = ad7314_probe,
261         .remove = __devexit_p(ad7314_remove),
262         .id_table = ad7314_id,
263 };
264
265 static __init int ad7314_init(void)
266 {
267         return spi_register_driver(&ad7314_driver);
268 }
269
270 static __exit void ad7314_exit(void)
271 {
272         spi_unregister_driver(&ad7314_driver);
273 }
274
275 MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
276 MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital"
277                         " temperature sensor driver");
278 MODULE_LICENSE("GPL v2");
279
280 module_init(ad7314_init);
281 module_exit(ad7314_exit);