gpio: move U300 GPIO driver to drivers/gpio
authorLinus Walleij <linus.walleij@linaro.org>
Tue, 24 May 2011 21:06:52 +0000 (23:06 +0200)
committerGrant Likely <grant.likely@secretlab.ca>
Thu, 26 May 2011 23:29:33 +0000 (17:29 -0600)
This moves the U300 GPIO driver out of arch/arm/mach-u300 and into
the desired location indicated by the subsystem maintainer.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
arch/arm/mach-u300/Makefile
arch/arm/mach-u300/gpio.c [deleted file]
drivers/gpio/Makefile
drivers/gpio/gpio-u300.c [new file with mode: 0644]

index fab46fe9a71f7b7061d2aa9e8f485f1449b625f1..8fd354aaf0a7f5c9aa309ee69b490e604868fc65 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the linux kernel, U300 machine.
 #
 
-obj-y          := core.o clock.o timer.o gpio.o padmux.o
+obj-y          := core.o clock.o timer.o padmux.o
 obj-m          :=
 obj-n          :=
 obj-           :=
diff --git a/arch/arm/mach-u300/gpio.c b/arch/arm/mach-u300/gpio.c
deleted file mode 100644 (file)
index d927901..0000000
+++ /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");
index d92ce3a62ae593aedbaee5681ad3acc4485a8e4d..27a22086739b541cbafd50828f503931613dd6c5 100644 (file)
@@ -34,6 +34,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_MACH_U300)                += gpio-u300.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/gpio-u300.c b/drivers/gpio/gpio-u300.c
new file mode 100644 (file)
index 0000000..d927901
--- /dev/null
@@ -0,0 +1,700 @@
+/*
+ *
+ * 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");