diff options
-rw-r--r-- | firmware/SOURCES | 4 | ||||
-rw-r--r-- | firmware/drivers/axp-pmu.c | 670 | ||||
-rw-r--r-- | firmware/drivers/axp173.c | 476 | ||||
-rw-r--r-- | firmware/export/axp-pmu.h | 151 | ||||
-rw-r--r-- | firmware/export/axp173.h | 118 | ||||
-rw-r--r-- | firmware/export/config/fiiom3k.h | 2 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/debug-x1000.c | 8 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c | 10 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/fiiom3k/i2c-target.h | 4 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c | 34 |
10 files changed, 853 insertions, 624 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES index 052847a6a6..0d93439ff8 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES | |||
@@ -1929,8 +1929,8 @@ drivers/touchpad.c | |||
1929 | drivers/i2c-async.c | 1929 | drivers/i2c-async.c |
1930 | #endif | 1930 | #endif |
1931 | 1931 | ||
1932 | #ifdef HAVE_AXP173 | 1932 | #ifdef HAVE_AXP_PMU |
1933 | drivers/axp173.c | 1933 | drivers/axp-pmu.c |
1934 | #endif | 1934 | #endif |
1935 | 1935 | ||
1936 | /* firmware/kernel section */ | 1936 | /* firmware/kernel section */ |
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/axp173.c b/firmware/drivers/axp173.c deleted file mode 100644 index 0c9b9c81a4..0000000000 --- a/firmware/drivers/axp173.c +++ /dev/null | |||
@@ -1,476 +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 "axp173.h" | ||
23 | #include "power.h" | ||
24 | #include "i2c-async.h" | ||
25 | |||
26 | /* Headers for the debug menu */ | ||
27 | #ifndef BOOTLOADER | ||
28 | # include "action.h" | ||
29 | # include "list.h" | ||
30 | # include <stdio.h> | ||
31 | #endif | ||
32 | |||
33 | static const struct axp173_adc_info { | ||
34 | uint8_t reg; | ||
35 | uint8_t en_reg; | ||
36 | uint8_t en_bit; | ||
37 | } axp173_adc_info[NUM_ADC_CHANNELS] = { | ||
38 | {0x56, AXP173_REG_ADCENABLE1, 5}, /* ACIN_VOLTAGE */ | ||
39 | {0x58, AXP173_REG_ADCENABLE1, 4}, /* ACIN_CURRENT */ | ||
40 | {0x5a, AXP173_REG_ADCENABLE1, 3}, /* VBUS_VOLTAGE */ | ||
41 | {0x5c, AXP173_REG_ADCENABLE1, 2}, /* VBUS_CURRENT */ | ||
42 | {0x5e, AXP173_REG_ADCENABLE2, 7}, /* INTERNAL_TEMP */ | ||
43 | {0x62, AXP173_REG_ADCENABLE1, 1}, /* TS_INPUT */ | ||
44 | {0x78, AXP173_REG_ADCENABLE1, 7}, /* BATTERY_VOLTAGE */ | ||
45 | {0x7a, AXP173_REG_ADCENABLE1, 6}, /* CHARGE_CURRENT */ | ||
46 | {0x7c, AXP173_REG_ADCENABLE1, 6}, /* DISCHARGE_CURRENT */ | ||
47 | {0x7e, AXP173_REG_ADCENABLE1, 1}, /* APS_VOLTAGE */ | ||
48 | {0x70, 0xff, 0}, /* BATTERY_POWER */ | ||
49 | }; | ||
50 | |||
51 | static struct axp173 { | ||
52 | int adc_enable; | ||
53 | int chargecurrent_setting; | ||
54 | } axp173; | ||
55 | |||
56 | static void axp173_init_enabled_adcs(void) | ||
57 | { | ||
58 | axp173.adc_enable = 0; | ||
59 | |||
60 | /* Read enabled ADCs from the hardware */ | ||
61 | uint8_t regs[2]; | ||
62 | int rc = i2c_reg_read(AXP173_BUS, AXP173_ADDR, | ||
63 | AXP173_REG_ADCENABLE1, 2, ®s[0]); | ||
64 | if(rc != I2C_STATUS_OK) | ||
65 | return; | ||
66 | |||
67 | /* Parse registers to set ADC enable bits */ | ||
68 | const struct axp173_adc_info* info = axp173_adc_info; | ||
69 | for(int i = 0; i < NUM_ADC_CHANNELS; ++i) { | ||
70 | if(info[i].en_reg == 0xff) | ||
71 | continue; | ||
72 | |||
73 | if(regs[info[i].en_reg - AXP173_REG_ADCENABLE1] & info[i].en_bit) | ||
74 | axp173.adc_enable |= 1 << i; | ||
75 | } | ||
76 | |||
77 | /* Handle battery power ADC */ | ||
78 | if((axp173.adc_enable & (1 << ADC_BATTERY_VOLTAGE)) && | ||
79 | (axp173.adc_enable & (1 << ADC_DISCHARGE_CURRENT))) { | ||
80 | axp173.adc_enable |= (1 << ADC_BATTERY_POWER); | ||
81 | } | ||
82 | } | ||
83 | |||
84 | void axp173_init(void) | ||
85 | { | ||
86 | axp173_init_enabled_adcs(); | ||
87 | |||
88 | /* We need discharge current ADC to reliably poll for a full battery */ | ||
89 | int bits = axp173.adc_enable; | ||
90 | bits |= (1 << ADC_DISCHARGE_CURRENT); | ||
91 | axp173_adc_set_enabled(bits); | ||
92 | |||
93 | /* Read the maximum charging current */ | ||
94 | int value = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, AXP173_REG_CHARGECONTROL1); | ||
95 | axp173.chargecurrent_setting = (value < 0) ? -1 : value; | ||
96 | } | ||
97 | |||
98 | /* TODO: this can STILL indicate some false positives! */ | ||
99 | int axp173_battery_status(void) | ||
100 | { | ||
101 | int r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, AXP173_REG_POWERSTATUS); | ||
102 | if(r >= 0) { | ||
103 | /* Charging bit indicates we're currently charging */ | ||
104 | if((r & 0x04) != 0) | ||
105 | return AXP173_BATT_CHARGING; | ||
106 | |||
107 | /* Not plugged in means we're discharging */ | ||
108 | if((r & 0xf0) == 0) | ||
109 | return AXP173_BATT_DISCHARGING; | ||
110 | } else { | ||
111 | /* Report discharging if we can't find out power status */ | ||
112 | return AXP173_BATT_DISCHARGING; | ||
113 | } | ||
114 | |||
115 | /* If the battery is full and not in use, the charging bit will be 0, | ||
116 | * there will be an external power source, AND the discharge current | ||
117 | * will be zero. Seems to rule out all false positives. */ | ||
118 | int d = axp173_adc_read_raw(ADC_DISCHARGE_CURRENT); | ||
119 | if(d == 0) | ||
120 | return AXP173_BATT_FULL; | ||
121 | |||
122 | return AXP173_BATT_DISCHARGING; | ||
123 | } | ||
124 | |||
125 | int axp173_input_status(void) | ||
126 | { | ||
127 | #ifdef HAVE_BATTERY_SWITCH | ||
128 | int input_status = 0; | ||
129 | #else | ||
130 | int input_status = AXP173_INPUT_BATTERY; | ||
131 | #endif | ||
132 | |||
133 | int r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, AXP173_REG_POWERSTATUS); | ||
134 | if(r < 0) | ||
135 | return input_status; | ||
136 | |||
137 | /* Check for AC input */ | ||
138 | if(r & 0x80) | ||
139 | input_status |= AXP173_INPUT_AC; | ||
140 | |||
141 | /* Only report USB if ACIN and VBUS are not shorted */ | ||
142 | if((r & 0x20) != 0 && (r & 0x02) == 0) | ||
143 | input_status |= AXP173_INPUT_USB; | ||
144 | |||
145 | #ifdef HAVE_BATTERY_SWITCH | ||
146 | /* Check for battery presence if target defines it as removable */ | ||
147 | r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, AXP173_REG_CHARGESTATUS); | ||
148 | if(r >= 0 && (r & 0x20) != 0) | ||
149 | input_status |= AXP173_INPUT_BATTERY; | ||
150 | #endif | ||
151 | |||
152 | return input_status; | ||
153 | } | ||
154 | |||
155 | int axp173_adc_read(int adc) | ||
156 | { | ||
157 | int value = axp173_adc_read_raw(adc); | ||
158 | if(value == INT_MIN) | ||
159 | return INT_MIN; | ||
160 | |||
161 | return axp173_adc_conv_raw(adc, value); | ||
162 | } | ||
163 | |||
164 | int axp173_adc_read_raw(int adc) | ||
165 | { | ||
166 | /* Don't give a reading if the ADC is not enabled */ | ||
167 | if((axp173.adc_enable & (1 << adc)) == 0) | ||
168 | return INT_MIN; | ||
169 | |||
170 | /* Read the ADC */ | ||
171 | uint8_t buf[3]; | ||
172 | int count = (adc == ADC_BATTERY_POWER) ? 3 : 2; | ||
173 | uint8_t reg = axp173_adc_info[adc].reg; | ||
174 | int rc = i2c_reg_read(AXP173_BUS, AXP173_ADDR, reg, count, &buf[0]); | ||
175 | if(rc != I2C_STATUS_OK) | ||
176 | return INT_MIN; | ||
177 | |||
178 | /* Parse the value */ | ||
179 | if(adc == ADC_BATTERY_POWER) | ||
180 | return (buf[0] << 16) | (buf[1] << 8) | buf[2]; | ||
181 | else if(adc == ADC_CHARGE_CURRENT || adc == ADC_DISCHARGE_CURRENT) | ||
182 | return (buf[0] << 5) | (buf[1] & 0x1f); | ||
183 | else | ||
184 | return (buf[0] << 4) | (buf[1] & 0xf); | ||
185 | } | ||
186 | |||
187 | int axp173_adc_conv_raw(int adc, int value) | ||
188 | { | ||
189 | switch(adc) { | ||
190 | case ADC_ACIN_VOLTAGE: | ||
191 | case ADC_VBUS_VOLTAGE: | ||
192 | /* 0 mV ... 6.9615 mV, step 1.7 mV */ | ||
193 | return value * 17 / 10; | ||
194 | case ADC_ACIN_CURRENT: | ||
195 | /* 0 mA ... 2.5594 A, step 0.625 mA */ | ||
196 | return value * 5 / 8; | ||
197 | case ADC_VBUS_CURRENT: | ||
198 | /* 0 mA ... 1.5356 A, step 0.375 mA */ | ||
199 | return value * 3 / 8; | ||
200 | case ADC_INTERNAL_TEMP: | ||
201 | /* -144.7 C ... 264.8 C, step 0.1 C */ | ||
202 | return value - 1447; | ||
203 | case ADC_TS_INPUT: | ||
204 | /* 0 mV ... 3.276 V, step 0.8 mV */ | ||
205 | return value * 4 / 5; | ||
206 | case ADC_BATTERY_VOLTAGE: | ||
207 | /* 0 mV ... 4.5045 V, step 1.1 mV */ | ||
208 | return value * 11 / 10; | ||
209 | case ADC_CHARGE_CURRENT: | ||
210 | case ADC_DISCHARGE_CURRENT: | ||
211 | /* 0 mA to 4.095 A, step 0.5 mA */ | ||
212 | return value / 2; | ||
213 | case ADC_APS_VOLTAGE: | ||
214 | /* 0 mV to 5.733 V, step 1.4 mV */ | ||
215 | return value * 7 / 5; | ||
216 | case ADC_BATTERY_POWER: | ||
217 | /* 0 uW to 23.6404 W, step 0.55 uW */ | ||
218 | return value * 11 / 20; | ||
219 | default: | ||
220 | /* Shouldn't happen */ | ||
221 | return INT_MIN; | ||
222 | } | ||
223 | } | ||
224 | |||
225 | int axp173_adc_get_enabled(void) | ||
226 | { | ||
227 | return axp173.adc_enable; | ||
228 | } | ||
229 | |||
230 | void axp173_adc_set_enabled(int adc_bits) | ||
231 | { | ||
232 | /* Ignore no-op */ | ||
233 | if(adc_bits == axp173.adc_enable) | ||
234 | return; | ||
235 | |||
236 | /* Compute the new register values */ | ||
237 | const struct axp173_adc_info* info = axp173_adc_info; | ||
238 | uint8_t regs[2] = {0, 0}; | ||
239 | for(int i = 0; i < NUM_ADC_CHANNELS; ++i) { | ||
240 | if(info[i].en_reg == 0xff) | ||
241 | continue; | ||
242 | |||
243 | if(adc_bits & (1 << i)) | ||
244 | regs[info[i].en_reg - 0x82] |= 1 << info[i].en_bit; | ||
245 | } | ||
246 | |||
247 | /* These ADCs share an enable bit */ | ||
248 | if(adc_bits & ((1 << ADC_CHARGE_CURRENT)|(1 << ADC_DISCHARGE_CURRENT))) { | ||
249 | adc_bits |= (1 << ADC_CHARGE_CURRENT); | ||
250 | adc_bits |= (1 << ADC_DISCHARGE_CURRENT); | ||
251 | } | ||
252 | |||
253 | /* Enable required bits for battery power ADC */ | ||
254 | if(adc_bits & (1 << ADC_BATTERY_POWER)) { | ||
255 | regs[0] |= 1 << info[ADC_DISCHARGE_CURRENT].en_bit; | ||
256 | regs[0] |= 1 << info[ADC_BATTERY_VOLTAGE].en_bit; | ||
257 | } | ||
258 | |||
259 | /* Update the configuration */ | ||
260 | i2c_reg_write(AXP173_BUS, AXP173_ADDR, AXP173_REG_ADCENABLE1, 2, ®s[0]); | ||
261 | axp173.adc_enable = adc_bits; | ||
262 | } | ||
263 | |||
264 | int axp173_adc_get_rate(void) | ||
265 | { | ||
266 | int r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, AXP173_REG_ADCSAMPLERATE); | ||
267 | if(r < 0) | ||
268 | return AXP173_ADC_RATE_100HZ; /* an arbitrary value */ | ||
269 | |||
270 | return (r >> 6) & 3; | ||
271 | } | ||
272 | |||
273 | void axp173_adc_set_rate(int rate) | ||
274 | { | ||
275 | i2c_reg_modify1(AXP173_BUS, AXP173_ADDR, AXP173_REG_ADCSAMPLERATE, | ||
276 | 0xc0, (rate & 3) << 6, NULL); | ||
277 | } | ||
278 | |||
279 | static uint32_t axp173_cc_parse(const uint8_t* buf) | ||
280 | { | ||
281 | return ((uint32_t)buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; | ||
282 | } | ||
283 | |||
284 | void axp173_cc_read(uint32_t* charge, uint32_t* discharge) | ||
285 | { | ||
286 | uint8_t buf[8]; | ||
287 | int rc = i2c_reg_read(AXP173_BUS, AXP173_ADDR, | ||
288 | AXP173_REG_COULOMBCOUNTERBASE, 8, &buf[0]); | ||
289 | if(rc != I2C_STATUS_OK) { | ||
290 | if(charge) | ||
291 | *charge = 0; | ||
292 | if(discharge) | ||
293 | *discharge = 0; | ||
294 | return; | ||
295 | } | ||
296 | |||
297 | if(charge) | ||
298 | *charge = axp173_cc_parse(&buf[0]); | ||
299 | if(discharge) | ||
300 | *discharge = axp173_cc_parse(&buf[4]); | ||
301 | } | ||
302 | |||
303 | void axp173_cc_clear(void) | ||
304 | { | ||
305 | i2c_reg_setbit1(AXP173_BUS, AXP173_ADDR, | ||
306 | AXP173_REG_COULOMBCOUNTERCTRL, 5, 1, NULL); | ||
307 | } | ||
308 | |||
309 | void axp173_cc_enable(bool en) | ||
310 | { | ||
311 | i2c_reg_setbit1(AXP173_BUS, AXP173_ADDR, | ||
312 | AXP173_REG_COULOMBCOUNTERCTRL, 7, en ? 1 : 0, NULL); | ||
313 | } | ||
314 | |||
315 | static const int chargecurrent_tbl[] = { | ||
316 | 100, 190, 280, 360, | ||
317 | 450, 550, 630, 700, | ||
318 | 780, 880, 960, 1000, | ||
319 | 1080, 1160, 1240, 1320, | ||
320 | }; | ||
321 | |||
322 | static const int chargecurrent_tblsz = sizeof(chargecurrent_tbl)/sizeof(int); | ||
323 | |||
324 | void axp173_set_charge_current(int maxcurrent) | ||
325 | { | ||
326 | /* Find the charge current just higher than maxcurrent */ | ||
327 | int value = 0; | ||
328 | while(value < chargecurrent_tblsz && | ||
329 | chargecurrent_tbl[value] <= maxcurrent) | ||
330 | ++value; | ||
331 | |||
332 | /* Select the next lower current, the greatest current <= maxcurrent */ | ||
333 | if(value >= chargecurrent_tblsz) | ||
334 | value = chargecurrent_tblsz - 1; | ||
335 | else if(value > 0) | ||
336 | --value; | ||
337 | |||
338 | /* Don't issue i2c write if desired setting is already in use */ | ||
339 | if(value == axp173.chargecurrent_setting) | ||
340 | return; | ||
341 | |||
342 | /* Update register */ | ||
343 | i2c_reg_modify1(AXP173_BUS, AXP173_ADDR, | ||
344 | AXP173_REG_CHARGECONTROL1, 0x0f, value, NULL); | ||
345 | axp173.chargecurrent_setting = value; | ||
346 | } | ||
347 | |||
348 | int axp173_get_charge_current(void) | ||
349 | { | ||
350 | if(axp173.chargecurrent_setting < 0) | ||
351 | return chargecurrent_tbl[0]; | ||
352 | else | ||
353 | return chargecurrent_tbl[axp173.chargecurrent_setting]; | ||
354 | } | ||
355 | |||
356 | #ifndef BOOTLOADER | ||
357 | #define AXP173_DEBUG_BATTERY_STATUS 0 | ||
358 | #define AXP173_DEBUG_INPUT_STATUS 1 | ||
359 | #define AXP173_DEBUG_CHARGE_CURRENT 2 | ||
360 | #define AXP173_DEBUG_ADC_RATE 3 | ||
361 | #define AXP173_DEBUG_FIRST_ADC 4 | ||
362 | #define AXP173_DEBUG_ENTRIES (AXP173_DEBUG_FIRST_ADC + NUM_ADC_CHANNELS) | ||
363 | |||
364 | static int axp173_debug_menu_cb(int action, struct gui_synclist* lists) | ||
365 | { | ||
366 | (void)lists; | ||
367 | |||
368 | if(action == ACTION_NONE) | ||
369 | action = ACTION_REDRAW; | ||
370 | |||
371 | return action; | ||
372 | } | ||
373 | |||
374 | static const char* axp173_debug_menu_get_name(int item, void* data, | ||
375 | char* buf, size_t buflen) | ||
376 | { | ||
377 | (void)data; | ||
378 | |||
379 | static const char* const adc_names[] = { | ||
380 | "V_acin", "I_acin", "V_vbus", "I_vbus", "T_int", | ||
381 | "V_ts", "V_batt", "I_chrg", "I_dchg", "V_aps", "P_batt" | ||
382 | }; | ||
383 | |||
384 | static const char* const adc_units[] = { | ||
385 | "mV", "mA", "mV", "mA", "C", "mV", "mV", "mA", "mA", "mV", "uW", | ||
386 | }; | ||
387 | |||
388 | int adc = item - AXP173_DEBUG_FIRST_ADC; | ||
389 | if(item >= AXP173_DEBUG_FIRST_ADC && adc < NUM_ADC_CHANNELS) { | ||
390 | int raw_value = axp173_adc_read_raw(adc); | ||
391 | if(raw_value == INT_MIN) { | ||
392 | snprintf(buf, buflen, "%s: [Disabled]", adc_names[adc]); | ||
393 | return buf; | ||
394 | } | ||
395 | |||
396 | int value = axp173_adc_conv_raw(adc, raw_value); | ||
397 | if(adc == ADC_INTERNAL_TEMP) { | ||
398 | snprintf(buf, buflen, "%s: %d.%d %s", adc_names[adc], | ||
399 | value/10, value%10, adc_units[adc]); | ||
400 | } else { | ||
401 | snprintf(buf, buflen, "%s: %d %s", adc_names[adc], | ||
402 | value, adc_units[adc]); | ||
403 | } | ||
404 | |||
405 | return buf; | ||
406 | } | ||
407 | |||
408 | switch(item) { | ||
409 | case AXP173_DEBUG_BATTERY_STATUS: { | ||
410 | switch(axp173_battery_status()) { | ||
411 | case AXP173_BATT_FULL: | ||
412 | return "Battery: Full"; | ||
413 | case AXP173_BATT_CHARGING: | ||
414 | return "Battery: Charging"; | ||
415 | case AXP173_BATT_DISCHARGING: | ||
416 | return "Battery: Discharging"; | ||
417 | default: | ||
418 | return "Battery: Unknown"; | ||
419 | } | ||
420 | } break; | ||
421 | |||
422 | case AXP173_DEBUG_INPUT_STATUS: { | ||
423 | int s = axp173_input_status(); | ||
424 | const char* ac = (s & AXP173_INPUT_AC) ? " AC" : ""; | ||
425 | const char* usb = (s & AXP173_INPUT_USB) ? " USB" : ""; | ||
426 | const char* batt = (s & AXP173_INPUT_BATTERY) ? " Battery" : ""; | ||
427 | snprintf(buf, buflen, "Inputs:%s%s%s", ac, usb, batt); | ||
428 | return buf; | ||
429 | } break; | ||
430 | |||
431 | case AXP173_DEBUG_CHARGE_CURRENT: { | ||
432 | int current = axp173_get_charge_current(); | ||
433 | snprintf(buf, buflen, "Max charge current: %d mA", current); | ||
434 | return buf; | ||
435 | } break; | ||
436 | |||
437 | case AXP173_DEBUG_ADC_RATE: { | ||
438 | int rate = 25 << axp173_adc_get_rate(); | ||
439 | snprintf(buf, buflen, "ADC sample rate: %d Hz", rate); | ||
440 | return buf; | ||
441 | } break; | ||
442 | |||
443 | default: | ||
444 | return "---"; | ||
445 | } | ||
446 | } | ||
447 | |||
448 | bool axp173_debug_menu(void) | ||
449 | { | ||
450 | struct simplelist_info info; | ||
451 | simplelist_info_init(&info, "AXP173 debug", AXP173_DEBUG_ENTRIES, NULL); | ||
452 | info.action_callback = axp173_debug_menu_cb; | ||
453 | info.get_name = axp173_debug_menu_get_name; | ||
454 | return simplelist_show_list(&info); | ||
455 | } | ||
456 | #endif /* !BOOTLOADER */ | ||
457 | |||
458 | /* This is basically the only valid implementation, so define it here */ | ||
459 | unsigned int power_input_status(void) | ||
460 | { | ||
461 | unsigned int state = 0; | ||
462 | int input_status = axp173_input_status(); | ||
463 | |||
464 | if(input_status & AXP173_INPUT_AC) | ||
465 | state |= POWER_INPUT_MAIN_CHARGER; | ||
466 | |||
467 | if(input_status & AXP173_INPUT_USB) | ||
468 | state |= POWER_INPUT_USB_CHARGER; | ||
469 | |||
470 | #ifdef HAVE_BATTERY_SWITCH | ||
471 | if(input_status & AXP173_INPUT_BATTERY) | ||
472 | state |= POWER_INPUT_BATTERY; | ||
473 | #endif | ||
474 | |||
475 | return state; | ||
476 | } | ||
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/axp173.h b/firmware/export/axp173.h deleted file mode 100644 index 34f0c2ec19..0000000000 --- a/firmware/export/axp173.h +++ /dev/null | |||
@@ -1,118 +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 __AXP173_H__ | ||
23 | #define __AXP173_H__ | ||
24 | |||
25 | #include <stdbool.h> | ||
26 | #include <stdint.h> | ||
27 | |||
28 | /* ADC channels */ | ||
29 | #define ADC_ACIN_VOLTAGE 0 | ||
30 | #define ADC_ACIN_CURRENT 1 | ||
31 | #define ADC_VBUS_VOLTAGE 2 | ||
32 | #define ADC_VBUS_CURRENT 3 | ||
33 | #define ADC_INTERNAL_TEMP 4 | ||
34 | #define ADC_TS_INPUT 5 | ||
35 | #define ADC_BATTERY_VOLTAGE 6 | ||
36 | #define ADC_CHARGE_CURRENT 7 | ||
37 | #define ADC_DISCHARGE_CURRENT 8 | ||
38 | #define ADC_APS_VOLTAGE 9 | ||
39 | #define ADC_BATTERY_POWER 10 | ||
40 | #define NUM_ADC_CHANNELS 11 | ||
41 | |||
42 | /* ADC sampling rates */ | ||
43 | #define AXP173_ADC_RATE_25HZ 0 | ||
44 | #define AXP173_ADC_RATE_50HZ 1 | ||
45 | #define AXP173_ADC_RATE_100HZ 2 | ||
46 | #define AXP173_ADC_RATE_200HZ 3 | ||
47 | |||
48 | /* Return values of axp173_battery_status() */ | ||
49 | #define AXP173_BATT_DISCHARGING 0 | ||
50 | #define AXP173_BATT_CHARGING 1 | ||
51 | #define AXP173_BATT_FULL 2 | ||
52 | |||
53 | /* Bits returned by axp173_input_status() */ | ||
54 | #define AXP173_INPUT_AC (1 << 0) | ||
55 | #define AXP173_INPUT_USB (1 << 1) | ||
56 | #define AXP173_INPUT_BATTERY (1 << 2) | ||
57 | #define AXP173_INPUT_EXTERNAL (AXP173_INPUT_AC|AXP173_INPUT_USB) | ||
58 | |||
59 | /* Registers -- common to AXP173 and AXP192 (incomplete listing) */ | ||
60 | #define AXP173_REG_POWERSTATUS 0x00 | ||
61 | #define AXP173_REG_CHARGESTATUS 0x01 | ||
62 | #define AXP173_REG_PWROUTPUTCTRL 0x12 | ||
63 | #define AXP173_REG_SHUTDOWNLEDCTRL 0x32 | ||
64 | #define AXP173_REG_CHARGECONTROL1 0x33 | ||
65 | #define AXP173_REG_DCDCWORKINGMODE 0x80 | ||
66 | #define AXP173_REG_ADCENABLE1 0x82 | ||
67 | #define AXP173_REG_ADCENABLE2 0x83 | ||
68 | #define AXP173_REG_ADCSAMPLERATE 0x84 | ||
69 | #define AXP173_REG_COULOMBCOUNTERBASE 0xb0 | ||
70 | #define AXP173_REG_COULOMBCOUNTERCTRL 0xb8 | ||
71 | |||
72 | /* AXP192-only registers (incomplete listing) */ | ||
73 | #define AXP192_REG_GPIO0FUNCTION 0x90 | ||
74 | #define AXP192_REG_GPIO1FUNCTION 0x92 | ||
75 | #define AXP192_REG_GPIO2FUNCTION 0x93 | ||
76 | #define AXP192_REG_GPIOSTATE1 0x94 | ||
77 | |||
78 | /* Must be called from power_init() to initialize the driver state */ | ||
79 | extern void axp173_init(void); | ||
80 | |||
81 | /* Basic battery and power supply status */ | ||
82 | extern int axp173_battery_status(void); | ||
83 | extern int axp173_input_status(void); | ||
84 | |||
85 | /* ADC access -- ADCs which are not enabled will return INT_MIN if read. | ||
86 | * The output of axp173_adc_read() is normalized to appropriate units: | ||
87 | * | ||
88 | * - for voltages, the scale is millivolts | ||
89 | * - for currents, the scale is milliamps | ||
90 | * - for temperatures, the scale is tenths of a degree Celsius | ||
91 | * - for power, the scale is microwatts | ||
92 | * | ||
93 | * See the comment in axp173_adc_conv_raw() for raw value precision/scale. | ||
94 | */ | ||
95 | extern int axp173_adc_read(int adc); | ||
96 | extern int axp173_adc_read_raw(int adc); | ||
97 | extern int axp173_adc_conv_raw(int adc, int value); | ||
98 | extern int axp173_adc_get_enabled(void); | ||
99 | extern void axp173_adc_set_enabled(int adc_bits); | ||
100 | extern int axp173_adc_get_rate(void); | ||
101 | extern void axp173_adc_set_rate(int rate); | ||
102 | |||
103 | /* - axp173_cc_read() reads the coulomb counters | ||
104 | * - axp173_cc_clear() resets both counters to zero | ||
105 | * - axp173_cc_enable() will stop/start the counters running | ||
106 | */ | ||
107 | extern void axp173_cc_read(uint32_t* charge, uint32_t* discharge); | ||
108 | extern void axp173_cc_clear(void); | ||
109 | extern void axp173_cc_enable(bool en); | ||
110 | |||
111 | /* Set/get maximum charging current in milliamps */ | ||
112 | extern void axp173_set_charge_current(int maxcurrent); | ||
113 | extern int axp173_get_charge_current(void); | ||
114 | |||
115 | /* Debug menu */ | ||
116 | extern bool axp173_debug_menu(void); | ||
117 | |||
118 | #endif /* __AXP173_H__ */ | ||
diff --git a/firmware/export/config/fiiom3k.h b/firmware/export/config/fiiom3k.h index 2c212b031d..a28efd43a5 100644 --- a/firmware/export/config/fiiom3k.h +++ b/firmware/export/config/fiiom3k.h | |||
@@ -90,7 +90,7 @@ | |||
90 | #define HAVE_SW_POWEROFF | 90 | #define HAVE_SW_POWEROFF |
91 | 91 | ||
92 | #ifndef SIMULATOR | 92 | #ifndef SIMULATOR |
93 | #define HAVE_AXP173 | 93 | #define HAVE_AXP_PMU 192 |
94 | #define HAVE_POWEROFF_WHILE_CHARGING | 94 | #define HAVE_POWEROFF_WHILE_CHARGING |
95 | #endif | 95 | #endif |
96 | 96 | ||
diff --git a/firmware/target/mips/ingenic_x1000/debug-x1000.c b/firmware/target/mips/ingenic_x1000/debug-x1000.c index 74bbcd77a6..fe469b1a72 100644 --- a/firmware/target/mips/ingenic_x1000/debug-x1000.c +++ b/firmware/target/mips/ingenic_x1000/debug-x1000.c | |||
@@ -148,7 +148,9 @@ static bool dbg_cpuidle(void) | |||
148 | 148 | ||
149 | #ifdef FIIO_M3K | 149 | #ifdef FIIO_M3K |
150 | extern bool dbg_fiiom3k_touchpad(void); | 150 | extern bool dbg_fiiom3k_touchpad(void); |
151 | extern bool axp173_debug_menu(void); | 151 | #endif |
152 | #ifdef HAVE_AXP_PMU | ||
153 | extern bool axp_debug_menu(void); | ||
152 | #endif | 154 | #endif |
153 | 155 | ||
154 | /* Menu definition */ | 156 | /* Menu definition */ |
@@ -164,7 +166,9 @@ static const struct { | |||
164 | {"Audio", &dbg_audio}, | 166 | {"Audio", &dbg_audio}, |
165 | #ifdef FIIO_M3K | 167 | #ifdef FIIO_M3K |
166 | {"Touchpad", &dbg_fiiom3k_touchpad}, | 168 | {"Touchpad", &dbg_fiiom3k_touchpad}, |
167 | {"Power stats", &axp173_debug_menu}, | 169 | #endif |
170 | #ifdef HAVE_AXP_PMU | ||
171 | {"Power stats", &axp_debug_menu}, | ||
168 | #endif | 172 | #endif |
169 | }; | 173 | }; |
170 | 174 | ||
diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c b/firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c index 85ccc5cf65..efc652c84f 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 "axp173.h" | 27 | #include "axp-pmu.h" |
28 | #include "gpio-x1000.h" | 28 | #include "gpio-x1000.h" |
29 | #include "i2c-x1000.h" | 29 | #include "i2c-x1000.h" |
30 | #include <string.h> | 30 | #include <string.h> |
@@ -418,7 +418,7 @@ static uint8_t hp_detect_reg = 0x00; | |||
418 | static int hp_detect_tmo_cb(struct timeout* tmo) | 418 | static int hp_detect_tmo_cb(struct timeout* tmo) |
419 | { | 419 | { |
420 | i2c_descriptor* d = (i2c_descriptor*)tmo->data; | 420 | i2c_descriptor* d = (i2c_descriptor*)tmo->data; |
421 | i2c_async_queue(AXP173_BUS, TIMEOUT_NOBLOCK, I2C_Q_ADD, 0, d); | 421 | i2c_async_queue(AXP_PMU_BUS, TIMEOUT_NOBLOCK, I2C_Q_ADD, 0, d); |
422 | return HPD_POLL_TIME; | 422 | return HPD_POLL_TIME; |
423 | } | 423 | } |
424 | 424 | ||
@@ -427,7 +427,7 @@ static void hp_detect_init(void) | |||
427 | static struct timeout tmo; | 427 | static struct timeout tmo; |
428 | static const uint8_t gpio_reg = AXP192_REG_GPIOSTATE1; | 428 | static const uint8_t gpio_reg = AXP192_REG_GPIOSTATE1; |
429 | static i2c_descriptor desc = { | 429 | static i2c_descriptor desc = { |
430 | .slave_addr = AXP173_ADDR, | 430 | .slave_addr = AXP_PMU_ADDR, |
431 | .bus_cond = I2C_START | I2C_STOP, | 431 | .bus_cond = I2C_START | I2C_STOP, |
432 | .tran_mode = I2C_READ, | 432 | .tran_mode = I2C_READ, |
433 | .buffer[0] = (void*)&gpio_reg, | 433 | .buffer[0] = (void*)&gpio_reg, |
@@ -440,10 +440,10 @@ static void hp_detect_init(void) | |||
440 | }; | 440 | }; |
441 | 441 | ||
442 | /* Headphone detect is wired to AXP192 GPIO: set it to input state */ | 442 | /* Headphone detect is wired to AXP192 GPIO: set it to input state */ |
443 | i2c_reg_write1(AXP173_BUS, AXP173_ADDR, AXP192_REG_GPIO2FUNCTION, 0x01); | 443 | i2c_reg_write1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP192_REG_GPIO2FUNCTION, 0x01); |
444 | 444 | ||
445 | /* Get an initial reading before startup */ | 445 | /* Get an initial reading before startup */ |
446 | int r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, gpio_reg); | 446 | int r = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, gpio_reg); |
447 | if(r >= 0) | 447 | if(r >= 0) |
448 | hp_detect_reg = r; | 448 | hp_detect_reg = r; |
449 | 449 | ||
diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/i2c-target.h b/firmware/target/mips/ingenic_x1000/fiiom3k/i2c-target.h index a389d2af42..1e8ebfbb15 100644 --- a/firmware/target/mips/ingenic_x1000/fiiom3k/i2c-target.h +++ b/firmware/target/mips/ingenic_x1000/fiiom3k/i2c-target.h | |||
@@ -31,7 +31,7 @@ | |||
31 | #define FT6x06_BUS 1 | 31 | #define FT6x06_BUS 1 |
32 | #define FT6x06_ADDR 0x38 | 32 | #define FT6x06_ADDR 0x38 |
33 | 33 | ||
34 | #define AXP173_BUS 2 | 34 | #define AXP_PMU_BUS 2 |
35 | #define AXP173_ADDR 0x34 | 35 | #define AXP_PMU_ADDR 0x34 |
36 | 36 | ||
37 | #endif /* __I2C_TARGET_H__ */ | 37 | #endif /* __I2C_TARGET_H__ */ |
diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c b/firmware/target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c index c346d16890..a7f6165980 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 "axp173.h" | 29 | #include "axp-pmu.h" |
30 | #include "i2c-x1000.h" | 30 | #include "i2c-x1000.h" |
31 | #include "gpio-x1000.h" | 31 | #include "gpio-x1000.h" |
32 | 32 | ||
@@ -53,32 +53,32 @@ const unsigned short percent_to_volt_charge[11] = | |||
53 | 3485, 3780, 3836, 3857, 3890, 3930, 3986, 4062, 4158, 4185, 4196 | 53 | 3485, 3780, 3836, 3857, 3890, 3930, 3986, 4062, 4158, 4185, 4196 |
54 | }; | 54 | }; |
55 | 55 | ||
56 | #define AXP173_IRQ_PORT GPIO_B | 56 | #define AXP_IRQ_PORT GPIO_B |
57 | #define AXP173_IRQ_PIN (1 << 10) | 57 | #define AXP_IRQ_PIN (1 << 10) |
58 | 58 | ||
59 | void power_init(void) | 59 | void power_init(void) |
60 | { | 60 | { |
61 | /* Initialize driver */ | 61 | /* Initialize driver */ |
62 | i2c_x1000_set_freq(2, I2C_FREQ_400K); | 62 | i2c_x1000_set_freq(2, I2C_FREQ_400K); |
63 | axp173_init(); | 63 | axp_init(); |
64 | 64 | ||
65 | /* Set lowest sample rate */ | 65 | /* Set lowest sample rate */ |
66 | axp173_adc_set_rate(AXP173_ADC_RATE_25HZ); | 66 | axp_adc_set_rate(AXP_ADC_RATE_25HZ); |
67 | 67 | ||
68 | /* Ensure battery voltage ADC is enabled */ | 68 | /* Ensure battery voltage ADC is enabled */ |
69 | int bits = axp173_adc_get_enabled(); | 69 | int bits = axp_adc_get_enabled(); |
70 | bits |= (1 << ADC_BATTERY_VOLTAGE); | 70 | bits |= (1 << ADC_BATTERY_VOLTAGE); |
71 | axp173_adc_set_enabled(bits); | 71 | axp_adc_set_enabled(bits); |
72 | 72 | ||
73 | /* Turn on all power outputs */ | 73 | /* Turn on all power outputs */ |
74 | i2c_reg_modify1(AXP173_BUS, AXP173_ADDR, | 74 | i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR, |
75 | AXP173_REG_PWROUTPUTCTRL, 0, 0x5f, NULL); | 75 | AXP_REG_PWROUTPUTCTRL2, 0, 0x5f, NULL); |
76 | i2c_reg_modify1(AXP173_BUS, AXP173_ADDR, | 76 | i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR, |
77 | AXP173_REG_DCDCWORKINGMODE, 0, 0xc0, NULL); | 77 | AXP_REG_DCDCWORKINGMODE, 0, 0xc0, NULL); |
78 | 78 | ||
79 | /* Set the default charging current. This is the same as the | 79 | /* Set the default charging current. This is the same as the |
80 | * OF's setting, although it's not strictly within the USB spec. */ | 80 | * OF's setting, although it's not strictly within the USB spec. */ |
81 | axp173_set_charge_current(780); | 81 | axp_set_charge_current(780); |
82 | 82 | ||
83 | /* Short delay to give power outputs time to stabilize */ | 83 | /* Short delay to give power outputs time to stabilize */ |
84 | mdelay(5); | 84 | mdelay(5); |
@@ -87,7 +87,7 @@ void power_init(void) | |||
87 | #ifdef HAVE_USB_CHARGING_ENABLE | 87 | #ifdef HAVE_USB_CHARGING_ENABLE |
88 | void usb_charging_maxcurrent_change(int maxcurrent) | 88 | void usb_charging_maxcurrent_change(int maxcurrent) |
89 | { | 89 | { |
90 | axp173_set_charge_current(maxcurrent); | 90 | axp_set_charge_current(maxcurrent); |
91 | } | 91 | } |
92 | #endif | 92 | #endif |
93 | 93 | ||
@@ -97,18 +97,16 @@ void adc_init(void) | |||
97 | 97 | ||
98 | void power_off(void) | 98 | void power_off(void) |
99 | { | 99 | { |
100 | /* Set the shutdown bit */ | 100 | axp_power_off(); |
101 | i2c_reg_setbit1(AXP173_BUS, AXP173_ADDR, | ||
102 | AXP173_REG_SHUTDOWNLEDCTRL, 7, 1, NULL); | ||
103 | while(1); | 101 | while(1); |
104 | } | 102 | } |
105 | 103 | ||
106 | bool charging_state(void) | 104 | bool charging_state(void) |
107 | { | 105 | { |
108 | return axp173_battery_status() == AXP173_BATT_CHARGING; | 106 | return axp_battery_status() == AXP_BATT_CHARGING; |
109 | } | 107 | } |
110 | 108 | ||
111 | int _battery_voltage(void) | 109 | int _battery_voltage(void) |
112 | { | 110 | { |
113 | return axp173_adc_read(ADC_BATTERY_VOLTAGE); | 111 | return axp_adc_read(ADC_BATTERY_VOLTAGE); |
114 | } | 112 | } |