diff options
author | Thierry Reding <thierry.reding@avionic-design.de> | 2012-09-18 04:57:10 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2012-09-18 17:27:25 -0400 |
commit | 5e969a401a0126806cc2a358800b5b52d6c0a246 (patch) | |
tree | bf1abac453b63d37222331cb414e2a783ae9887b /drivers/gpio/gpio-adnp.c | |
parent | d724f1c9c3c7dee420b8d778ee53207ef3c17120 (diff) |
gpio: Add Avionic Design N-bit GPIO expander support
This commit adds a driver for the Avionic Design N-bit GPIO expander.
The expander provides a variable number of GPIO pins with interrupt
support.
Changes in v2:
- allow building the driver as a module
- assign of_node unconditionally
- use linear mapping IRQ domain
- properly cleanup IRQ domain
- add OF device table and annotate device tables
- emulate rising and falling edge triggers
- increase #gpio-cells to 2
- drop support for !OF
- use IS_ENABLED to conditionalize DEBUG_FS code
Changes in v3:
- make IRQ support runtime configurable (interrupt-controller property)
- drop interrupt-controller and #interrupt-cells from DT binding
- add inline to_adnp() function to wrap container_of() macro
- consistently use adnp as name for struct adnp variables
- remove irq_mask_cur and rename irq_mask to irq_enable
- fix a subtle deadlock in adnp_gpio_direction_output()
- remove dynamic allocations from debugfs code
- rename regs to num_regs to avoid confusion
- annotate non-trivial code with comments
- don't acquire mutex in adnp_gpio_get()
- assume NO_IRQ == 0
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: devicetree-discuss@lists.ozlabs.org
Cc: Linus Walleij <linus.walleij@stericsson.com>
Cc: linux-kernel@vger.kernel.org
Acked-by: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio/gpio-adnp.c')
-rw-r--r-- | drivers/gpio/gpio-adnp.c | 611 |
1 files changed, 611 insertions, 0 deletions
diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c new file mode 100644 index 000000000000..3df88336415e --- /dev/null +++ b/drivers/gpio/gpio-adnp.c | |||
@@ -0,0 +1,611 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011-2012 Avionic Design GmbH | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/gpio.h> | ||
10 | #include <linux/i2c.h> | ||
11 | #include <linux/interrupt.h> | ||
12 | #include <linux/irqdomain.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/of_irq.h> | ||
15 | #include <linux/seq_file.h> | ||
16 | #include <linux/slab.h> | ||
17 | |||
18 | #define GPIO_DDR(gpio) (0x00 << (gpio)->reg_shift) | ||
19 | #define GPIO_PLR(gpio) (0x01 << (gpio)->reg_shift) | ||
20 | #define GPIO_IER(gpio) (0x02 << (gpio)->reg_shift) | ||
21 | #define GPIO_ISR(gpio) (0x03 << (gpio)->reg_shift) | ||
22 | #define GPIO_PTR(gpio) (0x04 << (gpio)->reg_shift) | ||
23 | |||
24 | struct adnp { | ||
25 | struct i2c_client *client; | ||
26 | struct gpio_chip gpio; | ||
27 | unsigned int reg_shift; | ||
28 | |||
29 | struct mutex i2c_lock; | ||
30 | |||
31 | struct irq_domain *domain; | ||
32 | struct mutex irq_lock; | ||
33 | |||
34 | u8 *irq_enable; | ||
35 | u8 *irq_level; | ||
36 | u8 *irq_rise; | ||
37 | u8 *irq_fall; | ||
38 | u8 *irq_high; | ||
39 | u8 *irq_low; | ||
40 | }; | ||
41 | |||
42 | static inline struct adnp *to_adnp(struct gpio_chip *chip) | ||
43 | { | ||
44 | return container_of(chip, struct adnp, gpio); | ||
45 | } | ||
46 | |||
47 | static int adnp_read(struct adnp *adnp, unsigned offset, uint8_t *value) | ||
48 | { | ||
49 | int err; | ||
50 | |||
51 | err = i2c_smbus_read_byte_data(adnp->client, offset); | ||
52 | if (err < 0) { | ||
53 | dev_err(adnp->gpio.dev, "%s failed: %d\n", | ||
54 | "i2c_smbus_read_byte_data()", err); | ||
55 | return err; | ||
56 | } | ||
57 | |||
58 | *value = err; | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | static int adnp_write(struct adnp *adnp, unsigned offset, uint8_t value) | ||
63 | { | ||
64 | int err; | ||
65 | |||
66 | err = i2c_smbus_write_byte_data(adnp->client, offset, value); | ||
67 | if (err < 0) { | ||
68 | dev_err(adnp->gpio.dev, "%s failed: %d\n", | ||
69 | "i2c_smbus_write_byte_data()", err); | ||
70 | return err; | ||
71 | } | ||
72 | |||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | static int adnp_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
77 | { | ||
78 | struct adnp *adnp = to_adnp(chip); | ||
79 | unsigned int reg = offset >> adnp->reg_shift; | ||
80 | unsigned int pos = offset & 7; | ||
81 | u8 value; | ||
82 | int err; | ||
83 | |||
84 | err = adnp_read(adnp, GPIO_PLR(adnp) + reg, &value); | ||
85 | if (err < 0) | ||
86 | return err; | ||
87 | |||
88 | return (value & BIT(pos)) ? 1 : 0; | ||
89 | } | ||
90 | |||
91 | static void __adnp_gpio_set(struct adnp *adnp, unsigned offset, int value) | ||
92 | { | ||
93 | unsigned int reg = offset >> adnp->reg_shift; | ||
94 | unsigned int pos = offset & 7; | ||
95 | int err; | ||
96 | u8 val; | ||
97 | |||
98 | err = adnp_read(adnp, GPIO_PLR(adnp) + reg, &val); | ||
99 | if (err < 0) | ||
100 | return; | ||
101 | |||
102 | if (value) | ||
103 | val |= BIT(pos); | ||
104 | else | ||
105 | val &= ~BIT(pos); | ||
106 | |||
107 | adnp_write(adnp, GPIO_PLR(adnp) + reg, val); | ||
108 | } | ||
109 | |||
110 | static void adnp_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | ||
111 | { | ||
112 | struct adnp *adnp = to_adnp(chip); | ||
113 | |||
114 | mutex_lock(&adnp->i2c_lock); | ||
115 | __adnp_gpio_set(adnp, offset, value); | ||
116 | mutex_unlock(&adnp->i2c_lock); | ||
117 | } | ||
118 | |||
119 | static int adnp_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | ||
120 | { | ||
121 | struct adnp *adnp = to_adnp(chip); | ||
122 | unsigned int reg = offset >> adnp->reg_shift; | ||
123 | unsigned int pos = offset & 7; | ||
124 | u8 value; | ||
125 | int err; | ||
126 | |||
127 | mutex_lock(&adnp->i2c_lock); | ||
128 | |||
129 | err = adnp_read(adnp, GPIO_DDR(adnp) + reg, &value); | ||
130 | if (err < 0) | ||
131 | goto out; | ||
132 | |||
133 | value &= ~BIT(pos); | ||
134 | |||
135 | err = adnp_write(adnp, GPIO_DDR(adnp) + reg, value); | ||
136 | if (err < 0) | ||
137 | goto out; | ||
138 | |||
139 | err = adnp_read(adnp, GPIO_DDR(adnp) + reg, &value); | ||
140 | if (err < 0) | ||
141 | goto out; | ||
142 | |||
143 | if (err & BIT(pos)) | ||
144 | err = -EACCES; | ||
145 | |||
146 | err = 0; | ||
147 | |||
148 | out: | ||
149 | mutex_unlock(&adnp->i2c_lock); | ||
150 | return err; | ||
151 | } | ||
152 | |||
153 | static int adnp_gpio_direction_output(struct gpio_chip *chip, unsigned offset, | ||
154 | int value) | ||
155 | { | ||
156 | struct adnp *adnp = to_adnp(chip); | ||
157 | unsigned int reg = offset >> adnp->reg_shift; | ||
158 | unsigned int pos = offset & 7; | ||
159 | int err; | ||
160 | u8 val; | ||
161 | |||
162 | mutex_lock(&adnp->i2c_lock); | ||
163 | |||
164 | err = adnp_read(adnp, GPIO_DDR(adnp) + reg, &val); | ||
165 | if (err < 0) | ||
166 | goto out; | ||
167 | |||
168 | val |= BIT(pos); | ||
169 | |||
170 | err = adnp_write(adnp, GPIO_DDR(adnp) + reg, val); | ||
171 | if (err < 0) | ||
172 | goto out; | ||
173 | |||
174 | err = adnp_read(adnp, GPIO_DDR(adnp) + reg, &val); | ||
175 | if (err < 0) | ||
176 | goto out; | ||
177 | |||
178 | if (!(val & BIT(pos))) { | ||
179 | err = -EPERM; | ||
180 | goto out; | ||
181 | } | ||
182 | |||
183 | __adnp_gpio_set(adnp, offset, value); | ||
184 | err = 0; | ||
185 | |||
186 | out: | ||
187 | mutex_unlock(&adnp->i2c_lock); | ||
188 | return err; | ||
189 | } | ||
190 | |||
191 | static void adnp_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) | ||
192 | { | ||
193 | struct adnp *adnp = to_adnp(chip); | ||
194 | unsigned int num_regs = 1 << adnp->reg_shift, i, j; | ||
195 | int err; | ||
196 | |||
197 | for (i = 0; i < num_regs; i++) { | ||
198 | u8 ddr, plr, ier, isr; | ||
199 | |||
200 | mutex_lock(&adnp->i2c_lock); | ||
201 | |||
202 | err = adnp_read(adnp, GPIO_DDR(adnp) + i, &ddr); | ||
203 | if (err < 0) { | ||
204 | mutex_unlock(&adnp->i2c_lock); | ||
205 | return; | ||
206 | } | ||
207 | |||
208 | err = adnp_read(adnp, GPIO_PLR(adnp) + i, &plr); | ||
209 | if (err < 0) { | ||
210 | mutex_unlock(&adnp->i2c_lock); | ||
211 | return; | ||
212 | } | ||
213 | |||
214 | err = adnp_read(adnp, GPIO_IER(adnp) + i, &ier); | ||
215 | if (err < 0) { | ||
216 | mutex_unlock(&adnp->i2c_lock); | ||
217 | return; | ||
218 | } | ||
219 | |||
220 | err = adnp_read(adnp, GPIO_ISR(adnp) + i, &isr); | ||
221 | if (err < 0) { | ||
222 | mutex_unlock(&adnp->i2c_lock); | ||
223 | return; | ||
224 | } | ||
225 | |||
226 | mutex_unlock(&adnp->i2c_lock); | ||
227 | |||
228 | for (j = 0; j < 8; j++) { | ||
229 | unsigned int bit = (i << adnp->reg_shift) + j; | ||
230 | const char *direction = "input "; | ||
231 | const char *level = "low "; | ||
232 | const char *interrupt = "disabled"; | ||
233 | const char *pending = ""; | ||
234 | |||
235 | if (ddr & BIT(j)) | ||
236 | direction = "output"; | ||
237 | |||
238 | if (plr & BIT(j)) | ||
239 | level = "high"; | ||
240 | |||
241 | if (ier & BIT(j)) | ||
242 | interrupt = "enabled "; | ||
243 | |||
244 | if (isr & BIT(j)) | ||
245 | pending = "pending"; | ||
246 | |||
247 | seq_printf(s, "%2u: %s %s IRQ %s %s\n", bit, | ||
248 | direction, level, interrupt, pending); | ||
249 | } | ||
250 | } | ||
251 | } | ||
252 | |||
253 | static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios) | ||
254 | { | ||
255 | struct gpio_chip *chip = &adnp->gpio; | ||
256 | |||
257 | adnp->reg_shift = get_count_order(num_gpios) - 3; | ||
258 | |||
259 | chip->direction_input = adnp_gpio_direction_input; | ||
260 | chip->direction_output = adnp_gpio_direction_output; | ||
261 | chip->get = adnp_gpio_get; | ||
262 | chip->set = adnp_gpio_set; | ||
263 | chip->can_sleep = 1; | ||
264 | |||
265 | if (IS_ENABLED(CONFIG_DEBUG_FS)) | ||
266 | chip->dbg_show = adnp_gpio_dbg_show; | ||
267 | |||
268 | chip->base = -1; | ||
269 | chip->ngpio = num_gpios; | ||
270 | chip->label = adnp->client->name; | ||
271 | chip->dev = &adnp->client->dev; | ||
272 | chip->of_node = chip->dev->of_node; | ||
273 | chip->owner = THIS_MODULE; | ||
274 | |||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | static irqreturn_t adnp_irq(int irq, void *data) | ||
279 | { | ||
280 | struct adnp *adnp = data; | ||
281 | unsigned int num_regs, i; | ||
282 | |||
283 | num_regs = 1 << adnp->reg_shift; | ||
284 | |||
285 | for (i = 0; i < num_regs; i++) { | ||
286 | unsigned int base = i << adnp->reg_shift, bit; | ||
287 | u8 changed, level, isr, ier; | ||
288 | unsigned long pending; | ||
289 | int err; | ||
290 | |||
291 | mutex_lock(&adnp->i2c_lock); | ||
292 | |||
293 | err = adnp_read(adnp, GPIO_PLR(adnp) + i, &level); | ||
294 | if (err < 0) { | ||
295 | mutex_unlock(&adnp->i2c_lock); | ||
296 | continue; | ||
297 | } | ||
298 | |||
299 | err = adnp_read(adnp, GPIO_ISR(adnp) + i, &isr); | ||
300 | if (err < 0) { | ||
301 | mutex_unlock(&adnp->i2c_lock); | ||
302 | continue; | ||
303 | } | ||
304 | |||
305 | err = adnp_read(adnp, GPIO_IER(adnp) + i, &ier); | ||
306 | if (err < 0) { | ||
307 | mutex_unlock(&adnp->i2c_lock); | ||
308 | continue; | ||
309 | } | ||
310 | |||
311 | mutex_unlock(&adnp->i2c_lock); | ||
312 | |||
313 | /* determine pins that changed levels */ | ||
314 | changed = level ^ adnp->irq_level[i]; | ||
315 | |||
316 | /* compute edge-triggered interrupts */ | ||
317 | pending = changed & ((adnp->irq_fall[i] & ~level) | | ||
318 | (adnp->irq_rise[i] & level)); | ||
319 | |||
320 | /* add in level-triggered interrupts */ | ||
321 | pending |= (adnp->irq_high[i] & level) | | ||
322 | (adnp->irq_low[i] & ~level); | ||
323 | |||
324 | /* mask out non-pending and disabled interrupts */ | ||
325 | pending &= isr & ier; | ||
326 | |||
327 | for_each_set_bit(bit, &pending, 8) { | ||
328 | unsigned int virq; | ||
329 | virq = irq_find_mapping(adnp->domain, base + bit); | ||
330 | handle_nested_irq(virq); | ||
331 | } | ||
332 | } | ||
333 | |||
334 | return IRQ_HANDLED; | ||
335 | } | ||
336 | |||
337 | static int adnp_gpio_to_irq(struct gpio_chip *chip, unsigned offset) | ||
338 | { | ||
339 | struct adnp *adnp = to_adnp(chip); | ||
340 | return irq_create_mapping(adnp->domain, offset); | ||
341 | } | ||
342 | |||
343 | static void adnp_irq_mask(struct irq_data *data) | ||
344 | { | ||
345 | struct adnp *adnp = irq_data_get_irq_chip_data(data); | ||
346 | unsigned int reg = data->hwirq >> adnp->reg_shift; | ||
347 | unsigned int pos = data->hwirq & 7; | ||
348 | |||
349 | adnp->irq_enable[reg] &= ~BIT(pos); | ||
350 | } | ||
351 | |||
352 | static void adnp_irq_unmask(struct irq_data *data) | ||
353 | { | ||
354 | struct adnp *adnp = irq_data_get_irq_chip_data(data); | ||
355 | unsigned int reg = data->hwirq >> adnp->reg_shift; | ||
356 | unsigned int pos = data->hwirq & 7; | ||
357 | |||
358 | adnp->irq_enable[reg] |= BIT(pos); | ||
359 | } | ||
360 | |||
361 | static int adnp_irq_set_type(struct irq_data *data, unsigned int type) | ||
362 | { | ||
363 | struct adnp *adnp = irq_data_get_irq_chip_data(data); | ||
364 | unsigned int reg = data->hwirq >> adnp->reg_shift; | ||
365 | unsigned int pos = data->hwirq & 7; | ||
366 | |||
367 | if (type & IRQ_TYPE_EDGE_RISING) | ||
368 | adnp->irq_rise[reg] |= BIT(pos); | ||
369 | else | ||
370 | adnp->irq_rise[reg] &= ~BIT(pos); | ||
371 | |||
372 | if (type & IRQ_TYPE_EDGE_FALLING) | ||
373 | adnp->irq_fall[reg] |= BIT(pos); | ||
374 | else | ||
375 | adnp->irq_fall[reg] &= ~BIT(pos); | ||
376 | |||
377 | if (type & IRQ_TYPE_LEVEL_HIGH) | ||
378 | adnp->irq_high[reg] |= BIT(pos); | ||
379 | else | ||
380 | adnp->irq_high[reg] &= ~BIT(pos); | ||
381 | |||
382 | if (type & IRQ_TYPE_LEVEL_LOW) | ||
383 | adnp->irq_low[reg] |= BIT(pos); | ||
384 | else | ||
385 | adnp->irq_low[reg] &= ~BIT(pos); | ||
386 | |||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | static void adnp_irq_bus_lock(struct irq_data *data) | ||
391 | { | ||
392 | struct adnp *adnp = irq_data_get_irq_chip_data(data); | ||
393 | |||
394 | mutex_lock(&adnp->irq_lock); | ||
395 | } | ||
396 | |||
397 | static void adnp_irq_bus_unlock(struct irq_data *data) | ||
398 | { | ||
399 | struct adnp *adnp = irq_data_get_irq_chip_data(data); | ||
400 | unsigned int num_regs = 1 << adnp->reg_shift, i; | ||
401 | |||
402 | mutex_lock(&adnp->i2c_lock); | ||
403 | |||
404 | for (i = 0; i < num_regs; i++) | ||
405 | adnp_write(adnp, GPIO_IER(adnp) + i, adnp->irq_enable[i]); | ||
406 | |||
407 | mutex_unlock(&adnp->i2c_lock); | ||
408 | mutex_unlock(&adnp->irq_lock); | ||
409 | } | ||
410 | |||
411 | static struct irq_chip adnp_irq_chip = { | ||
412 | .name = "gpio-adnp", | ||
413 | .irq_mask = adnp_irq_mask, | ||
414 | .irq_unmask = adnp_irq_unmask, | ||
415 | .irq_set_type = adnp_irq_set_type, | ||
416 | .irq_bus_lock = adnp_irq_bus_lock, | ||
417 | .irq_bus_sync_unlock = adnp_irq_bus_unlock, | ||
418 | }; | ||
419 | |||
420 | static int adnp_irq_map(struct irq_domain *domain, unsigned int irq, | ||
421 | irq_hw_number_t hwirq) | ||
422 | { | ||
423 | irq_set_chip_data(irq, domain->host_data); | ||
424 | irq_set_chip(irq, &adnp_irq_chip); | ||
425 | irq_set_nested_thread(irq, true); | ||
426 | |||
427 | #ifdef CONFIG_ARM | ||
428 | set_irq_flags(irq, IRQF_VALID); | ||
429 | #else | ||
430 | irq_set_noprobe(irq); | ||
431 | #endif | ||
432 | |||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | static const struct irq_domain_ops adnp_irq_domain_ops = { | ||
437 | .map = adnp_irq_map, | ||
438 | .xlate = irq_domain_xlate_twocell, | ||
439 | }; | ||
440 | |||
441 | static int adnp_irq_setup(struct adnp *adnp) | ||
442 | { | ||
443 | unsigned int num_regs = 1 << adnp->reg_shift, i; | ||
444 | struct gpio_chip *chip = &adnp->gpio; | ||
445 | int err; | ||
446 | |||
447 | mutex_init(&adnp->irq_lock); | ||
448 | |||
449 | /* | ||
450 | * Allocate memory to keep track of the current level and trigger | ||
451 | * modes of the interrupts. To avoid multiple allocations, a single | ||
452 | * large buffer is allocated and pointers are setup to point at the | ||
453 | * corresponding offsets. For consistency, the layout of the buffer | ||
454 | * is chosen to match the register layout of the hardware in that | ||
455 | * each segment contains the corresponding bits for all interrupts. | ||
456 | */ | ||
457 | adnp->irq_enable = devm_kzalloc(chip->dev, num_regs * 6, GFP_KERNEL); | ||
458 | if (!adnp->irq_enable) | ||
459 | return -ENOMEM; | ||
460 | |||
461 | adnp->irq_level = adnp->irq_enable + (num_regs * 1); | ||
462 | adnp->irq_rise = adnp->irq_enable + (num_regs * 2); | ||
463 | adnp->irq_fall = adnp->irq_enable + (num_regs * 3); | ||
464 | adnp->irq_high = adnp->irq_enable + (num_regs * 4); | ||
465 | adnp->irq_low = adnp->irq_enable + (num_regs * 5); | ||
466 | |||
467 | for (i = 0; i < num_regs; i++) { | ||
468 | /* | ||
469 | * Read the initial level of all pins to allow the emulation | ||
470 | * of edge triggered interrupts. | ||
471 | */ | ||
472 | err = adnp_read(adnp, GPIO_PLR(adnp) + i, &adnp->irq_level[i]); | ||
473 | if (err < 0) | ||
474 | return err; | ||
475 | |||
476 | /* disable all interrupts */ | ||
477 | err = adnp_write(adnp, GPIO_IER(adnp) + i, 0); | ||
478 | if (err < 0) | ||
479 | return err; | ||
480 | |||
481 | adnp->irq_enable[i] = 0x00; | ||
482 | } | ||
483 | |||
484 | adnp->domain = irq_domain_add_linear(chip->of_node, chip->ngpio, | ||
485 | &adnp_irq_domain_ops, adnp); | ||
486 | |||
487 | err = request_threaded_irq(adnp->client->irq, NULL, adnp_irq, | ||
488 | IRQF_TRIGGER_RISING | IRQF_ONESHOT, | ||
489 | dev_name(chip->dev), adnp); | ||
490 | if (err != 0) { | ||
491 | dev_err(chip->dev, "can't request IRQ#%d: %d\n", | ||
492 | adnp->client->irq, err); | ||
493 | goto error; | ||
494 | } | ||
495 | |||
496 | chip->to_irq = adnp_gpio_to_irq; | ||
497 | return 0; | ||
498 | |||
499 | error: | ||
500 | irq_domain_remove(adnp->domain); | ||
501 | return err; | ||
502 | } | ||
503 | |||
504 | static void adnp_irq_teardown(struct adnp *adnp) | ||
505 | { | ||
506 | unsigned int irq, i; | ||
507 | |||
508 | free_irq(adnp->client->irq, adnp); | ||
509 | |||
510 | for (i = 0; i < adnp->gpio.ngpio; i++) { | ||
511 | irq = irq_find_mapping(adnp->domain, i); | ||
512 | if (irq > 0) | ||
513 | irq_dispose_mapping(irq); | ||
514 | } | ||
515 | |||
516 | irq_domain_remove(adnp->domain); | ||
517 | } | ||
518 | |||
519 | static __devinit int adnp_i2c_probe(struct i2c_client *client, | ||
520 | const struct i2c_device_id *id) | ||
521 | { | ||
522 | struct device_node *np = client->dev.of_node; | ||
523 | struct adnp *adnp; | ||
524 | u32 num_gpios; | ||
525 | int err; | ||
526 | |||
527 | err = of_property_read_u32(np, "nr-gpios", &num_gpios); | ||
528 | if (err < 0) | ||
529 | return err; | ||
530 | |||
531 | client->irq = irq_of_parse_and_map(np, 0); | ||
532 | if (!client->irq) | ||
533 | return -EPROBE_DEFER; | ||
534 | |||
535 | adnp = devm_kzalloc(&client->dev, sizeof(*adnp), GFP_KERNEL); | ||
536 | if (!adnp) | ||
537 | return -ENOMEM; | ||
538 | |||
539 | mutex_init(&adnp->i2c_lock); | ||
540 | adnp->client = client; | ||
541 | |||
542 | err = adnp_gpio_setup(adnp, num_gpios); | ||
543 | if (err < 0) | ||
544 | return err; | ||
545 | |||
546 | if (of_find_property(np, "interrupt-controller", NULL)) { | ||
547 | err = adnp_irq_setup(adnp); | ||
548 | if (err < 0) | ||
549 | goto teardown; | ||
550 | } | ||
551 | |||
552 | err = gpiochip_add(&adnp->gpio); | ||
553 | if (err < 0) | ||
554 | goto teardown; | ||
555 | |||
556 | i2c_set_clientdata(client, adnp); | ||
557 | return 0; | ||
558 | |||
559 | teardown: | ||
560 | if (of_find_property(np, "interrupt-controller", NULL)) | ||
561 | adnp_irq_teardown(adnp); | ||
562 | |||
563 | return err; | ||
564 | } | ||
565 | |||
566 | static __devexit int adnp_i2c_remove(struct i2c_client *client) | ||
567 | { | ||
568 | struct adnp *adnp = i2c_get_clientdata(client); | ||
569 | struct device_node *np = client->dev.of_node; | ||
570 | int err; | ||
571 | |||
572 | err = gpiochip_remove(&adnp->gpio); | ||
573 | if (err < 0) { | ||
574 | dev_err(&client->dev, "%s failed: %d\n", "gpiochip_remove()", | ||
575 | err); | ||
576 | return err; | ||
577 | } | ||
578 | |||
579 | if (of_find_property(np, "interrupt-controller", NULL)) | ||
580 | adnp_irq_teardown(adnp); | ||
581 | |||
582 | return 0; | ||
583 | } | ||
584 | |||
585 | static const struct i2c_device_id adnp_i2c_id[] __devinitconst = { | ||
586 | { "gpio-adnp" }, | ||
587 | { }, | ||
588 | }; | ||
589 | MODULE_DEVICE_TABLE(i2c, adnp_i2c_id); | ||
590 | |||
591 | static const struct of_device_id adnp_of_match[] __devinitconst = { | ||
592 | { .compatible = "ad,gpio-adnp", }, | ||
593 | { }, | ||
594 | }; | ||
595 | MODULE_DEVICE_TABLE(of, adnp_of_match); | ||
596 | |||
597 | static struct i2c_driver adnp_i2c_driver = { | ||
598 | .driver = { | ||
599 | .name = "gpio-adnp", | ||
600 | .owner = THIS_MODULE, | ||
601 | .of_match_table = of_match_ptr(adnp_of_match), | ||
602 | }, | ||
603 | .probe = adnp_i2c_probe, | ||
604 | .remove = __devexit_p(adnp_i2c_remove), | ||
605 | .id_table = adnp_i2c_id, | ||
606 | }; | ||
607 | module_i2c_driver(adnp_i2c_driver); | ||
608 | |||
609 | MODULE_DESCRIPTION("Avionic Design N-bit GPIO expander"); | ||
610 | MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>"); | ||
611 | MODULE_LICENSE("GPL"); | ||