1 /*
2 * Copyright (c) 2016 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Imre Vadász <imre@vdsz.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34 /*
35 * Intel SoC gpio driver.
36 */
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/kernel.h>
41 #include <sys/module.h>
42 #include <sys/errno.h>
43 #include <sys/lock.h>
44 #include <sys/bus.h>
45
46 #include <sys/rman.h>
47
48 #include "opt_acpi.h"
49 #include "acpi.h"
50 #include <dev/acpica/acpivar.h>
51
52 #include <bus/pci/pcivar.h>
53
54 #include "gpio_intel_var.h"
55
56 #include "gpio_if.h"
57
58 static int gpio_intel_probe(device_t dev);
59 static int gpio_intel_attach(device_t dev);
60 static int gpio_intel_detach(device_t dev);
61 static int gpio_intel_alloc_intr(device_t dev, u_int pin, int trigger,
62 int polarity, int termination, void **cookiep);
63 static void gpio_intel_setup_intr(device_t dev, void *cookie, void *arg,
64 driver_intr_t *handler);
65 static void gpio_intel_teardown_intr(device_t dev, void *cookie);
66 static void gpio_intel_free_intr(device_t dev, void *cookie);
67 static int gpio_intel_alloc_io_pin(device_t dev, u_int pin, int flags,
68 void **cookiep);
69 static void gpio_intel_release_io_pin(device_t dev, void *cookie);
70 static int gpio_intel_read_pin(device_t dev, void *cookie);
71 static void gpio_intel_write_pin(device_t dev, void *cookie, int value);
72
73 static void gpio_intel_intr(void *arg);
74 static int gpio_intel_pin_exists(struct gpio_intel_softc *sc,
75 uint16_t pin);
76
77 static char *cherryview_ids[] = { "INT33FF", NULL };
78
79 static int
gpio_intel_probe(device_t dev)80 gpio_intel_probe(device_t dev)
81 {
82
83 if (acpi_disabled("gpio_intel") ||
84 ACPI_ID_PROBE(device_get_parent(dev), dev, cherryview_ids) == NULL)
85 return (ENXIO);
86
87 device_set_desc(dev, "Intel Cherry Trail GPIO Controller");
88
89 return (BUS_PROBE_DEFAULT);
90 }
91
92 static int
gpio_intel_attach(device_t dev)93 gpio_intel_attach(device_t dev)
94 {
95 struct gpio_intel_softc *sc = device_get_softc(dev);
96 int error, i, rid;
97
98 lockinit(&sc->lk, "gpio_intel", 0, LK_CANRECURSE);
99
100 sc->dev = dev;
101
102 if (ACPI_ID_PROBE(device_get_parent(dev), dev, cherryview_ids)
103 != NULL) {
104 error = gpio_cherryview_matchuid(sc);
105 if (error) {
106 error = ENXIO;
107 goto err;
108 }
109 } else {
110 error = ENXIO;
111 goto err;
112 }
113
114 for (i = 0; i < NELEM(sc->intrmaps); i++) {
115 sc->intrmaps[i].pin = -1;
116 }
117 for (i = 0; i < NELEM(sc->iomaps); i++) {
118 sc->iomaps[i].pin = -1;
119 }
120
121 rid = 0;
122 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
123 &rid, RF_ACTIVE);
124 if (sc->mem_res == NULL) {
125 device_printf(dev, "unable to map registers");
126 error = ENXIO;
127 goto err;
128 }
129 rid = 0;
130 sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
131 &rid, RF_ACTIVE);
132 if (sc->irq_res == NULL) {
133 device_printf(dev, "unable to map interrupt");
134 error = ENXIO;
135 goto err;
136 }
137
138 lockmgr(&sc->lk, LK_EXCLUSIVE);
139 /* Activate the interrupt */
140 error = bus_setup_intr(dev, sc->irq_res, INTR_MPSAFE,
141 gpio_intel_intr, sc, &sc->intrhand, NULL);
142 if (error)
143 device_printf(dev, "Can't setup IRQ\n");
144
145 /* power up the controller */
146 pci_set_powerstate(dev, PCI_POWERSTATE_D0);
147
148 sc->fns->init(sc);
149 lockmgr(&sc->lk, LK_RELEASE);
150
151 device_add_child(dev, "gpio_acpi", -1);
152 bus_generic_attach(dev);
153
154 return (0);
155
156 err:
157 if (sc->irq_res) {
158 bus_release_resource(dev, SYS_RES_IRQ,
159 rman_get_rid(sc->irq_res), sc->irq_res);
160 sc->irq_res = NULL;
161 }
162 if (sc->mem_res) {
163 bus_release_resource(dev, SYS_RES_MEMORY,
164 rman_get_rid(sc->mem_res), sc->mem_res);
165 sc->mem_res = NULL;
166 }
167 return (error);
168 }
169
170 static int
gpio_intel_detach(device_t dev)171 gpio_intel_detach(device_t dev)
172 {
173 struct gpio_intel_softc *sc = device_get_softc(dev);
174 int error;
175
176 error = bus_generic_detach(dev);
177 if (error)
178 return (error);
179
180 device_delete_children(dev);
181
182 bus_teardown_intr(dev, sc->irq_res, sc->intrhand);
183 if (sc->irq_res) {
184 bus_release_resource(dev, SYS_RES_IRQ,
185 rman_get_rid(sc->irq_res), sc->irq_res);
186 sc->irq_res = NULL;
187 }
188 if (sc->mem_res) {
189 bus_release_resource(dev, SYS_RES_MEMORY,
190 rman_get_rid(sc->mem_res), sc->mem_res);
191 sc->mem_res = NULL;
192 }
193 lockuninit(&sc->lk);
194
195 pci_set_powerstate(dev, PCI_POWERSTATE_D3);
196
197 return 0;
198 }
199
200 /*
201 * The trigger, polarity and termination parameters are only used for
202 * sanity checking. The gpios should already be configured correctly by
203 * the firmware.
204 */
205 static int
gpio_intel_alloc_intr(device_t dev,u_int pin,int trigger,int polarity,int termination,void ** cookiep)206 gpio_intel_alloc_intr(device_t dev, u_int pin, int trigger, int polarity,
207 int termination, void **cookiep)
208 {
209 struct gpio_intel_softc *sc = device_get_softc(dev);
210 struct pin_intr_map *map = NULL;
211 int i, ret;
212
213 if (cookiep == NULL)
214 return (EINVAL);
215
216 lockmgr(&sc->lk, LK_EXCLUSIVE);
217
218 if (gpio_intel_pin_exists(sc, pin)) {
219 /* Make sure this pin isn't mapped yet */
220 for (i = 0; i < NELEM(sc->intrmaps); i++) {
221 if (sc->intrmaps[i].pin == pin) {
222 lockmgr(&sc->lk, LK_RELEASE);
223 return (EBUSY);
224 }
225 }
226 ret = sc->fns->map_intr(sc, pin, trigger, polarity,
227 termination);
228 if (ret == 0) {
229 /* XXX map_intr should return the pin_intr_map */
230 for (i = 0; i < NELEM(sc->intrmaps); i++) {
231 if (sc->intrmaps[i].pin == pin)
232 map = &sc->intrmaps[i];
233 }
234 if (map != NULL) {
235 *cookiep = map;
236 map->arg = NULL;
237 map->handler = NULL;
238 }
239 }
240 } else {
241 device_printf(sc->dev, "%s: Invalid pin %d\n", __func__, pin);
242 ret = ENOENT;
243 }
244
245 lockmgr(&sc->lk, LK_RELEASE);
246
247 return (ret);
248 }
249
250 static void
gpio_intel_free_intr(device_t dev,void * cookie)251 gpio_intel_free_intr(device_t dev, void *cookie)
252 {
253 struct gpio_intel_softc *sc = device_get_softc(dev);
254 struct pin_intr_map *map = (struct pin_intr_map *)cookie;
255
256 KKASSERT(gpio_intel_pin_exists(sc, map->pin));
257
258 lockmgr(&sc->lk, LK_EXCLUSIVE);
259 map->arg = NULL;
260 map->handler = NULL;
261 sc->fns->unmap_intr(sc, map);
262 lockmgr(&sc->lk, LK_RELEASE);
263 }
264
265 static void
gpio_intel_setup_intr(device_t dev,void * cookie,void * arg,driver_intr_t * handler)266 gpio_intel_setup_intr(device_t dev, void *cookie, void *arg,
267 driver_intr_t *handler)
268 {
269 struct gpio_intel_softc *sc = device_get_softc(dev);
270 struct pin_intr_map *map = (struct pin_intr_map *)cookie;
271
272 KKASSERT(gpio_intel_pin_exists(sc, map->pin));
273
274 lockmgr(&sc->lk, LK_EXCLUSIVE);
275 map->arg = arg;
276 map->handler = handler;
277 sc->fns->enable_intr(sc, map);
278 lockmgr(&sc->lk, LK_RELEASE);
279 }
280
281 static void
gpio_intel_teardown_intr(device_t dev,void * cookie)282 gpio_intel_teardown_intr(device_t dev, void *cookie)
283 {
284 struct gpio_intel_softc *sc = device_get_softc(dev);
285 struct pin_intr_map *map = (struct pin_intr_map *)cookie;
286
287 KKASSERT(gpio_intel_pin_exists(sc, map->pin));
288
289 lockmgr(&sc->lk, LK_EXCLUSIVE);
290 sc->fns->disable_intr(sc, map);
291 map->arg = NULL;
292 map->handler = NULL;
293 lockmgr(&sc->lk, LK_RELEASE);
294 }
295
296 static int
gpio_intel_alloc_io_pin(device_t dev,u_int pin,int flags,void ** cookiep)297 gpio_intel_alloc_io_pin(device_t dev, u_int pin, int flags, void **cookiep)
298 {
299 struct gpio_intel_softc *sc = device_get_softc(dev);
300 struct pin_io_map *map = NULL;
301 int i, ret;
302
303 if (cookiep == NULL)
304 return (EINVAL);
305
306 if (!gpio_intel_pin_exists(sc, pin))
307 return (ENOENT);
308
309 lockmgr(&sc->lk, LK_EXCLUSIVE);
310
311 for (i = 0; i < NELEM(sc->iomaps); i++) {
312 if (sc->iomaps[i].pin == pin) {
313 lockmgr(&sc->lk, LK_RELEASE);
314 return (EBUSY);
315 }
316 }
317 for (i = 0; i < NELEM(sc->iomaps); i++) {
318 if (sc->iomaps[i].pin == -1) {
319 map = &sc->iomaps[i];
320 break;
321 }
322 }
323 if (map == NULL) {
324 ret = EBUSY;
325 } else if (sc->fns->check_io_pin(sc, pin, flags)) {
326 /*
327 * XXX It's possible that RX gets disabled when the interrupt
328 * on this pin gets released.
329 */
330 map->pin = pin;
331 map->flags = flags;
332 *cookiep = map;
333 ret = 0;
334 } else {
335 ret = EBUSY;
336 }
337
338 lockmgr(&sc->lk, LK_RELEASE);
339
340 return (ret);
341 }
342
343 static void
gpio_intel_release_io_pin(device_t dev,void * cookie)344 gpio_intel_release_io_pin(device_t dev, void *cookie)
345 {
346 struct gpio_intel_softc *sc = device_get_softc(dev);
347 struct pin_io_map *map = (struct pin_io_map *)cookie;
348
349 lockmgr(&sc->lk, LK_EXCLUSIVE);
350 map->pin = -1;
351 map->flags = 0;
352 lockmgr(&sc->lk, LK_RELEASE);
353 }
354
355 static int
gpio_intel_read_pin(device_t dev,void * cookie)356 gpio_intel_read_pin(device_t dev, void *cookie)
357 {
358 struct gpio_intel_softc *sc = device_get_softc(dev);
359 struct pin_io_map *map = (struct pin_io_map *)cookie;
360 int val;
361
362 KKASSERT(map->pin >= 0);
363 KKASSERT(gpio_intel_pin_exists(sc, map->pin));
364
365 lockmgr(&sc->lk, LK_EXCLUSIVE);
366 val = sc->fns->read_pin(sc, map->pin);
367 lockmgr(&sc->lk, LK_RELEASE);
368
369 return (val);
370 }
371
372 static void
gpio_intel_write_pin(device_t dev,void * cookie,int value)373 gpio_intel_write_pin(device_t dev, void *cookie, int value)
374 {
375 struct gpio_intel_softc *sc = device_get_softc(dev);
376 struct pin_io_map *map = (struct pin_io_map *)cookie;
377
378 KKASSERT(map->pin >= 0);
379 KKASSERT(gpio_intel_pin_exists(sc, map->pin));
380
381 lockmgr(&sc->lk, LK_EXCLUSIVE);
382 sc->fns->write_pin(sc, map->pin, value);
383 lockmgr(&sc->lk, LK_RELEASE);
384 }
385
386 static void
gpio_intel_intr(void * arg)387 gpio_intel_intr(void *arg)
388 {
389 struct gpio_intel_softc *sc = (struct gpio_intel_softc *)arg;
390
391 lockmgr(&sc->lk, LK_EXCLUSIVE);
392 sc->fns->intr(arg);
393 lockmgr(&sc->lk, LK_RELEASE);
394 }
395
396 static int
gpio_intel_pin_exists(struct gpio_intel_softc * sc,uint16_t pin)397 gpio_intel_pin_exists(struct gpio_intel_softc *sc, uint16_t pin)
398 {
399 struct pinrange *r;
400
401 for (r = sc->ranges; r->start != -1 && r->end != -1; r++) {
402 if (r->start <= (int)pin && r->end >= (int)pin)
403 return (TRUE);
404 }
405
406 return (FALSE);
407 }
408
409 static device_method_t gpio_intel_methods[] = {
410 /* Device interface */
411 DEVMETHOD(device_probe, gpio_intel_probe),
412 DEVMETHOD(device_attach, gpio_intel_attach),
413 DEVMETHOD(device_detach, gpio_intel_detach),
414
415 /* GPIO methods */
416 DEVMETHOD(gpio_alloc_intr, gpio_intel_alloc_intr),
417 DEVMETHOD(gpio_free_intr, gpio_intel_free_intr),
418 DEVMETHOD(gpio_setup_intr, gpio_intel_setup_intr),
419 DEVMETHOD(gpio_teardown_intr, gpio_intel_teardown_intr),
420 DEVMETHOD(gpio_alloc_io_pin, gpio_intel_alloc_io_pin),
421 DEVMETHOD(gpio_release_io_pin, gpio_intel_release_io_pin),
422 DEVMETHOD(gpio_read_pin, gpio_intel_read_pin),
423 DEVMETHOD(gpio_write_pin, gpio_intel_write_pin),
424
425 DEVMETHOD_END
426 };
427
428 static driver_t gpio_intel_driver = {
429 "gpio_intel",
430 gpio_intel_methods,
431 sizeof(struct gpio_intel_softc),
432 .gpri = KOBJ_GPRI_ACPI+2
433 };
434
435 static devclass_t gpio_intel_devclass;
436
437 DRIVER_MODULE(gpio_intel, acpi, gpio_intel_driver, gpio_intel_devclass,
438 NULL, NULL);
439 MODULE_DEPEND(gpio_intel, acpi, 1, 1, 1);
440 MODULE_DEPEND(gpio_intel, gpio_acpi, 1, 1, 1);
441 MODULE_VERSION(gpio_intel, 1);
442