axp20x.c revision 1.4 1 1.4 bouyer /* $NetBSD: axp20x.c,v 1.4 2015/10/15 13:48:57 bouyer Exp $ */
2 1.1 jmcneill
3 1.1 jmcneill /*-
4 1.1 jmcneill * Copyright (c) 2014 Jared D. McNeill <jmcneill (at) invisible.ca>
5 1.1 jmcneill * All rights reserved.
6 1.1 jmcneill *
7 1.1 jmcneill * Redistribution and use in source and binary forms, with or without
8 1.1 jmcneill * modification, are permitted provided that the following conditions
9 1.1 jmcneill * are met:
10 1.1 jmcneill * 1. Redistributions of source code must retain the above copyright
11 1.1 jmcneill * notice, this list of conditions and the following disclaimer.
12 1.1 jmcneill * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 jmcneill * notice, this list of conditions and the following disclaimer in the
14 1.1 jmcneill * documentation and/or other materials provided with the distribution.
15 1.1 jmcneill *
16 1.1 jmcneill * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 1.1 jmcneill * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 1.1 jmcneill * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 1.1 jmcneill * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 1.1 jmcneill * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 1.1 jmcneill * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 1.1 jmcneill * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 1.1 jmcneill * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 1.1 jmcneill * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 1.1 jmcneill * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 1.1 jmcneill * POSSIBILITY OF SUCH DAMAGE.
27 1.1 jmcneill */
28 1.1 jmcneill
29 1.1 jmcneill #include <sys/cdefs.h>
30 1.4 bouyer __KERNEL_RCSID(0, "$NetBSD: axp20x.c,v 1.4 2015/10/15 13:48:57 bouyer Exp $");
31 1.1 jmcneill
32 1.1 jmcneill #include <sys/param.h>
33 1.1 jmcneill #include <sys/systm.h>
34 1.1 jmcneill #include <sys/device.h>
35 1.1 jmcneill #include <sys/conf.h>
36 1.1 jmcneill #include <sys/bus.h>
37 1.1 jmcneill #include <sys/kmem.h>
38 1.1 jmcneill
39 1.1 jmcneill #include <dev/i2c/i2cvar.h>
40 1.3 bouyer #include <dev/i2c/axp20xvar.h>
41 1.1 jmcneill
42 1.1 jmcneill #include <dev/sysmon/sysmonvar.h>
43 1.1 jmcneill
44 1.3 bouyer #define AXP_INPUT_STATUS 0x00
45 1.3 bouyer #define AXP_INPUT_STATUS_AC_PRESENT __BIT(7)
46 1.3 bouyer #define AXP_INPUT_STATUS_AC_OK __BIT(6)
47 1.3 bouyer #define AXP_INPUT_STATUS_VBUS_PRESENT __BIT(5)
48 1.3 bouyer #define AXP_INPUT_STATUS_VBUS_OK __BIT(4)
49 1.3 bouyer
50 1.3 bouyer #define AXP_POWER_MODE 0x01
51 1.3 bouyer #define AXP_POWER_MODE_OVERTEMP __BIT(7)
52 1.3 bouyer #define AXP_POWER_MODE_CHARGING __BIT(6)
53 1.3 bouyer #define AXP_POWER_MODE_BATTOK __BIT(5)
54 1.3 bouyer
55 1.3 bouyer #define AXP_POWEROUT_CTRL 0x12
56 1.3 bouyer #define AXP_POWEROUT_CTRL_LDO3 __BIT(6)
57 1.3 bouyer #define AXP_POWEROUT_CTRL_DCDC2 __BIT(4)
58 1.3 bouyer #define AXP_POWEROUT_CTRL_LDO4 __BIT(3)
59 1.3 bouyer #define AXP_POWEROUT_CTRL_LDO2 __BIT(2)
60 1.3 bouyer #define AXP_POWEROUT_CTRL_DCDC3 __BIT(1)
61 1.3 bouyer #define AXP_POWEROUT_CTRL_EXTEN __BIT(0)
62 1.3 bouyer
63 1.3 bouyer #define AXP_DCDC2 0x23
64 1.3 bouyer #define AXP_DCDC2_VOLT_MASK __BITS(0,5)
65 1.3 bouyer #define AXP_DCDC2_VOLT_SHIFT 0
66 1.3 bouyer
67 1.3 bouyer #define AXP_DCDC2_LDO3_VRC 0x25
68 1.3 bouyer
69 1.3 bouyer #define AXP_DCDC3 0x27
70 1.3 bouyer #define AXP_DCDC3_VOLT_MASK __BITS(0,6)
71 1.3 bouyer #define AXP_DCDC3_VOLT_SHIFT 0
72 1.3 bouyer
73 1.3 bouyer #define AXP_LDO2_4 0x28
74 1.3 bouyer #define AXP_LDO2_VOLT_MASK __BITS(4,7)
75 1.3 bouyer #define AXP_LDO2_VOLT_SHIFT 4
76 1.3 bouyer #define AXP_LDO4_VOLT_MASK __BITS(0,3)
77 1.3 bouyer #define AXP_LDO4_VOLT_SHIFT 0
78 1.3 bouyer static int ldo4_mvV[] = {
79 1.3 bouyer 1250,
80 1.3 bouyer 1300,
81 1.3 bouyer 1400,
82 1.3 bouyer 1500,
83 1.3 bouyer 1600,
84 1.3 bouyer 1700,
85 1.3 bouyer 1800,
86 1.3 bouyer 1900,
87 1.3 bouyer 2000,
88 1.3 bouyer 2500,
89 1.3 bouyer 2700,
90 1.3 bouyer 2800,
91 1.3 bouyer 3000,
92 1.3 bouyer 3100,
93 1.3 bouyer 3200,
94 1.3 bouyer 3300
95 1.3 bouyer };
96 1.3 bouyer
97 1.3 bouyer #define AXP_LDO3 0x29
98 1.3 bouyer #define AXP_LDO3_TRACK __BIT(7)
99 1.3 bouyer #define AXP_LDO3_VOLT_MASK __BITS(0,6)
100 1.3 bouyer #define AXP_LDO3_VOLT_SHIFT 0
101 1.3 bouyer
102 1.3 bouyer #define AXP_ACV_MON_REG 0x56 /* 2 bytes */
103 1.3 bouyer #define AXP_ACI_MON_REG 0x58 /* 2 bytes */
104 1.3 bouyer #define AXP_VBUSV_MON_REG 0x5a /* 2 bytes */
105 1.3 bouyer #define AXP_VBUSI_MON_REG 0x5c /* 2 bytes */
106 1.1 jmcneill #define AXP_TEMP_MON_REG 0x5e /* 2 bytes */
107 1.3 bouyer #define AXP_BATTV_MON_REG 0x78 /* 2 bytes */
108 1.3 bouyer #define AXP_BATTCI_MON_REG 0x7a /* 2 bytes */
109 1.3 bouyer #define AXP_BATTDI_MON_REG 0x7c /* 2 bytes */
110 1.3 bouyer #define AXP_APSV_MON_REG 0x7e /* 2 bytes */
111 1.3 bouyer
112 1.3 bouyer #define AXP_ADC_EN1 0x82
113 1.3 bouyer #define AXP_ADC_EN1_BATTV __BIT(7)
114 1.3 bouyer #define AXP_ADC_EN1_BATTI __BIT(6)
115 1.3 bouyer #define AXP_ADC_EN1_ACV __BIT(5)
116 1.3 bouyer #define AXP_ADC_EN1_ACI __BIT(4)
117 1.3 bouyer #define AXP_ADC_EN1_VBUSV __BIT(3)
118 1.3 bouyer #define AXP_ADC_EN1_VBUSI __BIT(2)
119 1.3 bouyer #define AXP_ADC_EN1_APSV __BIT(1)
120 1.3 bouyer #define AXP_ADC_EN1_TS __BIT(0)
121 1.3 bouyer #define AXP_ADC_EN2 0x83
122 1.3 bouyer #define AXP_ADC_EN2_TEMP __BIT(7)
123 1.3 bouyer
124 1.3 bouyer #define AXP_SENSOR_ACOK 0
125 1.3 bouyer #define AXP_SENSOR_ACV 1
126 1.3 bouyer #define AXP_SENSOR_ACI 2
127 1.3 bouyer #define AXP_SENSOR_VBUSOK 3
128 1.3 bouyer #define AXP_SENSOR_VBUSV 4
129 1.3 bouyer #define AXP_SENSOR_VBUSI 5
130 1.3 bouyer #define AXP_SENSOR_BATTOK 6
131 1.3 bouyer #define AXP_SENSOR_BATTV 7
132 1.3 bouyer #define AXP_SENSOR_BATTI 8
133 1.3 bouyer #define AXP_SENSOR_APSV 9
134 1.3 bouyer #define AXP_SENSOR_TEMP 10
135 1.3 bouyer #define AXP_NSENSORS (AXP_SENSOR_TEMP + 1)
136 1.3 bouyer
137 1.3 bouyer /* define per-ADC LSB to uV/uA values */
138 1.3 bouyer static int axp20x_sensors_lsb[] = {
139 1.3 bouyer 0, /* AXP_SENSOR_ACOK */
140 1.3 bouyer 1700, /* AXP_SENSOR_ACV */
141 1.3 bouyer 625, /* AXP_SENSOR_ACI */
142 1.3 bouyer 0,
143 1.3 bouyer 1700, /* AXP_SENSOR_VBUSV */
144 1.3 bouyer 375, /* AXP_SENSOR_VBUSI */
145 1.3 bouyer 0,
146 1.3 bouyer 1100, /* AXP_SENSOR_BATTV */
147 1.3 bouyer 500, /* AXP_SENSOR_BATTI */
148 1.3 bouyer 1400, /* AXP_SENSOR_APSV */
149 1.3 bouyer };
150 1.3 bouyer
151 1.1 jmcneill
152 1.1 jmcneill struct axp20x_softc {
153 1.1 jmcneill device_t sc_dev;
154 1.1 jmcneill i2c_tag_t sc_i2c;
155 1.1 jmcneill i2c_addr_t sc_addr;
156 1.1 jmcneill
157 1.3 bouyer uint8_t sc_inputstatus;
158 1.3 bouyer uint8_t sc_powermode;
159 1.3 bouyer
160 1.1 jmcneill struct sysmon_envsys *sc_sme;
161 1.3 bouyer envsys_data_t sc_sensor[AXP_NSENSORS];
162 1.1 jmcneill };
163 1.1 jmcneill
164 1.1 jmcneill static int axp20x_match(device_t, cfdata_t, void *);
165 1.1 jmcneill static void axp20x_attach(device_t, device_t, void *);
166 1.1 jmcneill
167 1.1 jmcneill static void axp20x_sensors_refresh(struct sysmon_envsys *, envsys_data_t *);
168 1.3 bouyer static int axp20x_read(struct axp20x_softc *, uint8_t, uint8_t *, size_t, int);
169 1.3 bouyer static int axp20x_write(struct axp20x_softc *, uint8_t, uint8_t *, size_t, int);
170 1.1 jmcneill
171 1.1 jmcneill CFATTACH_DECL_NEW(axp20x, sizeof(struct axp20x_softc),
172 1.1 jmcneill axp20x_match, axp20x_attach, NULL, NULL);
173 1.1 jmcneill
174 1.1 jmcneill static int
175 1.1 jmcneill axp20x_match(device_t parent, cfdata_t match, void *aux)
176 1.1 jmcneill {
177 1.1 jmcneill return 1;
178 1.1 jmcneill }
179 1.1 jmcneill
180 1.1 jmcneill static void
181 1.1 jmcneill axp20x_attach(device_t parent, device_t self, void *aux)
182 1.1 jmcneill {
183 1.1 jmcneill struct axp20x_softc *sc = device_private(self);
184 1.1 jmcneill struct i2c_attach_args *ia = aux;
185 1.3 bouyer int first;
186 1.3 bouyer int error;
187 1.3 bouyer uint8_t value;
188 1.1 jmcneill
189 1.1 jmcneill sc->sc_dev = self;
190 1.1 jmcneill sc->sc_i2c = ia->ia_tag;
191 1.1 jmcneill sc->sc_addr = ia->ia_addr;
192 1.1 jmcneill
193 1.3 bouyer error = axp20x_read(sc, AXP_INPUT_STATUS,
194 1.3 bouyer &sc->sc_inputstatus, 1, I2C_F_POLL);
195 1.3 bouyer if (error) {
196 1.3 bouyer aprint_error(": can't read status: %d\n", error);
197 1.3 bouyer return;
198 1.3 bouyer }
199 1.3 bouyer error = axp20x_read(sc, AXP_POWER_MODE,
200 1.3 bouyer &sc->sc_powermode, 1, I2C_F_POLL);
201 1.3 bouyer if (error) {
202 1.3 bouyer aprint_error(": can't read power mode: %d\n", error);
203 1.3 bouyer return;
204 1.3 bouyer }
205 1.3 bouyer 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;
206 1.3 bouyer if (sc->sc_powermode & AXP_POWER_MODE_BATTOK)
207 1.3 bouyer value |= AXP_ADC_EN1_BATTV | AXP_ADC_EN1_BATTI;
208 1.3 bouyer error = axp20x_write(sc, AXP_ADC_EN1, &value, 1, I2C_F_POLL);
209 1.3 bouyer if (error) {
210 1.3 bouyer aprint_error(": can't set AXP_ADC_EN1\n");
211 1.3 bouyer return;
212 1.3 bouyer }
213 1.3 bouyer error = axp20x_read(sc, AXP_ADC_EN2, &value, 1, I2C_F_POLL);
214 1.3 bouyer if (error) {
215 1.3 bouyer aprint_error(": can't read AXP_ADC_EN2\n");
216 1.3 bouyer return;
217 1.3 bouyer }
218 1.3 bouyer value |= AXP_ADC_EN2_TEMP;
219 1.3 bouyer error = axp20x_write(sc, AXP_ADC_EN2, &value, 1, I2C_F_POLL);
220 1.3 bouyer if (error) {
221 1.3 bouyer aprint_error(": can't set AXP_ADC_EN2\n");
222 1.3 bouyer return;
223 1.3 bouyer }
224 1.3 bouyer
225 1.1 jmcneill aprint_naive("\n");
226 1.3 bouyer first = 1;
227 1.3 bouyer if (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_OK) {
228 1.4 bouyer aprint_verbose(": AC used");
229 1.3 bouyer first = 0;
230 1.3 bouyer } else if (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_PRESENT) {
231 1.4 bouyer aprint_verbose(": AC present (but unused)");
232 1.3 bouyer first = 0;
233 1.3 bouyer }
234 1.3 bouyer if (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_OK) {
235 1.4 bouyer aprint_verbose("%s VBUS used", first ? ":" : ",");
236 1.3 bouyer first = 0;
237 1.3 bouyer } else if (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_PRESENT) {
238 1.4 bouyer aprint_verbose("%s VBUS present (but unused)", first ? ":" : ",");
239 1.3 bouyer first = 0;
240 1.3 bouyer }
241 1.3 bouyer if (sc->sc_powermode & AXP_POWER_MODE_BATTOK) {
242 1.4 bouyer aprint_verbose("%s battery present", first ? ":" : ",");
243 1.3 bouyer }
244 1.1 jmcneill aprint_normal("\n");
245 1.1 jmcneill
246 1.1 jmcneill sc->sc_sme = sysmon_envsys_create();
247 1.1 jmcneill sc->sc_sme->sme_name = device_xname(self);
248 1.1 jmcneill sc->sc_sme->sme_cookie = sc;
249 1.1 jmcneill sc->sc_sme->sme_refresh = axp20x_sensors_refresh;
250 1.1 jmcneill
251 1.3 bouyer sc->sc_sensor[AXP_SENSOR_ACOK].units = ENVSYS_INDICATOR;
252 1.3 bouyer sc->sc_sensor[AXP_SENSOR_ACOK].state = ENVSYS_SVALID;
253 1.3 bouyer sc->sc_sensor[AXP_SENSOR_ACOK].value_cur =
254 1.3 bouyer (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_OK) ? 1 : 0;
255 1.3 bouyer snprintf(sc->sc_sensor[AXP_SENSOR_ACOK].desc,
256 1.3 bouyer sizeof(sc->sc_sensor[AXP_SENSOR_ACOK].desc), "AC input");
257 1.3 bouyer sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_ACOK]);
258 1.3 bouyer sc->sc_sensor[AXP_SENSOR_ACV].units = ENVSYS_SVOLTS_DC;
259 1.3 bouyer sc->sc_sensor[AXP_SENSOR_ACV].state = ENVSYS_SINVALID;
260 1.3 bouyer sc->sc_sensor[AXP_SENSOR_ACV].flags = ENVSYS_FHAS_ENTROPY;
261 1.3 bouyer snprintf(sc->sc_sensor[AXP_SENSOR_ACV].desc,
262 1.3 bouyer sizeof(sc->sc_sensor[AXP_SENSOR_ACV].desc), "AC input voltage");
263 1.3 bouyer sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_ACV]);
264 1.3 bouyer sc->sc_sensor[AXP_SENSOR_ACI].units = ENVSYS_SAMPS;
265 1.3 bouyer sc->sc_sensor[AXP_SENSOR_ACI].state = ENVSYS_SINVALID;
266 1.3 bouyer sc->sc_sensor[AXP_SENSOR_ACI].flags = ENVSYS_FHAS_ENTROPY;
267 1.3 bouyer snprintf(sc->sc_sensor[AXP_SENSOR_ACI].desc,
268 1.3 bouyer sizeof(sc->sc_sensor[AXP_SENSOR_ACI].desc), "AC input current");
269 1.3 bouyer sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_ACI]);
270 1.3 bouyer
271 1.3 bouyer sc->sc_sensor[AXP_SENSOR_VBUSOK].units = ENVSYS_INDICATOR;
272 1.3 bouyer sc->sc_sensor[AXP_SENSOR_VBUSOK].state = ENVSYS_SVALID;
273 1.3 bouyer sc->sc_sensor[AXP_SENSOR_VBUSOK].value_cur =
274 1.3 bouyer (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_OK) ? 1 : 0;
275 1.3 bouyer snprintf(sc->sc_sensor[AXP_SENSOR_VBUSOK].desc,
276 1.3 bouyer sizeof(sc->sc_sensor[AXP_SENSOR_VBUSOK].desc), "VBUS input");
277 1.3 bouyer sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_VBUSOK]);
278 1.3 bouyer sc->sc_sensor[AXP_SENSOR_VBUSV].units = ENVSYS_SVOLTS_DC;
279 1.3 bouyer sc->sc_sensor[AXP_SENSOR_VBUSV].state = ENVSYS_SINVALID;
280 1.3 bouyer sc->sc_sensor[AXP_SENSOR_VBUSV].flags = ENVSYS_FHAS_ENTROPY;
281 1.3 bouyer snprintf(sc->sc_sensor[AXP_SENSOR_VBUSV].desc,
282 1.3 bouyer sizeof(sc->sc_sensor[AXP_SENSOR_VBUSV].desc), "VBUS input voltage");
283 1.3 bouyer sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_VBUSV]);
284 1.3 bouyer sc->sc_sensor[AXP_SENSOR_VBUSI].units = ENVSYS_SAMPS;
285 1.3 bouyer sc->sc_sensor[AXP_SENSOR_VBUSI].state = ENVSYS_SINVALID;
286 1.3 bouyer sc->sc_sensor[AXP_SENSOR_VBUSI].flags = ENVSYS_FHAS_ENTROPY;
287 1.3 bouyer snprintf(sc->sc_sensor[AXP_SENSOR_VBUSI].desc,
288 1.3 bouyer sizeof(sc->sc_sensor[AXP_SENSOR_VBUSI].desc), "VBUS input current");
289 1.3 bouyer sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_VBUSI]);
290 1.3 bouyer
291 1.3 bouyer sc->sc_sensor[AXP_SENSOR_BATTOK].units = ENVSYS_INDICATOR;
292 1.3 bouyer sc->sc_sensor[AXP_SENSOR_BATTOK].state = ENVSYS_SVALID;
293 1.3 bouyer sc->sc_sensor[AXP_SENSOR_BATTOK].value_cur =
294 1.3 bouyer (sc->sc_powermode & AXP_POWER_MODE_BATTOK) ? 1 : 0;
295 1.3 bouyer snprintf(sc->sc_sensor[AXP_SENSOR_BATTOK].desc,
296 1.3 bouyer sizeof(sc->sc_sensor[AXP_SENSOR_BATTOK].desc), "battery");
297 1.3 bouyer sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_BATTOK]);
298 1.3 bouyer sc->sc_sensor[AXP_SENSOR_BATTV].units = ENVSYS_SVOLTS_DC;
299 1.3 bouyer sc->sc_sensor[AXP_SENSOR_BATTV].state = ENVSYS_SINVALID;
300 1.3 bouyer sc->sc_sensor[AXP_SENSOR_BATTV].flags = ENVSYS_FHAS_ENTROPY;
301 1.3 bouyer snprintf(sc->sc_sensor[AXP_SENSOR_BATTV].desc,
302 1.3 bouyer sizeof(sc->sc_sensor[AXP_SENSOR_BATTV].desc), "battery voltage");
303 1.3 bouyer sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_BATTV]);
304 1.3 bouyer sc->sc_sensor[AXP_SENSOR_BATTI].units = ENVSYS_SAMPS;
305 1.3 bouyer sc->sc_sensor[AXP_SENSOR_BATTI].state = ENVSYS_SINVALID;
306 1.3 bouyer sc->sc_sensor[AXP_SENSOR_BATTI].flags = ENVSYS_FHAS_ENTROPY;
307 1.3 bouyer snprintf(sc->sc_sensor[AXP_SENSOR_BATTI].desc,
308 1.3 bouyer sizeof(sc->sc_sensor[AXP_SENSOR_BATTI].desc), "battery current");
309 1.3 bouyer sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_BATTI]);
310 1.3 bouyer
311 1.3 bouyer sc->sc_sensor[AXP_SENSOR_APSV].units = ENVSYS_SVOLTS_DC;
312 1.3 bouyer sc->sc_sensor[AXP_SENSOR_APSV].state = ENVSYS_SINVALID;
313 1.3 bouyer sc->sc_sensor[AXP_SENSOR_APSV].flags = ENVSYS_FHAS_ENTROPY;
314 1.3 bouyer snprintf(sc->sc_sensor[AXP_SENSOR_APSV].desc,
315 1.3 bouyer sizeof(sc->sc_sensor[AXP_SENSOR_APSV].desc), "APS output voltage");
316 1.3 bouyer sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_APSV]);
317 1.3 bouyer sc->sc_sensor[AXP_SENSOR_TEMP].units = ENVSYS_STEMP;
318 1.3 bouyer sc->sc_sensor[AXP_SENSOR_TEMP].state = ENVSYS_SINVALID;
319 1.3 bouyer sc->sc_sensor[AXP_SENSOR_TEMP].flags = ENVSYS_FHAS_ENTROPY;
320 1.3 bouyer snprintf(sc->sc_sensor[AXP_SENSOR_TEMP].desc,
321 1.3 bouyer sizeof(sc->sc_sensor[AXP_SENSOR_TEMP].desc),
322 1.1 jmcneill "internal temperature");
323 1.3 bouyer sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_TEMP]);
324 1.1 jmcneill
325 1.1 jmcneill sysmon_envsys_register(sc->sc_sme);
326 1.3 bouyer
327 1.3 bouyer if (axp20x_read(sc, AXP_DCDC2, &value, 1, I2C_F_POLL) == 0) {
328 1.4 bouyer aprint_verbose_dev(sc->sc_dev, ": DCDC2 %dmV\n",
329 1.3 bouyer (int)(700 + (value & AXP_DCDC2_VOLT_MASK) * 25));
330 1.3 bouyer }
331 1.3 bouyer if (axp20x_read(sc, AXP_DCDC3, &value, 1, I2C_F_POLL) == 0) {
332 1.4 bouyer aprint_verbose_dev(sc->sc_dev, ": DCDC3 %dmV\n",
333 1.3 bouyer (int)(700 + (value & AXP_DCDC3_VOLT_MASK) * 25));
334 1.3 bouyer }
335 1.3 bouyer if (axp20x_read(sc, AXP_LDO2_4, &value, 1, I2C_F_POLL) == 0) {
336 1.4 bouyer aprint_verbose_dev(sc->sc_dev, ": LDO2 %dmV, LDO4 %dmV\n",
337 1.3 bouyer (int)(1800 +
338 1.3 bouyer ((value & AXP_LDO2_VOLT_MASK) >> AXP_LDO2_VOLT_SHIFT) * 100
339 1.3 bouyer ),
340 1.3 bouyer ldo4_mvV[(value & AXP_LDO4_VOLT_MASK) >> AXP_LDO4_VOLT_SHIFT]);
341 1.3 bouyer }
342 1.3 bouyer if (axp20x_read(sc, AXP_LDO3, &value, 1, I2C_F_POLL) == 0) {
343 1.3 bouyer if (value & AXP_LDO3_TRACK) {
344 1.4 bouyer aprint_verbose_dev(sc->sc_dev, ": LDO3: tracking\n");
345 1.3 bouyer } else {
346 1.4 bouyer aprint_verbose_dev(sc->sc_dev, ": LDO3 %dmV\n",
347 1.3 bouyer (int)(700 + (value & AXP_LDO3_VOLT_MASK) * 25));
348 1.3 bouyer }
349 1.3 bouyer }
350 1.1 jmcneill }
351 1.1 jmcneill
352 1.1 jmcneill static void
353 1.3 bouyer axp20x_sensors_refresh_volt(struct axp20x_softc *sc, int reg,
354 1.3 bouyer envsys_data_t *edata)
355 1.1 jmcneill {
356 1.1 jmcneill uint8_t buf[2];
357 1.1 jmcneill int error;
358 1.1 jmcneill
359 1.3 bouyer error = axp20x_read(sc, reg, buf, sizeof(buf), 0);
360 1.3 bouyer if (error) {
361 1.3 bouyer edata->state = ENVSYS_SINVALID;
362 1.3 bouyer } else {
363 1.3 bouyer edata->value_cur = ((buf[0] << 4) | (buf[1] & 0xf)) *
364 1.3 bouyer axp20x_sensors_lsb[edata->sensor];
365 1.3 bouyer edata->state = ENVSYS_SVALID;
366 1.3 bouyer }
367 1.3 bouyer }
368 1.3 bouyer
369 1.3 bouyer static void
370 1.3 bouyer axp20x_sensors_refresh_amp(struct axp20x_softc *sc, int reg,
371 1.3 bouyer envsys_data_t *edata)
372 1.3 bouyer {
373 1.3 bouyer uint8_t buf[2];
374 1.3 bouyer int error;
375 1.1 jmcneill
376 1.3 bouyer error = axp20x_read(sc, reg, buf, sizeof(buf), 0);
377 1.1 jmcneill if (error) {
378 1.1 jmcneill edata->state = ENVSYS_SINVALID;
379 1.1 jmcneill } else {
380 1.3 bouyer edata->value_cur = ((buf[0] << 4) | (buf[1] & 0xf)) *
381 1.3 bouyer axp20x_sensors_lsb[edata->sensor];
382 1.1 jmcneill edata->state = ENVSYS_SVALID;
383 1.1 jmcneill }
384 1.1 jmcneill }
385 1.1 jmcneill
386 1.3 bouyer static void
387 1.3 bouyer axp20x_sensors_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
388 1.3 bouyer {
389 1.3 bouyer struct axp20x_softc *sc = sme->sme_cookie;
390 1.3 bouyer uint8_t buf[2];
391 1.3 bouyer int error;
392 1.3 bouyer
393 1.3 bouyer switch(edata->sensor) {
394 1.3 bouyer case AXP_SENSOR_ACOK:
395 1.3 bouyer case AXP_SENSOR_VBUSOK:
396 1.3 bouyer error = axp20x_read(sc, AXP_INPUT_STATUS,
397 1.3 bouyer &sc->sc_inputstatus, 1, 0);
398 1.3 bouyer if (error) {
399 1.3 bouyer edata->state = ENVSYS_SINVALID;
400 1.3 bouyer return;
401 1.3 bouyer }
402 1.3 bouyer if (edata->sensor == AXP_SENSOR_ACOK) {
403 1.3 bouyer edata->value_cur =
404 1.3 bouyer (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_OK) ? 1 : 0;
405 1.3 bouyer } else {
406 1.3 bouyer edata->value_cur =
407 1.3 bouyer (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_OK) ? 1 : 0;
408 1.3 bouyer }
409 1.3 bouyer edata->state = ENVSYS_SVALID;
410 1.3 bouyer return;
411 1.3 bouyer case AXP_SENSOR_BATTOK:
412 1.3 bouyer error = axp20x_read(sc, AXP_POWER_MODE,
413 1.3 bouyer &sc->sc_powermode, 1, 0);
414 1.3 bouyer if (error) {
415 1.3 bouyer edata->state = ENVSYS_SINVALID;
416 1.3 bouyer return;
417 1.3 bouyer }
418 1.3 bouyer edata->value_cur =
419 1.3 bouyer (sc->sc_powermode & AXP_POWER_MODE_BATTOK) ? 1 : 0;
420 1.3 bouyer return;
421 1.3 bouyer case AXP_SENSOR_ACV:
422 1.3 bouyer if (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_OK)
423 1.3 bouyer axp20x_sensors_refresh_volt(sc, AXP_ACV_MON_REG, edata);
424 1.3 bouyer else
425 1.3 bouyer edata->state = ENVSYS_SINVALID;
426 1.3 bouyer return;
427 1.3 bouyer case AXP_SENSOR_ACI:
428 1.3 bouyer if (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_OK)
429 1.3 bouyer axp20x_sensors_refresh_amp(sc, AXP_ACI_MON_REG, edata);
430 1.3 bouyer else
431 1.3 bouyer edata->state = ENVSYS_SINVALID;
432 1.3 bouyer return;
433 1.3 bouyer case AXP_SENSOR_VBUSV:
434 1.3 bouyer if (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_OK)
435 1.3 bouyer axp20x_sensors_refresh_volt(sc, AXP_VBUSV_MON_REG, edata);
436 1.3 bouyer else
437 1.3 bouyer edata->state = ENVSYS_SINVALID;
438 1.3 bouyer return;
439 1.3 bouyer case AXP_SENSOR_VBUSI:
440 1.3 bouyer if (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_OK)
441 1.3 bouyer axp20x_sensors_refresh_amp(sc, AXP_VBUSI_MON_REG, edata);
442 1.3 bouyer else
443 1.3 bouyer edata->state = ENVSYS_SINVALID;
444 1.3 bouyer return;
445 1.3 bouyer case AXP_SENSOR_BATTV:
446 1.3 bouyer if (sc->sc_powermode & AXP_POWER_MODE_BATTOK)
447 1.3 bouyer axp20x_sensors_refresh_volt(sc, AXP_BATTV_MON_REG, edata);
448 1.3 bouyer else
449 1.3 bouyer edata->state = ENVSYS_SINVALID;
450 1.3 bouyer return;
451 1.3 bouyer case AXP_SENSOR_BATTI:
452 1.3 bouyer if ((sc->sc_powermode & AXP_POWER_MODE_BATTOK) == 0) {
453 1.3 bouyer edata->state = ENVSYS_SINVALID;
454 1.3 bouyer return;
455 1.3 bouyer }
456 1.3 bouyer error = axp20x_read(sc, AXP_POWER_MODE,
457 1.3 bouyer &sc->sc_inputstatus, 1, 0);
458 1.3 bouyer if (error) {
459 1.3 bouyer edata->state = ENVSYS_SINVALID;
460 1.3 bouyer return;
461 1.3 bouyer }
462 1.3 bouyer if (sc->sc_inputstatus & AXP_POWER_MODE_CHARGING) {
463 1.3 bouyer axp20x_sensors_refresh_amp(sc, AXP_BATTCI_MON_REG,
464 1.3 bouyer edata);
465 1.3 bouyer edata->value_cur = -edata->value_cur;
466 1.3 bouyer } else {
467 1.3 bouyer axp20x_sensors_refresh_amp(sc, AXP_BATTDI_MON_REG,
468 1.3 bouyer edata);
469 1.3 bouyer }
470 1.3 bouyer return;
471 1.3 bouyer case AXP_SENSOR_APSV:
472 1.3 bouyer axp20x_sensors_refresh_volt(sc, AXP_APSV_MON_REG, edata);
473 1.3 bouyer return;
474 1.3 bouyer case AXP_SENSOR_TEMP:
475 1.3 bouyer error = axp20x_read(sc, AXP_TEMP_MON_REG, buf, sizeof(buf), 0);
476 1.3 bouyer if (error) {
477 1.3 bouyer edata->state = ENVSYS_SINVALID;
478 1.3 bouyer } else {
479 1.3 bouyer /* between -144.7C and 264.8C, step +0.1C */
480 1.3 bouyer edata->value_cur =
481 1.3 bouyer (((buf[0] << 4) | (buf[1] & 0xf)) - 1447)
482 1.3 bouyer * 100000 + 273150000;
483 1.3 bouyer edata->state = ENVSYS_SVALID;
484 1.3 bouyer }
485 1.3 bouyer return;
486 1.3 bouyer default:
487 1.3 bouyer aprint_error_dev(sc->sc_dev, ": invalid sensor %d\n",
488 1.3 bouyer edata->sensor);
489 1.3 bouyer }
490 1.3 bouyer }
491 1.3 bouyer
492 1.3 bouyer static int
493 1.3 bouyer axp20x_read(struct axp20x_softc *sc, uint8_t reg, uint8_t *val, size_t len,
494 1.3 bouyer int flags)
495 1.3 bouyer {
496 1.3 bouyer int ret;
497 1.3 bouyer iic_acquire_bus(sc->sc_i2c, flags);
498 1.3 bouyer ret = iic_smbus_block_read(sc->sc_i2c, sc->sc_addr,
499 1.3 bouyer reg, val, len, flags);
500 1.3 bouyer iic_release_bus(sc->sc_i2c, flags);
501 1.3 bouyer return ret;
502 1.3 bouyer
503 1.3 bouyer }
504 1.3 bouyer
505 1.1 jmcneill static int
506 1.3 bouyer axp20x_write(struct axp20x_softc *sc, uint8_t reg, uint8_t *val, size_t len,
507 1.3 bouyer int flags)
508 1.1 jmcneill {
509 1.3 bouyer int ret;
510 1.3 bouyer iic_acquire_bus(sc->sc_i2c, flags);
511 1.3 bouyer ret = iic_smbus_block_write(sc->sc_i2c, sc->sc_addr,
512 1.3 bouyer reg, val, len, flags);
513 1.3 bouyer iic_release_bus(sc->sc_i2c, flags);
514 1.3 bouyer return ret;
515 1.3 bouyer }
516 1.3 bouyer
517 1.3 bouyer int
518 1.3 bouyer axp20x_set_dcdc(device_t dev, int dcdc, int mvolt, bool poll)
519 1.3 bouyer {
520 1.3 bouyer struct axp20x_softc *sc = device_private(dev);
521 1.3 bouyer int ret;
522 1.3 bouyer int value;
523 1.3 bouyer uint8_t reg;
524 1.3 bouyer
525 1.3 bouyer KASSERT(sc != NULL);
526 1.3 bouyer value = (mvolt - 700) / 25;
527 1.3 bouyer switch (dcdc) {
528 1.3 bouyer case AXP20X_DCDC2:
529 1.3 bouyer value <<= AXP_DCDC2_VOLT_SHIFT;
530 1.3 bouyer if (value > AXP_DCDC2_VOLT_MASK)
531 1.3 bouyer return EINVAL;
532 1.3 bouyer reg = value & AXP_DCDC2_VOLT_MASK;
533 1.3 bouyer ret = axp20x_write(sc, AXP_DCDC2, ®, 1,
534 1.3 bouyer poll ? I2C_F_POLL : 0);
535 1.3 bouyer if (ret)
536 1.3 bouyer return ret;
537 1.3 bouyer if (axp20x_read(sc, AXP_DCDC2, ®, 1, poll ? I2C_F_POLL : 0)
538 1.3 bouyer == 0) {
539 1.4 bouyer aprint_verbose_dev(sc->sc_dev,
540 1.3 bouyer ": DCDC2 changed to %dmV\n",
541 1.3 bouyer (int)(700 + (reg & AXP_DCDC2_VOLT_MASK) * 25));
542 1.3 bouyer }
543 1.3 bouyer return 0;
544 1.3 bouyer
545 1.3 bouyer case AXP20X_DCDC3:
546 1.4 bouyer value <<= AXP_DCDC3_VOLT_SHIFT;
547 1.4 bouyer if (value > AXP_DCDC3_VOLT_MASK)
548 1.3 bouyer return EINVAL;
549 1.4 bouyer reg = value & AXP_DCDC3_VOLT_MASK;
550 1.4 bouyer ret = axp20x_write(sc, AXP_DCDC3, ®, 1,
551 1.3 bouyer poll ? I2C_F_POLL : 0);
552 1.3 bouyer if (ret)
553 1.3 bouyer return ret;
554 1.4 bouyer if (axp20x_read(sc, AXP_DCDC3, ®, 1, poll ? I2C_F_POLL : 0)
555 1.3 bouyer == 0) {
556 1.4 bouyer aprint_verbose_dev(sc->sc_dev,
557 1.4 bouyer ": DCDC3 changed to %dmV\n",
558 1.4 bouyer (int)(700 + (reg & AXP_DCDC3_VOLT_MASK) * 25));
559 1.3 bouyer }
560 1.3 bouyer return 0;
561 1.3 bouyer default:
562 1.3 bouyer aprint_error_dev(dev, "wrong DCDC %d\n", dcdc);
563 1.3 bouyer return EINVAL;
564 1.3 bouyer }
565 1.1 jmcneill }
566