diff options
author | Antonio Niño Díaz <antonio.ninodiaz@arm.com> | 2019-01-28 12:04:13 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-01-28 12:04:13 +0000 |
commit | d4dcadb067e0ebdbb633562fd80e03538f3b7214 (patch) | |
tree | 10235820271dee070ea5c7bca1a535664f3b3654 /drivers | |
parent | 83a2285ec8d5e4bdbf12481b441489eed5bb6018 (diff) | |
parent | 2be86dd3954a5a3bd5111c3861a74c1f8a592884 (diff) | |
download | trusted-firmware-a-d4dcadb067e0ebdbb633562fd80e03538f3b7214.tar.gz |
Merge pull request #1773 from grandpaul/rpi3-gpio-driver
Rpi3 gpio driver
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/rpi3/gpio/rpi3_gpio.c | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/drivers/rpi3/gpio/rpi3_gpio.c b/drivers/rpi3/gpio/rpi3_gpio.c new file mode 100644 index 0000000000..b39808ff7c --- /dev/null +++ b/drivers/rpi3/gpio/rpi3_gpio.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2019, Linaro Limited + * Copyright (c) 2019, Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org> + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <string.h> +#include <assert.h> +#include <lib/mmio.h> +#include <drivers/delay_timer.h> +#include <drivers/rpi3/gpio/rpi3_gpio.h> + +static struct rpi3_gpio_params rpi3_gpio_params; + +static int rpi3_gpio_get_direction(int gpio); +static void rpi3_gpio_set_direction(int gpio, int direction); +static int rpi3_gpio_get_value(int gpio); +static void rpi3_gpio_set_value(int gpio, int value); +static void rpi3_gpio_set_pull(int gpio, int pull); + +static const gpio_ops_t rpi3_gpio_ops = { + .get_direction = rpi3_gpio_get_direction, + .set_direction = rpi3_gpio_set_direction, + .get_value = rpi3_gpio_get_value, + .set_value = rpi3_gpio_set_value, + .set_pull = rpi3_gpio_set_pull, +}; + +/** + * Get selection of GPIO pinmux settings. + * + * @param gpio The pin number of GPIO. From 0 to 53. + * @return The selection of pinmux. RPI3_GPIO_FUNC_INPUT: input, + * RPI3_GPIO_FUNC_OUTPUT: output, + * RPI3_GPIO_FUNC_ALT0: alt-0, + * RPI3_GPIO_FUNC_ALT1: alt-1, + * RPI3_GPIO_FUNC_ALT2: alt-2, + * RPI3_GPIO_FUNC_ALT3: alt-3, + * RPI3_GPIO_FUNC_ALT4: alt-4, + * RPI3_GPIO_FUNC_ALT5: alt-5 + */ +int rpi3_gpio_get_select(int gpio) +{ + int ret; + uintptr_t reg_base = rpi3_gpio_params.reg_base; + int regN = gpio / 10; + int shift = 3 * (gpio % 10); + uintptr_t reg_sel = reg_base + RPI3_GPIO_GPFSEL(regN); + uint32_t sel = mmio_read_32(reg_sel); + + ret = (sel >> shift) & 0x07; + + return ret; +} + +/** + * Set selection of GPIO pinmux settings. + * + * @param gpio The pin number of GPIO. From 0 to 53. + * @param fsel The selection of pinmux. RPI3_GPIO_FUNC_INPUT: input, + * RPI3_GPIO_FUNC_OUTPUT: output, + * RPI3_GPIO_FUNC_ALT0: alt-0, + * RPI3_GPIO_FUNC_ALT1: alt-1, + * RPI3_GPIO_FUNC_ALT2: alt-2, + * RPI3_GPIO_FUNC_ALT3: alt-3, + * RPI3_GPIO_FUNC_ALT4: alt-4, + * RPI3_GPIO_FUNC_ALT5: alt-5 + */ +void rpi3_gpio_set_select(int gpio, int fsel) +{ + uintptr_t reg_base = rpi3_gpio_params.reg_base; + int regN = gpio / 10; + int shift = 3 * (gpio % 10); + uintptr_t reg_sel = reg_base + RPI3_GPIO_GPFSEL(regN); + uint32_t sel = mmio_read_32(reg_sel); + uint32_t mask = U(0x07) << shift; + + sel = (sel & (~mask)) | ((fsel << shift) & mask); + mmio_write_32(reg_sel, sel); +} + +static int rpi3_gpio_get_direction(int gpio) +{ + int result = rpi3_gpio_get_select(gpio); + + if (result == RPI3_GPIO_FUNC_INPUT) + return GPIO_DIR_IN; + else if (result == RPI3_GPIO_FUNC_OUTPUT) + return GPIO_DIR_OUT; + + return GPIO_DIR_IN; +} + +static void rpi3_gpio_set_direction(int gpio, int direction) +{ + switch (direction) { + case GPIO_DIR_IN: + rpi3_gpio_set_select(gpio, RPI3_GPIO_FUNC_INPUT); + break; + case GPIO_DIR_OUT: + rpi3_gpio_set_select(gpio, RPI3_GPIO_FUNC_OUTPUT); + break; + } +} + +static int rpi3_gpio_get_value(int gpio) +{ + uintptr_t reg_base = rpi3_gpio_params.reg_base; + int regN = gpio / 32; + int shift = gpio % 32; + uintptr_t reg_lev = reg_base + RPI3_GPIO_GPLEV(regN); + uint32_t value = mmio_read_32(reg_lev); + + if ((value >> shift) & 0x01) + return GPIO_LEVEL_HIGH; + return GPIO_LEVEL_LOW; +} + +static void rpi3_gpio_set_value(int gpio, int value) +{ + uintptr_t reg_base = rpi3_gpio_params.reg_base; + int regN = gpio / 32; + int shift = gpio % 32; + uintptr_t reg_set = reg_base + RPI3_GPIO_GPSET(regN); + uintptr_t reg_clr = reg_base + RPI3_GPIO_GPSET(regN); + + switch (value) { + case GPIO_LEVEL_LOW: + mmio_write_32(reg_clr, U(1) << shift); + break; + case GPIO_LEVEL_HIGH: + mmio_write_32(reg_set, U(1) << shift); + break; + } +} + +static void rpi3_gpio_set_pull(int gpio, int pull) +{ + uintptr_t reg_base = rpi3_gpio_params.reg_base; + int regN = gpio / 32; + int shift = gpio % 32; + uintptr_t reg_pud = reg_base + RPI3_GPIO_GPPUD; + uintptr_t reg_clk = reg_base + RPI3_GPIO_GPPUDCLK(regN); + + switch (pull) { + case GPIO_PULL_NONE: + mmio_write_32(reg_pud, 0x0); + break; + case GPIO_PULL_UP: + mmio_write_32(reg_pud, 0x2); + break; + case GPIO_PULL_DOWN: + mmio_write_32(reg_pud, 0x1); + break; + } + mdelay(150); + mmio_write_32(reg_clk, U(1) << shift); + mdelay(150); + mmio_write_32(reg_clk, 0x0); + mmio_write_32(reg_pud, 0x0); +} + +void rpi3_gpio_init(struct rpi3_gpio_params *params) +{ + assert(params != 0); + memcpy(&rpi3_gpio_params, params, sizeof(struct rpi3_gpio_params)); + gpio_init(&rpi3_gpio_ops); +} |