14abe6533SAdrian Chadd /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
34abe6533SAdrian Chadd *
44abe6533SAdrian Chadd * Copyright (c) 2021 Adrian Chadd <adrian@FreeBSD.org>
54abe6533SAdrian Chadd *
64abe6533SAdrian Chadd * Redistribution and use in source and binary forms, with or without
74abe6533SAdrian Chadd * modification, are permitted provided that the following conditions
84abe6533SAdrian Chadd * are met:
94abe6533SAdrian Chadd * 1. Redistributions of source code must retain the above copyright
104abe6533SAdrian Chadd * notice unmodified, this list of conditions, and the following
114abe6533SAdrian Chadd * disclaimer.
124abe6533SAdrian Chadd * 2. Redistributions in binary form must reproduce the above copyright
134abe6533SAdrian Chadd * notice, this list of conditions and the following disclaimer in the
144abe6533SAdrian Chadd * documentation and/or other materials provided with the distribution.
154abe6533SAdrian Chadd *
164abe6533SAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
174abe6533SAdrian Chadd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
184abe6533SAdrian Chadd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
194abe6533SAdrian Chadd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
204abe6533SAdrian Chadd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
214abe6533SAdrian Chadd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
224abe6533SAdrian Chadd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
234abe6533SAdrian Chadd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
244abe6533SAdrian Chadd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
254abe6533SAdrian Chadd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
264abe6533SAdrian Chadd * SUCH DAMAGE.
274abe6533SAdrian Chadd */
284abe6533SAdrian Chadd
294abe6533SAdrian Chadd /*
304abe6533SAdrian Chadd * This is a pinmux/gpio controller for the IPQ4018/IPQ4019.
314abe6533SAdrian Chadd */
324abe6533SAdrian Chadd
334abe6533SAdrian Chadd #include <sys/param.h>
344abe6533SAdrian Chadd #include <sys/systm.h>
354abe6533SAdrian Chadd #include <sys/bus.h>
364abe6533SAdrian Chadd
374abe6533SAdrian Chadd #include <sys/kernel.h>
384abe6533SAdrian Chadd #include <sys/module.h>
394abe6533SAdrian Chadd #include <sys/rman.h>
404abe6533SAdrian Chadd #include <sys/lock.h>
414abe6533SAdrian Chadd #include <sys/malloc.h>
424abe6533SAdrian Chadd #include <sys/mutex.h>
434abe6533SAdrian Chadd #include <sys/gpio.h>
444abe6533SAdrian Chadd
454abe6533SAdrian Chadd #include <machine/bus.h>
464abe6533SAdrian Chadd #include <machine/resource.h>
474abe6533SAdrian Chadd #include <dev/gpio/gpiobusvar.h>
484abe6533SAdrian Chadd
494abe6533SAdrian Chadd #include <dev/fdt/fdt_common.h>
504abe6533SAdrian Chadd #include <dev/ofw/ofw_bus.h>
514abe6533SAdrian Chadd #include <dev/ofw/ofw_bus_subr.h>
524abe6533SAdrian Chadd
534abe6533SAdrian Chadd #include <dev/fdt/fdt_pinctrl.h>
544abe6533SAdrian Chadd
554abe6533SAdrian Chadd #include "qcom_tlmm_var.h"
564abe6533SAdrian Chadd #include "qcom_tlmm_pin.h"
574abe6533SAdrian Chadd #include "qcom_tlmm_debug.h"
584abe6533SAdrian Chadd
594abe6533SAdrian Chadd #include "qcom_tlmm_ipq4018_reg.h"
604abe6533SAdrian Chadd #include "qcom_tlmm_ipq4018_hw.h"
614abe6533SAdrian Chadd
624abe6533SAdrian Chadd #include "gpio_if.h"
634abe6533SAdrian Chadd
644abe6533SAdrian Chadd #define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | \
654abe6533SAdrian Chadd GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN)
664abe6533SAdrian Chadd
674abe6533SAdrian Chadd /* 100 GPIO pins, 0..99 */
684abe6533SAdrian Chadd #define QCOM_TLMM_IPQ4018_GPIO_PINS 100
694abe6533SAdrian Chadd
704abe6533SAdrian Chadd static const struct qcom_tlmm_gpio_mux gpio_muxes[] = {
714abe6533SAdrian Chadd GDEF(0, "jtag_tdi", "smart0", "i2s_rx_bclk"),
724abe6533SAdrian Chadd GDEF(1, "jtag_tck", "smart0", "i2s_rx_fsync"),
734abe6533SAdrian Chadd GDEF(2, "jtag_tms", "smart0", "i2s_rxd"),
744abe6533SAdrian Chadd GDEF(3, "jtag_tdo"),
754abe6533SAdrian Chadd GDEF(4, "jtag_rst"),
764abe6533SAdrian Chadd GDEF(5, "jtag_trst"),
774abe6533SAdrian Chadd GDEF(6, "mdio0", NULL, "wcss0_dbg18", "wcss1_dbg18", NULL,
784abe6533SAdrian Chadd "qdss_tracedata_a"),
794abe6533SAdrian Chadd GDEF(7, "mdc", NULL, "wcss0_dbg19", "wcss1_dbg19", NULL,
804abe6533SAdrian Chadd "qdss_tracedata_a"),
814abe6533SAdrian Chadd GDEF(8, "blsp_uart1", "wifi0_uart", "wifi1_uart", "smart1", NULL,
824abe6533SAdrian Chadd "wcss0_dbg20", "wcss1_dbg20", NULL, "qdss_tracedata_a"),
834abe6533SAdrian Chadd GDEF(9, "blsp_uart1", "wifi0_uart0", "wifi1_uart0", "smart1",
844abe6533SAdrian Chadd "wifi0_uart", NULL, "wcss0_dbg21", "wcss1_dbg21", NULL,
854abe6533SAdrian Chadd "qdss_tracedata_a"),
864abe6533SAdrian Chadd
874abe6533SAdrian Chadd GDEF(10, "blsp_uart1", "wifi0_uart0", "wifi1_uart0", "blsp_i2c0",
884abe6533SAdrian Chadd NULL, "wcss0_dbg22", "wcss1_dbg22", NULL, "qdss_tracedata_a"),
894abe6533SAdrian Chadd GDEF(11, "blsp_uart1", "wifi0_uart", "wifi1_uart", "blsp_i2c0",
904abe6533SAdrian Chadd NULL, "wcss0_dbg23", "wcss1_dbg23", NULL, "qdss_tracedata_a"),
914abe6533SAdrian Chadd GDEF(12, "blsp_spi0", "blsp_i2c1", NULL, "wcss0_dbg24",
924abe6533SAdrian Chadd "wcss1_dbg24"),
934abe6533SAdrian Chadd GDEF(13, "blsp_spi0", "blsp_i2c1", NULL, "wcss0_dbg25",
944abe6533SAdrian Chadd "wcss1_dbg25"),
954abe6533SAdrian Chadd GDEF(14, "blsp_spi0", NULL, "wcss0_dbg26", "wcss1_dbg26"),
964abe6533SAdrian Chadd GDEF(15, "blsp_spi0", NULL, "wcss0_dbg", "wcss1_dbg"),
974abe6533SAdrian Chadd GDEF(16, "blsp_uart0", "led0", "smart1", NULL, "wcss0_dbg28",
984abe6533SAdrian Chadd "wcss1_dbg28", NULL, "qdss_tracedata_a"),
994abe6533SAdrian Chadd GDEF(17, "blsp_uart0", "led1", "smart1", NULL, "wcss0_dbg29",
1004abe6533SAdrian Chadd "wcss1_dbg29", NULL, "qdss_tracedata_a"),
1014abe6533SAdrian Chadd GDEF(18, "wifi0_uart1", "wifi1_uart1", NULL, "wcss0_dbg30",
1024abe6533SAdrian Chadd "wcss1_dbg30"),
1034abe6533SAdrian Chadd GDEF(19, "wifi0_uart", "wifi1_uart", NULL, "wcss0_dbg31",
1044abe6533SAdrian Chadd "wcss1_dbg31"),
1054abe6533SAdrian Chadd
1064abe6533SAdrian Chadd GDEF(20, "blsp_i2c0", "i2s_rx_mclk", NULL, "wcss0_dbg16",
1074abe6533SAdrian Chadd "wcss1_dbg16"),
1084abe6533SAdrian Chadd GDEF(21, "blsp_i2c0", "i2s_rx_bclk", NULL, "wcss0_dbg17",
1094abe6533SAdrian Chadd "wcss1_dbg17"),
1104abe6533SAdrian Chadd GDEF(22, "rgmii0", "i2s_rx_fsync", NULL, "wcss0_dbg18",
1114abe6533SAdrian Chadd "wcss1_dbg18"),
1124abe6533SAdrian Chadd GDEF(23, "sdio0", "rgmii1", "i2s_rxd", NULL, "wcss0_dbg19",
1134abe6533SAdrian Chadd "wcss1_dbg19"),
1144abe6533SAdrian Chadd GDEF(24, "sdio1", "rgmii2", "i2s_tx_mclk", NULL, "wcss0_dbg20",
1154abe6533SAdrian Chadd "wcss1_dbg20"),
1164abe6533SAdrian Chadd GDEF(25, "sdio2", "rgmii3", "i2s_tx_bclk", NULL, "wcss0_dbg21",
1174abe6533SAdrian Chadd "wcss1_dbg21"),
1184abe6533SAdrian Chadd GDEF(26, "sdio3", "rgmii_rx", "i2s_tx_fsync", NULL, "wcss0_dbg22",
1194abe6533SAdrian Chadd "wcss1_dbg22"),
1204abe6533SAdrian Chadd GDEF(27, "sdio_clk", "rgmii_txc", "i2s_tdl", NULL, "wcss0_dbg23",
1214abe6533SAdrian Chadd "wcss1_dbg23"),
1224abe6533SAdrian Chadd GDEF(28, "sdio_cmd", "rgmii0", "i2s_td2", NULL, "wcss0_dbg24",
1234abe6533SAdrian Chadd "wcss1_dbg24"),
1244abe6533SAdrian Chadd GDEF(29, "sdio4", "rgmii1", "i2s_td3", NULL, "wcss0_dbg25",
1254abe6533SAdrian Chadd "wcss1_dbg25"),
1264abe6533SAdrian Chadd
1274abe6533SAdrian Chadd GDEF(30, "sdio5", "rgmii2", "audio_pwm0", NULL, "wcss0_dbg26",
1284abe6533SAdrian Chadd "wcss1_dbg26"),
1294abe6533SAdrian Chadd GDEF(31, "sdio6", "rgmii3", "audio_pwm1", NULL, "wcss0_dbg27",
1304abe6533SAdrian Chadd "wcss1_dbg27"),
1314abe6533SAdrian Chadd GDEF(32, "sdio7", "rgmii_rxc", "audio_pwm2", NULL, "wcss0_dbg28",
1324abe6533SAdrian Chadd "wcss1_dbg28"),
1334abe6533SAdrian Chadd GDEF(33, "rgmii_tx", "audio_pwm3", NULL, "wcss0_dbg29",
1344abe6533SAdrian Chadd "wcss1_dbg29", NULL, "boot2"),
1354abe6533SAdrian Chadd GDEF(34, "blsp_i2c1", "i2s_spdif_in", NULL, "wcss0_dbg30",
1364abe6533SAdrian Chadd "wcss1_dbg30"),
1374abe6533SAdrian Chadd GDEF(35, "blsp_i2c1", "i2s_spdif_out", NULL, "wcss0_dbg31",
1384abe6533SAdrian Chadd "wcss1_dbg31"),
1394abe6533SAdrian Chadd GDEF(36, "rmii00", "led2", "led0"),
1404abe6533SAdrian Chadd GDEF(37, "rmii01", "wifi0_wci", "wifi1_wci", "led1", NULL, NULL,
1414abe6533SAdrian Chadd "wcss0_dbg16", "wcss1_dbg16", NULL, "qdss_tracedata_a", "boot4"),
1424abe6533SAdrian Chadd GDEF(38, "rmii0_tx", "led2", NULL, NULL, "wcss0_dbg17",
1434abe6533SAdrian Chadd "wcss1_dbg17", NULL, "qdss_tracedata_a", "boot5"),
1444abe6533SAdrian Chadd GDEF(39, "rmii0_rx", "pcie_clk1", "led3", NULL, NULL, "wcss0_dbg18",
1454abe6533SAdrian Chadd "wcss1_dbg18", NULL, NULL, "qdss_tracedata_a"),
1464abe6533SAdrian Chadd
1474abe6533SAdrian Chadd GDEF(40, "rmii0_refclk", "wifi0_rfsilent0", "wifi1_rfsilent0",
1484abe6533SAdrian Chadd "smart2", "led4", NULL, NULL, "wcss0_dbg19", "wcss1_dbg19", NULL,
1494abe6533SAdrian Chadd NULL, "qdss_tracedata_a"),
1504abe6533SAdrian Chadd GDEF(41, "rmii00", "wifi0_cal", "wifi1_cal", "smart2", NULL, NULL,
1514abe6533SAdrian Chadd "wcss0_dbg20", "wcss1_dbg20", NULL, NULL, "qdss_tracedata_a"),
1524abe6533SAdrian Chadd GDEF(42, "rmii01", "wifi_wci0", NULL, NULL, "wcss0_dbg21",
1534abe6533SAdrian Chadd "wcss1_dbg21", NULL, NULL, "qdss_tracedata_a"),
1544abe6533SAdrian Chadd GDEF(43, "rmii0_dv", "wifi_wci1", NULL, NULL, "wcss0_dbg22",
1554abe6533SAdrian Chadd "wcss1_dbg22", NULL, NULL, "qdss_tracedata_a"),
1564abe6533SAdrian Chadd GDEF(44, "rmii1_refclk", "blsp_spi1", "smart0", "led5", NULL, NULL,
1574abe6533SAdrian Chadd "wcss0_dbg23", "wcss1_dbg23"),
1584abe6533SAdrian Chadd GDEF(45, "rmii10", "blsp_spi1", "smart0", "led6", NULL, NULL,
1594abe6533SAdrian Chadd "wcss0_dbg24", "wcss1_dbg24"),
1604abe6533SAdrian Chadd GDEF(46, "rmii11", "blsp_spi1", "smart0", "led7", NULL, NULL,
1614abe6533SAdrian Chadd "wcss0_dbg25", "wcss1_dbg25"),
1624abe6533SAdrian Chadd GDEF(47, "rmii1_dv", "blsp_spi1", "smart0", "led8", NULL, NULL,
1634abe6533SAdrian Chadd "wcss0_dbg26", "wcss1_dbg26"),
1644abe6533SAdrian Chadd GDEF(48, "rmii1_tx", "aud_pin", "smart2", "led9", NULL, NULL,
1654abe6533SAdrian Chadd "wcss0_dbg27", "wcss1_dbg27"),
1664abe6533SAdrian Chadd GDEF(49, "rmii1_rx", "aud_pin", "smart2", "led10", NULL, NULL,
1674abe6533SAdrian Chadd "wcss0_dbg28", "wcss1_dbg28"),
1684abe6533SAdrian Chadd
1694abe6533SAdrian Chadd GDEF(50, "rmii10", "aud_pin", "wifi0_rfsilent1", "wifi1_rfsilent1",
1704abe6533SAdrian Chadd "led11", NULL, NULL, "wcss0_dbg29", "wcss1_dbg29"),
1714abe6533SAdrian Chadd GDEF(51, "rmii11", "aud_pin", "wifi0_cal", "wifi1_cal", NULL, NULL,
1724abe6533SAdrian Chadd "wcss0_dbg30", "wcss1_dbg30", NULL, "boot7"),
1734abe6533SAdrian Chadd GDEF(52, "qpic_pad", "mdc", "pcie_clk", "i2s_tx_mclk", NULL, NULL,
1744abe6533SAdrian Chadd "wcss0_dbg31", "tm_clk0", "wifi00", "wifi10"),
1754abe6533SAdrian Chadd GDEF(53, "qpic_pad", "mdio1", "i2s_tx_bclk", "prng_rsoc", "dbg_out",
1764abe6533SAdrian Chadd "tm0", "wifi01", "wifi11"),
1774abe6533SAdrian Chadd GDEF(54, "qpic_pad", "blsp_spi0", "i2s_tdl", "atest_char3", "pmu0",
1784abe6533SAdrian Chadd NULL, NULL, "boot8", "tm1"),
1794abe6533SAdrian Chadd GDEF(55, "qpic_pad", "blsp_spi0", "i2s_td2", "atest_char2", "pmu1",
1804abe6533SAdrian Chadd NULL, NULL, "boot9", "tm2"),
1814abe6533SAdrian Chadd GDEF(56, "qpic_pad", "blsp_spi0", "i2s_td3", "atest_char1", NULL,
1824abe6533SAdrian Chadd "tm_ack", "wifi03", "wifi13"),
1834abe6533SAdrian Chadd GDEF(57, "qpic_pad4", "blsp_spi0", "i2s_tx_fsync", "atest_char0",
1844abe6533SAdrian Chadd NULL, "tm3", "wifi02", "wifi12"),
1854abe6533SAdrian Chadd GDEF(58, "qpic_pad5", "led2", "blsp_i2c0", "smart3", "smart1",
1864abe6533SAdrian Chadd "i2s_rx_mclk", NULL, "wcss0_dbg14", "tm4", "wifi04", "wifi14"),
1874abe6533SAdrian Chadd GDEF(59, "qpic_pad6", "blsp_i2c0", "smart3", "smart1", "i2c_spdif_in",
1884abe6533SAdrian Chadd NULL, NULL, "wcss0_dbg15", "qdss_tracectl_a", "boot18", "tm5" ),
1894abe6533SAdrian Chadd
1904abe6533SAdrian Chadd GDEF(60, "qpic_pad7", "blsp_uart0", "smart1", "smart3", "led0",
1914abe6533SAdrian Chadd "i2s_tx_bclk", "i2s_rx_bclk", "atest_char", NULL, "wcss0_dbg4",
1924abe6533SAdrian Chadd "qdss_traceclk_a", "boot19", "tm6" ),
1934abe6533SAdrian Chadd GDEF(61, "qpic_pad", "blsp_uart0", "smart1", "smart3", "led1",
1944abe6533SAdrian Chadd "i2s_tx_fsync", "i2s_rx_fsync", NULL, NULL, "wcss0_dbg5",
1954abe6533SAdrian Chadd "qdss_cti_trig_out_a0", "boot14", "tm7"),
1964abe6533SAdrian Chadd GDEF(62, "qpic_pad", "chip_rst", "wifi0_uart", "wifi1_uart",
1974abe6533SAdrian Chadd "i2s_spdif_out", NULL, NULL, "wcss0_dbg6", "qdss_cti_trig_out_b0",
1984abe6533SAdrian Chadd "boot11", "tm8"),
1994abe6533SAdrian Chadd GDEF(63, "qpic_pad", "wifi0_uart1", "wifi1_uart1", "wifi1_uart",
2004abe6533SAdrian Chadd "i2s_tdl", "i2s_rxd", "i2s_spdif_out", "i2s_spdif_in", NULL,
2014abe6533SAdrian Chadd "wcss0_dbg7", "wcss1_dbg7", "boot20", "tm9"),
2024abe6533SAdrian Chadd GDEF(64, "qpic_pad1", "audio_pwm0", NULL, "wcss0_dbg8", "wcss1_dbg8"),
2034abe6533SAdrian Chadd GDEF(65, "qpic_pad2", "audio_pwm1", NULL, "wcss0_dbg9",
2044abe6533SAdrian Chadd "wcss1_dbg9" ),
2054abe6533SAdrian Chadd GDEF(66, "qpic_pad3", "audio_pwm2", NULL, "wcss0_dbg10",
2064abe6533SAdrian Chadd "wcss1_dbg10"),
2074abe6533SAdrian Chadd GDEF(67, "qpic_pad0", "audio_pwm3", NULL, "wcss0_dbg11",
2084abe6533SAdrian Chadd "wcss1_dbg11"),
2094abe6533SAdrian Chadd GDEF(68, "qpic_pad8", NULL, "wcss0_dbg12", "wcss1_dbg12"),
2104abe6533SAdrian Chadd GDEF(69, "qpic_pad", NULL, "wcss0_dbg"),
2114abe6533SAdrian Chadd
2124abe6533SAdrian Chadd GDEF(70),
2134abe6533SAdrian Chadd GDEF(71),
2144abe6533SAdrian Chadd GDEF(72),
2154abe6533SAdrian Chadd GDEF(73),
2164abe6533SAdrian Chadd GDEF(74),
2174abe6533SAdrian Chadd GDEF(75),
2184abe6533SAdrian Chadd GDEF(76),
2194abe6533SAdrian Chadd GDEF(77),
2204abe6533SAdrian Chadd GDEF(78),
2214abe6533SAdrian Chadd GDEF(79),
2224abe6533SAdrian Chadd
2234abe6533SAdrian Chadd GDEF(80),
2244abe6533SAdrian Chadd GDEF(81),
2254abe6533SAdrian Chadd GDEF(82),
2264abe6533SAdrian Chadd GDEF(83),
2274abe6533SAdrian Chadd GDEF(84),
2284abe6533SAdrian Chadd GDEF(85),
2294abe6533SAdrian Chadd GDEF(86),
2304abe6533SAdrian Chadd GDEF(87),
2314abe6533SAdrian Chadd GDEF(88),
2324abe6533SAdrian Chadd GDEF(89),
2334abe6533SAdrian Chadd
2344abe6533SAdrian Chadd GDEF(90),
2354abe6533SAdrian Chadd GDEF(91),
2364abe6533SAdrian Chadd GDEF(92),
2374abe6533SAdrian Chadd GDEF(93),
2384abe6533SAdrian Chadd GDEF(94),
2394abe6533SAdrian Chadd GDEF(95),
2404abe6533SAdrian Chadd GDEF(96),
2414abe6533SAdrian Chadd GDEF(97),
2424abe6533SAdrian Chadd GDEF(98, "wifi034", "wifi134"),
2434abe6533SAdrian Chadd GDEF(99),
2444abe6533SAdrian Chadd
2454abe6533SAdrian Chadd GDEF(-1),
2464abe6533SAdrian Chadd };
2474abe6533SAdrian Chadd
2484abe6533SAdrian Chadd static int
qcom_tlmm_ipq4018_probe(device_t dev)2494abe6533SAdrian Chadd qcom_tlmm_ipq4018_probe(device_t dev)
2504abe6533SAdrian Chadd {
2514abe6533SAdrian Chadd
2524abe6533SAdrian Chadd if (! ofw_bus_status_okay(dev))
2534abe6533SAdrian Chadd return (ENXIO);
2544abe6533SAdrian Chadd
2554abe6533SAdrian Chadd if (ofw_bus_is_compatible(dev, "qcom,ipq4019-pinctrl") == 0)
2564abe6533SAdrian Chadd return (ENXIO);
2574abe6533SAdrian Chadd
2584abe6533SAdrian Chadd device_set_desc(dev,
2594abe6533SAdrian Chadd "Qualcomm Atheross TLMM IPQ4018/IPQ4019 GPIO/Pinmux driver");
2604abe6533SAdrian Chadd return (0);
2614abe6533SAdrian Chadd }
2624abe6533SAdrian Chadd
2634abe6533SAdrian Chadd static int
qcom_tlmm_ipq4018_detach(device_t dev)2644abe6533SAdrian Chadd qcom_tlmm_ipq4018_detach(device_t dev)
2654abe6533SAdrian Chadd {
2664abe6533SAdrian Chadd struct qcom_tlmm_softc *sc = device_get_softc(dev);
2674abe6533SAdrian Chadd
2684abe6533SAdrian Chadd KASSERT(mtx_initialized(&sc->gpio_mtx), ("gpio mutex not initialized"));
2694abe6533SAdrian Chadd
2704abe6533SAdrian Chadd gpiobus_detach_bus(dev);
2714abe6533SAdrian Chadd if (sc->gpio_ih)
2724abe6533SAdrian Chadd bus_teardown_intr(dev, sc->gpio_irq_res, sc->gpio_ih);
2734abe6533SAdrian Chadd if (sc->gpio_irq_res)
2744abe6533SAdrian Chadd bus_release_resource(dev, SYS_RES_IRQ, sc->gpio_irq_rid,
2754abe6533SAdrian Chadd sc->gpio_irq_res);
2764abe6533SAdrian Chadd if (sc->gpio_mem_res)
2774abe6533SAdrian Chadd bus_release_resource(dev, SYS_RES_MEMORY, sc->gpio_mem_rid,
2784abe6533SAdrian Chadd sc->gpio_mem_res);
2794abe6533SAdrian Chadd if (sc->gpio_pins)
2804abe6533SAdrian Chadd free(sc->gpio_pins, M_DEVBUF);
2814abe6533SAdrian Chadd mtx_destroy(&sc->gpio_mtx);
2824abe6533SAdrian Chadd
2834abe6533SAdrian Chadd return(0);
2844abe6533SAdrian Chadd }
2854abe6533SAdrian Chadd
2864abe6533SAdrian Chadd
2874abe6533SAdrian Chadd
2884abe6533SAdrian Chadd static int
qcom_tlmm_ipq4018_attach(device_t dev)2894abe6533SAdrian Chadd qcom_tlmm_ipq4018_attach(device_t dev)
2904abe6533SAdrian Chadd {
2914abe6533SAdrian Chadd struct qcom_tlmm_softc *sc = device_get_softc(dev);
2924abe6533SAdrian Chadd int i;
2934abe6533SAdrian Chadd
2944abe6533SAdrian Chadd KASSERT((device_get_unit(dev) == 0),
2954abe6533SAdrian Chadd ("qcom_tlmm_ipq4018: Only one gpio module supported"));
2964abe6533SAdrian Chadd
2974abe6533SAdrian Chadd mtx_init(&sc->gpio_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
2984abe6533SAdrian Chadd
2994abe6533SAdrian Chadd /* Map control/status registers. */
3004abe6533SAdrian Chadd sc->gpio_mem_rid = 0;
3014abe6533SAdrian Chadd sc->gpio_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
3024abe6533SAdrian Chadd &sc->gpio_mem_rid, RF_ACTIVE);
3034abe6533SAdrian Chadd
3044abe6533SAdrian Chadd if (sc->gpio_mem_res == NULL) {
3054abe6533SAdrian Chadd device_printf(dev, "couldn't map memory\n");
3064abe6533SAdrian Chadd qcom_tlmm_ipq4018_detach(dev);
3074abe6533SAdrian Chadd return (ENXIO);
3084abe6533SAdrian Chadd }
3094abe6533SAdrian Chadd
3104abe6533SAdrian Chadd if ((sc->gpio_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
3114abe6533SAdrian Chadd &sc->gpio_irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
3124abe6533SAdrian Chadd device_printf(dev, "unable to allocate IRQ resource\n");
3134abe6533SAdrian Chadd qcom_tlmm_ipq4018_detach(dev);
3144abe6533SAdrian Chadd return (ENXIO);
3154abe6533SAdrian Chadd }
3164abe6533SAdrian Chadd
3174abe6533SAdrian Chadd if ((bus_setup_intr(dev, sc->gpio_irq_res, INTR_TYPE_MISC,
3184abe6533SAdrian Chadd qcom_tlmm_filter, qcom_tlmm_intr, sc, &sc->gpio_ih))) {
3194abe6533SAdrian Chadd device_printf(dev,
3204abe6533SAdrian Chadd "WARNING: unable to register interrupt handler\n");
3214abe6533SAdrian Chadd qcom_tlmm_ipq4018_detach(dev);
3224abe6533SAdrian Chadd return (ENXIO);
3234abe6533SAdrian Chadd }
3244abe6533SAdrian Chadd
3254abe6533SAdrian Chadd sc->dev = dev;
3264abe6533SAdrian Chadd sc->gpio_npins = QCOM_TLMM_IPQ4018_GPIO_PINS;
3274abe6533SAdrian Chadd sc->gpio_muxes = &gpio_muxes[0];
3284abe6533SAdrian Chadd sc->sc_debug = 0;
3294abe6533SAdrian Chadd
3304abe6533SAdrian Chadd qcom_tlmm_debug_sysctl_attach(sc);
3314abe6533SAdrian Chadd
3324abe6533SAdrian Chadd /* Allocate local pin state for all of our pins */
3334abe6533SAdrian Chadd sc->gpio_pins = malloc(sizeof(*sc->gpio_pins) * sc->gpio_npins,
3344abe6533SAdrian Chadd M_DEVBUF, M_WAITOK | M_ZERO);
3354abe6533SAdrian Chadd
3364abe6533SAdrian Chadd /* Note: direct map between gpio pin and gpio_pin[] entry */
3374abe6533SAdrian Chadd for (i = 0; i < sc->gpio_npins; i++) {
3384abe6533SAdrian Chadd snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME,
3394abe6533SAdrian Chadd "gpio%d", i);
3404abe6533SAdrian Chadd sc->gpio_pins[i].gp_pin = i;
3414abe6533SAdrian Chadd sc->gpio_pins[i].gp_caps = DEFAULT_CAPS;
3424abe6533SAdrian Chadd (void) qcom_tlmm_pin_getflags(dev, i,
3434abe6533SAdrian Chadd &sc->gpio_pins[i].gp_flags);
3444abe6533SAdrian Chadd }
3454abe6533SAdrian Chadd
3464abe6533SAdrian Chadd fdt_pinctrl_register(dev, NULL);
3474abe6533SAdrian Chadd fdt_pinctrl_configure_by_name(dev, "default");
3484abe6533SAdrian Chadd
3494abe6533SAdrian Chadd sc->busdev = gpiobus_attach_bus(dev);
3504abe6533SAdrian Chadd if (sc->busdev == NULL) {
3514abe6533SAdrian Chadd device_printf(dev, "%s: failed to attach bus\n", __func__);
3524abe6533SAdrian Chadd qcom_tlmm_ipq4018_detach(dev);
3534abe6533SAdrian Chadd return (ENXIO);
3544abe6533SAdrian Chadd }
3554abe6533SAdrian Chadd
3564abe6533SAdrian Chadd return (0);
3574abe6533SAdrian Chadd }
3584abe6533SAdrian Chadd
3594abe6533SAdrian Chadd static device_method_t qcom_tlmm_ipq4018_methods[] = {
3604abe6533SAdrian Chadd /* Driver */
3614abe6533SAdrian Chadd DEVMETHOD(device_probe, qcom_tlmm_ipq4018_probe),
3624abe6533SAdrian Chadd DEVMETHOD(device_attach, qcom_tlmm_ipq4018_attach),
3634abe6533SAdrian Chadd DEVMETHOD(device_detach, qcom_tlmm_ipq4018_detach),
3644abe6533SAdrian Chadd
3654abe6533SAdrian Chadd /* GPIO protocol */
3664abe6533SAdrian Chadd DEVMETHOD(gpio_get_bus, qcom_tlmm_get_bus),
3674abe6533SAdrian Chadd DEVMETHOD(gpio_pin_max, qcom_tlmm_pin_max),
3684abe6533SAdrian Chadd DEVMETHOD(gpio_pin_getname, qcom_tlmm_pin_getname),
3694abe6533SAdrian Chadd DEVMETHOD(gpio_pin_getflags, qcom_tlmm_pin_getflags),
3704abe6533SAdrian Chadd DEVMETHOD(gpio_pin_getcaps, qcom_tlmm_pin_getcaps),
3714abe6533SAdrian Chadd DEVMETHOD(gpio_pin_setflags, qcom_tlmm_pin_setflags),
3724abe6533SAdrian Chadd DEVMETHOD(gpio_pin_get, qcom_tlmm_pin_get),
3734abe6533SAdrian Chadd DEVMETHOD(gpio_pin_set, qcom_tlmm_pin_set),
3744abe6533SAdrian Chadd DEVMETHOD(gpio_pin_toggle, qcom_tlmm_pin_toggle),
3754abe6533SAdrian Chadd
3764abe6533SAdrian Chadd /* OFW */
3774abe6533SAdrian Chadd DEVMETHOD(ofw_bus_get_node, qcom_tlmm_pin_get_node),
3784abe6533SAdrian Chadd
3794abe6533SAdrian Chadd /* fdt_pinctrl interface */
3804abe6533SAdrian Chadd DEVMETHOD(fdt_pinctrl_configure, qcom_tlmm_pinctrl_configure),
3814abe6533SAdrian Chadd
3824abe6533SAdrian Chadd {0, 0},
3834abe6533SAdrian Chadd };
3844abe6533SAdrian Chadd
3854abe6533SAdrian Chadd static driver_t qcom_tlmm_ipq4018_driver = {
3864abe6533SAdrian Chadd "gpio",
3874abe6533SAdrian Chadd qcom_tlmm_ipq4018_methods,
3884abe6533SAdrian Chadd sizeof(struct qcom_tlmm_softc),
3894abe6533SAdrian Chadd };
3904abe6533SAdrian Chadd
3914abe6533SAdrian Chadd EARLY_DRIVER_MODULE(qcom_tlmm_ipq4018, simplebus, qcom_tlmm_ipq4018_driver,
39253e1cbefSJohn Baldwin NULL, NULL, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);
3934abe6533SAdrian Chadd EARLY_DRIVER_MODULE(qcom_tlmm_ipq4018, ofwbus, qcom_tlmm_ipq4018_driver,
39453e1cbefSJohn Baldwin NULL, NULL, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);
3954abe6533SAdrian Chadd MODULE_VERSION(qcom_tlmm_ipq4018, 1);
396