diff options
-rw-r--r-- | arch/arm/plat-mxc/gpio.c | 49 | ||||
-rw-r--r-- | arch/arm/plat-mxc/include/mach/gpio.h | 1 |
2 files changed, 49 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 | } |
diff --git a/arch/arm/plat-mxc/include/mach/gpio.h b/arch/arm/plat-mxc/include/mach/gpio.h index ea509f1090fb..894d2f87c856 100644 --- a/arch/arm/plat-mxc/include/mach/gpio.h +++ b/arch/arm/plat-mxc/include/mach/gpio.h | |||
@@ -35,6 +35,7 @@ struct mxc_gpio_port { | |||
35 | int irq; | 35 | int irq; |
36 | int virtual_irq_start; | 36 | int virtual_irq_start; |
37 | struct gpio_chip chip; | 37 | struct gpio_chip chip; |
38 | u32 both_edges; | ||
38 | }; | 39 | }; |
39 | 40 | ||
40 | int mxc_gpio_init(struct mxc_gpio_port*, int); | 41 | int mxc_gpio_init(struct mxc_gpio_port*, int); |