diff options
author | William Breathitt Gray <vilhelm.gray@gmail.com> | 2016-05-01 18:44:39 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-05-02 12:32:04 -0400 |
commit | 4c23db0f9f7f5e554837f69a849de75777f3fefc (patch) | |
tree | 0afe9a95bbffbe1a1bcd6d0ecb1a7815c8e1724d | |
parent | 4ef1bec4e4f393aa96d2b5345bb08baabaec8ee1 (diff) |
gpio: 104-dio-48e: Utilize the ISA bus driver
The ACCES 104-DIO-48E series communicates via the ISA bus. As such, it
is more appropriate to use the ISA bus driver over the platform driver
to control the ACCES 104-DIO-48E GPIO driver.
This patch also adds support for multiple devices via the base and irq
module array parameters. Each element of the base array corresponds to a
discrete device; each element of the irq array corresponds to the
respective device addressed in the respective base array element.
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Cc: Alexandre Courbot <gnurou@gmail.com>
Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/gpio/Kconfig | 9 | ||||
-rw-r--r-- | drivers/gpio/gpio-104-dio-48e.c | 106 |
2 files changed, 43 insertions, 72 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 5f3429f0bf46..5aca476c6692 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig | |||
@@ -517,12 +517,13 @@ menu "Port-mapped I/O GPIO drivers" | |||
517 | 517 | ||
518 | config GPIO_104_DIO_48E | 518 | config GPIO_104_DIO_48E |
519 | tristate "ACCES 104-DIO-48E GPIO support" | 519 | tristate "ACCES 104-DIO-48E GPIO support" |
520 | depends on ISA | ||
520 | select GPIOLIB_IRQCHIP | 521 | select GPIOLIB_IRQCHIP |
521 | help | 522 | help |
522 | Enables GPIO support for the ACCES 104-DIO-48E family. The base port | 523 | Enables GPIO support for the ACCES 104-DIO-48E series (104-DIO-48E, |
523 | address for the device may be configured via the dio_48e_base module | 524 | 104-DIO-24E). The base port addresses for the devices may be |
524 | parameter. The interrupt line number for the device may be configured | 525 | configured via the base module parameter. The interrupt line numbers |
525 | via the dio_48e_irq module parameter. | 526 | for the devices may be configured via the irq module parameter. |
526 | 527 | ||
527 | config GPIO_104_IDIO_16 | 528 | config GPIO_104_IDIO_16 |
528 | tristate "ACCES 104-IDIO-16 GPIO support" | 529 | tristate "ACCES 104-IDIO-16 GPIO support" |
diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c index 448a903089ef..1a647c07be67 100644 --- a/drivers/gpio/gpio-104-dio-48e.c +++ b/drivers/gpio/gpio-104-dio-48e.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * GPIO driver for the ACCES 104-DIO-48E | 2 | * GPIO driver for the ACCES 104-DIO-48E series |
3 | * Copyright (C) 2016 William Breathitt Gray | 3 | * Copyright (C) 2016 William Breathitt Gray |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
@@ -10,6 +10,9 @@ | |||
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * General Public License for more details. | 12 | * General Public License for more details. |
13 | * | ||
14 | * This driver supports the following ACCES devices: 104-DIO-48E and | ||
15 | * 104-DIO-24E. | ||
13 | */ | 16 | */ |
14 | #include <linux/bitops.h> | 17 | #include <linux/bitops.h> |
15 | #include <linux/device.h> | 18 | #include <linux/device.h> |
@@ -19,18 +22,23 @@ | |||
19 | #include <linux/ioport.h> | 22 | #include <linux/ioport.h> |
20 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
21 | #include <linux/irqdesc.h> | 24 | #include <linux/irqdesc.h> |
25 | #include <linux/isa.h> | ||
22 | #include <linux/kernel.h> | 26 | #include <linux/kernel.h> |
23 | #include <linux/module.h> | 27 | #include <linux/module.h> |
24 | #include <linux/moduleparam.h> | 28 | #include <linux/moduleparam.h> |
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/spinlock.h> | 29 | #include <linux/spinlock.h> |
27 | 30 | ||
28 | static unsigned dio_48e_base; | 31 | #define DIO48E_EXTENT 16 |
29 | module_param(dio_48e_base, uint, 0); | 32 | #define MAX_NUM_DIO48E max_num_isa_dev(DIO48E_EXTENT) |
30 | MODULE_PARM_DESC(dio_48e_base, "ACCES 104-DIO-48E base address"); | 33 | |
31 | static unsigned dio_48e_irq; | 34 | static unsigned int base[MAX_NUM_DIO48E]; |
32 | module_param(dio_48e_irq, uint, 0); | 35 | static unsigned int num_dio48e; |
33 | MODULE_PARM_DESC(dio_48e_irq, "ACCES 104-DIO-48E interrupt line number"); | 36 | module_param_array(base, uint, &num_dio48e, 0); |
37 | MODULE_PARM_DESC(base, "ACCES 104-DIO-48E base addresses"); | ||
38 | |||
39 | static unsigned int irq[MAX_NUM_DIO48E]; | ||
40 | module_param_array(irq, uint, NULL, 0); | ||
41 | MODULE_PARM_DESC(irq, "ACCES 104-DIO-48E interrupt line numbers"); | ||
34 | 42 | ||
35 | /** | 43 | /** |
36 | * struct dio48e_gpio - GPIO device private data structure | 44 | * struct dio48e_gpio - GPIO device private data structure |
@@ -294,23 +302,19 @@ static irqreturn_t dio48e_irq_handler(int irq, void *dev_id) | |||
294 | return IRQ_HANDLED; | 302 | return IRQ_HANDLED; |
295 | } | 303 | } |
296 | 304 | ||
297 | static int __init dio48e_probe(struct platform_device *pdev) | 305 | static int dio48e_probe(struct device *dev, unsigned int id) |
298 | { | 306 | { |
299 | struct device *dev = &pdev->dev; | ||
300 | struct dio48e_gpio *dio48egpio; | 307 | struct dio48e_gpio *dio48egpio; |
301 | const unsigned base = dio_48e_base; | ||
302 | const unsigned extent = 16; | ||
303 | const char *const name = dev_name(dev); | 308 | const char *const name = dev_name(dev); |
304 | int err; | 309 | int err; |
305 | const unsigned irq = dio_48e_irq; | ||
306 | 310 | ||
307 | dio48egpio = devm_kzalloc(dev, sizeof(*dio48egpio), GFP_KERNEL); | 311 | dio48egpio = devm_kzalloc(dev, sizeof(*dio48egpio), GFP_KERNEL); |
308 | if (!dio48egpio) | 312 | if (!dio48egpio) |
309 | return -ENOMEM; | 313 | return -ENOMEM; |
310 | 314 | ||
311 | if (!devm_request_region(dev, base, extent, name)) { | 315 | if (!devm_request_region(dev, base[id], DIO48E_EXTENT, name)) { |
312 | dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", | 316 | dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", |
313 | base, base + extent); | 317 | base[id], base[id] + DIO48E_EXTENT); |
314 | return -EBUSY; | 318 | return -EBUSY; |
315 | } | 319 | } |
316 | 320 | ||
@@ -324,8 +328,8 @@ static int __init dio48e_probe(struct platform_device *pdev) | |||
324 | dio48egpio->chip.direction_output = dio48e_gpio_direction_output; | 328 | dio48egpio->chip.direction_output = dio48e_gpio_direction_output; |
325 | dio48egpio->chip.get = dio48e_gpio_get; | 329 | dio48egpio->chip.get = dio48e_gpio_get; |
326 | dio48egpio->chip.set = dio48e_gpio_set; | 330 | dio48egpio->chip.set = dio48e_gpio_set; |
327 | dio48egpio->base = base; | 331 | dio48egpio->base = base[id]; |
328 | dio48egpio->irq = irq; | 332 | dio48egpio->irq = irq[id]; |
329 | 333 | ||
330 | spin_lock_init(&dio48egpio->lock); | 334 | spin_lock_init(&dio48egpio->lock); |
331 | 335 | ||
@@ -338,19 +342,19 @@ static int __init dio48e_probe(struct platform_device *pdev) | |||
338 | } | 342 | } |
339 | 343 | ||
340 | /* initialize all GPIO as output */ | 344 | /* initialize all GPIO as output */ |
341 | outb(0x80, base + 3); | 345 | outb(0x80, base[id] + 3); |
342 | outb(0x00, base); | 346 | outb(0x00, base[id]); |
343 | outb(0x00, base + 1); | 347 | outb(0x00, base[id] + 1); |
344 | outb(0x00, base + 2); | 348 | outb(0x00, base[id] + 2); |
345 | outb(0x00, base + 3); | 349 | outb(0x00, base[id] + 3); |
346 | outb(0x80, base + 7); | 350 | outb(0x80, base[id] + 7); |
347 | outb(0x00, base + 4); | 351 | outb(0x00, base[id] + 4); |
348 | outb(0x00, base + 5); | 352 | outb(0x00, base[id] + 5); |
349 | outb(0x00, base + 6); | 353 | outb(0x00, base[id] + 6); |
350 | outb(0x00, base + 7); | 354 | outb(0x00, base[id] + 7); |
351 | 355 | ||
352 | /* disable IRQ by default */ | 356 | /* disable IRQ by default */ |
353 | inb(base + 0xB); | 357 | inb(base[id] + 0xB); |
354 | 358 | ||
355 | err = gpiochip_irqchip_add(&dio48egpio->chip, &dio48e_irqchip, 0, | 359 | err = gpiochip_irqchip_add(&dio48egpio->chip, &dio48e_irqchip, 0, |
356 | handle_edge_irq, IRQ_TYPE_NONE); | 360 | handle_edge_irq, IRQ_TYPE_NONE); |
@@ -359,7 +363,7 @@ static int __init dio48e_probe(struct platform_device *pdev) | |||
359 | goto err_gpiochip_remove; | 363 | goto err_gpiochip_remove; |
360 | } | 364 | } |
361 | 365 | ||
362 | err = request_irq(irq, dio48e_irq_handler, 0, name, dio48egpio); | 366 | err = request_irq(irq[id], dio48e_irq_handler, 0, name, dio48egpio); |
363 | if (err) { | 367 | if (err) { |
364 | dev_err(dev, "IRQ handler registering failed (%d)\n", err); | 368 | dev_err(dev, "IRQ handler registering failed (%d)\n", err); |
365 | goto err_gpiochip_remove; | 369 | goto err_gpiochip_remove; |
@@ -372,9 +376,9 @@ err_gpiochip_remove: | |||
372 | return err; | 376 | return err; |
373 | } | 377 | } |
374 | 378 | ||
375 | static int dio48e_remove(struct platform_device *pdev) | 379 | static int dio48e_remove(struct device *dev, unsigned int id) |
376 | { | 380 | { |
377 | struct dio48e_gpio *const dio48egpio = platform_get_drvdata(pdev); | 381 | struct dio48e_gpio *const dio48egpio = dev_get_drvdata(dev); |
378 | 382 | ||
379 | free_irq(dio48egpio->irq, dio48egpio); | 383 | free_irq(dio48egpio->irq, dio48egpio); |
380 | gpiochip_remove(&dio48egpio->chip); | 384 | gpiochip_remove(&dio48egpio->chip); |
@@ -382,48 +386,14 @@ static int dio48e_remove(struct platform_device *pdev) | |||
382 | return 0; | 386 | return 0; |
383 | } | 387 | } |
384 | 388 | ||
385 | static struct platform_device *dio48e_device; | 389 | static struct isa_driver dio48e_driver = { |
386 | 390 | .probe = dio48e_probe, | |
387 | static struct platform_driver dio48e_driver = { | ||
388 | .driver = { | 391 | .driver = { |
389 | .name = "104-dio-48e" | 392 | .name = "104-dio-48e" |
390 | }, | 393 | }, |
391 | .remove = dio48e_remove | 394 | .remove = dio48e_remove |
392 | }; | 395 | }; |
393 | 396 | module_isa_driver(dio48e_driver, num_dio48e); | |
394 | static void __exit dio48e_exit(void) | ||
395 | { | ||
396 | platform_device_unregister(dio48e_device); | ||
397 | platform_driver_unregister(&dio48e_driver); | ||
398 | } | ||
399 | |||
400 | static int __init dio48e_init(void) | ||
401 | { | ||
402 | int err; | ||
403 | |||
404 | dio48e_device = platform_device_alloc(dio48e_driver.driver.name, -1); | ||
405 | if (!dio48e_device) | ||
406 | return -ENOMEM; | ||
407 | |||
408 | err = platform_device_add(dio48e_device); | ||
409 | if (err) | ||
410 | goto err_platform_device; | ||
411 | |||
412 | err = platform_driver_probe(&dio48e_driver, dio48e_probe); | ||
413 | if (err) | ||
414 | goto err_platform_driver; | ||
415 | |||
416 | return 0; | ||
417 | |||
418 | err_platform_driver: | ||
419 | platform_device_del(dio48e_device); | ||
420 | err_platform_device: | ||
421 | platform_device_put(dio48e_device); | ||
422 | return err; | ||
423 | } | ||
424 | |||
425 | module_init(dio48e_init); | ||
426 | module_exit(dio48e_exit); | ||
427 | 397 | ||
428 | MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); | 398 | MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); |
429 | MODULE_DESCRIPTION("ACCES 104-DIO-48E GPIO driver"); | 399 | MODULE_DESCRIPTION("ACCES 104-DIO-48E GPIO driver"); |