diff options
| author | Benoît Thébaudeau <benoit.thebaudeau@advansee.com> | 2012-06-22 21:04:06 +0200 | 
|---|---|---|
| committer | Linus Walleij <linus.walleij@linaro.org> | 2012-07-17 21:00:16 +0200 | 
| commit | aeb27748e3bc1e89ec590713e574cb6f885cc3c6 (patch) | |
| tree | 79a76bb0bd3275173fdf5840db8e0c1683fd0f8b /drivers/gpio/gpio-mxc.c | |
| parent | 41920d16360ebc8c482911078a17d9994fb77612 (diff) | |
| download | olio-linux-3.10-aeb27748e3bc1e89ec590713e574cb6f885cc3c6.tar.xz olio-linux-3.10-aeb27748e3bc1e89ec590713e574cb6f885cc3c6.zip  | |
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/gpio-mxc.c')
| -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 c337143b18f..bb985e81553 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -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[] = {  	{ @@ -122,6 +142,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;  |