1 /* $NetBSD: axp20x.c,v 1.21 2021/08/07 16:19:11 thorpej Exp $ */
2 
3 /*-
4  * Copyright (c) 2014-2017 Jared McNeill <jmcneill@invisible.ca>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: axp20x.c,v 1.21 2021/08/07 16:19:11 thorpej Exp $");
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/device.h>
35 #include <sys/conf.h>
36 #include <sys/bus.h>
37 #include <sys/kmem.h>
38 
39 #include <dev/i2c/i2cvar.h>
40 
41 #include <dev/sysmon/sysmonvar.h>
42 
43 #include <dev/fdt/fdtvar.h>
44 
45 #define AXP20X_DCDC2    2
46 #define AXP20X_DCDC3    3
47 
48 #define   AXP209_I2C_ADDR               0x34
49 
50 #define AXP_INPUT_STATUS      0x00
51 #define AXP_INPUT_STATUS_AC_PRESENT     __BIT(7)
52 #define AXP_INPUT_STATUS_AC_OK                    __BIT(6)
53 #define AXP_INPUT_STATUS_VBUS_PRESENT   __BIT(5)
54 #define AXP_INPUT_STATUS_VBUS_OK        __BIT(4)
55 
56 #define AXP_POWER_MODE                  0x01
57 #define AXP_POWER_MODE_OVERTEMP                   __BIT(7)
58 #define AXP_POWER_MODE_CHARGING                   __BIT(6)
59 #define AXP_POWER_MODE_BATTOK           __BIT(5)
60 
61 #define AXP_POWEROUT_CTRL     0x12
62 #define AXP_POWEROUT_CTRL_LDO3                    __BIT(6)
63 #define AXP_POWEROUT_CTRL_DCDC2                   __BIT(4)
64 #define AXP_POWEROUT_CTRL_LDO4                    __BIT(3)
65 #define AXP_POWEROUT_CTRL_LDO2                    __BIT(2)
66 #define AXP_POWEROUT_CTRL_DCDC3                   __BIT(1)
67 #define AXP_POWEROUT_CTRL_EXTEN                   __BIT(0)
68 
69 #define AXP_DCDC2             0x23
70 #define AXP_DCDC2_VOLT_MASK             __BITS(0,5)
71 #define AXP_DCDC2_VOLT_SHIFT            0
72 
73 #define AXP_DCDC2_LDO3_VRC    0x25
74 
75 #define AXP_DCDC3             0x27
76 #define AXP_DCDC3_VOLT_MASK             __BITS(0,6)
77 #define AXP_DCDC3_VOLT_SHIFT            0
78 
79 #define AXP_LDO2_4            0x28
80 #define AXP_LDO2_VOLT_MASK              __BITS(4,7)
81 #define AXP_LDO2_VOLT_SHIFT             4
82 #define AXP_LDO4_VOLT_MASK              __BITS(0,3)
83 #define AXP_LDO4_VOLT_SHIFT             0
84 static int ldo4_mvV[] = {
85           1250,
86           1300,
87           1400,
88           1500,
89           1600,
90           1700,
91           1800,
92           1900,
93           2000,
94           2500,
95           2700,
96           2800,
97           3000,
98           3100,
99           3200,
100           3300
101 };
102 
103 #define AXP_LDO3              0x29
104 #define AXP_LDO3_TRACK                            __BIT(7)
105 #define AXP_LDO3_VOLT_MASK              __BITS(0,6)
106 #define AXP_LDO3_VOLT_SHIFT             0
107 
108 #define   AXP_SHUTDOWN                  0x32
109 #define   AXP_SHUTDOWN_CTRL   __BIT(7)
110 
111 #define AXP_BKUP_CTRL                             0x35
112 #define AXP_BKUP_CTRL_ENABLE            __BIT(7)
113 #define AXP_BKUP_CTRL_VOLT_MASK                   __BITS(5,6)
114 #define AXP_BKUP_CTRL_VOLT_SHIFT        5
115 #define AXP_BKUP_CTRL_VOLT_3V1                    0
116 #define AXP_BKUP_CTRL_VOLT_3V0                    1
117 #define AXP_BKUP_CTRL_VOLT_3V6                    2
118 #define AXP_BKUP_CTRL_VOLT_2V5                    3
119 static int bkup_volt[] = {
120           3100,
121           3000,
122           3600,
123           2500
124 };
125 #define AXP_BKUP_CTRL_CURR_MASK                   __BITS(0,1)
126 #define AXP_BKUP_CTRL_CURR_SHIFT        0
127 #define AXP_BKUP_CTRL_CURR_50U                    0
128 #define AXP_BKUP_CTRL_CURR_100U                   1
129 #define AXP_BKUP_CTRL_CURR_200U                   2
130 #define AXP_BKUP_CTRL_CURR_400U                   3
131 static int bkup_curr[] = {
132           50,
133           100,
134           200,
135           400
136 };
137 
138 #define AXP_ACV_MON_REG                 0x56      /* 2 bytes */
139 #define AXP_ACI_MON_REG                 0x58      /* 2 bytes */
140 #define AXP_VBUSV_MON_REG     0x5a      /* 2 bytes */
141 #define AXP_VBUSI_MON_REG     0x5c      /* 2 bytes */
142 #define AXP_TEMP_MON_REG      0x5e      /* 2 bytes */
143 #define AXP_BATTV_MON_REG     0x78      /* 2 bytes */
144 #define AXP_BATTCI_MON_REG    0x7a      /* 2 bytes */
145 #define AXP_BATTDI_MON_REG    0x7c      /* 2 bytes */
146 #define AXP_APSV_MON_REG      0x7e      /* 2 bytes */
147 
148 #define AXP_ADC_EN1           0x82
149 #define AXP_ADC_EN1_BATTV               __BIT(7)
150 #define AXP_ADC_EN1_BATTI               __BIT(6)
151 #define AXP_ADC_EN1_ACV                           __BIT(5)
152 #define AXP_ADC_EN1_ACI                           __BIT(4)
153 #define AXP_ADC_EN1_VBUSV               __BIT(3)
154 #define AXP_ADC_EN1_VBUSI               __BIT(2)
155 #define AXP_ADC_EN1_APSV                __BIT(1)
156 #define AXP_ADC_EN1_TS                            __BIT(0)
157 #define AXP_ADC_EN2           0x83
158 #define AXP_ADC_EN2_TEMP                __BIT(7)
159 
160 #define AXP_SENSOR_ACOK                 0
161 #define AXP_SENSOR_ACV                  1
162 #define AXP_SENSOR_ACI                  2
163 #define AXP_SENSOR_VBUSOK     3
164 #define AXP_SENSOR_VBUSV      4
165 #define AXP_SENSOR_VBUSI      5
166 #define AXP_SENSOR_BATTOK     6
167 #define AXP_SENSOR_BATTV      7
168 #define AXP_SENSOR_BATTI      8
169 #define AXP_SENSOR_APSV                 9
170 #define AXP_SENSOR_TEMP                 10
171 #define AXP_NSENSORS (AXP_SENSOR_TEMP + 1)
172 
173 /* define per-ADC LSB to uV/uA values */
174 static int axp20x_sensors_lsb[] = {
175              0, /* AXP_SENSOR_ACOK */
176           1700, /* AXP_SENSOR_ACV */
177            625, /* AXP_SENSOR_ACI */
178              0,
179           1700, /* AXP_SENSOR_VBUSV */
180            375, /* AXP_SENSOR_VBUSI */
181              0,
182           1100, /* AXP_SENSOR_BATTV */
183            500, /* AXP_SENSOR_BATTI */
184           1400, /* AXP_SENSOR_APSV */
185 };
186 
187 
188 struct axp20x_softc {
189           device_t  sc_dev;
190           i2c_tag_t sc_i2c;
191           i2c_addr_t          sc_addr;
192           int                 sc_phandle;
193 
194           uint8_t   sc_inputstatus;
195           uint8_t   sc_powermode;
196 
197           struct sysmon_envsys *sc_sme;
198           envsys_data_t       sc_sensor[AXP_NSENSORS];
199 };
200 
201 static int          axp20x_match(device_t, cfdata_t, void *);
202 static void         axp20x_attach(device_t, device_t, void *);
203 
204 static void         axp20x_sensors_refresh(struct sysmon_envsys *, envsys_data_t *);
205 static int          axp20x_read(struct axp20x_softc *, uint8_t, uint8_t *, size_t);
206 static int          axp20x_write(struct axp20x_softc *, uint8_t, uint8_t *, size_t);
207 
208 static void         axp20x_fdt_attach(struct axp20x_softc *);
209 
210 CFATTACH_DECL_NEW(axp20x, sizeof(struct axp20x_softc),
211     axp20x_match, axp20x_attach, NULL, NULL);
212 
213 static const struct device_compatible_entry compat_data[] = {
214           { .compat = "x-powers,axp209" },
215           DEVICE_COMPAT_EOL
216 };
217 
218 static int
axp20x_match(device_t parent,cfdata_t match,void * aux)219 axp20x_match(device_t parent, cfdata_t match, void *aux)
220 {
221           struct i2c_attach_args * const ia = aux;
222           int match_result;
223 
224           if (iic_use_direct_match(ia, match, compat_data, &match_result))
225                     return match_result;
226 
227           /* This device is direct-config only. */
228 
229           return 0;
230 }
231 
232 static void
axp20x_attach(device_t parent,device_t self,void * aux)233 axp20x_attach(device_t parent, device_t self, void *aux)
234 {
235           struct axp20x_softc *sc = device_private(self);
236           struct i2c_attach_args *ia = aux;
237           int first;
238           int error;
239           uint8_t value;
240 
241           sc->sc_dev = self;
242           sc->sc_i2c = ia->ia_tag;
243           sc->sc_addr = ia->ia_addr;
244           sc->sc_phandle = ia->ia_cookie;
245 
246           error = axp20x_read(sc, AXP_INPUT_STATUS,
247               &sc->sc_inputstatus, 1);
248           if (error) {
249                     aprint_error(": can't read status: %d\n", error);
250                     return;
251           }
252           error = axp20x_read(sc, AXP_POWER_MODE,
253               &sc->sc_powermode, 1);
254           if (error) {
255                     aprint_error(": can't read power mode: %d\n", error);
256                     return;
257           }
258           value = AXP_ADC_EN1_ACV | AXP_ADC_EN1_ACI | AXP_ADC_EN1_VBUSV | AXP_ADC_EN1_VBUSI | AXP_ADC_EN1_APSV | AXP_ADC_EN1_TS;
259           if (sc->sc_powermode & AXP_POWER_MODE_BATTOK)
260                     value |= AXP_ADC_EN1_BATTV | AXP_ADC_EN1_BATTI;
261           error = axp20x_write(sc, AXP_ADC_EN1, &value, 1);
262           if (error) {
263                     aprint_error(": can't set AXP_ADC_EN1\n");
264                     return;
265           }
266           error = axp20x_read(sc, AXP_ADC_EN2, &value, 1);
267           if (error) {
268                     aprint_error(": can't read AXP_ADC_EN2\n");
269                     return;
270           }
271           value |= AXP_ADC_EN2_TEMP;
272           error = axp20x_write(sc, AXP_ADC_EN2, &value, 1);
273           if (error) {
274                     aprint_error(": can't set AXP_ADC_EN2\n");
275                     return;
276           }
277 
278           aprint_naive("\n");
279           first = 1;
280           if (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_OK) {
281                     aprint_verbose(": AC used");
282                     first = 0;
283           } else if (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_PRESENT) {
284                     aprint_verbose(": AC present (but unused)");
285                     first = 0;
286           }
287           if (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_OK) {
288                     aprint_verbose("%s VBUS used", first ? ":" : ",");
289                     first = 0;
290           } else if (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_PRESENT) {
291                     aprint_verbose("%s VBUS present (but unused)", first ? ":" : ",");
292                     first = 0;
293           }
294           if (sc->sc_powermode & AXP_POWER_MODE_BATTOK) {
295                     aprint_verbose("%s battery present", first ? ":" : ",");
296           }
297           aprint_normal("\n");
298 
299           sc->sc_sme = sysmon_envsys_create();
300           sc->sc_sme->sme_name = device_xname(self);
301           sc->sc_sme->sme_cookie = sc;
302           sc->sc_sme->sme_refresh = axp20x_sensors_refresh;
303 
304           sc->sc_sensor[AXP_SENSOR_ACOK].units = ENVSYS_INDICATOR;
305           sc->sc_sensor[AXP_SENSOR_ACOK].state = ENVSYS_SVALID;
306           sc->sc_sensor[AXP_SENSOR_ACOK].value_cur =
307               (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_OK) ? 1 : 0;
308           snprintf(sc->sc_sensor[AXP_SENSOR_ACOK].desc,
309               sizeof(sc->sc_sensor[AXP_SENSOR_ACOK].desc), "AC input");
310           sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_ACOK]);
311           sc->sc_sensor[AXP_SENSOR_ACV].units = ENVSYS_SVOLTS_DC;
312           sc->sc_sensor[AXP_SENSOR_ACV].state = ENVSYS_SINVALID;
313           sc->sc_sensor[AXP_SENSOR_ACV].flags = ENVSYS_FHAS_ENTROPY;
314           snprintf(sc->sc_sensor[AXP_SENSOR_ACV].desc,
315               sizeof(sc->sc_sensor[AXP_SENSOR_ACV].desc), "AC input voltage");
316           sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_ACV]);
317           sc->sc_sensor[AXP_SENSOR_ACI].units = ENVSYS_SAMPS;
318           sc->sc_sensor[AXP_SENSOR_ACI].state = ENVSYS_SINVALID;
319           sc->sc_sensor[AXP_SENSOR_ACI].flags = ENVSYS_FHAS_ENTROPY;
320           snprintf(sc->sc_sensor[AXP_SENSOR_ACI].desc,
321               sizeof(sc->sc_sensor[AXP_SENSOR_ACI].desc), "AC input current");
322           sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_ACI]);
323 
324           sc->sc_sensor[AXP_SENSOR_VBUSOK].units = ENVSYS_INDICATOR;
325           sc->sc_sensor[AXP_SENSOR_VBUSOK].state = ENVSYS_SVALID;
326           sc->sc_sensor[AXP_SENSOR_VBUSOK].value_cur =
327               (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_OK) ? 1 : 0;
328           snprintf(sc->sc_sensor[AXP_SENSOR_VBUSOK].desc,
329               sizeof(sc->sc_sensor[AXP_SENSOR_VBUSOK].desc), "VBUS input");
330           sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_VBUSOK]);
331           sc->sc_sensor[AXP_SENSOR_VBUSV].units = ENVSYS_SVOLTS_DC;
332           sc->sc_sensor[AXP_SENSOR_VBUSV].state = ENVSYS_SINVALID;
333           sc->sc_sensor[AXP_SENSOR_VBUSV].flags = ENVSYS_FHAS_ENTROPY;
334           snprintf(sc->sc_sensor[AXP_SENSOR_VBUSV].desc,
335               sizeof(sc->sc_sensor[AXP_SENSOR_VBUSV].desc), "VBUS input voltage");
336           sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_VBUSV]);
337           sc->sc_sensor[AXP_SENSOR_VBUSI].units = ENVSYS_SAMPS;
338           sc->sc_sensor[AXP_SENSOR_VBUSI].state = ENVSYS_SINVALID;
339           sc->sc_sensor[AXP_SENSOR_VBUSI].flags = ENVSYS_FHAS_ENTROPY;
340           snprintf(sc->sc_sensor[AXP_SENSOR_VBUSI].desc,
341               sizeof(sc->sc_sensor[AXP_SENSOR_VBUSI].desc), "VBUS input current");
342           sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_VBUSI]);
343 
344           sc->sc_sensor[AXP_SENSOR_BATTOK].units = ENVSYS_INDICATOR;
345           sc->sc_sensor[AXP_SENSOR_BATTOK].state = ENVSYS_SVALID;
346           sc->sc_sensor[AXP_SENSOR_BATTOK].value_cur =
347               (sc->sc_powermode & AXP_POWER_MODE_BATTOK) ? 1 : 0;
348           snprintf(sc->sc_sensor[AXP_SENSOR_BATTOK].desc,
349               sizeof(sc->sc_sensor[AXP_SENSOR_BATTOK].desc), "battery");
350           sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_BATTOK]);
351           sc->sc_sensor[AXP_SENSOR_BATTV].units = ENVSYS_SVOLTS_DC;
352           sc->sc_sensor[AXP_SENSOR_BATTV].state = ENVSYS_SINVALID;
353           sc->sc_sensor[AXP_SENSOR_BATTV].flags = ENVSYS_FHAS_ENTROPY;
354           snprintf(sc->sc_sensor[AXP_SENSOR_BATTV].desc,
355               sizeof(sc->sc_sensor[AXP_SENSOR_BATTV].desc), "battery voltage");
356           sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_BATTV]);
357           sc->sc_sensor[AXP_SENSOR_BATTI].units = ENVSYS_SAMPS;
358           sc->sc_sensor[AXP_SENSOR_BATTI].state = ENVSYS_SINVALID;
359           sc->sc_sensor[AXP_SENSOR_BATTI].flags = ENVSYS_FHAS_ENTROPY;
360           snprintf(sc->sc_sensor[AXP_SENSOR_BATTI].desc,
361               sizeof(sc->sc_sensor[AXP_SENSOR_BATTI].desc), "battery current");
362           sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_BATTI]);
363 
364           sc->sc_sensor[AXP_SENSOR_APSV].units = ENVSYS_SVOLTS_DC;
365           sc->sc_sensor[AXP_SENSOR_APSV].state = ENVSYS_SINVALID;
366           sc->sc_sensor[AXP_SENSOR_APSV].flags = ENVSYS_FHAS_ENTROPY;
367           snprintf(sc->sc_sensor[AXP_SENSOR_APSV].desc,
368               sizeof(sc->sc_sensor[AXP_SENSOR_APSV].desc), "APS output voltage");
369           sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_APSV]);
370           sc->sc_sensor[AXP_SENSOR_TEMP].units = ENVSYS_STEMP;
371           sc->sc_sensor[AXP_SENSOR_TEMP].state = ENVSYS_SINVALID;
372           sc->sc_sensor[AXP_SENSOR_TEMP].flags = ENVSYS_FHAS_ENTROPY;
373           snprintf(sc->sc_sensor[AXP_SENSOR_TEMP].desc,
374               sizeof(sc->sc_sensor[AXP_SENSOR_TEMP].desc),
375               "internal temperature");
376           sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_TEMP]);
377 
378           sysmon_envsys_register(sc->sc_sme);
379 
380           if (axp20x_read(sc, AXP_DCDC2, &value, 1) == 0) {
381                     aprint_verbose_dev(sc->sc_dev, "DCDC2 %dmV\n",
382                         (int)(700 + (value & AXP_DCDC2_VOLT_MASK) * 25));
383           }
384           if (axp20x_read(sc, AXP_DCDC3, &value, 1) == 0) {
385                     aprint_verbose_dev(sc->sc_dev, "DCDC3 %dmV\n",
386                         (int)(700 + (value & AXP_DCDC3_VOLT_MASK) * 25));
387           }
388           if (axp20x_read(sc, AXP_LDO2_4, &value, 1) == 0) {
389                     aprint_verbose_dev(sc->sc_dev, "LDO2 %dmV, LDO4 %dmV\n",
390                         (int)(1800 +
391                         ((value & AXP_LDO2_VOLT_MASK) >> AXP_LDO2_VOLT_SHIFT) * 100
392                         ),
393                         ldo4_mvV[(value & AXP_LDO4_VOLT_MASK) >> AXP_LDO4_VOLT_SHIFT]);
394           }
395           if (axp20x_read(sc, AXP_LDO3, &value, 1) == 0) {
396                     if (value & AXP_LDO3_TRACK) {
397                               aprint_verbose_dev(sc->sc_dev, "LDO3: tracking\n");
398                     } else {
399                               aprint_verbose_dev(sc->sc_dev, "LDO3 %dmV\n",
400                                   (int)(700 + (value & AXP_LDO3_VOLT_MASK) * 25));
401                     }
402           }
403 
404           if (axp20x_read(sc, AXP_BKUP_CTRL, &value, 1) == 0) {
405                     if (value & AXP_BKUP_CTRL_ENABLE) {
406                               aprint_verbose_dev(sc->sc_dev,
407                                   "RTC supercap charger enabled: %dmV at %duA\n",
408                                   bkup_volt[(value & AXP_BKUP_CTRL_VOLT_MASK) >>
409                                   AXP_BKUP_CTRL_VOLT_SHIFT],
410                                   bkup_curr[(value & AXP_BKUP_CTRL_CURR_MASK) >>
411                                   AXP_BKUP_CTRL_CURR_SHIFT]
412                               );
413                     }
414           }
415 
416           axp20x_fdt_attach(sc);
417 }
418 
419 static void
axp20x_sensors_refresh_volt(struct axp20x_softc * sc,int reg,envsys_data_t * edata)420 axp20x_sensors_refresh_volt(struct axp20x_softc *sc, int reg,
421     envsys_data_t *edata)
422 {
423           uint8_t buf[2];
424           int error;
425 
426           error = axp20x_read(sc, reg, buf, sizeof(buf));
427           if (error) {
428                     edata->state = ENVSYS_SINVALID;
429           } else {
430                     edata->value_cur = ((buf[0] << 4) | (buf[1] & 0xf)) *
431                         axp20x_sensors_lsb[edata->sensor];
432                     edata->state = ENVSYS_SVALID;
433           }
434 }
435 
436 static void
axp20x_sensors_refresh_amp(struct axp20x_softc * sc,int reg,envsys_data_t * edata)437 axp20x_sensors_refresh_amp(struct axp20x_softc *sc, int reg,
438     envsys_data_t *edata)
439 {
440           uint8_t buf[2];
441           int error;
442 
443           error = axp20x_read(sc, reg, buf, sizeof(buf));
444           if (error) {
445                     edata->state = ENVSYS_SINVALID;
446           } else {
447                     edata->value_cur = ((buf[0] << 4) | (buf[1] & 0xf)) *
448                         axp20x_sensors_lsb[edata->sensor];
449                     edata->state = ENVSYS_SVALID;
450           }
451 }
452 
453 static void
axp20x_sensors_refresh(struct sysmon_envsys * sme,envsys_data_t * edata)454 axp20x_sensors_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
455 {
456           struct axp20x_softc *sc = sme->sme_cookie;
457           uint8_t buf[2];
458           int error;
459 
460           switch(edata->sensor) {
461           case AXP_SENSOR_ACOK:
462           case AXP_SENSOR_VBUSOK:
463                     error = axp20x_read(sc, AXP_INPUT_STATUS,
464                         &sc->sc_inputstatus, 1);
465                     if (error) {
466                               edata->state = ENVSYS_SINVALID;
467                               return;
468                     }
469                     if (edata->sensor == AXP_SENSOR_ACOK) {
470                         edata->value_cur =
471                               (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_OK) ? 1 : 0;
472                     } else {
473                         edata->value_cur =
474                               (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_OK) ? 1 : 0;
475                     }
476                     edata->state = ENVSYS_SVALID;
477                     return;
478           case AXP_SENSOR_BATTOK:
479                     error = axp20x_read(sc, AXP_POWER_MODE,
480                         &sc->sc_powermode, 1);
481                     if (error) {
482                               edata->state = ENVSYS_SINVALID;
483                               return;
484                     }
485                     edata->value_cur =
486                         (sc->sc_powermode & AXP_POWER_MODE_BATTOK) ? 1 : 0;
487                     return;
488           case AXP_SENSOR_ACV:
489                     if (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_OK)
490                               axp20x_sensors_refresh_volt(sc, AXP_ACV_MON_REG, edata);
491                     else
492                               edata->state = ENVSYS_SINVALID;
493                     return;
494           case AXP_SENSOR_ACI:
495                     if (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_OK)
496                               axp20x_sensors_refresh_amp(sc, AXP_ACI_MON_REG, edata);
497                     else
498                               edata->state = ENVSYS_SINVALID;
499                     return;
500           case AXP_SENSOR_VBUSV:
501                     if (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_OK)
502                               axp20x_sensors_refresh_volt(sc, AXP_VBUSV_MON_REG, edata);
503                     else
504                               edata->state = ENVSYS_SINVALID;
505                     return;
506           case AXP_SENSOR_VBUSI:
507                     if (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_OK)
508                               axp20x_sensors_refresh_amp(sc, AXP_VBUSI_MON_REG, edata);
509                     else
510                               edata->state = ENVSYS_SINVALID;
511                     return;
512           case AXP_SENSOR_BATTV:
513                     if (sc->sc_powermode & AXP_POWER_MODE_BATTOK)
514                               axp20x_sensors_refresh_volt(sc, AXP_BATTV_MON_REG, edata);
515                     else
516                               edata->state = ENVSYS_SINVALID;
517                     return;
518           case AXP_SENSOR_BATTI:
519                     if ((sc->sc_powermode & AXP_POWER_MODE_BATTOK) == 0) {
520                               edata->state = ENVSYS_SINVALID;
521                               return;
522                     }
523                     error = axp20x_read(sc, AXP_POWER_MODE,
524                         &sc->sc_inputstatus, 1);
525                     if (error) {
526                               edata->state = ENVSYS_SINVALID;
527                               return;
528                     }
529                     if (sc->sc_inputstatus & AXP_POWER_MODE_CHARGING) {
530                               axp20x_sensors_refresh_amp(sc, AXP_BATTCI_MON_REG,
531                                   edata);
532                               edata->value_cur = -edata->value_cur;
533                     } else {
534                               axp20x_sensors_refresh_amp(sc, AXP_BATTDI_MON_REG,
535                                   edata);
536                     }
537                     return;
538           case AXP_SENSOR_APSV:
539                     axp20x_sensors_refresh_volt(sc, AXP_APSV_MON_REG, edata);
540                     return;
541           case AXP_SENSOR_TEMP:
542                     error = axp20x_read(sc, AXP_TEMP_MON_REG, buf, sizeof(buf));
543                     if (error) {
544                               edata->state = ENVSYS_SINVALID;
545                     } else {
546                               /* between -144.7C and 264.8C, step +0.1C */
547                               edata->value_cur =
548                                   (((buf[0] << 4) | (buf[1] & 0xf)) - 1447)
549                                  * 100000 + 273150000;
550                               edata->state = ENVSYS_SVALID;
551                     }
552                     return;
553           default:
554                     aprint_error_dev(sc->sc_dev, "invalid sensor %d\n",
555                         edata->sensor);
556           }
557 }
558 
559 static int
axp20x_read(struct axp20x_softc * sc,uint8_t reg,uint8_t * val,size_t len)560 axp20x_read(struct axp20x_softc *sc, uint8_t reg, uint8_t *val, size_t len)
561 {
562           int ret;
563 
564           ret = iic_acquire_bus(sc->sc_i2c, 0);
565           if (ret == 0) {
566                     ret = iic_exec(sc->sc_i2c, I2C_OP_READ_WITH_STOP, sc->sc_addr,
567                         &reg, 1, val, len, 0);
568                     iic_release_bus(sc->sc_i2c, 0);
569           }
570 
571           return ret;
572 
573 }
574 
575 static int
axp20x_write(struct axp20x_softc * sc,uint8_t reg,uint8_t * val,size_t len)576 axp20x_write(struct axp20x_softc *sc, uint8_t reg, uint8_t *val, size_t len)
577 {
578           int ret;
579 
580           ret = iic_acquire_bus(sc->sc_i2c, 0);
581           if (ret == 0) {
582                     ret = iic_exec(sc->sc_i2c, I2C_OP_WRITE_WITH_STOP, sc->sc_addr,
583                         &reg, 1, val, len, 0);
584                     iic_release_bus(sc->sc_i2c, 0);
585           }
586 
587           return ret;
588 }
589 
590 static int
axp20x_set_dcdc(device_t dev,int dcdc,int mvolt)591 axp20x_set_dcdc(device_t dev, int dcdc, int mvolt)
592 {
593           struct axp20x_softc *sc = device_private(dev);
594           int ret;
595           int value;
596           uint8_t reg;
597 
598           KASSERT(sc != NULL);
599           value = (mvolt - 700) / 25;
600           switch (dcdc) {
601           case AXP20X_DCDC2:
602                     value <<= AXP_DCDC2_VOLT_SHIFT;
603                     if (value > AXP_DCDC2_VOLT_MASK)
604                               return EINVAL;
605                     reg = value & AXP_DCDC2_VOLT_MASK;
606                     ret = axp20x_write(sc, AXP_DCDC2, &reg, 1);
607                     if (ret)
608                               return ret;
609                     if (axp20x_read(sc, AXP_DCDC2, &reg, 1) == 0) {
610                               aprint_debug_dev(sc->sc_dev,
611                                   "DCDC2 changed to %dmV\n",
612                                   (int)(700 + (reg & AXP_DCDC2_VOLT_MASK) * 25));
613                     }
614                     return 0;
615 
616           case AXP20X_DCDC3:
617                     value <<= AXP_DCDC3_VOLT_SHIFT;
618                     if (value > AXP_DCDC3_VOLT_MASK)
619                               return EINVAL;
620                     reg = value & AXP_DCDC3_VOLT_MASK;
621                     ret = axp20x_write(sc, AXP_DCDC3, &reg, 1);
622                     if (ret)
623                               return ret;
624                     if (axp20x_read(sc, AXP_DCDC3, &reg, 1) == 0) {
625                               aprint_debug_dev(sc->sc_dev,
626                                   "DCDC3 changed to %dmV\n",
627                                   (int)(700 + (reg & AXP_DCDC3_VOLT_MASK) * 25));
628                     }
629                     return 0;
630           default:
631                     aprint_error_dev(dev, "wrong DCDC %d\n", dcdc);
632                     return EINVAL;
633           }
634 }
635 
636 static int
axp20x_get_dcdc(device_t dev,int dcdc,int * pmvolt)637 axp20x_get_dcdc(device_t dev, int dcdc, int *pmvolt)
638 {
639           struct axp20x_softc *sc = device_private(dev);
640           uint8_t reg;
641           int error;
642 
643           switch (dcdc) {
644           case AXP20X_DCDC2:
645                     error = axp20x_read(sc, AXP_DCDC2, &reg, 1);
646                     if (error != 0)
647                               return error;
648                     *pmvolt = __SHIFTOUT(reg, AXP_DCDC2_VOLT_MASK) * 25 + 700;
649                     return 0;
650           case AXP20X_DCDC3:
651                     error = axp20x_read(sc, AXP_DCDC3, &reg, 1);
652                     if (error != 0)
653                               return error;
654                     *pmvolt = __SHIFTOUT(reg, AXP_DCDC3_VOLT_MASK) * 25 + 700;
655                     return 0;
656           default:
657                     return EINVAL;
658           }
659 }
660 
661 static void
axp20x_poweroff(device_t dev)662 axp20x_poweroff(device_t dev)
663 {
664           struct axp20x_softc * const sc = device_private(dev);
665           uint8_t reg = AXP_SHUTDOWN_CTRL;
666           int error;
667 
668           error = axp20x_write(sc, AXP_SHUTDOWN, &reg, 1);
669           if (error) {
670                     device_printf(dev, "WARNING: unable to power off, error %d\n",
671                         error);
672           }
673 }
674 
675 static const struct axp20xregdef {
676           const char *name;
677           int dcdc;
678 } axp20x_regdefs[] = {
679           { "dcdc2", AXP20X_DCDC2 },
680           { "dcdc3", AXP20X_DCDC3 },
681 };
682 
683 struct axp20xreg_softc {
684           device_t  sc_dev;
685           int                 sc_phandle;
686           const struct axp20xregdef *sc_regdef;
687 };
688 
689 struct axp20xreg_attach_args {
690           int                 reg_phandle;
691 };
692 
693 static int
axp20xreg_acquire(device_t dev)694 axp20xreg_acquire(device_t dev)
695 {
696           return 0;
697 }
698 
699 static void
axp20xreg_release(device_t dev)700 axp20xreg_release(device_t dev)
701 {
702 }
703 
704 static int
axp20xreg_enable(device_t dev,bool enable)705 axp20xreg_enable(device_t dev, bool enable)
706 {
707           /* TODO */
708           return enable ? 0 : EINVAL;
709 }
710 
711 static int
axp20xreg_set_voltage(device_t dev,u_int min_uvol,u_int max_uvol)712 axp20xreg_set_voltage(device_t dev, u_int min_uvol, u_int max_uvol)
713 {
714           struct axp20xreg_softc * const sc = device_private(dev);
715 
716           return axp20x_set_dcdc(device_parent(dev), sc->sc_regdef->dcdc, min_uvol / 1000);
717 }
718 
719 static int
axp20xreg_get_voltage(device_t dev,u_int * puvol)720 axp20xreg_get_voltage(device_t dev, u_int *puvol)
721 {
722           struct axp20xreg_softc * const sc = device_private(dev);
723           int mvol, error;
724 
725           error = axp20x_get_dcdc(device_parent(dev), sc->sc_regdef->dcdc, &mvol);
726           if (error != 0)
727                     return error;
728 
729           *puvol = mvol * 1000;
730           return 0;
731 }
732 
733 static struct fdtbus_regulator_controller_func axp20xreg_funcs = {
734           .acquire = axp20xreg_acquire,
735           .release = axp20xreg_release,
736           .enable = axp20xreg_enable,
737           .set_voltage = axp20xreg_set_voltage,
738           .get_voltage = axp20xreg_get_voltage,
739 };
740 
741 static const struct axp20xregdef *
axp20xreg_lookup(int phandle)742 axp20xreg_lookup(int phandle)
743 {
744           const char *name;
745           int n;
746 
747           name = fdtbus_get_string(phandle, "name");
748           if (name == NULL)
749                     return NULL;
750 
751           for (n = 0; n < __arraycount(axp20x_regdefs); n++)
752                     if (strcmp(name, axp20x_regdefs[n].name) == 0)
753                               return &axp20x_regdefs[n];
754 
755           return NULL;
756 }
757 
758 static int
axp20xreg_match(device_t parent,cfdata_t match,void * aux)759 axp20xreg_match(device_t parent, cfdata_t match, void *aux)
760 {
761           const struct axp20xreg_attach_args *reg = aux;
762 
763           return axp20xreg_lookup(reg->reg_phandle) != NULL;
764 }
765 
766 static void
axp20xreg_attach(device_t parent,device_t self,void * aux)767 axp20xreg_attach(device_t parent, device_t self, void *aux)
768 {
769           struct axp20xreg_softc * const sc = device_private(self);
770           const struct axp20xreg_attach_args *reg = aux;
771           const char *regulator_name;
772 
773           sc->sc_dev = self;
774           sc->sc_phandle = reg->reg_phandle;
775           sc->sc_regdef = axp20xreg_lookup(reg->reg_phandle);
776 
777           regulator_name = fdtbus_get_string(reg->reg_phandle, "regulator-name");
778 
779           aprint_naive("\n");
780           if (regulator_name)
781                     aprint_normal(": %s (%s)\n", sc->sc_regdef->name, regulator_name);
782           else
783                     aprint_normal(": %s\n", sc->sc_regdef->name);
784 
785           fdtbus_register_regulator_controller(self, sc->sc_phandle, &axp20xreg_funcs);
786 }
787 
788 CFATTACH_DECL_NEW(axp20xreg, sizeof(struct axp20xreg_softc),
789     axp20xreg_match, axp20xreg_attach, NULL, NULL);
790 
791 static void
axp20x_fdt_poweroff(device_t dev)792 axp20x_fdt_poweroff(device_t dev)
793 {
794           delay(1000000);
795           axp20x_poweroff(dev);
796 }
797 
798 static struct fdtbus_power_controller_func axp20x_fdt_power_funcs = {
799           .poweroff = axp20x_fdt_poweroff,
800 };
801 
802 static void
axp20x_fdt_attach(struct axp20x_softc * sc)803 axp20x_fdt_attach(struct axp20x_softc *sc)
804 {
805           int regulators_phandle, child;
806 
807           fdtbus_register_power_controller(sc->sc_dev, sc->sc_phandle,
808               &axp20x_fdt_power_funcs);
809 
810           regulators_phandle = of_find_firstchild_byname(sc->sc_phandle, "regulators");
811           if (regulators_phandle == -1)
812                     return;
813 
814           for (child = OF_child(regulators_phandle); child; child = OF_peer(child)) {
815                     struct axp20xreg_attach_args reg = { .reg_phandle = child };
816                     config_found(sc->sc_dev, &reg, NULL, CFARGS_NONE);
817           }
818 }
819