From be11109547bf03ea5f855d76d92f7265f386784b Mon Sep 17 00:00:00 2001 From: Shunqing Chen Date: Fri, 26 May 2017 09:57:50 +0800 Subject: [PATCH] power_supply: add cw2015 battery support Change-Id: I36d65b9765a3303169f0ff60025d9ae722ceb1a9 Signed-off-by: Shunqing Chen --- drivers/power/Kconfig | 7 + drivers/power/Makefile | 1 + drivers/power/cw2015_battery.c | 1252 +++++++------------------- include/linux/power/cw2015_battery.h | 95 +- 4 files changed, 401 insertions(+), 954 deletions(-) mode change 100755 => 100644 drivers/power/cw2015_battery.c diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index e4b46fadd8fb..9427d28f2c8a 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -490,6 +490,13 @@ config BATTERY_EC If you say yes here you will get support for the battery of EC. This driver can give support for EC Battery Interface. +config BATTERY_CW2015 + bool "CW2015 Battery driver" + default n + help + If you say yes here you will get support for the battery of CW2015. + This driver can give support for CW2015 Battery Interface. + config BATTERY_GOLDFISH tristate "Goldfish battery driver" depends on GOLDFISH || COMPILE_TEST diff --git a/drivers/power/Makefile b/drivers/power/Makefile index b776caa73764..814abaf1617a 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_TEST_POWER) += test_power.o obj-$(CONFIG_BATTERY_88PM860X) += 88pm860x_battery.o obj-$(CONFIG_BATTERY_EC) += ec_battery.o +obj-$(CONFIG_BATTERY_CW2015) += cw2015_battery.o obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o obj-$(CONFIG_BATTERY_DS2780) += ds2780_battery.o obj-$(CONFIG_BATTERY_DS2781) += ds2781_battery.o diff --git a/drivers/power/cw2015_battery.c b/drivers/power/cw2015_battery.c old mode 100755 new mode 100644 index aaf01fc9f386..283367953e6b --- a/drivers/power/cw2015_battery.c +++ b/drivers/power/cw2015_battery.c @@ -11,110 +11,52 @@ * */ -#include -#include -#include -#include -#include -#include +#include +#include #include +#include #include -#include -#include -#include -#include -#include +#include +#include #include +#include #include -static int i2c_master_reg8_send(const struct i2c_client *client, const char reg, - const char *buf, int count, int scl_rate) -{ - int ret; - char *tx_buf; - struct i2c_msg msg; - struct i2c_adapter *adap = client->adapter; +static int dbg_enable; +module_param_named(dbg_level, dbg_enable, int, 0644); - tx_buf = kzalloc(count + 1, GFP_KERNEL); - if (!tx_buf) - return -ENOMEM; - - tx_buf[0] = reg; - memcpy(tx_buf + 1, buf, count); - - msg.addr = client->addr; - msg.flags = client->flags; - msg.len = count + 1; - msg.buf = (char *)tx_buf; - msg.scl_rate = scl_rate; - - ret = i2c_transfer(adap, &msg, 1); - kfree(tx_buf); - - return (ret == 1) ? count : ret; -} - -static int i2c_master_reg8_recv(const struct i2c_client *client, const char reg, - char *buf, int count, int scl_rate) -{ - struct i2c_adapter *adap = client->adapter; - struct i2c_msg msgs[2]; - int ret; - char reg_buf = reg; - - msgs[0].addr = client->addr; - msgs[0].flags = client->flags; - msgs[0].len = 1; - msgs[0].buf = ®_buf; - msgs[0].scl_rate = scl_rate; - - msgs[1].addr = client->addr; - msgs[1].flags = client->flags | I2C_M_RD; - msgs[1].len = count; - msgs[1].buf = (char *)buf; - msgs[1].scl_rate = scl_rate; - - ret = i2c_transfer(adap, msgs, 2); - - return (ret == 2) ? count : ret; -} +#define cw_printk(args...) \ + do { \ + if (dbg_enable) { \ + pr_info(args); \ + } \ + } while (0) static int cw_read(struct i2c_client *client, u8 reg, u8 buf[]) { - int ret; - - ret = i2c_master_reg8_recv(client, reg, buf, 1, CW_I2C_SPEED); - - return ret; + return i2c_smbus_read_i2c_block_data(client, reg, 1, buf); } static int cw_write(struct i2c_client *client, u8 reg, u8 const buf[]) { - int ret; - - ret = i2c_master_reg8_send(client, reg, buf, 1, CW_I2C_SPEED); - - return ret; + return i2c_smbus_write_i2c_block_data(client, reg, 1, &buf[0]); } static int cw_read_word(struct i2c_client *client, u8 reg, u8 buf[]) { - int ret; - - ret = i2c_master_reg8_recv(client, reg, buf, 2, CW_I2C_SPEED); - - return ret; + return i2c_smbus_read_i2c_block_data(client, reg, 2, buf); } -static int cw_update_config_info(struct cw_battery *cw_bat) +int cw_update_config_info(struct cw_battery *cw_bat) { int ret; u8 reg_val; u8 i; u8 reset_val; - dev_info(&cw_bat->client->dev, "func: %s-------\n", __func__); + cw_printk("[FGADC] test config_info = 0x%x\n", + cw_bat->plat_data.cw_bat_config_info[0]); /* make sure no in sleep mode */ ret = cw_read(cw_bat->client, REG_MODE, ®_val); @@ -124,7 +66,7 @@ static int cw_update_config_info(struct cw_battery *cw_bat) reset_val = reg_val; if ((reg_val & MODE_SLEEP_MASK) == MODE_SLEEP) { dev_err(&cw_bat->client->dev, - "Error, device in sleep mode, cannot update battery info\n"); + "device in sleep mode, cannot update battery info\n"); return -1; } @@ -138,18 +80,6 @@ static int cw_update_config_info(struct cw_battery *cw_bat) return ret; } - /* readback & check */ - for (i = 0; i < SIZE_BATINFO; i++) { - ret = cw_read(cw_bat->client, REG_BATINFO + i, ®_val); - if (reg_val != cw_bat->plat_data.cw_bat_config_info[i]) - return -1; - } - - /* 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 */ @@ -182,6 +112,8 @@ static int cw_update_config_info(struct cw_battery *cw_bat) if (ret < 0) return ret; + cw_printk("cw2015 update config success!\n"); + return 0; } @@ -216,16 +148,17 @@ static int cw_init(struct cw_battery *cw_bat) return ret; if (!(reg_val & CONFIG_UPDATE_FLG)) { - dev_info(&cw_bat->client->dev, - "update flag for new battery info have not set\n"); + cw_printk("update config flg is true, need update config\n"); ret = cw_update_config_info(cw_bat); - if (ret < 0) + if (ret < 0) { + dev_info(&cw_bat->client->dev, + "update flag for new battery info have not set\n"); return ret; + } } else { for (i = 0; i < SIZE_BATINFO; i++) { - ret = - cw_read(cw_bat->client, (REG_BATINFO + i), - ®_val); + ret = cw_read(cw_bat->client, (REG_BATINFO + i), + ®_val); if (ret < 0) return ret; @@ -248,11 +181,7 @@ static int cw_init(struct cw_battery *cw_bat) return ret; else if (reg_val <= 0x64) break; - - msleep(100); - if (i > 25) - dev_err(&cw_bat->client->dev, - "cw2015/cw2013 input unvalid power error\n"); + msleep(120); } if (i >= 30) { @@ -261,272 +190,231 @@ static int cw_init(struct cw_battery *cw_bat) dev_info(&cw_bat->client->dev, "report battery capacity error"); return -1; } + + cw_printk("cw2015 init success!\n"); return 0; } -static void cw_update_time_member_charge_start(struct cw_battery *cw_bat) +static int check_chrg_usb_psy(struct device *dev, void *data) { - struct timespec ts; - int new_run_time; - int new_sleep_time; + struct power_supply *psy = dev_get_drvdata(dev); + struct cw_battery *cw_bat = (struct cw_battery *)data; - ktime_get_ts(&ts); - new_run_time = ts.tv_sec; + if (psy->desc->type == POWER_SUPPLY_TYPE_USB) { + cw_bat->chrg_usb_psy = psy; + return 1; + } + return 0; +} - get_monotonic_boottime(&ts); - new_sleep_time = ts.tv_sec - new_run_time; +static int check_chrg_ac_psy(struct device *dev, void *data) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct cw_battery *cw_bat = (struct cw_battery *)data; - cw_bat->run_time_charge_start = new_run_time; - cw_bat->sleep_time_charge_start = new_sleep_time; + if (psy->desc->type == POWER_SUPPLY_TYPE_MAINS) { + cw_bat->chrg_ac_psy = psy; + return 1; + } + return 0; } -static void cw_update_time_member_capacity_change(struct cw_battery *cw_bat) +static void get_chrg_psy(struct cw_battery *cw_bat) { - struct timespec ts; - int new_run_time; - int new_sleep_time; + if (!cw_bat->chrg_usb_psy) + class_for_each_device(power_supply_class, NULL, cw_bat, + check_chrg_usb_psy); + if (!cw_bat->chrg_ac_psy) + class_for_each_device(power_supply_class, NULL, cw_bat, + check_chrg_ac_psy); +} - ktime_get_ts(&ts); - new_run_time = ts.tv_sec; +static int get_charge_state(struct cw_battery *cw_bat) +{ + union power_supply_propval val; + int ret = -ENODEV; + int usb_online = 0; + int ac_online = 0; + struct power_supply *chrg_usb_psy; + struct power_supply *chrg_ac_psy; - get_monotonic_boottime(&ts); - new_sleep_time = ts.tv_sec - new_run_time; + if (!cw_bat->chrg_usb_psy || !cw_bat->chrg_ac_psy) + get_chrg_psy(cw_bat); - cw_bat->run_time_capacity_change = new_run_time; - cw_bat->sleep_time_capacity_change = new_sleep_time; + chrg_usb_psy = cw_bat->chrg_usb_psy; + chrg_ac_psy = cw_bat->chrg_ac_psy; + if (chrg_usb_psy) { + ret = chrg_usb_psy->desc->get_property(chrg_usb_psy, + POWER_SUPPLY_PROP_ONLINE, + &val); + if (!ret) + usb_online = val.intval; + } + if (chrg_ac_psy) { + ret = chrg_ac_psy->desc->get_property(chrg_ac_psy, + POWER_SUPPLY_PROP_ONLINE, + &val); + if (!ret) + ac_online = val.intval; + } + if (!chrg_usb_psy) + cw_printk("Usb online didn't find\n"); + if (!chrg_ac_psy) + cw_printk("Ac online didn't find\n"); + + cw_printk("ac_online = %d, usb_online = %d\n", ac_online, usb_online); + if (ac_online || usb_online) + return 1; + + return 0; } -#if (CW_QUICKSTART) -static int cw_quickstart(struct cw_battery *cw_bat) +static int cw_por(struct cw_battery *cw_bat) { - int ret = 0; - u8 reg_val = MODE_QUICK_START; + int ret; + unsigned char reset_val; - ret = cw_write(cw_bat->client, REG_MODE, ®_val); - if (ret < 0) { - dev_err(&cw_bat->client->dev, "Error quick start1\n"); + reset_val = MODE_SLEEP; + ret = cw_write(cw_bat->client, REG_MODE, &reset_val); + if (ret < 0) return ret; - } - - reg_val = MODE_NORMAL; - ret = cw_write(cw_bat->client, REG_MODE, ®_val); - if (ret < 0) { - dev_err(&cw_bat->client->dev, "Error quick start2\n"); + reset_val = MODE_NORMAL; + msleep(20); + ret = cw_write(cw_bat->client, REG_MODE, &reset_val); + if (ret < 0) return ret; - } - return 1; + ret = cw_init(cw_bat); + if (ret) + return ret; + return 0; } -#endif + static int cw_get_capacity(struct cw_battery *cw_bat) { - u8 reg_val; - u8 reset_val; - int ret; int cw_capacity; - int charge_time; - int allow_change; - int allow_capacity; - long new_run_time; - long new_sleep_time; - long capacity_or_aconline_time; - static int if_quickstart; - static int jump_flag; + int ret; + unsigned char reg_val[2]; + static int reset_loop; - struct timespec ts; + static int charging_loop; + static int discharging_loop; + static int jump_flag; + static int charging_5_loop; + int sleep_cap; - ret = cw_read(cw_bat->client, REG_SOC, ®_val); + ret = cw_read_word(cw_bat->client, REG_SOC, reg_val); if (ret < 0) return ret; - cw_capacity = reg_val; - if (cw_capacity < 0 || cw_capacity > 100) { - dev_err(&cw_bat->client->dev, - "get cw_capacity error; cw_capacity = %d\n", - cw_capacity); - reset_loop++; + cw_capacity = reg_val[0]; - if (reset_loop > 5) { - reset_val = MODE_SLEEP; - ret = cw_write(cw_bat->client, REG_MODE, &reset_val); - if (ret < 0) - return ret; - reset_val = MODE_NORMAL; - msleep(10); - ret = cw_write(cw_bat->client, REG_MODE, &reset_val); - if (ret < 0) - return ret; - dev_info(&cw_bat->client->dev, - "report battery capacity error"); - ret = cw_update_config_info(cw_bat); - if (ret) - return ret; + if ((cw_capacity < 0) || (cw_capacity > 100)) { + cw_printk("Error: cw_capacity = %d\n", cw_capacity); + reset_loop++; + if (reset_loop > + (BATTERY_CAPACITY_ERROR / cw_bat->monitor_sec)) { + cw_por(cw_bat); reset_loop = 0; } - - return cw_capacity; + return cw_bat->capacity; } else { reset_loop = 0; } - ktime_get_ts(&ts); - new_run_time = ts.tv_sec; - - get_monotonic_boottime(&ts); - new_sleep_time = ts.tv_sec - new_run_time; - - /* modify battery level swing */ - if ((cw_bat->charger_mode > 0 && - cw_capacity <= (cw_bat->capacity - 1) && - cw_capacity > (cw_bat->capacity - 9)) || - (cw_bat->charger_mode == 0 && - cw_capacity == (cw_bat->capacity + 1))) { + /* case 1 : aviod swing */ + if (((cw_bat->charger_mode > 0) && + (cw_capacity <= cw_bat->capacity - 1) && + (cw_capacity > cw_bat->capacity - 9)) || + ((cw_bat->charger_mode == 0) && + (cw_capacity == (cw_bat->capacity + 1)))) { if (!(cw_capacity == 0 && cw_bat->capacity <= 2)) cw_capacity = cw_bat->capacity; } - /* avoid no charge full */ - if (cw_bat->charger_mode > 0 && - cw_capacity >= 95 && - cw_capacity <= cw_bat->capacity) { - 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; + /* case 2 : aviod no charge full */ + if ((cw_bat->charger_mode > 0) && + (cw_capacity >= 95) && (cw_capacity <= cw_bat->capacity)) { + cw_printk("Chaman join no charge full\n"); + charging_loop++; + if (charging_loop > + (BATTERY_UP_MAX_CHANGE / cw_bat->monitor_sec)) { + cw_capacity = (cw_bat->capacity + 1) <= 100 ? + (cw_bat->capacity + 1) : 100; + charging_loop = 0; jump_flag = 1; - } else if (cw_capacity <= cw_bat->capacity) { + } else { cw_capacity = cw_bat->capacity; } } - /* avoid battery level jump to CW_BAT */ - else if (cw_bat->charger_mode == 0 && - cw_capacity <= cw_bat->capacity && - cw_capacity >= 90 && jump_flag == 1) { - 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; - if (cw_capacity >= allow_capacity) { - jump_flag = 0; + + /* case 3 : avoid battery level jump to CW_BAT */ + if ((cw_bat->charger_mode == 0) && + (cw_capacity <= cw_bat->capacity) && + (cw_capacity >= 90) && (jump_flag == 1)) { + cw_printk("Chaman join no charge full discharging\n"); +#ifdef CONFIG_PM + if (cw_bat->suspend_resume_mark == 1) { + cw_bat->suspend_resume_mark = 0; + sleep_cap = (cw_bat->after.tv_sec + + discharging_loop * + (cw_bat->monitor_sec / 1000)) / + (BATTERY_DOWN_MAX_CHANGE / 1000); + cw_printk("sleep_cap = %d\n", sleep_cap); + + if (cw_capacity >= cw_bat->capacity - sleep_cap) { + return cw_capacity; } else { - cw_capacity = - (allow_capacity <= - 100) ? allow_capacity : 100; + if (!sleep_cap) + discharging_loop = discharging_loop + + 1 + cw_bat->after.tv_sec / + (cw_bat->monitor_sec / 1000); + else + discharging_loop = 0; + cw_printk("discharging_loop = %d\n", + discharging_loop); + return cw_bat->capacity - sleep_cap; } - } else if (cw_capacity <= cw_bat->capacity) { - cw_capacity = cw_bat->capacity; } - } +#endif + discharging_loop++; + if (discharging_loop > + (BATTERY_DOWN_MAX_CHANGE / cw_bat->monitor_sec)) { + if (cw_capacity >= cw_bat->capacity - 1) + jump_flag = 0; + else + cw_capacity = cw_bat->capacity - 1; - /* avoid battery level jump to 0% at a moment from more than 2% */ - if (cw_capacity == 0 && cw_bat->capacity > 1) { - 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; - dev_info(&cw_bat->client->dev, "report GGIC POR happened"); - reset_val = MODE_SLEEP; - ret = cw_write(cw_bat->client, REG_MODE, &reset_val); - if (ret < 0) - return ret; - reset_val = MODE_NORMAL; - msleep(10); - ret = cw_write(cw_bat->client, REG_MODE, &reset_val); - if (ret < 0) - return ret; - dev_info(&cw_bat->client->dev, "report battery capacity error"); - ret = cw_update_config_info(cw_bat); - if (ret) - return ret; - dev_info(&cw_bat->client->dev, - "report battery capacity jump 0 "); - } -#if 1 - if (cw_bat->charger_mode > 0 && cw_capacity == 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) { - reset_val = MODE_SLEEP; - ret = cw_write(cw_bat->client, REG_MODE, &reset_val); - if (ret < 0) - return ret; - reset_val = MODE_NORMAL; - msleep(10); - ret = cw_write(cw_bat->client, REG_MODE, &reset_val); - if (ret < 0) - return ret; - dev_info(&cw_bat->client->dev, - "report battery capacity error"); - ret = cw_update_config_info(cw_bat); - if (ret) - return ret; - dev_info(&cw_bat->client->dev, - "report battery capacity still 0 if in changing"); - if_quickstart = 1; + discharging_loop = 0; + } else { + cw_capacity = cw_bat->capacity; } - } else if (if_quickstart == 1 && cw_bat->charger_mode == 0) { - if_quickstart = 0; } -#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; + /* case 4 : avoid battery level is 0% when long time charging */ + if ((cw_bat->charger_mode > 0) && (cw_capacity == 0)) { + charging_5_loop++; + if (charging_5_loop > + BATTERY_CHARGING_ZERO / cw_bat->monitor_sec) { + cw_por(cw_bat); + charging_5_loop = 0; } - dev_info(&cw_bat->client->dev, - "voltage is less than shutdown voltage\n"); - } else if ((cw_bat->charger_mode > 0) && (if_quickstart <= 12)) { - if_quickstart = 0; + } else if (charging_5_loop != 0) { + charging_5_loop = 0; } +#ifdef CONFIG_PM + if (cw_bat->suspend_resume_mark == 1) + cw_bat->suspend_resume_mark = 0; #endif return cw_capacity; } -static int cw_get_vol(struct cw_battery *cw_bat) +static int cw_get_voltage(struct cw_battery *cw_bat) { int ret; u8 reg_val[2]; u16 value16, value16_1, value16_2, value16_3; int voltage; + int res1, res2; ret = cw_read_word(cw_bat->client, REG_VCELL, reg_val); if (ret < 0) @@ -561,39 +449,21 @@ static int cw_get_vol(struct cw_battery *cw_bat) value16_1 = value16_3; } - voltage = value16_1 * 305; + voltage = value16_1 * 312 / 1024; + + if (cw_bat->plat_data.divider_res1 && + cw_bat->plat_data.divider_res2) { + res1 = cw_bat->plat_data.divider_res1; + res2 = cw_bat->plat_data.divider_res2; + voltage = voltage * (res1 + res2) / res2; + } dev_dbg(&cw_bat->client->dev, "the cw201x voltage=%d,reg_val=%x %x\n", voltage, reg_val[0], reg_val[1]); return voltage; } -#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; - - value8 = value8 & 0x7f; - reg_val = value8; - ret = cw_write(cw_bat->client, REG_RRT_ALERT, ®_val); - if (ret < 0) { - dev_err(&cw_bat->client->dev, "Error clear ALRT\n"); - return ret; - } - - return alrt; -} -#endif - +/*This function called when get RRT from cw2015*/ static int cw_get_time_to_empty(struct cw_battery *cw_bat) { int ret; @@ -614,7 +484,18 @@ static int cw_get_time_to_empty(struct cw_battery *cw_bat) return value16; } -static void rk_bat_update_capacity(struct cw_battery *cw_bat) +static void cw_update_charge_status(struct cw_battery *cw_bat) +{ + int cw_charger_mode; + + cw_charger_mode = get_charge_state(cw_bat); + if (cw_bat->charger_mode != cw_charger_mode) { + cw_bat->charger_mode = cw_charger_mode; + cw_bat->bat_change = 1; + } +} + +static void cw_update_capacity(struct cw_battery *cw_bat) { int cw_capacity; @@ -623,24 +504,21 @@ static void rk_bat_update_capacity(struct cw_battery *cw_bat) (cw_bat->capacity != cw_capacity)) { cw_bat->capacity = cw_capacity; cw_bat->bat_change = 1; - cw_update_time_member_capacity_change(cw_bat); - - if (cw_bat->capacity == 0) - dev_info(&cw_bat->client->dev, - "report battery capacity 0 and will shutdown if no changing"); } } -static void rk_bat_update_vol(struct cw_battery *cw_bat) +static void cw_update_vol(struct cw_battery *cw_bat) { int ret; - ret = cw_get_vol(cw_bat); - if ((ret >= 0) && (cw_bat->voltage != ret)) + ret = cw_get_voltage(cw_bat); + if ((ret >= 0) && (cw_bat->voltage != ret)) { cw_bat->voltage = ret; + cw_bat->bat_change = 1; + } } -static void rk_bat_update_status(struct cw_battery *cw_bat) +static void cw_update_status(struct cw_battery *cw_bat) { int status; @@ -650,7 +528,7 @@ static void rk_bat_update_status(struct cw_battery *cw_bat) else status = POWER_SUPPLY_STATUS_CHARGING; } else { - status = POWER_SUPPLY_STATUS_NOT_CHARGING; + status = POWER_SUPPLY_STATUS_DISCHARGING; } if (cw_bat->status != status) { @@ -659,145 +537,15 @@ static void rk_bat_update_status(struct cw_battery *cw_bat) } } -static void rk_bat_update_time_to_empty(struct cw_battery *cw_bat) +static void cw_update_time_to_empty(struct cw_battery *cw_bat) { int ret; ret = cw_get_time_to_empty(cw_bat); - if ((ret >= 0) && (cw_bat->time_to_empty != ret)) + if ((ret >= 0) && (cw_bat->time_to_empty != ret)) { cw_bat->time_to_empty = ret; -} - -static int rk_ac_update_online(struct cw_battery *cw_bat) -{ - int ret = 0; - - if (!gpio_is_valid(cw_bat->plat_data.dc_det_pin)) { - cw_bat->dc_online = 0; - pr_info("%s dc charger without dc_det_pin\n", __func__); - return 0; - } - - 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_charge_start(cw_bat); - cw_bat->dc_online = 1; - if (cw_bat->charger_mode != AC_CHARGER_MODE) - cw_bat->charger_mode = AC_CHARGER_MODE; - - ret = 1; - } - } else { - if (cw_bat->dc_online != 0) { - cw_update_time_member_charge_start(cw_bat); - cw_bat->dc_online = 0; - if (cw_bat->usb_online == 0) - cw_bat->charger_mode = 0; - ret = 1; - } - } - return ret; -} - -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(); - - 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 - - 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); - - return usb_status; -} - -static int rk_usb_update_online(struct cw_battery *cw_bat) -{ - int gpio; - int value; - int ret = 0; - int usb_status = 0; - - gpio = cw_bat->plat_data.chg_mode_sel_pin; - value = cw_bat->plat_data.chg_mode_sel_level; - 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 (gpio_is_valid(gpio)) { - if (gpio_get_value(gpio) != value) - gpio_direction_output(gpio, value); - } - - 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 (gpio_is_valid(gpio)) { - if (gpio_get_value(gpio) == value) - gpio_direction_output(gpio, !value); - } - 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 (gpio_is_valid(gpio)) { - if (gpio_get_value(gpio) == value) - gpio_direction_output(gpio, !value); - } - - 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; + cw_bat->bat_change = 1; } - - return ret; } static void cw_bat_work(struct work_struct *work) @@ -805,105 +553,69 @@ static void cw_bat_work(struct work_struct *work) struct delayed_work *delay_work; struct cw_battery *cw_bat; int ret; + u8 reg_val; + int i = 0; delay_work = container_of(work, struct delayed_work, work); cw_bat = - container_of(delay_work, struct cw_battery, battery_delay_work); - - if (cw_bat->plat_data.is_dc_charge == 1) { - ret = rk_ac_update_online(cw_bat); - if (ret == 1) - power_supply_changed(&cw_bat->rk_ac); - } + container_of(delay_work, struct cw_battery, battery_delay_work); - if (cw_bat->plat_data.is_usb_charge == 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); + /* Add for battery swap start */ + ret = cw_read(cw_bat->client, REG_MODE, ®_val); + if (ret < 0) { + cw_bat->bat_mode = MODE_VIRTUAL; + cw_bat->bat_change = 1; + } else { + if ((reg_val & MODE_SLEEP_MASK) == MODE_SLEEP) { + for (i = 0; i < 5; i++) { + if (cw_por(cw_bat) == 0) + break; + } } - } + cw_update_capacity(cw_bat); + cw_update_vol(cw_bat); + cw_update_charge_status(cw_bat); + cw_update_status(cw_bat); + cw_update_time_to_empty(cw_bat); + } + /* Add for battery swap end */ + cw_printk("charger_mod = %d\n", cw_bat->charger_mode); + cw_printk("status = %d\n", cw_bat->status); + cw_printk("capacity = %d\n", cw_bat->capacity); + cw_printk("voltage = %d\n", cw_bat->voltage); - rk_bat_update_status(cw_bat); - rk_bat_update_capacity(cw_bat); - rk_bat_update_vol(cw_bat); - rk_bat_update_time_to_empty(cw_bat); +#ifdef CONFIG_PM + if (cw_bat->suspend_resume_mark == 1) + cw_bat->suspend_resume_mark = 0; +#endif - if (cw_bat->bat_change) { - power_supply_changed(&cw_bat->rk_bat); + if (cw_bat->bat_change == 1) { + power_supply_changed(cw_bat->rk_bat); cw_bat->bat_change = 0; } - queue_delayed_work(cw_bat->battery_workqueue, - &cw_bat->battery_delay_work, msecs_to_jiffies(1000)); - - dev_dbg(&cw_bat->client->dev, - "cw_bat->bat_change = %d, cw_bat->time_to_empty = %d, cw_bat->capacity = %d\n", - cw_bat->bat_change, cw_bat->time_to_empty, cw_bat->capacity); - - dev_dbg(&cw_bat->client->dev, - "cw_bat->voltage = %d, cw_bat->dc_online = %d, cw_bat->usb_online = %d\n", - cw_bat->voltage, cw_bat->dc_online, cw_bat->usb_online); + &cw_bat->battery_delay_work, + msecs_to_jiffies(cw_bat->monitor_sec)); } -static int rk_usb_get_property(struct power_supply *psy, - enum power_supply_property psp, - union power_supply_propval *val) -{ - int ret = 0; - struct cw_battery *cw_bat; - - cw_bat = container_of(psy, struct cw_battery, rk_usb); - switch (psp) { - case POWER_SUPPLY_PROP_ONLINE: - val->intval = (cw_bat->charger_mode == USB_CHARGER_MODE); - break; - default: - break; - } - return ret; -} - -static enum power_supply_property rk_usb_properties[] = { - POWER_SUPPLY_PROP_ONLINE, -}; - -static int rk_ac_get_property(struct power_supply *psy, - enum power_supply_property psp, - union power_supply_propval *val) -{ - int ret = 0; - struct cw_battery *cw_bat; - - cw_bat = container_of(psy, struct cw_battery, rk_ac); - switch (psp) { - case POWER_SUPPLY_PROP_ONLINE: - val->intval = (cw_bat->charger_mode == AC_CHARGER_MODE); - break; - default: - break; - } - return ret; -} - -static enum power_supply_property rk_ac_properties[] = { - POWER_SUPPLY_PROP_ONLINE, -}; - -static int rk_battery_get_property(struct power_supply *psy, +static int cw_battery_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { int ret = 0; struct cw_battery *cw_bat; - cw_bat = container_of(psy, struct cw_battery, rk_bat); + cw_bat = power_supply_get_drvdata(psy); switch (psp) { case POWER_SUPPLY_PROP_CAPACITY: val->intval = cw_bat->capacity; + if (cw_bat->bat_mode == MODE_VIRTUAL) + val->intval = VIRTUAL_SOC; break; case POWER_SUPPLY_PROP_STATUS: val->intval = cw_bat->status; + if (cw_bat->bat_mode == MODE_VIRTUAL) + val->intval = VIRTUAL_STATUS; break; case POWER_SUPPLY_PROP_HEALTH: @@ -911,14 +623,20 @@ static int rk_battery_get_property(struct power_supply *psy, break; case POWER_SUPPLY_PROP_PRESENT: val->intval = cw_bat->voltage <= 0 ? 0 : 1; + if (cw_bat->bat_mode == MODE_VIRTUAL) + val->intval = VIRTUAL_PRESET; break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: - val->intval = cw_bat->voltage; + val->intval = cw_bat->voltage * 1000; + if (cw_bat->bat_mode == MODE_VIRTUAL) + val->intval = VIRTUAL_VOLTAGE * 1000; break; case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: val->intval = cw_bat->time_to_empty; + if (cw_bat->bat_mode == MODE_VIRTUAL) + val->intval = VIRTUAL_TIME2EMPTY; break; case POWER_SUPPLY_PROP_TECHNOLOGY: @@ -931,7 +649,7 @@ static int rk_battery_get_property(struct power_supply *psy, return ret; } -static enum power_supply_property rk_battery_properties[] = { +static enum power_supply_property cw_battery_properties[] = { POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_HEALTH, @@ -941,166 +659,24 @@ static enum power_supply_property rk_battery_properties[] = { POWER_SUPPLY_PROP_TECHNOLOGY, }; -static int cw_bat_gpio_init(struct cw_battery *cw_bat) -{ - int ret; - - if (gpio_is_valid(cw_bat->plat_data.dc_det_pin)) { - ret = gpio_request(cw_bat->plat_data.dc_det_pin, NULL); - if (ret) { - dev_err(&cw_bat->client->dev, - "failed to request dc_det_pin gpio\n"); - goto request_dc_det_pin_fail; - } - ret = gpio_direction_input(cw_bat->plat_data.dc_det_pin); - if (ret) { - dev_err(&cw_bat->client->dev, - "failed to set dc_det_pin input\n"); - goto request_bat_low_pin_fail; - } - } - if (gpio_is_valid(cw_bat->plat_data.bat_low_pin)) { - ret = gpio_request(cw_bat->plat_data.bat_low_pin, NULL); - if (ret) { - dev_err(&cw_bat->client->dev, - "failed to request bat_low_pin gpio\n"); - goto request_bat_low_pin_fail; - } - - ret = gpio_direction_input(cw_bat->plat_data.bat_low_pin); - if (ret) { - dev_err(&cw_bat->client->dev, - "failed to set bat_low_pin input\n"); - goto request_bat_low_pin_fail; - } - } - if (gpio_is_valid(cw_bat->plat_data.chg_ok_pin)) { - ret = gpio_request(cw_bat->plat_data.chg_ok_pin, NULL); - if (ret) { - dev_err(&cw_bat->client->dev, - "failed to request chg_ok_pin gpio\n"); - goto request_chg_ok_pin_fail; - } - - ret = gpio_direction_input(cw_bat->plat_data.chg_ok_pin); - if (ret) { - 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 ((gpio_is_valid(cw_bat->plat_data.chg_mode_sel_pin))) { - ret = gpio_request(cw_bat->plat_data.chg_mode_sel_pin, NULL); - if (ret) { - dev_err(&cw_bat->client->dev, - "failed to request chg_mode_sel_pin gpio\n"); - goto request_chg_mode_sel_pin_fail; - } - ret = - gpio_direction_output(cw_bat->plat_data.chg_mode_sel_pin, - (cw_bat->plat_data. - chg_mode_sel_level == - CW2015_GPIO_LOW) ? CW2015_GPIO_HIGH : - CW2015_GPIO_LOW); - if (ret) { - dev_err(&cw_bat->client->dev, - "failed to set chg_mode_sel_pin output\n"); - gpio_free(cw_bat->plat_data.chg_mode_sel_pin); - goto request_chg_mode_sel_pin_fail; - } - } - - return 0; - -request_chg_mode_sel_pin_fail: - gpio_free(cw_bat->plat_data.chg_mode_sel_pin); -request_chg_ok_pin_fail: - if (gpio_is_valid(cw_bat->plat_data.bat_low_pin)) - gpio_free(cw_bat->plat_data.bat_low_pin); -request_bat_low_pin_fail: - if (gpio_is_valid(cw_bat->plat_data.dc_det_pin)) - gpio_free(cw_bat->plat_data.dc_det_pin); -request_dc_det_pin_fail: - - return ret; -} - -static void dc_detect_do_wakeup(struct work_struct *work) -{ - int ret; - int irq; - unsigned int type; - - 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, dc_wakeup_work); - - rk_send_wakeup_key(); - - 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; - ret = irq_set_irq_type(irq, type); - if (ret < 0) { - pr_err("%s: irq_set_irq_type(%d, %d) failed\n", __func__, irq, - type); - } - enable_irq(irq); -} - -static irqreturn_t dc_detect_irq_handler(int irq, void *dev_id) -{ - struct cw_battery *cw_bat = dev_id; - - /* for irq debounce */ - disable_irq_nosync(irq); - 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 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); -} - -static irqreturn_t bat_low_detect_irq_handler(int irq, void *dev_id) -{ - struct cw_battery *cw_bat = dev_id; - - queue_delayed_work(cw_bat->battery_workqueue, - &cw_bat->bat_low_wakeup_work, msecs_to_jiffies(20)); - return IRQ_HANDLED; -} -#endif +static const struct power_supply_desc cw2015_bat_desc = { + .name = "rk-bat", + .type = POWER_SUPPLY_TYPE_BATTERY, + .properties = cw_battery_properties, + .num_properties = ARRAY_SIZE(cw_battery_properties), + .get_property = cw_battery_get_property, +}; #ifdef CONFIG_OF -static int cw2015_parse_dt(struct device *dev, - struct cw_bat_platform_data *data) +static int cw2015_parse_dt(struct cw_battery *cw_bat) { + struct device *dev = &cw_bat->client->dev; struct device_node *node = dev->of_node; - enum of_gpio_flags flags; struct property *prop; int length; u32 value; int ret; + struct cw_bat_platform_data *data = &cw_bat->plat_data; if (!node) return -ENODEV; @@ -1128,69 +704,34 @@ static int cw2015_parse_dt(struct device *dev, return ret; } - data->dc_det_pin = of_get_named_gpio_flags(node, "dc_det_gpio", 0, - &flags); - if (data->dc_det_pin == -EPROBE_DEFER) - pr_info("%s dc_det_gpio error\n", __func__); - - if (gpio_is_valid(data->dc_det_pin)) - data->dc_det_level = - (flags & OF_GPIO_ACTIVE_LOW) ? CW2015_GPIO_LOW : - CW2015_GPIO_HIGH; - - data->bat_low_pin = of_get_named_gpio_flags(node, "bat_low_gpio", 0, - &flags); - if (data->bat_low_pin == -EPROBE_DEFER) - pr_info("%s bat_low_gpio error\n", __func__); - - if (gpio_is_valid(data->bat_low_pin)) - data->bat_low_level = - (flags & OF_GPIO_ACTIVE_LOW) ? CW2015_GPIO_LOW : - CW2015_GPIO_HIGH; - - data->chg_ok_pin = of_get_named_gpio_flags(node, "chg_ok_gpio", 0, - &flags); - if (data->chg_ok_pin == -EPROBE_DEFER) - pr_info("%s chg_ok_gpio error\n", __func__); - - if (gpio_is_valid(data->chg_ok_pin)) - data->chg_ok_level = - (flags & OF_GPIO_ACTIVE_LOW) ? CW2015_GPIO_LOW : - CW2015_GPIO_HIGH; - - data->chg_mode_sel_pin = - of_get_named_gpio_flags(node, "chg_mode_sel_gpio", 0, &flags); - if (data->chg_mode_sel_pin == -EPROBE_DEFER) - pr_info("%s chg_mod_sel_gpio error\n", __func__); - - if (gpio_is_valid(data->chg_mode_sel_pin)) - data->chg_mode_sel_level = - (flags & OF_GPIO_ACTIVE_LOW) ? CW2015_GPIO_LOW : - CW2015_GPIO_HIGH; - - ret = of_property_read_u32(node, "is_dc_charge", &value); - if (ret < 0) { - pr_info("%s:hardware unsupport dc charge\n", __func__); + cw_bat->bat_mode = MODE_BATTARY; + cw_bat->monitor_sec = DEFAULT_MONITOR_SEC * TIMER_MS_COUNTS; + + ret = of_property_read_u32(node, "divider_res1", &value); + if (ret < 0) value = 0; - } - data->is_dc_charge = value; + data->divider_res1 = value; - ret = of_property_read_u32(node, "is_usb_charge", &value); - if (ret < 0) { - pr_info("%s:hardware unsupport usb charge\n", __func__); + ret = of_property_read_u32(node, "divider_res2", &value); + if (ret < 0) value = 0; - } - data->is_usb_charge = value; + data->divider_res2 = value; + + ret = of_property_read_u32(node, "virtual_power", &value); + if (ret < 0) + value = 0; + cw_bat->bat_mode = value; - pr_info("cw201x:support %s %s charger\n", - data->is_dc_charge ? "DC" : "", - data->is_usb_charge ? "USB" : ""); + ret = of_property_read_u32(node, "monitor_sec", &value); + if (ret < 0) + dev_err(dev, "monitor_sec missing!\n"); + else + cw_bat->monitor_sec = value * TIMER_MS_COUNTS; return 0; } #else -static int cw2015_parse_dt(struct device *dev, - struct cw_bat_platform_data *data) +static int cw2015_parse_dt(struct cw_battery *cw_bat) { return -ENODEV; } @@ -1199,36 +740,33 @@ static int cw2015_parse_dt(struct device *dev, static int cw_bat_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct cw_battery *cw_bat; - struct cw_bat_platform_data *plat_data = client->dev.platform_data; int ret; - int irq; - int irq_flags; - int level = 0; + struct cw_battery *cw_bat; + struct power_supply_config psy_cfg = {0}; cw_bat = devm_kzalloc(&client->dev, sizeof(*cw_bat), GFP_KERNEL); if (!cw_bat) { - dev_err(&cw_bat->client->dev, + dev_err(&client->dev, "fail to allocate memory for cw2015\n"); return -ENOMEM; } + i2c_set_clientdata(client, cw_bat); + cw_bat->client = client; - if (!plat_data) { - ret = cw2015_parse_dt(&client->dev, &(cw_bat->plat_data)); - if (ret < 0) { - dev_err(&client->dev, - "failed to find cw2015 platform data\n"); - goto pdate_fail; - } + ret = cw2015_parse_dt(cw_bat); + if (ret < 0) { + dev_err(&client->dev, + "failed to find cw2015 platform data\n"); + return -1; } - cw_bat->client = client; - ret = cw_bat_gpio_init(cw_bat); - if (ret) { - dev_err(&cw_bat->client->dev, "cw_bat_gpio_init error\n"); - return ret; - } + cw_bat->capacity = 1; + cw_bat->voltage = 0; + cw_bat->status = 0; + cw_bat->suspend_resume_mark = 0; + cw_bat->charger_mode = NO_CHARGING; + cw_bat->bat_change = 0; ret = cw_init(cw_bat); if (ret) { @@ -1236,169 +774,79 @@ static int cw_bat_probe(struct i2c_client *client, return ret; } - cw_bat->rk_bat.name = "rk-bat"; - cw_bat->rk_bat.type = POWER_SUPPLY_TYPE_BATTERY; - cw_bat->rk_bat.properties = rk_battery_properties; - cw_bat->rk_bat.num_properties = ARRAY_SIZE(rk_battery_properties); - cw_bat->rk_bat.get_property = rk_battery_get_property; - ret = power_supply_register(&client->dev, &cw_bat->rk_bat); - if (ret < 0) { - dev_err(&cw_bat->client->dev, - "power supply register rk_bat error\n"); - goto rk_bat_register_fail; - } + psy_cfg.drv_data = cw_bat; - cw_bat->rk_ac.name = "rk-ac"; - cw_bat->rk_ac.type = POWER_SUPPLY_TYPE_MAINS; - cw_bat->rk_ac.properties = rk_ac_properties; - cw_bat->rk_ac.num_properties = ARRAY_SIZE(rk_ac_properties); - cw_bat->rk_ac.get_property = rk_ac_get_property; - ret = power_supply_register(&client->dev, &cw_bat->rk_ac); - if (ret < 0) { + cw_bat->rk_bat = devm_power_supply_register(&client->dev, + &cw2015_bat_desc, &psy_cfg); + if (IS_ERR(cw_bat->rk_bat)) { dev_err(&cw_bat->client->dev, - "power supply register rk_ac error\n"); - goto rk_ac_register_fail; - } - - if (cw_bat->plat_data.is_usb_charge == 1) { - cw_bat->rk_usb.name = "rk-usb"; - cw_bat->rk_usb.type = POWER_SUPPLY_TYPE_USB; - cw_bat->rk_usb.properties = rk_usb_properties; - cw_bat->rk_usb.num_properties = ARRAY_SIZE(rk_usb_properties); - cw_bat->rk_usb.get_property = rk_usb_get_property; - ret = power_supply_register(&client->dev, &cw_bat->rk_usb); - if (ret < 0) { - dev_err(&cw_bat->client->dev, - "power supply register rk_usb error\n"); - goto rk_usb_register_fail; - } - cw_bat->charger_init_mode = dwc_otg_check_dpdm(); - pr_info("%s cw2015 support charger by usb. usb_mode=%d\n", - __func__, cw_bat->charger_init_mode); + "power supply register rk_bat error\n"); + return -1; } - cw_bat->dc_online = 0; - cw_bat->usb_online = 0; - cw_bat->charger_mode = 0; - cw_bat->capacity = 1; - cw_bat->voltage = 0; - cw_bat->status = 0; - cw_bat->time_to_empty = 0; - cw_bat->bat_change = 0; - - 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)); - if (gpio_is_valid(cw_bat->plat_data.dc_det_pin)) { - irq = gpio_to_irq(cw_bat->plat_data.dc_det_pin); - level = gpio_get_value(cw_bat->plat_data.dc_det_pin); - if (level == cw_bat->plat_data.dc_det_level) { - pr_info("%s booting up with dc plug\n", __func__); - cw_bat->status = POWER_SUPPLY_STATUS_CHARGING; - } - irq_flags = level ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING; - ret = - request_irq(irq, dc_detect_irq_handler, irq_flags, - "dc_detect", cw_bat); - if (ret < 0) - pr_err("%s: request_irq(%d) failed\n", __func__, irq); - enable_irq_wake(irq); - } - - if (gpio_is_valid(cw_bat->plat_data.bat_low_pin)) { - INIT_DELAYED_WORK(&cw_bat->bat_low_wakeup_work, - bat_low_detect_do_wakeup); - level = gpio_get_value(cw_bat->plat_data.bat_low_pin); - if (level == cw_bat->plat_data.dc_det_level) { - pr_info("%s booting up with lower power\n", __func__); - cw_bat->capacity = 1; - } - 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); - } - dev_info(&cw_bat->client->dev, "cw2015/cw2013 driver v1.2 probe sucess\n"); return 0; - -rk_usb_register_fail: - power_supply_unregister(&cw_bat->rk_usb); -rk_ac_register_fail: - power_supply_unregister(&cw_bat->rk_ac); -rk_bat_register_fail: - power_supply_unregister(&cw_bat->rk_bat); -pdate_fail: - 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) +#ifdef CONFIG_PM +static int cw_bat_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct cw_battery *cw_bat = i2c_get_clientdata(client); - - dev_dbg(&cw_bat->client->dev, "%s\n", __func__); + read_persistent_clock(&cw_bat->suspend_time_before); cancel_delayed_work(&cw_bat->battery_delay_work); return 0; } -#ifdef CONFIG_PM -static int cw_bat_suspend(struct device *dev) +static int cw_bat_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct cw_battery *cw_bat = i2c_get_clientdata(client); - - dev_dbg(&cw_bat->client->dev, "%s\n", __func__); - cancel_delayed_work(&cw_bat->battery_delay_work); + cw_bat->suspend_resume_mark = 1; + read_persistent_clock(&cw_bat->after); + cw_bat->after = timespec_sub(cw_bat->after, + cw_bat->suspend_time_before); + queue_delayed_work(cw_bat->battery_workqueue, + &cw_bat->battery_delay_work, msecs_to_jiffies(2)); return 0; } -static int cw_bat_resume(struct device *dev) +static const struct dev_pm_ops cw_bat_pm_ops = { + .suspend = cw_bat_suspend, + .resume = cw_bat_resume, +}; +#endif + +static int cw_bat_remove(struct i2c_client *client) { - struct i2c_client *client = to_i2c_client(dev); struct cw_battery *cw_bat = i2c_get_clientdata(client); 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)); + cancel_delayed_work(&cw_bat->battery_delay_work); return 0; } -static const struct i2c_device_id cw_id[] = { +static const struct i2c_device_id cw_bat_id_table[] = { {"cw201x", 0}, {} }; -MODULE_DEVICE_TABLE(i2c, cw_id); - -static const struct dev_pm_ops cw_bat_pm_ops = { - .suspend = cw_bat_suspend, - .resume = cw_bat_resume, -}; -#endif static struct i2c_driver cw_bat_driver = { .driver = { - .name = "cw201x", + .name = "cw201x", #ifdef CONFIG_PM - .pm = &cw_bat_pm_ops, + .pm = &cw_bat_pm_ops, #endif - }, - + }, .probe = cw_bat_probe, .remove = cw_bat_remove, - .id_table = cw_id, + .id_table = cw_bat_id_table, }; static int __init cw_bat_init(void) @@ -1411,7 +859,7 @@ static void __exit cw_bat_exit(void) i2c_del_driver(&cw_bat_driver); } -fs_initcall(cw_bat_init); +module_init(cw_bat_init); module_exit(cw_bat_exit); MODULE_AUTHOR("xhc"); diff --git a/include/linux/power/cw2015_battery.h b/include/linux/power/cw2015_battery.h index 6f14aa71d00e..1e3703eff2f5 100644 --- a/include/linux/power/cw2015_battery.h +++ b/include/linux/power/cw2015_battery.h @@ -38,11 +38,20 @@ #define CONFIG_UPDATE_FLG (0x1<<1) #define ATHD (0x0<<3) -#define CW_I2C_SPEED 100000 -#define BATTERY_UP_MAX_CHANGE 420 -#define BATTERY_DOWN_CHANGE 60 -#define BATTERY_DOWN_MIN_CHANGE_RUN 30 -#define BATTERY_DOWN_MIN_CHANGE_SLEEP 1800 +#define CW_I2C_SPEED 100000 +#define BATTERY_UP_MAX_CHANGE (420 * 1000) +#define BATTERY_DOWN_MAX_CHANGE (120 * 1000) +#define BATTERY_DOWN_CHANGE 60 +#define BATTERY_DOWN_MIN_CHANGE_RUN 30 +#define BATTERY_DOWN_MIN_CHANGE_SLEEP 1800 +#define BATTERY_JUMP_TO_ZERO (30 * 1000) +#define BATTERY_CAPACITY_ERROR (40 * 1000) +#define BATTERY_CHARGING_ZERO (1800 * 1000) + +#define DOUBLE_SERIES_BATTERY 0 + +#define CHARGING_ON 1 +#define NO_CHARGING 0 #define BATTERY_DOWN_MAX_CHANGE_RUN_AC_ONLINE 3600 @@ -54,19 +63,26 @@ #define AC_CHARGER_MODE 2 #define CW_QUICKSTART 0 +#define TIMER_MS_COUNTS 1000 +#define DEFAULT_MONITOR_SEC 8 + +/* virtual params */ +#define VIRTUAL_CURRENT 1000 +#define VIRTUAL_VOLTAGE 3888 +#define VIRTUAL_SOC 66 +#define VIRTUAL_PRESET 1 +#define VIRTUAL_TEMPERATURE 188 +#define VIRTUAL_TIME2EMPTY 60 +#define VIRTUAL_STATUS POWER_SUPPLY_STATUS_CHARGING + +enum bat_mode { + MODE_BATTARY = 0, + MODE_VIRTUAL, +}; + struct cw_bat_platform_data { - int is_dc_charge; - int dc_det_pin; - int dc_det_level; - - int is_usb_charge; - int chg_mode_sel_pin; - int chg_mode_sel_level; - - int bat_low_pin; - int bat_low_level; - int chg_ok_pin; - int chg_ok_level; + int divider_res1; + int divider_res2; u32 *cw_bat_config_info; }; @@ -74,52 +90,27 @@ struct cw_battery { struct i2c_client *client; struct workqueue_struct *battery_workqueue; struct delayed_work battery_delay_work; - struct delayed_work dc_wakeup_work; - struct delayed_work bat_low_wakeup_work; 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_change; - long run_time_capacity_change; + struct power_supply *rk_bat; - long sleep_time_charge_start; - long run_time_charge_start; + struct power_supply *chrg_usb_psy; + struct power_supply *chrg_ac_psy; - int dc_online; - int usb_online; +#ifdef CONFIG_PM + struct timespec suspend_time_before; + struct timespec after; + int suspend_resume_mark; +#endif int charger_mode; - int charger_init_mode; int capacity; int voltage; int status; int time_to_empty; int alt; - + u32 monitor_sec; + u32 bat_mode; int bat_change; }; -#if defined(CONFIG_ARCH_ROCKCHIP) -int get_gadget_connect_flag(void); -int dwc_otg_check_dpdm(void); -int dwc_vbus_status(void); -#else -static inline int get_gadget_connect_flag(void) -{ - return 0; -} - -static inline int dwc_otg_check_dpdm(bool wait) -{ - return 0; -} - -static inline int dwc_vbus_status(void); -{ - return 0; -} -#endif - #endif -- 2.34.1