blob: 71a4369be1eb87ecbd1a13d2225d2ae4b3fe713a [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 Jaiswale0b3c472018-06-20 23:39:41 +0530285 chg->wa_flags |= WEAK_ADAPTER_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
1263static int smb5_batt_get_prop(struct power_supply *psy,
1264 enum power_supply_property psp,
1265 union power_supply_propval *val)
1266{
1267 struct smb_charger *chg = power_supply_get_drvdata(psy);
1268 int rc = 0;
1269
1270 switch (psp) {
1271 case POWER_SUPPLY_PROP_STATUS:
1272 rc = smblib_get_prop_batt_status(chg, val);
1273 break;
1274 case POWER_SUPPLY_PROP_HEALTH:
1275 rc = smblib_get_prop_batt_health(chg, val);
1276 break;
1277 case POWER_SUPPLY_PROP_PRESENT:
1278 rc = smblib_get_prop_batt_present(chg, val);
1279 break;
1280 case POWER_SUPPLY_PROP_INPUT_SUSPEND:
1281 rc = smblib_get_prop_input_suspend(chg, val);
1282 break;
Anirudh Ghayaldfdb8412018-04-21 10:37:18 +05301283 case POWER_SUPPLY_PROP_BATTERY_CHARGING_ENABLED:
1284 val->intval = !get_client_vote(chg->chg_disable_votable,
1285 USER_VOTER);
1286 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001287 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1288 rc = smblib_get_prop_batt_charge_type(chg, val);
1289 break;
1290 case POWER_SUPPLY_PROP_CAPACITY:
1291 rc = smblib_get_prop_batt_capacity(chg, val);
1292 break;
1293 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
1294 rc = smblib_get_prop_system_temp_level(chg, val);
1295 break;
1296 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX:
1297 rc = smblib_get_prop_system_temp_level_max(chg, val);
1298 break;
1299 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
1300 rc = smblib_get_prop_input_current_limited(chg, val);
1301 break;
1302 case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
1303 val->intval = chg->step_chg_enabled;
1304 break;
1305 case POWER_SUPPLY_PROP_SW_JEITA_ENABLED:
1306 val->intval = chg->sw_jeita_enabled;
1307 break;
1308 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Ashay Jaiswal5c5ba272018-07-23 14:54:20 +05301309 rc = smblib_get_prop_from_bms(chg,
1310 POWER_SUPPLY_PROP_VOLTAGE_NOW, val);
Harry Yang4b7db0f2017-11-27 10:50:44 -08001311 break;
1312 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
1313 val->intval = get_client_vote(chg->fv_votable,
1314 BATT_PROFILE_VOTER);
1315 break;
1316 case POWER_SUPPLY_PROP_CURRENT_NOW:
Ashay Jaiswal5c5ba272018-07-23 14:54:20 +05301317 rc = smblib_get_prop_from_bms(chg,
1318 POWER_SUPPLY_PROP_CURRENT_NOW, val);
Harry Yang4b7db0f2017-11-27 10:50:44 -08001319 break;
1320 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
1321 val->intval = get_client_vote(chg->fcc_votable,
1322 BATT_PROFILE_VOTER);
1323 break;
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001324 case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
1325 rc = smblib_get_prop_batt_iterm(chg, val);
1326 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001327 case POWER_SUPPLY_PROP_TEMP:
Ashay Jaiswal5c5ba272018-07-23 14:54:20 +05301328 rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_TEMP, val);
Harry Yang4b7db0f2017-11-27 10:50:44 -08001329 break;
1330 case POWER_SUPPLY_PROP_TECHNOLOGY:
1331 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1332 break;
1333 case POWER_SUPPLY_PROP_CHARGE_DONE:
1334 rc = smblib_get_prop_batt_charge_done(chg, val);
1335 break;
1336 case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
1337 val->intval = get_client_vote(chg->pl_disable_votable,
1338 USER_VOTER);
1339 break;
1340 case POWER_SUPPLY_PROP_SET_SHIP_MODE:
1341 /* Not in ship mode as long as device is active */
1342 val->intval = 0;
1343 break;
1344 case POWER_SUPPLY_PROP_DIE_HEALTH:
1345 if (chg->die_health == -EINVAL)
1346 rc = smblib_get_prop_die_health(chg, val);
1347 else
1348 val->intval = chg->die_health;
1349 break;
1350 case POWER_SUPPLY_PROP_DP_DM:
1351 val->intval = chg->pulse_cnt;
1352 break;
1353 case POWER_SUPPLY_PROP_RERUN_AICL:
1354 val->intval = 0;
1355 break;
1356 case POWER_SUPPLY_PROP_CHARGE_COUNTER:
Ashay Jaiswal5c5ba272018-07-23 14:54:20 +05301357 rc = smblib_get_prop_from_bms(chg,
1358 POWER_SUPPLY_PROP_CHARGE_COUNTER, val);
Harry Yang4b7db0f2017-11-27 10:50:44 -08001359 break;
Subbaraman Narayanamurthyc4feb892018-05-07 18:43:45 -07001360 case POWER_SUPPLY_PROP_CYCLE_COUNT:
Ashay Jaiswal5c5ba272018-07-23 14:54:20 +05301361 rc = smblib_get_prop_from_bms(chg,
1362 POWER_SUPPLY_PROP_CYCLE_COUNT, val);
Subbaraman Narayanamurthyc4feb892018-05-07 18:43:45 -07001363 break;
Anirudh Ghayal1380d312018-02-23 00:01:43 +05301364 case POWER_SUPPLY_PROP_RECHARGE_SOC:
1365 val->intval = chg->auto_recharge_soc;
1366 break;
Ashay Jaiswal5c5ba272018-07-23 14:54:20 +05301367 case POWER_SUPPLY_PROP_CHARGE_FULL:
1368 rc = smblib_get_prop_from_bms(chg,
1369 POWER_SUPPLY_PROP_CHARGE_FULL, val);
1370 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001371 default:
1372 pr_err("batt power supply prop %d not supported\n", psp);
1373 return -EINVAL;
1374 }
1375
1376 if (rc < 0) {
1377 pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
1378 return -ENODATA;
1379 }
1380
1381 return 0;
1382}
1383
1384static int smb5_batt_set_prop(struct power_supply *psy,
1385 enum power_supply_property prop,
1386 const union power_supply_propval *val)
1387{
1388 int rc = 0;
1389 struct smb_charger *chg = power_supply_get_drvdata(psy);
Ashay Jaiswala55b7ed2018-03-23 17:23:48 +05301390 bool enable;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001391
1392 switch (prop) {
1393 case POWER_SUPPLY_PROP_STATUS:
1394 rc = smblib_set_prop_batt_status(chg, val);
1395 break;
1396 case POWER_SUPPLY_PROP_INPUT_SUSPEND:
1397 rc = smblib_set_prop_input_suspend(chg, val);
1398 break;
Anirudh Ghayaldfdb8412018-04-21 10:37:18 +05301399 case POWER_SUPPLY_PROP_BATTERY_CHARGING_ENABLED:
1400 vote(chg->chg_disable_votable, USER_VOTER, !val->intval, 0);
1401 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001402 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
1403 rc = smblib_set_prop_system_temp_level(chg, val);
1404 break;
1405 case POWER_SUPPLY_PROP_CAPACITY:
1406 rc = smblib_set_prop_batt_capacity(chg, val);
1407 break;
1408 case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
1409 vote(chg->pl_disable_votable, USER_VOTER, (bool)val->intval, 0);
1410 break;
1411 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
1412 chg->batt_profile_fv_uv = val->intval;
1413 vote(chg->fv_votable, BATT_PROFILE_VOTER, true, val->intval);
1414 break;
1415 case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
Ashay Jaiswala55b7ed2018-03-23 17:23:48 +05301416 enable = !!val->intval || chg->sw_jeita_enabled;
1417 rc = smblib_configure_wdog(chg, enable);
1418 if (rc == 0)
1419 chg->step_chg_enabled = !!val->intval;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001420 break;
1421 case POWER_SUPPLY_PROP_SW_JEITA_ENABLED:
1422 if (chg->sw_jeita_enabled != (!!val->intval)) {
1423 rc = smblib_disable_hw_jeita(chg, !!val->intval);
Ashay Jaiswala55b7ed2018-03-23 17:23:48 +05301424 enable = !!val->intval || chg->step_chg_enabled;
1425 rc |= smblib_configure_wdog(chg, enable);
Harry Yang4b7db0f2017-11-27 10:50:44 -08001426 if (rc == 0)
1427 chg->sw_jeita_enabled = !!val->intval;
1428 }
1429 break;
1430 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
1431 chg->batt_profile_fcc_ua = val->intval;
1432 vote(chg->fcc_votable, BATT_PROFILE_VOTER, true, val->intval);
1433 break;
1434 case POWER_SUPPLY_PROP_SET_SHIP_MODE:
1435 /* Not in ship mode as long as the device is active */
1436 if (!val->intval)
1437 break;
1438 if (chg->pl.psy)
1439 power_supply_set_property(chg->pl.psy,
1440 POWER_SUPPLY_PROP_SET_SHIP_MODE, val);
1441 rc = smblib_set_prop_ship_mode(chg, val);
1442 break;
1443 case POWER_SUPPLY_PROP_RERUN_AICL:
Ashay Jaiswale0b3c472018-06-20 23:39:41 +05301444 rc = smblib_run_aicl(chg, RERUN_AICL);
Harry Yang4b7db0f2017-11-27 10:50:44 -08001445 break;
1446 case POWER_SUPPLY_PROP_DP_DM:
Ashay Jaiswal4d334f42018-04-25 10:58:49 +05301447 if (!chg->flash_active)
1448 rc = smblib_dp_dm(chg, val->intval);
Harry Yang4b7db0f2017-11-27 10:50:44 -08001449 break;
1450 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
1451 rc = smblib_set_prop_input_current_limited(chg, val);
1452 break;
1453 case POWER_SUPPLY_PROP_DIE_HEALTH:
1454 chg->die_health = val->intval;
1455 power_supply_changed(chg->batt_psy);
1456 break;
Anirudh Ghayaldfdb8412018-04-21 10:37:18 +05301457 case POWER_SUPPLY_PROP_RECHARGE_SOC:
1458 if (chg->smb_version == PMI632_SUBTYPE) {
1459 /* toggle charging to force recharge */
1460 vote(chg->chg_disable_votable, FORCE_RECHARGE_VOTER,
1461 true, 0);
1462 /* charge disable delay */
1463 msleep(50);
1464 vote(chg->chg_disable_votable, FORCE_RECHARGE_VOTER,
1465 false, 0);
1466 }
1467 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001468 default:
1469 rc = -EINVAL;
1470 }
1471
1472 return rc;
1473}
1474
1475static int smb5_batt_prop_is_writeable(struct power_supply *psy,
1476 enum power_supply_property psp)
1477{
1478 switch (psp) {
1479 case POWER_SUPPLY_PROP_STATUS:
1480 case POWER_SUPPLY_PROP_INPUT_SUSPEND:
1481 case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL:
1482 case POWER_SUPPLY_PROP_CAPACITY:
1483 case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
1484 case POWER_SUPPLY_PROP_DP_DM:
1485 case POWER_SUPPLY_PROP_RERUN_AICL:
1486 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
1487 case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
1488 case POWER_SUPPLY_PROP_SW_JEITA_ENABLED:
1489 case POWER_SUPPLY_PROP_DIE_HEALTH:
Anirudh Ghayaldfdb8412018-04-21 10:37:18 +05301490 case POWER_SUPPLY_PROP_BATTERY_CHARGING_ENABLED:
Harry Yang4b7db0f2017-11-27 10:50:44 -08001491 return 1;
1492 default:
1493 break;
1494 }
1495
1496 return 0;
1497}
1498
1499static const struct power_supply_desc batt_psy_desc = {
1500 .name = "battery",
1501 .type = POWER_SUPPLY_TYPE_BATTERY,
1502 .properties = smb5_batt_props,
1503 .num_properties = ARRAY_SIZE(smb5_batt_props),
1504 .get_property = smb5_batt_get_prop,
1505 .set_property = smb5_batt_set_prop,
1506 .property_is_writeable = smb5_batt_prop_is_writeable,
1507};
1508
1509static int smb5_init_batt_psy(struct smb5 *chip)
1510{
1511 struct power_supply_config batt_cfg = {};
1512 struct smb_charger *chg = &chip->chg;
1513 int rc = 0;
1514
1515 batt_cfg.drv_data = chg;
1516 batt_cfg.of_node = chg->dev->of_node;
1517 chg->batt_psy = devm_power_supply_register(chg->dev,
1518 &batt_psy_desc,
1519 &batt_cfg);
1520 if (IS_ERR(chg->batt_psy)) {
1521 pr_err("Couldn't register battery power supply\n");
1522 return PTR_ERR(chg->batt_psy);
1523 }
1524
1525 return rc;
1526}
1527
1528/******************************
1529 * VBUS REGULATOR REGISTRATION *
1530 ******************************/
1531
1532static struct regulator_ops smb5_vbus_reg_ops = {
1533 .enable = smblib_vbus_regulator_enable,
1534 .disable = smblib_vbus_regulator_disable,
1535 .is_enabled = smblib_vbus_regulator_is_enabled,
1536};
1537
1538static int smb5_init_vbus_regulator(struct smb5 *chip)
1539{
1540 struct smb_charger *chg = &chip->chg;
1541 struct regulator_config cfg = {};
1542 int rc = 0;
1543
1544 chg->vbus_vreg = devm_kzalloc(chg->dev, sizeof(*chg->vbus_vreg),
1545 GFP_KERNEL);
1546 if (!chg->vbus_vreg)
1547 return -ENOMEM;
1548
1549 cfg.dev = chg->dev;
1550 cfg.driver_data = chip;
1551
1552 chg->vbus_vreg->rdesc.owner = THIS_MODULE;
1553 chg->vbus_vreg->rdesc.type = REGULATOR_VOLTAGE;
1554 chg->vbus_vreg->rdesc.ops = &smb5_vbus_reg_ops;
1555 chg->vbus_vreg->rdesc.of_match = "qcom,smb5-vbus";
1556 chg->vbus_vreg->rdesc.name = "qcom,smb5-vbus";
1557
1558 chg->vbus_vreg->rdev = devm_regulator_register(chg->dev,
1559 &chg->vbus_vreg->rdesc, &cfg);
1560 if (IS_ERR(chg->vbus_vreg->rdev)) {
1561 rc = PTR_ERR(chg->vbus_vreg->rdev);
1562 chg->vbus_vreg->rdev = NULL;
1563 if (rc != -EPROBE_DEFER)
1564 pr_err("Couldn't register VBUS regulator rc=%d\n", rc);
1565 }
1566
1567 return rc;
1568}
1569
1570/******************************
1571 * VCONN REGULATOR REGISTRATION *
1572 ******************************/
1573
1574static struct regulator_ops smb5_vconn_reg_ops = {
1575 .enable = smblib_vconn_regulator_enable,
1576 .disable = smblib_vconn_regulator_disable,
1577 .is_enabled = smblib_vconn_regulator_is_enabled,
1578};
1579
1580static int smb5_init_vconn_regulator(struct smb5 *chip)
1581{
1582 struct smb_charger *chg = &chip->chg;
1583 struct regulator_config cfg = {};
1584 int rc = 0;
1585
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301586 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
Harry Yang4b7db0f2017-11-27 10:50:44 -08001587 return 0;
1588
1589 chg->vconn_vreg = devm_kzalloc(chg->dev, sizeof(*chg->vconn_vreg),
1590 GFP_KERNEL);
1591 if (!chg->vconn_vreg)
1592 return -ENOMEM;
1593
1594 cfg.dev = chg->dev;
1595 cfg.driver_data = chip;
1596
1597 chg->vconn_vreg->rdesc.owner = THIS_MODULE;
1598 chg->vconn_vreg->rdesc.type = REGULATOR_VOLTAGE;
1599 chg->vconn_vreg->rdesc.ops = &smb5_vconn_reg_ops;
1600 chg->vconn_vreg->rdesc.of_match = "qcom,smb5-vconn";
1601 chg->vconn_vreg->rdesc.name = "qcom,smb5-vconn";
1602
1603 chg->vconn_vreg->rdev = devm_regulator_register(chg->dev,
1604 &chg->vconn_vreg->rdesc, &cfg);
1605 if (IS_ERR(chg->vconn_vreg->rdev)) {
1606 rc = PTR_ERR(chg->vconn_vreg->rdev);
1607 chg->vconn_vreg->rdev = NULL;
1608 if (rc != -EPROBE_DEFER)
1609 pr_err("Couldn't register VCONN regulator rc=%d\n", rc);
1610 }
1611
1612 return rc;
1613}
1614
1615/***************************
1616 * HARDWARE INITIALIZATION *
1617 ***************************/
1618static int smb5_configure_typec(struct smb_charger *chg)
1619{
1620 int rc;
Ashay Jaiswal91d63f42018-05-16 11:30:40 +05301621 u8 val = 0;
1622
1623 rc = smblib_read(chg, LEGACY_CABLE_STATUS_REG, &val);
1624 if (rc < 0) {
1625 dev_err(chg->dev, "Couldn't read Legacy status rc=%d\n", rc);
1626 return rc;
1627 }
1628 /*
1629 * If Legacy cable is detected re-trigger Legacy detection
1630 * by disabling/enabling typeC mode.
1631 */
1632 if (val & TYPEC_LEGACY_CABLE_STATUS_BIT) {
1633 rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
1634 TYPEC_DISABLE_CMD_BIT, TYPEC_DISABLE_CMD_BIT);
1635 if (rc < 0) {
1636 dev_err(chg->dev, "Couldn't disable TYPEC rc=%d\n", rc);
1637 return rc;
1638 }
1639
1640 /* delay before enabling typeC */
1641 msleep(500);
1642
1643 rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
1644 TYPEC_DISABLE_CMD_BIT, 0);
1645 if (rc < 0) {
1646 dev_err(chg->dev, "Couldn't enable TYPEC rc=%d\n", rc);
1647 return rc;
1648 }
1649 }
Harry Yang4b7db0f2017-11-27 10:50:44 -08001650
Harry Yang6afaea22018-03-26 19:11:07 -07001651 /* disable apsd */
Ashay Jaiswalc96380de2018-05-16 12:02:36 +05301652 rc = smblib_configure_hvdcp_apsd(chg, false);
Harry Yang6afaea22018-03-26 19:11:07 -07001653 if (rc < 0) {
1654 dev_err(chg->dev, "Couldn't disable APSD rc=%d\n", rc);
1655 return rc;
1656 }
1657
Harry Yang4b7db0f2017-11-27 10:50:44 -08001658 rc = smblib_write(chg, TYPE_C_INTERRUPT_EN_CFG_1_REG,
1659 TYPEC_CCOUT_DETACH_INT_EN_BIT |
1660 TYPEC_CCOUT_ATTACH_INT_EN_BIT);
1661 if (rc < 0) {
1662 dev_err(chg->dev,
1663 "Couldn't configure Type-C interrupts rc=%d\n", rc);
1664 return rc;
1665 }
1666
Harry Yang423d5c32018-05-30 15:49:04 -07001667 rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
1668 EN_TRY_SNK_BIT, EN_TRY_SNK_BIT);
1669 if (rc < 0) {
1670 dev_err(chg->dev,
1671 "Couldn't enable try.snk rc=%d\n", rc);
1672 return rc;
1673 }
1674
Ashay Jaiswald5022b62018-05-27 19:21:11 +05301675 /* Keep VCONN in h/w controlled mode for PMI632 */
1676 if (chg->smb_version != PMI632_SUBTYPE) {
1677 /* configure VCONN for software control */
1678 rc = smblib_masked_write(chg, TYPE_C_VCONN_CONTROL_REG,
Harry Yang4b7db0f2017-11-27 10:50:44 -08001679 VCONN_EN_SRC_BIT | VCONN_EN_VALUE_BIT,
1680 VCONN_EN_SRC_BIT);
Ashay Jaiswald5022b62018-05-27 19:21:11 +05301681 if (rc < 0) {
1682 dev_err(chg->dev,
1683 "Couldn't configure VCONN for SW control rc=%d\n",
1684 rc);
1685 return rc;
1686 }
Harry Yang4b7db0f2017-11-27 10:50:44 -08001687 }
1688
1689 return rc;
1690}
1691
1692static int smb5_configure_micro_usb(struct smb_charger *chg)
1693{
1694 int rc;
1695
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301696 rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG,
1697 MICRO_USB_STATE_CHANGE_INT_EN_BIT,
1698 MICRO_USB_STATE_CHANGE_INT_EN_BIT);
1699 if (rc < 0) {
1700 dev_err(chg->dev,
1701 "Couldn't configure Type-C interrupts rc=%d\n", rc);
1702 return rc;
1703 }
1704
Umang Agrawal461e9ea2018-07-05 18:50:13 +05301705 if (chg->moisture_protection_enabled &&
1706 (chg->wa_flags & MOISTURE_PROTECTION_WA)) {
1707 /* Enable moisture detection interrupt */
1708 rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG,
1709 TYPEC_WATER_DETECTION_INT_EN_BIT,
1710 TYPEC_WATER_DETECTION_INT_EN_BIT);
1711 if (rc < 0) {
1712 dev_err(chg->dev, "Couldn't enable moisture detection interrupt rc=%d\n",
1713 rc);
1714 return rc;
1715 }
1716
1717 /* Enable uUSB factory mode */
1718 rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG,
1719 EN_MICRO_USB_FACTORY_MODE_BIT,
1720 EN_MICRO_USB_FACTORY_MODE_BIT);
1721 if (rc < 0) {
1722 dev_err(chg->dev, "Couldn't enable uUSB factory mode c=%d\n",
1723 rc);
1724 return rc;
1725 }
1726
1727 /* Disable periodic monitoring of CC_ID pin */
1728 rc = smblib_write(chg, TYPEC_U_USB_WATER_PROTECTION_CFG_REG, 0);
1729 if (rc < 0) {
1730 dev_err(chg->dev, "Couldn't disable periodic monitoring of CC_ID rc=%d\n",
1731 rc);
1732 return rc;
1733 }
1734 }
1735
Harry Yang4b7db0f2017-11-27 10:50:44 -08001736 return rc;
1737}
1738
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +05301739static int smb5_configure_mitigation(struct smb_charger *chg)
1740{
1741 int rc;
1742 u8 chan = 0;
1743
1744 if (!chg->hw_die_temp_mitigation && !chg->hw_connector_mitigation)
1745 return 0;
1746
1747 if (chg->hw_die_temp_mitigation) {
1748 rc = smblib_write(chg, MISC_THERMREG_SRC_CFG_REG,
1749 THERMREG_CONNECTOR_ADC_SRC_EN_BIT
1750 | THERMREG_DIE_ADC_SRC_EN_BIT
1751 | THERMREG_DIE_CMP_SRC_EN_BIT);
1752 if (rc < 0) {
1753 dev_err(chg->dev,
1754 "Couldn't configure THERM_SRC reg rc=%d\n", rc);
1755 return rc;
1756 };
1757
1758 chan = DIE_TEMP_CHANNEL_EN_BIT;
1759 }
1760
1761 if (chg->hw_connector_mitigation)
1762 chan |= CONN_THM_CHANNEL_EN_BIT;
1763
1764 rc = smblib_masked_write(chg, BATIF_ADC_CHANNEL_EN_REG,
1765 CONN_THM_CHANNEL_EN_BIT | DIE_TEMP_CHANNEL_EN_BIT,
1766 chan);
1767 if (rc < 0) {
Ashay Jaiswalb50706d2018-06-28 19:37:31 +05301768 dev_err(chg->dev, "Couldn't enable ADC channel rc=%d\n", rc);
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +05301769 return rc;
1770 }
1771
1772 return 0;
1773}
1774
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001775static int smb5_configure_iterm_thresholds_adc(struct smb5 *chip)
1776{
Guru Das Srinagesh31b2bb02018-06-20 15:44:03 -07001777 u8 *buf;
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001778 int rc = 0;
Guru Das Srinagesh31b2bb02018-06-20 15:44:03 -07001779 s16 raw_hi_thresh, raw_lo_thresh;
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001780 struct smb_charger *chg = &chip->chg;
1781
1782 if (chip->dt.term_current_thresh_hi_ma < -10000 ||
1783 chip->dt.term_current_thresh_hi_ma > 10000 ||
1784 chip->dt.term_current_thresh_lo_ma < -10000 ||
1785 chip->dt.term_current_thresh_lo_ma > 10000) {
1786 dev_err(chg->dev, "ITERM threshold out of range rc=%d\n", rc);
1787 return -EINVAL;
1788 }
1789
1790 /*
1791 * Conversion:
Guru Das Srinagesh31b2bb02018-06-20 15:44:03 -07001792 * raw (A) = (scaled_mA * ADC_CHG_TERM_MASK) / (10 * 1000)
1793 * Note: raw needs to be converted to big-endian format.
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001794 */
1795
1796 if (chip->dt.term_current_thresh_hi_ma) {
1797 raw_hi_thresh = ((chip->dt.term_current_thresh_hi_ma *
1798 ADC_CHG_TERM_MASK) / 10000);
1799 raw_hi_thresh = sign_extend32(raw_hi_thresh, 15);
Guru Das Srinagesh31b2bb02018-06-20 15:44:03 -07001800 buf = (u8 *)&raw_hi_thresh;
1801 raw_hi_thresh = buf[1] | (buf[0] << 8);
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001802
1803 rc = smblib_batch_write(chg, CHGR_ADC_ITERM_UP_THD_MSB_REG,
1804 (u8 *)&raw_hi_thresh, 2);
1805 if (rc < 0) {
1806 dev_err(chg->dev, "Couldn't configure ITERM threshold HIGH rc=%d\n",
1807 rc);
1808 return rc;
1809 }
1810 }
1811
1812 if (chip->dt.term_current_thresh_lo_ma) {
1813 raw_lo_thresh = ((chip->dt.term_current_thresh_lo_ma *
1814 ADC_CHG_TERM_MASK) / 10000);
1815 raw_lo_thresh = sign_extend32(raw_lo_thresh, 15);
Guru Das Srinagesh31b2bb02018-06-20 15:44:03 -07001816 buf = (u8 *)&raw_lo_thresh;
1817 raw_lo_thresh = buf[1] | (buf[0] << 8);
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07001818
1819 rc = smblib_batch_write(chg, CHGR_ADC_ITERM_LO_THD_MSB_REG,
1820 (u8 *)&raw_lo_thresh, 2);
1821 if (rc < 0) {
1822 dev_err(chg->dev, "Couldn't configure ITERM threshold LOW rc=%d\n",
1823 rc);
1824 return rc;
1825 }
1826 }
1827
1828 return rc;
1829}
1830
1831static int smb5_configure_iterm_thresholds(struct smb5 *chip)
1832{
1833 int rc = 0;
1834
1835 switch (chip->dt.term_current_src) {
1836 case ITERM_SRC_ADC:
1837 rc = smb5_configure_iterm_thresholds_adc(chip);
1838 break;
1839 default:
1840 break;
1841 }
1842
1843 return rc;
1844}
1845
Harry Yang4b7db0f2017-11-27 10:50:44 -08001846static int smb5_init_hw(struct smb5 *chip)
1847{
1848 struct smb_charger *chg = &chip->chg;
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301849 int rc, type = 0;
1850 u8 val = 0;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001851
1852 if (chip->dt.no_battery)
1853 chg->fake_capacity = 50;
1854
1855 if (chip->dt.batt_profile_fcc_ua < 0)
1856 smblib_get_charge_param(chg, &chg->param.fcc,
1857 &chg->batt_profile_fcc_ua);
1858
1859 if (chip->dt.batt_profile_fv_uv < 0)
1860 smblib_get_charge_param(chg, &chg->param.fv,
1861 &chg->batt_profile_fv_uv);
1862
1863 smblib_get_charge_param(chg, &chg->param.usb_icl,
1864 &chg->default_icl_ua);
Ashay Jaiswale0b3c472018-06-20 23:39:41 +05301865 smblib_get_charge_param(chg, &chg->param.aicl_5v_threshold,
1866 &chg->default_aicl_5v_threshold_mv);
1867 chg->aicl_5v_threshold_mv = chg->default_aicl_5v_threshold_mv;
1868 smblib_get_charge_param(chg, &chg->param.aicl_cont_threshold,
1869 &chg->default_aicl_cont_threshold_mv);
1870 chg->aicl_cont_threshold_mv = chg->default_aicl_cont_threshold_mv;
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301871
1872 /* Use SW based VBUS control, disable HW autonomous mode */
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301873 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1874 HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT,
1875 HVDCP_AUTH_ALG_EN_CFG_BIT);
1876 if (rc < 0) {
1877 dev_err(chg->dev, "Couldn't configure HVDCP rc=%d\n", rc);
1878 return rc;
1879 }
1880
1881 /*
1882 * PMI632 can have the connector type defined by a dedicated register
1883 * TYPEC_MICRO_USB_MODE_REG or by a common TYPEC_U_USB_CFG_REG.
1884 */
1885 if (chg->smb_version == PMI632_SUBTYPE) {
1886 rc = smblib_read(chg, TYPEC_MICRO_USB_MODE_REG, &val);
1887 if (rc < 0) {
1888 dev_err(chg->dev, "Couldn't read USB mode rc=%d\n", rc);
1889 return rc;
1890 }
1891 type = !!(val & MICRO_USB_MODE_ONLY_BIT);
1892 }
1893
1894 /*
1895 * If TYPEC_MICRO_USB_MODE_REG is not set and for all non-PMI632
1896 * check the connector type using TYPEC_U_USB_CFG_REG.
1897 */
1898 if (!type) {
1899 rc = smblib_read(chg, TYPEC_U_USB_CFG_REG, &val);
1900 if (rc < 0) {
1901 dev_err(chg->dev, "Couldn't read U_USB config rc=%d\n",
1902 rc);
1903 return rc;
1904 }
1905
1906 type = !!(val & EN_MICRO_USB_MODE_BIT);
1907 }
1908
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301909 pr_debug("Connector type=%s\n", type ? "Micro USB" : "TypeC");
1910
Harry Yang6afaea22018-03-26 19:11:07 -07001911 if (type) {
1912 chg->connector_type = POWER_SUPPLY_CONNECTOR_MICRO_USB;
Harry Yang6afaea22018-03-26 19:11:07 -07001913 rc = smb5_configure_micro_usb(chg);
1914 } else {
1915 chg->connector_type = POWER_SUPPLY_CONNECTOR_TYPEC;
1916 rc = smb5_configure_typec(chg);
1917 }
1918 if (rc < 0) {
1919 dev_err(chg->dev,
1920 "Couldn't configure TypeC/micro-USB mode rc=%d\n", rc);
1921 return rc;
1922 }
1923
Ashay Jaiswal09feab82018-02-12 12:33:18 +05301924 /*
1925 * PMI632 based hw init:
Ashay Jaiswal6f70a512018-05-11 17:25:58 +05301926 * - Enable STAT pin function on SMB_EN
Ashay Jaiswalc96380de2018-05-16 12:02:36 +05301927 * - Rerun APSD to ensure proper charger detection if device
1928 * boots with charger connected.
Ashay Jaiswal09feab82018-02-12 12:33:18 +05301929 * - Initialize flash module for PMI632
1930 */
Ashay Jaiswalc96380de2018-05-16 12:02:36 +05301931 if (chg->smb_version == PMI632_SUBTYPE) {
Ashay Jaiswal6f70a512018-05-11 17:25:58 +05301932 rc = smblib_masked_write(chg, MISC_SMB_EN_CMD_REG,
1933 EN_STAT_CMD_BIT, EN_STAT_CMD_BIT);
1934 if (rc < 0) {
1935 dev_err(chg->dev, "Couldn't configure SMB_EN rc=%d\n",
1936 rc);
1937 return rc;
1938 }
1939
Ashay Jaiswal09feab82018-02-12 12:33:18 +05301940 schgm_flash_init(chg);
Ashay Jaiswalc96380de2018-05-16 12:02:36 +05301941 smblib_rerun_apsd_if_required(chg);
1942 }
Ashay Jaiswal09feab82018-02-12 12:33:18 +05301943
Ashay Jaiswalcbdf2e82018-05-27 23:59:01 +05301944 /* clear the ICL override if it is set */
1945 rc = smblib_icl_override(chg, false);
1946 if (rc < 0) {
1947 pr_err("Couldn't disable ICL override rc=%d\n", rc);
1948 return rc;
1949 }
1950
Ashay Jaiswalb2b06fe2018-06-07 18:35:21 +05301951 /* set OTG current limit */
1952 rc = smblib_set_charge_param(chg, &chg->param.otg_cl, chg->otg_cl_ua);
1953 if (rc < 0) {
1954 pr_err("Couldn't set otg current limit rc=%d\n", rc);
1955 return rc;
1956 }
1957
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +05301958 /* configure temperature mitigation */
1959 rc = smb5_configure_mitigation(chg);
1960 if (rc < 0) {
1961 dev_err(chg->dev, "Couldn't configure mitigation rc=%d\n", rc);
1962 return rc;
1963 }
1964
Harry Yang4b7db0f2017-11-27 10:50:44 -08001965 /* vote 0mA on usb_icl for non battery platforms */
1966 vote(chg->usb_icl_votable,
1967 DEFAULT_VOTER, chip->dt.no_battery, 0);
1968 vote(chg->dc_suspend_votable,
1969 DEFAULT_VOTER, chip->dt.no_battery, 0);
1970 vote(chg->fcc_votable, HW_LIMIT_VOTER,
1971 chip->dt.batt_profile_fcc_ua > 0, chip->dt.batt_profile_fcc_ua);
1972 vote(chg->fv_votable, HW_LIMIT_VOTER,
1973 chip->dt.batt_profile_fv_uv > 0, chip->dt.batt_profile_fv_uv);
1974 vote(chg->fcc_votable,
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301975 BATT_PROFILE_VOTER, chg->batt_profile_fcc_ua > 0,
1976 chg->batt_profile_fcc_ua);
Harry Yang4b7db0f2017-11-27 10:50:44 -08001977 vote(chg->fv_votable,
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301978 BATT_PROFILE_VOTER, chg->batt_profile_fv_uv > 0,
1979 chg->batt_profile_fv_uv);
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301980
1981 /* Some h/w limit maximum supported ICL */
1982 vote(chg->usb_icl_votable, HW_LIMIT_VOTER,
1983 chg->hw_max_icl_ua > 0, chg->hw_max_icl_ua);
Harry Yang4b7db0f2017-11-27 10:50:44 -08001984
1985 /*
1986 * AICL configuration:
Ashay Jaiswalc96380de2018-05-16 12:02:36 +05301987 * AICL ADC disable
Harry Yang4b7db0f2017-11-27 10:50:44 -08001988 */
Ashay Jaiswalc96380de2018-05-16 12:02:36 +05301989 if (chg->smb_version != PMI632_SUBTYPE) {
1990 rc = smblib_masked_write(chg, USBIN_AICL_OPTIONS_CFG_REG,
Harry Yang4b7db0f2017-11-27 10:50:44 -08001991 USBIN_AICL_ADC_EN_BIT, 0);
Ashay Jaiswalc96380de2018-05-16 12:02:36 +05301992 if (rc < 0) {
1993 dev_err(chg->dev, "Couldn't config AICL rc=%d\n", rc);
1994 return rc;
1995 }
Harry Yang4b7db0f2017-11-27 10:50:44 -08001996 }
1997
1998 /* enable the charging path */
1999 rc = vote(chg->chg_disable_votable, DEFAULT_VOTER, false, 0);
2000 if (rc < 0) {
2001 dev_err(chg->dev, "Couldn't enable charging rc=%d\n", rc);
2002 return rc;
2003 }
2004
Harry Yang4b7db0f2017-11-27 10:50:44 -08002005 /* configure VBUS for software control */
2006 rc = smblib_masked_write(chg, DCDC_OTG_CFG_REG, OTG_EN_SRC_CFG_BIT, 0);
2007 if (rc < 0) {
2008 dev_err(chg->dev,
2009 "Couldn't configure VBUS for SW control rc=%d\n", rc);
2010 return rc;
2011 }
2012
Ashay Jaiswala55b7ed2018-03-23 17:23:48 +05302013 /*
2014 * configure the one time watchdong periodic interval and
2015 * disable "watchdog bite disable charging".
2016 */
Harry Yang4b7db0f2017-11-27 10:50:44 -08002017 val = (ilog2(chip->dt.wd_bark_time / 16) << BARK_WDOG_TIMEOUT_SHIFT)
2018 & BARK_WDOG_TIMEOUT_MASK;
2019 val |= BITE_WDOG_TIMEOUT_8S;
2020 rc = smblib_masked_write(chg, SNARL_BARK_BITE_WD_CFG_REG,
2021 BITE_WDOG_DISABLE_CHARGING_CFG_BIT |
2022 BARK_WDOG_TIMEOUT_MASK | BITE_WDOG_TIMEOUT_MASK,
2023 val);
2024 if (rc < 0) {
2025 pr_err("Couldn't configue WD config rc=%d\n", rc);
2026 return rc;
2027 }
2028
Guru Das Srinagesh3ca14372018-06-01 11:30:56 -07002029 /* set termination current threshold values */
2030 rc = smb5_configure_iterm_thresholds(chip);
2031 if (rc < 0) {
2032 pr_err("Couldn't configure ITERM thresholds rc=%d\n",
2033 rc);
2034 return rc;
2035 }
2036
Harry Yang4b7db0f2017-11-27 10:50:44 -08002037 /* configure float charger options */
2038 switch (chip->dt.float_option) {
2039 case FLOAT_DCP:
2040 rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
2041 FLOAT_OPTIONS_MASK, 0);
2042 break;
2043 case FLOAT_SDP:
2044 rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
2045 FLOAT_OPTIONS_MASK, FORCE_FLOAT_SDP_CFG_BIT);
2046 break;
2047 case DISABLE_CHARGING:
2048 rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
2049 FLOAT_OPTIONS_MASK, FLOAT_DIS_CHGING_CFG_BIT);
2050 break;
2051 case SUSPEND_INPUT:
2052 rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
2053 FLOAT_OPTIONS_MASK, SUSPEND_FLOAT_CFG_BIT);
2054 break;
2055 default:
2056 rc = 0;
2057 break;
2058 }
2059
2060 if (rc < 0) {
2061 dev_err(chg->dev, "Couldn't configure float charger options rc=%d\n",
2062 rc);
2063 return rc;
2064 }
2065
2066 rc = smblib_read(chg, USBIN_OPTIONS_2_CFG_REG, &chg->float_cfg);
2067 if (rc < 0) {
2068 dev_err(chg->dev, "Couldn't read float charger options rc=%d\n",
2069 rc);
2070 return rc;
2071 }
2072
2073 switch (chip->dt.chg_inhibit_thr_mv) {
2074 case 50:
2075 rc = smblib_masked_write(chg, CHARGE_INHIBIT_THRESHOLD_CFG_REG,
2076 CHARGE_INHIBIT_THRESHOLD_MASK,
2077 INHIBIT_ANALOG_VFLT_MINUS_50MV);
2078 break;
2079 case 100:
2080 rc = smblib_masked_write(chg, CHARGE_INHIBIT_THRESHOLD_CFG_REG,
2081 CHARGE_INHIBIT_THRESHOLD_MASK,
2082 INHIBIT_ANALOG_VFLT_MINUS_100MV);
2083 break;
2084 case 200:
2085 rc = smblib_masked_write(chg, CHARGE_INHIBIT_THRESHOLD_CFG_REG,
2086 CHARGE_INHIBIT_THRESHOLD_MASK,
2087 INHIBIT_ANALOG_VFLT_MINUS_200MV);
2088 break;
2089 case 300:
2090 rc = smblib_masked_write(chg, CHARGE_INHIBIT_THRESHOLD_CFG_REG,
2091 CHARGE_INHIBIT_THRESHOLD_MASK,
2092 INHIBIT_ANALOG_VFLT_MINUS_300MV);
2093 break;
2094 case 0:
2095 rc = smblib_masked_write(chg, CHGR_CFG2_REG,
2096 CHARGER_INHIBIT_BIT, 0);
2097 default:
2098 break;
2099 }
2100
2101 if (rc < 0) {
2102 dev_err(chg->dev, "Couldn't configure charge inhibit threshold rc=%d\n",
2103 rc);
2104 return rc;
2105 }
2106
Anirudh Ghayal1380d312018-02-23 00:01:43 +05302107 rc = smblib_masked_write(chg, CHGR_CFG2_REG, RECHG_MASK,
2108 (chip->dt.auto_recharge_vbat_mv != -EINVAL) ?
2109 VBAT_BASED_RECHG_BIT : 0);
Harry Yang4b7db0f2017-11-27 10:50:44 -08002110 if (rc < 0) {
Anirudh Ghayal1380d312018-02-23 00:01:43 +05302111 dev_err(chg->dev, "Couldn't configure VBAT-rechg CHG_CFG2_REG rc=%d\n",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002112 rc);
2113 return rc;
2114 }
2115
Anirudh Ghayal1380d312018-02-23 00:01:43 +05302116 /* program the auto-recharge VBAT threshold */
2117 if (chip->dt.auto_recharge_vbat_mv != -EINVAL) {
2118 u32 temp = VBAT_TO_VRAW_ADC(chip->dt.auto_recharge_vbat_mv);
2119
2120 temp = ((temp & 0xFF00) >> 8) | ((temp & 0xFF) << 8);
2121 rc = smblib_batch_write(chg,
2122 CHGR_ADC_RECHARGE_THRESHOLD_MSB_REG, (u8 *)&temp, 2);
2123 if (rc < 0) {
2124 dev_err(chg->dev, "Couldn't configure ADC_RECHARGE_THRESHOLD REG rc=%d\n",
2125 rc);
2126 return rc;
2127 }
2128 /* Program the sample count for VBAT based recharge to 3 */
2129 rc = smblib_masked_write(chg, CHGR_NO_SAMPLE_TERM_RCHG_CFG_REG,
2130 NO_OF_SAMPLE_FOR_RCHG,
2131 2 << NO_OF_SAMPLE_FOR_RCHG_SHIFT);
2132 if (rc < 0) {
2133 dev_err(chg->dev, "Couldn't configure CHGR_NO_SAMPLE_FOR_TERM_RCHG_CFG rc=%d\n",
2134 rc);
2135 return rc;
2136 }
2137 }
2138
2139 rc = smblib_masked_write(chg, CHGR_CFG2_REG, RECHG_MASK,
2140 (chip->dt.auto_recharge_soc != -EINVAL) ?
2141 SOC_BASED_RECHG_BIT : VBAT_BASED_RECHG_BIT);
2142 if (rc < 0) {
2143 dev_err(chg->dev, "Couldn't configure SOC-rechg CHG_CFG2_REG rc=%d\n",
2144 rc);
2145 return rc;
2146 }
2147
2148 /* program the auto-recharge threshold */
2149 if (chip->dt.auto_recharge_soc != -EINVAL) {
2150 rc = smblib_write(chg, CHARGE_RCHG_SOC_THRESHOLD_CFG_REG,
2151 (chip->dt.auto_recharge_soc * 255) / 100);
2152 if (rc < 0) {
2153 dev_err(chg->dev, "Couldn't configure CHG_RCHG_SOC_REG rc=%d\n",
2154 rc);
2155 return rc;
2156 }
2157 /* Program the sample count for SOC based recharge to 1 */
2158 rc = smblib_masked_write(chg, CHGR_NO_SAMPLE_TERM_RCHG_CFG_REG,
2159 NO_OF_SAMPLE_FOR_RCHG, 0);
2160 if (rc < 0) {
2161 dev_err(chg->dev, "Couldn't configure CHGR_NO_SAMPLE_FOR_TERM_RCHG_CFG rc=%d\n",
2162 rc);
2163 return rc;
2164 }
2165 }
2166
Harry Yang4b7db0f2017-11-27 10:50:44 -08002167 if (chg->sw_jeita_enabled) {
2168 rc = smblib_disable_hw_jeita(chg, true);
2169 if (rc < 0) {
2170 dev_err(chg->dev, "Couldn't set hw jeita rc=%d\n", rc);
2171 return rc;
2172 }
2173 }
2174
Ashay Jaiswala55b7ed2018-03-23 17:23:48 +05302175 rc = smblib_configure_wdog(chg,
2176 chg->step_chg_enabled || chg->sw_jeita_enabled);
2177 if (rc < 0) {
2178 dev_err(chg->dev, "Couldn't configure watchdog rc=%d\n",
2179 rc);
2180 return rc;
2181 }
2182
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +05302183 if (chg->connector_pull_up != -EINVAL) {
2184 rc = smb5_configure_internal_pull(chg, CONN_THERM,
2185 get_valid_pullup(chg->connector_pull_up));
2186 if (rc < 0) {
2187 dev_err(chg->dev,
2188 "Couldn't configure CONN_THERM pull-up rc=%d\n",
2189 rc);
2190 return rc;
2191 }
2192 }
2193
Harry Yang4b7db0f2017-11-27 10:50:44 -08002194 return rc;
2195}
2196
2197static int smb5_post_init(struct smb5 *chip)
2198{
2199 struct smb_charger *chg = &chip->chg;
2200 union power_supply_propval pval;
2201 int rc;
2202
2203 /*
2204 * In case the usb path is suspended, we would have missed disabling
2205 * the icl change interrupt because the interrupt could have been
2206 * not requested
2207 */
2208 rerun_election(chg->usb_icl_votable);
2209
2210 /* configure power role for dual-role */
2211 pval.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
2212 rc = smblib_set_prop_typec_power_role(chg, &pval);
2213 if (rc < 0) {
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302214 dev_err(chg->dev, "Couldn't configure DRP role rc=%d\n",
2215 rc);
Harry Yang4b7db0f2017-11-27 10:50:44 -08002216 return rc;
2217 }
2218
2219 rerun_election(chg->usb_irq_enable_votable);
2220
2221 return 0;
2222}
2223
2224/****************************
2225 * DETERMINE INITIAL STATUS *
2226 ****************************/
2227
2228static int smb5_determine_initial_status(struct smb5 *chip)
2229{
2230 struct smb_irq_data irq_data = {chip, "determine-initial-status"};
2231 struct smb_charger *chg = &chip->chg;
Harry Yang6afaea22018-03-26 19:11:07 -07002232 union power_supply_propval val;
2233 int rc;
2234
2235 rc = smblib_get_prop_usb_present(chg, &val);
2236 if (rc < 0) {
2237 pr_err("Couldn't get usb present rc=%d\n", rc);
2238 return rc;
2239 }
2240 chg->early_usb_attach = val.intval;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002241
2242 if (chg->bms_psy)
2243 smblib_suspend_on_debug_battery(chg);
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302244
Harry Yang4b7db0f2017-11-27 10:50:44 -08002245 usb_plugin_irq_handler(0, &irq_data);
Harry Yang6afaea22018-03-26 19:11:07 -07002246 typec_attach_detach_irq_handler(0, &irq_data);
Harry Yang4b7db0f2017-11-27 10:50:44 -08002247 typec_state_change_irq_handler(0, &irq_data);
2248 usb_source_change_irq_handler(0, &irq_data);
2249 chg_state_change_irq_handler(0, &irq_data);
2250 icl_change_irq_handler(0, &irq_data);
2251 batt_temp_changed_irq_handler(0, &irq_data);
2252 wdog_bark_irq_handler(0, &irq_data);
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302253 typec_or_rid_detection_change_irq_handler(0, &irq_data);
Harry Yang4b7db0f2017-11-27 10:50:44 -08002254
2255 return 0;
2256}
2257
2258/**************************
2259 * INTERRUPT REGISTRATION *
2260 **************************/
2261
2262static struct smb_irq_info smb5_irqs[] = {
2263 /* CHARGER IRQs */
2264 [CHGR_ERROR_IRQ] = {
2265 .name = "chgr-error",
2266 .handler = default_irq_handler,
2267 },
2268 [CHG_STATE_CHANGE_IRQ] = {
2269 .name = "chg-state-change",
2270 .handler = chg_state_change_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302271 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002272 },
2273 [STEP_CHG_STATE_CHANGE_IRQ] = {
2274 .name = "step-chg-state-change",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002275 },
2276 [STEP_CHG_SOC_UPDATE_FAIL_IRQ] = {
2277 .name = "step-chg-soc-update-fail",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002278 },
2279 [STEP_CHG_SOC_UPDATE_REQ_IRQ] = {
2280 .name = "step-chg-soc-update-req",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002281 },
2282 [FG_FVCAL_QUALIFIED_IRQ] = {
2283 .name = "fg-fvcal-qualified",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002284 },
2285 [VPH_ALARM_IRQ] = {
2286 .name = "vph-alarm",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002287 },
2288 [VPH_DROP_PRECHG_IRQ] = {
2289 .name = "vph-drop-prechg",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002290 },
2291 /* DCDC IRQs */
2292 [OTG_FAIL_IRQ] = {
2293 .name = "otg-fail",
2294 .handler = default_irq_handler,
2295 },
2296 [OTG_OC_DISABLE_SW_IRQ] = {
2297 .name = "otg-oc-disable-sw",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002298 },
2299 [OTG_OC_HICCUP_IRQ] = {
2300 .name = "otg-oc-hiccup",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002301 },
2302 [BSM_ACTIVE_IRQ] = {
2303 .name = "bsm-active",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002304 },
2305 [HIGH_DUTY_CYCLE_IRQ] = {
2306 .name = "high-duty-cycle",
2307 .handler = high_duty_cycle_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302308 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002309 },
2310 [INPUT_CURRENT_LIMITING_IRQ] = {
2311 .name = "input-current-limiting",
2312 .handler = default_irq_handler,
2313 },
2314 [CONCURRENT_MODE_DISABLE_IRQ] = {
2315 .name = "concurrent-mode-disable",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002316 },
2317 [SWITCHER_POWER_OK_IRQ] = {
2318 .name = "switcher-power-ok",
2319 .handler = switcher_power_ok_irq_handler,
2320 },
2321 /* BATTERY IRQs */
2322 [BAT_TEMP_IRQ] = {
2323 .name = "bat-temp",
2324 .handler = batt_temp_changed_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302325 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002326 },
2327 [ALL_CHNL_CONV_DONE_IRQ] = {
2328 .name = "all-chnl-conv-done",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002329 },
2330 [BAT_OV_IRQ] = {
2331 .name = "bat-ov",
2332 .handler = batt_psy_changed_irq_handler,
2333 },
2334 [BAT_LOW_IRQ] = {
2335 .name = "bat-low",
2336 .handler = batt_psy_changed_irq_handler,
2337 },
2338 [BAT_THERM_OR_ID_MISSING_IRQ] = {
2339 .name = "bat-therm-or-id-missing",
2340 .handler = batt_psy_changed_irq_handler,
2341 },
2342 [BAT_TERMINAL_MISSING_IRQ] = {
2343 .name = "bat-terminal-missing",
2344 .handler = batt_psy_changed_irq_handler,
2345 },
2346 [BUCK_OC_IRQ] = {
2347 .name = "buck-oc",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002348 },
2349 [VPH_OV_IRQ] = {
2350 .name = "vph-ov",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002351 },
2352 /* USB INPUT IRQs */
2353 [USBIN_COLLAPSE_IRQ] = {
2354 .name = "usbin-collapse",
2355 .handler = default_irq_handler,
2356 },
2357 [USBIN_VASHDN_IRQ] = {
2358 .name = "usbin-vashdn",
2359 .handler = default_irq_handler,
2360 },
2361 [USBIN_UV_IRQ] = {
2362 .name = "usbin-uv",
2363 .handler = usbin_uv_irq_handler,
Ashay Jaiswale0b3c472018-06-20 23:39:41 +05302364 .wake = true,
2365 .storm_data = {true, 3000, 5},
Harry Yang4b7db0f2017-11-27 10:50:44 -08002366 },
2367 [USBIN_OV_IRQ] = {
2368 .name = "usbin-ov",
2369 .handler = default_irq_handler,
2370 },
2371 [USBIN_PLUGIN_IRQ] = {
2372 .name = "usbin-plugin",
2373 .handler = usb_plugin_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302374 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002375 },
2376 [USBIN_REVI_CHANGE_IRQ] = {
2377 .name = "usbin-revi-change",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002378 },
2379 [USBIN_SRC_CHANGE_IRQ] = {
2380 .name = "usbin-src-change",
2381 .handler = usb_source_change_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302382 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002383 },
2384 [USBIN_ICL_CHANGE_IRQ] = {
2385 .name = "usbin-icl-change",
2386 .handler = icl_change_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302387 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002388 },
2389 /* DC INPUT IRQs */
2390 [DCIN_VASHDN_IRQ] = {
2391 .name = "dcin-vashdn",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002392 },
2393 [DCIN_UV_IRQ] = {
2394 .name = "dcin-uv",
2395 .handler = default_irq_handler,
2396 },
2397 [DCIN_OV_IRQ] = {
2398 .name = "dcin-ov",
2399 .handler = default_irq_handler,
2400 },
2401 [DCIN_PLUGIN_IRQ] = {
2402 .name = "dcin-plugin",
2403 .handler = dc_plugin_irq_handler,
2404 .wake = true,
2405 },
2406 [DCIN_REVI_IRQ] = {
2407 .name = "dcin-revi",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002408 },
2409 [DCIN_PON_IRQ] = {
2410 .name = "dcin-pon",
2411 .handler = default_irq_handler,
2412 },
2413 [DCIN_EN_IRQ] = {
2414 .name = "dcin-en",
2415 .handler = default_irq_handler,
2416 },
2417 /* TYPEC IRQs */
2418 [TYPEC_OR_RID_DETECTION_CHANGE_IRQ] = {
2419 .name = "typec-or-rid-detect-change",
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302420 .handler = typec_or_rid_detection_change_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302421 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002422 },
2423 [TYPEC_VPD_DETECT_IRQ] = {
2424 .name = "typec-vpd-detect",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002425 },
2426 [TYPEC_CC_STATE_CHANGE_IRQ] = {
2427 .name = "typec-cc-state-change",
2428 .handler = typec_state_change_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302429 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002430 },
2431 [TYPEC_VCONN_OC_IRQ] = {
2432 .name = "typec-vconn-oc",
2433 .handler = default_irq_handler,
2434 },
2435 [TYPEC_VBUS_CHANGE_IRQ] = {
2436 .name = "typec-vbus-change",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002437 },
2438 [TYPEC_ATTACH_DETACH_IRQ] = {
2439 .name = "typec-attach-detach",
Harry Yang6afaea22018-03-26 19:11:07 -07002440 .handler = typec_attach_detach_irq_handler,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002441 },
2442 [TYPEC_LEGACY_CABLE_DETECT_IRQ] = {
2443 .name = "typec-legacy-cable-detect",
2444 .handler = default_irq_handler,
2445 },
2446 [TYPEC_TRY_SNK_SRC_DETECT_IRQ] = {
2447 .name = "typec-try-snk-src-detect",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002448 },
2449 /* MISCELLANEOUS IRQs */
2450 [WDOG_SNARL_IRQ] = {
2451 .name = "wdog-snarl",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002452 },
2453 [WDOG_BARK_IRQ] = {
2454 .name = "wdog-bark",
2455 .handler = wdog_bark_irq_handler,
Ashay Jaiswala55b7ed2018-03-23 17:23:48 +05302456 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002457 },
2458 [AICL_FAIL_IRQ] = {
2459 .name = "aicl-fail",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002460 },
2461 [AICL_DONE_IRQ] = {
2462 .name = "aicl-done",
2463 .handler = default_irq_handler,
2464 },
2465 [SMB_EN_IRQ] = {
2466 .name = "smb-en",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002467 },
2468 [IMP_TRIGGER_IRQ] = {
2469 .name = "imp-trigger",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002470 },
2471 [TEMP_CHANGE_IRQ] = {
2472 .name = "temp-change",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002473 },
2474 [TEMP_CHANGE_SMB_IRQ] = {
2475 .name = "temp-change-smb",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002476 },
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302477 /* FLASH */
2478 [VREG_OK_IRQ] = {
2479 .name = "vreg-ok",
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302480 },
2481 [ILIM_S2_IRQ] = {
2482 .name = "ilim2-s2",
2483 .handler = schgm_flash_ilim2_irq_handler,
2484 },
2485 [ILIM_S1_IRQ] = {
2486 .name = "ilim1-s1",
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302487 },
2488 [VOUT_DOWN_IRQ] = {
2489 .name = "vout-down",
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302490 },
2491 [VOUT_UP_IRQ] = {
2492 .name = "vout-up",
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302493 },
2494 [FLASH_STATE_CHANGE_IRQ] = {
2495 .name = "flash-state-change",
2496 .handler = schgm_flash_state_change_irq_handler,
2497 },
2498 [TORCH_REQ_IRQ] = {
2499 .name = "torch-req",
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302500 },
2501 [FLASH_EN_IRQ] = {
2502 .name = "flash-en",
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302503 },
Harry Yang4b7db0f2017-11-27 10:50:44 -08002504};
2505
2506static int smb5_get_irq_index_byname(const char *irq_name)
2507{
2508 int i;
2509
2510 for (i = 0; i < ARRAY_SIZE(smb5_irqs); i++) {
2511 if (strcmp(smb5_irqs[i].name, irq_name) == 0)
2512 return i;
2513 }
2514
2515 return -ENOENT;
2516}
2517
2518static int smb5_request_interrupt(struct smb5 *chip,
2519 struct device_node *node, const char *irq_name)
2520{
2521 struct smb_charger *chg = &chip->chg;
2522 int rc, irq, irq_index;
2523 struct smb_irq_data *irq_data;
2524
2525 irq = of_irq_get_byname(node, irq_name);
2526 if (irq < 0) {
2527 pr_err("Couldn't get irq %s byname\n", irq_name);
2528 return irq;
2529 }
2530
2531 irq_index = smb5_get_irq_index_byname(irq_name);
2532 if (irq_index < 0) {
2533 pr_err("%s is not a defined irq\n", irq_name);
2534 return irq_index;
2535 }
2536
2537 if (!smb5_irqs[irq_index].handler)
2538 return 0;
2539
2540 irq_data = devm_kzalloc(chg->dev, sizeof(*irq_data), GFP_KERNEL);
2541 if (!irq_data)
2542 return -ENOMEM;
2543
2544 irq_data->parent_data = chip;
2545 irq_data->name = irq_name;
2546 irq_data->storm_data = smb5_irqs[irq_index].storm_data;
2547 mutex_init(&irq_data->storm_data.storm_lock);
2548
2549 rc = devm_request_threaded_irq(chg->dev, irq, NULL,
2550 smb5_irqs[irq_index].handler,
2551 IRQF_ONESHOT, irq_name, irq_data);
2552 if (rc < 0) {
2553 pr_err("Couldn't request irq %d\n", irq);
2554 return rc;
2555 }
2556
2557 smb5_irqs[irq_index].irq = irq;
2558 smb5_irqs[irq_index].irq_data = irq_data;
2559 if (smb5_irqs[irq_index].wake)
2560 enable_irq_wake(irq);
2561
2562 return rc;
2563}
2564
2565static int smb5_request_interrupts(struct smb5 *chip)
2566{
2567 struct smb_charger *chg = &chip->chg;
2568 struct device_node *node = chg->dev->of_node;
2569 struct device_node *child;
2570 int rc = 0;
2571 const char *name;
2572 struct property *prop;
2573
2574 for_each_available_child_of_node(node, child) {
2575 of_property_for_each_string(child, "interrupt-names",
2576 prop, name) {
2577 rc = smb5_request_interrupt(chip, child, name);
2578 if (rc < 0)
2579 return rc;
2580 }
2581 }
2582 if (chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq)
2583 chg->usb_icl_change_irq_enabled = true;
2584
2585 return rc;
2586}
2587
2588static void smb5_free_interrupts(struct smb_charger *chg)
2589{
2590 int i;
2591
2592 for (i = 0; i < ARRAY_SIZE(smb5_irqs); i++) {
2593 if (smb5_irqs[i].irq > 0) {
2594 if (smb5_irqs[i].wake)
2595 disable_irq_wake(smb5_irqs[i].irq);
2596
2597 devm_free_irq(chg->dev, smb5_irqs[i].irq,
2598 smb5_irqs[i].irq_data);
2599 }
2600 }
2601}
2602
2603static void smb5_disable_interrupts(struct smb_charger *chg)
2604{
2605 int i;
2606
2607 for (i = 0; i < ARRAY_SIZE(smb5_irqs); i++) {
2608 if (smb5_irqs[i].irq > 0)
2609 disable_irq(smb5_irqs[i].irq);
2610 }
2611}
2612
2613#if defined(CONFIG_DEBUG_FS)
2614
2615static int force_batt_psy_update_write(void *data, u64 val)
2616{
2617 struct smb_charger *chg = data;
2618
2619 power_supply_changed(chg->batt_psy);
2620 return 0;
2621}
2622DEFINE_SIMPLE_ATTRIBUTE(force_batt_psy_update_ops, NULL,
2623 force_batt_psy_update_write, "0x%02llx\n");
2624
2625static int force_usb_psy_update_write(void *data, u64 val)
2626{
2627 struct smb_charger *chg = data;
2628
2629 power_supply_changed(chg->usb_psy);
2630 return 0;
2631}
2632DEFINE_SIMPLE_ATTRIBUTE(force_usb_psy_update_ops, NULL,
2633 force_usb_psy_update_write, "0x%02llx\n");
2634
2635static int force_dc_psy_update_write(void *data, u64 val)
2636{
2637 struct smb_charger *chg = data;
2638
2639 power_supply_changed(chg->dc_psy);
2640 return 0;
2641}
2642DEFINE_SIMPLE_ATTRIBUTE(force_dc_psy_update_ops, NULL,
2643 force_dc_psy_update_write, "0x%02llx\n");
2644
2645static void smb5_create_debugfs(struct smb5 *chip)
2646{
2647 struct dentry *file;
2648
2649 chip->dfs_root = debugfs_create_dir("charger", NULL);
2650 if (IS_ERR_OR_NULL(chip->dfs_root)) {
2651 pr_err("Couldn't create charger debugfs rc=%ld\n",
2652 (long)chip->dfs_root);
2653 return;
2654 }
2655
2656 file = debugfs_create_file("force_batt_psy_update", 0600,
2657 chip->dfs_root, chip, &force_batt_psy_update_ops);
2658 if (IS_ERR_OR_NULL(file))
2659 pr_err("Couldn't create force_batt_psy_update file rc=%ld\n",
2660 (long)file);
2661
2662 file = debugfs_create_file("force_usb_psy_update", 0600,
2663 chip->dfs_root, chip, &force_usb_psy_update_ops);
2664 if (IS_ERR_OR_NULL(file))
2665 pr_err("Couldn't create force_usb_psy_update file rc=%ld\n",
2666 (long)file);
2667
2668 file = debugfs_create_file("force_dc_psy_update", 0600,
2669 chip->dfs_root, chip, &force_dc_psy_update_ops);
2670 if (IS_ERR_OR_NULL(file))
2671 pr_err("Couldn't create force_dc_psy_update file rc=%ld\n",
2672 (long)file);
2673}
2674
2675#else
2676
2677static void smb5_create_debugfs(struct smb5 *chip)
2678{}
2679
2680#endif
2681
2682static int smb5_show_charger_status(struct smb5 *chip)
2683{
2684 struct smb_charger *chg = &chip->chg;
2685 union power_supply_propval val;
2686 int usb_present, batt_present, batt_health, batt_charge_type;
2687 int rc;
2688
2689 rc = smblib_get_prop_usb_present(chg, &val);
2690 if (rc < 0) {
2691 pr_err("Couldn't get usb present rc=%d\n", rc);
2692 return rc;
2693 }
2694 usb_present = val.intval;
2695
2696 rc = smblib_get_prop_batt_present(chg, &val);
2697 if (rc < 0) {
2698 pr_err("Couldn't get batt present rc=%d\n", rc);
2699 return rc;
2700 }
2701 batt_present = val.intval;
2702
2703 rc = smblib_get_prop_batt_health(chg, &val);
2704 if (rc < 0) {
2705 pr_err("Couldn't get batt health rc=%d\n", rc);
2706 val.intval = POWER_SUPPLY_HEALTH_UNKNOWN;
2707 }
2708 batt_health = val.intval;
2709
2710 rc = smblib_get_prop_batt_charge_type(chg, &val);
2711 if (rc < 0) {
2712 pr_err("Couldn't get batt charge type rc=%d\n", rc);
2713 return rc;
2714 }
2715 batt_charge_type = val.intval;
2716
2717 pr_info("SMB5 status - usb:present=%d type=%d batt:present = %d health = %d charge = %d\n",
2718 usb_present, chg->real_charger_type,
2719 batt_present, batt_health, batt_charge_type);
2720 return rc;
2721}
2722
2723static int smb5_probe(struct platform_device *pdev)
2724{
2725 struct smb5 *chip;
2726 struct smb_charger *chg;
2727 int rc = 0;
2728
2729 chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
2730 if (!chip)
2731 return -ENOMEM;
2732
2733 chg = &chip->chg;
2734 chg->dev = &pdev->dev;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002735 chg->debug_mask = &__debug_mask;
Harry Yang6afaea22018-03-26 19:11:07 -07002736 chg->pd_disabled = &__pd_disabled;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002737 chg->weak_chg_icl_ua = &__weak_chg_icl_ua;
2738 chg->mode = PARALLEL_MASTER;
2739 chg->irq_info = smb5_irqs;
2740 chg->die_health = -EINVAL;
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302741 chg->otg_present = false;
Anirudh Ghayal75f8f812018-07-09 16:48:47 +05302742 mutex_init(&chg->vadc_lock);
Harry Yang4b7db0f2017-11-27 10:50:44 -08002743
2744 chg->regmap = dev_get_regmap(chg->dev->parent, NULL);
2745 if (!chg->regmap) {
2746 pr_err("parent regmap is missing\n");
2747 return -EINVAL;
2748 }
2749
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302750 rc = smb5_chg_config_init(chip);
2751 if (rc < 0) {
2752 if (rc != -EPROBE_DEFER)
2753 pr_err("Couldn't setup chg_config rc=%d\n", rc);
2754 return rc;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002755 }
2756
Ashay Jaiswalb2b06fe2018-06-07 18:35:21 +05302757 rc = smb5_parse_dt(chip);
2758 if (rc < 0) {
2759 pr_err("Couldn't parse device tree rc=%d\n", rc);
2760 return rc;
2761 }
2762
Harry Yang4b7db0f2017-11-27 10:50:44 -08002763 rc = smblib_init(chg);
2764 if (rc < 0) {
2765 pr_err("Smblib_init failed rc=%d\n", rc);
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302766 return rc;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002767 }
2768
2769 /* set driver data before resources request it */
2770 platform_set_drvdata(pdev, chip);
2771
2772 rc = smb5_init_vbus_regulator(chip);
2773 if (rc < 0) {
2774 pr_err("Couldn't initialize vbus regulator rc=%d\n",
2775 rc);
2776 goto cleanup;
2777 }
2778
2779 rc = smb5_init_vconn_regulator(chip);
2780 if (rc < 0) {
2781 pr_err("Couldn't initialize vconn regulator rc=%d\n",
2782 rc);
2783 goto cleanup;
2784 }
2785
2786 /* extcon registration */
2787 chg->extcon = devm_extcon_dev_allocate(chg->dev, smblib_extcon_cable);
2788 if (IS_ERR(chg->extcon)) {
2789 rc = PTR_ERR(chg->extcon);
2790 dev_err(chg->dev, "failed to allocate extcon device rc=%d\n",
2791 rc);
2792 goto cleanup;
2793 }
2794
2795 rc = devm_extcon_dev_register(chg->dev, chg->extcon);
2796 if (rc < 0) {
2797 dev_err(chg->dev, "failed to register extcon device rc=%d\n",
2798 rc);
2799 goto cleanup;
2800 }
2801
2802 rc = smb5_init_hw(chip);
2803 if (rc < 0) {
2804 pr_err("Couldn't initialize hardware rc=%d\n", rc);
2805 goto cleanup;
2806 }
2807
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302808 if (chg->smb_version == PM855B_SUBTYPE) {
2809 rc = smb5_init_dc_psy(chip);
2810 if (rc < 0) {
2811 pr_err("Couldn't initialize dc psy rc=%d\n", rc);
2812 goto cleanup;
2813 }
Harry Yang4b7db0f2017-11-27 10:50:44 -08002814 }
2815
2816 rc = smb5_init_usb_psy(chip);
2817 if (rc < 0) {
2818 pr_err("Couldn't initialize usb psy rc=%d\n", rc);
2819 goto cleanup;
2820 }
2821
2822 rc = smb5_init_usb_main_psy(chip);
2823 if (rc < 0) {
2824 pr_err("Couldn't initialize usb main psy rc=%d\n", rc);
2825 goto cleanup;
2826 }
2827
2828 rc = smb5_init_usb_port_psy(chip);
2829 if (rc < 0) {
2830 pr_err("Couldn't initialize usb pc_port psy rc=%d\n", rc);
2831 goto cleanup;
2832 }
2833
2834 rc = smb5_init_batt_psy(chip);
2835 if (rc < 0) {
2836 pr_err("Couldn't initialize batt psy rc=%d\n", rc);
2837 goto cleanup;
2838 }
2839
2840 rc = smb5_determine_initial_status(chip);
2841 if (rc < 0) {
2842 pr_err("Couldn't determine initial status rc=%d\n",
2843 rc);
2844 goto cleanup;
2845 }
2846
2847 rc = smb5_request_interrupts(chip);
2848 if (rc < 0) {
2849 pr_err("Couldn't request interrupts rc=%d\n", rc);
2850 goto cleanup;
2851 }
2852
2853 rc = smb5_post_init(chip);
2854 if (rc < 0) {
2855 pr_err("Failed in post init rc=%d\n", rc);
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302856 goto free_irq;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002857 }
2858
2859 smb5_create_debugfs(chip);
2860
2861 rc = smb5_show_charger_status(chip);
2862 if (rc < 0) {
2863 pr_err("Failed in getting charger status rc=%d\n", rc);
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302864 goto free_irq;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002865 }
2866
2867 device_init_wakeup(chg->dev, true);
2868
2869 pr_info("QPNP SMB5 probed successfully\n");
2870
2871 return rc;
2872
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302873free_irq:
Harry Yang4b7db0f2017-11-27 10:50:44 -08002874 smb5_free_interrupts(chg);
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302875cleanup:
Harry Yang4b7db0f2017-11-27 10:50:44 -08002876 smblib_deinit(chg);
2877 platform_set_drvdata(pdev, NULL);
2878
2879 return rc;
2880}
2881
2882static int smb5_remove(struct platform_device *pdev)
2883{
2884 struct smb5 *chip = platform_get_drvdata(pdev);
2885 struct smb_charger *chg = &chip->chg;
2886
Harry Yang6afaea22018-03-26 19:11:07 -07002887 /* force enable APSD */
2888 smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
2889 BC1P2_SRC_DETECT_BIT, BC1P2_SRC_DETECT_BIT);
2890
Harry Yang4b7db0f2017-11-27 10:50:44 -08002891 smb5_free_interrupts(chg);
2892 smblib_deinit(chg);
2893 platform_set_drvdata(pdev, NULL);
2894 return 0;
2895}
2896
2897static void smb5_shutdown(struct platform_device *pdev)
2898{
2899 struct smb5 *chip = platform_get_drvdata(pdev);
2900 struct smb_charger *chg = &chip->chg;
2901
2902 /* disable all interrupts */
2903 smb5_disable_interrupts(chg);
2904
2905 /* configure power role for UFP */
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302906 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_TYPEC)
Harry Yang4b7db0f2017-11-27 10:50:44 -08002907 smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
2908 TYPEC_POWER_ROLE_CMD_MASK, EN_SNK_ONLY_BIT);
2909
2910 /* force HVDCP to 5V */
2911 smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
2912 HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT, 0);
2913 smblib_write(chg, CMD_HVDCP_2_REG, FORCE_5V_BIT);
2914
2915 /* force enable APSD */
2916 smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
2917 BC1P2_SRC_DETECT_BIT, BC1P2_SRC_DETECT_BIT);
2918}
2919
2920static const struct of_device_id match_table[] = {
2921 { .compatible = "qcom,qpnp-smb5", },
2922 { },
2923};
2924
2925static struct platform_driver smb5_driver = {
2926 .driver = {
2927 .name = "qcom,qpnp-smb5",
2928 .owner = THIS_MODULE,
2929 .of_match_table = match_table,
2930 },
2931 .probe = smb5_probe,
2932 .remove = smb5_remove,
2933 .shutdown = smb5_shutdown,
2934};
2935module_platform_driver(smb5_driver);
2936
2937MODULE_DESCRIPTION("QPNP SMB5 Charger Driver");
2938MODULE_LICENSE("GPL v2");