Skip to content

Commit

Permalink
pinctrl/coh901: use irqdomain, allocate irqdescs
Browse files Browse the repository at this point in the history
This switches the COH 901 pinctrl driver to allocate its GPIO
IRQs dynamically, and start to use a linear irqdomain to map
from the hardware IRQs.

This way we can cut away the complex allocation of IRQ numbers
from the <mach/irqs.h> file.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
  • Loading branch information
Linus Walleij committed Nov 11, 2012
1 parent d4a31ee commit a6c45b9
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 27 deletions.
1 change: 0 additions & 1 deletion arch/arm/mach-u300/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1445,7 +1445,6 @@ static struct platform_device pinctrl_device = {
static struct u300_gpio_platform u300_gpio_plat = {
.ports = 7,
.gpio_base = 0,
.gpio_irq_base = IRQ_U300_GPIO_BASE,
.pinctrl_device = &pinctrl_device,
};

Expand Down
10 changes: 0 additions & 10 deletions arch/arm/mach-u300/include/mach/irqs.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,4 @@
#define IRQ_U300_GPIO_PORT6 87
#define U300_VIC_IRQS_END 88

/* Maximum 8*7 GPIO lines */
#ifdef CONFIG_PINCTRL_COH901
#define IRQ_U300_GPIO_BASE (U300_VIC_IRQS_END)
#define IRQ_U300_GPIO_END (IRQ_U300_GPIO_BASE + 56)
#else
#define IRQ_U300_GPIO_END (U300_VIC_IRQS_END)
#endif

#define NR_IRQS_U300 (IRQ_U300_GPIO_END - IRQ_U300_INTCON0_START)

#endif
60 changes: 46 additions & 14 deletions drivers/pinctrl/pinctrl-coh901.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/irqdomain.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/platform_device.h>
Expand Down Expand Up @@ -67,7 +68,6 @@ struct u300_gpio {
struct resource *memres;
void __iomem *base;
struct device *dev;
int irq_base;
u32 stride;
/* Register offsets */
u32 pcr;
Expand All @@ -83,6 +83,7 @@ struct u300_gpio_port {
struct list_head node;
struct u300_gpio *gpio;
char name[8];
struct irq_domain *domain;
int irq;
int number;
u8 toggle_edge_mode;
Expand Down Expand Up @@ -314,10 +315,30 @@ static int u300_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
static int u300_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct u300_gpio *gpio = to_u300_gpio(chip);
int retirq = gpio->irq_base + offset;
int portno = offset >> 3;
struct u300_gpio_port *port = NULL;
struct list_head *p;
int retirq;

dev_dbg(gpio->dev, "request IRQ for GPIO %d, return %d\n", offset,
retirq);
list_for_each(p, &gpio->port_list) {
port = list_entry(p, struct u300_gpio_port, node);
if (port->number == portno)
break;
}
if (port == NULL) {
dev_err(gpio->dev, "could not locate port for GPIO %d IRQ\n",
offset);
return -EINVAL;
}

/*
* The local hwirqs on the port are the lower three bits, there
* are exactly 8 IRQs per port since they are 8-bit
*/
retirq = irq_find_mapping(port->domain, (offset & 0x7));

dev_dbg(gpio->dev, "request IRQ for GPIO %d, return %d from port %d\n",
offset, retirq, port->number);
return retirq;
}

Expand Down Expand Up @@ -467,7 +488,7 @@ static int u300_gpio_irq_type(struct irq_data *d, unsigned trigger)
{
struct u300_gpio_port *port = irq_data_get_irq_chip_data(d);
struct u300_gpio *gpio = port->gpio;
int offset = d->irq - gpio->irq_base;
int offset = (port->number << 3) + d->hwirq;
u32 val;

if ((trigger & IRQF_TRIGGER_RISING) &&
Expand Down Expand Up @@ -503,10 +524,12 @@ static void u300_gpio_irq_enable(struct irq_data *d)
{
struct u300_gpio_port *port = irq_data_get_irq_chip_data(d);
struct u300_gpio *gpio = port->gpio;
int offset = d->irq - gpio->irq_base;
int offset = (port->number << 3) + d->hwirq;
u32 val;
unsigned long flags;

dev_dbg(gpio->dev, "enable IRQ for hwirq %lu on port %s, offset %d\n",
d->hwirq, port->name, offset);
local_irq_save(flags);
val = readl(U300_PIN_REG(offset, ien));
writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, ien));
Expand All @@ -517,7 +540,7 @@ static void u300_gpio_irq_disable(struct irq_data *d)
{
struct u300_gpio_port *port = irq_data_get_irq_chip_data(d);
struct u300_gpio *gpio = port->gpio;
int offset = d->irq - gpio->irq_base;
int offset = (port->number << 3) + d->hwirq;
u32 val;
unsigned long flags;

Expand Down Expand Up @@ -555,8 +578,7 @@ static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
int irqoffset;

for_each_set_bit(irqoffset, &val, U300_GPIO_PINS_PER_PORT) {
int pin_irq = gpio->irq_base + (port->number << 3)
+ irqoffset;
int pin_irq = irq_find_mapping(port->domain, irqoffset);
int offset = pinoffset + irqoffset;

dev_dbg(gpio->dev, "GPIO IRQ %d on pin %d\n",
Expand Down Expand Up @@ -631,6 +653,8 @@ static inline void u300_gpio_free_ports(struct u300_gpio *gpio)
list_for_each_safe(p, n, &gpio->port_list) {
port = list_entry(p, struct u300_gpio_port, node);
list_del(&port->node);
if (port->domain)
irq_domain_remove(port->domain);
kfree(port);
}
}
Expand All @@ -653,7 +677,6 @@ static int __init u300_gpio_probe(struct platform_device *pdev)

gpio->chip = u300_gpio_chip;
gpio->chip.ngpio = plat->ports * U300_GPIO_PINS_PER_PORT;
gpio->irq_base = plat->gpio_irq_base;
gpio->chip.dev = &pdev->dev;
gpio->chip.base = plat->gpio_base;
gpio->dev = &pdev->dev;
Expand Down Expand Up @@ -732,18 +755,26 @@ static int __init u300_gpio_probe(struct platform_device *pdev)
port->irq = platform_get_irq_byname(pdev,
port->name);

dev_dbg(gpio->dev, "register IRQ %d for %s\n", port->irq,
dev_dbg(gpio->dev, "register IRQ %d for port %s\n", port->irq,
port->name);

port->domain = irq_domain_add_linear(pdev->dev.of_node,
U300_GPIO_PINS_PER_PORT,
&irq_domain_simple_ops,
port);
if (!port->domain)
goto err_no_domain;

irq_set_chained_handler(port->irq, u300_gpio_irq_handler);
irq_set_handler_data(port->irq, port);

/* For each GPIO pin set the unique IRQ handler */
for (i = 0; i < U300_GPIO_PINS_PER_PORT; i++) {
int irqno = gpio->irq_base + (portno << 3) + i;
int irqno = irq_create_mapping(port->domain, i);

dev_dbg(gpio->dev, "handler for IRQ %d on %s\n",
irqno, port->name);
dev_dbg(gpio->dev, "GPIO%d on port %s gets IRQ %d\n",
gpio->chip.base + (port->number << 3) + i,
port->name, irqno);
irq_set_chip_and_handler(irqno, &u300_gpio_irqchip,
handle_simple_irq);
set_irq_flags(irqno, IRQF_VALID);
Expand Down Expand Up @@ -776,6 +807,7 @@ static int __init u300_gpio_probe(struct platform_device *pdev)
err_no_pinctrl:
err = gpiochip_remove(&gpio->chip);
err_no_chip:
err_no_domain:
err_no_port:
u300_gpio_free_ports(gpio);
iounmap(gpio->base);
Expand Down
2 changes: 0 additions & 2 deletions include/linux/platform_data/pinctrl-coh901.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,11 @@
* struct u300_gpio_platform - U300 GPIO platform data
* @ports: number of GPIO block ports
* @gpio_base: first GPIO number for this block (use a free range)
* @gpio_irq_base: first GPIO IRQ number for this block (use a free range)
* @pinctrl_device: pin control device to spawn as child
*/
struct u300_gpio_platform {
u8 ports;
int gpio_base;
int gpio_irq_base;
struct platform_device *pinctrl_device;
};

Expand Down

0 comments on commit a6c45b9

Please sign in to comment.