1*c7fb772bSthorpej /* $NetBSD: augpio.c,v 1.10 2021/08/07 16:18:58 thorpej Exp $ */
21388c544Sgdamore
31388c544Sgdamore /*-
41388c544Sgdamore * Copyright (c) 2006 Itronix Inc.
51388c544Sgdamore * All rights reserved.
61388c544Sgdamore *
71388c544Sgdamore * Written by Garrett D'Amore for Itronix Inc.
81388c544Sgdamore *
91388c544Sgdamore * Redistribution and use in source and binary forms, with or without
101388c544Sgdamore * modification, are permitted provided that the following conditions
111388c544Sgdamore * are met:
121388c544Sgdamore * 1. Redistributions of source code must retain the above copyright
131388c544Sgdamore * notice, this list of conditions and the following disclaimer.
141388c544Sgdamore * 2. Redistributions in binary form must reproduce the above copyright
151388c544Sgdamore * notice, this list of conditions and the following disclaimer in the
161388c544Sgdamore * documentation and/or other materials provided with the distribution.
171388c544Sgdamore * 3. The name of Itronix Inc. may not be used to endorse
181388c544Sgdamore * or promote products derived from this software without specific
191388c544Sgdamore * prior written permission.
201388c544Sgdamore *
211388c544Sgdamore * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
221388c544Sgdamore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
231388c544Sgdamore * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
241388c544Sgdamore * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
251388c544Sgdamore * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
261388c544Sgdamore * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
271388c544Sgdamore * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
281388c544Sgdamore * ON ANY THEORY OF LIABILITY, WHETHER IN
291388c544Sgdamore * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
301388c544Sgdamore * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
311388c544Sgdamore * POSSIBILITY OF SUCH DAMAGE.
321388c544Sgdamore */
331388c544Sgdamore
341388c544Sgdamore #include <sys/cdefs.h>
35*c7fb772bSthorpej __KERNEL_RCSID(0, "$NetBSD: augpio.c,v 1.10 2021/08/07 16:18:58 thorpej Exp $");
361388c544Sgdamore
371388c544Sgdamore #include <sys/types.h>
381388c544Sgdamore #include <sys/param.h>
391388c544Sgdamore #include <sys/systm.h>
401388c544Sgdamore #include <sys/errno.h>
411388c544Sgdamore #include <sys/device.h>
421388c544Sgdamore #include <sys/gpio.h>
431388c544Sgdamore #include <sys/kernel.h>
44914f086dSmatt #include <sys/bus.h>
451388c544Sgdamore
461388c544Sgdamore #include <dev/gpio/gpiovar.h>
471388c544Sgdamore
48914f086dSmatt #include <mips/locore.h>
491388c544Sgdamore
501388c544Sgdamore #include <mips/alchemy/include/aubusvar.h>
511388c544Sgdamore #include <mips/alchemy/include/aureg.h>
521388c544Sgdamore #include <mips/alchemy/dev/augpioreg.h>
535cd61be0Sgdamore #include <mips/alchemy/dev/augpiovar.h>
541388c544Sgdamore
551388c544Sgdamore struct augpio_softc {
56f58fcf6aSkiyohara device_t sc_dev;
571388c544Sgdamore struct gpio_chipset_tag sc_gc;
581388c544Sgdamore gpio_pin_t sc_pins[AUGPIO_NPINS];
591388c544Sgdamore int sc_npins;
6026ef9b6bSgdamore bus_space_tag_t sc_bst;
6126ef9b6bSgdamore int sc_caps;
6226ef9b6bSgdamore const char *sc_name;
6326ef9b6bSgdamore int (*sc_getctl)(void *, int);
641388c544Sgdamore };
651388c544Sgdamore
66f58fcf6aSkiyohara static int augpio_match(device_t, struct cfdata *, void *);
67f58fcf6aSkiyohara static void augpio_attach(device_t, device_t, void *);
681388c544Sgdamore
69f58fcf6aSkiyohara CFATTACH_DECL_NEW(augpio, sizeof(struct augpio_softc),
701388c544Sgdamore augpio_match, augpio_attach, NULL, NULL);
711388c544Sgdamore
721388c544Sgdamore #define GETREG(x) \
731388c544Sgdamore (*(volatile uint32_t *)MIPS_PHYS_TO_KSEG1(x))
741388c544Sgdamore #define PUTREG(x, v) \
751388c544Sgdamore ((*(volatile uint32_t *)MIPS_PHYS_TO_KSEG1(x)) = (v))
761388c544Sgdamore
775cd61be0Sgdamore #define GETGPIO(x) GETREG(GPIO_BASE + (x))
785cd61be0Sgdamore #define PUTGPIO(x,v) PUTREG(GPIO_BASE + (x), (v))
795cd61be0Sgdamore #define GETGPIO2(x) GETREG(GPIO2_BASE + (x))
805cd61be0Sgdamore #define PUTGPIO2(x,v) PUTREG(GPIO2_BASE + (x), (v))
815cd61be0Sgdamore
821388c544Sgdamore int
augpio_match(device_t parent,struct cfdata * match,void * aux)83f58fcf6aSkiyohara augpio_match(device_t parent, struct cfdata *match, void *aux)
841388c544Sgdamore {
851388c544Sgdamore struct aubus_attach_args *aa = (struct aubus_attach_args *)aux;
861388c544Sgdamore
871388c544Sgdamore if (strcmp(aa->aa_name, "augpio") != 0)
881388c544Sgdamore return 0;
891388c544Sgdamore
901388c544Sgdamore return 1;
911388c544Sgdamore }
921388c544Sgdamore
931388c544Sgdamore void
augpio_attach(device_t parent,device_t self,void * aux)94f58fcf6aSkiyohara augpio_attach(device_t parent, device_t self, void *aux)
951388c544Sgdamore {
961388c544Sgdamore int pin;
971388c544Sgdamore
98f58fcf6aSkiyohara struct augpio_softc *sc = device_private(self);
991388c544Sgdamore struct aubus_attach_args *aa = aux;
1001388c544Sgdamore struct gpiobus_attach_args gba;
1011388c544Sgdamore
102f58fcf6aSkiyohara sc->sc_dev = self;
10326ef9b6bSgdamore sc->sc_bst = aa->aa_st;
10426ef9b6bSgdamore sc->sc_npins = aa->aa_addrs[1];
10526ef9b6bSgdamore sc->sc_gc.gp_cookie = sc;
1061388c544Sgdamore
10726ef9b6bSgdamore if (aa->aa_addrs[0] == GPIO_BASE) {
1087d9a6498Sgdamore
10926ef9b6bSgdamore sc->sc_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT |
11026ef9b6bSgdamore GPIO_PIN_TRISTATE;
11126ef9b6bSgdamore sc->sc_gc.gp_pin_read = augpio_read;
11226ef9b6bSgdamore sc->sc_gc.gp_pin_write = augpio_write;
11326ef9b6bSgdamore sc->sc_gc.gp_pin_ctl = augpio_ctl;
11426ef9b6bSgdamore sc->sc_getctl = augpio_getctl;
11526ef9b6bSgdamore sc->sc_name = "primary block";
1161388c544Sgdamore
1171388c544Sgdamore } else if (aa->aa_addrs[0] == GPIO2_BASE) {
1187d9a6498Sgdamore /*
1197d9a6498Sgdamore * We rely on firmware (or platform init code) to initialize
1207d9a6498Sgdamore * the GPIO2 block. We can't do it ourselves, because
1217d9a6498Sgdamore * resetting the GPIO2 block can have nasty effects (e.g.
1227d9a6498Sgdamore * reset PCI bus...)
1237d9a6498Sgdamore */
12426ef9b6bSgdamore sc->sc_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
12526ef9b6bSgdamore sc->sc_gc.gp_pin_read = augpio2_read;
12626ef9b6bSgdamore sc->sc_gc.gp_pin_write = augpio2_write;
12726ef9b6bSgdamore sc->sc_gc.gp_pin_ctl = augpio2_ctl;
12826ef9b6bSgdamore sc->sc_getctl = augpio2_getctl;
12926ef9b6bSgdamore sc->sc_name = "secondary block";
1301388c544Sgdamore
1311388c544Sgdamore } else {
132f58fcf6aSkiyohara aprint_error(": unidentified block\n");
13326ef9b6bSgdamore return;
1341388c544Sgdamore }
1351388c544Sgdamore
13626ef9b6bSgdamore for (pin = 0; pin < sc->sc_npins; pin++) {
13726ef9b6bSgdamore gpio_pin_t *pp = &sc->sc_pins[pin];
13826ef9b6bSgdamore
13926ef9b6bSgdamore pp->pin_num = pin;
14026ef9b6bSgdamore pp->pin_caps = sc->sc_caps;
14126ef9b6bSgdamore pp->pin_flags = sc->sc_getctl(sc, pin);
14226ef9b6bSgdamore pp->pin_state = sc->sc_gc.gp_pin_read(sc, pin);
14326ef9b6bSgdamore }
1441388c544Sgdamore
1451388c544Sgdamore gba.gba_gc = &sc->sc_gc;
1461388c544Sgdamore gba.gba_pins = sc->sc_pins;
1471388c544Sgdamore gba.gba_npins = sc->sc_npins;
1481388c544Sgdamore
149f58fcf6aSkiyohara aprint_normal(": Alchemy GPIO, %s\n", sc->sc_name);
150f58fcf6aSkiyohara aprint_naive("\n");
151*c7fb772bSthorpej config_found(self, &gba, gpiobus_print, CFARGS_NONE);
1521388c544Sgdamore }
1531388c544Sgdamore
1541388c544Sgdamore int
augpio_read(void * arg,int pin)15526ef9b6bSgdamore augpio_read(void *arg, int pin)
1561388c544Sgdamore {
1571388c544Sgdamore
15826ef9b6bSgdamore pin = 1 << pin;
1591388c544Sgdamore
1605cd61be0Sgdamore if (GETGPIO(AUGPIO_PINSTATERD) & pin)
16126ef9b6bSgdamore return GPIO_PIN_HIGH;
1621388c544Sgdamore else
16326ef9b6bSgdamore return GPIO_PIN_LOW;
1641388c544Sgdamore }
1651388c544Sgdamore
1661388c544Sgdamore void
augpio_write(void * arg,int pin,int value)16726ef9b6bSgdamore augpio_write(void *arg, int pin, int value)
1681388c544Sgdamore {
1691388c544Sgdamore
1701388c544Sgdamore pin = 1 << pin;
1715cd61be0Sgdamore PUTGPIO(value ? AUGPIO_OUTPUTSET : AUGPIO_OUTPUTCLR, pin);
1721388c544Sgdamore }
1731388c544Sgdamore
1741388c544Sgdamore void
augpio_ctl(void * arg,int pin,int flags)17526ef9b6bSgdamore augpio_ctl(void *arg, int pin, int flags)
1761388c544Sgdamore {
17726ef9b6bSgdamore bus_addr_t reg;
1781388c544Sgdamore
1791388c544Sgdamore pin = 1 << pin;
1801388c544Sgdamore
1811388c544Sgdamore if (flags & (GPIO_PIN_TRISTATE|GPIO_PIN_INPUT)) {
18226ef9b6bSgdamore reg = AUGPIO_TRIOUTCLR;
1831388c544Sgdamore } else if (flags & GPIO_PIN_OUTPUT) {
18426ef9b6bSgdamore uint32_t out;
1855cd61be0Sgdamore out = GETGPIO(AUGPIO_OUTPUTRD);
18626ef9b6bSgdamore reg = pin & out ? AUGPIO_OUTPUTSET : AUGPIO_OUTPUTCLR;
1871388c544Sgdamore } else {
18826ef9b6bSgdamore return;
1891388c544Sgdamore }
1901388c544Sgdamore
1915cd61be0Sgdamore PUTGPIO(reg, pin);
1921388c544Sgdamore }
1931388c544Sgdamore
1941388c544Sgdamore int
augpio_getctl(void * arg,int pin)19526ef9b6bSgdamore augpio_getctl(void *arg, int pin)
1961388c544Sgdamore {
19726ef9b6bSgdamore
1985cd61be0Sgdamore if (GETGPIO(AUGPIO_TRIOUTRD) & pin)
19926ef9b6bSgdamore return GPIO_PIN_OUTPUT;
20026ef9b6bSgdamore else
20126ef9b6bSgdamore return GPIO_PIN_INPUT;
20226ef9b6bSgdamore }
20326ef9b6bSgdamore
20426ef9b6bSgdamore int
augpio2_read(void * arg,int pin)20526ef9b6bSgdamore augpio2_read(void *arg, int pin)
20626ef9b6bSgdamore {
2071388c544Sgdamore
2081388c544Sgdamore pin = 1 << pin;
2091388c544Sgdamore
2105cd61be0Sgdamore if (GETGPIO2(AUGPIO2_PINSTATE) & pin)
21126ef9b6bSgdamore return GPIO_PIN_HIGH;
21226ef9b6bSgdamore else
21326ef9b6bSgdamore return GPIO_PIN_LOW;
2141388c544Sgdamore }
2151388c544Sgdamore
2161388c544Sgdamore void
augpio2_write(void * arg,int pin,int value)21726ef9b6bSgdamore augpio2_write(void *arg, int pin, int value)
2181388c544Sgdamore {
2191388c544Sgdamore
2201388c544Sgdamore pin = 1 << pin;
2211388c544Sgdamore
2221388c544Sgdamore if (value) {
22326ef9b6bSgdamore pin = pin | (pin << 16);
2241388c544Sgdamore } else {
22526ef9b6bSgdamore pin = (pin << 16);
2261388c544Sgdamore }
2271388c544Sgdamore
2285cd61be0Sgdamore PUTGPIO2(AUGPIO2_OUTPUT, pin);
22926ef9b6bSgdamore }
23026ef9b6bSgdamore
23126ef9b6bSgdamore void
augpio2_ctl(void * arg,int pin,int flags)23226ef9b6bSgdamore augpio2_ctl(void *arg, int pin, int flags)
2331388c544Sgdamore {
2341388c544Sgdamore uint32_t dir;
2351388c544Sgdamore
2361388c544Sgdamore pin = 1 << pin;
2371388c544Sgdamore
2385cd61be0Sgdamore dir = GETGPIO2(AUGPIO2_DIR);
2391388c544Sgdamore
2401388c544Sgdamore if (flags & GPIO_PIN_INPUT) {
2411388c544Sgdamore dir |= pin;
2421388c544Sgdamore } else if (flags & GPIO_PIN_OUTPUT) {
2431388c544Sgdamore dir &= ~pin;
24426ef9b6bSgdamore }
2455cd61be0Sgdamore PUTGPIO2(AUGPIO2_DIR, dir);
2461388c544Sgdamore }
2471388c544Sgdamore
24826ef9b6bSgdamore int
augpio2_getctl(void * arg,int pin)24926ef9b6bSgdamore augpio2_getctl(void *arg, int pin)
25026ef9b6bSgdamore {
25126ef9b6bSgdamore uint32_t dir;
25226ef9b6bSgdamore
25326ef9b6bSgdamore pin = 1 << pin;
25426ef9b6bSgdamore
2555cd61be0Sgdamore dir = GETGPIO2(AUGPIO2_DIR);
25626ef9b6bSgdamore if (dir & (uint32_t)pin) {
25726ef9b6bSgdamore return GPIO_PIN_OUTPUT;
25826ef9b6bSgdamore } else {
25926ef9b6bSgdamore return GPIO_PIN_INPUT;
2601388c544Sgdamore }
26126ef9b6bSgdamore }
26226ef9b6bSgdamore
263