diff --git a/drivers/power/sd77426_fg_mmi/Android.mk b/drivers/power/sd77426_fg_mmi/Android.mk new file mode 100644 index 000000000000..b115b9f10768 --- /dev/null +++ b/drivers/power/sd77426_fg_mmi/Android.mk @@ -0,0 +1,8 @@ +DLKM_DIR := motorola/kernel/modules +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := sd77426_fg_mmi.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/AndroidKernelModule.mk diff --git a/drivers/power/sd77426_fg_mmi/Kbuild b/drivers/power/sd77426_fg_mmi/Kbuild new file mode 100644 index 000000000000..fe11c32b0770 --- /dev/null +++ b/drivers/power/sd77426_fg_mmi/Kbuild @@ -0,0 +1,10 @@ +# add -Wall to try to catch everything we can. +EXTRA_CFLAGS += -Wall +EXTRA_CFLAGS += -I$(ANDROID_BUILD_TOP)/motorola/kernel/modules/include +EXTRA_CFLAGS += -I$(ANDROID_BUILD_TOP)/motorola/kernel/drivers/power/sd77426_fg_mmi + +sd77426_fg_mmi-objs += oz8806_battery.o +sd77426_fg_mmi-objs += parameter.o +sd77426_fg_mmi-objs += table.o +sd77426_fg_mmi-objs += bmulib.o +obj-m += sd77426_fg_mmi.o diff --git a/drivers/power/sd77426_fg_mmi/Makefile b/drivers/power/sd77426_fg_mmi/Makefile new file mode 100644 index 000000000000..62a13fd28500 --- /dev/null +++ b/drivers/power/sd77426_fg_mmi/Makefile @@ -0,0 +1,11 @@ +KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build + +all: + $(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS) + +modules_install: + $(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(shell pwd) modules_install + +clean: + $(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean + diff --git a/drivers/power/sd77426_fg_mmi/battery_config.h b/drivers/power/sd77426_fg_mmi/battery_config.h new file mode 100644 index 000000000000..63595b5f8f36 --- /dev/null +++ b/drivers/power/sd77426_fg_mmi/battery_config.h @@ -0,0 +1,43 @@ +/***************************************************************************** +* Copyright(c) O2Micro, 2019. All rights reserved. +* +* O2Micro [OZ8806] Source Code Reference Design +* File:[battery_config.h] +* +* This Source Code Reference Design for O2MICRO [OZ8806] access +* ("Reference Design") is solely for the use of PRODUCT INTEGRATION REFERENCE ONLY, +* and contains confidential and privileged information of O2Micro International +* Limited. O2Micro shall have no liability to any PARTY FOR THE RELIABILITY, +* SERVICEABILITY FOR THE RESULT OF PRODUCT INTEGRATION, or results from: (i) any +* modification or attempted modification of the Reference Design by any party, or +* (ii) the combination, operation or use of the Reference Design with non-O2Micro +* Reference Design. Use of the Reference Design is at user's discretion to qualify +* the final work result. +*****************************************************************************/ + +#ifndef __O2_BATTERY_CONFIG_H +#define __O2_BATTERY_CONFIG_H __FILE__ + + +#define OZ88106_I2C_NUM 2 + +//#define EXT_THERMAL_READ + +#define OZ8806_VOLTAGE 4350 +#define O2_CONFIG_CAPACITY 5158 +#define O2_CONFIG_RSENSE 20 +#define O2_CONFIG_EOC 200 +#define OZ8806_EOD 3400 +#define O2_CONFIG_BOARD_OFFSET 12 +#define O2_SOC_START_THRESHOLD_VOL 3700 +#define O2_CONFIG_RECHARGE 100 +#define O2_TEMP_PULL_UP_R 121000 //121K +#define O2_TEMP_REF_VOLTAGE 1800 //mv +#define BATTERY_WORK_INTERVAL 10 + +#define RPULL (68000) +#define RDOWN (5100) + +#define ENABLE_10MIN_END_CHARGE_FUN + +#endif diff --git a/drivers/power/sd77426_fg_mmi/bmulib.o b/drivers/power/sd77426_fg_mmi/bmulib.o new file mode 100644 index 000000000000..907a72a03a92 Binary files /dev/null and b/drivers/power/sd77426_fg_mmi/bmulib.o differ diff --git a/drivers/power/sd77426_fg_mmi/oz8806_battery.c b/drivers/power/sd77426_fg_mmi/oz8806_battery.c new file mode 100644 index 000000000000..0ab63a9bc164 --- /dev/null +++ b/drivers/power/sd77426_fg_mmi/oz8806_battery.c @@ -0,0 +1,1633 @@ +/***************************************************************************** +* Copyright(c) O2Micro, 2019. All rights reserved. +* +* O2Micro [OZ8806] Source Code Reference Design +* File:[oz8806_battery.c] +* +* This Source Code Reference Design for O2MICRO [OZ8806] access +* ("Reference Design") is solely for the use of PRODUCT INTEGRATION REFERENCE ONLY, +* and contains confidential and privileged information of O2Micro International +* Limited. O2Micro shall have no liability to any PARTY FOR THE RELIABILITY, +* SERVICEABILITY FOR THE RESULT OF PRODUCT INTEGRATION, or results from: (i) any +* modification or attempted modification of the Reference Design by any party, or +* (ii) the combination, operation or use of the Reference Design with non-O2Micro +* Reference Design. Use of the Reference Design is at user's discretion to qualify +* the final work result. +*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include + +//you must add these here for O2MICRO +#include "parameter.h" +#include "table.h" +#include "battery_config.h" +#include "oz8806_regdef.h" + +#define batt_dbg(fmt, args...) printk(KERN_ERR"[oz8806]:"pr_fmt(fmt)"\n", ## args) + +/***************************************************************************** +* static variables/functions section +****************************************************************************/ +static int fg_hw_init_done = 0; +static uint8_t bmu_init_done = 0; +static int oz8806_suspend = 0; +static DEFINE_MUTEX(update_mutex); +static bmu_data_t *batt_info_ptr = NULL; +static gas_gauge_t *gas_gauge_ptr = NULL; +static uint8_t charger_finish = 0; +static unsigned long ic_wakeup_time = 0; +static int init_soc = 0; +static void (*bmu_polling_loop_callback)(void) = NULL; +static void (*bmu_wake_up_chip_callback)(void) = NULL; +static void (*bmu_power_down_chip_callback)(void) = NULL; +static void (*bmu_charge_end_process_callback)(void) = NULL; +static void (*bmu_discharge_end_process_callback)(void) = NULL; +static int32_t (*oz8806_temp_read_callback)(int32_t *voltage) = NULL; +static int32_t (*oz8806_current_read_callback)(int32_t *voltage) = NULL; +static int32_t (*oz8806_voltage_read_callback)(int32_t *voltage) = NULL; + +static int oz8806_update_batt_info(struct oz8806_data *data); +static int oz8806_update_batt_temp(struct oz8806_data *data); +static int32_t oz8806_write_byte(struct oz8806_data *data, uint8_t index, uint8_t dat); +static int32_t oz8806_read_byte(struct oz8806_data *data, uint8_t index, uint8_t *dat); + +static struct oz8806_data *the_oz8806 = NULL; +static int8_t adapter_status = O2_CHARGER_BATTERY; +static int32_t rsoc_pre = 0; +#ifdef EXT_THERMAL_READ +static uint8_t ext_thermal_read = 1; +#else +static uint8_t ext_thermal_read = 0; +#endif +static int capacity_init_ok = 0; + +static int save_capacity = INIT_CAP; + +static enum power_supply_property oz8806_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, + POWER_SUPPLY_PROP_ENERGY_NOW, + //POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, + //POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, + //POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, +}; + +/*-------------------------------------------------------------------------*/ +/***************************************************************************** +* Description: +* below function is linux power section +* Parameters: +* description for each argument, new argument starts at new line +* Return: +* what does this function returned? +*****************************************************************************/ +/*-------------------------------------------------------------------------*/ + +static int oz8806_battery_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct oz8806_data *data = (struct oz8806_data *)power_supply_get_drvdata(psy); + + switch (psp) { + + case POWER_SUPPLY_PROP_STATUS: + + if (adapter_status == O2_CHARGER_BATTERY) + { + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; /*discharging*/ + } + else if(adapter_status == O2_CHARGER_USB || + adapter_status == O2_CHARGER_AC ) + { + if (data->batt_info.batt_soc == 100) + val->intval = POWER_SUPPLY_STATUS_FULL; + else + val->intval = POWER_SUPPLY_STATUS_CHARGING; /*charging*/ + + } + else + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = data->batt_info.batt_voltage * 1000; + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = bmu_init_done; + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + val->intval = data->batt_info.batt_current * 1000; + break; + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = data->batt_info.batt_soc; + break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = POWER_SUPPLY_TECHNOLOGY_LION; + break; + case POWER_SUPPLY_PROP_HEALTH: + val->intval = POWER_SUPPLY_HEALTH_GOOD; + break; + + case POWER_SUPPLY_PROP_TEMP: + val->intval = data->batt_info.batt_temp * 10; + break; + + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + val->intval = data->batt_info.batt_fcc_data; + break; + + case POWER_SUPPLY_PROP_CHARGE_NOW: + val->intval = data->batt_info.batt_capacity; + break; + + case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: + val->intval = data->batt_info.batt_fcc_data; + break; + + case POWER_SUPPLY_PROP_ENERGY_NOW: + val->intval = data->batt_info.batt_capacity; + break; + + default: + return -EINVAL; + } + + return 0; +} + +static void oz8806_external_power_changed(struct power_supply *psy) +{ + struct oz8806_data *data = (struct oz8806_data *)power_supply_get_drvdata(psy); + + power_supply_changed(data->bat); + cancel_delayed_work(&data->work); + schedule_delayed_work(&data->work, 0); +} + +static void oz8806_powersupply_init(struct oz8806_data *data) +{ + + data->bat_desc.name = "battery"; + data->bat_desc.type = POWER_SUPPLY_TYPE_BATTERY; + data->bat_desc.properties = oz8806_battery_props; + data->bat_desc.num_properties = ARRAY_SIZE(oz8806_battery_props); + data->bat_desc.get_property = oz8806_battery_get_property; + data->bat_desc.external_power_changed = oz8806_external_power_changed; + data->bat_desc.no_thermal = 1; +} + +/***************************************************************************** + *write 0x20 into register 0x09 + *example:echo 0920 > /sys/class/i2c-dev/i2c-2/device/2-002f/registers + *****************************************************************************/ + +static ssize_t oz8806_register_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t _count) +{ + char data[num_3]; + uint8_t address; + uint8_t value = 0; + char *endp; + int len; + struct oz8806_data *oz8806; + + len = strlen(buf); + if(len < 5) + return -EINVAL; + + if (&(the_oz8806->myclient->dev) == dev) + oz8806 = dev_get_drvdata(dev); + else //this device is the private device of power supply + oz8806 = dev_get_drvdata(dev->parent); + + data[num_0] = buf[num_0]; + data[num_1] = buf[num_1]; + data[num_2] = num_0; + + address = simple_strtoul(data, &endp, 16); + + if (address != OZ8806_OP_PEC_CTRL + && address != OZ8806_OP_CTRL + && address != OZ8806_OP_CAR + && address != OZ8806_OP_CAR+1 + && address != OZ8806_OP_BOARD_OFFSET + && address != OZ8806_OP_BOARD_OFFSET+1) + { + pr_err("register[0x%.2x] is read-only\n", address); + return _count; + } + + data[num_0] = buf[num_2]; + data[num_1] = buf[num_3]; + data[num_2] = num_0; + + value = simple_strtoul(data, &endp, 16); + + oz8806_write_byte(oz8806, address, value); + + pr_err("write 0x%.2x into register[0x%.2x]\n", value, address); + + return _count; +} + +/* + example:cat /sys/class/i2c-dev/i2c-2/device/2-002f/registers +*/ +static ssize_t oz8806_register_show(struct device *dev, struct device_attribute *attr,char *buf) +{ + struct oz8806_data *oz8806; + u8 i = 0; + u8 data = 0; + int result = 0; + + if (&(the_oz8806->myclient->dev) == dev) + oz8806 = dev_get_drvdata(dev); + else //this device is the private device of power supply + oz8806 = dev_get_drvdata(dev->parent); + + //CHIP ID and Reversion + oz8806_read_byte(oz8806, OZ8806_OP_IDREV, &data); + result += sprintf(buf + result, "[0x%.2x] = 0x%.2x\n", OZ8806_OP_IDREV, data); + + //I2C config register + oz8806_read_byte(oz8806, OZ8806_OP_I2CCONFIG, &data); + result += sprintf(buf + result, "[0x%.2x] = 0x%.2x\n", OZ8806_OP_I2CCONFIG, data); + + for (i=0x00; i<=0x1a; i++) + { + oz8806_read_byte(oz8806, i, &data); + result += sprintf(buf + result, "[0x%.2x] = 0x%.2x\n", i, data); + } + + return result; +} + +// chip id: 0x38 +static ssize_t oz8806_chip_id_show(struct device *dev, struct device_attribute *attr,char *buf) +{ + struct oz8806_data *oz8806; + u8 data = 0; + int result = 0; + + if (&(the_oz8806->myclient->dev) == dev) + oz8806 = dev_get_drvdata(dev); + else //this device is the private device of power supply + oz8806 = dev_get_drvdata(dev->parent); + + //CHIP ID and Reversion + oz8806_read_byte(oz8806, OZ8806_OP_IDREV, &data); + result = sprintf(buf, "0x%.2x = 0x%.2x\n", OZ8806_OP_IDREV, data); + return result; +} + +static ssize_t oz8806_debug_show(struct device *dev, struct device_attribute *attr,char *buf) +{ + return sprintf(buf,"%d\n", config_data.debug); +} +/***************************************************************************** + * Description: + * oz8806_debug_store + * Parameters: + * write example: echo 1 > debug ---open debug + *****************************************************************************/ +static ssize_t oz8806_debug_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t _count) +{ + int val; + if (kstrtoint(buf, 10, &val)) + return -EINVAL; + + if(val == 1) + { + config_data.debug = 1; + pr_err("DEBUG ON \n"); + } + else if (val == 0) + { + config_data.debug = 0; + pr_err("DEBUG CLOSE \n"); + } + else + { + pr_err("invalid command\n"); + return -EINVAL; + } + + return _count; +} + +static ssize_t oz8806_bmu_init_done_show(struct device *dev, struct device_attribute *attr,char *buf) +{ + return sprintf(buf,"%d\n", bmu_init_done); +} +static ssize_t oz8806_bmu_init_done_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t _count) +{ + int val = 0; + if (kstrtoint(buf, 10, &val)) + return -EINVAL; + + bmu_init_done = 0; + ic_wakeup_time = jiffies; + + cancel_delayed_work(&the_oz8806->work); + msleep(1000); + + if(val == 1) + { + pr_err("reinit oz8806 from ocv\n"); + bmu_reinit(1);//bmu_init_done will be setted + } + else if (val == 0) + { + pr_err("reinit oz8806,just wakeup ic\n"); + bmu_reinit(0); + bmu_init_done = 1; + } + else + { + pr_err("invalid command\n"); + return -EINVAL; + } + schedule_delayed_work(&the_oz8806->work, 0); + return _count; +} +static ssize_t oz8806_save_capacity_show(struct device *dev, struct device_attribute *attr,char *buf) +{ + if (capacity_init_ok && gas_gauge_ptr && gas_gauge_ptr->stored_capacity) + return sprintf(buf,"%d\n", gas_gauge_ptr->stored_capacity); + + return sprintf(buf,"%d\n", save_capacity); +} +#ifdef USERSPACE_READ_SAVED_CAP +static ssize_t oz8806_save_capacity_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + int val; + struct oz8806_data *oz8806; + + if (&(the_oz8806->myclient->dev) == dev) + oz8806 = dev_get_drvdata(dev); + else //this device is the private device of power supply + oz8806 = dev_get_drvdata(dev->parent); + + if (kstrtoint(buf, 10, &val)) + return -EINVAL; + save_capacity = val; + batt_dbg("save_capacity:%d\n", save_capacity); + + if (oz8806 && !bmu_init_done) + { + cancel_delayed_work(&oz8806->work); + schedule_delayed_work(&oz8806->work, 0); + } + + return count; +} +#endif + +static DEVICE_ATTR(registers, S_IRUGO | (S_IWUSR|S_IWGRP), oz8806_register_show, oz8806_register_store); +static DEVICE_ATTR(chip_id, S_IRUGO, oz8806_chip_id_show, NULL); +static DEVICE_ATTR(debug, S_IRUGO | (S_IWUSR|S_IWGRP), oz8806_debug_show, oz8806_debug_store); +static DEVICE_ATTR(bmu_init_done, S_IRUGO| (S_IWUSR|S_IWGRP), oz8806_bmu_init_done_show, oz8806_bmu_init_done_store); + +#ifdef USERSPACE_READ_SAVED_CAP +static DEVICE_ATTR(save_capacity, S_IRUGO | (S_IWUSR|S_IWGRP), oz8806_save_capacity_show, oz8806_save_capacity_store); +#else +static DEVICE_ATTR(save_capacity, S_IRUGO, oz8806_save_capacity_show, NULL); +#endif + + +static struct attribute *oz8806_attributes[] = { + &dev_attr_registers.attr, + &dev_attr_chip_id.attr, + &dev_attr_debug.attr, + &dev_attr_bmu_init_done.attr, + &dev_attr_save_capacity.attr, + NULL, +}; + +static struct attribute_group oz8806_attribute_group = { + .attrs = oz8806_attributes, +}; + +static int oz8806_create_sys(struct device *dev, const struct attribute_group * grp) +{ + int err; + + batt_dbg("oz8806_create_sysfs"); + + if(NULL == dev){ + pr_err("[BATT]: failed to register battery\n"); + return -EINVAL; + } + + err = sysfs_create_group(&(dev->kobj), grp); + + if (!err) + { + batt_dbg("creat oz8806 sysfs group ok"); + } + else + { + pr_err("creat oz8806 sysfs group fail\n"); + return -EIO; + } + return err; +} + +static int32_t oz8806_read_byte(struct oz8806_data *data, uint8_t index, uint8_t *dat) +{ + int32_t ret; + uint8_t i; + struct i2c_client *client = data->myclient; + + for(i = 0; i < 4; i++){ + ret = i2c_smbus_read_byte_data(client, index); + + if(ret >= 0) break; + else + dev_err(&client->dev, "%s: err %d, %d times\n", __func__, ret, i); + } + if(i >= 4) + { + return ret; + } + *dat = (uint8_t)ret; + + return ret; +} + +static int32_t oz8806_write_byte(struct oz8806_data *data, uint8_t index, uint8_t dat) +{ + int32_t ret; + uint8_t i; + struct i2c_client *client = data->myclient; + + for(i = 0; i < 4; i++){ + ret = i2c_smbus_write_byte_data(client, index, dat); + if(ret >= 0) break; + else + dev_err(&client->dev, "%s: err %d, %d times\n", __func__, ret, i); + } + if(i >= 4) + { + return ret; + } + + return ret; +} + +static int32_t oz8806_update_bits(struct oz8806_data *data, uint8_t reg, uint8_t mask, uint8_t dat) +{ + int32_t ret; + uint8_t tmp; + + ret = oz8806_read_byte(data, reg, &tmp); + if (ret < 0) + return ret; + + if ((tmp & mask) != dat) + { + tmp &= ~mask; + tmp |= dat & mask; + return oz8806_write_byte(data, reg, tmp); + + } + else + return 0; +} +#if 0 +static int oz8806_check_battery_status(struct oz8806_data *data) +{ + uint8_t val; + int ret = 0; + + ret = oz8806_read_byte(data, OZ8806_OP_BATTERY_ID, &val); + + pr_err("battery ID: 0x%02x\n", val); + + return ret; +} +#endif +int oz8806_wakeup_full_power(void) +{ + uint8_t val = 0; + int32_t ret = 0; + struct oz8806_data *data = the_oz8806; + + ret = oz8806_read_byte(data, OZ8806_OP_CTRL, &val); + pr_err("OZ8806_OP_CTRL: 0x%02x\n", val); + + if ((val & SLEEP_MODE) != 0<<6) + { + ret = oz8806_update_bits(data, OZ8806_OP_CTRL, SLEEP_MODE, 0 << 6); + + ret = oz8806_read_byte(data, OZ8806_OP_CTRL, &val); + + pr_err("OZ8806_OP_CTRL: 0x%02x after writing\n", val); + + if ((val & SLEEP_MODE) != (0 << 6)) + pr_err("fail to wake up oz8806 to full power mode\n"); + else { + if (oz8806_get_boot_up_time() < 2000) + ic_wakeup_time = jiffies + msecs_to_jiffies(2000 - oz8806_get_boot_up_time()); + else + ic_wakeup_time = jiffies; + pr_err("wake up oz8806 to full power mode\n"); + } + } + pr_err("ic_wakeup_time %lu\n",ic_wakeup_time); + + return ret; +} +EXPORT_SYMBOL(oz8806_wakeup_full_power); + +static void discharge_end_fun(struct oz8806_data *data) +{ + //End discharge + //this may jump 2% + if (!gas_gauge_ptr || !batt_info_ptr) + return; + /* + if(batt_info_ptr->fCellTemp < -10) + config_data.discharge_end_voltage = OZ8806_EOD + 350; + else if (batt_info_ptr->fCellTemp < 0) + config_data.discharge_end_voltage = OZ8806_EOD + 300; + else if (batt_info_ptr->fCellTemp < 5) + config_data.discharge_end_voltage = OZ8806_EOD + 200; + else if (batt_info_ptr->fCellTemp < 10) + config_data.discharge_end_voltage = OZ8806_EOD + 100; + else + config_data.discharge_end_voltage = OZ8806_EOD; + +*/ + + if(batt_info_ptr->fVolt < (config_data.discharge_end_voltage - 100)) + { + + if(batt_info_ptr->fRSOC == 1) + { + batt_info_ptr->fRSOC = 0; + batt_info_ptr->sCaMAH = data->batt_info.batt_fcc_data / num_100 -1; + if (bmu_discharge_end_process_callback) + bmu_discharge_end_process_callback(); + } + else if(batt_info_ptr->fRSOC > 0){ + batt_info_ptr->sCaMAH = batt_info_ptr->fRSOC * data->batt_info.batt_fcc_data / num_100 - 1; + batt_info_ptr->fRSOC--; + } + } +} + +static int check_charger_full(void) +{ + int ret = 0; + +//from charge ic + return ret; +} + +static void charge_end_fun(void) +{ +#define CHG_END_PERIOD_MS (MSEC_PER_SEC * 60) //60 s = 1 minutes +#define FORCE_FULL_MS (MSEC_PER_SEC * 120) //120s = 2 minutes +#define CHG_END_PURSUE_STEP (MSEC_PER_SEC * 30) //30s + + static unsigned int time_accumulation; + static unsigned long start_jiffies; + int oz8806_eoc = 0; + static unsigned long chgr_full_soc_pursue_start; + static unsigned int chgr_full_soc_pursue_accumulation; + +#ifdef ENABLE_10MIN_END_CHARGE_FUN + static unsigned long start_record_jiffies; + static uint8_t start_record_flag = 0; +#endif + + if (!gas_gauge_ptr || !batt_info_ptr) + return; + + if (adapter_status != O2_CHARGER_BATTERY && check_charger_full()) + { + charger_finish = 1; + batt_dbg("charger is full, enter external charger finish"); + goto charger_full; + } + + if(adapter_status == O2_CHARGER_USB) + oz8806_eoc = 100; + else if(adapter_status == O2_CHARGER_AC) + oz8806_eoc = config_data.charge_end_current; + + if((adapter_status == O2_CHARGER_BATTERY) || + (batt_info_ptr->fCurr < DISCH_CURRENT_TH) || + (batt_info_ptr->fCurr > oz8806_eoc)) + { + charger_finish = 0; + time_accumulation = 0; + start_jiffies = 0; + chgr_full_soc_pursue_start = 0; +#ifdef ENABLE_10MIN_END_CHARGE_FUN + start_record_jiffies = 0; + start_record_flag = 0; +#endif + return; + } + /* + if(adapter_status == CHARGER_USB) + { + gas_gauge_ptr->fast_charge_step = 1; + } + else + { + gas_gauge_ptr->fast_charge_step = 2; + } + */ + + + + if((batt_info_ptr->fVolt >= (config_data.charge_cv_voltage - 50))&&(batt_info_ptr->fCurr >= DISCH_CURRENT_TH) && + (batt_info_ptr->fCurr < oz8806_eoc)&& (!gas_gauge_ptr->charge_end)) + { + if (!start_jiffies) + start_jiffies = jiffies; + + time_accumulation = jiffies_to_msecs(jiffies - start_jiffies); + + //time accumulation is over 5 minutes + if (time_accumulation >= CHG_END_PERIOD_MS) + { + charger_finish = 1; + batt_dbg("enter external charger finish"); + } + else + { + charger_finish = 0; + } + } + else + { + time_accumulation = 0; + start_jiffies = 0; + charger_finish = 0; + } + +charger_full: + batt_dbg("%s, time_accumulation:%d, charger_finish:%d", + __func__, time_accumulation, charger_finish); + + batt_dbg("voltage:%d, cv:%d, fcurr:%d, 8806 eoc:%d, gas_gauge_ptr->charge_end:%d", + batt_info_ptr->fVolt, config_data.charge_cv_voltage, + batt_info_ptr->fCurr, oz8806_eoc, gas_gauge_ptr->charge_end); + +#ifdef ENABLE_10MIN_END_CHARGE_FUN + if((batt_info_ptr->fRSOC == 99) &&(!start_record_flag) &&(batt_info_ptr->fCurr > oz8806_eoc)) + { + start_record_jiffies = jiffies; + start_record_flag = 1; + batt_dbg("start_record_flag: %d, at %d ms",start_record_flag, jiffies_to_msecs(jiffies)); + } + if((batt_info_ptr->fRSOC != 99) ||(batt_info_ptr->fCurr < oz8806_eoc)) + { + start_record_flag = 0; + } + + if((start_record_flag) && (batt_info_ptr->fCurr > oz8806_eoc)) + { + if(jiffies_to_msecs(jiffies - start_record_jiffies) > FORCE_FULL_MS) + { + batt_dbg("start_record_flag: %d, at %d ms",start_record_flag, jiffies_to_msecs(jiffies)); + charger_finish = 1; + start_record_flag = 0; + batt_dbg("enter charge timer finish"); + } + } +#endif + + if(charger_finish) + { + if(!gas_gauge_ptr->charge_end) + { + if(batt_info_ptr->fRSOC < 100) + { + static int32_t fRSOC_extern = 0; + + if(batt_info_ptr->fRSOC <= rsoc_pre){ + batt_dbg("fRSOC_extern:%d, soc:%d ",fRSOC_extern,batt_info_ptr->fRSOC); + + if (!chgr_full_soc_pursue_start || fRSOC_extern != batt_info_ptr->fRSOC) { + chgr_full_soc_pursue_start = jiffies; + fRSOC_extern = batt_info_ptr->fRSOC ; + } + + + chgr_full_soc_pursue_accumulation = + jiffies_to_msecs(jiffies - chgr_full_soc_pursue_start); + + if (chgr_full_soc_pursue_accumulation >= CHG_END_PURSUE_STEP){ + + chgr_full_soc_pursue_start = 0; + batt_info_ptr->fRSOC++; + batt_info_ptr->sCaMAH = batt_info_ptr->fRSOC * the_oz8806->batt_info.batt_fcc_data / num_100; + batt_info_ptr->sCaMAH += the_oz8806->batt_info.batt_fcc_data / 200; // + 0.5% + } + } + + if(batt_info_ptr->fRSOC > 100) { + batt_info_ptr->fRSOC = 100; + batt_info_ptr->sCaMAH = batt_info_ptr->fRSOC * the_oz8806->batt_info.batt_fcc_data / num_100; + batt_info_ptr->sCaMAH ++; + } + + //update fRSOC_extern + fRSOC_extern = batt_info_ptr->fRSOC ; + + batt_dbg("enter charger finsh update soc:%d",batt_info_ptr->fRSOC); + } + else + { + batt_dbg("enter charger charge end"); + gas_gauge_ptr->charge_end = 1; + + if (bmu_charge_end_process_callback) + bmu_charge_end_process_callback(); + + charger_finish = 0; + chgr_full_soc_pursue_start = 0; + } + + } + else { + charger_finish = 0; + chgr_full_soc_pursue_start = 0; + } + + } else chgr_full_soc_pursue_start = 0; + +} +static void oz8806_wakeup_event(struct oz8806_data *data) +{ + static int ws_active = 0; + + if (adapter_status == O2_CHARGER_BATTERY && ws_active) { + pm_relax(&data->myclient->dev); + ws_active = 0; + } + + if (adapter_status != O2_CHARGER_BATTERY && !ws_active) { + pm_stay_awake(&data->myclient->dev); + ws_active = 1; + } +} +//this is very important code customer need change +//customer should change charge discharge status according to your system +//O2micro +static void system_charge_discharge_status(struct oz8806_data *data) +{ + int8_t adapter_status_temp = O2_CHARGER_BATTERY; + + union power_supply_propval val_ac = {0}; + union power_supply_propval val_usb = {0}; + + if (!data->ac_psy) + data->ac_psy = power_supply_get_by_name ("ac"); + + if (!data->usb_psy) + data->usb_psy= power_supply_get_by_name ("usb"); + +//--------------------------------------------- +#ifdef QUALCOMM_MACH_SUPPORT + if (data->usb_psy) + { + if(0 == power_supply_get_property(data->usb_psy, POWER_SUPPLY_PROP_REAL_TYPE, &val_usb)) + { + if(POWER_SUPPLY_TYPE_USB_ACA == val_usb.intval|| POWER_SUPPLY_TYPE_USB_CDP == val_usb.intval|| POWER_SUPPLY_TYPE_USB_DCP == val_usb.intval) + adapter_status_temp = O2_CHARGER_AC; + else if(POWER_SUPPLY_TYPE_USB == val_usb.intval) + adapter_status_temp = O2_CHARGER_USB; + else + adapter_status_temp = O2_CHARGER_BATTERY; + } + } + +#else + if (data->usb_psy) + { + if(0 == power_supply_get_property(data->usb_psy, POWER_SUPPLY_PROP_ONLINE, &val_usb)) + { + if (val_usb.intval) + adapter_status_temp = O2_CHARGER_USB; + } + } + + if (data->ac_psy) + { + if(0 == power_supply_get_property(data->ac_psy, POWER_SUPPLY_PROP_ONLINE, &val_ac)) + { + if (val_ac.intval) + adapter_status_temp = O2_CHARGER_AC; + } + } + batt_dbg("val_ac.intval %d, val_usb.intval %d,adapter_status_temp %d",val_ac.intval,val_usb.intval,adapter_status_temp); +#endif + + adapter_status = adapter_status_temp; + batt_dbg("adapter_status:%d", adapter_status); +} + +static void oz8806_lock_soc(struct oz8806_data *data) +{ + unsigned long car = 0; + unsigned short temp = 0; + + //bmu ok + if(bmu_init_done) + { + pr_err("\n"); + if(rsoc_pre < 0) rsoc_pre = 0; + if(rsoc_pre > 100) rsoc_pre = 100; + + //adapter is online,and current > 0, lock to 0 or pre soc + if( (data->batt_info.batt_current > 0) && (O2_CHARGER_USB == adapter_status || O2_CHARGER_AC == adapter_status) ) + { + if(data->batt_info.batt_voltage <= O2_SOC_START_THRESHOLD_VOL) + { + pr_err("charge 1,lock soc to pre_soc,pre_soc=%d\n",rsoc_pre); + if(0 == rsoc_pre) + car = data->batt_info.batt_fcc_data / 100 -1; + else + car = rsoc_pre * data->batt_info.batt_fcc_data / 100; + + temp = (car * config_data.fRsense) / config_data.dbCARLSB; //transfer to CAR + + i2c_smbus_write_word_data(data->myclient, OZ8806_OP_CAR,(unsigned short)temp); + } + } + + //adapter is online,do not consider current, lock soc to 100 if voltage >= cv - recharge + if(O2_CHARGER_USB == adapter_status || O2_CHARGER_AC == adapter_status) + { + if( (100 == rsoc_pre) && (data->batt_info.batt_voltage >= (config_data.charge_cv_voltage - O2_CONFIG_RECHARGE)) ) + { + pr_err("charge 2,lock soc to pre_soc,pre_soc=%d\n",rsoc_pre); + car = 101 * data->batt_info.batt_fcc_data / 100 - 2; + batt_info_ptr->sCaMAH = car; + batt_info_ptr->fRC = car; + batt_info_ptr->fRCPrev = car; + temp = (car * config_data.fRsense) / config_data.dbCARLSB; //transfer to CAR + + i2c_smbus_write_word_data(data->myclient, OZ8806_OP_CAR,(unsigned short)temp); + } + } + } +} +static void oz8806_battery_func(struct oz8806_data *data) +{ + unsigned long time_since_last_update_ms = 0; + static unsigned long cur_jiffies = 0; + + if(0 == cur_jiffies) + cur_jiffies = jiffies; + + pr_err("%s: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n", __func__); + time_since_last_update_ms = jiffies_to_msecs(jiffies - cur_jiffies); + cur_jiffies = jiffies; + + //get charging type: battery, AC, or USB + system_charge_discharge_status(data); + + rsoc_pre = data->batt_info.batt_soc; + + //you must add this code here for O2MICRO + //Notice: don't nest mutex +#ifdef EXT_THERMAL_READ + oz8806_update_batt_temp(data); +#endif + oz8806_lock_soc(data); + + /**************mutex_lock*********************/ + mutex_lock(&update_mutex); + if (bmu_polling_loop_callback && !oz8806_suspend) + bmu_polling_loop_callback(); + + oz8806_update_batt_info(data); + + charge_end_fun(); + + if(adapter_status == O2_CHARGER_BATTERY) + discharge_end_fun(data); + + mutex_unlock(&update_mutex); + /**************mutex_unlock*********************/ + + + oz8806_wakeup_event(data); + + batt_dbg("l=%d v=%d t=%d c=%d ch=%d", + data->batt_info.batt_soc, data->batt_info.batt_voltage, + data->batt_info.batt_temp, data->batt_info.batt_current, adapter_status); + + power_supply_changed(data->bat); + batt_dbg("since last batt update = %lu ms", time_since_last_update_ms); +} + +static void oz8806_battery_work(struct work_struct *work) +{ + struct oz8806_data *data = container_of(work, struct oz8806_data, work.work); + + oz8806_battery_func(data); + + if (!bmu_init_done) + { + // data->interval = 2000; + schedule_delayed_work(&data->work, msecs_to_jiffies(200)); + } + else + { + data->interval = BATTERY_WORK_INTERVAL * 1000; + schedule_delayed_work(&data->work, msecs_to_jiffies(data->interval)); + + } + batt_dbg("interval:%d ms", data->interval); +} + +int32_t is_battery_exchanged(void) +{ + return 0; +} +EXPORT_SYMBOL(is_battery_exchanged); + + + +static int oz8806_suspend_notifier(struct notifier_block *nb, + unsigned long event, + void *dummy) +{ + struct oz8806_data *data = container_of(nb, struct oz8806_data, pm_nb); + + switch (event) { + + case PM_SUSPEND_PREPARE: + pr_err("oz8806 PM_SUSPEND_PREPARE \n"); + cancel_delayed_work_sync(&data->work); + system_charge_discharge_status(data); + oz8806_suspend = 1; + return NOTIFY_OK; + case PM_POST_SUSPEND: + pr_err("oz8806 PM_POST_SUSPEND \n"); + + system_charge_discharge_status(data); + + mutex_lock(&update_mutex); + // if AC charge can't wake up every 1 min,you must remove the if. + if(adapter_status == O2_CHARGER_BATTERY) + if (bmu_wake_up_chip_callback) + bmu_wake_up_chip_callback(); + + oz8806_update_batt_info(data); + mutex_unlock(&update_mutex); + + schedule_delayed_work(&data->work, 0); + //this code must be here,very carefull. + if(adapter_status == O2_CHARGER_BATTERY) + { + if(data->batt_info.batt_current >= data->batt_info.discharge_current_th) + { + if (batt_info_ptr) batt_info_ptr->fCurr = -20; + + data->batt_info.batt_current = -20; + pr_err("drop current\n"); + } + } + + oz8806_suspend = 0; + + return NOTIFY_OK; + + default: + return NOTIFY_DONE; + } +} +static void oz8806_init_soc(struct oz8806_data *data) +{ + int32_t ret = 0; + int32_t temp = 0; + uint32_t i = 0; + + for(i=0; i<5; i++) + { + ret = i2c_smbus_read_word_data(data->myclient, OZ8806_OP_CAR); + if(ret >= 0) + break; + msleep(5); + } + if(i >= 5) + { + batt_dbg("%s failed, reg value %x\n",__func__,ret); + init_soc = 50; + return; + } + + temp = (int16_t)ret; + temp = temp * config_data.dbCARLSB; + temp = temp / config_data.fRsense; + if(temp > 5) + { + init_soc = temp * 100 / config_data.design_capacity - 1; + if(init_soc >= 100) + init_soc = 100; + if(init_soc <= 0) + init_soc = 0; + } + else + init_soc = 0; + + batt_dbg("%s succeed, init soc is %d",__func__,init_soc); +} +static int oz8806_init_batt_info(struct oz8806_data *data) +{ + data->batt_info.batt_soc = 50; + data->batt_info.batt_voltage = 3999; + data->batt_info.batt_current = -300; + data->batt_info.batt_temp = 27; + data->batt_info.batt_capacity = 4000; + + data->batt_info.batt_fcc_data = config_data.design_capacity; + data->batt_info.discharge_current_th = DISCH_CURRENT_TH; + data->batt_info.charge_end = 0; + oz8806_init_soc(data); + return 0; +} +static int oz8806_update_batt_info(struct oz8806_data *data) +{ + int ret = 0; + + //Notice: before call this function, use mutex_lock(&update_mutex) + //Notice: don't nest mutex + if (!batt_info_ptr || !gas_gauge_ptr) + { + ret = -EINVAL; + goto end; + } + + data->batt_info.batt_soc = batt_info_ptr->fRSOC; + if (data->batt_info.batt_soc > 100) + data->batt_info.batt_soc = 100; + + + data->batt_info.batt_voltage = batt_info_ptr->fVolt; + data->batt_info.batt_current = batt_info_ptr->fCurr; + data->batt_info.batt_capacity = batt_info_ptr->sCaMAH; + + data->batt_info.charge_end = gas_gauge_ptr->charge_end; + bmu_init_done = gas_gauge_ptr->bmu_init_ok; +#ifndef EXT_THERMAL_READ + oz8806_update_batt_temp(data); +#endif +end: + return ret; +} + +static int oz8806_update_batt_temp(struct oz8806_data *data) +{ + int ret = 0; + + if (!batt_info_ptr || !gas_gauge_ptr) + { + ret = -EINVAL; + goto end; + } + + data->batt_info.batt_temp = batt_info_ptr->fCellTemp; + if (batt_info_ptr->fCellTemp != data->batt_info.batt_temp) + batt_info_ptr->fCellTemp = data->batt_info.batt_temp; + +end: + return ret; +} + +int oz8806_get_remaincap(void) +{ + int ret = -1; + + mutex_lock(&update_mutex); + + if (batt_info_ptr) + ret = batt_info_ptr->sCaMAH; + + mutex_unlock(&update_mutex); + + return ret; +} +EXPORT_SYMBOL(oz8806_get_remaincap); + + +int oz8806_get_soc_from_ext(void) +{ + int ret = -1; + + return ret; +} +EXPORT_SYMBOL(oz8806_get_soc_from_ext); + +int oz8806_get_soc(void) +{ + int ret = -1; + + mutex_lock(&update_mutex); + + if (!bmu_init_done) + { + ret = init_soc; + } + else if (batt_info_ptr) + ret = batt_info_ptr->fRSOC; + + mutex_unlock(&update_mutex); + + return ret; +} +EXPORT_SYMBOL(oz8806_get_soc); + +int oz8806_get_battry_current(void) +{ + int ret = -1; + + if (!bmu_init_done) return -1; + + mutex_lock(&update_mutex); + + if (oz8806_current_read_callback && batt_info_ptr) + ret = oz8806_current_read_callback(&batt_info_ptr->fCurr); + + if (ret < 0) + { + ret = -1; + batt_dbg("%s:oz8806 current adc error", __func__); + } + + if (batt_info_ptr && ret >= 0) + ret = batt_info_ptr->fCurr; + + mutex_unlock(&update_mutex); + + return ret; +} +EXPORT_SYMBOL(oz8806_get_battry_current); + +int oz8806_get_battery_voltage(void) +{ + int ret = -1; + + if (!bmu_init_done) return -1; + + mutex_lock(&update_mutex); + + if (oz8806_voltage_read_callback && batt_info_ptr) + ret = oz8806_voltage_read_callback(&batt_info_ptr->fVolt); + + if (ret < 0) + { + ret = -1; + batt_dbg("%s:oz8806 voltage adc error", __func__); + } + + if (batt_info_ptr && ret >= 0) + ret = batt_info_ptr->fVolt; + + mutex_unlock(&update_mutex); + + return ret; +} +EXPORT_SYMBOL(oz8806_get_battery_voltage); + +int oz8806_get_battery_temp(void) +{ + int ret = -1; + + if (!bmu_init_done) return -1; + + mutex_lock(&update_mutex); + + if (batt_info_ptr) + ret = batt_info_ptr->fCellTemp; + + mutex_unlock(&update_mutex); + + return ret; +} +EXPORT_SYMBOL(oz8806_get_battery_temp); + +void oz8806_battery_update_data(void) +{ + batt_dbg("enter %s", __func__); + if (fg_hw_init_done && the_oz8806 && bmu_init_done) + oz8806_battery_func(the_oz8806); +} +EXPORT_SYMBOL(oz8806_battery_update_data); + +int32_t oz8806_vbus_voltage(void) +{ + int32_t vbus_voltage = 0; + int ret = -1; + + if (oz8806_temp_read_callback) + ret = oz8806_temp_read_callback(&vbus_voltage); + + if (ret < 0) + { + batt_dbg("%s:oz8806 temp adc error", __func__); + return ret; + } + + batt_dbg("voltage from oz8806:%d", vbus_voltage); + vbus_voltage = vbus_voltage * (RPULL + RDOWN) / RDOWN; + + return vbus_voltage; +} +EXPORT_SYMBOL(oz8806_vbus_voltage); + +int32_t oz8806_get_simulated_temp(void) +{ + return 25; +} +EXPORT_SYMBOL(oz8806_get_simulated_temp); + +int32_t oz8806_get_init_status(void) +{ + return bmu_init_done; +} +EXPORT_SYMBOL(oz8806_get_init_status); + +int32_t gauge_int_done(void) +{ + return fg_hw_init_done; +} +EXPORT_SYMBOL(gauge_int_done); + +struct i2c_client * oz8806_get_client(void) +{ + if (the_oz8806) + return the_oz8806->myclient; + else + { + pr_err("the_oz8806 is NULL, oz8806_probe didn't call\n"); + return NULL; + + } +} +EXPORT_SYMBOL(oz8806_get_client); + + +int8_t get_adapter_status(void) +{ + return adapter_status; +} +EXPORT_SYMBOL(get_adapter_status); + +void oz8806_register_bmu_callback(void *bmu_polling_loop_func, + void *bmu_wake_up_chip_func, + void *bmu_power_down_chip_func, + void *charge_end_process_func, + void *discharge_end_process_func, + void *oz8806_temp_read_func, + void *oz8806_current_read_func, + void *oz8806_voltage_read_func) +{ + mutex_lock(&update_mutex); + + bmu_polling_loop_callback = bmu_polling_loop_func; + bmu_wake_up_chip_callback = bmu_wake_up_chip_func; + bmu_power_down_chip_callback = bmu_power_down_chip_func; + bmu_charge_end_process_callback = charge_end_process_func; + bmu_discharge_end_process_callback = discharge_end_process_func; + + oz8806_temp_read_callback = oz8806_temp_read_func; + oz8806_current_read_callback = oz8806_current_read_func; + oz8806_voltage_read_callback = oz8806_voltage_read_func; + + if(bmu_polling_loop_callback) + bmu_polling_loop_callback(); + + mutex_unlock(&update_mutex); +} +EXPORT_SYMBOL(oz8806_register_bmu_callback); + +void unregister_bmu_callback(void) +{ + mutex_lock(&update_mutex); + + bmu_polling_loop_callback = NULL; + bmu_wake_up_chip_callback = NULL; + bmu_power_down_chip_callback = NULL; + bmu_charge_end_process_callback = NULL; + bmu_discharge_end_process_callback = NULL; + + oz8806_temp_read_callback = NULL; + oz8806_current_read_callback = NULL; + oz8806_voltage_read_callback = NULL; + + oz8806_init_batt_info(the_oz8806); + + batt_info_ptr = NULL; + gas_gauge_ptr = NULL; + + mutex_unlock(&update_mutex); +} +EXPORT_SYMBOL(unregister_bmu_callback); + +void oz8806_set_batt_info_ptr(bmu_data_t *batt_info) +{ + mutex_lock(&update_mutex); + + if (!batt_info) + { + pr_err("%s: batt_info NULL\n", __func__); + mutex_unlock(&update_mutex); + return; + } + + batt_info_ptr = batt_info; + + mutex_unlock(&update_mutex); +} +EXPORT_SYMBOL(oz8806_set_batt_info_ptr); + +void oz8806_set_gas_gauge(gas_gauge_t *gas_gauge) +{ + mutex_lock(&update_mutex); + + if (!gas_gauge) + { + pr_err("%s: gas_gauge NULL\n", __func__); + mutex_unlock(&update_mutex); + return; + } + + gas_gauge_ptr = gas_gauge; + + if (gas_gauge_ptr->fcc_data != 0) + the_oz8806->batt_info.batt_fcc_data = gas_gauge_ptr->fcc_data; + + if (gas_gauge_ptr->discharge_current_th != 0) + the_oz8806->batt_info.discharge_current_th = gas_gauge_ptr->discharge_current_th; + + batt_dbg("batt_fcc_data:%d, discharge_current_th:%d", + the_oz8806->batt_info.batt_fcc_data, the_oz8806->batt_info.discharge_current_th); + + gas_gauge_ptr->ext_temp_measure = ext_thermal_read; + + mutex_unlock(&update_mutex); +} +EXPORT_SYMBOL(oz8806_set_gas_gauge); + +int oz8806_get_save_capacity(void) +{ + return save_capacity; +} +EXPORT_SYMBOL(oz8806_get_save_capacity); + +unsigned long oz8806_get_boot_up_time(void) +{ + unsigned long long t; + struct timespec time; + ktime_get_ts(&time); + t = time.tv_sec * 1000 + time.tv_nsec / 1000000; + batt_dbg("boot up time: %lu ms", (unsigned long) t); + + return t; +} +EXPORT_SYMBOL(oz8806_get_boot_up_time); + +unsigned long oz8806_get_power_on_time(void) +{ + unsigned int t = 0; + pr_info("jiffies %lu,ic_wakeup_time %lu\n",jiffies,ic_wakeup_time); + t = jiffies_to_msecs(jiffies - ic_wakeup_time); + + pr_info("IC wakeup time: %u ms\n", t); + + return (unsigned long)t; +} +EXPORT_SYMBOL(oz8806_get_power_on_time); + +static int oz8806_probe(struct i2c_client *client,const struct i2c_device_id *id) +{ + int32_t ret = 0; + struct oz8806_data* data = NULL; + + struct power_supply_config psy_cfg = { + .of_node = client->dev.of_node, + }; + + pr_err("%s start\n",__func__); +/***************************************************************************** +* O2Micro Warning: +* bmulib_init 是非常重要的函数,芯片需要client来执行初始化以及自检校验等工作 +* 不允许因为读不到I2C信息而提前于这个函数返回,这将引起非常严重的错误问题。 +* 再次提醒,不允许因为读不到I2C信息而直接返回。 +*****************************************************************************/ + + data = devm_kzalloc(&client->dev, sizeof(struct oz8806_data), GFP_KERNEL); + if (!data) { + dev_err(&client->dev, "Can't alloc oz8806_data struct\n"); + return -ENOMEM; + } + + // Init real i2c_client + i2c_set_clientdata(client, data); + + the_oz8806 = data; + data->myclient = client; + //init battery information as soon as possible + oz8806_init_batt_info(data); + + INIT_DELAYED_WORK(&data->work, oz8806_battery_work); +/***************************************************************************** +* O2Micro Warning: This is a very important code here(bmulib_init). +* The chip needs i2c client processing opt mapping and self init first in bmulib_init. +* You must not return before this code even if you read i2c error. +* Remind you again that it will make serious mistake if you return before bmulib_init. +*****************************************************************************/ + if (oz8806_get_boot_up_time() < 2000) + ic_wakeup_time = jiffies + msecs_to_jiffies(2000 - oz8806_get_boot_up_time()); + else + ic_wakeup_time = jiffies;//msecs_to_jiffies(2000); + +#ifndef CONFIG_OZ8806_M + bmulib_init(); +#else + /* + * Wake up oz8806 to full power mode here. + * Then, after at least 2.5s, detection of current, voltage, and temperature can be stable + * + * when IC start with start-up mode, after at least 2s, IC can enter Full Power Mode. + */ + oz8806_wakeup_full_power(); +#endif + + data->interval = BATTERY_WORK_INTERVAL * 1000; + + oz8806_powersupply_init(data); + psy_cfg.drv_data = data, + data->bat = power_supply_register(&client->dev, &the_oz8806->bat_desc,&psy_cfg); + if (!data->bat) { + pr_err("failed to register power_supply battery\n"); + goto register_fail; + } + + /* + * /sys/class/i2c-dev/i2c-2/device/2-002f/ + */ + ret = oz8806_create_sys(&(client->dev), &oz8806_attribute_group); + if(ret){ + pr_err("[BATT]: Err failed to creat oz8806 attributes\n"); + goto bat_failed; + } + + //alternative suspend/resume method + data->pm_nb.notifier_call = oz8806_suspend_notifier; + register_pm_notifier(&data->pm_nb); + + ret = device_init_wakeup(&client->dev, true); + if (ret) + dev_err(&client->dev, "wakeup source init failed.\n"); + + fg_hw_init_done = 1; + + schedule_delayed_work(&data->work, 0); + + pr_err("%s end\n",__func__); + return 0; //return Ok +bat_failed: + power_supply_unregister(the_oz8806->bat); +register_fail: + pr_err("%s() fail: return %d\n", __func__, ret); + the_oz8806 = NULL; + return ret; +} + + +static int oz8806_remove(struct i2c_client *client) +{ + struct oz8806_data *data = i2c_get_clientdata(client); + + cancel_delayed_work(&data->work); + + sysfs_remove_group(&(data->myclient->dev.kobj), &oz8806_attribute_group); + + power_supply_unregister(data->bat); + + mutex_lock(&update_mutex); + + if (bmu_power_down_chip_callback) + { + //这里需要注意,在关机流程中,必须要调用关机回调,否则芯片可能没有正常休眠,导致下次开机容量异常 + //并且要小心回调之后,如果有work或者线程跑起来,可能会再次唤醒芯片,要避免这种情况。 + fg_hw_init_done = 0;//be carefull other thread call bmu_polling_loop_func and wake up chip again + bmu_power_down_chip_callback(); + } + + oz8806_update_batt_info(data); + + mutex_unlock(&update_mutex); +#ifndef CONFIG_OZ8806_M + bmulib_exit(); +#endif + + return 0; +} + +static void oz8806_shutdown(struct i2c_client *client) +{ + struct oz8806_data *data = i2c_get_clientdata(client); + pr_err("oz8806 shutdown\n"); + + cancel_delayed_work(&data->work); + + sysfs_remove_group(&(data->myclient->dev.kobj), &oz8806_attribute_group); + + mutex_lock(&update_mutex); + if (bmu_power_down_chip_callback) + { + //这里需要注意,在关机流程中,必须要调用关机回调,否则芯片可能没有正常休眠,导致下次开机容量异常 + //并且要小心回调之后,如果有work或者线程跑起来,可能会再次唤醒芯片,要避免这种情况。 + fg_hw_init_done = 0; + bmu_power_down_chip_callback(); + } + + oz8806_update_batt_info(data); + mutex_unlock(&update_mutex); +} +/*-------------------------------------------------------------------------*/ + +static const struct i2c_device_id oz8806_id[] = { + { MYDRIVER, 0 }, //string, id?? + { } +}; +MODULE_DEVICE_TABLE(i2c, oz8806_id); + +static const struct of_device_id oz8806_of_match[] = { + {.compatible = "o2micro,oz8806",}, + {}, +}; +MODULE_DEVICE_TABLE(of, oz8806_of_match); + + +static struct i2c_driver oz8806_driver = { + .driver = { + .name = MYDRIVER, + .of_match_table = oz8806_of_match, + }, + .probe = oz8806_probe, + .remove = oz8806_remove, + .shutdown = oz8806_shutdown, + .id_table = oz8806_id, +}; + + +static int __init oz8806_init(void) +{ + int ret = 0; + + ret = i2c_add_driver(&oz8806_driver); + + if(ret != 0) + pr_err("failed to register oz8806 i2c driver.\n"); + else + pr_err("Success to register oz8806 i2c driver.\n"); + + return ret; +} + +static void __exit oz8806_exit(void) +{ + pr_err("%s\n", __func__); + i2c_del_driver(&oz8806_driver); +} + +/*-------------------------------------------------------------------------*/ + +MODULE_DESCRIPTION("oz8806 Battery Monitor IC Driver"); +MODULE_LICENSE("GPL"); + +//subsys_initcall_sync(oz8806_init); +module_init(oz8806_init); +module_exit(oz8806_exit); diff --git a/drivers/power/sd77426_fg_mmi/oz8806_regdef.h b/drivers/power/sd77426_fg_mmi/oz8806_regdef.h new file mode 100644 index 000000000000..eba2e835589f --- /dev/null +++ b/drivers/power/sd77426_fg_mmi/oz8806_regdef.h @@ -0,0 +1,95 @@ +/***************************************************************************** +* Copyright(c) O2Micro, 2019. All rights reserved. +* +* O2Micro [OZ8806] Source Code Reference Design +* File:[oz8806_regdef.h] +* +* This Source Code Reference Design for O2MICRO [OZ8806] access +* ("Reference Design") is solely for the use of PRODUCT INTEGRATION REFERENCE ONLY, +* and contains confidential and privileged information of O2Micro International +* Limited. O2Micro shall have no liability to any PARTY FOR THE RELIABILITY, +* SERVICEABILITY FOR THE RESULT OF PRODUCT INTEGRATION, or results from: (i) any +* modification or attempted modification of the Reference Design by any party, or +* (ii) the combination, operation or use of the Reference Design with non-O2Micro +* Reference Design. Use of the Reference Design is at user's discretion to qualify +* the final work result. +*****************************************************************************/ + + #ifndef _OZ8806_REGDEF_H_ + #define _OZ8806_REGDEF_H_ + +/***************************************************************************** + * #include section + * add #include here + *****************************************************************************/ + + +/***************************************************************************** + * const section + * add const #define here + *****************************************************************************/ + +/* Operation register map define */ +#define OZ8806_OP_IDREV 0X00 //CHIP ID and Reversion + #define CHIP_ID_MASK 0xF8 //default CHIP_ID[7:3]=0x07 + #define CHIP_VER_MASK 0x07 //default CHIP_VER[2:0]=0x00 for 8806 + +#define OZ8806_OP_VD23 0x03 // + +#define OZ8806_OP_I2CCONFIG 0x04 //I2C config register + #define I2C_ADDRESS_MASK 0x0E //default 0X07 + +#define OZ8806_OP_PEC_CTRL 0x08 //PEC control register + #define PEC_EN 0x04 //PEC control register[2]: 1: PEC enable 0: PEC disable + +#define OZ8806_OP_CTRL 0x09 //Status control register + #define SOFT_RESET 0x80 //Status control register[7]: 1: reset + #define SLEEP_MODE 0x40 //Status control register[6]: 1: sleep 0:active + #define SLEEP_OCV_EN 0x20 + #define CHARGE_ON 0x10 + #define VME_SEL 0x0c + #define CHG_SEL 0x02 + #define BI_STATUS 0x01 + + +#define OZ8806_OP_VOLT_OFFSET 0X0A + #define VOLT_OFFSET_MASK 0xFC + +#define OZ8806_OP_BATTERY_ID 0x0B + +#define OZ8806_OP_CELL_TEMP 0x0C //cell temperature low byte,[7:4]->[3:0]of cell temp + #define CELL_TEMP_MASK 0x0FFF + +#define OZ8806_OP_CELL_TEMP_HIGH 0x0D //cell temperature high byte,[7:0]->[11:4]of cell temp + +#define OZ8806_OP_CELL_VOLT 0x0E //cell voltage low byte,[7:4]->[3:0]of cell volt + #define CELL_VOLT_MASK 0x0FFF + +#define OZ8806_OP_CELL_VOLT_HIGH 0x0f //cell voltage high byte,[7:0]->[11:4]of cell volt + +#define OZ8806_OP_OCV_LOW 0x10 //OCV low byte,[7:4]->[3:0]of OCV + #define OCV_LOW_MASK 0xF0 + #define SLEEP_OCV_FLAG 0X02 + #define POWER_OCV_FLAG 0X01 + +#define OZ8806_OP_OCV_HIGH 0x11 //OCV high byte,[7:0]->[11:4]of OCV + +#define OZ8806_OP_CURRENT 0x12 //CURRENT low byte,[7:1]->[5:0]of CURRENT + + +#define OZ8806_OP_CAR 0x14 //CAR low byte + +#define OZ8806_OP_BOARD_OFFSET 0x18 + + + +/***************************************************************************** + * function prototype section + * add function prototype here + *****************************************************************************/ + + + + +#endif + diff --git a/drivers/power/sd77426_fg_mmi/parameter.c b/drivers/power/sd77426_fg_mmi/parameter.c new file mode 100644 index 000000000000..58c22530a9ea --- /dev/null +++ b/drivers/power/sd77426_fg_mmi/parameter.c @@ -0,0 +1,164 @@ +/***************************************************************************** +* Copyright(c) O2Micro, 2019. All rights reserved. +* +* O2Micro [OZ8806] Source Code Reference Design +* File:[parameter.c] +* +* This Source Code Reference Design for O2MICRO [OZ8806] access +* ("Reference Design") is solely for the use of PRODUCT INTEGRATION REFERENCE ONLY, +* and contains confidential and privileged information of O2Micro International +* Limited. O2Micro shall have no liability to any PARTY FOR THE RELIABILITY, +* SERVICEABILITY FOR THE RESULT OF PRODUCT INTEGRATION, or results from: (i) any +* modification or attempted modification of the Reference Design by any party, or +* (ii) the combination, operation or use of the Reference Design with non-O2Micro +* Reference Design. Use of the Reference Design is at user's discretion to qualify +* the final work result. +*****************************************************************************/ + +#include +#include +#include +#include "parameter.h" +#include "table.h" +#include "battery_config.h" + + +one_latitude_data_t cell_temp_data[TEMPERATURE_DATA_NUM] = { + {681, 115}, {766, 113}, {865, 105}, + {980, 100}, {1113, 95}, {1266, 90}, + {1451, 85}, {1668, 80}, {1924, 75}, + {2228, 70}, {2588, 65}, {3020, 60}, + {3536, 55}, {4160, 50}, {4911, 45}, + {5827, 40}, {6940, 35}, {8313, 30}, + {10000, 25}, {12090, 20}, {14690, 15}, + {17960, 10}, {22050, 5}, {27280, 0}, + {33900, -5}, {42470, -10}, {53410, -15}, + {67770, -20}, +}; + + +config_data_t config_data = { + .fRsense = O2_CONFIG_RSENSE, + .temp_pull_up = O2_TEMP_PULL_UP_R, + .temp_ref_voltage = O2_TEMP_REF_VOLTAGE, + .dbCARLSB = 5, + .dbCurrLSB = 781 , + .fVoltLSB = 250, + + .design_capacity = O2_CONFIG_CAPACITY, + .charge_cv_voltage = OZ8806_VOLTAGE, + .charge_end_current = O2_CONFIG_EOC, + .discharge_end_voltage = OZ8806_EOD, + .board_offset = O2_CONFIG_BOARD_OFFSET, + .debug = 1, +}; + + +/***************************************************************************** + * bmu_init_parameter: + * this implements a interface for customer initiating bmu parameters + * Return: NULL + *****************************************************************************/ +void bmu_init_parameter(parameter_data_t *parameter_customer) +{ + //如果选用88106,并且prg pin拉低,这一标志可以清0.以避免i2c通讯问题。 + //如果prg pin拉高,则这个标志需要写1,否则会导致电量不更新。此标志在 + //库中,默认拉高。 +#ifdef CONFIG_OZ115_SUPPORT + check_chip_function = 1; +#else + check_chip_function = 0; +#endif + parameter_customer->config = &config_data; + parameter_customer->ocv = ocv_data; + parameter_customer->temperature = cell_temp_data; + parameter_customer->ocv_data_num = OCV_DATA_NUM; + parameter_customer->cell_temp_num = TEMPERATURE_DATA_NUM; + parameter_customer->charge_pursue_step = 10; + parameter_customer->discharge_pursue_step = 6; + parameter_customer->discharge_pursue_th = 10; + parameter_customer->wait_method = 2; + + //parameter_customer->BATT_CAPACITY = "/data/sCaMAH.dat"; + //parameter_customer->BATT_FCC = "/data/fcc.dat"; + //parameter_customer->OCV_FLAG = "/data/ocv_flag.dat"; + //parameter_customer->BATT_OFFSET = "/data/offset.dat"; + + parameter_customer->fix_car_init = 0; + parameter_customer->power_on_retry_times = 0; + + //if read/write file /data/sCaMAH.dat in userspace + //please enable "bmu_sys_rw_kernel = 0" +#ifdef USERSPACE_READ_SAVED_CAP + parameter_customer->bmu_sys_rw_kernel = 0; +#else + parameter_customer->bmu_sys_rw_kernel = 1; +#endif +} +EXPORT_SYMBOL(bmu_init_parameter); + + +/***************************************************************************** + * Description: + * bmu_init_gg + * Return: NULL + *****************************************************************************/ +void bmu_init_gg(gas_gauge_t *gas_gauge) +{ + //gas_gauge->charge_table_num = CHARGE_DATA_NUM; + gas_gauge->rc_x_num = XAxis; + gas_gauge->rc_y_num = YAxis; + gas_gauge->rc_z_num = ZAxis; + + gas_gauge->discharge_current_th = DISCH_CURRENT_TH; + gas_gauge->fcc_data = config_data.design_capacity; + + pr_err("AAAA battery_id is %s\n", battery_id[0]); + + gas_gauge->ri = 18; + gas_gauge->line_impedance = 10; + +#if 0 + //add this for oinom + gas_gauge->lower_capacity_reserve = 5; + gas_gauge->lower_capacity_soc_start =30; + + + //gas_gauge->percent_10_reserve = 66; +#endif +} +EXPORT_SYMBOL(bmu_init_gg); + + +#ifdef OZ8806_API + +#define BMU_INIT(x) \ +void bmu_init_##x(uint8_t *dest, uint32_t bytes)\ +{\ + memcpy(dest, (uint8_t *)x, bytes);\ +}\ +EXPORT_SYMBOL(bmu_init_##x);\ + +//BMU_INIT(charge_data) +BMU_INIT(XAxisElement) +BMU_INIT(YAxisElement) +BMU_INIT(ZAxisElement) +BMU_INIT(RCtable) + +#endif + +void bmu_init_table(int **x, int **y, int **z, int **rc) +{ + *x = (int *)((uint8_t *)XAxisElement); + *y = (int *)((uint8_t *)YAxisElement); + *z = (int *)((uint8_t *)ZAxisElement); + *rc = (int *)((uint8_t *)RCtable); +} +EXPORT_SYMBOL(bmu_init_table); + +const char * get_table_version(void) +{ + return table_version; +} +EXPORT_SYMBOL(get_table_version); + diff --git a/drivers/power/sd77426_fg_mmi/parameter.h b/drivers/power/sd77426_fg_mmi/parameter.h new file mode 100644 index 000000000000..2aa57fcce29d --- /dev/null +++ b/drivers/power/sd77426_fg_mmi/parameter.h @@ -0,0 +1,335 @@ +/***************************************************************************** +* Copyright(c) O2Micro, 2019. All rights reserved. +* +* O2Micro [OZ8806] Source Code Reference Design +* File:[parameter.h] +* +* This Source Code Reference Design for O2MICRO [OZ8806] access +* ("Reference Design") is solely for the use of PRODUCT INTEGRATION REFERENCE ONLY, +* and contains confidential and privileged information of O2Micro International +* Limited. O2Micro shall have no liability to any PARTY FOR THE RELIABILITY, +* SERVICEABILITY FOR THE RESULT OF PRODUCT INTEGRATION, or results from: (i) any +* modification or attempted modification of the Reference Design by any party, or +* (ii) the combination, operation or use of the Reference Design with non-O2Micro +* Reference Design. Use of the Reference Design is at user's discretion to qualify +* the final work result. +*****************************************************************************/ + +#ifndef _PARAMETER_H_ +#define _PARAMETER_H_ + +/**************************************************************************** +* #include section +* add #include here if any +***************************************************************************/ +#include "table.h" +#include +#include + + +/**************************************************************************** +* #define section +* add constant #define here if any +***************************************************************************/ +//#define MUTEX_TIMEOUT 5000 +#define MYDRIVER "oz8806" //"oz8806" + +#define DISCH_CURRENT_TH -10 +#define O2_OCV_100_VOLTAGE (xaxis_table[X_AXIS - 1]) +#define TEMPERATURE_DATA_NUM 28 + +#define num_0 0 +#define num_1 1 +#define num_32768 32768 +#define num_5 5 +#define num_0x2c 0x2c +#define num_0x40 0x40 +#define num_0x20 0x20 +#define num_1000 1000 +#define num_50 50 +#define num_100 100 +#define num_10 10 +#define num_7 7 +#define num_2 2 +#define num_1000 1000 +#define num_0x2f 0x2f +#define num_0x28 0x28 +#define num_0x07 0x07 +#define num_6 6 +#define num_10 10 +#define num_20 20 +#define num_9 9 +#define num_95 95 +#define num_0x4c 0x4c +#define num_0x40 0x40 +#define num_3 3 +#define num_99 99 +#define num_15 15 +#define num_25 25 +#define num_0x80 0x80 + +//#define PEC_CHECK + +#define INIT_CAP (-2) +#define NO_FILE (-1) + + +/**************************************************************************** +* Struct section +* add struct #define here if any +***************************************************************************/ + +enum charger_type_t { + O2_CHARGER_UNKNOWN = -1, + O2_CHARGER_BATTERY = 0, + O2_CHARGER_USB = 1, + O2_CHARGER_AC = 4, +}; + +struct batt_data { + + int32_t batt_soc;//Relative State Of Charged, present percentage of battery capacity + int32_t batt_voltage;//Voltage of battery, in mV + int32_t batt_current;//Current of battery, in mA; plus value means charging, minus value means discharging + + int32_t batt_temp;//Temperature of battery + int32_t batt_capacity;//adjusted residual capacity + int32_t batt_fcc_data; + int32_t discharge_current_th; + uint8_t charge_end; +}; + +struct oz8806_data +{ + struct power_supply *bat; + struct power_supply_desc bat_desc; + struct power_supply *ac_psy; + struct power_supply *usb_psy; + + struct delayed_work work; + unsigned int interval; + + struct i2c_client *myclient; + + struct notifier_block pm_nb; //alternative suspend/resume method + struct batt_data batt_info; + int status; +}; + + +typedef struct tag_config_data { + int32_t fRsense; //= 20; //Rsense value of chip, in mini ohm + int32_t temp_pull_up; //230000; + int32_t temp_ref_voltage; //1800;1.8v + int32_t dbCARLSB; //= 5.0; //LSB of CAR, comes from spec + int32_t dbCurrLSB; //781 (7.8 *100 uV); //LSB of Current, comes from spec + int32_t fVoltLSB; //250 (2.5*100 mV); //LSB of Voltage, comes from spec + + int32_t design_capacity; //= 7000; //design capacity of the battery + int32_t charge_cv_voltage; //= 4200; //CV Voltage at fully charged + int32_t charge_end_current; //= 100; //the current threshold of End of Charged + int32_t discharge_end_voltage; //= 3550; //mV + int32_t board_offset; //0; //mA, not more than caculate data + uint8_t debug; // enable or disable O2MICRO debug information + +}config_data_t; + + +typedef struct tag_parameter_data { + int32_t ocv_data_num; + int32_t cell_temp_num; + one_latitude_data_t *ocv; + one_latitude_data_t *temperature; + config_data_t *config; + + struct i2c_client *client; + + uint8_t charge_pursue_step; + uint8_t discharge_pursue_step; + uint8_t discharge_pursue_th; + uint8_t wait_method; + char * BATT_CAPACITY ; + char * BATT_FCC; + char * OCV_FLAG; + char * BATT_OFFSET; + uint8_t oz8806_cell_num; + int32_t res_divider_ratio; + uint8_t set_soc_from_ext; + int32_t soc_external; + uint8_t file_not_ok_cap; + uint8_t fix_car_init; + uint8_t bmu_sys_rw_kernel; + int8_t power_on_retry_times; +}parameter_data_t; + + +typedef struct tag_bmu { + int32_t Battery_ok; + int32_t fRC; //= 0; //Remaining Capacity, indicates how many mAhr in battery + int32_t fRSOC; //50 = 50%; //Relative State Of Charged, present percentage of battery capacity + int32_t fVolt; //= 0; //Voltage of battery, in mV + int32_t fCurr; //= 0; //Current of battery, in mA; plus value means charging, minus value means discharging + int32_t fPrevCurr; //= 0; //last one current reading + int32_t fOCVVolt; //= 0; //Open Circuit Voltage + int32_t fCellTemp; //= 0; //Temperature of battery + int32_t fRCPrev; + int32_t sCaMAH; //= 0; //adjusted residual capacity + int32_t i2c_error_times; +}bmu_data_t; + +typedef struct tag_gas_gauge { + + int32_t overflow_data; //unit: mAh, maximum capacity that the IC can measure + uint8_t discharge_end; + uint8_t charge_end; + uint8_t charge_fcc_update; + uint8_t discharge_fcc_update; + + int32_t sCtMAH ; //be carefull, this must be int32_t + int32_t fcc_data; + int32_t discharge_sCtMAH ;//be carefull, this must be int32_t + //uint8_t charge_wait_times; + //uint8_t discharge_wait_times; + //uint8_t charge_count; + //uint8_t discharge_count; + //uint32_t bmu_tick; + //uint32_t charge_tick; + + //uint8_t charge_table_num; + uint8_t rc_x_num; + uint8_t rc_y_num; + uint8_t rc_z_num; + + uint8_t charge_strategy; + int32_t charge_sCaUAH; + int32_t charge_ratio; //this must be static + uint8_t charge_table_flag; + int32_t charge_end_current_th2; + int32_t charge_max_ratio; + + uint8_t discharge_strategy; + int32_t discharge_sCaUAH; + int32_t discharge_ratio; //this must be static + uint8_t discharge_table_flag; + int32_t discharge_current_th; + uint32_t discharge_max_ratio; + + int32_t dsg_end_voltage_hi; + int32_t dsg_end_voltage_th1; + int32_t dsg_end_voltage_th2; + uint8_t dsg_count_2; + + uint8_t ocv_flag; + + uint8_t vbus_ok; + + uint8_t charge_full; + int32_t ri; + int32_t batt_ri; + int32_t line_impedance; + int32_t max_chg_reserve_percentage; + int32_t fix_chg_reserve_percentage; + uint8_t fast_charge_step; + int32_t start_fast_charge_ratio; + uint8_t charge_method_select; + int32_t max_charge_current_fix; + uint8_t ext_temp_measure; + uint8_t bmu_init_ok; + int32_t stored_capacity; + + uint8_t lower_capacity_reserve; + uint8_t lower_capacity_soc_start; + + uint8_t percent_10_reserve; +}gas_gauge_t; + +/**************************************************************************** +* extern variable/function declaration of table.c +***************************************************************************/ + +extern one_latitude_data_t ocv_data[OCV_DATA_NUM]; +extern int XAxisElement[XAxis]; +extern int YAxisElement[YAxis]; +extern int ZAxisElement[ZAxis]; +extern int RCtable[YAxis*ZAxis][XAxis]; +//extern one_latitude_data_t charge_data[CHARGE_DATA_NUM]; + + +/**************************************************************************** +* extern variable/function defined by parameter.c +***************************************************************************/ +extern config_data_t config_data; +extern uint8_t check_chip_function; +//****************************************************************************** + +extern void bmu_init_parameter(parameter_data_t *parameter_customer); +extern void bmu_init_gg(gas_gauge_t *gas_gauge); +extern void bmu_reinit(int32_t mode); //mode = 0,wakeup ic,rewrite car; mode = 1, reinit from ocv +#ifndef CONFIG_OZ8806_M +extern int bmulib_init(void); +extern void bmulib_exit(void); +#endif + +#ifdef OZ8806_API +//extern void bmu_init_charge_data(uint8_t *dest, uint32_t bytes); +extern void bmu_init_XAxisElement(uint8_t *dest, uint32_t bytes); +extern void bmu_init_YAxisElement(uint8_t *dest, uint32_t bytes); +extern void bmu_init_ZAxisElement(uint8_t *dest, uint32_t bytes); +extern void bmu_init_RCtable(uint8_t *dest, uint32_t bytes); +#endif +extern void bmu_init_table(int **x, int **y, int **z, int **rc); + +extern const char * get_table_version(void); + +/**************************************************************************** +* extern variable/function defined by oz8806_battery.c +***************************************************************************/ +#ifdef OZ8806_API +extern bmu_data_t *batt_info_ptr; +extern struct mutex *update_mutex_ptr; +#endif +extern int32_t oz8806_vbus_voltage(void); +extern int32_t oz8806_get_simulated_temp(void); +extern int32_t oz8806_get_init_status(void); //if return 1, battery capacity is initiated successfully +extern void oz8806_battery_update_data(void); +extern int oz8806_get_soc(void); +extern int oz8806_get_remaincap(void); +extern int oz8806_get_battry_current(void); +extern int oz8806_get_battery_voltage(void); +extern int oz8806_get_battery_temp(void); + +//export symbol for bmulib +extern struct i2c_client * oz8806_get_client(void); +extern int8_t get_adapter_status(void); + +extern void oz8806_register_bmu_callback(void *bmu_polling_loop_func, + void *bmu_wake_up_chip_func, + void *bmu_power_down_chip_func, + void *charge_end_process_func, + void *discharge_end_process_func, + void *oz8806_temp_read_func, + void *oz8806_current_read_func, + void *oz8806_voltage_read_func); + +extern void unregister_bmu_callback(void); +extern void oz8806_set_batt_info_ptr(bmu_data_t *batt_info); +extern void oz8806_set_gas_gauge(gas_gauge_t *gas_gauge); +extern int oz8806_get_save_capacity(void); +extern int oz8806_get_soc_from_ext(void); +extern unsigned long oz8806_get_power_on_time(void); +extern unsigned long oz8806_get_boot_up_time(void); +extern int oz8806_wakeup_full_power(void); + +/**************************************************************************** +* extern variable/function defined by oz8806_api_dev.c. +* This file is deprecated in Linux system. +***************************************************************************/ +#ifdef OZ8806_API +extern unsigned long oz8806_get_kernel_memaddr(void); +extern void bmu_call(void); +#endif + +extern int is_battery_exchanged(void); + +#endif //end _PARAMETER_H_ + diff --git a/drivers/power/sd77426_fg_mmi/table.c b/drivers/power/sd77426_fg_mmi/table.c new file mode 100644 index 000000000000..c4a72b15fedd --- /dev/null +++ b/drivers/power/sd77426_fg_mmi/table.c @@ -0,0 +1,129 @@ +/***************************************************************************** +* Copyright(c) O2Micro, 2014. All rights reserved. +* +* O2Micro battery gauge driver +* File: table.c +* +* $Source: /data/code/CVS +* $Revision: 4.00.01 $ +* +* This program is free software and can be edistributed and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This Source Code Reference Design for O2MICRO Battery Gauge access (\u201cReference Design\u201d) +* is sole for the use of PRODUCT INTEGRATION REFERENCE ONLY, and contains confidential +* and privileged information of O2Micro International Limited. O2Micro shall have no +* liability to any PARTY FOR THE RELIABILITY, SERVICEABILITY FOR THE RESULT OF PRODUCT +* INTEGRATION, or results from: (i) any modification or attempted modification of the +* Reference Design by any party, or (ii) the combination, operation or use of the +* Reference Design with non-O2Micro Reference Design. +* +* Battery Manufacture: Lenovo +* Battery Model: BL244 +* Absolute Max Capacity(mAhr): 5158 +* Limited Charge Voltage(mV): 4350 +* Cutoff Discharge Voltage(mV): 3200 +* Equipment: "JY1-8","JY1-4","JY1-4","JY2-8","JY2-8","JY2-8","JY2-5","JY1-1","JY1-1","JY1-8","JY1-8","JY1-8","JY1-8","JY2-5","JY2-5","JY2-5","JY2-5","JY1-8","JY2-8","JY2-8","JY1-8","JY1-2","JY1-2","JY2-6","JY2-6","JY2-6","JY2-7","JY2-7","JY2-7","JY2-7","JY2-7","JY2-7","JY2-7","JY2-7","JY2-7","JY2-7","JY2-7","JY2-7","JY2-7","JY2-7","JY2-7","JY2-7","JY2-7","JY2-7","JY1-3","JY1-3","JY1-6","JY1-6","JY1-6","JY2-8","JY2-5","JY2-5" +* Tester: "SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ" +* Battery ID: "BL244-1","BL244-1","BL244-1","BL244-1","BL244-1","BL244-1","BL244-1","BL244-1","BL244-1","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-3","BL244-3","BL244-3","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-1","BL244-2","BL244-02" +* Version = V00.13.00 +* Date = 2015.6.23 +* Comment = +* +*****************************************************************************/ + +#include +#include "table.h" + +/***************************************************************************** +* Global variables section - Exported +* add declaration of global variables that will be exported here +* e.g. +* int8_t foo; +****************************************************************************/ +const char * table_version = "V00.13.00-2015.6.23-BL244"; + +const char *battery_id[BATTERY_ID_NUM] = {"BL244-1","BL244-1","BL244-1","BL244-1","BL244-1","BL244-1","BL244-1","BL244-1","BL244-1","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-3","BL244-3","BL244-3","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-1","BL244-2","BL244-02"}; + +one_latitude_data_t ocv_data[OCV_DATA_NUM] = {{3242, 0},{3248, 2},{3488, 3},{3597, 5},{3669, 6},{3685, 8},{3689, 9},{3691, 11},{3693, 13},{3700, 14},{3713, 16},{3720, 17},{3731, 19},{3739, 20},{3744, 22},{3749, 23},{3755, 25},{3761, 27},{3766, 28},{3771, 30},{3776, 31},{3780, 33},{3785, 34},{3789, 36},{3793, 38},{3797, 39},{3802, 41},{3808, 42},{3814, 44},{3819, 45},{3826, 47},{3833, 48},{3841, 50},{3848, 52},{3857, 53},{3867, 55},{3879, 56},{3893, 58},{3911, 59},{3928, 61},{3942, 63},{3955, 64},{3967, 66},{3976, 67},{3985, 69},{3996, 70},{4016, 72},{4041, 73},{4060, 75},{4070, 77},{4084, 78},{4100, 80},{4117, 81},{4135, 83},{4151, 84},{4168, 86},{4185, 88},{4203, 89},{4220, 91},{4238, 92},{4256, 94},{4274, 95},{4292, 97},{4311, 98},{4333, 100}}; + +//real current to soc +one_latitude_data_t charge_data[CHARGE_DATA_NUM] = {{100, 10000},{105, 9994},{110, 9988},{115, 9981},{120, 9976},{125, 9970},{130, 9963},{135, 9957},{140, 9951},{145, 9945},{150, 9940},{155, 9933},{160, 9927},{165, 9920},{170, 9915},{175, 9908},{180, 9902},{185, 9896},{190, 9890},{195, 9884},{200, 9878},{210, 9865},{220, 9854},{230, 9842},{240, 9830},{250, 9819},{260, 9806},{270, 9794},{280, 9782},{290, 9770},{300, 9758},{310, 9746},{320, 9734},{330, 9722},{340, 9711},{350, 9699},{360, 9687},{370, 9676},{380, 9664},{390, 9652},{400, 9640},{420, 9617},{440, 9594},{460, 9571},{480, 9548},{500, 9524},{520, 9501},{540, 9479},{560, 9455},{580, 9432},{600, 9409},{625, 9381},{650, 9352},{675, 9323},{700, 9295},{725, 9267},{750, 9238},{775, 9211},{800, 9182},{825, 9155},{850, 9128},{875, 9100},{900, 9073},{950, 9020},{1000, 9003}}; + +//RC table X Axis value, in mV format +int32_t XAxisElement[XAxis] = {3200, 3400, 3515, 3635, 3656, 3661, 3668, 3685, 3700, 3711, 3719, 3729, 3739, 3751, 3759, 3766, 3774, 3782, 3791, 3801, 3812, 3824, 3838, 3856, 3882, 3906, 3927, 3948, 3968, 3987, 4015, 4038, 4062, 4089, 4115, 4142, 4169, 4198, 4226, 4255, 4286, 4325}; + +//RC table Y Axis value, in mA format +int32_t YAxisElement[YAxis] = {200, 400, 600, 800, 1000, 1500, 2000}; + +// RC table Z Axis value, in 10*'C format +int32_t ZAxisElement[ZAxis] = {-49, 0, 100, 200, 250, 300, 400}; + +// contents of RC table, its unit is 10000C, 1C = DesignCapacity +int32_t RCtable[YAxis*ZAxis][XAxis]={ + + +//temp = -5.0 ^C +{385, 585, 861, 1845, 2149, 2234, 2377, 2813, 3414, 3870, 4138, 4427, 4676, 4949, 5113, 5251, 5404, 5536, 5689, 5844, 6013, 6189, 6393, 6666, 7020, 7238, 7381, 7507, 7631, 7786, 8110, 8321, 8535, 8774, 9005, 9244, 9462, 9683, 9865, 9979, 10000, 10000}, +{680, 1222, 1888, 3842, 4481, 4615, 4791, 5174, 5462, 5657, 5792, 5960, 6113, 6296, 6410, 6510, 6625, 6734, 6868, 7010, 7157, 7293, 7435, 7587, 7778, 7955, 8135, 8344, 8531, 8693, 8932, 9121, 9304, 9503, 9672, 9825, 9928, 9981, 10000, 10000, 10000, 10000}, +{1073, 2238, 3499, 6091, 6462, 6545, 6657, 6915, 7137, 7292, 7398, 7541, 7674, 7835, 7936, 8022, 8114, 8199, 8291, 8391, 8490, 8595, 8711, 8867, 9088, 9268, 9417, 9544, 9652, 9733, 9833, 9893, 9935, 9968, 9990, 10000, 10000, 10000, 10000, 10000, 10000, 10000}, +{1124, 2221, 3822, 6241, 6542, 6612, 6711, 6934, 7129, 7259, 7354, 7467, 7570, 7692, 7767, 7831, 7898, 7968, 8046, 8128, 8221, 8319, 8441, 8604, 8833, 9027, 9186, 9341, 9474, 9587, 9737, 9833, 9901, 9950, 9982, 9999, 10000, 10000, 10000, 10000, 10000, 10000}, +{1650, 3381, 5594, 7729, 8093, 8181, 8305, 8608, 8868, 9055, 9168, 9288, 9384, 9473, 9521, 9558, 9594, 9624, 9658, 9691, 9723, 9754, 9782, 9818, 9857, 9890, 9913, 9935, 9952, 9968, 9987, 9997, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000}, +{2515, 5346, 7329, 9237, 9419, 9460, 9512, 9603, 9664, 9699, 9720, 9746, 9767, 9790, 9802, 9811, 9826, 9834, 9846, 9856, 9870, 9883, 9898, 9913, 9938, 9959, 9976, 9987, 9999, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000}, +{3939, 7150, 8855, 9807, 9833, 9839, 9849, 9866, 9881, 9888, 9898, 9906, 9915, 9926, 9933, 9939, 9946, 9951, 9957, 9967, 9976, 9985, 9991, 9997, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000}, + +//temp = 0.0 ^C +{261, 403, 551, 1253, 1548, 1613, 1710, 1992, 2317, 2659, 2997, 3502, 3887, 4251, 4472, 4648, 4831, 5002, 5189, 5371, 5563, 5757, 5962, 6218, 6606, 6945, 7137, 7278, 7393, 7506, 7768, 8038, 8260, 8504, 8742, 8992, 9234, 9482, 9708, 9907, 9999, 10000}, +{476, 710, 1089, 2313, 2806, 2957, 3225, 3910, 4397, 4681, 4865, 5092, 5290, 5509, 5651, 5770, 5899, 6020, 6157, 6303, 6463, 6643, 6856, 7098, 7338, 7505, 7644, 7801, 8003, 8203, 8462, 8667, 8876, 9111, 9329, 9539, 9733, 9900, 9980, 10000, 10000, 10000}, +{1048, 1586, 2255, 4507, 5091, 5217, 5374, 5708, 5964, 6140, 6259, 6409, 6547, 6706, 6814, 6907, 7006, 7111, 7232, 7358, 7488, 7614, 7742, 7882, 8068, 8248, 8436, 8631, 8799, 8950, 9159, 9340, 9507, 9676, 9811, 9912, 9966, 9994, 10000, 10000, 10000, 10000}, +{930, 1787, 2854, 5497, 5878, 5967, 6082, 6343, 6561, 6714, 6824, 6959, 7087, 7241, 7337, 7422, 7514, 7595, 7690, 7780, 7877, 7973, 8087, 8229, 8456, 8672, 8852, 9018, 9176, 9314, 9507, 9651, 9777, 9884, 9945, 9980, 10000, 10000, 10000, 10000, 10000, 10000}, +{1371, 2608, 4230, 6652, 6947, 7012, 7104, 7313, 7493, 7618, 7704, 7816, 7921, 8036, 8113, 8174, 8241, 8304, 8378, 8456, 8540, 8630, 8737, 8878, 9073, 9235, 9367, 9489, 9597, 9685, 9798, 9869, 9920, 9960, 9986, 10000, 10000, 10000, 10000, 10000, 10000, 10000}, +{1916, 4103, 6464, 8163, 8399, 8455, 8535, 8701, 8841, 8932, 8995, 9073, 9144, 9227, 9274, 9316, 9363, 9404, 9450, 9496, 9543, 9594, 9643, 9700, 9776, 9827, 9867, 9899, 9924, 9947, 9975, 9993, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000}, +{2698, 5808, 7704, 9103, 9267, 9304, 9350, 9451, 9527, 9570, 9603, 9641, 9670, 9705, 9723, 9742, 9759, 9774, 9791, 9808, 9825, 9842, 9861, 9886, 9916, 9942, 9961, 9981, 9994, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000}, + +//temp = 10.0 ^C +{219, 334, 461, 731, 1085, 1275, 1423, 1638, 1889, 2091, 2298, 2610, 3038, 3582, 3866, 4086, 4320, 4525, 4749, 4970, 5192, 5408, 5633, 5884, 6205, 6516, 6837, 7069, 7218, 7326, 7492, 7765, 8023, 8272, 8508, 8754, 9000, 9255, 9500, 9738, 9958, 10000}, +{283, 428, 582, 1510, 1809, 1887, 2008, 2396, 2934, 3434, 3743, 4073, 4359, 4657, 4843, 4994, 5157, 5302, 5470, 5636, 5809, 5981, 6174, 6418, 6802, 7086, 7247, 7375, 7500, 7651, 7979, 8195, 8411, 8652, 8887, 9131, 9361, 9601, 9817, 9971, 10000, 10000}, +{315, 501, 756, 2088, 2595, 2748, 3012, 3707, 4198, 4485, 4678, 4906, 5112, 5339, 5482, 5604, 5734, 5857, 5993, 6139, 6292, 6457, 6655, 6910, 7180, 7351, 7485, 7640, 7844, 8051, 8311, 8518, 8731, 8975, 9199, 9425, 9641, 9845, 9964, 10000, 10000, 10000}, +{533, 806, 1341, 3258, 4058, 4220, 4428, 4851, 5179, 5388, 5530, 5706, 5866, 6046, 6164, 6262, 6372, 6478, 6602, 6735, 6888, 7045, 7212, 7377, 7567, 7733, 7908, 8128, 8323, 8490, 8735, 8932, 9133, 9353, 9550, 9737, 9884, 9968, 9997, 10000, 10000, 10000}, +{588, 1005, 1757, 4445, 4951, 5057, 5205, 5524, 5782, 5959, 6082, 6236, 6382, 6549, 6661, 6760, 6871, 6975, 7093, 7208, 7320, 7423, 7531, 7665, 7867, 8099, 8309, 8499, 8675, 8841, 9079, 9271, 9455, 9655, 9816, 9929, 9977, 10000, 10000, 10000, 10000, 10000}, +{1094, 2066, 3680, 6320, 6626, 6691, 6789, 7008, 7193, 7324, 7412, 7519, 7617, 7734, 7801, 7862, 7927, 7989, 8057, 8138, 8227, 8326, 8443, 8598, 8811, 8998, 9153, 9298, 9434, 9551, 9712, 9819, 9896, 9950, 9980, 10000, 10000, 10000, 10000, 10000, 10000, 10000}, +{1439, 3084, 5568, 7455, 7698, 7753, 7826, 7994, 8134, 8228, 8298, 8377, 8457, 8555, 8617, 8673, 8736, 8792, 8867, 8937, 9018, 9100, 9192, 9303, 9462, 9591, 9689, 9779, 9841, 9886, 9932, 9964, 9984, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000}, + +//temp = 20.0 ^C +{143, 253, 378, 608, 762, 887, 1236, 1499, 1755, 1937, 2123, 2408, 2699, 3182, 3487, 3733, 3997, 4221, 4469, 4709, 4948, 5182, 5423, 5680, 5978, 6232, 6484, 6813, 7052, 7193, 7363, 7579, 7869, 8121, 8357, 8604, 8849, 9106, 9350, 9600, 9850, 10000}, +{163, 290, 430, 1009, 1477, 1546, 1660, 1945, 2315, 2629, 2935, 3361, 3711, 4082, 4304, 4486, 4672, 4850, 5036, 5223, 5417, 5594, 5783, 5998, 6294, 6600, 6907, 7109, 7247, 7364, 7639, 7897, 8117, 8364, 8599, 8843, 9082, 9333, 9569, 9796, 9978, 10000}, +{214, 360, 521, 1592, 1928, 2024, 2180, 2652, 3249, 3660, 3917, 4208, 4465, 4752, 4931, 5072, 5226, 5364, 5517, 5666, 5824, 5973, 6140, 6352, 6691, 7016, 7199, 7340, 7476, 7662, 7976, 8189, 8404, 8653, 8885, 9126, 9356, 9595, 9806, 9964, 10000, 10000}, +{259, 426, 630, 2074, 2600, 2763, 3034, 3682, 4151, 4435, 4627, 4858, 5062, 5293, 5431, 5551, 5678, 5789, 5919, 6052, 6190, 6337, 6513, 6746, 7076, 7271, 7413, 7574, 7789, 7990, 8248, 8457, 8674, 8915, 9143, 9372, 9590, 9804, 9949, 10000, 10000, 10000}, +{346, 539, 865, 2913, 3708, 3874, 4090, 4543, 4889, 5110, 5262, 5448, 5613, 5802, 5919, 6015, 6124, 6228, 6350, 6477, 6620, 6778, 6963, 7162, 7371, 7540, 7725, 7945, 8140, 8309, 8559, 8763, 8968, 9200, 9413, 9626, 9811, 9945, 9993, 10000, 10000, 10000}, +{502, 868, 1860, 4929, 5343, 5433, 5558, 5827, 6056, 6211, 6326, 6461, 6596, 6755, 6857, 6948, 7046, 7132, 7226, 7318, 7409, 7499, 7607, 7757, 8005, 8234, 8421, 8603, 8775, 8935, 9168, 9353, 9533, 9719, 9865, 9950, 9989, 10000, 10000, 10000, 10000, 10000}, +{758, 1555, 3524, 6114, 6418, 6487, 6584, 6803, 6994, 7120, 7206, 7313, 7404, 7513, 7579, 7638, 7702, 7769, 7847, 7933, 8032, 8139, 8268, 8428, 8648, 8846, 9016, 9179, 9330, 9471, 9661, 9792, 9887, 9950, 9986, 10000, 10000, 10000, 10000, 10000, 10000, 10000}, + +//temp = 25.0 ^C +{148, 258, 383, 615, 761, 886, 1252, 1515, 1772, 1959, 2150, 2430, 2706, 3120, 3411, 3666, 3928, 4166, 4412, 4656, 4903, 5139, 5383, 5639, 5922, 6167, 6407, 6706, 6999, 7161, 7338, 7553, 7841, 8093, 8331, 8579, 8825, 9082, 9327, 9575, 9830, 10000}, +{162, 285, 425, 905, 1454, 1520, 1630, 1916, 2277, 2562, 2833, 3227, 3581, 3964, 4191, 4380, 4575, 4753, 4948, 5144, 5340, 5525, 5717, 5930, 6214, 6498, 6797, 7050, 7202, 7323, 7595, 7850, 8074, 8322, 8557, 8802, 9041, 9296, 9535, 9770, 9969, 10000}, +{233, 373, 531, 1570, 1898, 1990, 2135, 2579, 3103, 3520, 3791, 4093, 4359, 4658, 4837, 4984, 5145, 5286, 5446, 5601, 5757, 5907, 6072, 6273, 6585, 6920, 7145, 7294, 7431, 7611, 7921, 8136, 8352, 8599, 8832, 9072, 9303, 9547, 9767, 9949, 10000, 10000}, +{224, 378, 560, 1901, 2359, 2497, 2710, 3328, 3831, 4138, 4350, 4595, 4819, 5067, 5222, 5353, 5486, 5599, 5733, 5870, 6004, 6146, 6307, 6527, 6877, 7134, 7285, 7435, 7631, 7842, 8105, 8316, 8529, 8774, 9006, 9241, 9469, 9705, 9896, 9993, 10000, 10000}, +{256, 434, 678, 2466, 3163, 3349, 3601, 4097, 4484, 4729, 4902, 5107, 5284, 5488, 5615, 5719, 5829, 5934, 6050, 6173, 6307, 6451, 6626, 6858, 7136, 7313, 7474, 7685, 7892, 8070, 8325, 8534, 8748, 8988, 9213, 9440, 9661, 9865, 9976, 10000, 10000, 10000}, +{317, 587, 1382, 4310, 4793, 4893, 5031, 5342, 5595, 5760, 5877, 6022, 6159, 6319, 6420, 6512, 6614, 6712, 6830, 6943, 7064, 7170, 7281, 7422, 7650, 7890, 8088, 8279, 8454, 8623, 8869, 9068, 9265, 9489, 9685, 9860, 9958, 9998, 10000, 10000, 10000, 10000}, +{436, 957, 2570, 5495, 5829, 5902, 6006, 6242, 6452, 6591, 6693, 6819, 6935, 7059, 7139, 7201, 7272, 7338, 7420, 7501, 7599, 7702, 7830, 8003, 8241, 8452, 8633, 8813, 8983, 9137, 9357, 9527, 9701, 9863, 9947, 9988, 10000, 10000, 10000, 10000, 10000, 10000}, + +//temp = 30.0 ^C +{51, 163, 291, 527, 689, 824, 1215, 1450, 1708, 1903, 2121, 2397, 2673, 3020, 3298, 3551, 3823, 4061, 4316, 4569, 4815, 5052, 5302, 5561, 5839, 6085, 6325, 6590, 6897, 7098, 7297, 7528, 7794, 8051, 8294, 8542, 8788, 9049, 9292, 9543, 9801, 10000}, +{143, 266, 406, 856, 1431, 1495, 1606, 1889, 2248, 2532, 2777, 3128, 3473, 3862, 4102, 4293, 4492, 4674, 4876, 5075, 5276, 5469, 5659, 5871, 6153, 6424, 6690, 6985, 7170, 7306, 7572, 7820, 8044, 8294, 8531, 8777, 9017, 9272, 9509, 9747, 9961, 10000}, +{153, 291, 446, 1449, 1775, 1862, 2001, 2421, 2884, 3287, 3561, 3872, 4155, 4456, 4647, 4799, 4967, 5115, 5283, 5447, 5610, 5772, 5937, 6137, 6432, 6734, 7005, 7188, 7336, 7507, 7812, 8029, 8247, 8494, 8728, 8969, 9205, 9455, 9688, 9902, 10000, 10000}, +{197, 351, 527, 1847, 2290, 2417, 2610, 3187, 3694, 4001, 4221, 4467, 4697, 4947, 5102, 5235, 5368, 5494, 5630, 5760, 5898, 6039, 6195, 6398, 6718, 7019, 7196, 7355, 7545, 7749, 8011, 8224, 8440, 8683, 8914, 9152, 9378, 9621, 9831, 9979, 10000, 10000}, +{224, 394, 618, 2344, 2969, 3148, 3390, 3925, 4315, 4572, 4745, 4955, 5155, 5364, 5492, 5601, 5718, 5821, 5933, 6053, 6184, 6324, 6486, 6706, 7021, 7226, 7389, 7592, 7799, 7975, 8230, 8439, 8653, 8890, 9116, 9348, 9568, 9794, 9953, 10000, 10000, 10000}, +{258, 493, 1136, 3954, 4461, 4569, 4725, 5058, 5326, 5506, 5627, 5777, 5911, 6072, 6172, 6260, 6358, 6456, 6568, 6689, 6818, 6955, 7092, 7241, 7462, 7697, 7902, 8091, 8269, 8436, 8688, 8884, 9091, 9321, 9535, 9742, 9906, 9988, 10000, 10000, 10000, 10000}, +{336, 750, 2134, 5144, 5497, 5579, 5690, 5928, 6143, 6281, 6385, 6516, 6635, 6779, 6871, 6951, 7027, 7105, 7190, 7273, 7371, 7474, 7603, 7771, 8013, 8230, 8417, 8598, 8773, 8932, 9167, 9360, 9546, 9742, 9891, 9972, 10000, 10000, 10000, 10000, 10000, 10000}, + +//temp = 40.0 ^C +{0, 116, 250, 498, 759, 1053, 1252, 1500, 1755, 2011, 2245, 2502, 2744, 2983, 3244, 3501, 3768, 4005, 4259, 4510, 4759, 4999, 5245, 5501, 5756, 6000, 6252, 6509, 6755, 6997, 7257, 7504, 7745, 8007, 8253, 8502, 8745, 9005, 9251, 9499, 9752, 10000}, +{13, 142, 289, 825, 1372, 1448, 1569, 1882, 2272, 2559, 2760, 3010, 3330, 3729, 3963, 4156, 4363, 4546, 4750, 4956, 5160, 5355, 5546, 5742, 6013, 6287, 6539, 6799, 7039, 7212, 7495, 7730, 7960, 8215, 8457, 8702, 8943, 9197, 9437, 9676, 9910, 10000}, +{67, 207, 368, 1394, 1729, 1819, 1969, 2392, 2799, 3117, 3374, 3695, 3989, 4303, 4495, 4657, 4824, 4983, 5152, 5323, 5489, 5643, 5806, 6005, 6295, 6579, 6835, 7078, 7256, 7440, 7729, 7951, 8176, 8426, 8662, 8904, 9140, 9389, 9619, 9842, 9995, 10000}, +{94, 249, 424, 1730, 2170, 2292, 2473, 2959, 3442, 3772, 3993, 4258, 4489, 4753, 4919, 5053, 5198, 5329, 5472, 5607, 5744, 5881, 6035, 6236, 6537, 6823, 7058, 7259, 7458, 7649, 7920, 8134, 8356, 8604, 8832, 9072, 9305, 9547, 9766, 9948, 10000, 10000}, +{59, 231, 438, 2099, 2647, 2800, 3030, 3583, 4010, 4279, 4463, 4687, 4891, 5117, 5259, 5374, 5499, 5610, 5731, 5855, 5986, 6125, 6285, 6493, 6804, 7067, 7260, 7465, 7665, 7849, 8113, 8326, 8545, 8782, 9012, 9245, 9475, 9704, 9898, 9995, 10000, 10000}, +{140, 362, 931, 3614, 4173, 4289, 4446, 4805, 5098, 5287, 5414, 5572, 5717, 5881, 5983, 6066, 6164, 6258, 6368, 6482, 6608, 6746, 6903, 7089, 7348, 7582, 7783, 7981, 8169, 8340, 8590, 8797, 9005, 9234, 9454, 9671, 9857, 9974, 10000, 10000, 10000, 10000}, +{201, 567, 1823, 4820, 5204, 5292, 5407, 5664, 5880, 6031, 6138, 6263, 6384, 6528, 6622, 6702, 6792, 6880, 6979, 7077, 7188, 7308, 7439, 7611, 7859, 8083, 8272, 8460, 8634, 8800, 9041, 9239, 9434, 9645, 9827, 9948, 9995, 10000, 10000, 10000, 10000, 10000}, +}; diff --git a/drivers/power/sd77426_fg_mmi/table.h b/drivers/power/sd77426_fg_mmi/table.h new file mode 100644 index 000000000000..d89c59e6bc42 --- /dev/null +++ b/drivers/power/sd77426_fg_mmi/table.h @@ -0,0 +1,69 @@ +/***************************************************************************** +* Copyright(c) O2Micro, 2014. All rights reserved. +* +* O2Micro battery gauge driver +* File: table.h +* +* $Source: /data/code/CVS +* $Revision: 4.00.01 $ +* +* This program is free software and can be edistributed and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This Source Code Reference Design for O2MICRO Battery Gauge access (\u201cReference Design\u201d) +* is sole for the use of PRODUCT INTEGRATION REFERENCE ONLY, and contains confidential +* and privileged information of O2Micro International Limited. O2Micro shall have no +* liability to any PARTY FOR THE RELIABILITY, SERVICEABILITY FOR THE RESULT OF PRODUCT +* INTEGRATION, or results from: (i) any modification or attempted modification of the +* Reference Design by any party, or (ii) the combination, operation or use of the +* Reference Design with non-O2Micro Reference Design. +* +* Battery Manufacture: Lenovo +* Battery Model: BL244 +* Absolute Max Capacity(mAhr): 5158 +* Limited Charge Voltage(mV): 4350 +* Cutoff Discharge Voltage(mV): 3200 +* Equipment: "JY1-8","JY1-4","JY1-4","JY2-8","JY2-8","JY2-8","JY2-5","JY1-1","JY1-1","JY1-8","JY1-8","JY1-8","JY1-8","JY2-5","JY2-5","JY2-5","JY2-5","JY1-8","JY2-8","JY2-8","JY1-8","JY1-2","JY1-2","JY2-6","JY2-6","JY2-6","JY2-7","JY2-7","JY2-7","JY2-7","JY2-7","JY2-7","JY2-7","JY2-7","JY2-7","JY2-7","JY2-7","JY2-7","JY2-7","JY2-7","JY2-7","JY2-7","JY2-7","JY2-7","JY1-3","JY1-3","JY1-6","JY1-6","JY1-6","JY2-8","JY2-5","JY2-5" +* Tester: "SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ","SZ" +* Battery ID: "BL244-1","BL244-1","BL244-1","BL244-1","BL244-1","BL244-1","BL244-1","BL244-1","BL244-1","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-2","BL244-3","BL244-3","BL244-3","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-4","BL244-1","BL244-2","BL244-02" +* Version = V00.13.00 +* Date = 2015.6.23 +* Comment = +* +*****************************************************************************/ + +#ifndef _TABLE_H_ +#define _TABLE_H_ + + +#define OCV_DATA_NUM 65 +#define CHARGE_DATA_NUM 65 + + +#define XAxis 42 +#define YAxis 7 +#define ZAxis 7 + +#define BATTERY_ID_NUM 52 + + +/**************************************************************************** +* Struct section +* add struct #define here if any +***************************************************************************/ +typedef struct tag_one_latitude_data { + int32_t x;// + int32_t y;// +} one_latitude_data_t; + + +/**************************************************************************** +* extern variable declaration section +***************************************************************************/ +extern const char *battery_id[] ; + +extern const char *table_version; + +#endif +