xref: /freebsd/sys/dev/qcom_tlmm/qcom_tlmm_ipq4018.c (revision edf8578117e8844e02c0121147f45e4609b30680)
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