mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-10-13 10:07:38 -04:00
Check for the ES9018K2M dac in the bootloader for hw1/hw2 devices. Assume that all devices newer than hw2 have ES9018K2M DAC unconditionally. All devices will now report the correct hw revision in the debug menu under Device Data. Add devicedata.version field, current version 0. Rename device_data.lcd_version to device_data.hw_rev. hw2 devices with older bootloaders which ID as hw1 are special- cased to keep using hwvol on them. They should still upgrade though. Change-Id: If0fd5ce3bc6e85e511047721ec18e42fb89312e7
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.hw_rev;
|
|
# 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.hw_rev;
|
|
# 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;
|
|
}
|