blob: 6da3c0dbe7936eb5ff68f6f75dff59c2e89db428 [file] [log] [blame]
Harry Yang4b7db0f2017-11-27 10:50:44 -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#include <linux/debugfs.h>
14#include <linux/delay.h>
15#include <linux/device.h>
16#include <linux/module.h>
17#include <linux/platform_device.h>
18#include <linux/regmap.h>
19#include <linux/power_supply.h>
20#include <linux/of.h>
21#include <linux/of_irq.h>
22#include <linux/log2.h>
23#include <linux/qpnp/qpnp-revid.h>
24#include <linux/regulator/driver.h>
25#include <linux/regulator/of_regulator.h>
26#include <linux/regulator/machine.h>
27#include <linux/pmic-voter.h>
Ashay Jaiswal20688262018-04-25 11:45:34 +053028#include <linux/qpnp/qpnp-adc.h>
Harry Yang4b7db0f2017-11-27 10:50:44 -080029#include "smb5-reg.h"
30#include "smb5-lib.h"
Ashay Jaiswal09feab82018-02-12 12:33:18 +053031#include "schgm-flash.h"
Harry Yang4b7db0f2017-11-27 10:50:44 -080032
Ashay Jaiswala9e10912018-02-02 14:03:35 +053033static struct smb_params smb5_pmi632_params = {
34 .fcc = {
35 .name = "fast charge current",
36 .reg = CHGR_FAST_CHARGE_CURRENT_CFG_REG,
37 .min_u = 0,
38 .max_u = 3000000,
39 .step_u = 50000,
40 },
41 .fv = {
42 .name = "float voltage",
43 .reg = CHGR_FLOAT_VOLTAGE_CFG_REG,
44 .min_u = 3600000,
45 .max_u = 4800000,
46 .step_u = 10000,
47 },
48 .usb_icl = {
49 .name = "usb input current limit",
50 .reg = USBIN_CURRENT_LIMIT_CFG_REG,
51 .min_u = 0,
52 .max_u = 3000000,
53 .step_u = 50000,
54 },
Harry Yangf7b89902018-03-13 22:37:53 -070055 .icl_max_stat = {
56 .name = "dcdc icl max status",
57 .reg = ICL_MAX_STATUS_REG,
58 .min_u = 0,
59 .max_u = 3000000,
60 .step_u = 50000,
61 },
Ashay Jaiswala9e10912018-02-02 14:03:35 +053062 .icl_stat = {
63 .name = "input current limit status",
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +053064 .reg = ICL_STATUS_REG,
Ashay Jaiswala9e10912018-02-02 14:03:35 +053065 .min_u = 0,
66 .max_u = 3000000,
67 .step_u = 50000,
68 },
69 .otg_cl = {
70 .name = "usb otg current limit",
71 .reg = DCDC_OTG_CURRENT_LIMIT_CFG_REG,
72 .min_u = 500000,
73 .max_u = 1000000,
74 .step_u = 250000,
75 },
76 .jeita_cc_comp_hot = {
77 .name = "jeita fcc reduction",
78 .reg = JEITA_CCCOMP_CFG_HOT_REG,
79 .min_u = 0,
80 .max_u = 1575000,
81 .step_u = 25000,
82 },
83 .jeita_cc_comp_cold = {
84 .name = "jeita fcc reduction",
85 .reg = JEITA_CCCOMP_CFG_COLD_REG,
86 .min_u = 0,
87 .max_u = 1575000,
88 .step_u = 25000,
89 },
90 .freq_switcher = {
91 .name = "switching frequency",
92 .reg = DCDC_FSW_SEL_REG,
93 .min_u = 600,
94 .max_u = 1200,
95 .step_u = 400,
96 .set_proc = smblib_set_chg_freq,
97 },
Ashay Jaiswale0b3c472018-06-20 23:39:41 +053098 .aicl_5v_threshold = {
99 .name = "AICL 5V threshold",
100 .reg = USBIN_5V_AICL_THRESHOLD_REG,
101 .min_u = 4000,
102 .max_u = 4700,
103 .step_u = 100,
104 },
105 .aicl_cont_threshold = {
106 .name = "AICL CONT threshold",
107 .reg = USBIN_CONT_AICL_THRESHOLD_REG,
108 .min_u = 4000,
109 .max_u = 8800,
110 .step_u = 100,
111 .get_proc = smblib_get_aicl_cont_threshold,
112 .set_proc = smblib_set_aicl_cont_threshold,
113 },
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530114};
115
Harry Yangf7b89902018-03-13 22:37:53 -0700116static struct smb_params smb5_pm855b_params = {
Harry Yang4b7db0f2017-11-27 10:50:44 -0800117 .fcc = {
118 .name = "fast charge current",
119 .reg = CHGR_FAST_CHARGE_CURRENT_CFG_REG,
120 .min_u = 0,
121 .max_u = 8000000,
122 .step_u = 25000,
123 },
124 .fv = {
125 .name = "float voltage",
126 .reg = CHGR_FLOAT_VOLTAGE_CFG_REG,
127 .min_u = 3600000,
128 .max_u = 4790000,
129 .step_u = 10000,
130 },
131 .usb_icl = {
132 .name = "usb input current limit",
133 .reg = USBIN_CURRENT_LIMIT_CFG_REG,
134 .min_u = 0,
135 .max_u = 5000000,
136 .step_u = 50000,
137 },
Harry Yangf7b89902018-03-13 22:37:53 -0700138 .icl_max_stat = {
139 .name = "dcdc icl max status",
140 .reg = ICL_MAX_STATUS_REG,
141 .min_u = 0,
142 .max_u = 5000000,
143 .step_u = 50000,
144 },
Harry Yang4b7db0f2017-11-27 10:50:44 -0800145 .icl_stat = {
Harry Yangf7b89902018-03-13 22:37:53 -0700146 .name = "aicl icl status",
Harry Yang4b7db0f2017-11-27 10:50:44 -0800147 .reg = AICL_ICL_STATUS_REG,
148 .min_u = 0,
149 .max_u = 5000000,
150 .step_u = 50000,
151 },
152 .otg_cl = {
153 .name = "usb otg current limit",
154 .reg = DCDC_OTG_CURRENT_LIMIT_CFG_REG,
155 .min_u = 500000,
156 .max_u = 3000000,
157 .step_u = 500000,
158 },
159 .jeita_cc_comp_hot = {
160 .name = "jeita fcc reduction",
161 .reg = JEITA_CCCOMP_CFG_HOT_REG,
162 .min_u = 0,
163 .max_u = 8000000,
164 .step_u = 25000,
165 .set_proc = NULL,
166 },
167 .jeita_cc_comp_cold = {
168 .name = "jeita fcc reduction",
169 .reg = JEITA_CCCOMP_CFG_COLD_REG,
170 .min_u = 0,
171 .max_u = 8000000,
172 .step_u = 25000,
173 .set_proc = NULL,
174 },
175 .freq_switcher = {
176 .name = "switching frequency",
177 .reg = DCDC_FSW_SEL_REG,
178 .min_u = 1200,
179 .max_u = 2400,
180 .step_u = 400,
181 .set_proc = NULL,
182 },
Ashay Jaiswale0b3c472018-06-20 23:39:41 +0530183 .aicl_5v_threshold = {
184 .name = "AICL 5V threshold",
185 .reg = USBIN_5V_AICL_THRESHOLD_REG,
186 .min_u = 4000,
187 .max_u = 4700,
188 .step_u = 100,
189 },
190 .aicl_cont_threshold = {
191 .name = "AICL CONT threshold",
192 .reg = USBIN_CONT_AICL_THRESHOLD_REG,
193 .min_u = 4000,
194 .max_u = 1180,
195 .step_u = 100,
196 .get_proc = smblib_get_aicl_cont_threshold,
197 .set_proc = smblib_set_aicl_cont_threshold,
198 },
Harry Yang4b7db0f2017-11-27 10:50:44 -0800199};
200
201struct smb_dt_props {
202 int usb_icl_ua;
203 struct device_node *revid_dev_node;
204 enum float_options float_option;
205 int chg_inhibit_thr_mv;
206 bool no_battery;
207 bool hvdcp_disable;
Anirudh Ghayal1380d312018-02-23 00:01:43 +0530208 int auto_recharge_soc;
209 int auto_recharge_vbat_mv;
Harry Yang4b7db0f2017-11-27 10:50:44 -0800210 int wd_bark_time;
211 int batt_profile_fcc_ua;
212 int batt_profile_fv_uv;
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -0700213 int term_current_src;
214 int term_current_thresh_hi_ma;
215 int term_current_thresh_lo_ma;
Harry Yang4b7db0f2017-11-27 10:50:44 -0800216};
217
218struct smb5 {
219 struct smb_charger chg;
220 struct dentry *dfs_root;
221 struct smb_dt_props dt;
222};
223
224static int __debug_mask;
225module_param_named(
226 debug_mask, __debug_mask, int, 0600
227);
228
Harry Yang6afaea22018-03-26 19:11:07 -0700229static int __pd_disabled;
230module_param_named(
231 pd_disabled, __pd_disabled, int, 0600
232);
233
Harry Yang4b7db0f2017-11-27 10:50:44 -0800234static int __weak_chg_icl_ua = 500000;
235module_param_named(
236 weak_chg_icl_ua, __weak_chg_icl_ua, int, 0600
237);
238
Ashay Jaiswal20688262018-04-25 11:45:34 +0530239enum {
240 USBIN_CURRENT,
241 USBIN_VOLTAGE,
242};
243
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +0530244enum {
245 BAT_THERM = 0,
246 MISC_THERM,
247 CONN_THERM,
248 SMB_THERM,
249};
250
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530251#define PMI632_MAX_ICL_UA 3000000
252static int smb5_chg_config_init(struct smb5 *chip)
253{
254 struct smb_charger *chg = &chip->chg;
255 struct pmic_revid_data *pmic_rev_id;
256 struct device_node *revid_dev_node;
257 int rc = 0;
258
259 revid_dev_node = of_parse_phandle(chip->chg.dev->of_node,
260 "qcom,pmic-revid", 0);
261 if (!revid_dev_node) {
262 pr_err("Missing qcom,pmic-revid property\n");
263 return -EINVAL;
264 }
265
266 pmic_rev_id = get_revid_data(revid_dev_node);
267 if (IS_ERR_OR_NULL(pmic_rev_id)) {
268 /*
269 * the revid peripheral must be registered, any failure
270 * here only indicates that the rev-id module has not
271 * probed yet.
272 */
273 rc = -EPROBE_DEFER;
274 goto out;
275 }
276
277 switch (pmic_rev_id->pmic_subtype) {
278 case PM855B_SUBTYPE:
279 chip->chg.smb_version = PM855B_SUBTYPE;
Harry Yangf7b89902018-03-13 22:37:53 -0700280 chg->param = smb5_pm855b_params;
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530281 chg->name = "pm855b_charger";
282 break;
283 case PMI632_SUBTYPE:
284 chip->chg.smb_version = PMI632_SUBTYPE;
Ashay Jaiswal43107092018-08-20 18:59:28 +0530285 chg->wa_flags |= WEAK_ADAPTER_WA | USBIN_OV_WA;
Umang Agrawal461e9ea2018-07-05 18:50:13 +0530286 if (pmic_rev_id->rev4 >= 2)
287 chg->wa_flags |= MOISTURE_PROTECTION_WA;
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530288 chg->param = smb5_pmi632_params;
289 chg->use_extcon = true;
290 chg->name = "pmi632_charger";
Ashay Jaiswalc96380de2018-05-16 12:02:36 +0530291 /* PMI632 does not support PD */
Ashay Jaiswalf2ca7092018-05-22 21:33:15 +0530292 chg->pd_not_supported = true;
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530293 chg->hw_max_icl_ua =
294 (chip->dt.usb_icl_ua > 0) ? chip->dt.usb_icl_ua
295 : PMI632_MAX_ICL_UA;
296 chg->chg_freq.freq_5V = 600;
297 chg->chg_freq.freq_6V_8V = 800;
298 chg->chg_freq.freq_9V = 1050;
299 chg->chg_freq.freq_removal = 1050;
300 chg->chg_freq.freq_below_otg_threshold = 800;
301 chg->chg_freq.freq_above_otg_threshold = 800;
302 break;
303 default:
304 pr_err("PMIC subtype %d not supported\n",
305 pmic_rev_id->pmic_subtype);
306 rc = -EINVAL;
307 }
308
309out:
310 of_node_put(revid_dev_node);
311 return rc;
312}
313
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +0530314#define PULL_NO_PULL 0
315#define PULL_30K 30
316#define PULL_100K 100
317#define PULL_400K 400
318static int get_valid_pullup(int pull_up)
319{
320 int pull;
321
322 /* pull up can only be 0/30K/100K/400K) */
323 switch (pull_up) {
324 case PULL_NO_PULL:
325 pull = INTERNAL_PULL_NO_PULL;
326 break;
327 case PULL_30K:
328 pull = INTERNAL_PULL_30K_PULL;
329 break;
330 case PULL_100K:
331 pull = INTERNAL_PULL_100K_PULL;
332 break;
333 case PULL_400K:
334 pull = INTERNAL_PULL_400K_PULL;
335 break;
336 default:
337 pull = INTERNAL_PULL_100K_PULL;
338 }
339
340 return pull;
341}
342
343#define INTERNAL_PULL_UP_MASK 0x3
344static int smb5_configure_internal_pull(struct smb_charger *chg, int type,
345 int pull)
346{
347 int rc;
348 int shift = type * 2;
349 u8 mask = INTERNAL_PULL_UP_MASK << shift;
350 u8 val = pull << shift;
351
352 rc = smblib_masked_write(chg, BATIF_ADC_INTERNAL_PULL_UP_REG,
353 mask, val);
354 if (rc < 0)
355 dev_err(chg->dev,
356 "Couldn't configure ADC pull-up reg rc=%d\n", rc);
357
358 return rc;
359}
360
Harry Yang4b7db0f2017-11-27 10:50:44 -0800361#define MICRO_1P5A 1500000
Ashay Jaiswalb2b06fe2018-06-07 18:35:21 +0530362#define MICRO_1PA 1000000
Harry Yang4b7db0f2017-11-27 10:50:44 -0800363#define MICRO_P1A 100000
364#define OTG_DEFAULT_DEGLITCH_TIME_MS 50
365#define MIN_WD_BARK_TIME 16
366#define DEFAULT_WD_BARK_TIME 64
367#define BITE_WDOG_TIMEOUT_8S 0x3
368#define BARK_WDOG_TIMEOUT_MASK GENMASK(3, 2)
369#define BARK_WDOG_TIMEOUT_SHIFT 2
370static int smb5_parse_dt(struct smb5 *chip)
371{
372 struct smb_charger *chg = &chip->chg;
373 struct device_node *node = chg->dev->of_node;
374 int rc, byte_len;
375
376 if (!node) {
377 pr_err("device tree node missing\n");
378 return -EINVAL;
379 }
380
381 chg->step_chg_enabled = of_property_read_bool(node,
382 "qcom,step-charging-enable");
383
384 chg->sw_jeita_enabled = of_property_read_bool(node,
385 "qcom,sw-jeita-enable");
386
387 rc = of_property_read_u32(node, "qcom,wd-bark-time-secs",
388 &chip->dt.wd_bark_time);
389 if (rc < 0 || chip->dt.wd_bark_time < MIN_WD_BARK_TIME)
390 chip->dt.wd_bark_time = DEFAULT_WD_BARK_TIME;
391
392 chip->dt.no_battery = of_property_read_bool(node,
393 "qcom,batteryless-platform");
394
395 rc = of_property_read_u32(node,
396 "qcom,fcc-max-ua", &chip->dt.batt_profile_fcc_ua);
397 if (rc < 0)
398 chip->dt.batt_profile_fcc_ua = -EINVAL;
399
400 rc = of_property_read_u32(node,
401 "qcom,fv-max-uv", &chip->dt.batt_profile_fv_uv);
402 if (rc < 0)
403 chip->dt.batt_profile_fv_uv = -EINVAL;
404
405 rc = of_property_read_u32(node,
406 "qcom,usb-icl-ua", &chip->dt.usb_icl_ua);
407 if (rc < 0)
408 chip->dt.usb_icl_ua = -EINVAL;
409
410 rc = of_property_read_u32(node,
411 "qcom,otg-cl-ua", &chg->otg_cl_ua);
412 if (rc < 0)
Ashay Jaiswalb2b06fe2018-06-07 18:35:21 +0530413 chg->otg_cl_ua = (chip->chg.smb_version == PMI632_SUBTYPE) ?
414 MICRO_1PA : MICRO_1P5A;
Harry Yang4b7db0f2017-11-27 10:50:44 -0800415
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -0700416 rc = of_property_read_u32(node, "qcom,chg-term-src",
417 &chip->dt.term_current_src);
418 if (rc < 0)
419 chip->dt.term_current_src = ITERM_SRC_UNSPECIFIED;
420
421 rc = of_property_read_u32(node, "qcom,chg-term-current-ma",
422 &chip->dt.term_current_thresh_hi_ma);
423
424 if (chip->dt.term_current_src == ITERM_SRC_ADC)
425 rc = of_property_read_u32(node, "qcom,chg-term-base-current-ma",
426 &chip->dt.term_current_thresh_lo_ma);
427
Harry Yang4b7db0f2017-11-27 10:50:44 -0800428 if (of_find_property(node, "qcom,thermal-mitigation", &byte_len)) {
429 chg->thermal_mitigation = devm_kzalloc(chg->dev, byte_len,
430 GFP_KERNEL);
431
432 if (chg->thermal_mitigation == NULL)
433 return -ENOMEM;
434
435 chg->thermal_levels = byte_len / sizeof(u32);
436 rc = of_property_read_u32_array(node,
437 "qcom,thermal-mitigation",
438 chg->thermal_mitigation,
439 chg->thermal_levels);
440 if (rc < 0) {
441 dev_err(chg->dev,
442 "Couldn't read threm limits rc = %d\n", rc);
443 return rc;
444 }
445 }
446
447 rc = of_property_read_u32(node, "qcom,float-option",
448 &chip->dt.float_option);
449 if (!rc && (chip->dt.float_option < 0 || chip->dt.float_option > 4)) {
450 pr_err("qcom,float-option is out of range [0, 4]\n");
451 return -EINVAL;
452 }
453
454 chip->dt.hvdcp_disable = of_property_read_bool(node,
455 "qcom,hvdcp-disable");
456
457
458 rc = of_property_read_u32(node, "qcom,chg-inhibit-threshold-mv",
459 &chip->dt.chg_inhibit_thr_mv);
460 if (!rc && (chip->dt.chg_inhibit_thr_mv < 0 ||
461 chip->dt.chg_inhibit_thr_mv > 300)) {
462 pr_err("qcom,chg-inhibit-threshold-mv is incorrect\n");
463 return -EINVAL;
464 }
465
Anirudh Ghayal1380d312018-02-23 00:01:43 +0530466 chip->dt.auto_recharge_soc = -EINVAL;
467 rc = of_property_read_u32(node, "qcom,auto-recharge-soc",
468 &chip->dt.auto_recharge_soc);
469 if (!rc && (chip->dt.auto_recharge_soc < 0 ||
470 chip->dt.auto_recharge_soc > 100)) {
471 pr_err("qcom,auto-recharge-soc is incorrect\n");
472 return -EINVAL;
473 }
474 chg->auto_recharge_soc = chip->dt.auto_recharge_soc;
475
476 chip->dt.auto_recharge_vbat_mv = -EINVAL;
477 rc = of_property_read_u32(node, "qcom,auto-recharge-vbat-mv",
478 &chip->dt.auto_recharge_vbat_mv);
479 if (!rc && (chip->dt.auto_recharge_vbat_mv < 0)) {
480 pr_err("qcom,auto-recharge-vbat-mv is incorrect\n");
481 return -EINVAL;
482 }
Harry Yang4b7db0f2017-11-27 10:50:44 -0800483
Harry Yang4b7db0f2017-11-27 10:50:44 -0800484 chg->dcp_icl_ua = chip->dt.usb_icl_ua;
485
486 chg->suspend_input_on_debug_batt = of_property_read_bool(node,
487 "qcom,suspend-input-on-debug-batt");
488
489 rc = of_property_read_u32(node, "qcom,otg-deglitch-time-ms",
490 &chg->otg_delay_ms);
491 if (rc < 0)
492 chg->otg_delay_ms = OTG_DEFAULT_DEGLITCH_TIME_MS;
493
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +0530494 chg->hw_die_temp_mitigation = of_property_read_bool(node,
495 "qcom,hw-die-temp-mitigation");
496
497 chg->hw_connector_mitigation = of_property_read_bool(node,
498 "qcom,hw-connector-mitigation");
499
500 chg->connector_pull_up = -EINVAL;
501 of_property_read_u32(node, "qcom,connector-internal-pull-kohm",
502 &chg->connector_pull_up);
503
Umang Agrawal461e9ea2018-07-05 18:50:13 +0530504 chg->moisture_protection_enabled = of_property_read_bool(node,
505 "qcom,moisture-protection-enable");
506
Umang Agrawal238086f2018-05-28 12:29:31 +0530507 chg->fcc_stepper_enable = of_property_read_bool(node,
508 "qcom,fcc-stepping-enable");
509
Harry Yang4b7db0f2017-11-27 10:50:44 -0800510 return 0;
511}
512
Ashay Jaiswal20688262018-04-25 11:45:34 +0530513static int smb5_get_adc_data(struct smb_charger *chg, int channel,
514 union power_supply_propval *val)
515{
Anirudh Ghayal75f8f812018-07-09 16:48:47 +0530516 int rc = 0;
Ashay Jaiswal20688262018-04-25 11:45:34 +0530517 struct qpnp_vadc_result result;
Ashay Jaiswalb50706d2018-06-28 19:37:31 +0530518 u8 reg;
Ashay Jaiswal20688262018-04-25 11:45:34 +0530519
520 if (!chg->vadc_dev) {
521 if (of_find_property(chg->dev->of_node, "qcom,chg-vadc",
522 NULL)) {
523 chg->vadc_dev = qpnp_get_vadc(chg->dev, "chg");
524 if (IS_ERR(chg->vadc_dev)) {
525 rc = PTR_ERR(chg->vadc_dev);
526 if (rc != -EPROBE_DEFER)
527 pr_debug("Failed to find VADC node, rc=%d\n",
528 rc);
529 else
530 chg->vadc_dev = NULL;
531
532 return rc;
533 }
534 } else {
535 return -ENODATA;
536 }
537 }
538
539 if (IS_ERR(chg->vadc_dev))
540 return PTR_ERR(chg->vadc_dev);
541
Anirudh Ghayal75f8f812018-07-09 16:48:47 +0530542 mutex_lock(&chg->vadc_lock);
543
Ashay Jaiswal20688262018-04-25 11:45:34 +0530544 switch (channel) {
545 case USBIN_VOLTAGE:
Ashay Jaiswalb50706d2018-06-28 19:37:31 +0530546 /* Store ADC channel config */
547 rc = smblib_read(chg, BATIF_ADC_CHANNEL_EN_REG, &reg);
548 if (rc < 0) {
549 dev_err(chg->dev,
550 "Couldn't read ADC config rc=%d\n", rc);
Anirudh Ghayal75f8f812018-07-09 16:48:47 +0530551 goto done;
Ashay Jaiswalb50706d2018-06-28 19:37:31 +0530552 }
553
554 /* Disable all ADC channels except IBAT channel */
555 rc = smblib_write(chg, BATIF_ADC_CHANNEL_EN_REG,
556 IBATT_CHANNEL_EN_BIT);
557 if (rc < 0) {
558 dev_err(chg->dev,
559 "Couldn't write ADC config rc=%d\n", rc);
Anirudh Ghayal75f8f812018-07-09 16:48:47 +0530560 goto done;
Ashay Jaiswalb50706d2018-06-28 19:37:31 +0530561 }
562
Ashay Jaiswal20688262018-04-25 11:45:34 +0530563 rc = qpnp_vadc_read(chg->vadc_dev, VADC_USB_IN_V_DIV_16_PM5,
564 &result);
Anirudh Ghayal75f8f812018-07-09 16:48:47 +0530565 if (rc < 0)
Ashay Jaiswal20688262018-04-25 11:45:34 +0530566 pr_err("Failed to read USBIN_V over vadc, rc=%d\n", rc);
Anirudh Ghayal75f8f812018-07-09 16:48:47 +0530567 else
568 val->intval = result.physical;
Ashay Jaiswalb50706d2018-06-28 19:37:31 +0530569
Ashay Jaiswalb50706d2018-06-28 19:37:31 +0530570 /* Restore ADC channel config */
Anirudh Ghayal75f8f812018-07-09 16:48:47 +0530571 rc |= smblib_write(chg, BATIF_ADC_CHANNEL_EN_REG, reg);
572 if (rc < 0)
Ashay Jaiswalb50706d2018-06-28 19:37:31 +0530573 dev_err(chg->dev,
574 "Couldn't write ADC config rc=%d\n", rc);
Anirudh Ghayal75f8f812018-07-09 16:48:47 +0530575
Ashay Jaiswal20688262018-04-25 11:45:34 +0530576 break;
577 case USBIN_CURRENT:
578 rc = qpnp_vadc_read(chg->vadc_dev, VADC_USB_IN_I_PM5, &result);
579 if (rc < 0) {
580 pr_err("Failed to read USBIN_I over vadc, rc=%d\n", rc);
Anirudh Ghayal75f8f812018-07-09 16:48:47 +0530581 goto done;
Ashay Jaiswal20688262018-04-25 11:45:34 +0530582 }
583 val->intval = result.physical;
584 break;
585 default:
586 pr_debug("Invalid channel\n");
Anirudh Ghayal75f8f812018-07-09 16:48:47 +0530587 rc = -EINVAL;
588 break;
Ashay Jaiswal20688262018-04-25 11:45:34 +0530589 }
590
Anirudh Ghayal75f8f812018-07-09 16:48:47 +0530591done:
592 mutex_unlock(&chg->vadc_lock);
593 return rc;
Ashay Jaiswal20688262018-04-25 11:45:34 +0530594}
595
596
Harry Yang4b7db0f2017-11-27 10:50:44 -0800597/************************
598 * USB PSY REGISTRATION *
599 ************************/
600static enum power_supply_property smb5_usb_props[] = {
601 POWER_SUPPLY_PROP_PRESENT,
602 POWER_SUPPLY_PROP_ONLINE,
603 POWER_SUPPLY_PROP_PD_CURRENT_MAX,
604 POWER_SUPPLY_PROP_CURRENT_MAX,
605 POWER_SUPPLY_PROP_TYPE,
606 POWER_SUPPLY_PROP_TYPEC_MODE,
607 POWER_SUPPLY_PROP_TYPEC_POWER_ROLE,
608 POWER_SUPPLY_PROP_TYPEC_CC_ORIENTATION,
Harry Yang4b7db0f2017-11-27 10:50:44 -0800609 POWER_SUPPLY_PROP_PD_ACTIVE,
610 POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED,
611 POWER_SUPPLY_PROP_INPUT_CURRENT_NOW,
612 POWER_SUPPLY_PROP_BOOST_CURRENT,
613 POWER_SUPPLY_PROP_PE_START,
614 POWER_SUPPLY_PROP_CTM_CURRENT_MAX,
615 POWER_SUPPLY_PROP_HW_CURRENT_MAX,
616 POWER_SUPPLY_PROP_REAL_TYPE,
617 POWER_SUPPLY_PROP_PR_SWAP,
618 POWER_SUPPLY_PROP_PD_VOLTAGE_MAX,
619 POWER_SUPPLY_PROP_PD_VOLTAGE_MIN,
620 POWER_SUPPLY_PROP_SDP_CURRENT_MAX,
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530621 POWER_SUPPLY_PROP_CONNECTOR_TYPE,
Ashay Jaiswal1f71b412017-10-31 14:33:27 +0530622 POWER_SUPPLY_PROP_VOLTAGE_MAX,
Umang Agrawal9fb865a2018-06-25 16:24:00 +0530623 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
Ashay Jaiswal09feab82018-02-12 12:33:18 +0530624 POWER_SUPPLY_PROP_SCOPE,
Ashay Jaiswal20688262018-04-25 11:45:34 +0530625 POWER_SUPPLY_PROP_VOLTAGE_NOW,
Ashay Jaiswal4d334f42018-04-25 10:58:49 +0530626 POWER_SUPPLY_PROP_HVDCP_OPTI_ALLOWED,
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +0530627 POWER_SUPPLY_PROP_QC_OPTI_DISABLE,
Umang Agrawal461e9ea2018-07-05 18:50:13 +0530628 POWER_SUPPLY_PROP_MOISTURE_DETECTED,
Harry Yang4b7db0f2017-11-27 10:50:44 -0800629};
630
631static int smb5_usb_get_prop(struct power_supply *psy,
632 enum power_supply_property psp,
633 union power_supply_propval *val)
634{
635 struct smb5 *chip = power_supply_get_drvdata(psy);
636 struct smb_charger *chg = &chip->chg;
Ashay Jaiswal09feab82018-02-12 12:33:18 +0530637 union power_supply_propval pval;
Harry Yang4b7db0f2017-11-27 10:50:44 -0800638 int rc = 0;
639
640 switch (psp) {
641 case POWER_SUPPLY_PROP_PRESENT:
642 rc = smblib_get_prop_usb_present(chg, val);
643 break;
644 case POWER_SUPPLY_PROP_ONLINE:
645 rc = smblib_get_prop_usb_online(chg, val);
646 if (!val->intval)
647 break;
648
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530649 if (((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) ||
650 (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB))
651 && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB))
Harry Yang4b7db0f2017-11-27 10:50:44 -0800652 val->intval = 0;
653 else
654 val->intval = 1;
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530655
Harry Yang4b7db0f2017-11-27 10:50:44 -0800656 if (chg->real_charger_type == POWER_SUPPLY_TYPE_UNKNOWN)
657 val->intval = 0;
658 break;
659 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
660 rc = smblib_get_prop_usb_voltage_max(chg, val);
661 break;
Umang Agrawal9fb865a2018-06-25 16:24:00 +0530662 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
663 rc = smblib_get_prop_usb_voltage_max_design(chg, val);
664 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -0800665 case POWER_SUPPLY_PROP_PD_CURRENT_MAX:
666 val->intval = get_client_vote(chg->usb_icl_votable, PD_VOTER);
667 break;
668 case POWER_SUPPLY_PROP_CURRENT_MAX:
669 rc = smblib_get_prop_input_current_settled(chg, val);
670 break;
671 case POWER_SUPPLY_PROP_TYPE:
672 val->intval = POWER_SUPPLY_TYPE_USB_PD;
673 break;
674 case POWER_SUPPLY_PROP_REAL_TYPE:
675 val->intval = chg->real_charger_type;
676 break;
677 case POWER_SUPPLY_PROP_TYPEC_MODE:
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530678 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
Harry Yang4b7db0f2017-11-27 10:50:44 -0800679 val->intval = POWER_SUPPLY_TYPEC_NONE;
680 else
681 val->intval = chg->typec_mode;
682 break;
683 case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE:
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530684 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
Harry Yang4b7db0f2017-11-27 10:50:44 -0800685 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
686 else
687 rc = smblib_get_prop_typec_power_role(chg, val);
688 break;
689 case POWER_SUPPLY_PROP_TYPEC_CC_ORIENTATION:
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530690 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
Harry Yang4b7db0f2017-11-27 10:50:44 -0800691 val->intval = 0;
692 else
693 rc = smblib_get_prop_typec_cc_orientation(chg, val);
694 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -0800695 case POWER_SUPPLY_PROP_PD_ACTIVE:
696 val->intval = chg->pd_active;
697 break;
698 case POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED:
699 rc = smblib_get_prop_input_current_settled(chg, val);
700 break;
701 case POWER_SUPPLY_PROP_BOOST_CURRENT:
702 val->intval = chg->boost_current_ua;
703 break;
704 case POWER_SUPPLY_PROP_PD_IN_HARD_RESET:
705 rc = smblib_get_prop_pd_in_hard_reset(chg, val);
706 break;
707 case POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED:
708 val->intval = chg->system_suspend_supported;
709 break;
710 case POWER_SUPPLY_PROP_PE_START:
711 rc = smblib_get_pe_start(chg, val);
712 break;
713 case POWER_SUPPLY_PROP_CTM_CURRENT_MAX:
714 val->intval = get_client_vote(chg->usb_icl_votable, CTM_VOTER);
715 break;
716 case POWER_SUPPLY_PROP_HW_CURRENT_MAX:
717 rc = smblib_get_charge_current(chg, &val->intval);
718 break;
719 case POWER_SUPPLY_PROP_PR_SWAP:
720 rc = smblib_get_prop_pr_swap_in_progress(chg, val);
721 break;
722 case POWER_SUPPLY_PROP_PD_VOLTAGE_MAX:
723 val->intval = chg->voltage_max_uv;
724 break;
725 case POWER_SUPPLY_PROP_PD_VOLTAGE_MIN:
726 val->intval = chg->voltage_min_uv;
727 break;
728 case POWER_SUPPLY_PROP_SDP_CURRENT_MAX:
729 val->intval = get_client_vote(chg->usb_icl_votable,
730 USB_PSY_VOTER);
731 break;
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530732 case POWER_SUPPLY_PROP_CONNECTOR_TYPE:
733 val->intval = chg->connector_type;
734 break;
Ashay Jaiswal09feab82018-02-12 12:33:18 +0530735 case POWER_SUPPLY_PROP_SCOPE:
736 val->intval = POWER_SUPPLY_SCOPE_UNKNOWN;
737 rc = smblib_get_prop_usb_present(chg, &pval);
738 if (rc < 0)
739 break;
740 val->intval = pval.intval ? POWER_SUPPLY_SCOPE_DEVICE
741 : chg->otg_present ? POWER_SUPPLY_SCOPE_SYSTEM
742 : POWER_SUPPLY_SCOPE_UNKNOWN;
743 break;
Ashay Jaiswal20688262018-04-25 11:45:34 +0530744 case POWER_SUPPLY_PROP_INPUT_CURRENT_NOW:
745 rc = smblib_get_prop_usb_present(chg, &pval);
746 if (rc < 0 || !pval.intval) {
747 val->intval = 0;
748 return rc;
749 }
750 if (chg->smb_version == PMI632_SUBTYPE)
751 rc = smb5_get_adc_data(chg, USBIN_CURRENT, val);
752 break;
753 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
754 if (chg->smb_version == PMI632_SUBTYPE)
755 rc = smb5_get_adc_data(chg, USBIN_VOLTAGE, val);
756 break;
Ashay Jaiswal4d334f42018-04-25 10:58:49 +0530757 case POWER_SUPPLY_PROP_HVDCP_OPTI_ALLOWED:
758 val->intval = !chg->flash_active;
759 break;
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +0530760 case POWER_SUPPLY_PROP_QC_OPTI_DISABLE:
761 if (chg->hw_die_temp_mitigation)
762 val->intval = POWER_SUPPLY_QC_THERMAL_BALANCE_DISABLE
763 | POWER_SUPPLY_QC_INOV_THERMAL_DISABLE;
764 if (chg->hw_connector_mitigation)
765 val->intval |= POWER_SUPPLY_QC_CTM_DISABLE;
766 break;
Umang Agrawal461e9ea2018-07-05 18:50:13 +0530767 case POWER_SUPPLY_PROP_MOISTURE_DETECTED:
768 val->intval = chg->moisture_present;
769 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -0800770 default:
771 pr_err("get prop %d is not supported in usb\n", psp);
772 rc = -EINVAL;
773 break;
774 }
775
776 if (rc < 0) {
777 pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
778 return -ENODATA;
779 }
780
781 return 0;
782}
783
784static int smb5_usb_set_prop(struct power_supply *psy,
785 enum power_supply_property psp,
786 const union power_supply_propval *val)
787{
788 struct smb5 *chip = power_supply_get_drvdata(psy);
789 struct smb_charger *chg = &chip->chg;
790 int rc = 0;
791
Harry Yang4b7db0f2017-11-27 10:50:44 -0800792 switch (psp) {
793 case POWER_SUPPLY_PROP_PD_CURRENT_MAX:
794 rc = smblib_set_prop_pd_current_max(chg, val);
795 break;
796 case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE:
797 rc = smblib_set_prop_typec_power_role(chg, val);
798 break;
799 case POWER_SUPPLY_PROP_PD_ACTIVE:
800 rc = smblib_set_prop_pd_active(chg, val);
801 break;
802 case POWER_SUPPLY_PROP_PD_IN_HARD_RESET:
803 rc = smblib_set_prop_pd_in_hard_reset(chg, val);
804 break;
805 case POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED:
806 chg->system_suspend_supported = val->intval;
807 break;
808 case POWER_SUPPLY_PROP_BOOST_CURRENT:
809 rc = smblib_set_prop_boost_current(chg, val);
810 break;
811 case POWER_SUPPLY_PROP_CTM_CURRENT_MAX:
812 rc = vote(chg->usb_icl_votable, CTM_VOTER,
813 val->intval >= 0, val->intval);
814 break;
815 case POWER_SUPPLY_PROP_PR_SWAP:
816 rc = smblib_set_prop_pr_swap_in_progress(chg, val);
817 break;
818 case POWER_SUPPLY_PROP_PD_VOLTAGE_MAX:
819 rc = smblib_set_prop_pd_voltage_max(chg, val);
820 break;
821 case POWER_SUPPLY_PROP_PD_VOLTAGE_MIN:
822 rc = smblib_set_prop_pd_voltage_min(chg, val);
823 break;
824 case POWER_SUPPLY_PROP_SDP_CURRENT_MAX:
825 rc = smblib_set_prop_sdp_current_max(chg, val);
826 break;
827 default:
828 pr_err("set prop %d is not supported\n", psp);
829 rc = -EINVAL;
830 break;
831 }
832
Harry Yang4b7db0f2017-11-27 10:50:44 -0800833 return rc;
834}
835
836static int smb5_usb_prop_is_writeable(struct power_supply *psy,
837 enum power_supply_property psp)
838{
839 switch (psp) {
840 case POWER_SUPPLY_PROP_CTM_CURRENT_MAX:
841 return 1;
842 default:
843 break;
844 }
845
846 return 0;
847}
848
849static const struct power_supply_desc usb_psy_desc = {
850 .name = "usb",
851 .type = POWER_SUPPLY_TYPE_USB_PD,
852 .properties = smb5_usb_props,
853 .num_properties = ARRAY_SIZE(smb5_usb_props),
854 .get_property = smb5_usb_get_prop,
855 .set_property = smb5_usb_set_prop,
856 .property_is_writeable = smb5_usb_prop_is_writeable,
857};
858
859static int smb5_init_usb_psy(struct smb5 *chip)
860{
861 struct power_supply_config usb_cfg = {};
862 struct smb_charger *chg = &chip->chg;
863
864 usb_cfg.drv_data = chip;
865 usb_cfg.of_node = chg->dev->of_node;
866 chg->usb_psy = devm_power_supply_register(chg->dev,
867 &usb_psy_desc,
868 &usb_cfg);
869 if (IS_ERR(chg->usb_psy)) {
870 pr_err("Couldn't register USB power supply\n");
871 return PTR_ERR(chg->usb_psy);
872 }
873
874 return 0;
875}
876
877/********************************
878 * USB PC_PORT PSY REGISTRATION *
879 ********************************/
880static enum power_supply_property smb5_usb_port_props[] = {
881 POWER_SUPPLY_PROP_TYPE,
882 POWER_SUPPLY_PROP_ONLINE,
883 POWER_SUPPLY_PROP_VOLTAGE_MAX,
884 POWER_SUPPLY_PROP_CURRENT_MAX,
885};
886
887static int smb5_usb_port_get_prop(struct power_supply *psy,
888 enum power_supply_property psp,
889 union power_supply_propval *val)
890{
891 struct smb5 *chip = power_supply_get_drvdata(psy);
892 struct smb_charger *chg = &chip->chg;
893 int rc = 0;
894
895 switch (psp) {
896 case POWER_SUPPLY_PROP_TYPE:
897 val->intval = POWER_SUPPLY_TYPE_USB;
898 break;
899 case POWER_SUPPLY_PROP_ONLINE:
900 rc = smblib_get_prop_usb_online(chg, val);
901 if (!val->intval)
902 break;
903
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530904 if (((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) ||
905 (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB))
906 && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB))
Harry Yang4b7db0f2017-11-27 10:50:44 -0800907 val->intval = 1;
908 else
909 val->intval = 0;
910 break;
911 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
912 val->intval = 5000000;
913 break;
914 case POWER_SUPPLY_PROP_CURRENT_MAX:
915 rc = smblib_get_prop_input_current_settled(chg, val);
916 break;
917 default:
918 pr_err_ratelimited("Get prop %d is not supported in pc_port\n",
919 psp);
920 return -EINVAL;
921 }
922
923 if (rc < 0) {
924 pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
925 return -ENODATA;
926 }
927
928 return 0;
929}
930
931static int smb5_usb_port_set_prop(struct power_supply *psy,
932 enum power_supply_property psp,
933 const union power_supply_propval *val)
934{
935 int rc = 0;
936
937 switch (psp) {
938 default:
939 pr_err_ratelimited("Set prop %d is not supported in pc_port\n",
940 psp);
941 rc = -EINVAL;
942 break;
943 }
944
945 return rc;
946}
947
948static const struct power_supply_desc usb_port_psy_desc = {
949 .name = "pc_port",
950 .type = POWER_SUPPLY_TYPE_USB,
951 .properties = smb5_usb_port_props,
952 .num_properties = ARRAY_SIZE(smb5_usb_port_props),
953 .get_property = smb5_usb_port_get_prop,
954 .set_property = smb5_usb_port_set_prop,
955};
956
957static int smb5_init_usb_port_psy(struct smb5 *chip)
958{
959 struct power_supply_config usb_port_cfg = {};
960 struct smb_charger *chg = &chip->chg;
961
962 usb_port_cfg.drv_data = chip;
963 usb_port_cfg.of_node = chg->dev->of_node;
964 chg->usb_port_psy = devm_power_supply_register(chg->dev,
965 &usb_port_psy_desc,
966 &usb_port_cfg);
967 if (IS_ERR(chg->usb_port_psy)) {
968 pr_err("Couldn't register USB pc_port power supply\n");
969 return PTR_ERR(chg->usb_port_psy);
970 }
971
972 return 0;
973}
974
975/*****************************
976 * USB MAIN PSY REGISTRATION *
977 *****************************/
978
979static enum power_supply_property smb5_usb_main_props[] = {
980 POWER_SUPPLY_PROP_VOLTAGE_MAX,
981 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
982 POWER_SUPPLY_PROP_TYPE,
983 POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED,
984 POWER_SUPPLY_PROP_INPUT_VOLTAGE_SETTLED,
985 POWER_SUPPLY_PROP_FCC_DELTA,
986 POWER_SUPPLY_PROP_CURRENT_MAX,
Ashay Jaiswal09feab82018-02-12 12:33:18 +0530987 POWER_SUPPLY_PROP_FLASH_ACTIVE,
988 POWER_SUPPLY_PROP_FLASH_TRIGGER,
Harry Yang4b7db0f2017-11-27 10:50:44 -0800989};
990
991static int smb5_usb_main_get_prop(struct power_supply *psy,
992 enum power_supply_property psp,
993 union power_supply_propval *val)
994{
995 struct smb5 *chip = power_supply_get_drvdata(psy);
996 struct smb_charger *chg = &chip->chg;
997 int rc = 0;
998
999 switch (psp) {
1000 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
1001 rc = smblib_get_charge_param(chg, &chg->param.fv, &val->intval);
1002 break;
1003 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
1004 rc = smblib_get_charge_param(chg, &chg->param.fcc,
1005 &val->intval);
1006 break;
1007 case POWER_SUPPLY_PROP_TYPE:
1008 val->intval = POWER_SUPPLY_TYPE_MAIN;
1009 break;
1010 case POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED:
1011 rc = smblib_get_prop_input_current_settled(chg, val);
1012 break;
1013 case POWER_SUPPLY_PROP_INPUT_VOLTAGE_SETTLED:
1014 rc = smblib_get_prop_input_voltage_settled(chg, val);
1015 break;
1016 case POWER_SUPPLY_PROP_FCC_DELTA:
1017 rc = smblib_get_prop_fcc_delta(chg, val);
1018 break;
1019 case POWER_SUPPLY_PROP_CURRENT_MAX:
1020 rc = smblib_get_icl_current(chg, &val->intval);
1021 break;
Ashay Jaiswal09feab82018-02-12 12:33:18 +05301022 case POWER_SUPPLY_PROP_FLASH_ACTIVE:
1023 val->intval = chg->flash_active;
1024 break;
1025 case POWER_SUPPLY_PROP_FLASH_TRIGGER:
1026 rc = schgm_flash_get_vreg_ok(chg, &val->intval);
1027 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001028 default:
1029 pr_debug("get prop %d is not supported in usb-main\n", psp);
1030 rc = -EINVAL;
1031 break;
1032 }
1033 if (rc < 0) {
1034 pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
1035 return -ENODATA;
1036 }
1037
1038 return 0;
1039}
1040
1041static int smb5_usb_main_set_prop(struct power_supply *psy,
1042 enum power_supply_property psp,
1043 const union power_supply_propval *val)
1044{
1045 struct smb5 *chip = power_supply_get_drvdata(psy);
1046 struct smb_charger *chg = &chip->chg;
Ashay Jaiswal4d334f42018-04-25 10:58:49 +05301047 union power_supply_propval pval = {0, };
Harry Yang4b7db0f2017-11-27 10:50:44 -08001048 int rc = 0;
1049
1050 switch (psp) {
1051 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
1052 rc = smblib_set_charge_param(chg, &chg->param.fv, val->intval);
1053 break;
1054 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
1055 rc = smblib_set_charge_param(chg, &chg->param.fcc, val->intval);
1056 break;
1057 case POWER_SUPPLY_PROP_CURRENT_MAX:
1058 rc = smblib_set_icl_current(chg, val->intval);
1059 break;
Ashay Jaiswal09feab82018-02-12 12:33:18 +05301060 case POWER_SUPPLY_PROP_FLASH_ACTIVE:
Ashay Jaiswal4d334f42018-04-25 10:58:49 +05301061 if ((chg->smb_version == PMI632_SUBTYPE)
1062 && (chg->flash_active != val->intval)) {
1063 chg->flash_active = val->intval;
1064
1065 rc = smblib_get_prop_usb_present(chg, &pval);
1066 if (rc < 0)
1067 pr_err("Failed to get USB preset status rc=%d\n",
1068 rc);
1069 if (pval.intval) {
1070 rc = smblib_force_vbus_voltage(chg,
1071 chg->flash_active ? FORCE_5V_BIT
1072 : IDLE_BIT);
1073 if (rc < 0)
1074 pr_err("Failed to force 5V\n");
1075 else
1076 chg->pulse_cnt = 0;
Anirudh Ghayal4d5cddc2018-06-28 15:19:39 +05301077 } else {
1078 /* USB absent & flash not-active - vote 100mA */
1079 vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER,
1080 true, SDP_100_MA);
Ashay Jaiswal4d334f42018-04-25 10:58:49 +05301081 }
1082
1083 pr_debug("flash active VBUS 5V restriction %s\n",
1084 chg->flash_active ? "applied" : "removed");
1085
1086 /* Update userspace */
1087 if (chg->batt_psy)
1088 power_supply_changed(chg->batt_psy);
1089 }
Ashay Jaiswal09feab82018-02-12 12:33:18 +05301090 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001091 default:
1092 pr_err("set prop %d is not supported\n", psp);
1093 rc = -EINVAL;
1094 break;
1095 }
1096
1097 return rc;
1098}
1099
1100static const struct power_supply_desc usb_main_psy_desc = {
1101 .name = "main",
1102 .type = POWER_SUPPLY_TYPE_MAIN,
1103 .properties = smb5_usb_main_props,
1104 .num_properties = ARRAY_SIZE(smb5_usb_main_props),
1105 .get_property = smb5_usb_main_get_prop,
1106 .set_property = smb5_usb_main_set_prop,
1107};
1108
1109static int smb5_init_usb_main_psy(struct smb5 *chip)
1110{
1111 struct power_supply_config usb_main_cfg = {};
1112 struct smb_charger *chg = &chip->chg;
1113
1114 usb_main_cfg.drv_data = chip;
1115 usb_main_cfg.of_node = chg->dev->of_node;
1116 chg->usb_main_psy = devm_power_supply_register(chg->dev,
1117 &usb_main_psy_desc,
1118 &usb_main_cfg);
1119 if (IS_ERR(chg->usb_main_psy)) {
1120 pr_err("Couldn't register USB main power supply\n");
1121 return PTR_ERR(chg->usb_main_psy);
1122 }
1123
1124 return 0;
1125}
1126
1127/*************************
1128 * DC PSY REGISTRATION *
1129 *************************/
1130
1131static enum power_supply_property smb5_dc_props[] = {
1132 POWER_SUPPLY_PROP_INPUT_SUSPEND,
1133 POWER_SUPPLY_PROP_PRESENT,
1134 POWER_SUPPLY_PROP_ONLINE,
1135 POWER_SUPPLY_PROP_REAL_TYPE,
1136};
1137
1138static int smb5_dc_get_prop(struct power_supply *psy,
1139 enum power_supply_property psp,
1140 union power_supply_propval *val)
1141{
1142 struct smb5 *chip = power_supply_get_drvdata(psy);
1143 struct smb_charger *chg = &chip->chg;
1144 int rc = 0;
1145
1146 switch (psp) {
1147 case POWER_SUPPLY_PROP_INPUT_SUSPEND:
1148 val->intval = get_effective_result(chg->dc_suspend_votable);
1149 break;
1150 case POWER_SUPPLY_PROP_PRESENT:
1151 rc = smblib_get_prop_dc_present(chg, val);
1152 break;
1153 case POWER_SUPPLY_PROP_ONLINE:
1154 rc = smblib_get_prop_dc_online(chg, val);
1155 break;
1156 case POWER_SUPPLY_PROP_REAL_TYPE:
1157 val->intval = POWER_SUPPLY_TYPE_WIPOWER;
1158 break;
1159 default:
1160 return -EINVAL;
1161 }
1162 if (rc < 0) {
1163 pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
1164 return -ENODATA;
1165 }
1166 return 0;
1167}
1168
1169static int smb5_dc_set_prop(struct power_supply *psy,
1170 enum power_supply_property psp,
1171 const union power_supply_propval *val)
1172{
1173 struct smb5 *chip = power_supply_get_drvdata(psy);
1174 struct smb_charger *chg = &chip->chg;
1175 int rc = 0;
1176
1177 switch (psp) {
1178 case POWER_SUPPLY_PROP_INPUT_SUSPEND:
1179 rc = vote(chg->dc_suspend_votable, WBC_VOTER,
1180 (bool)val->intval, 0);
1181 break;
1182 default:
1183 return -EINVAL;
1184 }
1185
1186 return rc;
1187}
1188
1189static int smb5_dc_prop_is_writeable(struct power_supply *psy,
1190 enum power_supply_property psp)
1191{
1192 int rc;
1193
1194 switch (psp) {
1195 default:
1196 rc = 0;
1197 break;
1198 }
1199
1200 return rc;
1201}
1202
1203static const struct power_supply_desc dc_psy_desc = {
1204 .name = "dc",
1205 .type = POWER_SUPPLY_TYPE_WIRELESS,
1206 .properties = smb5_dc_props,
1207 .num_properties = ARRAY_SIZE(smb5_dc_props),
1208 .get_property = smb5_dc_get_prop,
1209 .set_property = smb5_dc_set_prop,
1210 .property_is_writeable = smb5_dc_prop_is_writeable,
1211};
1212
1213static int smb5_init_dc_psy(struct smb5 *chip)
1214{
1215 struct power_supply_config dc_cfg = {};
1216 struct smb_charger *chg = &chip->chg;
1217
1218 dc_cfg.drv_data = chip;
1219 dc_cfg.of_node = chg->dev->of_node;
1220 chg->dc_psy = devm_power_supply_register(chg->dev,
1221 &dc_psy_desc,
1222 &dc_cfg);
1223 if (IS_ERR(chg->dc_psy)) {
1224 pr_err("Couldn't register USB power supply\n");
1225 return PTR_ERR(chg->dc_psy);
1226 }
1227
1228 return 0;
1229}
1230
1231/*************************
1232 * BATT PSY REGISTRATION *
1233 *************************/
1234static enum power_supply_property smb5_batt_props[] = {
1235 POWER_SUPPLY_PROP_INPUT_SUSPEND,
Anirudh Ghayaldfdb8412018-04-21 10:37:18 +05301236 POWER_SUPPLY_PROP_BATTERY_CHARGING_ENABLED,
Harry Yang4b7db0f2017-11-27 10:50:44 -08001237 POWER_SUPPLY_PROP_STATUS,
1238 POWER_SUPPLY_PROP_HEALTH,
1239 POWER_SUPPLY_PROP_PRESENT,
1240 POWER_SUPPLY_PROP_CHARGE_TYPE,
1241 POWER_SUPPLY_PROP_CAPACITY,
1242 POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
1243 POWER_SUPPLY_PROP_VOLTAGE_NOW,
1244 POWER_SUPPLY_PROP_VOLTAGE_MAX,
1245 POWER_SUPPLY_PROP_CURRENT_NOW,
1246 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001247 POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
Harry Yang4b7db0f2017-11-27 10:50:44 -08001248 POWER_SUPPLY_PROP_TEMP,
1249 POWER_SUPPLY_PROP_TECHNOLOGY,
1250 POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED,
1251 POWER_SUPPLY_PROP_SW_JEITA_ENABLED,
1252 POWER_SUPPLY_PROP_CHARGE_DONE,
1253 POWER_SUPPLY_PROP_PARALLEL_DISABLE,
1254 POWER_SUPPLY_PROP_SET_SHIP_MODE,
1255 POWER_SUPPLY_PROP_DIE_HEALTH,
1256 POWER_SUPPLY_PROP_RERUN_AICL,
1257 POWER_SUPPLY_PROP_DP_DM,
1258 POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
1259 POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
1260 POWER_SUPPLY_PROP_CHARGE_COUNTER,
Subbaraman Narayanamurthyc4feb892018-05-07 18:43:45 -07001261 POWER_SUPPLY_PROP_CYCLE_COUNT,
Anirudh Ghayal1380d312018-02-23 00:01:43 +05301262 POWER_SUPPLY_PROP_RECHARGE_SOC,
Ashay Jaiswal5c5ba272018-07-23 14:54:20 +05301263 POWER_SUPPLY_PROP_CHARGE_FULL,
Umang Agrawal238086f2018-05-28 12:29:31 +05301264 POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE,
Harry Yang4b7db0f2017-11-27 10:50:44 -08001265};
1266
Ashay Jaiswald802c3d2018-07-25 14:55:10 +05301267#define ITERM_SCALING_FACTOR_PMI632 1525
1268#define ITERM_SCALING_FACTOR_PM855B 3050
1269static int smb5_get_prop_batt_iterm(struct smb_charger *chg,
1270 union power_supply_propval *val)
1271{
1272 int rc, temp, scaling_factor;
1273 u8 stat, buf[2];
1274
1275 /*
1276 * Currently, only ADC comparator-based termination is supported,
1277 * hence read only the threshold corresponding to ADC source.
1278 * Proceed only if CHGR_ITERM_USE_ANALOG_BIT is 0.
1279 */
1280 rc = smblib_read(chg, CHGR_ENG_CHARGING_CFG_REG, &stat);
1281 if (rc < 0) {
1282 pr_err("Couldn't read CHGR_ENG_CHARGING_CFG_REG rc=%d\n", rc);
1283 return rc;
1284 }
1285
1286 if (stat & CHGR_ITERM_USE_ANALOG_BIT) {
1287 val->intval = -EINVAL;
1288 return 0;
1289 }
1290
1291 rc = smblib_batch_read(chg, CHGR_ADC_ITERM_UP_THD_MSB_REG, buf, 2);
1292
1293 if (rc < 0) {
1294 pr_err("Couldn't read CHGR_ADC_ITERM_UP_THD_MSB_REG rc=%d\n",
1295 rc);
1296 return rc;
1297 }
1298
1299 temp = buf[1] | (buf[0] << 8);
1300 temp = sign_extend32(temp, 15);
1301
1302 if (chg->smb_version == PMI632_SUBTYPE)
1303 scaling_factor = ITERM_SCALING_FACTOR_PMI632;
1304 else
1305 scaling_factor = ITERM_SCALING_FACTOR_PM855B;
1306
1307 temp = div_s64(temp * scaling_factor, 10000);
1308 val->intval = temp;
1309
1310 return rc;
1311}
1312
Harry Yang4b7db0f2017-11-27 10:50:44 -08001313static int smb5_batt_get_prop(struct power_supply *psy,
1314 enum power_supply_property psp,
1315 union power_supply_propval *val)
1316{
1317 struct smb_charger *chg = power_supply_get_drvdata(psy);
1318 int rc = 0;
1319
1320 switch (psp) {
1321 case POWER_SUPPLY_PROP_STATUS:
1322 rc = smblib_get_prop_batt_status(chg, val);
1323 break;
1324 case POWER_SUPPLY_PROP_HEALTH:
1325 rc = smblib_get_prop_batt_health(chg, val);
1326 break;
1327 case POWER_SUPPLY_PROP_PRESENT:
1328 rc = smblib_get_prop_batt_present(chg, val);
1329 break;
1330 case POWER_SUPPLY_PROP_INPUT_SUSPEND:
1331 rc = smblib_get_prop_input_suspend(chg, val);
1332 break;
Anirudh Ghayaldfdb8412018-04-21 10:37:18 +05301333 case POWER_SUPPLY_PROP_BATTERY_CHARGING_ENABLED:
1334 val->intval = !get_client_vote(chg->chg_disable_votable,
1335 USER_VOTER);
1336 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001337 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1338 rc = smblib_get_prop_batt_charge_type(chg, val);
1339 break;
1340 case POWER_SUPPLY_PROP_CAPACITY:
1341 rc = smblib_get_prop_batt_capacity(chg, val);
1342 break;
1343 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
1344 rc = smblib_get_prop_system_temp_level(chg, val);
1345 break;
1346 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX:
1347 rc = smblib_get_prop_system_temp_level_max(chg, val);
1348 break;
1349 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
1350 rc = smblib_get_prop_input_current_limited(chg, val);
1351 break;
1352 case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
1353 val->intval = chg->step_chg_enabled;
1354 break;
1355 case POWER_SUPPLY_PROP_SW_JEITA_ENABLED:
1356 val->intval = chg->sw_jeita_enabled;
1357 break;
1358 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Ashay Jaiswal5c5ba272018-07-23 14:54:20 +05301359 rc = smblib_get_prop_from_bms(chg,
1360 POWER_SUPPLY_PROP_VOLTAGE_NOW, val);
Harry Yang4b7db0f2017-11-27 10:50:44 -08001361 break;
1362 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
1363 val->intval = get_client_vote(chg->fv_votable,
1364 BATT_PROFILE_VOTER);
1365 break;
1366 case POWER_SUPPLY_PROP_CURRENT_NOW:
Ashay Jaiswal5c5ba272018-07-23 14:54:20 +05301367 rc = smblib_get_prop_from_bms(chg,
1368 POWER_SUPPLY_PROP_CURRENT_NOW, val);
Harry Yang4b7db0f2017-11-27 10:50:44 -08001369 break;
1370 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
1371 val->intval = get_client_vote(chg->fcc_votable,
1372 BATT_PROFILE_VOTER);
1373 break;
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001374 case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
Ashay Jaiswald802c3d2018-07-25 14:55:10 +05301375 rc = smb5_get_prop_batt_iterm(chg, val);
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001376 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001377 case POWER_SUPPLY_PROP_TEMP:
Ashay Jaiswal5c5ba272018-07-23 14:54:20 +05301378 rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_TEMP, val);
Harry Yang4b7db0f2017-11-27 10:50:44 -08001379 break;
1380 case POWER_SUPPLY_PROP_TECHNOLOGY:
1381 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1382 break;
1383 case POWER_SUPPLY_PROP_CHARGE_DONE:
1384 rc = smblib_get_prop_batt_charge_done(chg, val);
1385 break;
1386 case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
1387 val->intval = get_client_vote(chg->pl_disable_votable,
1388 USER_VOTER);
1389 break;
1390 case POWER_SUPPLY_PROP_SET_SHIP_MODE:
1391 /* Not in ship mode as long as device is active */
1392 val->intval = 0;
1393 break;
1394 case POWER_SUPPLY_PROP_DIE_HEALTH:
1395 if (chg->die_health == -EINVAL)
1396 rc = smblib_get_prop_die_health(chg, val);
1397 else
1398 val->intval = chg->die_health;
1399 break;
1400 case POWER_SUPPLY_PROP_DP_DM:
1401 val->intval = chg->pulse_cnt;
1402 break;
1403 case POWER_SUPPLY_PROP_RERUN_AICL:
1404 val->intval = 0;
1405 break;
1406 case POWER_SUPPLY_PROP_CHARGE_COUNTER:
Ashay Jaiswal5c5ba272018-07-23 14:54:20 +05301407 rc = smblib_get_prop_from_bms(chg,
1408 POWER_SUPPLY_PROP_CHARGE_COUNTER, val);
Harry Yang4b7db0f2017-11-27 10:50:44 -08001409 break;
Subbaraman Narayanamurthyc4feb892018-05-07 18:43:45 -07001410 case POWER_SUPPLY_PROP_CYCLE_COUNT:
Ashay Jaiswal5c5ba272018-07-23 14:54:20 +05301411 rc = smblib_get_prop_from_bms(chg,
1412 POWER_SUPPLY_PROP_CYCLE_COUNT, val);
Subbaraman Narayanamurthyc4feb892018-05-07 18:43:45 -07001413 break;
Anirudh Ghayal1380d312018-02-23 00:01:43 +05301414 case POWER_SUPPLY_PROP_RECHARGE_SOC:
1415 val->intval = chg->auto_recharge_soc;
1416 break;
Ashay Jaiswal5c5ba272018-07-23 14:54:20 +05301417 case POWER_SUPPLY_PROP_CHARGE_FULL:
1418 rc = smblib_get_prop_from_bms(chg,
1419 POWER_SUPPLY_PROP_CHARGE_FULL, val);
1420 break;
Umang Agrawal238086f2018-05-28 12:29:31 +05301421 case POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE:
1422 val->intval = chg->fcc_stepper_enable;
1423 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001424 default:
1425 pr_err("batt power supply prop %d not supported\n", psp);
1426 return -EINVAL;
1427 }
1428
1429 if (rc < 0) {
1430 pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
1431 return -ENODATA;
1432 }
1433
1434 return 0;
1435}
1436
1437static int smb5_batt_set_prop(struct power_supply *psy,
1438 enum power_supply_property prop,
1439 const union power_supply_propval *val)
1440{
1441 int rc = 0;
1442 struct smb_charger *chg = power_supply_get_drvdata(psy);
Ashay Jaiswala55b7ed2018-03-23 17:23:48 +05301443 bool enable;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001444
1445 switch (prop) {
1446 case POWER_SUPPLY_PROP_STATUS:
1447 rc = smblib_set_prop_batt_status(chg, val);
1448 break;
1449 case POWER_SUPPLY_PROP_INPUT_SUSPEND:
1450 rc = smblib_set_prop_input_suspend(chg, val);
1451 break;
Anirudh Ghayaldfdb8412018-04-21 10:37:18 +05301452 case POWER_SUPPLY_PROP_BATTERY_CHARGING_ENABLED:
1453 vote(chg->chg_disable_votable, USER_VOTER, !val->intval, 0);
1454 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001455 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
1456 rc = smblib_set_prop_system_temp_level(chg, val);
1457 break;
1458 case POWER_SUPPLY_PROP_CAPACITY:
1459 rc = smblib_set_prop_batt_capacity(chg, val);
1460 break;
1461 case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
1462 vote(chg->pl_disable_votable, USER_VOTER, (bool)val->intval, 0);
1463 break;
1464 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
1465 chg->batt_profile_fv_uv = val->intval;
1466 vote(chg->fv_votable, BATT_PROFILE_VOTER, true, val->intval);
1467 break;
1468 case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
Ashay Jaiswala55b7ed2018-03-23 17:23:48 +05301469 enable = !!val->intval || chg->sw_jeita_enabled;
1470 rc = smblib_configure_wdog(chg, enable);
1471 if (rc == 0)
1472 chg->step_chg_enabled = !!val->intval;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001473 break;
1474 case POWER_SUPPLY_PROP_SW_JEITA_ENABLED:
1475 if (chg->sw_jeita_enabled != (!!val->intval)) {
1476 rc = smblib_disable_hw_jeita(chg, !!val->intval);
Ashay Jaiswala55b7ed2018-03-23 17:23:48 +05301477 enable = !!val->intval || chg->step_chg_enabled;
1478 rc |= smblib_configure_wdog(chg, enable);
Harry Yang4b7db0f2017-11-27 10:50:44 -08001479 if (rc == 0)
1480 chg->sw_jeita_enabled = !!val->intval;
1481 }
1482 break;
1483 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
1484 chg->batt_profile_fcc_ua = val->intval;
1485 vote(chg->fcc_votable, BATT_PROFILE_VOTER, true, val->intval);
1486 break;
1487 case POWER_SUPPLY_PROP_SET_SHIP_MODE:
1488 /* Not in ship mode as long as the device is active */
1489 if (!val->intval)
1490 break;
1491 if (chg->pl.psy)
1492 power_supply_set_property(chg->pl.psy,
1493 POWER_SUPPLY_PROP_SET_SHIP_MODE, val);
1494 rc = smblib_set_prop_ship_mode(chg, val);
1495 break;
1496 case POWER_SUPPLY_PROP_RERUN_AICL:
Ashay Jaiswale0b3c472018-06-20 23:39:41 +05301497 rc = smblib_run_aicl(chg, RERUN_AICL);
Harry Yang4b7db0f2017-11-27 10:50:44 -08001498 break;
1499 case POWER_SUPPLY_PROP_DP_DM:
Ashay Jaiswal4d334f42018-04-25 10:58:49 +05301500 if (!chg->flash_active)
1501 rc = smblib_dp_dm(chg, val->intval);
Harry Yang4b7db0f2017-11-27 10:50:44 -08001502 break;
1503 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
1504 rc = smblib_set_prop_input_current_limited(chg, val);
1505 break;
1506 case POWER_SUPPLY_PROP_DIE_HEALTH:
1507 chg->die_health = val->intval;
1508 power_supply_changed(chg->batt_psy);
1509 break;
Anirudh Ghayaldfdb8412018-04-21 10:37:18 +05301510 case POWER_SUPPLY_PROP_RECHARGE_SOC:
1511 if (chg->smb_version == PMI632_SUBTYPE) {
1512 /* toggle charging to force recharge */
1513 vote(chg->chg_disable_votable, FORCE_RECHARGE_VOTER,
1514 true, 0);
1515 /* charge disable delay */
1516 msleep(50);
1517 vote(chg->chg_disable_votable, FORCE_RECHARGE_VOTER,
1518 false, 0);
1519 }
1520 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001521 default:
1522 rc = -EINVAL;
1523 }
1524
1525 return rc;
1526}
1527
1528static int smb5_batt_prop_is_writeable(struct power_supply *psy,
1529 enum power_supply_property psp)
1530{
1531 switch (psp) {
1532 case POWER_SUPPLY_PROP_STATUS:
1533 case POWER_SUPPLY_PROP_INPUT_SUSPEND:
1534 case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL:
1535 case POWER_SUPPLY_PROP_CAPACITY:
1536 case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
1537 case POWER_SUPPLY_PROP_DP_DM:
1538 case POWER_SUPPLY_PROP_RERUN_AICL:
1539 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
1540 case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
1541 case POWER_SUPPLY_PROP_SW_JEITA_ENABLED:
1542 case POWER_SUPPLY_PROP_DIE_HEALTH:
Anirudh Ghayaldfdb8412018-04-21 10:37:18 +05301543 case POWER_SUPPLY_PROP_BATTERY_CHARGING_ENABLED:
Harry Yang4b7db0f2017-11-27 10:50:44 -08001544 return 1;
1545 default:
1546 break;
1547 }
1548
1549 return 0;
1550}
1551
1552static const struct power_supply_desc batt_psy_desc = {
1553 .name = "battery",
1554 .type = POWER_SUPPLY_TYPE_BATTERY,
1555 .properties = smb5_batt_props,
1556 .num_properties = ARRAY_SIZE(smb5_batt_props),
1557 .get_property = smb5_batt_get_prop,
1558 .set_property = smb5_batt_set_prop,
1559 .property_is_writeable = smb5_batt_prop_is_writeable,
1560};
1561
1562static int smb5_init_batt_psy(struct smb5 *chip)
1563{
1564 struct power_supply_config batt_cfg = {};
1565 struct smb_charger *chg = &chip->chg;
1566 int rc = 0;
1567
1568 batt_cfg.drv_data = chg;
1569 batt_cfg.of_node = chg->dev->of_node;
1570 chg->batt_psy = devm_power_supply_register(chg->dev,
1571 &batt_psy_desc,
1572 &batt_cfg);
1573 if (IS_ERR(chg->batt_psy)) {
1574 pr_err("Couldn't register battery power supply\n");
1575 return PTR_ERR(chg->batt_psy);
1576 }
1577
1578 return rc;
1579}
1580
1581/******************************
1582 * VBUS REGULATOR REGISTRATION *
1583 ******************************/
1584
1585static struct regulator_ops smb5_vbus_reg_ops = {
1586 .enable = smblib_vbus_regulator_enable,
1587 .disable = smblib_vbus_regulator_disable,
1588 .is_enabled = smblib_vbus_regulator_is_enabled,
1589};
1590
1591static int smb5_init_vbus_regulator(struct smb5 *chip)
1592{
1593 struct smb_charger *chg = &chip->chg;
1594 struct regulator_config cfg = {};
1595 int rc = 0;
1596
1597 chg->vbus_vreg = devm_kzalloc(chg->dev, sizeof(*chg->vbus_vreg),
1598 GFP_KERNEL);
1599 if (!chg->vbus_vreg)
1600 return -ENOMEM;
1601
1602 cfg.dev = chg->dev;
1603 cfg.driver_data = chip;
1604
1605 chg->vbus_vreg->rdesc.owner = THIS_MODULE;
1606 chg->vbus_vreg->rdesc.type = REGULATOR_VOLTAGE;
1607 chg->vbus_vreg->rdesc.ops = &smb5_vbus_reg_ops;
1608 chg->vbus_vreg->rdesc.of_match = "qcom,smb5-vbus";
1609 chg->vbus_vreg->rdesc.name = "qcom,smb5-vbus";
1610
1611 chg->vbus_vreg->rdev = devm_regulator_register(chg->dev,
1612 &chg->vbus_vreg->rdesc, &cfg);
1613 if (IS_ERR(chg->vbus_vreg->rdev)) {
1614 rc = PTR_ERR(chg->vbus_vreg->rdev);
1615 chg->vbus_vreg->rdev = NULL;
1616 if (rc != -EPROBE_DEFER)
1617 pr_err("Couldn't register VBUS regulator rc=%d\n", rc);
1618 }
1619
1620 return rc;
1621}
1622
1623/******************************
1624 * VCONN REGULATOR REGISTRATION *
1625 ******************************/
1626
1627static struct regulator_ops smb5_vconn_reg_ops = {
1628 .enable = smblib_vconn_regulator_enable,
1629 .disable = smblib_vconn_regulator_disable,
1630 .is_enabled = smblib_vconn_regulator_is_enabled,
1631};
1632
1633static int smb5_init_vconn_regulator(struct smb5 *chip)
1634{
1635 struct smb_charger *chg = &chip->chg;
1636 struct regulator_config cfg = {};
1637 int rc = 0;
1638
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301639 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
Harry Yang4b7db0f2017-11-27 10:50:44 -08001640 return 0;
1641
1642 chg->vconn_vreg = devm_kzalloc(chg->dev, sizeof(*chg->vconn_vreg),
1643 GFP_KERNEL);
1644 if (!chg->vconn_vreg)
1645 return -ENOMEM;
1646
1647 cfg.dev = chg->dev;
1648 cfg.driver_data = chip;
1649
1650 chg->vconn_vreg->rdesc.owner = THIS_MODULE;
1651 chg->vconn_vreg->rdesc.type = REGULATOR_VOLTAGE;
1652 chg->vconn_vreg->rdesc.ops = &smb5_vconn_reg_ops;
1653 chg->vconn_vreg->rdesc.of_match = "qcom,smb5-vconn";
1654 chg->vconn_vreg->rdesc.name = "qcom,smb5-vconn";
1655
1656 chg->vconn_vreg->rdev = devm_regulator_register(chg->dev,
1657 &chg->vconn_vreg->rdesc, &cfg);
1658 if (IS_ERR(chg->vconn_vreg->rdev)) {
1659 rc = PTR_ERR(chg->vconn_vreg->rdev);
1660 chg->vconn_vreg->rdev = NULL;
1661 if (rc != -EPROBE_DEFER)
1662 pr_err("Couldn't register VCONN regulator rc=%d\n", rc);
1663 }
1664
1665 return rc;
1666}
1667
1668/***************************
1669 * HARDWARE INITIALIZATION *
1670 ***************************/
1671static int smb5_configure_typec(struct smb_charger *chg)
1672{
1673 int rc;
Ashay Jaiswal91d63f42018-05-16 11:30:40 +05301674 u8 val = 0;
1675
1676 rc = smblib_read(chg, LEGACY_CABLE_STATUS_REG, &val);
1677 if (rc < 0) {
1678 dev_err(chg->dev, "Couldn't read Legacy status rc=%d\n", rc);
1679 return rc;
1680 }
1681 /*
1682 * If Legacy cable is detected re-trigger Legacy detection
1683 * by disabling/enabling typeC mode.
1684 */
1685 if (val & TYPEC_LEGACY_CABLE_STATUS_BIT) {
1686 rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
1687 TYPEC_DISABLE_CMD_BIT, TYPEC_DISABLE_CMD_BIT);
1688 if (rc < 0) {
1689 dev_err(chg->dev, "Couldn't disable TYPEC rc=%d\n", rc);
1690 return rc;
1691 }
1692
1693 /* delay before enabling typeC */
1694 msleep(500);
1695
1696 rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
1697 TYPEC_DISABLE_CMD_BIT, 0);
1698 if (rc < 0) {
1699 dev_err(chg->dev, "Couldn't enable TYPEC rc=%d\n", rc);
1700 return rc;
1701 }
1702 }
Harry Yang4b7db0f2017-11-27 10:50:44 -08001703
Harry Yang6afaea22018-03-26 19:11:07 -07001704 /* disable apsd */
Ashay Jaiswalc96380de2018-05-16 12:02:36 +05301705 rc = smblib_configure_hvdcp_apsd(chg, false);
Harry Yang6afaea22018-03-26 19:11:07 -07001706 if (rc < 0) {
1707 dev_err(chg->dev, "Couldn't disable APSD rc=%d\n", rc);
1708 return rc;
1709 }
1710
Harry Yang4b7db0f2017-11-27 10:50:44 -08001711 rc = smblib_write(chg, TYPE_C_INTERRUPT_EN_CFG_1_REG,
1712 TYPEC_CCOUT_DETACH_INT_EN_BIT |
1713 TYPEC_CCOUT_ATTACH_INT_EN_BIT);
1714 if (rc < 0) {
1715 dev_err(chg->dev,
1716 "Couldn't configure Type-C interrupts rc=%d\n", rc);
1717 return rc;
1718 }
1719
Harry Yang423d5c32018-05-30 15:49:04 -07001720 rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
1721 EN_TRY_SNK_BIT, EN_TRY_SNK_BIT);
1722 if (rc < 0) {
1723 dev_err(chg->dev,
1724 "Couldn't enable try.snk rc=%d\n", rc);
1725 return rc;
1726 }
1727
Ashay Jaiswald5022b62018-05-27 19:21:11 +05301728 /* Keep VCONN in h/w controlled mode for PMI632 */
1729 if (chg->smb_version != PMI632_SUBTYPE) {
1730 /* configure VCONN for software control */
1731 rc = smblib_masked_write(chg, TYPE_C_VCONN_CONTROL_REG,
Harry Yang4b7db0f2017-11-27 10:50:44 -08001732 VCONN_EN_SRC_BIT | VCONN_EN_VALUE_BIT,
1733 VCONN_EN_SRC_BIT);
Ashay Jaiswald5022b62018-05-27 19:21:11 +05301734 if (rc < 0) {
1735 dev_err(chg->dev,
1736 "Couldn't configure VCONN for SW control rc=%d\n",
1737 rc);
1738 return rc;
1739 }
Harry Yang4b7db0f2017-11-27 10:50:44 -08001740 }
1741
1742 return rc;
1743}
1744
1745static int smb5_configure_micro_usb(struct smb_charger *chg)
1746{
1747 int rc;
1748
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301749 rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG,
1750 MICRO_USB_STATE_CHANGE_INT_EN_BIT,
1751 MICRO_USB_STATE_CHANGE_INT_EN_BIT);
1752 if (rc < 0) {
1753 dev_err(chg->dev,
1754 "Couldn't configure Type-C interrupts rc=%d\n", rc);
1755 return rc;
1756 }
1757
Umang Agrawal461e9ea2018-07-05 18:50:13 +05301758 if (chg->moisture_protection_enabled &&
1759 (chg->wa_flags & MOISTURE_PROTECTION_WA)) {
1760 /* Enable moisture detection interrupt */
1761 rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG,
1762 TYPEC_WATER_DETECTION_INT_EN_BIT,
1763 TYPEC_WATER_DETECTION_INT_EN_BIT);
1764 if (rc < 0) {
1765 dev_err(chg->dev, "Couldn't enable moisture detection interrupt rc=%d\n",
1766 rc);
1767 return rc;
1768 }
1769
1770 /* Enable uUSB factory mode */
1771 rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG,
1772 EN_MICRO_USB_FACTORY_MODE_BIT,
1773 EN_MICRO_USB_FACTORY_MODE_BIT);
1774 if (rc < 0) {
1775 dev_err(chg->dev, "Couldn't enable uUSB factory mode c=%d\n",
1776 rc);
1777 return rc;
1778 }
1779
1780 /* Disable periodic monitoring of CC_ID pin */
1781 rc = smblib_write(chg, TYPEC_U_USB_WATER_PROTECTION_CFG_REG, 0);
1782 if (rc < 0) {
1783 dev_err(chg->dev, "Couldn't disable periodic monitoring of CC_ID rc=%d\n",
1784 rc);
1785 return rc;
1786 }
1787 }
1788
Harry Yang4b7db0f2017-11-27 10:50:44 -08001789 return rc;
1790}
1791
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +05301792static int smb5_configure_mitigation(struct smb_charger *chg)
1793{
1794 int rc;
Ashay Jaiswal40b66272018-09-03 16:08:54 +05301795 u8 chan = 0, src_cfg = 0;
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +05301796
1797 if (!chg->hw_die_temp_mitigation && !chg->hw_connector_mitigation)
1798 return 0;
1799
1800 if (chg->hw_die_temp_mitigation) {
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +05301801 chan = DIE_TEMP_CHANNEL_EN_BIT;
Ashay Jaiswal40b66272018-09-03 16:08:54 +05301802 src_cfg = THERMREG_DIE_ADC_SRC_EN_BIT
1803 | THERMREG_DIE_CMP_SRC_EN_BIT;
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +05301804 }
1805
Ashay Jaiswal40b66272018-09-03 16:08:54 +05301806 if (chg->hw_connector_mitigation) {
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +05301807 chan |= CONN_THM_CHANNEL_EN_BIT;
Ashay Jaiswal40b66272018-09-03 16:08:54 +05301808 src_cfg |= THERMREG_CONNECTOR_ADC_SRC_EN_BIT;
1809 }
1810
1811 rc = smblib_masked_write(chg, MISC_THERMREG_SRC_CFG_REG,
1812 THERMREG_SW_ICL_ADJUST_BIT | THERMREG_DIE_ADC_SRC_EN_BIT
1813 | THERMREG_DIE_CMP_SRC_EN_BIT
1814 | THERMREG_CONNECTOR_ADC_SRC_EN_BIT, src_cfg);
1815 if (rc < 0) {
1816 dev_err(chg->dev,
1817 "Couldn't configure THERM_SRC reg rc=%d\n", rc);
1818 return rc;
1819 };
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +05301820
1821 rc = smblib_masked_write(chg, BATIF_ADC_CHANNEL_EN_REG,
1822 CONN_THM_CHANNEL_EN_BIT | DIE_TEMP_CHANNEL_EN_BIT,
1823 chan);
1824 if (rc < 0) {
Ashay Jaiswalb50706d2018-06-28 19:37:31 +05301825 dev_err(chg->dev, "Couldn't enable ADC channel rc=%d\n", rc);
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +05301826 return rc;
1827 }
1828
1829 return 0;
1830}
1831
Ashay Jaiswald802c3d2018-07-25 14:55:10 +05301832#define RAW_TERM_CURR(conv_factor, scaled_ma) \
1833 div_s64((int64_t)scaled_ma * 10000, conv_factor)
1834#define ITERM_LIMITS_PMI632_MA 5000
1835#define ITERM_LIMITS_PM855B_MA 10000
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001836static int smb5_configure_iterm_thresholds_adc(struct smb5 *chip)
1837{
Guru Das Srinagesh31b2bb02018-06-20 15:44:03 -07001838 u8 *buf;
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001839 int rc = 0;
Ashay Jaiswald802c3d2018-07-25 14:55:10 +05301840 int raw_hi_thresh, raw_lo_thresh, max_limit_ma, scaling_factor;
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001841 struct smb_charger *chg = &chip->chg;
1842
Ashay Jaiswald802c3d2018-07-25 14:55:10 +05301843 if (chip->chg.smb_version == PMI632_SUBTYPE) {
1844 scaling_factor = ITERM_SCALING_FACTOR_PMI632;
1845 max_limit_ma = ITERM_LIMITS_PMI632_MA;
1846 } else {
1847 scaling_factor = ITERM_SCALING_FACTOR_PM855B;
1848 max_limit_ma = ITERM_LIMITS_PM855B_MA;
1849 }
1850
1851 if (chip->dt.term_current_thresh_hi_ma < (-1 * max_limit_ma)
1852 || chip->dt.term_current_thresh_hi_ma > max_limit_ma
1853 || chip->dt.term_current_thresh_lo_ma < (-1 * max_limit_ma)
1854 || chip->dt.term_current_thresh_lo_ma > max_limit_ma) {
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001855 dev_err(chg->dev, "ITERM threshold out of range rc=%d\n", rc);
1856 return -EINVAL;
1857 }
1858
1859 /*
1860 * Conversion:
Ashay Jaiswald802c3d2018-07-25 14:55:10 +05301861 * raw (A) = (scaled_mA * (10000) / conv_factor)
Guru Das Srinagesh31b2bb02018-06-20 15:44:03 -07001862 * Note: raw needs to be converted to big-endian format.
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001863 */
1864
1865 if (chip->dt.term_current_thresh_hi_ma) {
Ashay Jaiswald802c3d2018-07-25 14:55:10 +05301866 raw_hi_thresh = RAW_TERM_CURR(scaling_factor,
1867 chip->dt.term_current_thresh_hi_ma);
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001868 raw_hi_thresh = sign_extend32(raw_hi_thresh, 15);
Guru Das Srinagesh31b2bb02018-06-20 15:44:03 -07001869 buf = (u8 *)&raw_hi_thresh;
1870 raw_hi_thresh = buf[1] | (buf[0] << 8);
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001871
1872 rc = smblib_batch_write(chg, CHGR_ADC_ITERM_UP_THD_MSB_REG,
1873 (u8 *)&raw_hi_thresh, 2);
1874 if (rc < 0) {
1875 dev_err(chg->dev, "Couldn't configure ITERM threshold HIGH rc=%d\n",
1876 rc);
1877 return rc;
1878 }
1879 }
1880
1881 if (chip->dt.term_current_thresh_lo_ma) {
Ashay Jaiswald802c3d2018-07-25 14:55:10 +05301882 raw_lo_thresh = RAW_TERM_CURR(scaling_factor,
1883 chip->dt.term_current_thresh_lo_ma);
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001884 raw_lo_thresh = sign_extend32(raw_lo_thresh, 15);
Guru Das Srinagesh31b2bb02018-06-20 15:44:03 -07001885 buf = (u8 *)&raw_lo_thresh;
1886 raw_lo_thresh = buf[1] | (buf[0] << 8);
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001887
1888 rc = smblib_batch_write(chg, CHGR_ADC_ITERM_LO_THD_MSB_REG,
1889 (u8 *)&raw_lo_thresh, 2);
1890 if (rc < 0) {
1891 dev_err(chg->dev, "Couldn't configure ITERM threshold LOW rc=%d\n",
1892 rc);
1893 return rc;
1894 }
1895 }
1896
1897 return rc;
1898}
1899
1900static int smb5_configure_iterm_thresholds(struct smb5 *chip)
1901{
1902 int rc = 0;
1903
1904 switch (chip->dt.term_current_src) {
1905 case ITERM_SRC_ADC:
1906 rc = smb5_configure_iterm_thresholds_adc(chip);
1907 break;
1908 default:
1909 break;
1910 }
1911
1912 return rc;
1913}
1914
Harry Yang4b7db0f2017-11-27 10:50:44 -08001915static int smb5_init_hw(struct smb5 *chip)
1916{
1917 struct smb_charger *chg = &chip->chg;
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301918 int rc, type = 0;
1919 u8 val = 0;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001920
1921 if (chip->dt.no_battery)
1922 chg->fake_capacity = 50;
1923
1924 if (chip->dt.batt_profile_fcc_ua < 0)
1925 smblib_get_charge_param(chg, &chg->param.fcc,
1926 &chg->batt_profile_fcc_ua);
1927
1928 if (chip->dt.batt_profile_fv_uv < 0)
1929 smblib_get_charge_param(chg, &chg->param.fv,
1930 &chg->batt_profile_fv_uv);
1931
1932 smblib_get_charge_param(chg, &chg->param.usb_icl,
1933 &chg->default_icl_ua);
Ashay Jaiswale0b3c472018-06-20 23:39:41 +05301934 smblib_get_charge_param(chg, &chg->param.aicl_5v_threshold,
1935 &chg->default_aicl_5v_threshold_mv);
1936 chg->aicl_5v_threshold_mv = chg->default_aicl_5v_threshold_mv;
1937 smblib_get_charge_param(chg, &chg->param.aicl_cont_threshold,
1938 &chg->default_aicl_cont_threshold_mv);
1939 chg->aicl_cont_threshold_mv = chg->default_aicl_cont_threshold_mv;
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301940
1941 /* Use SW based VBUS control, disable HW autonomous mode */
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301942 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1943 HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT,
1944 HVDCP_AUTH_ALG_EN_CFG_BIT);
1945 if (rc < 0) {
1946 dev_err(chg->dev, "Couldn't configure HVDCP rc=%d\n", rc);
1947 return rc;
1948 }
1949
1950 /*
1951 * PMI632 can have the connector type defined by a dedicated register
1952 * TYPEC_MICRO_USB_MODE_REG or by a common TYPEC_U_USB_CFG_REG.
1953 */
1954 if (chg->smb_version == PMI632_SUBTYPE) {
1955 rc = smblib_read(chg, TYPEC_MICRO_USB_MODE_REG, &val);
1956 if (rc < 0) {
1957 dev_err(chg->dev, "Couldn't read USB mode rc=%d\n", rc);
1958 return rc;
1959 }
1960 type = !!(val & MICRO_USB_MODE_ONLY_BIT);
1961 }
1962
1963 /*
1964 * If TYPEC_MICRO_USB_MODE_REG is not set and for all non-PMI632
1965 * check the connector type using TYPEC_U_USB_CFG_REG.
1966 */
1967 if (!type) {
1968 rc = smblib_read(chg, TYPEC_U_USB_CFG_REG, &val);
1969 if (rc < 0) {
1970 dev_err(chg->dev, "Couldn't read U_USB config rc=%d\n",
1971 rc);
1972 return rc;
1973 }
1974
1975 type = !!(val & EN_MICRO_USB_MODE_BIT);
1976 }
1977
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301978 pr_debug("Connector type=%s\n", type ? "Micro USB" : "TypeC");
1979
Harry Yang6afaea22018-03-26 19:11:07 -07001980 if (type) {
1981 chg->connector_type = POWER_SUPPLY_CONNECTOR_MICRO_USB;
Harry Yang6afaea22018-03-26 19:11:07 -07001982 rc = smb5_configure_micro_usb(chg);
1983 } else {
1984 chg->connector_type = POWER_SUPPLY_CONNECTOR_TYPEC;
1985 rc = smb5_configure_typec(chg);
1986 }
1987 if (rc < 0) {
1988 dev_err(chg->dev,
1989 "Couldn't configure TypeC/micro-USB mode rc=%d\n", rc);
1990 return rc;
1991 }
1992
Ashay Jaiswal09feab82018-02-12 12:33:18 +05301993 /*
1994 * PMI632 based hw init:
Ashay Jaiswal6f70a512018-05-11 17:25:58 +05301995 * - Enable STAT pin function on SMB_EN
Ashay Jaiswalc96380de2018-05-16 12:02:36 +05301996 * - Rerun APSD to ensure proper charger detection if device
1997 * boots with charger connected.
Ashay Jaiswal09feab82018-02-12 12:33:18 +05301998 * - Initialize flash module for PMI632
1999 */
Ashay Jaiswalc96380de2018-05-16 12:02:36 +05302000 if (chg->smb_version == PMI632_SUBTYPE) {
Ashay Jaiswal6f70a512018-05-11 17:25:58 +05302001 rc = smblib_masked_write(chg, MISC_SMB_EN_CMD_REG,
2002 EN_STAT_CMD_BIT, EN_STAT_CMD_BIT);
2003 if (rc < 0) {
2004 dev_err(chg->dev, "Couldn't configure SMB_EN rc=%d\n",
2005 rc);
2006 return rc;
2007 }
2008
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302009 schgm_flash_init(chg);
Ashay Jaiswalc96380de2018-05-16 12:02:36 +05302010 smblib_rerun_apsd_if_required(chg);
2011 }
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302012
Ashay Jaiswalcbdf2e82018-05-27 23:59:01 +05302013 /* clear the ICL override if it is set */
2014 rc = smblib_icl_override(chg, false);
2015 if (rc < 0) {
2016 pr_err("Couldn't disable ICL override rc=%d\n", rc);
2017 return rc;
2018 }
2019
Ashay Jaiswalb2b06fe2018-06-07 18:35:21 +05302020 /* set OTG current limit */
2021 rc = smblib_set_charge_param(chg, &chg->param.otg_cl, chg->otg_cl_ua);
2022 if (rc < 0) {
2023 pr_err("Couldn't set otg current limit rc=%d\n", rc);
2024 return rc;
2025 }
2026
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +05302027 /* configure temperature mitigation */
2028 rc = smb5_configure_mitigation(chg);
2029 if (rc < 0) {
2030 dev_err(chg->dev, "Couldn't configure mitigation rc=%d\n", rc);
2031 return rc;
2032 }
2033
Harry Yang4b7db0f2017-11-27 10:50:44 -08002034 /* vote 0mA on usb_icl for non battery platforms */
2035 vote(chg->usb_icl_votable,
2036 DEFAULT_VOTER, chip->dt.no_battery, 0);
2037 vote(chg->dc_suspend_votable,
2038 DEFAULT_VOTER, chip->dt.no_battery, 0);
2039 vote(chg->fcc_votable, HW_LIMIT_VOTER,
2040 chip->dt.batt_profile_fcc_ua > 0, chip->dt.batt_profile_fcc_ua);
2041 vote(chg->fv_votable, HW_LIMIT_VOTER,
2042 chip->dt.batt_profile_fv_uv > 0, chip->dt.batt_profile_fv_uv);
2043 vote(chg->fcc_votable,
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302044 BATT_PROFILE_VOTER, chg->batt_profile_fcc_ua > 0,
2045 chg->batt_profile_fcc_ua);
Harry Yang4b7db0f2017-11-27 10:50:44 -08002046 vote(chg->fv_votable,
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302047 BATT_PROFILE_VOTER, chg->batt_profile_fv_uv > 0,
2048 chg->batt_profile_fv_uv);
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302049
2050 /* Some h/w limit maximum supported ICL */
2051 vote(chg->usb_icl_votable, HW_LIMIT_VOTER,
2052 chg->hw_max_icl_ua > 0, chg->hw_max_icl_ua);
Harry Yang4b7db0f2017-11-27 10:50:44 -08002053
2054 /*
2055 * AICL configuration:
Ashay Jaiswalc96380de2018-05-16 12:02:36 +05302056 * AICL ADC disable
Harry Yang4b7db0f2017-11-27 10:50:44 -08002057 */
Ashay Jaiswalc96380de2018-05-16 12:02:36 +05302058 if (chg->smb_version != PMI632_SUBTYPE) {
2059 rc = smblib_masked_write(chg, USBIN_AICL_OPTIONS_CFG_REG,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002060 USBIN_AICL_ADC_EN_BIT, 0);
Ashay Jaiswalc96380de2018-05-16 12:02:36 +05302061 if (rc < 0) {
2062 dev_err(chg->dev, "Couldn't config AICL rc=%d\n", rc);
2063 return rc;
2064 }
Harry Yang4b7db0f2017-11-27 10:50:44 -08002065 }
2066
2067 /* enable the charging path */
2068 rc = vote(chg->chg_disable_votable, DEFAULT_VOTER, false, 0);
2069 if (rc < 0) {
2070 dev_err(chg->dev, "Couldn't enable charging rc=%d\n", rc);
2071 return rc;
2072 }
2073
Harry Yang4b7db0f2017-11-27 10:50:44 -08002074 /* configure VBUS for software control */
2075 rc = smblib_masked_write(chg, DCDC_OTG_CFG_REG, OTG_EN_SRC_CFG_BIT, 0);
2076 if (rc < 0) {
2077 dev_err(chg->dev,
2078 "Couldn't configure VBUS for SW control rc=%d\n", rc);
2079 return rc;
2080 }
2081
Ashay Jaiswala55b7ed2018-03-23 17:23:48 +05302082 /*
2083 * configure the one time watchdong periodic interval and
2084 * disable "watchdog bite disable charging".
2085 */
Harry Yang4b7db0f2017-11-27 10:50:44 -08002086 val = (ilog2(chip->dt.wd_bark_time / 16) << BARK_WDOG_TIMEOUT_SHIFT)
2087 & BARK_WDOG_TIMEOUT_MASK;
2088 val |= BITE_WDOG_TIMEOUT_8S;
2089 rc = smblib_masked_write(chg, SNARL_BARK_BITE_WD_CFG_REG,
2090 BITE_WDOG_DISABLE_CHARGING_CFG_BIT |
2091 BARK_WDOG_TIMEOUT_MASK | BITE_WDOG_TIMEOUT_MASK,
2092 val);
2093 if (rc < 0) {
2094 pr_err("Couldn't configue WD config rc=%d\n", rc);
2095 return rc;
2096 }
2097
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07002098 /* set termination current threshold values */
2099 rc = smb5_configure_iterm_thresholds(chip);
2100 if (rc < 0) {
2101 pr_err("Couldn't configure ITERM thresholds rc=%d\n",
2102 rc);
2103 return rc;
2104 }
2105
Harry Yang4b7db0f2017-11-27 10:50:44 -08002106 /* configure float charger options */
2107 switch (chip->dt.float_option) {
2108 case FLOAT_DCP:
2109 rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
2110 FLOAT_OPTIONS_MASK, 0);
2111 break;
2112 case FLOAT_SDP:
2113 rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
2114 FLOAT_OPTIONS_MASK, FORCE_FLOAT_SDP_CFG_BIT);
2115 break;
2116 case DISABLE_CHARGING:
2117 rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
2118 FLOAT_OPTIONS_MASK, FLOAT_DIS_CHGING_CFG_BIT);
2119 break;
2120 case SUSPEND_INPUT:
2121 rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
2122 FLOAT_OPTIONS_MASK, SUSPEND_FLOAT_CFG_BIT);
2123 break;
2124 default:
2125 rc = 0;
2126 break;
2127 }
2128
2129 if (rc < 0) {
2130 dev_err(chg->dev, "Couldn't configure float charger options rc=%d\n",
2131 rc);
2132 return rc;
2133 }
2134
2135 rc = smblib_read(chg, USBIN_OPTIONS_2_CFG_REG, &chg->float_cfg);
2136 if (rc < 0) {
2137 dev_err(chg->dev, "Couldn't read float charger options rc=%d\n",
2138 rc);
2139 return rc;
2140 }
2141
2142 switch (chip->dt.chg_inhibit_thr_mv) {
2143 case 50:
2144 rc = smblib_masked_write(chg, CHARGE_INHIBIT_THRESHOLD_CFG_REG,
2145 CHARGE_INHIBIT_THRESHOLD_MASK,
2146 INHIBIT_ANALOG_VFLT_MINUS_50MV);
2147 break;
2148 case 100:
2149 rc = smblib_masked_write(chg, CHARGE_INHIBIT_THRESHOLD_CFG_REG,
2150 CHARGE_INHIBIT_THRESHOLD_MASK,
2151 INHIBIT_ANALOG_VFLT_MINUS_100MV);
2152 break;
2153 case 200:
2154 rc = smblib_masked_write(chg, CHARGE_INHIBIT_THRESHOLD_CFG_REG,
2155 CHARGE_INHIBIT_THRESHOLD_MASK,
2156 INHIBIT_ANALOG_VFLT_MINUS_200MV);
2157 break;
2158 case 300:
2159 rc = smblib_masked_write(chg, CHARGE_INHIBIT_THRESHOLD_CFG_REG,
2160 CHARGE_INHIBIT_THRESHOLD_MASK,
2161 INHIBIT_ANALOG_VFLT_MINUS_300MV);
2162 break;
2163 case 0:
2164 rc = smblib_masked_write(chg, CHGR_CFG2_REG,
2165 CHARGER_INHIBIT_BIT, 0);
2166 default:
2167 break;
2168 }
2169
2170 if (rc < 0) {
2171 dev_err(chg->dev, "Couldn't configure charge inhibit threshold rc=%d\n",
2172 rc);
2173 return rc;
2174 }
2175
Anirudh Ghayal1380d312018-02-23 00:01:43 +05302176 rc = smblib_masked_write(chg, CHGR_CFG2_REG, RECHG_MASK,
2177 (chip->dt.auto_recharge_vbat_mv != -EINVAL) ?
2178 VBAT_BASED_RECHG_BIT : 0);
Harry Yang4b7db0f2017-11-27 10:50:44 -08002179 if (rc < 0) {
Anirudh Ghayal1380d312018-02-23 00:01:43 +05302180 dev_err(chg->dev, "Couldn't configure VBAT-rechg CHG_CFG2_REG rc=%d\n",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002181 rc);
2182 return rc;
2183 }
2184
Anirudh Ghayal1380d312018-02-23 00:01:43 +05302185 /* program the auto-recharge VBAT threshold */
2186 if (chip->dt.auto_recharge_vbat_mv != -EINVAL) {
2187 u32 temp = VBAT_TO_VRAW_ADC(chip->dt.auto_recharge_vbat_mv);
2188
2189 temp = ((temp & 0xFF00) >> 8) | ((temp & 0xFF) << 8);
2190 rc = smblib_batch_write(chg,
2191 CHGR_ADC_RECHARGE_THRESHOLD_MSB_REG, (u8 *)&temp, 2);
2192 if (rc < 0) {
2193 dev_err(chg->dev, "Couldn't configure ADC_RECHARGE_THRESHOLD REG rc=%d\n",
2194 rc);
2195 return rc;
2196 }
2197 /* Program the sample count for VBAT based recharge to 3 */
2198 rc = smblib_masked_write(chg, CHGR_NO_SAMPLE_TERM_RCHG_CFG_REG,
2199 NO_OF_SAMPLE_FOR_RCHG,
2200 2 << NO_OF_SAMPLE_FOR_RCHG_SHIFT);
2201 if (rc < 0) {
2202 dev_err(chg->dev, "Couldn't configure CHGR_NO_SAMPLE_FOR_TERM_RCHG_CFG rc=%d\n",
2203 rc);
2204 return rc;
2205 }
2206 }
2207
2208 rc = smblib_masked_write(chg, CHGR_CFG2_REG, RECHG_MASK,
2209 (chip->dt.auto_recharge_soc != -EINVAL) ?
2210 SOC_BASED_RECHG_BIT : VBAT_BASED_RECHG_BIT);
2211 if (rc < 0) {
2212 dev_err(chg->dev, "Couldn't configure SOC-rechg CHG_CFG2_REG rc=%d\n",
2213 rc);
2214 return rc;
2215 }
2216
2217 /* program the auto-recharge threshold */
2218 if (chip->dt.auto_recharge_soc != -EINVAL) {
2219 rc = smblib_write(chg, CHARGE_RCHG_SOC_THRESHOLD_CFG_REG,
2220 (chip->dt.auto_recharge_soc * 255) / 100);
2221 if (rc < 0) {
2222 dev_err(chg->dev, "Couldn't configure CHG_RCHG_SOC_REG rc=%d\n",
2223 rc);
2224 return rc;
2225 }
2226 /* Program the sample count for SOC based recharge to 1 */
2227 rc = smblib_masked_write(chg, CHGR_NO_SAMPLE_TERM_RCHG_CFG_REG,
2228 NO_OF_SAMPLE_FOR_RCHG, 0);
2229 if (rc < 0) {
2230 dev_err(chg->dev, "Couldn't configure CHGR_NO_SAMPLE_FOR_TERM_RCHG_CFG rc=%d\n",
2231 rc);
2232 return rc;
2233 }
2234 }
2235
Harry Yang4b7db0f2017-11-27 10:50:44 -08002236 if (chg->sw_jeita_enabled) {
2237 rc = smblib_disable_hw_jeita(chg, true);
2238 if (rc < 0) {
2239 dev_err(chg->dev, "Couldn't set hw jeita rc=%d\n", rc);
2240 return rc;
2241 }
2242 }
2243
Ashay Jaiswala55b7ed2018-03-23 17:23:48 +05302244 rc = smblib_configure_wdog(chg,
2245 chg->step_chg_enabled || chg->sw_jeita_enabled);
2246 if (rc < 0) {
2247 dev_err(chg->dev, "Couldn't configure watchdog rc=%d\n",
2248 rc);
2249 return rc;
2250 }
2251
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +05302252 if (chg->connector_pull_up != -EINVAL) {
2253 rc = smb5_configure_internal_pull(chg, CONN_THERM,
2254 get_valid_pullup(chg->connector_pull_up));
2255 if (rc < 0) {
2256 dev_err(chg->dev,
2257 "Couldn't configure CONN_THERM pull-up rc=%d\n",
2258 rc);
2259 return rc;
2260 }
2261 }
2262
Harry Yang4b7db0f2017-11-27 10:50:44 -08002263 return rc;
2264}
2265
2266static int smb5_post_init(struct smb5 *chip)
2267{
2268 struct smb_charger *chg = &chip->chg;
2269 union power_supply_propval pval;
2270 int rc;
2271
2272 /*
2273 * In case the usb path is suspended, we would have missed disabling
2274 * the icl change interrupt because the interrupt could have been
2275 * not requested
2276 */
2277 rerun_election(chg->usb_icl_votable);
2278
2279 /* configure power role for dual-role */
2280 pval.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
2281 rc = smblib_set_prop_typec_power_role(chg, &pval);
2282 if (rc < 0) {
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302283 dev_err(chg->dev, "Couldn't configure DRP role rc=%d\n",
2284 rc);
Harry Yang4b7db0f2017-11-27 10:50:44 -08002285 return rc;
2286 }
2287
2288 rerun_election(chg->usb_irq_enable_votable);
2289
2290 return 0;
2291}
2292
2293/****************************
2294 * DETERMINE INITIAL STATUS *
2295 ****************************/
2296
2297static int smb5_determine_initial_status(struct smb5 *chip)
2298{
2299 struct smb_irq_data irq_data = {chip, "determine-initial-status"};
2300 struct smb_charger *chg = &chip->chg;
Harry Yang6afaea22018-03-26 19:11:07 -07002301 union power_supply_propval val;
2302 int rc;
2303
2304 rc = smblib_get_prop_usb_present(chg, &val);
2305 if (rc < 0) {
2306 pr_err("Couldn't get usb present rc=%d\n", rc);
2307 return rc;
2308 }
2309 chg->early_usb_attach = val.intval;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002310
2311 if (chg->bms_psy)
2312 smblib_suspend_on_debug_battery(chg);
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302313
Harry Yang4b7db0f2017-11-27 10:50:44 -08002314 usb_plugin_irq_handler(0, &irq_data);
Harry Yang6afaea22018-03-26 19:11:07 -07002315 typec_attach_detach_irq_handler(0, &irq_data);
Harry Yang4b7db0f2017-11-27 10:50:44 -08002316 typec_state_change_irq_handler(0, &irq_data);
2317 usb_source_change_irq_handler(0, &irq_data);
2318 chg_state_change_irq_handler(0, &irq_data);
2319 icl_change_irq_handler(0, &irq_data);
2320 batt_temp_changed_irq_handler(0, &irq_data);
2321 wdog_bark_irq_handler(0, &irq_data);
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302322 typec_or_rid_detection_change_irq_handler(0, &irq_data);
Harry Yang4b7db0f2017-11-27 10:50:44 -08002323
2324 return 0;
2325}
2326
2327/**************************
2328 * INTERRUPT REGISTRATION *
2329 **************************/
2330
2331static struct smb_irq_info smb5_irqs[] = {
2332 /* CHARGER IRQs */
2333 [CHGR_ERROR_IRQ] = {
2334 .name = "chgr-error",
2335 .handler = default_irq_handler,
2336 },
2337 [CHG_STATE_CHANGE_IRQ] = {
2338 .name = "chg-state-change",
2339 .handler = chg_state_change_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302340 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002341 },
2342 [STEP_CHG_STATE_CHANGE_IRQ] = {
2343 .name = "step-chg-state-change",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002344 },
2345 [STEP_CHG_SOC_UPDATE_FAIL_IRQ] = {
2346 .name = "step-chg-soc-update-fail",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002347 },
2348 [STEP_CHG_SOC_UPDATE_REQ_IRQ] = {
2349 .name = "step-chg-soc-update-req",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002350 },
2351 [FG_FVCAL_QUALIFIED_IRQ] = {
2352 .name = "fg-fvcal-qualified",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002353 },
2354 [VPH_ALARM_IRQ] = {
2355 .name = "vph-alarm",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002356 },
2357 [VPH_DROP_PRECHG_IRQ] = {
2358 .name = "vph-drop-prechg",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002359 },
2360 /* DCDC IRQs */
2361 [OTG_FAIL_IRQ] = {
2362 .name = "otg-fail",
2363 .handler = default_irq_handler,
2364 },
2365 [OTG_OC_DISABLE_SW_IRQ] = {
2366 .name = "otg-oc-disable-sw",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002367 },
2368 [OTG_OC_HICCUP_IRQ] = {
2369 .name = "otg-oc-hiccup",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002370 },
2371 [BSM_ACTIVE_IRQ] = {
2372 .name = "bsm-active",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002373 },
2374 [HIGH_DUTY_CYCLE_IRQ] = {
2375 .name = "high-duty-cycle",
2376 .handler = high_duty_cycle_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302377 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002378 },
2379 [INPUT_CURRENT_LIMITING_IRQ] = {
2380 .name = "input-current-limiting",
2381 .handler = default_irq_handler,
2382 },
2383 [CONCURRENT_MODE_DISABLE_IRQ] = {
2384 .name = "concurrent-mode-disable",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002385 },
2386 [SWITCHER_POWER_OK_IRQ] = {
2387 .name = "switcher-power-ok",
2388 .handler = switcher_power_ok_irq_handler,
2389 },
2390 /* BATTERY IRQs */
2391 [BAT_TEMP_IRQ] = {
2392 .name = "bat-temp",
2393 .handler = batt_temp_changed_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302394 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002395 },
2396 [ALL_CHNL_CONV_DONE_IRQ] = {
2397 .name = "all-chnl-conv-done",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002398 },
2399 [BAT_OV_IRQ] = {
2400 .name = "bat-ov",
2401 .handler = batt_psy_changed_irq_handler,
2402 },
2403 [BAT_LOW_IRQ] = {
2404 .name = "bat-low",
2405 .handler = batt_psy_changed_irq_handler,
2406 },
2407 [BAT_THERM_OR_ID_MISSING_IRQ] = {
2408 .name = "bat-therm-or-id-missing",
2409 .handler = batt_psy_changed_irq_handler,
2410 },
2411 [BAT_TERMINAL_MISSING_IRQ] = {
2412 .name = "bat-terminal-missing",
2413 .handler = batt_psy_changed_irq_handler,
2414 },
2415 [BUCK_OC_IRQ] = {
2416 .name = "buck-oc",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002417 },
2418 [VPH_OV_IRQ] = {
2419 .name = "vph-ov",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002420 },
2421 /* USB INPUT IRQs */
2422 [USBIN_COLLAPSE_IRQ] = {
2423 .name = "usbin-collapse",
2424 .handler = default_irq_handler,
2425 },
2426 [USBIN_VASHDN_IRQ] = {
2427 .name = "usbin-vashdn",
2428 .handler = default_irq_handler,
2429 },
2430 [USBIN_UV_IRQ] = {
2431 .name = "usbin-uv",
2432 .handler = usbin_uv_irq_handler,
Ashay Jaiswale0b3c472018-06-20 23:39:41 +05302433 .wake = true,
2434 .storm_data = {true, 3000, 5},
Harry Yang4b7db0f2017-11-27 10:50:44 -08002435 },
2436 [USBIN_OV_IRQ] = {
2437 .name = "usbin-ov",
Ashay Jaiswal43107092018-08-20 18:59:28 +05302438 .handler = usbin_ov_irq_handler,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002439 },
2440 [USBIN_PLUGIN_IRQ] = {
2441 .name = "usbin-plugin",
2442 .handler = usb_plugin_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302443 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002444 },
2445 [USBIN_REVI_CHANGE_IRQ] = {
2446 .name = "usbin-revi-change",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002447 },
2448 [USBIN_SRC_CHANGE_IRQ] = {
2449 .name = "usbin-src-change",
2450 .handler = usb_source_change_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302451 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002452 },
2453 [USBIN_ICL_CHANGE_IRQ] = {
2454 .name = "usbin-icl-change",
2455 .handler = icl_change_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302456 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002457 },
2458 /* DC INPUT IRQs */
2459 [DCIN_VASHDN_IRQ] = {
2460 .name = "dcin-vashdn",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002461 },
2462 [DCIN_UV_IRQ] = {
2463 .name = "dcin-uv",
2464 .handler = default_irq_handler,
2465 },
2466 [DCIN_OV_IRQ] = {
2467 .name = "dcin-ov",
2468 .handler = default_irq_handler,
2469 },
2470 [DCIN_PLUGIN_IRQ] = {
2471 .name = "dcin-plugin",
2472 .handler = dc_plugin_irq_handler,
2473 .wake = true,
2474 },
2475 [DCIN_REVI_IRQ] = {
2476 .name = "dcin-revi",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002477 },
2478 [DCIN_PON_IRQ] = {
2479 .name = "dcin-pon",
2480 .handler = default_irq_handler,
2481 },
2482 [DCIN_EN_IRQ] = {
2483 .name = "dcin-en",
2484 .handler = default_irq_handler,
2485 },
2486 /* TYPEC IRQs */
2487 [TYPEC_OR_RID_DETECTION_CHANGE_IRQ] = {
2488 .name = "typec-or-rid-detect-change",
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302489 .handler = typec_or_rid_detection_change_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302490 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002491 },
2492 [TYPEC_VPD_DETECT_IRQ] = {
2493 .name = "typec-vpd-detect",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002494 },
2495 [TYPEC_CC_STATE_CHANGE_IRQ] = {
2496 .name = "typec-cc-state-change",
2497 .handler = typec_state_change_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302498 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002499 },
2500 [TYPEC_VCONN_OC_IRQ] = {
2501 .name = "typec-vconn-oc",
2502 .handler = default_irq_handler,
2503 },
2504 [TYPEC_VBUS_CHANGE_IRQ] = {
2505 .name = "typec-vbus-change",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002506 },
2507 [TYPEC_ATTACH_DETACH_IRQ] = {
2508 .name = "typec-attach-detach",
Harry Yang6afaea22018-03-26 19:11:07 -07002509 .handler = typec_attach_detach_irq_handler,
Guru Das Srinageshdcd65ed2018-08-14 15:39:35 +05302510 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002511 },
2512 [TYPEC_LEGACY_CABLE_DETECT_IRQ] = {
2513 .name = "typec-legacy-cable-detect",
2514 .handler = default_irq_handler,
2515 },
2516 [TYPEC_TRY_SNK_SRC_DETECT_IRQ] = {
2517 .name = "typec-try-snk-src-detect",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002518 },
2519 /* MISCELLANEOUS IRQs */
2520 [WDOG_SNARL_IRQ] = {
2521 .name = "wdog-snarl",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002522 },
2523 [WDOG_BARK_IRQ] = {
2524 .name = "wdog-bark",
2525 .handler = wdog_bark_irq_handler,
Ashay Jaiswala55b7ed2018-03-23 17:23:48 +05302526 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002527 },
2528 [AICL_FAIL_IRQ] = {
2529 .name = "aicl-fail",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002530 },
2531 [AICL_DONE_IRQ] = {
2532 .name = "aicl-done",
2533 .handler = default_irq_handler,
2534 },
2535 [SMB_EN_IRQ] = {
2536 .name = "smb-en",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002537 },
2538 [IMP_TRIGGER_IRQ] = {
2539 .name = "imp-trigger",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002540 },
2541 [TEMP_CHANGE_IRQ] = {
2542 .name = "temp-change",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002543 },
2544 [TEMP_CHANGE_SMB_IRQ] = {
2545 .name = "temp-change-smb",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002546 },
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302547 /* FLASH */
2548 [VREG_OK_IRQ] = {
2549 .name = "vreg-ok",
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302550 },
2551 [ILIM_S2_IRQ] = {
2552 .name = "ilim2-s2",
2553 .handler = schgm_flash_ilim2_irq_handler,
2554 },
2555 [ILIM_S1_IRQ] = {
2556 .name = "ilim1-s1",
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302557 },
2558 [VOUT_DOWN_IRQ] = {
2559 .name = "vout-down",
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302560 },
2561 [VOUT_UP_IRQ] = {
2562 .name = "vout-up",
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302563 },
2564 [FLASH_STATE_CHANGE_IRQ] = {
2565 .name = "flash-state-change",
2566 .handler = schgm_flash_state_change_irq_handler,
2567 },
2568 [TORCH_REQ_IRQ] = {
2569 .name = "torch-req",
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302570 },
2571 [FLASH_EN_IRQ] = {
2572 .name = "flash-en",
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302573 },
Harry Yang4b7db0f2017-11-27 10:50:44 -08002574};
2575
2576static int smb5_get_irq_index_byname(const char *irq_name)
2577{
2578 int i;
2579
2580 for (i = 0; i < ARRAY_SIZE(smb5_irqs); i++) {
2581 if (strcmp(smb5_irqs[i].name, irq_name) == 0)
2582 return i;
2583 }
2584
2585 return -ENOENT;
2586}
2587
2588static int smb5_request_interrupt(struct smb5 *chip,
2589 struct device_node *node, const char *irq_name)
2590{
2591 struct smb_charger *chg = &chip->chg;
2592 int rc, irq, irq_index;
2593 struct smb_irq_data *irq_data;
2594
2595 irq = of_irq_get_byname(node, irq_name);
2596 if (irq < 0) {
2597 pr_err("Couldn't get irq %s byname\n", irq_name);
2598 return irq;
2599 }
2600
2601 irq_index = smb5_get_irq_index_byname(irq_name);
2602 if (irq_index < 0) {
2603 pr_err("%s is not a defined irq\n", irq_name);
2604 return irq_index;
2605 }
2606
2607 if (!smb5_irqs[irq_index].handler)
2608 return 0;
2609
2610 irq_data = devm_kzalloc(chg->dev, sizeof(*irq_data), GFP_KERNEL);
2611 if (!irq_data)
2612 return -ENOMEM;
2613
2614 irq_data->parent_data = chip;
2615 irq_data->name = irq_name;
2616 irq_data->storm_data = smb5_irqs[irq_index].storm_data;
2617 mutex_init(&irq_data->storm_data.storm_lock);
2618
2619 rc = devm_request_threaded_irq(chg->dev, irq, NULL,
2620 smb5_irqs[irq_index].handler,
2621 IRQF_ONESHOT, irq_name, irq_data);
2622 if (rc < 0) {
2623 pr_err("Couldn't request irq %d\n", irq);
2624 return rc;
2625 }
2626
2627 smb5_irqs[irq_index].irq = irq;
2628 smb5_irqs[irq_index].irq_data = irq_data;
2629 if (smb5_irqs[irq_index].wake)
2630 enable_irq_wake(irq);
2631
2632 return rc;
2633}
2634
2635static int smb5_request_interrupts(struct smb5 *chip)
2636{
2637 struct smb_charger *chg = &chip->chg;
2638 struct device_node *node = chg->dev->of_node;
2639 struct device_node *child;
2640 int rc = 0;
2641 const char *name;
2642 struct property *prop;
2643
2644 for_each_available_child_of_node(node, child) {
2645 of_property_for_each_string(child, "interrupt-names",
2646 prop, name) {
2647 rc = smb5_request_interrupt(chip, child, name);
2648 if (rc < 0)
2649 return rc;
2650 }
2651 }
2652 if (chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq)
2653 chg->usb_icl_change_irq_enabled = true;
2654
2655 return rc;
2656}
2657
2658static void smb5_free_interrupts(struct smb_charger *chg)
2659{
2660 int i;
2661
2662 for (i = 0; i < ARRAY_SIZE(smb5_irqs); i++) {
2663 if (smb5_irqs[i].irq > 0) {
2664 if (smb5_irqs[i].wake)
2665 disable_irq_wake(smb5_irqs[i].irq);
2666
2667 devm_free_irq(chg->dev, smb5_irqs[i].irq,
2668 smb5_irqs[i].irq_data);
2669 }
2670 }
2671}
2672
2673static void smb5_disable_interrupts(struct smb_charger *chg)
2674{
2675 int i;
2676
2677 for (i = 0; i < ARRAY_SIZE(smb5_irqs); i++) {
2678 if (smb5_irqs[i].irq > 0)
2679 disable_irq(smb5_irqs[i].irq);
2680 }
2681}
2682
2683#if defined(CONFIG_DEBUG_FS)
2684
2685static int force_batt_psy_update_write(void *data, u64 val)
2686{
2687 struct smb_charger *chg = data;
2688
2689 power_supply_changed(chg->batt_psy);
2690 return 0;
2691}
2692DEFINE_SIMPLE_ATTRIBUTE(force_batt_psy_update_ops, NULL,
2693 force_batt_psy_update_write, "0x%02llx\n");
2694
2695static int force_usb_psy_update_write(void *data, u64 val)
2696{
2697 struct smb_charger *chg = data;
2698
2699 power_supply_changed(chg->usb_psy);
2700 return 0;
2701}
2702DEFINE_SIMPLE_ATTRIBUTE(force_usb_psy_update_ops, NULL,
2703 force_usb_psy_update_write, "0x%02llx\n");
2704
2705static int force_dc_psy_update_write(void *data, u64 val)
2706{
2707 struct smb_charger *chg = data;
2708
2709 power_supply_changed(chg->dc_psy);
2710 return 0;
2711}
2712DEFINE_SIMPLE_ATTRIBUTE(force_dc_psy_update_ops, NULL,
2713 force_dc_psy_update_write, "0x%02llx\n");
2714
2715static void smb5_create_debugfs(struct smb5 *chip)
2716{
2717 struct dentry *file;
2718
2719 chip->dfs_root = debugfs_create_dir("charger", NULL);
2720 if (IS_ERR_OR_NULL(chip->dfs_root)) {
2721 pr_err("Couldn't create charger debugfs rc=%ld\n",
2722 (long)chip->dfs_root);
2723 return;
2724 }
2725
2726 file = debugfs_create_file("force_batt_psy_update", 0600,
2727 chip->dfs_root, chip, &force_batt_psy_update_ops);
2728 if (IS_ERR_OR_NULL(file))
2729 pr_err("Couldn't create force_batt_psy_update file rc=%ld\n",
2730 (long)file);
2731
2732 file = debugfs_create_file("force_usb_psy_update", 0600,
2733 chip->dfs_root, chip, &force_usb_psy_update_ops);
2734 if (IS_ERR_OR_NULL(file))
2735 pr_err("Couldn't create force_usb_psy_update file rc=%ld\n",
2736 (long)file);
2737
2738 file = debugfs_create_file("force_dc_psy_update", 0600,
2739 chip->dfs_root, chip, &force_dc_psy_update_ops);
2740 if (IS_ERR_OR_NULL(file))
2741 pr_err("Couldn't create force_dc_psy_update file rc=%ld\n",
2742 (long)file);
2743}
2744
2745#else
2746
2747static void smb5_create_debugfs(struct smb5 *chip)
2748{}
2749
2750#endif
2751
2752static int smb5_show_charger_status(struct smb5 *chip)
2753{
2754 struct smb_charger *chg = &chip->chg;
2755 union power_supply_propval val;
2756 int usb_present, batt_present, batt_health, batt_charge_type;
2757 int rc;
2758
2759 rc = smblib_get_prop_usb_present(chg, &val);
2760 if (rc < 0) {
2761 pr_err("Couldn't get usb present rc=%d\n", rc);
2762 return rc;
2763 }
2764 usb_present = val.intval;
2765
2766 rc = smblib_get_prop_batt_present(chg, &val);
2767 if (rc < 0) {
2768 pr_err("Couldn't get batt present rc=%d\n", rc);
2769 return rc;
2770 }
2771 batt_present = val.intval;
2772
2773 rc = smblib_get_prop_batt_health(chg, &val);
2774 if (rc < 0) {
2775 pr_err("Couldn't get batt health rc=%d\n", rc);
2776 val.intval = POWER_SUPPLY_HEALTH_UNKNOWN;
2777 }
2778 batt_health = val.intval;
2779
2780 rc = smblib_get_prop_batt_charge_type(chg, &val);
2781 if (rc < 0) {
2782 pr_err("Couldn't get batt charge type rc=%d\n", rc);
2783 return rc;
2784 }
2785 batt_charge_type = val.intval;
2786
2787 pr_info("SMB5 status - usb:present=%d type=%d batt:present = %d health = %d charge = %d\n",
2788 usb_present, chg->real_charger_type,
2789 batt_present, batt_health, batt_charge_type);
2790 return rc;
2791}
2792
2793static int smb5_probe(struct platform_device *pdev)
2794{
2795 struct smb5 *chip;
2796 struct smb_charger *chg;
2797 int rc = 0;
2798
2799 chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
2800 if (!chip)
2801 return -ENOMEM;
2802
2803 chg = &chip->chg;
2804 chg->dev = &pdev->dev;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002805 chg->debug_mask = &__debug_mask;
Harry Yang6afaea22018-03-26 19:11:07 -07002806 chg->pd_disabled = &__pd_disabled;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002807 chg->weak_chg_icl_ua = &__weak_chg_icl_ua;
2808 chg->mode = PARALLEL_MASTER;
2809 chg->irq_info = smb5_irqs;
2810 chg->die_health = -EINVAL;
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302811 chg->otg_present = false;
Anirudh Ghayal75f8f812018-07-09 16:48:47 +05302812 mutex_init(&chg->vadc_lock);
Harry Yang4b7db0f2017-11-27 10:50:44 -08002813
2814 chg->regmap = dev_get_regmap(chg->dev->parent, NULL);
2815 if (!chg->regmap) {
2816 pr_err("parent regmap is missing\n");
2817 return -EINVAL;
2818 }
2819
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302820 rc = smb5_chg_config_init(chip);
2821 if (rc < 0) {
2822 if (rc != -EPROBE_DEFER)
2823 pr_err("Couldn't setup chg_config rc=%d\n", rc);
2824 return rc;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002825 }
2826
Ashay Jaiswalb2b06fe2018-06-07 18:35:21 +05302827 rc = smb5_parse_dt(chip);
2828 if (rc < 0) {
2829 pr_err("Couldn't parse device tree rc=%d\n", rc);
2830 return rc;
2831 }
2832
Harry Yang4b7db0f2017-11-27 10:50:44 -08002833 rc = smblib_init(chg);
2834 if (rc < 0) {
2835 pr_err("Smblib_init failed rc=%d\n", rc);
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302836 return rc;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002837 }
2838
2839 /* set driver data before resources request it */
2840 platform_set_drvdata(pdev, chip);
2841
2842 rc = smb5_init_vbus_regulator(chip);
2843 if (rc < 0) {
2844 pr_err("Couldn't initialize vbus regulator rc=%d\n",
2845 rc);
2846 goto cleanup;
2847 }
2848
2849 rc = smb5_init_vconn_regulator(chip);
2850 if (rc < 0) {
2851 pr_err("Couldn't initialize vconn regulator rc=%d\n",
2852 rc);
2853 goto cleanup;
2854 }
2855
2856 /* extcon registration */
2857 chg->extcon = devm_extcon_dev_allocate(chg->dev, smblib_extcon_cable);
2858 if (IS_ERR(chg->extcon)) {
2859 rc = PTR_ERR(chg->extcon);
2860 dev_err(chg->dev, "failed to allocate extcon device rc=%d\n",
2861 rc);
2862 goto cleanup;
2863 }
2864
2865 rc = devm_extcon_dev_register(chg->dev, chg->extcon);
2866 if (rc < 0) {
2867 dev_err(chg->dev, "failed to register extcon device rc=%d\n",
2868 rc);
2869 goto cleanup;
2870 }
2871
2872 rc = smb5_init_hw(chip);
2873 if (rc < 0) {
2874 pr_err("Couldn't initialize hardware rc=%d\n", rc);
2875 goto cleanup;
2876 }
2877
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302878 if (chg->smb_version == PM855B_SUBTYPE) {
2879 rc = smb5_init_dc_psy(chip);
2880 if (rc < 0) {
2881 pr_err("Couldn't initialize dc psy rc=%d\n", rc);
2882 goto cleanup;
2883 }
Harry Yang4b7db0f2017-11-27 10:50:44 -08002884 }
2885
2886 rc = smb5_init_usb_psy(chip);
2887 if (rc < 0) {
2888 pr_err("Couldn't initialize usb psy rc=%d\n", rc);
2889 goto cleanup;
2890 }
2891
2892 rc = smb5_init_usb_main_psy(chip);
2893 if (rc < 0) {
2894 pr_err("Couldn't initialize usb main psy rc=%d\n", rc);
2895 goto cleanup;
2896 }
2897
2898 rc = smb5_init_usb_port_psy(chip);
2899 if (rc < 0) {
2900 pr_err("Couldn't initialize usb pc_port psy rc=%d\n", rc);
2901 goto cleanup;
2902 }
2903
2904 rc = smb5_init_batt_psy(chip);
2905 if (rc < 0) {
2906 pr_err("Couldn't initialize batt psy rc=%d\n", rc);
2907 goto cleanup;
2908 }
2909
2910 rc = smb5_determine_initial_status(chip);
2911 if (rc < 0) {
2912 pr_err("Couldn't determine initial status rc=%d\n",
2913 rc);
2914 goto cleanup;
2915 }
2916
2917 rc = smb5_request_interrupts(chip);
2918 if (rc < 0) {
2919 pr_err("Couldn't request interrupts rc=%d\n", rc);
2920 goto cleanup;
2921 }
2922
2923 rc = smb5_post_init(chip);
2924 if (rc < 0) {
2925 pr_err("Failed in post init rc=%d\n", rc);
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302926 goto free_irq;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002927 }
2928
2929 smb5_create_debugfs(chip);
2930
2931 rc = smb5_show_charger_status(chip);
2932 if (rc < 0) {
2933 pr_err("Failed in getting charger status rc=%d\n", rc);
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302934 goto free_irq;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002935 }
2936
2937 device_init_wakeup(chg->dev, true);
2938
2939 pr_info("QPNP SMB5 probed successfully\n");
2940
2941 return rc;
2942
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302943free_irq:
Harry Yang4b7db0f2017-11-27 10:50:44 -08002944 smb5_free_interrupts(chg);
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302945cleanup:
Harry Yang4b7db0f2017-11-27 10:50:44 -08002946 smblib_deinit(chg);
2947 platform_set_drvdata(pdev, NULL);
2948
2949 return rc;
2950}
2951
2952static int smb5_remove(struct platform_device *pdev)
2953{
2954 struct smb5 *chip = platform_get_drvdata(pdev);
2955 struct smb_charger *chg = &chip->chg;
2956
Harry Yang6afaea22018-03-26 19:11:07 -07002957 /* force enable APSD */
2958 smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
2959 BC1P2_SRC_DETECT_BIT, BC1P2_SRC_DETECT_BIT);
2960
Harry Yang4b7db0f2017-11-27 10:50:44 -08002961 smb5_free_interrupts(chg);
2962 smblib_deinit(chg);
2963 platform_set_drvdata(pdev, NULL);
2964 return 0;
2965}
2966
2967static void smb5_shutdown(struct platform_device *pdev)
2968{
2969 struct smb5 *chip = platform_get_drvdata(pdev);
2970 struct smb_charger *chg = &chip->chg;
2971
2972 /* disable all interrupts */
2973 smb5_disable_interrupts(chg);
2974
2975 /* configure power role for UFP */
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302976 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_TYPEC)
Harry Yang4b7db0f2017-11-27 10:50:44 -08002977 smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
2978 TYPEC_POWER_ROLE_CMD_MASK, EN_SNK_ONLY_BIT);
2979
2980 /* force HVDCP to 5V */
2981 smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
2982 HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT, 0);
2983 smblib_write(chg, CMD_HVDCP_2_REG, FORCE_5V_BIT);
2984
2985 /* force enable APSD */
2986 smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
2987 BC1P2_SRC_DETECT_BIT, BC1P2_SRC_DETECT_BIT);
2988}
2989
2990static const struct of_device_id match_table[] = {
2991 { .compatible = "qcom,qpnp-smb5", },
2992 { },
2993};
2994
2995static struct platform_driver smb5_driver = {
2996 .driver = {
2997 .name = "qcom,qpnp-smb5",
2998 .owner = THIS_MODULE,
2999 .of_match_table = match_table,
3000 },
3001 .probe = smb5_probe,
3002 .remove = smb5_remove,
3003 .shutdown = smb5_shutdown,
3004};
3005module_platform_driver(smb5_driver);
3006
3007MODULE_DESCRIPTION("QPNP SMB5 Charger Driver");
3008MODULE_LICENSE("GPL v2");