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