diff options
| author | Benoît Thébaudeau <benoit.thebaudeau@advansee.com> | 2012-06-22 15:04:06 -0400 |
|---|---|---|
| committer | Linus Walleij <linus.walleij@linaro.org> | 2012-07-17 15:00:16 -0400 |
| commit | aeb27748e3bc1e89ec590713e574cb6f885cc3c6 (patch) | |
| tree | 79a76bb0bd3275173fdf5840db8e0c1683fd0f8b /drivers/gpio | |
| parent | 41920d16360ebc8c482911078a17d9994fb77612 (diff) | |
gpio/mxc: use the edge_sel feature if available
Some mxc processors have an edge_sel feature, which allows the IRQ to be
triggered by any edge.
This patch makes use of this feature if available, which skips mxc_flip_edge().
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: Linus Walleij <linus.walleij@stericsson.com>
Acked-by: Sascha Hauer <kernel@pengutronix.de>
Cc: <linux-arm-kernel@lists.infradead.org>
Signed-off-by: Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio')
| -rw-r--r-- | drivers/gpio/gpio-mxc.c | 71 |
1 files changed, 57 insertions, 14 deletions
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index c337143b18f8..bb985e815533 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c | |||
| @@ -38,7 +38,8 @@ | |||
| 38 | enum mxc_gpio_hwtype { | 38 | enum mxc_gpio_hwtype { |
| 39 | IMX1_GPIO, /* runs on i.mx1 */ | 39 | IMX1_GPIO, /* runs on i.mx1 */ |
| 40 | IMX21_GPIO, /* runs on i.mx21 and i.mx27 */ | 40 | IMX21_GPIO, /* runs on i.mx21 and i.mx27 */ |
| 41 | IMX31_GPIO, /* runs on all other i.mx */ | 41 | IMX31_GPIO, /* runs on i.mx31 */ |
| 42 | IMX35_GPIO, /* runs on all other i.mx */ | ||
| 42 | }; | 43 | }; |
| 43 | 44 | ||
| 44 | /* device type dependent stuff */ | 45 | /* device type dependent stuff */ |
| @@ -50,6 +51,7 @@ struct mxc_gpio_hwdata { | |||
| 50 | unsigned icr2_reg; | 51 | unsigned icr2_reg; |
| 51 | unsigned imr_reg; | 52 | unsigned imr_reg; |
| 52 | unsigned isr_reg; | 53 | unsigned isr_reg; |
| 54 | int edge_sel_reg; | ||
| 53 | unsigned low_level; | 55 | unsigned low_level; |
| 54 | unsigned high_level; | 56 | unsigned high_level; |
| 55 | unsigned rise_edge; | 57 | unsigned rise_edge; |
| @@ -74,6 +76,7 @@ static struct mxc_gpio_hwdata imx1_imx21_gpio_hwdata = { | |||
| 74 | .icr2_reg = 0x2c, | 76 | .icr2_reg = 0x2c, |
| 75 | .imr_reg = 0x30, | 77 | .imr_reg = 0x30, |
| 76 | .isr_reg = 0x34, | 78 | .isr_reg = 0x34, |
| 79 | .edge_sel_reg = -EINVAL, | ||
| 77 | .low_level = 0x03, | 80 | .low_level = 0x03, |
| 78 | .high_level = 0x02, | 81 | .high_level = 0x02, |
| 79 | .rise_edge = 0x00, | 82 | .rise_edge = 0x00, |
| @@ -88,6 +91,22 @@ static struct mxc_gpio_hwdata imx31_gpio_hwdata = { | |||
| 88 | .icr2_reg = 0x10, | 91 | .icr2_reg = 0x10, |
| 89 | .imr_reg = 0x14, | 92 | .imr_reg = 0x14, |
| 90 | .isr_reg = 0x18, | 93 | .isr_reg = 0x18, |
| 94 | .edge_sel_reg = -EINVAL, | ||
| 95 | .low_level = 0x00, | ||
| 96 | .high_level = 0x01, | ||
| 97 | .rise_edge = 0x02, | ||
| 98 | .fall_edge = 0x03, | ||
| 99 | }; | ||
| 100 | |||
| 101 | static struct mxc_gpio_hwdata imx35_gpio_hwdata = { | ||
| 102 | .dr_reg = 0x00, | ||
| 103 | .gdir_reg = 0x04, | ||
| 104 | .psr_reg = 0x08, | ||
| 105 | .icr1_reg = 0x0c, | ||
| 106 | .icr2_reg = 0x10, | ||
| 107 | .imr_reg = 0x14, | ||
| 108 | .isr_reg = 0x18, | ||
| 109 | .edge_sel_reg = 0x1c, | ||
| 91 | .low_level = 0x00, | 110 | .low_level = 0x00, |
| 92 | .high_level = 0x01, | 111 | .high_level = 0x01, |
| 93 | .rise_edge = 0x02, | 112 | .rise_edge = 0x02, |
| @@ -104,12 +123,13 @@ static struct mxc_gpio_hwdata *mxc_gpio_hwdata; | |||
| 104 | #define GPIO_ICR2 (mxc_gpio_hwdata->icr2_reg) | 123 | #define GPIO_ICR2 (mxc_gpio_hwdata->icr2_reg) |
| 105 | #define GPIO_IMR (mxc_gpio_hwdata->imr_reg) | 124 | #define GPIO_IMR (mxc_gpio_hwdata->imr_reg) |
| 106 | #define GPIO_ISR (mxc_gpio_hwdata->isr_reg) | 125 | #define GPIO_ISR (mxc_gpio_hwdata->isr_reg) |
| 126 | #define GPIO_EDGE_SEL (mxc_gpio_hwdata->edge_sel_reg) | ||
| 107 | 127 | ||
| 108 | #define GPIO_INT_LOW_LEV (mxc_gpio_hwdata->low_level) | 128 | #define GPIO_INT_LOW_LEV (mxc_gpio_hwdata->low_level) |
| 109 | #define GPIO_INT_HIGH_LEV (mxc_gpio_hwdata->high_level) | 129 | #define GPIO_INT_HIGH_LEV (mxc_gpio_hwdata->high_level) |
| 110 | #define GPIO_INT_RISE_EDGE (mxc_gpio_hwdata->rise_edge) | 130 | #define GPIO_INT_RISE_EDGE (mxc_gpio_hwdata->rise_edge) |
| 111 | #define GPIO_INT_FALL_EDGE (mxc_gpio_hwdata->fall_edge) | 131 | #define GPIO_INT_FALL_EDGE (mxc_gpio_hwdata->fall_edge) |
| 112 | #define GPIO_INT_NONE 0x4 | 132 | #define GPIO_INT_BOTH_EDGES 0x4 |
| 113 | 133 | ||
| 114 | static struct platform_device_id mxc_gpio_devtype[] = { | 134 | static struct platform_device_id mxc_gpio_devtype[] = { |
| 115 | { | 135 | { |
| @@ -122,6 +142,9 @@ static struct platform_device_id mxc_gpio_devtype[] = { | |||
| 122 | .name = "imx31-gpio", | 142 | .name = "imx31-gpio", |
| 123 | .driver_data = IMX31_GPIO, | 143 | .driver_data = IMX31_GPIO, |
| 124 | }, { | 144 | }, { |
| 145 | .name = "imx35-gpio", | ||
| 146 | .driver_data = IMX35_GPIO, | ||
| 147 | }, { | ||
| 125 | /* sentinel */ | 148 | /* sentinel */ |
| 126 | } | 149 | } |
| 127 | }; | 150 | }; |
| @@ -130,6 +153,7 @@ static const struct of_device_id mxc_gpio_dt_ids[] = { | |||
| 130 | { .compatible = "fsl,imx1-gpio", .data = &mxc_gpio_devtype[IMX1_GPIO], }, | 153 | { .compatible = "fsl,imx1-gpio", .data = &mxc_gpio_devtype[IMX1_GPIO], }, |
| 131 | { .compatible = "fsl,imx21-gpio", .data = &mxc_gpio_devtype[IMX21_GPIO], }, | 154 | { .compatible = "fsl,imx21-gpio", .data = &mxc_gpio_devtype[IMX21_GPIO], }, |
| 132 | { .compatible = "fsl,imx31-gpio", .data = &mxc_gpio_devtype[IMX31_GPIO], }, | 155 | { .compatible = "fsl,imx31-gpio", .data = &mxc_gpio_devtype[IMX31_GPIO], }, |
| 156 | { .compatible = "fsl,imx35-gpio", .data = &mxc_gpio_devtype[IMX35_GPIO], }, | ||
| 133 | { /* sentinel */ } | 157 | { /* sentinel */ } |
| 134 | }; | 158 | }; |
| 135 | 159 | ||
| @@ -160,15 +184,19 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) | |||
| 160 | edge = GPIO_INT_FALL_EDGE; | 184 | edge = GPIO_INT_FALL_EDGE; |
| 161 | break; | 185 | break; |
| 162 | case IRQ_TYPE_EDGE_BOTH: | 186 | case IRQ_TYPE_EDGE_BOTH: |
| 163 | val = gpio_get_value(gpio); | 187 | if (GPIO_EDGE_SEL >= 0) { |
| 164 | if (val) { | 188 | edge = GPIO_INT_BOTH_EDGES; |
| 165 | edge = GPIO_INT_LOW_LEV; | ||
| 166 | pr_debug("mxc: set GPIO %d to low trigger\n", gpio); | ||
| 167 | } else { | 189 | } else { |
| 168 | edge = GPIO_INT_HIGH_LEV; | 190 | val = gpio_get_value(gpio); |
| 169 | pr_debug("mxc: set GPIO %d to high trigger\n", gpio); | 191 | if (val) { |
| 192 | edge = GPIO_INT_LOW_LEV; | ||
| 193 | pr_debug("mxc: set GPIO %d to low trigger\n", gpio); | ||
| 194 | } else { | ||
| 195 | edge = GPIO_INT_HIGH_LEV; | ||
| 196 | pr_debug("mxc: set GPIO %d to high trigger\n", gpio); | ||
| 197 | } | ||
| 198 | port->both_edges |= 1 << (gpio & 31); | ||
| 170 | } | 199 | } |
| 171 | port->both_edges |= 1 << (gpio & 31); | ||
| 172 | break; | 200 | break; |
| 173 | case IRQ_TYPE_LEVEL_LOW: | 201 | case IRQ_TYPE_LEVEL_LOW: |
| 174 | edge = GPIO_INT_LOW_LEV; | 202 | edge = GPIO_INT_LOW_LEV; |
| @@ -180,10 +208,23 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) | |||
| 180 | return -EINVAL; | 208 | return -EINVAL; |
| 181 | } | 209 | } |
| 182 | 210 | ||
| 183 | reg += GPIO_ICR1 + ((gpio & 0x10) >> 2); /* lower or upper register */ | 211 | if (GPIO_EDGE_SEL >= 0) { |
| 184 | bit = gpio & 0xf; | 212 | val = readl(port->base + GPIO_EDGE_SEL); |
| 185 | val = readl(reg) & ~(0x3 << (bit << 1)); | 213 | if (edge == GPIO_INT_BOTH_EDGES) |
| 186 | writel(val | (edge << (bit << 1)), reg); | 214 | writel(val | (1 << (gpio & 0x1f)), |
| 215 | port->base + GPIO_EDGE_SEL); | ||
| 216 | else | ||
| 217 | writel(val & ~(1 << (gpio & 0x1f)), | ||
| 218 | port->base + GPIO_EDGE_SEL); | ||
| 219 | } | ||
| 220 | |||
| 221 | if (edge != GPIO_INT_BOTH_EDGES) { | ||
| 222 | reg += GPIO_ICR1 + ((gpio & 0x10) >> 2); /* lower or upper register */ | ||
| 223 | bit = gpio & 0xf; | ||
| 224 | val = readl(reg) & ~(0x3 << (bit << 1)); | ||
| 225 | writel(val | (edge << (bit << 1)), reg); | ||
| 226 | } | ||
| 227 | |||
| 187 | writel(1 << (gpio & 0x1f), port->base + GPIO_ISR); | 228 | writel(1 << (gpio & 0x1f), port->base + GPIO_ISR); |
| 188 | 229 | ||
| 189 | return 0; | 230 | return 0; |
| @@ -338,7 +379,9 @@ static void __devinit mxc_gpio_get_hw(struct platform_device *pdev) | |||
| 338 | return; | 379 | return; |
| 339 | } | 380 | } |
| 340 | 381 | ||
| 341 | if (hwtype == IMX31_GPIO) | 382 | if (hwtype == IMX35_GPIO) |
| 383 | mxc_gpio_hwdata = &imx35_gpio_hwdata; | ||
| 384 | else if (hwtype == IMX31_GPIO) | ||
| 342 | mxc_gpio_hwdata = &imx31_gpio_hwdata; | 385 | mxc_gpio_hwdata = &imx31_gpio_hwdata; |
| 343 | else | 386 | else |
| 344 | mxc_gpio_hwdata = &imx1_imx21_gpio_hwdata; | 387 | mxc_gpio_hwdata = &imx1_imx21_gpio_hwdata; |
