1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Battery monitor driver for the uPI uG3105 battery monitor
4 *
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!).
8 *
9 * Since Linux does not monitor coulomb-counter changes while the device
10 * is off or suspended, the coulomb counter is not used atm.
11 *
12 * Possible improvements:
13 * 1. Activate commented out total_coulomb_count code
14 * 2. Reset total_coulomb_count val to 0 when the battery is as good as empty
15 * and remember that we did this (and clear the flag for this on susp/resume)
16 * 3. When the battery is full check if the flag that we set total_coulomb_count
17 * to when the battery was empty is set. If so we now know the capacity,
18 * not the design, but actual capacity, of the battery
19 * 4. Add some mechanism (needs userspace help, or maybe use efivar?) to remember
20 * the actual capacity of the battery over reboots
21 * 5. When we know the actual capacity at probe time, add energy_now and
22 * energy_full attributes. Guess boot + resume energy_now value based on ocv
23 * and then use total_coulomb_count to report energy_now over time, resetting
24 * things to adjust for drift when empty/full. This should give more accurate
25 * readings, esp. in the 30-70% range and allow userspace to estimate time
26 * remaining till empty/full
27 * 6. Maybe unregister + reregister the psy device when we learn the actual
28 * capacity during run-time ?
29 *
30 * The above will also require some sort of mwh_per_unit calculation. Testing
31 * has shown that an estimated 7404mWh increase of the battery's energy results
32 * in a total_coulomb_count increase of 3277 units with a 5 milli-ohm sense R.
33 *
34 * Copyright (C) 2021 Hans de Goede <[email protected]>
35 */
36
37 #include <linux/devm-helpers.h>
38 #include <linux/module.h>
39 #include <linux/mutex.h>
40 #include <linux/slab.h>
41 #include <linux/i2c.h>
42 #include <linux/mod_devicetable.h>
43 #include <linux/power_supply.h>
44 #include <linux/workqueue.h>
45
46 #define UG3105_MOV_AVG_WINDOW 8
47 #define UG3105_INIT_POLL_TIME (5 * HZ)
48 #define UG3105_POLL_TIME (30 * HZ)
49 #define UG3105_SETTLE_TIME (1 * HZ)
50
51 #define UG3105_INIT_POLL_COUNT 30
52
53 #define UG3105_REG_MODE 0x00
54 #define UG3105_REG_CTRL1 0x01
55 #define UG3105_REG_COULOMB_CNT 0x02
56 #define UG3105_REG_BAT_VOLT 0x08
57 #define UG3105_REG_BAT_CURR 0x0c
58
59 #define UG3105_MODE_STANDBY 0x00
60 #define UG3105_MODE_RUN 0x10
61
62 #define UG3105_CTRL1_RESET_COULOMB_CNT 0x03
63
64 #define UG3105_CURR_HYST_UA 65000
65
66 #define UG3105_LOW_BAT_UV 3700000
67 #define UG3105_FULL_BAT_HYST_UV 38000
68
69 struct ug3105_chip {
70 struct i2c_client *client;
71 struct power_supply *psy;
72 struct power_supply_battery_info *info;
73 struct delayed_work work;
74 struct mutex lock;
75 int ocv[UG3105_MOV_AVG_WINDOW]; /* micro-volt */
76 int intern_res[UG3105_MOV_AVG_WINDOW]; /* milli-ohm */
77 int poll_count;
78 int ocv_avg_index;
79 int ocv_avg; /* micro-volt */
80 int intern_res_poll_count;
81 int intern_res_avg_index;
82 int intern_res_avg; /* milli-ohm */
83 int volt; /* micro-volt */
84 int curr; /* micro-ampere */
85 int total_coulomb_count;
86 int uv_per_unit;
87 int ua_per_unit;
88 int status;
89 int capacity;
90 bool supplied;
91 };
92
ug3105_read_word(struct i2c_client * client,u8 reg)93 static int ug3105_read_word(struct i2c_client *client, u8 reg)
94 {
95 int val;
96
97 val = i2c_smbus_read_word_data(client, reg);
98 if (val < 0)
99 dev_err(&client->dev, "Error reading reg 0x%02x\n", reg);
100
101 return val;
102 }
103
ug3105_get_status(struct ug3105_chip * chip)104 static int ug3105_get_status(struct ug3105_chip *chip)
105 {
106 int full = chip->info->constant_charge_voltage_max_uv - UG3105_FULL_BAT_HYST_UV;
107
108 if (chip->curr > UG3105_CURR_HYST_UA)
109 return POWER_SUPPLY_STATUS_CHARGING;
110
111 if (chip->curr < -UG3105_CURR_HYST_UA)
112 return POWER_SUPPLY_STATUS_DISCHARGING;
113
114 if (chip->supplied && chip->ocv_avg > full)
115 return POWER_SUPPLY_STATUS_FULL;
116
117 return POWER_SUPPLY_STATUS_NOT_CHARGING;
118 }
119
ug3105_get_capacity(struct ug3105_chip * chip)120 static int ug3105_get_capacity(struct ug3105_chip *chip)
121 {
122 /*
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
125 * instead of the usual 4.2V.
126 */
127 static const int ocv_capacity_tbl[23] = {
128 3350000,
129 3610000,
130 3690000,
131 3710000,
132 3730000,
133 3750000,
134 3770000,
135 3786667,
136 3803333,
137 3820000,
138 3836667,
139 3853333,
140 3870000,
141 3907500,
142 3945000,
143 3982500,
144 4020000,
145 4075000,
146 4110000,
147 4150000,
148 4200000,
149 4250000,
150 4300000,
151 };
152 int i, ocv_diff, ocv_step;
153
154 if (chip->ocv_avg < ocv_capacity_tbl[0])
155 return 0;
156
157 if (chip->status == POWER_SUPPLY_STATUS_FULL)
158 return 100;
159
160 for (i = 1; i < ARRAY_SIZE(ocv_capacity_tbl); i++) {
161 if (chip->ocv_avg > ocv_capacity_tbl[i])
162 continue;
163
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;
169 else
170 return i * 5 - ocv_diff * 5 / ocv_step;
171 }
172
173 return 100;
174 }
175
ug3105_work(struct work_struct * work)176 static void ug3105_work(struct work_struct *work)
177 {
178 struct ug3105_chip *chip = container_of(work, struct ug3105_chip,
179 work.work);
180 int i, val, curr_diff, volt_diff, res, win_size;
181 bool prev_supplied = chip->supplied;
182 int prev_status = chip->status;
183 int prev_volt = chip->volt;
184 int prev_curr = chip->curr;
185 struct power_supply *psy;
186
187 mutex_lock(&chip->lock);
188
189 psy = chip->psy;
190 if (!psy)
191 goto out;
192
193 val = ug3105_read_word(chip->client, UG3105_REG_BAT_VOLT);
194 if (val < 0)
195 goto out;
196 chip->volt = val * chip->uv_per_unit;
197
198 val = ug3105_read_word(chip->client, UG3105_REG_BAT_CURR);
199 if (val < 0)
200 goto out;
201 chip->curr = (s16)val * chip->ua_per_unit;
202
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++;
207
208 /*
209 * See possible improvements comment above.
210 *
211 * Read + reset coulomb counter every 10 polls (every 300 seconds)
212 * if ((chip->poll_count % 10) == 0) {
213 * val = ug3105_read_word(chip->client, UG3105_REG_COULOMB_CNT);
214 * if (val < 0)
215 * goto out;
216 *
217 * i2c_smbus_write_byte_data(chip->client, UG3105_REG_CTRL1,
218 * UG3105_CTRL1_RESET_COULOMB_CNT);
219 *
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);
223 * }
224 */
225
226 chip->ocv_avg = 0;
227 win_size = min(chip->poll_count, UG3105_MOV_AVG_WINDOW);
228 for (i = 0; i < win_size; i++)
229 chip->ocv_avg += chip->ocv[i];
230 chip->ocv_avg /= win_size;
231
232 chip->supplied = power_supply_am_i_supplied(psy);
233 chip->status = ug3105_get_status(chip);
234 chip->capacity = ug3105_get_capacity(chip);
235
236 /*
237 * Skip internal resistance calc on charger [un]plug and
238 * when the battery is almost empty (voltage low).
239 */
240 if (chip->supplied != prev_supplied ||
241 chip->volt < UG3105_LOW_BAT_UV ||
242 chip->poll_count < 2)
243 goto out;
244
245 /*
246 * Assuming that the OCV voltage does not change significantly
247 * between 2 polls, then we can calculate the internal resistance
248 * on a significant current change by attributing all voltage
249 * change between the 2 readings to the internal resistance.
250 */
251 curr_diff = abs(chip->curr - prev_curr);
252 if (curr_diff < UG3105_CURR_HYST_UA)
253 goto out;
254
255 volt_diff = abs(chip->volt - prev_volt);
256 res = volt_diff * 1000 / curr_diff;
257
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);
261 goto out;
262 }
263
264 dev_dbg(&chip->client->dev, "Internal resistance %d mOhm\n", res);
265
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++;
269
270 chip->intern_res_avg = 0;
271 win_size = min(chip->intern_res_poll_count, UG3105_MOV_AVG_WINDOW);
272 for (i = 0; i < win_size; i++)
273 chip->intern_res_avg += chip->intern_res[i];
274 chip->intern_res_avg /= win_size;
275
276 out:
277 mutex_unlock(&chip->lock);
278
279 queue_delayed_work(system_wq, &chip->work,
280 (chip->poll_count <= UG3105_INIT_POLL_COUNT) ?
281 UG3105_INIT_POLL_TIME : UG3105_POLL_TIME);
282
283 if (chip->status != prev_status && psy)
284 power_supply_changed(psy);
285 }
286
287 static enum power_supply_property ug3105_battery_props[] = {
288 POWER_SUPPLY_PROP_STATUS,
289 POWER_SUPPLY_PROP_PRESENT,
290 POWER_SUPPLY_PROP_SCOPE,
291 POWER_SUPPLY_PROP_VOLTAGE_NOW,
292 POWER_SUPPLY_PROP_VOLTAGE_OCV,
293 POWER_SUPPLY_PROP_CURRENT_NOW,
294 POWER_SUPPLY_PROP_CAPACITY,
295 };
296
ug3105_get_property(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)297 static int ug3105_get_property(struct power_supply *psy,
298 enum power_supply_property psp,
299 union power_supply_propval *val)
300 {
301 struct ug3105_chip *chip = power_supply_get_drvdata(psy);
302 int ret = 0;
303
304 mutex_lock(&chip->lock);
305
306 if (!chip->psy) {
307 ret = -EAGAIN;
308 goto out;
309 }
310
311 switch (psp) {
312 case POWER_SUPPLY_PROP_STATUS:
313 val->intval = chip->status;
314 break;
315 case POWER_SUPPLY_PROP_PRESENT:
316 val->intval = 1;
317 break;
318 case POWER_SUPPLY_PROP_SCOPE:
319 val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
320 break;
321 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
322 ret = ug3105_read_word(chip->client, UG3105_REG_BAT_VOLT);
323 if (ret < 0)
324 break;
325 val->intval = ret * chip->uv_per_unit;
326 ret = 0;
327 break;
328 case POWER_SUPPLY_PROP_VOLTAGE_OCV:
329 val->intval = chip->ocv_avg;
330 break;
331 case POWER_SUPPLY_PROP_CURRENT_NOW:
332 ret = ug3105_read_word(chip->client, UG3105_REG_BAT_CURR);
333 if (ret < 0)
334 break;
335 val->intval = (s16)ret * chip->ua_per_unit;
336 ret = 0;
337 break;
338 case POWER_SUPPLY_PROP_CAPACITY:
339 val->intval = chip->capacity;
340 break;
341 default:
342 ret = -EINVAL;
343 }
344
345 out:
346 mutex_unlock(&chip->lock);
347 return ret;
348 }
349
ug3105_external_power_changed(struct power_supply * psy)350 static void ug3105_external_power_changed(struct power_supply *psy)
351 {
352 struct ug3105_chip *chip = power_supply_get_drvdata(psy);
353
354 dev_dbg(&chip->client->dev, "external power changed\n");
355 mod_delayed_work(system_wq, &chip->work, UG3105_SETTLE_TIME);
356 }
357
358 static const struct power_supply_desc ug3105_psy_desc = {
359 .name = "ug3105_battery",
360 .type = POWER_SUPPLY_TYPE_BATTERY,
361 .get_property = ug3105_get_property,
362 .external_power_changed = ug3105_external_power_changed,
363 .properties = ug3105_battery_props,
364 .num_properties = ARRAY_SIZE(ug3105_battery_props),
365 };
366
ug3105_init(struct ug3105_chip * chip)367 static void ug3105_init(struct ug3105_chip *chip)
368 {
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,
373 UG3105_MODE_RUN);
374 i2c_smbus_write_byte_data(chip->client, UG3105_REG_CTRL1,
375 UG3105_CTRL1_RESET_COULOMB_CNT);
376 queue_delayed_work(system_wq, &chip->work, 0);
377 flush_delayed_work(&chip->work);
378 }
379
ug3105_probe(struct i2c_client * client)380 static int ug3105_probe(struct i2c_client *client)
381 {
382 struct power_supply_config psy_cfg = {};
383 struct device *dev = &client->dev;
384 u32 curr_sense_res_uohm = 10000;
385 struct power_supply *psy;
386 struct ug3105_chip *chip;
387 int ret;
388
389 chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
390 if (!chip)
391 return -ENOMEM;
392
393 chip->client = client;
394 mutex_init(&chip->lock);
395 ret = devm_delayed_work_autocancel(dev, &chip->work, ug3105_work);
396 if (ret)
397 return ret;
398
399 psy_cfg.drv_data = chip;
400 psy = devm_power_supply_register(dev, &ug3105_psy_desc, &psy_cfg);
401 if (IS_ERR(psy))
402 return PTR_ERR(psy);
403
404 ret = power_supply_get_battery_info(psy, &chip->info);
405 if (ret)
406 return ret;
407
408 if (chip->info->factory_internal_resistance_uohm == -EINVAL ||
409 chip->info->constant_charge_voltage_max_uv == -EINVAL) {
410 dev_err(dev, "error required properties are missing\n");
411 return -ENODEV;
412 }
413
414 device_property_read_u32(dev, "upisemi,rsns-microohm", &curr_sense_res_uohm);
415
416 /*
417 * DAC maximum is 4.5V divided by 65536 steps + an unknown factor of 10
418 * coming from somewhere for some reason (verified with a volt-meter).
419 */
420 chip->uv_per_unit = 45000000/65536;
421 /* Datasheet says 8.1 uV per unit for the current ADC */
422 chip->ua_per_unit = 8100000 / curr_sense_res_uohm;
423
424 /* Use provided internal resistance as start point (in milli-ohm) */
425 chip->intern_res_avg = chip->info->factory_internal_resistance_uohm / 1000;
426 /* Also add it to the internal resistance moving average window */
427 chip->intern_res[0] = chip->intern_res_avg;
428 chip->intern_res_avg_index = 1;
429 chip->intern_res_poll_count = 1;
430
431 mutex_lock(&chip->lock);
432 chip->psy = psy;
433 mutex_unlock(&chip->lock);
434
435 ug3105_init(chip);
436
437 i2c_set_clientdata(client, chip);
438 return 0;
439 }
440
ug3105_suspend(struct device * dev)441 static int __maybe_unused ug3105_suspend(struct device *dev)
442 {
443 struct ug3105_chip *chip = dev_get_drvdata(dev);
444
445 cancel_delayed_work_sync(&chip->work);
446 i2c_smbus_write_byte_data(chip->client, UG3105_REG_MODE,
447 UG3105_MODE_STANDBY);
448
449 return 0;
450 }
451
ug3105_resume(struct device * dev)452 static int __maybe_unused ug3105_resume(struct device *dev)
453 {
454 struct ug3105_chip *chip = dev_get_drvdata(dev);
455
456 ug3105_init(chip);
457
458 return 0;
459 }
460
461 static SIMPLE_DEV_PM_OPS(ug3105_pm_ops, ug3105_suspend,
462 ug3105_resume);
463
464 static const struct i2c_device_id ug3105_id[] = {
465 { "ug3105" },
466 { }
467 };
468 MODULE_DEVICE_TABLE(i2c, ug3105_id);
469
470 static struct i2c_driver ug3105_i2c_driver = {
471 .driver = {
472 .name = "ug3105",
473 .pm = &ug3105_pm_ops,
474 },
475 .probe = ug3105_probe,
476 .id_table = ug3105_id,
477 };
478 module_i2c_driver(ug3105_i2c_driver);
479
480 MODULE_AUTHOR("Hans de Goede <[email protected]");
481 MODULE_DESCRIPTION("uPI uG3105 battery monitor driver");
482 MODULE_LICENSE("GPL");
483