blob: f938f563fc52c2982f3980b92bdd189a8936f883 [file] [log] [blame]
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +08001/*
2 * Copyright (c) 2019, Linaro Limited
3 * Copyright (c) 2019, Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8#include <string.h>
9#include <assert.h>
10#include <lib/mmio.h>
11#include <drivers/delay_timer.h>
12#include <drivers/rpi3/gpio/rpi3_gpio.h>
13
Andre Przywara203e7c42020-03-11 16:10:40 +000014static uintptr_t reg_base;
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +080015
16static int rpi3_gpio_get_direction(int gpio);
17static void rpi3_gpio_set_direction(int gpio, int direction);
18static int rpi3_gpio_get_value(int gpio);
19static void rpi3_gpio_set_value(int gpio, int value);
20static void rpi3_gpio_set_pull(int gpio, int pull);
21
22static const gpio_ops_t rpi3_gpio_ops = {
23 .get_direction = rpi3_gpio_get_direction,
24 .set_direction = rpi3_gpio_set_direction,
25 .get_value = rpi3_gpio_get_value,
26 .set_value = rpi3_gpio_set_value,
27 .set_pull = rpi3_gpio_set_pull,
28};
29
30/**
31 * Get selection of GPIO pinmux settings.
32 *
33 * @param gpio The pin number of GPIO. From 0 to 53.
34 * @return The selection of pinmux. RPI3_GPIO_FUNC_INPUT: input,
35 * RPI3_GPIO_FUNC_OUTPUT: output,
36 * RPI3_GPIO_FUNC_ALT0: alt-0,
37 * RPI3_GPIO_FUNC_ALT1: alt-1,
38 * RPI3_GPIO_FUNC_ALT2: alt-2,
39 * RPI3_GPIO_FUNC_ALT3: alt-3,
40 * RPI3_GPIO_FUNC_ALT4: alt-4,
41 * RPI3_GPIO_FUNC_ALT5: alt-5
42 */
43int rpi3_gpio_get_select(int gpio)
44{
45 int ret;
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +080046 int regN = gpio / 10;
47 int shift = 3 * (gpio % 10);
48 uintptr_t reg_sel = reg_base + RPI3_GPIO_GPFSEL(regN);
49 uint32_t sel = mmio_read_32(reg_sel);
50
51 ret = (sel >> shift) & 0x07;
52
53 return ret;
54}
55
56/**
57 * Set selection of GPIO pinmux settings.
58 *
59 * @param gpio The pin number of GPIO. From 0 to 53.
60 * @param fsel The selection of pinmux. RPI3_GPIO_FUNC_INPUT: input,
61 * RPI3_GPIO_FUNC_OUTPUT: output,
62 * RPI3_GPIO_FUNC_ALT0: alt-0,
63 * RPI3_GPIO_FUNC_ALT1: alt-1,
64 * RPI3_GPIO_FUNC_ALT2: alt-2,
65 * RPI3_GPIO_FUNC_ALT3: alt-3,
66 * RPI3_GPIO_FUNC_ALT4: alt-4,
67 * RPI3_GPIO_FUNC_ALT5: alt-5
68 */
69void rpi3_gpio_set_select(int gpio, int fsel)
70{
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +080071 int regN = gpio / 10;
72 int shift = 3 * (gpio % 10);
73 uintptr_t reg_sel = reg_base + RPI3_GPIO_GPFSEL(regN);
74 uint32_t sel = mmio_read_32(reg_sel);
75 uint32_t mask = U(0x07) << shift;
76
77 sel = (sel & (~mask)) | ((fsel << shift) & mask);
78 mmio_write_32(reg_sel, sel);
79}
80
81static int rpi3_gpio_get_direction(int gpio)
82{
83 int result = rpi3_gpio_get_select(gpio);
84
85 if (result == RPI3_GPIO_FUNC_INPUT)
86 return GPIO_DIR_IN;
87 else if (result == RPI3_GPIO_FUNC_OUTPUT)
88 return GPIO_DIR_OUT;
89
90 return GPIO_DIR_IN;
91}
92
93static void rpi3_gpio_set_direction(int gpio, int direction)
94{
95 switch (direction) {
96 case GPIO_DIR_IN:
97 rpi3_gpio_set_select(gpio, RPI3_GPIO_FUNC_INPUT);
98 break;
99 case GPIO_DIR_OUT:
100 rpi3_gpio_set_select(gpio, RPI3_GPIO_FUNC_OUTPUT);
101 break;
102 }
103}
104
105static int rpi3_gpio_get_value(int gpio)
106{
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +0800107 int regN = gpio / 32;
108 int shift = gpio % 32;
109 uintptr_t reg_lev = reg_base + RPI3_GPIO_GPLEV(regN);
110 uint32_t value = mmio_read_32(reg_lev);
111
112 if ((value >> shift) & 0x01)
113 return GPIO_LEVEL_HIGH;
114 return GPIO_LEVEL_LOW;
115}
116
117static void rpi3_gpio_set_value(int gpio, int value)
118{
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +0800119 int regN = gpio / 32;
120 int shift = gpio % 32;
121 uintptr_t reg_set = reg_base + RPI3_GPIO_GPSET(regN);
122 uintptr_t reg_clr = reg_base + RPI3_GPIO_GPSET(regN);
123
124 switch (value) {
125 case GPIO_LEVEL_LOW:
126 mmio_write_32(reg_clr, U(1) << shift);
127 break;
128 case GPIO_LEVEL_HIGH:
129 mmio_write_32(reg_set, U(1) << shift);
130 break;
131 }
132}
133
134static void rpi3_gpio_set_pull(int gpio, int pull)
135{
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +0800136 int regN = gpio / 32;
137 int shift = gpio % 32;
138 uintptr_t reg_pud = reg_base + RPI3_GPIO_GPPUD;
139 uintptr_t reg_clk = reg_base + RPI3_GPIO_GPPUDCLK(regN);
140
141 switch (pull) {
142 case GPIO_PULL_NONE:
143 mmio_write_32(reg_pud, 0x0);
144 break;
145 case GPIO_PULL_UP:
146 mmio_write_32(reg_pud, 0x2);
147 break;
148 case GPIO_PULL_DOWN:
149 mmio_write_32(reg_pud, 0x1);
150 break;
151 }
152 mdelay(150);
153 mmio_write_32(reg_clk, U(1) << shift);
154 mdelay(150);
155 mmio_write_32(reg_clk, 0x0);
156 mmio_write_32(reg_pud, 0x0);
157}
158
Andre Przywara203e7c42020-03-11 16:10:40 +0000159void rpi3_gpio_init(void)
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +0800160{
Andre Przywara203e7c42020-03-11 16:10:40 +0000161 reg_base = RPI3_GPIO_BASE;
Ying-Chun Liu (PaulLiu)4fb84fb2018-12-21 03:32:10 +0800162 gpio_init(&rpi3_gpio_ops);
163}