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