pinctrl_single.c revision 1.5
11.5Sthorpej/* $NetBSD: pinctrl_single.c,v 1.5 2021/01/27 03:10:21 thorpej Exp $ */ 21.1Sjmcneill 31.1Sjmcneill/*- 41.1Sjmcneill * Copyright (c) 2019 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.5Sthorpej__KERNEL_RCSID(0, "$NetBSD: pinctrl_single.c,v 1.5 2021/01/27 03:10:21 thorpej Exp $"); 311.1Sjmcneill 321.1Sjmcneill#include <sys/param.h> 331.1Sjmcneill#include <sys/bus.h> 341.1Sjmcneill#include <sys/device.h> 351.1Sjmcneill#include <sys/systm.h> 361.1Sjmcneill#include <sys/gpio.h> 371.1Sjmcneill 381.1Sjmcneill#include <dev/fdt/fdtvar.h> 391.1Sjmcneill 401.1Sjmcneill#define PINCTRL_FLAG_PINCONF __BIT(0) /* supports generic pinconf */ 411.1Sjmcneill 421.1Sjmcneillstruct pinctrl_single_config { 431.1Sjmcneill uint32_t flags; 441.1Sjmcneill}; 451.1Sjmcneill 461.1Sjmcneillstatic const struct pinctrl_single_config pinctrl_config = { 471.1Sjmcneill}; 481.1Sjmcneill 491.1Sjmcneillstatic const struct pinctrl_single_config pinconf_config = { 501.1Sjmcneill .flags = PINCTRL_FLAG_PINCONF 511.1Sjmcneill}; 521.1Sjmcneill 531.2Sthorpejstatic const struct device_compatible_entry compat_data[] = { 541.2Sthorpej { .compat = "pinctrl-single", .data = &pinctrl_config }, 551.2Sthorpej { .compat = "pinconf-single", .data = &pinconf_config }, 561.4Sthorpej DEVICE_COMPAT_EOL 571.1Sjmcneill}; 581.1Sjmcneill 591.1Sjmcneillstruct pinctrl_single_softc { 601.1Sjmcneill device_t sc_dev; 611.1Sjmcneill int sc_phandle; 621.1Sjmcneill bus_space_tag_t sc_bst; 631.1Sjmcneill bus_space_handle_t sc_bsh; 641.1Sjmcneill uint32_t sc_flags; 651.1Sjmcneill u_int sc_regwidth; 661.1Sjmcneill u_int sc_funcmask; 671.1Sjmcneill}; 681.1Sjmcneill 691.1Sjmcneillstatic void 701.1Sjmcneillpinctrl_single_pins_write(struct pinctrl_single_softc *sc, u_int off, u_int val) 711.1Sjmcneill{ 721.1Sjmcneill union { 731.1Sjmcneill uint32_t reg32; 741.1Sjmcneill uint16_t reg16; 751.1Sjmcneill uint8_t reg8; 761.1Sjmcneill } u; 771.1Sjmcneill 781.1Sjmcneill aprint_debug_dev(sc->sc_dev, "writing %#x with %#x\n", off, val); 791.1Sjmcneill 801.1Sjmcneill switch (sc->sc_regwidth) { 811.1Sjmcneill case 8: 821.1Sjmcneill u.reg8 = bus_space_read_1(sc->sc_bst, sc->sc_bsh, off); 831.1Sjmcneill u.reg8 &= ~sc->sc_funcmask; 841.1Sjmcneill u.reg8 |= val; 851.1Sjmcneill bus_space_write_1(sc->sc_bst, sc->sc_bsh, off, u.reg8); 861.1Sjmcneill break; 871.1Sjmcneill case 16: 881.1Sjmcneill u.reg16 = bus_space_read_2(sc->sc_bst, sc->sc_bsh, off); 891.1Sjmcneill u.reg16 &= ~sc->sc_funcmask; 901.1Sjmcneill u.reg16 |= val; 911.1Sjmcneill bus_space_write_2(sc->sc_bst, sc->sc_bsh, off, u.reg16); 921.1Sjmcneill break; 931.1Sjmcneill case 32: 941.1Sjmcneill u.reg32 = bus_space_read_4(sc->sc_bst, sc->sc_bsh, off); 951.1Sjmcneill u.reg32 &= ~sc->sc_funcmask; 961.1Sjmcneill u.reg32 |= val; 971.1Sjmcneill bus_space_write_4(sc->sc_bst, sc->sc_bsh, off, u.reg32); 981.1Sjmcneill break; 991.1Sjmcneill default: 1001.1Sjmcneill device_printf(sc->sc_dev, "%s: unsupported reg width %d\n", 1011.1Sjmcneill __func__, sc->sc_regwidth); 1021.1Sjmcneill break; 1031.1Sjmcneill } 1041.1Sjmcneill} 1051.1Sjmcneill 1061.1Sjmcneillstatic int 1071.1Sjmcneillpinctrl_single_pins_set_config(device_t dev, const void *data, size_t len) 1081.1Sjmcneill{ 1091.1Sjmcneill struct pinctrl_single_softc * const sc = device_private(dev); 1101.1Sjmcneill const u_int *pins; 1111.1Sjmcneill int pinslen; 1121.1Sjmcneill 1131.1Sjmcneill if (len != 4) 1141.1Sjmcneill return -1; 1151.1Sjmcneill 1161.1Sjmcneill const int phandle = fdtbus_get_phandle_from_native(be32dec(data)); 1171.1Sjmcneill 1181.1Sjmcneill pins = fdtbus_get_prop(phandle, "pinctrl-single,pins", &pinslen); 1191.1Sjmcneill if (pins == NULL) 1201.1Sjmcneill return -1; 1211.1Sjmcneill 1221.1Sjmcneill while (pinslen >= 8) { 1231.1Sjmcneill const int off = be32toh(pins[0]); 1241.1Sjmcneill const int val = be32toh(pins[1]); 1251.1Sjmcneill 1261.1Sjmcneill pinctrl_single_pins_write(sc, off, val); 1271.1Sjmcneill pins += 2; 1281.1Sjmcneill pinslen -= 8; 1291.1Sjmcneill } 1301.1Sjmcneill 1311.1Sjmcneill return 0; 1321.1Sjmcneill} 1331.1Sjmcneill 1341.1Sjmcneillstatic struct fdtbus_pinctrl_controller_func pinctrl_single_pins_funcs = { 1351.1Sjmcneill .set_config = pinctrl_single_pins_set_config, 1361.1Sjmcneill}; 1371.1Sjmcneill 1381.1Sjmcneillstatic int 1391.1Sjmcneillpinctrl_single_match(device_t parent, cfdata_t cf, void *aux) 1401.1Sjmcneill{ 1411.1Sjmcneill struct fdt_attach_args * const faa = aux; 1421.1Sjmcneill 1431.5Sthorpej return of_compatible_match(faa->faa_phandle, compat_data); 1441.1Sjmcneill} 1451.1Sjmcneill 1461.1Sjmcneillstatic void 1471.1Sjmcneillpinctrl_single_attach(device_t parent, device_t self, void *aux) 1481.1Sjmcneill{ 1491.1Sjmcneill struct pinctrl_single_softc * const sc = device_private(self); 1501.1Sjmcneill struct fdt_attach_args * const faa = aux; 1511.1Sjmcneill const int phandle = faa->faa_phandle; 1521.1Sjmcneill const struct pinctrl_single_config *conf; 1531.1Sjmcneill bus_addr_t addr; 1541.1Sjmcneill bus_size_t size; 1551.1Sjmcneill int child; 1561.1Sjmcneill 1571.1Sjmcneill if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 1581.1Sjmcneill aprint_error(": couldn't get registers\n"); 1591.1Sjmcneill return; 1601.1Sjmcneill } 1611.1Sjmcneill 1621.5Sthorpej conf = of_compatible_lookup(phandle, compat_data)->data; 1631.1Sjmcneill 1641.1Sjmcneill sc->sc_dev = self; 1651.1Sjmcneill sc->sc_phandle = phandle; 1661.1Sjmcneill sc->sc_bst = faa->faa_bst; 1671.1Sjmcneill if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { 1681.1Sjmcneill aprint_error(": couldn't map registers\n"); 1691.1Sjmcneill return; 1701.1Sjmcneill } 1711.1Sjmcneill sc->sc_flags = conf->flags; 1721.1Sjmcneill 1731.1Sjmcneill if (of_getprop_uint32(phandle, "pinctrl-single,register-width", &sc->sc_regwidth) != 0) { 1741.1Sjmcneill aprint_error(": missing 'pinctrl-single,register-width' property\n"); 1751.1Sjmcneill return; 1761.1Sjmcneill } 1771.1Sjmcneill if (of_getprop_uint32(phandle, "pinctrl-single,function-mask", &sc->sc_funcmask) != 0) { 1781.1Sjmcneill aprint_error(": missing 'pinctrl-single,function-mask' property\n"); 1791.1Sjmcneill return; 1801.1Sjmcneill } 1811.1Sjmcneill 1821.1Sjmcneill switch (sc->sc_regwidth) { 1831.1Sjmcneill case 8: 1841.1Sjmcneill case 16: 1851.1Sjmcneill case 32: 1861.1Sjmcneill break; 1871.1Sjmcneill default: 1881.1Sjmcneill aprint_error(": register width %d not supported\n", sc->sc_regwidth); 1891.1Sjmcneill return; 1901.1Sjmcneill } 1911.1Sjmcneill 1921.1Sjmcneill aprint_naive("\n"); 1931.1Sjmcneill aprint_normal("\n"); 1941.1Sjmcneill 1951.1Sjmcneill for (child = OF_child(phandle); child; child = OF_peer(child)) { 1961.1Sjmcneill if (of_hasprop(child, "pinctrl-single,pins")) 1971.1Sjmcneill fdtbus_register_pinctrl_config(self, child, &pinctrl_single_pins_funcs); 1981.1Sjmcneill } 1991.1Sjmcneill 2001.1Sjmcneill fdtbus_pinctrl_set_config(phandle, "default"); 2011.1Sjmcneill} 2021.1Sjmcneill 2031.1SjmcneillCFATTACH_DECL_NEW(pinctrl_single, sizeof(struct pinctrl_single_softc), 2041.1Sjmcneill pinctrl_single_match, pinctrl_single_attach, NULL, NULL); 205