1 /* $NetBSD: meson_pinctrl.c,v 1.13 2021/08/07 16:18:43 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 2019 Jared D. McNeill <jmcneill@invisible.ca>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include "opt_soc.h"
30
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: meson_pinctrl.c,v 1.13 2021/08/07 16:18:43 thorpej Exp $");
33
34 #include <sys/param.h>
35 #include <sys/bus.h>
36 #include <sys/device.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/mutex.h>
40 #include <sys/kmem.h>
41 #include <sys/gpio.h>
42
43 #include <dev/gpio/gpiovar.h>
44
45 #include <dev/fdt/fdtvar.h>
46
47 #include <arm/amlogic/meson_pinctrl.h>
48
49 struct meson_pinctrl_softc {
50 device_t sc_dev;
51 bus_space_tag_t sc_bst;
52 bus_space_handle_t sc_bsh_mux;
53 bus_space_handle_t sc_bsh_pull;
54 bus_space_handle_t sc_bsh_pull_enable;
55 bus_space_handle_t sc_bsh_gpio;
56 int sc_phandle;
57 int sc_phandle_gpio;
58
59 kmutex_t sc_lock;
60
61 const struct meson_pinctrl_config *sc_conf;
62
63 struct gpio_chipset_tag sc_gp;
64 gpio_pin_t *sc_pins;
65 };
66
67 struct meson_pinctrl_gpio_pin {
68 struct meson_pinctrl_softc *pin_sc;
69 const struct meson_pinctrl_gpio *pin_def;
70 int pin_flags;
71 bool pin_actlo;
72 };
73
74 static const struct device_compatible_entry compat_data[] = {
75 #ifdef SOC_MESON8B
76 { .compat = "amlogic,meson8b-aobus-pinctrl",
77 .data = &meson8b_aobus_pinctrl_config },
78 { .compat = "amlogic,meson8b-cbus-pinctrl",
79 .data = &meson8b_cbus_pinctrl_config },
80 #endif
81 #ifdef SOC_MESONGXBB
82 { .compat = "amlogic,meson-gxbb-aobus-pinctrl",
83 .data = &mesongxbb_aobus_pinctrl_config },
84 { .compat = "amlogic,meson-gxbb-periphs-pinctrl",
85 .data = &mesongxbb_periphs_pinctrl_config },
86 #endif
87 #ifdef SOC_MESONGXL
88 { .compat = "amlogic,meson-gxl-aobus-pinctrl",
89 .data = &mesongxl_aobus_pinctrl_config },
90 { .compat = "amlogic,meson-gxl-periphs-pinctrl",
91 .data = &mesongxl_periphs_pinctrl_config },
92 #endif
93 #ifdef SOC_MESONG12
94 { .compat = "amlogic,meson-g12a-aobus-pinctrl",
95 .data = &mesong12a_aobus_pinctrl_config },
96 { .compat = "amlogic,meson-g12a-periphs-pinctrl",
97 .data = &mesong12a_periphs_pinctrl_config },
98 #endif
99 DEVICE_COMPAT_EOL
100 };
101
102 #define MUX_READ(sc, reg) \
103 bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh_mux, (reg))
104 #define MUX_WRITE(sc, reg, val) \
105 bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh_mux, (reg), (val))
106
107 static const struct meson_pinctrl_group *
meson_pinctrl_find_group(struct meson_pinctrl_softc * sc,const char * name)108 meson_pinctrl_find_group(struct meson_pinctrl_softc *sc,
109 const char *name)
110 {
111 const struct meson_pinctrl_group *group;
112 u_int n;
113
114 for (n = 0; n < sc->sc_conf->ngroups; n++) {
115 group = &sc->sc_conf->groups[n];
116 if (strcmp(group->name, name) == 0)
117 return group;
118 }
119
120 return NULL;
121 }
122
123 static bool
meson_pinctrl_group_in_bank(struct meson_pinctrl_softc * sc,const struct meson_pinctrl_group * group,u_int bankno)124 meson_pinctrl_group_in_bank(struct meson_pinctrl_softc *sc,
125 const struct meson_pinctrl_group *group, u_int bankno)
126 {
127 u_int n;
128
129 for (n = 0; n < group->nbank; n++) {
130 if (group->bank[n] == bankno)
131 return true;
132 }
133
134 return false;
135 }
136
137 static void
meson_pinctrl_set_group(struct meson_pinctrl_softc * sc,const struct meson_pinctrl_group * group,bool enable)138 meson_pinctrl_set_group(struct meson_pinctrl_softc *sc,
139 const struct meson_pinctrl_group *group, bool enable)
140 {
141 uint32_t val;
142
143 val = MUX_READ(sc, group->reg);
144 if (group->mask == 0) {
145 if (enable)
146 val |= __BIT(group->bit);
147 else
148 val &= ~__BIT(group->bit);
149 } else {
150 val &= ~group->mask;
151 if (enable)
152 val |= __SHIFTIN(group->func, group->mask);
153 }
154 MUX_WRITE(sc, group->reg, val);
155 }
156
157 static void
meson_pinctrl_setfunc(struct meson_pinctrl_softc * sc,const char * name)158 meson_pinctrl_setfunc(struct meson_pinctrl_softc *sc, const char *name)
159 {
160 const struct meson_pinctrl_group *group, *target_group;
161 u_int n, bank;
162
163 target_group = meson_pinctrl_find_group(sc, name);
164 if (target_group == NULL) {
165 aprint_error_dev(sc->sc_dev, "function '%s' not supported\n", name);
166 return;
167 }
168
169 /* Disable conflicting groups */
170 for (n = 0; n < sc->sc_conf->ngroups; n++) {
171 group = &sc->sc_conf->groups[n];
172 if (target_group == group)
173 continue;
174 for (bank = 0; bank < target_group->nbank; bank++) {
175 if (meson_pinctrl_group_in_bank(sc, group, target_group->bank[bank]))
176 meson_pinctrl_set_group(sc, group, false);
177 }
178 }
179
180 /* Enable target group */
181 meson_pinctrl_set_group(sc, target_group, true);
182 }
183
184 static int
meson_pinctrl_set_config(device_t dev,const void * data,size_t len)185 meson_pinctrl_set_config(device_t dev, const void *data, size_t len)
186 {
187 struct meson_pinctrl_softc * const sc = device_private(dev);
188 const char *groups;
189 int groups_len;
190
191 if (len != 4)
192 return -1;
193
194 const int phandle = fdtbus_get_phandle_from_native(be32dec(data));
195 const int mux = of_find_firstchild_byname(phandle, "mux");
196 if (mux == -1)
197 return -1;
198
199 groups = fdtbus_pinctrl_parse_groups(mux, &groups_len);
200 if (groups == NULL)
201 return -1;
202
203 for (; groups_len > 0;
204 groups_len -= strlen(groups) + 1, groups += strlen(groups) + 1) {
205 meson_pinctrl_setfunc(sc, groups);
206 }
207
208 return 0;
209 }
210
211 static struct fdtbus_pinctrl_controller_func meson_pinctrl_funcs = {
212 .set_config = meson_pinctrl_set_config,
213 };
214
215 static bus_space_handle_t
meson_pinctrl_gpio_handle(struct meson_pinctrl_softc * sc,const struct meson_pinctrl_gpioreg * gpioreg)216 meson_pinctrl_gpio_handle(struct meson_pinctrl_softc *sc,
217 const struct meson_pinctrl_gpioreg *gpioreg)
218 {
219 switch (gpioreg->type) {
220 case MESON_PINCTRL_REGTYPE_PULL:
221 return sc->sc_bsh_pull;
222 case MESON_PINCTRL_REGTYPE_PULL_ENABLE:
223 return sc->sc_bsh_pull_enable;
224 case MESON_PINCTRL_REGTYPE_GPIO:
225 return sc->sc_bsh_gpio;
226 default:
227 panic("unsupported GPIO regtype %d", gpioreg->type);
228 }
229 }
230
231 static int
meson_pinctrl_pin_read(void * priv,int pin)232 meson_pinctrl_pin_read(void *priv, int pin)
233 {
234 struct meson_pinctrl_softc * const sc = priv;
235 const struct meson_pinctrl_gpio *pin_def = &sc->sc_conf->gpios[pin];
236 const struct meson_pinctrl_gpioreg *gpio_reg = &pin_def->in;
237 bus_space_handle_t bsh;
238 uint32_t data;
239 int val;
240
241 KASSERT(pin < sc->sc_conf->ngpios);
242
243 bsh = meson_pinctrl_gpio_handle(sc, gpio_reg);
244 data = bus_space_read_4(sc->sc_bst, bsh, gpio_reg->reg);
245 val = __SHIFTOUT(data, gpio_reg->mask);
246
247 return val;
248 }
249
250 static void
meson_pinctrl_pin_write(void * priv,int pin,int val)251 meson_pinctrl_pin_write(void *priv, int pin, int val)
252 {
253 struct meson_pinctrl_softc * const sc = priv;
254 const struct meson_pinctrl_gpio *pin_def = &sc->sc_conf->gpios[pin];
255 const struct meson_pinctrl_gpioreg *gpio_reg = &pin_def->out;
256 bus_space_handle_t bsh;
257 uint32_t data;
258
259 KASSERT(pin < sc->sc_conf->ngpios);
260
261 bsh = meson_pinctrl_gpio_handle(sc, gpio_reg);
262
263 mutex_enter(&sc->sc_lock);
264 data = bus_space_read_4(sc->sc_bst, bsh, gpio_reg->reg);
265 if (val)
266 data |= gpio_reg->mask;
267 else
268 data &= ~gpio_reg->mask;
269 bus_space_write_4(sc->sc_bst, bsh, gpio_reg->reg, data);
270 mutex_exit(&sc->sc_lock);
271 }
272
273 static void
meson_pinctrl_pin_dir(struct meson_pinctrl_softc * sc,const struct meson_pinctrl_gpio * pin_def,int flags)274 meson_pinctrl_pin_dir(struct meson_pinctrl_softc *sc,
275 const struct meson_pinctrl_gpio *pin_def, int flags)
276 {
277 bus_space_handle_t bsh;
278 uint32_t data;
279
280 KASSERT(mutex_owned(&sc->sc_lock));
281
282 bsh = meson_pinctrl_gpio_handle(sc, &pin_def->oen);
283 data = bus_space_read_4(sc->sc_bst, bsh, pin_def->oen.reg);
284 if ((flags & GPIO_PIN_INPUT) != 0)
285 data |= pin_def->oen.mask;
286 else
287 data &= ~pin_def->oen.mask;
288 bus_space_write_4(sc->sc_bst, bsh, pin_def->oen.reg, data);
289 }
290
291 static void
meson_pinctrl_pin_ctl(void * priv,int pin,int flags)292 meson_pinctrl_pin_ctl(void *priv, int pin, int flags)
293 {
294 struct meson_pinctrl_softc * const sc = priv;
295 const struct meson_pinctrl_gpio *pin_def = &sc->sc_conf->gpios[pin];
296 bus_space_handle_t bsh;
297 uint32_t data;
298
299 KASSERT(pin < sc->sc_conf->ngpios);
300
301 mutex_enter(&sc->sc_lock);
302
303 if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) != 0)
304 meson_pinctrl_pin_dir(sc, pin_def, flags);
305
306 if ((flags & (GPIO_PIN_PULLUP|GPIO_PIN_PULLDOWN)) != 0) {
307 bsh = meson_pinctrl_gpio_handle(sc, &pin_def->pupd);
308 data = bus_space_read_4(sc->sc_bst, bsh, pin_def->pupd.reg);
309 if ((flags & GPIO_PIN_PULLUP) != 0)
310 data |= pin_def->pupd.mask;
311 else
312 data &= ~pin_def->pupd.mask;
313 bus_space_write_4(sc->sc_bst, bsh, pin_def->pupd.reg, data);
314
315 bsh = meson_pinctrl_gpio_handle(sc, &pin_def->pupden);
316 data = bus_space_read_4(sc->sc_bst, bsh, pin_def->pupden.reg);
317 data |= pin_def->pupden.mask;
318 bus_space_write_4(sc->sc_bst, bsh, pin_def->pupden.reg, data);
319 } else {
320 bsh = meson_pinctrl_gpio_handle(sc, &pin_def->pupden);
321 data = bus_space_read_4(sc->sc_bst, bsh, pin_def->pupden.reg);
322 data &= ~pin_def->pupden.mask;
323 bus_space_write_4(sc->sc_bst, bsh, pin_def->pupden.reg, data);
324 }
325
326 mutex_exit(&sc->sc_lock);
327 }
328
329 static const struct meson_pinctrl_gpio *
meson_pinctrl_gpio_lookup(struct meson_pinctrl_softc * sc,u_int id)330 meson_pinctrl_gpio_lookup(struct meson_pinctrl_softc *sc, u_int id)
331 {
332 if (id >= sc->sc_conf->ngpios)
333 return NULL;
334
335 if (sc->sc_conf->gpios[id].name == NULL)
336 return NULL;
337
338 return &sc->sc_conf->gpios[id];
339 }
340
341 static void *
meson_pinctrl_gpio_acquire(device_t dev,const void * data,size_t len,int flags)342 meson_pinctrl_gpio_acquire(device_t dev, const void *data, size_t len, int flags)
343 {
344 struct meson_pinctrl_softc * const sc = device_private(dev);
345 const struct meson_pinctrl_gpio *pin_def;
346 const struct meson_pinctrl_group *group;
347 struct meson_pinctrl_gpio_pin *gpin;
348 const u_int *gpio = data;
349 u_int n, bank;
350
351 if (len != 12)
352 return NULL;
353
354 const u_int id = be32toh(gpio[1]);
355 const bool actlo = be32toh(gpio[2]) & 1;
356
357 pin_def = meson_pinctrl_gpio_lookup(sc, id);
358 if (pin_def == NULL)
359 return NULL;
360
361 /* Disable conflicting groups */
362 for (n = 0; n < sc->sc_conf->ngroups; n++) {
363 group = &sc->sc_conf->groups[n];
364 for (bank = 0; bank < group->nbank; bank++) {
365 if (group->bank[bank] == pin_def->id)
366 meson_pinctrl_set_group(sc, group, false);
367 }
368 }
369
370 mutex_enter(&sc->sc_lock);
371 meson_pinctrl_pin_dir(sc, pin_def, flags);
372 mutex_exit(&sc->sc_lock);
373
374 gpin = kmem_zalloc(sizeof(*gpin), KM_SLEEP);
375 gpin->pin_sc = sc;
376 gpin->pin_def = pin_def;
377 gpin->pin_flags = flags;
378 gpin->pin_actlo = actlo;
379
380 return gpin;
381 }
382
383 static void
meson_pinctrl_gpio_release(device_t dev,void * priv)384 meson_pinctrl_gpio_release(device_t dev, void *priv)
385 {
386 struct meson_pinctrl_softc * const sc = device_private(dev);
387 struct meson_pinctrl_gpio_pin *gpin = priv;
388 const struct meson_pinctrl_gpio *pin_def = gpin->pin_def;
389
390 KASSERT(sc == gpin->pin_sc);
391
392 mutex_enter(&sc->sc_lock);
393 meson_pinctrl_pin_dir(sc, pin_def, GPIO_PIN_INPUT);
394 mutex_exit(&sc->sc_lock);
395
396 kmem_free(gpin, sizeof(*gpin));
397 }
398
399 static int
meson_pinctrl_gpio_read(device_t dev,void * priv,bool raw)400 meson_pinctrl_gpio_read(device_t dev, void *priv, bool raw)
401 {
402 struct meson_pinctrl_softc * const sc = device_private(dev);
403 struct meson_pinctrl_gpio_pin *gpin = priv;
404 const struct meson_pinctrl_gpio *pin_def = gpin->pin_def;
405 int val;
406
407 val = meson_pinctrl_pin_read(sc, pin_def->id);
408 if (!raw && gpin->pin_actlo)
409 val = !val;
410
411 return val;
412 }
413
414 static void
meson_pinctrl_gpio_write(device_t dev,void * priv,int val,bool raw)415 meson_pinctrl_gpio_write(device_t dev, void *priv, int val, bool raw)
416 {
417 struct meson_pinctrl_softc * const sc = device_private(dev);
418 struct meson_pinctrl_gpio_pin *gpin = priv;
419 const struct meson_pinctrl_gpio *pin_def = gpin->pin_def;
420
421 if (!raw && gpin->pin_actlo)
422 val = !val;
423
424 meson_pinctrl_pin_write(sc, pin_def->id, val);
425 }
426
427 static struct fdtbus_gpio_controller_func meson_pinctrl_gpio_funcs = {
428 .acquire = meson_pinctrl_gpio_acquire,
429 .release = meson_pinctrl_gpio_release,
430 .read = meson_pinctrl_gpio_read,
431 .write = meson_pinctrl_gpio_write,
432 };
433
434 static int
meson_pinctrl_initres(struct meson_pinctrl_softc * sc)435 meson_pinctrl_initres(struct meson_pinctrl_softc *sc)
436 {
437 bool gpio_found = false;
438 bus_addr_t addr;
439 bus_size_t size;
440 int child;
441
442 for (child = OF_child(sc->sc_phandle); child; child = OF_peer(child)) {
443 if (of_hasprop(child, "gpio-controller")) {
444 if (gpio_found)
445 continue;
446 gpio_found = true;
447
448 if (fdtbus_get_reg_byname(child, "mux", &addr, &size) != 0 ||
449 bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh_mux) != 0) {
450 aprint_error(": couldn't map mux registers\n");
451 return ENXIO;
452 }
453 if (fdtbus_get_reg_byname(child, "gpio", &addr, &size) != 0 ||
454 bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh_gpio) != 0) {
455 aprint_error(": couldn't map gpio registers\n");
456 return ENXIO;
457 }
458
459 /* pull register is optional */
460 if (fdtbus_get_reg_byname(child, "pull", &addr, &size) == 0) {
461 if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh_pull) != 0) {
462 aprint_error(": couldn't map pull registers\n");
463 return ENXIO;
464 }
465 }
466 /* pull-enable register is optional */
467 if (fdtbus_get_reg_byname(child, "pull-enable", &addr, &size) == 0) {
468 if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh_pull_enable) != 0) {
469 aprint_error(": couldn't map pull-enable registers\n");
470 return ENXIO;
471 }
472 }
473
474 sc->sc_phandle_gpio = child;
475 } else if (of_find_firstchild_byname(child, "mux") != -1) {
476 fdtbus_register_pinctrl_config(sc->sc_dev, child, &meson_pinctrl_funcs);
477 }
478 }
479
480 if (!gpio_found) {
481 aprint_error(": couldn't find gpio controller\n");
482 return ENOENT;
483 }
484
485 return 0;
486 }
487
488 static void
meson_pinctrl_initgpio(struct meson_pinctrl_softc * sc)489 meson_pinctrl_initgpio(struct meson_pinctrl_softc *sc)
490 {
491 const struct meson_pinctrl_gpio *pin_def;
492 struct gpio_chipset_tag *gp;
493 struct gpiobus_attach_args gba;
494 int child, len, val;
495 u_int pin;
496
497 fdtbus_register_gpio_controller(sc->sc_dev, sc->sc_phandle_gpio, &meson_pinctrl_gpio_funcs);
498
499 for (child = OF_child(sc->sc_phandle_gpio); child; child = OF_peer(child)) {
500 if (!of_hasprop(child, "gpio-hog"))
501 continue;
502
503 const char *line_name = fdtbus_get_string(child, "line-name");
504 if (line_name == NULL)
505 line_name = fdtbus_get_string(child, "name");
506
507 const bool input = of_hasprop(child, "input");
508 const bool output_low = of_hasprop(child, "output-low");
509 const bool output_high = of_hasprop(child, "output-high");
510
511 if (!input && !output_low && !output_high) {
512 aprint_error_dev(sc->sc_dev, "no configuration for line %s\n", line_name);
513 continue;
514 }
515
516 const u_int *gpio = fdtbus_get_prop(child, "gpios", &len);
517 while (len >= 8) {
518 const u_int id = be32toh(gpio[0]);
519 const bool actlo = be32toh(gpio[1]) & 1;
520
521 pin_def = meson_pinctrl_gpio_lookup(sc, id);
522 if (pin_def != NULL) {
523 if (input) {
524 device_printf(sc->sc_dev, "%s %s set to input\n",
525 line_name, pin_def->name);
526 meson_pinctrl_pin_ctl(sc, pin_def->id, GPIO_PIN_INPUT);
527 } else {
528 val = output_high;
529 if (actlo)
530 val = !val;
531 device_printf(sc->sc_dev, "%s %s set to output (%s)\n",
532 line_name, pin_def->name, val ? "high" : "low");
533 meson_pinctrl_pin_write(sc, pin_def->id, val);
534 meson_pinctrl_pin_ctl(sc, pin_def->id, GPIO_PIN_OUTPUT);
535 }
536 } else {
537 aprint_error_dev(sc->sc_dev, "%s: unsupported pin %d\n", line_name, id);
538 }
539
540 len -= 8;
541 gpio += 8;
542 }
543 }
544
545 const u_int npins = sc->sc_conf->ngpios;
546 sc->sc_pins = kmem_zalloc(sizeof(*sc->sc_pins) * npins, KM_SLEEP);
547 for (pin = 0; pin < npins; pin++) {
548 pin_def = &sc->sc_conf->gpios[pin];
549 sc->sc_pins[pin].pin_num = pin;
550 if (pin_def->name == NULL)
551 continue;
552 sc->sc_pins[pin].pin_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT |
553 GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN;
554 sc->sc_pins[pin].pin_state = meson_pinctrl_pin_read(sc, pin);
555 strlcpy(sc->sc_pins[pin].pin_defname, pin_def->name,
556 sizeof(sc->sc_pins[pin].pin_defname));
557 }
558
559 gp = &sc->sc_gp;
560 gp->gp_cookie = sc;
561 gp->gp_pin_read = meson_pinctrl_pin_read;
562 gp->gp_pin_write = meson_pinctrl_pin_write;
563 gp->gp_pin_ctl = meson_pinctrl_pin_ctl;
564
565 memset(&gba, 0, sizeof(gba));
566 gba.gba_gc = gp;
567 gba.gba_pins = sc->sc_pins;
568 gba.gba_npins = npins;
569 config_found(sc->sc_dev, &gba, NULL, CFARGS_NONE);
570 }
571
572 static int
meson_pinctrl_match(device_t parent,cfdata_t cf,void * aux)573 meson_pinctrl_match(device_t parent, cfdata_t cf, void *aux)
574 {
575 struct fdt_attach_args * const faa = aux;
576
577 return of_compatible_match(faa->faa_phandle, compat_data);
578 }
579
580 static void
meson_pinctrl_attach(device_t parent,device_t self,void * aux)581 meson_pinctrl_attach(device_t parent, device_t self, void *aux)
582 {
583 struct meson_pinctrl_softc * const sc = device_private(self);
584 struct fdt_attach_args * const faa = aux;
585
586 sc->sc_dev = self;
587 sc->sc_phandle = faa->faa_phandle;
588 sc->sc_bst = faa->faa_bst;
589 sc->sc_conf = of_compatible_lookup(sc->sc_phandle, compat_data)->data;
590 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM);
591
592 if (meson_pinctrl_initres(sc) != 0)
593 return;
594
595 aprint_naive("\n");
596 aprint_normal(": %s\n", sc->sc_conf->name);
597
598 meson_pinctrl_initgpio(sc);
599 }
600
601 CFATTACH_DECL_NEW(meson_pinctrl, sizeof(struct meson_pinctrl_softc),
602 meson_pinctrl_match, meson_pinctrl_attach, NULL, NULL);
603