blob: 09c3fc47f0130aab3442ffd159b511a005fa9ac5 [file] [log] [blame]
Subbaraman Narayanamurthy390aa5e2018-01-26 12:49:57 -08001/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#define pr_fmt(fmt) "ALG: %s: " fmt, __func__
14
15#include <linux/err.h>
16#include <linux/kernel.h>
17#include <linux/mutex.h>
18#include <linux/power_supply.h>
Vamshi Krishna B V90792c02018-05-28 22:47:06 +053019#include <linux/slab.h>
20#include <linux/sort.h>
Subbaraman Narayanamurthy390aa5e2018-01-26 12:49:57 -080021#include "fg-alg.h"
22
23#define FULL_SOC_RAW 255
Vamshi Krishna B V342dce52018-05-17 14:37:29 +053024#define FULL_BATT_SOC GENMASK(31, 0)
Subbaraman Narayanamurthy390aa5e2018-01-26 12:49:57 -080025#define CAPACITY_DELTA_DECIPCT 500
26
Vamshi Krishna B V90792c02018-05-28 22:47:06 +053027#define CENTI_ICORRECT_C0 105
28#define CENTI_ICORRECT_C1 20
29
30#define HOURS_TO_SECONDS 3600
31#define OCV_SLOPE_UV 10869
32#define MILLI_UNIT 1000
33#define MICRO_UNIT 1000000
34#define NANO_UNIT 1000000000
35
36#define DEFAULT_TTF_RUN_PERIOD_MS 10000
37#define DEFAULT_TTF_ITERM_DELTA_MA 200
38
39static const struct ttf_pt ttf_ln_table[] = {
40 { 1000, 0 },
41 { 2000, 693 },
42 { 4000, 1386 },
43 { 6000, 1792 },
44 { 8000, 2079 },
45 { 16000, 2773 },
46 { 32000, 3466 },
47 { 64000, 4159 },
48 { 128000, 4852 },
49};
50
Subbaraman Narayanamurthy390aa5e2018-01-26 12:49:57 -080051/* Cycle counter APIs */
52
53/**
54 * restore_cycle_count -
55 * @counter: Cycle counter object
56 *
57 * Restores all the counters back from FG/QG during boot
58 *
59 */
60int restore_cycle_count(struct cycle_counter *counter)
61{
62 int rc = 0;
63
64 if (!counter)
65 return -ENODEV;
66
67 mutex_lock(&counter->lock);
68 rc = counter->restore_count(counter->data, counter->count,
69 BUCKET_COUNT);
70 if (rc < 0)
71 pr_err("failed to restore cycle counter rc=%d\n", rc);
72 mutex_unlock(&counter->lock);
73
74 return rc;
75}
76
77/**
78 * clear_cycle_count -
79 * @counter: Cycle counter object
80 *
81 * Clears all the counters stored by FG/QG when a battery is inserted
82 * or the profile is re-loaded.
83 *
84 */
85void clear_cycle_count(struct cycle_counter *counter)
86{
87 int rc = 0, i;
88
89 if (!counter)
90 return;
91
92 mutex_lock(&counter->lock);
93 memset(counter->count, 0, sizeof(counter->count));
94 for (i = 0; i < BUCKET_COUNT; i++) {
95 counter->started[i] = false;
96 counter->last_soc[i] = 0;
97 }
98
99 rc = counter->store_count(counter->data, counter->count, 0,
100 BUCKET_COUNT * 2);
101 if (rc < 0)
102 pr_err("failed to clear cycle counter rc=%d\n", rc);
103
104 mutex_unlock(&counter->lock);
105}
106
107/**
108 * store_cycle_count -
109 * @counter: Cycle counter object
110 * @id: Cycle counter bucket id
111 *
112 * Stores the cycle counter for a bucket in FG/QG.
113 *
114 */
115static int store_cycle_count(struct cycle_counter *counter, int id)
116{
117 int rc = 0;
118 u16 cyc_count;
119
120 if (!counter)
121 return -ENODEV;
122
123 if (id < 0 || (id > BUCKET_COUNT - 1)) {
124 pr_err("Invalid id %d\n", id);
125 return -EINVAL;
126 }
127
128 cyc_count = counter->count[id];
129 cyc_count++;
130
131 rc = counter->store_count(counter->data, &cyc_count, id, 2);
132 if (rc < 0) {
133 pr_err("failed to write cycle_count[%d] rc=%d\n",
134 id, rc);
135 return rc;
136 }
137
138 counter->count[id] = cyc_count;
139 pr_debug("Stored count %d in id %d\n", cyc_count, id);
140
141 return rc;
142}
143
144/**
145 * cycle_count_update -
146 * @counter: Cycle counter object
147 * @batt_soc: Battery State of Charge (SOC)
148 * @charge_status: Charging status from power supply
149 * @charge_done: Indicator for charge termination
150 * @input_present: Indicator for input presence
151 *
152 * Called by FG/QG whenever there is a state change (Charging status, SOC)
153 *
154 */
155void cycle_count_update(struct cycle_counter *counter, int batt_soc,
156 int charge_status, bool charge_done, bool input_present)
157{
158 int rc = 0, id, i, soc_thresh;
159
160 if (!counter)
161 return;
162
163 mutex_lock(&counter->lock);
164
165 /* Find out which id the SOC falls in */
166 id = batt_soc / BUCKET_SOC_PCT;
167
168 if (charge_status == POWER_SUPPLY_STATUS_CHARGING) {
169 if (!counter->started[id] && id != counter->last_bucket) {
170 counter->started[id] = true;
171 counter->last_soc[id] = batt_soc;
172 }
173 } else if (charge_done || !input_present) {
174 for (i = 0; i < BUCKET_COUNT; i++) {
175 soc_thresh = counter->last_soc[i] + BUCKET_SOC_PCT / 2;
176 if (counter->started[i] && batt_soc > soc_thresh) {
177 rc = store_cycle_count(counter, i);
178 if (rc < 0)
179 pr_err("Error in storing cycle_ctr rc: %d\n",
180 rc);
181 counter->last_soc[i] = 0;
182 counter->started[i] = false;
183 counter->last_bucket = i;
184 }
185 }
186 }
187
188 pr_debug("batt_soc: %d id: %d chg_status: %d\n", batt_soc, id,
189 charge_status);
190 mutex_unlock(&counter->lock);
191}
192
193/**
Vamshi Krishna B V9ec0ee52018-05-10 18:00:49 +0530194 * get_bucket_cycle_count -
Subbaraman Narayanamurthy390aa5e2018-01-26 12:49:57 -0800195 * @counter: Cycle counter object
196 *
197 * Returns the cycle counter for a SOC bucket.
198 *
199 */
Vamshi Krishna B V9ec0ee52018-05-10 18:00:49 +0530200static int get_bucket_cycle_count(struct cycle_counter *counter)
Subbaraman Narayanamurthy390aa5e2018-01-26 12:49:57 -0800201{
202 int count;
203
204 if (!counter)
205 return 0;
206
207 if ((counter->id <= 0) || (counter->id > BUCKET_COUNT))
208 return -EINVAL;
209
210 mutex_lock(&counter->lock);
211 count = counter->count[counter->id - 1];
212 mutex_unlock(&counter->lock);
213 return count;
214}
215
216/**
Vamshi Krishna B V9ec0ee52018-05-10 18:00:49 +0530217 * get_cycle_counts -
218 * @counter: Cycle counter object
219 * @buf: Bucket cycle counts formatted in a string returned to the caller
220 *
221 * Get cycle count for all buckets in a string format
222 */
223int get_cycle_counts(struct cycle_counter *counter, const char **buf)
224{
225 int i, rc, len = 0;
226
227 for (i = 1; i <= BUCKET_COUNT; i++) {
228 counter->id = i;
229 rc = get_bucket_cycle_count(counter);
230 if (rc < 0) {
231 pr_err("Couldn't get cycle count rc=%d\n", rc);
232 return rc;
233 }
234
235 if (sizeof(counter->str_buf) - len < 8) {
236 pr_err("Invalid length %d\n", len);
237 return -EINVAL;
238 }
239
240 len += snprintf(counter->str_buf+len, 8, "%d ", rc);
241 }
242
243 counter->str_buf[len] = '\0';
244 *buf = counter->str_buf;
245 return 0;
246}
247
248/**
249 * get_cycle_count -
250 * @counter: Cycle counter object
251 * @count: Average cycle count returned to the caller
252 *
253 * Get average cycle count for all buckets
254 */
255int get_cycle_count(struct cycle_counter *counter, int *count)
256{
257 int i, rc, temp = 0;
258
259 for (i = 1; i <= BUCKET_COUNT; i++) {
260 counter->id = i;
261 rc = get_bucket_cycle_count(counter);
262 if (rc < 0) {
263 pr_err("Couldn't get cycle count rc=%d\n", rc);
264 return rc;
265 }
266
267 temp += rc;
268 }
269
270 /*
271 * Normalize the counter across each bucket so that we can get
272 * the overall charge cycle count.
273 */
274 *count = temp / BUCKET_COUNT;
275 return 0;
276}
277
278/**
Subbaraman Narayanamurthy390aa5e2018-01-26 12:49:57 -0800279 * cycle_count_init -
280 * @counter: Cycle counter object
281 *
282 * FG/QG have to call this during driver probe to validate the required
283 * parameters after allocating cycle_counter object.
284 *
285 */
286int cycle_count_init(struct cycle_counter *counter)
287{
288 if (!counter)
289 return -ENODEV;
290
291 if (!counter->data || !counter->restore_count ||
292 !counter->store_count) {
293 pr_err("Invalid parameters for using cycle counter\n");
294 return -EINVAL;
295 }
296
297 mutex_init(&counter->lock);
298 counter->last_bucket = -1;
299 return 0;
300}
301
302/* Capacity learning algorithm APIs */
303
304/**
305 * cap_learning_post_process -
306 * @cl: Capacity learning object
307 *
308 * Does post processing on the learnt capacity based on the user specified
309 * or default parameters for the capacity learning algorithm.
310 *
311 */
312static void cap_learning_post_process(struct cap_learning *cl)
313{
314 int64_t max_inc_val, min_dec_val, old_cap;
315 int rc;
316
317 if (cl->dt.skew_decipct) {
318 pr_debug("applying skew %d on current learnt capacity %lld\n",
319 cl->dt.skew_decipct, cl->final_cap_uah);
320 cl->final_cap_uah = cl->final_cap_uah *
321 (1000 + cl->dt.skew_decipct);
322 cl->final_cap_uah = div64_u64(cl->final_cap_uah, 1000);
323 }
324
325 max_inc_val = cl->learned_cap_uah * (1000 + cl->dt.max_cap_inc);
326 max_inc_val = div64_u64(max_inc_val, 1000);
327
328 min_dec_val = cl->learned_cap_uah * (1000 - cl->dt.max_cap_dec);
329 min_dec_val = div64_u64(min_dec_val, 1000);
330
331 old_cap = cl->learned_cap_uah;
332 if (cl->final_cap_uah > max_inc_val)
333 cl->learned_cap_uah = max_inc_val;
334 else if (cl->final_cap_uah < min_dec_val)
335 cl->learned_cap_uah = min_dec_val;
336 else
337 cl->learned_cap_uah = cl->final_cap_uah;
338
339 if (cl->dt.max_cap_limit) {
340 max_inc_val = (int64_t)cl->nom_cap_uah * (1000 +
341 cl->dt.max_cap_limit);
342 max_inc_val = div64_u64(max_inc_val, 1000);
343 if (cl->final_cap_uah > max_inc_val) {
344 pr_debug("learning capacity %lld goes above max limit %lld\n",
345 cl->final_cap_uah, max_inc_val);
346 cl->learned_cap_uah = max_inc_val;
347 }
348 }
349
350 if (cl->dt.min_cap_limit) {
351 min_dec_val = (int64_t)cl->nom_cap_uah * (1000 -
352 cl->dt.min_cap_limit);
353 min_dec_val = div64_u64(min_dec_val, 1000);
354 if (cl->final_cap_uah < min_dec_val) {
355 pr_debug("learning capacity %lld goes below min limit %lld\n",
356 cl->final_cap_uah, min_dec_val);
357 cl->learned_cap_uah = min_dec_val;
358 }
359 }
360
361 if (cl->store_learned_capacity) {
362 rc = cl->store_learned_capacity(cl->data, cl->learned_cap_uah);
363 if (rc < 0)
364 pr_err("Error in storing learned_cap_uah, rc=%d\n", rc);
365 }
366
367 pr_debug("final cap_uah = %lld, learned capacity %lld -> %lld uah\n",
368 cl->final_cap_uah, old_cap, cl->learned_cap_uah);
369}
370
371/**
372 * cap_learning_process_full_data -
373 * @cl: Capacity learning object
374 *
375 * Processes the coulomb counter during charge termination and calculates the
376 * delta w.r.to the coulomb counter obtained earlier when the learning begun.
377 *
378 */
379static int cap_learning_process_full_data(struct cap_learning *cl)
380{
Vamshi Krishna B V342dce52018-05-17 14:37:29 +0530381 int rc, cc_soc_sw, cc_soc_delta_centi_pct;
Subbaraman Narayanamurthy390aa5e2018-01-26 12:49:57 -0800382 int64_t delta_cap_uah;
383
384 rc = cl->get_cc_soc(cl->data, &cc_soc_sw);
385 if (rc < 0) {
386 pr_err("Error in getting CC_SOC_SW, rc=%d\n", rc);
387 return rc;
388 }
389
Vamshi Krishna B V342dce52018-05-17 14:37:29 +0530390 cc_soc_delta_centi_pct =
391 div64_s64((int64_t)(cc_soc_sw - cl->init_cc_soc_sw) * 10000,
Subbaraman Narayanamurthy390aa5e2018-01-26 12:49:57 -0800392 cl->cc_soc_max);
393
394 /* If the delta is < 50%, then skip processing full data */
Vamshi Krishna B V342dce52018-05-17 14:37:29 +0530395 if (cc_soc_delta_centi_pct < 5000) {
396 pr_err("cc_soc_delta_centi_pct: %d\n", cc_soc_delta_centi_pct);
Subbaraman Narayanamurthy390aa5e2018-01-26 12:49:57 -0800397 return -ERANGE;
398 }
399
Vamshi Krishna B V342dce52018-05-17 14:37:29 +0530400 delta_cap_uah = div64_s64(cl->learned_cap_uah * cc_soc_delta_centi_pct,
401 10000);
Subbaraman Narayanamurthy390aa5e2018-01-26 12:49:57 -0800402 cl->final_cap_uah = cl->init_cap_uah + delta_cap_uah;
Vamshi Krishna B V342dce52018-05-17 14:37:29 +0530403 pr_debug("Current cc_soc=%d cc_soc_delta_centi_pct=%d total_cap_uah=%lld\n",
404 cc_soc_sw, cc_soc_delta_centi_pct, cl->final_cap_uah);
Subbaraman Narayanamurthy390aa5e2018-01-26 12:49:57 -0800405 return 0;
406}
407
408/**
409 * cap_learning_begin -
410 * @cl: Capacity learning object
411 * @batt_soc: Battery State of Charge (SOC)
412 *
413 * Gets the coulomb counter from FG/QG when the conditions are suitable for
414 * beginning capacity learning. Also, primes the coulomb counter based on
415 * battery SOC if required.
416 *
417 */
418static int cap_learning_begin(struct cap_learning *cl, u32 batt_soc)
419{
Vamshi Krishna B Vde193402018-04-27 12:14:50 +0530420 int rc, cc_soc_sw, batt_soc_msb, batt_soc_pct;
Subbaraman Narayanamurthy390aa5e2018-01-26 12:49:57 -0800421
422 batt_soc_msb = batt_soc >> 24;
Vamshi Krishna B Vde193402018-04-27 12:14:50 +0530423 batt_soc_pct = DIV_ROUND_CLOSEST(batt_soc_msb * 100, FULL_SOC_RAW);
424
425 if (batt_soc_pct > cl->dt.max_start_soc ||
426 batt_soc_pct < cl->dt.min_start_soc) {
427 pr_debug("Battery SOC %d is high/low, not starting\n",
428 batt_soc_pct);
Subbaraman Narayanamurthy390aa5e2018-01-26 12:49:57 -0800429 return -EINVAL;
430 }
431
Vamshi Krishna B V342dce52018-05-17 14:37:29 +0530432 cl->init_cap_uah = div64_s64(cl->learned_cap_uah * batt_soc,
433 FULL_BATT_SOC);
Subbaraman Narayanamurthy390aa5e2018-01-26 12:49:57 -0800434
435 if (cl->prime_cc_soc) {
436 /*
437 * Prime cc_soc_sw with battery SOC when capacity learning
438 * begins.
439 */
440 rc = cl->prime_cc_soc(cl->data, batt_soc);
441 if (rc < 0) {
442 pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
443 goto out;
444 }
445 }
446
447 rc = cl->get_cc_soc(cl->data, &cc_soc_sw);
448 if (rc < 0) {
449 pr_err("Error in getting CC_SOC_SW, rc=%d\n", rc);
450 goto out;
451 }
452
453 cl->init_cc_soc_sw = cc_soc_sw;
454 pr_debug("Capacity learning started @ battery SOC %d init_cc_soc_sw:%d\n",
455 batt_soc_msb, cl->init_cc_soc_sw);
456out:
457 return rc;
458}
459
460/**
461 * cap_learning_done -
462 * @cl: Capacity learning object
463 *
464 * Top level function for getting coulomb counter and post processing the
465 * data once the capacity learning is complete after charge termination.
466 *
467 */
468static int cap_learning_done(struct cap_learning *cl)
469{
470 int rc;
471
472 rc = cap_learning_process_full_data(cl);
473 if (rc < 0) {
474 pr_err("Error in processing cap learning full data, rc=%d\n",
475 rc);
476 goto out;
477 }
478
479 if (cl->prime_cc_soc) {
480 /* Write a FULL value to cc_soc_sw */
481 rc = cl->prime_cc_soc(cl->data, cl->cc_soc_max);
482 if (rc < 0) {
483 pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
484 goto out;
485 }
486 }
487
488 cap_learning_post_process(cl);
489out:
490 return rc;
491}
492
493/**
494 * cap_learning_update -
495 * @cl: Capacity learning object
496 * @batt_temp - Battery temperature
497 * @batt_soc: Battery State of Charge (SOC)
498 * @charge_status: Charging status from power supply
499 * @charge_done: Indicator for charge termination
500 * @input_present: Indicator for input presence
501 * @qnovo_en: Indicator for Qnovo enable status
502 *
503 * Called by FG/QG driver when there is a state change (Charging status, SOC)
504 *
505 */
506void cap_learning_update(struct cap_learning *cl, int batt_temp,
507 int batt_soc, int charge_status, bool charge_done,
508 bool input_present, bool qnovo_en)
509{
510 int rc, batt_soc_msb, batt_soc_prime;
511 bool prime_cc = false;
512
513 if (!cl)
514 return;
515
516 mutex_lock(&cl->lock);
517
518 if (batt_temp > cl->dt.max_temp || batt_temp < cl->dt.min_temp ||
519 !cl->learned_cap_uah) {
520 cl->active = false;
521 cl->init_cap_uah = 0;
522 goto out;
523 }
524
525 batt_soc_msb = (u32)batt_soc >> 24;
526 pr_debug("Charge_status: %d active: %d batt_soc: %d\n",
527 charge_status, cl->active, batt_soc_msb);
528
529 /* Initialize the starting point of learning capacity */
530 if (!cl->active) {
531 if (charge_status == POWER_SUPPLY_STATUS_CHARGING) {
532 rc = cap_learning_begin(cl, batt_soc);
533 cl->active = (rc == 0);
534 } else {
535 if (charge_status == POWER_SUPPLY_STATUS_DISCHARGING ||
536 charge_done)
537 prime_cc = true;
538 }
539 } else {
540 if (charge_done) {
541 rc = cap_learning_done(cl);
542 if (rc < 0)
543 pr_err("Error in completing capacity learning, rc=%d\n",
544 rc);
545
546 cl->active = false;
547 cl->init_cap_uah = 0;
548 }
549
550 if (charge_status == POWER_SUPPLY_STATUS_DISCHARGING) {
551 if (!input_present) {
552 pr_debug("Capacity learning aborted @ battery SOC %d\n",
553 batt_soc_msb);
554 cl->active = false;
555 cl->init_cap_uah = 0;
556 prime_cc = true;
557 }
558 }
559
560 if (charge_status == POWER_SUPPLY_STATUS_NOT_CHARGING) {
561 if (qnovo_en && input_present) {
562 /*
563 * Don't abort the capacity learning when qnovo
564 * is enabled and input is present where the
565 * charging status can go to "not charging"
566 * intermittently.
567 */
568 } else {
569 pr_debug("Capacity learning aborted @ battery SOC %d\n",
570 batt_soc_msb);
571 cl->active = false;
572 cl->init_cap_uah = 0;
573 prime_cc = true;
574 }
575 }
576 }
577
578 /*
579 * Prime CC_SOC_SW when the device is not charging or during charge
580 * termination when the capacity learning is not active.
581 */
582
583 if (prime_cc && cl->prime_cc_soc) {
584 if (charge_done)
585 batt_soc_prime = cl->cc_soc_max;
586 else
587 batt_soc_prime = batt_soc;
588
589 rc = cl->prime_cc_soc(cl->data, batt_soc_prime);
590 if (rc < 0)
591 pr_err("Error in writing cc_soc_sw, rc=%d\n",
592 rc);
593 }
594
595out:
596 mutex_unlock(&cl->lock);
597}
598
599/**
600 * cap_learning_abort -
601 * @cl: Capacity learning object
602 *
603 * Aborts the capacity learning and initializes variables
604 *
605 */
606void cap_learning_abort(struct cap_learning *cl)
607{
608 if (!cl)
609 return;
610
611 mutex_lock(&cl->lock);
612 pr_debug("Aborting cap_learning\n");
613 cl->active = false;
614 cl->init_cap_uah = 0;
615 mutex_lock(&cl->lock);
616}
617
618/**
619 * cap_learning_post_profile_init -
620 * @cl: Capacity learning object
621 * @nom_cap_uah: Nominal capacity of battery in uAh
622 *
623 * Called by FG/QG once the profile load is complete and nominal capacity
624 * of battery is known. This also gets the last learned capacity back from
625 * FG/QG to feed back to the algorithm.
626 *
627 */
628int cap_learning_post_profile_init(struct cap_learning *cl, int64_t nom_cap_uah)
629{
630 int64_t delta_cap_uah, pct_nom_cap_uah;
631 int rc;
632
633 if (!cl || !cl->data)
634 return -EINVAL;
635
636 mutex_lock(&cl->lock);
637 cl->nom_cap_uah = nom_cap_uah;
638 rc = cl->get_learned_capacity(cl->data, &cl->learned_cap_uah);
639 if (rc < 0) {
640 pr_err("Couldn't get learned capacity, rc=%d\n", rc);
641 goto out;
642 }
643
644 if (cl->learned_cap_uah != cl->nom_cap_uah) {
645 if (cl->learned_cap_uah == 0)
646 cl->learned_cap_uah = cl->nom_cap_uah;
647
648 delta_cap_uah = abs(cl->learned_cap_uah - cl->nom_cap_uah);
649 pct_nom_cap_uah = div64_s64((int64_t)cl->nom_cap_uah *
650 CAPACITY_DELTA_DECIPCT, 1000);
651 /*
652 * If the learned capacity is out of range by 50% from the
653 * nominal capacity, then overwrite the learned capacity with
654 * the nominal capacity.
655 */
656 if (cl->nom_cap_uah && delta_cap_uah > pct_nom_cap_uah) {
657 pr_debug("learned_cap_uah: %lld is higher than expected, capping it to nominal: %lld\n",
658 cl->learned_cap_uah, cl->nom_cap_uah);
659 cl->learned_cap_uah = cl->nom_cap_uah;
660 }
661
662 rc = cl->store_learned_capacity(cl->data, cl->learned_cap_uah);
663 if (rc < 0)
664 pr_err("Error in storing learned_cap_uah, rc=%d\n", rc);
665 }
666
667out:
668 mutex_unlock(&cl->lock);
669 return rc;
670}
671
672/**
673 * cap_learning_init -
674 * @cl: Capacity learning object
675 *
676 * FG/QG have to call this during driver probe to validate the required
677 * parameters after allocating cap_learning object.
678 *
679 */
680int cap_learning_init(struct cap_learning *cl)
681{
682 if (!cl)
683 return -ENODEV;
684
685 if (!cl->get_learned_capacity || !cl->store_learned_capacity ||
686 !cl->get_cc_soc) {
687 pr_err("Insufficient functions for supporting capacity learning\n");
688 return -EINVAL;
689 }
690
691 if (!cl->cc_soc_max) {
692 pr_err("Insufficient parameters for supporting capacity learning\n");
693 return -EINVAL;
694 }
695
696 mutex_init(&cl->lock);
697 return 0;
698}
Vamshi Krishna B V90792c02018-05-28 22:47:06 +0530699
700/* Time to full/empty algorithm helper functions */
701
702static void ttf_circ_buf_add(struct ttf_circ_buf *buf, int val)
703{
704 buf->arr[buf->head] = val;
705 buf->head = (buf->head + 1) % ARRAY_SIZE(buf->arr);
706 buf->size = min(++buf->size, (int)ARRAY_SIZE(buf->arr));
707}
708
709static void ttf_circ_buf_clr(struct ttf_circ_buf *buf)
710{
711 buf->size = 0;
712 buf->head = 0;
713 memset(buf->arr, 0, sizeof(buf->arr));
714}
715
716static int cmp_int(const void *a, const void *b)
717{
718 return *(int *)a - *(int *)b;
719}
720
721static int ttf_circ_buf_median(struct ttf_circ_buf *buf, int *median)
722{
723 int *temp;
724
725 if (buf->size == 0)
726 return -ENODATA;
727
728 if (buf->size == 1) {
729 *median = buf->arr[0];
730 return 0;
731 }
732
733 temp = kmalloc_array(buf->size, sizeof(*temp), GFP_KERNEL);
734 if (!temp)
735 return -ENOMEM;
736
737 memcpy(temp, buf->arr, buf->size * sizeof(*temp));
738 sort(temp, buf->size, sizeof(*temp), cmp_int, NULL);
739
740 if (buf->size % 2)
741 *median = temp[buf->size / 2];
742 else
743 *median = (temp[buf->size / 2 - 1] + temp[buf->size / 2]) / 2;
744
745 kfree(temp);
746 return 0;
747}
748
749static int ttf_lerp(const struct ttf_pt *pts, size_t tablesize,
750 s32 input, s32 *output)
751{
752 int i;
753 s64 temp;
754
755 if (pts == NULL) {
756 pr_err("Table is NULL\n");
757 return -EINVAL;
758 }
759
760 if (tablesize < 1) {
761 pr_err("Table has no entries\n");
762 return -ENOENT;
763 }
764
765 if (tablesize == 1) {
766 *output = pts[0].y;
767 return 0;
768 }
769
770 if (pts[0].x > pts[1].x) {
771 pr_err("Table is not in acending order\n");
772 return -EINVAL;
773 }
774
775 if (input <= pts[0].x) {
776 *output = pts[0].y;
777 return 0;
778 }
779
780 if (input >= pts[tablesize - 1].x) {
781 *output = pts[tablesize - 1].y;
782 return 0;
783 }
784
785 for (i = 1; i < tablesize; i++) {
786 if (input >= pts[i].x)
787 continue;
788
789 temp = ((s64)pts[i].y - pts[i - 1].y) *
790 ((s64)input - pts[i - 1].x);
791 temp = div_s64(temp, pts[i].x - pts[i - 1].x);
792 *output = temp + pts[i - 1].y;
793 return 0;
794 }
795
796 return -EINVAL;
797}
798
799static int get_time_to_full_locked(struct ttf *ttf, int *val)
800{
801 int rc, ibatt_avg, vbatt_avg, rbatt = 0, msoc = 0, act_cap_mah = 0,
802 i_cc2cv = 0, soc_cc2cv, tau, divisor, iterm = 0, ttf_mode = 0,
803 i, soc_per_step, msoc_this_step, msoc_next_step,
804 ibatt_this_step, t_predicted_this_step, ttf_slope,
805 t_predicted_cv, t_predicted = 0, charge_type = 0,
Anirudh Ghayal72c43f42018-06-25 16:16:41 +0530806 float_volt_uv = 0, valid = 0, charge_status = 0;
Vamshi Krishna B V90792c02018-05-28 22:47:06 +0530807 s64 delta_ms;
808
Anirudh Ghayal72c43f42018-06-25 16:16:41 +0530809 rc = ttf->get_ttf_param(ttf->data, TTF_VALID, &valid);
810 if (rc < 0) {
811 pr_err("failed to get ttf_valid rc=%d\n", rc);
812 return rc;
813 }
814
815 if (!valid) {
816 *val = -EINVAL;
817 return 0;
818 }
819
820 rc = ttf->get_ttf_param(ttf->data, TTF_CHG_STATUS, &charge_status);
821 if (rc < 0) {
822 pr_err("failed to get charge-status rc=%d\n", rc);
823 return rc;
824 }
825
826 if (charge_status != POWER_SUPPLY_STATUS_CHARGING) {
827 *val = -EINVAL;
828 return 0;
829 }
830
Vamshi Krishna B V90792c02018-05-28 22:47:06 +0530831 rc = ttf->get_ttf_param(ttf->data, TTF_MSOC, &msoc);
832 if (rc < 0) {
833 pr_err("failed to get msoc rc=%d\n", rc);
834 return rc;
835 }
836 pr_debug("TTF: msoc=%d\n", msoc);
837
838 /* the battery is considered full if the SOC is 100% */
839 if (msoc >= 100) {
840 *val = 0;
841 return 0;
842 }
843
844 rc = ttf->get_ttf_param(ttf->data, TTF_MODE, &ttf_mode);
845
846 /* when switching TTF algorithms the TTF needs to be reset */
847 if (ttf->mode != ttf_mode) {
848 ttf_circ_buf_clr(&ttf->ibatt);
849 ttf_circ_buf_clr(&ttf->vbatt);
850 ttf->last_ttf = 0;
851 ttf->last_ms = 0;
852 ttf->mode = ttf_mode;
853 }
854
855 /* at least 10 samples are required to produce a stable IBATT */
856 if (ttf->ibatt.size < MAX_TTF_SAMPLES) {
857 *val = -1;
858 return 0;
859 }
860
861 rc = ttf_circ_buf_median(&ttf->ibatt, &ibatt_avg);
862 if (rc < 0) {
863 pr_err("failed to get IBATT AVG rc=%d\n", rc);
864 return rc;
865 }
866
867 rc = ttf_circ_buf_median(&ttf->vbatt, &vbatt_avg);
868 if (rc < 0) {
869 pr_err("failed to get VBATT AVG rc=%d\n", rc);
870 return rc;
871 }
872
873 ibatt_avg = -ibatt_avg / MILLI_UNIT;
874 vbatt_avg /= MILLI_UNIT;
875
876 rc = ttf->get_ttf_param(ttf->data, TTF_ITERM, &iterm);
877 if (rc < 0) {
878 pr_err("failed to get iterm rc=%d\n", rc);
879 return rc;
880 }
881 /* clamp ibatt_avg to iterm */
882 if (ibatt_avg < abs(iterm))
883 ibatt_avg = abs(iterm);
884
885 rc = ttf->get_ttf_param(ttf->data, TTF_RBATT, &rbatt);
886 if (rc < 0) {
887 pr_err("failed to get battery resistance rc=%d\n", rc);
888 return rc;
889 }
890 rbatt /= MILLI_UNIT;
891
892 rc = ttf->get_ttf_param(ttf->data, TTF_FCC, &act_cap_mah);
893 if (rc < 0) {
894 pr_err("failed to get ACT_BATT_CAP rc=%d\n", rc);
895 return rc;
896 }
897
898 pr_debug(" TTF: ibatt_avg=%d vbatt_avg=%d rbatt=%d act_cap_mah=%d\n",
899 ibatt_avg, vbatt_avg, rbatt, act_cap_mah);
900
901 rc = ttf->get_ttf_param(ttf->data, TTF_VFLOAT, &float_volt_uv);
902 if (rc < 0) {
903 pr_err("failed to get float_volt_uv rc=%d\n", rc);
904 return rc;
905 }
906
907 rc = ttf->get_ttf_param(ttf->data, TTF_CHG_TYPE, &charge_type);
908 if (rc < 0) {
909 pr_err("failed to get charge_type rc=%d\n", rc);
910 return rc;
911 }
912 /* estimated battery current at the CC to CV transition */
913 switch (ttf->mode) {
914 case TTF_MODE_NORMAL:
915 i_cc2cv = ibatt_avg * vbatt_avg /
916 max(MILLI_UNIT, float_volt_uv / MILLI_UNIT);
917 break;
918 case TTF_MODE_QNOVO:
919 i_cc2cv = min(
920 ttf->cc_step.arr[MAX_CC_STEPS - 1] / MILLI_UNIT,
921 ibatt_avg * vbatt_avg /
922 max(MILLI_UNIT, float_volt_uv / MILLI_UNIT));
923 break;
924 default:
925 pr_err("TTF mode %d is not supported\n", ttf->mode);
926 break;
927 }
928 pr_debug("TTF: i_cc2cv=%d\n", i_cc2cv);
929
930 /* if we are already in CV state then we can skip estimating CC */
931 if (charge_type == POWER_SUPPLY_CHARGE_TYPE_TAPER)
932 goto cv_estimate;
933
934 /* estimated SOC at the CC to CV transition */
935 soc_cc2cv = DIV_ROUND_CLOSEST(rbatt * i_cc2cv, OCV_SLOPE_UV);
936 soc_cc2cv = 100 - soc_cc2cv;
937 pr_debug("TTF: soc_cc2cv=%d\n", soc_cc2cv);
938
939 switch (ttf->mode) {
940 case TTF_MODE_NORMAL:
941 if (soc_cc2cv - msoc <= 0)
942 goto cv_estimate;
943
944 divisor = max(100, (ibatt_avg + i_cc2cv) / 2 * 100);
945 t_predicted = div_s64((s64)act_cap_mah * (soc_cc2cv - msoc) *
946 HOURS_TO_SECONDS, divisor);
947 break;
948 case TTF_MODE_QNOVO:
949 soc_per_step = 100 / MAX_CC_STEPS;
950 for (i = msoc / soc_per_step; i < MAX_CC_STEPS - 1; ++i) {
951 msoc_next_step = (i + 1) * soc_per_step;
952 if (i == msoc / soc_per_step)
953 msoc_this_step = msoc;
954 else
955 msoc_this_step = i * soc_per_step;
956
957 /* scale ibatt by 85% to account for discharge pulses */
958 ibatt_this_step = min(
959 ttf->cc_step.arr[i] / MILLI_UNIT,
960 ibatt_avg) * 85 / 100;
961 divisor = max(100, ibatt_this_step * 100);
962 t_predicted_this_step = div_s64((s64)act_cap_mah *
963 (msoc_next_step - msoc_this_step) *
964 HOURS_TO_SECONDS, divisor);
965 t_predicted += t_predicted_this_step;
966 pr_debug("TTF: [%d, %d] ma=%d t=%d\n",
967 msoc_this_step, msoc_next_step,
968 ibatt_this_step, t_predicted_this_step);
969 }
970 break;
971 default:
972 pr_err("TTF mode %d is not supported\n", ttf->mode);
973 break;
974 }
975
976cv_estimate:
977 pr_debug("TTF: t_predicted_cc=%d\n", t_predicted);
978
979 iterm = max(100, abs(iterm) + ttf->iterm_delta);
980 pr_debug("TTF: iterm=%d\n", iterm);
981
982 if (charge_type == POWER_SUPPLY_CHARGE_TYPE_TAPER)
983 tau = max(MILLI_UNIT, ibatt_avg * MILLI_UNIT / iterm);
984 else
985 tau = max(MILLI_UNIT, i_cc2cv * MILLI_UNIT / iterm);
986
987 rc = ttf_lerp(ttf_ln_table, ARRAY_SIZE(ttf_ln_table), tau, &tau);
988 if (rc < 0) {
989 pr_err("failed to interpolate tau rc=%d\n", rc);
990 return rc;
991 }
992
993 /* tau is scaled linearly from 95% to 100% SOC */
994 if (msoc >= 95)
995 tau = tau * 2 * (100 - msoc) / 10;
996
997 pr_debug("TTF: tau=%d\n", tau);
998 t_predicted_cv = div_s64((s64)act_cap_mah * rbatt * tau *
999 HOURS_TO_SECONDS, NANO_UNIT);
1000 pr_debug("TTF: t_predicted_cv=%d\n", t_predicted_cv);
1001 t_predicted += t_predicted_cv;
1002
1003 pr_debug("TTF: t_predicted_prefilter=%d\n", t_predicted);
1004 if (ttf->last_ms != 0) {
1005 delta_ms = ktime_ms_delta(ktime_get_boottime(),
1006 ms_to_ktime(ttf->last_ms));
1007 if (delta_ms > 10000) {
1008 ttf_slope = div64_s64(
1009 ((s64)t_predicted - ttf->last_ttf) *
1010 MICRO_UNIT, delta_ms);
1011 if (ttf_slope > -100)
1012 ttf_slope = -100;
1013 else if (ttf_slope < -2000)
1014 ttf_slope = -2000;
1015
1016 t_predicted = div_s64(
1017 (s64)ttf_slope * delta_ms, MICRO_UNIT) +
1018 ttf->last_ttf;
1019 pr_debug("TTF: ttf_slope=%d\n", ttf_slope);
1020 } else {
1021 t_predicted = ttf->last_ttf;
1022 }
1023 }
1024
1025 /* clamp the ttf to 0 */
1026 if (t_predicted < 0)
1027 t_predicted = 0;
1028
1029 pr_debug("TTF: t_predicted_postfilter=%d\n", t_predicted);
1030 *val = t_predicted;
1031 return 0;
1032}
1033
1034/**
1035 * ttf_get_time_to_full -
1036 * @ttf: ttf object
1037 * @val: Average time to full returned to the caller
1038 *
1039 * Get Average time to full the battery based on current soc, rbatt
1040 * battery voltage and charge current etc.
1041 */
1042int ttf_get_time_to_full(struct ttf *ttf, int *val)
1043{
1044 int rc;
1045
1046 mutex_lock(&ttf->lock);
1047 rc = get_time_to_full_locked(ttf, val);
1048 mutex_unlock(&ttf->lock);
1049
1050 return rc;
1051}
1052
1053static void ttf_work(struct work_struct *work)
1054{
1055 struct ttf *ttf = container_of(work,
1056 struct ttf, ttf_work.work);
1057 int rc, ibatt_now, vbatt_now, ttf_now, charge_status;
Vamshi Krishna B V22af4a52018-12-18 15:39:24 +05301058 int valid = 0;
Vamshi Krishna B V90792c02018-05-28 22:47:06 +05301059 ktime_t ktime_now;
1060
1061 mutex_lock(&ttf->lock);
Vamshi Krishna B V22af4a52018-12-18 15:39:24 +05301062 rc = ttf->get_ttf_param(ttf->data, TTF_VALID, &valid);
1063 if (rc < 0) {
1064 pr_err("failed to get ttf_valid rc=%d\n", rc);
1065 goto end_work;
1066 }
1067
1068 if (!valid)
1069 goto end_work;
1070
Vamshi Krishna B V90792c02018-05-28 22:47:06 +05301071 rc = ttf->get_ttf_param(ttf->data, TTF_CHG_STATUS, &charge_status);
1072 if (rc < 0) {
1073 pr_err("failed to get charge_status rc=%d\n", rc);
1074 goto end_work;
1075 }
1076 if (charge_status != POWER_SUPPLY_STATUS_CHARGING &&
1077 charge_status != POWER_SUPPLY_STATUS_DISCHARGING)
1078 goto end_work;
1079
1080 rc = ttf->get_ttf_param(ttf->data, TTF_IBAT, &ibatt_now);
1081 if (rc < 0) {
1082 pr_err("failed to get battery current, rc=%d\n", rc);
1083 goto end_work;
1084 }
1085
1086 rc = ttf->get_ttf_param(ttf->data, TTF_VBAT, &vbatt_now);
1087 if (rc < 0) {
1088 pr_err("failed to get battery voltage, rc=%d\n", rc);
1089 goto end_work;
1090 }
1091
1092 ttf_circ_buf_add(&ttf->ibatt, ibatt_now);
1093 ttf_circ_buf_add(&ttf->vbatt, vbatt_now);
1094
1095 if (charge_status == POWER_SUPPLY_STATUS_CHARGING) {
1096 rc = get_time_to_full_locked(ttf, &ttf_now);
1097 if (rc < 0) {
1098 pr_err("failed to get ttf, rc=%d\n", rc);
1099 goto end_work;
1100 }
1101
1102 /* keep the wake lock and prime the IBATT and VBATT buffers */
1103 if (ttf_now < 0) {
1104 /* delay for one FG cycle */
1105 schedule_delayed_work(&ttf->ttf_work,
1106 msecs_to_jiffies(1000));
1107 mutex_unlock(&ttf->lock);
1108 return;
1109 }
1110
1111 /* update the TTF reference point every minute */
1112 ktime_now = ktime_get_boottime();
1113 if (ktime_ms_delta(ktime_now,
1114 ms_to_ktime(ttf->last_ms)) > 60000 ||
1115 ttf->last_ms == 0) {
1116 ttf->last_ttf = ttf_now;
1117 ttf->last_ms = ktime_to_ms(ktime_now);
1118 }
1119 }
1120
1121 /* recurse every 10 seconds */
1122 schedule_delayed_work(&ttf->ttf_work, msecs_to_jiffies(ttf->period_ms));
1123end_work:
1124 ttf->awake_voter(ttf->data, false);
1125 mutex_unlock(&ttf->lock);
1126}
1127
1128/**
1129 * ttf_get_time_to_empty -
1130 * @ttf: ttf object
1131 * @val: Average time to empty returned to the caller
1132 *
1133 * Get Average time to empty the battery based on current soc
1134 * and average battery current.
1135 */
1136int ttf_get_time_to_empty(struct ttf *ttf, int *val)
1137{
Anirudh Ghayal72c43f42018-06-25 16:16:41 +05301138 int rc, ibatt_avg, msoc, act_cap_mah, divisor, valid = 0,
1139 charge_status = 0;
1140
1141 rc = ttf->get_ttf_param(ttf->data, TTF_VALID, &valid);
1142 if (rc < 0) {
1143 pr_err("failed to get ttf_valid rc=%d\n", rc);
1144 return rc;
1145 }
1146
1147 if (!valid) {
1148 *val = -EINVAL;
1149 return 0;
1150 }
1151
1152 rc = ttf->get_ttf_param(ttf->data, TTF_CHG_STATUS, &charge_status);
1153 if (rc < 0) {
1154 pr_err("failed to get charge-status rc=%d\n", rc);
1155 return rc;
1156 }
1157
1158 if (charge_status == POWER_SUPPLY_STATUS_CHARGING) {
1159 *val = -EINVAL;
1160 return 0;
1161 }
Vamshi Krishna B V90792c02018-05-28 22:47:06 +05301162
1163 rc = ttf_circ_buf_median(&ttf->ibatt, &ibatt_avg);
1164 if (rc < 0) {
1165 /* try to get instantaneous current */
1166 rc = ttf->get_ttf_param(ttf->data, TTF_IBAT, &ibatt_avg);
1167 if (rc < 0) {
1168 pr_err("failed to get battery current, rc=%d\n", rc);
1169 return rc;
1170 }
1171 }
1172
1173 ibatt_avg /= MILLI_UNIT;
1174 /* clamp ibatt_avg to 100mA */
1175 if (ibatt_avg < 100)
1176 ibatt_avg = 100;
1177
1178 rc = ttf->get_ttf_param(ttf->data, TTF_MSOC, &msoc);
1179 if (rc < 0) {
1180 pr_err("Error in getting capacity, rc=%d\n", rc);
1181 return rc;
1182 }
1183
1184 rc = ttf->get_ttf_param(ttf->data, TTF_FCC, &act_cap_mah);
1185 if (rc < 0) {
1186 pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
1187 return rc;
1188 }
1189
1190 divisor = CENTI_ICORRECT_C0 * 100 + CENTI_ICORRECT_C1 * msoc;
1191 divisor = ibatt_avg * divisor / 100;
1192 divisor = max(100, divisor);
1193 *val = act_cap_mah * msoc * HOURS_TO_SECONDS / divisor;
Anirudh Ghayal72c43f42018-06-25 16:16:41 +05301194
1195 pr_debug("TTF: ibatt_avg=%d msoc=%d act_cap_mah=%d TTE=%d\n",
1196 ibatt_avg, msoc, act_cap_mah, *val);
1197
Vamshi Krishna B V90792c02018-05-28 22:47:06 +05301198 return 0;
1199}
1200
1201/**
1202 * ttf_update -
1203 * @ttf: ttf object
1204 * @input_present: Indicator for input presence
1205 *
1206 * Called by FG/QG driver when there is a state change (Charging status, SOC)
1207 *
1208 */
1209void ttf_update(struct ttf *ttf, bool input_present)
1210{
Vamshi Krishna B V22af4a52018-12-18 15:39:24 +05301211 int delay_ms, rc, valid = 0;
1212
1213 rc = ttf->get_ttf_param(ttf->data, TTF_VALID, &valid);
1214 if (rc < 0) {
1215 pr_err("failed to get ttf_valid rc=%d\n", rc);
1216 return;
1217 }
1218
1219 if (!valid)
1220 return;
Vamshi Krishna B V90792c02018-05-28 22:47:06 +05301221
1222 if (ttf->input_present == input_present)
1223 return;
1224
1225 ttf->input_present = input_present;
1226 if (input_present)
1227 /* wait 35 seconds for the input to settle */
1228 delay_ms = 35000;
1229 else
1230 /* wait 5 seconds for current to settle during discharge */
1231 delay_ms = 5000;
1232
1233 ttf->awake_voter(ttf->data, true);
1234 cancel_delayed_work_sync(&ttf->ttf_work);
1235 mutex_lock(&ttf->lock);
1236 ttf_circ_buf_clr(&ttf->ibatt);
1237 ttf_circ_buf_clr(&ttf->vbatt);
1238 ttf->last_ttf = 0;
1239 ttf->last_ms = 0;
1240 mutex_unlock(&ttf->lock);
1241 schedule_delayed_work(&ttf->ttf_work, msecs_to_jiffies(delay_ms));
1242}
1243
1244/**
1245 * ttf_tte_init -
1246 * @ttf: Time to full object
1247 *
1248 * FG/QG have to call this during driver probe to validate the required
1249 * parameters after allocating ttf object.
1250 *
1251 */
1252int ttf_tte_init(struct ttf *ttf)
1253{
1254 if (!ttf)
1255 return -ENODEV;
1256
1257 if (!ttf->awake_voter || !ttf->get_ttf_param) {
1258 pr_err("Insufficient functions for supporting ttf\n");
1259 return -EINVAL;
1260 }
1261
1262 if (!ttf->iterm_delta)
1263 ttf->iterm_delta = DEFAULT_TTF_ITERM_DELTA_MA;
1264 if (!ttf->period_ms)
1265 ttf->period_ms = DEFAULT_TTF_RUN_PERIOD_MS;
1266
1267 mutex_init(&ttf->lock);
1268 INIT_DELAYED_WORK(&ttf->ttf_work, ttf_work);
1269
1270 return 0;
1271}