]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/nvidia/as3722_gpio.c
zfs: merge openzfs/zfs@95f71c019
[FreeBSD/FreeBSD.git] / sys / arm / nvidia / as3722_gpio.c
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 }