Skip to content

Commit

Permalink
ARM: DaVinci: SOC GPIOs use gpiolib
Browse files Browse the repository at this point in the history
Switch DaVinci SOC gpios over to using the new GPIO library, so it can
access GPIO expanders and other non-SOC GPIOs using the same calls.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
  • Loading branch information
David Brownell authored and Kevin Hilman committed Sep 17, 2008
1 parent ac7643e commit dce1115
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 101 deletions.
1 change: 1 addition & 0 deletions arch/arm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,7 @@ config ARCH_DAVINCI
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
select GENERIC_GPIO
select ARCH_REQUIRE_GPIOLIB
select HAVE_CLK
help
Support for TI's DaVinci platform.
Expand Down
133 changes: 71 additions & 62 deletions arch/arm/mach-davinci/gpio.c
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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);
Expand All @@ -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.
Expand Down
73 changes: 34 additions & 39 deletions arch/arm/mach-davinci/include/mach/gpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#define __DAVINCI_GPIO_H

#include <linux/io.h>
#include <asm-generic/gpio.h>
#include <mach/hardware.h>

/*
Expand All @@ -27,13 +28,16 @@
* need to pay attention to PINMUX0 and PINMUX1 to be sure those pins are
* used as gpios, not with other peripherals.
*
* GPIOs are numbered 0..(DAVINCI_N_GPIO-1). For documentation, and maybe
* for later updates, code should write GPIO(N) or:
* On-chip GPIOs are numbered 0..(DAVINCI_N_GPIO-1). For documentation,
* and maybe for later updates, code should write GPIO(N) or:
* - GPIOV18(N) for 1.8V pins, N in 0..53; same as GPIO(0)..GPIO(53)
* - GPIOV33(N) for 3.3V pins, N in 0..17; same as GPIO(54)..GPIO(70)
*
* For GPIO IRQs use gpio_to_irq(GPIO(N)) or gpio_to_irq(GPIOV33(N)) etc
* for now, that's != GPIO(N)
*
* GPIOs can also be on external chips, numbered after the ones built-in
* to the DaVinci chip. For now, they won't be usable as IRQ sources.
*/
#define GPIO(X) (X) /* 0 <= X <= 70 */
#define GPIOV18(X) (X) /* 1.8V i/o; 0 <= X <= 53 */
Expand Down Expand Up @@ -67,11 +71,11 @@ __gpio_to_controller(unsigned gpio)
void *__iomem ptr;

if (gpio < 32)
ptr = (void *__iomem)IO_ADDRESS(DAVINCI_GPIO_BASE + 0x10);
ptr = IO_ADDRESS(DAVINCI_GPIO_BASE + 0x10);
else if (gpio < 64)
ptr = (void *__iomem)IO_ADDRESS(DAVINCI_GPIO_BASE + 0x38);
ptr = IO_ADDRESS(DAVINCI_GPIO_BASE + 0x38);
else if (gpio < DAVINCI_N_GPIO)
ptr = (void *__iomem)IO_ADDRESS(DAVINCI_GPIO_BASE + 0x60);
ptr = IO_ADDRESS(DAVINCI_GPIO_BASE + 0x60);
else
ptr = NULL;
return ptr;
Expand All @@ -83,25 +87,17 @@ static inline u32 __gpio_mask(unsigned gpio)
}

/* The get/set/clear functions will inline when called with constant
* parameters, for low-overhead bitbanging. Illegal constant parameters
* cause link-time errors.
* parameters referencing built-in GPIOs, for low-overhead bitbanging.
*
* Otherwise, calls with variable parameters use outlined functions.
* Otherwise, calls with variable parameters or referencing external
* GPIOs (e.g. on GPIO expander chips) use outlined functions.
*/
extern int __error_inval_gpio(void);

extern void __gpio_set(unsigned gpio, int value);
extern int __gpio_get(unsigned gpio);

static inline void gpio_set_value(unsigned gpio, int value)
{
if (__builtin_constant_p(value)) {
if (__builtin_constant_p(value) && gpio < DAVINCI_N_GPIO) {
struct gpio_controller *__iomem g;
u32 mask;

if (gpio >= DAVINCI_N_GPIO)
__error_inval_gpio();

g = __gpio_to_controller(gpio);
mask = __gpio_mask(gpio);
if (value)
Expand All @@ -111,48 +107,47 @@ static inline void gpio_set_value(unsigned gpio, int value)
return;
}

__gpio_set(gpio, value);
__gpio_set_value(gpio, value);
}

/* Returns zero or nonzero; works for gpios configured as inputs OR
* as outputs.
* as outputs, at least for built-in GPIOs.
*
* NOTE: changes in reported values are synchronized to the GPIO clock.
* This is most easily seen after calling gpio_set_value() and then immediatly
* gpio_get_value(), where the gpio_get_value() would return the old value
* until the GPIO clock ticks and the new value gets latched.
* NOTE: for built-in GPIOs, changes in reported values are synchronized
* to the GPIO clock. This is easily seen after calling gpio_set_value()
* and then immediately gpio_get_value(), where the gpio_get_value() will
* return the old value until the GPIO clock ticks and the new value gets
* latched.
*/

static inline int gpio_get_value(unsigned gpio)
{
struct gpio_controller *__iomem g;

if (!__builtin_constant_p(gpio))
return __gpio_get(gpio);
struct gpio_controller *__iomem g;

if (gpio >= DAVINCI_N_GPIO)
return __error_inval_gpio();
if (!__builtin_constant_p(gpio) || gpio >= DAVINCI_N_GPIO)
return __gpio_get_value(gpio);

g = __gpio_to_controller(gpio);
return !!(__gpio_mask(gpio) & __raw_readl(&g->in_data));
return __gpio_mask(gpio) & __raw_readl(&g->in_data);
}

/* powerup default direction is IN */
extern int gpio_direction_input(unsigned gpio);
extern int gpio_direction_output(unsigned gpio, int value);

#include <asm-generic/gpio.h> /* cansleep wrappers */

extern int gpio_request(unsigned gpio, const char *tag);
extern void gpio_free(unsigned gpio);
static inline int gpio_cansleep(unsigned gpio)
{
if (__builtin_constant_p(gpio) && gpio < DAVINCI_N_GPIO)
return 0;
else
return __gpio_cansleep(gpio);
}

static inline int gpio_to_irq(unsigned gpio)
{
if (gpio >= DAVINCI_N_GPIO)
return -EINVAL;
return DAVINCI_N_AINTC_IRQ + gpio;
}

static inline int irq_to_gpio(unsigned irq)
{
/* caller guarantees gpio_to_irq() succeeded */
return irq - DAVINCI_N_AINTC_IRQ;
}

Expand Down

0 comments on commit dce1115

Please sign in to comment.