Lines Matching refs:cw_bat
97 static int cw_read_word(struct cw_battery *cw_bat, u8 reg, u16 *val) in cw_read_word() argument
102 ret = regmap_bulk_read(cw_bat->regmap, reg, &value, sizeof(value)); in cw_read_word()
110 static void cw2017_enable(struct cw_battery *cw_bat) in cw2017_enable() argument
114 regmap_write(cw_bat->regmap, CW2017_REG_MODE_CONFIG, reg_val); in cw2017_enable()
117 regmap_write(cw_bat->regmap, CW2017_REG_MODE_CONFIG, reg_val); in cw2017_enable()
120 regmap_write(cw_bat->regmap, CW2017_REG_MODE_CONFIG, reg_val); in cw2017_enable()
124 static int cw_update_profile(struct cw_battery *cw_bat) in cw_update_profile() argument
131 ret = regmap_raw_write(cw_bat->regmap, CW2017_REG_BATINFO, in cw_update_profile()
132 cw_bat->bat_profile, in cw_update_profile()
140 reg_val |= cw_bat->alert_level; in cw_update_profile()
141 regmap_write(cw_bat->regmap, CW2017_REG_SOC_ALERT, reg_val); in cw_update_profile()
143 if (cw_bat->alert_level) in cw_update_profile()
146 cw_bat->temp_max = TEMP_MAX_ALERT; in cw_update_profile()
147 cw_bat->temp_min = TEMP_MIN_ALERT; in cw_update_profile()
148 if (cw_bat->temp_max != TEMP_ALERT_DISABLE) { in cw_update_profile()
150 reg_val = (cw_bat->temp_max + 40) * 2; in cw_update_profile()
151 regmap_write(cw_bat->regmap, CW2017_REG_TEMP_MAX, reg_val); in cw_update_profile()
153 if (cw_bat->temp_min != TEMP_ALERT_DISABLE) { in cw_update_profile()
155 reg_val = (cw_bat->temp_min + 40) * 2; in cw_update_profile()
156 regmap_write(cw_bat->regmap, CW2017_REG_TEMP_MIN, reg_val); in cw_update_profile()
158 regmap_write(cw_bat->regmap, CW2017_REG_INT_CONFIG, int_mask); in cw_update_profile()
164 ret = regmap_read_poll_timeout(cw_bat->regmap, CW2017_REG_SOC_INT, in cw_update_profile()
168 dev_err(cw_bat->dev, in cw_update_profile()
171 dev_dbg(cw_bat->dev, "Battery profile updated\n"); in cw_update_profile()
173 cw2017_enable(cw_bat); in cw_update_profile()
174 dev_dbg(cw_bat->dev, "Battery profile configured\n"); in cw_update_profile()
179 static int cw_init(struct cw_battery *cw_bat) in cw_init() argument
185 regmap_read(cw_bat->regmap, CW2017_REG_MODE_CONFIG, ®_val); in cw_init()
186 regmap_read(cw_bat->regmap, CW2017_REG_SOC_ALERT, &config_flg); in cw_init()
189 dev_dbg(cw_bat->dev, in cw_init()
191 if (cw_bat->bat_profile) { in cw_init()
192 ret = cw_update_profile(cw_bat); in cw_init()
194 dev_err(cw_bat->dev, in cw_init()
199 dev_warn(cw_bat->dev, in cw_init()
202 } else if (cw_bat->bat_profile) { in cw_init()
205 ret = regmap_raw_read(cw_bat->regmap, CW2017_REG_BATINFO, in cw_init()
208 dev_err(cw_bat->dev, in cw_init()
213 if (memcmp(bat_info, cw_bat->bat_profile, CW2017_SIZE_BATINFO)) { in cw_init()
214 dev_warn(cw_bat->dev, "Replacing stored battery profile\n"); in cw_init()
215 ret = cw_update_profile(cw_bat); in cw_init()
220 dev_warn(cw_bat->dev, in cw_init()
230 static int cw_get_soc(struct cw_battery *cw_bat) in cw_get_soc() argument
234 regmap_read(cw_bat->regmap, CW2017_REG_SOC_INT, &soc); in cw_get_soc()
237 CW2017_BAT_SOC_ERROR_MS / cw_bat->poll_interval_ms; in cw_get_soc()
239 dev_err(cw_bat->dev, "Invalid SoC %d%%\n", soc); in cw_get_soc()
240 cw_bat->read_errors++; in cw_get_soc()
241 if (cw_bat->read_errors > max_error_cycles) { in cw_get_soc()
242 dev_warn(cw_bat->dev, in cw_get_soc()
244 cw_bat->read_errors = 0; in cw_get_soc()
246 return cw_bat->soc; in cw_get_soc()
248 cw_bat->read_errors = 0; in cw_get_soc()
251 if (cw_bat->status == POWER_SUPPLY_STATUS_CHARGING && soc == cw_bat->soc) { in cw_get_soc()
253 CW2017_BAT_CHARGING_STUCK_MS / cw_bat->poll_interval_ms; in cw_get_soc()
255 cw_bat->charge_stuck_cnt++; in cw_get_soc()
256 if (cw_bat->charge_stuck_cnt > max_stuck_cycles) { in cw_get_soc()
257 dev_warn(cw_bat->dev, in cw_get_soc()
259 cw_bat->charge_stuck_cnt = 0; in cw_get_soc()
262 cw_bat->charge_stuck_cnt = 0; in cw_get_soc()
266 if (cw_bat->charger_attached && HYSTERESIS(soc, cw_bat->soc, 0, 3)) in cw_get_soc()
267 soc = cw_bat->soc; in cw_get_soc()
270 if (!cw_bat->charger_attached && HYSTERESIS(soc, cw_bat->soc, 3, 0)) in cw_get_soc()
271 soc = cw_bat->soc; in cw_get_soc()
276 static int cw_get_voltage(struct cw_battery *cw_bat) in cw_get_voltage() argument
281 cw_read_word(cw_bat, CW2017_REG_VCELL_H, ®_val); in cw_get_voltage()
284 if (cw_bat->dual_cell) in cw_get_voltage()
287 dev_dbg(cw_bat->dev, "Read voltage: %d mV, raw=0x%04x\n", in cw_get_voltage()
293 static void cw_update_charge_status(struct cw_battery *cw_bat) in cw_update_charge_status() argument
297 ret = power_supply_am_i_supplied(cw_bat->rk_bat); in cw_update_charge_status()
299 dev_warn(cw_bat->dev, "Failed to get supply state: %d\n", ret); in cw_update_charge_status()
304 if (cw_bat->charger_attached != charger_attached) { in cw_update_charge_status()
305 cw_bat->battery_changed = true; in cw_update_charge_status()
307 cw_bat->charge_count++; in cw_update_charge_status()
309 cw_bat->charger_attached = charger_attached; in cw_update_charge_status()
313 static void cw_update_soc(struct cw_battery *cw_bat) in cw_update_soc() argument
317 soc = cw_get_soc(cw_bat); in cw_update_soc()
319 dev_err(cw_bat->dev, "Failed to get SoC from gauge: %d\n", soc); in cw_update_soc()
320 else if (cw_bat->soc != soc) { in cw_update_soc()
321 cw_bat->soc = soc; in cw_update_soc()
322 cw_bat->battery_changed = true; in cw_update_soc()
326 static void cw_update_voltage(struct cw_battery *cw_bat) in cw_update_voltage() argument
330 voltage_mv = cw_get_voltage(cw_bat); in cw_update_voltage()
332 dev_err(cw_bat->dev, "Failed to get voltage from gauge: %d\n", in cw_update_voltage()
335 cw_bat->voltage_mv = voltage_mv; in cw_update_voltage()
338 static int cw_update_temp(struct cw_battery *cw_bat) in cw_update_temp() argument
342 regmap_read(cw_bat->regmap, CW2017_REG_TEMP, &val); in cw_update_temp()
343 cw_bat->temp = val * 10 / 2 - 400; in cw_update_temp()
345 return cw_bat->temp; in cw_update_temp()
348 static void cw_update_status(struct cw_battery *cw_bat) in cw_update_status() argument
352 if (cw_bat->charger_attached) { in cw_update_status()
353 if (cw_bat->soc >= 100) in cw_update_status()
359 if (cw_bat->status != status) in cw_update_status()
360 cw_bat->battery_changed = true; in cw_update_status()
361 cw_bat->status = status; in cw_update_status()
367 struct cw_battery *cw_bat; in cw_bat_work() local
370 cw_bat = container_of(delay_work, struct cw_battery, battery_delay_work); in cw_bat_work()
372 cw_update_soc(cw_bat); in cw_bat_work()
373 cw_update_voltage(cw_bat); in cw_bat_work()
374 cw_update_charge_status(cw_bat); in cw_bat_work()
375 cw_update_temp(cw_bat); in cw_bat_work()
376 cw_update_status(cw_bat); in cw_bat_work()
378 dev_dbg(cw_bat->dev, "charger_attached = %d\n", cw_bat->charger_attached); in cw_bat_work()
379 dev_dbg(cw_bat->dev, "status = %d\n", cw_bat->status); in cw_bat_work()
380 dev_dbg(cw_bat->dev, "soc = %d%%\n", cw_bat->soc); in cw_bat_work()
381 dev_dbg(cw_bat->dev, "voltage = %dmV\n", cw_bat->voltage_mv); in cw_bat_work()
383 if (cw_bat->battery_changed) in cw_bat_work()
384 power_supply_changed(cw_bat->rk_bat); in cw_bat_work()
385 cw_bat->battery_changed = false; in cw_bat_work()
387 queue_delayed_work(cw_bat->battery_workqueue, in cw_bat_work()
388 &cw_bat->battery_delay_work, in cw_bat_work()
389 msecs_to_jiffies(cw_bat->poll_interval_ms)); in cw_bat_work()
396 struct cw_battery *cw_bat; in cw_battery_get_property() local
398 cw_bat = power_supply_get_drvdata(psy); in cw_battery_get_property()
401 val->intval = cw_bat->soc; in cw_battery_get_property()
405 val->intval = cw_bat->status; in cw_battery_get_property()
409 val->intval = !!cw_bat->voltage_mv; in cw_battery_get_property()
413 val->intval = cw_bat->voltage_mv * 1000; in cw_battery_get_property()
425 val->intval = cw_bat->charge_count; in cw_battery_get_property()
429 val->intval = cw_bat->temp; in cw_battery_get_property()
434 if (cw_bat->battery.charge_full_design_uah > 0) in cw_battery_get_property()
435 val->intval = cw_bat->battery.charge_full_design_uah; in cw_battery_get_property()
437 val->intval = cw_bat->design_capacity * 1000; in cw_battery_get_property()
472 static int cw2017_parse_properties(struct cw_battery *cw_bat) in cw2017_parse_properties() argument
474 struct device *dev = cw_bat->dev; in cw2017_parse_properties()
480 dev_warn(cw_bat->dev, in cw2017_parse_properties()
483 dev_err(cw_bat->dev, "battery-profile must be %d bytes\n", in cw2017_parse_properties()
488 cw_bat->bat_profile = devm_kzalloc(dev, length, GFP_KERNEL); in cw2017_parse_properties()
489 if (!cw_bat->bat_profile) in cw2017_parse_properties()
494 cw_bat->bat_profile, in cw2017_parse_properties()
500 &cw_bat->design_capacity); in cw2017_parse_properties()
502 dev_info(cw_bat->dev, "Missing design capacity\n"); in cw2017_parse_properties()
503 cw_bat->design_capacity = DEF_DESIGN_CAPACITY; in cw2017_parse_properties()
507 &cw_bat->alert_level); in cw2017_parse_properties()
509 cw_bat->dual_cell = device_property_read_bool(dev, "cellwise,dual-cell"); in cw2017_parse_properties()
512 &cw_bat->poll_interval_ms); in cw2017_parse_properties()
514 dev_dbg(cw_bat->dev, "Using default poll interval\n"); in cw2017_parse_properties()
515 cw_bat->poll_interval_ms = CW2017_DEFAULT_POLL_INTERVAL_MS; in cw2017_parse_properties()
567 struct cw_battery *cw_bat; in cw_bat_probe() local
570 cw_bat = devm_kzalloc(&client->dev, sizeof(*cw_bat), GFP_KERNEL); in cw_bat_probe()
571 if (!cw_bat) in cw_bat_probe()
574 i2c_set_clientdata(client, cw_bat); in cw_bat_probe()
575 cw_bat->dev = &client->dev; in cw_bat_probe()
576 cw_bat->soc = 1; in cw_bat_probe()
578 ret = cw2017_parse_properties(cw_bat); in cw_bat_probe()
580 dev_err(cw_bat->dev, "Failed to parse cw2017 properties\n"); in cw_bat_probe()
584 cw_bat->regmap = devm_regmap_init_i2c(client, &cw2017_regmap_config); in cw_bat_probe()
585 if (IS_ERR(cw_bat->regmap)) { in cw_bat_probe()
586 dev_err(cw_bat->dev, "Failed to allocate regmap: %ld\n", in cw_bat_probe()
587 PTR_ERR(cw_bat->regmap)); in cw_bat_probe()
588 return PTR_ERR(cw_bat->regmap); in cw_bat_probe()
591 ret = cw_init(cw_bat); in cw_bat_probe()
593 dev_err(cw_bat->dev, "Init failed: %d\n", ret); in cw_bat_probe()
597 psy_cfg.drv_data = cw_bat; in cw_bat_probe()
598 psy_cfg.fwnode = dev_fwnode(cw_bat->dev); in cw_bat_probe()
600 cw_bat->rk_bat = devm_power_supply_register(&client->dev, in cw_bat_probe()
603 if (IS_ERR(cw_bat->rk_bat)) { in cw_bat_probe()
604 dev_err(cw_bat->dev, "Failed to register power supply\n"); in cw_bat_probe()
605 return PTR_ERR(cw_bat->rk_bat); in cw_bat_probe()
608 ret = power_supply_get_battery_info(cw_bat->rk_bat, &cw_bat->battery); in cw_bat_probe()
610 dev_warn(cw_bat->dev, in cw_bat_probe()
614 cw_bat->battery_workqueue = create_singlethread_workqueue("rk_battery"); in cw_bat_probe()
615 INIT_DELAYED_WORK(&cw_bat->battery_delay_work, cw_bat_work); in cw_bat_probe()
616 queue_delayed_work(cw_bat->battery_workqueue, in cw_bat_probe()
617 &cw_bat->battery_delay_work, msecs_to_jiffies(10)); in cw_bat_probe()
625 struct cw_battery *cw_bat = i2c_get_clientdata(client); in cw_bat_suspend() local
627 cancel_delayed_work_sync(&cw_bat->battery_delay_work); in cw_bat_suspend()
634 struct cw_battery *cw_bat = i2c_get_clientdata(client); in cw_bat_resume() local
636 queue_delayed_work(cw_bat->battery_workqueue, in cw_bat_resume()
637 &cw_bat->battery_delay_work, 0); in cw_bat_resume()
645 struct cw_battery *cw_bat = i2c_get_clientdata(client); in cw_bat_remove() local
647 cancel_delayed_work_sync(&cw_bat->battery_delay_work); in cw_bat_remove()
648 power_supply_put_battery_info(cw_bat->rk_bat, &cw_bat->battery); in cw_bat_remove()