11.1Sskrll/*	$NetBSD: apple_pinctrl.c,v 1.1 2022/04/27 07:59:18 skrll Exp $	*/
21.1Sskrll/*	$OpenBSD: aplpinctrl.c,v 1.4 2022/04/06 18:59:26 naddy Exp $	*/
31.1Sskrll
41.1Sskrll/*-
51.1Sskrll * Copyright (c) 2022 The NetBSD Foundation, Inc.
61.1Sskrll * All rights reserved.
71.1Sskrll *
81.1Sskrll * This code is derived from software contributed to The NetBSD Foundation
91.1Sskrll * by Nick Hudson
101.1Sskrll *
111.1Sskrll * Redistribution and use in source and binary forms, with or without
121.1Sskrll * modification, are permitted provided that the following conditions
131.1Sskrll * are met:
141.1Sskrll * 1. Redistributions of source code must retain the above copyright
151.1Sskrll *    notice, this list of conditions and the following disclaimer.
161.1Sskrll * 2. Redistributions in binary form must reproduce the above copyright
171.1Sskrll *    notice, this list of conditions and the following disclaimer in the
181.1Sskrll *    documentation and/or other materials provided with the distribution.
191.1Sskrll *
201.1Sskrll * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
211.1Sskrll * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
221.1Sskrll * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
231.1Sskrll * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
241.1Sskrll * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
251.1Sskrll * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
261.1Sskrll * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
271.1Sskrll * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
281.1Sskrll * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
291.1Sskrll * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
301.1Sskrll * POSSIBILITY OF SUCH DAMAGE.
311.1Sskrll */
321.1Sskrll
331.1Sskrll/*
341.1Sskrll * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
351.1Sskrll *
361.1Sskrll * Permission to use, copy, modify, and distribute this software for any
371.1Sskrll * purpose with or without fee is hereby granted, provided that the above
381.1Sskrll * copyright notice and this permission notice appear in all copies.
391.1Sskrll *
401.1Sskrll * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
411.1Sskrll * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
421.1Sskrll * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
431.1Sskrll * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
441.1Sskrll * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
451.1Sskrll * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
461.1Sskrll * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
471.1Sskrll */
481.1Sskrll
491.1Sskrll#include <sys/cdefs.h>
501.1Sskrll__KERNEL_RCSID(0, "$NetBSD: apple_pinctrl.c,v 1.1 2022/04/27 07:59:18 skrll Exp $");
511.1Sskrll
521.1Sskrll#include <sys/param.h>
531.1Sskrll#include <sys/bus.h>
541.1Sskrll#include <sys/device.h>
551.1Sskrll#include <sys/kmem.h>
561.1Sskrll
571.1Sskrll#include <dev/fdt/fdtvar.h>
581.1Sskrll
591.1Sskrll#include <arm/pic/picvar.h>
601.1Sskrll
611.1Sskrll#define APPLE_PIN(pinmux)	__SHIFTOUT((pinmux), __BITS(15, 0))
621.1Sskrll#define APPLE_FUNC(pinmux)	__SHIFTOUT((pinmux), __BITS(31, 16))
631.1Sskrll
641.1Sskrll#define GPIO_PIN(pin)		((pin) * 4)
651.1Sskrll#define  GPIO_PIN_GROUP_MASK	__BITS(18, 16)
661.1Sskrll#define  GPIO_PIN_INPUT_ENABLE	__BIT(9)
671.1Sskrll#define  GPIO_PIN_FUNC_MASK	__BITS(6, 5)
681.1Sskrll#define  GPIO_PIN_MODE_MASK	__BITS(3, 1)
691.1Sskrll#define  GPIO_PIN_MODE_INPUT	 __SHIFTIN(0, GPIO_PIN_MODE_MASK);
701.1Sskrll#define  GPIO_PIN_MODE_OUTPUT	 __SHIFTIN(1, GPIO_PIN_MODE_MASK);
711.1Sskrll#define  GPIO_PIN_MODE_IRQ_HI	 __SHIFTIN(2, GPIO_PIN_MODE_MASK);
721.1Sskrll#define  GPIO_PIN_MODE_IRQ_LO	 __SHIFTIN(3, GPIO_PIN_MODE_MASK);
731.1Sskrll#define  GPIO_PIN_MODE_IRQ_UP	 __SHIFTIN(4, GPIO_PIN_MODE_MASK);
741.1Sskrll#define  GPIO_PIN_MODE_IRQ_DN	 __SHIFTIN(5, GPIO_PIN_MODE_MASK);
751.1Sskrll#define  GPIO_PIN_MODE_IRQ_ANY	 __SHIFTIN(6, GPIO_PIN_MODE_MASK);
761.1Sskrll#define  GPIO_PIN_MODE_IRQ_OFF	 __SHIFTIN(7, GPIO_PIN_MODE_MASK);
771.1Sskrll#define  GPIO_PIN_DATA		__BIT(0)
781.1Sskrll#define GPIO_IRQ(grp, pin)	(0x800 + (grp) * 64 + ((pin) >> 5) * 4)
791.1Sskrll
801.1Sskrll#define PINCTRL_READ(sc, reg)						\
811.1Sskrll	(bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)))
821.1Sskrll#define PINCTRL_WRITE(sc, reg, val)					\
831.1Sskrll	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
841.1Sskrll#define PINCTRL_SET(sc, reg, bits)					\
851.1Sskrll	PINCTRL_WRITE((sc), (reg), PINCTRL_READ((sc), (reg)) | (bits))
861.1Sskrll#define PINCTRL_CLR(sc, reg, bits)					\
871.1Sskrll	PINCTRL_WRITE((sc), (reg), PINCTRL_READ((sc), (reg)) & ~(bits))
881.1Sskrll
891.1Sskrll
901.1Sskrllstruct apple_pinctrl_softc {
911.1Sskrll	device_t sc_dev;
921.1Sskrll	int sc_phandle;
931.1Sskrll	bus_space_tag_t sc_bst;
941.1Sskrll	bus_space_handle_t sc_bsh;
951.1Sskrll	u_int sc_npins;
961.1Sskrll};
971.1Sskrll
981.1Sskrllstruct apple_gpio_pin {
991.1Sskrll	int		pin_no;
1001.1Sskrll	u_int		pin_flags;
1011.1Sskrll	bool		pin_actlo;
1021.1Sskrll};
1031.1Sskrll
1041.1Sskrllstatic const struct device_compatible_entry compat_data[] = {
1051.1Sskrll	{ .compat = "apple,pinctrl" },
1061.1Sskrll	DEVICE_COMPAT_EOL
1071.1Sskrll};
1081.1Sskrll
1091.1Sskrllstatic void
1101.1Sskrllapple_gpio_pin_ctl(void *cookie, int pin, int flags)
1111.1Sskrll{
1121.1Sskrll	struct apple_pinctrl_softc * const sc = cookie;
1131.1Sskrll
1141.1Sskrll	KASSERT(pin < sc->sc_npins);
1151.1Sskrll
1161.1Sskrll	uint32_t reg = PINCTRL_READ(sc, GPIO_PIN(pin));
1171.1Sskrll	reg &= ~GPIO_PIN_FUNC_MASK;
1181.1Sskrll	reg &= ~GPIO_PIN_MODE_MASK;
1191.1Sskrll
1201.1Sskrll	if (flags & (GPIO_PIN_OUTPUT | GPIO_PIN_INPUT)) {
1211.1Sskrll		if (flags & GPIO_PIN_INPUT) {
1221.1Sskrll			/* for safety INPUT will override output */
1231.1Sskrll			reg |= GPIO_PIN_MODE_INPUT;
1241.1Sskrll		} else {
1251.1Sskrll			reg |= GPIO_PIN_MODE_OUTPUT;
1261.1Sskrll		}
1271.1Sskrll	}
1281.1Sskrll	PINCTRL_WRITE(sc, GPIO_PIN(pin), reg);
1291.1Sskrll}
1301.1Sskrll
1311.1Sskrllstatic void *
1321.1Sskrllapple_pinctrl_gpio_acquire(device_t dev, const void *data, size_t len, int flags)
1331.1Sskrll{
1341.1Sskrll	struct apple_pinctrl_softc * const sc = device_private(dev);
1351.1Sskrll	struct apple_gpio_pin *pin;
1361.1Sskrll	const u_int *gpio = data;
1371.1Sskrll
1381.1Sskrll	if (len != 12)
1391.1Sskrll		return NULL;
1401.1Sskrll
1411.1Sskrll	const u_int pinno = be32toh(gpio[1]);
1421.1Sskrll	const bool actlo = be32toh(gpio[2]) & 1;
1431.1Sskrll
1441.1Sskrll	if (pinno >= sc->sc_npins)
1451.1Sskrll		return NULL;
1461.1Sskrll
1471.1Sskrll	pin = kmem_alloc(sizeof(*pin), KM_SLEEP);
1481.1Sskrll	pin->pin_no = pinno;
1491.1Sskrll	pin->pin_flags = flags;
1501.1Sskrll	pin->pin_actlo = actlo;
1511.1Sskrll
1521.1Sskrll	apple_gpio_pin_ctl(sc, pin->pin_no, pin->pin_flags);
1531.1Sskrll
1541.1Sskrll	return pin;
1551.1Sskrll}
1561.1Sskrll
1571.1Sskrllstatic void
1581.1Sskrllapple_pinctrl_gpio_release(device_t dev, void *priv)
1591.1Sskrll{
1601.1Sskrll	struct apple_pinctrl_softc * const sc = device_private(dev);
1611.1Sskrll	struct apple_gpio_pin *pin = priv;
1621.1Sskrll
1631.1Sskrll	apple_gpio_pin_ctl(sc, pin->pin_no, GPIO_PIN_INPUT);
1641.1Sskrll	kmem_free(pin, sizeof(*pin));
1651.1Sskrll}
1661.1Sskrll
1671.1Sskrllstatic int
1681.1Sskrllapple_pinctrl_gpio_read(device_t dev, void *priv, bool raw)
1691.1Sskrll{
1701.1Sskrll	struct apple_pinctrl_softc * const sc = device_private(dev);
1711.1Sskrll	struct apple_gpio_pin *pin = priv;
1721.1Sskrll
1731.1Sskrll	KASSERT(pin->pin_no < sc->sc_npins);
1741.1Sskrll
1751.1Sskrll	uint32_t reg = PINCTRL_READ(sc, GPIO_PIN(pin->pin_no));
1761.1Sskrll	int val = __SHIFTOUT(reg, GPIO_PIN_DATA);
1771.1Sskrll	if (!raw && pin->pin_actlo)
1781.1Sskrll		val = !val;
1791.1Sskrll
1801.1Sskrll	return val;
1811.1Sskrll}
1821.1Sskrll
1831.1Sskrllstatic void
1841.1Sskrllapple_pinctrl_gpio_write(device_t dev, void *priv, int val, bool raw)
1851.1Sskrll{
1861.1Sskrll	struct apple_pinctrl_softc * const sc = device_private(dev);
1871.1Sskrll	struct apple_gpio_pin *pin = priv;
1881.1Sskrll
1891.1Sskrll	KASSERT(pin->pin_no < sc->sc_npins);
1901.1Sskrll
1911.1Sskrll	if (!raw && pin->pin_actlo)
1921.1Sskrll		val = !val;
1931.1Sskrll
1941.1Sskrll	if (val)
1951.1Sskrll		PINCTRL_SET(sc, GPIO_PIN(pin->pin_no), GPIO_PIN_DATA);
1961.1Sskrll	else
1971.1Sskrll		PINCTRL_CLR(sc, GPIO_PIN(pin->pin_no), GPIO_PIN_DATA);
1981.1Sskrll}
1991.1Sskrll
2001.1Sskrllstatic int
2011.1Sskrllapple_pinctrl_set_config(device_t dev, const void *data, size_t len)
2021.1Sskrll{
2031.1Sskrll	struct apple_pinctrl_softc * const sc = device_private(dev);
2041.1Sskrll
2051.1Sskrll	if (len != 4)
2061.1Sskrll		return -1;
2071.1Sskrll
2081.1Sskrll	int pins_len;
2091.1Sskrll	const int phandle = fdtbus_get_phandle_from_native(be32dec(data));
2101.1Sskrll	const u_int *pins = fdtbus_get_prop(phandle, "pinmux", &pins_len);
2111.1Sskrll
2121.1Sskrll	if (pins == NULL)
2131.1Sskrll		return -1;
2141.1Sskrll
2151.1Sskrll	const u_int npins = pins_len / sizeof(uint32_t);
2161.1Sskrll
2171.1Sskrll	for (u_int i = 0; i < npins; i++) {
2181.1Sskrll		uint32_t pinmux = be32dec(&pins[i]);
2191.1Sskrll		u_int pinno = APPLE_PIN(pinmux);
2201.1Sskrll		u_int func = APPLE_FUNC(pinmux);
2211.1Sskrll
2221.1Sskrll		uint32_t reg = PINCTRL_READ(sc, GPIO_PIN(pinno));
2231.1Sskrll		reg &= ~GPIO_PIN_FUNC_MASK;
2241.1Sskrll		reg |= __SHIFTIN(func, GPIO_PIN_FUNC_MASK);
2251.1Sskrll
2261.1Sskrll		PINCTRL_WRITE(sc, GPIO_PIN(pinno), reg);
2271.1Sskrll	}
2281.1Sskrll
2291.1Sskrll	return 0;
2301.1Sskrll}
2311.1Sskrll
2321.1Sskrllstatic struct fdtbus_gpio_controller_func apple_pinctrl_gpio_funcs = {
2331.1Sskrll	.acquire = apple_pinctrl_gpio_acquire,
2341.1Sskrll	.release = apple_pinctrl_gpio_release,
2351.1Sskrll	.read = apple_pinctrl_gpio_read,
2361.1Sskrll	.write = apple_pinctrl_gpio_write
2371.1Sskrll};
2381.1Sskrll
2391.1Sskrllstatic struct fdtbus_pinctrl_controller_func apple_pinctrl_funcs = {
2401.1Sskrll	.set_config = apple_pinctrl_set_config,
2411.1Sskrll};
2421.1Sskrll
2431.1Sskrllstatic int
2441.1Sskrllapple_pinctrl_match(device_t parent, cfdata_t cf, void *aux)
2451.1Sskrll{
2461.1Sskrll	struct fdt_attach_args * const faa = aux;
2471.1Sskrll
2481.1Sskrll	return of_compatible_match(faa->faa_phandle, compat_data);
2491.1Sskrll}
2501.1Sskrll
2511.1Sskrllstatic void
2521.1Sskrllapple_pinctrl_attach(device_t parent, device_t self, void *aux)
2531.1Sskrll{
2541.1Sskrll	struct apple_pinctrl_softc * const sc = device_private(self);
2551.1Sskrll	struct fdt_attach_args * const faa = aux;
2561.1Sskrll	const int phandle = faa->faa_phandle;
2571.1Sskrll	bus_addr_t addr;
2581.1Sskrll	bus_size_t size;
2591.1Sskrll
2601.1Sskrll	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
2611.1Sskrll		aprint_error(": couldn't get registers\n");
2621.1Sskrll		return;
2631.1Sskrll	}
2641.1Sskrll
2651.1Sskrll	sc->sc_dev = self;
2661.1Sskrll	sc->sc_bst = faa->faa_bst;
2671.1Sskrll
2681.1Sskrll	if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
2691.1Sskrll		aprint_error(": couldn't map registers\n");
2701.1Sskrll		return;
2711.1Sskrll	}
2721.1Sskrll
2731.1Sskrll	if (of_getprop_uint32(phandle, "apple,npins", &sc->sc_npins)) {
2741.1Sskrll		aprint_error(": couldn't get number of pins\n");
2751.1Sskrll		return;
2761.1Sskrll	}
2771.1Sskrll
2781.1Sskrll	if (!of_hasprop(phandle, "gpio-controller")) {
2791.1Sskrll		aprint_error(": no gpio controller");
2801.1Sskrll		return;
2811.1Sskrll	}
2821.1Sskrll
2831.1Sskrll	aprint_naive("\n");
2841.1Sskrll	aprint_normal(": Apple Pinctrl\n");
2851.1Sskrll
2861.1Sskrll	fdtbus_register_gpio_controller(self, phandle, &apple_pinctrl_gpio_funcs);
2871.1Sskrll
2881.1Sskrll	for (int child = OF_child(phandle); child; child = OF_peer(child)) {
2891.1Sskrll		if (!of_hasprop(child, "pinmux"))
2901.1Sskrll			continue;
2911.1Sskrll		fdtbus_register_pinctrl_config(self, child,
2921.1Sskrll		    &apple_pinctrl_funcs);
2931.1Sskrll
2941.1Sskrll	}
2951.1Sskrll}
2961.1Sskrll
2971.1SskrllCFATTACH_DECL_NEW(apple_pinctrl, sizeof(struct apple_pinctrl_softc),
2981.1Sskrll    apple_pinctrl_match, apple_pinctrl_attach, NULL, NULL);
2991.1Sskrll
300