From patchwork Wed Jun 8 22:08:12 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tom Warren X-Patchwork-Id: 99567 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 3C742B6F89 for ; Thu, 9 Jun 2011 08:15:44 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id CE808283CE; Thu, 9 Jun 2011 00:15:41 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id CAaJaI-0hKff; Thu, 9 Jun 2011 00:15:41 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id AF24A283C4; Thu, 9 Jun 2011 00:15:39 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 42151283C4 for ; Thu, 9 Jun 2011 00:15:37 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id CME3WRkGotTa for ; Thu, 9 Jun 2011 00:15:34 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-pv0-f172.google.com (mail-pv0-f172.google.com [74.125.83.172]) by theia.denx.de (Postfix) with ESMTPS id A891F283C2 for ; Thu, 9 Jun 2011 00:15:31 +0200 (CEST) Received: by pvh18 with SMTP id 18so453407pvh.3 for ; Wed, 08 Jun 2011 15:15:30 -0700 (PDT) Received: by 10.68.32.234 with SMTP id m10mr2602pbi.13.1307570971773; Wed, 08 Jun 2011 15:09:31 -0700 (PDT) Received: from localhost.localdomain (ip70-190-110-83.ph.ph.cox.net [70.190.110.83]) by mx.google.com with ESMTPS id p5sm820970pbk.68.2011.06.08.15.09.29 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 08 Jun 2011 15:09:31 -0700 (PDT) From: Tom Warren To: u-boot@lists.denx.de Date: Wed, 8 Jun 2011 15:08:12 -0700 Message-Id: <1307570893-31592-2-git-send-email-twarren@nvidia.com> X-Mailer: git-send-email 1.7.5.1 In-Reply-To: <1307570893-31592-1-git-send-email-twarren@nvidia.com> References: <1307570893-31592-1-git-send-email-twarren@nvidia.com> Cc: Tom Warren , twarren.nvidia@gmail.com Subject: [U-Boot] [PATCH V3 1/2] GPIO: Tegra2: add GPIO driver for Tegra2 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.9 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de Signed-off-by: Tom Warren --- Changes in V2: - use 'gpio_pin' enum in gpio.h (Simon Glass review request) - change 'GPIO_PORT8' to 'GPIO_FULLPORT' (Simon Glass request) - change 'offset' to 'pin' globally Changes in V3: - use common cmd_gpio; remove redundant cmd processing code - add gpio_request, gpio_free and gpio_toggle - alias 'gpio_status' to 'gpio_info' for use in cmd_gpio arch/arm/include/asm/arch-tegra2/gpio.h | 249 ++++++++++++++++++++++++++++++- common/cmd_gpio.c | 4 + drivers/gpio/Makefile | 1 + drivers/gpio/tegra2_gpio.c | 225 ++++++++++++++++++++++++++++ 4 files changed, 472 insertions(+), 7 deletions(-) create mode 100644 drivers/gpio/tegra2_gpio.c diff --git a/arch/arm/include/asm/arch-tegra2/gpio.h b/arch/arm/include/asm/arch-tegra2/gpio.h index 0fb8f0d..4718474 100644 --- a/arch/arm/include/asm/arch-tegra2/gpio.h +++ b/arch/arm/include/asm/arch-tegra2/gpio.h @@ -45,15 +45,250 @@ 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) +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); +void gpio_info(void); + +#define gpio_status() gpio_info() #endif /* TEGRA2_GPIO_H_ */ diff --git a/common/cmd_gpio.c b/common/cmd_gpio.c index 9cc790a..e5bff98 100644 --- a/common/cmd_gpio.c +++ b/common/cmd_gpio.c @@ -9,7 +9,11 @@ #include #include +#ifdef CONFIG_TEGRA2_GPIO +#include +#else #include +#endif #ifndef name_to_gpio #define name_to_gpio(name) simple_strtoul(name, NULL, 10) diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index a5fa2b5..1e3ae11 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 0000000..4ff5639 --- /dev/null +++ b/drivers/gpio/tegra2_gpio.c @@ -0,0 +1,225 @@ +/* + * NVIDIA Tegra2 GPIO handling. + * (C) Copyright 2010,2011 + * NVIDIA Corporation + * + * 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 +#include +#include +#include +#include + +enum { + TEGRA2_CMD_INFO, + TEGRA2_CMD_PORT, + TEGRA2_CMD_OUTPUT, + TEGRA2_CMD_INPUT, +}; + +int gpio_num = 0; +char gpio_label[20] = ""; + +/* Config pin 'gp' as GPIO or SFPIO, based on 'type' */ +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)]); + + gpio_num = gp; +} + +/* Config GPIO pin 'gp' as input or output (OE) as per 'output' */ +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' */ +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) +{ + /* Configure as a GPIO */ + __set_config(gp, 1); + + strcpy(gpio_label, label); + return 0; +} + +void gpio_free(int gp) +{ +} + +void gpio_toggle_value(int gp) +{ + gpio_set_value(gp, !gpio_get_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 as a GPIO */ + __set_config(gp, 1); + + /* 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 as a GPIO */ + __set_config(gp, 1); + + /* 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 i, port, gp = gpio_num; + struct gpio_ctlr *gpio = (struct gpio_ctlr *)NV_PA_GPIO_BASE; + struct gpio_ctlr_bank *bank = &gpio->gpio_bank[GPIO_BANK(gp)]; + u32 data; + + port = GPIO_FULLPORT(gp); /* 8-bit port # */ + + printf("Tegra2 GPIO port %d:\n", port); + printf("Label = %s\n", gpio_label); + printf("gpio bits: 76543210\n"); + printf("-------------------\n"); + + if (port < 0 || port > 27) + return; + + printf("GPIO_CNF: "); + data = readl(&bank->gpio_config[GPIO_PORT(gp)]); + for (i = 7; i >= 0; i--) + printf("%c", data & (1 << i) ? 'g' : 's'); + printf("\n"); + + printf("GPIO_OE: "); + data = readl(&bank->gpio_dir_out[GPIO_PORT(gp)]); + for (i = 7; i >= 0; i--) + printf("%c", data & (1 << i) ? 'o' : 'i'); + printf("\n"); + + printf("GPIO_IN: "); + data = readl(&bank->gpio_in[GPIO_PORT(gp)]); + for (i = 7; i >= 0; i--) + printf("%c", data & (1 << i) ? '1' : '0'); + printf("\n"); + + printf("GPIO_OUT: "); + data = readl(&bank->gpio_out[GPIO_PORT(gp)]); + for (i = 7; i >= 0; i--) + printf("%c", data & (1 << i) ? '1' : '0'); + printf("\n"); +}