Commit e952805d2d2e706aed182723e5ab3ec0b1f91de3
Committed by
Linus Torvalds
1 parent
5a98c04d78
Exists in
master
and in
7 other branches
gpio: add driver for MAX7300 I2C GPIO extender
Add the MAX7300-I2C variant of the MAX7301-SPI version. Both chips share the same core logic, so the generic part of the in-kernel SPI-driver is refactored into a generic part. The I2C and SPI specific funtions are then wrapped into seperate drivers picking up the generic part. Signed-off-by: Wolfram Sang <w.sang@pengutronix.de> Cc: Juergen Beisert <j.beisert@pengutronix.de> Cc: David Brownell <dbrownell@users.sourceforge.net> Cc: Jean Delvare <khali@linux-fr.org> Cc: Anton Vorontsov <avorontsov@ru.mvista.com> Cc: Randy Dunlap <randy.dunlap@oracle.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 6 changed files with 404 additions and 260 deletions Side-by-side Diff
drivers/gpio/Kconfig
... | ... | @@ -65,6 +65,9 @@ |
65 | 65 | |
66 | 66 | # put expanders in the right section, in alphabetical order |
67 | 67 | |
68 | +config GPIO_MAX730X | |
69 | + tristate | |
70 | + | |
68 | 71 | comment "Memory mapped GPIO expanders:" |
69 | 72 | |
70 | 73 | config GPIO_PL061 |
... | ... | @@ -87,6 +90,13 @@ |
87 | 90 | |
88 | 91 | comment "I2C GPIO expanders:" |
89 | 92 | |
93 | +config GPIO_MAX7300 | |
94 | + tristate "Maxim MAX7300 GPIO expander" | |
95 | + depends on I2C | |
96 | + select GPIO_MAX730X | |
97 | + help | |
98 | + GPIO driver for Maxim MAX7301 I2C-based GPIO expander. | |
99 | + | |
90 | 100 | config GPIO_MAX732X |
91 | 101 | tristate "MAX7319, MAX7320-7327 I2C Port Expanders" |
92 | 102 | depends on I2C |
93 | 103 | |
... | ... | @@ -226,8 +236,9 @@ |
226 | 236 | config GPIO_MAX7301 |
227 | 237 | tristate "Maxim MAX7301 GPIO expander" |
228 | 238 | depends on SPI_MASTER |
239 | + select GPIO_MAX730X | |
229 | 240 | help |
230 | - gpio driver for Maxim MAX7301 SPI GPIO expander. | |
241 | + GPIO driver for Maxim MAX7301 SPI-based GPIO expander. | |
231 | 242 | |
232 | 243 | config GPIO_MCP23S08 |
233 | 244 | tristate "Microchip MCP23S08 I/O expander" |
drivers/gpio/Makefile
... | ... | @@ -7,6 +7,8 @@ |
7 | 7 | obj-$(CONFIG_GPIO_ADP5520) += adp5520-gpio.o |
8 | 8 | obj-$(CONFIG_GPIO_ADP5588) += adp5588-gpio.o |
9 | 9 | obj-$(CONFIG_GPIO_LANGWELL) += langwell_gpio.o |
10 | +obj-$(CONFIG_GPIO_MAX730X) += max730x.o | |
11 | +obj-$(CONFIG_GPIO_MAX7300) += max7300.o | |
10 | 12 | obj-$(CONFIG_GPIO_MAX7301) += max7301.o |
11 | 13 | obj-$(CONFIG_GPIO_MAX732X) += max732x.o |
12 | 14 | obj-$(CONFIG_GPIO_MC33880) += mc33880.o |
drivers/gpio/max7300.c
1 | +/* | |
2 | + * drivers/gpio/max7300.c | |
3 | + * | |
4 | + * Copyright (C) 2009 Wolfram Sang, Pengutronix | |
5 | + * | |
6 | + * This program is free software; you can redistribute it and/or modify | |
7 | + * it under the terms of the GNU General Public License version 2 as | |
8 | + * published by the Free Software Foundation. | |
9 | + * | |
10 | + * Check max730x.c for further details. | |
11 | + */ | |
12 | + | |
13 | +#include <linux/module.h> | |
14 | +#include <linux/init.h> | |
15 | +#include <linux/platform_device.h> | |
16 | +#include <linux/mutex.h> | |
17 | +#include <linux/i2c.h> | |
18 | +#include <linux/spi/max7301.h> | |
19 | + | |
20 | +static int max7300_i2c_write(struct device *dev, unsigned int reg, | |
21 | + unsigned int val) | |
22 | +{ | |
23 | + struct i2c_client *client = to_i2c_client(dev); | |
24 | + | |
25 | + return i2c_smbus_write_byte_data(client, reg, val); | |
26 | +} | |
27 | + | |
28 | +static int max7300_i2c_read(struct device *dev, unsigned int reg) | |
29 | +{ | |
30 | + struct i2c_client *client = to_i2c_client(dev); | |
31 | + | |
32 | + return i2c_smbus_read_byte_data(client, reg); | |
33 | +} | |
34 | + | |
35 | +static int __devinit max7300_probe(struct i2c_client *client, | |
36 | + const struct i2c_device_id *id) | |
37 | +{ | |
38 | + struct max7301 *ts; | |
39 | + int ret; | |
40 | + | |
41 | + if (!i2c_check_functionality(client->adapter, | |
42 | + I2C_FUNC_SMBUS_BYTE_DATA)) | |
43 | + return -EIO; | |
44 | + | |
45 | + ts = kzalloc(sizeof(struct max7301), GFP_KERNEL); | |
46 | + if (!ts) | |
47 | + return -ENOMEM; | |
48 | + | |
49 | + ts->read = max7300_i2c_read; | |
50 | + ts->write = max7300_i2c_write; | |
51 | + ts->dev = &client->dev; | |
52 | + | |
53 | + ret = __max730x_probe(ts); | |
54 | + if (ret) | |
55 | + kfree(ts); | |
56 | + return ret; | |
57 | +} | |
58 | + | |
59 | +static int __devexit max7300_remove(struct i2c_client *client) | |
60 | +{ | |
61 | + return __max730x_remove(&client->dev); | |
62 | +} | |
63 | + | |
64 | +static const struct i2c_device_id max7300_id[] = { | |
65 | + { "max7300", 0 }, | |
66 | + { } | |
67 | +}; | |
68 | +MODULE_DEVICE_TABLE(i2c, max7300_id); | |
69 | + | |
70 | +static struct i2c_driver max7300_driver = { | |
71 | + .driver = { | |
72 | + .name = "max7300", | |
73 | + .owner = THIS_MODULE, | |
74 | + }, | |
75 | + .probe = max7300_probe, | |
76 | + .remove = __devexit_p(max7300_remove), | |
77 | + .id_table = max7300_id, | |
78 | +}; | |
79 | + | |
80 | +static int __init max7300_init(void) | |
81 | +{ | |
82 | + return i2c_add_driver(&max7300_driver); | |
83 | +} | |
84 | +subsys_initcall(max7300_init); | |
85 | + | |
86 | +static void __exit max7300_exit(void) | |
87 | +{ | |
88 | + i2c_del_driver(&max7300_driver); | |
89 | +} | |
90 | +module_exit(max7300_exit); | |
91 | + | |
92 | +MODULE_AUTHOR("Wolfram Sang"); | |
93 | +MODULE_LICENSE("GPL v2"); | |
94 | +MODULE_DESCRIPTION("MAX7300 GPIO-Expander"); |
drivers/gpio/max7301.c
1 | -/** | |
1 | +/* | |
2 | 2 | * drivers/gpio/max7301.c |
3 | 3 | * |
4 | 4 | * Copyright (C) 2006 Juergen Beisert, Pengutronix |
5 | 5 | * Copyright (C) 2008 Guennadi Liakhovetski, Pengutronix |
6 | + * Copyright (C) 2009 Wolfram Sang, Pengutronix | |
6 | 7 | * |
7 | 8 | * This program is free software; you can redistribute it and/or modify |
8 | 9 | * it under the terms of the GNU General Public License version 2 as |
9 | 10 | * published by the Free Software Foundation. |
10 | 11 | * |
11 | - * The Maxim's MAX7301 device is an SPI driven GPIO expander. There are | |
12 | - * 28 GPIOs. 8 of them can trigger an interrupt. See datasheet for more | |
13 | - * details | |
14 | - * Note: | |
15 | - * - DIN must be stable at the rising edge of clock. | |
16 | - * - when writing: | |
17 | - * - always clock in 16 clocks at once | |
18 | - * - at DIN: D15 first, D0 last | |
19 | - * - D0..D7 = databyte, D8..D14 = commandbyte | |
20 | - * - D15 = low -> write command | |
21 | - * - when reading | |
22 | - * - always clock in 16 clocks at once | |
23 | - * - at DIN: D15 first, D0 last | |
24 | - * - D0..D7 = dummy, D8..D14 = register address | |
25 | - * - D15 = high -> read command | |
26 | - * - raise CS and assert it again | |
27 | - * - always clock in 16 clocks at once | |
28 | - * - at DOUT: D15 first, D0 last | |
29 | - * - D0..D7 contains the data from the first cycle | |
30 | - * | |
31 | - * The driver exports a standard gpiochip interface | |
12 | + * Check max730x.c for further details. | |
32 | 13 | */ |
33 | 14 | |
15 | +#include <linux/module.h> | |
34 | 16 | #include <linux/init.h> |
35 | 17 | #include <linux/platform_device.h> |
36 | 18 | #include <linux/mutex.h> |
37 | 19 | #include <linux/spi/spi.h> |
38 | 20 | #include <linux/spi/max7301.h> |
39 | -#include <linux/gpio.h> | |
40 | 21 | |
41 | -#define DRIVER_NAME "max7301" | |
42 | - | |
43 | -/* | |
44 | - * Pin configurations, see MAX7301 datasheet page 6 | |
45 | - */ | |
46 | -#define PIN_CONFIG_MASK 0x03 | |
47 | -#define PIN_CONFIG_IN_PULLUP 0x03 | |
48 | -#define PIN_CONFIG_IN_WO_PULLUP 0x02 | |
49 | -#define PIN_CONFIG_OUT 0x01 | |
50 | - | |
51 | -#define PIN_NUMBER 28 | |
52 | - | |
53 | - | |
54 | -/* | |
55 | - * Some registers must be read back to modify. | |
56 | - * To save time we cache them here in memory | |
57 | - */ | |
58 | -struct max7301 { | |
59 | - struct mutex lock; | |
60 | - u8 port_config[8]; /* field 0 is unused */ | |
61 | - u32 out_level; /* cached output levels */ | |
62 | - struct gpio_chip chip; | |
63 | - struct spi_device *spi; | |
64 | -}; | |
65 | - | |
66 | -/** | |
67 | - * max7301_write - Write a new register content | |
68 | - * @spi: The SPI device | |
69 | - * @reg: Register offset | |
70 | - * @val: Value to write | |
71 | - * | |
72 | - * A write to the MAX7301 means one message with one transfer | |
73 | - * | |
74 | - * Returns 0 if successful or a negative value on error | |
75 | - */ | |
76 | -static int max7301_write(struct spi_device *spi, unsigned int reg, unsigned int val) | |
22 | +/* A write to the MAX7301 means one message with one transfer */ | |
23 | +static int max7301_spi_write(struct device *dev, unsigned int reg, | |
24 | + unsigned int val) | |
77 | 25 | { |
26 | + struct spi_device *spi = to_spi_device(dev); | |
78 | 27 | u16 word = ((reg & 0x7F) << 8) | (val & 0xFF); |
28 | + | |
79 | 29 | return spi_write(spi, (const u8 *)&word, sizeof(word)); |
80 | 30 | } |
81 | 31 | |
82 | -/** | |
83 | - * max7301_read - Read back register content | |
84 | - * @spi: The SPI device | |
85 | - * @reg: Register offset | |
86 | - * | |
87 | - * A read from the MAX7301 means two transfers; here, one message each | |
88 | - * | |
89 | - * Returns positive 8 bit value from device if successful or a | |
90 | - * negative value on error | |
91 | - */ | |
92 | -static int max7301_read(struct spi_device *spi, unsigned int reg) | |
32 | +/* A read from the MAX7301 means two transfers; here, one message each */ | |
33 | + | |
34 | +static int max7301_spi_read(struct device *dev, unsigned int reg) | |
93 | 35 | { |
94 | 36 | int ret; |
95 | 37 | u16 word; |
38 | + struct spi_device *spi = to_spi_device(dev); | |
96 | 39 | |
97 | 40 | word = 0x8000 | (reg << 8); |
98 | 41 | ret = spi_write(spi, (const u8 *)&word, sizeof(word)); |
99 | 42 | |
100 | 43 | |
101 | 44 | |
... | ... | @@ -108,125 +51,13 @@ |
108 | 51 | return word & 0xff; |
109 | 52 | } |
110 | 53 | |
111 | -static int max7301_direction_input(struct gpio_chip *chip, unsigned offset) | |
112 | -{ | |
113 | - struct max7301 *ts = container_of(chip, struct max7301, chip); | |
114 | - u8 *config; | |
115 | - int ret; | |
116 | - | |
117 | - /* First 4 pins are unused in the controller */ | |
118 | - offset += 4; | |
119 | - | |
120 | - config = &ts->port_config[offset >> 2]; | |
121 | - | |
122 | - mutex_lock(&ts->lock); | |
123 | - | |
124 | - /* Standard GPIO API doesn't support pull-ups, has to be extended. | |
125 | - * Hard-coding no pollup for now. */ | |
126 | - *config = (*config & ~(3 << (offset & 3))) | (1 << (offset & 3)); | |
127 | - | |
128 | - ret = max7301_write(ts->spi, 0x08 + (offset >> 2), *config); | |
129 | - | |
130 | - mutex_unlock(&ts->lock); | |
131 | - | |
132 | - return ret; | |
133 | -} | |
134 | - | |
135 | -static int __max7301_set(struct max7301 *ts, unsigned offset, int value) | |
136 | -{ | |
137 | - if (value) { | |
138 | - ts->out_level |= 1 << offset; | |
139 | - return max7301_write(ts->spi, 0x20 + offset, 0x01); | |
140 | - } else { | |
141 | - ts->out_level &= ~(1 << offset); | |
142 | - return max7301_write(ts->spi, 0x20 + offset, 0x00); | |
143 | - } | |
144 | -} | |
145 | - | |
146 | -static int max7301_direction_output(struct gpio_chip *chip, unsigned offset, | |
147 | - int value) | |
148 | -{ | |
149 | - struct max7301 *ts = container_of(chip, struct max7301, chip); | |
150 | - u8 *config; | |
151 | - int ret; | |
152 | - | |
153 | - /* First 4 pins are unused in the controller */ | |
154 | - offset += 4; | |
155 | - | |
156 | - config = &ts->port_config[offset >> 2]; | |
157 | - | |
158 | - mutex_lock(&ts->lock); | |
159 | - | |
160 | - *config = (*config & ~(3 << (offset & 3))) | (1 << (offset & 3)); | |
161 | - | |
162 | - ret = __max7301_set(ts, offset, value); | |
163 | - | |
164 | - if (!ret) | |
165 | - ret = max7301_write(ts->spi, 0x08 + (offset >> 2), *config); | |
166 | - | |
167 | - mutex_unlock(&ts->lock); | |
168 | - | |
169 | - return ret; | |
170 | -} | |
171 | - | |
172 | -static int max7301_get(struct gpio_chip *chip, unsigned offset) | |
173 | -{ | |
174 | - struct max7301 *ts = container_of(chip, struct max7301, chip); | |
175 | - int config, level = -EINVAL; | |
176 | - | |
177 | - /* First 4 pins are unused in the controller */ | |
178 | - offset += 4; | |
179 | - | |
180 | - mutex_lock(&ts->lock); | |
181 | - | |
182 | - config = (ts->port_config[offset >> 2] >> ((offset & 3) * 2)) & 3; | |
183 | - | |
184 | - switch (config) { | |
185 | - case 1: | |
186 | - /* Output: return cached level */ | |
187 | - level = !!(ts->out_level & (1 << offset)); | |
188 | - break; | |
189 | - case 2: | |
190 | - case 3: | |
191 | - /* Input: read out */ | |
192 | - level = max7301_read(ts->spi, 0x20 + offset) & 0x01; | |
193 | - } | |
194 | - mutex_unlock(&ts->lock); | |
195 | - | |
196 | - return level; | |
197 | -} | |
198 | - | |
199 | -static void max7301_set(struct gpio_chip *chip, unsigned offset, int value) | |
200 | -{ | |
201 | - struct max7301 *ts = container_of(chip, struct max7301, chip); | |
202 | - | |
203 | - /* First 4 pins are unused in the controller */ | |
204 | - offset += 4; | |
205 | - | |
206 | - mutex_lock(&ts->lock); | |
207 | - | |
208 | - __max7301_set(ts, offset, value); | |
209 | - | |
210 | - mutex_unlock(&ts->lock); | |
211 | -} | |
212 | - | |
213 | 54 | static int __devinit max7301_probe(struct spi_device *spi) |
214 | 55 | { |
215 | 56 | struct max7301 *ts; |
216 | - struct max7301_platform_data *pdata; | |
217 | - int i, ret; | |
57 | + int ret; | |
218 | 58 | |
219 | - pdata = spi->dev.platform_data; | |
220 | - if (!pdata || !pdata->base) { | |
221 | - dev_dbg(&spi->dev, "incorrect or missing platform data\n"); | |
222 | - return -EINVAL; | |
223 | - } | |
224 | - | |
225 | - /* | |
226 | - * bits_per_word cannot be configured in platform data | |
227 | - */ | |
59 | + /* bits_per_word cannot be configured in platform data */ | |
228 | 60 | spi->bits_per_word = 16; |
229 | - | |
230 | 61 | ret = spi_setup(spi); |
231 | 62 | if (ret < 0) |
232 | 63 | return ret; |
233 | 64 | |
234 | 65 | |
235 | 66 | |
236 | 67 | |
237 | 68 | |
238 | 69 | |
239 | 70 | |
... | ... | @@ -235,90 +66,35 @@ |
235 | 66 | if (!ts) |
236 | 67 | return -ENOMEM; |
237 | 68 | |
238 | - mutex_init(&ts->lock); | |
69 | + ts->read = max7301_spi_read; | |
70 | + ts->write = max7301_spi_write; | |
71 | + ts->dev = &spi->dev; | |
239 | 72 | |
240 | - dev_set_drvdata(&spi->dev, ts); | |
241 | - | |
242 | - /* Power up the chip and disable IRQ output */ | |
243 | - max7301_write(spi, 0x04, 0x01); | |
244 | - | |
245 | - ts->spi = spi; | |
246 | - | |
247 | - ts->chip.label = DRIVER_NAME, | |
248 | - | |
249 | - ts->chip.direction_input = max7301_direction_input; | |
250 | - ts->chip.get = max7301_get; | |
251 | - ts->chip.direction_output = max7301_direction_output; | |
252 | - ts->chip.set = max7301_set; | |
253 | - | |
254 | - ts->chip.base = pdata->base; | |
255 | - ts->chip.ngpio = PIN_NUMBER; | |
256 | - ts->chip.can_sleep = 1; | |
257 | - ts->chip.dev = &spi->dev; | |
258 | - ts->chip.owner = THIS_MODULE; | |
259 | - | |
260 | - /* | |
261 | - * tristate all pins in hardware and cache the | |
262 | - * register values for later use. | |
263 | - */ | |
264 | - for (i = 1; i < 8; i++) { | |
265 | - int j; | |
266 | - /* 0xAA means input with internal pullup disabled */ | |
267 | - max7301_write(spi, 0x08 + i, 0xAA); | |
268 | - ts->port_config[i] = 0xAA; | |
269 | - for (j = 0; j < 4; j++) { | |
270 | - int offset = (i - 1) * 4 + j; | |
271 | - ret = max7301_direction_input(&ts->chip, offset); | |
272 | - if (ret) | |
273 | - goto exit_destroy; | |
274 | - } | |
275 | - } | |
276 | - | |
277 | - ret = gpiochip_add(&ts->chip); | |
73 | + ret = __max730x_probe(ts); | |
278 | 74 | if (ret) |
279 | - goto exit_destroy; | |
280 | - | |
75 | + kfree(ts); | |
281 | 76 | return ret; |
282 | - | |
283 | -exit_destroy: | |
284 | - dev_set_drvdata(&spi->dev, NULL); | |
285 | - mutex_destroy(&ts->lock); | |
286 | - kfree(ts); | |
287 | - return ret; | |
288 | 77 | } |
289 | 78 | |
290 | 79 | static int __devexit max7301_remove(struct spi_device *spi) |
291 | 80 | { |
292 | - struct max7301 *ts; | |
293 | - int ret; | |
294 | - | |
295 | - ts = dev_get_drvdata(&spi->dev); | |
296 | - if (ts == NULL) | |
297 | - return -ENODEV; | |
298 | - | |
299 | - dev_set_drvdata(&spi->dev, NULL); | |
300 | - | |
301 | - /* Power down the chip and disable IRQ output */ | |
302 | - max7301_write(spi, 0x04, 0x00); | |
303 | - | |
304 | - ret = gpiochip_remove(&ts->chip); | |
305 | - if (!ret) { | |
306 | - mutex_destroy(&ts->lock); | |
307 | - kfree(ts); | |
308 | - } else | |
309 | - dev_err(&spi->dev, "Failed to remove the GPIO controller: %d\n", | |
310 | - ret); | |
311 | - | |
312 | - return ret; | |
81 | + return __max730x_remove(&spi->dev); | |
313 | 82 | } |
314 | 83 | |
84 | +static const struct spi_device_id max7301_id[] = { | |
85 | + { "max7301", 0 }, | |
86 | + { } | |
87 | +}; | |
88 | +MODULE_DEVICE_TABLE(spi, max7301_id); | |
89 | + | |
315 | 90 | static struct spi_driver max7301_driver = { |
316 | 91 | .driver = { |
317 | - .name = DRIVER_NAME, | |
318 | - .owner = THIS_MODULE, | |
92 | + .name = "max7301", | |
93 | + .owner = THIS_MODULE, | |
319 | 94 | }, |
320 | - .probe = max7301_probe, | |
321 | - .remove = __devexit_p(max7301_remove), | |
95 | + .probe = max7301_probe, | |
96 | + .remove = __devexit_p(max7301_remove), | |
97 | + .id_table = max7301_id, | |
322 | 98 | }; |
323 | 99 | |
324 | 100 | static int __init max7301_init(void) |
325 | 101 | |
... | ... | @@ -336,8 +112,7 @@ |
336 | 112 | } |
337 | 113 | module_exit(max7301_exit); |
338 | 114 | |
339 | -MODULE_AUTHOR("Juergen Beisert"); | |
115 | +MODULE_AUTHOR("Juergen Beisert, Wolfram Sang"); | |
340 | 116 | MODULE_LICENSE("GPL v2"); |
341 | -MODULE_DESCRIPTION("MAX7301 SPI based GPIO-Expander"); | |
342 | -MODULE_ALIAS("spi:" DRIVER_NAME); | |
117 | +MODULE_DESCRIPTION("MAX7301 GPIO-Expander"); |
drivers/gpio/max730x.c
1 | +/** | |
2 | + * drivers/gpio/max7301.c | |
3 | + * | |
4 | + * Copyright (C) 2006 Juergen Beisert, Pengutronix | |
5 | + * Copyright (C) 2008 Guennadi Liakhovetski, Pengutronix | |
6 | + * Copyright (C) 2009 Wolfram Sang, Pengutronix | |
7 | + * | |
8 | + * This program is free software; you can redistribute it and/or modify | |
9 | + * it under the terms of the GNU General Public License version 2 as | |
10 | + * published by the Free Software Foundation. | |
11 | + * | |
12 | + * The Maxim MAX7300/1 device is an I2C/SPI driven GPIO expander. There are | |
13 | + * 28 GPIOs. 8 of them can trigger an interrupt. See datasheet for more | |
14 | + * details | |
15 | + * Note: | |
16 | + * - DIN must be stable at the rising edge of clock. | |
17 | + * - when writing: | |
18 | + * - always clock in 16 clocks at once | |
19 | + * - at DIN: D15 first, D0 last | |
20 | + * - D0..D7 = databyte, D8..D14 = commandbyte | |
21 | + * - D15 = low -> write command | |
22 | + * - when reading | |
23 | + * - always clock in 16 clocks at once | |
24 | + * - at DIN: D15 first, D0 last | |
25 | + * - D0..D7 = dummy, D8..D14 = register address | |
26 | + * - D15 = high -> read command | |
27 | + * - raise CS and assert it again | |
28 | + * - always clock in 16 clocks at once | |
29 | + * - at DOUT: D15 first, D0 last | |
30 | + * - D0..D7 contains the data from the first cycle | |
31 | + * | |
32 | + * The driver exports a standard gpiochip interface | |
33 | + */ | |
34 | + | |
35 | +#include <linux/module.h> | |
36 | +#include <linux/init.h> | |
37 | +#include <linux/platform_device.h> | |
38 | +#include <linux/mutex.h> | |
39 | +#include <linux/spi/max7301.h> | |
40 | +#include <linux/gpio.h> | |
41 | + | |
42 | +/* | |
43 | + * Pin configurations, see MAX7301 datasheet page 6 | |
44 | + */ | |
45 | +#define PIN_CONFIG_MASK 0x03 | |
46 | +#define PIN_CONFIG_IN_PULLUP 0x03 | |
47 | +#define PIN_CONFIG_IN_WO_PULLUP 0x02 | |
48 | +#define PIN_CONFIG_OUT 0x01 | |
49 | + | |
50 | +#define PIN_NUMBER 28 | |
51 | + | |
52 | +static int max7301_direction_input(struct gpio_chip *chip, unsigned offset) | |
53 | +{ | |
54 | + struct max7301 *ts = container_of(chip, struct max7301, chip); | |
55 | + u8 *config; | |
56 | + u8 offset_bits; | |
57 | + int ret; | |
58 | + | |
59 | + /* First 4 pins are unused in the controller */ | |
60 | + offset += 4; | |
61 | + offset_bits = (offset & 3) << 1; | |
62 | + | |
63 | + config = &ts->port_config[offset >> 2]; | |
64 | + | |
65 | + mutex_lock(&ts->lock); | |
66 | + | |
67 | + /* Standard GPIO API doesn't support pull-ups, has to be extended. | |
68 | + * Hard-coding no pollup for now. */ | |
69 | + *config = (*config & ~(PIN_CONFIG_MASK << offset_bits)) | |
70 | + | (PIN_CONFIG_IN_WO_PULLUP << offset_bits); | |
71 | + | |
72 | + ret = ts->write(ts->dev, 0x08 + (offset >> 2), *config); | |
73 | + | |
74 | + mutex_unlock(&ts->lock); | |
75 | + | |
76 | + return ret; | |
77 | +} | |
78 | + | |
79 | +static int __max7301_set(struct max7301 *ts, unsigned offset, int value) | |
80 | +{ | |
81 | + if (value) { | |
82 | + ts->out_level |= 1 << offset; | |
83 | + return ts->write(ts->dev, 0x20 + offset, 0x01); | |
84 | + } else { | |
85 | + ts->out_level &= ~(1 << offset); | |
86 | + return ts->write(ts->dev, 0x20 + offset, 0x00); | |
87 | + } | |
88 | +} | |
89 | + | |
90 | +static int max7301_direction_output(struct gpio_chip *chip, unsigned offset, | |
91 | + int value) | |
92 | +{ | |
93 | + struct max7301 *ts = container_of(chip, struct max7301, chip); | |
94 | + u8 *config; | |
95 | + u8 offset_bits; | |
96 | + int ret; | |
97 | + | |
98 | + /* First 4 pins are unused in the controller */ | |
99 | + offset += 4; | |
100 | + offset_bits = (offset & 3) << 1; | |
101 | + | |
102 | + config = &ts->port_config[offset >> 2]; | |
103 | + | |
104 | + mutex_lock(&ts->lock); | |
105 | + | |
106 | + *config = (*config & ~(PIN_CONFIG_MASK << offset_bits)) | |
107 | + | (PIN_CONFIG_OUT << offset_bits); | |
108 | + | |
109 | + ret = __max7301_set(ts, offset, value); | |
110 | + | |
111 | + if (!ret) | |
112 | + ret = ts->write(ts->dev, 0x08 + (offset >> 2), *config); | |
113 | + | |
114 | + mutex_unlock(&ts->lock); | |
115 | + | |
116 | + return ret; | |
117 | +} | |
118 | + | |
119 | +static int max7301_get(struct gpio_chip *chip, unsigned offset) | |
120 | +{ | |
121 | + struct max7301 *ts = container_of(chip, struct max7301, chip); | |
122 | + int config, level = -EINVAL; | |
123 | + | |
124 | + /* First 4 pins are unused in the controller */ | |
125 | + offset += 4; | |
126 | + | |
127 | + mutex_lock(&ts->lock); | |
128 | + | |
129 | + config = (ts->port_config[offset >> 2] >> ((offset & 3) << 1)) | |
130 | + & PIN_CONFIG_MASK; | |
131 | + | |
132 | + switch (config) { | |
133 | + case PIN_CONFIG_OUT: | |
134 | + /* Output: return cached level */ | |
135 | + level = !!(ts->out_level & (1 << offset)); | |
136 | + break; | |
137 | + case PIN_CONFIG_IN_WO_PULLUP: | |
138 | + case PIN_CONFIG_IN_PULLUP: | |
139 | + /* Input: read out */ | |
140 | + level = ts->read(ts->dev, 0x20 + offset) & 0x01; | |
141 | + } | |
142 | + mutex_unlock(&ts->lock); | |
143 | + | |
144 | + return level; | |
145 | +} | |
146 | + | |
147 | +static void max7301_set(struct gpio_chip *chip, unsigned offset, int value) | |
148 | +{ | |
149 | + struct max7301 *ts = container_of(chip, struct max7301, chip); | |
150 | + | |
151 | + /* First 4 pins are unused in the controller */ | |
152 | + offset += 4; | |
153 | + | |
154 | + mutex_lock(&ts->lock); | |
155 | + | |
156 | + __max7301_set(ts, offset, value); | |
157 | + | |
158 | + mutex_unlock(&ts->lock); | |
159 | +} | |
160 | + | |
161 | +int __devinit __max730x_probe(struct max7301 *ts) | |
162 | +{ | |
163 | + struct device *dev = ts->dev; | |
164 | + struct max7301_platform_data *pdata; | |
165 | + int i, ret; | |
166 | + | |
167 | + pdata = dev->platform_data; | |
168 | + if (!pdata || !pdata->base) { | |
169 | + dev_err(dev, "incorrect or missing platform data\n"); | |
170 | + return -EINVAL; | |
171 | + } | |
172 | + | |
173 | + mutex_init(&ts->lock); | |
174 | + dev_set_drvdata(dev, ts); | |
175 | + | |
176 | + /* Power up the chip and disable IRQ output */ | |
177 | + ts->write(dev, 0x04, 0x01); | |
178 | + | |
179 | + ts->chip.label = dev->driver->name; | |
180 | + | |
181 | + ts->chip.direction_input = max7301_direction_input; | |
182 | + ts->chip.get = max7301_get; | |
183 | + ts->chip.direction_output = max7301_direction_output; | |
184 | + ts->chip.set = max7301_set; | |
185 | + | |
186 | + ts->chip.base = pdata->base; | |
187 | + ts->chip.ngpio = PIN_NUMBER; | |
188 | + ts->chip.can_sleep = 1; | |
189 | + ts->chip.dev = dev; | |
190 | + ts->chip.owner = THIS_MODULE; | |
191 | + | |
192 | + /* | |
193 | + * tristate all pins in hardware and cache the | |
194 | + * register values for later use. | |
195 | + */ | |
196 | + for (i = 1; i < 8; i++) { | |
197 | + int j; | |
198 | + /* 0xAA means input with internal pullup disabled */ | |
199 | + ts->write(dev, 0x08 + i, 0xAA); | |
200 | + ts->port_config[i] = 0xAA; | |
201 | + for (j = 0; j < 4; j++) { | |
202 | + int offset = (i - 1) * 4 + j; | |
203 | + ret = max7301_direction_input(&ts->chip, offset); | |
204 | + if (ret) | |
205 | + goto exit_destroy; | |
206 | + } | |
207 | + } | |
208 | + | |
209 | + ret = gpiochip_add(&ts->chip); | |
210 | + if (ret) | |
211 | + goto exit_destroy; | |
212 | + | |
213 | + return ret; | |
214 | + | |
215 | +exit_destroy: | |
216 | + dev_set_drvdata(dev, NULL); | |
217 | + mutex_destroy(&ts->lock); | |
218 | + return ret; | |
219 | +} | |
220 | +EXPORT_SYMBOL_GPL(__max730x_probe); | |
221 | + | |
222 | +int __devexit __max730x_remove(struct device *dev) | |
223 | +{ | |
224 | + struct max7301 *ts = dev_get_drvdata(dev); | |
225 | + int ret; | |
226 | + | |
227 | + if (ts == NULL) | |
228 | + return -ENODEV; | |
229 | + | |
230 | + dev_set_drvdata(dev, NULL); | |
231 | + | |
232 | + /* Power down the chip and disable IRQ output */ | |
233 | + ts->write(dev, 0x04, 0x00); | |
234 | + | |
235 | + ret = gpiochip_remove(&ts->chip); | |
236 | + if (!ret) { | |
237 | + mutex_destroy(&ts->lock); | |
238 | + kfree(ts); | |
239 | + } else | |
240 | + dev_err(dev, "Failed to remove GPIO controller: %d\n", ret); | |
241 | + | |
242 | + return ret; | |
243 | +} | |
244 | +EXPORT_SYMBOL_GPL(__max730x_remove); |
include/linux/spi/max7301.h
1 | 1 | #ifndef LINUX_SPI_MAX7301_H |
2 | 2 | #define LINUX_SPI_MAX7301_H |
3 | 3 | |
4 | +#include <linux/gpio.h> | |
5 | + | |
6 | +/* | |
7 | + * Some registers must be read back to modify. | |
8 | + * To save time we cache them here in memory | |
9 | + */ | |
10 | +struct max7301 { | |
11 | + struct mutex lock; | |
12 | + u8 port_config[8]; /* field 0 is unused */ | |
13 | + u32 out_level; /* cached output levels */ | |
14 | + struct gpio_chip chip; | |
15 | + struct device *dev; | |
16 | + int (*write)(struct device *dev, unsigned int reg, unsigned int val); | |
17 | + int (*read)(struct device *dev, unsigned int reg); | |
18 | +}; | |
19 | + | |
4 | 20 | struct max7301_platform_data { |
5 | 21 | /* number assigned to the first GPIO */ |
6 | 22 | unsigned base; |
7 | 23 | }; |
8 | 24 | |
25 | +extern int __max730x_remove(struct device *dev); | |
26 | +extern int __max730x_probe(struct max7301 *ts); | |
9 | 27 | #endif |