Signed-off-by: Albert ARIBAUD (3ADEV) <albert.arib...@3adev.fr> --- arch/arm/include/asm/arch-lpc32xx/gpio.h | 43 ++++++ drivers/gpio/Makefile | 1 + drivers/gpio/lpc32xx_gpio.c | 223 +++++++++++++++++++++++++++++++ 3 files changed, 267 insertions(+) create mode 100644 arch/arm/include/asm/arch-lpc32xx/gpio.h create mode 100644 drivers/gpio/lpc32xx_gpio.c
diff --git a/arch/arm/include/asm/arch-lpc32xx/gpio.h b/arch/arm/include/asm/arch-lpc32xx/gpio.h new file mode 100644 index 0000000..3bd94e3 --- /dev/null +++ b/arch/arm/include/asm/arch-lpc32xx/gpio.h @@ -0,0 +1,43 @@ +/* + * LPC32xx GPIO interface + * + * (C) Copyright 2014 DENX Software Engineering GmbH + * Written-by: Albert ARIBAUD <albert.arib...@3adev.fr> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/** + * GPIO Register map for LPC32xx + */ + +struct gpio_regs { + u32 p3_inp_state; + u32 p3_outp_set; + u32 p3_outp_clr; + u32 p3_outp_state; + /* Watch out! the following are shared between p2 and p3 */ + u32 p2_p3_dir_set; + u32 p2_p3_dir_clr; + u32 p2_p3_dir_state; + /* Now back to 'one register for one port' */ + u32 p2_inp_state; + u32 p2_outp_set; + u32 p2_outp_clr; + u32 reserved1[6]; + u32 p0_inp_state; + u32 p0_outp_set; + u32 p0_outp_clr; + u32 p0_outp_state; + u32 p0_dir_set; + u32 p0_dir_clr; + u32 p0_dir_state; + u32 reserved2; + u32 p1_inp_state; + u32 p1_outp_set; + u32 p1_outp_clr; + u32 p1_outp_state; + u32 p1_dir_set; + u32 p1_dir_clr; + u32 p1_dir_state; +}; diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index aa11f15..559894a 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -37,3 +37,4 @@ obj-$(CONFIG_ADI_GPIO2) += adi_gpio2.o obj-$(CONFIG_TCA642X) += tca642x.o oby-$(CONFIG_SX151X) += sx151x.o obj-$(CONFIG_SUNXI_GPIO) += sunxi_gpio.o +obj-$(CONFIG_LPC32XX_GPIO) += lpc32xx_gpio.o diff --git a/drivers/gpio/lpc32xx_gpio.c b/drivers/gpio/lpc32xx_gpio.c new file mode 100644 index 0000000..0c08b00 --- /dev/null +++ b/drivers/gpio/lpc32xx_gpio.c @@ -0,0 +1,223 @@ +/* + * LPC32xxGPIO driver + * + * (C) Copyright 2014 DENX Software Engineering GmbH + * Written-by: Albert ARIBAUD <albert.arib...@3adev.fr> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/errno.h> +#include <asm/arch-lpc32xx/cpu.h> +#include <asm/arch-lpc32xx/gpio.h> + +/** + * LPC32xx GPIOs work in banks but are non-homogeneous: + * - each bank holds a different number of GPIOs + * - some GPIOs are input/ouput, some input only, some output only; + * - some GPIOs have different meanings as an input and as an output; + * - some GPIOs are controlled on a given port and bit index, but + * read on another one. +* + * In order to keep this code simple, GPIOS are considered here as + * homogeneous and linear, from 0 to 127. + * + * ** WARNING ** + * + * Client code is responsible for properly using valid GPIO numbers, + * including cases where reading back a GPIO is done on a different + * register and bit than writing it. + */ + +static struct gpio_regs *regs = (struct gpio_regs *)GPIO_BASE; + +/** + * We have 4 GPIO ports of 32 bits each + */ + +#define MAX_GPIO 128 + +#define GPIO_TO_PORT(gpio) ((gpio / 32) & 3) +#define GPIO_TO_RANK(gpio) (gpio % 32) +#define GPIO_TO_MASK(gpio) (1 << (gpio % 32)) + +/** + * GPIO requesting and freeing are not implemented + */ + +int gpio_request(unsigned gpio, const char *label) +{ + debug("%s: GPIO %d requested as \"%s\"\n", __func__, gpio, label); + return 0; +} + +int gpio_free(unsigned gpio) +{ + debug("%s: GPIO %d freed\n", __func__, gpio); + return 0; +} + +/** + * Configure a GPIO as input + */ + +int gpio_direction_input(unsigned gpio) +{ + int port, mask; + + port = GPIO_TO_PORT(gpio); + mask = GPIO_TO_MASK(gpio); + + switch (port) { + case 0: + writel(mask, ®s->p0_dir_clr); + break; + case 1: + writel(mask, ®s->p1_dir_clr); + break; + case 2: + /* ports 2 and 3 share a common direction */ + case 3: + writel(mask, ®s->p2_p3_dir_clr); + break; + default: + return -1; + } + return 0; +} + +/** + * Configure a GPIO as output + */ + +int gpio_direction_output(unsigned gpio, int value) +{ + int port, mask; + + port = GPIO_TO_PORT(gpio); + mask = GPIO_TO_MASK(gpio); + + switch (port) { + case 0: + writel(mask, ®s->p0_dir_set); + break; + case 1: + writel(mask, ®s->p1_dir_set); + break; + case 2: + /* ports 2 and 3 share a common direction */ + case 3: + writel(mask, ®s->p2_p3_dir_set); + break; + default: + return -1; + } + return 0; +} + +/** + * Get the value of a GPIO + */ + +int gpio_get_value(unsigned gpio) +{ + int port, rank, mask, value; + + port = GPIO_TO_PORT(gpio); + + switch (port) { + case 0: + value = readl(®s->p0_inp_state); + break; + case 1: + value = readl(®s->p1_inp_state); + break; + case 2: + value = readl(®s->p2_inp_state); + break; + case 3: + value = readl(®s->p3_inp_state); + break; + default: + return -1; + } + + rank = GPIO_TO_RANK(gpio); + mask = GPIO_TO_MASK(gpio); + + return (value & mask) >> rank; +} + +/** + * Set a GPIO + */ + +static int gpio_set(unsigned gpio) +{ + int port, mask; + + port = GPIO_TO_PORT(gpio); + mask = GPIO_TO_MASK(gpio); + + switch (port) { + case 0: + writel(mask, ®s->p0_outp_set); + break; + case 1: + writel(mask, ®s->p1_outp_set); + break; + case 2: + writel(mask, ®s->p2_outp_set); + break; + case 3: + writel(mask, ®s->p3_outp_set); + break; + default: + return -1; + } + return 0; +} + +/** + * Clear a GPIO + */ + +static int gpio_clr(unsigned gpio) +{ + int port, mask; + + port = GPIO_TO_PORT(gpio); + mask = GPIO_TO_MASK(gpio); + + switch (port) { + case 0: + writel(mask, ®s->p0_outp_clr); + break; + case 1: + writel(mask, ®s->p1_outp_clr); + break; + case 2: + writel(mask, ®s->p2_outp_clr); + break; + case 3: + writel(mask, ®s->p3_outp_clr); + break; + default: + return -1; + } + return 0; +} + +/** + * Set the value of a GPIO + */ + +int gpio_set_value(unsigned gpio, int value) +{ + if (value) + return gpio_set(gpio); + else + return gpio_clr(gpio); +} -- 2.1.0 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot