xref: /freebsd/sys/arm/mv/mvebu_pinctrl.c (revision 62e8ccc3a489434af379c7f47da71545bc1e14ee)
12d2a0852SEmmanuel Vadot /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
32d2a0852SEmmanuel Vadot  *
42d2a0852SEmmanuel Vadot  * Copyright (c) 2018 Rubicon Communications, LLC (Netgate)
52d2a0852SEmmanuel Vadot  *
62d2a0852SEmmanuel Vadot  * Redistribution and use in source and binary forms, with or without
72d2a0852SEmmanuel Vadot  * modification, are permitted provided that the following conditions
82d2a0852SEmmanuel Vadot  * are met:
92d2a0852SEmmanuel Vadot  * 1. Redistributions of source code must retain the above copyright
102d2a0852SEmmanuel Vadot  *    notice, this list of conditions and the following disclaimer.
112d2a0852SEmmanuel Vadot  * 2. Redistributions in binary form must reproduce the above copyright
122d2a0852SEmmanuel Vadot  *    notice, this list of conditions and the following disclaimer in the
132d2a0852SEmmanuel Vadot  *    documentation and/or other materials provided with the distribution.
142d2a0852SEmmanuel Vadot  *
152d2a0852SEmmanuel Vadot  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
162d2a0852SEmmanuel Vadot  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
172d2a0852SEmmanuel Vadot  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
182d2a0852SEmmanuel Vadot  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
192d2a0852SEmmanuel Vadot  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
202d2a0852SEmmanuel Vadot  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
212d2a0852SEmmanuel Vadot  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
222d2a0852SEmmanuel Vadot  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
232d2a0852SEmmanuel Vadot  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
242d2a0852SEmmanuel Vadot  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
252d2a0852SEmmanuel Vadot  * SUCH DAMAGE.
262d2a0852SEmmanuel Vadot  */
272d2a0852SEmmanuel Vadot 
282d2a0852SEmmanuel Vadot #include <sys/param.h>
292d2a0852SEmmanuel Vadot #include <sys/systm.h>
302d2a0852SEmmanuel Vadot #include <sys/bus.h>
312d2a0852SEmmanuel Vadot 
322d2a0852SEmmanuel Vadot #include <sys/kernel.h>
332d2a0852SEmmanuel Vadot #include <sys/module.h>
342d2a0852SEmmanuel Vadot #include <sys/rman.h>
352d2a0852SEmmanuel Vadot #include <sys/lock.h>
362d2a0852SEmmanuel Vadot #include <sys/mutex.h>
372d2a0852SEmmanuel Vadot 
382d2a0852SEmmanuel Vadot #include <machine/bus.h>
392d2a0852SEmmanuel Vadot #include <machine/resource.h>
402d2a0852SEmmanuel Vadot #include <machine/intr.h>
412d2a0852SEmmanuel Vadot 
42*62e8ccc3SEmmanuel Vadot #include <dev/syscon/syscon.h>
434b84206bSMichal Meloun 
444b84206bSMichal Meloun #include <dev/fdt/fdt_pinctrl.h>
452d2a0852SEmmanuel Vadot 
462d2a0852SEmmanuel Vadot #include <dev/ofw/ofw_bus.h>
472d2a0852SEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h>
482d2a0852SEmmanuel Vadot 
494b84206bSMichal Meloun #include "syscon_if.h"
502d2a0852SEmmanuel Vadot 
512d2a0852SEmmanuel Vadot #define	PINS_PER_REG	8
522d2a0852SEmmanuel Vadot #define	BITS_PER_PIN	4
532d2a0852SEmmanuel Vadot #define	PINS_MASK	0xf
542d2a0852SEmmanuel Vadot #define	MAX_PIN_FUNC	5
552d2a0852SEmmanuel Vadot 
562d2a0852SEmmanuel Vadot struct mv_pins {
572d2a0852SEmmanuel Vadot 	const char	*name;
582d2a0852SEmmanuel Vadot 	const char	*functions[MAX_PIN_FUNC];
592d2a0852SEmmanuel Vadot };
602d2a0852SEmmanuel Vadot 
612d2a0852SEmmanuel Vadot struct mv_padconf {
622d2a0852SEmmanuel Vadot 	const struct mv_pins	*pins;
632d2a0852SEmmanuel Vadot 	size_t		npins;
642d2a0852SEmmanuel Vadot };
652d2a0852SEmmanuel Vadot 
662d2a0852SEmmanuel Vadot const static struct mv_pins ap806_pins[] = {
672d2a0852SEmmanuel Vadot 	{"mpp0", {"gpio", "sdio", NULL, "spi0"}},
682d2a0852SEmmanuel Vadot 	{"mpp1", {"gpio", "sdio", NULL, "spi0"}},
692d2a0852SEmmanuel Vadot 	{"mpp2", {"gpio", "sdio", NULL, "spi0"}},
702d2a0852SEmmanuel Vadot 	{"mpp3", {"gpio", "sdio", NULL, "spi0"}},
712d2a0852SEmmanuel Vadot 	{"mpp4", {"gpio", "sdio", NULL, "i2c0"}},
722d2a0852SEmmanuel Vadot 	{"mpp5", {"gpio", "sdio", NULL, "i2c0"}},
732d2a0852SEmmanuel Vadot 	{"mpp6", {"gpio", "sdio", NULL, NULL}},
742d2a0852SEmmanuel Vadot 	{"mpp7", {"gpio", "sdio", NULL, "uart1"}},
752d2a0852SEmmanuel Vadot 	{"mpp8", {"gpio", "sdio", NULL, "uart1"}},
762d2a0852SEmmanuel Vadot 	{"mpp9", {"gpio", "sdio", NULL, "spi0"}},
772d2a0852SEmmanuel Vadot 	{"mpp10", {"gpio", "sdio", NULL, NULL}},
782d2a0852SEmmanuel Vadot 	{"mpp11", {"gpio", NULL, NULL, "uart0"}},
792d2a0852SEmmanuel Vadot 	{"mpp12", {"gpio", "sdio", "sdio", NULL}},
802d2a0852SEmmanuel Vadot 	{"mpp13", {"gpio", NULL, NULL}},
812d2a0852SEmmanuel Vadot 	{"mpp14", {"gpio", NULL, NULL}},
822d2a0852SEmmanuel Vadot 	{"mpp15", {"gpio", NULL, NULL}},
832d2a0852SEmmanuel Vadot 	{"mpp16", {"gpio", NULL, NULL}},
842d2a0852SEmmanuel Vadot 	{"mpp17", {"gpio", NULL, NULL}},
852d2a0852SEmmanuel Vadot 	{"mpp18", {"gpio", NULL, NULL}},
862d2a0852SEmmanuel Vadot 	{"mpp19", {"gpio", NULL, NULL, "uart0", "sdio"}},
872d2a0852SEmmanuel Vadot };
882d2a0852SEmmanuel Vadot 
892d2a0852SEmmanuel Vadot const struct mv_padconf ap806_padconf = {
902d2a0852SEmmanuel Vadot 	.npins = nitems(ap806_pins),
912d2a0852SEmmanuel Vadot 	.pins = ap806_pins,
922d2a0852SEmmanuel Vadot };
932d2a0852SEmmanuel Vadot 
942d2a0852SEmmanuel Vadot struct mv_pinctrl_softc {
952d2a0852SEmmanuel Vadot 	device_t		dev;
964b84206bSMichal Meloun 	struct syscon		*syscon;
972d2a0852SEmmanuel Vadot 
982d2a0852SEmmanuel Vadot 	struct mv_padconf	*padconf;
992d2a0852SEmmanuel Vadot };
1002d2a0852SEmmanuel Vadot 
1012d2a0852SEmmanuel Vadot static struct ofw_compat_data compat_data[] = {
1022d2a0852SEmmanuel Vadot 	{"marvell,ap806-pinctrl", (uintptr_t)&ap806_padconf},
1032d2a0852SEmmanuel Vadot 	{NULL,             0}
1042d2a0852SEmmanuel Vadot };
1052d2a0852SEmmanuel Vadot 
1064b84206bSMichal Meloun #define	RD4(sc, reg)		SYSCON_READ_4((sc)->syscon, (reg))
1074b84206bSMichal Meloun #define	WR4(sc, reg, val)	SYSCON_WRITE_4((sc)->syscon, (reg), (val))
1082d2a0852SEmmanuel Vadot 
1092d2a0852SEmmanuel Vadot static void
mv_pinctrl_configure_pin(struct mv_pinctrl_softc * sc,uint32_t pin,uint32_t function)1102d2a0852SEmmanuel Vadot mv_pinctrl_configure_pin(struct mv_pinctrl_softc *sc, uint32_t pin,
1112d2a0852SEmmanuel Vadot     uint32_t function)
1122d2a0852SEmmanuel Vadot {
1132d2a0852SEmmanuel Vadot 	uint32_t offset, shift, reg;
1142d2a0852SEmmanuel Vadot 
1152d2a0852SEmmanuel Vadot 	offset = (pin / PINS_PER_REG) * BITS_PER_PIN;
1162d2a0852SEmmanuel Vadot 	shift = (pin % PINS_PER_REG) * BITS_PER_PIN;
1172d2a0852SEmmanuel Vadot 	reg = RD4(sc, offset);
1182d2a0852SEmmanuel Vadot 	reg &= ~(PINS_MASK << shift);
1192d2a0852SEmmanuel Vadot 	reg |= function << shift;
1202d2a0852SEmmanuel Vadot 	WR4(sc, offset, reg);
1212d2a0852SEmmanuel Vadot }
1222d2a0852SEmmanuel Vadot 
1232d2a0852SEmmanuel Vadot static int
mv_pinctrl_configure_pins(device_t dev,phandle_t cfgxref)1242d2a0852SEmmanuel Vadot mv_pinctrl_configure_pins(device_t dev, phandle_t cfgxref)
1252d2a0852SEmmanuel Vadot {
1262d2a0852SEmmanuel Vadot 	struct mv_pinctrl_softc *sc;
1272d2a0852SEmmanuel Vadot 	phandle_t node;
1282d2a0852SEmmanuel Vadot 	char *function;
1292d2a0852SEmmanuel Vadot 	const char **pins;
1302d2a0852SEmmanuel Vadot 	int i, pin_num, pin_func, npins;
1312d2a0852SEmmanuel Vadot 
1322d2a0852SEmmanuel Vadot 	sc = device_get_softc(dev);
1332d2a0852SEmmanuel Vadot 	node = OF_node_from_xref(cfgxref);
1342d2a0852SEmmanuel Vadot 
1352d2a0852SEmmanuel Vadot 	if (OF_getprop_alloc(node, "marvell,function",
1362d2a0852SEmmanuel Vadot 	    (void **)&function) == -1)
1372d2a0852SEmmanuel Vadot 		return (ENOMEM);
1382d2a0852SEmmanuel Vadot 
1392d2a0852SEmmanuel Vadot 	npins = ofw_bus_string_list_to_array(node, "marvell,pins", &pins);
1402d2a0852SEmmanuel Vadot 	if (npins == -1)
1412d2a0852SEmmanuel Vadot 		return (ENOMEM);
1422d2a0852SEmmanuel Vadot 
1432d2a0852SEmmanuel Vadot 	for (i = 0; i < npins; i++) {
1442d2a0852SEmmanuel Vadot 		for (pin_num = 0; pin_num < sc->padconf->npins; pin_num++) {
1452d2a0852SEmmanuel Vadot 			if (strcmp(pins[i], sc->padconf->pins[pin_num].name) == 0)
1462d2a0852SEmmanuel Vadot 				break;
1472d2a0852SEmmanuel Vadot 		}
1482d2a0852SEmmanuel Vadot 		if (pin_num == sc->padconf->npins)
1492d2a0852SEmmanuel Vadot 			continue;
1502d2a0852SEmmanuel Vadot 
1512d2a0852SEmmanuel Vadot 		for (pin_func = 0; pin_func < MAX_PIN_FUNC; pin_func++)
1522d2a0852SEmmanuel Vadot 			if (sc->padconf->pins[pin_num].functions[pin_func] &&
1532d2a0852SEmmanuel Vadot 			    strcmp(function, sc->padconf->pins[pin_num].functions[pin_func]) == 0)
1542d2a0852SEmmanuel Vadot 				break;
1552d2a0852SEmmanuel Vadot 
1562d2a0852SEmmanuel Vadot 		if (pin_func == MAX_PIN_FUNC)
1572d2a0852SEmmanuel Vadot 			continue;
1582d2a0852SEmmanuel Vadot 
1592d2a0852SEmmanuel Vadot 		mv_pinctrl_configure_pin(sc, pin_num, pin_func);
1602d2a0852SEmmanuel Vadot 	}
1612d2a0852SEmmanuel Vadot 
1622d2a0852SEmmanuel Vadot 	OF_prop_free(pins);
1632d2a0852SEmmanuel Vadot 
1642d2a0852SEmmanuel Vadot 	return (0);
1652d2a0852SEmmanuel Vadot }
1662d2a0852SEmmanuel Vadot 
1672d2a0852SEmmanuel Vadot static int
mv_pinctrl_probe(device_t dev)1682d2a0852SEmmanuel Vadot mv_pinctrl_probe(device_t dev)
1692d2a0852SEmmanuel Vadot {
1702d2a0852SEmmanuel Vadot 
1712d2a0852SEmmanuel Vadot 	if (!ofw_bus_status_okay(dev))
1722d2a0852SEmmanuel Vadot 		return (ENXIO);
1732d2a0852SEmmanuel Vadot 
1742d2a0852SEmmanuel Vadot 	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
1752d2a0852SEmmanuel Vadot 		return (ENXIO);
1762d2a0852SEmmanuel Vadot 
1772d2a0852SEmmanuel Vadot 	device_set_desc(dev, "Marvell Pinctrl controller");
1782d2a0852SEmmanuel Vadot 	return (BUS_PROBE_DEFAULT);
1792d2a0852SEmmanuel Vadot }
1802d2a0852SEmmanuel Vadot 
1812d2a0852SEmmanuel Vadot static int
mv_pinctrl_attach(device_t dev)1822d2a0852SEmmanuel Vadot mv_pinctrl_attach(device_t dev)
1832d2a0852SEmmanuel Vadot {
1842d2a0852SEmmanuel Vadot 	struct mv_pinctrl_softc *sc;
1852d2a0852SEmmanuel Vadot 
1862d2a0852SEmmanuel Vadot 	sc = device_get_softc(dev);
1872d2a0852SEmmanuel Vadot 	sc->dev = dev;
1884b84206bSMichal Meloun 	sc->padconf = (struct mv_padconf *)
1894b84206bSMichal Meloun 	    ofw_bus_search_compatible(dev,compat_data)->ocd_data;
1902d2a0852SEmmanuel Vadot 
1914b84206bSMichal Meloun 	if (SYSCON_GET_HANDLE(sc->dev, &sc->syscon) != 0 ||
1924b84206bSMichal Meloun 	    sc->syscon == NULL) {
1934b84206bSMichal Meloun 		device_printf(dev, "cannot get syscon for device\n");
1942d2a0852SEmmanuel Vadot 		return (ENXIO);
1952d2a0852SEmmanuel Vadot 	}
1962d2a0852SEmmanuel Vadot 
1972d2a0852SEmmanuel Vadot 	fdt_pinctrl_register(dev, "marvell,pins");
1982d2a0852SEmmanuel Vadot 	fdt_pinctrl_configure_tree(dev);
1992d2a0852SEmmanuel Vadot 
2002d2a0852SEmmanuel Vadot 	return (0);
2012d2a0852SEmmanuel Vadot }
2022d2a0852SEmmanuel Vadot 
2032d2a0852SEmmanuel Vadot static int
mv_pinctrl_detach(device_t dev)2042d2a0852SEmmanuel Vadot mv_pinctrl_detach(device_t dev)
2052d2a0852SEmmanuel Vadot {
2062d2a0852SEmmanuel Vadot 
2072d2a0852SEmmanuel Vadot 	return (EBUSY);
2082d2a0852SEmmanuel Vadot }
2092d2a0852SEmmanuel Vadot 
2102d2a0852SEmmanuel Vadot static device_method_t mv_pinctrl_methods[] = {
2112d2a0852SEmmanuel Vadot 	/* Device interface */
2122d2a0852SEmmanuel Vadot 	DEVMETHOD(device_probe,		mv_pinctrl_probe),
2132d2a0852SEmmanuel Vadot 	DEVMETHOD(device_attach,	mv_pinctrl_attach),
2142d2a0852SEmmanuel Vadot 	DEVMETHOD(device_detach,	mv_pinctrl_detach),
2152d2a0852SEmmanuel Vadot 
2162d2a0852SEmmanuel Vadot         /* fdt_pinctrl interface */
2172d2a0852SEmmanuel Vadot 	DEVMETHOD(fdt_pinctrl_configure,mv_pinctrl_configure_pins),
2182d2a0852SEmmanuel Vadot 
2192d2a0852SEmmanuel Vadot 	DEVMETHOD_END
2202d2a0852SEmmanuel Vadot };
2212d2a0852SEmmanuel Vadot 
2222d2a0852SEmmanuel Vadot static driver_t mv_pinctrl_driver = {
2232d2a0852SEmmanuel Vadot 	"mv_pinctrl",
2242d2a0852SEmmanuel Vadot 	mv_pinctrl_methods,
2252d2a0852SEmmanuel Vadot 	sizeof(struct mv_pinctrl_softc),
2262d2a0852SEmmanuel Vadot };
2272d2a0852SEmmanuel Vadot 
228a3b866cbSJohn Baldwin EARLY_DRIVER_MODULE(mv_pinctrl, simplebus, mv_pinctrl_driver, 0, 0,
229a3b866cbSJohn Baldwin     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);
230