summaryrefslogtreecommitdiff
path: root/drivers/rpi3
diff options
context:
space:
mode:
authorYing-Chun Liu (PaulLiu) <paulliu@debian.org>2018-12-21 03:32:10 +0800
committerYing-Chun Liu (PaulLiu) <paulliu@debian.org>2019-01-26 00:13:49 +0800
commitd604ac483136d8d611264474a5e57c31632f46ca (patch)
tree67033e098c9327af52aec3537d3279c36d77c356 /drivers/rpi3
parent7ca572d93c88bf8a86fccf30b2725315f092aef4 (diff)
rpi3: Add GPIO driver
This commit adds GPIO driver for RaspberryPi3. The GPIO driver for RPi3 also provides the way to do pinmux selections. Signed-off-by: Ying-Chun Liu (PaulLiu) <paulliu@debian.org>
Diffstat (limited to 'drivers/rpi3')
-rw-r--r--drivers/rpi3/gpio/rpi3_gpio.c169
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 00000000..b39808ff
--- /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);
+}