]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/allwinner/axp81x.c
Add support for the AXP813/AXP818 power key and GPIO pins.
[FreeBSD/FreeBSD.git] / sys / arm / allwinner / axp81x.c
1 /*-
2  * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 /*
30  * X-Powers AXP813/818 PMU for Allwinner SoCs
31  */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/eventhandler.h>
39 #include <sys/bus.h>
40 #include <sys/rman.h>
41 #include <sys/kernel.h>
42 #include <sys/reboot.h>
43 #include <sys/proc.h>
44 #include <sys/gpio.h>
45 #include <sys/module.h>
46 #include <machine/bus.h>
47
48 #include <dev/iicbus/iicbus.h>
49 #include <dev/iicbus/iiconf.h>
50
51 #include <dev/gpio/gpiobusvar.h>
52
53 #include <dev/ofw/ofw_bus.h>
54 #include <dev/ofw/ofw_bus_subr.h>
55
56 #include "iicbus_if.h"
57 #include "gpio_if.h"
58
59 #define AXP_ICTYPE              0x03
60 #define AXP_POWERBAT            0x32
61 #define  AXP_POWERBAT_SHUTDOWN  (1 << 7)
62 #define AXP_IRQEN1              0x40
63 #define AXP_IRQEN2              0x41
64 #define AXP_IRQEN3              0x42
65 #define AXP_IRQEN4              0x43
66 #define AXP_IRQEN5              0x44
67 #define  AXP_IRQEN5_POKSIRQ     (1 << 4)
68 #define AXP_IRQEN6              0x45
69 #define AXP_IRQSTAT5            0x4c
70 #define  AXP_IRQSTAT5_POKSIRQ   (1 << 4)
71 #define AXP_GPIO0_CTRL          0x90
72 #define AXP_GPIO1_CTRL          0x92
73 #define  AXP_GPIO_FUNC          (0x7 << 0)
74 #define  AXP_GPIO_FUNC_SHIFT    0
75 #define  AXP_GPIO_FUNC_DRVLO    0
76 #define  AXP_GPIO_FUNC_DRVHI    1
77 #define  AXP_GPIO_FUNC_INPUT    2
78 #define AXP_GPIO_SIGBIT         0x94
79 #define AXP_GPIO_PD             0x97
80
81 static const struct {
82         const char *name;
83         uint8_t ctrl_reg;
84 } axp81x_pins[] = {
85         { "GPIO0", AXP_GPIO0_CTRL },
86         { "GPIO1", AXP_GPIO1_CTRL },
87 };
88
89 static struct ofw_compat_data compat_data[] = {
90         { "x-powers,axp813",                    1 },
91         { "x-powers,axp818",                    1 },
92         { NULL,                                 0 }
93 };
94
95 static struct resource_spec axp81x_spec[] = {
96         { SYS_RES_IRQ,          0,      RF_ACTIVE },
97         { -1, 0 }
98 };
99
100 struct axp81x_softc {
101         struct resource         *res;
102         uint16_t                addr;
103         void                    *ih;
104         device_t                gpiodev;
105         struct mtx              mtx;
106         int                     busy;
107 };
108
109 #define AXP_LOCK(sc)    mtx_lock(&(sc)->mtx)
110 #define AXP_UNLOCK(sc)  mtx_unlock(&(sc)->mtx)
111
112 static int
113 axp81x_read(device_t dev, uint8_t reg, uint8_t *data, uint8_t size)
114 {
115         struct axp81x_softc *sc;
116         struct iic_msg msg[2];
117
118         sc = device_get_softc(dev);
119
120         msg[0].slave = sc->addr;
121         msg[0].flags = IIC_M_WR;
122         msg[0].len = 1;
123         msg[0].buf = &reg;
124
125         msg[1].slave = sc->addr;
126         msg[1].flags = IIC_M_RD;
127         msg[1].len = size;
128         msg[1].buf = data;
129
130         return (iicbus_transfer(dev, msg, 2));
131 }
132
133 static int
134 axp81x_write(device_t dev, uint8_t reg, uint8_t val)
135 {
136         struct axp81x_softc *sc;
137         struct iic_msg msg[2];
138
139         sc = device_get_softc(dev);
140
141         msg[0].slave = sc->addr;
142         msg[0].flags = IIC_M_WR;
143         msg[0].len = 1;
144         msg[0].buf = &reg;
145
146         msg[1].slave = sc->addr;
147         msg[1].flags = IIC_M_WR;
148         msg[1].len = 1;
149         msg[1].buf = &val;
150
151         return (iicbus_transfer(dev, msg, 2));
152 }
153
154 static void
155 axp81x_shutdown(void *devp, int howto)
156 {
157         device_t dev;
158
159         if ((howto & RB_POWEROFF) == 0)
160                 return;
161
162         dev = devp;
163
164         if (bootverbose)
165                 device_printf(dev, "Shutdown AXP81x\n");
166
167         axp81x_write(dev, AXP_POWERBAT, AXP_POWERBAT_SHUTDOWN);
168 }
169
170 static void
171 axp81x_intr(void *arg)
172 {
173         struct axp81x_softc *sc;
174         device_t dev;
175         uint8_t val;
176         int error;
177
178         dev = arg;
179         sc = device_get_softc(dev);
180
181         error = axp81x_read(dev, AXP_IRQSTAT5, &val, 1);
182         if (error != 0)
183                 return;
184
185         if (val != 0) {
186                 if ((val & AXP_IRQSTAT5_POKSIRQ) != 0) {
187                         if (bootverbose)
188                                 device_printf(dev, "Power button pressed\n");
189                         shutdown_nice(RB_POWEROFF);
190                 }
191                 /* Acknowledge */
192                 axp81x_write(dev, AXP_IRQSTAT5, val);
193         }
194 }
195
196 static device_t
197 axp81x_gpio_get_bus(device_t dev)
198 {
199         struct axp81x_softc *sc;
200
201         sc = device_get_softc(dev);
202
203         return (sc->gpiodev);
204 }
205
206 static int
207 axp81x_gpio_pin_max(device_t dev, int *maxpin)
208 {
209         *maxpin = nitems(axp81x_pins) - 1;
210
211         return (0);
212 }
213
214 static int
215 axp81x_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
216 {
217         if (pin >= nitems(axp81x_pins))
218                 return (EINVAL);
219
220         snprintf(name, GPIOMAXNAME, "%s", axp81x_pins[pin].name);
221
222         return (0);
223 }
224
225 static int
226 axp81x_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
227 {
228         if (pin >= nitems(axp81x_pins))
229                 return (EINVAL);
230
231         *caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
232
233         return (0);
234 }
235
236 static int
237 axp81x_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
238 {
239         struct axp81x_softc *sc;
240         uint8_t data, func;
241         int error;
242
243         if (pin >= nitems(axp81x_pins))
244                 return (EINVAL);
245
246         sc = device_get_softc(dev);
247
248         AXP_LOCK(sc);
249         THREAD_SLEEPING_OK();
250         error = axp81x_read(dev, axp81x_pins[pin].ctrl_reg, &data, 1);
251         if (error == 0) {
252                 func = (data & AXP_GPIO_FUNC) >> AXP_GPIO_FUNC_SHIFT;
253                 if (func == AXP_GPIO_FUNC_INPUT)
254                         *flags = GPIO_PIN_INPUT;
255                 else if (func == AXP_GPIO_FUNC_DRVLO ||
256                     func == AXP_GPIO_FUNC_DRVHI)
257                         *flags = GPIO_PIN_OUTPUT;
258                 else
259                         *flags = 0;
260         }
261         THREAD_NO_SLEEPING();
262         AXP_UNLOCK(sc);
263
264         return (error);
265 }
266
267 static int
268 axp81x_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
269 {
270         struct axp81x_softc *sc;
271         uint8_t data;
272         int error;
273
274         if (pin >= nitems(axp81x_pins))
275                 return (EINVAL);
276
277         sc = device_get_softc(dev);
278
279         AXP_LOCK(sc);
280         THREAD_SLEEPING_OK();
281         error = axp81x_read(dev, axp81x_pins[pin].ctrl_reg, &data, 1);
282         if (error == 0) {
283                 data &= ~AXP_GPIO_FUNC;
284                 if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) != 0) {
285                         if ((flags & GPIO_PIN_OUTPUT) == 0)
286                                 data |= AXP_GPIO_FUNC_INPUT;
287                 }
288                 error = axp81x_write(dev, axp81x_pins[pin].ctrl_reg, data);
289         }
290         THREAD_NO_SLEEPING();
291         AXP_UNLOCK(sc);
292
293         return (error);
294 }
295
296 static int
297 axp81x_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
298 {
299         struct axp81x_softc *sc;
300         uint8_t data, func;
301         int error;
302
303         if (pin >= nitems(axp81x_pins))
304                 return (EINVAL);
305
306         sc = device_get_softc(dev);
307
308         AXP_LOCK(sc);
309         THREAD_SLEEPING_OK();
310         error = axp81x_read(dev, axp81x_pins[pin].ctrl_reg, &data, 1);
311         if (error == 0) {
312                 func = (data & AXP_GPIO_FUNC) >> AXP_GPIO_FUNC_SHIFT;
313                 switch (func) {
314                 case AXP_GPIO_FUNC_DRVLO:
315                         *val = 0;
316                         break;
317                 case AXP_GPIO_FUNC_DRVHI:
318                         *val = 1;
319                         break;
320                 case AXP_GPIO_FUNC_INPUT:
321                         error = axp81x_read(dev, AXP_GPIO_SIGBIT, &data, 1);
322                         if (error == 0)
323                                 *val = (data & (1 << pin)) ? 1 : 0;
324                         break;
325                 default:
326                         error = EIO;
327                         break;
328                 }
329         }
330         THREAD_NO_SLEEPING();
331         AXP_UNLOCK(sc);
332
333         return (error);
334 }
335
336 static int
337 axp81x_gpio_pin_set(device_t dev, uint32_t pin, unsigned int val)
338 {
339         struct axp81x_softc *sc;
340         uint8_t data, func;
341         int error;
342
343         if (pin >= nitems(axp81x_pins))
344                 return (EINVAL);
345
346         sc = device_get_softc(dev);
347
348         AXP_LOCK(sc);
349         THREAD_SLEEPING_OK();
350         error = axp81x_read(dev, axp81x_pins[pin].ctrl_reg, &data, 1);
351         if (error == 0) {
352                 func = (data & AXP_GPIO_FUNC) >> AXP_GPIO_FUNC_SHIFT;
353                 switch (func) {
354                 case AXP_GPIO_FUNC_DRVLO:
355                 case AXP_GPIO_FUNC_DRVHI:
356                         data &= ~AXP_GPIO_FUNC;
357                         data |= (val << AXP_GPIO_FUNC_SHIFT);
358                         break;
359                 default:
360                         error = EIO;
361                         break;
362                 }
363         }
364         if (error == 0)
365                 error = axp81x_write(dev, axp81x_pins[pin].ctrl_reg, data);
366         THREAD_NO_SLEEPING();
367         AXP_UNLOCK(sc);
368
369         return (error);
370 }
371
372
373 static int
374 axp81x_gpio_pin_toggle(device_t dev, uint32_t pin)
375 {
376         struct axp81x_softc *sc;
377         uint8_t data, func;
378         int error;
379
380         if (pin >= nitems(axp81x_pins))
381                 return (EINVAL);
382
383         sc = device_get_softc(dev);
384
385         AXP_LOCK(sc);
386         THREAD_SLEEPING_OK();
387         error = axp81x_read(dev, axp81x_pins[pin].ctrl_reg, &data, 1);
388         if (error == 0) {
389                 func = (data & AXP_GPIO_FUNC) >> AXP_GPIO_FUNC_SHIFT;
390                 switch (func) {
391                 case AXP_GPIO_FUNC_DRVLO:
392                         data &= ~AXP_GPIO_FUNC;
393                         data |= (AXP_GPIO_FUNC_DRVHI << AXP_GPIO_FUNC_SHIFT);
394                         break;
395                 case AXP_GPIO_FUNC_DRVHI:
396                         data &= ~AXP_GPIO_FUNC;
397                         data |= (AXP_GPIO_FUNC_DRVLO << AXP_GPIO_FUNC_SHIFT);
398                         break;
399                 default:
400                         error = EIO;
401                         break;
402                 }
403         }
404         if (error == 0)
405                 error = axp81x_write(dev, axp81x_pins[pin].ctrl_reg, data);
406         THREAD_NO_SLEEPING();
407         AXP_UNLOCK(sc);
408
409         return (error);
410 }
411
412 static int
413 axp81x_gpio_map_gpios(device_t bus, phandle_t dev, phandle_t gparent,
414     int gcells, pcell_t *gpios, uint32_t *pin, uint32_t *flags)
415 {
416         if (gpios[0] >= nitems(axp81x_pins))
417                 return (EINVAL);
418
419         *pin = gpios[0];
420         *flags = gpios[1];
421
422         return (0);
423 }
424
425 static phandle_t
426 axp81x_get_node(device_t dev, device_t bus)
427 {
428         return (ofw_bus_get_node(dev));
429 }
430
431 static int
432 axp81x_probe(device_t dev)
433 {
434         if (!ofw_bus_status_okay(dev))
435                 return (ENXIO);
436
437         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
438                 return (ENXIO);
439
440         device_set_desc(dev, "X-Powers AXP81x Power Management Unit");
441
442         return (BUS_PROBE_DEFAULT);
443 }
444
445 static int
446 axp81x_attach(device_t dev)
447 {
448         struct axp81x_softc *sc;
449         uint8_t chip_id;
450         int error;
451
452         sc = device_get_softc(dev);
453
454         sc->addr = iicbus_get_addr(dev);
455         mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
456
457         error = bus_alloc_resources(dev, axp81x_spec, &sc->res);
458         if (error != 0) {
459                 device_printf(dev, "cannot allocate resources for device\n");
460                 return (error);
461         }
462
463         if (bootverbose) {
464                 axp81x_read(dev, AXP_ICTYPE, &chip_id, 1);
465                 device_printf(dev, "chip ID 0x%02x\n", chip_id);
466         }
467
468         /* Enable IRQ on short power key press */
469         axp81x_write(dev, AXP_IRQEN1, 0);
470         axp81x_write(dev, AXP_IRQEN2, 0);
471         axp81x_write(dev, AXP_IRQEN3, 0);
472         axp81x_write(dev, AXP_IRQEN4, 0);
473         axp81x_write(dev, AXP_IRQEN5, AXP_IRQEN5_POKSIRQ);
474         axp81x_write(dev, AXP_IRQEN6, 0);
475
476         /* Install interrupt handler */
477         error = bus_setup_intr(dev, sc->res, INTR_TYPE_MISC | INTR_MPSAFE,
478             NULL, axp81x_intr, dev, &sc->ih);
479         if (error != 0) {
480                 device_printf(dev, "cannot setup interrupt handler\n");
481                 return (error);
482         }
483
484         EVENTHANDLER_REGISTER(shutdown_final, axp81x_shutdown, dev,
485             SHUTDOWN_PRI_LAST);
486
487         sc->gpiodev = gpiobus_attach_bus(dev);
488
489         return (0);
490 }
491
492 static device_method_t axp81x_methods[] = {
493         /* Device interface */
494         DEVMETHOD(device_probe,         axp81x_probe),
495         DEVMETHOD(device_attach,        axp81x_attach),
496
497         /* GPIO interface */
498         DEVMETHOD(gpio_get_bus,         axp81x_gpio_get_bus),
499         DEVMETHOD(gpio_pin_max,         axp81x_gpio_pin_max),
500         DEVMETHOD(gpio_pin_getname,     axp81x_gpio_pin_getname),
501         DEVMETHOD(gpio_pin_getcaps,     axp81x_gpio_pin_getcaps),
502         DEVMETHOD(gpio_pin_getflags,    axp81x_gpio_pin_getflags),
503         DEVMETHOD(gpio_pin_setflags,    axp81x_gpio_pin_setflags),
504         DEVMETHOD(gpio_pin_get,         axp81x_gpio_pin_get),
505         DEVMETHOD(gpio_pin_set,         axp81x_gpio_pin_set),
506         DEVMETHOD(gpio_pin_toggle,      axp81x_gpio_pin_toggle),
507         DEVMETHOD(gpio_map_gpios,       axp81x_gpio_map_gpios),
508
509         /* OFW bus interface */
510         DEVMETHOD(ofw_bus_get_node,     axp81x_get_node),
511
512         DEVMETHOD_END
513 };
514
515 static driver_t axp81x_driver = {
516         "axp81x_pmu",
517         axp81x_methods,
518         sizeof(struct axp81x_softc),
519 };
520
521 static devclass_t axp81x_devclass;
522 extern devclass_t ofwgpiobus_devclass, gpioc_devclass;
523 extern driver_t ofw_gpiobus_driver, gpioc_driver;
524
525 DRIVER_MODULE(axp81x, iicbus, axp81x_driver, axp81x_devclass, 0, 0);
526 DRIVER_MODULE(ofw_gpiobus, axp81x_pmu, ofw_gpiobus_driver,
527     ofwgpiobus_devclass, 0, 0);
528 DRIVER_MODULE(gpioc, axp81x_pmu, gpioc_driver, gpioc_devclass, 0, 0);
529 MODULE_VERSION(axp81x, 1);
530 MODULE_DEPEND(axp81x, iicbus, 1, 1, 1);