summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-davinci/gpio.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-davinci/gpio.c')
-rw-r--r--arch/arm/mach-davinci/gpio.c160
1 files changed, 103 insertions, 57 deletions
diff --git a/arch/arm/mach-davinci/gpio.c b/arch/arm/mach-davinci/gpio.c
index 744755b53236..bf0ff587e46a 100644
--- a/arch/arm/mach-davinci/gpio.c
+++ b/arch/arm/mach-davinci/gpio.c
@@ -20,46 +20,92 @@
#include <asm/mach/irq.h>
-static DEFINE_SPINLOCK(gpio_lock);
-
-struct davinci_gpio {
- struct gpio_chip chip;
- struct gpio_controller *__iomem regs;
- int irq_base;
+struct davinci_gpio_regs {
+ u32 dir;
+ u32 out_data;
+ u32 set_data;
+ u32 clr_data;
+ u32 in_data;
+ u32 set_rising;
+ u32 clr_rising;
+ u32 set_falling;
+ u32 clr_falling;
+ u32 intstat;
};
-static struct davinci_gpio chips[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)];
+#define chip2controller(chip) \
+ container_of(chip, struct davinci_gpio_controller, chip)
+
+static struct davinci_gpio_controller chips[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)];
+static void __iomem *gpio_base;
+
+static struct davinci_gpio_regs __iomem __init *gpio2regs(unsigned gpio)
+{
+ void __iomem *ptr;
+
+ if (gpio < 32 * 1)
+ ptr = gpio_base + 0x10;
+ else if (gpio < 32 * 2)
+ ptr = gpio_base + 0x38;
+ else if (gpio < 32 * 3)
+ ptr = gpio_base + 0x60;
+ else if (gpio < 32 * 4)
+ ptr = gpio_base + 0x88;
+ else if (gpio < 32 * 5)
+ ptr = gpio_base + 0xb0;
+ else
+ ptr = NULL;
+ return ptr;
+}
-/* create a non-inlined version */
-static struct gpio_controller __iomem * __init gpio2controller(unsigned gpio)
+static inline struct davinci_gpio_regs __iomem *irq2regs(int irq)
{
- return __gpio_to_controller(gpio);
+ struct davinci_gpio_regs __iomem *g;
+
+ g = (__force struct davinci_gpio_regs __iomem *)get_irq_chip_data(irq);
+
+ return g;
}
static int __init davinci_gpio_irq_setup(void);
/*--------------------------------------------------------------------------*/
-/*
- * board setup code *MUST* set PINMUX0 and PINMUX1 as
- * needed, and enable the GPIO clock.
- */
-
-static int davinci_direction_in(struct gpio_chip *chip, unsigned offset)
+/* board setup code *MUST* setup pinmux and enable the GPIO clock. */
+static inline int __davinci_direction(struct gpio_chip *chip,
+ unsigned offset, bool out, int value)
{
- struct davinci_gpio *d = container_of(chip, struct davinci_gpio, chip);
- struct gpio_controller *__iomem g = d->regs;
+ struct davinci_gpio_controller *d = chip2controller(chip);
+ struct davinci_gpio_regs __iomem *g = d->regs;
+ unsigned long flags;
u32 temp;
+ u32 mask = 1 << offset;
- spin_lock(&gpio_lock);
+ spin_lock_irqsave(&d->lock, flags);
temp = __raw_readl(&g->dir);
- temp |= (1 << offset);
+ if (out) {
+ temp &= ~mask;
+ __raw_writel(mask, value ? &g->set_data : &g->clr_data);
+ } else {
+ temp |= mask;
+ }
__raw_writel(temp, &g->dir);
- spin_unlock(&gpio_lock);
+ spin_unlock_irqrestore(&d->lock, flags);
return 0;
}
+static int davinci_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+ return __davinci_direction(chip, offset, false, 0);
+}
+
+static int
+davinci_direction_out(struct gpio_chip *chip, unsigned offset, int value)
+{
+ return __davinci_direction(chip, offset, true, value);
+}
+
/*
* Read the pin's value (works even if it's set up as output);
* returns zero/nonzero.
@@ -69,37 +115,20 @@ static int davinci_direction_in(struct gpio_chip *chip, unsigned offset)
*/
static int davinci_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct davinci_gpio *d = container_of(chip, struct davinci_gpio, chip);
- struct gpio_controller *__iomem g = d->regs;
+ struct davinci_gpio_controller *d = chip2controller(chip);
+ struct davinci_gpio_regs __iomem *g = d->regs;
return (1 << offset) & __raw_readl(&g->in_data);
}
-static int
-davinci_direction_out(struct gpio_chip *chip, unsigned offset, int value)
-{
- struct davinci_gpio *d = container_of(chip, struct davinci_gpio, chip);
- struct gpio_controller *__iomem g = d->regs;
- u32 temp;
- u32 mask = 1 << offset;
-
- spin_lock(&gpio_lock);
- 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;
-}
-
/*
* 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 davinci_gpio *d = container_of(chip, struct davinci_gpio, chip);
- struct gpio_controller *__iomem g = d->regs;
+ struct davinci_gpio_controller *d = chip2controller(chip);
+ struct davinci_gpio_regs __iomem *g = d->regs;
__raw_writel((1 << offset), value ? &g->set_data : &g->clr_data);
}
@@ -109,6 +138,10 @@ static int __init davinci_gpio_setup(void)
int i, base;
unsigned ngpio;
struct davinci_soc_info *soc_info = &davinci_soc_info;
+ struct davinci_gpio_regs *regs;
+
+ if (soc_info->gpio_type != GPIO_TYPE_DAVINCI)
+ return 0;
/*
* The gpio banks conceptually expose a segmented bitmap,
@@ -124,6 +157,10 @@ static int __init davinci_gpio_setup(void)
if (WARN_ON(DAVINCI_N_GPIO < ngpio))
ngpio = DAVINCI_N_GPIO;
+ gpio_base = ioremap(soc_info->gpio_base, SZ_4K);
+ if (WARN_ON(!gpio_base))
+ return -ENOMEM;
+
for (i = 0, base = 0; base < ngpio; i++, base += 32) {
chips[i].chip.label = "DaVinci";
@@ -137,11 +174,20 @@ static int __init davinci_gpio_setup(void)
if (chips[i].chip.ngpio > 32)
chips[i].chip.ngpio = 32;
- chips[i].regs = gpio2controller(base);
+ spin_lock_init(&chips[i].lock);
+
+ regs = gpio2regs(base);
+ chips[i].regs = regs;
+ chips[i].set_data = &regs->set_data;
+ chips[i].clr_data = &regs->clr_data;
+ chips[i].in_data = &regs->in_data;
gpiochip_add(&chips[i].chip);
}
+ soc_info->gpio_ctlrs = chips;
+ soc_info->gpio_ctlrs_num = DIV_ROUND_UP(ngpio, 32);
+
davinci_gpio_irq_setup();
return 0;
}
@@ -161,7 +207,7 @@ pure_initcall(davinci_gpio_setup);
static void gpio_irq_disable(unsigned irq)
{
- struct gpio_controller *__iomem g = get_irq_chip_data(irq);
+ struct davinci_gpio_regs __iomem *g = irq2regs(irq);
u32 mask = (u32) get_irq_data(irq);
__raw_writel(mask, &g->clr_falling);
@@ -170,7 +216,7 @@ static void gpio_irq_disable(unsigned irq)
static void gpio_irq_enable(unsigned irq)
{
- struct gpio_controller *__iomem g = get_irq_chip_data(irq);
+ struct davinci_gpio_regs __iomem *g = irq2regs(irq);
u32 mask = (u32) get_irq_data(irq);
unsigned status = irq_desc[irq].status;
@@ -186,7 +232,7 @@ static void gpio_irq_enable(unsigned irq)
static int gpio_irq_type(unsigned irq, unsigned trigger)
{
- struct gpio_controller *__iomem g = get_irq_chip_data(irq);
+ struct davinci_gpio_regs __iomem *g = irq2regs(irq);
u32 mask = (u32) get_irq_data(irq);
if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
@@ -215,7 +261,7 @@ static struct irq_chip gpio_irqchip = {
static void
gpio_irq_handler(unsigned irq, struct irq_desc *desc)
{
- struct gpio_controller *__iomem g = get_irq_chip_data(irq);
+ struct davinci_gpio_regs __iomem *g = irq2regs(irq);
u32 mask = 0xffff;
/* we only care about one bank */
@@ -253,7 +299,7 @@ gpio_irq_handler(unsigned irq, struct irq_desc *desc)
static int gpio_to_irq_banked(struct gpio_chip *chip, unsigned offset)
{
- struct davinci_gpio *d = container_of(chip, struct davinci_gpio, chip);
+ struct davinci_gpio_controller *d = chip2controller(chip);
if (d->irq_base >= 0)
return d->irq_base + offset;
@@ -276,7 +322,7 @@ static int gpio_to_irq_unbanked(struct gpio_chip *chip, unsigned offset)
static int gpio_irq_type_unbanked(unsigned irq, unsigned trigger)
{
- struct gpio_controller *__iomem g = get_irq_chip_data(irq);
+ struct davinci_gpio_regs __iomem *g = irq2regs(irq);
u32 mask = (u32) get_irq_data(irq);
if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
@@ -305,7 +351,7 @@ static int __init davinci_gpio_irq_setup(void)
u32 binten = 0;
unsigned ngpio, bank_irq;
struct davinci_soc_info *soc_info = &davinci_soc_info;
- struct gpio_controller *__iomem g;
+ struct davinci_gpio_regs __iomem *g;
ngpio = soc_info->gpio_num;
@@ -354,7 +400,7 @@ static int __init davinci_gpio_irq_setup(void)
gpio_irqchip_unbanked.set_type = gpio_irq_type_unbanked;
/* default trigger: both edges */
- g = gpio2controller(0);
+ g = gpio2regs(0);
__raw_writel(~0, &g->set_falling);
__raw_writel(~0, &g->set_rising);
@@ -362,7 +408,7 @@ static int __init davinci_gpio_irq_setup(void)
for (gpio = 0; gpio < soc_info->gpio_unbanked; gpio++, irq++) {
set_irq_chip(irq, &gpio_irqchip_unbanked);
set_irq_data(irq, (void *) __gpio_mask(gpio));
- set_irq_chip_data(irq, g);
+ set_irq_chip_data(irq, (__force void *) g);
irq_desc[irq].status |= IRQ_TYPE_EDGE_BOTH;
}
@@ -379,18 +425,18 @@ static int __init davinci_gpio_irq_setup(void)
unsigned i;
/* disabled by default, enabled only as needed */
- g = gpio2controller(gpio);
+ g = gpio2regs(gpio);
__raw_writel(~0, &g->clr_falling);
__raw_writel(~0, &g->clr_rising);
/* set up all irqs in this bank */
set_irq_chained_handler(bank_irq, gpio_irq_handler);
- set_irq_chip_data(bank_irq, g);
- set_irq_data(bank_irq, (void *)irq);
+ set_irq_chip_data(bank_irq, (__force void *) g);
+ set_irq_data(bank_irq, (void *) irq);
for (i = 0; i < 16 && gpio < ngpio; i++, irq++, gpio++) {
set_irq_chip(irq, &gpio_irqchip);
- set_irq_chip_data(irq, g);
+ set_irq_chip_data(irq, (__force void *) g);
set_irq_data(irq, (void *) __gpio_mask(gpio));
set_irq_handler(irq, handle_simple_irq);
set_irq_flags(irq, IRQF_VALID);
@@ -403,7 +449,7 @@ done:
/* BINTEN -- per-bank interrupt enable. genirq would also let these
* bits be set/cleared dynamically.
*/
- __raw_writel(binten, soc_info->gpio_base + 0x08);
+ __raw_writel(binten, gpio_base + 0x08);
printk(KERN_INFO "DaVinci: %d gpio irqs\n", irq - gpio_to_irq(0));
OpenPOWER on IntegriCloud