blob: 64fda75a14a8bf8e575ac8aecd97a7830b795f86 [file] [log] [blame]
Harry Yang3b113a52016-12-08 12:37:40 -08001/* Copyright (c) 2016-2017 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 Jaiswal4aa2c0c2016-12-07 19:39:38 +0530690
691 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
692
Ashay Jaiswal67ec7072017-02-16 14:14:58 +0530693 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
694 /* re-enable AUTH_IRQ_EN_CFG_BIT */
695 rc = smblib_masked_write(chg,
696 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
697 AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
698 if (rc < 0)
699 smblib_err(chg,
700 "Couldn't enable QC auth setting rc=%d\n", rc);
701 }
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530702
703 /* reconfigure allowed voltage for HVDCP */
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530704 rc = smblib_set_adapter_allowance(chg,
705 USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530706 if (rc < 0)
707 smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
708 rc);
709
710 chg->voltage_min_uv = MICRO_5V;
711 chg->voltage_max_uv = MICRO_5V;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +0530712 chg->usb_icl_delta_ua = 0;
713 chg->pulse_cnt = 0;
Ashay Jaiswal8507aa52017-04-14 09:42:32 +0530714 chg->uusb_apsd_rerun_done = false;
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530715
716 /* clear USB ICL vote for USB_PSY_VOTER */
717 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
718 if (rc < 0)
719 smblib_err(chg, "Couldn't un-vote for USB ICL rc=%d\n", rc);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -0800720
721 /* clear USB ICL vote for DCP_VOTER */
722 rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
723 if (rc < 0)
724 smblib_err(chg,
725 "Couldn't un-vote DCP from USB ICL rc=%d\n", rc);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530726}
727
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530728void smblib_suspend_on_debug_battery(struct smb_charger *chg)
729{
730 int rc;
731 union power_supply_propval val;
732
Ashay Jaiswalda8669b2017-02-10 23:24:23 +0530733 if (!chg->suspend_input_on_debug_batt)
734 return;
735
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530736 rc = power_supply_get_property(chg->bms_psy,
737 POWER_SUPPLY_PROP_DEBUG_BATTERY, &val);
738 if (rc < 0) {
739 smblib_err(chg, "Couldn't get debug battery prop rc=%d\n", rc);
740 return;
741 }
742
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800743 vote(chg->usb_icl_votable, DEBUG_BOARD_VOTER, val.intval, 0);
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530744 vote(chg->dc_suspend_votable, DEBUG_BOARD_VOTER, val.intval, 0);
745 if (val.intval)
746 pr_info("Input suspended: Fake battery\n");
747}
748
Abhijeet Dharmapurikar9dd61292017-01-25 16:40:08 -0800749int smblib_rerun_apsd_if_required(struct smb_charger *chg)
750{
Abhijeet Dharmapurikar9dd61292017-01-25 16:40:08 -0800751 union power_supply_propval val;
752 int rc;
753
754 rc = smblib_get_prop_usb_present(chg, &val);
755 if (rc < 0) {
756 smblib_err(chg, "Couldn't get usb present rc = %d\n", rc);
757 return rc;
758 }
759
760 if (!val.intval)
761 return 0;
762
Ashay Jaiswal13a1b812017-07-17 14:49:05 +0530763 rc = smblib_request_dpdm(chg, true);
764 if (rc < 0)
765 smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
Abhijeet Dharmapurikar025e63a2017-02-24 14:06:22 -0800766
Ashay Jaiswal8507aa52017-04-14 09:42:32 +0530767 chg->uusb_apsd_rerun_done = true;
Abhijeet Dharmapurikar025e63a2017-02-24 14:06:22 -0800768 smblib_rerun_apsd(chg);
769
Abhijeet Dharmapurikar9dd61292017-01-25 16:40:08 -0800770 return 0;
771}
772
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +0530773static int smblib_get_hw_pulse_cnt(struct smb_charger *chg, int *count)
Ashay Jaiswal6d308da2017-02-18 09:59:23 +0530774{
775 int rc;
776 u8 val[2];
777
778 switch (chg->smb_version) {
779 case PMI8998_SUBTYPE:
780 rc = smblib_read(chg, QC_PULSE_COUNT_STATUS_REG, val);
781 if (rc) {
782 pr_err("failed to read QC_PULSE_COUNT_STATUS_REG rc=%d\n",
783 rc);
784 return rc;
785 }
786 *count = val[0] & QC_PULSE_COUNT_MASK;
787 break;
788 case PM660_SUBTYPE:
789 rc = smblib_multibyte_read(chg,
790 QC_PULSE_COUNT_STATUS_1_REG, val, 2);
791 if (rc) {
792 pr_err("failed to read QC_PULSE_COUNT_STATUS_1_REG rc=%d\n",
793 rc);
794 return rc;
795 }
796 *count = (val[1] << 8) | val[0];
797 break;
798 default:
799 smblib_dbg(chg, PR_PARALLEL, "unknown SMB chip %d\n",
800 chg->smb_version);
801 return -EINVAL;
802 }
803
804 return 0;
805}
806
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +0530807static int smblib_get_pulse_cnt(struct smb_charger *chg, int *count)
808{
809 int rc;
810
811 /* Use software based pulse count if HW INOV is disabled */
812 if (get_effective_result(chg->hvdcp_hw_inov_dis_votable) > 0) {
813 *count = chg->pulse_cnt;
814 return 0;
815 }
816
817 /* Use h/w pulse count if autonomous mode is enabled */
818 rc = smblib_get_hw_pulse_cnt(chg, count);
819 if (rc < 0)
820 smblib_err(chg, "failed to read h/w pulse count rc=%d\n", rc);
821
822 return rc;
823}
824
Nicholas Troastbb76a142016-09-23 11:23:23 -0700825#define USBIN_25MA 25000
826#define USBIN_100MA 100000
827#define USBIN_150MA 150000
828#define USBIN_500MA 500000
829#define USBIN_900MA 900000
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800830
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800831static int set_sdp_current(struct smb_charger *chg, int icl_ua)
Nicholas Troast34db5032016-03-28 12:26:44 -0700832{
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800833 int rc;
834 u8 icl_options;
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +0530835 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700836
Nicholas Troastbb76a142016-09-23 11:23:23 -0700837 /* power source is SDP */
838 switch (icl_ua) {
839 case USBIN_100MA:
840 /* USB 2.0 100mA */
841 icl_options = 0;
842 break;
843 case USBIN_150MA:
844 /* USB 3.0 150mA */
845 icl_options = CFG_USB3P0_SEL_BIT;
846 break;
847 case USBIN_500MA:
848 /* USB 2.0 500mA */
849 icl_options = USB51_MODE_BIT;
850 break;
851 case USBIN_900MA:
852 /* USB 3.0 900mA */
853 icl_options = CFG_USB3P0_SEL_BIT | USB51_MODE_BIT;
854 break;
855 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700856 smblib_err(chg, "ICL %duA isn't supported for SDP\n", icl_ua);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800857 return -EINVAL;
Nicholas Troastbb76a142016-09-23 11:23:23 -0700858 }
Nicholas Troast34db5032016-03-28 12:26:44 -0700859
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +0530860 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB &&
861 apsd_result->pst == POWER_SUPPLY_TYPE_USB_FLOAT) {
862 /*
863 * change the float charger configuration to SDP, if this
864 * is the case of SDP being detected as FLOAT
865 */
866 rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
867 FORCE_FLOAT_SDP_CFG_BIT, FORCE_FLOAT_SDP_CFG_BIT);
868 if (rc < 0) {
869 smblib_err(chg, "Couldn't set float ICL options rc=%d\n",
870 rc);
871 return rc;
872 }
873 }
874
Nicholas Troastbb76a142016-09-23 11:23:23 -0700875 rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800876 CFG_USB3P0_SEL_BIT | USB51_MODE_BIT, icl_options);
Nicholas Troast34db5032016-03-28 12:26:44 -0700877 if (rc < 0) {
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800878 smblib_err(chg, "Couldn't set ICL options rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -0700879 return rc;
880 }
881
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800882 return rc;
883}
884
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700885static int get_sdp_current(struct smb_charger *chg, int *icl_ua)
886{
887 int rc;
888 u8 icl_options;
889 bool usb3 = false;
890
891 rc = smblib_read(chg, USBIN_ICL_OPTIONS_REG, &icl_options);
892 if (rc < 0) {
893 smblib_err(chg, "Couldn't get ICL options rc=%d\n", rc);
894 return rc;
895 }
896
897 usb3 = (icl_options & CFG_USB3P0_SEL_BIT);
898
899 if (icl_options & USB51_MODE_BIT)
900 *icl_ua = usb3 ? USBIN_900MA : USBIN_500MA;
901 else
902 *icl_ua = usb3 ? USBIN_150MA : USBIN_100MA;
903
904 return rc;
905}
906
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530907int smblib_set_icl_current(struct smb_charger *chg, int icl_ua)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800908{
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800909 int rc = 0;
910 bool override;
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800911
912 /* suspend and return if 25mA or less is requested */
Harry Yang379484a2017-08-29 10:26:14 -0700913 if (icl_ua <= USBIN_25MA)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800914 return smblib_set_usb_suspend(chg, true);
915
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530916 if (icl_ua == INT_MAX)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800917 goto override_suspend_config;
918
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800919 /* configure current */
Nicholas Troaste1932e42017-04-12 12:38:18 -0700920 if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
Fenglin Wu80826e02017-04-25 21:45:08 +0800921 && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) {
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800922 rc = set_sdp_current(chg, icl_ua);
923 if (rc < 0) {
924 smblib_err(chg, "Couldn't set SDP ICL rc=%d\n", rc);
925 goto enable_icl_changed_interrupt;
926 }
927 } else {
Abhijeet Dharmapurikar949d67e2017-05-25 15:10:56 -0700928 set_sdp_current(chg, 100000);
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -0700929 rc = smblib_set_charge_param(chg, &chg->param.usb_icl, icl_ua);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800930 if (rc < 0) {
931 smblib_err(chg, "Couldn't set HC ICL rc=%d\n", rc);
932 goto enable_icl_changed_interrupt;
933 }
934 }
935
936override_suspend_config:
937 /* determine if override needs to be enforced */
938 override = true;
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530939 if (icl_ua == INT_MAX) {
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800940 /* remove override if no voters - hw defaults is desired */
941 override = false;
Nicholas Troaste1932e42017-04-12 12:38:18 -0700942 } else if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
Fenglin Wu80826e02017-04-25 21:45:08 +0800943 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800944 /* For std cable with type = SDP never override */
945 override = false;
Fenglin Wu80826e02017-04-25 21:45:08 +0800946 else if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_CDP
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -0700947 && icl_ua == 1500000)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800948 /*
949 * For std cable with type = CDP override only if
950 * current is not 1500mA
951 */
952 override = false;
953 }
954
955 /* enforce override */
956 rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
957 USBIN_MODE_CHG_BIT, override ? USBIN_MODE_CHG_BIT : 0);
958
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800959 rc = smblib_icl_override(chg, override);
960 if (rc < 0) {
961 smblib_err(chg, "Couldn't set ICL override rc=%d\n", rc);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800962 goto enable_icl_changed_interrupt;
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800963 }
964
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800965 /* unsuspend after configuring current and override */
966 rc = smblib_set_usb_suspend(chg, false);
967 if (rc < 0) {
968 smblib_err(chg, "Couldn't resume input rc=%d\n", rc);
969 goto enable_icl_changed_interrupt;
970 }
971
972enable_icl_changed_interrupt:
Nicholas Troast34db5032016-03-28 12:26:44 -0700973 return rc;
974}
975
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700976int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua)
977{
978 int rc = 0;
979 u8 load_cfg;
980 bool override;
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700981
Nicholas Troaste1932e42017-04-12 12:38:18 -0700982 if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700983 || chg->micro_usb_mode)
984 && (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)) {
985 rc = get_sdp_current(chg, icl_ua);
986 if (rc < 0) {
987 smblib_err(chg, "Couldn't get SDP ICL rc=%d\n", rc);
988 return rc;
989 }
990 } else {
991 rc = smblib_read(chg, USBIN_LOAD_CFG_REG, &load_cfg);
992 if (rc < 0) {
993 smblib_err(chg, "Couldn't get load cfg rc=%d\n", rc);
994 return rc;
995 }
996 override = load_cfg & ICL_OVERRIDE_AFTER_APSD_BIT;
997 if (!override)
998 return INT_MAX;
999
1000 /* override is set */
1001 rc = smblib_get_charge_param(chg, &chg->param.usb_icl, icl_ua);
1002 if (rc < 0) {
1003 smblib_err(chg, "Couldn't get HC ICL rc=%d\n", rc);
1004 return rc;
1005 }
1006 }
1007
1008 return 0;
1009}
1010
Ashay Jaiswalae1586d2017-03-22 23:18:51 +05301011/*********************
1012 * VOTABLE CALLBACKS *
1013 *********************/
1014
1015static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data,
1016 int suspend, const char *client)
1017{
1018 struct smb_charger *chg = data;
1019
1020 /* resume input if suspend is invalid */
1021 if (suspend < 0)
1022 suspend = 0;
1023
1024 return smblib_set_dc_suspend(chg, (bool)suspend);
1025}
1026
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001027static int smblib_dc_icl_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -07001028 int icl_ua, const char *client)
Nicholas Troast34db5032016-03-28 12:26:44 -07001029{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001030 struct smb_charger *chg = data;
Nicholas Troast34db5032016-03-28 12:26:44 -07001031 int rc = 0;
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001032 bool suspend;
1033
1034 if (icl_ua < 0) {
1035 smblib_dbg(chg, PR_MISC, "No Voter hence suspending\n");
1036 icl_ua = 0;
1037 }
1038
Harry Yang379484a2017-08-29 10:26:14 -07001039 suspend = (icl_ua <= USBIN_25MA);
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001040 if (suspend)
1041 goto suspend;
Nicholas Troast34db5032016-03-28 12:26:44 -07001042
1043 rc = smblib_set_charge_param(chg, &chg->param.dc_icl, icl_ua);
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001044 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001045 smblib_err(chg, "Couldn't set DC input current limit rc=%d\n",
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001046 rc);
1047 return rc;
1048 }
1049
1050suspend:
1051 rc = vote(chg->dc_suspend_votable, USER_VOTER, suspend, 0);
1052 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001053 smblib_err(chg, "Couldn't vote to %s DC rc=%d\n",
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001054 suspend ? "suspend" : "resume", rc);
1055 return rc;
1056 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001057 return rc;
1058}
1059
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07001060static int smblib_pd_disallowed_votable_indirect_callback(
1061 struct votable *votable, void *data, int disallowed, const char *client)
1062{
1063 struct smb_charger *chg = data;
1064 int rc;
1065
1066 rc = vote(chg->pd_allowed_votable, PD_DISALLOWED_INDIRECT_VOTER,
1067 !disallowed, 0);
1068
1069 return rc;
1070}
1071
Harry Yang223c6282016-06-14 15:48:36 -07001072static int smblib_awake_vote_callback(struct votable *votable, void *data,
1073 int awake, const char *client)
1074{
1075 struct smb_charger *chg = data;
1076
1077 if (awake)
1078 pm_stay_awake(chg->dev);
1079 else
1080 pm_relax(chg->dev);
1081
1082 return 0;
1083}
1084
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07001085static int smblib_chg_disable_vote_callback(struct votable *votable, void *data,
1086 int chg_disable, const char *client)
1087{
1088 struct smb_charger *chg = data;
1089 int rc;
1090
1091 rc = smblib_masked_write(chg, CHARGING_ENABLE_CMD_REG,
1092 CHARGING_ENABLE_CMD_BIT,
1093 chg_disable ? 0 : CHARGING_ENABLE_CMD_BIT);
1094 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001095 smblib_err(chg, "Couldn't %s charging rc=%d\n",
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07001096 chg_disable ? "disable" : "enable", rc);
1097 return rc;
1098 }
1099
1100 return 0;
1101}
Harry Yangaba1f5f2016-09-28 10:47:29 -07001102
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301103static int smblib_hvdcp_enable_vote_callback(struct votable *votable,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001104 void *data,
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301105 int hvdcp_enable, const char *client)
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001106{
1107 struct smb_charger *chg = data;
1108 int rc;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301109 u8 val = HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_EN_BIT;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07001110 u8 stat;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301111
1112 /* vote to enable/disable HW autonomous INOV */
1113 vote(chg->hvdcp_hw_inov_dis_votable, client, !hvdcp_enable, 0);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001114
1115 /*
1116 * Disable the autonomous bit and auth bit for disabling hvdcp.
1117 * This ensures only qc 2.0 detection runs but no vbus
1118 * negotiation happens.
1119 */
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301120 if (!hvdcp_enable)
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001121 val = HVDCP_EN_BIT;
1122
1123 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301124 HVDCP_EN_BIT | HVDCP_AUTH_ALG_EN_CFG_BIT,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001125 val);
1126 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001127 smblib_err(chg, "Couldn't %s hvdcp rc=%d\n",
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301128 hvdcp_enable ? "enable" : "disable", rc);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001129 return rc;
1130 }
1131
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07001132 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
1133 if (rc < 0) {
1134 smblib_err(chg, "Couldn't read APSD status rc=%d\n", rc);
1135 return rc;
1136 }
1137
1138 /* re-run APSD if HVDCP was detected */
1139 if (stat & QC_CHARGER_BIT)
1140 smblib_rerun_apsd(chg);
1141
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001142 return 0;
1143}
1144
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301145static int smblib_hvdcp_disable_indirect_vote_callback(struct votable *votable,
1146 void *data, int hvdcp_disable, const char *client)
1147{
1148 struct smb_charger *chg = data;
1149
1150 vote(chg->hvdcp_enable_votable, HVDCP_INDIRECT_VOTER,
1151 !hvdcp_disable, 0);
1152
1153 return 0;
1154}
1155
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07001156static int smblib_apsd_disable_vote_callback(struct votable *votable,
1157 void *data,
1158 int apsd_disable, const char *client)
1159{
1160 struct smb_charger *chg = data;
1161 int rc;
1162
Nicholas Troastec4703c2017-01-30 14:52:33 -08001163 if (apsd_disable) {
Nicholas Troastec4703c2017-01-30 14:52:33 -08001164 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1165 AUTO_SRC_DETECT_BIT,
1166 0);
1167 if (rc < 0) {
1168 smblib_err(chg, "Couldn't disable APSD rc=%d\n", rc);
1169 return rc;
1170 }
1171 } else {
1172 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1173 AUTO_SRC_DETECT_BIT,
1174 AUTO_SRC_DETECT_BIT);
1175 if (rc < 0) {
1176 smblib_err(chg, "Couldn't enable APSD rc=%d\n", rc);
1177 return rc;
1178 }
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07001179 }
1180
1181 return 0;
1182}
Nicholas Troast8995a702016-12-05 10:22:22 -08001183
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301184static int smblib_hvdcp_hw_inov_dis_vote_callback(struct votable *votable,
1185 void *data, int disable, const char *client)
1186{
1187 struct smb_charger *chg = data;
1188 int rc;
1189
1190 if (disable) {
1191 /*
1192 * the pulse count register get zeroed when autonomous mode is
1193 * disabled. Track that in variables before disabling
1194 */
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +05301195 rc = smblib_get_hw_pulse_cnt(chg, &chg->pulse_cnt);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301196 if (rc < 0) {
1197 pr_err("failed to read QC_PULSE_COUNT_STATUS_REG rc=%d\n",
1198 rc);
1199 return rc;
1200 }
1201 }
1202
1203 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1204 HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT,
1205 disable ? 0 : HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT);
1206 if (rc < 0) {
1207 smblib_err(chg, "Couldn't %s hvdcp rc=%d\n",
1208 disable ? "disable" : "enable", rc);
1209 return rc;
1210 }
1211
1212 return rc;
1213}
1214
Harry Yang4bf7d962017-03-13 16:51:43 -07001215static int smblib_usb_irq_enable_vote_callback(struct votable *votable,
1216 void *data, int enable, const char *client)
1217{
1218 struct smb_charger *chg = data;
1219
1220 if (!chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq ||
1221 !chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq)
1222 return 0;
1223
1224 if (enable) {
1225 enable_irq(chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq);
1226 enable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
1227 } else {
1228 disable_irq(chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq);
1229 disable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
1230 }
1231
1232 return 0;
1233}
1234
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07001235static int smblib_typec_irq_disable_vote_callback(struct votable *votable,
1236 void *data, int disable, const char *client)
1237{
1238 struct smb_charger *chg = data;
1239
1240 if (!chg->irq_info[TYPE_C_CHANGE_IRQ].irq)
1241 return 0;
1242
1243 if (disable)
1244 disable_irq_nosync(chg->irq_info[TYPE_C_CHANGE_IRQ].irq);
1245 else
1246 enable_irq(chg->irq_info[TYPE_C_CHANGE_IRQ].irq);
1247
1248 return 0;
1249}
1250
Nicholas Troast8995a702016-12-05 10:22:22 -08001251/*******************
1252 * VCONN REGULATOR *
1253 * *****************/
1254
Nicholas Troastb11015f2017-01-17 17:56:45 -08001255#define MAX_OTG_SS_TRIES 2
Nicholas Troast8995a702016-12-05 10:22:22 -08001256static int _smblib_vconn_regulator_enable(struct regulator_dev *rdev)
1257{
1258 struct smb_charger *chg = rdev_get_drvdata(rdev);
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001259 int rc = 0;
1260 u8 val;
Nicholas Troast8995a702016-12-05 10:22:22 -08001261
1262 /*
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001263 * When enabling VCONN using the command register the CC pin must be
1264 * selected. VCONN should be supplied to the inactive CC pin hence using
1265 * the opposite of the CC_ORIENTATION_BIT.
Nicholas Troast8995a702016-12-05 10:22:22 -08001266 */
Nicholas Troastb11015f2017-01-17 17:56:45 -08001267 smblib_dbg(chg, PR_OTG, "enabling VCONN\n");
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07001268 val = chg->typec_status[3] &
1269 CC_ORIENTATION_BIT ? 0 : VCONN_EN_ORIENTATION_BIT;
Nicholas Troast8995a702016-12-05 10:22:22 -08001270 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1271 VCONN_EN_VALUE_BIT | VCONN_EN_ORIENTATION_BIT,
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07001272 VCONN_EN_VALUE_BIT | val);
Nicholas Troast8995a702016-12-05 10:22:22 -08001273 if (rc < 0) {
1274 smblib_err(chg, "Couldn't enable vconn setting rc=%d\n", rc);
1275 return rc;
1276 }
1277
1278 return rc;
1279}
1280
1281int smblib_vconn_regulator_enable(struct regulator_dev *rdev)
1282{
1283 struct smb_charger *chg = rdev_get_drvdata(rdev);
1284 int rc = 0;
1285
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001286 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001287 if (chg->vconn_en)
1288 goto unlock;
1289
1290 rc = _smblib_vconn_regulator_enable(rdev);
1291 if (rc >= 0)
1292 chg->vconn_en = true;
1293
1294unlock:
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001295 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001296 return rc;
1297}
1298
1299static int _smblib_vconn_regulator_disable(struct regulator_dev *rdev)
1300{
1301 struct smb_charger *chg = rdev_get_drvdata(rdev);
1302 int rc = 0;
1303
Nicholas Troastb11015f2017-01-17 17:56:45 -08001304 smblib_dbg(chg, PR_OTG, "disabling VCONN\n");
Nicholas Troast8995a702016-12-05 10:22:22 -08001305 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1306 VCONN_EN_VALUE_BIT, 0);
1307 if (rc < 0)
1308 smblib_err(chg, "Couldn't disable vconn regulator rc=%d\n", rc);
1309
1310 return rc;
1311}
1312
1313int smblib_vconn_regulator_disable(struct regulator_dev *rdev)
1314{
1315 struct smb_charger *chg = rdev_get_drvdata(rdev);
1316 int rc = 0;
1317
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001318 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001319 if (!chg->vconn_en)
1320 goto unlock;
1321
1322 rc = _smblib_vconn_regulator_disable(rdev);
1323 if (rc >= 0)
1324 chg->vconn_en = false;
1325
1326unlock:
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001327 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001328 return rc;
1329}
1330
1331int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev)
1332{
1333 struct smb_charger *chg = rdev_get_drvdata(rdev);
1334 int ret;
1335
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001336 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001337 ret = chg->vconn_en;
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001338 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001339 return ret;
1340}
1341
Nicholas Troast34db5032016-03-28 12:26:44 -07001342/*****************
1343 * OTG REGULATOR *
1344 *****************/
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301345#define MAX_RETRY 15
1346#define MIN_DELAY_US 2000
1347#define MAX_DELAY_US 9000
Anirudh Ghayaladf20da2017-07-03 10:52:29 +05301348static int otg_current[] = {250000, 500000, 1000000, 1500000};
1349static int smblib_enable_otg_wa(struct smb_charger *chg)
1350{
1351 u8 stat;
1352 int rc, i, retry_count = 0, min_delay = MIN_DELAY_US;
1353
1354 for (i = 0; i < ARRAY_SIZE(otg_current); i++) {
1355 smblib_dbg(chg, PR_OTG, "enabling OTG with %duA\n",
1356 otg_current[i]);
1357 rc = smblib_set_charge_param(chg, &chg->param.otg_cl,
1358 otg_current[i]);
1359 if (rc < 0) {
1360 smblib_err(chg, "Couldn't set otg limit rc=%d\n", rc);
1361 return rc;
1362 }
1363
1364 rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT);
1365 if (rc < 0) {
1366 smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc);
1367 return rc;
1368 }
1369
1370 retry_count = 0;
1371 min_delay = MIN_DELAY_US;
1372 do {
1373 usleep_range(min_delay, min_delay + 100);
1374 rc = smblib_read(chg, OTG_STATUS_REG, &stat);
1375 if (rc < 0) {
1376 smblib_err(chg, "Couldn't read OTG status rc=%d\n",
1377 rc);
1378 goto out;
1379 }
1380
1381 if (stat & BOOST_SOFTSTART_DONE_BIT) {
1382 rc = smblib_set_charge_param(chg,
1383 &chg->param.otg_cl, chg->otg_cl_ua);
1384 if (rc < 0) {
1385 smblib_err(chg, "Couldn't set otg limit rc=%d\n",
1386 rc);
1387 goto out;
1388 }
1389 break;
1390 }
1391 /* increase the delay for following iterations */
1392 if (retry_count > 5)
1393 min_delay = MAX_DELAY_US;
1394
1395 } while (retry_count++ < MAX_RETRY);
1396
1397 if (retry_count >= MAX_RETRY) {
1398 smblib_dbg(chg, PR_OTG, "OTG enable failed with %duA\n",
1399 otg_current[i]);
1400 rc = smblib_write(chg, CMD_OTG_REG, 0);
1401 if (rc < 0) {
1402 smblib_err(chg, "disable OTG rc=%d\n", rc);
1403 goto out;
1404 }
1405 } else {
1406 smblib_dbg(chg, PR_OTG, "OTG enabled\n");
1407 return 0;
1408 }
1409 }
1410
1411 if (i == ARRAY_SIZE(otg_current)) {
1412 rc = -EINVAL;
1413 goto out;
1414 }
1415
1416 return 0;
1417out:
1418 smblib_write(chg, CMD_OTG_REG, 0);
1419 return rc;
1420}
1421
Nicholas Troast8995a702016-12-05 10:22:22 -08001422static int _smblib_vbus_regulator_enable(struct regulator_dev *rdev)
Nicholas Troast34db5032016-03-28 12:26:44 -07001423{
1424 struct smb_charger *chg = rdev_get_drvdata(rdev);
Anirudh Ghayaladf20da2017-07-03 10:52:29 +05301425 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001426
Nicholas Troastb11015f2017-01-17 17:56:45 -08001427 smblib_dbg(chg, PR_OTG, "halt 1 in 8 mode\n");
Harry Yang360bd532016-09-26 11:03:22 -07001428 rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
1429 ENG_BUCKBOOST_HALT1_8_MODE_BIT,
1430 ENG_BUCKBOOST_HALT1_8_MODE_BIT);
1431 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001432 smblib_err(chg, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n",
Harry Yang360bd532016-09-26 11:03:22 -07001433 rc);
1434 return rc;
1435 }
1436
Nicholas Troastb11015f2017-01-17 17:56:45 -08001437 smblib_dbg(chg, PR_OTG, "enabling OTG\n");
Harry Yang360bd532016-09-26 11:03:22 -07001438
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301439 if (chg->wa_flags & OTG_WA) {
Anirudh Ghayaladf20da2017-07-03 10:52:29 +05301440 rc = smblib_enable_otg_wa(chg);
1441 if (rc < 0)
1442 smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc);
1443 } else {
1444 rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT);
1445 if (rc < 0)
1446 smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc);
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301447 }
1448
Nicholas Troast34db5032016-03-28 12:26:44 -07001449 return rc;
1450}
1451
Nicholas Troast8995a702016-12-05 10:22:22 -08001452int smblib_vbus_regulator_enable(struct regulator_dev *rdev)
Nicholas Troast34db5032016-03-28 12:26:44 -07001453{
1454 struct smb_charger *chg = rdev_get_drvdata(rdev);
1455 int rc = 0;
1456
Nicholas Troastb11015f2017-01-17 17:56:45 -08001457 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001458 if (chg->otg_en)
1459 goto unlock;
1460
Harry Yanga2fb0e32017-03-22 22:45:25 -07001461 if (!chg->usb_icl_votable) {
1462 chg->usb_icl_votable = find_votable("USB_ICL");
1463
1464 if (!chg->usb_icl_votable)
1465 return -EINVAL;
1466 }
1467 vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, true, 0);
1468
Nicholas Troast8995a702016-12-05 10:22:22 -08001469 rc = _smblib_vbus_regulator_enable(rdev);
1470 if (rc >= 0)
1471 chg->otg_en = true;
1472
1473unlock:
Nicholas Troastb11015f2017-01-17 17:56:45 -08001474 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001475 return rc;
1476}
1477
1478static int _smblib_vbus_regulator_disable(struct regulator_dev *rdev)
1479{
1480 struct smb_charger *chg = rdev_get_drvdata(rdev);
1481 int rc;
Nicholas Troast8995a702016-12-05 10:22:22 -08001482
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301483 if (chg->wa_flags & OTG_WA) {
1484 /* set OTG current limit to minimum value */
1485 rc = smblib_set_charge_param(chg, &chg->param.otg_cl,
1486 chg->param.otg_cl.min_u);
1487 if (rc < 0) {
1488 smblib_err(chg,
1489 "Couldn't set otg current limit rc=%d\n", rc);
1490 return rc;
1491 }
1492 }
1493
Nicholas Troastb11015f2017-01-17 17:56:45 -08001494 smblib_dbg(chg, PR_OTG, "disabling OTG\n");
Harry Yang360bd532016-09-26 11:03:22 -07001495 rc = smblib_write(chg, CMD_OTG_REG, 0);
1496 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001497 smblib_err(chg, "Couldn't disable OTG regulator rc=%d\n", rc);
Harry Yang360bd532016-09-26 11:03:22 -07001498 return rc;
1499 }
1500
Nicholas Troastb11015f2017-01-17 17:56:45 -08001501 smblib_dbg(chg, PR_OTG, "start 1 in 8 mode\n");
Harry Yang360bd532016-09-26 11:03:22 -07001502 rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
1503 ENG_BUCKBOOST_HALT1_8_MODE_BIT, 0);
1504 if (rc < 0) {
Nicholas Troast8995a702016-12-05 10:22:22 -08001505 smblib_err(chg, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n", rc);
Harry Yang360bd532016-09-26 11:03:22 -07001506 return rc;
1507 }
1508
Nicholas Troast8995a702016-12-05 10:22:22 -08001509 return 0;
1510}
Nicholas Troast34db5032016-03-28 12:26:44 -07001511
Nicholas Troast8995a702016-12-05 10:22:22 -08001512int smblib_vbus_regulator_disable(struct regulator_dev *rdev)
1513{
1514 struct smb_charger *chg = rdev_get_drvdata(rdev);
1515 int rc = 0;
1516
Nicholas Troastb11015f2017-01-17 17:56:45 -08001517 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001518 if (!chg->otg_en)
1519 goto unlock;
1520
1521 rc = _smblib_vbus_regulator_disable(rdev);
1522 if (rc >= 0)
1523 chg->otg_en = false;
1524
Harry Yanga2fb0e32017-03-22 22:45:25 -07001525 if (chg->usb_icl_votable)
1526 vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0);
Nicholas Troast8995a702016-12-05 10:22:22 -08001527unlock:
Nicholas Troastb11015f2017-01-17 17:56:45 -08001528 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07001529 return rc;
1530}
1531
1532int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev)
1533{
1534 struct smb_charger *chg = rdev_get_drvdata(rdev);
Nicholas Troast8995a702016-12-05 10:22:22 -08001535 int ret;
Nicholas Troast34db5032016-03-28 12:26:44 -07001536
Nicholas Troastb11015f2017-01-17 17:56:45 -08001537 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001538 ret = chg->otg_en;
Nicholas Troastb11015f2017-01-17 17:56:45 -08001539 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001540 return ret;
Nicholas Troast34db5032016-03-28 12:26:44 -07001541}
1542
1543/********************
1544 * BATT PSY GETTERS *
1545 ********************/
1546
1547int smblib_get_prop_input_suspend(struct smb_charger *chg,
1548 union power_supply_propval *val)
1549{
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08001550 val->intval
1551 = (get_client_vote(chg->usb_icl_votable, USER_VOTER) == 0)
1552 && get_client_vote(chg->dc_suspend_votable, USER_VOTER);
Nicholas Troast34db5032016-03-28 12:26:44 -07001553 return 0;
1554}
1555
1556int smblib_get_prop_batt_present(struct smb_charger *chg,
1557 union power_supply_propval *val)
1558{
1559 int rc;
1560 u8 stat;
1561
1562 rc = smblib_read(chg, BATIF_BASE + INT_RT_STS_OFFSET, &stat);
1563 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001564 smblib_err(chg, "Couldn't read BATIF_INT_RT_STS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07001565 return rc;
1566 }
1567
1568 val->intval = !(stat & (BAT_THERM_OR_ID_MISSING_RT_STS_BIT
1569 | BAT_TERMINAL_MISSING_RT_STS_BIT));
1570
1571 return rc;
1572}
1573
1574int smblib_get_prop_batt_capacity(struct smb_charger *chg,
1575 union power_supply_propval *val)
1576{
Harry Yang5e1a5222016-07-26 15:16:04 -07001577 int rc = -EINVAL;
1578
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07001579 if (chg->fake_capacity >= 0) {
1580 val->intval = chg->fake_capacity;
1581 return 0;
1582 }
1583
Harry Yang5e1a5222016-07-26 15:16:04 -07001584 if (chg->bms_psy)
1585 rc = power_supply_get_property(chg->bms_psy,
1586 POWER_SUPPLY_PROP_CAPACITY, val);
1587 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001588}
1589
1590int smblib_get_prop_batt_status(struct smb_charger *chg,
1591 union power_supply_propval *val)
1592{
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001593 union power_supply_propval pval = {0, };
Abhijeet Dharmapurikard97b2bf2017-07-06 17:03:00 -07001594 bool usb_online, dc_online, qnovo_en;
1595 u8 stat, pt_en_cmd;
Nicholas Troast8cb77552016-09-23 11:50:18 -07001596 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001597
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001598 rc = smblib_get_prop_usb_online(chg, &pval);
1599 if (rc < 0) {
1600 smblib_err(chg, "Couldn't get usb online property rc=%d\n",
1601 rc);
1602 return rc;
1603 }
1604 usb_online = (bool)pval.intval;
1605
1606 rc = smblib_get_prop_dc_online(chg, &pval);
1607 if (rc < 0) {
1608 smblib_err(chg, "Couldn't get dc online property rc=%d\n",
1609 rc);
1610 return rc;
1611 }
1612 dc_online = (bool)pval.intval;
1613
Nicholas Troast34db5032016-03-28 12:26:44 -07001614 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1615 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001616 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001617 rc);
1618 return rc;
1619 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001620 stat = stat & BATTERY_CHARGER_STATUS_MASK;
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001621
1622 if (!usb_online && !dc_online) {
1623 switch (stat) {
1624 case TERMINATE_CHARGE:
1625 case INHIBIT_CHARGE:
1626 val->intval = POWER_SUPPLY_STATUS_FULL;
1627 break;
1628 default:
1629 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
1630 break;
1631 }
1632 return rc;
1633 }
1634
Nicholas Troast8cb77552016-09-23 11:50:18 -07001635 switch (stat) {
1636 case TRICKLE_CHARGE:
1637 case PRE_CHARGE:
1638 case FAST_CHARGE:
1639 case FULLON_CHARGE:
1640 case TAPER_CHARGE:
Nicholas Troast34db5032016-03-28 12:26:44 -07001641 val->intval = POWER_SUPPLY_STATUS_CHARGING;
Nicholas Troast8cb77552016-09-23 11:50:18 -07001642 break;
1643 case TERMINATE_CHARGE:
1644 case INHIBIT_CHARGE:
1645 val->intval = POWER_SUPPLY_STATUS_FULL;
1646 break;
1647 case DISABLE_CHARGE:
1648 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
1649 break;
1650 default:
1651 val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
1652 break;
1653 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001654
Harry Yang7ecc1a12017-04-06 12:24:56 -07001655 if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
1656 return 0;
1657
Harry Yang589dd422017-07-28 18:41:42 -07001658 if (!usb_online && dc_online
1659 && chg->fake_batt_status == POWER_SUPPLY_STATUS_FULL) {
1660 val->intval = POWER_SUPPLY_STATUS_FULL;
1661 return 0;
1662 }
1663
Harry Yangc3c28d12017-04-17 16:41:19 -07001664 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_7_REG, &stat);
Harry Yang7ecc1a12017-04-06 12:24:56 -07001665 if (rc < 0) {
1666 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
1667 rc);
1668 return rc;
Abhijeet Dharmapurikard97b2bf2017-07-06 17:03:00 -07001669 }
Harry Yang7ecc1a12017-04-06 12:24:56 -07001670
Harry Yangc3c28d12017-04-17 16:41:19 -07001671 stat &= ENABLE_TRICKLE_BIT | ENABLE_PRE_CHARGING_BIT |
1672 ENABLE_FAST_CHARGING_BIT | ENABLE_FULLON_MODE_BIT;
Abhijeet Dharmapurikard97b2bf2017-07-06 17:03:00 -07001673
1674 rc = smblib_read(chg, QNOVO_PT_ENABLE_CMD_REG, &pt_en_cmd);
1675 if (rc < 0) {
1676 smblib_err(chg, "Couldn't read QNOVO_PT_ENABLE_CMD_REG rc=%d\n",
1677 rc);
1678 return rc;
1679 }
1680
1681 qnovo_en = (bool)(pt_en_cmd & QNOVO_PT_ENABLE_CMD_BIT);
1682
1683 /* ignore stat7 when qnovo is enabled */
1684 if (!qnovo_en && !stat)
Harry Yang7ecc1a12017-04-06 12:24:56 -07001685 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
1686
Nicholas Troast8cb77552016-09-23 11:50:18 -07001687 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07001688}
1689
1690int smblib_get_prop_batt_charge_type(struct smb_charger *chg,
1691 union power_supply_propval *val)
1692{
1693 int rc;
1694 u8 stat;
1695
1696 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1697 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001698 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001699 rc);
1700 return rc;
1701 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001702
1703 switch (stat & BATTERY_CHARGER_STATUS_MASK) {
1704 case TRICKLE_CHARGE:
1705 case PRE_CHARGE:
1706 val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1707 break;
1708 case FAST_CHARGE:
1709 case FULLON_CHARGE:
1710 val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
1711 break;
1712 case TAPER_CHARGE:
1713 val->intval = POWER_SUPPLY_CHARGE_TYPE_TAPER;
1714 break;
1715 default:
1716 val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
1717 }
1718
1719 return rc;
1720}
1721
1722int smblib_get_prop_batt_health(struct smb_charger *chg,
1723 union power_supply_propval *val)
1724{
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001725 union power_supply_propval pval;
Nicholas Troast34db5032016-03-28 12:26:44 -07001726 int rc;
Abhijeet Dharmapurikar33d18462017-05-15 13:38:53 -07001727 int effective_fv_uv;
Nicholas Troast34db5032016-03-28 12:26:44 -07001728 u8 stat;
1729
1730 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat);
1731 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001732 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001733 rc);
1734 return rc;
1735 }
1736 smblib_dbg(chg, PR_REGISTER, "BATTERY_CHARGER_STATUS_2 = 0x%02x\n",
1737 stat);
1738
1739 if (stat & CHARGER_ERROR_STATUS_BAT_OV_BIT) {
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001740 rc = smblib_get_prop_batt_voltage_now(chg, &pval);
1741 if (!rc) {
1742 /*
1743 * If Vbatt is within 40mV above Vfloat, then don't
1744 * treat it as overvoltage.
1745 */
Abhijeet Dharmapurikar33d18462017-05-15 13:38:53 -07001746 effective_fv_uv = get_effective_result(chg->fv_votable);
1747 if (pval.intval >= effective_fv_uv + 40000) {
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001748 val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
Abhijeet Dharmapurikar33d18462017-05-15 13:38:53 -07001749 smblib_err(chg, "battery over-voltage vbat_fg = %duV, fv = %duV\n",
1750 pval.intval, effective_fv_uv);
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001751 goto done;
1752 }
1753 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001754 }
1755
Harry Yang668fc5e2016-07-12 16:51:47 -07001756 if (stat & BAT_TEMP_STATUS_TOO_COLD_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001757 val->intval = POWER_SUPPLY_HEALTH_COLD;
Harry Yang668fc5e2016-07-12 16:51:47 -07001758 else if (stat & BAT_TEMP_STATUS_TOO_HOT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001759 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
Harry Yang668fc5e2016-07-12 16:51:47 -07001760 else if (stat & BAT_TEMP_STATUS_COLD_SOFT_LIMIT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001761 val->intval = POWER_SUPPLY_HEALTH_COOL;
Harry Yang668fc5e2016-07-12 16:51:47 -07001762 else if (stat & BAT_TEMP_STATUS_HOT_SOFT_LIMIT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001763 val->intval = POWER_SUPPLY_HEALTH_WARM;
Harry Yang668fc5e2016-07-12 16:51:47 -07001764 else
Nicholas Troast34db5032016-03-28 12:26:44 -07001765 val->intval = POWER_SUPPLY_HEALTH_GOOD;
Nicholas Troast34db5032016-03-28 12:26:44 -07001766
1767done:
1768 return rc;
1769}
1770
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001771int smblib_get_prop_system_temp_level(struct smb_charger *chg,
1772 union power_supply_propval *val)
1773{
1774 val->intval = chg->system_temp_level;
1775 return 0;
1776}
1777
Abhijeet Dharmapurikaracf32002017-05-11 11:54:17 -07001778int smblib_get_prop_system_temp_level_max(struct smb_charger *chg,
1779 union power_supply_propval *val)
1780{
1781 val->intval = chg->thermal_levels;
1782 return 0;
1783}
1784
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001785int smblib_get_prop_input_current_limited(struct smb_charger *chg,
1786 union power_supply_propval *val)
1787{
1788 u8 stat;
1789 int rc;
1790
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07001791 if (chg->fake_input_current_limited >= 0) {
1792 val->intval = chg->fake_input_current_limited;
1793 return 0;
1794 }
1795
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001796 rc = smblib_read(chg, AICL_STATUS_REG, &stat);
1797 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001798 smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n", rc);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001799 return rc;
1800 }
1801 val->intval = (stat & SOFT_ILIMIT_BIT) || chg->is_hdc;
1802 return 0;
1803}
1804
Nicholas Troast66b21d72016-09-20 15:33:20 -07001805int smblib_get_prop_batt_voltage_now(struct smb_charger *chg,
1806 union power_supply_propval *val)
1807{
1808 int rc;
1809
1810 if (!chg->bms_psy)
1811 return -EINVAL;
1812
1813 rc = power_supply_get_property(chg->bms_psy,
1814 POWER_SUPPLY_PROP_VOLTAGE_NOW, val);
1815 return rc;
1816}
1817
1818int smblib_get_prop_batt_current_now(struct smb_charger *chg,
1819 union power_supply_propval *val)
1820{
1821 int rc;
1822
1823 if (!chg->bms_psy)
1824 return -EINVAL;
1825
1826 rc = power_supply_get_property(chg->bms_psy,
1827 POWER_SUPPLY_PROP_CURRENT_NOW, val);
1828 return rc;
1829}
1830
1831int smblib_get_prop_batt_temp(struct smb_charger *chg,
1832 union power_supply_propval *val)
1833{
1834 int rc;
1835
1836 if (!chg->bms_psy)
1837 return -EINVAL;
1838
1839 rc = power_supply_get_property(chg->bms_psy,
1840 POWER_SUPPLY_PROP_TEMP, val);
1841 return rc;
1842}
1843
Subbaraman Narayanamurthyb491d022016-10-10 20:22:48 -07001844int smblib_get_prop_batt_charge_done(struct smb_charger *chg,
1845 union power_supply_propval *val)
1846{
1847 int rc;
1848 u8 stat;
1849
1850 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1851 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001852 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Subbaraman Narayanamurthyb491d022016-10-10 20:22:48 -07001853 rc);
1854 return rc;
1855 }
1856
1857 stat = stat & BATTERY_CHARGER_STATUS_MASK;
1858 val->intval = (stat == TERMINATE_CHARGE);
1859 return 0;
1860}
1861
Harry Yang40192cb2017-02-25 23:25:17 -08001862int smblib_get_prop_charge_qnovo_enable(struct smb_charger *chg,
1863 union power_supply_propval *val)
1864{
1865 int rc;
1866 u8 stat;
1867
1868 rc = smblib_read(chg, QNOVO_PT_ENABLE_CMD_REG, &stat);
1869 if (rc < 0) {
1870 smblib_err(chg, "Couldn't read QNOVO_PT_ENABLE_CMD rc=%d\n",
1871 rc);
1872 return rc;
1873 }
1874
1875 val->intval = (bool)(stat & QNOVO_PT_ENABLE_CMD_BIT);
1876 return 0;
1877}
1878
Nicholas Troast4fe68d02017-07-26 14:17:34 -07001879int smblib_get_prop_batt_charge_counter(struct smb_charger *chg,
1880 union power_supply_propval *val)
1881{
1882 int rc;
1883
1884 if (!chg->bms_psy)
1885 return -EINVAL;
1886
1887 rc = power_supply_get_property(chg->bms_psy,
1888 POWER_SUPPLY_PROP_CHARGE_COUNTER, val);
1889 return rc;
1890}
1891
Nicholas Troast34db5032016-03-28 12:26:44 -07001892/***********************
1893 * BATTERY PSY SETTERS *
1894 ***********************/
1895
1896int smblib_set_prop_input_suspend(struct smb_charger *chg,
1897 const union power_supply_propval *val)
1898{
1899 int rc;
1900
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08001901 /* vote 0mA when suspended */
1902 rc = vote(chg->usb_icl_votable, USER_VOTER, (bool)val->intval, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07001903 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001904 smblib_err(chg, "Couldn't vote to %s USB rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001905 (bool)val->intval ? "suspend" : "resume", rc);
1906 return rc;
1907 }
1908
1909 rc = vote(chg->dc_suspend_votable, USER_VOTER, (bool)val->intval, 0);
1910 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001911 smblib_err(chg, "Couldn't vote to %s DC rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001912 (bool)val->intval ? "suspend" : "resume", rc);
1913 return rc;
1914 }
1915
Nicholas Troast61ff40f2016-07-08 10:59:22 -07001916 power_supply_changed(chg->batt_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07001917 return rc;
1918}
1919
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07001920int smblib_set_prop_batt_capacity(struct smb_charger *chg,
1921 const union power_supply_propval *val)
1922{
1923 chg->fake_capacity = val->intval;
1924
1925 power_supply_changed(chg->batt_psy);
1926
1927 return 0;
1928}
1929
Harry Yang589dd422017-07-28 18:41:42 -07001930int smblib_set_prop_batt_status(struct smb_charger *chg,
1931 const union power_supply_propval *val)
1932{
1933 /* Faking battery full */
1934 if (val->intval == POWER_SUPPLY_STATUS_FULL)
1935 chg->fake_batt_status = val->intval;
1936 else
1937 chg->fake_batt_status = -EINVAL;
1938
1939 power_supply_changed(chg->batt_psy);
1940
1941 return 0;
1942}
1943
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001944int smblib_set_prop_system_temp_level(struct smb_charger *chg,
1945 const union power_supply_propval *val)
1946{
1947 if (val->intval < 0)
1948 return -EINVAL;
1949
1950 if (chg->thermal_levels <= 0)
1951 return -EINVAL;
1952
1953 if (val->intval > chg->thermal_levels)
1954 return -EINVAL;
1955
1956 chg->system_temp_level = val->intval;
Ashay Jaiswal147a6c32017-03-28 17:19:47 +05301957 /* disable parallel charge in case of system temp level */
1958 vote(chg->pl_disable_votable, THERMAL_DAEMON_VOTER,
1959 chg->system_temp_level ? true : false, 0);
1960
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001961 if (chg->system_temp_level == chg->thermal_levels)
Harry Yangaba1f5f2016-09-28 10:47:29 -07001962 return vote(chg->chg_disable_votable,
1963 THERMAL_DAEMON_VOTER, true, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001964
Harry Yangaba1f5f2016-09-28 10:47:29 -07001965 vote(chg->chg_disable_votable, THERMAL_DAEMON_VOTER, false, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001966 if (chg->system_temp_level == 0)
Harry Yangaba1f5f2016-09-28 10:47:29 -07001967 return vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, false, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001968
Harry Yangaba1f5f2016-09-28 10:47:29 -07001969 vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, true,
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001970 chg->thermal_mitigation[chg->system_temp_level]);
1971 return 0;
1972}
1973
Harry Yang40192cb2017-02-25 23:25:17 -08001974int smblib_set_prop_charge_qnovo_enable(struct smb_charger *chg,
1975 const union power_supply_propval *val)
1976{
1977 int rc = 0;
1978
1979 rc = smblib_masked_write(chg, QNOVO_PT_ENABLE_CMD_REG,
1980 QNOVO_PT_ENABLE_CMD_BIT,
1981 val->intval ? QNOVO_PT_ENABLE_CMD_BIT : 0);
1982 if (rc < 0) {
1983 dev_err(chg->dev, "Couldn't enable qnovo rc=%d\n", rc);
1984 return rc;
1985 }
1986
1987 return rc;
1988}
1989
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07001990int smblib_set_prop_input_current_limited(struct smb_charger *chg,
1991 const union power_supply_propval *val)
1992{
1993 chg->fake_input_current_limited = val->intval;
1994 return 0;
1995}
1996
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301997int smblib_rerun_aicl(struct smb_charger *chg)
1998{
Nicholas Troast20ae1912017-02-15 10:15:32 -08001999 int rc, settled_icl_ua;
2000 u8 stat;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302001
Nicholas Troast20ae1912017-02-15 10:15:32 -08002002 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
2003 if (rc < 0) {
2004 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
2005 rc);
2006 return rc;
2007 }
2008
2009 /* USB is suspended so skip re-running AICL */
2010 if (stat & USBIN_SUSPEND_STS_BIT)
2011 return rc;
2012
2013 smblib_dbg(chg, PR_MISC, "re-running AICL\n");
Ashay Jaiswal59a14122017-05-16 13:38:52 +05302014 rc = smblib_get_charge_param(chg, &chg->param.icl_stat,
2015 &settled_icl_ua);
2016 if (rc < 0) {
2017 smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
2018 return rc;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302019 }
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302020
Ashay Jaiswal59a14122017-05-16 13:38:52 +05302021 vote(chg->usb_icl_votable, AICL_RERUN_VOTER, true,
2022 max(settled_icl_ua - chg->param.usb_icl.step_u,
2023 chg->param.usb_icl.step_u));
2024 vote(chg->usb_icl_votable, AICL_RERUN_VOTER, false, 0);
2025
Nicholas Troast20ae1912017-02-15 10:15:32 -08002026 return 0;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302027}
2028
2029static int smblib_dp_pulse(struct smb_charger *chg)
2030{
2031 int rc;
2032
2033 /* QC 3.0 increment */
2034 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, SINGLE_INCREMENT_BIT,
2035 SINGLE_INCREMENT_BIT);
2036 if (rc < 0)
2037 smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
2038 rc);
2039
2040 return rc;
2041}
2042
2043static int smblib_dm_pulse(struct smb_charger *chg)
2044{
2045 int rc;
2046
2047 /* QC 3.0 decrement */
2048 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, SINGLE_DECREMENT_BIT,
2049 SINGLE_DECREMENT_BIT);
2050 if (rc < 0)
2051 smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
2052 rc);
2053
2054 return rc;
2055}
2056
2057int smblib_dp_dm(struct smb_charger *chg, int val)
2058{
2059 int target_icl_ua, rc = 0;
Ashay Jaiswalae23a042017-05-18 15:28:31 +05302060 union power_supply_propval pval;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302061
2062 switch (val) {
2063 case POWER_SUPPLY_DP_DM_DP_PULSE:
2064 rc = smblib_dp_pulse(chg);
2065 if (!rc)
2066 chg->pulse_cnt++;
2067 smblib_dbg(chg, PR_PARALLEL, "DP_DM_DP_PULSE rc=%d cnt=%d\n",
2068 rc, chg->pulse_cnt);
2069 break;
2070 case POWER_SUPPLY_DP_DM_DM_PULSE:
2071 rc = smblib_dm_pulse(chg);
2072 if (!rc && chg->pulse_cnt)
2073 chg->pulse_cnt--;
2074 smblib_dbg(chg, PR_PARALLEL, "DP_DM_DM_PULSE rc=%d cnt=%d\n",
2075 rc, chg->pulse_cnt);
2076 break;
2077 case POWER_SUPPLY_DP_DM_ICL_DOWN:
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302078 target_icl_ua = get_effective_result(chg->usb_icl_votable);
Ashay Jaiswalae23a042017-05-18 15:28:31 +05302079 if (target_icl_ua < 0) {
2080 /* no client vote, get the ICL from charger */
2081 rc = power_supply_get_property(chg->usb_psy,
2082 POWER_SUPPLY_PROP_HW_CURRENT_MAX,
2083 &pval);
2084 if (rc < 0) {
2085 smblib_err(chg,
2086 "Couldn't get max current rc=%d\n",
2087 rc);
2088 return rc;
2089 }
2090 target_icl_ua = pval.intval;
2091 }
2092
2093 /*
2094 * Check if any other voter voted on USB_ICL in case of
2095 * voter other than SW_QC3_VOTER reset and restart reduction
2096 * again.
2097 */
2098 if (target_icl_ua != get_client_vote(chg->usb_icl_votable,
2099 SW_QC3_VOTER))
2100 chg->usb_icl_delta_ua = 0;
2101
2102 chg->usb_icl_delta_ua += 100000;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302103 vote(chg->usb_icl_votable, SW_QC3_VOTER, true,
Ashay Jaiswalae23a042017-05-18 15:28:31 +05302104 target_icl_ua - 100000);
2105 smblib_dbg(chg, PR_PARALLEL, "ICL DOWN ICL=%d reduction=%d\n",
2106 target_icl_ua, chg->usb_icl_delta_ua);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302107 break;
2108 case POWER_SUPPLY_DP_DM_ICL_UP:
2109 default:
2110 break;
2111 }
2112
2113 return rc;
2114}
2115
Abhijeet Dharmapurikar3a580042017-07-24 09:43:00 -07002116int smblib_disable_hw_jeita(struct smb_charger *chg, bool disable)
2117{
2118 int rc;
2119 u8 mask;
2120
2121 /*
2122 * Disable h/w base JEITA compensation if s/w JEITA is enabled
2123 */
2124 mask = JEITA_EN_COLD_SL_FCV_BIT
2125 | JEITA_EN_HOT_SL_FCV_BIT
2126 | JEITA_EN_HOT_SL_CCC_BIT
2127 | JEITA_EN_COLD_SL_CCC_BIT,
2128 rc = smblib_masked_write(chg, JEITA_EN_CFG_REG, mask,
2129 disable ? 0 : mask);
2130 if (rc < 0) {
2131 dev_err(chg->dev,
2132 "Couldn't configure s/w jeita rc=%d\n",
2133 rc);
2134 return rc;
2135 }
2136 return 0;
2137}
2138
Nicholas Troast34db5032016-03-28 12:26:44 -07002139/*******************
Harry Yangf3023592016-07-20 14:56:41 -07002140 * DC PSY GETTERS *
2141 *******************/
2142
2143int smblib_get_prop_dc_present(struct smb_charger *chg,
2144 union power_supply_propval *val)
2145{
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002146 int rc;
Harry Yangf3023592016-07-20 14:56:41 -07002147 u8 stat;
2148
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002149 rc = smblib_read(chg, DCIN_BASE + INT_RT_STS_OFFSET, &stat);
Harry Yangf3023592016-07-20 14:56:41 -07002150 if (rc < 0) {
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002151 smblib_err(chg, "Couldn't read DCIN_RT_STS rc=%d\n", rc);
Harry Yangf3023592016-07-20 14:56:41 -07002152 return rc;
2153 }
Harry Yangf3023592016-07-20 14:56:41 -07002154
2155 val->intval = (bool)(stat & DCIN_PLUGIN_RT_STS_BIT);
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002156 return 0;
Harry Yangf3023592016-07-20 14:56:41 -07002157}
2158
2159int smblib_get_prop_dc_online(struct smb_charger *chg,
2160 union power_supply_propval *val)
2161{
2162 int rc = 0;
2163 u8 stat;
2164
2165 if (get_client_vote(chg->dc_suspend_votable, USER_VOTER)) {
2166 val->intval = false;
2167 return rc;
2168 }
2169
2170 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
2171 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002172 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
Harry Yangf3023592016-07-20 14:56:41 -07002173 rc);
2174 return rc;
2175 }
2176 smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
2177 stat);
2178
2179 val->intval = (stat & USE_DCIN_BIT) &&
Vic Wei7ade2842016-12-14 18:47:49 -08002180 (stat & VALID_INPUT_POWER_SOURCE_STS_BIT);
Harry Yangf3023592016-07-20 14:56:41 -07002181
2182 return rc;
2183}
2184
2185int smblib_get_prop_dc_current_max(struct smb_charger *chg,
2186 union power_supply_propval *val)
2187{
2188 val->intval = get_effective_result_locked(chg->dc_icl_votable);
2189 return 0;
2190}
2191
2192/*******************
Harry Yangd89ff1f2016-12-05 14:59:11 -08002193 * DC PSY SETTERS *
Harry Yangf3023592016-07-20 14:56:41 -07002194 * *****************/
2195
2196int smblib_set_prop_dc_current_max(struct smb_charger *chg,
2197 const union power_supply_propval *val)
2198{
2199 int rc;
2200
2201 rc = vote(chg->dc_icl_votable, USER_VOTER, true, val->intval);
2202 return rc;
2203}
2204
2205/*******************
Nicholas Troast34db5032016-03-28 12:26:44 -07002206 * USB PSY GETTERS *
2207 *******************/
2208
2209int smblib_get_prop_usb_present(struct smb_charger *chg,
2210 union power_supply_propval *val)
2211{
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002212 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07002213 u8 stat;
2214
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002215 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
Nicholas Troast34db5032016-03-28 12:26:44 -07002216 if (rc < 0) {
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002217 smblib_err(chg, "Couldn't read USBIN_RT_STS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07002218 return rc;
2219 }
Nicholas Troast34db5032016-03-28 12:26:44 -07002220
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002221 val->intval = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
2222 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002223}
2224
2225int smblib_get_prop_usb_online(struct smb_charger *chg,
2226 union power_supply_propval *val)
2227{
2228 int rc = 0;
2229 u8 stat;
2230
Abhijeet Dharmapurikar84923af2017-03-23 14:07:07 -07002231 if (get_client_vote_locked(chg->usb_icl_votable, USER_VOTER) == 0) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002232 val->intval = false;
2233 return rc;
2234 }
2235
2236 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
2237 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002238 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002239 rc);
2240 return rc;
2241 }
2242 smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
2243 stat);
2244
2245 val->intval = (stat & USE_USBIN_BIT) &&
Vic Wei7ade2842016-12-14 18:47:49 -08002246 (stat & VALID_INPUT_POWER_SOURCE_STS_BIT);
Nicholas Troast34db5032016-03-28 12:26:44 -07002247 return rc;
2248}
2249
Nicholas Troast7f55c922017-07-25 13:18:03 -07002250int smblib_get_prop_usb_voltage_max(struct smb_charger *chg,
2251 union power_supply_propval *val)
2252{
2253 switch (chg->real_charger_type) {
2254 case POWER_SUPPLY_TYPE_USB_HVDCP:
2255 case POWER_SUPPLY_TYPE_USB_PD:
2256 if (chg->smb_version == PM660_SUBTYPE)
2257 val->intval = MICRO_9V;
2258 else
2259 val->intval = MICRO_12V;
2260 break;
2261 default:
2262 val->intval = MICRO_5V;
2263 break;
2264 }
2265
2266 return 0;
2267}
2268
Nicholas Troast34db5032016-03-28 12:26:44 -07002269int smblib_get_prop_usb_voltage_now(struct smb_charger *chg,
2270 union power_supply_propval *val)
2271{
Harry Yangba874ce2016-08-19 14:17:01 -07002272 if (!chg->iio.usbin_v_chan ||
2273 PTR_ERR(chg->iio.usbin_v_chan) == -EPROBE_DEFER)
2274 chg->iio.usbin_v_chan = iio_channel_get(chg->dev, "usbin_v");
2275
2276 if (IS_ERR(chg->iio.usbin_v_chan))
2277 return PTR_ERR(chg->iio.usbin_v_chan);
2278
2279 return iio_read_channel_processed(chg->iio.usbin_v_chan, &val->intval);
Nicholas Troast34db5032016-03-28 12:26:44 -07002280}
2281
Harry Yangba874ce2016-08-19 14:17:01 -07002282int smblib_get_prop_usb_current_now(struct smb_charger *chg,
2283 union power_supply_propval *val)
2284{
2285 int rc = 0;
2286
2287 rc = smblib_get_prop_usb_present(chg, val);
2288 if (rc < 0 || !val->intval)
2289 return rc;
2290
2291 if (!chg->iio.usbin_i_chan ||
2292 PTR_ERR(chg->iio.usbin_i_chan) == -EPROBE_DEFER)
2293 chg->iio.usbin_i_chan = iio_channel_get(chg->dev, "usbin_i");
2294
2295 if (IS_ERR(chg->iio.usbin_i_chan))
2296 return PTR_ERR(chg->iio.usbin_i_chan);
2297
2298 return iio_read_channel_processed(chg->iio.usbin_i_chan, &val->intval);
2299}
2300
2301int smblib_get_prop_charger_temp(struct smb_charger *chg,
2302 union power_supply_propval *val)
2303{
2304 int rc;
2305
2306 if (!chg->iio.temp_chan ||
2307 PTR_ERR(chg->iio.temp_chan) == -EPROBE_DEFER)
2308 chg->iio.temp_chan = iio_channel_get(chg->dev, "charger_temp");
2309
2310 if (IS_ERR(chg->iio.temp_chan))
2311 return PTR_ERR(chg->iio.temp_chan);
2312
2313 rc = iio_read_channel_processed(chg->iio.temp_chan, &val->intval);
2314 val->intval /= 100;
2315 return rc;
2316}
2317
2318int smblib_get_prop_charger_temp_max(struct smb_charger *chg,
2319 union power_supply_propval *val)
2320{
2321 int rc;
2322
2323 if (!chg->iio.temp_max_chan ||
2324 PTR_ERR(chg->iio.temp_max_chan) == -EPROBE_DEFER)
2325 chg->iio.temp_max_chan = iio_channel_get(chg->dev,
2326 "charger_temp_max");
2327 if (IS_ERR(chg->iio.temp_max_chan))
2328 return PTR_ERR(chg->iio.temp_max_chan);
2329
2330 rc = iio_read_channel_processed(chg->iio.temp_max_chan, &val->intval);
2331 val->intval /= 100;
2332 return rc;
2333}
2334
Nicholas Troast34db5032016-03-28 12:26:44 -07002335int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
2336 union power_supply_propval *val)
2337{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002338 if (chg->typec_status[3] & CC_ATTACHED_BIT)
2339 val->intval =
2340 (bool)(chg->typec_status[3] & CC_ORIENTATION_BIT) + 1;
Nicholas Troast34db5032016-03-28 12:26:44 -07002341 else
2342 val->intval = 0;
2343
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002344 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002345}
2346
2347static const char * const smblib_typec_mode_name[] = {
2348 [POWER_SUPPLY_TYPEC_NONE] = "NONE",
2349 [POWER_SUPPLY_TYPEC_SOURCE_DEFAULT] = "SOURCE_DEFAULT",
2350 [POWER_SUPPLY_TYPEC_SOURCE_MEDIUM] = "SOURCE_MEDIUM",
2351 [POWER_SUPPLY_TYPEC_SOURCE_HIGH] = "SOURCE_HIGH",
2352 [POWER_SUPPLY_TYPEC_NON_COMPLIANT] = "NON_COMPLIANT",
2353 [POWER_SUPPLY_TYPEC_SINK] = "SINK",
2354 [POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE] = "SINK_POWERED_CABLE",
2355 [POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY] = "SINK_DEBUG_ACCESSORY",
2356 [POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER] = "SINK_AUDIO_ADAPTER",
2357 [POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY] = "POWERED_CABLE_ONLY",
2358};
2359
2360static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
2361{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002362 switch (chg->typec_status[0]) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002363 case UFP_TYPEC_RDSTD_BIT:
2364 return POWER_SUPPLY_TYPEC_SOURCE_DEFAULT;
2365 case UFP_TYPEC_RD1P5_BIT:
2366 return POWER_SUPPLY_TYPEC_SOURCE_MEDIUM;
2367 case UFP_TYPEC_RD3P0_BIT:
2368 return POWER_SUPPLY_TYPEC_SOURCE_HIGH;
2369 default:
2370 break;
2371 }
2372
Nicholas Troaste1932e42017-04-12 12:38:18 -07002373 return POWER_SUPPLY_TYPEC_NONE;
Nicholas Troast34db5032016-03-28 12:26:44 -07002374}
2375
2376static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
2377{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002378 switch (chg->typec_status[1] & DFP_TYPEC_MASK) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002379 case DFP_RA_RA_BIT:
2380 return POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER;
2381 case DFP_RD_RD_BIT:
2382 return POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY;
2383 case DFP_RD_RA_VCONN_BIT:
2384 return POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE;
2385 case DFP_RD_OPEN_BIT:
2386 return POWER_SUPPLY_TYPEC_SINK;
Nicholas Troast34db5032016-03-28 12:26:44 -07002387 default:
2388 break;
2389 }
2390
2391 return POWER_SUPPLY_TYPEC_NONE;
2392}
2393
Nicholas Troaste1932e42017-04-12 12:38:18 -07002394static int smblib_get_prop_typec_mode(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07002395{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002396 if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
Nicholas Troaste1932e42017-04-12 12:38:18 -07002397 return smblib_get_prop_dfp_mode(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07002398 else
Nicholas Troaste1932e42017-04-12 12:38:18 -07002399 return smblib_get_prop_ufp_mode(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07002400}
2401
2402int smblib_get_prop_typec_power_role(struct smb_charger *chg,
2403 union power_supply_propval *val)
2404{
2405 int rc = 0;
2406 u8 ctrl;
2407
2408 rc = smblib_read(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &ctrl);
2409 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002410 smblib_err(chg, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002411 rc);
2412 return rc;
2413 }
2414 smblib_dbg(chg, PR_REGISTER, "TYPE_C_INTRPT_ENB_SOFTWARE_CTRL = 0x%02x\n",
2415 ctrl);
2416
2417 if (ctrl & TYPEC_DISABLE_CMD_BIT) {
2418 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
2419 return rc;
2420 }
2421
2422 switch (ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT)) {
2423 case 0:
2424 val->intval = POWER_SUPPLY_TYPEC_PR_DUAL;
2425 break;
2426 case DFP_EN_CMD_BIT:
2427 val->intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
2428 break;
2429 case UFP_EN_CMD_BIT:
2430 val->intval = POWER_SUPPLY_TYPEC_PR_SINK;
2431 break;
2432 default:
2433 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002434 smblib_err(chg, "unsupported power role 0x%02lx\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002435 ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT));
2436 return -EINVAL;
2437 }
2438
2439 return rc;
2440}
2441
2442int smblib_get_prop_pd_allowed(struct smb_charger *chg,
2443 union power_supply_propval *val)
2444{
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07002445 val->intval = get_effective_result(chg->pd_allowed_votable);
Nicholas Troast34db5032016-03-28 12:26:44 -07002446 return 0;
2447}
2448
Nicholas Troast133a7f52016-06-29 13:48:20 -07002449int smblib_get_prop_input_current_settled(struct smb_charger *chg,
2450 union power_supply_propval *val)
2451{
2452 return smblib_get_charge_param(chg, &chg->param.icl_stat, &val->intval);
2453}
2454
Fenglin Wuef4730e2017-01-11 18:16:25 +08002455#define HVDCP3_STEP_UV 200000
2456int smblib_get_prop_input_voltage_settled(struct smb_charger *chg,
2457 union power_supply_propval *val)
2458{
Fenglin Wuef4730e2017-01-11 18:16:25 +08002459 int rc, pulses;
Fenglin Wuef4730e2017-01-11 18:16:25 +08002460
Nicholas Troast5f314c12017-05-25 11:58:02 -07002461 switch (chg->real_charger_type) {
Fenglin Wuef4730e2017-01-11 18:16:25 +08002462 case POWER_SUPPLY_TYPE_USB_HVDCP_3:
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +05302463 rc = smblib_get_pulse_cnt(chg, &pulses);
Fenglin Wuef4730e2017-01-11 18:16:25 +08002464 if (rc < 0) {
2465 smblib_err(chg,
2466 "Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
2467 return 0;
2468 }
Fenglin Wuef4730e2017-01-11 18:16:25 +08002469 val->intval = MICRO_5V + HVDCP3_STEP_UV * pulses;
2470 break;
Nicholas Troast5f314c12017-05-25 11:58:02 -07002471 case POWER_SUPPLY_TYPE_USB_PD:
2472 val->intval = chg->voltage_min_uv;
2473 break;
Fenglin Wuef4730e2017-01-11 18:16:25 +08002474 default:
2475 val->intval = MICRO_5V;
2476 break;
2477 }
2478
2479 return 0;
2480}
2481
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002482int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg,
2483 union power_supply_propval *val)
2484{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002485 val->intval = chg->pd_hard_reset;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002486 return 0;
2487}
2488
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07002489int smblib_get_pe_start(struct smb_charger *chg,
2490 union power_supply_propval *val)
2491{
2492 /*
2493 * hvdcp timeout voter is the last one to allow pd. Use its vote
2494 * to indicate start of pe engine
2495 */
2496 val->intval
2497 = !get_client_vote_locked(chg->pd_disallowed_votable_indirect,
2498 HVDCP_TIMEOUT_VOTER);
2499 return 0;
2500}
2501
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002502int smblib_get_prop_die_health(struct smb_charger *chg,
Nicholas Troastb021dd92017-01-31 18:43:38 -08002503 union power_supply_propval *val)
2504{
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002505 int rc;
Nicholas Troastb021dd92017-01-31 18:43:38 -08002506 u8 stat;
2507
2508 rc = smblib_read(chg, TEMP_RANGE_STATUS_REG, &stat);
2509 if (rc < 0) {
2510 smblib_err(chg, "Couldn't read TEMP_RANGE_STATUS_REG rc=%d\n",
2511 rc);
2512 return rc;
2513 }
2514
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002515 /* TEMP_RANGE bits are mutually exclusive */
2516 switch (stat & TEMP_RANGE_MASK) {
2517 case TEMP_BELOW_RANGE_BIT:
2518 val->intval = POWER_SUPPLY_HEALTH_COOL;
2519 break;
2520 case TEMP_WITHIN_RANGE_BIT:
2521 val->intval = POWER_SUPPLY_HEALTH_WARM;
2522 break;
2523 case TEMP_ABOVE_RANGE_BIT:
2524 val->intval = POWER_SUPPLY_HEALTH_HOT;
2525 break;
2526 case ALERT_LEVEL_BIT:
2527 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
2528 break;
2529 default:
2530 val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
Nicholas Troastb021dd92017-01-31 18:43:38 -08002531 }
2532
Nicholas Troastb021dd92017-01-31 18:43:38 -08002533 return 0;
2534}
2535
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05302536#define SDP_CURRENT_UA 500000
2537#define CDP_CURRENT_UA 1500000
2538#define DCP_CURRENT_UA 1500000
2539#define HVDCP_CURRENT_UA 3000000
2540#define TYPEC_DEFAULT_CURRENT_UA 900000
2541#define TYPEC_MEDIUM_CURRENT_UA 1500000
2542#define TYPEC_HIGH_CURRENT_UA 3000000
2543static int get_rp_based_dcp_current(struct smb_charger *chg, int typec_mode)
2544{
2545 int rp_ua;
2546
2547 switch (typec_mode) {
2548 case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
2549 rp_ua = TYPEC_HIGH_CURRENT_UA;
2550 break;
2551 case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
2552 case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
2553 /* fall through */
2554 default:
2555 rp_ua = DCP_CURRENT_UA;
2556 }
2557
2558 return rp_ua;
2559}
2560
Nicholas Troast34db5032016-03-28 12:26:44 -07002561/*******************
2562 * USB PSY SETTERS *
2563 * *****************/
2564
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002565int smblib_set_prop_pd_current_max(struct smb_charger *chg,
2566 const union power_supply_propval *val)
2567{
2568 int rc;
2569
2570 if (chg->pd_active)
2571 rc = vote(chg->usb_icl_votable, PD_VOTER, true, val->intval);
2572 else
2573 rc = -EPERM;
2574
2575 return rc;
2576}
2577
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05302578static int smblib_handle_usb_current(struct smb_charger *chg,
2579 int usb_current)
2580{
2581 int rc = 0, rp_ua, typec_mode;
2582
2583 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_FLOAT) {
2584 if (usb_current == -ETIMEDOUT) {
2585 /*
2586 * Valid FLOAT charger, report the current based
2587 * of Rp
2588 */
2589 typec_mode = smblib_get_prop_typec_mode(chg);
2590 rp_ua = get_rp_based_dcp_current(chg, typec_mode);
2591 rc = vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER,
2592 true, rp_ua);
2593 if (rc < 0)
2594 return rc;
2595 } else {
2596 /*
2597 * FLOAT charger detected as SDP by USB driver,
2598 * charge with the requested current and update the
2599 * real_charger_type
2600 */
2601 chg->real_charger_type = POWER_SUPPLY_TYPE_USB;
2602 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
2603 true, usb_current);
2604 if (rc < 0)
2605 return rc;
2606 rc = vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER,
2607 false, 0);
2608 if (rc < 0)
2609 return rc;
2610 }
2611 } else {
2612 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
2613 true, usb_current);
2614 }
2615
2616 return rc;
2617}
2618
Nicholas Troast7f55c922017-07-25 13:18:03 -07002619int smblib_set_prop_sdp_current_max(struct smb_charger *chg,
Nicholas Troast34db5032016-03-28 12:26:44 -07002620 const union power_supply_propval *val)
2621{
Nicholas Troast8d33b7d2017-01-16 11:18:38 -08002622 int rc = 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002623
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002624 if (!chg->pd_active) {
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05302625 rc = smblib_handle_usb_current(chg, val->intval);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002626 } else if (chg->system_suspend_supported) {
2627 if (val->intval <= USBIN_25MA)
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302628 rc = vote(chg->usb_icl_votable,
2629 PD_SUSPEND_SUPPORTED_VOTER, true, val->intval);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002630 else
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302631 rc = vote(chg->usb_icl_votable,
2632 PD_SUSPEND_SUPPORTED_VOTER, false, 0);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002633 }
Nicholas Troast34db5032016-03-28 12:26:44 -07002634 return rc;
2635}
2636
Harry Yangd89ff1f2016-12-05 14:59:11 -08002637int smblib_set_prop_boost_current(struct smb_charger *chg,
2638 const union power_supply_propval *val)
2639{
2640 int rc = 0;
2641
2642 rc = smblib_set_charge_param(chg, &chg->param.freq_boost,
2643 val->intval <= chg->boost_threshold_ua ?
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05302644 chg->chg_freq.freq_below_otg_threshold :
2645 chg->chg_freq.freq_above_otg_threshold);
Harry Yangd89ff1f2016-12-05 14:59:11 -08002646 if (rc < 0) {
2647 dev_err(chg->dev, "Error in setting freq_boost rc=%d\n", rc);
2648 return rc;
2649 }
2650
2651 chg->boost_current_ua = val->intval;
2652 return rc;
2653}
2654
Nicholas Troast34db5032016-03-28 12:26:44 -07002655int smblib_set_prop_typec_power_role(struct smb_charger *chg,
2656 const union power_supply_propval *val)
2657{
2658 int rc = 0;
2659 u8 power_role;
2660
2661 switch (val->intval) {
2662 case POWER_SUPPLY_TYPEC_PR_NONE:
2663 power_role = TYPEC_DISABLE_CMD_BIT;
2664 break;
2665 case POWER_SUPPLY_TYPEC_PR_DUAL:
2666 power_role = 0;
2667 break;
2668 case POWER_SUPPLY_TYPEC_PR_SINK:
2669 power_role = UFP_EN_CMD_BIT;
2670 break;
2671 case POWER_SUPPLY_TYPEC_PR_SOURCE:
2672 power_role = DFP_EN_CMD_BIT;
2673 break;
2674 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002675 smblib_err(chg, "power role %d not supported\n", val->intval);
Nicholas Troast34db5032016-03-28 12:26:44 -07002676 return -EINVAL;
2677 }
2678
Jack Pham54a39bd2017-03-29 18:59:37 -07002679 if (power_role == UFP_EN_CMD_BIT) {
2680 /* disable PBS workaround when forcing sink mode */
2681 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0x0);
2682 if (rc < 0) {
2683 smblib_err(chg, "Couldn't write to TM_IO_DTEST4_SEL rc=%d\n",
2684 rc);
2685 }
2686 } else {
2687 /* restore it back to 0xA5 */
2688 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
2689 if (rc < 0) {
2690 smblib_err(chg, "Couldn't write to TM_IO_DTEST4_SEL rc=%d\n",
2691 rc);
2692 }
2693 }
2694
Nicholas Troast34db5032016-03-28 12:26:44 -07002695 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2696 TYPEC_POWER_ROLE_CMD_MASK, power_role);
2697 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002698 smblib_err(chg, "Couldn't write 0x%02x to TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002699 power_role, rc);
2700 return rc;
2701 }
2702
2703 return rc;
2704}
2705
Nicholas Troast7f55c922017-07-25 13:18:03 -07002706int smblib_set_prop_pd_voltage_min(struct smb_charger *chg,
Nicholas Troast34db5032016-03-28 12:26:44 -07002707 const union power_supply_propval *val)
2708{
2709 int rc, min_uv;
2710
2711 min_uv = min(val->intval, chg->voltage_max_uv);
2712 rc = smblib_set_usb_pd_allowed_voltage(chg, min_uv,
2713 chg->voltage_max_uv);
2714 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002715 smblib_err(chg, "invalid max voltage %duV rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002716 val->intval, rc);
2717 return rc;
2718 }
2719
Harry Yangaba1f5f2016-09-28 10:47:29 -07002720 chg->voltage_min_uv = min_uv;
Nicholas Troast5f314c12017-05-25 11:58:02 -07002721 power_supply_changed(chg->usb_main_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07002722 return rc;
2723}
2724
Nicholas Troast7f55c922017-07-25 13:18:03 -07002725int smblib_set_prop_pd_voltage_max(struct smb_charger *chg,
Nicholas Troast34db5032016-03-28 12:26:44 -07002726 const union power_supply_propval *val)
2727{
2728 int rc, max_uv;
2729
2730 max_uv = max(val->intval, chg->voltage_min_uv);
2731 rc = smblib_set_usb_pd_allowed_voltage(chg, chg->voltage_min_uv,
2732 max_uv);
2733 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002734 smblib_err(chg, "invalid min voltage %duV rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002735 val->intval, rc);
2736 return rc;
2737 }
2738
Harry Yangaba1f5f2016-09-28 10:47:29 -07002739 chg->voltage_max_uv = max_uv;
Nicholas Troast34db5032016-03-28 12:26:44 -07002740 return rc;
2741}
2742
2743int smblib_set_prop_pd_active(struct smb_charger *chg,
2744 const union power_supply_propval *val)
2745{
2746 int rc;
Nicholas Troaste1932e42017-04-12 12:38:18 -07002747 bool orientation, sink_attached, hvdcp;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002748 u8 stat;
Nicholas Troast34db5032016-03-28 12:26:44 -07002749
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002750 if (!get_effective_result(chg->pd_allowed_votable))
Nicholas Troast34db5032016-03-28 12:26:44 -07002751 return -EINVAL;
Nicholas Troast34db5032016-03-28 12:26:44 -07002752
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002753 chg->pd_active = val->intval;
2754 if (chg->pd_active) {
2755 vote(chg->apsd_disable_votable, PD_VOTER, true, 0);
2756 vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
2757 vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
2758
2759 /*
2760 * VCONN_EN_ORIENTATION_BIT controls whether to use CC1 or CC2
2761 * line when TYPEC_SPARE_CFG_BIT (CC pin selection s/w override)
2762 * is set or when VCONN_EN_VALUE_BIT is set.
2763 */
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002764 orientation = chg->typec_status[3] & CC_ORIENTATION_BIT;
Harry Yang88acff42016-09-21 14:56:06 -07002765 rc = smblib_masked_write(chg,
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07002766 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2767 VCONN_EN_ORIENTATION_BIT,
2768 orientation ? 0 : VCONN_EN_ORIENTATION_BIT);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002769 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002770 smblib_err(chg,
Harry Yang88acff42016-09-21 14:56:06 -07002771 "Couldn't enable vconn on CC line rc=%d\n", rc);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002772
2773 /* SW controlled CC_OUT */
2774 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
2775 TYPEC_SPARE_CFG_BIT, TYPEC_SPARE_CFG_BIT);
2776 if (rc < 0)
2777 smblib_err(chg, "Couldn't enable SW cc_out rc=%d\n",
2778 rc);
2779
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302780 /*
2781 * Enforce 500mA for PD until the real vote comes in later.
2782 * It is guaranteed that pd_active is set prior to
2783 * pd_current_max
2784 */
Harry Yangcd995202016-11-07 13:32:52 -08002785 rc = vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002786 if (rc < 0)
Harry Yangcd995202016-11-07 13:32:52 -08002787 smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n",
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002788 rc);
Harry Yangcd995202016-11-07 13:32:52 -08002789
Nicholas Troastf9e44992017-03-14 09:06:56 -07002790 /* since PD was found the cable must be non-legacy */
2791 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
2792
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002793 /* clear USB ICL vote for DCP_VOTER */
Harry Yang631b99e2016-11-17 11:24:25 -08002794 rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002795 if (rc < 0)
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002796 smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n",
2797 rc);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002798
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302799 /* remove USB_PSY_VOTER */
2800 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002801 if (rc < 0)
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302802 smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002803 } else {
Nicholas Troaste1932e42017-04-12 12:38:18 -07002804 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
2805 if (rc < 0) {
2806 smblib_err(chg, "Couldn't read APSD status rc=%d\n",
2807 rc);
2808 return rc;
2809 }
2810
2811 hvdcp = stat & QC_CHARGER_BIT;
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002812 vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
2813 vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
2814 vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002815 vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER,
2816 false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002817
2818 /* HW controlled CC_OUT */
2819 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
2820 TYPEC_SPARE_CFG_BIT, 0);
2821 if (rc < 0)
2822 smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n",
2823 rc);
2824
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002825 /*
2826 * This WA should only run for HVDCP. Non-legacy SDP/CDP could
2827 * draw more, but this WA will remove Rd causing VBUS to drop,
2828 * and data could be interrupted. Non-legacy DCP could also draw
2829 * more, but it may impact compliance.
2830 */
Nicholas Troaste1932e42017-04-12 12:38:18 -07002831 sink_attached = chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT;
2832 if (!chg->typec_legacy_valid && !sink_attached && hvdcp)
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002833 schedule_work(&chg->legacy_detection_work);
Harry Yang88acff42016-09-21 14:56:06 -07002834 }
2835
Harry Yang6607b4a2016-05-17 17:50:09 -07002836 smblib_update_usb_type(chg);
Abhijeet Dharmapurikar76e2af52016-10-06 17:25:01 -07002837 power_supply_changed(chg->usb_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07002838 return rc;
2839}
2840
Fenglin Wuedd70792016-11-22 13:16:19 +08002841int smblib_set_prop_ship_mode(struct smb_charger *chg,
2842 const union power_supply_propval *val)
2843{
2844 int rc;
2845
2846 smblib_dbg(chg, PR_MISC, "Set ship mode: %d!!\n", !!val->intval);
2847
2848 rc = smblib_masked_write(chg, SHIP_MODE_REG, SHIP_MODE_EN_BIT,
2849 !!val->intval ? SHIP_MODE_EN_BIT : 0);
2850 if (rc < 0)
2851 dev_err(chg->dev, "Couldn't %s ship mode, rc=%d\n",
2852 !!val->intval ? "enable" : "disable", rc);
2853
2854 return rc;
2855}
2856
Harry Yang5e2bb712016-10-18 16:47:48 -07002857int smblib_reg_block_update(struct smb_charger *chg,
2858 struct reg_info *entry)
2859{
2860 int rc = 0;
2861
2862 while (entry && entry->reg) {
2863 rc = smblib_read(chg, entry->reg, &entry->bak);
2864 if (rc < 0) {
2865 dev_err(chg->dev, "Error in reading %s rc=%d\n",
2866 entry->desc, rc);
2867 break;
2868 }
2869 entry->bak &= entry->mask;
2870
2871 rc = smblib_masked_write(chg, entry->reg,
2872 entry->mask, entry->val);
2873 if (rc < 0) {
2874 dev_err(chg->dev, "Error in writing %s rc=%d\n",
2875 entry->desc, rc);
2876 break;
2877 }
2878 entry++;
2879 }
2880
2881 return rc;
2882}
2883
2884int smblib_reg_block_restore(struct smb_charger *chg,
2885 struct reg_info *entry)
2886{
2887 int rc = 0;
2888
2889 while (entry && entry->reg) {
2890 rc = smblib_masked_write(chg, entry->reg,
2891 entry->mask, entry->bak);
2892 if (rc < 0) {
2893 dev_err(chg->dev, "Error in writing %s rc=%d\n",
2894 entry->desc, rc);
2895 break;
2896 }
2897 entry++;
2898 }
2899
2900 return rc;
2901}
2902
Harry Yang755a34b2016-11-01 01:18:51 -07002903static struct reg_info cc2_detach_settings[] = {
2904 {
2905 .reg = TYPE_C_CFG_2_REG,
2906 .mask = TYPE_C_UFP_MODE_BIT | EN_TRY_SOURCE_MODE_BIT,
2907 .val = TYPE_C_UFP_MODE_BIT,
2908 .desc = "TYPE_C_CFG_2_REG",
2909 },
2910 {
2911 .reg = TYPE_C_CFG_3_REG,
2912 .mask = EN_TRYSINK_MODE_BIT,
2913 .val = 0,
2914 .desc = "TYPE_C_CFG_3_REG",
2915 },
2916 {
2917 .reg = TAPER_TIMER_SEL_CFG_REG,
2918 .mask = TYPEC_SPARE_CFG_BIT,
2919 .val = TYPEC_SPARE_CFG_BIT,
2920 .desc = "TAPER_TIMER_SEL_CFG_REG",
2921 },
2922 {
2923 .reg = TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2924 .mask = VCONN_EN_ORIENTATION_BIT,
2925 .val = 0,
2926 .desc = "TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG",
2927 },
2928 {
2929 .reg = MISC_CFG_REG,
2930 .mask = TCC_DEBOUNCE_20MS_BIT,
2931 .val = TCC_DEBOUNCE_20MS_BIT,
2932 .desc = "Tccdebounce time"
2933 },
2934 {
2935 },
2936};
2937
2938static int smblib_cc2_sink_removal_enter(struct smb_charger *chg)
2939{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002940 int rc, ccout, ufp_mode;
2941 u8 stat;
Harry Yang755a34b2016-11-01 01:18:51 -07002942
2943 if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002944 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002945
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002946 if (chg->cc2_detach_wa_active)
2947 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002948
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002949 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
Harry Yang755a34b2016-11-01 01:18:51 -07002950 if (rc < 0) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002951 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
Harry Yang755a34b2016-11-01 01:18:51 -07002952 return rc;
2953 }
Nicholas Troaste1932e42017-04-12 12:38:18 -07002954
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002955 ccout = (stat & CC_ATTACHED_BIT) ?
2956 (!!(stat & CC_ORIENTATION_BIT) + 1) : 0;
2957 ufp_mode = (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT) ?
2958 !(stat & UFP_DFP_MODE_STATUS_BIT) : 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002959
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002960 if (ccout != 2)
2961 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002962
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002963 if (!ufp_mode)
2964 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002965
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002966 chg->cc2_detach_wa_active = true;
2967 /* The CC2 removal WA will cause a type-c-change IRQ storm */
2968 smblib_reg_block_update(chg, cc2_detach_settings);
2969 schedule_work(&chg->rdstd_cc2_detach_work);
Harry Yang755a34b2016-11-01 01:18:51 -07002970 return rc;
2971}
2972
2973static int smblib_cc2_sink_removal_exit(struct smb_charger *chg)
2974{
Harry Yang755a34b2016-11-01 01:18:51 -07002975 if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002976 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002977
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002978 if (!chg->cc2_detach_wa_active)
2979 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002980
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002981 chg->cc2_detach_wa_active = false;
2982 cancel_work_sync(&chg->rdstd_cc2_detach_work);
2983 smblib_reg_block_restore(chg, cc2_detach_settings);
2984 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002985}
2986
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002987int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
2988 const union power_supply_propval *val)
2989{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002990 int rc = 0;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002991
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002992 if (chg->pd_hard_reset == val->intval)
2993 return rc;
2994
2995 chg->pd_hard_reset = val->intval;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002996 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002997 EXIT_SNK_BASED_ON_CC_BIT,
2998 (chg->pd_hard_reset) ? EXIT_SNK_BASED_ON_CC_BIT : 0);
2999 if (rc < 0)
3000 smblib_err(chg, "Couldn't set EXIT_SNK_BASED_ON_CC rc=%d\n",
Harry Yang755a34b2016-11-01 01:18:51 -07003001 rc);
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07003002
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003003 vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER,
3004 chg->pd_hard_reset, 0);
Harry Yang755a34b2016-11-01 01:18:51 -07003005
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07003006 return rc;
3007}
3008
Anirudh Ghayal941acaa2017-07-19 16:04:44 +05303009static int smblib_recover_from_soft_jeita(struct smb_charger *chg)
3010{
3011 u8 stat_1, stat_2;
3012 int rc;
3013
3014 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat_1);
3015 if (rc < 0) {
3016 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
3017 rc);
3018 return rc;
3019 }
3020
3021 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat_2);
3022 if (rc < 0) {
3023 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
3024 rc);
3025 return rc;
3026 }
3027
3028 if ((chg->jeita_status && !(stat_2 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK) &&
3029 ((stat_1 & BATTERY_CHARGER_STATUS_MASK) == TERMINATE_CHARGE))) {
3030 /*
3031 * We are moving from JEITA soft -> Normal and charging
3032 * is terminated
3033 */
3034 rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG, 0);
3035 if (rc < 0) {
3036 smblib_err(chg, "Couldn't disable charging rc=%d\n",
3037 rc);
3038 return rc;
3039 }
3040 rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG,
3041 CHARGING_ENABLE_CMD_BIT);
3042 if (rc < 0) {
3043 smblib_err(chg, "Couldn't enable charging rc=%d\n",
3044 rc);
3045 return rc;
3046 }
3047 }
3048
3049 chg->jeita_status = stat_2 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK;
3050
3051 return 0;
3052}
3053
Nicholas Troast7dbcad22016-10-05 13:30:18 -07003054/************************
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003055 * USB MAIN PSY GETTERS *
3056 ************************/
3057int smblib_get_prop_fcc_delta(struct smb_charger *chg,
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05303058 union power_supply_propval *val)
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003059{
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05303060 int rc, jeita_cc_delta_ua = 0;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003061
3062 rc = smblib_get_jeita_cc_delta(chg, &jeita_cc_delta_ua);
3063 if (rc < 0) {
3064 smblib_err(chg, "Couldn't get jeita cc delta rc=%d\n", rc);
3065 jeita_cc_delta_ua = 0;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003066 }
3067
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05303068 val->intval = jeita_cc_delta_ua;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003069 return 0;
3070}
3071
3072/************************
3073 * USB MAIN PSY SETTERS *
3074 ************************/
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003075int smblib_get_charge_current(struct smb_charger *chg,
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003076 int *total_current_ua)
3077{
Ashay Jaiswal7b6eb962017-04-26 14:34:29 +05303078 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003079 union power_supply_propval val = {0, };
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003080 int rc = 0, typec_source_rd, current_ua;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003081 bool non_compliant;
3082 u8 stat5;
3083
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003084 if (chg->pd_active) {
3085 *total_current_ua =
3086 get_client_vote_locked(chg->usb_icl_votable, PD_VOTER);
3087 return rc;
3088 }
3089
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003090 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
3091 if (rc < 0) {
3092 smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc);
3093 return rc;
3094 }
3095 non_compliant = stat5 & TYPEC_NONCOMP_LEGACY_CABLE_STATUS_BIT;
3096
3097 /* get settled ICL */
3098 rc = smblib_get_prop_input_current_settled(chg, &val);
3099 if (rc < 0) {
3100 smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
3101 return rc;
3102 }
3103
3104 typec_source_rd = smblib_get_prop_ufp_mode(chg);
3105
3106 /* QC 2.0/3.0 adapter */
3107 if (apsd_result->bit & (QC_3P0_BIT | QC_2P0_BIT)) {
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303108 *total_current_ua = HVDCP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003109 return 0;
3110 }
3111
3112 if (non_compliant) {
3113 switch (apsd_result->bit) {
3114 case CDP_CHARGER_BIT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303115 current_ua = CDP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003116 break;
3117 case DCP_CHARGER_BIT:
3118 case OCP_CHARGER_BIT:
3119 case FLOAT_CHARGER_BIT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303120 current_ua = DCP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003121 break;
3122 default:
3123 current_ua = 0;
3124 break;
3125 }
3126
3127 *total_current_ua = max(current_ua, val.intval);
3128 return 0;
3129 }
3130
3131 switch (typec_source_rd) {
3132 case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
3133 switch (apsd_result->bit) {
3134 case CDP_CHARGER_BIT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303135 current_ua = CDP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003136 break;
3137 case DCP_CHARGER_BIT:
3138 case OCP_CHARGER_BIT:
3139 case FLOAT_CHARGER_BIT:
3140 current_ua = chg->default_icl_ua;
3141 break;
3142 default:
3143 current_ua = 0;
3144 break;
3145 }
3146 break;
3147 case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303148 current_ua = TYPEC_MEDIUM_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003149 break;
3150 case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303151 current_ua = TYPEC_HIGH_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003152 break;
3153 case POWER_SUPPLY_TYPEC_NON_COMPLIANT:
3154 case POWER_SUPPLY_TYPEC_NONE:
3155 default:
3156 current_ua = 0;
3157 break;
3158 }
3159
3160 *total_current_ua = max(current_ua, val.intval);
3161 return 0;
3162}
3163
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003164/************************
Nicholas Troast7dbcad22016-10-05 13:30:18 -07003165 * PARALLEL PSY GETTERS *
3166 ************************/
3167
3168int smblib_get_prop_slave_current_now(struct smb_charger *chg,
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003169 union power_supply_propval *pval)
Nicholas Troast7dbcad22016-10-05 13:30:18 -07003170{
3171 if (IS_ERR_OR_NULL(chg->iio.batt_i_chan))
3172 chg->iio.batt_i_chan = iio_channel_get(chg->dev, "batt_i");
3173
3174 if (IS_ERR(chg->iio.batt_i_chan))
3175 return PTR_ERR(chg->iio.batt_i_chan);
3176
3177 return iio_read_channel_processed(chg->iio.batt_i_chan, &pval->intval);
3178}
3179
Nicholas Troast34db5032016-03-28 12:26:44 -07003180/**********************
3181 * INTERRUPT HANDLERS *
3182 **********************/
3183
3184irqreturn_t smblib_handle_debug(int irq, void *data)
3185{
3186 struct smb_irq_data *irq_data = data;
3187 struct smb_charger *chg = irq_data->parent_data;
3188
3189 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003190 return IRQ_HANDLED;
3191}
3192
Nicholas Troast8995a702016-12-05 10:22:22 -08003193irqreturn_t smblib_handle_otg_overcurrent(int irq, void *data)
3194{
3195 struct smb_irq_data *irq_data = data;
3196 struct smb_charger *chg = irq_data->parent_data;
3197 int rc;
3198 u8 stat;
3199
3200 rc = smblib_read(chg, OTG_BASE + INT_RT_STS_OFFSET, &stat);
3201 if (rc < 0) {
3202 dev_err(chg->dev, "Couldn't read OTG_INT_RT_STS rc=%d\n", rc);
3203 return IRQ_HANDLED;
3204 }
3205
Ashay Jaiswal7c241382017-03-06 15:26:38 +05303206 if (chg->wa_flags & OTG_WA) {
3207 if (stat & OTG_OC_DIS_SW_STS_RT_STS_BIT)
3208 smblib_err(chg, "OTG disabled by hw\n");
3209
3210 /* not handling software based hiccups for PM660 */
3211 return IRQ_HANDLED;
3212 }
3213
Nicholas Troastb11015f2017-01-17 17:56:45 -08003214 if (stat & OTG_OVERCURRENT_RT_STS_BIT)
3215 schedule_work(&chg->otg_oc_work);
Nicholas Troast8995a702016-12-05 10:22:22 -08003216
Nicholas Troast8995a702016-12-05 10:22:22 -08003217 return IRQ_HANDLED;
3218}
3219
Harry Yang6fe72ab2016-06-14 16:21:39 -07003220irqreturn_t smblib_handle_chg_state_change(int irq, void *data)
3221{
3222 struct smb_irq_data *irq_data = data;
3223 struct smb_charger *chg = irq_data->parent_data;
Nicholas Troast8cb77552016-09-23 11:50:18 -07003224 u8 stat;
Harry Yang1d1034c2016-06-15 12:09:42 -07003225 int rc;
Harry Yang6fe72ab2016-06-14 16:21:39 -07003226
3227 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3228
Nicholas Troast8cb77552016-09-23 11:50:18 -07003229 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
Harry Yang1d1034c2016-06-15 12:09:42 -07003230 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003231 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003232 rc);
Harry Yang1d1034c2016-06-15 12:09:42 -07003233 return IRQ_HANDLED;
3234 }
3235
Nicholas Troast8cb77552016-09-23 11:50:18 -07003236 stat = stat & BATTERY_CHARGER_STATUS_MASK;
Nicholas Troast8cb77552016-09-23 11:50:18 -07003237 power_supply_changed(chg->batt_psy);
Harry Yang6fe72ab2016-06-14 16:21:39 -07003238 return IRQ_HANDLED;
3239}
3240
Abhijeet Dharmapurikar2644cd62016-07-20 16:54:55 -07003241irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data)
3242{
3243 struct smb_irq_data *irq_data = data;
3244 struct smb_charger *chg = irq_data->parent_data;
Anirudh Ghayal941acaa2017-07-19 16:04:44 +05303245 int rc;
3246
3247 rc = smblib_recover_from_soft_jeita(chg);
3248 if (rc < 0) {
3249 smblib_err(chg, "Couldn't recover chg from soft jeita rc=%d\n",
3250 rc);
3251 return IRQ_HANDLED;
3252 }
Abhijeet Dharmapurikar2644cd62016-07-20 16:54:55 -07003253
3254 rerun_election(chg->fcc_votable);
3255 power_supply_changed(chg->batt_psy);
3256 return IRQ_HANDLED;
3257}
3258
Nicholas Troast34db5032016-03-28 12:26:44 -07003259irqreturn_t smblib_handle_batt_psy_changed(int irq, void *data)
3260{
3261 struct smb_irq_data *irq_data = data;
3262 struct smb_charger *chg = irq_data->parent_data;
3263
Nicholas Troast47ae4612016-08-03 09:49:36 -07003264 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003265 power_supply_changed(chg->batt_psy);
3266 return IRQ_HANDLED;
3267}
3268
3269irqreturn_t smblib_handle_usb_psy_changed(int irq, void *data)
3270{
3271 struct smb_irq_data *irq_data = data;
3272 struct smb_charger *chg = irq_data->parent_data;
3273
Nicholas Troast47ae4612016-08-03 09:49:36 -07003274 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003275 power_supply_changed(chg->usb_psy);
3276 return IRQ_HANDLED;
3277}
3278
Subbaraman Narayanamurthy09327482017-02-06 16:33:12 -08003279irqreturn_t smblib_handle_usbin_uv(int irq, void *data)
3280{
3281 struct smb_irq_data *irq_data = data;
3282 struct smb_charger *chg = irq_data->parent_data;
3283 struct storm_watch *wdata;
3284
3285 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3286 if (!chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data)
3287 return IRQ_HANDLED;
3288
3289 wdata = &chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data->storm_data;
3290 reset_storm_count(wdata);
3291 return IRQ_HANDLED;
3292}
3293
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003294static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising)
3295{
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003296 if (vbus_rising) {
3297 /* use the typec flag even though its not typec */
3298 chg->typec_present = 1;
3299 } else {
3300 chg->typec_present = 0;
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003301 smblib_update_usb_type(chg);
3302 extcon_set_cable_state_(chg->extcon, EXTCON_USB, false);
3303 smblib_uusb_removal(chg);
3304 }
3305}
3306
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003307void smblib_usb_plugin_hard_reset_locked(struct smb_charger *chg)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003308{
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003309 int rc;
3310 u8 stat;
3311 bool vbus_rising;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303312 struct smb_irq_data *data;
3313 struct storm_watch *wdata;
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003314
3315 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
3316 if (rc < 0) {
3317 smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
3318 return;
3319 }
3320
3321 vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
3322
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303323 if (vbus_rising) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003324 smblib_cc2_sink_removal_exit(chg);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303325 } else {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003326 smblib_cc2_sink_removal_enter(chg);
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303327 if (chg->wa_flags & BOOST_BACK_WA) {
3328 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
3329 if (data) {
3330 wdata = &data->storm_data;
3331 update_storm_count(wdata,
3332 WEAK_CHG_STORM_COUNT);
3333 vote(chg->usb_icl_votable, BOOST_BACK_VOTER,
3334 false, 0);
3335 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
3336 false, 0);
3337 }
3338 }
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303339 }
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003340
3341 power_supply_changed(chg->usb_psy);
3342 smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
3343 vbus_rising ? "attached" : "detached");
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003344}
3345
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303346#define PL_DELAY_MS 30000
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003347void smblib_usb_plugin_locked(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07003348{
Nicholas Troast34db5032016-03-28 12:26:44 -07003349 int rc;
3350 u8 stat;
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003351 bool vbus_rising;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303352 struct smb_irq_data *data;
3353 struct storm_watch *wdata;
Nicholas Troast34db5032016-03-28 12:26:44 -07003354
Harry Yangcdad2bf2016-10-04 17:03:56 -07003355 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
3356 if (rc < 0) {
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003357 smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
3358 return;
Harry Yangcdad2bf2016-10-04 17:03:56 -07003359 }
3360
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003361 vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003362 smblib_set_opt_freq_buck(chg, vbus_rising ? chg->chg_freq.freq_5V :
3363 chg->chg_freq.freq_removal);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003364
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003365 if (vbus_rising) {
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05303366 rc = smblib_request_dpdm(chg, true);
3367 if (rc < 0)
3368 smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303369
3370 /* Schedule work to enable parallel charger */
3371 vote(chg->awake_votable, PL_DELAY_VOTER, true, 0);
3372 schedule_delayed_work(&chg->pl_enable_work,
3373 msecs_to_jiffies(PL_DELAY_MS));
Harry Yang1ed7f162017-08-25 11:26:51 -07003374 /* vbus rising when APSD was disabled and PD_ACTIVE = 0 */
3375 if (get_effective_result(chg->apsd_disable_votable) &&
3376 !chg->pd_active)
3377 pr_err("APSD disabled on vbus rising without PD\n");
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07003378 } else {
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303379 if (chg->wa_flags & BOOST_BACK_WA) {
3380 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
3381 if (data) {
3382 wdata = &data->storm_data;
3383 update_storm_count(wdata,
3384 WEAK_CHG_STORM_COUNT);
3385 vote(chg->usb_icl_votable, BOOST_BACK_VOTER,
3386 false, 0);
3387 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
3388 false, 0);
3389 }
3390 }
Nicholas Troastabedaf72016-09-16 11:07:45 -07003391
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05303392 rc = smblib_request_dpdm(chg, false);
3393 if (rc < 0)
3394 smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07003395 }
3396
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003397 if (chg->micro_usb_mode)
3398 smblib_micro_usb_plugin(chg, vbus_rising);
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003399
Nicholas Troast62d86622016-09-22 11:41:33 -07003400 power_supply_changed(chg->usb_psy);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003401 smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
3402 vbus_rising ? "attached" : "detached");
3403}
3404
3405irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
3406{
3407 struct smb_irq_data *irq_data = data;
3408 struct smb_charger *chg = irq_data->parent_data;
3409
3410 mutex_lock(&chg->lock);
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003411 if (chg->pd_hard_reset)
3412 smblib_usb_plugin_hard_reset_locked(chg);
3413 else
3414 smblib_usb_plugin_locked(chg);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003415 mutex_unlock(&chg->lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07003416 return IRQ_HANDLED;
3417}
3418
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -07003419#define USB_WEAK_INPUT_UA 1400000
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303420#define ICL_CHANGE_DELAY_MS 1000
Harry Yang6fe72ab2016-06-14 16:21:39 -07003421irqreturn_t smblib_handle_icl_change(int irq, void *data)
3422{
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303423 u8 stat;
3424 int rc, settled_ua, delay = ICL_CHANGE_DELAY_MS;
Harry Yang6fe72ab2016-06-14 16:21:39 -07003425 struct smb_irq_data *irq_data = data;
3426 struct smb_charger *chg = irq_data->parent_data;
3427
Nicholas Troastbb9e1a32017-02-09 10:57:28 -08003428 if (chg->mode == PARALLEL_MASTER) {
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303429 rc = smblib_read(chg, AICL_STATUS_REG, &stat);
3430 if (rc < 0) {
3431 smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n",
3432 rc);
3433 return IRQ_HANDLED;
3434 }
3435
3436 rc = smblib_get_charge_param(chg, &chg->param.icl_stat,
3437 &settled_ua);
3438 if (rc < 0) {
3439 smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
3440 return IRQ_HANDLED;
3441 }
3442
3443 /* If AICL settled then schedule work now */
3444 if ((settled_ua == get_effective_result(chg->usb_icl_votable))
3445 || (stat & AICL_DONE_BIT))
3446 delay = 0;
3447
Ashay Jaiswalac854862017-03-06 23:58:55 +05303448 cancel_delayed_work_sync(&chg->icl_change_work);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303449 schedule_delayed_work(&chg->icl_change_work,
3450 msecs_to_jiffies(delay));
Nicholas Troastbb9e1a32017-02-09 10:57:28 -08003451 }
Harry Yang1d1034c2016-06-15 12:09:42 -07003452
Harry Yang6fe72ab2016-06-14 16:21:39 -07003453 return IRQ_HANDLED;
3454}
3455
Nicholas Troast34db5032016-03-28 12:26:44 -07003456static void smblib_handle_slow_plugin_timeout(struct smb_charger *chg,
3457 bool rising)
3458{
3459 smblib_dbg(chg, PR_INTERRUPT, "IRQ: slow-plugin-timeout %s\n",
3460 rising ? "rising" : "falling");
3461}
3462
3463static void smblib_handle_sdp_enumeration_done(struct smb_charger *chg,
3464 bool rising)
3465{
3466 smblib_dbg(chg, PR_INTERRUPT, "IRQ: sdp-enumeration-done %s\n",
3467 rising ? "rising" : "falling");
3468}
3469
Harry Yangcdad2bf2016-10-04 17:03:56 -07003470#define QC3_PULSES_FOR_6V 5
3471#define QC3_PULSES_FOR_9V 20
3472#define QC3_PULSES_FOR_12V 35
3473static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg)
3474{
3475 int rc;
3476 u8 stat;
3477 int pulses;
3478
Fenglin Wuef4730e2017-01-11 18:16:25 +08003479 power_supply_changed(chg->usb_main_psy);
Fenglin Wu80826e02017-04-25 21:45:08 +08003480 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP) {
Harry Yangcdad2bf2016-10-04 17:03:56 -07003481 rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat);
3482 if (rc < 0) {
3483 smblib_err(chg,
3484 "Couldn't read QC_CHANGE_STATUS rc=%d\n", rc);
3485 return;
3486 }
3487
3488 switch (stat & QC_2P0_STATUS_MASK) {
3489 case QC_5V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303490 smblib_set_opt_freq_buck(chg,
3491 chg->chg_freq.freq_5V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003492 break;
3493 case QC_9V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303494 smblib_set_opt_freq_buck(chg,
3495 chg->chg_freq.freq_9V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003496 break;
3497 case QC_12V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303498 smblib_set_opt_freq_buck(chg,
3499 chg->chg_freq.freq_12V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003500 break;
3501 default:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303502 smblib_set_opt_freq_buck(chg,
3503 chg->chg_freq.freq_removal);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003504 break;
3505 }
3506 }
3507
Fenglin Wu80826e02017-04-25 21:45:08 +08003508 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP_3) {
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +05303509 rc = smblib_get_pulse_cnt(chg, &pulses);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003510 if (rc < 0) {
3511 smblib_err(chg,
3512 "Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
3513 return;
3514 }
Harry Yangcdad2bf2016-10-04 17:03:56 -07003515
3516 if (pulses < QC3_PULSES_FOR_6V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303517 smblib_set_opt_freq_buck(chg,
3518 chg->chg_freq.freq_5V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003519 else if (pulses < QC3_PULSES_FOR_9V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303520 smblib_set_opt_freq_buck(chg,
3521 chg->chg_freq.freq_6V_8V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003522 else if (pulses < QC3_PULSES_FOR_12V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303523 smblib_set_opt_freq_buck(chg,
3524 chg->chg_freq.freq_9V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003525 else
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303526 smblib_set_opt_freq_buck(chg,
3527 chg->chg_freq.freq_12V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003528 }
3529}
3530
Nicholas Troast34db5032016-03-28 12:26:44 -07003531/* triggers when HVDCP 3.0 authentication has finished */
3532static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
3533 bool rising)
3534{
3535 const struct apsd_result *apsd_result;
Harry Yangcdad2bf2016-10-04 17:03:56 -07003536 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07003537
3538 if (!rising)
3539 return;
3540
Ashay Jaiswal67ec7072017-02-16 14:14:58 +05303541 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
3542 /*
3543 * Disable AUTH_IRQ_EN_CFG_BIT to receive adapter voltage
3544 * change interrupt.
3545 */
3546 rc = smblib_masked_write(chg,
3547 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
3548 AUTH_IRQ_EN_CFG_BIT, 0);
3549 if (rc < 0)
3550 smblib_err(chg,
3551 "Couldn't enable QC auth setting rc=%d\n", rc);
3552 }
Harry Yangcdad2bf2016-10-04 17:03:56 -07003553
Harry Yangaba1f5f2016-09-28 10:47:29 -07003554 if (chg->mode == PARALLEL_MASTER)
3555 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0);
3556
Ashay Jaiswalac854862017-03-06 23:58:55 +05303557 /* the APSD done handler will set the USB supply type */
3558 apsd_result = smblib_get_apsd_result(chg);
3559 if (get_effective_result(chg->hvdcp_hw_inov_dis_votable)) {
3560 if (apsd_result->pst == POWER_SUPPLY_TYPE_USB_HVDCP) {
3561 /* force HVDCP2 to 9V if INOV is disabled */
3562 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG,
3563 FORCE_9V_BIT, FORCE_9V_BIT);
3564 if (rc < 0)
3565 smblib_err(chg,
3566 "Couldn't force 9V HVDCP rc=%d\n", rc);
3567 }
3568 }
3569
Nicholas Troast34db5032016-03-28 12:26:44 -07003570 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n",
3571 apsd_result->name);
3572}
3573
Harry Yang1369b7a2016-09-27 15:59:50 -07003574static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
3575 bool rising, bool qc_charger)
3576{
Ashay Jaiswal7b6eb962017-04-26 14:34:29 +05303577 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05303578
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003579 /* Hold off PD only until hvdcp 2.0 detection timeout */
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003580 if (rising) {
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003581 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003582 false, 0);
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -08003583
Harry Yang4bf7d962017-03-13 16:51:43 -07003584 /* enable HDC and ICL irq for QC2/3 charger */
3585 if (qc_charger)
3586 vote(chg->usb_irq_enable_votable, QC_VOTER, true, 0);
3587
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -08003588 /*
3589 * HVDCP detection timeout done
3590 * If adapter is not QC2.0/QC3.0 - it is a plain old DCP.
3591 */
3592 if (!qc_charger && (apsd_result->bit & DCP_CHARGER_BIT))
3593 /* enforce DCP ICL if specified */
3594 vote(chg->usb_icl_votable, DCP_VOTER,
3595 chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua);
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003596 }
Harry Yang1369b7a2016-09-27 15:59:50 -07003597
3598 smblib_dbg(chg, PR_INTERRUPT, "IRQ: smblib_handle_hvdcp_check_timeout %s\n",
3599 rising ? "rising" : "falling");
3600}
3601
Nicholas Troast34db5032016-03-28 12:26:44 -07003602/* triggers when HVDCP is detected */
3603static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg,
3604 bool rising)
3605{
3606 if (!rising)
3607 return;
3608
3609 /* the APSD done handler will set the USB supply type */
3610 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
3611 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-detect-done %s\n",
3612 rising ? "rising" : "falling");
3613}
3614
Nicholas Troastf9e44992017-03-14 09:06:56 -07003615static void smblib_force_legacy_icl(struct smb_charger *chg, int pst)
3616{
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303617 int typec_mode;
3618 int rp_ua;
3619
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003620 /* while PD is active it should have complete ICL control */
3621 if (chg->pd_active)
3622 return;
3623
Nicholas Troastf9e44992017-03-14 09:06:56 -07003624 switch (pst) {
3625 case POWER_SUPPLY_TYPE_USB:
3626 /*
3627 * USB_PSY will vote to increase the current to 500/900mA once
3628 * enumeration is done. Ensure that USB_PSY has at least voted
3629 * for 100mA before releasing the LEGACY_UNKNOWN vote
3630 */
3631 if (!is_client_vote_enabled(chg->usb_icl_votable,
3632 USB_PSY_VOTER))
3633 vote(chg->usb_icl_votable, USB_PSY_VOTER, true, 100000);
3634 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
3635 break;
3636 case POWER_SUPPLY_TYPE_USB_CDP:
3637 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1500000);
3638 break;
3639 case POWER_SUPPLY_TYPE_USB_DCP:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303640 typec_mode = smblib_get_prop_typec_mode(chg);
3641 rp_ua = get_rp_based_dcp_current(chg, typec_mode);
3642 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua);
Nicholas Troastf9e44992017-03-14 09:06:56 -07003643 break;
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05303644 case POWER_SUPPLY_TYPE_USB_FLOAT:
3645 /*
3646 * limit ICL to 100mA, the USB driver will enumerate to check
3647 * if this is a SDP and appropriately set the current
3648 */
3649 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
3650 break;
Nicholas Troastf9e44992017-03-14 09:06:56 -07003651 case POWER_SUPPLY_TYPE_USB_HVDCP:
3652 case POWER_SUPPLY_TYPE_USB_HVDCP_3:
3653 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 3000000);
3654 break;
3655 default:
3656 smblib_err(chg, "Unknown APSD %d; forcing 500mA\n", pst);
3657 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 500000);
3658 break;
3659 }
3660}
3661
Ankit Sharmade321e12017-09-01 20:17:45 +05303662static void smblib_notify_extcon_props(struct smb_charger *chg, int id)
3663{
3664 union extcon_property_value val;
3665 union power_supply_propval prop_val;
3666
3667 smblib_get_prop_typec_cc_orientation(chg, &prop_val);
3668 val.intval = ((prop_val.intval == 2) ? 1 : 0);
3669 extcon_set_property(chg->extcon, id,
3670 EXTCON_PROP_USB_TYPEC_POLARITY, val);
3671
3672 val.intval = true;
3673 extcon_set_property(chg->extcon, id,
3674 EXTCON_PROP_USB_SS, val);
3675}
3676
3677static void smblib_notify_device_mode(struct smb_charger *chg, bool enable)
3678{
3679 if (enable)
3680 smblib_notify_extcon_props(chg, EXTCON_USB);
3681
3682 extcon_set_state_sync(chg->extcon, EXTCON_USB, enable);
3683}
3684
3685static void smblib_notify_usb_host(struct smb_charger *chg, bool enable)
3686{
3687 if (enable)
3688 smblib_notify_extcon_props(chg, EXTCON_USB_HOST);
3689
3690 extcon_set_state_sync(chg->extcon, EXTCON_USB_HOST, enable);
3691}
3692
Nicholas Troast34db5032016-03-28 12:26:44 -07003693#define HVDCP_DET_MS 2500
3694static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
3695{
Nicholas Troast34db5032016-03-28 12:26:44 -07003696 const struct apsd_result *apsd_result;
3697
3698 if (!rising)
3699 return;
3700
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07003701 apsd_result = smblib_update_usb_type(chg);
Nicholas Troastf9e44992017-03-14 09:06:56 -07003702
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003703 if (!chg->typec_legacy_valid)
Nicholas Troastf9e44992017-03-14 09:06:56 -07003704 smblib_force_legacy_icl(chg, apsd_result->pst);
3705
Nicholas Troast34db5032016-03-28 12:26:44 -07003706 switch (apsd_result->bit) {
3707 case SDP_CHARGER_BIT:
3708 case CDP_CHARGER_BIT:
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05303709 if (chg->micro_usb_mode)
3710 extcon_set_cable_state_(chg->extcon, EXTCON_USB,
3711 true);
Abhijeet Dharmapurikarbb9505f2017-03-22 18:31:28 -07003712 /* if not DCP then no hvdcp timeout happens. Enable pd here */
3713 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3714 false, 0);
Ankit Sharmade321e12017-09-01 20:17:45 +05303715 if (chg->use_extcon)
3716 smblib_notify_device_mode(chg, true);
Abhijeet Dharmapurikarbb9505f2017-03-22 18:31:28 -07003717 break;
Nicholas Troast34db5032016-03-28 12:26:44 -07003718 case OCP_CHARGER_BIT:
3719 case FLOAT_CHARGER_BIT:
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303720 /* if not DCP then no hvdcp timeout happens, Enable pd here. */
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003721 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3722 false, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07003723 break;
3724 case DCP_CHARGER_BIT:
Harry Yang1369b7a2016-09-27 15:59:50 -07003725 if (chg->wa_flags & QC_CHARGER_DETECTION_WA_BIT)
3726 schedule_delayed_work(&chg->hvdcp_detect_work,
3727 msecs_to_jiffies(HVDCP_DET_MS));
Nicholas Troast34db5032016-03-28 12:26:44 -07003728 break;
3729 default:
3730 break;
3731 }
3732
Nicholas Troast34db5032016-03-28 12:26:44 -07003733 smblib_dbg(chg, PR_INTERRUPT, "IRQ: apsd-done rising; %s detected\n",
3734 apsd_result->name);
3735}
3736
3737irqreturn_t smblib_handle_usb_source_change(int irq, void *data)
3738{
3739 struct smb_irq_data *irq_data = data;
3740 struct smb_charger *chg = irq_data->parent_data;
3741 int rc = 0;
3742 u8 stat;
3743
3744 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
3745 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003746 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07003747 return IRQ_HANDLED;
3748 }
3749 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
3750
Ashay Jaiswal8507aa52017-04-14 09:42:32 +05303751 if (chg->micro_usb_mode && (stat & APSD_DTC_STATUS_DONE_BIT)
3752 && !chg->uusb_apsd_rerun_done) {
3753 /*
3754 * Force re-run APSD to handle slow insertion related
3755 * charger-mis-detection.
3756 */
3757 chg->uusb_apsd_rerun_done = true;
3758 smblib_rerun_apsd(chg);
3759 return IRQ_HANDLED;
3760 }
3761
Nicholas Troast34db5032016-03-28 12:26:44 -07003762 smblib_handle_apsd_done(chg,
3763 (bool)(stat & APSD_DTC_STATUS_DONE_BIT));
3764
3765 smblib_handle_hvdcp_detect_done(chg,
3766 (bool)(stat & QC_CHARGER_BIT));
3767
Harry Yang1369b7a2016-09-27 15:59:50 -07003768 smblib_handle_hvdcp_check_timeout(chg,
3769 (bool)(stat & HVDCP_CHECK_TIMEOUT_BIT),
3770 (bool)(stat & QC_CHARGER_BIT));
3771
Nicholas Troast34db5032016-03-28 12:26:44 -07003772 smblib_handle_hvdcp_3p0_auth_done(chg,
3773 (bool)(stat & QC_AUTH_DONE_STATUS_BIT));
3774
Nicholas Troast34db5032016-03-28 12:26:44 -07003775 smblib_handle_sdp_enumeration_done(chg,
3776 (bool)(stat & ENUMERATION_DONE_BIT));
3777
3778 smblib_handle_slow_plugin_timeout(chg,
3779 (bool)(stat & SLOW_PLUGIN_TIMEOUT_BIT));
3780
Harry Yangcdad2bf2016-10-04 17:03:56 -07003781 smblib_hvdcp_adaptive_voltage_change(chg);
3782
Nicholas Troast34db5032016-03-28 12:26:44 -07003783 power_supply_changed(chg->usb_psy);
3784
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08003785 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
3786 if (rc < 0) {
3787 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
3788 return IRQ_HANDLED;
3789 }
3790 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
3791
Nicholas Troast34db5032016-03-28 12:26:44 -07003792 return IRQ_HANDLED;
3793}
3794
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003795static void typec_sink_insertion(struct smb_charger *chg)
3796{
3797 /* when a sink is inserted we should not wait on hvdcp timeout to
3798 * enable pd
3799 */
3800 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3801 false, 0);
Ankit Sharmade321e12017-09-01 20:17:45 +05303802 if (chg->use_extcon) {
3803 smblib_notify_usb_host(chg, true);
3804 chg->otg_present = true;
3805 }
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003806}
Nicholas Troast34db5032016-03-28 12:26:44 -07003807
Harry Yangd89ff1f2016-12-05 14:59:11 -08003808static void typec_sink_removal(struct smb_charger *chg)
3809{
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303810 smblib_set_charge_param(chg, &chg->param.freq_boost,
3811 chg->chg_freq.freq_above_otg_threshold);
Harry Yangd89ff1f2016-12-05 14:59:11 -08003812 chg->boost_current_ua = 0;
3813}
3814
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003815static void smblib_handle_typec_removal(struct smb_charger *chg)
3816{
Nicholas Troastfe74c592017-03-14 09:20:55 -07003817 int rc;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303818 struct smb_irq_data *data;
3819 struct storm_watch *wdata;
Nicholas Troastfe74c592017-03-14 09:20:55 -07003820
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003821 chg->cc2_detach_wa_active = false;
3822
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05303823 rc = smblib_request_dpdm(chg, false);
3824 if (rc < 0)
3825 smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303826
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303827 if (chg->wa_flags & BOOST_BACK_WA) {
3828 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
3829 if (data) {
3830 wdata = &data->storm_data;
3831 update_storm_count(wdata, WEAK_CHG_STORM_COUNT);
3832 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
3833 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
3834 false, 0);
3835 }
3836 }
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303837
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003838 /* reset APSD voters */
3839 vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, false, 0);
3840 vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303841
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003842 cancel_delayed_work_sync(&chg->pl_enable_work);
3843 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
3844
3845 /* reset input current limit voters */
3846 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
3847 vote(chg->usb_icl_votable, PD_VOTER, false, 0);
3848 vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
3849 vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
3850 vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
Ashay Jaiswalae23a042017-05-18 15:28:31 +05303851 vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
Abhijeet Dharmapurikar66d2c442017-07-12 11:55:36 -07003852 vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003853
3854 /* reset hvdcp voters */
3855 vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, true, 0);
3856 vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER, true, 0);
3857
3858 /* reset power delivery voters */
3859 vote(chg->pd_allowed_votable, PD_VOTER, false, 0);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003860 vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0);
3861 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER, true, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003862
3863 /* reset usb irq voters */
Harry Yang4bf7d962017-03-13 16:51:43 -07003864 vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
3865 vote(chg->usb_irq_enable_votable, QC_VOTER, false, 0);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003866
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003867 /* reset parallel voters */
3868 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
Harry Yanga796cf72017-07-19 19:26:45 -07003869 vote(chg->pl_disable_votable, FCC_CHANGE_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003870 vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
3871 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
3872 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
Harry Yang1d1034c2016-06-15 12:09:42 -07003873
Nicholas Troast8995a702016-12-05 10:22:22 -08003874 chg->vconn_attempts = 0;
3875 chg->otg_attempts = 0;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05303876 chg->pulse_cnt = 0;
3877 chg->usb_icl_delta_ua = 0;
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003878 chg->voltage_min_uv = MICRO_5V;
3879 chg->voltage_max_uv = MICRO_5V;
3880 chg->pd_active = 0;
3881 chg->pd_hard_reset = 0;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003882 chg->typec_legacy_valid = false;
Harry Yang3b113a52016-12-08 12:37:40 -08003883
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05303884 /* write back the default FLOAT charger configuration */
3885 rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
3886 (u8)FLOAT_OPTIONS_MASK, chg->float_cfg);
3887 if (rc < 0)
3888 smblib_err(chg, "Couldn't write float charger options rc=%d\n",
3889 rc);
3890
Abhijeet Dharmapurikar676bd792017-05-31 16:21:57 -07003891 /* reset back to 120mS tCC debounce */
3892 rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT, 0);
3893 if (rc < 0)
3894 smblib_err(chg, "Couldn't set 120mS tCC debounce rc=%d\n", rc);
3895
Nicholas Troastfe74c592017-03-14 09:20:55 -07003896 /* enable APSD CC trigger for next insertion */
3897 rc = smblib_masked_write(chg, TYPE_C_CFG_REG,
3898 APSD_START_ON_CC_BIT, APSD_START_ON_CC_BIT);
3899 if (rc < 0)
3900 smblib_err(chg, "Couldn't enable APSD_START_ON_CC rc=%d\n", rc);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08003901
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003902 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
3903 /* re-enable AUTH_IRQ_EN_CFG_BIT */
3904 rc = smblib_masked_write(chg,
3905 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
3906 AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
3907 if (rc < 0)
3908 smblib_err(chg,
3909 "Couldn't enable QC auth setting rc=%d\n", rc);
3910 }
3911
3912 /* reconfigure allowed voltage for HVDCP */
3913 rc = smblib_set_adapter_allowance(chg,
3914 USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
3915 if (rc < 0)
3916 smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
3917 rc);
3918
3919 /* enable DRP */
3920 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
3921 TYPEC_POWER_ROLE_CMD_MASK, 0);
3922 if (rc < 0)
3923 smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc);
3924
3925 /* HW controlled CC_OUT */
3926 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
3927 TYPEC_SPARE_CFG_BIT, 0);
3928 if (rc < 0)
3929 smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n", rc);
3930
3931 /* restore crude sensor */
3932 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
3933 if (rc < 0)
3934 smblib_err(chg, "Couldn't restore crude sensor rc=%d\n", rc);
3935
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07003936 mutex_lock(&chg->vconn_oc_lock);
3937 if (!chg->vconn_en)
3938 goto unlock;
3939
3940 smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
3941 VCONN_EN_VALUE_BIT, 0);
3942 chg->vconn_en = false;
3943
3944unlock:
3945 mutex_unlock(&chg->vconn_oc_lock);
3946
Abhijeet Dharmapurikar319d6942017-06-05 17:14:17 -07003947 /* clear exit sink based on cc */
3948 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
3949 EXIT_SNK_BASED_ON_CC_BIT, 0);
3950 if (rc < 0)
3951 smblib_err(chg, "Couldn't clear exit_sink_based_on_cc rc=%d\n",
3952 rc);
3953
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08003954 typec_sink_removal(chg);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003955 smblib_update_usb_type(chg);
Ankit Sharmade321e12017-09-01 20:17:45 +05303956
3957 if (chg->use_extcon) {
3958 if (chg->otg_present)
3959 smblib_notify_usb_host(chg, false);
3960 else
3961 smblib_notify_device_mode(chg, false);
3962 }
3963 chg->otg_present = false;
Nicholas Troast34db5032016-03-28 12:26:44 -07003964}
3965
Nicholas Troaste1932e42017-04-12 12:38:18 -07003966static void smblib_handle_typec_insertion(struct smb_charger *chg)
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003967{
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003968 int rc;
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003969
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003970 vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, false, 0);
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003971
Nicholas Troastfe74c592017-03-14 09:20:55 -07003972 /* disable APSD CC trigger since CC is attached */
3973 rc = smblib_masked_write(chg, TYPE_C_CFG_REG, APSD_START_ON_CC_BIT, 0);
3974 if (rc < 0)
3975 smblib_err(chg, "Couldn't disable APSD_START_ON_CC rc=%d\n",
3976 rc);
3977
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05303978 if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT) {
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003979 typec_sink_insertion(chg);
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05303980 } else {
3981 rc = smblib_request_dpdm(chg, true);
3982 if (rc < 0)
3983 smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
Harry Yangd89ff1f2016-12-05 14:59:11 -08003984 typec_sink_removal(chg);
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05303985 }
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003986}
3987
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303988static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode)
3989{
3990 int rp_ua;
3991 const struct apsd_result *apsd = smblib_get_apsd_result(chg);
3992
3993 if ((apsd->pst != POWER_SUPPLY_TYPE_USB_DCP)
3994 && (apsd->pst != POWER_SUPPLY_TYPE_USB_FLOAT))
3995 return;
3996
3997 /*
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05303998 * if APSD indicates FLOAT and the USB stack had detected SDP,
3999 * do not respond to Rp changes as we do not confirm that its
4000 * a legacy cable
4001 */
4002 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
4003 return;
4004 /*
4005 * We want the ICL vote @ 100mA for a FLOAT charger
4006 * until the detection by the USB stack is complete.
4007 * Ignore the Rp changes unless there is a
4008 * pre-existing valid vote.
4009 */
4010 if (apsd->pst == POWER_SUPPLY_TYPE_USB_FLOAT &&
4011 get_client_vote(chg->usb_icl_votable,
4012 LEGACY_UNKNOWN_VOTER) <= 100000)
4013 return;
4014
4015 /*
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05304016 * handle Rp change for DCP/FLOAT/OCP.
4017 * Update the current only if the Rp is different from
4018 * the last Rp value.
4019 */
4020 smblib_dbg(chg, PR_MISC, "CC change old_mode=%d new_mode=%d\n",
4021 chg->typec_mode, typec_mode);
4022
4023 rp_ua = get_rp_based_dcp_current(chg, typec_mode);
4024 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua);
4025}
4026
Nicholas Troaste1932e42017-04-12 12:38:18 -07004027static void smblib_handle_typec_cc_state_change(struct smb_charger *chg)
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004028{
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05304029 int typec_mode;
4030
Nicholas Troaste1932e42017-04-12 12:38:18 -07004031 if (chg->pr_swap_in_progress)
4032 return;
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004033
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05304034 typec_mode = smblib_get_prop_typec_mode(chg);
4035 if (chg->typec_present && (typec_mode != chg->typec_mode))
4036 smblib_handle_rp_change(chg, typec_mode);
4037
4038 chg->typec_mode = typec_mode;
4039
Nicholas Troaste1932e42017-04-12 12:38:18 -07004040 if (!chg->typec_present && chg->typec_mode != POWER_SUPPLY_TYPEC_NONE) {
4041 chg->typec_present = true;
4042 smblib_dbg(chg, PR_MISC, "TypeC %s insertion\n",
4043 smblib_typec_mode_name[chg->typec_mode]);
4044 smblib_handle_typec_insertion(chg);
4045 } else if (chg->typec_present &&
4046 chg->typec_mode == POWER_SUPPLY_TYPEC_NONE) {
4047 chg->typec_present = false;
4048 smblib_dbg(chg, PR_MISC, "TypeC removal\n");
4049 smblib_handle_typec_removal(chg);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004050 }
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004051
Abhijeet Dharmapurikar66d2c442017-07-12 11:55:36 -07004052 /* suspend usb if sink */
Harry Yangca0664e2017-08-18 11:40:06 -07004053 if ((chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
4054 && chg->typec_present)
Abhijeet Dharmapurikar66d2c442017-07-12 11:55:36 -07004055 vote(chg->usb_icl_votable, OTG_VOTER, true, 0);
4056 else
4057 vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
4058
Nicholas Troaste1932e42017-04-12 12:38:18 -07004059 smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n",
4060 smblib_typec_mode_name[chg->typec_mode]);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004061}
4062
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004063static void smblib_usb_typec_change(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07004064{
Nicholas Troast34db5032016-03-28 12:26:44 -07004065 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07004066
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07004067 rc = smblib_multibyte_read(chg, TYPE_C_STATUS_1_REG,
4068 chg->typec_status, 5);
Nicholas Troast34db5032016-03-28 12:26:44 -07004069 if (rc < 0) {
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07004070 smblib_err(chg, "Couldn't cache USB Type-C status rc=%d\n", rc);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004071 return;
Nicholas Troast34db5032016-03-28 12:26:44 -07004072 }
Nicholas Troast34db5032016-03-28 12:26:44 -07004073
Nicholas Troaste1932e42017-04-12 12:38:18 -07004074 smblib_handle_typec_cc_state_change(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07004075
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07004076 if (chg->typec_status[3] & TYPEC_VBUS_ERROR_STATUS_BIT)
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004077 smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n");
Harry Yangd757c0f2016-09-23 10:52:05 -07004078
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07004079 if (chg->typec_status[3] & TYPEC_VCONN_OVERCURR_STATUS_BIT)
Nicholas Troastb11015f2017-01-17 17:56:45 -08004080 schedule_work(&chg->vconn_oc_work);
Nicholas Troast8995a702016-12-05 10:22:22 -08004081
Nicholas Troastb1486552016-11-10 08:20:11 -08004082 power_supply_changed(chg->usb_psy);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004083}
4084
4085irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
4086{
4087 struct smb_irq_data *irq_data = data;
4088 struct smb_charger *chg = irq_data->parent_data;
4089
4090 if (chg->micro_usb_mode) {
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05304091 cancel_delayed_work_sync(&chg->uusb_otg_work);
4092 vote(chg->awake_votable, OTG_DELAY_VOTER, true, 0);
4093 smblib_dbg(chg, PR_INTERRUPT, "Scheduling OTG work\n");
4094 schedule_delayed_work(&chg->uusb_otg_work,
4095 msecs_to_jiffies(chg->otg_delay_ms));
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004096 return IRQ_HANDLED;
4097 }
4098
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004099 if (chg->cc2_detach_wa_active || chg->typec_en_dis_active) {
4100 smblib_dbg(chg, PR_INTERRUPT, "Ignoring since %s active\n",
4101 chg->cc2_detach_wa_active ?
4102 "cc2_detach_wa" : "typec_en_dis");
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004103 return IRQ_HANDLED;
4104 }
4105
Abhijeet Dharmapurikar049b2552017-07-12 11:27:51 -07004106 if (chg->pr_swap_in_progress) {
4107 smblib_dbg(chg, PR_INTERRUPT,
4108 "Ignoring since pr_swap_in_progress\n");
4109 return IRQ_HANDLED;
4110 }
4111
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004112 mutex_lock(&chg->lock);
4113 smblib_usb_typec_change(chg);
4114 mutex_unlock(&chg->lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07004115 return IRQ_HANDLED;
4116}
4117
Abhijeet Dharmapurikar23916642016-10-03 10:38:50 -07004118irqreturn_t smblib_handle_dc_plugin(int irq, void *data)
4119{
4120 struct smb_irq_data *irq_data = data;
4121 struct smb_charger *chg = irq_data->parent_data;
4122
4123 power_supply_changed(chg->dc_psy);
4124 return IRQ_HANDLED;
4125}
4126
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004127irqreturn_t smblib_handle_high_duty_cycle(int irq, void *data)
4128{
4129 struct smb_irq_data *irq_data = data;
4130 struct smb_charger *chg = irq_data->parent_data;
4131
4132 chg->is_hdc = true;
4133 schedule_delayed_work(&chg->clear_hdc_work, msecs_to_jiffies(60));
4134
4135 return IRQ_HANDLED;
4136}
4137
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05304138static void smblib_bb_removal_work(struct work_struct *work)
4139{
4140 struct smb_charger *chg = container_of(work, struct smb_charger,
4141 bb_removal_work.work);
4142
4143 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
4144 vote(chg->awake_votable, BOOST_BACK_VOTER, false, 0);
4145}
4146
4147#define BOOST_BACK_UNVOTE_DELAY_MS 750
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304148#define BOOST_BACK_STORM_COUNT 3
4149#define WEAK_CHG_STORM_COUNT 8
Nicholas Troastabedaf72016-09-16 11:07:45 -07004150irqreturn_t smblib_handle_switcher_power_ok(int irq, void *data)
4151{
4152 struct smb_irq_data *irq_data = data;
4153 struct smb_charger *chg = irq_data->parent_data;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304154 struct storm_watch *wdata = &irq_data->storm_data;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004155 int rc, usb_icl;
Nicholas Troastabedaf72016-09-16 11:07:45 -07004156 u8 stat;
4157
4158 if (!(chg->wa_flags & BOOST_BACK_WA))
4159 return IRQ_HANDLED;
4160
4161 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
4162 if (rc < 0) {
4163 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n", rc);
4164 return IRQ_HANDLED;
4165 }
4166
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004167 /* skip suspending input if its already suspended by some other voter */
4168 usb_icl = get_effective_result(chg->usb_icl_votable);
Harry Yang379484a2017-08-29 10:26:14 -07004169 if ((stat & USE_USBIN_BIT) && usb_icl >= 0 && usb_icl <= USBIN_25MA)
Nicholas Troastabedaf72016-09-16 11:07:45 -07004170 return IRQ_HANDLED;
4171
Abhijeet Dharmapurikar2823fe32016-12-05 17:52:11 -08004172 if (stat & USE_DCIN_BIT)
Nicholas Troastabedaf72016-09-16 11:07:45 -07004173 return IRQ_HANDLED;
4174
4175 if (is_storming(&irq_data->storm_data)) {
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304176 /* This could be a weak charger reduce ICL */
4177 if (!is_client_vote_enabled(chg->usb_icl_votable,
4178 WEAK_CHARGER_VOTER)) {
4179 smblib_err(chg,
4180 "Weak charger detected: voting %dmA ICL\n",
4181 *chg->weak_chg_icl_ua / 1000);
4182 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
4183 true, *chg->weak_chg_icl_ua);
4184 /*
4185 * reset storm data and set the storm threshold
4186 * to 3 for reverse boost detection.
4187 */
4188 update_storm_count(wdata, BOOST_BACK_STORM_COUNT);
4189 } else {
4190 smblib_err(chg,
4191 "Reverse boost detected: voting 0mA to suspend input\n");
4192 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, true, 0);
4193 vote(chg->awake_votable, BOOST_BACK_VOTER, true, 0);
4194 /*
4195 * Remove the boost-back vote after a delay, to avoid
4196 * permanently suspending the input if the boost-back
4197 * condition is unintentionally hit.
4198 */
4199 schedule_delayed_work(&chg->bb_removal_work,
4200 msecs_to_jiffies(BOOST_BACK_UNVOTE_DELAY_MS));
4201 }
Nicholas Troastabedaf72016-09-16 11:07:45 -07004202 }
4203
4204 return IRQ_HANDLED;
4205}
4206
Nicholas Troast15dc0c82016-10-18 15:15:21 -07004207irqreturn_t smblib_handle_wdog_bark(int irq, void *data)
4208{
4209 struct smb_irq_data *irq_data = data;
4210 struct smb_charger *chg = irq_data->parent_data;
4211 int rc;
4212
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05304213 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
4214
Nicholas Troast15dc0c82016-10-18 15:15:21 -07004215 rc = smblib_write(chg, BARK_BITE_WDOG_PET_REG, BARK_BITE_WDOG_PET_BIT);
4216 if (rc < 0)
4217 smblib_err(chg, "Couldn't pet the dog rc=%d\n", rc);
4218
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +05304219 if (chg->step_chg_enabled || chg->sw_jeita_enabled)
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05304220 power_supply_changed(chg->batt_psy);
4221
Nicholas Troast15dc0c82016-10-18 15:15:21 -07004222 return IRQ_HANDLED;
4223}
4224
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004225/**************
4226 * Additional USB PSY getters/setters
4227 * that call interrupt functions
4228 ***************/
4229
4230int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg,
4231 union power_supply_propval *val)
4232{
4233 val->intval = chg->pr_swap_in_progress;
4234 return 0;
4235}
4236
4237int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg,
4238 const union power_supply_propval *val)
4239{
Abhijeet Dharmapurikar676bd792017-05-31 16:21:57 -07004240 int rc;
4241
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004242 chg->pr_swap_in_progress = val->intval;
4243 /*
4244 * call the cc changed irq to handle real removals while
4245 * PR_SWAP was in progress
4246 */
4247 smblib_usb_typec_change(chg);
Abhijeet Dharmapurikar676bd792017-05-31 16:21:57 -07004248 rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT,
4249 val->intval ? TCC_DEBOUNCE_20MS_BIT : 0);
4250 if (rc < 0)
4251 smblib_err(chg, "Couldn't set tCC debounce rc=%d\n", rc);
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004252 return 0;
4253}
4254
Nicholas Troast34db5032016-03-28 12:26:44 -07004255/***************
4256 * Work Queues *
4257 ***************/
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05304258static void smblib_uusb_otg_work(struct work_struct *work)
4259{
4260 struct smb_charger *chg = container_of(work, struct smb_charger,
4261 uusb_otg_work.work);
4262 int rc;
4263 u8 stat;
4264 bool otg;
4265
4266 rc = smblib_read(chg, TYPE_C_STATUS_3_REG, &stat);
4267 if (rc < 0) {
4268 smblib_err(chg, "Couldn't read TYPE_C_STATUS_3 rc=%d\n", rc);
4269 goto out;
4270 }
4271
4272 otg = !!(stat & (U_USB_GND_NOVBUS_BIT | U_USB_GND_BIT));
4273 extcon_set_cable_state_(chg->extcon, EXTCON_USB_HOST, otg);
4274 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_3 = 0x%02x OTG=%d\n",
4275 stat, otg);
4276 power_supply_changed(chg->usb_psy);
4277
4278out:
4279 vote(chg->awake_votable, OTG_DELAY_VOTER, false, 0);
4280}
4281
Nicholas Troast34db5032016-03-28 12:26:44 -07004282
4283static void smblib_hvdcp_detect_work(struct work_struct *work)
4284{
4285 struct smb_charger *chg = container_of(work, struct smb_charger,
4286 hvdcp_detect_work.work);
Nicholas Troast34db5032016-03-28 12:26:44 -07004287
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07004288 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
4289 false, 0);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004290 power_supply_changed(chg->usb_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07004291}
4292
Harry Yangfe913842016-08-10 12:27:28 -07004293static void bms_update_work(struct work_struct *work)
Harry Yang5e1a5222016-07-26 15:16:04 -07004294{
4295 struct smb_charger *chg = container_of(work, struct smb_charger,
4296 bms_update_work);
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05304297
4298 smblib_suspend_on_debug_battery(chg);
4299
4300 if (chg->batt_psy)
4301 power_supply_changed(chg->batt_psy);
Harry Yang5e1a5222016-07-26 15:16:04 -07004302}
4303
Harry Yang166b15d2017-08-28 13:00:40 -07004304static void pl_update_work(struct work_struct *work)
4305{
4306 struct smb_charger *chg = container_of(work, struct smb_charger,
4307 pl_update_work);
4308
4309 smblib_stat_sw_override_cfg(chg, false);
4310}
4311
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004312static void clear_hdc_work(struct work_struct *work)
4313{
4314 struct smb_charger *chg = container_of(work, struct smb_charger,
4315 clear_hdc_work.work);
4316
4317 chg->is_hdc = 0;
4318}
4319
Harry Yang755a34b2016-11-01 01:18:51 -07004320static void rdstd_cc2_detach_work(struct work_struct *work)
4321{
4322 int rc;
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004323 u8 stat4, stat5;
Harry Yang755a34b2016-11-01 01:18:51 -07004324 struct smb_charger *chg = container_of(work, struct smb_charger,
4325 rdstd_cc2_detach_work);
4326
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004327 if (!chg->cc2_detach_wa_active)
4328 return;
4329
Harry Yang755a34b2016-11-01 01:18:51 -07004330 /*
4331 * WA steps -
4332 * 1. Enable both UFP and DFP, wait for 10ms.
4333 * 2. Disable DFP, wait for 30ms.
4334 * 3. Removal detected if both TYPEC_DEBOUNCE_DONE_STATUS
4335 * and TIMER_STAGE bits are gone, otherwise repeat all by
4336 * work rescheduling.
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004337 * Note, work will be cancelled when USB_PLUGIN rises.
Harry Yang755a34b2016-11-01 01:18:51 -07004338 */
4339
4340 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4341 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT,
4342 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT);
4343 if (rc < 0) {
4344 smblib_err(chg, "Couldn't write TYPE_C_CTRL_REG rc=%d\n", rc);
4345 return;
4346 }
4347
4348 usleep_range(10000, 11000);
4349
4350 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4351 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT,
4352 UFP_EN_CMD_BIT);
4353 if (rc < 0) {
4354 smblib_err(chg, "Couldn't write TYPE_C_CTRL_REG rc=%d\n", rc);
4355 return;
4356 }
4357
4358 usleep_range(30000, 31000);
4359
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004360 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
Harry Yang755a34b2016-11-01 01:18:51 -07004361 if (rc < 0) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004362 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
Harry Yang755a34b2016-11-01 01:18:51 -07004363 return;
4364 }
Harry Yang755a34b2016-11-01 01:18:51 -07004365
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004366 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
Harry Yang755a34b2016-11-01 01:18:51 -07004367 if (rc < 0) {
4368 smblib_err(chg,
4369 "Couldn't read TYPE_C_STATUS_5_REG rc=%d\n", rc);
4370 return;
4371 }
Harry Yang755a34b2016-11-01 01:18:51 -07004372
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004373 if ((stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT)
4374 || (stat5 & TIMER_STAGE_2_BIT)) {
4375 smblib_dbg(chg, PR_MISC, "rerunning DD=%d TS2BIT=%d\n",
4376 (int)(stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT),
4377 (int)(stat5 & TIMER_STAGE_2_BIT));
4378 goto rerun;
4379 }
4380
4381 smblib_dbg(chg, PR_MISC, "Bingo CC2 Removal detected\n");
4382 chg->cc2_detach_wa_active = false;
4383 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4384 EXIT_SNK_BASED_ON_CC_BIT, 0);
Harry Yang755a34b2016-11-01 01:18:51 -07004385 smblib_reg_block_restore(chg, cc2_detach_settings);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004386 mutex_lock(&chg->lock);
4387 smblib_usb_typec_change(chg);
4388 mutex_unlock(&chg->lock);
Harry Yang755a34b2016-11-01 01:18:51 -07004389 return;
4390
4391rerun:
4392 schedule_work(&chg->rdstd_cc2_detach_work);
4393}
4394
Nicholas Troastb11015f2017-01-17 17:56:45 -08004395static void smblib_otg_oc_exit(struct smb_charger *chg, bool success)
4396{
4397 int rc;
4398
4399 chg->otg_attempts = 0;
4400 if (!success) {
4401 smblib_err(chg, "OTG soft start failed\n");
4402 chg->otg_en = false;
4403 }
4404
4405 smblib_dbg(chg, PR_OTG, "enabling VBUS < 1V check\n");
4406 rc = smblib_masked_write(chg, OTG_CFG_REG,
4407 QUICKSTART_OTG_FASTROLESWAP_BIT, 0);
4408 if (rc < 0)
4409 smblib_err(chg, "Couldn't enable VBUS < 1V check rc=%d\n", rc);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004410}
4411
4412#define MAX_OC_FALLING_TRIES 10
4413static void smblib_otg_oc_work(struct work_struct *work)
4414{
4415 struct smb_charger *chg = container_of(work, struct smb_charger,
4416 otg_oc_work);
4417 int rc, i;
4418 u8 stat;
4419
4420 if (!chg->vbus_vreg || !chg->vbus_vreg->rdev)
4421 return;
4422
4423 smblib_err(chg, "over-current detected on VBUS\n");
4424 mutex_lock(&chg->otg_oc_lock);
4425 if (!chg->otg_en)
4426 goto unlock;
4427
4428 smblib_dbg(chg, PR_OTG, "disabling VBUS < 1V check\n");
4429 smblib_masked_write(chg, OTG_CFG_REG,
4430 QUICKSTART_OTG_FASTROLESWAP_BIT,
4431 QUICKSTART_OTG_FASTROLESWAP_BIT);
4432
4433 /*
4434 * If 500ms has passed and another over-current interrupt has not
4435 * triggered then it is likely that the software based soft start was
4436 * successful and the VBUS < 1V restriction should be re-enabled.
4437 */
4438 schedule_delayed_work(&chg->otg_ss_done_work, msecs_to_jiffies(500));
4439
4440 rc = _smblib_vbus_regulator_disable(chg->vbus_vreg->rdev);
4441 if (rc < 0) {
4442 smblib_err(chg, "Couldn't disable VBUS rc=%d\n", rc);
4443 goto unlock;
4444 }
4445
4446 if (++chg->otg_attempts > OTG_MAX_ATTEMPTS) {
4447 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4448 smblib_err(chg, "OTG failed to enable after %d attempts\n",
4449 chg->otg_attempts - 1);
4450 smblib_otg_oc_exit(chg, false);
4451 goto unlock;
4452 }
4453
4454 /*
4455 * The real time status should go low within 10ms. Poll every 1-2ms to
4456 * minimize the delay when re-enabling OTG.
4457 */
4458 for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) {
4459 usleep_range(1000, 2000);
4460 rc = smblib_read(chg, OTG_BASE + INT_RT_STS_OFFSET, &stat);
4461 if (rc >= 0 && !(stat & OTG_OVERCURRENT_RT_STS_BIT))
4462 break;
4463 }
4464
4465 if (i >= MAX_OC_FALLING_TRIES) {
4466 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4467 smblib_err(chg, "OTG OC did not fall after %dms\n",
4468 2 * MAX_OC_FALLING_TRIES);
4469 smblib_otg_oc_exit(chg, false);
4470 goto unlock;
4471 }
4472
4473 smblib_dbg(chg, PR_OTG, "OTG OC fell after %dms\n", 2 * i + 1);
4474 rc = _smblib_vbus_regulator_enable(chg->vbus_vreg->rdev);
4475 if (rc < 0) {
4476 smblib_err(chg, "Couldn't enable VBUS rc=%d\n", rc);
4477 goto unlock;
4478 }
4479
4480unlock:
4481 mutex_unlock(&chg->otg_oc_lock);
4482}
4483
4484static void smblib_vconn_oc_work(struct work_struct *work)
4485{
4486 struct smb_charger *chg = container_of(work, struct smb_charger,
4487 vconn_oc_work);
4488 int rc, i;
4489 u8 stat;
4490
Ashay Jaiswal15edce42017-03-31 23:29:58 +05304491 if (chg->micro_usb_mode)
4492 return;
4493
Nicholas Troastb11015f2017-01-17 17:56:45 -08004494 smblib_err(chg, "over-current detected on VCONN\n");
4495 if (!chg->vconn_vreg || !chg->vconn_vreg->rdev)
4496 return;
4497
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07004498 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004499 rc = _smblib_vconn_regulator_disable(chg->vconn_vreg->rdev);
4500 if (rc < 0) {
4501 smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc);
4502 goto unlock;
4503 }
4504
4505 if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
4506 smblib_err(chg, "VCONN failed to enable after %d attempts\n",
4507 chg->otg_attempts - 1);
4508 chg->vconn_en = false;
4509 chg->vconn_attempts = 0;
4510 goto unlock;
4511 }
4512
4513 /*
4514 * The real time status should go low within 10ms. Poll every 1-2ms to
4515 * minimize the delay when re-enabling OTG.
4516 */
4517 for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) {
4518 usleep_range(1000, 2000);
4519 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
4520 if (rc >= 0 && !(stat & TYPEC_VCONN_OVERCURR_STATUS_BIT))
4521 break;
4522 }
4523
4524 if (i >= MAX_OC_FALLING_TRIES) {
4525 smblib_err(chg, "VCONN OC did not fall after %dms\n",
4526 2 * MAX_OC_FALLING_TRIES);
4527 chg->vconn_en = false;
4528 chg->vconn_attempts = 0;
4529 goto unlock;
4530 }
4531
4532 smblib_dbg(chg, PR_OTG, "VCONN OC fell after %dms\n", 2 * i + 1);
4533 if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
4534 smblib_err(chg, "VCONN failed to enable after %d attempts\n",
4535 chg->vconn_attempts - 1);
4536 chg->vconn_en = false;
4537 goto unlock;
4538 }
4539
4540 rc = _smblib_vconn_regulator_enable(chg->vconn_vreg->rdev);
4541 if (rc < 0) {
4542 smblib_err(chg, "Couldn't enable VCONN rc=%d\n", rc);
4543 goto unlock;
4544 }
4545
4546unlock:
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07004547 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004548}
4549
4550static void smblib_otg_ss_done_work(struct work_struct *work)
4551{
4552 struct smb_charger *chg = container_of(work, struct smb_charger,
4553 otg_ss_done_work.work);
4554 int rc;
4555 bool success = false;
4556 u8 stat;
4557
4558 mutex_lock(&chg->otg_oc_lock);
4559 rc = smblib_read(chg, OTG_STATUS_REG, &stat);
4560 if (rc < 0)
4561 smblib_err(chg, "Couldn't read OTG status rc=%d\n", rc);
4562 else if (stat & BOOST_SOFTSTART_DONE_BIT)
4563 success = true;
4564
4565 smblib_otg_oc_exit(chg, success);
4566 mutex_unlock(&chg->otg_oc_lock);
4567}
4568
Ashay Jaiswal4d825782017-02-18 10:11:34 +05304569static void smblib_icl_change_work(struct work_struct *work)
4570{
4571 struct smb_charger *chg = container_of(work, struct smb_charger,
4572 icl_change_work.work);
4573 int rc, settled_ua;
4574
4575 rc = smblib_get_charge_param(chg, &chg->param.icl_stat, &settled_ua);
4576 if (rc < 0) {
4577 smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
4578 return;
4579 }
4580
4581 power_supply_changed(chg->usb_main_psy);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05304582
4583 smblib_dbg(chg, PR_INTERRUPT, "icl_settled=%d\n", settled_ua);
4584}
4585
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304586static void smblib_pl_enable_work(struct work_struct *work)
4587{
4588 struct smb_charger *chg = container_of(work, struct smb_charger,
4589 pl_enable_work.work);
4590
4591 smblib_dbg(chg, PR_PARALLEL, "timer expired, enabling parallel\n");
4592 vote(chg->pl_disable_votable, PL_DELAY_VOTER, false, 0);
4593 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
4594}
4595
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004596static void smblib_legacy_detection_work(struct work_struct *work)
4597{
4598 struct smb_charger *chg = container_of(work, struct smb_charger,
4599 legacy_detection_work);
4600 int rc;
4601 u8 stat;
4602 bool legacy, rp_high;
4603
4604 mutex_lock(&chg->lock);
4605 chg->typec_en_dis_active = 1;
4606 smblib_dbg(chg, PR_MISC, "running legacy unknown workaround\n");
4607 rc = smblib_masked_write(chg,
4608 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4609 TYPEC_DISABLE_CMD_BIT,
4610 TYPEC_DISABLE_CMD_BIT);
4611 if (rc < 0)
4612 smblib_err(chg, "Couldn't disable type-c rc=%d\n", rc);
4613
4614 /* wait for the adapter to turn off VBUS */
4615 msleep(500);
4616
4617 rc = smblib_masked_write(chg,
4618 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4619 TYPEC_DISABLE_CMD_BIT, 0);
4620 if (rc < 0)
4621 smblib_err(chg, "Couldn't enable type-c rc=%d\n", rc);
4622
4623 /* wait for type-c detection to complete */
4624 msleep(100);
4625
4626 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat);
4627 if (rc < 0) {
4628 smblib_err(chg, "Couldn't read typec stat5 rc = %d\n", rc);
4629 goto unlock;
4630 }
4631
4632 chg->typec_legacy_valid = true;
4633 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
4634 legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT;
Nicholas Troaste1932e42017-04-12 12:38:18 -07004635 rp_high = chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004636 if (!legacy || !rp_high)
4637 vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
4638 false, 0);
4639
4640unlock:
4641 chg->typec_en_dis_active = 0;
Nicholas Troast6439e172017-06-02 14:45:39 -07004642 smblib_usb_typec_change(chg);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004643 mutex_unlock(&chg->lock);
4644}
4645
Harry Yangba874ce2016-08-19 14:17:01 -07004646static int smblib_create_votables(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07004647{
4648 int rc = 0;
4649
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304650 chg->fcc_votable = find_votable("FCC");
Harry Yang0c35ff62017-04-06 00:02:30 -07004651 if (chg->fcc_votable == NULL) {
4652 rc = -EINVAL;
4653 smblib_err(chg, "Couldn't find FCC votable rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304654 return rc;
4655 }
4656
4657 chg->fv_votable = find_votable("FV");
Harry Yang0c35ff62017-04-06 00:02:30 -07004658 if (chg->fv_votable == NULL) {
4659 rc = -EINVAL;
4660 smblib_err(chg, "Couldn't find FV votable rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304661 return rc;
4662 }
4663
Ashay Jaiswalae1586d2017-03-22 23:18:51 +05304664 chg->usb_icl_votable = find_votable("USB_ICL");
4665 if (!chg->usb_icl_votable) {
Harry Yang0c35ff62017-04-06 00:02:30 -07004666 rc = -EINVAL;
4667 smblib_err(chg, "Couldn't find USB_ICL votable rc=%d\n", rc);
Ashay Jaiswalae1586d2017-03-22 23:18:51 +05304668 return rc;
4669 }
4670
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304671 chg->pl_disable_votable = find_votable("PL_DISABLE");
Harry Yang0c35ff62017-04-06 00:02:30 -07004672 if (chg->pl_disable_votable == NULL) {
4673 rc = -EINVAL;
4674 smblib_err(chg, "Couldn't find votable PL_DISABLE rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304675 return rc;
4676 }
Abhijeet Dharmapurikar38ef1422017-05-18 15:37:56 -07004677
4678 chg->pl_enable_votable_indirect = find_votable("PL_ENABLE_INDIRECT");
4679 if (chg->pl_enable_votable_indirect == NULL) {
4680 rc = -EINVAL;
4681 smblib_err(chg,
4682 "Couldn't find votable PL_ENABLE_INDIRECT rc=%d\n",
4683 rc);
4684 return rc;
4685 }
4686
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304687 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304688
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004689 chg->dc_suspend_votable = create_votable("DC_SUSPEND", VOTE_SET_ANY,
4690 smblib_dc_suspend_vote_callback,
4691 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07004692 if (IS_ERR(chg->dc_suspend_votable)) {
4693 rc = PTR_ERR(chg->dc_suspend_votable);
4694 return rc;
4695 }
4696
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004697 chg->dc_icl_votable = create_votable("DC_ICL", VOTE_MIN,
4698 smblib_dc_icl_vote_callback,
4699 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07004700 if (IS_ERR(chg->dc_icl_votable)) {
4701 rc = PTR_ERR(chg->dc_icl_votable);
4702 return rc;
4703 }
4704
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07004705 chg->pd_disallowed_votable_indirect
4706 = create_votable("PD_DISALLOWED_INDIRECT", VOTE_SET_ANY,
4707 smblib_pd_disallowed_votable_indirect_callback, chg);
4708 if (IS_ERR(chg->pd_disallowed_votable_indirect)) {
4709 rc = PTR_ERR(chg->pd_disallowed_votable_indirect);
4710 return rc;
4711 }
4712
4713 chg->pd_allowed_votable = create_votable("PD_ALLOWED",
4714 VOTE_SET_ANY, NULL, NULL);
Nicholas Troast34db5032016-03-28 12:26:44 -07004715 if (IS_ERR(chg->pd_allowed_votable)) {
4716 rc = PTR_ERR(chg->pd_allowed_votable);
4717 return rc;
4718 }
4719
Harry Yang223c6282016-06-14 15:48:36 -07004720 chg->awake_votable = create_votable("AWAKE", VOTE_SET_ANY,
4721 smblib_awake_vote_callback,
4722 chg);
4723 if (IS_ERR(chg->awake_votable)) {
4724 rc = PTR_ERR(chg->awake_votable);
4725 return rc;
4726 }
4727
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07004728 chg->chg_disable_votable = create_votable("CHG_DISABLE", VOTE_SET_ANY,
4729 smblib_chg_disable_vote_callback,
4730 chg);
4731 if (IS_ERR(chg->chg_disable_votable)) {
4732 rc = PTR_ERR(chg->chg_disable_votable);
4733 return rc;
4734 }
4735
Harry Yangaba1f5f2016-09-28 10:47:29 -07004736
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05304737 chg->hvdcp_disable_votable_indirect = create_votable(
4738 "HVDCP_DISABLE_INDIRECT",
4739 VOTE_SET_ANY,
4740 smblib_hvdcp_disable_indirect_vote_callback,
4741 chg);
4742 if (IS_ERR(chg->hvdcp_disable_votable_indirect)) {
4743 rc = PTR_ERR(chg->hvdcp_disable_votable_indirect);
4744 return rc;
4745 }
4746
4747 chg->hvdcp_enable_votable = create_votable("HVDCP_ENABLE",
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07004748 VOTE_SET_ANY,
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05304749 smblib_hvdcp_enable_vote_callback,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07004750 chg);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05304751 if (IS_ERR(chg->hvdcp_enable_votable)) {
4752 rc = PTR_ERR(chg->hvdcp_enable_votable);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07004753 return rc;
4754 }
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07004755
4756 chg->apsd_disable_votable = create_votable("APSD_DISABLE",
4757 VOTE_SET_ANY,
4758 smblib_apsd_disable_vote_callback,
4759 chg);
4760 if (IS_ERR(chg->apsd_disable_votable)) {
4761 rc = PTR_ERR(chg->apsd_disable_votable);
4762 return rc;
4763 }
4764
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05304765 chg->hvdcp_hw_inov_dis_votable = create_votable("HVDCP_HW_INOV_DIS",
4766 VOTE_SET_ANY,
4767 smblib_hvdcp_hw_inov_dis_vote_callback,
4768 chg);
4769 if (IS_ERR(chg->hvdcp_hw_inov_dis_votable)) {
4770 rc = PTR_ERR(chg->hvdcp_hw_inov_dis_votable);
4771 return rc;
4772 }
4773
Harry Yang4bf7d962017-03-13 16:51:43 -07004774 chg->usb_irq_enable_votable = create_votable("USB_IRQ_DISABLE",
4775 VOTE_SET_ANY,
4776 smblib_usb_irq_enable_vote_callback,
4777 chg);
4778 if (IS_ERR(chg->usb_irq_enable_votable)) {
4779 rc = PTR_ERR(chg->usb_irq_enable_votable);
4780 return rc;
4781 }
4782
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004783 chg->typec_irq_disable_votable = create_votable("TYPEC_IRQ_DISABLE",
4784 VOTE_SET_ANY,
4785 smblib_typec_irq_disable_vote_callback,
4786 chg);
4787 if (IS_ERR(chg->typec_irq_disable_votable)) {
4788 rc = PTR_ERR(chg->typec_irq_disable_votable);
4789 return rc;
4790 }
4791
Nicholas Troast320839e2016-06-03 10:18:00 -07004792 return rc;
4793}
4794
Harry Yangba874ce2016-08-19 14:17:01 -07004795static void smblib_destroy_votables(struct smb_charger *chg)
4796{
Harry Yangba874ce2016-08-19 14:17:01 -07004797 if (chg->dc_suspend_votable)
4798 destroy_votable(chg->dc_suspend_votable);
Harry Yangba874ce2016-08-19 14:17:01 -07004799 if (chg->usb_icl_votable)
4800 destroy_votable(chg->usb_icl_votable);
4801 if (chg->dc_icl_votable)
4802 destroy_votable(chg->dc_icl_votable);
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07004803 if (chg->pd_disallowed_votable_indirect)
4804 destroy_votable(chg->pd_disallowed_votable_indirect);
Harry Yangba874ce2016-08-19 14:17:01 -07004805 if (chg->pd_allowed_votable)
4806 destroy_votable(chg->pd_allowed_votable);
4807 if (chg->awake_votable)
4808 destroy_votable(chg->awake_votable);
Harry Yangaba1f5f2016-09-28 10:47:29 -07004809 if (chg->chg_disable_votable)
4810 destroy_votable(chg->chg_disable_votable);
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07004811 if (chg->apsd_disable_votable)
4812 destroy_votable(chg->apsd_disable_votable);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05304813 if (chg->hvdcp_hw_inov_dis_votable)
4814 destroy_votable(chg->hvdcp_hw_inov_dis_votable);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004815 if (chg->typec_irq_disable_votable)
4816 destroy_votable(chg->typec_irq_disable_votable);
Harry Yangba874ce2016-08-19 14:17:01 -07004817}
4818
4819static void smblib_iio_deinit(struct smb_charger *chg)
4820{
4821 if (!IS_ERR_OR_NULL(chg->iio.temp_chan))
4822 iio_channel_release(chg->iio.temp_chan);
4823 if (!IS_ERR_OR_NULL(chg->iio.temp_max_chan))
4824 iio_channel_release(chg->iio.temp_max_chan);
4825 if (!IS_ERR_OR_NULL(chg->iio.usbin_i_chan))
4826 iio_channel_release(chg->iio.usbin_i_chan);
4827 if (!IS_ERR_OR_NULL(chg->iio.usbin_v_chan))
4828 iio_channel_release(chg->iio.usbin_v_chan);
Nicholas Troast7dbcad22016-10-05 13:30:18 -07004829 if (!IS_ERR_OR_NULL(chg->iio.batt_i_chan))
4830 iio_channel_release(chg->iio.batt_i_chan);
Harry Yangba874ce2016-08-19 14:17:01 -07004831}
4832
Nicholas Troast320839e2016-06-03 10:18:00 -07004833int smblib_init(struct smb_charger *chg)
4834{
4835 int rc = 0;
4836
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004837 mutex_init(&chg->lock);
Nicholas Troast320839e2016-06-03 10:18:00 -07004838 mutex_init(&chg->write_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004839 mutex_init(&chg->otg_oc_lock);
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07004840 mutex_init(&chg->vconn_oc_lock);
Harry Yangfe913842016-08-10 12:27:28 -07004841 INIT_WORK(&chg->bms_update_work, bms_update_work);
Harry Yang166b15d2017-08-28 13:00:40 -07004842 INIT_WORK(&chg->pl_update_work, pl_update_work);
Harry Yang755a34b2016-11-01 01:18:51 -07004843 INIT_WORK(&chg->rdstd_cc2_detach_work, rdstd_cc2_detach_work);
Nicholas Troast320839e2016-06-03 10:18:00 -07004844 INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004845 INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004846 INIT_WORK(&chg->otg_oc_work, smblib_otg_oc_work);
4847 INIT_WORK(&chg->vconn_oc_work, smblib_vconn_oc_work);
4848 INIT_DELAYED_WORK(&chg->otg_ss_done_work, smblib_otg_ss_done_work);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05304849 INIT_DELAYED_WORK(&chg->icl_change_work, smblib_icl_change_work);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304850 INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004851 INIT_WORK(&chg->legacy_detection_work, smblib_legacy_detection_work);
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05304852 INIT_DELAYED_WORK(&chg->uusb_otg_work, smblib_uusb_otg_work);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05304853 INIT_DELAYED_WORK(&chg->bb_removal_work, smblib_bb_removal_work);
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07004854 chg->fake_capacity = -EINVAL;
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07004855 chg->fake_input_current_limited = -EINVAL;
Harry Yang589dd422017-07-28 18:41:42 -07004856 chg->fake_batt_status = -EINVAL;
Nicholas Troast320839e2016-06-03 10:18:00 -07004857
4858 switch (chg->mode) {
4859 case PARALLEL_MASTER:
Harry Yang0c35ff62017-04-06 00:02:30 -07004860 rc = qcom_batt_init();
4861 if (rc < 0) {
4862 smblib_err(chg, "Couldn't init qcom_batt_init rc=%d\n",
4863 rc);
4864 return rc;
4865 }
4866
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +05304867 rc = qcom_step_chg_init(chg->step_chg_enabled,
4868 chg->sw_jeita_enabled);
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05304869 if (rc < 0) {
4870 smblib_err(chg, "Couldn't init qcom_step_chg_init rc=%d\n",
4871 rc);
4872 return rc;
4873 }
4874
Nicholas Troast320839e2016-06-03 10:18:00 -07004875 rc = smblib_create_votables(chg);
4876 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004877 smblib_err(chg, "Couldn't create votables rc=%d\n",
Nicholas Troast320839e2016-06-03 10:18:00 -07004878 rc);
Harry Yang58a9e7a2016-06-23 14:54:43 -07004879 return rc;
Nicholas Troast320839e2016-06-03 10:18:00 -07004880 }
Harry Yang58a9e7a2016-06-23 14:54:43 -07004881
Harry Yang5e1a5222016-07-26 15:16:04 -07004882 rc = smblib_register_notifier(chg);
4883 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004884 smblib_err(chg,
Harry Yang5e1a5222016-07-26 15:16:04 -07004885 "Couldn't register notifier rc=%d\n", rc);
4886 return rc;
Harry Yang58a9e7a2016-06-23 14:54:43 -07004887 }
4888
Harry Yang995b7422016-08-29 16:06:50 -07004889 chg->bms_psy = power_supply_get_by_name("bms");
Ashay Jaiswal8afedfc2017-02-03 11:18:22 +05304890 chg->pl.psy = power_supply_get_by_name("parallel");
Harry Yang166b15d2017-08-28 13:00:40 -07004891 if (chg->pl.psy) {
4892 rc = smblib_stat_sw_override_cfg(chg, false);
4893 if (rc < 0) {
4894 smblib_err(chg,
4895 "Couldn't config stat sw rc=%d\n", rc);
4896 return rc;
4897 }
4898 }
Nicholas Troast320839e2016-06-03 10:18:00 -07004899 break;
4900 case PARALLEL_SLAVE:
4901 break;
4902 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004903 smblib_err(chg, "Unsupported mode %d\n", chg->mode);
Nicholas Troast320839e2016-06-03 10:18:00 -07004904 return -EINVAL;
4905 }
4906
4907 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07004908}
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004909
4910int smblib_deinit(struct smb_charger *chg)
4911{
Harry Yangba874ce2016-08-19 14:17:01 -07004912 switch (chg->mode) {
4913 case PARALLEL_MASTER:
Harry Yang0c35ff62017-04-06 00:02:30 -07004914 cancel_work_sync(&chg->bms_update_work);
Harry Yang166b15d2017-08-28 13:00:40 -07004915 cancel_work_sync(&chg->pl_update_work);
Harry Yang0c35ff62017-04-06 00:02:30 -07004916 cancel_work_sync(&chg->rdstd_cc2_detach_work);
4917 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
Harry Yang0c35ff62017-04-06 00:02:30 -07004918 cancel_delayed_work_sync(&chg->clear_hdc_work);
4919 cancel_work_sync(&chg->otg_oc_work);
4920 cancel_work_sync(&chg->vconn_oc_work);
4921 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4922 cancel_delayed_work_sync(&chg->icl_change_work);
4923 cancel_delayed_work_sync(&chg->pl_enable_work);
4924 cancel_work_sync(&chg->legacy_detection_work);
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05304925 cancel_delayed_work_sync(&chg->uusb_otg_work);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05304926 cancel_delayed_work_sync(&chg->bb_removal_work);
Harry Yangba874ce2016-08-19 14:17:01 -07004927 power_supply_unreg_notifier(&chg->nb);
4928 smblib_destroy_votables(chg);
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05304929 qcom_step_chg_deinit();
Harry Yang0c35ff62017-04-06 00:02:30 -07004930 qcom_batt_deinit();
Harry Yangba874ce2016-08-19 14:17:01 -07004931 break;
4932 case PARALLEL_SLAVE:
4933 break;
4934 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004935 smblib_err(chg, "Unsupported mode %d\n", chg->mode);
Harry Yangba874ce2016-08-19 14:17:01 -07004936 return -EINVAL;
4937 }
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004938
Harry Yangba874ce2016-08-19 14:17:01 -07004939 smblib_iio_deinit(chg);
Harry Yang5e1a5222016-07-26 15:16:04 -07004940
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004941 return 0;
4942}