diff options
Diffstat (limited to 'drivers/gpio/gpio-mxs.c')
| -rw-r--r-- | drivers/gpio/gpio-mxs.c | 66 |
1 files changed, 44 insertions, 22 deletions
diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index 796fb13e481..8ffdd7d2bad 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -20,6 +20,7 @@ * MA 02110-1301, USA. */ +#include <linux/err.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/io.h> @@ -65,6 +66,7 @@ struct mxs_gpio_port { struct irq_domain *domain; struct bgpio_chip bgc; enum mxs_gpio_id devid; + u32 both_edges; }; static inline int is_imx23_gpio(struct mxs_gpio_port *port) @@ -81,13 +83,23 @@ static inline int is_imx28_gpio(struct mxs_gpio_port *port) static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type) { + u32 val; u32 pin_mask = 1 << d->hwirq; struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct mxs_gpio_port *port = gc->private; void __iomem *pin_addr; int edge; + port->both_edges &= ~pin_mask; switch (type) { + case IRQ_TYPE_EDGE_BOTH: + val = gpio_get_value(port->bgc.gc.base + d->hwirq); + if (val) + edge = GPIO_INT_FALL_EDGE; + else + edge = GPIO_INT_RISE_EDGE; + port->both_edges |= pin_mask; + break; case IRQ_TYPE_EDGE_RISING: edge = GPIO_INT_RISE_EDGE; break; @@ -124,6 +136,23 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type) return 0; } +static void mxs_flip_edge(struct mxs_gpio_port *port, u32 gpio) +{ + u32 bit, val, edge; + void __iomem *pin_addr; + + bit = 1 << gpio; + + pin_addr = port->base + PINCTRL_IRQPOL(port); + val = readl(pin_addr); + edge = val & bit; + + if (edge) + writel(bit, pin_addr + MXS_CLR); + else + writel(bit, pin_addr + MXS_SET); +} + /* MXS has one interrupt *per* gpio port */ static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc) { @@ -137,6 +166,9 @@ static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc) while (irq_stat != 0) { int irqoffset = fls(irq_stat) - 1; + if (port->both_edges & (1 << irqoffset)) + mxs_flip_edge(port, irqoffset); + generic_handle_irq(irq_find_mapping(port->domain, irqoffset)); irq_stat &= ~(1 << irqoffset); } @@ -182,7 +214,8 @@ static void __init mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base) ct->regs.ack = PINCTRL_IRQSTAT(port) + MXS_CLR; ct->regs.mask = PINCTRL_IRQEN(port); - irq_setup_generic_chip(gc, IRQ_MSK(32), 0, IRQ_NOREQUEST, 0); + irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_NESTED_LOCK, + IRQ_NOREQUEST, 0); } static int mxs_gpio_to_irq(struct gpio_chip *gc, unsigned offset) @@ -214,7 +247,7 @@ static const struct of_device_id mxs_gpio_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, mxs_gpio_dt_ids); -static int __devinit mxs_gpio_probe(struct platform_device *pdev) +static int mxs_gpio_probe(struct platform_device *pdev) { const struct of_device_id *of_id = of_match_device(mxs_gpio_dt_ids, &pdev->dev); @@ -222,7 +255,6 @@ static int __devinit mxs_gpio_probe(struct platform_device *pdev) struct device_node *parent; static void __iomem *base; struct mxs_gpio_port *port; - struct resource *iores = NULL; int irq_base; int err; @@ -230,16 +262,10 @@ static int __devinit mxs_gpio_probe(struct platform_device *pdev) if (!port) return -ENOMEM; - if (np) { - port->id = of_alias_get_id(np, "gpio"); - if (port->id < 0) - return port->id; - port->devid = (enum mxs_gpio_id) of_id->data; - } else { - port->id = pdev->id; - port->devid = pdev->id_entry->driver_data; - } - + port->id = of_alias_get_id(np, "gpio"); + if (port->id < 0) + return port->id; + port->devid = (enum mxs_gpio_id) of_id->data; port->irq = platform_get_irq(pdev, 0); if (port->irq < 0) return port->irq; @@ -249,14 +275,9 @@ static int __devinit mxs_gpio_probe(struct platform_device *pdev) * share the same one */ if (!base) { - if (np) { - parent = of_get_parent(np); - base = of_iomap(parent, 0); - of_node_put(parent); - } else { - iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_request_and_ioremap(&pdev->dev, iores); - } + parent = of_get_parent(np); + base = of_iomap(parent, 0); + of_node_put(parent); if (!base) return -EADDRNOTAVAIL; } @@ -292,7 +313,8 @@ static int __devinit mxs_gpio_probe(struct platform_device *pdev) err = bgpio_init(&port->bgc, &pdev->dev, 4, port->base + PINCTRL_DIN(port), - port->base + PINCTRL_DOUT(port), NULL, + port->base + PINCTRL_DOUT(port) + MXS_SET, + port->base + PINCTRL_DOUT(port) + MXS_CLR, port->base + PINCTRL_DOE(port), NULL, 0); if (err) goto out_irqdesc_free; |
