a41c2de0eae84cf9bb179a4f16f2d78b6dbe4197
[linux-2.6.git] / drivers / misc / ad525x_dpot.c
1 /*
2  * ad525x_dpot: Driver for the Analog Devices digital potentiometers
3  * Copyright (c) 2009-2010 Analog Devices, Inc.
4  * Author: Michael Hennerich <hennerich@blackfin.uclinux.org>
5  *
6  * DEVID                #Wipers         #Positions      Resistor Options (kOhm)
7  * AD5258               1               64              1, 10, 50, 100
8  * AD5259               1               256             5, 10, 50, 100
9  * AD5251               2               64              1, 10, 50, 100
10  * AD5252               2               256             1, 10, 50, 100
11  * AD5255               3               512             25, 250
12  * AD5253               4               64              1, 10, 50, 100
13  * AD5254               4               256             1, 10, 50, 100
14  * AD5160               1               256             5, 10, 50, 100
15  * AD5161               1               256             5, 10, 50, 100
16  * AD5162               2               256             2.5, 10, 50, 100
17  * AD5165               1               256             100
18  * AD5200               1               256             10, 50
19  * AD5201               1               33              10, 50
20  * AD5203               4               64              10, 100
21  * AD5204               4               256             10, 50, 100
22  * AD5206               6               256             10, 50, 100
23  * AD5207               2               256             10, 50, 100
24  * AD5231               1               1024            10, 50, 100
25  * AD5232               2               256             10, 50, 100
26  * AD5233               4               64              10, 50, 100
27  * AD5235               2               1024            25, 250
28  * AD5260               1               256             20, 50, 200
29  * AD5262               2               256             20, 50, 200
30  * AD5263               4               256             20, 50, 200
31  * AD5290               1               256             10, 50, 100
32  * AD5291               1               256             20
33  * AD5292               1               1024            20
34  * AD5293               1               1024            20
35  * AD7376               1               128             10, 50, 100, 1M
36  * AD8400               1               256             1, 10, 50, 100
37  * AD8402               2               256             1, 10, 50, 100
38  * AD8403               4               256             1, 10, 50, 100
39  * ADN2850              3               512             25, 250
40  *
41  * See Documentation/misc-devices/ad525x_dpot.txt for more info.
42  *
43  * derived from ad5258.c
44  * Copyright (c) 2009 Cyber Switching, Inc.
45  * Author: Chris Verges <chrisv@cyberswitching.com>
46  *
47  * derived from ad5252.c
48  * Copyright (c) 2006 Michael Hennerich <hennerich@blackfin.uclinux.org>
49  *
50  * Licensed under the GPL-2 or later.
51  */
52
53 #include <linux/module.h>
54 #include <linux/device.h>
55 #include <linux/kernel.h>
56 #include <linux/init.h>
57 #include <linux/delay.h>
58 #include <linux/slab.h>
59
60 #define DRIVER_VERSION                  "0.2"
61
62 #include "ad525x_dpot.h"
63
64 /*
65  * Client data (each client gets its own)
66  */
67
68 struct dpot_data {
69         struct ad_dpot_bus_data bdata;
70         struct mutex update_lock;
71         unsigned rdac_mask;
72         unsigned max_pos;
73         unsigned long devid;
74         unsigned uid;
75         unsigned feat;
76         unsigned wipers;
77         u16 rdac_cache[8];
78 };
79
80 static inline int dpot_read_d8(struct dpot_data *dpot)
81 {
82         return dpot->bdata.bops->read_d8(dpot->bdata.client);
83 }
84
85 static inline int dpot_read_r8d8(struct dpot_data *dpot, u8 reg)
86 {
87         return dpot->bdata.bops->read_r8d8(dpot->bdata.client, reg);
88 }
89
90 static inline int dpot_read_r8d16(struct dpot_data *dpot, u8 reg)
91 {
92         return dpot->bdata.bops->read_r8d16(dpot->bdata.client, reg);
93 }
94
95 static inline int dpot_write_d8(struct dpot_data *dpot, u8 val)
96 {
97         return dpot->bdata.bops->write_d8(dpot->bdata.client, val);
98 }
99
100 static inline int dpot_write_r8d8(struct dpot_data *dpot, u8 reg, u16 val)
101 {
102         return dpot->bdata.bops->write_r8d8(dpot->bdata.client, reg, val);
103 }
104
105 static inline int dpot_write_r8d16(struct dpot_data *dpot, u8 reg, u16 val)
106 {
107         return dpot->bdata.bops->write_r8d16(dpot->bdata.client, reg, val);
108 }
109
110 static s32 dpot_read(struct dpot_data *dpot, u8 reg)
111 {
112         unsigned val = 0;
113
114         if (dpot->feat & F_SPI) {
115                 if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD))) {
116
117                         if (dpot->feat & F_RDACS_WONLY)
118                                 return dpot->rdac_cache[reg & DPOT_RDAC_MASK];
119
120                         if (dpot->uid == DPOT_UID(AD5291_ID) ||
121                                 dpot->uid == DPOT_UID(AD5292_ID) ||
122                                 dpot->uid == DPOT_UID(AD5293_ID))
123                                 return dpot_read_r8d8(dpot,
124                                         DPOT_AD5291_READ_RDAC << 2);
125
126                         val = DPOT_SPI_READ_RDAC;
127                 } else if (reg & DPOT_ADDR_EEPROM) {
128                         val = DPOT_SPI_READ_EEPROM;
129                 }
130
131                 if (dpot->feat & F_SPI_16BIT)
132                         return dpot_read_r8d8(dpot, val);
133                 else if (dpot->feat & F_SPI_24BIT)
134                         return dpot_read_r8d16(dpot, val);
135
136         } else { /* I2C */
137
138                 if ((reg & DPOT_REG_TOL) || (dpot->max_pos > 256))
139                         return dpot_read_r8d16(dpot, (reg & 0xF8) |
140                                         ((reg & 0x7) << 1));
141                 else
142                         return dpot_read_r8d8(dpot, reg);
143
144         }
145         return -EFAULT;
146 }
147
148 static s32 dpot_write(struct dpot_data *dpot, u8 reg, u16 value)
149 {
150         unsigned val = 0;
151
152         if (dpot->feat & F_SPI) {
153                 if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD))) {
154                         if (dpot->feat & F_RDACS_WONLY)
155                                 dpot->rdac_cache[reg & DPOT_RDAC_MASK] = value;
156
157                         if (dpot->feat & F_AD_APPDATA) {
158                                 if (dpot->feat & F_SPI_8BIT) {
159                                         val = ((reg & DPOT_RDAC_MASK) <<
160                                                 DPOT_MAX_POS(dpot->devid)) |
161                                                 value;
162                                         return dpot_write_d8(dpot, val);
163                                 } else if (dpot->feat & F_SPI_16BIT) {
164                                         val = ((reg & DPOT_RDAC_MASK) <<
165                                                 DPOT_MAX_POS(dpot->devid)) |
166                                                 value;
167                                         return dpot_write_r8d8(dpot, val >> 8,
168                                                 val & 0xFF);
169                                 } else
170                                         BUG();
171                         } else {
172                                 if (dpot->uid == DPOT_UID(AD5291_ID) ||
173                                         dpot->uid == DPOT_UID(AD5292_ID) ||
174                                         dpot->uid == DPOT_UID(AD5293_ID))
175                                         return dpot_write_r8d8(dpot,
176                                                 (DPOT_AD5291_RDAC << 2) |
177                                                 (value >> 8), value & 0xFF);
178
179                                 val = DPOT_SPI_RDAC | (reg & DPOT_RDAC_MASK);
180                         }
181                 } else if (reg & DPOT_ADDR_EEPROM) {
182                         val = DPOT_SPI_EEPROM | (reg & DPOT_RDAC_MASK);
183                 } else if (reg & DPOT_ADDR_CMD) {
184                         switch (reg) {
185                         case DPOT_DEC_ALL_6DB:
186                                 val = DPOT_SPI_DEC_ALL_6DB;
187                                 break;
188                         case DPOT_INC_ALL_6DB:
189                                 val = DPOT_SPI_INC_ALL_6DB;
190                                 break;
191                         case DPOT_DEC_ALL:
192                                 val = DPOT_SPI_DEC_ALL;
193                                 break;
194                         case DPOT_INC_ALL:
195                                 val = DPOT_SPI_INC_ALL;
196                                 break;
197                         }
198                 } else
199                         BUG();
200
201                 if (dpot->feat & F_SPI_16BIT)
202                         return dpot_write_r8d8(dpot, val, value);
203                 else if (dpot->feat & F_SPI_24BIT)
204                         return dpot_write_r8d16(dpot, val, value);
205         } else {
206                 /* Only write the instruction byte for certain commands */
207                 if (reg & DPOT_ADDR_CMD)
208                         return dpot_write_d8(dpot, reg);
209
210                 if (dpot->max_pos > 256)
211                         return dpot_write_r8d16(dpot, (reg & 0xF8) |
212                                                 ((reg & 0x7) << 1), value);
213                 else
214                         /* All other registers require instruction + data bytes */
215                         return dpot_write_r8d8(dpot, reg, value);
216
217         }
218
219         return -EFAULT;
220 }
221
222 /* sysfs functions */
223
224 static ssize_t sysfs_show_reg(struct device *dev,
225                               struct device_attribute *attr,
226                               char *buf, u32 reg)
227 {
228         struct dpot_data *data = dev_get_drvdata(dev);
229         s32 value;
230
231         mutex_lock(&data->update_lock);
232         value = dpot_read(data, reg);
233         mutex_unlock(&data->update_lock);
234
235         if (value < 0)
236                 return -EINVAL;
237         /*
238          * Let someone else deal with converting this ...
239          * the tolerance is a two-byte value where the MSB
240          * is a sign + integer value, and the LSB is a
241          * decimal value.  See page 18 of the AD5258
242          * datasheet (Rev. A) for more details.
243          */
244
245         if (reg & DPOT_REG_TOL)
246                 return sprintf(buf, "0x%04x\n", value & 0xFFFF);
247         else
248                 return sprintf(buf, "%u\n", value & data->rdac_mask);
249 }
250
251 static ssize_t sysfs_set_reg(struct device *dev,
252                              struct device_attribute *attr,
253                              const char *buf, size_t count, u32 reg)
254 {
255         struct dpot_data *data = dev_get_drvdata(dev);
256         unsigned long value;
257         int err;
258
259         err = strict_strtoul(buf, 10, &value);
260         if (err)
261                 return err;
262
263         if (value > data->rdac_mask)
264                 value = data->rdac_mask;
265
266         mutex_lock(&data->update_lock);
267         dpot_write(data, reg, value);
268         if (reg & DPOT_ADDR_EEPROM)
269                 msleep(26);     /* Sleep while the EEPROM updates */
270         mutex_unlock(&data->update_lock);
271
272         return count;
273 }
274
275 static ssize_t sysfs_do_cmd(struct device *dev,
276                             struct device_attribute *attr,
277                             const char *buf, size_t count, u32 reg)
278 {
279         struct dpot_data *data = dev_get_drvdata(dev);
280
281         mutex_lock(&data->update_lock);
282         dpot_write(data, reg, 0);
283         mutex_unlock(&data->update_lock);
284
285         return count;
286 }
287
288 /* ------------------------------------------------------------------------- */
289
290 #define DPOT_DEVICE_SHOW(_name, _reg) static ssize_t \
291 show_##_name(struct device *dev, \
292                           struct device_attribute *attr, char *buf) \
293 { \
294         return sysfs_show_reg(dev, attr, buf, _reg); \
295 }
296
297 #define DPOT_DEVICE_SET(_name, _reg) static ssize_t \
298 set_##_name(struct device *dev, \
299                          struct device_attribute *attr, \
300                          const char *buf, size_t count) \
301 { \
302         return sysfs_set_reg(dev, attr, buf, count, _reg); \
303 }
304
305 #define DPOT_DEVICE_SHOW_SET(name, reg) \
306 DPOT_DEVICE_SHOW(name, reg) \
307 DPOT_DEVICE_SET(name, reg) \
308 static DEVICE_ATTR(name, S_IWUSR | S_IRUGO, show_##name, set_##name);
309
310 #define DPOT_DEVICE_SHOW_ONLY(name, reg) \
311 DPOT_DEVICE_SHOW(name, reg) \
312 static DEVICE_ATTR(name, S_IWUSR | S_IRUGO, show_##name, NULL);
313
314 DPOT_DEVICE_SHOW_SET(rdac0, DPOT_ADDR_RDAC | DPOT_RDAC0);
315 DPOT_DEVICE_SHOW_SET(eeprom0, DPOT_ADDR_EEPROM | DPOT_RDAC0);
316 DPOT_DEVICE_SHOW_ONLY(tolerance0, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC0);
317
318 DPOT_DEVICE_SHOW_SET(rdac1, DPOT_ADDR_RDAC | DPOT_RDAC1);
319 DPOT_DEVICE_SHOW_SET(eeprom1, DPOT_ADDR_EEPROM | DPOT_RDAC1);
320 DPOT_DEVICE_SHOW_ONLY(tolerance1, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC1);
321
322 DPOT_DEVICE_SHOW_SET(rdac2, DPOT_ADDR_RDAC | DPOT_RDAC2);
323 DPOT_DEVICE_SHOW_SET(eeprom2, DPOT_ADDR_EEPROM | DPOT_RDAC2);
324 DPOT_DEVICE_SHOW_ONLY(tolerance2, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC2);
325
326 DPOT_DEVICE_SHOW_SET(rdac3, DPOT_ADDR_RDAC | DPOT_RDAC3);
327 DPOT_DEVICE_SHOW_SET(eeprom3, DPOT_ADDR_EEPROM | DPOT_RDAC3);
328 DPOT_DEVICE_SHOW_ONLY(tolerance3, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC3);
329
330 DPOT_DEVICE_SHOW_SET(rdac4, DPOT_ADDR_RDAC | DPOT_RDAC4);
331 DPOT_DEVICE_SHOW_SET(eeprom4, DPOT_ADDR_EEPROM | DPOT_RDAC4);
332 DPOT_DEVICE_SHOW_ONLY(tolerance4, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC4);
333
334 DPOT_DEVICE_SHOW_SET(rdac5, DPOT_ADDR_RDAC | DPOT_RDAC5);
335 DPOT_DEVICE_SHOW_SET(eeprom5, DPOT_ADDR_EEPROM | DPOT_RDAC5);
336 DPOT_DEVICE_SHOW_ONLY(tolerance5, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC5);
337
338 static const struct attribute *dpot_attrib_wipers[] = {
339         &dev_attr_rdac0.attr,
340         &dev_attr_rdac1.attr,
341         &dev_attr_rdac2.attr,
342         &dev_attr_rdac3.attr,
343         &dev_attr_rdac4.attr,
344         &dev_attr_rdac5.attr,
345         NULL
346 };
347
348 static const struct attribute *dpot_attrib_eeprom[] = {
349         &dev_attr_eeprom0.attr,
350         &dev_attr_eeprom1.attr,
351         &dev_attr_eeprom2.attr,
352         &dev_attr_eeprom3.attr,
353         &dev_attr_eeprom4.attr,
354         &dev_attr_eeprom5.attr,
355         NULL
356 };
357
358 static const struct attribute *dpot_attrib_tolerance[] = {
359         &dev_attr_tolerance0.attr,
360         &dev_attr_tolerance1.attr,
361         &dev_attr_tolerance2.attr,
362         &dev_attr_tolerance3.attr,
363         &dev_attr_tolerance4.attr,
364         &dev_attr_tolerance5.attr,
365         NULL
366 };
367
368 /* ------------------------------------------------------------------------- */
369
370 #define DPOT_DEVICE_DO_CMD(_name, _cmd) static ssize_t \
371 set_##_name(struct device *dev, \
372                          struct device_attribute *attr, \
373                          const char *buf, size_t count) \
374 { \
375         return sysfs_do_cmd(dev, attr, buf, count, _cmd); \
376 } \
377 static DEVICE_ATTR(_name, S_IWUSR | S_IRUGO, NULL, set_##_name);
378
379 DPOT_DEVICE_DO_CMD(inc_all, DPOT_INC_ALL);
380 DPOT_DEVICE_DO_CMD(dec_all, DPOT_DEC_ALL);
381 DPOT_DEVICE_DO_CMD(inc_all_6db, DPOT_INC_ALL_6DB);
382 DPOT_DEVICE_DO_CMD(dec_all_6db, DPOT_DEC_ALL_6DB);
383
384 static struct attribute *ad525x_attributes_commands[] = {
385         &dev_attr_inc_all.attr,
386         &dev_attr_dec_all.attr,
387         &dev_attr_inc_all_6db.attr,
388         &dev_attr_dec_all_6db.attr,
389         NULL
390 };
391
392 static const struct attribute_group ad525x_group_commands = {
393         .attrs = ad525x_attributes_commands,
394 };
395
396 __devinit int ad_dpot_add_files(struct device *dev,
397                 unsigned features, unsigned rdac)
398 {
399         int err = sysfs_create_file(&dev->kobj,
400                 dpot_attrib_wipers[rdac]);
401         if (features & F_CMD_EEP)
402                 err |= sysfs_create_file(&dev->kobj,
403                         dpot_attrib_eeprom[rdac]);
404         if (features & F_CMD_TOL)
405                 err |= sysfs_create_file(&dev->kobj,
406                         dpot_attrib_tolerance[rdac]);
407
408         if (err)
409                 dev_err(dev, "failed to register sysfs hooks for RDAC%d\n",
410                         rdac);
411
412         return err;
413 }
414
415 inline void ad_dpot_remove_files(struct device *dev,
416                 unsigned features, unsigned rdac)
417 {
418         sysfs_remove_file(&dev->kobj,
419                 dpot_attrib_wipers[rdac]);
420         if (features & F_CMD_EEP)
421                 sysfs_remove_file(&dev->kobj,
422                         dpot_attrib_eeprom[rdac]);
423         if (features & F_CMD_TOL)
424                 sysfs_remove_file(&dev->kobj,
425                         dpot_attrib_tolerance[rdac]);
426 }
427
428 __devinit int ad_dpot_probe(struct device *dev,
429                 struct ad_dpot_bus_data *bdata, const struct ad_dpot_id *id)
430 {
431
432         struct dpot_data *data;
433         int i, err = 0;
434
435         data = kzalloc(sizeof(struct dpot_data), GFP_KERNEL);
436         if (!data) {
437                 err = -ENOMEM;
438                 goto exit;
439         }
440
441         dev_set_drvdata(dev, data);
442         mutex_init(&data->update_lock);
443
444         data->bdata = *bdata;
445         data->devid = id->devid;
446
447         data->max_pos = 1 << DPOT_MAX_POS(data->devid);
448         data->rdac_mask = data->max_pos - 1;
449         data->feat = DPOT_FEAT(data->devid);
450         data->uid = DPOT_UID(data->devid);
451         data->wipers = DPOT_WIPERS(data->devid);
452
453         for (i = DPOT_RDAC0; i <= DPOT_RDAC5; i++)
454                 if (data->wipers & (1 << i)) {
455                         err = ad_dpot_add_files(dev, data->feat, i);
456                         if (err)
457                                 goto exit_remove_files;
458                         /* power-up midscale */
459                         if (data->feat & F_RDACS_WONLY)
460                                 data->rdac_cache[i] = data->max_pos / 2;
461                 }
462
463         if (data->feat & F_CMD_INC)
464                 err = sysfs_create_group(&dev->kobj, &ad525x_group_commands);
465
466         if (err) {
467                 dev_err(dev, "failed to register sysfs hooks\n");
468                 goto exit_free;
469         }
470
471         dev_info(dev, "%s %d-Position Digital Potentiometer registered\n",
472                  id->name, data->max_pos);
473
474         return 0;
475
476 exit_remove_files:
477         for (i = DPOT_RDAC0; i <= DPOT_RDAC5; i++)
478                 if (data->wipers & (1 << i))
479                         ad_dpot_remove_files(dev, data->feat, i);
480
481 exit_free:
482         kfree(data);
483         dev_set_drvdata(dev, NULL);
484 exit:
485         dev_err(dev, "failed to create client for %s ID 0x%lX\n",
486                         id->name, id->devid);
487         return err;
488 }
489 EXPORT_SYMBOL(ad_dpot_probe);
490
491 __devexit int ad_dpot_remove(struct device *dev)
492 {
493         struct dpot_data *data = dev_get_drvdata(dev);
494         int i;
495
496         for (i = DPOT_RDAC0; i <= DPOT_RDAC5; i++)
497                 if (data->wipers & (1 << i))
498                         ad_dpot_remove_files(dev, data->feat, i);
499
500         kfree(data);
501
502         return 0;
503 }
504 EXPORT_SYMBOL(ad_dpot_remove);
505
506
507 MODULE_AUTHOR("Chris Verges <chrisv@cyberswitching.com>, "
508               "Michael Hennerich <hennerich@blackfin.uclinux.org>");
509 MODULE_DESCRIPTION("Digital potentiometer driver");
510 MODULE_LICENSE("GPL");
511 MODULE_VERSION(DRIVER_VERSION);