aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/ad525x_dpot.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/ad525x_dpot.c')
-rw-r--r--drivers/misc/ad525x_dpot.c629
1 files changed, 313 insertions, 316 deletions
diff --git a/drivers/misc/ad525x_dpot.c b/drivers/misc/ad525x_dpot.c
index ce92088bf0b8..a41c2de0eae8 100644
--- a/drivers/misc/ad525x_dpot.c
+++ b/drivers/misc/ad525x_dpot.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * ad525x_dpot: Driver for the Analog Devices AD525x digital potentiometers 2 * ad525x_dpot: Driver for the Analog Devices digital potentiometers
3 * Copyright (c) 2009 Analog Devices, Inc. 3 * Copyright (c) 2009-2010 Analog Devices, Inc.
4 * Author: Michael Hennerich <hennerich@blackfin.uclinux.org> 4 * Author: Michael Hennerich <hennerich@blackfin.uclinux.org>
5 * 5 *
6 * DEVID #Wipers #Positions Resistor Options (kOhm) 6 * DEVID #Wipers #Positions Resistor Options (kOhm)
@@ -11,6 +11,32 @@
11 * AD5255 3 512 25, 250 11 * AD5255 3 512 25, 250
12 * AD5253 4 64 1, 10, 50, 100 12 * AD5253 4 64 1, 10, 50, 100
13 * AD5254 4 256 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
14 * 40 *
15 * See Documentation/misc-devices/ad525x_dpot.txt for more info. 41 * See Documentation/misc-devices/ad525x_dpot.txt for more info.
16 * 42 *
@@ -28,77 +54,182 @@
28#include <linux/device.h> 54#include <linux/device.h>
29#include <linux/kernel.h> 55#include <linux/kernel.h>
30#include <linux/init.h> 56#include <linux/init.h>
31#include <linux/slab.h>
32#include <linux/i2c.h>
33#include <linux/delay.h> 57#include <linux/delay.h>
58#include <linux/slab.h>
34 59
35#define DRIVER_NAME "ad525x_dpot" 60#define DRIVER_VERSION "0.2"
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 61
48#define AD5258_MAX_POSITION 64 62#include "ad525x_dpot.h"
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);
78static s32 ad525x_write(struct i2c_client *client, u8 reg, u16 value);
79 63
80/* 64/*
81 * Client data (each client gets its own) 65 * Client data (each client gets its own)
82 */ 66 */
83 67
84struct dpot_data { 68struct dpot_data {
69 struct ad_dpot_bus_data bdata;
85 struct mutex update_lock; 70 struct mutex update_lock;
86 unsigned rdac_mask; 71 unsigned rdac_mask;
87 unsigned max_pos; 72 unsigned max_pos;
88 unsigned devid; 73 unsigned long devid;
74 unsigned uid;
75 unsigned feat;
76 unsigned wipers;
77 u16 rdac_cache[8];
89}; 78};
90 79
80static inline int dpot_read_d8(struct dpot_data *dpot)
81{
82 return dpot->bdata.bops->read_d8(dpot->bdata.client);
83}
84
85static 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
90static 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
95static 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
100static 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
105static 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
110static 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
148static 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
91/* sysfs functions */ 222/* sysfs functions */
92 223
93static ssize_t sysfs_show_reg(struct device *dev, 224static ssize_t sysfs_show_reg(struct device *dev,
94 struct device_attribute *attr, char *buf, u32 reg) 225 struct device_attribute *attr,
226 char *buf, u32 reg)
95{ 227{
96 struct i2c_client *client = to_i2c_client(dev); 228 struct dpot_data *data = dev_get_drvdata(dev);
97 struct dpot_data *data = i2c_get_clientdata(client);
98 s32 value; 229 s32 value;
99 230
100 mutex_lock(&data->update_lock); 231 mutex_lock(&data->update_lock);
101 value = ad525x_read(client, reg); 232 value = dpot_read(data, reg);
102 mutex_unlock(&data->update_lock); 233 mutex_unlock(&data->update_lock);
103 234
104 if (value < 0) 235 if (value < 0)
@@ -111,7 +242,7 @@ static ssize_t sysfs_show_reg(struct device *dev,
111 * datasheet (Rev. A) for more details. 242 * datasheet (Rev. A) for more details.
112 */ 243 */
113 244
114 if (reg & AD525X_REG_TOL) 245 if (reg & DPOT_REG_TOL)
115 return sprintf(buf, "0x%04x\n", value & 0xFFFF); 246 return sprintf(buf, "0x%04x\n", value & 0xFFFF);
116 else 247 else
117 return sprintf(buf, "%u\n", value & data->rdac_mask); 248 return sprintf(buf, "%u\n", value & data->rdac_mask);
@@ -121,8 +252,7 @@ static ssize_t sysfs_set_reg(struct device *dev,
121 struct device_attribute *attr, 252 struct device_attribute *attr,
122 const char *buf, size_t count, u32 reg) 253 const char *buf, size_t count, u32 reg)
123{ 254{
124 struct i2c_client *client = to_i2c_client(dev); 255 struct dpot_data *data = dev_get_drvdata(dev);
125 struct dpot_data *data = i2c_get_clientdata(client);
126 unsigned long value; 256 unsigned long value;
127 int err; 257 int err;
128 258
@@ -134,8 +264,8 @@ static ssize_t sysfs_set_reg(struct device *dev,
134 value = data->rdac_mask; 264 value = data->rdac_mask;
135 265
136 mutex_lock(&data->update_lock); 266 mutex_lock(&data->update_lock);
137 ad525x_write(client, reg, value); 267 dpot_write(data, reg, value);
138 if (reg & AD525X_I2C_EEPROM) 268 if (reg & DPOT_ADDR_EEPROM)
139 msleep(26); /* Sleep while the EEPROM updates */ 269 msleep(26); /* Sleep while the EEPROM updates */
140 mutex_unlock(&data->update_lock); 270 mutex_unlock(&data->update_lock);
141 271
@@ -146,11 +276,10 @@ static ssize_t sysfs_do_cmd(struct device *dev,
146 struct device_attribute *attr, 276 struct device_attribute *attr,
147 const char *buf, size_t count, u32 reg) 277 const char *buf, size_t count, u32 reg)
148{ 278{
149 struct i2c_client *client = to_i2c_client(dev); 279 struct dpot_data *data = dev_get_drvdata(dev);
150 struct dpot_data *data = i2c_get_clientdata(client);
151 280
152 mutex_lock(&data->update_lock); 281 mutex_lock(&data->update_lock);
153 ad525x_write(client, reg, 0); 282 dpot_write(data, reg, 0);
154 mutex_unlock(&data->update_lock); 283 mutex_unlock(&data->update_lock);
155 284
156 return count; 285 return count;
@@ -182,51 +311,58 @@ static DEVICE_ATTR(name, S_IWUSR | S_IRUGO, show_##name, set_##name);
182DPOT_DEVICE_SHOW(name, reg) \ 311DPOT_DEVICE_SHOW(name, reg) \
183static DEVICE_ATTR(name, S_IWUSR | S_IRUGO, show_##name, NULL); 312static DEVICE_ATTR(name, S_IWUSR | S_IRUGO, show_##name, NULL);
184 313
185DPOT_DEVICE_SHOW_SET(rdac0, AD525X_I2C_RDAC | AD525X_RDAC0); 314DPOT_DEVICE_SHOW_SET(rdac0, DPOT_ADDR_RDAC | DPOT_RDAC0);
186DPOT_DEVICE_SHOW_SET(eeprom0, AD525X_I2C_EEPROM | AD525X_RDAC0); 315DPOT_DEVICE_SHOW_SET(eeprom0, DPOT_ADDR_EEPROM | DPOT_RDAC0);
187DPOT_DEVICE_SHOW_ONLY(tolerance0, AD525X_I2C_EEPROM | AD525X_TOL_RDAC0); 316DPOT_DEVICE_SHOW_ONLY(tolerance0, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC0);
188 317
189DPOT_DEVICE_SHOW_SET(rdac1, AD525X_I2C_RDAC | AD525X_RDAC1); 318DPOT_DEVICE_SHOW_SET(rdac1, DPOT_ADDR_RDAC | DPOT_RDAC1);
190DPOT_DEVICE_SHOW_SET(eeprom1, AD525X_I2C_EEPROM | AD525X_RDAC1); 319DPOT_DEVICE_SHOW_SET(eeprom1, DPOT_ADDR_EEPROM | DPOT_RDAC1);
191DPOT_DEVICE_SHOW_ONLY(tolerance1, AD525X_I2C_EEPROM | AD525X_TOL_RDAC1); 320DPOT_DEVICE_SHOW_ONLY(tolerance1, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC1);
192 321
193DPOT_DEVICE_SHOW_SET(rdac2, AD525X_I2C_RDAC | AD525X_RDAC2); 322DPOT_DEVICE_SHOW_SET(rdac2, DPOT_ADDR_RDAC | DPOT_RDAC2);
194DPOT_DEVICE_SHOW_SET(eeprom2, AD525X_I2C_EEPROM | AD525X_RDAC2); 323DPOT_DEVICE_SHOW_SET(eeprom2, DPOT_ADDR_EEPROM | DPOT_RDAC2);
195DPOT_DEVICE_SHOW_ONLY(tolerance2, AD525X_I2C_EEPROM | AD525X_TOL_RDAC2); 324DPOT_DEVICE_SHOW_ONLY(tolerance2, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC2);
196 325
197DPOT_DEVICE_SHOW_SET(rdac3, AD525X_I2C_RDAC | AD525X_RDAC3); 326DPOT_DEVICE_SHOW_SET(rdac3, DPOT_ADDR_RDAC | DPOT_RDAC3);
198DPOT_DEVICE_SHOW_SET(eeprom3, AD525X_I2C_EEPROM | AD525X_RDAC3); 327DPOT_DEVICE_SHOW_SET(eeprom3, DPOT_ADDR_EEPROM | DPOT_RDAC3);
199DPOT_DEVICE_SHOW_ONLY(tolerance3, AD525X_I2C_EEPROM | AD525X_TOL_RDAC3); 328DPOT_DEVICE_SHOW_ONLY(tolerance3, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC3);
200 329
201static struct attribute *ad525x_attributes_wipers[4][4] = { 330DPOT_DEVICE_SHOW_SET(rdac4, DPOT_ADDR_RDAC | DPOT_RDAC4);
202 { 331DPOT_DEVICE_SHOW_SET(eeprom4, DPOT_ADDR_EEPROM | DPOT_RDAC4);
203 &dev_attr_rdac0.attr, 332DPOT_DEVICE_SHOW_ONLY(tolerance4, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC4);
204 &dev_attr_eeprom0.attr, 333
205 &dev_attr_tolerance0.attr, 334DPOT_DEVICE_SHOW_SET(rdac5, DPOT_ADDR_RDAC | DPOT_RDAC5);
206 NULL 335DPOT_DEVICE_SHOW_SET(eeprom5, DPOT_ADDR_EEPROM | DPOT_RDAC5);
207 }, { 336DPOT_DEVICE_SHOW_ONLY(tolerance5, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC5);
208 &dev_attr_rdac1.attr, 337
209 &dev_attr_eeprom1.attr, 338static const struct attribute *dpot_attrib_wipers[] = {
210 &dev_attr_tolerance1.attr, 339 &dev_attr_rdac0.attr,
211 NULL 340 &dev_attr_rdac1.attr,
212 }, { 341 &dev_attr_rdac2.attr,
213 &dev_attr_rdac2.attr, 342 &dev_attr_rdac3.attr,
214 &dev_attr_eeprom2.attr, 343 &dev_attr_rdac4.attr,
215 &dev_attr_tolerance2.attr, 344 &dev_attr_rdac5.attr,
216 NULL 345 NULL
217 }, { 346};
218 &dev_attr_rdac3.attr, 347
219 &dev_attr_eeprom3.attr, 348static const struct attribute *dpot_attrib_eeprom[] = {
220 &dev_attr_tolerance3.attr, 349 &dev_attr_eeprom0.attr,
221 NULL 350 &dev_attr_eeprom1.attr,
222 } 351 &dev_attr_eeprom2.attr,
352 &dev_attr_eeprom3.attr,
353 &dev_attr_eeprom4.attr,
354 &dev_attr_eeprom5.attr,
355 NULL
223}; 356};
224 357
225static const struct attribute_group ad525x_group_wipers[] = { 358static const struct attribute *dpot_attrib_tolerance[] = {
226 {.attrs = ad525x_attributes_wipers[AD525X_RDAC0]}, 359 &dev_attr_tolerance0.attr,
227 {.attrs = ad525x_attributes_wipers[AD525X_RDAC1]}, 360 &dev_attr_tolerance1.attr,
228 {.attrs = ad525x_attributes_wipers[AD525X_RDAC2]}, 361 &dev_attr_tolerance2.attr,
229 {.attrs = ad525x_attributes_wipers[AD525X_RDAC3]}, 362 &dev_attr_tolerance3.attr,
363 &dev_attr_tolerance4.attr,
364 &dev_attr_tolerance5.attr,
365 NULL
230}; 366};
231 367
232/* ------------------------------------------------------------------------- */ 368/* ------------------------------------------------------------------------- */
@@ -240,10 +376,10 @@ set_##_name(struct device *dev, \
240} \ 376} \
241static DEVICE_ATTR(_name, S_IWUSR | S_IRUGO, NULL, set_##_name); 377static DEVICE_ATTR(_name, S_IWUSR | S_IRUGO, NULL, set_##_name);
242 378
243DPOT_DEVICE_DO_CMD(inc_all, AD525X_INC_ALL); 379DPOT_DEVICE_DO_CMD(inc_all, DPOT_INC_ALL);
244DPOT_DEVICE_DO_CMD(dec_all, AD525X_DEC_ALL); 380DPOT_DEVICE_DO_CMD(dec_all, DPOT_DEC_ALL);
245DPOT_DEVICE_DO_CMD(inc_all_6db, AD525X_INC_ALL_6DB); 381DPOT_DEVICE_DO_CMD(inc_all_6db, DPOT_INC_ALL_6DB);
246DPOT_DEVICE_DO_CMD(dec_all_6db, AD525X_DEC_ALL_6DB); 382DPOT_DEVICE_DO_CMD(dec_all_6db, DPOT_DEC_ALL_6DB);
247 383
248static struct attribute *ad525x_attributes_commands[] = { 384static struct attribute *ad525x_attributes_commands[] = {
249 &dev_attr_inc_all.attr, 385 &dev_attr_inc_all.attr,
@@ -257,74 +393,44 @@ static const struct attribute_group ad525x_group_commands = {
257 .attrs = ad525x_attributes_commands, 393 .attrs = ad525x_attributes_commands,
258}; 394};
259 395
260/* ------------------------------------------------------------------------- */ 396__devinit int ad_dpot_add_files(struct device *dev,
261 397 unsigned features, unsigned rdac)
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{ 398{
276 struct dpot_data *data = i2c_get_clientdata(client); 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]);
277 407
278 if ((reg & AD525X_REG_TOL) || (data->max_pos > 256)) 408 if (err)
279 return i2c_smbus_read_word_data(client, (reg & 0xF8) | 409 dev_err(dev, "failed to register sysfs hooks for RDAC%d\n",
280 ((reg & 0x7) << 1)); 410 rdac);
281 else 411
282 return i2c_smbus_read_byte_data(client, reg); 412 return err;
283} 413}
284 414
285/** 415inline void ad_dpot_remove_files(struct device *dev,
286 * ad525x_write - store the given value in the specified register on 416 unsigned features, unsigned rdac)
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 */
299static s32 ad525x_write(struct i2c_client *client, u8 reg, u16 value)
300{ 417{
301 struct dpot_data *data = i2c_get_clientdata(client); 418 sysfs_remove_file(&dev->kobj,
302 419 dpot_attrib_wipers[rdac]);
303 /* Only write the instruction byte for certain commands */ 420 if (features & F_CMD_EEP)
304 if (reg & AD525X_I2C_CMD) 421 sysfs_remove_file(&dev->kobj,
305 return i2c_smbus_write_byte(client, reg); 422 dpot_attrib_eeprom[rdac]);
306 423 if (features & F_CMD_TOL)
307 if (data->max_pos > 256) 424 sysfs_remove_file(&dev->kobj,
308 return i2c_smbus_write_word_data(client, (reg & 0xF8) | 425 dpot_attrib_tolerance[rdac]);
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} 426}
314 427
315static int ad525x_probe(struct i2c_client *client, 428__devinit int ad_dpot_probe(struct device *dev,
316 const struct i2c_device_id *id) 429 struct ad_dpot_bus_data *bdata, const struct ad_dpot_id *id)
317{ 430{
318 struct device *dev = &client->dev;
319 struct dpot_data *data;
320 int err = 0;
321
322 dev_dbg(dev, "%s\n", __func__);
323 431
324 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) { 432 struct dpot_data *data;
325 dev_err(dev, "missing I2C functionality for this driver\n"); 433 int i, err = 0;
326 goto exit;
327 }
328 434
329 data = kzalloc(sizeof(struct dpot_data), GFP_KERNEL); 435 data = kzalloc(sizeof(struct dpot_data), GFP_KERNEL);
330 if (!data) { 436 if (!data) {
@@ -332,183 +438,74 @@ static int ad525x_probe(struct i2c_client *client,
332 goto exit; 438 goto exit;
333 } 439 }
334 440
335 i2c_set_clientdata(client, data); 441 dev_set_drvdata(dev, data);
336 mutex_init(&data->update_lock); 442 mutex_init(&data->update_lock);
337 443
338 switch (id->driver_data) { 444 data->bdata = *bdata;
339 case AD5258_ID: 445 data->devid = id->devid;
340 data->max_pos = AD5258_MAX_POSITION; 446
341 err = sysfs_create_group(&dev->kobj, 447 data->max_pos = 1 << DPOT_MAX_POS(data->devid);
342 &ad525x_group_wipers[AD525X_RDAC0]); 448 data->rdac_mask = data->max_pos - 1;
343 break; 449 data->feat = DPOT_FEAT(data->devid);
344 case AD5259_ID: 450 data->uid = DPOT_UID(data->devid);
345 data->max_pos = AD5259_MAX_POSITION; 451 data->wipers = DPOT_WIPERS(data->devid);
346 err = sysfs_create_group(&dev->kobj, 452
347 &ad525x_group_wipers[AD525X_RDAC0]); 453 for (i = DPOT_RDAC0; i <= DPOT_RDAC5; i++)
348 break; 454 if (data->wipers & (1 << i)) {
349 case AD5251_ID: 455 err = ad_dpot_add_files(dev, data->feat, i);
350 data->max_pos = AD5251_MAX_POSITION; 456 if (err)
351 err = sysfs_create_group(&dev->kobj, 457 goto exit_remove_files;
352 &ad525x_group_wipers[AD525X_RDAC1]); 458 /* power-up midscale */
353 err |= sysfs_create_group(&dev->kobj, 459 if (data->feat & F_RDACS_WONLY)
354 &ad525x_group_wipers[AD525X_RDAC3]); 460 data->rdac_cache[i] = data->max_pos / 2;
355 err |= sysfs_create_group(&dev->kobj, &ad525x_group_commands); 461 }
356 break; 462
357 case AD5252_ID: 463 if (data->feat & F_CMD_INC)
358 data->max_pos = AD5252_MAX_POSITION; 464 err = sysfs_create_group(&dev->kobj, &ad525x_group_commands);
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 465
404 if (err) { 466 if (err) {
405 dev_err(dev, "failed to register sysfs hooks\n"); 467 dev_err(dev, "failed to register sysfs hooks\n");
406 goto exit_free; 468 goto exit_free;
407 } 469 }
408 470
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", 471 dev_info(dev, "%s %d-Position Digital Potentiometer registered\n",
413 id->name, data->max_pos); 472 id->name, data->max_pos);
414 473
415 return 0; 474 return 0;
416 475
476exit_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
417exit_free: 481exit_free:
418 kfree(data); 482 kfree(data);
419 i2c_set_clientdata(client, NULL); 483 dev_set_drvdata(dev, NULL);
420exit: 484exit:
421 dev_err(dev, "failed to create client\n"); 485 dev_err(dev, "failed to create client for %s ID 0x%lX\n",
486 id->name, id->devid);
422 return err; 487 return err;
423} 488}
489EXPORT_SYMBOL(ad_dpot_probe);
424 490
425static int __devexit ad525x_remove(struct i2c_client *client) 491__devexit int ad_dpot_remove(struct device *dev)
426{ 492{
427 struct dpot_data *data = i2c_get_clientdata(client); 493 struct dpot_data *data = dev_get_drvdata(dev);
428 struct device *dev = &client->dev; 494 int i;
429 495
430 switch (data->devid) { 496 for (i = DPOT_RDAC0; i <= DPOT_RDAC5; i++)
431 case AD5258_ID: 497 if (data->wipers & (1 << i))
432 case AD5259_ID: 498 ad_dpot_remove_files(dev, data->feat, i);
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 499
467 i2c_set_clientdata(client, NULL);
468 kfree(data); 500 kfree(data);
469 501
470 return 0; 502 return 0;
471} 503}
504EXPORT_SYMBOL(ad_dpot_remove);
472 505
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 506
510MODULE_AUTHOR("Chris Verges <chrisv@cyberswitching.com>, " 507MODULE_AUTHOR("Chris Verges <chrisv@cyberswitching.com>, "
511 "Michael Hennerich <hennerich@blackfin.uclinux.org>, "); 508 "Michael Hennerich <hennerich@blackfin.uclinux.org>");
512MODULE_DESCRIPTION("AD5258/9 digital potentiometer driver"); 509MODULE_DESCRIPTION("Digital potentiometer driver");
513MODULE_LICENSE("GPL"); 510MODULE_LICENSE("GPL");
514MODULE_VERSION(DRIVER_VERSION); 511MODULE_VERSION(DRIVER_VERSION);