mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-11-09 13:12:37 -05:00
Support hw4 units with AXP2101 PMU
Bootloader successfully compiles and loads onto device.
The LCD appears to be identical to hw3 units.
Scroll wheel and buttons work
Audio output works, including volume.
HP/LO detect works
Rockbox build is generic
GPIO gating logic seems to be working as intended now.
- Added new GPIO definitions - some significant overlaps with pins
from previous hardware revisions...
- Added some GPIO definitions for older players we didn't know about
- Add register definitions for AXP2101 from datasheet
(these are very different from AXP192!)
- Add AXP2101 regulator definitions, need to support multiple step
sizes per regulator.
- Verify AXP2101 voltage set multi-range logic
- Verify AXP2101 voltage get multi-range logic
- Make AXP2101 its own driver
- AXP2101 driver should be "minimally viable", though I think
there is some extra functionality that could be implemented.
- Disabling the coulomb counter stuff - we could maybe make
the E-Gauge work for the same purpose, but it only appears to
be used on the debug screen at the moment so it doesn't seem
like it's worth the effort.
- Found new button GPIOs
- Found error in my GPIO setting logic, blue light works now!
- Set LDO/DCDC output voltages to OF's settings, as far as
I can tell.
- Determined we probably want TCS1421_CFG1:0 to be 0x00,
for UFP behavior
- Tested this rb build with both old and new bootloaders on hw1.5,
hw2, hw4 in as many configurations as I can think of, works across
the board.
- Bootloader can install itself on hw4, so nand chip isn't novel
- Uninstallation file can be made by patcher script, works on hw4
- Installation file can be made by patcher script, works on hw4
- Added HW4 to rbutil, manual
Change-Id: I5b75782273e81c2c6f2b9c79501c8b7cbf88391f
581 lines
16 KiB
C
581 lines
16 KiB
C
/***************************************************************************
|
|
* __________ __ ___.
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
* \/ \/ \/ \/ \/
|
|
* $Id$
|
|
*
|
|
* Copyright (C) 2021 Aidan MacDonald
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
* KIND, either express or implied.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include "axp-pmu.h"
|
|
#include "power.h"
|
|
#include "system.h"
|
|
#include "i2c-async.h"
|
|
#include <string.h>
|
|
|
|
#if defined(HAVE_AXP2101_ADDON)
|
|
# include "axp-2101.h"
|
|
# include "devicedata.h"
|
|
#endif
|
|
|
|
/* Headers for the debug menu */
|
|
#ifndef BOOTLOADER
|
|
# include "action.h"
|
|
# include "list.h"
|
|
# include <stdio.h>
|
|
#endif
|
|
|
|
struct axp_adc_info {
|
|
uint8_t reg;
|
|
uint8_t en_reg;
|
|
uint8_t en_bit;
|
|
int8_t num;
|
|
int8_t den;
|
|
};
|
|
|
|
struct axp_supply_info {
|
|
uint8_t volt_reg;
|
|
uint8_t volt_reg_mask;
|
|
uint8_t en_reg;
|
|
uint8_t en_bit;
|
|
int min_mV;
|
|
int max_mV;
|
|
int step_mV;
|
|
};
|
|
|
|
static const struct axp_adc_info axp_adc_info[NUM_ADC_CHANNELS] = {
|
|
[ADC_ACIN_VOLTAGE] = {0x56, AXP_REG_ADCENABLE1, 1 << 5, 17, 10},
|
|
[ADC_ACIN_CURRENT] = {0x58, AXP_REG_ADCENABLE1, 1 << 4, 5, 8},
|
|
[ADC_VBUS_VOLTAGE] = {0x5a, AXP_REG_ADCENABLE1, 1 << 3, 17, 10},
|
|
[ADC_VBUS_CURRENT] = {0x5c, AXP_REG_ADCENABLE1, 1 << 2, 3, 8},
|
|
[ADC_INTERNAL_TEMP] = {0x5e, AXP_REG_ADCENABLE2, 1 << 7, 0, 0},
|
|
[ADC_TS_INPUT] = {0x62, AXP_REG_ADCENABLE1, 1 << 1, 4, 5},
|
|
[ADC_BATTERY_VOLTAGE] = {0x78, AXP_REG_ADCENABLE1, 1 << 7, 11, 10},
|
|
[ADC_CHARGE_CURRENT] = {0x7a, AXP_REG_ADCENABLE1, 1 << 6, 1, 2},
|
|
[ADC_DISCHARGE_CURRENT] = {0x7c, AXP_REG_ADCENABLE1, 1 << 6, 1, 2},
|
|
[ADC_APS_VOLTAGE] = {0x7e, AXP_REG_ADCENABLE1, 1 << 1, 7, 5},
|
|
};
|
|
|
|
static const struct axp_supply_info axp_supply_info[AXP_NUM_SUPPLIES] = {
|
|
#if HAVE_AXP_PMU == 192
|
|
[AXP_SUPPLY_DCDC1] = {
|
|
.volt_reg = 0x26,
|
|
.volt_reg_mask = 0x7f,
|
|
.en_reg = 0x12,
|
|
.en_bit = 0,
|
|
.min_mV = 700,
|
|
.max_mV = 3500,
|
|
.step_mV = 25,
|
|
},
|
|
[AXP_SUPPLY_DCDC2] = {
|
|
.volt_reg = 0x23,
|
|
.volt_reg_mask = 0x3f,
|
|
.en_reg = 0x10,
|
|
.en_bit = 0,
|
|
.min_mV = 700,
|
|
.max_mV = 2275,
|
|
.step_mV = 25,
|
|
},
|
|
[AXP_SUPPLY_DCDC3] = {
|
|
.volt_reg = 0x27,
|
|
.volt_reg_mask = 0x7f,
|
|
.en_reg = 0x12,
|
|
.en_bit = 1,
|
|
.min_mV = 700,
|
|
.max_mV = 3500,
|
|
.step_mV = 25,
|
|
},
|
|
/*
|
|
* NOTE: LDO1 is always on, and we can't query it or change voltages
|
|
*/
|
|
[AXP_SUPPLY_LDO2] = {
|
|
.volt_reg = 0x28,
|
|
.volt_reg_mask = 0xf0,
|
|
.en_reg = 0x12,
|
|
.en_bit = 2,
|
|
.min_mV = 1800,
|
|
.max_mV = 3300,
|
|
.step_mV = 100,
|
|
},
|
|
[AXP_SUPPLY_LDO3] = {
|
|
.volt_reg = 0x28,
|
|
.volt_reg_mask = 0x0f,
|
|
.en_reg = 0x12,
|
|
.en_bit = 3,
|
|
.min_mV = 1800,
|
|
.max_mV = 3300,
|
|
.step_mV = 100,
|
|
},
|
|
[AXP_SUPPLY_LDO_IO0] = {
|
|
.volt_reg = 0x91,
|
|
.volt_reg_mask = 0xf0,
|
|
.en_reg = 0x90,
|
|
.en_bit = 0xff, /* this one requires special handling */
|
|
.min_mV = 1800,
|
|
.max_mV = 3300,
|
|
.step_mV = 100,
|
|
},
|
|
#else
|
|
# error "Untested AXP chip"
|
|
#endif
|
|
};
|
|
|
|
void axp_init(void)
|
|
{
|
|
}
|
|
|
|
void axp_supply_set_voltage(int supply, int voltage)
|
|
{
|
|
const struct axp_supply_info* info = &axp_supply_info[supply];
|
|
if(info->volt_reg == 0 || info->volt_reg_mask == 0)
|
|
return;
|
|
|
|
if(voltage > 0 && info->step_mV != 0) {
|
|
if(voltage < info->min_mV || voltage > info->max_mV)
|
|
return;
|
|
|
|
int regval = (voltage - info->min_mV) / info->step_mV;
|
|
i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR, info->volt_reg,
|
|
info->volt_reg_mask, regval, NULL);
|
|
}
|
|
|
|
if(info->en_bit != 0xff) {
|
|
i2c_reg_setbit1(AXP_PMU_BUS, AXP_PMU_ADDR,
|
|
info->en_reg, info->en_bit,
|
|
voltage > 0 ? 1 : 0, NULL);
|
|
}
|
|
}
|
|
|
|
int axp_supply_get_voltage(int supply)
|
|
{
|
|
const struct axp_supply_info* info = &axp_supply_info[supply];
|
|
if(info->volt_reg == 0)
|
|
return AXP_SUPPLY_NOT_PRESENT;
|
|
|
|
if(info->en_reg != 0) {
|
|
int r = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, info->en_reg);
|
|
if(r < 0)
|
|
return AXP_SUPPLY_DISABLED;
|
|
|
|
#if HAVE_AXP_PMU == 192
|
|
if(supply == AXP_SUPPLY_LDO_IO0) {
|
|
if((r & 7) != 2)
|
|
return AXP_SUPPLY_DISABLED;
|
|
} else
|
|
#endif
|
|
{
|
|
if(r & (1 << info->en_bit) == 0)
|
|
return AXP_SUPPLY_DISABLED;
|
|
}
|
|
}
|
|
|
|
/* Hack, avoid undefined shift below. Can be useful too... */
|
|
if(info->volt_reg_mask == 0)
|
|
return info->min_mV;
|
|
|
|
int r = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, info->volt_reg);
|
|
if(r < 0)
|
|
return 0;
|
|
|
|
int bit = find_first_set_bit(info->volt_reg_mask);
|
|
int val = (r & info->volt_reg_mask) >> bit;
|
|
return info->min_mV + (val * info->step_mV);
|
|
}
|
|
|
|
/* TODO: this can STILL indicate some false positives! */
|
|
int axp_battery_status(void)
|
|
{
|
|
int r = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP_REG_POWERSTATUS);
|
|
if(r >= 0) {
|
|
/* Charging bit indicates we're currently charging */
|
|
if((r & 0x04) != 0)
|
|
return AXP_BATT_CHARGING;
|
|
|
|
/* Not plugged in means we're discharging */
|
|
if((r & 0xf0) == 0)
|
|
return AXP_BATT_DISCHARGING;
|
|
} else {
|
|
/* Report discharging if we can't find out power status */
|
|
return AXP_BATT_DISCHARGING;
|
|
}
|
|
|
|
/* If the battery is full and not in use, the charging bit will be 0,
|
|
* there will be an external power source, AND the discharge current
|
|
* will be zero. Seems to rule out all false positives. */
|
|
int d = axp_adc_read_raw(ADC_DISCHARGE_CURRENT);
|
|
if(d == 0)
|
|
return AXP_BATT_FULL;
|
|
|
|
return AXP_BATT_DISCHARGING;
|
|
}
|
|
|
|
int axp_input_status(void)
|
|
{
|
|
#ifdef HAVE_BATTERY_SWITCH
|
|
int input_status = 0;
|
|
#else
|
|
int input_status = AXP_INPUT_BATTERY;
|
|
#endif
|
|
|
|
int r = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP_REG_POWERSTATUS);
|
|
if(r < 0)
|
|
return input_status;
|
|
|
|
/* Check for AC input */
|
|
if(r & 0x80)
|
|
input_status |= AXP_INPUT_AC;
|
|
|
|
/* Only report USB if ACIN and VBUS are not shorted */
|
|
if((r & 0x20) != 0 && (r & 0x02) == 0)
|
|
input_status |= AXP_INPUT_USB;
|
|
|
|
#ifdef HAVE_BATTERY_SWITCH
|
|
/* Check for battery presence if target defines it as removable */
|
|
r = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP_REG_CHARGESTATUS);
|
|
if(r >= 0 && (r & 0x20) != 0)
|
|
input_status |= AXP_INPUT_BATTERY;
|
|
#endif
|
|
|
|
return input_status;
|
|
}
|
|
|
|
int axp_adc_read(int adc)
|
|
{
|
|
int value = axp_adc_read_raw(adc);
|
|
if(value == INT_MIN)
|
|
return INT_MIN;
|
|
|
|
return axp_adc_conv_raw(adc, value);
|
|
}
|
|
|
|
int axp_adc_read_raw(int adc)
|
|
{
|
|
/* Read the ADC */
|
|
uint8_t buf[2];
|
|
uint8_t reg = axp_adc_info[adc].reg;
|
|
int rc = i2c_reg_read(AXP_PMU_BUS, AXP_PMU_ADDR, reg, 2, &buf[0]);
|
|
if(rc != I2C_STATUS_OK)
|
|
return INT_MIN;
|
|
|
|
/* Parse the value */
|
|
if(adc == ADC_CHARGE_CURRENT || adc == ADC_DISCHARGE_CURRENT)
|
|
return (buf[0] << 5) | (buf[1] & 0x1f);
|
|
else
|
|
return (buf[0] << 4) | (buf[1] & 0xf);
|
|
}
|
|
|
|
int axp_adc_conv_raw(int adc, int value)
|
|
{
|
|
if(adc == ADC_INTERNAL_TEMP)
|
|
return value - 1447;
|
|
else
|
|
return axp_adc_info[adc].num * value / axp_adc_info[adc].den;
|
|
}
|
|
|
|
void axp_adc_set_enabled(int adc_bits)
|
|
{
|
|
uint8_t xfer[3];
|
|
xfer[0] = 0;
|
|
xfer[1] = AXP_REG_ADCENABLE2;
|
|
xfer[2] = 0;
|
|
|
|
/* Compute the new register values */
|
|
const struct axp_adc_info* info = axp_adc_info;
|
|
for(int i = 0; i < NUM_ADC_CHANNELS; ++i) {
|
|
if(!(adc_bits & (1 << i)))
|
|
continue;
|
|
|
|
if(info[i].en_reg == AXP_REG_ADCENABLE1)
|
|
xfer[0] |= info[i].en_bit;
|
|
else
|
|
xfer[2] |= info[i].en_bit;
|
|
}
|
|
|
|
/* Update the configuration */
|
|
i2c_reg_write(AXP_PMU_BUS, AXP_PMU_ADDR, AXP_REG_ADCENABLE1, 3, &xfer[0]);
|
|
}
|
|
|
|
int axp_adc_get_rate(void)
|
|
{
|
|
int r = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP_REG_ADCSAMPLERATE);
|
|
if(r < 0)
|
|
return AXP_ADC_RATE_100HZ; /* an arbitrary value */
|
|
|
|
return (r >> 6) & 3;
|
|
}
|
|
|
|
void axp_adc_set_rate(int rate)
|
|
{
|
|
i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP_REG_ADCSAMPLERATE,
|
|
0xc0, (rate & 3) << 6, NULL);
|
|
}
|
|
|
|
static uint32_t axp_cc_parse(const uint8_t* buf)
|
|
{
|
|
return ((uint32_t)buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
|
|
}
|
|
|
|
void axp_cc_read(uint32_t* charge, uint32_t* discharge)
|
|
{
|
|
uint8_t buf[8];
|
|
int rc = i2c_reg_read(AXP_PMU_BUS, AXP_PMU_ADDR,
|
|
AXP_REG_COULOMBCOUNTERBASE, 8, &buf[0]);
|
|
if(rc != I2C_STATUS_OK) {
|
|
if(charge)
|
|
*charge = 0;
|
|
if(discharge)
|
|
*discharge = 0;
|
|
return;
|
|
}
|
|
|
|
if(charge)
|
|
*charge = axp_cc_parse(&buf[0]);
|
|
if(discharge)
|
|
*discharge = axp_cc_parse(&buf[4]);
|
|
}
|
|
|
|
void axp_cc_clear(void)
|
|
{
|
|
i2c_reg_setbit1(AXP_PMU_BUS, AXP_PMU_ADDR,
|
|
AXP_REG_COULOMBCOUNTERCTRL, 5, 1, NULL);
|
|
}
|
|
|
|
void axp_cc_enable(bool en)
|
|
{
|
|
i2c_reg_setbit1(AXP_PMU_BUS, AXP_PMU_ADDR,
|
|
AXP_REG_COULOMBCOUNTERCTRL, 7, en ? 1 : 0, NULL);
|
|
}
|
|
|
|
bool axp_cc_is_enabled(void)
|
|
{
|
|
int reg = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR,
|
|
AXP_REG_COULOMBCOUNTERCTRL);
|
|
return reg >= 0 && (reg & 0x40) != 0;
|
|
}
|
|
|
|
static const int chargecurrent_tbl[] = {
|
|
100, 190, 280, 360,
|
|
450, 550, 630, 700,
|
|
780, 880, 960, 1000,
|
|
1080, 1160, 1240, 1320,
|
|
};
|
|
|
|
void axp_set_charge_current(int current_mA)
|
|
{
|
|
/* find greatest charging current not exceeding requested current */
|
|
unsigned int index = 0;
|
|
while(index < ARRAYLEN(chargecurrent_tbl)-1 &&
|
|
chargecurrent_tbl[index+1] <= current_mA)
|
|
++index;
|
|
|
|
i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR,
|
|
AXP_REG_CHARGECONTROL1, 0x0f, index, NULL);
|
|
}
|
|
|
|
int axp_get_charge_current(void)
|
|
{
|
|
int ret = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR,
|
|
AXP_REG_CHARGECONTROL1);
|
|
if(ret < 0)
|
|
ret = 0;
|
|
|
|
return chargecurrent_tbl[ret & 0x0f];
|
|
}
|
|
|
|
void axp_power_off(void)
|
|
{
|
|
/* Set the shutdown bit */
|
|
i2c_reg_setbit1(AXP_PMU_BUS, AXP_PMU_ADDR,
|
|
AXP_REG_SHUTDOWNLEDCTRL, 7, 1, NULL);
|
|
}
|
|
|
|
#ifndef BOOTLOADER
|
|
enum {
|
|
AXP_DEBUG_BATTERY_STATUS,
|
|
AXP_DEBUG_INPUT_STATUS,
|
|
AXP_DEBUG_CHARGE_CURRENT,
|
|
AXP_DEBUG_COULOMB_COUNTERS,
|
|
AXP_DEBUG_ADC_RATE,
|
|
AXP_DEBUG_FIRST_ADC,
|
|
AXP_DEBUG_FIRST_SUPPLY = AXP_DEBUG_FIRST_ADC + NUM_ADC_CHANNELS,
|
|
AXP_DEBUG_NUM_ENTRIES = AXP_DEBUG_FIRST_SUPPLY + AXP_NUM_SUPPLIES,
|
|
};
|
|
|
|
static int axp_debug_menu_cb(int action, struct gui_synclist* lists)
|
|
{
|
|
(void)lists;
|
|
|
|
if(action == ACTION_NONE)
|
|
action = ACTION_REDRAW;
|
|
|
|
return action;
|
|
}
|
|
|
|
static const char* axp_debug_menu_get_name(int item, void* data,
|
|
char* buf, size_t buflen)
|
|
{
|
|
(void)data;
|
|
|
|
static const char* const adc_names[] = {
|
|
"V_acin", "I_acin", "V_vbus", "I_vbus", "T_int",
|
|
"V_ts", "V_batt", "I_chrg", "I_dchg", "V_aps", "P_batt"
|
|
};
|
|
|
|
static const char* const adc_units[] = {
|
|
"mV", "mA", "mV", "mA", "C", "mV", "mV", "mA", "mA", "mV", "uW",
|
|
};
|
|
|
|
static const char* const supply_names[] = {
|
|
"DCDC1", "DCDC2", "DCDC3",
|
|
"LDO1", "LDO2", "LDO3", "LDO_IO0",
|
|
};
|
|
|
|
int adc = item - AXP_DEBUG_FIRST_ADC;
|
|
if(item >= AXP_DEBUG_FIRST_ADC && adc < NUM_ADC_CHANNELS) {
|
|
int raw_value = axp_adc_read_raw(adc);
|
|
if(raw_value == INT_MIN) {
|
|
snprintf(buf, buflen, "%s: [Disabled]", adc_names[adc]);
|
|
return buf;
|
|
}
|
|
|
|
int value = axp_adc_conv_raw(adc, raw_value);
|
|
if(adc == ADC_INTERNAL_TEMP) {
|
|
snprintf(buf, buflen, "%s: %d.%d %s", adc_names[adc],
|
|
value/10, value%10, adc_units[adc]);
|
|
} else {
|
|
snprintf(buf, buflen, "%s: %d %s", adc_names[adc],
|
|
value, adc_units[adc]);
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
int supply = item - AXP_DEBUG_FIRST_SUPPLY;
|
|
if(item >= AXP_DEBUG_FIRST_SUPPLY && supply < AXP_NUM_SUPPLIES) {
|
|
int voltage = axp_supply_get_voltage(supply);
|
|
if(voltage == AXP_SUPPLY_NOT_PRESENT)
|
|
snprintf(buf, buflen, "%s: [Not Present]", supply_names[supply]);
|
|
else if(voltage == AXP_SUPPLY_DISABLED)
|
|
snprintf(buf, buflen, "%s: [Disabled]", supply_names[supply]);
|
|
else
|
|
snprintf(buf, buflen, "%s: %d mV", supply_names[supply], voltage);
|
|
|
|
return buf;
|
|
}
|
|
|
|
switch(item) {
|
|
case AXP_DEBUG_BATTERY_STATUS: {
|
|
switch(axp_battery_status()) {
|
|
case AXP_BATT_FULL:
|
|
return "Battery: Full";
|
|
case AXP_BATT_CHARGING:
|
|
return "Battery: Charging";
|
|
case AXP_BATT_DISCHARGING:
|
|
return "Battery: Discharging";
|
|
default:
|
|
return "Battery: Unknown";
|
|
}
|
|
} break;
|
|
|
|
case AXP_DEBUG_INPUT_STATUS: {
|
|
int s = axp_input_status();
|
|
const char* ac = (s & AXP_INPUT_AC) ? " AC" : "";
|
|
const char* usb = (s & AXP_INPUT_USB) ? " USB" : "";
|
|
const char* batt = (s & AXP_INPUT_BATTERY) ? " Battery" : "";
|
|
snprintf(buf, buflen, "Inputs:%s%s%s", ac, usb, batt);
|
|
return buf;
|
|
} break;
|
|
|
|
case AXP_DEBUG_CHARGE_CURRENT: {
|
|
int current = axp_get_charge_current();
|
|
snprintf(buf, buflen, "Max charge current: %d mA", current);
|
|
return buf;
|
|
} break;
|
|
|
|
case AXP_DEBUG_COULOMB_COUNTERS: {
|
|
uint32_t charge, discharge;
|
|
axp_cc_read(&charge, &discharge);
|
|
|
|
snprintf(buf, buflen, "Coulomb counters: +%lu / -%lu",
|
|
(unsigned long)charge, (unsigned long)discharge);
|
|
return buf;
|
|
} break;
|
|
|
|
case AXP_DEBUG_ADC_RATE: {
|
|
int rate = 25 << axp_adc_get_rate();
|
|
snprintf(buf, buflen, "ADC sample rate: %d Hz", rate);
|
|
return buf;
|
|
} break;
|
|
|
|
default:
|
|
return "---";
|
|
}
|
|
}
|
|
|
|
bool axp_debug_menu(void)
|
|
{
|
|
#if defined(EROS_QN)
|
|
int devicever;
|
|
# if defined(BOOTLOADER)
|
|
devicever = EROSQN_VER;
|
|
# else
|
|
devicever = device_data.lcd_version;
|
|
# endif
|
|
if (devicever >= 4) {
|
|
return axp2101_debug_menu();
|
|
} else
|
|
#endif
|
|
{
|
|
struct simplelist_info info;
|
|
simplelist_info_init(&info, "AXP debug", AXP_DEBUG_NUM_ENTRIES, NULL);
|
|
info.action_callback = axp_debug_menu_cb;
|
|
info.get_name = axp_debug_menu_get_name;
|
|
return simplelist_show_list(&info);
|
|
}
|
|
}
|
|
#endif /* !BOOTLOADER */
|
|
|
|
/* This is basically the only valid implementation, so define it here */
|
|
unsigned int power_input_status(void)
|
|
{
|
|
unsigned int state = 0;
|
|
#if defined(EROS_QN)
|
|
int devicever;
|
|
# if defined(BOOTLOADER)
|
|
devicever = EROSQN_VER;
|
|
# else
|
|
devicever = device_data.lcd_version;
|
|
# endif
|
|
if (devicever >= 4) {
|
|
return axp2101_power_input_status();
|
|
} else
|
|
#endif
|
|
{
|
|
int input_status = axp_input_status();
|
|
|
|
if(input_status & AXP_INPUT_AC)
|
|
state |= POWER_INPUT_MAIN_CHARGER;
|
|
|
|
if(input_status & AXP_INPUT_USB)
|
|
state |= POWER_INPUT_USB_CHARGER;
|
|
|
|
#ifdef HAVE_BATTERY_SWITCH
|
|
if(input_status & AXP_INPUT_BATTERY)
|
|
state |= POWER_INPUT_BATTERY;
|
|
#endif
|
|
}
|
|
|
|
return state;
|
|
}
|