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