diff options
-rw-r--r-- | firmware/SOURCES | 4 | ||||
-rw-r--r-- | firmware/drivers/axp-pmu.c | 670 | ||||
-rw-r--r-- | firmware/drivers/axp192.c | 810 | ||||
-rw-r--r-- | firmware/export/axp-pmu.h | 151 | ||||
-rw-r--r-- | firmware/export/axp192-defs.h | 308 | ||||
-rw-r--r-- | firmware/export/axp192.h | 131 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/erosqnative/button-erosqnative.c | 10 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/erosqnative/power-erosqnative.c | 82 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c | 8 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c | 80 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/shanlingq1/button-shanlingq1.c | 8 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/shanlingq1/power-shanlingq1.c | 70 |
12 files changed, 910 insertions, 1422 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES index 8868e4f21f..87db67d8fd 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES | |||
@@ -1947,8 +1947,8 @@ drivers/touchpad.c | |||
1947 | #ifdef HAVE_I2C_ASYNC | 1947 | #ifdef HAVE_I2C_ASYNC |
1948 | drivers/i2c-async.c | 1948 | drivers/i2c-async.c |
1949 | #endif | 1949 | #endif |
1950 | #if defined(HAVE_AXP_PMU) && HAVE_AXP_PMU == 192 | 1950 | #ifdef HAVE_AXP_PMU |
1951 | drivers/axp192.c | 1951 | drivers/axp-pmu.c |
1952 | #endif | 1952 | #endif |
1953 | #ifdef HAVE_FT6x06 | 1953 | #ifdef HAVE_FT6x06 |
1954 | drivers/ft6x06.c | 1954 | drivers/ft6x06.c |
diff --git a/firmware/drivers/axp-pmu.c b/firmware/drivers/axp-pmu.c new file mode 100644 index 0000000000..fd1126dbbf --- /dev/null +++ b/firmware/drivers/axp-pmu.c | |||
@@ -0,0 +1,670 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2021 Aidan MacDonald | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include "axp-pmu.h" | ||
23 | #include "power.h" | ||
24 | #include "system.h" | ||
25 | #include "i2c-async.h" | ||
26 | #include <string.h> | ||
27 | |||
28 | /* Headers for the debug menu */ | ||
29 | #ifndef BOOTLOADER | ||
30 | # include "action.h" | ||
31 | # include "list.h" | ||
32 | # include <stdio.h> | ||
33 | #endif | ||
34 | |||
35 | struct axp_adc_info { | ||
36 | uint8_t reg; | ||
37 | uint8_t en_reg; | ||
38 | uint8_t en_bit; | ||
39 | }; | ||
40 | |||
41 | struct axp_supply_info { | ||
42 | uint8_t volt_reg; | ||
43 | uint8_t volt_reg_mask; | ||
44 | uint8_t en_reg; | ||
45 | uint8_t en_bit; | ||
46 | int min_mV; | ||
47 | int max_mV; | ||
48 | int step_mV; | ||
49 | }; | ||
50 | |||
51 | static const struct axp_adc_info axp_adc_info[NUM_ADC_CHANNELS] = { | ||
52 | {0x56, AXP_REG_ADCENABLE1, 5}, /* ACIN_VOLTAGE */ | ||
53 | {0x58, AXP_REG_ADCENABLE1, 4}, /* ACIN_CURRENT */ | ||
54 | {0x5a, AXP_REG_ADCENABLE1, 3}, /* VBUS_VOLTAGE */ | ||
55 | {0x5c, AXP_REG_ADCENABLE1, 2}, /* VBUS_CURRENT */ | ||
56 | {0x5e, AXP_REG_ADCENABLE2, 7}, /* INTERNAL_TEMP */ | ||
57 | {0x62, AXP_REG_ADCENABLE1, 1}, /* TS_INPUT */ | ||
58 | {0x78, AXP_REG_ADCENABLE1, 7}, /* BATTERY_VOLTAGE */ | ||
59 | {0x7a, AXP_REG_ADCENABLE1, 6}, /* CHARGE_CURRENT */ | ||
60 | {0x7c, AXP_REG_ADCENABLE1, 6}, /* DISCHARGE_CURRENT */ | ||
61 | {0x7e, AXP_REG_ADCENABLE1, 1}, /* APS_VOLTAGE */ | ||
62 | {0x70, 0xff, 0}, /* BATTERY_POWER */ | ||
63 | }; | ||
64 | |||
65 | static const struct axp_supply_info axp_supply_info[AXP_NUM_SUPPLIES] = { | ||
66 | #if HAVE_AXP_PMU == 192 | ||
67 | [AXP_SUPPLY_DCDC1] = { | ||
68 | .volt_reg = 0x26, | ||
69 | .volt_reg_mask = 0x7f, | ||
70 | .en_reg = 0x12, | ||
71 | .en_bit = 0, | ||
72 | .min_mV = 700, | ||
73 | .max_mV = 3500, | ||
74 | .step_mV = 25, | ||
75 | }, | ||
76 | [AXP_SUPPLY_DCDC2] = { | ||
77 | .volt_reg = 0x23, | ||
78 | .volt_reg_mask = 0x3f, | ||
79 | .en_reg = 0x10, | ||
80 | .en_bit = 0, | ||
81 | .min_mV = 700, | ||
82 | .max_mV = 2275, | ||
83 | .step_mV = 25, | ||
84 | }, | ||
85 | [AXP_SUPPLY_DCDC3] = { | ||
86 | .volt_reg = 0x27, | ||
87 | .volt_reg_mask = 0x7f, | ||
88 | .en_reg = 0x12, | ||
89 | .en_bit = 1, | ||
90 | .min_mV = 700, | ||
91 | .max_mV = 3500, | ||
92 | .step_mV = 25, | ||
93 | }, | ||
94 | /* | ||
95 | * NOTE: LDO1 is always on, and we can't query it or change voltages | ||
96 | */ | ||
97 | [AXP_SUPPLY_LDO2] = { | ||
98 | .volt_reg = 0x28, | ||
99 | .volt_reg_mask = 0xf0, | ||
100 | .en_reg = 0x12, | ||
101 | .en_bit = 2, | ||
102 | .min_mV = 1800, | ||
103 | .max_mV = 3300, | ||
104 | .step_mV = 100, | ||
105 | }, | ||
106 | [AXP_SUPPLY_LDO3] = { | ||
107 | .volt_reg = 0x28, | ||
108 | .volt_reg_mask = 0x0f, | ||
109 | .en_reg = 0x12, | ||
110 | .en_bit = 3, | ||
111 | .min_mV = 1800, | ||
112 | .max_mV = 3300, | ||
113 | .step_mV = 100, | ||
114 | }, | ||
115 | [AXP_SUPPLY_LDO_IO0] = { | ||
116 | .volt_reg = 0x91, | ||
117 | .volt_reg_mask = 0xf0, | ||
118 | .en_reg = 0x90, | ||
119 | .en_bit = 0xff, /* this one requires special handling */ | ||
120 | .min_mV = 1800, | ||
121 | .max_mV = 3300, | ||
122 | .step_mV = 100, | ||
123 | }, | ||
124 | #else | ||
125 | # error "Untested AXP chip" | ||
126 | #endif | ||
127 | }; | ||
128 | |||
129 | static struct axp_driver { | ||
130 | int adc_enable; | ||
131 | int chargecurrent_setting; | ||
132 | int chip_id; | ||
133 | } axp; | ||
134 | |||
135 | static void axp_init_enabled_adcs(void) | ||
136 | { | ||
137 | axp.adc_enable = 0; | ||
138 | |||
139 | /* Read chip ID, so we can display it on the debug screen. | ||
140 | * This is undocumented but there's Linux driver code floating around | ||
141 | * which suggests this should work for many AXP chips. */ | ||
142 | axp.chip_id = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP_REG_CHIP_ID); | ||
143 | |||
144 | /* Read enabled ADCs from the hardware */ | ||
145 | uint8_t regs[2]; | ||
146 | int rc = i2c_reg_read(AXP_PMU_BUS, AXP_PMU_ADDR, | ||
147 | AXP_REG_ADCENABLE1, 2, ®s[0]); | ||
148 | if(rc != I2C_STATUS_OK) | ||
149 | return; | ||
150 | |||
151 | /* Parse registers to set ADC enable bits */ | ||
152 | const struct axp_adc_info* info = axp_adc_info; | ||
153 | for(int i = 0; i < NUM_ADC_CHANNELS; ++i) { | ||
154 | if(info[i].en_reg == 0xff) | ||
155 | continue; | ||
156 | |||
157 | if(regs[info[i].en_reg - AXP_REG_ADCENABLE1] & info[i].en_bit) | ||
158 | axp.adc_enable |= 1 << i; | ||
159 | } | ||
160 | |||
161 | /* Handle battery power ADC */ | ||
162 | if((axp.adc_enable & (1 << ADC_BATTERY_VOLTAGE)) && | ||
163 | (axp.adc_enable & (1 << ADC_DISCHARGE_CURRENT))) { | ||
164 | axp.adc_enable |= (1 << ADC_BATTERY_POWER); | ||
165 | } | ||
166 | } | ||
167 | |||
168 | void axp_init(void) | ||
169 | { | ||
170 | axp_init_enabled_adcs(); | ||
171 | |||
172 | /* We need discharge current ADC to reliably poll for a full battery */ | ||
173 | int bits = axp.adc_enable; | ||
174 | bits |= (1 << ADC_DISCHARGE_CURRENT); | ||
175 | axp_adc_set_enabled(bits); | ||
176 | |||
177 | /* Read the maximum charging current */ | ||
178 | int value = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP_REG_CHARGECONTROL1); | ||
179 | axp.chargecurrent_setting = (value < 0) ? -1 : (value & 0xf); | ||
180 | } | ||
181 | |||
182 | void axp_supply_set_voltage(int supply, int voltage) | ||
183 | { | ||
184 | const struct axp_supply_info* info = &axp_supply_info[supply]; | ||
185 | if(info->volt_reg == 0 || info->volt_reg_mask == 0) | ||
186 | return; | ||
187 | |||
188 | if(voltage > 0 && info->step_mV != 0) { | ||
189 | if(voltage < info->min_mV || voltage > info->max_mV) | ||
190 | return; | ||
191 | |||
192 | int regval = (voltage - info->min_mV) / info->step_mV; | ||
193 | i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR, info->volt_reg, | ||
194 | info->volt_reg_mask, regval, NULL); | ||
195 | } | ||
196 | |||
197 | if(info->en_bit != 0xff) { | ||
198 | i2c_reg_setbit1(AXP_PMU_BUS, AXP_PMU_ADDR, | ||
199 | info->en_reg, info->en_bit, | ||
200 | voltage > 0 ? 1 : 0, NULL); | ||
201 | } | ||
202 | } | ||
203 | |||
204 | int axp_supply_get_voltage(int supply) | ||
205 | { | ||
206 | const struct axp_supply_info* info = &axp_supply_info[supply]; | ||
207 | if(info->volt_reg == 0) | ||
208 | return AXP_SUPPLY_NOT_PRESENT; | ||
209 | |||
210 | if(info->en_reg != 0) { | ||
211 | int r = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, info->en_reg); | ||
212 | if(r < 0) | ||
213 | return AXP_SUPPLY_DISABLED; | ||
214 | |||
215 | #if HAVE_AXP_PMU == 192 | ||
216 | if(supply == AXP_SUPPLY_LDO_IO0) { | ||
217 | if((r & 7) != 2) | ||
218 | return AXP_SUPPLY_DISABLED; | ||
219 | } else | ||
220 | #endif | ||
221 | { | ||
222 | if(r & (1 << info->en_bit) == 0) | ||
223 | return AXP_SUPPLY_DISABLED; | ||
224 | } | ||
225 | } | ||
226 | |||
227 | /* Hack, avoid undefined shift below. Can be useful too... */ | ||
228 | if(info->volt_reg_mask == 0) | ||
229 | return info->min_mV; | ||
230 | |||
231 | int r = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, info->volt_reg); | ||
232 | if(r < 0) | ||
233 | return 0; | ||
234 | |||
235 | int bit = find_first_set_bit(info->volt_reg_mask); | ||
236 | int val = (r & info->volt_reg_mask) >> bit; | ||
237 | return info->min_mV + (val * info->step_mV); | ||
238 | } | ||
239 | |||
240 | /* TODO: this can STILL indicate some false positives! */ | ||
241 | int axp_battery_status(void) | ||
242 | { | ||
243 | int r = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP_REG_POWERSTATUS); | ||
244 | if(r >= 0) { | ||
245 | /* Charging bit indicates we're currently charging */ | ||
246 | if((r & 0x04) != 0) | ||
247 | return AXP_BATT_CHARGING; | ||
248 | |||
249 | /* Not plugged in means we're discharging */ | ||
250 | if((r & 0xf0) == 0) | ||
251 | return AXP_BATT_DISCHARGING; | ||
252 | } else { | ||
253 | /* Report discharging if we can't find out power status */ | ||
254 | return AXP_BATT_DISCHARGING; | ||
255 | } | ||
256 | |||
257 | /* If the battery is full and not in use, the charging bit will be 0, | ||
258 | * there will be an external power source, AND the discharge current | ||
259 | * will be zero. Seems to rule out all false positives. */ | ||
260 | int d = axp_adc_read_raw(ADC_DISCHARGE_CURRENT); | ||
261 | if(d == 0) | ||
262 | return AXP_BATT_FULL; | ||
263 | |||
264 | return AXP_BATT_DISCHARGING; | ||
265 | } | ||
266 | |||
267 | int axp_input_status(void) | ||
268 | { | ||
269 | #ifdef HAVE_BATTERY_SWITCH | ||
270 | int input_status = 0; | ||
271 | #else | ||
272 | int input_status = AXP_INPUT_BATTERY; | ||
273 | #endif | ||
274 | |||
275 | int r = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP_REG_POWERSTATUS); | ||
276 | if(r < 0) | ||
277 | return input_status; | ||
278 | |||
279 | /* Check for AC input */ | ||
280 | if(r & 0x80) | ||
281 | input_status |= AXP_INPUT_AC; | ||
282 | |||
283 | /* Only report USB if ACIN and VBUS are not shorted */ | ||
284 | if((r & 0x20) != 0 && (r & 0x02) == 0) | ||
285 | input_status |= AXP_INPUT_USB; | ||
286 | |||
287 | #ifdef HAVE_BATTERY_SWITCH | ||
288 | /* Check for battery presence if target defines it as removable */ | ||
289 | r = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP_REG_CHARGESTATUS); | ||
290 | if(r >= 0 && (r & 0x20) != 0) | ||
291 | input_status |= AXP_INPUT_BATTERY; | ||
292 | #endif | ||
293 | |||
294 | return input_status; | ||
295 | } | ||
296 | |||
297 | int axp_adc_read(int adc) | ||
298 | { | ||
299 | int value = axp_adc_read_raw(adc); | ||
300 | if(value == INT_MIN) | ||
301 | return INT_MIN; | ||
302 | |||
303 | return axp_adc_conv_raw(adc, value); | ||
304 | } | ||
305 | |||
306 | int axp_adc_read_raw(int adc) | ||
307 | { | ||
308 | /* Don't give a reading if the ADC is not enabled */ | ||
309 | if((axp.adc_enable & (1 << adc)) == 0) | ||
310 | return INT_MIN; | ||
311 | |||
312 | /* Read the ADC */ | ||
313 | uint8_t buf[3]; | ||
314 | int count = (adc == ADC_BATTERY_POWER) ? 3 : 2; | ||
315 | uint8_t reg = axp_adc_info[adc].reg; | ||
316 | int rc = i2c_reg_read(AXP_PMU_BUS, AXP_PMU_ADDR, reg, count, &buf[0]); | ||
317 | if(rc != I2C_STATUS_OK) | ||
318 | return INT_MIN; | ||
319 | |||
320 | /* Parse the value */ | ||
321 | if(adc == ADC_BATTERY_POWER) | ||
322 | return (buf[0] << 16) | (buf[1] << 8) | buf[2]; | ||
323 | else if(adc == ADC_CHARGE_CURRENT || adc == ADC_DISCHARGE_CURRENT) | ||
324 | return (buf[0] << 5) | (buf[1] & 0x1f); | ||
325 | else | ||
326 | return (buf[0] << 4) | (buf[1] & 0xf); | ||
327 | } | ||
328 | |||
329 | int axp_adc_conv_raw(int adc, int value) | ||
330 | { | ||
331 | switch(adc) { | ||
332 | case ADC_ACIN_VOLTAGE: | ||
333 | case ADC_VBUS_VOLTAGE: | ||
334 | /* 0 mV ... 6.9615 mV, step 1.7 mV */ | ||
335 | return value * 17 / 10; | ||
336 | case ADC_ACIN_CURRENT: | ||
337 | /* 0 mA ... 2.5594 A, step 0.625 mA */ | ||
338 | return value * 5 / 8; | ||
339 | case ADC_VBUS_CURRENT: | ||
340 | /* 0 mA ... 1.5356 A, step 0.375 mA */ | ||
341 | return value * 3 / 8; | ||
342 | case ADC_INTERNAL_TEMP: | ||
343 | /* -144.7 C ... 264.8 C, step 0.1 C */ | ||
344 | return value - 1447; | ||
345 | case ADC_TS_INPUT: | ||
346 | /* 0 mV ... 3.276 V, step 0.8 mV */ | ||
347 | return value * 4 / 5; | ||
348 | case ADC_BATTERY_VOLTAGE: | ||
349 | /* 0 mV ... 4.5045 V, step 1.1 mV */ | ||
350 | return value * 11 / 10; | ||
351 | case ADC_CHARGE_CURRENT: | ||
352 | case ADC_DISCHARGE_CURRENT: | ||
353 | /* 0 mA to 4.095 A, step 0.5 mA */ | ||
354 | return value / 2; | ||
355 | case ADC_APS_VOLTAGE: | ||
356 | /* 0 mV to 5.733 V, step 1.4 mV */ | ||
357 | return value * 7 / 5; | ||
358 | case ADC_BATTERY_POWER: | ||
359 | /* 0 uW to 23.6404 W, step 0.55 uW */ | ||
360 | return value * 11 / 20; | ||
361 | default: | ||
362 | /* Shouldn't happen */ | ||
363 | return INT_MIN; | ||
364 | } | ||
365 | } | ||
366 | |||
367 | int axp_adc_get_enabled(void) | ||
368 | { | ||
369 | return axp.adc_enable; | ||
370 | } | ||
371 | |||
372 | void axp_adc_set_enabled(int adc_bits) | ||
373 | { | ||
374 | /* Ignore no-op */ | ||
375 | if(adc_bits == axp.adc_enable) | ||
376 | return; | ||
377 | |||
378 | /* Compute the new register values */ | ||
379 | const struct axp_adc_info* info = axp_adc_info; | ||
380 | uint8_t regs[2] = {0, 0}; | ||
381 | for(int i = 0; i < NUM_ADC_CHANNELS; ++i) { | ||
382 | if(info[i].en_reg == 0xff) | ||
383 | continue; | ||
384 | |||
385 | if(adc_bits & (1 << i)) | ||
386 | regs[info[i].en_reg - 0x82] |= 1 << info[i].en_bit; | ||
387 | } | ||
388 | |||
389 | /* These ADCs share an enable bit */ | ||
390 | if(adc_bits & ((1 << ADC_CHARGE_CURRENT)|(1 << ADC_DISCHARGE_CURRENT))) { | ||
391 | adc_bits |= (1 << ADC_CHARGE_CURRENT); | ||
392 | adc_bits |= (1 << ADC_DISCHARGE_CURRENT); | ||
393 | } | ||
394 | |||
395 | /* Enable required bits for battery power ADC */ | ||
396 | if(adc_bits & (1 << ADC_BATTERY_POWER)) { | ||
397 | regs[0] |= 1 << info[ADC_DISCHARGE_CURRENT].en_bit; | ||
398 | regs[0] |= 1 << info[ADC_BATTERY_VOLTAGE].en_bit; | ||
399 | } | ||
400 | |||
401 | /* Update the configuration */ | ||
402 | i2c_reg_write(AXP_PMU_BUS, AXP_PMU_ADDR, AXP_REG_ADCENABLE1, 2, ®s[0]); | ||
403 | axp.adc_enable = adc_bits; | ||
404 | } | ||
405 | |||
406 | int axp_adc_get_rate(void) | ||
407 | { | ||
408 | int r = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP_REG_ADCSAMPLERATE); | ||
409 | if(r < 0) | ||
410 | return AXP_ADC_RATE_100HZ; /* an arbitrary value */ | ||
411 | |||
412 | return (r >> 6) & 3; | ||
413 | } | ||
414 | |||
415 | void axp_adc_set_rate(int rate) | ||
416 | { | ||
417 | i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP_REG_ADCSAMPLERATE, | ||
418 | 0xc0, (rate & 3) << 6, NULL); | ||
419 | } | ||
420 | |||
421 | static uint32_t axp_cc_parse(const uint8_t* buf) | ||
422 | { | ||
423 | return ((uint32_t)buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; | ||
424 | } | ||
425 | |||
426 | void axp_cc_read(uint32_t* charge, uint32_t* discharge) | ||
427 | { | ||
428 | uint8_t buf[8]; | ||
429 | int rc = i2c_reg_read(AXP_PMU_BUS, AXP_PMU_ADDR, | ||
430 | AXP_REG_COULOMBCOUNTERBASE, 8, &buf[0]); | ||
431 | if(rc != I2C_STATUS_OK) { | ||
432 | if(charge) | ||
433 | *charge = 0; | ||
434 | if(discharge) | ||
435 | *discharge = 0; | ||
436 | return; | ||
437 | } | ||
438 | |||
439 | if(charge) | ||
440 | *charge = axp_cc_parse(&buf[0]); | ||
441 | if(discharge) | ||
442 | *discharge = axp_cc_parse(&buf[4]); | ||
443 | } | ||
444 | |||
445 | void axp_cc_clear(void) | ||
446 | { | ||
447 | i2c_reg_setbit1(AXP_PMU_BUS, AXP_PMU_ADDR, | ||
448 | AXP_REG_COULOMBCOUNTERCTRL, 5, 1, NULL); | ||
449 | } | ||
450 | |||
451 | void axp_cc_enable(bool en) | ||
452 | { | ||
453 | i2c_reg_setbit1(AXP_PMU_BUS, AXP_PMU_ADDR, | ||
454 | AXP_REG_COULOMBCOUNTERCTRL, 7, en ? 1 : 0, NULL); | ||
455 | } | ||
456 | |||
457 | bool axp_cc_is_enabled(void) | ||
458 | { | ||
459 | int reg = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, | ||
460 | AXP_REG_COULOMBCOUNTERCTRL); | ||
461 | return reg >= 0 && (reg & 0x40) != 0; | ||
462 | } | ||
463 | |||
464 | static const int chargecurrent_tbl[] = { | ||
465 | 100, 190, 280, 360, | ||
466 | 450, 550, 630, 700, | ||
467 | 780, 880, 960, 1000, | ||
468 | 1080, 1160, 1240, 1320, | ||
469 | }; | ||
470 | |||
471 | static const int chargecurrent_tblsz = sizeof(chargecurrent_tbl)/sizeof(int); | ||
472 | |||
473 | void axp_set_charge_current(int maxcurrent) | ||
474 | { | ||
475 | /* Find the charge current just higher than maxcurrent */ | ||
476 | int value = 0; | ||
477 | while(value < chargecurrent_tblsz && | ||
478 | chargecurrent_tbl[value] <= maxcurrent) | ||
479 | ++value; | ||
480 | |||
481 | /* Select the next lower current, the greatest current <= maxcurrent */ | ||
482 | if(value >= chargecurrent_tblsz) | ||
483 | value = chargecurrent_tblsz - 1; | ||
484 | else if(value > 0) | ||
485 | --value; | ||
486 | |||
487 | /* Don't issue i2c write if desired setting is already in use */ | ||
488 | if(value == axp.chargecurrent_setting) | ||
489 | return; | ||
490 | |||
491 | /* Update register */ | ||
492 | i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR, | ||
493 | AXP_REG_CHARGECONTROL1, 0x0f, value, NULL); | ||
494 | axp.chargecurrent_setting = value; | ||
495 | } | ||
496 | |||
497 | int axp_get_charge_current(void) | ||
498 | { | ||
499 | if(axp.chargecurrent_setting < 0) | ||
500 | return chargecurrent_tbl[0]; | ||
501 | else | ||
502 | return chargecurrent_tbl[axp.chargecurrent_setting]; | ||
503 | } | ||
504 | |||
505 | void axp_power_off(void) | ||
506 | { | ||
507 | /* Set the shutdown bit */ | ||
508 | i2c_reg_setbit1(AXP_PMU_BUS, AXP_PMU_ADDR, | ||
509 | AXP_REG_SHUTDOWNLEDCTRL, 7, 1, NULL); | ||
510 | } | ||
511 | |||
512 | #ifndef BOOTLOADER | ||
513 | enum { | ||
514 | AXP_DEBUG_CHIP_ID, | ||
515 | AXP_DEBUG_BATTERY_STATUS, | ||
516 | AXP_DEBUG_INPUT_STATUS, | ||
517 | AXP_DEBUG_CHARGE_CURRENT, | ||
518 | AXP_DEBUG_COULOMB_COUNTERS, | ||
519 | AXP_DEBUG_ADC_RATE, | ||
520 | AXP_DEBUG_FIRST_ADC, | ||
521 | AXP_DEBUG_FIRST_SUPPLY = AXP_DEBUG_FIRST_ADC + NUM_ADC_CHANNELS, | ||
522 | AXP_DEBUG_NUM_ENTRIES = AXP_DEBUG_FIRST_SUPPLY + AXP_NUM_SUPPLIES, | ||
523 | }; | ||
524 | |||
525 | static int axp_debug_menu_cb(int action, struct gui_synclist* lists) | ||
526 | { | ||
527 | (void)lists; | ||
528 | |||
529 | if(action == ACTION_NONE) | ||
530 | action = ACTION_REDRAW; | ||
531 | |||
532 | return action; | ||
533 | } | ||
534 | |||
535 | static const char* axp_debug_menu_get_name(int item, void* data, | ||
536 | char* buf, size_t buflen) | ||
537 | { | ||
538 | (void)data; | ||
539 | |||
540 | static const char* const adc_names[] = { | ||
541 | "V_acin", "I_acin", "V_vbus", "I_vbus", "T_int", | ||
542 | "V_ts", "V_batt", "I_chrg", "I_dchg", "V_aps", "P_batt" | ||
543 | }; | ||
544 | |||
545 | static const char* const adc_units[] = { | ||
546 | "mV", "mA", "mV", "mA", "C", "mV", "mV", "mA", "mA", "mV", "uW", | ||
547 | }; | ||
548 | |||
549 | static const char* const supply_names[] = { | ||
550 | "DCDC1", "DCDC2", "DCDC3", | ||
551 | "LDO1", "LDO2", "LDO3", "LDO_IO0", | ||
552 | }; | ||
553 | |||
554 | int adc = item - AXP_DEBUG_FIRST_ADC; | ||
555 | if(item >= AXP_DEBUG_FIRST_ADC && adc < NUM_ADC_CHANNELS) { | ||
556 | int raw_value = axp_adc_read_raw(adc); | ||
557 | if(raw_value == INT_MIN) { | ||
558 | snprintf(buf, buflen, "%s: [Disabled]", adc_names[adc]); | ||
559 | return buf; | ||
560 | } | ||
561 | |||
562 | int value = axp_adc_conv_raw(adc, raw_value); | ||
563 | if(adc == ADC_INTERNAL_TEMP) { | ||
564 | snprintf(buf, buflen, "%s: %d.%d %s", adc_names[adc], | ||
565 | value/10, value%10, adc_units[adc]); | ||
566 | } else { | ||
567 | snprintf(buf, buflen, "%s: %d %s", adc_names[adc], | ||
568 | value, adc_units[adc]); | ||
569 | } | ||
570 | |||
571 | return buf; | ||
572 | } | ||
573 | |||
574 | int supply = item - AXP_DEBUG_FIRST_SUPPLY; | ||
575 | if(item >= AXP_DEBUG_FIRST_SUPPLY && supply < AXP_NUM_SUPPLIES) { | ||
576 | int voltage = axp_supply_get_voltage(supply); | ||
577 | if(voltage == AXP_SUPPLY_NOT_PRESENT) | ||
578 | snprintf(buf, buflen, "%s: [Not Present]", supply_names[supply]); | ||
579 | else if(voltage == AXP_SUPPLY_DISABLED) | ||
580 | snprintf(buf, buflen, "%s: [Disabled]", supply_names[supply]); | ||
581 | else | ||
582 | snprintf(buf, buflen, "%s: %d mV", supply_names[supply], voltage); | ||
583 | |||
584 | return buf; | ||
585 | } | ||
586 | |||
587 | switch(item) { | ||
588 | case AXP_DEBUG_CHIP_ID: { | ||
589 | snprintf(buf, buflen, "Chip ID: %d (%02x) [Driver: AXP%d]", | ||
590 | axp.chip_id, axp.chip_id, HAVE_AXP_PMU); | ||
591 | return buf; | ||
592 | } break; | ||
593 | |||
594 | case AXP_DEBUG_BATTERY_STATUS: { | ||
595 | switch(axp_battery_status()) { | ||
596 | case AXP_BATT_FULL: | ||
597 | return "Battery: Full"; | ||
598 | case AXP_BATT_CHARGING: | ||
599 | return "Battery: Charging"; | ||
600 | case AXP_BATT_DISCHARGING: | ||
601 | return "Battery: Discharging"; | ||
602 | default: | ||
603 | return "Battery: Unknown"; | ||
604 | } | ||
605 | } break; | ||
606 | |||
607 | case AXP_DEBUG_INPUT_STATUS: { | ||
608 | int s = axp_input_status(); | ||
609 | const char* ac = (s & AXP_INPUT_AC) ? " AC" : ""; | ||
610 | const char* usb = (s & AXP_INPUT_USB) ? " USB" : ""; | ||
611 | const char* batt = (s & AXP_INPUT_BATTERY) ? " Battery" : ""; | ||
612 | snprintf(buf, buflen, "Inputs:%s%s%s", ac, usb, batt); | ||
613 | return buf; | ||
614 | } break; | ||
615 | |||
616 | case AXP_DEBUG_CHARGE_CURRENT: { | ||
617 | int current = axp_get_charge_current(); | ||
618 | snprintf(buf, buflen, "Max charge current: %d mA", current); | ||
619 | return buf; | ||
620 | } break; | ||
621 | |||
622 | case AXP_DEBUG_COULOMB_COUNTERS: { | ||
623 | uint32_t charge, discharge; | ||
624 | axp_cc_read(&charge, &discharge); | ||
625 | |||
626 | snprintf(buf, buflen, "Coulomb counters: +%lu / -%lu", | ||
627 | (unsigned long)charge, (unsigned long)discharge); | ||
628 | return buf; | ||
629 | } break; | ||
630 | |||
631 | case AXP_DEBUG_ADC_RATE: { | ||
632 | int rate = 25 << axp_adc_get_rate(); | ||
633 | snprintf(buf, buflen, "ADC sample rate: %d Hz", rate); | ||
634 | return buf; | ||
635 | } break; | ||
636 | |||
637 | default: | ||
638 | return "---"; | ||
639 | } | ||
640 | } | ||
641 | |||
642 | bool axp_debug_menu(void) | ||
643 | { | ||
644 | struct simplelist_info info; | ||
645 | simplelist_info_init(&info, "AXP debug", AXP_DEBUG_NUM_ENTRIES, NULL); | ||
646 | info.action_callback = axp_debug_menu_cb; | ||
647 | info.get_name = axp_debug_menu_get_name; | ||
648 | return simplelist_show_list(&info); | ||
649 | } | ||
650 | #endif /* !BOOTLOADER */ | ||
651 | |||
652 | /* This is basically the only valid implementation, so define it here */ | ||
653 | unsigned int power_input_status(void) | ||
654 | { | ||
655 | unsigned int state = 0; | ||
656 | int input_status = axp_input_status(); | ||
657 | |||
658 | if(input_status & AXP_INPUT_AC) | ||
659 | state |= POWER_INPUT_MAIN_CHARGER; | ||
660 | |||
661 | if(input_status & AXP_INPUT_USB) | ||
662 | state |= POWER_INPUT_USB_CHARGER; | ||
663 | |||
664 | #ifdef HAVE_BATTERY_SWITCH | ||
665 | if(input_status & AXP_INPUT_BATTERY) | ||
666 | state |= POWER_INPUT_BATTERY; | ||
667 | #endif | ||
668 | |||
669 | return state; | ||
670 | } | ||
diff --git a/firmware/drivers/axp192.c b/firmware/drivers/axp192.c deleted file mode 100644 index 3c61d8c533..0000000000 --- a/firmware/drivers/axp192.c +++ /dev/null | |||
@@ -1,810 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2021 Aidan MacDonald | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include "axp192.h" | ||
23 | #include "system.h" | ||
24 | #include "power.h" | ||
25 | #include "i2c-async.h" | ||
26 | #include "logf.h" | ||
27 | |||
28 | /* | ||
29 | * Direct register access | ||
30 | */ | ||
31 | |||
32 | int axp_read(uint8_t reg) | ||
33 | { | ||
34 | int ret = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, reg); | ||
35 | if(ret < 0) | ||
36 | logf("axp: read reg %02x err=%d", reg, ret); | ||
37 | |||
38 | return ret; | ||
39 | } | ||
40 | |||
41 | int axp_write(uint8_t reg, uint8_t value) | ||
42 | { | ||
43 | int ret = i2c_reg_write1(AXP_PMU_BUS, AXP_PMU_ADDR, reg, value); | ||
44 | if(ret < 0) | ||
45 | logf("axp: write reg %02x err=%d", reg, ret); | ||
46 | |||
47 | return ret; | ||
48 | } | ||
49 | |||
50 | int axp_modify(uint8_t reg, uint8_t clr, uint8_t set) | ||
51 | { | ||
52 | int ret = i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR, reg, clr, set, NULL); | ||
53 | if(ret < 0) | ||
54 | logf("axp: modify reg %02x err=%d", reg, ret); | ||
55 | |||
56 | return ret; | ||
57 | } | ||
58 | |||
59 | /* | ||
60 | * Power supplies: enable/disable, set voltage | ||
61 | */ | ||
62 | |||
63 | struct axp_supplydata { | ||
64 | uint8_t en_reg; | ||
65 | uint8_t en_bit; | ||
66 | uint8_t volt_reg; | ||
67 | uint8_t volt_msb: 4; | ||
68 | uint8_t volt_lsb: 4; | ||
69 | short min_mV; | ||
70 | short step_mV; | ||
71 | }; | ||
72 | |||
73 | static const struct axp_supplydata supplydata[] = { | ||
74 | [AXP_SUPPLY_EXTEN] = { | ||
75 | .en_reg = AXP_REG_PWRCTL1, | ||
76 | .en_bit = 1 << 2, | ||
77 | .volt_reg = 0xff, /* undefined */ | ||
78 | .volt_msb = 0xf, | ||
79 | .volt_lsb = 0xf, | ||
80 | .min_mV = 0, | ||
81 | .step_mV = 0, | ||
82 | }, | ||
83 | [AXP_SUPPLY_DCDC1] = { | ||
84 | .en_reg = AXP_REG_PWRCTL2, | ||
85 | .en_bit = 1 << 0, | ||
86 | .volt_reg = AXP_REG_DCDC1VOLT, | ||
87 | .volt_msb = 6, | ||
88 | .volt_lsb = 0, | ||
89 | .min_mV = 700, | ||
90 | .step_mV = 25, | ||
91 | }, | ||
92 | [AXP_SUPPLY_DCDC2] = { | ||
93 | .en_reg = AXP_REG_PWRCTL1, | ||
94 | .en_bit = 1 << 0, | ||
95 | .volt_reg = AXP_REG_DCDC2VOLT, | ||
96 | .volt_msb = 5, | ||
97 | .volt_lsb = 0, | ||
98 | .min_mV = 700, | ||
99 | .step_mV = 25, | ||
100 | }, | ||
101 | [AXP_SUPPLY_DCDC3] = { | ||
102 | .en_reg = AXP_REG_PWRCTL2, | ||
103 | .en_bit = 1 << 1, | ||
104 | .volt_reg = AXP_REG_DCDC3VOLT, | ||
105 | .volt_msb = 6, | ||
106 | .volt_lsb = 0, | ||
107 | .min_mV = 700, | ||
108 | .step_mV = 25, | ||
109 | }, | ||
110 | [AXP_SUPPLY_LDO2] = { | ||
111 | .en_reg = AXP_REG_PWRCTL2, | ||
112 | .en_bit = 1 << 2, | ||
113 | .volt_reg = AXP_REG_LDO2LDO3VOLT, | ||
114 | .volt_msb = 7, | ||
115 | .volt_lsb = 4, | ||
116 | .min_mV = 1800, | ||
117 | .step_mV = 100, | ||
118 | }, | ||
119 | [AXP_SUPPLY_LDO3] = { | ||
120 | .en_reg = AXP_REG_PWRCTL2, | ||
121 | .en_bit = 1 << 3, | ||
122 | .volt_reg = AXP_REG_LDO2LDO3VOLT, | ||
123 | .volt_msb = 3, | ||
124 | .volt_lsb = 0, | ||
125 | .min_mV = 1800, | ||
126 | .step_mV = 100, | ||
127 | }, | ||
128 | [AXP_SUPPLY_LDOIO0] = { | ||
129 | .en_reg = 0xff, /* undefined */ | ||
130 | .en_bit = 0, | ||
131 | .volt_reg = AXP_REG_GPIO0LDO, | ||
132 | .volt_msb = 7, | ||
133 | .volt_lsb = 4, | ||
134 | .min_mV = 1800, | ||
135 | .step_mV = 100, | ||
136 | }, | ||
137 | }; | ||
138 | |||
139 | void axp_enable_supply(int supply, bool enable) | ||
140 | { | ||
141 | const struct axp_supplydata* data = &supplydata[supply]; | ||
142 | axp_modify(data->en_reg, data->en_bit, enable ? data->en_bit : 0); | ||
143 | } | ||
144 | |||
145 | void axp_set_enabled_supplies(unsigned int supply_mask) | ||
146 | { | ||
147 | uint8_t xfer[3]; | ||
148 | xfer[0] = 0; | ||
149 | xfer[1] = AXP_REG_PWRCTL2; | ||
150 | xfer[2] = 0; | ||
151 | |||
152 | for(int i = 0; i < AXP_NUM_SUPPLIES; ++i) { | ||
153 | if(!(supply_mask & (1 << i))) | ||
154 | continue; | ||
155 | |||
156 | const struct axp_supplydata* data = &supplydata[i]; | ||
157 | if(data->en_reg == AXP_REG_PWRCTL1) { | ||
158 | xfer[0] |= data->en_bit; | ||
159 | xfer[2] |= data->en_bit << 4; /* HACK: work around AXP quirk */ | ||
160 | } else { | ||
161 | xfer[2] |= data->en_bit; | ||
162 | } | ||
163 | } | ||
164 | |||
165 | i2c_reg_write(AXP_PMU_BUS, AXP_PMU_ADDR, AXP_REG_PWRCTL1, 3, xfer); | ||
166 | } | ||
167 | |||
168 | void axp_set_supply_voltage(int supply, int output_mV) | ||
169 | { | ||
170 | const struct axp_supplydata* data = &supplydata[supply]; | ||
171 | uint8_t mask = (1 << (data->volt_msb - data->volt_lsb + 1)) - 1; | ||
172 | uint8_t value = (output_mV - data->min_mV) / data->step_mV; | ||
173 | axp_modify(data->volt_reg, mask << data->volt_lsb, value << data->volt_lsb); | ||
174 | } | ||
175 | |||
176 | /* | ||
177 | * ADC control: enable/disable, read | ||
178 | */ | ||
179 | |||
180 | struct axp_adcdata { | ||
181 | uint8_t data_reg; | ||
182 | uint8_t en_reg; | ||
183 | uint8_t en_bit; | ||
184 | int8_t num; | ||
185 | int8_t den; | ||
186 | }; | ||
187 | |||
188 | static const struct axp_adcdata adcdata[] = { | ||
189 | [AXP_ADC_ACIN_VOLTAGE] = {0x56, AXP_REG_ADCEN1, 1 << 5, 17, 10}, | ||
190 | [AXP_ADC_ACIN_CURRENT] = {0x58, AXP_REG_ADCEN1, 1 << 4, 5, 8}, | ||
191 | [AXP_ADC_VBUS_VOLTAGE] = {0x5a, AXP_REG_ADCEN1, 1 << 3, 17, 10}, | ||
192 | [AXP_ADC_VBUS_CURRENT] = {0x5c, AXP_REG_ADCEN1, 1 << 2, 3, 8}, | ||
193 | [AXP_ADC_INTERNAL_TEMP] = {0x5e, AXP_REG_ADCEN2, 1 << 7, 0, 0}, | ||
194 | [AXP_ADC_TS_INPUT] = {0x62, AXP_REG_ADCEN1, 1 << 0, 4, 5}, | ||
195 | [AXP_ADC_GPIO0] = {0x64, AXP_REG_ADCEN2, 1 << 3, 1, 2}, | ||
196 | [AXP_ADC_GPIO1] = {0x66, AXP_REG_ADCEN2, 1 << 2, 1, 2}, | ||
197 | [AXP_ADC_GPIO2] = {0x68, AXP_REG_ADCEN2, 1 << 1, 1, 2}, | ||
198 | [AXP_ADC_GPIO3] = {0x6a, AXP_REG_ADCEN2, 1 << 0, 1, 2}, | ||
199 | [AXP_ADC_BATTERY_VOLTAGE] = {0x78, AXP_REG_ADCEN1, 1 << 7, 11, 10}, | ||
200 | [AXP_ADC_CHARGE_CURRENT] = {0x7a, AXP_REG_ADCEN1, 1 << 6, 1, 2}, | ||
201 | [AXP_ADC_DISCHARGE_CURRENT] = {0x7c, AXP_REG_ADCEN1, 1 << 6, 1, 2}, | ||
202 | [AXP_ADC_APS_VOLTAGE] = {0x7e, AXP_REG_ADCEN1, 1 << 1, 7, 5}, | ||
203 | }; | ||
204 | |||
205 | void axp_enable_adc(int adc, bool enable) | ||
206 | { | ||
207 | const struct axp_adcdata* data = &adcdata[adc]; | ||
208 | axp_modify(data->en_reg, data->en_bit, enable ? data->en_bit : 0); | ||
209 | } | ||
210 | |||
211 | void axp_set_enabled_adcs(unsigned int adc_mask) | ||
212 | { | ||
213 | uint8_t xfer[3]; | ||
214 | xfer[0] = 0; | ||
215 | xfer[1] = AXP_REG_ADCEN2; | ||
216 | xfer[2] = 0; | ||
217 | |||
218 | for(int i = 0; i < AXP_NUM_ADCS; ++i) { | ||
219 | if(!(adc_mask & (1 << i))) | ||
220 | continue; | ||
221 | |||
222 | const struct axp_adcdata* data = &adcdata[i]; | ||
223 | if(data->en_reg == AXP_REG_ADCEN1) | ||
224 | xfer[0] |= data->en_bit; | ||
225 | else | ||
226 | xfer[2] |= data->en_bit; | ||
227 | } | ||
228 | |||
229 | i2c_reg_write(AXP_PMU_BUS, AXP_PMU_ADDR, AXP_REG_ADCEN1, 3, xfer); | ||
230 | } | ||
231 | |||
232 | int axp_read_adc_raw(int adc) | ||
233 | { | ||
234 | uint8_t data[2]; | ||
235 | int ret = i2c_reg_read(AXP_PMU_BUS, AXP_PMU_ADDR, | ||
236 | adcdata[adc].data_reg, 2, data); | ||
237 | if(ret < 0) { | ||
238 | logf("axp: ADC read failed, err=%d", ret); | ||
239 | return INT_MIN; | ||
240 | } | ||
241 | |||
242 | if(adc == AXP_ADC_CHARGE_CURRENT || adc == AXP_ADC_DISCHARGE_CURRENT) | ||
243 | return (data[0] << 5) | data[1]; | ||
244 | else | ||
245 | return (data[0] << 4) | data[1]; | ||
246 | } | ||
247 | |||
248 | int axp_conv_adc(int adc, int value) | ||
249 | { | ||
250 | const struct axp_adcdata* data = &adcdata[adc]; | ||
251 | if(adc == AXP_ADC_INTERNAL_TEMP) | ||
252 | return value - 1447; | ||
253 | else | ||
254 | return data->num * value / data->den; | ||
255 | } | ||
256 | |||
257 | int axp_read_adc(int adc) | ||
258 | { | ||
259 | int ret = axp_read_adc_raw(adc); | ||
260 | if(ret == INT_MIN) | ||
261 | return ret; | ||
262 | |||
263 | return axp_conv_adc(adc, ret); | ||
264 | } | ||
265 | |||
266 | /* | ||
267 | * GPIOs: set function, pull down control, get/set pin level | ||
268 | */ | ||
269 | |||
270 | struct axp_gpiodata { | ||
271 | uint8_t func_reg; | ||
272 | uint8_t func_msb: 4; | ||
273 | uint8_t func_lsb: 4; | ||
274 | uint8_t level_reg; | ||
275 | uint8_t level_out: 4; | ||
276 | uint8_t level_in: 4; | ||
277 | }; | ||
278 | |||
279 | static const struct axp_gpiodata gpiodata[] = { | ||
280 | {AXP_REG_GPIO0FUNC, 2, 0, AXP_REG_GPIOLEVEL1, 0, 4}, | ||
281 | {AXP_REG_GPIO1FUNC, 2, 0, AXP_REG_GPIOLEVEL1, 1, 5}, | ||
282 | {AXP_REG_GPIO2FUNC, 2, 0, AXP_REG_GPIOLEVEL1, 2, 6}, | ||
283 | {AXP_REG_GPIO3GPIO4FUNC, 1, 0, AXP_REG_GPIOLEVEL2, 0, 4}, | ||
284 | {AXP_REG_GPIO3GPIO4FUNC, 3, 2, AXP_REG_GPIOLEVEL2, 1, 5}, | ||
285 | {AXP_REG_NRSTO, 7, 6, AXP_REG_NRSTO, 4, 5}, | ||
286 | }; | ||
287 | |||
288 | static const uint8_t gpio34funcmap[8] = { | ||
289 | [AXP_GPIO_SPECIAL] = 0x0, | ||
290 | [AXP_GPIO_OPEN_DRAIN_OUTPUT] = 0x1, | ||
291 | [AXP_GPIO_INPUT] = 0x2, | ||
292 | [AXP_GPIO_ADC_IN] = 0x3, | ||
293 | }; | ||
294 | |||
295 | static const uint8_t nrstofuncmap[8] = { | ||
296 | [AXP_GPIO_SPECIAL] = 0x0, | ||
297 | [AXP_GPIO_OPEN_DRAIN_OUTPUT] = 0x2, | ||
298 | [AXP_GPIO_INPUT] = 0x3, | ||
299 | }; | ||
300 | |||
301 | void axp_set_gpio_function(int gpio, int function) | ||
302 | { | ||
303 | const struct axp_gpiodata* data = &gpiodata[gpio]; | ||
304 | int mask = (1 << (data->func_msb - data->func_lsb + 1)) - 1; | ||
305 | |||
306 | if(gpio == 5) | ||
307 | function = nrstofuncmap[function]; | ||
308 | else if(gpio >= 3) | ||
309 | function = gpio34funcmap[function]; | ||
310 | |||
311 | axp_modify(data->func_reg, mask << data->func_lsb, function << data->func_lsb); | ||
312 | } | ||
313 | |||
314 | void axp_set_gpio_pulldown(int gpio, bool enable) | ||
315 | { | ||
316 | int bit = 1 << gpio; | ||
317 | axp_modify(AXP_REG_GPIOPULL, bit, enable ? bit : 0); | ||
318 | } | ||
319 | |||
320 | int axp_get_gpio(int gpio) | ||
321 | { | ||
322 | const struct axp_gpiodata* data = &gpiodata[gpio]; | ||
323 | return axp_read(data->level_reg) & (1 << data->level_in); | ||
324 | } | ||
325 | |||
326 | void axp_set_gpio(int gpio, bool enable) | ||
327 | { | ||
328 | const struct axp_gpiodata* data = &gpiodata[gpio]; | ||
329 | uint8_t bit = 1 << data->level_out; | ||
330 | axp_modify(data->level_reg, bit, enable ? bit : 0); | ||
331 | } | ||
332 | |||
333 | /* | ||
334 | * Charging: set charging current, query charging/input status | ||
335 | */ | ||
336 | |||
337 | static const short chargecurrent_tbl[] = { | ||
338 | 100, 190, 280, 360, | ||
339 | 450, 550, 630, 700, | ||
340 | 780, 880, 960, 1000, | ||
341 | 1080, 1160, 1240, 1320, | ||
342 | }; | ||
343 | |||
344 | void axp_set_charge_current(int current_mA) | ||
345 | { | ||
346 | /* find greatest charging current not exceeding requested current */ | ||
347 | unsigned int index = 0; | ||
348 | while(index < ARRAYLEN(chargecurrent_tbl)-1 && | ||
349 | chargecurrent_tbl[index+1] <= current_mA) | ||
350 | ++index; | ||
351 | |||
352 | axp_modify(AXP_REG_CHGCTL1, BM_AXP_CHGCTL1_CHARGE_CURRENT, | ||
353 | index << BP_AXP_CHGCTL1_CHARGE_CURRENT); | ||
354 | } | ||
355 | |||
356 | int axp_get_charge_current(void) | ||
357 | { | ||
358 | int value = axp_read(AXP_REG_CHGCTL1); | ||
359 | if(value < 0) | ||
360 | value = 0; | ||
361 | |||
362 | value &= BM_AXP_CHGCTL1_CHARGE_CURRENT; | ||
363 | value >>= BP_AXP_CHGCTL1_CHARGE_CURRENT; | ||
364 | return chargecurrent_tbl[value]; | ||
365 | } | ||
366 | |||
367 | void axp_set_vbus_limit(int mode) | ||
368 | { | ||
369 | const int mask = BM_AXP_VBUSIPSOUT_VHOLD_LIM | | ||
370 | BM_AXP_VBUSIPSOUT_VBUS_LIM | | ||
371 | BM_AXP_VBUSIPSOUT_LIM_100mA; | ||
372 | |||
373 | axp_modify(AXP_REG_VBUSIPSOUT, mask, mode); | ||
374 | } | ||
375 | |||
376 | void axp_set_vhold_level(int vhold_mV) | ||
377 | { | ||
378 | if(vhold_mV < 4000) | ||
379 | vhold_mV = 4000; | ||
380 | else if(vhold_mV > 4700) | ||
381 | vhold_mV = 4700; | ||
382 | |||
383 | int level = (vhold_mV - 4000) / 100; | ||
384 | axp_modify(AXP_REG_VBUSIPSOUT, BM_AXP_VBUSIPSOUT_VHOLD_LEV, | ||
385 | level << BP_AXP_VBUSIPSOUT_VHOLD_LEV); | ||
386 | } | ||
387 | |||
388 | bool axp_is_charging(void) | ||
389 | { | ||
390 | int value = axp_read(AXP_REG_CHGSTS); | ||
391 | return (value >= 0) && (value & BM_AXP_CHGSTS_CHARGING); | ||
392 | } | ||
393 | |||
394 | unsigned int axp_power_input_status(void) | ||
395 | { | ||
396 | unsigned int state = 0; | ||
397 | int value = axp_read(AXP_REG_PWRSTS); | ||
398 | if(value >= 0) { | ||
399 | /* ACIN is the main charger. Includes USB */ | ||
400 | if(value & BM_AXP_PWRSTS_ACIN_VALID) | ||
401 | state |= POWER_INPUT_MAIN_CHARGER; | ||
402 | |||
403 | /* Report USB separately if discernable from ACIN */ | ||
404 | if((value & BM_AXP_PWRSTS_VBUS_VALID) && | ||
405 | !(value & BM_AXP_PWRSTS_PCB_SHORTED)) | ||
406 | state |= POWER_INPUT_USB_CHARGER; | ||
407 | } | ||
408 | |||
409 | #ifdef HAVE_BATTERY_SWITCH | ||
410 | /* If target allows switching batteries then report if the | ||
411 | * battery is present or not */ | ||
412 | value = axp_read(AXP_REG_CHGSTS); | ||
413 | if(value >= 0 && (value & BM_AXP_CHGSTS_BATT_PRESENT)) | ||
414 | state |= POWER_INPUT_BATTERY; | ||
415 | #endif | ||
416 | |||
417 | return state; | ||
418 | } | ||
419 | |||
420 | /* | ||
421 | * Misc. functions | ||
422 | */ | ||
423 | |||
424 | void axp_power_off(void) | ||
425 | { | ||
426 | axp_modify(AXP_REG_PWROFF, BM_AXP_PWROFF_SHUTDOWN, BM_AXP_PWROFF_SHUTDOWN); | ||
427 | } | ||
428 | |||
429 | /* | ||
430 | * Debug menu | ||
431 | */ | ||
432 | |||
433 | #ifndef BOOTLOADER | ||
434 | #include "action.h" | ||
435 | #include "list.h" | ||
436 | #include "splash.h" | ||
437 | #include <stdio.h> | ||
438 | |||
439 | /* enable extra debug menus which are only useful for development, | ||
440 | * allow potentially dangerous operations and increase code size | ||
441 | * significantly */ | ||
442 | /*#define AXP_EXTRA_DEBUG*/ | ||
443 | |||
444 | enum { | ||
445 | MODE_ADC, | ||
446 | #ifdef AXP_EXTRA_DEBUG | ||
447 | MODE_SUPPLY, | ||
448 | MODE_REGISTER, | ||
449 | #endif | ||
450 | NUM_MODES, | ||
451 | }; | ||
452 | |||
453 | static const char* const axp_modenames[NUM_MODES] = { | ||
454 | [MODE_ADC] = "ADCs", | ||
455 | #ifdef AXP_EXTRA_DEBUG | ||
456 | [MODE_SUPPLY] = "Power supplies", | ||
457 | [MODE_REGISTER] = "Register viewer", | ||
458 | #endif | ||
459 | }; | ||
460 | |||
461 | struct axp_adcdebuginfo { | ||
462 | const char* name; | ||
463 | const char* unit; | ||
464 | }; | ||
465 | |||
466 | static const struct axp_adcdebuginfo adc_debuginfo[AXP_NUM_ADCS] = { | ||
467 | [AXP_ADC_ACIN_VOLTAGE] = {"V_acin", "mV"}, | ||
468 | [AXP_ADC_ACIN_CURRENT] = {"I_acin", "mA"}, | ||
469 | [AXP_ADC_VBUS_VOLTAGE] = {"V_vbus", "mV"}, | ||
470 | [AXP_ADC_VBUS_CURRENT] = {"I_vbus", "mA"}, | ||
471 | [AXP_ADC_INTERNAL_TEMP] = {"T_int", "C"}, | ||
472 | [AXP_ADC_TS_INPUT] = {"V_ts", "mV"}, | ||
473 | [AXP_ADC_GPIO0] = {"V_gpio0", "mV"}, | ||
474 | [AXP_ADC_GPIO1] = {"V_gpio1", "mV"}, | ||
475 | [AXP_ADC_GPIO2] = {"V_gpio2", "mV"}, | ||
476 | [AXP_ADC_GPIO3] = {"V_gpio3", "mV"}, | ||
477 | [AXP_ADC_BATTERY_VOLTAGE] = {"V_batt", "mV"}, | ||
478 | [AXP_ADC_CHARGE_CURRENT] = {"I_chrg", "mA"}, | ||
479 | [AXP_ADC_DISCHARGE_CURRENT] = {"I_dchg", "mA"}, | ||
480 | [AXP_ADC_APS_VOLTAGE] = {"V_aps", "mV"}, | ||
481 | }; | ||
482 | |||
483 | #ifdef AXP_EXTRA_DEBUG | ||
484 | static const char* supply_names[AXP_NUM_SUPPLIES] = { | ||
485 | [AXP_SUPPLY_EXTEN] = "EXTEN", | ||
486 | [AXP_SUPPLY_DCDC1] = "DCDC1", | ||
487 | [AXP_SUPPLY_DCDC2] = "DCDC2", | ||
488 | [AXP_SUPPLY_DCDC3] = "DCDC3", | ||
489 | [AXP_SUPPLY_LDO2] = "LDO2", | ||
490 | [AXP_SUPPLY_LDO3] = "LDO3", | ||
491 | [AXP_SUPPLY_LDOIO0] = "LDOIO0", | ||
492 | }; | ||
493 | |||
494 | struct axp_fieldinfo { | ||
495 | uint8_t rnum; | ||
496 | uint8_t msb: 4; | ||
497 | uint8_t lsb: 4; | ||
498 | }; | ||
499 | |||
500 | enum { | ||
501 | #define DEFREG(name, ...) AXP_RNUM_##name, | ||
502 | #include "axp192-defs.h" | ||
503 | AXP_NUM_REGS, | ||
504 | }; | ||
505 | |||
506 | enum { | ||
507 | #define DEFFLD(regname, fldname, ...) AXP_FNUM_##regname##_##fldname, | ||
508 | #include "axp192-defs.h" | ||
509 | AXP_NUM_FIELDS, | ||
510 | }; | ||
511 | |||
512 | static const uint8_t axp_regaddr[AXP_NUM_REGS] = { | ||
513 | #define DEFREG(name, addr) addr, | ||
514 | #include "axp192-defs.h" | ||
515 | }; | ||
516 | |||
517 | static const struct axp_fieldinfo axp_fieldinfo[AXP_NUM_FIELDS] = { | ||
518 | #define DEFFLD(regname, fldname, _msb, _lsb, ...) \ | ||
519 | {.rnum = AXP_RNUM_##regname, .msb = _msb, .lsb = _lsb}, | ||
520 | #include "axp192-defs.h" | ||
521 | }; | ||
522 | |||
523 | static const char* const axp_regnames[AXP_NUM_REGS] = { | ||
524 | #define DEFREG(name, ...) #name, | ||
525 | #include "axp192-defs.h" | ||
526 | }; | ||
527 | |||
528 | static const char* const axp_fldnames[AXP_NUM_FIELDS] = { | ||
529 | #define DEFFLD(regname, fldname, ...) #fldname, | ||
530 | #include "axp192-defs.h" | ||
531 | }; | ||
532 | #endif /* AXP_EXTRA_DEBUG */ | ||
533 | |||
534 | struct axp_debug_menu_state { | ||
535 | int mode; | ||
536 | #ifdef AXP_EXTRA_DEBUG | ||
537 | int reg_num; | ||
538 | int field_num; | ||
539 | int field_cnt; | ||
540 | uint8_t cache[AXP_NUM_REGS]; | ||
541 | uint8_t is_cached[AXP_NUM_REGS]; | ||
542 | #endif | ||
543 | }; | ||
544 | |||
545 | #ifdef AXP_EXTRA_DEBUG | ||
546 | static void axp_debug_clear_cache(struct axp_debug_menu_state* state) | ||
547 | { | ||
548 | memset(state->is_cached, 0, sizeof(state->is_cached)); | ||
549 | } | ||
550 | |||
551 | static int axp_debug_get_rnum(uint8_t addr) | ||
552 | { | ||
553 | for(int i = 0; i < AXP_NUM_REGS; ++i) | ||
554 | if(axp_regaddr[i] == addr) | ||
555 | return i; | ||
556 | |||
557 | return -1; | ||
558 | } | ||
559 | |||
560 | static uint8_t axp_debug_read(struct axp_debug_menu_state* state, int rnum) | ||
561 | { | ||
562 | if(state->is_cached[rnum]) | ||
563 | return state->cache[rnum]; | ||
564 | |||
565 | int value = axp_read(axp_regaddr[rnum]); | ||
566 | if(value < 0) | ||
567 | return 0; | ||
568 | |||
569 | state->is_cached[rnum] = 1; | ||
570 | state->cache[rnum] = value; | ||
571 | return value; | ||
572 | } | ||
573 | |||
574 | static void axp_debug_get_sel(const struct axp_debug_menu_state* state, | ||
575 | int item, int* rnum, int* fnum) | ||
576 | { | ||
577 | if(state->reg_num >= 0 && state->field_num >= 0) { | ||
578 | int i = item - state->reg_num; | ||
579 | if(i <= 0) { | ||
580 | /* preceding register is selected */ | ||
581 | } else if(i <= state->field_cnt) { | ||
582 | /* field is selected */ | ||
583 | *rnum = state->reg_num; | ||
584 | *fnum = i + state->field_num - 1; | ||
585 | return; | ||
586 | } else { | ||
587 | /* subsequent regiser is selected */ | ||
588 | item -= state->field_cnt; | ||
589 | } | ||
590 | } | ||
591 | |||
592 | /* register is selected */ | ||
593 | *rnum = item; | ||
594 | *fnum = -1; | ||
595 | } | ||
596 | |||
597 | static int axp_debug_set_sel(struct axp_debug_menu_state* state, int rnum) | ||
598 | { | ||
599 | state->reg_num = rnum; | ||
600 | state->field_num = -1; | ||
601 | state->field_cnt = 0; | ||
602 | |||
603 | for(int i = 0; i < AXP_NUM_FIELDS; ++i) { | ||
604 | if(axp_fieldinfo[i].rnum != rnum) | ||
605 | continue; | ||
606 | |||
607 | state->field_num = i; | ||
608 | do { | ||
609 | state->field_cnt++; | ||
610 | i++; | ||
611 | } while(axp_fieldinfo[i].rnum == rnum); | ||
612 | break; | ||
613 | } | ||
614 | |||
615 | return rnum; | ||
616 | } | ||
617 | #endif /* AXP_EXTRA_DEBUG */ | ||
618 | |||
619 | static const char* axp_debug_menu_get_name(int item, void* data, | ||
620 | char* buf, size_t buflen) | ||
621 | { | ||
622 | struct axp_debug_menu_state* state = data; | ||
623 | int value; | ||
624 | |||
625 | /* for safety */ | ||
626 | buf[0] = '\0'; | ||
627 | |||
628 | if(state->mode == MODE_ADC && item < AXP_NUM_ADCS) | ||
629 | { | ||
630 | const struct axp_adcdebuginfo* info = &adc_debuginfo[item]; | ||
631 | value = axp_read_adc(item); | ||
632 | if(item == AXP_ADC_INTERNAL_TEMP) { | ||
633 | snprintf(buf, buflen, "%s: %d.%d %s", | ||
634 | info->name, value/10, value%10, info->unit); | ||
635 | } else { | ||
636 | snprintf(buf, buflen, "%s: %d %s", info->name, value, info->unit); | ||
637 | } | ||
638 | } | ||
639 | #ifdef AXP_EXTRA_DEBUG | ||
640 | else if(state->mode == MODE_SUPPLY && item < AXP_NUM_SUPPLIES) | ||
641 | { | ||
642 | const struct axp_supplydata* data = &supplydata[item]; | ||
643 | int en_rnum = axp_debug_get_rnum(data->en_reg); | ||
644 | int volt_rnum = axp_debug_get_rnum(data->volt_reg); | ||
645 | bool enabled = false; | ||
646 | int voltage = -1; | ||
647 | |||
648 | if(en_rnum >= 0) { | ||
649 | value = axp_debug_read(state, en_rnum); | ||
650 | if(value & data->en_bit) | ||
651 | enabled = true; | ||
652 | else | ||
653 | enabled = false; | ||
654 | } else if(item == AXP_SUPPLY_LDOIO0) { | ||
655 | value = axp_debug_read(state, AXP_RNUM_GPIO0FUNC); | ||
656 | if((value & 0x7) == AXP_GPIO_SPECIAL) | ||
657 | enabled = true; | ||
658 | else | ||
659 | enabled = false; | ||
660 | } | ||
661 | |||
662 | if(volt_rnum >= 0) { | ||
663 | voltage = axp_debug_read(state, volt_rnum); | ||
664 | voltage >>= data->volt_lsb; | ||
665 | voltage &= (1 << (data->volt_msb - data->volt_lsb + 1)) - 1; | ||
666 | |||
667 | /* convert to mV */ | ||
668 | voltage = data->min_mV + voltage * data->step_mV; | ||
669 | } | ||
670 | |||
671 | if(enabled && voltage >= 0) { | ||
672 | snprintf(buf, buflen, "%s: %d mV", | ||
673 | supply_names[item], voltage); | ||
674 | } else { | ||
675 | snprintf(buf, buflen, "%s: %sabled", | ||
676 | supply_names[item], enabled ? "en" : "dis"); | ||
677 | } | ||
678 | } | ||
679 | else if(state->mode == MODE_REGISTER) | ||
680 | { | ||
681 | int rnum, fnum; | ||
682 | axp_debug_get_sel(state, item, &rnum, &fnum); | ||
683 | |||
684 | if(fnum >= 0) { | ||
685 | const struct axp_fieldinfo* info = &axp_fieldinfo[fnum]; | ||
686 | value = axp_debug_read(state, info->rnum); | ||
687 | value >>= info->lsb; | ||
688 | value &= (1 << (info->msb - info->lsb + 1)) - 1; | ||
689 | snprintf(buf, buflen, "\t%s: %d (0x%x)", | ||
690 | axp_fldnames[fnum], value, value); | ||
691 | } else if(rnum < AXP_NUM_REGS) { | ||
692 | value = axp_debug_read(state, rnum); | ||
693 | snprintf(buf, buflen, "%s: 0x%02x", axp_regnames[rnum], value); | ||
694 | } | ||
695 | } | ||
696 | #endif /* AXP_EXTRA_DEBUG */ | ||
697 | |||
698 | return buf; | ||
699 | } | ||
700 | |||
701 | static int axp_debug_menu_cb(int action, struct gui_synclist* lists) | ||
702 | { | ||
703 | struct axp_debug_menu_state* state = lists->data; | ||
704 | |||
705 | if(state->mode == MODE_ADC) | ||
706 | { | ||
707 | /* update continuously */ | ||
708 | if(action == ACTION_NONE) | ||
709 | action = ACTION_REDRAW; | ||
710 | } | ||
711 | #ifdef AXP_EXTRA_DEBUG | ||
712 | else if(state->mode == MODE_REGISTER) | ||
713 | { | ||
714 | if(action == ACTION_STD_OK) { | ||
715 | /* expand a register to show its fields */ | ||
716 | int rnum, fnum; | ||
717 | int sel_pos = gui_synclist_get_sel_pos(lists); | ||
718 | axp_debug_get_sel(state, sel_pos, &rnum, &fnum); | ||
719 | if(fnum < 0 && rnum < AXP_NUM_REGS) { | ||
720 | int delta_items = -state->field_cnt; | ||
721 | if(rnum != state->reg_num) { | ||
722 | if(rnum > state->reg_num) | ||
723 | sel_pos += delta_items; | ||
724 | |||
725 | axp_debug_set_sel(state, rnum); | ||
726 | delta_items += state->field_cnt; | ||
727 | } else { | ||
728 | state->reg_num = -1; | ||
729 | state->field_num = -1; | ||
730 | state->field_cnt = 0; | ||
731 | } | ||
732 | |||
733 | gui_synclist_set_nb_items(lists, lists->nb_items + delta_items); | ||
734 | gui_synclist_select_item(lists, sel_pos); | ||
735 | action = ACTION_REDRAW; | ||
736 | } | ||
737 | } | ||
738 | } | ||
739 | else if(state->mode == MODE_SUPPLY) | ||
740 | { | ||
741 | /* disable a supply... use with caution */ | ||
742 | if(action == ACTION_STD_CONTEXT) { | ||
743 | int sel_pos = gui_synclist_get_sel_pos(lists); | ||
744 | axp_enable_supply(sel_pos, false); | ||
745 | } | ||
746 | } | ||
747 | #endif | ||
748 | |||
749 | #ifdef AXP_EXTRA_DEBUG | ||
750 | /* clear register cache to refresh values */ | ||
751 | if(state->mode != MODE_ADC && action == ACTION_STD_CONTEXT) { | ||
752 | splashf(HZ/2, "Refreshed"); | ||
753 | axp_debug_clear_cache(state); | ||
754 | action = ACTION_REDRAW; | ||
755 | } | ||
756 | #endif | ||
757 | |||
758 | /* mode switching */ | ||
759 | if(action == ACTION_STD_MENU) { | ||
760 | state->mode = (state->mode + 1) % NUM_MODES; | ||
761 | gui_synclist_set_title(lists, (char*)axp_modenames[state->mode], Icon_NOICON); | ||
762 | action = ACTION_REDRAW; | ||
763 | |||
764 | switch(state->mode) { | ||
765 | case MODE_ADC: | ||
766 | gui_synclist_set_nb_items(lists, AXP_NUM_ADCS); | ||
767 | gui_synclist_select_item(lists, 0); | ||
768 | break; | ||
769 | |||
770 | #ifdef AXP_EXTRA_DEBUG | ||
771 | case MODE_SUPPLY: | ||
772 | axp_debug_clear_cache(state); | ||
773 | gui_synclist_set_nb_items(lists, AXP_NUM_SUPPLIES); | ||
774 | gui_synclist_select_item(lists, 0); | ||
775 | break; | ||
776 | |||
777 | case MODE_REGISTER: | ||
778 | state->reg_num = -1; | ||
779 | state->field_num = -1; | ||
780 | state->field_cnt = 0; | ||
781 | axp_debug_clear_cache(state); | ||
782 | gui_synclist_set_nb_items(lists, AXP_NUM_REGS); | ||
783 | gui_synclist_select_item(lists, 0); | ||
784 | break; | ||
785 | #endif | ||
786 | } | ||
787 | } | ||
788 | |||
789 | return action; | ||
790 | } | ||
791 | |||
792 | bool axp_debug_menu(void) | ||
793 | { | ||
794 | struct axp_debug_menu_state state; | ||
795 | state.mode = MODE_ADC; | ||
796 | #ifdef AXP_EXTRA_DEBUG | ||
797 | state.reg_num = -1; | ||
798 | state.field_num = -1; | ||
799 | state.field_cnt = 0; | ||
800 | axp_debug_clear_cache(&state); | ||
801 | #endif | ||
802 | |||
803 | struct simplelist_info info; | ||
804 | simplelist_info_init(&info, (char*)axp_modenames[state.mode], | ||
805 | AXP_NUM_ADCS, &state); | ||
806 | info.get_name = axp_debug_menu_get_name; | ||
807 | info.action_callback = axp_debug_menu_cb; | ||
808 | return simplelist_show_list(&info); | ||
809 | } | ||
810 | #endif | ||
diff --git a/firmware/export/axp-pmu.h b/firmware/export/axp-pmu.h new file mode 100644 index 0000000000..457f746e8c --- /dev/null +++ b/firmware/export/axp-pmu.h | |||
@@ -0,0 +1,151 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2021 Aidan MacDonald | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #ifndef __AXP_PMU_H__ | ||
23 | #define __AXP_PMU_H__ | ||
24 | |||
25 | #include "config.h" | ||
26 | #include <stdbool.h> | ||
27 | #include <stdint.h> | ||
28 | |||
29 | /* ADC channels */ | ||
30 | #define ADC_ACIN_VOLTAGE 0 | ||
31 | #define ADC_ACIN_CURRENT 1 | ||
32 | #define ADC_VBUS_VOLTAGE 2 | ||
33 | #define ADC_VBUS_CURRENT 3 | ||
34 | #define ADC_INTERNAL_TEMP 4 | ||
35 | #define ADC_TS_INPUT 5 | ||
36 | #define ADC_BATTERY_VOLTAGE 6 | ||
37 | #define ADC_CHARGE_CURRENT 7 | ||
38 | #define ADC_DISCHARGE_CURRENT 8 | ||
39 | #define ADC_APS_VOLTAGE 9 | ||
40 | #define ADC_BATTERY_POWER 10 | ||
41 | #define NUM_ADC_CHANNELS 11 | ||
42 | |||
43 | /* ADC sampling rates */ | ||
44 | #define AXP_ADC_RATE_25HZ 0 | ||
45 | #define AXP_ADC_RATE_50HZ 1 | ||
46 | #define AXP_ADC_RATE_100HZ 2 | ||
47 | #define AXP_ADC_RATE_200HZ 3 | ||
48 | |||
49 | /* Return values of axp_battery_status() */ | ||
50 | #define AXP_BATT_DISCHARGING 0 | ||
51 | #define AXP_BATT_CHARGING 1 | ||
52 | #define AXP_BATT_FULL 2 | ||
53 | |||
54 | /* Bits returned by axp_input_status() */ | ||
55 | #define AXP_INPUT_AC (1 << 0) | ||
56 | #define AXP_INPUT_USB (1 << 1) | ||
57 | #define AXP_INPUT_BATTERY (1 << 2) | ||
58 | #define AXP_INPUT_EXTERNAL (AXP_INPUT_AC|AXP_INPUT_USB) | ||
59 | |||
60 | /* Power supplies known by this driver. Not every chip has all supplies! */ | ||
61 | #define AXP_SUPPLY_DCDC1 0 | ||
62 | #define AXP_SUPPLY_DCDC2 1 | ||
63 | #define AXP_SUPPLY_DCDC3 2 | ||
64 | #define AXP_SUPPLY_LDO1 3 | ||
65 | #define AXP_SUPPLY_LDO2 4 | ||
66 | #define AXP_SUPPLY_LDO3 5 | ||
67 | #define AXP_SUPPLY_LDO_IO0 6 | ||
68 | #define AXP_NUM_SUPPLIES 7 | ||
69 | |||
70 | /* Special values returned by axp_supply_get_voltage */ | ||
71 | #define AXP_SUPPLY_NOT_PRESENT INT_MIN | ||
72 | #define AXP_SUPPLY_DISABLED (-1) | ||
73 | |||
74 | /* Registers -- common to AXP173 and AXP192 (incomplete listing) */ | ||
75 | #define AXP_REG_POWERSTATUS 0x00 | ||
76 | #define AXP_REG_CHARGESTATUS 0x01 | ||
77 | #define AXP_REG_CHIP_ID 0x03 | ||
78 | #define AXP_REG_PWROUTPUTCTRL1 0x10 | ||
79 | #define AXP_REG_PWROUTPUTCTRL2 0x12 | ||
80 | #define AXP_REG_SHUTDOWNLEDCTRL 0x32 | ||
81 | #define AXP_REG_CHARGECONTROL1 0x33 | ||
82 | #define AXP_REG_DCDCWORKINGMODE 0x80 | ||
83 | #define AXP_REG_ADCENABLE1 0x82 | ||
84 | #define AXP_REG_ADCENABLE2 0x83 | ||
85 | #define AXP_REG_ADCSAMPLERATE 0x84 | ||
86 | #define AXP_REG_COULOMBCOUNTERBASE 0xb0 | ||
87 | #define AXP_REG_COULOMBCOUNTERCTRL 0xb8 | ||
88 | |||
89 | /* AXP192-only registers (incomplete listing) */ | ||
90 | #define AXP192_REG_GPIO0FUNCTION 0x90 | ||
91 | #define AXP192_REG_GPIO1FUNCTION 0x92 | ||
92 | #define AXP192_REG_GPIO2FUNCTION 0x93 | ||
93 | #define AXP192_REG_GPIOSTATE1 0x94 | ||
94 | |||
95 | /* Must be called from power_init() to initialize the driver state */ | ||
96 | extern void axp_init(void); | ||
97 | |||
98 | /* - axp_supply_set_voltage(): set a supply voltage to the given value | ||
99 | * in millivolts. Pass a voltage of AXP_SUPPLY_DISABLED to shut off | ||
100 | * the supply. Any invalid supply or voltage will make the call a no-op. | ||
101 | * | ||
102 | * - axp_supply_get_voltage() returns a supply voltage in millivolts. | ||
103 | * If the supply is powered off, returns AXP_SUPPLY_DISABLED. | ||
104 | * If the chip does not have the supply, returns AXP_SUPPLY_NOT_PRESENT. | ||
105 | */ | ||
106 | extern void axp_supply_set_voltage(int supply, int voltage); | ||
107 | extern int axp_supply_get_voltage(int supply); | ||
108 | |||
109 | /* Basic battery and power supply status */ | ||
110 | extern int axp_battery_status(void); | ||
111 | extern int axp_input_status(void); | ||
112 | |||
113 | /* ADC access -- ADCs which are not enabled will return INT_MIN if read. | ||
114 | * The output of axp_adc_read() is normalized to appropriate units: | ||
115 | * | ||
116 | * - for voltages, the scale is millivolts | ||
117 | * - for currents, the scale is milliamps | ||
118 | * - for temperatures, the scale is tenths of a degree Celsius | ||
119 | * - for power, the scale is microwatts | ||
120 | * | ||
121 | * See the comment in axp_adc_conv_raw() for raw value precision/scale. | ||
122 | */ | ||
123 | extern int axp_adc_read(int adc); | ||
124 | extern int axp_adc_read_raw(int adc); | ||
125 | extern int axp_adc_conv_raw(int adc, int value); | ||
126 | extern int axp_adc_get_enabled(void); | ||
127 | extern void axp_adc_set_enabled(int adc_bits); | ||
128 | extern int axp_adc_get_rate(void); | ||
129 | extern void axp_adc_set_rate(int rate); | ||
130 | |||
131 | /* - axp_cc_read() reads the coulomb counters | ||
132 | * - axp_cc_clear() resets both counters to zero | ||
133 | * - axp_cc_enable() will stop/start the counters running | ||
134 | * - axp_cc_is_enabled() returns true if the counters are running | ||
135 | */ | ||
136 | extern void axp_cc_read(uint32_t* charge, uint32_t* discharge); | ||
137 | extern void axp_cc_clear(void); | ||
138 | extern void axp_cc_enable(bool en); | ||
139 | extern bool axp_cc_is_enabled(void); | ||
140 | |||
141 | /* Set/get maximum charging current in milliamps */ | ||
142 | extern void axp_set_charge_current(int maxcurrent); | ||
143 | extern int axp_get_charge_current(void); | ||
144 | |||
145 | /* Set the shutdown bit */ | ||
146 | extern void axp_power_off(void); | ||
147 | |||
148 | /* Debug menu */ | ||
149 | extern bool axp_debug_menu(void); | ||
150 | |||
151 | #endif /* __AXP_PMU_H__ */ | ||
diff --git a/firmware/export/axp192-defs.h b/firmware/export/axp192-defs.h deleted file mode 100644 index 13b465351b..0000000000 --- a/firmware/export/axp192-defs.h +++ /dev/null | |||
@@ -1,308 +0,0 @@ | |||
1 | /* Internal header for axp192 driver - not for general inclusion */ | ||
2 | |||
3 | #ifndef DEFREG | ||
4 | # define DEFREG(...) | ||
5 | #endif | ||
6 | #ifndef DEFFLD | ||
7 | # define DEFFLD(...) | ||
8 | #endif | ||
9 | |||
10 | #define DEFBIT(regname, fldname, bitpos, ...) \ | ||
11 | DEFFLD(regname, fldname, bitpos, bitpos, __VA_ARGS__) | ||
12 | |||
13 | DEFREG(PWRSTS, 0x00) | ||
14 | DEFREG(CHGSTS, 0x01) | ||
15 | DEFREG(CHIPID, 0x03) | ||
16 | DEFREG(VBUSSTS, 0x04) | ||
17 | DEFREG(DATA0, 0x06) | ||
18 | DEFREG(DATA1, 0x07) | ||
19 | DEFREG(DATA2, 0x08) | ||
20 | DEFREG(DATA3, 0x09) | ||
21 | DEFREG(DATA4, 0x0a) | ||
22 | DEFREG(DATA5, 0x0b) | ||
23 | DEFREG(PWRCTL1, 0x10) | ||
24 | DEFREG(PWRCTL2, 0x12) | ||
25 | DEFREG(DCDC2VOLT, 0x23) | ||
26 | DEFREG(DCDC2RAMP, 0x25) | ||
27 | DEFREG(DCDC1VOLT, 0x26) | ||
28 | DEFREG(DCDC3VOLT, 0x27) | ||
29 | DEFREG(LDO2LDO3VOLT, 0x28) | ||
30 | DEFREG(VBUSIPSOUT, 0x30) | ||
31 | DEFREG(VOFF, 0x31) | ||
32 | DEFREG(PWROFF, 0x32) | ||
33 | DEFREG(CHGCTL1, 0x33) | ||
34 | DEFREG(CHGCTL2, 0x34) | ||
35 | DEFREG(BKPCHGCTL, 0x35) | ||
36 | DEFREG(PEKPARAM, 0x36) | ||
37 | DEFREG(DCDCFREQ, 0x37) | ||
38 | DEFREG(VLTFCHG, 0x38) | ||
39 | DEFREG(VHTFCHG, 0x39) | ||
40 | DEFREG(APSLOW1, 0x3a) | ||
41 | DEFREG(APSLOW2, 0x3b) | ||
42 | DEFREG(VLTFDCHG, 0x3c) | ||
43 | DEFREG(VHTFDCHG, 0x3d) | ||
44 | DEFREG(IRQEN1, 0x40) | ||
45 | DEFREG(IRQEN2, 0x41) | ||
46 | DEFREG(IRQEN3, 0x42) | ||
47 | DEFREG(IRQEN4, 0x43) | ||
48 | DEFREG(IRQSTS1, 0x44) | ||
49 | DEFREG(IRQSTS2, 0x45) | ||
50 | DEFREG(IRQSTS3, 0x46) | ||
51 | DEFREG(IRQSTS4, 0x47) | ||
52 | DEFREG(IRQEN5, 0x4a) | ||
53 | DEFREG(IRQSTS5, 0x4d) | ||
54 | DEFREG(DCDCMODE, 0x80) | ||
55 | DEFREG(ADCEN1, 0x82) | ||
56 | DEFREG(ADCEN2, 0x83) | ||
57 | DEFREG(ADCCTL, 0x84) | ||
58 | DEFREG(ADCRANGE, 0x85) | ||
59 | DEFREG(TIMERCTL, 0x8a) | ||
60 | DEFREG(VBUSSRP, 0x8b) | ||
61 | DEFREG(OTPOWEROFF, 0x8f) | ||
62 | DEFREG(GPIO0FUNC, 0x90) | ||
63 | DEFREG(GPIO0LDO, 0x91) | ||
64 | DEFREG(GPIO1FUNC, 0x92) | ||
65 | DEFREG(GPIO2FUNC, 0x93) | ||
66 | DEFREG(GPIOLEVEL1, 0x94) | ||
67 | DEFREG(GPIO3GPIO4FUNC, 0x95) | ||
68 | DEFREG(GPIOLEVEL2, 0x96) | ||
69 | DEFREG(GPIOPULL, 0x97) | ||
70 | DEFREG(PWM1X, 0x98) | ||
71 | DEFREG(PWM1Y1, 0x99) | ||
72 | DEFREG(PWM1Y2, 0x9a) | ||
73 | DEFREG(PWM2X, 0x9b) | ||
74 | DEFREG(PWM2Y1, 0x9c) | ||
75 | DEFREG(PWM2Y2, 0x9d) | ||
76 | DEFREG(NRSTO, 0x9e) | ||
77 | DEFREG(CC_CTL, 0xb8) | ||
78 | |||
79 | DEFBIT(PWRSTS, ACIN_PRESENT, 7) | ||
80 | DEFBIT(PWRSTS, ACIN_VALID, 6) | ||
81 | DEFBIT(PWRSTS, VBUS_PRESENT, 5) | ||
82 | DEFBIT(PWRSTS, VBUS_VALID, 4) | ||
83 | DEFBIT(PWRSTS, VBUS_VHOLD, 3) | ||
84 | DEFBIT(PWRSTS, BATT_CURR_DIR, 2) | ||
85 | DEFBIT(PWRSTS, PCB_SHORTED, 1) | ||
86 | DEFBIT(PWRSTS, BOOT_TRIG, 0) | ||
87 | |||
88 | DEFBIT(VBUSSTS, VALID, 2) | ||
89 | DEFBIT(VBUSSTS, SESS_AB_VALID, 1) | ||
90 | DEFBIT(VBUSSTS, SESS_END, 0) | ||
91 | |||
92 | DEFBIT(CHGSTS, OVER_TEMP, 7) | ||
93 | DEFBIT(CHGSTS, CHARGING, 6) | ||
94 | DEFBIT(CHGSTS, BATT_PRESENT, 5) | ||
95 | DEFBIT(CHGSTS, BATT_ERROR, 3) | ||
96 | DEFBIT(CHGSTS, LOW_CHARGE, 2) | ||
97 | |||
98 | /* NOTE: These two bits are mirrored in the upper nibble of PWRCTL2. | ||
99 | * Modifications through one register will immediately reflect in the | ||
100 | * other register. */ | ||
101 | DEFBIT(PWRCTL1, EXTEN_SW, 2) | ||
102 | DEFBIT(PWRCTL1, DCDC2_SW, 0) | ||
103 | |||
104 | DEFBIT(PWRCTL2, EXTEN_SW, 6) | ||
105 | DEFBIT(PWRCTL2, DCDC2_SW, 4) | ||
106 | DEFBIT(PWRCTL2, LDO3_SW, 3) | ||
107 | DEFBIT(PWRCTL2, LDO2_SW, 2) | ||
108 | DEFBIT(PWRCTL2, DCDC3_SW, 1) | ||
109 | DEFBIT(PWRCTL2, DCDC1_SW, 0) | ||
110 | |||
111 | DEFFLD(DCDC2VOLT, VALUE, 5, 0) | ||
112 | |||
113 | DEFBIT(DCDC2RAMP, ENABLE, 2) | ||
114 | DEFBIT(DCDC2RAMP, SLOPE, 0) | ||
115 | |||
116 | DEFFLD(DCDC1VOLT, VALUE, 6, 0) | ||
117 | DEFFLD(DCDC3VOLT, VALUE, 6, 0) | ||
118 | |||
119 | DEFFLD(LDO2LDO3VOLT, LDO2_VALUE, 7, 4) | ||
120 | DEFFLD(LDO2LDO3VOLT, LDO3_VALUE, 3, 0) | ||
121 | |||
122 | DEFBIT(VBUSIPSOUT, ACCESS, 7) | ||
123 | DEFBIT(VBUSIPSOUT, VHOLD_LIM, 6) | ||
124 | DEFFLD(VBUSIPSOUT, VHOLD_LEV, 5, 3) | ||
125 | DEFBIT(VBUSIPSOUT, VBUS_LIM, 1) | ||
126 | DEFBIT(VBUSIPSOUT, LIM_100mA, 0) | ||
127 | |||
128 | DEFFLD(VOFF, VALUE, 3, 0) | ||
129 | |||
130 | DEFBIT(PWROFF, SHUTDOWN, 7) | ||
131 | DEFBIT(PWROFF, MON_EN, 6) | ||
132 | DEFFLD(PWROFF, LEDFUNC, 5, 4) | ||
133 | DEFBIT(PWROFF, LEDCTL, 3) | ||
134 | DEFBIT(PWROFF, DELAY, 1, 0) | ||
135 | |||
136 | DEFBIT(CHGCTL1, CHARGE_EN, 7) | ||
137 | DEFFLD(CHGCTL1, CHARGE_TGT, 6, 5) | ||
138 | DEFBIT(CHGCTL1, CHARGE_ENDCURR, 4) | ||
139 | DEFFLD(CHGCTL1, CHARGE_CURRENT, 3, 0) | ||
140 | |||
141 | DEFFLD(CHGCTL2, PRECHARGE_OT, 7, 6) | ||
142 | DEFFLD(CHGCTL2, EACCESS_CURRENT, 5, 3) | ||
143 | DEFBIT(CHGCTL2, EACCESS_CHG_EN, 2) | ||
144 | DEFFLD(CHGCTL2, CONST_CURR_OT, 1, 0) | ||
145 | |||
146 | DEFBIT(BKPCHGCTL, ENABLE, 7) | ||
147 | DEFFLD(BKPCHGCTL, TGT_VOLTAGE, 6, 5) | ||
148 | DEFFLD(BKPCHGCTL, CHARGE_CURRENT, 1, 0) | ||
149 | |||
150 | DEFFLD(PEKPARAM, POWER_ON_TIME, 7, 6) | ||
151 | DEFFLD(PEKPARAM, LONG_TIME, 5, 4) | ||
152 | DEFBIT(PEKPARAM, POWEROFF_EN, 3) | ||
153 | DEFBIT(PEKPARAM, PWROK_DELAY, 2) | ||
154 | DEFFLD(PEKPARAM, POWEROFF_TIME, 1, 0) | ||
155 | |||
156 | DEFFLD(DCDCFREQ, VALUE, 3, 0) | ||
157 | DEFFLD(VLTFCHG, VALUE, 7, 0) | ||
158 | DEFFLD(VHTFCHG, VALUE, 7, 0) | ||
159 | DEFFLD(APSLOW1, VALUE, 7, 0) | ||
160 | DEFFLD(APSLOW2, VALUE, 7, 0) | ||
161 | DEFFLD(VLTFDCHG, VALUE, 7, 0) | ||
162 | DEFFLD(VHTFDCHG, VALUE, 7, 0) | ||
163 | |||
164 | DEFBIT(IRQEN1, ACIN_OVER_VOLTAGE, 7) | ||
165 | DEFBIT(IRQEN1, ACIN_INSERT, 6) | ||
166 | DEFBIT(IRQEN1, ACIN_REMOVE, 5) | ||
167 | DEFBIT(IRQEN1, VBUS_OVER_VOLTAGE, 4) | ||
168 | DEFBIT(IRQEN1, VBUS_INSERT, 3) | ||
169 | DEFBIT(IRQEN1, VBUS_REMOVE, 2) | ||
170 | DEFBIT(IRQEN1, VBUS_BELOW_VHOLD, 1) | ||
171 | DEFBIT(IRQEN2, BATTERY_INSERT, 7) | ||
172 | DEFBIT(IRQEN2, BATTERY_REMOVE, 6) | ||
173 | DEFBIT(IRQEN2, BATTERY_ERROR, 5) | ||
174 | DEFBIT(IRQEN2, BATTERY_ERROR_CLR, 4) | ||
175 | DEFBIT(IRQEN2, CHARGING_STARTED, 3) | ||
176 | DEFBIT(IRQEN2, CHARGING_COMPLETE, 2) | ||
177 | DEFBIT(IRQEN2, BATTERY_OVER_TEMP, 1) | ||
178 | DEFBIT(IRQEN2, BATTERY_UNDER_TEMP, 0) | ||
179 | DEFBIT(IRQEN3, INTERNAL_OVER_TEMP, 7) | ||
180 | DEFBIT(IRQEN3, LOW_CHARGE_CURRENT, 6) | ||
181 | DEFBIT(IRQEN3, DCDC1_UNDER_VOLT, 5) | ||
182 | DEFBIT(IRQEN3, DCDC2_UNDER_VOLT, 4) | ||
183 | DEFBIT(IRQEN3, DCDC3_UNDER_VOLT, 3) | ||
184 | DEFBIT(IRQEN3, SHORT_PRESS, 1) | ||
185 | DEFBIT(IRQEN3, LONG_PRESS, 0) | ||
186 | DEFBIT(IRQEN4, POWER_ON_N_OE, 7) | ||
187 | DEFBIT(IRQEN4, POWER_OFF_N_OE, 6) | ||
188 | DEFBIT(IRQEN4, VBUS_VALID, 5) | ||
189 | DEFBIT(IRQEN4, VBUS_INVALID, 4) | ||
190 | DEFBIT(IRQEN4, VBUS_SESS_AB, 3) | ||
191 | DEFBIT(IRQEN4, VBUS_SESS_END, 2) | ||
192 | DEFBIT(IRQEN4, APS_UNDER_VOLT, 0) | ||
193 | |||
194 | DEFBIT(IRQSTS1, ACIN_OVER_VOLTAGE, 7) | ||
195 | DEFBIT(IRQSTS1, ACIN_INSERT, 6) | ||
196 | DEFBIT(IRQSTS1, ACIN_REMOVE, 5) | ||
197 | DEFBIT(IRQSTS1, VBUS_OVER_VOLTAGE, 4) | ||
198 | DEFBIT(IRQSTS1, VBUS_INSERT, 3) | ||
199 | DEFBIT(IRQSTS1, VBUS_REMOVE, 2) | ||
200 | DEFBIT(IRQSTS1, VBUS_BELOW_VHOLD, 1) | ||
201 | DEFBIT(IRQSTS2, BATTERY_INSERT, 7) | ||
202 | DEFBIT(IRQSTS2, BATTERY_REMOVE, 6) | ||
203 | DEFBIT(IRQSTS2, BATTERY_ERROR, 5) | ||
204 | DEFBIT(IRQSTS2, BATTERY_ERROR_CLR, 4) | ||
205 | DEFBIT(IRQSTS2, CHARGING_STARTED, 3) | ||
206 | DEFBIT(IRQSTS2, CHARGING_STOPPED, 2) | ||
207 | DEFBIT(IRQSTS2, BATTERY_OVER_TEMP, 1) | ||
208 | DEFBIT(IRQSTS2, BATTERY_UNDER_TEMP, 0) | ||
209 | DEFBIT(IRQSTS3, INTERNAL_OVER_TEMP, 7) | ||
210 | DEFBIT(IRQSTS3, LOW_CHARGE_CURRENT, 6) | ||
211 | DEFBIT(IRQSTS3, DCDC1_UNDER_VOLT, 5) | ||
212 | DEFBIT(IRQSTS3, DCDC2_UNDER_VOLT, 4) | ||
213 | DEFBIT(IRQSTS3, DCDC3_UNDER_VOLT, 3) | ||
214 | DEFBIT(IRQSTS3, SHORT_PRESS, 1) | ||
215 | DEFBIT(IRQSTS3, LONG_PRESS, 0) | ||
216 | DEFBIT(IRQSTS4, POWER_ON_N_OE, 7) | ||
217 | DEFBIT(IRQSTS4, POWER_OFF_N_OE, 6) | ||
218 | DEFBIT(IRQSTS4, VBUS_VALID, 5) | ||
219 | DEFBIT(IRQSTS4, VBUS_INVALID, 4) | ||
220 | DEFBIT(IRQSTS4, VBUS_SESS_AB, 3) | ||
221 | DEFBIT(IRQSTS4, VBUS_SESS_END, 2) | ||
222 | DEFBIT(IRQSTS4, APS_UNDER_VOLT, 0) | ||
223 | |||
224 | /* NOTE: IRQEN5 and IRQSTS5 are only listed on the Chinese datasheet. */ | ||
225 | DEFBIT(IRQEN5, TIME_OUT, 7) | ||
226 | DEFBIT(IRQEN5, GPIO2_CHANGE, 2) | ||
227 | DEFBIT(IRQEN5, GPIO1_CHANGE, 1) | ||
228 | DEFBIT(IRQEN5, GPIO0_CHANGE, 0) | ||
229 | |||
230 | DEFBIT(IRQSTS5, TIME_OUT, 7) | ||
231 | DEFBIT(IRQSTS5, GPIO2_CHANGE, 2) | ||
232 | DEFBIT(IRQSTS5, GPIO1_CHANGE, 1) | ||
233 | DEFBIT(IRQSTS5, GPIO0_CHANGE, 0) | ||
234 | |||
235 | DEFFLD(DCDCMODE, VALUE, 3, 1) | ||
236 | |||
237 | DEFBIT(ADCEN1, BATTERY_VOLTAGE, 7) | ||
238 | DEFBIT(ADCEN1, BATTERY_CURRENT, 6) | ||
239 | DEFBIT(ADCEN1, ACIN_VOLTAGE, 5) | ||
240 | DEFBIT(ADCEN1, ACIN_CURRENT, 4) | ||
241 | DEFBIT(ADCEN1, VBUS_VOLTAGE, 3) | ||
242 | DEFBIT(ADCEN1, VBUS_CURRENT, 2) | ||
243 | DEFBIT(ADCEN1, APS_VOLTAGE, 1) | ||
244 | DEFBIT(ADCEN1, TS_PIN, 0) | ||
245 | |||
246 | DEFBIT(ADCEN2, INTERNAL_TEMP, 7) | ||
247 | DEFBIT(ADCEN2, GPIO0, 3) | ||
248 | DEFBIT(ADCEN2, GPIO1, 2) | ||
249 | DEFBIT(ADCEN2, GPIO2, 1) | ||
250 | DEFBIT(ADCEN2, GPIO3, 0) | ||
251 | |||
252 | DEFFLD(ADCCTL, SAMPLE_RATE, 7, 6) | ||
253 | DEFFLD(ADCCTL, TS_OUT_CURR, 5, 4) | ||
254 | DEFBIT(ADCCTL, TS_FUNCTION, 2) | ||
255 | DEFFLD(ADCCTL, TS_OUT_MODE, 1, 0) | ||
256 | |||
257 | DEFBIT(ADCRANGE, GPIO3HIGH, 3) | ||
258 | DEFBIT(ADCRANGE, GPIO2HIGH, 2) | ||
259 | DEFBIT(ADCRANGE, GPIO1HIGH, 1) | ||
260 | DEFBIT(ADCRANGE, GPIO0HIGH, 0) | ||
261 | |||
262 | DEFBIT(TIMERCTL, TIMEOUT, 7) | ||
263 | DEFFLD(TIMERCTL, DURATION, 6, 0) | ||
264 | |||
265 | DEFFLD(VBUSSRP, VBUSVALID_VOLTAGE, 5, 4) | ||
266 | DEFBIT(VBUSSRP, VBUSVALID_MONITOR, 3) | ||
267 | DEFBIT(VBUSSRP, VBUS_SESS_MONITOR, 2) | ||
268 | DEFBIT(VBUSSRP, VBUS_DCHG_RESISTOR, 1) | ||
269 | DEFBIT(VBUSSRP, VBUS_CHG_RESISTOR, 0) | ||
270 | |||
271 | DEFBIT(OTPOWEROFF, ENABLE, 2) | ||
272 | |||
273 | DEFFLD(GPIO0FUNC, VALUE, 2, 0) | ||
274 | DEFFLD(GPIO0LDO, VALUE, 7, 4) | ||
275 | DEFFLD(GPIO1FUNC, VALUE, 2, 0) | ||
276 | DEFFLD(GPIO2FUNC, VALUE, 2, 0) | ||
277 | |||
278 | DEFBIT(GPIOLEVEL1, IN2, 6) | ||
279 | DEFBIT(GPIOLEVEL1, IN1, 5) | ||
280 | DEFBIT(GPIOLEVEL1, IN0, 4) | ||
281 | DEFBIT(GPIOLEVEL1, OUT2, 2) | ||
282 | DEFBIT(GPIOLEVEL1, OUT1, 1) | ||
283 | DEFBIT(GPIOLEVEL1, OUT0, 0) | ||
284 | |||
285 | DEFFLD(GPIO3GPIO4FUNC, FUNC3, 3, 2) | ||
286 | DEFFLD(GPIO3GPIO4FUNC, FUNC4, 1, 0) | ||
287 | |||
288 | DEFBIT(GPIOLEVEL2, IN4, 5) | ||
289 | DEFBIT(GPIOLEVEL2, IN3, 4) | ||
290 | DEFBIT(GPIOLEVEL2, OUT4, 1) | ||
291 | DEFBIT(GPIOLEVEL2, OUT3, 0) | ||
292 | |||
293 | DEFBIT(GPIOPULL, PULL2, 2) | ||
294 | DEFBIT(GPIOPULL, PULL1, 1) | ||
295 | DEFBIT(GPIOPULL, PULL0, 0) | ||
296 | |||
297 | DEFBIT(NRSTO, FUNC, 7) | ||
298 | DEFBIT(NRSTO, GPIO_DIR, 6) | ||
299 | DEFBIT(NRSTO, GPIO_OUT, 5) | ||
300 | DEFBIT(NRSTO, GPIO_IN, 4) | ||
301 | |||
302 | DEFBIT(CC_CTL, OPEN, 7) | ||
303 | DEFBIT(CC_CTL, PAUSE, 6) | ||
304 | DEFBIT(CC_CTL, CLEAR, 5) | ||
305 | |||
306 | #undef DEFBIT | ||
307 | #undef DEFFLD | ||
308 | #undef DEFREG | ||
diff --git a/firmware/export/axp192.h b/firmware/export/axp192.h deleted file mode 100644 index 6ed278d086..0000000000 --- a/firmware/export/axp192.h +++ /dev/null | |||
@@ -1,131 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2021 Aidan MacDonald | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #ifndef __AXP192_H__ | ||
23 | #define __AXP192_H__ | ||
24 | |||
25 | #include <stdint.h> | ||
26 | #include <stdbool.h> | ||
27 | |||
28 | enum { | ||
29 | #define DEFREG(regname, addr) AXP_REG_##regname = addr, | ||
30 | #include "axp192-defs.h" | ||
31 | }; | ||
32 | |||
33 | enum { | ||
34 | #define DEFFLD(regname, fldname, msb, lsb, ...) \ | ||
35 | BM_AXP_##regname##_##fldname = ((1 << ((msb) - (lsb) + 1)) - 1) << lsb, \ | ||
36 | BP_AXP_##regname##_##fldname = lsb, | ||
37 | #include "axp192-defs.h" | ||
38 | }; | ||
39 | |||
40 | enum { | ||
41 | AXP_SUPPLY_EXTEN, | ||
42 | AXP_SUPPLY_DCDC1, | ||
43 | AXP_SUPPLY_DCDC2, | ||
44 | AXP_SUPPLY_DCDC3, | ||
45 | AXP_SUPPLY_LDO2, | ||
46 | AXP_SUPPLY_LDO3, | ||
47 | AXP_SUPPLY_LDOIO0, | ||
48 | AXP_NUM_SUPPLIES, | ||
49 | }; | ||
50 | |||
51 | enum { | ||
52 | AXP_ADC_ACIN_VOLTAGE, | ||
53 | AXP_ADC_ACIN_CURRENT, | ||
54 | AXP_ADC_VBUS_VOLTAGE, | ||
55 | AXP_ADC_VBUS_CURRENT, | ||
56 | AXP_ADC_INTERNAL_TEMP, | ||
57 | AXP_ADC_TS_INPUT, | ||
58 | AXP_ADC_GPIO0, | ||
59 | AXP_ADC_GPIO1, | ||
60 | AXP_ADC_GPIO2, | ||
61 | AXP_ADC_GPIO3, | ||
62 | AXP_ADC_BATTERY_VOLTAGE, | ||
63 | AXP_ADC_CHARGE_CURRENT, | ||
64 | AXP_ADC_DISCHARGE_CURRENT, | ||
65 | AXP_ADC_APS_VOLTAGE, | ||
66 | AXP_NUM_ADCS, | ||
67 | }; | ||
68 | |||
69 | enum { | ||
70 | AXP_GPIO_OPEN_DRAIN_OUTPUT = 0x0, | ||
71 | AXP_GPIO_INPUT = 0x1, | ||
72 | AXP_GPIO_SPECIAL = 0x2, | ||
73 | AXP_GPIO_ADC_IN = 0x4, | ||
74 | AXP_GPIO_LOW_OUTPUT = 0x5, | ||
75 | AXP_GPIO_FLOATING = 0x7, | ||
76 | }; | ||
77 | |||
78 | enum { | ||
79 | /* Limit USB current consumption to 100 mA. */ | ||
80 | AXP_VBUS_LIMIT_100mA = (1 << BP_AXP_VBUSIPSOUT_VHOLD_LIM) | | ||
81 | (1 << BP_AXP_VBUSIPSOUT_VBUS_LIM) | | ||
82 | (1 << BP_AXP_VBUSIPSOUT_LIM_100mA), | ||
83 | |||
84 | /* Limit USB current consumption to 500 mA. */ | ||
85 | AXP_VBUS_LIMIT_500mA = (1 << BP_AXP_VBUSIPSOUT_VHOLD_LIM) | | ||
86 | (1 << BP_AXP_VBUSIPSOUT_VBUS_LIM) | | ||
87 | (0 << BP_AXP_VBUSIPSOUT_LIM_100mA), | ||
88 | |||
89 | /* No upper bound on USB current, but the current will still | ||
90 | * be reduced to maintain the bus voltage above V_hold. */ | ||
91 | AXP_VBUS_UNLIMITED = (1 << BP_AXP_VBUSIPSOUT_VHOLD_LIM) | | ||
92 | (0 << BP_AXP_VBUSIPSOUT_VBUS_LIM) | | ||
93 | (0 << BP_AXP_VBUSIPSOUT_LIM_100mA), | ||
94 | |||
95 | /* Unlimited USB current consumption. Voltage is allowed to drop | ||
96 | * below V_hold, which may interfere with normal USB operation. | ||
97 | * This mode is really only useful with AC charging adapters. */ | ||
98 | AXP_VBUS_FULLY_UNLIMITED = (0 << BP_AXP_VBUSIPSOUT_VHOLD_LIM) | | ||
99 | (0 << BP_AXP_VBUSIPSOUT_VBUS_LIM) | | ||
100 | (0 << BP_AXP_VBUSIPSOUT_LIM_100mA), | ||
101 | }; | ||
102 | |||
103 | extern int axp_read(uint8_t reg); | ||
104 | extern int axp_write(uint8_t reg, uint8_t value); | ||
105 | extern int axp_modify(uint8_t reg, uint8_t clr, uint8_t set); | ||
106 | |||
107 | extern void axp_enable_supply(int supply, bool enable); | ||
108 | extern void axp_set_enabled_supplies(unsigned int supply_mask); | ||
109 | extern void axp_set_supply_voltage(int supply, int output_mV); | ||
110 | |||
111 | extern void axp_enable_adc(int adc, bool enable); | ||
112 | extern void axp_set_enabled_adcs(unsigned int adc_mask); | ||
113 | extern int axp_read_adc_raw(int adc); | ||
114 | extern int axp_conv_adc(int adc, int value); | ||
115 | extern int axp_read_adc(int adc); | ||
116 | |||
117 | extern void axp_set_gpio_function(int gpio, int function); | ||
118 | extern void axp_set_gpio_pulldown(int gpio, bool enable); | ||
119 | extern int axp_get_gpio(int gpio); | ||
120 | extern void axp_set_gpio(int gpio, bool enable); | ||
121 | |||
122 | extern void axp_set_charge_current(int current_mA); | ||
123 | extern int axp_get_charge_current(void); | ||
124 | extern void axp_set_vbus_limit(int vbus_limit); | ||
125 | extern void axp_set_vhold_level(int vhold_mV); | ||
126 | extern bool axp_is_charging(void); | ||
127 | extern unsigned int axp_power_input_status(void); | ||
128 | |||
129 | extern void axp_power_off(void); | ||
130 | |||
131 | #endif /* __AXP192_H__ */ | ||
diff --git a/firmware/target/mips/ingenic_x1000/erosqnative/button-erosqnative.c b/firmware/target/mips/ingenic_x1000/erosqnative/button-erosqnative.c index 64041795a3..1583db175a 100644 --- a/firmware/target/mips/ingenic_x1000/erosqnative/button-erosqnative.c +++ b/firmware/target/mips/ingenic_x1000/erosqnative/button-erosqnative.c | |||
@@ -24,7 +24,7 @@ | |||
24 | #include "backlight.h" | 24 | #include "backlight.h" |
25 | #include "powermgmt.h" | 25 | #include "powermgmt.h" |
26 | #include "panic.h" | 26 | #include "panic.h" |
27 | #include "axp192.h" | 27 | #include "axp-pmu.h" |
28 | #include "gpio-x1000.h" | 28 | #include "gpio-x1000.h" |
29 | #include "irq-x1000.h" | 29 | #include "irq-x1000.h" |
30 | #include "i2c-x1000.h" | 30 | #include "i2c-x1000.h" |
@@ -89,7 +89,7 @@ static int hp_detect_tmo_cb(struct timeout* tmo) | |||
89 | static void hp_detect_init(void) | 89 | static void hp_detect_init(void) |
90 | { | 90 | { |
91 | static struct timeout tmo; | 91 | static struct timeout tmo; |
92 | static const uint8_t gpio_reg = AXP_REG_GPIOLEVEL1; | 92 | static const uint8_t gpio_reg = AXP192_REG_GPIOSTATE1; |
93 | static i2c_descriptor desc = { | 93 | static i2c_descriptor desc = { |
94 | .slave_addr = AXP_PMU_ADDR, | 94 | .slave_addr = AXP_PMU_ADDR, |
95 | .bus_cond = I2C_START | I2C_STOP, | 95 | .bus_cond = I2C_START | I2C_STOP, |
@@ -105,11 +105,11 @@ static void hp_detect_init(void) | |||
105 | 105 | ||
106 | /* Headphone and LO detects are wired to AXP192 GPIOs 0 and 1, | 106 | /* Headphone and LO detects are wired to AXP192 GPIOs 0 and 1, |
107 | * set them to inputs. */ | 107 | * set them to inputs. */ |
108 | axp_set_gpio_function(0, AXP_GPIO_INPUT); /* HP detect */ | 108 | i2c_reg_write1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP192_REG_GPIO0FUNCTION, 0x01); /* HP detect */ |
109 | axp_set_gpio_function(1, AXP_GPIO_INPUT); /* LO detect */ | 109 | i2c_reg_write1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP192_REG_GPIO1FUNCTION, 0x01); /* LO detect */ |
110 | 110 | ||
111 | /* Get an initial reading before startup */ | 111 | /* Get an initial reading before startup */ |
112 | int r = axp_read(gpio_reg); | 112 | int r = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, gpio_reg); |
113 | if(r >= 0) | 113 | if(r >= 0) |
114 | { | 114 | { |
115 | hp_detect_reg = r; | 115 | hp_detect_reg = r; |
diff --git a/firmware/target/mips/ingenic_x1000/erosqnative/power-erosqnative.c b/firmware/target/mips/ingenic_x1000/erosqnative/power-erosqnative.c index 9cf64cee01..a1a4d2c2b2 100644 --- a/firmware/target/mips/ingenic_x1000/erosqnative/power-erosqnative.c +++ b/firmware/target/mips/ingenic_x1000/erosqnative/power-erosqnative.c | |||
@@ -28,7 +28,7 @@ | |||
28 | #ifdef HAVE_USB_CHARGING_ENABLE | 28 | #ifdef HAVE_USB_CHARGING_ENABLE |
29 | # include "usb_core.h" | 29 | # include "usb_core.h" |
30 | #endif | 30 | #endif |
31 | #include "axp192.h" | 31 | #include "axp-pmu.h" |
32 | #include "i2c-x1000.h" | 32 | #include "i2c-x1000.h" |
33 | 33 | ||
34 | const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] = | 34 | const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] = |
@@ -56,35 +56,27 @@ const unsigned short percent_to_volt_charge[11] = | |||
56 | 56 | ||
57 | void power_init(void) | 57 | void power_init(void) |
58 | { | 58 | { |
59 | /* Configure I2C bus */ | 59 | /* Initialize driver */ |
60 | i2c_x1000_set_freq(AXP_PMU_BUS, I2C_FREQ_400K); | 60 | i2c_x1000_set_freq(2, I2C_FREQ_400K); |
61 | 61 | axp_init(); | |
62 | /* FIXME: Copy paste from M3K. Probably not necessary */ | 62 | |
63 | axp_modify(AXP_REG_DCDCMODE, 0, 0xc0); | 63 | /* Set lowest sample rate */ |
64 | 64 | axp_adc_set_rate(AXP_ADC_RATE_25HZ); | |
65 | /* Power on required supplies | 65 | |
66 | * TODO: This should be checked, though likely all but EXTEN are needed */ | 66 | /* Ensure battery voltage ADC is enabled */ |
67 | axp_set_enabled_supplies( | 67 | int bits = axp_adc_get_enabled(); |
68 | (1 << AXP_SUPPLY_EXTEN) | | 68 | bits |= (1 << ADC_BATTERY_VOLTAGE); |
69 | (1 << AXP_SUPPLY_DCDC1) | | 69 | axp_adc_set_enabled(bits); |
70 | (1 << AXP_SUPPLY_DCDC2) | | 70 | |
71 | (1 << AXP_SUPPLY_DCDC3) | | 71 | /* Turn on all power outputs */ |
72 | (1 << AXP_SUPPLY_LDO2) | | 72 | i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR, |
73 | (1 << AXP_SUPPLY_LDO3)); | 73 | AXP_REG_PWROUTPUTCTRL2, 0, 0x5f, NULL); |
74 | 74 | i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR, | |
75 | /* Enable required ADCs */ | 75 | AXP_REG_DCDCWORKINGMODE, 0, 0xc0, NULL); |
76 | axp_set_enabled_adcs( | 76 | |
77 | (1 << AXP_ADC_BATTERY_VOLTAGE) | | 77 | /* Set the default charging current. This is the same as the |
78 | (1 << AXP_ADC_CHARGE_CURRENT) | | 78 | * OF's setting, although it's not strictly within the USB spec. */ |
79 | (1 << AXP_ADC_DISCHARGE_CURRENT) | | 79 | axp_set_charge_current(780); |
80 | (1 << AXP_ADC_VBUS_VOLTAGE) | | ||
81 | (1 << AXP_ADC_VBUS_CURRENT) | | ||
82 | (1 << AXP_ADC_INTERNAL_TEMP) | | ||
83 | (1 << AXP_ADC_APS_VOLTAGE)); | ||
84 | |||
85 | /* Configure USB charging */ | ||
86 | axp_set_vhold_level(4400); | ||
87 | usb_charging_maxcurrent_change(100); | ||
88 | 80 | ||
89 | /* Delay to give power outputs time to stabilize. | 81 | /* Delay to give power outputs time to stabilize. |
90 | * With the power thread delay, this can apparently go as low as 50, | 82 | * With the power thread delay, this can apparently go as low as 50, |
@@ -96,22 +88,7 @@ void power_init(void) | |||
96 | #ifdef HAVE_USB_CHARGING_ENABLE | 88 | #ifdef HAVE_USB_CHARGING_ENABLE |
97 | void usb_charging_maxcurrent_change(int maxcurrent) | 89 | void usb_charging_maxcurrent_change(int maxcurrent) |
98 | { | 90 | { |
99 | int vbus_limit; | 91 | axp_set_charge_current(maxcurrent); |
100 | int charge_current; | ||
101 | |||
102 | /* Note that the charge current setting is a maximum: it will be | ||
103 | * reduced dynamically by the AXP192 so the combined load is less | ||
104 | * than the set VBUS current limit. */ | ||
105 | if(maxcurrent <= 100) { | ||
106 | vbus_limit = AXP_VBUS_LIMIT_500mA; | ||
107 | charge_current = 100; | ||
108 | } else { | ||
109 | vbus_limit = AXP_VBUS_LIMIT_500mA; | ||
110 | charge_current = 550; | ||
111 | } | ||
112 | |||
113 | axp_set_vbus_limit(vbus_limit); | ||
114 | axp_set_charge_current(charge_current); | ||
115 | } | 92 | } |
116 | #endif | 93 | #endif |
117 | 94 | ||
@@ -127,25 +104,20 @@ void power_off(void) | |||
127 | 104 | ||
128 | bool charging_state(void) | 105 | bool charging_state(void) |
129 | { | 106 | { |
130 | return axp_is_charging(); | 107 | return axp_battery_status() == AXP_BATT_CHARGING; |
131 | } | ||
132 | |||
133 | unsigned int power_input_status(void) | ||
134 | { | ||
135 | return axp_power_input_status(); | ||
136 | } | 108 | } |
137 | 109 | ||
138 | int _battery_voltage(void) | 110 | int _battery_voltage(void) |
139 | { | 111 | { |
140 | return axp_read_adc(AXP_ADC_BATTERY_VOLTAGE); | 112 | return axp_adc_read(ADC_BATTERY_VOLTAGE); |
141 | } | 113 | } |
142 | 114 | ||
143 | #if CONFIG_BATTERY_MEASURE & CURRENT_MEASURE | 115 | #if CONFIG_BATTERY_MEASURE & CURRENT_MEASURE |
144 | int _battery_current(void) | 116 | int _battery_current(void) |
145 | { | 117 | { |
146 | if(charging_state()) | 118 | if(charging_state()) |
147 | return axp_read_adc(AXP_ADC_CHARGE_CURRENT); | 119 | return axp_adc_read(ADC_CHARGE_CURRENT); |
148 | else | 120 | else |
149 | return axp_read_adc(AXP_ADC_DISCHARGE_CURRENT); | 121 | return axp_adc_read(ADC_DISCHARGE_CURRENT); |
150 | } | 122 | } |
151 | #endif | 123 | #endif |
diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c b/firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c index 0ef7bd2f64..24daf2ef69 100644 --- a/firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c +++ b/firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c | |||
@@ -24,7 +24,7 @@ | |||
24 | #include "backlight.h" | 24 | #include "backlight.h" |
25 | #include "powermgmt.h" | 25 | #include "powermgmt.h" |
26 | #include "panic.h" | 26 | #include "panic.h" |
27 | #include "axp192.h" | 27 | #include "axp-pmu.h" |
28 | #include "ft6x06.h" | 28 | #include "ft6x06.h" |
29 | #include "gpio-x1000.h" | 29 | #include "gpio-x1000.h" |
30 | #include "irq-x1000.h" | 30 | #include "irq-x1000.h" |
@@ -393,7 +393,7 @@ static int hp_detect_tmo_cb(struct timeout* tmo) | |||
393 | static void hp_detect_init(void) | 393 | static void hp_detect_init(void) |
394 | { | 394 | { |
395 | static struct timeout tmo; | 395 | static struct timeout tmo; |
396 | static const uint8_t gpio_reg = AXP_REG_GPIOLEVEL1; | 396 | static const uint8_t gpio_reg = AXP192_REG_GPIOSTATE1; |
397 | static i2c_descriptor desc = { | 397 | static i2c_descriptor desc = { |
398 | .slave_addr = AXP_PMU_ADDR, | 398 | .slave_addr = AXP_PMU_ADDR, |
399 | .bus_cond = I2C_START | I2C_STOP, | 399 | .bus_cond = I2C_START | I2C_STOP, |
@@ -408,10 +408,10 @@ static void hp_detect_init(void) | |||
408 | }; | 408 | }; |
409 | 409 | ||
410 | /* Headphone detect is wired to AXP192 GPIO: set it to input state */ | 410 | /* Headphone detect is wired to AXP192 GPIO: set it to input state */ |
411 | axp_set_gpio_function(2, AXP_GPIO_INPUT); | 411 | i2c_reg_write1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP192_REG_GPIO2FUNCTION, 0x01); |
412 | 412 | ||
413 | /* Get an initial reading before startup */ | 413 | /* Get an initial reading before startup */ |
414 | int r = axp_read(gpio_reg); | 414 | int r = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, gpio_reg); |
415 | if(r >= 0) | 415 | if(r >= 0) |
416 | hp_detect_reg = r; | 416 | hp_detect_reg = r; |
417 | 417 | ||
diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c b/firmware/target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c index b20bbd9e8c..2d28ad0975 100644 --- a/firmware/target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c +++ b/firmware/target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c | |||
@@ -26,7 +26,7 @@ | |||
26 | #ifdef HAVE_USB_CHARGING_ENABLE | 26 | #ifdef HAVE_USB_CHARGING_ENABLE |
27 | # include "usb_core.h" | 27 | # include "usb_core.h" |
28 | #endif | 28 | #endif |
29 | #include "axp192.h" | 29 | #include "axp-pmu.h" |
30 | #include "i2c-x1000.h" | 30 | #include "i2c-x1000.h" |
31 | 31 | ||
32 | const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] = | 32 | const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] = |
@@ -54,33 +54,27 @@ const unsigned short percent_to_volt_charge[11] = | |||
54 | 54 | ||
55 | void power_init(void) | 55 | void power_init(void) |
56 | { | 56 | { |
57 | /* Configure I2C bus */ | 57 | /* Initialize driver */ |
58 | i2c_x1000_set_freq(AXP_PMU_BUS, I2C_FREQ_400K); | 58 | i2c_x1000_set_freq(2, I2C_FREQ_400K); |
59 | 59 | axp_init(); | |
60 | /* Set DCDC1 and DCDC2 to fixed PWM mode to match OF settings. */ | 60 | |
61 | axp_modify(AXP_REG_DCDCMODE, 0, 0x0c); | 61 | /* Set lowest sample rate */ |
62 | 62 | axp_adc_set_rate(AXP_ADC_RATE_25HZ); | |
63 | /* Power on required supplies */ | 63 | |
64 | axp_set_enabled_supplies( | 64 | /* Ensure battery voltage ADC is enabled */ |
65 | (1 << AXP_SUPPLY_DCDC1) | /* not sure (3.3 V) */ | 65 | int bits = axp_adc_get_enabled(); |
66 | (1 << AXP_SUPPLY_DCDC2) | /* not sure (1.4 V) */ | 66 | bits |= (1 << ADC_BATTERY_VOLTAGE); |
67 | (1 << AXP_SUPPLY_DCDC3) | /* for CPU (1.8 V) */ | 67 | axp_adc_set_enabled(bits); |
68 | (1 << AXP_SUPPLY_LDO2) | /* LCD controller (3.3 V) */ | 68 | |
69 | (1 << AXP_SUPPLY_LDO3)); /* SD bus (3.3 V) */ | 69 | /* Turn on all power outputs */ |
70 | 70 | i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR, | |
71 | /* Enable required ADCs */ | 71 | AXP_REG_PWROUTPUTCTRL2, 0, 0x5f, NULL); |
72 | axp_set_enabled_adcs( | 72 | i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR, |
73 | (1 << AXP_ADC_BATTERY_VOLTAGE) | | 73 | AXP_REG_DCDCWORKINGMODE, 0, 0xc0, NULL); |
74 | (1 << AXP_ADC_CHARGE_CURRENT) | | 74 | |
75 | (1 << AXP_ADC_DISCHARGE_CURRENT) | | 75 | /* Set the default charging current. This is the same as the |
76 | (1 << AXP_ADC_VBUS_VOLTAGE) | | 76 | * OF's setting, although it's not strictly within the USB spec. */ |
77 | (1 << AXP_ADC_VBUS_CURRENT) | | 77 | axp_set_charge_current(780); |
78 | (1 << AXP_ADC_INTERNAL_TEMP) | | ||
79 | (1 << AXP_ADC_APS_VOLTAGE)); | ||
80 | |||
81 | /* Configure USB charging */ | ||
82 | axp_set_vhold_level(4400); | ||
83 | usb_charging_maxcurrent_change(100); | ||
84 | 78 | ||
85 | /* Short delay to give power outputs time to stabilize */ | 79 | /* Short delay to give power outputs time to stabilize */ |
86 | mdelay(200); | 80 | mdelay(200); |
@@ -89,22 +83,7 @@ void power_init(void) | |||
89 | #ifdef HAVE_USB_CHARGING_ENABLE | 83 | #ifdef HAVE_USB_CHARGING_ENABLE |
90 | void usb_charging_maxcurrent_change(int maxcurrent) | 84 | void usb_charging_maxcurrent_change(int maxcurrent) |
91 | { | 85 | { |
92 | int vbus_limit; | 86 | axp_set_charge_current(maxcurrent); |
93 | int charge_current; | ||
94 | |||
95 | /* Note that the charge current setting is a maximum: it will be | ||
96 | * reduced dynamically by the AXP192 so the combined load is less | ||
97 | * than the set VBUS current limit. */ | ||
98 | if(maxcurrent <= 100) { | ||
99 | vbus_limit = AXP_VBUS_LIMIT_500mA; | ||
100 | charge_current = 100; | ||
101 | } else { | ||
102 | vbus_limit = AXP_VBUS_LIMIT_500mA; | ||
103 | charge_current = 550; | ||
104 | } | ||
105 | |||
106 | axp_set_vbus_limit(vbus_limit); | ||
107 | axp_set_charge_current(charge_current); | ||
108 | } | 87 | } |
109 | #endif | 88 | #endif |
110 | 89 | ||
@@ -120,25 +99,20 @@ void power_off(void) | |||
120 | 99 | ||
121 | bool charging_state(void) | 100 | bool charging_state(void) |
122 | { | 101 | { |
123 | return axp_is_charging(); | 102 | return axp_battery_status() == AXP_BATT_CHARGING; |
124 | } | ||
125 | |||
126 | unsigned int power_input_status(void) | ||
127 | { | ||
128 | return axp_power_input_status(); | ||
129 | } | 103 | } |
130 | 104 | ||
131 | int _battery_voltage(void) | 105 | int _battery_voltage(void) |
132 | { | 106 | { |
133 | return axp_read_adc(AXP_ADC_BATTERY_VOLTAGE); | 107 | return axp_adc_read(ADC_BATTERY_VOLTAGE); |
134 | } | 108 | } |
135 | 109 | ||
136 | #if CONFIG_BATTERY_MEASURE & CURRENT_MEASURE | 110 | #if CONFIG_BATTERY_MEASURE & CURRENT_MEASURE |
137 | int _battery_current(void) | 111 | int _battery_current(void) |
138 | { | 112 | { |
139 | if(charging_state()) | 113 | if(charging_state()) |
140 | return axp_read_adc(AXP_ADC_CHARGE_CURRENT); | 114 | return axp_adc_read(ADC_CHARGE_CURRENT); |
141 | else | 115 | else |
142 | return axp_read_adc(AXP_ADC_DISCHARGE_CURRENT); | 116 | return axp_adc_read(ADC_DISCHARGE_CURRENT); |
143 | } | 117 | } |
144 | #endif | 118 | #endif |
diff --git a/firmware/target/mips/ingenic_x1000/shanlingq1/button-shanlingq1.c b/firmware/target/mips/ingenic_x1000/shanlingq1/button-shanlingq1.c index 1976dde793..13b0cdd078 100644 --- a/firmware/target/mips/ingenic_x1000/shanlingq1/button-shanlingq1.c +++ b/firmware/target/mips/ingenic_x1000/shanlingq1/button-shanlingq1.c | |||
@@ -23,7 +23,7 @@ | |||
23 | #include "button.h" | 23 | #include "button.h" |
24 | #include "touchscreen.h" | 24 | #include "touchscreen.h" |
25 | #include "ft6x06.h" | 25 | #include "ft6x06.h" |
26 | #include "axp192.h" | 26 | #include "axp-pmu.h" |
27 | #include "kernel.h" | 27 | #include "kernel.h" |
28 | #include "backlight.h" | 28 | #include "backlight.h" |
29 | #include "powermgmt.h" | 29 | #include "powermgmt.h" |
@@ -57,7 +57,7 @@ static void hp_detect_init(void) | |||
57 | { | 57 | { |
58 | /* TODO: replace this copy paste cruft with an API in axp-pmu */ | 58 | /* TODO: replace this copy paste cruft with an API in axp-pmu */ |
59 | static struct timeout tmo; | 59 | static struct timeout tmo; |
60 | static const uint8_t gpio_reg = AXP_REG_GPIOLEVEL1; | 60 | static const uint8_t gpio_reg = AXP192_REG_GPIOSTATE1; |
61 | static i2c_descriptor desc = { | 61 | static i2c_descriptor desc = { |
62 | .slave_addr = AXP_PMU_ADDR, | 62 | .slave_addr = AXP_PMU_ADDR, |
63 | .bus_cond = I2C_START | I2C_STOP, | 63 | .bus_cond = I2C_START | I2C_STOP, |
@@ -72,10 +72,10 @@ static void hp_detect_init(void) | |||
72 | }; | 72 | }; |
73 | 73 | ||
74 | /* Headphone detect is wired to AXP192 GPIO: set it to input state */ | 74 | /* Headphone detect is wired to AXP192 GPIO: set it to input state */ |
75 | axp_set_gpio_function(1, AXP_GPIO_INPUT); | 75 | i2c_reg_write1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP192_REG_GPIO1FUNCTION, 0x01); |
76 | 76 | ||
77 | /* Get an initial reading before startup */ | 77 | /* Get an initial reading before startup */ |
78 | int r = axp_read(gpio_reg); | 78 | int r = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, gpio_reg); |
79 | if(r >= 0) | 79 | if(r >= 0) |
80 | hp_detect_reg = r; | 80 | hp_detect_reg = r; |
81 | 81 | ||
diff --git a/firmware/target/mips/ingenic_x1000/shanlingq1/power-shanlingq1.c b/firmware/target/mips/ingenic_x1000/shanlingq1/power-shanlingq1.c index 86ee84c37a..75f8031dd9 100644 --- a/firmware/target/mips/ingenic_x1000/shanlingq1/power-shanlingq1.c +++ b/firmware/target/mips/ingenic_x1000/shanlingq1/power-shanlingq1.c | |||
@@ -22,7 +22,7 @@ | |||
22 | #include "power.h" | 22 | #include "power.h" |
23 | #include "adc.h" | 23 | #include "adc.h" |
24 | #include "system.h" | 24 | #include "system.h" |
25 | #include "axp192.h" | 25 | #include "axp-pmu.h" |
26 | #ifdef HAVE_CW2015 | 26 | #ifdef HAVE_CW2015 |
27 | # include "cw2015.h" | 27 | # include "cw2015.h" |
28 | #endif | 28 | #endif |
@@ -73,34 +73,24 @@ const unsigned short percent_to_volt_charge[11] = | |||
73 | void power_init(void) | 73 | void power_init(void) |
74 | { | 74 | { |
75 | i2c_x1000_set_freq(AXP_PMU_BUS, I2C_FREQ_400K); | 75 | i2c_x1000_set_freq(AXP_PMU_BUS, I2C_FREQ_400K); |
76 | axp_init(); | ||
76 | #ifdef HAVE_CW2015 | 77 | #ifdef HAVE_CW2015 |
77 | cw2015_init(); | 78 | cw2015_init(); |
78 | #endif | 79 | #endif |
79 | 80 | ||
80 | /* Set DCDC2 to 1.2 V to match OF settings. */ | 81 | /* Change supply voltage from the default of 1250 mV to 1200 mV, |
81 | axp_set_supply_voltage(AXP_SUPPLY_DCDC2, 1200); | 82 | * this matches the original firmware's settings. Didn't observe |
82 | 83 | * any obviously bad behavior at 1250 mV, but better to be safe. */ | |
83 | /* Power on required supplies */ | 84 | axp_supply_set_voltage(AXP_SUPPLY_DCDC2, 1200); |
84 | axp_set_enabled_supplies( | 85 | |
85 | (1 << AXP_SUPPLY_DCDC1) | /* SD bus (3.3 V) */ | 86 | /* For now, just turn everything on... definitely the touchscreen |
86 | (1 << AXP_SUPPLY_DCDC2) | /* LCD (1.2 V) */ | 87 | * is powered by one of the outputs */ |
87 | (1 << AXP_SUPPLY_DCDC3) | /* CPU (1.8 V) */ | 88 | i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR, |
88 | (1 << AXP_SUPPLY_LDO2) | /* Touchscreen (3.3 V) */ | 89 | AXP_REG_PWROUTPUTCTRL1, 0, 0x05, NULL); |
89 | (1 << AXP_SUPPLY_LDO3)); /* USB analog (2.5 V) */ | 90 | i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR, |
90 | 91 | AXP_REG_PWROUTPUTCTRL2, 0, 0x0f, NULL); | |
91 | /* Enable required ADCs */ | 92 | i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR, |
92 | axp_set_enabled_adcs( | 93 | AXP_REG_DCDCWORKINGMODE, 0, 0xc0, NULL); |
93 | (1 << AXP_ADC_BATTERY_VOLTAGE) | | ||
94 | (1 << AXP_ADC_CHARGE_CURRENT) | | ||
95 | (1 << AXP_ADC_DISCHARGE_CURRENT) | | ||
96 | (1 << AXP_ADC_VBUS_VOLTAGE) | | ||
97 | (1 << AXP_ADC_VBUS_CURRENT) | | ||
98 | (1 << AXP_ADC_INTERNAL_TEMP) | | ||
99 | (1 << AXP_ADC_APS_VOLTAGE)); | ||
100 | |||
101 | /* Configure USB charging */ | ||
102 | axp_set_vhold_level(4400); | ||
103 | usb_charging_maxcurrent_change(100); | ||
104 | 94 | ||
105 | /* Delay to give power output time to stabilize */ | 95 | /* Delay to give power output time to stabilize */ |
106 | mdelay(20); | 96 | mdelay(20); |
@@ -109,22 +99,7 @@ void power_init(void) | |||
109 | #ifdef HAVE_USB_CHARGING_ENABLE | 99 | #ifdef HAVE_USB_CHARGING_ENABLE |
110 | void usb_charging_maxcurrent_change(int maxcurrent) | 100 | void usb_charging_maxcurrent_change(int maxcurrent) |
111 | { | 101 | { |
112 | int vbus_limit; | 102 | axp_set_charge_current(maxcurrent); |
113 | int charge_current; | ||
114 | |||
115 | /* Note that the charge current setting is a maximum: it will be | ||
116 | * reduced dynamically by the AXP192 so the combined load is less | ||
117 | * than the set VBUS current limit. */ | ||
118 | if(maxcurrent <= 100) { | ||
119 | vbus_limit = AXP_VBUS_LIMIT_500mA; | ||
120 | charge_current = 100; | ||
121 | } else { | ||
122 | vbus_limit = AXP_VBUS_LIMIT_500mA; | ||
123 | charge_current = 550; | ||
124 | } | ||
125 | |||
126 | axp_set_vbus_limit(vbus_limit); | ||
127 | axp_set_charge_current(charge_current); | ||
128 | } | 103 | } |
129 | #endif | 104 | #endif |
130 | 105 | ||
@@ -136,28 +111,23 @@ void power_off(void) | |||
136 | 111 | ||
137 | bool charging_state(void) | 112 | bool charging_state(void) |
138 | { | 113 | { |
139 | return axp_is_charging(); | 114 | return axp_battery_status() == AXP_BATT_CHARGING; |
140 | } | ||
141 | |||
142 | unsigned int power_input_status(void) | ||
143 | { | ||
144 | return axp_power_input_status(); | ||
145 | } | 115 | } |
146 | 116 | ||
147 | int _battery_voltage(void) | 117 | int _battery_voltage(void) |
148 | { | 118 | { |
149 | /* CW2015 can also read battery voltage, but the AXP consistently | 119 | /* CW2015 can also read battery voltage, but the AXP consistently |
150 | * reads ~20-30 mV higher so I suspect it's the "real" voltage. */ | 120 | * reads ~20-30 mV higher so I suspect it's the "real" voltage. */ |
151 | return axp_read_adc(AXP_ADC_BATTERY_VOLTAGE); | 121 | return axp_adc_read(ADC_BATTERY_VOLTAGE); |
152 | } | 122 | } |
153 | 123 | ||
154 | #if CONFIG_BATTERY_MEASURE & CURRENT_MEASURE | 124 | #if CONFIG_BATTERY_MEASURE & CURRENT_MEASURE |
155 | int _battery_current(void) | 125 | int _battery_current(void) |
156 | { | 126 | { |
157 | if(charging_state()) | 127 | if(charging_state()) |
158 | return axp_read_adc(AXP_ADC_CHARGE_CURRENT); | 128 | return axp_adc_read(ADC_CHARGE_CURRENT); |
159 | else | 129 | else |
160 | return axp_read_adc(AXP_ADC_DISCHARGE_CURRENT); | 130 | return axp_adc_read(ADC_DISCHARGE_CURRENT); |
161 | } | 131 | } |
162 | #endif | 132 | #endif |
163 | 133 | ||