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);
Cache object: 6b8ec00f8df728f96ac7311b6a2eb401
|