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>
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
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
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 * AD5241 1 256 10, 100, 1M
41 * AD5246 1 128 5, 10, 50, 100
42 * AD5247 1 128 5, 10, 50, 100
43 * AD5245 1 256 5, 10, 50, 100
44 * AD5243 2 256 2.5, 10, 50, 100
45 * AD5248 2 256 2.5, 10, 50, 100
46 * AD5242 2 256 20, 50, 200
47 * AD5280 1 256 20, 50, 200
48 * AD5282 2 256 20, 50, 200
49 * ADN2860 3 512 25, 250
51 * See Documentation/misc-devices/ad525x_dpot.txt for more info.
53 * derived from ad5258.c
54 * Copyright (c) 2009 Cyber Switching, Inc.
55 * Author: Chris Verges <chrisv@cyberswitching.com>
57 * derived from ad5252.c
58 * Copyright (c) 2006 Michael Hennerich <hennerich@blackfin.uclinux.org>
60 * Licensed under the GPL-2 or later.
63 #include <linux/module.h>
64 #include <linux/device.h>
65 #include <linux/kernel.h>
66 #include <linux/init.h>
67 #include <linux/delay.h>
68 #include <linux/slab.h>
70 #define DRIVER_VERSION "0.2"
72 #include "ad525x_dpot.h"
75 * Client data (each client gets its own)
79 struct ad_dpot_bus_data bdata
;
80 struct mutex update_lock
;
90 static inline int dpot_read_d8(struct dpot_data
*dpot
)
92 return dpot
->bdata
.bops
->read_d8(dpot
->bdata
.client
);
95 static inline int dpot_read_r8d8(struct dpot_data
*dpot
, u8 reg
)
97 return dpot
->bdata
.bops
->read_r8d8(dpot
->bdata
.client
, reg
);
100 static inline int dpot_read_r8d16(struct dpot_data
*dpot
, u8 reg
)
102 return dpot
->bdata
.bops
->read_r8d16(dpot
->bdata
.client
, reg
);
105 static inline int dpot_write_d8(struct dpot_data
*dpot
, u8 val
)
107 return dpot
->bdata
.bops
->write_d8(dpot
->bdata
.client
, val
);
110 static inline int dpot_write_r8d8(struct dpot_data
*dpot
, u8 reg
, u16 val
)
112 return dpot
->bdata
.bops
->write_r8d8(dpot
->bdata
.client
, reg
, val
);
115 static inline int dpot_write_r8d16(struct dpot_data
*dpot
, u8 reg
, u16 val
)
117 return dpot
->bdata
.bops
->write_r8d16(dpot
->bdata
.client
, reg
, val
);
120 static s32
dpot_read_spi(struct dpot_data
*dpot
, u8 reg
)
124 if (!(reg
& (DPOT_ADDR_EEPROM
| DPOT_ADDR_CMD
))) {
126 if (dpot
->feat
& F_RDACS_WONLY
)
127 return dpot
->rdac_cache
[reg
& DPOT_RDAC_MASK
];
129 if (dpot
->uid
== DPOT_UID(AD5291_ID
) ||
130 dpot
->uid
== DPOT_UID(AD5292_ID
) ||
131 dpot
->uid
== DPOT_UID(AD5293_ID
))
132 return dpot_read_r8d8(dpot
,
133 DPOT_AD5291_READ_RDAC
<< 2);
135 ctrl
= DPOT_SPI_READ_RDAC
;
136 } else if (reg
& DPOT_ADDR_EEPROM
) {
137 ctrl
= DPOT_SPI_READ_EEPROM
;
140 if (dpot
->feat
& F_SPI_16BIT
)
141 return dpot_read_r8d8(dpot
, ctrl
);
142 else if (dpot
->feat
& F_SPI_24BIT
)
143 return dpot_read_r8d16(dpot
, ctrl
);
148 static s32
dpot_read_i2c(struct dpot_data
*dpot
, u8 reg
)
152 case DPOT_UID(AD5246_ID
):
153 case DPOT_UID(AD5247_ID
):
154 return dpot_read_d8(dpot
);
155 case DPOT_UID(AD5245_ID
):
156 case DPOT_UID(AD5241_ID
):
157 case DPOT_UID(AD5242_ID
):
158 case DPOT_UID(AD5243_ID
):
159 case DPOT_UID(AD5248_ID
):
160 case DPOT_UID(AD5280_ID
):
161 case DPOT_UID(AD5282_ID
):
162 ctrl
= ((reg
& DPOT_RDAC_MASK
) == DPOT_RDAC0
) ?
163 0 : DPOT_AD5291_RDAC_AB
;
164 return dpot_read_r8d8(dpot
, ctrl
);
166 if ((reg
& DPOT_REG_TOL
) || (dpot
->max_pos
> 256))
167 return dpot_read_r8d16(dpot
, (reg
& 0xF8) |
170 return dpot_read_r8d8(dpot
, reg
);
174 static s32
dpot_read(struct dpot_data
*dpot
, u8 reg
)
176 if (dpot
->feat
& F_SPI
)
177 return dpot_read_spi(dpot
, reg
);
179 return dpot_read_i2c(dpot
, reg
);
182 static s32
dpot_write_spi(struct dpot_data
*dpot
, u8 reg
, u16 value
)
186 if (!(reg
& (DPOT_ADDR_EEPROM
| DPOT_ADDR_CMD
))) {
187 if (dpot
->feat
& F_RDACS_WONLY
)
188 dpot
->rdac_cache
[reg
& DPOT_RDAC_MASK
] = value
;
190 if (dpot
->feat
& F_AD_APPDATA
) {
191 if (dpot
->feat
& F_SPI_8BIT
) {
192 val
= ((reg
& DPOT_RDAC_MASK
) <<
193 DPOT_MAX_POS(dpot
->devid
)) |
195 return dpot_write_d8(dpot
, val
);
196 } else if (dpot
->feat
& F_SPI_16BIT
) {
197 val
= ((reg
& DPOT_RDAC_MASK
) <<
198 DPOT_MAX_POS(dpot
->devid
)) |
200 return dpot_write_r8d8(dpot
, val
>> 8,
205 if (dpot
->uid
== DPOT_UID(AD5291_ID
) ||
206 dpot
->uid
== DPOT_UID(AD5292_ID
) ||
207 dpot
->uid
== DPOT_UID(AD5293_ID
))
208 return dpot_write_r8d8(dpot
,
209 (DPOT_AD5291_RDAC
<< 2) |
210 (value
>> 8), value
& 0xFF);
212 val
= DPOT_SPI_RDAC
| (reg
& DPOT_RDAC_MASK
);
214 } else if (reg
& DPOT_ADDR_EEPROM
) {
215 val
= DPOT_SPI_EEPROM
| (reg
& DPOT_RDAC_MASK
);
216 } else if (reg
& DPOT_ADDR_CMD
) {
218 case DPOT_DEC_ALL_6DB
:
219 val
= DPOT_SPI_DEC_ALL_6DB
;
221 case DPOT_INC_ALL_6DB
:
222 val
= DPOT_SPI_INC_ALL_6DB
;
225 val
= DPOT_SPI_DEC_ALL
;
228 val
= DPOT_SPI_INC_ALL
;
234 if (dpot
->feat
& F_SPI_16BIT
)
235 return dpot_write_r8d8(dpot
, val
, value
);
236 else if (dpot
->feat
& F_SPI_24BIT
)
237 return dpot_write_r8d16(dpot
, val
, value
);
242 static s32
dpot_write_i2c(struct dpot_data
*dpot
, u8 reg
, u16 value
)
244 /* Only write the instruction byte for certain commands */
248 case DPOT_UID(AD5246_ID
):
249 case DPOT_UID(AD5247_ID
):
250 return dpot_write_d8(dpot
, value
);
253 case DPOT_UID(AD5245_ID
):
254 case DPOT_UID(AD5241_ID
):
255 case DPOT_UID(AD5242_ID
):
256 case DPOT_UID(AD5243_ID
):
257 case DPOT_UID(AD5248_ID
):
258 case DPOT_UID(AD5280_ID
):
259 case DPOT_UID(AD5282_ID
):
260 ctrl
= ((reg
& DPOT_RDAC_MASK
) == DPOT_RDAC0
) ?
261 0 : DPOT_AD5291_RDAC_AB
;
262 return dpot_write_r8d8(dpot
, ctrl
, value
);
265 if (reg
& DPOT_ADDR_CMD
)
266 return dpot_write_d8(dpot
, reg
);
268 if (dpot
->max_pos
> 256)
269 return dpot_write_r8d16(dpot
, (reg
& 0xF8) |
270 ((reg
& 0x7) << 1), value
);
272 /* All other registers require instruction + data bytes */
273 return dpot_write_r8d8(dpot
, reg
, value
);
278 static s32
dpot_write(struct dpot_data
*dpot
, u8 reg
, u16 value
)
280 if (dpot
->feat
& F_SPI
)
281 return dpot_write_spi(dpot
, reg
, value
);
283 return dpot_write_i2c(dpot
, reg
, value
);
286 /* sysfs functions */
288 static ssize_t
sysfs_show_reg(struct device
*dev
,
289 struct device_attribute
*attr
,
292 struct dpot_data
*data
= dev_get_drvdata(dev
);
295 mutex_lock(&data
->update_lock
);
296 value
= dpot_read(data
, reg
);
297 mutex_unlock(&data
->update_lock
);
302 * Let someone else deal with converting this ...
303 * the tolerance is a two-byte value where the MSB
304 * is a sign + integer value, and the LSB is a
305 * decimal value. See page 18 of the AD5258
306 * datasheet (Rev. A) for more details.
309 if (reg
& DPOT_REG_TOL
)
310 return sprintf(buf
, "0x%04x\n", value
& 0xFFFF);
312 return sprintf(buf
, "%u\n", value
& data
->rdac_mask
);
315 static ssize_t
sysfs_set_reg(struct device
*dev
,
316 struct device_attribute
*attr
,
317 const char *buf
, size_t count
, u32 reg
)
319 struct dpot_data
*data
= dev_get_drvdata(dev
);
323 err
= strict_strtoul(buf
, 10, &value
);
327 if (value
> data
->rdac_mask
)
328 value
= data
->rdac_mask
;
330 mutex_lock(&data
->update_lock
);
331 dpot_write(data
, reg
, value
);
332 if (reg
& DPOT_ADDR_EEPROM
)
333 msleep(26); /* Sleep while the EEPROM updates */
334 mutex_unlock(&data
->update_lock
);
339 static ssize_t
sysfs_do_cmd(struct device
*dev
,
340 struct device_attribute
*attr
,
341 const char *buf
, size_t count
, u32 reg
)
343 struct dpot_data
*data
= dev_get_drvdata(dev
);
345 mutex_lock(&data
->update_lock
);
346 dpot_write(data
, reg
, 0);
347 mutex_unlock(&data
->update_lock
);
352 /* ------------------------------------------------------------------------- */
354 #define DPOT_DEVICE_SHOW(_name, _reg) static ssize_t \
355 show_##_name(struct device *dev, \
356 struct device_attribute *attr, char *buf) \
358 return sysfs_show_reg(dev, attr, buf, _reg); \
361 #define DPOT_DEVICE_SET(_name, _reg) static ssize_t \
362 set_##_name(struct device *dev, \
363 struct device_attribute *attr, \
364 const char *buf, size_t count) \
366 return sysfs_set_reg(dev, attr, buf, count, _reg); \
369 #define DPOT_DEVICE_SHOW_SET(name, reg) \
370 DPOT_DEVICE_SHOW(name, reg) \
371 DPOT_DEVICE_SET(name, reg) \
372 static DEVICE_ATTR(name, S_IWUSR | S_IRUGO, show_##name, set_##name);
374 #define DPOT_DEVICE_SHOW_ONLY(name, reg) \
375 DPOT_DEVICE_SHOW(name, reg) \
376 static DEVICE_ATTR(name, S_IWUSR | S_IRUGO, show_##name, NULL);
378 DPOT_DEVICE_SHOW_SET(rdac0
, DPOT_ADDR_RDAC
| DPOT_RDAC0
);
379 DPOT_DEVICE_SHOW_SET(eeprom0
, DPOT_ADDR_EEPROM
| DPOT_RDAC0
);
380 DPOT_DEVICE_SHOW_ONLY(tolerance0
, DPOT_ADDR_EEPROM
| DPOT_TOL_RDAC0
);
382 DPOT_DEVICE_SHOW_SET(rdac1
, DPOT_ADDR_RDAC
| DPOT_RDAC1
);
383 DPOT_DEVICE_SHOW_SET(eeprom1
, DPOT_ADDR_EEPROM
| DPOT_RDAC1
);
384 DPOT_DEVICE_SHOW_ONLY(tolerance1
, DPOT_ADDR_EEPROM
| DPOT_TOL_RDAC1
);
386 DPOT_DEVICE_SHOW_SET(rdac2
, DPOT_ADDR_RDAC
| DPOT_RDAC2
);
387 DPOT_DEVICE_SHOW_SET(eeprom2
, DPOT_ADDR_EEPROM
| DPOT_RDAC2
);
388 DPOT_DEVICE_SHOW_ONLY(tolerance2
, DPOT_ADDR_EEPROM
| DPOT_TOL_RDAC2
);
390 DPOT_DEVICE_SHOW_SET(rdac3
, DPOT_ADDR_RDAC
| DPOT_RDAC3
);
391 DPOT_DEVICE_SHOW_SET(eeprom3
, DPOT_ADDR_EEPROM
| DPOT_RDAC3
);
392 DPOT_DEVICE_SHOW_ONLY(tolerance3
, DPOT_ADDR_EEPROM
| DPOT_TOL_RDAC3
);
394 DPOT_DEVICE_SHOW_SET(rdac4
, DPOT_ADDR_RDAC
| DPOT_RDAC4
);
395 DPOT_DEVICE_SHOW_SET(eeprom4
, DPOT_ADDR_EEPROM
| DPOT_RDAC4
);
396 DPOT_DEVICE_SHOW_ONLY(tolerance4
, DPOT_ADDR_EEPROM
| DPOT_TOL_RDAC4
);
398 DPOT_DEVICE_SHOW_SET(rdac5
, DPOT_ADDR_RDAC
| DPOT_RDAC5
);
399 DPOT_DEVICE_SHOW_SET(eeprom5
, DPOT_ADDR_EEPROM
| DPOT_RDAC5
);
400 DPOT_DEVICE_SHOW_ONLY(tolerance5
, DPOT_ADDR_EEPROM
| DPOT_TOL_RDAC5
);
402 static const struct attribute
*dpot_attrib_wipers
[] = {
403 &dev_attr_rdac0
.attr
,
404 &dev_attr_rdac1
.attr
,
405 &dev_attr_rdac2
.attr
,
406 &dev_attr_rdac3
.attr
,
407 &dev_attr_rdac4
.attr
,
408 &dev_attr_rdac5
.attr
,
412 static const struct attribute
*dpot_attrib_eeprom
[] = {
413 &dev_attr_eeprom0
.attr
,
414 &dev_attr_eeprom1
.attr
,
415 &dev_attr_eeprom2
.attr
,
416 &dev_attr_eeprom3
.attr
,
417 &dev_attr_eeprom4
.attr
,
418 &dev_attr_eeprom5
.attr
,
422 static const struct attribute
*dpot_attrib_tolerance
[] = {
423 &dev_attr_tolerance0
.attr
,
424 &dev_attr_tolerance1
.attr
,
425 &dev_attr_tolerance2
.attr
,
426 &dev_attr_tolerance3
.attr
,
427 &dev_attr_tolerance4
.attr
,
428 &dev_attr_tolerance5
.attr
,
432 /* ------------------------------------------------------------------------- */
434 #define DPOT_DEVICE_DO_CMD(_name, _cmd) static ssize_t \
435 set_##_name(struct device *dev, \
436 struct device_attribute *attr, \
437 const char *buf, size_t count) \
439 return sysfs_do_cmd(dev, attr, buf, count, _cmd); \
441 static DEVICE_ATTR(_name, S_IWUSR | S_IRUGO, NULL, set_##_name);
443 DPOT_DEVICE_DO_CMD(inc_all
, DPOT_INC_ALL
);
444 DPOT_DEVICE_DO_CMD(dec_all
, DPOT_DEC_ALL
);
445 DPOT_DEVICE_DO_CMD(inc_all_6db
, DPOT_INC_ALL_6DB
);
446 DPOT_DEVICE_DO_CMD(dec_all_6db
, DPOT_DEC_ALL_6DB
);
448 static struct attribute
*ad525x_attributes_commands
[] = {
449 &dev_attr_inc_all
.attr
,
450 &dev_attr_dec_all
.attr
,
451 &dev_attr_inc_all_6db
.attr
,
452 &dev_attr_dec_all_6db
.attr
,
456 static const struct attribute_group ad525x_group_commands
= {
457 .attrs
= ad525x_attributes_commands
,
460 __devinit
int ad_dpot_add_files(struct device
*dev
,
461 unsigned features
, unsigned rdac
)
463 int err
= sysfs_create_file(&dev
->kobj
,
464 dpot_attrib_wipers
[rdac
]);
465 if (features
& F_CMD_EEP
)
466 err
|= sysfs_create_file(&dev
->kobj
,
467 dpot_attrib_eeprom
[rdac
]);
468 if (features
& F_CMD_TOL
)
469 err
|= sysfs_create_file(&dev
->kobj
,
470 dpot_attrib_tolerance
[rdac
]);
473 dev_err(dev
, "failed to register sysfs hooks for RDAC%d\n",
479 inline void ad_dpot_remove_files(struct device
*dev
,
480 unsigned features
, unsigned rdac
)
482 sysfs_remove_file(&dev
->kobj
,
483 dpot_attrib_wipers
[rdac
]);
484 if (features
& F_CMD_EEP
)
485 sysfs_remove_file(&dev
->kobj
,
486 dpot_attrib_eeprom
[rdac
]);
487 if (features
& F_CMD_TOL
)
488 sysfs_remove_file(&dev
->kobj
,
489 dpot_attrib_tolerance
[rdac
]);
492 __devinit
int ad_dpot_probe(struct device
*dev
,
493 struct ad_dpot_bus_data
*bdata
, const struct ad_dpot_id
*id
)
496 struct dpot_data
*data
;
499 data
= kzalloc(sizeof(struct dpot_data
), GFP_KERNEL
);
505 dev_set_drvdata(dev
, data
);
506 mutex_init(&data
->update_lock
);
508 data
->bdata
= *bdata
;
509 data
->devid
= id
->devid
;
511 data
->max_pos
= 1 << DPOT_MAX_POS(data
->devid
);
512 data
->rdac_mask
= data
->max_pos
- 1;
513 data
->feat
= DPOT_FEAT(data
->devid
);
514 data
->uid
= DPOT_UID(data
->devid
);
515 data
->wipers
= DPOT_WIPERS(data
->devid
);
517 for (i
= DPOT_RDAC0
; i
<= DPOT_RDAC5
; i
++)
518 if (data
->wipers
& (1 << i
)) {
519 err
= ad_dpot_add_files(dev
, data
->feat
, i
);
521 goto exit_remove_files
;
522 /* power-up midscale */
523 if (data
->feat
& F_RDACS_WONLY
)
524 data
->rdac_cache
[i
] = data
->max_pos
/ 2;
527 if (data
->feat
& F_CMD_INC
)
528 err
= sysfs_create_group(&dev
->kobj
, &ad525x_group_commands
);
531 dev_err(dev
, "failed to register sysfs hooks\n");
535 dev_info(dev
, "%s %d-Position Digital Potentiometer registered\n",
536 id
->name
, data
->max_pos
);
541 for (i
= DPOT_RDAC0
; i
<= DPOT_RDAC5
; i
++)
542 if (data
->wipers
& (1 << i
))
543 ad_dpot_remove_files(dev
, data
->feat
, i
);
547 dev_set_drvdata(dev
, NULL
);
549 dev_err(dev
, "failed to create client for %s ID 0x%lX\n",
550 id
->name
, id
->devid
);
553 EXPORT_SYMBOL(ad_dpot_probe
);
555 __devexit
int ad_dpot_remove(struct device
*dev
)
557 struct dpot_data
*data
= dev_get_drvdata(dev
);
560 for (i
= DPOT_RDAC0
; i
<= DPOT_RDAC5
; i
++)
561 if (data
->wipers
& (1 << i
))
562 ad_dpot_remove_files(dev
, data
->feat
, i
);
568 EXPORT_SYMBOL(ad_dpot_remove
);
571 MODULE_AUTHOR("Chris Verges <chrisv@cyberswitching.com>, "
572 "Michael Hennerich <hennerich@blackfin.uclinux.org>");
573 MODULE_DESCRIPTION("Digital potentiometer driver");
574 MODULE_LICENSE("GPL");
575 MODULE_VERSION(DRIVER_VERSION
);