Lines Matching +full:micro +full:- +full:volt

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>
76 int ocv[UG3105_MOV_AVG_WINDOW]; /* micro-volt */
77 int intern_res[UG3105_MOV_AVG_WINDOW]; /* milli-ohm */
80 int ocv_avg; /* micro-volt */
83 int intern_res_avg; /* milli-ohm */
84 int volt; /* micro-volt */ member
85 int curr; /* micro-ampere */
100 dev_err(&client->dev, "Error reading reg 0x%02x\n", reg); in ug3105_read_word()
107 int full = chip->psy->battery_info->constant_charge_voltage_max_uv - in ug3105_get_status()
110 if (chip->curr > UG3105_CURR_HYST_UA) in ug3105_get_status()
113 if (chip->curr < -UG3105_CURR_HYST_UA) in ug3105_get_status()
116 if (chip->supplied && chip->ocv_avg > full) in ug3105_get_status()
127 bool prev_supplied = chip->supplied; in ug3105_work()
128 int prev_status = chip->status; in ug3105_work()
129 int prev_volt = chip->volt; in ug3105_work()
130 int prev_curr = chip->curr; in ug3105_work()
133 mutex_lock(&chip->lock); in ug3105_work()
135 psy = chip->psy; in ug3105_work()
139 val = ug3105_read_word(chip->client, UG3105_REG_BAT_VOLT); in ug3105_work()
142 chip->volt = val * chip->uv_per_unit; in ug3105_work()
144 val = ug3105_read_word(chip->client, UG3105_REG_BAT_CURR); in ug3105_work()
147 chip->curr = (s16)val * chip->ua_per_unit; in ug3105_work()
149 chip->ocv[chip->ocv_avg_index] = in ug3105_work()
150 chip->volt - chip->curr * chip->intern_res_avg / 1000; in ug3105_work()
151 chip->ocv_avg_index = (chip->ocv_avg_index + 1) % UG3105_MOV_AVG_WINDOW; in ug3105_work()
152 chip->poll_count++; in ug3105_work()
158 * if ((chip->poll_count % 10) == 0) { in ug3105_work()
159 * val = ug3105_read_word(chip->client, UG3105_REG_COULOMB_CNT); in ug3105_work()
163 * i2c_smbus_write_byte_data(chip->client, UG3105_REG_CTRL1, in ug3105_work()
166 * chip->total_coulomb_count += (s16)val; in ug3105_work()
167 * dev_dbg(&chip->client->dev, "coulomb count %d total %d\n", in ug3105_work()
168 * (s16)val, chip->total_coulomb_count); in ug3105_work()
172 chip->ocv_avg = 0; in ug3105_work()
173 win_size = min(chip->poll_count, UG3105_MOV_AVG_WINDOW); in ug3105_work()
175 chip->ocv_avg += chip->ocv[i]; in ug3105_work()
176 chip->ocv_avg /= win_size; in ug3105_work()
178 chip->supplied = power_supply_am_i_supplied(psy); in ug3105_work()
179 chip->status = ug3105_get_status(chip); in ug3105_work()
180 if (chip->status == POWER_SUPPLY_STATUS_FULL) in ug3105_work()
181 chip->capacity = 100; in ug3105_work()
183 chip->capacity = power_supply_batinfo_ocv2cap(chip->psy->battery_info, in ug3105_work()
184 chip->ocv_avg, in ug3105_work()
191 if (chip->supplied != prev_supplied || in ug3105_work()
192 chip->volt < UG3105_LOW_BAT_UV || in ug3105_work()
193 chip->poll_count < 2) in ug3105_work()
202 curr_diff = abs(chip->curr - prev_curr); in ug3105_work()
206 volt_diff = abs(chip->volt - prev_volt); in ug3105_work()
209 if ((res < (chip->intern_res_avg * 2 / 3)) || in ug3105_work()
210 (res > (chip->intern_res_avg * 4 / 3))) { in ug3105_work()
211 dev_dbg(&chip->client->dev, "Ignoring outlier internal resistance %d mOhm\n", res); in ug3105_work()
215 dev_dbg(&chip->client->dev, "Internal resistance %d mOhm\n", res); in ug3105_work()
217 chip->intern_res[chip->intern_res_avg_index] = res; in ug3105_work()
218 chip->intern_res_avg_index = (chip->intern_res_avg_index + 1) % UG3105_MOV_AVG_WINDOW; in ug3105_work()
219 chip->intern_res_poll_count++; in ug3105_work()
221 chip->intern_res_avg = 0; in ug3105_work()
222 win_size = min(chip->intern_res_poll_count, UG3105_MOV_AVG_WINDOW); in ug3105_work()
224 chip->intern_res_avg += chip->intern_res[i]; in ug3105_work()
225 chip->intern_res_avg /= win_size; in ug3105_work()
228 mutex_unlock(&chip->lock); in ug3105_work()
230 queue_delayed_work(system_wq, &chip->work, in ug3105_work()
231 (chip->poll_count <= UG3105_INIT_POLL_COUNT) ? in ug3105_work()
234 if (chip->status != prev_status && psy) in ug3105_work()
255 mutex_lock(&chip->lock); in ug3105_get_property()
257 if (!chip->psy) { in ug3105_get_property()
258 ret = -EAGAIN; in ug3105_get_property()
264 val->intval = chip->status; in ug3105_get_property()
267 val->intval = 1; in ug3105_get_property()
270 val->intval = POWER_SUPPLY_SCOPE_SYSTEM; in ug3105_get_property()
273 ret = ug3105_read_word(chip->client, UG3105_REG_BAT_VOLT); in ug3105_get_property()
276 val->intval = ret * chip->uv_per_unit; in ug3105_get_property()
280 val->intval = chip->ocv_avg; in ug3105_get_property()
283 ret = ug3105_read_word(chip->client, UG3105_REG_BAT_CURR); in ug3105_get_property()
286 val->intval = (s16)ret * chip->ua_per_unit; in ug3105_get_property()
290 val->intval = chip->capacity; in ug3105_get_property()
293 ret = -EINVAL; in ug3105_get_property()
297 mutex_unlock(&chip->lock); in ug3105_get_property()
305 dev_dbg(&chip->client->dev, "external power changed\n"); in ug3105_external_power_changed()
306 mod_delayed_work(system_wq, &chip->work, UG3105_SETTLE_TIME); in ug3105_external_power_changed()
320 chip->poll_count = 0; in ug3105_init()
321 chip->ocv_avg_index = 0; in ug3105_init()
322 chip->total_coulomb_count = 0; in ug3105_init()
323 i2c_smbus_write_byte_data(chip->client, UG3105_REG_MODE, in ug3105_init()
325 i2c_smbus_write_byte_data(chip->client, UG3105_REG_CTRL1, in ug3105_init()
327 queue_delayed_work(system_wq, &chip->work, 0); in ug3105_init()
328 flush_delayed_work(&chip->work); in ug3105_init()
334 struct device *dev = &client->dev; in ug3105_probe()
342 return -ENOMEM; in ug3105_probe()
344 chip->client = client; in ug3105_probe()
345 mutex_init(&chip->lock); in ug3105_probe()
346 ret = devm_delayed_work_autocancel(dev, &chip->work, ug3105_work); in ug3105_probe()
355 if (!psy->battery_info || in ug3105_probe()
356 psy->battery_info->factory_internal_resistance_uohm == -EINVAL || in ug3105_probe()
357 psy->battery_info->constant_charge_voltage_max_uv == -EINVAL || in ug3105_probe()
358 !psy->battery_info->ocv_table[0]) { in ug3105_probe()
360 return -ENODEV; in ug3105_probe()
363 device_property_read_u32(dev, "upisemi,rsns-microohm", &curr_sense_res_uohm); in ug3105_probe()
367 * coming from somewhere for some reason (verified with a volt-meter). in ug3105_probe()
369 chip->uv_per_unit = 45000000/65536; in ug3105_probe()
371 chip->ua_per_unit = 8100000 / curr_sense_res_uohm; in ug3105_probe()
373 /* Use provided internal resistance as start point (in milli-ohm) */ in ug3105_probe()
374 chip->intern_res_avg = psy->battery_info->factory_internal_resistance_uohm / 1000; in ug3105_probe()
376 chip->intern_res[0] = chip->intern_res_avg; in ug3105_probe()
377 chip->intern_res_avg_index = 1; in ug3105_probe()
378 chip->intern_res_poll_count = 1; in ug3105_probe()
380 mutex_lock(&chip->lock); in ug3105_probe()
381 chip->psy = psy; in ug3105_probe()
382 mutex_unlock(&chip->lock); in ug3105_probe()
394 cancel_delayed_work_sync(&chip->work); in ug3105_suspend()
395 i2c_smbus_write_byte_data(chip->client, UG3105_REG_MODE, in ug3105_suspend()