]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/allwinner/axp81x.c
Import bhyve_graphics into CURRENT. Thanks to all who tested
[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/gpio.h>
44 #include <sys/module.h>
45 #include <machine/bus.h>
46
47 #include <dev/iicbus/iicbus.h>
48 #include <dev/iicbus/iiconf.h>
49
50 #include <dev/gpio/gpiobusvar.h>
51
52 #include <dev/ofw/ofw_bus.h>
53 #include <dev/ofw/ofw_bus_subr.h>
54
55 #include "iicbus_if.h"
56 #include "gpio_if.h"
57
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
79
80 static const struct {
81         const char *name;
82         uint8_t ctrl_reg;
83 } axp81x_pins[] = {
84         { "GPIO0", AXP_GPIO0_CTRL },
85         { "GPIO1", AXP_GPIO1_CTRL },
86 };
87
88 static struct ofw_compat_data compat_data[] = {
89         { "x-powers,axp813",                    1 },
90         { "x-powers,axp818",                    1 },
91         { NULL,                                 0 }
92 };
93
94 static struct resource_spec axp81x_spec[] = {
95         { SYS_RES_IRQ,          0,      RF_ACTIVE },
96         { -1, 0 }
97 };
98
99 struct axp81x_softc {
100         struct resource         *res;
101         uint16_t                addr;
102         void                    *ih;
103         device_t                gpiodev;
104         struct mtx              mtx;
105         int                     busy;
106 };
107
108 #define AXP_LOCK(sc)    mtx_lock(&(sc)->mtx)
109 #define AXP_UNLOCK(sc)  mtx_unlock(&(sc)->mtx)
110
111 static int
112 axp81x_read(device_t dev, uint8_t reg, uint8_t *data, uint8_t size)
113 {
114         struct axp81x_softc *sc;
115         struct iic_msg msg[2];
116
117         sc = device_get_softc(dev);
118
119         msg[0].slave = sc->addr;
120         msg[0].flags = IIC_M_WR;
121         msg[0].len = 1;
122         msg[0].buf = &reg;
123
124         msg[1].slave = sc->addr;
125         msg[1].flags = IIC_M_RD;
126         msg[1].len = size;
127         msg[1].buf = data;
128
129         return (iicbus_transfer(dev, msg, 2));
130 }
131
132 static int
133 axp81x_write(device_t dev, uint8_t reg, uint8_t val)
134 {
135         struct axp81x_softc *sc;
136         struct iic_msg msg[2];
137
138         sc = device_get_softc(dev);
139
140         msg[0].slave = sc->addr;
141         msg[0].flags = IIC_M_WR;
142         msg[0].len = 1;
143         msg[0].buf = &reg;
144
145         msg[1].slave = sc->addr;
146         msg[1].flags = IIC_M_WR;
147         msg[1].len = 1;
148         msg[1].buf = &val;
149
150         return (iicbus_transfer(dev, msg, 2));
151 }
152
153 static void
154 axp81x_shutdown(void *devp, int howto)
155 {
156         device_t dev;
157
158         if ((howto & RB_POWEROFF) == 0)
159                 return;
160
161         dev = devp;
162
163         if (bootverbose)
164                 device_printf(dev, "Shutdown AXP81x\n");
165
166         axp81x_write(dev, AXP_POWERBAT, AXP_POWERBAT_SHUTDOWN);
167 }
168
169 static void
170 axp81x_intr(void *arg)
171 {
172         struct axp81x_softc *sc;
173         device_t dev;
174         uint8_t val;
175         int error;
176
177         dev = arg;
178         sc = device_get_softc(dev);
179
180         error = axp81x_read(dev, AXP_IRQSTAT5, &val, 1);
181         if (error != 0)
182                 return;
183
184         if (val != 0) {
185                 if ((val & AXP_IRQSTAT5_POKSIRQ) != 0) {
186                         if (bootverbose)
187                                 device_printf(dev, "Power button pressed\n");
188                         shutdown_nice(RB_POWEROFF);
189                 }
190                 /* Acknowledge */
191                 axp81x_write(dev, AXP_IRQSTAT5, val);
192         }
193 }
194
195 static device_t
196 axp81x_gpio_get_bus(device_t dev)
197 {
198         struct axp81x_softc *sc;
199
200         sc = device_get_softc(dev);
201
202         return (sc->gpiodev);
203 }
204
205 static int
206 axp81x_gpio_pin_max(device_t dev, int *maxpin)
207 {
208         *maxpin = nitems(axp81x_pins) - 1;
209
210         return (0);
211 }
212
213 static int
214 axp81x_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
215 {
216         if (pin >= nitems(axp81x_pins))
217                 return (EINVAL);
218
219         snprintf(name, GPIOMAXNAME, "%s", axp81x_pins[pin].name);
220
221         return (0);
222 }
223
224 static int
225 axp81x_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
226 {
227         if (pin >= nitems(axp81x_pins))
228                 return (EINVAL);
229
230         *caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
231
232         return (0);
233 }
234
235 static int
236 axp81x_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
237 {
238         struct axp81x_softc *sc;
239         uint8_t data, func;
240         int error;
241
242         if (pin >= nitems(axp81x_pins))
243                 return (EINVAL);
244
245         sc = device_get_softc(dev);
246
247         AXP_LOCK(sc);
248         error = axp81x_read(dev, axp81x_pins[pin].ctrl_reg, &data, 1);
249         if (error == 0) {
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;
256                 else
257                         *flags = 0;
258         }
259         AXP_UNLOCK(sc);
260
261         return (error);
262 }
263
264 static int
265 axp81x_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
266 {
267         struct axp81x_softc *sc;
268         uint8_t data;
269         int error;
270
271         if (pin >= nitems(axp81x_pins))
272                 return (EINVAL);
273
274         sc = device_get_softc(dev);
275
276         AXP_LOCK(sc);
277         error = axp81x_read(dev, axp81x_pins[pin].ctrl_reg, &data, 1);
278         if (error == 0) {
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;
283                 }
284                 error = axp81x_write(dev, axp81x_pins[pin].ctrl_reg, data);
285         }
286         AXP_UNLOCK(sc);
287
288         return (error);
289 }
290
291 static int
292 axp81x_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
293 {
294         struct axp81x_softc *sc;
295         uint8_t data, func;
296         int error;
297
298         if (pin >= nitems(axp81x_pins))
299                 return (EINVAL);
300
301         sc = device_get_softc(dev);
302
303         AXP_LOCK(sc);
304         error = axp81x_read(dev, axp81x_pins[pin].ctrl_reg, &data, 1);
305         if (error == 0) {
306                 func = (data & AXP_GPIO_FUNC) >> AXP_GPIO_FUNC_SHIFT;
307                 switch (func) {
308                 case AXP_GPIO_FUNC_DRVLO:
309                         *val = 0;
310                         break;
311                 case AXP_GPIO_FUNC_DRVHI:
312                         *val = 1;
313                         break;
314                 case AXP_GPIO_FUNC_INPUT:
315                         error = axp81x_read(dev, AXP_GPIO_SIGBIT, &data, 1);
316                         if (error == 0)
317                                 *val = (data & (1 << pin)) ? 1 : 0;
318                         break;
319                 default:
320                         error = EIO;
321                         break;
322                 }
323         }
324         AXP_UNLOCK(sc);
325
326         return (error);
327 }
328
329 static int
330 axp81x_gpio_pin_set(device_t dev, uint32_t pin, unsigned int val)
331 {
332         struct axp81x_softc *sc;
333         uint8_t data, func;
334         int error;
335
336         if (pin >= nitems(axp81x_pins))
337                 return (EINVAL);
338
339         sc = device_get_softc(dev);
340
341         AXP_LOCK(sc);
342         error = axp81x_read(dev, axp81x_pins[pin].ctrl_reg, &data, 1);
343         if (error == 0) {
344                 func = (data & AXP_GPIO_FUNC) >> AXP_GPIO_FUNC_SHIFT;
345                 switch (func) {
346                 case AXP_GPIO_FUNC_DRVLO:
347                 case AXP_GPIO_FUNC_DRVHI:
348                         data &= ~AXP_GPIO_FUNC;
349                         data |= (val << AXP_GPIO_FUNC_SHIFT);
350                         break;
351                 default:
352                         error = EIO;
353                         break;
354                 }
355         }
356         if (error == 0)
357                 error = axp81x_write(dev, axp81x_pins[pin].ctrl_reg, data);
358         AXP_UNLOCK(sc);
359
360         return (error);
361 }
362
363
364 static int
365 axp81x_gpio_pin_toggle(device_t dev, uint32_t pin)
366 {
367         struct axp81x_softc *sc;
368         uint8_t data, func;
369         int error;
370
371         if (pin >= nitems(axp81x_pins))
372                 return (EINVAL);
373
374         sc = device_get_softc(dev);
375
376         AXP_LOCK(sc);
377         error = axp81x_read(dev, axp81x_pins[pin].ctrl_reg, &data, 1);
378         if (error == 0) {
379                 func = (data & AXP_GPIO_FUNC) >> AXP_GPIO_FUNC_SHIFT;
380                 switch (func) {
381                 case AXP_GPIO_FUNC_DRVLO:
382                         data &= ~AXP_GPIO_FUNC;
383                         data |= (AXP_GPIO_FUNC_DRVHI << AXP_GPIO_FUNC_SHIFT);
384                         break;
385                 case AXP_GPIO_FUNC_DRVHI:
386                         data &= ~AXP_GPIO_FUNC;
387                         data |= (AXP_GPIO_FUNC_DRVLO << AXP_GPIO_FUNC_SHIFT);
388                         break;
389                 default:
390                         error = EIO;
391                         break;
392                 }
393         }
394         if (error == 0)
395                 error = axp81x_write(dev, axp81x_pins[pin].ctrl_reg, data);
396         AXP_UNLOCK(sc);
397
398         return (error);
399 }
400
401 static int
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)
404 {
405         if (gpios[0] >= nitems(axp81x_pins))
406                 return (EINVAL);
407
408         *pin = gpios[0];
409         *flags = gpios[1];
410
411         return (0);
412 }
413
414 static phandle_t
415 axp81x_get_node(device_t dev, device_t bus)
416 {
417         return (ofw_bus_get_node(dev));
418 }
419
420 static int
421 axp81x_probe(device_t dev)
422 {
423         if (!ofw_bus_status_okay(dev))
424                 return (ENXIO);
425
426         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
427                 return (ENXIO);
428
429         device_set_desc(dev, "X-Powers AXP81x Power Management Unit");
430
431         return (BUS_PROBE_DEFAULT);
432 }
433
434 static int
435 axp81x_attach(device_t dev)
436 {
437         struct axp81x_softc *sc;
438         uint8_t chip_id;
439         int error;
440
441         sc = device_get_softc(dev);
442
443         sc->addr = iicbus_get_addr(dev);
444         mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
445
446         error = bus_alloc_resources(dev, axp81x_spec, &sc->res);
447         if (error != 0) {
448                 device_printf(dev, "cannot allocate resources for device\n");
449                 return (error);
450         }
451
452         if (bootverbose) {
453                 axp81x_read(dev, AXP_ICTYPE, &chip_id, 1);
454                 device_printf(dev, "chip ID 0x%02x\n", chip_id);
455         }
456
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);
464
465         /* Install interrupt handler */
466         error = bus_setup_intr(dev, sc->res, INTR_TYPE_MISC | INTR_MPSAFE,
467             NULL, axp81x_intr, dev, &sc->ih);
468         if (error != 0) {
469                 device_printf(dev, "cannot setup interrupt handler\n");
470                 return (error);
471         }
472
473         EVENTHANDLER_REGISTER(shutdown_final, axp81x_shutdown, dev,
474             SHUTDOWN_PRI_LAST);
475
476         sc->gpiodev = gpiobus_attach_bus(dev);
477
478         return (0);
479 }
480
481 static device_method_t axp81x_methods[] = {
482         /* Device interface */
483         DEVMETHOD(device_probe,         axp81x_probe),
484         DEVMETHOD(device_attach,        axp81x_attach),
485
486         /* GPIO interface */
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),
497
498         /* OFW bus interface */
499         DEVMETHOD(ofw_bus_get_node,     axp81x_get_node),
500
501         DEVMETHOD_END
502 };
503
504 static driver_t axp81x_driver = {
505         "axp81x_pmu",
506         axp81x_methods,
507         sizeof(struct axp81x_softc),
508 };
509
510 static devclass_t axp81x_devclass;
511 extern devclass_t ofwgpiobus_devclass, gpioc_devclass;
512 extern driver_t ofw_gpiobus_driver, gpioc_driver;
513
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);