Minor enhancements to axp173 driver
- Added register names to reduce usage of magic numbers - Added function to control max charging current, needed for USB - Corrected comment about axp173, since FiiO M3K has an axp192 Change-Id: I6604ce8d44e5a2ee84061cf042d17ccc4734ac57
This commit is contained in:
parent
f6d3680cb8
commit
088ebb5fac
|
@ -35,21 +35,22 @@ static const struct axp173_adc_info {
|
|||
uint8_t en_reg;
|
||||
uint8_t en_bit;
|
||||
} axp173_adc_info[NUM_ADC_CHANNELS] = {
|
||||
{0x56, 0x82, 5}, /* ACIN_VOLTAGE */
|
||||
{0x58, 0x82, 4}, /* ACIN_CURRENT */
|
||||
{0x5a, 0x82, 3}, /* VBUS_VOLTAGE */
|
||||
{0x5c, 0x82, 2}, /* VBUS_CURRENT */
|
||||
{0x5e, 0x83, 7}, /* INTERNAL_TEMP */
|
||||
{0x62, 0x82, 1}, /* TS_INPUT */
|
||||
{0x78, 0x82, 7}, /* BATTERY_VOLTAGE */
|
||||
{0x7a, 0x82, 6}, /* CHARGE_CURRENT */
|
||||
{0x7c, 0x82, 6}, /* DISCHARGE_CURRENT */
|
||||
{0x7e, 0x82, 1}, /* APS_VOLTAGE */
|
||||
{0x70, 0xff, 0}, /* BATTERY_POWER */
|
||||
{0x56, AXP173_REG_ADCENABLE1, 5}, /* ACIN_VOLTAGE */
|
||||
{0x58, AXP173_REG_ADCENABLE1, 4}, /* ACIN_CURRENT */
|
||||
{0x5a, AXP173_REG_ADCENABLE1, 3}, /* VBUS_VOLTAGE */
|
||||
{0x5c, AXP173_REG_ADCENABLE1, 2}, /* VBUS_CURRENT */
|
||||
{0x5e, AXP173_REG_ADCENABLE2, 7}, /* INTERNAL_TEMP */
|
||||
{0x62, AXP173_REG_ADCENABLE1, 1}, /* TS_INPUT */
|
||||
{0x78, AXP173_REG_ADCENABLE1, 7}, /* BATTERY_VOLTAGE */
|
||||
{0x7a, AXP173_REG_ADCENABLE1, 6}, /* CHARGE_CURRENT */
|
||||
{0x7c, AXP173_REG_ADCENABLE1, 6}, /* DISCHARGE_CURRENT */
|
||||
{0x7e, AXP173_REG_ADCENABLE1, 1}, /* APS_VOLTAGE */
|
||||
{0x70, 0xff, 0}, /* BATTERY_POWER */
|
||||
};
|
||||
|
||||
static struct axp173 {
|
||||
int adc_enable;
|
||||
int chargecurrent_setting;
|
||||
} axp173;
|
||||
|
||||
static void axp173_init_enabled_adcs(void)
|
||||
|
@ -58,7 +59,8 @@ static void axp173_init_enabled_adcs(void)
|
|||
|
||||
/* Read enabled ADCs from the hardware */
|
||||
uint8_t regs[2];
|
||||
int rc = i2c_reg_read(AXP173_BUS, AXP173_ADDR, 0x82, 2, ®s[0]);
|
||||
int rc = i2c_reg_read(AXP173_BUS, AXP173_ADDR,
|
||||
AXP173_REG_ADCENABLE1, 2, ®s[0]);
|
||||
if(rc != I2C_STATUS_OK)
|
||||
return;
|
||||
|
||||
|
@ -68,7 +70,7 @@ static void axp173_init_enabled_adcs(void)
|
|||
if(info[i].en_reg == 0xff)
|
||||
continue;
|
||||
|
||||
if(regs[info[i].en_reg - 0x82] & info[i].en_bit)
|
||||
if(regs[info[i].en_reg - AXP173_REG_ADCENABLE1] & info[i].en_bit)
|
||||
axp173.adc_enable |= 1 << i;
|
||||
}
|
||||
|
||||
|
@ -87,12 +89,16 @@ void axp173_init(void)
|
|||
int bits = axp173.adc_enable;
|
||||
bits |= (1 << ADC_DISCHARGE_CURRENT);
|
||||
axp173_adc_set_enabled(bits);
|
||||
|
||||
/* Read the maximum charging current */
|
||||
int value = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, AXP173_REG_CHARGECONTROL1);
|
||||
axp173.chargecurrent_setting = (value < 0) ? -1 : value;
|
||||
}
|
||||
|
||||
/* TODO: this can STILL indicate some false positives! */
|
||||
int axp173_battery_status(void)
|
||||
{
|
||||
int r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, 0x00);
|
||||
int r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, AXP173_REG_POWERSTATUS);
|
||||
if(r >= 0) {
|
||||
/* Charging bit indicates we're currently charging */
|
||||
if((r & 0x04) != 0)
|
||||
|
@ -124,7 +130,7 @@ int axp173_input_status(void)
|
|||
int input_status = AXP173_INPUT_BATTERY;
|
||||
#endif
|
||||
|
||||
int r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, 0x00);
|
||||
int r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, AXP173_REG_POWERSTATUS);
|
||||
if(r < 0)
|
||||
return input_status;
|
||||
|
||||
|
@ -138,7 +144,7 @@ int axp173_input_status(void)
|
|||
|
||||
#ifdef HAVE_BATTERY_SWITCH
|
||||
/* Check for battery presence if target defines it as removable */
|
||||
r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, 0x01);
|
||||
r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, AXP173_REG_CHARGESTATUS);
|
||||
if(r >= 0 && (r & 0x20) != 0)
|
||||
input_status |= AXP173_INPUT_BATTERY;
|
||||
#endif
|
||||
|
@ -251,13 +257,13 @@ void axp173_adc_set_enabled(int adc_bits)
|
|||
}
|
||||
|
||||
/* Update the configuration */
|
||||
i2c_reg_write(AXP173_BUS, AXP173_ADDR, 0x82, 2, ®s[0]);
|
||||
i2c_reg_write(AXP173_BUS, AXP173_ADDR, AXP173_REG_ADCENABLE1, 2, ®s[0]);
|
||||
axp173.adc_enable = adc_bits;
|
||||
}
|
||||
|
||||
int axp173_adc_get_rate(void)
|
||||
{
|
||||
int r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, 0x84);
|
||||
int r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, AXP173_REG_ADCSAMPLERATE);
|
||||
if(r < 0)
|
||||
return AXP173_ADC_RATE_100HZ; /* an arbitrary value */
|
||||
|
||||
|
@ -266,7 +272,7 @@ int axp173_adc_get_rate(void)
|
|||
|
||||
void axp173_adc_set_rate(int rate)
|
||||
{
|
||||
i2c_reg_modify1(AXP173_BUS, AXP173_ADDR, 0x84,
|
||||
i2c_reg_modify1(AXP173_BUS, AXP173_ADDR, AXP173_REG_ADCSAMPLERATE,
|
||||
0xc0, (rate & 3) << 6, NULL);
|
||||
}
|
||||
|
||||
|
@ -278,7 +284,8 @@ static uint32_t axp173_cc_parse(const uint8_t* buf)
|
|||
void axp173_cc_read(uint32_t* charge, uint32_t* discharge)
|
||||
{
|
||||
uint8_t buf[8];
|
||||
int rc = i2c_reg_read(AXP173_BUS, AXP173_ADDR, 0xb0, 8, &buf[0]);
|
||||
int rc = i2c_reg_read(AXP173_BUS, AXP173_ADDR,
|
||||
AXP173_REG_COULOMBCOUNTERBASE, 8, &buf[0]);
|
||||
if(rc != I2C_STATUS_OK) {
|
||||
if(charge)
|
||||
*charge = 0;
|
||||
|
@ -295,19 +302,63 @@ void axp173_cc_read(uint32_t* charge, uint32_t* discharge)
|
|||
|
||||
void axp173_cc_clear(void)
|
||||
{
|
||||
i2c_reg_setbit1(AXP173_BUS, AXP173_ADDR, 0xb8, 5, 1, NULL);
|
||||
i2c_reg_setbit1(AXP173_BUS, AXP173_ADDR,
|
||||
AXP173_REG_COULOMBCOUNTERCTRL, 5, 1, NULL);
|
||||
}
|
||||
|
||||
void axp173_cc_enable(bool en)
|
||||
{
|
||||
i2c_reg_setbit1(AXP173_BUS, AXP173_ADDR, 0xb8, 7, en ? 1 : 0, NULL);
|
||||
i2c_reg_setbit1(AXP173_BUS, AXP173_ADDR,
|
||||
AXP173_REG_COULOMBCOUNTERCTRL, 7, en ? 1 : 0, NULL);
|
||||
}
|
||||
|
||||
static const int chargecurrent_tbl[] = {
|
||||
100, 190, 280, 360,
|
||||
450, 550, 630, 700,
|
||||
780, 880, 960, 1000,
|
||||
1080, 1160, 1240, 1320,
|
||||
};
|
||||
|
||||
static const int chargecurrent_tblsz = sizeof(chargecurrent_tbl)/sizeof(int);
|
||||
|
||||
void axp173_set_charge_current(int maxcurrent)
|
||||
{
|
||||
/* Find the charge current just higher than maxcurrent */
|
||||
int value = 0;
|
||||
while(value < chargecurrent_tblsz &&
|
||||
chargecurrent_tbl[value] <= maxcurrent)
|
||||
++value;
|
||||
|
||||
/* Select the next lower current, the greatest current <= maxcurrent */
|
||||
if(value >= chargecurrent_tblsz)
|
||||
value = chargecurrent_tblsz - 1;
|
||||
else if(value > 0)
|
||||
--value;
|
||||
|
||||
/* Don't issue i2c write if desired setting is already in use */
|
||||
if(value == axp173.chargecurrent_setting)
|
||||
return;
|
||||
|
||||
/* Update register */
|
||||
i2c_reg_modify1(AXP173_BUS, AXP173_ADDR,
|
||||
AXP173_REG_CHARGECONTROL1, 0x0f, value, NULL);
|
||||
axp173.chargecurrent_setting = value;
|
||||
}
|
||||
|
||||
int axp173_get_charge_current(void)
|
||||
{
|
||||
if(axp173.chargecurrent_setting < 0)
|
||||
return chargecurrent_tbl[0];
|
||||
else
|
||||
return chargecurrent_tbl[axp173.chargecurrent_setting];
|
||||
}
|
||||
|
||||
#ifndef BOOTLOADER
|
||||
#define AXP173_DEBUG_BATTERY_STATUS 0
|
||||
#define AXP173_DEBUG_INPUT_STATUS 1
|
||||
#define AXP173_DEBUG_ADC_RATE 2
|
||||
#define AXP173_DEBUG_FIRST_ADC 3
|
||||
#define AXP173_DEBUG_CHARGE_CURRENT 2
|
||||
#define AXP173_DEBUG_ADC_RATE 3
|
||||
#define AXP173_DEBUG_FIRST_ADC 4
|
||||
#define AXP173_DEBUG_ENTRIES (AXP173_DEBUG_FIRST_ADC + NUM_ADC_CHANNELS)
|
||||
|
||||
static int axp173_debug_menu_cb(int action, struct gui_synclist* lists)
|
||||
|
@ -377,6 +428,12 @@ static const char* axp173_debug_menu_get_name(int item, void* data,
|
|||
return buf;
|
||||
} break;
|
||||
|
||||
case AXP173_DEBUG_CHARGE_CURRENT: {
|
||||
int current = axp173_get_charge_current();
|
||||
snprintf(buf, buflen, "Max charge current: %d mA", current);
|
||||
return buf;
|
||||
} break;
|
||||
|
||||
case AXP173_DEBUG_ADC_RATE: {
|
||||
int rate = 25 << axp173_adc_get_rate();
|
||||
snprintf(buf, buflen, "ADC sample rate: %d Hz", rate);
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* ADC channels */
|
||||
#define ADC_ACIN_VOLTAGE 0
|
||||
#define ADC_ACIN_CURRENT 1
|
||||
#define ADC_VBUS_VOLTAGE 2
|
||||
|
@ -55,6 +56,25 @@
|
|||
#define AXP173_INPUT_BATTERY (1 << 2)
|
||||
#define AXP173_INPUT_EXTERNAL (AXP173_INPUT_AC|AXP173_INPUT_USB)
|
||||
|
||||
/* Registers -- common to AXP173 and AXP192 (incomplete listing) */
|
||||
#define AXP173_REG_POWERSTATUS 0x00
|
||||
#define AXP173_REG_CHARGESTATUS 0x01
|
||||
#define AXP173_REG_PWROUTPUTCTRL 0x12
|
||||
#define AXP173_REG_SHUTDOWNLEDCTRL 0x32
|
||||
#define AXP173_REG_CHARGECONTROL1 0x33
|
||||
#define AXP173_REG_DCDCWORKINGMODE 0x80
|
||||
#define AXP173_REG_ADCENABLE1 0x82
|
||||
#define AXP173_REG_ADCENABLE2 0x83
|
||||
#define AXP173_REG_ADCSAMPLERATE 0x84
|
||||
#define AXP173_REG_COULOMBCOUNTERBASE 0xb0
|
||||
#define AXP173_REG_COULOMBCOUNTERCTRL 0xb8
|
||||
|
||||
/* AXP192-only registers (incomplete listing) */
|
||||
#define AXP192_REG_GPIO0FUNCTION 0x90
|
||||
#define AXP192_REG_GPIO1FUNCTION 0x92
|
||||
#define AXP192_REG_GPIO2FUNCTION 0x93
|
||||
#define AXP192_REG_GPIOSTATE1 0x94
|
||||
|
||||
/* Must be called from power_init() to initialize the driver state */
|
||||
extern void axp173_init(void);
|
||||
|
||||
|
@ -88,6 +108,10 @@ extern void axp173_cc_read(uint32_t* charge, uint32_t* discharge);
|
|||
extern void axp173_cc_clear(void);
|
||||
extern void axp173_cc_enable(bool en);
|
||||
|
||||
/* Set/get maximum charging current in milliamps */
|
||||
extern void axp173_set_charge_current(int maxcurrent);
|
||||
extern int axp173_get_charge_current(void);
|
||||
|
||||
/* Debug menu */
|
||||
extern bool axp173_debug_menu(void);
|
||||
|
||||
|
|
|
@ -23,13 +23,14 @@
|
|||
#include "kernel.h"
|
||||
#include "backlight.h"
|
||||
#include "panic.h"
|
||||
#include "lcd.h"
|
||||
#include "axp173.h"
|
||||
#include "gpio-x1000.h"
|
||||
#include "i2c-x1000.h"
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifndef BOOTLOADER
|
||||
# include "lcd.h"
|
||||
# include "font.h"
|
||||
#endif
|
||||
|
||||
|
@ -409,7 +410,7 @@ static int hp_detect_tmo_cb(struct timeout* tmo)
|
|||
static void hp_detect_init(void)
|
||||
{
|
||||
static struct timeout tmo;
|
||||
static const uint8_t gpio_reg = 0x94;
|
||||
static const uint8_t gpio_reg = AXP192_REG_GPIOSTATE1;
|
||||
static i2c_descriptor desc = {
|
||||
.slave_addr = AXP173_ADDR,
|
||||
.bus_cond = I2C_START | I2C_STOP,
|
||||
|
@ -423,9 +424,8 @@ static void hp_detect_init(void)
|
|||
.next = NULL,
|
||||
};
|
||||
|
||||
/* Headphone detect is wired to an undocumented GPIO on the AXP173.
|
||||
* This sets it to input mode so we can see the pin state. */
|
||||
i2c_reg_write1(AXP173_BUS, AXP173_ADDR, 0x93, 0x01);
|
||||
/* Headphone detect is wired to AXP192 GPIO: set it to input state */
|
||||
i2c_reg_write1(AXP173_BUS, AXP173_ADDR, AXP192_REG_GPIO2FUNCTION, 0x01);
|
||||
|
||||
/* Get an initial reading before startup */
|
||||
int r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, gpio_reg);
|
||||
|
|
|
@ -68,8 +68,14 @@ void power_init(void)
|
|||
axp173_adc_set_enabled(bits);
|
||||
|
||||
/* Turn on all power outputs */
|
||||
i2c_reg_modify1(AXP173_BUS, AXP173_ADDR, 0x12, 0, 0x5f, NULL);
|
||||
i2c_reg_modify1(AXP173_BUS, AXP173_ADDR, 0x80, 0, 0xc0, NULL);
|
||||
i2c_reg_modify1(AXP173_BUS, AXP173_ADDR,
|
||||
AXP173_REG_PWROUTPUTCTRL, 0, 0x5f, NULL);
|
||||
i2c_reg_modify1(AXP173_BUS, AXP173_ADDR,
|
||||
AXP173_REG_DCDCWORKINGMODE, 0, 0xc0, NULL);
|
||||
|
||||
/* Set the default charging current. This is the same as the
|
||||
* OF's setting, although it's not strictly within the USB spec. */
|
||||
axp173_set_charge_current(780);
|
||||
|
||||
/* Short delay to give power outputs time to stabilize */
|
||||
mdelay(5);
|
||||
|
@ -82,7 +88,8 @@ void adc_init(void)
|
|||
void power_off(void)
|
||||
{
|
||||
/* Set the shutdown bit */
|
||||
i2c_reg_setbit1(AXP173_BUS, AXP173_ADDR, 0x32, 7, 1, NULL);
|
||||
i2c_reg_setbit1(AXP173_BUS, AXP173_ADDR,
|
||||
AXP173_REG_SHUTDOWNLEDCTRL, 7, 1, NULL);
|
||||
while(1);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue