static void bq27520_hw_config(struct work_struct *work) { int ret = 0, flags = 0, type = 0, fw_ver = 0, status = 0; struct bq27520_device_info *di; di = container_of(work, struct bq27520_device_info, hw_config.work); pr_debug(KERN_INFO "Enter bq27520_hw_config\n"); ret = bq27520_chip_config(di); if (ret) { dev_err(di->dev, "Failed to config Bq27520 ret = %d\n", ret); return; } /* bq27520 is ready for access, update current_battery_status by reading * from hardware */ if_notify_msm_charger(&status); update_current_battery_status(status); msm_battery_gauge_register(&bq27520_batt_gauge); msm_charger_notify_event(NULL, CHG_BATT_STATUS_CHANGE); enable_irq(di->irq); /* poll battery status every 3 seconds, if charging status changes, * notify msm_charger */ schedule_delayed_work(¤t_battery_status.poller, BQ27520_POLLING_STATUS); if (di->pdata->enable_dlog) { schedule_work(&di->counter); init_timer(&timer); timer.function = &bq27520_every_30secs; timer.data = (unsigned long)di; timer.expires = jiffies + BQ27520_COULOMB_POLL; add_timer(&timer); } bq27520_cntl_cmd(di, BQ27520_SUBCMD_CTNL_STATUS); udelay(66); bq27520_read(BQ27520_REG_CNTL, &flags, 0, di); bq27520_cntl_cmd(di, BQ27520_SUBCMD_DEVCIE_TYPE); udelay(66); bq27520_read(BQ27520_REG_CNTL, &type, 0, di); bq27520_cntl_cmd(di, BQ27520_SUBCMD_FW_VER); udelay(66); bq27520_read(BQ27520_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 bq27520 configuration 0x%02X\n", flags); }
static ssize_t bq27520_read_subcmd(struct device *dev, struct device_attribute *attr, char *buf) { int ret, temp = 0; struct platform_device *client; struct bq27520_device_info *di; client = to_platform_device(dev); di = platform_get_drvdata(client); if (subcmd == BQ27520_SUBCMD_DEVCIE_TYPE || subcmd == BQ27520_SUBCMD_FW_VER || subcmd == BQ27520_SUBCMD_HW_VER || subcmd == BQ27520_SUBCMD_CHEM_ID) { bq27520_cntl_cmd(di, subcmd);/* Retrieve Chip status */ udelay(66); ret = bq27520_read(BQ27520_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; }
/* only if battery charging satus changes then notify msm_charger. otherwise * only refresh current_batter_status */ static int if_notify_msm_charger(int *data) { int ret = 0, flags = 0, status = 0; unsigned long flag; ret = bq27520_read(BQ27520_REG_FLAGS, &flags, 0, bq27520_di); if (ret < 0) { dev_err(bq27520_di->dev, "error %d reading register %02x\n", ret, BQ27520_REG_FLAGS); status = POWER_SUPPLY_STATUS_UNKNOWN; } else { if (flags & BQ27520_FLAG_FC) status = POWER_SUPPLY_STATUS_FULL; else if (flags & BQ27520_FLAG_DSC) status = POWER_SUPPLY_STATUS_DISCHARGING; else status = POWER_SUPPLY_STATUS_CHARGING; } *data = status; spin_lock_irqsave(¤t_battery_status.lock, flag); ret = (status != current_battery_status.status[GET_BATTERY_STATUS]); spin_unlock_irqrestore(¤t_battery_status.lock, flag); return ret; }
int bq27520_send_subcmd(struct i2c_client *client, int *rt_value, u16 sub_cmd) { int ret, tmp_buf = 0; int retry_count = RETRY_COUNT; do { ret = bq27520_cntl_cmd(client, sub_cmd); if (ret) { dev_err(&client->dev, "Send subcommand 0x%04X error.\n", sub_cmd); retry_count--; msleep(I2C_RETRY_DELAY); } } while (ret && retry_count > 0); if (!rt_value) return ret; retry_count = RETRY_COUNT; udelay(800); do { /* need read data to rt_value */ ret = bq27520_read(client, BQ27520_REG_CNTL, &tmp_buf, 0); if (ret) { dev_err(&client->dev, "Error!! %s subcommand %04X\n", __func__, sub_cmd); retry_count--; msleep(I2C_RETRY_DELAY); } } while (ret && retry_count > 0); *rt_value = tmp_buf; return ret; }
/* * Return the battery Voltage in milivolts * Or < 0 if something fails. */ static int bq27520_battery_voltage(struct bq27520_device_info *di) { int ret, volt = 0; ret = bq27520_read(BQ27520_REG_VOLT, &volt, 0, di); if (ret) { dev_err(di->dev, "error %d reading voltage\n", ret); return ret; } return volt; }
/* * Return the battery temperature in tenths of degree Celsius * Or < 0 if something fails. */ static int bq27520_battery_temperature(struct bq27520_device_info *di) { int ret, temp = 0; ret = bq27520_read(BQ27520_REG_TEMP, &temp, 0, di); if (ret) { dev_err(di->dev, "error %d reading temperature\n", ret); return ret; } return temp + ZERO_DEGREE_CELSIUS_IN_TENTH_KELVIN; }
/* * Return the battery Relative State-of-Charge * Or < 0 if something fails. */ static int bq27520_battery_rsoc(struct bq27520_device_info *di) { int ret, rsoc = 0; ret = bq27520_read(BQ27520_REG_SOC, &rsoc, 0, di); if (ret) { dev_err(di->dev, "error %d reading relative State-of-Charge\n", ret); return ret; } return rsoc; }
static void bq27520_coulomb_counter_work(struct work_struct *work) { int value = 0, temp = 0, index = 0, ret = 0, count = 0; struct bq27520_device_info *di; unsigned long flags; di = container_of(work, struct bq27520_device_info, counter); /* retrieve 30 values from FIFO of coulomb data logging buffer * and average over time */ do { ret = bq27520_read(BQ27520_REG_LOGBUF, &temp, 0, di); if (ret < 0) break; if (temp != 0x7FFF) { ++count; value += temp; } udelay(66); ret = bq27520_read(BQ27520_REG_LOGIDX, &index, 0, di); if (ret < 0) break; udelay(66); } while (index != 0 || temp != 0x7FFF); if (ret < 0) { dev_err(di->dev, "Error %d reading datalog register\n", ret); return; } if (count) { spin_lock_irqsave(&lock, flags); coulomb_counter = value/count; spin_unlock_irqrestore(&lock, flags); } }
static ssize_t bq27520_read_stdcmd(struct device *dev, struct device_attribute *attr, char *buf) { int ret; int temp = 0; struct platform_device *client; struct bq27520_device_info *di; client = to_platform_device(dev); di = platform_get_drvdata(client); if (reg <= BQ27520_REG_ICR && reg > 0x00) { ret = bq27520_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 bq27520_chip_config(struct bq27520_device_info *di) { int flags = 0, ret = 0; bq27520_cntl_cmd(di, BQ27520_SUBCMD_CTNL_STATUS); udelay(66); ret = bq27520_read(BQ27520_REG_CNTL, &flags, 0, di); if (ret < 0) { dev_err(di->dev, "error %d reading register %02x\n", ret, BQ27520_REG_CNTL); return ret; } udelay(66); bq27520_cntl_cmd(di, BQ27520_SUBCMD_ENABLE_IT); udelay(66); if (di->pdata->enable_dlog && !(flags & BQ27520_CS_DLOGEN)) { bq27520_cntl_cmd(di, BQ27520_SUBCMD_ENABLE_DLOG); udelay(66); } return 0; }