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