blob: f800b85f0105f56a82ed4c7288836c3dd468a817 [file] [log] [blame]
Ashay Jaiswald7a53152018-07-23 16:12:25 +05301/* Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +05302 *
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#define pr_fmt(fmt) "QCOM-STEPCHG: %s: " fmt, __func__
13
14#include <linux/delay.h>
15#include <linux/module.h>
Fenglin Wudd8f4cb2017-10-17 11:09:46 +080016#include <linux/of.h>
17#include <linux/of_batterydata.h>
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +053018#include <linux/power_supply.h>
19#include <linux/slab.h>
20#include <linux/pmic-voter.h>
21#include "step-chg-jeita.h"
22
23#define MAX_STEP_CHG_ENTRIES 8
24#define STEP_CHG_VOTER "STEP_CHG_VOTER"
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +053025#define JEITA_VOTER "JEITA_VOTER"
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +053026
27#define is_between(left, right, value) \
28 (((left) >= (right) && (left) >= (value) \
29 && (value) >= (right)) \
30 || ((left) <= (right) && (left) <= (value) \
31 && (value) <= (right)))
32
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +053033struct range_data {
34 u32 low_threshold;
35 u32 high_threshold;
36 u32 value;
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +053037};
38
39struct step_chg_cfg {
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +053040 u32 psy_prop;
41 char *prop_name;
42 int hysteresis;
43 struct range_data fcc_cfg[MAX_STEP_CHG_ENTRIES];
44};
45
46struct jeita_fcc_cfg {
47 u32 psy_prop;
48 char *prop_name;
49 int hysteresis;
50 struct range_data fcc_cfg[MAX_STEP_CHG_ENTRIES];
51};
52
53struct jeita_fv_cfg {
54 u32 psy_prop;
55 char *prop_name;
56 int hysteresis;
57 struct range_data fv_cfg[MAX_STEP_CHG_ENTRIES];
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +053058};
59
60struct step_chg_info {
Fenglin Wudd8f4cb2017-10-17 11:09:46 +080061 struct device *dev;
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +053062 ktime_t step_last_update_time;
63 ktime_t jeita_last_update_time;
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +053064 bool step_chg_enable;
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +053065 bool sw_jeita_enable;
Fenglin Wudd8f4cb2017-10-17 11:09:46 +080066 bool config_is_read;
67 bool step_chg_cfg_valid;
68 bool sw_jeita_cfg_valid;
69 bool soc_based_step_chg;
70 bool batt_missing;
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +053071 int jeita_fcc_index;
72 int jeita_fv_index;
73 int step_index;
Fenglin Wudd8f4cb2017-10-17 11:09:46 +080074 int get_config_retry_count;
75
76 struct step_chg_cfg *step_chg_config;
77 struct jeita_fcc_cfg *jeita_fcc_config;
78 struct jeita_fv_cfg *jeita_fv_config;
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +053079
80 struct votable *fcc_votable;
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +053081 struct votable *fv_votable;
Ashay Jaiswald7a53152018-07-23 16:12:25 +053082 struct votable *usb_icl_votable;
jessicatseng240bd292020-04-27 19:09:56 +080083//<2020/04/28-JessicaTseng, Setting jeita fv re-charge voltage for warm temp
84 struct votable *rechg_vol_votable;
85//>2020/04/28-JessicaTseng
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +053086 struct wakeup_source *step_chg_ws;
87 struct power_supply *batt_psy;
Fenglin Wudd8f4cb2017-10-17 11:09:46 +080088 struct power_supply *bms_psy;
Umang Agrawal271536f2018-03-15 12:55:57 +053089 struct power_supply *main_psy;
Ashay Jaiswald7a53152018-07-23 16:12:25 +053090 struct power_supply *usb_psy;
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +053091 struct delayed_work status_change_work;
Fenglin Wudd8f4cb2017-10-17 11:09:46 +080092 struct delayed_work get_config_work;
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +053093 struct notifier_block nb;
94};
95
96static struct step_chg_info *the_chip;
97
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +053098#define STEP_CHG_HYSTERISIS_DELAY_US 5000000 /* 5 secs */
99
Fenglin Wudd8f4cb2017-10-17 11:09:46 +0800100#define BATT_HOT_DECIDEGREE_MAX 600
101#define GET_CONFIG_DELAY_MS 2000
102#define GET_CONFIG_RETRY_COUNT 50
103#define WAIT_BATT_ID_READY_MS 200
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530104
105static bool is_batt_available(struct step_chg_info *chip)
106{
107 if (!chip->batt_psy)
108 chip->batt_psy = power_supply_get_by_name("battery");
109
110 if (!chip->batt_psy)
111 return false;
112
113 return true;
114}
115
Fenglin Wudd8f4cb2017-10-17 11:09:46 +0800116static bool is_bms_available(struct step_chg_info *chip)
117{
118 if (!chip->bms_psy)
119 chip->bms_psy = power_supply_get_by_name("bms");
120
121 if (!chip->bms_psy)
122 return false;
123
124 return true;
125}
126
Ashay Jaiswald7a53152018-07-23 16:12:25 +0530127static bool is_usb_available(struct step_chg_info *chip)
128{
129 if (!chip->usb_psy)
130 chip->usb_psy = power_supply_get_by_name("usb");
131
132 if (!chip->usb_psy)
133 return false;
134
135 return true;
136}
137
Fenglin Wudd8f4cb2017-10-17 11:09:46 +0800138static int read_range_data_from_node(struct device_node *node,
139 const char *prop_str, struct range_data *ranges,
140 u32 max_threshold, u32 max_value)
141{
142 int rc = 0, i, length, per_tuple_length, tuples;
143
144 rc = of_property_count_elems_of_size(node, prop_str, sizeof(u32));
145 if (rc < 0) {
146 pr_err("Count %s failed, rc=%d\n", prop_str, rc);
147 return rc;
148 }
149
150 length = rc;
151 per_tuple_length = sizeof(struct range_data) / sizeof(u32);
152 if (length % per_tuple_length) {
153 pr_err("%s length (%d) should be multiple of %d\n",
154 prop_str, length, per_tuple_length);
155 return -EINVAL;
156 }
157 tuples = length / per_tuple_length;
158
159 if (tuples > MAX_STEP_CHG_ENTRIES) {
160 pr_err("too many entries(%d), only %d allowed\n",
161 tuples, MAX_STEP_CHG_ENTRIES);
162 return -EINVAL;
163 }
164
165 rc = of_property_read_u32_array(node, prop_str,
166 (u32 *)ranges, length);
167 if (rc) {
168 pr_err("Read %s failed, rc=%d", prop_str, rc);
169 return rc;
170 }
171
172 for (i = 0; i < tuples; i++) {
173 if (ranges[i].low_threshold >
174 ranges[i].high_threshold) {
175 pr_err("%s thresholds should be in ascendant ranges\n",
176 prop_str);
177 rc = -EINVAL;
178 goto clean;
179 }
180
181 if (i != 0) {
182 if (ranges[i - 1].high_threshold >
183 ranges[i].low_threshold) {
184 pr_err("%s thresholds should be in ascendant ranges\n",
185 prop_str);
186 rc = -EINVAL;
187 goto clean;
188 }
189 }
190
191 if (ranges[i].low_threshold > max_threshold)
192 ranges[i].low_threshold = max_threshold;
193 if (ranges[i].high_threshold > max_threshold)
194 ranges[i].high_threshold = max_threshold;
195 if (ranges[i].value > max_value)
196 ranges[i].value = max_value;
197 }
198
199 return rc;
200clean:
201 memset(ranges, 0, tuples * sizeof(struct range_data));
202 return rc;
203}
204
205static int get_step_chg_jeita_setting_from_profile(struct step_chg_info *chip)
206{
207 struct device_node *batt_node, *profile_node;
208 u32 max_fv_uv, max_fcc_ma;
209 const char *batt_type_str;
210 const __be32 *handle;
211 int batt_id_ohms, rc;
212 union power_supply_propval prop = {0, };
213
214 handle = of_get_property(chip->dev->of_node,
215 "qcom,battery-data", NULL);
216 if (!handle) {
217 pr_debug("ignore getting sw-jeita/step charging settings from profile\n");
218 return 0;
219 }
220
221 batt_node = of_find_node_by_phandle(be32_to_cpup(handle));
222 if (!batt_node) {
223 pr_err("Get battery data node failed\n");
224 return -EINVAL;
225 }
226
227 if (!is_bms_available(chip))
228 return -ENODEV;
229
230 power_supply_get_property(chip->bms_psy,
231 POWER_SUPPLY_PROP_RESISTANCE_ID, &prop);
232 batt_id_ohms = prop.intval;
233
234 /* bms_psy has not yet read the batt_id */
235 if (batt_id_ohms < 0)
236 return -EBUSY;
237
238 profile_node = of_batterydata_get_best_profile(batt_node,
239 batt_id_ohms / 1000, NULL);
240 if (IS_ERR(profile_node))
241 return PTR_ERR(profile_node);
242
243 if (!profile_node) {
244 pr_err("Couldn't find profile\n");
245 return -ENODATA;
246 }
247
248 rc = of_property_read_string(profile_node, "qcom,battery-type",
249 &batt_type_str);
250 if (rc < 0) {
251 pr_err("battery type unavailable, rc:%d\n", rc);
252 return rc;
253 }
254 pr_debug("battery: %s detected, getting sw-jeita/step charging settings\n",
255 batt_type_str);
256
257 rc = of_property_read_u32(profile_node, "qcom,max-voltage-uv",
258 &max_fv_uv);
259 if (rc < 0) {
260 pr_err("max-voltage_uv reading failed, rc=%d\n", rc);
261 return rc;
262 }
263
264 rc = of_property_read_u32(profile_node, "qcom,fastchg-current-ma",
265 &max_fcc_ma);
266 if (rc < 0) {
267 pr_err("max-fastchg-current-ma reading failed, rc=%d\n", rc);
268 return rc;
269 }
270
271 chip->soc_based_step_chg =
272 of_property_read_bool(profile_node, "qcom,soc-based-step-chg");
273 if (chip->soc_based_step_chg) {
274 chip->step_chg_config->psy_prop = POWER_SUPPLY_PROP_CAPACITY,
275 chip->step_chg_config->prop_name = "SOC";
276 chip->step_chg_config->hysteresis = 0;
277 }
278
279 chip->step_chg_cfg_valid = true;
280 rc = read_range_data_from_node(profile_node,
281 "qcom,step-chg-ranges",
282 chip->step_chg_config->fcc_cfg,
283 chip->soc_based_step_chg ? 100 : max_fv_uv,
284 max_fcc_ma * 1000);
285 if (rc < 0) {
286 pr_debug("Read qcom,step-chg-ranges failed from battery profile, rc=%d\n",
287 rc);
288 chip->step_chg_cfg_valid = false;
289 }
290
291 chip->sw_jeita_cfg_valid = true;
292 rc = read_range_data_from_node(profile_node,
293 "qcom,jeita-fcc-ranges",
294 chip->jeita_fcc_config->fcc_cfg,
295 BATT_HOT_DECIDEGREE_MAX, max_fcc_ma * 1000);
296 if (rc < 0) {
297 pr_debug("Read qcom,jeita-fcc-ranges failed from battery profile, rc=%d\n",
298 rc);
299 chip->sw_jeita_cfg_valid = false;
300 }
301
302 rc = read_range_data_from_node(profile_node,
303 "qcom,jeita-fv-ranges",
304 chip->jeita_fv_config->fv_cfg,
305 BATT_HOT_DECIDEGREE_MAX, max_fv_uv);
306 if (rc < 0) {
307 pr_debug("Read qcom,jeita-fv-ranges failed from battery profile, rc=%d\n",
308 rc);
309 chip->sw_jeita_cfg_valid = false;
310 }
311
312 return rc;
313}
314
315static void get_config_work(struct work_struct *work)
316{
317 struct step_chg_info *chip = container_of(work,
318 struct step_chg_info, get_config_work.work);
319 int i, rc;
320
321 chip->config_is_read = false;
322 rc = get_step_chg_jeita_setting_from_profile(chip);
323
324 if (rc < 0) {
325 if (rc == -ENODEV || rc == -EBUSY) {
326 if (chip->get_config_retry_count++
327 < GET_CONFIG_RETRY_COUNT) {
328 pr_debug("bms_psy is not ready, retry: %d\n",
329 chip->get_config_retry_count);
330 goto reschedule;
331 }
332 }
333 }
334
335 chip->config_is_read = true;
336
337 for (i = 0; i < MAX_STEP_CHG_ENTRIES; i++)
338 pr_debug("step-chg-cfg: %duV(SoC) ~ %duV(SoC), %duA\n",
339 chip->step_chg_config->fcc_cfg[i].low_threshold,
340 chip->step_chg_config->fcc_cfg[i].high_threshold,
341 chip->step_chg_config->fcc_cfg[i].value);
342 for (i = 0; i < MAX_STEP_CHG_ENTRIES; i++)
343 pr_debug("jeita-fcc-cfg: %ddecidegree ~ %ddecidegre, %duA\n",
344 chip->jeita_fcc_config->fcc_cfg[i].low_threshold,
345 chip->jeita_fcc_config->fcc_cfg[i].high_threshold,
346 chip->jeita_fcc_config->fcc_cfg[i].value);
347 for (i = 0; i < MAX_STEP_CHG_ENTRIES; i++)
348 pr_debug("jeita-fv-cfg: %ddecidegree ~ %ddecidegre, %duV\n",
349 chip->jeita_fv_config->fv_cfg[i].low_threshold,
350 chip->jeita_fv_config->fv_cfg[i].high_threshold,
351 chip->jeita_fv_config->fv_cfg[i].value);
352
353 return;
354
355reschedule:
356 schedule_delayed_work(&chip->get_config_work,
357 msecs_to_jiffies(GET_CONFIG_DELAY_MS));
358
359}
360
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530361static int get_val(struct range_data *range, int hysteresis, int current_index,
362 int threshold,
363 int *new_index, int *val)
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530364{
365 int i;
366
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530367 *new_index = -EINVAL;
Guru Das Srinagesh9a57ce12018-06-26 18:08:19 -0700368
369 /*
370 * If the threshold is lesser than the minimum allowed range,
371 * return -ENODATA.
372 */
373 if (threshold < range[0].low_threshold)
374 return -ENODATA;
375
376 /* First try to find the matching index without hysteresis */
377 for (i = 0; i < MAX_STEP_CHG_ENTRIES; i++) {
378 if (!range[i].high_threshold && !range[i].low_threshold) {
379 /* First invalid table entry; exit loop */
380 break;
381 }
382
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530383 if (is_between(range[i].low_threshold,
384 range[i].high_threshold, threshold)) {
385 *new_index = i;
386 *val = range[i].value;
Guru Das Srinagesh9a57ce12018-06-26 18:08:19 -0700387 break;
388 }
389 }
390
391 /*
392 * If nothing was found, the threshold exceeds the max range for sure
393 * as the other case where it is lesser than the min range is handled
394 * at the very beginning of this function. Therefore, clip it to the
395 * max allowed range value, which is the one corresponding to the last
396 * valid entry in the battery profile data array.
397 */
398 if (*new_index == -EINVAL) {
399 if (i == 0) {
400 /* Battery profile data array is completely invalid */
401 return -ENODATA;
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530402 }
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530403
Guru Das Srinagesh9a57ce12018-06-26 18:08:19 -0700404 *new_index = (i - 1);
405 *val = range[*new_index].value;
406 }
407
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530408 /*
409 * If we don't have a current_index return this
410 * newfound value. There is no hysterisis from out of range
411 * to in range transition
412 */
413 if (current_index == -EINVAL)
414 return 0;
415
416 /*
417 * Check for hysteresis if it in the neighbourhood
418 * of our current index.
419 */
420 if (*new_index == current_index + 1) {
421 if (threshold < range[*new_index].low_threshold + hysteresis) {
422 /*
423 * Stay in the current index, threshold is not higher
424 * by hysteresis amount
425 */
426 *new_index = current_index;
427 *val = range[current_index].value;
428 }
429 } else if (*new_index == current_index - 1) {
430 if (threshold > range[*new_index].high_threshold - hysteresis) {
431 /*
432 * stay in the current index, threshold is not lower
433 * by hysteresis amount
434 */
435 *new_index = current_index;
436 *val = range[current_index].value;
437 }
438 }
439 return 0;
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530440}
441
442static int handle_step_chg_config(struct step_chg_info *chip)
443{
444 union power_supply_propval pval = {0, };
445 int rc = 0, fcc_ua = 0;
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530446 u64 elapsed_us;
447
448 elapsed_us = ktime_us_delta(ktime_get(), chip->step_last_update_time);
449 if (elapsed_us < STEP_CHG_HYSTERISIS_DELAY_US)
450 goto reschedule;
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530451
452 rc = power_supply_get_property(chip->batt_psy,
453 POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED, &pval);
454 if (rc < 0)
455 chip->step_chg_enable = 0;
456 else
457 chip->step_chg_enable = pval.intval;
458
Fenglin Wudd8f4cb2017-10-17 11:09:46 +0800459 if (!chip->step_chg_enable || !chip->step_chg_cfg_valid) {
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530460 if (chip->fcc_votable)
461 vote(chip->fcc_votable, STEP_CHG_VOTER, false, 0);
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530462 goto update_time;
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530463 }
464
465 rc = power_supply_get_property(chip->batt_psy,
Fenglin Wudd8f4cb2017-10-17 11:09:46 +0800466 chip->step_chg_config->psy_prop, &pval);
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530467 if (rc < 0) {
468 pr_err("Couldn't read %s property rc=%d\n",
Fenglin Wudd8f4cb2017-10-17 11:09:46 +0800469 chip->step_chg_config->prop_name, rc);
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530470 return rc;
471 }
472
Fenglin Wudd8f4cb2017-10-17 11:09:46 +0800473 rc = get_val(chip->step_chg_config->fcc_cfg,
474 chip->step_chg_config->hysteresis,
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530475 chip->step_index,
476 pval.intval,
477 &chip->step_index,
478 &fcc_ua);
479 if (rc < 0) {
480 /* remove the vote if no step-based fcc is found */
481 if (chip->fcc_votable)
482 vote(chip->fcc_votable, STEP_CHG_VOTER, false, 0);
483 goto update_time;
484 }
485
486 if (!chip->fcc_votable)
487 chip->fcc_votable = find_votable("FCC");
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530488 if (!chip->fcc_votable)
489 return -EINVAL;
490
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530491 vote(chip->fcc_votable, STEP_CHG_VOTER, true, fcc_ua);
492
493 pr_debug("%s = %d Step-FCC = %duA\n",
Fenglin Wudd8f4cb2017-10-17 11:09:46 +0800494 chip->step_chg_config->prop_name, pval.intval, fcc_ua);
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530495
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530496update_time:
497 chip->step_last_update_time = ktime_get();
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530498 return 0;
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530499
500reschedule:
501 /* reschedule 1000uS after the remaining time */
502 return (STEP_CHG_HYSTERISIS_DELAY_US - elapsed_us + 1000);
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530503}
504
jessicatseng18afffd2020-05-08 17:36:49 +0800505//<2020/05/07-JessicaTseng, Modify recharging voltage from 4.05V to 3.9V at battery temperature over 45 degree
506#define JEITA_SUSPEND_HYST_UV 200000//50000
jessicatseng240bd292020-04-27 19:09:56 +0800507//<2020/04/28-JessicaTseng, Setting jeita fv re-charge voltage for warm temp
508#define JEITA_RECHG_HYST_UV 200000//100000
509//>2020/04/28-JessicaTseng
jessicatseng18afffd2020-05-08 17:36:49 +0800510//>2020/05/07-JessicaTseng
jessicatseng240bd292020-04-27 19:09:56 +0800511
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530512static int handle_jeita(struct step_chg_info *chip)
513{
514 union power_supply_propval pval = {0, };
515 int rc = 0, fcc_ua = 0, fv_uv = 0;
516 u64 elapsed_us;
517
Abhijeet Dharmapurikar3a580042017-07-24 09:43:00 -0700518 rc = power_supply_get_property(chip->batt_psy,
519 POWER_SUPPLY_PROP_SW_JEITA_ENABLED, &pval);
520 if (rc < 0)
521 chip->sw_jeita_enable = 0;
522 else
523 chip->sw_jeita_enable = pval.intval;
524
Fenglin Wudd8f4cb2017-10-17 11:09:46 +0800525 if (!chip->sw_jeita_enable || !chip->sw_jeita_cfg_valid) {
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530526 if (chip->fcc_votable)
527 vote(chip->fcc_votable, JEITA_VOTER, false, 0);
528 if (chip->fv_votable)
529 vote(chip->fv_votable, JEITA_VOTER, false, 0);
Ashay Jaiswald7a53152018-07-23 16:12:25 +0530530 if (chip->usb_icl_votable)
531 vote(chip->usb_icl_votable, JEITA_VOTER, false, 0);
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530532 return 0;
533 }
534
535 elapsed_us = ktime_us_delta(ktime_get(), chip->jeita_last_update_time);
536 if (elapsed_us < STEP_CHG_HYSTERISIS_DELAY_US)
537 goto reschedule;
538
539 rc = power_supply_get_property(chip->batt_psy,
Fenglin Wudd8f4cb2017-10-17 11:09:46 +0800540 chip->jeita_fcc_config->psy_prop, &pval);
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530541 if (rc < 0) {
542 pr_err("Couldn't read %s property rc=%d\n",
Fenglin Wudd8f4cb2017-10-17 11:09:46 +0800543 chip->jeita_fcc_config->prop_name, rc);
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530544 return rc;
545 }
546
Fenglin Wudd8f4cb2017-10-17 11:09:46 +0800547 rc = get_val(chip->jeita_fcc_config->fcc_cfg,
548 chip->jeita_fcc_config->hysteresis,
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530549 chip->jeita_fcc_index,
550 pval.intval,
551 &chip->jeita_fcc_index,
552 &fcc_ua);
Ashay Jaiswald7a53152018-07-23 16:12:25 +0530553 if (rc < 0)
554 fcc_ua = 0;
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530555
556 if (!chip->fcc_votable)
557 chip->fcc_votable = find_votable("FCC");
558 if (!chip->fcc_votable)
559 /* changing FCC is a must */
560 return -EINVAL;
561
Ashay Jaiswald7a53152018-07-23 16:12:25 +0530562 vote(chip->fcc_votable, JEITA_VOTER, fcc_ua ? true : false, fcc_ua);
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530563
Fenglin Wudd8f4cb2017-10-17 11:09:46 +0800564 rc = get_val(chip->jeita_fv_config->fv_cfg,
565 chip->jeita_fv_config->hysteresis,
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530566 chip->jeita_fv_index,
567 pval.intval,
568 &chip->jeita_fv_index,
569 &fv_uv);
Ashay Jaiswald7a53152018-07-23 16:12:25 +0530570 if (rc < 0)
571 fv_uv = 0;
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530572
jessicatseng240bd292020-04-27 19:09:56 +0800573//<2020/04/28-JessicaTseng, Setting jeita fv re-charge voltage for warm temp
574 if (!chip->rechg_vol_votable)
575 chip->rechg_vol_votable = find_votable("RECHG_VOL");
576//>2020/04/28-JessicaTseng
577
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530578 chip->fv_votable = find_votable("FV");
579 if (!chip->fv_votable)
580 goto update_time;
581
Ashay Jaiswald7a53152018-07-23 16:12:25 +0530582 if (!chip->usb_icl_votable)
583 chip->usb_icl_votable = find_votable("USB_ICL");
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530584
Ashay Jaiswald7a53152018-07-23 16:12:25 +0530585 if (!chip->usb_icl_votable)
586 goto set_jeita_fv;
587
588 /*
589 * If JEITA float voltage is same as max-vfloat of battery then
590 * skip any further VBAT specific checks.
591 */
592 rc = power_supply_get_property(chip->batt_psy,
593 POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval);
594 if (rc || (pval.intval == fv_uv)) {
595 vote(chip->usb_icl_votable, JEITA_VOTER, false, 0);
596 goto set_jeita_fv;
597 }
598
599 /*
600 * Suspend USB input path if battery voltage is above
601 * JEITA VFLOAT threshold.
602 */
603 if (fv_uv > 0) {
604 rc = power_supply_get_property(chip->batt_psy,
605 POWER_SUPPLY_PROP_VOLTAGE_NOW, &pval);
606 if (!rc && (pval.intval > fv_uv))
607 vote(chip->usb_icl_votable, JEITA_VOTER, true, 0);
608 else if (pval.intval < (fv_uv - JEITA_SUSPEND_HYST_UV))
609 vote(chip->usb_icl_votable, JEITA_VOTER, false, 0);
610 }
611
612set_jeita_fv:
613 vote(chip->fv_votable, JEITA_VOTER, fv_uv ? true : false, fv_uv);
jessicatseng240bd292020-04-27 19:09:56 +0800614//<2020/04/28-JessicaTseng, Setting jeita fv re-charge voltage for warm temp
615 vote(chip->rechg_vol_votable,
616 JEITA_VOTER, true, (fv_uv -JEITA_RECHG_HYST_UV));
617//>2020/04/28-JessicaTseng
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530618
619update_time:
620 chip->jeita_last_update_time = ktime_get();
Umang Agrawal271536f2018-03-15 12:55:57 +0530621
622 if (!chip->main_psy)
623 chip->main_psy = power_supply_get_by_name("main");
624 if (chip->main_psy)
625 power_supply_changed(chip->main_psy);
626
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530627 return 0;
628
629reschedule:
630 /* reschedule 1000uS after the remaining time */
631 return (STEP_CHG_HYSTERISIS_DELAY_US - elapsed_us + 1000);
632}
633
Fenglin Wudd8f4cb2017-10-17 11:09:46 +0800634static int handle_battery_insertion(struct step_chg_info *chip)
635{
636 int rc;
637 union power_supply_propval pval = {0, };
638
639 rc = power_supply_get_property(chip->batt_psy,
640 POWER_SUPPLY_PROP_PRESENT, &pval);
641 if (rc < 0) {
642 pr_err("Get battery present status failed, rc=%d\n", rc);
643 return rc;
644 }
645
646 if (chip->batt_missing != (!pval.intval)) {
647 chip->batt_missing = !pval.intval;
648 pr_debug("battery %s detected\n",
649 chip->batt_missing ? "removal" : "insertion");
650 if (chip->batt_missing) {
651 chip->step_chg_cfg_valid = false;
652 chip->sw_jeita_cfg_valid = false;
653 chip->get_config_retry_count = 0;
654 } else {
655 /*
656 * Get config for the new inserted battery, delay
657 * to make sure BMS has read out the batt_id.
658 */
659 schedule_delayed_work(&chip->get_config_work,
660 msecs_to_jiffies(WAIT_BATT_ID_READY_MS));
661 }
662 }
663
664 return rc;
665}
666
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530667static void status_change_work(struct work_struct *work)
668{
669 struct step_chg_info *chip = container_of(work,
670 struct step_chg_info, status_change_work.work);
671 int rc = 0;
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530672 int reschedule_us;
673 int reschedule_jeita_work_us = 0;
674 int reschedule_step_work_us = 0;
Ashay Jaiswald7a53152018-07-23 16:12:25 +0530675 union power_supply_propval prop = {0, };
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530676
677 if (!is_batt_available(chip))
Ashay Jaiswald7a53152018-07-23 16:12:25 +0530678 goto exit_work;
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530679
Fenglin Wudd8f4cb2017-10-17 11:09:46 +0800680 handle_battery_insertion(chip);
Ashay Jaiswald7a53152018-07-23 16:12:25 +0530681
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530682 /* skip elapsed_us debounce for handling battery temperature */
683 rc = handle_jeita(chip);
684 if (rc > 0)
685 reschedule_jeita_work_us = rc;
686 else if (rc < 0)
687 pr_err("Couldn't handle sw jeita rc = %d\n", rc);
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530688
689 rc = handle_step_chg_config(chip);
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530690 if (rc > 0)
691 reschedule_step_work_us = rc;
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530692 if (rc < 0)
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530693 pr_err("Couldn't handle step rc = %d\n", rc);
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530694
Ashay Jaiswald7a53152018-07-23 16:12:25 +0530695 /* Remove stale votes on USB removal */
696 if (is_usb_available(chip)) {
697 prop.intval = 0;
698 power_supply_get_property(chip->usb_psy,
699 POWER_SUPPLY_PROP_PRESENT, &prop);
700 if (!prop.intval) {
701 if (chip->usb_icl_votable)
702 vote(chip->usb_icl_votable, JEITA_VOTER,
703 false, 0);
704 }
705 }
706
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530707 reschedule_us = min(reschedule_jeita_work_us, reschedule_step_work_us);
708 if (reschedule_us == 0)
Ashay Jaiswald7a53152018-07-23 16:12:25 +0530709 goto exit_work;
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530710 else
711 schedule_delayed_work(&chip->status_change_work,
712 usecs_to_jiffies(reschedule_us));
Ashay Jaiswald7a53152018-07-23 16:12:25 +0530713 return;
714
715exit_work:
716 __pm_relax(chip->step_chg_ws);
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530717}
718
719static int step_chg_notifier_call(struct notifier_block *nb,
720 unsigned long ev, void *v)
721{
722 struct power_supply *psy = v;
723 struct step_chg_info *chip = container_of(nb, struct step_chg_info, nb);
724
725 if (ev != PSY_EVENT_PROP_CHANGED)
726 return NOTIFY_OK;
727
Ashay Jaiswald7a53152018-07-23 16:12:25 +0530728 if ((strcmp(psy->desc->name, "battery") == 0)
729 || (strcmp(psy->desc->name, "usb") == 0)) {
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530730 __pm_stay_awake(chip->step_chg_ws);
731 schedule_delayed_work(&chip->status_change_work, 0);
732 }
733
Fenglin Wudd8f4cb2017-10-17 11:09:46 +0800734 if ((strcmp(psy->desc->name, "bms") == 0)) {
735 if (chip->bms_psy == NULL)
736 chip->bms_psy = psy;
737 if (!chip->config_is_read)
738 schedule_delayed_work(&chip->get_config_work, 0);
739 }
740
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530741 return NOTIFY_OK;
742}
743
744static int step_chg_register_notifier(struct step_chg_info *chip)
745{
746 int rc;
747
748 chip->nb.notifier_call = step_chg_notifier_call;
749 rc = power_supply_reg_notifier(&chip->nb);
750 if (rc < 0) {
751 pr_err("Couldn't register psy notifier rc = %d\n", rc);
752 return rc;
753 }
754
755 return 0;
756}
757
Fenglin Wudd8f4cb2017-10-17 11:09:46 +0800758int qcom_step_chg_init(struct device *dev,
759 bool step_chg_enable, bool sw_jeita_enable)
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530760{
761 int rc;
762 struct step_chg_info *chip;
763
764 if (the_chip) {
765 pr_err("Already initialized\n");
766 return -EINVAL;
767 }
768
Fenglin Wudd8f4cb2017-10-17 11:09:46 +0800769 chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530770 if (!chip)
771 return -ENOMEM;
772
773 chip->step_chg_ws = wakeup_source_register("qcom-step-chg");
Fenglin Wudd8f4cb2017-10-17 11:09:46 +0800774 if (!chip->step_chg_ws)
775 return -EINVAL;
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530776
Fenglin Wudd8f4cb2017-10-17 11:09:46 +0800777 chip->dev = dev;
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530778 chip->step_chg_enable = step_chg_enable;
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530779 chip->sw_jeita_enable = sw_jeita_enable;
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530780 chip->step_index = -EINVAL;
781 chip->jeita_fcc_index = -EINVAL;
782 chip->jeita_fv_index = -EINVAL;
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530783
Fenglin Wudd8f4cb2017-10-17 11:09:46 +0800784 chip->step_chg_config = devm_kzalloc(dev,
785 sizeof(struct step_chg_cfg), GFP_KERNEL);
786 if (!chip->step_chg_config)
787 return -ENOMEM;
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530788
Fenglin Wudd8f4cb2017-10-17 11:09:46 +0800789 chip->step_chg_config->psy_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW;
790 chip->step_chg_config->prop_name = "VBATT";
791 chip->step_chg_config->hysteresis = 100000;
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +0530792
Fenglin Wudd8f4cb2017-10-17 11:09:46 +0800793 chip->jeita_fcc_config = devm_kzalloc(dev,
794 sizeof(struct jeita_fcc_cfg), GFP_KERNEL);
795 chip->jeita_fv_config = devm_kzalloc(dev,
796 sizeof(struct jeita_fv_cfg), GFP_KERNEL);
797 if (!chip->jeita_fcc_config || !chip->jeita_fv_config)
798 return -ENOMEM;
799
800 chip->jeita_fcc_config->psy_prop = POWER_SUPPLY_PROP_TEMP;
801 chip->jeita_fcc_config->prop_name = "BATT_TEMP";
802 chip->jeita_fcc_config->hysteresis = 10;
803 chip->jeita_fv_config->psy_prop = POWER_SUPPLY_PROP_TEMP;
804 chip->jeita_fv_config->prop_name = "BATT_TEMP";
805 chip->jeita_fv_config->hysteresis = 10;
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530806
807 INIT_DELAYED_WORK(&chip->status_change_work, status_change_work);
Fenglin Wudd8f4cb2017-10-17 11:09:46 +0800808 INIT_DELAYED_WORK(&chip->get_config_work, get_config_work);
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530809
810 rc = step_chg_register_notifier(chip);
811 if (rc < 0) {
812 pr_err("Couldn't register psy notifier rc = %d\n", rc);
813 goto release_wakeup_source;
814 }
815
Fenglin Wudd8f4cb2017-10-17 11:09:46 +0800816 schedule_delayed_work(&chip->get_config_work,
817 msecs_to_jiffies(GET_CONFIG_DELAY_MS));
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530818
Fenglin Wudd8f4cb2017-10-17 11:09:46 +0800819 the_chip = chip;
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530820
821 return 0;
822
823release_wakeup_source:
824 wakeup_source_unregister(chip->step_chg_ws);
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530825 return rc;
826}
827
828void qcom_step_chg_deinit(void)
829{
830 struct step_chg_info *chip = the_chip;
831
832 if (!chip)
833 return;
834
835 cancel_delayed_work_sync(&chip->status_change_work);
Fenglin Wudd8f4cb2017-10-17 11:09:46 +0800836 cancel_delayed_work_sync(&chip->get_config_work);
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530837 power_supply_unreg_notifier(&chip->nb);
838 wakeup_source_unregister(chip->step_chg_ws);
839 the_chip = NULL;
Anirudh Ghayalfa10fac2017-07-11 09:17:50 +0530840}