aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/ad525x_dpot.c
diff options
context:
space:
mode:
authorMichael Hennerich <michael.hennerich@analog.com>2010-05-24 17:33:14 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-05-25 11:07:04 -0400
commit6c536e4ce8edd61fdc4ab68e19ae164a54fc958f (patch)
tree1d09ef6de4c04a4bd597b060d668fce2eac14681 /drivers/misc/ad525x_dpot.c
parent0c53b9fbcca8870e4f4b248f4ed5fdadd43a01b6 (diff)
ad525x_dpot: add support for SPI parts
Split the bus logic out into separate files so that we can handle I2C and SPI busses independently. The new SPI bus logic brings in support for a lot more parts: AD5160, AD5161, AD5162, AD5165, AD5200, AD5201, AD5203, AD5204, AD5206, AD5207, AD5231, AD5232, AD5233, AD5235, AD5260, AD5262, AD5263, AD5290, AD5291, AD5292, AD5293, AD7376, AD8400, AD8402, AD8403, ADN2850 [randy.dunlap@oracle.com: fix ad525X_dpot build] Signed-off-by: Michael Hennerich <michael.hennerich@analog.com> Signed-off-by: Mike Frysinger <vapier@gentoo.org> Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
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);