blob: aa50be72f282f6785529338f49158374b77e6c63 [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;
213};
214
215struct smb5 {
216 struct smb_charger chg;
217 struct dentry *dfs_root;
218 struct smb_dt_props dt;
219};
220
221static int __debug_mask;
222module_param_named(
223 debug_mask, __debug_mask, int, 0600
224);
225
Harry Yang6afaea22018-03-26 19:11:07 -0700226static int __pd_disabled;
227module_param_named(
228 pd_disabled, __pd_disabled, int, 0600
229);
230
Harry Yang4b7db0f2017-11-27 10:50:44 -0800231static int __weak_chg_icl_ua = 500000;
232module_param_named(
233 weak_chg_icl_ua, __weak_chg_icl_ua, int, 0600
234);
235
Ashay Jaiswal20688262018-04-25 11:45:34 +0530236enum {
237 USBIN_CURRENT,
238 USBIN_VOLTAGE,
239};
240
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +0530241enum {
242 BAT_THERM = 0,
243 MISC_THERM,
244 CONN_THERM,
245 SMB_THERM,
246};
247
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530248#define PMI632_MAX_ICL_UA 3000000
249static int smb5_chg_config_init(struct smb5 *chip)
250{
251 struct smb_charger *chg = &chip->chg;
252 struct pmic_revid_data *pmic_rev_id;
253 struct device_node *revid_dev_node;
254 int rc = 0;
255
256 revid_dev_node = of_parse_phandle(chip->chg.dev->of_node,
257 "qcom,pmic-revid", 0);
258 if (!revid_dev_node) {
259 pr_err("Missing qcom,pmic-revid property\n");
260 return -EINVAL;
261 }
262
263 pmic_rev_id = get_revid_data(revid_dev_node);
264 if (IS_ERR_OR_NULL(pmic_rev_id)) {
265 /*
266 * the revid peripheral must be registered, any failure
267 * here only indicates that the rev-id module has not
268 * probed yet.
269 */
270 rc = -EPROBE_DEFER;
271 goto out;
272 }
273
274 switch (pmic_rev_id->pmic_subtype) {
275 case PM855B_SUBTYPE:
276 chip->chg.smb_version = PM855B_SUBTYPE;
Harry Yangf7b89902018-03-13 22:37:53 -0700277 chg->param = smb5_pm855b_params;
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530278 chg->name = "pm855b_charger";
279 break;
280 case PMI632_SUBTYPE:
281 chip->chg.smb_version = PMI632_SUBTYPE;
Ashay Jaiswale0b3c472018-06-20 23:39:41 +0530282 chg->wa_flags |= WEAK_ADAPTER_WA;
Umang Agrawal461e9ea2018-07-05 18:50:13 +0530283 if (pmic_rev_id->rev4 >= 2)
284 chg->wa_flags |= MOISTURE_PROTECTION_WA;
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530285 chg->param = smb5_pmi632_params;
286 chg->use_extcon = true;
287 chg->name = "pmi632_charger";
Ashay Jaiswalc96380de2018-05-16 12:02:36 +0530288 /* PMI632 does not support PD */
Ashay Jaiswalf2ca7092018-05-22 21:33:15 +0530289 chg->pd_not_supported = true;
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530290 chg->hw_max_icl_ua =
291 (chip->dt.usb_icl_ua > 0) ? chip->dt.usb_icl_ua
292 : PMI632_MAX_ICL_UA;
293 chg->chg_freq.freq_5V = 600;
294 chg->chg_freq.freq_6V_8V = 800;
295 chg->chg_freq.freq_9V = 1050;
296 chg->chg_freq.freq_removal = 1050;
297 chg->chg_freq.freq_below_otg_threshold = 800;
298 chg->chg_freq.freq_above_otg_threshold = 800;
299 break;
300 default:
301 pr_err("PMIC subtype %d not supported\n",
302 pmic_rev_id->pmic_subtype);
303 rc = -EINVAL;
304 }
305
306out:
307 of_node_put(revid_dev_node);
308 return rc;
309}
310
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +0530311#define PULL_NO_PULL 0
312#define PULL_30K 30
313#define PULL_100K 100
314#define PULL_400K 400
315static int get_valid_pullup(int pull_up)
316{
317 int pull;
318
319 /* pull up can only be 0/30K/100K/400K) */
320 switch (pull_up) {
321 case PULL_NO_PULL:
322 pull = INTERNAL_PULL_NO_PULL;
323 break;
324 case PULL_30K:
325 pull = INTERNAL_PULL_30K_PULL;
326 break;
327 case PULL_100K:
328 pull = INTERNAL_PULL_100K_PULL;
329 break;
330 case PULL_400K:
331 pull = INTERNAL_PULL_400K_PULL;
332 break;
333 default:
334 pull = INTERNAL_PULL_100K_PULL;
335 }
336
337 return pull;
338}
339
340#define INTERNAL_PULL_UP_MASK 0x3
341static int smb5_configure_internal_pull(struct smb_charger *chg, int type,
342 int pull)
343{
344 int rc;
345 int shift = type * 2;
346 u8 mask = INTERNAL_PULL_UP_MASK << shift;
347 u8 val = pull << shift;
348
349 rc = smblib_masked_write(chg, BATIF_ADC_INTERNAL_PULL_UP_REG,
350 mask, val);
351 if (rc < 0)
352 dev_err(chg->dev,
353 "Couldn't configure ADC pull-up reg rc=%d\n", rc);
354
355 return rc;
356}
357
Harry Yang4b7db0f2017-11-27 10:50:44 -0800358#define MICRO_1P5A 1500000
Ashay Jaiswalb2b06fe2018-06-07 18:35:21 +0530359#define MICRO_1PA 1000000
Harry Yang4b7db0f2017-11-27 10:50:44 -0800360#define MICRO_P1A 100000
361#define OTG_DEFAULT_DEGLITCH_TIME_MS 50
362#define MIN_WD_BARK_TIME 16
363#define DEFAULT_WD_BARK_TIME 64
364#define BITE_WDOG_TIMEOUT_8S 0x3
365#define BARK_WDOG_TIMEOUT_MASK GENMASK(3, 2)
366#define BARK_WDOG_TIMEOUT_SHIFT 2
367static int smb5_parse_dt(struct smb5 *chip)
368{
369 struct smb_charger *chg = &chip->chg;
370 struct device_node *node = chg->dev->of_node;
371 int rc, byte_len;
372
373 if (!node) {
374 pr_err("device tree node missing\n");
375 return -EINVAL;
376 }
377
378 chg->step_chg_enabled = of_property_read_bool(node,
379 "qcom,step-charging-enable");
380
381 chg->sw_jeita_enabled = of_property_read_bool(node,
382 "qcom,sw-jeita-enable");
383
384 rc = of_property_read_u32(node, "qcom,wd-bark-time-secs",
385 &chip->dt.wd_bark_time);
386 if (rc < 0 || chip->dt.wd_bark_time < MIN_WD_BARK_TIME)
387 chip->dt.wd_bark_time = DEFAULT_WD_BARK_TIME;
388
389 chip->dt.no_battery = of_property_read_bool(node,
390 "qcom,batteryless-platform");
391
392 rc = of_property_read_u32(node,
393 "qcom,fcc-max-ua", &chip->dt.batt_profile_fcc_ua);
394 if (rc < 0)
395 chip->dt.batt_profile_fcc_ua = -EINVAL;
396
397 rc = of_property_read_u32(node,
398 "qcom,fv-max-uv", &chip->dt.batt_profile_fv_uv);
399 if (rc < 0)
400 chip->dt.batt_profile_fv_uv = -EINVAL;
401
402 rc = of_property_read_u32(node,
403 "qcom,usb-icl-ua", &chip->dt.usb_icl_ua);
404 if (rc < 0)
405 chip->dt.usb_icl_ua = -EINVAL;
406
407 rc = of_property_read_u32(node,
408 "qcom,otg-cl-ua", &chg->otg_cl_ua);
409 if (rc < 0)
Ashay Jaiswalb2b06fe2018-06-07 18:35:21 +0530410 chg->otg_cl_ua = (chip->chg.smb_version == PMI632_SUBTYPE) ?
411 MICRO_1PA : MICRO_1P5A;
Harry Yang4b7db0f2017-11-27 10:50:44 -0800412
413 if (of_find_property(node, "qcom,thermal-mitigation", &byte_len)) {
414 chg->thermal_mitigation = devm_kzalloc(chg->dev, byte_len,
415 GFP_KERNEL);
416
417 if (chg->thermal_mitigation == NULL)
418 return -ENOMEM;
419
420 chg->thermal_levels = byte_len / sizeof(u32);
421 rc = of_property_read_u32_array(node,
422 "qcom,thermal-mitigation",
423 chg->thermal_mitigation,
424 chg->thermal_levels);
425 if (rc < 0) {
426 dev_err(chg->dev,
427 "Couldn't read threm limits rc = %d\n", rc);
428 return rc;
429 }
430 }
431
432 rc = of_property_read_u32(node, "qcom,float-option",
433 &chip->dt.float_option);
434 if (!rc && (chip->dt.float_option < 0 || chip->dt.float_option > 4)) {
435 pr_err("qcom,float-option is out of range [0, 4]\n");
436 return -EINVAL;
437 }
438
439 chip->dt.hvdcp_disable = of_property_read_bool(node,
440 "qcom,hvdcp-disable");
441
442
443 rc = of_property_read_u32(node, "qcom,chg-inhibit-threshold-mv",
444 &chip->dt.chg_inhibit_thr_mv);
445 if (!rc && (chip->dt.chg_inhibit_thr_mv < 0 ||
446 chip->dt.chg_inhibit_thr_mv > 300)) {
447 pr_err("qcom,chg-inhibit-threshold-mv is incorrect\n");
448 return -EINVAL;
449 }
450
Anirudh Ghayal1380d312018-02-23 00:01:43 +0530451 chip->dt.auto_recharge_soc = -EINVAL;
452 rc = of_property_read_u32(node, "qcom,auto-recharge-soc",
453 &chip->dt.auto_recharge_soc);
454 if (!rc && (chip->dt.auto_recharge_soc < 0 ||
455 chip->dt.auto_recharge_soc > 100)) {
456 pr_err("qcom,auto-recharge-soc is incorrect\n");
457 return -EINVAL;
458 }
459 chg->auto_recharge_soc = chip->dt.auto_recharge_soc;
460
461 chip->dt.auto_recharge_vbat_mv = -EINVAL;
462 rc = of_property_read_u32(node, "qcom,auto-recharge-vbat-mv",
463 &chip->dt.auto_recharge_vbat_mv);
464 if (!rc && (chip->dt.auto_recharge_vbat_mv < 0)) {
465 pr_err("qcom,auto-recharge-vbat-mv is incorrect\n");
466 return -EINVAL;
467 }
Harry Yang4b7db0f2017-11-27 10:50:44 -0800468
Harry Yang4b7db0f2017-11-27 10:50:44 -0800469 chg->dcp_icl_ua = chip->dt.usb_icl_ua;
470
471 chg->suspend_input_on_debug_batt = of_property_read_bool(node,
472 "qcom,suspend-input-on-debug-batt");
473
474 rc = of_property_read_u32(node, "qcom,otg-deglitch-time-ms",
475 &chg->otg_delay_ms);
476 if (rc < 0)
477 chg->otg_delay_ms = OTG_DEFAULT_DEGLITCH_TIME_MS;
478
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +0530479 chg->hw_die_temp_mitigation = of_property_read_bool(node,
480 "qcom,hw-die-temp-mitigation");
481
482 chg->hw_connector_mitigation = of_property_read_bool(node,
483 "qcom,hw-connector-mitigation");
484
485 chg->connector_pull_up = -EINVAL;
486 of_property_read_u32(node, "qcom,connector-internal-pull-kohm",
487 &chg->connector_pull_up);
488
Umang Agrawal461e9ea2018-07-05 18:50:13 +0530489 chg->moisture_protection_enabled = of_property_read_bool(node,
490 "qcom,moisture-protection-enable");
491
Harry Yang4b7db0f2017-11-27 10:50:44 -0800492 return 0;
493}
494
Ashay Jaiswal20688262018-04-25 11:45:34 +0530495static int smb5_get_adc_data(struct smb_charger *chg, int channel,
496 union power_supply_propval *val)
497{
Ashay Jaiswalb50706d2018-06-28 19:37:31 +0530498 int rc, ret = 0;
Ashay Jaiswal20688262018-04-25 11:45:34 +0530499 struct qpnp_vadc_result result;
Ashay Jaiswalb50706d2018-06-28 19:37:31 +0530500 u8 reg;
Ashay Jaiswal20688262018-04-25 11:45:34 +0530501
502 if (!chg->vadc_dev) {
503 if (of_find_property(chg->dev->of_node, "qcom,chg-vadc",
504 NULL)) {
505 chg->vadc_dev = qpnp_get_vadc(chg->dev, "chg");
506 if (IS_ERR(chg->vadc_dev)) {
507 rc = PTR_ERR(chg->vadc_dev);
508 if (rc != -EPROBE_DEFER)
509 pr_debug("Failed to find VADC node, rc=%d\n",
510 rc);
511 else
512 chg->vadc_dev = NULL;
513
514 return rc;
515 }
516 } else {
517 return -ENODATA;
518 }
519 }
520
521 if (IS_ERR(chg->vadc_dev))
522 return PTR_ERR(chg->vadc_dev);
523
524 switch (channel) {
525 case USBIN_VOLTAGE:
Ashay Jaiswalb50706d2018-06-28 19:37:31 +0530526 /* Store ADC channel config */
527 rc = smblib_read(chg, BATIF_ADC_CHANNEL_EN_REG, &reg);
528 if (rc < 0) {
529 dev_err(chg->dev,
530 "Couldn't read ADC config rc=%d\n", rc);
531 return rc;
532 }
533
534 /* Disable all ADC channels except IBAT channel */
535 rc = smblib_write(chg, BATIF_ADC_CHANNEL_EN_REG,
536 IBATT_CHANNEL_EN_BIT);
537 if (rc < 0) {
538 dev_err(chg->dev,
539 "Couldn't write ADC config rc=%d\n", rc);
540 return rc;
541 }
542
Ashay Jaiswal20688262018-04-25 11:45:34 +0530543 rc = qpnp_vadc_read(chg->vadc_dev, VADC_USB_IN_V_DIV_16_PM5,
544 &result);
545 if (rc < 0) {
546 pr_err("Failed to read USBIN_V over vadc, rc=%d\n", rc);
Ashay Jaiswalb50706d2018-06-28 19:37:31 +0530547 ret = rc;
548 goto restore;
Ashay Jaiswal20688262018-04-25 11:45:34 +0530549 }
550 val->intval = result.physical;
Ashay Jaiswalb50706d2018-06-28 19:37:31 +0530551
552restore:
553 /* Restore ADC channel config */
554 rc = smblib_write(chg, BATIF_ADC_CHANNEL_EN_REG, reg);
555 if (rc < 0) {
556 dev_err(chg->dev,
557 "Couldn't write ADC config rc=%d\n", rc);
558 return rc;
559 }
560 /* If ADC read failed return ADC error */
561 if (ret < 0)
562 rc = ret;
Ashay Jaiswal20688262018-04-25 11:45:34 +0530563 break;
564 case USBIN_CURRENT:
565 rc = qpnp_vadc_read(chg->vadc_dev, VADC_USB_IN_I_PM5, &result);
566 if (rc < 0) {
567 pr_err("Failed to read USBIN_I over vadc, rc=%d\n", rc);
568 return rc;
569 }
570 val->intval = result.physical;
571 break;
572 default:
573 pr_debug("Invalid channel\n");
574 return -EINVAL;
575 }
576
577 return 0;
578}
579
580
Harry Yang4b7db0f2017-11-27 10:50:44 -0800581/************************
582 * USB PSY REGISTRATION *
583 ************************/
584static enum power_supply_property smb5_usb_props[] = {
585 POWER_SUPPLY_PROP_PRESENT,
586 POWER_SUPPLY_PROP_ONLINE,
587 POWER_SUPPLY_PROP_PD_CURRENT_MAX,
588 POWER_SUPPLY_PROP_CURRENT_MAX,
589 POWER_SUPPLY_PROP_TYPE,
590 POWER_SUPPLY_PROP_TYPEC_MODE,
591 POWER_SUPPLY_PROP_TYPEC_POWER_ROLE,
592 POWER_SUPPLY_PROP_TYPEC_CC_ORIENTATION,
Harry Yang4b7db0f2017-11-27 10:50:44 -0800593 POWER_SUPPLY_PROP_PD_ACTIVE,
594 POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED,
595 POWER_SUPPLY_PROP_INPUT_CURRENT_NOW,
596 POWER_SUPPLY_PROP_BOOST_CURRENT,
597 POWER_SUPPLY_PROP_PE_START,
598 POWER_SUPPLY_PROP_CTM_CURRENT_MAX,
599 POWER_SUPPLY_PROP_HW_CURRENT_MAX,
600 POWER_SUPPLY_PROP_REAL_TYPE,
601 POWER_SUPPLY_PROP_PR_SWAP,
602 POWER_SUPPLY_PROP_PD_VOLTAGE_MAX,
603 POWER_SUPPLY_PROP_PD_VOLTAGE_MIN,
604 POWER_SUPPLY_PROP_SDP_CURRENT_MAX,
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530605 POWER_SUPPLY_PROP_CONNECTOR_TYPE,
Ashay Jaiswal1f71b412017-10-31 14:33:27 +0530606 POWER_SUPPLY_PROP_VOLTAGE_MAX,
Umang Agrawal9fb865a2018-06-25 16:24:00 +0530607 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
Ashay Jaiswal09feab82018-02-12 12:33:18 +0530608 POWER_SUPPLY_PROP_SCOPE,
Ashay Jaiswal20688262018-04-25 11:45:34 +0530609 POWER_SUPPLY_PROP_VOLTAGE_NOW,
Ashay Jaiswal4d334f42018-04-25 10:58:49 +0530610 POWER_SUPPLY_PROP_HVDCP_OPTI_ALLOWED,
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +0530611 POWER_SUPPLY_PROP_QC_OPTI_DISABLE,
Umang Agrawal461e9ea2018-07-05 18:50:13 +0530612 POWER_SUPPLY_PROP_MOISTURE_DETECTED,
Harry Yang4b7db0f2017-11-27 10:50:44 -0800613};
614
615static int smb5_usb_get_prop(struct power_supply *psy,
616 enum power_supply_property psp,
617 union power_supply_propval *val)
618{
619 struct smb5 *chip = power_supply_get_drvdata(psy);
620 struct smb_charger *chg = &chip->chg;
Ashay Jaiswal09feab82018-02-12 12:33:18 +0530621 union power_supply_propval pval;
Harry Yang4b7db0f2017-11-27 10:50:44 -0800622 int rc = 0;
623
624 switch (psp) {
625 case POWER_SUPPLY_PROP_PRESENT:
626 rc = smblib_get_prop_usb_present(chg, val);
627 break;
628 case POWER_SUPPLY_PROP_ONLINE:
629 rc = smblib_get_prop_usb_online(chg, val);
630 if (!val->intval)
631 break;
632
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530633 if (((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) ||
634 (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB))
635 && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB))
Harry Yang4b7db0f2017-11-27 10:50:44 -0800636 val->intval = 0;
637 else
638 val->intval = 1;
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530639
Harry Yang4b7db0f2017-11-27 10:50:44 -0800640 if (chg->real_charger_type == POWER_SUPPLY_TYPE_UNKNOWN)
641 val->intval = 0;
642 break;
643 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
644 rc = smblib_get_prop_usb_voltage_max(chg, val);
645 break;
Umang Agrawal9fb865a2018-06-25 16:24:00 +0530646 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
647 rc = smblib_get_prop_usb_voltage_max_design(chg, val);
648 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -0800649 case POWER_SUPPLY_PROP_PD_CURRENT_MAX:
650 val->intval = get_client_vote(chg->usb_icl_votable, PD_VOTER);
651 break;
652 case POWER_SUPPLY_PROP_CURRENT_MAX:
653 rc = smblib_get_prop_input_current_settled(chg, val);
654 break;
655 case POWER_SUPPLY_PROP_TYPE:
656 val->intval = POWER_SUPPLY_TYPE_USB_PD;
657 break;
658 case POWER_SUPPLY_PROP_REAL_TYPE:
659 val->intval = chg->real_charger_type;
660 break;
661 case POWER_SUPPLY_PROP_TYPEC_MODE:
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530662 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
Harry Yang4b7db0f2017-11-27 10:50:44 -0800663 val->intval = POWER_SUPPLY_TYPEC_NONE;
664 else
665 val->intval = chg->typec_mode;
666 break;
667 case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE:
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530668 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
Harry Yang4b7db0f2017-11-27 10:50:44 -0800669 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
670 else
671 rc = smblib_get_prop_typec_power_role(chg, val);
672 break;
673 case POWER_SUPPLY_PROP_TYPEC_CC_ORIENTATION:
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530674 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
Harry Yang4b7db0f2017-11-27 10:50:44 -0800675 val->intval = 0;
676 else
677 rc = smblib_get_prop_typec_cc_orientation(chg, val);
678 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -0800679 case POWER_SUPPLY_PROP_PD_ACTIVE:
680 val->intval = chg->pd_active;
681 break;
682 case POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED:
683 rc = smblib_get_prop_input_current_settled(chg, val);
684 break;
685 case POWER_SUPPLY_PROP_BOOST_CURRENT:
686 val->intval = chg->boost_current_ua;
687 break;
688 case POWER_SUPPLY_PROP_PD_IN_HARD_RESET:
689 rc = smblib_get_prop_pd_in_hard_reset(chg, val);
690 break;
691 case POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED:
692 val->intval = chg->system_suspend_supported;
693 break;
694 case POWER_SUPPLY_PROP_PE_START:
695 rc = smblib_get_pe_start(chg, val);
696 break;
697 case POWER_SUPPLY_PROP_CTM_CURRENT_MAX:
698 val->intval = get_client_vote(chg->usb_icl_votable, CTM_VOTER);
699 break;
700 case POWER_SUPPLY_PROP_HW_CURRENT_MAX:
701 rc = smblib_get_charge_current(chg, &val->intval);
702 break;
703 case POWER_SUPPLY_PROP_PR_SWAP:
704 rc = smblib_get_prop_pr_swap_in_progress(chg, val);
705 break;
706 case POWER_SUPPLY_PROP_PD_VOLTAGE_MAX:
707 val->intval = chg->voltage_max_uv;
708 break;
709 case POWER_SUPPLY_PROP_PD_VOLTAGE_MIN:
710 val->intval = chg->voltage_min_uv;
711 break;
712 case POWER_SUPPLY_PROP_SDP_CURRENT_MAX:
713 val->intval = get_client_vote(chg->usb_icl_votable,
714 USB_PSY_VOTER);
715 break;
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530716 case POWER_SUPPLY_PROP_CONNECTOR_TYPE:
717 val->intval = chg->connector_type;
718 break;
Ashay Jaiswal09feab82018-02-12 12:33:18 +0530719 case POWER_SUPPLY_PROP_SCOPE:
720 val->intval = POWER_SUPPLY_SCOPE_UNKNOWN;
721 rc = smblib_get_prop_usb_present(chg, &pval);
722 if (rc < 0)
723 break;
724 val->intval = pval.intval ? POWER_SUPPLY_SCOPE_DEVICE
725 : chg->otg_present ? POWER_SUPPLY_SCOPE_SYSTEM
726 : POWER_SUPPLY_SCOPE_UNKNOWN;
727 break;
Ashay Jaiswal20688262018-04-25 11:45:34 +0530728 case POWER_SUPPLY_PROP_INPUT_CURRENT_NOW:
729 rc = smblib_get_prop_usb_present(chg, &pval);
730 if (rc < 0 || !pval.intval) {
731 val->intval = 0;
732 return rc;
733 }
734 if (chg->smb_version == PMI632_SUBTYPE)
735 rc = smb5_get_adc_data(chg, USBIN_CURRENT, val);
736 break;
737 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
738 if (chg->smb_version == PMI632_SUBTYPE)
739 rc = smb5_get_adc_data(chg, USBIN_VOLTAGE, val);
740 break;
Ashay Jaiswal4d334f42018-04-25 10:58:49 +0530741 case POWER_SUPPLY_PROP_HVDCP_OPTI_ALLOWED:
742 val->intval = !chg->flash_active;
743 break;
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +0530744 case POWER_SUPPLY_PROP_QC_OPTI_DISABLE:
745 if (chg->hw_die_temp_mitigation)
746 val->intval = POWER_SUPPLY_QC_THERMAL_BALANCE_DISABLE
747 | POWER_SUPPLY_QC_INOV_THERMAL_DISABLE;
748 if (chg->hw_connector_mitigation)
749 val->intval |= POWER_SUPPLY_QC_CTM_DISABLE;
750 break;
Umang Agrawal461e9ea2018-07-05 18:50:13 +0530751 case POWER_SUPPLY_PROP_MOISTURE_DETECTED:
752 val->intval = chg->moisture_present;
753 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -0800754 default:
755 pr_err("get prop %d is not supported in usb\n", psp);
756 rc = -EINVAL;
757 break;
758 }
759
760 if (rc < 0) {
761 pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
762 return -ENODATA;
763 }
764
765 return 0;
766}
767
768static int smb5_usb_set_prop(struct power_supply *psy,
769 enum power_supply_property psp,
770 const union power_supply_propval *val)
771{
772 struct smb5 *chip = power_supply_get_drvdata(psy);
773 struct smb_charger *chg = &chip->chg;
774 int rc = 0;
775
Harry Yang4b7db0f2017-11-27 10:50:44 -0800776 switch (psp) {
777 case POWER_SUPPLY_PROP_PD_CURRENT_MAX:
778 rc = smblib_set_prop_pd_current_max(chg, val);
779 break;
780 case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE:
781 rc = smblib_set_prop_typec_power_role(chg, val);
782 break;
783 case POWER_SUPPLY_PROP_PD_ACTIVE:
784 rc = smblib_set_prop_pd_active(chg, val);
785 break;
786 case POWER_SUPPLY_PROP_PD_IN_HARD_RESET:
787 rc = smblib_set_prop_pd_in_hard_reset(chg, val);
788 break;
789 case POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED:
790 chg->system_suspend_supported = val->intval;
791 break;
792 case POWER_SUPPLY_PROP_BOOST_CURRENT:
793 rc = smblib_set_prop_boost_current(chg, val);
794 break;
795 case POWER_SUPPLY_PROP_CTM_CURRENT_MAX:
796 rc = vote(chg->usb_icl_votable, CTM_VOTER,
797 val->intval >= 0, val->intval);
798 break;
799 case POWER_SUPPLY_PROP_PR_SWAP:
800 rc = smblib_set_prop_pr_swap_in_progress(chg, val);
801 break;
802 case POWER_SUPPLY_PROP_PD_VOLTAGE_MAX:
803 rc = smblib_set_prop_pd_voltage_max(chg, val);
804 break;
805 case POWER_SUPPLY_PROP_PD_VOLTAGE_MIN:
806 rc = smblib_set_prop_pd_voltage_min(chg, val);
807 break;
808 case POWER_SUPPLY_PROP_SDP_CURRENT_MAX:
809 rc = smblib_set_prop_sdp_current_max(chg, val);
810 break;
811 default:
812 pr_err("set prop %d is not supported\n", psp);
813 rc = -EINVAL;
814 break;
815 }
816
Harry Yang4b7db0f2017-11-27 10:50:44 -0800817 return rc;
818}
819
820static int smb5_usb_prop_is_writeable(struct power_supply *psy,
821 enum power_supply_property psp)
822{
823 switch (psp) {
824 case POWER_SUPPLY_PROP_CTM_CURRENT_MAX:
825 return 1;
826 default:
827 break;
828 }
829
830 return 0;
831}
832
833static const struct power_supply_desc usb_psy_desc = {
834 .name = "usb",
835 .type = POWER_SUPPLY_TYPE_USB_PD,
836 .properties = smb5_usb_props,
837 .num_properties = ARRAY_SIZE(smb5_usb_props),
838 .get_property = smb5_usb_get_prop,
839 .set_property = smb5_usb_set_prop,
840 .property_is_writeable = smb5_usb_prop_is_writeable,
841};
842
843static int smb5_init_usb_psy(struct smb5 *chip)
844{
845 struct power_supply_config usb_cfg = {};
846 struct smb_charger *chg = &chip->chg;
847
848 usb_cfg.drv_data = chip;
849 usb_cfg.of_node = chg->dev->of_node;
850 chg->usb_psy = devm_power_supply_register(chg->dev,
851 &usb_psy_desc,
852 &usb_cfg);
853 if (IS_ERR(chg->usb_psy)) {
854 pr_err("Couldn't register USB power supply\n");
855 return PTR_ERR(chg->usb_psy);
856 }
857
858 return 0;
859}
860
861/********************************
862 * USB PC_PORT PSY REGISTRATION *
863 ********************************/
864static enum power_supply_property smb5_usb_port_props[] = {
865 POWER_SUPPLY_PROP_TYPE,
866 POWER_SUPPLY_PROP_ONLINE,
867 POWER_SUPPLY_PROP_VOLTAGE_MAX,
868 POWER_SUPPLY_PROP_CURRENT_MAX,
869};
870
871static int smb5_usb_port_get_prop(struct power_supply *psy,
872 enum power_supply_property psp,
873 union power_supply_propval *val)
874{
875 struct smb5 *chip = power_supply_get_drvdata(psy);
876 struct smb_charger *chg = &chip->chg;
877 int rc = 0;
878
879 switch (psp) {
880 case POWER_SUPPLY_PROP_TYPE:
881 val->intval = POWER_SUPPLY_TYPE_USB;
882 break;
883 case POWER_SUPPLY_PROP_ONLINE:
884 rc = smblib_get_prop_usb_online(chg, val);
885 if (!val->intval)
886 break;
887
Ashay Jaiswala9e10912018-02-02 14:03:35 +0530888 if (((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) ||
889 (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB))
890 && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB))
Harry Yang4b7db0f2017-11-27 10:50:44 -0800891 val->intval = 1;
892 else
893 val->intval = 0;
894 break;
895 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
896 val->intval = 5000000;
897 break;
898 case POWER_SUPPLY_PROP_CURRENT_MAX:
899 rc = smblib_get_prop_input_current_settled(chg, val);
900 break;
901 default:
902 pr_err_ratelimited("Get prop %d is not supported in pc_port\n",
903 psp);
904 return -EINVAL;
905 }
906
907 if (rc < 0) {
908 pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
909 return -ENODATA;
910 }
911
912 return 0;
913}
914
915static int smb5_usb_port_set_prop(struct power_supply *psy,
916 enum power_supply_property psp,
917 const union power_supply_propval *val)
918{
919 int rc = 0;
920
921 switch (psp) {
922 default:
923 pr_err_ratelimited("Set prop %d is not supported in pc_port\n",
924 psp);
925 rc = -EINVAL;
926 break;
927 }
928
929 return rc;
930}
931
932static const struct power_supply_desc usb_port_psy_desc = {
933 .name = "pc_port",
934 .type = POWER_SUPPLY_TYPE_USB,
935 .properties = smb5_usb_port_props,
936 .num_properties = ARRAY_SIZE(smb5_usb_port_props),
937 .get_property = smb5_usb_port_get_prop,
938 .set_property = smb5_usb_port_set_prop,
939};
940
941static int smb5_init_usb_port_psy(struct smb5 *chip)
942{
943 struct power_supply_config usb_port_cfg = {};
944 struct smb_charger *chg = &chip->chg;
945
946 usb_port_cfg.drv_data = chip;
947 usb_port_cfg.of_node = chg->dev->of_node;
948 chg->usb_port_psy = devm_power_supply_register(chg->dev,
949 &usb_port_psy_desc,
950 &usb_port_cfg);
951 if (IS_ERR(chg->usb_port_psy)) {
952 pr_err("Couldn't register USB pc_port power supply\n");
953 return PTR_ERR(chg->usb_port_psy);
954 }
955
956 return 0;
957}
958
959/*****************************
960 * USB MAIN PSY REGISTRATION *
961 *****************************/
962
963static enum power_supply_property smb5_usb_main_props[] = {
964 POWER_SUPPLY_PROP_VOLTAGE_MAX,
965 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
966 POWER_SUPPLY_PROP_TYPE,
967 POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED,
968 POWER_SUPPLY_PROP_INPUT_VOLTAGE_SETTLED,
969 POWER_SUPPLY_PROP_FCC_DELTA,
970 POWER_SUPPLY_PROP_CURRENT_MAX,
Ashay Jaiswal09feab82018-02-12 12:33:18 +0530971 POWER_SUPPLY_PROP_FLASH_ACTIVE,
972 POWER_SUPPLY_PROP_FLASH_TRIGGER,
Harry Yang4b7db0f2017-11-27 10:50:44 -0800973};
974
975static int smb5_usb_main_get_prop(struct power_supply *psy,
976 enum power_supply_property psp,
977 union power_supply_propval *val)
978{
979 struct smb5 *chip = power_supply_get_drvdata(psy);
980 struct smb_charger *chg = &chip->chg;
981 int rc = 0;
982
983 switch (psp) {
984 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
985 rc = smblib_get_charge_param(chg, &chg->param.fv, &val->intval);
986 break;
987 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
988 rc = smblib_get_charge_param(chg, &chg->param.fcc,
989 &val->intval);
990 break;
991 case POWER_SUPPLY_PROP_TYPE:
992 val->intval = POWER_SUPPLY_TYPE_MAIN;
993 break;
994 case POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED:
995 rc = smblib_get_prop_input_current_settled(chg, val);
996 break;
997 case POWER_SUPPLY_PROP_INPUT_VOLTAGE_SETTLED:
998 rc = smblib_get_prop_input_voltage_settled(chg, val);
999 break;
1000 case POWER_SUPPLY_PROP_FCC_DELTA:
1001 rc = smblib_get_prop_fcc_delta(chg, val);
1002 break;
1003 case POWER_SUPPLY_PROP_CURRENT_MAX:
1004 rc = smblib_get_icl_current(chg, &val->intval);
1005 break;
Ashay Jaiswal09feab82018-02-12 12:33:18 +05301006 case POWER_SUPPLY_PROP_FLASH_ACTIVE:
1007 val->intval = chg->flash_active;
1008 break;
1009 case POWER_SUPPLY_PROP_FLASH_TRIGGER:
1010 rc = schgm_flash_get_vreg_ok(chg, &val->intval);
1011 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001012 default:
1013 pr_debug("get prop %d is not supported in usb-main\n", psp);
1014 rc = -EINVAL;
1015 break;
1016 }
1017 if (rc < 0) {
1018 pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
1019 return -ENODATA;
1020 }
1021
1022 return 0;
1023}
1024
1025static int smb5_usb_main_set_prop(struct power_supply *psy,
1026 enum power_supply_property psp,
1027 const union power_supply_propval *val)
1028{
1029 struct smb5 *chip = power_supply_get_drvdata(psy);
1030 struct smb_charger *chg = &chip->chg;
Ashay Jaiswal4d334f42018-04-25 10:58:49 +05301031 union power_supply_propval pval = {0, };
Harry Yang4b7db0f2017-11-27 10:50:44 -08001032 int rc = 0;
1033
1034 switch (psp) {
1035 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
1036 rc = smblib_set_charge_param(chg, &chg->param.fv, val->intval);
1037 break;
1038 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
1039 rc = smblib_set_charge_param(chg, &chg->param.fcc, val->intval);
1040 break;
1041 case POWER_SUPPLY_PROP_CURRENT_MAX:
1042 rc = smblib_set_icl_current(chg, val->intval);
1043 break;
Ashay Jaiswal09feab82018-02-12 12:33:18 +05301044 case POWER_SUPPLY_PROP_FLASH_ACTIVE:
Ashay Jaiswal4d334f42018-04-25 10:58:49 +05301045 if ((chg->smb_version == PMI632_SUBTYPE)
1046 && (chg->flash_active != val->intval)) {
1047 chg->flash_active = val->intval;
1048
1049 rc = smblib_get_prop_usb_present(chg, &pval);
1050 if (rc < 0)
1051 pr_err("Failed to get USB preset status rc=%d\n",
1052 rc);
1053 if (pval.intval) {
1054 rc = smblib_force_vbus_voltage(chg,
1055 chg->flash_active ? FORCE_5V_BIT
1056 : IDLE_BIT);
1057 if (rc < 0)
1058 pr_err("Failed to force 5V\n");
1059 else
1060 chg->pulse_cnt = 0;
Anirudh Ghayal4d5cddc2018-06-28 15:19:39 +05301061 } else {
1062 /* USB absent & flash not-active - vote 100mA */
1063 vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER,
1064 true, SDP_100_MA);
Ashay Jaiswal4d334f42018-04-25 10:58:49 +05301065 }
1066
1067 pr_debug("flash active VBUS 5V restriction %s\n",
1068 chg->flash_active ? "applied" : "removed");
1069
1070 /* Update userspace */
1071 if (chg->batt_psy)
1072 power_supply_changed(chg->batt_psy);
1073 }
Ashay Jaiswal09feab82018-02-12 12:33:18 +05301074 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001075 default:
1076 pr_err("set prop %d is not supported\n", psp);
1077 rc = -EINVAL;
1078 break;
1079 }
1080
1081 return rc;
1082}
1083
1084static const struct power_supply_desc usb_main_psy_desc = {
1085 .name = "main",
1086 .type = POWER_SUPPLY_TYPE_MAIN,
1087 .properties = smb5_usb_main_props,
1088 .num_properties = ARRAY_SIZE(smb5_usb_main_props),
1089 .get_property = smb5_usb_main_get_prop,
1090 .set_property = smb5_usb_main_set_prop,
1091};
1092
1093static int smb5_init_usb_main_psy(struct smb5 *chip)
1094{
1095 struct power_supply_config usb_main_cfg = {};
1096 struct smb_charger *chg = &chip->chg;
1097
1098 usb_main_cfg.drv_data = chip;
1099 usb_main_cfg.of_node = chg->dev->of_node;
1100 chg->usb_main_psy = devm_power_supply_register(chg->dev,
1101 &usb_main_psy_desc,
1102 &usb_main_cfg);
1103 if (IS_ERR(chg->usb_main_psy)) {
1104 pr_err("Couldn't register USB main power supply\n");
1105 return PTR_ERR(chg->usb_main_psy);
1106 }
1107
1108 return 0;
1109}
1110
1111/*************************
1112 * DC PSY REGISTRATION *
1113 *************************/
1114
1115static enum power_supply_property smb5_dc_props[] = {
1116 POWER_SUPPLY_PROP_INPUT_SUSPEND,
1117 POWER_SUPPLY_PROP_PRESENT,
1118 POWER_SUPPLY_PROP_ONLINE,
1119 POWER_SUPPLY_PROP_REAL_TYPE,
1120};
1121
1122static int smb5_dc_get_prop(struct power_supply *psy,
1123 enum power_supply_property psp,
1124 union power_supply_propval *val)
1125{
1126 struct smb5 *chip = power_supply_get_drvdata(psy);
1127 struct smb_charger *chg = &chip->chg;
1128 int rc = 0;
1129
1130 switch (psp) {
1131 case POWER_SUPPLY_PROP_INPUT_SUSPEND:
1132 val->intval = get_effective_result(chg->dc_suspend_votable);
1133 break;
1134 case POWER_SUPPLY_PROP_PRESENT:
1135 rc = smblib_get_prop_dc_present(chg, val);
1136 break;
1137 case POWER_SUPPLY_PROP_ONLINE:
1138 rc = smblib_get_prop_dc_online(chg, val);
1139 break;
1140 case POWER_SUPPLY_PROP_REAL_TYPE:
1141 val->intval = POWER_SUPPLY_TYPE_WIPOWER;
1142 break;
1143 default:
1144 return -EINVAL;
1145 }
1146 if (rc < 0) {
1147 pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
1148 return -ENODATA;
1149 }
1150 return 0;
1151}
1152
1153static int smb5_dc_set_prop(struct power_supply *psy,
1154 enum power_supply_property psp,
1155 const union power_supply_propval *val)
1156{
1157 struct smb5 *chip = power_supply_get_drvdata(psy);
1158 struct smb_charger *chg = &chip->chg;
1159 int rc = 0;
1160
1161 switch (psp) {
1162 case POWER_SUPPLY_PROP_INPUT_SUSPEND:
1163 rc = vote(chg->dc_suspend_votable, WBC_VOTER,
1164 (bool)val->intval, 0);
1165 break;
1166 default:
1167 return -EINVAL;
1168 }
1169
1170 return rc;
1171}
1172
1173static int smb5_dc_prop_is_writeable(struct power_supply *psy,
1174 enum power_supply_property psp)
1175{
1176 int rc;
1177
1178 switch (psp) {
1179 default:
1180 rc = 0;
1181 break;
1182 }
1183
1184 return rc;
1185}
1186
1187static const struct power_supply_desc dc_psy_desc = {
1188 .name = "dc",
1189 .type = POWER_SUPPLY_TYPE_WIRELESS,
1190 .properties = smb5_dc_props,
1191 .num_properties = ARRAY_SIZE(smb5_dc_props),
1192 .get_property = smb5_dc_get_prop,
1193 .set_property = smb5_dc_set_prop,
1194 .property_is_writeable = smb5_dc_prop_is_writeable,
1195};
1196
1197static int smb5_init_dc_psy(struct smb5 *chip)
1198{
1199 struct power_supply_config dc_cfg = {};
1200 struct smb_charger *chg = &chip->chg;
1201
1202 dc_cfg.drv_data = chip;
1203 dc_cfg.of_node = chg->dev->of_node;
1204 chg->dc_psy = devm_power_supply_register(chg->dev,
1205 &dc_psy_desc,
1206 &dc_cfg);
1207 if (IS_ERR(chg->dc_psy)) {
1208 pr_err("Couldn't register USB power supply\n");
1209 return PTR_ERR(chg->dc_psy);
1210 }
1211
1212 return 0;
1213}
1214
1215/*************************
1216 * BATT PSY REGISTRATION *
1217 *************************/
1218static enum power_supply_property smb5_batt_props[] = {
1219 POWER_SUPPLY_PROP_INPUT_SUSPEND,
Anirudh Ghayaldfdb8412018-04-21 10:37:18 +05301220 POWER_SUPPLY_PROP_BATTERY_CHARGING_ENABLED,
Harry Yang4b7db0f2017-11-27 10:50:44 -08001221 POWER_SUPPLY_PROP_STATUS,
1222 POWER_SUPPLY_PROP_HEALTH,
1223 POWER_SUPPLY_PROP_PRESENT,
1224 POWER_SUPPLY_PROP_CHARGE_TYPE,
1225 POWER_SUPPLY_PROP_CAPACITY,
1226 POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
1227 POWER_SUPPLY_PROP_VOLTAGE_NOW,
1228 POWER_SUPPLY_PROP_VOLTAGE_MAX,
1229 POWER_SUPPLY_PROP_CURRENT_NOW,
1230 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
1231 POWER_SUPPLY_PROP_TEMP,
1232 POWER_SUPPLY_PROP_TECHNOLOGY,
1233 POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED,
1234 POWER_SUPPLY_PROP_SW_JEITA_ENABLED,
1235 POWER_SUPPLY_PROP_CHARGE_DONE,
1236 POWER_SUPPLY_PROP_PARALLEL_DISABLE,
1237 POWER_SUPPLY_PROP_SET_SHIP_MODE,
1238 POWER_SUPPLY_PROP_DIE_HEALTH,
1239 POWER_SUPPLY_PROP_RERUN_AICL,
1240 POWER_SUPPLY_PROP_DP_DM,
1241 POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
1242 POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
1243 POWER_SUPPLY_PROP_CHARGE_COUNTER,
Subbaraman Narayanamurthyc4feb892018-05-07 18:43:45 -07001244 POWER_SUPPLY_PROP_CYCLE_COUNT,
Anirudh Ghayal1380d312018-02-23 00:01:43 +05301245 POWER_SUPPLY_PROP_RECHARGE_SOC,
Harry Yang4b7db0f2017-11-27 10:50:44 -08001246};
1247
1248static int smb5_batt_get_prop(struct power_supply *psy,
1249 enum power_supply_property psp,
1250 union power_supply_propval *val)
1251{
1252 struct smb_charger *chg = power_supply_get_drvdata(psy);
1253 int rc = 0;
1254
1255 switch (psp) {
1256 case POWER_SUPPLY_PROP_STATUS:
1257 rc = smblib_get_prop_batt_status(chg, val);
1258 break;
1259 case POWER_SUPPLY_PROP_HEALTH:
1260 rc = smblib_get_prop_batt_health(chg, val);
1261 break;
1262 case POWER_SUPPLY_PROP_PRESENT:
1263 rc = smblib_get_prop_batt_present(chg, val);
1264 break;
1265 case POWER_SUPPLY_PROP_INPUT_SUSPEND:
1266 rc = smblib_get_prop_input_suspend(chg, val);
1267 break;
Anirudh Ghayaldfdb8412018-04-21 10:37:18 +05301268 case POWER_SUPPLY_PROP_BATTERY_CHARGING_ENABLED:
1269 val->intval = !get_client_vote(chg->chg_disable_votable,
1270 USER_VOTER);
1271 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001272 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1273 rc = smblib_get_prop_batt_charge_type(chg, val);
1274 break;
1275 case POWER_SUPPLY_PROP_CAPACITY:
1276 rc = smblib_get_prop_batt_capacity(chg, val);
1277 break;
1278 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
1279 rc = smblib_get_prop_system_temp_level(chg, val);
1280 break;
1281 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX:
1282 rc = smblib_get_prop_system_temp_level_max(chg, val);
1283 break;
1284 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
1285 rc = smblib_get_prop_input_current_limited(chg, val);
1286 break;
1287 case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
1288 val->intval = chg->step_chg_enabled;
1289 break;
1290 case POWER_SUPPLY_PROP_SW_JEITA_ENABLED:
1291 val->intval = chg->sw_jeita_enabled;
1292 break;
1293 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
1294 rc = smblib_get_prop_batt_voltage_now(chg, val);
1295 break;
1296 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
1297 val->intval = get_client_vote(chg->fv_votable,
1298 BATT_PROFILE_VOTER);
1299 break;
1300 case POWER_SUPPLY_PROP_CURRENT_NOW:
1301 rc = smblib_get_prop_batt_current_now(chg, val);
1302 break;
1303 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
1304 val->intval = get_client_vote(chg->fcc_votable,
1305 BATT_PROFILE_VOTER);
1306 break;
1307 case POWER_SUPPLY_PROP_TEMP:
1308 rc = smblib_get_prop_batt_temp(chg, val);
1309 break;
1310 case POWER_SUPPLY_PROP_TECHNOLOGY:
1311 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1312 break;
1313 case POWER_SUPPLY_PROP_CHARGE_DONE:
1314 rc = smblib_get_prop_batt_charge_done(chg, val);
1315 break;
1316 case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
1317 val->intval = get_client_vote(chg->pl_disable_votable,
1318 USER_VOTER);
1319 break;
1320 case POWER_SUPPLY_PROP_SET_SHIP_MODE:
1321 /* Not in ship mode as long as device is active */
1322 val->intval = 0;
1323 break;
1324 case POWER_SUPPLY_PROP_DIE_HEALTH:
1325 if (chg->die_health == -EINVAL)
1326 rc = smblib_get_prop_die_health(chg, val);
1327 else
1328 val->intval = chg->die_health;
1329 break;
1330 case POWER_SUPPLY_PROP_DP_DM:
1331 val->intval = chg->pulse_cnt;
1332 break;
1333 case POWER_SUPPLY_PROP_RERUN_AICL:
1334 val->intval = 0;
1335 break;
1336 case POWER_SUPPLY_PROP_CHARGE_COUNTER:
1337 rc = smblib_get_prop_batt_charge_counter(chg, val);
1338 break;
Subbaraman Narayanamurthyc4feb892018-05-07 18:43:45 -07001339 case POWER_SUPPLY_PROP_CYCLE_COUNT:
1340 rc = smblib_get_prop_batt_cycle_count(chg, val);
1341 break;
Anirudh Ghayal1380d312018-02-23 00:01:43 +05301342 case POWER_SUPPLY_PROP_RECHARGE_SOC:
1343 val->intval = chg->auto_recharge_soc;
1344 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001345 default:
1346 pr_err("batt power supply prop %d not supported\n", psp);
1347 return -EINVAL;
1348 }
1349
1350 if (rc < 0) {
1351 pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
1352 return -ENODATA;
1353 }
1354
1355 return 0;
1356}
1357
1358static int smb5_batt_set_prop(struct power_supply *psy,
1359 enum power_supply_property prop,
1360 const union power_supply_propval *val)
1361{
1362 int rc = 0;
1363 struct smb_charger *chg = power_supply_get_drvdata(psy);
Ashay Jaiswala55b7ed2018-03-23 17:23:48 +05301364 bool enable;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001365
1366 switch (prop) {
1367 case POWER_SUPPLY_PROP_STATUS:
1368 rc = smblib_set_prop_batt_status(chg, val);
1369 break;
1370 case POWER_SUPPLY_PROP_INPUT_SUSPEND:
1371 rc = smblib_set_prop_input_suspend(chg, val);
1372 break;
Anirudh Ghayaldfdb8412018-04-21 10:37:18 +05301373 case POWER_SUPPLY_PROP_BATTERY_CHARGING_ENABLED:
1374 vote(chg->chg_disable_votable, USER_VOTER, !val->intval, 0);
1375 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001376 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
1377 rc = smblib_set_prop_system_temp_level(chg, val);
1378 break;
1379 case POWER_SUPPLY_PROP_CAPACITY:
1380 rc = smblib_set_prop_batt_capacity(chg, val);
1381 break;
1382 case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
1383 vote(chg->pl_disable_votable, USER_VOTER, (bool)val->intval, 0);
1384 break;
1385 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
1386 chg->batt_profile_fv_uv = val->intval;
1387 vote(chg->fv_votable, BATT_PROFILE_VOTER, true, val->intval);
1388 break;
1389 case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
Ashay Jaiswala55b7ed2018-03-23 17:23:48 +05301390 enable = !!val->intval || chg->sw_jeita_enabled;
1391 rc = smblib_configure_wdog(chg, enable);
1392 if (rc == 0)
1393 chg->step_chg_enabled = !!val->intval;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001394 break;
1395 case POWER_SUPPLY_PROP_SW_JEITA_ENABLED:
1396 if (chg->sw_jeita_enabled != (!!val->intval)) {
1397 rc = smblib_disable_hw_jeita(chg, !!val->intval);
Ashay Jaiswala55b7ed2018-03-23 17:23:48 +05301398 enable = !!val->intval || chg->step_chg_enabled;
1399 rc |= smblib_configure_wdog(chg, enable);
Harry Yang4b7db0f2017-11-27 10:50:44 -08001400 if (rc == 0)
1401 chg->sw_jeita_enabled = !!val->intval;
1402 }
1403 break;
1404 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
1405 chg->batt_profile_fcc_ua = val->intval;
1406 vote(chg->fcc_votable, BATT_PROFILE_VOTER, true, val->intval);
1407 break;
1408 case POWER_SUPPLY_PROP_SET_SHIP_MODE:
1409 /* Not in ship mode as long as the device is active */
1410 if (!val->intval)
1411 break;
1412 if (chg->pl.psy)
1413 power_supply_set_property(chg->pl.psy,
1414 POWER_SUPPLY_PROP_SET_SHIP_MODE, val);
1415 rc = smblib_set_prop_ship_mode(chg, val);
1416 break;
1417 case POWER_SUPPLY_PROP_RERUN_AICL:
Ashay Jaiswale0b3c472018-06-20 23:39:41 +05301418 rc = smblib_run_aicl(chg, RERUN_AICL);
Harry Yang4b7db0f2017-11-27 10:50:44 -08001419 break;
1420 case POWER_SUPPLY_PROP_DP_DM:
Ashay Jaiswal4d334f42018-04-25 10:58:49 +05301421 if (!chg->flash_active)
1422 rc = smblib_dp_dm(chg, val->intval);
Harry Yang4b7db0f2017-11-27 10:50:44 -08001423 break;
1424 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
1425 rc = smblib_set_prop_input_current_limited(chg, val);
1426 break;
1427 case POWER_SUPPLY_PROP_DIE_HEALTH:
1428 chg->die_health = val->intval;
1429 power_supply_changed(chg->batt_psy);
1430 break;
Anirudh Ghayaldfdb8412018-04-21 10:37:18 +05301431 case POWER_SUPPLY_PROP_RECHARGE_SOC:
1432 if (chg->smb_version == PMI632_SUBTYPE) {
1433 /* toggle charging to force recharge */
1434 vote(chg->chg_disable_votable, FORCE_RECHARGE_VOTER,
1435 true, 0);
1436 /* charge disable delay */
1437 msleep(50);
1438 vote(chg->chg_disable_votable, FORCE_RECHARGE_VOTER,
1439 false, 0);
1440 }
1441 break;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001442 default:
1443 rc = -EINVAL;
1444 }
1445
1446 return rc;
1447}
1448
1449static int smb5_batt_prop_is_writeable(struct power_supply *psy,
1450 enum power_supply_property psp)
1451{
1452 switch (psp) {
1453 case POWER_SUPPLY_PROP_STATUS:
1454 case POWER_SUPPLY_PROP_INPUT_SUSPEND:
1455 case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL:
1456 case POWER_SUPPLY_PROP_CAPACITY:
1457 case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
1458 case POWER_SUPPLY_PROP_DP_DM:
1459 case POWER_SUPPLY_PROP_RERUN_AICL:
1460 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
1461 case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
1462 case POWER_SUPPLY_PROP_SW_JEITA_ENABLED:
1463 case POWER_SUPPLY_PROP_DIE_HEALTH:
Anirudh Ghayaldfdb8412018-04-21 10:37:18 +05301464 case POWER_SUPPLY_PROP_BATTERY_CHARGING_ENABLED:
Harry Yang4b7db0f2017-11-27 10:50:44 -08001465 return 1;
1466 default:
1467 break;
1468 }
1469
1470 return 0;
1471}
1472
1473static const struct power_supply_desc batt_psy_desc = {
1474 .name = "battery",
1475 .type = POWER_SUPPLY_TYPE_BATTERY,
1476 .properties = smb5_batt_props,
1477 .num_properties = ARRAY_SIZE(smb5_batt_props),
1478 .get_property = smb5_batt_get_prop,
1479 .set_property = smb5_batt_set_prop,
1480 .property_is_writeable = smb5_batt_prop_is_writeable,
1481};
1482
1483static int smb5_init_batt_psy(struct smb5 *chip)
1484{
1485 struct power_supply_config batt_cfg = {};
1486 struct smb_charger *chg = &chip->chg;
1487 int rc = 0;
1488
1489 batt_cfg.drv_data = chg;
1490 batt_cfg.of_node = chg->dev->of_node;
1491 chg->batt_psy = devm_power_supply_register(chg->dev,
1492 &batt_psy_desc,
1493 &batt_cfg);
1494 if (IS_ERR(chg->batt_psy)) {
1495 pr_err("Couldn't register battery power supply\n");
1496 return PTR_ERR(chg->batt_psy);
1497 }
1498
1499 return rc;
1500}
1501
1502/******************************
1503 * VBUS REGULATOR REGISTRATION *
1504 ******************************/
1505
1506static struct regulator_ops smb5_vbus_reg_ops = {
1507 .enable = smblib_vbus_regulator_enable,
1508 .disable = smblib_vbus_regulator_disable,
1509 .is_enabled = smblib_vbus_regulator_is_enabled,
1510};
1511
1512static int smb5_init_vbus_regulator(struct smb5 *chip)
1513{
1514 struct smb_charger *chg = &chip->chg;
1515 struct regulator_config cfg = {};
1516 int rc = 0;
1517
1518 chg->vbus_vreg = devm_kzalloc(chg->dev, sizeof(*chg->vbus_vreg),
1519 GFP_KERNEL);
1520 if (!chg->vbus_vreg)
1521 return -ENOMEM;
1522
1523 cfg.dev = chg->dev;
1524 cfg.driver_data = chip;
1525
1526 chg->vbus_vreg->rdesc.owner = THIS_MODULE;
1527 chg->vbus_vreg->rdesc.type = REGULATOR_VOLTAGE;
1528 chg->vbus_vreg->rdesc.ops = &smb5_vbus_reg_ops;
1529 chg->vbus_vreg->rdesc.of_match = "qcom,smb5-vbus";
1530 chg->vbus_vreg->rdesc.name = "qcom,smb5-vbus";
1531
1532 chg->vbus_vreg->rdev = devm_regulator_register(chg->dev,
1533 &chg->vbus_vreg->rdesc, &cfg);
1534 if (IS_ERR(chg->vbus_vreg->rdev)) {
1535 rc = PTR_ERR(chg->vbus_vreg->rdev);
1536 chg->vbus_vreg->rdev = NULL;
1537 if (rc != -EPROBE_DEFER)
1538 pr_err("Couldn't register VBUS regulator rc=%d\n", rc);
1539 }
1540
1541 return rc;
1542}
1543
1544/******************************
1545 * VCONN REGULATOR REGISTRATION *
1546 ******************************/
1547
1548static struct regulator_ops smb5_vconn_reg_ops = {
1549 .enable = smblib_vconn_regulator_enable,
1550 .disable = smblib_vconn_regulator_disable,
1551 .is_enabled = smblib_vconn_regulator_is_enabled,
1552};
1553
1554static int smb5_init_vconn_regulator(struct smb5 *chip)
1555{
1556 struct smb_charger *chg = &chip->chg;
1557 struct regulator_config cfg = {};
1558 int rc = 0;
1559
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301560 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
Harry Yang4b7db0f2017-11-27 10:50:44 -08001561 return 0;
1562
1563 chg->vconn_vreg = devm_kzalloc(chg->dev, sizeof(*chg->vconn_vreg),
1564 GFP_KERNEL);
1565 if (!chg->vconn_vreg)
1566 return -ENOMEM;
1567
1568 cfg.dev = chg->dev;
1569 cfg.driver_data = chip;
1570
1571 chg->vconn_vreg->rdesc.owner = THIS_MODULE;
1572 chg->vconn_vreg->rdesc.type = REGULATOR_VOLTAGE;
1573 chg->vconn_vreg->rdesc.ops = &smb5_vconn_reg_ops;
1574 chg->vconn_vreg->rdesc.of_match = "qcom,smb5-vconn";
1575 chg->vconn_vreg->rdesc.name = "qcom,smb5-vconn";
1576
1577 chg->vconn_vreg->rdev = devm_regulator_register(chg->dev,
1578 &chg->vconn_vreg->rdesc, &cfg);
1579 if (IS_ERR(chg->vconn_vreg->rdev)) {
1580 rc = PTR_ERR(chg->vconn_vreg->rdev);
1581 chg->vconn_vreg->rdev = NULL;
1582 if (rc != -EPROBE_DEFER)
1583 pr_err("Couldn't register VCONN regulator rc=%d\n", rc);
1584 }
1585
1586 return rc;
1587}
1588
1589/***************************
1590 * HARDWARE INITIALIZATION *
1591 ***************************/
1592static int smb5_configure_typec(struct smb_charger *chg)
1593{
1594 int rc;
Ashay Jaiswal91d63f42018-05-16 11:30:40 +05301595 u8 val = 0;
1596
1597 rc = smblib_read(chg, LEGACY_CABLE_STATUS_REG, &val);
1598 if (rc < 0) {
1599 dev_err(chg->dev, "Couldn't read Legacy status rc=%d\n", rc);
1600 return rc;
1601 }
1602 /*
1603 * If Legacy cable is detected re-trigger Legacy detection
1604 * by disabling/enabling typeC mode.
1605 */
1606 if (val & TYPEC_LEGACY_CABLE_STATUS_BIT) {
1607 rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
1608 TYPEC_DISABLE_CMD_BIT, TYPEC_DISABLE_CMD_BIT);
1609 if (rc < 0) {
1610 dev_err(chg->dev, "Couldn't disable TYPEC rc=%d\n", rc);
1611 return rc;
1612 }
1613
1614 /* delay before enabling typeC */
1615 msleep(500);
1616
1617 rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
1618 TYPEC_DISABLE_CMD_BIT, 0);
1619 if (rc < 0) {
1620 dev_err(chg->dev, "Couldn't enable TYPEC rc=%d\n", rc);
1621 return rc;
1622 }
1623 }
Harry Yang4b7db0f2017-11-27 10:50:44 -08001624
Harry Yang6afaea22018-03-26 19:11:07 -07001625 /* disable apsd */
Ashay Jaiswalc96380de2018-05-16 12:02:36 +05301626 rc = smblib_configure_hvdcp_apsd(chg, false);
Harry Yang6afaea22018-03-26 19:11:07 -07001627 if (rc < 0) {
1628 dev_err(chg->dev, "Couldn't disable APSD rc=%d\n", rc);
1629 return rc;
1630 }
1631
Harry Yang4b7db0f2017-11-27 10:50:44 -08001632 rc = smblib_write(chg, TYPE_C_INTERRUPT_EN_CFG_1_REG,
1633 TYPEC_CCOUT_DETACH_INT_EN_BIT |
1634 TYPEC_CCOUT_ATTACH_INT_EN_BIT);
1635 if (rc < 0) {
1636 dev_err(chg->dev,
1637 "Couldn't configure Type-C interrupts rc=%d\n", rc);
1638 return rc;
1639 }
1640
Harry Yang423d5c32018-05-30 15:49:04 -07001641 rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
1642 EN_TRY_SNK_BIT, EN_TRY_SNK_BIT);
1643 if (rc < 0) {
1644 dev_err(chg->dev,
1645 "Couldn't enable try.snk rc=%d\n", rc);
1646 return rc;
1647 }
1648
Ashay Jaiswald5022b62018-05-27 19:21:11 +05301649 /* Keep VCONN in h/w controlled mode for PMI632 */
1650 if (chg->smb_version != PMI632_SUBTYPE) {
1651 /* configure VCONN for software control */
1652 rc = smblib_masked_write(chg, TYPE_C_VCONN_CONTROL_REG,
Harry Yang4b7db0f2017-11-27 10:50:44 -08001653 VCONN_EN_SRC_BIT | VCONN_EN_VALUE_BIT,
1654 VCONN_EN_SRC_BIT);
Ashay Jaiswald5022b62018-05-27 19:21:11 +05301655 if (rc < 0) {
1656 dev_err(chg->dev,
1657 "Couldn't configure VCONN for SW control rc=%d\n",
1658 rc);
1659 return rc;
1660 }
Harry Yang4b7db0f2017-11-27 10:50:44 -08001661 }
1662
1663 return rc;
1664}
1665
1666static int smb5_configure_micro_usb(struct smb_charger *chg)
1667{
1668 int rc;
1669
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301670 rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG,
1671 MICRO_USB_STATE_CHANGE_INT_EN_BIT,
1672 MICRO_USB_STATE_CHANGE_INT_EN_BIT);
1673 if (rc < 0) {
1674 dev_err(chg->dev,
1675 "Couldn't configure Type-C interrupts rc=%d\n", rc);
1676 return rc;
1677 }
1678
Umang Agrawal461e9ea2018-07-05 18:50:13 +05301679 if (chg->moisture_protection_enabled &&
1680 (chg->wa_flags & MOISTURE_PROTECTION_WA)) {
1681 /* Enable moisture detection interrupt */
1682 rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG,
1683 TYPEC_WATER_DETECTION_INT_EN_BIT,
1684 TYPEC_WATER_DETECTION_INT_EN_BIT);
1685 if (rc < 0) {
1686 dev_err(chg->dev, "Couldn't enable moisture detection interrupt rc=%d\n",
1687 rc);
1688 return rc;
1689 }
1690
1691 /* Enable uUSB factory mode */
1692 rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG,
1693 EN_MICRO_USB_FACTORY_MODE_BIT,
1694 EN_MICRO_USB_FACTORY_MODE_BIT);
1695 if (rc < 0) {
1696 dev_err(chg->dev, "Couldn't enable uUSB factory mode c=%d\n",
1697 rc);
1698 return rc;
1699 }
1700
1701 /* Disable periodic monitoring of CC_ID pin */
1702 rc = smblib_write(chg, TYPEC_U_USB_WATER_PROTECTION_CFG_REG, 0);
1703 if (rc < 0) {
1704 dev_err(chg->dev, "Couldn't disable periodic monitoring of CC_ID rc=%d\n",
1705 rc);
1706 return rc;
1707 }
1708 }
1709
Harry Yang4b7db0f2017-11-27 10:50:44 -08001710 return rc;
1711}
1712
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +05301713static int smb5_configure_mitigation(struct smb_charger *chg)
1714{
1715 int rc;
1716 u8 chan = 0;
1717
1718 if (!chg->hw_die_temp_mitigation && !chg->hw_connector_mitigation)
1719 return 0;
1720
1721 if (chg->hw_die_temp_mitigation) {
1722 rc = smblib_write(chg, MISC_THERMREG_SRC_CFG_REG,
1723 THERMREG_CONNECTOR_ADC_SRC_EN_BIT
1724 | THERMREG_DIE_ADC_SRC_EN_BIT
1725 | THERMREG_DIE_CMP_SRC_EN_BIT);
1726 if (rc < 0) {
1727 dev_err(chg->dev,
1728 "Couldn't configure THERM_SRC reg rc=%d\n", rc);
1729 return rc;
1730 };
1731
1732 chan = DIE_TEMP_CHANNEL_EN_BIT;
1733 }
1734
1735 if (chg->hw_connector_mitigation)
1736 chan |= CONN_THM_CHANNEL_EN_BIT;
1737
1738 rc = smblib_masked_write(chg, BATIF_ADC_CHANNEL_EN_REG,
1739 CONN_THM_CHANNEL_EN_BIT | DIE_TEMP_CHANNEL_EN_BIT,
1740 chan);
1741 if (rc < 0) {
Ashay Jaiswalb50706d2018-06-28 19:37:31 +05301742 dev_err(chg->dev, "Couldn't enable ADC channel rc=%d\n", rc);
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +05301743 return rc;
1744 }
1745
1746 return 0;
1747}
1748
Harry Yang4b7db0f2017-11-27 10:50:44 -08001749static int smb5_init_hw(struct smb5 *chip)
1750{
1751 struct smb_charger *chg = &chip->chg;
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301752 int rc, type = 0;
1753 u8 val = 0;
Harry Yang4b7db0f2017-11-27 10:50:44 -08001754
1755 if (chip->dt.no_battery)
1756 chg->fake_capacity = 50;
1757
1758 if (chip->dt.batt_profile_fcc_ua < 0)
1759 smblib_get_charge_param(chg, &chg->param.fcc,
1760 &chg->batt_profile_fcc_ua);
1761
1762 if (chip->dt.batt_profile_fv_uv < 0)
1763 smblib_get_charge_param(chg, &chg->param.fv,
1764 &chg->batt_profile_fv_uv);
1765
1766 smblib_get_charge_param(chg, &chg->param.usb_icl,
1767 &chg->default_icl_ua);
Ashay Jaiswale0b3c472018-06-20 23:39:41 +05301768 smblib_get_charge_param(chg, &chg->param.aicl_5v_threshold,
1769 &chg->default_aicl_5v_threshold_mv);
1770 chg->aicl_5v_threshold_mv = chg->default_aicl_5v_threshold_mv;
1771 smblib_get_charge_param(chg, &chg->param.aicl_cont_threshold,
1772 &chg->default_aicl_cont_threshold_mv);
1773 chg->aicl_cont_threshold_mv = chg->default_aicl_cont_threshold_mv;
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301774
1775 /* Use SW based VBUS control, disable HW autonomous mode */
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301776 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1777 HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT,
1778 HVDCP_AUTH_ALG_EN_CFG_BIT);
1779 if (rc < 0) {
1780 dev_err(chg->dev, "Couldn't configure HVDCP rc=%d\n", rc);
1781 return rc;
1782 }
1783
1784 /*
1785 * PMI632 can have the connector type defined by a dedicated register
1786 * TYPEC_MICRO_USB_MODE_REG or by a common TYPEC_U_USB_CFG_REG.
1787 */
1788 if (chg->smb_version == PMI632_SUBTYPE) {
1789 rc = smblib_read(chg, TYPEC_MICRO_USB_MODE_REG, &val);
1790 if (rc < 0) {
1791 dev_err(chg->dev, "Couldn't read USB mode rc=%d\n", rc);
1792 return rc;
1793 }
1794 type = !!(val & MICRO_USB_MODE_ONLY_BIT);
1795 }
1796
1797 /*
1798 * If TYPEC_MICRO_USB_MODE_REG is not set and for all non-PMI632
1799 * check the connector type using TYPEC_U_USB_CFG_REG.
1800 */
1801 if (!type) {
1802 rc = smblib_read(chg, TYPEC_U_USB_CFG_REG, &val);
1803 if (rc < 0) {
1804 dev_err(chg->dev, "Couldn't read U_USB config rc=%d\n",
1805 rc);
1806 return rc;
1807 }
1808
1809 type = !!(val & EN_MICRO_USB_MODE_BIT);
1810 }
1811
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301812 pr_debug("Connector type=%s\n", type ? "Micro USB" : "TypeC");
1813
Harry Yang6afaea22018-03-26 19:11:07 -07001814 if (type) {
1815 chg->connector_type = POWER_SUPPLY_CONNECTOR_MICRO_USB;
Harry Yang6afaea22018-03-26 19:11:07 -07001816 rc = smb5_configure_micro_usb(chg);
1817 } else {
1818 chg->connector_type = POWER_SUPPLY_CONNECTOR_TYPEC;
1819 rc = smb5_configure_typec(chg);
1820 }
1821 if (rc < 0) {
1822 dev_err(chg->dev,
1823 "Couldn't configure TypeC/micro-USB mode rc=%d\n", rc);
1824 return rc;
1825 }
1826
Ashay Jaiswal09feab82018-02-12 12:33:18 +05301827 /*
1828 * PMI632 based hw init:
Ashay Jaiswal6f70a512018-05-11 17:25:58 +05301829 * - Enable STAT pin function on SMB_EN
Ashay Jaiswalc96380de2018-05-16 12:02:36 +05301830 * - Rerun APSD to ensure proper charger detection if device
1831 * boots with charger connected.
Ashay Jaiswal09feab82018-02-12 12:33:18 +05301832 * - Initialize flash module for PMI632
1833 */
Ashay Jaiswalc96380de2018-05-16 12:02:36 +05301834 if (chg->smb_version == PMI632_SUBTYPE) {
Ashay Jaiswal6f70a512018-05-11 17:25:58 +05301835 rc = smblib_masked_write(chg, MISC_SMB_EN_CMD_REG,
1836 EN_STAT_CMD_BIT, EN_STAT_CMD_BIT);
1837 if (rc < 0) {
1838 dev_err(chg->dev, "Couldn't configure SMB_EN rc=%d\n",
1839 rc);
1840 return rc;
1841 }
1842
Ashay Jaiswal09feab82018-02-12 12:33:18 +05301843 schgm_flash_init(chg);
Ashay Jaiswalc96380de2018-05-16 12:02:36 +05301844 smblib_rerun_apsd_if_required(chg);
1845 }
Ashay Jaiswal09feab82018-02-12 12:33:18 +05301846
Ashay Jaiswalcbdf2e82018-05-27 23:59:01 +05301847 /* clear the ICL override if it is set */
1848 rc = smblib_icl_override(chg, false);
1849 if (rc < 0) {
1850 pr_err("Couldn't disable ICL override rc=%d\n", rc);
1851 return rc;
1852 }
1853
Ashay Jaiswalb2b06fe2018-06-07 18:35:21 +05301854 /* set OTG current limit */
1855 rc = smblib_set_charge_param(chg, &chg->param.otg_cl, chg->otg_cl_ua);
1856 if (rc < 0) {
1857 pr_err("Couldn't set otg current limit rc=%d\n", rc);
1858 return rc;
1859 }
1860
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +05301861 /* configure temperature mitigation */
1862 rc = smb5_configure_mitigation(chg);
1863 if (rc < 0) {
1864 dev_err(chg->dev, "Couldn't configure mitigation rc=%d\n", rc);
1865 return rc;
1866 }
1867
Harry Yang4b7db0f2017-11-27 10:50:44 -08001868 /* vote 0mA on usb_icl for non battery platforms */
1869 vote(chg->usb_icl_votable,
1870 DEFAULT_VOTER, chip->dt.no_battery, 0);
1871 vote(chg->dc_suspend_votable,
1872 DEFAULT_VOTER, chip->dt.no_battery, 0);
1873 vote(chg->fcc_votable, HW_LIMIT_VOTER,
1874 chip->dt.batt_profile_fcc_ua > 0, chip->dt.batt_profile_fcc_ua);
1875 vote(chg->fv_votable, HW_LIMIT_VOTER,
1876 chip->dt.batt_profile_fv_uv > 0, chip->dt.batt_profile_fv_uv);
1877 vote(chg->fcc_votable,
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301878 BATT_PROFILE_VOTER, chg->batt_profile_fcc_ua > 0,
1879 chg->batt_profile_fcc_ua);
Harry Yang4b7db0f2017-11-27 10:50:44 -08001880 vote(chg->fv_votable,
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301881 BATT_PROFILE_VOTER, chg->batt_profile_fv_uv > 0,
1882 chg->batt_profile_fv_uv);
Ashay Jaiswala9e10912018-02-02 14:03:35 +05301883
1884 /* Some h/w limit maximum supported ICL */
1885 vote(chg->usb_icl_votable, HW_LIMIT_VOTER,
1886 chg->hw_max_icl_ua > 0, chg->hw_max_icl_ua);
Harry Yang4b7db0f2017-11-27 10:50:44 -08001887
1888 /*
1889 * AICL configuration:
Ashay Jaiswalc96380de2018-05-16 12:02:36 +05301890 * AICL ADC disable
Harry Yang4b7db0f2017-11-27 10:50:44 -08001891 */
Ashay Jaiswalc96380de2018-05-16 12:02:36 +05301892 if (chg->smb_version != PMI632_SUBTYPE) {
1893 rc = smblib_masked_write(chg, USBIN_AICL_OPTIONS_CFG_REG,
Harry Yang4b7db0f2017-11-27 10:50:44 -08001894 USBIN_AICL_ADC_EN_BIT, 0);
Ashay Jaiswalc96380de2018-05-16 12:02:36 +05301895 if (rc < 0) {
1896 dev_err(chg->dev, "Couldn't config AICL rc=%d\n", rc);
1897 return rc;
1898 }
Harry Yang4b7db0f2017-11-27 10:50:44 -08001899 }
1900
1901 /* enable the charging path */
1902 rc = vote(chg->chg_disable_votable, DEFAULT_VOTER, false, 0);
1903 if (rc < 0) {
1904 dev_err(chg->dev, "Couldn't enable charging rc=%d\n", rc);
1905 return rc;
1906 }
1907
Harry Yang4b7db0f2017-11-27 10:50:44 -08001908 /* configure VBUS for software control */
1909 rc = smblib_masked_write(chg, DCDC_OTG_CFG_REG, OTG_EN_SRC_CFG_BIT, 0);
1910 if (rc < 0) {
1911 dev_err(chg->dev,
1912 "Couldn't configure VBUS for SW control rc=%d\n", rc);
1913 return rc;
1914 }
1915
Ashay Jaiswala55b7ed2018-03-23 17:23:48 +05301916 /*
1917 * configure the one time watchdong periodic interval and
1918 * disable "watchdog bite disable charging".
1919 */
Harry Yang4b7db0f2017-11-27 10:50:44 -08001920 val = (ilog2(chip->dt.wd_bark_time / 16) << BARK_WDOG_TIMEOUT_SHIFT)
1921 & BARK_WDOG_TIMEOUT_MASK;
1922 val |= BITE_WDOG_TIMEOUT_8S;
1923 rc = smblib_masked_write(chg, SNARL_BARK_BITE_WD_CFG_REG,
1924 BITE_WDOG_DISABLE_CHARGING_CFG_BIT |
1925 BARK_WDOG_TIMEOUT_MASK | BITE_WDOG_TIMEOUT_MASK,
1926 val);
1927 if (rc < 0) {
1928 pr_err("Couldn't configue WD config rc=%d\n", rc);
1929 return rc;
1930 }
1931
Harry Yang4b7db0f2017-11-27 10:50:44 -08001932 /* configure float charger options */
1933 switch (chip->dt.float_option) {
1934 case FLOAT_DCP:
1935 rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
1936 FLOAT_OPTIONS_MASK, 0);
1937 break;
1938 case FLOAT_SDP:
1939 rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
1940 FLOAT_OPTIONS_MASK, FORCE_FLOAT_SDP_CFG_BIT);
1941 break;
1942 case DISABLE_CHARGING:
1943 rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
1944 FLOAT_OPTIONS_MASK, FLOAT_DIS_CHGING_CFG_BIT);
1945 break;
1946 case SUSPEND_INPUT:
1947 rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
1948 FLOAT_OPTIONS_MASK, SUSPEND_FLOAT_CFG_BIT);
1949 break;
1950 default:
1951 rc = 0;
1952 break;
1953 }
1954
1955 if (rc < 0) {
1956 dev_err(chg->dev, "Couldn't configure float charger options rc=%d\n",
1957 rc);
1958 return rc;
1959 }
1960
1961 rc = smblib_read(chg, USBIN_OPTIONS_2_CFG_REG, &chg->float_cfg);
1962 if (rc < 0) {
1963 dev_err(chg->dev, "Couldn't read float charger options rc=%d\n",
1964 rc);
1965 return rc;
1966 }
1967
1968 switch (chip->dt.chg_inhibit_thr_mv) {
1969 case 50:
1970 rc = smblib_masked_write(chg, CHARGE_INHIBIT_THRESHOLD_CFG_REG,
1971 CHARGE_INHIBIT_THRESHOLD_MASK,
1972 INHIBIT_ANALOG_VFLT_MINUS_50MV);
1973 break;
1974 case 100:
1975 rc = smblib_masked_write(chg, CHARGE_INHIBIT_THRESHOLD_CFG_REG,
1976 CHARGE_INHIBIT_THRESHOLD_MASK,
1977 INHIBIT_ANALOG_VFLT_MINUS_100MV);
1978 break;
1979 case 200:
1980 rc = smblib_masked_write(chg, CHARGE_INHIBIT_THRESHOLD_CFG_REG,
1981 CHARGE_INHIBIT_THRESHOLD_MASK,
1982 INHIBIT_ANALOG_VFLT_MINUS_200MV);
1983 break;
1984 case 300:
1985 rc = smblib_masked_write(chg, CHARGE_INHIBIT_THRESHOLD_CFG_REG,
1986 CHARGE_INHIBIT_THRESHOLD_MASK,
1987 INHIBIT_ANALOG_VFLT_MINUS_300MV);
1988 break;
1989 case 0:
1990 rc = smblib_masked_write(chg, CHGR_CFG2_REG,
1991 CHARGER_INHIBIT_BIT, 0);
1992 default:
1993 break;
1994 }
1995
1996 if (rc < 0) {
1997 dev_err(chg->dev, "Couldn't configure charge inhibit threshold rc=%d\n",
1998 rc);
1999 return rc;
2000 }
2001
Anirudh Ghayal1380d312018-02-23 00:01:43 +05302002 rc = smblib_masked_write(chg, CHGR_CFG2_REG, RECHG_MASK,
2003 (chip->dt.auto_recharge_vbat_mv != -EINVAL) ?
2004 VBAT_BASED_RECHG_BIT : 0);
Harry Yang4b7db0f2017-11-27 10:50:44 -08002005 if (rc < 0) {
Anirudh Ghayal1380d312018-02-23 00:01:43 +05302006 dev_err(chg->dev, "Couldn't configure VBAT-rechg CHG_CFG2_REG rc=%d\n",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002007 rc);
2008 return rc;
2009 }
2010
Anirudh Ghayal1380d312018-02-23 00:01:43 +05302011 /* program the auto-recharge VBAT threshold */
2012 if (chip->dt.auto_recharge_vbat_mv != -EINVAL) {
2013 u32 temp = VBAT_TO_VRAW_ADC(chip->dt.auto_recharge_vbat_mv);
2014
2015 temp = ((temp & 0xFF00) >> 8) | ((temp & 0xFF) << 8);
2016 rc = smblib_batch_write(chg,
2017 CHGR_ADC_RECHARGE_THRESHOLD_MSB_REG, (u8 *)&temp, 2);
2018 if (rc < 0) {
2019 dev_err(chg->dev, "Couldn't configure ADC_RECHARGE_THRESHOLD REG rc=%d\n",
2020 rc);
2021 return rc;
2022 }
2023 /* Program the sample count for VBAT based recharge to 3 */
2024 rc = smblib_masked_write(chg, CHGR_NO_SAMPLE_TERM_RCHG_CFG_REG,
2025 NO_OF_SAMPLE_FOR_RCHG,
2026 2 << NO_OF_SAMPLE_FOR_RCHG_SHIFT);
2027 if (rc < 0) {
2028 dev_err(chg->dev, "Couldn't configure CHGR_NO_SAMPLE_FOR_TERM_RCHG_CFG rc=%d\n",
2029 rc);
2030 return rc;
2031 }
2032 }
2033
2034 rc = smblib_masked_write(chg, CHGR_CFG2_REG, RECHG_MASK,
2035 (chip->dt.auto_recharge_soc != -EINVAL) ?
2036 SOC_BASED_RECHG_BIT : VBAT_BASED_RECHG_BIT);
2037 if (rc < 0) {
2038 dev_err(chg->dev, "Couldn't configure SOC-rechg CHG_CFG2_REG rc=%d\n",
2039 rc);
2040 return rc;
2041 }
2042
2043 /* program the auto-recharge threshold */
2044 if (chip->dt.auto_recharge_soc != -EINVAL) {
2045 rc = smblib_write(chg, CHARGE_RCHG_SOC_THRESHOLD_CFG_REG,
2046 (chip->dt.auto_recharge_soc * 255) / 100);
2047 if (rc < 0) {
2048 dev_err(chg->dev, "Couldn't configure CHG_RCHG_SOC_REG rc=%d\n",
2049 rc);
2050 return rc;
2051 }
2052 /* Program the sample count for SOC based recharge to 1 */
2053 rc = smblib_masked_write(chg, CHGR_NO_SAMPLE_TERM_RCHG_CFG_REG,
2054 NO_OF_SAMPLE_FOR_RCHG, 0);
2055 if (rc < 0) {
2056 dev_err(chg->dev, "Couldn't configure CHGR_NO_SAMPLE_FOR_TERM_RCHG_CFG rc=%d\n",
2057 rc);
2058 return rc;
2059 }
2060 }
2061
Harry Yang4b7db0f2017-11-27 10:50:44 -08002062 if (chg->sw_jeita_enabled) {
2063 rc = smblib_disable_hw_jeita(chg, true);
2064 if (rc < 0) {
2065 dev_err(chg->dev, "Couldn't set hw jeita rc=%d\n", rc);
2066 return rc;
2067 }
2068 }
2069
Ashay Jaiswala55b7ed2018-03-23 17:23:48 +05302070 rc = smblib_configure_wdog(chg,
2071 chg->step_chg_enabled || chg->sw_jeita_enabled);
2072 if (rc < 0) {
2073 dev_err(chg->dev, "Couldn't configure watchdog rc=%d\n",
2074 rc);
2075 return rc;
2076 }
2077
Ashay Jaiswal0de6fb92018-06-12 17:23:45 +05302078 if (chg->connector_pull_up != -EINVAL) {
2079 rc = smb5_configure_internal_pull(chg, CONN_THERM,
2080 get_valid_pullup(chg->connector_pull_up));
2081 if (rc < 0) {
2082 dev_err(chg->dev,
2083 "Couldn't configure CONN_THERM pull-up rc=%d\n",
2084 rc);
2085 return rc;
2086 }
2087 }
2088
Harry Yang4b7db0f2017-11-27 10:50:44 -08002089 return rc;
2090}
2091
2092static int smb5_post_init(struct smb5 *chip)
2093{
2094 struct smb_charger *chg = &chip->chg;
2095 union power_supply_propval pval;
2096 int rc;
2097
2098 /*
2099 * In case the usb path is suspended, we would have missed disabling
2100 * the icl change interrupt because the interrupt could have been
2101 * not requested
2102 */
2103 rerun_election(chg->usb_icl_votable);
2104
2105 /* configure power role for dual-role */
2106 pval.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
2107 rc = smblib_set_prop_typec_power_role(chg, &pval);
2108 if (rc < 0) {
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302109 dev_err(chg->dev, "Couldn't configure DRP role rc=%d\n",
2110 rc);
Harry Yang4b7db0f2017-11-27 10:50:44 -08002111 return rc;
2112 }
2113
2114 rerun_election(chg->usb_irq_enable_votable);
2115
2116 return 0;
2117}
2118
2119/****************************
2120 * DETERMINE INITIAL STATUS *
2121 ****************************/
2122
2123static int smb5_determine_initial_status(struct smb5 *chip)
2124{
2125 struct smb_irq_data irq_data = {chip, "determine-initial-status"};
2126 struct smb_charger *chg = &chip->chg;
Harry Yang6afaea22018-03-26 19:11:07 -07002127 union power_supply_propval val;
2128 int rc;
2129
2130 rc = smblib_get_prop_usb_present(chg, &val);
2131 if (rc < 0) {
2132 pr_err("Couldn't get usb present rc=%d\n", rc);
2133 return rc;
2134 }
2135 chg->early_usb_attach = val.intval;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002136
2137 if (chg->bms_psy)
2138 smblib_suspend_on_debug_battery(chg);
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302139
Harry Yang4b7db0f2017-11-27 10:50:44 -08002140 usb_plugin_irq_handler(0, &irq_data);
Harry Yang6afaea22018-03-26 19:11:07 -07002141 typec_attach_detach_irq_handler(0, &irq_data);
Harry Yang4b7db0f2017-11-27 10:50:44 -08002142 typec_state_change_irq_handler(0, &irq_data);
2143 usb_source_change_irq_handler(0, &irq_data);
2144 chg_state_change_irq_handler(0, &irq_data);
2145 icl_change_irq_handler(0, &irq_data);
2146 batt_temp_changed_irq_handler(0, &irq_data);
2147 wdog_bark_irq_handler(0, &irq_data);
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302148 typec_or_rid_detection_change_irq_handler(0, &irq_data);
Harry Yang4b7db0f2017-11-27 10:50:44 -08002149
2150 return 0;
2151}
2152
2153/**************************
2154 * INTERRUPT REGISTRATION *
2155 **************************/
2156
2157static struct smb_irq_info smb5_irqs[] = {
2158 /* CHARGER IRQs */
2159 [CHGR_ERROR_IRQ] = {
2160 .name = "chgr-error",
2161 .handler = default_irq_handler,
2162 },
2163 [CHG_STATE_CHANGE_IRQ] = {
2164 .name = "chg-state-change",
2165 .handler = chg_state_change_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302166 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002167 },
2168 [STEP_CHG_STATE_CHANGE_IRQ] = {
2169 .name = "step-chg-state-change",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002170 },
2171 [STEP_CHG_SOC_UPDATE_FAIL_IRQ] = {
2172 .name = "step-chg-soc-update-fail",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002173 },
2174 [STEP_CHG_SOC_UPDATE_REQ_IRQ] = {
2175 .name = "step-chg-soc-update-req",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002176 },
2177 [FG_FVCAL_QUALIFIED_IRQ] = {
2178 .name = "fg-fvcal-qualified",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002179 },
2180 [VPH_ALARM_IRQ] = {
2181 .name = "vph-alarm",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002182 },
2183 [VPH_DROP_PRECHG_IRQ] = {
2184 .name = "vph-drop-prechg",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002185 },
2186 /* DCDC IRQs */
2187 [OTG_FAIL_IRQ] = {
2188 .name = "otg-fail",
2189 .handler = default_irq_handler,
2190 },
2191 [OTG_OC_DISABLE_SW_IRQ] = {
2192 .name = "otg-oc-disable-sw",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002193 },
2194 [OTG_OC_HICCUP_IRQ] = {
2195 .name = "otg-oc-hiccup",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002196 },
2197 [BSM_ACTIVE_IRQ] = {
2198 .name = "bsm-active",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002199 },
2200 [HIGH_DUTY_CYCLE_IRQ] = {
2201 .name = "high-duty-cycle",
2202 .handler = high_duty_cycle_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302203 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002204 },
2205 [INPUT_CURRENT_LIMITING_IRQ] = {
2206 .name = "input-current-limiting",
2207 .handler = default_irq_handler,
2208 },
2209 [CONCURRENT_MODE_DISABLE_IRQ] = {
2210 .name = "concurrent-mode-disable",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002211 },
2212 [SWITCHER_POWER_OK_IRQ] = {
2213 .name = "switcher-power-ok",
2214 .handler = switcher_power_ok_irq_handler,
2215 },
2216 /* BATTERY IRQs */
2217 [BAT_TEMP_IRQ] = {
2218 .name = "bat-temp",
2219 .handler = batt_temp_changed_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302220 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002221 },
2222 [ALL_CHNL_CONV_DONE_IRQ] = {
2223 .name = "all-chnl-conv-done",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002224 },
2225 [BAT_OV_IRQ] = {
2226 .name = "bat-ov",
2227 .handler = batt_psy_changed_irq_handler,
2228 },
2229 [BAT_LOW_IRQ] = {
2230 .name = "bat-low",
2231 .handler = batt_psy_changed_irq_handler,
2232 },
2233 [BAT_THERM_OR_ID_MISSING_IRQ] = {
2234 .name = "bat-therm-or-id-missing",
2235 .handler = batt_psy_changed_irq_handler,
2236 },
2237 [BAT_TERMINAL_MISSING_IRQ] = {
2238 .name = "bat-terminal-missing",
2239 .handler = batt_psy_changed_irq_handler,
2240 },
2241 [BUCK_OC_IRQ] = {
2242 .name = "buck-oc",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002243 },
2244 [VPH_OV_IRQ] = {
2245 .name = "vph-ov",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002246 },
2247 /* USB INPUT IRQs */
2248 [USBIN_COLLAPSE_IRQ] = {
2249 .name = "usbin-collapse",
2250 .handler = default_irq_handler,
2251 },
2252 [USBIN_VASHDN_IRQ] = {
2253 .name = "usbin-vashdn",
2254 .handler = default_irq_handler,
2255 },
2256 [USBIN_UV_IRQ] = {
2257 .name = "usbin-uv",
2258 .handler = usbin_uv_irq_handler,
Ashay Jaiswale0b3c472018-06-20 23:39:41 +05302259 .wake = true,
2260 .storm_data = {true, 3000, 5},
Harry Yang4b7db0f2017-11-27 10:50:44 -08002261 },
2262 [USBIN_OV_IRQ] = {
2263 .name = "usbin-ov",
2264 .handler = default_irq_handler,
2265 },
2266 [USBIN_PLUGIN_IRQ] = {
2267 .name = "usbin-plugin",
2268 .handler = usb_plugin_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302269 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002270 },
2271 [USBIN_REVI_CHANGE_IRQ] = {
2272 .name = "usbin-revi-change",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002273 },
2274 [USBIN_SRC_CHANGE_IRQ] = {
2275 .name = "usbin-src-change",
2276 .handler = usb_source_change_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302277 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002278 },
2279 [USBIN_ICL_CHANGE_IRQ] = {
2280 .name = "usbin-icl-change",
2281 .handler = icl_change_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302282 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002283 },
2284 /* DC INPUT IRQs */
2285 [DCIN_VASHDN_IRQ] = {
2286 .name = "dcin-vashdn",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002287 },
2288 [DCIN_UV_IRQ] = {
2289 .name = "dcin-uv",
2290 .handler = default_irq_handler,
2291 },
2292 [DCIN_OV_IRQ] = {
2293 .name = "dcin-ov",
2294 .handler = default_irq_handler,
2295 },
2296 [DCIN_PLUGIN_IRQ] = {
2297 .name = "dcin-plugin",
2298 .handler = dc_plugin_irq_handler,
2299 .wake = true,
2300 },
2301 [DCIN_REVI_IRQ] = {
2302 .name = "dcin-revi",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002303 },
2304 [DCIN_PON_IRQ] = {
2305 .name = "dcin-pon",
2306 .handler = default_irq_handler,
2307 },
2308 [DCIN_EN_IRQ] = {
2309 .name = "dcin-en",
2310 .handler = default_irq_handler,
2311 },
2312 /* TYPEC IRQs */
2313 [TYPEC_OR_RID_DETECTION_CHANGE_IRQ] = {
2314 .name = "typec-or-rid-detect-change",
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302315 .handler = typec_or_rid_detection_change_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302316 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002317 },
2318 [TYPEC_VPD_DETECT_IRQ] = {
2319 .name = "typec-vpd-detect",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002320 },
2321 [TYPEC_CC_STATE_CHANGE_IRQ] = {
2322 .name = "typec-cc-state-change",
2323 .handler = typec_state_change_irq_handler,
Ashay Jaiswal48015c32018-03-07 18:25:43 +05302324 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002325 },
2326 [TYPEC_VCONN_OC_IRQ] = {
2327 .name = "typec-vconn-oc",
2328 .handler = default_irq_handler,
2329 },
2330 [TYPEC_VBUS_CHANGE_IRQ] = {
2331 .name = "typec-vbus-change",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002332 },
2333 [TYPEC_ATTACH_DETACH_IRQ] = {
2334 .name = "typec-attach-detach",
Harry Yang6afaea22018-03-26 19:11:07 -07002335 .handler = typec_attach_detach_irq_handler,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002336 },
2337 [TYPEC_LEGACY_CABLE_DETECT_IRQ] = {
2338 .name = "typec-legacy-cable-detect",
2339 .handler = default_irq_handler,
2340 },
2341 [TYPEC_TRY_SNK_SRC_DETECT_IRQ] = {
2342 .name = "typec-try-snk-src-detect",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002343 },
2344 /* MISCELLANEOUS IRQs */
2345 [WDOG_SNARL_IRQ] = {
2346 .name = "wdog-snarl",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002347 },
2348 [WDOG_BARK_IRQ] = {
2349 .name = "wdog-bark",
2350 .handler = wdog_bark_irq_handler,
Ashay Jaiswala55b7ed2018-03-23 17:23:48 +05302351 .wake = true,
Harry Yang4b7db0f2017-11-27 10:50:44 -08002352 },
2353 [AICL_FAIL_IRQ] = {
2354 .name = "aicl-fail",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002355 },
2356 [AICL_DONE_IRQ] = {
2357 .name = "aicl-done",
2358 .handler = default_irq_handler,
2359 },
2360 [SMB_EN_IRQ] = {
2361 .name = "smb-en",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002362 },
2363 [IMP_TRIGGER_IRQ] = {
2364 .name = "imp-trigger",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002365 },
2366 [TEMP_CHANGE_IRQ] = {
2367 .name = "temp-change",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002368 },
2369 [TEMP_CHANGE_SMB_IRQ] = {
2370 .name = "temp-change-smb",
Harry Yang4b7db0f2017-11-27 10:50:44 -08002371 },
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302372 /* FLASH */
2373 [VREG_OK_IRQ] = {
2374 .name = "vreg-ok",
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302375 },
2376 [ILIM_S2_IRQ] = {
2377 .name = "ilim2-s2",
2378 .handler = schgm_flash_ilim2_irq_handler,
2379 },
2380 [ILIM_S1_IRQ] = {
2381 .name = "ilim1-s1",
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302382 },
2383 [VOUT_DOWN_IRQ] = {
2384 .name = "vout-down",
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302385 },
2386 [VOUT_UP_IRQ] = {
2387 .name = "vout-up",
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302388 },
2389 [FLASH_STATE_CHANGE_IRQ] = {
2390 .name = "flash-state-change",
2391 .handler = schgm_flash_state_change_irq_handler,
2392 },
2393 [TORCH_REQ_IRQ] = {
2394 .name = "torch-req",
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302395 },
2396 [FLASH_EN_IRQ] = {
2397 .name = "flash-en",
Ashay Jaiswal09feab82018-02-12 12:33:18 +05302398 },
Harry Yang4b7db0f2017-11-27 10:50:44 -08002399};
2400
2401static int smb5_get_irq_index_byname(const char *irq_name)
2402{
2403 int i;
2404
2405 for (i = 0; i < ARRAY_SIZE(smb5_irqs); i++) {
2406 if (strcmp(smb5_irqs[i].name, irq_name) == 0)
2407 return i;
2408 }
2409
2410 return -ENOENT;
2411}
2412
2413static int smb5_request_interrupt(struct smb5 *chip,
2414 struct device_node *node, const char *irq_name)
2415{
2416 struct smb_charger *chg = &chip->chg;
2417 int rc, irq, irq_index;
2418 struct smb_irq_data *irq_data;
2419
2420 irq = of_irq_get_byname(node, irq_name);
2421 if (irq < 0) {
2422 pr_err("Couldn't get irq %s byname\n", irq_name);
2423 return irq;
2424 }
2425
2426 irq_index = smb5_get_irq_index_byname(irq_name);
2427 if (irq_index < 0) {
2428 pr_err("%s is not a defined irq\n", irq_name);
2429 return irq_index;
2430 }
2431
2432 if (!smb5_irqs[irq_index].handler)
2433 return 0;
2434
2435 irq_data = devm_kzalloc(chg->dev, sizeof(*irq_data), GFP_KERNEL);
2436 if (!irq_data)
2437 return -ENOMEM;
2438
2439 irq_data->parent_data = chip;
2440 irq_data->name = irq_name;
2441 irq_data->storm_data = smb5_irqs[irq_index].storm_data;
2442 mutex_init(&irq_data->storm_data.storm_lock);
2443
2444 rc = devm_request_threaded_irq(chg->dev, irq, NULL,
2445 smb5_irqs[irq_index].handler,
2446 IRQF_ONESHOT, irq_name, irq_data);
2447 if (rc < 0) {
2448 pr_err("Couldn't request irq %d\n", irq);
2449 return rc;
2450 }
2451
2452 smb5_irqs[irq_index].irq = irq;
2453 smb5_irqs[irq_index].irq_data = irq_data;
2454 if (smb5_irqs[irq_index].wake)
2455 enable_irq_wake(irq);
2456
2457 return rc;
2458}
2459
2460static int smb5_request_interrupts(struct smb5 *chip)
2461{
2462 struct smb_charger *chg = &chip->chg;
2463 struct device_node *node = chg->dev->of_node;
2464 struct device_node *child;
2465 int rc = 0;
2466 const char *name;
2467 struct property *prop;
2468
2469 for_each_available_child_of_node(node, child) {
2470 of_property_for_each_string(child, "interrupt-names",
2471 prop, name) {
2472 rc = smb5_request_interrupt(chip, child, name);
2473 if (rc < 0)
2474 return rc;
2475 }
2476 }
2477 if (chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq)
2478 chg->usb_icl_change_irq_enabled = true;
2479
2480 return rc;
2481}
2482
2483static void smb5_free_interrupts(struct smb_charger *chg)
2484{
2485 int i;
2486
2487 for (i = 0; i < ARRAY_SIZE(smb5_irqs); i++) {
2488 if (smb5_irqs[i].irq > 0) {
2489 if (smb5_irqs[i].wake)
2490 disable_irq_wake(smb5_irqs[i].irq);
2491
2492 devm_free_irq(chg->dev, smb5_irqs[i].irq,
2493 smb5_irqs[i].irq_data);
2494 }
2495 }
2496}
2497
2498static void smb5_disable_interrupts(struct smb_charger *chg)
2499{
2500 int i;
2501
2502 for (i = 0; i < ARRAY_SIZE(smb5_irqs); i++) {
2503 if (smb5_irqs[i].irq > 0)
2504 disable_irq(smb5_irqs[i].irq);
2505 }
2506}
2507
2508#if defined(CONFIG_DEBUG_FS)
2509
2510static int force_batt_psy_update_write(void *data, u64 val)
2511{
2512 struct smb_charger *chg = data;
2513
2514 power_supply_changed(chg->batt_psy);
2515 return 0;
2516}
2517DEFINE_SIMPLE_ATTRIBUTE(force_batt_psy_update_ops, NULL,
2518 force_batt_psy_update_write, "0x%02llx\n");
2519
2520static int force_usb_psy_update_write(void *data, u64 val)
2521{
2522 struct smb_charger *chg = data;
2523
2524 power_supply_changed(chg->usb_psy);
2525 return 0;
2526}
2527DEFINE_SIMPLE_ATTRIBUTE(force_usb_psy_update_ops, NULL,
2528 force_usb_psy_update_write, "0x%02llx\n");
2529
2530static int force_dc_psy_update_write(void *data, u64 val)
2531{
2532 struct smb_charger *chg = data;
2533
2534 power_supply_changed(chg->dc_psy);
2535 return 0;
2536}
2537DEFINE_SIMPLE_ATTRIBUTE(force_dc_psy_update_ops, NULL,
2538 force_dc_psy_update_write, "0x%02llx\n");
2539
2540static void smb5_create_debugfs(struct smb5 *chip)
2541{
2542 struct dentry *file;
2543
2544 chip->dfs_root = debugfs_create_dir("charger", NULL);
2545 if (IS_ERR_OR_NULL(chip->dfs_root)) {
2546 pr_err("Couldn't create charger debugfs rc=%ld\n",
2547 (long)chip->dfs_root);
2548 return;
2549 }
2550
2551 file = debugfs_create_file("force_batt_psy_update", 0600,
2552 chip->dfs_root, chip, &force_batt_psy_update_ops);
2553 if (IS_ERR_OR_NULL(file))
2554 pr_err("Couldn't create force_batt_psy_update file rc=%ld\n",
2555 (long)file);
2556
2557 file = debugfs_create_file("force_usb_psy_update", 0600,
2558 chip->dfs_root, chip, &force_usb_psy_update_ops);
2559 if (IS_ERR_OR_NULL(file))
2560 pr_err("Couldn't create force_usb_psy_update file rc=%ld\n",
2561 (long)file);
2562
2563 file = debugfs_create_file("force_dc_psy_update", 0600,
2564 chip->dfs_root, chip, &force_dc_psy_update_ops);
2565 if (IS_ERR_OR_NULL(file))
2566 pr_err("Couldn't create force_dc_psy_update file rc=%ld\n",
2567 (long)file);
2568}
2569
2570#else
2571
2572static void smb5_create_debugfs(struct smb5 *chip)
2573{}
2574
2575#endif
2576
2577static int smb5_show_charger_status(struct smb5 *chip)
2578{
2579 struct smb_charger *chg = &chip->chg;
2580 union power_supply_propval val;
2581 int usb_present, batt_present, batt_health, batt_charge_type;
2582 int rc;
2583
2584 rc = smblib_get_prop_usb_present(chg, &val);
2585 if (rc < 0) {
2586 pr_err("Couldn't get usb present rc=%d\n", rc);
2587 return rc;
2588 }
2589 usb_present = val.intval;
2590
2591 rc = smblib_get_prop_batt_present(chg, &val);
2592 if (rc < 0) {
2593 pr_err("Couldn't get batt present rc=%d\n", rc);
2594 return rc;
2595 }
2596 batt_present = val.intval;
2597
2598 rc = smblib_get_prop_batt_health(chg, &val);
2599 if (rc < 0) {
2600 pr_err("Couldn't get batt health rc=%d\n", rc);
2601 val.intval = POWER_SUPPLY_HEALTH_UNKNOWN;
2602 }
2603 batt_health = val.intval;
2604
2605 rc = smblib_get_prop_batt_charge_type(chg, &val);
2606 if (rc < 0) {
2607 pr_err("Couldn't get batt charge type rc=%d\n", rc);
2608 return rc;
2609 }
2610 batt_charge_type = val.intval;
2611
2612 pr_info("SMB5 status - usb:present=%d type=%d batt:present = %d health = %d charge = %d\n",
2613 usb_present, chg->real_charger_type,
2614 batt_present, batt_health, batt_charge_type);
2615 return rc;
2616}
2617
2618static int smb5_probe(struct platform_device *pdev)
2619{
2620 struct smb5 *chip;
2621 struct smb_charger *chg;
2622 int rc = 0;
2623
2624 chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
2625 if (!chip)
2626 return -ENOMEM;
2627
2628 chg = &chip->chg;
2629 chg->dev = &pdev->dev;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002630 chg->debug_mask = &__debug_mask;
Harry Yang6afaea22018-03-26 19:11:07 -07002631 chg->pd_disabled = &__pd_disabled;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002632 chg->weak_chg_icl_ua = &__weak_chg_icl_ua;
2633 chg->mode = PARALLEL_MASTER;
2634 chg->irq_info = smb5_irqs;
2635 chg->die_health = -EINVAL;
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302636 chg->otg_present = false;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002637
2638 chg->regmap = dev_get_regmap(chg->dev->parent, NULL);
2639 if (!chg->regmap) {
2640 pr_err("parent regmap is missing\n");
2641 return -EINVAL;
2642 }
2643
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302644 rc = smb5_chg_config_init(chip);
2645 if (rc < 0) {
2646 if (rc != -EPROBE_DEFER)
2647 pr_err("Couldn't setup chg_config rc=%d\n", rc);
2648 return rc;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002649 }
2650
Ashay Jaiswalb2b06fe2018-06-07 18:35:21 +05302651 rc = smb5_parse_dt(chip);
2652 if (rc < 0) {
2653 pr_err("Couldn't parse device tree rc=%d\n", rc);
2654 return rc;
2655 }
2656
Harry Yang4b7db0f2017-11-27 10:50:44 -08002657 rc = smblib_init(chg);
2658 if (rc < 0) {
2659 pr_err("Smblib_init failed rc=%d\n", rc);
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302660 return rc;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002661 }
2662
2663 /* set driver data before resources request it */
2664 platform_set_drvdata(pdev, chip);
2665
2666 rc = smb5_init_vbus_regulator(chip);
2667 if (rc < 0) {
2668 pr_err("Couldn't initialize vbus regulator rc=%d\n",
2669 rc);
2670 goto cleanup;
2671 }
2672
2673 rc = smb5_init_vconn_regulator(chip);
2674 if (rc < 0) {
2675 pr_err("Couldn't initialize vconn regulator rc=%d\n",
2676 rc);
2677 goto cleanup;
2678 }
2679
2680 /* extcon registration */
2681 chg->extcon = devm_extcon_dev_allocate(chg->dev, smblib_extcon_cable);
2682 if (IS_ERR(chg->extcon)) {
2683 rc = PTR_ERR(chg->extcon);
2684 dev_err(chg->dev, "failed to allocate extcon device rc=%d\n",
2685 rc);
2686 goto cleanup;
2687 }
2688
2689 rc = devm_extcon_dev_register(chg->dev, chg->extcon);
2690 if (rc < 0) {
2691 dev_err(chg->dev, "failed to register extcon device rc=%d\n",
2692 rc);
2693 goto cleanup;
2694 }
2695
2696 rc = smb5_init_hw(chip);
2697 if (rc < 0) {
2698 pr_err("Couldn't initialize hardware rc=%d\n", rc);
2699 goto cleanup;
2700 }
2701
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302702 if (chg->smb_version == PM855B_SUBTYPE) {
2703 rc = smb5_init_dc_psy(chip);
2704 if (rc < 0) {
2705 pr_err("Couldn't initialize dc psy rc=%d\n", rc);
2706 goto cleanup;
2707 }
Harry Yang4b7db0f2017-11-27 10:50:44 -08002708 }
2709
2710 rc = smb5_init_usb_psy(chip);
2711 if (rc < 0) {
2712 pr_err("Couldn't initialize usb psy rc=%d\n", rc);
2713 goto cleanup;
2714 }
2715
2716 rc = smb5_init_usb_main_psy(chip);
2717 if (rc < 0) {
2718 pr_err("Couldn't initialize usb main psy rc=%d\n", rc);
2719 goto cleanup;
2720 }
2721
2722 rc = smb5_init_usb_port_psy(chip);
2723 if (rc < 0) {
2724 pr_err("Couldn't initialize usb pc_port psy rc=%d\n", rc);
2725 goto cleanup;
2726 }
2727
2728 rc = smb5_init_batt_psy(chip);
2729 if (rc < 0) {
2730 pr_err("Couldn't initialize batt psy rc=%d\n", rc);
2731 goto cleanup;
2732 }
2733
2734 rc = smb5_determine_initial_status(chip);
2735 if (rc < 0) {
2736 pr_err("Couldn't determine initial status rc=%d\n",
2737 rc);
2738 goto cleanup;
2739 }
2740
2741 rc = smb5_request_interrupts(chip);
2742 if (rc < 0) {
2743 pr_err("Couldn't request interrupts rc=%d\n", rc);
2744 goto cleanup;
2745 }
2746
2747 rc = smb5_post_init(chip);
2748 if (rc < 0) {
2749 pr_err("Failed in post init rc=%d\n", rc);
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302750 goto free_irq;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002751 }
2752
2753 smb5_create_debugfs(chip);
2754
2755 rc = smb5_show_charger_status(chip);
2756 if (rc < 0) {
2757 pr_err("Failed in getting charger status rc=%d\n", rc);
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302758 goto free_irq;
Harry Yang4b7db0f2017-11-27 10:50:44 -08002759 }
2760
2761 device_init_wakeup(chg->dev, true);
2762
2763 pr_info("QPNP SMB5 probed successfully\n");
2764
2765 return rc;
2766
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302767free_irq:
Harry Yang4b7db0f2017-11-27 10:50:44 -08002768 smb5_free_interrupts(chg);
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302769cleanup:
Harry Yang4b7db0f2017-11-27 10:50:44 -08002770 smblib_deinit(chg);
2771 platform_set_drvdata(pdev, NULL);
2772
2773 return rc;
2774}
2775
2776static int smb5_remove(struct platform_device *pdev)
2777{
2778 struct smb5 *chip = platform_get_drvdata(pdev);
2779 struct smb_charger *chg = &chip->chg;
2780
Harry Yang6afaea22018-03-26 19:11:07 -07002781 /* force enable APSD */
2782 smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
2783 BC1P2_SRC_DETECT_BIT, BC1P2_SRC_DETECT_BIT);
2784
Harry Yang4b7db0f2017-11-27 10:50:44 -08002785 smb5_free_interrupts(chg);
2786 smblib_deinit(chg);
2787 platform_set_drvdata(pdev, NULL);
2788 return 0;
2789}
2790
2791static void smb5_shutdown(struct platform_device *pdev)
2792{
2793 struct smb5 *chip = platform_get_drvdata(pdev);
2794 struct smb_charger *chg = &chip->chg;
2795
2796 /* disable all interrupts */
2797 smb5_disable_interrupts(chg);
2798
2799 /* configure power role for UFP */
Ashay Jaiswala9e10912018-02-02 14:03:35 +05302800 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_TYPEC)
Harry Yang4b7db0f2017-11-27 10:50:44 -08002801 smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
2802 TYPEC_POWER_ROLE_CMD_MASK, EN_SNK_ONLY_BIT);
2803
2804 /* force HVDCP to 5V */
2805 smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
2806 HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT, 0);
2807 smblib_write(chg, CMD_HVDCP_2_REG, FORCE_5V_BIT);
2808
2809 /* force enable APSD */
2810 smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
2811 BC1P2_SRC_DETECT_BIT, BC1P2_SRC_DETECT_BIT);
2812}
2813
2814static const struct of_device_id match_table[] = {
2815 { .compatible = "qcom,qpnp-smb5", },
2816 { },
2817};
2818
2819static struct platform_driver smb5_driver = {
2820 .driver = {
2821 .name = "qcom,qpnp-smb5",
2822 .owner = THIS_MODULE,
2823 .of_match_table = match_table,
2824 },
2825 .probe = smb5_probe,
2826 .remove = smb5_remove,
2827 .shutdown = smb5_shutdown,
2828};
2829module_platform_driver(smb5_driver);
2830
2831MODULE_DESCRIPTION("QPNP SMB5 Charger Driver");
2832MODULE_LICENSE("GPL v2");