*
*/
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
-#include <linux/platform_device.h>
-#include <linux/power_supply.h>
-#include <linux/workqueue.h>
-#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
#include <linux/i2c.h>
+#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/time.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/rk_keys.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
#include <linux/slab.h>
+#include <linux/workqueue.h>
#include <linux/power/cw2015_battery.h>
-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);
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;
}
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 */
if (ret < 0)
return ret;
+ cw_printk("cw2015 update config success!\n");
+
return 0;
}
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;
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) {
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)
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;
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;
(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;
else
status = POWER_SUPPLY_STATUS_CHARGING;
} else {
- status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ status = POWER_SUPPLY_STATUS_DISCHARGING;
}
if (cw_bat->status != status) {
}
}
-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)
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:
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:
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,
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;
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;
}
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) {
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)
i2c_del_driver(&cw_bat_driver);
}
-fs_initcall(cw_bat_init);
+module_init(cw_bat_init);
module_exit(cw_bat_exit);
MODULE_AUTHOR("xhc<xhc@rock-chips.com>");