From 8944df726c7d2916764d18be8e944bd7ea3f2f51 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 5 Oct 2012 11:45:28 +0200 Subject: gpio/gpio-pl061: Covert to use devm_* functions Use the devm_* family of functions during probe to reduce the error handling code footprint. Signed-off-by: Tobias Klauser Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pl061.c | 59 ++++++++++++++++++----------------------------- 1 file changed, 22 insertions(+), 37 deletions(-) diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index b4b5da4fd2c..31d9c9e79ea 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -216,39 +216,34 @@ static void __init pl061_init_gc(struct pl061_gpio *chip, int irq_base) IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0); } -static int pl061_probe(struct amba_device *dev, const struct amba_id *id) +static int pl061_probe(struct amba_device *adev, const struct amba_id *id) { - struct pl061_platform_data *pdata; + struct device *dev = &adev->dev; + struct pl061_platform_data *pdata = dev->platform_data; struct pl061_gpio *chip; int ret, irq, i; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; - pdata = dev->dev.platform_data; if (pdata) { chip->gc.base = pdata->gpio_base; chip->irq_base = pdata->irq_base; - } else if (dev->dev.of_node) { + } else if (adev->dev.of_node) { chip->gc.base = -1; chip->irq_base = 0; - } else { - ret = -ENODEV; - goto free_mem; - } + } else + return -ENODEV; - if (!request_mem_region(dev->res.start, - resource_size(&dev->res), "pl061")) { - ret = -EBUSY; - goto free_mem; - } + if (!devm_request_mem_region(dev, adev->res.start, + resource_size(&adev->res), "pl061")) + return -EBUSY; - chip->base = ioremap(dev->res.start, resource_size(&dev->res)); - if (chip->base == NULL) { - ret = -ENOMEM; - goto release_region; - } + chip->base = devm_ioremap(dev, adev->res.start, + resource_size(&adev->res)); + if (chip->base == NULL) + return -ENOMEM; spin_lock_init(&chip->lock); @@ -258,13 +253,13 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) chip->gc.set = pl061_set_value; chip->gc.to_irq = pl061_to_irq; chip->gc.ngpio = PL061_GPIO_NR; - chip->gc.label = dev_name(&dev->dev); - chip->gc.dev = &dev->dev; + chip->gc.label = dev_name(dev); + chip->gc.dev = dev; chip->gc.owner = THIS_MODULE; ret = gpiochip_add(&chip->gc); if (ret) - goto iounmap; + return ret; /* * irq_chip support @@ -276,11 +271,10 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) pl061_init_gc(chip, chip->irq_base); writeb(0, chip->base + GPIOIE); /* disable irqs */ - irq = dev->irq[0]; - if (irq < 0) { - ret = -ENODEV; - goto iounmap; - } + irq = adev->irq[0]; + if (irq < 0) + return -ENODEV; + irq_set_chained_handler(irq, pl061_irq_handler); irq_set_handler_data(irq, chip); @@ -294,18 +288,9 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) } } - amba_set_drvdata(dev, chip); + amba_set_drvdata(adev, chip); return 0; - -iounmap: - iounmap(chip->base); -release_region: - release_mem_region(dev->res.start, resource_size(&dev->res)); -free_mem: - kfree(chip); - - return ret; } #ifdef CONFIG_PM -- cgit v1.2.3-18-g5258 From 086d585f13542de205c25fd225a37aa0cadc3be0 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 5 Oct 2012 11:37:38 +0200 Subject: gpio/gpio-omap: Use existing pointer to struct device A pointer to "pdev->dev" is already stored in "dev", so use it in devm_kzalloc. Signed-off-by: Tobias Klauser Acked-by: Kevin Hilman Signed-off-by: Linus Walleij --- drivers/gpio/gpio-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 94cbc842fbc..eb73dee0ab3 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1070,7 +1070,7 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) if (!pdata) return -EINVAL; - bank = devm_kzalloc(&pdev->dev, sizeof(struct gpio_bank), GFP_KERNEL); + bank = devm_kzalloc(dev, sizeof(struct gpio_bank), GFP_KERNEL); if (!bank) { dev_err(dev, "Memory alloc failed\n"); return -ENOMEM; -- cgit v1.2.3-18-g5258 From 04ed4279715f685857b8d5b84a48bf7bd43a36c5 Mon Sep 17 00:00:00 2001 From: Ashish Jangam Date: Fri, 14 Sep 2012 19:00:16 +0530 Subject: DA9055 GPIO driver This is the GPIO patch for the DA9055 PMIC. This patch has got dependency on the DA9055 MFD core. This patch is functionally tested on SMDK6410 board. Signed-off-by: David Dajun Chen Signed-off-by: Ashish Jangam Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 11 +++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-da9055.c | 204 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 216 insertions(+) create mode 100644 drivers/gpio/gpio-da9055.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d055cee3694..150eeb705fb 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -86,6 +86,17 @@ config GPIO_DA9052 help Say yes here to enable the GPIO driver for the DA9052 chip. +config GPIO_DA9055 + tristate "Dialog Semiconductor DA9055 GPIO" + depends on MFD_DA9055 + help + Say yes here to enable the GPIO driver for the DA9055 chip. + + The Dialog DA9055 PMIC chip has 3 GPIO pins that can be + be controller by this driver. + + If driver is built as a module it will be called gpio-da9055. + config GPIO_MAX730X tristate diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 9aeed670732..e6f8e379a2e 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o +obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o obj-$(CONFIG_GPIO_EM) += gpio-em.o obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o diff --git a/drivers/gpio/gpio-da9055.c b/drivers/gpio/gpio-da9055.c new file mode 100644 index 00000000000..55d83c7d9c7 --- /dev/null +++ b/drivers/gpio/gpio-da9055.c @@ -0,0 +1,204 @@ +/* + * GPIO Driver for Dialog DA9055 PMICs. + * + * Copyright(c) 2012 Dialog Semiconductor Ltd. + * + * Author: David Dajun Chen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include +#include +#include + +#include +#include +#include + +#define DA9055_VDD_IO 0x0 +#define DA9055_PUSH_PULL 0x3 +#define DA9055_ACT_LOW 0x0 +#define DA9055_GPI 0x1 +#define DA9055_PORT_MASK 0x3 +#define DA9055_PORT_SHIFT(offset) (4 * (offset % 2)) + +#define DA9055_INPUT DA9055_GPI +#define DA9055_OUTPUT DA9055_PUSH_PULL +#define DA9055_IRQ_GPI0 3 + +struct da9055_gpio { + struct da9055 *da9055; + struct gpio_chip gp; +}; + +static inline struct da9055_gpio *to_da9055_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct da9055_gpio, gp); +} + +static int da9055_gpio_get(struct gpio_chip *gc, unsigned offset) +{ + struct da9055_gpio *gpio = to_da9055_gpio(gc); + int gpio_direction = 0; + int ret; + + /* Get GPIO direction */ + ret = da9055_reg_read(gpio->da9055, (offset >> 1) + DA9055_REG_GPIO0_1); + if (ret < 0) + return ret; + + gpio_direction = ret & (DA9055_PORT_MASK) << DA9055_PORT_SHIFT(offset); + gpio_direction >>= DA9055_PORT_SHIFT(offset); + switch (gpio_direction) { + case DA9055_INPUT: + ret = da9055_reg_read(gpio->da9055, DA9055_REG_STATUS_B); + if (ret < 0) + return ret; + break; + case DA9055_OUTPUT: + ret = da9055_reg_read(gpio->da9055, DA9055_REG_GPIO_MODE0_2); + if (ret < 0) + return ret; + } + + return ret & (1 << offset); + +} + +static void da9055_gpio_set(struct gpio_chip *gc, unsigned offset, int value) +{ + struct da9055_gpio *gpio = to_da9055_gpio(gc); + + da9055_reg_update(gpio->da9055, + DA9055_REG_GPIO_MODE0_2, + 1 << offset, + value << offset); +} + +static int da9055_gpio_direction_input(struct gpio_chip *gc, unsigned offset) +{ + struct da9055_gpio *gpio = to_da9055_gpio(gc); + unsigned char reg_byte; + + reg_byte = (DA9055_ACT_LOW | DA9055_GPI) + << DA9055_PORT_SHIFT(offset); + + return da9055_reg_update(gpio->da9055, (offset >> 1) + + DA9055_REG_GPIO0_1, + DA9055_PORT_MASK << + DA9055_PORT_SHIFT(offset), + reg_byte); +} + +static int da9055_gpio_direction_output(struct gpio_chip *gc, + unsigned offset, int value) +{ + struct da9055_gpio *gpio = to_da9055_gpio(gc); + unsigned char reg_byte; + int ret; + + reg_byte = (DA9055_VDD_IO | DA9055_PUSH_PULL) + << DA9055_PORT_SHIFT(offset); + + ret = da9055_reg_update(gpio->da9055, (offset >> 1) + + DA9055_REG_GPIO0_1, + DA9055_PORT_MASK << + DA9055_PORT_SHIFT(offset), + reg_byte); + if (ret < 0) + return ret; + + da9055_gpio_set(gc, offset, value); + + return 0; +} + +static int da9055_gpio_to_irq(struct gpio_chip *gc, u32 offset) +{ + struct da9055_gpio *gpio = to_da9055_gpio(gc); + struct da9055 *da9055 = gpio->da9055; + + return regmap_irq_get_virq(da9055->irq_data, + DA9055_IRQ_GPI0 + offset); +} + +static struct gpio_chip reference_gp __devinitdata = { + .label = "da9055-gpio", + .owner = THIS_MODULE, + .get = da9055_gpio_get, + .set = da9055_gpio_set, + .direction_input = da9055_gpio_direction_input, + .direction_output = da9055_gpio_direction_output, + .to_irq = da9055_gpio_to_irq, + .can_sleep = 1, + .ngpio = 3, + .base = -1, +}; + +static int __devinit da9055_gpio_probe(struct platform_device *pdev) +{ + struct da9055_gpio *gpio; + struct da9055_pdata *pdata; + int ret; + + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); + if (gpio == NULL) + return -ENOMEM; + + gpio->da9055 = dev_get_drvdata(pdev->dev.parent); + pdata = gpio->da9055->dev->platform_data; + + gpio->gp = reference_gp; + if (pdata && pdata->gpio_base) + gpio->gp.base = pdata->gpio_base; + + ret = gpiochip_add(&gpio->gp); + if (ret < 0) { + dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); + goto err_mem; + } + + platform_set_drvdata(pdev, gpio); + + return 0; + +err_mem: + return ret; +} + +static int __devexit da9055_gpio_remove(struct platform_device *pdev) +{ + struct da9055_gpio *gpio = platform_get_drvdata(pdev); + + return gpiochip_remove(&gpio->gp); +} + +static struct platform_driver da9055_gpio_driver = { + .probe = da9055_gpio_probe, + .remove = __devexit_p(da9055_gpio_remove), + .driver = { + .name = "da9055-gpio", + .owner = THIS_MODULE, + }, +}; + +static int __init da9055_gpio_init(void) +{ + return platform_driver_register(&da9055_gpio_driver); +} +subsys_initcall(da9055_gpio_init); + +static void __exit da9055_gpio_exit(void) +{ + platform_driver_unregister(&da9055_gpio_driver); +} +module_exit(da9055_gpio_exit); + +MODULE_AUTHOR("David Dajun Chen "); +MODULE_DESCRIPTION("DA9055 GPIO Device Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:da9055-gpio"); -- cgit v1.2.3-18-g5258 From a3b8d4a513574e6adf76bcacad21c95ee6b8ce4b Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 9 Oct 2012 20:05:56 +0400 Subject: GPIO: Add support for GPIO on CLPS711X-target platform The CLPS711X CPUs provide some GPIOs for use in the system. This driver provides support for these via gpiolib. Due to platform limitations, driver does not support interrupts, only inputs and outputs. Signed-off-by: Alexander Shiyan Acked-by: Russell King Signed-off-by: Linus Walleij --- arch/arm/Kconfig | 1 + arch/arm/mach-clps711x/include/mach/gpio.h | 13 +++ drivers/gpio/Kconfig | 4 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-clps711x.c | 163 +++++++++++++++++++++++++++++ 5 files changed, 182 insertions(+) create mode 100644 arch/arm/mach-clps711x/include/mach/gpio.h create mode 100644 drivers/gpio/gpio-clps711x.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 73067efd484..f456cf4ae3c 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -364,6 +364,7 @@ config ARCH_CNS3XXX config ARCH_CLPS711X bool "Cirrus Logic CLPS711x/EP721x/EP731x-based" + select ARCH_REQUIRE_GPIOLIB select ARCH_USES_GETTIMEOFFSET select CLKDEV_LOOKUP select COMMON_CLK diff --git a/arch/arm/mach-clps711x/include/mach/gpio.h b/arch/arm/mach-clps711x/include/mach/gpio.h new file mode 100644 index 00000000000..8ac6889fabc --- /dev/null +++ b/arch/arm/mach-clps711x/include/mach/gpio.h @@ -0,0 +1,13 @@ +/* + * This file contains the CLPS711X GPIO definitions. + * + * Copyright (C) 2012 Alexander Shiyan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +/* Simple helper for convert port & pin to GPIO number */ +#define CLPS711X_GPIO(port, bit) ((port) * 8 + (bit)) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 150eeb705fb..9e3fb343871 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -102,6 +102,10 @@ config GPIO_MAX730X comment "Memory mapped GPIO drivers:" +config GPIO_CLPS711X + def_bool y + depends on ARCH_CLPS711X + config GPIO_GENERIC_PLATFORM tristate "Generic memory-mapped GPIO controller support (MMIO platform device)" select GPIO_GENERIC diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index e6f8e379a2e..1c1b63fcaeb 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o +obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c new file mode 100644 index 00000000000..ea21822b3de --- /dev/null +++ b/drivers/gpio/gpio-clps711x.c @@ -0,0 +1,163 @@ +/* + * CLPS711X GPIO driver + * + * Copyright (C) 2012 Alexander Shiyan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#define CLPS711X_GPIO_PORTS 5 +#define CLPS711X_GPIO_NAME "gpio-clps711x" + +struct clps711x_gpio { + struct gpio_chip chip[CLPS711X_GPIO_PORTS]; + spinlock_t lock; +}; + +static void __iomem *clps711x_ports[] = { + CLPS711X_VIRT_BASE + PADR, + CLPS711X_VIRT_BASE + PBDR, + CLPS711X_VIRT_BASE + PCDR, + CLPS711X_VIRT_BASE + PDDR, + CLPS711X_VIRT_BASE + PEDR, +}; + +static void __iomem *clps711x_pdirs[] = { + CLPS711X_VIRT_BASE + PADDR, + CLPS711X_VIRT_BASE + PBDDR, + CLPS711X_VIRT_BASE + PCDDR, + CLPS711X_VIRT_BASE + PDDDR, + CLPS711X_VIRT_BASE + PEDDR, +}; + +#define clps711x_port(x) clps711x_ports[x->base / 8] +#define clps711x_pdir(x) clps711x_pdirs[x->base / 8] + +static int gpio_clps711x_get(struct gpio_chip *chip, unsigned offset) +{ + return !!readb(clps711x_port(chip)) & (1 << offset); +} + +static void gpio_clps711x_set(struct gpio_chip *chip, unsigned offset, + int value) +{ + int tmp; + unsigned long flags; + struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); + + spin_lock_irqsave(&gpio->lock, flags); + tmp = readb(clps711x_port(chip)) & ~(1 << offset); + if (value) + tmp |= 1 << offset; + writeb(tmp, clps711x_port(chip)); + spin_unlock_irqrestore(&gpio->lock, flags); +} + +static int gpio_clps711x_direction_in(struct gpio_chip *chip, unsigned offset) +{ + int tmp; + unsigned long flags; + struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); + + spin_lock_irqsave(&gpio->lock, flags); + tmp = readb(clps711x_pdir(chip)) & ~(1 << offset); + writeb(tmp, clps711x_pdir(chip)); + spin_unlock_irqrestore(&gpio->lock, flags); + + return 0; +} + +static int gpio_clps711x_direction_out(struct gpio_chip *chip, unsigned offset, + int value) +{ + int tmp; + unsigned long flags; + struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); + + spin_lock_irqsave(&gpio->lock, flags); + tmp = readb(clps711x_pdir(chip)) | (1 << offset); + writeb(tmp, clps711x_pdir(chip)); + tmp = readb(clps711x_port(chip)) & ~(1 << offset); + if (value) + tmp |= 1 << offset; + writeb(tmp, clps711x_port(chip)); + spin_unlock_irqrestore(&gpio->lock, flags); + + return 0; +} + +struct clps711x_gpio_port { + char *name; + int nr; +}; + +static const struct clps711x_gpio_port clps711x_gpio_ports[] __initconst = { + { "PORTA", 8, }, + { "PORTB", 8, }, + { "PORTC", 8, }, + { "PORTD", 8, }, + { "PORTE", 3, }, +}; + +static int __init gpio_clps711x_init(void) +{ + int i; + struct platform_device *pdev; + struct clps711x_gpio *gpio; + + pdev = platform_device_alloc(CLPS711X_GPIO_NAME, 0); + if (!pdev) { + pr_err("Cannot create platform device: %s\n", + CLPS711X_GPIO_NAME); + return -ENOMEM; + } + + platform_device_add(pdev); + + gpio = devm_kzalloc(&pdev->dev, sizeof(struct clps711x_gpio), + GFP_KERNEL); + if (!gpio) { + dev_err(&pdev->dev, "GPIO allocating memory error\n"); + platform_device_del(pdev); + platform_device_put(pdev); + return -ENOMEM; + } + + platform_set_drvdata(pdev, gpio); + + spin_lock_init(&gpio->lock); + + for (i = 0; i < CLPS711X_GPIO_PORTS; i++) { + gpio->chip[i].owner = THIS_MODULE; + gpio->chip[i].dev = &pdev->dev; + gpio->chip[i].label = clps711x_gpio_ports[i].name; + gpio->chip[i].base = i * 8; + gpio->chip[i].ngpio = clps711x_gpio_ports[i].nr; + gpio->chip[i].direction_input = gpio_clps711x_direction_in; + gpio->chip[i].get = gpio_clps711x_get; + gpio->chip[i].direction_output = gpio_clps711x_direction_out; + gpio->chip[i].set = gpio_clps711x_set; + WARN_ON(gpiochip_add(&gpio->chip[i])); + } + + dev_info(&pdev->dev, "GPIO driver initialized\n"); + + return 0; +} +arch_initcall(gpio_clps711x_init); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Alexander Shiyan "); +MODULE_DESCRIPTION("CLPS711X GPIO driver"); -- cgit v1.2.3-18-g5258 From a6d7092a3460ebb32a63d691c5c3a1ff2a656424 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 15 Oct 2012 22:32:37 +0200 Subject: gpio: clps711x: delete local header This header file is unused and we shall not add new headers to the namespace. The macro may be reintroduced when there is a user for it. Cc: Alexander Shiyan Cc: Arnd Bergmann Cc: Russell King Signed-off-by: Linus Walleij --- arch/arm/mach-clps711x/include/mach/gpio.h | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 arch/arm/mach-clps711x/include/mach/gpio.h diff --git a/arch/arm/mach-clps711x/include/mach/gpio.h b/arch/arm/mach-clps711x/include/mach/gpio.h deleted file mode 100644 index 8ac6889fabc..00000000000 --- a/arch/arm/mach-clps711x/include/mach/gpio.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * This file contains the CLPS711X GPIO definitions. - * - * Copyright (C) 2012 Alexander Shiyan - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -/* Simple helper for convert port & pin to GPIO number */ -#define CLPS711X_GPIO(port, bit) ((port) * 8 + (bit)) -- cgit v1.2.3-18-g5258 From 67a0d4993d85ee2f42c9909127794553df69dd59 Mon Sep 17 00:00:00 2001 From: Tony Prisk Date: Thu, 18 Oct 2012 07:18:13 +1300 Subject: GPIO: vt8500: Add extended gpio bank for WM8505/WM8650 These SoC's have an extended bank of GPIO's seperate to the main GPIO block. This patch adds the additional 5 GPIO's located in this block which control I2C and PWMOUT. Signed-off-by: Tony Prisk Signed-off-by: Linus Walleij --- drivers/gpio/gpio-vt8500.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpio/gpio-vt8500.c b/drivers/gpio/gpio-vt8500.c index bcd8e4aa7c7..9ed2a2b347f 100644 --- a/drivers/gpio/gpio-vt8500.c +++ b/drivers/gpio/gpio-vt8500.c @@ -96,6 +96,7 @@ static struct vt8500_gpio_data wm8505_data = { VT8500_BANK(0x5C, 0x84, 0xAC, 0xD4, 12), VT8500_BANK(0x60, 0x88, 0xB0, 0xD8, 16), VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22), + VT8500_BANK(0x500, 0x504, 0x508, 0x50C, 6), }, }; @@ -115,6 +116,7 @@ static struct vt8500_gpio_data wm8650_data = { VT8500_BANK(0x58, 0x98, 0xD8, 0x18, 32), VT8500_BANK(0x5C, 0x9C, 0xDC, 0x1C, 32), VT8500_BANK(0x7C, 0xBC, 0xFC, 0x3C, 32), + VT8500_BANK(0x500, 0x504, 0x508, 0x50C, 6), }, }; -- cgit v1.2.3-18-g5258 From fc4e2514995d9cd7f3e1a67098ce65d72acf8ec7 Mon Sep 17 00:00:00 2001 From: Ryan Mallon Date: Mon, 22 Oct 2012 11:39:12 +1100 Subject: gpiolib: Refactor gpio_export The gpio_export function uses nested if statements and the status variable to handle the failure cases. This makes the function logic difficult to follow. Refactor the code to abort immediately on failure using goto. This makes the code slightly longer, but significantly reduces the nesting and number of split lines and makes the code easier to read. Signed-off-by: Ryan Mallon Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 85 +++++++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 39 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 5d6c71edc73..d5f9742d9ac 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -702,8 +702,9 @@ int gpio_export(unsigned gpio, bool direction_may_change) { unsigned long flags; struct gpio_desc *desc; - int status = -EINVAL; + int status; const char *ioname = NULL; + struct device *dev; /* can't export until sysfs is available ... */ if (!gpio_class.p) { @@ -711,59 +712,65 @@ int gpio_export(unsigned gpio, bool direction_may_change) return -ENOENT; } - if (!gpio_is_valid(gpio)) - goto done; + if (!gpio_is_valid(gpio)) { + pr_debug("%s: gpio %d is not valid\n", __func__, gpio); + return -EINVAL; + } mutex_lock(&sysfs_lock); spin_lock_irqsave(&gpio_lock, flags); desc = &gpio_desc[gpio]; - if (test_bit(FLAG_REQUESTED, &desc->flags) - && !test_bit(FLAG_EXPORT, &desc->flags)) { - status = 0; - if (!desc->chip->direction_input - || !desc->chip->direction_output) - direction_may_change = false; + if (!test_bit(FLAG_REQUESTED, &desc->flags) || + test_bit(FLAG_EXPORT, &desc->flags)) { + spin_unlock_irqrestore(&gpio_lock, flags); + pr_debug("%s: gpio %d unavailable (requested=%d, exported=%d)\n", + __func__, gpio, + test_bit(FLAG_REQUESTED, &desc->flags), + test_bit(FLAG_EXPORT, &desc->flags)); + return -EPERM; } + + if (!desc->chip->direction_input || !desc->chip->direction_output) + direction_may_change = false; spin_unlock_irqrestore(&gpio_lock, flags); if (desc->chip->names && desc->chip->names[gpio - desc->chip->base]) ioname = desc->chip->names[gpio - desc->chip->base]; - if (status == 0) { - struct device *dev; - - dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0), - desc, ioname ? ioname : "gpio%u", gpio); - if (!IS_ERR(dev)) { - status = sysfs_create_group(&dev->kobj, - &gpio_attr_group); - - if (!status && direction_may_change) - status = device_create_file(dev, - &dev_attr_direction); - - if (!status && gpio_to_irq(gpio) >= 0 - && (direction_may_change - || !test_bit(FLAG_IS_OUT, - &desc->flags))) - status = device_create_file(dev, - &dev_attr_edge); - - if (status != 0) - device_unregister(dev); - } else - status = PTR_ERR(dev); - if (status == 0) - set_bit(FLAG_EXPORT, &desc->flags); + dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0), + desc, ioname ? ioname : "gpio%u", gpio); + if (IS_ERR(dev)) { + status = PTR_ERR(dev); + goto fail_unlock; } - mutex_unlock(&sysfs_lock); - -done: + status = sysfs_create_group(&dev->kobj, &gpio_attr_group); if (status) - pr_debug("%s: gpio%d status %d\n", __func__, gpio, status); + goto fail_unregister_device; + + if (direction_may_change) { + status = device_create_file(dev, &dev_attr_direction); + if (status) + goto fail_unregister_device; + } + if (gpio_to_irq(gpio) >= 0 && (direction_may_change || + !test_bit(FLAG_IS_OUT, &desc->flags))) { + status = device_create_file(dev, &dev_attr_edge); + if (status) + goto fail_unregister_device; + } + + set_bit(FLAG_EXPORT, &desc->flags); + mutex_unlock(&sysfs_lock); + return 0; + +fail_unregister_device: + device_unregister(dev); +fail_unlock: + mutex_unlock(&sysfs_lock); + pr_debug("%s: gpio%d status %d\n", __func__, gpio, status); return status; } EXPORT_SYMBOL_GPL(gpio_export); -- cgit v1.2.3-18-g5258 From 41b3996e3b6825bd3a0624d62fde53fbad092ed0 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Wed, 24 Oct 2012 10:58:57 +0400 Subject: GPIO: clps711x: Fix return value for gpio_clps711x_get Signed-off-by: Alexander Shiyan Signed-off-by: Linus Walleij --- drivers/gpio/gpio-clps711x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c index ea21822b3de..0753b3a9a34 100644 --- a/drivers/gpio/gpio-clps711x.c +++ b/drivers/gpio/gpio-clps711x.c @@ -47,7 +47,7 @@ static void __iomem *clps711x_pdirs[] = { static int gpio_clps711x_get(struct gpio_chip *chip, unsigned offset) { - return !!readb(clps711x_port(chip)) & (1 << offset); + return !!(readb(clps711x_port(chip)) & (1 << offset)); } static void gpio_clps711x_set(struct gpio_chip *chip, unsigned offset, -- cgit v1.2.3-18-g5258 From d6a2fa0424aefe97289aa561444ec3ae09bdbba0 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Wed, 24 Oct 2012 12:34:46 +0400 Subject: GPIO: clps711x: Fix direction logic for PORTD PORTD have different direction logic, i.e. "0" is output and "1" is input. This patch fix this issue. Signed-off-by: Alexander Shiyan Signed-off-by: Linus Walleij --- drivers/gpio/gpio-clps711x.c | 65 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 51 insertions(+), 14 deletions(-) diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c index 0753b3a9a34..ad181db7950 100644 --- a/drivers/gpio/gpio-clps711x.c +++ b/drivers/gpio/gpio-clps711x.c @@ -65,7 +65,7 @@ static void gpio_clps711x_set(struct gpio_chip *chip, unsigned offset, spin_unlock_irqrestore(&gpio->lock, flags); } -static int gpio_clps711x_direction_in(struct gpio_chip *chip, unsigned offset) +static int gpio_clps711x_dir_in(struct gpio_chip *chip, unsigned offset) { int tmp; unsigned long flags; @@ -79,8 +79,8 @@ static int gpio_clps711x_direction_in(struct gpio_chip *chip, unsigned offset) return 0; } -static int gpio_clps711x_direction_out(struct gpio_chip *chip, unsigned offset, - int value) +static int gpio_clps711x_dir_out(struct gpio_chip *chip, unsigned offset, + int value) { int tmp; unsigned long flags; @@ -98,17 +98,49 @@ static int gpio_clps711x_direction_out(struct gpio_chip *chip, unsigned offset, return 0; } -struct clps711x_gpio_port { +static int gpio_clps711x_dir_in_inv(struct gpio_chip *chip, unsigned offset) +{ + int tmp; + unsigned long flags; + struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); + + spin_lock_irqsave(&gpio->lock, flags); + tmp = readb(clps711x_pdir(chip)) | (1 << offset); + writeb(tmp, clps711x_pdir(chip)); + spin_unlock_irqrestore(&gpio->lock, flags); + + return 0; +} + +static int gpio_clps711x_dir_out_inv(struct gpio_chip *chip, unsigned offset, + int value) +{ + int tmp; + unsigned long flags; + struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); + + spin_lock_irqsave(&gpio->lock, flags); + tmp = readb(clps711x_pdir(chip)) & ~(1 << offset); + writeb(tmp, clps711x_pdir(chip)); + tmp = readb(clps711x_port(chip)) & ~(1 << offset); + if (value) + tmp |= 1 << offset; + writeb(tmp, clps711x_port(chip)); + spin_unlock_irqrestore(&gpio->lock, flags); + + return 0; +} + +static struct { char *name; int nr; -}; - -static const struct clps711x_gpio_port clps711x_gpio_ports[] __initconst = { - { "PORTA", 8, }, - { "PORTB", 8, }, - { "PORTC", 8, }, - { "PORTD", 8, }, - { "PORTE", 3, }, + int inv_dir; +} clps711x_gpio_ports[] __initconst = { + { "PORTA", 8, 0, }, + { "PORTB", 8, 0, }, + { "PORTC", 8, 0, }, + { "PORTD", 8, 1, }, + { "PORTE", 3, 0, }, }; static int __init gpio_clps711x_init(void) @@ -145,10 +177,15 @@ static int __init gpio_clps711x_init(void) gpio->chip[i].label = clps711x_gpio_ports[i].name; gpio->chip[i].base = i * 8; gpio->chip[i].ngpio = clps711x_gpio_ports[i].nr; - gpio->chip[i].direction_input = gpio_clps711x_direction_in; gpio->chip[i].get = gpio_clps711x_get; - gpio->chip[i].direction_output = gpio_clps711x_direction_out; gpio->chip[i].set = gpio_clps711x_set; + if (!clps711x_gpio_ports[i].inv_dir) { + gpio->chip[i].direction_input = gpio_clps711x_dir_in; + gpio->chip[i].direction_output = gpio_clps711x_dir_out; + } else { + gpio->chip[i].direction_input = gpio_clps711x_dir_in_inv; + gpio->chip[i].direction_output = gpio_clps711x_dir_out_inv; + } WARN_ON(gpiochip_add(&gpio->chip[i])); } -- cgit v1.2.3-18-g5258 From 80b0a6029272247f19146bf8f88e5d4bba94cba5 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Wed, 24 Oct 2012 17:25:27 +0300 Subject: gpiolib: add gpio get direction callback support Add .get_direction callback to gpio_chip. This allows gpiolib to check the current direction of a gpio. Used to show the correct gpio direction in sysfs and debug entries. If callback is not set then gpiolib will work as previously; e.g. guessing everything is input until a direction is set. Signed-off-by: Mathias Nyman Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 38 +++++++++++++++++++++++++++++++++++++- include/asm-generic/gpio.h | 5 ++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index d5f9742d9ac..e468eed261c 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -191,6 +191,32 @@ err: return ret; } +/* caller ensures gpio is valid and requested, chip->get_direction may sleep */ +static int gpio_get_direction(unsigned gpio) +{ + struct gpio_chip *chip; + struct gpio_desc *desc = &gpio_desc[gpio]; + int status = -EINVAL; + + chip = gpio_to_chip(gpio); + gpio -= chip->base; + + if (!chip->get_direction) + return status; + + status = chip->get_direction(chip, gpio); + if (status > 0) { + /* GPIOF_DIR_IN, or other positive */ + status = 1; + clear_bit(FLAG_IS_OUT, &desc->flags); + } + if (status == 0) { + /* GPIOF_DIR_OUT */ + set_bit(FLAG_IS_OUT, &desc->flags); + } + return status; +} + #ifdef CONFIG_GPIO_SYSFS /* lock protects against unexport_gpio() being called while @@ -223,6 +249,7 @@ static ssize_t gpio_direction_show(struct device *dev, struct device_attribute *attr, char *buf) { const struct gpio_desc *desc = dev_get_drvdata(dev); + unsigned gpio = desc - gpio_desc; ssize_t status; mutex_lock(&sysfs_lock); @@ -230,6 +257,7 @@ static ssize_t gpio_direction_show(struct device *dev, if (!test_bit(FLAG_EXPORT, &desc->flags)) status = -EIO; else + gpio_get_direction(gpio); status = sprintf(buf, "%s\n", test_bit(FLAG_IS_OUT, &desc->flags) ? "out" : "in"); @@ -1080,6 +1108,7 @@ int gpiochip_add(struct gpio_chip *chip) * inputs (often with pullups enabled) so power * usage is minimized. Linux code should set the * gpio direction first thing; but until it does, + * and in case chip->get_direction is not set, * we may expose the wrong direction in sysfs. */ gpio_desc[id].flags = !chip->direction_input @@ -1231,9 +1260,15 @@ int gpio_request(unsigned gpio, const char *label) desc_set_label(desc, NULL); module_put(chip->owner); clear_bit(FLAG_REQUESTED, &desc->flags); + goto done; } } - + if (chip->get_direction) { + /* chip->get_direction may sleep */ + spin_unlock_irqrestore(&gpio_lock, flags); + gpio_get_direction(gpio); + spin_lock_irqsave(&gpio_lock, flags); + } done: if (status) pr_debug("gpio_request: gpio-%d (%s) status %d\n", @@ -1769,6 +1804,7 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) if (!test_bit(FLAG_REQUESTED, &gdesc->flags)) continue; + gpio_get_direction(gpio); is_out = test_bit(FLAG_IS_OUT, &gdesc->flags); seq_printf(s, " gpio-%-3d (%-20.20s) %s %s", gpio, gdesc->label, diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index a9432fc6b8b..eb70ca29597 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -56,6 +56,8 @@ struct device_node; * enabling module power and clock; may sleep * @free: optional hook for chip-specific deactivation, such as * disabling module power and clock; may sleep + * @get_direction: returns direction for signal "offset", 0=out, 1=in, + * (same as GPIOF_DIR_XXX), or negative error * @direction_input: configures signal "offset" as input, or returns error * @get: returns value for signal "offset"; for output signals this * returns either the value actually sensed, or zero @@ -100,7 +102,8 @@ struct gpio_chip { unsigned offset); void (*free)(struct gpio_chip *chip, unsigned offset); - + int (*get_direction)(struct gpio_chip *chip, + unsigned offset); int (*direction_input)(struct gpio_chip *chip, unsigned offset); int (*get)(struct gpio_chip *chip, -- cgit v1.2.3-18-g5258 From 529f2ad5e374f61987a8312603963c61d75a890a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 26 Oct 2012 09:59:43 +0300 Subject: gpiolib: unlock on error in gpio_export() We need to unlock here before returning. Signed-off-by: Dan Carpenter Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e468eed261c..fd2b71c7099 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -756,7 +756,8 @@ int gpio_export(unsigned gpio, bool direction_may_change) __func__, gpio, test_bit(FLAG_REQUESTED, &desc->flags), test_bit(FLAG_EXPORT, &desc->flags)); - return -EPERM; + status = -EPERM; + goto fail_unlock; } if (!desc->chip->direction_input || !desc->chip->direction_output) -- cgit v1.2.3-18-g5258 From d0235677311cbd404a3dcd3c0f24bf15dd24dd36 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 16 Oct 2012 21:00:09 +0200 Subject: gpio/tegra: convert to use linear irqdomain The Tegra driver tries to do the work of irq_domain_add_linear() by reserving a bunch of descriptors somewhere and keeping track of the base offset, then calling irq_domain_add_legacy(). Let's stop doing that and simply use the linear IRQ domain. For this to work: use irq_create_mapping() in the IRQ iterator so that the descriptors get allocated here. Cc: Rob Herring Cc: Grant Likely Tested-by: Stephen Warren Acked-by: Stephen Warren Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tegra.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index d982593d756..c7c175a4aff 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -380,7 +380,6 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) { const struct of_device_id *match; struct tegra_gpio_soc_config *config; - int irq_base; struct resource *res; struct tegra_gpio_bank *bank; int gpio; @@ -417,14 +416,11 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) return -ENODEV; } - irq_base = irq_alloc_descs(-1, 0, tegra_gpio_chip.ngpio, 0); - if (irq_base < 0) { - dev_err(&pdev->dev, "Couldn't allocate IRQ numbers\n"); - return -ENODEV; - } - irq_domain = irq_domain_add_legacy(pdev->dev.of_node, - tegra_gpio_chip.ngpio, irq_base, 0, + irq_domain = irq_domain_add_linear(pdev->dev.of_node, + tegra_gpio_chip.ngpio, &irq_domain_simple_ops, NULL); + if (!irq_domain) + return -ENODEV; for (i = 0; i < tegra_gpio_bank_count; i++) { res = platform_get_resource(pdev, IORESOURCE_IRQ, i); @@ -464,7 +460,7 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) gpiochip_add(&tegra_gpio_chip); for (gpio = 0; gpio < tegra_gpio_chip.ngpio; gpio++) { - int irq = irq_find_mapping(irq_domain, gpio); + int irq = irq_create_mapping(irq_domain, gpio); /* No validity check; all Tegra GPIOs are valid IRQs */ bank = &tegra_gpio_banks[GPIO_BANK(gpio)]; -- cgit v1.2.3-18-g5258 From ce931f571b6dcf8534e8740e8cd16565cf362536 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 16 Oct 2012 20:21:04 +0200 Subject: gpio/mvebu: convert to use irq_domain_add_simple() The MVEBU driver probably just wants a few IRQs. Using the simple domain has the upside of allocating IRQ descriptors if need be, especially in a SPARSE_IRQ environment. Cc: Rob Herring Cc: Grant Likely Cc: Thomas Petazzoni Cc: Sebastian Hesselbarth Cc: Andrew Lunn Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mvebu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 902af437eaf..e0bde063221 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -645,8 +645,8 @@ static int __devinit mvebu_gpio_probe(struct platform_device *pdev) IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE); /* Setup irq domain on top of the generic chip. */ - mvchip->domain = irq_domain_add_legacy(np, mvchip->chip.ngpio, - mvchip->irqbase, 0, + mvchip->domain = irq_domain_add_simple(np, mvchip->chip.ngpio, + mvchip->irqbase, &irq_domain_simple_ops, mvchip); if (!mvchip->domain) { -- cgit v1.2.3-18-g5258 From 7385500a49b769c95438c111aff92110b06ff751 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 16 Oct 2012 20:15:02 +0200 Subject: gpio/em: convert to linear IRQ domain The code in the em driver seems to want to try to do the job of the linear IRQ domain (allocate descriptors and grab a virtual range). So why not just use the linear IRQ domain? The code is now cut down so we don't need isolated functions for this. Also note that we use irq_create_mapping() to make sure descriptors are allocated for these IRQs. Also fixed the FIXME to remove the domain after use. Cc: Grant Likely Cc: Magnus Damm Signed-off-by: Linus Walleij --- drivers/gpio/gpio-em.c | 46 +++++++--------------------------------------- 1 file changed, 7 insertions(+), 39 deletions(-) diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index efb4c2d0d13..88bdfe37816 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -35,7 +35,6 @@ struct em_gio_priv { void __iomem *base0; void __iomem *base1; - unsigned int irq_base; spinlock_t sense_lock; struct platform_device *pdev; struct gpio_chip gpio_chip; @@ -214,7 +213,7 @@ static int em_gio_direction_output(struct gpio_chip *chip, unsigned offset, static int em_gio_to_irq(struct gpio_chip *chip, unsigned offset) { - return irq_find_mapping(gpio_to_priv(chip)->irq_domain, offset); + return irq_create_mapping(gpio_to_priv(chip)->irq_domain, offset); } static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int virq, @@ -234,40 +233,6 @@ static struct irq_domain_ops em_gio_irq_domain_ops = { .map = em_gio_irq_domain_map, }; -static int __devinit em_gio_irq_domain_init(struct em_gio_priv *p) -{ - struct platform_device *pdev = p->pdev; - struct gpio_em_config *pdata = pdev->dev.platform_data; - - p->irq_base = irq_alloc_descs(pdata->irq_base, 0, - pdata->number_of_pins, numa_node_id()); - if (p->irq_base < 0) { - dev_err(&pdev->dev, "cannot get irq_desc\n"); - return p->irq_base; - } - pr_debug("gio: hw base = %d, nr = %d, sw base = %d\n", - pdata->gpio_base, pdata->number_of_pins, p->irq_base); - - p->irq_domain = irq_domain_add_legacy(pdev->dev.of_node, - pdata->number_of_pins, - p->irq_base, 0, - &em_gio_irq_domain_ops, p); - if (!p->irq_domain) { - irq_free_descs(p->irq_base, pdata->number_of_pins); - return -ENXIO; - } - - return 0; -} - -static void em_gio_irq_domain_cleanup(struct em_gio_priv *p) -{ - struct gpio_em_config *pdata = p->pdev->dev.platform_data; - - irq_free_descs(p->irq_base, pdata->number_of_pins); - /* FIXME: irq domain wants to be freed! */ -} - static int __devinit em_gio_probe(struct platform_device *pdev) { struct gpio_em_config *pdata = pdev->dev.platform_data; @@ -334,8 +299,11 @@ static int __devinit em_gio_probe(struct platform_device *pdev) irq_chip->irq_set_type = em_gio_irq_set_type; irq_chip->flags = IRQCHIP_SKIP_SET_WAKE; - ret = em_gio_irq_domain_init(p); - if (ret) { + p->irq_domain = irq_domain_add_linear(pdev->dev.of_node, + pdata->number_of_pins, + &em_gio_irq_domain_ops, p); + if (!p->irq_domain) + err = -ENXIO; dev_err(&pdev->dev, "cannot initialize irq domain\n"); goto err3; } @@ -364,7 +332,7 @@ err6: err5: free_irq(irq[0]->start, pdev); err4: - em_gio_irq_domain_cleanup(p); + irq_domain_remove(p->irq_domain); err3: iounmap(p->base1); err2: -- cgit v1.2.3-18-g5258 From a362605b341d95e7209ead8052363cb28dda1c44 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 16 Oct 2012 19:43:53 +0200 Subject: gpio/tc3589x: convert to use the simple irqdomain The special checks for whether we have a base IRQ offset or not is surplus if we use the simple IRQ domain. The IRQ offset zero will be interpreted as a linear domain case. Plus this makes sure we allocate descriptors where need be, or warn if they are preallocated with SPARSE_IRQ. Cc: Grant Likely Cc: Rob Herring Cc: Lee Jones Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tc3589x.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index 1e48317e70f..8c8447c7d2a 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -292,17 +292,15 @@ static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio, { int base = tc3589x_gpio->irq_base; - if (base) { - tc3589x_gpio->domain = irq_domain_add_legacy( - NULL, tc3589x_gpio->chip.ngpio, base, - 0, &tc3589x_irq_ops, tc3589x_gpio); - } - else { - tc3589x_gpio->domain = irq_domain_add_linear( - np, tc3589x_gpio->chip.ngpio, - &tc3589x_irq_ops, tc3589x_gpio); - } - + /* + * If this results in a linear domain, irq_create_mapping() will + * take care of allocating IRQ descriptors at runtime. When a base + * is provided, the IRQ descriptors will be allocated when the + * domain is instantiated. + */ + tc3589x_gpio->domain = irq_domain_add_simple(np, + tc3589x_gpio->chip.ngpio, base, &tc3589x_irq_ops, + tc3589x_gpio); if (!tc3589x_gpio->domain) { dev_err(tc3589x_gpio->dev, "Failed to create irqdomain\n"); return -ENOSYS; -- cgit v1.2.3-18-g5258 From 2cad6a8a4c31175578943f087e1dbef9f52e6ec3 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 26 Oct 2012 23:15:05 +0800 Subject: GPIO: clps711x: use platform_device_unregister in gpio_clps711x_init() platform_device_unregister() only calls platform_device_del() and platform_device_put(), thus use platform_device_unregister() to simplify the code. Also the documents in platform.c shows that platform_device_del and platform_device_put must _only_ be externally called in error cases. All other usage is a bug. dpatch engine is used to auto generate this patch. (https://github.com/weiyj/dpatch) Signed-off-by: Wei Yongjun Signed-off-by: Linus Walleij --- drivers/gpio/gpio-clps711x.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c index ad181db7950..ce63b75b13f 100644 --- a/drivers/gpio/gpio-clps711x.c +++ b/drivers/gpio/gpio-clps711x.c @@ -162,8 +162,7 @@ static int __init gpio_clps711x_init(void) GFP_KERNEL); if (!gpio) { dev_err(&pdev->dev, "GPIO allocating memory error\n"); - platform_device_del(pdev); - platform_device_put(pdev); + platform_device_unregister(pdev); return -ENOMEM; } -- cgit v1.2.3-18-g5258 From 1631081993b1e6a6d668b3eb089904b88f0efc2b Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 31 Oct 2012 17:03:33 +0800 Subject: gpio: em: Fix build errors Fix below build errors: CC [M] drivers/gpio/gpio-em.o drivers/gpio/gpio-em.c: In function 'em_gio_probe': drivers/gpio/gpio-em.c:306: error: 'err' undeclared (first use in this function) drivers/gpio/gpio-em.c:306: error: (Each undeclared identifier is reported only once drivers/gpio/gpio-em.c:306: error: for each function it appears in.) drivers/gpio/gpio-em.c:308: error: label 'err3' used but not defined drivers/gpio/gpio-em.c:279: error: label 'err2' used but not defined drivers/gpio/gpio-em.c:265: error: label 'err1' used but not defined drivers/gpio/gpio-em.c:250: error: label 'err0' used but not defined drivers/gpio/gpio-em.c:309: warning: no return statement in function returning non-void drivers/gpio/gpio-em.c: At top level: drivers/gpio/gpio-em.c:311: error: expected identifier or '(' before 'if' drivers/gpio/gpio-em.c:317: error: expected identifier or '(' before 'if' drivers/gpio/gpio-em.c:323: warning: data definition has no type or storage class drivers/gpio/gpio-em.c:323: warning: type defaults to 'int' in declaration of 'ret' drivers/gpio/gpio-em.c:323: error: 'gpio_chip' undeclared here (not in a function) drivers/gpio/gpio-em.c:323: error: initializer element is not constant drivers/gpio/gpio-em.c:324: error: expected identifier or '(' before 'if' drivers/gpio/gpio-em.c:328: error: expected identifier or '(' before 'return' drivers/gpio/gpio-em.c:330: error: expected '=', ',', ';', 'asm' or '__attribute__' before ':' token drivers/gpio/gpio-em.c:332: error: expected '=', ',', ';', 'asm' or '__attribute__' before ':' token drivers/gpio/gpio-em.c:334: error: expected '=', ',', ';', 'asm' or '__attribute__' before ':' token drivers/gpio/gpio-em.c:336: error: expected '=', ',', ';', 'asm' or '__attribute__' before ':' token drivers/gpio/gpio-em.c:338: error: expected '=', ',', ';', 'asm' or '__attribute__' before ':' token drivers/gpio/gpio-em.c:340: error: expected '=', ',', ';', 'asm' or '__attribute__' before ':' token drivers/gpio/gpio-em.c:342: error: expected '=', ',', ';', 'asm' or '__attribute__' before ':' token drivers/gpio/gpio-em.c:344: error: expected identifier or '(' before '}' token drivers/gpio/gpio-em.c: In function 'em_gio_remove': drivers/gpio/gpio-em.c:361: error: implicit declaration of function 'em_gio_irq_domain_cleanup' make[2]: *** [drivers/gpio/gpio-em.o] Error 1 make[1]: *** [drivers/gpio] Error 2 make: *** [drivers] Error 2 Signed-off-by: Axel Lin Signed-off-by: Linus Walleij --- drivers/gpio/gpio-em.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index 88bdfe37816..b00706329d2 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -302,8 +302,8 @@ static int __devinit em_gio_probe(struct platform_device *pdev) p->irq_domain = irq_domain_add_linear(pdev->dev.of_node, pdata->number_of_pins, &em_gio_irq_domain_ops, p); - if (!p->irq_domain) - err = -ENXIO; + if (!p->irq_domain) { + ret = -ENXIO; dev_err(&pdev->dev, "cannot initialize irq domain\n"); goto err3; } @@ -358,7 +358,7 @@ static int __devexit em_gio_remove(struct platform_device *pdev) free_irq(irq[1]->start, pdev); free_irq(irq[0]->start, pdev); - em_gio_irq_domain_cleanup(p); + irq_domain_remove(p->irq_domain); iounmap(p->base1); iounmap(p->base0); kfree(p); -- cgit v1.2.3-18-g5258 From 5c868fc629b0e645a68aec3a6834d965e71531f4 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Fri, 2 Nov 2012 16:02:25 +0100 Subject: gpio-pch: Set parent dev for gpio chip This will show the gpio chip as a child node under /sys/bus/pci/devices/xxxx:xx:xx.x/ Signed-off-by: Alexander Stein Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pch.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index 4ad0c4f9171..e3a14fef79e 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -215,6 +215,7 @@ static void pch_gpio_setup(struct pch_gpio *chip) struct gpio_chip *gpio = &chip->gpio; gpio->label = dev_name(chip->dev); + gpio->dev = chip->dev; gpio->owner = THIS_MODULE; gpio->direction_input = pch_gpio_direction_input; gpio->get = pch_gpio_get; -- cgit v1.2.3-18-g5258 From 8939ddc76a2f3399be98a60246ae0b365442f008 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Wed, 7 Nov 2012 20:31:32 +0530 Subject: gpio: tegra: fix suspend/resume apis Following are changes done to fix the suspend/resume functionality of tegra gpio driver: - Protect suspend/resume callbacks with CONFIG_PM_SLEEP because CONFIG_PM doesn't actually enable any of the PM callbacks, it only allows to enable CONFIG_PM_SLEEP and CONFIG_PM_RUNTIME. This means if CONFIG_PM is used to protect system sleep callbacks then it may end up unreferenced if only runtime PM is enabled. - Fix the suspend/resume APIs declaration as per callback prototype. Signed-off-by: Laxman Dewangan Acked-by: Stephen Warren Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tegra.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index c7c175a4aff..da32754fb25 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -64,7 +65,7 @@ struct tegra_gpio_bank { int bank; int irq; spinlock_t lvl_lock[4]; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP u32 cnf[4]; u32 out[4]; u32 oe[4]; @@ -285,8 +286,8 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) } -#ifdef CONFIG_PM -void tegra_gpio_resume(void) +#ifdef CONFIG_PM_SLEEP +static int tegra_gpio_resume(struct device *dev) { unsigned long flags; int b; @@ -308,9 +309,10 @@ void tegra_gpio_resume(void) } local_irq_restore(flags); + return 0; } -void tegra_gpio_suspend(void) +static int tegra_gpio_suspend(struct device *dev) { unsigned long flags; int b; @@ -330,6 +332,7 @@ void tegra_gpio_suspend(void) } } local_irq_restore(flags); + return 0; } static int tegra_gpio_wake_enable(struct irq_data *d, unsigned int enable) @@ -345,11 +348,15 @@ static struct irq_chip tegra_gpio_irq_chip = { .irq_mask = tegra_gpio_irq_mask, .irq_unmask = tegra_gpio_irq_unmask, .irq_set_type = tegra_gpio_irq_set_type, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP .irq_set_wake = tegra_gpio_wake_enable, #endif }; +static const struct dev_pm_ops tegra_gpio_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(tegra_gpio_suspend, tegra_gpio_resume) +}; + struct tegra_gpio_soc_config { u32 bank_stride; u32 upper_offset; @@ -489,6 +496,7 @@ static struct platform_driver tegra_gpio_driver = { .driver = { .name = "tegra-gpio", .owner = THIS_MODULE, + .pm = &tegra_gpio_pm_ops, .of_match_table = tegra_gpio_of_match, }, .probe = tegra_gpio_probe, -- cgit v1.2.3-18-g5258 From 924a09873c658a23e416258c6f81348cba2cfe87 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 8 Nov 2012 10:45:24 +0800 Subject: gpio: tegra: Staticize non-exported symbols Both tegra_gpio_request() and tegra_gpio_free() are not referenced outside of this file, make them static. Signed-off-by: Axel Lin Acked-by: Stephen Warren Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tegra.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index da32754fb25..5ad4ceb14da 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -118,12 +118,12 @@ static void tegra_gpio_disable(int gpio) } EXPORT_SYMBOL_GPL(tegra_gpio_disable); -int tegra_gpio_request(struct gpio_chip *chip, unsigned offset) +static int tegra_gpio_request(struct gpio_chip *chip, unsigned offset) { return pinctrl_request_gpio(offset); } -void tegra_gpio_free(struct gpio_chip *chip, unsigned offset) +static void tegra_gpio_free(struct gpio_chip *chip, unsigned offset) { pinctrl_free_gpio(offset); tegra_gpio_disable(offset); -- cgit v1.2.3-18-g5258 From 65b6ca466748a8e0a906e40a470e1582bc565d79 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 8 Nov 2012 10:47:02 +0800 Subject: gpio: tegra: Drop exporting static functions Both tegra_gpio_enable() and tegra_gpio_disable() are static functions, it does not make sense to export them. Signed-off-by: Axel Lin Acked-by: Stephen Warren Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tegra.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 5ad4ceb14da..cfd9b723002 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -110,13 +110,11 @@ static void tegra_gpio_enable(int gpio) { tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 1); } -EXPORT_SYMBOL_GPL(tegra_gpio_enable); static void tegra_gpio_disable(int gpio) { tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 0); } -EXPORT_SYMBOL_GPL(tegra_gpio_disable); static int tegra_gpio_request(struct gpio_chip *chip, unsigned offset) { -- cgit v1.2.3-18-g5258 From 3764bdde1dc2fe53a87db1777440c2532cfccd58 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 8 Nov 2012 10:27:29 +0800 Subject: gpio: mvebu: Set free callback for gpio_chip We call pinctrl_request_gpio() in request callback, thus we need to call pinctrl_free_gpio() in free callback. Both mvebu_gpio_request() and mvebu_gpio_free() are not referenced outside of this file, make them static. Signed-off-by: Axel Lin Acked-by: Thomas Petazzoni Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mvebu.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index e0bde063221..8b306570356 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -163,12 +163,12 @@ static void __iomem *mvebu_gpioreg_level_mask(struct mvebu_gpio_chip *mvchip) * Functions implementing the gpio_chip methods */ -int mvebu_gpio_request(struct gpio_chip *chip, unsigned pin) +static int mvebu_gpio_request(struct gpio_chip *chip, unsigned pin) { return pinctrl_request_gpio(chip->base + pin); } -void mvebu_gpio_free(struct gpio_chip *chip, unsigned pin) +static void mvebu_gpio_free(struct gpio_chip *chip, unsigned pin) { pinctrl_free_gpio(chip->base + pin); } @@ -518,6 +518,7 @@ static int __devinit mvebu_gpio_probe(struct platform_device *pdev) mvchip->chip.label = dev_name(&pdev->dev); mvchip->chip.dev = &pdev->dev; mvchip->chip.request = mvebu_gpio_request; + mvchip->chip.free = mvebu_gpio_free; mvchip->chip.direction_input = mvebu_gpio_direction_input; mvchip->chip.get = mvebu_gpio_get; mvchip->chip.direction_output = mvebu_gpio_direction_output; -- cgit v1.2.3-18-g5258 From 55ecd26373bc995c279a5d988ee36c2767e4f3ca Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 8 Nov 2012 18:01:51 +0100 Subject: gpio: pca953x: Register an IRQ domain The PCA953x used to register no IRQ domain, which made it impossible to use it as an interrupt-parent from the device tree. Signed-off-by: Maxime Ripard Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pca953x.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 9c693ae1795..5ba7e60de94 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -83,6 +84,7 @@ struct pca953x_chip { u32 irq_trig_raise; u32 irq_trig_fall; int irq_base; + struct irq_domain *domain; #endif struct i2c_client *client; @@ -333,14 +335,14 @@ static void pca953x_irq_mask(struct irq_data *d) { struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); - chip->irq_mask &= ~(1 << (d->irq - chip->irq_base)); + chip->irq_mask &= ~(1 << d->hwirq); } static void pca953x_irq_unmask(struct irq_data *d) { struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); - chip->irq_mask |= 1 << (d->irq - chip->irq_base); + chip->irq_mask |= 1 << d->hwirq; } static void pca953x_irq_bus_lock(struct irq_data *d) @@ -372,8 +374,7 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) static int pca953x_irq_set_type(struct irq_data *d, unsigned int type) { struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); - u32 level = d->irq - chip->irq_base; - u32 mask = 1 << level; + u32 mask = 1 << d->hwirq; if (!(type & IRQ_TYPE_EDGE_BOTH)) { dev_err(&chip->client->dev, "irq %d: unsupported type %d\n", @@ -454,7 +455,7 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid) do { level = __ffs(pending); - handle_nested_irq(level + chip->irq_base); + handle_nested_irq(irq_find_mapping(chip->domain, level)); pending &= ~(1 << level); } while (pending); @@ -499,6 +500,17 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, if (chip->irq_base < 0) goto out_failed; + chip->domain = irq_domain_add_legacy(client->dev.of_node, + chip->gpio_chip.ngpio, + chip->irq_base, + 0, + &irq_domain_simple_ops, + NULL); + if (!chip->domain) { + ret = -ENODEV; + goto out_irqdesc_free; + } + for (lvl = 0; lvl < chip->gpio_chip.ngpio; lvl++) { int irq = lvl + chip->irq_base; @@ -521,7 +533,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, if (ret) { dev_err(&client->dev, "failed to request irq %d\n", client->irq); - goto out_failed; + goto out_irqdesc_free; } chip->gpio_chip.to_irq = pca953x_gpio_to_irq; @@ -529,6 +541,8 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, return 0; +out_irqdesc_free: + irq_free_descs(chip->irq_base, chip->gpio_chip.ngpio); out_failed: chip->irq_base = -1; return ret; -- cgit v1.2.3-18-g5258 From ed32620ea72889c8a9dda278a960bce01136d9a4 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 8 Nov 2012 18:01:52 +0100 Subject: gpio: pca953x: Add compatible strings to gpio-pca953x driver Even though the device tree binding code was already written, the compatible strings were not yet in the driver. Signed-off-by: Maxime Ripard Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pca953x.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 5ba7e60de94..0c5eaf5f4c9 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -765,9 +765,38 @@ static int pca953x_remove(struct i2c_client *client) return 0; } +static const struct of_device_id pca953x_dt_ids[] = { + { .compatible = "nxp,pca9534", }, + { .compatible = "nxp,pca9535", }, + { .compatible = "nxp,pca9536", }, + { .compatible = "nxp,pca9537", }, + { .compatible = "nxp,pca9538", }, + { .compatible = "nxp,pca9539", }, + { .compatible = "nxp,pca9554", }, + { .compatible = "nxp,pca9555", }, + { .compatible = "nxp,pca9556", }, + { .compatible = "nxp,pca9557", }, + { .compatible = "nxp,pca9574", }, + { .compatible = "nxp,pca9575", }, + + { .compatible = "maxim,max7310", }, + { .compatible = "maxim,max7312", }, + { .compatible = "maxim,max7313", }, + { .compatible = "maxim,max7315", }, + + { .compatible = "ti,pca6107", }, + { .compatible = "ti,tca6408", }, + { .compatible = "ti,tca6416", }, + { .compatible = "ti,tca6424", }, + { } +}; + +MODULE_DEVICE_TABLE(of, pca953x_dt_ids); + static struct i2c_driver pca953x_driver = { .driver = { .name = "pca953x", + .of_match_table = pca953x_dt_ids, }, .probe = pca953x_probe, .remove = pca953x_remove, -- cgit v1.2.3-18-g5258 From 195812e4b6a631e8eaad4046bf6890db4328ea1f Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 9 Nov 2012 11:34:20 +0530 Subject: gpio: tegra: read output value when gpio is set in direction_out Read the output value when gpio is set for the output mode for gpio_get_value(). Reading input value in direction out does not give correct value. Signed-off-by: Laxman Dewangan Acked-by: Stephen Warren Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tegra.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index cfd9b723002..5389be8c2b5 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -134,6 +134,11 @@ static void tegra_gpio_set(struct gpio_chip *chip, unsigned offset, int value) static int tegra_gpio_get(struct gpio_chip *chip, unsigned offset) { + /* If gpio is in output mode then read from the out value */ + if ((tegra_gpio_readl(GPIO_OE(offset)) >> GPIO_BIT(offset)) & 1) + return (tegra_gpio_readl(GPIO_OUT(offset)) >> + GPIO_BIT(offset)) & 0x1; + return (tegra_gpio_readl(GPIO_IN(offset)) >> GPIO_BIT(offset)) & 0x1; } -- cgit v1.2.3-18-g5258 From 9859eb99e9212339e2009b98c396b08260276edf Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 13 Nov 2012 10:35:13 +0100 Subject: gpio: twl4030: Use only TWL4030_MODULE_LED for LED configuration Avoid using the TWL4030_MODULE_PWMA/B as module ID. Th