* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-04-27 13:13 ` Linus Walleij 0 siblings, 0 replies; 57+ messages in thread From: Linus Walleij @ 2011-04-27 13:13 UTC (permalink / raw) To: Grant Likely, linux-kernel, linux-arm-kernel Cc: Lee Jones, Linus Walleij, Jonas Aaberg From: Linus Walleij <linus.walleij@linaro.org> This rewrites the U300 GPIO driver using gpiolib and the irq_chip abstractions, makes it runtime-configured rather than compile-time, and moves it to the drivers/gpio subsystem where it belongs, depopulating the ARM tree of one more driver. Cc: Jonas Aaberg <jonas.aberg@stericsson.com> Acked-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> --- arch/arm/Kconfig | 2 +- arch/arm/mach-u300/Kconfig | 1 + arch/arm/mach-u300/Makefile | 6 +- arch/arm/mach-u300/core.c | 31 ++- arch/arm/mach-u300/gpio.c | 700 -------------------------- arch/arm/mach-u300/include/mach/gpio.h | 163 +------ arch/arm/mach-u300/include/mach/irqs.h | 25 +- drivers/gpio/Kconfig | 9 + drivers/gpio/Makefile | 1 + drivers/gpio/u300-gpio.c | 836 ++++++++++++++++++++++++++++++++ include/linux/gpio/u300.h | 32 ++ 11 files changed, 932 insertions(+), 874 deletions(-) delete mode 100644 arch/arm/mach-u300/gpio.c create mode 100644 drivers/gpio/u300-gpio.c create mode 100644 include/linux/gpio/u300.h diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 377a7a5..5fb980d 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -820,7 +820,7 @@ config ARCH_U300 select ARM_VIC select GENERIC_CLOCKEVENTS select CLKDEV_LOOKUP - select GENERIC_GPIO + select ARCH_REQUIRE_GPIOLIB help Support for ST-Ericsson U300 series mobile platforms. diff --git a/arch/arm/mach-u300/Kconfig b/arch/arm/mach-u300/Kconfig index 32a7b0f..7b5c229 100644 --- a/arch/arm/mach-u300/Kconfig +++ b/arch/arm/mach-u300/Kconfig @@ -6,6 +6,7 @@ comment "ST-Ericsson Mobile Platform Products" config MACH_U300 bool "U300" + select GPIO_U300 comment "ST-Ericsson U300/U330/U335/U365 Feature Selections" diff --git a/arch/arm/mach-u300/Makefile b/arch/arm/mach-u300/Makefile index fab46fe..73da230 100644 --- a/arch/arm/mach-u300/Makefile +++ b/arch/arm/mach-u300/Makefile @@ -2,11 +2,7 @@ # Makefile for the linux kernel, U300 machine. # -obj-y := core.o clock.o timer.o gpio.o padmux.o -obj-m := -obj-n := -obj- := - +obj-y := core.o clock.o timer.o padmux.o obj-$(CONFIG_ARCH_U300) += u300.o obj-$(CONFIG_MMC) += mmc.o obj-$(CONFIG_SPI_PL022) += spi.o diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c index 513d6ab..ddb604c 100644 --- a/arch/arm/mach-u300/core.c +++ b/arch/arm/mach-u300/core.c @@ -25,6 +25,7 @@ #include <linux/err.h> #include <linux/mtd/nand.h> #include <linux/mtd/fsmc.h> +#include <linux/gpio/u300.h> #include <asm/types.h> #include <asm/setup.h> @@ -239,7 +240,7 @@ static struct resource gpio_resources[] = { .end = IRQ_U300_GPIO_PORT2, .flags = IORESOURCE_IRQ, }, -#ifdef U300_COH901571_3 +#if defined(CONFIG_MACH_U300_BS365) || defined(CONFIG_MACH_U300_BS335) { .name = "gpio3", .start = IRQ_U300_GPIO_PORT3, @@ -252,6 +253,7 @@ static struct resource gpio_resources[] = { .end = IRQ_U300_GPIO_PORT4, .flags = IORESOURCE_IRQ, }, +#endif #ifdef CONFIG_MACH_U300_BS335 { .name = "gpio5", @@ -266,7 +268,6 @@ static struct resource gpio_resources[] = { .flags = IORESOURCE_IRQ, }, #endif /* CONFIG_MACH_U300_BS335 */ -#endif /* U300_COH901571_3 */ }; static struct resource keypad_resources[] = { @@ -1556,11 +1557,35 @@ static struct platform_device i2c1_device = { .resource = i2c1_resources, }; +/* + * The different variants have a few different versions of the + * GPIO block, with different number of ports. + */ +static struct u300_gpio_platform u300_gpio_plat = { +#if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330) + .variant = U300_GPIO_COH901335, + .ports = 3, +#endif +#ifdef CONFIG_MACH_U300_BS335 + .variant = U300_GPIO_COH901571_3_BS335, + .ports = 7, +#endif +#ifdef CONFIG_MACH_U300_BS365 + .variant = U300_GPIO_COH901571_3_BS365, + .ports = 5, +#endif + .gpio_base = 0, + .gpio_irq_base = IRQ_U300_GPIO_BASE, +}; + static struct platform_device gpio_device = { .name = "u300-gpio", .id = -1, .num_resources = ARRAY_SIZE(gpio_resources), .resource = gpio_resources, + .dev = { + .platform_data = &u300_gpio_plat, + }, }; static struct platform_device keypad_device = { @@ -1666,7 +1691,7 @@ void __init u300_init_irq(void) BUG_ON(IS_ERR(clk)); clk_enable(clk); - for (i = 0; i < NR_IRQS; i++) + for (i = 0; i < U300_VIC_IRQS_END; i++) set_bit(i, (unsigned long *) &mask[0]); vic_init((void __iomem *) U300_INTCON0_VBASE, 0, mask[0], mask[0]); vic_init((void __iomem *) U300_INTCON1_VBASE, 32, mask[1], mask[1]); diff --git a/arch/arm/mach-u300/gpio.c b/arch/arm/mach-u300/gpio.c deleted file mode 100644 index d927901..0000000 --- a/arch/arm/mach-u300/gpio.c +++ /dev/null @@ -1,700 +0,0 @@ -/* - * - * arch/arm/mach-u300/gpio.c - * - * - * Copyright (C) 2007-2009 ST-Ericsson AB - * License terms: GNU General Public License (GPL) version 2 - * U300 GPIO module. - * This can driver either of the two basic GPIO cores - * available in the U300 platforms: - * COH 901 335 - Used in DB3150 (U300 1.0) and DB3200 (U330 1.0) - * COH 901 571/3 - Used in DB3210 (U365 2.0) and DB3350 (U335 1.0) - * Notice that you also have inline macros in <asm-arch/gpio.h> - * Author: Linus Walleij <linus.walleij@stericsson.com> - * Author: Jonas Aaberg <jonas.aberg@stericsson.com> - * - */ -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/errno.h> -#include <linux/io.h> -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/platform_device.h> -#include <linux/gpio.h> - -/* Reference to GPIO block clock */ -static struct clk *clk; - -/* Memory resource */ -static struct resource *memres; -static void __iomem *virtbase; -static struct device *gpiodev; - -struct u300_gpio_port { - const char *name; - int irq; - int number; -}; - - -static struct u300_gpio_port gpio_ports[] = { - { - .name = "gpio0", - .number = 0, - }, - { - .name = "gpio1", - .number = 1, - }, - { - .name = "gpio2", - .number = 2, - }, -#ifdef U300_COH901571_3 - { - .name = "gpio3", - .number = 3, - }, - { - .name = "gpio4", - .number = 4, - }, -#ifdef CONFIG_MACH_U300_BS335 - { - .name = "gpio5", - .number = 5, - }, - { - .name = "gpio6", - .number = 6, - }, -#endif -#endif - -}; - - -#ifdef U300_COH901571_3 - -/* Default input value */ -#define DEFAULT_OUTPUT_LOW 0 -#define DEFAULT_OUTPUT_HIGH 1 - -/* GPIO Pull-Up status */ -#define DISABLE_PULL_UP 0 -#define ENABLE_PULL_UP 1 - -#define GPIO_NOT_USED 0 -#define GPIO_IN 1 -#define GPIO_OUT 2 - -struct u300_gpio_configuration_data { - unsigned char pin_usage; - unsigned char default_output_value; - unsigned char pull_up; -}; - -/* Initial configuration */ -const struct u300_gpio_configuration_data -u300_gpio_config[U300_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = { -#ifdef CONFIG_MACH_U300_BS335 - /* Port 0, pins 0-7 */ - { - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_HIGH, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} - }, - /* Port 1, pins 0-7 */ - { - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_HIGH, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} - }, - /* Port 2, pins 0-7 */ - { - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP} - }, - /* Port 3, pins 0-7 */ - { - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} - }, - /* Port 4, pins 0-7 */ - { - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} - }, - /* Port 5, pins 0-7 */ - { - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} - }, - /* Port 6, pind 0-7 */ - { - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} - } -#endif - -#ifdef CONFIG_MACH_U300_BS365 - /* Port 0, pins 0-7 */ - { - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} - }, - /* Port 1, pins 0-7 */ - { - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_HIGH, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} - }, - /* Port 2, pins 0-7 */ - { - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP} - }, - /* Port 3, pins 0-7 */ - { - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP} - }, - /* Port 4, pins 0-7 */ - { - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - /* These 4 pins doesn't exist on DB3210 */ - {GPIO_OUT, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP} - } -#endif -}; -#endif - - -/* No users == we can power down GPIO */ -static int gpio_users; - -struct gpio_struct { - int (*callback)(void *); - void *data; - int users; -}; - -static struct gpio_struct gpio_pin[U300_GPIO_MAX]; - -/* - * Let drivers register callback in order to get notified when there is - * an interrupt on the gpio pin - */ -int gpio_register_callback(unsigned gpio, int (*func)(void *arg), void *data) -{ - if (gpio_pin[gpio].callback) - dev_warn(gpiodev, "%s: WARNING: callback already " - "registered for gpio pin#%d\n", __func__, gpio); - gpio_pin[gpio].callback = func; - gpio_pin[gpio].data = data; - - return 0; -} -EXPORT_SYMBOL(gpio_register_callback); - -int gpio_unregister_callback(unsigned gpio) -{ - if (!gpio_pin[gpio].callback) - dev_warn(gpiodev, "%s: WARNING: callback already " - "unregistered for gpio pin#%d\n", __func__, gpio); - gpio_pin[gpio].callback = NULL; - gpio_pin[gpio].data = NULL; - - return 0; -} -EXPORT_SYMBOL(gpio_unregister_callback); - -/* Non-zero means valid */ -int gpio_is_valid(int number) -{ - if (number >= 0 && - number < (U300_GPIO_NUM_PORTS * U300_GPIO_PINS_PER_PORT)) - return 1; - return 0; -} -EXPORT_SYMBOL(gpio_is_valid); - -int gpio_request(unsigned gpio, const char *label) -{ - if (gpio_pin[gpio].users) - return -EINVAL; - else - gpio_pin[gpio].users++; - - gpio_users++; - - return 0; -} -EXPORT_SYMBOL(gpio_request); - -void gpio_free(unsigned gpio) -{ - gpio_users--; - gpio_pin[gpio].users--; - if (unlikely(gpio_pin[gpio].users < 0)) { - dev_warn(gpiodev, "warning: gpio#%d release mismatch\n", - gpio); - gpio_pin[gpio].users = 0; - } - - return; -} -EXPORT_SYMBOL(gpio_free); - -/* This returns zero or nonzero */ -int gpio_get_value(unsigned gpio) -{ - return readl(virtbase + U300_GPIO_PXPDIR + - PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING) & (1 << (gpio & 0x07)); -} -EXPORT_SYMBOL(gpio_get_value); - -/* - * We hope that the compiler will optimize away the unused branch - * in case "value" is a constant - */ -void gpio_set_value(unsigned gpio, int value) -{ - u32 val; - unsigned long flags; - - local_irq_save(flags); - if (value) { - /* set */ - val = readl(virtbase + U300_GPIO_PXPDOR + - PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING) - & (1 << (gpio & 0x07)); - writel(val | (1 << (gpio & 0x07)), virtbase + - U300_GPIO_PXPDOR + - PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING); - } else { - /* clear */ - val = readl(virtbase + U300_GPIO_PXPDOR + - PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING) - & (1 << (gpio & 0x07)); - writel(val & ~(1 << (gpio & 0x07)), virtbase + - U300_GPIO_PXPDOR + - PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING); - } - local_irq_restore(flags); -} -EXPORT_SYMBOL(gpio_set_value); - -int gpio_direction_input(unsigned gpio) -{ - unsigned long flags; - u32 val; - - if (gpio > U300_GPIO_MAX) - return -EINVAL; - - local_irq_save(flags); - val = readl(virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - /* Mask out this pin*/ - val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << ((gpio & 0x07) << 1)); - /* This is not needed since it sets the bits to zero.*/ - /* val |= (U300_GPIO_PXPCR_PIN_MODE_INPUT << (gpio*2)); */ - writel(val, virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - local_irq_restore(flags); - return 0; -} -EXPORT_SYMBOL(gpio_direction_input); - -int gpio_direction_output(unsigned gpio, int value) -{ - unsigned long flags; - u32 val; - - if (gpio > U300_GPIO_MAX) - return -EINVAL; - - local_irq_save(flags); - val = readl(virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - /* Mask out this pin */ - val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << ((gpio & 0x07) << 1)); - /* - * FIXME: configure for push/pull, open drain or open source per pin - * in setup. The current driver will only support push/pull. - */ - val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL - << ((gpio & 0x07) << 1)); - writel(val, virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - gpio_set_value(gpio, value); - local_irq_restore(flags); - return 0; -} -EXPORT_SYMBOL(gpio_direction_output); - -/* - * Enable an IRQ, edge is rising edge (!= 0) or falling edge (==0). - */ -void enable_irq_on_gpio_pin(unsigned gpio, int edge) -{ - u32 val; - unsigned long flags; - local_irq_save(flags); - - val = readl(virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - val |= (1 << (gpio & 0x07)); - writel(val, virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - val = readl(virtbase + U300_GPIO_PXICR + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - if (edge) - val |= (1 << (gpio & 0x07)); - else - val &= ~(1 << (gpio & 0x07)); - writel(val, virtbase + U300_GPIO_PXICR + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - local_irq_restore(flags); -} -EXPORT_SYMBOL(enable_irq_on_gpio_pin); - -void disable_irq_on_gpio_pin(unsigned gpio) -{ - u32 val; - unsigned long flags; - - local_irq_save(flags); - val = readl(virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - val &= ~(1 << (gpio & 0x07)); - writel(val, virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - local_irq_restore(flags); -} -EXPORT_SYMBOL(disable_irq_on_gpio_pin); - -/* Enable (value == 0) or disable (value == 1) internal pullup */ -void gpio_pullup(unsigned gpio, int value) -{ - u32 val; - unsigned long flags; - - local_irq_save(flags); - if (value) { - val = readl(virtbase + U300_GPIO_PXPER + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - writel(val | (1 << (gpio & 0x07)), virtbase + U300_GPIO_PXPER + - PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING); - } else { - val = readl(virtbase + U300_GPIO_PXPER + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - writel(val & ~(1 << (gpio & 0x07)), virtbase + U300_GPIO_PXPER + - PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING); - } - local_irq_restore(flags); -} -EXPORT_SYMBOL(gpio_pullup); - -static irqreturn_t gpio_irq_handler(int irq, void *dev_id) -{ - struct u300_gpio_port *port = dev_id; - u32 val; - int pin; - - /* Read event register */ - val = readl(virtbase + U300_GPIO_PXIEV + port->number * - U300_GPIO_PORTX_SPACING); - /* Mask with enable register */ - val &= readl(virtbase + U300_GPIO_PXIEV + port->number * - U300_GPIO_PORTX_SPACING); - /* Mask relevant bits */ - val &= U300_GPIO_PXIEV_ALL_IRQ_EVENT_MASK; - /* ACK IRQ (clear event) */ - writel(val, virtbase + U300_GPIO_PXIEV + port->number * - U300_GPIO_PORTX_SPACING); - /* Print message */ - while (val != 0) { - unsigned gpio; - - pin = __ffs(val); - /* mask off this pin */ - val &= ~(1 << pin); - gpio = (port->number << 3) + pin; - - if (gpio_pin[gpio].callback) - (void)gpio_pin[gpio].callback(gpio_pin[gpio].data); - else - dev_dbg(gpiodev, "stray GPIO IRQ on line %d\n", - gpio); - } - return IRQ_HANDLED; -} - -static void gpio_set_initial_values(void) -{ -#ifdef U300_COH901571_3 - int i, j; - unsigned long flags; - u32 val; - - /* Write default values to all pins */ - for (i = 0; i < U300_GPIO_NUM_PORTS; i++) { - val = 0; - for (j = 0; j < 8; j++) - val |= (u32) (u300_gpio_config[i][j].default_output_value != DEFAULT_OUTPUT_LOW) << j; - local_irq_save(flags); - writel(val, virtbase + U300_GPIO_PXPDOR + i * U300_GPIO_PORTX_SPACING); - local_irq_restore(flags); - } - - /* - * Put all pins that are set to either 'GPIO_OUT' or 'GPIO_NOT_USED' - * to output and 'GPIO_IN' to input for each port. And initialize - * default value on outputs. - */ - for (i = 0; i < U300_GPIO_NUM_PORTS; i++) { - for (j = 0; j < U300_GPIO_PINS_PER_PORT; j++) { - local_irq_save(flags); - val = readl(virtbase + U300_GPIO_PXPCR + - i * U300_GPIO_PORTX_SPACING); - /* Mask out this pin */ - val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << (j << 1)); - - if (u300_gpio_config[i][j].pin_usage != GPIO_IN) - val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL << (j << 1)); - writel(val, virtbase + U300_GPIO_PXPCR + - i * U300_GPIO_PORTX_SPACING); - local_irq_restore(flags); - } - } - - /* Enable or disable the internal pull-ups in the GPIO ASIC block */ - for (i = 0; i < U300_GPIO_MAX; i++) { - val = 0; - for (j = 0; j < 8; j++) - val |= (u32)((u300_gpio_config[i][j].pull_up == DISABLE_PULL_UP) << j); - local_irq_save(flags); - writel(val, virtbase + U300_GPIO_PXPER + i * U300_GPIO_PORTX_SPACING); - local_irq_restore(flags); - } -#endif -} - -static int __init gpio_probe(struct platform_device *pdev) -{ - u32 val; - int err = 0; - int i; - int num_irqs; - - gpiodev = &pdev->dev; - memset(gpio_pin, 0, sizeof(gpio_pin)); - - /* Get GPIO clock */ - clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(clk)) { - err = PTR_ERR(clk); - dev_err(gpiodev, "could not get GPIO clock\n"); - goto err_no_clk; - } - err = clk_enable(clk); - if (err) { - dev_err(gpiodev, "could not enable GPIO clock\n"); - goto err_no_clk_enable; - } - - memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!memres) - goto err_no_resource; - - if (request_mem_region(memres->start, memres->end - memres->start, "GPIO Controller") - == NULL) { - err = -ENODEV; - goto err_no_ioregion; - } - - virtbase = ioremap(memres->start, resource_size(memres)); - if (!virtbase) { - err = -ENOMEM; - goto err_no_ioremap; - } - dev_info(gpiodev, "remapped 0x%08x to %p\n", - memres->start, virtbase); - -#ifdef U300_COH901335 - dev_info(gpiodev, "initializing GPIO Controller COH 901 335\n"); - /* Turn on the GPIO block */ - writel(U300_GPIO_CR_BLOCK_CLOCK_ENABLE, virtbase + U300_GPIO_CR); -#endif - -#ifdef U300_COH901571_3 - dev_info(gpiodev, "initializing GPIO Controller COH 901 571/3\n"); - val = readl(virtbase + U300_GPIO_CR); - dev_info(gpiodev, "COH901571/3 block version: %d, " \ - "number of cores: %d\n", - ((val & 0x0000FE00) >> 9), - ((val & 0x000001FC) >> 2)); - writel(U300_GPIO_CR_BLOCK_CLKRQ_ENABLE, virtbase + U300_GPIO_CR); -#endif - - gpio_set_initial_values(); - - for (num_irqs = 0 ; num_irqs < U300_GPIO_NUM_PORTS; num_irqs++) { - - gpio_ports[num_irqs].irq = - platform_get_irq_byname(pdev, - gpio_ports[num_irqs].name); - - err = request_irq(gpio_ports[num_irqs].irq, - gpio_irq_handler, IRQF_DISABLED, - gpio_ports[num_irqs].name, - &gpio_ports[num_irqs]); - if (err) { - dev_err(gpiodev, "cannot allocate IRQ for %s!\n", - gpio_ports[num_irqs].name); - goto err_no_irq; - } - /* Turns off PortX_irq_force */ - writel(0x0, virtbase + U300_GPIO_PXIFR + - num_irqs * U300_GPIO_PORTX_SPACING); - } - - return 0; - - err_no_irq: - for (i = 0; i < num_irqs; i++) - free_irq(gpio_ports[i].irq, &gpio_ports[i]); - iounmap(virtbase); - err_no_ioremap: - release_mem_region(memres->start, memres->end - memres->start); - err_no_ioregion: - err_no_resource: - clk_disable(clk); - err_no_clk_enable: - clk_put(clk); - err_no_clk: - dev_info(gpiodev, "module ERROR:%d\n", err); - return err; -} - -static int __exit gpio_remove(struct platform_device *pdev) -{ - int i; - - /* Turn off the GPIO block */ - writel(0x00000000U, virtbase + U300_GPIO_CR); - for (i = 0 ; i < U300_GPIO_NUM_PORTS; i++) - free_irq(gpio_ports[i].irq, &gpio_ports[i]); - iounmap(virtbase); - release_mem_region(memres->start, memres->end - memres->start); - clk_disable(clk); - clk_put(clk); - return 0; -} - -static struct platform_driver gpio_driver = { - .driver = { - .name = "u300-gpio", - }, - .remove = __exit_p(gpio_remove), -}; - - -static int __init u300_gpio_init(void) -{ - return platform_driver_probe(&gpio_driver, gpio_probe); -} - -static void __exit u300_gpio_exit(void) -{ - platform_driver_unregister(&gpio_driver); -} - -arch_initcall(u300_gpio_init); -module_exit(u300_gpio_exit); - -MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>"); - -#ifdef U300_COH901571_3 -MODULE_DESCRIPTION("ST-Ericsson AB COH 901 571/3 GPIO driver"); -#endif - -#ifdef U300_COH901335 -MODULE_DESCRIPTION("ST-Ericsson AB COH 901 335 GPIO driver"); -#endif - -MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-u300/include/mach/gpio.h b/arch/arm/mach-u300/include/mach/gpio.h index d5a71ab..6fc3205 100644 --- a/arch/arm/mach-u300/include/mach/gpio.h +++ b/arch/arm/mach-u300/include/mach/gpio.h @@ -17,127 +17,13 @@ #include <linux/io.h> #include <mach/hardware.h> #include <asm/irq.h> +#include <asm-generic/gpio.h> -/* Switch type depending on platform/chip variant */ -#if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330) -#define U300_COH901335 -#endif -#if defined(CONFIG_MACH_U300_BS365) || defined(CONFIG_MACH_U300_BS335) -#define U300_COH901571_3 -#endif - -/* Get base address for regs here */ -#include "u300-regs.h" -/* IRQ numbers */ -#include "irqs.h" - -/* - * This is the GPIO block definitions. GPIO (General Purpose I/O) can be - * used for anything, and often is. The event/enable etc figures are for - * the lowermost pin (pin 0 on each port), shift this left to match your - * pin if you're gonna use these values. - */ -#ifdef U300_COH901335 -#define U300_GPIO_PORTX_SPACING (0x1C) -/* Port X Pin Data Register 32bit, this is both input and output (R/W) */ -#define U300_GPIO_PXPDIR (0x00) -#define U300_GPIO_PXPDOR (0x00) -/* Port X Pin Config Register 32bit (R/W) */ -#define U300_GPIO_PXPCR (0x04) -#define U300_GPIO_PXPCR_ALL_PINS_MODE_MASK (0x0000FFFFUL) -#define U300_GPIO_PXPCR_PIN_MODE_MASK (0x00000003UL) -#define U300_GPIO_PXPCR_PIN_MODE_SHIFT (0x00000002UL) -#define U300_GPIO_PXPCR_PIN_MODE_INPUT (0x00000000UL) -#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL (0x00000001UL) -#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_DRAIN (0x00000002UL) -#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_SOURCE (0x00000003UL) -/* Port X Interrupt Event Register 32bit (R/W) */ -#define U300_GPIO_PXIEV (0x08) -#define U300_GPIO_PXIEV_ALL_IRQ_EVENT_MASK (0x000000FFUL) -#define U300_GPIO_PXIEV_IRQ_EVENT (0x00000001UL) -/* Port X Interrupt Enable Register 32bit (R/W) */ -#define U300_GPIO_PXIEN (0x0C) -#define U300_GPIO_PXIEN_ALL_IRQ_ENABLE_MASK (0x000000FFUL) -#define U300_GPIO_PXIEN_IRQ_ENABLE (0x00000001UL) -/* Port X Interrupt Force Register 32bit (R/W) */ -#define U300_GPIO_PXIFR (0x10) -#define U300_GPIO_PXIFR_ALL_IRQ_FORCE_MASK (0x000000FFUL) -#define U300_GPIO_PXIFR_IRQ_FORCE (0x00000001UL) -/* Port X Interrupt Config Register 32bit (R/W) */ -#define U300_GPIO_PXICR (0x14) -#define U300_GPIO_PXICR_ALL_IRQ_CONFIG_MASK (0x000000FFUL) -#define U300_GPIO_PXICR_IRQ_CONFIG_MASK (0x00000001UL) -#define U300_GPIO_PXICR_IRQ_CONFIG_FALLING_EDGE (0x00000000UL) -#define U300_GPIO_PXICR_IRQ_CONFIG_RISING_EDGE (0x00000001UL) -/* Port X Pull-up Enable Register 32bit (R/W) */ -#define U300_GPIO_PXPER (0x18) -#define U300_GPIO_PXPER_ALL_PULL_UP_DISABLE_MASK (0x000000FFUL) -#define U300_GPIO_PXPER_PULL_UP_DISABLE (0x00000001UL) -/* Control Register 32bit (R/W) */ -#define U300_GPIO_CR (0x54) -#define U300_GPIO_CR_BLOCK_CLOCK_ENABLE (0x00000001UL) -/* three ports of 8 bits each = GPIO pins 0..23 */ -#define U300_GPIO_NUM_PORTS 3 -#define U300_GPIO_PINS_PER_PORT 8 -#define U300_GPIO_MAX (U300_GPIO_PINS_PER_PORT * U300_GPIO_NUM_PORTS - 1) -#endif - -#ifdef U300_COH901571_3 -/* - * Control Register 32bit (R/W) - * bit 15-9 (mask 0x0000FE00) contains the number of cores. 8*cores - * gives the number of GPIO pins. - * bit 8-2 (mask 0x000001FC) contains the core version ID. - */ -#define U300_GPIO_CR (0x00) -#define U300_GPIO_CR_SYNC_SEL_ENABLE (0x00000002UL) -#define U300_GPIO_CR_BLOCK_CLKRQ_ENABLE (0x00000001UL) -#define U300_GPIO_PORTX_SPACING (0x30) -/* Port X Pin Data INPUT Register 32bit (R/W) */ -#define U300_GPIO_PXPDIR (0x04) -/* Port X Pin Data OUTPUT Register 32bit (R/W) */ -#define U300_GPIO_PXPDOR (0x08) -/* Port X Pin Config Register 32bit (R/W) */ -#define U300_GPIO_PXPCR (0x0C) -#define U300_GPIO_PXPCR_ALL_PINS_MODE_MASK (0x0000FFFFUL) -#define U300_GPIO_PXPCR_PIN_MODE_MASK (0x00000003UL) -#define U300_GPIO_PXPCR_PIN_MODE_SHIFT (0x00000002UL) -#define U300_GPIO_PXPCR_PIN_MODE_INPUT (0x00000000UL) -#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL (0x00000001UL) -#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_DRAIN (0x00000002UL) -#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_SOURCE (0x00000003UL) -/* Port X Pull-up Enable Register 32bit (R/W) */ -#define U300_GPIO_PXPER (0x10) -#define U300_GPIO_PXPER_ALL_PULL_UP_DISABLE_MASK (0x000000FFUL) -#define U300_GPIO_PXPER_PULL_UP_DISABLE (0x00000001UL) -/* Port X Interrupt Event Register 32bit (R/W) */ -#define U300_GPIO_PXIEV (0x14) -#define U300_GPIO_PXIEV_ALL_IRQ_EVENT_MASK (0x000000FFUL) -#define U300_GPIO_PXIEV_IRQ_EVENT (0x00000001UL) -/* Port X Interrupt Enable Register 32bit (R/W) */ -#define U300_GPIO_PXIEN (0x18) -#define U300_GPIO_PXIEN_ALL_IRQ_ENABLE_MASK (0x000000FFUL) -#define U300_GPIO_PXIEN_IRQ_ENABLE (0x00000001UL) -/* Port X Interrupt Force Register 32bit (R/W) */ -#define U300_GPIO_PXIFR (0x1C) -#define U300_GPIO_PXIFR_ALL_IRQ_FORCE_MASK (0x000000FFUL) -#define U300_GPIO_PXIFR_IRQ_FORCE (0x00000001UL) -/* Port X Interrupt Config Register 32bit (R/W) */ -#define U300_GPIO_PXICR (0x20) -#define U300_GPIO_PXICR_ALL_IRQ_CONFIG_MASK (0x000000FFUL) -#define U300_GPIO_PXICR_IRQ_CONFIG_MASK (0x00000001UL) -#define U300_GPIO_PXICR_IRQ_CONFIG_FALLING_EDGE (0x00000000UL) -#define U300_GPIO_PXICR_IRQ_CONFIG_RISING_EDGE (0x00000001UL) -#ifdef CONFIG_MACH_U300_BS335 -/* seven ports of 8 bits each = GPIO pins 0..55 */ -#define U300_GPIO_NUM_PORTS 7 -#else -/* five ports of 8 bits each = GPIO pins 0..39 */ -#define U300_GPIO_NUM_PORTS 5 -#endif -#define U300_GPIO_PINS_PER_PORT 8 -#define U300_GPIO_MAX (U300_GPIO_PINS_PER_PORT * U300_GPIO_NUM_PORTS - 1) -#endif +/* Map these overrides to gpiolib functions, simply */ +#define gpio_get_value __gpio_get_value +#define gpio_set_value __gpio_set_value +#define gpio_cansleep __gpio_cansleep +#define gpio_to_irq __gpio_to_irq /* * Individual pin assignments for the B26/S26. Notice that the @@ -254,41 +140,4 @@ #endif -/* translates a pin number to a port number */ -#define PIN_TO_PORT(val) (val >> 3) - -/* These can be found in arch/arm/mach-u300/gpio.c */ -extern int gpio_is_valid(int number); -extern int gpio_request(unsigned gpio, const char *label); -extern void gpio_free(unsigned gpio); -extern int gpio_direction_input(unsigned gpio); -extern int gpio_direction_output(unsigned gpio, int value); -extern int gpio_register_callback(unsigned gpio, - int (*func)(void *arg), - void *); -extern int gpio_unregister_callback(unsigned gpio); -extern void enable_irq_on_gpio_pin(unsigned gpio, int edge); -extern void disable_irq_on_gpio_pin(unsigned gpio); -extern void gpio_pullup(unsigned gpio, int value); -extern int gpio_get_value(unsigned gpio); -extern void gpio_set_value(unsigned gpio, int value); - -#define gpio_get_value_cansleep gpio_get_value -#define gpio_set_value_cansleep gpio_set_value - -/* wrappers to sleep-enable the previous two functions */ -static inline unsigned gpio_to_irq(unsigned gpio) -{ - return PIN_TO_PORT(gpio) + IRQ_U300_GPIO_PORT0; -} - -static inline unsigned irq_to_gpio(unsigned irq) -{ - /* - * FIXME: This is no 1-1 mapping at all, it points to the - * whole block of 8 pins. - */ - return (irq - IRQ_U300_GPIO_PORT0) << 3; -} - #endif diff --git a/arch/arm/mach-u300/include/mach/irqs.h b/arch/arm/mach-u300/include/mach/irqs.h index 09b1b28..d270fea 100644 --- a/arch/arm/mach-u300/include/mach/irqs.h +++ b/arch/arm/mach-u300/include/mach/irqs.h @@ -72,7 +72,7 @@ /* DB3150 and DB3200 have only 45 IRQs */ #if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330) -#define U300_NR_IRQS 45 +#define U300_VIC_IRQS_END 45 #endif /* The DB3350-specific interrupt lines */ @@ -88,7 +88,7 @@ #define IRQ_U300_GPIO_PORT4 53 #define IRQ_U300_GPIO_PORT5 54 #define IRQ_U300_GPIO_PORT6 55 -#define U300_NR_IRQS 56 +#define U300_VIC_IRQS_END 56 #endif /* The DB3210-specific interrupt lines */ @@ -106,16 +106,25 @@ #define IRQ_U300_NFIF 45 #define IRQ_U300_NFIF2 46 #define IRQ_U300_SYSCON_PLL_LOCK 47 -#define U300_NR_IRQS 48 +#define U300_VIC_IRQS_END 48 #endif -#ifdef CONFIG_AB3550_CORE -#define IRQ_AB3550_BASE (U300_NR_IRQS) -#define IRQ_AB3550_END (IRQ_AB3550_BASE + 37) +/* Maximum 8*7 GPIO lines */ +#ifdef CONFIG_GPIO_U300 +#define IRQ_U300_GPIO_BASE (U300_VIC_IRQS_END) +#define IRQ_U300_GPIO_END (IRQ_U300_GPIO_BASE + 56) +#else +#define IRQ_U300_GPIO_END (U300_VIC_IRQS_END) +#endif -#define NR_IRQS (IRQ_AB3550_END + 1) +/* Optional AB3550 mixsig chip */ +#ifdef CONFIG_AB3550_CORE +#define IRQ_AB3550_BASE (IRQ_U300_GPIO_END) +#define IRQ_AB3550_END (IRQ_AB3550_BASE + 38) #else -#define NR_IRQS U300_NR_IRQS +#define IRQ_AB3550_END (IRQ_U300_GPIO_END) #endif +#define NR_IRQS (IRQ_AB3550_END) + #endif diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d3b2953..cc89dfa 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -119,6 +119,15 @@ config GPIO_SCH This driver can also be built as a module. If so, the module will be called sch-gpio. +config GPIO_U300 + bool "ST-Ericsson U300 COH 901 335/571 GPIO" + depends on GPIOLIB && ARCH_U300 + help + Say yes here to support GPIO interface on ST-Ericsson U300. + The names of the two IP block variants supported are + COH 901 335 and COH 901 571/3. They contain 3, 5 or 7 + ports of 8 GPIO pins each. + config GPIO_VX855 tristate "VIA VX855/VX875 GPIO" depends on GPIOLIB && MFD_SUPPORT && PCI diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index becef59..26032b1 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_GPIO_WM831X) += wm831x-gpio.o obj-$(CONFIG_GPIO_WM8350) += wm8350-gpiolib.o obj-$(CONFIG_GPIO_WM8994) += wm8994-gpio.o obj-$(CONFIG_GPIO_SCH) += sch_gpio.o +obj-$(CONFIG_GPIO_U300) += u300-gpio.o obj-$(CONFIG_GPIO_RDC321X) += rdc321x-gpio.o obj-$(CONFIG_GPIO_JANZ_TTL) += janz-ttl.o obj-$(CONFIG_GPIO_SX150X) += sx150x.o diff --git a/drivers/gpio/u300-gpio.c b/drivers/gpio/u300-gpio.c new file mode 100644 index 0000000..d85a116 --- /dev/null +++ b/drivers/gpio/u300-gpio.c @@ -0,0 +1,836 @@ +/* + * Copyright (C) 2007-2011 ST-Ericsson AB + * License terms: GNU General Public License (GPL) version 2 + * U300 GPIO module. + * This can driver either of the two basic GPIO cores + * available in the U300 platforms: + * COH 901 335 - Used in DB3150 (U300 1.0) and DB3200 (U330 1.0) + * COH 901 571/3 - Used in DB3210 (U365 2.0) and DB3350 (U335 1.0) + * Author: Linus Walleij <linus.walleij@linaro.org> + * Author: Jonas Aaberg <jonas.aberg@stericsson.com> + */ +#include <linux/module.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/list.h> +#include <linux/slab.h> +#include <linux/gpio/u300.h> + +/* + * Register definitions for COH 901 335 variant + */ +#define U300_335_PORT_STRIDE (0x1C) +/* Port X Pin Data Register 32bit, this is both input and output (R/W) */ +#define U300_335_PXPDIR (0x00) +#define U300_335_PXPDOR (0x00) +/* Port X Pin Config Register 32bit (R/W) */ +#define U300_335_PXPCR (0x04) +/* This register layout is the same in both blocks */ +#define U300_GPIO_PXPCR_ALL_PINS_MODE_MASK (0x0000FFFFUL) +#define U300_GPIO_PXPCR_PIN_MODE_MASK (0x00000003UL) +#define U300_GPIO_PXPCR_PIN_MODE_SHIFT (0x00000002UL) +#define U300_GPIO_PXPCR_PIN_MODE_INPUT (0x00000000UL) +#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL (0x00000001UL) +#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_DRAIN (0x00000002UL) +#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_SOURCE (0x00000003UL) +/* Port X Interrupt Event Register 32bit (R/W) */ +#define U300_335_PXIEV (0x08) +/* Port X Interrupt Enable Register 32bit (R/W) */ +#define U300_335_PXIEN (0x0C) +/* Port X Interrupt Force Register 32bit (R/W) */ +#define U300_335_PXIFR (0x10) +/* Port X Interrupt Config Register 32bit (R/W) */ +#define U300_335_PXICR (0x14) +/* This register layout is the same in both blocks */ +#define U300_GPIO_PXICR_ALL_IRQ_CONFIG_MASK (0x000000FFUL) +#define U300_GPIO_PXICR_IRQ_CONFIG_MASK (0x00000001UL) +#define U300_GPIO_PXICR_IRQ_CONFIG_FALLING_EDGE (0x00000000UL) +#define U300_GPIO_PXICR_IRQ_CONFIG_RISING_EDGE (0x00000001UL) +/* Port X Pull-up Enable Register 32bit (R/W) */ +#define U300_335_PXPER (0x18) +/* This register layout is the same in both blocks */ +#define U300_GPIO_PXPER_ALL_PULL_UP_DISABLE_MASK (0x000000FFUL) +#define U300_GPIO_PXPER_PULL_UP_DISABLE (0x00000001UL) +/* Control Register 32bit (R/W) */ +#define U300_335_CR (0x54) +#define U300_335_CR_BLOCK_CLOCK_ENABLE (0x00000001UL) + +/* + * Register definitions for COH 901 571 / 3 variant + */ +#define U300_571_PORT_STRIDE (0x30) +/* + * Control Register 32bit (R/W) + * bit 15-9 (mask 0x0000FE00) contains the number of cores. 8*cores + * gives the number of GPIO pins. + * bit 8-2 (mask 0x000001FC) contains the core version ID. + */ +#define U300_571_CR (0x00) +#define U300_571_CR_SYNC_SEL_ENABLE (0x00000002UL) +#define U300_571_CR_BLOCK_CLKRQ_ENABLE (0x00000001UL) +/* + * These registers have the same layout and function as the corresponding + * COH 901 335 registers, just at different offset. + */ +#define U300_571_PXPDIR (0x04) +#define U300_571_PXPDOR (0x08) +#define U300_571_PXPCR (0x0C) +#define U300_571_PXPER (0x10) +#define U300_571_PXIEV (0x14) +#define U300_571_PXIEN (0x18) +#define U300_571_PXIFR (0x1C) +#define U300_571_PXICR (0x20) + +/* 8 bits per port, no version has more than 7 ports */ +#define U300_GPIO_PINS_PER_PORT 8 +#define U300_GPIO_MAX (U300_GPIO_PINS_PER_PORT * 7) + +struct u300_gpio { + struct gpio_chip chip; + struct list_head port_list; + struct clk *clk; + struct resource *memres; + void __iomem *base; + struct device *dev; + int irq_base; + int users; + u32 stride; + /* Register offsets */ + u32 pcr; + u32 dor; + u32 dir; + u32 per; + u32 icr; + u32 ien; + u32 iev; +}; + +struct u300_gpio_port { + struct list_head node; + struct u300_gpio *gpio; + char name[8]; + int irq; + int number; +}; + +/* + * Macro to expand to read a specific register found in the "gpio" + * struct. It requires the struct u300_gpio *gpio variable to exist in + * its context. It calculates the port offset from the given pin + * offset, muliplies by the port stride and adds the register offset + * so it provides a pointer to the desired register. + */ +#define U300_PIN_REG(pin, reg) \ + (gpio->base + (pin >> 3) * gpio->stride + gpio->reg) + +/* + * Provides a bitmask for a specific gpio pin inside an 8-bit GPIO + * register. + */ +#define U300_PIN_BIT(pin) \ + (1 << (pin & 0x07)) + +struct u300_gpio_confdata { + u16 bias_mode; + bool output; + int outval; +}; + +/* BS335 has seven ports of 8 bits each = GPIO pins 0..55 */ +#define BS335_GPIO_NUM_PORTS 7 +/* BS365 has five ports of 8 bits each = GPIO pins 0..39 */ +#define BS365_GPIO_NUM_PORTS 5 + +#define U300_FLOATING_INPUT { \ + .bias_mode = GPIO_CONFIG_BIAS_FLOAT, \ + .output = false, \ +} + +#define U300_PULL_UP_INPUT { \ + .bias_mode = GPIO_CONFIG_BIAS_PULL_UP, \ + .output = false, \ +} + +#define U300_OUTPUT_LOW { \ + .output = true, \ + .outval = 0, \ +} + +#define U300_OUTPUT_HIGH { \ + .output = true, \ + .outval = 1, \ +} + + +/* Initial configuration */ +static struct __initdata u300_gpio_confdata +bs335_gpio_config[BS335_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = { + /* Port 0, pins 0-7 */ + { + U300_FLOATING_INPUT, + U300_OUTPUT_HIGH, + U300_FLOATING_INPUT, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + }, + /* Port 1, pins 0-7 */ + { + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_PULL_UP_INPUT, + U300_FLOATING_INPUT, + U300_OUTPUT_HIGH, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + }, + /* Port 2, pins 0-7 */ + { + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_OUTPUT_LOW, + U300_PULL_UP_INPUT, + U300_OUTPUT_LOW, + U300_PULL_UP_INPUT, + }, + /* Port 3, pins 0-7 */ + { + U300_PULL_UP_INPUT, + U300_OUTPUT_LOW, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + }, + /* Port 4, pins 0-7 */ + { + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + }, + /* Port 5, pins 0-7 */ + { + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + }, + /* Port 6, pind 0-7 */ + { + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + } +}; + +static struct __initdata u300_gpio_confdata +bs365_gpio_config[BS365_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = { + /* Port 0, pins 0-7 */ + { + U300_FLOATING_INPUT, + U300_OUTPUT_LOW, + U300_FLOATING_INPUT, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_PULL_UP_INPUT, + U300_FLOATING_INPUT, + }, + /* Port 1, pins 0-7 */ + { + U300_OUTPUT_LOW, + U300_FLOATING_INPUT, + U300_OUTPUT_LOW, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_OUTPUT_HIGH, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + }, + /* Port 2, pins 0-7 */ + { + U300_FLOATING_INPUT, + U300_PULL_UP_INPUT, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + }, + /* Port 3, pins 0-7 */ + { + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + }, + /* Port 4, pins 0-7 */ + { + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + /* These 4 pins doesn't exist on DB3210 */ + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + } +}; + +/** + * to_u300_gpio() - get the pointer to u300_gpio + * @chip: the gpio chip member of the structure u300_gpio + */ +static inline struct u300_gpio *to_u300_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct u300_gpio, chip); +} + +static int u300_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct u300_gpio *gpio = to_u300_gpio(chip); + + return readl(U300_PIN_REG(offset, dir)) & U300_PIN_BIT(offset); +} + +static void u300_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct u300_gpio *gpio = to_u300_gpio(chip); + unsigned long flags; + u32 val; + + local_irq_save(flags); + + val = readl(U300_PIN_REG(offset, dor)); + if (value) + writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, dor)); + else + writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, dor)); + + local_irq_restore(flags); +} + +static int u300_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct u300_gpio *gpio = to_u300_gpio(chip); + unsigned long flags; + u32 val; + + local_irq_save(flags); + val = readl(U300_PIN_REG(offset, pcr)); + /* Mask out this pin, note 2 bits per setting */ + val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << ((offset & 0x07) << 1)); + writel(val, U300_PIN_REG(offset, pcr)); + local_irq_restore(flags); + return 0; +} + +static int u300_gpio_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct u300_gpio *gpio = to_u300_gpio(chip); + unsigned long flags; + u32 oldmode; + u32 val; + + local_irq_save(flags); + val = readl(U300_PIN_REG(offset, pcr)); + /* + * Drive mode must be set by the special mode set function, set + * push/pull mode by default if no mode has been selected. + */ + oldmode = val & (U300_GPIO_PXPCR_PIN_MODE_MASK << + ((offset & 0x07) << 1)); + /* mode = 0 means input, else some mode is already set */ + if (oldmode == 0) { + val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << + ((offset & 0x07) << 1)); + val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL + << ((offset & 0x07) << 1)); + writel(val, U300_PIN_REG(offset, pcr)); + } + u300_gpio_set(chip, offset, value); + local_irq_restore(flags); + return 0; +} + +static int u300_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct u300_gpio *gpio = to_u300_gpio(chip); + int retirq = gpio->irq_base + offset; + + dev_dbg(gpio->dev, "request IRQ for GPIO %d, return %d\n", offset, + retirq); + return retirq; +} + +static int u300_gpio_config(struct gpio_chip *chip, unsigned offset, + u16 param, unsigned long *data) +{ + struct u300_gpio *gpio = to_u300_gpio(chip); + unsigned long flags; + u32 val; + + local_irq_save(flags); + switch (param) { + case GPIO_CONFIG_BIAS_UNKNOWN: + case GPIO_CONFIG_BIAS_FLOAT: + val = readl(U300_PIN_REG(offset, per)); + writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, per)); + break; + case GPIO_CONFIG_BIAS_PULL_UP: + val = readl(U300_PIN_REG(offset, per)); + writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, per)); + break; + case GPIO_CONFIG_DRIVE_PUSH_PULL: + val = readl(U300_PIN_REG(offset, pcr)); + val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK + << ((offset & 0x07) << 1)); + val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL + << ((offset & 0x07) << 1)); + writel(val, U300_PIN_REG(offset, pcr)); + break; + case GPIO_CONFIG_DRIVE_OPEN_DRAIN: + val = readl(U300_PIN_REG(offset, pcr)); + val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK + << ((offset & 0x07) << 1)); + val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_DRAIN + << ((offset & 0x07) << 1)); + writel(val, U300_PIN_REG(offset, pcr)); + break; + case GPIO_CONFIG_DRIVE_OPEN_SOURCE: + val = readl(U300_PIN_REG(offset, pcr)); + val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK + << ((offset & 0x07) << 1)); + val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_SOURCE + << ((offset & 0x07) << 1)); + writel(val, U300_PIN_REG(offset, pcr)); + break; + default: + local_irq_restore(flags); + dev_err(gpio->dev, "illegal configuration requested\n"); + return -EINVAL; + } + local_irq_restore(flags); + return 0; +} + +static struct gpio_chip u300_gpio_chip = { + .label = "u300-gpio-chip", + .owner = THIS_MODULE, + .get = u300_gpio_get, + .set = u300_gpio_set, + .config = u300_gpio_config, + .direction_input = u300_gpio_direction_input, + .direction_output = u300_gpio_direction_output, + .to_irq = u300_gpio_to_irq, +}; + +static int u300_gpio_irq_type(struct irq_data *d, unsigned trigger) +{ + struct u300_gpio *gpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - gpio->irq_base; + u32 val; + + val = readl(U300_PIN_REG(offset, icr)); + if (trigger & IRQF_TRIGGER_RISING) + writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, icr)); + else + writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, icr)); + + return 0; +} + +static void u300_gpio_irq_enable(struct irq_data *d) +{ + struct u300_gpio *gpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - gpio->irq_base; + u32 val; + unsigned long flags; + + local_irq_save(flags); + val = readl(U300_PIN_REG(offset, ien)); + writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, ien)); + local_irq_restore(flags); +} + +static void u300_gpio_irq_disable(struct irq_data *d) +{ + struct u300_gpio *gpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - gpio->irq_base; + u32 val; + unsigned long flags; + + local_irq_save(flags); + val = readl(U300_PIN_REG(offset, ien)); + writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, ien)); + local_irq_restore(flags); +} + +static struct irq_chip u300_gpio_irqchip = { + .name = "u300-gpio-irqchip", + .irq_enable = u300_gpio_irq_enable, + .irq_disable = u300_gpio_irq_disable, + .irq_set_type = u300_gpio_irq_type, + +}; + +static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc) +{ + struct u300_gpio_port *port = irq_get_handler_data(irq); + struct u300_gpio *gpio = port->gpio; + int pinoffset = port->number << 3; /* get the right stride */ + unsigned long val; + + desc->irq_data.chip->irq_ack(&desc->irq_data); + /* Read event register */ + val = readl(U300_PIN_REG(pinoffset, iev)); + /* Mask relevant bits */ + val &= 0xFFU; /* 8 bits per port */ + /* ACK IRQ (clear event) */ + writel(val, U300_PIN_REG(pinoffset, iev)); + + /* Call IRQ handler */ + if (val != 0) { + int irqoffset; + + for_each_set_bit(irqoffset, &val, U300_GPIO_PINS_PER_PORT) { + int pin_irq = gpio->irq_base + (port->number << 3) + + irqoffset; + + dev_dbg(gpio->dev, "GPIO IRQ on pin %d\n", pin_irq); + generic_handle_irq(pin_irq); + } + } + desc->irq_data.chip->irq_unmask(&desc->irq_data); +} + +static void __init u300_gpio_init_pin(struct u300_gpio *gpio, + int offset, + struct u300_gpio_confdata *conf) +{ + /* Set mode: input or output */ + if (conf->output) { + u300_gpio_direction_output(&gpio->chip, offset, conf->outval); + + /* Deactivate bias mode for output */ + u300_gpio_config(&gpio->chip, offset, GPIO_CONFIG_BIAS_FLOAT, + NULL); + + /* Set drive mode for output */ + u300_gpio_config(&gpio->chip, offset, + GPIO_CONFIG_DRIVE_PUSH_PULL, NULL); + + dev_dbg(gpio->dev, "set up pin %d as output, value: %d\n", + offset, conf->outval); + } else { + u300_gpio_direction_input(&gpio->chip, offset); + + /* Always set output low on input pins */ + u300_gpio_set(&gpio->chip, offset, 0); + + /* Set bias mode for input */ + u300_gpio_config(&gpio->chip, offset, conf->bias_mode, NULL); + + dev_dbg(gpio->dev, "set up pin %d as input, bias: %d\n", + offset, conf->bias_mode); + } +} + +static void __init u300_gpio_init_coh901571(struct u300_gpio *gpio, + struct u300_gpio_platform *plat) +{ + int i, j; + + /* Write default config and values to all pins */ + for (i = 0; i < plat->ports; i++) { + for (j = 0; j < 8; j++) { + struct u300_gpio_confdata *conf; + int offset = (i*8) + j; + + if (plat->variant == U300_GPIO_COH901571_3_BS335) + conf = &bs335_gpio_config[i][j]; + else if (plat->variant == U300_GPIO_COH901571_3_BS365) + conf = &bs365_gpio_config[i][j]; + else + break; + + u300_gpio_init_pin(gpio, offset, conf); + } + } +} + +static inline void u300_gpio_free_ports(struct u300_gpio *gpio) +{ + struct u300_gpio_port *port; + struct list_head *p, *n; + + list_for_each_safe(p, n, &gpio->port_list) { + port = list_entry(p, struct u300_gpio_port, node); + list_del(&port->node); + free_irq(port->irq, port); + kfree(port); + } +} + +static int __init u300_gpio_probe(struct platform_device *pdev) +{ + struct u300_gpio_platform *plat = dev_get_platdata(&pdev->dev); + struct u300_gpio *gpio; + int err = 0; + int portno; + u32 val; + u32 ifr; + int i; + + gpio = kzalloc(sizeof(struct u300_gpio), GFP_KERNEL); + if (gpio == NULL) { + dev_err(&pdev->dev, "failed to allocate memory\n"); + return -ENOMEM; + } + + gpio->chip = u300_gpio_chip; + gpio->chip.ngpio = plat->ports * U300_GPIO_PINS_PER_PORT; + gpio->irq_base = plat->gpio_irq_base; + gpio->chip.dev = &pdev->dev; + gpio->chip.base = plat->gpio_base; + gpio->dev = &pdev->dev; + + /* Get GPIO clock */ + gpio->clk = clk_get(gpio->dev, NULL); + if (IS_ERR(gpio->clk)) { + err = PTR_ERR(gpio->clk); + dev_err(gpio->dev, "could not get GPIO clock\n"); + goto err_no_clk; + } + err = clk_enable(gpio->clk); + if (err) { + dev_err(gpio->dev, "could not enable GPIO clock\n"); + goto err_no_clk_enable; + } + + gpio->memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!gpio->memres) { + dev_err(gpio->dev, "could not get GPIO memory resource\n"); + err = -ENODEV; + goto err_no_resource; + } + + if (request_mem_region(gpio->memres->start, + gpio->memres->end - gpio->memres->start, + "GPIO Controller") + == NULL) { + dev_err(gpio->dev, "could not reserve GPIO memory region\n"); + err = -ENODEV; + goto err_no_ioregion; + } + + gpio->base = ioremap(gpio->memres->start, resource_size(gpio->memres)); + if (!gpio->base) { + err = -ENOMEM; + goto err_no_ioremap; + } + + if (plat->variant == U300_GPIO_COH901335) { + dev_info(gpio->dev, + "initializing GPIO Controller COH 901 335\n"); + gpio->stride = U300_335_PORT_STRIDE; + gpio->pcr = U300_335_PXPCR; + gpio->dor = U300_335_PXPDOR; + gpio->dir = U300_335_PXPDIR; + gpio->per = U300_335_PXPER; + gpio->icr = U300_335_PXICR; + gpio->ien = U300_335_PXIEN; + gpio->iev = U300_335_PXIEV; + ifr = U300_335_PXIFR; + + /* Turn on the GPIO block */ + writel(U300_335_CR_BLOCK_CLOCK_ENABLE, + gpio->base + U300_335_CR); + } else if (plat->variant == U300_GPIO_COH901571_3_BS335 || + plat->variant == U300_GPIO_COH901571_3_BS365) { + dev_info(gpio->dev, + "initializing GPIO Controller COH 901 571/3\n"); + gpio->stride = U300_571_PORT_STRIDE; + gpio->pcr = U300_571_PXPCR; + gpio->dor = U300_571_PXPDOR; + gpio->dir = U300_571_PXPDIR; + gpio->per = U300_571_PXPER; + gpio->icr = U300_571_PXICR; + gpio->ien = U300_571_PXIEN; + gpio->iev = U300_571_PXIEV; + ifr = U300_571_PXIFR; + + val = readl(gpio->base + U300_571_CR); + dev_info(gpio->dev, "COH901571/3 block version: %d, " \ + "number of cores: %d\n", + ((val & 0x0000FE00) >> 9), + ((val & 0x000001FC) >> 2)); + writel(U300_571_CR_BLOCK_CLKRQ_ENABLE, + gpio->base + U300_571_CR); + u300_gpio_init_coh901571(gpio, plat); + } else { + dev_err(gpio->dev, "unknown block variant\n"); + err = -ENODEV; + goto err_unknown_variant; + } + + /* Add each port with its IRQ separately */ + INIT_LIST_HEAD(&gpio->port_list); + for (portno = 0 ; portno < plat->ports; portno++) { + struct u300_gpio_port *port = + kmalloc(sizeof(struct u300_gpio_port), GFP_KERNEL); + + if (!port) { + dev_err(gpio->dev, "out of memory\n"); + err = -ENOMEM; + goto err_no_port; + } + + snprintf(port->name, 8, "gpio%d", portno); + port->number = portno; + port->gpio = gpio; + + port->irq = platform_get_irq_byname(pdev, + port->name); + + dev_dbg(gpio->dev, "register IRQ %d for %s\n", port->irq, + port->name); + + irq_set_chained_handler(port->irq, u300_gpio_irq_handler); + irq_set_handler_data(port->irq, port); + + /* Then for each GPIO pin set the unique IRQ handler */ + for (i = 0; i < U300_GPIO_PINS_PER_PORT; i++) { + int irqno = gpio->irq_base + (portno << 3) + i; + + dev_dbg(gpio->dev, "handler for IRQ %d on %s\n", + irqno, port->name); + irq_set_chip_and_handler(irqno, &u300_gpio_irqchip, + handle_simple_irq); + set_irq_flags(irqno, IRQF_VALID); + irq_set_chip_data(irqno, gpio); + } + + /* Turns off irq force (test register) for this port */ + writel(0x0, gpio->base + portno * gpio->stride + ifr); + + list_add_tail(&port->node, &gpio->port_list); + } + + err = gpiochip_add(&gpio->chip); + if (err) { + dev_err(gpio->dev, "unable to add gpiochip: %d\n", err); + goto err_no_chip; + } + + platform_set_drvdata(pdev, gpio); + + return 0; + +err_no_chip: +err_no_port: + u300_gpio_free_ports(gpio); +err_unknown_variant: + iounmap(gpio->base); +err_no_ioremap: + release_mem_region(gpio->memres->start, + gpio->memres->end - gpio->memres->start); +err_no_ioregion: +err_no_resource: + clk_disable(gpio->clk); +err_no_clk_enable: + clk_put(gpio->clk); +err_no_clk: + kfree(gpio); + dev_info(&pdev->dev, "module ERROR:%d\n", err); + return err; +} + +static int __exit u300_gpio_remove(struct platform_device *pdev) +{ + struct u300_gpio_platform *plat = dev_get_platdata(&pdev->dev); + struct u300_gpio *gpio = platform_get_drvdata(pdev); + int err; + + /* Turn off the GPIO block */ + if (plat->variant == U300_GPIO_COH901335) + writel(0x00000000U, gpio->base + U300_335_CR); + if (plat->variant == U300_GPIO_COH901571_3_BS335 || + plat->variant == U300_GPIO_COH901571_3_BS365) + writel(0x00000000U, gpio->base + U300_571_CR); + + err = gpiochip_remove(&gpio->chip); + if (err < 0) { + dev_err(gpio->dev, "unable to remove gpiochip: %d\n", err); + return err; + } + u300_gpio_free_ports(gpio); + iounmap(gpio->base); + release_mem_region(gpio->memres->start, + gpio->memres->end - gpio->memres->start); + clk_disable(gpio->clk); + clk_put(gpio->clk); + platform_set_drvdata(pdev, NULL); + kfree(gpio); + return 0; +} + +static struct platform_driver u300_gpio_driver = { + .driver = { + .name = "u300-gpio", + }, + .remove = __exit_p(u300_gpio_remove), +}; + + +static int __init u300_gpio_init(void) +{ + return platform_driver_probe(&u300_gpio_driver, u300_gpio_probe); +} + +static void __exit u300_gpio_exit(void) +{ + platform_driver_unregister(&u300_gpio_driver); +} + +arch_initcall(u300_gpio_init); +module_exit(u300_gpio_exit); + +MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>"); +MODULE_DESCRIPTION("ST-Ericsson AB COH 901 335/COH 901 571/3 GPIO driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/gpio/u300.h b/include/linux/gpio/u300.h new file mode 100644 index 0000000..38cd064 --- /dev/null +++ b/include/linux/gpio/u300.h @@ -0,0 +1,32 @@ +/* + * U300 GPIO platform data header + * Copyright (C) 2011 ST-Ericsson SA + * Written on behalf of Linaro for ST-Ericsson + * + * Author: Linus Walleij <linus.walleij@linaro.org> + * + * License terms: GNU General Public License (GPL) version 2 + */ + +/** + * enum u300_gpio_variant - the type of U300 GPIO employed + */ +enum u300_gpio_variant { + U300_GPIO_COH901335, + U300_GPIO_COH901571_3_BS335, + U300_GPIO_COH901571_3_BS365, +}; + +/** + * struct u300_gpio_platform - U300 GPIO platform data + * @variant: IP block variant + * @ports: number of GPIO block ports + * @gpio_base: first GPIO number for this block (use a free range) + * @gpio_irq_base: first GPIO IRQ number for this block (use a free range) + */ +struct u300_gpio_platform { + enum u300_gpio_variant variant; + u8 ports; + int gpio_base; + int gpio_irq_base; +}; -- 1.7.3.2 ^ permalink raw reply related [flat|nested] 57+ messages in thread
* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-04-27 13:13 ` Linus Walleij 0 siblings, 0 replies; 57+ messages in thread From: Linus Walleij @ 2011-04-27 13:13 UTC (permalink / raw) To: linux-arm-kernel From: Linus Walleij <linus.walleij@linaro.org> This rewrites the U300 GPIO driver using gpiolib and the irq_chip abstractions, makes it runtime-configured rather than compile-time, and moves it to the drivers/gpio subsystem where it belongs, depopulating the ARM tree of one more driver. Cc: Jonas Aaberg <jonas.aberg@stericsson.com> Acked-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> --- arch/arm/Kconfig | 2 +- arch/arm/mach-u300/Kconfig | 1 + arch/arm/mach-u300/Makefile | 6 +- arch/arm/mach-u300/core.c | 31 ++- arch/arm/mach-u300/gpio.c | 700 -------------------------- arch/arm/mach-u300/include/mach/gpio.h | 163 +------ arch/arm/mach-u300/include/mach/irqs.h | 25 +- drivers/gpio/Kconfig | 9 + drivers/gpio/Makefile | 1 + drivers/gpio/u300-gpio.c | 836 ++++++++++++++++++++++++++++++++ include/linux/gpio/u300.h | 32 ++ 11 files changed, 932 insertions(+), 874 deletions(-) delete mode 100644 arch/arm/mach-u300/gpio.c create mode 100644 drivers/gpio/u300-gpio.c create mode 100644 include/linux/gpio/u300.h diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 377a7a5..5fb980d 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -820,7 +820,7 @@ config ARCH_U300 select ARM_VIC select GENERIC_CLOCKEVENTS select CLKDEV_LOOKUP - select GENERIC_GPIO + select ARCH_REQUIRE_GPIOLIB help Support for ST-Ericsson U300 series mobile platforms. diff --git a/arch/arm/mach-u300/Kconfig b/arch/arm/mach-u300/Kconfig index 32a7b0f..7b5c229 100644 --- a/arch/arm/mach-u300/Kconfig +++ b/arch/arm/mach-u300/Kconfig @@ -6,6 +6,7 @@ comment "ST-Ericsson Mobile Platform Products" config MACH_U300 bool "U300" + select GPIO_U300 comment "ST-Ericsson U300/U330/U335/U365 Feature Selections" diff --git a/arch/arm/mach-u300/Makefile b/arch/arm/mach-u300/Makefile index fab46fe..73da230 100644 --- a/arch/arm/mach-u300/Makefile +++ b/arch/arm/mach-u300/Makefile @@ -2,11 +2,7 @@ # Makefile for the linux kernel, U300 machine. # -obj-y := core.o clock.o timer.o gpio.o padmux.o -obj-m := -obj-n := -obj- := - +obj-y := core.o clock.o timer.o padmux.o obj-$(CONFIG_ARCH_U300) += u300.o obj-$(CONFIG_MMC) += mmc.o obj-$(CONFIG_SPI_PL022) += spi.o diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c index 513d6ab..ddb604c 100644 --- a/arch/arm/mach-u300/core.c +++ b/arch/arm/mach-u300/core.c @@ -25,6 +25,7 @@ #include <linux/err.h> #include <linux/mtd/nand.h> #include <linux/mtd/fsmc.h> +#include <linux/gpio/u300.h> #include <asm/types.h> #include <asm/setup.h> @@ -239,7 +240,7 @@ static struct resource gpio_resources[] = { .end = IRQ_U300_GPIO_PORT2, .flags = IORESOURCE_IRQ, }, -#ifdef U300_COH901571_3 +#if defined(CONFIG_MACH_U300_BS365) || defined(CONFIG_MACH_U300_BS335) { .name = "gpio3", .start = IRQ_U300_GPIO_PORT3, @@ -252,6 +253,7 @@ static struct resource gpio_resources[] = { .end = IRQ_U300_GPIO_PORT4, .flags = IORESOURCE_IRQ, }, +#endif #ifdef CONFIG_MACH_U300_BS335 { .name = "gpio5", @@ -266,7 +268,6 @@ static struct resource gpio_resources[] = { .flags = IORESOURCE_IRQ, }, #endif /* CONFIG_MACH_U300_BS335 */ -#endif /* U300_COH901571_3 */ }; static struct resource keypad_resources[] = { @@ -1556,11 +1557,35 @@ static struct platform_device i2c1_device = { .resource = i2c1_resources, }; +/* + * The different variants have a few different versions of the + * GPIO block, with different number of ports. + */ +static struct u300_gpio_platform u300_gpio_plat = { +#if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330) + .variant = U300_GPIO_COH901335, + .ports = 3, +#endif +#ifdef CONFIG_MACH_U300_BS335 + .variant = U300_GPIO_COH901571_3_BS335, + .ports = 7, +#endif +#ifdef CONFIG_MACH_U300_BS365 + .variant = U300_GPIO_COH901571_3_BS365, + .ports = 5, +#endif + .gpio_base = 0, + .gpio_irq_base = IRQ_U300_GPIO_BASE, +}; + static struct platform_device gpio_device = { .name = "u300-gpio", .id = -1, .num_resources = ARRAY_SIZE(gpio_resources), .resource = gpio_resources, + .dev = { + .platform_data = &u300_gpio_plat, + }, }; static struct platform_device keypad_device = { @@ -1666,7 +1691,7 @@ void __init u300_init_irq(void) BUG_ON(IS_ERR(clk)); clk_enable(clk); - for (i = 0; i < NR_IRQS; i++) + for (i = 0; i < U300_VIC_IRQS_END; i++) set_bit(i, (unsigned long *) &mask[0]); vic_init((void __iomem *) U300_INTCON0_VBASE, 0, mask[0], mask[0]); vic_init((void __iomem *) U300_INTCON1_VBASE, 32, mask[1], mask[1]); diff --git a/arch/arm/mach-u300/gpio.c b/arch/arm/mach-u300/gpio.c deleted file mode 100644 index d927901..0000000 --- a/arch/arm/mach-u300/gpio.c +++ /dev/null @@ -1,700 +0,0 @@ -/* - * - * arch/arm/mach-u300/gpio.c - * - * - * Copyright (C) 2007-2009 ST-Ericsson AB - * License terms: GNU General Public License (GPL) version 2 - * U300 GPIO module. - * This can driver either of the two basic GPIO cores - * available in the U300 platforms: - * COH 901 335 - Used in DB3150 (U300 1.0) and DB3200 (U330 1.0) - * COH 901 571/3 - Used in DB3210 (U365 2.0) and DB3350 (U335 1.0) - * Notice that you also have inline macros in <asm-arch/gpio.h> - * Author: Linus Walleij <linus.walleij@stericsson.com> - * Author: Jonas Aaberg <jonas.aberg@stericsson.com> - * - */ -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/errno.h> -#include <linux/io.h> -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/platform_device.h> -#include <linux/gpio.h> - -/* Reference to GPIO block clock */ -static struct clk *clk; - -/* Memory resource */ -static struct resource *memres; -static void __iomem *virtbase; -static struct device *gpiodev; - -struct u300_gpio_port { - const char *name; - int irq; - int number; -}; - - -static struct u300_gpio_port gpio_ports[] = { - { - .name = "gpio0", - .number = 0, - }, - { - .name = "gpio1", - .number = 1, - }, - { - .name = "gpio2", - .number = 2, - }, -#ifdef U300_COH901571_3 - { - .name = "gpio3", - .number = 3, - }, - { - .name = "gpio4", - .number = 4, - }, -#ifdef CONFIG_MACH_U300_BS335 - { - .name = "gpio5", - .number = 5, - }, - { - .name = "gpio6", - .number = 6, - }, -#endif -#endif - -}; - - -#ifdef U300_COH901571_3 - -/* Default input value */ -#define DEFAULT_OUTPUT_LOW 0 -#define DEFAULT_OUTPUT_HIGH 1 - -/* GPIO Pull-Up status */ -#define DISABLE_PULL_UP 0 -#define ENABLE_PULL_UP 1 - -#define GPIO_NOT_USED 0 -#define GPIO_IN 1 -#define GPIO_OUT 2 - -struct u300_gpio_configuration_data { - unsigned char pin_usage; - unsigned char default_output_value; - unsigned char pull_up; -}; - -/* Initial configuration */ -const struct u300_gpio_configuration_data -u300_gpio_config[U300_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = { -#ifdef CONFIG_MACH_U300_BS335 - /* Port 0, pins 0-7 */ - { - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_HIGH, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} - }, - /* Port 1, pins 0-7 */ - { - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_HIGH, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} - }, - /* Port 2, pins 0-7 */ - { - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP} - }, - /* Port 3, pins 0-7 */ - { - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} - }, - /* Port 4, pins 0-7 */ - { - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} - }, - /* Port 5, pins 0-7 */ - { - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} - }, - /* Port 6, pind 0-7 */ - { - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} - } -#endif - -#ifdef CONFIG_MACH_U300_BS365 - /* Port 0, pins 0-7 */ - { - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} - }, - /* Port 1, pins 0-7 */ - { - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_HIGH, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} - }, - /* Port 2, pins 0-7 */ - { - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP} - }, - /* Port 3, pins 0-7 */ - { - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP} - }, - /* Port 4, pins 0-7 */ - { - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - /* These 4 pins doesn't exist on DB3210 */ - {GPIO_OUT, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP} - } -#endif -}; -#endif - - -/* No users == we can power down GPIO */ -static int gpio_users; - -struct gpio_struct { - int (*callback)(void *); - void *data; - int users; -}; - -static struct gpio_struct gpio_pin[U300_GPIO_MAX]; - -/* - * Let drivers register callback in order to get notified when there is - * an interrupt on the gpio pin - */ -int gpio_register_callback(unsigned gpio, int (*func)(void *arg), void *data) -{ - if (gpio_pin[gpio].callback) - dev_warn(gpiodev, "%s: WARNING: callback already " - "registered for gpio pin#%d\n", __func__, gpio); - gpio_pin[gpio].callback = func; - gpio_pin[gpio].data = data; - - return 0; -} -EXPORT_SYMBOL(gpio_register_callback); - -int gpio_unregister_callback(unsigned gpio) -{ - if (!gpio_pin[gpio].callback) - dev_warn(gpiodev, "%s: WARNING: callback already " - "unregistered for gpio pin#%d\n", __func__, gpio); - gpio_pin[gpio].callback = NULL; - gpio_pin[gpio].data = NULL; - - return 0; -} -EXPORT_SYMBOL(gpio_unregister_callback); - -/* Non-zero means valid */ -int gpio_is_valid(int number) -{ - if (number >= 0 && - number < (U300_GPIO_NUM_PORTS * U300_GPIO_PINS_PER_PORT)) - return 1; - return 0; -} -EXPORT_SYMBOL(gpio_is_valid); - -int gpio_request(unsigned gpio, const char *label) -{ - if (gpio_pin[gpio].users) - return -EINVAL; - else - gpio_pin[gpio].users++; - - gpio_users++; - - return 0; -} -EXPORT_SYMBOL(gpio_request); - -void gpio_free(unsigned gpio) -{ - gpio_users--; - gpio_pin[gpio].users--; - if (unlikely(gpio_pin[gpio].users < 0)) { - dev_warn(gpiodev, "warning: gpio#%d release mismatch\n", - gpio); - gpio_pin[gpio].users = 0; - } - - return; -} -EXPORT_SYMBOL(gpio_free); - -/* This returns zero or nonzero */ -int gpio_get_value(unsigned gpio) -{ - return readl(virtbase + U300_GPIO_PXPDIR + - PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING) & (1 << (gpio & 0x07)); -} -EXPORT_SYMBOL(gpio_get_value); - -/* - * We hope that the compiler will optimize away the unused branch - * in case "value" is a constant - */ -void gpio_set_value(unsigned gpio, int value) -{ - u32 val; - unsigned long flags; - - local_irq_save(flags); - if (value) { - /* set */ - val = readl(virtbase + U300_GPIO_PXPDOR + - PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING) - & (1 << (gpio & 0x07)); - writel(val | (1 << (gpio & 0x07)), virtbase + - U300_GPIO_PXPDOR + - PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING); - } else { - /* clear */ - val = readl(virtbase + U300_GPIO_PXPDOR + - PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING) - & (1 << (gpio & 0x07)); - writel(val & ~(1 << (gpio & 0x07)), virtbase + - U300_GPIO_PXPDOR + - PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING); - } - local_irq_restore(flags); -} -EXPORT_SYMBOL(gpio_set_value); - -int gpio_direction_input(unsigned gpio) -{ - unsigned long flags; - u32 val; - - if (gpio > U300_GPIO_MAX) - return -EINVAL; - - local_irq_save(flags); - val = readl(virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - /* Mask out this pin*/ - val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << ((gpio & 0x07) << 1)); - /* This is not needed since it sets the bits to zero.*/ - /* val |= (U300_GPIO_PXPCR_PIN_MODE_INPUT << (gpio*2)); */ - writel(val, virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - local_irq_restore(flags); - return 0; -} -EXPORT_SYMBOL(gpio_direction_input); - -int gpio_direction_output(unsigned gpio, int value) -{ - unsigned long flags; - u32 val; - - if (gpio > U300_GPIO_MAX) - return -EINVAL; - - local_irq_save(flags); - val = readl(virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - /* Mask out this pin */ - val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << ((gpio & 0x07) << 1)); - /* - * FIXME: configure for push/pull, open drain or open source per pin - * in setup. The current driver will only support push/pull. - */ - val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL - << ((gpio & 0x07) << 1)); - writel(val, virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - gpio_set_value(gpio, value); - local_irq_restore(flags); - return 0; -} -EXPORT_SYMBOL(gpio_direction_output); - -/* - * Enable an IRQ, edge is rising edge (!= 0) or falling edge (==0). - */ -void enable_irq_on_gpio_pin(unsigned gpio, int edge) -{ - u32 val; - unsigned long flags; - local_irq_save(flags); - - val = readl(virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - val |= (1 << (gpio & 0x07)); - writel(val, virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - val = readl(virtbase + U300_GPIO_PXICR + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - if (edge) - val |= (1 << (gpio & 0x07)); - else - val &= ~(1 << (gpio & 0x07)); - writel(val, virtbase + U300_GPIO_PXICR + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - local_irq_restore(flags); -} -EXPORT_SYMBOL(enable_irq_on_gpio_pin); - -void disable_irq_on_gpio_pin(unsigned gpio) -{ - u32 val; - unsigned long flags; - - local_irq_save(flags); - val = readl(virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - val &= ~(1 << (gpio & 0x07)); - writel(val, virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - local_irq_restore(flags); -} -EXPORT_SYMBOL(disable_irq_on_gpio_pin); - -/* Enable (value == 0) or disable (value == 1) internal pullup */ -void gpio_pullup(unsigned gpio, int value) -{ - u32 val; - unsigned long flags; - - local_irq_save(flags); - if (value) { - val = readl(virtbase + U300_GPIO_PXPER + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - writel(val | (1 << (gpio & 0x07)), virtbase + U300_GPIO_PXPER + - PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING); - } else { - val = readl(virtbase + U300_GPIO_PXPER + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - writel(val & ~(1 << (gpio & 0x07)), virtbase + U300_GPIO_PXPER + - PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING); - } - local_irq_restore(flags); -} -EXPORT_SYMBOL(gpio_pullup); - -static irqreturn_t gpio_irq_handler(int irq, void *dev_id) -{ - struct u300_gpio_port *port = dev_id; - u32 val; - int pin; - - /* Read event register */ - val = readl(virtbase + U300_GPIO_PXIEV + port->number * - U300_GPIO_PORTX_SPACING); - /* Mask with enable register */ - val &= readl(virtbase + U300_GPIO_PXIEV + port->number * - U300_GPIO_PORTX_SPACING); - /* Mask relevant bits */ - val &= U300_GPIO_PXIEV_ALL_IRQ_EVENT_MASK; - /* ACK IRQ (clear event) */ - writel(val, virtbase + U300_GPIO_PXIEV + port->number * - U300_GPIO_PORTX_SPACING); - /* Print message */ - while (val != 0) { - unsigned gpio; - - pin = __ffs(val); - /* mask off this pin */ - val &= ~(1 << pin); - gpio = (port->number << 3) + pin; - - if (gpio_pin[gpio].callback) - (void)gpio_pin[gpio].callback(gpio_pin[gpio].data); - else - dev_dbg(gpiodev, "stray GPIO IRQ on line %d\n", - gpio); - } - return IRQ_HANDLED; -} - -static void gpio_set_initial_values(void) -{ -#ifdef U300_COH901571_3 - int i, j; - unsigned long flags; - u32 val; - - /* Write default values to all pins */ - for (i = 0; i < U300_GPIO_NUM_PORTS; i++) { - val = 0; - for (j = 0; j < 8; j++) - val |= (u32) (u300_gpio_config[i][j].default_output_value != DEFAULT_OUTPUT_LOW) << j; - local_irq_save(flags); - writel(val, virtbase + U300_GPIO_PXPDOR + i * U300_GPIO_PORTX_SPACING); - local_irq_restore(flags); - } - - /* - * Put all pins that are set to either 'GPIO_OUT' or 'GPIO_NOT_USED' - * to output and 'GPIO_IN' to input for each port. And initialize - * default value on outputs. - */ - for (i = 0; i < U300_GPIO_NUM_PORTS; i++) { - for (j = 0; j < U300_GPIO_PINS_PER_PORT; j++) { - local_irq_save(flags); - val = readl(virtbase + U300_GPIO_PXPCR + - i * U300_GPIO_PORTX_SPACING); - /* Mask out this pin */ - val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << (j << 1)); - - if (u300_gpio_config[i][j].pin_usage != GPIO_IN) - val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL << (j << 1)); - writel(val, virtbase + U300_GPIO_PXPCR + - i * U300_GPIO_PORTX_SPACING); - local_irq_restore(flags); - } - } - - /* Enable or disable the internal pull-ups in the GPIO ASIC block */ - for (i = 0; i < U300_GPIO_MAX; i++) { - val = 0; - for (j = 0; j < 8; j++) - val |= (u32)((u300_gpio_config[i][j].pull_up == DISABLE_PULL_UP) << j); - local_irq_save(flags); - writel(val, virtbase + U300_GPIO_PXPER + i * U300_GPIO_PORTX_SPACING); - local_irq_restore(flags); - } -#endif -} - -static int __init gpio_probe(struct platform_device *pdev) -{ - u32 val; - int err = 0; - int i; - int num_irqs; - - gpiodev = &pdev->dev; - memset(gpio_pin, 0, sizeof(gpio_pin)); - - /* Get GPIO clock */ - clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(clk)) { - err = PTR_ERR(clk); - dev_err(gpiodev, "could not get GPIO clock\n"); - goto err_no_clk; - } - err = clk_enable(clk); - if (err) { - dev_err(gpiodev, "could not enable GPIO clock\n"); - goto err_no_clk_enable; - } - - memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!memres) - goto err_no_resource; - - if (request_mem_region(memres->start, memres->end - memres->start, "GPIO Controller") - == NULL) { - err = -ENODEV; - goto err_no_ioregion; - } - - virtbase = ioremap(memres->start, resource_size(memres)); - if (!virtbase) { - err = -ENOMEM; - goto err_no_ioremap; - } - dev_info(gpiodev, "remapped 0x%08x to %p\n", - memres->start, virtbase); - -#ifdef U300_COH901335 - dev_info(gpiodev, "initializing GPIO Controller COH 901 335\n"); - /* Turn on the GPIO block */ - writel(U300_GPIO_CR_BLOCK_CLOCK_ENABLE, virtbase + U300_GPIO_CR); -#endif - -#ifdef U300_COH901571_3 - dev_info(gpiodev, "initializing GPIO Controller COH 901 571/3\n"); - val = readl(virtbase + U300_GPIO_CR); - dev_info(gpiodev, "COH901571/3 block version: %d, " \ - "number of cores: %d\n", - ((val & 0x0000FE00) >> 9), - ((val & 0x000001FC) >> 2)); - writel(U300_GPIO_CR_BLOCK_CLKRQ_ENABLE, virtbase + U300_GPIO_CR); -#endif - - gpio_set_initial_values(); - - for (num_irqs = 0 ; num_irqs < U300_GPIO_NUM_PORTS; num_irqs++) { - - gpio_ports[num_irqs].irq = - platform_get_irq_byname(pdev, - gpio_ports[num_irqs].name); - - err = request_irq(gpio_ports[num_irqs].irq, - gpio_irq_handler, IRQF_DISABLED, - gpio_ports[num_irqs].name, - &gpio_ports[num_irqs]); - if (err) { - dev_err(gpiodev, "cannot allocate IRQ for %s!\n", - gpio_ports[num_irqs].name); - goto err_no_irq; - } - /* Turns off PortX_irq_force */ - writel(0x0, virtbase + U300_GPIO_PXIFR + - num_irqs * U300_GPIO_PORTX_SPACING); - } - - return 0; - - err_no_irq: - for (i = 0; i < num_irqs; i++) - free_irq(gpio_ports[i].irq, &gpio_ports[i]); - iounmap(virtbase); - err_no_ioremap: - release_mem_region(memres->start, memres->end - memres->start); - err_no_ioregion: - err_no_resource: - clk_disable(clk); - err_no_clk_enable: - clk_put(clk); - err_no_clk: - dev_info(gpiodev, "module ERROR:%d\n", err); - return err; -} - -static int __exit gpio_remove(struct platform_device *pdev) -{ - int i; - - /* Turn off the GPIO block */ - writel(0x00000000U, virtbase + U300_GPIO_CR); - for (i = 0 ; i < U300_GPIO_NUM_PORTS; i++) - free_irq(gpio_ports[i].irq, &gpio_ports[i]); - iounmap(virtbase); - release_mem_region(memres->start, memres->end - memres->start); - clk_disable(clk); - clk_put(clk); - return 0; -} - -static struct platform_driver gpio_driver = { - .driver = { - .name = "u300-gpio", - }, - .remove = __exit_p(gpio_remove), -}; - - -static int __init u300_gpio_init(void) -{ - return platform_driver_probe(&gpio_driver, gpio_probe); -} - -static void __exit u300_gpio_exit(void) -{ - platform_driver_unregister(&gpio_driver); -} - -arch_initcall(u300_gpio_init); -module_exit(u300_gpio_exit); - -MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>"); - -#ifdef U300_COH901571_3 -MODULE_DESCRIPTION("ST-Ericsson AB COH 901 571/3 GPIO driver"); -#endif - -#ifdef U300_COH901335 -MODULE_DESCRIPTION("ST-Ericsson AB COH 901 335 GPIO driver"); -#endif - -MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-u300/include/mach/gpio.h b/arch/arm/mach-u300/include/mach/gpio.h index d5a71ab..6fc3205 100644 --- a/arch/arm/mach-u300/include/mach/gpio.h +++ b/arch/arm/mach-u300/include/mach/gpio.h @@ -17,127 +17,13 @@ #include <linux/io.h> #include <mach/hardware.h> #include <asm/irq.h> +#include <asm-generic/gpio.h> -/* Switch type depending on platform/chip variant */ -#if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330) -#define U300_COH901335 -#endif -#if defined(CONFIG_MACH_U300_BS365) || defined(CONFIG_MACH_U300_BS335) -#define U300_COH901571_3 -#endif - -/* Get base address for regs here */ -#include "u300-regs.h" -/* IRQ numbers */ -#include "irqs.h" - -/* - * This is the GPIO block definitions. GPIO (General Purpose I/O) can be - * used for anything, and often is. The event/enable etc figures are for - * the lowermost pin (pin 0 on each port), shift this left to match your - * pin if you're gonna use these values. - */ -#ifdef U300_COH901335 -#define U300_GPIO_PORTX_SPACING (0x1C) -/* Port X Pin Data Register 32bit, this is both input and output (R/W) */ -#define U300_GPIO_PXPDIR (0x00) -#define U300_GPIO_PXPDOR (0x00) -/* Port X Pin Config Register 32bit (R/W) */ -#define U300_GPIO_PXPCR (0x04) -#define U300_GPIO_PXPCR_ALL_PINS_MODE_MASK (0x0000FFFFUL) -#define U300_GPIO_PXPCR_PIN_MODE_MASK (0x00000003UL) -#define U300_GPIO_PXPCR_PIN_MODE_SHIFT (0x00000002UL) -#define U300_GPIO_PXPCR_PIN_MODE_INPUT (0x00000000UL) -#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL (0x00000001UL) -#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_DRAIN (0x00000002UL) -#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_SOURCE (0x00000003UL) -/* Port X Interrupt Event Register 32bit (R/W) */ -#define U300_GPIO_PXIEV (0x08) -#define U300_GPIO_PXIEV_ALL_IRQ_EVENT_MASK (0x000000FFUL) -#define U300_GPIO_PXIEV_IRQ_EVENT (0x00000001UL) -/* Port X Interrupt Enable Register 32bit (R/W) */ -#define U300_GPIO_PXIEN (0x0C) -#define U300_GPIO_PXIEN_ALL_IRQ_ENABLE_MASK (0x000000FFUL) -#define U300_GPIO_PXIEN_IRQ_ENABLE (0x00000001UL) -/* Port X Interrupt Force Register 32bit (R/W) */ -#define U300_GPIO_PXIFR (0x10) -#define U300_GPIO_PXIFR_ALL_IRQ_FORCE_MASK (0x000000FFUL) -#define U300_GPIO_PXIFR_IRQ_FORCE (0x00000001UL) -/* Port X Interrupt Config Register 32bit (R/W) */ -#define U300_GPIO_PXICR (0x14) -#define U300_GPIO_PXICR_ALL_IRQ_CONFIG_MASK (0x000000FFUL) -#define U300_GPIO_PXICR_IRQ_CONFIG_MASK (0x00000001UL) -#define U300_GPIO_PXICR_IRQ_CONFIG_FALLING_EDGE (0x00000000UL) -#define U300_GPIO_PXICR_IRQ_CONFIG_RISING_EDGE (0x00000001UL) -/* Port X Pull-up Enable Register 32bit (R/W) */ -#define U300_GPIO_PXPER (0x18) -#define U300_GPIO_PXPER_ALL_PULL_UP_DISABLE_MASK (0x000000FFUL) -#define U300_GPIO_PXPER_PULL_UP_DISABLE (0x00000001UL) -/* Control Register 32bit (R/W) */ -#define U300_GPIO_CR (0x54) -#define U300_GPIO_CR_BLOCK_CLOCK_ENABLE (0x00000001UL) -/* three ports of 8 bits each = GPIO pins 0..23 */ -#define U300_GPIO_NUM_PORTS 3 -#define U300_GPIO_PINS_PER_PORT 8 -#define U300_GPIO_MAX (U300_GPIO_PINS_PER_PORT * U300_GPIO_NUM_PORTS - 1) -#endif - -#ifdef U300_COH901571_3 -/* - * Control Register 32bit (R/W) - * bit 15-9 (mask 0x0000FE00) contains the number of cores. 8*cores - * gives the number of GPIO pins. - * bit 8-2 (mask 0x000001FC) contains the core version ID. - */ -#define U300_GPIO_CR (0x00) -#define U300_GPIO_CR_SYNC_SEL_ENABLE (0x00000002UL) -#define U300_GPIO_CR_BLOCK_CLKRQ_ENABLE (0x00000001UL) -#define U300_GPIO_PORTX_SPACING (0x30) -/* Port X Pin Data INPUT Register 32bit (R/W) */ -#define U300_GPIO_PXPDIR (0x04) -/* Port X Pin Data OUTPUT Register 32bit (R/W) */ -#define U300_GPIO_PXPDOR (0x08) -/* Port X Pin Config Register 32bit (R/W) */ -#define U300_GPIO_PXPCR (0x0C) -#define U300_GPIO_PXPCR_ALL_PINS_MODE_MASK (0x0000FFFFUL) -#define U300_GPIO_PXPCR_PIN_MODE_MASK (0x00000003UL) -#define U300_GPIO_PXPCR_PIN_MODE_SHIFT (0x00000002UL) -#define U300_GPIO_PXPCR_PIN_MODE_INPUT (0x00000000UL) -#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL (0x00000001UL) -#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_DRAIN (0x00000002UL) -#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_SOURCE (0x00000003UL) -/* Port X Pull-up Enable Register 32bit (R/W) */ -#define U300_GPIO_PXPER (0x10) -#define U300_GPIO_PXPER_ALL_PULL_UP_DISABLE_MASK (0x000000FFUL) -#define U300_GPIO_PXPER_PULL_UP_DISABLE (0x00000001UL) -/* Port X Interrupt Event Register 32bit (R/W) */ -#define U300_GPIO_PXIEV (0x14) -#define U300_GPIO_PXIEV_ALL_IRQ_EVENT_MASK (0x000000FFUL) -#define U300_GPIO_PXIEV_IRQ_EVENT (0x00000001UL) -/* Port X Interrupt Enable Register 32bit (R/W) */ -#define U300_GPIO_PXIEN (0x18) -#define U300_GPIO_PXIEN_ALL_IRQ_ENABLE_MASK (0x000000FFUL) -#define U300_GPIO_PXIEN_IRQ_ENABLE (0x00000001UL) -/* Port X Interrupt Force Register 32bit (R/W) */ -#define U300_GPIO_PXIFR (0x1C) -#define U300_GPIO_PXIFR_ALL_IRQ_FORCE_MASK (0x000000FFUL) -#define U300_GPIO_PXIFR_IRQ_FORCE (0x00000001UL) -/* Port X Interrupt Config Register 32bit (R/W) */ -#define U300_GPIO_PXICR (0x20) -#define U300_GPIO_PXICR_ALL_IRQ_CONFIG_MASK (0x000000FFUL) -#define U300_GPIO_PXICR_IRQ_CONFIG_MASK (0x00000001UL) -#define U300_GPIO_PXICR_IRQ_CONFIG_FALLING_EDGE (0x00000000UL) -#define U300_GPIO_PXICR_IRQ_CONFIG_RISING_EDGE (0x00000001UL) -#ifdef CONFIG_MACH_U300_BS335 -/* seven ports of 8 bits each = GPIO pins 0..55 */ -#define U300_GPIO_NUM_PORTS 7 -#else -/* five ports of 8 bits each = GPIO pins 0..39 */ -#define U300_GPIO_NUM_PORTS 5 -#endif -#define U300_GPIO_PINS_PER_PORT 8 -#define U300_GPIO_MAX (U300_GPIO_PINS_PER_PORT * U300_GPIO_NUM_PORTS - 1) -#endif +/* Map these overrides to gpiolib functions, simply */ +#define gpio_get_value __gpio_get_value +#define gpio_set_value __gpio_set_value +#define gpio_cansleep __gpio_cansleep +#define gpio_to_irq __gpio_to_irq /* * Individual pin assignments for the B26/S26. Notice that the @@ -254,41 +140,4 @@ #endif -/* translates a pin number to a port number */ -#define PIN_TO_PORT(val) (val >> 3) - -/* These can be found in arch/arm/mach-u300/gpio.c */ -extern int gpio_is_valid(int number); -extern int gpio_request(unsigned gpio, const char *label); -extern void gpio_free(unsigned gpio); -extern int gpio_direction_input(unsigned gpio); -extern int gpio_direction_output(unsigned gpio, int value); -extern int gpio_register_callback(unsigned gpio, - int (*func)(void *arg), - void *); -extern int gpio_unregister_callback(unsigned gpio); -extern void enable_irq_on_gpio_pin(unsigned gpio, int edge); -extern void disable_irq_on_gpio_pin(unsigned gpio); -extern void gpio_pullup(unsigned gpio, int value); -extern int gpio_get_value(unsigned gpio); -extern void gpio_set_value(unsigned gpio, int value); - -#define gpio_get_value_cansleep gpio_get_value -#define gpio_set_value_cansleep gpio_set_value - -/* wrappers to sleep-enable the previous two functions */ -static inline unsigned gpio_to_irq(unsigned gpio) -{ - return PIN_TO_PORT(gpio) + IRQ_U300_GPIO_PORT0; -} - -static inline unsigned irq_to_gpio(unsigned irq) -{ - /* - * FIXME: This is no 1-1 mapping at all, it points to the - * whole block of 8 pins. - */ - return (irq - IRQ_U300_GPIO_PORT0) << 3; -} - #endif diff --git a/arch/arm/mach-u300/include/mach/irqs.h b/arch/arm/mach-u300/include/mach/irqs.h index 09b1b28..d270fea 100644 --- a/arch/arm/mach-u300/include/mach/irqs.h +++ b/arch/arm/mach-u300/include/mach/irqs.h @@ -72,7 +72,7 @@ /* DB3150 and DB3200 have only 45 IRQs */ #if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330) -#define U300_NR_IRQS 45 +#define U300_VIC_IRQS_END 45 #endif /* The DB3350-specific interrupt lines */ @@ -88,7 +88,7 @@ #define IRQ_U300_GPIO_PORT4 53 #define IRQ_U300_GPIO_PORT5 54 #define IRQ_U300_GPIO_PORT6 55 -#define U300_NR_IRQS 56 +#define U300_VIC_IRQS_END 56 #endif /* The DB3210-specific interrupt lines */ @@ -106,16 +106,25 @@ #define IRQ_U300_NFIF 45 #define IRQ_U300_NFIF2 46 #define IRQ_U300_SYSCON_PLL_LOCK 47 -#define U300_NR_IRQS 48 +#define U300_VIC_IRQS_END 48 #endif -#ifdef CONFIG_AB3550_CORE -#define IRQ_AB3550_BASE (U300_NR_IRQS) -#define IRQ_AB3550_END (IRQ_AB3550_BASE + 37) +/* Maximum 8*7 GPIO lines */ +#ifdef CONFIG_GPIO_U300 +#define IRQ_U300_GPIO_BASE (U300_VIC_IRQS_END) +#define IRQ_U300_GPIO_END (IRQ_U300_GPIO_BASE + 56) +#else +#define IRQ_U300_GPIO_END (U300_VIC_IRQS_END) +#endif -#define NR_IRQS (IRQ_AB3550_END + 1) +/* Optional AB3550 mixsig chip */ +#ifdef CONFIG_AB3550_CORE +#define IRQ_AB3550_BASE (IRQ_U300_GPIO_END) +#define IRQ_AB3550_END (IRQ_AB3550_BASE + 38) #else -#define NR_IRQS U300_NR_IRQS +#define IRQ_AB3550_END (IRQ_U300_GPIO_END) #endif +#define NR_IRQS (IRQ_AB3550_END) + #endif diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d3b2953..cc89dfa 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -119,6 +119,15 @@ config GPIO_SCH This driver can also be built as a module. If so, the module will be called sch-gpio. +config GPIO_U300 + bool "ST-Ericsson U300 COH 901 335/571 GPIO" + depends on GPIOLIB && ARCH_U300 + help + Say yes here to support GPIO interface on ST-Ericsson U300. + The names of the two IP block variants supported are + COH 901 335 and COH 901 571/3. They contain 3, 5 or 7 + ports of 8 GPIO pins each. + config GPIO_VX855 tristate "VIA VX855/VX875 GPIO" depends on GPIOLIB && MFD_SUPPORT && PCI diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index becef59..26032b1 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_GPIO_WM831X) += wm831x-gpio.o obj-$(CONFIG_GPIO_WM8350) += wm8350-gpiolib.o obj-$(CONFIG_GPIO_WM8994) += wm8994-gpio.o obj-$(CONFIG_GPIO_SCH) += sch_gpio.o +obj-$(CONFIG_GPIO_U300) += u300-gpio.o obj-$(CONFIG_GPIO_RDC321X) += rdc321x-gpio.o obj-$(CONFIG_GPIO_JANZ_TTL) += janz-ttl.o obj-$(CONFIG_GPIO_SX150X) += sx150x.o diff --git a/drivers/gpio/u300-gpio.c b/drivers/gpio/u300-gpio.c new file mode 100644 index 0000000..d85a116 --- /dev/null +++ b/drivers/gpio/u300-gpio.c @@ -0,0 +1,836 @@ +/* + * Copyright (C) 2007-2011 ST-Ericsson AB + * License terms: GNU General Public License (GPL) version 2 + * U300 GPIO module. + * This can driver either of the two basic GPIO cores + * available in the U300 platforms: + * COH 901 335 - Used in DB3150 (U300 1.0) and DB3200 (U330 1.0) + * COH 901 571/3 - Used in DB3210 (U365 2.0) and DB3350 (U335 1.0) + * Author: Linus Walleij <linus.walleij@linaro.org> + * Author: Jonas Aaberg <jonas.aberg@stericsson.com> + */ +#include <linux/module.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/list.h> +#include <linux/slab.h> +#include <linux/gpio/u300.h> + +/* + * Register definitions for COH 901 335 variant + */ +#define U300_335_PORT_STRIDE (0x1C) +/* Port X Pin Data Register 32bit, this is both input and output (R/W) */ +#define U300_335_PXPDIR (0x00) +#define U300_335_PXPDOR (0x00) +/* Port X Pin Config Register 32bit (R/W) */ +#define U300_335_PXPCR (0x04) +/* This register layout is the same in both blocks */ +#define U300_GPIO_PXPCR_ALL_PINS_MODE_MASK (0x0000FFFFUL) +#define U300_GPIO_PXPCR_PIN_MODE_MASK (0x00000003UL) +#define U300_GPIO_PXPCR_PIN_MODE_SHIFT (0x00000002UL) +#define U300_GPIO_PXPCR_PIN_MODE_INPUT (0x00000000UL) +#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL (0x00000001UL) +#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_DRAIN (0x00000002UL) +#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_SOURCE (0x00000003UL) +/* Port X Interrupt Event Register 32bit (R/W) */ +#define U300_335_PXIEV (0x08) +/* Port X Interrupt Enable Register 32bit (R/W) */ +#define U300_335_PXIEN (0x0C) +/* Port X Interrupt Force Register 32bit (R/W) */ +#define U300_335_PXIFR (0x10) +/* Port X Interrupt Config Register 32bit (R/W) */ +#define U300_335_PXICR (0x14) +/* This register layout is the same in both blocks */ +#define U300_GPIO_PXICR_ALL_IRQ_CONFIG_MASK (0x000000FFUL) +#define U300_GPIO_PXICR_IRQ_CONFIG_MASK (0x00000001UL) +#define U300_GPIO_PXICR_IRQ_CONFIG_FALLING_EDGE (0x00000000UL) +#define U300_GPIO_PXICR_IRQ_CONFIG_RISING_EDGE (0x00000001UL) +/* Port X Pull-up Enable Register 32bit (R/W) */ +#define U300_335_PXPER (0x18) +/* This register layout is the same in both blocks */ +#define U300_GPIO_PXPER_ALL_PULL_UP_DISABLE_MASK (0x000000FFUL) +#define U300_GPIO_PXPER_PULL_UP_DISABLE (0x00000001UL) +/* Control Register 32bit (R/W) */ +#define U300_335_CR (0x54) +#define U300_335_CR_BLOCK_CLOCK_ENABLE (0x00000001UL) + +/* + * Register definitions for COH 901 571 / 3 variant + */ +#define U300_571_PORT_STRIDE (0x30) +/* + * Control Register 32bit (R/W) + * bit 15-9 (mask 0x0000FE00) contains the number of cores. 8*cores + * gives the number of GPIO pins. + * bit 8-2 (mask 0x000001FC) contains the core version ID. + */ +#define U300_571_CR (0x00) +#define U300_571_CR_SYNC_SEL_ENABLE (0x00000002UL) +#define U300_571_CR_BLOCK_CLKRQ_ENABLE (0x00000001UL) +/* + * These registers have the same layout and function as the corresponding + * COH 901 335 registers, just at different offset. + */ +#define U300_571_PXPDIR (0x04) +#define U300_571_PXPDOR (0x08) +#define U300_571_PXPCR (0x0C) +#define U300_571_PXPER (0x10) +#define U300_571_PXIEV (0x14) +#define U300_571_PXIEN (0x18) +#define U300_571_PXIFR (0x1C) +#define U300_571_PXICR (0x20) + +/* 8 bits per port, no version has more than 7 ports */ +#define U300_GPIO_PINS_PER_PORT 8 +#define U300_GPIO_MAX (U300_GPIO_PINS_PER_PORT * 7) + +struct u300_gpio { + struct gpio_chip chip; + struct list_head port_list; + struct clk *clk; + struct resource *memres; + void __iomem *base; + struct device *dev; + int irq_base; + int users; + u32 stride; + /* Register offsets */ + u32 pcr; + u32 dor; + u32 dir; + u32 per; + u32 icr; + u32 ien; + u32 iev; +}; + +struct u300_gpio_port { + struct list_head node; + struct u300_gpio *gpio; + char name[8]; + int irq; + int number; +}; + +/* + * Macro to expand to read a specific register found in the "gpio" + * struct. It requires the struct u300_gpio *gpio variable to exist in + * its context. It calculates the port offset from the given pin + * offset, muliplies by the port stride and adds the register offset + * so it provides a pointer to the desired register. + */ +#define U300_PIN_REG(pin, reg) \ + (gpio->base + (pin >> 3) * gpio->stride + gpio->reg) + +/* + * Provides a bitmask for a specific gpio pin inside an 8-bit GPIO + * register. + */ +#define U300_PIN_BIT(pin) \ + (1 << (pin & 0x07)) + +struct u300_gpio_confdata { + u16 bias_mode; + bool output; + int outval; +}; + +/* BS335 has seven ports of 8 bits each = GPIO pins 0..55 */ +#define BS335_GPIO_NUM_PORTS 7 +/* BS365 has five ports of 8 bits each = GPIO pins 0..39 */ +#define BS365_GPIO_NUM_PORTS 5 + +#define U300_FLOATING_INPUT { \ + .bias_mode = GPIO_CONFIG_BIAS_FLOAT, \ + .output = false, \ +} + +#define U300_PULL_UP_INPUT { \ + .bias_mode = GPIO_CONFIG_BIAS_PULL_UP, \ + .output = false, \ +} + +#define U300_OUTPUT_LOW { \ + .output = true, \ + .outval = 0, \ +} + +#define U300_OUTPUT_HIGH { \ + .output = true, \ + .outval = 1, \ +} + + +/* Initial configuration */ +static struct __initdata u300_gpio_confdata +bs335_gpio_config[BS335_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = { + /* Port 0, pins 0-7 */ + { + U300_FLOATING_INPUT, + U300_OUTPUT_HIGH, + U300_FLOATING_INPUT, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + }, + /* Port 1, pins 0-7 */ + { + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_PULL_UP_INPUT, + U300_FLOATING_INPUT, + U300_OUTPUT_HIGH, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + }, + /* Port 2, pins 0-7 */ + { + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_OUTPUT_LOW, + U300_PULL_UP_INPUT, + U300_OUTPUT_LOW, + U300_PULL_UP_INPUT, + }, + /* Port 3, pins 0-7 */ + { + U300_PULL_UP_INPUT, + U300_OUTPUT_LOW, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + }, + /* Port 4, pins 0-7 */ + { + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + }, + /* Port 5, pins 0-7 */ + { + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + }, + /* Port 6, pind 0-7 */ + { + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + } +}; + +static struct __initdata u300_gpio_confdata +bs365_gpio_config[BS365_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = { + /* Port 0, pins 0-7 */ + { + U300_FLOATING_INPUT, + U300_OUTPUT_LOW, + U300_FLOATING_INPUT, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_PULL_UP_INPUT, + U300_FLOATING_INPUT, + }, + /* Port 1, pins 0-7 */ + { + U300_OUTPUT_LOW, + U300_FLOATING_INPUT, + U300_OUTPUT_LOW, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_OUTPUT_HIGH, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + }, + /* Port 2, pins 0-7 */ + { + U300_FLOATING_INPUT, + U300_PULL_UP_INPUT, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + }, + /* Port 3, pins 0-7 */ + { + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + }, + /* Port 4, pins 0-7 */ + { + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + /* These 4 pins doesn't exist on DB3210 */ + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + } +}; + +/** + * to_u300_gpio() - get the pointer to u300_gpio + * @chip: the gpio chip member of the structure u300_gpio + */ +static inline struct u300_gpio *to_u300_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct u300_gpio, chip); +} + +static int u300_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct u300_gpio *gpio = to_u300_gpio(chip); + + return readl(U300_PIN_REG(offset, dir)) & U300_PIN_BIT(offset); +} + +static void u300_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct u300_gpio *gpio = to_u300_gpio(chip); + unsigned long flags; + u32 val; + + local_irq_save(flags); + + val = readl(U300_PIN_REG(offset, dor)); + if (value) + writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, dor)); + else + writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, dor)); + + local_irq_restore(flags); +} + +static int u300_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct u300_gpio *gpio = to_u300_gpio(chip); + unsigned long flags; + u32 val; + + local_irq_save(flags); + val = readl(U300_PIN_REG(offset, pcr)); + /* Mask out this pin, note 2 bits per setting */ + val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << ((offset & 0x07) << 1)); + writel(val, U300_PIN_REG(offset, pcr)); + local_irq_restore(flags); + return 0; +} + +static int u300_gpio_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct u300_gpio *gpio = to_u300_gpio(chip); + unsigned long flags; + u32 oldmode; + u32 val; + + local_irq_save(flags); + val = readl(U300_PIN_REG(offset, pcr)); + /* + * Drive mode must be set by the special mode set function, set + * push/pull mode by default if no mode has been selected. + */ + oldmode = val & (U300_GPIO_PXPCR_PIN_MODE_MASK << + ((offset & 0x07) << 1)); + /* mode = 0 means input, else some mode is already set */ + if (oldmode == 0) { + val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << + ((offset & 0x07) << 1)); + val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL + << ((offset & 0x07) << 1)); + writel(val, U300_PIN_REG(offset, pcr)); + } + u300_gpio_set(chip, offset, value); + local_irq_restore(flags); + return 0; +} + +static int u300_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct u300_gpio *gpio = to_u300_gpio(chip); + int retirq = gpio->irq_base + offset; + + dev_dbg(gpio->dev, "request IRQ for GPIO %d, return %d\n", offset, + retirq); + return retirq; +} + +static int u300_gpio_config(struct gpio_chip *chip, unsigned offset, + u16 param, unsigned long *data) +{ + struct u300_gpio *gpio = to_u300_gpio(chip); + unsigned long flags; + u32 val; + + local_irq_save(flags); + switch (param) { + case GPIO_CONFIG_BIAS_UNKNOWN: + case GPIO_CONFIG_BIAS_FLOAT: + val = readl(U300_PIN_REG(offset, per)); + writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, per)); + break; + case GPIO_CONFIG_BIAS_PULL_UP: + val = readl(U300_PIN_REG(offset, per)); + writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, per)); + break; + case GPIO_CONFIG_DRIVE_PUSH_PULL: + val = readl(U300_PIN_REG(offset, pcr)); + val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK + << ((offset & 0x07) << 1)); + val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL + << ((offset & 0x07) << 1)); + writel(val, U300_PIN_REG(offset, pcr)); + break; + case GPIO_CONFIG_DRIVE_OPEN_DRAIN: + val = readl(U300_PIN_REG(offset, pcr)); + val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK + << ((offset & 0x07) << 1)); + val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_DRAIN + << ((offset & 0x07) << 1)); + writel(val, U300_PIN_REG(offset, pcr)); + break; + case GPIO_CONFIG_DRIVE_OPEN_SOURCE: + val = readl(U300_PIN_REG(offset, pcr)); + val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK + << ((offset & 0x07) << 1)); + val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_SOURCE + << ((offset & 0x07) << 1)); + writel(val, U300_PIN_REG(offset, pcr)); + break; + default: + local_irq_restore(flags); + dev_err(gpio->dev, "illegal configuration requested\n"); + return -EINVAL; + } + local_irq_restore(flags); + return 0; +} + +static struct gpio_chip u300_gpio_chip = { + .label = "u300-gpio-chip", + .owner = THIS_MODULE, + .get = u300_gpio_get, + .set = u300_gpio_set, + .config = u300_gpio_config, + .direction_input = u300_gpio_direction_input, + .direction_output = u300_gpio_direction_output, + .to_irq = u300_gpio_to_irq, +}; + +static int u300_gpio_irq_type(struct irq_data *d, unsigned trigger) +{ + struct u300_gpio *gpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - gpio->irq_base; + u32 val; + + val = readl(U300_PIN_REG(offset, icr)); + if (trigger & IRQF_TRIGGER_RISING) + writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, icr)); + else + writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, icr)); + + return 0; +} + +static void u300_gpio_irq_enable(struct irq_data *d) +{ + struct u300_gpio *gpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - gpio->irq_base; + u32 val; + unsigned long flags; + + local_irq_save(flags); + val = readl(U300_PIN_REG(offset, ien)); + writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, ien)); + local_irq_restore(flags); +} + +static void u300_gpio_irq_disable(struct irq_data *d) +{ + struct u300_gpio *gpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - gpio->irq_base; + u32 val; + unsigned long flags; + + local_irq_save(flags); + val = readl(U300_PIN_REG(offset, ien)); + writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, ien)); + local_irq_restore(flags); +} + +static struct irq_chip u300_gpio_irqchip = { + .name = "u300-gpio-irqchip", + .irq_enable = u300_gpio_irq_enable, + .irq_disable = u300_gpio_irq_disable, + .irq_set_type = u300_gpio_irq_type, + +}; + +static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc) +{ + struct u300_gpio_port *port = irq_get_handler_data(irq); + struct u300_gpio *gpio = port->gpio; + int pinoffset = port->number << 3; /* get the right stride */ + unsigned long val; + + desc->irq_data.chip->irq_ack(&desc->irq_data); + /* Read event register */ + val = readl(U300_PIN_REG(pinoffset, iev)); + /* Mask relevant bits */ + val &= 0xFFU; /* 8 bits per port */ + /* ACK IRQ (clear event) */ + writel(val, U300_PIN_REG(pinoffset, iev)); + + /* Call IRQ handler */ + if (val != 0) { + int irqoffset; + + for_each_set_bit(irqoffset, &val, U300_GPIO_PINS_PER_PORT) { + int pin_irq = gpio->irq_base + (port->number << 3) + + irqoffset; + + dev_dbg(gpio->dev, "GPIO IRQ on pin %d\n", pin_irq); + generic_handle_irq(pin_irq); + } + } + desc->irq_data.chip->irq_unmask(&desc->irq_data); +} + +static void __init u300_gpio_init_pin(struct u300_gpio *gpio, + int offset, + struct u300_gpio_confdata *conf) +{ + /* Set mode: input or output */ + if (conf->output) { + u300_gpio_direction_output(&gpio->chip, offset, conf->outval); + + /* Deactivate bias mode for output */ + u300_gpio_config(&gpio->chip, offset, GPIO_CONFIG_BIAS_FLOAT, + NULL); + + /* Set drive mode for output */ + u300_gpio_config(&gpio->chip, offset, + GPIO_CONFIG_DRIVE_PUSH_PULL, NULL); + + dev_dbg(gpio->dev, "set up pin %d as output, value: %d\n", + offset, conf->outval); + } else { + u300_gpio_direction_input(&gpio->chip, offset); + + /* Always set output low on input pins */ + u300_gpio_set(&gpio->chip, offset, 0); + + /* Set bias mode for input */ + u300_gpio_config(&gpio->chip, offset, conf->bias_mode, NULL); + + dev_dbg(gpio->dev, "set up pin %d as input, bias: %d\n", + offset, conf->bias_mode); + } +} + +static void __init u300_gpio_init_coh901571(struct u300_gpio *gpio, + struct u300_gpio_platform *plat) +{ + int i, j; + + /* Write default config and values to all pins */ + for (i = 0; i < plat->ports; i++) { + for (j = 0; j < 8; j++) { + struct u300_gpio_confdata *conf; + int offset = (i*8) + j; + + if (plat->variant == U300_GPIO_COH901571_3_BS335) + conf = &bs335_gpio_config[i][j]; + else if (plat->variant == U300_GPIO_COH901571_3_BS365) + conf = &bs365_gpio_config[i][j]; + else + break; + + u300_gpio_init_pin(gpio, offset, conf); + } + } +} + +static inline void u300_gpio_free_ports(struct u300_gpio *gpio) +{ + struct u300_gpio_port *port; + struct list_head *p, *n; + + list_for_each_safe(p, n, &gpio->port_list) { + port = list_entry(p, struct u300_gpio_port, node); + list_del(&port->node); + free_irq(port->irq, port); + kfree(port); + } +} + +static int __init u300_gpio_probe(struct platform_device *pdev) +{ + struct u300_gpio_platform *plat = dev_get_platdata(&pdev->dev); + struct u300_gpio *gpio; + int err = 0; + int portno; + u32 val; + u32 ifr; + int i; + + gpio = kzalloc(sizeof(struct u300_gpio), GFP_KERNEL); + if (gpio == NULL) { + dev_err(&pdev->dev, "failed to allocate memory\n"); + return -ENOMEM; + } + + gpio->chip = u300_gpio_chip; + gpio->chip.ngpio = plat->ports * U300_GPIO_PINS_PER_PORT; + gpio->irq_base = plat->gpio_irq_base; + gpio->chip.dev = &pdev->dev; + gpio->chip.base = plat->gpio_base; + gpio->dev = &pdev->dev; + + /* Get GPIO clock */ + gpio->clk = clk_get(gpio->dev, NULL); + if (IS_ERR(gpio->clk)) { + err = PTR_ERR(gpio->clk); + dev_err(gpio->dev, "could not get GPIO clock\n"); + goto err_no_clk; + } + err = clk_enable(gpio->clk); + if (err) { + dev_err(gpio->dev, "could not enable GPIO clock\n"); + goto err_no_clk_enable; + } + + gpio->memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!gpio->memres) { + dev_err(gpio->dev, "could not get GPIO memory resource\n"); + err = -ENODEV; + goto err_no_resource; + } + + if (request_mem_region(gpio->memres->start, + gpio->memres->end - gpio->memres->start, + "GPIO Controller") + == NULL) { + dev_err(gpio->dev, "could not reserve GPIO memory region\n"); + err = -ENODEV; + goto err_no_ioregion; + } + + gpio->base = ioremap(gpio->memres->start, resource_size(gpio->memres)); + if (!gpio->base) { + err = -ENOMEM; + goto err_no_ioremap; + } + + if (plat->variant == U300_GPIO_COH901335) { + dev_info(gpio->dev, + "initializing GPIO Controller COH 901 335\n"); + gpio->stride = U300_335_PORT_STRIDE; + gpio->pcr = U300_335_PXPCR; + gpio->dor = U300_335_PXPDOR; + gpio->dir = U300_335_PXPDIR; + gpio->per = U300_335_PXPER; + gpio->icr = U300_335_PXICR; + gpio->ien = U300_335_PXIEN; + gpio->iev = U300_335_PXIEV; + ifr = U300_335_PXIFR; + + /* Turn on the GPIO block */ + writel(U300_335_CR_BLOCK_CLOCK_ENABLE, + gpio->base + U300_335_CR); + } else if (plat->variant == U300_GPIO_COH901571_3_BS335 || + plat->variant == U300_GPIO_COH901571_3_BS365) { + dev_info(gpio->dev, + "initializing GPIO Controller COH 901 571/3\n"); + gpio->stride = U300_571_PORT_STRIDE; + gpio->pcr = U300_571_PXPCR; + gpio->dor = U300_571_PXPDOR; + gpio->dir = U300_571_PXPDIR; + gpio->per = U300_571_PXPER; + gpio->icr = U300_571_PXICR; + gpio->ien = U300_571_PXIEN; + gpio->iev = U300_571_PXIEV; + ifr = U300_571_PXIFR; + + val = readl(gpio->base + U300_571_CR); + dev_info(gpio->dev, "COH901571/3 block version: %d, " \ + "number of cores: %d\n", + ((val & 0x0000FE00) >> 9), + ((val & 0x000001FC) >> 2)); + writel(U300_571_CR_BLOCK_CLKRQ_ENABLE, + gpio->base + U300_571_CR); + u300_gpio_init_coh901571(gpio, plat); + } else { + dev_err(gpio->dev, "unknown block variant\n"); + err = -ENODEV; + goto err_unknown_variant; + } + + /* Add each port with its IRQ separately */ + INIT_LIST_HEAD(&gpio->port_list); + for (portno = 0 ; portno < plat->ports; portno++) { + struct u300_gpio_port *port = + kmalloc(sizeof(struct u300_gpio_port), GFP_KERNEL); + + if (!port) { + dev_err(gpio->dev, "out of memory\n"); + err = -ENOMEM; + goto err_no_port; + } + + snprintf(port->name, 8, "gpio%d", portno); + port->number = portno; + port->gpio = gpio; + + port->irq = platform_get_irq_byname(pdev, + port->name); + + dev_dbg(gpio->dev, "register IRQ %d for %s\n", port->irq, + port->name); + + irq_set_chained_handler(port->irq, u300_gpio_irq_handler); + irq_set_handler_data(port->irq, port); + + /* Then for each GPIO pin set the unique IRQ handler */ + for (i = 0; i < U300_GPIO_PINS_PER_PORT; i++) { + int irqno = gpio->irq_base + (portno << 3) + i; + + dev_dbg(gpio->dev, "handler for IRQ %d on %s\n", + irqno, port->name); + irq_set_chip_and_handler(irqno, &u300_gpio_irqchip, + handle_simple_irq); + set_irq_flags(irqno, IRQF_VALID); + irq_set_chip_data(irqno, gpio); + } + + /* Turns off irq force (test register) for this port */ + writel(0x0, gpio->base + portno * gpio->stride + ifr); + + list_add_tail(&port->node, &gpio->port_list); + } + + err = gpiochip_add(&gpio->chip); + if (err) { + dev_err(gpio->dev, "unable to add gpiochip: %d\n", err); + goto err_no_chip; + } + + platform_set_drvdata(pdev, gpio); + + return 0; + +err_no_chip: +err_no_port: + u300_gpio_free_ports(gpio); +err_unknown_variant: + iounmap(gpio->base); +err_no_ioremap: + release_mem_region(gpio->memres->start, + gpio->memres->end - gpio->memres->start); +err_no_ioregion: +err_no_resource: + clk_disable(gpio->clk); +err_no_clk_enable: + clk_put(gpio->clk); +err_no_clk: + kfree(gpio); + dev_info(&pdev->dev, "module ERROR:%d\n", err); + return err; +} + +static int __exit u300_gpio_remove(struct platform_device *pdev) +{ + struct u300_gpio_platform *plat = dev_get_platdata(&pdev->dev); + struct u300_gpio *gpio = platform_get_drvdata(pdev); + int err; + + /* Turn off the GPIO block */ + if (plat->variant == U300_GPIO_COH901335) + writel(0x00000000U, gpio->base + U300_335_CR); + if (plat->variant == U300_GPIO_COH901571_3_BS335 || + plat->variant == U300_GPIO_COH901571_3_BS365) + writel(0x00000000U, gpio->base + U300_571_CR); + + err = gpiochip_remove(&gpio->chip); + if (err < 0) { + dev_err(gpio->dev, "unable to remove gpiochip: %d\n", err); + return err; + } + u300_gpio_free_ports(gpio); + iounmap(gpio->base); + release_mem_region(gpio->memres->start, + gpio->memres->end - gpio->memres->start); + clk_disable(gpio->clk); + clk_put(gpio->clk); + platform_set_drvdata(pdev, NULL); + kfree(gpio); + return 0; +} + +static struct platform_driver u300_gpio_driver = { + .driver = { + .name = "u300-gpio", + }, + .remove = __exit_p(u300_gpio_remove), +}; + + +static int __init u300_gpio_init(void) +{ + return platform_driver_probe(&u300_gpio_driver, u300_gpio_probe); +} + +static void __exit u300_gpio_exit(void) +{ + platform_driver_unregister(&u300_gpio_driver); +} + +arch_initcall(u300_gpio_init); +module_exit(u300_gpio_exit); + +MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>"); +MODULE_DESCRIPTION("ST-Ericsson AB COH 901 335/COH 901 571/3 GPIO driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/gpio/u300.h b/include/linux/gpio/u300.h new file mode 100644 index 0000000..38cd064 --- /dev/null +++ b/include/linux/gpio/u300.h @@ -0,0 +1,32 @@ +/* + * U300 GPIO platform data header + * Copyright (C) 2011 ST-Ericsson SA + * Written on behalf of Linaro for ST-Ericsson + * + * Author: Linus Walleij <linus.walleij@linaro.org> + * + * License terms: GNU General Public License (GPL) version 2 + */ + +/** + * enum u300_gpio_variant - the type of U300 GPIO employed + */ +enum u300_gpio_variant { + U300_GPIO_COH901335, + U300_GPIO_COH901571_3_BS335, + U300_GPIO_COH901571_3_BS365, +}; + +/** + * struct u300_gpio_platform - U300 GPIO platform data + * @variant: IP block variant + * @ports: number of GPIO block ports + * @gpio_base: first GPIO number for this block (use a free range) + * @gpio_irq_base: first GPIO IRQ number for this block (use a free range) + */ +struct u300_gpio_platform { + enum u300_gpio_variant variant; + u8 ports; + int gpio_base; + int gpio_irq_base; +}; -- 1.7.3.2 ^ permalink raw reply related [flat|nested] 57+ messages in thread
* RE: [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio 2011-04-27 13:13 ` Linus Walleij @ 2011-04-27 18:23 ` H Hartley Sweeten -1 siblings, 0 replies; 57+ messages in thread From: H Hartley Sweeten @ 2011-04-27 18:23 UTC (permalink / raw) To: Linus Walleij, Grant Likely, linux-kernel, linux-arm-kernel Cc: Linus Walleij, Lee Jones, Jonas Aaberg On Wednesday, April 27, 2011 6:13 AM, Linus Walleij wrote: > From: Linus Walleij <linus.walleij@linaro.org> > > This rewrites the U300 GPIO driver using gpiolib and the irq_chip > abstractions, makes it runtime-configured rather than compile-time, > and moves it to the drivers/gpio subsystem where it belongs, > depopulating the ARM tree of one more driver. > > Cc: Jonas Aaberg <jonas.aberg@stericsson.com> > Acked-by: Arnd Bergmann <arnd@arndb.de> > Signed-off-by: Linus Walleij <linus.walleij@linaro.org> If this and other platform-specific GPIO drivers are going to be moved to the drivers/gpio subsystem, the Kconfig and Makefile should probably be updated to reflect this. In drivers/gpio/Kconfig: # # platform-neutral GPIO infrastructure and expanders # And in drivers/gpio/Makefile: # generic gpio support: dedicated expander chips, etc # # NOTE: platform-specific GPIO drivers don't belong in the # drivers/gpio directory; put them with other platform setup # code, IRQ controllers, board init, etc. The Makefile should probably be reordered, either alphabetically or grouped by type (arch/mmio/i2c/spi/pci/etc) and then alphabetically in order to reduce merge conflicts. Regards, Hartley ^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-04-27 18:23 ` H Hartley Sweeten 0 siblings, 0 replies; 57+ messages in thread From: H Hartley Sweeten @ 2011-04-27 18:23 UTC (permalink / raw) To: linux-arm-kernel On Wednesday, April 27, 2011 6:13 AM, Linus Walleij wrote: > From: Linus Walleij <linus.walleij@linaro.org> > > This rewrites the U300 GPIO driver using gpiolib and the irq_chip > abstractions, makes it runtime-configured rather than compile-time, > and moves it to the drivers/gpio subsystem where it belongs, > depopulating the ARM tree of one more driver. > > Cc: Jonas Aaberg <jonas.aberg@stericsson.com> > Acked-by: Arnd Bergmann <arnd@arndb.de> > Signed-off-by: Linus Walleij <linus.walleij@linaro.org> If this and other platform-specific GPIO drivers are going to be moved to the drivers/gpio subsystem, the Kconfig and Makefile should probably be updated to reflect this. In drivers/gpio/Kconfig: # # platform-neutral GPIO infrastructure and expanders # And in drivers/gpio/Makefile: # generic gpio support: dedicated expander chips, etc # # NOTE: platform-specific GPIO drivers don't belong in the # drivers/gpio directory; put them with other platform setup # code, IRQ controllers, board init, etc. The Makefile should probably be reordered, either alphabetically or grouped by type (arch/mmio/i2c/spi/pci/etc) and then alphabetically in order to reduce merge conflicts. Regards, Hartley ^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio 2011-04-27 18:23 ` H Hartley Sweeten @ 2011-04-28 7:07 ` Linus Walleij -1 siblings, 0 replies; 57+ messages in thread From: Linus Walleij @ 2011-04-28 7:07 UTC (permalink / raw) To: H Hartley Sweeten, Grant Likely Cc: linux-kernel, linux-arm-kernel, Lee Jones, Jonas Aaberg 2011/4/27 H Hartley Sweeten <hartleys@visionengravers.com>: > On Wednesday, April 27, 2011 6:13 AM, Linus Walleij wrote: >> From: Linus Walleij <linus.walleij@linaro.org> >> >> This rewrites the U300 GPIO driver using gpiolib and the irq_chip >> abstractions, makes it runtime-configured rather than compile-time, >> and moves it to the drivers/gpio subsystem where it belongs, >> depopulating the ARM tree of one more driver. >> >> Cc: Jonas Aaberg <jonas.aberg@stericsson.com> >> Acked-by: Arnd Bergmann <arnd@arndb.de> >> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> > > If this and other platform-specific GPIO drivers are going to be > moved to the drivers/gpio subsystem, the Kconfig and Makefile should > probably be updated to reflect this. > > In drivers/gpio/Kconfig: > > # > # platform-neutral GPIO infrastructure and expanders > # > > And in drivers/gpio/Makefile: > > # generic gpio support: dedicated expander chips, etc > # > # NOTE: platform-specific GPIO drivers don't belong in the > # drivers/gpio directory; put them with other platform setup > # code, IRQ controllers, board init, etc. Yeah, you're right. I can take these comments out, simply. I'll review the files as bit to make sure there aren't any more statements like that. > The Makefile should probably be reordered, either alphabetically > or grouped by type (arch/mmio/i2c/spi/pci/etc) and then > alphabetically in order to reduce merge conflicts. Yes, but if I do that in my patchset I will screw up Grants GPIO tree completely, so I prefer that Grant do this. And maybe after pulling in my GPIO consolidation tree to his in that case, so we don't get undesired collisions. So leaving this for the GPIO maintainer. Yours, Linus Walleij ^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-04-28 7:07 ` Linus Walleij 0 siblings, 0 replies; 57+ messages in thread From: Linus Walleij @ 2011-04-28 7:07 UTC (permalink / raw) To: linux-arm-kernel 2011/4/27 H Hartley Sweeten <hartleys@visionengravers.com>: > On Wednesday, April 27, 2011 6:13 AM, Linus Walleij wrote: >> From: Linus Walleij <linus.walleij@linaro.org> >> >> This rewrites the U300 GPIO driver using gpiolib and the irq_chip >> abstractions, makes it runtime-configured rather than compile-time, >> and moves it to the drivers/gpio subsystem where it belongs, >> depopulating the ARM tree of one more driver. >> >> Cc: Jonas Aaberg <jonas.aberg@stericsson.com> >> Acked-by: Arnd Bergmann <arnd@arndb.de> >> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> > > If this and other platform-specific GPIO drivers are going to be > moved to the drivers/gpio subsystem, the Kconfig and Makefile should > probably be updated to reflect this. > > In drivers/gpio/Kconfig: > > # > # platform-neutral GPIO infrastructure and expanders > # > > And in drivers/gpio/Makefile: > > # generic gpio support: dedicated expander chips, etc > # > # NOTE: platform-specific GPIO drivers don't belong in the > # drivers/gpio directory; put them with other platform setup > # code, IRQ controllers, board init, etc. Yeah, you're right. I can take these comments out, simply. I'll review the files as bit to make sure there aren't any more statements like that. > The Makefile should probably be reordered, either alphabetically > or grouped by type (arch/mmio/i2c/spi/pci/etc) and then > alphabetically in order to reduce merge conflicts. Yes, but if I do that in my patchset I will screw up Grants GPIO tree completely, so I prefer that Grant do this. And maybe after pulling in my GPIO consolidation tree to his in that case, so we don't get undesired collisions. So leaving this for the GPIO maintainer. Yours, Linus Walleij ^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio 2011-04-28 7:07 ` Linus Walleij @ 2011-04-28 7:10 ` Linus Walleij -1 siblings, 0 replies; 57+ messages in thread From: Linus Walleij @ 2011-04-28 7:10 UTC (permalink / raw) To: H Hartley Sweeten, Grant Likely Cc: linux-kernel, linux-arm-kernel, Lee Jones, Jonas Aaberg 2011/4/28 Linus Walleij <linus.walleij@linaro.org>: > 2011/4/27 H Hartley Sweeten <hartleys@visionengravers.com>: >> # NOTE: platform-specific GPIO drivers don't belong in the >> # drivers/gpio directory; put them with other platform setup >> # code, IRQ controllers, board init, etc. > > Yeah, you're right. I can take these comments out, simply. > I'll review the files as bit to make sure there aren't any more > statements like that. Thinking of this, the pl061.c driver is already no expansion chip (it's SoC silicon) so this statement has been wrong for some time already. Linus Walleij ^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-04-28 7:10 ` Linus Walleij 0 siblings, 0 replies; 57+ messages in thread From: Linus Walleij @ 2011-04-28 7:10 UTC (permalink / raw) To: linux-arm-kernel 2011/4/28 Linus Walleij <linus.walleij@linaro.org>: > 2011/4/27 H Hartley Sweeten <hartleys@visionengravers.com>: >> # NOTE: platform-specific GPIO drivers don't belong in the >> # drivers/gpio directory; put them with other platform setup >> # code, IRQ controllers, board init, etc. > > Yeah, you're right. I can take these comments out, simply. > I'll review the files as bit to make sure there aren't any more > statements like that. Thinking of this, the pl061.c driver is already no expansion chip (it's SoC silicon) so this statement has been wrong for some time already. Linus Walleij ^ permalink raw reply [flat|nested] 57+ messages in thread
* RE: [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio 2011-04-28 7:07 ` Linus Walleij @ 2011-04-28 17:41 ` H Hartley Sweeten -1 siblings, 0 replies; 57+ messages in thread From: H Hartley Sweeten @ 2011-04-28 17:41 UTC (permalink / raw) To: Linus Walleij, Grant Likely Cc: linux-kernel, linux-arm-kernel, Lee Jones, Jonas Aaberg On Thursday, April 28, 2011 12:08 AM, Linus Walleij wrote: > 2011/4/27 H Hartley Sweeten <hartleys@visionengravers.com>: >> The Makefile should probably be reordered, either alphabetically >> or grouped by type (arch/mmio/i2c/spi/pci/etc) and then >> alphabetically in order to reduce merge conflicts. > > Yes, but if I do that in my patchset I will screw up Grants GPIO tree > completely, so I prefer that Grant do this. And maybe after pulling > in my GPIO consolidation tree to his in that case, so we don't get > undesired collisions. So leaving this for the GPIO maintainer. This comment was intended for the GPIO maintainer. Sorry for any confusion. Regards, Hartley ^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-04-28 17:41 ` H Hartley Sweeten 0 siblings, 0 replies; 57+ messages in thread From: H Hartley Sweeten @ 2011-04-28 17:41 UTC (permalink / raw) To: linux-arm-kernel On Thursday, April 28, 2011 12:08 AM, Linus Walleij wrote: > 2011/4/27 H Hartley Sweeten <hartleys@visionengravers.com>: >> The Makefile should probably be reordered, either alphabetically >> or grouped by type (arch/mmio/i2c/spi/pci/etc) and then >> alphabetically in order to reduce merge conflicts. > > Yes, but if I do that in my patchset I will screw up Grants GPIO tree > completely, so I prefer that Grant do this. And maybe after pulling > in my GPIO consolidation tree to his in that case, so we don't get > undesired collisions. So leaving this for the GPIO maintainer. This comment was intended for the GPIO maintainer. Sorry for any confusion. Regards, Hartley ^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio 2011-04-28 17:41 ` H Hartley Sweeten @ 2011-05-13 14:51 ` Linus Walleij -1 siblings, 0 replies; 57+ messages in thread From: Linus Walleij @ 2011-05-13 14:51 UTC (permalink / raw) To: H Hartley Sweeten Cc: Grant Likely, Jonas Aaberg, Lee Jones, linux-kernel, linux-arm-kernel 2011/4/28 H Hartley Sweeten <hartleys@visionengravers.com>: > On Thursday, April 28, 2011 12:08 AM, Linus Walleij wrote: >> 2011/4/27 H Hartley Sweeten <hartleys@visionengravers.com>: >>> The Makefile should probably be reordered, either alphabetically >>> or grouped by type (arch/mmio/i2c/spi/pci/etc) and then >>> alphabetically in order to reduce merge conflicts. >> >> Yes, but if I do that in my patchset I will screw up Grants GPIO tree >> completely, so I prefer that Grant do this. And maybe after pulling >> in my GPIO consolidation tree to his in that case, so we don't get >> undesired collisions. So leaving this for the GPIO maintainer. > > This comment was intended for the GPIO maintainer. Sorry for any > confusion. Nop problem, I actually made a fix for it that I think Grant can take in for 2.6.40. Yours, Linus Walleij ^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-05-13 14:51 ` Linus Walleij 0 siblings, 0 replies; 57+ messages in thread From: Linus Walleij @ 2011-05-13 14:51 UTC (permalink / raw) To: linux-arm-kernel 2011/4/28 H Hartley Sweeten <hartleys@visionengravers.com>: > On Thursday, April 28, 2011 12:08 AM, Linus Walleij wrote: >> 2011/4/27 H Hartley Sweeten <hartleys@visionengravers.com>: >>> The Makefile should probably be reordered, either alphabetically >>> or grouped by type (arch/mmio/i2c/spi/pci/etc) and then >>> alphabetically in order to reduce merge conflicts. >> >> Yes, but if I do that in my patchset I will screw up Grants GPIO tree >> completely, so I prefer that Grant do this. And maybe after pulling >> in my GPIO consolidation tree to his in that case, so we don't get >> undesired collisions. So leaving this for the GPIO maintainer. > > This comment was intended for the GPIO maintainer. ?Sorry for any > confusion. Nop problem, I actually made a fix for it that I think Grant can take in for 2.6.40. Yours, Linus Walleij ^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio 2011-04-27 13:13 ` Linus Walleij @ 2011-05-19 8:56 ` Shawn Guo -1 siblings, 0 replies; 57+ messages in thread From: Shawn Guo @ 2011-05-19 8:56 UTC (permalink / raw) To: Linus Walleij Cc: Grant Likely, linux-kernel, linux-arm-kernel, Linus Walleij, Lee Jones, Jonas Aaberg On Wed, Apr 27, 2011 at 03:13:22PM +0200, Linus Walleij wrote: > From: Linus Walleij <linus.walleij@linaro.org> > > This rewrites the U300 GPIO driver using gpiolib and the irq_chip > abstractions, makes it runtime-configured rather than compile-time, > and moves it to the drivers/gpio subsystem where it belongs, > depopulating the ARM tree of one more driver. > > Cc: Jonas Aaberg <jonas.aberg@stericsson.com> > Acked-by: Arnd Bergmann <arnd@arndb.de> > Signed-off-by: Linus Walleij <linus.walleij@linaro.org> > --- I start working on moving mxs gpio (arch/arm/mach-mxs/gpio.c) into driver/gpio, and I see the possibility to go a different approach from U300 one posted here. The common thing between these two hardwares is there are several gpio ports implemented in one memory region. And it seems no problem to treat all these gpio ports as one gpio chip, and we can use platform data to specify port number, and calculate base address of each port with shifting start address. But I do not think this approach is able to scale comparing to the one that we treat each port as an independent gpio chip. Looking at mxc gpio driver, we will see those gpio ports lay at the discrete memory regions. One port one chip approach works for both cases, since sharing one memory region is just a special case of one port one region case. And most importantly, it will make gpio driver clean and easy to see the common pattern among different gpio drivers. -- Regards, Shawn ^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-05-19 8:56 ` Shawn Guo 0 siblings, 0 replies; 57+ messages in thread From: Shawn Guo @ 2011-05-19 8:56 UTC (permalink / raw) To: linux-arm-kernel On Wed, Apr 27, 2011 at 03:13:22PM +0200, Linus Walleij wrote: > From: Linus Walleij <linus.walleij@linaro.org> > > This rewrites the U300 GPIO driver using gpiolib and the irq_chip > abstractions, makes it runtime-configured rather than compile-time, > and moves it to the drivers/gpio subsystem where it belongs, > depopulating the ARM tree of one more driver. > > Cc: Jonas Aaberg <jonas.aberg@stericsson.com> > Acked-by: Arnd Bergmann <arnd@arndb.de> > Signed-off-by: Linus Walleij <linus.walleij@linaro.org> > --- I start working on moving mxs gpio (arch/arm/mach-mxs/gpio.c) into driver/gpio, and I see the possibility to go a different approach from U300 one posted here. The common thing between these two hardwares is there are several gpio ports implemented in one memory region. And it seems no problem to treat all these gpio ports as one gpio chip, and we can use platform data to specify port number, and calculate base address of each port with shifting start address. But I do not think this approach is able to scale comparing to the one that we treat each port as an independent gpio chip. Looking at mxc gpio driver, we will see those gpio ports lay at the discrete memory regions. One port one chip approach works for both cases, since sharing one memory region is just a special case of one port one region case. And most importantly, it will make gpio driver clean and easy to see the common pattern among different gpio drivers. -- Regards, Shawn ^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio 2011-05-19 8:56 ` Shawn Guo @ 2011-05-19 12:21 ` Linus Walleij -1 siblings, 0 replies; 57+ messages in thread From: Linus Walleij @ 2011-05-19 12:21 UTC (permalink / raw) To: Shawn Guo Cc: Linus Walleij, Grant Likely, linux-kernel, linux-arm-kernel, Lee Jones, Jonas Aaberg On Thu, May 19, 2011 at 10:56 AM, Shawn Guo <shawn.guo@freescale.com> wrote: > I start working on moving mxs gpio (arch/arm/mach-mxs/gpio.c) into > driver/gpio, and I see the possibility to go a different approach > from U300 one posted here. I've tried to figure out what relation the mail has to the U300 driver but cannot find any, more than that it's moving a driver... Please start a new mail thread. Linus Walleij ^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-05-19 12:21 ` Linus Walleij 0 siblings, 0 replies; 57+ messages in thread From: Linus Walleij @ 2011-05-19 12:21 UTC (permalink / raw) To: linux-arm-kernel On Thu, May 19, 2011 at 10:56 AM, Shawn Guo <shawn.guo@freescale.com> wrote: > I start working on moving mxs gpio (arch/arm/mach-mxs/gpio.c) into > driver/gpio, and I see the possibility to go a different approach > from U300 one posted here. I've tried to figure out what relation the mail has to the U300 driver but cannot find any, more than that it's moving a driver... Please start a new mail thread. Linus Walleij ^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio 2011-05-19 12:21 ` Linus Walleij @ 2011-05-19 13:56 ` Shawn Guo -1 siblings, 0 replies; 57+ messages in thread From: Shawn Guo @ 2011-05-19 13:56 UTC (permalink / raw) To: Linus Walleij Cc: Linus Walleij, Grant Likely, linux-kernel, linux-arm-kernel, Lee Jones, Jonas Aaberg On Thu, May 19, 2011 at 02:21:27PM +0200, Linus Walleij wrote: > On Thu, May 19, 2011 at 10:56 AM, Shawn Guo <shawn.guo@freescale.com> wrote: > > > I start working on moving mxs gpio (arch/arm/mach-mxs/gpio.c) into > > driver/gpio, and I see the possibility to go a different approach > > from U300 one posted here. > > I've tried to figure out what relation the mail has to the U300 driver > but cannot find any, more than that it's moving a driver... Please > start a new mail thread. > I will post mxs-gpio driver once I get it done. Then please review the code and see the difference between mxs-gpio and u300-gpio, though these hardwares have something in common. -- Regards, Shawn ^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-05-19 13:56 ` Shawn Guo 0 siblings, 0 replies; 57+ messages in thread From: Shawn Guo @ 2011-05-19 13:56 UTC (permalink / raw) To: linux-arm-kernel On Thu, May 19, 2011 at 02:21:27PM +0200, Linus Walleij wrote: > On Thu, May 19, 2011 at 10:56 AM, Shawn Guo <shawn.guo@freescale.com> wrote: > > > I start working on moving mxs gpio (arch/arm/mach-mxs/gpio.c) into > > driver/gpio, and I see the possibility to go a different approach > > from U300 one posted here. > > I've tried to figure out what relation the mail has to the U300 driver > but cannot find any, more than that it's moving a driver... Please > start a new mail thread. > I will post mxs-gpio driver once I get it done. Then please review the code and see the difference between mxs-gpio and u300-gpio, though these hardwares have something in common. -- Regards, Shawn ^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio 2011-05-19 13:56 ` Shawn Guo @ 2011-05-19 19:11 ` Sascha Hauer -1 siblings, 0 replies; 57+ messages in thread From: Sascha Hauer @ 2011-05-19 19:11 UTC (permalink / raw) To: Shawn Guo Cc: Linus Walleij, Linus Walleij, Jonas Aaberg, linux-kernel, Grant Likely, Lee Jones, linux-arm-kernel On Thu, May 19, 2011 at 09:56:32PM +0800, Shawn Guo wrote: > On Thu, May 19, 2011 at 02:21:27PM +0200, Linus Walleij wrote: > > On Thu, May 19, 2011 at 10:56 AM, Shawn Guo <shawn.guo@freescale.com> wrote: > > > > > I start working on moving mxs gpio (arch/arm/mach-mxs/gpio.c) into > > > driver/gpio, and I see the possibility to go a different approach > > > from U300 one posted here. > > > > I've tried to figure out what relation the mail has to the U300 driver > > but cannot find any, more than that it's moving a driver... Please > > start a new mail thread. > > > I will post mxs-gpio driver once I get it done. Then please review > the code and see the difference between mxs-gpio and u300-gpio, > though these hardwares have something in common. I'm pretty sure they have something in common and even more that *all* gpio drivers have something in common. I wonder if it really makes sense to move the gpio driver to drivers/gpio without creating a common mmio_gpio_chip beforehand. This can't be very hard. Sascha -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-05-19 19:11 ` Sascha Hauer 0 siblings, 0 replies; 57+ messages in thread From: Sascha Hauer @ 2011-05-19 19:11 UTC (permalink / raw) To: linux-arm-kernel On Thu, May 19, 2011 at 09:56:32PM +0800, Shawn Guo wrote: > On Thu, May 19, 2011 at 02:21:27PM +0200, Linus Walleij wrote: > > On Thu, May 19, 2011 at 10:56 AM, Shawn Guo <shawn.guo@freescale.com> wrote: > > > > > I start working on moving mxs gpio (arch/arm/mach-mxs/gpio.c) into > > > driver/gpio, and I see the possibility to go a different approach > > > from U300 one posted here. > > > > I've tried to figure out what relation the mail has to the U300 driver > > but cannot find any, more than that it's moving a driver... Please > > start a new mail thread. > > > I will post mxs-gpio driver once I get it done. Then please review > the code and see the difference between mxs-gpio and u300-gpio, > though these hardwares have something in common. I'm pretty sure they have something in common and even more that *all* gpio drivers have something in common. I wonder if it really makes sense to move the gpio driver to drivers/gpio without creating a common mmio_gpio_chip beforehand. This can't be very hard. Sascha -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio 2011-05-19 19:11 ` Sascha Hauer @ 2011-05-19 19:30 ` Nicolas Pitre -1 siblings, 0 replies; 57+ messages in thread From: Nicolas Pitre @ 2011-05-19 19:30 UTC (permalink / raw) To: Sascha Hauer Cc: Shawn Guo, Linus Walleij, Linus Walleij, Jonas Aaberg, linux-kernel, Grant Likely, Lee Jones, linux-arm-kernel On Thu, 19 May 2011, Sascha Hauer wrote: > On Thu, May 19, 2011 at 09:56:32PM +0800, Shawn Guo wrote: > > On Thu, May 19, 2011 at 02:21:27PM +0200, Linus Walleij wrote: > > > On Thu, May 19, 2011 at 10:56 AM, Shawn Guo <shawn.guo@freescale.com> wrote: > > > > > > > I start working on moving mxs gpio (arch/arm/mach-mxs/gpio.c) into > > > > driver/gpio, and I see the possibility to go a different approach > > > > from U300 one posted here. > > > > > > I've tried to figure out what relation the mail has to the U300 driver > > > but cannot find any, more than that it's moving a driver... Please > > > start a new mail thread. > > > > > I will post mxs-gpio driver once I get it done. Then please review > > the code and see the difference between mxs-gpio and u300-gpio, > > though these hardwares have something in common. > > I'm pretty sure they have something in common and even more that *all* > gpio drivers have something in common. I wonder if it really makes sense > to move the gpio driver to drivers/gpio without creating a common > mmio_gpio_chip beforehand. This can't be very hard. I do think that performing the move first will make a subsequent conversion easier. And since a move is a no-op from a functional point of view, it is the safest thing to do first. Nicolas ^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-05-19 19:30 ` Nicolas Pitre 0 siblings, 0 replies; 57+ messages in thread From: Nicolas Pitre @ 2011-05-19 19:30 UTC (permalink / raw) To: linux-arm-kernel On Thu, 19 May 2011, Sascha Hauer wrote: > On Thu, May 19, 2011 at 09:56:32PM +0800, Shawn Guo wrote: > > On Thu, May 19, 2011 at 02:21:27PM +0200, Linus Walleij wrote: > > > On Thu, May 19, 2011 at 10:56 AM, Shawn Guo <shawn.guo@freescale.com> wrote: > > > > > > > I start working on moving mxs gpio (arch/arm/mach-mxs/gpio.c) into > > > > driver/gpio, and I see the possibility to go a different approach > > > > from U300 one posted here. > > > > > > I've tried to figure out what relation the mail has to the U300 driver > > > but cannot find any, more than that it's moving a driver... Please > > > start a new mail thread. > > > > > I will post mxs-gpio driver once I get it done. Then please review > > the code and see the difference between mxs-gpio and u300-gpio, > > though these hardwares have something in common. > > I'm pretty sure they have something in common and even more that *all* > gpio drivers have something in common. I wonder if it really makes sense > to move the gpio driver to drivers/gpio without creating a common > mmio_gpio_chip beforehand. This can't be very hard. I do think that performing the move first will make a subsequent conversion easier. And since a move is a no-op from a functional point of view, it is the safest thing to do first. Nicolas ^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio 2011-05-19 19:30 ` Nicolas Pitre @ 2011-05-20 3:18 ` Shawn Guo -1 siblings, 0 replies; 57+ messages in thread From: Shawn Guo @ 2011-05-20 3:18 UTC (permalink / raw) To: Nicolas Pitre Cc: Sascha Hauer, Linus Walleij, Linus Walleij, Jonas Aaberg, linux-kernel, Grant Likely, Lee Jones, linux-arm-kernel On Thu, May 19, 2011 at 03:30:36PM -0400, Nicolas Pitre wrote: > On Thu, 19 May 2011, Sascha Hauer wrote: > > > On Thu, May 19, 2011 at 09:56:32PM +0800, Shawn Guo wrote: > > > On Thu, May 19, 2011 at 02:21:27PM +0200, Linus Walleij wrote: > > > > On Thu, May 19, 2011 at 10:56 AM, Shawn Guo <shawn.guo@freescale.com> wrote: > > > > > > > > > I start working on moving mxs gpio (arch/arm/mach-mxs/gpio.c) into > > > > > driver/gpio, and I see the possibility to go a different approach > > > > > from U300 one posted here. > > > > > > > > I've tried to figure out what relation the mail has to the U300 driver > > > > but cannot find any, more than that it's moving a driver... Please > > > > start a new mail thread. > > > > > > > I will post mxs-gpio driver once I get it done. Then please review > > > the code and see the difference between mxs-gpio and u300-gpio, > > > though these hardwares have something in common. > > > > I'm pretty sure they have something in common and even more that *all* > > gpio drivers have something in common. I wonder if it really makes sense > > to move the gpio driver to drivers/gpio without creating a common > > mmio_gpio_chip beforehand. This can't be very hard. > > I do think that performing the move first will make a subsequent > conversion easier. And since a move is a no-op from a functional point > of view, it is the safest thing to do first. > That's also what I heard on UDS week. Move stuff into driver/gpio first, then try to find the pattern in those drivers and come up with some framework. -- Regards, Shawn ^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-05-20 3:18 ` Shawn Guo 0 siblings, 0 replies; 57+ messages in thread From: Shawn Guo @ 2011-05-20 3:18 UTC (permalink / raw) To: linux-arm-kernel On Thu, May 19, 2011 at 03:30:36PM -0400, Nicolas Pitre wrote: > On Thu, 19 May 2011, Sascha Hauer wrote: > > > On Thu, May 19, 2011 at 09:56:32PM +0800, Shawn Guo wrote: > > > On Thu, May 19, 2011 at 02:21:27PM +0200, Linus Walleij wrote: > > > > On Thu, May 19, 2011 at 10:56 AM, Shawn Guo <shawn.guo@freescale.com> wrote: > > > > > > > > > I start working on moving mxs gpio (arch/arm/mach-mxs/gpio.c) into > > > > > driver/gpio, and I see the possibility to go a different approach > > > > > from U300 one posted here. > > > > > > > > I've tried to figure out what relation the mail has to the U300 driver > > > > but cannot find any, more than that it's moving a driver... Please > > > > start a new mail thread. > > > > > > > I will post mxs-gpio driver once I get it done. Then please review > > > the code and see the difference between mxs-gpio and u300-gpio, > > > though these hardwares have something in common. > > > > I'm pretty sure they have something in common and even more that *all* > > gpio drivers have something in common. I wonder if it really makes sense > > to move the gpio driver to drivers/gpio without creating a common > > mmio_gpio_chip beforehand. This can't be very hard. > > I do think that performing the move first will make a subsequent > conversion easier. And since a move is a no-op from a functional point > of view, it is the safest thing to do first. > That's also what I heard on UDS week. Move stuff into driver/gpio first, then try to find the pattern in those drivers and come up with some framework. -- Regards, Shawn ^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio 2011-05-20 3:18 ` Shawn Guo @ 2011-05-20 3:43 ` Kyungmin Park -1 siblings, 0 replies; 57+ messages in thread From: Kyungmin Park @ 2011-05-20 3:43 UTC (permalink / raw) To: Shawn Guo Cc: Nicolas Pitre, Linus Walleij, Jonas Aaberg, Sascha Hauer, linux-kernel, Grant Likely, Lee Jones, Linus Walleij, linux-arm-kernel On Fri, May 20, 2011 at 12:18 PM, Shawn Guo <shawn.guo@freescale.com> wrote: > On Thu, May 19, 2011 at 03:30:36PM -0400, Nicolas Pitre wrote: >> On Thu, 19 May 2011, Sascha Hauer wrote: >> >> > On Thu, May 19, 2011 at 09:56:32PM +0800, Shawn Guo wrote: >> > > On Thu, May 19, 2011 at 02:21:27PM +0200, Linus Walleij wrote: >> > > > On Thu, May 19, 2011 at 10:56 AM, Shawn Guo <shawn.guo@freescale.com> wrote: >> > > > >> > > > > I start working on moving mxs gpio (arch/arm/mach-mxs/gpio.c) into >> > > > > driver/gpio, and I see the possibility to go a different approach >> > > > > from U300 one posted here. >> > > > >> > > > I've tried to figure out what relation the mail has to the U300 driver >> > > > but cannot find any, more than that it's moving a driver... Please >> > > > start a new mail thread. >> > > > >> > > I will post mxs-gpio driver once I get it done. Then please review >> > > the code and see the difference between mxs-gpio and u300-gpio, >> > > though these hardwares have something in common. >> > >> > I'm pretty sure they have something in common and even more that *all* >> > gpio drivers have something in common. I wonder if it really makes sense >> > to move the gpio driver to drivers/gpio without creating a common >> > mmio_gpio_chip beforehand. This can't be very hard. >> >> I do think that performing the move first will make a subsequent >> conversion easier. And since a move is a no-op from a functional point >> of view, it is the safest thing to do first. >> > That's also what I heard on UDS week. Move stuff into driver/gpio > first, then try to find the pattern in those drivers and come up with > some framework. I agree, I reviewed the mmio_gpio_chip, but it's too simple to cover current implementation. So first move to the drivers/gpio and make more common mmio_gpio instead of basic. BTW, how do you think the GPIO interrupt routine. If it uses the drivers/gpio drivers, it also cover the gpio interrupt codes at drivers/gpio? or separate it? Thank you, Kyungmin Park ^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-05-20 3:43 ` Kyungmin Park 0 siblings, 0 replies; 57+ messages in thread From: Kyungmin Park @ 2011-05-20 3:43 UTC (permalink / raw) To: linux-arm-kernel On Fri, May 20, 2011 at 12:18 PM, Shawn Guo <shawn.guo@freescale.com> wrote: > On Thu, May 19, 2011 at 03:30:36PM -0400, Nicolas Pitre wrote: >> On Thu, 19 May 2011, Sascha Hauer wrote: >> >> > On Thu, May 19, 2011 at 09:56:32PM +0800, Shawn Guo wrote: >> > > On Thu, May 19, 2011 at 02:21:27PM +0200, Linus Walleij wrote: >> > > > On Thu, May 19, 2011 at 10:56 AM, Shawn Guo <shawn.guo@freescale.com> wrote: >> > > > >> > > > > I start working on moving mxs gpio (arch/arm/mach-mxs/gpio.c) into >> > > > > driver/gpio, and I see the possibility to go a different approach >> > > > > from U300 one posted here. >> > > > >> > > > I've tried to figure out what relation the mail has to the U300 driver >> > > > but cannot find any, more than that it's moving a driver... Please >> > > > start a new mail thread. >> > > > >> > > I will post mxs-gpio driver once I get it done. ?Then please review >> > > the code and see the difference between mxs-gpio and u300-gpio, >> > > though these hardwares have something in common. >> > >> > I'm pretty sure they have something in common and even more that *all* >> > gpio drivers have something in common. I wonder if it really makes sense >> > to move the gpio driver to drivers/gpio without creating a common >> > mmio_gpio_chip beforehand. This can't be very hard. >> >> I do think that performing the move first will make a subsequent >> conversion easier. ?And since a move is a no-op from a functional point >> of view, it is the safest thing to do first. >> > That's also what I heard on UDS week. ?Move stuff into driver/gpio > first, then try to find the pattern in those drivers and come up with > some framework. I agree, I reviewed the mmio_gpio_chip, but it's too simple to cover current implementation. So first move to the drivers/gpio and make more common mmio_gpio instead of basic. BTW, how do you think the GPIO interrupt routine. If it uses the drivers/gpio drivers, it also cover the gpio interrupt codes at drivers/gpio? or separate it? Thank you, Kyungmin Park ^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio 2011-05-20 3:43 ` Kyungmin Park @ 2011-05-20 3:54 ` Nicolas Pitre -1 siblings, 0 replies; 57+ messages in thread From: Nicolas Pitre @ 2011-05-20 3:54 UTC (permalink / raw) To: Kyungmin Park Cc: Shawn Guo, Linus Walleij, Jonas Aaberg, Sascha Hauer, linux-kernel, Grant Likely, Lee Jones, Linus Walleij, linux-arm-kernel On Fri, 20 May 2011, Kyungmin Park wrote: > BTW, how do you think the GPIO interrupt routine. If it uses the > drivers/gpio drivers, it also cover the gpio interrupt codes at > drivers/gpio? or separate it? Let's just do the move for now. I don't think it is worth splitting out the IRQ code just yet, unless there is a common pattern to be seen there. Nicolas ^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-05-20 3:54 ` Nicolas Pitre 0 siblings, 0 replies; 57+ messages in thread From: Nicolas Pitre @ 2011-05-20 3:54 UTC (permalink / raw) To: linux-arm-kernel On Fri, 20 May 2011, Kyungmin Park wrote: > BTW, how do you think the GPIO interrupt routine. If it uses the > drivers/gpio drivers, it also cover the gpio interrupt codes at > drivers/gpio? or separate it? Let's just do the move for now. I don't think it is worth splitting out the IRQ code just yet, unless there is a common pattern to be seen there. Nicolas ^ permalink raw reply [flat|nested] 57+ messages in thread
* RE: [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio 2011-05-19 19:11 ` Sascha Hauer @ 2011-05-19 21:18 ` H Hartley Sweeten -1 siblings, 0 replies; 57+ messages in thread From: H Hartley Sweeten @ 2011-05-19 21:18 UTC (permalink / raw) To: Sascha Hauer, Shawn Guo Cc: Linus Walleij, Jonas Aaberg, Linus Walleij, linux-kernel, Grant Likely, Lee Jones, linux-arm-kernel, Jamie Iles On Thursday, May 19, 2011 12:12 PM, Sascha Hauer wrote: > On Thu, May 19, 2011 at 09:56:32PM +0800, Shawn Guo wrote: >> On Thu, May 19, 2011 at 02:21:27PM +0200, Linus Walleij wrote: >>> On Thu, May 19, 2011 at 10:56 AM, Shawn Guo <shawn.guo@freescale.com> wrote: >>> >>>> I start working on moving mxs gpio (arch/arm/mach-mxs/gpio.c) into >>>> driver/gpio, and I see the possibility to go a different approach >>>> from U300 one posted here. >>> >>> I've tried to figure out what relation the mail has to the U300 driver >>> but cannot find any, more than that it's moving a driver... Please >>> start a new mail thread. >>> >> I will post mxs-gpio driver once I get it done. Then please review >> the code and see the difference between mxs-gpio and u300-gpio, >> though these hardwares have something in common. > > I'm pretty sure they have something in common and even more that *all* > gpio drivers have something in common. I wonder if it really makes sense > to move the gpio driver to drivers/gpio without creating a common > mmio_gpio_chip beforehand. This can't be very hard. Jamie Iles (cc'ed) posted some patches that extended the basic_mmio_gpio driver so that it could be used as a library by other gpio drivers. Jamie, could you re-post that series to the linux-arm-kernel list for review? Thanks, Hartley ^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-05-19 21:18 ` H Hartley Sweeten 0 siblings, 0 replies; 57+ messages in thread From: H Hartley Sweeten @ 2011-05-19 21:18 UTC (permalink / raw) To: linux-arm-kernel On Thursday, May 19, 2011 12:12 PM, Sascha Hauer wrote: > On Thu, May 19, 2011 at 09:56:32PM +0800, Shawn Guo wrote: >> On Thu, May 19, 2011 at 02:21:27PM +0200, Linus Walleij wrote: >>> On Thu, May 19, 2011 at 10:56 AM, Shawn Guo <shawn.guo@freescale.com> wrote: >>> >>>> I start working on moving mxs gpio (arch/arm/mach-mxs/gpio.c) into >>>> driver/gpio, and I see the possibility to go a different approach >>>> from U300 one posted here. >>> >>> I've tried to figure out what relation the mail has to the U300 driver >>> but cannot find any, more than that it's moving a driver... Please >>> start a new mail thread. >>> >> I will post mxs-gpio driver once I get it done. Then please review >> the code and see the difference between mxs-gpio and u300-gpio, >> though these hardwares have something in common. > > I'm pretty sure they have something in common and even more that *all* > gpio drivers have something in common. I wonder if it really makes sense > to move the gpio driver to drivers/gpio without creating a common > mmio_gpio_chip beforehand. This can't be very hard. Jamie Iles (cc'ed) posted some patches that extended the basic_mmio_gpio driver so that it could be used as a library by other gpio drivers. Jamie, could you re-post that series to the linux-arm-kernel list for review? Thanks, Hartley ^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio 2011-05-19 21:18 ` H Hartley Sweeten @ 2011-05-20 1:50 ` Jamie Iles -1 siblings, 0 replies; 57+ messages in thread From: Jamie Iles @ 2011-05-20 1:50 UTC (permalink / raw) To: H Hartley Sweeten Cc: Sascha Hauer, Shawn Guo, Linus Walleij, Jonas Aaberg, Linus Walleij, linux-kernel, Grant Likely, Lee Jones, linux-arm-kernel, Jamie Iles On Thu, May 19, 2011 at 04:18:56PM -0500, H Hartley Sweeten wrote: > On Thursday, May 19, 2011 12:12 PM, Sascha Hauer wrote: > > On Thu, May 19, 2011 at 09:56:32PM +0800, Shawn Guo wrote: > >> On Thu, May 19, 2011 at 02:21:27PM +0200, Linus Walleij wrote: > >>> On Thu, May 19, 2011 at 10:56 AM, Shawn Guo <shawn.guo@freescale.com> wrote: > >>> > >>>> I start working on moving mxs gpio (arch/arm/mach-mxs/gpio.c) into > >>>> driver/gpio, and I see the possibility to go a different approach > >>>> from U300 one posted here. > >>> > >>> I've tried to figure out what relation the mail has to the U300 driver > >>> but cannot find any, more than that it's moving a driver... Please > >>> start a new mail thread. > >>> > >> I will post mxs-gpio driver once I get it done. Then please review > >> the code and see the difference between mxs-gpio and u300-gpio, > >> though these hardwares have something in common. > > > > I'm pretty sure they have something in common and even more that *all* > > gpio drivers have something in common. I wonder if it really makes sense > > to move the gpio driver to drivers/gpio without creating a common > > mmio_gpio_chip beforehand. This can't be very hard. > > Jamie Iles (cc'ed) posted some patches that extended the basic_mmio_gpio > driver so that it could be used as a library by other gpio drivers. > > Jamie, could you re-post that series to the linux-arm-kernel list for > review? Grant has applied these patches but I've put them in a public branch if that's OK rather than reposting: git://github.com/jamieiles/linux-2.6-ji.git gpio Jamie ^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-05-20 1:50 ` Jamie Iles 0 siblings, 0 replies; 57+ messages in thread From: Jamie Iles @ 2011-05-20 1:50 UTC (permalink / raw) To: linux-arm-kernel On Thu, May 19, 2011 at 04:18:56PM -0500, H Hartley Sweeten wrote: > On Thursday, May 19, 2011 12:12 PM, Sascha Hauer wrote: > > On Thu, May 19, 2011 at 09:56:32PM +0800, Shawn Guo wrote: > >> On Thu, May 19, 2011 at 02:21:27PM +0200, Linus Walleij wrote: > >>> On Thu, May 19, 2011 at 10:56 AM, Shawn Guo <shawn.guo@freescale.com> wrote: > >>> > >>>> I start working on moving mxs gpio (arch/arm/mach-mxs/gpio.c) into > >>>> driver/gpio, and I see the possibility to go a different approach > >>>> from U300 one posted here. > >>> > >>> I've tried to figure out what relation the mail has to the U300 driver > >>> but cannot find any, more than that it's moving a driver... Please > >>> start a new mail thread. > >>> > >> I will post mxs-gpio driver once I get it done. Then please review > >> the code and see the difference between mxs-gpio and u300-gpio, > >> though these hardwares have something in common. > > > > I'm pretty sure they have something in common and even more that *all* > > gpio drivers have something in common. I wonder if it really makes sense > > to move the gpio driver to drivers/gpio without creating a common > > mmio_gpio_chip beforehand. This can't be very hard. > > Jamie Iles (cc'ed) posted some patches that extended the basic_mmio_gpio > driver so that it could be used as a library by other gpio drivers. > > Jamie, could you re-post that series to the linux-arm-kernel list for > review? Grant has applied these patches but I've put them in a public branch if that's OK rather than reposting: git://github.com/jamieiles/linux-2.6-ji.git gpio Jamie ^ permalink raw reply [flat|nested] 57+ messages in thread
* RE: [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio 2011-05-20 1:50 ` Jamie Iles @ 2011-05-20 22:07 ` H Hartley Sweeten -1 siblings, 0 replies; 57+ messages in thread From: H Hartley Sweeten @ 2011-05-20 22:07 UTC (permalink / raw) To: Jamie Iles Cc: Sascha Hauer, Shawn Guo, Linus Walleij, Jonas Aaberg, Linus Walleij, linux-kernel, Grant Likely, Lee Jones, linux-arm-kernel On Thursday, May 19, 2011 6:50 PM, Jamie Iles wrote: >> Jamie Iles (cc'ed) posted some patches that extended the basic_mmio_gpio >> driver so that it could be used as a library by other gpio drivers. >> >> Jamie, could you re-post that series to the linux-arm-kernel list for >> review? > > Grant has applied these patches but I've put them in a public branch if > that's OK rather than reposting: > > git://github.com/jamieiles/linux-2.6-ji.git gpio Thanks for the link. I just noticed something in commit fdcd80cb991dac7a70433be1e336726415762b6a "basic_mmio_gpio: split into a gpio library and platform device". > diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig > index d3b2953..2186d22 100644 > --- a/drivers/gpio/Kconfig > +++ b/drivers/gpio/Kconfig > @@ -70,8 +70,14 @@ config GPIO_MAX730X > > comment "Memory mapped GPIO expanders:" > > +config GPIO_BASIC_MMIO_CORE > + tristate > + help > + Provides core functionality for basic memory-mapped GPIO controllers. > + > config GPIO_BASIC_MMIO > tristate "Basic memory-mapped GPIO controllers support" > + select GPIO_BASIC_MMIO_CORE > help > Say yes here to support basic memory-mapped GPIO controllers. > > diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile > index becef59..aa9e97f 100644 > --- a/drivers/gpio/Makefile > +++ b/drivers/gpio/Makefile > @@ -10,6 +10,7 @@ obj-$(CONFIG_GPIOLIB) += gpiolib.o > > obj-$(CONFIG_GPIO_ADP5520) += adp5520-gpio.o > obj-$(CONFIG_GPIO_ADP5588) += adp5588-gpio.o > +obj-$(CONFIG_GPIO_BASIC_MMIO_CORE) += basic_mmio_gpio.o > obj-$(CONFIG_GPIO_BASIC_MMIO) += basic_mmio_gpio.o I think the line above should be removed. GPIO_BASIC_MMIO selects GPIO_BASIC_MMIO_CORE so the line you added previous to it will cause basic_mmio_gpio to be compiled. GPIO_BASIC_MMIO is really just used in the driver to enable the code at the end which creates the generic gbpio_driver. > obj-$(CONFIG_GPIO_LANGWELL) += langwell_gpio.o > obj-$(CONFIG_GPIO_MAX730X) += max730x.o Regards, Hartley ^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-05-20 22:07 ` H Hartley Sweeten 0 siblings, 0 replies; 57+ messages in thread From: H Hartley Sweeten @ 2011-05-20 22:07 UTC (permalink / raw) To: linux-arm-kernel On Thursday, May 19, 2011 6:50 PM, Jamie Iles wrote: >> Jamie Iles (cc'ed) posted some patches that extended the basic_mmio_gpio >> driver so that it could be used as a library by other gpio drivers. >> >> Jamie, could you re-post that series to the linux-arm-kernel list for >> review? > > Grant has applied these patches but I've put them in a public branch if > that's OK rather than reposting: > > git://github.com/jamieiles/linux-2.6-ji.git gpio Thanks for the link. I just noticed something in commit fdcd80cb991dac7a70433be1e336726415762b6a "basic_mmio_gpio: split into a gpio library and platform device". > diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig > index d3b2953..2186d22 100644 > --- a/drivers/gpio/Kconfig > +++ b/drivers/gpio/Kconfig > @@ -70,8 +70,14 @@ config GPIO_MAX730X > > comment "Memory mapped GPIO expanders:" > > +config GPIO_BASIC_MMIO_CORE > + tristate > + help > + Provides core functionality for basic memory-mapped GPIO controllers. > + > config GPIO_BASIC_MMIO > tristate "Basic memory-mapped GPIO controllers support" > + select GPIO_BASIC_MMIO_CORE > help > Say yes here to support basic memory-mapped GPIO controllers. > > diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile > index becef59..aa9e97f 100644 > --- a/drivers/gpio/Makefile > +++ b/drivers/gpio/Makefile > @@ -10,6 +10,7 @@ obj-$(CONFIG_GPIOLIB) += gpiolib.o > > obj-$(CONFIG_GPIO_ADP5520) += adp5520-gpio.o > obj-$(CONFIG_GPIO_ADP5588) += adp5588-gpio.o > +obj-$(CONFIG_GPIO_BASIC_MMIO_CORE) += basic_mmio_gpio.o > obj-$(CONFIG_GPIO_BASIC_MMIO) += basic_mmio_gpio.o I think the line above should be removed. GPIO_BASIC_MMIO selects GPIO_BASIC_MMIO_CORE so the line you added previous to it will cause basic_mmio_gpio to be compiled. GPIO_BASIC_MMIO is really just used in the driver to enable the code at the end which creates the generic gbpio_driver. > obj-$(CONFIG_GPIO_LANGWELL) += langwell_gpio.o > obj-$(CONFIG_GPIO_MAX730X) += max730x.o Regards, Hartley ^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio 2011-05-20 22:07 ` H Hartley Sweeten @ 2011-05-21 13:03 ` Jamie Iles -1 siblings, 0 replies; 57+ messages in thread From: Jamie Iles @ 2011-05-21 13:03 UTC (permalink / raw) To: H Hartley Sweeten Cc: Jamie Iles, Sascha Hauer, Shawn Guo, Linus Walleij, Jonas Aaberg, Linus Walleij, linux-kernel, Grant Likely, Lee Jones, linux-arm-kernel, Anton Vorontsov On Fri, May 20, 2011 at 05:07:12PM -0500, H Hartley Sweeten wrote: > On Thursday, May 19, 2011 6:50 PM, Jamie Iles wrote: > > diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile > > index becef59..aa9e97f 100644 > > --- a/drivers/gpio/Makefile > > +++ b/drivers/gpio/Makefile > > @@ -10,6 +10,7 @@ obj-$(CONFIG_GPIOLIB) += gpiolib.o > > > > obj-$(CONFIG_GPIO_ADP5520) += adp5520-gpio.o > > obj-$(CONFIG_GPIO_ADP5588) += adp5588-gpio.o > > +obj-$(CONFIG_GPIO_BASIC_MMIO_CORE) += basic_mmio_gpio.o > > obj-$(CONFIG_GPIO_BASIC_MMIO) += basic_mmio_gpio.o > > I think the line above should be removed. GPIO_BASIC_MMIO selects > GPIO_BASIC_MMIO_CORE so the line you added previous to it will cause > basic_mmio_gpio to be compiled. > > GPIO_BASIC_MMIO is really just used in the driver to enable the code > at the end which creates the generic gbpio_driver. Yes, well spotted. I'll create a patch to remove this. Jamie ^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-05-21 13:03 ` Jamie Iles 0 siblings, 0 replies; 57+ messages in thread From: Jamie Iles @ 2011-05-21 13:03 UTC (permalink / raw) To: linux-arm-kernel On Fri, May 20, 2011 at 05:07:12PM -0500, H Hartley Sweeten wrote: > On Thursday, May 19, 2011 6:50 PM, Jamie Iles wrote: > > diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile > > index becef59..aa9e97f 100644 > > --- a/drivers/gpio/Makefile > > +++ b/drivers/gpio/Makefile > > @@ -10,6 +10,7 @@ obj-$(CONFIG_GPIOLIB) += gpiolib.o > > > > obj-$(CONFIG_GPIO_ADP5520) += adp5520-gpio.o > > obj-$(CONFIG_GPIO_ADP5588) += adp5588-gpio.o > > +obj-$(CONFIG_GPIO_BASIC_MMIO_CORE) += basic_mmio_gpio.o > > obj-$(CONFIG_GPIO_BASIC_MMIO) += basic_mmio_gpio.o > > I think the line above should be removed. GPIO_BASIC_MMIO selects > GPIO_BASIC_MMIO_CORE so the line you added previous to it will cause > basic_mmio_gpio to be compiled. > > GPIO_BASIC_MMIO is really just used in the driver to enable the code > at the end which creates the generic gbpio_driver. Yes, well spotted. I'll create a patch to remove this. Jamie ^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio 2011-05-19 19:11 ` Sascha Hauer @ 2011-05-20 7:01 ` Grant Likely -1 siblings, 0 replies; 57+ messages in thread From: Grant Likely @ 2011-05-20 7:01 UTC (permalink / raw) To: Sascha Hauer Cc: Shawn Guo, Linus Walleij, Linus Walleij, Jonas Aaberg, linux-kernel, Lee Jones, linux-arm-kernel On Thu, May 19, 2011 at 09:11:56PM +0200, Sascha Hauer wrote: > On Thu, May 19, 2011 at 09:56:32PM +0800, Shawn Guo wrote: > > On Thu, May 19, 2011 at 02:21:27PM +0200, Linus Walleij wrote: > > > On Thu, May 19, 2011 at 10:56 AM, Shawn Guo <shawn.guo@freescale.com> wrote: > > > > > > > I start working on moving mxs gpio (arch/arm/mach-mxs/gpio.c) into > > > > driver/gpio, and I see the possibility to go a different approach > > > > from U300 one posted here. > > > > > > I've tried to figure out what relation the mail has to the U300 driver > > > but cannot find any, more than that it's moving a driver... Please > > > start a new mail thread. > > > > > I will post mxs-gpio driver once I get it done. Then please review > > the code and see the difference between mxs-gpio and u300-gpio, > > though these hardwares have something in common. > > I'm pretty sure they have something in common and even more that *all* > gpio drivers have something in common. I wonder if it really makes sense > to move the gpio driver to drivers/gpio without creating a common > mmio_gpio_chip beforehand. This can't be very hard. already done and queued for 2.6.39. It may not be in it's final form, and I'll possibly change the name, but take a look at the bgpio_chip patches that were circulated on the list, and will be in my gpio/next branch on git://git.secretlab.ca/git/linux-2.6 That said, I don't mind moving stuff into drivers/gpio first and consolidating it after. g. ^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-05-20 7:01 ` Grant Likely 0 siblings, 0 replies; 57+ messages in thread From: Grant Likely @ 2011-05-20 7:01 UTC (permalink / raw) To: linux-arm-kernel On Thu, May 19, 2011 at 09:11:56PM +0200, Sascha Hauer wrote: > On Thu, May 19, 2011 at 09:56:32PM +0800, Shawn Guo wrote: > > On Thu, May 19, 2011 at 02:21:27PM +0200, Linus Walleij wrote: > > > On Thu, May 19, 2011 at 10:56 AM, Shawn Guo <shawn.guo@freescale.com> wrote: > > > > > > > I start working on moving mxs gpio (arch/arm/mach-mxs/gpio.c) into > > > > driver/gpio, and I see the possibility to go a different approach > > > > from U300 one posted here. > > > > > > I've tried to figure out what relation the mail has to the U300 driver > > > but cannot find any, more than that it's moving a driver... Please > > > start a new mail thread. > > > > > I will post mxs-gpio driver once I get it done. Then please review > > the code and see the difference between mxs-gpio and u300-gpio, > > though these hardwares have something in common. > > I'm pretty sure they have something in common and even more that *all* > gpio drivers have something in common. I wonder if it really makes sense > to move the gpio driver to drivers/gpio without creating a common > mmio_gpio_chip beforehand. This can't be very hard. already done and queued for 2.6.39. It may not be in it's final form, and I'll possibly change the name, but take a look at the bgpio_chip patches that were circulated on the list, and will be in my gpio/next branch on git://git.secretlab.ca/git/linux-2.6 That said, I don't mind moving stuff into drivers/gpio first and consolidating it after. g. ^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio 2011-05-20 7:01 ` Grant Likely @ 2011-05-20 7:47 ` Linus Walleij -1 siblings, 0 replies; 57+ messages in thread From: Linus Walleij @ 2011-05-20 7:47 UTC (permalink / raw) To: Grant Likely Cc: Sascha Hauer, Jonas Aaberg, linux-kernel, linux-arm-kernel, Lee Jones, Shawn Guo 2011/5/20 Grant Likely <grant.likely@secretlab.ca>: > That said, I don't mind moving stuff into drivers/gpio first and > consolidating it after. Speaking of which, the topic of the post is not going to be merged since I did too much in this patch trying to solve all issues at once. I'll post something much simpler that just moves the U300 and Nomadik gpio over. Linus Walleij ^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-05-20 7:47 ` Linus Walleij 0 siblings, 0 replies; 57+ messages in thread From: Linus Walleij @ 2011-05-20 7:47 UTC (permalink / raw) To: linux-arm-kernel 2011/5/20 Grant Likely <grant.likely@secretlab.ca>: > That said, I don't mind moving stuff into drivers/gpio first and > consolidating it after. Speaking of which, the topic of the post is not going to be merged since I did too much in this patch trying to solve all issues at once. I'll post something much simpler that just moves the U300 and Nomadik gpio over. Linus Walleij ^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio 2011-04-27 13:13 ` Linus Walleij ` (2 preceding siblings ...) (?) @ 2011-05-19 11:11 ` Barry Song 2011-05-19 11:38 ` Barry Song -1 siblings, 1 reply; 57+ messages in thread From: Barry Song @ 2011-05-19 11:11 UTC (permalink / raw) To: Linus Walleij Cc: Grant Likely, linux-kernel, linux-arm-kernel, Linus Walleij, Lee Jones, Jonas Aaberg [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain; charset=UTF-8, Size: 84879 bytes --] 2011/4/27 Linus Walleij <linus.walleij@stericsson.com>: > From: Linus Walleij <linus.walleij@linaro.org> > > This rewrites the U300 GPIO driver using gpiolib and the irq_chip > abstractions, makes it runtime-configured rather than compile-time, > and moves it to the drivers/gpio subsystem where it belongs, > depopulating the ARM tree of one more driver. > > Cc: Jonas Aaberg <jonas.aberg@stericsson.com> > Acked-by: Arnd Bergmann <arnd@arndb.de> > Signed-off-by: Linus Walleij <linus.walleij@linaro.org> > --- >  arch/arm/Kconfig            |   2 +- >  arch/arm/mach-u300/Kconfig       |   1 + >  arch/arm/mach-u300/Makefile       |   6 +- >  arch/arm/mach-u300/core.c        |  31 ++- >  arch/arm/mach-u300/gpio.c        |  700 -------------------------- >  arch/arm/mach-u300/include/mach/gpio.h |  163 +------ >  arch/arm/mach-u300/include/mach/irqs.h |  25 +- >  drivers/gpio/Kconfig          |   9 + >  drivers/gpio/Makefile          |   1 + >  drivers/gpio/u300-gpio.c        |  836 ++++++++++++++++++++++++++++++++ >  include/linux/gpio/u300.h        |  32 ++ >  11 files changed, 932 insertions(+), 874 deletions(-) >  delete mode 100644 arch/arm/mach-u300/gpio.c >  create mode 100644 drivers/gpio/u300-gpio.c >  create mode 100644 include/linux/gpio/u300.h > > diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig > index 377a7a5..5fb980d 100644 > --- a/arch/arm/Kconfig > +++ b/arch/arm/Kconfig > @@ -820,7 +820,7 @@ config ARCH_U300 >     select ARM_VIC >     select GENERIC_CLOCKEVENTS >     select CLKDEV_LOOKUP > -    select GENERIC_GPIO > +    select ARCH_REQUIRE_GPIOLIB >     help >      Support for ST-Ericsson U300 series mobile platforms. > > diff --git a/arch/arm/mach-u300/Kconfig b/arch/arm/mach-u300/Kconfig > index 32a7b0f..7b5c229 100644 > --- a/arch/arm/mach-u300/Kconfig > +++ b/arch/arm/mach-u300/Kconfig > @@ -6,6 +6,7 @@ comment "ST-Ericsson Mobile Platform Products" > >  config MACH_U300 >     bool "U300" > +    select GPIO_U300 > >  comment "ST-Ericsson U300/U330/U335/U365 Feature Selections" > > diff --git a/arch/arm/mach-u300/Makefile b/arch/arm/mach-u300/Makefile > index fab46fe..73da230 100644 > --- a/arch/arm/mach-u300/Makefile > +++ b/arch/arm/mach-u300/Makefile > @@ -2,11 +2,7 @@ >  # Makefile for the linux kernel, U300 machine. >  # > > -obj-y      := core.o clock.o timer.o gpio.o padmux.o > -obj-m      := > -obj-n      := > -obj-      := > - > +obj-y              := core.o clock.o timer.o padmux.o >  obj-$(CONFIG_ARCH_U300)          += u300.o >  obj-$(CONFIG_MMC)         += mmc.o >  obj-$(CONFIG_SPI_PL022)      += spi.o > diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c > index 513d6ab..ddb604c 100644 > --- a/arch/arm/mach-u300/core.c > +++ b/arch/arm/mach-u300/core.c > @@ -25,6 +25,7 @@ >  #include <linux/err.h> >  #include <linux/mtd/nand.h> >  #include <linux/mtd/fsmc.h> > +#include <linux/gpio/u300.h> > >  #include <asm/types.h> >  #include <asm/setup.h> > @@ -239,7 +240,7 @@ static struct resource gpio_resources[] = { >         .end  = IRQ_U300_GPIO_PORT2, >         .flags = IORESOURCE_IRQ, >     }, > -#ifdef U300_COH901571_3 > +#if defined(CONFIG_MACH_U300_BS365) || defined(CONFIG_MACH_U300_BS335) >     { >         .name  = "gpio3", >         .start = IRQ_U300_GPIO_PORT3, > @@ -252,6 +253,7 @@ static struct resource gpio_resources[] = { >         .end  = IRQ_U300_GPIO_PORT4, >         .flags = IORESOURCE_IRQ, >     }, > +#endif >  #ifdef CONFIG_MACH_U300_BS335 >     { >         .name  = "gpio5", > @@ -266,7 +268,6 @@ static struct resource gpio_resources[] = { >         .flags = IORESOURCE_IRQ, >     }, >  #endif /* CONFIG_MACH_U300_BS335 */ > -#endif /* U300_COH901571_3 */ >  }; > >  static struct resource keypad_resources[] = { > @@ -1556,11 +1557,35 @@ static struct platform_device i2c1_device = { >     .resource = i2c1_resources, >  }; > > +/* > + * The different variants have a few different versions of the > + * GPIO block, with different number of ports. > + */ > +static struct u300_gpio_platform u300_gpio_plat = { > +#if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330) > +    .variant = U300_GPIO_COH901335, > +    .ports = 3, > +#endif > +#ifdef CONFIG_MACH_U300_BS335 > +    .variant = U300_GPIO_COH901571_3_BS335, > +    .ports = 7, > +#endif > +#ifdef CONFIG_MACH_U300_BS365 > +    .variant = U300_GPIO_COH901571_3_BS365, > +    .ports = 5, > +#endif > +    .gpio_base = 0, > +    .gpio_irq_base = IRQ_U300_GPIO_BASE, > +}; > + >  static struct platform_device gpio_device = { >     .name = "u300-gpio", >     .id = -1, >     .num_resources = ARRAY_SIZE(gpio_resources), >     .resource = gpio_resources, > +    .dev = { > +        .platform_data = &u300_gpio_plat, > +    }, >  }; > >  static struct platform_device keypad_device = { > @@ -1666,7 +1691,7 @@ void __init u300_init_irq(void) >     BUG_ON(IS_ERR(clk)); >     clk_enable(clk); > > -    for (i = 0; i < NR_IRQS; i++) > +    for (i = 0; i < U300_VIC_IRQS_END; i++) >         set_bit(i, (unsigned long *) &mask[0]); >     vic_init((void __iomem *) U300_INTCON0_VBASE, 0, mask[0], mask[0]); >     vic_init((void __iomem *) U300_INTCON1_VBASE, 32, mask[1], mask[1]); > diff --git a/arch/arm/mach-u300/gpio.c b/arch/arm/mach-u300/gpio.c > deleted file mode 100644 > index d927901..0000000 > --- a/arch/arm/mach-u300/gpio.c > +++ /dev/null > @@ -1,700 +0,0 @@ > -/* > - * > - * arch/arm/mach-u300/gpio.c > - * > - * > - * Copyright (C) 2007-2009 ST-Ericsson AB > - * License terms: GNU General Public License (GPL) version 2 > - * U300 GPIO module. > - * This can driver either of the two basic GPIO cores > - * available in the U300 platforms: > - * COH 901 335  - Used in DB3150 (U300 1.0) and DB3200 (U330 1.0) > - * COH 901 571/3 - Used in DB3210 (U365 2.0) and DB3350 (U335 1.0) > - * Notice that you also have inline macros in <asm-arch/gpio.h> > - * Author: Linus Walleij <linus.walleij@stericsson.com> > - * Author: Jonas Aaberg <jonas.aberg@stericsson.com> > - * > - */ > -#include <linux/module.h> > -#include <linux/interrupt.h> > -#include <linux/delay.h> > -#include <linux/errno.h> > -#include <linux/io.h> > -#include <linux/clk.h> > -#include <linux/err.h> > -#include <linux/platform_device.h> > -#include <linux/gpio.h> > - > -/* Reference to GPIO block clock */ > -static struct clk *clk; > - > -/* Memory resource */ > -static struct resource *memres; > -static void __iomem *virtbase; > -static struct device *gpiodev; > - > -struct u300_gpio_port { > -    const char *name; > -    int irq; > -    int number; > -}; > - > - > -static struct u300_gpio_port gpio_ports[] = { > -    { > -        .name = "gpio0", > -        .number = 0, > -    }, > -    { > -        .name = "gpio1", > -        .number = 1, > -    }, > -    { > -        .name = "gpio2", > -        .number = 2, > -    }, > -#ifdef U300_COH901571_3 > -    { > -        .name = "gpio3", > -        .number = 3, > -    }, > -    { > -        .name = "gpio4", > -        .number = 4, > -    }, > -#ifdef CONFIG_MACH_U300_BS335 > -    { > -        .name = "gpio5", > -        .number = 5, > -    }, > -    { > -        .name = "gpio6", > -        .number = 6, > -    }, > -#endif > -#endif > - > -}; > - > - > -#ifdef U300_COH901571_3 > - > -/* Default input value */ > -#define DEFAULT_OUTPUT_LOW  0 > -#define DEFAULT_OUTPUT_HIGH  1 > - > -/* GPIO Pull-Up status */ > -#define DISABLE_PULL_UP  0 > -#define ENABLE_PULL_UP  1 > - > -#define GPIO_NOT_USED 0 > -#define GPIO_IN    1 > -#define GPIO_OUT    2 > - > -struct u300_gpio_configuration_data { > -    unsigned char pin_usage; > -    unsigned char default_output_value; > -    unsigned char pull_up; > -}; > - > -/* Initial configuration */ > -const struct u300_gpio_configuration_data > -u300_gpio_config[U300_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = { > -#ifdef CONFIG_MACH_U300_BS335 > -    /* Port 0, pins 0-7 */ > -    { > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_OUT, DEFAULT_OUTPUT_HIGH,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_OUT, DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_OUT, DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_OUT, DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_OUT, DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_OUT, DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP} > -    }, > -    /* Port 1, pins 0-7 */ > -    { > -        {GPIO_OUT, DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_OUT, DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_OUT, DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,   ENABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_OUT, DEFAULT_OUTPUT_HIGH,  DISABLE_PULL_UP}, > -        {GPIO_OUT, DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_OUT, DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP} > -    }, > -    /* Port 2, pins 0-7 */ > -    { > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_OUT, DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,   ENABLE_PULL_UP}, > -        {GPIO_OUT, DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,   ENABLE_PULL_UP} > -    }, > -    /* Port 3, pins 0-7 */ > -    { > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,   ENABLE_PULL_UP}, > -        {GPIO_OUT, DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP} > -    }, > -    /* Port 4, pins 0-7 */ > -    { > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP} > -    }, > -    /* Port 5, pins 0-7 */ > -    { > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP} > -    }, > -    /* Port 6, pind 0-7 */ > -    { > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP} > -    } > -#endif > - > -#ifdef CONFIG_MACH_U300_BS365 > -    /* Port 0, pins 0-7 */ > -    { > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_OUT, DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_OUT, DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_OUT, DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_OUT, DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,   ENABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP} > -    }, > -    /* Port 1, pins 0-7 */ > -    { > -        {GPIO_OUT, DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_OUT, DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_OUT, DEFAULT_OUTPUT_HIGH,  DISABLE_PULL_UP}, > -        {GPIO_OUT, DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_OUT, DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP} > -    }, > -    /* Port 2, pins 0-7 */ > -    { > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,   ENABLE_PULL_UP}, > -        {GPIO_OUT, DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_OUT, DEFAULT_OUTPUT_LOW,  DISABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,   ENABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,   ENABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,   ENABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,   ENABLE_PULL_UP} > -    }, > -    /* Port 3, pins 0-7 */ > -    { > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,   ENABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,   ENABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,   ENABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,   ENABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,   ENABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,   ENABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,   ENABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,   ENABLE_PULL_UP} > -    }, > -    /* Port 4, pins 0-7 */ > -    { > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,   ENABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,   ENABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,   ENABLE_PULL_UP}, > -        {GPIO_IN,  DEFAULT_OUTPUT_LOW,   ENABLE_PULL_UP}, > -        /* These 4 pins doesn't exist on DB3210 */ > -        {GPIO_OUT, DEFAULT_OUTPUT_LOW,   ENABLE_PULL_UP}, > -        {GPIO_OUT, DEFAULT_OUTPUT_LOW,   ENABLE_PULL_UP}, > -        {GPIO_OUT, DEFAULT_OUTPUT_LOW,   ENABLE_PULL_UP}, > -        {GPIO_OUT, DEFAULT_OUTPUT_LOW,   ENABLE_PULL_UP} > -    } > -#endif > -}; > -#endif > - > - > -/* No users == we can power down GPIO */ > -static int gpio_users; > - > -struct gpio_struct { > -    int (*callback)(void *); > -    void *data; > -    int users; > -}; > - > -static struct gpio_struct gpio_pin[U300_GPIO_MAX]; > - > -/* > - * Let drivers register callback in order to get notified when there is > - * an interrupt on the gpio pin > - */ > -int gpio_register_callback(unsigned gpio, int (*func)(void *arg), void *data) > -{ > -    if (gpio_pin[gpio].callback) > -        dev_warn(gpiodev, "%s: WARNING: callback already " > -             "registered for gpio pin#%d\n", __func__, gpio); > -    gpio_pin[gpio].callback = func; > -    gpio_pin[gpio].data = data; > - > -    return 0; > -} > -EXPORT_SYMBOL(gpio_register_callback); > - > -int gpio_unregister_callback(unsigned gpio) > -{ > -    if (!gpio_pin[gpio].callback) > -        dev_warn(gpiodev, "%s: WARNING: callback already " > -             "unregistered for gpio pin#%d\n", __func__, gpio); > -    gpio_pin[gpio].callback = NULL; > -    gpio_pin[gpio].data = NULL; > - > -    return 0; > -} > -EXPORT_SYMBOL(gpio_unregister_callback); > - > -/* Non-zero means valid */ > -int gpio_is_valid(int number) > -{ > -    if (number >= 0 && > -      number < (U300_GPIO_NUM_PORTS * U300_GPIO_PINS_PER_PORT)) > -        return 1; > -    return 0; > -} > -EXPORT_SYMBOL(gpio_is_valid); > - > -int gpio_request(unsigned gpio, const char *label) > -{ > -    if (gpio_pin[gpio].users) > -        return -EINVAL; > -    else > -        gpio_pin[gpio].users++; > - > -    gpio_users++; > - > -    return 0; > -} > -EXPORT_SYMBOL(gpio_request); > - > -void gpio_free(unsigned gpio) > -{ > -    gpio_users--; > -    gpio_pin[gpio].users--; > -    if (unlikely(gpio_pin[gpio].users < 0)) { > -        dev_warn(gpiodev, "warning: gpio#%d release mismatch\n", > -             gpio); > -        gpio_pin[gpio].users = 0; > -    } > - > -    return; > -} > -EXPORT_SYMBOL(gpio_free); > - > -/* This returns zero or nonzero */ > -int gpio_get_value(unsigned gpio) > -{ > -    return readl(virtbase + U300_GPIO_PXPDIR + > -     PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING) & (1 << (gpio & 0x07)); > -} > -EXPORT_SYMBOL(gpio_get_value); > - > -/* > - * We hope that the compiler will optimize away the unused branch > - * in case "value" is a constant > - */ > -void gpio_set_value(unsigned gpio, int value) > -{ > -    u32 val; > -    unsigned long flags; > - > -    local_irq_save(flags); > -    if (value) { > -        /* set */ > -        val = readl(virtbase + U300_GPIO_PXPDOR + > -         PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING) > -         & (1 << (gpio & 0x07)); > -        writel(val | (1 << (gpio & 0x07)), virtbase + > -         U300_GPIO_PXPDOR + > -         PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING); > -    } else { > -        /* clear */ > -        val = readl(virtbase + U300_GPIO_PXPDOR + > -         PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING) > -         & (1 << (gpio & 0x07)); > -        writel(val & ~(1 << (gpio & 0x07)), virtbase + > -         U300_GPIO_PXPDOR + > -         PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING); > -    } > -    local_irq_restore(flags); > -} > -EXPORT_SYMBOL(gpio_set_value); > - > -int gpio_direction_input(unsigned gpio) > -{ > -    unsigned long flags; > -    u32 val; > - > -    if (gpio > U300_GPIO_MAX) > -        return -EINVAL; > - > -    local_irq_save(flags); > -    val = readl(virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) * > -                U300_GPIO_PORTX_SPACING); > -    /* Mask out this pin*/ > -    val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << ((gpio & 0x07) << 1)); > -    /* This is not needed since it sets the bits to zero.*/ > -    /* val |= (U300_GPIO_PXPCR_PIN_MODE_INPUT << (gpio*2)); */ > -    writel(val, virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) * > -                U300_GPIO_PORTX_SPACING); > -    local_irq_restore(flags); > -    return 0; > -} > -EXPORT_SYMBOL(gpio_direction_input); > - > -int gpio_direction_output(unsigned gpio, int value) > -{ > -    unsigned long flags; > -    u32 val; > - > -    if (gpio > U300_GPIO_MAX) > -        return -EINVAL; > - > -    local_irq_save(flags); > -    val = readl(virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) * > -                U300_GPIO_PORTX_SPACING); > -    /* Mask out this pin */ > -    val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << ((gpio & 0x07) << 1)); > -    /* > -     * FIXME: configure for push/pull, open drain or open source per pin > -     * in setup. The current driver will only support push/pull. > -     */ > -    val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL > -            << ((gpio & 0x07) << 1)); > -    writel(val, virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) * > -                U300_GPIO_PORTX_SPACING); > -    gpio_set_value(gpio, value); > -    local_irq_restore(flags); > -    return 0; > -} > -EXPORT_SYMBOL(gpio_direction_output); > - > -/* > - * Enable an IRQ, edge is rising edge (!= 0) or falling edge (==0). > - */ > -void enable_irq_on_gpio_pin(unsigned gpio, int edge) > -{ > -    u32 val; > -    unsigned long flags; > -    local_irq_save(flags); > - > -    val = readl(virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) * > -                U300_GPIO_PORTX_SPACING); > -    val |= (1 << (gpio & 0x07)); > -    writel(val, virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) * > -                U300_GPIO_PORTX_SPACING); > -    val = readl(virtbase + U300_GPIO_PXICR + PIN_TO_PORT(gpio) * > -                U300_GPIO_PORTX_SPACING); > -    if (edge) > -        val |= (1 << (gpio & 0x07)); > -    else > -        val &= ~(1 << (gpio & 0x07)); > -    writel(val, virtbase + U300_GPIO_PXICR + PIN_TO_PORT(gpio) * > -                U300_GPIO_PORTX_SPACING); > -    local_irq_restore(flags); > -} > -EXPORT_SYMBOL(enable_irq_on_gpio_pin); > - > -void disable_irq_on_gpio_pin(unsigned gpio) > -{ > -    u32 val; > -    unsigned long flags; > - > -    local_irq_save(flags); > -    val = readl(virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) * > -                U300_GPIO_PORTX_SPACING); > -    val &= ~(1 << (gpio & 0x07)); > -    writel(val, virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) * > -                U300_GPIO_PORTX_SPACING); > -    local_irq_restore(flags); > -} > -EXPORT_SYMBOL(disable_irq_on_gpio_pin); > - > -/* Enable (value == 0) or disable (value == 1) internal pullup */ > -void gpio_pullup(unsigned gpio, int value) > -{ > -    u32 val; > -    unsigned long flags; > - > -    local_irq_save(flags); > -    if (value) { > -        val = readl(virtbase + U300_GPIO_PXPER + PIN_TO_PORT(gpio) * > -                    U300_GPIO_PORTX_SPACING); > -        writel(val | (1 << (gpio & 0x07)), virtbase + U300_GPIO_PXPER + > -                PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING); > -    } else { > -        val = readl(virtbase + U300_GPIO_PXPER + PIN_TO_PORT(gpio) * > -                    U300_GPIO_PORTX_SPACING); > -        writel(val & ~(1 << (gpio & 0x07)), virtbase + U300_GPIO_PXPER + > -                PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING); > -    } > -    local_irq_restore(flags); > -} > -EXPORT_SYMBOL(gpio_pullup); > - > -static irqreturn_t gpio_irq_handler(int irq, void *dev_id) > -{ > -    struct u300_gpio_port *port = dev_id; > -    u32 val; > -    int pin; > - > -    /* Read event register */ > -    val = readl(virtbase + U300_GPIO_PXIEV + port->number * > -                U300_GPIO_PORTX_SPACING); > -    /* Mask with enable register */ > -    val &= readl(virtbase + U300_GPIO_PXIEV + port->number * > -                U300_GPIO_PORTX_SPACING); > -    /* Mask relevant bits */ > -    val &= U300_GPIO_PXIEV_ALL_IRQ_EVENT_MASK; > -    /* ACK IRQ (clear event) */ > -    writel(val, virtbase + U300_GPIO_PXIEV + port->number * > -                U300_GPIO_PORTX_SPACING); > -    /* Print message */ > -    while (val != 0) { > -        unsigned gpio; > - > -        pin = __ffs(val); > -        /* mask off this pin */ > -        val &= ~(1 << pin); > -        gpio = (port->number << 3) + pin; > - > -        if (gpio_pin[gpio].callback) > -            (void)gpio_pin[gpio].callback(gpio_pin[gpio].data); > -        else > -            dev_dbg(gpiodev, "stray GPIO IRQ on line %d\n", > -                gpio); > -    } > -    return IRQ_HANDLED; > -} > - > -static void gpio_set_initial_values(void) > -{ > -#ifdef U300_COH901571_3 > -    int i, j; > -    unsigned long flags; > -    u32 val; > - > -    /* Write default values to all pins */ > -    for (i = 0; i < U300_GPIO_NUM_PORTS; i++) { > -        val = 0; > -        for (j = 0; j < 8; j++) > -            val |= (u32) (u300_gpio_config[i][j].default_output_value != DEFAULT_OUTPUT_LOW) << j; > -        local_irq_save(flags); > -        writel(val, virtbase + U300_GPIO_PXPDOR + i * U300_GPIO_PORTX_SPACING); > -        local_irq_restore(flags); > -    } > - > -    /* > -     * Put all pins that are set to either 'GPIO_OUT' or 'GPIO_NOT_USED' > -     * to output and 'GPIO_IN' to input for each port. And initialize > -     * default value on outputs. > -     */ > -    for (i = 0; i < U300_GPIO_NUM_PORTS; i++) { > -        for (j = 0; j < U300_GPIO_PINS_PER_PORT; j++) { > -            local_irq_save(flags); > -            val = readl(virtbase + U300_GPIO_PXPCR + > -                     i * U300_GPIO_PORTX_SPACING); > -            /* Mask out this pin */ > -            val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << (j << 1)); > - > -            if (u300_gpio_config[i][j].pin_usage != GPIO_IN) > -                val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL << (j << 1)); > -            writel(val, virtbase + U300_GPIO_PXPCR + > -                     i * U300_GPIO_PORTX_SPACING); > -            local_irq_restore(flags); > -        } > -    } > - > -    /* Enable or disable the internal pull-ups in the GPIO ASIC block */ > -    for (i = 0; i < U300_GPIO_MAX; i++) { > -        val = 0; > -        for (j = 0; j < 8; j++) > -            val |= (u32)((u300_gpio_config[i][j].pull_up == DISABLE_PULL_UP) << j); > -        local_irq_save(flags); > -        writel(val, virtbase + U300_GPIO_PXPER + i * U300_GPIO_PORTX_SPACING); > -        local_irq_restore(flags); > -    } > -#endif > -} > - > -static int __init gpio_probe(struct platform_device *pdev) > -{ > -    u32 val; > -    int err = 0; > -    int i; > -    int num_irqs; > - > -    gpiodev = &pdev->dev; > -    memset(gpio_pin, 0, sizeof(gpio_pin)); > - > -    /* Get GPIO clock */ > -    clk = clk_get(&pdev->dev, NULL); > -    if (IS_ERR(clk)) { > -        err = PTR_ERR(clk); > -        dev_err(gpiodev, "could not get GPIO clock\n"); > -        goto err_no_clk; > -    } > -    err = clk_enable(clk); > -    if (err) { > -        dev_err(gpiodev, "could not enable GPIO clock\n"); > -        goto err_no_clk_enable; > -    } > - > -    memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); > -    if (!memres) > -        goto err_no_resource; > - > -    if (request_mem_region(memres->start, memres->end - memres->start, "GPIO Controller") > -      == NULL) { > -        err = -ENODEV; > -        goto err_no_ioregion; > -    } > - > -    virtbase = ioremap(memres->start, resource_size(memres)); > -    if (!virtbase) { > -        err = -ENOMEM; > -        goto err_no_ioremap; > -    } > -    dev_info(gpiodev, "remapped 0x%08x to %p\n", > -         memres->start, virtbase); > - > -#ifdef U300_COH901335 > -    dev_info(gpiodev, "initializing GPIO Controller COH 901 335\n"); > -    /* Turn on the GPIO block */ > -    writel(U300_GPIO_CR_BLOCK_CLOCK_ENABLE, virtbase + U300_GPIO_CR); > -#endif > - > -#ifdef U300_COH901571_3 > -    dev_info(gpiodev, "initializing GPIO Controller COH 901 571/3\n"); > -    val = readl(virtbase + U300_GPIO_CR); > -    dev_info(gpiodev, "COH901571/3 block version: %d, " \ > -        "number of cores: %d\n", > -        ((val & 0x0000FE00) >> 9), > -        ((val & 0x000001FC) >> 2)); > -    writel(U300_GPIO_CR_BLOCK_CLKRQ_ENABLE, virtbase + U300_GPIO_CR); > -#endif > - > -    gpio_set_initial_values(); > - > -    for (num_irqs = 0 ; num_irqs < U300_GPIO_NUM_PORTS; num_irqs++) { > - > -        gpio_ports[num_irqs].irq = > -            platform_get_irq_byname(pdev, > -                        gpio_ports[num_irqs].name); > - > -        err = request_irq(gpio_ports[num_irqs].irq, > -                 gpio_irq_handler, IRQF_DISABLED, > -                 gpio_ports[num_irqs].name, > -                 &gpio_ports[num_irqs]); > -        if (err) { > -            dev_err(gpiodev, "cannot allocate IRQ for %s!\n", > -                gpio_ports[num_irqs].name); > -            goto err_no_irq; > -        } > -        /* Turns off PortX_irq_force */ > -        writel(0x0, virtbase + U300_GPIO_PXIFR + > -                 num_irqs * U300_GPIO_PORTX_SPACING); > -    } > - > -    return 0; > - > - err_no_irq: > -    for (i = 0; i < num_irqs; i++) > -        free_irq(gpio_ports[i].irq, &gpio_ports[i]); > -    iounmap(virtbase); > - err_no_ioremap: > -    release_mem_region(memres->start, memres->end - memres->start); > - err_no_ioregion: > - err_no_resource: > -    clk_disable(clk); > - err_no_clk_enable: > -    clk_put(clk); > - err_no_clk: > -    dev_info(gpiodev, "module ERROR:%d\n", err); > -    return err; > -} > - > -static int __exit gpio_remove(struct platform_device *pdev) > -{ > -    int i; > - > -    /* Turn off the GPIO block */ > -    writel(0x00000000U, virtbase + U300_GPIO_CR); > -    for (i = 0 ; i < U300_GPIO_NUM_PORTS; i++) > -        free_irq(gpio_ports[i].irq, &gpio_ports[i]); > -    iounmap(virtbase); > -    release_mem_region(memres->start, memres->end - memres->start); > -    clk_disable(clk); > -    clk_put(clk); > -    return 0; > -} > - > -static struct platform_driver gpio_driver = { > -    .driver     = { > -        .name  = "u300-gpio", > -    }, > -    .remove     = __exit_p(gpio_remove), > -}; > - > - > -static int __init u300_gpio_init(void) > -{ > -    return platform_driver_probe(&gpio_driver, gpio_probe); > -} > - > -static void __exit u300_gpio_exit(void) > -{ > -    platform_driver_unregister(&gpio_driver); > -} > - > -arch_initcall(u300_gpio_init); > -module_exit(u300_gpio_exit); looks like the driver can't be a real module, is the module_exit suitable? > - > -MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>"); > - > -#ifdef U300_COH901571_3 > -MODULE_DESCRIPTION("ST-Ericsson AB COH 901 571/3 GPIO driver"); > -#endif > - > -#ifdef U300_COH901335 > -MODULE_DESCRIPTION("ST-Ericsson AB COH 901 335 GPIO driver"); > -#endif > - > -MODULE_LICENSE("GPL"); > diff --git a/arch/arm/mach-u300/include/mach/gpio.h b/arch/arm/mach-u300/include/mach/gpio.h > index d5a71ab..6fc3205 100644 > --- a/arch/arm/mach-u300/include/mach/gpio.h > +++ b/arch/arm/mach-u300/include/mach/gpio.h > @@ -17,127 +17,13 @@ >  #include <linux/io.h> >  #include <mach/hardware.h> >  #include <asm/irq.h> > +#include <asm-generic/gpio.h> > > -/* Switch type depending on platform/chip variant */ > -#if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330) > -#define U300_COH901335 > -#endif > -#if defined(CONFIG_MACH_U300_BS365) || defined(CONFIG_MACH_U300_BS335) > -#define U300_COH901571_3 > -#endif > - > -/* Get base address for regs here */ > -#include "u300-regs.h" > -/* IRQ numbers */ > -#include "irqs.h" > - > -/* > - * This is the GPIO block definitions. GPIO (General Purpose I/O) can be > - * used for anything, and often is. The event/enable etc figures are for > - * the lowermost pin (pin 0 on each port), shift this left to match your > - * pin if you're gonna use these values. > - */ > -#ifdef U300_COH901335 > -#define U300_GPIO_PORTX_SPACING                 (0x1C) > -/* Port X Pin Data Register 32bit, this is both input and output (R/W) */ > -#define U300_GPIO_PXPDIR                (0x00) > -#define U300_GPIO_PXPDOR                (0x00) > -/* Port X Pin Config Register 32bit (R/W) */ > -#define U300_GPIO_PXPCR                     (0x04) > -#define U300_GPIO_PXPCR_ALL_PINS_MODE_MASK       (0x0000FFFFUL) > -#define U300_GPIO_PXPCR_PIN_MODE_MASK          (0x00000003UL) > -#define U300_GPIO_PXPCR_PIN_MODE_SHIFT         (0x00000002UL) > -#define U300_GPIO_PXPCR_PIN_MODE_INPUT         (0x00000000UL) > -#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL    (0x00000001UL) > -#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_DRAIN   (0x00000002UL) > -#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_SOURCE   (0x00000003UL) > -/* Port X Interrupt Event Register 32bit (R/W) */ > -#define U300_GPIO_PXIEV                     (0x08) > -#define U300_GPIO_PXIEV_ALL_IRQ_EVENT_MASK       (0x000000FFUL) > -#define U300_GPIO_PXIEV_IRQ_EVENT            (0x00000001UL) > -/* Port X Interrupt Enable Register 32bit (R/W) */ > -#define U300_GPIO_PXIEN                     (0x0C) > -#define U300_GPIO_PXIEN_ALL_IRQ_ENABLE_MASK       (0x000000FFUL) > -#define U300_GPIO_PXIEN_IRQ_ENABLE           (0x00000001UL) > -/* Port X Interrupt Force Register 32bit (R/W) */ > -#define U300_GPIO_PXIFR                     (0x10) > -#define U300_GPIO_PXIFR_ALL_IRQ_FORCE_MASK       (0x000000FFUL) > -#define U300_GPIO_PXIFR_IRQ_FORCE            (0x00000001UL) > -/* Port X Interrupt Config Register 32bit (R/W) */ > -#define U300_GPIO_PXICR                     (0x14) > -#define U300_GPIO_PXICR_ALL_IRQ_CONFIG_MASK       (0x000000FFUL) > -#define U300_GPIO_PXICR_IRQ_CONFIG_MASK             (0x00000001UL) > -#define U300_GPIO_PXICR_IRQ_CONFIG_FALLING_EDGE         (0x00000000UL) > -#define U300_GPIO_PXICR_IRQ_CONFIG_RISING_EDGE     (0x00000001UL) > -/* Port X Pull-up Enable Register 32bit (R/W) */ > -#define U300_GPIO_PXPER                     (0x18) > -#define U300_GPIO_PXPER_ALL_PULL_UP_DISABLE_MASK    (0x000000FFUL) > -#define U300_GPIO_PXPER_PULL_UP_DISABLE             (0x00000001UL) > -/* Control Register 32bit (R/W) */ > -#define U300_GPIO_CR                  (0x54) > -#define U300_GPIO_CR_BLOCK_CLOCK_ENABLE             (0x00000001UL) > -/* three ports of 8 bits each = GPIO pins 0..23 */ > -#define U300_GPIO_NUM_PORTS 3 > -#define U300_GPIO_PINS_PER_PORT 8 > -#define U300_GPIO_MAX  (U300_GPIO_PINS_PER_PORT * U300_GPIO_NUM_PORTS - 1) > -#endif > - > -#ifdef U300_COH901571_3 > -/* > - * Control Register 32bit (R/W) > - * bit 15-9 (mask 0x0000FE00) contains the number of cores. 8*cores > - * gives the number of GPIO pins. > - * bit 8-2  (mask 0x000001FC) contains the core version ID. > - */ > -#define U300_GPIO_CR                  (0x00) > -#define U300_GPIO_CR_SYNC_SEL_ENABLE          (0x00000002UL) > -#define U300_GPIO_CR_BLOCK_CLKRQ_ENABLE             (0x00000001UL) > -#define U300_GPIO_PORTX_SPACING                 (0x30) > -/* Port X Pin Data INPUT Register 32bit (R/W) */ > -#define U300_GPIO_PXPDIR                (0x04) > -/* Port X Pin Data OUTPUT Register 32bit (R/W) */ > -#define U300_GPIO_PXPDOR                (0x08) > -/* Port X Pin Config Register 32bit (R/W) */ > -#define U300_GPIO_PXPCR                     (0x0C) > -#define U300_GPIO_PXPCR_ALL_PINS_MODE_MASK       (0x0000FFFFUL) > -#define U300_GPIO_PXPCR_PIN_MODE_MASK          (0x00000003UL) > -#define U300_GPIO_PXPCR_PIN_MODE_SHIFT         (0x00000002UL) > -#define U300_GPIO_PXPCR_PIN_MODE_INPUT         (0x00000000UL) > -#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL    (0x00000001UL) > -#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_DRAIN   (0x00000002UL) > -#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_SOURCE   (0x00000003UL) > -/* Port X Pull-up Enable Register 32bit (R/W) */ > -#define U300_GPIO_PXPER                     (0x10) > -#define U300_GPIO_PXPER_ALL_PULL_UP_DISABLE_MASK    (0x000000FFUL) > -#define U300_GPIO_PXPER_PULL_UP_DISABLE             (0x00000001UL) > -/* Port X Interrupt Event Register 32bit (R/W) */ > -#define U300_GPIO_PXIEV                     (0x14) > -#define U300_GPIO_PXIEV_ALL_IRQ_EVENT_MASK       (0x000000FFUL) > -#define U300_GPIO_PXIEV_IRQ_EVENT            (0x00000001UL) > -/* Port X Interrupt Enable Register 32bit (R/W) */ > -#define U300_GPIO_PXIEN                     (0x18) > -#define U300_GPIO_PXIEN_ALL_IRQ_ENABLE_MASK       (0x000000FFUL) > -#define U300_GPIO_PXIEN_IRQ_ENABLE           (0x00000001UL) > -/* Port X Interrupt Force Register 32bit (R/W) */ > -#define U300_GPIO_PXIFR                     (0x1C) > -#define U300_GPIO_PXIFR_ALL_IRQ_FORCE_MASK       (0x000000FFUL) > -#define U300_GPIO_PXIFR_IRQ_FORCE            (0x00000001UL) > -/* Port X Interrupt Config Register 32bit (R/W) */ > -#define U300_GPIO_PXICR                     (0x20) > -#define U300_GPIO_PXICR_ALL_IRQ_CONFIG_MASK       (0x000000FFUL) > -#define U300_GPIO_PXICR_IRQ_CONFIG_MASK             (0x00000001UL) > -#define U300_GPIO_PXICR_IRQ_CONFIG_FALLING_EDGE         (0x00000000UL) > -#define U300_GPIO_PXICR_IRQ_CONFIG_RISING_EDGE     (0x00000001UL) > -#ifdef CONFIG_MACH_U300_BS335 > -/* seven ports of 8 bits each = GPIO pins 0..55 */ > -#define U300_GPIO_NUM_PORTS 7 > -#else > -/* five ports of 8 bits each = GPIO pins 0..39 */ > -#define U300_GPIO_NUM_PORTS 5 > -#endif > -#define U300_GPIO_PINS_PER_PORT 8 > -#define U300_GPIO_MAX (U300_GPIO_PINS_PER_PORT * U300_GPIO_NUM_PORTS - 1) > -#endif > +/* Map these overrides to gpiolib functions, simply */ > +#define gpio_get_value  __gpio_get_value > +#define gpio_set_value  __gpio_set_value > +#define gpio_cansleep  __gpio_cansleep > +#define gpio_to_irq   __gpio_to_irq > >  /* >  * Individual pin assignments for the B26/S26. Notice that the > @@ -254,41 +140,4 @@ > >  #endif > > -/* translates a pin number to a port number */ > -#define PIN_TO_PORT(val) (val >> 3) > - > -/* These can be found in arch/arm/mach-u300/gpio.c */ > -extern int gpio_is_valid(int number); > -extern int gpio_request(unsigned gpio, const char *label); > -extern void gpio_free(unsigned gpio); > -extern int gpio_direction_input(unsigned gpio); > -extern int gpio_direction_output(unsigned gpio, int value); > -extern int gpio_register_callback(unsigned gpio, > -                 int (*func)(void *arg), > -                 void *); > -extern int gpio_unregister_callback(unsigned gpio); > -extern void enable_irq_on_gpio_pin(unsigned gpio, int edge); > -extern void disable_irq_on_gpio_pin(unsigned gpio); > -extern void gpio_pullup(unsigned gpio, int value); > -extern int gpio_get_value(unsigned gpio); > -extern void gpio_set_value(unsigned gpio, int value); > - > -#define gpio_get_value_cansleep gpio_get_value > -#define gpio_set_value_cansleep gpio_set_value > - > -/* wrappers to sleep-enable the previous two functions */ > -static inline unsigned gpio_to_irq(unsigned gpio) > -{ > -    return PIN_TO_PORT(gpio) + IRQ_U300_GPIO_PORT0; > -} > - > -static inline unsigned irq_to_gpio(unsigned irq) > -{ > -    /* > -     * FIXME: This is no 1-1 mapping at all, it points to the > -     * whole block of 8 pins. > -     */ > -    return (irq - IRQ_U300_GPIO_PORT0) << 3; > -} > - >  #endif > diff --git a/arch/arm/mach-u300/include/mach/irqs.h b/arch/arm/mach-u300/include/mach/irqs.h > index 09b1b28..d270fea 100644 > --- a/arch/arm/mach-u300/include/mach/irqs.h > +++ b/arch/arm/mach-u300/include/mach/irqs.h > @@ -72,7 +72,7 @@ > >  /* DB3150 and DB3200 have only 45 IRQs */ >  #if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330) > -#define U300_NR_IRQS          45 > +#define U300_VIC_IRQS_END        45 >  #endif > >  /* The DB3350-specific interrupt lines */ > @@ -88,7 +88,7 @@ >  #define IRQ_U300_GPIO_PORT4       53 >  #define IRQ_U300_GPIO_PORT5       54 >  #define IRQ_U300_GPIO_PORT6       55 > -#define U300_NR_IRQS          56 > +#define U300_VIC_IRQS_END        56 >  #endif > >  /* The DB3210-specific interrupt lines */ > @@ -106,16 +106,25 @@ >  #define IRQ_U300_NFIF          45 >  #define IRQ_U300_NFIF2         46 >  #define IRQ_U300_SYSCON_PLL_LOCK    47 > -#define U300_NR_IRQS          48 > +#define U300_VIC_IRQS_END        48 >  #endif > > -#ifdef CONFIG_AB3550_CORE > -#define IRQ_AB3550_BASE             (U300_NR_IRQS) > -#define IRQ_AB3550_END         (IRQ_AB3550_BASE + 37) > +/* Maximum 8*7 GPIO lines */ > +#ifdef CONFIG_GPIO_U300 > +#define IRQ_U300_GPIO_BASE       (U300_VIC_IRQS_END) > +#define IRQ_U300_GPIO_END        (IRQ_U300_GPIO_BASE + 56) > +#else > +#define IRQ_U300_GPIO_END        (U300_VIC_IRQS_END) > +#endif > > -#define NR_IRQS                 (IRQ_AB3550_END + 1) > +/* Optional AB3550 mixsig chip */ > +#ifdef CONFIG_AB3550_CORE > +#define IRQ_AB3550_BASE             (IRQ_U300_GPIO_END) > +#define IRQ_AB3550_END         (IRQ_AB3550_BASE + 38) >  #else > -#define NR_IRQS U300_NR_IRQS > +#define IRQ_AB3550_END         (IRQ_U300_GPIO_END) >  #endif > > +#define NR_IRQS                 (IRQ_AB3550_END) > + >  #endif > diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig > index d3b2953..cc89dfa 100644 > --- a/drivers/gpio/Kconfig > +++ b/drivers/gpio/Kconfig > @@ -119,6 +119,15 @@ config GPIO_SCH >      This driver can also be built as a module. If so, the module >      will be called sch-gpio. > > +config GPIO_U300 > +    bool "ST-Ericsson U300 COH 901 335/571 GPIO" > +    depends on GPIOLIB && ARCH_U300 > +    help > +     Say yes here to support GPIO interface on ST-Ericsson U300. > +     The names of the two IP block variants supported are > +     COH 901 335 and COH 901 571/3. They contain 3, 5 or 7 > +     ports of 8 GPIO pins each. > + >  config GPIO_VX855 >     tristate "VIA VX855/VX875 GPIO" >     depends on GPIOLIB && MFD_SUPPORT && PCI > diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile > index becef59..26032b1 100644 > --- a/drivers/gpio/Makefile > +++ b/drivers/gpio/Makefile > @@ -37,6 +37,7 @@ obj-$(CONFIG_GPIO_WM831X)   += wm831x-gpio.o >  obj-$(CONFIG_GPIO_WM8350)    += wm8350-gpiolib.o >  obj-$(CONFIG_GPIO_WM8994)    += wm8994-gpio.o >  obj-$(CONFIG_GPIO_SCH)     += sch_gpio.o > +obj-$(CONFIG_GPIO_U300)         += u300-gpio.o >  obj-$(CONFIG_GPIO_RDC321X)   += rdc321x-gpio.o >  obj-$(CONFIG_GPIO_JANZ_TTL)   += janz-ttl.o >  obj-$(CONFIG_GPIO_SX150X)    += sx150x.o > diff --git a/drivers/gpio/u300-gpio.c b/drivers/gpio/u300-gpio.c > new file mode 100644 > index 0000000..d85a116 > --- /dev/null > +++ b/drivers/gpio/u300-gpio.c > @@ -0,0 +1,836 @@ > +/* > + * Copyright (C) 2007-2011 ST-Ericsson AB > + * License terms: GNU General Public License (GPL) version 2 > + * U300 GPIO module. > + * This can driver either of the two basic GPIO cores > + * available in the U300 platforms: > + * COH 901 335  - Used in DB3150 (U300 1.0) and DB3200 (U330 1.0) > + * COH 901 571/3 - Used in DB3210 (U365 2.0) and DB3350 (U335 1.0) > + * Author: Linus Walleij <linus.walleij@linaro.org> > + * Author: Jonas Aaberg <jonas.aberg@stericsson.com> > + */ > +#include <linux/module.h> > +#include <linux/irq.h> > +#include <linux/interrupt.h> > +#include <linux/delay.h> > +#include <linux/errno.h> > +#include <linux/io.h> > +#include <linux/clk.h> > +#include <linux/err.h> > +#include <linux/platform_device.h> > +#include <linux/gpio.h> > +#include <linux/list.h> > +#include <linux/slab.h> > +#include <linux/gpio/u300.h> > + > +/* > + * Register definitions for COH 901 335 variant > + */ > +#define U300_335_PORT_STRIDE              (0x1C) > +/* Port X Pin Data Register 32bit, this is both input and output (R/W) */ > +#define U300_335_PXPDIR                     (0x00) > +#define U300_335_PXPDOR                     (0x00) > +/* Port X Pin Config Register 32bit (R/W) */ > +#define U300_335_PXPCR                 (0x04) > +/* This register layout is the same in both blocks */ > +#define U300_GPIO_PXPCR_ALL_PINS_MODE_MASK       (0x0000FFFFUL) > +#define U300_GPIO_PXPCR_PIN_MODE_MASK          (0x00000003UL) > +#define U300_GPIO_PXPCR_PIN_MODE_SHIFT         (0x00000002UL) > +#define U300_GPIO_PXPCR_PIN_MODE_INPUT         (0x00000000UL) > +#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL    (0x00000001UL) > +#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_DRAIN   (0x00000002UL) > +#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_SOURCE   (0x00000003UL) > +/* Port X Interrupt Event Register 32bit (R/W) */ > +#define U300_335_PXIEV                 (0x08) > +/* Port X Interrupt Enable Register 32bit (R/W) */ > +#define U300_335_PXIEN                 (0x0C) > +/* Port X Interrupt Force Register 32bit (R/W) */ > +#define U300_335_PXIFR                 (0x10) > +/* Port X Interrupt Config Register 32bit (R/W) */ > +#define U300_335_PXICR                 (0x14) > +/* This register layout is the same in both blocks */ > +#define U300_GPIO_PXICR_ALL_IRQ_CONFIG_MASK       (0x000000FFUL) > +#define U300_GPIO_PXICR_IRQ_CONFIG_MASK             (0x00000001UL) > +#define U300_GPIO_PXICR_IRQ_CONFIG_FALLING_EDGE         (0x00000000UL) > +#define U300_GPIO_PXICR_IRQ_CONFIG_RISING_EDGE     (0x00000001UL) > +/* Port X Pull-up Enable Register 32bit (R/W) */ > +#define U300_335_PXPER                 (0x18) > +/* This register layout is the same in both blocks */ > +#define U300_GPIO_PXPER_ALL_PULL_UP_DISABLE_MASK    (0x000000FFUL) > +#define U300_GPIO_PXPER_PULL_UP_DISABLE             (0x00000001UL) > +/* Control Register 32bit (R/W) */ > +#define U300_335_CR                   (0x54) > +#define U300_335_CR_BLOCK_CLOCK_ENABLE         (0x00000001UL) > + > +/* > + * Register definitions for COH 901 571 / 3 variant > + */ > +#define U300_571_PORT_STRIDE              (0x30) > +/* > + * Control Register 32bit (R/W) > + * bit 15-9 (mask 0x0000FE00) contains the number of cores. 8*cores > + * gives the number of GPIO pins. > + * bit 8-2  (mask 0x000001FC) contains the core version ID. > + */ > +#define U300_571_CR                   (0x00) > +#define U300_571_CR_SYNC_SEL_ENABLE           (0x00000002UL) > +#define U300_571_CR_BLOCK_CLKRQ_ENABLE         (0x00000001UL) > +/* > + * These registers have the same layout and function as the corresponding > + * COH 901 335 registers, just at different offset. > + */ > +#define U300_571_PXPDIR                     (0x04) > +#define U300_571_PXPDOR                     (0x08) > +#define U300_571_PXPCR                 (0x0C) > +#define U300_571_PXPER                 (0x10) > +#define U300_571_PXIEV                 (0x14) > +#define U300_571_PXIEN                 (0x18) > +#define U300_571_PXIFR                 (0x1C) > +#define U300_571_PXICR                 (0x20) > + > +/* 8 bits per port, no version has more than 7 ports */ > +#define U300_GPIO_PINS_PER_PORT 8 > +#define U300_GPIO_MAX (U300_GPIO_PINS_PER_PORT * 7) > + > +struct u300_gpio { > +    struct gpio_chip chip; > +    struct list_head port_list; > +    struct clk *clk; > +    struct resource *memres; > +    void __iomem *base; > +    struct device *dev; > +    int irq_base; > +    int users; > +    u32 stride; > +    /* Register offsets */ > +    u32 pcr; > +    u32 dor; > +    u32 dir; > +    u32 per; > +    u32 icr; > +    u32 ien; > +    u32 iev; > +}; > + > +struct u300_gpio_port { > +    struct list_head node; > +    struct u300_gpio *gpio; > +    char name[8]; > +    int irq; > +    int number; > +}; > + > +/* > + * Macro to expand to read a specific register found in the "gpio" > + * struct. It requires the struct u300_gpio *gpio variable to exist in > + * its context. It calculates the port offset from the given pin > + * offset, muliplies by the port stride and adds the register offset > + * so it provides a pointer to the desired register. > + */ > +#define U300_PIN_REG(pin, reg) \ > +    (gpio->base + (pin >> 3) * gpio->stride + gpio->reg) > + > +/* > + * Provides a bitmask for a specific gpio pin inside an 8-bit GPIO > + * register. > + */ > +#define U300_PIN_BIT(pin) \ > +    (1 << (pin & 0x07)) > + > +struct u300_gpio_confdata { > +    u16 bias_mode; > +    bool output; > +    int outval; > +}; > + > +/* BS335 has seven ports of 8 bits each = GPIO pins 0..55 */ > +#define BS335_GPIO_NUM_PORTS 7 > +/* BS365 has five ports of 8 bits each = GPIO pins 0..39 */ > +#define BS365_GPIO_NUM_PORTS 5 > + > +#define U300_FLOATING_INPUT { \ > +    .bias_mode = GPIO_CONFIG_BIAS_FLOAT, \ > +    .output = false, \ > +} > + > +#define U300_PULL_UP_INPUT { \ > +    .bias_mode = GPIO_CONFIG_BIAS_PULL_UP, \ > +    .output = false, \ > +} > + > +#define U300_OUTPUT_LOW { \ > +    .output = true, \ > +    .outval = 0, \ > +} > + > +#define U300_OUTPUT_HIGH { \ > +    .output = true, \ > +    .outval = 1, \ > +} > + > + > +/* Initial configuration */ > +static struct __initdata u300_gpio_confdata > +bs335_gpio_config[BS335_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = { > +    /* Port 0, pins 0-7 */ > +    { > +        U300_FLOATING_INPUT, > +        U300_OUTPUT_HIGH, > +        U300_FLOATING_INPUT, > +        U300_OUTPUT_LOW, > +        U300_OUTPUT_LOW, > +        U300_OUTPUT_LOW, > +        U300_OUTPUT_LOW, > +        U300_OUTPUT_LOW, > +    }, > +    /* Port 1, pins 0-7 */ > +    { > +        U300_OUTPUT_LOW, > +        U300_OUTPUT_LOW, > +        U300_OUTPUT_LOW, > +        U300_PULL_UP_INPUT, > +        U300_FLOATING_INPUT, > +        U300_OUTPUT_HIGH, > +        U300_OUTPUT_LOW, > +        U300_OUTPUT_LOW, > +    }, > +    /* Port 2, pins 0-7 */ > +    { > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +        U300_OUTPUT_LOW, > +        U300_PULL_UP_INPUT, > +        U300_OUTPUT_LOW, > +        U300_PULL_UP_INPUT, > +    }, > +    /* Port 3, pins 0-7 */ > +    { > +        U300_PULL_UP_INPUT, > +        U300_OUTPUT_LOW, > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +    }, > +    /* Port 4, pins 0-7 */ > +    { > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +    }, > +    /* Port 5, pins 0-7 */ > +    { > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +    }, > +    /* Port 6, pind 0-7 */ > +    { > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +    } > +}; > + > +static struct __initdata u300_gpio_confdata > +bs365_gpio_config[BS365_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = { > +    /* Port 0, pins 0-7 */ > +    { > +        U300_FLOATING_INPUT, > +        U300_OUTPUT_LOW, > +        U300_FLOATING_INPUT, > +        U300_OUTPUT_LOW, > +        U300_OUTPUT_LOW, > +        U300_OUTPUT_LOW, > +        U300_PULL_UP_INPUT, > +        U300_FLOATING_INPUT, > +    }, > +    /* Port 1, pins 0-7 */ > +    { > +        U300_OUTPUT_LOW, > +        U300_FLOATING_INPUT, > +        U300_OUTPUT_LOW, > +        U300_FLOATING_INPUT, > +        U300_FLOATING_INPUT, > +        U300_OUTPUT_HIGH, > +        U300_OUTPUT_LOW, > +        U300_OUTPUT_LOW, > +    }, > +    /* Port 2, pins 0-7 */ > +    { > +        U300_FLOATING_INPUT, > +        U300_PULL_UP_INPUT, > +        U300_OUTPUT_LOW, > +        U300_OUTPUT_LOW, > +        U300_PULL_UP_INPUT, > +        U300_PULL_UP_INPUT, > +        U300_PULL_UP_INPUT, > +        U300_PULL_UP_INPUT, > +    }, > +    /* Port 3, pins 0-7 */ > +    { > +        U300_PULL_UP_INPUT, > +        U300_PULL_UP_INPUT, > +        U300_PULL_UP_INPUT, > +        U300_PULL_UP_INPUT, > +        U300_PULL_UP_INPUT, > +        U300_PULL_UP_INPUT, > +        U300_PULL_UP_INPUT, > +        U300_PULL_UP_INPUT, > +    }, > +    /* Port 4, pins 0-7 */ > +    { > +        U300_PULL_UP_INPUT, > +        U300_PULL_UP_INPUT, > +        U300_PULL_UP_INPUT, > +        U300_PULL_UP_INPUT, > +        /* These 4 pins doesn't exist on DB3210 */ > +        U300_OUTPUT_LOW, > +        U300_OUTPUT_LOW, > +        U300_OUTPUT_LOW, > +        U300_OUTPUT_LOW, > +    } > +}; > + > +/** > + * to_u300_gpio() - get the pointer to u300_gpio > + * @chip: the gpio chip member of the structure u300_gpio > + */ > +static inline struct u300_gpio *to_u300_gpio(struct gpio_chip *chip) > +{ > +    return container_of(chip, struct u300_gpio, chip); > +} > + > +static int u300_gpio_get(struct gpio_chip *chip, unsigned offset) > +{ > +    struct u300_gpio *gpio = to_u300_gpio(chip); > + > +    return readl(U300_PIN_REG(offset, dir)) & U300_PIN_BIT(offset); > +} > + > +static void u300_gpio_set(struct gpio_chip *chip, unsigned offset, int value) > +{ > +    struct u300_gpio *gpio = to_u300_gpio(chip); > +    unsigned long flags; > +    u32 val; > + > +    local_irq_save(flags); > + > +    val = readl(U300_PIN_REG(offset, dor)); > +    if (value) > +        writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, dor)); > +    else > +        writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, dor)); > + > +    local_irq_restore(flags); > +} > + > +static int u300_gpio_direction_input(struct gpio_chip *chip, unsigned offset) > +{ > +    struct u300_gpio *gpio = to_u300_gpio(chip); > +    unsigned long flags; > +    u32 val; > + > +    local_irq_save(flags); > +    val = readl(U300_PIN_REG(offset, pcr)); > +    /* Mask out this pin, note 2 bits per setting */ > +    val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << ((offset & 0x07) << 1)); > +    writel(val, U300_PIN_REG(offset, pcr)); > +    local_irq_restore(flags); > +    return 0; > +} > + > +static int u300_gpio_direction_output(struct gpio_chip *chip, unsigned offset, > +                   int value) > +{ > +    struct u300_gpio *gpio = to_u300_gpio(chip); > +    unsigned long flags; > +    u32 oldmode; > +    u32 val; > + > +    local_irq_save(flags); > +    val = readl(U300_PIN_REG(offset, pcr)); > +    /* > +     * Drive mode must be set by the special mode set function, set > +     * push/pull mode by default if no mode has been selected. > +     */ > +    oldmode = val & (U300_GPIO_PXPCR_PIN_MODE_MASK << > +             ((offset & 0x07) << 1)); > +    /* mode = 0 means input, else some mode is already set */ > +    if (oldmode == 0) { > +        val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << > +             ((offset & 0x07) << 1)); > +        val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL > +            << ((offset & 0x07) << 1)); > +        writel(val, U300_PIN_REG(offset, pcr)); > +    } > +    u300_gpio_set(chip, offset, value); > +    local_irq_restore(flags); > +    return 0; > +} > + > +static int u300_gpio_to_irq(struct gpio_chip *chip, unsigned offset) > +{ > +    struct u300_gpio *gpio = to_u300_gpio(chip); > +    int retirq = gpio->irq_base + offset; > + > +    dev_dbg(gpio->dev, "request IRQ for GPIO %d, return %d\n", offset, > +        retirq); > +    return retirq; > +} > + > +static int u300_gpio_config(struct gpio_chip *chip, unsigned offset, > +               u16 param, unsigned long *data) > +{ > +    struct u300_gpio *gpio = to_u300_gpio(chip); > +    unsigned long flags; > +    u32 val; > + > +    local_irq_save(flags); > +    switch (param) { > +    case GPIO_CONFIG_BIAS_UNKNOWN: > +    case GPIO_CONFIG_BIAS_FLOAT: > +        val = readl(U300_PIN_REG(offset, per)); > +        writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, per)); > +        break; > +    case GPIO_CONFIG_BIAS_PULL_UP: > +        val = readl(U300_PIN_REG(offset, per)); > +        writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, per)); > +        break; > +    case GPIO_CONFIG_DRIVE_PUSH_PULL: > +        val = readl(U300_PIN_REG(offset, pcr)); > +        val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK > +             << ((offset & 0x07) << 1)); > +        val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL > +            << ((offset & 0x07) << 1)); > +        writel(val, U300_PIN_REG(offset, pcr)); > +        break; > +    case GPIO_CONFIG_DRIVE_OPEN_DRAIN: > +        val = readl(U300_PIN_REG(offset, pcr)); > +        val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK > +             << ((offset & 0x07) << 1)); > +        val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_DRAIN > +            << ((offset & 0x07) << 1)); > +        writel(val, U300_PIN_REG(offset, pcr)); > +        break; > +    case GPIO_CONFIG_DRIVE_OPEN_SOURCE: > +        val = readl(U300_PIN_REG(offset, pcr)); > +        val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK > +             << ((offset & 0x07) << 1)); > +        val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_SOURCE > +            << ((offset & 0x07) << 1)); > +        writel(val, U300_PIN_REG(offset, pcr)); > +        break; > +    default: > +        local_irq_restore(flags); > +        dev_err(gpio->dev, "illegal configuration requested\n"); > +        return -EINVAL; > +    } > +    local_irq_restore(flags); > +    return 0; > +} > + > +static struct gpio_chip u300_gpio_chip = { > +    .label          = "u300-gpio-chip", > +    .owner          = THIS_MODULE, > +    .get           = u300_gpio_get, > +    .set           = u300_gpio_set, > +    .config         = u300_gpio_config, > +    .direction_input     = u300_gpio_direction_input, > +    .direction_output    = u300_gpio_direction_output, > +    .to_irq         = u300_gpio_to_irq, > +}; > + > +static int u300_gpio_irq_type(struct irq_data *d, unsigned trigger) > +{ > +    struct u300_gpio *gpio = irq_data_get_irq_chip_data(d); > +    int offset = d->irq - gpio->irq_base; > +    u32 val; > + > +    val = readl(U300_PIN_REG(offset, icr)); > +    if (trigger & IRQF_TRIGGER_RISING) > +        writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, icr)); > +    else > +        writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, icr)); > + > +    return 0; > +} > + > +static void u300_gpio_irq_enable(struct irq_data *d) > +{ > +    struct u300_gpio *gpio = irq_data_get_irq_chip_data(d); > +    int offset = d->irq - gpio->irq_base; > +    u32 val; > +    unsigned long flags; > + > +    local_irq_save(flags); > +    val = readl(U300_PIN_REG(offset, ien)); > +    writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, ien)); > +    local_irq_restore(flags); > +} > + > +static void u300_gpio_irq_disable(struct irq_data *d) > +{ > +    struct u300_gpio *gpio = irq_data_get_irq_chip_data(d); > +    int offset = d->irq - gpio->irq_base; > +    u32 val; > +    unsigned long flags; > + > +    local_irq_save(flags); > +    val = readl(U300_PIN_REG(offset, ien)); > +    writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, ien)); > +    local_irq_restore(flags); > +} > + > +static struct irq_chip u300_gpio_irqchip = { > +    .name          = "u300-gpio-irqchip", > +    .irq_enable       = u300_gpio_irq_enable, > +    .irq_disable       = u300_gpio_irq_disable, > +    .irq_set_type      = u300_gpio_irq_type, > + > +}; > + > +static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc) > +{ > +    struct u300_gpio_port *port = irq_get_handler_data(irq); > +    struct u300_gpio *gpio = port->gpio; > +    int pinoffset = port->number << 3; /* get the right stride */ > +    unsigned long val; > + > +    desc->irq_data.chip->irq_ack(&desc->irq_data); > +    /* Read event register */ > +    val = readl(U300_PIN_REG(pinoffset, iev)); > +    /* Mask relevant bits */ > +    val &= 0xFFU; /* 8 bits per port */ > +    /* ACK IRQ (clear event) */ > +    writel(val, U300_PIN_REG(pinoffset, iev)); > + > +    /* Call IRQ handler */ > +    if (val != 0) { > +        int irqoffset; > + > +        for_each_set_bit(irqoffset, &val, U300_GPIO_PINS_PER_PORT) { > +            int pin_irq = gpio->irq_base + (port->number << 3) > +                + irqoffset; > + > +            dev_dbg(gpio->dev, "GPIO IRQ on pin %d\n", pin_irq); > +            generic_handle_irq(pin_irq); > +        } > +    } > +    desc->irq_data.chip->irq_unmask(&desc->irq_data); > +} > + > +static void __init u300_gpio_init_pin(struct u300_gpio *gpio, > +                   int offset, > +                   struct u300_gpio_confdata *conf) > +{ > +    /* Set mode: input or output */ > +    if (conf->output) { > +        u300_gpio_direction_output(&gpio->chip, offset, conf->outval); > + > +        /* Deactivate bias mode for output */ > +        u300_gpio_config(&gpio->chip, offset, GPIO_CONFIG_BIAS_FLOAT, > +                 NULL); > + > +        /* Set drive mode for output */ > +        u300_gpio_config(&gpio->chip, offset, > +                 GPIO_CONFIG_DRIVE_PUSH_PULL, NULL); > + > +        dev_dbg(gpio->dev, "set up pin %d as output, value: %d\n", > +            offset, conf->outval); > +    } else { > +        u300_gpio_direction_input(&gpio->chip, offset); > + > +        /* Always set output low on input pins */ > +        u300_gpio_set(&gpio->chip, offset, 0); > + > +        /* Set bias mode for input */ > +        u300_gpio_config(&gpio->chip, offset, conf->bias_mode, NULL); > + > +        dev_dbg(gpio->dev, "set up pin %d as input, bias: %d\n", > +            offset, conf->bias_mode); > +    } > +} > + > +static void __init u300_gpio_init_coh901571(struct u300_gpio *gpio, > +                   struct u300_gpio_platform *plat) > +{ > +    int i, j; > + > +    /* Write default config and values to all pins */ > +    for (i = 0; i < plat->ports; i++) { > +        for (j = 0; j < 8; j++) { > +            struct u300_gpio_confdata *conf; > +            int offset = (i*8) + j; > + > +            if (plat->variant == U300_GPIO_COH901571_3_BS335) > +                conf = &bs335_gpio_config[i][j]; > +            else if (plat->variant == U300_GPIO_COH901571_3_BS365) > +                conf = &bs365_gpio_config[i][j]; > +            else > +                break; > + > +            u300_gpio_init_pin(gpio, offset, conf); > +        } > +    } > +} > + > +static inline void u300_gpio_free_ports(struct u300_gpio *gpio) > +{ > +    struct u300_gpio_port *port; > +    struct list_head *p, *n; > + > +    list_for_each_safe(p, n, &gpio->port_list) { > +        port = list_entry(p, struct u300_gpio_port, node); > +        list_del(&port->node); > +        free_irq(port->irq, port); > +        kfree(port); > +    } > +} > + > +static int __init u300_gpio_probe(struct platform_device *pdev) > +{ > +    struct u300_gpio_platform *plat = dev_get_platdata(&pdev->dev); > +    struct u300_gpio *gpio; > +    int err = 0; > +    int portno; > +    u32 val; > +    u32 ifr; > +    int i; > + > +    gpio = kzalloc(sizeof(struct u300_gpio), GFP_KERNEL); > +    if (gpio == NULL) { > +        dev_err(&pdev->dev, "failed to allocate memory\n"); > +        return -ENOMEM; > +    } > + > +    gpio->chip = u300_gpio_chip; > +    gpio->chip.ngpio = plat->ports * U300_GPIO_PINS_PER_PORT; > +    gpio->irq_base = plat->gpio_irq_base; > +    gpio->chip.dev = &pdev->dev; > +    gpio->chip.base = plat->gpio_base; > +    gpio->dev = &pdev->dev; > + > +    /* Get GPIO clock */ > +    gpio->clk = clk_get(gpio->dev, NULL); > +    if (IS_ERR(gpio->clk)) { > +        err = PTR_ERR(gpio->clk); > +        dev_err(gpio->dev, "could not get GPIO clock\n"); > +        goto err_no_clk; > +    } > +    err = clk_enable(gpio->clk); > +    if (err) { > +        dev_err(gpio->dev, "could not enable GPIO clock\n"); > +        goto err_no_clk_enable; > +    } > + > +    gpio->memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); > +    if (!gpio->memres) { > +        dev_err(gpio->dev, "could not get GPIO memory resource\n"); > +        err = -ENODEV; > +        goto err_no_resource; > +    } > + > +    if (request_mem_region(gpio->memres->start, > +                gpio->memres->end - gpio->memres->start, > +                "GPIO Controller") > +      == NULL) { > +        dev_err(gpio->dev, "could not reserve GPIO memory region\n"); > +        err = -ENODEV; > +        goto err_no_ioregion; > +    } > + > +    gpio->base = ioremap(gpio->memres->start, resource_size(gpio->memres)); > +    if (!gpio->base) { > +        err = -ENOMEM; > +        goto err_no_ioremap; > +    } > + > +    if (plat->variant == U300_GPIO_COH901335) { > +        dev_info(gpio->dev, > +             "initializing GPIO Controller COH 901 335\n"); > +        gpio->stride = U300_335_PORT_STRIDE; > +        gpio->pcr = U300_335_PXPCR; > +        gpio->dor = U300_335_PXPDOR; > +        gpio->dir = U300_335_PXPDIR; > +        gpio->per = U300_335_PXPER; > +        gpio->icr = U300_335_PXICR; > +        gpio->ien = U300_335_PXIEN; > +        gpio->iev = U300_335_PXIEV; > +        ifr = U300_335_PXIFR; > + > +        /* Turn on the GPIO block */ > +        writel(U300_335_CR_BLOCK_CLOCK_ENABLE, > +            gpio->base + U300_335_CR); > +    } else if (plat->variant == U300_GPIO_COH901571_3_BS335 || > +          plat->variant == U300_GPIO_COH901571_3_BS365) { > +        dev_info(gpio->dev, > +             "initializing GPIO Controller COH 901 571/3\n"); > +        gpio->stride = U300_571_PORT_STRIDE; > +        gpio->pcr = U300_571_PXPCR; > +        gpio->dor = U300_571_PXPDOR; > +        gpio->dir = U300_571_PXPDIR; > +        gpio->per = U300_571_PXPER; > +        gpio->icr = U300_571_PXICR; > +        gpio->ien = U300_571_PXIEN; > +        gpio->iev = U300_571_PXIEV; > +        ifr = U300_571_PXIFR; > + > +        val = readl(gpio->base + U300_571_CR); > +        dev_info(gpio->dev, "COH901571/3 block version: %d, " \ > +             "number of cores: %d\n", > +             ((val & 0x0000FE00) >> 9), > +             ((val & 0x000001FC) >> 2)); > +        writel(U300_571_CR_BLOCK_CLKRQ_ENABLE, > +            gpio->base + U300_571_CR); > +        u300_gpio_init_coh901571(gpio, plat); > +    } else { > +        dev_err(gpio->dev, "unknown block variant\n"); > +        err = -ENODEV; > +        goto err_unknown_variant; > +    } > + > +    /* Add each port with its IRQ separately */ > +    INIT_LIST_HEAD(&gpio->port_list); > +    for (portno = 0 ; portno < plat->ports; portno++) { > +        struct u300_gpio_port *port = > +            kmalloc(sizeof(struct u300_gpio_port), GFP_KERNEL); > + > +        if (!port) { > +            dev_err(gpio->dev, "out of memory\n"); > +            err = -ENOMEM; > +            goto err_no_port; > +        } > + > +        snprintf(port->name, 8, "gpio%d", portno); > +        port->number = portno; > +        port->gpio = gpio; > + > +        port->irq = platform_get_irq_byname(pdev, > +                          port->name); > + > +        dev_dbg(gpio->dev, "register IRQ %d for %s\n", port->irq, > +            port->name); > + > +        irq_set_chained_handler(port->irq, u300_gpio_irq_handler); > +        irq_set_handler_data(port->irq, port); > + > +        /* Then for each GPIO pin set the unique IRQ handler */ > +        for (i = 0; i < U300_GPIO_PINS_PER_PORT; i++) { > +            int irqno = gpio->irq_base + (portno << 3) + i; > + > +            dev_dbg(gpio->dev, "handler for IRQ %d on %s\n", > +                irqno, port->name); > +            irq_set_chip_and_handler(irqno, &u300_gpio_irqchip, > +                         handle_simple_irq); > +            set_irq_flags(irqno, IRQF_VALID); > +            irq_set_chip_data(irqno, gpio); > +        } > + > +        /* Turns off irq force (test register) for this port */ > +        writel(0x0, gpio->base + portno * gpio->stride + ifr); > + > +        list_add_tail(&port->node, &gpio->port_list); > +    } > + > +    err = gpiochip_add(&gpio->chip); > +    if (err) { > +        dev_err(gpio->dev, "unable to add gpiochip: %d\n", err); > +        goto err_no_chip; > +    } > + > +    platform_set_drvdata(pdev, gpio); > + > +    return 0; > + > +err_no_chip: > +err_no_port: > +    u300_gpio_free_ports(gpio); > +err_unknown_variant: > +    iounmap(gpio->base); > +err_no_ioremap: > +    release_mem_region(gpio->memres->start, > +              gpio->memres->end - gpio->memres->start); > +err_no_ioregion: > +err_no_resource: > +    clk_disable(gpio->clk); > +err_no_clk_enable: > +    clk_put(gpio->clk); > +err_no_clk: > +    kfree(gpio); > +    dev_info(&pdev->dev, "module ERROR:%d\n", err); > +    return err; > +} > + > +static int __exit u300_gpio_remove(struct platform_device *pdev) > +{ > +    struct u300_gpio_platform *plat = dev_get_platdata(&pdev->dev); > +    struct u300_gpio *gpio = platform_get_drvdata(pdev); > +    int err; > + > +    /* Turn off the GPIO block */ > +    if (plat->variant == U300_GPIO_COH901335) > +        writel(0x00000000U, gpio->base + U300_335_CR); > +    if (plat->variant == U300_GPIO_COH901571_3_BS335 || > +      plat->variant == U300_GPIO_COH901571_3_BS365) > +        writel(0x00000000U, gpio->base + U300_571_CR); > + > +    err = gpiochip_remove(&gpio->chip); > +    if (err < 0) { > +        dev_err(gpio->dev, "unable to remove gpiochip: %d\n", err); > +        return err; > +    } > +    u300_gpio_free_ports(gpio); > +    iounmap(gpio->base); > +    release_mem_region(gpio->memres->start, > +              gpio->memres->end - gpio->memres->start); > +    clk_disable(gpio->clk); > +    clk_put(gpio->clk); > +    platform_set_drvdata(pdev, NULL); > +    kfree(gpio); > +    return 0; > +} > + > +static struct platform_driver u300_gpio_driver = { > +    .driver     = { > +        .name  = "u300-gpio", > +    }, > +    .remove     = __exit_p(u300_gpio_remove), > +}; > + > + > +static int __init u300_gpio_init(void) > +{ > +    return platform_driver_probe(&u300_gpio_driver, u300_gpio_probe); > +} > + > +static void __exit u300_gpio_exit(void) > +{ > +    platform_driver_unregister(&u300_gpio_driver); > +} > + > +arch_initcall(u300_gpio_init); > +module_exit(u300_gpio_exit); > + > +MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>"); > +MODULE_DESCRIPTION("ST-Ericsson AB COH 901 335/COH 901 571/3 GPIO driver"); > +MODULE_LICENSE("GPL"); > diff --git a/include/linux/gpio/u300.h b/include/linux/gpio/u300.h > new file mode 100644 > index 0000000..38cd064 > --- /dev/null > +++ b/include/linux/gpio/u300.h > @@ -0,0 +1,32 @@ > +/* > + * U300 GPIO platform data header > + * Copyright (C) 2011 ST-Ericsson SA > + * Written on behalf of Linaro for ST-Ericsson > + * > + * Author: Linus Walleij <linus.walleij@linaro.org> > + * > + * License terms: GNU General Public License (GPL) version 2 > + */ > + > +/** > + * enum u300_gpio_variant - the type of U300 GPIO employed > + */ > +enum u300_gpio_variant { > +    U300_GPIO_COH901335, > +    U300_GPIO_COH901571_3_BS335, > +    U300_GPIO_COH901571_3_BS365, > +}; > + > +/** > + * struct u300_gpio_platform - U300 GPIO platform data > + * @variant: IP block variant > + * @ports: number of GPIO block ports > + * @gpio_base: first GPIO number for this block (use a free range) > + * @gpio_irq_base: first GPIO IRQ number for this block (use a free range) > + */ > +struct u300_gpio_platform { > +    enum u300_gpio_variant variant; > +    u8 ports; > +    int gpio_base; > +    int gpio_irq_base; > +}; > -- > 1.7.3.2 > > > _______________________________________________ > linux-arm-kernel mailing list > linux-arm-kernel@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel > ÿôèº{.nÇ+·®+%Ëÿ±éݶ\x17¥wÿº{.nÇ+·¥{±þG«éÿ{ayº\x1dÊÚë,j\a¢f£¢·hïêÿêçz_è®\x03(éÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?¨èÚ&£ø§~á¶iOæ¬z·vØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?I¥ ^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio 2011-05-19 11:11 ` Barry Song @ 2011-05-19 11:38 ` Barry Song 0 siblings, 0 replies; 57+ messages in thread From: Barry Song @ 2011-05-19 11:38 UTC (permalink / raw) To: Linus Walleij Cc: Grant Likely, linux-kernel, linux-arm-kernel, Linus Walleij, Lee Jones, Jonas Aaberg > -arch_initcall(u300_gpio_init); > -module_exit(u300_gpio_exit); > looks like the driver can't be a real module, is the module_exit suitable? it looks strange module_exit plays together with arch_initcall. guess symbol u300_gpio_exit will finally lose in the last vmlinux since it is in exit section and built-in kernel. another problem i see is after moving gpio/pinmux to drivers as platform device, codes in arch/arm/plat(mach) can't call gpio/pinmux api before the related platform devices registerred. that will required these platform devices enter system earlier. ^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-05-19 11:38 ` Barry Song 0 siblings, 0 replies; 57+ messages in thread From: Barry Song @ 2011-05-19 11:38 UTC (permalink / raw) To: linux-arm-kernel > -arch_initcall(u300_gpio_init); > -module_exit(u300_gpio_exit); > looks like the driver can't be a real module, is the module_exit suitable? it looks strange module_exit plays together with arch_initcall. guess symbol u300_gpio_exit will finally lose in the last vmlinux since it is in exit section and built-in kernel. another problem i see is after moving gpio/pinmux to drivers as platform device, codes in arch/arm/plat(mach) can't call gpio/pinmux api before the related platform devices registerred. that will required these platform devices enter system earlier. ^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio 2011-05-19 11:38 ` Barry Song @ 2011-05-19 12:25 ` Linus Walleij -1 siblings, 0 replies; 57+ messages in thread From: Linus Walleij @ 2011-05-19 12:25 UTC (permalink / raw) To: Barry Song Cc: Linus Walleij, Grant Likely, linux-kernel, linux-arm-kernel, Lee Jones, Jonas Aaberg On Thu, May 19, 2011 at 1:38 PM, Barry Song <21cnbao@gmail.com> wrote: >> -arch_initcall(u300_gpio_init); >> -module_exit(u300_gpio_exit); >> > looks like the driver can't be a real module, is the module_exit > suitable? it looks strange module_exit plays together with > arch_initcall. It's a rather common design pattern in the kernel for early platform drivers. Either the dependencies are resolved by the different initlevels or they are resolved in probe order with loadable modules. Module load will call all initlevels in order. It is not elegant but it is common. > guess symbol u300_gpio_exit will finally lose in the last vmlinux > since it is in exit section and built-in kernel. Yes. And if you one day, to do some testing, compile and load it as module and unload it, it is handy. I have other drivers where I simply don't have an exit function but this one I have actually used. > another problem i see is after moving gpio/pinmux to drivers as > platform device, codes in arch/arm/plat(mach) can't call gpio/pinmux > api before the related platform devices registerred. that will > required these platform devices enter system earlier. This is exactly the reason why the u300 gpio driver needs to be initialized in an arch_initcall(). Yours, Linus Walleij ^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-05-19 12:25 ` Linus Walleij 0 siblings, 0 replies; 57+ messages in thread From: Linus Walleij @ 2011-05-19 12:25 UTC (permalink / raw) To: linux-arm-kernel On Thu, May 19, 2011 at 1:38 PM, Barry Song <21cnbao@gmail.com> wrote: >> -arch_initcall(u300_gpio_init); >> -module_exit(u300_gpio_exit); >> > looks like the driver can't be a real module, is the module_exit > suitable? it looks strange module_exit plays together with > arch_initcall. It's a rather common design pattern in the kernel for early platform drivers. Either the dependencies are resolved by the different initlevels or they are resolved in probe order with loadable modules. Module load will call all initlevels in order. It is not elegant but it is common. > guess symbol u300_gpio_exit will finally lose in the last vmlinux > since it is in exit section and built-in kernel. Yes. And if you one day, to do some testing, compile and load it as module and unload it, it is handy. I have other drivers where I simply don't have an exit function but this one I have actually used. > another problem i see is after moving gpio/pinmux to drivers as > platform device, codes in arch/arm/plat(mach) can't ?call gpio/pinmux > api before the related platform devices registerred. that will > required these platform devices enter system earlier. This is exactly the reason why the u300 gpio driver needs to be initialized in an arch_initcall(). Yours, Linus Walleij ^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio 2011-05-19 12:25 ` Linus Walleij @ 2011-05-19 12:35 ` Barry Song -1 siblings, 0 replies; 57+ messages in thread From: Barry Song @ 2011-05-19 12:35 UTC (permalink / raw) To: Linus Walleij Cc: Linus Walleij, Grant Likely, linux-kernel, linux-arm-kernel, Lee Jones, Jonas Aaberg 2011/5/19 Linus Walleij <linus.walleij@linaro.org>: > On Thu, May 19, 2011 at 1:38 PM, Barry Song <21cnbao@gmail.com> wrote: > >>> -arch_initcall(u300_gpio_init); >>> -module_exit(u300_gpio_exit); >>> >> looks like the driver can't be a real module, is the module_exit >> suitable? it looks strange module_exit plays together with >> arch_initcall. > > It's a rather common design pattern in the kernel for early > platform drivers. Either the dependencies are resolved by the > different initlevels or they are resolved in probe order with > loadable modules. Module load will call all initlevels in order. > > It is not elegant but it is common. Linus, thanks for your reply. module_exit and related functions are really useless codes. but people have done that before, then we have no way except following. u300_gpio_exit never gets chance to run and when we disassemble vmlinux, u300_gpio_exit() function should be not in the final binary at all, just a symbol name is left. > >> guess symbol u300_gpio_exit will finally lose in the last vmlinux >> since it is in exit section and built-in kernel. > > Yes. And if you one day, to do some testing, compile and load it > as module and unload it, it is handy. > > I have other drivers where I simply don't have an exit function > but this one I have actually used. > >> another problem i see is after moving gpio/pinmux to drivers as >> platform device, codes in arch/arm/plat(mach) can't call gpio/pinmux >> api before the related platform devices registerred. that will >> required these platform devices enter system earlier. > > This is exactly the reason why the u300 gpio driver needs to > be initialized in an arch_initcall(). > > Yours, > Linus Walleij > ^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-05-19 12:35 ` Barry Song 0 siblings, 0 replies; 57+ messages in thread From: Barry Song @ 2011-05-19 12:35 UTC (permalink / raw) To: linux-arm-kernel 2011/5/19 Linus Walleij <linus.walleij@linaro.org>: > On Thu, May 19, 2011 at 1:38 PM, Barry Song <21cnbao@gmail.com> wrote: > >>> -arch_initcall(u300_gpio_init); >>> -module_exit(u300_gpio_exit); >>> >> looks like the driver can't be a real module, is the module_exit >> suitable? it looks strange module_exit plays together with >> arch_initcall. > > It's a rather common design pattern in the kernel for early > platform drivers. Either the dependencies are resolved by the > different initlevels or they are resolved in probe order with > loadable modules. Module load will call all initlevels in order. > > It is not elegant but it is common. Linus, thanks for your reply. module_exit and related functions are really useless codes. but people have done that before, then we have no way except following. u300_gpio_exit never gets chance to run and when we disassemble vmlinux, u300_gpio_exit() function should be not in the final binary at all, just a symbol name is left. > >> guess symbol u300_gpio_exit will finally lose in the last vmlinux >> since it is in exit section and built-in kernel. > > Yes. And if you one day, to do some testing, compile and load it > as module and unload it, it is handy. > > I have other drivers where I simply don't have an exit function > but this one I have actually used. > >> another problem i see is after moving gpio/pinmux to drivers as >> platform device, codes in arch/arm/plat(mach) can't ?call gpio/pinmux >> api before the related platform devices registerred. that will >> required these platform devices enter system earlier. > > This is exactly the reason why the u300 gpio driver needs to > be initialized in an arch_initcall(). > > Yours, > Linus Walleij > ^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio 2011-05-19 12:35 ` Barry Song @ 2011-05-19 13:17 ` Linus Walleij -1 siblings, 0 replies; 57+ messages in thread From: Linus Walleij @ 2011-05-19 13:17 UTC (permalink / raw) To: Barry Song Cc: Linus Walleij, Grant Likely, linux-kernel, linux-arm-kernel, Lee Jones, Jonas Aaberg On Thu, May 19, 2011 at 2:35 PM, Barry Song <21cnbao@gmail.com> wrote: > 2011/5/19 Linus Walleij <linus.walleij@linaro.org>: >> On Thu, May 19, 2011 at 1:38 PM, Barry Song <21cnbao@gmail.com> wrote: >>> >>> looks like the driver can't be a real module, is the module_exit >>> suitable? it looks strange module_exit plays together with >>> arch_initcall. >> >> It's a rather common design pattern in the kernel for early >> platform drivers. Either the dependencies are resolved by the >> different initlevels or they are resolved in probe order with >> loadable modules. Module load will call all initlevels in order. >> >> It is not elegant but it is common. > > Linus, thanks for your reply. module_exit and related functions are > really useless codes. but people have done that before, then we have > no way except following. > u300_gpio_exit never gets chance to run and when we disassemble > vmlinux, u300_gpio_exit() function should be not in the final binary > at all, just a symbol name is left. I know. I can make the Kconfig options tristate if it makes you feel better... Linus Walleij ^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-05-19 13:17 ` Linus Walleij 0 siblings, 0 replies; 57+ messages in thread From: Linus Walleij @ 2011-05-19 13:17 UTC (permalink / raw) To: linux-arm-kernel On Thu, May 19, 2011 at 2:35 PM, Barry Song <21cnbao@gmail.com> wrote: > 2011/5/19 Linus Walleij <linus.walleij@linaro.org>: >> On Thu, May 19, 2011 at 1:38 PM, Barry Song <21cnbao@gmail.com> wrote: >>> >>> looks like the driver can't be a real module, is the module_exit >>> suitable? it looks strange module_exit plays together with >>> arch_initcall. >> >> It's a rather common design pattern in the kernel for early >> platform drivers. Either the dependencies are resolved by the >> different initlevels or they are resolved in probe order with >> loadable modules. Module load will call all initlevels in order. >> >> It is not elegant but it is common. > > Linus, thanks for your reply. module_exit and related functions are > really useless codes. but people have done that before, then we have > no way except following. > u300_gpio_exit never gets chance to run and when we disassemble > vmlinux, u300_gpio_exit() ?function should be not in the final binary > at all, just a symbol name is left. I know. I can make the Kconfig options tristate if it makes you feel better... Linus Walleij ^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio 2011-05-19 13:17 ` Linus Walleij @ 2011-05-19 14:05 ` Barry Song -1 siblings, 0 replies; 57+ messages in thread From: Barry Song @ 2011-05-19 14:05 UTC (permalink / raw) To: Linus Walleij Cc: Linus Walleij, Grant Likely, linux-kernel, linux-arm-kernel, Lee Jones, Jonas Aaberg 2011/5/19 Linus Walleij <linus.walleij@linaro.org>: > On Thu, May 19, 2011 at 2:35 PM, Barry Song <21cnbao@gmail.com> wrote: >> 2011/5/19 Linus Walleij <linus.walleij@linaro.org>: >>> On Thu, May 19, 2011 at 1:38 PM, Barry Song <21cnbao@gmail.com> wrote: >>>> >>>> looks like the driver can't be a real module, is the module_exit >>>> suitable? it looks strange module_exit plays together with >>>> arch_initcall. >>> >>> It's a rather common design pattern in the kernel for early >>> platform drivers. Either the dependencies are resolved by the >>> different initlevels or they are resolved in probe order with >>> loadable modules. Module load will call all initlevels in order. >>> >>> It is not elegant but it is common. >> >> Linus, thanks for your reply. module_exit and related functions are >> really useless codes. but people have done that before, then we have >> no way except following. >> u300_gpio_exit never gets chance to run and when we disassemble >> vmlinux, u300_gpio_exit() function should be not in the final binary >> at all, just a symbol name is left. > > I know. I can make the Kconfig options tristate if it makes you feel > better... what i feel headache is that it is really difficult and unpredicted for an internal gpio driver to be removable in lots of read products because gpio is probably the last bottom module other drivers need. even it can be called in arch/arm/plat(mach). i am not sure whether i am thinking right. gpio and pinmux are more things of bottom level APIs like dma/clock tree but not like device drivers. but i really think you have sent a great pinmux core framework. we once thought we could have a plat-common above all plat-xxx/mach-xxx, and let the plat-common provide the cores of dma, clk, gpio, pinmux(pinmux core from you), for example, all common API and abstract level codes like gpio_request can be there, and SoCs just implement some hardware-related callbacks required by plat-common in themselves plat-xxx . > > Linus Walleij > ^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-05-19 14:05 ` Barry Song 0 siblings, 0 replies; 57+ messages in thread From: Barry Song @ 2011-05-19 14:05 UTC (permalink / raw) To: linux-arm-kernel 2011/5/19 Linus Walleij <linus.walleij@linaro.org>: > On Thu, May 19, 2011 at 2:35 PM, Barry Song <21cnbao@gmail.com> wrote: >> 2011/5/19 Linus Walleij <linus.walleij@linaro.org>: >>> On Thu, May 19, 2011 at 1:38 PM, Barry Song <21cnbao@gmail.com> wrote: >>>> >>>> looks like the driver can't be a real module, is the module_exit >>>> suitable? it looks strange module_exit plays together with >>>> arch_initcall. >>> >>> It's a rather common design pattern in the kernel for early >>> platform drivers. Either the dependencies are resolved by the >>> different initlevels or they are resolved in probe order with >>> loadable modules. Module load will call all initlevels in order. >>> >>> It is not elegant but it is common. >> >> Linus, thanks for your reply. module_exit and related functions are >> really useless codes. but people have done that before, then we have >> no way except following. >> u300_gpio_exit never gets chance to run and when we disassemble >> vmlinux, u300_gpio_exit() ?function should be not in the final binary >> at all, just a symbol name is left. > > I know. I can make the Kconfig options tristate if it makes you feel > better... what i feel headache is that it is really difficult and unpredicted for an internal gpio driver to be removable in lots of read products because gpio is probably the last bottom module other drivers need. even it can be called in arch/arm/plat(mach). i am not sure whether i am thinking right. gpio and pinmux are more things of bottom level APIs like dma/clock tree but not like device drivers. but i really think you have sent a great pinmux core framework. we once thought we could have a plat-common above all plat-xxx/mach-xxx, and let the plat-common provide the cores of dma, clk, gpio, pinmux(pinmux core from you), for example, all common API and abstract level codes like gpio_request can be there, and SoCs just implement some hardware-related callbacks required by plat-common in themselves plat-xxx . > > Linus Walleij > ^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio 2011-05-19 14:05 ` Barry Song @ 2011-05-20 6:58 ` Grant Likely -1 siblings, 0 replies; 57+ messages in thread From: Grant Likely @ 2011-05-20 6:58 UTC (permalink / raw) To: Barry Song Cc: Linus Walleij, Linus Walleij, linux-kernel, linux-arm-kernel, Lee Jones, Jonas Aaberg On Thu, May 19, 2011 at 10:05:25PM +0800, Barry Song wrote: > 2011/5/19 Linus Walleij <linus.walleij@linaro.org>: > > On Thu, May 19, 2011 at 2:35 PM, Barry Song <21cnbao@gmail.com> wrote: > >> 2011/5/19 Linus Walleij <linus.walleij@linaro.org>: > >>> On Thu, May 19, 2011 at 1:38 PM, Barry Song <21cnbao@gmail.com> wrote: > >>>> > >>>> looks like the driver can't be a real module, is the module_exit > >>>> suitable? it looks strange module_exit plays together with > >>>> arch_initcall. > >>> > >>> It's a rather common design pattern in the kernel for early > >>> platform drivers. Either the dependencies are resolved by the > >>> different initlevels or they are resolved in probe order with > >>> loadable modules. Module load will call all initlevels in order. > >>> > >>> It is not elegant but it is common. > >> > >> Linus, thanks for your reply. module_exit and related functions are > >> really useless codes. but people have done that before, then we have > >> no way except following. > >> u300_gpio_exit never gets chance to run and when we disassemble > >> vmlinux, u300_gpio_exit() function should be not in the final binary > >> at all, just a symbol name is left. > > > > I know. I can make the Kconfig options tristate if it makes you feel > > better... > what i feel headache is that it is really difficult and unpredicted > for an internal gpio driver to be removable in lots of read products > because gpio is probably the last bottom module other drivers need. > even it can be called in arch/arm/plat(mach). > > i am not sure whether i am thinking right. gpio and pinmux are more > things of bottom level APIs like dma/clock tree but not like device > drivers. but i really think you have sent a great pinmux core > framework. > No, gpio controllers are just another set of devices, albeit really low level devices that lots of other things depend on. The Linux model does and should support loading/unloading of GPIO drivers providing there is nothing using them. So, yes, in a lot of cases unloading them is simply not possible because board support code depends on them at some point in early boot, but that doesn't mean that they should be treated differently than any other drivers. Oh, and just to be clear, there are also use cases where really low level code has to go and poke GPIO devices directly before any of the driver model subsystems are up and running. That is a different use-case and it is not what I'm talking about here. g. > we once thought we could have a plat-common above all > plat-xxx/mach-xxx, and let the plat-common provide the cores of dma, > clk, gpio, pinmux(pinmux core from you), for example, all common API > and abstract level codes like gpio_request can be there, and SoCs just > implement some hardware-related callbacks required by plat-common in > themselves plat-xxx . > > > > > Linus Walleij > > ^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-05-20 6:58 ` Grant Likely 0 siblings, 0 replies; 57+ messages in thread From: Grant Likely @ 2011-05-20 6:58 UTC (permalink / raw) To: linux-arm-kernel On Thu, May 19, 2011 at 10:05:25PM +0800, Barry Song wrote: > 2011/5/19 Linus Walleij <linus.walleij@linaro.org>: > > On Thu, May 19, 2011 at 2:35 PM, Barry Song <21cnbao@gmail.com> wrote: > >> 2011/5/19 Linus Walleij <linus.walleij@linaro.org>: > >>> On Thu, May 19, 2011 at 1:38 PM, Barry Song <21cnbao@gmail.com> wrote: > >>>> > >>>> looks like the driver can't be a real module, is the module_exit > >>>> suitable? it looks strange module_exit plays together with > >>>> arch_initcall. > >>> > >>> It's a rather common design pattern in the kernel for early > >>> platform drivers. Either the dependencies are resolved by the > >>> different initlevels or they are resolved in probe order with > >>> loadable modules. Module load will call all initlevels in order. > >>> > >>> It is not elegant but it is common. > >> > >> Linus, thanks for your reply. module_exit and related functions are > >> really useless codes. but people have done that before, then we have > >> no way except following. > >> u300_gpio_exit never gets chance to run and when we disassemble > >> vmlinux, u300_gpio_exit() ?function should be not in the final binary > >> at all, just a symbol name is left. > > > > I know. I can make the Kconfig options tristate if it makes you feel > > better... > what i feel headache is that it is really difficult and unpredicted > for an internal gpio driver to be removable in lots of read products > because gpio is probably the last bottom module other drivers need. > even it can be called in arch/arm/plat(mach). > > i am not sure whether i am thinking right. gpio and pinmux are more > things of bottom level APIs like dma/clock tree but not like device > drivers. but i really think you have sent a great pinmux core > framework. > No, gpio controllers are just another set of devices, albeit really low level devices that lots of other things depend on. The Linux model does and should support loading/unloading of GPIO drivers providing there is nothing using them. So, yes, in a lot of cases unloading them is simply not possible because board support code depends on them at some point in early boot, but that doesn't mean that they should be treated differently than any other drivers. Oh, and just to be clear, there are also use cases where really low level code has to go and poke GPIO devices directly before any of the driver model subsystems are up and running. That is a different use-case and it is not what I'm talking about here. g. > we once thought we could have a plat-common above all > plat-xxx/mach-xxx, and let the plat-common provide the cores of dma, > clk, gpio, pinmux(pinmux core from you), for example, all common API > and abstract level codes like gpio_request can be there, and SoCs just > implement some hardware-related callbacks required by plat-common in > themselves plat-xxx . > > > > > Linus Walleij > > ^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio 2011-05-19 12:25 ` Linus Walleij @ 2011-05-20 6:52 ` Grant Likely -1 siblings, 0 replies; 57+ messages in thread From: Grant Likely @ 2011-05-20 6:52 UTC (permalink / raw) To: Linus Walleij Cc: Barry Song, Linus Walleij, linux-kernel, linux-arm-kernel, Lee Jones, Jonas Aaberg On Thu, May 19, 2011 at 02:25:47PM +0200, Linus Walleij wrote: > On Thu, May 19, 2011 at 1:38 PM, Barry Song <21cnbao@gmail.com> wrote: > > >> -arch_initcall(u300_gpio_init); > >> -module_exit(u300_gpio_exit); > >> > > looks like the driver can't be a real module, is the module_exit > > suitable? it looks strange module_exit plays together with > > arch_initcall. > > It's a rather common design pattern in the kernel for early > platform drivers. Either the dependencies are resolved by the > different initlevels or they are resolved in probe order with > loadable modules. Module load will call all initlevels in order. > > It is not elegant but it is common. but it does need to be fixed. Unfortunately it is not simple. What is needed is a generic deferral or ability for drivers to declare dependences on other devices beyond their immediate parent. I've thought about this a bit on and off over the last year, but I haven't actually sat down to try and hack anything out yet. g. ^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-05-20 6:52 ` Grant Likely 0 siblings, 0 replies; 57+ messages in thread From: Grant Likely @ 2011-05-20 6:52 UTC (permalink / raw) To: linux-arm-kernel On Thu, May 19, 2011 at 02:25:47PM +0200, Linus Walleij wrote: > On Thu, May 19, 2011 at 1:38 PM, Barry Song <21cnbao@gmail.com> wrote: > > >> -arch_initcall(u300_gpio_init); > >> -module_exit(u300_gpio_exit); > >> > > looks like the driver can't be a real module, is the module_exit > > suitable? it looks strange module_exit plays together with > > arch_initcall. > > It's a rather common design pattern in the kernel for early > platform drivers. Either the dependencies are resolved by the > different initlevels or they are resolved in probe order with > loadable modules. Module load will call all initlevels in order. > > It is not elegant but it is common. but it does need to be fixed. Unfortunately it is not simple. What is needed is a generic deferral or ability for drivers to declare dependences on other devices beyond their immediate parent. I've thought about this a bit on and off over the last year, but I haven't actually sat down to try and hack anything out yet. g. ^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio 2011-05-20 6:52 ` Grant Likely @ 2011-05-20 7:46 ` Linus Walleij -1 siblings, 0 replies; 57+ messages in thread From: Linus Walleij @ 2011-05-20 7:46 UTC (permalink / raw) To: Grant Likely Cc: Jonas Aaberg, Barry Song, linux-kernel, Lee Jones, linux-arm-kernel, Arjan van de Ven 2011/5/20 Grant Likely <grant.likely@secretlab.ca>: > On Thu, May 19, 2011 at 02:25:47PM +0200, Linus Walleij wrote: >> On Thu, May 19, 2011 at 1:38 PM, Barry Song <21cnbao@gmail.com> wrote: >> >> >> -arch_initcall(u300_gpio_init); >> >> -module_exit(u300_gpio_exit); >> >> >> > looks like the driver can't be a real module, is the module_exit >> > suitable? it looks strange module_exit plays together with >> > arch_initcall. >> >> It's a rather common design pattern in the kernel for early >> platform drivers. Either the dependencies are resolved by the >> different initlevels or they are resolved in probe order with >> loadable modules. Module load will call all initlevels in order. >> >> It is not elegant but it is common. > > but it does need to be fixed. Unfortunately it is not simple. What > is needed is a generic deferral or ability for drivers to declare > dependences on other devices beyond their immediate parent. > > I've thought about this a bit on and off over the last year, but I > haven't actually sat down to try and hack anything out yet. Sounds like it needs to do for the kernel what systemd does for userspace in my ears. And I wholeheartedly agree it needs fixing. A main concern would be that these dependencies are currently implicit, Arjan did a great job on fixing some of it by parallellizing initilization of drivers per initlevel and sync it at at the end of each level, doing a clean dependecy resolution would do away with all the initlevels eventually. Yours, Linus Walleij ^ permalink raw reply [flat|nested] 57+ messages in thread
* [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio @ 2011-05-20 7:46 ` Linus Walleij 0 siblings, 0 replies; 57+ messages in thread From: Linus Walleij @ 2011-05-20 7:46 UTC (permalink / raw) To: linux-arm-kernel 2011/5/20 Grant Likely <grant.likely@secretlab.ca>: > On Thu, May 19, 2011 at 02:25:47PM +0200, Linus Walleij wrote: >> On Thu, May 19, 2011 at 1:38 PM, Barry Song <21cnbao@gmail.com> wrote: >> >> >> -arch_initcall(u300_gpio_init); >> >> -module_exit(u300_gpio_exit); >> >> >> > looks like the driver can't be a real module, is the module_exit >> > suitable? it looks strange module_exit plays together with >> > arch_initcall. >> >> It's a rather common design pattern in the kernel for early >> platform drivers. Either the dependencies are resolved by the >> different initlevels or they are resolved in probe order with >> loadable modules. Module load will call all initlevels in order. >> >> It is not elegant but it is common. > > but it does need to be fixed. ?Unfortunately it is not simple. ?What > is needed is a generic deferral or ability for drivers to declare > dependences on other devices beyond their immediate parent. > > I've thought about this a bit on and off over the last year, but I > haven't actually sat down to try and hack anything out yet. Sounds like it needs to do for the kernel what systemd does for userspace in my ears. And I wholeheartedly agree it needs fixing. A main concern would be that these dependencies are currently implicit, Arjan did a great job on fixing some of it by parallellizing initilization of drivers per initlevel and sync it at at the end of each level, doing a clean dependecy resolution would do away with all the initlevels eventually. Yours, Linus Walleij ^ permalink raw reply [flat|nested] 57+ messages in thread
end of thread, other threads:[~2011-05-21 13:03 UTC | newest] Thread overview: 57+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2011-04-27 13:13 [PATCH 02/10] mach-u300: rewrite gpio driver, move to drivers/gpio Linus Walleij 2011-04-27 13:13 ` Linus Walleij 2011-04-27 18:23 ` H Hartley Sweeten 2011-04-27 18:23 ` H Hartley Sweeten 2011-04-28 7:07 ` Linus Walleij 2011-04-28 7:07 ` Linus Walleij 2011-04-28 7:10 ` Linus Walleij 2011-04-28 7:10 ` Linus Walleij 2011-04-28 17:41 ` H Hartley Sweeten 2011-04-28 17:41 ` H Hartley Sweeten 2011-05-13 14:51 ` Linus Walleij 2011-05-13 14:51 ` Linus Walleij 2011-05-19 8:56 ` Shawn Guo 2011-05-19 8:56 ` Shawn Guo 2011-05-19 12:21 ` Linus Walleij 2011-05-19 12:21 ` Linus Walleij 2011-05-19 13:56 ` Shawn Guo 2011-05-19 13:56 ` Shawn Guo 2011-05-19 19:11 ` Sascha Hauer 2011-05-19 19:11 ` Sascha Hauer 2011-05-19 19:30 ` Nicolas Pitre 2011-05-19 19:30 ` Nicolas Pitre 2011-05-20 3:18 ` Shawn Guo 2011-05-20 3:18 ` Shawn Guo 2011-05-20 3:43 ` Kyungmin Park 2011-05-20 3:43 ` Kyungmin Park 2011-05-20 3:54 ` Nicolas Pitre 2011-05-20 3:54 ` Nicolas Pitre 2011-05-19 21:18 ` H Hartley Sweeten 2011-05-19 21:18 ` H Hartley Sweeten 2011-05-20 1:50 ` Jamie Iles 2011-05-20 1:50 ` Jamie Iles 2011-05-20 22:07 ` H Hartley Sweeten 2011-05-20 22:07 ` H Hartley Sweeten 2011-05-21 13:03 ` Jamie Iles 2011-05-21 13:03 ` Jamie Iles 2011-05-20 7:01 ` Grant Likely 2011-05-20 7:01 ` Grant Likely 2011-05-20 7:47 ` Linus Walleij 2011-05-20 7:47 ` Linus Walleij 2011-05-19 11:11 ` Barry Song 2011-05-19 11:38 ` Barry Song 2011-05-19 11:38 ` Barry Song 2011-05-19 12:25 ` Linus Walleij 2011-05-19 12:25 ` Linus Walleij 2011-05-19 12:35 ` Barry Song 2011-05-19 12:35 ` Barry Song 2011-05-19 13:17 ` Linus Walleij 2011-05-19 13:17 ` Linus Walleij 2011-05-19 14:05 ` Barry Song 2011-05-19 14:05 ` Barry Song 2011-05-20 6:58 ` Grant Likely 2011-05-20 6:58 ` Grant Likely 2011-05-20 6:52 ` Grant Likely 2011-05-20 6:52 ` Grant Likely 2011-05-20 7:46 ` Linus Walleij 2011-05-20 7:46 ` Linus Walleij
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.