diff options
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/Kconfig | 39 | ||||
-rw-r--r-- | drivers/gpio/gpio-104-dio-48e.c | 110 | ||||
-rw-r--r-- | drivers/gpio/gpio-104-idi-48.c | 87 | ||||
-rw-r--r-- | drivers/gpio/gpio-104-idio-16.c | 85 | ||||
-rw-r--r-- | drivers/gpio/gpio-bcm-kona.c | 4 | ||||
-rw-r--r-- | drivers/gpio/gpio-lpc32xx.c | 48 | ||||
-rw-r--r-- | drivers/gpio/gpio-ws16c48.c | 88 | ||||
-rw-r--r-- | drivers/gpio/gpio-xlp.c | 2 | ||||
-rw-r--r-- | drivers/gpio/gpio-zynq.c | 7 | ||||
-rw-r--r-- | drivers/gpio/gpiolib-of.c | 1 | ||||
-rw-r--r-- | drivers/gpio/gpiolib.c | 78 |
11 files changed, 221 insertions, 328 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d00e7b67be9a..cebcb405812e 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -33,6 +33,7 @@ config ARCH_REQUIRE_GPIOLIB menuconfig GPIOLIB bool "GPIO Support" + select ANON_INODES help This enables GPIO support through the generic GPIO library. You only need to enable this, if you also want to enable @@ -530,30 +531,35 @@ menu "Port-mapped I/O GPIO drivers" config GPIO_104_DIO_48E tristate "ACCES 104-DIO-48E GPIO support" + depends on ISA_BUS_API select GPIOLIB_IRQCHIP help - Enables GPIO support for the ACCES 104-DIO-48E family. The base port - address for the device may be configured via the dio_48e_base module - parameter. The interrupt line number for the device may be configured - via the dio_48e_irq module parameter. + Enables GPIO support for the ACCES 104-DIO-48E series (104-DIO-48E, + 104-DIO-24E). The base port addresses for the devices may be + configured via the base module parameter. The interrupt line numbers + for the devices may be configured via the irq module parameter. config GPIO_104_IDIO_16 tristate "ACCES 104-IDIO-16 GPIO support" + depends on ISA_BUS_API select GPIOLIB_IRQCHIP help - Enables GPIO support for the ACCES 104-IDIO-16 family. The base port - address for the device may be set via the idio_16_base module - parameter. The interrupt line number for the device may be set via the - idio_16_irq module parameter. + Enables GPIO support for the ACCES 104-IDIO-16 family (104-IDIO-16, + 104-IDIO-16E, 104-IDO-16, 104-IDIO-8, 104-IDIO-8E, 104-IDO-8). The + base port addresses for the devices may be configured via the base + module parameter. The interrupt line numbers for the devices may be + configured via the irq module parameter. config GPIO_104_IDI_48 tristate "ACCES 104-IDI-48 GPIO support" + depends on ISA_BUS_API select GPIOLIB_IRQCHIP help - Enables GPIO support for the ACCES 104-IDI-48 family. The base port - address for the device may be configured via the idi_48_base module - parameter. The interrupt line number for the device may be configured - via the idi_48_irq module parameter. + Enables GPIO support for the ACCES 104-IDI-48 family (104-IDI-48A, + 104-IDI-48AC, 104-IDI-48B, 104-IDI-48BC). The base port addresses for + the devices may be configured via the base module parameter. The + interrupt line numbers for the devices may be configured via the irq + module parameter. config GPIO_F7188X tristate "F71869, F71869A, F71882FG, F71889F and F81866 GPIO support" @@ -622,12 +628,13 @@ config GPIO_TS5500 config GPIO_WS16C48 tristate "WinSystems WS16C48 GPIO support" + depends on ISA_BUS_API select GPIOLIB_IRQCHIP help - Enables GPIO support for the WinSystems WS16C48. The base port address - for the device may be configured via the ws16c48_base module - parameter. The interrupt line number for the device may be configured - via the ws16c48_irq module parameter. + Enables GPIO support for the WinSystems WS16C48. The base port + addresses for the devices may be configured via the base module + parameter. The interrupt line numbers for the devices may be + configured via the irq module parameter. endmenu diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c index 448a903089ef..fcf776971ca9 100644 --- a/drivers/gpio/gpio-104-dio-48e.c +++ b/drivers/gpio/gpio-104-dio-48e.c @@ -1,5 +1,5 @@ /* - * GPIO driver for the ACCES 104-DIO-48E + * GPIO driver for the ACCES 104-DIO-48E series * Copyright (C) 2016 William Breathitt Gray * * This program is free software; you can redistribute it and/or modify @@ -10,6 +10,9 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. + * + * This driver supports the following ACCES devices: 104-DIO-48E and + * 104-DIO-24E. */ #include <linux/bitops.h> #include <linux/device.h> @@ -19,18 +22,23 @@ #include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/irqdesc.h> +#include <linux/isa.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/platform_device.h> #include <linux/spinlock.h> -static unsigned dio_48e_base; -module_param(dio_48e_base, uint, 0); -MODULE_PARM_DESC(dio_48e_base, "ACCES 104-DIO-48E base address"); -static unsigned dio_48e_irq; -module_param(dio_48e_irq, uint, 0); -MODULE_PARM_DESC(dio_48e_irq, "ACCES 104-DIO-48E interrupt line number"); +#define DIO48E_EXTENT 16 +#define MAX_NUM_DIO48E max_num_isa_dev(DIO48E_EXTENT) + +static unsigned int base[MAX_NUM_DIO48E]; +static unsigned int num_dio48e; +module_param_array(base, uint, &num_dio48e, 0); +MODULE_PARM_DESC(base, "ACCES 104-DIO-48E base addresses"); + +static unsigned int irq[MAX_NUM_DIO48E]; +module_param_array(irq, uint, NULL, 0); +MODULE_PARM_DESC(irq, "ACCES 104-DIO-48E interrupt line numbers"); /** * struct dio48e_gpio - GPIO device private data structure @@ -67,7 +75,7 @@ static int dio48e_gpio_direction_input(struct gpio_chip *chip, unsigned offset) { struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); const unsigned io_port = offset / 8; - const unsigned control_port = io_port / 2; + const unsigned int control_port = io_port / 3; const unsigned control_addr = dio48egpio->base + 3 + control_port*4; unsigned long flags; unsigned control; @@ -107,7 +115,7 @@ static int dio48e_gpio_direction_output(struct gpio_chip *chip, unsigned offset, { struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); const unsigned io_port = offset / 8; - const unsigned control_port = io_port / 2; + const unsigned int control_port = io_port / 3; const unsigned mask = BIT(offset % 8); const unsigned control_addr = dio48egpio->base + 3 + control_port*4; const unsigned out_port = (io_port > 2) ? io_port + 1 : io_port; @@ -294,23 +302,19 @@ static irqreturn_t dio48e_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } -static int __init dio48e_probe(struct platform_device *pdev) +static int dio48e_probe(struct device *dev, unsigned int id) { - struct device *dev = &pdev->dev; struct dio48e_gpio *dio48egpio; - const unsigned base = dio_48e_base; - const unsigned extent = 16; const char *const name = dev_name(dev); int err; - const unsigned irq = dio_48e_irq; dio48egpio = devm_kzalloc(dev, sizeof(*dio48egpio), GFP_KERNEL); if (!dio48egpio) return -ENOMEM; - if (!devm_request_region(dev, base, extent, name)) { + if (!devm_request_region(dev, base[id], DIO48E_EXTENT, name)) { dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", - base, base + extent); + base[id], base[id] + DIO48E_EXTENT); return -EBUSY; } @@ -324,8 +328,8 @@ static int __init dio48e_probe(struct platform_device *pdev) dio48egpio->chip.direction_output = dio48e_gpio_direction_output; dio48egpio->chip.get = dio48e_gpio_get; dio48egpio->chip.set = dio48e_gpio_set; - dio48egpio->base = base; - dio48egpio->irq = irq; + dio48egpio->base = base[id]; + dio48egpio->irq = irq[id]; spin_lock_init(&dio48egpio->lock); @@ -338,19 +342,19 @@ static int __init dio48e_probe(struct platform_device *pdev) } /* initialize all GPIO as output */ - outb(0x80, base + 3); - outb(0x00, base); - outb(0x00, base + 1); - outb(0x00, base + 2); - outb(0x00, base + 3); - outb(0x80, base + 7); - outb(0x00, base + 4); - outb(0x00, base + 5); - outb(0x00, base + 6); - outb(0x00, base + 7); + outb(0x80, base[id] + 3); + outb(0x00, base[id]); + outb(0x00, base[id] + 1); + outb(0x00, base[id] + 2); + outb(0x00, base[id] + 3); + outb(0x80, base[id] + 7); + outb(0x00, base[id] + 4); + outb(0x00, base[id] + 5); + outb(0x00, base[id] + 6); + outb(0x00, base[id] + 7); /* disable IRQ by default */ - inb(base + 0xB); + inb(base[id] + 0xB); err = gpiochip_irqchip_add(&dio48egpio->chip, &dio48e_irqchip, 0, handle_edge_irq, IRQ_TYPE_NONE); @@ -359,7 +363,7 @@ static int __init dio48e_probe(struct platform_device *pdev) goto err_gpiochip_remove; } - err = request_irq(irq, dio48e_irq_handler, 0, name, dio48egpio); + err = request_irq(irq[id], dio48e_irq_handler, 0, name, dio48egpio); if (err) { dev_err(dev, "IRQ handler registering failed (%d)\n", err); goto err_gpiochip_remove; @@ -372,9 +376,9 @@ err_gpiochip_remove: return err; } -static int dio48e_remove(struct platform_device *pdev) +static int dio48e_remove(struct device *dev, unsigned int id) { - struct dio48e_gpio *const dio48egpio = platform_get_drvdata(pdev); + struct dio48e_gpio *const dio48egpio = dev_get_drvdata(dev); free_irq(dio48egpio->irq, dio48egpio); gpiochip_remove(&dio48egpio->chip); @@ -382,48 +386,14 @@ static int dio48e_remove(struct platform_device *pdev) return 0; } -static struct platform_device *dio48e_device; - -static struct platform_driver dio48e_driver = { +static struct isa_driver dio48e_driver = { + .probe = dio48e_probe, .driver = { .name = "104-dio-48e" }, .remove = dio48e_remove }; - -static void __exit dio48e_exit(void) -{ - platform_device_unregister(dio48e_device); - platform_driver_unregister(&dio48e_driver); -} - -static int __init dio48e_init(void) -{ - int err; - - dio48e_device = platform_device_alloc(dio48e_driver.driver.name, -1); - if (!dio48e_device) - return -ENOMEM; - - err = platform_device_add(dio48e_device); - if (err) - goto err_platform_device; - - err = platform_driver_probe(&dio48e_driver, dio48e_probe); - if (err) - goto err_platform_driver; - - return 0; - -err_platform_driver: - platform_device_del(dio48e_device); -err_platform_device: - platform_device_put(dio48e_device); - return err; -} - -module_init(dio48e_init); -module_exit(dio48e_exit); +module_isa_driver(dio48e_driver, num_dio48e); MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); MODULE_DESCRIPTION("ACCES 104-DIO-48E GPIO driver"); diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c index e37cd4cdda35..2d2763ea1a68 100644 --- a/drivers/gpio/gpio-104-idi-48.c +++ b/drivers/gpio/gpio-104-idi-48.c @@ -10,6 +10,9 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. + * + * This driver supports the following ACCES devices: 104-IDI-48A, + * 104-IDI-48AC, 104-IDI-48B, and 104-IDI-48BC. */ #include <linux/bitops.h> #include <linux/device.h> @@ -19,18 +22,23 @@ #include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/irqdesc.h> +#include <linux/isa.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/platform_device.h> #include <linux/spinlock.h> -static unsigned idi_48_base; -module_param(idi_48_base, uint, 0); -MODULE_PARM_DESC(idi_48_base, "ACCES 104-IDI-48 base address"); -static unsigned idi_48_irq; -module_param(idi_48_irq, uint, 0); -MODULE_PARM_DESC(idi_48_irq, "ACCES 104-IDI-48 interrupt line number"); +#define IDI_48_EXTENT 8 +#define MAX_NUM_IDI_48 max_num_isa_dev(IDI_48_EXTENT) + +static unsigned int base[MAX_NUM_IDI_48]; +static unsigned int num_idi_48; +module_param_array(base, uint, &num_idi_48, 0); +MODULE_PARM_DESC(base, "ACCES 104-IDI-48 base addresses"); + +static unsigned int irq[MAX_NUM_IDI_48]; +module_param_array(irq, uint, NULL, 0); +MODULE_PARM_DESC(irq, "ACCES 104-IDI-48 interrupt line numbers"); /** * struct idi_48_gpio - GPIO device private data structure @@ -211,23 +219,19 @@ static irqreturn_t idi_48_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } -static int __init idi_48_probe(struct platform_device *pdev) +static int idi_48_probe(struct device *dev, unsigned int id) { - struct device *dev = &pdev->dev; struct idi_48_gpio *idi48gpio; - const unsigned base = idi_48_base; - const unsigned extent = 8; const char *const name = dev_name(dev); int err; - const unsigned irq = idi_48_irq; idi48gpio = devm_kzalloc(dev, sizeof(*idi48gpio), GFP_KERNEL); if (!idi48gpio) return -ENOMEM; - if (!devm_request_region(dev, base, extent, name)) { + if (!devm_request_region(dev, base[id], IDI_48_EXTENT, name)) { dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", - base, base + extent); + base[id], base[id] + IDI_48_EXTENT); return -EBUSY; } @@ -239,10 +243,11 @@ static int __init idi_48_probe(struct platform_device *pdev) idi48gpio->chip.get_direction = idi_48_gpio_get_direction; idi48gpio->chip.direction_input = idi_48_gpio_direction_input; idi48gpio->chip.get = idi_48_gpio_get; - idi48gpio->base = base; - idi48gpio->irq = irq; + idi48gpio->base = base[id]; + idi48gpio->irq = irq[id]; spin_lock_init(&idi48gpio->lock); + spin_lock_init(&idi48gpio->ack_lock); dev_set_drvdata(dev, idi48gpio); @@ -253,8 +258,8 @@ static int __init idi_48_probe(struct platform_device *pdev) } /* Disable IRQ by default */ - outb(0, base + 7); - inb(base + 7); + outb(0, base[id] + 7); + inb(base[id] + 7); err = gpiochip_irqchip_add(&idi48gpio->chip, &idi_48_irqchip, 0, handle_edge_irq, IRQ_TYPE_NONE); @@ -263,7 +268,7 @@ static int __init idi_48_probe(struct platform_device *pdev) goto err_gpiochip_remove; } - err = request_irq(irq, idi_48_irq_handler, IRQF_SHARED, name, + err = request_irq(irq[id], idi_48_irq_handler, IRQF_SHARED, name, idi48gpio); if (err) { dev_err(dev, "IRQ handler registering failed (%d)\n", err); @@ -277,9 +282,9 @@ err_gpiochip_remove: return err; } -static int idi_48_remove(struct platform_device *pdev) +static int idi_48_remove(struct device *dev, unsigned int id) { - struct idi_48_gpio *const idi48gpio = platform_get_drvdata(pdev); + struct idi_48_gpio *const idi48gpio = dev_get_drvdata(dev); free_irq(idi48gpio->irq, idi48gpio); gpiochip_remove(&idi48gpio->chip); @@ -287,48 +292,14 @@ static int idi_48_remove(struct platform_device *pdev) return 0; } -static struct platform_device *idi_48_device; - -static struct platform_driver idi_48_driver = { +static struct isa_driver idi_48_driver = { + .probe = idi_48_probe, .driver = { .name = "104-idi-48" }, .remove = idi_48_remove }; - -static void __exit idi_48_exit(void) -{ - platform_device_unregister(idi_48_device); - platform_driver_unregister(&idi_48_driver); -} - -static int __init idi_48_init(void) -{ - int err; - - idi_48_device = platform_device_alloc(idi_48_driver.driver.name, -1); - if (!idi_48_device) - return -ENOMEM; - - err = platform_device_add(idi_48_device); - if (err) - goto err_platform_device; - - err = platform_driver_probe(&idi_48_driver, idi_48_probe); - if (err) - goto err_platform_driver; - - return 0; - -err_platform_driver: - platform_device_del(idi_48_device); -err_platform_device: - platform_device_put(idi_48_device); - return err; -} - -module_init(idi_48_init); -module_exit(idi_48_exit); +module_isa_driver(idi_48_driver, num_idi_48); MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); MODULE_DESCRIPTION("ACCES 104-IDI-48 GPIO driver"); diff --git a/drivers/gpio/gpio-104-idio-16.c b/drivers/gpio/gpio-104-idio-16.c index ecc85fe9323d..6787b8fcf0d8 100644 --- a/drivers/gpio/gpio-104-idio-16.c +++ b/drivers/gpio/gpio-104-idio-16.c @@ -10,6 +10,9 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. + * + * This driver supports the following ACCES devices: 104-IDIO-16, + * 104-IDIO-16E, 104-IDO-16, 104-IDIO-8, 104-IDIO-8E, and 104-IDO-8. */ #include <linux/bitops.h> #include <linux/device.h> @@ -19,18 +22,23 @@ #include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/irqdesc.h> +#include <linux/isa.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/platform_device.h> #include <linux/spinlock.h> -static unsigned idio_16_base; -module_param(idio_16_base, uint, 0); -MODULE_PARM_DESC(idio_16_base, "ACCES 104-IDIO-16 base address"); -static unsigned idio_16_irq; -module_param(idio_16_irq, uint, 0); -MODULE_PARM_DESC(idio_16_irq, "ACCES 104-IDIO-16 interrupt line number"); +#define IDIO_16_EXTENT 8 +#define MAX_NUM_IDIO_16 max_num_isa_dev(IDIO_16_EXTENT) + +static unsigned int base[MAX_NUM_IDIO_16]; +static unsigned int num_idio_16; +module_param_array(base, uint, &num_idio_16, 0); +MODULE_PARM_DESC(base, "ACCES 104-IDIO-16 base addresses"); + +static unsigned int irq[MAX_NUM_IDIO_16]; +module_param_array(irq, uint, NULL, 0); +MODULE_PARM_DESC(irq, "ACCES 104-IDIO-16 interrupt line numbers"); /** * struct idio_16_gpio - GPIO device private data structure @@ -185,23 +193,19 @@ static irqreturn_t idio_16_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } -static int __init idio_16_probe(struct platform_device *pdev) +static int idio_16_probe(struct device *dev, unsigned int id) { - struct device *dev = &pdev->dev; struct idio_16_gpio *idio16gpio; - const unsigned base = idio_16_base; - const unsigned extent = 8; const char *const name = dev_name(dev); int err; - const unsigned irq = idio_16_irq; idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL); if (!idio16gpio) return -ENOMEM; - if (!devm_request_region(dev, base, extent, name)) { + if (!devm_request_region(dev, base[id], IDIO_16_EXTENT, name)) { dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", - base, base + extent); + base[id], base[id] + IDIO_16_EXTENT); return -EBUSY; } @@ -215,8 +219,8 @@ static int __init idio_16_probe(struct platform_device *pdev) idio16gpio->chip.direction_output = idio_16_gpio_direction_output; idio16gpio->chip.get = idio_16_gpio_get; idio16gpio->chip.set = idio_16_gpio_set; - idio16gpio->base = base; - idio16gpio->irq = irq; + idio16gpio->base = base[id]; + idio16gpio->irq = irq[id]; idio16gpio->out_state = 0xFFFF; spin_lock_init(&idio16gpio->lock); @@ -230,8 +234,8 @@ static int __init idio_16_probe(struct platform_device *pdev) } /* Disable IRQ by default */ - outb(0, base + 2); - outb(0, base + 1); + outb(0, base[id] + 2); + outb(0, base[id] + 1); err = gpiochip_irqchip_add(&idio16gpio->chip, &idio_16_irqchip, 0, handle_edge_irq, IRQ_TYPE_NONE); @@ -240,7 +244,7 @@ static int __init idio_16_probe(struct platform_device *pdev) goto err_gpiochip_remove; } - err = request_irq(irq, idio_16_irq_handler, 0, name, idio16gpio); + err = request_irq(irq[id], idio_16_irq_handler, 0, name, idio16gpio); if (err) { dev_err(dev, "IRQ handler registering failed (%d)\n", err); goto err_gpiochip_remove; @@ -253,9 +257,9 @@ err_gpiochip_remove: return err; } -static int idio_16_remove(struct platform_device *pdev) +static int idio_16_remove(struct device *dev, unsigned int id) { - struct idio_16_gpio *const idio16gpio = platform_get_drvdata(pdev); + struct idio_16_gpio *const idio16gpio = dev_get_drvdata(dev); free_irq(idio16gpio->irq, idio16gpio); gpiochip_remove(&idio16gpio->chip); @@ -263,48 +267,15 @@ static int idio_16_remove(struct platform_device *pdev) return 0; } -static struct platform_device *idio_16_device; - -static struct platform_driver idio_16_driver = { +static struct isa_driver idio_16_driver = { + .probe = idio_16_probe, .driver = { .name = "104-idio-16" }, .remove = idio_16_remove }; -static void __exit idio_16_exit(void) -{ - platform_device_unregister(idio_16_device); - platform_driver_unregister(&idio_16_driver); -} - -static int __init idio_16_init(void) -{ - int err; - - idio_16_device = platform_device_alloc(idio_16_driver.driver.name, -1); - if (!idio_16_device) - return -ENOMEM; - - err = platform_device_add(idio_16_device); - if (err) - goto err_platform_device; - - err = platform_driver_probe(&idio_16_driver, idio_16_probe); - if (err) - goto err_platform_driver; - - return 0; - -err_platform_driver: - platform_device_del(idio_16_device); -err_platform_device: - platform_device_put(idio_16_device); - return err; -} - -module_init(idio_16_init); -module_exit(idio_16_exit); +module_isa_driver(idio_16_driver, num_idio_16); MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); MODULE_DESCRIPTION("ACCES 104-IDIO-16 GPIO driver"); diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 9aabc48ff5de..953e4b829e32 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -547,11 +547,11 @@ static void bcm_kona_gpio_reset(struct bcm_kona_gpio *kona_gpio) /* disable interrupts and clear status */ for (i = 0; i < kona_gpio->num_bank; i++) { /* Unlock the entire bank first */ - bcm_kona_gpio_write_lock_regs(kona_gpio, i, UNLOCK_CODE); + bcm_kona_gpio_write_lock_regs(reg_base, i, UNLOCK_CODE); writel(0xffffffff, reg_base + GPIO_INT_MASK(i)); writel(0xffffffff, reg_base + GPIO_INT_STATUS(i)); /* Now re-lock the bank */ - bcm_kona_gpio_write_lock_regs(kona_gpio, i, LOCK_CODE); + bcm_kona_gpio_write_lock_regs(reg_base, i, LOCK_CODE); } } diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c index d39014daeef9..fc5f197906ac 100644 --- a/drivers/gpio/gpio-lpc32xx.c +++ b/drivers/gpio/gpio-lpc32xx.c @@ -29,7 +29,6 @@ #include <mach/hardware.h> #include <mach/platform.h> -#include <mach/irqs.h> #define LPC32XX_GPIO_P3_INP_STATE _GPREG(0x000) #define LPC32XX_GPIO_P3_OUTP_SET _GPREG(0x004) @@ -371,61 +370,16 @@ static int lpc32xx_gpio_request(struct gpio_chip *chip, unsigned pin) static int lpc32xx_gpio_to_irq_p01(struct gpio_chip *chip, unsigned offset) { - return IRQ_LPC32XX_P0_P1_IRQ; + return -ENXIO; } -static const char lpc32xx_gpio_to_irq_gpio_p3_table[] = { - IRQ_LPC32XX_GPIO_00, - IRQ_LPC32XX_GPIO_01, - IRQ_LPC32XX_GPIO_02, - IRQ_LPC32XX_GPIO_03, - IRQ_LPC32XX_GPIO_04, - IRQ_LPC32XX_GPIO_05, -}; - static int lpc32xx_gpio_to_irq_gpio_p3(struct gpio_chip *chip, unsigned offset) { - if (offset < ARRAY_SIZE(lpc32xx_gpio_to_irq_gpio_p3_table)) - return lpc32xx_gpio_to_irq_gpio_p3_table[offset]; return -ENXIO; } -static const char lpc32xx_gpio_to_irq_gpi_p3_table[] = { - IRQ_LPC32XX_GPI_00, - IRQ_LPC32XX_GPI_01, - IRQ_LPC32XX_GPI_02, - IRQ_LPC32XX_GPI_03, - IRQ_LPC32XX_GPI_04, - IRQ_LPC32XX_GPI_05, - IRQ_LPC32XX_GPI_06, - IRQ_LPC32XX_GPI_07, - IRQ_LPC32XX_GPI_08, - IRQ_LPC32XX_GPI_09, - -ENXIO, /* 10 */ - -ENXIO, /* 11 */ - -ENXIO, /* 12 */ - -ENXIO, /* 13 */ - -ENXIO, /* 14 */ - -ENXIO, /* 15 */ - -ENXIO, /* 16 */ - -ENXIO, /* 17 */ - -ENXIO, /* 18 */ - IRQ_LPC32XX_GPI_19, - -ENXIO, /* 20 */ - -ENXIO, /* 21 */ - -ENXIO, /* 22 */ - -ENXIO, /* 23 */ - -ENXIO, /* 24 */ - -ENXIO, /* 25 */ - -ENXIO, /* 26 */ - -ENXIO, /* 27 */ - IRQ_LPC32XX_GPI_28, -}; - static int lpc32xx_gpio_to_irq_gpi_p3(struct gpio_chip *chip, unsigned offset) { - if (offset < ARRAY_SIZE(lpc32xx_gpio_to_irq_gpi_p3_table)) - return lpc32xx_gpio_to_irq_gpi_p3_table[offset]; return -ENXIO; } diff --git a/drivers/gpio/gpio-ws16c48.c b/drivers/gpio/gpio-ws16c48.c index 51f41e8fd21e..eaa71d440ccf 100644 --- a/drivers/gpio/gpio-ws16c48.c +++ b/drivers/gpio/gpio-ws16c48.c @@ -19,18 +19,23 @@ #include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/irqdesc.h> +#include <linux/isa.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/platform_device.h> #include <linux/spinlock.h> -static unsigned ws16c48_base; -module_param(ws16c48_base, uint, 0); -MODULE_PARM_DESC(ws16c48_base, "WinSystems WS16C48 base address"); -static unsigned ws16c48_irq; -module_param(ws16c48_irq, uint, 0); -MODULE_PARM_DESC(ws16c48_irq, "WinSystems WS16C48 interrupt line number"); +#define WS16C48_EXTENT 16 +#define MAX_NUM_WS16C48 max_num_isa_dev(WS16C48_EXTENT) + +static unsigned int base[MAX_NUM_WS16C48]; +static unsigned int num_ws16c48; +module_param_array(base, uint, &num_ws16c48, 0); +MODULE_PARM_DESC(base, "WinSystems WS16C48 base addresses"); + +static unsigned int irq[MAX_NUM_WS16C48]; +module_param_array(irq, uint, NULL, 0); +MODULE_PARM_DESC(irq, "WinSystems WS16C48 interrupt line numbers"); /** * struct ws16c48_gpio - GPIO device private data structure @@ -298,23 +303,19 @@ static irqreturn_t ws16c48_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } -static int __init ws16c48_probe(struct platform_device *pdev) +static int ws16c48_probe(struct device *dev, unsigned int id) { - struct device *dev = &pdev->dev; struct ws16c48_gpio *ws16c48gpio; - const unsigned base = ws16c48_base; - const unsigned extent = 16; const char *const name = dev_name(dev); int err; - const unsigned irq = ws16c48_irq; ws16c48gpio = devm_kzalloc(dev, sizeof(*ws16c48gpio), GFP_KERNEL); if (!ws16c48gpio) return -ENOMEM; - if (!devm_request_region(dev, base, extent, name)) { + if (!devm_request_region(dev, base[id], WS16C48_EXTENT, name)) { dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", - base, base + extent); + base[id], base[id] + WS16C48_EXTENT); return -EBUSY; } @@ -328,8 +329,8 @@ static int __init ws16c48_probe(struct platform_device *pdev) ws16c48gpio->chip.direction_output = ws16c48_gpio_direction_output; ws16c48gpio->chip.get = ws16c48_gpio_get; ws16c48gpio->chip.set = ws16c48_gpio_set; - ws16c48gpio->base = base; - ws16c48gpio->irq = irq; + ws16c48gpio->base = base[id]; + ws16c48gpio->irq = irq[id]; spin_lock_init(&ws16c48gpio->lock); @@ -342,11 +343,11 @@ static int __init ws16c48_probe(struct platform_device *pdev) } /* Disable IRQ by default */ - outb(0x80, base + 7); - outb(0, base + 8); - outb(0, base + 9); - outb(0, base + 10); - outb(0xC0, base + 7); + outb(0x80, base[id] + 7); + outb(0, base[id] + 8); + outb(0, base[id] + 9); + outb(0, base[id] + 10); + outb(0xC0, base[id] + 7); err = gpiochip_irqchip_add(&ws16c48gpio->chip, &ws16c48_irqchip, 0, handle_edge_irq, IRQ_TYPE_NONE); @@ -355,7 +356,7 @@ static int __init ws16c48_probe(struct platform_device *pdev) goto err_gpiochip_remove; } - err = request_irq(irq, ws16c48_irq_handler, IRQF_SHARED, name, + err = request_irq(irq[id], ws16c48_irq_handler, IRQF_SHARED, name, ws16c48gpio); if (err) { dev_err(dev, "IRQ handler registering failed (%d)\n", err); @@ -369,9 +370,9 @@ err_gpiochip_remove: return err; } -static int ws16c48_remove(struct platform_device *pdev) +static int ws16c48_remove(struct device *dev, unsigned int id) { - struct ws16c48_gpio *const ws16c48gpio = platform_get_drvdata(pdev); + struct ws16c48_gpio *const ws16c48gpio = dev_get_drvdata(dev); free_irq(ws16c48gpio->irq, ws16c48gpio); gpiochip_remove(&ws16c48gpio->chip); @@ -379,48 +380,15 @@ static int ws16c48_remove(struct platform_device *pdev) return 0; } -static struct platform_device *ws16c48_device; - -static struct platform_driver ws16c48_driver = { +static struct isa_driver ws16c48_driver = { + .probe = ws16c48_probe, .driver = { .name = "ws16c48" }, .remove = ws16c48_remove }; -static void __exit ws16c48_exit(void) -{ - platform_device_unregister(ws16c48_device); - platform_driver_unregister(&ws16c48_driver); -} - -static int __init ws16c48_init(void) -{ - int err; - - ws16c48_device = platform_device_alloc(ws16c48_driver.driver.name, -1); - if (!ws16c48_device) - return -ENOMEM; - - err = platform_device_add(ws16c48_device); - if (err) - goto err_platform_device; - - err = platform_driver_probe(&ws16c48_driver, ws16c48_probe); - if (err) - goto err_platform_driver; - - return 0; - -err_platform_driver: - platform_device_del(ws16c48_device); -err_platform_device: - platform_device_put(ws16c48_device); - return err; -} - -module_init(ws16c48_init); -module_exit(ws16c48_exit); +module_isa_driver(ws16c48_driver, num_ws16c48); MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); MODULE_DESCRIPTION("WinSystems WS16C48 GPIO driver"); diff --git a/drivers/gpio/gpio-xlp.c b/drivers/gpio/gpio-xlp.c index 08897dc11915..1a33a19d95b9 100644 --- a/drivers/gpio/gpio-xlp.c +++ b/drivers/gpio/gpio-xlp.c @@ -393,7 +393,7 @@ static int xlp_gpio_probe(struct platform_device *pdev) irq_base = irq_alloc_descs(-1, 0, gc->ngpio, 0); else irq_base = irq_alloc_descs(-1, XLP_GPIO_IRQ_BASE, gc->ngpio, 0); - if (IS_ERR_VALUE(irq_base)) { + if (irq_base < 0) { dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n"); return irq_base; } diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c index 75c6355b018d..e72794e463aa 100644 --- a/drivers/gpio/gpio-zynq.c +++ b/drivers/gpio/gpio-zynq.c @@ -709,7 +709,13 @@ static int zynq_gpio_probe(struct platform_device *pdev) dev_err(&pdev->dev, "input clock not found.\n"); return PTR_ERR(gpio->clk); } + ret = clk_prepare_enable(gpio->clk); + if (ret) { + dev_err(&pdev->dev, "Unable to enable clock.\n"); + return ret; + } + pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); ret = pm_runtime_get_sync(&pdev->dev); if (ret < 0) @@ -747,6 +753,7 @@ err_pm_put: pm_runtime_put(&pdev->dev); err_pm_dis: pm_runtime_disable(&pdev->dev); + clk_disable_unprepare(gpio->clk); return ret; } diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index d22dcc38179d..4aabddb38b59 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -16,6 +16,7 @@ #include <linux/errno.h> #include <linux/module.h> #include <linux/io.h> +#include <linux/io-mapping.h> #include <linux/gpio/consumer.h> #include <linux/of.h> #include <linux/of_address.h> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index d407f904a31c..570771ed19e6 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -20,6 +20,7 @@ #include <linux/cdev.h> #include <linux/fs.h> #include <linux/uaccess.h> +#include <linux/compat.h> #include <uapi/linux/gpio.h> #include "gpiolib.h" @@ -316,7 +317,7 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct gpio_device *gdev = filp->private_data; struct gpio_chip *chip = gdev->chip; - int __user *ip = (int __user *)arg; + void __user *ip = (void __user *)arg; /* We fail any subsequent ioctl():s when the chip is gone */ if (!chip) @@ -388,6 +389,14 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return -EINVAL; } +#ifdef CONFIG_COMPAT +static long gpio_ioctl_compat(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + return gpio_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)); +} +#endif + /** * gpio_chrdev_open() - open the chardev for ioctl operations * @inode: inode for this chardev @@ -431,14 +440,15 @@ static const struct file_operations gpio_fileops = { .owner = THIS_MODULE, .llseek = noop_llseek, .unlocked_ioctl = gpio_ioctl, - .compat_ioctl = gpio_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = gpio_ioctl_compat, +#endif }; static void gpiodevice_release(struct device *dev) { struct gpio_device *gdev = dev_get_drvdata(dev); - cdev_del(&gdev->chrdev); list_del(&gdev->list); ida_simple_remove(&gpio_ida, gdev->id); kfree(gdev->label); @@ -471,7 +481,6 @@ static int gpiochip_setup_dev(struct gpio_device *gdev) /* From this point, the .release() function cleans up gpio_device */ gdev->dev.release = gpiodevice_release; - get_device(&gdev->dev); pr_debug("%s: registered GPIOs %d to %d on device: %s (%s)\n", __func__, gdev->base, gdev->base + gdev->ngpio - 1, dev_name(&gdev->dev), gdev->chip->label ? : "generic"); @@ -618,6 +627,8 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data) goto err_free_label; } + spin_unlock_irqrestore(&gpio_lock, flags); + for (i = 0; i < chip->ngpio; i++) { struct gpio_desc *desc = &gdev->descs[i]; @@ -649,8 +660,6 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data) } } - spin_unlock_irqrestore(&gpio_lock, flags); - #ifdef CONFIG_PINCTRL INIT_LIST_HEAD(&gdev->pin_ranges); #endif @@ -759,6 +768,8 @@ void gpiochip_remove(struct gpio_chip *chip) * be removed, else it will be dangling until the last user is * gone. */ + cdev_del(&gdev->chrdev); + device_del(&gdev->dev); put_device(&gdev->dev); } EXPORT_SYMBOL_GPL(gpiochip_remove); @@ -858,7 +869,7 @@ struct gpio_chip *gpiochip_find(void *data, spin_lock_irqsave(&gpio_lock, flags); list_for_each_entry(gdev, &gpio_devices, list) - if (match(gdev->chip, data)) + if (gdev->chip && match(gdev->chip, data)) break; /* No match? */ @@ -1356,11 +1367,18 @@ done: /* * This descriptor validation needs to be inserted verbatim into each * function taking a descriptor, so we need to use a preprocessor - * macro to avoid endless duplication. + * macro to avoid endless duplication. If the desc is NULL it is an + * optional GPIO and calls should just bail out. */ #define VALIDATE_DESC(desc) do { \ - if (!desc || !desc->gdev) { \ - pr_warn("%s: invalid GPIO\n", __func__); \ + if (!desc) \ + return 0; \ + if (IS_ERR(desc)) { \ + pr_warn("%s: invalid GPIO (errorpointer)\n", __func__); \ + return PTR_ERR(desc); \ + } \ + if (!desc->gdev) { \ + pr_warn("%s: invalid GPIO (no device)\n", __func__); \ return -EINVAL; \ } \ if ( !desc->gdev->chip ) { \ @@ -1370,8 +1388,14 @@ done: } } while (0) #define VALIDATE_DESC_VOID(desc) do { \ - if (!desc || !desc->gdev) { \ - pr_warn("%s: invalid GPIO\n", __func__); \ + if (!desc) \ + return; \ + if (IS_ERR(desc)) { \ + pr_warn("%s: invalid GPIO (errorpointer)\n", __func__); \ + return; \ + } \ + if (!desc->gdev) { \ + pr_warn("%s: invalid GPIO (no device)\n", __func__); \ return; \ } \ if (!desc->gdev->chip) { \ @@ -2040,7 +2064,14 @@ int gpiod_to_irq(const struct gpio_desc *desc) struct gpio_chip *chip; int offset; - VALIDATE_DESC(desc); + /* + * Cannot VALIDATE_DESC() here as gpiod_to_irq() consumer semantics + * requires this function to not return zero on an invalid descriptor + * but rather a negative error number. + */ + if (!desc || IS_ERR(desc) || !desc->gdev || !desc->gdev->chip) + return -EINVAL; + chip = desc->gdev->chip; offset = gpio_chip_hwgpio(desc); if (chip->to_irq) { @@ -2066,17 +2097,30 @@ EXPORT_SYMBOL_GPL(gpiod_to_irq); */ int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset) { - if (offset >= chip->ngpio) - return -EINVAL; + struct gpio_desc *desc; + + desc = gpiochip_get_desc(chip, offset); + if (IS_ERR(desc)) + return PTR_ERR(desc); + + /* Flush direction if something changed behind our back */ + if (chip->get_direction) { + int dir = chip->get_direction(chip, offset); + + if (dir) + clear_bit(FLAG_IS_OUT, &desc->flags); + else + set_bit(FLAG_IS_OUT, &desc->flags); + } - if (test_bit(FLAG_IS_OUT, &chip->gpiodev->descs[offset].flags)) { + if (test_bit(FLAG_IS_OUT, &desc->flags)) { chip_err(chip, "%s: tried to flag a GPIO set as output for IRQ\n", __func__); return -EIO; } - set_bit(FLAG_USED_AS_IRQ, &chip->gpiodev->descs[offset].flags); + set_bit(FLAG_USED_AS_IRQ, &desc->flags); return 0; } EXPORT_SYMBOL_GPL(gpiochip_lock_as_irq); |