xref: /netbsd-src/sys/arch/arm/amlogic/meson_pinctrl.c (revision c7fb772b85b2b5d4cfb282f868f454b4701534fd)
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