blob: 48e689f5cef17b98a82d2ea9f823691867c5d137 [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
Nicholas Troast34db5032016-03-28 12:26:44 -0700146/********************
147 * REGISTER GETTERS *
148 ********************/
149
Nicholas Troast4c310492016-05-12 17:56:35 -0700150int smblib_get_charge_param(struct smb_charger *chg,
151 struct smb_chg_param *param, int *val_u)
152{
153 int rc = 0;
154 u8 val_raw;
155
156 rc = smblib_read(chg, param->reg, &val_raw);
157 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700158 smblib_err(chg, "%s: Couldn't read from 0x%04x rc=%d\n",
Nicholas Troast4c310492016-05-12 17:56:35 -0700159 param->name, param->reg, rc);
160 return rc;
161 }
162
Harry Yangf8b41252016-08-10 14:21:10 -0700163 if (param->get_proc)
164 *val_u = param->get_proc(param, val_raw);
165 else
166 *val_u = val_raw * param->step_u + param->min_u;
Nicholas Troast4c310492016-05-12 17:56:35 -0700167 smblib_dbg(chg, PR_REGISTER, "%s = %d (0x%02x)\n",
168 param->name, *val_u, val_raw);
169
170 return rc;
171}
172
173int smblib_get_usb_suspend(struct smb_charger *chg, int *suspend)
174{
175 int rc = 0;
176 u8 temp;
177
178 rc = smblib_read(chg, USBIN_CMD_IL_REG, &temp);
179 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700180 smblib_err(chg, "Couldn't read USBIN_CMD_IL rc=%d\n", rc);
Nicholas Troast4c310492016-05-12 17:56:35 -0700181 return rc;
182 }
183 *suspend = temp & USBIN_SUSPEND_BIT;
184
185 return rc;
186}
187
Nicholas Troast34db5032016-03-28 12:26:44 -0700188struct apsd_result {
189 const char * const name;
190 const u8 bit;
191 const enum power_supply_type pst;
192};
193
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700194enum {
195 UNKNOWN,
196 SDP,
197 CDP,
198 DCP,
199 OCP,
200 FLOAT,
201 HVDCP2,
202 HVDCP3,
203 MAX_TYPES
204};
205
Nicholas Troast34db5032016-03-28 12:26:44 -0700206static const struct apsd_result const smblib_apsd_results[] = {
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700207 [UNKNOWN] = {
208 .name = "UNKNOWN",
209 .bit = 0,
210 .pst = POWER_SUPPLY_TYPE_UNKNOWN
211 },
212 [SDP] = {
213 .name = "SDP",
214 .bit = SDP_CHARGER_BIT,
215 .pst = POWER_SUPPLY_TYPE_USB
216 },
217 [CDP] = {
218 .name = "CDP",
219 .bit = CDP_CHARGER_BIT,
220 .pst = POWER_SUPPLY_TYPE_USB_CDP
221 },
222 [DCP] = {
223 .name = "DCP",
224 .bit = DCP_CHARGER_BIT,
225 .pst = POWER_SUPPLY_TYPE_USB_DCP
226 },
227 [OCP] = {
228 .name = "OCP",
229 .bit = OCP_CHARGER_BIT,
230 .pst = POWER_SUPPLY_TYPE_USB_DCP
231 },
232 [FLOAT] = {
233 .name = "FLOAT",
234 .bit = FLOAT_CHARGER_BIT,
Ashay Jaiswalb9b2d2f2017-06-21 12:08:38 +0530235 .pst = POWER_SUPPLY_TYPE_USB_FLOAT
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700236 },
237 [HVDCP2] = {
238 .name = "HVDCP2",
239 .bit = DCP_CHARGER_BIT | QC_2P0_BIT,
240 .pst = POWER_SUPPLY_TYPE_USB_HVDCP
241 },
242 [HVDCP3] = {
243 .name = "HVDCP3",
244 .bit = DCP_CHARGER_BIT | QC_3P0_BIT,
245 .pst = POWER_SUPPLY_TYPE_USB_HVDCP_3,
246 },
Nicholas Troast34db5032016-03-28 12:26:44 -0700247};
248
249static const struct apsd_result *smblib_get_apsd_result(struct smb_charger *chg)
250{
251 int rc, i;
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700252 u8 apsd_stat, stat;
253 const struct apsd_result *result = &smblib_apsd_results[UNKNOWN];
Nicholas Troast34db5032016-03-28 12:26:44 -0700254
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700255 rc = smblib_read(chg, APSD_STATUS_REG, &apsd_stat);
Nicholas Troast34db5032016-03-28 12:26:44 -0700256 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700257 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700258 return result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700259 }
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700260 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", apsd_stat);
Nicholas Troast34db5032016-03-28 12:26:44 -0700261
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700262 if (!(apsd_stat & APSD_DTC_STATUS_DONE_BIT))
263 return result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700264
265 rc = smblib_read(chg, APSD_RESULT_STATUS_REG, &stat);
266 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700267 smblib_err(chg, "Couldn't read APSD_RESULT_STATUS rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700268 rc);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700269 return result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700270 }
271 stat &= APSD_RESULT_STATUS_MASK;
272
273 for (i = 0; i < ARRAY_SIZE(smblib_apsd_results); i++) {
274 if (smblib_apsd_results[i].bit == stat)
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700275 result = &smblib_apsd_results[i];
Nicholas Troast34db5032016-03-28 12:26:44 -0700276 }
277
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700278 if (apsd_stat & QC_CHARGER_BIT) {
279 /* since its a qc_charger, either return HVDCP3 or HVDCP2 */
280 if (result != &smblib_apsd_results[HVDCP3])
281 result = &smblib_apsd_results[HVDCP2];
282 }
283
284 return result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700285}
286
Nicholas Troast34db5032016-03-28 12:26:44 -0700287/********************
288 * REGISTER SETTERS *
289 ********************/
290
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530291static int chg_freq_list[] = {
292 9600, 9600, 6400, 4800, 3800, 3200, 2700, 2400, 2100, 1900, 1700,
293 1600, 1500, 1400, 1300, 1200,
294};
295
296int smblib_set_chg_freq(struct smb_chg_param *param,
297 int val_u, u8 *val_raw)
298{
299 u8 i;
300
301 if (val_u > param->max_u || val_u < param->min_u)
302 return -EINVAL;
303
304 /* Charger FSW is the configured freqency / 2 */
305 val_u *= 2;
306 for (i = 0; i < ARRAY_SIZE(chg_freq_list); i++) {
307 if (chg_freq_list[i] == val_u)
308 break;
309 }
310 if (i == ARRAY_SIZE(chg_freq_list)) {
311 pr_err("Invalid frequency %d Hz\n", val_u / 2);
312 return -EINVAL;
313 }
314
315 *val_raw = i;
316
317 return 0;
318}
319
320static int smblib_set_opt_freq_buck(struct smb_charger *chg, int fsw_khz)
321{
322 union power_supply_propval pval = {0, };
323 int rc = 0;
324
325 rc = smblib_set_charge_param(chg, &chg->param.freq_buck, fsw_khz);
326 if (rc < 0)
327 dev_err(chg->dev, "Error in setting freq_buck rc=%d\n", rc);
328
329 if (chg->mode == PARALLEL_MASTER && chg->pl.psy) {
330 pval.intval = fsw_khz;
Abhijeet Dharmapurikare9fd08d2017-02-27 11:05:28 -0800331 /*
332 * Some parallel charging implementations may not have
333 * PROP_BUCK_FREQ property - they could be running
334 * with a fixed frequency
335 */
336 power_supply_set_property(chg->pl.psy,
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530337 POWER_SUPPLY_PROP_BUCK_FREQ, &pval);
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530338 }
339
340 return rc;
341}
342
Nicholas Troast4c310492016-05-12 17:56:35 -0700343int smblib_set_charge_param(struct smb_charger *chg,
344 struct smb_chg_param *param, int val_u)
Nicholas Troast34db5032016-03-28 12:26:44 -0700345{
346 int rc = 0;
347 u8 val_raw;
348
Harry Yangf8b41252016-08-10 14:21:10 -0700349 if (param->set_proc) {
350 rc = param->set_proc(param, val_u, &val_raw);
351 if (rc < 0)
352 return -EINVAL;
353 } else {
354 if (val_u > param->max_u || val_u < param->min_u) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700355 smblib_err(chg, "%s: %d is out of range [%d, %d]\n",
Harry Yangf8b41252016-08-10 14:21:10 -0700356 param->name, val_u, param->min_u, param->max_u);
357 return -EINVAL;
358 }
359
360 val_raw = (val_u - param->min_u) / param->step_u;
Nicholas Troast34db5032016-03-28 12:26:44 -0700361 }
362
Nicholas Troast34db5032016-03-28 12:26:44 -0700363 rc = smblib_write(chg, param->reg, val_raw);
364 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700365 smblib_err(chg, "%s: Couldn't write 0x%02x to 0x%04x rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700366 param->name, val_raw, param->reg, rc);
367 return rc;
368 }
369
370 smblib_dbg(chg, PR_REGISTER, "%s = %d (0x%02x)\n",
371 param->name, val_u, val_raw);
372
373 return rc;
374}
375
Nicholas Troast4c310492016-05-12 17:56:35 -0700376int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend)
Nicholas Troast34db5032016-03-28 12:26:44 -0700377{
378 int rc = 0;
Abhijeet Dharmapurikar109802f712017-07-07 18:30:54 -0700379 int irq = chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq;
380
381 if (suspend && irq) {
382 if (chg->usb_icl_change_irq_enabled) {
383 disable_irq_nosync(irq);
384 chg->usb_icl_change_irq_enabled = false;
385 }
386 }
Nicholas Troast34db5032016-03-28 12:26:44 -0700387
388 rc = smblib_masked_write(chg, USBIN_CMD_IL_REG, USBIN_SUSPEND_BIT,
389 suspend ? USBIN_SUSPEND_BIT : 0);
390 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700391 smblib_err(chg, "Couldn't write %s to USBIN_SUSPEND_BIT rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700392 suspend ? "suspend" : "resume", rc);
393
Abhijeet Dharmapurikar109802f712017-07-07 18:30:54 -0700394 if (!suspend && irq) {
395 if (!chg->usb_icl_change_irq_enabled) {
396 enable_irq(irq);
397 chg->usb_icl_change_irq_enabled = true;
398 }
399 }
400
Nicholas Troast34db5032016-03-28 12:26:44 -0700401 return rc;
402}
403
Nicholas Troast4c310492016-05-12 17:56:35 -0700404int smblib_set_dc_suspend(struct smb_charger *chg, bool suspend)
Nicholas Troast34db5032016-03-28 12:26:44 -0700405{
406 int rc = 0;
407
408 rc = smblib_masked_write(chg, DCIN_CMD_IL_REG, DCIN_SUSPEND_BIT,
409 suspend ? DCIN_SUSPEND_BIT : 0);
410 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700411 smblib_err(chg, "Couldn't write %s to DCIN_SUSPEND_BIT rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700412 suspend ? "suspend" : "resume", rc);
413
414 return rc;
415}
416
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530417static int smblib_set_adapter_allowance(struct smb_charger *chg,
418 u8 allowed_voltage)
419{
420 int rc = 0;
421
Nicholas Troast7f55c922017-07-25 13:18:03 -0700422 /* PM660 only support max. 9V */
423 if (chg->smb_version == PM660_SUBTYPE) {
424 switch (allowed_voltage) {
425 case USBIN_ADAPTER_ALLOW_12V:
426 case USBIN_ADAPTER_ALLOW_9V_TO_12V:
427 allowed_voltage = USBIN_ADAPTER_ALLOW_9V;
428 break;
429 case USBIN_ADAPTER_ALLOW_5V_OR_12V:
430 case USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V:
431 allowed_voltage = USBIN_ADAPTER_ALLOW_5V_OR_9V;
432 break;
433 case USBIN_ADAPTER_ALLOW_5V_TO_12V:
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530434 allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_9V;
Nicholas Troast7f55c922017-07-25 13:18:03 -0700435 break;
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530436 }
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530437 }
438
439 rc = smblib_write(chg, USBIN_ADAPTER_ALLOW_CFG_REG, allowed_voltage);
440 if (rc < 0) {
441 smblib_err(chg, "Couldn't write 0x%02x to USBIN_ADAPTER_ALLOW_CFG rc=%d\n",
442 allowed_voltage, rc);
443 return rc;
444 }
445
446 return rc;
447}
448
Nicholas Troast34db5032016-03-28 12:26:44 -0700449#define MICRO_5V 5000000
450#define MICRO_9V 9000000
451#define MICRO_12V 12000000
452static int smblib_set_usb_pd_allowed_voltage(struct smb_charger *chg,
453 int min_allowed_uv, int max_allowed_uv)
454{
455 int rc;
456 u8 allowed_voltage;
457
458 if (min_allowed_uv == MICRO_5V && max_allowed_uv == MICRO_5V) {
459 allowed_voltage = USBIN_ADAPTER_ALLOW_5V;
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530460 smblib_set_opt_freq_buck(chg, chg->chg_freq.freq_5V);
Nicholas Troast34db5032016-03-28 12:26:44 -0700461 } else if (min_allowed_uv == MICRO_9V && max_allowed_uv == MICRO_9V) {
462 allowed_voltage = USBIN_ADAPTER_ALLOW_9V;
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530463 smblib_set_opt_freq_buck(chg, chg->chg_freq.freq_9V);
Nicholas Troast34db5032016-03-28 12:26:44 -0700464 } else if (min_allowed_uv == MICRO_12V && max_allowed_uv == MICRO_12V) {
465 allowed_voltage = USBIN_ADAPTER_ALLOW_12V;
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530466 smblib_set_opt_freq_buck(chg, chg->chg_freq.freq_12V);
Nicholas Troast34db5032016-03-28 12:26:44 -0700467 } else if (min_allowed_uv < MICRO_9V && max_allowed_uv <= MICRO_9V) {
468 allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_9V;
469 } else if (min_allowed_uv < MICRO_9V && max_allowed_uv <= MICRO_12V) {
470 allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_12V;
471 } else if (min_allowed_uv < MICRO_12V && max_allowed_uv <= MICRO_12V) {
472 allowed_voltage = USBIN_ADAPTER_ALLOW_9V_TO_12V;
473 } else {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700474 smblib_err(chg, "invalid allowed voltage [%d, %d]\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700475 min_allowed_uv, max_allowed_uv);
476 return -EINVAL;
477 }
478
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530479 rc = smblib_set_adapter_allowance(chg, allowed_voltage);
Nicholas Troast34db5032016-03-28 12:26:44 -0700480 if (rc < 0) {
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530481 smblib_err(chg, "Couldn't configure adapter allowance rc=%d\n",
482 rc);
Nicholas Troast34db5032016-03-28 12:26:44 -0700483 return rc;
484 }
485
486 return rc;
487}
488
489/********************
490 * HELPER FUNCTIONS *
491 ********************/
Ashay Jaiswal13a1b812017-07-17 14:49:05 +0530492static int smblib_request_dpdm(struct smb_charger *chg, bool enable)
493{
494 int rc = 0;
495
496 /* fetch the DPDM regulator */
497 if (!chg->dpdm_reg && of_get_property(chg->dev->of_node,
498 "dpdm-supply", NULL)) {
499 chg->dpdm_reg = devm_regulator_get(chg->dev, "dpdm");
500 if (IS_ERR(chg->dpdm_reg)) {
501 rc = PTR_ERR(chg->dpdm_reg);
502 smblib_err(chg, "Couldn't get dpdm regulator rc=%d\n",
503 rc);
504 chg->dpdm_reg = NULL;
505 return rc;
506 }
507 }
508
509 if (enable) {
510 if (chg->dpdm_reg && !regulator_is_enabled(chg->dpdm_reg)) {
511 smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n");
512 rc = regulator_enable(chg->dpdm_reg);
513 if (rc < 0)
514 smblib_err(chg,
515 "Couldn't enable dpdm regulator rc=%d\n",
516 rc);
517 }
518 } else {
519 if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) {
520 smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n");
521 rc = regulator_disable(chg->dpdm_reg);
522 if (rc < 0)
523 smblib_err(chg,
524 "Couldn't disable dpdm regulator rc=%d\n",
525 rc);
526 }
527 }
528
529 return rc;
530}
Nicholas Troast34db5032016-03-28 12:26:44 -0700531
Nicholas Troast93fb0f02017-03-01 10:17:13 -0800532static void smblib_rerun_apsd(struct smb_charger *chg)
533{
534 int rc;
535
536 smblib_dbg(chg, PR_MISC, "re-running APSD\n");
537 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
538 rc = smblib_masked_write(chg,
539 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
540 AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
541 if (rc < 0)
542 smblib_err(chg, "Couldn't enable HVDCP auth IRQ rc=%d\n",
543 rc);
544 }
545
546 rc = smblib_masked_write(chg, CMD_APSD_REG,
547 APSD_RERUN_BIT, APSD_RERUN_BIT);
548 if (rc < 0)
549 smblib_err(chg, "Couldn't re-run APSD rc=%d\n", rc);
550}
551
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -0700552static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -0700553{
Abhijeet Dharmapurikareda08222016-11-01 11:35:29 -0700554 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -0700555
Jack Pham9696e252016-05-23 11:15:15 -0700556 /* if PD is active, APSD is disabled so won't have a valid result */
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +0530557 if (chg->pd_active) {
Fenglin Wu80826e02017-04-25 21:45:08 +0800558 chg->real_charger_type = POWER_SUPPLY_TYPE_USB_PD;
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +0530559 } else {
560 /*
561 * Update real charger type only if its not FLOAT
562 * detected as as SDP
563 */
564 if (!(apsd_result->pst == POWER_SUPPLY_TYPE_USB_FLOAT &&
565 chg->real_charger_type == POWER_SUPPLY_TYPE_USB))
Fenglin Wu80826e02017-04-25 21:45:08 +0800566 chg->real_charger_type = apsd_result->pst;
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +0530567 }
Nicholas Troast34db5032016-03-28 12:26:44 -0700568
Nicholas Troast93fb0f02017-03-01 10:17:13 -0800569 smblib_dbg(chg, PR_MISC, "APSD=%s PD=%d\n",
570 apsd_result->name, chg->pd_active);
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -0700571 return apsd_result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700572}
573
Harry Yang5e1a5222016-07-26 15:16:04 -0700574static int smblib_notifier_call(struct notifier_block *nb,
Harry Yang58a9e7a2016-06-23 14:54:43 -0700575 unsigned long ev, void *v)
Harry Yang1d1034c2016-06-15 12:09:42 -0700576{
Harry Yang58a9e7a2016-06-23 14:54:43 -0700577 struct power_supply *psy = v;
Harry Yang5e1a5222016-07-26 15:16:04 -0700578 struct smb_charger *chg = container_of(nb, struct smb_charger, nb);
Harry Yang1d1034c2016-06-15 12:09:42 -0700579
Harry Yang5e1a5222016-07-26 15:16:04 -0700580 if (!strcmp(psy->desc->name, "bms")) {
581 if (!chg->bms_psy)
582 chg->bms_psy = psy;
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530583 if (ev == PSY_EVENT_PROP_CHANGED)
Harry Yang5e1a5222016-07-26 15:16:04 -0700584 schedule_work(&chg->bms_update_work);
585 }
586
Ashay Jaiswal8afedfc2017-02-03 11:18:22 +0530587 if (!chg->pl.psy && !strcmp(psy->desc->name, "parallel"))
Harry Yang58a9e7a2016-06-23 14:54:43 -0700588 chg->pl.psy = psy;
Harry Yang1d1034c2016-06-15 12:09:42 -0700589
Harry Yang58a9e7a2016-06-23 14:54:43 -0700590 return NOTIFY_OK;
591}
592
Harry Yang5e1a5222016-07-26 15:16:04 -0700593static int smblib_register_notifier(struct smb_charger *chg)
Harry Yang58a9e7a2016-06-23 14:54:43 -0700594{
595 int rc;
596
Harry Yang5e1a5222016-07-26 15:16:04 -0700597 chg->nb.notifier_call = smblib_notifier_call;
598 rc = power_supply_reg_notifier(&chg->nb);
Harry Yang58a9e7a2016-06-23 14:54:43 -0700599 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700600 smblib_err(chg, "Couldn't register psy notifier rc = %d\n", rc);
Harry Yang58a9e7a2016-06-23 14:54:43 -0700601 return rc;
602 }
603
604 return 0;
Harry Yang1d1034c2016-06-15 12:09:42 -0700605}
606
Harry Yangfe913842016-08-10 12:27:28 -0700607int smblib_mapping_soc_from_field_value(struct smb_chg_param *param,
608 int val_u, u8 *val_raw)
609{
610 if (val_u > param->max_u || val_u < param->min_u)
611 return -EINVAL;
612
613 *val_raw = val_u << 1;
614
615 return 0;
616}
617
618int smblib_mapping_cc_delta_to_field_value(struct smb_chg_param *param,
619 u8 val_raw)
620{
621 int val_u = val_raw * param->step_u + param->min_u;
622
623 if (val_u > param->max_u)
624 val_u -= param->max_u * 2;
625
626 return val_u;
627}
628
629int smblib_mapping_cc_delta_from_field_value(struct smb_chg_param *param,
630 int val_u, u8 *val_raw)
631{
632 if (val_u > param->max_u || val_u < param->min_u - param->max_u)
633 return -EINVAL;
634
635 val_u += param->max_u * 2 - param->min_u;
636 val_u %= param->max_u * 2;
637 *val_raw = val_u / param->step_u;
638
639 return 0;
640}
641
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530642static void smblib_uusb_removal(struct smb_charger *chg)
643{
644 int rc;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +0530645 struct smb_irq_data *data;
646 struct storm_watch *wdata;
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530647
Ashay Jaiswalc0361672017-03-21 12:24:16 +0530648 cancel_delayed_work_sync(&chg->pl_enable_work);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +0530649
Ashay Jaiswal13a1b812017-07-17 14:49:05 +0530650 rc = smblib_request_dpdm(chg, false);
651 if (rc < 0)
652 smblib_err(chg, "Couldn't to disable DPDM rc=%d\n", rc);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +0530653
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +0530654 if (chg->wa_flags & BOOST_BACK_WA) {
655 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
656 if (data) {
657 wdata = &data->storm_data;
658 update_storm_count(wdata, WEAK_CHG_STORM_COUNT);
659 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
660 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
661 false, 0);
662 }
663 }
Ashay Jaiswalc0361672017-03-21 12:24:16 +0530664 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
665 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
666
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530667 /* reset both usbin current and voltage votes */
668 vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
669 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
Ashay Jaiswalae23a042017-05-18 15:28:31 +0530670 vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530671
672 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
673
Ashay Jaiswal67ec7072017-02-16 14:14:58 +0530674 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
675 /* re-enable AUTH_IRQ_EN_CFG_BIT */
676 rc = smblib_masked_write(chg,
677 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
678 AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
679 if (rc < 0)
680 smblib_err(chg,
681 "Couldn't enable QC auth setting rc=%d\n", rc);
682 }
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530683
684 /* reconfigure allowed voltage for HVDCP */
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530685 rc = smblib_set_adapter_allowance(chg,
686 USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530687 if (rc < 0)
688 smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
689 rc);
690
691 chg->voltage_min_uv = MICRO_5V;
692 chg->voltage_max_uv = MICRO_5V;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +0530693 chg->usb_icl_delta_ua = 0;
694 chg->pulse_cnt = 0;
Ashay Jaiswal8507aa52017-04-14 09:42:32 +0530695 chg->uusb_apsd_rerun_done = false;
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530696
697 /* clear USB ICL vote for USB_PSY_VOTER */
698 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
699 if (rc < 0)
700 smblib_err(chg, "Couldn't un-vote for USB ICL rc=%d\n", rc);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -0800701
702 /* clear USB ICL vote for DCP_VOTER */
703 rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
704 if (rc < 0)
705 smblib_err(chg,
706 "Couldn't un-vote DCP from USB ICL rc=%d\n", rc);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530707}
708
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530709void smblib_suspend_on_debug_battery(struct smb_charger *chg)
710{
711 int rc;
712 union power_supply_propval val;
713
Ashay Jaiswalda8669b2017-02-10 23:24:23 +0530714 if (!chg->suspend_input_on_debug_batt)
715 return;
716
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530717 rc = power_supply_get_property(chg->bms_psy,
718 POWER_SUPPLY_PROP_DEBUG_BATTERY, &val);
719 if (rc < 0) {
720 smblib_err(chg, "Couldn't get debug battery prop rc=%d\n", rc);
721 return;
722 }
723
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800724 vote(chg->usb_icl_votable, DEBUG_BOARD_VOTER, val.intval, 0);
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530725 vote(chg->dc_suspend_votable, DEBUG_BOARD_VOTER, val.intval, 0);
726 if (val.intval)
727 pr_info("Input suspended: Fake battery\n");
728}
729
Abhijeet Dharmapurikar9dd61292017-01-25 16:40:08 -0800730int smblib_rerun_apsd_if_required(struct smb_charger *chg)
731{
Abhijeet Dharmapurikar9dd61292017-01-25 16:40:08 -0800732 union power_supply_propval val;
733 int rc;
734
735 rc = smblib_get_prop_usb_present(chg, &val);
736 if (rc < 0) {
737 smblib_err(chg, "Couldn't get usb present rc = %d\n", rc);
738 return rc;
739 }
740
741 if (!val.intval)
742 return 0;
743
Ashay Jaiswal13a1b812017-07-17 14:49:05 +0530744 rc = smblib_request_dpdm(chg, true);
745 if (rc < 0)
746 smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
Abhijeet Dharmapurikar025e63a2017-02-24 14:06:22 -0800747
Ashay Jaiswal8507aa52017-04-14 09:42:32 +0530748 chg->uusb_apsd_rerun_done = true;
Abhijeet Dharmapurikar025e63a2017-02-24 14:06:22 -0800749 smblib_rerun_apsd(chg);
750
Abhijeet Dharmapurikar9dd61292017-01-25 16:40:08 -0800751 return 0;
752}
753
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +0530754static int smblib_get_hw_pulse_cnt(struct smb_charger *chg, int *count)
Ashay Jaiswal6d308da2017-02-18 09:59:23 +0530755{
756 int rc;
757 u8 val[2];
758
759 switch (chg->smb_version) {
760 case PMI8998_SUBTYPE:
761 rc = smblib_read(chg, QC_PULSE_COUNT_STATUS_REG, val);
762 if (rc) {
763 pr_err("failed to read QC_PULSE_COUNT_STATUS_REG rc=%d\n",
764 rc);
765 return rc;
766 }
767 *count = val[0] & QC_PULSE_COUNT_MASK;
768 break;
769 case PM660_SUBTYPE:
770 rc = smblib_multibyte_read(chg,
771 QC_PULSE_COUNT_STATUS_1_REG, val, 2);
772 if (rc) {
773 pr_err("failed to read QC_PULSE_COUNT_STATUS_1_REG rc=%d\n",
774 rc);
775 return rc;
776 }
777 *count = (val[1] << 8) | val[0];
778 break;
779 default:
780 smblib_dbg(chg, PR_PARALLEL, "unknown SMB chip %d\n",
781 chg->smb_version);
782 return -EINVAL;
783 }
784
785 return 0;
786}
787
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +0530788static int smblib_get_pulse_cnt(struct smb_charger *chg, int *count)
789{
790 int rc;
791
792 /* Use software based pulse count if HW INOV is disabled */
793 if (get_effective_result(chg->hvdcp_hw_inov_dis_votable) > 0) {
794 *count = chg->pulse_cnt;
795 return 0;
796 }
797
798 /* Use h/w pulse count if autonomous mode is enabled */
799 rc = smblib_get_hw_pulse_cnt(chg, count);
800 if (rc < 0)
801 smblib_err(chg, "failed to read h/w pulse count rc=%d\n", rc);
802
803 return rc;
804}
805
Nicholas Troastbb76a142016-09-23 11:23:23 -0700806#define USBIN_25MA 25000
807#define USBIN_100MA 100000
808#define USBIN_150MA 150000
809#define USBIN_500MA 500000
810#define USBIN_900MA 900000
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800811
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800812static int set_sdp_current(struct smb_charger *chg, int icl_ua)
Nicholas Troast34db5032016-03-28 12:26:44 -0700813{
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800814 int rc;
815 u8 icl_options;
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +0530816 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700817
Nicholas Troastbb76a142016-09-23 11:23:23 -0700818 /* power source is SDP */
819 switch (icl_ua) {
820 case USBIN_100MA:
821 /* USB 2.0 100mA */
822 icl_options = 0;
823 break;
824 case USBIN_150MA:
825 /* USB 3.0 150mA */
826 icl_options = CFG_USB3P0_SEL_BIT;
827 break;
828 case USBIN_500MA:
829 /* USB 2.0 500mA */
830 icl_options = USB51_MODE_BIT;
831 break;
832 case USBIN_900MA:
833 /* USB 3.0 900mA */
834 icl_options = CFG_USB3P0_SEL_BIT | USB51_MODE_BIT;
835 break;
836 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700837 smblib_err(chg, "ICL %duA isn't supported for SDP\n", icl_ua);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800838 return -EINVAL;
Nicholas Troastbb76a142016-09-23 11:23:23 -0700839 }
Nicholas Troast34db5032016-03-28 12:26:44 -0700840
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +0530841 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB &&
842 apsd_result->pst == POWER_SUPPLY_TYPE_USB_FLOAT) {
843 /*
844 * change the float charger configuration to SDP, if this
845 * is the case of SDP being detected as FLOAT
846 */
847 rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
848 FORCE_FLOAT_SDP_CFG_BIT, FORCE_FLOAT_SDP_CFG_BIT);
849 if (rc < 0) {
850 smblib_err(chg, "Couldn't set float ICL options rc=%d\n",
851 rc);
852 return rc;
853 }
854 }
855
Nicholas Troastbb76a142016-09-23 11:23:23 -0700856 rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800857 CFG_USB3P0_SEL_BIT | USB51_MODE_BIT, icl_options);
Nicholas Troast34db5032016-03-28 12:26:44 -0700858 if (rc < 0) {
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800859 smblib_err(chg, "Couldn't set ICL options rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -0700860 return rc;
861 }
862
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800863 return rc;
864}
865
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700866static int get_sdp_current(struct smb_charger *chg, int *icl_ua)
867{
868 int rc;
869 u8 icl_options;
870 bool usb3 = false;
871
872 rc = smblib_read(chg, USBIN_ICL_OPTIONS_REG, &icl_options);
873 if (rc < 0) {
874 smblib_err(chg, "Couldn't get ICL options rc=%d\n", rc);
875 return rc;
876 }
877
878 usb3 = (icl_options & CFG_USB3P0_SEL_BIT);
879
880 if (icl_options & USB51_MODE_BIT)
881 *icl_ua = usb3 ? USBIN_900MA : USBIN_500MA;
882 else
883 *icl_ua = usb3 ? USBIN_150MA : USBIN_100MA;
884
885 return rc;
886}
887
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530888int smblib_set_icl_current(struct smb_charger *chg, int icl_ua)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800889{
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800890 int rc = 0;
891 bool override;
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800892
893 /* suspend and return if 25mA or less is requested */
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530894 if (icl_ua < USBIN_25MA)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800895 return smblib_set_usb_suspend(chg, true);
896
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530897 if (icl_ua == INT_MAX)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800898 goto override_suspend_config;
899
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800900 /* configure current */
Nicholas Troaste1932e42017-04-12 12:38:18 -0700901 if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
Fenglin Wu80826e02017-04-25 21:45:08 +0800902 && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) {
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800903 rc = set_sdp_current(chg, icl_ua);
904 if (rc < 0) {
905 smblib_err(chg, "Couldn't set SDP ICL rc=%d\n", rc);
906 goto enable_icl_changed_interrupt;
907 }
908 } else {
Abhijeet Dharmapurikar949d67e2017-05-25 15:10:56 -0700909 set_sdp_current(chg, 100000);
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -0700910 rc = smblib_set_charge_param(chg, &chg->param.usb_icl, icl_ua);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800911 if (rc < 0) {
912 smblib_err(chg, "Couldn't set HC ICL rc=%d\n", rc);
913 goto enable_icl_changed_interrupt;
914 }
915 }
916
917override_suspend_config:
918 /* determine if override needs to be enforced */
919 override = true;
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530920 if (icl_ua == INT_MAX) {
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800921 /* remove override if no voters - hw defaults is desired */
922 override = false;
Nicholas Troaste1932e42017-04-12 12:38:18 -0700923 } else if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
Fenglin Wu80826e02017-04-25 21:45:08 +0800924 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800925 /* For std cable with type = SDP never override */
926 override = false;
Fenglin Wu80826e02017-04-25 21:45:08 +0800927 else if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_CDP
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -0700928 && icl_ua == 1500000)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800929 /*
930 * For std cable with type = CDP override only if
931 * current is not 1500mA
932 */
933 override = false;
934 }
935
936 /* enforce override */
937 rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
938 USBIN_MODE_CHG_BIT, override ? USBIN_MODE_CHG_BIT : 0);
939
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800940 rc = smblib_icl_override(chg, override);
941 if (rc < 0) {
942 smblib_err(chg, "Couldn't set ICL override rc=%d\n", rc);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800943 goto enable_icl_changed_interrupt;
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800944 }
945
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800946 /* unsuspend after configuring current and override */
947 rc = smblib_set_usb_suspend(chg, false);
948 if (rc < 0) {
949 smblib_err(chg, "Couldn't resume input rc=%d\n", rc);
950 goto enable_icl_changed_interrupt;
951 }
952
953enable_icl_changed_interrupt:
Nicholas Troast34db5032016-03-28 12:26:44 -0700954 return rc;
955}
956
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700957int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua)
958{
959 int rc = 0;
960 u8 load_cfg;
961 bool override;
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700962
Nicholas Troaste1932e42017-04-12 12:38:18 -0700963 if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700964 || chg->micro_usb_mode)
965 && (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)) {
966 rc = get_sdp_current(chg, icl_ua);
967 if (rc < 0) {
968 smblib_err(chg, "Couldn't get SDP ICL rc=%d\n", rc);
969 return rc;
970 }
971 } else {
972 rc = smblib_read(chg, USBIN_LOAD_CFG_REG, &load_cfg);
973 if (rc < 0) {
974 smblib_err(chg, "Couldn't get load cfg rc=%d\n", rc);
975 return rc;
976 }
977 override = load_cfg & ICL_OVERRIDE_AFTER_APSD_BIT;
978 if (!override)
979 return INT_MAX;
980
981 /* override is set */
982 rc = smblib_get_charge_param(chg, &chg->param.usb_icl, icl_ua);
983 if (rc < 0) {
984 smblib_err(chg, "Couldn't get HC ICL rc=%d\n", rc);
985 return rc;
986 }
987 }
988
989 return 0;
990}
991
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530992/*********************
993 * VOTABLE CALLBACKS *
994 *********************/
995
996static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data,
997 int suspend, const char *client)
998{
999 struct smb_charger *chg = data;
1000
1001 /* resume input if suspend is invalid */
1002 if (suspend < 0)
1003 suspend = 0;
1004
1005 return smblib_set_dc_suspend(chg, (bool)suspend);
1006}
1007
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001008static int smblib_dc_icl_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -07001009 int icl_ua, const char *client)
Nicholas Troast34db5032016-03-28 12:26:44 -07001010{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001011 struct smb_charger *chg = data;
Nicholas Troast34db5032016-03-28 12:26:44 -07001012 int rc = 0;
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001013 bool suspend;
1014
1015 if (icl_ua < 0) {
1016 smblib_dbg(chg, PR_MISC, "No Voter hence suspending\n");
1017 icl_ua = 0;
1018 }
1019
1020 suspend = (icl_ua < USBIN_25MA);
1021 if (suspend)
1022 goto suspend;
Nicholas Troast34db5032016-03-28 12:26:44 -07001023
1024 rc = smblib_set_charge_param(chg, &chg->param.dc_icl, icl_ua);
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001025 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001026 smblib_err(chg, "Couldn't set DC input current limit rc=%d\n",
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001027 rc);
1028 return rc;
1029 }
1030
1031suspend:
1032 rc = vote(chg->dc_suspend_votable, USER_VOTER, suspend, 0);
1033 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001034 smblib_err(chg, "Couldn't vote to %s DC rc=%d\n",
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001035 suspend ? "suspend" : "resume", rc);
1036 return rc;
1037 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001038 return rc;
1039}
1040
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07001041static int smblib_pd_disallowed_votable_indirect_callback(
1042 struct votable *votable, void *data, int disallowed, const char *client)
1043{
1044 struct smb_charger *chg = data;
1045 int rc;
1046
1047 rc = vote(chg->pd_allowed_votable, PD_DISALLOWED_INDIRECT_VOTER,
1048 !disallowed, 0);
1049
1050 return rc;
1051}
1052
Harry Yang223c6282016-06-14 15:48:36 -07001053static int smblib_awake_vote_callback(struct votable *votable, void *data,
1054 int awake, const char *client)
1055{
1056 struct smb_charger *chg = data;
1057
1058 if (awake)
1059 pm_stay_awake(chg->dev);
1060 else
1061 pm_relax(chg->dev);
1062
1063 return 0;
1064}
1065
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07001066static int smblib_chg_disable_vote_callback(struct votable *votable, void *data,
1067 int chg_disable, const char *client)
1068{
1069 struct smb_charger *chg = data;
1070 int rc;
1071
1072 rc = smblib_masked_write(chg, CHARGING_ENABLE_CMD_REG,
1073 CHARGING_ENABLE_CMD_BIT,
1074 chg_disable ? 0 : CHARGING_ENABLE_CMD_BIT);
1075 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001076 smblib_err(chg, "Couldn't %s charging rc=%d\n",
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07001077 chg_disable ? "disable" : "enable", rc);
1078 return rc;
1079 }
1080
1081 return 0;
1082}
Harry Yangaba1f5f2016-09-28 10:47:29 -07001083
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301084static int smblib_hvdcp_enable_vote_callback(struct votable *votable,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001085 void *data,
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301086 int hvdcp_enable, const char *client)
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001087{
1088 struct smb_charger *chg = data;
1089 int rc;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301090 u8 val = HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_EN_BIT;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07001091 u8 stat;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301092
1093 /* vote to enable/disable HW autonomous INOV */
1094 vote(chg->hvdcp_hw_inov_dis_votable, client, !hvdcp_enable, 0);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001095
1096 /*
1097 * Disable the autonomous bit and auth bit for disabling hvdcp.
1098 * This ensures only qc 2.0 detection runs but no vbus
1099 * negotiation happens.
1100 */
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301101 if (!hvdcp_enable)
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001102 val = HVDCP_EN_BIT;
1103
1104 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301105 HVDCP_EN_BIT | HVDCP_AUTH_ALG_EN_CFG_BIT,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001106 val);
1107 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001108 smblib_err(chg, "Couldn't %s hvdcp rc=%d\n",
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301109 hvdcp_enable ? "enable" : "disable", rc);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001110 return rc;
1111 }
1112
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07001113 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
1114 if (rc < 0) {
1115 smblib_err(chg, "Couldn't read APSD status rc=%d\n", rc);
1116 return rc;
1117 }
1118
1119 /* re-run APSD if HVDCP was detected */
1120 if (stat & QC_CHARGER_BIT)
1121 smblib_rerun_apsd(chg);
1122
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001123 return 0;
1124}
1125
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301126static int smblib_hvdcp_disable_indirect_vote_callback(struct votable *votable,
1127 void *data, int hvdcp_disable, const char *client)
1128{
1129 struct smb_charger *chg = data;
1130
1131 vote(chg->hvdcp_enable_votable, HVDCP_INDIRECT_VOTER,
1132 !hvdcp_disable, 0);
1133
1134 return 0;
1135}
1136
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07001137static int smblib_apsd_disable_vote_callback(struct votable *votable,
1138 void *data,
1139 int apsd_disable, const char *client)
1140{
1141 struct smb_charger *chg = data;
1142 int rc;
1143
Nicholas Troastec4703c2017-01-30 14:52:33 -08001144 if (apsd_disable) {
Nicholas Troastec4703c2017-01-30 14:52:33 -08001145 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1146 AUTO_SRC_DETECT_BIT,
1147 0);
1148 if (rc < 0) {
1149 smblib_err(chg, "Couldn't disable APSD rc=%d\n", rc);
1150 return rc;
1151 }
1152 } else {
1153 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1154 AUTO_SRC_DETECT_BIT,
1155 AUTO_SRC_DETECT_BIT);
1156 if (rc < 0) {
1157 smblib_err(chg, "Couldn't enable APSD rc=%d\n", rc);
1158 return rc;
1159 }
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07001160 }
1161
1162 return 0;
1163}
Nicholas Troast8995a702016-12-05 10:22:22 -08001164
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301165static int smblib_hvdcp_hw_inov_dis_vote_callback(struct votable *votable,
1166 void *data, int disable, const char *client)
1167{
1168 struct smb_charger *chg = data;
1169 int rc;
1170
1171 if (disable) {
1172 /*
1173 * the pulse count register get zeroed when autonomous mode is
1174 * disabled. Track that in variables before disabling
1175 */
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +05301176 rc = smblib_get_hw_pulse_cnt(chg, &chg->pulse_cnt);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301177 if (rc < 0) {
1178 pr_err("failed to read QC_PULSE_COUNT_STATUS_REG rc=%d\n",
1179 rc);
1180 return rc;
1181 }
1182 }
1183
1184 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1185 HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT,
1186 disable ? 0 : HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT);
1187 if (rc < 0) {
1188 smblib_err(chg, "Couldn't %s hvdcp rc=%d\n",
1189 disable ? "disable" : "enable", rc);
1190 return rc;
1191 }
1192
1193 return rc;
1194}
1195
Harry Yang4bf7d962017-03-13 16:51:43 -07001196static int smblib_usb_irq_enable_vote_callback(struct votable *votable,
1197 void *data, int enable, const char *client)
1198{
1199 struct smb_charger *chg = data;
1200
1201 if (!chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq ||
1202 !chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq)
1203 return 0;
1204
1205 if (enable) {
1206 enable_irq(chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq);
1207 enable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
1208 } else {
1209 disable_irq(chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq);
1210 disable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
1211 }
1212
1213 return 0;
1214}
1215
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07001216static int smblib_typec_irq_disable_vote_callback(struct votable *votable,
1217 void *data, int disable, const char *client)
1218{
1219 struct smb_charger *chg = data;
1220
1221 if (!chg->irq_info[TYPE_C_CHANGE_IRQ].irq)
1222 return 0;
1223
1224 if (disable)
1225 disable_irq_nosync(chg->irq_info[TYPE_C_CHANGE_IRQ].irq);
1226 else
1227 enable_irq(chg->irq_info[TYPE_C_CHANGE_IRQ].irq);
1228
1229 return 0;
1230}
1231
Nicholas Troast8995a702016-12-05 10:22:22 -08001232/*******************
1233 * VCONN REGULATOR *
1234 * *****************/
1235
Nicholas Troastb11015f2017-01-17 17:56:45 -08001236#define MAX_OTG_SS_TRIES 2
Nicholas Troast8995a702016-12-05 10:22:22 -08001237static int _smblib_vconn_regulator_enable(struct regulator_dev *rdev)
1238{
1239 struct smb_charger *chg = rdev_get_drvdata(rdev);
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001240 int rc = 0;
1241 u8 val;
Nicholas Troast8995a702016-12-05 10:22:22 -08001242
1243 /*
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001244 * When enabling VCONN using the command register the CC pin must be
1245 * selected. VCONN should be supplied to the inactive CC pin hence using
1246 * the opposite of the CC_ORIENTATION_BIT.
Nicholas Troast8995a702016-12-05 10:22:22 -08001247 */
Nicholas Troastb11015f2017-01-17 17:56:45 -08001248 smblib_dbg(chg, PR_OTG, "enabling VCONN\n");
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07001249 val = chg->typec_status[3] &
1250 CC_ORIENTATION_BIT ? 0 : VCONN_EN_ORIENTATION_BIT;
Nicholas Troast8995a702016-12-05 10:22:22 -08001251 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1252 VCONN_EN_VALUE_BIT | VCONN_EN_ORIENTATION_BIT,
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07001253 VCONN_EN_VALUE_BIT | val);
Nicholas Troast8995a702016-12-05 10:22:22 -08001254 if (rc < 0) {
1255 smblib_err(chg, "Couldn't enable vconn setting rc=%d\n", rc);
1256 return rc;
1257 }
1258
1259 return rc;
1260}
1261
1262int smblib_vconn_regulator_enable(struct regulator_dev *rdev)
1263{
1264 struct smb_charger *chg = rdev_get_drvdata(rdev);
1265 int rc = 0;
1266
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001267 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001268 if (chg->vconn_en)
1269 goto unlock;
1270
1271 rc = _smblib_vconn_regulator_enable(rdev);
1272 if (rc >= 0)
1273 chg->vconn_en = true;
1274
1275unlock:
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001276 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001277 return rc;
1278}
1279
1280static int _smblib_vconn_regulator_disable(struct regulator_dev *rdev)
1281{
1282 struct smb_charger *chg = rdev_get_drvdata(rdev);
1283 int rc = 0;
1284
Nicholas Troastb11015f2017-01-17 17:56:45 -08001285 smblib_dbg(chg, PR_OTG, "disabling VCONN\n");
Nicholas Troast8995a702016-12-05 10:22:22 -08001286 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1287 VCONN_EN_VALUE_BIT, 0);
1288 if (rc < 0)
1289 smblib_err(chg, "Couldn't disable vconn regulator rc=%d\n", rc);
1290
1291 return rc;
1292}
1293
1294int smblib_vconn_regulator_disable(struct regulator_dev *rdev)
1295{
1296 struct smb_charger *chg = rdev_get_drvdata(rdev);
1297 int rc = 0;
1298
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001299 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001300 if (!chg->vconn_en)
1301 goto unlock;
1302
1303 rc = _smblib_vconn_regulator_disable(rdev);
1304 if (rc >= 0)
1305 chg->vconn_en = false;
1306
1307unlock:
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001308 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001309 return rc;
1310}
1311
1312int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev)
1313{
1314 struct smb_charger *chg = rdev_get_drvdata(rdev);
1315 int ret;
1316
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001317 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001318 ret = chg->vconn_en;
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001319 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001320 return ret;
1321}
1322
Nicholas Troast34db5032016-03-28 12:26:44 -07001323/*****************
1324 * OTG REGULATOR *
1325 *****************/
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301326#define MAX_RETRY 15
1327#define MIN_DELAY_US 2000
1328#define MAX_DELAY_US 9000
Anirudh Ghayaladf20da2017-07-03 10:52:29 +05301329static int otg_current[] = {250000, 500000, 1000000, 1500000};
1330static int smblib_enable_otg_wa(struct smb_charger *chg)
1331{
1332 u8 stat;
1333 int rc, i, retry_count = 0, min_delay = MIN_DELAY_US;
1334
1335 for (i = 0; i < ARRAY_SIZE(otg_current); i++) {
1336 smblib_dbg(chg, PR_OTG, "enabling OTG with %duA\n",
1337 otg_current[i]);
1338 rc = smblib_set_charge_param(chg, &chg->param.otg_cl,
1339 otg_current[i]);
1340 if (rc < 0) {
1341 smblib_err(chg, "Couldn't set otg limit rc=%d\n", rc);
1342 return rc;
1343 }
1344
1345 rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT);
1346 if (rc < 0) {
1347 smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc);
1348 return rc;
1349 }
1350
1351 retry_count = 0;
1352 min_delay = MIN_DELAY_US;
1353 do {
1354 usleep_range(min_delay, min_delay + 100);
1355 rc = smblib_read(chg, OTG_STATUS_REG, &stat);
1356 if (rc < 0) {
1357 smblib_err(chg, "Couldn't read OTG status rc=%d\n",
1358 rc);
1359 goto out;
1360 }
1361
1362 if (stat & BOOST_SOFTSTART_DONE_BIT) {
1363 rc = smblib_set_charge_param(chg,
1364 &chg->param.otg_cl, chg->otg_cl_ua);
1365 if (rc < 0) {
1366 smblib_err(chg, "Couldn't set otg limit rc=%d\n",
1367 rc);
1368 goto out;
1369 }
1370 break;
1371 }
1372 /* increase the delay for following iterations */
1373 if (retry_count > 5)
1374 min_delay = MAX_DELAY_US;
1375
1376 } while (retry_count++ < MAX_RETRY);
1377
1378 if (retry_count >= MAX_RETRY) {
1379 smblib_dbg(chg, PR_OTG, "OTG enable failed with %duA\n",
1380 otg_current[i]);
1381 rc = smblib_write(chg, CMD_OTG_REG, 0);
1382 if (rc < 0) {
1383 smblib_err(chg, "disable OTG rc=%d\n", rc);
1384 goto out;
1385 }
1386 } else {
1387 smblib_dbg(chg, PR_OTG, "OTG enabled\n");
1388 return 0;
1389 }
1390 }
1391
1392 if (i == ARRAY_SIZE(otg_current)) {
1393 rc = -EINVAL;
1394 goto out;
1395 }
1396
1397 return 0;
1398out:
1399 smblib_write(chg, CMD_OTG_REG, 0);
1400 return rc;
1401}
1402
Nicholas Troast8995a702016-12-05 10:22:22 -08001403static int _smblib_vbus_regulator_enable(struct regulator_dev *rdev)
Nicholas Troast34db5032016-03-28 12:26:44 -07001404{
1405 struct smb_charger *chg = rdev_get_drvdata(rdev);
Anirudh Ghayaladf20da2017-07-03 10:52:29 +05301406 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001407
Nicholas Troastb11015f2017-01-17 17:56:45 -08001408 smblib_dbg(chg, PR_OTG, "halt 1 in 8 mode\n");
Harry Yang360bd532016-09-26 11:03:22 -07001409 rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
1410 ENG_BUCKBOOST_HALT1_8_MODE_BIT,
1411 ENG_BUCKBOOST_HALT1_8_MODE_BIT);
1412 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001413 smblib_err(chg, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n",
Harry Yang360bd532016-09-26 11:03:22 -07001414 rc);
1415 return rc;
1416 }
1417
Nicholas Troastb11015f2017-01-17 17:56:45 -08001418 smblib_dbg(chg, PR_OTG, "enabling OTG\n");
Harry Yang360bd532016-09-26 11:03:22 -07001419
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301420 if (chg->wa_flags & OTG_WA) {
Anirudh Ghayaladf20da2017-07-03 10:52:29 +05301421 rc = smblib_enable_otg_wa(chg);
1422 if (rc < 0)
1423 smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc);
1424 } else {
1425 rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT);
1426 if (rc < 0)
1427 smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc);
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301428 }
1429
Nicholas Troast34db5032016-03-28 12:26:44 -07001430 return rc;
1431}
1432
Nicholas Troast8995a702016-12-05 10:22:22 -08001433int smblib_vbus_regulator_enable(struct regulator_dev *rdev)
Nicholas Troast34db5032016-03-28 12:26:44 -07001434{
1435 struct smb_charger *chg = rdev_get_drvdata(rdev);
1436 int rc = 0;
1437
Nicholas Troastb11015f2017-01-17 17:56:45 -08001438 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001439 if (chg->otg_en)
1440 goto unlock;
1441
Harry Yanga2fb0e32017-03-22 22:45:25 -07001442 if (!chg->usb_icl_votable) {
1443 chg->usb_icl_votable = find_votable("USB_ICL");
1444
1445 if (!chg->usb_icl_votable)
1446 return -EINVAL;
1447 }
1448 vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, true, 0);
1449
Nicholas Troast8995a702016-12-05 10:22:22 -08001450 rc = _smblib_vbus_regulator_enable(rdev);
1451 if (rc >= 0)
1452 chg->otg_en = true;
1453
1454unlock:
Nicholas Troastb11015f2017-01-17 17:56:45 -08001455 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001456 return rc;
1457}
1458
1459static int _smblib_vbus_regulator_disable(struct regulator_dev *rdev)
1460{
1461 struct smb_charger *chg = rdev_get_drvdata(rdev);
1462 int rc;
Nicholas Troast8995a702016-12-05 10:22:22 -08001463
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301464 if (chg->wa_flags & OTG_WA) {
1465 /* set OTG current limit to minimum value */
1466 rc = smblib_set_charge_param(chg, &chg->param.otg_cl,
1467 chg->param.otg_cl.min_u);
1468 if (rc < 0) {
1469 smblib_err(chg,
1470 "Couldn't set otg current limit rc=%d\n", rc);
1471 return rc;
1472 }
1473 }
1474
Nicholas Troastb11015f2017-01-17 17:56:45 -08001475 smblib_dbg(chg, PR_OTG, "disabling OTG\n");
Harry Yang360bd532016-09-26 11:03:22 -07001476 rc = smblib_write(chg, CMD_OTG_REG, 0);
1477 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001478 smblib_err(chg, "Couldn't disable OTG regulator rc=%d\n", rc);
Harry Yang360bd532016-09-26 11:03:22 -07001479 return rc;
1480 }
1481
Nicholas Troastb11015f2017-01-17 17:56:45 -08001482 smblib_dbg(chg, PR_OTG, "start 1 in 8 mode\n");
Harry Yang360bd532016-09-26 11:03:22 -07001483 rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
1484 ENG_BUCKBOOST_HALT1_8_MODE_BIT, 0);
1485 if (rc < 0) {
Nicholas Troast8995a702016-12-05 10:22:22 -08001486 smblib_err(chg, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n", rc);
Harry Yang360bd532016-09-26 11:03:22 -07001487 return rc;
1488 }
1489
Nicholas Troast8995a702016-12-05 10:22:22 -08001490 return 0;
1491}
Nicholas Troast34db5032016-03-28 12:26:44 -07001492
Nicholas Troast8995a702016-12-05 10:22:22 -08001493int smblib_vbus_regulator_disable(struct regulator_dev *rdev)
1494{
1495 struct smb_charger *chg = rdev_get_drvdata(rdev);
1496 int rc = 0;
1497
Nicholas Troastb11015f2017-01-17 17:56:45 -08001498 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001499 if (!chg->otg_en)
1500 goto unlock;
1501
1502 rc = _smblib_vbus_regulator_disable(rdev);
1503 if (rc >= 0)
1504 chg->otg_en = false;
1505
Harry Yanga2fb0e32017-03-22 22:45:25 -07001506 if (chg->usb_icl_votable)
1507 vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0);
Nicholas Troast8995a702016-12-05 10:22:22 -08001508unlock:
Nicholas Troastb11015f2017-01-17 17:56:45 -08001509 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07001510 return rc;
1511}
1512
1513int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev)
1514{
1515 struct smb_charger *chg = rdev_get_drvdata(rdev);
Nicholas Troast8995a702016-12-05 10:22:22 -08001516 int ret;
Nicholas Troast34db5032016-03-28 12:26:44 -07001517
Nicholas Troastb11015f2017-01-17 17:56:45 -08001518 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001519 ret = chg->otg_en;
Nicholas Troastb11015f2017-01-17 17:56:45 -08001520 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001521 return ret;
Nicholas Troast34db5032016-03-28 12:26:44 -07001522}
1523
1524/********************
1525 * BATT PSY GETTERS *
1526 ********************/
1527
1528int smblib_get_prop_input_suspend(struct smb_charger *chg,
1529 union power_supply_propval *val)
1530{
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08001531 val->intval
1532 = (get_client_vote(chg->usb_icl_votable, USER_VOTER) == 0)
1533 && get_client_vote(chg->dc_suspend_votable, USER_VOTER);
Nicholas Troast34db5032016-03-28 12:26:44 -07001534 return 0;
1535}
1536
1537int smblib_get_prop_batt_present(struct smb_charger *chg,
1538 union power_supply_propval *val)
1539{
1540 int rc;
1541 u8 stat;
1542
1543 rc = smblib_read(chg, BATIF_BASE + INT_RT_STS_OFFSET, &stat);
1544 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001545 smblib_err(chg, "Couldn't read BATIF_INT_RT_STS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07001546 return rc;
1547 }
1548
1549 val->intval = !(stat & (BAT_THERM_OR_ID_MISSING_RT_STS_BIT
1550 | BAT_TERMINAL_MISSING_RT_STS_BIT));
1551
1552 return rc;
1553}
1554
1555int smblib_get_prop_batt_capacity(struct smb_charger *chg,
1556 union power_supply_propval *val)
1557{
Harry Yang5e1a5222016-07-26 15:16:04 -07001558 int rc = -EINVAL;
1559
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07001560 if (chg->fake_capacity >= 0) {
1561 val->intval = chg->fake_capacity;
1562 return 0;
1563 }
1564
Harry Yang5e1a5222016-07-26 15:16:04 -07001565 if (chg->bms_psy)
1566 rc = power_supply_get_property(chg->bms_psy,
1567 POWER_SUPPLY_PROP_CAPACITY, val);
1568 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001569}
1570
1571int smblib_get_prop_batt_status(struct smb_charger *chg,
1572 union power_supply_propval *val)
1573{
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001574 union power_supply_propval pval = {0, };
Abhijeet Dharmapurikard97b2bf2017-07-06 17:03:00 -07001575 bool usb_online, dc_online, qnovo_en;
1576 u8 stat, pt_en_cmd;
Nicholas Troast8cb77552016-09-23 11:50:18 -07001577 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001578
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001579 rc = smblib_get_prop_usb_online(chg, &pval);
1580 if (rc < 0) {
1581 smblib_err(chg, "Couldn't get usb online property rc=%d\n",
1582 rc);
1583 return rc;
1584 }
1585 usb_online = (bool)pval.intval;
1586
1587 rc = smblib_get_prop_dc_online(chg, &pval);
1588 if (rc < 0) {
1589 smblib_err(chg, "Couldn't get dc online property rc=%d\n",
1590 rc);
1591 return rc;
1592 }
1593 dc_online = (bool)pval.intval;
1594
Nicholas Troast34db5032016-03-28 12:26:44 -07001595 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1596 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001597 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001598 rc);
1599 return rc;
1600 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001601 stat = stat & BATTERY_CHARGER_STATUS_MASK;
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001602
1603 if (!usb_online && !dc_online) {
1604 switch (stat) {
1605 case TERMINATE_CHARGE:
1606 case INHIBIT_CHARGE:
1607 val->intval = POWER_SUPPLY_STATUS_FULL;
1608 break;
1609 default:
1610 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
1611 break;
1612 }
1613 return rc;
1614 }
1615
Nicholas Troast8cb77552016-09-23 11:50:18 -07001616 switch (stat) {
1617 case TRICKLE_CHARGE:
1618 case PRE_CHARGE:
1619 case FAST_CHARGE:
1620 case FULLON_CHARGE:
1621 case TAPER_CHARGE:
Nicholas Troast34db5032016-03-28 12:26:44 -07001622 val->intval = POWER_SUPPLY_STATUS_CHARGING;
Nicholas Troast8cb77552016-09-23 11:50:18 -07001623 break;
1624 case TERMINATE_CHARGE:
1625 case INHIBIT_CHARGE:
1626 val->intval = POWER_SUPPLY_STATUS_FULL;
1627 break;
1628 case DISABLE_CHARGE:
1629 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
1630 break;
1631 default:
1632 val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
1633 break;
1634 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001635
Harry Yang7ecc1a12017-04-06 12:24:56 -07001636 if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
1637 return 0;
1638
Harry Yang589dd422017-07-28 18:41:42 -07001639 if (!usb_online && dc_online
1640 && chg->fake_batt_status == POWER_SUPPLY_STATUS_FULL) {
1641 val->intval = POWER_SUPPLY_STATUS_FULL;
1642 return 0;
1643 }
1644
Harry Yangc3c28d12017-04-17 16:41:19 -07001645 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_7_REG, &stat);
Harry Yang7ecc1a12017-04-06 12:24:56 -07001646 if (rc < 0) {
1647 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
1648 rc);
1649 return rc;
Abhijeet Dharmapurikard97b2bf2017-07-06 17:03:00 -07001650 }
Harry Yang7ecc1a12017-04-06 12:24:56 -07001651
Harry Yangc3c28d12017-04-17 16:41:19 -07001652 stat &= ENABLE_TRICKLE_BIT | ENABLE_PRE_CHARGING_BIT |
1653 ENABLE_FAST_CHARGING_BIT | ENABLE_FULLON_MODE_BIT;
Abhijeet Dharmapurikard97b2bf2017-07-06 17:03:00 -07001654
1655 rc = smblib_read(chg, QNOVO_PT_ENABLE_CMD_REG, &pt_en_cmd);
1656 if (rc < 0) {
1657 smblib_err(chg, "Couldn't read QNOVO_PT_ENABLE_CMD_REG rc=%d\n",
1658 rc);
1659 return rc;
1660 }
1661
1662 qnovo_en = (bool)(pt_en_cmd & QNOVO_PT_ENABLE_CMD_BIT);
1663
1664 /* ignore stat7 when qnovo is enabled */
1665 if (!qnovo_en && !stat)
Harry Yang7ecc1a12017-04-06 12:24:56 -07001666 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
1667
Nicholas Troast8cb77552016-09-23 11:50:18 -07001668 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07001669}
1670
1671int smblib_get_prop_batt_charge_type(struct smb_charger *chg,
1672 union power_supply_propval *val)
1673{
1674 int rc;
1675 u8 stat;
1676
1677 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1678 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001679 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001680 rc);
1681 return rc;
1682 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001683
1684 switch (stat & BATTERY_CHARGER_STATUS_MASK) {
1685 case TRICKLE_CHARGE:
1686 case PRE_CHARGE:
1687 val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1688 break;
1689 case FAST_CHARGE:
1690 case FULLON_CHARGE:
1691 val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
1692 break;
1693 case TAPER_CHARGE:
1694 val->intval = POWER_SUPPLY_CHARGE_TYPE_TAPER;
1695 break;
1696 default:
1697 val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
1698 }
1699
1700 return rc;
1701}
1702
1703int smblib_get_prop_batt_health(struct smb_charger *chg,
1704 union power_supply_propval *val)
1705{
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001706 union power_supply_propval pval;
Nicholas Troast34db5032016-03-28 12:26:44 -07001707 int rc;
Abhijeet Dharmapurikar33d18462017-05-15 13:38:53 -07001708 int effective_fv_uv;
Nicholas Troast34db5032016-03-28 12:26:44 -07001709 u8 stat;
1710
1711 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat);
1712 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001713 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001714 rc);
1715 return rc;
1716 }
1717 smblib_dbg(chg, PR_REGISTER, "BATTERY_CHARGER_STATUS_2 = 0x%02x\n",
1718 stat);
1719
1720 if (stat & CHARGER_ERROR_STATUS_BAT_OV_BIT) {
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001721 rc = smblib_get_prop_batt_voltage_now(chg, &pval);
1722 if (!rc) {
1723 /*
1724 * If Vbatt is within 40mV above Vfloat, then don't
1725 * treat it as overvoltage.
1726 */
Abhijeet Dharmapurikar33d18462017-05-15 13:38:53 -07001727 effective_fv_uv = get_effective_result(chg->fv_votable);
1728 if (pval.intval >= effective_fv_uv + 40000) {
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001729 val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
Abhijeet Dharmapurikar33d18462017-05-15 13:38:53 -07001730 smblib_err(chg, "battery over-voltage vbat_fg = %duV, fv = %duV\n",
1731 pval.intval, effective_fv_uv);
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001732 goto done;
1733 }
1734 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001735 }
1736
Harry Yang668fc5e2016-07-12 16:51:47 -07001737 if (stat & BAT_TEMP_STATUS_TOO_COLD_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001738 val->intval = POWER_SUPPLY_HEALTH_COLD;
Harry Yang668fc5e2016-07-12 16:51:47 -07001739 else if (stat & BAT_TEMP_STATUS_TOO_HOT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001740 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
Harry Yang668fc5e2016-07-12 16:51:47 -07001741 else if (stat & BAT_TEMP_STATUS_COLD_SOFT_LIMIT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001742 val->intval = POWER_SUPPLY_HEALTH_COOL;
Harry Yang668fc5e2016-07-12 16:51:47 -07001743 else if (stat & BAT_TEMP_STATUS_HOT_SOFT_LIMIT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001744 val->intval = POWER_SUPPLY_HEALTH_WARM;
Harry Yang668fc5e2016-07-12 16:51:47 -07001745 else
Nicholas Troast34db5032016-03-28 12:26:44 -07001746 val->intval = POWER_SUPPLY_HEALTH_GOOD;
Nicholas Troast34db5032016-03-28 12:26:44 -07001747
1748done:
1749 return rc;
1750}
1751
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001752int smblib_get_prop_system_temp_level(struct smb_charger *chg,
1753 union power_supply_propval *val)
1754{
1755 val->intval = chg->system_temp_level;
1756 return 0;
1757}
1758
Abhijeet Dharmapurikaracf32002017-05-11 11:54:17 -07001759int smblib_get_prop_system_temp_level_max(struct smb_charger *chg,
1760 union power_supply_propval *val)
1761{
1762 val->intval = chg->thermal_levels;
1763 return 0;
1764}
1765
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001766int smblib_get_prop_input_current_limited(struct smb_charger *chg,
1767 union power_supply_propval *val)
1768{
1769 u8 stat;
1770 int rc;
1771
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07001772 if (chg->fake_input_current_limited >= 0) {
1773 val->intval = chg->fake_input_current_limited;
1774 return 0;
1775 }
1776
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001777 rc = smblib_read(chg, AICL_STATUS_REG, &stat);
1778 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001779 smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n", rc);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001780 return rc;
1781 }
1782 val->intval = (stat & SOFT_ILIMIT_BIT) || chg->is_hdc;
1783 return 0;
1784}
1785
Nicholas Troast66b21d72016-09-20 15:33:20 -07001786int smblib_get_prop_batt_voltage_now(struct smb_charger *chg,
1787 union power_supply_propval *val)
1788{
1789 int rc;
1790
1791 if (!chg->bms_psy)
1792 return -EINVAL;
1793
1794 rc = power_supply_get_property(chg->bms_psy,
1795 POWER_SUPPLY_PROP_VOLTAGE_NOW, val);
1796 return rc;
1797}
1798
1799int smblib_get_prop_batt_current_now(struct smb_charger *chg,
1800 union power_supply_propval *val)
1801{
1802 int rc;
1803
1804 if (!chg->bms_psy)
1805 return -EINVAL;
1806
1807 rc = power_supply_get_property(chg->bms_psy,
1808 POWER_SUPPLY_PROP_CURRENT_NOW, val);
1809 return rc;
1810}
1811
1812int smblib_get_prop_batt_temp(struct smb_charger *chg,
1813 union power_supply_propval *val)
1814{
1815 int rc;
1816
1817 if (!chg->bms_psy)
1818 return -EINVAL;
1819
1820 rc = power_supply_get_property(chg->bms_psy,
1821 POWER_SUPPLY_PROP_TEMP, val);
1822 return rc;
1823}
1824
Subbaraman Narayanamurthyb491d022016-10-10 20:22:48 -07001825int smblib_get_prop_batt_charge_done(struct smb_charger *chg,
1826 union power_supply_propval *val)
1827{
1828 int rc;
1829 u8 stat;
1830
1831 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1832 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001833 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Subbaraman Narayanamurthyb491d022016-10-10 20:22:48 -07001834 rc);
1835 return rc;
1836 }
1837
1838 stat = stat & BATTERY_CHARGER_STATUS_MASK;
1839 val->intval = (stat == TERMINATE_CHARGE);
1840 return 0;
1841}
1842
Harry Yang40192cb2017-02-25 23:25:17 -08001843int smblib_get_prop_charge_qnovo_enable(struct smb_charger *chg,
1844 union power_supply_propval *val)
1845{
1846 int rc;
1847 u8 stat;
1848
1849 rc = smblib_read(chg, QNOVO_PT_ENABLE_CMD_REG, &stat);
1850 if (rc < 0) {
1851 smblib_err(chg, "Couldn't read QNOVO_PT_ENABLE_CMD rc=%d\n",
1852 rc);
1853 return rc;
1854 }
1855
1856 val->intval = (bool)(stat & QNOVO_PT_ENABLE_CMD_BIT);
1857 return 0;
1858}
1859
Nicholas Troast4fe68d02017-07-26 14:17:34 -07001860int smblib_get_prop_batt_charge_counter(struct smb_charger *chg,
1861 union power_supply_propval *val)
1862{
1863 int rc;
1864
1865 if (!chg->bms_psy)
1866 return -EINVAL;
1867
1868 rc = power_supply_get_property(chg->bms_psy,
1869 POWER_SUPPLY_PROP_CHARGE_COUNTER, val);
1870 return rc;
1871}
1872
Nicholas Troast34db5032016-03-28 12:26:44 -07001873/***********************
1874 * BATTERY PSY SETTERS *
1875 ***********************/
1876
1877int smblib_set_prop_input_suspend(struct smb_charger *chg,
1878 const union power_supply_propval *val)
1879{
1880 int rc;
1881
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08001882 /* vote 0mA when suspended */
1883 rc = vote(chg->usb_icl_votable, USER_VOTER, (bool)val->intval, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07001884 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001885 smblib_err(chg, "Couldn't vote to %s USB rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001886 (bool)val->intval ? "suspend" : "resume", rc);
1887 return rc;
1888 }
1889
1890 rc = vote(chg->dc_suspend_votable, USER_VOTER, (bool)val->intval, 0);
1891 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001892 smblib_err(chg, "Couldn't vote to %s DC rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001893 (bool)val->intval ? "suspend" : "resume", rc);
1894 return rc;
1895 }
1896
Nicholas Troast61ff40f2016-07-08 10:59:22 -07001897 power_supply_changed(chg->batt_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07001898 return rc;
1899}
1900
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07001901int smblib_set_prop_batt_capacity(struct smb_charger *chg,
1902 const union power_supply_propval *val)
1903{
1904 chg->fake_capacity = val->intval;
1905
1906 power_supply_changed(chg->batt_psy);
1907
1908 return 0;
1909}
1910
Harry Yang589dd422017-07-28 18:41:42 -07001911int smblib_set_prop_batt_status(struct smb_charger *chg,
1912 const union power_supply_propval *val)
1913{
1914 /* Faking battery full */
1915 if (val->intval == POWER_SUPPLY_STATUS_FULL)
1916 chg->fake_batt_status = val->intval;
1917 else
1918 chg->fake_batt_status = -EINVAL;
1919
1920 power_supply_changed(chg->batt_psy);
1921
1922 return 0;
1923}
1924
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001925int smblib_set_prop_system_temp_level(struct smb_charger *chg,
1926 const union power_supply_propval *val)
1927{
1928 if (val->intval < 0)
1929 return -EINVAL;
1930
1931 if (chg->thermal_levels <= 0)
1932 return -EINVAL;
1933
1934 if (val->intval > chg->thermal_levels)
1935 return -EINVAL;
1936
1937 chg->system_temp_level = val->intval;
Ashay Jaiswal147a6c32017-03-28 17:19:47 +05301938 /* disable parallel charge in case of system temp level */
1939 vote(chg->pl_disable_votable, THERMAL_DAEMON_VOTER,
1940 chg->system_temp_level ? true : false, 0);
1941
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001942 if (chg->system_temp_level == chg->thermal_levels)
Harry Yangaba1f5f2016-09-28 10:47:29 -07001943 return vote(chg->chg_disable_votable,
1944 THERMAL_DAEMON_VOTER, true, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001945
Harry Yangaba1f5f2016-09-28 10:47:29 -07001946 vote(chg->chg_disable_votable, THERMAL_DAEMON_VOTER, false, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001947 if (chg->system_temp_level == 0)
Harry Yangaba1f5f2016-09-28 10:47:29 -07001948 return vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, false, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001949
Harry Yangaba1f5f2016-09-28 10:47:29 -07001950 vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, true,
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001951 chg->thermal_mitigation[chg->system_temp_level]);
1952 return 0;
1953}
1954
Harry Yang40192cb2017-02-25 23:25:17 -08001955int smblib_set_prop_charge_qnovo_enable(struct smb_charger *chg,
1956 const union power_supply_propval *val)
1957{
1958 int rc = 0;
1959
1960 rc = smblib_masked_write(chg, QNOVO_PT_ENABLE_CMD_REG,
1961 QNOVO_PT_ENABLE_CMD_BIT,
1962 val->intval ? QNOVO_PT_ENABLE_CMD_BIT : 0);
1963 if (rc < 0) {
1964 dev_err(chg->dev, "Couldn't enable qnovo rc=%d\n", rc);
1965 return rc;
1966 }
1967
1968 return rc;
1969}
1970
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07001971int smblib_set_prop_input_current_limited(struct smb_charger *chg,
1972 const union power_supply_propval *val)
1973{
1974 chg->fake_input_current_limited = val->intval;
1975 return 0;
1976}
1977
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301978int smblib_rerun_aicl(struct smb_charger *chg)
1979{
Nicholas Troast20ae1912017-02-15 10:15:32 -08001980 int rc, settled_icl_ua;
1981 u8 stat;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301982
Nicholas Troast20ae1912017-02-15 10:15:32 -08001983 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
1984 if (rc < 0) {
1985 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
1986 rc);
1987 return rc;
1988 }
1989
1990 /* USB is suspended so skip re-running AICL */
1991 if (stat & USBIN_SUSPEND_STS_BIT)
1992 return rc;
1993
1994 smblib_dbg(chg, PR_MISC, "re-running AICL\n");
Ashay Jaiswal59a14122017-05-16 13:38:52 +05301995 rc = smblib_get_charge_param(chg, &chg->param.icl_stat,
1996 &settled_icl_ua);
1997 if (rc < 0) {
1998 smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
1999 return rc;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302000 }
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302001
Ashay Jaiswal59a14122017-05-16 13:38:52 +05302002 vote(chg->usb_icl_votable, AICL_RERUN_VOTER, true,
2003 max(settled_icl_ua - chg->param.usb_icl.step_u,
2004 chg->param.usb_icl.step_u));
2005 vote(chg->usb_icl_votable, AICL_RERUN_VOTER, false, 0);
2006
Nicholas Troast20ae1912017-02-15 10:15:32 -08002007 return 0;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302008}
2009
2010static int smblib_dp_pulse(struct smb_charger *chg)
2011{
2012 int rc;
2013
2014 /* QC 3.0 increment */
2015 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, SINGLE_INCREMENT_BIT,
2016 SINGLE_INCREMENT_BIT);
2017 if (rc < 0)
2018 smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
2019 rc);
2020
2021 return rc;
2022}
2023
2024static int smblib_dm_pulse(struct smb_charger *chg)
2025{
2026 int rc;
2027
2028 /* QC 3.0 decrement */
2029 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, SINGLE_DECREMENT_BIT,
2030 SINGLE_DECREMENT_BIT);
2031 if (rc < 0)
2032 smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
2033 rc);
2034
2035 return rc;
2036}
2037
2038int smblib_dp_dm(struct smb_charger *chg, int val)
2039{
2040 int target_icl_ua, rc = 0;
Ashay Jaiswalae23a042017-05-18 15:28:31 +05302041 union power_supply_propval pval;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302042
2043 switch (val) {
2044 case POWER_SUPPLY_DP_DM_DP_PULSE:
2045 rc = smblib_dp_pulse(chg);
2046 if (!rc)
2047 chg->pulse_cnt++;
2048 smblib_dbg(chg, PR_PARALLEL, "DP_DM_DP_PULSE rc=%d cnt=%d\n",
2049 rc, chg->pulse_cnt);
2050 break;
2051 case POWER_SUPPLY_DP_DM_DM_PULSE:
2052 rc = smblib_dm_pulse(chg);
2053 if (!rc && chg->pulse_cnt)
2054 chg->pulse_cnt--;
2055 smblib_dbg(chg, PR_PARALLEL, "DP_DM_DM_PULSE rc=%d cnt=%d\n",
2056 rc, chg->pulse_cnt);
2057 break;
2058 case POWER_SUPPLY_DP_DM_ICL_DOWN:
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302059 target_icl_ua = get_effective_result(chg->usb_icl_votable);
Ashay Jaiswalae23a042017-05-18 15:28:31 +05302060 if (target_icl_ua < 0) {
2061 /* no client vote, get the ICL from charger */
2062 rc = power_supply_get_property(chg->usb_psy,
2063 POWER_SUPPLY_PROP_HW_CURRENT_MAX,
2064 &pval);
2065 if (rc < 0) {
2066 smblib_err(chg,
2067 "Couldn't get max current rc=%d\n",
2068 rc);
2069 return rc;
2070 }
2071 target_icl_ua = pval.intval;
2072 }
2073
2074 /*
2075 * Check if any other voter voted on USB_ICL in case of
2076 * voter other than SW_QC3_VOTER reset and restart reduction
2077 * again.
2078 */
2079 if (target_icl_ua != get_client_vote(chg->usb_icl_votable,
2080 SW_QC3_VOTER))
2081 chg->usb_icl_delta_ua = 0;
2082
2083 chg->usb_icl_delta_ua += 100000;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302084 vote(chg->usb_icl_votable, SW_QC3_VOTER, true,
Ashay Jaiswalae23a042017-05-18 15:28:31 +05302085 target_icl_ua - 100000);
2086 smblib_dbg(chg, PR_PARALLEL, "ICL DOWN ICL=%d reduction=%d\n",
2087 target_icl_ua, chg->usb_icl_delta_ua);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302088 break;
2089 case POWER_SUPPLY_DP_DM_ICL_UP:
2090 default:
2091 break;
2092 }
2093
2094 return rc;
2095}
2096
Abhijeet Dharmapurikar3a580042017-07-24 09:43:00 -07002097int smblib_disable_hw_jeita(struct smb_charger *chg, bool disable)
2098{
2099 int rc;
2100 u8 mask;
2101
2102 /*
2103 * Disable h/w base JEITA compensation if s/w JEITA is enabled
2104 */
2105 mask = JEITA_EN_COLD_SL_FCV_BIT
2106 | JEITA_EN_HOT_SL_FCV_BIT
2107 | JEITA_EN_HOT_SL_CCC_BIT
2108 | JEITA_EN_COLD_SL_CCC_BIT,
2109 rc = smblib_masked_write(chg, JEITA_EN_CFG_REG, mask,
2110 disable ? 0 : mask);
2111 if (rc < 0) {
2112 dev_err(chg->dev,
2113 "Couldn't configure s/w jeita rc=%d\n",
2114 rc);
2115 return rc;
2116 }
2117 return 0;
2118}
2119
Nicholas Troast34db5032016-03-28 12:26:44 -07002120/*******************
Harry Yangf3023592016-07-20 14:56:41 -07002121 * DC PSY GETTERS *
2122 *******************/
2123
2124int smblib_get_prop_dc_present(struct smb_charger *chg,
2125 union power_supply_propval *val)
2126{
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002127 int rc;
Harry Yangf3023592016-07-20 14:56:41 -07002128 u8 stat;
2129
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002130 rc = smblib_read(chg, DCIN_BASE + INT_RT_STS_OFFSET, &stat);
Harry Yangf3023592016-07-20 14:56:41 -07002131 if (rc < 0) {
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002132 smblib_err(chg, "Couldn't read DCIN_RT_STS rc=%d\n", rc);
Harry Yangf3023592016-07-20 14:56:41 -07002133 return rc;
2134 }
Harry Yangf3023592016-07-20 14:56:41 -07002135
2136 val->intval = (bool)(stat & DCIN_PLUGIN_RT_STS_BIT);
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002137 return 0;
Harry Yangf3023592016-07-20 14:56:41 -07002138}
2139
2140int smblib_get_prop_dc_online(struct smb_charger *chg,
2141 union power_supply_propval *val)
2142{
2143 int rc = 0;
2144 u8 stat;
2145
2146 if (get_client_vote(chg->dc_suspend_votable, USER_VOTER)) {
2147 val->intval = false;
2148 return rc;
2149 }
2150
2151 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
2152 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002153 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
Harry Yangf3023592016-07-20 14:56:41 -07002154 rc);
2155 return rc;
2156 }
2157 smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
2158 stat);
2159
2160 val->intval = (stat & USE_DCIN_BIT) &&
Vic Wei7ade2842016-12-14 18:47:49 -08002161 (stat & VALID_INPUT_POWER_SOURCE_STS_BIT);
Harry Yangf3023592016-07-20 14:56:41 -07002162
2163 return rc;
2164}
2165
2166int smblib_get_prop_dc_current_max(struct smb_charger *chg,
2167 union power_supply_propval *val)
2168{
2169 val->intval = get_effective_result_locked(chg->dc_icl_votable);
2170 return 0;
2171}
2172
2173/*******************
Harry Yangd89ff1f2016-12-05 14:59:11 -08002174 * DC PSY SETTERS *
Harry Yangf3023592016-07-20 14:56:41 -07002175 * *****************/
2176
2177int smblib_set_prop_dc_current_max(struct smb_charger *chg,
2178 const union power_supply_propval *val)
2179{
2180 int rc;
2181
2182 rc = vote(chg->dc_icl_votable, USER_VOTER, true, val->intval);
2183 return rc;
2184}
2185
2186/*******************
Nicholas Troast34db5032016-03-28 12:26:44 -07002187 * USB PSY GETTERS *
2188 *******************/
2189
2190int smblib_get_prop_usb_present(struct smb_charger *chg,
2191 union power_supply_propval *val)
2192{
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002193 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07002194 u8 stat;
2195
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002196 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
Nicholas Troast34db5032016-03-28 12:26:44 -07002197 if (rc < 0) {
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002198 smblib_err(chg, "Couldn't read USBIN_RT_STS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07002199 return rc;
2200 }
Nicholas Troast34db5032016-03-28 12:26:44 -07002201
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002202 val->intval = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
2203 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002204}
2205
2206int smblib_get_prop_usb_online(struct smb_charger *chg,
2207 union power_supply_propval *val)
2208{
2209 int rc = 0;
2210 u8 stat;
2211
Abhijeet Dharmapurikar84923af2017-03-23 14:07:07 -07002212 if (get_client_vote_locked(chg->usb_icl_votable, USER_VOTER) == 0) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002213 val->intval = false;
2214 return rc;
2215 }
2216
2217 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
2218 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002219 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002220 rc);
2221 return rc;
2222 }
2223 smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
2224 stat);
2225
2226 val->intval = (stat & USE_USBIN_BIT) &&
Vic Wei7ade2842016-12-14 18:47:49 -08002227 (stat & VALID_INPUT_POWER_SOURCE_STS_BIT);
Nicholas Troast34db5032016-03-28 12:26:44 -07002228 return rc;
2229}
2230
Nicholas Troast7f55c922017-07-25 13:18:03 -07002231int smblib_get_prop_usb_voltage_max(struct smb_charger *chg,
2232 union power_supply_propval *val)
2233{
2234 switch (chg->real_charger_type) {
2235 case POWER_SUPPLY_TYPE_USB_HVDCP:
2236 case POWER_SUPPLY_TYPE_USB_PD:
2237 if (chg->smb_version == PM660_SUBTYPE)
2238 val->intval = MICRO_9V;
2239 else
2240 val->intval = MICRO_12V;
2241 break;
2242 default:
2243 val->intval = MICRO_5V;
2244 break;
2245 }
2246
2247 return 0;
2248}
2249
Nicholas Troast34db5032016-03-28 12:26:44 -07002250int smblib_get_prop_usb_voltage_now(struct smb_charger *chg,
2251 union power_supply_propval *val)
2252{
Harry Yangba874ce2016-08-19 14:17:01 -07002253 int rc = 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002254
Harry Yangba874ce2016-08-19 14:17:01 -07002255 rc = smblib_get_prop_usb_present(chg, val);
2256 if (rc < 0 || !val->intval)
2257 return rc;
2258
2259 if (!chg->iio.usbin_v_chan ||
2260 PTR_ERR(chg->iio.usbin_v_chan) == -EPROBE_DEFER)
2261 chg->iio.usbin_v_chan = iio_channel_get(chg->dev, "usbin_v");
2262
2263 if (IS_ERR(chg->iio.usbin_v_chan))
2264 return PTR_ERR(chg->iio.usbin_v_chan);
2265
2266 return iio_read_channel_processed(chg->iio.usbin_v_chan, &val->intval);
Nicholas Troast34db5032016-03-28 12:26:44 -07002267}
2268
Harry Yangba874ce2016-08-19 14:17:01 -07002269int smblib_get_prop_usb_current_now(struct smb_charger *chg,
2270 union power_supply_propval *val)
2271{
2272 int rc = 0;
2273
2274 rc = smblib_get_prop_usb_present(chg, val);
2275 if (rc < 0 || !val->intval)
2276 return rc;
2277
2278 if (!chg->iio.usbin_i_chan ||
2279 PTR_ERR(chg->iio.usbin_i_chan) == -EPROBE_DEFER)
2280 chg->iio.usbin_i_chan = iio_channel_get(chg->dev, "usbin_i");
2281
2282 if (IS_ERR(chg->iio.usbin_i_chan))
2283 return PTR_ERR(chg->iio.usbin_i_chan);
2284
2285 return iio_read_channel_processed(chg->iio.usbin_i_chan, &val->intval);
2286}
2287
2288int smblib_get_prop_charger_temp(struct smb_charger *chg,
2289 union power_supply_propval *val)
2290{
2291 int rc;
2292
2293 if (!chg->iio.temp_chan ||
2294 PTR_ERR(chg->iio.temp_chan) == -EPROBE_DEFER)
2295 chg->iio.temp_chan = iio_channel_get(chg->dev, "charger_temp");
2296
2297 if (IS_ERR(chg->iio.temp_chan))
2298 return PTR_ERR(chg->iio.temp_chan);
2299
2300 rc = iio_read_channel_processed(chg->iio.temp_chan, &val->intval);
2301 val->intval /= 100;
2302 return rc;
2303}
2304
2305int smblib_get_prop_charger_temp_max(struct smb_charger *chg,
2306 union power_supply_propval *val)
2307{
2308 int rc;
2309
2310 if (!chg->iio.temp_max_chan ||
2311 PTR_ERR(chg->iio.temp_max_chan) == -EPROBE_DEFER)
2312 chg->iio.temp_max_chan = iio_channel_get(chg->dev,
2313 "charger_temp_max");
2314 if (IS_ERR(chg->iio.temp_max_chan))
2315 return PTR_ERR(chg->iio.temp_max_chan);
2316
2317 rc = iio_read_channel_processed(chg->iio.temp_max_chan, &val->intval);
2318 val->intval /= 100;
2319 return rc;
2320}
2321
Nicholas Troast34db5032016-03-28 12:26:44 -07002322int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
2323 union power_supply_propval *val)
2324{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002325 if (chg->typec_status[3] & CC_ATTACHED_BIT)
2326 val->intval =
2327 (bool)(chg->typec_status[3] & CC_ORIENTATION_BIT) + 1;
Nicholas Troast34db5032016-03-28 12:26:44 -07002328 else
2329 val->intval = 0;
2330
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002331 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002332}
2333
2334static const char * const smblib_typec_mode_name[] = {
2335 [POWER_SUPPLY_TYPEC_NONE] = "NONE",
2336 [POWER_SUPPLY_TYPEC_SOURCE_DEFAULT] = "SOURCE_DEFAULT",
2337 [POWER_SUPPLY_TYPEC_SOURCE_MEDIUM] = "SOURCE_MEDIUM",
2338 [POWER_SUPPLY_TYPEC_SOURCE_HIGH] = "SOURCE_HIGH",
2339 [POWER_SUPPLY_TYPEC_NON_COMPLIANT] = "NON_COMPLIANT",
2340 [POWER_SUPPLY_TYPEC_SINK] = "SINK",
2341 [POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE] = "SINK_POWERED_CABLE",
2342 [POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY] = "SINK_DEBUG_ACCESSORY",
2343 [POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER] = "SINK_AUDIO_ADAPTER",
2344 [POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY] = "POWERED_CABLE_ONLY",
2345};
2346
2347static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
2348{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002349 switch (chg->typec_status[0]) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002350 case UFP_TYPEC_RDSTD_BIT:
2351 return POWER_SUPPLY_TYPEC_SOURCE_DEFAULT;
2352 case UFP_TYPEC_RD1P5_BIT:
2353 return POWER_SUPPLY_TYPEC_SOURCE_MEDIUM;
2354 case UFP_TYPEC_RD3P0_BIT:
2355 return POWER_SUPPLY_TYPEC_SOURCE_HIGH;
2356 default:
2357 break;
2358 }
2359
Nicholas Troaste1932e42017-04-12 12:38:18 -07002360 return POWER_SUPPLY_TYPEC_NONE;
Nicholas Troast34db5032016-03-28 12:26:44 -07002361}
2362
2363static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
2364{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002365 switch (chg->typec_status[1] & DFP_TYPEC_MASK) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002366 case DFP_RA_RA_BIT:
2367 return POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER;
2368 case DFP_RD_RD_BIT:
2369 return POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY;
2370 case DFP_RD_RA_VCONN_BIT:
2371 return POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE;
2372 case DFP_RD_OPEN_BIT:
2373 return POWER_SUPPLY_TYPEC_SINK;
Nicholas Troast34db5032016-03-28 12:26:44 -07002374 default:
2375 break;
2376 }
2377
2378 return POWER_SUPPLY_TYPEC_NONE;
2379}
2380
Nicholas Troaste1932e42017-04-12 12:38:18 -07002381static int smblib_get_prop_typec_mode(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07002382{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002383 if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
Nicholas Troaste1932e42017-04-12 12:38:18 -07002384 return smblib_get_prop_dfp_mode(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07002385 else
Nicholas Troaste1932e42017-04-12 12:38:18 -07002386 return smblib_get_prop_ufp_mode(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07002387}
2388
2389int smblib_get_prop_typec_power_role(struct smb_charger *chg,
2390 union power_supply_propval *val)
2391{
2392 int rc = 0;
2393 u8 ctrl;
2394
2395 rc = smblib_read(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &ctrl);
2396 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002397 smblib_err(chg, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002398 rc);
2399 return rc;
2400 }
2401 smblib_dbg(chg, PR_REGISTER, "TYPE_C_INTRPT_ENB_SOFTWARE_CTRL = 0x%02x\n",
2402 ctrl);
2403
2404 if (ctrl & TYPEC_DISABLE_CMD_BIT) {
2405 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
2406 return rc;
2407 }
2408
2409 switch (ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT)) {
2410 case 0:
2411 val->intval = POWER_SUPPLY_TYPEC_PR_DUAL;
2412 break;
2413 case DFP_EN_CMD_BIT:
2414 val->intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
2415 break;
2416 case UFP_EN_CMD_BIT:
2417 val->intval = POWER_SUPPLY_TYPEC_PR_SINK;
2418 break;
2419 default:
2420 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002421 smblib_err(chg, "unsupported power role 0x%02lx\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002422 ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT));
2423 return -EINVAL;
2424 }
2425
2426 return rc;
2427}
2428
2429int smblib_get_prop_pd_allowed(struct smb_charger *chg,
2430 union power_supply_propval *val)
2431{
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07002432 val->intval = get_effective_result(chg->pd_allowed_votable);
Nicholas Troast34db5032016-03-28 12:26:44 -07002433 return 0;
2434}
2435
Nicholas Troast133a7f52016-06-29 13:48:20 -07002436int smblib_get_prop_input_current_settled(struct smb_charger *chg,
2437 union power_supply_propval *val)
2438{
2439 return smblib_get_charge_param(chg, &chg->param.icl_stat, &val->intval);
2440}
2441
Fenglin Wuef4730e2017-01-11 18:16:25 +08002442#define HVDCP3_STEP_UV 200000
2443int smblib_get_prop_input_voltage_settled(struct smb_charger *chg,
2444 union power_supply_propval *val)
2445{
Fenglin Wuef4730e2017-01-11 18:16:25 +08002446 int rc, pulses;
Fenglin Wuef4730e2017-01-11 18:16:25 +08002447
Nicholas Troast5f314c12017-05-25 11:58:02 -07002448 switch (chg->real_charger_type) {
Fenglin Wuef4730e2017-01-11 18:16:25 +08002449 case POWER_SUPPLY_TYPE_USB_HVDCP_3:
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +05302450 rc = smblib_get_pulse_cnt(chg, &pulses);
Fenglin Wuef4730e2017-01-11 18:16:25 +08002451 if (rc < 0) {
2452 smblib_err(chg,
2453 "Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
2454 return 0;
2455 }
Fenglin Wuef4730e2017-01-11 18:16:25 +08002456 val->intval = MICRO_5V + HVDCP3_STEP_UV * pulses;
2457 break;
Nicholas Troast5f314c12017-05-25 11:58:02 -07002458 case POWER_SUPPLY_TYPE_USB_PD:
2459 val->intval = chg->voltage_min_uv;
2460 break;
Fenglin Wuef4730e2017-01-11 18:16:25 +08002461 default:
2462 val->intval = MICRO_5V;
2463 break;
2464 }
2465
2466 return 0;
2467}
2468
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002469int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg,
2470 union power_supply_propval *val)
2471{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002472 val->intval = chg->pd_hard_reset;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002473 return 0;
2474}
2475
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07002476int smblib_get_pe_start(struct smb_charger *chg,
2477 union power_supply_propval *val)
2478{
2479 /*
2480 * hvdcp timeout voter is the last one to allow pd. Use its vote
2481 * to indicate start of pe engine
2482 */
2483 val->intval
2484 = !get_client_vote_locked(chg->pd_disallowed_votable_indirect,
2485 HVDCP_TIMEOUT_VOTER);
2486 return 0;
2487}
2488
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002489int smblib_get_prop_die_health(struct smb_charger *chg,
Nicholas Troastb021dd92017-01-31 18:43:38 -08002490 union power_supply_propval *val)
2491{
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002492 int rc;
Nicholas Troastb021dd92017-01-31 18:43:38 -08002493 u8 stat;
2494
2495 rc = smblib_read(chg, TEMP_RANGE_STATUS_REG, &stat);
2496 if (rc < 0) {
2497 smblib_err(chg, "Couldn't read TEMP_RANGE_STATUS_REG rc=%d\n",
2498 rc);
2499 return rc;
2500 }
2501
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002502 /* TEMP_RANGE bits are mutually exclusive */
2503 switch (stat & TEMP_RANGE_MASK) {
2504 case TEMP_BELOW_RANGE_BIT:
2505 val->intval = POWER_SUPPLY_HEALTH_COOL;
2506 break;
2507 case TEMP_WITHIN_RANGE_BIT:
2508 val->intval = POWER_SUPPLY_HEALTH_WARM;
2509 break;
2510 case TEMP_ABOVE_RANGE_BIT:
2511 val->intval = POWER_SUPPLY_HEALTH_HOT;
2512 break;
2513 case ALERT_LEVEL_BIT:
2514 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
2515 break;
2516 default:
2517 val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
Nicholas Troastb021dd92017-01-31 18:43:38 -08002518 }
2519
Nicholas Troastb021dd92017-01-31 18:43:38 -08002520 return 0;
2521}
2522
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05302523#define SDP_CURRENT_UA 500000
2524#define CDP_CURRENT_UA 1500000
2525#define DCP_CURRENT_UA 1500000
2526#define HVDCP_CURRENT_UA 3000000
2527#define TYPEC_DEFAULT_CURRENT_UA 900000
2528#define TYPEC_MEDIUM_CURRENT_UA 1500000
2529#define TYPEC_HIGH_CURRENT_UA 3000000
2530static int get_rp_based_dcp_current(struct smb_charger *chg, int typec_mode)
2531{
2532 int rp_ua;
2533
2534 switch (typec_mode) {
2535 case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
2536 rp_ua = TYPEC_HIGH_CURRENT_UA;
2537 break;
2538 case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
2539 case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
2540 /* fall through */
2541 default:
2542 rp_ua = DCP_CURRENT_UA;
2543 }
2544
2545 return rp_ua;
2546}
2547
Nicholas Troast34db5032016-03-28 12:26:44 -07002548/*******************
2549 * USB PSY SETTERS *
2550 * *****************/
2551
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002552int smblib_set_prop_pd_current_max(struct smb_charger *chg,
2553 const union power_supply_propval *val)
2554{
2555 int rc;
2556
2557 if (chg->pd_active)
2558 rc = vote(chg->usb_icl_votable, PD_VOTER, true, val->intval);
2559 else
2560 rc = -EPERM;
2561
2562 return rc;
2563}
2564
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05302565static int smblib_handle_usb_current(struct smb_charger *chg,
2566 int usb_current)
2567{
2568 int rc = 0, rp_ua, typec_mode;
2569
2570 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_FLOAT) {
2571 if (usb_current == -ETIMEDOUT) {
2572 /*
2573 * Valid FLOAT charger, report the current based
2574 * of Rp
2575 */
2576 typec_mode = smblib_get_prop_typec_mode(chg);
2577 rp_ua = get_rp_based_dcp_current(chg, typec_mode);
2578 rc = vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER,
2579 true, rp_ua);
2580 if (rc < 0)
2581 return rc;
2582 } else {
2583 /*
2584 * FLOAT charger detected as SDP by USB driver,
2585 * charge with the requested current and update the
2586 * real_charger_type
2587 */
2588 chg->real_charger_type = POWER_SUPPLY_TYPE_USB;
2589 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
2590 true, usb_current);
2591 if (rc < 0)
2592 return rc;
2593 rc = vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER,
2594 false, 0);
2595 if (rc < 0)
2596 return rc;
2597 }
2598 } else {
2599 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
2600 true, usb_current);
2601 }
2602
2603 return rc;
2604}
2605
Nicholas Troast7f55c922017-07-25 13:18:03 -07002606int smblib_set_prop_sdp_current_max(struct smb_charger *chg,
Nicholas Troast34db5032016-03-28 12:26:44 -07002607 const union power_supply_propval *val)
2608{
Nicholas Troast8d33b7d2017-01-16 11:18:38 -08002609 int rc = 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002610
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002611 if (!chg->pd_active) {
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05302612 rc = smblib_handle_usb_current(chg, val->intval);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002613 } else if (chg->system_suspend_supported) {
2614 if (val->intval <= USBIN_25MA)
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302615 rc = vote(chg->usb_icl_votable,
2616 PD_SUSPEND_SUPPORTED_VOTER, true, val->intval);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002617 else
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302618 rc = vote(chg->usb_icl_votable,
2619 PD_SUSPEND_SUPPORTED_VOTER, false, 0);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002620 }
Nicholas Troast34db5032016-03-28 12:26:44 -07002621 return rc;
2622}
2623
Harry Yangd89ff1f2016-12-05 14:59:11 -08002624int smblib_set_prop_boost_current(struct smb_charger *chg,
2625 const union power_supply_propval *val)
2626{
2627 int rc = 0;
2628
2629 rc = smblib_set_charge_param(chg, &chg->param.freq_boost,
2630 val->intval <= chg->boost_threshold_ua ?
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05302631 chg->chg_freq.freq_below_otg_threshold :
2632 chg->chg_freq.freq_above_otg_threshold);
Harry Yangd89ff1f2016-12-05 14:59:11 -08002633 if (rc < 0) {
2634 dev_err(chg->dev, "Error in setting freq_boost rc=%d\n", rc);
2635 return rc;
2636 }
2637
2638 chg->boost_current_ua = val->intval;
2639 return rc;
2640}
2641
Nicholas Troast34db5032016-03-28 12:26:44 -07002642int smblib_set_prop_typec_power_role(struct smb_charger *chg,
2643 const union power_supply_propval *val)
2644{
2645 int rc = 0;
2646 u8 power_role;
2647
2648 switch (val->intval) {
2649 case POWER_SUPPLY_TYPEC_PR_NONE:
2650 power_role = TYPEC_DISABLE_CMD_BIT;
2651 break;
2652 case POWER_SUPPLY_TYPEC_PR_DUAL:
2653 power_role = 0;
2654 break;
2655 case POWER_SUPPLY_TYPEC_PR_SINK:
2656 power_role = UFP_EN_CMD_BIT;
2657 break;
2658 case POWER_SUPPLY_TYPEC_PR_SOURCE:
2659 power_role = DFP_EN_CMD_BIT;
2660 break;
2661 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002662 smblib_err(chg, "power role %d not supported\n", val->intval);
Nicholas Troast34db5032016-03-28 12:26:44 -07002663 return -EINVAL;
2664 }
2665
Jack Pham54a39bd2017-03-29 18:59:37 -07002666 if (power_role == UFP_EN_CMD_BIT) {
2667 /* disable PBS workaround when forcing sink mode */
2668 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0x0);
2669 if (rc < 0) {
2670 smblib_err(chg, "Couldn't write to TM_IO_DTEST4_SEL rc=%d\n",
2671 rc);
2672 }
2673 } else {
2674 /* restore it back to 0xA5 */
2675 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
2676 if (rc < 0) {
2677 smblib_err(chg, "Couldn't write to TM_IO_DTEST4_SEL rc=%d\n",
2678 rc);
2679 }
2680 }
2681
Nicholas Troast34db5032016-03-28 12:26:44 -07002682 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2683 TYPEC_POWER_ROLE_CMD_MASK, power_role);
2684 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002685 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 -07002686 power_role, rc);
2687 return rc;
2688 }
2689
2690 return rc;
2691}
2692
Nicholas Troast7f55c922017-07-25 13:18:03 -07002693int smblib_set_prop_pd_voltage_min(struct smb_charger *chg,
Nicholas Troast34db5032016-03-28 12:26:44 -07002694 const union power_supply_propval *val)
2695{
2696 int rc, min_uv;
2697
2698 min_uv = min(val->intval, chg->voltage_max_uv);
2699 rc = smblib_set_usb_pd_allowed_voltage(chg, min_uv,
2700 chg->voltage_max_uv);
2701 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002702 smblib_err(chg, "invalid max voltage %duV rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002703 val->intval, rc);
2704 return rc;
2705 }
2706
Harry Yangaba1f5f2016-09-28 10:47:29 -07002707 chg->voltage_min_uv = min_uv;
Nicholas Troast5f314c12017-05-25 11:58:02 -07002708 power_supply_changed(chg->usb_main_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07002709 return rc;
2710}
2711
Nicholas Troast7f55c922017-07-25 13:18:03 -07002712int smblib_set_prop_pd_voltage_max(struct smb_charger *chg,
Nicholas Troast34db5032016-03-28 12:26:44 -07002713 const union power_supply_propval *val)
2714{
2715 int rc, max_uv;
2716
2717 max_uv = max(val->intval, chg->voltage_min_uv);
2718 rc = smblib_set_usb_pd_allowed_voltage(chg, chg->voltage_min_uv,
2719 max_uv);
2720 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002721 smblib_err(chg, "invalid min voltage %duV rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002722 val->intval, rc);
2723 return rc;
2724 }
2725
Harry Yangaba1f5f2016-09-28 10:47:29 -07002726 chg->voltage_max_uv = max_uv;
Nicholas Troast34db5032016-03-28 12:26:44 -07002727 return rc;
2728}
2729
2730int smblib_set_prop_pd_active(struct smb_charger *chg,
2731 const union power_supply_propval *val)
2732{
2733 int rc;
Nicholas Troaste1932e42017-04-12 12:38:18 -07002734 bool orientation, sink_attached, hvdcp;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002735 u8 stat;
Nicholas Troast34db5032016-03-28 12:26:44 -07002736
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002737 if (!get_effective_result(chg->pd_allowed_votable))
Nicholas Troast34db5032016-03-28 12:26:44 -07002738 return -EINVAL;
Nicholas Troast34db5032016-03-28 12:26:44 -07002739
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002740 chg->pd_active = val->intval;
2741 if (chg->pd_active) {
2742 vote(chg->apsd_disable_votable, PD_VOTER, true, 0);
2743 vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
2744 vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
2745
2746 /*
2747 * VCONN_EN_ORIENTATION_BIT controls whether to use CC1 or CC2
2748 * line when TYPEC_SPARE_CFG_BIT (CC pin selection s/w override)
2749 * is set or when VCONN_EN_VALUE_BIT is set.
2750 */
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002751 orientation = chg->typec_status[3] & CC_ORIENTATION_BIT;
Harry Yang88acff42016-09-21 14:56:06 -07002752 rc = smblib_masked_write(chg,
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07002753 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2754 VCONN_EN_ORIENTATION_BIT,
2755 orientation ? 0 : VCONN_EN_ORIENTATION_BIT);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002756 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002757 smblib_err(chg,
Harry Yang88acff42016-09-21 14:56:06 -07002758 "Couldn't enable vconn on CC line rc=%d\n", rc);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002759
2760 /* SW controlled CC_OUT */
2761 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
2762 TYPEC_SPARE_CFG_BIT, TYPEC_SPARE_CFG_BIT);
2763 if (rc < 0)
2764 smblib_err(chg, "Couldn't enable SW cc_out rc=%d\n",
2765 rc);
2766
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302767 /*
2768 * Enforce 500mA for PD until the real vote comes in later.
2769 * It is guaranteed that pd_active is set prior to
2770 * pd_current_max
2771 */
Harry Yangcd995202016-11-07 13:32:52 -08002772 rc = vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002773 if (rc < 0)
Harry Yangcd995202016-11-07 13:32:52 -08002774 smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n",
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002775 rc);
Harry Yangcd995202016-11-07 13:32:52 -08002776
Nicholas Troastf9e44992017-03-14 09:06:56 -07002777 /* since PD was found the cable must be non-legacy */
2778 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
2779
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002780 /* clear USB ICL vote for DCP_VOTER */
Harry Yang631b99e2016-11-17 11:24:25 -08002781 rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002782 if (rc < 0)
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002783 smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n",
2784 rc);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002785
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302786 /* remove USB_PSY_VOTER */
2787 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002788 if (rc < 0)
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302789 smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002790 } else {
Nicholas Troaste1932e42017-04-12 12:38:18 -07002791 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
2792 if (rc < 0) {
2793 smblib_err(chg, "Couldn't read APSD status rc=%d\n",
2794 rc);
2795 return rc;
2796 }
2797
2798 hvdcp = stat & QC_CHARGER_BIT;
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002799 vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
2800 vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
2801 vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002802 vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER,
2803 false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002804
2805 /* HW controlled CC_OUT */
2806 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
2807 TYPEC_SPARE_CFG_BIT, 0);
2808 if (rc < 0)
2809 smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n",
2810 rc);
2811
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002812 /*
2813 * This WA should only run for HVDCP. Non-legacy SDP/CDP could
2814 * draw more, but this WA will remove Rd causing VBUS to drop,
2815 * and data could be interrupted. Non-legacy DCP could also draw
2816 * more, but it may impact compliance.
2817 */
Nicholas Troaste1932e42017-04-12 12:38:18 -07002818 sink_attached = chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT;
2819 if (!chg->typec_legacy_valid && !sink_attached && hvdcp)
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002820 schedule_work(&chg->legacy_detection_work);
Harry Yang88acff42016-09-21 14:56:06 -07002821 }
2822
Harry Yang6607b4a2016-05-17 17:50:09 -07002823 smblib_update_usb_type(chg);
Abhijeet Dharmapurikar76e2af52016-10-06 17:25:01 -07002824 power_supply_changed(chg->usb_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07002825 return rc;
2826}
2827
Fenglin Wuedd70792016-11-22 13:16:19 +08002828int smblib_set_prop_ship_mode(struct smb_charger *chg,
2829 const union power_supply_propval *val)
2830{
2831 int rc;
2832
2833 smblib_dbg(chg, PR_MISC, "Set ship mode: %d!!\n", !!val->intval);
2834
2835 rc = smblib_masked_write(chg, SHIP_MODE_REG, SHIP_MODE_EN_BIT,
2836 !!val->intval ? SHIP_MODE_EN_BIT : 0);
2837 if (rc < 0)
2838 dev_err(chg->dev, "Couldn't %s ship mode, rc=%d\n",
2839 !!val->intval ? "enable" : "disable", rc);
2840
2841 return rc;
2842}
2843
Harry Yang5e2bb712016-10-18 16:47:48 -07002844int smblib_reg_block_update(struct smb_charger *chg,
2845 struct reg_info *entry)
2846{
2847 int rc = 0;
2848
2849 while (entry && entry->reg) {
2850 rc = smblib_read(chg, entry->reg, &entry->bak);
2851 if (rc < 0) {
2852 dev_err(chg->dev, "Error in reading %s rc=%d\n",
2853 entry->desc, rc);
2854 break;
2855 }
2856 entry->bak &= entry->mask;
2857
2858 rc = smblib_masked_write(chg, entry->reg,
2859 entry->mask, entry->val);
2860 if (rc < 0) {
2861 dev_err(chg->dev, "Error in writing %s rc=%d\n",
2862 entry->desc, rc);
2863 break;
2864 }
2865 entry++;
2866 }
2867
2868 return rc;
2869}
2870
2871int smblib_reg_block_restore(struct smb_charger *chg,
2872 struct reg_info *entry)
2873{
2874 int rc = 0;
2875
2876 while (entry && entry->reg) {
2877 rc = smblib_masked_write(chg, entry->reg,
2878 entry->mask, entry->bak);
2879 if (rc < 0) {
2880 dev_err(chg->dev, "Error in writing %s rc=%d\n",
2881 entry->desc, rc);
2882 break;
2883 }
2884 entry++;
2885 }
2886
2887 return rc;
2888}
2889
Harry Yang755a34b2016-11-01 01:18:51 -07002890static struct reg_info cc2_detach_settings[] = {
2891 {
2892 .reg = TYPE_C_CFG_2_REG,
2893 .mask = TYPE_C_UFP_MODE_BIT | EN_TRY_SOURCE_MODE_BIT,
2894 .val = TYPE_C_UFP_MODE_BIT,
2895 .desc = "TYPE_C_CFG_2_REG",
2896 },
2897 {
2898 .reg = TYPE_C_CFG_3_REG,
2899 .mask = EN_TRYSINK_MODE_BIT,
2900 .val = 0,
2901 .desc = "TYPE_C_CFG_3_REG",
2902 },
2903 {
2904 .reg = TAPER_TIMER_SEL_CFG_REG,
2905 .mask = TYPEC_SPARE_CFG_BIT,
2906 .val = TYPEC_SPARE_CFG_BIT,
2907 .desc = "TAPER_TIMER_SEL_CFG_REG",
2908 },
2909 {
2910 .reg = TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2911 .mask = VCONN_EN_ORIENTATION_BIT,
2912 .val = 0,
2913 .desc = "TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG",
2914 },
2915 {
2916 .reg = MISC_CFG_REG,
2917 .mask = TCC_DEBOUNCE_20MS_BIT,
2918 .val = TCC_DEBOUNCE_20MS_BIT,
2919 .desc = "Tccdebounce time"
2920 },
2921 {
2922 },
2923};
2924
2925static int smblib_cc2_sink_removal_enter(struct smb_charger *chg)
2926{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002927 int rc, ccout, ufp_mode;
2928 u8 stat;
Harry Yang755a34b2016-11-01 01:18:51 -07002929
2930 if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002931 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002932
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002933 if (chg->cc2_detach_wa_active)
2934 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002935
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002936 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
Harry Yang755a34b2016-11-01 01:18:51 -07002937 if (rc < 0) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002938 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
Harry Yang755a34b2016-11-01 01:18:51 -07002939 return rc;
2940 }
Nicholas Troaste1932e42017-04-12 12:38:18 -07002941
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002942 ccout = (stat & CC_ATTACHED_BIT) ?
2943 (!!(stat & CC_ORIENTATION_BIT) + 1) : 0;
2944 ufp_mode = (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT) ?
2945 !(stat & UFP_DFP_MODE_STATUS_BIT) : 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002946
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002947 if (ccout != 2)
2948 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002949
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002950 if (!ufp_mode)
2951 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002952
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002953 chg->cc2_detach_wa_active = true;
2954 /* The CC2 removal WA will cause a type-c-change IRQ storm */
2955 smblib_reg_block_update(chg, cc2_detach_settings);
2956 schedule_work(&chg->rdstd_cc2_detach_work);
Harry Yang755a34b2016-11-01 01:18:51 -07002957 return rc;
2958}
2959
2960static int smblib_cc2_sink_removal_exit(struct smb_charger *chg)
2961{
Harry Yang755a34b2016-11-01 01:18:51 -07002962 if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002963 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002964
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002965 if (!chg->cc2_detach_wa_active)
2966 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002967
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002968 chg->cc2_detach_wa_active = false;
2969 cancel_work_sync(&chg->rdstd_cc2_detach_work);
2970 smblib_reg_block_restore(chg, cc2_detach_settings);
2971 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002972}
2973
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002974int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
2975 const union power_supply_propval *val)
2976{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002977 int rc = 0;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002978
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002979 if (chg->pd_hard_reset == val->intval)
2980 return rc;
2981
2982 chg->pd_hard_reset = val->intval;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002983 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002984 EXIT_SNK_BASED_ON_CC_BIT,
2985 (chg->pd_hard_reset) ? EXIT_SNK_BASED_ON_CC_BIT : 0);
2986 if (rc < 0)
2987 smblib_err(chg, "Couldn't set EXIT_SNK_BASED_ON_CC rc=%d\n",
Harry Yang755a34b2016-11-01 01:18:51 -07002988 rc);
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002989
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002990 vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER,
2991 chg->pd_hard_reset, 0);
Harry Yang755a34b2016-11-01 01:18:51 -07002992
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002993 return rc;
2994}
2995
Anirudh Ghayal941acaa2017-07-19 16:04:44 +05302996static int smblib_recover_from_soft_jeita(struct smb_charger *chg)
2997{
2998 u8 stat_1, stat_2;
2999 int rc;
3000
3001 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat_1);
3002 if (rc < 0) {
3003 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
3004 rc);
3005 return rc;
3006 }
3007
3008 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat_2);
3009 if (rc < 0) {
3010 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
3011 rc);
3012 return rc;
3013 }
3014
3015 if ((chg->jeita_status && !(stat_2 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK) &&
3016 ((stat_1 & BATTERY_CHARGER_STATUS_MASK) == TERMINATE_CHARGE))) {
3017 /*
3018 * We are moving from JEITA soft -> Normal and charging
3019 * is terminated
3020 */
3021 rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG, 0);
3022 if (rc < 0) {
3023 smblib_err(chg, "Couldn't disable charging rc=%d\n",
3024 rc);
3025 return rc;
3026 }
3027 rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG,
3028 CHARGING_ENABLE_CMD_BIT);
3029 if (rc < 0) {
3030 smblib_err(chg, "Couldn't enable charging rc=%d\n",
3031 rc);
3032 return rc;
3033 }
3034 }
3035
3036 chg->jeita_status = stat_2 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK;
3037
3038 return 0;
3039}
3040
Nicholas Troast7dbcad22016-10-05 13:30:18 -07003041/************************
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003042 * USB MAIN PSY GETTERS *
3043 ************************/
3044int smblib_get_prop_fcc_delta(struct smb_charger *chg,
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05303045 union power_supply_propval *val)
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003046{
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05303047 int rc, jeita_cc_delta_ua = 0;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003048
3049 rc = smblib_get_jeita_cc_delta(chg, &jeita_cc_delta_ua);
3050 if (rc < 0) {
3051 smblib_err(chg, "Couldn't get jeita cc delta rc=%d\n", rc);
3052 jeita_cc_delta_ua = 0;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003053 }
3054
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05303055 val->intval = jeita_cc_delta_ua;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003056 return 0;
3057}
3058
3059/************************
3060 * USB MAIN PSY SETTERS *
3061 ************************/
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003062int smblib_get_charge_current(struct smb_charger *chg,
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003063 int *total_current_ua)
3064{
Ashay Jaiswal7b6eb962017-04-26 14:34:29 +05303065 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003066 union power_supply_propval val = {0, };
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003067 int rc = 0, typec_source_rd, current_ua;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003068 bool non_compliant;
3069 u8 stat5;
3070
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003071 if (chg->pd_active) {
3072 *total_current_ua =
3073 get_client_vote_locked(chg->usb_icl_votable, PD_VOTER);
3074 return rc;
3075 }
3076
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003077 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
3078 if (rc < 0) {
3079 smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc);
3080 return rc;
3081 }
3082 non_compliant = stat5 & TYPEC_NONCOMP_LEGACY_CABLE_STATUS_BIT;
3083
3084 /* get settled ICL */
3085 rc = smblib_get_prop_input_current_settled(chg, &val);
3086 if (rc < 0) {
3087 smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
3088 return rc;
3089 }
3090
3091 typec_source_rd = smblib_get_prop_ufp_mode(chg);
3092
3093 /* QC 2.0/3.0 adapter */
3094 if (apsd_result->bit & (QC_3P0_BIT | QC_2P0_BIT)) {
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303095 *total_current_ua = HVDCP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003096 return 0;
3097 }
3098
3099 if (non_compliant) {
3100 switch (apsd_result->bit) {
3101 case CDP_CHARGER_BIT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303102 current_ua = CDP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003103 break;
3104 case DCP_CHARGER_BIT:
3105 case OCP_CHARGER_BIT:
3106 case FLOAT_CHARGER_BIT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303107 current_ua = DCP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003108 break;
3109 default:
3110 current_ua = 0;
3111 break;
3112 }
3113
3114 *total_current_ua = max(current_ua, val.intval);
3115 return 0;
3116 }
3117
3118 switch (typec_source_rd) {
3119 case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
3120 switch (apsd_result->bit) {
3121 case CDP_CHARGER_BIT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303122 current_ua = CDP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003123 break;
3124 case DCP_CHARGER_BIT:
3125 case OCP_CHARGER_BIT:
3126 case FLOAT_CHARGER_BIT:
3127 current_ua = chg->default_icl_ua;
3128 break;
3129 default:
3130 current_ua = 0;
3131 break;
3132 }
3133 break;
3134 case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303135 current_ua = TYPEC_MEDIUM_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003136 break;
3137 case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303138 current_ua = TYPEC_HIGH_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003139 break;
3140 case POWER_SUPPLY_TYPEC_NON_COMPLIANT:
3141 case POWER_SUPPLY_TYPEC_NONE:
3142 default:
3143 current_ua = 0;
3144 break;
3145 }
3146
3147 *total_current_ua = max(current_ua, val.intval);
3148 return 0;
3149}
3150
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003151/************************
Nicholas Troast7dbcad22016-10-05 13:30:18 -07003152 * PARALLEL PSY GETTERS *
3153 ************************/
3154
3155int smblib_get_prop_slave_current_now(struct smb_charger *chg,
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003156 union power_supply_propval *pval)
Nicholas Troast7dbcad22016-10-05 13:30:18 -07003157{
3158 if (IS_ERR_OR_NULL(chg->iio.batt_i_chan))
3159 chg->iio.batt_i_chan = iio_channel_get(chg->dev, "batt_i");
3160
3161 if (IS_ERR(chg->iio.batt_i_chan))
3162 return PTR_ERR(chg->iio.batt_i_chan);
3163
3164 return iio_read_channel_processed(chg->iio.batt_i_chan, &pval->intval);
3165}
3166
Nicholas Troast34db5032016-03-28 12:26:44 -07003167/**********************
3168 * INTERRUPT HANDLERS *
3169 **********************/
3170
3171irqreturn_t smblib_handle_debug(int irq, void *data)
3172{
3173 struct smb_irq_data *irq_data = data;
3174 struct smb_charger *chg = irq_data->parent_data;
3175
3176 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003177 return IRQ_HANDLED;
3178}
3179
Nicholas Troast8995a702016-12-05 10:22:22 -08003180irqreturn_t smblib_handle_otg_overcurrent(int irq, void *data)
3181{
3182 struct smb_irq_data *irq_data = data;
3183 struct smb_charger *chg = irq_data->parent_data;
3184 int rc;
3185 u8 stat;
3186
3187 rc = smblib_read(chg, OTG_BASE + INT_RT_STS_OFFSET, &stat);
3188 if (rc < 0) {
3189 dev_err(chg->dev, "Couldn't read OTG_INT_RT_STS rc=%d\n", rc);
3190 return IRQ_HANDLED;
3191 }
3192
Ashay Jaiswal7c241382017-03-06 15:26:38 +05303193 if (chg->wa_flags & OTG_WA) {
3194 if (stat & OTG_OC_DIS_SW_STS_RT_STS_BIT)
3195 smblib_err(chg, "OTG disabled by hw\n");
3196
3197 /* not handling software based hiccups for PM660 */
3198 return IRQ_HANDLED;
3199 }
3200
Nicholas Troastb11015f2017-01-17 17:56:45 -08003201 if (stat & OTG_OVERCURRENT_RT_STS_BIT)
3202 schedule_work(&chg->otg_oc_work);
Nicholas Troast8995a702016-12-05 10:22:22 -08003203
Nicholas Troast8995a702016-12-05 10:22:22 -08003204 return IRQ_HANDLED;
3205}
3206
Harry Yang6fe72ab2016-06-14 16:21:39 -07003207irqreturn_t smblib_handle_chg_state_change(int irq, void *data)
3208{
3209 struct smb_irq_data *irq_data = data;
3210 struct smb_charger *chg = irq_data->parent_data;
Nicholas Troast8cb77552016-09-23 11:50:18 -07003211 u8 stat;
Harry Yang1d1034c2016-06-15 12:09:42 -07003212 int rc;
Harry Yang6fe72ab2016-06-14 16:21:39 -07003213
3214 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3215
Nicholas Troast8cb77552016-09-23 11:50:18 -07003216 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
Harry Yang1d1034c2016-06-15 12:09:42 -07003217 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003218 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003219 rc);
Harry Yang1d1034c2016-06-15 12:09:42 -07003220 return IRQ_HANDLED;
3221 }
3222
Nicholas Troast8cb77552016-09-23 11:50:18 -07003223 stat = stat & BATTERY_CHARGER_STATUS_MASK;
Nicholas Troast8cb77552016-09-23 11:50:18 -07003224 power_supply_changed(chg->batt_psy);
Harry Yang6fe72ab2016-06-14 16:21:39 -07003225 return IRQ_HANDLED;
3226}
3227
Abhijeet Dharmapurikar2644cd62016-07-20 16:54:55 -07003228irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data)
3229{
3230 struct smb_irq_data *irq_data = data;
3231 struct smb_charger *chg = irq_data->parent_data;
Anirudh Ghayal941acaa2017-07-19 16:04:44 +05303232 int rc;
3233
3234 rc = smblib_recover_from_soft_jeita(chg);
3235 if (rc < 0) {
3236 smblib_err(chg, "Couldn't recover chg from soft jeita rc=%d\n",
3237 rc);
3238 return IRQ_HANDLED;
3239 }
Abhijeet Dharmapurikar2644cd62016-07-20 16:54:55 -07003240
3241 rerun_election(chg->fcc_votable);
3242 power_supply_changed(chg->batt_psy);
3243 return IRQ_HANDLED;
3244}
3245
Nicholas Troast34db5032016-03-28 12:26:44 -07003246irqreturn_t smblib_handle_batt_psy_changed(int irq, void *data)
3247{
3248 struct smb_irq_data *irq_data = data;
3249 struct smb_charger *chg = irq_data->parent_data;
3250
Nicholas Troast47ae4612016-08-03 09:49:36 -07003251 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003252 power_supply_changed(chg->batt_psy);
3253 return IRQ_HANDLED;
3254}
3255
3256irqreturn_t smblib_handle_usb_psy_changed(int irq, void *data)
3257{
3258 struct smb_irq_data *irq_data = data;
3259 struct smb_charger *chg = irq_data->parent_data;
3260
Nicholas Troast47ae4612016-08-03 09:49:36 -07003261 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003262 power_supply_changed(chg->usb_psy);
3263 return IRQ_HANDLED;
3264}
3265
Subbaraman Narayanamurthy09327482017-02-06 16:33:12 -08003266irqreturn_t smblib_handle_usbin_uv(int irq, void *data)
3267{
3268 struct smb_irq_data *irq_data = data;
3269 struct smb_charger *chg = irq_data->parent_data;
3270 struct storm_watch *wdata;
3271
3272 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3273 if (!chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data)
3274 return IRQ_HANDLED;
3275
3276 wdata = &chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data->storm_data;
3277 reset_storm_count(wdata);
3278 return IRQ_HANDLED;
3279}
3280
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003281static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising)
3282{
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003283 if (vbus_rising) {
3284 /* use the typec flag even though its not typec */
3285 chg->typec_present = 1;
3286 } else {
3287 chg->typec_present = 0;
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003288 smblib_update_usb_type(chg);
3289 extcon_set_cable_state_(chg->extcon, EXTCON_USB, false);
3290 smblib_uusb_removal(chg);
3291 }
3292}
3293
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003294void smblib_usb_plugin_hard_reset_locked(struct smb_charger *chg)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003295{
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003296 int rc;
3297 u8 stat;
3298 bool vbus_rising;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303299 struct smb_irq_data *data;
3300 struct storm_watch *wdata;
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003301
3302 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
3303 if (rc < 0) {
3304 smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
3305 return;
3306 }
3307
3308 vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
3309
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303310 if (vbus_rising) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003311 smblib_cc2_sink_removal_exit(chg);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303312 } else {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003313 smblib_cc2_sink_removal_enter(chg);
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303314 if (chg->wa_flags & BOOST_BACK_WA) {
3315 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
3316 if (data) {
3317 wdata = &data->storm_data;
3318 update_storm_count(wdata,
3319 WEAK_CHG_STORM_COUNT);
3320 vote(chg->usb_icl_votable, BOOST_BACK_VOTER,
3321 false, 0);
3322 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
3323 false, 0);
3324 }
3325 }
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303326 }
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003327
3328 power_supply_changed(chg->usb_psy);
3329 smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
3330 vbus_rising ? "attached" : "detached");
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003331}
3332
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303333#define PL_DELAY_MS 30000
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003334void smblib_usb_plugin_locked(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07003335{
Nicholas Troast34db5032016-03-28 12:26:44 -07003336 int rc;
3337 u8 stat;
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003338 bool vbus_rising;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303339 struct smb_irq_data *data;
3340 struct storm_watch *wdata;
Nicholas Troast34db5032016-03-28 12:26:44 -07003341
Harry Yangcdad2bf2016-10-04 17:03:56 -07003342 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
3343 if (rc < 0) {
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003344 smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
3345 return;
Harry Yangcdad2bf2016-10-04 17:03:56 -07003346 }
3347
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003348 vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003349 smblib_set_opt_freq_buck(chg, vbus_rising ? chg->chg_freq.freq_5V :
3350 chg->chg_freq.freq_removal);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003351
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003352 if (vbus_rising) {
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05303353 rc = smblib_request_dpdm(chg, true);
3354 if (rc < 0)
3355 smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303356
3357 /* Schedule work to enable parallel charger */
3358 vote(chg->awake_votable, PL_DELAY_VOTER, true, 0);
3359 schedule_delayed_work(&chg->pl_enable_work,
3360 msecs_to_jiffies(PL_DELAY_MS));
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07003361 } else {
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303362 if (chg->wa_flags & BOOST_BACK_WA) {
3363 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
3364 if (data) {
3365 wdata = &data->storm_data;
3366 update_storm_count(wdata,
3367 WEAK_CHG_STORM_COUNT);
3368 vote(chg->usb_icl_votable, BOOST_BACK_VOTER,
3369 false, 0);
3370 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
3371 false, 0);
3372 }
3373 }
Nicholas Troastabedaf72016-09-16 11:07:45 -07003374
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05303375 rc = smblib_request_dpdm(chg, false);
3376 if (rc < 0)
3377 smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07003378 }
3379
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003380 if (chg->micro_usb_mode)
3381 smblib_micro_usb_plugin(chg, vbus_rising);
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003382
Nicholas Troast62d86622016-09-22 11:41:33 -07003383 power_supply_changed(chg->usb_psy);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003384 smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
3385 vbus_rising ? "attached" : "detached");
3386}
3387
3388irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
3389{
3390 struct smb_irq_data *irq_data = data;
3391 struct smb_charger *chg = irq_data->parent_data;
3392
3393 mutex_lock(&chg->lock);
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003394 if (chg->pd_hard_reset)
3395 smblib_usb_plugin_hard_reset_locked(chg);
3396 else
3397 smblib_usb_plugin_locked(chg);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003398 mutex_unlock(&chg->lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07003399 return IRQ_HANDLED;
3400}
3401
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -07003402#define USB_WEAK_INPUT_UA 1400000
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303403#define ICL_CHANGE_DELAY_MS 1000
Harry Yang6fe72ab2016-06-14 16:21:39 -07003404irqreturn_t smblib_handle_icl_change(int irq, void *data)
3405{
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303406 u8 stat;
3407 int rc, settled_ua, delay = ICL_CHANGE_DELAY_MS;
Harry Yang6fe72ab2016-06-14 16:21:39 -07003408 struct smb_irq_data *irq_data = data;
3409 struct smb_charger *chg = irq_data->parent_data;
3410
Nicholas Troastbb9e1a32017-02-09 10:57:28 -08003411 if (chg->mode == PARALLEL_MASTER) {
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303412 rc = smblib_read(chg, AICL_STATUS_REG, &stat);
3413 if (rc < 0) {
3414 smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n",
3415 rc);
3416 return IRQ_HANDLED;
3417 }
3418
3419 rc = smblib_get_charge_param(chg, &chg->param.icl_stat,
3420 &settled_ua);
3421 if (rc < 0) {
3422 smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
3423 return IRQ_HANDLED;
3424 }
3425
3426 /* If AICL settled then schedule work now */
3427 if ((settled_ua == get_effective_result(chg->usb_icl_votable))
3428 || (stat & AICL_DONE_BIT))
3429 delay = 0;
3430
Ashay Jaiswalac854862017-03-06 23:58:55 +05303431 cancel_delayed_work_sync(&chg->icl_change_work);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303432 schedule_delayed_work(&chg->icl_change_work,
3433 msecs_to_jiffies(delay));
Nicholas Troastbb9e1a32017-02-09 10:57:28 -08003434 }
Harry Yang1d1034c2016-06-15 12:09:42 -07003435
Harry Yang6fe72ab2016-06-14 16:21:39 -07003436 return IRQ_HANDLED;
3437}
3438
Nicholas Troast34db5032016-03-28 12:26:44 -07003439static void smblib_handle_slow_plugin_timeout(struct smb_charger *chg,
3440 bool rising)
3441{
3442 smblib_dbg(chg, PR_INTERRUPT, "IRQ: slow-plugin-timeout %s\n",
3443 rising ? "rising" : "falling");
3444}
3445
3446static void smblib_handle_sdp_enumeration_done(struct smb_charger *chg,
3447 bool rising)
3448{
3449 smblib_dbg(chg, PR_INTERRUPT, "IRQ: sdp-enumeration-done %s\n",
3450 rising ? "rising" : "falling");
3451}
3452
Harry Yangcdad2bf2016-10-04 17:03:56 -07003453#define QC3_PULSES_FOR_6V 5
3454#define QC3_PULSES_FOR_9V 20
3455#define QC3_PULSES_FOR_12V 35
3456static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg)
3457{
3458 int rc;
3459 u8 stat;
3460 int pulses;
3461
Fenglin Wuef4730e2017-01-11 18:16:25 +08003462 power_supply_changed(chg->usb_main_psy);
Fenglin Wu80826e02017-04-25 21:45:08 +08003463 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP) {
Harry Yangcdad2bf2016-10-04 17:03:56 -07003464 rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat);
3465 if (rc < 0) {
3466 smblib_err(chg,
3467 "Couldn't read QC_CHANGE_STATUS rc=%d\n", rc);
3468 return;
3469 }
3470
3471 switch (stat & QC_2P0_STATUS_MASK) {
3472 case QC_5V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303473 smblib_set_opt_freq_buck(chg,
3474 chg->chg_freq.freq_5V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003475 break;
3476 case QC_9V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303477 smblib_set_opt_freq_buck(chg,
3478 chg->chg_freq.freq_9V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003479 break;
3480 case QC_12V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303481 smblib_set_opt_freq_buck(chg,
3482 chg->chg_freq.freq_12V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003483 break;
3484 default:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303485 smblib_set_opt_freq_buck(chg,
3486 chg->chg_freq.freq_removal);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003487 break;
3488 }
3489 }
3490
Fenglin Wu80826e02017-04-25 21:45:08 +08003491 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP_3) {
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +05303492 rc = smblib_get_pulse_cnt(chg, &pulses);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003493 if (rc < 0) {
3494 smblib_err(chg,
3495 "Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
3496 return;
3497 }
Harry Yangcdad2bf2016-10-04 17:03:56 -07003498
3499 if (pulses < QC3_PULSES_FOR_6V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303500 smblib_set_opt_freq_buck(chg,
3501 chg->chg_freq.freq_5V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003502 else if (pulses < QC3_PULSES_FOR_9V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303503 smblib_set_opt_freq_buck(chg,
3504 chg->chg_freq.freq_6V_8V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003505 else if (pulses < QC3_PULSES_FOR_12V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303506 smblib_set_opt_freq_buck(chg,
3507 chg->chg_freq.freq_9V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003508 else
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303509 smblib_set_opt_freq_buck(chg,
3510 chg->chg_freq.freq_12V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003511 }
3512}
3513
Nicholas Troast34db5032016-03-28 12:26:44 -07003514/* triggers when HVDCP 3.0 authentication has finished */
3515static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
3516 bool rising)
3517{
3518 const struct apsd_result *apsd_result;
Harry Yangcdad2bf2016-10-04 17:03:56 -07003519 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07003520
3521 if (!rising)
3522 return;
3523
Ashay Jaiswal67ec7072017-02-16 14:14:58 +05303524 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
3525 /*
3526 * Disable AUTH_IRQ_EN_CFG_BIT to receive adapter voltage
3527 * change interrupt.
3528 */
3529 rc = smblib_masked_write(chg,
3530 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
3531 AUTH_IRQ_EN_CFG_BIT, 0);
3532 if (rc < 0)
3533 smblib_err(chg,
3534 "Couldn't enable QC auth setting rc=%d\n", rc);
3535 }
Harry Yangcdad2bf2016-10-04 17:03:56 -07003536
Harry Yangaba1f5f2016-09-28 10:47:29 -07003537 if (chg->mode == PARALLEL_MASTER)
3538 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0);
3539
Ashay Jaiswalac854862017-03-06 23:58:55 +05303540 /* the APSD done handler will set the USB supply type */
3541 apsd_result = smblib_get_apsd_result(chg);
3542 if (get_effective_result(chg->hvdcp_hw_inov_dis_votable)) {
3543 if (apsd_result->pst == POWER_SUPPLY_TYPE_USB_HVDCP) {
3544 /* force HVDCP2 to 9V if INOV is disabled */
3545 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG,
3546 FORCE_9V_BIT, FORCE_9V_BIT);
3547 if (rc < 0)
3548 smblib_err(chg,
3549 "Couldn't force 9V HVDCP rc=%d\n", rc);
3550 }
3551 }
3552
Nicholas Troast34db5032016-03-28 12:26:44 -07003553 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n",
3554 apsd_result->name);
3555}
3556
Harry Yang1369b7a2016-09-27 15:59:50 -07003557static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
3558 bool rising, bool qc_charger)
3559{
Ashay Jaiswal7b6eb962017-04-26 14:34:29 +05303560 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05303561
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003562 /* Hold off PD only until hvdcp 2.0 detection timeout */
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003563 if (rising) {
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003564 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003565 false, 0);
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -08003566
Harry Yang4bf7d962017-03-13 16:51:43 -07003567 /* enable HDC and ICL irq for QC2/3 charger */
3568 if (qc_charger)
3569 vote(chg->usb_irq_enable_votable, QC_VOTER, true, 0);
3570
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -08003571 /*
3572 * HVDCP detection timeout done
3573 * If adapter is not QC2.0/QC3.0 - it is a plain old DCP.
3574 */
3575 if (!qc_charger && (apsd_result->bit & DCP_CHARGER_BIT))
3576 /* enforce DCP ICL if specified */
3577 vote(chg->usb_icl_votable, DCP_VOTER,
3578 chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua);
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003579 }
Harry Yang1369b7a2016-09-27 15:59:50 -07003580
3581 smblib_dbg(chg, PR_INTERRUPT, "IRQ: smblib_handle_hvdcp_check_timeout %s\n",
3582 rising ? "rising" : "falling");
3583}
3584
Nicholas Troast34db5032016-03-28 12:26:44 -07003585/* triggers when HVDCP is detected */
3586static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg,
3587 bool rising)
3588{
3589 if (!rising)
3590 return;
3591
3592 /* the APSD done handler will set the USB supply type */
3593 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
3594 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-detect-done %s\n",
3595 rising ? "rising" : "falling");
3596}
3597
Nicholas Troastf9e44992017-03-14 09:06:56 -07003598static void smblib_force_legacy_icl(struct smb_charger *chg, int pst)
3599{
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303600 int typec_mode;
3601 int rp_ua;
3602
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003603 /* while PD is active it should have complete ICL control */
3604 if (chg->pd_active)
3605 return;
3606
Nicholas Troastf9e44992017-03-14 09:06:56 -07003607 switch (pst) {
3608 case POWER_SUPPLY_TYPE_USB:
3609 /*
3610 * USB_PSY will vote to increase the current to 500/900mA once
3611 * enumeration is done. Ensure that USB_PSY has at least voted
3612 * for 100mA before releasing the LEGACY_UNKNOWN vote
3613 */
3614 if (!is_client_vote_enabled(chg->usb_icl_votable,
3615 USB_PSY_VOTER))
3616 vote(chg->usb_icl_votable, USB_PSY_VOTER, true, 100000);
3617 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
3618 break;
3619 case POWER_SUPPLY_TYPE_USB_CDP:
3620 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1500000);
3621 break;
3622 case POWER_SUPPLY_TYPE_USB_DCP:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303623 typec_mode = smblib_get_prop_typec_mode(chg);
3624 rp_ua = get_rp_based_dcp_current(chg, typec_mode);
3625 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua);
Nicholas Troastf9e44992017-03-14 09:06:56 -07003626 break;
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05303627 case POWER_SUPPLY_TYPE_USB_FLOAT:
3628 /*
3629 * limit ICL to 100mA, the USB driver will enumerate to check
3630 * if this is a SDP and appropriately set the current
3631 */
3632 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
3633 break;
Nicholas Troastf9e44992017-03-14 09:06:56 -07003634 case POWER_SUPPLY_TYPE_USB_HVDCP:
3635 case POWER_SUPPLY_TYPE_USB_HVDCP_3:
3636 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 3000000);
3637 break;
3638 default:
3639 smblib_err(chg, "Unknown APSD %d; forcing 500mA\n", pst);
3640 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 500000);
3641 break;
3642 }
3643}
3644
Nicholas Troast34db5032016-03-28 12:26:44 -07003645#define HVDCP_DET_MS 2500
3646static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
3647{
Nicholas Troast34db5032016-03-28 12:26:44 -07003648 const struct apsd_result *apsd_result;
3649
3650 if (!rising)
3651 return;
3652
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07003653 apsd_result = smblib_update_usb_type(chg);
Nicholas Troastf9e44992017-03-14 09:06:56 -07003654
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003655 if (!chg->typec_legacy_valid)
Nicholas Troastf9e44992017-03-14 09:06:56 -07003656 smblib_force_legacy_icl(chg, apsd_result->pst);
3657
Nicholas Troast34db5032016-03-28 12:26:44 -07003658 switch (apsd_result->bit) {
3659 case SDP_CHARGER_BIT:
3660 case CDP_CHARGER_BIT:
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05303661 if (chg->micro_usb_mode)
3662 extcon_set_cable_state_(chg->extcon, EXTCON_USB,
3663 true);
Abhijeet Dharmapurikarbb9505f2017-03-22 18:31:28 -07003664 /* if not DCP then no hvdcp timeout happens. Enable pd here */
3665 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3666 false, 0);
3667 break;
Nicholas Troast34db5032016-03-28 12:26:44 -07003668 case OCP_CHARGER_BIT:
3669 case FLOAT_CHARGER_BIT:
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303670 /* if not DCP then no hvdcp timeout happens, Enable pd here. */
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003671 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3672 false, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07003673 break;
3674 case DCP_CHARGER_BIT:
Harry Yang1369b7a2016-09-27 15:59:50 -07003675 if (chg->wa_flags & QC_CHARGER_DETECTION_WA_BIT)
3676 schedule_delayed_work(&chg->hvdcp_detect_work,
3677 msecs_to_jiffies(HVDCP_DET_MS));
Nicholas Troast34db5032016-03-28 12:26:44 -07003678 break;
3679 default:
3680 break;
3681 }
3682
Nicholas Troast34db5032016-03-28 12:26:44 -07003683 smblib_dbg(chg, PR_INTERRUPT, "IRQ: apsd-done rising; %s detected\n",
3684 apsd_result->name);
3685}
3686
3687irqreturn_t smblib_handle_usb_source_change(int irq, void *data)
3688{
3689 struct smb_irq_data *irq_data = data;
3690 struct smb_charger *chg = irq_data->parent_data;
3691 int rc = 0;
3692 u8 stat;
3693
3694 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
3695 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003696 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07003697 return IRQ_HANDLED;
3698 }
3699 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
3700
Ashay Jaiswal8507aa52017-04-14 09:42:32 +05303701 if (chg->micro_usb_mode && (stat & APSD_DTC_STATUS_DONE_BIT)
3702 && !chg->uusb_apsd_rerun_done) {
3703 /*
3704 * Force re-run APSD to handle slow insertion related
3705 * charger-mis-detection.
3706 */
3707 chg->uusb_apsd_rerun_done = true;
3708 smblib_rerun_apsd(chg);
3709 return IRQ_HANDLED;
3710 }
3711
Nicholas Troast34db5032016-03-28 12:26:44 -07003712 smblib_handle_apsd_done(chg,
3713 (bool)(stat & APSD_DTC_STATUS_DONE_BIT));
3714
3715 smblib_handle_hvdcp_detect_done(chg,
3716 (bool)(stat & QC_CHARGER_BIT));
3717
Harry Yang1369b7a2016-09-27 15:59:50 -07003718 smblib_handle_hvdcp_check_timeout(chg,
3719 (bool)(stat & HVDCP_CHECK_TIMEOUT_BIT),
3720 (bool)(stat & QC_CHARGER_BIT));
3721
Nicholas Troast34db5032016-03-28 12:26:44 -07003722 smblib_handle_hvdcp_3p0_auth_done(chg,
3723 (bool)(stat & QC_AUTH_DONE_STATUS_BIT));
3724
Nicholas Troast34db5032016-03-28 12:26:44 -07003725 smblib_handle_sdp_enumeration_done(chg,
3726 (bool)(stat & ENUMERATION_DONE_BIT));
3727
3728 smblib_handle_slow_plugin_timeout(chg,
3729 (bool)(stat & SLOW_PLUGIN_TIMEOUT_BIT));
3730
Harry Yangcdad2bf2016-10-04 17:03:56 -07003731 smblib_hvdcp_adaptive_voltage_change(chg);
3732
Nicholas Troast34db5032016-03-28 12:26:44 -07003733 power_supply_changed(chg->usb_psy);
3734
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08003735 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
3736 if (rc < 0) {
3737 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
3738 return IRQ_HANDLED;
3739 }
3740 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
3741
Nicholas Troast34db5032016-03-28 12:26:44 -07003742 return IRQ_HANDLED;
3743}
3744
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003745static void typec_sink_insertion(struct smb_charger *chg)
3746{
3747 /* when a sink is inserted we should not wait on hvdcp timeout to
3748 * enable pd
3749 */
3750 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3751 false, 0);
3752}
Nicholas Troast34db5032016-03-28 12:26:44 -07003753
Harry Yangd89ff1f2016-12-05 14:59:11 -08003754static void typec_sink_removal(struct smb_charger *chg)
3755{
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303756 smblib_set_charge_param(chg, &chg->param.freq_boost,
3757 chg->chg_freq.freq_above_otg_threshold);
Harry Yangd89ff1f2016-12-05 14:59:11 -08003758 chg->boost_current_ua = 0;
3759}
3760
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003761static void smblib_handle_typec_removal(struct smb_charger *chg)
3762{
Nicholas Troastfe74c592017-03-14 09:20:55 -07003763 int rc;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303764 struct smb_irq_data *data;
3765 struct storm_watch *wdata;
Nicholas Troastfe74c592017-03-14 09:20:55 -07003766
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003767 chg->cc2_detach_wa_active = false;
3768
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05303769 rc = smblib_request_dpdm(chg, false);
3770 if (rc < 0)
3771 smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303772
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303773 if (chg->wa_flags & BOOST_BACK_WA) {
3774 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
3775 if (data) {
3776 wdata = &data->storm_data;
3777 update_storm_count(wdata, WEAK_CHG_STORM_COUNT);
3778 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
3779 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
3780 false, 0);
3781 }
3782 }
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303783
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003784 /* reset APSD voters */
3785 vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, false, 0);
3786 vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303787
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003788 cancel_delayed_work_sync(&chg->pl_enable_work);
3789 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
3790
3791 /* reset input current limit voters */
3792 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
3793 vote(chg->usb_icl_votable, PD_VOTER, false, 0);
3794 vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
3795 vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
3796 vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
Ashay Jaiswalae23a042017-05-18 15:28:31 +05303797 vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
Abhijeet Dharmapurikar66d2c442017-07-12 11:55:36 -07003798 vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003799
3800 /* reset hvdcp voters */
3801 vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, true, 0);
3802 vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER, true, 0);
3803
3804 /* reset power delivery voters */
3805 vote(chg->pd_allowed_votable, PD_VOTER, false, 0);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003806 vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0);
3807 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER, true, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003808
3809 /* reset usb irq voters */
Harry Yang4bf7d962017-03-13 16:51:43 -07003810 vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
3811 vote(chg->usb_irq_enable_votable, QC_VOTER, false, 0);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003812
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003813 /* reset parallel voters */
3814 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
Harry Yanga796cf72017-07-19 19:26:45 -07003815 vote(chg->pl_disable_votable, FCC_CHANGE_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003816 vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
3817 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
3818 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
Harry Yang1d1034c2016-06-15 12:09:42 -07003819
Nicholas Troast8995a702016-12-05 10:22:22 -08003820 chg->vconn_attempts = 0;
3821 chg->otg_attempts = 0;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05303822 chg->pulse_cnt = 0;
3823 chg->usb_icl_delta_ua = 0;
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003824 chg->voltage_min_uv = MICRO_5V;
3825 chg->voltage_max_uv = MICRO_5V;
3826 chg->pd_active = 0;
3827 chg->pd_hard_reset = 0;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003828 chg->typec_legacy_valid = false;
Harry Yang3b113a52016-12-08 12:37:40 -08003829
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05303830 /* write back the default FLOAT charger configuration */
3831 rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
3832 (u8)FLOAT_OPTIONS_MASK, chg->float_cfg);
3833 if (rc < 0)
3834 smblib_err(chg, "Couldn't write float charger options rc=%d\n",
3835 rc);
3836
Abhijeet Dharmapurikar676bd792017-05-31 16:21:57 -07003837 /* reset back to 120mS tCC debounce */
3838 rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT, 0);
3839 if (rc < 0)
3840 smblib_err(chg, "Couldn't set 120mS tCC debounce rc=%d\n", rc);
3841
Nicholas Troastfe74c592017-03-14 09:20:55 -07003842 /* enable APSD CC trigger for next insertion */
3843 rc = smblib_masked_write(chg, TYPE_C_CFG_REG,
3844 APSD_START_ON_CC_BIT, APSD_START_ON_CC_BIT);
3845 if (rc < 0)
3846 smblib_err(chg, "Couldn't enable APSD_START_ON_CC rc=%d\n", rc);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08003847
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003848 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
3849 /* re-enable AUTH_IRQ_EN_CFG_BIT */
3850 rc = smblib_masked_write(chg,
3851 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
3852 AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
3853 if (rc < 0)
3854 smblib_err(chg,
3855 "Couldn't enable QC auth setting rc=%d\n", rc);
3856 }
3857
3858 /* reconfigure allowed voltage for HVDCP */
3859 rc = smblib_set_adapter_allowance(chg,
3860 USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
3861 if (rc < 0)
3862 smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
3863 rc);
3864
3865 /* enable DRP */
3866 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
3867 TYPEC_POWER_ROLE_CMD_MASK, 0);
3868 if (rc < 0)
3869 smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc);
3870
3871 /* HW controlled CC_OUT */
3872 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
3873 TYPEC_SPARE_CFG_BIT, 0);
3874 if (rc < 0)
3875 smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n", rc);
3876
3877 /* restore crude sensor */
3878 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
3879 if (rc < 0)
3880 smblib_err(chg, "Couldn't restore crude sensor rc=%d\n", rc);
3881
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07003882 mutex_lock(&chg->vconn_oc_lock);
3883 if (!chg->vconn_en)
3884 goto unlock;
3885
3886 smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
3887 VCONN_EN_VALUE_BIT, 0);
3888 chg->vconn_en = false;
3889
3890unlock:
3891 mutex_unlock(&chg->vconn_oc_lock);
3892
Abhijeet Dharmapurikar319d6942017-06-05 17:14:17 -07003893 /* clear exit sink based on cc */
3894 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
3895 EXIT_SNK_BASED_ON_CC_BIT, 0);
3896 if (rc < 0)
3897 smblib_err(chg, "Couldn't clear exit_sink_based_on_cc rc=%d\n",
3898 rc);
3899
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08003900 typec_sink_removal(chg);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003901 smblib_update_usb_type(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07003902}
3903
Nicholas Troaste1932e42017-04-12 12:38:18 -07003904static void smblib_handle_typec_insertion(struct smb_charger *chg)
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003905{
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003906 int rc;
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003907
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003908 vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, false, 0);
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003909
Nicholas Troastfe74c592017-03-14 09:20:55 -07003910 /* disable APSD CC trigger since CC is attached */
3911 rc = smblib_masked_write(chg, TYPE_C_CFG_REG, APSD_START_ON_CC_BIT, 0);
3912 if (rc < 0)
3913 smblib_err(chg, "Couldn't disable APSD_START_ON_CC rc=%d\n",
3914 rc);
3915
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05303916 if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT) {
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003917 typec_sink_insertion(chg);
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05303918 } else {
3919 rc = smblib_request_dpdm(chg, true);
3920 if (rc < 0)
3921 smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
Harry Yangd89ff1f2016-12-05 14:59:11 -08003922 typec_sink_removal(chg);
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05303923 }
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003924}
3925
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303926static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode)
3927{
3928 int rp_ua;
3929 const struct apsd_result *apsd = smblib_get_apsd_result(chg);
3930
3931 if ((apsd->pst != POWER_SUPPLY_TYPE_USB_DCP)
3932 && (apsd->pst != POWER_SUPPLY_TYPE_USB_FLOAT))
3933 return;
3934
3935 /*
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05303936 * if APSD indicates FLOAT and the USB stack had detected SDP,
3937 * do not respond to Rp changes as we do not confirm that its
3938 * a legacy cable
3939 */
3940 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
3941 return;
3942 /*
3943 * We want the ICL vote @ 100mA for a FLOAT charger
3944 * until the detection by the USB stack is complete.
3945 * Ignore the Rp changes unless there is a
3946 * pre-existing valid vote.
3947 */
3948 if (apsd->pst == POWER_SUPPLY_TYPE_USB_FLOAT &&
3949 get_client_vote(chg->usb_icl_votable,
3950 LEGACY_UNKNOWN_VOTER) <= 100000)
3951 return;
3952
3953 /*
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303954 * handle Rp change for DCP/FLOAT/OCP.
3955 * Update the current only if the Rp is different from
3956 * the last Rp value.
3957 */
3958 smblib_dbg(chg, PR_MISC, "CC change old_mode=%d new_mode=%d\n",
3959 chg->typec_mode, typec_mode);
3960
3961 rp_ua = get_rp_based_dcp_current(chg, typec_mode);
3962 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua);
3963}
3964
Nicholas Troaste1932e42017-04-12 12:38:18 -07003965static void smblib_handle_typec_cc_state_change(struct smb_charger *chg)
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003966{
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303967 int typec_mode;
3968
Nicholas Troaste1932e42017-04-12 12:38:18 -07003969 if (chg->pr_swap_in_progress)
3970 return;
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003971
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303972 typec_mode = smblib_get_prop_typec_mode(chg);
3973 if (chg->typec_present && (typec_mode != chg->typec_mode))
3974 smblib_handle_rp_change(chg, typec_mode);
3975
3976 chg->typec_mode = typec_mode;
3977
Nicholas Troaste1932e42017-04-12 12:38:18 -07003978 if (!chg->typec_present && chg->typec_mode != POWER_SUPPLY_TYPEC_NONE) {
3979 chg->typec_present = true;
3980 smblib_dbg(chg, PR_MISC, "TypeC %s insertion\n",
3981 smblib_typec_mode_name[chg->typec_mode]);
3982 smblib_handle_typec_insertion(chg);
3983 } else if (chg->typec_present &&
3984 chg->typec_mode == POWER_SUPPLY_TYPEC_NONE) {
3985 chg->typec_present = false;
3986 smblib_dbg(chg, PR_MISC, "TypeC removal\n");
3987 smblib_handle_typec_removal(chg);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003988 }
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003989
Abhijeet Dharmapurikar66d2c442017-07-12 11:55:36 -07003990 /* suspend usb if sink */
Harry Yangca0664e2017-08-18 11:40:06 -07003991 if ((chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
3992 && chg->typec_present)
Abhijeet Dharmapurikar66d2c442017-07-12 11:55:36 -07003993 vote(chg->usb_icl_votable, OTG_VOTER, true, 0);
3994 else
3995 vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
3996
Nicholas Troaste1932e42017-04-12 12:38:18 -07003997 smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n",
3998 smblib_typec_mode_name[chg->typec_mode]);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003999}
4000
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004001static void smblib_usb_typec_change(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07004002{
Nicholas Troast34db5032016-03-28 12:26:44 -07004003 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07004004
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07004005 rc = smblib_multibyte_read(chg, TYPE_C_STATUS_1_REG,
4006 chg->typec_status, 5);
Nicholas Troast34db5032016-03-28 12:26:44 -07004007 if (rc < 0) {
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07004008 smblib_err(chg, "Couldn't cache USB Type-C status rc=%d\n", rc);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004009 return;
Nicholas Troast34db5032016-03-28 12:26:44 -07004010 }
Nicholas Troast34db5032016-03-28 12:26:44 -07004011
Nicholas Troaste1932e42017-04-12 12:38:18 -07004012 smblib_handle_typec_cc_state_change(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07004013
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07004014 if (chg->typec_status[3] & TYPEC_VBUS_ERROR_STATUS_BIT)
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004015 smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n");
Harry Yangd757c0f2016-09-23 10:52:05 -07004016
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07004017 if (chg->typec_status[3] & TYPEC_VCONN_OVERCURR_STATUS_BIT)
Nicholas Troastb11015f2017-01-17 17:56:45 -08004018 schedule_work(&chg->vconn_oc_work);
Nicholas Troast8995a702016-12-05 10:22:22 -08004019
Nicholas Troastb1486552016-11-10 08:20:11 -08004020 power_supply_changed(chg->usb_psy);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004021}
4022
4023irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
4024{
4025 struct smb_irq_data *irq_data = data;
4026 struct smb_charger *chg = irq_data->parent_data;
4027
4028 if (chg->micro_usb_mode) {
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05304029 cancel_delayed_work_sync(&chg->uusb_otg_work);
4030 vote(chg->awake_votable, OTG_DELAY_VOTER, true, 0);
4031 smblib_dbg(chg, PR_INTERRUPT, "Scheduling OTG work\n");
4032 schedule_delayed_work(&chg->uusb_otg_work,
4033 msecs_to_jiffies(chg->otg_delay_ms));
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004034 return IRQ_HANDLED;
4035 }
4036
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004037 if (chg->cc2_detach_wa_active || chg->typec_en_dis_active) {
4038 smblib_dbg(chg, PR_INTERRUPT, "Ignoring since %s active\n",
4039 chg->cc2_detach_wa_active ?
4040 "cc2_detach_wa" : "typec_en_dis");
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004041 return IRQ_HANDLED;
4042 }
4043
Abhijeet Dharmapurikar049b2552017-07-12 11:27:51 -07004044 if (chg->pr_swap_in_progress) {
4045 smblib_dbg(chg, PR_INTERRUPT,
4046 "Ignoring since pr_swap_in_progress\n");
4047 return IRQ_HANDLED;
4048 }
4049
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004050 mutex_lock(&chg->lock);
4051 smblib_usb_typec_change(chg);
4052 mutex_unlock(&chg->lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07004053 return IRQ_HANDLED;
4054}
4055
Abhijeet Dharmapurikar23916642016-10-03 10:38:50 -07004056irqreturn_t smblib_handle_dc_plugin(int irq, void *data)
4057{
4058 struct smb_irq_data *irq_data = data;
4059 struct smb_charger *chg = irq_data->parent_data;
4060
4061 power_supply_changed(chg->dc_psy);
4062 return IRQ_HANDLED;
4063}
4064
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004065irqreturn_t smblib_handle_high_duty_cycle(int irq, void *data)
4066{
4067 struct smb_irq_data *irq_data = data;
4068 struct smb_charger *chg = irq_data->parent_data;
4069
4070 chg->is_hdc = true;
4071 schedule_delayed_work(&chg->clear_hdc_work, msecs_to_jiffies(60));
4072
4073 return IRQ_HANDLED;
4074}
4075
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05304076static void smblib_bb_removal_work(struct work_struct *work)
4077{
4078 struct smb_charger *chg = container_of(work, struct smb_charger,
4079 bb_removal_work.work);
4080
4081 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
4082 vote(chg->awake_votable, BOOST_BACK_VOTER, false, 0);
4083}
4084
4085#define BOOST_BACK_UNVOTE_DELAY_MS 750
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304086#define BOOST_BACK_STORM_COUNT 3
4087#define WEAK_CHG_STORM_COUNT 8
Nicholas Troastabedaf72016-09-16 11:07:45 -07004088irqreturn_t smblib_handle_switcher_power_ok(int irq, void *data)
4089{
4090 struct smb_irq_data *irq_data = data;
4091 struct smb_charger *chg = irq_data->parent_data;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304092 struct storm_watch *wdata = &irq_data->storm_data;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004093 int rc, usb_icl;
Nicholas Troastabedaf72016-09-16 11:07:45 -07004094 u8 stat;
4095
4096 if (!(chg->wa_flags & BOOST_BACK_WA))
4097 return IRQ_HANDLED;
4098
4099 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
4100 if (rc < 0) {
4101 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n", rc);
4102 return IRQ_HANDLED;
4103 }
4104
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004105 /* skip suspending input if its already suspended by some other voter */
4106 usb_icl = get_effective_result(chg->usb_icl_votable);
4107 if ((stat & USE_USBIN_BIT) && usb_icl >= 0 && usb_icl < USBIN_25MA)
Nicholas Troastabedaf72016-09-16 11:07:45 -07004108 return IRQ_HANDLED;
4109
Abhijeet Dharmapurikar2823fe32016-12-05 17:52:11 -08004110 if (stat & USE_DCIN_BIT)
Nicholas Troastabedaf72016-09-16 11:07:45 -07004111 return IRQ_HANDLED;
4112
4113 if (is_storming(&irq_data->storm_data)) {
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304114 /* This could be a weak charger reduce ICL */
4115 if (!is_client_vote_enabled(chg->usb_icl_votable,
4116 WEAK_CHARGER_VOTER)) {
4117 smblib_err(chg,
4118 "Weak charger detected: voting %dmA ICL\n",
4119 *chg->weak_chg_icl_ua / 1000);
4120 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
4121 true, *chg->weak_chg_icl_ua);
4122 /*
4123 * reset storm data and set the storm threshold
4124 * to 3 for reverse boost detection.
4125 */
4126 update_storm_count(wdata, BOOST_BACK_STORM_COUNT);
4127 } else {
4128 smblib_err(chg,
4129 "Reverse boost detected: voting 0mA to suspend input\n");
4130 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, true, 0);
4131 vote(chg->awake_votable, BOOST_BACK_VOTER, true, 0);
4132 /*
4133 * Remove the boost-back vote after a delay, to avoid
4134 * permanently suspending the input if the boost-back
4135 * condition is unintentionally hit.
4136 */
4137 schedule_delayed_work(&chg->bb_removal_work,
4138 msecs_to_jiffies(BOOST_BACK_UNVOTE_DELAY_MS));
4139 }
Nicholas Troastabedaf72016-09-16 11:07:45 -07004140 }
4141
4142 return IRQ_HANDLED;
4143}
4144
Nicholas Troast15dc0c82016-10-18 15:15:21 -07004145irqreturn_t smblib_handle_wdog_bark(int irq, void *data)
4146{
4147 struct smb_irq_data *irq_data = data;
4148 struct smb_charger *chg = irq_data->parent_data;
4149 int rc;
4150
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05304151 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
4152
Nicholas Troast15dc0c82016-10-18 15:15:21 -07004153 rc = smblib_write(chg, BARK_BITE_WDOG_PET_REG, BARK_BITE_WDOG_PET_BIT);
4154 if (rc < 0)
4155 smblib_err(chg, "Couldn't pet the dog rc=%d\n", rc);
4156
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +05304157 if (chg->step_chg_enabled || chg->sw_jeita_enabled)
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05304158 power_supply_changed(chg->batt_psy);
4159
Nicholas Troast15dc0c82016-10-18 15:15:21 -07004160 return IRQ_HANDLED;
4161}
4162
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004163/**************
4164 * Additional USB PSY getters/setters
4165 * that call interrupt functions
4166 ***************/
4167
4168int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg,
4169 union power_supply_propval *val)
4170{
4171 val->intval = chg->pr_swap_in_progress;
4172 return 0;
4173}
4174
4175int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg,
4176 const union power_supply_propval *val)
4177{
Abhijeet Dharmapurikar676bd792017-05-31 16:21:57 -07004178 int rc;
4179
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004180 chg->pr_swap_in_progress = val->intval;
4181 /*
4182 * call the cc changed irq to handle real removals while
4183 * PR_SWAP was in progress
4184 */
4185 smblib_usb_typec_change(chg);
Abhijeet Dharmapurikar676bd792017-05-31 16:21:57 -07004186 rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT,
4187 val->intval ? TCC_DEBOUNCE_20MS_BIT : 0);
4188 if (rc < 0)
4189 smblib_err(chg, "Couldn't set tCC debounce rc=%d\n", rc);
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004190 return 0;
4191}
4192
Nicholas Troast34db5032016-03-28 12:26:44 -07004193/***************
4194 * Work Queues *
4195 ***************/
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05304196static void smblib_uusb_otg_work(struct work_struct *work)
4197{
4198 struct smb_charger *chg = container_of(work, struct smb_charger,
4199 uusb_otg_work.work);
4200 int rc;
4201 u8 stat;
4202 bool otg;
4203
4204 rc = smblib_read(chg, TYPE_C_STATUS_3_REG, &stat);
4205 if (rc < 0) {
4206 smblib_err(chg, "Couldn't read TYPE_C_STATUS_3 rc=%d\n", rc);
4207 goto out;
4208 }
4209
4210 otg = !!(stat & (U_USB_GND_NOVBUS_BIT | U_USB_GND_BIT));
4211 extcon_set_cable_state_(chg->extcon, EXTCON_USB_HOST, otg);
4212 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_3 = 0x%02x OTG=%d\n",
4213 stat, otg);
4214 power_supply_changed(chg->usb_psy);
4215
4216out:
4217 vote(chg->awake_votable, OTG_DELAY_VOTER, false, 0);
4218}
4219
Nicholas Troast34db5032016-03-28 12:26:44 -07004220
4221static void smblib_hvdcp_detect_work(struct work_struct *work)
4222{
4223 struct smb_charger *chg = container_of(work, struct smb_charger,
4224 hvdcp_detect_work.work);
Nicholas Troast34db5032016-03-28 12:26:44 -07004225
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07004226 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
4227 false, 0);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004228 power_supply_changed(chg->usb_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07004229}
4230
Harry Yangfe913842016-08-10 12:27:28 -07004231static void bms_update_work(struct work_struct *work)
Harry Yang5e1a5222016-07-26 15:16:04 -07004232{
4233 struct smb_charger *chg = container_of(work, struct smb_charger,
4234 bms_update_work);
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05304235
4236 smblib_suspend_on_debug_battery(chg);
4237
4238 if (chg->batt_psy)
4239 power_supply_changed(chg->batt_psy);
Harry Yang5e1a5222016-07-26 15:16:04 -07004240}
4241
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004242static void clear_hdc_work(struct work_struct *work)
4243{
4244 struct smb_charger *chg = container_of(work, struct smb_charger,
4245 clear_hdc_work.work);
4246
4247 chg->is_hdc = 0;
4248}
4249
Harry Yang755a34b2016-11-01 01:18:51 -07004250static void rdstd_cc2_detach_work(struct work_struct *work)
4251{
4252 int rc;
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004253 u8 stat4, stat5;
Harry Yang755a34b2016-11-01 01:18:51 -07004254 struct smb_charger *chg = container_of(work, struct smb_charger,
4255 rdstd_cc2_detach_work);
4256
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004257 if (!chg->cc2_detach_wa_active)
4258 return;
4259
Harry Yang755a34b2016-11-01 01:18:51 -07004260 /*
4261 * WA steps -
4262 * 1. Enable both UFP and DFP, wait for 10ms.
4263 * 2. Disable DFP, wait for 30ms.
4264 * 3. Removal detected if both TYPEC_DEBOUNCE_DONE_STATUS
4265 * and TIMER_STAGE bits are gone, otherwise repeat all by
4266 * work rescheduling.
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004267 * Note, work will be cancelled when USB_PLUGIN rises.
Harry Yang755a34b2016-11-01 01:18:51 -07004268 */
4269
4270 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4271 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT,
4272 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT);
4273 if (rc < 0) {
4274 smblib_err(chg, "Couldn't write TYPE_C_CTRL_REG rc=%d\n", rc);
4275 return;
4276 }
4277
4278 usleep_range(10000, 11000);
4279
4280 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4281 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT,
4282 UFP_EN_CMD_BIT);
4283 if (rc < 0) {
4284 smblib_err(chg, "Couldn't write TYPE_C_CTRL_REG rc=%d\n", rc);
4285 return;
4286 }
4287
4288 usleep_range(30000, 31000);
4289
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004290 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
Harry Yang755a34b2016-11-01 01:18:51 -07004291 if (rc < 0) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004292 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
Harry Yang755a34b2016-11-01 01:18:51 -07004293 return;
4294 }
Harry Yang755a34b2016-11-01 01:18:51 -07004295
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004296 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
Harry Yang755a34b2016-11-01 01:18:51 -07004297 if (rc < 0) {
4298 smblib_err(chg,
4299 "Couldn't read TYPE_C_STATUS_5_REG rc=%d\n", rc);
4300 return;
4301 }
Harry Yang755a34b2016-11-01 01:18:51 -07004302
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004303 if ((stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT)
4304 || (stat5 & TIMER_STAGE_2_BIT)) {
4305 smblib_dbg(chg, PR_MISC, "rerunning DD=%d TS2BIT=%d\n",
4306 (int)(stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT),
4307 (int)(stat5 & TIMER_STAGE_2_BIT));
4308 goto rerun;
4309 }
4310
4311 smblib_dbg(chg, PR_MISC, "Bingo CC2 Removal detected\n");
4312 chg->cc2_detach_wa_active = false;
4313 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4314 EXIT_SNK_BASED_ON_CC_BIT, 0);
Harry Yang755a34b2016-11-01 01:18:51 -07004315 smblib_reg_block_restore(chg, cc2_detach_settings);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004316 mutex_lock(&chg->lock);
4317 smblib_usb_typec_change(chg);
4318 mutex_unlock(&chg->lock);
Harry Yang755a34b2016-11-01 01:18:51 -07004319 return;
4320
4321rerun:
4322 schedule_work(&chg->rdstd_cc2_detach_work);
4323}
4324
Nicholas Troastb11015f2017-01-17 17:56:45 -08004325static void smblib_otg_oc_exit(struct smb_charger *chg, bool success)
4326{
4327 int rc;
4328
4329 chg->otg_attempts = 0;
4330 if (!success) {
4331 smblib_err(chg, "OTG soft start failed\n");
4332 chg->otg_en = false;
4333 }
4334
4335 smblib_dbg(chg, PR_OTG, "enabling VBUS < 1V check\n");
4336 rc = smblib_masked_write(chg, OTG_CFG_REG,
4337 QUICKSTART_OTG_FASTROLESWAP_BIT, 0);
4338 if (rc < 0)
4339 smblib_err(chg, "Couldn't enable VBUS < 1V check rc=%d\n", rc);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004340}
4341
4342#define MAX_OC_FALLING_TRIES 10
4343static void smblib_otg_oc_work(struct work_struct *work)
4344{
4345 struct smb_charger *chg = container_of(work, struct smb_charger,
4346 otg_oc_work);
4347 int rc, i;
4348 u8 stat;
4349
4350 if (!chg->vbus_vreg || !chg->vbus_vreg->rdev)
4351 return;
4352
4353 smblib_err(chg, "over-current detected on VBUS\n");
4354 mutex_lock(&chg->otg_oc_lock);
4355 if (!chg->otg_en)
4356 goto unlock;
4357
4358 smblib_dbg(chg, PR_OTG, "disabling VBUS < 1V check\n");
4359 smblib_masked_write(chg, OTG_CFG_REG,
4360 QUICKSTART_OTG_FASTROLESWAP_BIT,
4361 QUICKSTART_OTG_FASTROLESWAP_BIT);
4362
4363 /*
4364 * If 500ms has passed and another over-current interrupt has not
4365 * triggered then it is likely that the software based soft start was
4366 * successful and the VBUS < 1V restriction should be re-enabled.
4367 */
4368 schedule_delayed_work(&chg->otg_ss_done_work, msecs_to_jiffies(500));
4369
4370 rc = _smblib_vbus_regulator_disable(chg->vbus_vreg->rdev);
4371 if (rc < 0) {
4372 smblib_err(chg, "Couldn't disable VBUS rc=%d\n", rc);
4373 goto unlock;
4374 }
4375
4376 if (++chg->otg_attempts > OTG_MAX_ATTEMPTS) {
4377 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4378 smblib_err(chg, "OTG failed to enable after %d attempts\n",
4379 chg->otg_attempts - 1);
4380 smblib_otg_oc_exit(chg, false);
4381 goto unlock;
4382 }
4383
4384 /*
4385 * The real time status should go low within 10ms. Poll every 1-2ms to
4386 * minimize the delay when re-enabling OTG.
4387 */
4388 for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) {
4389 usleep_range(1000, 2000);
4390 rc = smblib_read(chg, OTG_BASE + INT_RT_STS_OFFSET, &stat);
4391 if (rc >= 0 && !(stat & OTG_OVERCURRENT_RT_STS_BIT))
4392 break;
4393 }
4394
4395 if (i >= MAX_OC_FALLING_TRIES) {
4396 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4397 smblib_err(chg, "OTG OC did not fall after %dms\n",
4398 2 * MAX_OC_FALLING_TRIES);
4399 smblib_otg_oc_exit(chg, false);
4400 goto unlock;
4401 }
4402
4403 smblib_dbg(chg, PR_OTG, "OTG OC fell after %dms\n", 2 * i + 1);
4404 rc = _smblib_vbus_regulator_enable(chg->vbus_vreg->rdev);
4405 if (rc < 0) {
4406 smblib_err(chg, "Couldn't enable VBUS rc=%d\n", rc);
4407 goto unlock;
4408 }
4409
4410unlock:
4411 mutex_unlock(&chg->otg_oc_lock);
4412}
4413
4414static void smblib_vconn_oc_work(struct work_struct *work)
4415{
4416 struct smb_charger *chg = container_of(work, struct smb_charger,
4417 vconn_oc_work);
4418 int rc, i;
4419 u8 stat;
4420
Ashay Jaiswal15edce42017-03-31 23:29:58 +05304421 if (chg->micro_usb_mode)
4422 return;
4423
Nicholas Troastb11015f2017-01-17 17:56:45 -08004424 smblib_err(chg, "over-current detected on VCONN\n");
4425 if (!chg->vconn_vreg || !chg->vconn_vreg->rdev)
4426 return;
4427
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07004428 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004429 rc = _smblib_vconn_regulator_disable(chg->vconn_vreg->rdev);
4430 if (rc < 0) {
4431 smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc);
4432 goto unlock;
4433 }
4434
4435 if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
4436 smblib_err(chg, "VCONN failed to enable after %d attempts\n",
4437 chg->otg_attempts - 1);
4438 chg->vconn_en = false;
4439 chg->vconn_attempts = 0;
4440 goto unlock;
4441 }
4442
4443 /*
4444 * The real time status should go low within 10ms. Poll every 1-2ms to
4445 * minimize the delay when re-enabling OTG.
4446 */
4447 for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) {
4448 usleep_range(1000, 2000);
4449 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
4450 if (rc >= 0 && !(stat & TYPEC_VCONN_OVERCURR_STATUS_BIT))
4451 break;
4452 }
4453
4454 if (i >= MAX_OC_FALLING_TRIES) {
4455 smblib_err(chg, "VCONN OC did not fall after %dms\n",
4456 2 * MAX_OC_FALLING_TRIES);
4457 chg->vconn_en = false;
4458 chg->vconn_attempts = 0;
4459 goto unlock;
4460 }
4461
4462 smblib_dbg(chg, PR_OTG, "VCONN OC fell after %dms\n", 2 * i + 1);
4463 if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
4464 smblib_err(chg, "VCONN failed to enable after %d attempts\n",
4465 chg->vconn_attempts - 1);
4466 chg->vconn_en = false;
4467 goto unlock;
4468 }
4469
4470 rc = _smblib_vconn_regulator_enable(chg->vconn_vreg->rdev);
4471 if (rc < 0) {
4472 smblib_err(chg, "Couldn't enable VCONN rc=%d\n", rc);
4473 goto unlock;
4474 }
4475
4476unlock:
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07004477 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004478}
4479
4480static void smblib_otg_ss_done_work(struct work_struct *work)
4481{
4482 struct smb_charger *chg = container_of(work, struct smb_charger,
4483 otg_ss_done_work.work);
4484 int rc;
4485 bool success = false;
4486 u8 stat;
4487
4488 mutex_lock(&chg->otg_oc_lock);
4489 rc = smblib_read(chg, OTG_STATUS_REG, &stat);
4490 if (rc < 0)
4491 smblib_err(chg, "Couldn't read OTG status rc=%d\n", rc);
4492 else if (stat & BOOST_SOFTSTART_DONE_BIT)
4493 success = true;
4494
4495 smblib_otg_oc_exit(chg, success);
4496 mutex_unlock(&chg->otg_oc_lock);
4497}
4498
Ashay Jaiswal4d825782017-02-18 10:11:34 +05304499static void smblib_icl_change_work(struct work_struct *work)
4500{
4501 struct smb_charger *chg = container_of(work, struct smb_charger,
4502 icl_change_work.work);
4503 int rc, settled_ua;
4504
4505 rc = smblib_get_charge_param(chg, &chg->param.icl_stat, &settled_ua);
4506 if (rc < 0) {
4507 smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
4508 return;
4509 }
4510
4511 power_supply_changed(chg->usb_main_psy);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05304512
4513 smblib_dbg(chg, PR_INTERRUPT, "icl_settled=%d\n", settled_ua);
4514}
4515
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304516static void smblib_pl_enable_work(struct work_struct *work)
4517{
4518 struct smb_charger *chg = container_of(work, struct smb_charger,
4519 pl_enable_work.work);
4520
4521 smblib_dbg(chg, PR_PARALLEL, "timer expired, enabling parallel\n");
4522 vote(chg->pl_disable_votable, PL_DELAY_VOTER, false, 0);
4523 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
4524}
4525
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004526static void smblib_legacy_detection_work(struct work_struct *work)
4527{
4528 struct smb_charger *chg = container_of(work, struct smb_charger,
4529 legacy_detection_work);
4530 int rc;
4531 u8 stat;
4532 bool legacy, rp_high;
4533
4534 mutex_lock(&chg->lock);
4535 chg->typec_en_dis_active = 1;
4536 smblib_dbg(chg, PR_MISC, "running legacy unknown workaround\n");
4537 rc = smblib_masked_write(chg,
4538 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4539 TYPEC_DISABLE_CMD_BIT,
4540 TYPEC_DISABLE_CMD_BIT);
4541 if (rc < 0)
4542 smblib_err(chg, "Couldn't disable type-c rc=%d\n", rc);
4543
4544 /* wait for the adapter to turn off VBUS */
4545 msleep(500);
4546
4547 rc = smblib_masked_write(chg,
4548 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4549 TYPEC_DISABLE_CMD_BIT, 0);
4550 if (rc < 0)
4551 smblib_err(chg, "Couldn't enable type-c rc=%d\n", rc);
4552
4553 /* wait for type-c detection to complete */
4554 msleep(100);
4555
4556 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat);
4557 if (rc < 0) {
4558 smblib_err(chg, "Couldn't read typec stat5 rc = %d\n", rc);
4559 goto unlock;
4560 }
4561
4562 chg->typec_legacy_valid = true;
4563 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
4564 legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT;
Nicholas Troaste1932e42017-04-12 12:38:18 -07004565 rp_high = chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004566 if (!legacy || !rp_high)
4567 vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
4568 false, 0);
4569
4570unlock:
4571 chg->typec_en_dis_active = 0;
Nicholas Troast6439e172017-06-02 14:45:39 -07004572 smblib_usb_typec_change(chg);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004573 mutex_unlock(&chg->lock);
4574}
4575
Harry Yangba874ce2016-08-19 14:17:01 -07004576static int smblib_create_votables(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07004577{
4578 int rc = 0;
4579
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304580 chg->fcc_votable = find_votable("FCC");
Harry Yang0c35ff62017-04-06 00:02:30 -07004581 if (chg->fcc_votable == NULL) {
4582 rc = -EINVAL;
4583 smblib_err(chg, "Couldn't find FCC votable rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304584 return rc;
4585 }
4586
4587 chg->fv_votable = find_votable("FV");
Harry Yang0c35ff62017-04-06 00:02:30 -07004588 if (chg->fv_votable == NULL) {
4589 rc = -EINVAL;
4590 smblib_err(chg, "Couldn't find FV votable rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304591 return rc;
4592 }
4593
Ashay Jaiswalae1586d2017-03-22 23:18:51 +05304594 chg->usb_icl_votable = find_votable("USB_ICL");
4595 if (!chg->usb_icl_votable) {
Harry Yang0c35ff62017-04-06 00:02:30 -07004596 rc = -EINVAL;
4597 smblib_err(chg, "Couldn't find USB_ICL votable rc=%d\n", rc);
Ashay Jaiswalae1586d2017-03-22 23:18:51 +05304598 return rc;
4599 }
4600
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304601 chg->pl_disable_votable = find_votable("PL_DISABLE");
Harry Yang0c35ff62017-04-06 00:02:30 -07004602 if (chg->pl_disable_votable == NULL) {
4603 rc = -EINVAL;
4604 smblib_err(chg, "Couldn't find votable PL_DISABLE rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304605 return rc;
4606 }
Abhijeet Dharmapurikar38ef1422017-05-18 15:37:56 -07004607
4608 chg->pl_enable_votable_indirect = find_votable("PL_ENABLE_INDIRECT");
4609 if (chg->pl_enable_votable_indirect == NULL) {
4610 rc = -EINVAL;
4611 smblib_err(chg,
4612 "Couldn't find votable PL_ENABLE_INDIRECT rc=%d\n",
4613 rc);
4614 return rc;
4615 }
4616
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304617 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304618
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004619 chg->dc_suspend_votable = create_votable("DC_SUSPEND", VOTE_SET_ANY,
4620 smblib_dc_suspend_vote_callback,
4621 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07004622 if (IS_ERR(chg->dc_suspend_votable)) {
4623 rc = PTR_ERR(chg->dc_suspend_votable);
4624 return rc;
4625 }
4626
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004627 chg->dc_icl_votable = create_votable("DC_ICL", VOTE_MIN,
4628 smblib_dc_icl_vote_callback,
4629 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07004630 if (IS_ERR(chg->dc_icl_votable)) {
4631 rc = PTR_ERR(chg->dc_icl_votable);
4632 return rc;
4633 }
4634
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07004635 chg->pd_disallowed_votable_indirect
4636 = create_votable("PD_DISALLOWED_INDIRECT", VOTE_SET_ANY,
4637 smblib_pd_disallowed_votable_indirect_callback, chg);
4638 if (IS_ERR(chg->pd_disallowed_votable_indirect)) {
4639 rc = PTR_ERR(chg->pd_disallowed_votable_indirect);
4640 return rc;
4641 }
4642
4643 chg->pd_allowed_votable = create_votable("PD_ALLOWED",
4644 VOTE_SET_ANY, NULL, NULL);
Nicholas Troast34db5032016-03-28 12:26:44 -07004645 if (IS_ERR(chg->pd_allowed_votable)) {
4646 rc = PTR_ERR(chg->pd_allowed_votable);
4647 return rc;
4648 }
4649
Harry Yang223c6282016-06-14 15:48:36 -07004650 chg->awake_votable = create_votable("AWAKE", VOTE_SET_ANY,
4651 smblib_awake_vote_callback,
4652 chg);
4653 if (IS_ERR(chg->awake_votable)) {
4654 rc = PTR_ERR(chg->awake_votable);
4655 return rc;
4656 }
4657
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07004658 chg->chg_disable_votable = create_votable("CHG_DISABLE", VOTE_SET_ANY,
4659 smblib_chg_disable_vote_callback,
4660 chg);
4661 if (IS_ERR(chg->chg_disable_votable)) {
4662 rc = PTR_ERR(chg->chg_disable_votable);
4663 return rc;
4664 }
4665
Harry Yangaba1f5f2016-09-28 10:47:29 -07004666
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05304667 chg->hvdcp_disable_votable_indirect = create_votable(
4668 "HVDCP_DISABLE_INDIRECT",
4669 VOTE_SET_ANY,
4670 smblib_hvdcp_disable_indirect_vote_callback,
4671 chg);
4672 if (IS_ERR(chg->hvdcp_disable_votable_indirect)) {
4673 rc = PTR_ERR(chg->hvdcp_disable_votable_indirect);
4674 return rc;
4675 }
4676
4677 chg->hvdcp_enable_votable = create_votable("HVDCP_ENABLE",
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07004678 VOTE_SET_ANY,
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05304679 smblib_hvdcp_enable_vote_callback,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07004680 chg);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05304681 if (IS_ERR(chg->hvdcp_enable_votable)) {
4682 rc = PTR_ERR(chg->hvdcp_enable_votable);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07004683 return rc;
4684 }
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07004685
4686 chg->apsd_disable_votable = create_votable("APSD_DISABLE",
4687 VOTE_SET_ANY,
4688 smblib_apsd_disable_vote_callback,
4689 chg);
4690 if (IS_ERR(chg->apsd_disable_votable)) {
4691 rc = PTR_ERR(chg->apsd_disable_votable);
4692 return rc;
4693 }
4694
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05304695 chg->hvdcp_hw_inov_dis_votable = create_votable("HVDCP_HW_INOV_DIS",
4696 VOTE_SET_ANY,
4697 smblib_hvdcp_hw_inov_dis_vote_callback,
4698 chg);
4699 if (IS_ERR(chg->hvdcp_hw_inov_dis_votable)) {
4700 rc = PTR_ERR(chg->hvdcp_hw_inov_dis_votable);
4701 return rc;
4702 }
4703
Harry Yang4bf7d962017-03-13 16:51:43 -07004704 chg->usb_irq_enable_votable = create_votable("USB_IRQ_DISABLE",
4705 VOTE_SET_ANY,
4706 smblib_usb_irq_enable_vote_callback,
4707 chg);
4708 if (IS_ERR(chg->usb_irq_enable_votable)) {
4709 rc = PTR_ERR(chg->usb_irq_enable_votable);
4710 return rc;
4711 }
4712
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004713 chg->typec_irq_disable_votable = create_votable("TYPEC_IRQ_DISABLE",
4714 VOTE_SET_ANY,
4715 smblib_typec_irq_disable_vote_callback,
4716 chg);
4717 if (IS_ERR(chg->typec_irq_disable_votable)) {
4718 rc = PTR_ERR(chg->typec_irq_disable_votable);
4719 return rc;
4720 }
4721
Nicholas Troast320839e2016-06-03 10:18:00 -07004722 return rc;
4723}
4724
Harry Yangba874ce2016-08-19 14:17:01 -07004725static void smblib_destroy_votables(struct smb_charger *chg)
4726{
Harry Yangba874ce2016-08-19 14:17:01 -07004727 if (chg->dc_suspend_votable)
4728 destroy_votable(chg->dc_suspend_votable);
Harry Yangba874ce2016-08-19 14:17:01 -07004729 if (chg->usb_icl_votable)
4730 destroy_votable(chg->usb_icl_votable);
4731 if (chg->dc_icl_votable)
4732 destroy_votable(chg->dc_icl_votable);
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07004733 if (chg->pd_disallowed_votable_indirect)
4734 destroy_votable(chg->pd_disallowed_votable_indirect);
Harry Yangba874ce2016-08-19 14:17:01 -07004735 if (chg->pd_allowed_votable)
4736 destroy_votable(chg->pd_allowed_votable);
4737 if (chg->awake_votable)
4738 destroy_votable(chg->awake_votable);
Harry Yangaba1f5f2016-09-28 10:47:29 -07004739 if (chg->chg_disable_votable)
4740 destroy_votable(chg->chg_disable_votable);
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07004741 if (chg->apsd_disable_votable)
4742 destroy_votable(chg->apsd_disable_votable);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05304743 if (chg->hvdcp_hw_inov_dis_votable)
4744 destroy_votable(chg->hvdcp_hw_inov_dis_votable);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004745 if (chg->typec_irq_disable_votable)
4746 destroy_votable(chg->typec_irq_disable_votable);
Harry Yangba874ce2016-08-19 14:17:01 -07004747}
4748
4749static void smblib_iio_deinit(struct smb_charger *chg)
4750{
4751 if (!IS_ERR_OR_NULL(chg->iio.temp_chan))
4752 iio_channel_release(chg->iio.temp_chan);
4753 if (!IS_ERR_OR_NULL(chg->iio.temp_max_chan))
4754 iio_channel_release(chg->iio.temp_max_chan);
4755 if (!IS_ERR_OR_NULL(chg->iio.usbin_i_chan))
4756 iio_channel_release(chg->iio.usbin_i_chan);
4757 if (!IS_ERR_OR_NULL(chg->iio.usbin_v_chan))
4758 iio_channel_release(chg->iio.usbin_v_chan);
Nicholas Troast7dbcad22016-10-05 13:30:18 -07004759 if (!IS_ERR_OR_NULL(chg->iio.batt_i_chan))
4760 iio_channel_release(chg->iio.batt_i_chan);
Harry Yangba874ce2016-08-19 14:17:01 -07004761}
4762
Nicholas Troast320839e2016-06-03 10:18:00 -07004763int smblib_init(struct smb_charger *chg)
4764{
4765 int rc = 0;
4766
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004767 mutex_init(&chg->lock);
Nicholas Troast320839e2016-06-03 10:18:00 -07004768 mutex_init(&chg->write_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004769 mutex_init(&chg->otg_oc_lock);
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07004770 mutex_init(&chg->vconn_oc_lock);
Harry Yangfe913842016-08-10 12:27:28 -07004771 INIT_WORK(&chg->bms_update_work, bms_update_work);
Harry Yang755a34b2016-11-01 01:18:51 -07004772 INIT_WORK(&chg->rdstd_cc2_detach_work, rdstd_cc2_detach_work);
Nicholas Troast320839e2016-06-03 10:18:00 -07004773 INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004774 INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004775 INIT_WORK(&chg->otg_oc_work, smblib_otg_oc_work);
4776 INIT_WORK(&chg->vconn_oc_work, smblib_vconn_oc_work);
4777 INIT_DELAYED_WORK(&chg->otg_ss_done_work, smblib_otg_ss_done_work);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05304778 INIT_DELAYED_WORK(&chg->icl_change_work, smblib_icl_change_work);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304779 INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004780 INIT_WORK(&chg->legacy_detection_work, smblib_legacy_detection_work);
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05304781 INIT_DELAYED_WORK(&chg->uusb_otg_work, smblib_uusb_otg_work);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05304782 INIT_DELAYED_WORK(&chg->bb_removal_work, smblib_bb_removal_work);
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07004783 chg->fake_capacity = -EINVAL;
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07004784 chg->fake_input_current_limited = -EINVAL;
Harry Yang589dd422017-07-28 18:41:42 -07004785 chg->fake_batt_status = -EINVAL;
Nicholas Troast320839e2016-06-03 10:18:00 -07004786
4787 switch (chg->mode) {
4788 case PARALLEL_MASTER:
Harry Yang0c35ff62017-04-06 00:02:30 -07004789 rc = qcom_batt_init();
4790 if (rc < 0) {
4791 smblib_err(chg, "Couldn't init qcom_batt_init rc=%d\n",
4792 rc);
4793 return rc;
4794 }
4795
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +05304796 rc = qcom_step_chg_init(chg->step_chg_enabled,
4797 chg->sw_jeita_enabled);
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05304798 if (rc < 0) {
4799 smblib_err(chg, "Couldn't init qcom_step_chg_init rc=%d\n",
4800 rc);
4801 return rc;
4802 }
4803
Nicholas Troast320839e2016-06-03 10:18:00 -07004804 rc = smblib_create_votables(chg);
4805 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004806 smblib_err(chg, "Couldn't create votables rc=%d\n",
Nicholas Troast320839e2016-06-03 10:18:00 -07004807 rc);
Harry Yang58a9e7a2016-06-23 14:54:43 -07004808 return rc;
Nicholas Troast320839e2016-06-03 10:18:00 -07004809 }
Harry Yang58a9e7a2016-06-23 14:54:43 -07004810
Harry Yang5e1a5222016-07-26 15:16:04 -07004811 rc = smblib_register_notifier(chg);
4812 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004813 smblib_err(chg,
Harry Yang5e1a5222016-07-26 15:16:04 -07004814 "Couldn't register notifier rc=%d\n", rc);
4815 return rc;
Harry Yang58a9e7a2016-06-23 14:54:43 -07004816 }
4817
Harry Yang995b7422016-08-29 16:06:50 -07004818 chg->bms_psy = power_supply_get_by_name("bms");
Ashay Jaiswal8afedfc2017-02-03 11:18:22 +05304819 chg->pl.psy = power_supply_get_by_name("parallel");
Nicholas Troast320839e2016-06-03 10:18:00 -07004820 break;
4821 case PARALLEL_SLAVE:
4822 break;
4823 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004824 smblib_err(chg, "Unsupported mode %d\n", chg->mode);
Nicholas Troast320839e2016-06-03 10:18:00 -07004825 return -EINVAL;
4826 }
4827
4828 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07004829}
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004830
4831int smblib_deinit(struct smb_charger *chg)
4832{
Harry Yangba874ce2016-08-19 14:17:01 -07004833 switch (chg->mode) {
4834 case PARALLEL_MASTER:
Harry Yang0c35ff62017-04-06 00:02:30 -07004835 cancel_work_sync(&chg->bms_update_work);
4836 cancel_work_sync(&chg->rdstd_cc2_detach_work);
4837 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
Harry Yang0c35ff62017-04-06 00:02:30 -07004838 cancel_delayed_work_sync(&chg->clear_hdc_work);
4839 cancel_work_sync(&chg->otg_oc_work);
4840 cancel_work_sync(&chg->vconn_oc_work);
4841 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4842 cancel_delayed_work_sync(&chg->icl_change_work);
4843 cancel_delayed_work_sync(&chg->pl_enable_work);
4844 cancel_work_sync(&chg->legacy_detection_work);
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05304845 cancel_delayed_work_sync(&chg->uusb_otg_work);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05304846 cancel_delayed_work_sync(&chg->bb_removal_work);
Harry Yangba874ce2016-08-19 14:17:01 -07004847 power_supply_unreg_notifier(&chg->nb);
4848 smblib_destroy_votables(chg);
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05304849 qcom_step_chg_deinit();
Harry Yang0c35ff62017-04-06 00:02:30 -07004850 qcom_batt_deinit();
Harry Yangba874ce2016-08-19 14:17:01 -07004851 break;
4852 case PARALLEL_SLAVE:
4853 break;
4854 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004855 smblib_err(chg, "Unsupported mode %d\n", chg->mode);
Harry Yangba874ce2016-08-19 14:17:01 -07004856 return -EINVAL;
4857 }
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004858
Harry Yangba874ce2016-08-19 14:17:01 -07004859 smblib_iio_deinit(chg);
Harry Yang5e1a5222016-07-26 15:16:04 -07004860
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004861 return 0;
4862}