2 * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
21 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * X-Powers AXP813/818 PMU for Allwinner SoCs
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/eventhandler.h>
41 #include <sys/kernel.h>
42 #include <sys/reboot.h>
44 #include <sys/module.h>
45 #include <machine/bus.h>
47 #include <dev/iicbus/iicbus.h>
48 #include <dev/iicbus/iiconf.h>
50 #include <dev/gpio/gpiobusvar.h>
52 #include <dev/ofw/ofw_bus.h>
53 #include <dev/ofw/ofw_bus_subr.h>
55 #include "iicbus_if.h"
58 #define AXP_ICTYPE 0x03
59 #define AXP_POWERBAT 0x32
60 #define AXP_POWERBAT_SHUTDOWN (1 << 7)
61 #define AXP_IRQEN1 0x40
62 #define AXP_IRQEN2 0x41
63 #define AXP_IRQEN3 0x42
64 #define AXP_IRQEN4 0x43
65 #define AXP_IRQEN5 0x44
66 #define AXP_IRQEN5_POKSIRQ (1 << 4)
67 #define AXP_IRQEN6 0x45
68 #define AXP_IRQSTAT5 0x4c
69 #define AXP_IRQSTAT5_POKSIRQ (1 << 4)
70 #define AXP_GPIO0_CTRL 0x90
71 #define AXP_GPIO1_CTRL 0x92
72 #define AXP_GPIO_FUNC (0x7 << 0)
73 #define AXP_GPIO_FUNC_SHIFT 0
74 #define AXP_GPIO_FUNC_DRVLO 0
75 #define AXP_GPIO_FUNC_DRVHI 1
76 #define AXP_GPIO_FUNC_INPUT 2
77 #define AXP_GPIO_SIGBIT 0x94
78 #define AXP_GPIO_PD 0x97
84 { "GPIO0", AXP_GPIO0_CTRL },
85 { "GPIO1", AXP_GPIO1_CTRL },
88 static struct ofw_compat_data compat_data[] = {
89 { "x-powers,axp813", 1 },
90 { "x-powers,axp818", 1 },
94 static struct resource_spec axp81x_spec[] = {
95 { SYS_RES_IRQ, 0, RF_ACTIVE },
100 struct resource *res;
108 #define AXP_LOCK(sc) mtx_lock(&(sc)->mtx)
109 #define AXP_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
112 axp81x_read(device_t dev, uint8_t reg, uint8_t *data, uint8_t size)
114 struct axp81x_softc *sc;
115 struct iic_msg msg[2];
117 sc = device_get_softc(dev);
119 msg[0].slave = sc->addr;
120 msg[0].flags = IIC_M_WR;
124 msg[1].slave = sc->addr;
125 msg[1].flags = IIC_M_RD;
129 return (iicbus_transfer(dev, msg, 2));
133 axp81x_write(device_t dev, uint8_t reg, uint8_t val)
135 struct axp81x_softc *sc;
136 struct iic_msg msg[2];
138 sc = device_get_softc(dev);
140 msg[0].slave = sc->addr;
141 msg[0].flags = IIC_M_WR;
145 msg[1].slave = sc->addr;
146 msg[1].flags = IIC_M_WR;
150 return (iicbus_transfer(dev, msg, 2));
154 axp81x_shutdown(void *devp, int howto)
158 if ((howto & RB_POWEROFF) == 0)
164 device_printf(dev, "Shutdown AXP81x\n");
166 axp81x_write(dev, AXP_POWERBAT, AXP_POWERBAT_SHUTDOWN);
170 axp81x_intr(void *arg)
172 struct axp81x_softc *sc;
178 sc = device_get_softc(dev);
180 error = axp81x_read(dev, AXP_IRQSTAT5, &val, 1);
185 if ((val & AXP_IRQSTAT5_POKSIRQ) != 0) {
187 device_printf(dev, "Power button pressed\n");
188 shutdown_nice(RB_POWEROFF);
191 axp81x_write(dev, AXP_IRQSTAT5, val);
196 axp81x_gpio_get_bus(device_t dev)
198 struct axp81x_softc *sc;
200 sc = device_get_softc(dev);
202 return (sc->gpiodev);
206 axp81x_gpio_pin_max(device_t dev, int *maxpin)
208 *maxpin = nitems(axp81x_pins) - 1;
214 axp81x_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
216 if (pin >= nitems(axp81x_pins))
219 snprintf(name, GPIOMAXNAME, "%s", axp81x_pins[pin].name);
225 axp81x_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
227 if (pin >= nitems(axp81x_pins))
230 *caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
236 axp81x_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
238 struct axp81x_softc *sc;
242 if (pin >= nitems(axp81x_pins))
245 sc = device_get_softc(dev);
248 error = axp81x_read(dev, axp81x_pins[pin].ctrl_reg, &data, 1);
250 func = (data & AXP_GPIO_FUNC) >> AXP_GPIO_FUNC_SHIFT;
251 if (func == AXP_GPIO_FUNC_INPUT)
252 *flags = GPIO_PIN_INPUT;
253 else if (func == AXP_GPIO_FUNC_DRVLO ||
254 func == AXP_GPIO_FUNC_DRVHI)
255 *flags = GPIO_PIN_OUTPUT;
265 axp81x_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
267 struct axp81x_softc *sc;
271 if (pin >= nitems(axp81x_pins))
274 sc = device_get_softc(dev);
277 error = axp81x_read(dev, axp81x_pins[pin].ctrl_reg, &data, 1);
279 data &= ~AXP_GPIO_FUNC;
280 if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) != 0) {
281 if ((flags & GPIO_PIN_OUTPUT) == 0)
282 data |= AXP_GPIO_FUNC_INPUT;
284 error = axp81x_write(dev, axp81x_pins[pin].ctrl_reg, data);
292 axp81x_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
294 struct axp81x_softc *sc;
298 if (pin >= nitems(axp81x_pins))
301 sc = device_get_softc(dev);
304 error = axp81x_read(dev, axp81x_pins[pin].ctrl_reg, &data, 1);
306 func = (data & AXP_GPIO_FUNC) >> AXP_GPIO_FUNC_SHIFT;
308 case AXP_GPIO_FUNC_DRVLO:
311 case AXP_GPIO_FUNC_DRVHI:
314 case AXP_GPIO_FUNC_INPUT:
315 error = axp81x_read(dev, AXP_GPIO_SIGBIT, &data, 1);
317 *val = (data & (1 << pin)) ? 1 : 0;
330 axp81x_gpio_pin_set(device_t dev, uint32_t pin, unsigned int val)
332 struct axp81x_softc *sc;
336 if (pin >= nitems(axp81x_pins))
339 sc = device_get_softc(dev);
342 error = axp81x_read(dev, axp81x_pins[pin].ctrl_reg, &data, 1);
344 func = (data & AXP_GPIO_FUNC) >> AXP_GPIO_FUNC_SHIFT;
346 case AXP_GPIO_FUNC_DRVLO:
347 case AXP_GPIO_FUNC_DRVHI:
348 data &= ~AXP_GPIO_FUNC;
349 data |= (val << AXP_GPIO_FUNC_SHIFT);
357 error = axp81x_write(dev, axp81x_pins[pin].ctrl_reg, data);
365 axp81x_gpio_pin_toggle(device_t dev, uint32_t pin)
367 struct axp81x_softc *sc;
371 if (pin >= nitems(axp81x_pins))
374 sc = device_get_softc(dev);
377 error = axp81x_read(dev, axp81x_pins[pin].ctrl_reg, &data, 1);
379 func = (data & AXP_GPIO_FUNC) >> AXP_GPIO_FUNC_SHIFT;
381 case AXP_GPIO_FUNC_DRVLO:
382 data &= ~AXP_GPIO_FUNC;
383 data |= (AXP_GPIO_FUNC_DRVHI << AXP_GPIO_FUNC_SHIFT);
385 case AXP_GPIO_FUNC_DRVHI:
386 data &= ~AXP_GPIO_FUNC;
387 data |= (AXP_GPIO_FUNC_DRVLO << AXP_GPIO_FUNC_SHIFT);
395 error = axp81x_write(dev, axp81x_pins[pin].ctrl_reg, data);
402 axp81x_gpio_map_gpios(device_t bus, phandle_t dev, phandle_t gparent,
403 int gcells, pcell_t *gpios, uint32_t *pin, uint32_t *flags)
405 if (gpios[0] >= nitems(axp81x_pins))
415 axp81x_get_node(device_t dev, device_t bus)
417 return (ofw_bus_get_node(dev));
421 axp81x_probe(device_t dev)
423 if (!ofw_bus_status_okay(dev))
426 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
429 device_set_desc(dev, "X-Powers AXP81x Power Management Unit");
431 return (BUS_PROBE_DEFAULT);
435 axp81x_attach(device_t dev)
437 struct axp81x_softc *sc;
441 sc = device_get_softc(dev);
443 sc->addr = iicbus_get_addr(dev);
444 mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
446 error = bus_alloc_resources(dev, axp81x_spec, &sc->res);
448 device_printf(dev, "cannot allocate resources for device\n");
453 axp81x_read(dev, AXP_ICTYPE, &chip_id, 1);
454 device_printf(dev, "chip ID 0x%02x\n", chip_id);
457 /* Enable IRQ on short power key press */
458 axp81x_write(dev, AXP_IRQEN1, 0);
459 axp81x_write(dev, AXP_IRQEN2, 0);
460 axp81x_write(dev, AXP_IRQEN3, 0);
461 axp81x_write(dev, AXP_IRQEN4, 0);
462 axp81x_write(dev, AXP_IRQEN5, AXP_IRQEN5_POKSIRQ);
463 axp81x_write(dev, AXP_IRQEN6, 0);
465 /* Install interrupt handler */
466 error = bus_setup_intr(dev, sc->res, INTR_TYPE_MISC | INTR_MPSAFE,
467 NULL, axp81x_intr, dev, &sc->ih);
469 device_printf(dev, "cannot setup interrupt handler\n");
473 EVENTHANDLER_REGISTER(shutdown_final, axp81x_shutdown, dev,
476 sc->gpiodev = gpiobus_attach_bus(dev);
481 static device_method_t axp81x_methods[] = {
482 /* Device interface */
483 DEVMETHOD(device_probe, axp81x_probe),
484 DEVMETHOD(device_attach, axp81x_attach),
487 DEVMETHOD(gpio_get_bus, axp81x_gpio_get_bus),
488 DEVMETHOD(gpio_pin_max, axp81x_gpio_pin_max),
489 DEVMETHOD(gpio_pin_getname, axp81x_gpio_pin_getname),
490 DEVMETHOD(gpio_pin_getcaps, axp81x_gpio_pin_getcaps),
491 DEVMETHOD(gpio_pin_getflags, axp81x_gpio_pin_getflags),
492 DEVMETHOD(gpio_pin_setflags, axp81x_gpio_pin_setflags),
493 DEVMETHOD(gpio_pin_get, axp81x_gpio_pin_get),
494 DEVMETHOD(gpio_pin_set, axp81x_gpio_pin_set),
495 DEVMETHOD(gpio_pin_toggle, axp81x_gpio_pin_toggle),
496 DEVMETHOD(gpio_map_gpios, axp81x_gpio_map_gpios),
498 /* OFW bus interface */
499 DEVMETHOD(ofw_bus_get_node, axp81x_get_node),
504 static driver_t axp81x_driver = {
507 sizeof(struct axp81x_softc),
510 static devclass_t axp81x_devclass;
511 extern devclass_t ofwgpiobus_devclass, gpioc_devclass;
512 extern driver_t ofw_gpiobus_driver, gpioc_driver;
514 DRIVER_MODULE(axp81x, iicbus, axp81x_driver, axp81x_devclass, 0, 0);
515 DRIVER_MODULE(ofw_gpiobus, axp81x_pmu, ofw_gpiobus_driver,
516 ofwgpiobus_devclass, 0, 0);
517 DRIVER_MODULE(gpioc, axp81x_pmu, gpioc_driver, gpioc_devclass, 0, 0);
518 MODULE_VERSION(axp81x, 1);
519 MODULE_DEPEND(axp81x, iicbus, 1, 1, 1);