blob: b082940d10ee0c774a80a00435e848a3e6a69d1f [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
Harry Yang4b7db0f2017-11-27 10:50:44 -0800507 return 0;
508}
509
Ashay Jaiswal20688262018-04-25 11:45:34 +0530510static int smb5_get_adc_data(struct smb_charger *chg, int channel,
511 union power_supply_propval *val)
512{
Anirudh Ghayal75f8f812018-07-09 16:48:47 +0530513 int rc = 0;
Ashay Jaiswal20688262018-04-25 11:45:34 +0530514 struct qpnp_vadc_result result;
Ashay Jaiswalb50706d2018-06-28 19:37:31 +0530515 u8 reg;
Ashay Jaiswal20688262018-04-25 11:45:34 +0530516
517 if (!chg->vadc_dev) {
518 if (of_find_property(chg->dev->of_node, "qcom,chg-vadc",
519 NULL)) {
520 chg->vadc_dev = qpnp_get_vadc(chg->dev, "chg");
521 if (IS_ERR(chg->vadc_dev)) {
522 rc = PTR_ERR(chg->vadc_dev);
523 if (rc != -EPROBE_DEFER)
524 pr_debug("Failed to find VADC node, rc=%d\n",
525 rc);
526 else
527 chg->vadc_dev = NULL;
528
529 return rc;
530 }
531 } else {
532 return -ENODATA;
533 }
534 }
535
536 if (IS_ERR(chg->vadc_dev))
537 return PTR_ERR(chg->vadc_dev);
538
Anirudh Ghayal75f8f812018-07-09 16:48:47 +0530539 mutex_lock(&chg->vadc_lock);
540
Ashay Jaiswal20688262018-04-25 11:45:34 +0530541 switch (channel) {
542 case USBIN_VOLTAGE:
Ashay Jaiswalb50706d2018-06-28 19:37:31 +0530543 /* Store ADC channel config */
544 rc = smblib_read(chg, BATIF_ADC_CHANNEL_EN_REG, &reg);
545 if (rc < 0) {
546 dev_err(chg->dev,
547 "Couldn't read ADC config rc=%d\n", rc);
Anirudh Ghayal75f8f812018-07-09 16:48:47 +0530548 goto done;
Ashay Jaiswalb50706d2018-06-28 19:37:31 +0530549 }
550
551 /* Disable all ADC channels except IBAT channel */
552 rc = smblib_write(chg, BATIF_ADC_CHANNEL_EN_REG,
553 IBATT_CHANNEL_EN_BIT);
554 if (rc < 0) {
555 dev_err(chg->dev,
556 "Couldn't write ADC config rc=%d\n", rc);
Anirudh Ghayal75f8f812018-07-09 16:48:47 +0530557 goto done;
Ashay Jaiswalb50706d2018-06-28 19:37:31 +0530558 }
559
Ashay Jaiswal20688262018-04-25 11:45:34 +0530560 rc = qpnp_vadc_read(chg->vadc_dev, VADC_USB_IN_V_DIV_16_PM5,
561 &result);
Anirudh Ghayal75f8f812018-07-09 16:48:47 +0530562 if (rc < 0)
Ashay Jaiswal20688262018-04-25 11:45:34 +0530563 pr_err("Failed to read USBIN_V over vadc, rc=%d\n", rc);
Anirudh Ghayal75f8f812018-07-09 16:48:47 +0530564 else
565 val->intval = result.physical;
Ashay Jaiswalb50706d2018-06-28 19:37:31 +0530566
Ashay Jaiswalb50706d2018-06-28 19:37:31 +0530567 /* Restore ADC channel config */
Anirudh Ghayal75f8f812018-07-09 16:48:47 +0530568 rc |= smblib_write(chg, BATIF_ADC_CHANNEL_EN_REG, reg);
569 if (rc < 0)
Ashay Jaiswalb50706d2018-06-28 19:37:31 +0530570 dev_err(chg->dev,
571 "Couldn't write ADC config rc=%d\n", rc);
Anirudh Ghayal75f8f812018-07-09 16:48:47 +0530572
Ashay Jaiswal20688262018-04-25 11:45:34 +0530573 break;
574 case USBIN_CURRENT:
575 rc = qpnp_vadc_read(chg->vadc_dev, VADC_USB_IN_I_PM5, &result);
576 if (rc < 0) {
577 pr_err("Failed to read USBIN_I over vadc, rc=%d\n", rc);
Anirudh Ghayal75f8f812018-07-09 16:48:47 +0530578 goto done;
Ashay Jaiswal20688262018-04-25 11:45:34 +0530579 }
580 val->intval = result.physical;
581 break;
582 default:
583 pr_debug("Invalid channel\n");
Anirudh Ghayal75f8f812018-07-09 16:48:47 +0530584 rc = -EINVAL;
585 break;
Ashay Jaiswal20688262018-04-25 11:45:34 +0530586 }
587
Anirudh Ghayal75f8f812018-07-09 16:48:47 +0530588done:
589 mutex_unlock(&chg->vadc_lock);
590 return rc;
Ashay Jaiswal20688262018-04-25 11:45:34 +0530591}
592
593
Harry Yang4b7db0f2017-11-27 10:50:44 -0800594/************************
595 * USB PSY REGISTRATION *
596 ************************/
597static enum power_supply_property smb5_usb_props[] = {
598 POWER_SUPPLY_PROP_PRESENT,
599 POWER_SUPPLY_PROP_ONLINE,
600 POWER_SUPPLY_PROP_PD_CURRENT_MAX,
601 POWER_SUPPLY_PROP_CURRENT_MAX,
602 POWER_SUPPLY_PROP_TYPE,
603 POWER_SUPPLY_PROP_TYPEC_MODE,
604 POWER_SUPPLY_PROP_TYPEC_POWER_ROLE,
605 POWER_SUPPLY_PROP_TYPEC_CC_ORIENTATION,
Harry Yang4b7db0f2017-11-27 10:50:44 -0800606 POWER_SUPPLY_PROP_PD_ACTIVE,
607 POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED,
608 POWER_SUPPLY_PROP_INPUT_CURRENT_NOW,
609 POWER_SUPPLY_PROP_BOOST_CURRENT,
610 POWER_SUPPLY_PROP_PE_START,
611 POWER_SUPPLY_PROP_CTM_CURRENT_MAX,
612 POWER_SUPPLY_PROP_HW_CURRENT_MAX,
613 POWER_SUPPLY_PROP_REAL_TYPE,
614 POWER_SUPPLY_PROP_PR_SWAP,
615 POWER_SUPPLY_PROP_PD_VOLTAGE_MAX,
616 POWER_SUPPLY_PROP_PD_VOLTAGE_MIN,
617 POWER_SUPPLY_PROP_SDP_CURRENT_MAX,
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530618 POWER_SUPPLY_PROP_CONNECTOR_TYPE,
Ashay Jaiswal1f71b412017-10-31 14:33:27 +0530619 POWER_SUPPLY_PROP_VOLTAGE_MAX,
Umang Agrawal9fb865a2018-06-25 16:24:00 +0530620 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
Ashay Jaiswal09feab82018-02-12 12:33:18 +0530621 POWER_SUPPLY_PROP_SCOPE,
Ashay Jaiswal20688262018-04-25 11:45:34 +0530622 POWER_SUPPLY_PROP_VOLTAGE_NOW,
Ashay Jaiswal4d334f42018-04-25 10:58:49 +0530623 POWER_SUPPLY_PROP_HVDCP_OPTI_ALLOWED,
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +0530624 POWER_SUPPLY_PROP_QC_OPTI_DISABLE,
Umang Agrawal461e9ea2018-07-05 18:50:13 +0530625 POWER_SUPPLY_PROP_MOISTURE_DETECTED,
Harry Yang4b7db0f2017-11-27 10:50:44 -0800626};
627
628static int smb5_usb_get_prop(struct power_supply *psy,
629 enum power_supply_property psp,
630 union power_supply_propval *val)
631{
632 struct smb5 *chip = power_supply_get_drvdata(psy);
633 struct smb_charger *chg = &chip->chg;
Ashay Jaiswal09feab82018-02-12 12:33:18 +0530634 union power_supply_propval pval;
Harry Yang4b7db0f2017-11-27 10:50:44 -0800635 int rc = 0;
636
637 switch (psp) {
638 case POWER_SUPPLY_PROP_PRESENT:
639 rc = smblib_get_prop_usb_present(chg, val);
640 break;
641 case POWER_SUPPLY_PROP_ONLINE:
642 rc = smblib_get_prop_usb_online(chg, val);
643 if (!val->intval)
644 break;
645
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530646 if (((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) ||
647 (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB))
648 && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB))
Harry Yang4b7db0f2017-11-27 10:50:44 -0800649 val->intval = 0;
650 else
651 val->intval = 1;
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530652
Harry Yang4b7db0f2017-11-27 10:50:44 -0800653 if (chg->real_charger_type == POWER_SUPPLY_TYPE_UNKNOWN)
654 val->intval = 0;
655 break;
656 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
657 rc = smblib_get_prop_usb_voltage_max(chg, val);
658 break;
Umang Agrawal9fb865a2018-06-25 16:24:00 +0530659 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
660 rc = smblib_get_prop_usb_voltage_max_design(chg, val);
661 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -0800662 case POWER_SUPPLY_PROP_PD_CURRENT_MAX:
663 val->intval = get_client_vote(chg->usb_icl_votable, PD_VOTER);
664 break;
665 case POWER_SUPPLY_PROP_CURRENT_MAX:
666 rc = smblib_get_prop_input_current_settled(chg, val);
667 break;
668 case POWER_SUPPLY_PROP_TYPE:
669 val->intval = POWER_SUPPLY_TYPE_USB_PD;
670 break;
671 case POWER_SUPPLY_PROP_REAL_TYPE:
672 val->intval = chg->real_charger_type;
673 break;
674 case POWER_SUPPLY_PROP_TYPEC_MODE:
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530675 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
Harry Yang4b7db0f2017-11-27 10:50:44 -0800676 val->intval = POWER_SUPPLY_TYPEC_NONE;
677 else
678 val->intval = chg->typec_mode;
679 break;
680 case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE:
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530681 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
Harry Yang4b7db0f2017-11-27 10:50:44 -0800682 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
683 else
684 rc = smblib_get_prop_typec_power_role(chg, val);
685 break;
686 case POWER_SUPPLY_PROP_TYPEC_CC_ORIENTATION:
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530687 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
Harry Yang4b7db0f2017-11-27 10:50:44 -0800688 val->intval = 0;
689 else
690 rc = smblib_get_prop_typec_cc_orientation(chg, val);
691 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -0800692 case POWER_SUPPLY_PROP_PD_ACTIVE:
693 val->intval = chg->pd_active;
694 break;
695 case POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED:
696 rc = smblib_get_prop_input_current_settled(chg, val);
697 break;
698 case POWER_SUPPLY_PROP_BOOST_CURRENT:
699 val->intval = chg->boost_current_ua;
700 break;
701 case POWER_SUPPLY_PROP_PD_IN_HARD_RESET:
702 rc = smblib_get_prop_pd_in_hard_reset(chg, val);
703 break;
704 case POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED:
705 val->intval = chg->system_suspend_supported;
706 break;
707 case POWER_SUPPLY_PROP_PE_START:
708 rc = smblib_get_pe_start(chg, val);
709 break;
710 case POWER_SUPPLY_PROP_CTM_CURRENT_MAX:
711 val->intval = get_client_vote(chg->usb_icl_votable, CTM_VOTER);
712 break;
713 case POWER_SUPPLY_PROP_HW_CURRENT_MAX:
714 rc = smblib_get_charge_current(chg, &val->intval);
715 break;
716 case POWER_SUPPLY_PROP_PR_SWAP:
717 rc = smblib_get_prop_pr_swap_in_progress(chg, val);
718 break;
719 case POWER_SUPPLY_PROP_PD_VOLTAGE_MAX:
720 val->intval = chg->voltage_max_uv;
721 break;
722 case POWER_SUPPLY_PROP_PD_VOLTAGE_MIN:
723 val->intval = chg->voltage_min_uv;
724 break;
725 case POWER_SUPPLY_PROP_SDP_CURRENT_MAX:
726 val->intval = get_client_vote(chg->usb_icl_votable,
727 USB_PSY_VOTER);
728 break;
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530729 case POWER_SUPPLY_PROP_CONNECTOR_TYPE:
730 val->intval = chg->connector_type;
731 break;
Ashay Jaiswal09feab82018-02-12 12:33:18 +0530732 case POWER_SUPPLY_PROP_SCOPE:
733 val->intval = POWER_SUPPLY_SCOPE_UNKNOWN;
734 rc = smblib_get_prop_usb_present(chg, &pval);
735 if (rc < 0)
736 break;
737 val->intval = pval.intval ? POWER_SUPPLY_SCOPE_DEVICE
738 : chg->otg_present ? POWER_SUPPLY_SCOPE_SYSTEM
739 : POWER_SUPPLY_SCOPE_UNKNOWN;
740 break;
Ashay Jaiswal20688262018-04-25 11:45:34 +0530741 case POWER_SUPPLY_PROP_INPUT_CURRENT_NOW:
742 rc = smblib_get_prop_usb_present(chg, &pval);
743 if (rc < 0 || !pval.intval) {
744 val->intval = 0;
745 return rc;
746 }
747 if (chg->smb_version == PMI632_SUBTYPE)
748 rc = smb5_get_adc_data(chg, USBIN_CURRENT, val);
749 break;
750 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
751 if (chg->smb_version == PMI632_SUBTYPE)
752 rc = smb5_get_adc_data(chg, USBIN_VOLTAGE, val);
753 break;
Ashay Jaiswal4d334f42018-04-25 10:58:49 +0530754 case POWER_SUPPLY_PROP_HVDCP_OPTI_ALLOWED:
755 val->intval = !chg->flash_active;
756 break;
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +0530757 case POWER_SUPPLY_PROP_QC_OPTI_DISABLE:
758 if (chg->hw_die_temp_mitigation)
759 val->intval = POWER_SUPPLY_QC_THERMAL_BALANCE_DISABLE
760 | POWER_SUPPLY_QC_INOV_THERMAL_DISABLE;
761 if (chg->hw_connector_mitigation)
762 val->intval |= POWER_SUPPLY_QC_CTM_DISABLE;
763 break;
Umang Agrawal461e9ea2018-07-05 18:50:13 +0530764 case POWER_SUPPLY_PROP_MOISTURE_DETECTED:
765 val->intval = chg->moisture_present;
766 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -0800767 default:
768 pr_err("get prop %d is not supported in usb\n", psp);
769 rc = -EINVAL;
770 break;
771 }
772
773 if (rc < 0) {
774 pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
775 return -ENODATA;
776 }
777
778 return 0;
779}
780
781static int smb5_usb_set_prop(struct power_supply *psy,
782 enum power_supply_property psp,
783 const union power_supply_propval *val)
784{
785 struct smb5 *chip = power_supply_get_drvdata(psy);
786 struct smb_charger *chg = &chip->chg;
787 int rc = 0;
788
Harry Yang4b7db0f2017-11-27 10:50:44 -0800789 switch (psp) {
790 case POWER_SUPPLY_PROP_PD_CURRENT_MAX:
791 rc = smblib_set_prop_pd_current_max(chg, val);
792 break;
793 case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE:
794 rc = smblib_set_prop_typec_power_role(chg, val);
795 break;
796 case POWER_SUPPLY_PROP_PD_ACTIVE:
797 rc = smblib_set_prop_pd_active(chg, val);
798 break;
799 case POWER_SUPPLY_PROP_PD_IN_HARD_RESET:
800 rc = smblib_set_prop_pd_in_hard_reset(chg, val);
801 break;
802 case POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED:
803 chg->system_suspend_supported = val->intval;
804 break;
805 case POWER_SUPPLY_PROP_BOOST_CURRENT:
806 rc = smblib_set_prop_boost_current(chg, val);
807 break;
808 case POWER_SUPPLY_PROP_CTM_CURRENT_MAX:
809 rc = vote(chg->usb_icl_votable, CTM_VOTER,
810 val->intval >= 0, val->intval);
811 break;
812 case POWER_SUPPLY_PROP_PR_SWAP:
813 rc = smblib_set_prop_pr_swap_in_progress(chg, val);
814 break;
815 case POWER_SUPPLY_PROP_PD_VOLTAGE_MAX:
816 rc = smblib_set_prop_pd_voltage_max(chg, val);
817 break;
818 case POWER_SUPPLY_PROP_PD_VOLTAGE_MIN:
819 rc = smblib_set_prop_pd_voltage_min(chg, val);
820 break;
821 case POWER_SUPPLY_PROP_SDP_CURRENT_MAX:
822 rc = smblib_set_prop_sdp_current_max(chg, val);
823 break;
824 default:
825 pr_err("set prop %d is not supported\n", psp);
826 rc = -EINVAL;
827 break;
828 }
829
Harry Yang4b7db0f2017-11-27 10:50:44 -0800830 return rc;
831}
832
833static int smb5_usb_prop_is_writeable(struct power_supply *psy,
834 enum power_supply_property psp)
835{
836 switch (psp) {
837 case POWER_SUPPLY_PROP_CTM_CURRENT_MAX:
838 return 1;
839 default:
840 break;
841 }
842
843 return 0;
844}
845
846static const struct power_supply_desc usb_psy_desc = {
847 .name = "usb",
848 .type = POWER_SUPPLY_TYPE_USB_PD,
849 .properties = smb5_usb_props,
850 .num_properties = ARRAY_SIZE(smb5_usb_props),
851 .get_property = smb5_usb_get_prop,
852 .set_property = smb5_usb_set_prop,
853 .property_is_writeable = smb5_usb_prop_is_writeable,
854};
855
856static int smb5_init_usb_psy(struct smb5 *chip)
857{
858 struct power_supply_config usb_cfg = {};
859 struct smb_charger *chg = &chip->chg;
860
861 usb_cfg.drv_data = chip;
862 usb_cfg.of_node = chg->dev->of_node;
863 chg->usb_psy = devm_power_supply_register(chg->dev,
864 &usb_psy_desc,
865 &usb_cfg);
866 if (IS_ERR(chg->usb_psy)) {
867 pr_err("Couldn't register USB power supply\n");
868 return PTR_ERR(chg->usb_psy);
869 }
870
871 return 0;
872}
873
874/********************************
875 * USB PC_PORT PSY REGISTRATION *
876 ********************************/
877static enum power_supply_property smb5_usb_port_props[] = {
878 POWER_SUPPLY_PROP_TYPE,
879 POWER_SUPPLY_PROP_ONLINE,
880 POWER_SUPPLY_PROP_VOLTAGE_MAX,
881 POWER_SUPPLY_PROP_CURRENT_MAX,
882};
883
884static int smb5_usb_port_get_prop(struct power_supply *psy,
885 enum power_supply_property psp,
886 union power_supply_propval *val)
887{
888 struct smb5 *chip = power_supply_get_drvdata(psy);
889 struct smb_charger *chg = &chip->chg;
890 int rc = 0;
891
892 switch (psp) {
893 case POWER_SUPPLY_PROP_TYPE:
894 val->intval = POWER_SUPPLY_TYPE_USB;
895 break;
896 case POWER_SUPPLY_PROP_ONLINE:
897 rc = smblib_get_prop_usb_online(chg, val);
898 if (!val->intval)
899 break;
900
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530901 if (((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) ||
902 (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB))
903 && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB))
Harry Yang4b7db0f2017-11-27 10:50:44 -0800904 val->intval = 1;
905 else
906 val->intval = 0;
907 break;
908 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
909 val->intval = 5000000;
910 break;
911 case POWER_SUPPLY_PROP_CURRENT_MAX:
912 rc = smblib_get_prop_input_current_settled(chg, val);
913 break;
914 default:
915 pr_err_ratelimited("Get prop %d is not supported in pc_port\n",
916 psp);
917 return -EINVAL;
918 }
919
920 if (rc < 0) {
921 pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
922 return -ENODATA;
923 }
924
925 return 0;
926}
927
928static int smb5_usb_port_set_prop(struct power_supply *psy,
929 enum power_supply_property psp,
930 const union power_supply_propval *val)
931{
932 int rc = 0;
933
934 switch (psp) {
935 default:
936 pr_err_ratelimited("Set prop %d is not supported in pc_port\n",
937 psp);
938 rc = -EINVAL;
939 break;
940 }
941
942 return rc;
943}
944
945static const struct power_supply_desc usb_port_psy_desc = {
946 .name = "pc_port",
947 .type = POWER_SUPPLY_TYPE_USB,
948 .properties = smb5_usb_port_props,
949 .num_properties = ARRAY_SIZE(smb5_usb_port_props),
950 .get_property = smb5_usb_port_get_prop,
951 .set_property = smb5_usb_port_set_prop,
952};
953
954static int smb5_init_usb_port_psy(struct smb5 *chip)
955{
956 struct power_supply_config usb_port_cfg = {};
957 struct smb_charger *chg = &chip->chg;
958
959 usb_port_cfg.drv_data = chip;
960 usb_port_cfg.of_node = chg->dev->of_node;
961 chg->usb_port_psy = devm_power_supply_register(chg->dev,
962 &usb_port_psy_desc,
963 &usb_port_cfg);
964 if (IS_ERR(chg->usb_port_psy)) {
965 pr_err("Couldn't register USB pc_port power supply\n");
966 return PTR_ERR(chg->usb_port_psy);
967 }
968
969 return 0;
970}
971
972/*****************************
973 * USB MAIN PSY REGISTRATION *
974 *****************************/
975
976static enum power_supply_property smb5_usb_main_props[] = {
977 POWER_SUPPLY_PROP_VOLTAGE_MAX,
978 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
979 POWER_SUPPLY_PROP_TYPE,
980 POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED,
981 POWER_SUPPLY_PROP_INPUT_VOLTAGE_SETTLED,
982 POWER_SUPPLY_PROP_FCC_DELTA,
983 POWER_SUPPLY_PROP_CURRENT_MAX,
Ashay Jaiswal09feab82018-02-12 12:33:18 +0530984 POWER_SUPPLY_PROP_FLASH_ACTIVE,
985 POWER_SUPPLY_PROP_FLASH_TRIGGER,
Harry Yang4b7db0f2017-11-27 10:50:44 -0800986};
987
988static int smb5_usb_main_get_prop(struct power_supply *psy,
989 enum power_supply_property psp,
990 union power_supply_propval *val)
991{
992 struct smb5 *chip = power_supply_get_drvdata(psy);
993 struct smb_charger *chg = &chip->chg;
994 int rc = 0;
995
996 switch (psp) {
997 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
998 rc = smblib_get_charge_param(chg, &chg->param.fv, &val->intval);
999 break;
1000 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
1001 rc = smblib_get_charge_param(chg, &chg->param.fcc,
1002 &val->intval);
1003 break;
1004 case POWER_SUPPLY_PROP_TYPE:
1005 val->intval = POWER_SUPPLY_TYPE_MAIN;
1006 break;
1007 case POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED:
1008 rc = smblib_get_prop_input_current_settled(chg, val);
1009 break;
1010 case POWER_SUPPLY_PROP_INPUT_VOLTAGE_SETTLED:
1011 rc = smblib_get_prop_input_voltage_settled(chg, val);
1012 break;
1013 case POWER_SUPPLY_PROP_FCC_DELTA:
1014 rc = smblib_get_prop_fcc_delta(chg, val);
1015 break;
1016 case POWER_SUPPLY_PROP_CURRENT_MAX:
1017 rc = smblib_get_icl_current(chg, &val->intval);
1018 break;
Ashay Jaiswal09feab82018-02-12 12:33:18 +05301019 case POWER_SUPPLY_PROP_FLASH_ACTIVE:
1020 val->intval = chg->flash_active;
1021 break;
1022 case POWER_SUPPLY_PROP_FLASH_TRIGGER:
1023 rc = schgm_flash_get_vreg_ok(chg, &val->intval);
1024 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001025 default:
1026 pr_debug("get prop %d is not supported in usb-main\n", psp);
1027 rc = -EINVAL;
1028 break;
1029 }
1030 if (rc < 0) {
1031 pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
1032 return -ENODATA;
1033 }
1034
1035 return 0;
1036}
1037
1038static int smb5_usb_main_set_prop(struct power_supply *psy,
1039 enum power_supply_property psp,
1040 const union power_supply_propval *val)
1041{
1042 struct smb5 *chip = power_supply_get_drvdata(psy);
1043 struct smb_charger *chg = &chip->chg;
Ashay Jaiswal4d334f42018-04-25 10:58:49 +05301044 union power_supply_propval pval = {0, };
Harry Yang4b7db0f2017-11-27 10:50:44 -08001045 int rc = 0;
1046
1047 switch (psp) {
1048 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
1049 rc = smblib_set_charge_param(chg, &chg->param.fv, val->intval);
1050 break;
1051 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
1052 rc = smblib_set_charge_param(chg, &chg->param.fcc, val->intval);
1053 break;
1054 case POWER_SUPPLY_PROP_CURRENT_MAX:
1055 rc = smblib_set_icl_current(chg, val->intval);
1056 break;
Ashay Jaiswal09feab82018-02-12 12:33:18 +05301057 case POWER_SUPPLY_PROP_FLASH_ACTIVE:
Ashay Jaiswal4d334f42018-04-25 10:58:49 +05301058 if ((chg->smb_version == PMI632_SUBTYPE)
1059 && (chg->flash_active != val->intval)) {
1060 chg->flash_active = val->intval;
1061
1062 rc = smblib_get_prop_usb_present(chg, &pval);
1063 if (rc < 0)
1064 pr_err("Failed to get USB preset status rc=%d\n",
1065 rc);
1066 if (pval.intval) {
1067 rc = smblib_force_vbus_voltage(chg,
1068 chg->flash_active ? FORCE_5V_BIT
1069 : IDLE_BIT);
1070 if (rc < 0)
1071 pr_err("Failed to force 5V\n");
1072 else
1073 chg->pulse_cnt = 0;
Anirudh Ghayal4d5cddc2018-06-28 15:19:39 +05301074 } else {
1075 /* USB absent & flash not-active - vote 100mA */
1076 vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER,
1077 true, SDP_100_MA);
Ashay Jaiswal4d334f42018-04-25 10:58:49 +05301078 }
1079
1080 pr_debug("flash active VBUS 5V restriction %s\n",
1081 chg->flash_active ? "applied" : "removed");
1082
1083 /* Update userspace */
1084 if (chg->batt_psy)
1085 power_supply_changed(chg->batt_psy);
1086 }
Ashay Jaiswal09feab82018-02-12 12:33:18 +05301087 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001088 default:
1089 pr_err("set prop %d is not supported\n", psp);
1090 rc = -EINVAL;
1091 break;
1092 }
1093
1094 return rc;
1095}
1096
1097static const struct power_supply_desc usb_main_psy_desc = {
1098 .name = "main",
1099 .type = POWER_SUPPLY_TYPE_MAIN,
1100 .properties = smb5_usb_main_props,
1101 .num_properties = ARRAY_SIZE(smb5_usb_main_props),
1102 .get_property = smb5_usb_main_get_prop,
1103 .set_property = smb5_usb_main_set_prop,
1104};
1105
1106static int smb5_init_usb_main_psy(struct smb5 *chip)
1107{
1108 struct power_supply_config usb_main_cfg = {};
1109 struct smb_charger *chg = &chip->chg;
1110
1111 usb_main_cfg.drv_data = chip;
1112 usb_main_cfg.of_node = chg->dev->of_node;
1113 chg->usb_main_psy = devm_power_supply_register(chg->dev,
1114 &usb_main_psy_desc,
1115 &usb_main_cfg);
1116 if (IS_ERR(chg->usb_main_psy)) {
1117 pr_err("Couldn't register USB main power supply\n");
1118 return PTR_ERR(chg->usb_main_psy);
1119 }
1120
1121 return 0;
1122}
1123
1124/*************************
1125 * DC PSY REGISTRATION *
1126 *************************/
1127
1128static enum power_supply_property smb5_dc_props[] = {
1129 POWER_SUPPLY_PROP_INPUT_SUSPEND,
1130 POWER_SUPPLY_PROP_PRESENT,
1131 POWER_SUPPLY_PROP_ONLINE,
1132 POWER_SUPPLY_PROP_REAL_TYPE,
1133};
1134
1135static int smb5_dc_get_prop(struct power_supply *psy,
1136 enum power_supply_property psp,
1137 union power_supply_propval *val)
1138{
1139 struct smb5 *chip = power_supply_get_drvdata(psy);
1140 struct smb_charger *chg = &chip->chg;
1141 int rc = 0;
1142
1143 switch (psp) {
1144 case POWER_SUPPLY_PROP_INPUT_SUSPEND:
1145 val->intval = get_effective_result(chg->dc_suspend_votable);
1146 break;
1147 case POWER_SUPPLY_PROP_PRESENT:
1148 rc = smblib_get_prop_dc_present(chg, val);
1149 break;
1150 case POWER_SUPPLY_PROP_ONLINE:
1151 rc = smblib_get_prop_dc_online(chg, val);
1152 break;
1153 case POWER_SUPPLY_PROP_REAL_TYPE:
1154 val->intval = POWER_SUPPLY_TYPE_WIPOWER;
1155 break;
1156 default:
1157 return -EINVAL;
1158 }
1159 if (rc < 0) {
1160 pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
1161 return -ENODATA;
1162 }
1163 return 0;
1164}
1165
1166static int smb5_dc_set_prop(struct power_supply *psy,
1167 enum power_supply_property psp,
1168 const union power_supply_propval *val)
1169{
1170 struct smb5 *chip = power_supply_get_drvdata(psy);
1171 struct smb_charger *chg = &chip->chg;
1172 int rc = 0;
1173
1174 switch (psp) {
1175 case POWER_SUPPLY_PROP_INPUT_SUSPEND:
1176 rc = vote(chg->dc_suspend_votable, WBC_VOTER,
1177 (bool)val->intval, 0);
1178 break;
1179 default:
1180 return -EINVAL;
1181 }
1182
1183 return rc;
1184}
1185
1186static int smb5_dc_prop_is_writeable(struct power_supply *psy,
1187 enum power_supply_property psp)
1188{
1189 int rc;
1190
1191 switch (psp) {
1192 default:
1193 rc = 0;
1194 break;
1195 }
1196
1197 return rc;
1198}
1199
1200static const struct power_supply_desc dc_psy_desc = {
1201 .name = "dc",
1202 .type = POWER_SUPPLY_TYPE_WIRELESS,
1203 .properties = smb5_dc_props,
1204 .num_properties = ARRAY_SIZE(smb5_dc_props),
1205 .get_property = smb5_dc_get_prop,
1206 .set_property = smb5_dc_set_prop,
1207 .property_is_writeable = smb5_dc_prop_is_writeable,
1208};
1209
1210static int smb5_init_dc_psy(struct smb5 *chip)
1211{
1212 struct power_supply_config dc_cfg = {};
1213 struct smb_charger *chg = &chip->chg;
1214
1215 dc_cfg.drv_data = chip;
1216 dc_cfg.of_node = chg->dev->of_node;
1217 chg->dc_psy = devm_power_supply_register(chg->dev,
1218 &dc_psy_desc,
1219 &dc_cfg);
1220 if (IS_ERR(chg->dc_psy)) {
1221 pr_err("Couldn't register USB power supply\n");
1222 return PTR_ERR(chg->dc_psy);
1223 }
1224
1225 return 0;
1226}
1227
1228/*************************
1229 * BATT PSY REGISTRATION *
1230 *************************/
1231static enum power_supply_property smb5_batt_props[] = {
1232 POWER_SUPPLY_PROP_INPUT_SUSPEND,
Anirudh Ghayaldfdb8412018-04-21 10:37:18 +05301233 POWER_SUPPLY_PROP_BATTERY_CHARGING_ENABLED,
Harry Yang4b7db0f2017-11-27 10:50:44 -08001234 POWER_SUPPLY_PROP_STATUS,
1235 POWER_SUPPLY_PROP_HEALTH,
1236 POWER_SUPPLY_PROP_PRESENT,
1237 POWER_SUPPLY_PROP_CHARGE_TYPE,
1238 POWER_SUPPLY_PROP_CAPACITY,
1239 POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
1240 POWER_SUPPLY_PROP_VOLTAGE_NOW,
1241 POWER_SUPPLY_PROP_VOLTAGE_MAX,
1242 POWER_SUPPLY_PROP_CURRENT_NOW,
1243 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001244 POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
Harry Yang4b7db0f2017-11-27 10:50:44 -08001245 POWER_SUPPLY_PROP_TEMP,
1246 POWER_SUPPLY_PROP_TECHNOLOGY,
1247 POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED,
1248 POWER_SUPPLY_PROP_SW_JEITA_ENABLED,
1249 POWER_SUPPLY_PROP_CHARGE_DONE,
1250 POWER_SUPPLY_PROP_PARALLEL_DISABLE,
1251 POWER_SUPPLY_PROP_SET_SHIP_MODE,
1252 POWER_SUPPLY_PROP_DIE_HEALTH,
1253 POWER_SUPPLY_PROP_RERUN_AICL,
1254 POWER_SUPPLY_PROP_DP_DM,
1255 POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
1256 POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
1257 POWER_SUPPLY_PROP_CHARGE_COUNTER,
Subbaraman Narayanamurthyc4feb892018-05-07 18:43:45 -07001258 POWER_SUPPLY_PROP_CYCLE_COUNT,
Anirudh Ghayal1380d312018-02-23 00:01:43 +05301259 POWER_SUPPLY_PROP_RECHARGE_SOC,
Ashay Jaiswal5c5ba272018-07-23 14:54:20 +05301260 POWER_SUPPLY_PROP_CHARGE_FULL,
Harry Yang4b7db0f2017-11-27 10:50:44 -08001261};
1262
Ashay Jaiswald802c3d2018-07-25 14:55:10 +05301263#define ITERM_SCALING_FACTOR_PMI632 1525
1264#define ITERM_SCALING_FACTOR_PM855B 3050
1265static int smb5_get_prop_batt_iterm(struct smb_charger *chg,
1266 union power_supply_propval *val)
1267{
1268 int rc, temp, scaling_factor;
1269 u8 stat, buf[2];
1270
1271 /*
1272 * Currently, only ADC comparator-based termination is supported,
1273 * hence read only the threshold corresponding to ADC source.
1274 * Proceed only if CHGR_ITERM_USE_ANALOG_BIT is 0.
1275 */
1276 rc = smblib_read(chg, CHGR_ENG_CHARGING_CFG_REG, &stat);
1277 if (rc < 0) {
1278 pr_err("Couldn't read CHGR_ENG_CHARGING_CFG_REG rc=%d\n", rc);
1279 return rc;
1280 }
1281
1282 if (stat & CHGR_ITERM_USE_ANALOG_BIT) {
1283 val->intval = -EINVAL;
1284 return 0;
1285 }
1286
1287 rc = smblib_batch_read(chg, CHGR_ADC_ITERM_UP_THD_MSB_REG, buf, 2);
1288
1289 if (rc < 0) {
1290 pr_err("Couldn't read CHGR_ADC_ITERM_UP_THD_MSB_REG rc=%d\n",
1291 rc);
1292 return rc;
1293 }
1294
1295 temp = buf[1] | (buf[0] << 8);
1296 temp = sign_extend32(temp, 15);
1297
1298 if (chg->smb_version == PMI632_SUBTYPE)
1299 scaling_factor = ITERM_SCALING_FACTOR_PMI632;
1300 else
1301 scaling_factor = ITERM_SCALING_FACTOR_PM855B;
1302
1303 temp = div_s64(temp * scaling_factor, 10000);
1304 val->intval = temp;
1305
1306 return rc;
1307}
1308
Harry Yang4b7db0f2017-11-27 10:50:44 -08001309static int smb5_batt_get_prop(struct power_supply *psy,
1310 enum power_supply_property psp,
1311 union power_supply_propval *val)
1312{
1313 struct smb_charger *chg = power_supply_get_drvdata(psy);
1314 int rc = 0;
1315
1316 switch (psp) {
1317 case POWER_SUPPLY_PROP_STATUS:
1318 rc = smblib_get_prop_batt_status(chg, val);
1319 break;
1320 case POWER_SUPPLY_PROP_HEALTH:
1321 rc = smblib_get_prop_batt_health(chg, val);
1322 break;
1323 case POWER_SUPPLY_PROP_PRESENT:
1324 rc = smblib_get_prop_batt_present(chg, val);
1325 break;
1326 case POWER_SUPPLY_PROP_INPUT_SUSPEND:
1327 rc = smblib_get_prop_input_suspend(chg, val);
1328 break;
Anirudh Ghayaldfdb8412018-04-21 10:37:18 +05301329 case POWER_SUPPLY_PROP_BATTERY_CHARGING_ENABLED:
1330 val->intval = !get_client_vote(chg->chg_disable_votable,
1331 USER_VOTER);
1332 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001333 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1334 rc = smblib_get_prop_batt_charge_type(chg, val);
1335 break;
1336 case POWER_SUPPLY_PROP_CAPACITY:
1337 rc = smblib_get_prop_batt_capacity(chg, val);
1338 break;
1339 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
1340 rc = smblib_get_prop_system_temp_level(chg, val);
1341 break;
1342 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX:
1343 rc = smblib_get_prop_system_temp_level_max(chg, val);
1344 break;
1345 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
1346 rc = smblib_get_prop_input_current_limited(chg, val);
1347 break;
1348 case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
1349 val->intval = chg->step_chg_enabled;
1350 break;
1351 case POWER_SUPPLY_PROP_SW_JEITA_ENABLED:
1352 val->intval = chg->sw_jeita_enabled;
1353 break;
1354 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Ashay Jaiswal5c5ba272018-07-23 14:54:20 +05301355 rc = smblib_get_prop_from_bms(chg,
1356 POWER_SUPPLY_PROP_VOLTAGE_NOW, val);
Harry Yang4b7db0f2017-11-27 10:50:44 -08001357 break;
1358 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
1359 val->intval = get_client_vote(chg->fv_votable,
1360 BATT_PROFILE_VOTER);
1361 break;
1362 case POWER_SUPPLY_PROP_CURRENT_NOW:
Ashay Jaiswal5c5ba272018-07-23 14:54:20 +05301363 rc = smblib_get_prop_from_bms(chg,
1364 POWER_SUPPLY_PROP_CURRENT_NOW, val);
Harry Yang4b7db0f2017-11-27 10:50:44 -08001365 break;
1366 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
1367 val->intval = get_client_vote(chg->fcc_votable,
1368 BATT_PROFILE_VOTER);
1369 break;
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001370 case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
Ashay Jaiswald802c3d2018-07-25 14:55:10 +05301371 rc = smb5_get_prop_batt_iterm(chg, val);
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001372 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001373 case POWER_SUPPLY_PROP_TEMP:
Ashay Jaiswal5c5ba272018-07-23 14:54:20 +05301374 rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_TEMP, val);
Harry Yang4b7db0f2017-11-27 10:50:44 -08001375 break;
1376 case POWER_SUPPLY_PROP_TECHNOLOGY:
1377 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1378 break;
1379 case POWER_SUPPLY_PROP_CHARGE_DONE:
1380 rc = smblib_get_prop_batt_charge_done(chg, val);
1381 break;
1382 case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
1383 val->intval = get_client_vote(chg->pl_disable_votable,
1384 USER_VOTER);
1385 break;
1386 case POWER_SUPPLY_PROP_SET_SHIP_MODE:
1387 /* Not in ship mode as long as device is active */
1388 val->intval = 0;
1389 break;
1390 case POWER_SUPPLY_PROP_DIE_HEALTH:
1391 if (chg->die_health == -EINVAL)
1392 rc = smblib_get_prop_die_health(chg, val);
1393 else
1394 val->intval = chg->die_health;
1395 break;
1396 case POWER_SUPPLY_PROP_DP_DM:
1397 val->intval = chg->pulse_cnt;
1398 break;
1399 case POWER_SUPPLY_PROP_RERUN_AICL:
1400 val->intval = 0;
1401 break;
1402 case POWER_SUPPLY_PROP_CHARGE_COUNTER:
Ashay Jaiswal5c5ba272018-07-23 14:54:20 +05301403 rc = smblib_get_prop_from_bms(chg,
1404 POWER_SUPPLY_PROP_CHARGE_COUNTER, val);
Harry Yang4b7db0f2017-11-27 10:50:44 -08001405 break;
Subbaraman Narayanamurthyc4feb892018-05-07 18:43:45 -07001406 case POWER_SUPPLY_PROP_CYCLE_COUNT:
Ashay Jaiswal5c5ba272018-07-23 14:54:20 +05301407 rc = smblib_get_prop_from_bms(chg,
1408 POWER_SUPPLY_PROP_CYCLE_COUNT, val);
Subbaraman Narayanamurthyc4feb892018-05-07 18:43:45 -07001409 break;
Anirudh Ghayal1380d312018-02-23 00:01:43 +05301410 case POWER_SUPPLY_PROP_RECHARGE_SOC:
1411 val->intval = chg->auto_recharge_soc;
1412 break;
Ashay Jaiswal5c5ba272018-07-23 14:54:20 +05301413 case POWER_SUPPLY_PROP_CHARGE_FULL:
1414 rc = smblib_get_prop_from_bms(chg,
1415 POWER_SUPPLY_PROP_CHARGE_FULL, val);
1416 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001417 default:
1418 pr_err("batt power supply prop %d not supported\n", psp);
1419 return -EINVAL;
1420 }
1421
1422 if (rc < 0) {
1423 pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
1424 return -ENODATA;
1425 }
1426
1427 return 0;
1428}
1429
1430static int smb5_batt_set_prop(struct power_supply *psy,
1431 enum power_supply_property prop,
1432 const union power_supply_propval *val)
1433{
1434 int rc = 0;
1435 struct smb_charger *chg = power_supply_get_drvdata(psy);
Ashay Jaiswala55b7ed2018-03-23 17:23:48 +05301436 bool enable;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001437
1438 switch (prop) {
1439 case POWER_SUPPLY_PROP_STATUS:
1440 rc = smblib_set_prop_batt_status(chg, val);
1441 break;
1442 case POWER_SUPPLY_PROP_INPUT_SUSPEND:
1443 rc = smblib_set_prop_input_suspend(chg, val);
1444 break;
Anirudh Ghayaldfdb8412018-04-21 10:37:18 +05301445 case POWER_SUPPLY_PROP_BATTERY_CHARGING_ENABLED:
1446 vote(chg->chg_disable_votable, USER_VOTER, !val->intval, 0);
1447 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001448 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
1449 rc = smblib_set_prop_system_temp_level(chg, val);
1450 break;
1451 case POWER_SUPPLY_PROP_CAPACITY:
1452 rc = smblib_set_prop_batt_capacity(chg, val);
1453 break;
1454 case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
1455 vote(chg->pl_disable_votable, USER_VOTER, (bool)val->intval, 0);
1456 break;
1457 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
1458 chg->batt_profile_fv_uv = val->intval;
1459 vote(chg->fv_votable, BATT_PROFILE_VOTER, true, val->intval);
1460 break;
1461 case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
Ashay Jaiswala55b7ed2018-03-23 17:23:48 +05301462 enable = !!val->intval || chg->sw_jeita_enabled;
1463 rc = smblib_configure_wdog(chg, enable);
1464 if (rc == 0)
1465 chg->step_chg_enabled = !!val->intval;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001466 break;
1467 case POWER_SUPPLY_PROP_SW_JEITA_ENABLED:
1468 if (chg->sw_jeita_enabled != (!!val->intval)) {
1469 rc = smblib_disable_hw_jeita(chg, !!val->intval);
Ashay Jaiswala55b7ed2018-03-23 17:23:48 +05301470 enable = !!val->intval || chg->step_chg_enabled;
1471 rc |= smblib_configure_wdog(chg, enable);
Harry Yang4b7db0f2017-11-27 10:50:44 -08001472 if (rc == 0)
1473 chg->sw_jeita_enabled = !!val->intval;
1474 }
1475 break;
1476 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
1477 chg->batt_profile_fcc_ua = val->intval;
1478 vote(chg->fcc_votable, BATT_PROFILE_VOTER, true, val->intval);
1479 break;
1480 case POWER_SUPPLY_PROP_SET_SHIP_MODE:
1481 /* Not in ship mode as long as the device is active */
1482 if (!val->intval)
1483 break;
1484 if (chg->pl.psy)
1485 power_supply_set_property(chg->pl.psy,
1486 POWER_SUPPLY_PROP_SET_SHIP_MODE, val);
1487 rc = smblib_set_prop_ship_mode(chg, val);
1488 break;
1489 case POWER_SUPPLY_PROP_RERUN_AICL:
Ashay Jaiswale0b3c472018-06-20 23:39:41 +05301490 rc = smblib_run_aicl(chg, RERUN_AICL);
Harry Yang4b7db0f2017-11-27 10:50:44 -08001491 break;
1492 case POWER_SUPPLY_PROP_DP_DM:
Ashay Jaiswal4d334f42018-04-25 10:58:49 +05301493 if (!chg->flash_active)
1494 rc = smblib_dp_dm(chg, val->intval);
Harry Yang4b7db0f2017-11-27 10:50:44 -08001495 break;
1496 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
1497 rc = smblib_set_prop_input_current_limited(chg, val);
1498 break;
1499 case POWER_SUPPLY_PROP_DIE_HEALTH:
1500 chg->die_health = val->intval;
1501 power_supply_changed(chg->batt_psy);
1502 break;
Anirudh Ghayaldfdb8412018-04-21 10:37:18 +05301503 case POWER_SUPPLY_PROP_RECHARGE_SOC:
1504 if (chg->smb_version == PMI632_SUBTYPE) {
1505 /* toggle charging to force recharge */
1506 vote(chg->chg_disable_votable, FORCE_RECHARGE_VOTER,
1507 true, 0);
1508 /* charge disable delay */
1509 msleep(50);
1510 vote(chg->chg_disable_votable, FORCE_RECHARGE_VOTER,
1511 false, 0);
1512 }
1513 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001514 default:
1515 rc = -EINVAL;
1516 }
1517
1518 return rc;
1519}
1520
1521static int smb5_batt_prop_is_writeable(struct power_supply *psy,
1522 enum power_supply_property psp)
1523{
1524 switch (psp) {
1525 case POWER_SUPPLY_PROP_STATUS:
1526 case POWER_SUPPLY_PROP_INPUT_SUSPEND:
1527 case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL:
1528 case POWER_SUPPLY_PROP_CAPACITY:
1529 case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
1530 case POWER_SUPPLY_PROP_DP_DM:
1531 case POWER_SUPPLY_PROP_RERUN_AICL:
1532 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
1533 case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
1534 case POWER_SUPPLY_PROP_SW_JEITA_ENABLED:
1535 case POWER_SUPPLY_PROP_DIE_HEALTH:
Anirudh Ghayaldfdb8412018-04-21 10:37:18 +05301536 case POWER_SUPPLY_PROP_BATTERY_CHARGING_ENABLED:
Harry Yang4b7db0f2017-11-27 10:50:44 -08001537 return 1;
1538 default:
1539 break;
1540 }
1541
1542 return 0;
1543}
1544
1545static const struct power_supply_desc batt_psy_desc = {
1546 .name = "battery",
1547 .type = POWER_SUPPLY_TYPE_BATTERY,
1548 .properties = smb5_batt_props,
1549 .num_properties = ARRAY_SIZE(smb5_batt_props),
1550 .get_property = smb5_batt_get_prop,
1551 .set_property = smb5_batt_set_prop,
1552 .property_is_writeable = smb5_batt_prop_is_writeable,
1553};
1554
1555static int smb5_init_batt_psy(struct smb5 *chip)
1556{
1557 struct power_supply_config batt_cfg = {};
1558 struct smb_charger *chg = &chip->chg;
1559 int rc = 0;
1560
1561 batt_cfg.drv_data = chg;
1562 batt_cfg.of_node = chg->dev->of_node;
1563 chg->batt_psy = devm_power_supply_register(chg->dev,
1564 &batt_psy_desc,
1565 &batt_cfg);
1566 if (IS_ERR(chg->batt_psy)) {
1567 pr_err("Couldn't register battery power supply\n");
1568 return PTR_ERR(chg->batt_psy);
1569 }
1570
1571 return rc;
1572}
1573
1574/******************************
1575 * VBUS REGULATOR REGISTRATION *
1576 ******************************/
1577
1578static struct regulator_ops smb5_vbus_reg_ops = {
1579 .enable = smblib_vbus_regulator_enable,
1580 .disable = smblib_vbus_regulator_disable,
1581 .is_enabled = smblib_vbus_regulator_is_enabled,
1582};
1583
1584static int smb5_init_vbus_regulator(struct smb5 *chip)
1585{
1586 struct smb_charger *chg = &chip->chg;
1587 struct regulator_config cfg = {};
1588 int rc = 0;
1589
1590 chg->vbus_vreg = devm_kzalloc(chg->dev, sizeof(*chg->vbus_vreg),
1591 GFP_KERNEL);
1592 if (!chg->vbus_vreg)
1593 return -ENOMEM;
1594
1595 cfg.dev = chg->dev;
1596 cfg.driver_data = chip;
1597
1598 chg->vbus_vreg->rdesc.owner = THIS_MODULE;
1599 chg->vbus_vreg->rdesc.type = REGULATOR_VOLTAGE;
1600 chg->vbus_vreg->rdesc.ops = &smb5_vbus_reg_ops;
1601 chg->vbus_vreg->rdesc.of_match = "qcom,smb5-vbus";
1602 chg->vbus_vreg->rdesc.name = "qcom,smb5-vbus";
1603
1604 chg->vbus_vreg->rdev = devm_regulator_register(chg->dev,
1605 &chg->vbus_vreg->rdesc, &cfg);
1606 if (IS_ERR(chg->vbus_vreg->rdev)) {
1607 rc = PTR_ERR(chg->vbus_vreg->rdev);
1608 chg->vbus_vreg->rdev = NULL;
1609 if (rc != -EPROBE_DEFER)
1610 pr_err("Couldn't register VBUS regulator rc=%d\n", rc);
1611 }
1612
1613 return rc;
1614}
1615
1616/******************************
1617 * VCONN REGULATOR REGISTRATION *
1618 ******************************/
1619
1620static struct regulator_ops smb5_vconn_reg_ops = {
1621 .enable = smblib_vconn_regulator_enable,
1622 .disable = smblib_vconn_regulator_disable,
1623 .is_enabled = smblib_vconn_regulator_is_enabled,
1624};
1625
1626static int smb5_init_vconn_regulator(struct smb5 *chip)
1627{
1628 struct smb_charger *chg = &chip->chg;
1629 struct regulator_config cfg = {};
1630 int rc = 0;
1631
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301632 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
Harry Yang4b7db0f2017-11-27 10:50:44 -08001633 return 0;
1634
1635 chg->vconn_vreg = devm_kzalloc(chg->dev, sizeof(*chg->vconn_vreg),
1636 GFP_KERNEL);
1637 if (!chg->vconn_vreg)
1638 return -ENOMEM;
1639
1640 cfg.dev = chg->dev;
1641 cfg.driver_data = chip;
1642
1643 chg->vconn_vreg->rdesc.owner = THIS_MODULE;
1644 chg->vconn_vreg->rdesc.type = REGULATOR_VOLTAGE;
1645 chg->vconn_vreg->rdesc.ops = &smb5_vconn_reg_ops;
1646 chg->vconn_vreg->rdesc.of_match = "qcom,smb5-vconn";
1647 chg->vconn_vreg->rdesc.name = "qcom,smb5-vconn";
1648
1649 chg->vconn_vreg->rdev = devm_regulator_register(chg->dev,
1650 &chg->vconn_vreg->rdesc, &cfg);
1651 if (IS_ERR(chg->vconn_vreg->rdev)) {
1652 rc = PTR_ERR(chg->vconn_vreg->rdev);
1653 chg->vconn_vreg->rdev = NULL;
1654 if (rc != -EPROBE_DEFER)
1655 pr_err("Couldn't register VCONN regulator rc=%d\n", rc);
1656 }
1657
1658 return rc;
1659}
1660
1661/***************************
1662 * HARDWARE INITIALIZATION *
1663 ***************************/
1664static int smb5_configure_typec(struct smb_charger *chg)
1665{
1666 int rc;
Ashay Jaiswal91d63f42018-05-16 11:30:40 +05301667 u8 val = 0;
1668
1669 rc = smblib_read(chg, LEGACY_CABLE_STATUS_REG, &val);
1670 if (rc < 0) {
1671 dev_err(chg->dev, "Couldn't read Legacy status rc=%d\n", rc);
1672 return rc;
1673 }
1674 /*
1675 * If Legacy cable is detected re-trigger Legacy detection
1676 * by disabling/enabling typeC mode.
1677 */
1678 if (val & TYPEC_LEGACY_CABLE_STATUS_BIT) {
1679 rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
1680 TYPEC_DISABLE_CMD_BIT, TYPEC_DISABLE_CMD_BIT);
1681 if (rc < 0) {
1682 dev_err(chg->dev, "Couldn't disable TYPEC rc=%d\n", rc);
1683 return rc;
1684 }
1685
1686 /* delay before enabling typeC */
1687 msleep(500);
1688
1689 rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
1690 TYPEC_DISABLE_CMD_BIT, 0);
1691 if (rc < 0) {
1692 dev_err(chg->dev, "Couldn't enable TYPEC rc=%d\n", rc);
1693 return rc;
1694 }
1695 }
Harry Yang4b7db0f2017-11-27 10:50:44 -08001696
Harry Yang6afaea22018-03-26 19:11:07 -07001697 /* disable apsd */
Ashay Jaiswalc96380de2018-05-16 12:02:36 +05301698 rc = smblib_configure_hvdcp_apsd(chg, false);
Harry Yang6afaea22018-03-26 19:11:07 -07001699 if (rc < 0) {
1700 dev_err(chg->dev, "Couldn't disable APSD rc=%d\n", rc);
1701 return rc;
1702 }
1703
Harry Yang4b7db0f2017-11-27 10:50:44 -08001704 rc = smblib_write(chg, TYPE_C_INTERRUPT_EN_CFG_1_REG,
1705 TYPEC_CCOUT_DETACH_INT_EN_BIT |
1706 TYPEC_CCOUT_ATTACH_INT_EN_BIT);
1707 if (rc < 0) {
1708 dev_err(chg->dev,
1709 "Couldn't configure Type-C interrupts rc=%d\n", rc);
1710 return rc;
1711 }
1712
Harry Yang423d5c32018-05-30 15:49:04 -07001713 rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
1714 EN_TRY_SNK_BIT, EN_TRY_SNK_BIT);
1715 if (rc < 0) {
1716 dev_err(chg->dev,
1717 "Couldn't enable try.snk rc=%d\n", rc);
1718 return rc;
1719 }
1720
Ashay Jaiswald5022b62018-05-27 19:21:11 +05301721 /* Keep VCONN in h/w controlled mode for PMI632 */
1722 if (chg->smb_version != PMI632_SUBTYPE) {
1723 /* configure VCONN for software control */
1724 rc = smblib_masked_write(chg, TYPE_C_VCONN_CONTROL_REG,
Harry Yang4b7db0f2017-11-27 10:50:44 -08001725 VCONN_EN_SRC_BIT | VCONN_EN_VALUE_BIT,
1726 VCONN_EN_SRC_BIT);
Ashay Jaiswald5022b62018-05-27 19:21:11 +05301727 if (rc < 0) {
1728 dev_err(chg->dev,
1729 "Couldn't configure VCONN for SW control rc=%d\n",
1730 rc);
1731 return rc;
1732 }
Harry Yang4b7db0f2017-11-27 10:50:44 -08001733 }
1734
1735 return rc;
1736}
1737
1738static int smb5_configure_micro_usb(struct smb_charger *chg)
1739{
1740 int rc;
1741
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301742 rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG,
1743 MICRO_USB_STATE_CHANGE_INT_EN_BIT,
1744 MICRO_USB_STATE_CHANGE_INT_EN_BIT);
1745 if (rc < 0) {
1746 dev_err(chg->dev,
1747 "Couldn't configure Type-C interrupts rc=%d\n", rc);
1748 return rc;
1749 }
1750
Umang Agrawal461e9ea2018-07-05 18:50:13 +05301751 if (chg->moisture_protection_enabled &&
1752 (chg->wa_flags & MOISTURE_PROTECTION_WA)) {
1753 /* Enable moisture detection interrupt */
1754 rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG,
1755 TYPEC_WATER_DETECTION_INT_EN_BIT,
1756 TYPEC_WATER_DETECTION_INT_EN_BIT);
1757 if (rc < 0) {
1758 dev_err(chg->dev, "Couldn't enable moisture detection interrupt rc=%d\n",
1759 rc);
1760 return rc;
1761 }
1762
1763 /* Enable uUSB factory mode */
1764 rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG,
1765 EN_MICRO_USB_FACTORY_MODE_BIT,
1766 EN_MICRO_USB_FACTORY_MODE_BIT);
1767 if (rc < 0) {
1768 dev_err(chg->dev, "Couldn't enable uUSB factory mode c=%d\n",
1769 rc);
1770 return rc;
1771 }
1772
1773 /* Disable periodic monitoring of CC_ID pin */
1774 rc = smblib_write(chg, TYPEC_U_USB_WATER_PROTECTION_CFG_REG, 0);
1775 if (rc < 0) {
1776 dev_err(chg->dev, "Couldn't disable periodic monitoring of CC_ID rc=%d\n",
1777 rc);
1778 return rc;
1779 }
1780 }
1781
Harry Yang4b7db0f2017-11-27 10:50:44 -08001782 return rc;
1783}
1784
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +05301785static int smb5_configure_mitigation(struct smb_charger *chg)
1786{
1787 int rc;
1788 u8 chan = 0;
1789
1790 if (!chg->hw_die_temp_mitigation && !chg->hw_connector_mitigation)
1791 return 0;
1792
1793 if (chg->hw_die_temp_mitigation) {
1794 rc = smblib_write(chg, MISC_THERMREG_SRC_CFG_REG,
1795 THERMREG_CONNECTOR_ADC_SRC_EN_BIT
1796 | THERMREG_DIE_ADC_SRC_EN_BIT
1797 | THERMREG_DIE_CMP_SRC_EN_BIT);
1798 if (rc < 0) {
1799 dev_err(chg->dev,
1800 "Couldn't configure THERM_SRC reg rc=%d\n", rc);
1801 return rc;
1802 };
1803
1804 chan = DIE_TEMP_CHANNEL_EN_BIT;
1805 }
1806
1807 if (chg->hw_connector_mitigation)
1808 chan |= CONN_THM_CHANNEL_EN_BIT;
1809
1810 rc = smblib_masked_write(chg, BATIF_ADC_CHANNEL_EN_REG,
1811 CONN_THM_CHANNEL_EN_BIT | DIE_TEMP_CHANNEL_EN_BIT,
1812 chan);
1813 if (rc < 0) {
Ashay Jaiswalb50706d2018-06-28 19:37:31 +05301814 dev_err(chg->dev, "Couldn't enable ADC channel rc=%d\n", rc);
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +05301815 return rc;
1816 }
1817
1818 return 0;
1819}
1820
Ashay Jaiswald802c3d2018-07-25 14:55:10 +05301821#define RAW_TERM_CURR(conv_factor, scaled_ma) \
1822 div_s64((int64_t)scaled_ma * 10000, conv_factor)
1823#define ITERM_LIMITS_PMI632_MA 5000
1824#define ITERM_LIMITS_PM855B_MA 10000
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001825static int smb5_configure_iterm_thresholds_adc(struct smb5 *chip)
1826{
Guru Das Srinagesh31b2bb02018-06-20 15:44:03 -07001827 u8 *buf;
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001828 int rc = 0;
Ashay Jaiswald802c3d2018-07-25 14:55:10 +05301829 int raw_hi_thresh, raw_lo_thresh, max_limit_ma, scaling_factor;
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001830 struct smb_charger *chg = &chip->chg;
1831
Ashay Jaiswald802c3d2018-07-25 14:55:10 +05301832 if (chip->chg.smb_version == PMI632_SUBTYPE) {
1833 scaling_factor = ITERM_SCALING_FACTOR_PMI632;
1834 max_limit_ma = ITERM_LIMITS_PMI632_MA;
1835 } else {
1836 scaling_factor = ITERM_SCALING_FACTOR_PM855B;
1837 max_limit_ma = ITERM_LIMITS_PM855B_MA;
1838 }
1839
1840 if (chip->dt.term_current_thresh_hi_ma < (-1 * max_limit_ma)
1841 || chip->dt.term_current_thresh_hi_ma > max_limit_ma
1842 || chip->dt.term_current_thresh_lo_ma < (-1 * max_limit_ma)
1843 || chip->dt.term_current_thresh_lo_ma > max_limit_ma) {
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001844 dev_err(chg->dev, "ITERM threshold out of range rc=%d\n", rc);
1845 return -EINVAL;
1846 }
1847
1848 /*
1849 * Conversion:
Ashay Jaiswald802c3d2018-07-25 14:55:10 +05301850 * raw (A) = (scaled_mA * (10000) / conv_factor)
Guru Das Srinagesh31b2bb02018-06-20 15:44:03 -07001851 * Note: raw needs to be converted to big-endian format.
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001852 */
1853
1854 if (chip->dt.term_current_thresh_hi_ma) {
Ashay Jaiswald802c3d2018-07-25 14:55:10 +05301855 raw_hi_thresh = RAW_TERM_CURR(scaling_factor,
1856 chip->dt.term_current_thresh_hi_ma);
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001857 raw_hi_thresh = sign_extend32(raw_hi_thresh, 15);
Guru Das Srinagesh31b2bb02018-06-20 15:44:03 -07001858 buf = (u8 *)&raw_hi_thresh;
1859 raw_hi_thresh = buf[1] | (buf[0] << 8);
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001860
1861 rc = smblib_batch_write(chg, CHGR_ADC_ITERM_UP_THD_MSB_REG,
1862 (u8 *)&raw_hi_thresh, 2);
1863 if (rc < 0) {
1864 dev_err(chg->dev, "Couldn't configure ITERM threshold HIGH rc=%d\n",
1865 rc);
1866 return rc;
1867 }
1868 }
1869
1870 if (chip->dt.term_current_thresh_lo_ma) {
Ashay Jaiswald802c3d2018-07-25 14:55:10 +05301871 raw_lo_thresh = RAW_TERM_CURR(scaling_factor,
1872 chip->dt.term_current_thresh_lo_ma);
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001873 raw_lo_thresh = sign_extend32(raw_lo_thresh, 15);
Guru Das Srinagesh31b2bb02018-06-20 15:44:03 -07001874 buf = (u8 *)&raw_lo_thresh;
1875 raw_lo_thresh = buf[1] | (buf[0] << 8);
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001876
1877 rc = smblib_batch_write(chg, CHGR_ADC_ITERM_LO_THD_MSB_REG,
1878 (u8 *)&raw_lo_thresh, 2);
1879 if (rc < 0) {
1880 dev_err(chg->dev, "Couldn't configure ITERM threshold LOW rc=%d\n",
1881 rc);
1882 return rc;
1883 }
1884 }
1885
1886 return rc;
1887}
1888
1889static int smb5_configure_iterm_thresholds(struct smb5 *chip)
1890{
1891 int rc = 0;
1892
1893 switch (chip->dt.term_current_src) {
1894 case ITERM_SRC_ADC:
1895 rc = smb5_configure_iterm_thresholds_adc(chip);
1896 break;
1897 default:
1898 break;
1899 }
1900
1901 return rc;
1902}
1903
Harry Yang4b7db0f2017-11-27 10:50:44 -08001904static int smb5_init_hw(struct smb5 *chip)
1905{
1906 struct smb_charger *chg = &chip->chg;
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301907 int rc, type = 0;
1908 u8 val = 0;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001909
1910 if (chip->dt.no_battery)
1911 chg->fake_capacity = 50;
1912
1913 if (chip->dt.batt_profile_fcc_ua < 0)
1914 smblib_get_charge_param(chg, &chg->param.fcc,
1915 &chg->batt_profile_fcc_ua);
1916
1917 if (chip->dt.batt_profile_fv_uv < 0)
1918 smblib_get_charge_param(chg, &chg->param.fv,
1919 &chg->batt_profile_fv_uv);
1920
1921 smblib_get_charge_param(chg, &chg->param.usb_icl,
1922 &chg->default_icl_ua);
Ashay Jaiswale0b3c472018-06-20 23:39:41 +05301923 smblib_get_charge_param(chg, &chg->param.aicl_5v_threshold,
1924 &chg->default_aicl_5v_threshold_mv);
1925 chg->aicl_5v_threshold_mv = chg->default_aicl_5v_threshold_mv;
1926 smblib_get_charge_param(chg, &chg->param.aicl_cont_threshold,
1927 &chg->default_aicl_cont_threshold_mv);
1928 chg->aicl_cont_threshold_mv = chg->default_aicl_cont_threshold_mv;
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301929
1930 /* Use SW based VBUS control, disable HW autonomous mode */
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301931 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1932 HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT,
1933 HVDCP_AUTH_ALG_EN_CFG_BIT);
1934 if (rc < 0) {
1935 dev_err(chg->dev, "Couldn't configure HVDCP rc=%d\n", rc);
1936 return rc;
1937 }
1938
1939 /*
1940 * PMI632 can have the connector type defined by a dedicated register
1941 * TYPEC_MICRO_USB_MODE_REG or by a common TYPEC_U_USB_CFG_REG.
1942 */
1943 if (chg->smb_version == PMI632_SUBTYPE) {
1944 rc = smblib_read(chg, TYPEC_MICRO_USB_MODE_REG, &val);
1945 if (rc < 0) {
1946 dev_err(chg->dev, "Couldn't read USB mode rc=%d\n", rc);
1947 return rc;
1948 }
1949 type = !!(val & MICRO_USB_MODE_ONLY_BIT);
1950 }
1951
1952 /*
1953 * If TYPEC_MICRO_USB_MODE_REG is not set and for all non-PMI632
1954 * check the connector type using TYPEC_U_USB_CFG_REG.
1955 */
1956 if (!type) {
1957 rc = smblib_read(chg, TYPEC_U_USB_CFG_REG, &val);
1958 if (rc < 0) {
1959 dev_err(chg->dev, "Couldn't read U_USB config rc=%d\n",
1960 rc);
1961 return rc;
1962 }
1963
1964 type = !!(val & EN_MICRO_USB_MODE_BIT);
1965 }
1966
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301967 pr_debug("Connector type=%s\n", type ? "Micro USB" : "TypeC");
1968
Harry Yang6afaea22018-03-26 19:11:07 -07001969 if (type) {
1970 chg->connector_type = POWER_SUPPLY_CONNECTOR_MICRO_USB;
Harry Yang6afaea22018-03-26 19:11:07 -07001971 rc = smb5_configure_micro_usb(chg);
1972 } else {
1973 chg->connector_type = POWER_SUPPLY_CONNECTOR_TYPEC;
1974 rc = smb5_configure_typec(chg);
1975 }
1976 if (rc < 0) {
1977 dev_err(chg->dev,
1978 "Couldn't configure TypeC/micro-USB mode rc=%d\n", rc);
1979 return rc;
1980 }
1981
Ashay Jaiswal09feab82018-02-12 12:33:18 +05301982 /*
1983 * PMI632 based hw init:
Ashay Jaiswal6f70a512018-05-11 17:25:58 +05301984 * - Enable STAT pin function on SMB_EN
Ashay Jaiswalc96380de2018-05-16 12:02:36 +05301985 * - Rerun APSD to ensure proper charger detection if device
1986 * boots with charger connected.
Ashay Jaiswal09feab82018-02-12 12:33:18 +05301987 * - Initialize flash module for PMI632
1988 */
Ashay Jaiswalc96380de2018-05-16 12:02:36 +05301989 if (chg->smb_version == PMI632_SUBTYPE) {
Ashay Jaiswal6f70a512018-05-11 17:25:58 +05301990 rc = smblib_masked_write(chg, MISC_SMB_EN_CMD_REG,
1991 EN_STAT_CMD_BIT, EN_STAT_CMD_BIT);
1992 if (rc < 0) {
1993 dev_err(chg->dev, "Couldn't configure SMB_EN rc=%d\n",
1994 rc);
1995 return rc;
1996 }
1997
Ashay Jaiswal09feab82018-02-12 12:33:18 +05301998 schgm_flash_init(chg);
Ashay Jaiswalc96380de2018-05-16 12:02:36 +05301999 smblib_rerun_apsd_if_required(chg);
2000 }
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302001
Ashay Jaiswalcbdf2e82018-05-27 23:59:01 +05302002 /* clear the ICL override if it is set */
2003 rc = smblib_icl_override(chg, false);
2004 if (rc < 0) {
2005 pr_err("Couldn't disable ICL override rc=%d\n", rc);
2006 return rc;
2007 }
2008
Ashay Jaiswalb2b06fe2018-06-07 18:35:21 +05302009 /* set OTG current limit */
2010 rc = smblib_set_charge_param(chg, &chg->param.otg_cl, chg->otg_cl_ua);
2011 if (rc < 0) {
2012 pr_err("Couldn't set otg current limit rc=%d\n", rc);
2013 return rc;
2014 }
2015
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +05302016 /* configure temperature mitigation */
2017 rc = smb5_configure_mitigation(chg);
2018 if (rc < 0) {
2019 dev_err(chg->dev, "Couldn't configure mitigation rc=%d\n", rc);
2020 return rc;
2021 }
2022
Harry Yang4b7db0f2017-11-27 10:50:44 -08002023 /* vote 0mA on usb_icl for non battery platforms */
2024 vote(chg->usb_icl_votable,
2025 DEFAULT_VOTER, chip->dt.no_battery, 0);
2026 vote(chg->dc_suspend_votable,
2027 DEFAULT_VOTER, chip->dt.no_battery, 0);
2028 vote(chg->fcc_votable, HW_LIMIT_VOTER,
2029 chip->dt.batt_profile_fcc_ua > 0, chip->dt.batt_profile_fcc_ua);
2030 vote(chg->fv_votable, HW_LIMIT_VOTER,
2031 chip->dt.batt_profile_fv_uv > 0, chip->dt.batt_profile_fv_uv);
2032 vote(chg->fcc_votable,
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302033 BATT_PROFILE_VOTER, chg->batt_profile_fcc_ua > 0,
2034 chg->batt_profile_fcc_ua);
Harry Yang4b7db0f2017-11-27 10:50:44 -08002035 vote(chg->fv_votable,
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302036 BATT_PROFILE_VOTER, chg->batt_profile_fv_uv > 0,
2037 chg->batt_profile_fv_uv);
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302038
2039 /* Some h/w limit maximum supported ICL */
2040 vote(chg->usb_icl_votable, HW_LIMIT_VOTER,
2041 chg->hw_max_icl_ua > 0, chg->hw_max_icl_ua);
Harry Yang4b7db0f2017-11-27 10:50:44 -08002042
2043 /*
2044 * AICL configuration:
Ashay Jaiswalc96380de2018-05-16 12:02:36 +05302045 * AICL ADC disable
Harry Yang4b7db0f2017-11-27 10:50:44 -08002046 */
Ashay Jaiswalc96380de2018-05-16 12:02:36 +05302047 if (chg->smb_version != PMI632_SUBTYPE) {
2048 rc = smblib_masked_write(chg, USBIN_AICL_OPTIONS_CFG_REG,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002049 USBIN_AICL_ADC_EN_BIT, 0);
Ashay Jaiswalc96380de2018-05-16 12:02:36 +05302050 if (rc < 0) {
2051 dev_err(chg->dev, "Couldn't config AICL rc=%d\n", rc);
2052 return rc;
2053 }
Harry Yang4b7db0f2017-11-27 10:50:44 -08002054 }
2055
2056 /* enable the charging path */
2057 rc = vote(chg->chg_disable_votable, DEFAULT_VOTER, false, 0);
2058 if (rc < 0) {
2059 dev_err(chg->dev, "Couldn't enable charging rc=%d\n", rc);
2060 return rc;
2061 }
2062
Harry Yang4b7db0f2017-11-27 10:50:44 -08002063 /* configure VBUS for software control */
2064 rc = smblib_masked_write(chg, DCDC_OTG_CFG_REG, OTG_EN_SRC_CFG_BIT, 0);
2065 if (rc < 0) {
2066 dev_err(chg->dev,
2067 "Couldn't configure VBUS for SW control rc=%d\n", rc);
2068 return rc;
2069 }
2070
Ashay Jaiswala55b7ed2018-03-23 17:23:48 +05302071 /*
2072 * configure the one time watchdong periodic interval and
2073 * disable "watchdog bite disable charging".
2074 */
Harry Yang4b7db0f2017-11-27 10:50:44 -08002075 val = (ilog2(chip->dt.wd_bark_time / 16) << BARK_WDOG_TIMEOUT_SHIFT)
2076 & BARK_WDOG_TIMEOUT_MASK;
2077 val |= BITE_WDOG_TIMEOUT_8S;
2078 rc = smblib_masked_write(chg, SNARL_BARK_BITE_WD_CFG_REG,
2079 BITE_WDOG_DISABLE_CHARGING_CFG_BIT |
2080 BARK_WDOG_TIMEOUT_MASK | BITE_WDOG_TIMEOUT_MASK,
2081 val);
2082 if (rc < 0) {
2083 pr_err("Couldn't configue WD config rc=%d\n", rc);
2084 return rc;
2085 }
2086
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07002087 /* set termination current threshold values */
2088 rc = smb5_configure_iterm_thresholds(chip);
2089 if (rc < 0) {
2090 pr_err("Couldn't configure ITERM thresholds rc=%d\n",
2091 rc);
2092 return rc;
2093 }
2094
Harry Yang4b7db0f2017-11-27 10:50:44 -08002095 /* configure float charger options */
2096 switch (chip->dt.float_option) {
2097 case FLOAT_DCP:
2098 rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
2099 FLOAT_OPTIONS_MASK, 0);
2100 break;
2101 case FLOAT_SDP:
2102 rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
2103 FLOAT_OPTIONS_MASK, FORCE_FLOAT_SDP_CFG_BIT);
2104 break;
2105 case DISABLE_CHARGING:
2106 rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
2107 FLOAT_OPTIONS_MASK, FLOAT_DIS_CHGING_CFG_BIT);
2108 break;
2109 case SUSPEND_INPUT:
2110 rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
2111 FLOAT_OPTIONS_MASK, SUSPEND_FLOAT_CFG_BIT);
2112 break;
2113 default:
2114 rc = 0;
2115 break;
2116 }
2117
2118 if (rc < 0) {
2119 dev_err(chg->dev, "Couldn't configure float charger options rc=%d\n",
2120 rc);
2121 return rc;
2122 }
2123
2124 rc = smblib_read(chg, USBIN_OPTIONS_2_CFG_REG, &chg->float_cfg);
2125 if (rc < 0) {
2126 dev_err(chg->dev, "Couldn't read float charger options rc=%d\n",
2127 rc);
2128 return rc;
2129 }
2130
2131 switch (chip->dt.chg_inhibit_thr_mv) {
2132 case 50:
2133 rc = smblib_masked_write(chg, CHARGE_INHIBIT_THRESHOLD_CFG_REG,
2134 CHARGE_INHIBIT_THRESHOLD_MASK,
2135 INHIBIT_ANALOG_VFLT_MINUS_50MV);
2136 break;
2137 case 100:
2138 rc = smblib_masked_write(chg, CHARGE_INHIBIT_THRESHOLD_CFG_REG,
2139 CHARGE_INHIBIT_THRESHOLD_MASK,
2140 INHIBIT_ANALOG_VFLT_MINUS_100MV);
2141 break;
2142 case 200:
2143 rc = smblib_masked_write(chg, CHARGE_INHIBIT_THRESHOLD_CFG_REG,
2144 CHARGE_INHIBIT_THRESHOLD_MASK,
2145 INHIBIT_ANALOG_VFLT_MINUS_200MV);
2146 break;
2147 case 300:
2148 rc = smblib_masked_write(chg, CHARGE_INHIBIT_THRESHOLD_CFG_REG,
2149 CHARGE_INHIBIT_THRESHOLD_MASK,
2150 INHIBIT_ANALOG_VFLT_MINUS_300MV);
2151 break;
2152 case 0:
2153 rc = smblib_masked_write(chg, CHGR_CFG2_REG,
2154 CHARGER_INHIBIT_BIT, 0);
2155 default:
2156 break;
2157 }
2158
2159 if (rc < 0) {
2160 dev_err(chg->dev, "Couldn't configure charge inhibit threshold rc=%d\n",
2161 rc);
2162 return rc;
2163 }
2164
Anirudh Ghayal1380d312018-02-23 00:01:43 +05302165 rc = smblib_masked_write(chg, CHGR_CFG2_REG, RECHG_MASK,
2166 (chip->dt.auto_recharge_vbat_mv != -EINVAL) ?
2167 VBAT_BASED_RECHG_BIT : 0);
Harry Yang4b7db0f2017-11-27 10:50:44 -08002168 if (rc < 0) {
Anirudh Ghayal1380d312018-02-23 00:01:43 +05302169 dev_err(chg->dev, "Couldn't configure VBAT-rechg CHG_CFG2_REG rc=%d\n",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002170 rc);
2171 return rc;
2172 }
2173
Anirudh Ghayal1380d312018-02-23 00:01:43 +05302174 /* program the auto-recharge VBAT threshold */
2175 if (chip->dt.auto_recharge_vbat_mv != -EINVAL) {
2176 u32 temp = VBAT_TO_VRAW_ADC(chip->dt.auto_recharge_vbat_mv);
2177
2178 temp = ((temp & 0xFF00) >> 8) | ((temp & 0xFF) << 8);
2179 rc = smblib_batch_write(chg,
2180 CHGR_ADC_RECHARGE_THRESHOLD_MSB_REG, (u8 *)&temp, 2);
2181 if (rc < 0) {
2182 dev_err(chg->dev, "Couldn't configure ADC_RECHARGE_THRESHOLD REG rc=%d\n",
2183 rc);
2184 return rc;
2185 }
2186 /* Program the sample count for VBAT based recharge to 3 */
2187 rc = smblib_masked_write(chg, CHGR_NO_SAMPLE_TERM_RCHG_CFG_REG,
2188 NO_OF_SAMPLE_FOR_RCHG,
2189 2 << NO_OF_SAMPLE_FOR_RCHG_SHIFT);
2190 if (rc < 0) {
2191 dev_err(chg->dev, "Couldn't configure CHGR_NO_SAMPLE_FOR_TERM_RCHG_CFG rc=%d\n",
2192 rc);
2193 return rc;
2194 }
2195 }
2196
2197 rc = smblib_masked_write(chg, CHGR_CFG2_REG, RECHG_MASK,
2198 (chip->dt.auto_recharge_soc != -EINVAL) ?
2199 SOC_BASED_RECHG_BIT : VBAT_BASED_RECHG_BIT);
2200 if (rc < 0) {
2201 dev_err(chg->dev, "Couldn't configure SOC-rechg CHG_CFG2_REG rc=%d\n",
2202 rc);
2203 return rc;
2204 }
2205
2206 /* program the auto-recharge threshold */
2207 if (chip->dt.auto_recharge_soc != -EINVAL) {
2208 rc = smblib_write(chg, CHARGE_RCHG_SOC_THRESHOLD_CFG_REG,
2209 (chip->dt.auto_recharge_soc * 255) / 100);
2210 if (rc < 0) {
2211 dev_err(chg->dev, "Couldn't configure CHG_RCHG_SOC_REG rc=%d\n",
2212 rc);
2213 return rc;
2214 }
2215 /* Program the sample count for SOC based recharge to 1 */
2216 rc = smblib_masked_write(chg, CHGR_NO_SAMPLE_TERM_RCHG_CFG_REG,
2217 NO_OF_SAMPLE_FOR_RCHG, 0);
2218 if (rc < 0) {
2219 dev_err(chg->dev, "Couldn't configure CHGR_NO_SAMPLE_FOR_TERM_RCHG_CFG rc=%d\n",
2220 rc);
2221 return rc;
2222 }
2223 }
2224
Harry Yang4b7db0f2017-11-27 10:50:44 -08002225 if (chg->sw_jeita_enabled) {
2226 rc = smblib_disable_hw_jeita(chg, true);
2227 if (rc < 0) {
2228 dev_err(chg->dev, "Couldn't set hw jeita rc=%d\n", rc);
2229 return rc;
2230 }
2231 }
2232
Ashay Jaiswala55b7ed2018-03-23 17:23:48 +05302233 rc = smblib_configure_wdog(chg,
2234 chg->step_chg_enabled || chg->sw_jeita_enabled);
2235 if (rc < 0) {
2236 dev_err(chg->dev, "Couldn't configure watchdog rc=%d\n",
2237 rc);
2238 return rc;
2239 }
2240
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +05302241 if (chg->connector_pull_up != -EINVAL) {
2242 rc = smb5_configure_internal_pull(chg, CONN_THERM,
2243 get_valid_pullup(chg->connector_pull_up));
2244 if (rc < 0) {
2245 dev_err(chg->dev,
2246 "Couldn't configure CONN_THERM pull-up rc=%d\n",
2247 rc);
2248 return rc;
2249 }
2250 }
2251
Harry Yang4b7db0f2017-11-27 10:50:44 -08002252 return rc;
2253}
2254
2255static int smb5_post_init(struct smb5 *chip)
2256{
2257 struct smb_charger *chg = &chip->chg;
2258 union power_supply_propval pval;
2259 int rc;
2260
2261 /*
2262 * In case the usb path is suspended, we would have missed disabling
2263 * the icl change interrupt because the interrupt could have been
2264 * not requested
2265 */
2266 rerun_election(chg->usb_icl_votable);
2267
2268 /* configure power role for dual-role */
2269 pval.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
2270 rc = smblib_set_prop_typec_power_role(chg, &pval);
2271 if (rc < 0) {
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302272 dev_err(chg->dev, "Couldn't configure DRP role rc=%d\n",
2273 rc);
Harry Yang4b7db0f2017-11-27 10:50:44 -08002274 return rc;
2275 }
2276
2277 rerun_election(chg->usb_irq_enable_votable);
2278
2279 return 0;
2280}
2281
2282/****************************
2283 * DETERMINE INITIAL STATUS *
2284 ****************************/
2285
2286static int smb5_determine_initial_status(struct smb5 *chip)
2287{
2288 struct smb_irq_data irq_data = {chip, "determine-initial-status"};
2289 struct smb_charger *chg = &chip->chg;
Harry Yang6afaea22018-03-26 19:11:07 -07002290 union power_supply_propval val;
2291 int rc;
2292
2293 rc = smblib_get_prop_usb_present(chg, &val);
2294 if (rc < 0) {
2295 pr_err("Couldn't get usb present rc=%d\n", rc);
2296 return rc;
2297 }
2298 chg->early_usb_attach = val.intval;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002299
2300 if (chg->bms_psy)
2301 smblib_suspend_on_debug_battery(chg);
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302302
Harry Yang4b7db0f2017-11-27 10:50:44 -08002303 usb_plugin_irq_handler(0, &irq_data);
Harry Yang6afaea22018-03-26 19:11:07 -07002304 typec_attach_detach_irq_handler(0, &irq_data);
Harry Yang4b7db0f2017-11-27 10:50:44 -08002305 typec_state_change_irq_handler(0, &irq_data);
2306 usb_source_change_irq_handler(0, &irq_data);
2307 chg_state_change_irq_handler(0, &irq_data);
2308 icl_change_irq_handler(0, &irq_data);
2309 batt_temp_changed_irq_handler(0, &irq_data);
2310 wdog_bark_irq_handler(0, &irq_data);
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302311 typec_or_rid_detection_change_irq_handler(0, &irq_data);
Harry Yang4b7db0f2017-11-27 10:50:44 -08002312
2313 return 0;
2314}
2315
2316/**************************
2317 * INTERRUPT REGISTRATION *
2318 **************************/
2319
2320static struct smb_irq_info smb5_irqs[] = {
2321 /* CHARGER IRQs */
2322 [CHGR_ERROR_IRQ] = {
2323 .name = "chgr-error",
2324 .handler = default_irq_handler,
2325 },
2326 [CHG_STATE_CHANGE_IRQ] = {
2327 .name = "chg-state-change",
2328 .handler = chg_state_change_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302329 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002330 },
2331 [STEP_CHG_STATE_CHANGE_IRQ] = {
2332 .name = "step-chg-state-change",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002333 },
2334 [STEP_CHG_SOC_UPDATE_FAIL_IRQ] = {
2335 .name = "step-chg-soc-update-fail",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002336 },
2337 [STEP_CHG_SOC_UPDATE_REQ_IRQ] = {
2338 .name = "step-chg-soc-update-req",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002339 },
2340 [FG_FVCAL_QUALIFIED_IRQ] = {
2341 .name = "fg-fvcal-qualified",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002342 },
2343 [VPH_ALARM_IRQ] = {
2344 .name = "vph-alarm",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002345 },
2346 [VPH_DROP_PRECHG_IRQ] = {
2347 .name = "vph-drop-prechg",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002348 },
2349 /* DCDC IRQs */
2350 [OTG_FAIL_IRQ] = {
2351 .name = "otg-fail",
2352 .handler = default_irq_handler,
2353 },
2354 [OTG_OC_DISABLE_SW_IRQ] = {
2355 .name = "otg-oc-disable-sw",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002356 },
2357 [OTG_OC_HICCUP_IRQ] = {
2358 .name = "otg-oc-hiccup",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002359 },
2360 [BSM_ACTIVE_IRQ] = {
2361 .name = "bsm-active",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002362 },
2363 [HIGH_DUTY_CYCLE_IRQ] = {
2364 .name = "high-duty-cycle",
2365 .handler = high_duty_cycle_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302366 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002367 },
2368 [INPUT_CURRENT_LIMITING_IRQ] = {
2369 .name = "input-current-limiting",
2370 .handler = default_irq_handler,
2371 },
2372 [CONCURRENT_MODE_DISABLE_IRQ] = {
2373 .name = "concurrent-mode-disable",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002374 },
2375 [SWITCHER_POWER_OK_IRQ] = {
2376 .name = "switcher-power-ok",
2377 .handler = switcher_power_ok_irq_handler,
2378 },
2379 /* BATTERY IRQs */
2380 [BAT_TEMP_IRQ] = {
2381 .name = "bat-temp",
2382 .handler = batt_temp_changed_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302383 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002384 },
2385 [ALL_CHNL_CONV_DONE_IRQ] = {
2386 .name = "all-chnl-conv-done",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002387 },
2388 [BAT_OV_IRQ] = {
2389 .name = "bat-ov",
2390 .handler = batt_psy_changed_irq_handler,
2391 },
2392 [BAT_LOW_IRQ] = {
2393 .name = "bat-low",
2394 .handler = batt_psy_changed_irq_handler,
2395 },
2396 [BAT_THERM_OR_ID_MISSING_IRQ] = {
2397 .name = "bat-therm-or-id-missing",
2398 .handler = batt_psy_changed_irq_handler,
2399 },
2400 [BAT_TERMINAL_MISSING_IRQ] = {
2401 .name = "bat-terminal-missing",
2402 .handler = batt_psy_changed_irq_handler,
2403 },
2404 [BUCK_OC_IRQ] = {
2405 .name = "buck-oc",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002406 },
2407 [VPH_OV_IRQ] = {
2408 .name = "vph-ov",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002409 },
2410 /* USB INPUT IRQs */
2411 [USBIN_COLLAPSE_IRQ] = {
2412 .name = "usbin-collapse",
2413 .handler = default_irq_handler,
2414 },
2415 [USBIN_VASHDN_IRQ] = {
2416 .name = "usbin-vashdn",
2417 .handler = default_irq_handler,
2418 },
2419 [USBIN_UV_IRQ] = {
2420 .name = "usbin-uv",
2421 .handler = usbin_uv_irq_handler,
Ashay Jaiswale0b3c472018-06-20 23:39:41 +05302422 .wake = true,
2423 .storm_data = {true, 3000, 5},
Harry Yang4b7db0f2017-11-27 10:50:44 -08002424 },
2425 [USBIN_OV_IRQ] = {
2426 .name = "usbin-ov",
Ashay Jaiswal43107092018-08-20 18:59:28 +05302427 .handler = usbin_ov_irq_handler,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002428 },
2429 [USBIN_PLUGIN_IRQ] = {
2430 .name = "usbin-plugin",
2431 .handler = usb_plugin_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302432 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002433 },
2434 [USBIN_REVI_CHANGE_IRQ] = {
2435 .name = "usbin-revi-change",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002436 },
2437 [USBIN_SRC_CHANGE_IRQ] = {
2438 .name = "usbin-src-change",
2439 .handler = usb_source_change_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302440 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002441 },
2442 [USBIN_ICL_CHANGE_IRQ] = {
2443 .name = "usbin-icl-change",
2444 .handler = icl_change_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302445 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002446 },
2447 /* DC INPUT IRQs */
2448 [DCIN_VASHDN_IRQ] = {
2449 .name = "dcin-vashdn",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002450 },
2451 [DCIN_UV_IRQ] = {
2452 .name = "dcin-uv",
2453 .handler = default_irq_handler,
2454 },
2455 [DCIN_OV_IRQ] = {
2456 .name = "dcin-ov",
2457 .handler = default_irq_handler,
2458 },
2459 [DCIN_PLUGIN_IRQ] = {
2460 .name = "dcin-plugin",
2461 .handler = dc_plugin_irq_handler,
2462 .wake = true,
2463 },
2464 [DCIN_REVI_IRQ] = {
2465 .name = "dcin-revi",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002466 },
2467 [DCIN_PON_IRQ] = {
2468 .name = "dcin-pon",
2469 .handler = default_irq_handler,
2470 },
2471 [DCIN_EN_IRQ] = {
2472 .name = "dcin-en",
2473 .handler = default_irq_handler,
2474 },
2475 /* TYPEC IRQs */
2476 [TYPEC_OR_RID_DETECTION_CHANGE_IRQ] = {
2477 .name = "typec-or-rid-detect-change",
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302478 .handler = typec_or_rid_detection_change_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302479 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002480 },
2481 [TYPEC_VPD_DETECT_IRQ] = {
2482 .name = "typec-vpd-detect",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002483 },
2484 [TYPEC_CC_STATE_CHANGE_IRQ] = {
2485 .name = "typec-cc-state-change",
2486 .handler = typec_state_change_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302487 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002488 },
2489 [TYPEC_VCONN_OC_IRQ] = {
2490 .name = "typec-vconn-oc",
2491 .handler = default_irq_handler,
2492 },
2493 [TYPEC_VBUS_CHANGE_IRQ] = {
2494 .name = "typec-vbus-change",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002495 },
2496 [TYPEC_ATTACH_DETACH_IRQ] = {
2497 .name = "typec-attach-detach",
Harry Yang6afaea22018-03-26 19:11:07 -07002498 .handler = typec_attach_detach_irq_handler,
Guru Das Srinageshdcd65ed2018-08-14 15:39:35 +05302499 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002500 },
2501 [TYPEC_LEGACY_CABLE_DETECT_IRQ] = {
2502 .name = "typec-legacy-cable-detect",
2503 .handler = default_irq_handler,
2504 },
2505 [TYPEC_TRY_SNK_SRC_DETECT_IRQ] = {
2506 .name = "typec-try-snk-src-detect",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002507 },
2508 /* MISCELLANEOUS IRQs */
2509 [WDOG_SNARL_IRQ] = {
2510 .name = "wdog-snarl",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002511 },
2512 [WDOG_BARK_IRQ] = {
2513 .name = "wdog-bark",
2514 .handler = wdog_bark_irq_handler,
Ashay Jaiswala55b7ed2018-03-23 17:23:48 +05302515 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002516 },
2517 [AICL_FAIL_IRQ] = {
2518 .name = "aicl-fail",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002519 },
2520 [AICL_DONE_IRQ] = {
2521 .name = "aicl-done",
2522 .handler = default_irq_handler,
2523 },
2524 [SMB_EN_IRQ] = {
2525 .name = "smb-en",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002526 },
2527 [IMP_TRIGGER_IRQ] = {
2528 .name = "imp-trigger",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002529 },
2530 [TEMP_CHANGE_IRQ] = {
2531 .name = "temp-change",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002532 },
2533 [TEMP_CHANGE_SMB_IRQ] = {
2534 .name = "temp-change-smb",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002535 },
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302536 /* FLASH */
2537 [VREG_OK_IRQ] = {
2538 .name = "vreg-ok",
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302539 },
2540 [ILIM_S2_IRQ] = {
2541 .name = "ilim2-s2",
2542 .handler = schgm_flash_ilim2_irq_handler,
2543 },
2544 [ILIM_S1_IRQ] = {
2545 .name = "ilim1-s1",
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302546 },
2547 [VOUT_DOWN_IRQ] = {
2548 .name = "vout-down",
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302549 },
2550 [VOUT_UP_IRQ] = {
2551 .name = "vout-up",
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302552 },
2553 [FLASH_STATE_CHANGE_IRQ] = {
2554 .name = "flash-state-change",
2555 .handler = schgm_flash_state_change_irq_handler,
2556 },
2557 [TORCH_REQ_IRQ] = {
2558 .name = "torch-req",
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302559 },
2560 [FLASH_EN_IRQ] = {
2561 .name = "flash-en",
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302562 },
Harry Yang4b7db0f2017-11-27 10:50:44 -08002563};
2564
2565static int smb5_get_irq_index_byname(const char *irq_name)
2566{
2567 int i;
2568
2569 for (i = 0; i < ARRAY_SIZE(smb5_irqs); i++) {
2570 if (strcmp(smb5_irqs[i].name, irq_name) == 0)
2571 return i;
2572 }
2573
2574 return -ENOENT;
2575}
2576
2577static int smb5_request_interrupt(struct smb5 *chip,
2578 struct device_node *node, const char *irq_name)
2579{
2580 struct smb_charger *chg = &chip->chg;
2581 int rc, irq, irq_index;
2582 struct smb_irq_data *irq_data;
2583
2584 irq = of_irq_get_byname(node, irq_name);
2585 if (irq < 0) {
2586 pr_err("Couldn't get irq %s byname\n", irq_name);
2587 return irq;
2588 }
2589
2590 irq_index = smb5_get_irq_index_byname(irq_name);
2591 if (irq_index < 0) {
2592 pr_err("%s is not a defined irq\n", irq_name);
2593 return irq_index;
2594 }
2595
2596 if (!smb5_irqs[irq_index].handler)
2597 return 0;
2598
2599 irq_data = devm_kzalloc(chg->dev, sizeof(*irq_data), GFP_KERNEL);
2600 if (!irq_data)
2601 return -ENOMEM;
2602
2603 irq_data->parent_data = chip;
2604 irq_data->name = irq_name;
2605 irq_data->storm_data = smb5_irqs[irq_index].storm_data;
2606 mutex_init(&irq_data->storm_data.storm_lock);
2607
2608 rc = devm_request_threaded_irq(chg->dev, irq, NULL,
2609 smb5_irqs[irq_index].handler,
2610 IRQF_ONESHOT, irq_name, irq_data);
2611 if (rc < 0) {
2612 pr_err("Couldn't request irq %d\n", irq);
2613 return rc;
2614 }
2615
2616 smb5_irqs[irq_index].irq = irq;
2617 smb5_irqs[irq_index].irq_data = irq_data;
2618 if (smb5_irqs[irq_index].wake)
2619 enable_irq_wake(irq);
2620
2621 return rc;
2622}
2623
2624static int smb5_request_interrupts(struct smb5 *chip)
2625{
2626 struct smb_charger *chg = &chip->chg;
2627 struct device_node *node = chg->dev->of_node;
2628 struct device_node *child;
2629 int rc = 0;
2630 const char *name;
2631 struct property *prop;
2632
2633 for_each_available_child_of_node(node, child) {
2634 of_property_for_each_string(child, "interrupt-names",
2635 prop, name) {
2636 rc = smb5_request_interrupt(chip, child, name);
2637 if (rc < 0)
2638 return rc;
2639 }
2640 }
2641 if (chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq)
2642 chg->usb_icl_change_irq_enabled = true;
2643
2644 return rc;
2645}
2646
2647static void smb5_free_interrupts(struct smb_charger *chg)
2648{
2649 int i;
2650
2651 for (i = 0; i < ARRAY_SIZE(smb5_irqs); i++) {
2652 if (smb5_irqs[i].irq > 0) {
2653 if (smb5_irqs[i].wake)
2654 disable_irq_wake(smb5_irqs[i].irq);
2655
2656 devm_free_irq(chg->dev, smb5_irqs[i].irq,
2657 smb5_irqs[i].irq_data);
2658 }
2659 }
2660}
2661
2662static void smb5_disable_interrupts(struct smb_charger *chg)
2663{
2664 int i;
2665
2666 for (i = 0; i < ARRAY_SIZE(smb5_irqs); i++) {
2667 if (smb5_irqs[i].irq > 0)
2668 disable_irq(smb5_irqs[i].irq);
2669 }
2670}
2671
2672#if defined(CONFIG_DEBUG_FS)
2673
2674static int force_batt_psy_update_write(void *data, u64 val)
2675{
2676 struct smb_charger *chg = data;
2677
2678 power_supply_changed(chg->batt_psy);
2679 return 0;
2680}
2681DEFINE_SIMPLE_ATTRIBUTE(force_batt_psy_update_ops, NULL,
2682 force_batt_psy_update_write, "0x%02llx\n");
2683
2684static int force_usb_psy_update_write(void *data, u64 val)
2685{
2686 struct smb_charger *chg = data;
2687
2688 power_supply_changed(chg->usb_psy);
2689 return 0;
2690}
2691DEFINE_SIMPLE_ATTRIBUTE(force_usb_psy_update_ops, NULL,
2692 force_usb_psy_update_write, "0x%02llx\n");
2693
2694static int force_dc_psy_update_write(void *data, u64 val)
2695{
2696 struct smb_charger *chg = data;
2697
2698 power_supply_changed(chg->dc_psy);
2699 return 0;
2700}
2701DEFINE_SIMPLE_ATTRIBUTE(force_dc_psy_update_ops, NULL,
2702 force_dc_psy_update_write, "0x%02llx\n");
2703
2704static void smb5_create_debugfs(struct smb5 *chip)
2705{
2706 struct dentry *file;
2707
2708 chip->dfs_root = debugfs_create_dir("charger", NULL);
2709 if (IS_ERR_OR_NULL(chip->dfs_root)) {
2710 pr_err("Couldn't create charger debugfs rc=%ld\n",
2711 (long)chip->dfs_root);
2712 return;
2713 }
2714
2715 file = debugfs_create_file("force_batt_psy_update", 0600,
2716 chip->dfs_root, chip, &force_batt_psy_update_ops);
2717 if (IS_ERR_OR_NULL(file))
2718 pr_err("Couldn't create force_batt_psy_update file rc=%ld\n",
2719 (long)file);
2720
2721 file = debugfs_create_file("force_usb_psy_update", 0600,
2722 chip->dfs_root, chip, &force_usb_psy_update_ops);
2723 if (IS_ERR_OR_NULL(file))
2724 pr_err("Couldn't create force_usb_psy_update file rc=%ld\n",
2725 (long)file);
2726
2727 file = debugfs_create_file("force_dc_psy_update", 0600,
2728 chip->dfs_root, chip, &force_dc_psy_update_ops);
2729 if (IS_ERR_OR_NULL(file))
2730 pr_err("Couldn't create force_dc_psy_update file rc=%ld\n",
2731 (long)file);
2732}
2733
2734#else
2735
2736static void smb5_create_debugfs(struct smb5 *chip)
2737{}
2738
2739#endif
2740
2741static int smb5_show_charger_status(struct smb5 *chip)
2742{
2743 struct smb_charger *chg = &chip->chg;
2744 union power_supply_propval val;
2745 int usb_present, batt_present, batt_health, batt_charge_type;
2746 int rc;
2747
2748 rc = smblib_get_prop_usb_present(chg, &val);
2749 if (rc < 0) {
2750 pr_err("Couldn't get usb present rc=%d\n", rc);
2751 return rc;
2752 }
2753 usb_present = val.intval;
2754
2755 rc = smblib_get_prop_batt_present(chg, &val);
2756 if (rc < 0) {
2757 pr_err("Couldn't get batt present rc=%d\n", rc);
2758 return rc;
2759 }
2760 batt_present = val.intval;
2761
2762 rc = smblib_get_prop_batt_health(chg, &val);
2763 if (rc < 0) {
2764 pr_err("Couldn't get batt health rc=%d\n", rc);
2765 val.intval = POWER_SUPPLY_HEALTH_UNKNOWN;
2766 }
2767 batt_health = val.intval;
2768
2769 rc = smblib_get_prop_batt_charge_type(chg, &val);
2770 if (rc < 0) {
2771 pr_err("Couldn't get batt charge type rc=%d\n", rc);
2772 return rc;
2773 }
2774 batt_charge_type = val.intval;
2775
2776 pr_info("SMB5 status - usb:present=%d type=%d batt:present = %d health = %d charge = %d\n",
2777 usb_present, chg->real_charger_type,
2778 batt_present, batt_health, batt_charge_type);
2779 return rc;
2780}
2781
2782static int smb5_probe(struct platform_device *pdev)
2783{
2784 struct smb5 *chip;
2785 struct smb_charger *chg;
2786 int rc = 0;
2787
2788 chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
2789 if (!chip)
2790 return -ENOMEM;
2791
2792 chg = &chip->chg;
2793 chg->dev = &pdev->dev;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002794 chg->debug_mask = &__debug_mask;
Harry Yang6afaea22018-03-26 19:11:07 -07002795 chg->pd_disabled = &__pd_disabled;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002796 chg->weak_chg_icl_ua = &__weak_chg_icl_ua;
2797 chg->mode = PARALLEL_MASTER;
2798 chg->irq_info = smb5_irqs;
2799 chg->die_health = -EINVAL;
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302800 chg->otg_present = false;
Anirudh Ghayal75f8f812018-07-09 16:48:47 +05302801 mutex_init(&chg->vadc_lock);
Harry Yang4b7db0f2017-11-27 10:50:44 -08002802
2803 chg->regmap = dev_get_regmap(chg->dev->parent, NULL);
2804 if (!chg->regmap) {
2805 pr_err("parent regmap is missing\n");
2806 return -EINVAL;
2807 }
2808
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302809 rc = smb5_chg_config_init(chip);
2810 if (rc < 0) {
2811 if (rc != -EPROBE_DEFER)
2812 pr_err("Couldn't setup chg_config rc=%d\n", rc);
2813 return rc;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002814 }
2815
Ashay Jaiswalb2b06fe2018-06-07 18:35:21 +05302816 rc = smb5_parse_dt(chip);
2817 if (rc < 0) {
2818 pr_err("Couldn't parse device tree rc=%d\n", rc);
2819 return rc;
2820 }
2821
Harry Yang4b7db0f2017-11-27 10:50:44 -08002822 rc = smblib_init(chg);
2823 if (rc < 0) {
2824 pr_err("Smblib_init failed rc=%d\n", rc);
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302825 return rc;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002826 }
2827
2828 /* set driver data before resources request it */
2829 platform_set_drvdata(pdev, chip);
2830
2831 rc = smb5_init_vbus_regulator(chip);
2832 if (rc < 0) {
2833 pr_err("Couldn't initialize vbus regulator rc=%d\n",
2834 rc);
2835 goto cleanup;
2836 }
2837
2838 rc = smb5_init_vconn_regulator(chip);
2839 if (rc < 0) {
2840 pr_err("Couldn't initialize vconn regulator rc=%d\n",
2841 rc);
2842 goto cleanup;
2843 }
2844
2845 /* extcon registration */
2846 chg->extcon = devm_extcon_dev_allocate(chg->dev, smblib_extcon_cable);
2847 if (IS_ERR(chg->extcon)) {
2848 rc = PTR_ERR(chg->extcon);
2849 dev_err(chg->dev, "failed to allocate extcon device rc=%d\n",
2850 rc);
2851 goto cleanup;
2852 }
2853
2854 rc = devm_extcon_dev_register(chg->dev, chg->extcon);
2855 if (rc < 0) {
2856 dev_err(chg->dev, "failed to register extcon device rc=%d\n",
2857 rc);
2858 goto cleanup;
2859 }
2860
2861 rc = smb5_init_hw(chip);
2862 if (rc < 0) {
2863 pr_err("Couldn't initialize hardware rc=%d\n", rc);
2864 goto cleanup;
2865 }
2866
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302867 if (chg->smb_version == PM855B_SUBTYPE) {
2868 rc = smb5_init_dc_psy(chip);
2869 if (rc < 0) {
2870 pr_err("Couldn't initialize dc psy rc=%d\n", rc);
2871 goto cleanup;
2872 }
Harry Yang4b7db0f2017-11-27 10:50:44 -08002873 }
2874
2875 rc = smb5_init_usb_psy(chip);
2876 if (rc < 0) {
2877 pr_err("Couldn't initialize usb psy rc=%d\n", rc);
2878 goto cleanup;
2879 }
2880
2881 rc = smb5_init_usb_main_psy(chip);
2882 if (rc < 0) {
2883 pr_err("Couldn't initialize usb main psy rc=%d\n", rc);
2884 goto cleanup;
2885 }
2886
2887 rc = smb5_init_usb_port_psy(chip);
2888 if (rc < 0) {
2889 pr_err("Couldn't initialize usb pc_port psy rc=%d\n", rc);
2890 goto cleanup;
2891 }
2892
2893 rc = smb5_init_batt_psy(chip);
2894 if (rc < 0) {
2895 pr_err("Couldn't initialize batt psy rc=%d\n", rc);
2896 goto cleanup;
2897 }
2898
2899 rc = smb5_determine_initial_status(chip);
2900 if (rc < 0) {
2901 pr_err("Couldn't determine initial status rc=%d\n",
2902 rc);
2903 goto cleanup;
2904 }
2905
2906 rc = smb5_request_interrupts(chip);
2907 if (rc < 0) {
2908 pr_err("Couldn't request interrupts rc=%d\n", rc);
2909 goto cleanup;
2910 }
2911
2912 rc = smb5_post_init(chip);
2913 if (rc < 0) {
2914 pr_err("Failed in post init rc=%d\n", rc);
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302915 goto free_irq;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002916 }
2917
2918 smb5_create_debugfs(chip);
2919
2920 rc = smb5_show_charger_status(chip);
2921 if (rc < 0) {
2922 pr_err("Failed in getting charger status rc=%d\n", rc);
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302923 goto free_irq;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002924 }
2925
2926 device_init_wakeup(chg->dev, true);
2927
2928 pr_info("QPNP SMB5 probed successfully\n");
2929
2930 return rc;
2931
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302932free_irq:
Harry Yang4b7db0f2017-11-27 10:50:44 -08002933 smb5_free_interrupts(chg);
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302934cleanup:
Harry Yang4b7db0f2017-11-27 10:50:44 -08002935 smblib_deinit(chg);
2936 platform_set_drvdata(pdev, NULL);
2937
2938 return rc;
2939}
2940
2941static int smb5_remove(struct platform_device *pdev)
2942{
2943 struct smb5 *chip = platform_get_drvdata(pdev);
2944 struct smb_charger *chg = &chip->chg;
2945
Harry Yang6afaea22018-03-26 19:11:07 -07002946 /* force enable APSD */
2947 smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
2948 BC1P2_SRC_DETECT_BIT, BC1P2_SRC_DETECT_BIT);
2949
Harry Yang4b7db0f2017-11-27 10:50:44 -08002950 smb5_free_interrupts(chg);
2951 smblib_deinit(chg);
2952 platform_set_drvdata(pdev, NULL);
2953 return 0;
2954}
2955
2956static void smb5_shutdown(struct platform_device *pdev)
2957{
2958 struct smb5 *chip = platform_get_drvdata(pdev);
2959 struct smb_charger *chg = &chip->chg;
2960
2961 /* disable all interrupts */
2962 smb5_disable_interrupts(chg);
2963
2964 /* configure power role for UFP */
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302965 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_TYPEC)
Harry Yang4b7db0f2017-11-27 10:50:44 -08002966 smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
2967 TYPEC_POWER_ROLE_CMD_MASK, EN_SNK_ONLY_BIT);
2968
2969 /* force HVDCP to 5V */
2970 smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
2971 HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT, 0);
2972 smblib_write(chg, CMD_HVDCP_2_REG, FORCE_5V_BIT);
2973
2974 /* force enable APSD */
2975 smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
2976 BC1P2_SRC_DETECT_BIT, BC1P2_SRC_DETECT_BIT);
2977}
2978
2979static const struct of_device_id match_table[] = {
2980 { .compatible = "qcom,qpnp-smb5", },
2981 { },
2982};
2983
2984static struct platform_driver smb5_driver = {
2985 .driver = {
2986 .name = "qcom,qpnp-smb5",
2987 .owner = THIS_MODULE,
2988 .of_match_table = match_table,
2989 },
2990 .probe = smb5_probe,
2991 .remove = smb5_remove,
2992 .shutdown = smb5_shutdown,
2993};
2994module_platform_driver(smb5_driver);
2995
2996MODULE_DESCRIPTION("QPNP SMB5 Charger Driver");
2997MODULE_LICENSE("GPL v2");