aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio
diff options
context:
space:
mode:
authorGwenhael Goavec-Merou <gwenhael.goavec-merou@armadeus.com>2013-01-29 03:16:33 -0500
committerLinus Walleij <linus.walleij@linaro.org>2013-01-29 06:02:05 -0500
commit66d7990e282f8015686b9bab30be30eec297e736 (patch)
tree539def58cb73bb84493def504fc4e6354990aa10 /drivers/gpio
parent0d1c28a449c6c23a126e3a08ee30914609aac227 (diff)
gpio: mxs: Add IRQ_TYPE_EDGE_BOTH support
This patch adds support for IRQ_TYPE_EDGE_BOTH needed for some driver (gpio-keys). Inspired from gpio-mxc.c Acked-by: Shawn Guo <shawn.guo@linaro.org> Signed-off-by: Gwenhael Goavec-Merou <gwenhael.goavec-merou@armadeus.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/gpio-mxs.c31
1 files changed, 31 insertions, 0 deletions
diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c
index fa2a63cad32e..859b6fabc7bc 100644
--- a/drivers/gpio/gpio-mxs.c
+++ b/drivers/gpio/gpio-mxs.c
@@ -65,6 +65,7 @@ struct mxs_gpio_port {
65 struct irq_domain *domain; 65 struct irq_domain *domain;
66 struct bgpio_chip bgc; 66 struct bgpio_chip bgc;
67 enum mxs_gpio_id devid; 67 enum mxs_gpio_id devid;
68 u32 both_edges;
68}; 69};
69 70
70static inline int is_imx23_gpio(struct mxs_gpio_port *port) 71static inline int is_imx23_gpio(struct mxs_gpio_port *port)
@@ -81,13 +82,23 @@ static inline int is_imx28_gpio(struct mxs_gpio_port *port)
81 82
82static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type) 83static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
83{ 84{
85 u32 val;
84 u32 pin_mask = 1 << d->hwirq; 86 u32 pin_mask = 1 << d->hwirq;
85 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 87 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
86 struct mxs_gpio_port *port = gc->private; 88 struct mxs_gpio_port *port = gc->private;
87 void __iomem *pin_addr; 89 void __iomem *pin_addr;
88 int edge; 90 int edge;
89 91
92 port->both_edges &= ~pin_mask;
90 switch (type) { 93 switch (type) {
94 case IRQ_TYPE_EDGE_BOTH:
95 val = gpio_get_value(port->bgc.gc.base + d->hwirq);
96 if (val)
97 edge = GPIO_INT_FALL_EDGE;
98 else
99 edge = GPIO_INT_RISE_EDGE;
100 port->both_edges |= pin_mask;
101 break;
91 case IRQ_TYPE_EDGE_RISING: 102 case IRQ_TYPE_EDGE_RISING:
92 edge = GPIO_INT_RISE_EDGE; 103 edge = GPIO_INT_RISE_EDGE;
93 break; 104 break;
@@ -124,6 +135,23 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
124 return 0; 135 return 0;
125} 136}
126 137
138static void mxs_flip_edge(struct mxs_gpio_port *port, u32 gpio)
139{
140 u32 bit, val, edge;
141 void __iomem *pin_addr;
142
143 bit = 1 << gpio;
144
145 pin_addr = port->base + PINCTRL_IRQPOL(port);
146 val = readl(pin_addr);
147 edge = val & bit;
148
149 if (edge)
150 writel(bit, pin_addr + MXS_CLR);
151 else
152 writel(bit, pin_addr + MXS_SET);
153}
154
127/* MXS has one interrupt *per* gpio port */ 155/* MXS has one interrupt *per* gpio port */
128static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc) 156static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc)
129{ 157{
@@ -137,6 +165,9 @@ static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc)
137 165
138 while (irq_stat != 0) { 166 while (irq_stat != 0) {
139 int irqoffset = fls(irq_stat) - 1; 167 int irqoffset = fls(irq_stat) - 1;
168 if (port->both_edges & (1 << irqoffset))
169 mxs_flip_edge(port, irqoffset);
170
140 generic_handle_irq(irq_find_mapping(port->domain, irqoffset)); 171 generic_handle_irq(irq_find_mapping(port->domain, irqoffset));
141 irq_stat &= ~(1 << irqoffset); 172 irq_stat &= ~(1 << irqoffset);
142 } 173 }