]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm64/rockchip/rk_gpio.c
arm64: rockchip: rk_gpio: Improve mode switching
[FreeBSD/FreeBSD.git] / sys / arm64 / rockchip / rk_gpio.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2018 Emmanuel Vadot <manu@FreeBSD.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/bus.h>
35
36 #include <sys/kernel.h>
37 #include <sys/module.h>
38 #include <sys/rman.h>
39 #include <sys/lock.h>
40 #include <sys/mutex.h>
41 #include <sys/gpio.h>
42
43 #include <machine/bus.h>
44 #include <machine/resource.h>
45 #include <machine/intr.h>
46
47 #include <dev/gpio/gpiobusvar.h>
48 #include <dev/ofw/ofw_bus.h>
49 #include <dev/ofw/ofw_bus_subr.h>
50 #include <dev/extres/clk/clk.h>
51
52 #include "gpio_if.h"
53
54 #include "fdt_pinctrl_if.h"
55
56 #define RK_GPIO_SWPORTA_DR      0x00    /* Data register */
57 #define RK_GPIO_SWPORTA_DDR     0x04    /* Data direction register */
58
59 #define RK_GPIO_INTEN           0x30    /* Interrupt enable register */
60 #define RK_GPIO_INTMASK         0x34    /* Interrupt mask register */
61 #define RK_GPIO_INTTYPE_LEVEL   0x38    /* Interrupt level register */
62 #define RK_GPIO_INT_POLARITY    0x3C    /* Interrupt polarity register */
63 #define RK_GPIO_INT_STATUS      0x40    /* Interrupt status register */
64 #define RK_GPIO_INT_RAWSTATUS   0x44    /* Raw Interrupt status register */
65
66 #define RK_GPIO_DEBOUNCE        0x48    /* Debounce enable register */
67
68 #define RK_GPIO_PORTA_EOI       0x4C    /* Clear interrupt register */
69 #define RK_GPIO_EXT_PORTA       0x50    /* External port register */
70
71 #define RK_GPIO_LS_SYNC         0x60    /* Level sensitive syncronization enable register */
72
73 #define RK_GPIO_DEFAULT_CAPS    (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT |     \
74     GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN)
75
76 #define GPIO_FLAGS_PINCTRL      GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN
77 #define RK_GPIO_MAX_PINS        32
78
79 struct pin_cached {
80         uint8_t         is_gpio;
81         uint32_t        flags;
82 };
83
84 struct rk_gpio_softc {
85         device_t                sc_dev;
86         device_t                sc_busdev;
87         struct mtx              sc_mtx;
88         struct resource         *sc_res[2];
89         bus_space_tag_t         sc_bst;
90         bus_space_handle_t      sc_bsh;
91         clk_t                   clk;
92         device_t                pinctrl;
93         uint32_t                swporta;
94         uint32_t                swporta_ddr;
95         struct pin_cached       pin_cached[RK_GPIO_MAX_PINS];
96 };
97
98 static struct ofw_compat_data compat_data[] = {
99         {"rockchip,gpio-bank", 1},
100         {NULL,             0}
101 };
102
103 static struct resource_spec rk_gpio_spec[] = {
104         { SYS_RES_MEMORY,       0,      RF_ACTIVE },
105         { SYS_RES_IRQ,          0,      RF_ACTIVE },
106         { -1, 0 }
107 };
108
109 static int rk_gpio_detach(device_t dev);
110
111 #define RK_GPIO_LOCK(_sc)               mtx_lock_spin(&(_sc)->sc_mtx)
112 #define RK_GPIO_UNLOCK(_sc)             mtx_unlock_spin(&(_sc)->sc_mtx)
113 #define RK_GPIO_LOCK_ASSERT(_sc)        mtx_assert(&(_sc)->sc_mtx, MA_OWNED)
114
115 #define RK_GPIO_WRITE(_sc, _off, _val)          \
116     bus_space_write_4(_sc->sc_bst, _sc->sc_bsh, _off, _val)
117 #define RK_GPIO_READ(_sc, _off)         \
118     bus_space_read_4(_sc->sc_bst, _sc->sc_bsh, _off)
119
120 static int
121 rk_gpio_probe(device_t dev)
122 {
123
124         if (!ofw_bus_status_okay(dev))
125                 return (ENXIO);
126
127         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
128                 return (ENXIO);
129
130         device_set_desc(dev, "RockChip GPIO Bank controller");
131         return (BUS_PROBE_DEFAULT);
132 }
133
134 static int
135 rk_gpio_attach(device_t dev)
136 {
137         struct rk_gpio_softc *sc;
138         phandle_t node;
139         int err, i;
140
141         sc = device_get_softc(dev);
142         sc->sc_dev = dev;
143         sc->pinctrl = device_get_parent(dev);
144
145         node = ofw_bus_get_node(sc->sc_dev);
146         if (!OF_hasprop(node, "gpio-controller"))
147                 return (ENXIO);
148
149         mtx_init(&sc->sc_mtx, "rk gpio", "gpio", MTX_SPIN);
150
151         if (bus_alloc_resources(dev, rk_gpio_spec, sc->sc_res)) {
152                 device_printf(dev, "could not allocate resources\n");
153                 bus_release_resources(dev, rk_gpio_spec, sc->sc_res);
154                 mtx_destroy(&sc->sc_mtx);
155                 return (ENXIO);
156         }
157
158         sc->sc_bst = rman_get_bustag(sc->sc_res[0]);
159         sc->sc_bsh = rman_get_bushandle(sc->sc_res[0]);
160
161         if (clk_get_by_ofw_index(dev, 0, 0, &sc->clk) != 0) {
162                 device_printf(dev, "Cannot get clock\n");
163                 rk_gpio_detach(dev);
164                 return (ENXIO);
165         }
166         err = clk_enable(sc->clk);
167         if (err != 0) {
168                 device_printf(dev, "Could not enable clock %s\n",
169                     clk_get_name(sc->clk));
170                 rk_gpio_detach(dev);
171                 return (ENXIO);
172         }
173
174         sc->sc_busdev = gpiobus_attach_bus(dev);
175         if (sc->sc_busdev == NULL) {
176                 rk_gpio_detach(dev);
177                 return (ENXIO);
178         }
179
180         /* Set the cached value to unknown */
181         for (i = 0; i < RK_GPIO_MAX_PINS; i++)
182                 sc->pin_cached[i].is_gpio = 2;
183
184         RK_GPIO_LOCK(sc);
185         sc->swporta = RK_GPIO_READ(sc, RK_GPIO_SWPORTA_DR);
186         sc->swporta_ddr = RK_GPIO_READ(sc, RK_GPIO_SWPORTA_DDR);
187         RK_GPIO_UNLOCK(sc);
188
189         return (0);
190 }
191
192 static int
193 rk_gpio_detach(device_t dev)
194 {
195         struct rk_gpio_softc *sc;
196
197         sc = device_get_softc(dev);
198
199         if (sc->sc_busdev)
200                 gpiobus_detach_bus(dev);
201         bus_release_resources(dev, rk_gpio_spec, sc->sc_res);
202         mtx_destroy(&sc->sc_mtx);
203         clk_disable(sc->clk);
204
205         return(0);
206 }
207
208 static device_t
209 rk_gpio_get_bus(device_t dev)
210 {
211         struct rk_gpio_softc *sc;
212
213         sc = device_get_softc(dev);
214
215         return (sc->sc_busdev);
216 }
217
218 static int
219 rk_gpio_pin_max(device_t dev, int *maxpin)
220 {
221
222         /* Each bank have always 32 pins */
223         /* XXX not true*/
224         *maxpin = 31;
225         return (0);
226 }
227
228 static int
229 rk_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
230 {
231         struct rk_gpio_softc *sc;
232         uint32_t bank;
233
234         sc = device_get_softc(dev);
235
236         if (pin >= 32)
237                 return (EINVAL);
238
239         bank = pin / 8;
240         pin = pin - (bank * 8);
241         RK_GPIO_LOCK(sc);
242         snprintf(name, GPIOMAXNAME, "P%c%d", bank + 'A', pin);
243         RK_GPIO_UNLOCK(sc);
244
245         return (0);
246 }
247
248 static int
249 rk_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
250 {
251         struct rk_gpio_softc *sc;
252         int rv;
253
254         sc = device_get_softc(dev);
255
256         if (__predict_false(sc->pin_cached[pin].is_gpio != 1)) {
257                 rv = FDT_PINCTRL_IS_GPIO(sc->pinctrl, dev, pin, (bool *)&sc->pin_cached[pin].is_gpio);
258                 if (rv != 0)
259                         return (rv);
260                 if (sc->pin_cached[pin].is_gpio == 0)
261                         return (EINVAL);
262         }
263
264         *flags = 0;
265         rv = FDT_PINCTRL_GET_FLAGS(sc->pinctrl, dev, pin, flags);
266         if (rv != 0)
267                 return (rv);
268         sc->pin_cached[pin].flags = *flags;
269
270         if (sc->swporta_ddr & (1 << pin))
271                 *flags |= GPIO_PIN_OUTPUT;
272         else
273                 *flags |= GPIO_PIN_INPUT;
274
275         return (0);
276 }
277
278 static int
279 rk_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
280 {
281
282         *caps = RK_GPIO_DEFAULT_CAPS;
283         return (0);
284 }
285
286 static int
287 rk_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
288 {
289         struct rk_gpio_softc *sc;
290         int rv;
291
292         sc = device_get_softc(dev);
293
294         if (__predict_false(sc->pin_cached[pin].is_gpio != 1)) {
295                 rv = FDT_PINCTRL_IS_GPIO(sc->pinctrl, dev, pin, (bool *)&sc->pin_cached[pin].is_gpio);
296                 if (rv != 0)
297                         return (rv);
298                 if (sc->pin_cached[pin].is_gpio == 0)
299                         return (EINVAL);
300         }
301
302         if (__predict_false((flags & GPIO_PIN_INPUT) && ((flags & GPIO_FLAGS_PINCTRL) != sc->pin_cached[pin].flags))) {
303                 rv = FDT_PINCTRL_SET_FLAGS(sc->pinctrl, dev, pin, flags);
304                 sc->pin_cached[pin].flags = flags & GPIO_FLAGS_PINCTRL;
305                 if (rv != 0)
306                         return (rv);
307         }
308
309         RK_GPIO_LOCK(sc);
310         if (flags & GPIO_PIN_INPUT)
311                 sc->swporta_ddr &= ~(1 << pin);
312         else if (flags & GPIO_PIN_OUTPUT)
313                 sc->swporta_ddr |= (1 << pin);
314
315         RK_GPIO_WRITE(sc, RK_GPIO_SWPORTA_DDR, sc->swporta_ddr);
316         RK_GPIO_UNLOCK(sc);
317
318         return (0);
319 }
320
321 static int
322 rk_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
323 {
324         struct rk_gpio_softc *sc;
325         uint32_t reg;
326
327         sc = device_get_softc(dev);
328
329         RK_GPIO_LOCK(sc);
330         reg = RK_GPIO_READ(sc, RK_GPIO_EXT_PORTA);
331         RK_GPIO_UNLOCK(sc);
332
333         *val = reg & (1 << pin) ? 1 : 0;
334
335         return (0);
336 }
337
338 static int
339 rk_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
340 {
341         struct rk_gpio_softc *sc;
342
343         sc = device_get_softc(dev);
344
345         RK_GPIO_LOCK(sc);
346         if (value)
347                 sc->swporta |= (1 << pin);
348         else
349                 sc->swporta &= ~(1 << pin);
350         RK_GPIO_WRITE(sc, RK_GPIO_SWPORTA_DR, sc->swporta);
351         RK_GPIO_UNLOCK(sc);
352
353         return (0);
354 }
355
356 static int
357 rk_gpio_pin_toggle(device_t dev, uint32_t pin)
358 {
359         struct rk_gpio_softc *sc;
360
361         sc = device_get_softc(dev);
362
363         RK_GPIO_LOCK(sc);
364         if (sc->swporta & (1 << pin))
365                 sc->swporta &= ~(1 << pin);
366         else
367                 sc->swporta |= (1 << pin);
368         RK_GPIO_WRITE(sc, RK_GPIO_SWPORTA_DR, sc->swporta);
369         RK_GPIO_UNLOCK(sc);
370
371         return (0);
372 }
373
374 static int
375 rk_gpio_pin_access_32(device_t dev, uint32_t first_pin, uint32_t clear_pins,
376     uint32_t change_pins, uint32_t *orig_pins)
377 {
378         struct rk_gpio_softc *sc;
379         uint32_t reg;
380
381         sc = device_get_softc(dev);
382
383         RK_GPIO_LOCK(sc);
384         reg = RK_GPIO_READ(sc, RK_GPIO_SWPORTA_DR);
385         if (orig_pins)
386                 *orig_pins = reg;
387         sc->swporta = reg;
388
389         if ((clear_pins | change_pins) != 0) {
390                 reg = (reg & ~clear_pins) ^ change_pins;
391                 RK_GPIO_WRITE(sc, RK_GPIO_SWPORTA_DR, reg);
392         }
393         RK_GPIO_UNLOCK(sc);
394
395         return (0);
396 }
397
398 static int
399 rk_gpio_pin_config_32(device_t dev, uint32_t first_pin, uint32_t num_pins,
400     uint32_t *pin_flags)
401 {
402         struct rk_gpio_softc *sc;
403         uint32_t reg, set, mask, flags;
404         int i;
405
406         sc = device_get_softc(dev);
407
408         if (first_pin != 0 || num_pins > 32)
409                 return (EINVAL);
410
411         set = 0;
412         mask = 0;
413         for (i = 0; i < num_pins; i++) {
414                 mask = (mask << 1) | 1;
415                 flags = pin_flags[i];
416                 if (flags & GPIO_PIN_INPUT) {
417                         set &= ~(1 << i);
418                 } else if (flags & GPIO_PIN_OUTPUT) {
419                         set |= (1 << i);
420                 }
421         }
422
423         RK_GPIO_LOCK(sc);
424         reg = RK_GPIO_READ(sc, RK_GPIO_SWPORTA_DDR);
425         reg &= ~mask;
426         reg |= set;
427         RK_GPIO_WRITE(sc, RK_GPIO_SWPORTA_DDR, reg);
428         sc->swporta_ddr = reg;
429         RK_GPIO_UNLOCK(sc);
430
431         return (0);
432 }
433
434 static int
435 rk_gpio_map_gpios(device_t bus, phandle_t dev, phandle_t gparent, int gcells,
436     pcell_t *gpios, uint32_t *pin, uint32_t *flags)
437 {
438
439         /* The gpios are mapped as <pin flags> */
440         *pin = gpios[0];
441         *flags = gpios[1];
442         return (0);
443 }
444
445 static phandle_t
446 rk_gpio_get_node(device_t bus, device_t dev)
447 {
448
449         /* We only have one child, the GPIO bus, which needs our own node. */
450         return (ofw_bus_get_node(bus));
451 }
452
453 static device_method_t rk_gpio_methods[] = {
454         /* Device interface */
455         DEVMETHOD(device_probe,         rk_gpio_probe),
456         DEVMETHOD(device_attach,        rk_gpio_attach),
457         DEVMETHOD(device_detach,        rk_gpio_detach),
458
459         /* GPIO protocol */
460         DEVMETHOD(gpio_get_bus,         rk_gpio_get_bus),
461         DEVMETHOD(gpio_pin_max,         rk_gpio_pin_max),
462         DEVMETHOD(gpio_pin_getname,     rk_gpio_pin_getname),
463         DEVMETHOD(gpio_pin_getflags,    rk_gpio_pin_getflags),
464         DEVMETHOD(gpio_pin_getcaps,     rk_gpio_pin_getcaps),
465         DEVMETHOD(gpio_pin_setflags,    rk_gpio_pin_setflags),
466         DEVMETHOD(gpio_pin_get,         rk_gpio_pin_get),
467         DEVMETHOD(gpio_pin_set,         rk_gpio_pin_set),
468         DEVMETHOD(gpio_pin_toggle,      rk_gpio_pin_toggle),
469         DEVMETHOD(gpio_pin_access_32,   rk_gpio_pin_access_32),
470         DEVMETHOD(gpio_pin_config_32,   rk_gpio_pin_config_32),
471         DEVMETHOD(gpio_map_gpios,       rk_gpio_map_gpios),
472
473         /* ofw_bus interface */
474         DEVMETHOD(ofw_bus_get_node,     rk_gpio_get_node),
475
476         DEVMETHOD_END
477 };
478
479 static driver_t rk_gpio_driver = {
480         "gpio",
481         rk_gpio_methods,
482         sizeof(struct rk_gpio_softc),
483 };
484
485 /*
486  * GPIO driver is always a child of rk_pinctrl driver and should be probed
487  * and attached within rk_pinctrl_attach function. Due to this, bus pass order
488  * must be same as bus pass order of rk_pinctrl driver.
489  */
490 EARLY_DRIVER_MODULE(rk_gpio, simplebus, rk_gpio_driver, 0, 0,
491     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);