1 /*-
2 * Copyright (c) 2016 Michal Meloun <[email protected]>
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
as3722_pinmux_get_function(struct as3722_softc * sc,char * name)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
as3722_pinmux_config_node(struct as3722_softc * sc,char * pin_name,struct as3722_pincfg * cfg)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
as3722_pinmux_read_node(struct as3722_softc * sc,phandle_t node,struct as3722_pincfg * cfg,char ** pins,int * lpins)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
as3722_pinmux_process_node(struct as3722_softc * sc,phandle_t node)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
as3722_pinmux_configure(device_t dev,phandle_t cfgxref)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
as3722_gpio_get_bus(device_t dev)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
as3722_gpio_pin_max(device_t dev,int * maxpin)292 as3722_gpio_pin_max(device_t dev, int *maxpin)
293 {
294
295 *maxpin = NGPIO - 1;
296 return (0);
297 }
298
299 int
as3722_gpio_pin_getcaps(device_t dev,uint32_t pin,uint32_t * caps)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
as3722_gpio_pin_getname(device_t dev,uint32_t pin,char * name)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
as3722_gpio_pin_getflags(device_t dev,uint32_t pin,uint32_t * out_flags)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
as3722_gpio_get_mode(struct as3722_softc * sc,uint32_t pin,uint32_t gpio_flags)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
as3722_gpio_pin_setflags(device_t dev,uint32_t pin,uint32_t flags)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
as3722_gpio_pin_set(device_t dev,uint32_t pin,uint32_t val)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
as3722_gpio_pin_get(device_t dev,uint32_t pin,uint32_t * val)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
as3722_gpio_pin_toggle(device_t dev,uint32_t pin)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
as3722_gpio_map_gpios(device_t dev,phandle_t pdev,phandle_t gparent,int gcells,pcell_t * gpios,uint32_t * pin,uint32_t * flags)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
as3722_gpio_attach(struct as3722_softc * sc,phandle_t node)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