xref: /freebsd/sys/arm/nvidia/as3722_gpio.c (revision 4928135658a9d0eaee37003df6137ab363fcb0b4)
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  *
130  *  Pinmux functions.
131  */
132 static int
133 as3722_pinmux_get_function(struct as3722_softc *sc, char *name)
134 {
135 	int i;
136 
137 	for (i = 0; i < nitems(as3722_fnc_table); i++) {
138 		if (strcmp(as3722_fnc_table[i].name, name) == 0)
139 			 return (as3722_fnc_table[i].fnc_val);
140 	}
141 	return (-1);
142 }
143 
144 
145 
146 static int
147 as3722_pinmux_config_node(struct as3722_softc *sc, char *pin_name,
148     struct as3722_pincfg *cfg)
149 {
150 	uint8_t ctrl;
151 	int rv, fnc, pin;
152 
153 	for (pin = 0; pin < sc->gpio_npins; pin++) {
154 		if (strcmp(sc->gpio_pins[pin]->pin_name, pin_name) == 0)
155 			 break;
156 	}
157 	if (pin >= sc->gpio_npins) {
158 		device_printf(sc->dev, "Unknown pin: %s\n", pin_name);
159 		return (ENXIO);
160 	}
161 
162 	ctrl = sc->gpio_pins[pin]->pin_ctrl_reg;
163 	sc->gpio_pins[pin]->pin_cfg_flags = cfg->flags;
164 	if (cfg->function != NULL) {
165 		fnc = as3722_pinmux_get_function(sc, cfg->function);
166 		if (fnc == -1) {
167 			device_printf(sc->dev,
168 			    "Unknown function %s for pin %s\n", cfg->function,
169 			    sc->gpio_pins[pin]->pin_name);
170 			return (ENXIO);
171 		}
172 		switch (fnc) {
173 		case AS3722_IOSF_INTERRUPT_OUT:
174 		case AS3722_IOSF_VSUP_VBAT_LOW_UNDEBOUNCE_OUT:
175 		case AS3722_IOSF_OC_PG_SD0:
176 		case AS3722_IOSF_POWERGOOD_OUT:
177 		case AS3722_IOSF_CLK32K_OUT:
178 		case AS3722_IOSF_PWM_OUT:
179 		case AS3722_IOSF_OC_PG_SD6:
180 			ctrl &= ~(AS3722_GPIO_MODE_MASK <<
181 			    AS3722_GPIO_MODE_SHIFT);
182 			ctrl |= AS3722_MODE_PUSH_PULL << AS3722_GPIO_MODE_SHIFT;
183 			/* XXX Handle flags (OC + pullup) */
184 			break;
185 		case AS3722_IOSF_GPIO_IN_INTERRUPT:
186 		case AS3722_IOSF_PWM_IN:
187 		case AS3722_IOSF_VOLTAGE_IN_STANDBY:
188 		case AS3722_IOSF_WATCHDOG_IN:
189 		case AS3722_IOSF_SOFT_RESET_IN:
190 			ctrl &= ~(AS3722_GPIO_MODE_MASK <<
191 			    AS3722_GPIO_MODE_SHIFT);
192 			ctrl |= AS3722_MODE_INPUT << AS3722_GPIO_MODE_SHIFT;
193 			/* XXX Handle flags (pulldown + pullup) */
194 
195 		default:
196 			break;
197 		}
198 		ctrl &= ~(AS3722_GPIO_IOSF_MASK << AS3722_GPIO_IOSF_SHIFT);
199 		ctrl |= fnc << AS3722_GPIO_IOSF_SHIFT;
200 	}
201 	rv = 0;
202 	if (ctrl != sc->gpio_pins[pin]->pin_ctrl_reg) {
203 		rv = WR1(sc, AS3722_GPIO0_CONTROL + pin, ctrl);
204 		sc->gpio_pins[pin]->pin_ctrl_reg = ctrl;
205 	}
206 	return (rv);
207 }
208 
209 static int
210 as3722_pinmux_read_node(struct as3722_softc *sc, phandle_t node,
211      struct as3722_pincfg *cfg, char **pins, int *lpins)
212 {
213 	int rv, i;
214 
215 	*lpins = OF_getprop_alloc(node, "pins", (void **)pins);
216 	if (*lpins <= 0)
217 		return (ENOENT);
218 
219 	/* Read function (mux) settings. */
220 	rv = OF_getprop_alloc(node, "function", (void **)&cfg->function);
221 	if (rv <= 0)
222 		cfg->function = NULL;
223 
224 	/* Read boolean properties. */
225 	for (i = 0; i < nitems(as3722_cfg_names); i++) {
226 		if (OF_hasprop(node, as3722_cfg_names[i].name))
227 			cfg->flags |= as3722_cfg_names[i].config;
228 	}
229 	return (0);
230 }
231 
232 static int
233 as3722_pinmux_process_node(struct as3722_softc *sc, phandle_t node)
234 {
235 	struct as3722_pincfg cfg;
236 	char *pins, *pname;
237 	int i, len, lpins, rv;
238 
239 	rv = as3722_pinmux_read_node(sc, node, &cfg, &pins, &lpins);
240 	if (rv != 0)
241 		return (rv);
242 
243 	len = 0;
244 	pname = pins;
245 	do {
246 		i = strlen(pname) + 1;
247 		rv = as3722_pinmux_config_node(sc, pname, &cfg);
248 		if (rv != 0) {
249 			device_printf(sc->dev,
250 			    "Cannot configure pin: %s: %d\n", pname, rv);
251 		}
252 		len += i;
253 		pname += i;
254 	} while (len < lpins);
255 
256 	if (pins != NULL)
257 		OF_prop_free(pins);
258 	if (cfg.function != NULL)
259 		OF_prop_free(cfg.function);
260 
261 	return (rv);
262 }
263 
264 int as3722_pinmux_configure(device_t dev, phandle_t cfgxref)
265 {
266 	struct as3722_softc *sc;
267 	phandle_t node, cfgnode;
268 	int rv;
269 
270 	sc = device_get_softc(dev);
271 	cfgnode = OF_node_from_xref(cfgxref);
272 
273 	for (node = OF_child(cfgnode); node != 0; node = OF_peer(node)) {
274 		if (!ofw_bus_node_status_okay(node))
275 			continue;
276 		rv = as3722_pinmux_process_node(sc, node);
277 		if (rv != 0)
278 			device_printf(dev, "Failed to process pinmux");
279 
280 	}
281 	return (0);
282 }
283 
284 /* --------------------------------------------------------------------------
285  *
286  *  GPIO
287  */
288 device_t
289 as3722_gpio_get_bus(device_t dev)
290 {
291 	struct as3722_softc *sc;
292 
293 	sc = device_get_softc(dev);
294 	return (sc->gpio_busdev);
295 }
296 
297 int
298 as3722_gpio_pin_max(device_t dev, int *maxpin)
299 {
300 
301 	*maxpin = NGPIO - 1;
302 	return (0);
303 }
304 
305 int
306 as3722_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
307 {
308 	struct as3722_softc *sc;
309 
310 	sc = device_get_softc(dev);
311 	if (pin >= sc->gpio_npins)
312 		return (EINVAL);
313 	GPIO_LOCK(sc);
314 	*caps = sc->gpio_pins[pin]->pin_caps;
315 	GPIO_UNLOCK(sc);
316 	return (0);
317 }
318 
319 int
320 as3722_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
321 {
322 	struct as3722_softc *sc;
323 
324 	sc = device_get_softc(dev);
325 	if (pin >= sc->gpio_npins)
326 		return (EINVAL);
327 	GPIO_LOCK(sc);
328 	memcpy(name, sc->gpio_pins[pin]->pin_name, GPIOMAXNAME);
329 	GPIO_UNLOCK(sc);
330 	return (0);
331 }
332 
333 int
334 as3722_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *out_flags)
335 {
336 	struct as3722_softc *sc;
337 	uint8_t tmp, mode, iosf;
338 	uint32_t flags;
339 	bool inverted;
340 
341 	sc = device_get_softc(dev);
342 	if (pin >= sc->gpio_npins)
343 		return (EINVAL);
344 
345 	GPIO_LOCK(sc);
346 	tmp = sc->gpio_pins[pin]->pin_ctrl_reg;
347 	GPIO_UNLOCK(sc);
348 	iosf = (tmp >> AS3722_GPIO_IOSF_SHIFT) & AS3722_GPIO_IOSF_MASK;
349 	mode = (tmp >> AS3722_GPIO_MODE_SHIFT) & AS3722_GPIO_MODE_MASK;
350 	inverted = (tmp & AS3722_GPIO_INVERT) != 0;
351 	/* Is pin in GPIO mode ? */
352 	if (iosf != AS3722_IOSF_GPIO)
353 		return (ENXIO);
354 
355 	flags = 0;
356 	switch (mode) {
357 	case AS3722_MODE_INPUT:
358 		flags = GPIO_PIN_INPUT;
359 		break;
360 	case AS3722_MODE_PUSH_PULL:
361 	case AS3722_MODE_PUSH_PULL_LV:
362 		flags = GPIO_PIN_OUTPUT;
363 		break;
364 	case AS3722_MODE_OPEN_DRAIN:
365 	case AS3722_MODE_OPEN_DRAIN_LV:
366 		flags = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN;
367 		break;
368 	case AS3722_MODE_TRISTATE:
369 		flags = GPIO_PIN_TRISTATE;
370 		break;
371 	case AS3722_MODE_INPUT_PULL_UP_LV:
372 		flags = GPIO_PIN_INPUT | GPIO_PIN_PULLUP;
373 		break;
374 
375 	case AS3722_MODE_INPUT_PULL_DOWN:
376 		flags = GPIO_PIN_OUTPUT | GPIO_PIN_PULLDOWN;
377 		break;
378 	}
379 	if (inverted)
380 		flags |= GPIO_PIN_INVIN | GPIO_PIN_INVOUT;
381 	*out_flags = flags;
382 	return (0);
383 }
384 
385 static int
386 as3722_gpio_get_mode(struct as3722_softc *sc, uint32_t pin, uint32_t gpio_flags)
387 {
388 	uint8_t ctrl;
389 	int flags;
390 
391 	ctrl = sc->gpio_pins[pin]->pin_ctrl_reg;
392 	flags =  sc->gpio_pins[pin]->pin_cfg_flags;
393 
394 	/* Tristate mode. */
395 	if (flags & AS3722_CFG_BIAS_HIGH_IMPEDANCE ||
396 	    gpio_flags & GPIO_PIN_TRISTATE)
397 		return (AS3722_MODE_TRISTATE);
398 
399 	/* Open drain modes. */
400 	if (flags & AS3722_CFG_OPEN_DRAIN || gpio_flags & GPIO_PIN_OPENDRAIN) {
401 		/* Only pull up have effect */
402 		if (flags & AS3722_CFG_BIAS_PULL_UP ||
403 		    gpio_flags & GPIO_PIN_PULLUP)
404 			return (AS3722_MODE_OPEN_DRAIN_LV);
405 		return (AS3722_MODE_OPEN_DRAIN);
406 	}
407 	/* Input modes. */
408 	if (gpio_flags & GPIO_PIN_INPUT) {
409 		/* Accept pull up or pull down. */
410 		if (flags & AS3722_CFG_BIAS_PULL_UP ||
411 		    gpio_flags & GPIO_PIN_PULLUP)
412 			return (AS3722_MODE_INPUT_PULL_UP_LV);
413 
414 		if (flags & AS3722_CFG_BIAS_PULL_DOWN ||
415 		    gpio_flags & GPIO_PIN_PULLDOWN)
416 			return (AS3722_MODE_INPUT_PULL_DOWN);
417 		return (AS3722_MODE_INPUT);
418 	}
419 	/*
420 	 * Output modes.
421 	 * Pull down is used as indicator of low voltage output.
422 	 */
423 	if (flags & AS3722_CFG_BIAS_PULL_DOWN ||
424 		    gpio_flags & GPIO_PIN_PULLDOWN)
425 		return (AS3722_MODE_PUSH_PULL_LV);
426 	return (AS3722_MODE_PUSH_PULL);
427 }
428 
429 int
430 as3722_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
431 {
432 	struct as3722_softc *sc;
433 	uint8_t ctrl, mode, iosf;
434 	int rv;
435 
436 	sc = device_get_softc(dev);
437 	if (pin >= sc->gpio_npins)
438 		return (EINVAL);
439 
440 	GPIO_LOCK(sc);
441 	ctrl = sc->gpio_pins[pin]->pin_ctrl_reg;
442 	iosf = (ctrl >> AS3722_GPIO_IOSF_SHIFT) & AS3722_GPIO_IOSF_MASK;
443 	/* Is pin in GPIO mode ? */
444 	if (iosf != AS3722_IOSF_GPIO) {
445 		GPIO_UNLOCK(sc);
446 		return (ENXIO);
447 	}
448 	mode = as3722_gpio_get_mode(sc, pin, flags);
449 	ctrl &= ~(AS3722_GPIO_MODE_MASK << AS3722_GPIO_MODE_SHIFT);
450 	ctrl |= AS3722_MODE_PUSH_PULL << AS3722_GPIO_MODE_SHIFT;
451 	rv = 0;
452 	if (ctrl != sc->gpio_pins[pin]->pin_ctrl_reg) {
453 		rv = WR1(sc, AS3722_GPIO0_CONTROL + pin, ctrl);
454 		sc->gpio_pins[pin]->pin_ctrl_reg = ctrl;
455 	}
456 	GPIO_UNLOCK(sc);
457 	return (rv);
458 }
459 
460 int
461 as3722_gpio_pin_set(device_t dev, uint32_t pin, uint32_t val)
462 {
463 	struct as3722_softc *sc;
464 	uint8_t tmp;
465 	int rv;
466 
467 	sc = device_get_softc(dev);
468 	if (pin >= sc->gpio_npins)
469 		return (EINVAL);
470 
471 	tmp =  (val != 0) ? 1 : 0;
472 	if (sc->gpio_pins[pin]->pin_ctrl_reg & AS3722_GPIO_INVERT)
473 		tmp ^= 1;
474 
475 	GPIO_LOCK(sc);
476 	rv = RM1(sc, AS3722_GPIO_SIGNAL_OUT, (1 << pin), (tmp << pin));
477 	GPIO_UNLOCK(sc);
478 	return (rv);
479 }
480 
481 int
482 as3722_gpio_pin_get(device_t dev, uint32_t pin, uint32_t *val)
483 {
484 	struct as3722_softc *sc;
485 	uint8_t tmp, mode, ctrl;
486 	int rv;
487 
488 	sc = device_get_softc(dev);
489 	if (pin >= sc->gpio_npins)
490 		return (EINVAL);
491 
492 	GPIO_LOCK(sc);
493 	ctrl = sc->gpio_pins[pin]->pin_ctrl_reg;
494 	mode = (ctrl >> AS3722_GPIO_MODE_SHIFT) & AS3722_GPIO_MODE_MASK;
495 	if ((mode == AS3722_MODE_PUSH_PULL) ||
496 	    (mode == AS3722_MODE_PUSH_PULL_LV))
497 		rv = RD1(sc, AS3722_GPIO_SIGNAL_OUT, &tmp);
498 	else
499 		rv = RD1(sc, AS3722_GPIO_SIGNAL_IN, &tmp);
500 	GPIO_UNLOCK(sc);
501 	if (rv != 0)
502 		return (rv);
503 
504 	*val = tmp & (1 << pin) ? 1 : 0;
505 	if (ctrl & AS3722_GPIO_INVERT)
506 		*val ^= 1;
507 	return (0);
508 }
509 
510 int
511 as3722_gpio_pin_toggle(device_t dev, uint32_t pin)
512 {
513 	struct as3722_softc *sc;
514 	uint8_t tmp;
515 	int rv;
516 
517 	sc = device_get_softc(dev);
518 	if (pin >= sc->gpio_npins)
519 		return (EINVAL);
520 
521 	GPIO_LOCK(sc);
522 	rv = RD1(sc, AS3722_GPIO_SIGNAL_OUT, &tmp);
523 	if (rv != 0) {
524 		GPIO_UNLOCK(sc);
525 		return (rv);
526 	}
527 	tmp ^= (1 <<pin);
528 	rv = RM1(sc, AS3722_GPIO_SIGNAL_OUT, (1 << pin), tmp);
529 	GPIO_UNLOCK(sc);
530 	return (0);
531 }
532 
533 int
534 as3722_gpio_map_gpios(device_t dev, phandle_t pdev, phandle_t gparent,
535     int gcells, pcell_t *gpios, uint32_t *pin, uint32_t *flags)
536 {
537 
538 	if (gcells != 2)
539 		return (ERANGE);
540 	*pin = gpios[0];
541 	*flags= gpios[1];
542 	return (0);
543 }
544 
545 int
546 as3722_gpio_attach(struct as3722_softc *sc, phandle_t node)
547 {
548 	struct as3722_gpio_pin *pin;
549 	int i, rv;
550 
551 	sx_init(&sc->gpio_lock, "AS3722 GPIO lock");
552 	sc->gpio_npins = NGPIO;
553 	sc->gpio_pins = malloc(sizeof(struct as3722_gpio_pin *) *
554 	    sc->gpio_npins, M_AS3722_GPIO, M_WAITOK | M_ZERO);
555 
556 
557 	sc->gpio_busdev = gpiobus_attach_bus(sc->dev);
558 	if (sc->gpio_busdev == NULL)
559 		return (ENXIO);
560 	for (i = 0; i < sc->gpio_npins; i++) {
561 		sc->gpio_pins[i] = malloc(sizeof(struct as3722_gpio_pin),
562 		    M_AS3722_GPIO, M_WAITOK | M_ZERO);
563 		pin = sc->gpio_pins[i];
564 		sprintf(pin->pin_name, "gpio%d", i);
565 		pin->pin_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT  |
566 		    GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL | GPIO_PIN_TRISTATE |
567 		    GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN | GPIO_PIN_INVIN |
568 		    GPIO_PIN_INVOUT;
569 		rv = RD1(sc, AS3722_GPIO0_CONTROL + i, &pin->pin_ctrl_reg);
570 		if (rv != 0) {
571 			device_printf(sc->dev,
572 			    "Cannot read configuration for pin %s\n",
573 			    sc->gpio_pins[i]->pin_name);
574 		}
575 	}
576 	return (0);
577 }
578