1 /* $OpenBSD: gpiocharger.c,v 1.2 2022/04/06 18:59:28 naddy Exp $ */
2 /*
3 * Copyright (c) 2021 Klemens Nanni <kn@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21 #include <sys/gpio.h>
22 #include <sys/malloc.h>
23
24 #include <machine/bus.h>
25 #include <machine/fdt.h>
26
27 #include <dev/gpio/gpiovar.h>
28 #include <dev/ofw/ofw_gpio.h>
29 #include <dev/ofw/ofw_pinctrl.h>
30 #include <dev/ofw/openfirm.h>
31 #include <dev/ofw/fdt.h>
32
33 #include <sys/sensors.h>
34
35 struct gpiocharger_softc {
36 struct device sc_dev;
37 int sc_node;
38 uint32_t *sc_charger_pin;
39 struct ksensor sc_sensor;
40 struct ksensordev sc_sensordev;
41 };
42
43 int gpiocharger_match(struct device *, void *, void *);
44 void gpiocharger_attach(struct device *, struct device *, void *);
45
46 const struct cfattach gpiocharger_ca = {
47 sizeof (struct gpiocharger_softc), gpiocharger_match, gpiocharger_attach
48 };
49
50 struct cfdriver gpiocharger_cd = {
51 NULL, "gpiocharger", DV_DULL
52 };
53
54 void gpiocharger_update_charger(void *);
55
56 int
gpiocharger_match(struct device * parent,void * match,void * aux)57 gpiocharger_match(struct device *parent, void *match, void *aux)
58 {
59 const struct fdt_attach_args *faa = aux;
60
61 return OF_is_compatible(faa->fa_node, "gpio-charger");
62 }
63
64 void
gpiocharger_attach(struct device * parent,struct device * self,void * aux)65 gpiocharger_attach(struct device *parent, struct device *self, void *aux)
66 {
67 struct gpiocharger_softc *sc = (struct gpiocharger_softc *)self;
68 struct fdt_attach_args *faa = aux;
69 char *charger_type, *gpios_property;
70 int charger_type_len, gpios_len;
71 int node = faa->fa_node;
72
73 pinctrl_byname(node, "default");
74
75 charger_type_len = OF_getproplen(node, "charger-type");
76 if (charger_type_len <= 0)
77 goto nocharger;
78 gpios_property = "gpios";
79 gpios_len = OF_getproplen(node, gpios_property);
80 if (gpios_len <= 0) {
81 gpios_property = "charger-status-gpios";
82 gpios_len = OF_getproplen(node, gpios_property);
83 if (gpios_len <= 0)
84 goto nocharger;
85 }
86
87 charger_type = malloc(charger_type_len, M_TEMP, M_WAITOK);
88 OF_getprop(node, "charger-type", charger_type, charger_type_len);
89 sc->sc_charger_pin = malloc(gpios_len, M_DEVBUF, M_WAITOK);
90 OF_getpropintarray(node, gpios_property, sc->sc_charger_pin, gpios_len);
91 gpio_controller_config_pin(sc->sc_charger_pin, GPIO_CONFIG_INPUT);
92
93 strlcpy(sc->sc_sensor.desc, charger_type, sizeof(sc->sc_sensor.desc));
94 strlcat(sc->sc_sensor.desc, " power supply",
95 sizeof(sc->sc_sensor.desc));
96 sc->sc_sensor.type = SENSOR_INDICATOR;
97 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
98 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
99 sizeof(sc->sc_sensordev.xname));
100 sensordev_install(&sc->sc_sensordev);
101 sensor_task_register(sc, gpiocharger_update_charger, 5);
102
103 printf(": \"%s\"\n", charger_type);
104 free(charger_type, M_TEMP, charger_type_len);
105 return;
106
107 nocharger:
108 printf(": no charger\n");
109 }
110
111 void
gpiocharger_update_charger(void * arg)112 gpiocharger_update_charger(void *arg)
113 {
114 struct gpiocharger_softc *sc = arg;
115
116 sc->sc_sensor.value = gpio_controller_get_pin(sc->sc_charger_pin);
117 }
118