*
*/
+// #define DEBUG 1
+
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/workqueue.h>
#define MODE_RESTART (0xf<<0)
#define CONFIG_UPDATE_FLG (0x1<<1)
-#define ATHD (0x0<<3) //ATHD =10%
+#define ATHD (0x0<<3) //ATHD = 0%
#define CW_I2C_SPEED 100000 // default i2c speed set 100khz
-
#define BATTERY_UP_MAX_CHANGE 420 // the max time allow battery change quantity
#define BATTERY_DOWN_CHANGE 60 // the max time allow battery change quantity
#define BATTERY_DOWN_MIN_CHANGE_RUN 30 // the min time allow battery change quantity when run
#define BATTERY_DOWN_MAX_CHANGE_RUN_AC_ONLINE 3600
-#define Enable_BATDRV_LOG 0
+#define NO_STANDARD_AC_BIG_CHARGE_MODE 1
+// #define SYSTEM_SHUTDOWN_VOLTAGE 3400000 //set system shutdown voltage related in battery info.
+#define BAT_LOW_INTERRUPT 1
#define USB_CHARGER_MODE 1
#define AC_CHARGER_MODE 2
-
-#if Enable_BATDRV_LOG
-#define xprintk(format, arg...) printk("func: %s\n" format, __FUNCTION__, ##arg)
-#else
-#define xprintk(format, ...)
-#endif
-
extern int dwc_otg_check_dpdm(void);
extern int get_gadget_connect_flag(void);
extern int dwc_vbus_status( void );
struct workqueue_struct *battery_workqueue;
struct delayed_work battery_delay_work;
struct delayed_work dc_wakeup_work;
+ struct delayed_work bat_low_wakeup_work;
const struct cw_bat_platform_data *plat_data;
struct power_supply rk_bat;
struct power_supply rk_ac;
struct power_supply rk_usb;
- long sleep_time_capacity; // the sleep time from capacity change to present, it will set 0 when capacity change
- long run_time_capacity;
+ long sleep_time_capacity_change; // the sleep time from capacity change to present, it will set 0 when capacity change
+ long run_time_capacity_change;
- long sleep_time_ac_online; // the sleep time from insert ac to present, it will set 0 when insert ac
- long run_time_ac_online;
+ long sleep_time_charge_start; // the sleep time from insert ac to present, it will set 0 when insert ac
+ long run_time_charge_start;
int dc_online;
int usb_online;
ret = i2c_master_reg8_send(client, reg, buf, 1, CW_I2C_SPEED);
return ret;
}
+
static int cw_read_word(struct i2c_client *client, u8 reg, u8 buf[])
{
int ret;
int i;
u8 reset_val;
- printk("func: %s-------\n", __func__);
+ dev_info(&cw_bat->client->dev, "func: %s-------\n", __func__);
+
/* make sure no in sleep mode */
ret = cw_read(cw_bat->client, REG_MODE, ®_val);
if (ret < 0)
reset_val = reg_val;
if((reg_val & MODE_SLEEP_MASK) == MODE_SLEEP) {
- printk("Error, device in sleep mode, cannot update battery info\n");
+ dev_err(&cw_bat->client->dev, "Error, device in sleep mode, cannot update battery info\n");
return -1;
}
/* update new battery info */
-
for (i = 0; i < SIZE_BATINFO; i++) {
- printk("cw_bat->plat_data->cw_bat_config_info[%d] = 0x%x\n", i, \
+ dev_info(&cw_bat->client->dev, "cw_bat->plat_data->cw_bat_config_info[%d] = 0x%x\n", i, \
cw_bat->plat_data->cw_bat_config_info[i]);
ret = cw_write(cw_bat->client, REG_BATINFO + i, &cw_bat->plat_data->cw_bat_config_info[i]);
if (reg_val != cw_bat->plat_data->cw_bat_config_info[i])
return -1;
}
-
- /* set cw2015 to use new battery info */
+ /* set cw2015/cw2013 to use new battery info */
ret = cw_read(cw_bat->client, REG_CONFIG, ®_val);
if (ret < 0)
return ret;
- reg_val |= CONFIG_UPDATE_FLG;/* set UPDATE_FLAG */
- reg_val &= 0x07; // clear ATHD
- reg_val |= ATHD; // set ATHD
+ reg_val |= CONFIG_UPDATE_FLG; /* set UPDATE_FLAG */
+ reg_val &= 0x07; /* clear ATHD */
+ reg_val |= ATHD; /* set ATHD */
ret = cw_write(cw_bat->client, REG_CONFIG, ®_val);
if (ret < 0)
return ret;
- /* check 2015 for ATHD & update_flag */
+ /* check 2015/cw2013 for ATHD & update_flag */
ret = cw_read(cw_bat->client, REG_CONFIG, ®_val);
if (ret < 0)
return ret;
if (!(reg_val & CONFIG_UPDATE_FLG)) {
- printk("update flag for new battery info have not set..\n");
+ dev_info(&cw_bat->client->dev, "update flag for new battery info have not set..\n");
}
if ((reg_val & 0xf8) != ATHD) {
- printk("the new ATHD have not set..\n");
+ dev_info(&cw_bat->client->dev, "the new ATHD have not set..\n");
}
/* reset */
return ret;
if ((reg_val & 0xf8) != ATHD) {
- printk("the new ATHD have not set\n");
- reg_val &= 0x07; // clear ATHD
- reg_val |= ATHD; // set ATHD
+ dev_info(&cw_bat->client->dev, "the new ATHD have not set\n");
+ reg_val &= 0x07; /* clear ATHD */
+ reg_val |= ATHD; /* set ATHD */
ret = cw_write(cw_bat->client, REG_CONFIG, ®_val);
if (ret < 0)
return ret;
return ret;
if (!(reg_val & CONFIG_UPDATE_FLG)) {
- printk("update flag for new battery info have not set\n");
+ dev_info(&cw_bat->client->dev, "update flag for new battery info have not set\n");
ret = cw_update_config_info(cw_bat);
if (ret < 0)
return ret;
}
if (i != SIZE_BATINFO) {
- printk("update flag for new battery info have not set\n");
+ dev_info(&cw_bat->client->dev, "update flag for new battery info have not set\n");
ret = cw_update_config_info(cw_bat);
if (ret < 0)
return ret;
msleep(100);
if (i > 25)
- printk("cw2015 input unvalid power error\n");
+ dev_err(&cw_bat->client->dev, "cw2015/cw2013 input unvalid power error\n");
}
return 0;
}
-static void cw_update_time_member_ac_online(struct cw_battery *cw_bat)
+static void cw_update_time_member_charge_start(struct cw_battery *cw_bat)
{
struct timespec ts;
int new_run_time;
get_monotonic_boottime(&ts);
new_sleep_time = ts.tv_sec - new_run_time;
- cw_bat->run_time_ac_online = new_run_time;
- cw_bat->sleep_time_ac_online = new_sleep_time;
+ cw_bat->run_time_charge_start = new_run_time;
+ cw_bat->sleep_time_charge_start = new_sleep_time;
}
-static void cw_update_time_member_capacity(struct cw_battery *cw_bat)
+static void cw_update_time_member_capacity_change(struct cw_battery *cw_bat)
{
struct timespec ts;
int new_run_time;
get_monotonic_boottime(&ts);
new_sleep_time = ts.tv_sec - new_run_time;
- cw_bat->run_time_capacity = new_run_time;
- cw_bat->sleep_time_capacity = new_sleep_time;
+ cw_bat->run_time_capacity_change = new_run_time;
+ cw_bat->sleep_time_capacity_change = new_sleep_time;
}
static int cw_quickstart(struct cw_battery *cw_bat)
ret = cw_write(cw_bat->client, REG_MODE, ®_val); //(MODE_QUICK_START | MODE_NORMAL)); // 0x30
if(ret < 0) {
- printk("Error quick start1\n");
+ dev_err(&cw_bat->client->dev, "Error quick start1\n");
return ret;
}
reg_val = MODE_NORMAL;
ret = cw_write(cw_bat->client, REG_MODE, ®_val);
if(ret < 0) {
- printk("Error quick start2\n");
+ dev_err(&cw_bat->client->dev, "Error quick start2\n");
return ret;
}
return 1;
int allow_capacity;
static int if_quickstart = 0;
static int jump_flag =0;
+ int charge_time;
// ret = cw_read(cw_bat->client, REG_SOC, ®_val);
cw_capacity = reg_val[0];
if ((cw_capacity < 0) || (cw_capacity > 100)) {
- printk("get cw_capacity error; cw_capacity = %d\n", cw_capacity);
+ dev_err(&cw_bat->client->dev, "get cw_capacity error; cw_capacity = %d\n", cw_capacity);
return cw_capacity;
}
if (cw_capacity == 0)
- xprintk("the cw201x capacity is 0 !!!!!!!, funciton: %s, line: %d\n", __func__, __LINE__);
+ dev_dbg(&cw_bat->client->dev, "the cw201x capacity is 0 !!!!!!!, funciton: %s, line: %d\n", __func__, __LINE__);
else
- xprintk("the cw201x capacity is %d, funciton: %s\n", cw_capacity, __func__);
+ dev_dbg(&cw_bat->client->dev, "the cw201x capacity is %d, funciton: %s\n", cw_capacity, __func__);
// ret = cw_read(cw_bat->client, REG_SOC + 1, ®_val);
if ((cw_bat->charger_mode > 0) && (cw_capacity >= 95) && (cw_capacity <= cw_bat->capacity)) { // avoid no charge full
- capacity_or_aconline_time = (cw_bat->sleep_time_capacity > cw_bat->sleep_time_ac_online) ? cw_bat->sleep_time_capacity : cw_bat->sleep_time_ac_online;
- capacity_or_aconline_time += (cw_bat->run_time_capacity > cw_bat->run_time_ac_online) ? cw_bat->run_time_capacity : cw_bat->run_time_ac_online;
+ capacity_or_aconline_time = (cw_bat->sleep_time_capacity_change > cw_bat->sleep_time_charge_start) ? cw_bat->sleep_time_capacity_change : cw_bat->sleep_time_charge_start;
+ capacity_or_aconline_time += (cw_bat->run_time_capacity_change > cw_bat->run_time_charge_start) ? cw_bat->run_time_capacity_change : cw_bat->run_time_charge_start;
allow_change = (new_sleep_time + new_run_time - capacity_or_aconline_time) / BATTERY_UP_MAX_CHANGE;
if (allow_change > 0) {
allow_capacity = cw_bat->capacity + allow_change;
cw_capacity = (allow_capacity <= 100) ? allow_capacity : 100;
jump_flag =1;
+ } else if (cw_capacity <= cw_bat->capacity) {
+ cw_capacity = cw_bat->capacity;
}
} else if (((cw_bat->charger_mode > 0) && (cw_capacity == (cw_bat->capacity - 1)))
} else if ((cw_capacity == 0) && (cw_bat->capacity > 1)) { // avoid battery level jump to 0% at a moment from more than 2%
- allow_change = ((new_run_time - cw_bat->run_time_capacity) / BATTERY_DOWN_MIN_CHANGE_RUN);
- allow_change += ((new_sleep_time - cw_bat->sleep_time_capacity) / BATTERY_DOWN_MIN_CHANGE_SLEEP);
+ allow_change = ((new_run_time - cw_bat->run_time_capacity_change) / BATTERY_DOWN_MIN_CHANGE_RUN);
+ allow_change += ((new_sleep_time - cw_bat->sleep_time_capacity_change) / BATTERY_DOWN_MIN_CHANGE_SLEEP);
allow_capacity = cw_bat->capacity - allow_change;
cw_capacity = (allow_capacity >= cw_capacity) ? allow_capacity: cw_capacity;
return ret;
} else if ((cw_bat->charger_mode == 0) && (cw_capacity <= cw_bat->capacity ) && (cw_capacity >= 90) && (jump_flag == 1)) { // avoid battery level jump to CW_BAT
- capacity_or_aconline_time = (cw_bat->sleep_time_capacity > cw_bat->sleep_time_ac_online) ? cw_bat->sleep_time_capacity : cw_bat->sleep_time_ac_online;
- capacity_or_aconline_time += (cw_bat->run_time_capacity > cw_bat->run_time_ac_online) ? cw_bat->run_time_capacity : cw_bat->run_time_ac_online;
+ capacity_or_aconline_time = (cw_bat->sleep_time_capacity_change > cw_bat->sleep_time_charge_start) ? cw_bat->sleep_time_capacity_change : cw_bat->sleep_time_charge_start;
+ capacity_or_aconline_time += (cw_bat->run_time_capacity_change > cw_bat->run_time_charge_start) ? cw_bat->run_time_capacity_change : cw_bat->run_time_charge_start;
allow_change = (new_sleep_time + new_run_time - capacity_or_aconline_time) / BATTERY_DOWN_CHANGE;
if (allow_change > 0) {
allow_capacity = cw_bat->capacity - allow_change;
jump_flag =0;
}
else{
- cw_capacity = (allow_capacity <= 100) ? allow_capacity : 100;
+ cw_capacity = (allow_capacity <= 100) ? allow_capacity : 100;
}
+ } else if (cw_capacity <= cw_bat->capacity) {
+ cw_capacity = cw_bat->capacity;
}
}
#if 1
if((cw_bat->charger_mode > 0) &&(cw_capacity == 0))
{
- if (((new_sleep_time + new_run_time - cw_bat->sleep_time_ac_online - cw_bat->run_time_ac_online) > BATTERY_DOWN_MAX_CHANGE_RUN_AC_ONLINE) && (if_quickstart == 0)) {
+ charge_time = new_sleep_time + new_run_time - cw_bat->sleep_time_charge_start - cw_bat->run_time_charge_start;
+ if ((charge_time > BATTERY_DOWN_MAX_CHANGE_RUN_AC_ONLINE) && (if_quickstart == 0)) {
cw_quickstart(cw_bat); // if the cw_capacity = 0 the cw2015 will qstrt
if_quickstart = 1;
}
#endif
+#if 0
if (cw_bat->plat_data->chg_ok_pin != INVALID_GPIO) {
- if((cw_capacity == 100) && (gpio_get_value(cw_bat->plat_data->chg_ok_pin) != cw_bat->plat_data->chg_ok_level))
- cw_capacity = 99;
+ if(gpio_get_value(cw_bat->plat_data->chg_ok_pin) != cw_bat->plat_data->chg_ok_level) {
+ if (cw_capacity == 100) {
+ cw_capacity = 99;
+ }
+ } else {
+ if (cw_bat->charger_mode > 0) {
+ cw_capacity = 100;
+ }
+ }
}
+#endif
+#ifdef SYSTEM_SHUTDOWN_VOLTAGE
+ if ((cw_bat->charger_mode == 0) && (cw_capacity <= 10) && (cw_bat->voltage <= SYSTEM_SHUTDOWN_VOLTAGE)){
+ if (if_quickstart == 10){
+ cw_quickstart(cw_bat);
+ if_quickstart = 12;
+ cw_capacity = 0;
+ } else if (if_quickstart <= 10)
+ if_quickstart =if_quickstart+2;
+ dev_info(&cw_bat->client->dev, "the cw201x voltage is less than SYSTEM_SHUTDOWN_VOLTAGE !!!!!!!, funciton: %s, line: %d\n", __func__, __LINE__);
+ } else if ((cw_bat->charger_mode > 0)&& (if_quickstart <= 12)) {
+ if_quickstart = 0;
+ }
+#endif
return cw_capacity;
}
}
voltage = value16_1 * 312 / 1024;
+ voltage = voltage * 1000;
return voltage;
}
-#if 0
+#ifdef BAT_LOW_INTERRUPT
static int cw_get_alt(struct cw_battery *cw_bat)
{
- int ret = 0;
- u8 reg_val;
- u8 value8 = 0;
- int alrt;
-
- ret = cw_read(cw_bat->client, REG_RRT_ALERT, ®_val);
- if (ret < 0)
- return ret;
- value8 = reg_val;
- alrt = value8 >>7;
-
- //dev_info(&client->dev, "read RRT %d%%. value16 0x%x\n", alrt, value16);
- value8 = value8&0x7f;
- reg_val = value8;
- ret = cw_write(cw_bat->client, REG_RRT_ALERT, ®_val);
+ int ret = 0;
+ u8 reg_val;
+ u8 value8 = 0;
+ int alrt;
+
+ ret = cw_read(cw_bat->client, REG_RRT_ALERT, ®_val);
+ if (ret < 0)
+ return ret;
+ value8 = reg_val;
+ alrt = value8 >>7;
+
+ //dev_info(&cw_bat->client->dev, "read RRT %d%%. value16 0x%x\n", alrt, value16);
+ value8 = value8&0x7f;
+ reg_val = value8;
+ ret = cw_write(cw_bat->client, REG_RRT_ALERT, ®_val);
if(ret < 0) {
- printk("Error clear ALRT\n");
+ dev_err(&cw_bat->client->dev, "Error clear ALRT\n");
return ret;
}
-
- return alrt;
+
+ return alrt;
}
#endif
if ((cw_capacity >= 0) && (cw_capacity <= 100) && (cw_bat->capacity != cw_capacity)) {
cw_bat->capacity = cw_capacity;
cw_bat->bat_change = 1;
- cw_update_time_member_capacity(cw_bat);
+ cw_update_time_member_capacity_change(cw_bat);
if (cw_bat->capacity == 0)
- printk("report battery capacity 0 and will shutdown if no changing");
+ dev_info(&cw_bat->client->dev, "report battery capacity 0 and will shutdown if no changing");
}
}
int status;
- if ((cw_bat->dc_online == 1) || (cw_bat->usb_online == 1)) {
+ if (cw_bat->charger_mode > 0) {
if (cw_bat->capacity >= 100)
status=POWER_SUPPLY_STATUS_FULL;
else
static int rk_ac_update_online(struct cw_battery *cw_bat)
{
- if(cw_bat->plat_data->dc_det_pin == INVALID_GPIO)
+ int ret = 0;
+
+ if(cw_bat->plat_data->dc_det_pin == INVALID_GPIO) {
+ cw_bat->dc_online = 0;
+ return 0;
+ }
+#if 0
+ if (cw_bat->plat_data->is_dc_charge == 0) {
+ cw_bat->dc_online = 0;
return 0;
+ }
+#endif
+
if (gpio_get_value(cw_bat->plat_data->dc_det_pin) == cw_bat->plat_data->dc_det_level) {
if (cw_bat->dc_online != 1) {
- cw_update_time_member_ac_online(cw_bat);
+ cw_update_time_member_charge_start(cw_bat);
cw_bat->dc_online = 1;
if (cw_bat->charger_mode != AC_CHARGER_MODE)
cw_bat->charger_mode = AC_CHARGER_MODE;
- return 1;
+ ret = 1;
}
} else {
if (cw_bat->dc_online != 0) {
- cw_update_time_member_ac_online(cw_bat);
+ cw_update_time_member_charge_start(cw_bat);
cw_bat->dc_online = 0;
- if ((cw_bat->usb_online == 0)&&(cw_bat->charger_mode != 0))
- cw_bat->charger_mode = 0;
-
- return 1;
+ if (cw_bat->usb_online == 0)
+ cw_bat->charger_mode = 0;
+ ret = 1;
}
}
-
- return 0;
+ return ret;
}
-static int rk_usb_update_online(struct cw_battery *cw_bat)
+static int get_usb_charge_state(struct cw_battery *cw_bat)
{
+ int charge_time;
+ int time_from_boot;
+ struct timespec ts;
+
+ int gadget_status = get_gadget_connect_flag();
int usb_status = dwc_vbus_status();
- int gadget_status =get_gadget_connect_flag();
- xprintk("%s usb_status=[%d],cw_bat->charger_mode=[%d],cw_bat->gadget_status=[%d], cw_bat->charger_init_mode = [%d]\n",__func__,usb_status,cw_bat->charger_mode,gadget_status, cw_bat->charger_init_mode);
+ get_monotonic_boottime(&ts);
+ time_from_boot = ts.tv_sec;
+
+ if (cw_bat->charger_init_mode) {
+
+ if (usb_status == 1 || usb_status == 2) {
+ cw_bat->charger_init_mode = 0;
+ } else if (time_from_boot < 8) {
+ usb_status = cw_bat->charger_init_mode;
+ } else if (strstr(saved_command_line,"charger")) {
+ cw_bat->charger_init_mode = dwc_otg_check_dpdm();
+ usb_status = cw_bat->charger_init_mode;
+ }
+ }
+#ifdef NO_STANDARD_AC_BIG_CHARGE_MODE
+ if (cw_bat->usb_online == 1) {
+
+ charge_time = time_from_boot - cw_bat->sleep_time_charge_start - cw_bat->run_time_charge_start;
+ if (charge_time > 3) {
+ if (gadget_status == 0 && dwc_vbus_status() == 1) {
+ usb_status = 2;
+ }
+ }
+ }
+#endif
+ return usb_status;
+
+ dev_dbg(&cw_bat->client->dev, "%s usb_status=[%d],cw_bat->charger_mode=[%d],cw_bat->gadget_status=[%d], cw_bat->charger_init_mode = [%d]\n",__func__,usb_status,cw_bat->charger_mode,gadget_status, cw_bat->charger_init_mode);
+
+}
+
+static int rk_usb_update_online(struct cw_battery *cw_bat)
+{
+ int ret = 0;
+ int usb_status = 0;
+
if (cw_bat->plat_data->is_usb_charge == 0) {
cw_bat->usb_online = 0;
return 0;
}
+
+ usb_status = get_usb_charge_state(cw_bat);
+ if (usb_status == 2) {
+ if (cw_bat->charger_mode != AC_CHARGER_MODE) {
+ cw_bat->charger_mode = AC_CHARGER_MODE;
+ ret = 1;
+ }
+ if (cw_bat->plat_data->chg_mode_sel_pin != INVALID_GPIO) {
+ if (gpio_get_value (cw_bat->plat_data->chg_mode_sel_pin) != cw_bat->plat_data->chg_mode_sel_level)
+ gpio_direction_output(cw_bat->plat_data->chg_mode_sel_pin, (cw_bat->plat_data->chg_mode_sel_level==GPIO_HIGH) ? GPIO_HIGH : GPIO_LOW);
+ }
+
+ if (cw_bat->usb_online != 1) {
+ cw_bat->usb_online = 1;
+ cw_update_time_member_charge_start(cw_bat);
+ }
+
+ } else if (usb_status == 1) {
+ if ((cw_bat->charger_mode != USB_CHARGER_MODE) && (cw_bat->dc_online == 0)) {
+ cw_bat->charger_mode = USB_CHARGER_MODE;
+ ret = 1;
+ }
+
+ if (cw_bat->plat_data->chg_mode_sel_pin != INVALID_GPIO) {
+ if (gpio_get_value (cw_bat->plat_data->chg_mode_sel_pin) == cw_bat->plat_data->chg_mode_sel_level)
+ gpio_direction_output(cw_bat->plat_data->chg_mode_sel_pin, (cw_bat->plat_data->chg_mode_sel_level==GPIO_HIGH) ? GPIO_LOW : GPIO_HIGH);
+ }
+ if (cw_bat->usb_online != 1){
+ cw_bat->usb_online = 1;
+ cw_update_time_member_charge_start(cw_bat);
+ }
+
+ } else if (usb_status == 0 && cw_bat->usb_online != 0) {
+
+ if (cw_bat->plat_data->chg_mode_sel_pin != INVALID_GPIO) {
+ if (gpio_get_value (cw_bat->plat_data->chg_mode_sel_pin == cw_bat->plat_data->chg_mode_sel_level))
+ gpio_direction_output(cw_bat->plat_data->chg_mode_sel_pin, (cw_bat->plat_data->chg_mode_sel_level==GPIO_HIGH) ? GPIO_LOW : GPIO_HIGH);
+ }
+
+ if (cw_bat->dc_online == 0)
+ cw_bat->charger_mode = 0;
+
+ cw_update_time_member_charge_start(cw_bat);
+ cw_bat->usb_online = 0;
+ ret = 1;
+ }
- if (((usb_status == 2) || (cw_bat->charger_init_mode==2)) && (cw_bat->charger_mode != AC_CHARGER_MODE)){
-
- if (cw_bat->charger_mode != AC_CHARGER_MODE)
- cw_bat->charger_mode = AC_CHARGER_MODE;
- if (cw_bat->plat_data->chg_mode_sel_pin != INVALID_GPIO)
- gpio_direction_output(cw_bat->plat_data->chg_mode_sel_pin, (cw_bat->plat_data->chg_mode_sel_level==GPIO_HIGH) ? GPIO_HIGH : GPIO_LOW);
- if (cw_bat->usb_online != 1){
- cw_bat->usb_online = 1;
- cw_update_time_member_ac_online(cw_bat);
- return 1;
- }
- } else if ((usb_status == 1) || ((cw_bat->charger_init_mode==1))) {
-#if 1
- if (0 == gadget_status){
- if (cw_bat->charger_mode != AC_CHARGER_MODE)
- cw_bat->charger_mode = AC_CHARGER_MODE;
- if (cw_bat->plat_data->chg_mode_sel_pin != INVALID_GPIO)
- gpio_direction_output(cw_bat->plat_data->chg_mode_sel_pin, (cw_bat->plat_data->chg_mode_sel_level==GPIO_HIGH) ? GPIO_HIGH : GPIO_LOW);
- if (cw_bat->usb_online != 1){
- cw_bat->usb_online = 1;
- cw_update_time_member_ac_online(cw_bat);
- return 1;
- }
- }
- else{
-#endif
- if (cw_bat->charger_mode != USB_CHARGER_MODE)
- cw_bat->charger_mode = USB_CHARGER_MODE;
- if (cw_bat->plat_data->chg_mode_sel_pin != INVALID_GPIO)
- gpio_direction_output(cw_bat->plat_data->chg_mode_sel_pin, (cw_bat->plat_data->chg_mode_sel_level==GPIO_HIGH) ? GPIO_LOW : GPIO_HIGH);
- if (cw_bat->usb_online != 1){
- cw_bat->usb_online = 1;
- cw_update_time_member_ac_online(cw_bat);
- return 1;
- }
- }
- } else {//if (usb_status == 0){
- if (cw_bat->plat_data->chg_mode_sel_pin != INVALID_GPIO)
- gpio_direction_output(cw_bat->plat_data->chg_mode_sel_pin, (cw_bat->plat_data->chg_mode_sel_level==GPIO_HIGH) ? GPIO_LOW : GPIO_HIGH);
- if ((cw_bat->dc_online == 0)&&(cw_bat->charger_mode != 0))
- cw_bat->charger_mode = 0;
- if (cw_bat->usb_online != 0) {
- cw_update_time_member_ac_online(cw_bat);
- cw_bat->usb_online = 0;
- return 1;
- }
- }
-
-
- return 0;
+ return ret;
}
static void cw_bat_work(struct work_struct *work)
struct cw_battery *cw_bat;
int ret;
- struct timespec ts;
- int time_from_boot;
-
delay_work = container_of(work, struct delayed_work, work);
cw_bat = container_of(delay_work, struct cw_battery, battery_delay_work);
- get_monotonic_boottime(&ts);
- time_from_boot = ts.tv_sec;
- if ((time_from_boot > 30) && cw_bat->charger_init_mode) {
- cw_bat->charger_init_mode = 0;
- }
ret = rk_ac_update_online(cw_bat);
if (ret == 1) {
ret = rk_usb_update_online(cw_bat);
if (ret == 1) {
power_supply_changed(&cw_bat->rk_usb);
- power_supply_changed(&cw_bat->rk_ac); /////////////////////////////////////////////////////
+ power_supply_changed(&cw_bat->rk_ac);
}
}
queue_delayed_work(cw_bat->battery_workqueue, &cw_bat->battery_delay_work, msecs_to_jiffies(1000));
- xprintk("cw_bat->bat_change = %d, cw_bat->time_to_empty = %d, cw_bat->capacity = %d, cw_bat->voltage = %d, cw_bat->dc_online = %d, cw_bat->usb_online = %d\n",\
+ dev_dbg(&cw_bat->client->dev, "cw_bat->bat_change = %d, cw_bat->time_to_empty = %d, cw_bat->capacity = %d, cw_bat->voltage = %d, cw_bat->dc_online = %d, cw_bat->usb_online = %d\n",\
cw_bat->bat_change, cw_bat->time_to_empty, cw_bat->capacity, cw_bat->voltage, cw_bat->dc_online, cw_bat->usb_online);
}
if (cw_bat->plat_data->dc_det_pin != INVALID_GPIO) {
ret = gpio_request(cw_bat->plat_data->dc_det_pin, NULL);
if (ret) {
- printk("failed to request dc_det_pin gpio\n");
+ dev_err(&cw_bat->client->dev, "failed to request dc_det_pin gpio\n");
goto request_dc_det_pin_fail;
}
gpio_pull_updown(cw_bat->plat_data->dc_det_pin, GPIOPullUp);
ret = gpio_direction_input(cw_bat->plat_data->dc_det_pin);
if (ret) {
- printk("failed to set dc_det_pin input\n");
+ dev_err(&cw_bat->client->dev, "failed to set dc_det_pin input\n");
goto request_bat_low_pin_fail;
}
}
if (cw_bat->plat_data->bat_low_pin != INVALID_GPIO) {
ret = gpio_request(cw_bat->plat_data->bat_low_pin, NULL);
if (ret) {
- printk("failed to request bat_low_pin gpio\n");
+ dev_err(&cw_bat->client->dev, "failed to request bat_low_pin gpio\n");
goto request_bat_low_pin_fail;
}
gpio_pull_updown(cw_bat->plat_data->bat_low_pin, GPIOPullUp);
ret = gpio_direction_input(cw_bat->plat_data->bat_low_pin);
if (ret) {
- printk("failed to set bat_low_pin input\n");
+ dev_err(&cw_bat->client->dev, "failed to set bat_low_pin input\n");
goto request_chg_ok_pin_fail;
}
}
if (cw_bat->plat_data->chg_ok_pin != INVALID_GPIO) {
ret = gpio_request(cw_bat->plat_data->chg_ok_pin, NULL);
if (ret) {
- printk("failed to request chg_ok_pin gpio\n");
+ dev_err(&cw_bat->client->dev, "failed to request chg_ok_pin gpio\n");
goto request_chg_ok_pin_fail;
}
gpio_pull_updown(cw_bat->plat_data->chg_ok_pin, GPIOPullUp);
ret = gpio_direction_input(cw_bat->plat_data->chg_ok_pin);
if (ret) {
- printk("failed to set chg_ok_pin input\n");
+ dev_err(&cw_bat->client->dev, "failed to set chg_ok_pin input\n");
gpio_free(cw_bat->plat_data->chg_ok_pin);
goto request_chg_ok_pin_fail;
}
if ((cw_bat->plat_data->is_usb_charge == 1) && (cw_bat->plat_data->chg_mode_sel_pin!= INVALID_GPIO)) {
ret = gpio_request(cw_bat->plat_data->chg_mode_sel_pin, NULL);
if (ret) {
- printk("failed to request chg_mode_sel_pin gpio\n");
+ dev_err(&cw_bat->client->dev, "failed to request chg_mode_sel_pin gpio\n");
goto request_chg_ok_pin_fail;
}
ret = gpio_direction_output(cw_bat->plat_data->chg_mode_sel_pin, (cw_bat->plat_data->chg_mode_sel_level==GPIO_HIGH) ? GPIO_LOW : GPIO_HIGH);
if (ret) {
- printk("failed to set chg_mode_sel_pin input\n");
+ dev_err(&cw_bat->client->dev, "failed to set chg_mode_sel_pin input\n");
gpio_free(cw_bat->plat_data->chg_mode_sel_pin);
goto request_chg_ok_pin_fail;
}
rk28_send_wakeup_key();
/* this assume if usb insert or extract dc_det pin is change */
+#if 0
if(cw_bat->charger_init_mode)
cw_bat->charger_init_mode=0;
+#endif
irq = gpio_to_irq(cw_bat->plat_data->dc_det_pin);
type = gpio_get_value(cw_bat->plat_data->dc_det_pin) ? IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING;
{
struct cw_battery *cw_bat = dev_id;
disable_irq_nosync(irq); // for irq debounce
- //wake_lock_timeout(&usb_wakelock, WAKE_LOCK_TIMEOUT);
- //schedule_delayed_work(&wakeup_work, HZ / 10);
queue_delayed_work(cw_bat->battery_workqueue, &cw_bat->dc_wakeup_work, msecs_to_jiffies(20));
return IRQ_HANDLED;
}
+#ifdef BAT_LOW_INTERRUPT
+
+#define WAKE_LOCK_TIMEOUT (10 * HZ)
+static struct wake_lock bat_low_wakelock;
+
+static void bat_low_detect_do_wakeup(struct work_struct *work)
+{
+ struct delayed_work *delay_work;
+ struct cw_battery *cw_bat;
+
+ delay_work = container_of(work, struct delayed_work, work);
+ cw_bat = container_of(delay_work, struct cw_battery, bat_low_wakeup_work);
+ dev_info(&cw_bat->client->dev, "func: %s-------\n", __func__);
+ cw_get_alt(cw_bat);
+ //enable_irq(irq);
+}
+
+static irqreturn_t bat_low_detect_irq_handler(int irq, void *dev_id)
+{
+ struct cw_battery *cw_bat = dev_id;
+ // disable_irq_nosync(irq); // for irq debounce
+ wake_lock_timeout(&bat_low_wakelock, WAKE_LOCK_TIMEOUT);
+ queue_delayed_work(cw_bat->battery_workqueue, &cw_bat->bat_low_wakeup_work, msecs_to_jiffies(20));
+ return IRQ_HANDLED;
+}
+#endif
static int cw_bat_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
cw_bat = devm_kzalloc(&client->dev, sizeof(*cw_bat), GFP_KERNEL);
if (!cw_bat) {
- printk("fail to allocate memory\n");
+ dev_err(&cw_bat->client->dev, "fail to allocate memory\n");
return -ENOMEM;
}
cw_bat->plat_data = client->dev.platform_data;
ret = cw_bat_gpio_init(cw_bat);
if (ret) {
- printk("cw_bat_gpio_init error\n");
+ dev_err(&cw_bat->client->dev, "cw_bat_gpio_init error\n");
return ret;
}
cw_bat->rk_bat.get_property = rk_battery_get_property;
ret = power_supply_register(&client->dev, &cw_bat->rk_bat);
if(ret < 0) {
- printk("power supply register rk_bat error\n");
+ dev_err(&cw_bat->client->dev, "power supply register rk_bat error\n");
goto rk_bat_register_fail;
}
cw_bat->rk_ac.get_property = rk_ac_get_property;
ret = power_supply_register(&client->dev, &cw_bat->rk_ac);
if(ret < 0) {
- printk("power supply register rk_ac error\n");
+ dev_err(&cw_bat->client->dev, "power supply register rk_ac error\n");
goto rk_ac_register_fail;
}
cw_bat->rk_usb.get_property = rk_usb_get_property;
ret = power_supply_register(&client->dev, &cw_bat->rk_usb);
if(ret < 0) {
- printk("power supply register rk_ac error\n");
+ dev_err(&cw_bat->client->dev, "power supply register rk_ac error\n");
goto rk_usb_register_fail;
}
cw_bat->time_to_empty = 0;
cw_bat->bat_change = 0;
- cw_update_time_member_capacity(cw_bat);
- cw_update_time_member_ac_online(cw_bat);
+ cw_update_time_member_capacity_change(cw_bat);
+ cw_update_time_member_charge_start(cw_bat);
cw_bat->battery_workqueue = create_singlethread_workqueue("rk_battery");
INIT_DELAYED_WORK(&cw_bat->battery_delay_work, cw_bat_work);
INIT_DELAYED_WORK(&cw_bat->dc_wakeup_work, dc_detect_do_wakeup);
queue_delayed_work(cw_bat->battery_workqueue, &cw_bat->battery_delay_work, msecs_to_jiffies(10));
- irq = gpio_to_irq(cw_bat->plat_data->dc_det_pin);
- irq_flags = gpio_get_value(cw_bat->plat_data->dc_det_pin) ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
- ret = request_irq(irq, dc_detect_irq_handler, irq_flags, "usb_detect", cw_bat);
- if (ret < 0) {
- pr_err("%s: request_irq(%d) failed\n", __func__, irq);
+ if (cw_bat->plat_data->dc_det_pin != INVALID_GPIO) {
+ irq = gpio_to_irq(cw_bat->plat_data->dc_det_pin);
+ irq_flags = gpio_get_value(cw_bat->plat_data->dc_det_pin) ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
+ ret = request_irq(irq, dc_detect_irq_handler, irq_flags, "usb_detect", cw_bat);
+ if (ret < 0) {
+ pr_err("%s: request_irq(%d) failed\n", __func__, irq);
+ }
+ enable_irq_wake(irq);
}
- enable_irq_wake(irq);
- printk("cw2015 driver v1.0 probe sucess\n");
+#ifdef BAT_LOW_INTERRUPT
+ INIT_DELAYED_WORK(&cw_bat->bat_low_wakeup_work, bat_low_detect_do_wakeup);
+ wake_lock_init(&bat_low_wakelock, WAKE_LOCK_SUSPEND, "bat_low_detect");
+ if (cw_bat->plat_data->bat_low_pin != INVALID_GPIO) {
+ irq = gpio_to_irq(cw_bat->plat_data->bat_low_pin);
+ ret = request_irq(irq, bat_low_detect_irq_handler, IRQF_TRIGGER_RISING, "bat_low_detect", cw_bat);
+ if (ret < 0) {
+ gpio_free(cw_bat->plat_data->bat_low_pin);
+ }
+ enable_irq_wake(irq);
+ }
+#endif
+
+ dev_info(&cw_bat->client->dev, "cw2015/cw2013 driver v1.2 probe sucess\n");
return 0;
rk_usb_register_fail:
rk_ac_register_fail:
power_supply_unregister(&cw_bat->rk_ac);
rk_bat_register_fail:
- printk("cw2015 driver v1.0 probe error!!!!\n");
+ dev_info(&cw_bat->client->dev, "cw2015/cw2013 driver v1.2 probe error!!!!\n");
return ret;
}
static int cw_bat_remove(struct i2c_client *client)
{
struct cw_battery *cw_bat = i2c_get_clientdata(client);
- xprintk();
+ dev_dbg(&cw_bat->client->dev, "%s\n", __func__);
cancel_delayed_work(&cw_bat->battery_delay_work);
return 0;
}
{
struct i2c_client *client = to_i2c_client(dev);
struct cw_battery *cw_bat = i2c_get_clientdata(client);
- xprintk();
+ dev_dbg(&cw_bat->client->dev, "%s\n", __func__);
cancel_delayed_work(&cw_bat->battery_delay_work);
return 0;
}
{
struct i2c_client *client = to_i2c_client(dev);
struct cw_battery *cw_bat = i2c_get_clientdata(client);
- xprintk();
+ dev_dbg(&cw_bat->client->dev, "%s\n", __func__);
queue_delayed_work(cw_bat->battery_workqueue, &cw_bat->battery_delay_work, msecs_to_jiffies(100));
return 0;
}
static int __init cw_bat_init(void)
{
- xprintk();
return i2c_add_driver(&cw_bat_driver);
}
static void __exit cw_bat_exit(void)
{
- xprintk();
i2c_del_driver(&cw_bat_driver);
}
module_exit(cw_bat_exit);
MODULE_AUTHOR("xhc<xhc@rock-chips.com>");
-MODULE_DESCRIPTION("cw2015 battery driver");
+MODULE_DESCRIPTION("cw2015/cw2013 battery driver");
MODULE_LICENSE("GPL");