blob: ce92088bf0b8bdb9902e7d3d482f6355265b9154 [file] [log] [blame]
Michael Hennerich4eb174b2009-12-14 18:00:15 -08001/*
2 * ad525x_dpot: Driver for the Analog Devices AD525x digital potentiometers
3 * Copyright (c) 2009 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 *
15 * See Documentation/misc-devices/ad525x_dpot.txt for more info.
16 *
17 * derived from ad5258.c
18 * Copyright (c) 2009 Cyber Switching, Inc.
19 * Author: Chris Verges <chrisv@cyberswitching.com>
20 *
21 * derived from ad5252.c
22 * Copyright (c) 2006 Michael Hennerich <hennerich@blackfin.uclinux.org>
23 *
24 * Licensed under the GPL-2 or later.
25 */
26
27#include <linux/module.h>
28#include <linux/device.h>
29#include <linux/kernel.h>
30#include <linux/init.h>
31#include <linux/slab.h>
32#include <linux/i2c.h>
33#include <linux/delay.h>
34
35#define DRIVER_NAME "ad525x_dpot"
36#define DRIVER_VERSION "0.1"
37
38enum dpot_devid {
39 AD5258_ID,
40 AD5259_ID,
41 AD5251_ID,
42 AD5252_ID,
43 AD5253_ID,
44 AD5254_ID,
45 AD5255_ID,
46};
47
48#define AD5258_MAX_POSITION 64
49#define AD5259_MAX_POSITION 256
50#define AD5251_MAX_POSITION 64
51#define AD5252_MAX_POSITION 256
52#define AD5253_MAX_POSITION 64
53#define AD5254_MAX_POSITION 256
54#define AD5255_MAX_POSITION 512
55
56#define AD525X_RDAC0 0
57#define AD525X_RDAC1 1
58#define AD525X_RDAC2 2
59#define AD525X_RDAC3 3
60
61#define AD525X_REG_TOL 0x18
62#define AD525X_TOL_RDAC0 (AD525X_REG_TOL | AD525X_RDAC0)
63#define AD525X_TOL_RDAC1 (AD525X_REG_TOL | AD525X_RDAC1)
64#define AD525X_TOL_RDAC2 (AD525X_REG_TOL | AD525X_RDAC2)
65#define AD525X_TOL_RDAC3 (AD525X_REG_TOL | AD525X_RDAC3)
66
67/* RDAC-to-EEPROM Interface Commands */
68#define AD525X_I2C_RDAC (0x00 << 5)
69#define AD525X_I2C_EEPROM (0x01 << 5)
70#define AD525X_I2C_CMD (0x80)
71
72#define AD525X_DEC_ALL_6DB (AD525X_I2C_CMD | (0x4 << 3))
73#define AD525X_INC_ALL_6DB (AD525X_I2C_CMD | (0x9 << 3))
74#define AD525X_DEC_ALL (AD525X_I2C_CMD | (0x6 << 3))
75#define AD525X_INC_ALL (AD525X_I2C_CMD | (0xB << 3))
76
77static s32 ad525x_read(struct i2c_client *client, u8 reg);
Michael Hennerich0c53b9f2010-05-24 14:33:13 -070078static s32 ad525x_write(struct i2c_client *client, u8 reg, u16 value);
Michael Hennerich4eb174b2009-12-14 18:00:15 -080079
80/*
81 * Client data (each client gets its own)
82 */
83
84struct dpot_data {
85 struct mutex update_lock;
86 unsigned rdac_mask;
87 unsigned max_pos;
88 unsigned devid;
89};
90
91/* sysfs functions */
92
93static ssize_t sysfs_show_reg(struct device *dev,
94 struct device_attribute *attr, char *buf, u32 reg)
95{
96 struct i2c_client *client = to_i2c_client(dev);
97 struct dpot_data *data = i2c_get_clientdata(client);
98 s32 value;
99
100 mutex_lock(&data->update_lock);
101 value = ad525x_read(client, reg);
102 mutex_unlock(&data->update_lock);
103
104 if (value < 0)
105 return -EINVAL;
106 /*
107 * Let someone else deal with converting this ...
108 * the tolerance is a two-byte value where the MSB
109 * is a sign + integer value, and the LSB is a
110 * decimal value. See page 18 of the AD5258
111 * datasheet (Rev. A) for more details.
112 */
113
114 if (reg & AD525X_REG_TOL)
115 return sprintf(buf, "0x%04x\n", value & 0xFFFF);
116 else
117 return sprintf(buf, "%u\n", value & data->rdac_mask);
118}
119
120static ssize_t sysfs_set_reg(struct device *dev,
121 struct device_attribute *attr,
122 const char *buf, size_t count, u32 reg)
123{
124 struct i2c_client *client = to_i2c_client(dev);
125 struct dpot_data *data = i2c_get_clientdata(client);
126 unsigned long value;
127 int err;
128
129 err = strict_strtoul(buf, 10, &value);
130 if (err)
131 return err;
132
133 if (value > data->rdac_mask)
134 value = data->rdac_mask;
135
136 mutex_lock(&data->update_lock);
137 ad525x_write(client, reg, value);
138 if (reg & AD525X_I2C_EEPROM)
139 msleep(26); /* Sleep while the EEPROM updates */
140 mutex_unlock(&data->update_lock);
141
142 return count;
143}
144
145static ssize_t sysfs_do_cmd(struct device *dev,
146 struct device_attribute *attr,
147 const char *buf, size_t count, u32 reg)
148{
149 struct i2c_client *client = to_i2c_client(dev);
150 struct dpot_data *data = i2c_get_clientdata(client);
151
152 mutex_lock(&data->update_lock);
153 ad525x_write(client, reg, 0);
154 mutex_unlock(&data->update_lock);
155
156 return count;
157}
158
159/* ------------------------------------------------------------------------- */
160
Michael Hennerich0993dbe2010-05-24 14:33:13 -0700161#define DPOT_DEVICE_SHOW(_name, _reg) static ssize_t \
162show_##_name(struct device *dev, \
163 struct device_attribute *attr, char *buf) \
164{ \
165 return sysfs_show_reg(dev, attr, buf, _reg); \
Michael Hennerich4eb174b2009-12-14 18:00:15 -0800166}
167
Michael Hennerich0993dbe2010-05-24 14:33:13 -0700168#define DPOT_DEVICE_SET(_name, _reg) static ssize_t \
169set_##_name(struct device *dev, \
170 struct device_attribute *attr, \
171 const char *buf, size_t count) \
172{ \
173 return sysfs_set_reg(dev, attr, buf, count, _reg); \
Michael Hennerich4eb174b2009-12-14 18:00:15 -0800174}
175
Michael Hennerich0993dbe2010-05-24 14:33:13 -0700176#define DPOT_DEVICE_SHOW_SET(name, reg) \
177DPOT_DEVICE_SHOW(name, reg) \
178DPOT_DEVICE_SET(name, reg) \
179static DEVICE_ATTR(name, S_IWUSR | S_IRUGO, show_##name, set_##name);
Michael Hennerich4eb174b2009-12-14 18:00:15 -0800180
Michael Hennerich0993dbe2010-05-24 14:33:13 -0700181#define DPOT_DEVICE_SHOW_ONLY(name, reg) \
182DPOT_DEVICE_SHOW(name, reg) \
183static DEVICE_ATTR(name, S_IWUSR | S_IRUGO, show_##name, NULL);
Michael Hennerich4eb174b2009-12-14 18:00:15 -0800184
Michael Hennerich0993dbe2010-05-24 14:33:13 -0700185DPOT_DEVICE_SHOW_SET(rdac0, AD525X_I2C_RDAC | AD525X_RDAC0);
186DPOT_DEVICE_SHOW_SET(eeprom0, AD525X_I2C_EEPROM | AD525X_RDAC0);
187DPOT_DEVICE_SHOW_ONLY(tolerance0, AD525X_I2C_EEPROM | AD525X_TOL_RDAC0);
Michael Hennerich4eb174b2009-12-14 18:00:15 -0800188
Michael Hennerich0993dbe2010-05-24 14:33:13 -0700189DPOT_DEVICE_SHOW_SET(rdac1, AD525X_I2C_RDAC | AD525X_RDAC1);
190DPOT_DEVICE_SHOW_SET(eeprom1, AD525X_I2C_EEPROM | AD525X_RDAC1);
191DPOT_DEVICE_SHOW_ONLY(tolerance1, AD525X_I2C_EEPROM | AD525X_TOL_RDAC1);
Michael Hennerich4eb174b2009-12-14 18:00:15 -0800192
Michael Hennerich0993dbe2010-05-24 14:33:13 -0700193DPOT_DEVICE_SHOW_SET(rdac2, AD525X_I2C_RDAC | AD525X_RDAC2);
194DPOT_DEVICE_SHOW_SET(eeprom2, AD525X_I2C_EEPROM | AD525X_RDAC2);
195DPOT_DEVICE_SHOW_ONLY(tolerance2, AD525X_I2C_EEPROM | AD525X_TOL_RDAC2);
Michael Hennerich4eb174b2009-12-14 18:00:15 -0800196
Michael Hennerich0993dbe2010-05-24 14:33:13 -0700197DPOT_DEVICE_SHOW_SET(rdac3, AD525X_I2C_RDAC | AD525X_RDAC3);
198DPOT_DEVICE_SHOW_SET(eeprom3, AD525X_I2C_EEPROM | AD525X_RDAC3);
199DPOT_DEVICE_SHOW_ONLY(tolerance3, AD525X_I2C_EEPROM | AD525X_TOL_RDAC3);
Michael Hennerich4eb174b2009-12-14 18:00:15 -0800200
201static struct attribute *ad525x_attributes_wipers[4][4] = {
202 {
203 &dev_attr_rdac0.attr,
204 &dev_attr_eeprom0.attr,
205 &dev_attr_tolerance0.attr,
206 NULL
207 }, {
208 &dev_attr_rdac1.attr,
209 &dev_attr_eeprom1.attr,
210 &dev_attr_tolerance1.attr,
211 NULL
212 }, {
213 &dev_attr_rdac2.attr,
214 &dev_attr_eeprom2.attr,
215 &dev_attr_tolerance2.attr,
216 NULL
217 }, {
218 &dev_attr_rdac3.attr,
219 &dev_attr_eeprom3.attr,
220 &dev_attr_tolerance3.attr,
221 NULL
222 }
223};
224
225static const struct attribute_group ad525x_group_wipers[] = {
226 {.attrs = ad525x_attributes_wipers[AD525X_RDAC0]},
227 {.attrs = ad525x_attributes_wipers[AD525X_RDAC1]},
228 {.attrs = ad525x_attributes_wipers[AD525X_RDAC2]},
229 {.attrs = ad525x_attributes_wipers[AD525X_RDAC3]},
230};
231
232/* ------------------------------------------------------------------------- */
233
Michael Hennerich0993dbe2010-05-24 14:33:13 -0700234#define DPOT_DEVICE_DO_CMD(_name, _cmd) static ssize_t \
235set_##_name(struct device *dev, \
236 struct device_attribute *attr, \
237 const char *buf, size_t count) \
238{ \
239 return sysfs_do_cmd(dev, attr, buf, count, _cmd); \
240} \
241static DEVICE_ATTR(_name, S_IWUSR | S_IRUGO, NULL, set_##_name);
Michael Hennerich4eb174b2009-12-14 18:00:15 -0800242
Michael Hennerich0993dbe2010-05-24 14:33:13 -0700243DPOT_DEVICE_DO_CMD(inc_all, AD525X_INC_ALL);
244DPOT_DEVICE_DO_CMD(dec_all, AD525X_DEC_ALL);
245DPOT_DEVICE_DO_CMD(inc_all_6db, AD525X_INC_ALL_6DB);
246DPOT_DEVICE_DO_CMD(dec_all_6db, AD525X_DEC_ALL_6DB);
Michael Hennerich4eb174b2009-12-14 18:00:15 -0800247
248static struct attribute *ad525x_attributes_commands[] = {
249 &dev_attr_inc_all.attr,
250 &dev_attr_dec_all.attr,
251 &dev_attr_inc_all_6db.attr,
252 &dev_attr_dec_all_6db.attr,
253 NULL
254};
255
256static const struct attribute_group ad525x_group_commands = {
257 .attrs = ad525x_attributes_commands,
258};
259
260/* ------------------------------------------------------------------------- */
261
262/* i2c device functions */
263
264/**
265 * ad525x_read - return the value contained in the specified register
266 * on the AD5258 device.
267 * @client: value returned from i2c_new_device()
268 * @reg: the register to read
269 *
270 * If the tolerance register is specified, 2 bytes are returned.
271 * Otherwise, 1 byte is returned. A negative value indicates an error
272 * occurred while reading the register.
273 */
274static s32 ad525x_read(struct i2c_client *client, u8 reg)
275{
276 struct dpot_data *data = i2c_get_clientdata(client);
277
278 if ((reg & AD525X_REG_TOL) || (data->max_pos > 256))
279 return i2c_smbus_read_word_data(client, (reg & 0xF8) |
280 ((reg & 0x7) << 1));
281 else
282 return i2c_smbus_read_byte_data(client, reg);
283}
284
285/**
286 * ad525x_write - store the given value in the specified register on
287 * the AD5258 device.
288 * @client: value returned from i2c_new_device()
289 * @reg: the register to write
290 * @value: the byte to store in the register
291 *
292 * For certain instructions that do not require a data byte, "NULL"
293 * should be specified for the "value" parameter. These instructions
294 * include NOP, RESTORE_FROM_EEPROM, and STORE_TO_EEPROM.
295 *
296 * A negative return value indicates an error occurred while reading
297 * the register.
298 */
Michael Hennerich0c53b9f2010-05-24 14:33:13 -0700299static s32 ad525x_write(struct i2c_client *client, u8 reg, u16 value)
Michael Hennerich4eb174b2009-12-14 18:00:15 -0800300{
301 struct dpot_data *data = i2c_get_clientdata(client);
302
303 /* Only write the instruction byte for certain commands */
304 if (reg & AD525X_I2C_CMD)
305 return i2c_smbus_write_byte(client, reg);
306
307 if (data->max_pos > 256)
308 return i2c_smbus_write_word_data(client, (reg & 0xF8) |
309 ((reg & 0x7) << 1), value);
310 else
311 /* All other registers require instruction + data bytes */
312 return i2c_smbus_write_byte_data(client, reg, value);
313}
314
315static int ad525x_probe(struct i2c_client *client,
316 const struct i2c_device_id *id)
317{
318 struct device *dev = &client->dev;
319 struct dpot_data *data;
320 int err = 0;
321
322 dev_dbg(dev, "%s\n", __func__);
323
324 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) {
325 dev_err(dev, "missing I2C functionality for this driver\n");
326 goto exit;
327 }
328
329 data = kzalloc(sizeof(struct dpot_data), GFP_KERNEL);
330 if (!data) {
331 err = -ENOMEM;
332 goto exit;
333 }
334
335 i2c_set_clientdata(client, data);
336 mutex_init(&data->update_lock);
337
338 switch (id->driver_data) {
339 case AD5258_ID:
340 data->max_pos = AD5258_MAX_POSITION;
341 err = sysfs_create_group(&dev->kobj,
342 &ad525x_group_wipers[AD525X_RDAC0]);
343 break;
344 case AD5259_ID:
345 data->max_pos = AD5259_MAX_POSITION;
346 err = sysfs_create_group(&dev->kobj,
347 &ad525x_group_wipers[AD525X_RDAC0]);
348 break;
349 case AD5251_ID:
350 data->max_pos = AD5251_MAX_POSITION;
351 err = sysfs_create_group(&dev->kobj,
352 &ad525x_group_wipers[AD525X_RDAC1]);
353 err |= sysfs_create_group(&dev->kobj,
354 &ad525x_group_wipers[AD525X_RDAC3]);
355 err |= sysfs_create_group(&dev->kobj, &ad525x_group_commands);
356 break;
357 case AD5252_ID:
358 data->max_pos = AD5252_MAX_POSITION;
359 err = sysfs_create_group(&dev->kobj,
360 &ad525x_group_wipers[AD525X_RDAC1]);
361 err |= sysfs_create_group(&dev->kobj,
362 &ad525x_group_wipers[AD525X_RDAC3]);
363 err |= sysfs_create_group(&dev->kobj, &ad525x_group_commands);
364 break;
365 case AD5253_ID:
366 data->max_pos = AD5253_MAX_POSITION;
367 err = sysfs_create_group(&dev->kobj,
368 &ad525x_group_wipers[AD525X_RDAC0]);
369 err |= sysfs_create_group(&dev->kobj,
370 &ad525x_group_wipers[AD525X_RDAC1]);
371 err |= sysfs_create_group(&dev->kobj,
372 &ad525x_group_wipers[AD525X_RDAC2]);
373 err |= sysfs_create_group(&dev->kobj,
374 &ad525x_group_wipers[AD525X_RDAC3]);
375 err |= sysfs_create_group(&dev->kobj, &ad525x_group_commands);
376 break;
377 case AD5254_ID:
378 data->max_pos = AD5254_MAX_POSITION;
379 err = sysfs_create_group(&dev->kobj,
380 &ad525x_group_wipers[AD525X_RDAC0]);
381 err |= sysfs_create_group(&dev->kobj,
382 &ad525x_group_wipers[AD525X_RDAC1]);
383 err |= sysfs_create_group(&dev->kobj,
384 &ad525x_group_wipers[AD525X_RDAC2]);
385 err |= sysfs_create_group(&dev->kobj,
386 &ad525x_group_wipers[AD525X_RDAC3]);
387 err |= sysfs_create_group(&dev->kobj, &ad525x_group_commands);
388 break;
389 case AD5255_ID:
390 data->max_pos = AD5255_MAX_POSITION;
391 err = sysfs_create_group(&dev->kobj,
392 &ad525x_group_wipers[AD525X_RDAC0]);
393 err |= sysfs_create_group(&dev->kobj,
394 &ad525x_group_wipers[AD525X_RDAC1]);
395 err |= sysfs_create_group(&dev->kobj,
396 &ad525x_group_wipers[AD525X_RDAC2]);
397 err |= sysfs_create_group(&dev->kobj, &ad525x_group_commands);
398 break;
399 default:
400 err = -ENODEV;
401 goto exit_free;
402 }
403
404 if (err) {
405 dev_err(dev, "failed to register sysfs hooks\n");
406 goto exit_free;
407 }
408
409 data->devid = id->driver_data;
410 data->rdac_mask = data->max_pos - 1;
411
412 dev_info(dev, "%s %d-Position Digital Potentiometer registered\n",
413 id->name, data->max_pos);
414
415 return 0;
416
417exit_free:
418 kfree(data);
419 i2c_set_clientdata(client, NULL);
420exit:
421 dev_err(dev, "failed to create client\n");
422 return err;
423}
424
425static int __devexit ad525x_remove(struct i2c_client *client)
426{
427 struct dpot_data *data = i2c_get_clientdata(client);
428 struct device *dev = &client->dev;
429
430 switch (data->devid) {
431 case AD5258_ID:
432 case AD5259_ID:
433 sysfs_remove_group(&dev->kobj,
434 &ad525x_group_wipers[AD525X_RDAC0]);
435 break;
436 case AD5251_ID:
437 case AD5252_ID:
438 sysfs_remove_group(&dev->kobj,
439 &ad525x_group_wipers[AD525X_RDAC1]);
440 sysfs_remove_group(&dev->kobj,
441 &ad525x_group_wipers[AD525X_RDAC3]);
442 sysfs_remove_group(&dev->kobj, &ad525x_group_commands);
443 break;
444 case AD5253_ID:
445 case AD5254_ID:
446 sysfs_remove_group(&dev->kobj,
447 &ad525x_group_wipers[AD525X_RDAC0]);
448 sysfs_remove_group(&dev->kobj,
449 &ad525x_group_wipers[AD525X_RDAC1]);
450 sysfs_remove_group(&dev->kobj,
451 &ad525x_group_wipers[AD525X_RDAC2]);
452 sysfs_remove_group(&dev->kobj,
453 &ad525x_group_wipers[AD525X_RDAC3]);
454 sysfs_remove_group(&dev->kobj, &ad525x_group_commands);
455 break;
456 case AD5255_ID:
457 sysfs_remove_group(&dev->kobj,
458 &ad525x_group_wipers[AD525X_RDAC0]);
459 sysfs_remove_group(&dev->kobj,
460 &ad525x_group_wipers[AD525X_RDAC1]);
461 sysfs_remove_group(&dev->kobj,
462 &ad525x_group_wipers[AD525X_RDAC2]);
463 sysfs_remove_group(&dev->kobj, &ad525x_group_commands);
464 break;
465 }
466
467 i2c_set_clientdata(client, NULL);
468 kfree(data);
469
470 return 0;
471}
472
473static const struct i2c_device_id ad525x_idtable[] = {
474 {"ad5258", AD5258_ID},
475 {"ad5259", AD5259_ID},
476 {"ad5251", AD5251_ID},
477 {"ad5252", AD5252_ID},
478 {"ad5253", AD5253_ID},
479 {"ad5254", AD5254_ID},
480 {"ad5255", AD5255_ID},
481 {}
482};
483
484MODULE_DEVICE_TABLE(i2c, ad525x_idtable);
485
486static struct i2c_driver ad525x_driver = {
487 .driver = {
488 .owner = THIS_MODULE,
489 .name = DRIVER_NAME,
490 },
491 .id_table = ad525x_idtable,
492 .probe = ad525x_probe,
493 .remove = __devexit_p(ad525x_remove),
494};
495
496static int __init ad525x_init(void)
497{
498 return i2c_add_driver(&ad525x_driver);
499}
500
501module_init(ad525x_init);
502
503static void __exit ad525x_exit(void)
504{
505 i2c_del_driver(&ad525x_driver);
506}
507
508module_exit(ad525x_exit);
509
510MODULE_AUTHOR("Chris Verges <chrisv@cyberswitching.com>, "
511 "Michael Hennerich <hennerich@blackfin.uclinux.org>, ");
512MODULE_DESCRIPTION("AD5258/9 digital potentiometer driver");
513MODULE_LICENSE("GPL");
514MODULE_VERSION(DRIVER_VERSION);