diff --git a/drivers/power/axp818.c b/drivers/power/axp818.c index 2b732705db4..1ac93e789df 100644 --- a/drivers/power/axp818.c +++ b/drivers/power/axp818.c @@ -311,3 +311,225 @@ int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) /* not reached */ return 0; } + +// battery/charger related functions + +int axp_is_charging(bool* charging) +{ + int ret; + u8 cs; + + ret = pmic_bus_read(AXP_CHARGER_STATUS, &cs); + if (ret) + return ret; + + *charging = (cs & AXP_CHARGER_STATUS_CHARGING); + return 0; +} + +int axp_is_vbus_present(bool* vbus) +{ + int ret; + u8 ps; + + ret = pmic_bus_read(AXP_POWER_STATUS, &ps); + if (ret) + return ret; + + *vbus = (ps & AXP_POWER_STATUS_VBUS_PRESENT) && + (ps & AXP_POWER_STATUS_VBUS_VALID); + return 0; +} + +int axp_is_battery_present(bool* vbus) +{ + int ret; + u8 cs; + + ret = pmic_bus_read(AXP_CHARGER_STATUS, &cs); + if (ret) + return ret; + + *vbus = (cs & AXP_CHARGER_STATUS_BAT_PRESENT_VALID) && + (cs & AXP_CHARGER_STATUS_BAT_PRESENT); + return 0; +} + +int axp_clear_startup_reason(void) +{ + return pmic_bus_write(AXP_POWER_UP_DOWN_REASON, 0xff); +} + +static int axp_read_adc(u8 addr_msb, u8 addr_lsb, u32* raw) +{ + u8 val; + int ret; + + ret = pmic_bus_read(addr_lsb, &val); + if (ret) + return ret; + + *raw = val & 0xf; + + ret = pmic_bus_read(addr_msb, &val); + if (ret) + return ret; + + *raw |= (u32)val << 4; + return 0; +} + +int axp_get_battery_voltage(int* uV) +{ + u32 raw; + int ret; + + ret = axp_read_adc(AXP_AD_BAT_VOLTAGE_MSB8, AXP_AD_BAT_VOLTAGE_LSB4, + &raw); + if (ret) + return ret; + + *uV = (raw) * 1100; + return 0; +} + +int axp_get_battery_current(int* uA) +{ + u32 raw; + int ret; + bool charging; + + ret = axp_is_charging(&charging); + if (ret) + return ret; + + if (charging) + ret = axp_read_adc(AXP_AD_BAT_CHG_CURRENT_MSB8, + AXP_AD_BAT_CHG_CURRENT_LSB4, &raw); + else + ret = axp_read_adc(AXP_AD_BAT_DIS_CURRENT_MSB8, + AXP_AD_BAT_DIS_CURRENT_LSB4, &raw); + if (ret) + return ret; + + *uA = raw * 1000; + return 0; +} + +int axp_battery_get_capacity(int* capacity) +{ + int ret; + u8 val; + + ret = pmic_bus_read(AXP_BATTERY_CAPACITY, &val); + if (ret) + return ret; + + if (!(val & 0x80)) + return -EINVAL; + + *capacity = val & 0x7f; + return 0; +} + +struct { + u8 vbus_i; + int mA; +} vbus_currents[] = { + { AXP_CHARGER_CTRL3_VBUS_I_100, 100 }, + { AXP_CHARGER_CTRL3_VBUS_I_500, 500 }, + { AXP_CHARGER_CTRL3_VBUS_I_900, 900 }, + { AXP_CHARGER_CTRL3_VBUS_I_1500, 1500 }, + { AXP_CHARGER_CTRL3_VBUS_I_2000, 2000 }, + { AXP_CHARGER_CTRL3_VBUS_I_2500, 2500 }, + { AXP_CHARGER_CTRL3_VBUS_I_3000, 3000 }, + { AXP_CHARGER_CTRL3_VBUS_I_3500, 3500 }, + { AXP_CHARGER_CTRL3_VBUS_I_4000, 4000 }, +}; + +int axp_usb_get_max_current(int* mA) +{ + int i, ret; + u8 val; + + ret = pmic_bus_read(AXP_CHARGER_CTRL3, &val); + if (ret) + return ret; + + val &= AXP_CHARGER_CTRL3_VBUS_I_MASK; + + *mA = 4000; + for (i = 0; i < ARRAY_SIZE(vbus_currents); i++) { + if (vbus_currents[i].vbus_i == val) { + *mA = vbus_currents[i].mA; + break; + } + } + + return 0; +} + +int axp_usb_set_max_current(int mA) +{ + int i, ret; + u8 val; + + ret = pmic_bus_read(AXP_CHARGER_CTRL3, &val); + if (ret) + return ret; + + val &= ~AXP_CHARGER_CTRL3_VBUS_I_MASK; + + for (i = ARRAY_SIZE(vbus_currents) - 1; i >= 0; i--) { + if (vbus_currents[i].mA <= mA || i == 0) { + val |= vbus_currents[i].vbus_i; + break; + } + } + + return pmic_bus_write(AXP_CHARGER_CTRL3, val); +} + +int axp_led_set_charger_controlled(void) +{ + int ret; + u8 val; + + ret = pmic_bus_read(AXP_CHGLED, &val); + if (ret) + return ret; + + val |= AXP_CHGLED_CTRL_CHARGER; + + return pmic_bus_write(AXP_CHGLED, val); +} + +int axp_led_set(bool on) +{ + int ret; + u8 val; + + ret = pmic_bus_read(AXP_CHGLED, &val); + if (ret) + return ret; + + val &= ~(AXP_CHGLED_CTRL_CHARGER | AXP_CHGLED_SETUP_MASK); + val |= on ? AXP_CHGLED_SETUP_ON : AXP_CHGLED_SETUP_OFF; + + return pmic_bus_write(AXP_CHGLED, val); +} + +int axp_pok_set_quick(void) +{ + int ret; + u8 val; + + ret = pmic_bus_read(AXP_POK, &val); + if (ret) + return ret; + + val &= ~(AXP_POK_ON_MASK | AXP_POK_OFF_MASK); + val |= AXP_POK_ON_128MS | AXP_POK_OFF_4S; + + return pmic_bus_write(AXP_POK, val); +} diff --git a/include/axp818.h b/include/axp818.h index 18e69c605b7..226729ead19 100644 --- a/include/axp818.h +++ b/include/axp818.h @@ -60,6 +60,10 @@ /* For axp_gpio.c */ #define AXP_POWER_STATUS 0x00 #define AXP_POWER_STATUS_VBUS_PRESENT (1 << 5) +#define AXP_POWER_STATUS_VBUS_VALID (1 << 4) +#define AXP_POWER_STATUS_VBAT_GT_3_5V (1 << 3) +#define AXP_POWER_STATUS_VBUS_STARTUP (1 << 0) + #define AXP_VBUS_IPSOUT 0x30 #define AXP_VBUS_IPSOUT_DRIVEBUS (1 << 2) #define AXP_MISC_CTRL 0x8f @@ -74,5 +78,73 @@ #define AXP_GPIO_STATE 0x94 #define AXP_GPIO_STATE_OFFSET 0 +#define AXP_CHARGER_STATUS 0x01 +#define AXP_CHARGER_STATUS_BAT_PRESENT (1 << 5) +#define AXP_CHARGER_STATUS_BAT_PRESENT_VALID (1 << 4) +#define AXP_CHARGER_STATUS_CHARGING (1 << 6) +#define AXP_CHARGER_STATUS_OVER_TEMP (1 << 7) + +#define AXP_POWER_UP_DOWN_REASON 0x02 +#define AXP_POWER_UP_REASON_POK (1 << 0) +#define AXP_POWER_UP_REASON_CHARGER (1 << 1) +#define AXP_POWER_UP_REASON_GLOBAL_RESET (1 << 3) +#define AXP_POWER_UP_REASON_COLD_RESET (1 << 4) +#define AXP_POWER_DOWN_REASON_UVLO (1 << 5) +#define AXP_POWER_DOWN_REASON_COLD_OFF (1 << 6) +#define AXP_POWER_DOWN_REASON_POK_OR (1 << 7) + +#define AXP_CHGLED 0x32 +#define AXP_CHGLED_CTRL_CHARGER (1 << 3) +#define AXP_CHGLED_SETUP_MASK (0x3 << 4) +#define AXP_CHGLED_SETUP_OFF (0 << 4) +#define AXP_CHGLED_SETUP_BLINK_FAST (1 << 4) +#define AXP_CHGLED_SETUP_BLINK_SLOW (2 << 4) +#define AXP_CHGLED_SETUP_ON (3 << 4) + +#define AXP_POK 0x36 +#define AXP_POK_ON_MASK (3 << 6) +#define AXP_POK_ON_128MS (0 << 6) +#define AXP_POK_ON_1S (1 << 6) +#define AXP_POK_ON_2S (2 << 6) +#define AXP_POK_ON_3S (3 << 6) +#define AXP_POK_OFF_MASK (3 << 0) +#define AXP_POK_OFF_4S (0 << 6) +#define AXP_POK_OFF_6S (1 << 6) +#define AXP_POK_OFF_8S (2 << 6) +#define AXP_POK_OFF_10S (3 << 6) + +#define AXP_CHARGER_CTRL3 0x35 +#define AXP_CHARGER_CTRL3_VBUS_I_MASK 0xf0 +#define AXP_CHARGER_CTRL3_VBUS_I_100 0x00 +#define AXP_CHARGER_CTRL3_VBUS_I_500 0x10 +#define AXP_CHARGER_CTRL3_VBUS_I_900 0x20 +#define AXP_CHARGER_CTRL3_VBUS_I_1500 0x30 +#define AXP_CHARGER_CTRL3_VBUS_I_2000 0x40 +#define AXP_CHARGER_CTRL3_VBUS_I_2500 0x50 +#define AXP_CHARGER_CTRL3_VBUS_I_3000 0x60 +#define AXP_CHARGER_CTRL3_VBUS_I_3500 0x70 +#define AXP_CHARGER_CTRL3_VBUS_I_4000 0x80 + +#define AXP_AD_BAT_VOLTAGE_MSB8 0x78 +#define AXP_AD_BAT_VOLTAGE_LSB4 0x79 +#define AXP_AD_BAT_CHG_CURRENT_MSB8 0x7a +#define AXP_AD_BAT_CHG_CURRENT_LSB4 0x7b +#define AXP_AD_BAT_DIS_CURRENT_MSB8 0x7c +#define AXP_AD_BAT_DIS_CURRENT_LSB4 0x7d + +#define AXP_BATTERY_CAPACITY 0xb9 + int axp_gpio0_enable_ldo_set_voltage(u32 mV); +int axp_is_charging(bool* charging); +int axp_is_vbus_present(bool* vbus); +int axp_is_battery_present(bool* vbus); +int axp_clear_startup_reason(void); +int axp_get_battery_voltage(int* uV); +int axp_get_battery_current(int* uA); +int axp_battery_get_capacity(int* capacity); +int axp_usb_get_max_current(int* mA); +int axp_usb_set_max_current(int mA); +int axp_led_set_charger_controlled(void); +int axp_led_set(bool on); +int axp_pok_set_quick(void);