Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/arm64/rockchip/rk_grf_gpio.c
39478 views
1
/*
2
* Copyright (c) 2025 Stephen Hurd <[email protected]>
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
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
51
rk_grf_gpio_pin_max(device_t dev, int *maxpin)
52
{
53
*maxpin = 1;
54
return (0);
55
}
56
57
static int
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
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
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
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
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
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
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
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
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_add_bus(dev);
185
if (sc->sc_busdev == NULL) {
186
return (ENXIO);
187
}
188
189
bus_attach_children(dev);
190
return (0);
191
}
192
193
static int
194
rk_grf_gpio_detach(device_t dev)
195
{
196
struct rk_grf_gpio_softc *sc;
197
198
sc = device_get_softc(dev);
199
200
if (sc->sc_busdev)
201
gpiobus_detach_bus(dev);
202
203
return(0);
204
}
205
206
static device_method_t rk_grf_gpio_methods[] = {
207
DEVMETHOD(device_probe, rk_grf_gpio_probe),
208
DEVMETHOD(device_attach, rk_grf_gpio_attach),
209
DEVMETHOD(device_detach, rk_grf_gpio_detach),
210
211
/* GPIO protocol */
212
DEVMETHOD(gpio_get_bus, rk_grf_gpio_get_bus),
213
DEVMETHOD(gpio_pin_max, rk_grf_gpio_pin_max),
214
DEVMETHOD(gpio_pin_getname, rk_grf_gpio_pin_getname),
215
DEVMETHOD(gpio_pin_getflags, rk_grf_gpio_pin_getflags),
216
DEVMETHOD(gpio_pin_setflags, rk_grf_gpio_pin_setflags),
217
DEVMETHOD(gpio_pin_getcaps, rk_grf_gpio_pin_getcaps),
218
DEVMETHOD(gpio_pin_get, rk_grf_gpio_pin_get),
219
DEVMETHOD(gpio_pin_set, rk_grf_gpio_pin_set),
220
DEVMETHOD(gpio_map_gpios, rk_grf_gpio_map_gpios),
221
222
DEVMETHOD_END
223
};
224
225
static driver_t rk_grf_gpio_driver = {
226
"gpio",
227
rk_grf_gpio_methods,
228
sizeof(struct rk_grf_gpio_softc),
229
};
230
231
/*
232
* GPIO driver is always a child of rk_grf driver and should be probed
233
* and attached within rk_grf function. Due to this, bus pass order
234
* must be same as bus pass order of rk_grf driver.
235
*/
236
EARLY_DRIVER_MODULE(rk_grf_gpio, simplebus, rk_grf_gpio_driver, 0, 0,
237
BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
238
239