aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/misc/Kconfig30
-rw-r--r--drivers/misc/Makefile2
-rw-r--r--drivers/misc/ad525x_dpot-i2c.c119
-rw-r--r--drivers/misc/ad525x_dpot-spi.c172
-rw-r--r--drivers/misc/ad525x_dpot.c629
-rw-r--r--drivers/misc/ad525x_dpot.h173
6 files changed, 806 insertions, 319 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 0d0d625fece2..69e019e7d69c 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -14,11 +14,15 @@ menuconfig MISC_DEVICES
14if MISC_DEVICES 14if MISC_DEVICES
15 15
16config AD525X_DPOT 16config AD525X_DPOT
17 tristate "Analog Devices AD525x Digital Potentiometers" 17 tristate "Analog Devices Digital Potentiometers"
18 depends on I2C && SYSFS 18 depends on (I2C || SPI) && SYSFS
19 help 19 help
20 If you say yes here, you get support for the Analog Devices 20 If you say yes here, you get support for the Analog Devices
21 AD5258, AD5259, AD5251, AD5252, AD5253, AD5254 and AD5255 21 AD5258, AD5259, AD5251, AD5252, AD5253, AD5254, AD5255
22 AD5160, AD5161, AD5162, AD5165, AD5200, AD5201, AD5203,
23 AD5204, AD5206, AD5207, AD5231, AD5232, AD5233, AD5235,
24 AD5260, AD5262, AD5263, AD5290, AD5291, AD5292, AD5293,
25 AD7376, AD8400, AD8402, AD8403, ADN2850
22 digital potentiometer chips. 26 digital potentiometer chips.
23 27
24 See Documentation/misc-devices/ad525x_dpot.txt for the 28 See Documentation/misc-devices/ad525x_dpot.txt for the
@@ -27,6 +31,26 @@ config AD525X_DPOT
27 This driver can also be built as a module. If so, the module 31 This driver can also be built as a module. If so, the module
28 will be called ad525x_dpot. 32 will be called ad525x_dpot.
29 33
34config AD525X_DPOT_I2C
35 tristate "support I2C bus connection"
36 depends on AD525X_DPOT && I2C
37 help
38 Say Y here if you have a digital potentiometers hooked to an I2C bus.
39
40 To compile this driver as a module, choose M here: the
41 module will be called ad525x_dpot-i2c.
42
43config AD525X_DPOT_SPI
44 tristate "support SPI bus connection"
45 depends on AD525X_DPOT && SPI_MASTER
46 help
47 Say Y here if you have a digital potentiometers hooked to an SPI bus.
48
49 If unsure, say N (but it's safe to say "Y").
50
51 To compile this driver as a module, choose M here: the
52 module will be called ad525x_dpot-spi.
53
30config ATMEL_PWM 54config ATMEL_PWM
31 tristate "Atmel AT32/AT91 PWM support" 55 tristate "Atmel AT32/AT91 PWM support"
32 depends on AVR32 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9 56 depends on AVR32 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index f12dc3e54402..6ed06a19474a 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -4,6 +4,8 @@
4 4
5obj-$(CONFIG_IBM_ASM) += ibmasm/ 5obj-$(CONFIG_IBM_ASM) += ibmasm/
6obj-$(CONFIG_AD525X_DPOT) += ad525x_dpot.o 6obj-$(CONFIG_AD525X_DPOT) += ad525x_dpot.o
7obj-$(CONFIG_AD525X_DPOT_I2C) += ad525x_dpot-i2c.o
8obj-$(CONFIG_AD525X_DPOT_SPI) += ad525x_dpot-spi.o
7obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o 9obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o
8obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o 10obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
9obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o 11obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o
diff --git a/drivers/misc/ad525x_dpot-i2c.c b/drivers/misc/ad525x_dpot-i2c.c
new file mode 100644
index 000000000000..971e61d7f881
--- /dev/null
+++ b/drivers/misc/ad525x_dpot-i2c.c
@@ -0,0 +1,119 @@
1/*
2 * Driver for the Analog Devices digital potentiometers (I2C bus)
3 *
4 * Copyright (C) 2010 Michael Hennerich, Analog Devices Inc.
5 *
6 * Licensed under the GPL-2 or later.
7 */
8
9#include <linux/i2c.h>
10#include <linux/module.h>
11
12#include "ad525x_dpot.h"
13
14/* ------------------------------------------------------------------------- */
15/* I2C bus functions */
16static int write_d8(void *client, u8 val)
17{
18 return i2c_smbus_write_byte(client, val);
19}
20
21static int write_r8d8(void *client, u8 reg, u8 val)
22{
23 return i2c_smbus_write_byte_data(client, reg, val);
24}
25
26static int write_r8d16(void *client, u8 reg, u16 val)
27{
28 return i2c_smbus_write_word_data(client, reg, val);
29}
30
31static int read_d8(void *client)
32{
33 return i2c_smbus_read_byte(client);
34}
35
36static int read_r8d8(void *client, u8 reg)
37{
38 return i2c_smbus_read_byte_data(client, reg);
39}
40
41static int read_r8d16(void *client, u8 reg)
42{
43 return i2c_smbus_read_word_data(client, reg);
44}
45
46static const struct ad_dpot_bus_ops bops = {
47 .read_d8 = read_d8,
48 .read_r8d8 = read_r8d8,
49 .read_r8d16 = read_r8d16,
50 .write_d8 = write_d8,
51 .write_r8d8 = write_r8d8,
52 .write_r8d16 = write_r8d16,
53};
54
55static int __devinit ad_dpot_i2c_probe(struct i2c_client *client,
56 const struct i2c_device_id *id)
57{
58 struct ad_dpot_bus_data bdata = {
59 .client = client,
60 .bops = &bops,
61 };
62
63 struct ad_dpot_id dpot_id = {
64 .name = (char *) &id->name,
65 .devid = id->driver_data,
66 };
67
68 if (!i2c_check_functionality(client->adapter,
69 I2C_FUNC_SMBUS_WORD_DATA)) {
70 dev_err(&client->dev, "SMBUS Word Data not Supported\n");
71 return -EIO;
72 }
73
74 return ad_dpot_probe(&client->dev, &bdata, &dpot_id);
75}
76
77static int __devexit ad_dpot_i2c_remove(struct i2c_client *client)
78{
79 return ad_dpot_remove(&client->dev);
80}
81
82static const struct i2c_device_id ad_dpot_id[] = {
83 {"ad5258", AD5258_ID},
84 {"ad5259", AD5259_ID},
85 {"ad5251", AD5251_ID},
86 {"ad5252", AD5252_ID},
87 {"ad5253", AD5253_ID},
88 {"ad5254", AD5254_ID},
89 {"ad5255", AD5255_ID},
90 {}
91};
92MODULE_DEVICE_TABLE(i2c, ad_dpot_id);
93
94static struct i2c_driver ad_dpot_i2c_driver = {
95 .driver = {
96 .name = "ad_dpot",
97 .owner = THIS_MODULE,
98 },
99 .probe = ad_dpot_i2c_probe,
100 .remove = __devexit_p(ad_dpot_i2c_remove),
101 .id_table = ad_dpot_id,
102};
103
104static int __init ad_dpot_i2c_init(void)
105{
106 return i2c_add_driver(&ad_dpot_i2c_driver);
107}
108module_init(ad_dpot_i2c_init);
109
110static void __exit ad_dpot_i2c_exit(void)
111{
112 i2c_del_driver(&ad_dpot_i2c_driver);
113}
114module_exit(ad_dpot_i2c_exit);
115
116MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
117MODULE_DESCRIPTION("digital potentiometer I2C bus driver");
118MODULE_LICENSE("GPL");
119MODULE_ALIAS("i2c:ad_dpot");
diff --git a/drivers/misc/ad525x_dpot-spi.c b/drivers/misc/ad525x_dpot-spi.c
new file mode 100644
index 000000000000..b8c6df9c8437
--- /dev/null
+++ b/drivers/misc/ad525x_dpot-spi.c
@@ -0,0 +1,172 @@
1/*
2 * Driver for the Analog Devices digital potentiometers (SPI bus)
3 *
4 * Copyright (C) 2010 Michael Hennerich, Analog Devices Inc.
5 *
6 * Licensed under the GPL-2 or later.
7 */
8
9#include <linux/spi/spi.h>
10#include <linux/module.h>
11
12#include "ad525x_dpot.h"
13
14static const struct ad_dpot_id ad_dpot_spi_devlist[] = {
15 {.name = "ad5160", .devid = AD5160_ID},
16 {.name = "ad5161", .devid = AD5161_ID},
17 {.name = "ad5162", .devid = AD5162_ID},
18 {.name = "ad5165", .devid = AD5165_ID},
19 {.name = "ad5200", .devid = AD5200_ID},
20 {.name = "ad5201", .devid = AD5201_ID},
21 {.name = "ad5203", .devid = AD5203_ID},
22 {.name = "ad5204", .devid = AD5204_ID},
23 {.name = "ad5206", .devid = AD5206_ID},
24 {.name = "ad5207", .devid = AD5207_ID},
25 {.name = "ad5231", .devid = AD5231_ID},
26 {.name = "ad5232", .devid = AD5232_ID},
27 {.name = "ad5233", .devid = AD5233_ID},
28 {.name = "ad5235", .devid = AD5235_ID},
29 {.name = "ad5260", .devid = AD5260_ID},
30 {.name = "ad5262", .devid = AD5262_ID},
31 {.name = "ad5263", .devid = AD5263_ID},
32 {.name = "ad5290", .devid = AD5290_ID},
33 {.name = "ad5291", .devid = AD5291_ID},
34 {.name = "ad5292", .devid = AD5292_ID},
35 {.name = "ad5293", .devid = AD5293_ID},
36 {.name = "ad7376", .devid = AD7376_ID},
37 {.name = "ad8400", .devid = AD8400_ID},
38 {.name = "ad8402", .devid = AD8402_ID},
39 {.name = "ad8403", .devid = AD8403_ID},
40 {.name = "adn2850", .devid = ADN2850_ID},
41 {}
42};
43
44/* ------------------------------------------------------------------------- */
45
46/* SPI bus functions */
47static int write8(void *client, u8 val)
48{
49 u8 data = val;
50 return spi_write(client, &data, 1);
51}
52
53static int write16(void *client, u8 reg, u8 val)
54{
55 u8 data[2] = {reg, val};
56 return spi_write(client, data, 1);
57}
58
59static int write24(void *client, u8 reg, u16 val)
60{
61 u8 data[3] = {reg, val >> 8, val};
62 return spi_write(client, data, 1);
63}
64
65static int read8(void *client)
66{
67 int ret;
68 u8 data;
69 ret = spi_read(client, &data, 1);
70 if (ret < 0)
71 return ret;
72
73 return data;
74}
75
76static int read16(void *client, u8 reg)
77{
78 int ret;
79 u8 buf_rx[2];
80
81 write16(client, reg, 0);
82 ret = spi_read(client, buf_rx, 2);
83 if (ret < 0)
84 return ret;
85
86 return (buf_rx[0] << 8) | buf_rx[1];
87}
88
89static int read24(void *client, u8 reg)
90{
91 int ret;
92 u8 buf_rx[3];
93
94 write24(client, reg, 0);
95 ret = spi_read(client, buf_rx, 3);
96 if (ret < 0)
97 return ret;
98
99 return (buf_rx[1] << 8) | buf_rx[2];
100}
101
102static const struct ad_dpot_bus_ops bops = {
103 .read_d8 = read8,
104 .read_r8d8 = read16,
105 .read_r8d16 = read24,
106 .write_d8 = write8,
107 .write_r8d8 = write16,
108 .write_r8d16 = write24,
109};
110
111static const struct ad_dpot_id *dpot_match_id(const struct ad_dpot_id *id,
112 char *name)
113{
114 while (id->name && id->name[0]) {
115 if (strcmp(name, id->name) == 0)
116 return id;
117 id++;
118 }
119 return NULL;
120}
121
122static int __devinit ad_dpot_spi_probe(struct spi_device *spi)
123{
124 char *name = spi->dev.platform_data;
125 const struct ad_dpot_id *dpot_id;
126
127 struct ad_dpot_bus_data bdata = {
128 .client = spi,
129 .bops = &bops,
130 };
131
132 dpot_id = dpot_match_id(ad_dpot_spi_devlist, name);
133
134 if (dpot_id == NULL) {
135 dev_err(&spi->dev, "%s not in supported device list", name);
136 return -ENODEV;
137 }
138
139 return ad_dpot_probe(&spi->dev, &bdata, dpot_id);
140}
141
142static int __devexit ad_dpot_spi_remove(struct spi_device *spi)
143{
144 return ad_dpot_remove(&spi->dev);
145}
146
147static struct spi_driver ad_dpot_spi_driver = {
148 .driver = {
149 .name = "ad_dpot",
150 .bus = &spi_bus_type,
151 .owner = THIS_MODULE,
152 },
153 .probe = ad_dpot_spi_probe,
154 .remove = __devexit_p(ad_dpot_spi_remove),
155};
156
157static int __init ad_dpot_spi_init(void)
158{
159 return spi_register_driver(&ad_dpot_spi_driver);
160}
161module_init(ad_dpot_spi_init);
162
163static void __exit ad_dpot_spi_exit(void)
164{
165 spi_unregister_driver(&ad_dpot_spi_driver);
166}
167module_exit(ad_dpot_spi_exit);
168
169MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
170MODULE_DESCRIPTION("digital potentiometer SPI bus driver");
171MODULE_LICENSE("GPL");
172MODULE_ALIAS("spi:ad_dpot");
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);
diff --git a/drivers/misc/ad525x_dpot.h b/drivers/misc/ad525x_dpot.h
new file mode 100644
index 000000000000..99b388e12f5f
--- /dev/null
+++ b/drivers/misc/ad525x_dpot.h
@@ -0,0 +1,173 @@
1/*
2 * Driver for the Analog Devices digital potentiometers
3 *
4 * Copyright (C) 2010 Michael Hennerich, Analog Devices Inc.
5 *
6 * Licensed under the GPL-2 or later.
7 */
8
9#ifndef _AD_DPOT_H_
10#define _AD_DPOT_H_
11
12#include <linux/types.h>
13
14#define DPOT_CONF(features, wipers, max_pos, uid) \
15 (((features) << 18) | (((wipers) & 0xFF) << 10) | \
16 ((max_pos & 0xF) << 6) | (uid & 0x3F))
17
18#define DPOT_UID(conf) (conf & 0x3F)
19#define DPOT_MAX_POS(conf) ((conf >> 6) & 0xF)
20#define DPOT_WIPERS(conf) ((conf >> 10) & 0xFF)
21#define DPOT_FEAT(conf) (conf >> 18)
22
23#define BRDAC0 (1 << 0)
24#define BRDAC1 (1 << 1)
25#define BRDAC2 (1 << 2)
26#define BRDAC3 (1 << 3)
27#define BRDAC4 (1 << 4)
28#define BRDAC5 (1 << 5)
29
30#define F_CMD_INC (1 << 0) /* Features INC/DEC ALL, 6dB */
31#define F_CMD_EEP (1 << 1) /* Features EEPROM */
32#define F_CMD_TOL (1 << 2) /* RDACS are Read/Write + Tolerance REG */
33#define F_RDACS_RW (1 << 3) /* RDACS are Read/Write + Tolerance REG */
34#define F_RDACS_WONLY (1 << 4) /* RDACS are Write only */
35#define F_AD_APPDATA (1 << 5) /* RDAC Address append to data */
36#define F_SPI_8BIT (1 << 6) /* All SPI XFERS are 8-bit */
37#define F_SPI_16BIT (1 << 7) /* All SPI XFERS are 16-bit */
38#define F_SPI_24BIT (1 << 8) /* All SPI XFERS are 24-bit */
39
40#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_SPI (F_SPI_8BIT | F_SPI_16BIT | F_SPI_24BIT)
43
44enum dpot_devid {
45 AD5258_ID = DPOT_CONF(F_RDACS_RW_TOL, BRDAC0, 6, 0), /* I2C */
46 AD5259_ID = DPOT_CONF(F_RDACS_RW_TOL, BRDAC0, 8, 1),
47 AD5251_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC,
48 BRDAC0 | BRDAC3, 6, 2),
49 AD5252_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC,
50 BRDAC0 | BRDAC3, 8, 3),
51 AD5253_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC,
52 BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3, 6, 4),
53 AD5254_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC,
54 BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3, 8, 5),
55 AD5255_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC,
56 BRDAC0 | BRDAC1 | BRDAC2, 9, 6),
57 AD5160_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
58 BRDAC0, 8, 7), /* SPI */
59 AD5161_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
60 BRDAC0, 8, 8),
61 AD5162_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_16BIT,
62 BRDAC0 | BRDAC1, 8, 9),
63 AD5165_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
64 BRDAC0, 8, 10),
65 AD5200_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
66 BRDAC0, 8, 11),
67 AD5201_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
68 BRDAC0, 5, 12),
69 AD5203_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
70 BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3, 6, 13),
71 AD5204_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_16BIT,
72 BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3, 8, 14),
73 AD5206_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_16BIT,
74 BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3 | BRDAC4 | BRDAC5,
75 8, 15),
76 AD5207_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_16BIT,
77 BRDAC0 | BRDAC1, 8, 16),
78 AD5231_ID = DPOT_CONF(F_RDACS_RW_EEP | F_CMD_INC | F_SPI_24BIT,
79 BRDAC0, 10, 17),
80 AD5232_ID = DPOT_CONF(F_RDACS_RW_EEP | F_CMD_INC | F_SPI_16BIT,
81 BRDAC0 | BRDAC1, 8, 18),
82 AD5233_ID = DPOT_CONF(F_RDACS_RW_EEP | F_CMD_INC | F_SPI_16BIT,
83 BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3, 6, 19),
84 AD5235_ID = DPOT_CONF(F_RDACS_RW_EEP | F_CMD_INC | F_SPI_24BIT,
85 BRDAC0 | BRDAC1, 10, 20),
86 AD5260_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
87 BRDAC0, 8, 21),
88 AD5262_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_16BIT,
89 BRDAC0 | BRDAC1, 8, 22),
90 AD5263_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_16BIT,
91 BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3, 8, 23),
92 AD5290_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
93 BRDAC0, 8, 24),
94 AD5291_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT, BRDAC0, 8, 25),
95 AD5292_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT, BRDAC0, 10, 26),
96 AD5293_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT, BRDAC0, 10, 27),
97 AD7376_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
98 BRDAC0, 7, 28),
99 AD8400_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
100 BRDAC0, 8, 29),
101 AD8402_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_16BIT,
102 BRDAC0 | BRDAC1, 8, 30),
103 AD8403_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_16BIT,
104 BRDAC0 | BRDAC1 | BRDAC2, 8, 31),
105 ADN2850_ID = DPOT_CONF(F_RDACS_RW_EEP | F_CMD_INC | F_SPI_24BIT,
106 BRDAC0 | BRDAC1, 10, 32),
107};
108
109#define DPOT_RDAC0 0
110#define DPOT_RDAC1 1
111#define DPOT_RDAC2 2
112#define DPOT_RDAC3 3
113#define DPOT_RDAC4 4
114#define DPOT_RDAC5 5
115
116#define DPOT_RDAC_MASK 0x1F
117
118#define DPOT_REG_TOL 0x18
119#define DPOT_TOL_RDAC0 (DPOT_REG_TOL | DPOT_RDAC0)
120#define DPOT_TOL_RDAC1 (DPOT_REG_TOL | DPOT_RDAC1)
121#define DPOT_TOL_RDAC2 (DPOT_REG_TOL | DPOT_RDAC2)
122#define DPOT_TOL_RDAC3 (DPOT_REG_TOL | DPOT_RDAC3)
123#define DPOT_TOL_RDAC4 (DPOT_REG_TOL | DPOT_RDAC4)
124#define DPOT_TOL_RDAC5 (DPOT_REG_TOL | DPOT_RDAC5)
125
126/* RDAC-to-EEPROM Interface Commands */
127#define DPOT_ADDR_RDAC (0x00 << 5)
128#define DPOT_ADDR_EEPROM (0x01 << 5)
129#define DPOT_ADDR_CMD (0x80)
130
131#define DPOT_DEC_ALL_6DB (DPOT_ADDR_CMD | (0x4 << 3))
132#define DPOT_INC_ALL_6DB (DPOT_ADDR_CMD | (0x9 << 3))
133#define DPOT_DEC_ALL (DPOT_ADDR_CMD | (0x6 << 3))
134#define DPOT_INC_ALL (DPOT_ADDR_CMD | (0xB << 3))
135
136#define DPOT_SPI_RDAC 0xB0
137#define DPOT_SPI_EEPROM 0x30
138#define DPOT_SPI_READ_RDAC 0xA0
139#define DPOT_SPI_READ_EEPROM 0x90
140#define DPOT_SPI_DEC_ALL_6DB 0x50
141#define DPOT_SPI_INC_ALL_6DB 0xD0
142#define DPOT_SPI_DEC_ALL 0x70
143#define DPOT_SPI_INC_ALL 0xF0
144
145/* AD5291/2/3 use special commands */
146#define DPOT_AD5291_RDAC 0x01
147#define DPOT_AD5291_READ_RDAC 0x02
148
149struct dpot_data;
150
151struct ad_dpot_bus_ops {
152 int (*read_d8) (void *client);
153 int (*read_r8d8) (void *client, u8 reg);
154 int (*read_r8d16) (void *client, u8 reg);
155 int (*write_d8) (void *client, u8 val);
156 int (*write_r8d8) (void *client, u8 reg, u8 val);
157 int (*write_r8d16) (void *client, u8 reg, u16 val);
158};
159
160struct ad_dpot_bus_data {
161 void *client;
162 const struct ad_dpot_bus_ops *bops;
163};
164
165struct ad_dpot_id {
166 char *name;
167 unsigned long devid;
168};
169
170int ad_dpot_probe(struct device *dev, struct ad_dpot_bus_data *bdata, const struct ad_dpot_id *id);
171int ad_dpot_remove(struct device *dev);
172
173#endif