blob: 86f6638ae950d8f7f15dc9d2803a7e7f6c45d379 [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
Umang Agrawalbed5d982018-04-17 20:16:01 +05301124 if (chg->wa_flags & TYPEC_PBS_WA_BIT) {
1125 if (power_role == UFP_EN_CMD_BIT) {
1126 /* disable PBS workaround when forcing sink mode */
1127 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0x0);
1128 if (rc < 0) {
1129 smblib_err(chg, "Couldn't write to TM_IO_DTEST4_SEL rc=%d\n",
1130 rc);
1131 }
1132 } else {
1133 /* restore it back to 0xA5 */
1134 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
1135 if (rc < 0) {
1136 smblib_err(chg, "Couldn't write to TM_IO_DTEST4_SEL rc=%d\n",
1137 rc);
1138 }
Tirupathi Reddy0c5d0a52017-09-27 16:31:07 +05301139 }
1140 }
1141
1142 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1143 TYPEC_POWER_ROLE_CMD_MASK, power_role);
1144 if (rc < 0) {
1145 smblib_err(chg, "Couldn't write 0x%02x to TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
1146 power_role, rc);
1147 return rc;
1148 }
1149
1150 return rc;
1151}
1152
Ashay Jaiswalae1586d2017-03-22 23:18:51 +05301153/*********************
1154 * VOTABLE CALLBACKS *
1155 *********************/
1156
1157static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data,
1158 int suspend, const char *client)
1159{
1160 struct smb_charger *chg = data;
1161
1162 /* resume input if suspend is invalid */
1163 if (suspend < 0)
1164 suspend = 0;
1165
1166 return smblib_set_dc_suspend(chg, (bool)suspend);
1167}
1168
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001169static int smblib_dc_icl_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -07001170 int icl_ua, const char *client)
Nicholas Troast34db5032016-03-28 12:26:44 -07001171{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001172 struct smb_charger *chg = data;
Nicholas Troast34db5032016-03-28 12:26:44 -07001173 int rc = 0;
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001174 bool suspend;
1175
1176 if (icl_ua < 0) {
1177 smblib_dbg(chg, PR_MISC, "No Voter hence suspending\n");
1178 icl_ua = 0;
1179 }
1180
Harry Yang379484a2017-08-29 10:26:14 -07001181 suspend = (icl_ua <= USBIN_25MA);
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001182 if (suspend)
1183 goto suspend;
Nicholas Troast34db5032016-03-28 12:26:44 -07001184
1185 rc = smblib_set_charge_param(chg, &chg->param.dc_icl, icl_ua);
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001186 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001187 smblib_err(chg, "Couldn't set DC input current limit rc=%d\n",
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001188 rc);
1189 return rc;
1190 }
1191
1192suspend:
1193 rc = vote(chg->dc_suspend_votable, USER_VOTER, suspend, 0);
1194 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001195 smblib_err(chg, "Couldn't vote to %s DC rc=%d\n",
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001196 suspend ? "suspend" : "resume", rc);
1197 return rc;
1198 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001199 return rc;
1200}
1201
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07001202static int smblib_pd_disallowed_votable_indirect_callback(
1203 struct votable *votable, void *data, int disallowed, const char *client)
1204{
1205 struct smb_charger *chg = data;
1206 int rc;
1207
1208 rc = vote(chg->pd_allowed_votable, PD_DISALLOWED_INDIRECT_VOTER,
1209 !disallowed, 0);
1210
1211 return rc;
1212}
1213
Harry Yang223c6282016-06-14 15:48:36 -07001214static int smblib_awake_vote_callback(struct votable *votable, void *data,
1215 int awake, const char *client)
1216{
1217 struct smb_charger *chg = data;
1218
1219 if (awake)
1220 pm_stay_awake(chg->dev);
1221 else
1222 pm_relax(chg->dev);
1223
1224 return 0;
1225}
1226
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07001227static int smblib_chg_disable_vote_callback(struct votable *votable, void *data,
1228 int chg_disable, const char *client)
1229{
1230 struct smb_charger *chg = data;
1231 int rc;
1232
1233 rc = smblib_masked_write(chg, CHARGING_ENABLE_CMD_REG,
1234 CHARGING_ENABLE_CMD_BIT,
1235 chg_disable ? 0 : CHARGING_ENABLE_CMD_BIT);
1236 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001237 smblib_err(chg, "Couldn't %s charging rc=%d\n",
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07001238 chg_disable ? "disable" : "enable", rc);
1239 return rc;
1240 }
1241
1242 return 0;
1243}
Harry Yangaba1f5f2016-09-28 10:47:29 -07001244
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301245static int smblib_hvdcp_enable_vote_callback(struct votable *votable,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001246 void *data,
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301247 int hvdcp_enable, const char *client)
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001248{
1249 struct smb_charger *chg = data;
1250 int rc;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301251 u8 val = HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_EN_BIT;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07001252 u8 stat;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301253
1254 /* vote to enable/disable HW autonomous INOV */
1255 vote(chg->hvdcp_hw_inov_dis_votable, client, !hvdcp_enable, 0);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001256
1257 /*
1258 * Disable the autonomous bit and auth bit for disabling hvdcp.
1259 * This ensures only qc 2.0 detection runs but no vbus
1260 * negotiation happens.
1261 */
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301262 if (!hvdcp_enable)
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001263 val = HVDCP_EN_BIT;
1264
1265 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301266 HVDCP_EN_BIT | HVDCP_AUTH_ALG_EN_CFG_BIT,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001267 val);
1268 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001269 smblib_err(chg, "Couldn't %s hvdcp rc=%d\n",
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301270 hvdcp_enable ? "enable" : "disable", rc);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001271 return rc;
1272 }
1273
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07001274 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
1275 if (rc < 0) {
1276 smblib_err(chg, "Couldn't read APSD status rc=%d\n", rc);
1277 return rc;
1278 }
1279
1280 /* re-run APSD if HVDCP was detected */
1281 if (stat & QC_CHARGER_BIT)
1282 smblib_rerun_apsd(chg);
1283
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001284 return 0;
1285}
1286
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301287static int smblib_hvdcp_disable_indirect_vote_callback(struct votable *votable,
1288 void *data, int hvdcp_disable, const char *client)
1289{
1290 struct smb_charger *chg = data;
1291
1292 vote(chg->hvdcp_enable_votable, HVDCP_INDIRECT_VOTER,
1293 !hvdcp_disable, 0);
1294
1295 return 0;
1296}
1297
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07001298static int smblib_apsd_disable_vote_callback(struct votable *votable,
1299 void *data,
1300 int apsd_disable, const char *client)
1301{
1302 struct smb_charger *chg = data;
1303 int rc;
1304
Nicholas Troastec4703c2017-01-30 14:52:33 -08001305 if (apsd_disable) {
Nicholas Troastec4703c2017-01-30 14:52:33 -08001306 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1307 AUTO_SRC_DETECT_BIT,
1308 0);
1309 if (rc < 0) {
1310 smblib_err(chg, "Couldn't disable APSD rc=%d\n", rc);
1311 return rc;
1312 }
1313 } else {
1314 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1315 AUTO_SRC_DETECT_BIT,
1316 AUTO_SRC_DETECT_BIT);
1317 if (rc < 0) {
1318 smblib_err(chg, "Couldn't enable APSD rc=%d\n", rc);
1319 return rc;
1320 }
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07001321 }
1322
1323 return 0;
1324}
Nicholas Troast8995a702016-12-05 10:22:22 -08001325
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301326static int smblib_hvdcp_hw_inov_dis_vote_callback(struct votable *votable,
1327 void *data, int disable, const char *client)
1328{
1329 struct smb_charger *chg = data;
1330 int rc;
1331
1332 if (disable) {
1333 /*
1334 * the pulse count register get zeroed when autonomous mode is
1335 * disabled. Track that in variables before disabling
1336 */
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +05301337 rc = smblib_get_hw_pulse_cnt(chg, &chg->pulse_cnt);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301338 if (rc < 0) {
1339 pr_err("failed to read QC_PULSE_COUNT_STATUS_REG rc=%d\n",
1340 rc);
1341 return rc;
1342 }
1343 }
1344
1345 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1346 HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT,
1347 disable ? 0 : HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT);
1348 if (rc < 0) {
1349 smblib_err(chg, "Couldn't %s hvdcp rc=%d\n",
1350 disable ? "disable" : "enable", rc);
1351 return rc;
1352 }
1353
1354 return rc;
1355}
1356
Harry Yang4bf7d962017-03-13 16:51:43 -07001357static int smblib_usb_irq_enable_vote_callback(struct votable *votable,
1358 void *data, int enable, const char *client)
1359{
1360 struct smb_charger *chg = data;
1361
1362 if (!chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq ||
1363 !chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq)
1364 return 0;
1365
1366 if (enable) {
1367 enable_irq(chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq);
1368 enable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
1369 } else {
1370 disable_irq(chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq);
1371 disable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
1372 }
1373
1374 return 0;
1375}
1376
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07001377static int smblib_typec_irq_disable_vote_callback(struct votable *votable,
1378 void *data, int disable, const char *client)
1379{
1380 struct smb_charger *chg = data;
1381
1382 if (!chg->irq_info[TYPE_C_CHANGE_IRQ].irq)
1383 return 0;
1384
1385 if (disable)
1386 disable_irq_nosync(chg->irq_info[TYPE_C_CHANGE_IRQ].irq);
1387 else
1388 enable_irq(chg->irq_info[TYPE_C_CHANGE_IRQ].irq);
1389
1390 return 0;
1391}
1392
Tirupathi Reddy0c5d0a52017-09-27 16:31:07 +05301393static int smblib_disable_power_role_switch_callback(struct votable *votable,
1394 void *data, int disable, const char *client)
1395{
1396 struct smb_charger *chg = data;
1397 union power_supply_propval pval;
1398 int rc = 0;
1399
1400 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) {
1401 rc = smblib_micro_usb_disable_power_role_switch(chg, disable);
1402 } else {
1403 pval.intval = disable ? POWER_SUPPLY_TYPEC_PR_SINK
1404 : POWER_SUPPLY_TYPEC_PR_DUAL;
1405 rc = __smblib_set_prop_typec_power_role(chg, &pval);
1406 }
1407
1408 if (rc)
1409 smblib_err(chg, "power_role_switch = %s failed, rc=%d\n",
1410 disable ? "disabled" : "enabled", rc);
1411 else
1412 smblib_dbg(chg, PR_MISC, "power_role_switch = %s\n",
1413 disable ? "disabled" : "enabled");
1414
1415 return rc;
1416}
1417
Nicholas Troast8995a702016-12-05 10:22:22 -08001418/*******************
1419 * VCONN REGULATOR *
1420 * *****************/
1421
Nicholas Troastb11015f2017-01-17 17:56:45 -08001422#define MAX_OTG_SS_TRIES 2
Nicholas Troast8995a702016-12-05 10:22:22 -08001423static int _smblib_vconn_regulator_enable(struct regulator_dev *rdev)
1424{
1425 struct smb_charger *chg = rdev_get_drvdata(rdev);
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001426 int rc = 0;
1427 u8 val;
Nicholas Troast8995a702016-12-05 10:22:22 -08001428
1429 /*
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001430 * When enabling VCONN using the command register the CC pin must be
1431 * selected. VCONN should be supplied to the inactive CC pin hence using
1432 * the opposite of the CC_ORIENTATION_BIT.
Nicholas Troast8995a702016-12-05 10:22:22 -08001433 */
Nicholas Troastb11015f2017-01-17 17:56:45 -08001434 smblib_dbg(chg, PR_OTG, "enabling VCONN\n");
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07001435 val = chg->typec_status[3] &
1436 CC_ORIENTATION_BIT ? 0 : VCONN_EN_ORIENTATION_BIT;
Nicholas Troast8995a702016-12-05 10:22:22 -08001437 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1438 VCONN_EN_VALUE_BIT | VCONN_EN_ORIENTATION_BIT,
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07001439 VCONN_EN_VALUE_BIT | val);
Nicholas Troast8995a702016-12-05 10:22:22 -08001440 if (rc < 0) {
1441 smblib_err(chg, "Couldn't enable vconn setting rc=%d\n", rc);
1442 return rc;
1443 }
1444
1445 return rc;
1446}
1447
1448int smblib_vconn_regulator_enable(struct regulator_dev *rdev)
1449{
1450 struct smb_charger *chg = rdev_get_drvdata(rdev);
1451 int rc = 0;
1452
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001453 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001454 if (chg->vconn_en)
1455 goto unlock;
1456
1457 rc = _smblib_vconn_regulator_enable(rdev);
1458 if (rc >= 0)
1459 chg->vconn_en = true;
1460
1461unlock:
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001462 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001463 return rc;
1464}
1465
1466static int _smblib_vconn_regulator_disable(struct regulator_dev *rdev)
1467{
1468 struct smb_charger *chg = rdev_get_drvdata(rdev);
1469 int rc = 0;
1470
Nicholas Troastb11015f2017-01-17 17:56:45 -08001471 smblib_dbg(chg, PR_OTG, "disabling VCONN\n");
Nicholas Troast8995a702016-12-05 10:22:22 -08001472 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1473 VCONN_EN_VALUE_BIT, 0);
1474 if (rc < 0)
1475 smblib_err(chg, "Couldn't disable vconn regulator rc=%d\n", rc);
1476
1477 return rc;
1478}
1479
1480int smblib_vconn_regulator_disable(struct regulator_dev *rdev)
1481{
1482 struct smb_charger *chg = rdev_get_drvdata(rdev);
1483 int rc = 0;
1484
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001485 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001486 if (!chg->vconn_en)
1487 goto unlock;
1488
1489 rc = _smblib_vconn_regulator_disable(rdev);
1490 if (rc >= 0)
1491 chg->vconn_en = false;
1492
1493unlock:
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001494 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001495 return rc;
1496}
1497
1498int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev)
1499{
1500 struct smb_charger *chg = rdev_get_drvdata(rdev);
1501 int ret;
1502
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001503 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001504 ret = chg->vconn_en;
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001505 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001506 return ret;
1507}
1508
Nicholas Troast34db5032016-03-28 12:26:44 -07001509/*****************
1510 * OTG REGULATOR *
1511 *****************/
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301512#define MAX_RETRY 15
1513#define MIN_DELAY_US 2000
1514#define MAX_DELAY_US 9000
Anirudh Ghayaladf20da2017-07-03 10:52:29 +05301515static int otg_current[] = {250000, 500000, 1000000, 1500000};
1516static int smblib_enable_otg_wa(struct smb_charger *chg)
1517{
1518 u8 stat;
1519 int rc, i, retry_count = 0, min_delay = MIN_DELAY_US;
1520
1521 for (i = 0; i < ARRAY_SIZE(otg_current); i++) {
1522 smblib_dbg(chg, PR_OTG, "enabling OTG with %duA\n",
1523 otg_current[i]);
1524 rc = smblib_set_charge_param(chg, &chg->param.otg_cl,
1525 otg_current[i]);
1526 if (rc < 0) {
1527 smblib_err(chg, "Couldn't set otg limit rc=%d\n", rc);
1528 return rc;
1529 }
1530
1531 rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT);
1532 if (rc < 0) {
1533 smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc);
1534 return rc;
1535 }
1536
1537 retry_count = 0;
1538 min_delay = MIN_DELAY_US;
1539 do {
1540 usleep_range(min_delay, min_delay + 100);
1541 rc = smblib_read(chg, OTG_STATUS_REG, &stat);
1542 if (rc < 0) {
1543 smblib_err(chg, "Couldn't read OTG status rc=%d\n",
1544 rc);
1545 goto out;
1546 }
1547
1548 if (stat & BOOST_SOFTSTART_DONE_BIT) {
1549 rc = smblib_set_charge_param(chg,
1550 &chg->param.otg_cl, chg->otg_cl_ua);
1551 if (rc < 0) {
1552 smblib_err(chg, "Couldn't set otg limit rc=%d\n",
1553 rc);
1554 goto out;
1555 }
1556 break;
1557 }
1558 /* increase the delay for following iterations */
1559 if (retry_count > 5)
1560 min_delay = MAX_DELAY_US;
1561
1562 } while (retry_count++ < MAX_RETRY);
1563
1564 if (retry_count >= MAX_RETRY) {
1565 smblib_dbg(chg, PR_OTG, "OTG enable failed with %duA\n",
1566 otg_current[i]);
1567 rc = smblib_write(chg, CMD_OTG_REG, 0);
1568 if (rc < 0) {
1569 smblib_err(chg, "disable OTG rc=%d\n", rc);
1570 goto out;
1571 }
1572 } else {
1573 smblib_dbg(chg, PR_OTG, "OTG enabled\n");
1574 return 0;
1575 }
1576 }
1577
1578 if (i == ARRAY_SIZE(otg_current)) {
1579 rc = -EINVAL;
1580 goto out;
1581 }
1582
1583 return 0;
1584out:
1585 smblib_write(chg, CMD_OTG_REG, 0);
1586 return rc;
1587}
1588
Nicholas Troast8995a702016-12-05 10:22:22 -08001589static int _smblib_vbus_regulator_enable(struct regulator_dev *rdev)
Nicholas Troast34db5032016-03-28 12:26:44 -07001590{
1591 struct smb_charger *chg = rdev_get_drvdata(rdev);
Anirudh Ghayaladf20da2017-07-03 10:52:29 +05301592 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001593
Nicholas Troastb11015f2017-01-17 17:56:45 -08001594 smblib_dbg(chg, PR_OTG, "halt 1 in 8 mode\n");
Harry Yang360bd532016-09-26 11:03:22 -07001595 rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
1596 ENG_BUCKBOOST_HALT1_8_MODE_BIT,
1597 ENG_BUCKBOOST_HALT1_8_MODE_BIT);
1598 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001599 smblib_err(chg, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n",
Harry Yang360bd532016-09-26 11:03:22 -07001600 rc);
1601 return rc;
1602 }
1603
Nicholas Troastb11015f2017-01-17 17:56:45 -08001604 smblib_dbg(chg, PR_OTG, "enabling OTG\n");
Harry Yang360bd532016-09-26 11:03:22 -07001605
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301606 if (chg->wa_flags & OTG_WA) {
Anirudh Ghayaladf20da2017-07-03 10:52:29 +05301607 rc = smblib_enable_otg_wa(chg);
1608 if (rc < 0)
1609 smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc);
1610 } else {
1611 rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT);
1612 if (rc < 0)
1613 smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc);
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301614 }
1615
Nicholas Troast34db5032016-03-28 12:26:44 -07001616 return rc;
1617}
1618
Nicholas Troast8995a702016-12-05 10:22:22 -08001619int smblib_vbus_regulator_enable(struct regulator_dev *rdev)
Nicholas Troast34db5032016-03-28 12:26:44 -07001620{
1621 struct smb_charger *chg = rdev_get_drvdata(rdev);
1622 int rc = 0;
1623
Nicholas Troastb11015f2017-01-17 17:56:45 -08001624 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001625 if (chg->otg_en)
1626 goto unlock;
1627
Harry Yanga2fb0e32017-03-22 22:45:25 -07001628 if (!chg->usb_icl_votable) {
1629 chg->usb_icl_votable = find_votable("USB_ICL");
1630
Harry Yang4e619b42017-12-06 10:13:21 -08001631 if (!chg->usb_icl_votable) {
1632 rc = -EINVAL;
1633 goto unlock;
1634 }
Harry Yanga2fb0e32017-03-22 22:45:25 -07001635 }
1636 vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, true, 0);
1637
Nicholas Troast8995a702016-12-05 10:22:22 -08001638 rc = _smblib_vbus_regulator_enable(rdev);
1639 if (rc >= 0)
1640 chg->otg_en = true;
Ashay Jaiswal3d22f4b2017-11-15 18:09:19 +05301641 else
1642 vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0);
Nicholas Troast8995a702016-12-05 10:22:22 -08001643
1644unlock:
Nicholas Troastb11015f2017-01-17 17:56:45 -08001645 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001646 return rc;
1647}
1648
1649static int _smblib_vbus_regulator_disable(struct regulator_dev *rdev)
1650{
1651 struct smb_charger *chg = rdev_get_drvdata(rdev);
1652 int rc;
Nicholas Troast8995a702016-12-05 10:22:22 -08001653
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301654 if (chg->wa_flags & OTG_WA) {
1655 /* set OTG current limit to minimum value */
1656 rc = smblib_set_charge_param(chg, &chg->param.otg_cl,
1657 chg->param.otg_cl.min_u);
1658 if (rc < 0) {
1659 smblib_err(chg,
1660 "Couldn't set otg current limit rc=%d\n", rc);
1661 return rc;
1662 }
1663 }
1664
Nicholas Troastb11015f2017-01-17 17:56:45 -08001665 smblib_dbg(chg, PR_OTG, "disabling OTG\n");
Harry Yang360bd532016-09-26 11:03:22 -07001666 rc = smblib_write(chg, CMD_OTG_REG, 0);
1667 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001668 smblib_err(chg, "Couldn't disable OTG regulator rc=%d\n", rc);
Harry Yang360bd532016-09-26 11:03:22 -07001669 return rc;
1670 }
1671
Nicholas Troastb11015f2017-01-17 17:56:45 -08001672 smblib_dbg(chg, PR_OTG, "start 1 in 8 mode\n");
Harry Yang360bd532016-09-26 11:03:22 -07001673 rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
1674 ENG_BUCKBOOST_HALT1_8_MODE_BIT, 0);
1675 if (rc < 0) {
Nicholas Troast8995a702016-12-05 10:22:22 -08001676 smblib_err(chg, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n", rc);
Harry Yang360bd532016-09-26 11:03:22 -07001677 return rc;
1678 }
1679
Nicholas Troast8995a702016-12-05 10:22:22 -08001680 return 0;
1681}
Nicholas Troast34db5032016-03-28 12:26:44 -07001682
Nicholas Troast8995a702016-12-05 10:22:22 -08001683int smblib_vbus_regulator_disable(struct regulator_dev *rdev)
1684{
1685 struct smb_charger *chg = rdev_get_drvdata(rdev);
1686 int rc = 0;
1687
Nicholas Troastb11015f2017-01-17 17:56:45 -08001688 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001689 if (!chg->otg_en)
1690 goto unlock;
1691
1692 rc = _smblib_vbus_regulator_disable(rdev);
1693 if (rc >= 0)
1694 chg->otg_en = false;
1695
Harry Yanga2fb0e32017-03-22 22:45:25 -07001696 if (chg->usb_icl_votable)
1697 vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0);
Nicholas Troast8995a702016-12-05 10:22:22 -08001698unlock:
Nicholas Troastb11015f2017-01-17 17:56:45 -08001699 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07001700 return rc;
1701}
1702
1703int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev)
1704{
1705 struct smb_charger *chg = rdev_get_drvdata(rdev);
Nicholas Troast8995a702016-12-05 10:22:22 -08001706 int ret;
Nicholas Troast34db5032016-03-28 12:26:44 -07001707
Nicholas Troastb11015f2017-01-17 17:56:45 -08001708 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001709 ret = chg->otg_en;
Nicholas Troastb11015f2017-01-17 17:56:45 -08001710 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001711 return ret;
Nicholas Troast34db5032016-03-28 12:26:44 -07001712}
1713
1714/********************
1715 * BATT PSY GETTERS *
1716 ********************/
1717
1718int smblib_get_prop_input_suspend(struct smb_charger *chg,
1719 union power_supply_propval *val)
1720{
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08001721 val->intval
1722 = (get_client_vote(chg->usb_icl_votable, USER_VOTER) == 0)
1723 && get_client_vote(chg->dc_suspend_votable, USER_VOTER);
Nicholas Troast34db5032016-03-28 12:26:44 -07001724 return 0;
1725}
1726
1727int smblib_get_prop_batt_present(struct smb_charger *chg,
1728 union power_supply_propval *val)
1729{
1730 int rc;
1731 u8 stat;
1732
1733 rc = smblib_read(chg, BATIF_BASE + INT_RT_STS_OFFSET, &stat);
1734 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001735 smblib_err(chg, "Couldn't read BATIF_INT_RT_STS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07001736 return rc;
1737 }
1738
1739 val->intval = !(stat & (BAT_THERM_OR_ID_MISSING_RT_STS_BIT
1740 | BAT_TERMINAL_MISSING_RT_STS_BIT));
1741
1742 return rc;
1743}
1744
1745int smblib_get_prop_batt_capacity(struct smb_charger *chg,
1746 union power_supply_propval *val)
1747{
Harry Yang5e1a5222016-07-26 15:16:04 -07001748 int rc = -EINVAL;
1749
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07001750 if (chg->fake_capacity >= 0) {
1751 val->intval = chg->fake_capacity;
1752 return 0;
1753 }
1754
Harry Yang5e1a5222016-07-26 15:16:04 -07001755 if (chg->bms_psy)
1756 rc = power_supply_get_property(chg->bms_psy,
1757 POWER_SUPPLY_PROP_CAPACITY, val);
1758 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001759}
1760
1761int smblib_get_prop_batt_status(struct smb_charger *chg,
1762 union power_supply_propval *val)
1763{
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001764 union power_supply_propval pval = {0, };
Abhijeet Dharmapurikard97b2bf2017-07-06 17:03:00 -07001765 bool usb_online, dc_online, qnovo_en;
1766 u8 stat, pt_en_cmd;
Nicholas Troast8cb77552016-09-23 11:50:18 -07001767 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001768
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001769 rc = smblib_get_prop_usb_online(chg, &pval);
1770 if (rc < 0) {
1771 smblib_err(chg, "Couldn't get usb online property rc=%d\n",
1772 rc);
1773 return rc;
1774 }
1775 usb_online = (bool)pval.intval;
1776
1777 rc = smblib_get_prop_dc_online(chg, &pval);
1778 if (rc < 0) {
1779 smblib_err(chg, "Couldn't get dc online property rc=%d\n",
1780 rc);
1781 return rc;
1782 }
1783 dc_online = (bool)pval.intval;
1784
Nicholas Troast34db5032016-03-28 12:26:44 -07001785 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1786 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001787 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001788 rc);
1789 return rc;
1790 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001791 stat = stat & BATTERY_CHARGER_STATUS_MASK;
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001792
1793 if (!usb_online && !dc_online) {
1794 switch (stat) {
1795 case TERMINATE_CHARGE:
1796 case INHIBIT_CHARGE:
1797 val->intval = POWER_SUPPLY_STATUS_FULL;
1798 break;
1799 default:
1800 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
1801 break;
1802 }
1803 return rc;
1804 }
1805
Nicholas Troast8cb77552016-09-23 11:50:18 -07001806 switch (stat) {
1807 case TRICKLE_CHARGE:
1808 case PRE_CHARGE:
1809 case FAST_CHARGE:
1810 case FULLON_CHARGE:
1811 case TAPER_CHARGE:
Nicholas Troast34db5032016-03-28 12:26:44 -07001812 val->intval = POWER_SUPPLY_STATUS_CHARGING;
Nicholas Troast8cb77552016-09-23 11:50:18 -07001813 break;
1814 case TERMINATE_CHARGE:
1815 case INHIBIT_CHARGE:
1816 val->intval = POWER_SUPPLY_STATUS_FULL;
1817 break;
1818 case DISABLE_CHARGE:
1819 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
1820 break;
1821 default:
1822 val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
1823 break;
1824 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001825
Harry Yang7ecc1a12017-04-06 12:24:56 -07001826 if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
1827 return 0;
1828
Harry Yang589dd422017-07-28 18:41:42 -07001829 if (!usb_online && dc_online
1830 && chg->fake_batt_status == POWER_SUPPLY_STATUS_FULL) {
1831 val->intval = POWER_SUPPLY_STATUS_FULL;
1832 return 0;
1833 }
1834
Harry Yangc3c28d12017-04-17 16:41:19 -07001835 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_7_REG, &stat);
Harry Yang7ecc1a12017-04-06 12:24:56 -07001836 if (rc < 0) {
1837 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
1838 rc);
1839 return rc;
Abhijeet Dharmapurikard97b2bf2017-07-06 17:03:00 -07001840 }
Harry Yang7ecc1a12017-04-06 12:24:56 -07001841
Harry Yangc3c28d12017-04-17 16:41:19 -07001842 stat &= ENABLE_TRICKLE_BIT | ENABLE_PRE_CHARGING_BIT |
1843 ENABLE_FAST_CHARGING_BIT | ENABLE_FULLON_MODE_BIT;
Abhijeet Dharmapurikard97b2bf2017-07-06 17:03:00 -07001844
1845 rc = smblib_read(chg, QNOVO_PT_ENABLE_CMD_REG, &pt_en_cmd);
1846 if (rc < 0) {
1847 smblib_err(chg, "Couldn't read QNOVO_PT_ENABLE_CMD_REG rc=%d\n",
1848 rc);
1849 return rc;
1850 }
1851
1852 qnovo_en = (bool)(pt_en_cmd & QNOVO_PT_ENABLE_CMD_BIT);
1853
1854 /* ignore stat7 when qnovo is enabled */
1855 if (!qnovo_en && !stat)
Harry Yang7ecc1a12017-04-06 12:24:56 -07001856 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
1857
Nicholas Troast8cb77552016-09-23 11:50:18 -07001858 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07001859}
1860
1861int smblib_get_prop_batt_charge_type(struct smb_charger *chg,
1862 union power_supply_propval *val)
1863{
1864 int rc;
1865 u8 stat;
1866
1867 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1868 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001869 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001870 rc);
1871 return rc;
1872 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001873
1874 switch (stat & BATTERY_CHARGER_STATUS_MASK) {
1875 case TRICKLE_CHARGE:
1876 case PRE_CHARGE:
1877 val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1878 break;
1879 case FAST_CHARGE:
1880 case FULLON_CHARGE:
1881 val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
1882 break;
1883 case TAPER_CHARGE:
1884 val->intval = POWER_SUPPLY_CHARGE_TYPE_TAPER;
1885 break;
1886 default:
1887 val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
1888 }
1889
1890 return rc;
1891}
1892
1893int smblib_get_prop_batt_health(struct smb_charger *chg,
1894 union power_supply_propval *val)
1895{
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001896 union power_supply_propval pval;
Nicholas Troast34db5032016-03-28 12:26:44 -07001897 int rc;
Abhijeet Dharmapurikar33d18462017-05-15 13:38:53 -07001898 int effective_fv_uv;
Nicholas Troast34db5032016-03-28 12:26:44 -07001899 u8 stat;
1900
1901 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat);
1902 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001903 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001904 rc);
1905 return rc;
1906 }
1907 smblib_dbg(chg, PR_REGISTER, "BATTERY_CHARGER_STATUS_2 = 0x%02x\n",
1908 stat);
1909
1910 if (stat & CHARGER_ERROR_STATUS_BAT_OV_BIT) {
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001911 rc = smblib_get_prop_batt_voltage_now(chg, &pval);
1912 if (!rc) {
1913 /*
1914 * If Vbatt is within 40mV above Vfloat, then don't
1915 * treat it as overvoltage.
1916 */
Abhijeet Dharmapurikar33d18462017-05-15 13:38:53 -07001917 effective_fv_uv = get_effective_result(chg->fv_votable);
1918 if (pval.intval >= effective_fv_uv + 40000) {
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001919 val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
Abhijeet Dharmapurikar33d18462017-05-15 13:38:53 -07001920 smblib_err(chg, "battery over-voltage vbat_fg = %duV, fv = %duV\n",
1921 pval.intval, effective_fv_uv);
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001922 goto done;
1923 }
1924 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001925 }
1926
Harry Yang668fc5e2016-07-12 16:51:47 -07001927 if (stat & BAT_TEMP_STATUS_TOO_COLD_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001928 val->intval = POWER_SUPPLY_HEALTH_COLD;
Harry Yang668fc5e2016-07-12 16:51:47 -07001929 else if (stat & BAT_TEMP_STATUS_TOO_HOT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001930 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
Harry Yang668fc5e2016-07-12 16:51:47 -07001931 else if (stat & BAT_TEMP_STATUS_COLD_SOFT_LIMIT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001932 val->intval = POWER_SUPPLY_HEALTH_COOL;
Harry Yang668fc5e2016-07-12 16:51:47 -07001933 else if (stat & BAT_TEMP_STATUS_HOT_SOFT_LIMIT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001934 val->intval = POWER_SUPPLY_HEALTH_WARM;
Harry Yang668fc5e2016-07-12 16:51:47 -07001935 else
Nicholas Troast34db5032016-03-28 12:26:44 -07001936 val->intval = POWER_SUPPLY_HEALTH_GOOD;
Nicholas Troast34db5032016-03-28 12:26:44 -07001937
1938done:
1939 return rc;
1940}
1941
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001942int smblib_get_prop_system_temp_level(struct smb_charger *chg,
1943 union power_supply_propval *val)
1944{
1945 val->intval = chg->system_temp_level;
1946 return 0;
1947}
1948
Abhijeet Dharmapurikaracf32002017-05-11 11:54:17 -07001949int smblib_get_prop_system_temp_level_max(struct smb_charger *chg,
1950 union power_supply_propval *val)
1951{
1952 val->intval = chg->thermal_levels;
1953 return 0;
1954}
1955
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001956int smblib_get_prop_input_current_limited(struct smb_charger *chg,
1957 union power_supply_propval *val)
1958{
1959 u8 stat;
1960 int rc;
1961
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07001962 if (chg->fake_input_current_limited >= 0) {
1963 val->intval = chg->fake_input_current_limited;
1964 return 0;
1965 }
1966
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001967 rc = smblib_read(chg, AICL_STATUS_REG, &stat);
1968 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001969 smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n", rc);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001970 return rc;
1971 }
1972 val->intval = (stat & SOFT_ILIMIT_BIT) || chg->is_hdc;
1973 return 0;
1974}
1975
Nicholas Troast66b21d72016-09-20 15:33:20 -07001976int smblib_get_prop_batt_voltage_now(struct smb_charger *chg,
1977 union power_supply_propval *val)
1978{
1979 int rc;
1980
1981 if (!chg->bms_psy)
1982 return -EINVAL;
1983
1984 rc = power_supply_get_property(chg->bms_psy,
1985 POWER_SUPPLY_PROP_VOLTAGE_NOW, val);
1986 return rc;
1987}
1988
1989int smblib_get_prop_batt_current_now(struct smb_charger *chg,
1990 union power_supply_propval *val)
1991{
1992 int rc;
1993
1994 if (!chg->bms_psy)
1995 return -EINVAL;
1996
1997 rc = power_supply_get_property(chg->bms_psy,
1998 POWER_SUPPLY_PROP_CURRENT_NOW, val);
1999 return rc;
2000}
2001
2002int smblib_get_prop_batt_temp(struct smb_charger *chg,
2003 union power_supply_propval *val)
2004{
2005 int rc;
2006
2007 if (!chg->bms_psy)
2008 return -EINVAL;
2009
2010 rc = power_supply_get_property(chg->bms_psy,
2011 POWER_SUPPLY_PROP_TEMP, val);
2012 return rc;
2013}
2014
Subbaraman Narayanamurthyb491d022016-10-10 20:22:48 -07002015int smblib_get_prop_batt_charge_done(struct smb_charger *chg,
2016 union power_supply_propval *val)
2017{
2018 int rc;
2019 u8 stat;
2020
2021 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
2022 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002023 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Subbaraman Narayanamurthyb491d022016-10-10 20:22:48 -07002024 rc);
2025 return rc;
2026 }
2027
2028 stat = stat & BATTERY_CHARGER_STATUS_MASK;
2029 val->intval = (stat == TERMINATE_CHARGE);
2030 return 0;
2031}
2032
Harry Yang40192cb2017-02-25 23:25:17 -08002033int smblib_get_prop_charge_qnovo_enable(struct smb_charger *chg,
2034 union power_supply_propval *val)
2035{
2036 int rc;
2037 u8 stat;
2038
2039 rc = smblib_read(chg, QNOVO_PT_ENABLE_CMD_REG, &stat);
2040 if (rc < 0) {
2041 smblib_err(chg, "Couldn't read QNOVO_PT_ENABLE_CMD rc=%d\n",
2042 rc);
2043 return rc;
2044 }
2045
2046 val->intval = (bool)(stat & QNOVO_PT_ENABLE_CMD_BIT);
2047 return 0;
2048}
2049
Nicholas Troast4fe68d02017-07-26 14:17:34 -07002050int smblib_get_prop_batt_charge_counter(struct smb_charger *chg,
2051 union power_supply_propval *val)
2052{
2053 int rc;
2054
2055 if (!chg->bms_psy)
2056 return -EINVAL;
2057
2058 rc = power_supply_get_property(chg->bms_psy,
2059 POWER_SUPPLY_PROP_CHARGE_COUNTER, val);
2060 return rc;
2061}
2062
Nicholas Troast34db5032016-03-28 12:26:44 -07002063/***********************
2064 * BATTERY PSY SETTERS *
2065 ***********************/
2066
2067int smblib_set_prop_input_suspend(struct smb_charger *chg,
2068 const union power_supply_propval *val)
2069{
2070 int rc;
2071
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08002072 /* vote 0mA when suspended */
2073 rc = vote(chg->usb_icl_votable, USER_VOTER, (bool)val->intval, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07002074 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002075 smblib_err(chg, "Couldn't vote to %s USB rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002076 (bool)val->intval ? "suspend" : "resume", rc);
2077 return rc;
2078 }
2079
2080 rc = vote(chg->dc_suspend_votable, USER_VOTER, (bool)val->intval, 0);
2081 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002082 smblib_err(chg, "Couldn't vote to %s DC rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002083 (bool)val->intval ? "suspend" : "resume", rc);
2084 return rc;
2085 }
2086
Nicholas Troast61ff40f2016-07-08 10:59:22 -07002087 power_supply_changed(chg->batt_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07002088 return rc;
2089}
2090
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07002091int smblib_set_prop_batt_capacity(struct smb_charger *chg,
2092 const union power_supply_propval *val)
2093{
2094 chg->fake_capacity = val->intval;
2095
2096 power_supply_changed(chg->batt_psy);
2097
2098 return 0;
2099}
2100
Harry Yang589dd422017-07-28 18:41:42 -07002101int smblib_set_prop_batt_status(struct smb_charger *chg,
2102 const union power_supply_propval *val)
2103{
2104 /* Faking battery full */
2105 if (val->intval == POWER_SUPPLY_STATUS_FULL)
2106 chg->fake_batt_status = val->intval;
2107 else
2108 chg->fake_batt_status = -EINVAL;
2109
2110 power_supply_changed(chg->batt_psy);
2111
2112 return 0;
2113}
2114
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07002115int smblib_set_prop_system_temp_level(struct smb_charger *chg,
2116 const union power_supply_propval *val)
2117{
2118 if (val->intval < 0)
2119 return -EINVAL;
2120
2121 if (chg->thermal_levels <= 0)
2122 return -EINVAL;
2123
2124 if (val->intval > chg->thermal_levels)
2125 return -EINVAL;
2126
2127 chg->system_temp_level = val->intval;
Ashay Jaiswal147a6c32017-03-28 17:19:47 +05302128
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07002129 if (chg->system_temp_level == chg->thermal_levels)
Harry Yangaba1f5f2016-09-28 10:47:29 -07002130 return vote(chg->chg_disable_votable,
2131 THERMAL_DAEMON_VOTER, true, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07002132
Harry Yangaba1f5f2016-09-28 10:47:29 -07002133 vote(chg->chg_disable_votable, THERMAL_DAEMON_VOTER, false, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07002134 if (chg->system_temp_level == 0)
Harry Yangaba1f5f2016-09-28 10:47:29 -07002135 return vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, false, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07002136
Harry Yangaba1f5f2016-09-28 10:47:29 -07002137 vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, true,
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07002138 chg->thermal_mitigation[chg->system_temp_level]);
2139 return 0;
2140}
2141
Harry Yang40192cb2017-02-25 23:25:17 -08002142int smblib_set_prop_charge_qnovo_enable(struct smb_charger *chg,
2143 const union power_supply_propval *val)
2144{
2145 int rc = 0;
2146
2147 rc = smblib_masked_write(chg, QNOVO_PT_ENABLE_CMD_REG,
2148 QNOVO_PT_ENABLE_CMD_BIT,
2149 val->intval ? QNOVO_PT_ENABLE_CMD_BIT : 0);
2150 if (rc < 0) {
2151 dev_err(chg->dev, "Couldn't enable qnovo rc=%d\n", rc);
2152 return rc;
2153 }
2154
2155 return rc;
2156}
2157
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07002158int smblib_set_prop_input_current_limited(struct smb_charger *chg,
2159 const union power_supply_propval *val)
2160{
2161 chg->fake_input_current_limited = val->intval;
2162 return 0;
2163}
2164
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302165int smblib_rerun_aicl(struct smb_charger *chg)
2166{
Nicholas Troast20ae1912017-02-15 10:15:32 -08002167 int rc, settled_icl_ua;
2168 u8 stat;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302169
Nicholas Troast20ae1912017-02-15 10:15:32 -08002170 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
2171 if (rc < 0) {
2172 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
2173 rc);
2174 return rc;
2175 }
2176
2177 /* USB is suspended so skip re-running AICL */
2178 if (stat & USBIN_SUSPEND_STS_BIT)
2179 return rc;
2180
2181 smblib_dbg(chg, PR_MISC, "re-running AICL\n");
Ashay Jaiswal59a14122017-05-16 13:38:52 +05302182 rc = smblib_get_charge_param(chg, &chg->param.icl_stat,
2183 &settled_icl_ua);
2184 if (rc < 0) {
2185 smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
2186 return rc;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302187 }
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302188
Ashay Jaiswal59a14122017-05-16 13:38:52 +05302189 vote(chg->usb_icl_votable, AICL_RERUN_VOTER, true,
2190 max(settled_icl_ua - chg->param.usb_icl.step_u,
2191 chg->param.usb_icl.step_u));
2192 vote(chg->usb_icl_votable, AICL_RERUN_VOTER, false, 0);
2193
Nicholas Troast20ae1912017-02-15 10:15:32 -08002194 return 0;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302195}
2196
2197static int smblib_dp_pulse(struct smb_charger *chg)
2198{
2199 int rc;
2200
2201 /* QC 3.0 increment */
2202 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, SINGLE_INCREMENT_BIT,
2203 SINGLE_INCREMENT_BIT);
2204 if (rc < 0)
2205 smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
2206 rc);
2207
2208 return rc;
2209}
2210
2211static int smblib_dm_pulse(struct smb_charger *chg)
2212{
2213 int rc;
2214
2215 /* QC 3.0 decrement */
2216 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, SINGLE_DECREMENT_BIT,
2217 SINGLE_DECREMENT_BIT);
2218 if (rc < 0)
2219 smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
2220 rc);
2221
2222 return rc;
2223}
2224
Ashay Jaiswalcf243372017-10-31 14:33:27 +05302225static int smblib_force_vbus_voltage(struct smb_charger *chg, u8 val)
2226{
2227 int rc;
2228
2229 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, val, val);
2230 if (rc < 0)
2231 smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
2232 rc);
2233
2234 return rc;
2235}
2236
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302237int smblib_dp_dm(struct smb_charger *chg, int val)
2238{
2239 int target_icl_ua, rc = 0;
Ashay Jaiswalae23a042017-05-18 15:28:31 +05302240 union power_supply_propval pval;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302241
2242 switch (val) {
2243 case POWER_SUPPLY_DP_DM_DP_PULSE:
2244 rc = smblib_dp_pulse(chg);
2245 if (!rc)
2246 chg->pulse_cnt++;
2247 smblib_dbg(chg, PR_PARALLEL, "DP_DM_DP_PULSE rc=%d cnt=%d\n",
2248 rc, chg->pulse_cnt);
2249 break;
2250 case POWER_SUPPLY_DP_DM_DM_PULSE:
2251 rc = smblib_dm_pulse(chg);
2252 if (!rc && chg->pulse_cnt)
2253 chg->pulse_cnt--;
2254 smblib_dbg(chg, PR_PARALLEL, "DP_DM_DM_PULSE rc=%d cnt=%d\n",
2255 rc, chg->pulse_cnt);
2256 break;
2257 case POWER_SUPPLY_DP_DM_ICL_DOWN:
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302258 target_icl_ua = get_effective_result(chg->usb_icl_votable);
Ashay Jaiswalae23a042017-05-18 15:28:31 +05302259 if (target_icl_ua < 0) {
2260 /* no client vote, get the ICL from charger */
2261 rc = power_supply_get_property(chg->usb_psy,
2262 POWER_SUPPLY_PROP_HW_CURRENT_MAX,
2263 &pval);
2264 if (rc < 0) {
2265 smblib_err(chg,
2266 "Couldn't get max current rc=%d\n",
2267 rc);
2268 return rc;
2269 }
2270 target_icl_ua = pval.intval;
2271 }
2272
2273 /*
2274 * Check if any other voter voted on USB_ICL in case of
2275 * voter other than SW_QC3_VOTER reset and restart reduction
2276 * again.
2277 */
2278 if (target_icl_ua != get_client_vote(chg->usb_icl_votable,
2279 SW_QC3_VOTER))
2280 chg->usb_icl_delta_ua = 0;
2281
2282 chg->usb_icl_delta_ua += 100000;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302283 vote(chg->usb_icl_votable, SW_QC3_VOTER, true,
Ashay Jaiswalae23a042017-05-18 15:28:31 +05302284 target_icl_ua - 100000);
2285 smblib_dbg(chg, PR_PARALLEL, "ICL DOWN ICL=%d reduction=%d\n",
2286 target_icl_ua, chg->usb_icl_delta_ua);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302287 break;
Ashay Jaiswalcf243372017-10-31 14:33:27 +05302288 case POWER_SUPPLY_DP_DM_FORCE_5V:
2289 rc = smblib_force_vbus_voltage(chg, FORCE_5V_BIT);
2290 if (rc < 0)
2291 pr_err("Failed to force 5V\n");
2292 break;
2293 case POWER_SUPPLY_DP_DM_FORCE_9V:
Ashay Jaiswal1c360c82018-03-15 23:24:42 +05302294 /* Force 1A ICL before requesting higher voltage */
2295 vote(chg->usb_icl_votable, HVDCP2_ICL_VOTER, true, 1000000);
Ashay Jaiswalcf243372017-10-31 14:33:27 +05302296 rc = smblib_force_vbus_voltage(chg, FORCE_9V_BIT);
2297 if (rc < 0)
2298 pr_err("Failed to force 9V\n");
2299 break;
2300 case POWER_SUPPLY_DP_DM_FORCE_12V:
Ashay Jaiswal1c360c82018-03-15 23:24:42 +05302301 /* Force 1A ICL before requesting higher voltage */
2302 vote(chg->usb_icl_votable, HVDCP2_ICL_VOTER, true, 1000000);
Ashay Jaiswalcf243372017-10-31 14:33:27 +05302303 rc = smblib_force_vbus_voltage(chg, FORCE_12V_BIT);
2304 if (rc < 0)
2305 pr_err("Failed to force 12V\n");
2306 break;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302307 case POWER_SUPPLY_DP_DM_ICL_UP:
2308 default:
2309 break;
2310 }
2311
2312 return rc;
2313}
2314
Abhijeet Dharmapurikar3a580042017-07-24 09:43:00 -07002315int smblib_disable_hw_jeita(struct smb_charger *chg, bool disable)
2316{
2317 int rc;
2318 u8 mask;
2319
2320 /*
2321 * Disable h/w base JEITA compensation if s/w JEITA is enabled
2322 */
2323 mask = JEITA_EN_COLD_SL_FCV_BIT
2324 | JEITA_EN_HOT_SL_FCV_BIT
2325 | JEITA_EN_HOT_SL_CCC_BIT
2326 | JEITA_EN_COLD_SL_CCC_BIT,
2327 rc = smblib_masked_write(chg, JEITA_EN_CFG_REG, mask,
2328 disable ? 0 : mask);
2329 if (rc < 0) {
2330 dev_err(chg->dev,
2331 "Couldn't configure s/w jeita rc=%d\n",
2332 rc);
2333 return rc;
2334 }
2335 return 0;
2336}
2337
Nicholas Troast34db5032016-03-28 12:26:44 -07002338/*******************
Harry Yangf3023592016-07-20 14:56:41 -07002339 * DC PSY GETTERS *
2340 *******************/
2341
2342int smblib_get_prop_dc_present(struct smb_charger *chg,
2343 union power_supply_propval *val)
2344{
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002345 int rc;
Harry Yangf3023592016-07-20 14:56:41 -07002346 u8 stat;
2347
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002348 rc = smblib_read(chg, DCIN_BASE + INT_RT_STS_OFFSET, &stat);
Harry Yangf3023592016-07-20 14:56:41 -07002349 if (rc < 0) {
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002350 smblib_err(chg, "Couldn't read DCIN_RT_STS rc=%d\n", rc);
Harry Yangf3023592016-07-20 14:56:41 -07002351 return rc;
2352 }
Harry Yangf3023592016-07-20 14:56:41 -07002353
2354 val->intval = (bool)(stat & DCIN_PLUGIN_RT_STS_BIT);
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002355 return 0;
Harry Yangf3023592016-07-20 14:56:41 -07002356}
2357
2358int smblib_get_prop_dc_online(struct smb_charger *chg,
2359 union power_supply_propval *val)
2360{
2361 int rc = 0;
2362 u8 stat;
2363
2364 if (get_client_vote(chg->dc_suspend_votable, USER_VOTER)) {
2365 val->intval = false;
2366 return rc;
2367 }
2368
2369 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
2370 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002371 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
Harry Yangf3023592016-07-20 14:56:41 -07002372 rc);
2373 return rc;
2374 }
2375 smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
2376 stat);
2377
2378 val->intval = (stat & USE_DCIN_BIT) &&
Vic Wei7ade2842016-12-14 18:47:49 -08002379 (stat & VALID_INPUT_POWER_SOURCE_STS_BIT);
Harry Yangf3023592016-07-20 14:56:41 -07002380
2381 return rc;
2382}
2383
2384int smblib_get_prop_dc_current_max(struct smb_charger *chg,
2385 union power_supply_propval *val)
2386{
2387 val->intval = get_effective_result_locked(chg->dc_icl_votable);
2388 return 0;
2389}
2390
2391/*******************
Harry Yangd89ff1f2016-12-05 14:59:11 -08002392 * DC PSY SETTERS *
Harry Yangf3023592016-07-20 14:56:41 -07002393 * *****************/
2394
2395int smblib_set_prop_dc_current_max(struct smb_charger *chg,
2396 const union power_supply_propval *val)
2397{
2398 int rc;
2399
2400 rc = vote(chg->dc_icl_votable, USER_VOTER, true, val->intval);
2401 return rc;
2402}
2403
2404/*******************
Nicholas Troast34db5032016-03-28 12:26:44 -07002405 * USB PSY GETTERS *
2406 *******************/
2407
2408int smblib_get_prop_usb_present(struct smb_charger *chg,
2409 union power_supply_propval *val)
2410{
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002411 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07002412 u8 stat;
2413
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002414 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
Nicholas Troast34db5032016-03-28 12:26:44 -07002415 if (rc < 0) {
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002416 smblib_err(chg, "Couldn't read USBIN_RT_STS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07002417 return rc;
2418 }
Nicholas Troast34db5032016-03-28 12:26:44 -07002419
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002420 val->intval = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
2421 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002422}
2423
2424int smblib_get_prop_usb_online(struct smb_charger *chg,
2425 union power_supply_propval *val)
2426{
2427 int rc = 0;
2428 u8 stat;
2429
Abhijeet Dharmapurikar84923af2017-03-23 14:07:07 -07002430 if (get_client_vote_locked(chg->usb_icl_votable, USER_VOTER) == 0) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002431 val->intval = false;
2432 return rc;
2433 }
2434
2435 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
2436 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002437 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002438 rc);
2439 return rc;
2440 }
2441 smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
2442 stat);
2443
2444 val->intval = (stat & USE_USBIN_BIT) &&
Vic Wei7ade2842016-12-14 18:47:49 -08002445 (stat & VALID_INPUT_POWER_SOURCE_STS_BIT);
Nicholas Troast34db5032016-03-28 12:26:44 -07002446 return rc;
2447}
2448
Nicholas Troast7f55c922017-07-25 13:18:03 -07002449int smblib_get_prop_usb_voltage_max(struct smb_charger *chg,
2450 union power_supply_propval *val)
2451{
2452 switch (chg->real_charger_type) {
2453 case POWER_SUPPLY_TYPE_USB_HVDCP:
Ashay Jaiswal3c82d282017-11-28 22:07:36 +05302454 case POWER_SUPPLY_TYPE_USB_HVDCP_3:
Nicholas Troast7f55c922017-07-25 13:18:03 -07002455 case POWER_SUPPLY_TYPE_USB_PD:
2456 if (chg->smb_version == PM660_SUBTYPE)
2457 val->intval = MICRO_9V;
2458 else
2459 val->intval = MICRO_12V;
2460 break;
2461 default:
2462 val->intval = MICRO_5V;
2463 break;
2464 }
2465
2466 return 0;
2467}
2468
Nicholas Troast34db5032016-03-28 12:26:44 -07002469int smblib_get_prop_usb_voltage_now(struct smb_charger *chg,
2470 union power_supply_propval *val)
2471{
Harry Yangba874ce2016-08-19 14:17:01 -07002472 if (!chg->iio.usbin_v_chan ||
2473 PTR_ERR(chg->iio.usbin_v_chan) == -EPROBE_DEFER)
2474 chg->iio.usbin_v_chan = iio_channel_get(chg->dev, "usbin_v");
2475
2476 if (IS_ERR(chg->iio.usbin_v_chan))
2477 return PTR_ERR(chg->iio.usbin_v_chan);
2478
2479 return iio_read_channel_processed(chg->iio.usbin_v_chan, &val->intval);
Nicholas Troast34db5032016-03-28 12:26:44 -07002480}
2481
Harry Yangba874ce2016-08-19 14:17:01 -07002482int smblib_get_prop_usb_current_now(struct smb_charger *chg,
2483 union power_supply_propval *val)
2484{
2485 int rc = 0;
2486
2487 rc = smblib_get_prop_usb_present(chg, val);
2488 if (rc < 0 || !val->intval)
2489 return rc;
2490
2491 if (!chg->iio.usbin_i_chan ||
2492 PTR_ERR(chg->iio.usbin_i_chan) == -EPROBE_DEFER)
2493 chg->iio.usbin_i_chan = iio_channel_get(chg->dev, "usbin_i");
2494
2495 if (IS_ERR(chg->iio.usbin_i_chan))
2496 return PTR_ERR(chg->iio.usbin_i_chan);
2497
2498 return iio_read_channel_processed(chg->iio.usbin_i_chan, &val->intval);
2499}
2500
2501int smblib_get_prop_charger_temp(struct smb_charger *chg,
2502 union power_supply_propval *val)
2503{
2504 int rc;
2505
2506 if (!chg->iio.temp_chan ||
2507 PTR_ERR(chg->iio.temp_chan) == -EPROBE_DEFER)
2508 chg->iio.temp_chan = iio_channel_get(chg->dev, "charger_temp");
2509
2510 if (IS_ERR(chg->iio.temp_chan))
2511 return PTR_ERR(chg->iio.temp_chan);
2512
2513 rc = iio_read_channel_processed(chg->iio.temp_chan, &val->intval);
2514 val->intval /= 100;
2515 return rc;
2516}
2517
2518int smblib_get_prop_charger_temp_max(struct smb_charger *chg,
2519 union power_supply_propval *val)
2520{
2521 int rc;
2522
2523 if (!chg->iio.temp_max_chan ||
2524 PTR_ERR(chg->iio.temp_max_chan) == -EPROBE_DEFER)
2525 chg->iio.temp_max_chan = iio_channel_get(chg->dev,
2526 "charger_temp_max");
2527 if (IS_ERR(chg->iio.temp_max_chan))
2528 return PTR_ERR(chg->iio.temp_max_chan);
2529
2530 rc = iio_read_channel_processed(chg->iio.temp_max_chan, &val->intval);
2531 val->intval /= 100;
2532 return rc;
2533}
2534
Nicholas Troast34db5032016-03-28 12:26:44 -07002535int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
2536 union power_supply_propval *val)
2537{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002538 if (chg->typec_status[3] & CC_ATTACHED_BIT)
2539 val->intval =
2540 (bool)(chg->typec_status[3] & CC_ORIENTATION_BIT) + 1;
Nicholas Troast34db5032016-03-28 12:26:44 -07002541 else
2542 val->intval = 0;
2543
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002544 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002545}
2546
2547static const char * const smblib_typec_mode_name[] = {
2548 [POWER_SUPPLY_TYPEC_NONE] = "NONE",
2549 [POWER_SUPPLY_TYPEC_SOURCE_DEFAULT] = "SOURCE_DEFAULT",
2550 [POWER_SUPPLY_TYPEC_SOURCE_MEDIUM] = "SOURCE_MEDIUM",
2551 [POWER_SUPPLY_TYPEC_SOURCE_HIGH] = "SOURCE_HIGH",
2552 [POWER_SUPPLY_TYPEC_NON_COMPLIANT] = "NON_COMPLIANT",
2553 [POWER_SUPPLY_TYPEC_SINK] = "SINK",
2554 [POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE] = "SINK_POWERED_CABLE",
2555 [POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY] = "SINK_DEBUG_ACCESSORY",
2556 [POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER] = "SINK_AUDIO_ADAPTER",
2557 [POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY] = "POWERED_CABLE_ONLY",
2558};
2559
2560static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
2561{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002562 switch (chg->typec_status[0]) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002563 case UFP_TYPEC_RDSTD_BIT:
2564 return POWER_SUPPLY_TYPEC_SOURCE_DEFAULT;
2565 case UFP_TYPEC_RD1P5_BIT:
2566 return POWER_SUPPLY_TYPEC_SOURCE_MEDIUM;
2567 case UFP_TYPEC_RD3P0_BIT:
2568 return POWER_SUPPLY_TYPEC_SOURCE_HIGH;
2569 default:
2570 break;
2571 }
2572
Nicholas Troaste1932e42017-04-12 12:38:18 -07002573 return POWER_SUPPLY_TYPEC_NONE;
Nicholas Troast34db5032016-03-28 12:26:44 -07002574}
2575
2576static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
2577{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002578 switch (chg->typec_status[1] & DFP_TYPEC_MASK) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002579 case DFP_RA_RA_BIT:
2580 return POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER;
2581 case DFP_RD_RD_BIT:
2582 return POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY;
2583 case DFP_RD_RA_VCONN_BIT:
2584 return POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE;
2585 case DFP_RD_OPEN_BIT:
2586 return POWER_SUPPLY_TYPEC_SINK;
Nicholas Troast34db5032016-03-28 12:26:44 -07002587 default:
2588 break;
2589 }
2590
2591 return POWER_SUPPLY_TYPEC_NONE;
2592}
2593
Nicholas Troaste1932e42017-04-12 12:38:18 -07002594static int smblib_get_prop_typec_mode(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07002595{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002596 if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
Nicholas Troaste1932e42017-04-12 12:38:18 -07002597 return smblib_get_prop_dfp_mode(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07002598 else
Nicholas Troaste1932e42017-04-12 12:38:18 -07002599 return smblib_get_prop_ufp_mode(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07002600}
2601
2602int smblib_get_prop_typec_power_role(struct smb_charger *chg,
2603 union power_supply_propval *val)
2604{
2605 int rc = 0;
2606 u8 ctrl;
2607
2608 rc = smblib_read(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &ctrl);
2609 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002610 smblib_err(chg, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002611 rc);
2612 return rc;
2613 }
2614 smblib_dbg(chg, PR_REGISTER, "TYPE_C_INTRPT_ENB_SOFTWARE_CTRL = 0x%02x\n",
2615 ctrl);
2616
2617 if (ctrl & TYPEC_DISABLE_CMD_BIT) {
2618 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
2619 return rc;
2620 }
2621
2622 switch (ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT)) {
2623 case 0:
2624 val->intval = POWER_SUPPLY_TYPEC_PR_DUAL;
2625 break;
2626 case DFP_EN_CMD_BIT:
2627 val->intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
2628 break;
2629 case UFP_EN_CMD_BIT:
2630 val->intval = POWER_SUPPLY_TYPEC_PR_SINK;
2631 break;
2632 default:
2633 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002634 smblib_err(chg, "unsupported power role 0x%02lx\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002635 ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT));
2636 return -EINVAL;
2637 }
2638
2639 return rc;
2640}
2641
2642int smblib_get_prop_pd_allowed(struct smb_charger *chg,
2643 union power_supply_propval *val)
2644{
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07002645 val->intval = get_effective_result(chg->pd_allowed_votable);
Nicholas Troast34db5032016-03-28 12:26:44 -07002646 return 0;
2647}
2648
Nicholas Troast133a7f52016-06-29 13:48:20 -07002649int smblib_get_prop_input_current_settled(struct smb_charger *chg,
2650 union power_supply_propval *val)
2651{
2652 return smblib_get_charge_param(chg, &chg->param.icl_stat, &val->intval);
2653}
2654
Fenglin Wuef4730e2017-01-11 18:16:25 +08002655#define HVDCP3_STEP_UV 200000
2656int smblib_get_prop_input_voltage_settled(struct smb_charger *chg,
2657 union power_supply_propval *val)
2658{
Fenglin Wuef4730e2017-01-11 18:16:25 +08002659 int rc, pulses;
Fenglin Wuef4730e2017-01-11 18:16:25 +08002660
Nicholas Troast5f314c12017-05-25 11:58:02 -07002661 switch (chg->real_charger_type) {
Fenglin Wuef4730e2017-01-11 18:16:25 +08002662 case POWER_SUPPLY_TYPE_USB_HVDCP_3:
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +05302663 rc = smblib_get_pulse_cnt(chg, &pulses);
Fenglin Wuef4730e2017-01-11 18:16:25 +08002664 if (rc < 0) {
2665 smblib_err(chg,
2666 "Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
2667 return 0;
2668 }
Fenglin Wuef4730e2017-01-11 18:16:25 +08002669 val->intval = MICRO_5V + HVDCP3_STEP_UV * pulses;
2670 break;
Nicholas Troast5f314c12017-05-25 11:58:02 -07002671 case POWER_SUPPLY_TYPE_USB_PD:
2672 val->intval = chg->voltage_min_uv;
2673 break;
Fenglin Wuef4730e2017-01-11 18:16:25 +08002674 default:
2675 val->intval = MICRO_5V;
2676 break;
2677 }
2678
2679 return 0;
2680}
2681
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002682int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg,
2683 union power_supply_propval *val)
2684{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002685 val->intval = chg->pd_hard_reset;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002686 return 0;
2687}
2688
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07002689int smblib_get_pe_start(struct smb_charger *chg,
2690 union power_supply_propval *val)
2691{
2692 /*
2693 * hvdcp timeout voter is the last one to allow pd. Use its vote
2694 * to indicate start of pe engine
2695 */
2696 val->intval
2697 = !get_client_vote_locked(chg->pd_disallowed_votable_indirect,
2698 HVDCP_TIMEOUT_VOTER);
2699 return 0;
2700}
2701
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002702int smblib_get_prop_die_health(struct smb_charger *chg,
Nicholas Troastb021dd92017-01-31 18:43:38 -08002703 union power_supply_propval *val)
2704{
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002705 int rc;
Nicholas Troastb021dd92017-01-31 18:43:38 -08002706 u8 stat;
2707
2708 rc = smblib_read(chg, TEMP_RANGE_STATUS_REG, &stat);
2709 if (rc < 0) {
2710 smblib_err(chg, "Couldn't read TEMP_RANGE_STATUS_REG rc=%d\n",
2711 rc);
2712 return rc;
2713 }
2714
Harry Yang6ed35462017-11-16 23:01:39 -08002715 if (stat & ALERT_LEVEL_BIT)
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002716 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
Harry Yang6ed35462017-11-16 23:01:39 -08002717 else if (stat & TEMP_ABOVE_RANGE_BIT)
2718 val->intval = POWER_SUPPLY_HEALTH_HOT;
2719 else if (stat & TEMP_WITHIN_RANGE_BIT)
2720 val->intval = POWER_SUPPLY_HEALTH_WARM;
2721 else if (stat & TEMP_BELOW_RANGE_BIT)
2722 val->intval = POWER_SUPPLY_HEALTH_COOL;
2723 else
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002724 val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
Nicholas Troastb021dd92017-01-31 18:43:38 -08002725
Nicholas Troastb021dd92017-01-31 18:43:38 -08002726 return 0;
2727}
2728
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05302729#define SDP_CURRENT_UA 500000
2730#define CDP_CURRENT_UA 1500000
2731#define DCP_CURRENT_UA 1500000
2732#define HVDCP_CURRENT_UA 3000000
2733#define TYPEC_DEFAULT_CURRENT_UA 900000
2734#define TYPEC_MEDIUM_CURRENT_UA 1500000
2735#define TYPEC_HIGH_CURRENT_UA 3000000
2736static int get_rp_based_dcp_current(struct smb_charger *chg, int typec_mode)
2737{
2738 int rp_ua;
2739
2740 switch (typec_mode) {
2741 case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
2742 rp_ua = TYPEC_HIGH_CURRENT_UA;
2743 break;
2744 case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
2745 case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
2746 /* fall through */
2747 default:
2748 rp_ua = DCP_CURRENT_UA;
2749 }
2750
2751 return rp_ua;
2752}
2753
Nicholas Troast34db5032016-03-28 12:26:44 -07002754/*******************
2755 * USB PSY SETTERS *
2756 * *****************/
2757
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002758int smblib_set_prop_pd_current_max(struct smb_charger *chg,
2759 const union power_supply_propval *val)
2760{
2761 int rc;
2762
2763 if (chg->pd_active)
2764 rc = vote(chg->usb_icl_votable, PD_VOTER, true, val->intval);
2765 else
2766 rc = -EPERM;
2767
2768 return rc;
2769}
2770
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05302771static int smblib_handle_usb_current(struct smb_charger *chg,
2772 int usb_current)
2773{
2774 int rc = 0, rp_ua, typec_mode;
2775
2776 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_FLOAT) {
2777 if (usb_current == -ETIMEDOUT) {
2778 /*
2779 * Valid FLOAT charger, report the current based
2780 * of Rp
2781 */
2782 typec_mode = smblib_get_prop_typec_mode(chg);
2783 rp_ua = get_rp_based_dcp_current(chg, typec_mode);
2784 rc = vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER,
2785 true, rp_ua);
2786 if (rc < 0)
2787 return rc;
2788 } else {
2789 /*
2790 * FLOAT charger detected as SDP by USB driver,
2791 * charge with the requested current and update the
2792 * real_charger_type
2793 */
2794 chg->real_charger_type = POWER_SUPPLY_TYPE_USB;
2795 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
2796 true, usb_current);
2797 if (rc < 0)
2798 return rc;
2799 rc = vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER,
2800 false, 0);
2801 if (rc < 0)
2802 return rc;
2803 }
2804 } else {
2805 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
2806 true, usb_current);
2807 }
2808
2809 return rc;
2810}
2811
Nicholas Troast7f55c922017-07-25 13:18:03 -07002812int smblib_set_prop_sdp_current_max(struct smb_charger *chg,
Nicholas Troast34db5032016-03-28 12:26:44 -07002813 const union power_supply_propval *val)
2814{
Nicholas Troast8d33b7d2017-01-16 11:18:38 -08002815 int rc = 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002816
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002817 if (!chg->pd_active) {
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05302818 rc = smblib_handle_usb_current(chg, val->intval);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002819 } else if (chg->system_suspend_supported) {
2820 if (val->intval <= USBIN_25MA)
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302821 rc = vote(chg->usb_icl_votable,
2822 PD_SUSPEND_SUPPORTED_VOTER, true, val->intval);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002823 else
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302824 rc = vote(chg->usb_icl_votable,
2825 PD_SUSPEND_SUPPORTED_VOTER, false, 0);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002826 }
Nicholas Troast34db5032016-03-28 12:26:44 -07002827 return rc;
2828}
2829
Harry Yangd89ff1f2016-12-05 14:59:11 -08002830int smblib_set_prop_boost_current(struct smb_charger *chg,
2831 const union power_supply_propval *val)
2832{
2833 int rc = 0;
2834
2835 rc = smblib_set_charge_param(chg, &chg->param.freq_boost,
2836 val->intval <= chg->boost_threshold_ua ?
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05302837 chg->chg_freq.freq_below_otg_threshold :
2838 chg->chg_freq.freq_above_otg_threshold);
Harry Yangd89ff1f2016-12-05 14:59:11 -08002839 if (rc < 0) {
2840 dev_err(chg->dev, "Error in setting freq_boost rc=%d\n", rc);
2841 return rc;
2842 }
2843
2844 chg->boost_current_ua = val->intval;
2845 return rc;
2846}
2847
Nicholas Troast34db5032016-03-28 12:26:44 -07002848int smblib_set_prop_typec_power_role(struct smb_charger *chg,
2849 const union power_supply_propval *val)
2850{
Tirupathi Reddy0c5d0a52017-09-27 16:31:07 +05302851 /* Check if power role switch is disabled */
2852 if (!get_effective_result(chg->disable_power_role_switch))
2853 return __smblib_set_prop_typec_power_role(chg, val);
Nicholas Troast34db5032016-03-28 12:26:44 -07002854
Tirupathi Reddy0c5d0a52017-09-27 16:31:07 +05302855 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002856}
2857
Nicholas Troast7f55c922017-07-25 13:18:03 -07002858int smblib_set_prop_pd_voltage_min(struct smb_charger *chg,
Nicholas Troast34db5032016-03-28 12:26:44 -07002859 const union power_supply_propval *val)
2860{
2861 int rc, min_uv;
2862
2863 min_uv = min(val->intval, chg->voltage_max_uv);
2864 rc = smblib_set_usb_pd_allowed_voltage(chg, min_uv,
2865 chg->voltage_max_uv);
2866 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002867 smblib_err(chg, "invalid max voltage %duV rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002868 val->intval, rc);
2869 return rc;
2870 }
2871
Harry Yangaba1f5f2016-09-28 10:47:29 -07002872 chg->voltage_min_uv = min_uv;
Nicholas Troast5f314c12017-05-25 11:58:02 -07002873 power_supply_changed(chg->usb_main_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07002874 return rc;
2875}
2876
Nicholas Troast7f55c922017-07-25 13:18:03 -07002877int smblib_set_prop_pd_voltage_max(struct smb_charger *chg,
Nicholas Troast34db5032016-03-28 12:26:44 -07002878 const union power_supply_propval *val)
2879{
2880 int rc, max_uv;
2881
2882 max_uv = max(val->intval, chg->voltage_min_uv);
2883 rc = smblib_set_usb_pd_allowed_voltage(chg, chg->voltage_min_uv,
2884 max_uv);
2885 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002886 smblib_err(chg, "invalid min voltage %duV rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002887 val->intval, rc);
2888 return rc;
2889 }
2890
Harry Yangaba1f5f2016-09-28 10:47:29 -07002891 chg->voltage_max_uv = max_uv;
Nicholas Troast34db5032016-03-28 12:26:44 -07002892 return rc;
2893}
2894
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07002895static int __smblib_set_prop_pd_active(struct smb_charger *chg, bool pd_active)
Nicholas Troast34db5032016-03-28 12:26:44 -07002896{
2897 int rc;
Nicholas Troaste1932e42017-04-12 12:38:18 -07002898 bool orientation, sink_attached, hvdcp;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002899 u8 stat;
Nicholas Troast34db5032016-03-28 12:26:44 -07002900
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07002901 chg->pd_active = pd_active;
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002902 if (chg->pd_active) {
2903 vote(chg->apsd_disable_votable, PD_VOTER, true, 0);
2904 vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
2905 vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
2906
2907 /*
2908 * VCONN_EN_ORIENTATION_BIT controls whether to use CC1 or CC2
2909 * line when TYPEC_SPARE_CFG_BIT (CC pin selection s/w override)
2910 * is set or when VCONN_EN_VALUE_BIT is set.
2911 */
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002912 orientation = chg->typec_status[3] & CC_ORIENTATION_BIT;
Harry Yang88acff42016-09-21 14:56:06 -07002913 rc = smblib_masked_write(chg,
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07002914 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2915 VCONN_EN_ORIENTATION_BIT,
2916 orientation ? 0 : VCONN_EN_ORIENTATION_BIT);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002917 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002918 smblib_err(chg,
Harry Yang88acff42016-09-21 14:56:06 -07002919 "Couldn't enable vconn on CC line rc=%d\n", rc);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002920
2921 /* SW controlled CC_OUT */
2922 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
2923 TYPEC_SPARE_CFG_BIT, TYPEC_SPARE_CFG_BIT);
2924 if (rc < 0)
2925 smblib_err(chg, "Couldn't enable SW cc_out rc=%d\n",
2926 rc);
2927
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302928 /*
2929 * Enforce 500mA for PD until the real vote comes in later.
2930 * It is guaranteed that pd_active is set prior to
2931 * pd_current_max
2932 */
Harry Yangcd995202016-11-07 13:32:52 -08002933 rc = vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002934 if (rc < 0)
Harry Yangcd995202016-11-07 13:32:52 -08002935 smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n",
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002936 rc);
Harry Yangcd995202016-11-07 13:32:52 -08002937
Nicholas Troastf9e44992017-03-14 09:06:56 -07002938 /* since PD was found the cable must be non-legacy */
2939 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
2940
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002941 /* clear USB ICL vote for DCP_VOTER */
Harry Yang631b99e2016-11-17 11:24:25 -08002942 rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002943 if (rc < 0)
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002944 smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n",
2945 rc);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002946
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302947 /* remove USB_PSY_VOTER */
2948 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002949 if (rc < 0)
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302950 smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002951 } else {
Nicholas Troaste1932e42017-04-12 12:38:18 -07002952 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
2953 if (rc < 0) {
2954 smblib_err(chg, "Couldn't read APSD status rc=%d\n",
2955 rc);
2956 return rc;
2957 }
2958
2959 hvdcp = stat & QC_CHARGER_BIT;
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002960 vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
2961 vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
Harry Yang7b429572017-09-12 11:15:04 -07002962 vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002963 vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER,
2964 false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002965
2966 /* HW controlled CC_OUT */
2967 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
2968 TYPEC_SPARE_CFG_BIT, 0);
2969 if (rc < 0)
2970 smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n",
2971 rc);
2972
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002973 /*
2974 * This WA should only run for HVDCP. Non-legacy SDP/CDP could
2975 * draw more, but this WA will remove Rd causing VBUS to drop,
2976 * and data could be interrupted. Non-legacy DCP could also draw
2977 * more, but it may impact compliance.
2978 */
Nicholas Troaste1932e42017-04-12 12:38:18 -07002979 sink_attached = chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT;
Ashay Jaiswal8207ee42017-11-27 11:41:27 +05302980 if ((chg->connector_type != POWER_SUPPLY_CONNECTOR_MICRO_USB)
2981 && !chg->typec_legacy_valid
2982 && !sink_attached && hvdcp)
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002983 schedule_work(&chg->legacy_detection_work);
Harry Yang88acff42016-09-21 14:56:06 -07002984 }
2985
Harry Yang6607b4a2016-05-17 17:50:09 -07002986 smblib_update_usb_type(chg);
Abhijeet Dharmapurikar76e2af52016-10-06 17:25:01 -07002987 power_supply_changed(chg->usb_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07002988 return rc;
2989}
2990
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07002991int smblib_set_prop_pd_active(struct smb_charger *chg,
2992 const union power_supply_propval *val)
2993{
2994 if (!get_effective_result(chg->pd_allowed_votable))
2995 return -EINVAL;
2996
2997 return __smblib_set_prop_pd_active(chg, val->intval);
2998}
2999
Fenglin Wuedd70792016-11-22 13:16:19 +08003000int smblib_set_prop_ship_mode(struct smb_charger *chg,
3001 const union power_supply_propval *val)
3002{
3003 int rc;
3004
3005 smblib_dbg(chg, PR_MISC, "Set ship mode: %d!!\n", !!val->intval);
3006
3007 rc = smblib_masked_write(chg, SHIP_MODE_REG, SHIP_MODE_EN_BIT,
3008 !!val->intval ? SHIP_MODE_EN_BIT : 0);
3009 if (rc < 0)
3010 dev_err(chg->dev, "Couldn't %s ship mode, rc=%d\n",
3011 !!val->intval ? "enable" : "disable", rc);
3012
3013 return rc;
3014}
3015
Harry Yang5e2bb712016-10-18 16:47:48 -07003016int smblib_reg_block_update(struct smb_charger *chg,
3017 struct reg_info *entry)
3018{
3019 int rc = 0;
3020
3021 while (entry && entry->reg) {
3022 rc = smblib_read(chg, entry->reg, &entry->bak);
3023 if (rc < 0) {
3024 dev_err(chg->dev, "Error in reading %s rc=%d\n",
3025 entry->desc, rc);
3026 break;
3027 }
3028 entry->bak &= entry->mask;
3029
3030 rc = smblib_masked_write(chg, entry->reg,
3031 entry->mask, entry->val);
3032 if (rc < 0) {
3033 dev_err(chg->dev, "Error in writing %s rc=%d\n",
3034 entry->desc, rc);
3035 break;
3036 }
3037 entry++;
3038 }
3039
3040 return rc;
3041}
3042
3043int smblib_reg_block_restore(struct smb_charger *chg,
3044 struct reg_info *entry)
3045{
3046 int rc = 0;
3047
3048 while (entry && entry->reg) {
3049 rc = smblib_masked_write(chg, entry->reg,
3050 entry->mask, entry->bak);
3051 if (rc < 0) {
3052 dev_err(chg->dev, "Error in writing %s rc=%d\n",
3053 entry->desc, rc);
3054 break;
3055 }
3056 entry++;
3057 }
3058
3059 return rc;
3060}
3061
Harry Yang755a34b2016-11-01 01:18:51 -07003062static struct reg_info cc2_detach_settings[] = {
3063 {
3064 .reg = TYPE_C_CFG_2_REG,
3065 .mask = TYPE_C_UFP_MODE_BIT | EN_TRY_SOURCE_MODE_BIT,
3066 .val = TYPE_C_UFP_MODE_BIT,
3067 .desc = "TYPE_C_CFG_2_REG",
3068 },
3069 {
3070 .reg = TYPE_C_CFG_3_REG,
3071 .mask = EN_TRYSINK_MODE_BIT,
3072 .val = 0,
3073 .desc = "TYPE_C_CFG_3_REG",
3074 },
3075 {
3076 .reg = TAPER_TIMER_SEL_CFG_REG,
3077 .mask = TYPEC_SPARE_CFG_BIT,
3078 .val = TYPEC_SPARE_CFG_BIT,
3079 .desc = "TAPER_TIMER_SEL_CFG_REG",
3080 },
3081 {
3082 .reg = TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
3083 .mask = VCONN_EN_ORIENTATION_BIT,
3084 .val = 0,
3085 .desc = "TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG",
3086 },
3087 {
3088 .reg = MISC_CFG_REG,
3089 .mask = TCC_DEBOUNCE_20MS_BIT,
3090 .val = TCC_DEBOUNCE_20MS_BIT,
3091 .desc = "Tccdebounce time"
3092 },
3093 {
3094 },
3095};
3096
3097static int smblib_cc2_sink_removal_enter(struct smb_charger *chg)
3098{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003099 int rc, ccout, ufp_mode;
3100 u8 stat;
Harry Yang755a34b2016-11-01 01:18:51 -07003101
3102 if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003103 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07003104
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003105 if (chg->cc2_detach_wa_active)
3106 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07003107
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003108 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
Harry Yang755a34b2016-11-01 01:18:51 -07003109 if (rc < 0) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003110 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
Harry Yang755a34b2016-11-01 01:18:51 -07003111 return rc;
3112 }
Nicholas Troaste1932e42017-04-12 12:38:18 -07003113
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003114 ccout = (stat & CC_ATTACHED_BIT) ?
3115 (!!(stat & CC_ORIENTATION_BIT) + 1) : 0;
3116 ufp_mode = (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT) ?
3117 !(stat & UFP_DFP_MODE_STATUS_BIT) : 0;
Harry Yang755a34b2016-11-01 01:18:51 -07003118
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003119 if (ccout != 2)
3120 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07003121
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003122 if (!ufp_mode)
3123 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07003124
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003125 chg->cc2_detach_wa_active = true;
3126 /* The CC2 removal WA will cause a type-c-change IRQ storm */
3127 smblib_reg_block_update(chg, cc2_detach_settings);
3128 schedule_work(&chg->rdstd_cc2_detach_work);
Harry Yang755a34b2016-11-01 01:18:51 -07003129 return rc;
3130}
3131
3132static int smblib_cc2_sink_removal_exit(struct smb_charger *chg)
3133{
Harry Yang755a34b2016-11-01 01:18:51 -07003134 if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003135 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07003136
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003137 if (!chg->cc2_detach_wa_active)
3138 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07003139
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003140 chg->cc2_detach_wa_active = false;
3141 cancel_work_sync(&chg->rdstd_cc2_detach_work);
3142 smblib_reg_block_restore(chg, cc2_detach_settings);
3143 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07003144}
3145
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07003146int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
3147 const union power_supply_propval *val)
3148{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003149 int rc = 0;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07003150
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003151 if (chg->pd_hard_reset == val->intval)
3152 return rc;
3153
3154 chg->pd_hard_reset = val->intval;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07003155 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003156 EXIT_SNK_BASED_ON_CC_BIT,
3157 (chg->pd_hard_reset) ? EXIT_SNK_BASED_ON_CC_BIT : 0);
3158 if (rc < 0)
3159 smblib_err(chg, "Couldn't set EXIT_SNK_BASED_ON_CC rc=%d\n",
Harry Yang755a34b2016-11-01 01:18:51 -07003160 rc);
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07003161
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003162 vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER,
3163 chg->pd_hard_reset, 0);
Harry Yang755a34b2016-11-01 01:18:51 -07003164
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07003165 return rc;
3166}
3167
Anirudh Ghayal941acaa2017-07-19 16:04:44 +05303168static int smblib_recover_from_soft_jeita(struct smb_charger *chg)
3169{
3170 u8 stat_1, stat_2;
3171 int rc;
3172
3173 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat_1);
3174 if (rc < 0) {
3175 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
3176 rc);
3177 return rc;
3178 }
3179
3180 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat_2);
3181 if (rc < 0) {
3182 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
3183 rc);
3184 return rc;
3185 }
3186
3187 if ((chg->jeita_status && !(stat_2 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK) &&
3188 ((stat_1 & BATTERY_CHARGER_STATUS_MASK) == TERMINATE_CHARGE))) {
3189 /*
3190 * We are moving from JEITA soft -> Normal and charging
3191 * is terminated
3192 */
3193 rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG, 0);
3194 if (rc < 0) {
3195 smblib_err(chg, "Couldn't disable charging rc=%d\n",
3196 rc);
3197 return rc;
3198 }
3199 rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG,
3200 CHARGING_ENABLE_CMD_BIT);
3201 if (rc < 0) {
3202 smblib_err(chg, "Couldn't enable charging rc=%d\n",
3203 rc);
3204 return rc;
3205 }
3206 }
3207
3208 chg->jeita_status = stat_2 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK;
3209
3210 return 0;
3211}
3212
Nicholas Troast7dbcad22016-10-05 13:30:18 -07003213/************************
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003214 * USB MAIN PSY GETTERS *
3215 ************************/
3216int smblib_get_prop_fcc_delta(struct smb_charger *chg,
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05303217 union power_supply_propval *val)
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003218{
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05303219 int rc, jeita_cc_delta_ua = 0;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003220
Harry Yang0d189772017-10-06 12:42:10 -07003221 if (chg->sw_jeita_enabled) {
3222 val->intval = 0;
3223 return 0;
3224 }
3225
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003226 rc = smblib_get_jeita_cc_delta(chg, &jeita_cc_delta_ua);
3227 if (rc < 0) {
3228 smblib_err(chg, "Couldn't get jeita cc delta rc=%d\n", rc);
3229 jeita_cc_delta_ua = 0;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003230 }
3231
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05303232 val->intval = jeita_cc_delta_ua;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003233 return 0;
3234}
3235
3236/************************
3237 * USB MAIN PSY SETTERS *
3238 ************************/
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003239int smblib_get_charge_current(struct smb_charger *chg,
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003240 int *total_current_ua)
3241{
Ashay Jaiswal7b6eb962017-04-26 14:34:29 +05303242 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003243 union power_supply_propval val = {0, };
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003244 int rc = 0, typec_source_rd, current_ua;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003245 bool non_compliant;
3246 u8 stat5;
3247
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003248 if (chg->pd_active) {
3249 *total_current_ua =
3250 get_client_vote_locked(chg->usb_icl_votable, PD_VOTER);
3251 return rc;
3252 }
3253
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003254 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
3255 if (rc < 0) {
3256 smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc);
3257 return rc;
3258 }
3259 non_compliant = stat5 & TYPEC_NONCOMP_LEGACY_CABLE_STATUS_BIT;
3260
3261 /* get settled ICL */
3262 rc = smblib_get_prop_input_current_settled(chg, &val);
3263 if (rc < 0) {
3264 smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
3265 return rc;
3266 }
3267
3268 typec_source_rd = smblib_get_prop_ufp_mode(chg);
3269
3270 /* QC 2.0/3.0 adapter */
3271 if (apsd_result->bit & (QC_3P0_BIT | QC_2P0_BIT)) {
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303272 *total_current_ua = HVDCP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003273 return 0;
3274 }
3275
3276 if (non_compliant) {
3277 switch (apsd_result->bit) {
3278 case CDP_CHARGER_BIT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303279 current_ua = CDP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003280 break;
3281 case DCP_CHARGER_BIT:
3282 case OCP_CHARGER_BIT:
3283 case FLOAT_CHARGER_BIT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303284 current_ua = DCP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003285 break;
3286 default:
3287 current_ua = 0;
3288 break;
3289 }
3290
3291 *total_current_ua = max(current_ua, val.intval);
3292 return 0;
3293 }
3294
3295 switch (typec_source_rd) {
3296 case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
3297 switch (apsd_result->bit) {
3298 case CDP_CHARGER_BIT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303299 current_ua = CDP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003300 break;
3301 case DCP_CHARGER_BIT:
3302 case OCP_CHARGER_BIT:
3303 case FLOAT_CHARGER_BIT:
3304 current_ua = chg->default_icl_ua;
3305 break;
3306 default:
3307 current_ua = 0;
3308 break;
3309 }
3310 break;
3311 case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303312 current_ua = TYPEC_MEDIUM_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003313 break;
3314 case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303315 current_ua = TYPEC_HIGH_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003316 break;
3317 case POWER_SUPPLY_TYPEC_NON_COMPLIANT:
3318 case POWER_SUPPLY_TYPEC_NONE:
3319 default:
3320 current_ua = 0;
3321 break;
3322 }
3323
3324 *total_current_ua = max(current_ua, val.intval);
3325 return 0;
3326}
3327
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003328/************************
Nicholas Troast7dbcad22016-10-05 13:30:18 -07003329 * PARALLEL PSY GETTERS *
3330 ************************/
3331
3332int smblib_get_prop_slave_current_now(struct smb_charger *chg,
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003333 union power_supply_propval *pval)
Nicholas Troast7dbcad22016-10-05 13:30:18 -07003334{
3335 if (IS_ERR_OR_NULL(chg->iio.batt_i_chan))
3336 chg->iio.batt_i_chan = iio_channel_get(chg->dev, "batt_i");
3337
3338 if (IS_ERR(chg->iio.batt_i_chan))
3339 return PTR_ERR(chg->iio.batt_i_chan);
3340
3341 return iio_read_channel_processed(chg->iio.batt_i_chan, &pval->intval);
3342}
3343
Nicholas Troast34db5032016-03-28 12:26:44 -07003344/**********************
3345 * INTERRUPT HANDLERS *
3346 **********************/
3347
3348irqreturn_t smblib_handle_debug(int irq, void *data)
3349{
3350 struct smb_irq_data *irq_data = data;
3351 struct smb_charger *chg = irq_data->parent_data;
3352
3353 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003354 return IRQ_HANDLED;
3355}
3356
Nicholas Troast8995a702016-12-05 10:22:22 -08003357irqreturn_t smblib_handle_otg_overcurrent(int irq, void *data)
3358{
3359 struct smb_irq_data *irq_data = data;
3360 struct smb_charger *chg = irq_data->parent_data;
3361 int rc;
3362 u8 stat;
3363
3364 rc = smblib_read(chg, OTG_BASE + INT_RT_STS_OFFSET, &stat);
3365 if (rc < 0) {
3366 dev_err(chg->dev, "Couldn't read OTG_INT_RT_STS rc=%d\n", rc);
3367 return IRQ_HANDLED;
3368 }
3369
Ashay Jaiswal7c241382017-03-06 15:26:38 +05303370 if (chg->wa_flags & OTG_WA) {
3371 if (stat & OTG_OC_DIS_SW_STS_RT_STS_BIT)
3372 smblib_err(chg, "OTG disabled by hw\n");
3373
3374 /* not handling software based hiccups for PM660 */
3375 return IRQ_HANDLED;
3376 }
3377
Nicholas Troastb11015f2017-01-17 17:56:45 -08003378 if (stat & OTG_OVERCURRENT_RT_STS_BIT)
3379 schedule_work(&chg->otg_oc_work);
Nicholas Troast8995a702016-12-05 10:22:22 -08003380
Nicholas Troast8995a702016-12-05 10:22:22 -08003381 return IRQ_HANDLED;
3382}
3383
Harry Yang6fe72ab2016-06-14 16:21:39 -07003384irqreturn_t smblib_handle_chg_state_change(int irq, void *data)
3385{
3386 struct smb_irq_data *irq_data = data;
3387 struct smb_charger *chg = irq_data->parent_data;
Nicholas Troast8cb77552016-09-23 11:50:18 -07003388 u8 stat;
Harry Yang1d1034c2016-06-15 12:09:42 -07003389 int rc;
Harry Yang6fe72ab2016-06-14 16:21:39 -07003390
3391 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3392
Nicholas Troast8cb77552016-09-23 11:50:18 -07003393 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
Harry Yang1d1034c2016-06-15 12:09:42 -07003394 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003395 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003396 rc);
Harry Yang1d1034c2016-06-15 12:09:42 -07003397 return IRQ_HANDLED;
3398 }
3399
Nicholas Troast8cb77552016-09-23 11:50:18 -07003400 stat = stat & BATTERY_CHARGER_STATUS_MASK;
Nicholas Troast8cb77552016-09-23 11:50:18 -07003401 power_supply_changed(chg->batt_psy);
Harry Yang6fe72ab2016-06-14 16:21:39 -07003402 return IRQ_HANDLED;
3403}
3404
Abhijeet Dharmapurikar2644cd62016-07-20 16:54:55 -07003405irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data)
3406{
3407 struct smb_irq_data *irq_data = data;
3408 struct smb_charger *chg = irq_data->parent_data;
Anirudh Ghayal941acaa2017-07-19 16:04:44 +05303409 int rc;
3410
3411 rc = smblib_recover_from_soft_jeita(chg);
3412 if (rc < 0) {
3413 smblib_err(chg, "Couldn't recover chg from soft jeita rc=%d\n",
3414 rc);
3415 return IRQ_HANDLED;
3416 }
Abhijeet Dharmapurikar2644cd62016-07-20 16:54:55 -07003417
3418 rerun_election(chg->fcc_votable);
3419 power_supply_changed(chg->batt_psy);
3420 return IRQ_HANDLED;
3421}
3422
Nicholas Troast34db5032016-03-28 12:26:44 -07003423irqreturn_t smblib_handle_batt_psy_changed(int irq, void *data)
3424{
3425 struct smb_irq_data *irq_data = data;
3426 struct smb_charger *chg = irq_data->parent_data;
3427
Nicholas Troast47ae4612016-08-03 09:49:36 -07003428 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003429 power_supply_changed(chg->batt_psy);
3430 return IRQ_HANDLED;
3431}
3432
3433irqreturn_t smblib_handle_usb_psy_changed(int irq, void *data)
3434{
3435 struct smb_irq_data *irq_data = data;
3436 struct smb_charger *chg = irq_data->parent_data;
3437
Nicholas Troast47ae4612016-08-03 09:49:36 -07003438 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003439 power_supply_changed(chg->usb_psy);
3440 return IRQ_HANDLED;
3441}
3442
Subbaraman Narayanamurthy09327482017-02-06 16:33:12 -08003443irqreturn_t smblib_handle_usbin_uv(int irq, void *data)
3444{
3445 struct smb_irq_data *irq_data = data;
3446 struct smb_charger *chg = irq_data->parent_data;
3447 struct storm_watch *wdata;
Harry Yang3d515b82018-04-06 16:01:04 -07003448 const struct apsd_result *apsd = smblib_get_apsd_result(chg);
3449 int rc;
3450 u8 stat = 0, max_pulses = 0;
Subbaraman Narayanamurthy09327482017-02-06 16:33:12 -08003451
3452 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3453 if (!chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data)
3454 return IRQ_HANDLED;
3455
3456 wdata = &chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data->storm_data;
3457 reset_storm_count(wdata);
Harry Yang3d515b82018-04-06 16:01:04 -07003458
3459 if (!chg->non_compliant_chg_detected &&
3460 apsd->pst == POWER_SUPPLY_TYPE_USB_HVDCP) {
3461 rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat);
3462 if (rc < 0)
3463 smblib_err(chg,
3464 "Couldn't read CHANGE_STATUS_REG rc=%d\n", rc);
3465
3466 if (stat & QC_5V_BIT)
3467 return IRQ_HANDLED;
3468
3469 rc = smblib_read(chg, HVDCP_PULSE_COUNT_MAX_REG, &max_pulses);
3470 if (rc < 0)
3471 smblib_err(chg,
3472 "Couldn't read QC2 max pulses rc=%d\n", rc);
3473
3474 chg->non_compliant_chg_detected = true;
3475 chg->qc2_max_pulses = (max_pulses &
3476 HVDCP_PULSE_COUNT_MAX_QC2_MASK);
3477
3478 if (stat & QC_12V_BIT) {
3479 rc = smblib_masked_write(chg, HVDCP_PULSE_COUNT_MAX_REG,
3480 HVDCP_PULSE_COUNT_MAX_QC2_MASK,
3481 HVDCP_PULSE_COUNT_MAX_QC2_9V);
3482 if (rc < 0)
3483 smblib_err(chg, "Couldn't force max pulses to 9V rc=%d\n",
3484 rc);
3485
3486 } else if (stat & QC_9V_BIT) {
3487 rc = smblib_masked_write(chg, HVDCP_PULSE_COUNT_MAX_REG,
3488 HVDCP_PULSE_COUNT_MAX_QC2_MASK,
3489 HVDCP_PULSE_COUNT_MAX_QC2_5V);
3490 if (rc < 0)
3491 smblib_err(chg, "Couldn't force max pulses to 5V rc=%d\n",
3492 rc);
3493
3494 }
3495 smblib_rerun_apsd(chg);
3496 }
3497
Subbaraman Narayanamurthy09327482017-02-06 16:33:12 -08003498 return IRQ_HANDLED;
3499}
3500
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003501static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising)
3502{
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003503 if (vbus_rising) {
3504 /* use the typec flag even though its not typec */
3505 chg->typec_present = 1;
3506 } else {
3507 chg->typec_present = 0;
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003508 smblib_update_usb_type(chg);
3509 extcon_set_cable_state_(chg->extcon, EXTCON_USB, false);
3510 smblib_uusb_removal(chg);
3511 }
3512}
3513
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003514void smblib_usb_plugin_hard_reset_locked(struct smb_charger *chg)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003515{
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003516 int rc;
3517 u8 stat;
3518 bool vbus_rising;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303519 struct smb_irq_data *data;
3520 struct storm_watch *wdata;
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003521
3522 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
3523 if (rc < 0) {
3524 smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
3525 return;
3526 }
3527
3528 vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
3529
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303530 if (vbus_rising) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003531 smblib_cc2_sink_removal_exit(chg);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303532 } else {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003533 smblib_cc2_sink_removal_enter(chg);
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303534 if (chg->wa_flags & BOOST_BACK_WA) {
3535 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
3536 if (data) {
3537 wdata = &data->storm_data;
3538 update_storm_count(wdata,
3539 WEAK_CHG_STORM_COUNT);
3540 vote(chg->usb_icl_votable, BOOST_BACK_VOTER,
3541 false, 0);
3542 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
3543 false, 0);
3544 }
3545 }
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303546 }
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003547
3548 power_supply_changed(chg->usb_psy);
3549 smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
3550 vbus_rising ? "attached" : "detached");
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003551}
3552
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303553#define PL_DELAY_MS 30000
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003554void smblib_usb_plugin_locked(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07003555{
Nicholas Troast34db5032016-03-28 12:26:44 -07003556 int rc;
3557 u8 stat;
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003558 bool vbus_rising;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303559 struct smb_irq_data *data;
3560 struct storm_watch *wdata;
Nicholas Troast34db5032016-03-28 12:26:44 -07003561
Harry Yangcdad2bf2016-10-04 17:03:56 -07003562 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
3563 if (rc < 0) {
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003564 smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
3565 return;
Harry Yangcdad2bf2016-10-04 17:03:56 -07003566 }
3567
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003568 vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003569 smblib_set_opt_freq_buck(chg, vbus_rising ? chg->chg_freq.freq_5V :
3570 chg->chg_freq.freq_removal);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003571
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003572 if (vbus_rising) {
Harry Yang287e3e92018-03-27 14:17:42 -07003573 if (smblib_get_prop_dfp_mode(chg) != POWER_SUPPLY_TYPEC_NONE) {
3574 chg->fake_usb_insertion = true;
3575 return;
3576 }
3577
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05303578 rc = smblib_request_dpdm(chg, true);
3579 if (rc < 0)
3580 smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303581
3582 /* Schedule work to enable parallel charger */
3583 vote(chg->awake_votable, PL_DELAY_VOTER, true, 0);
3584 schedule_delayed_work(&chg->pl_enable_work,
3585 msecs_to_jiffies(PL_DELAY_MS));
Harry Yang1ed7f162017-08-25 11:26:51 -07003586 /* vbus rising when APSD was disabled and PD_ACTIVE = 0 */
3587 if (get_effective_result(chg->apsd_disable_votable) &&
3588 !chg->pd_active)
3589 pr_err("APSD disabled on vbus rising without PD\n");
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07003590 } else {
Harry Yang287e3e92018-03-27 14:17:42 -07003591 if (chg->fake_usb_insertion) {
3592 chg->fake_usb_insertion = false;
3593 return;
3594 }
3595
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303596 if (chg->wa_flags & BOOST_BACK_WA) {
3597 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
3598 if (data) {
3599 wdata = &data->storm_data;
3600 update_storm_count(wdata,
3601 WEAK_CHG_STORM_COUNT);
3602 vote(chg->usb_icl_votable, BOOST_BACK_VOTER,
3603 false, 0);
3604 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
3605 false, 0);
3606 }
3607 }
Nicholas Troastabedaf72016-09-16 11:07:45 -07003608
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05303609 rc = smblib_request_dpdm(chg, false);
3610 if (rc < 0)
3611 smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07003612 }
3613
Ashay Jaiswal0ce2c7c2017-11-14 12:29:02 +05303614 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003615 smblib_micro_usb_plugin(chg, vbus_rising);
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003616
Nicholas Troast62d86622016-09-22 11:41:33 -07003617 power_supply_changed(chg->usb_psy);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003618 smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
3619 vbus_rising ? "attached" : "detached");
3620}
3621
3622irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
3623{
3624 struct smb_irq_data *irq_data = data;
3625 struct smb_charger *chg = irq_data->parent_data;
3626
3627 mutex_lock(&chg->lock);
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003628 if (chg->pd_hard_reset)
3629 smblib_usb_plugin_hard_reset_locked(chg);
3630 else
3631 smblib_usb_plugin_locked(chg);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003632 mutex_unlock(&chg->lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07003633 return IRQ_HANDLED;
3634}
3635
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -07003636#define USB_WEAK_INPUT_UA 1400000
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303637#define ICL_CHANGE_DELAY_MS 1000
Harry Yang6fe72ab2016-06-14 16:21:39 -07003638irqreturn_t smblib_handle_icl_change(int irq, void *data)
3639{
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303640 u8 stat;
3641 int rc, settled_ua, delay = ICL_CHANGE_DELAY_MS;
Harry Yang6fe72ab2016-06-14 16:21:39 -07003642 struct smb_irq_data *irq_data = data;
3643 struct smb_charger *chg = irq_data->parent_data;
3644
Nicholas Troastbb9e1a32017-02-09 10:57:28 -08003645 if (chg->mode == PARALLEL_MASTER) {
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303646 rc = smblib_read(chg, AICL_STATUS_REG, &stat);
3647 if (rc < 0) {
3648 smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n",
3649 rc);
3650 return IRQ_HANDLED;
3651 }
3652
3653 rc = smblib_get_charge_param(chg, &chg->param.icl_stat,
3654 &settled_ua);
3655 if (rc < 0) {
3656 smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
3657 return IRQ_HANDLED;
3658 }
3659
3660 /* If AICL settled then schedule work now */
3661 if ((settled_ua == get_effective_result(chg->usb_icl_votable))
3662 || (stat & AICL_DONE_BIT))
3663 delay = 0;
3664
Ashay Jaiswalac854862017-03-06 23:58:55 +05303665 cancel_delayed_work_sync(&chg->icl_change_work);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303666 schedule_delayed_work(&chg->icl_change_work,
3667 msecs_to_jiffies(delay));
Nicholas Troastbb9e1a32017-02-09 10:57:28 -08003668 }
Harry Yang1d1034c2016-06-15 12:09:42 -07003669
Harry Yang6fe72ab2016-06-14 16:21:39 -07003670 return IRQ_HANDLED;
3671}
3672
Nicholas Troast34db5032016-03-28 12:26:44 -07003673static void smblib_handle_slow_plugin_timeout(struct smb_charger *chg,
3674 bool rising)
3675{
3676 smblib_dbg(chg, PR_INTERRUPT, "IRQ: slow-plugin-timeout %s\n",
3677 rising ? "rising" : "falling");
3678}
3679
3680static void smblib_handle_sdp_enumeration_done(struct smb_charger *chg,
3681 bool rising)
3682{
3683 smblib_dbg(chg, PR_INTERRUPT, "IRQ: sdp-enumeration-done %s\n",
3684 rising ? "rising" : "falling");
3685}
3686
Umang Agrawal49680b62018-04-16 14:41:11 +05303687#define MICRO_10P3V 10300000
3688static void smblib_check_ov_condition(struct smb_charger *chg)
3689{
3690 union power_supply_propval pval = {0, };
3691 int rc;
3692
3693 if (chg->wa_flags & OV_IRQ_WA_BIT) {
3694 rc = power_supply_get_property(chg->usb_psy,
3695 POWER_SUPPLY_PROP_VOLTAGE_NOW, &pval);
3696 if (rc < 0) {
3697 smblib_err(chg, "Couldn't get current voltage, rc=%d\n",
3698 rc);
3699 return;
3700 }
3701
3702 if (pval.intval > MICRO_10P3V) {
3703 smblib_err(chg, "USBIN OV detected\n");
3704 vote(chg->hvdcp_hw_inov_dis_votable, OV_VOTER, true,
3705 0);
3706 pval.intval = POWER_SUPPLY_DP_DM_FORCE_5V;
3707 rc = power_supply_set_property(chg->batt_psy,
3708 POWER_SUPPLY_PROP_DP_DM, &pval);
3709 return;
3710 }
3711 }
3712}
3713
Harry Yangcdad2bf2016-10-04 17:03:56 -07003714#define QC3_PULSES_FOR_6V 5
3715#define QC3_PULSES_FOR_9V 20
3716#define QC3_PULSES_FOR_12V 35
3717static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg)
3718{
3719 int rc;
3720 u8 stat;
3721 int pulses;
3722
Umang Agrawal49680b62018-04-16 14:41:11 +05303723 smblib_check_ov_condition(chg);
Fenglin Wuef4730e2017-01-11 18:16:25 +08003724 power_supply_changed(chg->usb_main_psy);
Fenglin Wu80826e02017-04-25 21:45:08 +08003725 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP) {
Harry Yangcdad2bf2016-10-04 17:03:56 -07003726 rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat);
3727 if (rc < 0) {
3728 smblib_err(chg,
3729 "Couldn't read QC_CHANGE_STATUS rc=%d\n", rc);
3730 return;
3731 }
3732
3733 switch (stat & QC_2P0_STATUS_MASK) {
3734 case QC_5V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303735 smblib_set_opt_freq_buck(chg,
3736 chg->chg_freq.freq_5V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003737 break;
3738 case QC_9V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303739 smblib_set_opt_freq_buck(chg,
3740 chg->chg_freq.freq_9V);
Ashay Jaiswal1c360c82018-03-15 23:24:42 +05303741 vote(chg->usb_icl_votable, HVDCP2_ICL_VOTER, false, 0);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003742 break;
3743 case QC_12V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303744 smblib_set_opt_freq_buck(chg,
3745 chg->chg_freq.freq_12V);
Ashay Jaiswal1c360c82018-03-15 23:24:42 +05303746 vote(chg->usb_icl_votable, HVDCP2_ICL_VOTER, false, 0);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003747 break;
3748 default:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303749 smblib_set_opt_freq_buck(chg,
3750 chg->chg_freq.freq_removal);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003751 break;
3752 }
3753 }
3754
Fenglin Wu80826e02017-04-25 21:45:08 +08003755 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP_3) {
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +05303756 rc = smblib_get_pulse_cnt(chg, &pulses);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003757 if (rc < 0) {
3758 smblib_err(chg,
3759 "Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
3760 return;
3761 }
Harry Yangcdad2bf2016-10-04 17:03:56 -07003762
3763 if (pulses < QC3_PULSES_FOR_6V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303764 smblib_set_opt_freq_buck(chg,
3765 chg->chg_freq.freq_5V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003766 else if (pulses < QC3_PULSES_FOR_9V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303767 smblib_set_opt_freq_buck(chg,
3768 chg->chg_freq.freq_6V_8V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003769 else if (pulses < QC3_PULSES_FOR_12V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303770 smblib_set_opt_freq_buck(chg,
3771 chg->chg_freq.freq_9V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003772 else
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303773 smblib_set_opt_freq_buck(chg,
3774 chg->chg_freq.freq_12V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003775 }
3776}
3777
Nicholas Troast34db5032016-03-28 12:26:44 -07003778/* triggers when HVDCP 3.0 authentication has finished */
3779static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
3780 bool rising)
3781{
3782 const struct apsd_result *apsd_result;
Harry Yangcdad2bf2016-10-04 17:03:56 -07003783 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07003784
3785 if (!rising)
3786 return;
3787
Ashay Jaiswal67ec7072017-02-16 14:14:58 +05303788 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
3789 /*
3790 * Disable AUTH_IRQ_EN_CFG_BIT to receive adapter voltage
3791 * change interrupt.
3792 */
3793 rc = smblib_masked_write(chg,
3794 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
3795 AUTH_IRQ_EN_CFG_BIT, 0);
3796 if (rc < 0)
3797 smblib_err(chg,
3798 "Couldn't enable QC auth setting rc=%d\n", rc);
3799 }
Harry Yangcdad2bf2016-10-04 17:03:56 -07003800
Harry Yangaba1f5f2016-09-28 10:47:29 -07003801 if (chg->mode == PARALLEL_MASTER)
3802 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0);
3803
Ashay Jaiswalac854862017-03-06 23:58:55 +05303804 /* the APSD done handler will set the USB supply type */
3805 apsd_result = smblib_get_apsd_result(chg);
Ashay Jaiswalac854862017-03-06 23:58:55 +05303806
Nicholas Troast34db5032016-03-28 12:26:44 -07003807 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n",
3808 apsd_result->name);
3809}
3810
Harry Yang1369b7a2016-09-27 15:59:50 -07003811static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
3812 bool rising, bool qc_charger)
3813{
Ashay Jaiswal7b6eb962017-04-26 14:34:29 +05303814 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05303815
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003816 /* Hold off PD only until hvdcp 2.0 detection timeout */
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003817 if (rising) {
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003818 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003819 false, 0);
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -08003820
Harry Yang4bf7d962017-03-13 16:51:43 -07003821 /* enable HDC and ICL irq for QC2/3 charger */
3822 if (qc_charger)
3823 vote(chg->usb_irq_enable_votable, QC_VOTER, true, 0);
3824
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -08003825 /*
3826 * HVDCP detection timeout done
3827 * If adapter is not QC2.0/QC3.0 - it is a plain old DCP.
3828 */
3829 if (!qc_charger && (apsd_result->bit & DCP_CHARGER_BIT))
3830 /* enforce DCP ICL if specified */
3831 vote(chg->usb_icl_votable, DCP_VOTER,
3832 chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua);
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07003833
3834 /*
3835 * if pd is not allowed, then set pd_active = false right here,
3836 * so that it starts the hvdcp engine
3837 */
3838 if (!get_effective_result(chg->pd_allowed_votable))
3839 __smblib_set_prop_pd_active(chg, 0);
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003840 }
Harry Yang1369b7a2016-09-27 15:59:50 -07003841
3842 smblib_dbg(chg, PR_INTERRUPT, "IRQ: smblib_handle_hvdcp_check_timeout %s\n",
3843 rising ? "rising" : "falling");
3844}
3845
Nicholas Troast34db5032016-03-28 12:26:44 -07003846/* triggers when HVDCP is detected */
3847static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg,
3848 bool rising)
3849{
3850 if (!rising)
3851 return;
3852
3853 /* the APSD done handler will set the USB supply type */
3854 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
3855 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-detect-done %s\n",
3856 rising ? "rising" : "falling");
3857}
3858
Nicholas Troastf9e44992017-03-14 09:06:56 -07003859static void smblib_force_legacy_icl(struct smb_charger *chg, int pst)
3860{
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303861 int typec_mode;
3862 int rp_ua;
3863
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003864 /* while PD is active it should have complete ICL control */
3865 if (chg->pd_active)
3866 return;
3867
Nicholas Troastf9e44992017-03-14 09:06:56 -07003868 switch (pst) {
3869 case POWER_SUPPLY_TYPE_USB:
3870 /*
3871 * USB_PSY will vote to increase the current to 500/900mA once
3872 * enumeration is done. Ensure that USB_PSY has at least voted
3873 * for 100mA before releasing the LEGACY_UNKNOWN vote
3874 */
3875 if (!is_client_vote_enabled(chg->usb_icl_votable,
3876 USB_PSY_VOTER))
3877 vote(chg->usb_icl_votable, USB_PSY_VOTER, true, 100000);
3878 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
3879 break;
3880 case POWER_SUPPLY_TYPE_USB_CDP:
3881 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1500000);
3882 break;
3883 case POWER_SUPPLY_TYPE_USB_DCP:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303884 typec_mode = smblib_get_prop_typec_mode(chg);
3885 rp_ua = get_rp_based_dcp_current(chg, typec_mode);
3886 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua);
Nicholas Troastf9e44992017-03-14 09:06:56 -07003887 break;
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05303888 case POWER_SUPPLY_TYPE_USB_FLOAT:
3889 /*
3890 * limit ICL to 100mA, the USB driver will enumerate to check
3891 * if this is a SDP and appropriately set the current
3892 */
3893 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
3894 break;
Nicholas Troastf9e44992017-03-14 09:06:56 -07003895 case POWER_SUPPLY_TYPE_USB_HVDCP:
3896 case POWER_SUPPLY_TYPE_USB_HVDCP_3:
3897 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 3000000);
3898 break;
3899 default:
3900 smblib_err(chg, "Unknown APSD %d; forcing 500mA\n", pst);
3901 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 500000);
3902 break;
3903 }
3904}
3905
Ankit Sharmade321e12017-09-01 20:17:45 +05303906static void smblib_notify_extcon_props(struct smb_charger *chg, int id)
3907{
3908 union extcon_property_value val;
3909 union power_supply_propval prop_val;
3910
3911 smblib_get_prop_typec_cc_orientation(chg, &prop_val);
3912 val.intval = ((prop_val.intval == 2) ? 1 : 0);
3913 extcon_set_property(chg->extcon, id,
3914 EXTCON_PROP_USB_TYPEC_POLARITY, val);
3915
3916 val.intval = true;
3917 extcon_set_property(chg->extcon, id,
3918 EXTCON_PROP_USB_SS, val);
3919}
3920
3921static void smblib_notify_device_mode(struct smb_charger *chg, bool enable)
3922{
3923 if (enable)
3924 smblib_notify_extcon_props(chg, EXTCON_USB);
3925
3926 extcon_set_state_sync(chg->extcon, EXTCON_USB, enable);
3927}
3928
3929static void smblib_notify_usb_host(struct smb_charger *chg, bool enable)
3930{
3931 if (enable)
3932 smblib_notify_extcon_props(chg, EXTCON_USB_HOST);
3933
3934 extcon_set_state_sync(chg->extcon, EXTCON_USB_HOST, enable);
3935}
3936
Nicholas Troast34db5032016-03-28 12:26:44 -07003937#define HVDCP_DET_MS 2500
3938static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
3939{
Nicholas Troast34db5032016-03-28 12:26:44 -07003940 const struct apsd_result *apsd_result;
3941
3942 if (!rising)
3943 return;
3944
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07003945 apsd_result = smblib_update_usb_type(chg);
Nicholas Troastf9e44992017-03-14 09:06:56 -07003946
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003947 if (!chg->typec_legacy_valid)
Nicholas Troastf9e44992017-03-14 09:06:56 -07003948 smblib_force_legacy_icl(chg, apsd_result->pst);
3949
Nicholas Troast34db5032016-03-28 12:26:44 -07003950 switch (apsd_result->bit) {
3951 case SDP_CHARGER_BIT:
3952 case CDP_CHARGER_BIT:
Sundara Vinayagamf32d3f52018-02-27 18:08:44 +05303953 /* if not DCP, Enable pd here */
Abhijeet Dharmapurikarbb9505f2017-03-22 18:31:28 -07003954 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3955 false, 0);
Sundara Vinayagamf32d3f52018-02-27 18:08:44 +05303956 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB
3957 || chg->use_extcon)
Ankit Sharmade321e12017-09-01 20:17:45 +05303958 smblib_notify_device_mode(chg, true);
Abhijeet Dharmapurikarbb9505f2017-03-22 18:31:28 -07003959 break;
Nicholas Troast34db5032016-03-28 12:26:44 -07003960 case OCP_CHARGER_BIT:
3961 case FLOAT_CHARGER_BIT:
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303962 /* if not DCP then no hvdcp timeout happens, Enable pd here. */
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003963 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3964 false, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07003965 break;
3966 case DCP_CHARGER_BIT:
Harry Yang1369b7a2016-09-27 15:59:50 -07003967 if (chg->wa_flags & QC_CHARGER_DETECTION_WA_BIT)
3968 schedule_delayed_work(&chg->hvdcp_detect_work,
3969 msecs_to_jiffies(HVDCP_DET_MS));
Nicholas Troast34db5032016-03-28 12:26:44 -07003970 break;
3971 default:
3972 break;
3973 }
3974
Nicholas Troast34db5032016-03-28 12:26:44 -07003975 smblib_dbg(chg, PR_INTERRUPT, "IRQ: apsd-done rising; %s detected\n",
3976 apsd_result->name);
3977}
3978
3979irqreturn_t smblib_handle_usb_source_change(int irq, void *data)
3980{
3981 struct smb_irq_data *irq_data = data;
3982 struct smb_charger *chg = irq_data->parent_data;
3983 int rc = 0;
3984 u8 stat;
3985
Harry Yang287e3e92018-03-27 14:17:42 -07003986 if (chg->fake_usb_insertion)
3987 return IRQ_HANDLED;
3988
Nicholas Troast34db5032016-03-28 12:26:44 -07003989 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
3990 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003991 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07003992 return IRQ_HANDLED;
3993 }
3994 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
3995
Ashay Jaiswal0ce2c7c2017-11-14 12:29:02 +05303996 if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
3997 && (stat & APSD_DTC_STATUS_DONE_BIT)
Ashay Jaiswal8507aa52017-04-14 09:42:32 +05303998 && !chg->uusb_apsd_rerun_done) {
3999 /*
4000 * Force re-run APSD to handle slow insertion related
4001 * charger-mis-detection.
4002 */
4003 chg->uusb_apsd_rerun_done = true;
4004 smblib_rerun_apsd(chg);
4005 return IRQ_HANDLED;
4006 }
4007
Nicholas Troast34db5032016-03-28 12:26:44 -07004008 smblib_handle_apsd_done(chg,
4009 (bool)(stat & APSD_DTC_STATUS_DONE_BIT));
4010
4011 smblib_handle_hvdcp_detect_done(chg,
4012 (bool)(stat & QC_CHARGER_BIT));
4013
Harry Yang1369b7a2016-09-27 15:59:50 -07004014 smblib_handle_hvdcp_check_timeout(chg,
4015 (bool)(stat & HVDCP_CHECK_TIMEOUT_BIT),
4016 (bool)(stat & QC_CHARGER_BIT));
4017
Nicholas Troast34db5032016-03-28 12:26:44 -07004018 smblib_handle_hvdcp_3p0_auth_done(chg,
4019 (bool)(stat & QC_AUTH_DONE_STATUS_BIT));
4020
Nicholas Troast34db5032016-03-28 12:26:44 -07004021 smblib_handle_sdp_enumeration_done(chg,
4022 (bool)(stat & ENUMERATION_DONE_BIT));
4023
4024 smblib_handle_slow_plugin_timeout(chg,
4025 (bool)(stat & SLOW_PLUGIN_TIMEOUT_BIT));
4026
Harry Yangcdad2bf2016-10-04 17:03:56 -07004027 smblib_hvdcp_adaptive_voltage_change(chg);
4028
Nicholas Troast34db5032016-03-28 12:26:44 -07004029 power_supply_changed(chg->usb_psy);
4030
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08004031 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
4032 if (rc < 0) {
4033 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
4034 return IRQ_HANDLED;
4035 }
4036 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
4037
Nicholas Troast34db5032016-03-28 12:26:44 -07004038 return IRQ_HANDLED;
4039}
4040
Harry Yang29f23822017-09-09 00:09:36 -07004041static int typec_try_sink(struct smb_charger *chg)
4042{
4043 union power_supply_propval val;
4044 bool debounce_done, vbus_detected, sink;
4045 u8 stat;
4046 int exit_mode = ATTACHED_SRC, rc;
Abhijeet Dharmapurikarb0eb10d2017-11-13 18:42:40 -08004047 int typec_mode;
4048
4049 if (!(*chg->try_sink_enabled))
4050 return ATTACHED_SRC;
4051
4052 typec_mode = smblib_get_prop_typec_mode(chg);
4053 if (typec_mode == POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER
4054 || typec_mode == POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY)
4055 return ATTACHED_SRC;
4056
4057 /*
4058 * Try.SNK entry status - ATTACHWAIT.SRC state and detected Rd-open
4059 * or RD-Ra for TccDebounce time.
4060 */
Harry Yang29f23822017-09-09 00:09:36 -07004061
4062 /* ignore typec interrupt while try.snk WIP */
4063 chg->try_sink_active = true;
4064
4065 /* force SNK mode */
4066 val.intval = POWER_SUPPLY_TYPEC_PR_SINK;
4067 rc = smblib_set_prop_typec_power_role(chg, &val);
4068 if (rc < 0) {
4069 smblib_err(chg, "Couldn't set UFP mode rc=%d\n", rc);
4070 goto try_sink_exit;
4071 }
4072
4073 /* reduce Tccdebounce time to ~20ms */
4074 rc = smblib_masked_write(chg, MISC_CFG_REG,
4075 TCC_DEBOUNCE_20MS_BIT, TCC_DEBOUNCE_20MS_BIT);
4076 if (rc < 0) {
4077 smblib_err(chg, "Couldn't set MISC_CFG_REG rc=%d\n", rc);
4078 goto try_sink_exit;
4079 }
4080
4081 /*
4082 * give opportunity to the other side to be a SRC,
4083 * for tDRPTRY + Tccdebounce time
4084 */
Harry Yang692cec42017-10-16 16:21:19 -07004085 msleep(120);
Harry Yang29f23822017-09-09 00:09:36 -07004086
4087 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
4088 if (rc < 0) {
4089 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
4090 rc);
4091 goto try_sink_exit;
4092 }
4093
4094 debounce_done = stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT;
4095
4096 if (!debounce_done)
4097 /*
4098 * The other side didn't switch to source, either it
4099 * is an adamant sink or is removed go back to showing Rp
4100 */
4101 goto try_wait_src;
4102
4103 /*
4104 * We are in force sink mode and the other side has switched to
4105 * showing Rp. Config DRP in case the other side removes Rp so we
4106 * can quickly (20ms) switch to showing our Rp. Note that the spec
4107 * needs us to show Rp for 80mS while the drp DFP residency is just
4108 * 54mS. But 54mS is plenty time for us to react and force Rp for
4109 * the remaining 26mS.
4110 */
4111 val.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
4112 rc = smblib_set_prop_typec_power_role(chg, &val);
4113 if (rc < 0) {
4114 smblib_err(chg, "Couldn't set DFP mode rc=%d\n",
4115 rc);
4116 goto try_sink_exit;
4117 }
4118
4119 /*
4120 * while other side is Rp, wait for VBUS from it; exit if other side
4121 * removes Rp
4122 */
4123 do {
4124 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
4125 if (rc < 0) {
4126 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
4127 rc);
4128 goto try_sink_exit;
4129 }
4130
4131 debounce_done = stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT;
4132 vbus_detected = stat & TYPEC_VBUS_STATUS_BIT;
4133
4134 /* Successfully transitioned to ATTACHED.SNK */
4135 if (vbus_detected && debounce_done) {
4136 exit_mode = ATTACHED_SINK;
4137 goto try_sink_exit;
4138 }
4139
4140 /*
4141 * Ensure sink since drp may put us in source if other
4142 * side switches back to Rd
4143 */
4144 sink = !(stat & UFP_DFP_MODE_STATUS_BIT);
4145
4146 usleep_range(1000, 2000);
4147 } while (debounce_done && sink);
4148
4149try_wait_src:
4150 /*
4151 * Transition to trywait.SRC state. check if other side still wants
4152 * to be SNK or has been removed.
4153 */
4154 val.intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
4155 rc = smblib_set_prop_typec_power_role(chg, &val);
4156 if (rc < 0) {
4157 smblib_err(chg, "Couldn't set UFP mode rc=%d\n", rc);
4158 goto try_sink_exit;
4159 }
4160
4161 /* Need to be in this state for tDRPTRY time, 75ms~150ms */
4162 msleep(80);
4163
4164 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
4165 if (rc < 0) {
4166 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
4167 goto try_sink_exit;
4168 }
4169
4170 debounce_done = stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT;
4171
4172 if (debounce_done)
4173 /* the other side wants to be a sink */
4174 exit_mode = ATTACHED_SRC;
4175 else
4176 /* the other side is detached */
4177 exit_mode = UNATTACHED_SINK;
4178
4179try_sink_exit:
4180 /* release forcing of SRC/SNK mode */
4181 val.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
4182 rc = smblib_set_prop_typec_power_role(chg, &val);
4183 if (rc < 0)
4184 smblib_err(chg, "Couldn't set DFP mode rc=%d\n", rc);
4185
4186 /* revert Tccdebounce time back to ~120ms */
4187 rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT, 0);
4188 if (rc < 0)
4189 smblib_err(chg, "Couldn't set MISC_CFG_REG rc=%d\n", rc);
4190
4191 chg->try_sink_active = false;
4192
4193 return exit_mode;
4194}
4195
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004196static void typec_sink_insertion(struct smb_charger *chg)
4197{
Harry Yang29f23822017-09-09 00:09:36 -07004198 int exit_mode;
Abhijeet Dharmapurikarb0eb10d2017-11-13 18:42:40 -08004199 int typec_mode;
Harry Yang29f23822017-09-09 00:09:36 -07004200
Abhijeet Dharmapurikarb0eb10d2017-11-13 18:42:40 -08004201 exit_mode = typec_try_sink(chg);
Harry Yang29f23822017-09-09 00:09:36 -07004202
Abhijeet Dharmapurikarb0eb10d2017-11-13 18:42:40 -08004203 if (exit_mode != ATTACHED_SRC) {
4204 smblib_usb_typec_change(chg);
4205 return;
Harry Yang29f23822017-09-09 00:09:36 -07004206 }
4207
Abhijeet Dharmapurikarb0eb10d2017-11-13 18:42:40 -08004208 typec_mode = smblib_get_prop_typec_mode(chg);
4209 if (typec_mode == POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER)
4210 chg->is_audio_adapter = true;
4211
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004212 /* when a sink is inserted we should not wait on hvdcp timeout to
4213 * enable pd
4214 */
4215 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
4216 false, 0);
Ankit Sharmade321e12017-09-01 20:17:45 +05304217 if (chg->use_extcon) {
4218 smblib_notify_usb_host(chg, true);
4219 chg->otg_present = true;
4220 }
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004221}
Nicholas Troast34db5032016-03-28 12:26:44 -07004222
Harry Yangd89ff1f2016-12-05 14:59:11 -08004223static void typec_sink_removal(struct smb_charger *chg)
4224{
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05304225 smblib_set_charge_param(chg, &chg->param.freq_boost,
4226 chg->chg_freq.freq_above_otg_threshold);
Harry Yangd89ff1f2016-12-05 14:59:11 -08004227 chg->boost_current_ua = 0;
4228}
4229
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004230static void smblib_handle_typec_removal(struct smb_charger *chg)
4231{
Nicholas Troastfe74c592017-03-14 09:20:55 -07004232 int rc;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304233 struct smb_irq_data *data;
4234 struct storm_watch *wdata;
Tirupathi Reddy0c5d0a52017-09-27 16:31:07 +05304235 union power_supply_propval val;
Nicholas Troastfe74c592017-03-14 09:20:55 -07004236
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004237 chg->cc2_detach_wa_active = false;
4238
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05304239 rc = smblib_request_dpdm(chg, false);
4240 if (rc < 0)
4241 smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05304242
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304243 if (chg->wa_flags & BOOST_BACK_WA) {
4244 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
4245 if (data) {
4246 wdata = &data->storm_data;
4247 update_storm_count(wdata, WEAK_CHG_STORM_COUNT);
4248 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
4249 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
4250 false, 0);
4251 }
4252 }
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05304253
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004254 /* reset APSD voters */
4255 vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, false, 0);
4256 vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304257
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004258 cancel_delayed_work_sync(&chg->pl_enable_work);
4259 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
4260
4261 /* reset input current limit voters */
4262 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
4263 vote(chg->usb_icl_votable, PD_VOTER, false, 0);
4264 vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
4265 vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
4266 vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
Ashay Jaiswalae23a042017-05-18 15:28:31 +05304267 vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
Abhijeet Dharmapurikar66d2c442017-07-12 11:55:36 -07004268 vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
Harry Yangfeb95002017-10-06 12:11:42 -07004269 vote(chg->usb_icl_votable, CTM_VOTER, false, 0);
Ashay Jaiswal1c360c82018-03-15 23:24:42 +05304270 vote(chg->usb_icl_votable, HVDCP2_ICL_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004271
4272 /* reset hvdcp voters */
4273 vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, true, 0);
4274 vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER, true, 0);
Umang Agrawal49680b62018-04-16 14:41:11 +05304275 vote(chg->hvdcp_hw_inov_dis_votable, OV_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004276
4277 /* reset power delivery voters */
4278 vote(chg->pd_allowed_votable, PD_VOTER, false, 0);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004279 vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0);
4280 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER, true, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004281
4282 /* reset usb irq voters */
Harry Yang4bf7d962017-03-13 16:51:43 -07004283 vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
4284 vote(chg->usb_irq_enable_votable, QC_VOTER, false, 0);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004285
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004286 /* reset parallel voters */
4287 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
Abhijeet Dharmapurikar004f7ba2017-09-26 16:23:51 -07004288 vote(chg->pl_disable_votable, PL_FCC_LOW_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004289 vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
4290 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
4291 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
Harry Yang1d1034c2016-06-15 12:09:42 -07004292
Ashay Jaiswal3d22f4b2017-11-15 18:09:19 +05304293 vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0);
Nicholas Troast8995a702016-12-05 10:22:22 -08004294 chg->vconn_attempts = 0;
4295 chg->otg_attempts = 0;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05304296 chg->pulse_cnt = 0;
4297 chg->usb_icl_delta_ua = 0;
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004298 chg->voltage_min_uv = MICRO_5V;
4299 chg->voltage_max_uv = MICRO_5V;
4300 chg->pd_active = 0;
4301 chg->pd_hard_reset = 0;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004302 chg->typec_legacy_valid = false;
Harry Yang3b113a52016-12-08 12:37:40 -08004303
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05304304 /* write back the default FLOAT charger configuration */
4305 rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
4306 (u8)FLOAT_OPTIONS_MASK, chg->float_cfg);
4307 if (rc < 0)
4308 smblib_err(chg, "Couldn't write float charger options rc=%d\n",
4309 rc);
4310
Abhijeet Dharmapurikar676bd792017-05-31 16:21:57 -07004311 /* reset back to 120mS tCC debounce */
4312 rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT, 0);
4313 if (rc < 0)
4314 smblib_err(chg, "Couldn't set 120mS tCC debounce rc=%d\n", rc);
4315
Harry Yang3d515b82018-04-06 16:01:04 -07004316 /* if non-compliant charger caused UV, restore original max pulses */
4317 if (chg->non_compliant_chg_detected) {
4318 rc = smblib_masked_write(chg, HVDCP_PULSE_COUNT_MAX_REG,
4319 HVDCP_PULSE_COUNT_MAX_QC2_MASK,
4320 chg->qc2_max_pulses);
4321 if (rc < 0)
4322 smblib_err(chg, "Couldn't restore max pulses rc=%d\n",
4323 rc);
4324 chg->non_compliant_chg_detected = false;
4325 }
4326
Nicholas Troastfe74c592017-03-14 09:20:55 -07004327 /* enable APSD CC trigger for next insertion */
4328 rc = smblib_masked_write(chg, TYPE_C_CFG_REG,
4329 APSD_START_ON_CC_BIT, APSD_START_ON_CC_BIT);
4330 if (rc < 0)
4331 smblib_err(chg, "Couldn't enable APSD_START_ON_CC rc=%d\n", rc);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08004332
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004333 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
4334 /* re-enable AUTH_IRQ_EN_CFG_BIT */
4335 rc = smblib_masked_write(chg,
4336 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
4337 AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
4338 if (rc < 0)
4339 smblib_err(chg,
4340 "Couldn't enable QC auth setting rc=%d\n", rc);
4341 }
4342
4343 /* reconfigure allowed voltage for HVDCP */
4344 rc = smblib_set_adapter_allowance(chg,
4345 USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
4346 if (rc < 0)
4347 smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
4348 rc);
4349
Abhijeet Dharmapurikarb0eb10d2017-11-13 18:42:40 -08004350 if (chg->is_audio_adapter == true)
4351 /* wait for the audio driver to lower its en gpio */
4352 msleep(*chg->audio_headset_drp_wait_ms);
4353
4354 chg->is_audio_adapter = false;
4355
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004356 /* enable DRP */
Tirupathi Reddy0c5d0a52017-09-27 16:31:07 +05304357 val.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
4358 rc = smblib_set_prop_typec_power_role(chg, &val);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004359 if (rc < 0)
4360 smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc);
4361
4362 /* HW controlled CC_OUT */
4363 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
4364 TYPEC_SPARE_CFG_BIT, 0);
4365 if (rc < 0)
4366 smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n", rc);
4367
Umang Agrawalbed5d982018-04-17 20:16:01 +05304368 /* restore crude sensor if PM660/PMI8998 */
4369 if (chg->wa_flags & TYPEC_PBS_WA_BIT) {
4370 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
4371 if (rc < 0)
4372 smblib_err(chg, "Couldn't restore crude sensor rc=%d\n",
4373 rc);
4374 }
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004375
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004376 mutex_lock(&chg->vconn_oc_lock);
4377 if (!chg->vconn_en)
4378 goto unlock;
4379
4380 smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4381 VCONN_EN_VALUE_BIT, 0);
4382 chg->vconn_en = false;
4383
4384unlock:
4385 mutex_unlock(&chg->vconn_oc_lock);
4386
Abhijeet Dharmapurikar319d6942017-06-05 17:14:17 -07004387 /* clear exit sink based on cc */
4388 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4389 EXIT_SNK_BASED_ON_CC_BIT, 0);
4390 if (rc < 0)
4391 smblib_err(chg, "Couldn't clear exit_sink_based_on_cc rc=%d\n",
4392 rc);
4393
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08004394 typec_sink_removal(chg);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004395 smblib_update_usb_type(chg);
Ankit Sharmade321e12017-09-01 20:17:45 +05304396
4397 if (chg->use_extcon) {
4398 if (chg->otg_present)
4399 smblib_notify_usb_host(chg, false);
4400 else
4401 smblib_notify_device_mode(chg, false);
4402 }
4403 chg->otg_present = false;
Nicholas Troast34db5032016-03-28 12:26:44 -07004404}
4405
Nicholas Troaste1932e42017-04-12 12:38:18 -07004406static void smblib_handle_typec_insertion(struct smb_charger *chg)
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07004407{
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004408 int rc;
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07004409
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004410 vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, false, 0);
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07004411
Nicholas Troastfe74c592017-03-14 09:20:55 -07004412 /* disable APSD CC trigger since CC is attached */
4413 rc = smblib_masked_write(chg, TYPE_C_CFG_REG, APSD_START_ON_CC_BIT, 0);
4414 if (rc < 0)
4415 smblib_err(chg, "Couldn't disable APSD_START_ON_CC rc=%d\n",
4416 rc);
4417
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05304418 if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT) {
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004419 typec_sink_insertion(chg);
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05304420 } else {
4421 rc = smblib_request_dpdm(chg, true);
4422 if (rc < 0)
4423 smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
Harry Yangd89ff1f2016-12-05 14:59:11 -08004424 typec_sink_removal(chg);
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05304425 }
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07004426}
4427
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05304428static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode)
4429{
4430 int rp_ua;
4431 const struct apsd_result *apsd = smblib_get_apsd_result(chg);
4432
4433 if ((apsd->pst != POWER_SUPPLY_TYPE_USB_DCP)
4434 && (apsd->pst != POWER_SUPPLY_TYPE_USB_FLOAT))
4435 return;
4436
4437 /*
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05304438 * if APSD indicates FLOAT and the USB stack had detected SDP,
4439 * do not respond to Rp changes as we do not confirm that its
4440 * a legacy cable
4441 */
4442 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
4443 return;
4444 /*
4445 * We want the ICL vote @ 100mA for a FLOAT charger
4446 * until the detection by the USB stack is complete.
4447 * Ignore the Rp changes unless there is a
4448 * pre-existing valid vote.
4449 */
4450 if (apsd->pst == POWER_SUPPLY_TYPE_USB_FLOAT &&
4451 get_client_vote(chg->usb_icl_votable,
4452 LEGACY_UNKNOWN_VOTER) <= 100000)
4453 return;
4454
4455 /*
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05304456 * handle Rp change for DCP/FLOAT/OCP.
4457 * Update the current only if the Rp is different from
4458 * the last Rp value.
4459 */
4460 smblib_dbg(chg, PR_MISC, "CC change old_mode=%d new_mode=%d\n",
4461 chg->typec_mode, typec_mode);
4462
4463 rp_ua = get_rp_based_dcp_current(chg, typec_mode);
4464 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua);
4465}
4466
Nicholas Troaste1932e42017-04-12 12:38:18 -07004467static void smblib_handle_typec_cc_state_change(struct smb_charger *chg)
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004468{
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05304469 int typec_mode;
4470
Nicholas Troaste1932e42017-04-12 12:38:18 -07004471 if (chg->pr_swap_in_progress)
4472 return;
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004473
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05304474 typec_mode = smblib_get_prop_typec_mode(chg);
4475 if (chg->typec_present && (typec_mode != chg->typec_mode))
4476 smblib_handle_rp_change(chg, typec_mode);
4477
4478 chg->typec_mode = typec_mode;
4479
Nicholas Troaste1932e42017-04-12 12:38:18 -07004480 if (!chg->typec_present && chg->typec_mode != POWER_SUPPLY_TYPEC_NONE) {
4481 chg->typec_present = true;
4482 smblib_dbg(chg, PR_MISC, "TypeC %s insertion\n",
4483 smblib_typec_mode_name[chg->typec_mode]);
4484 smblib_handle_typec_insertion(chg);
4485 } else if (chg->typec_present &&
4486 chg->typec_mode == POWER_SUPPLY_TYPEC_NONE) {
4487 chg->typec_present = false;
4488 smblib_dbg(chg, PR_MISC, "TypeC removal\n");
4489 smblib_handle_typec_removal(chg);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004490 }
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004491
Abhijeet Dharmapurikar66d2c442017-07-12 11:55:36 -07004492 /* suspend usb if sink */
Harry Yangca0664e2017-08-18 11:40:06 -07004493 if ((chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
4494 && chg->typec_present)
Abhijeet Dharmapurikar66d2c442017-07-12 11:55:36 -07004495 vote(chg->usb_icl_votable, OTG_VOTER, true, 0);
4496 else
4497 vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
4498
Nicholas Troaste1932e42017-04-12 12:38:18 -07004499 smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n",
4500 smblib_typec_mode_name[chg->typec_mode]);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004501}
4502
Harry Yang29f23822017-09-09 00:09:36 -07004503void smblib_usb_typec_change(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07004504{
Nicholas Troast34db5032016-03-28 12:26:44 -07004505 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07004506
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07004507 rc = smblib_multibyte_read(chg, TYPE_C_STATUS_1_REG,
4508 chg->typec_status, 5);
Nicholas Troast34db5032016-03-28 12:26:44 -07004509 if (rc < 0) {
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07004510 smblib_err(chg, "Couldn't cache USB Type-C status rc=%d\n", rc);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004511 return;
Nicholas Troast34db5032016-03-28 12:26:44 -07004512 }
Nicholas Troast34db5032016-03-28 12:26:44 -07004513
Nicholas Troaste1932e42017-04-12 12:38:18 -07004514 smblib_handle_typec_cc_state_change(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07004515
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07004516 if (chg->typec_status[3] & TYPEC_VBUS_ERROR_STATUS_BIT)
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004517 smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n");
Harry Yangd757c0f2016-09-23 10:52:05 -07004518
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07004519 if (chg->typec_status[3] & TYPEC_VCONN_OVERCURR_STATUS_BIT)
Nicholas Troastb11015f2017-01-17 17:56:45 -08004520 schedule_work(&chg->vconn_oc_work);
Nicholas Troast8995a702016-12-05 10:22:22 -08004521
Nicholas Troastb1486552016-11-10 08:20:11 -08004522 power_supply_changed(chg->usb_psy);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004523}
4524
4525irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
4526{
4527 struct smb_irq_data *irq_data = data;
4528 struct smb_charger *chg = irq_data->parent_data;
4529
Ashay Jaiswal0ce2c7c2017-11-14 12:29:02 +05304530 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) {
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05304531 cancel_delayed_work_sync(&chg->uusb_otg_work);
4532 vote(chg->awake_votable, OTG_DELAY_VOTER, true, 0);
4533 smblib_dbg(chg, PR_INTERRUPT, "Scheduling OTG work\n");
4534 schedule_delayed_work(&chg->uusb_otg_work,
4535 msecs_to_jiffies(chg->otg_delay_ms));
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004536 return IRQ_HANDLED;
4537 }
4538
Harry Yang29f23822017-09-09 00:09:36 -07004539 if (chg->cc2_detach_wa_active || chg->typec_en_dis_active ||
4540 chg->try_sink_active) {
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07004541 smblib_dbg(chg, PR_MISC | PR_INTERRUPT, "Ignoring since %s active\n",
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004542 chg->cc2_detach_wa_active ?
4543 "cc2_detach_wa" : "typec_en_dis");
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004544 return IRQ_HANDLED;
4545 }
4546
Abhijeet Dharmapurikar049b2552017-07-12 11:27:51 -07004547 if (chg->pr_swap_in_progress) {
4548 smblib_dbg(chg, PR_INTERRUPT,
4549 "Ignoring since pr_swap_in_progress\n");
4550 return IRQ_HANDLED;
4551 }
4552
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004553 mutex_lock(&chg->lock);
4554 smblib_usb_typec_change(chg);
4555 mutex_unlock(&chg->lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07004556 return IRQ_HANDLED;
4557}
4558
Abhijeet Dharmapurikar23916642016-10-03 10:38:50 -07004559irqreturn_t smblib_handle_dc_plugin(int irq, void *data)
4560{
4561 struct smb_irq_data *irq_data = data;
4562 struct smb_charger *chg = irq_data->parent_data;
4563
4564 power_supply_changed(chg->dc_psy);
4565 return IRQ_HANDLED;
4566}
4567
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004568irqreturn_t smblib_handle_high_duty_cycle(int irq, void *data)
4569{
4570 struct smb_irq_data *irq_data = data;
4571 struct smb_charger *chg = irq_data->parent_data;
4572
4573 chg->is_hdc = true;
Fenglin Wu4f4dcc12017-08-24 14:28:54 +08004574 /*
4575 * Disable usb IRQs after the flag set and re-enable IRQs after
4576 * the flag cleared in the delayed work queue, to avoid any IRQ
4577 * storming during the delays
4578 */
4579 if (chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq)
4580 disable_irq_nosync(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
4581
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004582 schedule_delayed_work(&chg->clear_hdc_work, msecs_to_jiffies(60));
4583
4584 return IRQ_HANDLED;
4585}
4586
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05304587static void smblib_bb_removal_work(struct work_struct *work)
4588{
4589 struct smb_charger *chg = container_of(work, struct smb_charger,
4590 bb_removal_work.work);
4591
4592 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
4593 vote(chg->awake_votable, BOOST_BACK_VOTER, false, 0);
4594}
4595
4596#define BOOST_BACK_UNVOTE_DELAY_MS 750
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304597#define BOOST_BACK_STORM_COUNT 3
4598#define WEAK_CHG_STORM_COUNT 8
Nicholas Troastabedaf72016-09-16 11:07:45 -07004599irqreturn_t smblib_handle_switcher_power_ok(int irq, void *data)
4600{
4601 struct smb_irq_data *irq_data = data;
4602 struct smb_charger *chg = irq_data->parent_data;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304603 struct storm_watch *wdata = &irq_data->storm_data;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004604 int rc, usb_icl;
Nicholas Troastabedaf72016-09-16 11:07:45 -07004605 u8 stat;
4606
4607 if (!(chg->wa_flags & BOOST_BACK_WA))
4608 return IRQ_HANDLED;
4609
4610 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
4611 if (rc < 0) {
4612 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n", rc);
4613 return IRQ_HANDLED;
4614 }
4615
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004616 /* skip suspending input if its already suspended by some other voter */
4617 usb_icl = get_effective_result(chg->usb_icl_votable);
Harry Yang379484a2017-08-29 10:26:14 -07004618 if ((stat & USE_USBIN_BIT) && usb_icl >= 0 && usb_icl <= USBIN_25MA)
Nicholas Troastabedaf72016-09-16 11:07:45 -07004619 return IRQ_HANDLED;
4620
Abhijeet Dharmapurikar2823fe32016-12-05 17:52:11 -08004621 if (stat & USE_DCIN_BIT)
Nicholas Troastabedaf72016-09-16 11:07:45 -07004622 return IRQ_HANDLED;
4623
4624 if (is_storming(&irq_data->storm_data)) {
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304625 /* This could be a weak charger reduce ICL */
4626 if (!is_client_vote_enabled(chg->usb_icl_votable,
4627 WEAK_CHARGER_VOTER)) {
4628 smblib_err(chg,
4629 "Weak charger detected: voting %dmA ICL\n",
4630 *chg->weak_chg_icl_ua / 1000);
4631 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
4632 true, *chg->weak_chg_icl_ua);
4633 /*
4634 * reset storm data and set the storm threshold
4635 * to 3 for reverse boost detection.
4636 */
4637 update_storm_count(wdata, BOOST_BACK_STORM_COUNT);
4638 } else {
4639 smblib_err(chg,
4640 "Reverse boost detected: voting 0mA to suspend input\n");
4641 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, true, 0);
4642 vote(chg->awake_votable, BOOST_BACK_VOTER, true, 0);
4643 /*
4644 * Remove the boost-back vote after a delay, to avoid
4645 * permanently suspending the input if the boost-back
4646 * condition is unintentionally hit.
4647 */
4648 schedule_delayed_work(&chg->bb_removal_work,
4649 msecs_to_jiffies(BOOST_BACK_UNVOTE_DELAY_MS));
4650 }
Nicholas Troastabedaf72016-09-16 11:07:45 -07004651 }
4652
4653 return IRQ_HANDLED;
4654}
4655
Nicholas Troast15dc0c82016-10-18 15:15:21 -07004656irqreturn_t smblib_handle_wdog_bark(int irq, void *data)
4657{
4658 struct smb_irq_data *irq_data = data;
4659 struct smb_charger *chg = irq_data->parent_data;
4660 int rc;
4661
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05304662 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
4663
Nicholas Troast15dc0c82016-10-18 15:15:21 -07004664 rc = smblib_write(chg, BARK_BITE_WDOG_PET_REG, BARK_BITE_WDOG_PET_BIT);
4665 if (rc < 0)
4666 smblib_err(chg, "Couldn't pet the dog rc=%d\n", rc);
4667
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +05304668 if (chg->step_chg_enabled || chg->sw_jeita_enabled)
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05304669 power_supply_changed(chg->batt_psy);
4670
Nicholas Troast15dc0c82016-10-18 15:15:21 -07004671 return IRQ_HANDLED;
4672}
4673
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004674/**************
4675 * Additional USB PSY getters/setters
4676 * that call interrupt functions
4677 ***************/
4678
4679int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg,
4680 union power_supply_propval *val)
4681{
4682 val->intval = chg->pr_swap_in_progress;
4683 return 0;
4684}
4685
4686int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg,
4687 const union power_supply_propval *val)
4688{
Abhijeet Dharmapurikar676bd792017-05-31 16:21:57 -07004689 int rc;
4690
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004691 chg->pr_swap_in_progress = val->intval;
4692 /*
4693 * call the cc changed irq to handle real removals while
4694 * PR_SWAP was in progress
4695 */
4696 smblib_usb_typec_change(chg);
Abhijeet Dharmapurikar676bd792017-05-31 16:21:57 -07004697 rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT,
4698 val->intval ? TCC_DEBOUNCE_20MS_BIT : 0);
4699 if (rc < 0)
4700 smblib_err(chg, "Couldn't set tCC debounce rc=%d\n", rc);
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004701 return 0;
4702}
4703
Nicholas Troast34db5032016-03-28 12:26:44 -07004704/***************
4705 * Work Queues *
4706 ***************/
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05304707static void smblib_uusb_otg_work(struct work_struct *work)
4708{
4709 struct smb_charger *chg = container_of(work, struct smb_charger,
4710 uusb_otg_work.work);
4711 int rc;
4712 u8 stat;
4713 bool otg;
4714
4715 rc = smblib_read(chg, TYPE_C_STATUS_3_REG, &stat);
4716 if (rc < 0) {
4717 smblib_err(chg, "Couldn't read TYPE_C_STATUS_3 rc=%d\n", rc);
4718 goto out;
4719 }
4720
4721 otg = !!(stat & (U_USB_GND_NOVBUS_BIT | U_USB_GND_BIT));
4722 extcon_set_cable_state_(chg->extcon, EXTCON_USB_HOST, otg);
4723 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_3 = 0x%02x OTG=%d\n",
4724 stat, otg);
4725 power_supply_changed(chg->usb_psy);
4726
4727out:
4728 vote(chg->awake_votable, OTG_DELAY_VOTER, false, 0);
4729}
4730
Nicholas Troast34db5032016-03-28 12:26:44 -07004731
4732static void smblib_hvdcp_detect_work(struct work_struct *work)
4733{
4734 struct smb_charger *chg = container_of(work, struct smb_charger,
4735 hvdcp_detect_work.work);
Nicholas Troast34db5032016-03-28 12:26:44 -07004736
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07004737 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
4738 false, 0);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004739 power_supply_changed(chg->usb_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07004740}
4741
Harry Yangfe913842016-08-10 12:27:28 -07004742static void bms_update_work(struct work_struct *work)
Harry Yang5e1a5222016-07-26 15:16:04 -07004743{
4744 struct smb_charger *chg = container_of(work, struct smb_charger,
4745 bms_update_work);
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05304746
4747 smblib_suspend_on_debug_battery(chg);
4748
4749 if (chg->batt_psy)
4750 power_supply_changed(chg->batt_psy);
Harry Yang5e1a5222016-07-26 15:16:04 -07004751}
4752
Harry Yang166b15d2017-08-28 13:00:40 -07004753static void pl_update_work(struct work_struct *work)
4754{
4755 struct smb_charger *chg = container_of(work, struct smb_charger,
4756 pl_update_work);
4757
4758 smblib_stat_sw_override_cfg(chg, false);
4759}
4760
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004761static void clear_hdc_work(struct work_struct *work)
4762{
4763 struct smb_charger *chg = container_of(work, struct smb_charger,
4764 clear_hdc_work.work);
4765
4766 chg->is_hdc = 0;
Fenglin Wu4f4dcc12017-08-24 14:28:54 +08004767 if (chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq)
4768 enable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004769}
4770
Harry Yang755a34b2016-11-01 01:18:51 -07004771static void rdstd_cc2_detach_work(struct work_struct *work)
4772{
4773 int rc;
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004774 u8 stat4, stat5;
Harry Yang755a34b2016-11-01 01:18:51 -07004775 struct smb_charger *chg = container_of(work, struct smb_charger,
4776 rdstd_cc2_detach_work);
4777
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004778 if (!chg->cc2_detach_wa_active)
4779 return;
4780
Harry Yang755a34b2016-11-01 01:18:51 -07004781 /*
4782 * WA steps -
4783 * 1. Enable both UFP and DFP, wait for 10ms.
4784 * 2. Disable DFP, wait for 30ms.
4785 * 3. Removal detected if both TYPEC_DEBOUNCE_DONE_STATUS
4786 * and TIMER_STAGE bits are gone, otherwise repeat all by
4787 * work rescheduling.
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004788 * Note, work will be cancelled when USB_PLUGIN rises.
Harry Yang755a34b2016-11-01 01:18:51 -07004789 */
4790
4791 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4792 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT,
4793 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT);
4794 if (rc < 0) {
4795 smblib_err(chg, "Couldn't write TYPE_C_CTRL_REG rc=%d\n", rc);
4796 return;
4797 }
4798
4799 usleep_range(10000, 11000);
4800
4801 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4802 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT,
4803 UFP_EN_CMD_BIT);
4804 if (rc < 0) {
4805 smblib_err(chg, "Couldn't write TYPE_C_CTRL_REG rc=%d\n", rc);
4806 return;
4807 }
4808
4809 usleep_range(30000, 31000);
4810
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004811 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
Harry Yang755a34b2016-11-01 01:18:51 -07004812 if (rc < 0) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004813 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
Harry Yang755a34b2016-11-01 01:18:51 -07004814 return;
4815 }
Harry Yang755a34b2016-11-01 01:18:51 -07004816
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004817 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
Harry Yang755a34b2016-11-01 01:18:51 -07004818 if (rc < 0) {
4819 smblib_err(chg,
4820 "Couldn't read TYPE_C_STATUS_5_REG rc=%d\n", rc);
4821 return;
4822 }
Harry Yang755a34b2016-11-01 01:18:51 -07004823
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004824 if ((stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT)
4825 || (stat5 & TIMER_STAGE_2_BIT)) {
4826 smblib_dbg(chg, PR_MISC, "rerunning DD=%d TS2BIT=%d\n",
4827 (int)(stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT),
4828 (int)(stat5 & TIMER_STAGE_2_BIT));
4829 goto rerun;
4830 }
4831
4832 smblib_dbg(chg, PR_MISC, "Bingo CC2 Removal detected\n");
4833 chg->cc2_detach_wa_active = false;
4834 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4835 EXIT_SNK_BASED_ON_CC_BIT, 0);
Harry Yang755a34b2016-11-01 01:18:51 -07004836 smblib_reg_block_restore(chg, cc2_detach_settings);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004837 mutex_lock(&chg->lock);
4838 smblib_usb_typec_change(chg);
4839 mutex_unlock(&chg->lock);
Harry Yang755a34b2016-11-01 01:18:51 -07004840 return;
4841
4842rerun:
4843 schedule_work(&chg->rdstd_cc2_detach_work);
4844}
4845
Nicholas Troastb11015f2017-01-17 17:56:45 -08004846static void smblib_otg_oc_exit(struct smb_charger *chg, bool success)
4847{
4848 int rc;
4849
4850 chg->otg_attempts = 0;
4851 if (!success) {
4852 smblib_err(chg, "OTG soft start failed\n");
4853 chg->otg_en = false;
4854 }
4855
4856 smblib_dbg(chg, PR_OTG, "enabling VBUS < 1V check\n");
4857 rc = smblib_masked_write(chg, OTG_CFG_REG,
4858 QUICKSTART_OTG_FASTROLESWAP_BIT, 0);
4859 if (rc < 0)
4860 smblib_err(chg, "Couldn't enable VBUS < 1V check rc=%d\n", rc);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004861}
4862
4863#define MAX_OC_FALLING_TRIES 10
4864static void smblib_otg_oc_work(struct work_struct *work)
4865{
4866 struct smb_charger *chg = container_of(work, struct smb_charger,
4867 otg_oc_work);
4868 int rc, i;
4869 u8 stat;
4870
4871 if (!chg->vbus_vreg || !chg->vbus_vreg->rdev)
4872 return;
4873
4874 smblib_err(chg, "over-current detected on VBUS\n");
4875 mutex_lock(&chg->otg_oc_lock);
4876 if (!chg->otg_en)
4877 goto unlock;
4878
4879 smblib_dbg(chg, PR_OTG, "disabling VBUS < 1V check\n");
4880 smblib_masked_write(chg, OTG_CFG_REG,
4881 QUICKSTART_OTG_FASTROLESWAP_BIT,
4882 QUICKSTART_OTG_FASTROLESWAP_BIT);
4883
4884 /*
4885 * If 500ms has passed and another over-current interrupt has not
4886 * triggered then it is likely that the software based soft start was
4887 * successful and the VBUS < 1V restriction should be re-enabled.
4888 */
4889 schedule_delayed_work(&chg->otg_ss_done_work, msecs_to_jiffies(500));
4890
4891 rc = _smblib_vbus_regulator_disable(chg->vbus_vreg->rdev);
4892 if (rc < 0) {
4893 smblib_err(chg, "Couldn't disable VBUS rc=%d\n", rc);
4894 goto unlock;
4895 }
4896
4897 if (++chg->otg_attempts > OTG_MAX_ATTEMPTS) {
4898 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4899 smblib_err(chg, "OTG failed to enable after %d attempts\n",
4900 chg->otg_attempts - 1);
4901 smblib_otg_oc_exit(chg, false);
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, OTG_BASE + INT_RT_STS_OFFSET, &stat);
4912 if (rc >= 0 && !(stat & OTG_OVERCURRENT_RT_STS_BIT))
4913 break;
4914 }
4915
4916 if (i >= MAX_OC_FALLING_TRIES) {
4917 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4918 smblib_err(chg, "OTG OC did not fall after %dms\n",
4919 2 * MAX_OC_FALLING_TRIES);
4920 smblib_otg_oc_exit(chg, false);
4921 goto unlock;
4922 }
4923
4924 smblib_dbg(chg, PR_OTG, "OTG OC fell after %dms\n", 2 * i + 1);
4925 rc = _smblib_vbus_regulator_enable(chg->vbus_vreg->rdev);
4926 if (rc < 0) {
4927 smblib_err(chg, "Couldn't enable VBUS rc=%d\n", rc);
4928 goto unlock;
4929 }
4930
4931unlock:
4932 mutex_unlock(&chg->otg_oc_lock);
4933}
4934
4935static void smblib_vconn_oc_work(struct work_struct *work)
4936{
4937 struct smb_charger *chg = container_of(work, struct smb_charger,
4938 vconn_oc_work);
4939 int rc, i;
4940 u8 stat;
4941
Ashay Jaiswal0ce2c7c2017-11-14 12:29:02 +05304942 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
Ashay Jaiswal15edce42017-03-31 23:29:58 +05304943 return;
4944
Nicholas Troastb11015f2017-01-17 17:56:45 -08004945 smblib_err(chg, "over-current detected on VCONN\n");
4946 if (!chg->vconn_vreg || !chg->vconn_vreg->rdev)
4947 return;
4948
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07004949 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004950 rc = _smblib_vconn_regulator_disable(chg->vconn_vreg->rdev);
4951 if (rc < 0) {
4952 smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc);
4953 goto unlock;
4954 }
4955
4956 if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
4957 smblib_err(chg, "VCONN failed to enable after %d attempts\n",
Guru Das Srinagesh2034dbe2018-02-27 11:16:08 -08004958 chg->vconn_attempts - 1);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004959 chg->vconn_en = false;
4960 chg->vconn_attempts = 0;
4961 goto unlock;
4962 }
4963
4964 /*
4965 * The real time status should go low within 10ms. Poll every 1-2ms to
4966 * minimize the delay when re-enabling OTG.
4967 */
4968 for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) {
4969 usleep_range(1000, 2000);
4970 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
4971 if (rc >= 0 && !(stat & TYPEC_VCONN_OVERCURR_STATUS_BIT))
4972 break;
4973 }
4974
4975 if (i >= MAX_OC_FALLING_TRIES) {
4976 smblib_err(chg, "VCONN OC did not fall after %dms\n",
4977 2 * MAX_OC_FALLING_TRIES);
4978 chg->vconn_en = false;
4979 chg->vconn_attempts = 0;
4980 goto unlock;
4981 }
Nicholas Troastb11015f2017-01-17 17:56:45 -08004982 smblib_dbg(chg, PR_OTG, "VCONN OC fell after %dms\n", 2 * i + 1);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004983
4984 rc = _smblib_vconn_regulator_enable(chg->vconn_vreg->rdev);
4985 if (rc < 0) {
4986 smblib_err(chg, "Couldn't enable VCONN rc=%d\n", rc);
4987 goto unlock;
4988 }
4989
4990unlock:
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07004991 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004992}
4993
4994static void smblib_otg_ss_done_work(struct work_struct *work)
4995{
4996 struct smb_charger *chg = container_of(work, struct smb_charger,
4997 otg_ss_done_work.work);
4998 int rc;
4999 bool success = false;
5000 u8 stat;
5001
5002 mutex_lock(&chg->otg_oc_lock);
5003 rc = smblib_read(chg, OTG_STATUS_REG, &stat);
5004 if (rc < 0)
5005 smblib_err(chg, "Couldn't read OTG status rc=%d\n", rc);
5006 else if (stat & BOOST_SOFTSTART_DONE_BIT)
5007 success = true;
5008
5009 smblib_otg_oc_exit(chg, success);
5010 mutex_unlock(&chg->otg_oc_lock);
5011}
5012
Ashay Jaiswal4d825782017-02-18 10:11:34 +05305013static void smblib_icl_change_work(struct work_struct *work)
5014{
5015 struct smb_charger *chg = container_of(work, struct smb_charger,
5016 icl_change_work.work);
5017 int rc, settled_ua;
5018
5019 rc = smblib_get_charge_param(chg, &chg->param.icl_stat, &settled_ua);
5020 if (rc < 0) {
5021 smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
5022 return;
5023 }
5024
5025 power_supply_changed(chg->usb_main_psy);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05305026
5027 smblib_dbg(chg, PR_INTERRUPT, "icl_settled=%d\n", settled_ua);
5028}
5029
Ashay Jaiswalc0361672017-03-21 12:24:16 +05305030static void smblib_pl_enable_work(struct work_struct *work)
5031{
5032 struct smb_charger *chg = container_of(work, struct smb_charger,
5033 pl_enable_work.work);
5034
5035 smblib_dbg(chg, PR_PARALLEL, "timer expired, enabling parallel\n");
5036 vote(chg->pl_disable_votable, PL_DELAY_VOTER, false, 0);
5037 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
5038}
5039
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07005040static void smblib_legacy_detection_work(struct work_struct *work)
5041{
5042 struct smb_charger *chg = container_of(work, struct smb_charger,
5043 legacy_detection_work);
5044 int rc;
5045 u8 stat;
5046 bool legacy, rp_high;
5047
5048 mutex_lock(&chg->lock);
5049 chg->typec_en_dis_active = 1;
5050 smblib_dbg(chg, PR_MISC, "running legacy unknown workaround\n");
5051 rc = smblib_masked_write(chg,
5052 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
5053 TYPEC_DISABLE_CMD_BIT,
5054 TYPEC_DISABLE_CMD_BIT);
5055 if (rc < 0)
5056 smblib_err(chg, "Couldn't disable type-c rc=%d\n", rc);
5057
5058 /* wait for the adapter to turn off VBUS */
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07005059 msleep(1000);
5060
5061 smblib_dbg(chg, PR_MISC, "legacy workaround enabling typec\n");
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07005062
5063 rc = smblib_masked_write(chg,
5064 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
5065 TYPEC_DISABLE_CMD_BIT, 0);
5066 if (rc < 0)
5067 smblib_err(chg, "Couldn't enable type-c rc=%d\n", rc);
5068
5069 /* wait for type-c detection to complete */
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07005070 msleep(400);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07005071
5072 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat);
5073 if (rc < 0) {
5074 smblib_err(chg, "Couldn't read typec stat5 rc = %d\n", rc);
5075 goto unlock;
5076 }
5077
5078 chg->typec_legacy_valid = true;
5079 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
5080 legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT;
Nicholas Troaste1932e42017-04-12 12:38:18 -07005081 rp_high = chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH;
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07005082 smblib_dbg(chg, PR_MISC, "legacy workaround done legacy = %d rp_high = %d\n",
5083 legacy, rp_high);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07005084 if (!legacy || !rp_high)
5085 vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
5086 false, 0);
5087
5088unlock:
5089 chg->typec_en_dis_active = 0;
Nicholas Troast6439e172017-06-02 14:45:39 -07005090 smblib_usb_typec_change(chg);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07005091 mutex_unlock(&chg->lock);
5092}
5093
Harry Yangba874ce2016-08-19 14:17:01 -07005094static int smblib_create_votables(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07005095{
5096 int rc = 0;
5097
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05305098 chg->fcc_votable = find_votable("FCC");
Harry Yang0c35ff62017-04-06 00:02:30 -07005099 if (chg->fcc_votable == NULL) {
5100 rc = -EINVAL;
5101 smblib_err(chg, "Couldn't find FCC votable rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05305102 return rc;
5103 }
5104
5105 chg->fv_votable = find_votable("FV");
Harry Yang0c35ff62017-04-06 00:02:30 -07005106 if (chg->fv_votable == NULL) {
5107 rc = -EINVAL;
5108 smblib_err(chg, "Couldn't find FV votable rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05305109 return rc;
5110 }
5111
Ashay Jaiswalae1586d2017-03-22 23:18:51 +05305112 chg->usb_icl_votable = find_votable("USB_ICL");
5113 if (!chg->usb_icl_votable) {
Harry Yang0c35ff62017-04-06 00:02:30 -07005114 rc = -EINVAL;
5115 smblib_err(chg, "Couldn't find USB_ICL votable rc=%d\n", rc);
Ashay Jaiswalae1586d2017-03-22 23:18:51 +05305116 return rc;
5117 }
5118
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05305119 chg->pl_disable_votable = find_votable("PL_DISABLE");
Harry Yang0c35ff62017-04-06 00:02:30 -07005120 if (chg->pl_disable_votable == NULL) {
5121 rc = -EINVAL;
5122 smblib_err(chg, "Couldn't find votable PL_DISABLE rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05305123 return rc;
5124 }
Abhijeet Dharmapurikar38ef1422017-05-18 15:37:56 -07005125
5126 chg->pl_enable_votable_indirect = find_votable("PL_ENABLE_INDIRECT");
5127 if (chg->pl_enable_votable_indirect == NULL) {
5128 rc = -EINVAL;
5129 smblib_err(chg,
5130 "Couldn't find votable PL_ENABLE_INDIRECT rc=%d\n",
5131 rc);
5132 return rc;
5133 }
5134
Ashay Jaiswalc0361672017-03-21 12:24:16 +05305135 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05305136
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07005137 chg->dc_suspend_votable = create_votable("DC_SUSPEND", VOTE_SET_ANY,
5138 smblib_dc_suspend_vote_callback,
5139 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07005140 if (IS_ERR(chg->dc_suspend_votable)) {
5141 rc = PTR_ERR(chg->dc_suspend_votable);
5142 return rc;
5143 }
5144
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07005145 chg->dc_icl_votable = create_votable("DC_ICL", VOTE_MIN,
5146 smblib_dc_icl_vote_callback,
5147 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07005148 if (IS_ERR(chg->dc_icl_votable)) {
5149 rc = PTR_ERR(chg->dc_icl_votable);
5150 return rc;
5151 }
5152
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07005153 chg->pd_disallowed_votable_indirect
5154 = create_votable("PD_DISALLOWED_INDIRECT", VOTE_SET_ANY,
5155 smblib_pd_disallowed_votable_indirect_callback, chg);
5156 if (IS_ERR(chg->pd_disallowed_votable_indirect)) {
5157 rc = PTR_ERR(chg->pd_disallowed_votable_indirect);
5158 return rc;
5159 }
5160
5161 chg->pd_allowed_votable = create_votable("PD_ALLOWED",
5162 VOTE_SET_ANY, NULL, NULL);
Nicholas Troast34db5032016-03-28 12:26:44 -07005163 if (IS_ERR(chg->pd_allowed_votable)) {
5164 rc = PTR_ERR(chg->pd_allowed_votable);
5165 return rc;
5166 }
5167
Harry Yang223c6282016-06-14 15:48:36 -07005168 chg->awake_votable = create_votable("AWAKE", VOTE_SET_ANY,
5169 smblib_awake_vote_callback,
5170 chg);
5171 if (IS_ERR(chg->awake_votable)) {
5172 rc = PTR_ERR(chg->awake_votable);
5173 return rc;
5174 }
5175
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07005176 chg->chg_disable_votable = create_votable("CHG_DISABLE", VOTE_SET_ANY,
5177 smblib_chg_disable_vote_callback,
5178 chg);
5179 if (IS_ERR(chg->chg_disable_votable)) {
5180 rc = PTR_ERR(chg->chg_disable_votable);
5181 return rc;
5182 }
5183
Harry Yangaba1f5f2016-09-28 10:47:29 -07005184
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05305185 chg->hvdcp_disable_votable_indirect = create_votable(
5186 "HVDCP_DISABLE_INDIRECT",
5187 VOTE_SET_ANY,
5188 smblib_hvdcp_disable_indirect_vote_callback,
5189 chg);
5190 if (IS_ERR(chg->hvdcp_disable_votable_indirect)) {
5191 rc = PTR_ERR(chg->hvdcp_disable_votable_indirect);
5192 return rc;
5193 }
5194
5195 chg->hvdcp_enable_votable = create_votable("HVDCP_ENABLE",
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07005196 VOTE_SET_ANY,
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05305197 smblib_hvdcp_enable_vote_callback,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07005198 chg);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05305199 if (IS_ERR(chg->hvdcp_enable_votable)) {
5200 rc = PTR_ERR(chg->hvdcp_enable_votable);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07005201 return rc;
5202 }
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07005203
5204 chg->apsd_disable_votable = create_votable("APSD_DISABLE",
5205 VOTE_SET_ANY,
5206 smblib_apsd_disable_vote_callback,
5207 chg);
5208 if (IS_ERR(chg->apsd_disable_votable)) {
5209 rc = PTR_ERR(chg->apsd_disable_votable);
5210 return rc;
5211 }
5212
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05305213 chg->hvdcp_hw_inov_dis_votable = create_votable("HVDCP_HW_INOV_DIS",
5214 VOTE_SET_ANY,
5215 smblib_hvdcp_hw_inov_dis_vote_callback,
5216 chg);
5217 if (IS_ERR(chg->hvdcp_hw_inov_dis_votable)) {
5218 rc = PTR_ERR(chg->hvdcp_hw_inov_dis_votable);
5219 return rc;
5220 }
5221
Harry Yang4bf7d962017-03-13 16:51:43 -07005222 chg->usb_irq_enable_votable = create_votable("USB_IRQ_DISABLE",
5223 VOTE_SET_ANY,
5224 smblib_usb_irq_enable_vote_callback,
5225 chg);
5226 if (IS_ERR(chg->usb_irq_enable_votable)) {
5227 rc = PTR_ERR(chg->usb_irq_enable_votable);
5228 return rc;
5229 }
5230
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07005231 chg->typec_irq_disable_votable = create_votable("TYPEC_IRQ_DISABLE",
5232 VOTE_SET_ANY,
5233 smblib_typec_irq_disable_vote_callback,
5234 chg);
5235 if (IS_ERR(chg->typec_irq_disable_votable)) {
5236 rc = PTR_ERR(chg->typec_irq_disable_votable);
5237 return rc;
5238 }
5239
Tirupathi Reddy0c5d0a52017-09-27 16:31:07 +05305240 chg->disable_power_role_switch
5241 = create_votable("DISABLE_POWER_ROLE_SWITCH",
5242 VOTE_SET_ANY,
5243 smblib_disable_power_role_switch_callback,
5244 chg);
5245 if (IS_ERR(chg->disable_power_role_switch)) {
5246 rc = PTR_ERR(chg->disable_power_role_switch);
5247 return rc;
5248 }
5249
Nicholas Troast320839e2016-06-03 10:18:00 -07005250 return rc;
5251}
5252
Harry Yangba874ce2016-08-19 14:17:01 -07005253static void smblib_destroy_votables(struct smb_charger *chg)
5254{
Harry Yangba874ce2016-08-19 14:17:01 -07005255 if (chg->dc_suspend_votable)
5256 destroy_votable(chg->dc_suspend_votable);
Harry Yangba874ce2016-08-19 14:17:01 -07005257 if (chg->usb_icl_votable)
5258 destroy_votable(chg->usb_icl_votable);
5259 if (chg->dc_icl_votable)
5260 destroy_votable(chg->dc_icl_votable);
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07005261 if (chg->pd_disallowed_votable_indirect)
5262 destroy_votable(chg->pd_disallowed_votable_indirect);
Harry Yangba874ce2016-08-19 14:17:01 -07005263 if (chg->pd_allowed_votable)
5264 destroy_votable(chg->pd_allowed_votable);
5265 if (chg->awake_votable)
5266 destroy_votable(chg->awake_votable);
Harry Yangaba1f5f2016-09-28 10:47:29 -07005267 if (chg->chg_disable_votable)
5268 destroy_votable(chg->chg_disable_votable);
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07005269 if (chg->apsd_disable_votable)
5270 destroy_votable(chg->apsd_disable_votable);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05305271 if (chg->hvdcp_hw_inov_dis_votable)
5272 destroy_votable(chg->hvdcp_hw_inov_dis_votable);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07005273 if (chg->typec_irq_disable_votable)
5274 destroy_votable(chg->typec_irq_disable_votable);
Tirupathi Reddy0c5d0a52017-09-27 16:31:07 +05305275 if (chg->disable_power_role_switch)
5276 destroy_votable(chg->disable_power_role_switch);
Harry Yangba874ce2016-08-19 14:17:01 -07005277}
5278
5279static void smblib_iio_deinit(struct smb_charger *chg)
5280{
5281 if (!IS_ERR_OR_NULL(chg->iio.temp_chan))
5282 iio_channel_release(chg->iio.temp_chan);
5283 if (!IS_ERR_OR_NULL(chg->iio.temp_max_chan))
5284 iio_channel_release(chg->iio.temp_max_chan);
5285 if (!IS_ERR_OR_NULL(chg->iio.usbin_i_chan))
5286 iio_channel_release(chg->iio.usbin_i_chan);
5287 if (!IS_ERR_OR_NULL(chg->iio.usbin_v_chan))
5288 iio_channel_release(chg->iio.usbin_v_chan);
Nicholas Troast7dbcad22016-10-05 13:30:18 -07005289 if (!IS_ERR_OR_NULL(chg->iio.batt_i_chan))
5290 iio_channel_release(chg->iio.batt_i_chan);
Harry Yangba874ce2016-08-19 14:17:01 -07005291}
5292
Nicholas Troast320839e2016-06-03 10:18:00 -07005293int smblib_init(struct smb_charger *chg)
5294{
5295 int rc = 0;
5296
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07005297 mutex_init(&chg->lock);
Nicholas Troast320839e2016-06-03 10:18:00 -07005298 mutex_init(&chg->write_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08005299 mutex_init(&chg->otg_oc_lock);
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07005300 mutex_init(&chg->vconn_oc_lock);
Harry Yangfe913842016-08-10 12:27:28 -07005301 INIT_WORK(&chg->bms_update_work, bms_update_work);
Harry Yang166b15d2017-08-28 13:00:40 -07005302 INIT_WORK(&chg->pl_update_work, pl_update_work);
Harry Yang755a34b2016-11-01 01:18:51 -07005303 INIT_WORK(&chg->rdstd_cc2_detach_work, rdstd_cc2_detach_work);
Nicholas Troast320839e2016-06-03 10:18:00 -07005304 INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07005305 INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work);
Nicholas Troastb11015f2017-01-17 17:56:45 -08005306 INIT_WORK(&chg->otg_oc_work, smblib_otg_oc_work);
5307 INIT_WORK(&chg->vconn_oc_work, smblib_vconn_oc_work);
5308 INIT_DELAYED_WORK(&chg->otg_ss_done_work, smblib_otg_ss_done_work);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05305309 INIT_DELAYED_WORK(&chg->icl_change_work, smblib_icl_change_work);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05305310 INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07005311 INIT_WORK(&chg->legacy_detection_work, smblib_legacy_detection_work);
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05305312 INIT_DELAYED_WORK(&chg->uusb_otg_work, smblib_uusb_otg_work);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05305313 INIT_DELAYED_WORK(&chg->bb_removal_work, smblib_bb_removal_work);
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07005314 chg->fake_capacity = -EINVAL;
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07005315 chg->fake_input_current_limited = -EINVAL;
Harry Yang589dd422017-07-28 18:41:42 -07005316 chg->fake_batt_status = -EINVAL;
Nicholas Troast320839e2016-06-03 10:18:00 -07005317
5318 switch (chg->mode) {
5319 case PARALLEL_MASTER:
Ashay Jaiswal9ad978672018-02-28 17:13:05 +05305320 rc = qcom_batt_init(chg->smb_version);
Harry Yang0c35ff62017-04-06 00:02:30 -07005321 if (rc < 0) {
5322 smblib_err(chg, "Couldn't init qcom_batt_init rc=%d\n",
5323 rc);
5324 return rc;
5325 }
5326
Fenglin Wudd8f4cb2017-10-17 11:09:46 +08005327 rc = qcom_step_chg_init(chg->dev, chg->step_chg_enabled,
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +05305328 chg->sw_jeita_enabled);
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05305329 if (rc < 0) {
5330 smblib_err(chg, "Couldn't init qcom_step_chg_init rc=%d\n",
5331 rc);
5332 return rc;
5333 }
5334
Nicholas Troast320839e2016-06-03 10:18:00 -07005335 rc = smblib_create_votables(chg);
5336 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07005337 smblib_err(chg, "Couldn't create votables rc=%d\n",
Nicholas Troast320839e2016-06-03 10:18:00 -07005338 rc);
Harry Yang58a9e7a2016-06-23 14:54:43 -07005339 return rc;
Nicholas Troast320839e2016-06-03 10:18:00 -07005340 }
Harry Yang58a9e7a2016-06-23 14:54:43 -07005341
Harry Yang5e1a5222016-07-26 15:16:04 -07005342 rc = smblib_register_notifier(chg);
5343 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07005344 smblib_err(chg,
Harry Yang5e1a5222016-07-26 15:16:04 -07005345 "Couldn't register notifier rc=%d\n", rc);
5346 return rc;
Harry Yang58a9e7a2016-06-23 14:54:43 -07005347 }
5348
Harry Yang995b7422016-08-29 16:06:50 -07005349 chg->bms_psy = power_supply_get_by_name("bms");
Ashay Jaiswal8afedfc2017-02-03 11:18:22 +05305350 chg->pl.psy = power_supply_get_by_name("parallel");
Harry Yang166b15d2017-08-28 13:00:40 -07005351 if (chg->pl.psy) {
5352 rc = smblib_stat_sw_override_cfg(chg, false);
5353 if (rc < 0) {
5354 smblib_err(chg,
5355 "Couldn't config stat sw rc=%d\n", rc);
5356 return rc;
5357 }
5358 }
Nicholas Troast320839e2016-06-03 10:18:00 -07005359 break;
5360 case PARALLEL_SLAVE:
5361 break;
5362 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07005363 smblib_err(chg, "Unsupported mode %d\n", chg->mode);
Nicholas Troast320839e2016-06-03 10:18:00 -07005364 return -EINVAL;
5365 }
5366
5367 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07005368}
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07005369
5370int smblib_deinit(struct smb_charger *chg)
5371{
Harry Yangba874ce2016-08-19 14:17:01 -07005372 switch (chg->mode) {
5373 case PARALLEL_MASTER:
Harry Yang0c35ff62017-04-06 00:02:30 -07005374 cancel_work_sync(&chg->bms_update_work);
Harry Yang166b15d2017-08-28 13:00:40 -07005375 cancel_work_sync(&chg->pl_update_work);
Harry Yang0c35ff62017-04-06 00:02:30 -07005376 cancel_work_sync(&chg->rdstd_cc2_detach_work);
5377 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
Harry Yang0c35ff62017-04-06 00:02:30 -07005378 cancel_delayed_work_sync(&chg->clear_hdc_work);
5379 cancel_work_sync(&chg->otg_oc_work);
5380 cancel_work_sync(&chg->vconn_oc_work);
5381 cancel_delayed_work_sync(&chg->otg_ss_done_work);
5382 cancel_delayed_work_sync(&chg->icl_change_work);
5383 cancel_delayed_work_sync(&chg->pl_enable_work);
5384 cancel_work_sync(&chg->legacy_detection_work);
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05305385 cancel_delayed_work_sync(&chg->uusb_otg_work);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05305386 cancel_delayed_work_sync(&chg->bb_removal_work);
Harry Yangba874ce2016-08-19 14:17:01 -07005387 power_supply_unreg_notifier(&chg->nb);
5388 smblib_destroy_votables(chg);
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05305389 qcom_step_chg_deinit();
Harry Yang0c35ff62017-04-06 00:02:30 -07005390 qcom_batt_deinit();
Harry Yangba874ce2016-08-19 14:17:01 -07005391 break;
5392 case PARALLEL_SLAVE:
5393 break;
5394 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07005395 smblib_err(chg, "Unsupported mode %d\n", chg->mode);
Harry Yangba874ce2016-08-19 14:17:01 -07005396 return -EINVAL;
5397 }
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07005398
Harry Yangba874ce2016-08-19 14:17:01 -07005399 smblib_iio_deinit(chg);
Harry Yang5e1a5222016-07-26 15:16:04 -07005400
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07005401 return 0;
5402}