1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2021 Adrian Chadd <adrian@FreeBSD.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice unmodified, this list of conditions, and the following 11 * disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 /* 30 * This is a pinmux/gpio controller for the IPQ4018/IPQ4019. 31 */ 32 33 #include <sys/cdefs.h> 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/bus.h> 37 38 #include <sys/kernel.h> 39 #include <sys/module.h> 40 #include <sys/rman.h> 41 #include <sys/lock.h> 42 #include <sys/malloc.h> 43 #include <sys/mutex.h> 44 #include <sys/gpio.h> 45 46 #include <machine/bus.h> 47 #include <machine/resource.h> 48 #include <dev/gpio/gpiobusvar.h> 49 50 #include <dev/fdt/fdt_common.h> 51 #include <dev/ofw/ofw_bus.h> 52 #include <dev/ofw/ofw_bus_subr.h> 53 54 #include <dev/fdt/fdt_pinctrl.h> 55 56 #include "qcom_tlmm_var.h" 57 #include "qcom_tlmm_pin.h" 58 #include "qcom_tlmm_debug.h" 59 60 #include "qcom_tlmm_ipq4018_reg.h" 61 #include "qcom_tlmm_ipq4018_hw.h" 62 63 #include "gpio_if.h" 64 65 #define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | \ 66 GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN) 67 68 /* 100 GPIO pins, 0..99 */ 69 #define QCOM_TLMM_IPQ4018_GPIO_PINS 100 70 71 static const struct qcom_tlmm_gpio_mux gpio_muxes[] = { 72 GDEF(0, "jtag_tdi", "smart0", "i2s_rx_bclk"), 73 GDEF(1, "jtag_tck", "smart0", "i2s_rx_fsync"), 74 GDEF(2, "jtag_tms", "smart0", "i2s_rxd"), 75 GDEF(3, "jtag_tdo"), 76 GDEF(4, "jtag_rst"), 77 GDEF(5, "jtag_trst"), 78 GDEF(6, "mdio0", NULL, "wcss0_dbg18", "wcss1_dbg18", NULL, 79 "qdss_tracedata_a"), 80 GDEF(7, "mdc", NULL, "wcss0_dbg19", "wcss1_dbg19", NULL, 81 "qdss_tracedata_a"), 82 GDEF(8, "blsp_uart1", "wifi0_uart", "wifi1_uart", "smart1", NULL, 83 "wcss0_dbg20", "wcss1_dbg20", NULL, "qdss_tracedata_a"), 84 GDEF(9, "blsp_uart1", "wifi0_uart0", "wifi1_uart0", "smart1", 85 "wifi0_uart", NULL, "wcss0_dbg21", "wcss1_dbg21", NULL, 86 "qdss_tracedata_a"), 87 88 GDEF(10, "blsp_uart1", "wifi0_uart0", "wifi1_uart0", "blsp_i2c0", 89 NULL, "wcss0_dbg22", "wcss1_dbg22", NULL, "qdss_tracedata_a"), 90 GDEF(11, "blsp_uart1", "wifi0_uart", "wifi1_uart", "blsp_i2c0", 91 NULL, "wcss0_dbg23", "wcss1_dbg23", NULL, "qdss_tracedata_a"), 92 GDEF(12, "blsp_spi0", "blsp_i2c1", NULL, "wcss0_dbg24", 93 "wcss1_dbg24"), 94 GDEF(13, "blsp_spi0", "blsp_i2c1", NULL, "wcss0_dbg25", 95 "wcss1_dbg25"), 96 GDEF(14, "blsp_spi0", NULL, "wcss0_dbg26", "wcss1_dbg26"), 97 GDEF(15, "blsp_spi0", NULL, "wcss0_dbg", "wcss1_dbg"), 98 GDEF(16, "blsp_uart0", "led0", "smart1", NULL, "wcss0_dbg28", 99 "wcss1_dbg28", NULL, "qdss_tracedata_a"), 100 GDEF(17, "blsp_uart0", "led1", "smart1", NULL, "wcss0_dbg29", 101 "wcss1_dbg29", NULL, "qdss_tracedata_a"), 102 GDEF(18, "wifi0_uart1", "wifi1_uart1", NULL, "wcss0_dbg30", 103 "wcss1_dbg30"), 104 GDEF(19, "wifi0_uart", "wifi1_uart", NULL, "wcss0_dbg31", 105 "wcss1_dbg31"), 106 107 GDEF(20, "blsp_i2c0", "i2s_rx_mclk", NULL, "wcss0_dbg16", 108 "wcss1_dbg16"), 109 GDEF(21, "blsp_i2c0", "i2s_rx_bclk", NULL, "wcss0_dbg17", 110 "wcss1_dbg17"), 111 GDEF(22, "rgmii0", "i2s_rx_fsync", NULL, "wcss0_dbg18", 112 "wcss1_dbg18"), 113 GDEF(23, "sdio0", "rgmii1", "i2s_rxd", NULL, "wcss0_dbg19", 114 "wcss1_dbg19"), 115 GDEF(24, "sdio1", "rgmii2", "i2s_tx_mclk", NULL, "wcss0_dbg20", 116 "wcss1_dbg20"), 117 GDEF(25, "sdio2", "rgmii3", "i2s_tx_bclk", NULL, "wcss0_dbg21", 118 "wcss1_dbg21"), 119 GDEF(26, "sdio3", "rgmii_rx", "i2s_tx_fsync", NULL, "wcss0_dbg22", 120 "wcss1_dbg22"), 121 GDEF(27, "sdio_clk", "rgmii_txc", "i2s_tdl", NULL, "wcss0_dbg23", 122 "wcss1_dbg23"), 123 GDEF(28, "sdio_cmd", "rgmii0", "i2s_td2", NULL, "wcss0_dbg24", 124 "wcss1_dbg24"), 125 GDEF(29, "sdio4", "rgmii1", "i2s_td3", NULL, "wcss0_dbg25", 126 "wcss1_dbg25"), 127 128 GDEF(30, "sdio5", "rgmii2", "audio_pwm0", NULL, "wcss0_dbg26", 129 "wcss1_dbg26"), 130 GDEF(31, "sdio6", "rgmii3", "audio_pwm1", NULL, "wcss0_dbg27", 131 "wcss1_dbg27"), 132 GDEF(32, "sdio7", "rgmii_rxc", "audio_pwm2", NULL, "wcss0_dbg28", 133 "wcss1_dbg28"), 134 GDEF(33, "rgmii_tx", "audio_pwm3", NULL, "wcss0_dbg29", 135 "wcss1_dbg29", NULL, "boot2"), 136 GDEF(34, "blsp_i2c1", "i2s_spdif_in", NULL, "wcss0_dbg30", 137 "wcss1_dbg30"), 138 GDEF(35, "blsp_i2c1", "i2s_spdif_out", NULL, "wcss0_dbg31", 139 "wcss1_dbg31"), 140 GDEF(36, "rmii00", "led2", "led0"), 141 GDEF(37, "rmii01", "wifi0_wci", "wifi1_wci", "led1", NULL, NULL, 142 "wcss0_dbg16", "wcss1_dbg16", NULL, "qdss_tracedata_a", "boot4"), 143 GDEF(38, "rmii0_tx", "led2", NULL, NULL, "wcss0_dbg17", 144 "wcss1_dbg17", NULL, "qdss_tracedata_a", "boot5"), 145 GDEF(39, "rmii0_rx", "pcie_clk1", "led3", NULL, NULL, "wcss0_dbg18", 146 "wcss1_dbg18", NULL, NULL, "qdss_tracedata_a"), 147 148 GDEF(40, "rmii0_refclk", "wifi0_rfsilent0", "wifi1_rfsilent0", 149 "smart2", "led4", NULL, NULL, "wcss0_dbg19", "wcss1_dbg19", NULL, 150 NULL, "qdss_tracedata_a"), 151 GDEF(41, "rmii00", "wifi0_cal", "wifi1_cal", "smart2", NULL, NULL, 152 "wcss0_dbg20", "wcss1_dbg20", NULL, NULL, "qdss_tracedata_a"), 153 GDEF(42, "rmii01", "wifi_wci0", NULL, NULL, "wcss0_dbg21", 154 "wcss1_dbg21", NULL, NULL, "qdss_tracedata_a"), 155 GDEF(43, "rmii0_dv", "wifi_wci1", NULL, NULL, "wcss0_dbg22", 156 "wcss1_dbg22", NULL, NULL, "qdss_tracedata_a"), 157 GDEF(44, "rmii1_refclk", "blsp_spi1", "smart0", "led5", NULL, NULL, 158 "wcss0_dbg23", "wcss1_dbg23"), 159 GDEF(45, "rmii10", "blsp_spi1", "smart0", "led6", NULL, NULL, 160 "wcss0_dbg24", "wcss1_dbg24"), 161 GDEF(46, "rmii11", "blsp_spi1", "smart0", "led7", NULL, NULL, 162 "wcss0_dbg25", "wcss1_dbg25"), 163 GDEF(47, "rmii1_dv", "blsp_spi1", "smart0", "led8", NULL, NULL, 164 "wcss0_dbg26", "wcss1_dbg26"), 165 GDEF(48, "rmii1_tx", "aud_pin", "smart2", "led9", NULL, NULL, 166 "wcss0_dbg27", "wcss1_dbg27"), 167 GDEF(49, "rmii1_rx", "aud_pin", "smart2", "led10", NULL, NULL, 168 "wcss0_dbg28", "wcss1_dbg28"), 169 170 GDEF(50, "rmii10", "aud_pin", "wifi0_rfsilent1", "wifi1_rfsilent1", 171 "led11", NULL, NULL, "wcss0_dbg29", "wcss1_dbg29"), 172 GDEF(51, "rmii11", "aud_pin", "wifi0_cal", "wifi1_cal", NULL, NULL, 173 "wcss0_dbg30", "wcss1_dbg30", NULL, "boot7"), 174 GDEF(52, "qpic_pad", "mdc", "pcie_clk", "i2s_tx_mclk", NULL, NULL, 175 "wcss0_dbg31", "tm_clk0", "wifi00", "wifi10"), 176 GDEF(53, "qpic_pad", "mdio1", "i2s_tx_bclk", "prng_rsoc", "dbg_out", 177 "tm0", "wifi01", "wifi11"), 178 GDEF(54, "qpic_pad", "blsp_spi0", "i2s_tdl", "atest_char3", "pmu0", 179 NULL, NULL, "boot8", "tm1"), 180 GDEF(55, "qpic_pad", "blsp_spi0", "i2s_td2", "atest_char2", "pmu1", 181 NULL, NULL, "boot9", "tm2"), 182 GDEF(56, "qpic_pad", "blsp_spi0", "i2s_td3", "atest_char1", NULL, 183 "tm_ack", "wifi03", "wifi13"), 184 GDEF(57, "qpic_pad4", "blsp_spi0", "i2s_tx_fsync", "atest_char0", 185 NULL, "tm3", "wifi02", "wifi12"), 186 GDEF(58, "qpic_pad5", "led2", "blsp_i2c0", "smart3", "smart1", 187 "i2s_rx_mclk", NULL, "wcss0_dbg14", "tm4", "wifi04", "wifi14"), 188 GDEF(59, "qpic_pad6", "blsp_i2c0", "smart3", "smart1", "i2c_spdif_in", 189 NULL, NULL, "wcss0_dbg15", "qdss_tracectl_a", "boot18", "tm5" ), 190 191 GDEF(60, "qpic_pad7", "blsp_uart0", "smart1", "smart3", "led0", 192 "i2s_tx_bclk", "i2s_rx_bclk", "atest_char", NULL, "wcss0_dbg4", 193 "qdss_traceclk_a", "boot19", "tm6" ), 194 GDEF(61, "qpic_pad", "blsp_uart0", "smart1", "smart3", "led1", 195 "i2s_tx_fsync", "i2s_rx_fsync", NULL, NULL, "wcss0_dbg5", 196 "qdss_cti_trig_out_a0", "boot14", "tm7"), 197 GDEF(62, "qpic_pad", "chip_rst", "wifi0_uart", "wifi1_uart", 198 "i2s_spdif_out", NULL, NULL, "wcss0_dbg6", "qdss_cti_trig_out_b0", 199 "boot11", "tm8"), 200 GDEF(63, "qpic_pad", "wifi0_uart1", "wifi1_uart1", "wifi1_uart", 201 "i2s_tdl", "i2s_rxd", "i2s_spdif_out", "i2s_spdif_in", NULL, 202 "wcss0_dbg7", "wcss1_dbg7", "boot20", "tm9"), 203 GDEF(64, "qpic_pad1", "audio_pwm0", NULL, "wcss0_dbg8", "wcss1_dbg8"), 204 GDEF(65, "qpic_pad2", "audio_pwm1", NULL, "wcss0_dbg9", 205 "wcss1_dbg9" ), 206 GDEF(66, "qpic_pad3", "audio_pwm2", NULL, "wcss0_dbg10", 207 "wcss1_dbg10"), 208 GDEF(67, "qpic_pad0", "audio_pwm3", NULL, "wcss0_dbg11", 209 "wcss1_dbg11"), 210 GDEF(68, "qpic_pad8", NULL, "wcss0_dbg12", "wcss1_dbg12"), 211 GDEF(69, "qpic_pad", NULL, "wcss0_dbg"), 212 213 GDEF(70), 214 GDEF(71), 215 GDEF(72), 216 GDEF(73), 217 GDEF(74), 218 GDEF(75), 219 GDEF(76), 220 GDEF(77), 221 GDEF(78), 222 GDEF(79), 223 224 GDEF(80), 225 GDEF(81), 226 GDEF(82), 227 GDEF(83), 228 GDEF(84), 229 GDEF(85), 230 GDEF(86), 231 GDEF(87), 232 GDEF(88), 233 GDEF(89), 234 235 GDEF(90), 236 GDEF(91), 237 GDEF(92), 238 GDEF(93), 239 GDEF(94), 240 GDEF(95), 241 GDEF(96), 242 GDEF(97), 243 GDEF(98, "wifi034", "wifi134"), 244 GDEF(99), 245 246 GDEF(-1), 247 }; 248 249 static int 250 qcom_tlmm_ipq4018_probe(device_t dev) 251 { 252 253 if (! ofw_bus_status_okay(dev)) 254 return (ENXIO); 255 256 if (ofw_bus_is_compatible(dev, "qcom,ipq4019-pinctrl") == 0) 257 return (ENXIO); 258 259 device_set_desc(dev, 260 "Qualcomm Atheross TLMM IPQ4018/IPQ4019 GPIO/Pinmux driver"); 261 return (0); 262 } 263 264 static int 265 qcom_tlmm_ipq4018_detach(device_t dev) 266 { 267 struct qcom_tlmm_softc *sc = device_get_softc(dev); 268 269 KASSERT(mtx_initialized(&sc->gpio_mtx), ("gpio mutex not initialized")); 270 271 gpiobus_detach_bus(dev); 272 if (sc->gpio_ih) 273 bus_teardown_intr(dev, sc->gpio_irq_res, sc->gpio_ih); 274 if (sc->gpio_irq_res) 275 bus_release_resource(dev, SYS_RES_IRQ, sc->gpio_irq_rid, 276 sc->gpio_irq_res); 277 if (sc->gpio_mem_res) 278 bus_release_resource(dev, SYS_RES_MEMORY, sc->gpio_mem_rid, 279 sc->gpio_mem_res); 280 if (sc->gpio_pins) 281 free(sc->gpio_pins, M_DEVBUF); 282 mtx_destroy(&sc->gpio_mtx); 283 284 return(0); 285 } 286 287 288 289 static int 290 qcom_tlmm_ipq4018_attach(device_t dev) 291 { 292 struct qcom_tlmm_softc *sc = device_get_softc(dev); 293 int i; 294 295 KASSERT((device_get_unit(dev) == 0), 296 ("qcom_tlmm_ipq4018: Only one gpio module supported")); 297 298 mtx_init(&sc->gpio_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 299 300 /* Map control/status registers. */ 301 sc->gpio_mem_rid = 0; 302 sc->gpio_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 303 &sc->gpio_mem_rid, RF_ACTIVE); 304 305 if (sc->gpio_mem_res == NULL) { 306 device_printf(dev, "couldn't map memory\n"); 307 qcom_tlmm_ipq4018_detach(dev); 308 return (ENXIO); 309 } 310 311 if ((sc->gpio_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 312 &sc->gpio_irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 313 device_printf(dev, "unable to allocate IRQ resource\n"); 314 qcom_tlmm_ipq4018_detach(dev); 315 return (ENXIO); 316 } 317 318 if ((bus_setup_intr(dev, sc->gpio_irq_res, INTR_TYPE_MISC, 319 qcom_tlmm_filter, qcom_tlmm_intr, sc, &sc->gpio_ih))) { 320 device_printf(dev, 321 "WARNING: unable to register interrupt handler\n"); 322 qcom_tlmm_ipq4018_detach(dev); 323 return (ENXIO); 324 } 325 326 sc->dev = dev; 327 sc->gpio_npins = QCOM_TLMM_IPQ4018_GPIO_PINS; 328 sc->gpio_muxes = &gpio_muxes[0]; 329 sc->sc_debug = 0; 330 331 qcom_tlmm_debug_sysctl_attach(sc); 332 333 /* Allocate local pin state for all of our pins */ 334 sc->gpio_pins = malloc(sizeof(*sc->gpio_pins) * sc->gpio_npins, 335 M_DEVBUF, M_WAITOK | M_ZERO); 336 337 /* Note: direct map between gpio pin and gpio_pin[] entry */ 338 for (i = 0; i < sc->gpio_npins; i++) { 339 snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME, 340 "gpio%d", i); 341 sc->gpio_pins[i].gp_pin = i; 342 sc->gpio_pins[i].gp_caps = DEFAULT_CAPS; 343 (void) qcom_tlmm_pin_getflags(dev, i, 344 &sc->gpio_pins[i].gp_flags); 345 } 346 347 fdt_pinctrl_register(dev, NULL); 348 fdt_pinctrl_configure_by_name(dev, "default"); 349 350 sc->busdev = gpiobus_attach_bus(dev); 351 if (sc->busdev == NULL) { 352 device_printf(dev, "%s: failed to attach bus\n", __func__); 353 qcom_tlmm_ipq4018_detach(dev); 354 return (ENXIO); 355 } 356 357 return (0); 358 } 359 360 static device_method_t qcom_tlmm_ipq4018_methods[] = { 361 /* Driver */ 362 DEVMETHOD(device_probe, qcom_tlmm_ipq4018_probe), 363 DEVMETHOD(device_attach, qcom_tlmm_ipq4018_attach), 364 DEVMETHOD(device_detach, qcom_tlmm_ipq4018_detach), 365 366 /* GPIO protocol */ 367 DEVMETHOD(gpio_get_bus, qcom_tlmm_get_bus), 368 DEVMETHOD(gpio_pin_max, qcom_tlmm_pin_max), 369 DEVMETHOD(gpio_pin_getname, qcom_tlmm_pin_getname), 370 DEVMETHOD(gpio_pin_getflags, qcom_tlmm_pin_getflags), 371 DEVMETHOD(gpio_pin_getcaps, qcom_tlmm_pin_getcaps), 372 DEVMETHOD(gpio_pin_setflags, qcom_tlmm_pin_setflags), 373 DEVMETHOD(gpio_pin_get, qcom_tlmm_pin_get), 374 DEVMETHOD(gpio_pin_set, qcom_tlmm_pin_set), 375 DEVMETHOD(gpio_pin_toggle, qcom_tlmm_pin_toggle), 376 377 /* OFW */ 378 DEVMETHOD(ofw_bus_get_node, qcom_tlmm_pin_get_node), 379 380 /* fdt_pinctrl interface */ 381 DEVMETHOD(fdt_pinctrl_configure, qcom_tlmm_pinctrl_configure), 382 383 {0, 0}, 384 }; 385 386 static driver_t qcom_tlmm_ipq4018_driver = { 387 "gpio", 388 qcom_tlmm_ipq4018_methods, 389 sizeof(struct qcom_tlmm_softc), 390 }; 391 392 EARLY_DRIVER_MODULE(qcom_tlmm_ipq4018, simplebus, qcom_tlmm_ipq4018_driver, 393 NULL, NULL, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE); 394 EARLY_DRIVER_MODULE(qcom_tlmm_ipq4018, ofwbus, qcom_tlmm_ipq4018_driver, 395 NULL, NULL, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE); 396 MODULE_VERSION(qcom_tlmm_ipq4018, 1); 397