xref: /freebsd/sys/dev/qcom_tlmm/qcom_tlmm_ipq4018.c (revision 38a52bd3b5cac3da6f7f6eef3dd050e6aa08ebb3)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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