Blame view

drivers/misc/ad525x_dpot.c 20.2 KB
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
1
  /*
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
2
3
   * ad525x_dpot: Driver for the Analog Devices digital potentiometers
   * Copyright (c) 2009-2010 Analog Devices, Inc.
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
4
5
6
7
8
9
10
11
12
13
   * Author: Michael Hennerich <hennerich@blackfin.uclinux.org>
   *
   * DEVID		#Wipers		#Positions 	Resistor Options (kOhm)
   * AD5258		1		64		1, 10, 50, 100
   * AD5259		1		256		5, 10, 50, 100
   * AD5251		2		64		1, 10, 50, 100
   * AD5252		2		256		1, 10, 50, 100
   * AD5255		3		512		25, 250
   * AD5253		4		64		1, 10, 50, 100
   * AD5254		4		256		1, 10, 50, 100
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
   * AD5160		1		256		5, 10, 50, 100
   * AD5161		1		256		5, 10, 50, 100
   * AD5162		2		256		2.5, 10, 50, 100
   * AD5165		1		256		100
   * AD5200		1		256		10, 50
   * AD5201		1		33		10, 50
   * AD5203		4		64		10, 100
   * AD5204		4		256		10, 50, 100
   * AD5206		6		256		10, 50, 100
   * AD5207		2		256		10, 50, 100
   * AD5231		1		1024		10, 50, 100
   * AD5232		2		256		10, 50, 100
   * AD5233		4		64		10, 50, 100
   * AD5235		2		1024		25, 250
   * AD5260		1		256		20, 50, 200
   * AD5262		2		256		20, 50, 200
   * AD5263		4		256		20, 50, 200
   * AD5290		1		256		10, 50, 100
a4bd39495   Michael Hennerich   drivers/misc/ad52...
32
33
34
   * AD5291		1		256		20, 50, 100  (20-TP)
   * AD5292		1		1024		20, 50, 100  (20-TP)
   * AD5293		1		1024		20, 50, 100
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
35
36
37
38
39
   * AD7376		1		128		10, 50, 100, 1M
   * AD8400		1		256		1, 10, 50, 100
   * AD8402		2		256		1, 10, 50, 100
   * AD8403		4		256		1, 10, 50, 100
   * ADN2850		3		512		25, 250
e3ae68476   Michael Hennerich   ad525x_dpot: add ...
40
41
42
43
44
45
46
   * AD5241		1		256		10, 100, 1M
   * AD5246		1		128		5, 10, 50, 100
   * AD5247		1		128		5, 10, 50, 100
   * AD5245		1		256		5, 10, 50, 100
   * AD5243		2		256		2.5, 10, 50, 100
   * AD5248		2		256		2.5, 10, 50, 100
   * AD5242		2		256		20, 50, 200
c74cba610   Michael Hennerich   ad525x_dpot: add ...
47
48
49
   * AD5280		1		256		20, 50, 200
   * AD5282		2		256		20, 50, 200
   * ADN2860		3		512		25, 250
59592d0cc   Michael Hennerich   ad525x_dpot: add ...
50
51
52
53
54
   * AD5273		1		64		1, 10, 50, 100 (OTP)
   * AD5171		1		64		5, 10, 50, 100 (OTP)
   * AD5170		1		256		2.5, 10, 50, 100 (OTP)
   * AD5172		2		256		2.5, 10, 50, 100 (OTP)
   * AD5173		2		256		2.5, 10, 50, 100 (OTP)
a4bd39495   Michael Hennerich   drivers/misc/ad52...
55
56
57
58
   * AD5270		1		1024		20, 50, 100 (50-TP)
   * AD5271		1		256		20, 50, 100 (50-TP)
   * AD5272		1		1024		20, 50, 100 (50-TP)
   * AD5274		1		256		20, 50, 100 (50-TP)
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
59
60
61
62
63
64
65
66
   *
   * See Documentation/misc-devices/ad525x_dpot.txt for more info.
   *
   * derived from ad5258.c
   * Copyright (c) 2009 Cyber Switching, Inc.
   * Author: Chris Verges <chrisv@cyberswitching.com>
   *
   * derived from ad5252.c
7f3379de9   Michael Hennerich   misc: ad525x_dpot...
67
   * Copyright (c) 2006-2011 Michael Hennerich <hennerich@blackfin.uclinux.org>
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
68
69
70
71
72
73
74
75
   *
   * Licensed under the GPL-2 or later.
   */
  
  #include <linux/module.h>
  #include <linux/device.h>
  #include <linux/kernel.h>
  #include <linux/init.h>
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
76
  #include <linux/delay.h>
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
77
  #include <linux/slab.h>
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
78

6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
79
  #include "ad525x_dpot.h"
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
80
81
82
83
84
85
  
  /*
   * Client data (each client gets its own)
   */
  
  struct dpot_data {
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
86
  	struct ad_dpot_bus_data	bdata;
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
87
88
89
  	struct mutex update_lock;
  	unsigned rdac_mask;
  	unsigned max_pos;
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
90
91
92
93
  	unsigned long devid;
  	unsigned uid;
  	unsigned feat;
  	unsigned wipers;
59592d0cc   Michael Hennerich   ad525x_dpot: add ...
94
95
  	u16 rdac_cache[MAX_RDACS];
  	DECLARE_BITMAP(otp_en_mask, MAX_RDACS);
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
96
  };
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
  static inline int dpot_read_d8(struct dpot_data *dpot)
  {
  	return dpot->bdata.bops->read_d8(dpot->bdata.client);
  }
  
  static inline int dpot_read_r8d8(struct dpot_data *dpot, u8 reg)
  {
  	return dpot->bdata.bops->read_r8d8(dpot->bdata.client, reg);
  }
  
  static inline int dpot_read_r8d16(struct dpot_data *dpot, u8 reg)
  {
  	return dpot->bdata.bops->read_r8d16(dpot->bdata.client, reg);
  }
  
  static inline int dpot_write_d8(struct dpot_data *dpot, u8 val)
  {
  	return dpot->bdata.bops->write_d8(dpot->bdata.client, val);
  }
  
  static inline int dpot_write_r8d8(struct dpot_data *dpot, u8 reg, u16 val)
  {
  	return dpot->bdata.bops->write_r8d8(dpot->bdata.client, reg, val);
  }
  
  static inline int dpot_write_r8d16(struct dpot_data *dpot, u8 reg, u16 val)
  {
  	return dpot->bdata.bops->write_r8d16(dpot->bdata.client, reg, val);
  }
e3ae68476   Michael Hennerich   ad525x_dpot: add ...
126
  static s32 dpot_read_spi(struct dpot_data *dpot, u8 reg)
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
127
  {
e3ae68476   Michael Hennerich   ad525x_dpot: add ...
128
  	unsigned ctrl = 0;
a4bd39495   Michael Hennerich   drivers/misc/ad52...
129
  	int value;
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
130

e3ae68476   Michael Hennerich   ad525x_dpot: add ...
131
  	if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD))) {
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
132

e3ae68476   Michael Hennerich   ad525x_dpot: add ...
133
134
  		if (dpot->feat & F_RDACS_WONLY)
  			return dpot->rdac_cache[reg & DPOT_RDAC_MASK];
e3ae68476   Michael Hennerich   ad525x_dpot: add ...
135
136
  		if (dpot->uid == DPOT_UID(AD5291_ID) ||
  			dpot->uid == DPOT_UID(AD5292_ID) ||
a4bd39495   Michael Hennerich   drivers/misc/ad52...
137
138
139
  			dpot->uid == DPOT_UID(AD5293_ID)) {
  
  			value = dpot_read_r8d8(dpot,
e3ae68476   Michael Hennerich   ad525x_dpot: add ...
140
  				DPOT_AD5291_READ_RDAC << 2);
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
141

a4bd39495   Michael Hennerich   drivers/misc/ad52...
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
  			if (dpot->uid == DPOT_UID(AD5291_ID))
  				value = value >> 2;
  
  			return value;
  		} else if (dpot->uid == DPOT_UID(AD5270_ID) ||
  			dpot->uid == DPOT_UID(AD5271_ID)) {
  
  			value = dpot_read_r8d8(dpot,
  				DPOT_AD5270_1_2_4_READ_RDAC << 2);
  
  			if (value < 0)
  				return value;
  
  			if (dpot->uid == DPOT_UID(AD5271_ID))
  				value = value >> 2;
  
  			return value;
  		}
e3ae68476   Michael Hennerich   ad525x_dpot: add ...
160
161
162
163
  		ctrl = DPOT_SPI_READ_RDAC;
  	} else if (reg & DPOT_ADDR_EEPROM) {
  		ctrl = DPOT_SPI_READ_EEPROM;
  	}
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
164

e3ae68476   Michael Hennerich   ad525x_dpot: add ...
165
166
167
168
  	if (dpot->feat & F_SPI_16BIT)
  		return dpot_read_r8d8(dpot, ctrl);
  	else if (dpot->feat & F_SPI_24BIT)
  		return dpot_read_r8d16(dpot, ctrl);
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
169

e3ae68476   Michael Hennerich   ad525x_dpot: add ...
170
171
  	return -EFAULT;
  }
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
172

e3ae68476   Michael Hennerich   ad525x_dpot: add ...
173
174
  static s32 dpot_read_i2c(struct dpot_data *dpot, u8 reg)
  {
a4bd39495   Michael Hennerich   drivers/misc/ad52...
175
  	int value;
e3ae68476   Michael Hennerich   ad525x_dpot: add ...
176
177
178
179
180
181
182
183
184
185
  	unsigned ctrl = 0;
  	switch (dpot->uid) {
  	case DPOT_UID(AD5246_ID):
  	case DPOT_UID(AD5247_ID):
  		return dpot_read_d8(dpot);
  	case DPOT_UID(AD5245_ID):
  	case DPOT_UID(AD5241_ID):
  	case DPOT_UID(AD5242_ID):
  	case DPOT_UID(AD5243_ID):
  	case DPOT_UID(AD5248_ID):
c74cba610   Michael Hennerich   ad525x_dpot: add ...
186
187
  	case DPOT_UID(AD5280_ID):
  	case DPOT_UID(AD5282_ID):
e3ae68476   Michael Hennerich   ad525x_dpot: add ...
188
  		ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
5f400cf40   Michael Hennerich   drivers/misc/ad52...
189
  			0 : DPOT_AD5282_RDAC_AB;
e3ae68476   Michael Hennerich   ad525x_dpot: add ...
190
  		return dpot_read_r8d8(dpot, ctrl);
59592d0cc   Michael Hennerich   ad525x_dpot: add ...
191
192
193
194
195
196
197
  	case DPOT_UID(AD5170_ID):
  	case DPOT_UID(AD5171_ID):
  	case DPOT_UID(AD5273_ID):
  			return dpot_read_d8(dpot);
  	case DPOT_UID(AD5172_ID):
  	case DPOT_UID(AD5173_ID):
  		ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
5f400cf40   Michael Hennerich   drivers/misc/ad52...
198
  			0 : DPOT_AD5172_3_A0;
59592d0cc   Michael Hennerich   ad525x_dpot: add ...
199
  		return dpot_read_r8d8(dpot, ctrl);
a4bd39495   Michael Hennerich   drivers/misc/ad52...
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
  	case DPOT_UID(AD5272_ID):
  	case DPOT_UID(AD5274_ID):
  			dpot_write_r8d8(dpot,
  				(DPOT_AD5270_1_2_4_READ_RDAC << 2), 0);
  
  			value = dpot_read_r8d16(dpot,
  				DPOT_AD5270_1_2_4_RDAC << 2);
  
  			if (value < 0)
  				return value;
  			/*
  			 * AD5272/AD5274 returns high byte first, however
  			 * underling smbus expects low byte first.
  			 */
  			value = swab16(value);
  
  			if (dpot->uid == DPOT_UID(AD5271_ID))
  				value = value >> 2;
  		return value;
e3ae68476   Michael Hennerich   ad525x_dpot: add ...
219
  	default:
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
220
221
222
223
224
  		if ((reg & DPOT_REG_TOL) || (dpot->max_pos > 256))
  			return dpot_read_r8d16(dpot, (reg & 0xF8) |
  					((reg & 0x7) << 1));
  		else
  			return dpot_read_r8d8(dpot, reg);
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
225
  	}
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
226
  }
e3ae68476   Michael Hennerich   ad525x_dpot: add ...
227
228
229
230
231
232
233
234
235
  static s32 dpot_read(struct dpot_data *dpot, u8 reg)
  {
  	if (dpot->feat & F_SPI)
  		return dpot_read_spi(dpot, reg);
  	else
  		return dpot_read_i2c(dpot, reg);
  }
  
  static s32 dpot_write_spi(struct dpot_data *dpot, u8 reg, u16 value)
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
236
237
  {
  	unsigned val = 0;
a4bd39495   Michael Hennerich   drivers/misc/ad52...
238
  	if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD | DPOT_ADDR_OTP))) {
e3ae68476   Michael Hennerich   ad525x_dpot: add ...
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
  		if (dpot->feat & F_RDACS_WONLY)
  			dpot->rdac_cache[reg & DPOT_RDAC_MASK] = value;
  
  		if (dpot->feat & F_AD_APPDATA) {
  			if (dpot->feat & F_SPI_8BIT) {
  				val = ((reg & DPOT_RDAC_MASK) <<
  					DPOT_MAX_POS(dpot->devid)) |
  					value;
  				return dpot_write_d8(dpot, val);
  			} else if (dpot->feat & F_SPI_16BIT) {
  				val = ((reg & DPOT_RDAC_MASK) <<
  					DPOT_MAX_POS(dpot->devid)) |
  					value;
  				return dpot_write_r8d8(dpot, val >> 8,
  					val & 0xFF);
  			} else
  				BUG();
  		} else {
  			if (dpot->uid == DPOT_UID(AD5291_ID) ||
  				dpot->uid == DPOT_UID(AD5292_ID) ||
a4bd39495   Michael Hennerich   drivers/misc/ad52...
259
260
261
262
263
264
265
  				dpot->uid == DPOT_UID(AD5293_ID)) {
  
  				dpot_write_r8d8(dpot, DPOT_AD5291_CTRLREG << 2,
  						DPOT_AD5291_UNLOCK_CMD);
  
  				if (dpot->uid == DPOT_UID(AD5291_ID))
  					value = value << 2;
e3ae68476   Michael Hennerich   ad525x_dpot: add ...
266
267
268
  				return dpot_write_r8d8(dpot,
  					(DPOT_AD5291_RDAC << 2) |
  					(value >> 8), value & 0xFF);
a4bd39495   Michael Hennerich   drivers/misc/ad52...
269
270
271
272
273
274
275
276
  			} else if (dpot->uid == DPOT_UID(AD5270_ID) ||
  				dpot->uid == DPOT_UID(AD5271_ID)) {
  				dpot_write_r8d8(dpot,
  						DPOT_AD5270_1_2_4_CTRLREG << 2,
  						DPOT_AD5270_1_2_4_UNLOCK_CMD);
  
  				if (dpot->uid == DPOT_UID(AD5271_ID))
  					value = value << 2;
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
277

a4bd39495   Michael Hennerich   drivers/misc/ad52...
278
279
280
281
  				return dpot_write_r8d8(dpot,
  					(DPOT_AD5270_1_2_4_RDAC << 2) |
  					(value >> 8), value & 0xFF);
  			}
e3ae68476   Michael Hennerich   ad525x_dpot: add ...
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
  			val = DPOT_SPI_RDAC | (reg & DPOT_RDAC_MASK);
  		}
  	} else if (reg & DPOT_ADDR_EEPROM) {
  		val = DPOT_SPI_EEPROM | (reg & DPOT_RDAC_MASK);
  	} else if (reg & DPOT_ADDR_CMD) {
  		switch (reg) {
  		case DPOT_DEC_ALL_6DB:
  			val = DPOT_SPI_DEC_ALL_6DB;
  			break;
  		case DPOT_INC_ALL_6DB:
  			val = DPOT_SPI_INC_ALL_6DB;
  			break;
  		case DPOT_DEC_ALL:
  			val = DPOT_SPI_DEC_ALL;
  			break;
  		case DPOT_INC_ALL:
  			val = DPOT_SPI_INC_ALL;
  			break;
  		}
a4bd39495   Michael Hennerich   drivers/misc/ad52...
301
302
303
304
305
306
307
308
309
310
  	} else if (reg & DPOT_ADDR_OTP) {
  		if (dpot->uid == DPOT_UID(AD5291_ID) ||
  			dpot->uid == DPOT_UID(AD5292_ID)) {
  			return dpot_write_r8d8(dpot,
  				DPOT_AD5291_STORE_XTPM << 2, 0);
  		} else if (dpot->uid == DPOT_UID(AD5270_ID) ||
  			dpot->uid == DPOT_UID(AD5271_ID)) {
  			return dpot_write_r8d8(dpot,
  				DPOT_AD5270_1_2_4_STORE_XTPM << 2, 0);
  		}
e3ae68476   Michael Hennerich   ad525x_dpot: add ...
311
312
313
314
315
316
317
  	} else
  		BUG();
  
  	if (dpot->feat & F_SPI_16BIT)
  		return dpot_write_r8d8(dpot, val, value);
  	else if (dpot->feat & F_SPI_24BIT)
  		return dpot_write_r8d16(dpot, val, value);
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
318
319
320
  
  	return -EFAULT;
  }
e3ae68476   Michael Hennerich   ad525x_dpot: add ...
321
322
323
  static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value)
  {
  	/* Only write the instruction byte for certain commands */
59592d0cc   Michael Hennerich   ad525x_dpot: add ...
324
  	unsigned tmp = 0, ctrl = 0;
e3ae68476   Michael Hennerich   ad525x_dpot: add ...
325
326
327
328
329
330
331
332
333
334
335
336
  
  	switch (dpot->uid) {
  	case DPOT_UID(AD5246_ID):
  	case DPOT_UID(AD5247_ID):
  		return dpot_write_d8(dpot, value);
  		break;
  
  	case DPOT_UID(AD5245_ID):
  	case DPOT_UID(AD5241_ID):
  	case DPOT_UID(AD5242_ID):
  	case DPOT_UID(AD5243_ID):
  	case DPOT_UID(AD5248_ID):
c74cba610   Michael Hennerich   ad525x_dpot: add ...
337
338
339
  	case DPOT_UID(AD5280_ID):
  	case DPOT_UID(AD5282_ID):
  		ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
5f400cf40   Michael Hennerich   drivers/misc/ad52...
340
  			0 : DPOT_AD5282_RDAC_AB;
e3ae68476   Michael Hennerich   ad525x_dpot: add ...
341
342
  		return dpot_write_r8d8(dpot, ctrl, value);
  		break;
59592d0cc   Michael Hennerich   ad525x_dpot: add ...
343
344
345
346
347
348
349
350
351
352
353
354
355
  	case DPOT_UID(AD5171_ID):
  	case DPOT_UID(AD5273_ID):
  		if (reg & DPOT_ADDR_OTP) {
  			tmp = dpot_read_d8(dpot);
  			if (tmp >> 6) /* Ready to Program? */
  				return -EFAULT;
  			ctrl = DPOT_AD5273_FUSE;
  		}
  		return dpot_write_r8d8(dpot, ctrl, value);
  		break;
  	case DPOT_UID(AD5172_ID):
  	case DPOT_UID(AD5173_ID):
  		ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
5f400cf40   Michael Hennerich   drivers/misc/ad52...
356
  			0 : DPOT_AD5172_3_A0;
59592d0cc   Michael Hennerich   ad525x_dpot: add ...
357
358
359
360
  		if (reg & DPOT_ADDR_OTP) {
  			tmp = dpot_read_r8d16(dpot, ctrl);
  			if (tmp >> 14) /* Ready to Program? */
  				return -EFAULT;
5f400cf40   Michael Hennerich   drivers/misc/ad52...
361
  			ctrl |= DPOT_AD5170_2_3_FUSE;
59592d0cc   Michael Hennerich   ad525x_dpot: add ...
362
363
364
365
366
367
368
369
  		}
  		return dpot_write_r8d8(dpot, ctrl, value);
  		break;
  	case DPOT_UID(AD5170_ID):
  		if (reg & DPOT_ADDR_OTP) {
  			tmp = dpot_read_r8d16(dpot, tmp);
  			if (tmp >> 14) /* Ready to Program? */
  				return -EFAULT;
a4bd39495   Michael Hennerich   drivers/misc/ad52...
370
  			ctrl = DPOT_AD5170_2_3_FUSE;
59592d0cc   Michael Hennerich   ad525x_dpot: add ...
371
372
373
  		}
  		return dpot_write_r8d8(dpot, ctrl, value);
  		break;
a4bd39495   Michael Hennerich   drivers/misc/ad52...
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
  	case DPOT_UID(AD5272_ID):
  	case DPOT_UID(AD5274_ID):
  		dpot_write_r8d8(dpot, DPOT_AD5270_1_2_4_CTRLREG << 2,
  				DPOT_AD5270_1_2_4_UNLOCK_CMD);
  
  		if (reg & DPOT_ADDR_OTP)
  			return dpot_write_r8d8(dpot,
  					DPOT_AD5270_1_2_4_STORE_XTPM << 2, 0);
  
  		if (dpot->uid == DPOT_UID(AD5274_ID))
  			value = value << 2;
  
  		return dpot_write_r8d8(dpot, (DPOT_AD5270_1_2_4_RDAC << 2) |
  				       (value >> 8), value & 0xFF);
  		break;
e3ae68476   Michael Hennerich   ad525x_dpot: add ...
389
  	default:
c74cba610   Michael Hennerich   ad525x_dpot: add ...
390
391
  		if (reg & DPOT_ADDR_CMD)
  			return dpot_write_d8(dpot, reg);
e3ae68476   Michael Hennerich   ad525x_dpot: add ...
392

c74cba610   Michael Hennerich   ad525x_dpot: add ...
393
394
395
396
397
398
  		if (dpot->max_pos > 256)
  			return dpot_write_r8d16(dpot, (reg & 0xF8) |
  						((reg & 0x7) << 1), value);
  		else
  			/* All other registers require instruction + data bytes */
  			return dpot_write_r8d8(dpot, reg, value);
e3ae68476   Michael Hennerich   ad525x_dpot: add ...
399
400
  	}
  }
e3ae68476   Michael Hennerich   ad525x_dpot: add ...
401
402
403
404
405
406
407
  static s32 dpot_write(struct dpot_data *dpot, u8 reg, u16 value)
  {
  	if (dpot->feat & F_SPI)
  		return dpot_write_spi(dpot, reg, value);
  	else
  		return dpot_write_i2c(dpot, reg, value);
  }
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
408
409
410
  /* sysfs functions */
  
  static ssize_t sysfs_show_reg(struct device *dev,
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
411
412
  			      struct device_attribute *attr,
  			      char *buf, u32 reg)
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
413
  {
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
414
  	struct dpot_data *data = dev_get_drvdata(dev);
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
415
  	s32 value;
59592d0cc   Michael Hennerich   ad525x_dpot: add ...
416
417
418
419
420
  	if (reg & DPOT_ADDR_OTP_EN)
  		return sprintf(buf, "%s
  ",
  			test_bit(DPOT_RDAC_MASK & reg, data->otp_en_mask) ?
  			"enabled" : "disabled");
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
421
  	mutex_lock(&data->update_lock);
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
422
  	value = dpot_read(data, reg);
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
423
424
425
426
427
428
429
430
431
432
433
  	mutex_unlock(&data->update_lock);
  
  	if (value < 0)
  		return -EINVAL;
  	/*
  	 * Let someone else deal with converting this ...
  	 * the tolerance is a two-byte value where the MSB
  	 * is a sign + integer value, and the LSB is a
  	 * decimal value.  See page 18 of the AD5258
  	 * datasheet (Rev. A) for more details.
  	 */
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
434
  	if (reg & DPOT_REG_TOL)
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
435
436
437
438
439
440
441
442
443
444
445
  		return sprintf(buf, "0x%04x
  ", value & 0xFFFF);
  	else
  		return sprintf(buf, "%u
  ", value & data->rdac_mask);
  }
  
  static ssize_t sysfs_set_reg(struct device *dev,
  			     struct device_attribute *attr,
  			     const char *buf, size_t count, u32 reg)
  {
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
446
  	struct dpot_data *data = dev_get_drvdata(dev);
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
447
448
  	unsigned long value;
  	int err;
59592d0cc   Michael Hennerich   ad525x_dpot: add ...
449
450
451
452
453
454
455
456
457
458
459
460
  	if (reg & DPOT_ADDR_OTP_EN) {
  		if (!strncmp(buf, "enabled", sizeof("enabled")))
  			set_bit(DPOT_RDAC_MASK & reg, data->otp_en_mask);
  		else
  			clear_bit(DPOT_RDAC_MASK & reg, data->otp_en_mask);
  
  		return count;
  	}
  
  	if ((reg & DPOT_ADDR_OTP) &&
  		!test_bit(DPOT_RDAC_MASK & reg, data->otp_en_mask))
  		return -EPERM;
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
461
462
463
464
465
466
467
468
  	err = strict_strtoul(buf, 10, &value);
  	if (err)
  		return err;
  
  	if (value > data->rdac_mask)
  		value = data->rdac_mask;
  
  	mutex_lock(&data->update_lock);
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
469
470
  	dpot_write(data, reg, value);
  	if (reg & DPOT_ADDR_EEPROM)
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
471
  		msleep(26);	/* Sleep while the EEPROM updates */
59592d0cc   Michael Hennerich   ad525x_dpot: add ...
472
473
  	else if (reg & DPOT_ADDR_OTP)
  		msleep(400);	/* Sleep while the OTP updates */
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
474
475
476
477
478
479
480
481
482
  	mutex_unlock(&data->update_lock);
  
  	return count;
  }
  
  static ssize_t sysfs_do_cmd(struct device *dev,
  			    struct device_attribute *attr,
  			    const char *buf, size_t count, u32 reg)
  {
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
483
  	struct dpot_data *data = dev_get_drvdata(dev);
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
484
485
  
  	mutex_lock(&data->update_lock);
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
486
  	dpot_write(data, reg, 0);
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
487
488
489
490
491
492
  	mutex_unlock(&data->update_lock);
  
  	return count;
  }
  
  /* ------------------------------------------------------------------------- */
0993dbedf   Michael Hennerich   ad525x_dpot: simp...
493
494
495
496
497
  #define DPOT_DEVICE_SHOW(_name, _reg) static ssize_t \
  show_##_name(struct device *dev, \
  			  struct device_attribute *attr, char *buf) \
  { \
  	return sysfs_show_reg(dev, attr, buf, _reg); \
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
498
  }
0993dbedf   Michael Hennerich   ad525x_dpot: simp...
499
500
501
502
503
504
  #define DPOT_DEVICE_SET(_name, _reg) static ssize_t \
  set_##_name(struct device *dev, \
  			 struct device_attribute *attr, \
  			 const char *buf, size_t count) \
  { \
  	return sysfs_set_reg(dev, attr, buf, count, _reg); \
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
505
  }
0993dbedf   Michael Hennerich   ad525x_dpot: simp...
506
507
508
509
  #define DPOT_DEVICE_SHOW_SET(name, reg) \
  DPOT_DEVICE_SHOW(name, reg) \
  DPOT_DEVICE_SET(name, reg) \
  static DEVICE_ATTR(name, S_IWUSR | S_IRUGO, show_##name, set_##name);
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
510

0993dbedf   Michael Hennerich   ad525x_dpot: simp...
511
512
513
  #define DPOT_DEVICE_SHOW_ONLY(name, reg) \
  DPOT_DEVICE_SHOW(name, reg) \
  static DEVICE_ATTR(name, S_IWUSR | S_IRUGO, show_##name, NULL);
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
514

6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
515
516
517
  DPOT_DEVICE_SHOW_SET(rdac0, DPOT_ADDR_RDAC | DPOT_RDAC0);
  DPOT_DEVICE_SHOW_SET(eeprom0, DPOT_ADDR_EEPROM | DPOT_RDAC0);
  DPOT_DEVICE_SHOW_ONLY(tolerance0, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC0);
59592d0cc   Michael Hennerich   ad525x_dpot: add ...
518
519
  DPOT_DEVICE_SHOW_SET(otp0, DPOT_ADDR_OTP | DPOT_RDAC0);
  DPOT_DEVICE_SHOW_SET(otp0en, DPOT_ADDR_OTP_EN | DPOT_RDAC0);
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
520
521
522
523
  
  DPOT_DEVICE_SHOW_SET(rdac1, DPOT_ADDR_RDAC | DPOT_RDAC1);
  DPOT_DEVICE_SHOW_SET(eeprom1, DPOT_ADDR_EEPROM | DPOT_RDAC1);
  DPOT_DEVICE_SHOW_ONLY(tolerance1, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC1);
59592d0cc   Michael Hennerich   ad525x_dpot: add ...
524
525
  DPOT_DEVICE_SHOW_SET(otp1, DPOT_ADDR_OTP | DPOT_RDAC1);
  DPOT_DEVICE_SHOW_SET(otp1en, DPOT_ADDR_OTP_EN | DPOT_RDAC1);
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
526
527
528
529
  
  DPOT_DEVICE_SHOW_SET(rdac2, DPOT_ADDR_RDAC | DPOT_RDAC2);
  DPOT_DEVICE_SHOW_SET(eeprom2, DPOT_ADDR_EEPROM | DPOT_RDAC2);
  DPOT_DEVICE_SHOW_ONLY(tolerance2, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC2);
59592d0cc   Michael Hennerich   ad525x_dpot: add ...
530
531
  DPOT_DEVICE_SHOW_SET(otp2, DPOT_ADDR_OTP | DPOT_RDAC2);
  DPOT_DEVICE_SHOW_SET(otp2en, DPOT_ADDR_OTP_EN | DPOT_RDAC2);
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
532
533
534
535
  
  DPOT_DEVICE_SHOW_SET(rdac3, DPOT_ADDR_RDAC | DPOT_RDAC3);
  DPOT_DEVICE_SHOW_SET(eeprom3, DPOT_ADDR_EEPROM | DPOT_RDAC3);
  DPOT_DEVICE_SHOW_ONLY(tolerance3, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC3);
59592d0cc   Michael Hennerich   ad525x_dpot: add ...
536
537
  DPOT_DEVICE_SHOW_SET(otp3, DPOT_ADDR_OTP | DPOT_RDAC3);
  DPOT_DEVICE_SHOW_SET(otp3en, DPOT_ADDR_OTP_EN | DPOT_RDAC3);
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
538
539
540
541
  
  DPOT_DEVICE_SHOW_SET(rdac4, DPOT_ADDR_RDAC | DPOT_RDAC4);
  DPOT_DEVICE_SHOW_SET(eeprom4, DPOT_ADDR_EEPROM | DPOT_RDAC4);
  DPOT_DEVICE_SHOW_ONLY(tolerance4, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC4);
59592d0cc   Michael Hennerich   ad525x_dpot: add ...
542
543
  DPOT_DEVICE_SHOW_SET(otp4, DPOT_ADDR_OTP | DPOT_RDAC4);
  DPOT_DEVICE_SHOW_SET(otp4en, DPOT_ADDR_OTP_EN | DPOT_RDAC4);
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
544
545
546
547
  
  DPOT_DEVICE_SHOW_SET(rdac5, DPOT_ADDR_RDAC | DPOT_RDAC5);
  DPOT_DEVICE_SHOW_SET(eeprom5, DPOT_ADDR_EEPROM | DPOT_RDAC5);
  DPOT_DEVICE_SHOW_ONLY(tolerance5, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC5);
59592d0cc   Michael Hennerich   ad525x_dpot: add ...
548
549
  DPOT_DEVICE_SHOW_SET(otp5, DPOT_ADDR_OTP | DPOT_RDAC5);
  DPOT_DEVICE_SHOW_SET(otp5en, DPOT_ADDR_OTP_EN | DPOT_RDAC5);
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
  
  static const struct attribute *dpot_attrib_wipers[] = {
  	&dev_attr_rdac0.attr,
  	&dev_attr_rdac1.attr,
  	&dev_attr_rdac2.attr,
  	&dev_attr_rdac3.attr,
  	&dev_attr_rdac4.attr,
  	&dev_attr_rdac5.attr,
  	NULL
  };
  
  static const struct attribute *dpot_attrib_eeprom[] = {
  	&dev_attr_eeprom0.attr,
  	&dev_attr_eeprom1.attr,
  	&dev_attr_eeprom2.attr,
  	&dev_attr_eeprom3.attr,
  	&dev_attr_eeprom4.attr,
  	&dev_attr_eeprom5.attr,
  	NULL
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
569
  };
59592d0cc   Michael Hennerich   ad525x_dpot: add ...
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
  static const struct attribute *dpot_attrib_otp[] = {
  	&dev_attr_otp0.attr,
  	&dev_attr_otp1.attr,
  	&dev_attr_otp2.attr,
  	&dev_attr_otp3.attr,
  	&dev_attr_otp4.attr,
  	&dev_attr_otp5.attr,
  	NULL
  };
  
  static const struct attribute *dpot_attrib_otp_en[] = {
  	&dev_attr_otp0en.attr,
  	&dev_attr_otp1en.attr,
  	&dev_attr_otp2en.attr,
  	&dev_attr_otp3en.attr,
  	&dev_attr_otp4en.attr,
  	&dev_attr_otp5en.attr,
  	NULL
  };
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
589
590
591
592
593
594
595
596
  static const struct attribute *dpot_attrib_tolerance[] = {
  	&dev_attr_tolerance0.attr,
  	&dev_attr_tolerance1.attr,
  	&dev_attr_tolerance2.attr,
  	&dev_attr_tolerance3.attr,
  	&dev_attr_tolerance4.attr,
  	&dev_attr_tolerance5.attr,
  	NULL
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
597
598
599
  };
  
  /* ------------------------------------------------------------------------- */
0993dbedf   Michael Hennerich   ad525x_dpot: simp...
600
601
602
603
604
605
606
607
  #define DPOT_DEVICE_DO_CMD(_name, _cmd) static ssize_t \
  set_##_name(struct device *dev, \
  			 struct device_attribute *attr, \
  			 const char *buf, size_t count) \
  { \
  	return sysfs_do_cmd(dev, attr, buf, count, _cmd); \
  } \
  static DEVICE_ATTR(_name, S_IWUSR | S_IRUGO, NULL, set_##_name);
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
608
609
610
611
  DPOT_DEVICE_DO_CMD(inc_all, DPOT_INC_ALL);
  DPOT_DEVICE_DO_CMD(dec_all, DPOT_DEC_ALL);
  DPOT_DEVICE_DO_CMD(inc_all_6db, DPOT_INC_ALL_6DB);
  DPOT_DEVICE_DO_CMD(dec_all_6db, DPOT_DEC_ALL_6DB);
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
612
613
614
615
616
617
618
619
620
621
622
623
  
  static struct attribute *ad525x_attributes_commands[] = {
  	&dev_attr_inc_all.attr,
  	&dev_attr_dec_all.attr,
  	&dev_attr_inc_all_6db.attr,
  	&dev_attr_dec_all_6db.attr,
  	NULL
  };
  
  static const struct attribute_group ad525x_group_commands = {
  	.attrs = ad525x_attributes_commands,
  };
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
624
625
  __devinit int ad_dpot_add_files(struct device *dev,
  		unsigned features, unsigned rdac)
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
626
  {
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
627
628
629
630
631
632
633
634
  	int err = sysfs_create_file(&dev->kobj,
  		dpot_attrib_wipers[rdac]);
  	if (features & F_CMD_EEP)
  		err |= sysfs_create_file(&dev->kobj,
  			dpot_attrib_eeprom[rdac]);
  	if (features & F_CMD_TOL)
  		err |= sysfs_create_file(&dev->kobj,
  			dpot_attrib_tolerance[rdac]);
59592d0cc   Michael Hennerich   ad525x_dpot: add ...
635
636
637
638
639
640
  	if (features & F_CMD_OTP) {
  		err |= sysfs_create_file(&dev->kobj,
  			dpot_attrib_otp_en[rdac]);
  		err |= sysfs_create_file(&dev->kobj,
  			dpot_attrib_otp[rdac]);
  	}
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
641

6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
642
643
644
645
646
647
  	if (err)
  		dev_err(dev, "failed to register sysfs hooks for RDAC%d
  ",
  			rdac);
  
  	return err;
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
648
  }
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
649
650
  inline void ad_dpot_remove_files(struct device *dev,
  		unsigned features, unsigned rdac)
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
651
  {
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
652
653
654
655
656
657
658
659
  	sysfs_remove_file(&dev->kobj,
  		dpot_attrib_wipers[rdac]);
  	if (features & F_CMD_EEP)
  		sysfs_remove_file(&dev->kobj,
  			dpot_attrib_eeprom[rdac]);
  	if (features & F_CMD_TOL)
  		sysfs_remove_file(&dev->kobj,
  			dpot_attrib_tolerance[rdac]);
59592d0cc   Michael Hennerich   ad525x_dpot: add ...
660
661
662
663
664
665
  	if (features & F_CMD_OTP) {
  		sysfs_remove_file(&dev->kobj,
  			dpot_attrib_otp_en[rdac]);
  		sysfs_remove_file(&dev->kobj,
  			dpot_attrib_otp[rdac]);
  	}
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
666
  }
7f3379de9   Michael Hennerich   misc: ad525x_dpot...
667
668
669
  int __devinit ad_dpot_probe(struct device *dev,
  		struct ad_dpot_bus_data *bdata, unsigned long devid,
  			    const char *name)
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
670
  {
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
671

6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
672
673
  	struct dpot_data *data;
  	int i, err = 0;
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
674
675
676
677
678
679
  
  	data = kzalloc(sizeof(struct dpot_data), GFP_KERNEL);
  	if (!data) {
  		err = -ENOMEM;
  		goto exit;
  	}
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
680
  	dev_set_drvdata(dev, data);
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
681
  	mutex_init(&data->update_lock);
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
682
  	data->bdata = *bdata;
7f3379de9   Michael Hennerich   misc: ad525x_dpot...
683
  	data->devid = devid;
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
684

7f3379de9   Michael Hennerich   misc: ad525x_dpot...
685
  	data->max_pos = 1 << DPOT_MAX_POS(devid);
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
686
  	data->rdac_mask = data->max_pos - 1;
7f3379de9   Michael Hennerich   misc: ad525x_dpot...
687
688
689
  	data->feat = DPOT_FEAT(devid);
  	data->uid = DPOT_UID(devid);
  	data->wipers = DPOT_WIPERS(devid);
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
690

59592d0cc   Michael Hennerich   ad525x_dpot: add ...
691
  	for (i = DPOT_RDAC0; i < MAX_RDACS; i++)
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
692
693
694
695
696
697
698
699
700
701
702
  		if (data->wipers & (1 << i)) {
  			err = ad_dpot_add_files(dev, data->feat, i);
  			if (err)
  				goto exit_remove_files;
  			/* power-up midscale */
  			if (data->feat & F_RDACS_WONLY)
  				data->rdac_cache[i] = data->max_pos / 2;
  		}
  
  	if (data->feat & F_CMD_INC)
  		err = sysfs_create_group(&dev->kobj, &ad525x_group_commands);
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
703
704
705
706
707
708
  
  	if (err) {
  		dev_err(dev, "failed to register sysfs hooks
  ");
  		goto exit_free;
  	}
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
709
710
  	dev_info(dev, "%s %d-Position Digital Potentiometer registered
  ",
7f3379de9   Michael Hennerich   misc: ad525x_dpot...
711
  		 name, data->max_pos);
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
712
713
  
  	return 0;
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
714
  exit_remove_files:
59592d0cc   Michael Hennerich   ad525x_dpot: add ...
715
  	for (i = DPOT_RDAC0; i < MAX_RDACS; i++)
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
716
717
  		if (data->wipers & (1 << i))
  			ad_dpot_remove_files(dev, data->feat, i);
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
718
719
  exit_free:
  	kfree(data);
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
720
  	dev_set_drvdata(dev, NULL);
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
721
  exit:
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
722
723
  	dev_err(dev, "failed to create client for %s ID 0x%lX
  ",
7f3379de9   Michael Hennerich   misc: ad525x_dpot...
724
  		name, devid);
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
725
726
  	return err;
  }
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
727
  EXPORT_SYMBOL(ad_dpot_probe);
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
728

6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
729
  __devexit int ad_dpot_remove(struct device *dev)
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
730
  {
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
731
732
  	struct dpot_data *data = dev_get_drvdata(dev);
  	int i;
59592d0cc   Michael Hennerich   ad525x_dpot: add ...
733
  	for (i = DPOT_RDAC0; i < MAX_RDACS; i++)
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
734
735
  		if (data->wipers & (1 << i))
  			ad_dpot_remove_files(dev, data->feat, i);
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
736

4eb174bee   Michael Hennerich   ad525x_dpot: new ...
737
738
739
740
  	kfree(data);
  
  	return 0;
  }
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
741
  EXPORT_SYMBOL(ad_dpot_remove);
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
742

4eb174bee   Michael Hennerich   ad525x_dpot: new ...
743
744
  
  MODULE_AUTHOR("Chris Verges <chrisv@cyberswitching.com>, "
6c536e4ce   Michael Hennerich   ad525x_dpot: add ...
745
746
  	      "Michael Hennerich <hennerich@blackfin.uclinux.org>");
  MODULE_DESCRIPTION("Digital potentiometer driver");
4eb174bee   Michael Hennerich   ad525x_dpot: new ...
747
  MODULE_LICENSE("GPL");