diff options
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/Kconfig | 30 | ||||
-rw-r--r-- | drivers/misc/Makefile | 2 | ||||
-rw-r--r-- | drivers/misc/ad525x_dpot-i2c.c | 119 | ||||
-rw-r--r-- | drivers/misc/ad525x_dpot-spi.c | 172 | ||||
-rw-r--r-- | drivers/misc/ad525x_dpot.c | 629 | ||||
-rw-r--r-- | drivers/misc/ad525x_dpot.h | 173 |
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 | |||
14 | if MISC_DEVICES | 14 | if MISC_DEVICES |
15 | 15 | ||
16 | config AD525X_DPOT | 16 | config 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 | ||
34 | config 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 | |||
43 | config 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 | |||
30 | config ATMEL_PWM | 54 | config 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 | ||
5 | obj-$(CONFIG_IBM_ASM) += ibmasm/ | 5 | obj-$(CONFIG_IBM_ASM) += ibmasm/ |
6 | obj-$(CONFIG_AD525X_DPOT) += ad525x_dpot.o | 6 | obj-$(CONFIG_AD525X_DPOT) += ad525x_dpot.o |
7 | obj-$(CONFIG_AD525X_DPOT_I2C) += ad525x_dpot-i2c.o | ||
8 | obj-$(CONFIG_AD525X_DPOT_SPI) += ad525x_dpot-spi.o | ||
7 | obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o | 9 | obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o |
8 | obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o | 10 | obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o |
9 | obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o | 11 | obj-$(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 */ | ||
16 | static int write_d8(void *client, u8 val) | ||
17 | { | ||
18 | return i2c_smbus_write_byte(client, val); | ||
19 | } | ||
20 | |||
21 | static int write_r8d8(void *client, u8 reg, u8 val) | ||
22 | { | ||
23 | return i2c_smbus_write_byte_data(client, reg, val); | ||
24 | } | ||
25 | |||
26 | static int write_r8d16(void *client, u8 reg, u16 val) | ||
27 | { | ||
28 | return i2c_smbus_write_word_data(client, reg, val); | ||
29 | } | ||
30 | |||
31 | static int read_d8(void *client) | ||
32 | { | ||
33 | return i2c_smbus_read_byte(client); | ||
34 | } | ||
35 | |||
36 | static int read_r8d8(void *client, u8 reg) | ||
37 | { | ||
38 | return i2c_smbus_read_byte_data(client, reg); | ||
39 | } | ||
40 | |||
41 | static int read_r8d16(void *client, u8 reg) | ||
42 | { | ||
43 | return i2c_smbus_read_word_data(client, reg); | ||
44 | } | ||
45 | |||
46 | static 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 | |||
55 | static 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 | |||
77 | static int __devexit ad_dpot_i2c_remove(struct i2c_client *client) | ||
78 | { | ||
79 | return ad_dpot_remove(&client->dev); | ||
80 | } | ||
81 | |||
82 | static 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 | }; | ||
92 | MODULE_DEVICE_TABLE(i2c, ad_dpot_id); | ||
93 | |||
94 | static 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 | |||
104 | static int __init ad_dpot_i2c_init(void) | ||
105 | { | ||
106 | return i2c_add_driver(&ad_dpot_i2c_driver); | ||
107 | } | ||
108 | module_init(ad_dpot_i2c_init); | ||
109 | |||
110 | static void __exit ad_dpot_i2c_exit(void) | ||
111 | { | ||
112 | i2c_del_driver(&ad_dpot_i2c_driver); | ||
113 | } | ||
114 | module_exit(ad_dpot_i2c_exit); | ||
115 | |||
116 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | ||
117 | MODULE_DESCRIPTION("digital potentiometer I2C bus driver"); | ||
118 | MODULE_LICENSE("GPL"); | ||
119 | MODULE_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 | |||
14 | static 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 */ | ||
47 | static int write8(void *client, u8 val) | ||
48 | { | ||
49 | u8 data = val; | ||
50 | return spi_write(client, &data, 1); | ||
51 | } | ||
52 | |||
53 | static int write16(void *client, u8 reg, u8 val) | ||
54 | { | ||
55 | u8 data[2] = {reg, val}; | ||
56 | return spi_write(client, data, 1); | ||
57 | } | ||
58 | |||
59 | static 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 | |||
65 | static 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 | |||
76 | static 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 | |||
89 | static 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 | |||
102 | static 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 | |||
111 | static 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 | |||
122 | static 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 | |||
142 | static int __devexit ad_dpot_spi_remove(struct spi_device *spi) | ||
143 | { | ||
144 | return ad_dpot_remove(&spi->dev); | ||
145 | } | ||
146 | |||
147 | static 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 | |||
157 | static int __init ad_dpot_spi_init(void) | ||
158 | { | ||
159 | return spi_register_driver(&ad_dpot_spi_driver); | ||
160 | } | ||
161 | module_init(ad_dpot_spi_init); | ||
162 | |||
163 | static void __exit ad_dpot_spi_exit(void) | ||
164 | { | ||
165 | spi_unregister_driver(&ad_dpot_spi_driver); | ||
166 | } | ||
167 | module_exit(ad_dpot_spi_exit); | ||
168 | |||
169 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | ||
170 | MODULE_DESCRIPTION("digital potentiometer SPI bus driver"); | ||
171 | MODULE_LICENSE("GPL"); | ||
172 | MODULE_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 | |||
38 | enum 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 | |||
77 | static s32 ad525x_read(struct i2c_client *client, u8 reg); | ||
78 | static 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 | ||
84 | struct dpot_data { | 68 | struct 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 | ||
80 | static inline int dpot_read_d8(struct dpot_data *dpot) | ||
81 | { | ||
82 | return dpot->bdata.bops->read_d8(dpot->bdata.client); | ||
83 | } | ||
84 | |||
85 | static 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 | |||
90 | static 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 | |||
95 | static 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 | |||
100 | static 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 | |||
105 | static 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 | |||
110 | static 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 | |||
148 | static 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 | ||
93 | static ssize_t sysfs_show_reg(struct device *dev, | 224 | static 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); | |||
182 | DPOT_DEVICE_SHOW(name, reg) \ | 311 | DPOT_DEVICE_SHOW(name, reg) \ |
183 | static DEVICE_ATTR(name, S_IWUSR | S_IRUGO, show_##name, NULL); | 312 | static DEVICE_ATTR(name, S_IWUSR | S_IRUGO, show_##name, NULL); |
184 | 313 | ||
185 | DPOT_DEVICE_SHOW_SET(rdac0, AD525X_I2C_RDAC | AD525X_RDAC0); | 314 | DPOT_DEVICE_SHOW_SET(rdac0, DPOT_ADDR_RDAC | DPOT_RDAC0); |
186 | DPOT_DEVICE_SHOW_SET(eeprom0, AD525X_I2C_EEPROM | AD525X_RDAC0); | 315 | DPOT_DEVICE_SHOW_SET(eeprom0, DPOT_ADDR_EEPROM | DPOT_RDAC0); |
187 | DPOT_DEVICE_SHOW_ONLY(tolerance0, AD525X_I2C_EEPROM | AD525X_TOL_RDAC0); | 316 | DPOT_DEVICE_SHOW_ONLY(tolerance0, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC0); |
188 | 317 | ||
189 | DPOT_DEVICE_SHOW_SET(rdac1, AD525X_I2C_RDAC | AD525X_RDAC1); | 318 | DPOT_DEVICE_SHOW_SET(rdac1, DPOT_ADDR_RDAC | DPOT_RDAC1); |
190 | DPOT_DEVICE_SHOW_SET(eeprom1, AD525X_I2C_EEPROM | AD525X_RDAC1); | 319 | DPOT_DEVICE_SHOW_SET(eeprom1, DPOT_ADDR_EEPROM | DPOT_RDAC1); |
191 | DPOT_DEVICE_SHOW_ONLY(tolerance1, AD525X_I2C_EEPROM | AD525X_TOL_RDAC1); | 320 | DPOT_DEVICE_SHOW_ONLY(tolerance1, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC1); |
192 | 321 | ||
193 | DPOT_DEVICE_SHOW_SET(rdac2, AD525X_I2C_RDAC | AD525X_RDAC2); | 322 | DPOT_DEVICE_SHOW_SET(rdac2, DPOT_ADDR_RDAC | DPOT_RDAC2); |
194 | DPOT_DEVICE_SHOW_SET(eeprom2, AD525X_I2C_EEPROM | AD525X_RDAC2); | 323 | DPOT_DEVICE_SHOW_SET(eeprom2, DPOT_ADDR_EEPROM | DPOT_RDAC2); |
195 | DPOT_DEVICE_SHOW_ONLY(tolerance2, AD525X_I2C_EEPROM | AD525X_TOL_RDAC2); | 324 | DPOT_DEVICE_SHOW_ONLY(tolerance2, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC2); |
196 | 325 | ||
197 | DPOT_DEVICE_SHOW_SET(rdac3, AD525X_I2C_RDAC | AD525X_RDAC3); | 326 | DPOT_DEVICE_SHOW_SET(rdac3, DPOT_ADDR_RDAC | DPOT_RDAC3); |
198 | DPOT_DEVICE_SHOW_SET(eeprom3, AD525X_I2C_EEPROM | AD525X_RDAC3); | 327 | DPOT_DEVICE_SHOW_SET(eeprom3, DPOT_ADDR_EEPROM | DPOT_RDAC3); |
199 | DPOT_DEVICE_SHOW_ONLY(tolerance3, AD525X_I2C_EEPROM | AD525X_TOL_RDAC3); | 328 | DPOT_DEVICE_SHOW_ONLY(tolerance3, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC3); |
200 | 329 | ||
201 | static struct attribute *ad525x_attributes_wipers[4][4] = { | 330 | DPOT_DEVICE_SHOW_SET(rdac4, DPOT_ADDR_RDAC | DPOT_RDAC4); |
202 | { | 331 | DPOT_DEVICE_SHOW_SET(eeprom4, DPOT_ADDR_EEPROM | DPOT_RDAC4); |
203 | &dev_attr_rdac0.attr, | 332 | DPOT_DEVICE_SHOW_ONLY(tolerance4, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC4); |
204 | &dev_attr_eeprom0.attr, | 333 | |
205 | &dev_attr_tolerance0.attr, | 334 | DPOT_DEVICE_SHOW_SET(rdac5, DPOT_ADDR_RDAC | DPOT_RDAC5); |
206 | NULL | 335 | DPOT_DEVICE_SHOW_SET(eeprom5, DPOT_ADDR_EEPROM | DPOT_RDAC5); |
207 | }, { | 336 | DPOT_DEVICE_SHOW_ONLY(tolerance5, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC5); |
208 | &dev_attr_rdac1.attr, | 337 | |
209 | &dev_attr_eeprom1.attr, | 338 | static 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, | 348 | static 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 | ||
225 | static const struct attribute_group ad525x_group_wipers[] = { | 358 | static 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 | } \ |
241 | static DEVICE_ATTR(_name, S_IWUSR | S_IRUGO, NULL, set_##_name); | 377 | static DEVICE_ATTR(_name, S_IWUSR | S_IRUGO, NULL, set_##_name); |
242 | 378 | ||
243 | DPOT_DEVICE_DO_CMD(inc_all, AD525X_INC_ALL); | 379 | DPOT_DEVICE_DO_CMD(inc_all, DPOT_INC_ALL); |
244 | DPOT_DEVICE_DO_CMD(dec_all, AD525X_DEC_ALL); | 380 | DPOT_DEVICE_DO_CMD(dec_all, DPOT_DEC_ALL); |
245 | DPOT_DEVICE_DO_CMD(inc_all_6db, AD525X_INC_ALL_6DB); | 381 | DPOT_DEVICE_DO_CMD(inc_all_6db, DPOT_INC_ALL_6DB); |
246 | DPOT_DEVICE_DO_CMD(dec_all_6db, AD525X_DEC_ALL_6DB); | 382 | DPOT_DEVICE_DO_CMD(dec_all_6db, DPOT_DEC_ALL_6DB); |
247 | 383 | ||
248 | static struct attribute *ad525x_attributes_commands[] = { | 384 | static 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 | */ | ||
274 | static 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 | /** | 415 | inline 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 | */ | ||
299 | static 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 | ||
315 | static 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 | ||
476 | exit_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 | |||
417 | exit_free: | 481 | exit_free: |
418 | kfree(data); | 482 | kfree(data); |
419 | i2c_set_clientdata(client, NULL); | 483 | dev_set_drvdata(dev, NULL); |
420 | exit: | 484 | exit: |
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 | } |
489 | EXPORT_SYMBOL(ad_dpot_probe); | ||
424 | 490 | ||
425 | static 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 | } |
504 | EXPORT_SYMBOL(ad_dpot_remove); | ||
472 | 505 | ||
473 | static 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 | |||
484 | MODULE_DEVICE_TABLE(i2c, ad525x_idtable); | ||
485 | |||
486 | static 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 | |||
496 | static int __init ad525x_init(void) | ||
497 | { | ||
498 | return i2c_add_driver(&ad525x_driver); | ||
499 | } | ||
500 | |||
501 | module_init(ad525x_init); | ||
502 | |||
503 | static void __exit ad525x_exit(void) | ||
504 | { | ||
505 | i2c_del_driver(&ad525x_driver); | ||
506 | } | ||
507 | |||
508 | module_exit(ad525x_exit); | ||
509 | 506 | ||
510 | MODULE_AUTHOR("Chris Verges <chrisv@cyberswitching.com>, " | 507 | MODULE_AUTHOR("Chris Verges <chrisv@cyberswitching.com>, " |
511 | "Michael Hennerich <hennerich@blackfin.uclinux.org>, "); | 508 | "Michael Hennerich <hennerich@blackfin.uclinux.org>"); |
512 | MODULE_DESCRIPTION("AD5258/9 digital potentiometer driver"); | 509 | MODULE_DESCRIPTION("Digital potentiometer driver"); |
513 | MODULE_LICENSE("GPL"); | 510 | MODULE_LICENSE("GPL"); |
514 | MODULE_VERSION(DRIVER_VERSION); | 511 | MODULE_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 | |||
44 | enum 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 | |||
149 | struct dpot_data; | ||
150 | |||
151 | struct 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 | |||
160 | struct ad_dpot_bus_data { | ||
161 | void *client; | ||
162 | const struct ad_dpot_bus_ops *bops; | ||
163 | }; | ||
164 | |||
165 | struct ad_dpot_id { | ||
166 | char *name; | ||
167 | unsigned long devid; | ||
168 | }; | ||
169 | |||
170 | int ad_dpot_probe(struct device *dev, struct ad_dpot_bus_data *bdata, const struct ad_dpot_id *id); | ||
171 | int ad_dpot_remove(struct device *dev); | ||
172 | |||
173 | #endif | ||