#include <linux/wakelock.h>
#include <linux/usb/otg.h>
+#include <mach/gpio.h>
+
#define CONTROLLER_INT_MASK 0x00
#define CONTROLLER_CTRL1 0x01
#define CONTROLLER_WDG 0x02
#define BATTERY_RESISTOR 10000
#define SIMULATOR_RESISTOR 5000
-#define BATTERY_DETECT_THRESHOLD ((BATTERY_RESISTOR + SIMULATOR_RESISTOR) / 2)
-#define CHARGING_CAPACITY_UPDATE_PERIOD (1000 * 60 * 10)
+#define BATTERY_DETECT_THRESHOLD ((BATTERY_RESISTOR + SIMULATOR_RESISTOR) / 2) //battery voltage threshold divided by 22uA
+#define CHARGING_CAPACITY_UPDATE_PERIOD (1000 * 60 * 1)
+
+
+
+/************************************************************/
+#define TIMER_MS_COUNTS 1000
+#define NUM_DISCHARGE_MIN_SAMPLE 30
+#define NUM_CHARGE_MIN_SAMPLE 30
+/**************************************************************/
/* To get VBUS input limit from twl6030_usb */
#if CONFIG_TWL6030_USB
struct notifier_block nb;
struct work_struct usb_work;
+ struct workqueue_struct *freezable_work;
+
struct delayed_work twl6030_bci_monitor_work;
struct delayed_work twl6030_current_avg_work;
/* max scale current based on sense resitor */
int current_max_scale;
+ struct delayed_work work;
+ unsigned int interval;
+
+ int gBatCapacityDisChargeCnt;
+ int capacitytmp;
+ int usb_status;
+ int usb_old_satus;
+ int gBatCapacityChargeCnt;
+ int suspend_capacity;
+ int resume_status;
};
static BLOCKING_NOTIFIER_HEAD(notifier_list);
return;
if (value > 4760 || value < 4200) {
- dev_dbg(di->dev, "invalid min vbus\n");
+ dev_err(di->dev, "invalid min vbus\n");
return;
}
int ret;
if ((term_currentmA > 400) || (term_currentmA < 50)) {
- dev_dbg(di->dev, "invalid termination current\n");
+ dev_err(di->dev, "invalid termination current\n");
return;
}
int ret;
if ((voltagemV < 3500) || (voltagemV > 4760)) {
- dev_dbg(di->dev, "invalid charger_voltagemV\n");
+ dev_err(di->dev, "invalid charger_voltagemV\n");
return;
}
else if ((currentmA >= 500) && (currentmA <= 1500))
currentmA = (currentmA - 500) / 100 + 4;
else {
- dev_dbg(di->dev, "invalid charger_currentmA\n");
+ dev_err(di->dev, "invalid charger_currentmA\n");
return;
}
currentmA = ((currentmA % 100) ? 0x30 : 0x20) +
((currentmA - 100) / 100);
} else if (currentmA < 50) {
- dev_dbg(di->dev, "invalid input current limit\n");
+ dev_err(di->dev, "invalid input current limit\n");
return;
} else {
/* This is no current limit */
int ret;
if ((voltagemV < 3500) || (voltagemV > 4760)) {
- dev_dbg(di->dev, "invalid max_charger_voltagemV\n");
+ dev_err(di->dev, "invalid max_charger_voltagemV\n");
return;
}
else if ((currentmA >= 500) && (currentmA <= 1500))
currentmA = (currentmA - 500) / 100 + 4;
else {
- dev_dbg(di->dev, "invalid max_charger_currentmA\n");
+ dev_err(di->dev, "invalid max_charger_currentmA\n");
return;
}
* Prevent charging on batteries were id resistor is
* less than 5K.
*/
- val = twl6030_get_gpadc_conversion(di, 0);
+ val = twl6030_get_gpadc_conversion(di,di->gpadc_vbat_chnl);
/*
* twl6030_get_gpadc_conversion for
{
int ret;
u8 reg;
-
+ //printk("*************twl6030_stop_usb_charger***************\n");
if (di->use_hw_charger) {
ret = twl_i2c_read_u8(TWL6030_MODULE_CHARGER, ®,
CHARGERUSB_CTRL1);
int ret;
u8 reg;
+
+//printk("***************twl6030_start_usb_charger*****************************************\n");
+
if (di->use_hw_charger) {
ret = twl_i2c_read_u8(TWL6030_MODULE_CHARGER, ®,
CHARGERUSB_CTRL1);
}
if (!is_battery_present(di)) {
- dev_dbg(di->dev, "BATTERY NOT DETECTED!\n");
+ dev_info(di->dev, "BATTERY NOT DETECTED!\n");
return;
}
int ret;
if (!is_battery_present(di)) {
- dev_dbg(di->dev, "BATTERY NOT DETECTED!\n");
+ dev_info(di->dev, "BATTERY NOT DETECTED!\n");
return;
}
dev_dbg(di->dev, "AC charger detected\n");
static void twl6030_stop_charger(struct twl6030_bci_device_info *di)
{
+ //printk("$$$$$$$$$$$$twl6030_stop_charger$$$$$$$$$$$$\n");
if (di->charger_source == POWER_SUPPLY_TYPE_MAINS)
twl6030_stop_ac_charger(di);
else if (di->charger_source == POWER_SUPPLY_TYPE_USB)
*/
static irqreturn_t twl6030charger_ctrl_interrupt(int irq, void *_di)
{
+// printk("%s\n", __func__);
+
struct twl6030_bci_device_info *di = _di;
int ret;
int charger_fault = 0;
goto err;
}
di->usb_online = 0;
- dev_dbg(di->dev, "usb removed\n");
+ dev_info(di->dev, "usb removed\n");
twl6030_stop_usb_charger(di);
if (present_charge_state & VAC_DET)
twl6030_start_ac_charger(di);
di->usb_online = POWER_SUPPLY_TYPE_USB;
if ((present_charge_state & VAC_DET) &&
(di->vac_priority == 2))
- dev_dbg(di->dev, "USB charger detected"
+ dev_info(di->dev, "USB charger detected"
", continue with VAC\n");
else {
di->charger_source =
di->charge_status =
POWER_SUPPLY_STATUS_CHARGING;
}
- dev_dbg(di->dev, "vbus detect\n");
+ dev_info(di->dev, "vbus detect\n");
}
}
if (stat_reset & VAC_DET) {
di->ac_online = 0;
- dev_dbg(di->dev, "vac removed\n");
+ dev_info(di->dev, "vac removed\n");
twl6030_stop_ac_charger(di);
if (present_charge_state & VBUS_DET) {
di->charger_source = POWER_SUPPLY_TYPE_USB;
di->ac_online = POWER_SUPPLY_TYPE_MAINS;
if ((present_charge_state & VBUS_DET) &&
(di->vac_priority == 3))
- dev_dbg(di->dev,
+ dev_info(di->dev,
"AC charger detected"
", continue with VBUS\n");
else
if (stat_set & CONTROLLER_STAT1_FAULT_WDG) {
charger_fault = 1;
- dev_dbg(di->dev, "Fault watchdog fired\n");
+ dev_info(di->dev, "Fault watchdog fired\n");
}
if (stat_reset & CONTROLLER_STAT1_FAULT_WDG)
- dev_dbg(di->dev, "Fault watchdog recovered\n");
+ dev_err(di->dev, "Fault watchdog recovered\n");
if (stat_set & CONTROLLER_STAT1_BAT_REMOVED)
- dev_dbg(di->dev, "Battery removed\n");
+ dev_err(di->dev, "Battery removed\n");
if (stat_reset & CONTROLLER_STAT1_BAT_REMOVED)
- dev_dbg(di->dev, "Battery inserted\n");
+ dev_err(di->dev, "Battery inserted\n");
if (stat_set & CONTROLLER_STAT1_BAT_TEMP_OVRANGE) {
- dev_dbg(di->dev, "Battery temperature overrange\n");
+ dev_err(di->dev, "Battery temperature overrange\n");
di->bat_health = POWER_SUPPLY_HEALTH_OVERHEAT;
}
if (stat_reset & CONTROLLER_STAT1_BAT_TEMP_OVRANGE) {
if (charger_fault) {
twl6030_stop_usb_charger(di);
di->charge_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
- dev_err(di->dev, "Charger Fault stop charging\n");
+ dev_dbg(di->dev, "Charger Fault stop charging\n");
}
if (di->capacity != -1)
power_supply_changed(&di->bat);
else {
cancel_delayed_work(&di->twl6030_bci_monitor_work);
- schedule_delayed_work(&di->twl6030_bci_monitor_work, 0);
+ queue_delayed_work(di->freezable_work, &di->twl6030_bci_monitor_work, 0);
}
err:
return IRQ_HANDLED;
if (charger_fault) {
twl6030_stop_usb_charger(di);
di->charge_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
- dev_err(di->dev, "Charger Fault stop charging\n");
+ dev_dbg(di->dev, "Charger Fault stop charging\n");
}
- dev_dbg(di->dev, "Charger fault detected STS, INT1, INT2 %x %x %x\n",
+ dev_info(di->dev, "Charger fault detected STS, INT1, INT2 %x %x %x\n",
usb_charge_sts, usb_charge_sts1, usb_charge_sts2);
power_supply_changed(&di->bat);
int charger_stop = 0, end_of_charge = 0;
int ret;
+ //printk("xxxxxxxxxxxxxxxxxxxxxxxx twl6032charger_ctrl_interrupt_hw xxxxxxxxxxxxxx\n");
/* read charger controller_stat1 */
ret = twl_i2c_read_u8(TWL6030_MODULE_CHARGER, &stat1,
CONTROLLER_STAT1);
if (!(stat1 & (VBUS_DET | VAC_DET))) {
charger_stop = 1;
di->ac_online = di->usb_online = 0;
+ //printk("%%%%%%%%%%%%%%charger_stop = 1%%%%%%%%%%%%%\n");
}
if (!(di->usb_online || di->ac_online)) {
if (stat1 & VBUS_DET) {
di->usb_online = 1;
di->bat_health = POWER_SUPPLY_HEALTH_GOOD;
+// printk("%%%%%%%%%%%%%%di->usb_online = 1%%%%%%%%%%%%%\n");
+
+ //schedule_work(&di->usb_work);
} else if (stat1 & VAC_DET) {
di->ac_online = 1;
di->bat_health = POWER_SUPPLY_HEALTH_GOOD;
+// printk("%%%%%%%%%%%%%%di->ac_online = 1%%%%%%%%%%%%%\n");
}
}
if (stat1 & CONTROLLER_STAT1_FAULT_WDG) {
charger_stop = 1;
di->bat_health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
- dev_dbg(di->dev, "Charger error : Fault watchdog\n");
+ dev_err(di->dev, "Charger error : Fault watchdog\n");
}
if (stat1 & CONTROLLER_STAT1_BAT_REMOVED) {
charger_stop = 1;
di->bat_health = POWER_SUPPLY_HEALTH_DEAD;
- dev_dbg(di->dev, "Battery removed\n");
+ dev_info(di->dev, "Battery removed\n");
}
if (stat1 & CONTROLLER_STAT1_BAT_TEMP_OVRANGE) {
charger_stop = 1;
- dev_dbg(di->dev,
+ dev_dbg(di->dev,
"Charger error : Battery temperature overrange\n");
di->bat_health = POWER_SUPPLY_HEALTH_OVERHEAT;
}
if (linear & LINEAR_CHRG_STS_CRYSTL_OSC_OK) {
di->bat_health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
- dev_dbg(di->dev, "Charger error: CRYSTAL OSC OK\n");
+ dev_dbg(di->dev, "Charger error: CRYSTAL OSC OK\n");
}
if (linear & LINEAR_CHRG_STS_END_OF_CHARGE) {
if (linear & LINEAR_CHRG_STS_VBATOV) {
di->bat_health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
- dev_dbg(di->dev,
+ dev_dbg(di->dev,
"Charger error : Linear Status: VBATOV\n");
}
if (linear & LINEAR_CHRG_STS_VSYSOV) {
di->bat_health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
- dev_dbg(di->dev,
+ dev_dbg(di->dev,
"Charger error : Linear Status: VSYSOV\n");
}
}
POWER_SUPPLY_STATUS_NOT_CHARGING;
}
}
+ //printk("%%%%%%%%%%%%%%%%%%twl6032charger_ctrl_interrupt_hw end xxxxxxxxxxxxxx\n");
power_supply_changed(&di->bat);
if (sts_int2 & CURRENT_TERM) {
charger_stop = 1;
- dev_dbg(di->dev, "Charger error: CURRENT_TERM\n");
+ dev_dbg(di->dev, "Charger error: CURRENT_TERM\n");
}
}
dev_dbg(di->dev, "Charger: CHARGEUSB_STAT\n");
if (sts_int2 & ANTICOLLAPSE)
- dev_dbg(di->dev, "Charger error: ANTICOLLAPSE\n");
+ dev_dbg(di->dev, "Charger error: ANTICOLLAPSE\n");
}
if (sts & CHARGERUSB_THMREG) {
if (!di->use_power_path) {
if (sts_int1 & CHARGERUSB_STATUS_INT1_NO_BAT) {
di->bat_health = POWER_SUPPLY_HEALTH_DEAD;
- dev_dbg(di->dev,
+ dev_err(di->dev,
"Charger error : NO_BAT\n");
}
if (sts_int1 & CHARGERUSB_STATUS_INT1_BAT_OVP) {
ret = twl_i2c_read(TWL6030_MODULE_GASGAUGE, (u8 *)&read_value,
FG_REG_10, 2);
if (ret < 0) {
- dev_dbg(di->dev, "failed to read FG_REG_10: current_now\n");
+ dev_info(di->dev, "failed to read FG_REG_10: current_now\n");
return;
}
static void twl6030_current_avg(struct work_struct *work)
{
+// printk("%s\n", __func__);
+
s32 samples = 0;
s16 cc_offset = 0;
int current_avg_uA = 0;
di->current_avg_uA = current_avg_uA * 1000;
}
- schedule_delayed_work(&di->twl6030_current_avg_work,
+ queue_delayed_work(di->freezable_work, &di->twl6030_current_avg_work,
msecs_to_jiffies(1000 * di->current_avg_interval));
return;
err:
pr_err("%s: Error access to TWL6030 (%d)\n", __func__, ret);
}
-
+#define BATT_NUM 11
+struct batt_vol_cal{
+ u32 disp_cal;
+ u32 dis_charge_vol;
+ u32 charge_vol;
+};
+static struct batt_vol_cal batt_table[BATT_NUM] = {
+ {0,3571,3730},//{1,3420,3525},{2,3420,3575},{3,3475,3600},{5,3505,3620},{7,3525,3644},
+ {9,3628,3770},//{11,3557,3670},{13,3570,3684},{15,3580,3700},{17,3610,3715},
+ {19,3670,3878},//{21,3640,3748},{23,3652,3756},{25,3662,3775},{27,3672,3790},
+ {29,3719,3895},//{31,3687,3814},{33,3693,3818},{35,3699,3822},{37,3705,3825},
+ {39,3770,3941},//{41,3714,3832},{43,3718,3834},{45,3722,3836},{47,3726,3837},
+ {49,3801,3980},//{51,3734,3841},{53,3738,3842},{55,3742,3844},{57,3746,3844},
+ {59,3849,4010},//{61,3756,3860},{63,3764,3864},{65,3774,3871},{67,3786,3890},
+ {69,3864,4024},//{71,3808,3930},{73,3817,3977},{75,3827,3977},{77,3845,3997},
+ {79,3884,4040},//{81,3964,4047},{83,3982,4064},{85,4002,4080},{87,4026,4096},
+ {89,4001,4050},//{91,4034,4144},{93,4055,4150},{95,4085,4195},{97,4085,4195},
+ {100,4070,4090},
+};
+#if 0
static int capacity_changed(struct twl6030_bci_device_info *di)
{
int curr_capacity = di->capacity;
int charger_source = di->charger_source;
int charging_disabled = 0;
+ struct batt_vol_cal *p;
+ int i=0;
+ p = batt_table;
/* Because system load is always greater than
* termination current, we will never get a CHARGE DONE
* int from BQ. And charging will alwys be in progress.
/* if it has been more than 10 minutes since our last update
* and we are charging we force a update.
*/
-
if (time_after(jiffies, di->ac_next_refresh)
&& (di->charger_source != POWER_SUPPLY_TYPE_BATTERY)) {
-
charging_disabled = 1;
di->ac_next_refresh = jiffies +
msecs_to_jiffies(CHARGING_CAPACITY_UPDATE_PERIOD);
twl6030_stop_charger(di);
/*voltage setteling time*/
msleep(200);
-
di->voltage_mV = twl6030_get_gpadc_conversion(di,
di->gpadc_vbat_chnl);
+
}
/* Setting the capacity level only makes sense when on
* the battery is powering the board.
*/
- if (di->charge_status == POWER_SUPPLY_STATUS_DISCHARGING) {
- if (di->voltage_mV < 3500)
- curr_capacity = 5;
+ if (di->charge_status == POWER_SUPPLY_STATUS_CHARGING){ //charge
+ if(di->voltage_mV >= p[BATT_NUM - 1].charge_vol){
+ curr_capacity = 100;
+ }
+ else{
+ if(di->voltage_mV <= p[0].charge_vol){
+ curr_capacity = 0;
+ }
+ else{
+ for(i = 0; i < BATT_NUM - 1; i++){
+
+ if((p[i].charge_vol <= di->voltage_mV) && (di->voltage_mV < (p[i+1].charge_vol))){
+ curr_capacity = p[i].disp_cal ;
+ break;
+ }
+ }
+ }
+ }
+
+ }
+ else if (di->charge_status == POWER_SUPPLY_STATUS_DISCHARGING){ //discharge
+ if(di->voltage_mV >= p[BATT_NUM - 1].dis_charge_vol){
+ curr_capacity = 100;
+ }
+ else{
+ if(di->voltage_mV <= p[0].dis_charge_vol){
+ curr_capacity = 0;
+ }
+ else{
+ for(i = 0; i < BATT_NUM - 1; i++){
+ if(((p[i].dis_charge_vol) <= di->voltage_mV) && (di->voltage_mV < (p[i+1].dis_charge_vol))){
+ curr_capacity = p[i].disp_cal ;
+ break;
+ }
+ }
+ }
+
+ }
+
+
+ }
+
+ /*
+ if (di->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
+ if (di->voltage_mV < 3520)
+ curr_capacity = 0;
else if (di->voltage_mV < 3600 && di->voltage_mV >= 3500)
curr_capacity = 20;
else if (di->voltage_mV < 3700 && di->voltage_mV >= 3600)
else if (di->voltage_mV >= 3900)
curr_capacity = 100;
}
+
+*/
+
/* if we disabled charging to check capacity,
* enable it again after we read the
*/
if (!is_battery_present(di))
curr_capacity = 100;
+
/* Debouncing of voltage change. */
if (di->capacity == -1) {
di->capacity_debounce_count = 0;
return 1;
}
-
+/*
if (curr_capacity != di->prev_capacity) {
di->prev_capacity = curr_capacity;
di->capacity_debounce_count = 0;
di->capacity_debounce_count = 0;
return 1;
}
+*/
+ return 1;
+}
+#endif
+static int twl6030_batt_vol_to_capacity (struct twl6030_bci_device_info *di)
+
+{
+
+ int i = 0;
+ int capacity = 0;
+ int BatVoltage;
+
+ struct batt_vol_cal *p;
+ p = batt_table;
+
+ BatVoltage = di ->voltage_mV;
+
+ if (di->charge_status == POWER_SUPPLY_STATUS_CHARGING){ //charge
+ if(BatVoltage >= (p[BATT_NUM - 1].charge_vol)){
+ capacity = 100;
+ }
+ else{
+ if(BatVoltage <= (p[0].charge_vol)){
+ capacity = 0;
+ }
+ else{
+ for(i = 0; i < BATT_NUM - 1; i++){
+
+ if(((p[i].charge_vol) <= BatVoltage) && (BatVoltage < (p[i+1].charge_vol))){
+ // capacity = p[i].disp_cal ;
+ capacity = i * 10 + ((BatVoltage - p[i].charge_vol) * 10) / (p[i+1] .charge_vol- p[i].charge_vol);
+
+
+ break;
+ }
+ }
+ }
+ }
+
+ }
+ else{ //discharge
+ if(BatVoltage >= (p[BATT_NUM - 1].dis_charge_vol)){
+ capacity = 100;
+ }
+ else{
+ if(BatVoltage <= (p[0].dis_charge_vol)){
+ capacity = 0;
+ }
+ else{
+ for(i = 0; i < BATT_NUM - 1; i++){
+ if(((p[i].dis_charge_vol) <= BatVoltage) && (BatVoltage < (p[i+1].dis_charge_vol))){
+ // capacity = p[i].disp_cal ;
+ capacity = i * 10 + ((BatVoltage - p[i].dis_charge_vol) * 10) / (p[i+1] .dis_charge_vol- p[i].dis_charge_vol);
+ break;
+ }
+ }
+ }
+
+ }
+
+
+ }
+
+ return capacity;
- return 0;
+}
+
+
+
+static void twl6030_batt_capacity_samples(struct twl6030_bci_device_info *di)
+{
+ int capacity = 0;
+ capacity = twl6030_batt_vol_to_capacity (di);
+ twl6030battery_current(di);
+
+ if( 1 == di->resume_status ){
+ di->resume_status = 0;
+ if (di->charge_status == POWER_SUPPLY_STATUS_CHARGING){\
+ if (di->suspend_capacity > capacity){
+
+ di->capacity = di->suspend_capacity;
+ }else{
+ di->capacity = capacity;
+ }
+ }else{
+ if (di->suspend_capacity > capacity){
+ di->capacity = capacity;
+ }else{
+ di->capacity = di->suspend_capacity;
+ }
+
+ }
+ return;
+
+ }
+
+ if (di->charge_status == POWER_SUPPLY_STATUS_FULL){
+ if (capacity < di->capacity){
+ if (di ->gBatCapacityChargeCnt >= NUM_CHARGE_MIN_SAMPLE){
+ di ->gBatCapacityChargeCnt = 0;
+ if (di -> capacity < 99){
+ di -> capacity++;
+ }
+ }
+
+ }
+
+ }
+
+
+ if (di->charge_status == POWER_SUPPLY_STATUS_CHARGING){
+ if (capacity > di->capacity){
+ //ʵ¼Ê²ÉÑùµ½µÄÈÝÁ¿±ÈÏÔʾµÄÈÝÁ¿´ó£¬Öð¼¶ÉÏÉý
+ if (++(di->gBatCapacityChargeCnt) >= NUM_CHARGE_MIN_SAMPLE){
+ di ->gBatCapacityChargeCnt = 0;
+ if (di -> capacity < 99){
+ di -> capacity++;
+
+ }
+ }
+ di->gBatCapacityDisChargeCnt = 0; //·ÅµçµÄ¼ÆÊýֵΪ0
+ }
+
+ }
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ if ((di->charge_status == POWER_SUPPLY_STATUS_DISCHARGING)||(di->charge_status == POWER_SUPPLY_STATUS_NOT_CHARGING)){
+
+ //·Åµçʱ,Ö»ÔÊÐíµçѹϽµ
+ if (capacity < di -> capacity){
+ if (++(di->gBatCapacityDisChargeCnt) >= NUM_DISCHARGE_MIN_SAMPLE){
+ di ->gBatCapacityDisChargeCnt = 0;
+ if (di -> capacity > 0){
+ di -> capacity-- ;
+ //bat->bat_change = 1;
+ }
+ }
+ }
+ else{
+ di ->gBatCapacityDisChargeCnt = 0;
+ }
+ //di ->gBatCapacityChargeCnt = 0;
+ }
+ di ->capacitytmp = capacity;
}
static int twl6030_set_watchdog(struct twl6030_bci_device_info *di, int val)
return twl_i2c_write_u8(TWL6030_MODULE_CHARGER, val, CONTROLLER_WDG);
}
+#if 0
+static void twl6030_bci_adc_set(struct twl6030_bci_device_info *di)
+{
+ struct twl6030_gpadc_request req;
+ int adc_code;
+ int temp;
+ int ret;
+ //int level;
+
+ /* Kick the charger watchdog */
+ if (di->charge_status == POWER_SUPPLY_STATUS_CHARGING)
+ twl6030_set_watchdog(di, di->watchdog_duration);
+
+ req.method = TWL6030_GPADC_SW2;
+ req.channels = (1 << 1) | (1 << di->gpadc_vbat_chnl) | (1 << 8);
+ req.active = 0;
+ req.func_cb = NULL;
+ ret = twl6030_gpadc_conversion(&req);
+
+
+ if (ret < 0) {
+ dev_dbg(di->dev, "gpadc conversion failed: %d\n", ret);
+ return;
+ }
+
+ if (req.rbuf[di->gpadc_vbat_chnl] > 0)
+ di->voltage_mV = req.rbuf[di->gpadc_vbat_chnl];
+
+ if (req.rbuf[8] > 0)
+ di->bk_voltage_mV = req.rbuf[8];
+
+ if (di->platform_data->battery_tmp_tbl == NULL)
+ return;
+ adc_code = req.rbuf[1];
+ for (temp = 0; temp < di->platform_data->tblsize; temp++) {
+ if (adc_code >= di->platform_data->
+ battery_tmp_tbl[temp])
+ break;
+ }
+ //printk("twl6030_bci_adc_set---di->voltage_mV-=-%d,di->capacity = %d \n",di->voltage_mV,di->capacity);
+ /* first 2 values are for negative temperature */
+
+}
+#endif
static void twl6030_bci_battery_work(struct work_struct *work)
{
+
struct twl6030_bci_device_info *di = container_of(work,
struct twl6030_bci_device_info, twl6030_bci_monitor_work.work);
struct twl6030_gpadc_request req;
int adc_code;
int temp;
int ret;
+// int level;
/* Kick the charger watchdog */
if (di->charge_status == POWER_SUPPLY_STATUS_CHARGING)
twl6030_set_watchdog(di, di->watchdog_duration);
-
+
req.method = TWL6030_GPADC_SW2;
req.channels = (1 << 1) | (1 << di->gpadc_vbat_chnl) | (1 << 8);
-
req.active = 0;
req.func_cb = NULL;
ret = twl6030_gpadc_conversion(&req);
- schedule_delayed_work(&di->twl6030_bci_monitor_work,
- msecs_to_jiffies(1000 * di->monitoring_interval));
+ queue_delayed_work(di->freezable_work, &di->twl6030_bci_monitor_work,
+ msecs_to_jiffies(TIMER_MS_COUNTS)); //* di->monitoring_interval
+
if (ret < 0) {
dev_dbg(di->dev, "gpadc conversion failed: %d\n", ret);
return;
}
-
+
if (req.rbuf[di->gpadc_vbat_chnl] > 0)
di->voltage_mV = req.rbuf[di->gpadc_vbat_chnl];
battery_tmp_tbl[temp])
break;
}
-
+ //printk("workxxxxx---di->voltage_mV-=-%d,di->capacity = %d \n",di->voltage_mV,di->capacity);
/* first 2 values are for negative temperature */
di->temp_C = (temp - 2); /* in degrees Celsius */
-
- if (capacity_changed(di))
+// if (capacity_changed(di)) //xsf
+ {
+ twl6030_batt_capacity_samples(di);
+ // di->capacity = level;
power_supply_changed(&di->bat);
+ }
}
static void twl6030_current_mode_changed(struct twl6030_bci_device_info *di)
{
int ret;
+ //printk("%s\n", __func__);
/* FG_REG_01, 02, 03 is 24 bit unsigned sample counter value */
ret = twl_i2c_read(TWL6030_MODULE_GASGAUGE, (u8 *) &di->timer_n1,
goto err;
cancel_delayed_work(&di->twl6030_current_avg_work);
- schedule_delayed_work(&di->twl6030_current_avg_work,
+ queue_delayed_work(di->freezable_work, &di->twl6030_current_avg_work,
msecs_to_jiffies(1000 * di->current_avg_interval));
return;
err:
static void twl6030_work_interval_changed(struct twl6030_bci_device_info *di)
{
+ //printk("%s\n", __func__);
+
cancel_delayed_work(&di->twl6030_bci_monitor_work);
- schedule_delayed_work(&di->twl6030_bci_monitor_work,
+ queue_delayed_work(di->freezable_work, &di->twl6030_bci_monitor_work,
msecs_to_jiffies(1000 * di->monitoring_interval));
}
#define to_twl6030_bci_device_info(x) container_of((x), \
struct twl6030_bci_device_info, bat);
-
+#if 0
static void twl6030_bci_battery_external_power_changed(struct power_supply *psy)
-{
+{// printk("%s\n", __func__);
+
struct twl6030_bci_device_info *di = to_twl6030_bci_device_info(psy);
cancel_delayed_work(&di->twl6030_bci_monitor_work);
- schedule_delayed_work(&di->twl6030_bci_monitor_work, 0);
+ queue_delayed_work(di->freezable_work, &di->twl6030_bci_monitor_work, 0);
}
+#endif
#define to_twl6030_ac_device_info(x) container_of((x), \
struct twl6030_bci_device_info, ac);
enum power_supply_property psp,
union power_supply_propval *val)
{
+ u8 stat1;
struct twl6030_bci_device_info *di = to_twl6030_ac_device_info(psy);
-
switch (psp) {
case POWER_SUPPLY_PROP_ONLINE:
- val->intval = di->ac_online;
+ twl_i2c_read_u8(TWL6030_MODULE_CHARGER, &stat1,
+ CONTROLLER_STAT1);
+
+ if (stat1 & VAC_DET) {
+ val->intval = 1;
+ }
+ else
+ val->intval = 0;
+
+ ///printk("&&&&&&&&&&&&ac---charge ac->intval = %d &&&&&&&&&&&&&&&\n" ,val->intval);
+
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
val->intval = twl6030_get_gpadc_conversion(di, 9) * 1000;
+
break;
default:
return -EINVAL;
enum power_supply_property psp,
union power_supply_propval *val)
{
+ u8 stat1;
struct twl6030_bci_device_info *di = to_twl6030_usb_device_info(psy);
-
switch (psp) {
case POWER_SUPPLY_PROP_ONLINE:
- val->intval = di->usb_online;
+
+ twl_i2c_read_u8(TWL6030_MODULE_CHARGER, &stat1,
+ CONTROLLER_STAT1);
+
+ if (stat1 & VBUS_DET) {
+ val->intval = 1;
+ }
+ else
+ val->intval = 0;
+
+ //val->intval = di->usb_online; //xsf
+
+ //printk("&&&&&&&&&&&&usb---charge val->intval = %d &&&&&&&&&&&&&&&\n" ,val->intval);
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
val->intval = twl6030_get_gpadc_conversion(di, 10) * 1000;
+ //printk("&&&&&&&&&&&&usb-voltage = &&&&&&&&&&&&&&&%d\n", val->intval);
break;
default:
return -EINVAL;
union power_supply_propval *val)
{
struct twl6030_bci_device_info *di = to_twl6030_bk_bci_device_info(psy);
-
+ val->intval = 0;
switch (psp) {
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
val->intval = di->bk_voltage_mV * 1000;
{
struct twl6030_bci_device_info *di =
container_of(work, struct twl6030_bci_device_info, usb_work);
-
switch (di->event) {
case USB_EVENT_CHARGER:
/* POWER_SUPPLY_TYPE_USB_DCP */
return;
}
twl6030_start_usb_charger(di);
+
power_supply_changed(&di->usb);
}
{
struct twl6030_bci_device_info *di =
container_of(nb, struct twl6030_bci_device_info, nb);
-
di->event = event;
switch (event) {
case USB_EVENT_VBUS:
"twl6030_battery",
};
+extern int dwc_vbus_status(void);
+
+static void twl6030_battery_update_status(struct twl6030_bci_device_info *di)
+{
+ power_supply_changed(&di->bat);
+ power_supply_changed(&di->usb);
+ power_supply_changed(&di->ac);
+
+}
+static void twl6030_battery_work(struct work_struct *work)
+{
+
+ struct twl6030_bci_device_info *di = container_of(work, struct twl6030_bci_device_info, work.work);
+ twl6030_battery_update_status(di);
+ //set charging current
+ twl_i2c_write_u8(TWL6030_MODULE_CHARGER,0x00,CHARGERUSB_CTRL1);
+ if(2 == dwc_vbus_status()){
+ twl_i2c_write_u8(TWL6030_MODULE_CHARGER, 0x2e,CHARGERUSB_CINLIMIT); //set vbus input current is 1.5A
+ twl_i2c_write_u8(TWL6030_MODULE_CHARGER, 0x0b,CHARGERUSB_VICHRG); //set mos output current is 1A
+ }
+ else if(1 == dwc_vbus_status()){
+ twl_i2c_write_u8(TWL6030_MODULE_CHARGER, 0x2e,CHARGERUSB_CINLIMIT);//set vbus input current is 500ma
+ twl_i2c_write_u8(TWL6030_MODULE_CHARGER, 0x09,CHARGERUSB_VICHRG); //set mos output current is 500ma
+ }
+ /* reschedule for the next time */
+ queue_delayed_work(di->freezable_work, &di->work, di->interval);
+}
+
static int __devinit twl6030_bci_battery_probe(struct platform_device *pdev)
{
struct twl4030_bci_platform_data *pdata = pdev->dev.platform_data;
u8 chargerusb_ctrl1 = 0;
u8 hw_state = 0;
u8 reg = 0;
-
+ //printk("%s\n", __func__);
if (!pdata) {
- dev_dbg(&pdev->dev, "platform_data not available\n");
+ dev_info(&pdev->dev, "platform_data not available\n");
return -EINVAL;
}
di->features = pdata->features;
di->dev = &pdev->dev;
+
+// printk("di->feature = %d, TWL6032_SUBCLASS = %d\n",di->features,TWL6032_SUBCLASS);
if (di->features & TWL6032_SUBCLASS) {
ret = twl_i2c_read_u8(TWL_MODULE_RTC, ®, CHARGER_MODE_REG);
if (ret)
di->use_power_path = 0;
di->use_hw_charger = 0;
}
+// printk("di->feature = %d, TWL6032_SUBCLASS = %d,di->use_hw_charger =%d \n",di->features,TWL6032_SUBCLASS,di->use_hw_charger );
+
if (di->use_hw_charger) {
di->platform_data->max_charger_currentmA =
twl6030_get_limit2_reg(di);
di->platform_data->max_bat_voltagemV =
twl6030_get_voreg_reg(di);
}
-
+// printk("max_charger_currentmA = %d, max_charger_voltagemV = %d\n,termination_currentmA =%d, max_bat_voltagemV =%d \n",di->platform_data->max_charger_currentmA ,
+// di->platform_data->max_charger_voltagemV,di->platform_data->termination_currentmA, di->platform_data->max_bat_voltagemV);
di->bat.name = "twl6030_battery";
di->bat.supplied_to = twl6030_bci_supplied_to;
di->bat.num_supplicants = ARRAY_SIZE(twl6030_bci_supplied_to);
di->bat.properties = twl6030_bci_battery_props;
di->bat.num_properties = ARRAY_SIZE(twl6030_bci_battery_props);
di->bat.get_property = twl6030_bci_battery_get_property;
- di->bat.external_power_changed =
- twl6030_bci_battery_external_power_changed;
+ //di->bat.external_power_changed =
+ // twl6030_bci_battery_external_power_changed;
di->bat_health = POWER_SUPPLY_HEALTH_GOOD;
di->usb.name = "twl6030_usb";
0, "twl_bci_fault", di);
if (ret) {
- dev_dbg(&pdev->dev, "could not request irq %d, status %d\n",
+ dev_info(&pdev->dev, "could not request irq %d, status %d\n",
irq, ret);
goto temp_setup_fail;
}
0, "twl_bci_ctrl", di);
else
ret = request_threaded_irq(irq, NULL,
- twl6032charger_ctrl_interrupt_hw,
- 0, "twl_bci_ctrl", di);
+ twl6032charger_ctrl_interrupt_hw,
+ 0, "twl_bci_ctrl", di); // Ò»Ö±ÔÚ¼ì²âµç³ØµÄ״̬
if (ret) {
- dev_dbg(&pdev->dev, "could not request irq %d, status %d\n",
+ dev_info(&pdev->dev, "could not request irq %d, status %d\n",
irq, ret);
goto chg_irq_fail;
}
ret = power_supply_register(&pdev->dev, &di->bat);
if (ret) {
- dev_dbg(&pdev->dev, "failed to register main battery\n");
+ dev_info(&pdev->dev, "failed to register main battery\n");
goto batt_failed;
}
ret = power_supply_register(&pdev->dev, &di->usb);
if (ret) {
- dev_dbg(&pdev->dev, "failed to register usb power supply\n");
+ dev_info(&pdev->dev, "failed to register usb power supply\n");
goto usb_failed;
}
ret = power_supply_register(&pdev->dev, &di->ac);
if (ret) {
- dev_dbg(&pdev->dev, "failed to register ac power supply\n");
+ dev_info(&pdev->dev, "failed to register ac power supply\n");
goto ac_failed;
}
ret = power_supply_register(&pdev->dev, &di->bk_bat);
if (ret) {
- dev_dbg(&pdev->dev, "failed to register backup battery\n");
+ dev_info(&pdev->dev, "failed to register backup battery\n");
goto bk_batt_failed;
}
di->charge_n1 = 0;
di->timer_n1 = 0;
- INIT_DELAYED_WORK_DEFERRABLE(&di->twl6030_bci_monitor_work,
- twl6030_bci_battery_work);
- schedule_delayed_work(&di->twl6030_bci_monitor_work, 0);
+ //di->freezable_work = create_freezable_workqueue("battery");
+#if 1
+ if (di->features & TWL6032_SUBCLASS) {
+ di->charger_incurrentmA = 1000;
+ di->gpadc_vbat_chnl = TWL6032_GPADC_VBAT_CHNL;
+ } else {
+ di->charger_incurrentmA = twl6030_get_usb_max_power(di->otg);
+ di->gpadc_vbat_chnl = TWL6030_GPADC_VBAT_CHNL;
+ }
+#endif
+#if 1
+
+ ret = twl6030battery_voltage_setup(di);
+ if (ret)
+ dev_info(&pdev->dev, "voltage measurement setup failed\n");
+ ret = twl6030battery_current_setup(true);
+ if (ret)
+ dev_info(&pdev->dev, "current measurement setup failed\n");
+
+
+ di->voltage_mV = twl6030_get_gpadc_conversion(di, di->gpadc_vbat_chnl);
+ di->voltage_mV = twl6030_get_gpadc_conversion(di, di->gpadc_vbat_chnl);
+ di->capacity = twl6030_batt_vol_to_capacity( di);
+ twl6030battery_current(di);
+#endif
+ di->freezable_work = system_freezable_wq;
+ INIT_DELAYED_WORK(&di->twl6030_bci_monitor_work,
+ twl6030_bci_battery_work);
+ queue_delayed_work(di->freezable_work, &di->twl6030_bci_monitor_work, 0);
+#if 1
INIT_DELAYED_WORK_DEFERRABLE(&di->twl6030_current_avg_work,
twl6030_current_avg);
- schedule_delayed_work(&di->twl6030_current_avg_work, 500);
-
+ queue_delayed_work(di->freezable_work, &di->twl6030_current_avg_work, 500);
+#endif
+#if 0
ret = twl6030battery_voltage_setup(di);
if (ret)
- dev_dbg(&pdev->dev, "voltage measurement setup failed\n");
+ dev_info(&pdev->dev, "voltage measurement setup failed\n");
ret = twl6030battery_current_setup(true);
if (ret)
- dev_dbg(&pdev->dev, "current measurement setup failed\n");
+ dev_info(&pdev->dev, "current measurement setup failed\n");
+#endif
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* initialize for USB charging */
if (!di->use_hw_charger) {
twl6030_config_limit1_reg(di, pdata->max_charger_voltagemV);
} else
dev_err(&pdev->dev, "otg_get_transceiver failed %d\n", ret);
+
if (di->features & TWL6032_SUBCLASS) {
- di->charger_incurrentmA = 100;
+ di->charger_incurrentmA = 1000;
di->gpadc_vbat_chnl = TWL6032_GPADC_VBAT_CHNL;
} else {
di->charger_incurrentmA = twl6030_get_usb_max_power(di->otg);
if (ret)
goto bk_batt_failed;
- chargerusb_ctrl1 |= HZ_MODE;
+ chargerusb_ctrl1 |= HZ_MODE; // high-impedance
ret = twl_i2c_write_u8(TWL6030_MODULE_CHARGER,
chargerusb_ctrl1, CHARGERUSB_CTRL1);
if (ret)
POWER_SUPPLY_STATUS_DISCHARGING;
}
}
-
+#if 1
+ di->interval = msecs_to_jiffies(1 * 1000);
+ INIT_DELAYED_WORK(&di->work, twl6030_battery_work);
+ queue_delayed_work(di->freezable_work, &di->work, 1*HZ);
+#endif
ret = twl6030backupbatt_setup();
if (ret)
- dev_dbg(&pdev->dev, "Backup Bat charging setup failed\n");
+ dev_info(&pdev->dev, "Backup Bat charging setup failed\n");
twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK,
REG_INT_MSK_LINE_C);
ret = sysfs_create_group(&pdev->dev.kobj, &twl6030_bci_attr_group);
if (ret)
- dev_dbg(&pdev->dev, "could not create sysfs files\n");
+ dev_info(&pdev->dev, "could not create sysfs files\n");
return 0;
if (ret)
goto err;
- cancel_delayed_work(&di->twl6030_bci_monitor_work);
- cancel_delayed_work(&di->twl6030_current_avg_work);
+ //cancel_delayed_work(&di->work);
+ cancel_delayed_work(&di->twl6030_bci_monitor_work);
+ //cancel_delayed_work(&di->twl6030_current_avg_work);
+
+ di->suspend_capacity = di->capacity;
/* We cannot tolarate a sleep longer than 30 seconds
* while on ac charging we have to reset the BQ watchdog timer.
*/
- if ((di->charger_source == POWER_SUPPLY_TYPE_MAINS) &&
- ((wakeup_timer_seconds > 25) || !wakeup_timer_seconds)) {
- wakeup_timer_seconds = 25;
- }
+// if ((di->charger_source == POWER_SUPPLY_TYPE_MAINS) &&
+// ((wakeup_timer_seconds > 25) || !wakeup_timer_seconds)) {
+// wakeup_timer_seconds = 25;
+// }
/*reset the BQ watch dog*/
events = BQ2415x_RESET_TIMER;
u8 rd_reg = 0;
int ret;
+ di->resume_status =1;
ret = twl6030battery_temp_setup(true);
if (ret) {
pr_err("%s: Temp measurement setup failed (%d)!\n",
if (ret)
goto err;
- schedule_delayed_work(&di->twl6030_bci_monitor_work, 0);
- schedule_delayed_work(&di->twl6030_current_avg_work, 50);
+ queue_delayed_work(di->freezable_work, &di->twl6030_bci_monitor_work, 0);
+ //queue_delayed_work(di->freezable_work, &di->twl6030_current_avg_work, 50);
+ //queue_delayed_work(di->freezable_work, &di->work, di->interval);
events = BQ2415x_RESET_TIMER;
blocking_notifier_call_chain(¬ifier_list, events, NULL);