/* * Return the battery Voltage in milivolts * Or < 0 if something fails. */ static int bq27541_battery_voltage(struct bq27541_device_info *di) { int ret; int volt = 0; #ifdef CONFIG_MACH_OPPO if (atomic_read(&di->suspended) == 1) { return di->batt_vol_pre; } if (di->alow_reading) { ret = bq27541_read(BQ27541_REG_VOLT, &volt, 0, di); if (ret) { dev_err(di->dev, "error reading voltage,ret:%d\n", ret); return ret; } } else { return di->batt_vol_pre; } di->batt_vol_pre = volt * 1000; #else ret = bq27541_read(BQ27541_REG_VOLT, &volt, 0, di); if (ret) { dev_err(di->dev, "error reading voltage\n"); return ret; } #endif return volt * 1000; }
static void bq27541_hw_config(struct work_struct *work) { int ret = 0, flags = 0, type = 0, fw_ver = 0; struct bq27541_device_info *di; di = container_of(work, struct bq27541_device_info, hw_config.work); ret = bq27541_chip_config(di); if (ret) { dev_err(di->dev, "Failed to config Bq27541\n"); return; } msm_battery_gauge_register(&bq27541_batt_gauge); bq27541_cntl_cmd(di, BQ27541_SUBCMD_CTNL_STATUS); udelay(66); bq27541_read(BQ27541_REG_CNTL, &flags, 0, di); bq27541_cntl_cmd(di, BQ27541_SUBCMD_DEVCIE_TYPE); udelay(66); bq27541_read(BQ27541_REG_CNTL, &type, 0, di); bq27541_cntl_cmd(di, BQ27541_SUBCMD_FW_VER); udelay(66); bq27541_read(BQ27541_REG_CNTL, &fw_ver, 0, di); dev_info(di->dev, "DEVICE_TYPE is 0x%02X, FIRMWARE_VERSION is 0x%02X\n", type, fw_ver); dev_info(di->dev, "Complete bq27541 configuration 0x%02X\n", flags); }
static int bq27541_battery_rsoc(struct bq27541_device_info *di) { int ret; int rsoc = 0; int flags = 0; int status = 0; u8 buf[2]; #if defined (CONFIG_NO_BATTERY_IC) return 100; #endif if(virtual_battery_enable == 1) return 50/*100*/; ret = bq27541_read(di->client,BQ27500_REG_SOC,buf,2); if (ret<0) { dev_err(di->dev, "error reading relative State-of-Charge\n"); return ret; } rsoc = get_unaligned_le16(buf); DBG("Enter:%s %d--read rsoc = %d\n",__FUNCTION__,__LINE__,rsoc); /* covert the capacity range */ rsoc = min(rsoc, 100); if ((g_pdata != NULL) && g_pdata->capacity_max && g_pdata->capacity_min) { rsoc = max(rsoc, g_pdata->capacity_min); rsoc = ((rsoc - g_pdata->capacity_min) * 100 + (g_pdata->capacity_max - g_pdata->capacity_min) / 2) / (g_pdata->capacity_max - g_pdata->capacity_min); } bq27541_cap = rsoc; #if 0 /*check full flags,if not full, show 99%*/ ret = bq27541_read(di->client,BQ27x00_REG_FLAGS, buf, 2); if (ret < 0) { dev_err(di->dev, "error reading flags\n"); return ret; } flags = get_unaligned_le16(buf); DBG("Enter:%s %d--flags = 0x%x\n",__FUNCTION__,__LINE__,flags); if (flags & BQ27500_FLAG_FC) status = POWER_SUPPLY_STATUS_FULL; if(status != POWER_SUPPLY_STATUS_FULL) rsoc = min(rsoc, 99); #endif DBG("Enter:%s %d--cal rsoc = %d\n",__FUNCTION__,__LINE__,rsoc); #if defined (CONFIG_NO_BATTERY_IC) rsoc = 100; #endif return rsoc; }
static int bq27541_battery_temperature(struct bq27541_device_info *di) { int ret; int temp = 0; u8 buf[2] ={0}; #if defined (CONFIG_NO_BATTERY_IC) return 258; #endif if(virtual_battery_enable == 1) return 125/*258*/; ret = bq27541_read(di->client,BQ27x00_REG_TEMP,buf,2); if (ret<0) { dev_err(di->dev, "error reading temperature\n"); return ret; } temp = get_unaligned_le16(buf); temp = temp - 2731; //K DBG("Enter:%s %d--temp = %d\n",__FUNCTION__,__LINE__,temp); #if defined(CONFIG_CHARGER_LIMITED_BY_TEMP) if((temp >= DIS_CHARGING_TEMP) && (0 == charge_en_flags)){ bq24196_charge_disable(); charge_en_flags = 1; }else if((temp <= EN_CHARGING_TEMP) && (1 == charge_en_flags)){ bq24196_charge_en(); charge_en_flags = 0; } #endif // rk29_pm_power_off(); return temp; }
static int bq27541_health_status(struct bq27541_device_info *di, union power_supply_propval *val) { u8 buf[2] = {0}; int flags = 0; int status; int ret; #if defined (CONFIG_NO_BATTERY_IC) val->intval = POWER_SUPPLY_HEALTH_GOOD; return 0; #endif if(virtual_battery_enable == 1) { val->intval = POWER_SUPPLY_HEALTH_GOOD; return 0; } ret = bq27541_read(di->client,BQ27x00_REG_FLAGS, buf, 2); if (ret < 0) { dev_err(di->dev, "error reading flags\n"); return ret; } flags = get_unaligned_le16(buf); DBG("Enter:%s %d--status = %x\n",__FUNCTION__,__LINE__,flags); if ((flags & BQ27500_FLAG_OTD)||(flags & BQ27500_FLAG_OTC)) status = POWER_SUPPLY_HEALTH_OVERHEAT; else status = POWER_SUPPLY_HEALTH_GOOD; val->intval = status; return 0; }
static int bq27541_average_current(struct bq27541_device_info *di) { int ret; int curr = 0; if (atomic_read(&di->suspended) == 1) { return -di->current_pre; } if (di->alow_reading == true) { ret = bq27541_read(BQ27541_REG_AI, &curr, 0, di); if (ret) { dev_err(di->dev, "error reading current.\n"); return ret; } } else { return -di->current_pre; } // negative current if (curr & 0x8000) curr = -((~(curr - 1)) & 0xFFFF); di->current_pre = curr; return -curr; }
static int bq27541_battery_status(struct bq27541_device_info *di, union power_supply_propval *val) { u8 buf[2] = {0}; int flags = 0; int status = 0; int ret = 0; #if defined (CONFIG_NO_BATTERY_IC) val->intval = POWER_SUPPLY_STATUS_FULL; return 0; #endif if(virtual_battery_enable == 1) { val->intval = POWER_SUPPLY_STATUS_FULL; return 0; } ret = bq27541_read(di->client,BQ27x00_REG_FLAGS, buf, 2); if (ret < 0) { dev_err(di->dev, "error reading flags\n"); return ret; } flags = get_unaligned_le16(buf); DBG("Enter:%s %d--flags = 0x%x\n",__FUNCTION__,__LINE__,flags); if (flags & BQ27500_FLAG_FC) status = POWER_SUPPLY_STATUS_FULL; #if 0 else if (flags & BQ27500_FLAG_DSC) status = POWER_SUPPLY_STATUS_DISCHARGING; else status = POWER_SUPPLY_STATUS_CHARGING; #else else if ((g_pdata != NULL) && g_pdata->get_charging_stat)
static ssize_t bq27541_read_subcmd(struct device *dev, struct device_attribute *attr, char *buf) { int ret; int temp = 0; struct platform_device *client; struct bq27541_device_info *di; client = to_platform_device(dev); di = platform_get_drvdata(client); if (subcmd == BQ27541_SUBCMD_DEVCIE_TYPE || subcmd == BQ27541_SUBCMD_FW_VER || subcmd == BQ27541_SUBCMD_HW_VER || subcmd == BQ27541_SUBCMD_CHEM_ID) { bq27541_cntl_cmd(di, subcmd); /* Retrieve Chip status */ udelay(66); ret = bq27541_read(BQ27541_REG_CNTL, &temp, 0, di); if (ret) ret = snprintf(buf, PAGE_SIZE, "Read Error!\n"); else ret = snprintf(buf, PAGE_SIZE, "0x%02x\n", temp); } else ret = snprintf(buf, PAGE_SIZE, "Register Error!\n"); return ret; }
/* * Return the battery average current * Note that current can be negative signed as well * Or 0 if something fails. */ static int bq27541_battery_current(struct bq27541_device_info *di) { int ret; int curr = 0; u8 buf[2] = {0}; #if defined (CONFIG_NO_BATTERY_IC) return 22000; #endif if(virtual_battery_enable == 1) return 11000/*22000*/; ret = bq27541_read(di->client,BQ27x00_REG_AI,buf,2); if (ret<0) { dev_err(di->dev, "error reading current\n"); return 0; } curr = get_unaligned_le16(buf); DBG("curr = %x \n",curr); if(curr>0x8000){ curr = 0xFFFF^(curr-1); } curr = curr * 1000; DBG("Enter:%s %d--curr = %d\n",__FUNCTION__,__LINE__,curr); return curr; }
static void bq27541_set(void) { struct bq27541_device_info *di; int i = 0; u8 buf[2]; di = bq27541_di; printk("enter 0x41\n"); buf[0] = 0x41; buf[1] = 0x00; bq27541_write(di->client,0x00,buf,2); msleep(1500); printk("enter 0x21\n"); buf[0] = 0x21; buf[1] = 0x00; bq27541_write(di->client,0x00,buf,2); buf[0] = 0; buf[1] = 0; bq27541_read(di->client,0x00,buf,2); while((buf[0] & 0x04)&&(i<5)) { printk("enter more 0x21 times i = %d\n",i); mdelay(1000); buf[0] = 0x21; buf[1] = 0x00; bq27541_write(di->client,0x00,buf,2); buf[0] = 0; buf[1] = 0; bq27541_read(di->client,0x00,buf,2); i++; } if(i>5) printk("write 0x21 error\n"); else printk("bq27541 write 0x21 success\n"); }
/* * Return the battery temperature in tenths of degree Celsius * Or < 0 if something fails. */ static int bq27541_battery_temperature(struct bq27541_device_info *di) { int ret; int temp = 0; #ifdef CONFIG_MACH_OPPO static int count = 0; if (atomic_read(&di->suspended) == 1) { return di->temp_pre + ZERO_DEGREE_CELSIUS_IN_TENTH_KELVIN; } if (di->alow_reading == true) { ret = bq27541_read(BQ27541_REG_TEMP, &temp, 0, di); if (ret) { count++; dev_err(di->dev, "error reading temperature\n"); if (count > 1) { count = 0; di->temp_pre = -400 - ZERO_DEGREE_CELSIUS_IN_TENTH_KELVIN; return -400; } else { return di->temp_pre + ZERO_DEGREE_CELSIUS_IN_TENTH_KELVIN; } } count = 0; } else { return di->temp_pre + ZERO_DEGREE_CELSIUS_IN_TENTH_KELVIN; } di->temp_pre = temp; #else ret = bq27541_read(BQ27541_REG_TEMP, &temp, 0, di); if (ret) { dev_err(di->dev, "error reading temperature\n"); return ret; } #endif return temp + ZERO_DEGREE_CELSIUS_IN_TENTH_KELVIN; }
static void bq27541_hw_config(struct work_struct *work) { int ret = 0, flags = 0, type = 0, fw_ver = 0; struct bq27541_device_info *di; di = container_of(work, struct bq27541_device_info, hw_config.work); ret = bq27541_chip_config(di); if (ret) { dev_err(di->dev, "Failed to config Bq27541\n"); #ifdef CONFIG_MACH_OPPO di->retry_count--; if (di->retry_count > 0) { schedule_delayed_work(&di->hw_config, HZ); } #endif return; } #ifdef CONFIG_MACH_OPPO qpnp_battery_gauge_register(&bq27541_batt_gauge); #else msm_battery_gauge_register(&bq27541_batt_gauge); #endif bq27541_cntl_cmd(di, BQ27541_SUBCMD_CTNL_STATUS); udelay(66); bq27541_read(BQ27541_REG_CNTL, &flags, 0, di); bq27541_cntl_cmd(di, BQ27541_SUBCMD_DEVCIE_TYPE); udelay(66); bq27541_read(BQ27541_REG_CNTL, &type, 0, di); bq27541_cntl_cmd(di, BQ27541_SUBCMD_FW_VER); udelay(66); bq27541_read(BQ27541_REG_CNTL, &fw_ver, 0, di); #ifdef CONFIG_MACH_OPPO di->is_authenticated = bq27541_authenticate(di->client); di->battery_type = bq27541_batt_type_detect(di->client); #endif dev_info(di->dev, "DEVICE_TYPE is 0x%02X, FIRMWARE_VERSION is 0x%02X\n", type, fw_ver); dev_info(di->dev, "Complete bq27541 configuration 0x%02X\n", flags); }
static void bq27541_coulomb_counter_work(struct work_struct *work) { int value = 0, temp = 0, index = 0, ret = 0; struct bq27541_device_info *di; unsigned long flags; int count = 0; di = container_of(work, struct bq27541_device_info, counter); /* retrieve 30 values from FIFO of coulomb data logging buffer * and average over time */ do { ret = bq27541_read(BQ27541_REG_LOGBUF, &temp, 0, di); if (ret < 0) break; if (temp != 0x7FFF) { ++count; value += temp; } /* delay 66uS, waiting time between continuous reading * results */ udelay(66); ret = bq27541_read(BQ27541_REG_LOGIDX, &index, 0, di); if (ret < 0) break; udelay(66); } while (index != 0 || temp != 0x7FFF); if (ret < 0) { dev_err(di->dev, "Error reading datalog register\n"); return; } if (count) { spin_lock_irqsave(&lock, flags); coulomb_counter = value/count; spin_unlock_irqrestore(&lock, flags); } }
/* * Return the battery temperature in tenths of degree Celsius * Or < 0 if something fails. */ static int bq27541_battery_temperature(struct bq27541_device_info *di) { int ret; int temp = 0; ret = bq27541_read(BQ27541_REG_TEMP, &temp, 0, di); if (ret) { dev_err(di->dev, "error reading temperature\n"); return ret; } return temp + ZERO_DEGREE_CELSIUS_IN_TENTH_KELVIN; }
/* * Return the battery Voltage in milivolts * Or < 0 if something fails. */ static int bq27541_battery_voltage(struct bq27541_device_info *di) { int ret; int volt = 0; ret = bq27541_read(BQ27541_REG_VOLT, &volt, 0, di); if (ret) { dev_err(di->dev, "error reading voltage\n"); return ret; } return volt * 1000; }
static int bq27541_remaining_capacity(struct bq27541_device_info *di) { int ret; int cap = 0; if(di->alow_reading == true) { ret = bq27541_read(BQ27541_REG_RM, &cap, 0, di); if (ret) { dev_err(di->dev, "error reading capacity.\n"); return ret; } } return cap; }
static int bq27541_battery_voltage(struct bq27541_device_info *di) { int ret; u8 buf[2] = {0}; int volt = 0; #if defined (CONFIG_NO_BATTERY_IC) return 4000000; #endif if(virtual_battery_enable == 1) return 2000000/*4000000*/; ret = bq27541_read(di->client,BQ27x00_REG_VOLT,buf,2); if (ret<0) { dev_err(di->dev, "error reading voltage\n"); // gpio_set_value(POWER_ON_PIN, GPIO_LOW); return ret; } volt = get_unaligned_le16(buf); //bp27510 can only measure one li-lion bat if(di->bat_num == 2){ volt = volt * 1000 * 2; }else{ volt = volt * 1000; } if ((volt <= 3400000) && (volt > 0) && gpio_get_value(di->dc_check_pin)){ printk("vol smaller then 3.4V, report to android!"); di->power_down = 1; }else{ di->power_down = 0; } DBG("Enter:%s %d--volt = %d\n",__FUNCTION__,__LINE__,volt); return volt; }
/* * Read a time register. * Return < 0 if something fails. */ static int bq27541_battery_time(struct bq27541_device_info *di, int reg, union power_supply_propval *val) { u8 buf[2] = {0}; int tval = 0; int ret; ret = bq27541_read(di->client,reg,buf,2); if (ret<0) { dev_err(di->dev, "error reading register %02x\n", reg); return ret; } tval = get_unaligned_le16(buf); DBG("Enter:%s %d--tval=%d\n",__FUNCTION__,__LINE__,tval); if (tval == 65535) return -ENODATA; val->intval = tval * 60; DBG("Enter:%s %d val->intval = %d\n",__FUNCTION__,__LINE__,val->intval); return 0; }
static int bq27541_battery_soc(struct bq27541_device_info *di, bool raw) { int ret; int soc = 0; if (atomic_read(&di->suspended) == 1) { return di->soc_pre; } if (di->alow_reading == true) { ret = bq27541_read(BQ27541_REG_SOC, &soc, 0, di); if (ret) { dev_err(di->dev, "error reading soc.ret:%d\n",ret); goto read_soc_err; } } else { if(di->soc_pre) return di->soc_pre; else return 0; } if (raw == true) { if(soc > 90) { soc += 2; } if(soc <= di->soc_pre) { di->soc_pre = soc; } } soc = bq27541_soc_calibrate(di,soc); return soc; read_soc_err: if (di->soc_pre) return di->soc_pre; else return 0; }
static ssize_t bq27541_read_stdcmd(struct device *dev, struct device_attribute *attr, char *buf) { int ret; int temp = 0; struct platform_device *client; struct bq27541_device_info *di; client = to_platform_device(dev); di = platform_get_drvdata(client); if (reg <= BQ27541_REG_ICR && reg > 0x00) { ret = bq27541_read(reg, &temp, 0, di); if (ret) ret = snprintf(buf, PAGE_SIZE, "Read Error!\n"); else ret = snprintf(buf, PAGE_SIZE, "0x%02x\n", temp); } else ret = snprintf(buf, PAGE_SIZE, "Register Error!\n"); return ret; }
static int bq27541_battery_temperature(struct bq27541_device_info *di) { int ret; int temp = 0; u8 buf[2] ={0}; #if defined (CONFIG_NO_BATTERY_IC) return 258; #endif if(virtual_battery_enable == 1) return 125/*258*/; ret = bq27541_read(di->client,BQ27x00_REG_TEMP,buf,2); if (ret<0) { dev_err(di->dev, "error reading temperature\n"); return ret; } temp = get_unaligned_le16(buf); temp = temp - 2731; //K DBG("Enter:%s %d--temp = %d\n",__FUNCTION__,__LINE__,temp); // rk29_pm_power_off(); return temp; }
static int bq27541_chip_config(struct bq27541_device_info *di) { int flags = 0, ret = 0; bq27541_cntl_cmd(di, BQ27541_SUBCMD_CTNL_STATUS); udelay(66); ret = bq27541_read(BQ27541_REG_CNTL, &flags, 0, di); if (ret < 0) { dev_err(di->dev, "error reading register %02x ret = %d\n", BQ27541_REG_CNTL, ret); return ret; } udelay(66); bq27541_cntl_cmd(di, BQ27541_SUBCMD_ENABLE_IT); udelay(66); if (!(flags & BQ27541_CS_DLOGEN)) { bq27541_cntl_cmd(di, BQ27541_SUBCMD_ENABLE_DLOG); udelay(66); } return 0; }
/* * Return the battery Relative State-of-Charge * Or < 0 if something fails. */ static int bq27541_battery_rsoc(struct bq27541_device_info *di) { int ret; int rsoc = 0; int flags = 0; int status = 0; #if 0 int nvcap = 0,facap = 0,remcap=0,fccap=0,full=0,cnt=0; int art = 0, artte = 0, ai = 0, tte = 0, ttf = 0, si = 0; int stte = 0, mli = 0, mltte = 0, ae = 0, ap = 0, ttecp = 0, cc = 0; #endif u8 buf[2]; #if defined (CONFIG_NO_BATTERY_IC) return 100; #endif if(virtual_battery_enable == 1) return 50/*100*/; ret = bq27541_read(di->client,BQ27500_REG_SOC,buf,2); if (ret<0) { dev_err(di->dev, "error reading relative State-of-Charge\n"); return ret; } rsoc = get_unaligned_le16(buf); DBG("Enter:%s %d--read rsoc = %d\n",__FUNCTION__,__LINE__,rsoc); /* covert the capacity range */ rsoc = min(rsoc, 100); if ((g_pdata != NULL) && g_pdata->capacity_max && g_pdata->capacity_min) { rsoc = max(rsoc, g_pdata->capacity_min); rsoc = ((rsoc - g_pdata->capacity_min) * 100 + (g_pdata->capacity_max - g_pdata->capacity_min) / 2) / (g_pdata->capacity_max - g_pdata->capacity_min); } bq27541_cap = rsoc; /*check full flags,if not full, show 99%*/ ret = bq27541_read(di->client,BQ27x00_REG_FLAGS, buf, 2); if (ret < 0) { dev_err(di->dev, "error reading flags\n"); return ret; } flags = get_unaligned_le16(buf); DBG("Enter:%s %d--flags = 0x%x\n",__FUNCTION__,__LINE__,flags); if ((bq27541_cap > 99) && (flags & BQ27500_FLAG_FC)) status = POWER_SUPPLY_STATUS_FULL; if(status != POWER_SUPPLY_STATUS_FULL) rsoc = min(rsoc, 99); DBG("Enter:%s %d--cal rsoc = %d\n",__FUNCTION__,__LINE__,rsoc); #if defined (CONFIG_NO_BATTERY_IC) rsoc = 100; #endif #if 0 //other register information, for debug use ret = bq27541_read(di->client,0x0c,buf,2); //NominalAvailableCapacity nvcap = get_unaligned_le16(buf); DBG("\nEnter:%s %d--nvcap = %d\n",__FUNCTION__,__LINE__,nvcap); ret = bq27541_read(di->client,0x0e,buf,2); //FullAvailableCapacity facap = get_unaligned_le16(buf); DBG("Enter:%s %d--facap = %d\n",__FUNCTION__,__LINE__,facap); ret = bq27541_read(di->client,0x10,buf,2); //RemainingCapacity remcap = get_unaligned_le16(buf); DBG("Enter:%s %d--remcap = %d\n",__FUNCTION__,__LINE__,remcap); ret = bq27541_read(di->client,0x12,buf,2); //FullChargeCapacity fccap = get_unaligned_le16(buf); DBG("Enter:%s %d--fccap = %d\n",__FUNCTION__,__LINE__,fccap); ret = bq27541_read(di->client,0x3c,buf,2); //DesignCapacity full = get_unaligned_le16(buf); DBG("Enter:%s %d--DesignCapacity = %d\n",__FUNCTION__,__LINE__,full); buf[0] = 0x00; //CONTROL_STATUS buf[1] = 0x00; bq27541_write(di->client,0x00,buf,2); ret = bq27541_read(di->client,0x00,buf,2); cnt = get_unaligned_le16(buf); DBG("Enter:%s %d--Control status = %x\n",__FUNCTION__,__LINE__,cnt); ret = bq27541_read(di->client,0x02,buf,2); //AtRate art = get_unaligned_le16(buf); DBG("Enter:%s %d--AtRate = %d\n",__FUNCTION__,__LINE__,art); ret = bq27541_read(di->client,0x04,buf,2); //AtRateTimeToEmpty artte = get_unaligned_le16(buf); DBG("Enter:%s %d--AtRateTimeToEmpty = %d\n",__FUNCTION__,__LINE__,artte); ret = bq27541_read(di->client,0x14,buf,2); //AverageCurrent ai = get_unaligned_le16(buf); DBG("Enter:%s %d--AverageCurrent = %d\n",__FUNCTION__,__LINE__,ai); ret = bq27541_read(di->client,0x16,buf,2); //TimeToEmpty tte = get_unaligned_le16(buf); DBG("Enter:%s %d--TimeToEmpty = %d\n",__FUNCTION__,__LINE__,tte); ret = bq27541_read(di->client,0x18,buf,2); //TimeToFull ttf = get_unaligned_le16(buf); DBG("Enter:%s %d--TimeToFull = %d\n",__FUNCTION__,__LINE__,ttf); ret = bq27541_read(di->client,0x1a,buf,2); //StandbyCurrent si = get_unaligned_le16(buf); DBG("Enter:%s %d--StandbyCurrent = %d\n",__FUNCTION__,__LINE__,si); ret = bq27541_read(di->client,0x1c,buf,2); //StandbyTimeToEmpty stte = get_unaligned_le16(buf); DBG("Enter:%s %d--StandbyTimeToEmpty = %d\n",__FUNCTION__,__LINE__,stte); ret = bq27541_read(di->client,0x1e,buf,2); //MaxLoadCurrent mli = get_unaligned_le16(buf); DBG("Enter:%s %d--MaxLoadCurrent = %d\n",__FUNCTION__,__LINE__,mli); ret = bq27541_read(di->client,0x20,buf,2); //MaxLoadTimeToEmpty mltte = get_unaligned_le16(buf); DBG("Enter:%s %d--MaxLoadTimeToEmpty = %d\n",__FUNCTION__,__LINE__,mltte); ret = bq27541_read(di->client,0x22,buf,2); //AvailableEnergy ae = get_unaligned_le16(buf); DBG("Enter:%s %d--AvailableEnergy = %d\n",__FUNCTION__,__LINE__,ae); ret = bq27541_read(di->client,0x24,buf,2); //AveragePower ap = get_unaligned_le16(buf); DBG("Enter:%s %d--AveragePower = %d\n",__FUNCTION__,__LINE__,ap); ret = bq27541_read(di->client,0x26,buf,2); //TTEatConstantPower ttecp = get_unaligned_le16(buf); DBG("Enter:%s %d--TTEatConstantPower = %d\n",__FUNCTION__,__LINE__,ttecp); ret = bq27541_read(di->client,0x2a,buf,2); //CycleCount cc = get_unaligned_le16(buf); DBG("Enter:%s %d--CycleCount = %d\n",__FUNCTION__,__LINE__,cc); #endif return rsoc; }
static int bq27541_battery_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct bq27541_device_info *di; int retval = 0; struct bq27541_platform_data *pdata; int val =0; char buf[2]; int volt; DBG("********** bq27541_battery_probe************** "); pdata = client->dev.platform_data; g_pdata = pdata; di = kzalloc(sizeof(*di), GFP_KERNEL); if (!di) { dev_err(&client->dev, "failed to allocate device info data\n"); retval = -ENOMEM; goto batt_failed_2; } i2c_set_clientdata(client, di); di->dev = &client->dev; di->bat.name = "battery"; di->client = client; /* 1 seconds between monotor runs interval */ di->interval = msecs_to_jiffies(4 * 1000); di->bat_num = pdata->bat_num; di->dc_check_pin = pdata->dc_check_pin; di->bat_check_pin = pdata->bat_check_pin; if (pdata->init_dc_check_pin) pdata->init_dc_check_pin( ); bq27541_powersupply_init(di); mutex_init(&g_bq27541_mutex); retval = bq27541_read(di->client,BQ27x00_REG_FLAGS, buf, 2); if (retval < 0) { printk("can't find bq27541\n"); goto batt_failed_2; }else{ rk30_bat_unregister(); bq27541_init = 1; } retval = power_supply_register(&client->dev, &di->bat); if (retval) { dev_err(&client->dev, "failed to register battery\n"); goto batt_failed_4; } bq27541_di = di; #if 0 retval = power_supply_register(&client->dev, &di->ac); if (retval) { dev_err(&client->dev, "failed to register ac\n"); goto batt_failed_4; } #endif INIT_DELAYED_WORK(&di->work, bq27541_battery_work); schedule_delayed_work(&di->work, di->interval); dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION); battery_capacity_check(di); #if defined(CONFIG_CHARGER_LIMITED_BY_TEMP) bq27541_sysfs_init(); #endif return 0; batt_failed_4: kfree(di); batt_failed_2: err_batirq_failed: gpio_free(pdata->bat_check_pin); return retval; }
static int bq27541_battery_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct bq27541_device_info *di; int retval = 0; struct bq27541_platform_data *pdata; int val =0; char buf[2]; int volt; DBG("********** bq27541_battery_probe************** "); pdata = client->dev.platform_data; di = kzalloc(sizeof(*di), GFP_KERNEL); if (!di) { dev_err(&client->dev, "failed to allocate device info data\n"); retval = -ENOMEM; goto batt_failed_2; } i2c_set_clientdata(client, di); di->dev = &client->dev; di->bat.name = "bq27541-battery"; di->client = client; /* 4 seconds between monotor runs interval */ di->interval = msecs_to_jiffies(4 * 1000); di->bat_num = pdata->bat_num; di->dc_check_pin = pdata->dc_check_pin; di->bat_check_pin = pdata->bat_check_pin; if (pdata->init_dc_check_pin) pdata->init_dc_check_pin( ); bq27541_powersupply_init(di); retval = power_supply_register(&client->dev, &di->bat); if (retval) { dev_err(&client->dev, "failed to register battery\n"); goto batt_failed_4; } bq27541_di = di; retval = power_supply_register(&client->dev, &di->ac); if (retval) { dev_err(&client->dev, "failed to register ac\n"); goto batt_failed_4; } INIT_DELAYED_WORK(&di->work, bq27541_battery_work); schedule_delayed_work(&di->work, di->interval); dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION); #if !defined (CONFIG_NO_BATTERY_IC) // no battery , no power up gpio_request(POWER_ON_PIN, "poweronpin"); gpio_request(pdata->bat_check_pin, NULL); gpio_direction_input(pdata->bat_check_pin); gpio_request(pdata->chgok_check_pin, "CHG_OK"); gpio_direction_input(pdata->chgok_check_pin); val = gpio_get_value(pdata->bat_check_pin); if (val == 1){ printk("\n\n!!! bat_low high !!!\n\n"); val = bq27541_read(di->client,BQ27x00_REG_VOLT,buf,2); if (val < 0){ printk("\n\n!!! bq i2c err! no battery, power down\n!!!\n\n"); gpio_direction_output(POWER_ON_PIN, GPIO_LOW); while(1){ gpio_set_value(POWER_ON_PIN, GPIO_LOW); mdelay(100); } } }else{ printk("\n\n!!! bat_low low !!!\n\n"); val = gpio_get_value(pdata->chgok_check_pin); if (val == 1){ printk("no battery, power down \n"); gpio_direction_output(POWER_ON_PIN, GPIO_LOW); while(1){ gpio_set_value(POWER_ON_PIN, GPIO_LOW); mdelay(100); } }else{ mdelay(1000); val = gpio_get_value(pdata->chgok_check_pin); if (val == 1){ printk("no battery, power down \n"); gpio_direction_output(POWER_ON_PIN, GPIO_LOW); while(1){ gpio_set_value(POWER_ON_PIN, GPIO_LOW); mdelay(100); } } } } // gpio_free(POWER_ON_PIN); // gpio_free(pdata->bat_check_pin); gpio_free(pdata->chgok_check_pin); //smaller 3.4V , no power up if (gpio_get_value(di->dc_check_pin) && (gpio_get_value(pdata->bat_check_pin) == 0)){ printk("no AC && battery low ,so power down \n"); gpio_direction_output(POWER_ON_PIN, GPIO_LOW); while(1){ printk("no AC && battery low ,so power down \n"); gpio_set_value(POWER_ON_PIN, GPIO_LOW); mdelay(100); } } // battery low irq di->wake_irq = gpio_to_irq(pdata->bat_check_pin); retval = request_irq(di->wake_irq, bq27541_bat_wakeup, IRQF_TRIGGER_FALLING, "bq27541_battery", di); if (retval) { printk("failed to request bat det irq\n"); goto err_batirq_failed; } INIT_DELAYED_WORK(&di->wakeup_work, bq27541_battery_wake_work); enable_irq_wake(di->wake_irq); #endif return 0; batt_failed_4: kfree(di); batt_failed_2: err_batirq_failed: gpio_free(pdata->bat_check_pin); return retval; }
/* * Return the battery Relative State-of-Charge * Or < 0 if something fails. */ static int bq27541_battery_rsoc(struct bq27541_device_info *di) { int ret; int rsoc = 0; #if 0 int nvcap = 0,facap = 0,remcap=0,fccap=0,full=0,cnt=0; int art = 0, artte = 0, ai = 0, tte = 0, ttf = 0, si = 0; int stte = 0, mli = 0, mltte = 0, ae = 0, ap = 0, ttecp = 0, cc = 0; #endif u8 buf[2]; #if defined (CONFIG_NO_BATTERY_IC) return 100; #endif if(virtual_battery_enable == 1) return 50/*100*/; ret = bq27541_read(di->client,BQ27500_REG_SOC,buf,2); if (ret<0) { dev_err(di->dev, "error reading relative State-of-Charge\n"); return ret; } rsoc = get_unaligned_le16(buf); DBG("Enter:%s %d--rsoc = %d\n",__FUNCTION__,__LINE__,rsoc); #if defined (CONFIG_NO_BATTERY_IC) rsoc = 100; #endif #if 0 //other register information, for debug use ret = bq27541_read(di->client,0x0c,buf,2); //NominalAvailableCapacity nvcap = get_unaligned_le16(buf); DBG("\nEnter:%s %d--nvcap = %d\n",__FUNCTION__,__LINE__,nvcap); ret = bq27541_read(di->client,0x0e,buf,2); //FullAvailableCapacity facap = get_unaligned_le16(buf); DBG("Enter:%s %d--facap = %d\n",__FUNCTION__,__LINE__,facap); ret = bq27541_read(di->client,0x10,buf,2); //RemainingCapacity remcap = get_unaligned_le16(buf); DBG("Enter:%s %d--remcap = %d\n",__FUNCTION__,__LINE__,remcap); ret = bq27541_read(di->client,0x12,buf,2); //FullChargeCapacity fccap = get_unaligned_le16(buf); DBG("Enter:%s %d--fccap = %d\n",__FUNCTION__,__LINE__,fccap); ret = bq27541_read(di->client,0x3c,buf,2); //DesignCapacity full = get_unaligned_le16(buf); DBG("Enter:%s %d--DesignCapacity = %d\n",__FUNCTION__,__LINE__,full); buf[0] = 0x00; //CONTROL_STATUS buf[1] = 0x00; bq27541_write(di->client,0x00,buf,2); ret = bq27541_read(di->client,0x00,buf,2); cnt = get_unaligned_le16(buf); DBG("Enter:%s %d--Control status = %x\n",__FUNCTION__,__LINE__,cnt); ret = bq27541_read(di->client,0x02,buf,2); //AtRate art = get_unaligned_le16(buf); DBG("Enter:%s %d--AtRate = %d\n",__FUNCTION__,__LINE__,art); ret = bq27541_read(di->client,0x04,buf,2); //AtRateTimeToEmpty artte = get_unaligned_le16(buf); DBG("Enter:%s %d--AtRateTimeToEmpty = %d\n",__FUNCTION__,__LINE__,artte); ret = bq27541_read(di->client,0x14,buf,2); //AverageCurrent ai = get_unaligned_le16(buf); DBG("Enter:%s %d--AverageCurrent = %d\n",__FUNCTION__,__LINE__,ai); ret = bq27541_read(di->client,0x16,buf,2); //TimeToEmpty tte = get_unaligned_le16(buf); DBG("Enter:%s %d--TimeToEmpty = %d\n",__FUNCTION__,__LINE__,tte); ret = bq27541_read(di->client,0x18,buf,2); //TimeToFull ttf = get_unaligned_le16(buf); DBG("Enter:%s %d--TimeToFull = %d\n",__FUNCTION__,__LINE__,ttf); ret = bq27541_read(di->client,0x1a,buf,2); //StandbyCurrent si = get_unaligned_le16(buf); DBG("Enter:%s %d--StandbyCurrent = %d\n",__FUNCTION__,__LINE__,si); ret = bq27541_read(di->client,0x1c,buf,2); //StandbyTimeToEmpty stte = get_unaligned_le16(buf); DBG("Enter:%s %d--StandbyTimeToEmpty = %d\n",__FUNCTION__,__LINE__,stte); ret = bq27541_read(di->client,0x1e,buf,2); //MaxLoadCurrent mli = get_unaligned_le16(buf); DBG("Enter:%s %d--MaxLoadCurrent = %d\n",__FUNCTION__,__LINE__,mli); ret = bq27541_read(di->client,0x20,buf,2); //MaxLoadTimeToEmpty mltte = get_unaligned_le16(buf); DBG("Enter:%s %d--MaxLoadTimeToEmpty = %d\n",__FUNCTION__,__LINE__,mltte); ret = bq27541_read(di->client,0x22,buf,2); //AvailableEnergy ae = get_unaligned_le16(buf); DBG("Enter:%s %d--AvailableEnergy = %d\n",__FUNCTION__,__LINE__,ae); ret = bq27541_read(di->client,0x24,buf,2); //AveragePower ap = get_unaligned_le16(buf); DBG("Enter:%s %d--AveragePower = %d\n",__FUNCTION__,__LINE__,ap); ret = bq27541_read(di->client,0x26,buf,2); //TTEatConstantPower ttecp = get_unaligned_le16(buf); DBG("Enter:%s %d--TTEatConstantPower = %d\n",__FUNCTION__,__LINE__,ttecp); ret = bq27541_read(di->client,0x2a,buf,2); //CycleCount cc = get_unaligned_le16(buf); DBG("Enter:%s %d--CycleCount = %d\n",__FUNCTION__,__LINE__,cc); #endif return rsoc; }
static int bq27541_battery_status(struct bq27541_device_info *di, union power_supply_propval *val) { u8 buf[2] = {0}; int flags = 0; int status = 0; int ret = 0; #if defined (CONFIG_NO_BATTERY_IC) val->intval = POWER_SUPPLY_STATUS_FULL; return 0; #endif if(virtual_battery_enable == 1) { val->intval = POWER_SUPPLY_STATUS_FULL; return 0; } ret = bq27541_read(di->client,BQ27x00_REG_FLAGS, buf, 2); if (ret < 0) { dev_err(di->dev, "error reading flags\n"); return ret; } flags = get_unaligned_le16(buf); DBG("Enter:%s %d--flags = 0x%x\n",__FUNCTION__,__LINE__,flags); #if 0 if (flags & BQ27500_FLAG_FC) status = POWER_SUPPLY_STATUS_FULL; else if (flags & BQ27500_FLAG_DSC) status = POWER_SUPPLY_STATUS_DISCHARGING; else status = POWER_SUPPLY_STATUS_CHARGING; #else if ((g_pdata != NULL) && g_pdata->get_charging_stat) { #ifdef CONFIG_BATTERY_BQ24196_OTG_MODE if(!(*g_pdata->get_charging_stat)() || (bq24196_mode == 1)) #else if(!(*g_pdata->get_charging_stat)()) #endif status = POWER_SUPPLY_STATUS_DISCHARGING; else if(1 == (*g_pdata->get_charging_stat)()){ if ((bq27541_cap > 99) && (flags & BQ27500_FLAG_FC)) status = POWER_SUPPLY_STATUS_FULL; else status = POWER_SUPPLY_STATUS_CHARGING; } } #endif #if defined(CONFIG_CHARGER_LIMITED_BY_TEMP) if((1 == check_charge_ok) && (!strstr(saved_command_line,"charger"))){ if(1 == charge_en_flags) { if(status != POWER_SUPPLY_STATUS_DISCHARGING){ status = POWER_SUPPLY_STATUS_DISCHARGING; stop_charging = 1; } }else{ stop_charging = 0; } if(1 == update_temp_ok){ if(1 == charge_en_flags) status = POWER_SUPPLY_STATUS_NOT_CHARGING; else update_temp_ok = 0; } } #endif val->intval = status; DBG("Enter:%s %d--status = %x\n",__FUNCTION__,__LINE__,status); return 0; }