xref: /freebsd/sys/arm64/rockchip/rk_grf_gpio.c (revision 0832a409c21b45b2a31b90c50a005d9a4b1a5efd)
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