xref: /netbsd-src/sys/arch/mips/alchemy/dev/augpio.c (revision c7fb772b85b2b5d4cfb282f868f454b4701534fd)
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