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>
This commit is contained in:

committed by
Linus Walleij

parent
41920d1636
commit
aeb27748e3
@@ -38,7 +38,8 @@
|
||||
enum mxc_gpio_hwtype {
|
||||
IMX1_GPIO, /* runs on i.mx1 */
|
||||
IMX21_GPIO, /* runs on i.mx21 and i.mx27 */
|
||||
IMX31_GPIO, /* runs on all other i.mx */
|
||||
IMX31_GPIO, /* runs on i.mx31 */
|
||||
IMX35_GPIO, /* runs on all other i.mx */
|
||||
};
|
||||
|
||||
/* device type dependent stuff */
|
||||
@@ -50,6 +51,7 @@ struct mxc_gpio_hwdata {
|
||||
unsigned icr2_reg;
|
||||
unsigned imr_reg;
|
||||
unsigned isr_reg;
|
||||
int edge_sel_reg;
|
||||
unsigned low_level;
|
||||
unsigned high_level;
|
||||
unsigned rise_edge;
|
||||
@@ -74,6 +76,7 @@ static struct mxc_gpio_hwdata imx1_imx21_gpio_hwdata = {
|
||||
.icr2_reg = 0x2c,
|
||||
.imr_reg = 0x30,
|
||||
.isr_reg = 0x34,
|
||||
.edge_sel_reg = -EINVAL,
|
||||
.low_level = 0x03,
|
||||
.high_level = 0x02,
|
||||
.rise_edge = 0x00,
|
||||
@@ -88,6 +91,22 @@ static struct mxc_gpio_hwdata imx31_gpio_hwdata = {
|
||||
.icr2_reg = 0x10,
|
||||
.imr_reg = 0x14,
|
||||
.isr_reg = 0x18,
|
||||
.edge_sel_reg = -EINVAL,
|
||||
.low_level = 0x00,
|
||||
.high_level = 0x01,
|
||||
.rise_edge = 0x02,
|
||||
.fall_edge = 0x03,
|
||||
};
|
||||
|
||||
static struct mxc_gpio_hwdata imx35_gpio_hwdata = {
|
||||
.dr_reg = 0x00,
|
||||
.gdir_reg = 0x04,
|
||||
.psr_reg = 0x08,
|
||||
.icr1_reg = 0x0c,
|
||||
.icr2_reg = 0x10,
|
||||
.imr_reg = 0x14,
|
||||
.isr_reg = 0x18,
|
||||
.edge_sel_reg = 0x1c,
|
||||
.low_level = 0x00,
|
||||
.high_level = 0x01,
|
||||
.rise_edge = 0x02,
|
||||
@@ -104,12 +123,13 @@ static struct mxc_gpio_hwdata *mxc_gpio_hwdata;
|
||||
#define GPIO_ICR2 (mxc_gpio_hwdata->icr2_reg)
|
||||
#define GPIO_IMR (mxc_gpio_hwdata->imr_reg)
|
||||
#define GPIO_ISR (mxc_gpio_hwdata->isr_reg)
|
||||
#define GPIO_EDGE_SEL (mxc_gpio_hwdata->edge_sel_reg)
|
||||
|
||||
#define GPIO_INT_LOW_LEV (mxc_gpio_hwdata->low_level)
|
||||
#define GPIO_INT_HIGH_LEV (mxc_gpio_hwdata->high_level)
|
||||
#define GPIO_INT_RISE_EDGE (mxc_gpio_hwdata->rise_edge)
|
||||
#define GPIO_INT_FALL_EDGE (mxc_gpio_hwdata->fall_edge)
|
||||
#define GPIO_INT_NONE 0x4
|
||||
#define GPIO_INT_BOTH_EDGES 0x4
|
||||
|
||||
static struct platform_device_id mxc_gpio_devtype[] = {
|
||||
{
|
||||
@@ -121,6 +141,9 @@ static struct platform_device_id mxc_gpio_devtype[] = {
|
||||
}, {
|
||||
.name = "imx31-gpio",
|
||||
.driver_data = IMX31_GPIO,
|
||||
}, {
|
||||
.name = "imx35-gpio",
|
||||
.driver_data = IMX35_GPIO,
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
@@ -130,6 +153,7 @@ static const struct of_device_id mxc_gpio_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx1-gpio", .data = &mxc_gpio_devtype[IMX1_GPIO], },
|
||||
{ .compatible = "fsl,imx21-gpio", .data = &mxc_gpio_devtype[IMX21_GPIO], },
|
||||
{ .compatible = "fsl,imx31-gpio", .data = &mxc_gpio_devtype[IMX31_GPIO], },
|
||||
{ .compatible = "fsl,imx35-gpio", .data = &mxc_gpio_devtype[IMX35_GPIO], },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
@@ -160,15 +184,19 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type)
|
||||
edge = GPIO_INT_FALL_EDGE;
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
val = gpio_get_value(gpio);
|
||||
if (val) {
|
||||
edge = GPIO_INT_LOW_LEV;
|
||||
pr_debug("mxc: set GPIO %d to low trigger\n", gpio);
|
||||
if (GPIO_EDGE_SEL >= 0) {
|
||||
edge = GPIO_INT_BOTH_EDGES;
|
||||
} else {
|
||||
edge = GPIO_INT_HIGH_LEV;
|
||||
pr_debug("mxc: set GPIO %d to high trigger\n", gpio);
|
||||
val = gpio_get_value(gpio);
|
||||
if (val) {
|
||||
edge = GPIO_INT_LOW_LEV;
|
||||
pr_debug("mxc: set GPIO %d to low trigger\n", gpio);
|
||||
} else {
|
||||
edge = GPIO_INT_HIGH_LEV;
|
||||
pr_debug("mxc: set GPIO %d to high trigger\n", gpio);
|
||||
}
|
||||
port->both_edges |= 1 << (gpio & 31);
|
||||
}
|
||||
port->both_edges |= 1 << (gpio & 31);
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
edge = GPIO_INT_LOW_LEV;
|
||||
@@ -180,10 +208,23 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
reg += GPIO_ICR1 + ((gpio & 0x10) >> 2); /* lower or upper register */
|
||||
bit = gpio & 0xf;
|
||||
val = readl(reg) & ~(0x3 << (bit << 1));
|
||||
writel(val | (edge << (bit << 1)), reg);
|
||||
if (GPIO_EDGE_SEL >= 0) {
|
||||
val = readl(port->base + GPIO_EDGE_SEL);
|
||||
if (edge == GPIO_INT_BOTH_EDGES)
|
||||
writel(val | (1 << (gpio & 0x1f)),
|
||||
port->base + GPIO_EDGE_SEL);
|
||||
else
|
||||
writel(val & ~(1 << (gpio & 0x1f)),
|
||||
port->base + GPIO_EDGE_SEL);
|
||||
}
|
||||
|
||||
if (edge != GPIO_INT_BOTH_EDGES) {
|
||||
reg += GPIO_ICR1 + ((gpio & 0x10) >> 2); /* lower or upper register */
|
||||
bit = gpio & 0xf;
|
||||
val = readl(reg) & ~(0x3 << (bit << 1));
|
||||
writel(val | (edge << (bit << 1)), reg);
|
||||
}
|
||||
|
||||
writel(1 << (gpio & 0x1f), port->base + GPIO_ISR);
|
||||
|
||||
return 0;
|
||||
@@ -338,7 +379,9 @@ static void __devinit mxc_gpio_get_hw(struct platform_device *pdev)
|
||||
return;
|
||||
}
|
||||
|
||||
if (hwtype == IMX31_GPIO)
|
||||
if (hwtype == IMX35_GPIO)
|
||||
mxc_gpio_hwdata = &imx35_gpio_hwdata;
|
||||
else if (hwtype == IMX31_GPIO)
|
||||
mxc_gpio_hwdata = &imx31_gpio_hwdata;
|
||||
else
|
||||
mxc_gpio_hwdata = &imx1_imx21_gpio_hwdata;
|
||||
|
Reference in New Issue
Block a user