xref: /freebsd/sys/arm/nvidia/as3722_gpio.c (revision a0b9e2e854027e6ff61fb075a1309dbc71c42b54)
1 /*-
2  * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/bus.h>
33 #include <sys/gpio.h>
34 #include <sys/kernel.h>
35 #include <sys/malloc.h>
36 #include <sys/sx.h>
37 
38 #include <machine/bus.h>
39 
40 #include <dev/fdt/fdt_common.h>
41 #include <dev/gpio/gpiobusvar.h>
42 
43 #include "as3722.h"
44 
45 MALLOC_DEFINE(M_AS3722_GPIO, "AS3722 gpio", "AS3722 GPIO");
46 
47 /* AS3722_GPIOx_CONTROL	 MODE and IOSF definition. */
48 #define	AS3722_IOSF_GPIO				0x00
49 #define	AS3722_IOSF_INTERRUPT_OUT			0x01
50 #define	AS3722_IOSF_VSUP_VBAT_LOW_UNDEBOUNCE_OUT	0x02
51 #define	AS3722_IOSF_GPIO_IN_INTERRUPT			0x03
52 #define	AS3722_IOSF_PWM_IN				0x04
53 #define	AS3722_IOSF_VOLTAGE_IN_STANDBY			0x05
54 #define	AS3722_IOSF_OC_PG_SD0				0x06
55 #define	AS3722_IOSF_POWERGOOD_OUT			0x07
56 #define	AS3722_IOSF_CLK32K_OUT				0x08
57 #define	AS3722_IOSF_WATCHDOG_IN				0x09
58 #define	AS3722_IOSF_SOFT_RESET_IN			0x0b
59 #define	AS3722_IOSF_PWM_OUT				0x0c
60 #define	AS3722_IOSF_VSUP_VBAT_LOW_DEBOUNCE_OUT		0x0d
61 #define	AS3722_IOSF_OC_PG_SD6				0x0e
62 
63 #define	AS3722_MODE_INPUT				0
64 #define	AS3722_MODE_PUSH_PULL				1
65 #define	AS3722_MODE_OPEN_DRAIN				2
66 #define	AS3722_MODE_TRISTATE				3
67 #define	AS3722_MODE_INPUT_PULL_UP_LV			4
68 #define	AS3722_MODE_INPUT_PULL_DOWN			5
69 #define	AS3722_MODE_OPEN_DRAIN_LV			6
70 #define	AS3722_MODE_PUSH_PULL_LV			7
71 
72 #define	NGPIO		8
73 
74 #define	GPIO_LOCK(_sc)	sx_slock(&(_sc)->gpio_lock)
75 #define	GPIO_UNLOCK(_sc)	sx_unlock(&(_sc)->gpio_lock)
76 #define	GPIO_ASSERT(_sc)	sx_assert(&(_sc)->gpio_lock, SA_LOCKED)
77 
78 #define	AS3722_CFG_BIAS_DISABLE		0x0001
79 #define	AS3722_CFG_BIAS_PULL_UP		0x0002
80 #define	AS3722_CFG_BIAS_PULL_DOWN	0x0004
81 #define	AS3722_CFG_BIAS_HIGH_IMPEDANCE	0x0008
82 #define	AS3722_CFG_OPEN_DRAIN		0x0010
83 
84 static const struct {
85 	const char	*name;
86 	int  		config;		/* AS3722_CFG_  */
87 } as3722_cfg_names[] = {
88 	{"bias-disable",	AS3722_CFG_BIAS_DISABLE},
89 	{"bias-pull-up",	AS3722_CFG_BIAS_PULL_UP},
90 	{"bias-pull-down",	AS3722_CFG_BIAS_PULL_DOWN},
91 	{"bias-high-impedance",	AS3722_CFG_BIAS_HIGH_IMPEDANCE},
92 	{"drive-open-drain",	AS3722_CFG_OPEN_DRAIN},
93 };
94 
95 static struct {
96 	const char *name;
97 	int fnc_val;
98 } as3722_fnc_table[] = {
99 	{"gpio",			AS3722_IOSF_GPIO},
100 	{"interrupt-out",		AS3722_IOSF_INTERRUPT_OUT},
101 	{"vsup-vbat-low-undebounce-out", AS3722_IOSF_VSUP_VBAT_LOW_UNDEBOUNCE_OUT},
102 	{"gpio-in-interrupt",		AS3722_IOSF_GPIO_IN_INTERRUPT},
103 	{"pwm-in",			AS3722_IOSF_PWM_IN},
104 	{"voltage-in-standby",		AS3722_IOSF_VOLTAGE_IN_STANDBY},
105 	{"oc-pg-sd0",			AS3722_IOSF_OC_PG_SD0},
106 	{"powergood-out",		AS3722_IOSF_POWERGOOD_OUT},
107 	{"clk32k-out",			AS3722_IOSF_CLK32K_OUT},
108 	{"watchdog-in",			AS3722_IOSF_WATCHDOG_IN},
109 	{"soft-reset-in",		AS3722_IOSF_SOFT_RESET_IN},
110 	{"pwm-out",			AS3722_IOSF_PWM_OUT},
111 	{"vsup-vbat-low-debounce-out",	AS3722_IOSF_VSUP_VBAT_LOW_DEBOUNCE_OUT},
112 	{"oc-pg-sd6",			AS3722_IOSF_OC_PG_SD6},
113 };
114 
115 struct as3722_pincfg {
116 	char	*function;
117 	int	flags;
118 };
119 
120 struct as3722_gpio_pin {
121 	int	pin_caps;
122 	uint8_t	pin_ctrl_reg;
123 	char	pin_name[GPIOMAXNAME];
124 	int	pin_cfg_flags;
125 };
126 
127 /* --------------------------------------------------------------------------
128  *
129  *  Pinmux functions.
130  */
131 static int
132 as3722_pinmux_get_function(struct as3722_softc *sc, char *name)
133 {
134 	int i;
135 
136 	for (i = 0; i < nitems(as3722_fnc_table); i++) {
137 		if (strcmp(as3722_fnc_table[i].name, name) == 0)
138 			 return (as3722_fnc_table[i].fnc_val);
139 	}
140 	return (-1);
141 }
142 
143 static int
144 as3722_pinmux_config_node(struct as3722_softc *sc, char *pin_name,
145     struct as3722_pincfg *cfg)
146 {
147 	uint8_t ctrl;
148 	int rv, fnc, pin;
149 
150 	for (pin = 0; pin < sc->gpio_npins; pin++) {
151 		if (strcmp(sc->gpio_pins[pin]->pin_name, pin_name) == 0)
152 			 break;
153 	}
154 	if (pin >= sc->gpio_npins) {
155 		device_printf(sc->dev, "Unknown pin: %s\n", pin_name);
156 		return (ENXIO);
157 	}
158 
159 	ctrl = sc->gpio_pins[pin]->pin_ctrl_reg;
160 	sc->gpio_pins[pin]->pin_cfg_flags = cfg->flags;
161 	if (cfg->function != NULL) {
162 		fnc = as3722_pinmux_get_function(sc, cfg->function);
163 		if (fnc == -1) {
164 			device_printf(sc->dev,
165 			    "Unknown function %s for pin %s\n", cfg->function,
166 			    sc->gpio_pins[pin]->pin_name);
167 			return (ENXIO);
168 		}
169 		switch (fnc) {
170 		case AS3722_IOSF_INTERRUPT_OUT:
171 		case AS3722_IOSF_VSUP_VBAT_LOW_UNDEBOUNCE_OUT:
172 		case AS3722_IOSF_OC_PG_SD0:
173 		case AS3722_IOSF_POWERGOOD_OUT:
174 		case AS3722_IOSF_CLK32K_OUT:
175 		case AS3722_IOSF_PWM_OUT:
176 		case AS3722_IOSF_OC_PG_SD6:
177 			ctrl &= ~(AS3722_GPIO_MODE_MASK <<
178 			    AS3722_GPIO_MODE_SHIFT);
179 			ctrl |= AS3722_MODE_PUSH_PULL << AS3722_GPIO_MODE_SHIFT;
180 			/* XXX Handle flags (OC + pullup) */
181 			break;
182 		case AS3722_IOSF_GPIO_IN_INTERRUPT:
183 		case AS3722_IOSF_PWM_IN:
184 		case AS3722_IOSF_VOLTAGE_IN_STANDBY:
185 		case AS3722_IOSF_WATCHDOG_IN:
186 		case AS3722_IOSF_SOFT_RESET_IN:
187 			ctrl &= ~(AS3722_GPIO_MODE_MASK <<
188 			    AS3722_GPIO_MODE_SHIFT);
189 			ctrl |= AS3722_MODE_INPUT << AS3722_GPIO_MODE_SHIFT;
190 			/* XXX Handle flags (pulldown + pullup) */
191 
192 		default:
193 			break;
194 		}
195 		ctrl &= ~(AS3722_GPIO_IOSF_MASK << AS3722_GPIO_IOSF_SHIFT);
196 		ctrl |= fnc << AS3722_GPIO_IOSF_SHIFT;
197 	}
198 	rv = 0;
199 	if (ctrl != sc->gpio_pins[pin]->pin_ctrl_reg) {
200 		rv = WR1(sc, AS3722_GPIO0_CONTROL + pin, ctrl);
201 		sc->gpio_pins[pin]->pin_ctrl_reg = ctrl;
202 	}
203 	return (rv);
204 }
205 
206 static int
207 as3722_pinmux_read_node(struct as3722_softc *sc, phandle_t node,
208      struct as3722_pincfg *cfg, char **pins, int *lpins)
209 {
210 	int rv, i;
211 
212 	*lpins = OF_getprop_alloc(node, "pins", (void **)pins);
213 	if (*lpins <= 0)
214 		return (ENOENT);
215 
216 	/* Read function (mux) settings. */
217 	rv = OF_getprop_alloc(node, "function", (void **)&cfg->function);
218 	if (rv <= 0)
219 		cfg->function = NULL;
220 
221 	/* Read boolean properties. */
222 	for (i = 0; i < nitems(as3722_cfg_names); i++) {
223 		if (OF_hasprop(node, as3722_cfg_names[i].name))
224 			cfg->flags |= as3722_cfg_names[i].config;
225 	}
226 	return (0);
227 }
228 
229 static int
230 as3722_pinmux_process_node(struct as3722_softc *sc, phandle_t node)
231 {
232 	struct as3722_pincfg cfg;
233 	char *pins, *pname;
234 	int i, len, lpins, rv;
235 
236 	rv = as3722_pinmux_read_node(sc, node, &cfg, &pins, &lpins);
237 	if (rv != 0)
238 		return (rv);
239 
240 	len = 0;
241 	pname = pins;
242 	do {
243 		i = strlen(pname) + 1;
244 		rv = as3722_pinmux_config_node(sc, pname, &cfg);
245 		if (rv != 0) {
246 			device_printf(sc->dev,
247 			    "Cannot configure pin: %s: %d\n", pname, rv);
248 		}
249 		len += i;
250 		pname += i;
251 	} while (len < lpins);
252 
253 	if (pins != NULL)
254 		OF_prop_free(pins);
255 	if (cfg.function != NULL)
256 		OF_prop_free(cfg.function);
257 
258 	return (rv);
259 }
260 
261 int as3722_pinmux_configure(device_t dev, phandle_t cfgxref)
262 {
263 	struct as3722_softc *sc;
264 	phandle_t node, cfgnode;
265 	int rv;
266 
267 	sc = device_get_softc(dev);
268 	cfgnode = OF_node_from_xref(cfgxref);
269 
270 	for (node = OF_child(cfgnode); node != 0; node = OF_peer(node)) {
271 		if (!ofw_bus_node_status_okay(node))
272 			continue;
273 		rv = as3722_pinmux_process_node(sc, node);
274 		if (rv != 0)
275 			device_printf(dev, "Failed to process pinmux");
276 	}
277 	return (0);
278 }
279 
280 /* --------------------------------------------------------------------------
281  *
282  *  GPIO
283  */
284 device_t
285 as3722_gpio_get_bus(device_t dev)
286 {
287 	struct as3722_softc *sc;
288 
289 	sc = device_get_softc(dev);
290 	return (sc->gpio_busdev);
291 }
292 
293 int
294 as3722_gpio_pin_max(device_t dev, int *maxpin)
295 {
296 
297 	*maxpin = NGPIO - 1;
298 	return (0);
299 }
300 
301 int
302 as3722_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
303 {
304 	struct as3722_softc *sc;
305 
306 	sc = device_get_softc(dev);
307 	if (pin >= sc->gpio_npins)
308 		return (EINVAL);
309 	GPIO_LOCK(sc);
310 	*caps = sc->gpio_pins[pin]->pin_caps;
311 	GPIO_UNLOCK(sc);
312 	return (0);
313 }
314 
315 int
316 as3722_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
317 {
318 	struct as3722_softc *sc;
319 
320 	sc = device_get_softc(dev);
321 	if (pin >= sc->gpio_npins)
322 		return (EINVAL);
323 	GPIO_LOCK(sc);
324 	memcpy(name, sc->gpio_pins[pin]->pin_name, GPIOMAXNAME);
325 	GPIO_UNLOCK(sc);
326 	return (0);
327 }
328 
329 int
330 as3722_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *out_flags)
331 {
332 	struct as3722_softc *sc;
333 	uint8_t tmp, mode, iosf;
334 	uint32_t flags;
335 	bool inverted;
336 
337 	sc = device_get_softc(dev);
338 	if (pin >= sc->gpio_npins)
339 		return (EINVAL);
340 
341 	GPIO_LOCK(sc);
342 	tmp = sc->gpio_pins[pin]->pin_ctrl_reg;
343 	GPIO_UNLOCK(sc);
344 	iosf = (tmp >> AS3722_GPIO_IOSF_SHIFT) & AS3722_GPIO_IOSF_MASK;
345 	mode = (tmp >> AS3722_GPIO_MODE_SHIFT) & AS3722_GPIO_MODE_MASK;
346 	inverted = (tmp & AS3722_GPIO_INVERT) != 0;
347 	/* Is pin in GPIO mode ? */
348 	if (iosf != AS3722_IOSF_GPIO)
349 		return (ENXIO);
350 
351 	flags = 0;
352 	switch (mode) {
353 	case AS3722_MODE_INPUT:
354 		flags = GPIO_PIN_INPUT;
355 		break;
356 	case AS3722_MODE_PUSH_PULL:
357 	case AS3722_MODE_PUSH_PULL_LV:
358 		flags = GPIO_PIN_OUTPUT;
359 		break;
360 	case AS3722_MODE_OPEN_DRAIN:
361 	case AS3722_MODE_OPEN_DRAIN_LV:
362 		flags = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN;
363 		break;
364 	case AS3722_MODE_TRISTATE:
365 		flags = GPIO_PIN_TRISTATE;
366 		break;
367 	case AS3722_MODE_INPUT_PULL_UP_LV:
368 		flags = GPIO_PIN_INPUT | GPIO_PIN_PULLUP;
369 		break;
370 
371 	case AS3722_MODE_INPUT_PULL_DOWN:
372 		flags = GPIO_PIN_OUTPUT | GPIO_PIN_PULLDOWN;
373 		break;
374 	}
375 	if (inverted)
376 		flags |= GPIO_PIN_INVIN | GPIO_PIN_INVOUT;
377 	*out_flags = flags;
378 	return (0);
379 }
380 
381 static int
382 as3722_gpio_get_mode(struct as3722_softc *sc, uint32_t pin, uint32_t gpio_flags)
383 {
384 	uint8_t ctrl;
385 	int flags;
386 
387 	ctrl = sc->gpio_pins[pin]->pin_ctrl_reg;
388 	flags =  sc->gpio_pins[pin]->pin_cfg_flags;
389 
390 	/* Tristate mode. */
391 	if (flags & AS3722_CFG_BIAS_HIGH_IMPEDANCE ||
392 	    gpio_flags & GPIO_PIN_TRISTATE)
393 		return (AS3722_MODE_TRISTATE);
394 
395 	/* Open drain modes. */
396 	if (flags & AS3722_CFG_OPEN_DRAIN || gpio_flags & GPIO_PIN_OPENDRAIN) {
397 		/* Only pull up have effect */
398 		if (flags & AS3722_CFG_BIAS_PULL_UP ||
399 		    gpio_flags & GPIO_PIN_PULLUP)
400 			return (AS3722_MODE_OPEN_DRAIN_LV);
401 		return (AS3722_MODE_OPEN_DRAIN);
402 	}
403 	/* Input modes. */
404 	if (gpio_flags & GPIO_PIN_INPUT) {
405 		/* Accept pull up or pull down. */
406 		if (flags & AS3722_CFG_BIAS_PULL_UP ||
407 		    gpio_flags & GPIO_PIN_PULLUP)
408 			return (AS3722_MODE_INPUT_PULL_UP_LV);
409 
410 		if (flags & AS3722_CFG_BIAS_PULL_DOWN ||
411 		    gpio_flags & GPIO_PIN_PULLDOWN)
412 			return (AS3722_MODE_INPUT_PULL_DOWN);
413 		return (AS3722_MODE_INPUT);
414 	}
415 	/*
416 	 * Output modes.
417 	 * Pull down is used as indicator of low voltage output.
418 	 */
419 	if (flags & AS3722_CFG_BIAS_PULL_DOWN ||
420 		    gpio_flags & GPIO_PIN_PULLDOWN)
421 		return (AS3722_MODE_PUSH_PULL_LV);
422 	return (AS3722_MODE_PUSH_PULL);
423 }
424 
425 int
426 as3722_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
427 {
428 	struct as3722_softc *sc;
429 	uint8_t ctrl, mode, iosf;
430 	int rv;
431 
432 	sc = device_get_softc(dev);
433 	if (pin >= sc->gpio_npins)
434 		return (EINVAL);
435 
436 	GPIO_LOCK(sc);
437 	ctrl = sc->gpio_pins[pin]->pin_ctrl_reg;
438 	iosf = (ctrl >> AS3722_GPIO_IOSF_SHIFT) & AS3722_GPIO_IOSF_MASK;
439 	/* Is pin in GPIO mode ? */
440 	if (iosf != AS3722_IOSF_GPIO) {
441 		GPIO_UNLOCK(sc);
442 		return (ENXIO);
443 	}
444 	mode = as3722_gpio_get_mode(sc, pin, flags);
445 	ctrl &= ~(AS3722_GPIO_MODE_MASK << AS3722_GPIO_MODE_SHIFT);
446 	ctrl |= AS3722_MODE_PUSH_PULL << AS3722_GPIO_MODE_SHIFT;
447 	rv = 0;
448 	if (ctrl != sc->gpio_pins[pin]->pin_ctrl_reg) {
449 		rv = WR1(sc, AS3722_GPIO0_CONTROL + pin, ctrl);
450 		sc->gpio_pins[pin]->pin_ctrl_reg = ctrl;
451 	}
452 	GPIO_UNLOCK(sc);
453 	return (rv);
454 }
455 
456 int
457 as3722_gpio_pin_set(device_t dev, uint32_t pin, uint32_t val)
458 {
459 	struct as3722_softc *sc;
460 	uint8_t tmp;
461 	int rv;
462 
463 	sc = device_get_softc(dev);
464 	if (pin >= sc->gpio_npins)
465 		return (EINVAL);
466 
467 	tmp =  (val != 0) ? 1 : 0;
468 	if (sc->gpio_pins[pin]->pin_ctrl_reg & AS3722_GPIO_INVERT)
469 		tmp ^= 1;
470 
471 	GPIO_LOCK(sc);
472 	rv = RM1(sc, AS3722_GPIO_SIGNAL_OUT, (1 << pin), (tmp << pin));
473 	GPIO_UNLOCK(sc);
474 	return (rv);
475 }
476 
477 int
478 as3722_gpio_pin_get(device_t dev, uint32_t pin, uint32_t *val)
479 {
480 	struct as3722_softc *sc;
481 	uint8_t tmp, mode, ctrl;
482 	int rv;
483 
484 	sc = device_get_softc(dev);
485 	if (pin >= sc->gpio_npins)
486 		return (EINVAL);
487 
488 	GPIO_LOCK(sc);
489 	ctrl = sc->gpio_pins[pin]->pin_ctrl_reg;
490 	mode = (ctrl >> AS3722_GPIO_MODE_SHIFT) & AS3722_GPIO_MODE_MASK;
491 	if ((mode == AS3722_MODE_PUSH_PULL) ||
492 	    (mode == AS3722_MODE_PUSH_PULL_LV))
493 		rv = RD1(sc, AS3722_GPIO_SIGNAL_OUT, &tmp);
494 	else
495 		rv = RD1(sc, AS3722_GPIO_SIGNAL_IN, &tmp);
496 	GPIO_UNLOCK(sc);
497 	if (rv != 0)
498 		return (rv);
499 
500 	*val = tmp & (1 << pin) ? 1 : 0;
501 	if (ctrl & AS3722_GPIO_INVERT)
502 		*val ^= 1;
503 	return (0);
504 }
505 
506 int
507 as3722_gpio_pin_toggle(device_t dev, uint32_t pin)
508 {
509 	struct as3722_softc *sc;
510 	uint8_t tmp;
511 	int rv;
512 
513 	sc = device_get_softc(dev);
514 	if (pin >= sc->gpio_npins)
515 		return (EINVAL);
516 
517 	GPIO_LOCK(sc);
518 	rv = RD1(sc, AS3722_GPIO_SIGNAL_OUT, &tmp);
519 	if (rv != 0) {
520 		GPIO_UNLOCK(sc);
521 		return (rv);
522 	}
523 	tmp ^= (1 <<pin);
524 	rv = RM1(sc, AS3722_GPIO_SIGNAL_OUT, (1 << pin), tmp);
525 	GPIO_UNLOCK(sc);
526 	return (0);
527 }
528 
529 int
530 as3722_gpio_map_gpios(device_t dev, phandle_t pdev, phandle_t gparent,
531     int gcells, pcell_t *gpios, uint32_t *pin, uint32_t *flags)
532 {
533 
534 	if (gcells != 2)
535 		return (ERANGE);
536 	*pin = gpios[0];
537 	*flags= gpios[1];
538 	return (0);
539 }
540 
541 int
542 as3722_gpio_attach(struct as3722_softc *sc, phandle_t node)
543 {
544 	struct as3722_gpio_pin *pin;
545 	int i, rv;
546 
547 	sx_init(&sc->gpio_lock, "AS3722 GPIO lock");
548 	sc->gpio_npins = NGPIO;
549 	sc->gpio_pins = malloc(sizeof(struct as3722_gpio_pin *) *
550 	    sc->gpio_npins, M_AS3722_GPIO, M_WAITOK | M_ZERO);
551 
552 	sc->gpio_busdev = gpiobus_attach_bus(sc->dev);
553 	if (sc->gpio_busdev == NULL)
554 		return (ENXIO);
555 	for (i = 0; i < sc->gpio_npins; i++) {
556 		sc->gpio_pins[i] = malloc(sizeof(struct as3722_gpio_pin),
557 		    M_AS3722_GPIO, M_WAITOK | M_ZERO);
558 		pin = sc->gpio_pins[i];
559 		sprintf(pin->pin_name, "gpio%d", i);
560 		pin->pin_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT  |
561 		    GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL | GPIO_PIN_TRISTATE |
562 		    GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN | GPIO_PIN_INVIN |
563 		    GPIO_PIN_INVOUT;
564 		rv = RD1(sc, AS3722_GPIO0_CONTROL + i, &pin->pin_ctrl_reg);
565 		if (rv != 0) {
566 			device_printf(sc->dev,
567 			    "Cannot read configuration for pin %s\n",
568 			    sc->gpio_pins[i]->pin_name);
569 		}
570 	}
571 	return (0);
572 }
573