blob: 6facc698aa4dfbc78b84e7cb1c0ed91fc33005fa [file] [log] [blame]
Fenglin Wuf5f49492018-01-09 20:01:48 +08001/* Copyright (c) 2016-2018 The Linux Foundation. All rights reserved.
Nicholas Troast34db5032016-03-28 12:26:44 -07002 *
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/device.h>
14#include <linux/regmap.h>
Harry Yang360bd532016-09-26 11:03:22 -070015#include <linux/delay.h>
Harry Yangba874ce2016-08-19 14:17:01 -070016#include <linux/iio/consumer.h>
Nicholas Troast34db5032016-03-28 12:26:44 -070017#include <linux/power_supply.h>
18#include <linux/regulator/driver.h>
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -080019#include <linux/qpnp/qpnp-revid.h>
Nicholas Troast34db5032016-03-28 12:26:44 -070020#include <linux/irq.h>
Harry Yang0c35ff62017-04-06 00:02:30 -070021#include <linux/pmic-voter.h>
Nicholas Troast34db5032016-03-28 12:26:44 -070022#include "smb-lib.h"
23#include "smb-reg.h"
Harry Yang0c35ff62017-04-06 00:02:30 -070024#include "battery.h"
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +053025#include "step-chg-jeita.h"
Nicholas Troast47ae4612016-08-03 09:49:36 -070026#include "storm-watch.h"
Nicholas Troast34db5032016-03-28 12:26:44 -070027
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -070028#define smblib_err(chg, fmt, ...) \
29 pr_err("%s: %s: " fmt, chg->name, \
30 __func__, ##__VA_ARGS__) \
31
Nicholas Troast34db5032016-03-28 12:26:44 -070032#define smblib_dbg(chg, reason, fmt, ...) \
33 do { \
34 if (*chg->debug_mask & (reason)) \
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -070035 pr_info("%s: %s: " fmt, chg->name, \
36 __func__, ##__VA_ARGS__); \
Nicholas Troast34db5032016-03-28 12:26:44 -070037 else \
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -070038 pr_debug("%s: %s: " fmt, chg->name, \
39 __func__, ##__VA_ARGS__); \
Nicholas Troast34db5032016-03-28 12:26:44 -070040 } while (0)
41
42static bool is_secure(struct smb_charger *chg, int addr)
43{
Anirudh Ghayal4da3df92017-01-25 18:55:57 +053044 if (addr == SHIP_MODE_REG || addr == FREQ_CLK_DIV_REG)
Fenglin Wuedd70792016-11-22 13:16:19 +080045 return true;
Harry Yang47bd3852016-10-17 10:37:12 -070046 /* assume everything above 0xA0 is secure */
47 return (bool)((addr & 0xFF) >= 0xA0);
Nicholas Troast34db5032016-03-28 12:26:44 -070048}
49
50int smblib_read(struct smb_charger *chg, u16 addr, u8 *val)
51{
52 unsigned int temp;
53 int rc = 0;
54
55 rc = regmap_read(chg->regmap, addr, &temp);
56 if (rc >= 0)
57 *val = (u8)temp;
58
59 return rc;
60}
61
Ashay Jaiswal6d308da2017-02-18 09:59:23 +053062int smblib_multibyte_read(struct smb_charger *chg, u16 addr, u8 *val,
63 int count)
64{
65 return regmap_bulk_read(chg->regmap, addr, val, count);
66}
67
Nicholas Troast34db5032016-03-28 12:26:44 -070068int smblib_masked_write(struct smb_charger *chg, u16 addr, u8 mask, u8 val)
69{
Nicholas Troast34db5032016-03-28 12:26:44 -070070 int rc = 0;
71
Harry Yangbacd2222016-05-11 16:43:51 -070072 mutex_lock(&chg->write_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -070073 if (is_secure(chg, addr)) {
74 rc = regmap_write(chg->regmap, (addr & 0xFF00) | 0xD0, 0xA5);
75 if (rc < 0)
76 goto unlock;
77 }
78
79 rc = regmap_update_bits(chg->regmap, addr, mask, val);
80
81unlock:
Harry Yangbacd2222016-05-11 16:43:51 -070082 mutex_unlock(&chg->write_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -070083 return rc;
84}
85
86int smblib_write(struct smb_charger *chg, u16 addr, u8 val)
87{
Nicholas Troast34db5032016-03-28 12:26:44 -070088 int rc = 0;
89
Harry Yangbacd2222016-05-11 16:43:51 -070090 mutex_lock(&chg->write_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -070091
92 if (is_secure(chg, addr)) {
93 rc = regmap_write(chg->regmap, (addr & ~(0xFF)) | 0xD0, 0xA5);
94 if (rc < 0)
95 goto unlock;
96 }
97
98 rc = regmap_write(chg->regmap, addr, val);
99
100unlock:
Harry Yangbacd2222016-05-11 16:43:51 -0700101 mutex_unlock(&chg->write_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -0700102 return rc;
103}
104
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -0700105static int smblib_get_jeita_cc_delta(struct smb_charger *chg, int *cc_delta_ua)
106{
107 int rc, cc_minus_ua;
108 u8 stat;
Harry Yangfe913842016-08-10 12:27:28 -0700109
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -0700110 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat);
111 if (rc < 0) {
112 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
113 rc);
114 return rc;
115 }
116
117 if (!(stat & BAT_TEMP_STATUS_SOFT_LIMIT_MASK)) {
118 *cc_delta_ua = 0;
119 return 0;
120 }
121
122 rc = smblib_get_charge_param(chg, &chg->param.jeita_cc_comp,
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +0530123 &cc_minus_ua);
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -0700124 if (rc < 0) {
125 smblib_err(chg, "Couldn't get jeita cc minus rc=%d\n", rc);
126 return rc;
127 }
128
129 *cc_delta_ua = -cc_minus_ua;
130 return 0;
131}
132
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800133int smblib_icl_override(struct smb_charger *chg, bool override)
134{
135 int rc;
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800136
Nicholas Troast11af51b2017-03-15 10:45:28 -0700137 rc = smblib_masked_write(chg, USBIN_LOAD_CFG_REG,
138 ICL_OVERRIDE_AFTER_APSD_BIT,
139 override ? ICL_OVERRIDE_AFTER_APSD_BIT : 0);
140 if (rc < 0)
141 smblib_err(chg, "Couldn't override ICL rc=%d\n", rc);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -0800142
Nicholas Troast11af51b2017-03-15 10:45:28 -0700143 return rc;
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800144}
145
Harry Yang166b15d2017-08-28 13:00:40 -0700146int smblib_stat_sw_override_cfg(struct smb_charger *chg, bool override)
147{
148 int rc;
149
150 /* override = 1, SW STAT override; override = 0, HW auto mode */
151 rc = smblib_masked_write(chg, STAT_CFG_REG,
152 STAT_SW_OVERRIDE_CFG_BIT,
153 override ? STAT_SW_OVERRIDE_CFG_BIT : 0);
154 if (rc < 0) {
155 dev_err(chg->dev, "Couldn't configure SW STAT override rc=%d\n",
156 rc);
157 return rc;
158 }
159
160 return rc;
161}
162
Nicholas Troast34db5032016-03-28 12:26:44 -0700163/********************
164 * REGISTER GETTERS *
165 ********************/
166
Nicholas Troast4c310492016-05-12 17:56:35 -0700167int smblib_get_charge_param(struct smb_charger *chg,
168 struct smb_chg_param *param, int *val_u)
169{
170 int rc = 0;
171 u8 val_raw;
172
173 rc = smblib_read(chg, param->reg, &val_raw);
174 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700175 smblib_err(chg, "%s: Couldn't read from 0x%04x rc=%d\n",
Nicholas Troast4c310492016-05-12 17:56:35 -0700176 param->name, param->reg, rc);
177 return rc;
178 }
179
Harry Yangf8b41252016-08-10 14:21:10 -0700180 if (param->get_proc)
181 *val_u = param->get_proc(param, val_raw);
182 else
183 *val_u = val_raw * param->step_u + param->min_u;
Nicholas Troast4c310492016-05-12 17:56:35 -0700184 smblib_dbg(chg, PR_REGISTER, "%s = %d (0x%02x)\n",
185 param->name, *val_u, val_raw);
186
187 return rc;
188}
189
190int smblib_get_usb_suspend(struct smb_charger *chg, int *suspend)
191{
192 int rc = 0;
193 u8 temp;
194
195 rc = smblib_read(chg, USBIN_CMD_IL_REG, &temp);
196 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700197 smblib_err(chg, "Couldn't read USBIN_CMD_IL rc=%d\n", rc);
Nicholas Troast4c310492016-05-12 17:56:35 -0700198 return rc;
199 }
200 *suspend = temp & USBIN_SUSPEND_BIT;
201
202 return rc;
203}
204
Nicholas Troast34db5032016-03-28 12:26:44 -0700205struct apsd_result {
206 const char * const name;
207 const u8 bit;
208 const enum power_supply_type pst;
209};
210
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700211enum {
212 UNKNOWN,
213 SDP,
214 CDP,
215 DCP,
216 OCP,
217 FLOAT,
218 HVDCP2,
219 HVDCP3,
220 MAX_TYPES
221};
222
Nicholas Troast34db5032016-03-28 12:26:44 -0700223static const struct apsd_result const smblib_apsd_results[] = {
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700224 [UNKNOWN] = {
225 .name = "UNKNOWN",
226 .bit = 0,
227 .pst = POWER_SUPPLY_TYPE_UNKNOWN
228 },
229 [SDP] = {
230 .name = "SDP",
231 .bit = SDP_CHARGER_BIT,
232 .pst = POWER_SUPPLY_TYPE_USB
233 },
234 [CDP] = {
235 .name = "CDP",
236 .bit = CDP_CHARGER_BIT,
237 .pst = POWER_SUPPLY_TYPE_USB_CDP
238 },
239 [DCP] = {
240 .name = "DCP",
241 .bit = DCP_CHARGER_BIT,
242 .pst = POWER_SUPPLY_TYPE_USB_DCP
243 },
244 [OCP] = {
245 .name = "OCP",
246 .bit = OCP_CHARGER_BIT,
247 .pst = POWER_SUPPLY_TYPE_USB_DCP
248 },
249 [FLOAT] = {
250 .name = "FLOAT",
251 .bit = FLOAT_CHARGER_BIT,
Ashay Jaiswalb9b2d2f2017-06-21 12:08:38 +0530252 .pst = POWER_SUPPLY_TYPE_USB_FLOAT
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700253 },
254 [HVDCP2] = {
255 .name = "HVDCP2",
256 .bit = DCP_CHARGER_BIT | QC_2P0_BIT,
257 .pst = POWER_SUPPLY_TYPE_USB_HVDCP
258 },
259 [HVDCP3] = {
260 .name = "HVDCP3",
261 .bit = DCP_CHARGER_BIT | QC_3P0_BIT,
262 .pst = POWER_SUPPLY_TYPE_USB_HVDCP_3,
263 },
Nicholas Troast34db5032016-03-28 12:26:44 -0700264};
265
266static const struct apsd_result *smblib_get_apsd_result(struct smb_charger *chg)
267{
268 int rc, i;
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700269 u8 apsd_stat, stat;
270 const struct apsd_result *result = &smblib_apsd_results[UNKNOWN];
Nicholas Troast34db5032016-03-28 12:26:44 -0700271
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700272 rc = smblib_read(chg, APSD_STATUS_REG, &apsd_stat);
Nicholas Troast34db5032016-03-28 12:26:44 -0700273 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700274 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700275 return result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700276 }
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700277 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", apsd_stat);
Nicholas Troast34db5032016-03-28 12:26:44 -0700278
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700279 if (!(apsd_stat & APSD_DTC_STATUS_DONE_BIT))
280 return result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700281
282 rc = smblib_read(chg, APSD_RESULT_STATUS_REG, &stat);
283 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700284 smblib_err(chg, "Couldn't read APSD_RESULT_STATUS rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700285 rc);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700286 return result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700287 }
288 stat &= APSD_RESULT_STATUS_MASK;
289
290 for (i = 0; i < ARRAY_SIZE(smblib_apsd_results); i++) {
291 if (smblib_apsd_results[i].bit == stat)
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700292 result = &smblib_apsd_results[i];
Nicholas Troast34db5032016-03-28 12:26:44 -0700293 }
294
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700295 if (apsd_stat & QC_CHARGER_BIT) {
296 /* since its a qc_charger, either return HVDCP3 or HVDCP2 */
297 if (result != &smblib_apsd_results[HVDCP3])
298 result = &smblib_apsd_results[HVDCP2];
299 }
300
301 return result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700302}
303
Nicholas Troast34db5032016-03-28 12:26:44 -0700304/********************
305 * REGISTER SETTERS *
306 ********************/
307
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530308static int chg_freq_list[] = {
309 9600, 9600, 6400, 4800, 3800, 3200, 2700, 2400, 2100, 1900, 1700,
310 1600, 1500, 1400, 1300, 1200,
311};
312
313int smblib_set_chg_freq(struct smb_chg_param *param,
314 int val_u, u8 *val_raw)
315{
316 u8 i;
317
318 if (val_u > param->max_u || val_u < param->min_u)
319 return -EINVAL;
320
321 /* Charger FSW is the configured freqency / 2 */
322 val_u *= 2;
323 for (i = 0; i < ARRAY_SIZE(chg_freq_list); i++) {
324 if (chg_freq_list[i] == val_u)
325 break;
326 }
327 if (i == ARRAY_SIZE(chg_freq_list)) {
328 pr_err("Invalid frequency %d Hz\n", val_u / 2);
329 return -EINVAL;
330 }
331
332 *val_raw = i;
333
334 return 0;
335}
336
337static int smblib_set_opt_freq_buck(struct smb_charger *chg, int fsw_khz)
338{
339 union power_supply_propval pval = {0, };
340 int rc = 0;
341
342 rc = smblib_set_charge_param(chg, &chg->param.freq_buck, fsw_khz);
343 if (rc < 0)
344 dev_err(chg->dev, "Error in setting freq_buck rc=%d\n", rc);
345
346 if (chg->mode == PARALLEL_MASTER && chg->pl.psy) {
347 pval.intval = fsw_khz;
Abhijeet Dharmapurikare9fd08d2017-02-27 11:05:28 -0800348 /*
349 * Some parallel charging implementations may not have
350 * PROP_BUCK_FREQ property - they could be running
351 * with a fixed frequency
352 */
353 power_supply_set_property(chg->pl.psy,
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530354 POWER_SUPPLY_PROP_BUCK_FREQ, &pval);
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530355 }
356
357 return rc;
358}
359
Nicholas Troast4c310492016-05-12 17:56:35 -0700360int smblib_set_charge_param(struct smb_charger *chg,
361 struct smb_chg_param *param, int val_u)
Nicholas Troast34db5032016-03-28 12:26:44 -0700362{
363 int rc = 0;
364 u8 val_raw;
365
Harry Yangf8b41252016-08-10 14:21:10 -0700366 if (param->set_proc) {
367 rc = param->set_proc(param, val_u, &val_raw);
368 if (rc < 0)
369 return -EINVAL;
370 } else {
371 if (val_u > param->max_u || val_u < param->min_u) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700372 smblib_err(chg, "%s: %d is out of range [%d, %d]\n",
Harry Yangf8b41252016-08-10 14:21:10 -0700373 param->name, val_u, param->min_u, param->max_u);
374 return -EINVAL;
375 }
376
377 val_raw = (val_u - param->min_u) / param->step_u;
Nicholas Troast34db5032016-03-28 12:26:44 -0700378 }
379
Nicholas Troast34db5032016-03-28 12:26:44 -0700380 rc = smblib_write(chg, param->reg, val_raw);
381 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700382 smblib_err(chg, "%s: Couldn't write 0x%02x to 0x%04x rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700383 param->name, val_raw, param->reg, rc);
384 return rc;
385 }
386
387 smblib_dbg(chg, PR_REGISTER, "%s = %d (0x%02x)\n",
388 param->name, val_u, val_raw);
389
390 return rc;
391}
392
Nicholas Troast4c310492016-05-12 17:56:35 -0700393int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend)
Nicholas Troast34db5032016-03-28 12:26:44 -0700394{
395 int rc = 0;
Abhijeet Dharmapurikar109802f712017-07-07 18:30:54 -0700396 int irq = chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq;
397
398 if (suspend && irq) {
399 if (chg->usb_icl_change_irq_enabled) {
400 disable_irq_nosync(irq);
401 chg->usb_icl_change_irq_enabled = false;
402 }
403 }
Nicholas Troast34db5032016-03-28 12:26:44 -0700404
405 rc = smblib_masked_write(chg, USBIN_CMD_IL_REG, USBIN_SUSPEND_BIT,
406 suspend ? USBIN_SUSPEND_BIT : 0);
407 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700408 smblib_err(chg, "Couldn't write %s to USBIN_SUSPEND_BIT rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700409 suspend ? "suspend" : "resume", rc);
410
Abhijeet Dharmapurikar109802f712017-07-07 18:30:54 -0700411 if (!suspend && irq) {
412 if (!chg->usb_icl_change_irq_enabled) {
413 enable_irq(irq);
414 chg->usb_icl_change_irq_enabled = true;
415 }
416 }
417
Nicholas Troast34db5032016-03-28 12:26:44 -0700418 return rc;
419}
420
Nicholas Troast4c310492016-05-12 17:56:35 -0700421int smblib_set_dc_suspend(struct smb_charger *chg, bool suspend)
Nicholas Troast34db5032016-03-28 12:26:44 -0700422{
423 int rc = 0;
424
425 rc = smblib_masked_write(chg, DCIN_CMD_IL_REG, DCIN_SUSPEND_BIT,
426 suspend ? DCIN_SUSPEND_BIT : 0);
427 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700428 smblib_err(chg, "Couldn't write %s to DCIN_SUSPEND_BIT rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700429 suspend ? "suspend" : "resume", rc);
430
431 return rc;
432}
433
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530434static int smblib_set_adapter_allowance(struct smb_charger *chg,
435 u8 allowed_voltage)
436{
437 int rc = 0;
438
Nicholas Troast7f55c922017-07-25 13:18:03 -0700439 /* PM660 only support max. 9V */
440 if (chg->smb_version == PM660_SUBTYPE) {
441 switch (allowed_voltage) {
442 case USBIN_ADAPTER_ALLOW_12V:
443 case USBIN_ADAPTER_ALLOW_9V_TO_12V:
444 allowed_voltage = USBIN_ADAPTER_ALLOW_9V;
445 break;
446 case USBIN_ADAPTER_ALLOW_5V_OR_12V:
447 case USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V:
448 allowed_voltage = USBIN_ADAPTER_ALLOW_5V_OR_9V;
449 break;
450 case USBIN_ADAPTER_ALLOW_5V_TO_12V:
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530451 allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_9V;
Nicholas Troast7f55c922017-07-25 13:18:03 -0700452 break;
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530453 }
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530454 }
455
456 rc = smblib_write(chg, USBIN_ADAPTER_ALLOW_CFG_REG, allowed_voltage);
457 if (rc < 0) {
458 smblib_err(chg, "Couldn't write 0x%02x to USBIN_ADAPTER_ALLOW_CFG rc=%d\n",
459 allowed_voltage, rc);
460 return rc;
461 }
462
463 return rc;
464}
465
Nicholas Troast34db5032016-03-28 12:26:44 -0700466#define MICRO_5V 5000000
467#define MICRO_9V 9000000
468#define MICRO_12V 12000000
469static int smblib_set_usb_pd_allowed_voltage(struct smb_charger *chg,
470 int min_allowed_uv, int max_allowed_uv)
471{
472 int rc;
473 u8 allowed_voltage;
474
475 if (min_allowed_uv == MICRO_5V && max_allowed_uv == MICRO_5V) {
476 allowed_voltage = USBIN_ADAPTER_ALLOW_5V;
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530477 smblib_set_opt_freq_buck(chg, chg->chg_freq.freq_5V);
Nicholas Troast34db5032016-03-28 12:26:44 -0700478 } else if (min_allowed_uv == MICRO_9V && max_allowed_uv == MICRO_9V) {
479 allowed_voltage = USBIN_ADAPTER_ALLOW_9V;
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530480 smblib_set_opt_freq_buck(chg, chg->chg_freq.freq_9V);
Nicholas Troast34db5032016-03-28 12:26:44 -0700481 } else if (min_allowed_uv == MICRO_12V && max_allowed_uv == MICRO_12V) {
482 allowed_voltage = USBIN_ADAPTER_ALLOW_12V;
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530483 smblib_set_opt_freq_buck(chg, chg->chg_freq.freq_12V);
Nicholas Troast34db5032016-03-28 12:26:44 -0700484 } else if (min_allowed_uv < MICRO_9V && max_allowed_uv <= MICRO_9V) {
485 allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_9V;
486 } else if (min_allowed_uv < MICRO_9V && max_allowed_uv <= MICRO_12V) {
487 allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_12V;
488 } else if (min_allowed_uv < MICRO_12V && max_allowed_uv <= MICRO_12V) {
489 allowed_voltage = USBIN_ADAPTER_ALLOW_9V_TO_12V;
490 } else {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700491 smblib_err(chg, "invalid allowed voltage [%d, %d]\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700492 min_allowed_uv, max_allowed_uv);
493 return -EINVAL;
494 }
495
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530496 rc = smblib_set_adapter_allowance(chg, allowed_voltage);
Nicholas Troast34db5032016-03-28 12:26:44 -0700497 if (rc < 0) {
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530498 smblib_err(chg, "Couldn't configure adapter allowance rc=%d\n",
499 rc);
Nicholas Troast34db5032016-03-28 12:26:44 -0700500 return rc;
501 }
502
503 return rc;
504}
505
506/********************
507 * HELPER FUNCTIONS *
508 ********************/
Ashay Jaiswal13a1b812017-07-17 14:49:05 +0530509static int smblib_request_dpdm(struct smb_charger *chg, bool enable)
510{
511 int rc = 0;
512
513 /* fetch the DPDM regulator */
514 if (!chg->dpdm_reg && of_get_property(chg->dev->of_node,
515 "dpdm-supply", NULL)) {
516 chg->dpdm_reg = devm_regulator_get(chg->dev, "dpdm");
517 if (IS_ERR(chg->dpdm_reg)) {
518 rc = PTR_ERR(chg->dpdm_reg);
519 smblib_err(chg, "Couldn't get dpdm regulator rc=%d\n",
520 rc);
521 chg->dpdm_reg = NULL;
522 return rc;
523 }
524 }
525
526 if (enable) {
527 if (chg->dpdm_reg && !regulator_is_enabled(chg->dpdm_reg)) {
528 smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n");
529 rc = regulator_enable(chg->dpdm_reg);
530 if (rc < 0)
531 smblib_err(chg,
532 "Couldn't enable dpdm regulator rc=%d\n",
533 rc);
534 }
535 } else {
536 if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) {
537 smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n");
538 rc = regulator_disable(chg->dpdm_reg);
539 if (rc < 0)
540 smblib_err(chg,
541 "Couldn't disable dpdm regulator rc=%d\n",
542 rc);
543 }
544 }
545
546 return rc;
547}
Nicholas Troast34db5032016-03-28 12:26:44 -0700548
Nicholas Troast93fb0f02017-03-01 10:17:13 -0800549static void smblib_rerun_apsd(struct smb_charger *chg)
550{
551 int rc;
552
553 smblib_dbg(chg, PR_MISC, "re-running APSD\n");
554 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
555 rc = smblib_masked_write(chg,
556 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
557 AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
558 if (rc < 0)
559 smblib_err(chg, "Couldn't enable HVDCP auth IRQ rc=%d\n",
560 rc);
561 }
562
563 rc = smblib_masked_write(chg, CMD_APSD_REG,
564 APSD_RERUN_BIT, APSD_RERUN_BIT);
565 if (rc < 0)
566 smblib_err(chg, "Couldn't re-run APSD rc=%d\n", rc);
567}
568
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -0700569static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -0700570{
Abhijeet Dharmapurikareda08222016-11-01 11:35:29 -0700571 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -0700572
Jack Pham9696e252016-05-23 11:15:15 -0700573 /* if PD is active, APSD is disabled so won't have a valid result */
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +0530574 if (chg->pd_active) {
Fenglin Wu80826e02017-04-25 21:45:08 +0800575 chg->real_charger_type = POWER_SUPPLY_TYPE_USB_PD;
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +0530576 } else {
577 /*
578 * Update real charger type only if its not FLOAT
579 * detected as as SDP
580 */
581 if (!(apsd_result->pst == POWER_SUPPLY_TYPE_USB_FLOAT &&
582 chg->real_charger_type == POWER_SUPPLY_TYPE_USB))
Fenglin Wu80826e02017-04-25 21:45:08 +0800583 chg->real_charger_type = apsd_result->pst;
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +0530584 }
Nicholas Troast34db5032016-03-28 12:26:44 -0700585
Nicholas Troast93fb0f02017-03-01 10:17:13 -0800586 smblib_dbg(chg, PR_MISC, "APSD=%s PD=%d\n",
587 apsd_result->name, chg->pd_active);
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -0700588 return apsd_result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700589}
590
Harry Yang5e1a5222016-07-26 15:16:04 -0700591static int smblib_notifier_call(struct notifier_block *nb,
Harry Yang58a9e7a2016-06-23 14:54:43 -0700592 unsigned long ev, void *v)
Harry Yang1d1034c2016-06-15 12:09:42 -0700593{
Harry Yang58a9e7a2016-06-23 14:54:43 -0700594 struct power_supply *psy = v;
Harry Yang5e1a5222016-07-26 15:16:04 -0700595 struct smb_charger *chg = container_of(nb, struct smb_charger, nb);
Harry Yang1d1034c2016-06-15 12:09:42 -0700596
Harry Yang5e1a5222016-07-26 15:16:04 -0700597 if (!strcmp(psy->desc->name, "bms")) {
598 if (!chg->bms_psy)
599 chg->bms_psy = psy;
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530600 if (ev == PSY_EVENT_PROP_CHANGED)
Harry Yang5e1a5222016-07-26 15:16:04 -0700601 schedule_work(&chg->bms_update_work);
602 }
603
Harry Yang166b15d2017-08-28 13:00:40 -0700604 if (!chg->pl.psy && !strcmp(psy->desc->name, "parallel")) {
Harry Yang58a9e7a2016-06-23 14:54:43 -0700605 chg->pl.psy = psy;
Harry Yang166b15d2017-08-28 13:00:40 -0700606 schedule_work(&chg->pl_update_work);
607 }
Harry Yang1d1034c2016-06-15 12:09:42 -0700608
Harry Yang58a9e7a2016-06-23 14:54:43 -0700609 return NOTIFY_OK;
610}
611
Harry Yang5e1a5222016-07-26 15:16:04 -0700612static int smblib_register_notifier(struct smb_charger *chg)
Harry Yang58a9e7a2016-06-23 14:54:43 -0700613{
614 int rc;
615
Harry Yang5e1a5222016-07-26 15:16:04 -0700616 chg->nb.notifier_call = smblib_notifier_call;
617 rc = power_supply_reg_notifier(&chg->nb);
Harry Yang58a9e7a2016-06-23 14:54:43 -0700618 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700619 smblib_err(chg, "Couldn't register psy notifier rc = %d\n", rc);
Harry Yang58a9e7a2016-06-23 14:54:43 -0700620 return rc;
621 }
622
623 return 0;
Harry Yang1d1034c2016-06-15 12:09:42 -0700624}
625
Harry Yangfe913842016-08-10 12:27:28 -0700626int smblib_mapping_soc_from_field_value(struct smb_chg_param *param,
627 int val_u, u8 *val_raw)
628{
629 if (val_u > param->max_u || val_u < param->min_u)
630 return -EINVAL;
631
632 *val_raw = val_u << 1;
633
634 return 0;
635}
636
637int smblib_mapping_cc_delta_to_field_value(struct smb_chg_param *param,
638 u8 val_raw)
639{
640 int val_u = val_raw * param->step_u + param->min_u;
641
642 if (val_u > param->max_u)
643 val_u -= param->max_u * 2;
644
645 return val_u;
646}
647
648int smblib_mapping_cc_delta_from_field_value(struct smb_chg_param *param,
649 int val_u, u8 *val_raw)
650{
651 if (val_u > param->max_u || val_u < param->min_u - param->max_u)
652 return -EINVAL;
653
654 val_u += param->max_u * 2 - param->min_u;
655 val_u %= param->max_u * 2;
656 *val_raw = val_u / param->step_u;
657
658 return 0;
659}
660
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530661static void smblib_uusb_removal(struct smb_charger *chg)
662{
663 int rc;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +0530664 struct smb_irq_data *data;
665 struct storm_watch *wdata;
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530666
Ashay Jaiswalc0361672017-03-21 12:24:16 +0530667 cancel_delayed_work_sync(&chg->pl_enable_work);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +0530668
Ashay Jaiswal13a1b812017-07-17 14:49:05 +0530669 rc = smblib_request_dpdm(chg, false);
670 if (rc < 0)
671 smblib_err(chg, "Couldn't to disable DPDM rc=%d\n", rc);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +0530672
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +0530673 if (chg->wa_flags & BOOST_BACK_WA) {
674 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
675 if (data) {
676 wdata = &data->storm_data;
677 update_storm_count(wdata, WEAK_CHG_STORM_COUNT);
678 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
679 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
680 false, 0);
681 }
682 }
Ashay Jaiswalc0361672017-03-21 12:24:16 +0530683 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
684 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
685
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530686 /* reset both usbin current and voltage votes */
687 vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
688 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
Ashay Jaiswalae23a042017-05-18 15:28:31 +0530689 vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
Ashay Jaiswal3d22f4b2017-11-15 18:09:19 +0530690 vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0);
Ashay Jaiswal1c360c82018-03-15 23:24:42 +0530691 vote(chg->usb_icl_votable, HVDCP2_ICL_VOTER, false, 0);
Umang Agrawal49680b62018-04-16 14:41:11 +0530692 vote(chg->hvdcp_hw_inov_dis_votable, OV_VOTER, false, 0);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530693
694 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
695
Ashay Jaiswal67ec7072017-02-16 14:14:58 +0530696 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
697 /* re-enable AUTH_IRQ_EN_CFG_BIT */
698 rc = smblib_masked_write(chg,
699 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
700 AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
701 if (rc < 0)
702 smblib_err(chg,
703 "Couldn't enable QC auth setting rc=%d\n", rc);
704 }
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530705
706 /* reconfigure allowed voltage for HVDCP */
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530707 rc = smblib_set_adapter_allowance(chg,
708 USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530709 if (rc < 0)
710 smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
711 rc);
712
713 chg->voltage_min_uv = MICRO_5V;
714 chg->voltage_max_uv = MICRO_5V;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +0530715 chg->usb_icl_delta_ua = 0;
716 chg->pulse_cnt = 0;
Ashay Jaiswal8507aa52017-04-14 09:42:32 +0530717 chg->uusb_apsd_rerun_done = false;
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530718
719 /* clear USB ICL vote for USB_PSY_VOTER */
720 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
721 if (rc < 0)
722 smblib_err(chg, "Couldn't un-vote for USB ICL rc=%d\n", rc);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -0800723
724 /* clear USB ICL vote for DCP_VOTER */
725 rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
726 if (rc < 0)
727 smblib_err(chg,
728 "Couldn't un-vote DCP from USB ICL rc=%d\n", rc);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530729}
730
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530731void smblib_suspend_on_debug_battery(struct smb_charger *chg)
732{
733 int rc;
734 union power_supply_propval val;
735
Ashay Jaiswalda8669b2017-02-10 23:24:23 +0530736 if (!chg->suspend_input_on_debug_batt)
737 return;
738
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530739 rc = power_supply_get_property(chg->bms_psy,
740 POWER_SUPPLY_PROP_DEBUG_BATTERY, &val);
741 if (rc < 0) {
742 smblib_err(chg, "Couldn't get debug battery prop rc=%d\n", rc);
743 return;
744 }
745
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800746 vote(chg->usb_icl_votable, DEBUG_BOARD_VOTER, val.intval, 0);
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530747 vote(chg->dc_suspend_votable, DEBUG_BOARD_VOTER, val.intval, 0);
748 if (val.intval)
749 pr_info("Input suspended: Fake battery\n");
750}
751
Abhijeet Dharmapurikar9dd61292017-01-25 16:40:08 -0800752int smblib_rerun_apsd_if_required(struct smb_charger *chg)
753{
Abhijeet Dharmapurikar9dd61292017-01-25 16:40:08 -0800754 union power_supply_propval val;
755 int rc;
756
757 rc = smblib_get_prop_usb_present(chg, &val);
758 if (rc < 0) {
759 smblib_err(chg, "Couldn't get usb present rc = %d\n", rc);
760 return rc;
761 }
762
763 if (!val.intval)
764 return 0;
765
Ashay Jaiswal13a1b812017-07-17 14:49:05 +0530766 rc = smblib_request_dpdm(chg, true);
767 if (rc < 0)
768 smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
Abhijeet Dharmapurikar025e63a2017-02-24 14:06:22 -0800769
Ashay Jaiswal8507aa52017-04-14 09:42:32 +0530770 chg->uusb_apsd_rerun_done = true;
Abhijeet Dharmapurikar025e63a2017-02-24 14:06:22 -0800771 smblib_rerun_apsd(chg);
772
Abhijeet Dharmapurikar9dd61292017-01-25 16:40:08 -0800773 return 0;
774}
775
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +0530776static int smblib_get_hw_pulse_cnt(struct smb_charger *chg, int *count)
Ashay Jaiswal6d308da2017-02-18 09:59:23 +0530777{
778 int rc;
779 u8 val[2];
780
781 switch (chg->smb_version) {
782 case PMI8998_SUBTYPE:
783 rc = smblib_read(chg, QC_PULSE_COUNT_STATUS_REG, val);
784 if (rc) {
785 pr_err("failed to read QC_PULSE_COUNT_STATUS_REG rc=%d\n",
786 rc);
787 return rc;
788 }
789 *count = val[0] & QC_PULSE_COUNT_MASK;
790 break;
791 case PM660_SUBTYPE:
792 rc = smblib_multibyte_read(chg,
793 QC_PULSE_COUNT_STATUS_1_REG, val, 2);
794 if (rc) {
795 pr_err("failed to read QC_PULSE_COUNT_STATUS_1_REG rc=%d\n",
796 rc);
797 return rc;
798 }
799 *count = (val[1] << 8) | val[0];
800 break;
801 default:
802 smblib_dbg(chg, PR_PARALLEL, "unknown SMB chip %d\n",
803 chg->smb_version);
804 return -EINVAL;
805 }
806
807 return 0;
808}
809
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +0530810static int smblib_get_pulse_cnt(struct smb_charger *chg, int *count)
811{
812 int rc;
813
814 /* Use software based pulse count if HW INOV is disabled */
815 if (get_effective_result(chg->hvdcp_hw_inov_dis_votable) > 0) {
816 *count = chg->pulse_cnt;
817 return 0;
818 }
819
820 /* Use h/w pulse count if autonomous mode is enabled */
821 rc = smblib_get_hw_pulse_cnt(chg, count);
822 if (rc < 0)
823 smblib_err(chg, "failed to read h/w pulse count rc=%d\n", rc);
824
825 return rc;
826}
827
Nicholas Troastbb76a142016-09-23 11:23:23 -0700828#define USBIN_25MA 25000
829#define USBIN_100MA 100000
830#define USBIN_150MA 150000
831#define USBIN_500MA 500000
832#define USBIN_900MA 900000
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800833
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800834static int set_sdp_current(struct smb_charger *chg, int icl_ua)
Nicholas Troast34db5032016-03-28 12:26:44 -0700835{
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800836 int rc;
837 u8 icl_options;
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +0530838 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700839
Nicholas Troastbb76a142016-09-23 11:23:23 -0700840 /* power source is SDP */
841 switch (icl_ua) {
842 case USBIN_100MA:
843 /* USB 2.0 100mA */
844 icl_options = 0;
845 break;
846 case USBIN_150MA:
847 /* USB 3.0 150mA */
848 icl_options = CFG_USB3P0_SEL_BIT;
849 break;
850 case USBIN_500MA:
851 /* USB 2.0 500mA */
852 icl_options = USB51_MODE_BIT;
853 break;
854 case USBIN_900MA:
855 /* USB 3.0 900mA */
856 icl_options = CFG_USB3P0_SEL_BIT | USB51_MODE_BIT;
857 break;
858 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700859 smblib_err(chg, "ICL %duA isn't supported for SDP\n", icl_ua);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800860 return -EINVAL;
Nicholas Troastbb76a142016-09-23 11:23:23 -0700861 }
Nicholas Troast34db5032016-03-28 12:26:44 -0700862
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +0530863 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB &&
864 apsd_result->pst == POWER_SUPPLY_TYPE_USB_FLOAT) {
865 /*
866 * change the float charger configuration to SDP, if this
867 * is the case of SDP being detected as FLOAT
868 */
869 rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
870 FORCE_FLOAT_SDP_CFG_BIT, FORCE_FLOAT_SDP_CFG_BIT);
871 if (rc < 0) {
872 smblib_err(chg, "Couldn't set float ICL options rc=%d\n",
873 rc);
874 return rc;
875 }
876 }
877
Nicholas Troastbb76a142016-09-23 11:23:23 -0700878 rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800879 CFG_USB3P0_SEL_BIT | USB51_MODE_BIT, icl_options);
Nicholas Troast34db5032016-03-28 12:26:44 -0700880 if (rc < 0) {
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800881 smblib_err(chg, "Couldn't set ICL options rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -0700882 return rc;
883 }
884
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800885 return rc;
886}
887
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700888static int get_sdp_current(struct smb_charger *chg, int *icl_ua)
889{
890 int rc;
891 u8 icl_options;
892 bool usb3 = false;
893
894 rc = smblib_read(chg, USBIN_ICL_OPTIONS_REG, &icl_options);
895 if (rc < 0) {
896 smblib_err(chg, "Couldn't get ICL options rc=%d\n", rc);
897 return rc;
898 }
899
900 usb3 = (icl_options & CFG_USB3P0_SEL_BIT);
901
902 if (icl_options & USB51_MODE_BIT)
903 *icl_ua = usb3 ? USBIN_900MA : USBIN_500MA;
904 else
905 *icl_ua = usb3 ? USBIN_150MA : USBIN_100MA;
906
907 return rc;
908}
909
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530910int smblib_set_icl_current(struct smb_charger *chg, int icl_ua)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800911{
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800912 int rc = 0;
913 bool override;
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800914
915 /* suspend and return if 25mA or less is requested */
Harry Yang379484a2017-08-29 10:26:14 -0700916 if (icl_ua <= USBIN_25MA)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800917 return smblib_set_usb_suspend(chg, true);
918
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530919 if (icl_ua == INT_MAX)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800920 goto override_suspend_config;
921
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800922 /* configure current */
Nicholas Troaste1932e42017-04-12 12:38:18 -0700923 if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
Fenglin Wu80826e02017-04-25 21:45:08 +0800924 && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) {
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800925 rc = set_sdp_current(chg, icl_ua);
926 if (rc < 0) {
927 smblib_err(chg, "Couldn't set SDP ICL rc=%d\n", rc);
928 goto enable_icl_changed_interrupt;
929 }
930 } else {
Abhijeet Dharmapurikar949d67e2017-05-25 15:10:56 -0700931 set_sdp_current(chg, 100000);
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -0700932 rc = smblib_set_charge_param(chg, &chg->param.usb_icl, icl_ua);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800933 if (rc < 0) {
934 smblib_err(chg, "Couldn't set HC ICL rc=%d\n", rc);
935 goto enable_icl_changed_interrupt;
936 }
937 }
938
939override_suspend_config:
940 /* determine if override needs to be enforced */
941 override = true;
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530942 if (icl_ua == INT_MAX) {
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800943 /* remove override if no voters - hw defaults is desired */
944 override = false;
Nicholas Troaste1932e42017-04-12 12:38:18 -0700945 } else if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
Fenglin Wu80826e02017-04-25 21:45:08 +0800946 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800947 /* For std cable with type = SDP never override */
948 override = false;
Fenglin Wu80826e02017-04-25 21:45:08 +0800949 else if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_CDP
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -0700950 && icl_ua == 1500000)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800951 /*
952 * For std cable with type = CDP override only if
953 * current is not 1500mA
954 */
955 override = false;
956 }
957
958 /* enforce override */
959 rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
960 USBIN_MODE_CHG_BIT, override ? USBIN_MODE_CHG_BIT : 0);
961
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800962 rc = smblib_icl_override(chg, override);
963 if (rc < 0) {
964 smblib_err(chg, "Couldn't set ICL override rc=%d\n", rc);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800965 goto enable_icl_changed_interrupt;
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800966 }
967
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800968 /* unsuspend after configuring current and override */
969 rc = smblib_set_usb_suspend(chg, false);
970 if (rc < 0) {
971 smblib_err(chg, "Couldn't resume input rc=%d\n", rc);
972 goto enable_icl_changed_interrupt;
973 }
974
975enable_icl_changed_interrupt:
Nicholas Troast34db5032016-03-28 12:26:44 -0700976 return rc;
977}
978
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700979int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua)
980{
981 int rc = 0;
982 u8 load_cfg;
983 bool override;
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700984
Ashay Jaiswal0ce2c7c2017-11-14 12:29:02 +0530985 if (((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT)
986 || (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB))
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700987 && (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)) {
988 rc = get_sdp_current(chg, icl_ua);
989 if (rc < 0) {
990 smblib_err(chg, "Couldn't get SDP ICL rc=%d\n", rc);
991 return rc;
992 }
993 } else {
994 rc = smblib_read(chg, USBIN_LOAD_CFG_REG, &load_cfg);
995 if (rc < 0) {
996 smblib_err(chg, "Couldn't get load cfg rc=%d\n", rc);
997 return rc;
998 }
999 override = load_cfg & ICL_OVERRIDE_AFTER_APSD_BIT;
1000 if (!override)
1001 return INT_MAX;
1002
1003 /* override is set */
1004 rc = smblib_get_charge_param(chg, &chg->param.usb_icl, icl_ua);
1005 if (rc < 0) {
1006 smblib_err(chg, "Couldn't get HC ICL rc=%d\n", rc);
1007 return rc;
1008 }
1009 }
1010
1011 return 0;
1012}
1013
Umang Agrawal527728a2018-03-15 13:31:32 +05301014int smblib_toggle_stat(struct smb_charger *chg, int reset)
1015{
1016 int rc = 0;
1017
1018 if (reset) {
1019 rc = smblib_masked_write(chg, STAT_CFG_REG,
1020 STAT_SW_OVERRIDE_CFG_BIT | STAT_SW_OVERRIDE_VALUE_BIT,
1021 STAT_SW_OVERRIDE_CFG_BIT | 0);
1022 if (rc < 0) {
1023 smblib_err(chg,
1024 "Couldn't pull STAT pin low rc=%d\n", rc);
1025 return rc;
1026 }
1027
1028 /*
1029 * A minimum of 20us delay is expected before switching on STAT
1030 * pin
1031 */
1032 usleep_range(20, 30);
1033
1034 rc = smblib_masked_write(chg, STAT_CFG_REG,
1035 STAT_SW_OVERRIDE_CFG_BIT | STAT_SW_OVERRIDE_VALUE_BIT,
1036 STAT_SW_OVERRIDE_CFG_BIT | STAT_SW_OVERRIDE_VALUE_BIT);
1037 if (rc < 0) {
1038 smblib_err(chg,
1039 "Couldn't pull STAT pin high rc=%d\n", rc);
1040 return rc;
1041 }
1042
1043 rc = smblib_masked_write(chg, STAT_CFG_REG,
1044 STAT_SW_OVERRIDE_CFG_BIT | STAT_SW_OVERRIDE_VALUE_BIT,
1045 0);
1046 if (rc < 0) {
1047 smblib_err(chg,
1048 "Couldn't set hardware control rc=%d\n", rc);
1049 return rc;
1050 }
1051 }
1052
1053 return rc;
1054}
1055
Tirupathi Reddy0c5d0a52017-09-27 16:31:07 +05301056static int smblib_micro_usb_disable_power_role_switch(struct smb_charger *chg,
1057 bool disable)
1058{
1059 int rc = 0;
1060 u8 power_role;
1061
1062 power_role = disable ? TYPEC_DISABLE_CMD_BIT : 0;
1063 /* Disable pullup on CC1_ID pin and stop detection on CC pins */
1064 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1065 (uint8_t)TYPEC_POWER_ROLE_CMD_MASK,
1066 power_role);
1067 if (rc < 0) {
1068 smblib_err(chg, "Couldn't write 0x%02x to TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
1069 power_role, rc);
1070 return rc;
1071 }
1072
1073 if (disable) {
1074 /* configure TypeC mode */
1075 rc = smblib_masked_write(chg, TYPE_C_CFG_REG,
1076 TYPE_C_OR_U_USB_BIT, 0);
1077 if (rc < 0) {
1078 smblib_err(chg, "Couldn't configure typec mode rc=%d\n",
1079 rc);
1080 return rc;
1081 }
1082
1083 /* wait for FSM to enter idle state */
1084 usleep_range(5000, 5100);
1085
1086 /* configure micro USB mode */
1087 rc = smblib_masked_write(chg, TYPE_C_CFG_REG,
1088 TYPE_C_OR_U_USB_BIT,
1089 TYPE_C_OR_U_USB_BIT);
1090 if (rc < 0) {
1091 smblib_err(chg, "Couldn't configure micro USB mode rc=%d\n",
1092 rc);
1093 return rc;
1094 }
1095 }
1096
1097 return rc;
1098}
1099
1100static int __smblib_set_prop_typec_power_role(struct smb_charger *chg,
1101 const union power_supply_propval *val)
1102{
1103 int rc = 0;
1104 u8 power_role;
1105
1106 switch (val->intval) {
1107 case POWER_SUPPLY_TYPEC_PR_NONE:
1108 power_role = TYPEC_DISABLE_CMD_BIT;
1109 break;
1110 case POWER_SUPPLY_TYPEC_PR_DUAL:
1111 power_role = 0;
1112 break;
1113 case POWER_SUPPLY_TYPEC_PR_SINK:
1114 power_role = UFP_EN_CMD_BIT;
1115 break;
1116 case POWER_SUPPLY_TYPEC_PR_SOURCE:
1117 power_role = DFP_EN_CMD_BIT;
1118 break;
1119 default:
1120 smblib_err(chg, "power role %d not supported\n", val->intval);
1121 return -EINVAL;
1122 }
1123
1124 if (power_role == UFP_EN_CMD_BIT) {
1125 /* disable PBS workaround when forcing sink mode */
1126 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0x0);
1127 if (rc < 0) {
1128 smblib_err(chg, "Couldn't write to TM_IO_DTEST4_SEL rc=%d\n",
1129 rc);
1130 }
1131 } else {
1132 /* restore it back to 0xA5 */
1133 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
1134 if (rc < 0) {
1135 smblib_err(chg, "Couldn't write to TM_IO_DTEST4_SEL rc=%d\n",
1136 rc);
1137 }
1138 }
1139
1140 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1141 TYPEC_POWER_ROLE_CMD_MASK, power_role);
1142 if (rc < 0) {
1143 smblib_err(chg, "Couldn't write 0x%02x to TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
1144 power_role, rc);
1145 return rc;
1146 }
1147
1148 return rc;
1149}
1150
Ashay Jaiswalae1586d2017-03-22 23:18:51 +05301151/*********************
1152 * VOTABLE CALLBACKS *
1153 *********************/
1154
1155static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data,
1156 int suspend, const char *client)
1157{
1158 struct smb_charger *chg = data;
1159
1160 /* resume input if suspend is invalid */
1161 if (suspend < 0)
1162 suspend = 0;
1163
1164 return smblib_set_dc_suspend(chg, (bool)suspend);
1165}
1166
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001167static int smblib_dc_icl_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -07001168 int icl_ua, const char *client)
Nicholas Troast34db5032016-03-28 12:26:44 -07001169{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001170 struct smb_charger *chg = data;
Nicholas Troast34db5032016-03-28 12:26:44 -07001171 int rc = 0;
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001172 bool suspend;
1173
1174 if (icl_ua < 0) {
1175 smblib_dbg(chg, PR_MISC, "No Voter hence suspending\n");
1176 icl_ua = 0;
1177 }
1178
Harry Yang379484a2017-08-29 10:26:14 -07001179 suspend = (icl_ua <= USBIN_25MA);
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001180 if (suspend)
1181 goto suspend;
Nicholas Troast34db5032016-03-28 12:26:44 -07001182
1183 rc = smblib_set_charge_param(chg, &chg->param.dc_icl, icl_ua);
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001184 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001185 smblib_err(chg, "Couldn't set DC input current limit rc=%d\n",
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001186 rc);
1187 return rc;
1188 }
1189
1190suspend:
1191 rc = vote(chg->dc_suspend_votable, USER_VOTER, suspend, 0);
1192 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001193 smblib_err(chg, "Couldn't vote to %s DC rc=%d\n",
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001194 suspend ? "suspend" : "resume", rc);
1195 return rc;
1196 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001197 return rc;
1198}
1199
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07001200static int smblib_pd_disallowed_votable_indirect_callback(
1201 struct votable *votable, void *data, int disallowed, const char *client)
1202{
1203 struct smb_charger *chg = data;
1204 int rc;
1205
1206 rc = vote(chg->pd_allowed_votable, PD_DISALLOWED_INDIRECT_VOTER,
1207 !disallowed, 0);
1208
1209 return rc;
1210}
1211
Harry Yang223c6282016-06-14 15:48:36 -07001212static int smblib_awake_vote_callback(struct votable *votable, void *data,
1213 int awake, const char *client)
1214{
1215 struct smb_charger *chg = data;
1216
1217 if (awake)
1218 pm_stay_awake(chg->dev);
1219 else
1220 pm_relax(chg->dev);
1221
1222 return 0;
1223}
1224
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07001225static int smblib_chg_disable_vote_callback(struct votable *votable, void *data,
1226 int chg_disable, const char *client)
1227{
1228 struct smb_charger *chg = data;
1229 int rc;
1230
1231 rc = smblib_masked_write(chg, CHARGING_ENABLE_CMD_REG,
1232 CHARGING_ENABLE_CMD_BIT,
1233 chg_disable ? 0 : CHARGING_ENABLE_CMD_BIT);
1234 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001235 smblib_err(chg, "Couldn't %s charging rc=%d\n",
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07001236 chg_disable ? "disable" : "enable", rc);
1237 return rc;
1238 }
1239
1240 return 0;
1241}
Harry Yangaba1f5f2016-09-28 10:47:29 -07001242
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301243static int smblib_hvdcp_enable_vote_callback(struct votable *votable,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001244 void *data,
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301245 int hvdcp_enable, const char *client)
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001246{
1247 struct smb_charger *chg = data;
1248 int rc;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301249 u8 val = HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_EN_BIT;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07001250 u8 stat;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301251
1252 /* vote to enable/disable HW autonomous INOV */
1253 vote(chg->hvdcp_hw_inov_dis_votable, client, !hvdcp_enable, 0);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001254
1255 /*
1256 * Disable the autonomous bit and auth bit for disabling hvdcp.
1257 * This ensures only qc 2.0 detection runs but no vbus
1258 * negotiation happens.
1259 */
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301260 if (!hvdcp_enable)
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001261 val = HVDCP_EN_BIT;
1262
1263 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301264 HVDCP_EN_BIT | HVDCP_AUTH_ALG_EN_CFG_BIT,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001265 val);
1266 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001267 smblib_err(chg, "Couldn't %s hvdcp rc=%d\n",
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301268 hvdcp_enable ? "enable" : "disable", rc);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001269 return rc;
1270 }
1271
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07001272 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
1273 if (rc < 0) {
1274 smblib_err(chg, "Couldn't read APSD status rc=%d\n", rc);
1275 return rc;
1276 }
1277
1278 /* re-run APSD if HVDCP was detected */
1279 if (stat & QC_CHARGER_BIT)
1280 smblib_rerun_apsd(chg);
1281
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001282 return 0;
1283}
1284
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301285static int smblib_hvdcp_disable_indirect_vote_callback(struct votable *votable,
1286 void *data, int hvdcp_disable, const char *client)
1287{
1288 struct smb_charger *chg = data;
1289
1290 vote(chg->hvdcp_enable_votable, HVDCP_INDIRECT_VOTER,
1291 !hvdcp_disable, 0);
1292
1293 return 0;
1294}
1295
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07001296static int smblib_apsd_disable_vote_callback(struct votable *votable,
1297 void *data,
1298 int apsd_disable, const char *client)
1299{
1300 struct smb_charger *chg = data;
1301 int rc;
1302
Nicholas Troastec4703c2017-01-30 14:52:33 -08001303 if (apsd_disable) {
Nicholas Troastec4703c2017-01-30 14:52:33 -08001304 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1305 AUTO_SRC_DETECT_BIT,
1306 0);
1307 if (rc < 0) {
1308 smblib_err(chg, "Couldn't disable APSD rc=%d\n", rc);
1309 return rc;
1310 }
1311 } else {
1312 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1313 AUTO_SRC_DETECT_BIT,
1314 AUTO_SRC_DETECT_BIT);
1315 if (rc < 0) {
1316 smblib_err(chg, "Couldn't enable APSD rc=%d\n", rc);
1317 return rc;
1318 }
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07001319 }
1320
1321 return 0;
1322}
Nicholas Troast8995a702016-12-05 10:22:22 -08001323
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301324static int smblib_hvdcp_hw_inov_dis_vote_callback(struct votable *votable,
1325 void *data, int disable, const char *client)
1326{
1327 struct smb_charger *chg = data;
1328 int rc;
1329
1330 if (disable) {
1331 /*
1332 * the pulse count register get zeroed when autonomous mode is
1333 * disabled. Track that in variables before disabling
1334 */
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +05301335 rc = smblib_get_hw_pulse_cnt(chg, &chg->pulse_cnt);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301336 if (rc < 0) {
1337 pr_err("failed to read QC_PULSE_COUNT_STATUS_REG rc=%d\n",
1338 rc);
1339 return rc;
1340 }
1341 }
1342
1343 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1344 HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT,
1345 disable ? 0 : HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT);
1346 if (rc < 0) {
1347 smblib_err(chg, "Couldn't %s hvdcp rc=%d\n",
1348 disable ? "disable" : "enable", rc);
1349 return rc;
1350 }
1351
1352 return rc;
1353}
1354
Harry Yang4bf7d962017-03-13 16:51:43 -07001355static int smblib_usb_irq_enable_vote_callback(struct votable *votable,
1356 void *data, int enable, const char *client)
1357{
1358 struct smb_charger *chg = data;
1359
1360 if (!chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq ||
1361 !chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq)
1362 return 0;
1363
1364 if (enable) {
1365 enable_irq(chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq);
1366 enable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
1367 } else {
1368 disable_irq(chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq);
1369 disable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
1370 }
1371
1372 return 0;
1373}
1374
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07001375static int smblib_typec_irq_disable_vote_callback(struct votable *votable,
1376 void *data, int disable, const char *client)
1377{
1378 struct smb_charger *chg = data;
1379
1380 if (!chg->irq_info[TYPE_C_CHANGE_IRQ].irq)
1381 return 0;
1382
1383 if (disable)
1384 disable_irq_nosync(chg->irq_info[TYPE_C_CHANGE_IRQ].irq);
1385 else
1386 enable_irq(chg->irq_info[TYPE_C_CHANGE_IRQ].irq);
1387
1388 return 0;
1389}
1390
Tirupathi Reddy0c5d0a52017-09-27 16:31:07 +05301391static int smblib_disable_power_role_switch_callback(struct votable *votable,
1392 void *data, int disable, const char *client)
1393{
1394 struct smb_charger *chg = data;
1395 union power_supply_propval pval;
1396 int rc = 0;
1397
1398 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) {
1399 rc = smblib_micro_usb_disable_power_role_switch(chg, disable);
1400 } else {
1401 pval.intval = disable ? POWER_SUPPLY_TYPEC_PR_SINK
1402 : POWER_SUPPLY_TYPEC_PR_DUAL;
1403 rc = __smblib_set_prop_typec_power_role(chg, &pval);
1404 }
1405
1406 if (rc)
1407 smblib_err(chg, "power_role_switch = %s failed, rc=%d\n",
1408 disable ? "disabled" : "enabled", rc);
1409 else
1410 smblib_dbg(chg, PR_MISC, "power_role_switch = %s\n",
1411 disable ? "disabled" : "enabled");
1412
1413 return rc;
1414}
1415
Nicholas Troast8995a702016-12-05 10:22:22 -08001416/*******************
1417 * VCONN REGULATOR *
1418 * *****************/
1419
Nicholas Troastb11015f2017-01-17 17:56:45 -08001420#define MAX_OTG_SS_TRIES 2
Nicholas Troast8995a702016-12-05 10:22:22 -08001421static int _smblib_vconn_regulator_enable(struct regulator_dev *rdev)
1422{
1423 struct smb_charger *chg = rdev_get_drvdata(rdev);
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001424 int rc = 0;
1425 u8 val;
Nicholas Troast8995a702016-12-05 10:22:22 -08001426
1427 /*
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001428 * When enabling VCONN using the command register the CC pin must be
1429 * selected. VCONN should be supplied to the inactive CC pin hence using
1430 * the opposite of the CC_ORIENTATION_BIT.
Nicholas Troast8995a702016-12-05 10:22:22 -08001431 */
Nicholas Troastb11015f2017-01-17 17:56:45 -08001432 smblib_dbg(chg, PR_OTG, "enabling VCONN\n");
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07001433 val = chg->typec_status[3] &
1434 CC_ORIENTATION_BIT ? 0 : VCONN_EN_ORIENTATION_BIT;
Nicholas Troast8995a702016-12-05 10:22:22 -08001435 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1436 VCONN_EN_VALUE_BIT | VCONN_EN_ORIENTATION_BIT,
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07001437 VCONN_EN_VALUE_BIT | val);
Nicholas Troast8995a702016-12-05 10:22:22 -08001438 if (rc < 0) {
1439 smblib_err(chg, "Couldn't enable vconn setting rc=%d\n", rc);
1440 return rc;
1441 }
1442
1443 return rc;
1444}
1445
1446int smblib_vconn_regulator_enable(struct regulator_dev *rdev)
1447{
1448 struct smb_charger *chg = rdev_get_drvdata(rdev);
1449 int rc = 0;
1450
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001451 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001452 if (chg->vconn_en)
1453 goto unlock;
1454
1455 rc = _smblib_vconn_regulator_enable(rdev);
1456 if (rc >= 0)
1457 chg->vconn_en = true;
1458
1459unlock:
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001460 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001461 return rc;
1462}
1463
1464static int _smblib_vconn_regulator_disable(struct regulator_dev *rdev)
1465{
1466 struct smb_charger *chg = rdev_get_drvdata(rdev);
1467 int rc = 0;
1468
Nicholas Troastb11015f2017-01-17 17:56:45 -08001469 smblib_dbg(chg, PR_OTG, "disabling VCONN\n");
Nicholas Troast8995a702016-12-05 10:22:22 -08001470 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1471 VCONN_EN_VALUE_BIT, 0);
1472 if (rc < 0)
1473 smblib_err(chg, "Couldn't disable vconn regulator rc=%d\n", rc);
1474
1475 return rc;
1476}
1477
1478int smblib_vconn_regulator_disable(struct regulator_dev *rdev)
1479{
1480 struct smb_charger *chg = rdev_get_drvdata(rdev);
1481 int rc = 0;
1482
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001483 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001484 if (!chg->vconn_en)
1485 goto unlock;
1486
1487 rc = _smblib_vconn_regulator_disable(rdev);
1488 if (rc >= 0)
1489 chg->vconn_en = false;
1490
1491unlock:
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001492 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001493 return rc;
1494}
1495
1496int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev)
1497{
1498 struct smb_charger *chg = rdev_get_drvdata(rdev);
1499 int ret;
1500
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001501 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001502 ret = chg->vconn_en;
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001503 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001504 return ret;
1505}
1506
Nicholas Troast34db5032016-03-28 12:26:44 -07001507/*****************
1508 * OTG REGULATOR *
1509 *****************/
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301510#define MAX_RETRY 15
1511#define MIN_DELAY_US 2000
1512#define MAX_DELAY_US 9000
Anirudh Ghayaladf20da2017-07-03 10:52:29 +05301513static int otg_current[] = {250000, 500000, 1000000, 1500000};
1514static int smblib_enable_otg_wa(struct smb_charger *chg)
1515{
1516 u8 stat;
1517 int rc, i, retry_count = 0, min_delay = MIN_DELAY_US;
1518
1519 for (i = 0; i < ARRAY_SIZE(otg_current); i++) {
1520 smblib_dbg(chg, PR_OTG, "enabling OTG with %duA\n",
1521 otg_current[i]);
1522 rc = smblib_set_charge_param(chg, &chg->param.otg_cl,
1523 otg_current[i]);
1524 if (rc < 0) {
1525 smblib_err(chg, "Couldn't set otg limit rc=%d\n", rc);
1526 return rc;
1527 }
1528
1529 rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT);
1530 if (rc < 0) {
1531 smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc);
1532 return rc;
1533 }
1534
1535 retry_count = 0;
1536 min_delay = MIN_DELAY_US;
1537 do {
1538 usleep_range(min_delay, min_delay + 100);
1539 rc = smblib_read(chg, OTG_STATUS_REG, &stat);
1540 if (rc < 0) {
1541 smblib_err(chg, "Couldn't read OTG status rc=%d\n",
1542 rc);
1543 goto out;
1544 }
1545
1546 if (stat & BOOST_SOFTSTART_DONE_BIT) {
1547 rc = smblib_set_charge_param(chg,
1548 &chg->param.otg_cl, chg->otg_cl_ua);
1549 if (rc < 0) {
1550 smblib_err(chg, "Couldn't set otg limit rc=%d\n",
1551 rc);
1552 goto out;
1553 }
1554 break;
1555 }
1556 /* increase the delay for following iterations */
1557 if (retry_count > 5)
1558 min_delay = MAX_DELAY_US;
1559
1560 } while (retry_count++ < MAX_RETRY);
1561
1562 if (retry_count >= MAX_RETRY) {
1563 smblib_dbg(chg, PR_OTG, "OTG enable failed with %duA\n",
1564 otg_current[i]);
1565 rc = smblib_write(chg, CMD_OTG_REG, 0);
1566 if (rc < 0) {
1567 smblib_err(chg, "disable OTG rc=%d\n", rc);
1568 goto out;
1569 }
1570 } else {
1571 smblib_dbg(chg, PR_OTG, "OTG enabled\n");
1572 return 0;
1573 }
1574 }
1575
1576 if (i == ARRAY_SIZE(otg_current)) {
1577 rc = -EINVAL;
1578 goto out;
1579 }
1580
1581 return 0;
1582out:
1583 smblib_write(chg, CMD_OTG_REG, 0);
1584 return rc;
1585}
1586
Nicholas Troast8995a702016-12-05 10:22:22 -08001587static int _smblib_vbus_regulator_enable(struct regulator_dev *rdev)
Nicholas Troast34db5032016-03-28 12:26:44 -07001588{
1589 struct smb_charger *chg = rdev_get_drvdata(rdev);
Anirudh Ghayaladf20da2017-07-03 10:52:29 +05301590 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001591
Nicholas Troastb11015f2017-01-17 17:56:45 -08001592 smblib_dbg(chg, PR_OTG, "halt 1 in 8 mode\n");
Harry Yang360bd532016-09-26 11:03:22 -07001593 rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
1594 ENG_BUCKBOOST_HALT1_8_MODE_BIT,
1595 ENG_BUCKBOOST_HALT1_8_MODE_BIT);
1596 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001597 smblib_err(chg, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n",
Harry Yang360bd532016-09-26 11:03:22 -07001598 rc);
1599 return rc;
1600 }
1601
Nicholas Troastb11015f2017-01-17 17:56:45 -08001602 smblib_dbg(chg, PR_OTG, "enabling OTG\n");
Harry Yang360bd532016-09-26 11:03:22 -07001603
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301604 if (chg->wa_flags & OTG_WA) {
Anirudh Ghayaladf20da2017-07-03 10:52:29 +05301605 rc = smblib_enable_otg_wa(chg);
1606 if (rc < 0)
1607 smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc);
1608 } else {
1609 rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT);
1610 if (rc < 0)
1611 smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc);
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301612 }
1613
Nicholas Troast34db5032016-03-28 12:26:44 -07001614 return rc;
1615}
1616
Nicholas Troast8995a702016-12-05 10:22:22 -08001617int smblib_vbus_regulator_enable(struct regulator_dev *rdev)
Nicholas Troast34db5032016-03-28 12:26:44 -07001618{
1619 struct smb_charger *chg = rdev_get_drvdata(rdev);
1620 int rc = 0;
1621
Nicholas Troastb11015f2017-01-17 17:56:45 -08001622 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001623 if (chg->otg_en)
1624 goto unlock;
1625
Harry Yanga2fb0e32017-03-22 22:45:25 -07001626 if (!chg->usb_icl_votable) {
1627 chg->usb_icl_votable = find_votable("USB_ICL");
1628
Harry Yang4e619b42017-12-06 10:13:21 -08001629 if (!chg->usb_icl_votable) {
1630 rc = -EINVAL;
1631 goto unlock;
1632 }
Harry Yanga2fb0e32017-03-22 22:45:25 -07001633 }
1634 vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, true, 0);
1635
Nicholas Troast8995a702016-12-05 10:22:22 -08001636 rc = _smblib_vbus_regulator_enable(rdev);
1637 if (rc >= 0)
1638 chg->otg_en = true;
Ashay Jaiswal3d22f4b2017-11-15 18:09:19 +05301639 else
1640 vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0);
Nicholas Troast8995a702016-12-05 10:22:22 -08001641
1642unlock:
Nicholas Troastb11015f2017-01-17 17:56:45 -08001643 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001644 return rc;
1645}
1646
1647static int _smblib_vbus_regulator_disable(struct regulator_dev *rdev)
1648{
1649 struct smb_charger *chg = rdev_get_drvdata(rdev);
1650 int rc;
Nicholas Troast8995a702016-12-05 10:22:22 -08001651
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301652 if (chg->wa_flags & OTG_WA) {
1653 /* set OTG current limit to minimum value */
1654 rc = smblib_set_charge_param(chg, &chg->param.otg_cl,
1655 chg->param.otg_cl.min_u);
1656 if (rc < 0) {
1657 smblib_err(chg,
1658 "Couldn't set otg current limit rc=%d\n", rc);
1659 return rc;
1660 }
1661 }
1662
Nicholas Troastb11015f2017-01-17 17:56:45 -08001663 smblib_dbg(chg, PR_OTG, "disabling OTG\n");
Harry Yang360bd532016-09-26 11:03:22 -07001664 rc = smblib_write(chg, CMD_OTG_REG, 0);
1665 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001666 smblib_err(chg, "Couldn't disable OTG regulator rc=%d\n", rc);
Harry Yang360bd532016-09-26 11:03:22 -07001667 return rc;
1668 }
1669
Nicholas Troastb11015f2017-01-17 17:56:45 -08001670 smblib_dbg(chg, PR_OTG, "start 1 in 8 mode\n");
Harry Yang360bd532016-09-26 11:03:22 -07001671 rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
1672 ENG_BUCKBOOST_HALT1_8_MODE_BIT, 0);
1673 if (rc < 0) {
Nicholas Troast8995a702016-12-05 10:22:22 -08001674 smblib_err(chg, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n", rc);
Harry Yang360bd532016-09-26 11:03:22 -07001675 return rc;
1676 }
1677
Nicholas Troast8995a702016-12-05 10:22:22 -08001678 return 0;
1679}
Nicholas Troast34db5032016-03-28 12:26:44 -07001680
Nicholas Troast8995a702016-12-05 10:22:22 -08001681int smblib_vbus_regulator_disable(struct regulator_dev *rdev)
1682{
1683 struct smb_charger *chg = rdev_get_drvdata(rdev);
1684 int rc = 0;
1685
Nicholas Troastb11015f2017-01-17 17:56:45 -08001686 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001687 if (!chg->otg_en)
1688 goto unlock;
1689
1690 rc = _smblib_vbus_regulator_disable(rdev);
1691 if (rc >= 0)
1692 chg->otg_en = false;
1693
Harry Yanga2fb0e32017-03-22 22:45:25 -07001694 if (chg->usb_icl_votable)
1695 vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0);
Nicholas Troast8995a702016-12-05 10:22:22 -08001696unlock:
Nicholas Troastb11015f2017-01-17 17:56:45 -08001697 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07001698 return rc;
1699}
1700
1701int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev)
1702{
1703 struct smb_charger *chg = rdev_get_drvdata(rdev);
Nicholas Troast8995a702016-12-05 10:22:22 -08001704 int ret;
Nicholas Troast34db5032016-03-28 12:26:44 -07001705
Nicholas Troastb11015f2017-01-17 17:56:45 -08001706 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001707 ret = chg->otg_en;
Nicholas Troastb11015f2017-01-17 17:56:45 -08001708 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001709 return ret;
Nicholas Troast34db5032016-03-28 12:26:44 -07001710}
1711
1712/********************
1713 * BATT PSY GETTERS *
1714 ********************/
1715
1716int smblib_get_prop_input_suspend(struct smb_charger *chg,
1717 union power_supply_propval *val)
1718{
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08001719 val->intval
1720 = (get_client_vote(chg->usb_icl_votable, USER_VOTER) == 0)
1721 && get_client_vote(chg->dc_suspend_votable, USER_VOTER);
Nicholas Troast34db5032016-03-28 12:26:44 -07001722 return 0;
1723}
1724
1725int smblib_get_prop_batt_present(struct smb_charger *chg,
1726 union power_supply_propval *val)
1727{
1728 int rc;
1729 u8 stat;
1730
1731 rc = smblib_read(chg, BATIF_BASE + INT_RT_STS_OFFSET, &stat);
1732 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001733 smblib_err(chg, "Couldn't read BATIF_INT_RT_STS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07001734 return rc;
1735 }
1736
1737 val->intval = !(stat & (BAT_THERM_OR_ID_MISSING_RT_STS_BIT
1738 | BAT_TERMINAL_MISSING_RT_STS_BIT));
1739
1740 return rc;
1741}
1742
1743int smblib_get_prop_batt_capacity(struct smb_charger *chg,
1744 union power_supply_propval *val)
1745{
Harry Yang5e1a5222016-07-26 15:16:04 -07001746 int rc = -EINVAL;
1747
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07001748 if (chg->fake_capacity >= 0) {
1749 val->intval = chg->fake_capacity;
1750 return 0;
1751 }
1752
Harry Yang5e1a5222016-07-26 15:16:04 -07001753 if (chg->bms_psy)
1754 rc = power_supply_get_property(chg->bms_psy,
1755 POWER_SUPPLY_PROP_CAPACITY, val);
1756 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001757}
1758
1759int smblib_get_prop_batt_status(struct smb_charger *chg,
1760 union power_supply_propval *val)
1761{
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001762 union power_supply_propval pval = {0, };
Abhijeet Dharmapurikard97b2bf2017-07-06 17:03:00 -07001763 bool usb_online, dc_online, qnovo_en;
1764 u8 stat, pt_en_cmd;
Nicholas Troast8cb77552016-09-23 11:50:18 -07001765 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001766
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001767 rc = smblib_get_prop_usb_online(chg, &pval);
1768 if (rc < 0) {
1769 smblib_err(chg, "Couldn't get usb online property rc=%d\n",
1770 rc);
1771 return rc;
1772 }
1773 usb_online = (bool)pval.intval;
1774
1775 rc = smblib_get_prop_dc_online(chg, &pval);
1776 if (rc < 0) {
1777 smblib_err(chg, "Couldn't get dc online property rc=%d\n",
1778 rc);
1779 return rc;
1780 }
1781 dc_online = (bool)pval.intval;
1782
Nicholas Troast34db5032016-03-28 12:26:44 -07001783 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1784 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001785 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001786 rc);
1787 return rc;
1788 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001789 stat = stat & BATTERY_CHARGER_STATUS_MASK;
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001790
1791 if (!usb_online && !dc_online) {
1792 switch (stat) {
1793 case TERMINATE_CHARGE:
1794 case INHIBIT_CHARGE:
1795 val->intval = POWER_SUPPLY_STATUS_FULL;
1796 break;
1797 default:
1798 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
1799 break;
1800 }
1801 return rc;
1802 }
1803
Nicholas Troast8cb77552016-09-23 11:50:18 -07001804 switch (stat) {
1805 case TRICKLE_CHARGE:
1806 case PRE_CHARGE:
1807 case FAST_CHARGE:
1808 case FULLON_CHARGE:
1809 case TAPER_CHARGE:
Nicholas Troast34db5032016-03-28 12:26:44 -07001810 val->intval = POWER_SUPPLY_STATUS_CHARGING;
Nicholas Troast8cb77552016-09-23 11:50:18 -07001811 break;
1812 case TERMINATE_CHARGE:
1813 case INHIBIT_CHARGE:
1814 val->intval = POWER_SUPPLY_STATUS_FULL;
1815 break;
1816 case DISABLE_CHARGE:
1817 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
1818 break;
1819 default:
1820 val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
1821 break;
1822 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001823
Harry Yang7ecc1a12017-04-06 12:24:56 -07001824 if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
1825 return 0;
1826
Harry Yang589dd422017-07-28 18:41:42 -07001827 if (!usb_online && dc_online
1828 && chg->fake_batt_status == POWER_SUPPLY_STATUS_FULL) {
1829 val->intval = POWER_SUPPLY_STATUS_FULL;
1830 return 0;
1831 }
1832
Harry Yangc3c28d12017-04-17 16:41:19 -07001833 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_7_REG, &stat);
Harry Yang7ecc1a12017-04-06 12:24:56 -07001834 if (rc < 0) {
1835 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
1836 rc);
1837 return rc;
Abhijeet Dharmapurikard97b2bf2017-07-06 17:03:00 -07001838 }
Harry Yang7ecc1a12017-04-06 12:24:56 -07001839
Harry Yangc3c28d12017-04-17 16:41:19 -07001840 stat &= ENABLE_TRICKLE_BIT | ENABLE_PRE_CHARGING_BIT |
1841 ENABLE_FAST_CHARGING_BIT | ENABLE_FULLON_MODE_BIT;
Abhijeet Dharmapurikard97b2bf2017-07-06 17:03:00 -07001842
1843 rc = smblib_read(chg, QNOVO_PT_ENABLE_CMD_REG, &pt_en_cmd);
1844 if (rc < 0) {
1845 smblib_err(chg, "Couldn't read QNOVO_PT_ENABLE_CMD_REG rc=%d\n",
1846 rc);
1847 return rc;
1848 }
1849
1850 qnovo_en = (bool)(pt_en_cmd & QNOVO_PT_ENABLE_CMD_BIT);
1851
1852 /* ignore stat7 when qnovo is enabled */
1853 if (!qnovo_en && !stat)
Harry Yang7ecc1a12017-04-06 12:24:56 -07001854 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
1855
Nicholas Troast8cb77552016-09-23 11:50:18 -07001856 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07001857}
1858
1859int smblib_get_prop_batt_charge_type(struct smb_charger *chg,
1860 union power_supply_propval *val)
1861{
1862 int rc;
1863 u8 stat;
1864
1865 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1866 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001867 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001868 rc);
1869 return rc;
1870 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001871
1872 switch (stat & BATTERY_CHARGER_STATUS_MASK) {
1873 case TRICKLE_CHARGE:
1874 case PRE_CHARGE:
1875 val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1876 break;
1877 case FAST_CHARGE:
1878 case FULLON_CHARGE:
1879 val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
1880 break;
1881 case TAPER_CHARGE:
1882 val->intval = POWER_SUPPLY_CHARGE_TYPE_TAPER;
1883 break;
1884 default:
1885 val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
1886 }
1887
1888 return rc;
1889}
1890
1891int smblib_get_prop_batt_health(struct smb_charger *chg,
1892 union power_supply_propval *val)
1893{
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001894 union power_supply_propval pval;
Nicholas Troast34db5032016-03-28 12:26:44 -07001895 int rc;
Abhijeet Dharmapurikar33d18462017-05-15 13:38:53 -07001896 int effective_fv_uv;
Nicholas Troast34db5032016-03-28 12:26:44 -07001897 u8 stat;
1898
1899 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat);
1900 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001901 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001902 rc);
1903 return rc;
1904 }
1905 smblib_dbg(chg, PR_REGISTER, "BATTERY_CHARGER_STATUS_2 = 0x%02x\n",
1906 stat);
1907
1908 if (stat & CHARGER_ERROR_STATUS_BAT_OV_BIT) {
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001909 rc = smblib_get_prop_batt_voltage_now(chg, &pval);
1910 if (!rc) {
1911 /*
1912 * If Vbatt is within 40mV above Vfloat, then don't
1913 * treat it as overvoltage.
1914 */
Abhijeet Dharmapurikar33d18462017-05-15 13:38:53 -07001915 effective_fv_uv = get_effective_result(chg->fv_votable);
1916 if (pval.intval >= effective_fv_uv + 40000) {
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001917 val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
Abhijeet Dharmapurikar33d18462017-05-15 13:38:53 -07001918 smblib_err(chg, "battery over-voltage vbat_fg = %duV, fv = %duV\n",
1919 pval.intval, effective_fv_uv);
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001920 goto done;
1921 }
1922 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001923 }
1924
Harry Yang668fc5e2016-07-12 16:51:47 -07001925 if (stat & BAT_TEMP_STATUS_TOO_COLD_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001926 val->intval = POWER_SUPPLY_HEALTH_COLD;
Harry Yang668fc5e2016-07-12 16:51:47 -07001927 else if (stat & BAT_TEMP_STATUS_TOO_HOT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001928 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
Harry Yang668fc5e2016-07-12 16:51:47 -07001929 else if (stat & BAT_TEMP_STATUS_COLD_SOFT_LIMIT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001930 val->intval = POWER_SUPPLY_HEALTH_COOL;
Harry Yang668fc5e2016-07-12 16:51:47 -07001931 else if (stat & BAT_TEMP_STATUS_HOT_SOFT_LIMIT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001932 val->intval = POWER_SUPPLY_HEALTH_WARM;
Harry Yang668fc5e2016-07-12 16:51:47 -07001933 else
Nicholas Troast34db5032016-03-28 12:26:44 -07001934 val->intval = POWER_SUPPLY_HEALTH_GOOD;
Nicholas Troast34db5032016-03-28 12:26:44 -07001935
1936done:
1937 return rc;
1938}
1939
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001940int smblib_get_prop_system_temp_level(struct smb_charger *chg,
1941 union power_supply_propval *val)
1942{
1943 val->intval = chg->system_temp_level;
1944 return 0;
1945}
1946
Abhijeet Dharmapurikaracf32002017-05-11 11:54:17 -07001947int smblib_get_prop_system_temp_level_max(struct smb_charger *chg,
1948 union power_supply_propval *val)
1949{
1950 val->intval = chg->thermal_levels;
1951 return 0;
1952}
1953
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001954int smblib_get_prop_input_current_limited(struct smb_charger *chg,
1955 union power_supply_propval *val)
1956{
1957 u8 stat;
1958 int rc;
1959
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07001960 if (chg->fake_input_current_limited >= 0) {
1961 val->intval = chg->fake_input_current_limited;
1962 return 0;
1963 }
1964
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001965 rc = smblib_read(chg, AICL_STATUS_REG, &stat);
1966 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001967 smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n", rc);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001968 return rc;
1969 }
1970 val->intval = (stat & SOFT_ILIMIT_BIT) || chg->is_hdc;
1971 return 0;
1972}
1973
Nicholas Troast66b21d72016-09-20 15:33:20 -07001974int smblib_get_prop_batt_voltage_now(struct smb_charger *chg,
1975 union power_supply_propval *val)
1976{
1977 int rc;
1978
1979 if (!chg->bms_psy)
1980 return -EINVAL;
1981
1982 rc = power_supply_get_property(chg->bms_psy,
1983 POWER_SUPPLY_PROP_VOLTAGE_NOW, val);
1984 return rc;
1985}
1986
1987int smblib_get_prop_batt_current_now(struct smb_charger *chg,
1988 union power_supply_propval *val)
1989{
1990 int rc;
1991
1992 if (!chg->bms_psy)
1993 return -EINVAL;
1994
1995 rc = power_supply_get_property(chg->bms_psy,
1996 POWER_SUPPLY_PROP_CURRENT_NOW, val);
1997 return rc;
1998}
1999
2000int smblib_get_prop_batt_temp(struct smb_charger *chg,
2001 union power_supply_propval *val)
2002{
2003 int rc;
2004
2005 if (!chg->bms_psy)
2006 return -EINVAL;
2007
2008 rc = power_supply_get_property(chg->bms_psy,
2009 POWER_SUPPLY_PROP_TEMP, val);
2010 return rc;
2011}
2012
Subbaraman Narayanamurthyb491d022016-10-10 20:22:48 -07002013int smblib_get_prop_batt_charge_done(struct smb_charger *chg,
2014 union power_supply_propval *val)
2015{
2016 int rc;
2017 u8 stat;
2018
2019 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
2020 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002021 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Subbaraman Narayanamurthyb491d022016-10-10 20:22:48 -07002022 rc);
2023 return rc;
2024 }
2025
2026 stat = stat & BATTERY_CHARGER_STATUS_MASK;
2027 val->intval = (stat == TERMINATE_CHARGE);
2028 return 0;
2029}
2030
Harry Yang40192cb2017-02-25 23:25:17 -08002031int smblib_get_prop_charge_qnovo_enable(struct smb_charger *chg,
2032 union power_supply_propval *val)
2033{
2034 int rc;
2035 u8 stat;
2036
2037 rc = smblib_read(chg, QNOVO_PT_ENABLE_CMD_REG, &stat);
2038 if (rc < 0) {
2039 smblib_err(chg, "Couldn't read QNOVO_PT_ENABLE_CMD rc=%d\n",
2040 rc);
2041 return rc;
2042 }
2043
2044 val->intval = (bool)(stat & QNOVO_PT_ENABLE_CMD_BIT);
2045 return 0;
2046}
2047
Nicholas Troast4fe68d02017-07-26 14:17:34 -07002048int smblib_get_prop_batt_charge_counter(struct smb_charger *chg,
2049 union power_supply_propval *val)
2050{
2051 int rc;
2052
2053 if (!chg->bms_psy)
2054 return -EINVAL;
2055
2056 rc = power_supply_get_property(chg->bms_psy,
2057 POWER_SUPPLY_PROP_CHARGE_COUNTER, val);
2058 return rc;
2059}
2060
Nicholas Troast34db5032016-03-28 12:26:44 -07002061/***********************
2062 * BATTERY PSY SETTERS *
2063 ***********************/
2064
2065int smblib_set_prop_input_suspend(struct smb_charger *chg,
2066 const union power_supply_propval *val)
2067{
2068 int rc;
2069
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08002070 /* vote 0mA when suspended */
2071 rc = vote(chg->usb_icl_votable, USER_VOTER, (bool)val->intval, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07002072 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002073 smblib_err(chg, "Couldn't vote to %s USB rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002074 (bool)val->intval ? "suspend" : "resume", rc);
2075 return rc;
2076 }
2077
2078 rc = vote(chg->dc_suspend_votable, USER_VOTER, (bool)val->intval, 0);
2079 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002080 smblib_err(chg, "Couldn't vote to %s DC rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002081 (bool)val->intval ? "suspend" : "resume", rc);
2082 return rc;
2083 }
2084
Nicholas Troast61ff40f2016-07-08 10:59:22 -07002085 power_supply_changed(chg->batt_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07002086 return rc;
2087}
2088
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07002089int smblib_set_prop_batt_capacity(struct smb_charger *chg,
2090 const union power_supply_propval *val)
2091{
2092 chg->fake_capacity = val->intval;
2093
2094 power_supply_changed(chg->batt_psy);
2095
2096 return 0;
2097}
2098
Harry Yang589dd422017-07-28 18:41:42 -07002099int smblib_set_prop_batt_status(struct smb_charger *chg,
2100 const union power_supply_propval *val)
2101{
2102 /* Faking battery full */
2103 if (val->intval == POWER_SUPPLY_STATUS_FULL)
2104 chg->fake_batt_status = val->intval;
2105 else
2106 chg->fake_batt_status = -EINVAL;
2107
2108 power_supply_changed(chg->batt_psy);
2109
2110 return 0;
2111}
2112
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07002113int smblib_set_prop_system_temp_level(struct smb_charger *chg,
2114 const union power_supply_propval *val)
2115{
2116 if (val->intval < 0)
2117 return -EINVAL;
2118
2119 if (chg->thermal_levels <= 0)
2120 return -EINVAL;
2121
2122 if (val->intval > chg->thermal_levels)
2123 return -EINVAL;
2124
2125 chg->system_temp_level = val->intval;
Ashay Jaiswal147a6c32017-03-28 17:19:47 +05302126
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07002127 if (chg->system_temp_level == chg->thermal_levels)
Harry Yangaba1f5f2016-09-28 10:47:29 -07002128 return vote(chg->chg_disable_votable,
2129 THERMAL_DAEMON_VOTER, true, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07002130
Harry Yangaba1f5f2016-09-28 10:47:29 -07002131 vote(chg->chg_disable_votable, THERMAL_DAEMON_VOTER, false, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07002132 if (chg->system_temp_level == 0)
Harry Yangaba1f5f2016-09-28 10:47:29 -07002133 return vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, false, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07002134
Harry Yangaba1f5f2016-09-28 10:47:29 -07002135 vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, true,
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07002136 chg->thermal_mitigation[chg->system_temp_level]);
2137 return 0;
2138}
2139
Harry Yang40192cb2017-02-25 23:25:17 -08002140int smblib_set_prop_charge_qnovo_enable(struct smb_charger *chg,
2141 const union power_supply_propval *val)
2142{
2143 int rc = 0;
2144
2145 rc = smblib_masked_write(chg, QNOVO_PT_ENABLE_CMD_REG,
2146 QNOVO_PT_ENABLE_CMD_BIT,
2147 val->intval ? QNOVO_PT_ENABLE_CMD_BIT : 0);
2148 if (rc < 0) {
2149 dev_err(chg->dev, "Couldn't enable qnovo rc=%d\n", rc);
2150 return rc;
2151 }
2152
2153 return rc;
2154}
2155
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07002156int smblib_set_prop_input_current_limited(struct smb_charger *chg,
2157 const union power_supply_propval *val)
2158{
2159 chg->fake_input_current_limited = val->intval;
2160 return 0;
2161}
2162
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302163int smblib_rerun_aicl(struct smb_charger *chg)
2164{
Nicholas Troast20ae1912017-02-15 10:15:32 -08002165 int rc, settled_icl_ua;
2166 u8 stat;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302167
Nicholas Troast20ae1912017-02-15 10:15:32 -08002168 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
2169 if (rc < 0) {
2170 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
2171 rc);
2172 return rc;
2173 }
2174
2175 /* USB is suspended so skip re-running AICL */
2176 if (stat & USBIN_SUSPEND_STS_BIT)
2177 return rc;
2178
2179 smblib_dbg(chg, PR_MISC, "re-running AICL\n");
Ashay Jaiswal59a14122017-05-16 13:38:52 +05302180 rc = smblib_get_charge_param(chg, &chg->param.icl_stat,
2181 &settled_icl_ua);
2182 if (rc < 0) {
2183 smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
2184 return rc;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302185 }
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302186
Ashay Jaiswal59a14122017-05-16 13:38:52 +05302187 vote(chg->usb_icl_votable, AICL_RERUN_VOTER, true,
2188 max(settled_icl_ua - chg->param.usb_icl.step_u,
2189 chg->param.usb_icl.step_u));
2190 vote(chg->usb_icl_votable, AICL_RERUN_VOTER, false, 0);
2191
Nicholas Troast20ae1912017-02-15 10:15:32 -08002192 return 0;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302193}
2194
2195static int smblib_dp_pulse(struct smb_charger *chg)
2196{
2197 int rc;
2198
2199 /* QC 3.0 increment */
2200 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, SINGLE_INCREMENT_BIT,
2201 SINGLE_INCREMENT_BIT);
2202 if (rc < 0)
2203 smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
2204 rc);
2205
2206 return rc;
2207}
2208
2209static int smblib_dm_pulse(struct smb_charger *chg)
2210{
2211 int rc;
2212
2213 /* QC 3.0 decrement */
2214 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, SINGLE_DECREMENT_BIT,
2215 SINGLE_DECREMENT_BIT);
2216 if (rc < 0)
2217 smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
2218 rc);
2219
2220 return rc;
2221}
2222
Ashay Jaiswalcf243372017-10-31 14:33:27 +05302223static int smblib_force_vbus_voltage(struct smb_charger *chg, u8 val)
2224{
2225 int rc;
2226
2227 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, val, val);
2228 if (rc < 0)
2229 smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
2230 rc);
2231
2232 return rc;
2233}
2234
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302235int smblib_dp_dm(struct smb_charger *chg, int val)
2236{
2237 int target_icl_ua, rc = 0;
Ashay Jaiswalae23a042017-05-18 15:28:31 +05302238 union power_supply_propval pval;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302239
2240 switch (val) {
2241 case POWER_SUPPLY_DP_DM_DP_PULSE:
2242 rc = smblib_dp_pulse(chg);
2243 if (!rc)
2244 chg->pulse_cnt++;
2245 smblib_dbg(chg, PR_PARALLEL, "DP_DM_DP_PULSE rc=%d cnt=%d\n",
2246 rc, chg->pulse_cnt);
2247 break;
2248 case POWER_SUPPLY_DP_DM_DM_PULSE:
2249 rc = smblib_dm_pulse(chg);
2250 if (!rc && chg->pulse_cnt)
2251 chg->pulse_cnt--;
2252 smblib_dbg(chg, PR_PARALLEL, "DP_DM_DM_PULSE rc=%d cnt=%d\n",
2253 rc, chg->pulse_cnt);
2254 break;
2255 case POWER_SUPPLY_DP_DM_ICL_DOWN:
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302256 target_icl_ua = get_effective_result(chg->usb_icl_votable);
Ashay Jaiswalae23a042017-05-18 15:28:31 +05302257 if (target_icl_ua < 0) {
2258 /* no client vote, get the ICL from charger */
2259 rc = power_supply_get_property(chg->usb_psy,
2260 POWER_SUPPLY_PROP_HW_CURRENT_MAX,
2261 &pval);
2262 if (rc < 0) {
2263 smblib_err(chg,
2264 "Couldn't get max current rc=%d\n",
2265 rc);
2266 return rc;
2267 }
2268 target_icl_ua = pval.intval;
2269 }
2270
2271 /*
2272 * Check if any other voter voted on USB_ICL in case of
2273 * voter other than SW_QC3_VOTER reset and restart reduction
2274 * again.
2275 */
2276 if (target_icl_ua != get_client_vote(chg->usb_icl_votable,
2277 SW_QC3_VOTER))
2278 chg->usb_icl_delta_ua = 0;
2279
2280 chg->usb_icl_delta_ua += 100000;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302281 vote(chg->usb_icl_votable, SW_QC3_VOTER, true,
Ashay Jaiswalae23a042017-05-18 15:28:31 +05302282 target_icl_ua - 100000);
2283 smblib_dbg(chg, PR_PARALLEL, "ICL DOWN ICL=%d reduction=%d\n",
2284 target_icl_ua, chg->usb_icl_delta_ua);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302285 break;
Ashay Jaiswalcf243372017-10-31 14:33:27 +05302286 case POWER_SUPPLY_DP_DM_FORCE_5V:
2287 rc = smblib_force_vbus_voltage(chg, FORCE_5V_BIT);
2288 if (rc < 0)
2289 pr_err("Failed to force 5V\n");
2290 break;
2291 case POWER_SUPPLY_DP_DM_FORCE_9V:
Ashay Jaiswal1c360c82018-03-15 23:24:42 +05302292 /* Force 1A ICL before requesting higher voltage */
2293 vote(chg->usb_icl_votable, HVDCP2_ICL_VOTER, true, 1000000);
Ashay Jaiswalcf243372017-10-31 14:33:27 +05302294 rc = smblib_force_vbus_voltage(chg, FORCE_9V_BIT);
2295 if (rc < 0)
2296 pr_err("Failed to force 9V\n");
2297 break;
2298 case POWER_SUPPLY_DP_DM_FORCE_12V:
Ashay Jaiswal1c360c82018-03-15 23:24:42 +05302299 /* Force 1A ICL before requesting higher voltage */
2300 vote(chg->usb_icl_votable, HVDCP2_ICL_VOTER, true, 1000000);
Ashay Jaiswalcf243372017-10-31 14:33:27 +05302301 rc = smblib_force_vbus_voltage(chg, FORCE_12V_BIT);
2302 if (rc < 0)
2303 pr_err("Failed to force 12V\n");
2304 break;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302305 case POWER_SUPPLY_DP_DM_ICL_UP:
2306 default:
2307 break;
2308 }
2309
2310 return rc;
2311}
2312
Abhijeet Dharmapurikar3a580042017-07-24 09:43:00 -07002313int smblib_disable_hw_jeita(struct smb_charger *chg, bool disable)
2314{
2315 int rc;
2316 u8 mask;
2317
2318 /*
2319 * Disable h/w base JEITA compensation if s/w JEITA is enabled
2320 */
2321 mask = JEITA_EN_COLD_SL_FCV_BIT
2322 | JEITA_EN_HOT_SL_FCV_BIT
2323 | JEITA_EN_HOT_SL_CCC_BIT
2324 | JEITA_EN_COLD_SL_CCC_BIT,
2325 rc = smblib_masked_write(chg, JEITA_EN_CFG_REG, mask,
2326 disable ? 0 : mask);
2327 if (rc < 0) {
2328 dev_err(chg->dev,
2329 "Couldn't configure s/w jeita rc=%d\n",
2330 rc);
2331 return rc;
2332 }
2333 return 0;
2334}
2335
Nicholas Troast34db5032016-03-28 12:26:44 -07002336/*******************
Harry Yangf3023592016-07-20 14:56:41 -07002337 * DC PSY GETTERS *
2338 *******************/
2339
2340int smblib_get_prop_dc_present(struct smb_charger *chg,
2341 union power_supply_propval *val)
2342{
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002343 int rc;
Harry Yangf3023592016-07-20 14:56:41 -07002344 u8 stat;
2345
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002346 rc = smblib_read(chg, DCIN_BASE + INT_RT_STS_OFFSET, &stat);
Harry Yangf3023592016-07-20 14:56:41 -07002347 if (rc < 0) {
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002348 smblib_err(chg, "Couldn't read DCIN_RT_STS rc=%d\n", rc);
Harry Yangf3023592016-07-20 14:56:41 -07002349 return rc;
2350 }
Harry Yangf3023592016-07-20 14:56:41 -07002351
2352 val->intval = (bool)(stat & DCIN_PLUGIN_RT_STS_BIT);
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002353 return 0;
Harry Yangf3023592016-07-20 14:56:41 -07002354}
2355
2356int smblib_get_prop_dc_online(struct smb_charger *chg,
2357 union power_supply_propval *val)
2358{
2359 int rc = 0;
2360 u8 stat;
2361
2362 if (get_client_vote(chg->dc_suspend_votable, USER_VOTER)) {
2363 val->intval = false;
2364 return rc;
2365 }
2366
2367 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
2368 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002369 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
Harry Yangf3023592016-07-20 14:56:41 -07002370 rc);
2371 return rc;
2372 }
2373 smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
2374 stat);
2375
2376 val->intval = (stat & USE_DCIN_BIT) &&
Vic Wei7ade2842016-12-14 18:47:49 -08002377 (stat & VALID_INPUT_POWER_SOURCE_STS_BIT);
Harry Yangf3023592016-07-20 14:56:41 -07002378
2379 return rc;
2380}
2381
2382int smblib_get_prop_dc_current_max(struct smb_charger *chg,
2383 union power_supply_propval *val)
2384{
2385 val->intval = get_effective_result_locked(chg->dc_icl_votable);
2386 return 0;
2387}
2388
2389/*******************
Harry Yangd89ff1f2016-12-05 14:59:11 -08002390 * DC PSY SETTERS *
Harry Yangf3023592016-07-20 14:56:41 -07002391 * *****************/
2392
2393int smblib_set_prop_dc_current_max(struct smb_charger *chg,
2394 const union power_supply_propval *val)
2395{
2396 int rc;
2397
2398 rc = vote(chg->dc_icl_votable, USER_VOTER, true, val->intval);
2399 return rc;
2400}
2401
2402/*******************
Nicholas Troast34db5032016-03-28 12:26:44 -07002403 * USB PSY GETTERS *
2404 *******************/
2405
2406int smblib_get_prop_usb_present(struct smb_charger *chg,
2407 union power_supply_propval *val)
2408{
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002409 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07002410 u8 stat;
2411
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002412 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
Nicholas Troast34db5032016-03-28 12:26:44 -07002413 if (rc < 0) {
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002414 smblib_err(chg, "Couldn't read USBIN_RT_STS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07002415 return rc;
2416 }
Nicholas Troast34db5032016-03-28 12:26:44 -07002417
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002418 val->intval = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
2419 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002420}
2421
2422int smblib_get_prop_usb_online(struct smb_charger *chg,
2423 union power_supply_propval *val)
2424{
2425 int rc = 0;
2426 u8 stat;
2427
Abhijeet Dharmapurikar84923af2017-03-23 14:07:07 -07002428 if (get_client_vote_locked(chg->usb_icl_votable, USER_VOTER) == 0) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002429 val->intval = false;
2430 return rc;
2431 }
2432
2433 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
2434 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002435 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002436 rc);
2437 return rc;
2438 }
2439 smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
2440 stat);
2441
2442 val->intval = (stat & USE_USBIN_BIT) &&
Vic Wei7ade2842016-12-14 18:47:49 -08002443 (stat & VALID_INPUT_POWER_SOURCE_STS_BIT);
Nicholas Troast34db5032016-03-28 12:26:44 -07002444 return rc;
2445}
2446
Nicholas Troast7f55c922017-07-25 13:18:03 -07002447int smblib_get_prop_usb_voltage_max(struct smb_charger *chg,
2448 union power_supply_propval *val)
2449{
2450 switch (chg->real_charger_type) {
2451 case POWER_SUPPLY_TYPE_USB_HVDCP:
Ashay Jaiswal3c82d282017-11-28 22:07:36 +05302452 case POWER_SUPPLY_TYPE_USB_HVDCP_3:
Nicholas Troast7f55c922017-07-25 13:18:03 -07002453 case POWER_SUPPLY_TYPE_USB_PD:
2454 if (chg->smb_version == PM660_SUBTYPE)
2455 val->intval = MICRO_9V;
2456 else
2457 val->intval = MICRO_12V;
2458 break;
2459 default:
2460 val->intval = MICRO_5V;
2461 break;
2462 }
2463
2464 return 0;
2465}
2466
Nicholas Troast34db5032016-03-28 12:26:44 -07002467int smblib_get_prop_usb_voltage_now(struct smb_charger *chg,
2468 union power_supply_propval *val)
2469{
Harry Yangba874ce2016-08-19 14:17:01 -07002470 if (!chg->iio.usbin_v_chan ||
2471 PTR_ERR(chg->iio.usbin_v_chan) == -EPROBE_DEFER)
2472 chg->iio.usbin_v_chan = iio_channel_get(chg->dev, "usbin_v");
2473
2474 if (IS_ERR(chg->iio.usbin_v_chan))
2475 return PTR_ERR(chg->iio.usbin_v_chan);
2476
2477 return iio_read_channel_processed(chg->iio.usbin_v_chan, &val->intval);
Nicholas Troast34db5032016-03-28 12:26:44 -07002478}
2479
Harry Yangba874ce2016-08-19 14:17:01 -07002480int smblib_get_prop_usb_current_now(struct smb_charger *chg,
2481 union power_supply_propval *val)
2482{
2483 int rc = 0;
2484
2485 rc = smblib_get_prop_usb_present(chg, val);
2486 if (rc < 0 || !val->intval)
2487 return rc;
2488
2489 if (!chg->iio.usbin_i_chan ||
2490 PTR_ERR(chg->iio.usbin_i_chan) == -EPROBE_DEFER)
2491 chg->iio.usbin_i_chan = iio_channel_get(chg->dev, "usbin_i");
2492
2493 if (IS_ERR(chg->iio.usbin_i_chan))
2494 return PTR_ERR(chg->iio.usbin_i_chan);
2495
2496 return iio_read_channel_processed(chg->iio.usbin_i_chan, &val->intval);
2497}
2498
2499int smblib_get_prop_charger_temp(struct smb_charger *chg,
2500 union power_supply_propval *val)
2501{
2502 int rc;
2503
2504 if (!chg->iio.temp_chan ||
2505 PTR_ERR(chg->iio.temp_chan) == -EPROBE_DEFER)
2506 chg->iio.temp_chan = iio_channel_get(chg->dev, "charger_temp");
2507
2508 if (IS_ERR(chg->iio.temp_chan))
2509 return PTR_ERR(chg->iio.temp_chan);
2510
2511 rc = iio_read_channel_processed(chg->iio.temp_chan, &val->intval);
2512 val->intval /= 100;
2513 return rc;
2514}
2515
2516int smblib_get_prop_charger_temp_max(struct smb_charger *chg,
2517 union power_supply_propval *val)
2518{
2519 int rc;
2520
2521 if (!chg->iio.temp_max_chan ||
2522 PTR_ERR(chg->iio.temp_max_chan) == -EPROBE_DEFER)
2523 chg->iio.temp_max_chan = iio_channel_get(chg->dev,
2524 "charger_temp_max");
2525 if (IS_ERR(chg->iio.temp_max_chan))
2526 return PTR_ERR(chg->iio.temp_max_chan);
2527
2528 rc = iio_read_channel_processed(chg->iio.temp_max_chan, &val->intval);
2529 val->intval /= 100;
2530 return rc;
2531}
2532
Nicholas Troast34db5032016-03-28 12:26:44 -07002533int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
2534 union power_supply_propval *val)
2535{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002536 if (chg->typec_status[3] & CC_ATTACHED_BIT)
2537 val->intval =
2538 (bool)(chg->typec_status[3] & CC_ORIENTATION_BIT) + 1;
Nicholas Troast34db5032016-03-28 12:26:44 -07002539 else
2540 val->intval = 0;
2541
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002542 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002543}
2544
2545static const char * const smblib_typec_mode_name[] = {
2546 [POWER_SUPPLY_TYPEC_NONE] = "NONE",
2547 [POWER_SUPPLY_TYPEC_SOURCE_DEFAULT] = "SOURCE_DEFAULT",
2548 [POWER_SUPPLY_TYPEC_SOURCE_MEDIUM] = "SOURCE_MEDIUM",
2549 [POWER_SUPPLY_TYPEC_SOURCE_HIGH] = "SOURCE_HIGH",
2550 [POWER_SUPPLY_TYPEC_NON_COMPLIANT] = "NON_COMPLIANT",
2551 [POWER_SUPPLY_TYPEC_SINK] = "SINK",
2552 [POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE] = "SINK_POWERED_CABLE",
2553 [POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY] = "SINK_DEBUG_ACCESSORY",
2554 [POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER] = "SINK_AUDIO_ADAPTER",
2555 [POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY] = "POWERED_CABLE_ONLY",
2556};
2557
2558static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
2559{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002560 switch (chg->typec_status[0]) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002561 case UFP_TYPEC_RDSTD_BIT:
2562 return POWER_SUPPLY_TYPEC_SOURCE_DEFAULT;
2563 case UFP_TYPEC_RD1P5_BIT:
2564 return POWER_SUPPLY_TYPEC_SOURCE_MEDIUM;
2565 case UFP_TYPEC_RD3P0_BIT:
2566 return POWER_SUPPLY_TYPEC_SOURCE_HIGH;
2567 default:
2568 break;
2569 }
2570
Nicholas Troaste1932e42017-04-12 12:38:18 -07002571 return POWER_SUPPLY_TYPEC_NONE;
Nicholas Troast34db5032016-03-28 12:26:44 -07002572}
2573
2574static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
2575{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002576 switch (chg->typec_status[1] & DFP_TYPEC_MASK) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002577 case DFP_RA_RA_BIT:
2578 return POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER;
2579 case DFP_RD_RD_BIT:
2580 return POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY;
2581 case DFP_RD_RA_VCONN_BIT:
2582 return POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE;
2583 case DFP_RD_OPEN_BIT:
2584 return POWER_SUPPLY_TYPEC_SINK;
Nicholas Troast34db5032016-03-28 12:26:44 -07002585 default:
2586 break;
2587 }
2588
2589 return POWER_SUPPLY_TYPEC_NONE;
2590}
2591
Nicholas Troaste1932e42017-04-12 12:38:18 -07002592static int smblib_get_prop_typec_mode(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07002593{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002594 if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
Nicholas Troaste1932e42017-04-12 12:38:18 -07002595 return smblib_get_prop_dfp_mode(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07002596 else
Nicholas Troaste1932e42017-04-12 12:38:18 -07002597 return smblib_get_prop_ufp_mode(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07002598}
2599
2600int smblib_get_prop_typec_power_role(struct smb_charger *chg,
2601 union power_supply_propval *val)
2602{
2603 int rc = 0;
2604 u8 ctrl;
2605
2606 rc = smblib_read(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &ctrl);
2607 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002608 smblib_err(chg, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002609 rc);
2610 return rc;
2611 }
2612 smblib_dbg(chg, PR_REGISTER, "TYPE_C_INTRPT_ENB_SOFTWARE_CTRL = 0x%02x\n",
2613 ctrl);
2614
2615 if (ctrl & TYPEC_DISABLE_CMD_BIT) {
2616 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
2617 return rc;
2618 }
2619
2620 switch (ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT)) {
2621 case 0:
2622 val->intval = POWER_SUPPLY_TYPEC_PR_DUAL;
2623 break;
2624 case DFP_EN_CMD_BIT:
2625 val->intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
2626 break;
2627 case UFP_EN_CMD_BIT:
2628 val->intval = POWER_SUPPLY_TYPEC_PR_SINK;
2629 break;
2630 default:
2631 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002632 smblib_err(chg, "unsupported power role 0x%02lx\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002633 ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT));
2634 return -EINVAL;
2635 }
2636
2637 return rc;
2638}
2639
2640int smblib_get_prop_pd_allowed(struct smb_charger *chg,
2641 union power_supply_propval *val)
2642{
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07002643 val->intval = get_effective_result(chg->pd_allowed_votable);
Nicholas Troast34db5032016-03-28 12:26:44 -07002644 return 0;
2645}
2646
Nicholas Troast133a7f52016-06-29 13:48:20 -07002647int smblib_get_prop_input_current_settled(struct smb_charger *chg,
2648 union power_supply_propval *val)
2649{
2650 return smblib_get_charge_param(chg, &chg->param.icl_stat, &val->intval);
2651}
2652
Fenglin Wuef4730e2017-01-11 18:16:25 +08002653#define HVDCP3_STEP_UV 200000
2654int smblib_get_prop_input_voltage_settled(struct smb_charger *chg,
2655 union power_supply_propval *val)
2656{
Fenglin Wuef4730e2017-01-11 18:16:25 +08002657 int rc, pulses;
Fenglin Wuef4730e2017-01-11 18:16:25 +08002658
Nicholas Troast5f314c12017-05-25 11:58:02 -07002659 switch (chg->real_charger_type) {
Fenglin Wuef4730e2017-01-11 18:16:25 +08002660 case POWER_SUPPLY_TYPE_USB_HVDCP_3:
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +05302661 rc = smblib_get_pulse_cnt(chg, &pulses);
Fenglin Wuef4730e2017-01-11 18:16:25 +08002662 if (rc < 0) {
2663 smblib_err(chg,
2664 "Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
2665 return 0;
2666 }
Fenglin Wuef4730e2017-01-11 18:16:25 +08002667 val->intval = MICRO_5V + HVDCP3_STEP_UV * pulses;
2668 break;
Nicholas Troast5f314c12017-05-25 11:58:02 -07002669 case POWER_SUPPLY_TYPE_USB_PD:
2670 val->intval = chg->voltage_min_uv;
2671 break;
Fenglin Wuef4730e2017-01-11 18:16:25 +08002672 default:
2673 val->intval = MICRO_5V;
2674 break;
2675 }
2676
2677 return 0;
2678}
2679
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002680int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg,
2681 union power_supply_propval *val)
2682{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002683 val->intval = chg->pd_hard_reset;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002684 return 0;
2685}
2686
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07002687int smblib_get_pe_start(struct smb_charger *chg,
2688 union power_supply_propval *val)
2689{
2690 /*
2691 * hvdcp timeout voter is the last one to allow pd. Use its vote
2692 * to indicate start of pe engine
2693 */
2694 val->intval
2695 = !get_client_vote_locked(chg->pd_disallowed_votable_indirect,
2696 HVDCP_TIMEOUT_VOTER);
2697 return 0;
2698}
2699
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002700int smblib_get_prop_die_health(struct smb_charger *chg,
Nicholas Troastb021dd92017-01-31 18:43:38 -08002701 union power_supply_propval *val)
2702{
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002703 int rc;
Nicholas Troastb021dd92017-01-31 18:43:38 -08002704 u8 stat;
2705
2706 rc = smblib_read(chg, TEMP_RANGE_STATUS_REG, &stat);
2707 if (rc < 0) {
2708 smblib_err(chg, "Couldn't read TEMP_RANGE_STATUS_REG rc=%d\n",
2709 rc);
2710 return rc;
2711 }
2712
Harry Yang6ed35462017-11-16 23:01:39 -08002713 if (stat & ALERT_LEVEL_BIT)
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002714 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
Harry Yang6ed35462017-11-16 23:01:39 -08002715 else if (stat & TEMP_ABOVE_RANGE_BIT)
2716 val->intval = POWER_SUPPLY_HEALTH_HOT;
2717 else if (stat & TEMP_WITHIN_RANGE_BIT)
2718 val->intval = POWER_SUPPLY_HEALTH_WARM;
2719 else if (stat & TEMP_BELOW_RANGE_BIT)
2720 val->intval = POWER_SUPPLY_HEALTH_COOL;
2721 else
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002722 val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
Nicholas Troastb021dd92017-01-31 18:43:38 -08002723
Nicholas Troastb021dd92017-01-31 18:43:38 -08002724 return 0;
2725}
2726
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05302727#define SDP_CURRENT_UA 500000
2728#define CDP_CURRENT_UA 1500000
2729#define DCP_CURRENT_UA 1500000
2730#define HVDCP_CURRENT_UA 3000000
2731#define TYPEC_DEFAULT_CURRENT_UA 900000
2732#define TYPEC_MEDIUM_CURRENT_UA 1500000
2733#define TYPEC_HIGH_CURRENT_UA 3000000
2734static int get_rp_based_dcp_current(struct smb_charger *chg, int typec_mode)
2735{
2736 int rp_ua;
2737
2738 switch (typec_mode) {
2739 case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
2740 rp_ua = TYPEC_HIGH_CURRENT_UA;
2741 break;
2742 case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
2743 case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
2744 /* fall through */
2745 default:
2746 rp_ua = DCP_CURRENT_UA;
2747 }
2748
2749 return rp_ua;
2750}
2751
Nicholas Troast34db5032016-03-28 12:26:44 -07002752/*******************
2753 * USB PSY SETTERS *
2754 * *****************/
2755
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002756int smblib_set_prop_pd_current_max(struct smb_charger *chg,
2757 const union power_supply_propval *val)
2758{
2759 int rc;
2760
2761 if (chg->pd_active)
2762 rc = vote(chg->usb_icl_votable, PD_VOTER, true, val->intval);
2763 else
2764 rc = -EPERM;
2765
2766 return rc;
2767}
2768
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05302769static int smblib_handle_usb_current(struct smb_charger *chg,
2770 int usb_current)
2771{
2772 int rc = 0, rp_ua, typec_mode;
2773
2774 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_FLOAT) {
2775 if (usb_current == -ETIMEDOUT) {
2776 /*
2777 * Valid FLOAT charger, report the current based
2778 * of Rp
2779 */
2780 typec_mode = smblib_get_prop_typec_mode(chg);
2781 rp_ua = get_rp_based_dcp_current(chg, typec_mode);
2782 rc = vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER,
2783 true, rp_ua);
2784 if (rc < 0)
2785 return rc;
2786 } else {
2787 /*
2788 * FLOAT charger detected as SDP by USB driver,
2789 * charge with the requested current and update the
2790 * real_charger_type
2791 */
2792 chg->real_charger_type = POWER_SUPPLY_TYPE_USB;
2793 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
2794 true, usb_current);
2795 if (rc < 0)
2796 return rc;
2797 rc = vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER,
2798 false, 0);
2799 if (rc < 0)
2800 return rc;
2801 }
2802 } else {
2803 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
2804 true, usb_current);
2805 }
2806
2807 return rc;
2808}
2809
Nicholas Troast7f55c922017-07-25 13:18:03 -07002810int smblib_set_prop_sdp_current_max(struct smb_charger *chg,
Nicholas Troast34db5032016-03-28 12:26:44 -07002811 const union power_supply_propval *val)
2812{
Nicholas Troast8d33b7d2017-01-16 11:18:38 -08002813 int rc = 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002814
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002815 if (!chg->pd_active) {
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05302816 rc = smblib_handle_usb_current(chg, val->intval);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002817 } else if (chg->system_suspend_supported) {
2818 if (val->intval <= USBIN_25MA)
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302819 rc = vote(chg->usb_icl_votable,
2820 PD_SUSPEND_SUPPORTED_VOTER, true, val->intval);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002821 else
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302822 rc = vote(chg->usb_icl_votable,
2823 PD_SUSPEND_SUPPORTED_VOTER, false, 0);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002824 }
Nicholas Troast34db5032016-03-28 12:26:44 -07002825 return rc;
2826}
2827
Harry Yangd89ff1f2016-12-05 14:59:11 -08002828int smblib_set_prop_boost_current(struct smb_charger *chg,
2829 const union power_supply_propval *val)
2830{
2831 int rc = 0;
2832
2833 rc = smblib_set_charge_param(chg, &chg->param.freq_boost,
2834 val->intval <= chg->boost_threshold_ua ?
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05302835 chg->chg_freq.freq_below_otg_threshold :
2836 chg->chg_freq.freq_above_otg_threshold);
Harry Yangd89ff1f2016-12-05 14:59:11 -08002837 if (rc < 0) {
2838 dev_err(chg->dev, "Error in setting freq_boost rc=%d\n", rc);
2839 return rc;
2840 }
2841
2842 chg->boost_current_ua = val->intval;
2843 return rc;
2844}
2845
Nicholas Troast34db5032016-03-28 12:26:44 -07002846int smblib_set_prop_typec_power_role(struct smb_charger *chg,
2847 const union power_supply_propval *val)
2848{
Tirupathi Reddy0c5d0a52017-09-27 16:31:07 +05302849 /* Check if power role switch is disabled */
2850 if (!get_effective_result(chg->disable_power_role_switch))
2851 return __smblib_set_prop_typec_power_role(chg, val);
Nicholas Troast34db5032016-03-28 12:26:44 -07002852
Tirupathi Reddy0c5d0a52017-09-27 16:31:07 +05302853 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002854}
2855
Nicholas Troast7f55c922017-07-25 13:18:03 -07002856int smblib_set_prop_pd_voltage_min(struct smb_charger *chg,
Nicholas Troast34db5032016-03-28 12:26:44 -07002857 const union power_supply_propval *val)
2858{
2859 int rc, min_uv;
2860
2861 min_uv = min(val->intval, chg->voltage_max_uv);
2862 rc = smblib_set_usb_pd_allowed_voltage(chg, min_uv,
2863 chg->voltage_max_uv);
2864 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002865 smblib_err(chg, "invalid max voltage %duV rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002866 val->intval, rc);
2867 return rc;
2868 }
2869
Harry Yangaba1f5f2016-09-28 10:47:29 -07002870 chg->voltage_min_uv = min_uv;
Nicholas Troast5f314c12017-05-25 11:58:02 -07002871 power_supply_changed(chg->usb_main_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07002872 return rc;
2873}
2874
Nicholas Troast7f55c922017-07-25 13:18:03 -07002875int smblib_set_prop_pd_voltage_max(struct smb_charger *chg,
Nicholas Troast34db5032016-03-28 12:26:44 -07002876 const union power_supply_propval *val)
2877{
2878 int rc, max_uv;
2879
2880 max_uv = max(val->intval, chg->voltage_min_uv);
2881 rc = smblib_set_usb_pd_allowed_voltage(chg, chg->voltage_min_uv,
2882 max_uv);
2883 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002884 smblib_err(chg, "invalid min voltage %duV rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002885 val->intval, rc);
2886 return rc;
2887 }
2888
Harry Yangaba1f5f2016-09-28 10:47:29 -07002889 chg->voltage_max_uv = max_uv;
Nicholas Troast34db5032016-03-28 12:26:44 -07002890 return rc;
2891}
2892
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07002893static int __smblib_set_prop_pd_active(struct smb_charger *chg, bool pd_active)
Nicholas Troast34db5032016-03-28 12:26:44 -07002894{
2895 int rc;
Nicholas Troaste1932e42017-04-12 12:38:18 -07002896 bool orientation, sink_attached, hvdcp;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002897 u8 stat;
Nicholas Troast34db5032016-03-28 12:26:44 -07002898
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07002899 chg->pd_active = pd_active;
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002900 if (chg->pd_active) {
2901 vote(chg->apsd_disable_votable, PD_VOTER, true, 0);
2902 vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
2903 vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
2904
2905 /*
2906 * VCONN_EN_ORIENTATION_BIT controls whether to use CC1 or CC2
2907 * line when TYPEC_SPARE_CFG_BIT (CC pin selection s/w override)
2908 * is set or when VCONN_EN_VALUE_BIT is set.
2909 */
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002910 orientation = chg->typec_status[3] & CC_ORIENTATION_BIT;
Harry Yang88acff42016-09-21 14:56:06 -07002911 rc = smblib_masked_write(chg,
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07002912 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2913 VCONN_EN_ORIENTATION_BIT,
2914 orientation ? 0 : VCONN_EN_ORIENTATION_BIT);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002915 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002916 smblib_err(chg,
Harry Yang88acff42016-09-21 14:56:06 -07002917 "Couldn't enable vconn on CC line rc=%d\n", rc);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002918
2919 /* SW controlled CC_OUT */
2920 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
2921 TYPEC_SPARE_CFG_BIT, TYPEC_SPARE_CFG_BIT);
2922 if (rc < 0)
2923 smblib_err(chg, "Couldn't enable SW cc_out rc=%d\n",
2924 rc);
2925
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302926 /*
2927 * Enforce 500mA for PD until the real vote comes in later.
2928 * It is guaranteed that pd_active is set prior to
2929 * pd_current_max
2930 */
Harry Yangcd995202016-11-07 13:32:52 -08002931 rc = vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002932 if (rc < 0)
Harry Yangcd995202016-11-07 13:32:52 -08002933 smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n",
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002934 rc);
Harry Yangcd995202016-11-07 13:32:52 -08002935
Nicholas Troastf9e44992017-03-14 09:06:56 -07002936 /* since PD was found the cable must be non-legacy */
2937 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
2938
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002939 /* clear USB ICL vote for DCP_VOTER */
Harry Yang631b99e2016-11-17 11:24:25 -08002940 rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002941 if (rc < 0)
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002942 smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n",
2943 rc);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002944
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302945 /* remove USB_PSY_VOTER */
2946 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002947 if (rc < 0)
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302948 smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002949 } else {
Nicholas Troaste1932e42017-04-12 12:38:18 -07002950 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
2951 if (rc < 0) {
2952 smblib_err(chg, "Couldn't read APSD status rc=%d\n",
2953 rc);
2954 return rc;
2955 }
2956
2957 hvdcp = stat & QC_CHARGER_BIT;
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002958 vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
2959 vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
Harry Yang7b429572017-09-12 11:15:04 -07002960 vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002961 vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER,
2962 false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002963
2964 /* HW controlled CC_OUT */
2965 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
2966 TYPEC_SPARE_CFG_BIT, 0);
2967 if (rc < 0)
2968 smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n",
2969 rc);
2970
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002971 /*
2972 * This WA should only run for HVDCP. Non-legacy SDP/CDP could
2973 * draw more, but this WA will remove Rd causing VBUS to drop,
2974 * and data could be interrupted. Non-legacy DCP could also draw
2975 * more, but it may impact compliance.
2976 */
Nicholas Troaste1932e42017-04-12 12:38:18 -07002977 sink_attached = chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT;
Ashay Jaiswal8207ee42017-11-27 11:41:27 +05302978 if ((chg->connector_type != POWER_SUPPLY_CONNECTOR_MICRO_USB)
2979 && !chg->typec_legacy_valid
2980 && !sink_attached && hvdcp)
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002981 schedule_work(&chg->legacy_detection_work);
Harry Yang88acff42016-09-21 14:56:06 -07002982 }
2983
Harry Yang6607b4a2016-05-17 17:50:09 -07002984 smblib_update_usb_type(chg);
Abhijeet Dharmapurikar76e2af52016-10-06 17:25:01 -07002985 power_supply_changed(chg->usb_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07002986 return rc;
2987}
2988
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07002989int smblib_set_prop_pd_active(struct smb_charger *chg,
2990 const union power_supply_propval *val)
2991{
2992 if (!get_effective_result(chg->pd_allowed_votable))
2993 return -EINVAL;
2994
2995 return __smblib_set_prop_pd_active(chg, val->intval);
2996}
2997
Fenglin Wuedd70792016-11-22 13:16:19 +08002998int smblib_set_prop_ship_mode(struct smb_charger *chg,
2999 const union power_supply_propval *val)
3000{
3001 int rc;
3002
3003 smblib_dbg(chg, PR_MISC, "Set ship mode: %d!!\n", !!val->intval);
3004
3005 rc = smblib_masked_write(chg, SHIP_MODE_REG, SHIP_MODE_EN_BIT,
3006 !!val->intval ? SHIP_MODE_EN_BIT : 0);
3007 if (rc < 0)
3008 dev_err(chg->dev, "Couldn't %s ship mode, rc=%d\n",
3009 !!val->intval ? "enable" : "disable", rc);
3010
3011 return rc;
3012}
3013
Harry Yang5e2bb712016-10-18 16:47:48 -07003014int smblib_reg_block_update(struct smb_charger *chg,
3015 struct reg_info *entry)
3016{
3017 int rc = 0;
3018
3019 while (entry && entry->reg) {
3020 rc = smblib_read(chg, entry->reg, &entry->bak);
3021 if (rc < 0) {
3022 dev_err(chg->dev, "Error in reading %s rc=%d\n",
3023 entry->desc, rc);
3024 break;
3025 }
3026 entry->bak &= entry->mask;
3027
3028 rc = smblib_masked_write(chg, entry->reg,
3029 entry->mask, entry->val);
3030 if (rc < 0) {
3031 dev_err(chg->dev, "Error in writing %s rc=%d\n",
3032 entry->desc, rc);
3033 break;
3034 }
3035 entry++;
3036 }
3037
3038 return rc;
3039}
3040
3041int smblib_reg_block_restore(struct smb_charger *chg,
3042 struct reg_info *entry)
3043{
3044 int rc = 0;
3045
3046 while (entry && entry->reg) {
3047 rc = smblib_masked_write(chg, entry->reg,
3048 entry->mask, entry->bak);
3049 if (rc < 0) {
3050 dev_err(chg->dev, "Error in writing %s rc=%d\n",
3051 entry->desc, rc);
3052 break;
3053 }
3054 entry++;
3055 }
3056
3057 return rc;
3058}
3059
Harry Yang755a34b2016-11-01 01:18:51 -07003060static struct reg_info cc2_detach_settings[] = {
3061 {
3062 .reg = TYPE_C_CFG_2_REG,
3063 .mask = TYPE_C_UFP_MODE_BIT | EN_TRY_SOURCE_MODE_BIT,
3064 .val = TYPE_C_UFP_MODE_BIT,
3065 .desc = "TYPE_C_CFG_2_REG",
3066 },
3067 {
3068 .reg = TYPE_C_CFG_3_REG,
3069 .mask = EN_TRYSINK_MODE_BIT,
3070 .val = 0,
3071 .desc = "TYPE_C_CFG_3_REG",
3072 },
3073 {
3074 .reg = TAPER_TIMER_SEL_CFG_REG,
3075 .mask = TYPEC_SPARE_CFG_BIT,
3076 .val = TYPEC_SPARE_CFG_BIT,
3077 .desc = "TAPER_TIMER_SEL_CFG_REG",
3078 },
3079 {
3080 .reg = TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
3081 .mask = VCONN_EN_ORIENTATION_BIT,
3082 .val = 0,
3083 .desc = "TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG",
3084 },
3085 {
3086 .reg = MISC_CFG_REG,
3087 .mask = TCC_DEBOUNCE_20MS_BIT,
3088 .val = TCC_DEBOUNCE_20MS_BIT,
3089 .desc = "Tccdebounce time"
3090 },
3091 {
3092 },
3093};
3094
3095static int smblib_cc2_sink_removal_enter(struct smb_charger *chg)
3096{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003097 int rc, ccout, ufp_mode;
3098 u8 stat;
Harry Yang755a34b2016-11-01 01:18:51 -07003099
3100 if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003101 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07003102
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003103 if (chg->cc2_detach_wa_active)
3104 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07003105
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003106 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
Harry Yang755a34b2016-11-01 01:18:51 -07003107 if (rc < 0) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003108 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
Harry Yang755a34b2016-11-01 01:18:51 -07003109 return rc;
3110 }
Nicholas Troaste1932e42017-04-12 12:38:18 -07003111
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003112 ccout = (stat & CC_ATTACHED_BIT) ?
3113 (!!(stat & CC_ORIENTATION_BIT) + 1) : 0;
3114 ufp_mode = (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT) ?
3115 !(stat & UFP_DFP_MODE_STATUS_BIT) : 0;
Harry Yang755a34b2016-11-01 01:18:51 -07003116
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003117 if (ccout != 2)
3118 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07003119
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003120 if (!ufp_mode)
3121 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07003122
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003123 chg->cc2_detach_wa_active = true;
3124 /* The CC2 removal WA will cause a type-c-change IRQ storm */
3125 smblib_reg_block_update(chg, cc2_detach_settings);
3126 schedule_work(&chg->rdstd_cc2_detach_work);
Harry Yang755a34b2016-11-01 01:18:51 -07003127 return rc;
3128}
3129
3130static int smblib_cc2_sink_removal_exit(struct smb_charger *chg)
3131{
Harry Yang755a34b2016-11-01 01:18:51 -07003132 if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003133 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07003134
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003135 if (!chg->cc2_detach_wa_active)
3136 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07003137
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003138 chg->cc2_detach_wa_active = false;
3139 cancel_work_sync(&chg->rdstd_cc2_detach_work);
3140 smblib_reg_block_restore(chg, cc2_detach_settings);
3141 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07003142}
3143
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07003144int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
3145 const union power_supply_propval *val)
3146{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003147 int rc = 0;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07003148
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003149 if (chg->pd_hard_reset == val->intval)
3150 return rc;
3151
3152 chg->pd_hard_reset = val->intval;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07003153 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003154 EXIT_SNK_BASED_ON_CC_BIT,
3155 (chg->pd_hard_reset) ? EXIT_SNK_BASED_ON_CC_BIT : 0);
3156 if (rc < 0)
3157 smblib_err(chg, "Couldn't set EXIT_SNK_BASED_ON_CC rc=%d\n",
Harry Yang755a34b2016-11-01 01:18:51 -07003158 rc);
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07003159
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003160 vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER,
3161 chg->pd_hard_reset, 0);
Harry Yang755a34b2016-11-01 01:18:51 -07003162
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07003163 return rc;
3164}
3165
Anirudh Ghayal941acaa2017-07-19 16:04:44 +05303166static int smblib_recover_from_soft_jeita(struct smb_charger *chg)
3167{
3168 u8 stat_1, stat_2;
3169 int rc;
3170
3171 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat_1);
3172 if (rc < 0) {
3173 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
3174 rc);
3175 return rc;
3176 }
3177
3178 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat_2);
3179 if (rc < 0) {
3180 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
3181 rc);
3182 return rc;
3183 }
3184
3185 if ((chg->jeita_status && !(stat_2 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK) &&
3186 ((stat_1 & BATTERY_CHARGER_STATUS_MASK) == TERMINATE_CHARGE))) {
3187 /*
3188 * We are moving from JEITA soft -> Normal and charging
3189 * is terminated
3190 */
3191 rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG, 0);
3192 if (rc < 0) {
3193 smblib_err(chg, "Couldn't disable charging rc=%d\n",
3194 rc);
3195 return rc;
3196 }
3197 rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG,
3198 CHARGING_ENABLE_CMD_BIT);
3199 if (rc < 0) {
3200 smblib_err(chg, "Couldn't enable charging rc=%d\n",
3201 rc);
3202 return rc;
3203 }
3204 }
3205
3206 chg->jeita_status = stat_2 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK;
3207
3208 return 0;
3209}
3210
Nicholas Troast7dbcad22016-10-05 13:30:18 -07003211/************************
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003212 * USB MAIN PSY GETTERS *
3213 ************************/
3214int smblib_get_prop_fcc_delta(struct smb_charger *chg,
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05303215 union power_supply_propval *val)
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003216{
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05303217 int rc, jeita_cc_delta_ua = 0;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003218
Harry Yang0d189772017-10-06 12:42:10 -07003219 if (chg->sw_jeita_enabled) {
3220 val->intval = 0;
3221 return 0;
3222 }
3223
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003224 rc = smblib_get_jeita_cc_delta(chg, &jeita_cc_delta_ua);
3225 if (rc < 0) {
3226 smblib_err(chg, "Couldn't get jeita cc delta rc=%d\n", rc);
3227 jeita_cc_delta_ua = 0;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003228 }
3229
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05303230 val->intval = jeita_cc_delta_ua;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003231 return 0;
3232}
3233
3234/************************
3235 * USB MAIN PSY SETTERS *
3236 ************************/
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003237int smblib_get_charge_current(struct smb_charger *chg,
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003238 int *total_current_ua)
3239{
Ashay Jaiswal7b6eb962017-04-26 14:34:29 +05303240 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003241 union power_supply_propval val = {0, };
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003242 int rc = 0, typec_source_rd, current_ua;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003243 bool non_compliant;
3244 u8 stat5;
3245
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003246 if (chg->pd_active) {
3247 *total_current_ua =
3248 get_client_vote_locked(chg->usb_icl_votable, PD_VOTER);
3249 return rc;
3250 }
3251
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003252 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
3253 if (rc < 0) {
3254 smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc);
3255 return rc;
3256 }
3257 non_compliant = stat5 & TYPEC_NONCOMP_LEGACY_CABLE_STATUS_BIT;
3258
3259 /* get settled ICL */
3260 rc = smblib_get_prop_input_current_settled(chg, &val);
3261 if (rc < 0) {
3262 smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
3263 return rc;
3264 }
3265
3266 typec_source_rd = smblib_get_prop_ufp_mode(chg);
3267
3268 /* QC 2.0/3.0 adapter */
3269 if (apsd_result->bit & (QC_3P0_BIT | QC_2P0_BIT)) {
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303270 *total_current_ua = HVDCP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003271 return 0;
3272 }
3273
3274 if (non_compliant) {
3275 switch (apsd_result->bit) {
3276 case CDP_CHARGER_BIT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303277 current_ua = CDP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003278 break;
3279 case DCP_CHARGER_BIT:
3280 case OCP_CHARGER_BIT:
3281 case FLOAT_CHARGER_BIT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303282 current_ua = DCP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003283 break;
3284 default:
3285 current_ua = 0;
3286 break;
3287 }
3288
3289 *total_current_ua = max(current_ua, val.intval);
3290 return 0;
3291 }
3292
3293 switch (typec_source_rd) {
3294 case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
3295 switch (apsd_result->bit) {
3296 case CDP_CHARGER_BIT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303297 current_ua = CDP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003298 break;
3299 case DCP_CHARGER_BIT:
3300 case OCP_CHARGER_BIT:
3301 case FLOAT_CHARGER_BIT:
3302 current_ua = chg->default_icl_ua;
3303 break;
3304 default:
3305 current_ua = 0;
3306 break;
3307 }
3308 break;
3309 case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303310 current_ua = TYPEC_MEDIUM_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003311 break;
3312 case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303313 current_ua = TYPEC_HIGH_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003314 break;
3315 case POWER_SUPPLY_TYPEC_NON_COMPLIANT:
3316 case POWER_SUPPLY_TYPEC_NONE:
3317 default:
3318 current_ua = 0;
3319 break;
3320 }
3321
3322 *total_current_ua = max(current_ua, val.intval);
3323 return 0;
3324}
3325
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003326/************************
Nicholas Troast7dbcad22016-10-05 13:30:18 -07003327 * PARALLEL PSY GETTERS *
3328 ************************/
3329
3330int smblib_get_prop_slave_current_now(struct smb_charger *chg,
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003331 union power_supply_propval *pval)
Nicholas Troast7dbcad22016-10-05 13:30:18 -07003332{
3333 if (IS_ERR_OR_NULL(chg->iio.batt_i_chan))
3334 chg->iio.batt_i_chan = iio_channel_get(chg->dev, "batt_i");
3335
3336 if (IS_ERR(chg->iio.batt_i_chan))
3337 return PTR_ERR(chg->iio.batt_i_chan);
3338
3339 return iio_read_channel_processed(chg->iio.batt_i_chan, &pval->intval);
3340}
3341
Nicholas Troast34db5032016-03-28 12:26:44 -07003342/**********************
3343 * INTERRUPT HANDLERS *
3344 **********************/
3345
3346irqreturn_t smblib_handle_debug(int irq, void *data)
3347{
3348 struct smb_irq_data *irq_data = data;
3349 struct smb_charger *chg = irq_data->parent_data;
3350
3351 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003352 return IRQ_HANDLED;
3353}
3354
Nicholas Troast8995a702016-12-05 10:22:22 -08003355irqreturn_t smblib_handle_otg_overcurrent(int irq, void *data)
3356{
3357 struct smb_irq_data *irq_data = data;
3358 struct smb_charger *chg = irq_data->parent_data;
3359 int rc;
3360 u8 stat;
3361
3362 rc = smblib_read(chg, OTG_BASE + INT_RT_STS_OFFSET, &stat);
3363 if (rc < 0) {
3364 dev_err(chg->dev, "Couldn't read OTG_INT_RT_STS rc=%d\n", rc);
3365 return IRQ_HANDLED;
3366 }
3367
Ashay Jaiswal7c241382017-03-06 15:26:38 +05303368 if (chg->wa_flags & OTG_WA) {
3369 if (stat & OTG_OC_DIS_SW_STS_RT_STS_BIT)
3370 smblib_err(chg, "OTG disabled by hw\n");
3371
3372 /* not handling software based hiccups for PM660 */
3373 return IRQ_HANDLED;
3374 }
3375
Nicholas Troastb11015f2017-01-17 17:56:45 -08003376 if (stat & OTG_OVERCURRENT_RT_STS_BIT)
3377 schedule_work(&chg->otg_oc_work);
Nicholas Troast8995a702016-12-05 10:22:22 -08003378
Nicholas Troast8995a702016-12-05 10:22:22 -08003379 return IRQ_HANDLED;
3380}
3381
Harry Yang6fe72ab2016-06-14 16:21:39 -07003382irqreturn_t smblib_handle_chg_state_change(int irq, void *data)
3383{
3384 struct smb_irq_data *irq_data = data;
3385 struct smb_charger *chg = irq_data->parent_data;
Nicholas Troast8cb77552016-09-23 11:50:18 -07003386 u8 stat;
Harry Yang1d1034c2016-06-15 12:09:42 -07003387 int rc;
Harry Yang6fe72ab2016-06-14 16:21:39 -07003388
3389 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3390
Nicholas Troast8cb77552016-09-23 11:50:18 -07003391 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
Harry Yang1d1034c2016-06-15 12:09:42 -07003392 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003393 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003394 rc);
Harry Yang1d1034c2016-06-15 12:09:42 -07003395 return IRQ_HANDLED;
3396 }
3397
Nicholas Troast8cb77552016-09-23 11:50:18 -07003398 stat = stat & BATTERY_CHARGER_STATUS_MASK;
Nicholas Troast8cb77552016-09-23 11:50:18 -07003399 power_supply_changed(chg->batt_psy);
Harry Yang6fe72ab2016-06-14 16:21:39 -07003400 return IRQ_HANDLED;
3401}
3402
Abhijeet Dharmapurikar2644cd62016-07-20 16:54:55 -07003403irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data)
3404{
3405 struct smb_irq_data *irq_data = data;
3406 struct smb_charger *chg = irq_data->parent_data;
Anirudh Ghayal941acaa2017-07-19 16:04:44 +05303407 int rc;
3408
3409 rc = smblib_recover_from_soft_jeita(chg);
3410 if (rc < 0) {
3411 smblib_err(chg, "Couldn't recover chg from soft jeita rc=%d\n",
3412 rc);
3413 return IRQ_HANDLED;
3414 }
Abhijeet Dharmapurikar2644cd62016-07-20 16:54:55 -07003415
3416 rerun_election(chg->fcc_votable);
3417 power_supply_changed(chg->batt_psy);
3418 return IRQ_HANDLED;
3419}
3420
Nicholas Troast34db5032016-03-28 12:26:44 -07003421irqreturn_t smblib_handle_batt_psy_changed(int irq, void *data)
3422{
3423 struct smb_irq_data *irq_data = data;
3424 struct smb_charger *chg = irq_data->parent_data;
3425
Nicholas Troast47ae4612016-08-03 09:49:36 -07003426 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003427 power_supply_changed(chg->batt_psy);
3428 return IRQ_HANDLED;
3429}
3430
3431irqreturn_t smblib_handle_usb_psy_changed(int irq, void *data)
3432{
3433 struct smb_irq_data *irq_data = data;
3434 struct smb_charger *chg = irq_data->parent_data;
3435
Nicholas Troast47ae4612016-08-03 09:49:36 -07003436 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003437 power_supply_changed(chg->usb_psy);
3438 return IRQ_HANDLED;
3439}
3440
Subbaraman Narayanamurthy09327482017-02-06 16:33:12 -08003441irqreturn_t smblib_handle_usbin_uv(int irq, void *data)
3442{
3443 struct smb_irq_data *irq_data = data;
3444 struct smb_charger *chg = irq_data->parent_data;
3445 struct storm_watch *wdata;
3446
3447 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3448 if (!chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data)
3449 return IRQ_HANDLED;
3450
3451 wdata = &chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data->storm_data;
3452 reset_storm_count(wdata);
3453 return IRQ_HANDLED;
3454}
3455
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003456static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising)
3457{
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003458 if (vbus_rising) {
3459 /* use the typec flag even though its not typec */
3460 chg->typec_present = 1;
3461 } else {
3462 chg->typec_present = 0;
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003463 smblib_update_usb_type(chg);
3464 extcon_set_cable_state_(chg->extcon, EXTCON_USB, false);
3465 smblib_uusb_removal(chg);
3466 }
3467}
3468
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003469void smblib_usb_plugin_hard_reset_locked(struct smb_charger *chg)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003470{
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003471 int rc;
3472 u8 stat;
3473 bool vbus_rising;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303474 struct smb_irq_data *data;
3475 struct storm_watch *wdata;
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003476
3477 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
3478 if (rc < 0) {
3479 smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
3480 return;
3481 }
3482
3483 vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
3484
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303485 if (vbus_rising) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003486 smblib_cc2_sink_removal_exit(chg);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303487 } else {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003488 smblib_cc2_sink_removal_enter(chg);
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303489 if (chg->wa_flags & BOOST_BACK_WA) {
3490 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
3491 if (data) {
3492 wdata = &data->storm_data;
3493 update_storm_count(wdata,
3494 WEAK_CHG_STORM_COUNT);
3495 vote(chg->usb_icl_votable, BOOST_BACK_VOTER,
3496 false, 0);
3497 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
3498 false, 0);
3499 }
3500 }
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303501 }
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003502
3503 power_supply_changed(chg->usb_psy);
3504 smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
3505 vbus_rising ? "attached" : "detached");
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003506}
3507
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303508#define PL_DELAY_MS 30000
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003509void smblib_usb_plugin_locked(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07003510{
Nicholas Troast34db5032016-03-28 12:26:44 -07003511 int rc;
3512 u8 stat;
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003513 bool vbus_rising;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303514 struct smb_irq_data *data;
3515 struct storm_watch *wdata;
Nicholas Troast34db5032016-03-28 12:26:44 -07003516
Harry Yangcdad2bf2016-10-04 17:03:56 -07003517 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
3518 if (rc < 0) {
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003519 smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
3520 return;
Harry Yangcdad2bf2016-10-04 17:03:56 -07003521 }
3522
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003523 vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003524 smblib_set_opt_freq_buck(chg, vbus_rising ? chg->chg_freq.freq_5V :
3525 chg->chg_freq.freq_removal);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003526
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003527 if (vbus_rising) {
Harry Yang287e3e92018-03-27 14:17:42 -07003528 if (smblib_get_prop_dfp_mode(chg) != POWER_SUPPLY_TYPEC_NONE) {
3529 chg->fake_usb_insertion = true;
3530 return;
3531 }
3532
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05303533 rc = smblib_request_dpdm(chg, true);
3534 if (rc < 0)
3535 smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303536
3537 /* Schedule work to enable parallel charger */
3538 vote(chg->awake_votable, PL_DELAY_VOTER, true, 0);
3539 schedule_delayed_work(&chg->pl_enable_work,
3540 msecs_to_jiffies(PL_DELAY_MS));
Harry Yang1ed7f162017-08-25 11:26:51 -07003541 /* vbus rising when APSD was disabled and PD_ACTIVE = 0 */
3542 if (get_effective_result(chg->apsd_disable_votable) &&
3543 !chg->pd_active)
3544 pr_err("APSD disabled on vbus rising without PD\n");
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07003545 } else {
Harry Yang287e3e92018-03-27 14:17:42 -07003546 if (chg->fake_usb_insertion) {
3547 chg->fake_usb_insertion = false;
3548 return;
3549 }
3550
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303551 if (chg->wa_flags & BOOST_BACK_WA) {
3552 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
3553 if (data) {
3554 wdata = &data->storm_data;
3555 update_storm_count(wdata,
3556 WEAK_CHG_STORM_COUNT);
3557 vote(chg->usb_icl_votable, BOOST_BACK_VOTER,
3558 false, 0);
3559 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
3560 false, 0);
3561 }
3562 }
Nicholas Troastabedaf72016-09-16 11:07:45 -07003563
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05303564 rc = smblib_request_dpdm(chg, false);
3565 if (rc < 0)
3566 smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07003567 }
3568
Ashay Jaiswal0ce2c7c2017-11-14 12:29:02 +05303569 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003570 smblib_micro_usb_plugin(chg, vbus_rising);
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003571
Nicholas Troast62d86622016-09-22 11:41:33 -07003572 power_supply_changed(chg->usb_psy);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003573 smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
3574 vbus_rising ? "attached" : "detached");
3575}
3576
3577irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
3578{
3579 struct smb_irq_data *irq_data = data;
3580 struct smb_charger *chg = irq_data->parent_data;
3581
3582 mutex_lock(&chg->lock);
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003583 if (chg->pd_hard_reset)
3584 smblib_usb_plugin_hard_reset_locked(chg);
3585 else
3586 smblib_usb_plugin_locked(chg);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003587 mutex_unlock(&chg->lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07003588 return IRQ_HANDLED;
3589}
3590
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -07003591#define USB_WEAK_INPUT_UA 1400000
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303592#define ICL_CHANGE_DELAY_MS 1000
Harry Yang6fe72ab2016-06-14 16:21:39 -07003593irqreturn_t smblib_handle_icl_change(int irq, void *data)
3594{
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303595 u8 stat;
3596 int rc, settled_ua, delay = ICL_CHANGE_DELAY_MS;
Harry Yang6fe72ab2016-06-14 16:21:39 -07003597 struct smb_irq_data *irq_data = data;
3598 struct smb_charger *chg = irq_data->parent_data;
3599
Nicholas Troastbb9e1a32017-02-09 10:57:28 -08003600 if (chg->mode == PARALLEL_MASTER) {
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303601 rc = smblib_read(chg, AICL_STATUS_REG, &stat);
3602 if (rc < 0) {
3603 smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n",
3604 rc);
3605 return IRQ_HANDLED;
3606 }
3607
3608 rc = smblib_get_charge_param(chg, &chg->param.icl_stat,
3609 &settled_ua);
3610 if (rc < 0) {
3611 smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
3612 return IRQ_HANDLED;
3613 }
3614
3615 /* If AICL settled then schedule work now */
3616 if ((settled_ua == get_effective_result(chg->usb_icl_votable))
3617 || (stat & AICL_DONE_BIT))
3618 delay = 0;
3619
Ashay Jaiswalac854862017-03-06 23:58:55 +05303620 cancel_delayed_work_sync(&chg->icl_change_work);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303621 schedule_delayed_work(&chg->icl_change_work,
3622 msecs_to_jiffies(delay));
Nicholas Troastbb9e1a32017-02-09 10:57:28 -08003623 }
Harry Yang1d1034c2016-06-15 12:09:42 -07003624
Harry Yang6fe72ab2016-06-14 16:21:39 -07003625 return IRQ_HANDLED;
3626}
3627
Nicholas Troast34db5032016-03-28 12:26:44 -07003628static void smblib_handle_slow_plugin_timeout(struct smb_charger *chg,
3629 bool rising)
3630{
3631 smblib_dbg(chg, PR_INTERRUPT, "IRQ: slow-plugin-timeout %s\n",
3632 rising ? "rising" : "falling");
3633}
3634
3635static void smblib_handle_sdp_enumeration_done(struct smb_charger *chg,
3636 bool rising)
3637{
3638 smblib_dbg(chg, PR_INTERRUPT, "IRQ: sdp-enumeration-done %s\n",
3639 rising ? "rising" : "falling");
3640}
3641
Umang Agrawal49680b62018-04-16 14:41:11 +05303642#define MICRO_10P3V 10300000
3643static void smblib_check_ov_condition(struct smb_charger *chg)
3644{
3645 union power_supply_propval pval = {0, };
3646 int rc;
3647
3648 if (chg->wa_flags & OV_IRQ_WA_BIT) {
3649 rc = power_supply_get_property(chg->usb_psy,
3650 POWER_SUPPLY_PROP_VOLTAGE_NOW, &pval);
3651 if (rc < 0) {
3652 smblib_err(chg, "Couldn't get current voltage, rc=%d\n",
3653 rc);
3654 return;
3655 }
3656
3657 if (pval.intval > MICRO_10P3V) {
3658 smblib_err(chg, "USBIN OV detected\n");
3659 vote(chg->hvdcp_hw_inov_dis_votable, OV_VOTER, true,
3660 0);
3661 pval.intval = POWER_SUPPLY_DP_DM_FORCE_5V;
3662 rc = power_supply_set_property(chg->batt_psy,
3663 POWER_SUPPLY_PROP_DP_DM, &pval);
3664 return;
3665 }
3666 }
3667}
3668
Harry Yangcdad2bf2016-10-04 17:03:56 -07003669#define QC3_PULSES_FOR_6V 5
3670#define QC3_PULSES_FOR_9V 20
3671#define QC3_PULSES_FOR_12V 35
3672static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg)
3673{
3674 int rc;
3675 u8 stat;
3676 int pulses;
3677
Umang Agrawal49680b62018-04-16 14:41:11 +05303678 smblib_check_ov_condition(chg);
Fenglin Wuef4730e2017-01-11 18:16:25 +08003679 power_supply_changed(chg->usb_main_psy);
Fenglin Wu80826e02017-04-25 21:45:08 +08003680 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP) {
Harry Yangcdad2bf2016-10-04 17:03:56 -07003681 rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat);
3682 if (rc < 0) {
3683 smblib_err(chg,
3684 "Couldn't read QC_CHANGE_STATUS rc=%d\n", rc);
3685 return;
3686 }
3687
3688 switch (stat & QC_2P0_STATUS_MASK) {
3689 case QC_5V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303690 smblib_set_opt_freq_buck(chg,
3691 chg->chg_freq.freq_5V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003692 break;
3693 case QC_9V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303694 smblib_set_opt_freq_buck(chg,
3695 chg->chg_freq.freq_9V);
Ashay Jaiswal1c360c82018-03-15 23:24:42 +05303696 vote(chg->usb_icl_votable, HVDCP2_ICL_VOTER, false, 0);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003697 break;
3698 case QC_12V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303699 smblib_set_opt_freq_buck(chg,
3700 chg->chg_freq.freq_12V);
Ashay Jaiswal1c360c82018-03-15 23:24:42 +05303701 vote(chg->usb_icl_votable, HVDCP2_ICL_VOTER, false, 0);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003702 break;
3703 default:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303704 smblib_set_opt_freq_buck(chg,
3705 chg->chg_freq.freq_removal);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003706 break;
3707 }
3708 }
3709
Fenglin Wu80826e02017-04-25 21:45:08 +08003710 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP_3) {
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +05303711 rc = smblib_get_pulse_cnt(chg, &pulses);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003712 if (rc < 0) {
3713 smblib_err(chg,
3714 "Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
3715 return;
3716 }
Harry Yangcdad2bf2016-10-04 17:03:56 -07003717
3718 if (pulses < QC3_PULSES_FOR_6V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303719 smblib_set_opt_freq_buck(chg,
3720 chg->chg_freq.freq_5V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003721 else if (pulses < QC3_PULSES_FOR_9V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303722 smblib_set_opt_freq_buck(chg,
3723 chg->chg_freq.freq_6V_8V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003724 else if (pulses < QC3_PULSES_FOR_12V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303725 smblib_set_opt_freq_buck(chg,
3726 chg->chg_freq.freq_9V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003727 else
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303728 smblib_set_opt_freq_buck(chg,
3729 chg->chg_freq.freq_12V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003730 }
3731}
3732
Nicholas Troast34db5032016-03-28 12:26:44 -07003733/* triggers when HVDCP 3.0 authentication has finished */
3734static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
3735 bool rising)
3736{
3737 const struct apsd_result *apsd_result;
Harry Yangcdad2bf2016-10-04 17:03:56 -07003738 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07003739
3740 if (!rising)
3741 return;
3742
Ashay Jaiswal67ec7072017-02-16 14:14:58 +05303743 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
3744 /*
3745 * Disable AUTH_IRQ_EN_CFG_BIT to receive adapter voltage
3746 * change interrupt.
3747 */
3748 rc = smblib_masked_write(chg,
3749 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
3750 AUTH_IRQ_EN_CFG_BIT, 0);
3751 if (rc < 0)
3752 smblib_err(chg,
3753 "Couldn't enable QC auth setting rc=%d\n", rc);
3754 }
Harry Yangcdad2bf2016-10-04 17:03:56 -07003755
Harry Yangaba1f5f2016-09-28 10:47:29 -07003756 if (chg->mode == PARALLEL_MASTER)
3757 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0);
3758
Ashay Jaiswalac854862017-03-06 23:58:55 +05303759 /* the APSD done handler will set the USB supply type */
3760 apsd_result = smblib_get_apsd_result(chg);
Ashay Jaiswalac854862017-03-06 23:58:55 +05303761
Nicholas Troast34db5032016-03-28 12:26:44 -07003762 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n",
3763 apsd_result->name);
3764}
3765
Harry Yang1369b7a2016-09-27 15:59:50 -07003766static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
3767 bool rising, bool qc_charger)
3768{
Ashay Jaiswal7b6eb962017-04-26 14:34:29 +05303769 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05303770
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003771 /* Hold off PD only until hvdcp 2.0 detection timeout */
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003772 if (rising) {
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003773 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003774 false, 0);
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -08003775
Harry Yang4bf7d962017-03-13 16:51:43 -07003776 /* enable HDC and ICL irq for QC2/3 charger */
3777 if (qc_charger)
3778 vote(chg->usb_irq_enable_votable, QC_VOTER, true, 0);
3779
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -08003780 /*
3781 * HVDCP detection timeout done
3782 * If adapter is not QC2.0/QC3.0 - it is a plain old DCP.
3783 */
3784 if (!qc_charger && (apsd_result->bit & DCP_CHARGER_BIT))
3785 /* enforce DCP ICL if specified */
3786 vote(chg->usb_icl_votable, DCP_VOTER,
3787 chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua);
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07003788
3789 /*
3790 * if pd is not allowed, then set pd_active = false right here,
3791 * so that it starts the hvdcp engine
3792 */
3793 if (!get_effective_result(chg->pd_allowed_votable))
3794 __smblib_set_prop_pd_active(chg, 0);
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003795 }
Harry Yang1369b7a2016-09-27 15:59:50 -07003796
3797 smblib_dbg(chg, PR_INTERRUPT, "IRQ: smblib_handle_hvdcp_check_timeout %s\n",
3798 rising ? "rising" : "falling");
3799}
3800
Nicholas Troast34db5032016-03-28 12:26:44 -07003801/* triggers when HVDCP is detected */
3802static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg,
3803 bool rising)
3804{
3805 if (!rising)
3806 return;
3807
3808 /* the APSD done handler will set the USB supply type */
3809 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
3810 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-detect-done %s\n",
3811 rising ? "rising" : "falling");
3812}
3813
Nicholas Troastf9e44992017-03-14 09:06:56 -07003814static void smblib_force_legacy_icl(struct smb_charger *chg, int pst)
3815{
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303816 int typec_mode;
3817 int rp_ua;
3818
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003819 /* while PD is active it should have complete ICL control */
3820 if (chg->pd_active)
3821 return;
3822
Nicholas Troastf9e44992017-03-14 09:06:56 -07003823 switch (pst) {
3824 case POWER_SUPPLY_TYPE_USB:
3825 /*
3826 * USB_PSY will vote to increase the current to 500/900mA once
3827 * enumeration is done. Ensure that USB_PSY has at least voted
3828 * for 100mA before releasing the LEGACY_UNKNOWN vote
3829 */
3830 if (!is_client_vote_enabled(chg->usb_icl_votable,
3831 USB_PSY_VOTER))
3832 vote(chg->usb_icl_votable, USB_PSY_VOTER, true, 100000);
3833 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
3834 break;
3835 case POWER_SUPPLY_TYPE_USB_CDP:
3836 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1500000);
3837 break;
3838 case POWER_SUPPLY_TYPE_USB_DCP:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303839 typec_mode = smblib_get_prop_typec_mode(chg);
3840 rp_ua = get_rp_based_dcp_current(chg, typec_mode);
3841 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua);
Nicholas Troastf9e44992017-03-14 09:06:56 -07003842 break;
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05303843 case POWER_SUPPLY_TYPE_USB_FLOAT:
3844 /*
3845 * limit ICL to 100mA, the USB driver will enumerate to check
3846 * if this is a SDP and appropriately set the current
3847 */
3848 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
3849 break;
Nicholas Troastf9e44992017-03-14 09:06:56 -07003850 case POWER_SUPPLY_TYPE_USB_HVDCP:
3851 case POWER_SUPPLY_TYPE_USB_HVDCP_3:
3852 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 3000000);
3853 break;
3854 default:
3855 smblib_err(chg, "Unknown APSD %d; forcing 500mA\n", pst);
3856 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 500000);
3857 break;
3858 }
3859}
3860
Ankit Sharmade321e12017-09-01 20:17:45 +05303861static void smblib_notify_extcon_props(struct smb_charger *chg, int id)
3862{
3863 union extcon_property_value val;
3864 union power_supply_propval prop_val;
3865
3866 smblib_get_prop_typec_cc_orientation(chg, &prop_val);
3867 val.intval = ((prop_val.intval == 2) ? 1 : 0);
3868 extcon_set_property(chg->extcon, id,
3869 EXTCON_PROP_USB_TYPEC_POLARITY, val);
3870
3871 val.intval = true;
3872 extcon_set_property(chg->extcon, id,
3873 EXTCON_PROP_USB_SS, val);
3874}
3875
3876static void smblib_notify_device_mode(struct smb_charger *chg, bool enable)
3877{
3878 if (enable)
3879 smblib_notify_extcon_props(chg, EXTCON_USB);
3880
3881 extcon_set_state_sync(chg->extcon, EXTCON_USB, enable);
3882}
3883
3884static void smblib_notify_usb_host(struct smb_charger *chg, bool enable)
3885{
3886 if (enable)
3887 smblib_notify_extcon_props(chg, EXTCON_USB_HOST);
3888
3889 extcon_set_state_sync(chg->extcon, EXTCON_USB_HOST, enable);
3890}
3891
Nicholas Troast34db5032016-03-28 12:26:44 -07003892#define HVDCP_DET_MS 2500
3893static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
3894{
Nicholas Troast34db5032016-03-28 12:26:44 -07003895 const struct apsd_result *apsd_result;
3896
3897 if (!rising)
3898 return;
3899
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07003900 apsd_result = smblib_update_usb_type(chg);
Nicholas Troastf9e44992017-03-14 09:06:56 -07003901
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003902 if (!chg->typec_legacy_valid)
Nicholas Troastf9e44992017-03-14 09:06:56 -07003903 smblib_force_legacy_icl(chg, apsd_result->pst);
3904
Nicholas Troast34db5032016-03-28 12:26:44 -07003905 switch (apsd_result->bit) {
3906 case SDP_CHARGER_BIT:
3907 case CDP_CHARGER_BIT:
Sundara Vinayagamf32d3f52018-02-27 18:08:44 +05303908 /* if not DCP, Enable pd here */
Abhijeet Dharmapurikarbb9505f2017-03-22 18:31:28 -07003909 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3910 false, 0);
Sundara Vinayagamf32d3f52018-02-27 18:08:44 +05303911 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB
3912 || chg->use_extcon)
Ankit Sharmade321e12017-09-01 20:17:45 +05303913 smblib_notify_device_mode(chg, true);
Abhijeet Dharmapurikarbb9505f2017-03-22 18:31:28 -07003914 break;
Nicholas Troast34db5032016-03-28 12:26:44 -07003915 case OCP_CHARGER_BIT:
3916 case FLOAT_CHARGER_BIT:
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303917 /* if not DCP then no hvdcp timeout happens, Enable pd here. */
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003918 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3919 false, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07003920 break;
3921 case DCP_CHARGER_BIT:
Harry Yang1369b7a2016-09-27 15:59:50 -07003922 if (chg->wa_flags & QC_CHARGER_DETECTION_WA_BIT)
3923 schedule_delayed_work(&chg->hvdcp_detect_work,
3924 msecs_to_jiffies(HVDCP_DET_MS));
Nicholas Troast34db5032016-03-28 12:26:44 -07003925 break;
3926 default:
3927 break;
3928 }
3929
Nicholas Troast34db5032016-03-28 12:26:44 -07003930 smblib_dbg(chg, PR_INTERRUPT, "IRQ: apsd-done rising; %s detected\n",
3931 apsd_result->name);
3932}
3933
3934irqreturn_t smblib_handle_usb_source_change(int irq, void *data)
3935{
3936 struct smb_irq_data *irq_data = data;
3937 struct smb_charger *chg = irq_data->parent_data;
3938 int rc = 0;
3939 u8 stat;
3940
Harry Yang287e3e92018-03-27 14:17:42 -07003941 if (chg->fake_usb_insertion)
3942 return IRQ_HANDLED;
3943
Nicholas Troast34db5032016-03-28 12:26:44 -07003944 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
3945 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003946 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07003947 return IRQ_HANDLED;
3948 }
3949 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
3950
Ashay Jaiswal0ce2c7c2017-11-14 12:29:02 +05303951 if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
3952 && (stat & APSD_DTC_STATUS_DONE_BIT)
Ashay Jaiswal8507aa52017-04-14 09:42:32 +05303953 && !chg->uusb_apsd_rerun_done) {
3954 /*
3955 * Force re-run APSD to handle slow insertion related
3956 * charger-mis-detection.
3957 */
3958 chg->uusb_apsd_rerun_done = true;
3959 smblib_rerun_apsd(chg);
3960 return IRQ_HANDLED;
3961 }
3962
Nicholas Troast34db5032016-03-28 12:26:44 -07003963 smblib_handle_apsd_done(chg,
3964 (bool)(stat & APSD_DTC_STATUS_DONE_BIT));
3965
3966 smblib_handle_hvdcp_detect_done(chg,
3967 (bool)(stat & QC_CHARGER_BIT));
3968
Harry Yang1369b7a2016-09-27 15:59:50 -07003969 smblib_handle_hvdcp_check_timeout(chg,
3970 (bool)(stat & HVDCP_CHECK_TIMEOUT_BIT),
3971 (bool)(stat & QC_CHARGER_BIT));
3972
Nicholas Troast34db5032016-03-28 12:26:44 -07003973 smblib_handle_hvdcp_3p0_auth_done(chg,
3974 (bool)(stat & QC_AUTH_DONE_STATUS_BIT));
3975
Nicholas Troast34db5032016-03-28 12:26:44 -07003976 smblib_handle_sdp_enumeration_done(chg,
3977 (bool)(stat & ENUMERATION_DONE_BIT));
3978
3979 smblib_handle_slow_plugin_timeout(chg,
3980 (bool)(stat & SLOW_PLUGIN_TIMEOUT_BIT));
3981
Harry Yangcdad2bf2016-10-04 17:03:56 -07003982 smblib_hvdcp_adaptive_voltage_change(chg);
3983
Nicholas Troast34db5032016-03-28 12:26:44 -07003984 power_supply_changed(chg->usb_psy);
3985
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08003986 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
3987 if (rc < 0) {
3988 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
3989 return IRQ_HANDLED;
3990 }
3991 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
3992
Nicholas Troast34db5032016-03-28 12:26:44 -07003993 return IRQ_HANDLED;
3994}
3995
Harry Yang29f23822017-09-09 00:09:36 -07003996static int typec_try_sink(struct smb_charger *chg)
3997{
3998 union power_supply_propval val;
3999 bool debounce_done, vbus_detected, sink;
4000 u8 stat;
4001 int exit_mode = ATTACHED_SRC, rc;
Abhijeet Dharmapurikarb0eb10d2017-11-13 18:42:40 -08004002 int typec_mode;
4003
4004 if (!(*chg->try_sink_enabled))
4005 return ATTACHED_SRC;
4006
4007 typec_mode = smblib_get_prop_typec_mode(chg);
4008 if (typec_mode == POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER
4009 || typec_mode == POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY)
4010 return ATTACHED_SRC;
4011
4012 /*
4013 * Try.SNK entry status - ATTACHWAIT.SRC state and detected Rd-open
4014 * or RD-Ra for TccDebounce time.
4015 */
Harry Yang29f23822017-09-09 00:09:36 -07004016
4017 /* ignore typec interrupt while try.snk WIP */
4018 chg->try_sink_active = true;
4019
4020 /* force SNK mode */
4021 val.intval = POWER_SUPPLY_TYPEC_PR_SINK;
4022 rc = smblib_set_prop_typec_power_role(chg, &val);
4023 if (rc < 0) {
4024 smblib_err(chg, "Couldn't set UFP mode rc=%d\n", rc);
4025 goto try_sink_exit;
4026 }
4027
4028 /* reduce Tccdebounce time to ~20ms */
4029 rc = smblib_masked_write(chg, MISC_CFG_REG,
4030 TCC_DEBOUNCE_20MS_BIT, TCC_DEBOUNCE_20MS_BIT);
4031 if (rc < 0) {
4032 smblib_err(chg, "Couldn't set MISC_CFG_REG rc=%d\n", rc);
4033 goto try_sink_exit;
4034 }
4035
4036 /*
4037 * give opportunity to the other side to be a SRC,
4038 * for tDRPTRY + Tccdebounce time
4039 */
Harry Yang692cec42017-10-16 16:21:19 -07004040 msleep(120);
Harry Yang29f23822017-09-09 00:09:36 -07004041
4042 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
4043 if (rc < 0) {
4044 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
4045 rc);
4046 goto try_sink_exit;
4047 }
4048
4049 debounce_done = stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT;
4050
4051 if (!debounce_done)
4052 /*
4053 * The other side didn't switch to source, either it
4054 * is an adamant sink or is removed go back to showing Rp
4055 */
4056 goto try_wait_src;
4057
4058 /*
4059 * We are in force sink mode and the other side has switched to
4060 * showing Rp. Config DRP in case the other side removes Rp so we
4061 * can quickly (20ms) switch to showing our Rp. Note that the spec
4062 * needs us to show Rp for 80mS while the drp DFP residency is just
4063 * 54mS. But 54mS is plenty time for us to react and force Rp for
4064 * the remaining 26mS.
4065 */
4066 val.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
4067 rc = smblib_set_prop_typec_power_role(chg, &val);
4068 if (rc < 0) {
4069 smblib_err(chg, "Couldn't set DFP mode rc=%d\n",
4070 rc);
4071 goto try_sink_exit;
4072 }
4073
4074 /*
4075 * while other side is Rp, wait for VBUS from it; exit if other side
4076 * removes Rp
4077 */
4078 do {
4079 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
4080 if (rc < 0) {
4081 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
4082 rc);
4083 goto try_sink_exit;
4084 }
4085
4086 debounce_done = stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT;
4087 vbus_detected = stat & TYPEC_VBUS_STATUS_BIT;
4088
4089 /* Successfully transitioned to ATTACHED.SNK */
4090 if (vbus_detected && debounce_done) {
4091 exit_mode = ATTACHED_SINK;
4092 goto try_sink_exit;
4093 }
4094
4095 /*
4096 * Ensure sink since drp may put us in source if other
4097 * side switches back to Rd
4098 */
4099 sink = !(stat & UFP_DFP_MODE_STATUS_BIT);
4100
4101 usleep_range(1000, 2000);
4102 } while (debounce_done && sink);
4103
4104try_wait_src:
4105 /*
4106 * Transition to trywait.SRC state. check if other side still wants
4107 * to be SNK or has been removed.
4108 */
4109 val.intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
4110 rc = smblib_set_prop_typec_power_role(chg, &val);
4111 if (rc < 0) {
4112 smblib_err(chg, "Couldn't set UFP mode rc=%d\n", rc);
4113 goto try_sink_exit;
4114 }
4115
4116 /* Need to be in this state for tDRPTRY time, 75ms~150ms */
4117 msleep(80);
4118
4119 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
4120 if (rc < 0) {
4121 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
4122 goto try_sink_exit;
4123 }
4124
4125 debounce_done = stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT;
4126
4127 if (debounce_done)
4128 /* the other side wants to be a sink */
4129 exit_mode = ATTACHED_SRC;
4130 else
4131 /* the other side is detached */
4132 exit_mode = UNATTACHED_SINK;
4133
4134try_sink_exit:
4135 /* release forcing of SRC/SNK mode */
4136 val.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
4137 rc = smblib_set_prop_typec_power_role(chg, &val);
4138 if (rc < 0)
4139 smblib_err(chg, "Couldn't set DFP mode rc=%d\n", rc);
4140
4141 /* revert Tccdebounce time back to ~120ms */
4142 rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT, 0);
4143 if (rc < 0)
4144 smblib_err(chg, "Couldn't set MISC_CFG_REG rc=%d\n", rc);
4145
4146 chg->try_sink_active = false;
4147
4148 return exit_mode;
4149}
4150
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004151static void typec_sink_insertion(struct smb_charger *chg)
4152{
Harry Yang29f23822017-09-09 00:09:36 -07004153 int exit_mode;
Abhijeet Dharmapurikarb0eb10d2017-11-13 18:42:40 -08004154 int typec_mode;
Harry Yang29f23822017-09-09 00:09:36 -07004155
Abhijeet Dharmapurikarb0eb10d2017-11-13 18:42:40 -08004156 exit_mode = typec_try_sink(chg);
Harry Yang29f23822017-09-09 00:09:36 -07004157
Abhijeet Dharmapurikarb0eb10d2017-11-13 18:42:40 -08004158 if (exit_mode != ATTACHED_SRC) {
4159 smblib_usb_typec_change(chg);
4160 return;
Harry Yang29f23822017-09-09 00:09:36 -07004161 }
4162
Abhijeet Dharmapurikarb0eb10d2017-11-13 18:42:40 -08004163 typec_mode = smblib_get_prop_typec_mode(chg);
4164 if (typec_mode == POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER)
4165 chg->is_audio_adapter = true;
4166
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004167 /* when a sink is inserted we should not wait on hvdcp timeout to
4168 * enable pd
4169 */
4170 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
4171 false, 0);
Ankit Sharmade321e12017-09-01 20:17:45 +05304172 if (chg->use_extcon) {
4173 smblib_notify_usb_host(chg, true);
4174 chg->otg_present = true;
4175 }
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004176}
Nicholas Troast34db5032016-03-28 12:26:44 -07004177
Harry Yangd89ff1f2016-12-05 14:59:11 -08004178static void typec_sink_removal(struct smb_charger *chg)
4179{
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05304180 smblib_set_charge_param(chg, &chg->param.freq_boost,
4181 chg->chg_freq.freq_above_otg_threshold);
Harry Yangd89ff1f2016-12-05 14:59:11 -08004182 chg->boost_current_ua = 0;
4183}
4184
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004185static void smblib_handle_typec_removal(struct smb_charger *chg)
4186{
Nicholas Troastfe74c592017-03-14 09:20:55 -07004187 int rc;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304188 struct smb_irq_data *data;
4189 struct storm_watch *wdata;
Tirupathi Reddy0c5d0a52017-09-27 16:31:07 +05304190 union power_supply_propval val;
Nicholas Troastfe74c592017-03-14 09:20:55 -07004191
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004192 chg->cc2_detach_wa_active = false;
4193
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05304194 rc = smblib_request_dpdm(chg, false);
4195 if (rc < 0)
4196 smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05304197
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304198 if (chg->wa_flags & BOOST_BACK_WA) {
4199 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
4200 if (data) {
4201 wdata = &data->storm_data;
4202 update_storm_count(wdata, WEAK_CHG_STORM_COUNT);
4203 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
4204 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
4205 false, 0);
4206 }
4207 }
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05304208
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004209 /* reset APSD voters */
4210 vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, false, 0);
4211 vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304212
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004213 cancel_delayed_work_sync(&chg->pl_enable_work);
4214 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
4215
4216 /* reset input current limit voters */
4217 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
4218 vote(chg->usb_icl_votable, PD_VOTER, false, 0);
4219 vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
4220 vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
4221 vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
Ashay Jaiswalae23a042017-05-18 15:28:31 +05304222 vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
Abhijeet Dharmapurikar66d2c442017-07-12 11:55:36 -07004223 vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
Harry Yangfeb95002017-10-06 12:11:42 -07004224 vote(chg->usb_icl_votable, CTM_VOTER, false, 0);
Ashay Jaiswal1c360c82018-03-15 23:24:42 +05304225 vote(chg->usb_icl_votable, HVDCP2_ICL_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004226
4227 /* reset hvdcp voters */
4228 vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, true, 0);
4229 vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER, true, 0);
Umang Agrawal49680b62018-04-16 14:41:11 +05304230 vote(chg->hvdcp_hw_inov_dis_votable, OV_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004231
4232 /* reset power delivery voters */
4233 vote(chg->pd_allowed_votable, PD_VOTER, false, 0);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004234 vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0);
4235 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER, true, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004236
4237 /* reset usb irq voters */
Harry Yang4bf7d962017-03-13 16:51:43 -07004238 vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
4239 vote(chg->usb_irq_enable_votable, QC_VOTER, false, 0);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004240
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004241 /* reset parallel voters */
4242 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
Abhijeet Dharmapurikar004f7ba2017-09-26 16:23:51 -07004243 vote(chg->pl_disable_votable, PL_FCC_LOW_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004244 vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
4245 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
4246 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
Harry Yang1d1034c2016-06-15 12:09:42 -07004247
Ashay Jaiswal3d22f4b2017-11-15 18:09:19 +05304248 vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0);
Nicholas Troast8995a702016-12-05 10:22:22 -08004249 chg->vconn_attempts = 0;
4250 chg->otg_attempts = 0;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05304251 chg->pulse_cnt = 0;
4252 chg->usb_icl_delta_ua = 0;
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004253 chg->voltage_min_uv = MICRO_5V;
4254 chg->voltage_max_uv = MICRO_5V;
4255 chg->pd_active = 0;
4256 chg->pd_hard_reset = 0;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004257 chg->typec_legacy_valid = false;
Harry Yang3b113a52016-12-08 12:37:40 -08004258
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05304259 /* write back the default FLOAT charger configuration */
4260 rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
4261 (u8)FLOAT_OPTIONS_MASK, chg->float_cfg);
4262 if (rc < 0)
4263 smblib_err(chg, "Couldn't write float charger options rc=%d\n",
4264 rc);
4265
Abhijeet Dharmapurikar676bd792017-05-31 16:21:57 -07004266 /* reset back to 120mS tCC debounce */
4267 rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT, 0);
4268 if (rc < 0)
4269 smblib_err(chg, "Couldn't set 120mS tCC debounce rc=%d\n", rc);
4270
Nicholas Troastfe74c592017-03-14 09:20:55 -07004271 /* enable APSD CC trigger for next insertion */
4272 rc = smblib_masked_write(chg, TYPE_C_CFG_REG,
4273 APSD_START_ON_CC_BIT, APSD_START_ON_CC_BIT);
4274 if (rc < 0)
4275 smblib_err(chg, "Couldn't enable APSD_START_ON_CC rc=%d\n", rc);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08004276
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004277 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
4278 /* re-enable AUTH_IRQ_EN_CFG_BIT */
4279 rc = smblib_masked_write(chg,
4280 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
4281 AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
4282 if (rc < 0)
4283 smblib_err(chg,
4284 "Couldn't enable QC auth setting rc=%d\n", rc);
4285 }
4286
4287 /* reconfigure allowed voltage for HVDCP */
4288 rc = smblib_set_adapter_allowance(chg,
4289 USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
4290 if (rc < 0)
4291 smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
4292 rc);
4293
Abhijeet Dharmapurikarb0eb10d2017-11-13 18:42:40 -08004294 if (chg->is_audio_adapter == true)
4295 /* wait for the audio driver to lower its en gpio */
4296 msleep(*chg->audio_headset_drp_wait_ms);
4297
4298 chg->is_audio_adapter = false;
4299
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004300 /* enable DRP */
Tirupathi Reddy0c5d0a52017-09-27 16:31:07 +05304301 val.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
4302 rc = smblib_set_prop_typec_power_role(chg, &val);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004303 if (rc < 0)
4304 smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc);
4305
4306 /* HW controlled CC_OUT */
4307 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
4308 TYPEC_SPARE_CFG_BIT, 0);
4309 if (rc < 0)
4310 smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n", rc);
4311
4312 /* restore crude sensor */
4313 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
4314 if (rc < 0)
4315 smblib_err(chg, "Couldn't restore crude sensor rc=%d\n", rc);
4316
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004317 mutex_lock(&chg->vconn_oc_lock);
4318 if (!chg->vconn_en)
4319 goto unlock;
4320
4321 smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4322 VCONN_EN_VALUE_BIT, 0);
4323 chg->vconn_en = false;
4324
4325unlock:
4326 mutex_unlock(&chg->vconn_oc_lock);
4327
Abhijeet Dharmapurikar319d6942017-06-05 17:14:17 -07004328 /* clear exit sink based on cc */
4329 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4330 EXIT_SNK_BASED_ON_CC_BIT, 0);
4331 if (rc < 0)
4332 smblib_err(chg, "Couldn't clear exit_sink_based_on_cc rc=%d\n",
4333 rc);
4334
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08004335 typec_sink_removal(chg);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004336 smblib_update_usb_type(chg);
Ankit Sharmade321e12017-09-01 20:17:45 +05304337
4338 if (chg->use_extcon) {
4339 if (chg->otg_present)
4340 smblib_notify_usb_host(chg, false);
4341 else
4342 smblib_notify_device_mode(chg, false);
4343 }
4344 chg->otg_present = false;
Nicholas Troast34db5032016-03-28 12:26:44 -07004345}
4346
Nicholas Troaste1932e42017-04-12 12:38:18 -07004347static void smblib_handle_typec_insertion(struct smb_charger *chg)
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07004348{
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004349 int rc;
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07004350
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004351 vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, false, 0);
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07004352
Nicholas Troastfe74c592017-03-14 09:20:55 -07004353 /* disable APSD CC trigger since CC is attached */
4354 rc = smblib_masked_write(chg, TYPE_C_CFG_REG, APSD_START_ON_CC_BIT, 0);
4355 if (rc < 0)
4356 smblib_err(chg, "Couldn't disable APSD_START_ON_CC rc=%d\n",
4357 rc);
4358
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05304359 if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT) {
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004360 typec_sink_insertion(chg);
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05304361 } else {
4362 rc = smblib_request_dpdm(chg, true);
4363 if (rc < 0)
4364 smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
Harry Yangd89ff1f2016-12-05 14:59:11 -08004365 typec_sink_removal(chg);
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05304366 }
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07004367}
4368
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05304369static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode)
4370{
4371 int rp_ua;
4372 const struct apsd_result *apsd = smblib_get_apsd_result(chg);
4373
4374 if ((apsd->pst != POWER_SUPPLY_TYPE_USB_DCP)
4375 && (apsd->pst != POWER_SUPPLY_TYPE_USB_FLOAT))
4376 return;
4377
4378 /*
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05304379 * if APSD indicates FLOAT and the USB stack had detected SDP,
4380 * do not respond to Rp changes as we do not confirm that its
4381 * a legacy cable
4382 */
4383 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
4384 return;
4385 /*
4386 * We want the ICL vote @ 100mA for a FLOAT charger
4387 * until the detection by the USB stack is complete.
4388 * Ignore the Rp changes unless there is a
4389 * pre-existing valid vote.
4390 */
4391 if (apsd->pst == POWER_SUPPLY_TYPE_USB_FLOAT &&
4392 get_client_vote(chg->usb_icl_votable,
4393 LEGACY_UNKNOWN_VOTER) <= 100000)
4394 return;
4395
4396 /*
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05304397 * handle Rp change for DCP/FLOAT/OCP.
4398 * Update the current only if the Rp is different from
4399 * the last Rp value.
4400 */
4401 smblib_dbg(chg, PR_MISC, "CC change old_mode=%d new_mode=%d\n",
4402 chg->typec_mode, typec_mode);
4403
4404 rp_ua = get_rp_based_dcp_current(chg, typec_mode);
4405 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua);
4406}
4407
Nicholas Troaste1932e42017-04-12 12:38:18 -07004408static void smblib_handle_typec_cc_state_change(struct smb_charger *chg)
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004409{
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05304410 int typec_mode;
4411
Nicholas Troaste1932e42017-04-12 12:38:18 -07004412 if (chg->pr_swap_in_progress)
4413 return;
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004414
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05304415 typec_mode = smblib_get_prop_typec_mode(chg);
4416 if (chg->typec_present && (typec_mode != chg->typec_mode))
4417 smblib_handle_rp_change(chg, typec_mode);
4418
4419 chg->typec_mode = typec_mode;
4420
Nicholas Troaste1932e42017-04-12 12:38:18 -07004421 if (!chg->typec_present && chg->typec_mode != POWER_SUPPLY_TYPEC_NONE) {
4422 chg->typec_present = true;
4423 smblib_dbg(chg, PR_MISC, "TypeC %s insertion\n",
4424 smblib_typec_mode_name[chg->typec_mode]);
4425 smblib_handle_typec_insertion(chg);
4426 } else if (chg->typec_present &&
4427 chg->typec_mode == POWER_SUPPLY_TYPEC_NONE) {
4428 chg->typec_present = false;
4429 smblib_dbg(chg, PR_MISC, "TypeC removal\n");
4430 smblib_handle_typec_removal(chg);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004431 }
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004432
Abhijeet Dharmapurikar66d2c442017-07-12 11:55:36 -07004433 /* suspend usb if sink */
Harry Yangca0664e2017-08-18 11:40:06 -07004434 if ((chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
4435 && chg->typec_present)
Abhijeet Dharmapurikar66d2c442017-07-12 11:55:36 -07004436 vote(chg->usb_icl_votable, OTG_VOTER, true, 0);
4437 else
4438 vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
4439
Nicholas Troaste1932e42017-04-12 12:38:18 -07004440 smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n",
4441 smblib_typec_mode_name[chg->typec_mode]);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004442}
4443
Harry Yang29f23822017-09-09 00:09:36 -07004444void smblib_usb_typec_change(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07004445{
Nicholas Troast34db5032016-03-28 12:26:44 -07004446 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07004447
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07004448 rc = smblib_multibyte_read(chg, TYPE_C_STATUS_1_REG,
4449 chg->typec_status, 5);
Nicholas Troast34db5032016-03-28 12:26:44 -07004450 if (rc < 0) {
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07004451 smblib_err(chg, "Couldn't cache USB Type-C status rc=%d\n", rc);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004452 return;
Nicholas Troast34db5032016-03-28 12:26:44 -07004453 }
Nicholas Troast34db5032016-03-28 12:26:44 -07004454
Nicholas Troaste1932e42017-04-12 12:38:18 -07004455 smblib_handle_typec_cc_state_change(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07004456
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07004457 if (chg->typec_status[3] & TYPEC_VBUS_ERROR_STATUS_BIT)
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004458 smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n");
Harry Yangd757c0f2016-09-23 10:52:05 -07004459
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07004460 if (chg->typec_status[3] & TYPEC_VCONN_OVERCURR_STATUS_BIT)
Nicholas Troastb11015f2017-01-17 17:56:45 -08004461 schedule_work(&chg->vconn_oc_work);
Nicholas Troast8995a702016-12-05 10:22:22 -08004462
Nicholas Troastb1486552016-11-10 08:20:11 -08004463 power_supply_changed(chg->usb_psy);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004464}
4465
4466irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
4467{
4468 struct smb_irq_data *irq_data = data;
4469 struct smb_charger *chg = irq_data->parent_data;
4470
Ashay Jaiswal0ce2c7c2017-11-14 12:29:02 +05304471 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) {
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05304472 cancel_delayed_work_sync(&chg->uusb_otg_work);
4473 vote(chg->awake_votable, OTG_DELAY_VOTER, true, 0);
4474 smblib_dbg(chg, PR_INTERRUPT, "Scheduling OTG work\n");
4475 schedule_delayed_work(&chg->uusb_otg_work,
4476 msecs_to_jiffies(chg->otg_delay_ms));
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004477 return IRQ_HANDLED;
4478 }
4479
Harry Yang29f23822017-09-09 00:09:36 -07004480 if (chg->cc2_detach_wa_active || chg->typec_en_dis_active ||
4481 chg->try_sink_active) {
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07004482 smblib_dbg(chg, PR_MISC | PR_INTERRUPT, "Ignoring since %s active\n",
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004483 chg->cc2_detach_wa_active ?
4484 "cc2_detach_wa" : "typec_en_dis");
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004485 return IRQ_HANDLED;
4486 }
4487
Abhijeet Dharmapurikar049b2552017-07-12 11:27:51 -07004488 if (chg->pr_swap_in_progress) {
4489 smblib_dbg(chg, PR_INTERRUPT,
4490 "Ignoring since pr_swap_in_progress\n");
4491 return IRQ_HANDLED;
4492 }
4493
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004494 mutex_lock(&chg->lock);
4495 smblib_usb_typec_change(chg);
4496 mutex_unlock(&chg->lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07004497 return IRQ_HANDLED;
4498}
4499
Abhijeet Dharmapurikar23916642016-10-03 10:38:50 -07004500irqreturn_t smblib_handle_dc_plugin(int irq, void *data)
4501{
4502 struct smb_irq_data *irq_data = data;
4503 struct smb_charger *chg = irq_data->parent_data;
4504
4505 power_supply_changed(chg->dc_psy);
4506 return IRQ_HANDLED;
4507}
4508
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004509irqreturn_t smblib_handle_high_duty_cycle(int irq, void *data)
4510{
4511 struct smb_irq_data *irq_data = data;
4512 struct smb_charger *chg = irq_data->parent_data;
4513
4514 chg->is_hdc = true;
Fenglin Wu4f4dcc12017-08-24 14:28:54 +08004515 /*
4516 * Disable usb IRQs after the flag set and re-enable IRQs after
4517 * the flag cleared in the delayed work queue, to avoid any IRQ
4518 * storming during the delays
4519 */
4520 if (chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq)
4521 disable_irq_nosync(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
4522
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004523 schedule_delayed_work(&chg->clear_hdc_work, msecs_to_jiffies(60));
4524
4525 return IRQ_HANDLED;
4526}
4527
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05304528static void smblib_bb_removal_work(struct work_struct *work)
4529{
4530 struct smb_charger *chg = container_of(work, struct smb_charger,
4531 bb_removal_work.work);
4532
4533 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
4534 vote(chg->awake_votable, BOOST_BACK_VOTER, false, 0);
4535}
4536
4537#define BOOST_BACK_UNVOTE_DELAY_MS 750
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304538#define BOOST_BACK_STORM_COUNT 3
4539#define WEAK_CHG_STORM_COUNT 8
Nicholas Troastabedaf72016-09-16 11:07:45 -07004540irqreturn_t smblib_handle_switcher_power_ok(int irq, void *data)
4541{
4542 struct smb_irq_data *irq_data = data;
4543 struct smb_charger *chg = irq_data->parent_data;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304544 struct storm_watch *wdata = &irq_data->storm_data;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004545 int rc, usb_icl;
Nicholas Troastabedaf72016-09-16 11:07:45 -07004546 u8 stat;
4547
4548 if (!(chg->wa_flags & BOOST_BACK_WA))
4549 return IRQ_HANDLED;
4550
4551 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
4552 if (rc < 0) {
4553 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n", rc);
4554 return IRQ_HANDLED;
4555 }
4556
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004557 /* skip suspending input if its already suspended by some other voter */
4558 usb_icl = get_effective_result(chg->usb_icl_votable);
Harry Yang379484a2017-08-29 10:26:14 -07004559 if ((stat & USE_USBIN_BIT) && usb_icl >= 0 && usb_icl <= USBIN_25MA)
Nicholas Troastabedaf72016-09-16 11:07:45 -07004560 return IRQ_HANDLED;
4561
Abhijeet Dharmapurikar2823fe32016-12-05 17:52:11 -08004562 if (stat & USE_DCIN_BIT)
Nicholas Troastabedaf72016-09-16 11:07:45 -07004563 return IRQ_HANDLED;
4564
4565 if (is_storming(&irq_data->storm_data)) {
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304566 /* This could be a weak charger reduce ICL */
4567 if (!is_client_vote_enabled(chg->usb_icl_votable,
4568 WEAK_CHARGER_VOTER)) {
4569 smblib_err(chg,
4570 "Weak charger detected: voting %dmA ICL\n",
4571 *chg->weak_chg_icl_ua / 1000);
4572 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
4573 true, *chg->weak_chg_icl_ua);
4574 /*
4575 * reset storm data and set the storm threshold
4576 * to 3 for reverse boost detection.
4577 */
4578 update_storm_count(wdata, BOOST_BACK_STORM_COUNT);
4579 } else {
4580 smblib_err(chg,
4581 "Reverse boost detected: voting 0mA to suspend input\n");
4582 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, true, 0);
4583 vote(chg->awake_votable, BOOST_BACK_VOTER, true, 0);
4584 /*
4585 * Remove the boost-back vote after a delay, to avoid
4586 * permanently suspending the input if the boost-back
4587 * condition is unintentionally hit.
4588 */
4589 schedule_delayed_work(&chg->bb_removal_work,
4590 msecs_to_jiffies(BOOST_BACK_UNVOTE_DELAY_MS));
4591 }
Nicholas Troastabedaf72016-09-16 11:07:45 -07004592 }
4593
4594 return IRQ_HANDLED;
4595}
4596
Nicholas Troast15dc0c82016-10-18 15:15:21 -07004597irqreturn_t smblib_handle_wdog_bark(int irq, void *data)
4598{
4599 struct smb_irq_data *irq_data = data;
4600 struct smb_charger *chg = irq_data->parent_data;
4601 int rc;
4602
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05304603 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
4604
Nicholas Troast15dc0c82016-10-18 15:15:21 -07004605 rc = smblib_write(chg, BARK_BITE_WDOG_PET_REG, BARK_BITE_WDOG_PET_BIT);
4606 if (rc < 0)
4607 smblib_err(chg, "Couldn't pet the dog rc=%d\n", rc);
4608
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +05304609 if (chg->step_chg_enabled || chg->sw_jeita_enabled)
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05304610 power_supply_changed(chg->batt_psy);
4611
Nicholas Troast15dc0c82016-10-18 15:15:21 -07004612 return IRQ_HANDLED;
4613}
4614
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004615/**************
4616 * Additional USB PSY getters/setters
4617 * that call interrupt functions
4618 ***************/
4619
4620int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg,
4621 union power_supply_propval *val)
4622{
4623 val->intval = chg->pr_swap_in_progress;
4624 return 0;
4625}
4626
4627int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg,
4628 const union power_supply_propval *val)
4629{
Abhijeet Dharmapurikar676bd792017-05-31 16:21:57 -07004630 int rc;
4631
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004632 chg->pr_swap_in_progress = val->intval;
4633 /*
4634 * call the cc changed irq to handle real removals while
4635 * PR_SWAP was in progress
4636 */
4637 smblib_usb_typec_change(chg);
Abhijeet Dharmapurikar676bd792017-05-31 16:21:57 -07004638 rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT,
4639 val->intval ? TCC_DEBOUNCE_20MS_BIT : 0);
4640 if (rc < 0)
4641 smblib_err(chg, "Couldn't set tCC debounce rc=%d\n", rc);
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004642 return 0;
4643}
4644
Nicholas Troast34db5032016-03-28 12:26:44 -07004645/***************
4646 * Work Queues *
4647 ***************/
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05304648static void smblib_uusb_otg_work(struct work_struct *work)
4649{
4650 struct smb_charger *chg = container_of(work, struct smb_charger,
4651 uusb_otg_work.work);
4652 int rc;
4653 u8 stat;
4654 bool otg;
4655
4656 rc = smblib_read(chg, TYPE_C_STATUS_3_REG, &stat);
4657 if (rc < 0) {
4658 smblib_err(chg, "Couldn't read TYPE_C_STATUS_3 rc=%d\n", rc);
4659 goto out;
4660 }
4661
4662 otg = !!(stat & (U_USB_GND_NOVBUS_BIT | U_USB_GND_BIT));
4663 extcon_set_cable_state_(chg->extcon, EXTCON_USB_HOST, otg);
4664 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_3 = 0x%02x OTG=%d\n",
4665 stat, otg);
4666 power_supply_changed(chg->usb_psy);
4667
4668out:
4669 vote(chg->awake_votable, OTG_DELAY_VOTER, false, 0);
4670}
4671
Nicholas Troast34db5032016-03-28 12:26:44 -07004672
4673static void smblib_hvdcp_detect_work(struct work_struct *work)
4674{
4675 struct smb_charger *chg = container_of(work, struct smb_charger,
4676 hvdcp_detect_work.work);
Nicholas Troast34db5032016-03-28 12:26:44 -07004677
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07004678 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
4679 false, 0);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004680 power_supply_changed(chg->usb_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07004681}
4682
Harry Yangfe913842016-08-10 12:27:28 -07004683static void bms_update_work(struct work_struct *work)
Harry Yang5e1a5222016-07-26 15:16:04 -07004684{
4685 struct smb_charger *chg = container_of(work, struct smb_charger,
4686 bms_update_work);
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05304687
4688 smblib_suspend_on_debug_battery(chg);
4689
4690 if (chg->batt_psy)
4691 power_supply_changed(chg->batt_psy);
Harry Yang5e1a5222016-07-26 15:16:04 -07004692}
4693
Harry Yang166b15d2017-08-28 13:00:40 -07004694static void pl_update_work(struct work_struct *work)
4695{
4696 struct smb_charger *chg = container_of(work, struct smb_charger,
4697 pl_update_work);
4698
4699 smblib_stat_sw_override_cfg(chg, false);
4700}
4701
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004702static void clear_hdc_work(struct work_struct *work)
4703{
4704 struct smb_charger *chg = container_of(work, struct smb_charger,
4705 clear_hdc_work.work);
4706
4707 chg->is_hdc = 0;
Fenglin Wu4f4dcc12017-08-24 14:28:54 +08004708 if (chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq)
4709 enable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004710}
4711
Harry Yang755a34b2016-11-01 01:18:51 -07004712static void rdstd_cc2_detach_work(struct work_struct *work)
4713{
4714 int rc;
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004715 u8 stat4, stat5;
Harry Yang755a34b2016-11-01 01:18:51 -07004716 struct smb_charger *chg = container_of(work, struct smb_charger,
4717 rdstd_cc2_detach_work);
4718
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004719 if (!chg->cc2_detach_wa_active)
4720 return;
4721
Harry Yang755a34b2016-11-01 01:18:51 -07004722 /*
4723 * WA steps -
4724 * 1. Enable both UFP and DFP, wait for 10ms.
4725 * 2. Disable DFP, wait for 30ms.
4726 * 3. Removal detected if both TYPEC_DEBOUNCE_DONE_STATUS
4727 * and TIMER_STAGE bits are gone, otherwise repeat all by
4728 * work rescheduling.
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004729 * Note, work will be cancelled when USB_PLUGIN rises.
Harry Yang755a34b2016-11-01 01:18:51 -07004730 */
4731
4732 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4733 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT,
4734 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT);
4735 if (rc < 0) {
4736 smblib_err(chg, "Couldn't write TYPE_C_CTRL_REG rc=%d\n", rc);
4737 return;
4738 }
4739
4740 usleep_range(10000, 11000);
4741
4742 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4743 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT,
4744 UFP_EN_CMD_BIT);
4745 if (rc < 0) {
4746 smblib_err(chg, "Couldn't write TYPE_C_CTRL_REG rc=%d\n", rc);
4747 return;
4748 }
4749
4750 usleep_range(30000, 31000);
4751
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004752 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
Harry Yang755a34b2016-11-01 01:18:51 -07004753 if (rc < 0) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004754 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
Harry Yang755a34b2016-11-01 01:18:51 -07004755 return;
4756 }
Harry Yang755a34b2016-11-01 01:18:51 -07004757
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004758 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
Harry Yang755a34b2016-11-01 01:18:51 -07004759 if (rc < 0) {
4760 smblib_err(chg,
4761 "Couldn't read TYPE_C_STATUS_5_REG rc=%d\n", rc);
4762 return;
4763 }
Harry Yang755a34b2016-11-01 01:18:51 -07004764
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004765 if ((stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT)
4766 || (stat5 & TIMER_STAGE_2_BIT)) {
4767 smblib_dbg(chg, PR_MISC, "rerunning DD=%d TS2BIT=%d\n",
4768 (int)(stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT),
4769 (int)(stat5 & TIMER_STAGE_2_BIT));
4770 goto rerun;
4771 }
4772
4773 smblib_dbg(chg, PR_MISC, "Bingo CC2 Removal detected\n");
4774 chg->cc2_detach_wa_active = false;
4775 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4776 EXIT_SNK_BASED_ON_CC_BIT, 0);
Harry Yang755a34b2016-11-01 01:18:51 -07004777 smblib_reg_block_restore(chg, cc2_detach_settings);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004778 mutex_lock(&chg->lock);
4779 smblib_usb_typec_change(chg);
4780 mutex_unlock(&chg->lock);
Harry Yang755a34b2016-11-01 01:18:51 -07004781 return;
4782
4783rerun:
4784 schedule_work(&chg->rdstd_cc2_detach_work);
4785}
4786
Nicholas Troastb11015f2017-01-17 17:56:45 -08004787static void smblib_otg_oc_exit(struct smb_charger *chg, bool success)
4788{
4789 int rc;
4790
4791 chg->otg_attempts = 0;
4792 if (!success) {
4793 smblib_err(chg, "OTG soft start failed\n");
4794 chg->otg_en = false;
4795 }
4796
4797 smblib_dbg(chg, PR_OTG, "enabling VBUS < 1V check\n");
4798 rc = smblib_masked_write(chg, OTG_CFG_REG,
4799 QUICKSTART_OTG_FASTROLESWAP_BIT, 0);
4800 if (rc < 0)
4801 smblib_err(chg, "Couldn't enable VBUS < 1V check rc=%d\n", rc);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004802}
4803
4804#define MAX_OC_FALLING_TRIES 10
4805static void smblib_otg_oc_work(struct work_struct *work)
4806{
4807 struct smb_charger *chg = container_of(work, struct smb_charger,
4808 otg_oc_work);
4809 int rc, i;
4810 u8 stat;
4811
4812 if (!chg->vbus_vreg || !chg->vbus_vreg->rdev)
4813 return;
4814
4815 smblib_err(chg, "over-current detected on VBUS\n");
4816 mutex_lock(&chg->otg_oc_lock);
4817 if (!chg->otg_en)
4818 goto unlock;
4819
4820 smblib_dbg(chg, PR_OTG, "disabling VBUS < 1V check\n");
4821 smblib_masked_write(chg, OTG_CFG_REG,
4822 QUICKSTART_OTG_FASTROLESWAP_BIT,
4823 QUICKSTART_OTG_FASTROLESWAP_BIT);
4824
4825 /*
4826 * If 500ms has passed and another over-current interrupt has not
4827 * triggered then it is likely that the software based soft start was
4828 * successful and the VBUS < 1V restriction should be re-enabled.
4829 */
4830 schedule_delayed_work(&chg->otg_ss_done_work, msecs_to_jiffies(500));
4831
4832 rc = _smblib_vbus_regulator_disable(chg->vbus_vreg->rdev);
4833 if (rc < 0) {
4834 smblib_err(chg, "Couldn't disable VBUS rc=%d\n", rc);
4835 goto unlock;
4836 }
4837
4838 if (++chg->otg_attempts > OTG_MAX_ATTEMPTS) {
4839 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4840 smblib_err(chg, "OTG failed to enable after %d attempts\n",
4841 chg->otg_attempts - 1);
4842 smblib_otg_oc_exit(chg, false);
4843 goto unlock;
4844 }
4845
4846 /*
4847 * The real time status should go low within 10ms. Poll every 1-2ms to
4848 * minimize the delay when re-enabling OTG.
4849 */
4850 for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) {
4851 usleep_range(1000, 2000);
4852 rc = smblib_read(chg, OTG_BASE + INT_RT_STS_OFFSET, &stat);
4853 if (rc >= 0 && !(stat & OTG_OVERCURRENT_RT_STS_BIT))
4854 break;
4855 }
4856
4857 if (i >= MAX_OC_FALLING_TRIES) {
4858 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4859 smblib_err(chg, "OTG OC did not fall after %dms\n",
4860 2 * MAX_OC_FALLING_TRIES);
4861 smblib_otg_oc_exit(chg, false);
4862 goto unlock;
4863 }
4864
4865 smblib_dbg(chg, PR_OTG, "OTG OC fell after %dms\n", 2 * i + 1);
4866 rc = _smblib_vbus_regulator_enable(chg->vbus_vreg->rdev);
4867 if (rc < 0) {
4868 smblib_err(chg, "Couldn't enable VBUS rc=%d\n", rc);
4869 goto unlock;
4870 }
4871
4872unlock:
4873 mutex_unlock(&chg->otg_oc_lock);
4874}
4875
4876static void smblib_vconn_oc_work(struct work_struct *work)
4877{
4878 struct smb_charger *chg = container_of(work, struct smb_charger,
4879 vconn_oc_work);
4880 int rc, i;
4881 u8 stat;
4882
Ashay Jaiswal0ce2c7c2017-11-14 12:29:02 +05304883 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
Ashay Jaiswal15edce42017-03-31 23:29:58 +05304884 return;
4885
Nicholas Troastb11015f2017-01-17 17:56:45 -08004886 smblib_err(chg, "over-current detected on VCONN\n");
4887 if (!chg->vconn_vreg || !chg->vconn_vreg->rdev)
4888 return;
4889
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07004890 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004891 rc = _smblib_vconn_regulator_disable(chg->vconn_vreg->rdev);
4892 if (rc < 0) {
4893 smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc);
4894 goto unlock;
4895 }
4896
4897 if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
4898 smblib_err(chg, "VCONN failed to enable after %d attempts\n",
Guru Das Srinagesh2034dbe2018-02-27 11:16:08 -08004899 chg->vconn_attempts - 1);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004900 chg->vconn_en = false;
4901 chg->vconn_attempts = 0;
4902 goto unlock;
4903 }
4904
4905 /*
4906 * The real time status should go low within 10ms. Poll every 1-2ms to
4907 * minimize the delay when re-enabling OTG.
4908 */
4909 for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) {
4910 usleep_range(1000, 2000);
4911 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
4912 if (rc >= 0 && !(stat & TYPEC_VCONN_OVERCURR_STATUS_BIT))
4913 break;
4914 }
4915
4916 if (i >= MAX_OC_FALLING_TRIES) {
4917 smblib_err(chg, "VCONN OC did not fall after %dms\n",
4918 2 * MAX_OC_FALLING_TRIES);
4919 chg->vconn_en = false;
4920 chg->vconn_attempts = 0;
4921 goto unlock;
4922 }
Nicholas Troastb11015f2017-01-17 17:56:45 -08004923 smblib_dbg(chg, PR_OTG, "VCONN OC fell after %dms\n", 2 * i + 1);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004924
4925 rc = _smblib_vconn_regulator_enable(chg->vconn_vreg->rdev);
4926 if (rc < 0) {
4927 smblib_err(chg, "Couldn't enable VCONN rc=%d\n", rc);
4928 goto unlock;
4929 }
4930
4931unlock:
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07004932 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004933}
4934
4935static void smblib_otg_ss_done_work(struct work_struct *work)
4936{
4937 struct smb_charger *chg = container_of(work, struct smb_charger,
4938 otg_ss_done_work.work);
4939 int rc;
4940 bool success = false;
4941 u8 stat;
4942
4943 mutex_lock(&chg->otg_oc_lock);
4944 rc = smblib_read(chg, OTG_STATUS_REG, &stat);
4945 if (rc < 0)
4946 smblib_err(chg, "Couldn't read OTG status rc=%d\n", rc);
4947 else if (stat & BOOST_SOFTSTART_DONE_BIT)
4948 success = true;
4949
4950 smblib_otg_oc_exit(chg, success);
4951 mutex_unlock(&chg->otg_oc_lock);
4952}
4953
Ashay Jaiswal4d825782017-02-18 10:11:34 +05304954static void smblib_icl_change_work(struct work_struct *work)
4955{
4956 struct smb_charger *chg = container_of(work, struct smb_charger,
4957 icl_change_work.work);
4958 int rc, settled_ua;
4959
4960 rc = smblib_get_charge_param(chg, &chg->param.icl_stat, &settled_ua);
4961 if (rc < 0) {
4962 smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
4963 return;
4964 }
4965
4966 power_supply_changed(chg->usb_main_psy);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05304967
4968 smblib_dbg(chg, PR_INTERRUPT, "icl_settled=%d\n", settled_ua);
4969}
4970
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304971static void smblib_pl_enable_work(struct work_struct *work)
4972{
4973 struct smb_charger *chg = container_of(work, struct smb_charger,
4974 pl_enable_work.work);
4975
4976 smblib_dbg(chg, PR_PARALLEL, "timer expired, enabling parallel\n");
4977 vote(chg->pl_disable_votable, PL_DELAY_VOTER, false, 0);
4978 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
4979}
4980
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004981static void smblib_legacy_detection_work(struct work_struct *work)
4982{
4983 struct smb_charger *chg = container_of(work, struct smb_charger,
4984 legacy_detection_work);
4985 int rc;
4986 u8 stat;
4987 bool legacy, rp_high;
4988
4989 mutex_lock(&chg->lock);
4990 chg->typec_en_dis_active = 1;
4991 smblib_dbg(chg, PR_MISC, "running legacy unknown workaround\n");
4992 rc = smblib_masked_write(chg,
4993 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4994 TYPEC_DISABLE_CMD_BIT,
4995 TYPEC_DISABLE_CMD_BIT);
4996 if (rc < 0)
4997 smblib_err(chg, "Couldn't disable type-c rc=%d\n", rc);
4998
4999 /* wait for the adapter to turn off VBUS */
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07005000 msleep(1000);
5001
5002 smblib_dbg(chg, PR_MISC, "legacy workaround enabling typec\n");
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07005003
5004 rc = smblib_masked_write(chg,
5005 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
5006 TYPEC_DISABLE_CMD_BIT, 0);
5007 if (rc < 0)
5008 smblib_err(chg, "Couldn't enable type-c rc=%d\n", rc);
5009
5010 /* wait for type-c detection to complete */
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07005011 msleep(400);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07005012
5013 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat);
5014 if (rc < 0) {
5015 smblib_err(chg, "Couldn't read typec stat5 rc = %d\n", rc);
5016 goto unlock;
5017 }
5018
5019 chg->typec_legacy_valid = true;
5020 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
5021 legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT;
Nicholas Troaste1932e42017-04-12 12:38:18 -07005022 rp_high = chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH;
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07005023 smblib_dbg(chg, PR_MISC, "legacy workaround done legacy = %d rp_high = %d\n",
5024 legacy, rp_high);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07005025 if (!legacy || !rp_high)
5026 vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
5027 false, 0);
5028
5029unlock:
5030 chg->typec_en_dis_active = 0;
Nicholas Troast6439e172017-06-02 14:45:39 -07005031 smblib_usb_typec_change(chg);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07005032 mutex_unlock(&chg->lock);
5033}
5034
Harry Yangba874ce2016-08-19 14:17:01 -07005035static int smblib_create_votables(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07005036{
5037 int rc = 0;
5038
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05305039 chg->fcc_votable = find_votable("FCC");
Harry Yang0c35ff62017-04-06 00:02:30 -07005040 if (chg->fcc_votable == NULL) {
5041 rc = -EINVAL;
5042 smblib_err(chg, "Couldn't find FCC votable rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05305043 return rc;
5044 }
5045
5046 chg->fv_votable = find_votable("FV");
Harry Yang0c35ff62017-04-06 00:02:30 -07005047 if (chg->fv_votable == NULL) {
5048 rc = -EINVAL;
5049 smblib_err(chg, "Couldn't find FV votable rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05305050 return rc;
5051 }
5052
Ashay Jaiswalae1586d2017-03-22 23:18:51 +05305053 chg->usb_icl_votable = find_votable("USB_ICL");
5054 if (!chg->usb_icl_votable) {
Harry Yang0c35ff62017-04-06 00:02:30 -07005055 rc = -EINVAL;
5056 smblib_err(chg, "Couldn't find USB_ICL votable rc=%d\n", rc);
Ashay Jaiswalae1586d2017-03-22 23:18:51 +05305057 return rc;
5058 }
5059
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05305060 chg->pl_disable_votable = find_votable("PL_DISABLE");
Harry Yang0c35ff62017-04-06 00:02:30 -07005061 if (chg->pl_disable_votable == NULL) {
5062 rc = -EINVAL;
5063 smblib_err(chg, "Couldn't find votable PL_DISABLE rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05305064 return rc;
5065 }
Abhijeet Dharmapurikar38ef1422017-05-18 15:37:56 -07005066
5067 chg->pl_enable_votable_indirect = find_votable("PL_ENABLE_INDIRECT");
5068 if (chg->pl_enable_votable_indirect == NULL) {
5069 rc = -EINVAL;
5070 smblib_err(chg,
5071 "Couldn't find votable PL_ENABLE_INDIRECT rc=%d\n",
5072 rc);
5073 return rc;
5074 }
5075
Ashay Jaiswalc0361672017-03-21 12:24:16 +05305076 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05305077
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07005078 chg->dc_suspend_votable = create_votable("DC_SUSPEND", VOTE_SET_ANY,
5079 smblib_dc_suspend_vote_callback,
5080 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07005081 if (IS_ERR(chg->dc_suspend_votable)) {
5082 rc = PTR_ERR(chg->dc_suspend_votable);
5083 return rc;
5084 }
5085
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07005086 chg->dc_icl_votable = create_votable("DC_ICL", VOTE_MIN,
5087 smblib_dc_icl_vote_callback,
5088 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07005089 if (IS_ERR(chg->dc_icl_votable)) {
5090 rc = PTR_ERR(chg->dc_icl_votable);
5091 return rc;
5092 }
5093
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07005094 chg->pd_disallowed_votable_indirect
5095 = create_votable("PD_DISALLOWED_INDIRECT", VOTE_SET_ANY,
5096 smblib_pd_disallowed_votable_indirect_callback, chg);
5097 if (IS_ERR(chg->pd_disallowed_votable_indirect)) {
5098 rc = PTR_ERR(chg->pd_disallowed_votable_indirect);
5099 return rc;
5100 }
5101
5102 chg->pd_allowed_votable = create_votable("PD_ALLOWED",
5103 VOTE_SET_ANY, NULL, NULL);
Nicholas Troast34db5032016-03-28 12:26:44 -07005104 if (IS_ERR(chg->pd_allowed_votable)) {
5105 rc = PTR_ERR(chg->pd_allowed_votable);
5106 return rc;
5107 }
5108
Harry Yang223c6282016-06-14 15:48:36 -07005109 chg->awake_votable = create_votable("AWAKE", VOTE_SET_ANY,
5110 smblib_awake_vote_callback,
5111 chg);
5112 if (IS_ERR(chg->awake_votable)) {
5113 rc = PTR_ERR(chg->awake_votable);
5114 return rc;
5115 }
5116
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07005117 chg->chg_disable_votable = create_votable("CHG_DISABLE", VOTE_SET_ANY,
5118 smblib_chg_disable_vote_callback,
5119 chg);
5120 if (IS_ERR(chg->chg_disable_votable)) {
5121 rc = PTR_ERR(chg->chg_disable_votable);
5122 return rc;
5123 }
5124
Harry Yangaba1f5f2016-09-28 10:47:29 -07005125
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05305126 chg->hvdcp_disable_votable_indirect = create_votable(
5127 "HVDCP_DISABLE_INDIRECT",
5128 VOTE_SET_ANY,
5129 smblib_hvdcp_disable_indirect_vote_callback,
5130 chg);
5131 if (IS_ERR(chg->hvdcp_disable_votable_indirect)) {
5132 rc = PTR_ERR(chg->hvdcp_disable_votable_indirect);
5133 return rc;
5134 }
5135
5136 chg->hvdcp_enable_votable = create_votable("HVDCP_ENABLE",
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07005137 VOTE_SET_ANY,
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05305138 smblib_hvdcp_enable_vote_callback,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07005139 chg);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05305140 if (IS_ERR(chg->hvdcp_enable_votable)) {
5141 rc = PTR_ERR(chg->hvdcp_enable_votable);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07005142 return rc;
5143 }
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07005144
5145 chg->apsd_disable_votable = create_votable("APSD_DISABLE",
5146 VOTE_SET_ANY,
5147 smblib_apsd_disable_vote_callback,
5148 chg);
5149 if (IS_ERR(chg->apsd_disable_votable)) {
5150 rc = PTR_ERR(chg->apsd_disable_votable);
5151 return rc;
5152 }
5153
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05305154 chg->hvdcp_hw_inov_dis_votable = create_votable("HVDCP_HW_INOV_DIS",
5155 VOTE_SET_ANY,
5156 smblib_hvdcp_hw_inov_dis_vote_callback,
5157 chg);
5158 if (IS_ERR(chg->hvdcp_hw_inov_dis_votable)) {
5159 rc = PTR_ERR(chg->hvdcp_hw_inov_dis_votable);
5160 return rc;
5161 }
5162
Harry Yang4bf7d962017-03-13 16:51:43 -07005163 chg->usb_irq_enable_votable = create_votable("USB_IRQ_DISABLE",
5164 VOTE_SET_ANY,
5165 smblib_usb_irq_enable_vote_callback,
5166 chg);
5167 if (IS_ERR(chg->usb_irq_enable_votable)) {
5168 rc = PTR_ERR(chg->usb_irq_enable_votable);
5169 return rc;
5170 }
5171
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07005172 chg->typec_irq_disable_votable = create_votable("TYPEC_IRQ_DISABLE",
5173 VOTE_SET_ANY,
5174 smblib_typec_irq_disable_vote_callback,
5175 chg);
5176 if (IS_ERR(chg->typec_irq_disable_votable)) {
5177 rc = PTR_ERR(chg->typec_irq_disable_votable);
5178 return rc;
5179 }
5180
Tirupathi Reddy0c5d0a52017-09-27 16:31:07 +05305181 chg->disable_power_role_switch
5182 = create_votable("DISABLE_POWER_ROLE_SWITCH",
5183 VOTE_SET_ANY,
5184 smblib_disable_power_role_switch_callback,
5185 chg);
5186 if (IS_ERR(chg->disable_power_role_switch)) {
5187 rc = PTR_ERR(chg->disable_power_role_switch);
5188 return rc;
5189 }
5190
Nicholas Troast320839e2016-06-03 10:18:00 -07005191 return rc;
5192}
5193
Harry Yangba874ce2016-08-19 14:17:01 -07005194static void smblib_destroy_votables(struct smb_charger *chg)
5195{
Harry Yangba874ce2016-08-19 14:17:01 -07005196 if (chg->dc_suspend_votable)
5197 destroy_votable(chg->dc_suspend_votable);
Harry Yangba874ce2016-08-19 14:17:01 -07005198 if (chg->usb_icl_votable)
5199 destroy_votable(chg->usb_icl_votable);
5200 if (chg->dc_icl_votable)
5201 destroy_votable(chg->dc_icl_votable);
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07005202 if (chg->pd_disallowed_votable_indirect)
5203 destroy_votable(chg->pd_disallowed_votable_indirect);
Harry Yangba874ce2016-08-19 14:17:01 -07005204 if (chg->pd_allowed_votable)
5205 destroy_votable(chg->pd_allowed_votable);
5206 if (chg->awake_votable)
5207 destroy_votable(chg->awake_votable);
Harry Yangaba1f5f2016-09-28 10:47:29 -07005208 if (chg->chg_disable_votable)
5209 destroy_votable(chg->chg_disable_votable);
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07005210 if (chg->apsd_disable_votable)
5211 destroy_votable(chg->apsd_disable_votable);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05305212 if (chg->hvdcp_hw_inov_dis_votable)
5213 destroy_votable(chg->hvdcp_hw_inov_dis_votable);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07005214 if (chg->typec_irq_disable_votable)
5215 destroy_votable(chg->typec_irq_disable_votable);
Tirupathi Reddy0c5d0a52017-09-27 16:31:07 +05305216 if (chg->disable_power_role_switch)
5217 destroy_votable(chg->disable_power_role_switch);
Harry Yangba874ce2016-08-19 14:17:01 -07005218}
5219
5220static void smblib_iio_deinit(struct smb_charger *chg)
5221{
5222 if (!IS_ERR_OR_NULL(chg->iio.temp_chan))
5223 iio_channel_release(chg->iio.temp_chan);
5224 if (!IS_ERR_OR_NULL(chg->iio.temp_max_chan))
5225 iio_channel_release(chg->iio.temp_max_chan);
5226 if (!IS_ERR_OR_NULL(chg->iio.usbin_i_chan))
5227 iio_channel_release(chg->iio.usbin_i_chan);
5228 if (!IS_ERR_OR_NULL(chg->iio.usbin_v_chan))
5229 iio_channel_release(chg->iio.usbin_v_chan);
Nicholas Troast7dbcad22016-10-05 13:30:18 -07005230 if (!IS_ERR_OR_NULL(chg->iio.batt_i_chan))
5231 iio_channel_release(chg->iio.batt_i_chan);
Harry Yangba874ce2016-08-19 14:17:01 -07005232}
5233
Nicholas Troast320839e2016-06-03 10:18:00 -07005234int smblib_init(struct smb_charger *chg)
5235{
5236 int rc = 0;
5237
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07005238 mutex_init(&chg->lock);
Nicholas Troast320839e2016-06-03 10:18:00 -07005239 mutex_init(&chg->write_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08005240 mutex_init(&chg->otg_oc_lock);
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07005241 mutex_init(&chg->vconn_oc_lock);
Harry Yangfe913842016-08-10 12:27:28 -07005242 INIT_WORK(&chg->bms_update_work, bms_update_work);
Harry Yang166b15d2017-08-28 13:00:40 -07005243 INIT_WORK(&chg->pl_update_work, pl_update_work);
Harry Yang755a34b2016-11-01 01:18:51 -07005244 INIT_WORK(&chg->rdstd_cc2_detach_work, rdstd_cc2_detach_work);
Nicholas Troast320839e2016-06-03 10:18:00 -07005245 INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07005246 INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work);
Nicholas Troastb11015f2017-01-17 17:56:45 -08005247 INIT_WORK(&chg->otg_oc_work, smblib_otg_oc_work);
5248 INIT_WORK(&chg->vconn_oc_work, smblib_vconn_oc_work);
5249 INIT_DELAYED_WORK(&chg->otg_ss_done_work, smblib_otg_ss_done_work);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05305250 INIT_DELAYED_WORK(&chg->icl_change_work, smblib_icl_change_work);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05305251 INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07005252 INIT_WORK(&chg->legacy_detection_work, smblib_legacy_detection_work);
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05305253 INIT_DELAYED_WORK(&chg->uusb_otg_work, smblib_uusb_otg_work);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05305254 INIT_DELAYED_WORK(&chg->bb_removal_work, smblib_bb_removal_work);
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07005255 chg->fake_capacity = -EINVAL;
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07005256 chg->fake_input_current_limited = -EINVAL;
Harry Yang589dd422017-07-28 18:41:42 -07005257 chg->fake_batt_status = -EINVAL;
Nicholas Troast320839e2016-06-03 10:18:00 -07005258
5259 switch (chg->mode) {
5260 case PARALLEL_MASTER:
Harry Yang0c35ff62017-04-06 00:02:30 -07005261 rc = qcom_batt_init();
5262 if (rc < 0) {
5263 smblib_err(chg, "Couldn't init qcom_batt_init rc=%d\n",
5264 rc);
5265 return rc;
5266 }
5267
Fenglin Wudd8f4cb2017-10-17 11:09:46 +08005268 rc = qcom_step_chg_init(chg->dev, chg->step_chg_enabled,
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +05305269 chg->sw_jeita_enabled);
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05305270 if (rc < 0) {
5271 smblib_err(chg, "Couldn't init qcom_step_chg_init rc=%d\n",
5272 rc);
5273 return rc;
5274 }
5275
Nicholas Troast320839e2016-06-03 10:18:00 -07005276 rc = smblib_create_votables(chg);
5277 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07005278 smblib_err(chg, "Couldn't create votables rc=%d\n",
Nicholas Troast320839e2016-06-03 10:18:00 -07005279 rc);
Harry Yang58a9e7a2016-06-23 14:54:43 -07005280 return rc;
Nicholas Troast320839e2016-06-03 10:18:00 -07005281 }
Harry Yang58a9e7a2016-06-23 14:54:43 -07005282
Harry Yang5e1a5222016-07-26 15:16:04 -07005283 rc = smblib_register_notifier(chg);
5284 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07005285 smblib_err(chg,
Harry Yang5e1a5222016-07-26 15:16:04 -07005286 "Couldn't register notifier rc=%d\n", rc);
5287 return rc;
Harry Yang58a9e7a2016-06-23 14:54:43 -07005288 }
5289
Harry Yang995b7422016-08-29 16:06:50 -07005290 chg->bms_psy = power_supply_get_by_name("bms");
Ashay Jaiswal8afedfc2017-02-03 11:18:22 +05305291 chg->pl.psy = power_supply_get_by_name("parallel");
Harry Yang166b15d2017-08-28 13:00:40 -07005292 if (chg->pl.psy) {
5293 rc = smblib_stat_sw_override_cfg(chg, false);
5294 if (rc < 0) {
5295 smblib_err(chg,
5296 "Couldn't config stat sw rc=%d\n", rc);
5297 return rc;
5298 }
5299 }
Nicholas Troast320839e2016-06-03 10:18:00 -07005300 break;
5301 case PARALLEL_SLAVE:
5302 break;
5303 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07005304 smblib_err(chg, "Unsupported mode %d\n", chg->mode);
Nicholas Troast320839e2016-06-03 10:18:00 -07005305 return -EINVAL;
5306 }
5307
5308 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07005309}
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07005310
5311int smblib_deinit(struct smb_charger *chg)
5312{
Harry Yangba874ce2016-08-19 14:17:01 -07005313 switch (chg->mode) {
5314 case PARALLEL_MASTER:
Harry Yang0c35ff62017-04-06 00:02:30 -07005315 cancel_work_sync(&chg->bms_update_work);
Harry Yang166b15d2017-08-28 13:00:40 -07005316 cancel_work_sync(&chg->pl_update_work);
Harry Yang0c35ff62017-04-06 00:02:30 -07005317 cancel_work_sync(&chg->rdstd_cc2_detach_work);
5318 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
Harry Yang0c35ff62017-04-06 00:02:30 -07005319 cancel_delayed_work_sync(&chg->clear_hdc_work);
5320 cancel_work_sync(&chg->otg_oc_work);
5321 cancel_work_sync(&chg->vconn_oc_work);
5322 cancel_delayed_work_sync(&chg->otg_ss_done_work);
5323 cancel_delayed_work_sync(&chg->icl_change_work);
5324 cancel_delayed_work_sync(&chg->pl_enable_work);
5325 cancel_work_sync(&chg->legacy_detection_work);
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05305326 cancel_delayed_work_sync(&chg->uusb_otg_work);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05305327 cancel_delayed_work_sync(&chg->bb_removal_work);
Harry Yangba874ce2016-08-19 14:17:01 -07005328 power_supply_unreg_notifier(&chg->nb);
5329 smblib_destroy_votables(chg);
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05305330 qcom_step_chg_deinit();
Harry Yang0c35ff62017-04-06 00:02:30 -07005331 qcom_batt_deinit();
Harry Yangba874ce2016-08-19 14:17:01 -07005332 break;
5333 case PARALLEL_SLAVE:
5334 break;
5335 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07005336 smblib_err(chg, "Unsupported mode %d\n", chg->mode);
Harry Yangba874ce2016-08-19 14:17:01 -07005337 return -EINVAL;
5338 }
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07005339
Harry Yangba874ce2016-08-19 14:17:01 -07005340 smblib_iio_deinit(chg);
Harry Yang5e1a5222016-07-26 15:16:04 -07005341
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07005342 return 0;
5343}