xref: /freebsd/sys/dev/qcom_tlmm/qcom_tlmm_ipq4018.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
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
qcom_tlmm_ipq4018_probe(device_t dev)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
qcom_tlmm_ipq4018_detach(device_t dev)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
qcom_tlmm_ipq4018_attach(device_t dev)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