diff options
author | Michael Hennerich <michael.hennerich@analog.com> | 2010-05-24 17:33:15 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-25 11:07:04 -0400 |
commit | e3ae68476ce0636554b5d95a33777f80ba407dc0 (patch) | |
tree | 3aa1fbefa2d573e1830914fe899f79caf90157d8 /drivers/misc | |
parent | 6c536e4ce8edd61fdc4ab68e19ae164a54fc958f (diff) |
ad525x_dpot: add support for AD524x pots
New parts supported:
AD5241, AD5242, AD5243, AD5245, AD5246, AD5247, AD5248
Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/Kconfig | 3 | ||||
-rw-r--r-- | drivers/misc/ad525x_dpot-i2c.c | 7 | ||||
-rw-r--r-- | drivers/misc/ad525x_dpot.c | 234 | ||||
-rw-r--r-- | drivers/misc/ad525x_dpot.h | 27 |
4 files changed, 175 insertions, 96 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 69e019e7d69c..90c3415dc90a 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
@@ -22,7 +22,8 @@ config AD525X_DPOT | |||
22 | AD5160, AD5161, AD5162, AD5165, AD5200, AD5201, AD5203, | 22 | AD5160, AD5161, AD5162, AD5165, AD5200, AD5201, AD5203, |
23 | AD5204, AD5206, AD5207, AD5231, AD5232, AD5233, AD5235, | 23 | AD5204, AD5206, AD5207, AD5231, AD5232, AD5233, AD5235, |
24 | AD5260, AD5262, AD5263, AD5290, AD5291, AD5292, AD5293, | 24 | AD5260, AD5262, AD5263, AD5290, AD5291, AD5292, AD5293, |
25 | AD7376, AD8400, AD8402, AD8403, ADN2850 | 25 | AD7376, AD8400, AD8402, AD8403, ADN2850, AD5241, AD5242, |
26 | AD5243, AD5245, AD5246, AD5247, AD5248 | ||
26 | digital potentiometer chips. | 27 | digital potentiometer chips. |
27 | 28 | ||
28 | See Documentation/misc-devices/ad525x_dpot.txt for the | 29 | See Documentation/misc-devices/ad525x_dpot.txt for the |
diff --git a/drivers/misc/ad525x_dpot-i2c.c b/drivers/misc/ad525x_dpot-i2c.c index 971e61d7f881..0dfad4e70f74 100644 --- a/drivers/misc/ad525x_dpot-i2c.c +++ b/drivers/misc/ad525x_dpot-i2c.c | |||
@@ -87,6 +87,13 @@ static const struct i2c_device_id ad_dpot_id[] = { | |||
87 | {"ad5253", AD5253_ID}, | 87 | {"ad5253", AD5253_ID}, |
88 | {"ad5254", AD5254_ID}, | 88 | {"ad5254", AD5254_ID}, |
89 | {"ad5255", AD5255_ID}, | 89 | {"ad5255", AD5255_ID}, |
90 | {"ad5241", AD5241_ID}, | ||
91 | {"ad5242", AD5242_ID}, | ||
92 | {"ad5243", AD5243_ID}, | ||
93 | {"ad5245", AD5245_ID}, | ||
94 | {"ad5246", AD5246_ID}, | ||
95 | {"ad5247", AD5247_ID}, | ||
96 | {"ad5248", AD5248_ID}, | ||
90 | {} | 97 | {} |
91 | }; | 98 | }; |
92 | MODULE_DEVICE_TABLE(i2c, ad_dpot_id); | 99 | MODULE_DEVICE_TABLE(i2c, ad_dpot_id); |
diff --git a/drivers/misc/ad525x_dpot.c b/drivers/misc/ad525x_dpot.c index a41c2de0eae8..35a4c4b343d4 100644 --- a/drivers/misc/ad525x_dpot.c +++ b/drivers/misc/ad525x_dpot.c | |||
@@ -37,6 +37,13 @@ | |||
37 | * AD8402 2 256 1, 10, 50, 100 | 37 | * AD8402 2 256 1, 10, 50, 100 |
38 | * AD8403 4 256 1, 10, 50, 100 | 38 | * AD8403 4 256 1, 10, 50, 100 |
39 | * ADN2850 3 512 25, 250 | 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 | ||
40 | * | 47 | * |
41 | * See Documentation/misc-devices/ad525x_dpot.txt for more info. | 48 | * See Documentation/misc-devices/ad525x_dpot.txt for more info. |
42 | * | 49 | * |
@@ -107,118 +114,169 @@ static inline int dpot_write_r8d16(struct dpot_data *dpot, u8 reg, u16 val) | |||
107 | return dpot->bdata.bops->write_r8d16(dpot->bdata.client, reg, val); | 114 | return dpot->bdata.bops->write_r8d16(dpot->bdata.client, reg, val); |
108 | } | 115 | } |
109 | 116 | ||
110 | static s32 dpot_read(struct dpot_data *dpot, u8 reg) | 117 | static s32 dpot_read_spi(struct dpot_data *dpot, u8 reg) |
111 | { | 118 | { |
112 | unsigned val = 0; | 119 | unsigned ctrl = 0; |
113 | 120 | ||
114 | if (dpot->feat & F_SPI) { | 121 | if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD))) { |
115 | if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD))) { | ||
116 | 122 | ||
117 | if (dpot->feat & F_RDACS_WONLY) | 123 | if (dpot->feat & F_RDACS_WONLY) |
118 | return dpot->rdac_cache[reg & DPOT_RDAC_MASK]; | 124 | return dpot->rdac_cache[reg & DPOT_RDAC_MASK]; |
119 | 125 | ||
120 | if (dpot->uid == DPOT_UID(AD5291_ID) || | 126 | if (dpot->uid == DPOT_UID(AD5291_ID) || |
121 | dpot->uid == DPOT_UID(AD5292_ID) || | 127 | dpot->uid == DPOT_UID(AD5292_ID) || |
122 | dpot->uid == DPOT_UID(AD5293_ID)) | 128 | dpot->uid == DPOT_UID(AD5293_ID)) |
123 | return dpot_read_r8d8(dpot, | 129 | return dpot_read_r8d8(dpot, |
124 | DPOT_AD5291_READ_RDAC << 2); | 130 | DPOT_AD5291_READ_RDAC << 2); |
125 | 131 | ||
126 | val = DPOT_SPI_READ_RDAC; | 132 | ctrl = DPOT_SPI_READ_RDAC; |
127 | } else if (reg & DPOT_ADDR_EEPROM) { | 133 | } else if (reg & DPOT_ADDR_EEPROM) { |
128 | val = DPOT_SPI_READ_EEPROM; | 134 | ctrl = DPOT_SPI_READ_EEPROM; |
129 | } | 135 | } |
130 | 136 | ||
131 | if (dpot->feat & F_SPI_16BIT) | 137 | if (dpot->feat & F_SPI_16BIT) |
132 | return dpot_read_r8d8(dpot, val); | 138 | return dpot_read_r8d8(dpot, ctrl); |
133 | else if (dpot->feat & F_SPI_24BIT) | 139 | else if (dpot->feat & F_SPI_24BIT) |
134 | return dpot_read_r8d16(dpot, val); | 140 | return dpot_read_r8d16(dpot, ctrl); |
135 | 141 | ||
136 | } else { /* I2C */ | 142 | return -EFAULT; |
143 | } | ||
137 | 144 | ||
145 | static s32 dpot_read_i2c(struct dpot_data *dpot, u8 reg) | ||
146 | { | ||
147 | unsigned ctrl = 0; | ||
148 | switch (dpot->uid) { | ||
149 | case DPOT_UID(AD5246_ID): | ||
150 | case DPOT_UID(AD5247_ID): | ||
151 | return dpot_read_d8(dpot); | ||
152 | case DPOT_UID(AD5245_ID): | ||
153 | case DPOT_UID(AD5241_ID): | ||
154 | case DPOT_UID(AD5242_ID): | ||
155 | case DPOT_UID(AD5243_ID): | ||
156 | case DPOT_UID(AD5248_ID): | ||
157 | ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ? | ||
158 | 0 : DPOT_AD5291_RDAC_AB; | ||
159 | return dpot_read_r8d8(dpot, ctrl); | ||
160 | default: | ||
138 | if ((reg & DPOT_REG_TOL) || (dpot->max_pos > 256)) | 161 | if ((reg & DPOT_REG_TOL) || (dpot->max_pos > 256)) |
139 | return dpot_read_r8d16(dpot, (reg & 0xF8) | | 162 | return dpot_read_r8d16(dpot, (reg & 0xF8) | |
140 | ((reg & 0x7) << 1)); | 163 | ((reg & 0x7) << 1)); |
141 | else | 164 | else |
142 | return dpot_read_r8d8(dpot, reg); | 165 | return dpot_read_r8d8(dpot, reg); |
143 | |||
144 | } | 166 | } |
145 | return -EFAULT; | ||
146 | } | 167 | } |
147 | 168 | ||
148 | static s32 dpot_write(struct dpot_data *dpot, u8 reg, u16 value) | 169 | static s32 dpot_read(struct dpot_data *dpot, u8 reg) |
170 | { | ||
171 | if (dpot->feat & F_SPI) | ||
172 | return dpot_read_spi(dpot, reg); | ||
173 | else | ||
174 | return dpot_read_i2c(dpot, reg); | ||
175 | } | ||
176 | |||
177 | static s32 dpot_write_spi(struct dpot_data *dpot, u8 reg, u16 value) | ||
149 | { | 178 | { |
150 | unsigned val = 0; | 179 | unsigned val = 0; |
151 | 180 | ||
152 | if (dpot->feat & F_SPI) { | 181 | if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD))) { |
153 | if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD))) { | 182 | if (dpot->feat & F_RDACS_WONLY) |
154 | if (dpot->feat & F_RDACS_WONLY) | 183 | dpot->rdac_cache[reg & DPOT_RDAC_MASK] = value; |
155 | dpot->rdac_cache[reg & DPOT_RDAC_MASK] = value; | 184 | |
156 | 185 | if (dpot->feat & F_AD_APPDATA) { | |
157 | if (dpot->feat & F_AD_APPDATA) { | 186 | if (dpot->feat & F_SPI_8BIT) { |
158 | if (dpot->feat & F_SPI_8BIT) { | 187 | val = ((reg & DPOT_RDAC_MASK) << |
159 | val = ((reg & DPOT_RDAC_MASK) << | 188 | DPOT_MAX_POS(dpot->devid)) | |
160 | DPOT_MAX_POS(dpot->devid)) | | 189 | value; |
161 | value; | 190 | return dpot_write_d8(dpot, val); |
162 | return dpot_write_d8(dpot, val); | 191 | } else if (dpot->feat & F_SPI_16BIT) { |
163 | } else if (dpot->feat & F_SPI_16BIT) { | 192 | val = ((reg & DPOT_RDAC_MASK) << |
164 | val = ((reg & DPOT_RDAC_MASK) << | 193 | DPOT_MAX_POS(dpot->devid)) | |
165 | DPOT_MAX_POS(dpot->devid)) | | 194 | value; |
166 | value; | 195 | return dpot_write_r8d8(dpot, val >> 8, |
167 | return dpot_write_r8d8(dpot, val >> 8, | 196 | val & 0xFF); |
168 | val & 0xFF); | 197 | } else |
169 | } else | 198 | BUG(); |
170 | BUG(); | 199 | } else { |
171 | } else { | 200 | if (dpot->uid == DPOT_UID(AD5291_ID) || |
172 | if (dpot->uid == DPOT_UID(AD5291_ID) || | 201 | dpot->uid == DPOT_UID(AD5292_ID) || |
173 | dpot->uid == DPOT_UID(AD5292_ID) || | 202 | dpot->uid == DPOT_UID(AD5293_ID)) |
174 | dpot->uid == DPOT_UID(AD5293_ID)) | 203 | return dpot_write_r8d8(dpot, |
175 | return dpot_write_r8d8(dpot, | 204 | (DPOT_AD5291_RDAC << 2) | |
176 | (DPOT_AD5291_RDAC << 2) | | 205 | (value >> 8), value & 0xFF); |
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 | 206 | ||
217 | } | 207 | val = DPOT_SPI_RDAC | (reg & DPOT_RDAC_MASK); |
208 | } | ||
209 | } else if (reg & DPOT_ADDR_EEPROM) { | ||
210 | val = DPOT_SPI_EEPROM | (reg & DPOT_RDAC_MASK); | ||
211 | } else if (reg & DPOT_ADDR_CMD) { | ||
212 | switch (reg) { | ||
213 | case DPOT_DEC_ALL_6DB: | ||
214 | val = DPOT_SPI_DEC_ALL_6DB; | ||
215 | break; | ||
216 | case DPOT_INC_ALL_6DB: | ||
217 | val = DPOT_SPI_INC_ALL_6DB; | ||
218 | break; | ||
219 | case DPOT_DEC_ALL: | ||
220 | val = DPOT_SPI_DEC_ALL; | ||
221 | break; | ||
222 | case DPOT_INC_ALL: | ||
223 | val = DPOT_SPI_INC_ALL; | ||
224 | break; | ||
225 | } | ||
226 | } else | ||
227 | BUG(); | ||
228 | |||
229 | if (dpot->feat & F_SPI_16BIT) | ||
230 | return dpot_write_r8d8(dpot, val, value); | ||
231 | else if (dpot->feat & F_SPI_24BIT) | ||
232 | return dpot_write_r8d16(dpot, val, value); | ||
218 | 233 | ||
219 | return -EFAULT; | 234 | return -EFAULT; |
220 | } | 235 | } |
221 | 236 | ||
237 | static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value) | ||
238 | { | ||
239 | /* Only write the instruction byte for certain commands */ | ||
240 | unsigned ctrl = 0; | ||
241 | |||
242 | switch (dpot->uid) { | ||
243 | case DPOT_UID(AD5246_ID): | ||
244 | case DPOT_UID(AD5247_ID): | ||
245 | return dpot_write_d8(dpot, value); | ||
246 | break; | ||
247 | |||
248 | case DPOT_UID(AD5245_ID): | ||
249 | case DPOT_UID(AD5241_ID): | ||
250 | case DPOT_UID(AD5242_ID): | ||
251 | case DPOT_UID(AD5243_ID): | ||
252 | case DPOT_UID(AD5248_ID): | ||
253 | ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ? 0 : DPOT_AD5291_RDAC_AB; | ||
254 | return dpot_write_r8d8(dpot, ctrl, value); | ||
255 | break; | ||
256 | |||
257 | |||
258 | default: | ||
259 | if (reg & DPOT_ADDR_CMD) | ||
260 | return dpot_write_d8(dpot, reg); | ||
261 | |||
262 | if (dpot->max_pos > 256) | ||
263 | return dpot_write_r8d16(dpot, (reg & 0xF8) | | ||
264 | ((reg & 0x7) << 1), value); | ||
265 | else | ||
266 | /* All other registers require instruction + data bytes */ | ||
267 | return dpot_write_r8d8(dpot, reg, value); | ||
268 | } | ||
269 | } | ||
270 | |||
271 | |||
272 | static s32 dpot_write(struct dpot_data *dpot, u8 reg, u16 value) | ||
273 | { | ||
274 | if (dpot->feat & F_SPI) | ||
275 | return dpot_write_spi(dpot, reg, value); | ||
276 | else | ||
277 | return dpot_write_i2c(dpot, reg, value); | ||
278 | } | ||
279 | |||
222 | /* sysfs functions */ | 280 | /* sysfs functions */ |
223 | 281 | ||
224 | static ssize_t sysfs_show_reg(struct device *dev, | 282 | static ssize_t sysfs_show_reg(struct device *dev, |
diff --git a/drivers/misc/ad525x_dpot.h b/drivers/misc/ad525x_dpot.h index 99b388e12f5f..849c5d0782b2 100644 --- a/drivers/misc/ad525x_dpot.h +++ b/drivers/misc/ad525x_dpot.h | |||
@@ -29,13 +29,14 @@ | |||
29 | 29 | ||
30 | #define F_CMD_INC (1 << 0) /* Features INC/DEC ALL, 6dB */ | 30 | #define F_CMD_INC (1 << 0) /* Features INC/DEC ALL, 6dB */ |
31 | #define F_CMD_EEP (1 << 1) /* Features EEPROM */ | 31 | #define F_CMD_EEP (1 << 1) /* Features EEPROM */ |
32 | #define F_CMD_TOL (1 << 2) /* RDACS are Read/Write + Tolerance REG */ | 32 | #define F_CMD_OTP (1 << 2) /* Features OTP */ |
33 | #define F_RDACS_RW (1 << 3) /* RDACS are Read/Write + Tolerance REG */ | 33 | #define F_CMD_TOL (1 << 3) /* RDACS feature Tolerance REG */ |
34 | #define F_RDACS_WONLY (1 << 4) /* RDACS are Write only */ | 34 | #define F_RDACS_RW (1 << 4) /* RDACS are Read/Write */ |
35 | #define F_AD_APPDATA (1 << 5) /* RDAC Address append to data */ | 35 | #define F_RDACS_WONLY (1 << 5) /* RDACS are Write only */ |
36 | #define F_SPI_8BIT (1 << 6) /* All SPI XFERS are 8-bit */ | 36 | #define F_AD_APPDATA (1 << 6) /* RDAC Address append to data */ |
37 | #define F_SPI_16BIT (1 << 7) /* All SPI XFERS are 16-bit */ | 37 | #define F_SPI_8BIT (1 << 7) /* All SPI XFERS are 8-bit */ |
38 | #define F_SPI_24BIT (1 << 8) /* All SPI XFERS are 24-bit */ | 38 | #define F_SPI_16BIT (1 << 8) /* All SPI XFERS are 16-bit */ |
39 | #define F_SPI_24BIT (1 << 9) /* All SPI XFERS are 24-bit */ | ||
39 | 40 | ||
40 | #define F_RDACS_RW_TOL (F_RDACS_RW | F_CMD_EEP | F_CMD_TOL) | 41 | #define F_RDACS_RW_TOL (F_RDACS_RW | F_CMD_EEP | F_CMD_TOL) |
41 | #define F_RDACS_RW_EEP (F_RDACS_RW | F_CMD_EEP) | 42 | #define F_RDACS_RW_EEP (F_RDACS_RW | F_CMD_EEP) |
@@ -104,6 +105,15 @@ enum dpot_devid { | |||
104 | BRDAC0 | BRDAC1 | BRDAC2, 8, 31), | 105 | BRDAC0 | BRDAC1 | BRDAC2, 8, 31), |
105 | ADN2850_ID = DPOT_CONF(F_RDACS_RW_EEP | F_CMD_INC | F_SPI_24BIT, | 106 | ADN2850_ID = DPOT_CONF(F_RDACS_RW_EEP | F_CMD_INC | F_SPI_24BIT, |
106 | BRDAC0 | BRDAC1, 10, 32), | 107 | BRDAC0 | BRDAC1, 10, 32), |
108 | AD5241_ID = DPOT_CONF(F_RDACS_RW, BRDAC0, 8, 33), | ||
109 | AD5242_ID = DPOT_CONF(F_RDACS_RW, BRDAC0 | BRDAC1, 8, 34), | ||
110 | AD5243_ID = DPOT_CONF(F_RDACS_RW, BRDAC0 | BRDAC1, 8, 35), | ||
111 | AD5245_ID = DPOT_CONF(F_RDACS_RW, BRDAC0, 8, 36), | ||
112 | AD5246_ID = DPOT_CONF(F_RDACS_RW, BRDAC0, 7, 37), | ||
113 | AD5247_ID = DPOT_CONF(F_RDACS_RW, BRDAC0, 7, 38), | ||
114 | AD5248_ID = DPOT_CONF(F_RDACS_RW, BRDAC0 | BRDAC1, 8, 39), | ||
115 | |||
116 | |||
107 | }; | 117 | }; |
108 | 118 | ||
109 | #define DPOT_RDAC0 0 | 119 | #define DPOT_RDAC0 0 |
@@ -146,6 +156,9 @@ enum dpot_devid { | |||
146 | #define DPOT_AD5291_RDAC 0x01 | 156 | #define DPOT_AD5291_RDAC 0x01 |
147 | #define DPOT_AD5291_READ_RDAC 0x02 | 157 | #define DPOT_AD5291_READ_RDAC 0x02 |
148 | 158 | ||
159 | /* AD524x use special commands */ | ||
160 | #define DPOT_AD5291_RDAC_AB 0x80 | ||
161 | |||
149 | struct dpot_data; | 162 | struct dpot_data; |
150 | 163 | ||
151 | struct ad_dpot_bus_ops { | 164 | struct ad_dpot_bus_ops { |