From ebe5a0596f2ee4182dc42b39583be71e81aa0443 Mon Sep 17 00:00:00 2001 From: Tony Prisk Date: Mon, 31 Dec 2012 09:29:34 +1300 Subject: gpio: vt8500: Export dedicated GPIO before multifunction pins. The vendor does not provide numbering for gpio pins. Vendor source exports dedicated gpio pins first, followed by multifunction pins. As this is what end users expect, this patch changes vt8500 and wm8505 to do the same. Signed-off-by: Tony Prisk Signed-off-by: Linus Walleij --- drivers/gpio/gpio-vt8500.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-vt8500.c b/drivers/gpio/gpio-vt8500.c index b53320a16fc..9a7c434d294 100644 --- a/drivers/gpio/gpio-vt8500.c +++ b/drivers/gpio/gpio-vt8500.c @@ -73,19 +73,20 @@ struct vt8500_gpio_data { static struct vt8500_gpio_data vt8500_data = { .num_banks = 7, .banks = { + VT8500_BANK(NO_REG, 0x3C, 0x5C, 0x7C, 9), VT8500_BANK(0x00, 0x20, 0x40, 0x60, 26), VT8500_BANK(0x04, 0x24, 0x44, 0x64, 28), VT8500_BANK(0x08, 0x28, 0x48, 0x68, 31), VT8500_BANK(0x0C, 0x2C, 0x4C, 0x6C, 19), VT8500_BANK(0x10, 0x30, 0x50, 0x70, 19), VT8500_BANK(0x14, 0x34, 0x54, 0x74, 23), - VT8500_BANK(NO_REG, 0x3C, 0x5C, 0x7C, 9), }, }; static struct vt8500_gpio_data wm8505_data = { .num_banks = 10, .banks = { + VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22), VT8500_BANK(0x40, 0x68, 0x90, 0xB8, 8), VT8500_BANK(0x44, 0x6C, 0x94, 0xBC, 32), VT8500_BANK(0x48, 0x70, 0x98, 0xC0, 6), @@ -95,7 +96,6 @@ static struct vt8500_gpio_data wm8505_data = { VT8500_BANK(0x58, 0x80, 0xA8, 0xD0, 5), 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), }, }; -- cgit v1.2.3 From 72c7901ef00925c6d0cc7ab69183a684908303bc Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 6 Dec 2012 10:52:05 +0000 Subject: gpio: twl4030: Introduce private structure to store variables needed runtime Move most of the global variables inside a private structure and allocate it dynamically. Signed-off-by: Peter Ujfalusi Signed-off-by: Linus Walleij --- drivers/gpio/gpio-twl4030.c | 82 +++++++++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 32 deletions(-) diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index 9572aa137e6..4643f9cd0ca 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -49,11 +49,6 @@ * There are also two LED pins used sometimes as output-only GPIOs. */ - -static struct gpio_chip twl_gpiochip; -static int twl4030_gpio_base; -static int twl4030_gpio_irq_base; - /* genirq interfaces are not available to modules */ #ifdef MODULE #define is_module() true @@ -72,11 +67,20 @@ static int twl4030_gpio_irq_base; /* Data structures */ static DEFINE_MUTEX(gpio_lock); -/* store usage of each GPIO. - each bit represents one GPIO */ -static unsigned int gpio_usage_count; +struct gpio_twl4030_priv { + struct gpio_chip gpio_chip; + int irq_base; + + unsigned int usage_count; +}; /*----------------------------------------------------------------------*/ +static inline struct gpio_twl4030_priv *to_gpio_twl4030(struct gpio_chip *chip) +{ + return container_of(chip, struct gpio_twl4030_priv, gpio_chip); +} + /* * To configure TWL4030 GPIO module registers */ @@ -193,10 +197,6 @@ static int twl4030_get_gpio_datain(int gpio) u8 base = 0; int ret = 0; - if (unlikely((gpio >= TWL4030_GPIO_MAX) - || !(gpio_usage_count & BIT(gpio)))) - return -EPERM; - base = REG_GPIODATAIN1 + d_bnk; ret = gpio_twl4030_read(base); if (ret > 0) @@ -209,6 +209,7 @@ static int twl4030_get_gpio_datain(int gpio) static int twl_request(struct gpio_chip *chip, unsigned offset) { + struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); int status = 0; mutex_lock(&gpio_lock); @@ -252,7 +253,7 @@ static int twl_request(struct gpio_chip *chip, unsigned offset) } /* on first use, turn GPIO module "on" */ - if (!gpio_usage_count) { + if (!priv->usage_count) { struct twl4030_gpio_platform_data *pdata; u8 value = MASK_GPIO_CTRL_GPIO_ON; @@ -266,16 +267,18 @@ static int twl_request(struct gpio_chip *chip, unsigned offset) status = gpio_twl4030_write(REG_GPIO_CTRL, value); } +done: if (!status) - gpio_usage_count |= (0x1 << offset); + priv->usage_count |= BIT(offset); -done: mutex_unlock(&gpio_lock); return status; } static void twl_free(struct gpio_chip *chip, unsigned offset) { + struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); + if (offset >= TWL4030_GPIO_MAX) { twl4030_led_set_value(offset - TWL4030_GPIO_MAX, 1); return; @@ -283,10 +286,10 @@ static void twl_free(struct gpio_chip *chip, unsigned offset) mutex_lock(&gpio_lock); - gpio_usage_count &= ~BIT(offset); + priv->usage_count &= ~BIT(offset); /* on last use, switch off GPIO module */ - if (!gpio_usage_count) + if (!priv->usage_count) gpio_twl4030_write(REG_GPIO_CTRL, 0x0); mutex_unlock(&gpio_lock); @@ -301,14 +304,19 @@ static int twl_direction_in(struct gpio_chip *chip, unsigned offset) static int twl_get(struct gpio_chip *chip, unsigned offset) { + struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); int status = 0; + if (!(priv->usage_count & BIT(offset))) + return -EPERM; + if (offset < TWL4030_GPIO_MAX) status = twl4030_get_gpio_datain(offset); else if (offset == TWL4030_GPIO_MAX) status = cached_leden & LEDEN_LEDAON; else status = cached_leden & LEDEN_LEDBON; + return (status < 0) ? 0 : status; } @@ -333,12 +341,14 @@ static void twl_set(struct gpio_chip *chip, unsigned offset, int value) static int twl_to_irq(struct gpio_chip *chip, unsigned offset) { - return (twl4030_gpio_irq_base && (offset < TWL4030_GPIO_MAX)) - ? (twl4030_gpio_irq_base + offset) + struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); + + return (priv->irq_base && (offset < TWL4030_GPIO_MAX)) + ? (priv->irq_base + offset) : -EINVAL; } -static struct gpio_chip twl_gpiochip = { +static struct gpio_chip template_chip = { .label = "twl4030", .owner = THIS_MODULE, .request = twl_request, @@ -424,8 +434,14 @@ static int gpio_twl4030_probe(struct platform_device *pdev) { struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; struct device_node *node = pdev->dev.of_node; + struct gpio_twl4030_priv *priv; int ret, irq_base; + priv = devm_kzalloc(&pdev->dev, sizeof(struct gpio_twl4030_priv), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + /* maybe setup IRQs */ if (is_module()) { dev_err(&pdev->dev, "can't dispatch IRQs from modules\n"); @@ -445,12 +461,13 @@ static int gpio_twl4030_probe(struct platform_device *pdev) if (ret < 0) return ret; - twl4030_gpio_irq_base = irq_base; + priv->irq_base = irq_base; no_irqs: - twl_gpiochip.base = -1; - twl_gpiochip.ngpio = TWL4030_GPIO_MAX; - twl_gpiochip.dev = &pdev->dev; + priv->gpio_chip = template_chip; + priv->gpio_chip.base = -1; + priv->gpio_chip.ngpio = TWL4030_GPIO_MAX; + priv->gpio_chip.dev = &pdev->dev; if (node) pdata = of_gpio_twl4030(&pdev->dev); @@ -481,23 +498,23 @@ no_irqs: * is (still) clear if use_leds is set. */ if (pdata->use_leds) - twl_gpiochip.ngpio += 2; + priv->gpio_chip.ngpio += 2; - ret = gpiochip_add(&twl_gpiochip); + ret = gpiochip_add(&priv->gpio_chip); if (ret < 0) { dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret); - twl_gpiochip.ngpio = 0; + priv->gpio_chip.ngpio = 0; gpio_twl4030_remove(pdev); goto out; } - twl4030_gpio_base = twl_gpiochip.base; + platform_set_drvdata(pdev, priv); if (pdata && pdata->setup) { int status; - status = pdata->setup(&pdev->dev, - twl4030_gpio_base, TWL4030_GPIO_MAX); + status = pdata->setup(&pdev->dev, priv->gpio_chip.base, + TWL4030_GPIO_MAX); if (status) dev_dbg(&pdev->dev, "setup --> %d\n", status); } @@ -510,18 +527,19 @@ out: static int gpio_twl4030_remove(struct platform_device *pdev) { struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; + struct gpio_twl4030_priv *priv = platform_get_drvdata(pdev); int status; if (pdata && pdata->teardown) { - status = pdata->teardown(&pdev->dev, - twl4030_gpio_base, TWL4030_GPIO_MAX); + status = pdata->teardown(&pdev->dev, priv->gpio_chip.base, + TWL4030_GPIO_MAX); if (status) { dev_dbg(&pdev->dev, "teardown --> %d\n", status); return status; } } - status = gpiochip_remove(&twl_gpiochip); + status = gpiochip_remove(&priv->gpio_chip); if (status < 0) return status; -- cgit v1.2.3 From c111feabe2e200b15300d97107ffc1280bf8de2a Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 20 Dec 2012 10:44:11 +0100 Subject: gpio: twl4030: Cache the direction and output states in private data Use more coherent locking in the driver. Use bitfield to store the GPIO direction and if the pin is configured as output store the status also in a bitfiled. In this way we can just look at these bitfields when we need information about the pin status and only reach out to the chip when it is needed. Signed-off-by: Peter Ujfalusi Acked-by: Linus Walleij Signed-off-by: Linus Walleij --- drivers/gpio/gpio-twl4030.c | 100 ++++++++++++++++++++++++++++---------------- 1 file changed, 65 insertions(+), 35 deletions(-) diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index 4643f9cd0ca..4d330e36da1 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -37,7 +37,6 @@ #include - /* * The GPIO "subchip" supports 18 GPIOs which can be configured as * inputs or outputs, with pullups or pulldowns on each pin. Each @@ -64,14 +63,15 @@ /* Mask for GPIO registers when aggregated into a 32-bit integer */ #define GPIO_32_MASK 0x0003ffff -/* Data structures */ -static DEFINE_MUTEX(gpio_lock); - struct gpio_twl4030_priv { struct gpio_chip gpio_chip; + struct mutex mutex; int irq_base; + /* Bitfields for state caching */ unsigned int usage_count; + unsigned int direction; + unsigned int out_state; }; /*----------------------------------------------------------------------*/ @@ -130,7 +130,7 @@ static inline int gpio_twl4030_read(u8 address) /*----------------------------------------------------------------------*/ -static u8 cached_leden; /* protected by gpio_lock */ +static u8 cached_leden; /* The LED lines are open drain outputs ... a FET pulls to GND, so an * external pullup is needed. We could also expose the integrated PWM @@ -144,14 +144,12 @@ static void twl4030_led_set_value(int led, int value) if (led) mask <<= 1; - mutex_lock(&gpio_lock); if (value) cached_leden &= ~mask; else cached_leden |= mask; status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden, TWL4030_LED_LEDEN_REG); - mutex_unlock(&gpio_lock); } static int twl4030_set_gpio_direction(int gpio, int is_input) @@ -162,7 +160,6 @@ static int twl4030_set_gpio_direction(int gpio, int is_input) u8 base = REG_GPIODATADIR1 + d_bnk; int ret = 0; - mutex_lock(&gpio_lock); ret = gpio_twl4030_read(base); if (ret >= 0) { if (is_input) @@ -172,7 +169,6 @@ static int twl4030_set_gpio_direction(int gpio, int is_input) ret = gpio_twl4030_write(base, reg); } - mutex_unlock(&gpio_lock); return ret; } @@ -212,7 +208,7 @@ static int twl_request(struct gpio_chip *chip, unsigned offset) struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); int status = 0; - mutex_lock(&gpio_lock); + mutex_lock(&priv->mutex); /* Support the two LED outputs as output-only GPIOs. */ if (offset >= TWL4030_GPIO_MAX) { @@ -271,7 +267,7 @@ done: if (!status) priv->usage_count |= BIT(offset); - mutex_unlock(&gpio_lock); + mutex_unlock(&priv->mutex); return status; } @@ -279,64 +275,96 @@ static void twl_free(struct gpio_chip *chip, unsigned offset) { struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); + mutex_lock(&priv->mutex); if (offset >= TWL4030_GPIO_MAX) { twl4030_led_set_value(offset - TWL4030_GPIO_MAX, 1); - return; + goto out; } - mutex_lock(&gpio_lock); - priv->usage_count &= ~BIT(offset); /* on last use, switch off GPIO module */ if (!priv->usage_count) gpio_twl4030_write(REG_GPIO_CTRL, 0x0); - mutex_unlock(&gpio_lock); +out: + mutex_unlock(&priv->mutex); } static int twl_direction_in(struct gpio_chip *chip, unsigned offset) { - return (offset < TWL4030_GPIO_MAX) - ? twl4030_set_gpio_direction(offset, 1) - : -EINVAL; + struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); + int ret; + + mutex_lock(&priv->mutex); + if (offset < TWL4030_GPIO_MAX) + ret = twl4030_set_gpio_direction(offset, 1); + else + ret = -EINVAL; + + if (!ret) + priv->direction &= ~BIT(offset); + + mutex_unlock(&priv->mutex); + + return ret; } static int twl_get(struct gpio_chip *chip, unsigned offset) { struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); + int ret; int status = 0; - if (!(priv->usage_count & BIT(offset))) - return -EPERM; + mutex_lock(&priv->mutex); + if (!(priv->usage_count & BIT(offset))) { + ret = -EPERM; + goto out; + } - if (offset < TWL4030_GPIO_MAX) - status = twl4030_get_gpio_datain(offset); - else if (offset == TWL4030_GPIO_MAX) - status = cached_leden & LEDEN_LEDAON; + if (priv->direction & BIT(offset)) + status = priv->out_state & BIT(offset); else - status = cached_leden & LEDEN_LEDBON; + status = twl4030_get_gpio_datain(offset); - return (status < 0) ? 0 : status; + ret = (status <= 0) ? 0 : 1; +out: + mutex_unlock(&priv->mutex); + return ret; } -static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value) +static void twl_set(struct gpio_chip *chip, unsigned offset, int value) { - if (offset < TWL4030_GPIO_MAX) { + struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); + + mutex_lock(&priv->mutex); + if (offset < TWL4030_GPIO_MAX) twl4030_set_gpio_dataout(offset, value); - return twl4030_set_gpio_direction(offset, 0); - } else { + else twl4030_led_set_value(offset - TWL4030_GPIO_MAX, value); - return 0; - } + + if (value) + priv->out_state |= BIT(offset); + else + priv->out_state &= ~BIT(offset); + + mutex_unlock(&priv->mutex); } -static void twl_set(struct gpio_chip *chip, unsigned offset, int value) +static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value) { + struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); + + mutex_lock(&priv->mutex); if (offset < TWL4030_GPIO_MAX) twl4030_set_gpio_dataout(offset, value); - else - twl4030_led_set_value(offset - TWL4030_GPIO_MAX, value); + + priv->direction |= BIT(offset); + mutex_unlock(&priv->mutex); + + twl_set(chip, offset, value); + + return 0; } static int twl_to_irq(struct gpio_chip *chip, unsigned offset) @@ -469,6 +497,8 @@ no_irqs: priv->gpio_chip.ngpio = TWL4030_GPIO_MAX; priv->gpio_chip.dev = &pdev->dev; + mutex_init(&priv->mutex); + if (node) pdata = of_gpio_twl4030(&pdev->dev); -- cgit v1.2.3 From d59b4eaaf04db07a02f092bfcb00de7f2e2d10db Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Thu, 17 Jan 2013 22:03:22 +0800 Subject: gpio: fix warning of 'struct gpio_chip' declaration The struct gpio_chip is only defined inside #ifdef CONFIG_GPIOLIB, but it's referenced by gpiochip_add_pin_range() and gpiochip_remove_pin_ranges() which are outside #ifdef CONFIG_GPIOLIB. Thus, we see the following warning when building blackfin image, where GPIOLIB is not required. CC arch/blackfin/kernel/bfin_gpio.o CC init/version.o In file included from arch/blackfin/include/asm/gpio.h:321, from arch/blackfin/kernel/bfin_gpio.c:15: include/asm-generic/gpio.h:298: warning: 'struct gpio_chip' declared inside parameter list include/asm-generic/gpio.h:298: warning: its scope is only this definition or declaration, which is probably not what you want include/asm-generic/gpio.h:304: warning: 'struct gpio_chip' declared inside parameter list Move pinctrl trunk into #ifdef CONFIG_GPIOLIB to fix the warning, since it appears that pinctrl gpio range support depends on GPIOLIB. Signed-off-by: Shawn Guo Signed-off-by: Linus Walleij --- include/asm-generic/gpio.h | 74 +++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 20ca7663975..23410147555 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -212,6 +212,43 @@ extern void gpio_unexport(unsigned gpio); #endif /* CONFIG_GPIO_SYSFS */ +#ifdef CONFIG_PINCTRL + +/** + * struct gpio_pin_range - pin range controlled by a gpio chip + * @head: list for maintaining set of pin ranges, used internally + * @pctldev: pinctrl device which handles corresponding pins + * @range: actual range of pins controlled by a gpio controller + */ + +struct gpio_pin_range { + struct list_head node; + struct pinctrl_dev *pctldev; + struct pinctrl_gpio_range range; +}; + +int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, + unsigned int gpio_offset, unsigned int pin_offset, + unsigned int npins); +void gpiochip_remove_pin_ranges(struct gpio_chip *chip); + +#else + +static inline int +gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, + unsigned int gpio_offset, unsigned int pin_offset, + unsigned int npins) +{ + return 0; +} + +static inline void +gpiochip_remove_pin_ranges(struct gpio_chip *chip) +{ +} + +#endif /* CONFIG_PINCTRL */ + #else /* !CONFIG_GPIOLIB */ static inline bool gpio_is_valid(int number) @@ -270,41 +307,4 @@ static inline void gpio_unexport(unsigned gpio) } #endif /* CONFIG_GPIO_SYSFS */ -#ifdef CONFIG_PINCTRL - -/** - * struct gpio_pin_range - pin range controlled by a gpio chip - * @head: list for maintaining set of pin ranges, used internally - * @pctldev: pinctrl device which handles corresponding pins - * @range: actual range of pins controlled by a gpio controller - */ - -struct gpio_pin_range { - struct list_head node; - struct pinctrl_dev *pctldev; - struct pinctrl_gpio_range range; -}; - -int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, - unsigned int gpio_offset, unsigned int pin_offset, - unsigned int npins); -void gpiochip_remove_pin_ranges(struct gpio_chip *chip); - -#else - -static inline int -gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, - unsigned int gpio_offset, unsigned int pin_offset, - unsigned int npins) -{ - return 0; -} - -static inline void -gpiochip_remove_pin_ranges(struct gpio_chip *chip) -{ -} - -#endif /* CONFIG_PINCTRL */ - #endif /* _ASM_GENERIC_GPIO_H */ -- cgit v1.2.3 From 6a89a314ab107a12af08c71420c19a37a30fc2d3 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Fri, 18 Jan 2013 15:57:46 +0800 Subject: gpio: devm_gpio_* support should not depend on GPIOLIB Some architectures (e.g. blackfin) provide gpio API without requiring GPIOLIB support (ARCH_WANT_OPTIONAL_GPIOLIB). devm_gpio_* functions should also work for these architectures, since they do not really depend on GPIOLIB. Add a new option GPIO_DEVRES (enabled by default) to control the build of devres.c. It also removes the empty version of devm_gpio_* functions for !GENERIC_GPIO build from linux/gpio.h, and moves the function declarations from asm-generic/gpio.h into linux/gpio.h. Signed-off-by: Shawn Guo Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 3 +++ drivers/gpio/Makefile | 3 ++- include/asm-generic/gpio.h | 6 ------ include/linux/gpio.h | 28 ++++++++-------------------- 4 files changed, 13 insertions(+), 27 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 682de754d63..d9729322b1c 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -30,6 +30,9 @@ config ARCH_REQUIRE_GPIOLIB Selecting this from the architecture code will cause the gpiolib code to always get built in. +config GPIO_DEVRES + def_bool y + depends on HAS_IOMEM menuconfig GPIOLIB diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index c5aebd008dd..36ca605ff03 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -2,7 +2,8 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG -obj-$(CONFIG_GPIOLIB) += gpiolib.o devres.o +obj-$(CONFIG_GPIO_DEVRES) += devres.o +obj-$(CONFIG_GPIOLIB) += gpiolib.o obj-$(CONFIG_OF_GPIO) += gpiolib-of.o obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 23410147555..45b8916805f 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -192,12 +192,6 @@ extern int gpio_request_one(unsigned gpio, unsigned long flags, const char *labe extern int gpio_request_array(const struct gpio *array, size_t num); extern void gpio_free_array(const struct gpio *array, size_t num); -/* bindings for managed devices that want to request gpios */ -int devm_gpio_request(struct device *dev, unsigned gpio, const char *label); -int devm_gpio_request_one(struct device *dev, unsigned gpio, - unsigned long flags, const char *label); -void devm_gpio_free(struct device *dev, unsigned int gpio); - #ifdef CONFIG_GPIO_SYSFS /* diff --git a/include/linux/gpio.h b/include/linux/gpio.h index bfe66562153..f6c7ae3e223 100644 --- a/include/linux/gpio.h +++ b/include/linux/gpio.h @@ -94,24 +94,12 @@ static inline int gpio_request(unsigned gpio, const char *label) return -ENOSYS; } -static inline int devm_gpio_request(struct device *dev, unsigned gpio, - const char *label) -{ - return -ENOSYS; -} - static inline int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) { return -ENOSYS; } -static inline int devm_gpio_request_one(struct device *dev, unsigned gpio, - unsigned long flags, const char *label) -{ - return -ENOSYS; -} - static inline int gpio_request_array(const struct gpio *array, size_t num) { return -ENOSYS; @@ -125,14 +113,6 @@ static inline void gpio_free(unsigned gpio) WARN_ON(1); } -static inline void devm_gpio_free(struct device *dev, unsigned gpio) -{ - might_sleep(); - - /* GPIO can never have been requested */ - WARN_ON(1); -} - static inline void gpio_free_array(const struct gpio *array, size_t num) { might_sleep(); @@ -248,4 +228,12 @@ gpiochip_remove_pin_ranges(struct gpio_chip *chip) #endif /* ! CONFIG_GENERIC_GPIO */ +struct device; + +/* bindings for managed devices that want to request gpios */ +int devm_gpio_request(struct device *dev, unsigned gpio, const char *label); +int devm_gpio_request_one(struct device *dev, unsigned gpio, + unsigned long flags, const char *label); +void devm_gpio_free(struct device *dev, unsigned int gpio); + #endif /* __LINUX_GPIO_H */ -- cgit v1.2.3 From 5985d76cc1b62125301754c9b636a18c346bfc52 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Fri, 18 Jan 2013 15:31:13 +0800 Subject: gpio: pl061: set initcall level to module init Replace subsys initcall by module initcall level. Since pinctrl driver is already launched before gpio driver. It's unnecessary to set gpio driver in subsys init call level. Signed-off-by: Haojian Zhuang Tested-by: Dinh Nguyen Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pl061.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index c1720de18a4..b820869ca93 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -365,7 +365,7 @@ static int __init pl061_gpio_init(void) { return amba_driver_register(&pl061_gpio_driver); } -subsys_initcall(pl061_gpio_init); +module_init(pl061_gpio_init); MODULE_AUTHOR("Baruch Siach "); MODULE_DESCRIPTION("PL061 GPIO driver"); -- cgit v1.2.3 From f5f0b7aa897ebf6b0d077356a787526212460dd7 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Tue, 22 Jan 2013 22:10:23 +0100 Subject: gpio: pca953x: make the register access by GPIO bank Until now the pca953x driver accessed all the bank of a given register in a single command using only a 32 bits variable. New expanders from the pca53x family come with 40 GPIOs which no more fit in a 32 variable. This patch make access to the registers more generic by relying on an array of u8 variables. This fits exactly the way the registers are represented in the hardware. It also adds helpers to access to a single register of a bank instead of reading or writing all the banks for a given register. Signed-off-by: Gregory CLEMENT Tested-by: Maxime Ripard Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pca953x.c | 281 +++++++++++++++++++++++++++----------------- 1 file changed, 175 insertions(+), 106 deletions(-) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index cc102d25ee2..b35ba069016 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -71,18 +71,23 @@ static const struct i2c_device_id pca953x_id[] = { }; MODULE_DEVICE_TABLE(i2c, pca953x_id); +#define MAX_BANK 5 +#define BANK_SZ 8 + +#define NBANK(chip) (chip->gpio_chip.ngpio / BANK_SZ) + struct pca953x_chip { unsigned gpio_start; - u32 reg_output; - u32 reg_direction; + u8 reg_output[MAX_BANK]; + u8 reg_direction[MAX_BANK]; struct mutex i2c_lock; #ifdef CONFIG_GPIO_PCA953X_IRQ struct mutex irq_lock; - u32 irq_mask; - u32 irq_stat; - u32 irq_trig_raise; - u32 irq_trig_fall; + u8 irq_mask[MAX_BANK]; + u8 irq_stat[MAX_BANK]; + u8 irq_trig_raise[MAX_BANK]; + u8 irq_trig_fall[MAX_BANK]; int irq_base; struct irq_domain *domain; #endif @@ -93,33 +98,69 @@ struct pca953x_chip { int chip_type; }; -static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val) +static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val, + int off) +{ + int ret; + int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ); + int offset = off / BANK_SZ; + + ret = i2c_smbus_read_byte_data(chip->client, + (reg << bank_shift) + offset); + *val = ret; + + if (ret < 0) { + dev_err(&chip->client->dev, "failed reading register\n"); + return ret; + } + + return 0; +} + +static int pca953x_write_single(struct pca953x_chip *chip, int reg, u32 val, + int off) +{ + int ret = 0; + int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ); + int offset = off / BANK_SZ; + + ret = i2c_smbus_write_byte_data(chip->client, + (reg << bank_shift) + offset, val); + + if (ret < 0) { + dev_err(&chip->client->dev, "failed writing register\n"); + return ret; + } + + return 0; +} + +static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val) { int ret = 0; if (chip->gpio_chip.ngpio <= 8) - ret = i2c_smbus_write_byte_data(chip->client, reg, val); - else if (chip->gpio_chip.ngpio == 24) { - cpu_to_le32s(&val); + ret = i2c_smbus_write_byte_data(chip->client, reg, *val); + else if (chip->gpio_chip.ngpio >= 24) { + int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ); ret = i2c_smbus_write_i2c_block_data(chip->client, - (reg << 2) | REG_ADDR_AI, - 3, - (u8 *) &val); + (reg << bank_shift) | REG_ADDR_AI, + NBANK(chip), val); } else { switch (chip->chip_type) { case PCA953X_TYPE: ret = i2c_smbus_write_word_data(chip->client, - reg << 1, val); + reg << 1, (u16) *val); break; case PCA957X_TYPE: ret = i2c_smbus_write_byte_data(chip->client, reg << 1, - val & 0xff); + val[0]); if (ret < 0) break; ret = i2c_smbus_write_byte_data(chip->client, (reg << 1) + 1, - (val & 0xff00) >> 8); + val[1]); break; } } @@ -132,26 +173,24 @@ static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val) return 0; } -static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val) +static int pca953x_read_regs(struct pca953x_chip *chip, int reg, u8 *val) { int ret; if (chip->gpio_chip.ngpio <= 8) { ret = i2c_smbus_read_byte_data(chip->client, reg); *val = ret; - } - else if (chip->gpio_chip.ngpio == 24) { - *val = 0; + } else if (chip->gpio_chip.ngpio >= 24) { + int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ); + ret = i2c_smbus_read_i2c_block_data(chip->client, - (reg << 2) | REG_ADDR_AI, - 3, - (u8 *) val); - le32_to_cpus(val); + (reg << bank_shift) | REG_ADDR_AI, + NBANK(chip), val); } else { ret = i2c_smbus_read_word_data(chip->client, reg << 1); - *val = ret; + val[0] = (u16)ret & 0xFF; + val[1] = (u16)ret >> 8; } - if (ret < 0) { dev_err(&chip->client->dev, "failed reading register\n"); return ret; @@ -163,13 +202,13 @@ static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val) static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) { struct pca953x_chip *chip; - uint reg_val; + u8 reg_val; int ret, offset = 0; chip = container_of(gc, struct pca953x_chip, gpio_chip); mutex_lock(&chip->i2c_lock); - reg_val = chip->reg_direction | (1u << off); + reg_val = chip->reg_direction[off / BANK_SZ] | (1u << (off % BANK_SZ)); switch (chip->chip_type) { case PCA953X_TYPE: @@ -179,11 +218,11 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) offset = PCA957X_CFG; break; } - ret = pca953x_write_reg(chip, offset, reg_val); + ret = pca953x_write_single(chip, offset, reg_val, off); if (ret) goto exit; - chip->reg_direction = reg_val; + chip->reg_direction[off / BANK_SZ] = reg_val; ret = 0; exit: mutex_unlock(&chip->i2c_lock); @@ -194,7 +233,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, unsigned off, int val) { struct pca953x_chip *chip; - uint reg_val; + u8 reg_val; int ret, offset = 0; chip = container_of(gc, struct pca953x_chip, gpio_chip); @@ -202,9 +241,11 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, mutex_lock(&chip->i2c_lock); /* set output level */ if (val) - reg_val = chip->reg_output | (1u << off); + reg_val = chip->reg_output[off / BANK_SZ] + | (1u << (off % BANK_SZ)); else - reg_val = chip->reg_output & ~(1u << off); + reg_val = chip->reg_output[off / BANK_SZ] + & ~(1u << (off % BANK_SZ)); switch (chip->chip_type) { case PCA953X_TYPE: @@ -214,14 +255,14 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, offset = PCA957X_OUT; break; } - ret = pca953x_write_reg(chip, offset, reg_val); + ret = pca953x_write_single(chip, offset, reg_val, off); if (ret) goto exit; - chip->reg_output = reg_val; + chip->reg_output[off / BANK_SZ] = reg_val; /* then direction */ - reg_val = chip->reg_direction & ~(1u << off); + reg_val = chip->reg_direction[off / BANK_SZ] & ~(1u << (off % BANK_SZ)); switch (chip->chip_type) { case PCA953X_TYPE: offset = PCA953X_DIRECTION; @@ -230,11 +271,11 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, offset = PCA957X_CFG; break; } - ret = pca953x_write_reg(chip, offset, reg_val); + ret = pca953x_write_single(chip, offset, reg_val, off); if (ret) goto exit; - chip->reg_direction = reg_val; + chip->reg_direction[off / BANK_SZ] = reg_val; ret = 0; exit: mutex_unlock(&chip->i2c_lock); @@ -258,7 +299,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) offset = PCA957X_IN; break; } - ret = pca953x_read_reg(chip, offset, ®_val); + ret = pca953x_read_single(chip, offset, ®_val, off); mutex_unlock(&chip->i2c_lock); if (ret < 0) { /* NOTE: diagnostic already emitted; that's all we should @@ -274,16 +315,18 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) { struct pca953x_chip *chip; - u32 reg_val; + u8 reg_val; int ret, offset = 0; chip = container_of(gc, struct pca953x_chip, gpio_chip); mutex_lock(&chip->i2c_lock); if (val) - reg_val = chip->reg_output | (1u << off); + reg_val = chip->reg_output[off / BANK_SZ] + | (1u << (off % BANK_SZ)); else - reg_val = chip->reg_output & ~(1u << off); + reg_val = chip->reg_output[off / BANK_SZ] + & ~(1u << (off % BANK_SZ)); switch (chip->chip_type) { case PCA953X_TYPE: @@ -293,11 +336,11 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) offset = PCA957X_OUT; break; } - ret = pca953x_write_reg(chip, offset, reg_val); + ret = pca953x_write_single(chip, offset, reg_val, off); if (ret) goto exit; - chip->reg_output = reg_val; + chip->reg_output[off / BANK_SZ] = reg_val; exit: mutex_unlock(&chip->i2c_lock); } @@ -335,14 +378,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->hwirq); + chip->irq_mask[d->hwirq / BANK_SZ] &= ~(1 << (d->hwirq % BANK_SZ)); } 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->hwirq; + chip->irq_mask[d->hwirq / BANK_SZ] |= 1 << (d->hwirq % BANK_SZ); } static void pca953x_irq_bus_lock(struct irq_data *d) @@ -355,17 +398,20 @@ static void pca953x_irq_bus_lock(struct irq_data *d) static void pca953x_irq_bus_sync_unlock(struct irq_data *d) { struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); - u32 new_irqs; - u32 level; + u8 new_irqs; + int level, i; /* Look for any newly setup interrupt */ - new_irqs = chip->irq_trig_fall | chip->irq_trig_raise; - new_irqs &= ~chip->reg_direction; - - while (new_irqs) { - level = __ffs(new_irqs); - pca953x_gpio_direction_input(&chip->gpio_chip, level); - new_irqs &= ~(1 << level); + for (i = 0; i < NBANK(chip); i++) { + new_irqs = chip->irq_trig_fall[i] | chip->irq_trig_raise[i]; + new_irqs &= ~chip->reg_direction[i]; + + while (new_irqs) { + level = __ffs(new_irqs); + pca953x_gpio_direction_input(&chip->gpio_chip, + level + (BANK_SZ * i)); + new_irqs &= ~(1 << level); + } } mutex_unlock(&chip->irq_lock); @@ -374,7 +420,8 @@ 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 mask = 1 << d->hwirq; + int bank_nb = d->hwirq / BANK_SZ; + u8 mask = 1 << (d->hwirq % BANK_SZ); if (!(type & IRQ_TYPE_EDGE_BOTH)) { dev_err(&chip->client->dev, "irq %d: unsupported type %d\n", @@ -383,14 +430,14 @@ static int pca953x_irq_set_type(struct irq_data *d, unsigned int type) } if (type & IRQ_TYPE_EDGE_FALLING) - chip->irq_trig_fall |= mask; + chip->irq_trig_fall[bank_nb] |= mask; else - chip->irq_trig_fall &= ~mask; + chip->irq_trig_fall[bank_nb] &= ~mask; if (type & IRQ_TYPE_EDGE_RISING) - chip->irq_trig_raise |= mask; + chip->irq_trig_raise[bank_nb] |= mask; else - chip->irq_trig_raise &= ~mask; + chip->irq_trig_raise[bank_nb] &= ~mask; return 0; } @@ -404,13 +451,13 @@ static struct irq_chip pca953x_irq_chip = { .irq_set_type = pca953x_irq_set_type, }; -static u32 pca953x_irq_pending(struct pca953x_chip *chip) +static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending) { - u32 cur_stat; - u32 old_stat; - u32 pending; - u32 trigger; - int ret, offset = 0; + u8 cur_stat[MAX_BANK]; + u8 old_stat[MAX_BANK]; + u8 pendings = 0; + u8 trigger[MAX_BANK], triggers = 0; + int ret, i, offset = 0; switch (chip->chip_type) { case PCA953X_TYPE: @@ -420,45 +467,54 @@ static u32 pca953x_irq_pending(struct pca953x_chip *chip) offset = PCA957X_IN; break; } - ret = pca953x_read_reg(chip, offset, &cur_stat); + ret = pca953x_read_regs(chip, offset, cur_stat); if (ret) return 0; /* Remove output pins from the equation */ - cur_stat &= chip->reg_direction; + for (i = 0; i < NBANK(chip); i++) + cur_stat[i] &= chip->reg_direction[i]; - old_stat = chip->irq_stat; - trigger = (cur_stat ^ old_stat) & chip->irq_mask; + memcpy(old_stat, chip->irq_stat, NBANK(chip)); - if (!trigger) + for (i = 0; i < NBANK(chip); i++) { + trigger[i] = (cur_stat[i] ^ old_stat[i]) & chip->irq_mask[i]; + triggers += trigger[i]; + } + + if (!triggers) return 0; - chip->irq_stat = cur_stat; + memcpy(chip->irq_stat, cur_stat, NBANK(chip)); - pending = (old_stat & chip->irq_trig_fall) | - (cur_stat & chip->irq_trig_raise); - pending &= trigger; + for (i = 0; i < NBANK(chip); i++) { + pending[i] = (old_stat[i] & chip->irq_trig_fall[i]) | + (cur_stat[i] & chip->irq_trig_raise[i]); + pending[i] &= trigger[i]; + pendings += pending[i]; + } - return pending; + return pendings; } static irqreturn_t pca953x_irq_handler(int irq, void *devid) { struct pca953x_chip *chip = devid; - u32 pending; - u32 level; - - pending = pca953x_irq_pending(chip); + u8 pending[MAX_BANK]; + u8 level; + int i; - if (!pending) + if (!pca953x_irq_pending(chip, pending)) return IRQ_HANDLED; - do { - level = __ffs(pending); - handle_nested_irq(irq_find_mapping(chip->domain, level)); - - pending &= ~(1 << level); - } while (pending); + for (i = 0; i < NBANK(chip); i++) { + while (pending[i]) { + level = __ffs(pending[i]); + handle_nested_irq(irq_find_mapping(chip->domain, + level + (BANK_SZ * i))); + pending[i] &= ~(1 << level); + } + } return IRQ_HANDLED; } @@ -468,8 +524,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, int irq_base) { struct i2c_client *client = chip->client; - int ret, offset = 0; - u32 temporary; + int ret, i, offset = 0; if (irq_base != -1 && (id->driver_data & PCA_INT)) { @@ -483,8 +538,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, offset = PCA957X_IN; break; } - ret = pca953x_read_reg(chip, offset, &temporary); - chip->irq_stat = temporary; + ret = pca953x_read_regs(chip, offset, chip->irq_stat); if (ret) goto out_failed; @@ -493,7 +547,8 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, * interrupt. We have to rely on the previous read for * this purpose. */ - chip->irq_stat &= chip->reg_direction; + for (i = 0; i < NBANK(chip); i++) + chip->irq_stat[i] &= chip->reg_direction[i]; mutex_init(&chip->irq_lock); chip->irq_base = irq_alloc_descs(-1, irq_base, chip->gpio_chip.ngpio, -1); @@ -619,18 +674,24 @@ pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert) static int device_pca953x_init(struct pca953x_chip *chip, u32 invert) { int ret; + u8 val[MAX_BANK]; - ret = pca953x_read_reg(chip, PCA953X_OUTPUT, &chip->reg_output); + ret = pca953x_read_regs(chip, PCA953X_OUTPUT, chip->reg_output); if (ret) goto out; - ret = pca953x_read_reg(chip, PCA953X_DIRECTION, - &chip->reg_direction); + ret = pca953x_read_regs(chip, PCA953X_DIRECTION, + chip->reg_direction); if (ret) goto out; /* set platform specific polarity inversion */ - ret = pca953x_write_reg(chip, PCA953X_INVERT, invert); + if (invert) + memset(val, 0xFF, NBANK(chip)); + else + memset(val, 0, NBANK(chip)); + + ret = pca953x_write_regs(chip, PCA953X_INVERT, val); out: return ret; } @@ -638,28 +699,36 @@ out: static int device_pca957x_init(struct pca953x_chip *chip, u32 invert) { int ret; - u32 val = 0; + u8 val[MAX_BANK]; /* Let every port in proper state, that could save power */ - pca953x_write_reg(chip, PCA957X_PUPD, 0x0); - pca953x_write_reg(chip, PCA957X_CFG, 0xffff); - pca953x_write_reg(chip, PCA957X_OUT, 0x0); - - ret = pca953x_read_reg(chip, PCA957X_IN, &val); + memset(val, 0, NBANK(chip)); + pca953x_write_regs(chip, PCA957X_PUPD, val); + memset(val, 0xFF, NBANK(chip)); + pca953x_write_regs(chip, PCA957X_CFG, val); + memset(val, 0, NBANK(chip)); + pca953x_write_regs(chip, PCA957X_OUT, val); + + ret = pca953x_read_regs(chip, PCA957X_IN, val); if (ret) goto out; - ret = pca953x_read_reg(chip, PCA957X_OUT, &chip->reg_output); + ret = pca953x_read_regs(chip, PCA957X_OUT, chip->reg_output); if (ret) goto out; - ret = pca953x_read_reg(chip, PCA957X_CFG, &chip->reg_direction); + ret = pca953x_read_regs(chip, PCA957X_CFG, chip->reg_direction); if (ret) goto out; /* set platform specific polarity inversion */ - pca953x_write_reg(chip, PCA957X_INVRT, invert); + if (invert) + memset(val, 0xFF, NBANK(chip)); + else + memset(val, 0, NBANK(chip)); + pca953x_write_regs(chip, PCA957X_INVRT, val); /* To enable register 6, 7 to controll pull up and pull down */ - pca953x_write_reg(chip, PCA957X_BKEN, 0x202); + memset(val, 0x02, NBANK(chip)); + pca953x_write_regs(chip, PCA957X_BKEN, val); return 0; out: -- cgit v1.2.3 From 89f5df01c6b7f2471267bc55b1ecb196c98e195f Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Tue, 22 Jan 2013 22:10:24 +0100 Subject: gpio: pca953x: add support for pca9505 Now that pca953x driver can handle GPIO expanders with more than 32 bits this patch adds the support for the pca9505 which cam with 40 GPIOs. Signed-off-by: Gregory CLEMENT Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pca953x.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index b35ba069016..3a68aed9111 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -46,6 +46,7 @@ #define PCA957X_TYPE 0x2000 static const struct i2c_device_id pca953x_id[] = { + { "pca9505", 40 | PCA953X_TYPE | PCA_INT, }, { "pca9534", 8 | PCA953X_TYPE | PCA_INT, }, { "pca9535", 16 | PCA953X_TYPE | PCA_INT, }, { "pca9536", 4 | PCA953X_TYPE, }, @@ -835,6 +836,7 @@ static int pca953x_remove(struct i2c_client *client) } static const struct of_device_id pca953x_dt_ids[] = { + { .compatible = "nxp,pca9505", }, { .compatible = "nxp,pca9534", }, { .compatible = "nxp,pca9535", }, { .compatible = "nxp,pca9536", }, -- cgit v1.2.3 From 6c7e660a27da7494c670bfba21cfeba30457656c Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Wed, 23 Jan 2013 16:25:45 +0800 Subject: gpio: pxa: set initcall level to module init gpio & pinctrl driver are used together. The pinctrl driver is already launched before gpio driver in Makefile. So set gpio driver to module init level. Otherwise, the sequence will be inverted. Signed-off-by: Haojian Zhuang Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pxa.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index 8325f580c0f..9cc108d2b77 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -642,12 +642,7 @@ static struct platform_driver pxa_gpio_driver = { .of_match_table = of_match_ptr(pxa_gpio_dt_ids), }, }; - -static int __init pxa_gpio_init(void) -{ - return platform_driver_register(&pxa_gpio_driver); -} -postcore_initcall(pxa_gpio_init); +module_platform_driver(pxa_gpio_driver); #ifdef CONFIG_PM static int pxa_gpio_suspend(void) -- cgit v1.2.3 From 0e8f2fdacf1d44651aa7e57063c76142d1f4988b Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Fri, 25 Jan 2013 17:59:27 +0100 Subject: gpio: pca953x: use simple irqdomain This switches the legacy irqdomain to the simple one, which will auto-allocate descriptors, and also make sure that we use irq_create_mapping() in the to_irq function. Also use the map function of irq_domain_ops to setup the irq configuration on demand and no more statically during the initialization of the driver. Based on a initial patch from Linus Walleij Signed-off-by: Gregory CLEMENT Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pca953x.c | 65 +++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 37 deletions(-) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 3a68aed9111..1dc99062eb1 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -89,7 +89,6 @@ struct pca953x_chip { u8 irq_stat[MAX_BANK]; u8 irq_trig_raise[MAX_BANK]; u8 irq_trig_fall[MAX_BANK]; - int irq_base; struct irq_domain *domain; #endif @@ -372,7 +371,7 @@ static int pca953x_gpio_to_irq(struct gpio_chip *gc, unsigned off) struct pca953x_chip *chip; chip = container_of(gc, struct pca953x_chip, gpio_chip); - return chip->irq_base + off; + return irq_create_mapping(chip->domain, off); } static void pca953x_irq_mask(struct irq_data *d) @@ -520,6 +519,27 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid) return IRQ_HANDLED; } +static int pca953x_gpio_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + irq_clear_status_flags(irq, IRQ_NOREQUEST); + irq_set_chip_data(irq, d->host_data); + irq_set_chip(irq, &pca953x_irq_chip); + irq_set_nested_thread(irq, true); +#ifdef CONFIG_ARM + set_irq_flags(irq, IRQF_VALID); +#else + irq_set_noprobe(irq); +#endif + + return 0; +} + +static const struct irq_domain_ops pca953x_irq_simple_ops = { + .map = pca953x_gpio_irq_map, + .xlate = irq_domain_xlate_twocell, +}; + static int pca953x_irq_setup(struct pca953x_chip *chip, const struct i2c_device_id *id, int irq_base) @@ -529,7 +549,6 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, if (irq_base != -1 && (id->driver_data & PCA_INT)) { - int lvl; switch (chip->chip_type) { case PCA953X_TYPE: @@ -552,34 +571,13 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, chip->irq_stat[i] &= chip->reg_direction[i]; mutex_init(&chip->irq_lock); - chip->irq_base = irq_alloc_descs(-1, irq_base, chip->gpio_chip.ngpio, -1); - if (chip->irq_base < 0) - goto out_failed; - - chip->domain = irq_domain_add_legacy(client->dev.of_node, + chip->domain = irq_domain_add_simple(client->dev.of_node, chip->gpio_chip.ngpio, - chip->irq_base, - 0, - &irq_domain_simple_ops, + irq_base, + &pca953x_irq_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; - - irq_clear_status_flags(irq, IRQ_NOREQUEST); - irq_set_chip_data(irq, chip); - irq_set_chip(irq, &pca953x_irq_chip); - irq_set_nested_thread(irq, true); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else - irq_set_noprobe(irq); -#endif - } + if (!chip->domain) + return -ENODEV; ret = request_threaded_irq(client->irq, NULL, @@ -589,25 +587,18 @@ 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_irqdesc_free; + return ret; } chip->gpio_chip.to_irq = pca953x_gpio_to_irq; } return 0; - -out_irqdesc_free: - irq_free_descs(chip->irq_base, chip->gpio_chip.ngpio); -out_failed: - chip->irq_base = -1; - return ret; } static void pca953x_irq_teardown(struct pca953x_chip *chip) { if (chip->irq_base != -1) { - irq_free_descs(chip->irq_base, chip->gpio_chip.ngpio); free_irq(chip->client->irq, chip); } } -- cgit v1.2.3 From b42748c970d1865685749960cb23f08e259a9f86 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 25 Jan 2013 17:59:28 +0100 Subject: gpio: pca953x: use managed resources Using the devm_* managed resources the pca driver can be simplified and cut down on boilerplate code. [gcl: fixed a inccorect reference to a removed label, "goto fail_out" became "return ret"] Signed-off-by: Linus Walleij Signed-off-by: Gregory CLEMENT Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pca953x.c | 32 ++++++++------------------------ 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 1dc99062eb1..24059462c87 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -560,7 +560,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, } ret = pca953x_read_regs(chip, offset, chip->irq_stat); if (ret) - goto out_failed; + return ret; /* * There is no way to know which GPIO line generated the @@ -579,7 +579,8 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, if (!chip->domain) return -ENODEV; - ret = request_threaded_irq(client->irq, + ret = devm_request_threaded_irq(&client->dev, + client->irq, NULL, pca953x_irq_handler, IRQF_TRIGGER_LOW | IRQF_ONESHOT, @@ -596,12 +597,6 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, return 0; } -static void pca953x_irq_teardown(struct pca953x_chip *chip) -{ - if (chip->irq_base != -1) { - free_irq(chip->client->irq, chip); - } -} #else /* CONFIG_GPIO_PCA953X_IRQ */ static int pca953x_irq_setup(struct pca953x_chip *chip, const struct i2c_device_id *id, @@ -614,10 +609,6 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, return 0; } - -static void pca953x_irq_teardown(struct pca953x_chip *chip) -{ -} #endif /* @@ -736,7 +727,8 @@ static int pca953x_probe(struct i2c_client *client, int ret; u32 invert = 0; - chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL); + chip = devm_kzalloc(&client->dev, + sizeof(struct pca953x_chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; @@ -771,15 +763,15 @@ static int pca953x_probe(struct i2c_client *client, else ret = device_pca957x_init(chip, invert); if (ret) - goto out_failed; + return ret; ret = pca953x_irq_setup(chip, id, irq_base); if (ret) - goto out_failed; + return ret; ret = gpiochip_add(&chip->gpio_chip); if (ret) - goto out_failed_irq; + return ret; if (pdata && pdata->setup) { ret = pdata->setup(client, chip->gpio_chip.base, @@ -790,12 +782,6 @@ static int pca953x_probe(struct i2c_client *client, i2c_set_clientdata(client, chip); return 0; - -out_failed_irq: - pca953x_irq_teardown(chip); -out_failed: - kfree(chip); - return ret; } static int pca953x_remove(struct i2c_client *client) @@ -821,8 +807,6 @@ static int pca953x_remove(struct i2c_client *client) return ret; } - pca953x_irq_teardown(chip); - kfree(chip); return 0; } -- cgit v1.2.3 From 0d1c28a449c6c23a126e3a08ee30914609aac227 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Mon, 28 Jan 2013 16:23:10 +0200 Subject: gpiolib-acpi: Add ACPI5 event model support to gpio. Add ability to handle ACPI events signalled by GPIO interrupts. ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are handled by ACPI event methods which need to be called from the GPIO controller's interrupt handler. acpi_gpio_request_interrupt() finds out which gpio pins have acpi event methods and assigns interrupt handlers that calls the acpi event methods for those pins. Partially based on work by Rui Zhang Signed-off-by: Mathias Nyman Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 82 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/acpi_gpio.h | 4 +++ 2 files changed, 86 insertions(+) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index cbad6e908d3..54ce2269ed2 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -15,6 +15,7 @@ #include #include #include +#include static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) { @@ -52,3 +53,84 @@ int acpi_get_gpio(char *path, int pin) return chip->base + pin; } EXPORT_SYMBOL_GPL(acpi_get_gpio); + + +static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) +{ + acpi_handle handle = data; + + acpi_evaluate_object(handle, NULL, NULL, NULL); + + return IRQ_HANDLED; +} + +/** + * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events + * @chip: gpio chip + * + * ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are + * handled by ACPI event methods which need to be called from the GPIO + * chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which + * gpio pins have acpi event methods and assigns interrupt handlers that calls + * the acpi event methods for those pins. + * + * Interrupts are automatically freed on driver detach + */ + +void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) +{ + struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; + struct acpi_resource *res; + acpi_handle handle, ev_handle; + acpi_status status; + unsigned int pin, irq; + char ev_name[5]; + + if (!chip->dev || !chip->to_irq) + return; + + handle = ACPI_HANDLE(chip->dev); + if (!handle) + return; + + status = acpi_get_event_resources(handle, &buf); + if (ACPI_FAILURE(status)) + return; + + /* If a gpio interrupt has an acpi event handler method, then + * set up an interrupt handler that calls the acpi event handler + */ + + for (res = buf.pointer; + res && (res->type != ACPI_RESOURCE_TYPE_END_TAG); + res = ACPI_NEXT_RESOURCE(res)) { + + if (res->type != ACPI_RESOURCE_TYPE_GPIO || + res->data.gpio.connection_type != + ACPI_RESOURCE_GPIO_TYPE_INT) + continue; + + pin = res->data.gpio.pin_table[0]; + if (pin > chip->ngpio) + continue; + + sprintf(ev_name, "_%c%02X", + res->data.gpio.triggering ? 'E' : 'L', pin); + + status = acpi_get_handle(handle, ev_name, &ev_handle); + if (ACPI_FAILURE(status)) + continue; + + irq = chip->to_irq(chip, pin); + if (irq < 0) + continue; + + /* Assume BIOS sets the triggering, so no flags */ + devm_request_threaded_irq(chip->dev, irq, NULL, + acpi_gpio_irq_handler, + 0, + "GPIO-signaled-ACPI-event", + ev_handle); + } +} +EXPORT_SYMBOL(acpi_gpiochip_request_interrupts); diff --git a/include/linux/acpi_gpio.h b/include/linux/acpi_gpio.h index 91615a389b6..b76ebd08ff8 100644 --- a/include/linux/acpi_gpio.h +++ b/include/linux/acpi_gpio.h @@ -2,10 +2,12 @@ #define _LINUX_ACPI_GPIO_H_ #include +#include #ifdef CONFIG_GPIO_ACPI int acpi_get_gpio(char *path, int pin); +void acpi_gpiochip_request_interrupts(struct gpio_chip *chip); #else /* CONFIG_GPIO_ACPI */ @@ -14,6 +16,8 @@ static inline int acpi_get_gpio(char *path, int pin) return -ENODEV; } +static inline void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { } + #endif /* CONFIG_GPIO_ACPI */ #endif /* _LINUX_ACPI_GPIO_H_ */ -- cgit v1.2.3 From 66d7990e282f8015686b9bab30be30eec297e736 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Tue, 29 Jan 2013 09:16:33 +0100 Subject: gpio: mxs: Add IRQ_TYPE_EDGE_BOTH support This patch adds support for IRQ_TYPE_EDGE_BOTH needed for some driver (gpio-keys). Inspired from gpio-mxc.c Acked-by: Shawn Guo Signed-off-by: Gwenhael Goavec-Merou Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mxs.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index fa2a63cad32..859b6fabc7b 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -65,6 +65,7 @@ struct mxs_gpio_port { struct irq_domain *domain; struct bgpio_chip bgc; enum mxs_gpio_id devid; + u32 both_edges; }; static inline int is_imx23_gpio(struct mxs_gpio_port *port) @@ -81,13 +82,23 @@ static inline int is_imx28_gpio(struct mxs_gpio_port *port) static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type) { + u32 val; u32 pin_mask = 1 << d->hwirq; struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct mxs_gpio_port *port = gc->private; void __iomem *pin_addr; int edge; + port->both_edges &= ~pin_mask; switch (type) { + case IRQ_TYPE_EDGE_BOTH: + val = gpio_get_value(port->bgc.gc.base + d->hwirq); + if (val) + edge = GPIO_INT_FALL_EDGE; + else + edge = GPIO_INT_RISE_EDGE; + port->both_edges |= pin_mask; + break; case IRQ_TYPE_EDGE_RISING: edge = GPIO_INT_RISE_EDGE; break; @@ -124,6 +135,23 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type) return 0; } +static void mxs_flip_edge(struct mxs_gpio_port *port, u32 gpio) +{ + u32 bit, val, edge; + void __iomem *pin_addr; + + bit = 1 << gpio; + + pin_addr = port->base + PINCTRL_IRQPOL(port); + val = readl(pin_addr); + edge = val & bit; + + if (edge) + writel(bit, pin_addr + MXS_CLR); + else + writel(bit, pin_addr + MXS_SET); +} + /* MXS has one interrupt *per* gpio port */ static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc) { @@ -137,6 +165,9 @@ static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc) while (irq_stat != 0) { int irqoffset = fls(irq_stat) - 1; + if (port->both_edges & (1 << irqoffset)) + mxs_flip_edge(port, irqoffset); + generic_handle_irq(irq_find_mapping(port->domain, irqoffset)); irq_stat &= ~(1 << irqoffset); } -- cgit v1.2.3 From 6320c7b7990e1e759a18666b6c616aae9bd3b12d Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Sat, 2 Feb 2013 23:44:05 +0900 Subject: arm: pxa: tosa: do not use gpiochip_reserve() GPIO address space reservation during early platform initialization is not needed anymore for Tosa. Remove the calls to gpiochip_reserve() which is due to be removed. Acked-by: Haojian Zhuang Signed-off-by: Alexandre Courbot Signed-off-by: Linus Walleij --- arch/arm/mach-pxa/tosa.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c index 233629edf7e..4f35b333de4 100644 --- a/arch/arm/mach-pxa/tosa.c +++ b/arch/arm/mach-pxa/tosa.c @@ -927,8 +927,6 @@ static void tosa_restart(char mode, const char *cmd) static void __init tosa_init(void) { - int dummy; - pxa2xx_mfp_config(ARRAY_AND_SIZE(tosa_pin_config)); pxa_set_ffuart_info(NULL); @@ -947,10 +945,6 @@ static void __init tosa_init(void) /* enable batt_fault */ PMCR = 0x01; - dummy = gpiochip_reserve(TOSA_SCOOP_GPIO_BASE, 12); - dummy = gpiochip_reserve(TOSA_SCOOP_JC_GPIO_BASE, 12); - dummy = gpiochip_reserve(TOSA_TC6393XB_GPIO_BASE, 16); - pxa_set_mci_info(&tosa_mci_platform_data); pxa_set_ficp_info(&tosa_ficp_platform_data); pxa_set_i2c_info(NULL); -- cgit v1.2.3 From 710b40eac4d91bd08f07f289cf6d6f3861c87187 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Sat, 2 Feb 2013 23:44:06 +0900 Subject: gpiolib: remove gpiochip_reserve() gpiochip_reserve() has no user and stands in the way of the removal of the static gpio_desc[] array. Remove this function as well as the now unneeded RESERVED flag of struct gpio_desc. Signed-off-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 58 +++++++--------------------------------------- include/asm-generic/gpio.h | 1 - 2 files changed, 8 insertions(+), 51 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 199fca15f27..e27877ad016 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -52,14 +52,13 @@ struct gpio_desc { /* flag symbols are bit numbers */ #define FLAG_REQUESTED 0 #define FLAG_IS_OUT 1 -#define FLAG_RESERVED 2 -#define FLAG_EXPORT 3 /* protected by sysfs_lock */ -#define FLAG_SYSFS 4 /* exported via /sys/class/gpio/control */ -#define FLAG_TRIG_FALL 5 /* trigger on falling edge */ -#define FLAG_TRIG_RISE 6 /* trigger on rising edge */ -#define FLAG_ACTIVE_LOW 7 /* sysfs value has active low */ -#define FLAG_OPEN_DRAIN 8 /* Gpio is open drain type */ -#define FLAG_OPEN_SOURCE 9 /* Gpio is open source type */ +#define FLAG_EXPORT 2 /* protected by sysfs_lock */ +#define FLAG_SYSFS 3 /* exported via /sys/class/gpio/control */ +#define FLAG_TRIG_FALL 4 /* trigger on falling edge */ +#define FLAG_TRIG_RISE 5 /* trigger on rising edge */ +#define FLAG_ACTIVE_LOW 6 /* sysfs value has active low */ +#define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */ +#define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */ #define ID_SHIFT 16 /* add new flags before this one */ @@ -132,7 +131,7 @@ static int gpiochip_find_base(int ngpio) struct gpio_desc *desc = &gpio_desc[i]; struct gpio_chip *chip = desc->chip; - if (!chip && !test_bit(FLAG_RESERVED, &desc->flags)) { + if (!chip) { spare++; if (spare == ngpio) { base = i; @@ -150,47 +149,6 @@ static int gpiochip_find_base(int ngpio) return base; } -/** - * gpiochip_reserve() - reserve range of gpios to use with platform code only - * @start: starting gpio number - * @ngpio: number of gpios to reserve - * Context: platform init, potentially before irqs or kmalloc will work - * - * Returns a negative errno if any gpio within the range is already reserved - * or registered, else returns zero as a success code. Use this function - * to mark a range of gpios as unavailable for dynamic gpio number allocation, - * for example because its driver support is not yet loaded. - */ -int __init gpiochip_reserve(int start, int ngpio) -{ - int ret = 0; - unsigned long flags; - int i; - - if (!gpio_is_valid(start) || !gpio_is_valid(start + ngpio - 1)) - return -EINVAL; - - spin_lock_irqsave(&gpio_lock, flags); - - for (i = start; i < start + ngpio; i++) { - struct gpio_desc *desc = &gpio_desc[i]; - - if (desc->chip || test_bit(FLAG_RESERVED, &desc->flags)) { - ret = -EBUSY; - goto err; - } - - set_bit(FLAG_RESERVED, &desc->flags); - } - - pr_debug("%s: reserved gpios from %d to %d\n", - __func__, start, start + ngpio - 1); -err: - spin_unlock_irqrestore(&gpio_lock, flags); - - return ret; -} - /* caller ensures gpio is valid and requested, chip->get_direction may sleep */ static int gpio_get_direction(unsigned gpio) { diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 45b8916805f..2034e691c7a 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -152,7 +152,6 @@ struct gpio_chip { extern const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset); extern struct gpio_chip *gpio_to_chip(unsigned gpio); -extern int __must_check gpiochip_reserve(int start, int ngpio); /* add/remove chips */ extern int gpiochip_add(struct gpio_chip *chip); -- cgit v1.2.3 From de0ccf788147440eee2383c74408080f3ff0a43b Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Mon, 4 Feb 2013 09:10:15 +0100 Subject: gpio: mpc8xxx: don't set IRQ_TYPE_NONE when creating irq mapping Exporting gpios over sysfs GPIO interface throws genirq error messages, i.e. on an mpc5121 based board exporting GPIO 5 triggers it: # echo 229 > /sys/class/gpio/export genirq: Setting trigger mode 0 for irq 44 failed (mpc512x_irq_set_type+0x0/0x18c) Similar error messages appear in the kernel boot log since the board specifies GPIOs for matrix keypad and also SD Card write protect and card detect GPIOs in its device tree. For all these GPIOs there is an error message in the log. The issue is triggered by setting the irq type to IRQ_TYPE_NONE in the driver's irq_domain map function mpc8xxx_gpio_irq_map(). ... mpc8xxx_gpio_irq_map irq_set_irq_type __irq_set_trigger __irq_set_trigger() calls irq_set_type() callback of the mpc8xxx gpio irq chip with the IRQ_TYPE_NONE in its 'flags' argument. This callback is either mpc8xxx_irq_set_type() or mpc512x_irq_set_type(). Both these functions return -EINVAL in the case if IRQ_TYPE_NONE is passed in the flow_type argument. This return value triggers the observed error message in __irq_set_trigger(). Modifying these callbacks to not return an error in IRQ_TYPE_NONE case doesn't make any sense to me. The line setting IRQ_TYPE_NONE type has been originally added by commit 345e5c8a "powerpc: Add interrupt support to mpc8xxx_gpio". At this time set_irq_type() checked its type argument and returned 0 if the type argument didn't specify any meaningful type in its type sense bits (and thus was equal to IRQ_TYPE_NONE). Effectively this line was a nop and I wonder what was the point of adding it. Remove IRQ_TYPE_NONE setting in the irq_domain mapping function. Signed-off-by: Anatolij Gustschin Acked-by: Peter Korsgaard Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mpc8xxx.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index 9ae29cc0d17..a0b33a216d4 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -292,7 +292,6 @@ static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int virq, irq_set_chip_data(virq, h->host_data); irq_set_chip_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq); - irq_set_irq_type(virq, IRQ_TYPE_NONE); return 0; } -- cgit v1.2.3 From 1107ca104f0331627f6446bfefa2d4b0e673db18 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Mon, 4 Feb 2013 11:32:22 +0200 Subject: gpiolib-acpi: Fix error checks in interrupt requesting Print error message if requesting an interrupt fails. Use int instead of unsigned for interrupts in case of error values Signed-off-by: Mathias Nyman Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 54ce2269ed2..a063eb04b6c 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -83,7 +83,8 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) struct acpi_resource *res; acpi_handle handle, ev_handle; acpi_status status; - unsigned int pin, irq; + unsigned int pin; + int irq, ret; char ev_name[5]; if (!chip->dev || !chip->to_irq) @@ -126,11 +127,15 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) continue; /* Assume BIOS sets the triggering, so no flags */ - devm_request_threaded_irq(chip->dev, irq, NULL, + ret = devm_request_threaded_irq(chip->dev, irq, NULL, acpi_gpio_irq_handler, 0, "GPIO-signaled-ACPI-event", ev_handle); + if (ret) + dev_err(chip->dev, + "Failed to request IRQ %d ACPI event handler\n", + irq); } } EXPORT_SYMBOL(acpi_gpiochip_request_interrupts); -- cgit v1.2.3 From 476171ce7850b28280db6a2d0c0e4d3ff26c8117 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Mon, 4 Feb 2013 17:42:04 +0900 Subject: gpiolib: add missing braces in gpio_direction_show Add missing braces in an if..else condition. Signed-off-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e27877ad016..e14eb88bbe8 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -212,13 +212,14 @@ static ssize_t gpio_direction_show(struct device *dev, mutex_lock(&sysfs_lock); - if (!test_bit(FLAG_EXPORT, &desc->flags)) + if (!test_bit(FLAG_EXPORT, &desc->flags)) { status = -EIO; - else + } else { gpio_get_direction(gpio); status = sprintf(buf, "%s\n", test_bit(FLAG_IS_OUT, &desc->flags) ? "out" : "in"); + } mutex_unlock(&sysfs_lock); return status; -- cgit v1.2.3 From 1d09aaa6a325d55680506d585c7d5ee4744f5539 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Wed, 12 Dec 2012 17:42:38 +0200 Subject: gpio/lynxpoint: add chipset gpio driver. Add gpio support for Intel Lynxpoint chipset. Lynxpoint supports 94 gpio pins which can generate interrupts. Driver will fail requests for pins that are marked as owned by ACPI, or set in an alternate mode (non-gpio). Signed-off-by: Mathias Nyman Signed-off-by: Grant Likely --- drivers/gpio/Kconfig | 8 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-lynxpoint.c | 469 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 478 insertions(+) create mode 100644 drivers/gpio/gpio-lynxpoint.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 682de754d63..3a671453920 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -298,6 +298,14 @@ config GPIO_GE_FPGA and write pin state) for GPIO implemented in a number of GE single board computers. +config GPIO_LYNXPOINT + bool "Intel Lynxpoint GPIO support" + depends on ACPI + select IRQ_DOMAIN + help + driver for GPIO functionality on Intel Lynxpoint PCH chipset + Requires ACPI device enumeration code to set up a platform device. + comment "I2C GPIO expanders:" config GPIO_ARIZONA diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index c5aebd008dd..519daaf57da 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o obj-$(CONFIG_GPIO_LANGWELL) += gpio-langwell.o obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o +obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c new file mode 100644 index 00000000000..3472b05ac51 --- /dev/null +++ b/drivers/gpio/gpio-lynxpoint.c @@ -0,0 +1,469 @@ +/* + * GPIO controller driver for Intel Lynxpoint PCH chipset> + * Copyright (c) 2012, Intel Corporation. + * + * Author: Mathias Nyman + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* LynxPoint chipset has support for 94 gpio pins */ + +#define LP_NUM_GPIO 94 + +/* Bitmapped register offsets */ +#define LP_ACPI_OWNED 0x00 /* Bitmap, set by bios, 0: pin reserved for ACPI */ +#define LP_GC 0x7C /* set APIC IRQ to IRQ14 or IRQ15 for all pins */ +#define LP_INT_STAT 0x80 +#define LP_INT_ENABLE 0x90 + +/* Each pin has two 32 bit config registers, starting at 0x100 */ +#define LP_CONFIG1 0x100 +#define LP_CONFIG2 0x104 + +/* LP_CONFIG1 reg bits */ +#define OUT_LVL_BIT BIT(31) +#define IN_LVL_BIT BIT(30) +#define TRIG_SEL_BIT BIT(4) /* 0: Edge, 1: Level */ +#define INT_INV_BIT BIT(3) /* Invert interrupt triggering */ +#define DIR_BIT BIT(2) /* 0: Output, 1: Input */ +#define USE_SEL_BIT BIT(0) /* 0: Native, 1: GPIO */ + +/* LP_CONFIG2 reg bits */ +#define GPINDIS_BIT BIT(2) /* disable input sensing */ +#define GPIWP_BIT (BIT(0) | BIT(1)) /* weak pull options */ + +struct lp_gpio { + struct gpio_chip chip; + struct irq_domain *domain; + struct platform_device *pdev; + spinlock_t lock; + unsigned long reg_base; +}; + +/* + * Lynxpoint gpios are controlled through both bitmapped registers and + * per gpio specific registers. The bitmapped registers are in chunks of + * 3 x 32bit registers to cover all 94 gpios + * + * per gpio specific registers consist of two 32bit registers per gpio + * (LP_CONFIG1 and LP_CONFIG2), with 94 gpios there's a total of + * 188 config registes. + * + * A simplified view of the register layout look like this: + * + * LP_ACPI_OWNED[31:0] gpio ownerships for gpios 0-31 (bitmapped registers) + * LP_ACPI_OWNED[63:32] gpio ownerships for gpios 32-63 + * LP_ACPI_OWNED[94:64] gpio ownerships for gpios 63-94 + * ... + * LP_INT_ENABLE[31:0] ... + * LP_INT_ENABLE[63:31] ... + * LP_INT_ENABLE[94:64] ... + * LP0_CONFIG1 (gpio 0) config1 reg for gpio 0 (per gpio registers) + * LP0_CONFIG2 (gpio 0) config2 reg for gpio 0 + * LP1_CONFIG1 (gpio 1) config1 reg for gpio 1 + * LP1_CONFIG2 (gpio 1) config2 reg for gpio 1 + * LP2_CONFIG1 (gpio 2) ... + * LP2_CONFIG2 (gpio 2) ... + * ... + * LP94_CONFIG1 (gpio 94) ... + * LP94_CONFIG2 (gpio 94) ... + */ + +static unsigned long lp_gpio_reg(struct gpio_chip *chip, unsigned offset, + int reg) +{ + struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip); + int reg_offset; + + if (reg == LP_CONFIG1 || reg == LP_CONFIG2) + /* per gpio specific config registers */ + reg_offset = offset * 8; + else + /* bitmapped registers */ + reg_offset = (offset / 32) * 4; + + return lg->reg_base + reg + reg_offset; +} + +static int lp_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip); + unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1); + unsigned long conf2 = lp_gpio_reg(chip, offset, LP_CONFIG2); + unsigned long acpi_use = lp_gpio_reg(chip, offset, LP_ACPI_OWNED); + + pm_runtime_get(&lg->pdev->dev); /* should we put if failed */ + + /* Fail if BIOS reserved pin for ACPI use */ + if (!(inl(acpi_use) & BIT(offset % 32))) { + dev_err(&lg->pdev->dev, "gpio %d reserved for ACPI\n", offset); + return -EBUSY; + } + /* Fail if pin is in alternate function mode (not GPIO mode) */ + if (!(inl(reg) & USE_SEL_BIT)) + return -ENODEV; + + /* enable input sensing */ + outl(inl(conf2) & ~GPINDIS_BIT, conf2); + + + return 0; +} + +static void lp_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip); + unsigned long conf2 = lp_gpio_reg(chip, offset, LP_CONFIG2); + + /* disable input sensing */ + outl(inl(conf2) | GPINDIS_BIT, conf2); + + pm_runtime_put(&lg->pdev->dev); +} + +static int lp_irq_type(struct irq_data *d, unsigned type) +{ + struct lp_gpio *lg = irq_data_get_irq_chip_data(d); + u32 hwirq = irqd_to_hwirq(d); + unsigned long flags; + u32 value; + unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_CONFIG1); + + if (hwirq >= lg->chip.ngpio) + return -EINVAL; + + spin_lock_irqsave(&lg->lock, flags); + value = inl(reg); + + /* set both TRIG_SEL and INV bits to 0 for rising edge */ + if (type & IRQ_TYPE_EDGE_RISING) + value &= ~(TRIG_SEL_BIT | INT_INV_BIT); + + /* TRIG_SEL bit 0, INV bit 1 for falling edge */ + if (type & IRQ_TYPE_EDGE_FALLING) + value = (value | INT_INV_BIT) & ~TRIG_SEL_BIT; + + /* TRIG_SEL bit 1, INV bit 0 for level low */ + if (type & IRQ_TYPE_LEVEL_LOW) + value = (value | TRIG_SEL_BIT) & ~INT_INV_BIT; + + /* TRIG_SEL bit 1, INV bit 1 for level high */ + if (type & IRQ_TYPE_LEVEL_HIGH) + value |= TRIG_SEL_BIT | INT_INV_BIT; + + outl(value, reg); + spin_unlock_irqrestore(&lg->lock, flags); + + return 0; +} + +static int lp_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1); + return inl(reg) & IN_LVL_BIT; +} + +static void lp_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip); + unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1); + unsigned long flags; + + spin_lock_irqsave(&lg->lock, flags); + + if (value) + outl(inl(reg) | OUT_LVL_BIT, reg); + else + outl(inl(reg) & ~OUT_LVL_BIT, reg); + + spin_unlock_irqrestore(&lg->lock, flags); +} + +static int lp_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip); + unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1); + unsigned long flags; + + spin_lock_irqsave(&lg->lock, flags); + outl(inl(reg) | DIR_BIT, reg); + spin_unlock_irqrestore(&lg->lock, flags); + + return 0; +} + +static int lp_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip); + unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1); + unsigned long flags; + + lp_gpio_set(chip, offset, value); + + spin_lock_irqsave(&lg->lock, flags); + outl(inl(reg) & ~DIR_BIT, reg); + spin_unlock_irqrestore(&lg->lock, flags); + + return 0; +} + +static int lp_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip); + return irq_create_mapping(lg->domain, offset); +} + +static void lp_gpio_irq_handler(unsigned irq, struct irq_desc *desc) +{ + struct irq_data *data = irq_desc_get_irq_data(desc); + struct lp_gpio *lg = irq_data_get_irq_handler_data(data); + struct irq_chip *chip = irq_data_get_irq_chip(data); + u32 base, pin, mask; + unsigned long reg, pending; + unsigned virq; + + /* check from GPIO controller which pin triggered the interrupt */ + for (base = 0; base < lg->chip.ngpio; base += 32) { + reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT); + + while ((pending = inl(reg))) { + pin = __ffs(pending); + mask = BIT(pin); + /* Clear before handling so we don't lose an edge */ + outl(mask, reg); + virq = irq_find_mapping(lg->domain, base + pin); + generic_handle_irq(virq); + } + } + chip->irq_eoi(data); +} + +static void lp_irq_unmask(struct irq_data *d) +{ +} + +static void lp_irq_mask(struct irq_data *d) +{ +} + +static void lp_irq_enable(struct irq_data *d) +{ + struct lp_gpio *lg = irq_data_get_irq_chip_data(d); + u32 hwirq = irqd_to_hwirq(d); + unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE); + unsigned long flags; + + spin_lock_irqsave(&lg->lock, flags); + outl(inl(reg) | BIT(hwirq % 32), reg); + spin_unlock_irqrestore(&lg->lock, flags); +} + +static void lp_irq_disable(struct irq_data *d) +{ + struct lp_gpio *lg = irq_data_get_irq_chip_data(d); + u32 hwirq = irqd_to_hwirq(d); + unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE); + unsigned long flags; + + spin_lock_irqsave(&lg->lock, flags); + outl(inl(reg) & ~BIT(hwirq % 32), reg); + spin_unlock_irqrestore(&lg->lock, flags); +} + +static struct irq_chip lp_irqchip = { + .name = "LP-GPIO", + .irq_mask = lp_irq_mask, + .irq_unmask = lp_irq_unmask, + .irq_enable = lp_irq_enable, + .irq_disable = lp_irq_disable, + .irq_set_type = lp_irq_type, + .flags = IRQCHIP_SKIP_SET_WAKE, +}; + +static void lp_gpio_irq_init_hw(struct lp_gpio *lg) +{ + unsigned long reg; + unsigned base; + + for (base = 0; base < lg->chip.ngpio; base += 32) { + /* disable gpio pin interrupts */ + reg = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE); + outl(0, reg); + /* Clear interrupt status register */ + reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT); + outl(0xffffffff, reg); + } +} + +static int lp_gpio_irq_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hw) +{ + struct lp_gpio *lg = d->host_data; + + irq_set_chip_and_handler_name(virq, &lp_irqchip, handle_simple_irq, + "demux"); + irq_set_chip_data(virq, lg); + irq_set_irq_type(virq, IRQ_TYPE_NONE); + + return 0; +} + +static const struct irq_domain_ops lp_gpio_irq_ops = { + .map = lp_gpio_irq_map, +}; + +static int lp_gpio_probe(struct platform_device *pdev) +{ + struct lp_gpio *lg; + struct gpio_chip *gc; + struct resource *io_rc, *irq_rc; + struct device *dev = &pdev->dev; + unsigned long reg_len; + unsigned hwirq; + int ret = -ENODEV; + + lg = devm_kzalloc(dev, sizeof(struct lp_gpio), GFP_KERNEL); + if (!lg) { + dev_err(dev, "can't allocate lp_gpio chip data\n"); + return -ENOMEM; + } + + lg->pdev = pdev; + platform_set_drvdata(pdev, lg); + + io_rc = platform_get_resource(pdev, IORESOURCE_IO, 0); + irq_rc = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + + if (!io_rc) { + dev_err(dev, "missing IO resources\n"); + return -EINVAL; + } + + lg->reg_base = io_rc->start; + reg_len = resource_size(io_rc); + + if (!devm_request_region(dev, lg->reg_base, reg_len, "lp-gpio")) { + dev_err(dev, "failed requesting IO region 0x%x\n", + (unsigned int)lg->reg_base); + return -EBUSY; + } + + spin_lock_init(&lg->lock); + + gc = &lg->chip; + gc->label = dev_name(dev); + gc->owner = THIS_MODULE; + gc->request = lp_gpio_request; + gc->free = lp_gpio_free; + gc->direction_input = lp_gpio_direction_input; + gc->direction_output = lp_gpio_direction_output; + gc->get = lp_gpio_get; + gc->set = lp_gpio_set; + gc->base = -1; + gc->ngpio = LP_NUM_GPIO; + gc->can_sleep = 0; + gc->dev = dev; + + /* set up interrupts */ + if (irq_rc && irq_rc->start) { + hwirq = irq_rc->start; + gc->to_irq = lp_gpio_to_irq; + + lg->domain = irq_domain_add_linear(NULL, LP_NUM_GPIO, + &lp_gpio_irq_ops, lg); + if (!lg->domain) + return -ENXIO; + + lp_gpio_irq_init_hw(lg); + + irq_set_handler_data(hwirq, lg); + irq_set_chained_handler(hwirq, lp_gpio_irq_handler); + } + + ret = gpiochip_add(gc); + if (ret) { + dev_err(dev, "failed adding lp-gpio chip\n"); + return ret; + } + pm_runtime_enable(dev); + + return 0; +} + +static int lp_gpio_runtime_suspend(struct device *dev) +{ + return 0; +} + +static int lp_gpio_runtime_resume(struct device *dev) +{ + return 0; +} + +static const struct dev_pm_ops lp_gpio_pm_ops = { + .runtime_suspend = lp_gpio_runtime_suspend, + .runtime_resume = lp_gpio_runtime_resume, +}; + +static const struct acpi_device_id lynxpoint_gpio_acpi_match[] = { + { "INT33C7", 0 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, lynxpoint_gpio_acpi_match); + +static int lp_gpio_remove(struct platform_device *pdev) +{ + struct lp_gpio *lg = platform_get_drvdata(pdev); + int err; + err = gpiochip_remove(&lg->chip); + if (err) + dev_warn(&pdev->dev, "failed to remove gpio_chip.\n"); + platform_set_drvdata(pdev, NULL); + return 0; +} + +static struct platform_driver lp_gpio_driver = { + .probe = lp_gpio_probe, + .remove = lp_gpio_remove, + .driver = { + .name = "lp_gpio", + .owner = THIS_MODULE, + .pm = &lp_gpio_pm_ops, + .acpi_match_table = ACPI_PTR(lynxpoint_gpio_acpi_match), + }, +}; + +static int __init lp_gpio_init(void) +{ + return platform_driver_register(&lp_gpio_driver); +} + +subsys_initcall(lp_gpio_init); -- cgit v1.2.3 From 936cb1b12519c73373e461df6e106c460396941c Mon Sep 17 00:00:00 2001 From: David Cohen Date: Tue, 18 Dec 2012 17:52:12 -0800 Subject: gpio/langwell: Add Cloverview ids to pci device table Adds support for new Cloverview hardware. Signed-off-by: David Cohen Signed-off-by: Grant Likely --- drivers/gpio/gpio-langwell.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpio/gpio-langwell.c b/drivers/gpio/gpio-langwell.c index e77b2b3e94a..a53ad08974c 100644 --- a/drivers/gpio/gpio-langwell.c +++ b/drivers/gpio/gpio-langwell.c @@ -234,6 +234,8 @@ static DEFINE_PCI_DEVICE_TABLE(lnw_gpio_ids) = { /* pin number */ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080f), .driver_data = 64 }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081f), .driver_data = 96 }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081a), .driver_data = 96 }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08eb), .driver_data = 96 }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08f7), .driver_data = 96 }, { 0, } }; MODULE_DEVICE_TABLE(pci, lnw_gpio_ids); -- cgit v1.2.3 From 46ebfbc3745597067494186a0e7031add22f3134 Mon Sep 17 00:00:00 2001 From: David Cohen Date: Thu, 20 Dec 2012 14:45:51 -0800 Subject: gpio/langwell: cleanup driver This patch cleans up cosmetic issues, remove useless functions and add to_lnw_priv() macro to replace many usages of container_of(). Signed-off-by: David Cohen Signed-off-by: Grant Likely --- drivers/gpio/gpio-langwell.c | 51 +++++++++++++++----------------------------- 1 file changed, 17 insertions(+), 34 deletions(-) diff --git a/drivers/gpio/gpio-langwell.c b/drivers/gpio/gpio-langwell.c index a53ad08974c..634c3d37f7b 100644 --- a/drivers/gpio/gpio-langwell.c +++ b/drivers/gpio/gpio-langwell.c @@ -71,10 +71,12 @@ struct lnw_gpio { struct irq_domain *domain; }; +#define to_lnw_priv(chip) container_of(chip, struct lnw_gpio, chip) + static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset, enum GPIO_REG reg_type) { - struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip); + struct lnw_gpio *lnw = to_lnw_priv(chip); unsigned nreg = chip->ngpio / 32; u8 reg = offset / 32; void __iomem *ptr; @@ -86,7 +88,7 @@ static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset, static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset, enum GPIO_REG reg_type) { - struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip); + struct lnw_gpio *lnw = to_lnw_priv(chip); unsigned nreg = chip->ngpio / 32; u8 reg = offset / 16; void __iomem *ptr; @@ -130,7 +132,7 @@ static void lnw_gpio_set(struct gpio_chip *chip, unsigned offset, int value) static int lnw_gpio_direction_input(struct gpio_chip *chip, unsigned offset) { - struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip); + struct lnw_gpio *lnw = to_lnw_priv(chip); void __iomem *gpdr = gpio_reg(chip, offset, GPDR); u32 value; unsigned long flags; @@ -153,7 +155,7 @@ static int lnw_gpio_direction_input(struct gpio_chip *chip, unsigned offset) static int lnw_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value) { - struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip); + struct lnw_gpio *lnw = to_lnw_priv(chip); void __iomem *gpdr = gpio_reg(chip, offset, GPDR); unsigned long flags; @@ -176,7 +178,7 @@ static int lnw_gpio_direction_output(struct gpio_chip *chip, static int lnw_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { - struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip); + struct lnw_gpio *lnw = to_lnw_priv(chip); return irq_create_mapping(lnw->domain, offset); } @@ -301,17 +303,6 @@ static const struct irq_domain_ops lnw_gpio_irq_ops = { .xlate = irq_domain_xlate_twocell, }; -#ifdef CONFIG_PM -static int lnw_gpio_runtime_resume(struct device *dev) -{ - return 0; -} - -static int lnw_gpio_runtime_suspend(struct device *dev) -{ - return 0; -} - static int lnw_gpio_runtime_idle(struct device *dev) { int err = pm_schedule_suspend(dev, 500); @@ -322,16 +313,8 @@ static int lnw_gpio_runtime_idle(struct device *dev) return -EBUSY; } -#else -#define lnw_gpio_runtime_suspend NULL -#define lnw_gpio_runtime_resume NULL -#define lnw_gpio_runtime_idle NULL -#endif - static const struct dev_pm_ops lnw_gpio_pm_ops = { - .runtime_suspend = lnw_gpio_runtime_suspend, - .runtime_resume = lnw_gpio_runtime_resume, - .runtime_idle = lnw_gpio_runtime_idle, + SET_RUNTIME_PM_OPS(NULL, NULL, lnw_gpio_runtime_idle) }; static int lnw_gpio_probe(struct pci_dev *pdev, @@ -351,7 +334,7 @@ static int lnw_gpio_probe(struct pci_dev *pdev, retval = pci_request_regions(pdev, "langwell_gpio"); if (retval) { dev_err(&pdev->dev, "error requesting resources\n"); - goto err2; + goto err_pci_req_region; } /* get the gpio_base from bar1 */ start = pci_resource_start(pdev, 1); @@ -360,7 +343,7 @@ static int lnw_gpio_probe(struct pci_dev *pdev, if (!base) { dev_err(&pdev->dev, "error mapping bar1\n"); retval = -EFAULT; - goto err3; + goto err_ioremap; } gpio_base = *((u32 *)base + 1); /* release the IO mapping, since we already get the info from bar1 */ @@ -372,21 +355,21 @@ static int lnw_gpio_probe(struct pci_dev *pdev, if (!base) { dev_err(&pdev->dev, "error mapping bar0\n"); retval = -EFAULT; - goto err3; + goto err_ioremap; } - lnw = devm_kzalloc(&pdev->dev, sizeof(struct lnw_gpio), GFP_KERNEL); + lnw = devm_kzalloc(&pdev->dev, sizeof(*lnw), GFP_KERNEL); if (!lnw) { dev_err(&pdev->dev, "can't allocate langwell_gpio chip data\n"); retval = -ENOMEM; - goto err3; + goto err_ioremap; } lnw->domain = irq_domain_add_linear(pdev->dev.of_node, ngpio, &lnw_gpio_irq_ops, lnw); if (!lnw->domain) { retval = -ENOMEM; - goto err3; + goto err_ioremap; } lnw->reg_base = base; @@ -405,7 +388,7 @@ static int lnw_gpio_probe(struct pci_dev *pdev, retval = gpiochip_add(&lnw->chip); if (retval) { dev_err(&pdev->dev, "langwell gpiochip_add error %d\n", retval); - goto err3; + goto err_ioremap; } lnw_irq_init_hw(lnw); @@ -420,9 +403,9 @@ static int lnw_gpio_probe(struct pci_dev *pdev, return 0; -err3: +err_ioremap: pci_release_regions(pdev); -err2: +err_pci_req_region: pci_disable_device(pdev); return retval; } -- cgit v1.2.3 From 1a989d0f1de8f5a150b35e1e8181cc1abc139162 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Sun, 3 Feb 2013 01:29:24 +0900 Subject: gpiolib: link all gpio_chips using a list Add a list member to gpio_chip that allows all chips to be parsed quickly. The current method requires parsing the entire GPIO integer space, which is painfully slow. Using a list makes many chip operations that involve lookup or parsing faster, and also simplifies the code. It is also necessary to eventually get rid of the global gpio_desc[] array. The list of gpio_chips is always ordered by base GPIO number to ensure chips traversal is done in the right order. Signed-off-by: Alexandre Courbot Reviewed-by: Linus Walleij Signed-off-by: Grant Likely --- drivers/gpio/gpiolib.c | 51 +++++++++++++++++++++++++++++++++++++++------- include/asm-generic/gpio.h | 2 ++ 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e14eb88bbe8..453ac77771c 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -71,6 +72,8 @@ struct gpio_desc { }; static struct gpio_desc gpio_desc[ARCH_NR_GPIOS]; +static LIST_HEAD(gpio_chips); + #ifdef CONFIG_GPIO_SYSFS static DEFINE_IDR(dirent_idr); #endif @@ -1014,6 +1017,43 @@ static inline void gpiochip_unexport(struct gpio_chip *chip) #endif /* CONFIG_GPIO_SYSFS */ +/* + * Add a new chip to the global chips list, keeping the list of chips sorted + * by base order. + * + * Return -EBUSY if the new chip overlaps with some other chip's integer + * space. + */ +static int gpiochip_add_to_list(struct gpio_chip *chip) +{ + struct list_head *pos = &gpio_chips; + struct gpio_chip *_chip; + int err = 0; + + /* find where to insert our chip */ + list_for_each(pos, &gpio_chips) { + _chip = list_entry(pos, struct gpio_chip, list); + /* shall we insert before _chip? */ + if (_chip->base >= chip->base + chip->ngpio) + break; + } + + /* are we stepping on the chip right before? */ + if (pos != &gpio_chips && pos->prev != &gpio_chips) { + _chip = list_entry(pos->prev, struct gpio_chip, list); + if (_chip->base + _chip->ngpio > chip->base) { + dev_err(chip->dev, + "GPIO integer space overlap, cannot add chip\n"); + err = -EBUSY; + } + } + + if (!err) + list_add_tail(&chip->list, pos); + + return err; +} + /** * gpiochip_add() - register a gpio_chip * @chip: the chip to register, with chip->base initialized @@ -1055,13 +1095,8 @@ int gpiochip_add(struct gpio_chip *chip) chip->base = base; } - /* these GPIO numbers must not be managed by another gpio_chip */ - for (id = base; id < base + chip->ngpio; id++) { - if (gpio_desc[id].chip != NULL) { - status = -EBUSY; - break; - } - } + status = gpiochip_add_to_list(chip); + if (status == 0) { for (id = base; id < base + chip->ngpio; id++) { gpio_desc[id].chip = chip; @@ -1135,6 +1170,8 @@ int gpiochip_remove(struct gpio_chip *chip) if (status == 0) { for (id = chip->base; id < chip->base + chip->ngpio; id++) gpio_desc[id].chip = NULL; + + list_del(&chip->list); } spin_unlock_irqrestore(&gpio_lock, flags); diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 2034e691c7a..b562f95cdc2 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -53,6 +53,7 @@ struct device_node; * @label: for diagnostics * @dev: optional device providing the GPIOs * @owner: helps prevent removal of modules exporting active GPIOs + * @list: links gpio_chips together for traversal * @request: optional hook for chip-specific activation, such as * enabling module power and clock; may sleep * @free: optional hook for chip-specific deactivation, such as @@ -98,6 +99,7 @@ struct gpio_chip { const char *label; struct device *dev; struct module *owner; + struct list_head list; int (*request)(struct gpio_chip *chip, unsigned offset); -- cgit v1.2.3 From 65493e3ac429623df021e0859d97691f4b42615a Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Sun, 3 Feb 2013 01:29:25 +0900 Subject: gpiolib: use gpio_chips list in gpiolib_sysfs_init Use the small list of GPIO chips instead of parsing the whole GPIO number space. Signed-off-by: Alexandre Courbot Reviewed-by: Linus Walleij Signed-off-by: Grant Likely --- drivers/gpio/gpiolib.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 453ac77771c..c1d8f7bdcd8 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -974,7 +974,7 @@ static int __init gpiolib_sysfs_init(void) { int status; unsigned long flags; - unsigned gpio; + struct gpio_chip *chip; status = class_register(&gpio_class); if (status < 0) @@ -987,10 +987,7 @@ static int __init gpiolib_sysfs_init(void) * registered, and so arch_initcall() can always gpio_export(). */ spin_lock_irqsave(&gpio_lock, flags); - for (gpio = 0; gpio < ARCH_NR_GPIOS; gpio++) { - struct gpio_chip *chip; - - chip = gpio_desc[gpio].chip; + list_for_each_entry(chip, &gpio_chips, list) { if (!chip || chip->exported) continue; -- cgit v1.2.3 From 125eef96f6cfadddbac8f6b9fccc9848988e7c6e Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Sun, 3 Feb 2013 01:29:26 +0900 Subject: gpiolib: use gpio_chips list in gpiochip_find Using the GPIO chips list is much faster than parsing the entire GPIO number space. Signed-off-by: Alexandre Courbot Reviewed-by: Linus Walleij Signed-off-by: Grant Likely --- drivers/gpio/gpiolib.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index c1d8f7bdcd8..5a79cb955d9 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1195,20 +1195,17 @@ struct gpio_chip *gpiochip_find(void *data, int (*match)(struct gpio_chip *chip, void *data)) { - struct gpio_chip *chip = NULL; + struct gpio_chip *chip; unsigned long flags; - int i; spin_lock_irqsave(&gpio_lock, flags); - for (i = 0; i < ARCH_NR_GPIOS; i++) { - if (!gpio_desc[i].chip) - continue; - - if (match(gpio_desc[i].chip, data)) { - chip = gpio_desc[i].chip; + list_for_each_entry(chip, &gpio_chips, list) + if (match(chip, data)) break; - } - } + + /* No match? */ + if (&chip->list == &gpio_chips) + chip = NULL; spin_unlock_irqrestore(&gpio_lock, flags); return chip; -- cgit v1.2.3 From cb1650d4e0da27e88c1a1bd8fe98c40ae1a5d313 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Sun, 3 Feb 2013 01:29:27 +0900 Subject: gpiolib: use gpio_chips list in sysfs ops This makes the code both simpler and faster compared to parsing the GPIO number space. Signed-off-by: Alexandre Courbot Signed-off-by: Grant Likely --- drivers/gpio/gpiolib.c | 37 ++++++++++--------------------------- 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 5a79cb955d9..585d7c3ce12 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1890,45 +1890,28 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) static void *gpiolib_seq_start(struct seq_file *s, loff_t *pos) { struct gpio_chip *chip = NULL; - unsigned int gpio; - void *ret = NULL; - loff_t index = 0; + loff_t index = *pos; /* REVISIT this isn't locked against gpio_chip removal ... */ - for (gpio = 0; gpio_is_valid(gpio); gpio++) { - if (gpio_desc[gpio].chip == chip) - continue; - - chip = gpio_desc[gpio].chip; - if (!chip) - continue; - - if (index++ >= *pos) { - ret = chip; - break; - } - } - s->private = ""; - return ret; + list_for_each_entry(chip, &gpio_chips, list) + if (index-- == 0) + return chip; + + return NULL; } static void *gpiolib_seq_next(struct seq_file *s, void *v, loff_t *pos) { struct gpio_chip *chip = v; - unsigned int gpio; void *ret = NULL; - /* skip GPIOs provided by the current chip */ - for (gpio = chip->base + chip->ngpio; gpio_is_valid(gpio); gpio++) { - chip = gpio_desc[gpio].chip; - if (chip) { - ret = chip; - break; - } - } + if (list_is_last(&chip->list, &gpio_chips)) + ret = NULL; + else + ret = list_entry(chip->list.next, struct gpio_chip, list); s->private = "\n"; ++*pos; -- cgit v1.2.3 From 83cabe33eb05b51a6239a3df344d89cafac2306c Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Sun, 3 Feb 2013 01:29:28 +0900 Subject: gpiolib: use gpio_chips list in gpiochip_find_base Re-implement gpiochip_find_base using the list of chips instead of the global gpio_desc[] array. This makes it both simpler and more efficient, and is needed to remove the global descriptors array. The new code should preserve the exact same GPIO number assignment policy as the code it is replacing. There shouldn't be any visible change to the assigned GPIO numbers. Signed-off-by: Alexandre Courbot [grant.likely: Added comment about assignment policy] Signed-off-by: Grant Likely --- drivers/gpio/gpiolib.c | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 585d7c3ce12..8ccf68bb8a4 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -126,30 +126,25 @@ struct gpio_chip *gpio_to_chip(unsigned gpio) /* dynamic allocation of GPIOs, e.g. on a hotplugged device */ static int gpiochip_find_base(int ngpio) { - int i; - int spare = 0; - int base = -ENOSPC; - - for (i = ARCH_NR_GPIOS - 1; i >= 0 ; i--) { - struct gpio_desc *desc = &gpio_desc[i]; - struct gpio_chip *chip = desc->chip; - - if (!chip) { - spare++; - if (spare == ngpio) { - base = i; - break; - } - } else { - spare = 0; - if (chip) - i -= chip->ngpio - 1; - } + struct gpio_chip *chip; + int base = ARCH_NR_GPIOS - ngpio; + + list_for_each_entry_reverse(chip, &gpio_chips, list) { + /* found a free space? */ + if (chip->base + chip->ngpio <= base) + break; + else + /* nope, check the space right before the chip */ + base = chip->base - ngpio; } - if (gpio_is_valid(base)) + if (gpio_is_valid(base)) { pr_debug("%s: found new base at %d\n", __func__, base); - return base; + return base; + } else { + pr_err("%s: cannot find free range\n", __func__); + return -ENOSPC; + } } /* caller ensures gpio is valid and requested, chip->get_direction may sleep */ -- cgit v1.2.3 From 372e722ea4dd4ca11c3d04845e11cbc15f32144c Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Sun, 3 Feb 2013 01:29:29 +0900 Subject: gpiolib: use descriptors internally Make sure gpiolib works internally with descriptors and (chip, offset) pairs instead of using the global integer namespace. This prepares the ground for the removal of the global gpio_desc[] array and the introduction of the descriptor-based GPIO API. Signed-off-by: Alexandre Courbot Reviewed-by: Linus Walleij [grant.likely: Squash in fix for link error when CONFIG_SYSFS=n] Signed-off-by: Grant Likely --- drivers/gpio/gpiolib.c | 514 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 338 insertions(+), 176 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 8ccf68bb8a4..866431f674c 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -78,6 +78,28 @@ static LIST_HEAD(gpio_chips); static DEFINE_IDR(dirent_idr); #endif +/* + * Internal gpiod_* API using descriptors instead of the integer namespace. + * Most of this should eventually go public. + */ +static int gpiod_request(struct gpio_desc *desc, const char *label); +static void gpiod_free(struct gpio_desc *desc); +static int gpiod_direction_input(struct gpio_desc *desc); +static int gpiod_direction_output(struct gpio_desc *desc, int value); +static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce); +static int gpiod_get_value_cansleep(struct gpio_desc *desc); +static void gpiod_set_value_cansleep(struct gpio_desc *desc, int value); +static int gpiod_get_value(struct gpio_desc *desc); +static void gpiod_set_value(struct gpio_desc *desc, int value); +static int gpiod_cansleep(struct gpio_desc *desc); +static int gpiod_to_irq(struct gpio_desc *desc); +static int gpiod_export(struct gpio_desc *desc, bool direction_may_change); +static int gpiod_export_link(struct device *dev, const char *name, + struct gpio_desc *desc); +static int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value); +static void gpiod_unexport(struct gpio_desc *desc); + + static inline void desc_set_label(struct gpio_desc *d, const char *label) { #ifdef CONFIG_DEBUG_FS @@ -85,6 +107,36 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label) #endif } +/* + * Return the GPIO number of the passed descriptor relative to its chip + */ +static int gpio_chip_hwgpio(const struct gpio_desc *desc) +{ + return (desc - &gpio_desc[0]) - desc->chip->base; +} + +/** + * Convert a GPIO number to its descriptor + */ +static struct gpio_desc *gpio_to_desc(unsigned gpio) +{ + if (WARN(!gpio_is_valid(gpio), "invalid GPIO %d\n", gpio)) + return NULL; + else + return &gpio_desc[gpio]; +} + +/** + * Convert a GPIO descriptor to the integer namespace. + * This should disappear in the future but is needed since we still + * use GPIO numbers for error messages and sysfs nodes + */ +static int desc_to_gpio(const struct gpio_desc *desc) +{ + return desc - &gpio_desc[0]; +} + + /* Warn when drivers omit gpio_request() calls -- legal but ill-advised * when setting direction, and otherwise illegal. Until board setup code * and drivers use explicit requests everywhere (which won't happen when @@ -96,10 +148,10 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label) * only "legal" in the sense that (old) code using it won't break yet, * but instead only triggers a WARN() stack dump. */ -static int gpio_ensure_requested(struct gpio_desc *desc, unsigned offset) +static int gpio_ensure_requested(struct gpio_desc *desc) { const struct gpio_chip *chip = desc->chip; - const int gpio = chip->base + offset; + const int gpio = desc_to_gpio(desc); if (WARN(test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0, "autorequest GPIO-%d\n", gpio)) { @@ -118,9 +170,14 @@ static int gpio_ensure_requested(struct gpio_desc *desc, unsigned offset) } /* caller holds gpio_lock *OR* gpio is marked as requested */ +static struct gpio_chip *gpiod_to_chip(struct gpio_desc *desc) +{ + return desc->chip; +} + struct gpio_chip *gpio_to_chip(unsigned gpio) { - return gpio_desc[gpio].chip; + return gpiod_to_chip(gpio_to_desc(gpio)); } /* dynamic allocation of GPIOs, e.g. on a hotplugged device */ @@ -148,19 +205,19 @@ static int gpiochip_find_base(int ngpio) } /* caller ensures gpio is valid and requested, chip->get_direction may sleep */ -static int gpio_get_direction(unsigned gpio) +static int gpiod_get_direction(struct gpio_desc *desc) { struct gpio_chip *chip; - struct gpio_desc *desc = &gpio_desc[gpio]; + unsigned offset; int status = -EINVAL; - chip = gpio_to_chip(gpio); - gpio -= chip->base; + chip = gpiod_to_chip(desc); + offset = gpio_chip_hwgpio(desc); if (!chip->get_direction) return status; - status = chip->get_direction(chip, gpio); + status = chip->get_direction(chip, offset); if (status > 0) { /* GPIOF_DIR_IN, or other positive */ status = 1; @@ -204,8 +261,7 @@ static DEFINE_MUTEX(sysfs_lock); 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; + struct gpio_desc *desc = dev_get_drvdata(dev); ssize_t status; mutex_lock(&sysfs_lock); @@ -213,7 +269,7 @@ static ssize_t gpio_direction_show(struct device *dev, if (!test_bit(FLAG_EXPORT, &desc->flags)) { status = -EIO; } else { - gpio_get_direction(gpio); + gpiod_get_direction(desc); status = sprintf(buf, "%s\n", test_bit(FLAG_IS_OUT, &desc->flags) ? "out" : "in"); @@ -226,8 +282,7 @@ static ssize_t gpio_direction_show(struct device *dev, static ssize_t gpio_direction_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - const struct gpio_desc *desc = dev_get_drvdata(dev); - unsigned gpio = desc - gpio_desc; + struct gpio_desc *desc = dev_get_drvdata(dev); ssize_t status; mutex_lock(&sysfs_lock); @@ -235,11 +290,11 @@ static ssize_t gpio_direction_store(struct device *dev, if (!test_bit(FLAG_EXPORT, &desc->flags)) status = -EIO; else if (sysfs_streq(buf, "high")) - status = gpio_direction_output(gpio, 1); + status = gpiod_direction_output(desc, 1); else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low")) - status = gpio_direction_output(gpio, 0); + status = gpiod_direction_output(desc, 0); else if (sysfs_streq(buf, "in")) - status = gpio_direction_input(gpio); + status = gpiod_direction_input(desc); else status = -EINVAL; @@ -253,8 +308,7 @@ static /* const */ DEVICE_ATTR(direction, 0644, static ssize_t gpio_value_show(struct device *dev, struct device_attribute *attr, char *buf) { - const struct gpio_desc *desc = dev_get_drvdata(dev); - unsigned gpio = desc - gpio_desc; + struct gpio_desc *desc = dev_get_drvdata(dev); ssize_t status; mutex_lock(&sysfs_lock); @@ -264,7 +318,7 @@ static ssize_t gpio_value_show(struct device *dev, } else { int value; - value = !!gpio_get_value_cansleep(gpio); + value = !!gpiod_get_value_cansleep(desc); if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) value = !value; @@ -278,8 +332,7 @@ static ssize_t gpio_value_show(struct device *dev, static ssize_t gpio_value_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - const struct gpio_desc *desc = dev_get_drvdata(dev); - unsigned gpio = desc - gpio_desc; + struct gpio_desc *desc = dev_get_drvdata(dev); ssize_t status; mutex_lock(&sysfs_lock); @@ -295,7 +348,7 @@ static ssize_t gpio_value_store(struct device *dev, if (status == 0) { if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) value = !value; - gpio_set_value_cansleep(gpio, value != 0); + gpiod_set_value_cansleep(desc, value != 0); status = size; } } @@ -325,7 +378,7 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, if ((desc->flags & GPIO_TRIGGER_MASK) == gpio_flags) return 0; - irq = gpio_to_irq(desc - gpio_desc); + irq = gpiod_to_irq(desc); if (irq < 0) return -EIO; @@ -595,29 +648,32 @@ static ssize_t export_store(struct class *class, struct class_attribute *attr, const char *buf, size_t len) { - long gpio; - int status; + long gpio; + struct gpio_desc *desc; + int status; status = strict_strtol(buf, 0, &gpio); if (status < 0) goto done; + desc = gpio_to_desc(gpio); + /* No extra locking here; FLAG_SYSFS just signifies that the * request and export were done by on behalf of userspace, so * they may be undone on its behalf too. */ - status = gpio_request(gpio, "sysfs"); + status = gpiod_request(desc, "sysfs"); if (status < 0) { if (status == -EPROBE_DEFER) status = -ENODEV; goto done; } - status = gpio_export(gpio, true); + status = gpiod_export(desc, true); if (status < 0) - gpio_free(gpio); + gpiod_free(desc); else - set_bit(FLAG_SYSFS, &gpio_desc[gpio].flags); + set_bit(FLAG_SYSFS, &desc->flags); done: if (status) @@ -629,8 +685,9 @@ static ssize_t unexport_store(struct class *class, struct class_attribute *attr, const char *buf, size_t len) { - long gpio; - int status; + long gpio; + struct gpio_desc *desc; + int status; status = strict_strtol(buf, 0, &gpio); if (status < 0) @@ -638,17 +695,18 @@ static ssize_t unexport_store(struct class *class, status = -EINVAL; + desc = gpio_to_desc(gpio); /* reject bogus commands (gpio_unexport ignores them) */ - if (!gpio_is_valid(gpio)) + if (!desc) goto done; /* No extra locking here; FLAG_SYSFS just signifies that the * request and export were done by on behalf of userspace, so * they may be undone on its behalf too. */ - if (test_and_clear_bit(FLAG_SYSFS, &gpio_desc[gpio].flags)) { + if (test_and_clear_bit(FLAG_SYSFS, &desc->flags)) { status = 0; - gpio_free(gpio); + gpiod_free(desc); } done: if (status) @@ -685,13 +743,13 @@ static struct class gpio_class = { * * Returns zero on success, else an error. */ -int gpio_export(unsigned gpio, bool direction_may_change) +static int gpiod_export(struct gpio_desc *desc, bool direction_may_change) { unsigned long flags; - struct gpio_desc *desc; int status; const char *ioname = NULL; struct device *dev; + int offset; /* can't export until sysfs is available ... */ if (!gpio_class.p) { @@ -699,20 +757,19 @@ int gpio_export(unsigned gpio, bool direction_may_change) return -ENOENT; } - if (!gpio_is_valid(gpio)) { - pr_debug("%s: gpio %d is not valid\n", __func__, gpio); + if (!desc) { + pr_debug("%s: invalid gpio descriptor\n", __func__); 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)) { spin_unlock_irqrestore(&gpio_lock, flags); pr_debug("%s: gpio %d unavailable (requested=%d, exported=%d)\n", - __func__, gpio, + __func__, desc_to_gpio(desc), test_bit(FLAG_REQUESTED, &desc->flags), test_bit(FLAG_EXPORT, &desc->flags)); status = -EPERM; @@ -723,11 +780,13 @@ int gpio_export(unsigned gpio, bool direction_may_change) 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]; + offset = gpio_chip_hwgpio(desc); + if (desc->chip->names && desc->chip->names[offset]) + ioname = desc->chip->names[offset]; dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0), - desc, ioname ? ioname : "gpio%u", gpio); + desc, ioname ? ioname : "gpio%u", + desc_to_gpio(desc)); if (IS_ERR(dev)) { status = PTR_ERR(dev); goto fail_unlock; @@ -743,7 +802,7 @@ int gpio_export(unsigned gpio, bool direction_may_change) goto fail_unregister_device; } - if (gpio_to_irq(gpio) >= 0 && (direction_may_change || + if (gpiod_to_irq(desc) >= 0 && (direction_may_change || !test_bit(FLAG_IS_OUT, &desc->flags))) { status = device_create_file(dev, &dev_attr_edge); if (status) @@ -758,9 +817,15 @@ fail_unregister_device: device_unregister(dev); fail_unlock: mutex_unlock(&sysfs_lock); - pr_debug("%s: gpio%d status %d\n", __func__, gpio, status); + pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc), + status); return status; } + +int gpio_export(unsigned gpio, bool direction_may_change) +{ + return gpiod_export(gpio_to_desc(gpio), direction_may_change); +} EXPORT_SYMBOL_GPL(gpio_export); static int match_export(struct device *dev, void *data) @@ -779,18 +844,16 @@ static int match_export(struct device *dev, void *data) * * Returns zero on success, else an error. */ -int gpio_export_link(struct device *dev, const char *name, unsigned gpio) +static int gpiod_export_link(struct device *dev, const char *name, + struct gpio_desc *desc) { - struct gpio_desc *desc; int status = -EINVAL; - if (!gpio_is_valid(gpio)) + if (!desc) goto done; mutex_lock(&sysfs_lock); - desc = &gpio_desc[gpio]; - if (test_bit(FLAG_EXPORT, &desc->flags)) { struct device *tdev; @@ -807,12 +870,17 @@ int gpio_export_link(struct device *dev, const char *name, unsigned gpio) done: if (status) - pr_debug("%s: gpio%d status %d\n", __func__, gpio, status); + pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc), + status); return status; } -EXPORT_SYMBOL_GPL(gpio_export_link); +int gpio_export_link(struct device *dev, const char *name, unsigned gpio) +{ + return gpiod_export_link(dev, name, gpio_to_desc(gpio)); +} +EXPORT_SYMBOL_GPL(gpio_export_link); /** * gpio_sysfs_set_active_low - set the polarity of gpio sysfs value @@ -826,19 +894,16 @@ EXPORT_SYMBOL_GPL(gpio_export_link); * * Returns zero on success, else an error. */ -int gpio_sysfs_set_active_low(unsigned gpio, int value) +static int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value) { - struct gpio_desc *desc; struct device *dev = NULL; int status = -EINVAL; - if (!gpio_is_valid(gpio)) + if (!desc) goto done; mutex_lock(&sysfs_lock); - desc = &gpio_desc[gpio]; - if (test_bit(FLAG_EXPORT, &desc->flags)) { dev = class_find_device(&gpio_class, NULL, desc, match_export); if (dev == NULL) { @@ -854,10 +919,16 @@ unlock: done: if (status) - pr_debug("%s: gpio%d status %d\n", __func__, gpio, status); + pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc), + status); return status; } + +int gpio_sysfs_set_active_low(unsigned gpio, int value) +{ + return gpiod_sysfs_set_active_low(gpio_to_desc(gpio), value); +} EXPORT_SYMBOL_GPL(gpio_sysfs_set_active_low); /** @@ -866,21 +937,18 @@ EXPORT_SYMBOL_GPL(gpio_sysfs_set_active_low); * * This is implicit on gpio_free(). */ -void gpio_unexport(unsigned gpio) +static void gpiod_unexport(struct gpio_desc *desc) { - struct gpio_desc *desc; int status = 0; struct device *dev = NULL; - if (!gpio_is_valid(gpio)) { + if (!desc) { status = -EINVAL; goto done; } mutex_lock(&sysfs_lock); - desc = &gpio_desc[gpio]; - if (test_bit(FLAG_EXPORT, &desc->flags)) { dev = class_find_device(&gpio_class, NULL, desc, match_export); @@ -892,13 +960,20 @@ void gpio_unexport(unsigned gpio) } mutex_unlock(&sysfs_lock); + if (dev) { device_unregister(dev); put_device(dev); } done: if (status) - pr_debug("%s: gpio%d status %d\n", __func__, gpio, status); + pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc), + status); +} + +void gpio_unexport(unsigned gpio) +{ + gpiod_unexport(gpio_to_desc(gpio)); } EXPORT_SYMBOL_GPL(gpio_unexport); @@ -1007,6 +1082,27 @@ static inline void gpiochip_unexport(struct gpio_chip *chip) { } +static inline int gpiod_export(struct gpio_desc *desc, + bool direction_may_change) +{ + return -ENOSYS; +} + +static inline int gpiod_export_link(struct device *dev, const char *name, + struct gpio_desc *desc) +{ + return -ENOSYS; +} + +static inline int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value) +{ + return -ENOSYS; +} + +static inline void gpiod_unexport(struct gpio_desc *desc) +{ +} + #endif /* CONFIG_GPIO_SYSFS */ /* @@ -1282,20 +1378,18 @@ EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges); * on each other, and help provide better diagnostics in debugfs. * They're called even less than the "set direction" calls. */ -int gpio_request(unsigned gpio, const char *label) +static int gpiod_request(struct gpio_desc *desc, const char *label) { - struct gpio_desc *desc; struct gpio_chip *chip; int status = -EPROBE_DEFER; unsigned long flags; spin_lock_irqsave(&gpio_lock, flags); - if (!gpio_is_valid(gpio)) { + if (!desc) { status = -EINVAL; goto done; } - desc = &gpio_desc[gpio]; chip = desc->chip; if (chip == NULL) goto done; @@ -1319,7 +1413,7 @@ int gpio_request(unsigned gpio, const char *label) if (chip->request) { /* chip->request may sleep */ spin_unlock_irqrestore(&gpio_lock, flags); - status = chip->request(chip, gpio - chip->base); + status = chip->request(chip, gpio_chip_hwgpio(desc)); spin_lock_irqsave(&gpio_lock, flags); if (status < 0) { @@ -1332,42 +1426,46 @@ int gpio_request(unsigned gpio, const char *label) if (chip->get_direction) { /* chip->get_direction may sleep */ spin_unlock_irqrestore(&gpio_lock, flags); - gpio_get_direction(gpio); + gpiod_get_direction(desc); spin_lock_irqsave(&gpio_lock, flags); } done: if (status) - pr_debug("gpio_request: gpio-%d (%s) status %d\n", - gpio, label ? : "?", status); + pr_debug("_gpio_request: gpio-%d (%s) status %d\n", + desc ? desc_to_gpio(desc) : -1, + label ? : "?", status); spin_unlock_irqrestore(&gpio_lock, flags); return status; } + +int gpio_request(unsigned gpio, const char *label) +{ + return gpiod_request(gpio_to_desc(gpio), label); +} EXPORT_SYMBOL_GPL(gpio_request); -void gpio_free(unsigned gpio) +static void gpiod_free(struct gpio_desc *desc) { unsigned long flags; - struct gpio_desc *desc; struct gpio_chip *chip; might_sleep(); - if (!gpio_is_valid(gpio)) { + if (!desc) { WARN_ON(extra_checks); return; } - gpio_unexport(gpio); + gpiod_unexport(desc); spin_lock_irqsave(&gpio_lock, flags); - desc = &gpio_desc[gpio]; chip = desc->chip; if (chip && test_bit(FLAG_REQUESTED, &desc->flags)) { if (chip->free) { spin_unlock_irqrestore(&gpio_lock, flags); might_sleep_if(chip->can_sleep); - chip->free(chip, gpio - chip->base); + chip->free(chip, gpio_chip_hwgpio(desc)); spin_lock_irqsave(&gpio_lock, flags); } desc_set_label(desc, NULL); @@ -1381,6 +1479,11 @@ void gpio_free(unsigned gpio) spin_unlock_irqrestore(&gpio_lock, flags); } + +void gpio_free(unsigned gpio) +{ + gpiod_free(gpio_to_desc(gpio)); +} EXPORT_SYMBOL_GPL(gpio_free); /** @@ -1391,29 +1494,32 @@ EXPORT_SYMBOL_GPL(gpio_free); */ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) { + struct gpio_desc *desc; int err; - err = gpio_request(gpio, label); + desc = gpio_to_desc(gpio); + + err = gpiod_request(desc, label); if (err) return err; if (flags & GPIOF_OPEN_DRAIN) - set_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags); + set_bit(FLAG_OPEN_DRAIN, &desc->flags); if (flags & GPIOF_OPEN_SOURCE) - set_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags); + set_bit(FLAG_OPEN_SOURCE, &desc->flags); if (flags & GPIOF_DIR_IN) - err = gpio_direction_input(gpio); + err = gpiod_direction_input(desc); else - err = gpio_direction_output(gpio, + err = gpiod_direction_output(desc, (flags & GPIOF_INIT_HIGH) ? 1 : 0); if (err) goto free_gpio; if (flags & GPIOF_EXPORT) { - err = gpio_export(gpio, flags & GPIOF_EXPORT_CHANGEABLE); + err = gpiod_export(desc, flags & GPIOF_EXPORT_CHANGEABLE); if (err) goto free_gpio; } @@ -1421,7 +1527,7 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) return 0; free_gpio: - gpio_free(gpio); + gpiod_free(desc); return err; } EXPORT_SYMBOL_GPL(gpio_request_one); @@ -1477,13 +1583,14 @@ EXPORT_SYMBOL_GPL(gpio_free_array); const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset) { unsigned gpio = chip->base + offset; + struct gpio_desc *desc = &gpio_desc[gpio]; - if (!gpio_is_valid(gpio) || gpio_desc[gpio].chip != chip) + if (!gpio_is_valid(gpio) || desc->chip != chip) return NULL; - if (test_bit(FLAG_REQUESTED, &gpio_desc[gpio].flags) == 0) + if (test_bit(FLAG_REQUESTED, &desc->flags) == 0) return NULL; #ifdef CONFIG_DEBUG_FS - return gpio_desc[gpio].label; + return desc->label; #else return "?"; #endif @@ -1500,24 +1607,21 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested); * rely on gpio_request() having been called beforehand. */ -int gpio_direction_input(unsigned gpio) +static int gpiod_direction_input(struct gpio_desc *desc) { unsigned long flags; struct gpio_chip *chip; - struct gpio_desc *desc = &gpio_desc[gpio]; int status = -EINVAL; + int offset; spin_lock_irqsave(&gpio_lock, flags); - if (!gpio_is_valid(gpio)) + if (!desc) goto fail; chip = desc->chip; if (!chip || !chip->get || !chip->direction_input) goto fail; - gpio -= chip->base; - if (gpio >= chip->ngpio) - goto fail; - status = gpio_ensure_requested(desc, gpio); + status = gpio_ensure_requested(desc); if (status < 0) goto fail; @@ -1527,11 +1631,12 @@ int gpio_direction_input(unsigned gpio) might_sleep_if(chip->can_sleep); + offset = gpio_chip_hwgpio(desc); if (status) { - status = chip->request(chip, gpio); + status = chip->request(chip, offset); if (status < 0) { pr_debug("GPIO-%d: chip request fail, %d\n", - chip->base + gpio, status); + desc_to_gpio(desc), status); /* and it's not available to anyone else ... * gpio_request() is the fully clean solution. */ @@ -1539,48 +1644,54 @@ int gpio_direction_input(unsigned gpio) } } - status = chip->direction_input(chip, gpio); + status = chip->direction_input(chip, offset); if (status == 0) clear_bit(FLAG_IS_OUT, &desc->flags); - trace_gpio_direction(chip->base + gpio, 1, status); + trace_gpio_direction(desc_to_gpio(desc), 1, status); lose: return status; fail: spin_unlock_irqrestore(&gpio_lock, flags); - if (status) + if (status) { + int gpio = -1; + if (desc) + gpio = desc_to_gpio(desc); pr_debug("%s: gpio-%d status %d\n", __func__, gpio, status); + } return status; } + +int gpio_direction_input(unsigned gpio) +{ + return gpiod_direction_input(gpio_to_desc(gpio)); +} EXPORT_SYMBOL_GPL(gpio_direction_input); -int gpio_direction_output(unsigned gpio, int value) +static int gpiod_direction_output(struct gpio_desc *desc, int value) { unsigned long flags; struct gpio_chip *chip; - struct gpio_desc *desc = &gpio_desc[gpio]; int status = -EINVAL; + int offset; /* Open drain pin should not be driven to 1 */ if (value && test_bit(FLAG_OPEN_DRAIN, &desc->flags)) - return gpio_direction_input(gpio); + return gpiod_direction_input(desc); /* Open source pin should not be driven to 0 */ if (!value && test_bit(FLAG_OPEN_SOURCE, &desc->flags)) - return gpio_direction_input(gpio); + return gpiod_direction_input(desc); spin_lock_irqsave(&gpio_lock, flags); - if (!gpio_is_valid(gpio)) + if (!desc) goto fail; chip = desc->chip; if (!chip || !chip->set || !chip->direction_output) goto fail; - gpio -= chip->base; - if (gpio >= chip->ngpio) - goto fail; - status = gpio_ensure_requested(desc, gpio); + status = gpio_ensure_requested(desc); if (status < 0) goto fail; @@ -1590,11 +1701,12 @@ int gpio_direction_output(unsigned gpio, int value) might_sleep_if(chip->can_sleep); + offset = gpio_chip_hwgpio(desc); if (status) { - status = chip->request(chip, gpio); + status = chip->request(chip, offset); if (status < 0) { pr_debug("GPIO-%d: chip request fail, %d\n", - chip->base + gpio, status); + desc_to_gpio(desc), status); /* and it's not available to anyone else ... * gpio_request() is the fully clean solution. */ @@ -1602,20 +1714,29 @@ int gpio_direction_output(unsigned gpio, int value) } } - status = chip->direction_output(chip, gpio, value); + status = chip->direction_output(chip, offset, value); if (status == 0) set_bit(FLAG_IS_OUT, &desc->flags); - trace_gpio_value(chip->base + gpio, 0, value); - trace_gpio_direction(chip->base + gpio, 0, status); + trace_gpio_value(desc_to_gpio(desc), 0, value); + trace_gpio_direction(desc_to_gpio(desc), 0, status); lose: return status; fail: spin_unlock_irqrestore(&gpio_lock, flags); - if (status) + if (status) { + int gpio = -1; + if (desc) + gpio = desc_to_gpio(desc); pr_debug("%s: gpio-%d status %d\n", __func__, gpio, status); + } return status; } + +int gpio_direction_output(unsigned gpio, int value) +{ + return gpiod_direction_output(gpio_to_desc(gpio), value); +} EXPORT_SYMBOL_GPL(gpio_direction_output); /** @@ -1623,24 +1744,22 @@ EXPORT_SYMBOL_GPL(gpio_direction_output); * @gpio: the gpio to set debounce time * @debounce: debounce time is microseconds */ -int gpio_set_debounce(unsigned gpio, unsigned debounce) +static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) { unsigned long flags; struct gpio_chip *chip; - struct gpio_desc *desc = &gpio_desc[gpio]; int status = -EINVAL; + int offset; spin_lock_irqsave(&gpio_lock, flags); - if (!gpio_is_valid(gpio)) + if (!desc) goto fail; chip = desc->chip; if (!chip || !chip->set || !chip->set_debounce) goto fail; - gpio -= chip->base; - if (gpio >= chip->ngpio) - goto fail; - status = gpio_ensure_requested(desc, gpio); + + status = gpio_ensure_requested(desc); if (status < 0) goto fail; @@ -1650,16 +1769,26 @@ int gpio_set_debounce(unsigned gpio, unsigned debounce) might_sleep_if(chip->can_sleep); - return chip->set_debounce(chip, gpio, debounce); + offset = gpio_chip_hwgpio(desc); + return chip->set_debounce(chip, offset, debounce); fail: spin_unlock_irqrestore(&gpio_lock, flags); - if (status) + if (status) { + int gpio = -1; + if (desc) + gpio = desc_to_gpio(desc); pr_debug("%s: gpio-%d status %d\n", __func__, gpio, status); + } return status; } + +int gpio_set_debounce(unsigned gpio, unsigned debounce) +{ + return gpiod_set_debounce(gpio_to_desc(gpio), debounce); +} EXPORT_SYMBOL_GPL(gpio_set_debounce); /* I/O calls are only valid after configuration completed; the relevant @@ -1693,18 +1822,25 @@ EXPORT_SYMBOL_GPL(gpio_set_debounce); * It returns the zero or nonzero value provided by the associated * gpio_chip.get() method; or zero if no such method is provided. */ -int __gpio_get_value(unsigned gpio) +static int gpiod_get_value(struct gpio_desc *desc) { struct gpio_chip *chip; int value; + int offset; - chip = gpio_to_chip(gpio); + chip = desc->chip; + offset = gpio_chip_hwgpio(desc); /* Should be using gpio_get_value_cansleep() */ WARN_ON(chip->can_sleep); - value = chip->get ? chip->get(chip, gpio - chip->base) : 0; - trace_gpio_value(gpio, 1, value); + value = chip->get ? chip->get(chip, offset) : 0; + trace_gpio_value(desc_to_gpio(desc), 1, value); return value; } + +int __gpio_get_value(unsigned gpio) +{ + return gpiod_get_value(gpio_to_desc(gpio)); +} EXPORT_SYMBOL_GPL(__gpio_get_value); /* @@ -1713,23 +1849,25 @@ EXPORT_SYMBOL_GPL(__gpio_get_value); * @chip: Gpio chip. * @value: Non-zero for setting it HIGH otherise it will set to LOW. */ -static void _gpio_set_open_drain_value(unsigned gpio, - struct gpio_chip *chip, int value) +static void _gpio_set_open_drain_value(struct gpio_desc *desc, int value) { int err = 0; + struct gpio_chip *chip = desc->chip; + int offset = gpio_chip_hwgpio(desc); + if (value) { - err = chip->direction_input(chip, gpio - chip->base); + err = chip->direction_input(chip, offset); if (!err) - clear_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags); + clear_bit(FLAG_IS_OUT, &desc->flags); } else { - err = chip->direction_output(chip, gpio - chip->base, 0); + err = chip->direction_output(chip, offset, 0); if (!err) - set_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags); + set_bit(FLAG_IS_OUT, &desc->flags); } - trace_gpio_direction(gpio, value, err); + trace_gpio_direction(desc_to_gpio(desc), value, err); if (err < 0) pr_err("%s: Error in set_value for open drain gpio%d err %d\n", - __func__, gpio, err); + __func__, desc_to_gpio(desc), err); } /* @@ -1738,26 +1876,27 @@ static void _gpio_set_open_drain_value(unsigned gpio, * @chip: Gpio chip. * @value: Non-zero for setting it HIGH otherise it will set to LOW. */ -static void _gpio_set_open_source_value(unsigned gpio, - struct gpio_chip *chip, int value) +static void _gpio_set_open_source_value(struct gpio_desc *desc, int value) { int err = 0; + struct gpio_chip *chip = desc->chip; + int offset = gpio_chip_hwgpio(desc); + if (value) { - err = chip->direction_output(chip, gpio - chip->base, 1); + err = chip->direction_output(chip, offset, 1); if (!err) - set_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags); + set_bit(FLAG_IS_OUT, &desc->flags); } else { - err = chip->direction_input(chip, gpio - chip->base); + err = chip->direction_input(chip, offset); if (!err) - clear_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags); + clear_bit(FLAG_IS_OUT, &desc->flags); } - trace_gpio_direction(gpio, !value, err); + trace_gpio_direction(desc_to_gpio(desc), !value, err); if (err < 0) pr_err("%s: Error in set_value for open source gpio%d err %d\n", - __func__, gpio, err); + __func__, desc_to_gpio(desc), err); } - /** * __gpio_set_value() - assign a gpio's value * @gpio: gpio whose value will be assigned @@ -1767,20 +1906,25 @@ static void _gpio_set_open_source_value(unsigned gpio, * This is used directly or indirectly to implement gpio_set_value(). * It invokes the associated gpio_chip.set() method. */ -void __gpio_set_value(unsigned gpio, int value) +static void gpiod_set_value(struct gpio_desc *desc, int value) { struct gpio_chip *chip; - chip = gpio_to_chip(gpio); + chip = desc->chip; /* Should be using gpio_set_value_cansleep() */ WARN_ON(chip->can_sleep); - trace_gpio_value(gpio, 0, value); - if (test_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags)) - _gpio_set_open_drain_value(gpio, chip, value); - else if (test_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags)) - _gpio_set_open_source_value(gpio, chip, value); + trace_gpio_value(desc_to_gpio(desc), 0, value); + if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) + _gpio_set_open_drain_value(desc, value); + else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) + _gpio_set_open_source_value(desc, value); else - chip->set(chip, gpio - chip->base, value); + chip->set(chip, gpio_chip_hwgpio(desc), value); +} + +void __gpio_set_value(unsigned gpio, int value) +{ + return gpiod_set_value(gpio_to_desc(gpio), value); } EXPORT_SYMBOL_GPL(__gpio_set_value); @@ -1792,14 +1936,15 @@ EXPORT_SYMBOL_GPL(__gpio_set_value); * This is used directly or indirectly to implement gpio_cansleep(). It * returns nonzero if access reading or writing the GPIO value can sleep. */ -int __gpio_cansleep(unsigned gpio) +static int gpiod_cansleep(struct gpio_desc *desc) { - struct gpio_chip *chip; - /* only call this on GPIOs that are valid! */ - chip = gpio_to_chip(gpio); + return desc->chip->can_sleep; +} - return chip->can_sleep; +int __gpio_cansleep(unsigned gpio) +{ + return gpiod_cansleep(gpio_to_desc(gpio)); } EXPORT_SYMBOL_GPL(__gpio_cansleep); @@ -1812,50 +1957,67 @@ EXPORT_SYMBOL_GPL(__gpio_cansleep); * It returns the number of the IRQ signaled by this (input) GPIO, * or a negative errno. */ -int __gpio_to_irq(unsigned gpio) +static int gpiod_to_irq(struct gpio_desc *desc) { struct gpio_chip *chip; + int offset; - chip = gpio_to_chip(gpio); - return chip->to_irq ? chip->to_irq(chip, gpio - chip->base) : -ENXIO; + chip = desc->chip; + offset = gpio_chip_hwgpio(desc); + return chip->to_irq ? chip->to_irq(chip, offset) : -ENXIO; } -EXPORT_SYMBOL_GPL(__gpio_to_irq); +int __gpio_to_irq(unsigned gpio) +{ + return gpiod_to_irq(gpio_to_desc(gpio)); +} +EXPORT_SYMBOL_GPL(__gpio_to_irq); /* There's no value in making it easy to inline GPIO calls that may sleep. * Common examples include ones connected to I2C or SPI chips. */ -int gpio_get_value_cansleep(unsigned gpio) +static int gpiod_get_value_cansleep(struct gpio_desc *desc) { struct gpio_chip *chip; int value; + int offset; might_sleep_if(extra_checks); - chip = gpio_to_chip(gpio); - value = chip->get ? chip->get(chip, gpio - chip->base) : 0; - trace_gpio_value(gpio, 1, value); + chip = desc->chip; + offset = gpio_chip_hwgpio(desc); + value = chip->get ? chip->get(chip, offset) : 0; + trace_gpio_value(desc_to_gpio(desc), 1, value); return value; } + +int gpio_get_value_cansleep(unsigned gpio) +{ + return gpiod_get_value_cansleep(gpio_to_desc(gpio)); +} EXPORT_SYMBOL_GPL(gpio_get_value_cansleep); -void gpio_set_value_cansleep(unsigned gpio, int value) +static void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) { struct gpio_chip *chip; might_sleep_if(extra_checks); - chip = gpio_to_chip(gpio); - trace_gpio_value(gpio, 0, value); - if (test_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags)) - _gpio_set_open_drain_value(gpio, chip, value); - else if (test_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags)) - _gpio_set_open_source_value(gpio, chip, value); + chip = desc->chip; + trace_gpio_value(desc_to_gpio(desc), 0, value); + if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) + _gpio_set_open_drain_value(desc, value); + else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) + _gpio_set_open_source_value(desc, value); else - chip->set(chip, gpio - chip->base, value); + chip->set(chip, gpio_chip_hwgpio(desc), value); } -EXPORT_SYMBOL_GPL(gpio_set_value_cansleep); +void gpio_set_value_cansleep(unsigned gpio, int value) +{ + return gpiod_set_value_cansleep(gpio_to_desc(gpio), value); +} +EXPORT_SYMBOL_GPL(gpio_set_value_cansleep); #ifdef CONFIG_DEBUG_FS @@ -1870,7 +2032,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); + gpiod_get_direction(gdesc); is_out = test_bit(FLAG_IS_OUT, &gdesc->flags); seq_printf(s, " gpio-%-3d (%-20.20s) %s %s", gpio, gdesc->label, -- cgit v1.2.3 From 6c0b4e6c85d085bd92966bc2b8da73e2d7f35929 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Sun, 3 Feb 2013 01:29:30 +0900 Subject: gpiolib: let gpio_chip reference its descriptors Add a pointer to the gpio_chip structure that references the array of GPIO descriptors belonging to the chip, and update gpiolib code to use this pointer instead of the global gpio_desc[] array. This is another step towards the removal of the gpio_desc[] global array. Signed-off-by: Alexandre Courbot Reviewed-by: Linus Walleij Signed-off-by: Grant Likely --- drivers/gpio/gpiolib.c | 39 +++++++++++++++++++++++---------------- include/asm-generic/gpio.h | 3 +++ 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 866431f674c..5050693dcc3 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -72,6 +72,8 @@ struct gpio_desc { }; static struct gpio_desc gpio_desc[ARCH_NR_GPIOS]; +#define GPIO_OFFSET_VALID(chip, offset) (offset >= 0 && offset < chip->ngpio) + static LIST_HEAD(gpio_chips); #ifdef CONFIG_GPIO_SYSFS @@ -112,7 +114,7 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label) */ static int gpio_chip_hwgpio(const struct gpio_desc *desc) { - return (desc - &gpio_desc[0]) - desc->chip->base; + return desc - &desc->chip->desc[0]; } /** @@ -133,7 +135,7 @@ static struct gpio_desc *gpio_to_desc(unsigned gpio) */ static int desc_to_gpio(const struct gpio_desc *desc) { - return desc - &gpio_desc[0]; + return desc->chip->base + gpio_chip_hwgpio(desc); } @@ -1007,9 +1009,9 @@ static int gpiochip_export(struct gpio_chip *chip) unsigned gpio; spin_lock_irqsave(&gpio_lock, flags); - gpio = chip->base; - while (gpio_desc[gpio].chip == chip) - gpio_desc[gpio++].chip = NULL; + gpio = 0; + while (gpio < chip->ngpio) + chip->desc[gpio++].chip = NULL; spin_unlock_irqrestore(&gpio_lock, flags); pr_debug("%s: chip %s status %d\n", __func__, @@ -1186,8 +1188,11 @@ int gpiochip_add(struct gpio_chip *chip) status = gpiochip_add_to_list(chip); if (status == 0) { - for (id = base; id < base + chip->ngpio; id++) { - gpio_desc[id].chip = chip; + chip->desc = &gpio_desc[chip->base]; + + for (id = 0; id < chip->ngpio; id++) { + struct gpio_desc *desc = &chip->desc[id]; + desc->chip = chip; /* REVISIT: most hardware initializes GPIOs as * inputs (often with pullups enabled) so power @@ -1196,7 +1201,7 @@ int gpiochip_add(struct gpio_chip *chip) * and in case chip->get_direction is not set, * we may expose the wrong direction in sysfs. */ - gpio_desc[id].flags = !chip->direction_input + desc->flags = !chip->direction_input ? (1 << FLAG_IS_OUT) : 0; } @@ -1249,15 +1254,15 @@ int gpiochip_remove(struct gpio_chip *chip) gpiochip_remove_pin_ranges(chip); of_gpiochip_remove(chip); - for (id = chip->base; id < chip->base + chip->ngpio; id++) { - if (test_bit(FLAG_REQUESTED, &gpio_desc[id].flags)) { + for (id = 0; id < chip->ngpio; id++) { + if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags)) { status = -EBUSY; break; } } if (status == 0) { - for (id = chip->base; id < chip->base + chip->ngpio; id++) - gpio_desc[id].chip = NULL; + for (id = 0; id < chip->ngpio; id++) + chip->desc[id].chip = NULL; list_del(&chip->list); } @@ -1582,11 +1587,13 @@ EXPORT_SYMBOL_GPL(gpio_free_array); */ const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset) { - unsigned gpio = chip->base + offset; - struct gpio_desc *desc = &gpio_desc[gpio]; + struct gpio_desc *desc; - if (!gpio_is_valid(gpio) || desc->chip != chip) + if (!GPIO_OFFSET_VALID(chip, offset)) return NULL; + + desc = &chip->desc[offset]; + if (test_bit(FLAG_REQUESTED, &desc->flags) == 0) return NULL; #ifdef CONFIG_DEBUG_FS @@ -2025,7 +2032,7 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) { unsigned i; unsigned gpio = chip->base; - struct gpio_desc *gdesc = &gpio_desc[gpio]; + struct gpio_desc *gdesc = &chip->desc[0]; int is_out; for (i = 0; i < chip->ngpio; i++, gpio++, gdesc++) { diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index b562f95cdc2..bde646995d1 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -47,6 +47,7 @@ struct gpio; struct seq_file; struct module; struct device_node; +struct gpio_desc; /** * struct gpio_chip - abstract a GPIO controller @@ -76,6 +77,7 @@ struct device_node; * negative during registration, requests dynamic ID allocation. * @ngpio: the number of GPIOs handled by this controller; the last GPIO * handled is (base + ngpio - 1). + * @desc: array of ngpio descriptors. Private. * @can_sleep: flag must be set iff get()/set() methods sleep, as they * must while accessing GPIO expander chips over I2C or SPI * @names: if set, must be an array of strings to use as alternative @@ -126,6 +128,7 @@ struct gpio_chip { struct gpio_chip *chip); int base; u16 ngpio; + struct gpio_desc *desc; const char *const *names; unsigned can_sleep:1; unsigned exported:1; -- cgit v1.2.3 From 362432aed5e5b497a8cf7b20c268ba71df93c045 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sat, 9 Feb 2013 09:41:49 +0000 Subject: gpiolib: Fix locking on gpio debugfs files The debugfs files really need to hold the gpiolib spinlock before accessing the list. Otherwise chip addition/removal will cause an oops. Cc: Alexandre Courbot Cc: Linus Walleij Signed-off-by: Grant Likely --- drivers/gpio/gpiolib.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 5050693dcc3..4b3f388bcc6 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2053,29 +2053,35 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) static void *gpiolib_seq_start(struct seq_file *s, loff_t *pos) { + unsigned long flags; struct gpio_chip *chip = NULL; loff_t index = *pos; - /* REVISIT this isn't locked against gpio_chip removal ... */ - s->private = ""; + spin_lock_irqsave(&gpio_lock, flags); list_for_each_entry(chip, &gpio_chips, list) - if (index-- == 0) + if (index-- == 0) { + spin_unlock_irqrestore(&gpio_lock, flags); return chip; + } + spin_unlock_irqrestore(&gpio_lock, flags); return NULL; } static void *gpiolib_seq_next(struct seq_file *s, void *v, loff_t *pos) { + unsigned long flags; struct gpio_chip *chip = v; void *ret = NULL; + spin_lock_irqsave(&gpio_lock, flags); if (list_is_last(&chip->list, &gpio_chips)) ret = NULL; else ret = list_entry(chip->list.next, struct gpio_chip, list); + spin_unlock_irqrestore(&gpio_lock, flags); s->private = "\n"; ++*pos; -- cgit v1.2.3 From 9f01d30ee191a74f1e7a2ac0710f064f472d000a Mon Sep 17 00:00:00 2001 From: Tony Prisk Date: Fri, 18 Jan 2013 17:58:22 +1300 Subject: gpio/vt8500: memory cleanup missing This driver is missing a .remove callback, and the fail path on probe is incomplete. If an error occurs in vt8500_add_chips, gpio_base is not unmapped. The driver is also ignoring the return value from this function so if a chip fails to register it completes as successful. Replaced pr_err with dev_err in vt8500_add_chips since the device is available. There is also no .remove callback defined so the function is added. Signed-off-by: Tony Prisk Signed-off-by: Grant Likely --- drivers/gpio/gpio-vt8500.c | 61 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 12 deletions(-) diff --git a/drivers/gpio/gpio-vt8500.c b/drivers/gpio/gpio-vt8500.c index 9a7c434d294..81683ca35ac 100644 --- a/drivers/gpio/gpio-vt8500.c +++ b/drivers/gpio/gpio-vt8500.c @@ -127,6 +127,12 @@ struct vt8500_gpio_chip { void __iomem *base; }; +struct vt8500_data { + struct vt8500_gpio_chip *chip; + void __iomem *iobase; + int num_banks; +}; + #define to_vt8500(__chip) container_of(__chip, struct vt8500_gpio_chip, chip) @@ -224,19 +230,32 @@ static int vt8500_of_xlate(struct gpio_chip *gc, static int vt8500_add_chips(struct platform_device *pdev, void __iomem *base, const struct vt8500_gpio_data *data) { + struct vt8500_data *priv; struct vt8500_gpio_chip *vtchip; struct gpio_chip *chip; int i; int pin_cnt = 0; - vtchip = devm_kzalloc(&pdev->dev, + priv = devm_kzalloc(&pdev->dev, sizeof(struct vt8500_data), GFP_KERNEL); + if (!priv) { + dev_err(&pdev->dev, "failed to allocate memory\n"); + return -ENOMEM; + } + + priv->chip = devm_kzalloc(&pdev->dev, sizeof(struct vt8500_gpio_chip) * data->num_banks, GFP_KERNEL); - if (!vtchip) { - pr_err("%s: failed to allocate chip memory\n", __func__); + if (!priv->chip) { + dev_err(&pdev->dev, "failed to allocate chip memory\n"); return -ENOMEM; } + priv->iobase = base; + priv->num_banks = data->num_banks; + platform_set_drvdata(pdev, priv); + + vtchip = priv->chip; + for (i = 0; i < data->num_banks; i++) { vtchip[i].base = base; vtchip[i].regs = &data->banks[i]; @@ -273,36 +292,54 @@ static struct of_device_id vt8500_gpio_dt_ids[] = { static int vt8500_gpio_probe(struct platform_device *pdev) { + int ret; void __iomem *gpio_base; - struct device_node *np; + struct resource *res; const struct of_device_id *of_id = of_match_device(vt8500_gpio_dt_ids, &pdev->dev); if (!of_id) { - dev_err(&pdev->dev, "Failed to find gpio controller\n"); + dev_err(&pdev->dev, "No matching driver data\n"); return -ENODEV; } - np = pdev->dev.of_node; - if (!np) { - dev_err(&pdev->dev, "Missing GPIO description in devicetree\n"); - return -EFAULT; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "Unable to get IO resource\n"); + return -ENODEV; } - gpio_base = of_iomap(np, 0); + gpio_base = devm_request_and_ioremap(&pdev->dev, res); if (!gpio_base) { dev_err(&pdev->dev, "Unable to map GPIO registers\n"); - of_node_put(np); return -ENOMEM; } - vt8500_add_chips(pdev, gpio_base, of_id->data); + ret = vt8500_add_chips(pdev, gpio_base, of_id->data); + + return ret; +} + +static int vt8500_gpio_remove(struct platform_device *pdev) +{ + int i; + int ret; + struct vt8500_data *priv = platform_get_drvdata(pdev); + struct vt8500_gpio_chip *vtchip = priv->chip; + + for (i = 0; i < priv->num_banks; i++) { + ret = gpiochip_remove(&vtchip[i].chip); + if (ret) + dev_warn(&pdev->dev, "gpiochip_remove returned %d\n", + ret); + } return 0; } static struct platform_driver vt8500_gpio_driver = { .probe = vt8500_gpio_probe, + .remove = vt8500_gpio_remove, .driver = { .name = "vt8500-gpio", .owner = THIS_MODULE, -- cgit v1.2.3 From e9a65bb63e5fe45b9d0ecd1983749786858da14d Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Wed, 6 Feb 2013 18:44:32 +0800 Subject: gpio: using common order: let 'static const' instead of 'const static' 'const static ' is not a common order, better to use 'static const' instead. building: make EXTRA_CFLAGS=-W ARCH=arm drivers/gpio/gpio-omap.c:1479: warning: 'static' is not at beginning of declaration drivers/gpio/gpio-omap.c:1485: warning: 'static' is not at beginning of declaration drivers/gpio/gpio-omap.c:1491: warning: 'static' is not at beginning of declaration Signed-off-by: Chen Gang Acked-by: Santosh Shilimkar Signed-off-by: Grant Likely --- drivers/gpio/gpio-omap.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index f1fbedb2a6f..159f5c57eb4 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1476,19 +1476,19 @@ static struct omap_gpio_reg_offs omap4_gpio_regs = { .fallingdetect = OMAP4_GPIO_FALLINGDETECT, }; -const static struct omap_gpio_platform_data omap2_pdata = { +static const struct omap_gpio_platform_data omap2_pdata = { .regs = &omap2_gpio_regs, .bank_width = 32, .dbck_flag = false, }; -const static struct omap_gpio_platform_data omap3_pdata = { +static const struct omap_gpio_platform_data omap3_pdata = { .regs = &omap2_gpio_regs, .bank_width = 32, .dbck_flag = true, }; -const static struct omap_gpio_platform_data omap4_pdata = { +static const struct omap_gpio_platform_data omap4_pdata = { .regs = &omap4_gpio_regs, .bank_width = 32, .dbck_flag = true, -- cgit v1.2.3 From c7886b18273b07042e25e8d3ba5c983837b84123 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 13 Feb 2013 00:56:13 +0900 Subject: gpio: em: Use irq_domain_add_simple() to fix runtime error Adjust the gpio-em.c driver to reconsider the pdata->irq_base variable. Non-DT board code like for instance board-kzm9d.c needs to operate of a static IRQ range for platform devices. So this patch is updating the code to make use of the function irq_domain_add_simple() instead of irq_domain_add_linear(). Fixes a EMEV2 / KZM9D runtime error caused by the following commit: 7385500 gpio/em: convert to linear IRQ domain Cc: stable@kernel.org Signed-off-by: Magnus Damm Tested-by: Simon Horman Reported-by: Simon Horman Signed-off-by: Linus Walleij --- drivers/gpio/gpio-em.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index bdc8302e711..deca78f9931 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -299,8 +299,9 @@ static int em_gio_probe(struct platform_device *pdev) irq_chip->irq_set_type = em_gio_irq_set_type; irq_chip->flags = IRQCHIP_SKIP_SET_WAKE; - p->irq_domain = irq_domain_add_linear(pdev->dev.of_node, + p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, pdata->number_of_pins, + pdata->irq_base, &em_gio_irq_domain_ops, p); if (!p->irq_domain) { ret = -ENXIO; -- cgit v1.2.3 From 9170100ee46402af6d318134525c728027318d67 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 21 Feb 2013 11:42:57 +0100 Subject: arm64: select ARCH_WANT_OPTIONAL_GPIOLIB An architecture should not unconditionally enable 'GENERIC_GPIO' without providing an implementation. In case of arm64, selecting ARCH_WANT_OPTIONAL_GPIOLIB is the right solution, because it lets us enable GPIOLIB when configuring the kernel, and that implicitly turns on GENERIC_GPIO. Reported-by: Mark Rutland Signed-off-by: Arnd Bergmann Acked-by: Catalin Marinas Acked-by: Linus Walleij Signed-off-by: Grant Likely --- arch/arm64/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index f8f362aafee..e9a8fe60791 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -1,6 +1,7 @@ config ARM64 def_bool y select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE + select ARCH_WANT_OPTIONAL_GPIOLIB select ARCH_WANT_COMPAT_IPC_PARSE_VERSION select ARM_AMBA select CLONE_BACKWARDS @@ -92,7 +93,7 @@ config IOMMU_HELPER def_bool SWIOTLB config GENERIC_GPIO - def_bool y + bool source "init/Kconfig" -- cgit v1.2.3