diff options
Diffstat (limited to 'arch/arm/plat-mxc/gpio.c')
| -rw-r--r-- | arch/arm/plat-mxc/gpio.c | 49 |
1 files changed, 48 insertions, 1 deletions
diff --git a/arch/arm/plat-mxc/gpio.c b/arch/arm/plat-mxc/gpio.c index 89e95798cc3b..7506d963be4b 100644 --- a/arch/arm/plat-mxc/gpio.c +++ b/arch/arm/plat-mxc/gpio.c | |||
| @@ -64,6 +64,8 @@ static void gpio_unmask_irq(u32 irq) | |||
| 64 | _set_gpio_irqenable(&mxc_gpio_ports[gpio / 32], gpio & 0x1f, 1); | 64 | _set_gpio_irqenable(&mxc_gpio_ports[gpio / 32], gpio & 0x1f, 1); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | static int mxc_gpio_get(struct gpio_chip *chip, unsigned offset); | ||
| 68 | |||
| 67 | static int gpio_set_irq_type(u32 irq, u32 type) | 69 | static int gpio_set_irq_type(u32 irq, u32 type) |
| 68 | { | 70 | { |
| 69 | u32 gpio = irq_to_gpio(irq); | 71 | u32 gpio = irq_to_gpio(irq); |
| @@ -72,6 +74,7 @@ static int gpio_set_irq_type(u32 irq, u32 type) | |||
| 72 | int edge; | 74 | int edge; |
| 73 | void __iomem *reg = port->base; | 75 | void __iomem *reg = port->base; |
| 74 | 76 | ||
| 77 | port->both_edges &= ~(1 << (gpio & 31)); | ||
| 75 | switch (type) { | 78 | switch (type) { |
| 76 | case IRQ_TYPE_EDGE_RISING: | 79 | case IRQ_TYPE_EDGE_RISING: |
| 77 | edge = GPIO_INT_RISE_EDGE; | 80 | edge = GPIO_INT_RISE_EDGE; |
| @@ -79,13 +82,24 @@ static int gpio_set_irq_type(u32 irq, u32 type) | |||
| 79 | case IRQ_TYPE_EDGE_FALLING: | 82 | case IRQ_TYPE_EDGE_FALLING: |
| 80 | edge = GPIO_INT_FALL_EDGE; | 83 | edge = GPIO_INT_FALL_EDGE; |
| 81 | break; | 84 | break; |
| 85 | case IRQ_TYPE_EDGE_BOTH: | ||
| 86 | val = mxc_gpio_get(&port->chip, gpio & 31); | ||
| 87 | if (val) { | ||
| 88 | edge = GPIO_INT_LOW_LEV; | ||
| 89 | pr_debug("mxc: set GPIO %d to low trigger\n", gpio); | ||
| 90 | } else { | ||
| 91 | edge = GPIO_INT_HIGH_LEV; | ||
| 92 | pr_debug("mxc: set GPIO %d to high trigger\n", gpio); | ||
| 93 | } | ||
| 94 | port->both_edges |= 1 << (gpio & 31); | ||
| 95 | break; | ||
| 82 | case IRQ_TYPE_LEVEL_LOW: | 96 | case IRQ_TYPE_LEVEL_LOW: |
| 83 | edge = GPIO_INT_LOW_LEV; | 97 | edge = GPIO_INT_LOW_LEV; |
| 84 | break; | 98 | break; |
| 85 | case IRQ_TYPE_LEVEL_HIGH: | 99 | case IRQ_TYPE_LEVEL_HIGH: |
| 86 | edge = GPIO_INT_HIGH_LEV; | 100 | edge = GPIO_INT_HIGH_LEV; |
| 87 | break; | 101 | break; |
| 88 | default: /* this includes IRQ_TYPE_EDGE_BOTH */ | 102 | default: |
| 89 | return -EINVAL; | 103 | return -EINVAL; |
| 90 | } | 104 | } |
| 91 | 105 | ||
| @@ -98,6 +112,34 @@ static int gpio_set_irq_type(u32 irq, u32 type) | |||
| 98 | return 0; | 112 | return 0; |
| 99 | } | 113 | } |
| 100 | 114 | ||
| 115 | static void mxc_flip_edge(struct mxc_gpio_port *port, u32 gpio) | ||
| 116 | { | ||
| 117 | void __iomem *reg = port->base; | ||
| 118 | u32 bit, val; | ||
| 119 | int edge; | ||
| 120 | |||
| 121 | reg += GPIO_ICR1 + ((gpio & 0x10) >> 2); /* lower or upper register */ | ||
| 122 | bit = gpio & 0xf; | ||
| 123 | val = __raw_readl(reg); | ||
| 124 | edge = (val >> (bit << 1)) & 3; | ||
| 125 | val &= ~(0x3 << (bit << 1)); | ||
| 126 | switch (edge) { | ||
| 127 | case GPIO_INT_HIGH_LEV: | ||
| 128 | edge = GPIO_INT_LOW_LEV; | ||
| 129 | pr_debug("mxc: switch GPIO %d to low trigger\n", gpio); | ||
| 130 | break; | ||
| 131 | case GPIO_INT_LOW_LEV: | ||
| 132 | edge = GPIO_INT_HIGH_LEV; | ||
| 133 | pr_debug("mxc: switch GPIO %d to high trigger\n", gpio); | ||
| 134 | break; | ||
| 135 | default: | ||
| 136 | pr_err("mxc: invalid configuration for GPIO %d: %x\n", | ||
| 137 | gpio, edge); | ||
| 138 | return; | ||
| 139 | } | ||
| 140 | __raw_writel(val | (edge << (bit << 1)), reg); | ||
| 141 | } | ||
| 142 | |||
| 101 | /* handle n interrupts in one status register */ | 143 | /* handle n interrupts in one status register */ |
| 102 | static void mxc_gpio_irq_handler(struct mxc_gpio_port *port, u32 irq_stat) | 144 | static void mxc_gpio_irq_handler(struct mxc_gpio_port *port, u32 irq_stat) |
| 103 | { | 145 | { |
| @@ -105,11 +147,16 @@ static void mxc_gpio_irq_handler(struct mxc_gpio_port *port, u32 irq_stat) | |||
| 105 | 147 | ||
| 106 | gpio_irq_no = port->virtual_irq_start; | 148 | gpio_irq_no = port->virtual_irq_start; |
| 107 | for (; irq_stat != 0; irq_stat >>= 1, gpio_irq_no++) { | 149 | for (; irq_stat != 0; irq_stat >>= 1, gpio_irq_no++) { |
| 150 | u32 gpio = irq_to_gpio(gpio_irq_no); | ||
| 108 | 151 | ||
| 109 | if ((irq_stat & 1) == 0) | 152 | if ((irq_stat & 1) == 0) |
| 110 | continue; | 153 | continue; |
| 111 | 154 | ||
| 112 | BUG_ON(!(irq_desc[gpio_irq_no].handle_irq)); | 155 | BUG_ON(!(irq_desc[gpio_irq_no].handle_irq)); |
| 156 | |||
| 157 | if (port->both_edges & (1 << (gpio & 31))) | ||
| 158 | mxc_flip_edge(port, gpio); | ||
| 159 | |||
| 113 | irq_desc[gpio_irq_no].handle_irq(gpio_irq_no, | 160 | irq_desc[gpio_irq_no].handle_irq(gpio_irq_no, |
| 114 | &irq_desc[gpio_irq_no]); | 161 | &irq_desc[gpio_irq_no]); |
| 115 | } | 162 | } |
