Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 163185
b: refs/heads/master
c: 7a36071
h: refs/heads/master
i:
  163183: d15f464
v: v3
  • Loading branch information
David Brownell authored and Kevin Hilman committed Aug 26, 2009
1 parent 76bb772 commit 0e6d303
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 13 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: af5dbaef76cb01995639cef10ca6f5a2b08207e8
refs/heads/master: 7a36071e7954836ba437987e5ca4ced174462b28
3 changes: 2 additions & 1 deletion trunk/arch/arm/mach-davinci/dm365.c
Original file line number Diff line number Diff line change
Expand Up @@ -882,7 +882,8 @@ static struct davinci_soc_info davinci_soc_info_dm365 = {
.timer_info = &dm365_timer_info,
.gpio_base = IO_ADDRESS(DAVINCI_GPIO_BASE),
.gpio_num = 104,
.gpio_irq = 44,
.gpio_irq = IRQ_DM365_GPIO0,
.gpio_unbanked = 8, /* really 16 ... skip muxed GPIOs */
.serial_dev = &dm365_serial_device,
.emac_pdata = &dm365_emac_pdata,
.sram_dma = 0x00010000,
Expand Down
105 changes: 99 additions & 6 deletions trunk/arch/arm/mach-davinci/gpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ static DEFINE_SPINLOCK(gpio_lock);
struct davinci_gpio {
struct gpio_chip chip;
struct gpio_controller *__iomem regs;
int irq_base;
};

static struct davinci_gpio chips[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)];
Expand Down Expand Up @@ -161,8 +162,7 @@ pure_initcall(davinci_gpio_setup);
* used as output pins ... which is convenient for testing.
*
* NOTE: The first few GPIOs also have direct INTC hookups in addition
* to their GPIOBNK0 irq, with a bit less overhead but less flexibility
* on triggering (e.g. no edge options). We don't try to use those.
* to their GPIOBNK0 irq, with a bit less overhead.
*
* All those INTC hookups (direct, plus several IRQ banks) can also
* serve as EDMA event triggers.
Expand All @@ -171,7 +171,7 @@ pure_initcall(davinci_gpio_setup);
static void gpio_irq_disable(unsigned irq)
{
struct gpio_controller *__iomem g = get_irq_chip_data(irq);
u32 mask = __gpio_mask(irq_to_gpio(irq));
u32 mask = (u32) get_irq_data(irq);

__raw_writel(mask, &g->clr_falling);
__raw_writel(mask, &g->clr_rising);
Expand All @@ -180,7 +180,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);
u32 mask = __gpio_mask(irq_to_gpio(irq));
u32 mask = (u32) get_irq_data(irq);
unsigned status = irq_desc[irq].status;

status &= IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING;
Expand All @@ -196,7 +196,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);
u32 mask = __gpio_mask(irq_to_gpio(irq));
u32 mask = (u32) get_irq_data(irq);

if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
return -EINVAL;
Expand Down Expand Up @@ -260,6 +260,45 @@ gpio_irq_handler(unsigned irq, struct irq_desc *desc)
/* now it may re-trigger */
}

static int gpio_to_irq_banked(struct gpio_chip *chip, unsigned offset)
{
struct davinci_gpio *d = container_of(chip, struct davinci_gpio, chip);

if (d->irq_base >= 0)
return d->irq_base + offset;
else
return -ENODEV;
}

static int gpio_to_irq_unbanked(struct gpio_chip *chip, unsigned offset)
{
struct davinci_soc_info *soc_info = &davinci_soc_info;

/* NOTE: we assume for now that only irqs in the first gpio_chip
* can provide direct-mapped IRQs to AINTC (up to 32 GPIOs).
*/
if (offset < soc_info->gpio_unbanked)
return soc_info->gpio_irq + offset;
else
return -ENODEV;
}

static int gpio_irq_type_unbanked(unsigned irq, unsigned trigger)
{
struct gpio_controller *__iomem g = get_irq_chip_data(irq);
u32 mask = (u32) get_irq_data(irq);

if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
return -EINVAL;

__raw_writel(mask, (trigger & IRQ_TYPE_EDGE_FALLING)
? &g->set_falling : &g->clr_falling);
__raw_writel(mask, (trigger & IRQ_TYPE_EDGE_RISING)
? &g->set_rising : &g->clr_rising);

return 0;
}

/*
* NOTE: for suspend/resume, probably best to make a platform_device with
* suspend_late/resume_resume calls hooking into results of the set_wake()
Expand All @@ -275,6 +314,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;

ngpio = soc_info->gpio_num;

Expand All @@ -292,12 +332,63 @@ static int __init davinci_gpio_irq_setup(void)
}
clk_enable(clk);

/* Arrange gpio_to_irq() support, handling either direct IRQs or
* banked IRQs. Having GPIOs in the first GPIO bank use direct
* IRQs, while the others use banked IRQs, would need some setup
* tweaks to recognize hardware which can do that.
*/
for (gpio = 0, bank = 0; gpio < ngpio; bank++, gpio += 32) {
chips[bank].chip.to_irq = gpio_to_irq_banked;
chips[bank].irq_base = soc_info->gpio_unbanked
? -EINVAL
: (soc_info->intc_irq_num + gpio);
}

/*
* AINTC can handle direct/unbanked IRQs for GPIOs, with the GPIO
* controller only handling trigger modes. We currently assume no
* IRQ mux conflicts; gpio_irq_type_unbanked() is only for GPIOs.
*/
if (soc_info->gpio_unbanked) {
static struct irq_chip gpio_irqchip_unbanked;

/* pass "bank 0" GPIO IRQs to AINTC */
chips[0].chip.to_irq = gpio_to_irq_unbanked;
binten = BIT(0);

/* AINTC handles mask/unmask; GPIO handles triggering */
irq = bank_irq;
gpio_irqchip_unbanked = *get_irq_desc_chip(irq_to_desc(irq));
gpio_irqchip_unbanked.name = "GPIO-AINTC";
gpio_irqchip_unbanked.set_type = gpio_irq_type_unbanked;

/* default trigger: both edges */
g = gpio2controller(0);
__raw_writel(~0, &g->set_falling);
__raw_writel(~0, &g->set_rising);

/* set the direct IRQs up to use that irqchip */
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);
irq_desc[irq].status |= IRQ_TYPE_EDGE_BOTH;
}

goto done;
}

/*
* Or, AINTC can handle IRQs for banks of 16 GPIO IRQs, which we
* then chain through our own handler.
*/
for (gpio = 0, irq = gpio_to_irq(0), bank = 0;
gpio < ngpio;
bank++, bank_irq++) {
struct gpio_controller *__iomem g = gpio2controller(gpio);
unsigned i;

/* disabled by default, enabled only as needed */
g = gpio2controller(gpio);
__raw_writel(~0, &g->clr_falling);
__raw_writel(~0, &g->clr_rising);

Expand All @@ -309,13 +400,15 @@ static int __init davinci_gpio_irq_setup(void)
for (i = 0; i < 16 && gpio < ngpio; i++, irq++, gpio++) {
set_irq_chip(irq, &gpio_irqchip);
set_irq_chip_data(irq, g);
set_irq_data(irq, (void *) __gpio_mask(gpio));
set_irq_handler(irq, handle_simple_irq);
set_irq_flags(irq, IRQF_VALID);
}

binten |= BIT(bank);
}

done:
/* BINTEN -- per-bank interrupt enable. genirq would also let these
* bits be set/cleared dynamically.
*/
Expand Down
1 change: 1 addition & 0 deletions trunk/arch/arm/mach-davinci/include/mach/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ struct davinci_soc_info {
void __iomem *gpio_base;
unsigned gpio_num;
unsigned gpio_irq;
unsigned gpio_unbanked;
struct platform_device *serial_dev;
struct emac_platform_data *emac_pdata;
dma_addr_t sram_dma;
Expand Down
8 changes: 3 additions & 5 deletions trunk/arch/arm/mach-davinci/include/mach/gpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,15 +142,13 @@ static inline int gpio_cansleep(unsigned gpio)

static inline int gpio_to_irq(unsigned gpio)
{
if (gpio >= DAVINCI_N_GPIO)
return -EINVAL;
return davinci_soc_info.intc_irq_num + gpio;
return __gpio_to_irq(gpio);
}

static inline int irq_to_gpio(unsigned irq)
{
/* caller guarantees gpio_to_irq() succeeded */
return irq - davinci_soc_info.intc_irq_num;
/* don't support the reverse mapping */
return -ENOSYS;
}

#endif /* __DAVINCI_GPIO_H */

0 comments on commit 0e6d303

Please sign in to comment.