2 * Copyright (c) 2016 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Imre Vadász <imre@vdsz.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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
35 * Intel SoC gpio driver.
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>
44 #include <sys/mutex.h>
51 #include <dev/acpica/acpivar.h>
53 #include <bus/pci/pcivar.h>
55 #include <bus/gpio/gpio_acpi/gpio_acpivar.h>
57 #include "gpio_intel_var.h"
61 static int gpio_intel_probe(device_t dev);
62 static int gpio_intel_attach(device_t dev);
63 static int gpio_intel_detach(device_t dev);
64 static int gpio_intel_alloc_intr(device_t dev, u_int pin, int trigger,
65 int polarity, int termination, void **cookiep);
66 static void gpio_intel_setup_intr(device_t dev, void *cookie, void *arg,
67 driver_intr_t *handler);
68 static void gpio_intel_teardown_intr(device_t dev, void *cookie);
69 static void gpio_intel_free_intr(device_t dev, void *cookie);
70 static int gpio_intel_read_pin(device_t dev, u_int pin);
71 static void gpio_intel_write_pin(device_t dev, u_int pin, int value);
73 static void gpio_intel_intr(void *arg);
74 static int gpio_intel_pin_exists(struct gpio_intel_softc *sc,
77 static char *cherryview_ids[] = { "INT33FF", NULL };
80 gpio_intel_probe(device_t dev)
83 if (acpi_disabled("gpio_intel") ||
84 ACPI_ID_PROBE(device_get_parent(dev), dev, cherryview_ids) == NULL)
87 device_set_desc(dev, "Intel Cherry Trail GPIO Controller");
89 return (BUS_PROBE_DEFAULT);
93 gpio_intel_attach(device_t dev)
95 struct gpio_intel_softc *sc = device_get_softc(dev);
98 lockinit(&sc->lk, "gpio_intel", 0, LK_CANRECURSE);
102 if (ACPI_ID_PROBE(device_get_parent(dev), dev, cherryview_ids)
104 error = gpio_cherryview_matchuid(sc);
114 for (i = 0; i < 16; i++) {
115 sc->intrmaps[i].pin = -1;
119 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
121 if (sc->mem_res == NULL) {
122 device_printf(dev, "unable to map registers");
127 sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
129 if (sc->irq_res == NULL) {
130 device_printf(dev, "unable to map interrupt");
135 lockmgr(&sc->lk, LK_EXCLUSIVE);
136 /* Activate the interrupt */
137 error = bus_setup_intr(dev, sc->irq_res, INTR_MPSAFE,
138 gpio_intel_intr, sc, &sc->intrhand, NULL);
140 device_printf(dev, "Can't setup IRQ\n");
142 /* power up the controller */
143 pci_set_powerstate(dev, PCI_POWERSTATE_D0);
146 lockmgr(&sc->lk, LK_RELEASE);
148 sc->acpireg = gpio_acpi_register(dev);
154 bus_release_resource(dev, SYS_RES_IRQ,
155 rman_get_rid(sc->irq_res), sc->irq_res);
159 bus_release_resource(dev, SYS_RES_MEMORY,
160 rman_get_rid(sc->mem_res), sc->mem_res);
167 gpio_intel_detach(device_t dev)
169 struct gpio_intel_softc *sc = device_get_softc(dev);
171 gpio_acpi_unregister(dev, sc->acpireg);
173 bus_teardown_intr(dev, sc->irq_res, sc->intrhand);
175 bus_release_resource(dev, SYS_RES_IRQ,
176 rman_get_rid(sc->irq_res), sc->irq_res);
180 bus_release_resource(dev, SYS_RES_MEMORY,
181 rman_get_rid(sc->mem_res), sc->mem_res);
186 pci_set_powerstate(dev, PCI_POWERSTATE_D3);
192 * The trigger, polarity and termination parameters are only used for
193 * sanity checking. The gpios should already be configured correctly by
197 gpio_intel_alloc_intr(device_t dev, u_int pin, int trigger, int polarity,
198 int termination, void **cookiep)
200 struct gpio_intel_softc *sc = device_get_softc(dev);
201 struct pin_intr_map *map = NULL;
207 lockmgr(&sc->lk, LK_EXCLUSIVE);
209 if (gpio_intel_pin_exists(sc, pin)) {
210 /* Make sure this pin isn't mapped yet */
211 for (i = 0; i < 16; i++) {
212 if (sc->intrmaps[i].pin == pin)
215 ret = sc->fns->map_intr(sc, pin, trigger, polarity,
218 /* XXX map_intr should return the pin_intr_map */
219 for (i = 0; i < NELEM(sc->intrmaps); i++) {
220 if (sc->intrmaps[i].pin == pin)
221 map = &sc->intrmaps[i];
230 device_printf(sc->dev, "%s: Invalid pin %d\n", __func__, pin);
234 lockmgr(&sc->lk, LK_RELEASE);
240 gpio_intel_free_intr(device_t dev, void *cookie)
242 struct gpio_intel_softc *sc = device_get_softc(dev);
243 struct pin_intr_map *map = (struct pin_intr_map *)cookie;
245 KKASSERT(gpio_intel_pin_exists(sc, map->pin));
247 lockmgr(&sc->lk, LK_EXCLUSIVE);
250 sc->fns->unmap_intr(sc, map);
251 lockmgr(&sc->lk, LK_RELEASE);
255 gpio_intel_setup_intr(device_t dev, void *cookie, void *arg,
256 driver_intr_t *handler)
258 struct gpio_intel_softc *sc = device_get_softc(dev);
259 struct pin_intr_map *map = (struct pin_intr_map *)cookie;
261 KKASSERT(gpio_intel_pin_exists(sc, map->pin));
263 lockmgr(&sc->lk, LK_EXCLUSIVE);
265 map->handler = handler;
266 sc->fns->enable_intr(sc, map);
267 lockmgr(&sc->lk, LK_RELEASE);
271 gpio_intel_teardown_intr(device_t dev, void *cookie)
273 struct gpio_intel_softc *sc = device_get_softc(dev);
274 struct pin_intr_map *map = (struct pin_intr_map *)cookie;
276 KKASSERT(gpio_intel_pin_exists(sc, map->pin));
278 lockmgr(&sc->lk, LK_EXCLUSIVE);
279 sc->fns->disable_intr(sc, map);
282 lockmgr(&sc->lk, LK_RELEASE);
286 gpio_intel_read_pin(device_t dev, u_int pin)
288 struct gpio_intel_softc *sc = device_get_softc(dev);
291 /* This operation mustn't fail, otherwise ACPI would be in trouble */
292 KKASSERT(gpio_intel_pin_exists(sc, pin));
294 lockmgr(&sc->lk, LK_EXCLUSIVE);
295 val = sc->fns->read_pin(sc, pin);
296 lockmgr(&sc->lk, LK_RELEASE);
302 gpio_intel_write_pin(device_t dev, u_int pin, int value)
304 struct gpio_intel_softc *sc = device_get_softc(dev);
306 /* This operation mustn't fail, otherwise ACPI would be in trouble */
307 KKASSERT(gpio_intel_pin_exists(sc, pin));
309 lockmgr(&sc->lk, LK_EXCLUSIVE);
310 sc->fns->write_pin(sc, pin, value);
311 lockmgr(&sc->lk, LK_RELEASE);
315 gpio_intel_intr(void *arg)
317 struct gpio_intel_softc *sc = (struct gpio_intel_softc *)arg;
319 lockmgr(&sc->lk, LK_EXCLUSIVE);
321 lockmgr(&sc->lk, LK_RELEASE);
325 gpio_intel_pin_exists(struct gpio_intel_softc *sc, uint16_t pin)
329 for (r = sc->ranges; r->start != -1 && r->end != -1; r++) {
330 if (r->start <= (int)pin && r->end >= (int)pin)
337 static device_method_t gpio_intel_methods[] = {
338 /* Device interface */
339 DEVMETHOD(device_probe, gpio_intel_probe),
340 DEVMETHOD(device_attach, gpio_intel_attach),
341 DEVMETHOD(device_detach, gpio_intel_detach),
344 DEVMETHOD(gpio_alloc_intr, gpio_intel_alloc_intr),
345 DEVMETHOD(gpio_free_intr, gpio_intel_free_intr),
346 DEVMETHOD(gpio_setup_intr, gpio_intel_setup_intr),
347 DEVMETHOD(gpio_teardown_intr, gpio_intel_teardown_intr),
348 DEVMETHOD(gpio_read_pin, gpio_intel_read_pin),
349 DEVMETHOD(gpio_write_pin, gpio_intel_write_pin),
354 static driver_t gpio_intel_driver = {
357 sizeof(struct gpio_intel_softc)
360 static devclass_t gpio_intel_devclass;
362 DRIVER_MODULE(gpio_intel, acpi, gpio_intel_driver, gpio_intel_devclass,
364 MODULE_DEPEND(gpio_intel, acpi, 1, 1, 1);
365 MODULE_DEPEND(gpio_intel, gpio_acpi, 1, 1, 1);
366 MODULE_VERSION(gpio_intel, 1);