xref: /netbsd-src/sys/arch/evbppc/wii/dev/hwgpio.c (revision 297a048c7058ddeb18e8f319a3ae433c18738b5e)
1*297a048cSjmcneill /* $NetBSD: hwgpio.c,v 1.1 2024/01/23 21:48:12 jmcneill Exp $ */
2*297a048cSjmcneill 
3*297a048cSjmcneill /*-
4*297a048cSjmcneill  * Copyright (c) 2024 Jared McNeill <jmcneill@invisible.ca>
5*297a048cSjmcneill  * All rights reserved.
6*297a048cSjmcneill  *
7*297a048cSjmcneill  * Redistribution and use in source and binary forms, with or without
8*297a048cSjmcneill  * modification, are permitted provided that the following conditions
9*297a048cSjmcneill  * are met:
10*297a048cSjmcneill  * 1. Redistributions of source code must retain the above copyright
11*297a048cSjmcneill  *    notice, this list of conditions and the following disclaimer.
12*297a048cSjmcneill  * 2. Redistributions in binary form must reproduce the above copyright
13*297a048cSjmcneill  *    notice, this list of conditions and the following disclaimer in the
14*297a048cSjmcneill  *    documentation and/or other materials provided with the distribution.
15*297a048cSjmcneill  *
16*297a048cSjmcneill  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17*297a048cSjmcneill  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18*297a048cSjmcneill  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19*297a048cSjmcneill  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20*297a048cSjmcneill  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21*297a048cSjmcneill  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22*297a048cSjmcneill  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23*297a048cSjmcneill  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24*297a048cSjmcneill  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*297a048cSjmcneill  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*297a048cSjmcneill  * SUCH DAMAGE.
27*297a048cSjmcneill  */
28*297a048cSjmcneill 
29*297a048cSjmcneill #include <sys/cdefs.h>
30*297a048cSjmcneill __KERNEL_RCSID(0, "$NetBSD: hwgpio.c,v 1.1 2024/01/23 21:48:12 jmcneill Exp $");
31*297a048cSjmcneill 
32*297a048cSjmcneill #include <sys/param.h>
33*297a048cSjmcneill #include <sys/bus.h>
34*297a048cSjmcneill #include <sys/cpu.h>
35*297a048cSjmcneill #include <sys/device.h>
36*297a048cSjmcneill #include <sys/kmem.h>
37*297a048cSjmcneill #include <sys/bitops.h>
38*297a048cSjmcneill #include <sys/gpio.h>
39*297a048cSjmcneill 
40*297a048cSjmcneill #include <dev/gpio/gpiovar.h>
41*297a048cSjmcneill 
42*297a048cSjmcneill #include <machine/wii.h>
43*297a048cSjmcneill 
44*297a048cSjmcneill #include "hollywood.h"
45*297a048cSjmcneill 
46*297a048cSjmcneill #define PIN(_num, _name, _caps)		\
47*297a048cSjmcneill 	{ .pin_num = (_num), 		\
48*297a048cSjmcneill 	  .pin_caps = (_caps),		\
49*297a048cSjmcneill 	  .pin_defname = (_name),	\
50*297a048cSjmcneill 	}
51*297a048cSjmcneill static gpio_pin_t hwgpio_pins[] = {
52*297a048cSjmcneill 	PIN( 0, "POWER",	GPIO_PIN_INPUT),
53*297a048cSjmcneill 	PIN( 1, "SHUTDOWN",	GPIO_PIN_OUTPUT),
54*297a048cSjmcneill 	PIN( 2, "FAN",		GPIO_PIN_OUTPUT),
55*297a048cSjmcneill 	PIN( 3, "DC_DC",	GPIO_PIN_OUTPUT),
56*297a048cSjmcneill 	PIN( 4, "DI_SPIN",	GPIO_PIN_OUTPUT),
57*297a048cSjmcneill 	PIN( 5, "SLOT_LED",	GPIO_PIN_OUTPUT),
58*297a048cSjmcneill 	PIN( 6, "EJECT_BTN",	GPIO_PIN_INPUT),
59*297a048cSjmcneill 	PIN( 7, "SLOT_IN",	GPIO_PIN_INPUT),
60*297a048cSjmcneill 	PIN( 8, "SENSOR_BAR",	GPIO_PIN_OUTPUT),
61*297a048cSjmcneill 	PIN( 9, "DO_EJECT",	GPIO_PIN_OUTPUT),
62*297a048cSjmcneill 	PIN(10, "EEP_CS",	GPIO_PIN_OUTPUT),
63*297a048cSjmcneill 	PIN(11, "EEP_CLK",	GPIO_PIN_OUTPUT),
64*297a048cSjmcneill 	PIN(12, "EEP_MOSI",	GPIO_PIN_OUTPUT),
65*297a048cSjmcneill 	PIN(13, "EEP_MISO",	GPIO_PIN_INPUT),
66*297a048cSjmcneill 	PIN(14, "AVE_SCL",	GPIO_PIN_OUTPUT),
67*297a048cSjmcneill 	PIN(15, "AVE_SDA",	GPIO_PIN_INPUT | GPIO_PIN_OUTPUT),
68*297a048cSjmcneill 	PIN(16, "DEBUG0",	GPIO_PIN_INPUT | GPIO_PIN_OUTPUT),
69*297a048cSjmcneill 	PIN(17, "DEBUG1",	GPIO_PIN_INPUT | GPIO_PIN_OUTPUT),
70*297a048cSjmcneill 	PIN(18, "DEBUG2",	GPIO_PIN_INPUT | GPIO_PIN_OUTPUT),
71*297a048cSjmcneill 	PIN(19, "DEBUG3",	GPIO_PIN_INPUT | GPIO_PIN_OUTPUT),
72*297a048cSjmcneill 	PIN(20, "DEBUG4",	GPIO_PIN_INPUT | GPIO_PIN_OUTPUT),
73*297a048cSjmcneill 	PIN(21, "DEBUG5",	GPIO_PIN_INPUT | GPIO_PIN_OUTPUT),
74*297a048cSjmcneill 	PIN(22, "DEBUG6",	GPIO_PIN_INPUT | GPIO_PIN_OUTPUT),
75*297a048cSjmcneill 	PIN(23, "DEBUG7",	GPIO_PIN_INPUT | GPIO_PIN_OUTPUT),
76*297a048cSjmcneill };
77*297a048cSjmcneill #undef PIN
78*297a048cSjmcneill 
79*297a048cSjmcneill struct hwgpio_softc {
80*297a048cSjmcneill 	struct gpio_chipset_tag	sc_gp;
81*297a048cSjmcneill };
82*297a048cSjmcneill 
83*297a048cSjmcneill #define	RD4(reg)		in32(reg)
84*297a048cSjmcneill #define	WR4(reg, val)		out32((reg), (val))
85*297a048cSjmcneill 
86*297a048cSjmcneill static int
hwgpio_pin_read(void * priv,int pin)87*297a048cSjmcneill hwgpio_pin_read(void *priv, int pin)
88*297a048cSjmcneill {
89*297a048cSjmcneill 	return (RD4(HW_GPIOB_IN) & __BIT(pin)) != 0;
90*297a048cSjmcneill }
91*297a048cSjmcneill 
92*297a048cSjmcneill static void
hwgpio_pin_write(void * priv,int pin,int value)93*297a048cSjmcneill hwgpio_pin_write(void *priv, int pin, int value)
94*297a048cSjmcneill {
95*297a048cSjmcneill 	uint32_t out;
96*297a048cSjmcneill 	int s;
97*297a048cSjmcneill 
98*297a048cSjmcneill 	s = splhigh();
99*297a048cSjmcneill 	out = RD4(HW_GPIOB_OUT);
100*297a048cSjmcneill 	if (value) {
101*297a048cSjmcneill 		out |= __BIT(pin);
102*297a048cSjmcneill 	} else {
103*297a048cSjmcneill 		out &= ~__BIT(pin);
104*297a048cSjmcneill 	}
105*297a048cSjmcneill 	WR4(HW_GPIOB_OUT, out);
106*297a048cSjmcneill 	splx(s);
107*297a048cSjmcneill }
108*297a048cSjmcneill 
109*297a048cSjmcneill static void
hwgpio_pin_ctl(void * priv,int pin,int flags)110*297a048cSjmcneill hwgpio_pin_ctl(void *priv, int pin, int flags)
111*297a048cSjmcneill {
112*297a048cSjmcneill 	uint32_t dir;
113*297a048cSjmcneill 	int s;
114*297a048cSjmcneill 
115*297a048cSjmcneill 	s = splhigh();
116*297a048cSjmcneill 	dir = RD4(HW_GPIOB_DIR);
117*297a048cSjmcneill 	if (flags & GPIO_PIN_OUTPUT) {
118*297a048cSjmcneill 		dir |= __BIT(pin);
119*297a048cSjmcneill 	} else {
120*297a048cSjmcneill 		dir &= ~__BIT(pin);
121*297a048cSjmcneill 	}
122*297a048cSjmcneill 	WR4(HW_GPIOB_DIR, dir);
123*297a048cSjmcneill 	splx(s);
124*297a048cSjmcneill }
125*297a048cSjmcneill 
126*297a048cSjmcneill static int
hwgpio_match(device_t parent,cfdata_t cf,void * aux)127*297a048cSjmcneill hwgpio_match(device_t parent, cfdata_t cf, void *aux)
128*297a048cSjmcneill {
129*297a048cSjmcneill 	return 1;
130*297a048cSjmcneill }
131*297a048cSjmcneill 
132*297a048cSjmcneill static void
hwgpio_attach(device_t parent,device_t self,void * aux)133*297a048cSjmcneill hwgpio_attach(device_t parent, device_t self, void *aux)
134*297a048cSjmcneill {
135*297a048cSjmcneill 	struct hwgpio_softc * const sc = device_private(self);
136*297a048cSjmcneill 	struct gpio_chipset_tag *gp = &sc->sc_gp;
137*297a048cSjmcneill 	struct gpiobus_attach_args gba = {};
138*297a048cSjmcneill 	uint32_t in, out, dir;
139*297a048cSjmcneill 	u_int n;
140*297a048cSjmcneill 
141*297a048cSjmcneill 	gp->gp_cookie = sc;
142*297a048cSjmcneill 	gp->gp_pin_read = hwgpio_pin_read;
143*297a048cSjmcneill 	gp->gp_pin_write = hwgpio_pin_write;
144*297a048cSjmcneill 	gp->gp_pin_ctl = hwgpio_pin_ctl;
145*297a048cSjmcneill 
146*297a048cSjmcneill 	aprint_naive("\n");
147*297a048cSjmcneill 	aprint_normal(": GPIO\n");
148*297a048cSjmcneill 
149*297a048cSjmcneill 	in = RD4(HW_GPIOB_IN);
150*297a048cSjmcneill 	out = RD4(HW_GPIOB_OUT);
151*297a048cSjmcneill 	dir = RD4(HW_GPIOB_DIR);
152*297a048cSjmcneill 	for (n = 0; n < __arraycount(hwgpio_pins); n++) {
153*297a048cSjmcneill 		const uint32_t mask = __BIT(hwgpio_pins[n].pin_num);
154*297a048cSjmcneill 		if (dir & mask) {
155*297a048cSjmcneill 			hwgpio_pins[n].pin_state = (out & mask) != 0;
156*297a048cSjmcneill 		} else {
157*297a048cSjmcneill 			hwgpio_pins[n].pin_state = (in & mask) != 0;
158*297a048cSjmcneill 		}
159*297a048cSjmcneill 	}
160*297a048cSjmcneill 
161*297a048cSjmcneill 	gba.gba_gc = &sc->sc_gp;
162*297a048cSjmcneill 	gba.gba_pins = hwgpio_pins;
163*297a048cSjmcneill 	gba.gba_npins = __arraycount(hwgpio_pins);
164*297a048cSjmcneill 	config_found(self, &gba, NULL, CFARGS_NONE);
165*297a048cSjmcneill }
166*297a048cSjmcneill 
167*297a048cSjmcneill CFATTACH_DECL_NEW(hwgpio, sizeof(struct hwgpio_softc),
168*297a048cSjmcneill     hwgpio_match, hwgpio_attach, NULL, NULL);
169