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