diff options
| author | Dieter Kiermaier <dk-arm-linux@gmx.de> | 2009-06-29 14:45:08 +0200 | 
|---|---|---|
| committer | Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> | 2009-07-23 00:19:28 +0200 | 
| commit | ec16441085f471c03a8c0909579463e31e5b947a (patch) | |
| tree | e5ff996bebfac324a332c2754d565017de7b1e68 /drivers/gpio/kw_gpio.c | |
| parent | 688b6a0ff2dcbb0c7e63ef63cbbcc291f14f321f (diff) | |
| download | olio-uboot-2014.01-ec16441085f471c03a8c0909579463e31e5b947a.tar.xz olio-uboot-2014.01-ec16441085f471c03a8c0909579463e31e5b947a.zip | |
Kirkwood: add Marvell Kirkwood gpio driver
Signed-off-by: Dieter Kiermaier <dk-arm-linux@gmx.de>
Acked-by: Prafulla Wadaskar <prafulla@marvell.com>
Tested-by: Heiko Schocher <hs@denx.de>
Diffstat (limited to 'drivers/gpio/kw_gpio.c')
| -rw-r--r-- | drivers/gpio/kw_gpio.c | 151 | 
1 files changed, 151 insertions, 0 deletions
| diff --git a/drivers/gpio/kw_gpio.c b/drivers/gpio/kw_gpio.c new file mode 100644 index 000000000..1c2883479 --- /dev/null +++ b/drivers/gpio/kw_gpio.c @@ -0,0 +1,151 @@ +/* + * arch/arm/plat-orion/gpio.c + * + * Marvell Orion SoC GPIO handling. + * + * This file is licensed under the terms of the GNU General Public + * License version 2.  This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +/* + * Based on (mostly copied from) plat-orion based Linux 2.6 kernel driver. + * Removed orion_gpiochip struct and kernel level irq handling. + * + * Dieter Kiermaier dk-arm-linux@gmx.de + */ + +#include <common.h> +#include <asm/bitops.h> +#include <asm/arch/kirkwood.h> +#include <asm/arch/gpio.h> + +static unsigned long gpio_valid_input[BITS_TO_LONGS(GPIO_MAX)]; +static unsigned long gpio_valid_output[BITS_TO_LONGS(GPIO_MAX)]; + +void __set_direction(unsigned pin, int input) +{ +	u32 u; + +	u = readl(GPIO_IO_CONF(pin)); +	if (input) +		u |= 1 << (pin & 31); +	else +		u &= ~(1 << (pin & 31)); +	writel(u, GPIO_IO_CONF(pin)); + +	u = readl(GPIO_IO_CONF(pin)); +} + +void __set_level(unsigned pin, int high) +{ +	u32 u; + +	u = readl(GPIO_OUT(pin)); +	if (high) +		u |= 1 << (pin & 31); +	else +		u &= ~(1 << (pin & 31)); +	writel(u, GPIO_OUT(pin)); +} + +void __set_blinking(unsigned pin, int blink) +{ +	u32 u; + +	u = readl(GPIO_BLINK_EN(pin)); +	if (blink) +		u |= 1 << (pin & 31); +	else +		u &= ~(1 << (pin & 31)); +	writel(u, GPIO_BLINK_EN(pin)); +} + +int kw_gpio_is_valid(unsigned pin, int mode) +{ +	if (pin < GPIO_MAX) { +		if ((mode & GPIO_INPUT_OK) && !test_bit(pin, gpio_valid_input)) +			goto err_out; + +		if ((mode & GPIO_OUTPUT_OK) && !test_bit(pin, gpio_valid_output)) +			goto err_out; +		return 0; +	} + +err_out: +		printf("%s: invalid GPIO %d\n", __func__, pin); +	return 1; +} + +void kw_gpio_set_valid(unsigned pin, int mode) +{ +	if (mode == 1) +		mode = GPIO_INPUT_OK | GPIO_OUTPUT_OK; +	if (mode & GPIO_INPUT_OK) +		__set_bit(pin, gpio_valid_input); +	else +		__clear_bit(pin, gpio_valid_input); +	if (mode & GPIO_OUTPUT_OK) +		__set_bit(pin, gpio_valid_output); +	else +		__clear_bit(pin, gpio_valid_output); +} +/* + * GENERIC_GPIO primitives. + */ +int kw_gpio_direction_input(unsigned pin) +{ +	if (!kw_gpio_is_valid(pin, GPIO_INPUT_OK)) +		return 1; + +	/* Configure GPIO direction. */ +	__set_direction(pin, 1); + +	return 0; +} + +int kw_gpio_direction_output(unsigned pin, int value) +{ +	if (kw_gpio_is_valid(pin, GPIO_OUTPUT_OK) != 0) +	{ +		printf("%s: invalid GPIO %d\n", __func__, pin); +		return 1; +	} + +	__set_blinking(pin, 0); + +	/* Configure GPIO output value. */ +	__set_level(pin, value); + +	/* Configure GPIO direction. */ +	__set_direction(pin, 0); + +	return 0; +} + +int kw_gpio_get_value(unsigned pin) +{ +	int val; + +	if (readl(GPIO_IO_CONF(pin)) & (1 << (pin & 31))) +		val = readl(GPIO_DATA_IN(pin)) ^ readl(GPIO_IN_POL(pin)); +	else +		val = readl(GPIO_OUT(pin)); + +	return (val >> (pin & 31)) & 1; +} + +void kw_gpio_set_value(unsigned pin, int value) +{ +	/* Configure GPIO output value. */ +	__set_level(pin, value); +} + +void kw_gpio_set_blink(unsigned pin, int blink) +{ +	/* Set output value to zero. */ +	__set_level(pin, 0); + +	/* Set blinking. */ +	__set_blinking(pin, blink); +} |