1 /*
2 * Copyright (c) 2025 Stephen Hurd <shurd@FreeBSD.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7 #include <sys/param.h>
8 #include <sys/bus.h>
9 #include <sys/gpio.h>
10 #include <sys/kernel.h>
11 #include <sys/module.h>
12
13 #include <dev/ofw/openfirm.h>
14 #include <dev/ofw/ofw_bus.h>
15 #include <dev/ofw/ofw_bus_subr.h>
16
17 #include <dev/gpio/gpiobusvar.h>
18 #include <dev/syscon/syscon.h>
19
20 #include "syscon_if.h"
21
22 #define GRF_SOC_CON10 0x0428
23 #define SOC_CON10_GPIOMUT (1 << 1)
24 #define SOC_CON10_GPIOMUT_MASK ((1 << 1) << 16)
25 #define SOC_CON10_GPIOMUT_EN (1 << 0)
26 #define SOC_CON10_GPIOMUT_EN_MASK ((1 << 0) << 16)
27
28 struct rk_grf_gpio_softc {
29 device_t sc_dev;
30 device_t sc_busdev;
31 struct syscon *sc_grf;
32 bool active_high;
33 };
34
35 static struct ofw_compat_data compat_data[] = {
36 {"rockchip,rk3328-grf-gpio", 1},
37 {NULL, 0}
38 };
39
40 static device_t
rk_grf_gpio_get_bus(device_t dev)41 rk_grf_gpio_get_bus(device_t dev)
42 {
43 struct rk_grf_gpio_softc *sc;
44
45 sc = device_get_softc(dev);
46
47 return (sc->sc_busdev);
48 }
49
50 static int
rk_grf_gpio_pin_max(device_t dev,int * maxpin)51 rk_grf_gpio_pin_max(device_t dev, int *maxpin)
52 {
53 *maxpin = 1;
54 return (0);
55 }
56
57 static int
rk_grf_gpio_pin_getname(device_t dev,uint32_t pin,char * name)58 rk_grf_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
59 {
60 if (pin)
61 return (EINVAL);
62
63 snprintf(name, GPIOMAXNAME, "GPIO_MUTE");
64
65 return (0);
66 }
67
68 static int
rk_grf_gpio_pin_getflags(device_t dev,uint32_t pin,uint32_t * flags)69 rk_grf_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
70 {
71 if (pin)
72 return (EINVAL);
73 *flags = GPIO_PIN_OUTPUT;
74 return (0);
75 }
76
77 static int
rk_grf_gpio_pin_setflags(device_t dev,uint32_t pin,uint32_t flags)78 rk_grf_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
79 {
80 if (pin)
81 return (EINVAL);
82 if (flags != GPIO_PIN_OUTPUT)
83 return (EINVAL);
84
85 return (0);
86 }
87
88 static int
rk_grf_gpio_pin_getcaps(device_t dev,uint32_t pin,uint32_t * caps)89 rk_grf_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
90 {
91 if (pin)
92 return (EINVAL);
93
94 *caps = GPIO_PIN_OUTPUT;
95 return (0);
96 }
97
98 static int
rk_grf_gpio_pin_get(device_t dev,uint32_t pin,unsigned int * val)99 rk_grf_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
100 {
101 struct rk_grf_gpio_softc *sc;
102 uint32_t reg;
103
104 sc = device_get_softc(dev);
105
106 if (pin)
107 return (EINVAL);
108
109 reg = SYSCON_READ_4(sc->sc_grf, GRF_SOC_CON10);
110 if (reg & SOC_CON10_GPIOMUT)
111 *val = 1;
112 else
113 *val = 0;
114
115 return (0);
116 }
117
118 static int
rk_grf_gpio_pin_set(device_t dev,uint32_t pin,unsigned int value)119 rk_grf_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
120 {
121 struct rk_grf_gpio_softc *sc;
122 uint32_t val;
123
124 sc = device_get_softc(dev);
125
126 if (pin)
127 return (EINVAL);
128
129 val = SOC_CON10_GPIOMUT_MASK;
130 if (value)
131 val |= SOC_CON10_GPIOMUT;
132 SYSCON_WRITE_4(sc->sc_grf, GRF_SOC_CON10, val);
133
134 return (0);
135 }
136
137 static int
rk_grf_gpio_map_gpios(device_t bus,phandle_t dev,phandle_t gparent,int gcells,pcell_t * gpios,uint32_t * pin,uint32_t * flags)138 rk_grf_gpio_map_gpios(device_t bus, phandle_t dev, phandle_t gparent, int gcells,
139 pcell_t *gpios, uint32_t *pin, uint32_t *flags)
140 {
141 if (gpios[0])
142 return (EINVAL);
143
144 /* The gpios are mapped as <pin flags> */
145 *pin = 0;
146 /* TODO: The only valid flags are active low or active high */
147 *flags = GPIO_PIN_OUTPUT;
148 return (0);
149 }
150
151 static int
rk_grf_gpio_probe(device_t dev)152 rk_grf_gpio_probe(device_t dev)
153 {
154
155 if (!ofw_bus_status_okay(dev))
156 return (ENXIO);
157 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
158 return (ENXIO);
159
160 device_set_desc(dev, "RockChip General Register File GPIO (GPIO_MUTE)");
161 return (BUS_PROBE_DEFAULT);
162 }
163
164 static int
rk_grf_gpio_attach(device_t dev)165 rk_grf_gpio_attach(device_t dev)
166 {
167 struct rk_grf_gpio_softc *sc;
168 phandle_t parent_node, node;
169 device_t pdev;
170
171 sc = device_get_softc(dev);
172 sc->sc_dev = dev;
173
174 node = ofw_bus_get_node(sc->sc_dev);
175 if (!OF_hasprop(node, "gpio-controller"))
176 return (ENXIO);
177 pdev = device_get_parent(dev);
178 parent_node = ofw_bus_get_node(pdev);
179 if (syscon_get_by_ofw_node(dev, parent_node, &sc->sc_grf) != 0) {
180 device_printf(dev, "cannot get parent syscon handle\n");
181 return (ENXIO);
182 }
183
184 sc->sc_busdev = gpiobus_attach_bus(dev);
185 if (sc->sc_busdev == NULL) {
186 return (ENXIO);
187 }
188
189 return (0);
190 }
191
192 static int
rk_grf_gpio_detach(device_t dev)193 rk_grf_gpio_detach(device_t dev)
194 {
195 struct rk_grf_gpio_softc *sc;
196
197 sc = device_get_softc(dev);
198
199 if (sc->sc_busdev)
200 gpiobus_detach_bus(dev);
201
202 return(0);
203 }
204
205 static device_method_t rk_grf_gpio_methods[] = {
206 DEVMETHOD(device_probe, rk_grf_gpio_probe),
207 DEVMETHOD(device_attach, rk_grf_gpio_attach),
208 DEVMETHOD(device_detach, rk_grf_gpio_detach),
209
210 /* GPIO protocol */
211 DEVMETHOD(gpio_get_bus, rk_grf_gpio_get_bus),
212 DEVMETHOD(gpio_pin_max, rk_grf_gpio_pin_max),
213 DEVMETHOD(gpio_pin_getname, rk_grf_gpio_pin_getname),
214 DEVMETHOD(gpio_pin_getflags, rk_grf_gpio_pin_getflags),
215 DEVMETHOD(gpio_pin_setflags, rk_grf_gpio_pin_setflags),
216 DEVMETHOD(gpio_pin_getcaps, rk_grf_gpio_pin_getcaps),
217 DEVMETHOD(gpio_pin_get, rk_grf_gpio_pin_get),
218 DEVMETHOD(gpio_pin_set, rk_grf_gpio_pin_set),
219 DEVMETHOD(gpio_map_gpios, rk_grf_gpio_map_gpios),
220
221 DEVMETHOD_END
222 };
223
224 static driver_t rk_grf_gpio_driver = {
225 "gpio",
226 rk_grf_gpio_methods,
227 sizeof(struct rk_grf_gpio_softc),
228 };
229
230 /*
231 * GPIO driver is always a child of rk_grf driver and should be probed
232 * and attached within rk_grf function. Due to this, bus pass order
233 * must be same as bus pass order of rk_grf driver.
234 */
235 EARLY_DRIVER_MODULE(rk_grf_gpio, simplebus, rk_grf_gpio_driver, 0, 0,
236 BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
237