summaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpio-mxs.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-02-26 09:35:29 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2013-02-26 09:35:29 -0800
commit4c8c225abf972ce422c241579ce1d4d27eaeb166 (patch)
tree77bc67defdc53c494b20632e66b82ce9be3c06af /drivers/gpio/gpio-mxs.c
parent3eb05225ee8efb81fe50558f5f9d94e7477ade8f (diff)
parent9170100ee46402af6d318134525c728027318d67 (diff)
Merge tag 'gpio-for-linus' of git://git.secretlab.ca/git/linux
Pull GPIO changes from Grant Likely: "This branch contains the usual set of individual driver improvements and bug fixes, as well as updates to the core code. The more notable changes include: - Internally add new API for referencing GPIOs by gpio_desc instead of number. Eventually this will become a public API - ACPI GPIO binding support" * tag 'gpio-for-linus' of git://git.secretlab.ca/git/linux: (33 commits) arm64: select ARCH_WANT_OPTIONAL_GPIOLIB gpio: em: Use irq_domain_add_simple() to fix runtime error gpio: using common order: let 'static const' instead of 'const static' gpio/vt8500: memory cleanup missing gpiolib: Fix locking on gpio debugfs files gpiolib: let gpio_chip reference its descriptors gpiolib: use descriptors internally gpiolib: use gpio_chips list in gpiochip_find_base gpiolib: use gpio_chips list in sysfs ops gpiolib: use gpio_chips list in gpiochip_find gpiolib: use gpio_chips list in gpiolib_sysfs_init gpiolib: link all gpio_chips using a list gpio/langwell: cleanup driver gpio/langwell: Add Cloverview ids to pci device table gpio/lynxpoint: add chipset gpio driver. gpiolib: add missing braces in gpio_direction_show gpiolib-acpi: Fix error checks in interrupt requesting gpio: mpc8xxx: don't set IRQ_TYPE_NONE when creating irq mapping gpiolib: remove gpiochip_reserve() arm: pxa: tosa: do not use gpiochip_reserve() ...
Diffstat (limited to 'drivers/gpio/gpio-mxs.c')
-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 45d97c46831..25000b0f845 100644
--- a/drivers/gpio/gpio-mxs.c
+++ b/drivers/gpio/gpio-mxs.c
@@ -66,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)
@@ -82,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;
@@ -125,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)
{
@@ -138,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);
}