|
@@ -1,7 +1,7 @@
|
|
|
/*
|
|
|
* TI DaVinci GPIO Support
|
|
|
*
|
|
|
- * Copyright (c) 2006 David Brownell
|
|
|
+ * Copyright (c) 2006-2007 David Brownell
|
|
|
* Copyright (c) 2007, MontaVista Software, Inc. <source@mvista.com>
|
|
|
*
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
@@ -26,47 +26,45 @@
|
|
|
|
|
|
#include <asm/mach/irq.h>
|
|
|
|
|
|
-static DEFINE_SPINLOCK(gpio_lock);
|
|
|
-static DECLARE_BITMAP(gpio_in_use, DAVINCI_N_GPIO);
|
|
|
|
|
|
-int gpio_request(unsigned gpio, const char *tag)
|
|
|
-{
|
|
|
- if (gpio >= DAVINCI_N_GPIO)
|
|
|
- return -EINVAL;
|
|
|
+static DEFINE_SPINLOCK(gpio_lock);
|
|
|
|
|
|
- if (test_and_set_bit(gpio, gpio_in_use))
|
|
|
- return -EBUSY;
|
|
|
+struct davinci_gpio {
|
|
|
+ struct gpio_chip chip;
|
|
|
+ struct gpio_controller *__iomem regs;
|
|
|
+};
|
|
|
|
|
|
- return 0;
|
|
|
-}
|
|
|
-EXPORT_SYMBOL(gpio_request);
|
|
|
+static struct davinci_gpio chips[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)];
|
|
|
|
|
|
-void gpio_free(unsigned gpio)
|
|
|
-{
|
|
|
- if (gpio >= DAVINCI_N_GPIO)
|
|
|
- return;
|
|
|
-
|
|
|
- clear_bit(gpio, gpio_in_use);
|
|
|
-}
|
|
|
-EXPORT_SYMBOL(gpio_free);
|
|
|
|
|
|
/* create a non-inlined version */
|
|
|
-static struct gpio_controller *__iomem gpio2controller(unsigned gpio)
|
|
|
+static struct gpio_controller *__iomem __init gpio2controller(unsigned gpio)
|
|
|
{
|
|
|
return __gpio_to_controller(gpio);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+/*--------------------------------------------------------------------------*/
|
|
|
+
|
|
|
/*
|
|
|
- * Assuming the pin is muxed as a gpio output, set its output value.
|
|
|
+ * board setup code *MUST* set PINMUX0 and PINMUX1 as
|
|
|
+ * needed, and enable the GPIO clock.
|
|
|
*/
|
|
|
-void __gpio_set(unsigned gpio, int value)
|
|
|
+
|
|
|
+static int davinci_direction_in(struct gpio_chip *chip, unsigned offset)
|
|
|
{
|
|
|
- struct gpio_controller *__iomem g = gpio2controller(gpio);
|
|
|
+ struct davinci_gpio *d = container_of(chip, struct davinci_gpio, chip);
|
|
|
+ struct gpio_controller *__iomem g = d->regs;
|
|
|
+ u32 temp;
|
|
|
|
|
|
- __raw_writel(__gpio_mask(gpio), value ? &g->set_data : &g->clr_data);
|
|
|
-}
|
|
|
-EXPORT_SYMBOL(__gpio_set);
|
|
|
+ spin_lock(&gpio_lock);
|
|
|
+ temp = __raw_readl(&g->dir);
|
|
|
+ temp |= (1 << offset);
|
|
|
+ __raw_writel(temp, &g->dir);
|
|
|
+ spin_unlock(&gpio_lock);
|
|
|
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
/*
|
|
|
* Read the pin's value (works even if it's set up as output);
|
|
@@ -75,61 +73,72 @@ EXPORT_SYMBOL(__gpio_set);
|
|
|
* Note that changes are synched to the GPIO clock, so reading values back
|
|
|
* right after you've set them may give old values.
|
|
|
*/
|
|
|
-int __gpio_get(unsigned gpio)
|
|
|
+static int davinci_gpio_get(struct gpio_chip *chip, unsigned offset)
|
|
|
{
|
|
|
- struct gpio_controller *__iomem g = gpio2controller(gpio);
|
|
|
+ struct davinci_gpio *d = container_of(chip, struct davinci_gpio, chip);
|
|
|
+ struct gpio_controller *__iomem g = d->regs;
|
|
|
|
|
|
- return !!(__gpio_mask(gpio) & __raw_readl(&g->in_data));
|
|
|
+ return (1 << offset) & __raw_readl(&g->in_data);
|
|
|
}
|
|
|
-EXPORT_SYMBOL(__gpio_get);
|
|
|
|
|
|
-
|
|
|
-/*--------------------------------------------------------------------------*/
|
|
|
-
|
|
|
-/*
|
|
|
- * board setup code *MUST* set PINMUX0 and PINMUX1 as
|
|
|
- * needed, and enable the GPIO clock.
|
|
|
- */
|
|
|
-
|
|
|
-int gpio_direction_input(unsigned gpio)
|
|
|
+static int
|
|
|
+davinci_direction_out(struct gpio_chip *chip, unsigned offset, int value)
|
|
|
{
|
|
|
- struct gpio_controller *__iomem g = gpio2controller(gpio);
|
|
|
+ struct davinci_gpio *d = container_of(chip, struct davinci_gpio, chip);
|
|
|
+ struct gpio_controller *__iomem g = d->regs;
|
|
|
u32 temp;
|
|
|
- u32 mask;
|
|
|
-
|
|
|
- if (!g)
|
|
|
- return -EINVAL;
|
|
|
+ u32 mask = 1 << offset;
|
|
|
|
|
|
spin_lock(&gpio_lock);
|
|
|
- mask = __gpio_mask(gpio);
|
|
|
temp = __raw_readl(&g->dir);
|
|
|
- temp |= mask;
|
|
|
+ temp &= ~mask;
|
|
|
+ __raw_writel(mask, value ? &g->set_data : &g->clr_data);
|
|
|
__raw_writel(temp, &g->dir);
|
|
|
spin_unlock(&gpio_lock);
|
|
|
return 0;
|
|
|
}
|
|
|
-EXPORT_SYMBOL(gpio_direction_input);
|
|
|
|
|
|
-int gpio_direction_output(unsigned gpio, int value)
|
|
|
+/*
|
|
|
+ * Assuming the pin is muxed as a gpio output, set its output value.
|
|
|
+ */
|
|
|
+static void
|
|
|
+davinci_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
|
|
{
|
|
|
- struct gpio_controller *__iomem g = gpio2controller(gpio);
|
|
|
- u32 temp;
|
|
|
- u32 mask;
|
|
|
+ struct davinci_gpio *d = container_of(chip, struct davinci_gpio, chip);
|
|
|
+ struct gpio_controller *__iomem g = d->regs;
|
|
|
|
|
|
- if (!g)
|
|
|
- return -EINVAL;
|
|
|
+ __raw_writel((1 << offset), value ? &g->set_data : &g->clr_data);
|
|
|
+}
|
|
|
+
|
|
|
+static int __init davinci_gpio_setup(void)
|
|
|
+{
|
|
|
+ int i, base;
|
|
|
+
|
|
|
+ for (i = 0, base = 0;
|
|
|
+ i < ARRAY_SIZE(chips);
|
|
|
+ i++, base += 32) {
|
|
|
+ chips[i].chip.label = "DaVinci";
|
|
|
+
|
|
|
+ chips[i].chip.direction_input = davinci_direction_in;
|
|
|
+ chips[i].chip.get = davinci_gpio_get;
|
|
|
+ chips[i].chip.direction_output = davinci_direction_out;
|
|
|
+ chips[i].chip.set = davinci_gpio_set;
|
|
|
+
|
|
|
+ chips[i].chip.base = base;
|
|
|
+ chips[i].chip.ngpio = DAVINCI_N_GPIO - base;
|
|
|
+ if (chips[i].chip.ngpio > 32)
|
|
|
+ chips[i].chip.ngpio = 32;
|
|
|
+
|
|
|
+ chips[i].regs = gpio2controller(base);
|
|
|
+
|
|
|
+ gpiochip_add(&chips[i].chip);
|
|
|
+ }
|
|
|
|
|
|
- spin_lock(&gpio_lock);
|
|
|
- mask = __gpio_mask(gpio);
|
|
|
- temp = __raw_readl(&g->dir);
|
|
|
- temp &= ~mask;
|
|
|
- __raw_writel(mask, value ? &g->set_data : &g->clr_data);
|
|
|
- __raw_writel(temp, &g->dir);
|
|
|
- spin_unlock(&gpio_lock);
|
|
|
return 0;
|
|
|
}
|
|
|
-EXPORT_SYMBOL(gpio_direction_output);
|
|
|
+pure_initcall(davinci_gpio_setup);
|
|
|
|
|
|
+/*--------------------------------------------------------------------------*/
|
|
|
/*
|
|
|
* We expect irqs will normally be set up as input pins, but they can also be
|
|
|
* used as output pins ... which is convenient for testing.
|