Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 83037
b: refs/heads/master
c: b98348b
h: refs/heads/master
i:
  83035: c905771
v: v3
  • Loading branch information
David Brownell authored and Linus Torvalds committed Feb 5, 2008
1 parent d58c6c8 commit 806a80b
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 95 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: b72540c30c9c8c2c3f17cae29962cfb50fbe166a
refs/heads/master: b98348bdd08dc4ec11828aa98a78edde15c53cfa
1 change: 1 addition & 0 deletions trunk/arch/avr32/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ config PLATFORM_AT32AP
select SUBARCH_AVR32B
select MMU
select PERFORMANCE_COUNTERS
select HAVE_GPIO_LIB

#
# CPU types
Expand Down
172 changes: 92 additions & 80 deletions trunk/arch/avr32/mach-at32ap/pio.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@
#define MAX_NR_PIO_DEVICES 8

struct pio_device {
struct gpio_chip chip;
void __iomem *regs;
const struct platform_device *pdev;
struct clk *clk;
u32 pinmux_mask;
u32 gpio_mask;
char name[8];
};

Expand Down Expand Up @@ -64,7 +64,8 @@ void __init at32_select_periph(unsigned int pin, unsigned int periph,
goto fail;
}

if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask))) {
if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask)
|| gpiochip_is_requested(&pio->chip, pin_index))) {
printk("%s: pin %u is busy\n", pio->name, pin_index);
goto fail;
}
Expand All @@ -79,9 +80,6 @@ void __init at32_select_periph(unsigned int pin, unsigned int periph,
if (!(flags & AT32_GPIOF_PULLUP))
pio_writel(pio, PUDR, mask);

/* gpio_request NOT allowed */
set_bit(pin_index, &pio->gpio_mask);

return;

fail:
Expand Down Expand Up @@ -130,9 +128,6 @@ void __init at32_select_gpio(unsigned int pin, unsigned long flags)

pio_writel(pio, PER, mask);

/* gpio_request now allowed */
clear_bit(pin_index, &pio->gpio_mask);

return;

fail:
Expand Down Expand Up @@ -166,96 +161,50 @@ void __init at32_reserve_pin(unsigned int pin)

/* GPIO API */

int gpio_request(unsigned int gpio, const char *label)
static int direction_input(struct gpio_chip *chip, unsigned offset)
{
struct pio_device *pio;
unsigned int pin;

pio = gpio_to_pio(gpio);
if (!pio)
return -ENODEV;
struct pio_device *pio = container_of(chip, struct pio_device, chip);
u32 mask = 1 << offset;

pin = gpio & 0x1f;
if (test_and_set_bit(pin, &pio->gpio_mask))
return -EBUSY;
if (!(pio_readl(pio, PSR) & mask))
return -EINVAL;

pio_writel(pio, ODR, mask);
return 0;
}
EXPORT_SYMBOL(gpio_request);

void gpio_free(unsigned int gpio)
static int gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct pio_device *pio;
unsigned int pin;
struct pio_device *pio = container_of(chip, struct pio_device, chip);

pio = gpio_to_pio(gpio);
if (!pio) {
printk(KERN_ERR
"gpio: attempted to free invalid pin %u\n", gpio);
return;
}

pin = gpio & 0x1f;
if (!test_and_clear_bit(pin, &pio->gpio_mask))
printk(KERN_ERR "gpio: freeing free or non-gpio pin %s-%u\n",
pio->name, pin);
return (pio_readl(pio, PDSR) >> offset) & 1;
}
EXPORT_SYMBOL(gpio_free);

int gpio_direction_input(unsigned int gpio)
{
struct pio_device *pio;
unsigned int pin;

pio = gpio_to_pio(gpio);
if (!pio)
return -ENODEV;

pin = gpio & 0x1f;
pio_writel(pio, ODR, 1 << pin);

return 0;
}
EXPORT_SYMBOL(gpio_direction_input);
static void gpio_set(struct gpio_chip *chip, unsigned offset, int value);

int gpio_direction_output(unsigned int gpio, int value)
static int direction_output(struct gpio_chip *chip, unsigned offset, int value)
{
struct pio_device *pio;
unsigned int pin;

pio = gpio_to_pio(gpio);
if (!pio)
return -ENODEV;
struct pio_device *pio = container_of(chip, struct pio_device, chip);
u32 mask = 1 << offset;

gpio_set_value(gpio, value);

pin = gpio & 0x1f;
pio_writel(pio, OER, 1 << pin);
if (!(pio_readl(pio, PSR) & mask))
return -EINVAL;

gpio_set(chip, offset, value);
pio_writel(pio, OER, mask);
return 0;
}
EXPORT_SYMBOL(gpio_direction_output);

int gpio_get_value(unsigned int gpio)
static void gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct pio_device *pio = &pio_dev[gpio >> 5];
struct pio_device *pio = container_of(chip, struct pio_device, chip);
u32 mask = 1 << offset;

return (pio_readl(pio, PDSR) >> (gpio & 0x1f)) & 1;
}
EXPORT_SYMBOL(gpio_get_value);

void gpio_set_value(unsigned int gpio, int value)
{
struct pio_device *pio = &pio_dev[gpio >> 5];
u32 mask;

mask = 1 << (gpio & 0x1f);
if (value)
pio_writel(pio, SODR, mask);
else
pio_writel(pio, CODR, mask);
}
EXPORT_SYMBOL(gpio_set_value);

/*--------------------------------------------------------------------------*/

Expand Down Expand Up @@ -337,6 +286,63 @@ gpio_irq_setup(struct pio_device *pio, int irq, int gpio_irq)
set_irq_chained_handler(irq, gpio_irq_handler);
}

/*--------------------------------------------------------------------------*/

#ifdef CONFIG_DEBUG_FS

#include <linux/seq_file.h>

/*
* This shows more info than the generic gpio dump code:
* pullups, deglitching, open drain drive.
*/
static void pio_bank_show(struct seq_file *s, struct gpio_chip *chip)
{
struct pio_device *pio = container_of(chip, struct pio_device, chip);
u32 psr, osr, imr, pdsr, pusr, ifsr, mdsr;
unsigned i;
u32 mask;
char bank;

psr = pio_readl(pio, PSR);
osr = pio_readl(pio, OSR);
imr = pio_readl(pio, IMR);
pdsr = pio_readl(pio, PDSR);
pusr = pio_readl(pio, PUSR);
ifsr = pio_readl(pio, IFSR);
mdsr = pio_readl(pio, MDSR);

bank = 'A' + pio->pdev->id;

for (i = 0, mask = 1; i < 32; i++, mask <<= 1) {
const char *label;

label = gpiochip_is_requested(chip, i);
if (!label)
continue;

seq_printf(s, " gpio-%-3d P%c%-2d (%-12s) %s %s %s",
chip->base + i, bank, i,
label,
(osr & mask) ? "out" : "in ",
(mask & pdsr) ? "hi" : "lo",
(mask & pusr) ? " " : "up");
if (ifsr & mask)
seq_printf(s, " deglitch");
if ((osr & mdsr) & mask)
seq_printf(s, " open-drain");
if (imr & mask)
seq_printf(s, " irq-%d edge-both",
gpio_to_irq(chip->base + i));
seq_printf(s, "\n");
}
}

#else
#define pio_bank_show NULL
#endif


/*--------------------------------------------------------------------------*/

static int __init pio_probe(struct platform_device *pdev)
Expand All @@ -349,6 +355,18 @@ static int __init pio_probe(struct platform_device *pdev)
pio = &pio_dev[pdev->id];
BUG_ON(!pio->regs);

pio->chip.label = pio->name;
pio->chip.base = pdev->id * 32;
pio->chip.ngpio = 32;

pio->chip.direction_input = direction_input;
pio->chip.get = gpio_get;
pio->chip.direction_output = direction_output;
pio->chip.set = gpio_set;
pio->chip.dbg_show = pio_bank_show;

gpiochip_add(&pio->chip);

gpio_irq_setup(pio, irq, gpio_irq_base);

platform_set_drvdata(pdev, pio);
Expand Down Expand Up @@ -406,12 +424,6 @@ void __init at32_init_pio(struct platform_device *pdev)
pio->pdev = pdev;
pio->regs = ioremap(regs->start, regs->end - regs->start + 1);

/*
* request_gpio() is only valid for pins that have been
* explicitly configured as GPIO and not previously requested
*/
pio->gpio_mask = ~0UL;

/* start with irqs disabled and acked */
pio_writel(pio, IDR, ~0UL);
(void) pio_readl(pio, ISR);
Expand Down
2 changes: 1 addition & 1 deletion trunk/arch/avr32/mach-at32ap/pio.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
#define PIO_OSR 0x0018
#define PIO_IFER 0x0020
#define PIO_IFDR 0x0024
#define PIO_ISFR 0x0028
#define PIO_IFSR 0x0028
#define PIO_SODR 0x0030
#define PIO_CODR 0x0034
#define PIO_ODSR 0x0038
Expand Down
2 changes: 0 additions & 2 deletions trunk/include/asm-avr32/arch-at32ap/at32ap700x.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@
#define GPIO_PERIPH_A 0
#define GPIO_PERIPH_B 1

#define NR_GPIO_CONTROLLERS 4

/*
* Pin numbers identifying specific GPIO pins on the chip. They can
* also be converted to IRQ numbers by passing them through
Expand Down
34 changes: 25 additions & 9 deletions trunk/include/asm-avr32/arch-at32ap/gpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,36 @@
#include <asm/irq.h>


/* Arch-neutral GPIO API */
int __must_check gpio_request(unsigned int gpio, const char *label);
void gpio_free(unsigned int gpio);
/* Some GPIO chips can manage IRQs; some can't. The exact numbers can
* be changed if needed, but for the moment they're not configurable.
*/
#define ARCH_NR_GPIOS (NR_GPIO_IRQS + 2 * 32)

int gpio_direction_input(unsigned int gpio);
int gpio_direction_output(unsigned int gpio, int value);
int gpio_get_value(unsigned int gpio);
void gpio_set_value(unsigned int gpio, int value);

#include <asm-generic/gpio.h> /* cansleep wrappers */
/* Arch-neutral GPIO API, supporting both "native" and external GPIOs. */
#include <asm-generic/gpio.h>

static inline int gpio_get_value(unsigned int gpio)
{
return __gpio_get_value(gpio);
}

static inline void gpio_set_value(unsigned int gpio, int value)
{
__gpio_set_value(gpio, value);
}

static inline int gpio_cansleep(unsigned int gpio)
{
return __gpio_cansleep(gpio);
}


static inline int gpio_to_irq(unsigned int gpio)
{
return gpio + GPIO_IRQ_BASE;
if (gpio < NR_GPIO_IRQS)
return gpio + GPIO_IRQ_BASE;
return -EINVAL;
}

static inline int irq_to_gpio(unsigned int irq)
Expand Down
4 changes: 2 additions & 2 deletions trunk/include/asm-avr32/arch-at32ap/irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@

#define EIM_IRQ_BASE NR_INTERNAL_IRQS
#define NR_EIM_IRQS 32

#define AT32_EXTINT(n) (EIM_IRQ_BASE + (n))

#define GPIO_IRQ_BASE (EIM_IRQ_BASE + NR_EIM_IRQS)
#define NR_GPIO_IRQS (5 * 32)
#define NR_GPIO_CTLR (5 /*internal*/ + 1 /*external*/)
#define NR_GPIO_IRQS (NR_GPIO_CTLR * 32)

#define NR_IRQS (GPIO_IRQ_BASE + NR_GPIO_IRQS)

Expand Down

0 comments on commit 806a80b

Please sign in to comment.