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