Lines Matching +full:rsns +full:- +full:microohm
1 // SPDX-License-Identifier: GPL-2.0+
5 * Note the uG3105 is not a full-featured autonomous fuel-gauge. Instead it is
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
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);
106 int full = chip->info->constant_charge_voltage_max_uv - UG3105_FULL_BAT_HYST_UV;
108 if (chip->curr > UG3105_CURR_HYST_UA)
111 if (chip->curr < -UG3105_CURR_HYST_UA)
114 if (chip->supplied && chip->ocv_avg > full)
123 * OCV voltages in uV for 0-110% in 5% increments, the 100-110% is
124 * for LiPo HV (High-Voltage) bateries which can go up to 4.35V
154 if (chip->ocv_avg < ocv_capacity_tbl[0])
157 if (chip->status == POWER_SUPPLY_STATUS_FULL)
161 if (chip->ocv_avg > ocv_capacity_tbl[i])
164 ocv_diff = ocv_capacity_tbl[i] - chip->ocv_avg;
165 ocv_step = ocv_capacity_tbl[i] - ocv_capacity_tbl[i - 1];
166 /* scale 0-110% down to 0-100% for LiPo HV */
167 if (chip->info->constant_charge_voltage_max_uv >= 4300000)
168 return (i * 500 - ocv_diff * 500 / ocv_step) / 110;
170 return i * 5 - ocv_diff * 5 / ocv_step;
181 bool prev_supplied = chip->supplied;
182 int prev_status = chip->status;
183 int prev_volt = chip->volt;
184 int prev_curr = chip->curr;
187 mutex_lock(&chip->lock);
189 psy = chip->psy;
193 val = ug3105_read_word(chip->client, UG3105_REG_BAT_VOLT);
196 chip->volt = val * chip->uv_per_unit;
198 val = ug3105_read_word(chip->client, UG3105_REG_BAT_CURR);
201 chip->curr = (s16)val * chip->ua_per_unit;
203 chip->ocv[chip->ocv_avg_index] =
204 chip->volt - chip->curr * chip->intern_res_avg / 1000;
205 chip->ocv_avg_index = (chip->ocv_avg_index + 1) % UG3105_MOV_AVG_WINDOW;
206 chip->poll_count++;
212 * if ((chip->poll_count % 10) == 0) {
213 * val = ug3105_read_word(chip->client, UG3105_REG_COULOMB_CNT);
217 * i2c_smbus_write_byte_data(chip->client, UG3105_REG_CTRL1,
220 * chip->total_coulomb_count += (s16)val;
221 * dev_dbg(&chip->client->dev, "coulomb count %d total %d\n",
222 * (s16)val, chip->total_coulomb_count);
226 chip->ocv_avg = 0;
227 win_size = min(chip->poll_count, UG3105_MOV_AVG_WINDOW);
229 chip->ocv_avg += chip->ocv[i];
230 chip->ocv_avg /= win_size;
232 chip->supplied = power_supply_am_i_supplied(psy);
233 chip->status = ug3105_get_status(chip);
234 chip->capacity = ug3105_get_capacity(chip);
240 if (chip->supplied != prev_supplied ||
241 chip->volt < UG3105_LOW_BAT_UV ||
242 chip->poll_count < 2)
251 curr_diff = abs(chip->curr - prev_curr);
255 volt_diff = abs(chip->volt - prev_volt);
258 if ((res < (chip->intern_res_avg * 2 / 3)) ||
259 (res > (chip->intern_res_avg * 4 / 3))) {
260 dev_dbg(&chip->client->dev, "Ignoring outlier internal resistance %d mOhm\n", res);
264 dev_dbg(&chip->client->dev, "Internal resistance %d mOhm\n", res);
266 chip->intern_res[chip->intern_res_avg_index] = res;
267 chip->intern_res_avg_index = (chip->intern_res_avg_index + 1) % UG3105_MOV_AVG_WINDOW;
268 chip->intern_res_poll_count++;
270 chip->intern_res_avg = 0;
271 win_size = min(chip->intern_res_poll_count, UG3105_MOV_AVG_WINDOW);
273 chip->intern_res_avg += chip->intern_res[i];
274 chip->intern_res_avg /= win_size;
277 mutex_unlock(&chip->lock);
279 queue_delayed_work(system_wq, &chip->work,
280 (chip->poll_count <= UG3105_INIT_POLL_COUNT) ?
283 if (chip->status != prev_status && psy)
304 mutex_lock(&chip->lock);
306 if (!chip->psy) {
307 ret = -EAGAIN;
313 val->intval = chip->status;
316 val->intval = 1;
319 val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
322 ret = ug3105_read_word(chip->client, UG3105_REG_BAT_VOLT);
325 val->intval = ret * chip->uv_per_unit;
329 val->intval = chip->ocv_avg;
332 ret = ug3105_read_word(chip->client, UG3105_REG_BAT_CURR);
335 val->intval = (s16)ret * chip->ua_per_unit;
339 val->intval = chip->capacity;
342 ret = -EINVAL;
346 mutex_unlock(&chip->lock);
354 dev_dbg(&chip->client->dev, "external power changed\n");
355 mod_delayed_work(system_wq, &chip->work, UG3105_SETTLE_TIME);
369 chip->poll_count = 0;
370 chip->ocv_avg_index = 0;
371 chip->total_coulomb_count = 0;
372 i2c_smbus_write_byte_data(chip->client, UG3105_REG_MODE,
374 i2c_smbus_write_byte_data(chip->client, UG3105_REG_CTRL1,
376 queue_delayed_work(system_wq, &chip->work, 0);
377 flush_delayed_work(&chip->work);
383 struct device *dev = &client->dev;
391 return -ENOMEM;
393 chip->client = client;
394 mutex_init(&chip->lock);
395 ret = devm_delayed_work_autocancel(dev, &chip->work, ug3105_work);
404 ret = power_supply_get_battery_info(psy, &chip->info);
408 if (chip->info->factory_internal_resistance_uohm == -EINVAL ||
409 chip->info->constant_charge_voltage_max_uv == -EINVAL) {
411 return -ENODEV;
414 device_property_read_u32(dev, "upisemi,rsns-microohm", &curr_sense_res_uohm);
418 * coming from somewhere for some reason (verified with a volt-meter).
420 chip->uv_per_unit = 45000000/65536;
422 chip->ua_per_unit = 8100000 / curr_sense_res_uohm;
424 /* Use provided internal resistance as start point (in milli-ohm) */
425 chip->intern_res_avg = chip->info->factory_internal_resistance_uohm / 1000;
427 chip->intern_res[0] = chip->intern_res_avg;
428 chip->intern_res_avg_index = 1;
429 chip->intern_res_poll_count = 1;
431 mutex_lock(&chip->lock);
432 chip->psy = psy;
433 mutex_unlock(&chip->lock);
445 cancel_delayed_work_sync(&chip->work);
446 i2c_smbus_write_byte_data(chip->client, UG3105_REG_MODE,