diff options
| -rw-r--r-- | arch/arm/include/asm/arch-tegra2/gpio.h | 250 | ||||
| -rw-r--r-- | arch/arm/include/asm/gpio.h | 38 | ||||
| -rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
| -rw-r--r-- | drivers/gpio/tegra2_gpio.c | 255 | 
4 files changed, 534 insertions, 10 deletions
| diff --git a/arch/arm/include/asm/arch-tegra2/gpio.h b/arch/arm/include/asm/arch-tegra2/gpio.h index 0fb8f0d40f4..41e66fe1b15 100644 --- a/arch/arm/include/asm/arch-tegra2/gpio.h +++ b/arch/arm/include/asm/arch-tegra2/gpio.h @@ -23,11 +23,13 @@  #define _TEGRA2_GPIO_H_  /* - * The Tegra 2x GPIO controller has 222 GPIOs arranged in 8 banks of 4 ports, + * The Tegra 2x GPIO controller has 224 GPIOs arranged in 7 banks of 4 ports,   * each with 8 GPIOs.   */ -#define TEGRA_GPIO_PORTS 4   /* The number of ports per bank */ -#define TEGRA_GPIO_BANKS 8   /* The number of banks */ +#define TEGRA_GPIO_PORTS	4	/* number of ports per bank */ +#define TEGRA_GPIO_BANKS	7	/* number of banks */ +#define MAX_NUM_GPIOS		(TEGRA_GPIO_PORTS * TEGRA_GPIO_BANKS * 8) +#define GPIO_NAME_SIZE		20	/* gpio_request max label len */  /* GPIO Controller registers for a single bank */  struct gpio_ctlr_bank { @@ -45,15 +47,243 @@ struct gpio_ctlr {  	struct gpio_ctlr_bank gpio_bank[TEGRA_GPIO_BANKS];  }; -#define GPIO_BANK(x)	((x) >> 5) -#define GPIO_PORT(x)	(((x) >> 3) & 0x3) -#define GPIO_BIT(x)	((x) & 0x7) +#define GPIO_BANK(x)		((x) >> 5) +#define GPIO_PORT(x)		(((x) >> 3) & 0x3) +#define GPIO_FULLPORT(x)	((x) >> 3) +#define GPIO_BIT(x)		((x) & 0x7) + +enum gpio_pin { +	GPIO_PA0 = 0,	/* pin 0 */ +	GPIO_PA1, +	GPIO_PA2, +	GPIO_PA3, +	GPIO_PA4, +	GPIO_PA5, +	GPIO_PA6, +	GPIO_PA7, +	GPIO_PB0,	/* pin 8 */ +	GPIO_PB1, +	GPIO_PB2, +	GPIO_PB3, +	GPIO_PB4, +	GPIO_PB5, +	GPIO_PB6, +	GPIO_PB7, +	GPIO_PC0,	/* pin 16 */ +	GPIO_PC1, +	GPIO_PC2, +	GPIO_PC3, +	GPIO_PC4, +	GPIO_PC5, +	GPIO_PC6, +	GPIO_PC7, +	GPIO_PD0,	/* pin 24 */ +	GPIO_PD1, +	GPIO_PD2, +	GPIO_PD3, +	GPIO_PD4, +	GPIO_PD5, +	GPIO_PD6, +	GPIO_PD7, +	GPIO_PE0,	/* pin 32 */ +	GPIO_PE1, +	GPIO_PE2, +	GPIO_PE3, +	GPIO_PE4, +	GPIO_PE5, +	GPIO_PE6, +	GPIO_PE7, +	GPIO_PF0,	/* pin 40 */ +	GPIO_PF1, +	GPIO_PF2, +	GPIO_PF3, +	GPIO_PF4, +	GPIO_PF5, +	GPIO_PF6, +	GPIO_PF7, +	GPIO_PG0,	/* pin 48 */ +	GPIO_PG1, +	GPIO_PG2, +	GPIO_PG3, +	GPIO_PG4, +	GPIO_PG5, +	GPIO_PG6, +	GPIO_PG7, +	GPIO_PH0,	/* pin 56 */ +	GPIO_PH1, +	GPIO_PH2, +	GPIO_PH3, +	GPIO_PH4, +	GPIO_PH5, +	GPIO_PH6, +	GPIO_PH7, +	GPIO_PI0,	/* pin 64 */ +	GPIO_PI1, +	GPIO_PI2, +	GPIO_PI3, +	GPIO_PI4, +	GPIO_PI5, +	GPIO_PI6, +	GPIO_PI7, +	GPIO_PJ0,	/* pin 72 */ +	GPIO_PJ1, +	GPIO_PJ2, +	GPIO_PJ3, +	GPIO_PJ4, +	GPIO_PJ5, +	GPIO_PJ6, +	GPIO_PJ7, +	GPIO_PK0,	/* pin 80 */ +	GPIO_PK1, +	GPIO_PK2, +	GPIO_PK3, +	GPIO_PK4, +	GPIO_PK5, +	GPIO_PK6, +	GPIO_PK7, +	GPIO_PL0,	/* pin 88 */ +	GPIO_PL1, +	GPIO_PL2, +	GPIO_PL3, +	GPIO_PL4, +	GPIO_PL5, +	GPIO_PL6, +	GPIO_PL7, +	GPIO_PM0,	/* pin 96 */ +	GPIO_PM1, +	GPIO_PM2, +	GPIO_PM3, +	GPIO_PM4, +	GPIO_PM5, +	GPIO_PM6, +	GPIO_PM7, +	GPIO_PN0,	/* pin 104 */ +	GPIO_PN1, +	GPIO_PN2, +	GPIO_PN3, +	GPIO_PN4, +	GPIO_PN5, +	GPIO_PN6, +	GPIO_PN7, +	GPIO_PO0,	/* pin 112 */ +	GPIO_PO1, +	GPIO_PO2, +	GPIO_PO3, +	GPIO_PO4, +	GPIO_PO5, +	GPIO_PO6, +	GPIO_PO7, +	GPIO_PP0,	/* pin 120 */ +	GPIO_PP1, +	GPIO_PP2, +	GPIO_PP3, +	GPIO_PP4, +	GPIO_PP5, +	GPIO_PP6, +	GPIO_PP7, +	GPIO_PQ0,	/* pin 128 */ +	GPIO_PQ1, +	GPIO_PQ2, +	GPIO_PQ3, +	GPIO_PQ4, +	GPIO_PQ5, +	GPIO_PQ6, +	GPIO_PQ7, +	GPIO_PR0,	/* pin 136 */ +	GPIO_PR1, +	GPIO_PR2, +	GPIO_PR3, +	GPIO_PR4, +	GPIO_PR5, +	GPIO_PR6, +	GPIO_PR7, +	GPIO_PS0,	/* pin 144 */ +	GPIO_PS1, +	GPIO_PS2, +	GPIO_PS3, +	GPIO_PS4, +	GPIO_PS5, +	GPIO_PS6, +	GPIO_PS7, +	GPIO_PT0,	/* pin 152 */ +	GPIO_PT1, +	GPIO_PT2, +	GPIO_PT3, +	GPIO_PT4, +	GPIO_PT5, +	GPIO_PT6, +	GPIO_PT7, +	GPIO_PU0,	/* pin 160 */ +	GPIO_PU1, +	GPIO_PU2, +	GPIO_PU3, +	GPIO_PU4, +	GPIO_PU5, +	GPIO_PU6, +	GPIO_PU7, +	GPIO_PV0,	/* pin 168 */ +	GPIO_PV1, +	GPIO_PV2, +	GPIO_PV3, +	GPIO_PV4, +	GPIO_PV5, +	GPIO_PV6, +	GPIO_PV7, +	GPIO_PW0,	/* pin 176 */ +	GPIO_PW1, +	GPIO_PW2, +	GPIO_PW3, +	GPIO_PW4, +	GPIO_PW5, +	GPIO_PW6, +	GPIO_PW7, +	GPIO_PX0,	/* pin 184 */ +	GPIO_PX1, +	GPIO_PX2, +	GPIO_PX3, +	GPIO_PX4, +	GPIO_PX5, +	GPIO_PX6, +	GPIO_PX7, +	GPIO_PY0,	/* pin 192 */ +	GPIO_PY1, +	GPIO_PY2, +	GPIO_PY3, +	GPIO_PY4, +	GPIO_PY5, +	GPIO_PY6, +	GPIO_PY7, +	GPIO_PZ0,	/* pin 200 */ +	GPIO_PZ1, +	GPIO_PZ2, +	GPIO_PZ3, +	GPIO_PZ4, +	GPIO_PZ5, +	GPIO_PZ6, +	GPIO_PZ7, +	GPIO_PAA0,	/* pin 208 */ +	GPIO_PAA1, +	GPIO_PAA2, +	GPIO_PAA3, +	GPIO_PAA4, +	GPIO_PAA5, +	GPIO_PAA6, +	GPIO_PAA7, +	GPIO_PBB0,	/* pin 216 */ +	GPIO_PBB1, +	GPIO_PBB2, +	GPIO_PBB3, +	GPIO_PBB4, +	GPIO_PBB5, +	GPIO_PBB6, +	GPIO_PBB7,	/* pin 223 */ +};  /* - * GPIO_PI3 = Port I = 8, bit = 3. - * Seaboard: used for UART/SPI selection - * Harmony: not used + * Tegra2-specific GPIO API   */ -#define GPIO_PI3	((8 << 3) | 3) +void gpio_info(void); + +#define gpio_status()	gpio_info()  #endif	/* TEGRA2_GPIO_H_ */ diff --git a/arch/arm/include/asm/gpio.h b/arch/arm/include/asm/gpio.h new file mode 100644 index 00000000000..eb071d18245 --- /dev/null +++ b/arch/arm/include/asm/gpio.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011, NVIDIA Corp. All rights reserved. + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _GPIO_H_ +#define _GPIO_H_ + +#include <asm/arch/gpio.h> +/* + * Generic GPIO API + */ + +int gpio_request(int gp, const char *label); +void gpio_free(int gp); +void gpio_toggle_value(int gp); +int gpio_direction_input(int gp); +int gpio_direction_output(int gp, int value); +int gpio_get_value(int gp); +void gpio_set_value(int gp, int value); + +#endif	/* _GPIO_H_ */ diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index a5fa2b5d851..1e3ae11347b 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -31,6 +31,7 @@ COBJS-$(CONFIG_MARVELL_MFP)	+= mvmfp.o  COBJS-$(CONFIG_MXC_GPIO)	+= mxc_gpio.o  COBJS-$(CONFIG_PCA953X)		+= pca953x.o  COBJS-$(CONFIG_S5P)		+= s5p_gpio.o +COBJS-$(CONFIG_TEGRA2_GPIO)	+= tegra2_gpio.o  COBJS	:= $(COBJS-y)  SRCS 	:= $(COBJS:.o=.c) diff --git a/drivers/gpio/tegra2_gpio.c b/drivers/gpio/tegra2_gpio.c new file mode 100644 index 00000000000..f686e80637a --- /dev/null +++ b/drivers/gpio/tegra2_gpio.c @@ -0,0 +1,255 @@ +/* + * NVIDIA Tegra2 GPIO handling. + *  (C) Copyright 2010,2011 + *  NVIDIA Corporation <www.nvidia.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Based on (mostly copied from) kw_gpio.c based Linux 2.6 kernel driver. + * Tom Warren (twarren@nvidia.com) + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/bitops.h> +#include <asm/arch/tegra2.h> +#include <asm/gpio.h> + +enum { +	TEGRA2_CMD_INFO, +	TEGRA2_CMD_PORT, +	TEGRA2_CMD_OUTPUT, +	TEGRA2_CMD_INPUT, +}; + +static struct gpio_names { +	char name[GPIO_NAME_SIZE]; +} gpio_names[MAX_NUM_GPIOS]; + +static char *get_name(int i) +{ +	return *gpio_names[i].name ? gpio_names[i].name : "UNKNOWN"; +} + +/* Return config of pin 'gp' as GPIO (1) or SFPIO (0) */ +static int get_config(int gp) +{ +	struct gpio_ctlr *gpio = (struct gpio_ctlr *)NV_PA_GPIO_BASE; +	struct gpio_ctlr_bank *bank = &gpio->gpio_bank[GPIO_BANK(gp)]; +	u32 u; +	int type; + +	u = readl(&bank->gpio_config[GPIO_PORT(gp)]); +	type =  (u >> GPIO_BIT(gp)) & 1; + +	debug("get_config: port = %d, bit = %d is %s\n", +		GPIO_FULLPORT(gp), GPIO_BIT(gp), type ? "GPIO" : "SFPIO"); + +	return type; +} + +/* Config pin 'gp' as GPIO or SFPIO, based on 'type' */ +static void set_config(int gp, int type) +{ +	struct gpio_ctlr *gpio = (struct gpio_ctlr *)NV_PA_GPIO_BASE; +	struct gpio_ctlr_bank *bank = &gpio->gpio_bank[GPIO_BANK(gp)]; +	u32 u; + +	debug("set_config: port = %d, bit = %d, %s\n", +		GPIO_FULLPORT(gp), GPIO_BIT(gp), type ? "GPIO" : "SFPIO"); + +	u = readl(&bank->gpio_config[GPIO_PORT(gp)]); +	if (type)				/* GPIO */ +		u |= 1 << GPIO_BIT(gp); +	else +		u &= ~(1 << GPIO_BIT(gp)); +	writel(u, &bank->gpio_config[GPIO_PORT(gp)]); +} + +/* Return GPIO pin 'gp' direction - 0 = input or 1 = output */ +static int get_direction(int gp) +{ +	struct gpio_ctlr *gpio = (struct gpio_ctlr *)NV_PA_GPIO_BASE; +	struct gpio_ctlr_bank *bank = &gpio->gpio_bank[GPIO_BANK(gp)]; +	u32 u; +	int dir; + +	u = readl(&bank->gpio_dir_out[GPIO_PORT(gp)]); +	dir =  (u >> GPIO_BIT(gp)) & 1; + +	debug("get_direction: port = %d, bit = %d, %s\n", +		GPIO_FULLPORT(gp), GPIO_BIT(gp), dir ? "OUT" : "IN"); + +	return dir; +} + +/* Config GPIO pin 'gp' as input or output (OE) as per 'output' */ +static void set_direction(int gp, int output) +{ +	struct gpio_ctlr *gpio = (struct gpio_ctlr *)NV_PA_GPIO_BASE; +	struct gpio_ctlr_bank *bank = &gpio->gpio_bank[GPIO_BANK(gp)]; +	u32 u; + +	debug("set_direction: port = %d, bit = %d, %s\n", +		GPIO_FULLPORT(gp), GPIO_BIT(gp), output ? "OUT" : "IN"); + +	u = readl(&bank->gpio_dir_out[GPIO_PORT(gp)]); +	if (output) +		u |= 1 << GPIO_BIT(gp); +	else +		u &= ~(1 << GPIO_BIT(gp)); +	writel(u, &bank->gpio_dir_out[GPIO_PORT(gp)]); +} + +/* set GPIO pin 'gp' output bit as 0 or 1 as per 'high' */ +static void set_level(int gp, int high) +{ +	struct gpio_ctlr *gpio = (struct gpio_ctlr *)NV_PA_GPIO_BASE; +	struct gpio_ctlr_bank *bank = &gpio->gpio_bank[GPIO_BANK(gp)]; +	u32 u; + +	debug("set_level: port = %d, bit %d == %d\n", +		GPIO_FULLPORT(gp), GPIO_BIT(gp), high); + +	u = readl(&bank->gpio_out[GPIO_PORT(gp)]); +	if (high) +		u |= 1 << GPIO_BIT(gp); +	else +		u &= ~(1 << GPIO_BIT(gp)); +	writel(u, &bank->gpio_out[GPIO_PORT(gp)]); +} + +/* + * Generic_GPIO primitives. + */ + +int gpio_request(int gp, const char *label) +{ +	if (gp >= MAX_NUM_GPIOS) +		return -1; + +	strncpy(gpio_names[gp].name, label, GPIO_NAME_SIZE); +	gpio_names[gp].name[GPIO_NAME_SIZE - 1] = '\0'; + +	/* Configure as a GPIO */ +	set_config(gp, 1); + +	return 0; +} + +void gpio_free(int gp) +{ +} + +/* read GPIO OUT value of pin 'gp' */ +static int gpio_get_output_value(int gp) +{ +	struct gpio_ctlr *gpio = (struct gpio_ctlr *)NV_PA_GPIO_BASE; +	struct gpio_ctlr_bank *bank = &gpio->gpio_bank[GPIO_BANK(gp)]; +	int val; + +	debug("gpio_get_output_value: pin = %d (port %d:bit %d)\n", +		gp, GPIO_FULLPORT(gp), GPIO_BIT(gp)); + +	val = readl(&bank->gpio_out[GPIO_PORT(gp)]); + +	return (val >> GPIO_BIT(gp)) & 1; +} + +void gpio_toggle_value(int gp) +{ +	gpio_set_value(gp, !gpio_get_output_value(gp)); +} + +/* set GPIO pin 'gp' as an input */ +int gpio_direction_input(int gp) +{ +	debug("gpio_direction_input: pin = %d (port %d:bit %d)\n", +		gp, GPIO_FULLPORT(gp), GPIO_BIT(gp)); + +	/* Configure GPIO direction as input. */ +	set_direction(gp, 0); + +	return 0; +} + +/* set GPIO pin 'gp' as an output, with polarity 'value' */ +int gpio_direction_output(int gp, int value) +{ +	debug("gpio_direction_output: pin = %d (port %d:bit %d) = %s\n", +		gp, GPIO_FULLPORT(gp), GPIO_BIT(gp), value ? "HIGH" : "LOW"); + +	/* Configure GPIO output value. */ +	set_level(gp, value); + +	/* Configure GPIO direction as output. */ +	set_direction(gp, 1); + +	return 0; +} + +/* read GPIO IN value of pin 'gp' */ +int gpio_get_value(int gp) +{ +	struct gpio_ctlr *gpio = (struct gpio_ctlr *)NV_PA_GPIO_BASE; +	struct gpio_ctlr_bank *bank = &gpio->gpio_bank[GPIO_BANK(gp)]; +	int val; + +	debug("gpio_get_value: pin = %d (port %d:bit %d)\n", +		gp, GPIO_FULLPORT(gp), GPIO_BIT(gp)); + +	val = readl(&bank->gpio_in[GPIO_PORT(gp)]); + +	return (val >> GPIO_BIT(gp)) & 1; +} + +/* write GPIO OUT value to pin 'gp' */ +void gpio_set_value(int gp, int value) +{ +	debug("gpio_set_value: pin = %d (port %d:bit %d), value = %d\n", +		gp, GPIO_FULLPORT(gp), GPIO_BIT(gp), value); + +	/* Configure GPIO output value. */ +	set_level(gp, value); +} + +/* + * Display Tegra GPIO information + */ +void gpio_info(void) +{ +	int c, type; + +	for (c = 0; c < MAX_NUM_GPIOS; c++) { +		type = get_config(c);		/* GPIO, not SFPIO */ +		if (type) { +			printf("GPIO_%d:\t%s is an %s, ", c, +				get_name(c), +				get_direction(c) ? "OUTPUT" : "INPUT"); +			if (get_direction(c)) +				printf("value = %d", gpio_get_output_value(c)); +			else +				printf("value = %d", gpio_get_value(c)); +			printf("\n"); +		} else +			continue; +	} +} | 
