Lines Matching +full:adc +full:- +full:use +full:- +full:res
1 // SPDX-License-Identifier: GPL-2.0+
5 * Note the uG3105 is not a full-featured autonomous fuel-gauge. Instead it is
6 * expected to be use in combination with some always on microcontroller reading
7 * its coulomb-counter before it can wrap (must be read every 400 seconds!).
9 * Since Linux does not monitor coulomb-counter changes while the device
19 * 4. Add some mechanism (needs userspace help, or maybe use efivar?) to remember
23 * and then use total_coulomb_count to report energy_now over time, resetting
25 * readings, esp. in the 30-70% range and allow userspace to estimate time
28 * capacity during run-time ?
32 * in a total_coulomb_count increase of 3277 units with a 5 milli-ohm sense R.
37 #include <linux/devm-helpers.h>
75 int ocv[UG3105_MOV_AVG_WINDOW]; /* micro-volt */
76 int intern_res[UG3105_MOV_AVG_WINDOW]; /* milli-ohm */
79 int ocv_avg; /* micro-volt */
82 int intern_res_avg; /* milli-ohm */
83 int volt; /* micro-volt */
84 int curr; /* micro-ampere */
99 dev_err(&client->dev, "Error reading reg 0x%02x\n", reg); in ug3105_read_word()
106 int full = chip->info->constant_charge_voltage_max_uv - UG3105_FULL_BAT_HYST_UV; in ug3105_get_status()
108 if (chip->curr > UG3105_CURR_HYST_UA) in ug3105_get_status()
111 if (chip->curr < -UG3105_CURR_HYST_UA) in ug3105_get_status()
114 if (chip->supplied && chip->ocv_avg > full) in ug3105_get_status()
123 * OCV voltages in uV for 0-110% in 5% increments, the 100-110% is in ug3105_get_capacity()
124 * for LiPo HV (High-Voltage) bateries which can go up to 4.35V in ug3105_get_capacity()
154 if (chip->ocv_avg < ocv_capacity_tbl[0]) in ug3105_get_capacity()
157 if (chip->status == POWER_SUPPLY_STATUS_FULL) in ug3105_get_capacity()
161 if (chip->ocv_avg > ocv_capacity_tbl[i]) in ug3105_get_capacity()
164 ocv_diff = ocv_capacity_tbl[i] - chip->ocv_avg; in ug3105_get_capacity()
165 ocv_step = ocv_capacity_tbl[i] - ocv_capacity_tbl[i - 1]; in ug3105_get_capacity()
166 /* scale 0-110% down to 0-100% for LiPo HV */ in ug3105_get_capacity()
167 if (chip->info->constant_charge_voltage_max_uv >= 4300000) in ug3105_get_capacity()
168 return (i * 500 - ocv_diff * 500 / ocv_step) / 110; in ug3105_get_capacity()
170 return i * 5 - ocv_diff * 5 / ocv_step; in ug3105_get_capacity()
180 int i, val, curr_diff, volt_diff, res, win_size; in ug3105_work() local
181 bool prev_supplied = chip->supplied; in ug3105_work()
182 int prev_status = chip->status; in ug3105_work()
183 int prev_volt = chip->volt; in ug3105_work()
184 int prev_curr = chip->curr; in ug3105_work()
187 mutex_lock(&chip->lock); in ug3105_work()
189 psy = chip->psy; in ug3105_work()
193 val = ug3105_read_word(chip->client, UG3105_REG_BAT_VOLT); in ug3105_work()
196 chip->volt = val * chip->uv_per_unit; in ug3105_work()
198 val = ug3105_read_word(chip->client, UG3105_REG_BAT_CURR); in ug3105_work()
201 chip->curr = (s16)val * chip->ua_per_unit; in ug3105_work()
203 chip->ocv[chip->ocv_avg_index] = in ug3105_work()
204 chip->volt - chip->curr * chip->intern_res_avg / 1000; in ug3105_work()
205 chip->ocv_avg_index = (chip->ocv_avg_index + 1) % UG3105_MOV_AVG_WINDOW; in ug3105_work()
206 chip->poll_count++; in ug3105_work()
212 * if ((chip->poll_count % 10) == 0) { in ug3105_work()
213 * val = ug3105_read_word(chip->client, UG3105_REG_COULOMB_CNT); in ug3105_work()
217 * i2c_smbus_write_byte_data(chip->client, UG3105_REG_CTRL1, in ug3105_work()
220 * chip->total_coulomb_count += (s16)val; in ug3105_work()
221 * dev_dbg(&chip->client->dev, "coulomb count %d total %d\n", in ug3105_work()
222 * (s16)val, chip->total_coulomb_count); in ug3105_work()
226 chip->ocv_avg = 0; in ug3105_work()
227 win_size = min(chip->poll_count, UG3105_MOV_AVG_WINDOW); in ug3105_work()
229 chip->ocv_avg += chip->ocv[i]; in ug3105_work()
230 chip->ocv_avg /= win_size; in ug3105_work()
232 chip->supplied = power_supply_am_i_supplied(psy); in ug3105_work()
233 chip->status = ug3105_get_status(chip); in ug3105_work()
234 chip->capacity = ug3105_get_capacity(chip); in ug3105_work()
240 if (chip->supplied != prev_supplied || in ug3105_work()
241 chip->volt < UG3105_LOW_BAT_UV || in ug3105_work()
242 chip->poll_count < 2) in ug3105_work()
251 curr_diff = abs(chip->curr - prev_curr); in ug3105_work()
255 volt_diff = abs(chip->volt - prev_volt); in ug3105_work()
256 res = volt_diff * 1000 / curr_diff; in ug3105_work()
258 if ((res < (chip->intern_res_avg * 2 / 3)) || in ug3105_work()
259 (res > (chip->intern_res_avg * 4 / 3))) { in ug3105_work()
260 dev_dbg(&chip->client->dev, "Ignoring outlier internal resistance %d mOhm\n", res); in ug3105_work()
264 dev_dbg(&chip->client->dev, "Internal resistance %d mOhm\n", res); in ug3105_work()
266 chip->intern_res[chip->intern_res_avg_index] = res; in ug3105_work()
267 chip->intern_res_avg_index = (chip->intern_res_avg_index + 1) % UG3105_MOV_AVG_WINDOW; in ug3105_work()
268 chip->intern_res_poll_count++; in ug3105_work()
270 chip->intern_res_avg = 0; in ug3105_work()
271 win_size = min(chip->intern_res_poll_count, UG3105_MOV_AVG_WINDOW); in ug3105_work()
273 chip->intern_res_avg += chip->intern_res[i]; in ug3105_work()
274 chip->intern_res_avg /= win_size; in ug3105_work()
277 mutex_unlock(&chip->lock); in ug3105_work()
279 queue_delayed_work(system_wq, &chip->work, in ug3105_work()
280 (chip->poll_count <= UG3105_INIT_POLL_COUNT) ? in ug3105_work()
283 if (chip->status != prev_status && psy) in ug3105_work()
305 mutex_lock(&chip->lock); in ug3105_get_property()
307 if (!chip->psy) { in ug3105_get_property()
308 ret = -EAGAIN; in ug3105_get_property()
314 val->intval = chip->status; in ug3105_get_property()
317 val->intval = 1; in ug3105_get_property()
320 val->intval = chip->info->technology; in ug3105_get_property()
323 val->intval = POWER_SUPPLY_SCOPE_SYSTEM; in ug3105_get_property()
326 ret = ug3105_read_word(chip->client, UG3105_REG_BAT_VOLT); in ug3105_get_property()
329 val->intval = ret * chip->uv_per_unit; in ug3105_get_property()
333 val->intval = chip->ocv_avg; in ug3105_get_property()
336 ret = ug3105_read_word(chip->client, UG3105_REG_BAT_CURR); in ug3105_get_property()
339 val->intval = (s16)ret * chip->ua_per_unit; in ug3105_get_property()
343 val->intval = chip->capacity; in ug3105_get_property()
346 ret = -EINVAL; in ug3105_get_property()
350 mutex_unlock(&chip->lock); in ug3105_get_property()
358 dev_dbg(&chip->client->dev, "external power changed\n"); in ug3105_external_power_changed()
359 mod_delayed_work(system_wq, &chip->work, UG3105_SETTLE_TIME); in ug3105_external_power_changed()
373 chip->poll_count = 0; in ug3105_init()
374 chip->ocv_avg_index = 0; in ug3105_init()
375 chip->total_coulomb_count = 0; in ug3105_init()
376 i2c_smbus_write_byte_data(chip->client, UG3105_REG_MODE, in ug3105_init()
378 i2c_smbus_write_byte_data(chip->client, UG3105_REG_CTRL1, in ug3105_init()
380 queue_delayed_work(system_wq, &chip->work, 0); in ug3105_init()
381 flush_delayed_work(&chip->work); in ug3105_init()
387 struct device *dev = &client->dev; in ug3105_probe()
395 return -ENOMEM; in ug3105_probe()
397 chip->client = client; in ug3105_probe()
398 mutex_init(&chip->lock); in ug3105_probe()
399 ret = devm_delayed_work_autocancel(dev, &chip->work, ug3105_work); in ug3105_probe()
408 ret = power_supply_get_battery_info(psy, &chip->info); in ug3105_probe()
412 if (chip->info->factory_internal_resistance_uohm == -EINVAL || in ug3105_probe()
413 chip->info->constant_charge_voltage_max_uv == -EINVAL) { in ug3105_probe()
415 return -ENODEV; in ug3105_probe()
418 device_property_read_u32(dev, "upisemi,rsns-microohm", &curr_sense_res_uohm); in ug3105_probe()
422 * coming from somewhere for some reason (verified with a volt-meter). in ug3105_probe()
424 chip->uv_per_unit = 45000000/65536; in ug3105_probe()
425 /* Datasheet says 8.1 uV per unit for the current ADC */ in ug3105_probe()
426 chip->ua_per_unit = 8100000 / curr_sense_res_uohm; in ug3105_probe()
428 /* Use provided internal resistance as start point (in milli-ohm) */ in ug3105_probe()
429 chip->intern_res_avg = chip->info->factory_internal_resistance_uohm / 1000; in ug3105_probe()
431 chip->intern_res[0] = chip->intern_res_avg; in ug3105_probe()
432 chip->intern_res_avg_index = 1; in ug3105_probe()
433 chip->intern_res_poll_count = 1; in ug3105_probe()
435 mutex_lock(&chip->lock); in ug3105_probe()
436 chip->psy = psy; in ug3105_probe()
437 mutex_unlock(&chip->lock); in ug3105_probe()
449 cancel_delayed_work_sync(&chip->work); in ug3105_suspend()
450 i2c_smbus_write_byte_data(chip->client, UG3105_REG_MODE, in ug3105_suspend()