hwgpio.c revision 1.1
11.1Sjmcneill/* $NetBSD: hwgpio.c,v 1.1 2026/01/09 22:54:30 jmcneill Exp $ */
21.1Sjmcneill
31.1Sjmcneill/*-
41.1Sjmcneill * Copyright (c) 2024 Jared McNeill <jmcneill@invisible.ca>
51.1Sjmcneill * All rights reserved.
61.1Sjmcneill *
71.1Sjmcneill * Redistribution and use in source and binary forms, with or without
81.1Sjmcneill * modification, are permitted provided that the following conditions
91.1Sjmcneill * are met:
101.1Sjmcneill * 1. Redistributions of source code must retain the above copyright
111.1Sjmcneill *    notice, this list of conditions and the following disclaimer.
121.1Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright
131.1Sjmcneill *    notice, this list of conditions and the following disclaimer in the
141.1Sjmcneill *    documentation and/or other materials provided with the distribution.
151.1Sjmcneill *
161.1Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
171.1Sjmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
181.1Sjmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
191.1Sjmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
201.1Sjmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
211.1Sjmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
221.1Sjmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
231.1Sjmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
241.1Sjmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
251.1Sjmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
261.1Sjmcneill * SUCH DAMAGE.
271.1Sjmcneill */
281.1Sjmcneill
291.1Sjmcneill#include <sys/cdefs.h>
301.1Sjmcneill__KERNEL_RCSID(0, "$NetBSD: hwgpio.c,v 1.1 2026/01/09 22:54:30 jmcneill Exp $");
311.1Sjmcneill
321.1Sjmcneill#include <sys/param.h>
331.1Sjmcneill#include <sys/bus.h>
341.1Sjmcneill#include <sys/cpu.h>
351.1Sjmcneill#include <sys/device.h>
361.1Sjmcneill#include <sys/kmem.h>
371.1Sjmcneill#include <sys/bitops.h>
381.1Sjmcneill#include <sys/gpio.h>
391.1Sjmcneill#include <sys/mutex.h>
401.1Sjmcneill
411.1Sjmcneill#include <dev/gpio/gpiovar.h>
421.1Sjmcneill
431.1Sjmcneill#include <machine/wii.h>
441.1Sjmcneill#include <machine/wiiu.h>
451.1Sjmcneill
461.1Sjmcneill#define PIN(_num, _name, _caps)		\
471.1Sjmcneill	{ .pin_num = (_num), 		\
481.1Sjmcneill	  .pin_caps = (_caps),		\
491.1Sjmcneill	  .pin_defname = (_name),	\
501.1Sjmcneill	}
511.1Sjmcneillstatic gpio_pin_t hwgpio_pins[] = {
521.1Sjmcneill	PIN( 0, "POWER",	GPIO_PIN_INPUT),
531.1Sjmcneill	PIN( 1, "SHUTDOWN",	GPIO_PIN_OUTPUT),
541.1Sjmcneill	PIN( 2, "FAN",		GPIO_PIN_OUTPUT),
551.1Sjmcneill	PIN( 3, "DC_DC",	GPIO_PIN_OUTPUT),
561.1Sjmcneill	PIN( 4, "DI_SPIN",	GPIO_PIN_OUTPUT),
571.1Sjmcneill	PIN( 5, "SLOT_LED",	GPIO_PIN_OUTPUT),
581.1Sjmcneill	PIN( 6, "EJECT_BTN",	GPIO_PIN_INPUT),
591.1Sjmcneill	PIN( 7, "SLOT_IN",	GPIO_PIN_INPUT),
601.1Sjmcneill	PIN( 8, "SENSOR_BAR",	GPIO_PIN_OUTPUT),
611.1Sjmcneill	PIN( 9, "DO_EJECT",	GPIO_PIN_OUTPUT),
621.1Sjmcneill	PIN(10, "EEP_CS",	GPIO_PIN_OUTPUT),
631.1Sjmcneill	PIN(11, "EEP_CLK",	GPIO_PIN_OUTPUT),
641.1Sjmcneill	PIN(12, "EEP_MOSI",	GPIO_PIN_OUTPUT),
651.1Sjmcneill	PIN(13, "EEP_MISO",	GPIO_PIN_INPUT),
661.1Sjmcneill	PIN(14, "AVE_SCL",	GPIO_PIN_OUTPUT),
671.1Sjmcneill	PIN(15, "AVE_SDA",	GPIO_PIN_INPUT | GPIO_PIN_OUTPUT),
681.1Sjmcneill	PIN(16, "DEBUG0",	GPIO_PIN_INPUT | GPIO_PIN_OUTPUT),
691.1Sjmcneill	PIN(17, "DEBUG1",	GPIO_PIN_INPUT | GPIO_PIN_OUTPUT),
701.1Sjmcneill	PIN(18, "DEBUG2",	GPIO_PIN_INPUT | GPIO_PIN_OUTPUT),
711.1Sjmcneill	PIN(19, "DEBUG3",	GPIO_PIN_INPUT | GPIO_PIN_OUTPUT),
721.1Sjmcneill	PIN(20, "DEBUG4",	GPIO_PIN_INPUT | GPIO_PIN_OUTPUT),
731.1Sjmcneill	PIN(21, "DEBUG5",	GPIO_PIN_INPUT | GPIO_PIN_OUTPUT),
741.1Sjmcneill	PIN(22, "DEBUG6",	GPIO_PIN_INPUT | GPIO_PIN_OUTPUT),
751.1Sjmcneill	PIN(23, "DEBUG7",	GPIO_PIN_INPUT | GPIO_PIN_OUTPUT),
761.1Sjmcneill};
771.1Sjmcneill#undef PIN
781.1Sjmcneill
791.1Sjmcneillstruct hwgpio_softc {
801.1Sjmcneill	struct gpio_chipset_tag	sc_gp;
811.1Sjmcneill	kmutex_t sc_lock;
821.1Sjmcneill};
831.1Sjmcneill
841.1Sjmcneill#define	RD4(reg)		in32(reg)
851.1Sjmcneill#define	WR4(reg, val)		out32((reg), (val))
861.1Sjmcneill
871.1Sjmcneillstatic int
881.1Sjmcneillhwgpio_pin_read(void *priv, int pin)
891.1Sjmcneill{
901.1Sjmcneill	return (RD4(HW_GPIOB_IN) & __BIT(pin)) != 0;
911.1Sjmcneill}
921.1Sjmcneill
931.1Sjmcneillstatic void
941.1Sjmcneillhwgpio_pin_write(void *priv, int pin, int value)
951.1Sjmcneill{
961.1Sjmcneill	struct hwgpio_softc * const sc = priv;
971.1Sjmcneill	uint32_t out;
981.1Sjmcneill
991.1Sjmcneill	mutex_enter(&sc->sc_lock);
1001.1Sjmcneill	out = RD4(HW_GPIOB_OUT);
1011.1Sjmcneill	if (value) {
1021.1Sjmcneill		out |= __BIT(pin);
1031.1Sjmcneill	} else {
1041.1Sjmcneill		out &= ~__BIT(pin);
1051.1Sjmcneill	}
1061.1Sjmcneill	WR4(HW_GPIOB_OUT, out);
1071.1Sjmcneill	mutex_exit(&sc->sc_lock);
1081.1Sjmcneill}
1091.1Sjmcneill
1101.1Sjmcneillstatic void
1111.1Sjmcneillhwgpio_pin_ctl(void *priv, int pin, int flags)
1121.1Sjmcneill{
1131.1Sjmcneill	struct hwgpio_softc * const sc = priv;
1141.1Sjmcneill	uint32_t dir;
1151.1Sjmcneill
1161.1Sjmcneill	mutex_enter(&sc->sc_lock);
1171.1Sjmcneill	dir = RD4(HW_GPIOB_DIR);
1181.1Sjmcneill	if (flags & GPIO_PIN_OUTPUT) {
1191.1Sjmcneill		dir |= __BIT(pin);
1201.1Sjmcneill	} else {
1211.1Sjmcneill		dir &= ~__BIT(pin);
1221.1Sjmcneill	}
1231.1Sjmcneill	WR4(HW_GPIOB_DIR, dir);
1241.1Sjmcneill	mutex_exit(&sc->sc_lock);
1251.1Sjmcneill}
1261.1Sjmcneill
1271.1Sjmcneillstatic int
1281.1Sjmcneillhwgpio_match(device_t parent, cfdata_t cf, void *aux)
1291.1Sjmcneill{
1301.1Sjmcneill	return !wiiu_plat;
1311.1Sjmcneill}
1321.1Sjmcneill
1331.1Sjmcneillstatic void
1341.1Sjmcneillhwgpio_attach(device_t parent, device_t self, void *aux)
1351.1Sjmcneill{
1361.1Sjmcneill	struct hwgpio_softc * const sc = device_private(self);
1371.1Sjmcneill	struct gpio_chipset_tag *gp = &sc->sc_gp;
1381.1Sjmcneill	struct gpiobus_attach_args gba = {};
1391.1Sjmcneill	uint32_t in, out, dir;
1401.1Sjmcneill	u_int n;
1411.1Sjmcneill
1421.1Sjmcneill	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_HIGH);
1431.1Sjmcneill
1441.1Sjmcneill	gp->gp_cookie = sc;
1451.1Sjmcneill	gp->gp_pin_read = hwgpio_pin_read;
1461.1Sjmcneill	gp->gp_pin_write = hwgpio_pin_write;
1471.1Sjmcneill	gp->gp_pin_ctl = hwgpio_pin_ctl;
1481.1Sjmcneill
1491.1Sjmcneill	aprint_naive("\n");
1501.1Sjmcneill	aprint_normal(": GPIO\n");
1511.1Sjmcneill
1521.1Sjmcneill	in = RD4(HW_GPIOB_IN);
1531.1Sjmcneill	out = RD4(HW_GPIOB_OUT);
1541.1Sjmcneill	dir = RD4(HW_GPIOB_DIR);
1551.1Sjmcneill	for (n = 0; n < __arraycount(hwgpio_pins); n++) {
1561.1Sjmcneill		const uint32_t mask = __BIT(hwgpio_pins[n].pin_num);
1571.1Sjmcneill		if (dir & mask) {
1581.1Sjmcneill			hwgpio_pins[n].pin_state = (out & mask) != 0;
1591.1Sjmcneill		} else {
1601.1Sjmcneill			hwgpio_pins[n].pin_state = (in & mask) != 0;
1611.1Sjmcneill		}
1621.1Sjmcneill	}
1631.1Sjmcneill
1641.1Sjmcneill	gba.gba_gc = &sc->sc_gp;
1651.1Sjmcneill	gba.gba_pins = hwgpio_pins;
1661.1Sjmcneill	gba.gba_npins = __arraycount(hwgpio_pins);
1671.1Sjmcneill	config_found(self, &gba, NULL, CFARGS_NONE);
1681.1Sjmcneill}
1691.1Sjmcneill
1701.1SjmcneillCFATTACH_DECL_NEW(hwgpio, sizeof(struct hwgpio_softc),
1711.1Sjmcneill    hwgpio_match, hwgpio_attach, NULL, NULL);
172