blob: 1a4c524e42c45935e5d9498011b14d652cf9f89b [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 */
Harry Yang379484a2017-08-29 10:26:14 -0700894 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
Harry Yang379484a2017-08-29 10:26:14 -07001020 suspend = (icl_ua <= USBIN_25MA);
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001021 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 if (!chg->iio.usbin_v_chan ||
2254 PTR_ERR(chg->iio.usbin_v_chan) == -EPROBE_DEFER)
2255 chg->iio.usbin_v_chan = iio_channel_get(chg->dev, "usbin_v");
2256
2257 if (IS_ERR(chg->iio.usbin_v_chan))
2258 return PTR_ERR(chg->iio.usbin_v_chan);
2259
2260 return iio_read_channel_processed(chg->iio.usbin_v_chan, &val->intval);
Nicholas Troast34db5032016-03-28 12:26:44 -07002261}
2262
Harry Yangba874ce2016-08-19 14:17:01 -07002263int smblib_get_prop_usb_current_now(struct smb_charger *chg,
2264 union power_supply_propval *val)
2265{
2266 int rc = 0;
2267
2268 rc = smblib_get_prop_usb_present(chg, val);
2269 if (rc < 0 || !val->intval)
2270 return rc;
2271
2272 if (!chg->iio.usbin_i_chan ||
2273 PTR_ERR(chg->iio.usbin_i_chan) == -EPROBE_DEFER)
2274 chg->iio.usbin_i_chan = iio_channel_get(chg->dev, "usbin_i");
2275
2276 if (IS_ERR(chg->iio.usbin_i_chan))
2277 return PTR_ERR(chg->iio.usbin_i_chan);
2278
2279 return iio_read_channel_processed(chg->iio.usbin_i_chan, &val->intval);
2280}
2281
2282int smblib_get_prop_charger_temp(struct smb_charger *chg,
2283 union power_supply_propval *val)
2284{
2285 int rc;
2286
2287 if (!chg->iio.temp_chan ||
2288 PTR_ERR(chg->iio.temp_chan) == -EPROBE_DEFER)
2289 chg->iio.temp_chan = iio_channel_get(chg->dev, "charger_temp");
2290
2291 if (IS_ERR(chg->iio.temp_chan))
2292 return PTR_ERR(chg->iio.temp_chan);
2293
2294 rc = iio_read_channel_processed(chg->iio.temp_chan, &val->intval);
2295 val->intval /= 100;
2296 return rc;
2297}
2298
2299int smblib_get_prop_charger_temp_max(struct smb_charger *chg,
2300 union power_supply_propval *val)
2301{
2302 int rc;
2303
2304 if (!chg->iio.temp_max_chan ||
2305 PTR_ERR(chg->iio.temp_max_chan) == -EPROBE_DEFER)
2306 chg->iio.temp_max_chan = iio_channel_get(chg->dev,
2307 "charger_temp_max");
2308 if (IS_ERR(chg->iio.temp_max_chan))
2309 return PTR_ERR(chg->iio.temp_max_chan);
2310
2311 rc = iio_read_channel_processed(chg->iio.temp_max_chan, &val->intval);
2312 val->intval /= 100;
2313 return rc;
2314}
2315
Nicholas Troast34db5032016-03-28 12:26:44 -07002316int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
2317 union power_supply_propval *val)
2318{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002319 if (chg->typec_status[3] & CC_ATTACHED_BIT)
2320 val->intval =
2321 (bool)(chg->typec_status[3] & CC_ORIENTATION_BIT) + 1;
Nicholas Troast34db5032016-03-28 12:26:44 -07002322 else
2323 val->intval = 0;
2324
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002325 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002326}
2327
2328static const char * const smblib_typec_mode_name[] = {
2329 [POWER_SUPPLY_TYPEC_NONE] = "NONE",
2330 [POWER_SUPPLY_TYPEC_SOURCE_DEFAULT] = "SOURCE_DEFAULT",
2331 [POWER_SUPPLY_TYPEC_SOURCE_MEDIUM] = "SOURCE_MEDIUM",
2332 [POWER_SUPPLY_TYPEC_SOURCE_HIGH] = "SOURCE_HIGH",
2333 [POWER_SUPPLY_TYPEC_NON_COMPLIANT] = "NON_COMPLIANT",
2334 [POWER_SUPPLY_TYPEC_SINK] = "SINK",
2335 [POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE] = "SINK_POWERED_CABLE",
2336 [POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY] = "SINK_DEBUG_ACCESSORY",
2337 [POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER] = "SINK_AUDIO_ADAPTER",
2338 [POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY] = "POWERED_CABLE_ONLY",
2339};
2340
2341static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
2342{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002343 switch (chg->typec_status[0]) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002344 case UFP_TYPEC_RDSTD_BIT:
2345 return POWER_SUPPLY_TYPEC_SOURCE_DEFAULT;
2346 case UFP_TYPEC_RD1P5_BIT:
2347 return POWER_SUPPLY_TYPEC_SOURCE_MEDIUM;
2348 case UFP_TYPEC_RD3P0_BIT:
2349 return POWER_SUPPLY_TYPEC_SOURCE_HIGH;
2350 default:
2351 break;
2352 }
2353
Nicholas Troaste1932e42017-04-12 12:38:18 -07002354 return POWER_SUPPLY_TYPEC_NONE;
Nicholas Troast34db5032016-03-28 12:26:44 -07002355}
2356
2357static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
2358{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002359 switch (chg->typec_status[1] & DFP_TYPEC_MASK) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002360 case DFP_RA_RA_BIT:
2361 return POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER;
2362 case DFP_RD_RD_BIT:
2363 return POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY;
2364 case DFP_RD_RA_VCONN_BIT:
2365 return POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE;
2366 case DFP_RD_OPEN_BIT:
2367 return POWER_SUPPLY_TYPEC_SINK;
Nicholas Troast34db5032016-03-28 12:26:44 -07002368 default:
2369 break;
2370 }
2371
2372 return POWER_SUPPLY_TYPEC_NONE;
2373}
2374
Nicholas Troaste1932e42017-04-12 12:38:18 -07002375static int smblib_get_prop_typec_mode(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07002376{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002377 if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
Nicholas Troaste1932e42017-04-12 12:38:18 -07002378 return smblib_get_prop_dfp_mode(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07002379 else
Nicholas Troaste1932e42017-04-12 12:38:18 -07002380 return smblib_get_prop_ufp_mode(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07002381}
2382
2383int smblib_get_prop_typec_power_role(struct smb_charger *chg,
2384 union power_supply_propval *val)
2385{
2386 int rc = 0;
2387 u8 ctrl;
2388
2389 rc = smblib_read(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &ctrl);
2390 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002391 smblib_err(chg, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002392 rc);
2393 return rc;
2394 }
2395 smblib_dbg(chg, PR_REGISTER, "TYPE_C_INTRPT_ENB_SOFTWARE_CTRL = 0x%02x\n",
2396 ctrl);
2397
2398 if (ctrl & TYPEC_DISABLE_CMD_BIT) {
2399 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
2400 return rc;
2401 }
2402
2403 switch (ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT)) {
2404 case 0:
2405 val->intval = POWER_SUPPLY_TYPEC_PR_DUAL;
2406 break;
2407 case DFP_EN_CMD_BIT:
2408 val->intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
2409 break;
2410 case UFP_EN_CMD_BIT:
2411 val->intval = POWER_SUPPLY_TYPEC_PR_SINK;
2412 break;
2413 default:
2414 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002415 smblib_err(chg, "unsupported power role 0x%02lx\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002416 ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT));
2417 return -EINVAL;
2418 }
2419
2420 return rc;
2421}
2422
2423int smblib_get_prop_pd_allowed(struct smb_charger *chg,
2424 union power_supply_propval *val)
2425{
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07002426 val->intval = get_effective_result(chg->pd_allowed_votable);
Nicholas Troast34db5032016-03-28 12:26:44 -07002427 return 0;
2428}
2429
Nicholas Troast133a7f52016-06-29 13:48:20 -07002430int smblib_get_prop_input_current_settled(struct smb_charger *chg,
2431 union power_supply_propval *val)
2432{
2433 return smblib_get_charge_param(chg, &chg->param.icl_stat, &val->intval);
2434}
2435
Fenglin Wuef4730e2017-01-11 18:16:25 +08002436#define HVDCP3_STEP_UV 200000
2437int smblib_get_prop_input_voltage_settled(struct smb_charger *chg,
2438 union power_supply_propval *val)
2439{
Fenglin Wuef4730e2017-01-11 18:16:25 +08002440 int rc, pulses;
Fenglin Wuef4730e2017-01-11 18:16:25 +08002441
Nicholas Troast5f314c12017-05-25 11:58:02 -07002442 switch (chg->real_charger_type) {
Fenglin Wuef4730e2017-01-11 18:16:25 +08002443 case POWER_SUPPLY_TYPE_USB_HVDCP_3:
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +05302444 rc = smblib_get_pulse_cnt(chg, &pulses);
Fenglin Wuef4730e2017-01-11 18:16:25 +08002445 if (rc < 0) {
2446 smblib_err(chg,
2447 "Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
2448 return 0;
2449 }
Fenglin Wuef4730e2017-01-11 18:16:25 +08002450 val->intval = MICRO_5V + HVDCP3_STEP_UV * pulses;
2451 break;
Nicholas Troast5f314c12017-05-25 11:58:02 -07002452 case POWER_SUPPLY_TYPE_USB_PD:
2453 val->intval = chg->voltage_min_uv;
2454 break;
Fenglin Wuef4730e2017-01-11 18:16:25 +08002455 default:
2456 val->intval = MICRO_5V;
2457 break;
2458 }
2459
2460 return 0;
2461}
2462
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002463int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg,
2464 union power_supply_propval *val)
2465{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002466 val->intval = chg->pd_hard_reset;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002467 return 0;
2468}
2469
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07002470int smblib_get_pe_start(struct smb_charger *chg,
2471 union power_supply_propval *val)
2472{
2473 /*
2474 * hvdcp timeout voter is the last one to allow pd. Use its vote
2475 * to indicate start of pe engine
2476 */
2477 val->intval
2478 = !get_client_vote_locked(chg->pd_disallowed_votable_indirect,
2479 HVDCP_TIMEOUT_VOTER);
2480 return 0;
2481}
2482
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002483int smblib_get_prop_die_health(struct smb_charger *chg,
Nicholas Troastb021dd92017-01-31 18:43:38 -08002484 union power_supply_propval *val)
2485{
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002486 int rc;
Nicholas Troastb021dd92017-01-31 18:43:38 -08002487 u8 stat;
2488
2489 rc = smblib_read(chg, TEMP_RANGE_STATUS_REG, &stat);
2490 if (rc < 0) {
2491 smblib_err(chg, "Couldn't read TEMP_RANGE_STATUS_REG rc=%d\n",
2492 rc);
2493 return rc;
2494 }
2495
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002496 /* TEMP_RANGE bits are mutually exclusive */
2497 switch (stat & TEMP_RANGE_MASK) {
2498 case TEMP_BELOW_RANGE_BIT:
2499 val->intval = POWER_SUPPLY_HEALTH_COOL;
2500 break;
2501 case TEMP_WITHIN_RANGE_BIT:
2502 val->intval = POWER_SUPPLY_HEALTH_WARM;
2503 break;
2504 case TEMP_ABOVE_RANGE_BIT:
2505 val->intval = POWER_SUPPLY_HEALTH_HOT;
2506 break;
2507 case ALERT_LEVEL_BIT:
2508 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
2509 break;
2510 default:
2511 val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
Nicholas Troastb021dd92017-01-31 18:43:38 -08002512 }
2513
Nicholas Troastb021dd92017-01-31 18:43:38 -08002514 return 0;
2515}
2516
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05302517#define SDP_CURRENT_UA 500000
2518#define CDP_CURRENT_UA 1500000
2519#define DCP_CURRENT_UA 1500000
2520#define HVDCP_CURRENT_UA 3000000
2521#define TYPEC_DEFAULT_CURRENT_UA 900000
2522#define TYPEC_MEDIUM_CURRENT_UA 1500000
2523#define TYPEC_HIGH_CURRENT_UA 3000000
2524static int get_rp_based_dcp_current(struct smb_charger *chg, int typec_mode)
2525{
2526 int rp_ua;
2527
2528 switch (typec_mode) {
2529 case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
2530 rp_ua = TYPEC_HIGH_CURRENT_UA;
2531 break;
2532 case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
2533 case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
2534 /* fall through */
2535 default:
2536 rp_ua = DCP_CURRENT_UA;
2537 }
2538
2539 return rp_ua;
2540}
2541
Nicholas Troast34db5032016-03-28 12:26:44 -07002542/*******************
2543 * USB PSY SETTERS *
2544 * *****************/
2545
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002546int smblib_set_prop_pd_current_max(struct smb_charger *chg,
2547 const union power_supply_propval *val)
2548{
2549 int rc;
2550
2551 if (chg->pd_active)
2552 rc = vote(chg->usb_icl_votable, PD_VOTER, true, val->intval);
2553 else
2554 rc = -EPERM;
2555
2556 return rc;
2557}
2558
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05302559static int smblib_handle_usb_current(struct smb_charger *chg,
2560 int usb_current)
2561{
2562 int rc = 0, rp_ua, typec_mode;
2563
2564 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_FLOAT) {
2565 if (usb_current == -ETIMEDOUT) {
2566 /*
2567 * Valid FLOAT charger, report the current based
2568 * of Rp
2569 */
2570 typec_mode = smblib_get_prop_typec_mode(chg);
2571 rp_ua = get_rp_based_dcp_current(chg, typec_mode);
2572 rc = vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER,
2573 true, rp_ua);
2574 if (rc < 0)
2575 return rc;
2576 } else {
2577 /*
2578 * FLOAT charger detected as SDP by USB driver,
2579 * charge with the requested current and update the
2580 * real_charger_type
2581 */
2582 chg->real_charger_type = POWER_SUPPLY_TYPE_USB;
2583 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
2584 true, usb_current);
2585 if (rc < 0)
2586 return rc;
2587 rc = vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER,
2588 false, 0);
2589 if (rc < 0)
2590 return rc;
2591 }
2592 } else {
2593 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
2594 true, usb_current);
2595 }
2596
2597 return rc;
2598}
2599
Nicholas Troast7f55c922017-07-25 13:18:03 -07002600int smblib_set_prop_sdp_current_max(struct smb_charger *chg,
Nicholas Troast34db5032016-03-28 12:26:44 -07002601 const union power_supply_propval *val)
2602{
Nicholas Troast8d33b7d2017-01-16 11:18:38 -08002603 int rc = 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002604
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002605 if (!chg->pd_active) {
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05302606 rc = smblib_handle_usb_current(chg, val->intval);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002607 } else if (chg->system_suspend_supported) {
2608 if (val->intval <= USBIN_25MA)
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302609 rc = vote(chg->usb_icl_votable,
2610 PD_SUSPEND_SUPPORTED_VOTER, true, val->intval);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002611 else
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302612 rc = vote(chg->usb_icl_votable,
2613 PD_SUSPEND_SUPPORTED_VOTER, false, 0);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002614 }
Nicholas Troast34db5032016-03-28 12:26:44 -07002615 return rc;
2616}
2617
Harry Yangd89ff1f2016-12-05 14:59:11 -08002618int smblib_set_prop_boost_current(struct smb_charger *chg,
2619 const union power_supply_propval *val)
2620{
2621 int rc = 0;
2622
2623 rc = smblib_set_charge_param(chg, &chg->param.freq_boost,
2624 val->intval <= chg->boost_threshold_ua ?
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05302625 chg->chg_freq.freq_below_otg_threshold :
2626 chg->chg_freq.freq_above_otg_threshold);
Harry Yangd89ff1f2016-12-05 14:59:11 -08002627 if (rc < 0) {
2628 dev_err(chg->dev, "Error in setting freq_boost rc=%d\n", rc);
2629 return rc;
2630 }
2631
2632 chg->boost_current_ua = val->intval;
2633 return rc;
2634}
2635
Nicholas Troast34db5032016-03-28 12:26:44 -07002636int smblib_set_prop_typec_power_role(struct smb_charger *chg,
2637 const union power_supply_propval *val)
2638{
2639 int rc = 0;
2640 u8 power_role;
2641
2642 switch (val->intval) {
2643 case POWER_SUPPLY_TYPEC_PR_NONE:
2644 power_role = TYPEC_DISABLE_CMD_BIT;
2645 break;
2646 case POWER_SUPPLY_TYPEC_PR_DUAL:
2647 power_role = 0;
2648 break;
2649 case POWER_SUPPLY_TYPEC_PR_SINK:
2650 power_role = UFP_EN_CMD_BIT;
2651 break;
2652 case POWER_SUPPLY_TYPEC_PR_SOURCE:
2653 power_role = DFP_EN_CMD_BIT;
2654 break;
2655 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002656 smblib_err(chg, "power role %d not supported\n", val->intval);
Nicholas Troast34db5032016-03-28 12:26:44 -07002657 return -EINVAL;
2658 }
2659
Jack Pham54a39bd2017-03-29 18:59:37 -07002660 if (power_role == UFP_EN_CMD_BIT) {
2661 /* disable PBS workaround when forcing sink mode */
2662 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0x0);
2663 if (rc < 0) {
2664 smblib_err(chg, "Couldn't write to TM_IO_DTEST4_SEL rc=%d\n",
2665 rc);
2666 }
2667 } else {
2668 /* restore it back to 0xA5 */
2669 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
2670 if (rc < 0) {
2671 smblib_err(chg, "Couldn't write to TM_IO_DTEST4_SEL rc=%d\n",
2672 rc);
2673 }
2674 }
2675
Nicholas Troast34db5032016-03-28 12:26:44 -07002676 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2677 TYPEC_POWER_ROLE_CMD_MASK, power_role);
2678 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002679 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 -07002680 power_role, rc);
2681 return rc;
2682 }
2683
2684 return rc;
2685}
2686
Nicholas Troast7f55c922017-07-25 13:18:03 -07002687int smblib_set_prop_pd_voltage_min(struct smb_charger *chg,
Nicholas Troast34db5032016-03-28 12:26:44 -07002688 const union power_supply_propval *val)
2689{
2690 int rc, min_uv;
2691
2692 min_uv = min(val->intval, chg->voltage_max_uv);
2693 rc = smblib_set_usb_pd_allowed_voltage(chg, min_uv,
2694 chg->voltage_max_uv);
2695 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002696 smblib_err(chg, "invalid max voltage %duV rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002697 val->intval, rc);
2698 return rc;
2699 }
2700
Harry Yangaba1f5f2016-09-28 10:47:29 -07002701 chg->voltage_min_uv = min_uv;
Nicholas Troast5f314c12017-05-25 11:58:02 -07002702 power_supply_changed(chg->usb_main_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07002703 return rc;
2704}
2705
Nicholas Troast7f55c922017-07-25 13:18:03 -07002706int smblib_set_prop_pd_voltage_max(struct smb_charger *chg,
Nicholas Troast34db5032016-03-28 12:26:44 -07002707 const union power_supply_propval *val)
2708{
2709 int rc, max_uv;
2710
2711 max_uv = max(val->intval, chg->voltage_min_uv);
2712 rc = smblib_set_usb_pd_allowed_voltage(chg, chg->voltage_min_uv,
2713 max_uv);
2714 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002715 smblib_err(chg, "invalid min voltage %duV rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002716 val->intval, rc);
2717 return rc;
2718 }
2719
Harry Yangaba1f5f2016-09-28 10:47:29 -07002720 chg->voltage_max_uv = max_uv;
Nicholas Troast34db5032016-03-28 12:26:44 -07002721 return rc;
2722}
2723
2724int smblib_set_prop_pd_active(struct smb_charger *chg,
2725 const union power_supply_propval *val)
2726{
2727 int rc;
Nicholas Troaste1932e42017-04-12 12:38:18 -07002728 bool orientation, sink_attached, hvdcp;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002729 u8 stat;
Nicholas Troast34db5032016-03-28 12:26:44 -07002730
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002731 if (!get_effective_result(chg->pd_allowed_votable))
Nicholas Troast34db5032016-03-28 12:26:44 -07002732 return -EINVAL;
Nicholas Troast34db5032016-03-28 12:26:44 -07002733
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002734 chg->pd_active = val->intval;
2735 if (chg->pd_active) {
2736 vote(chg->apsd_disable_votable, PD_VOTER, true, 0);
2737 vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
2738 vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
2739
2740 /*
2741 * VCONN_EN_ORIENTATION_BIT controls whether to use CC1 or CC2
2742 * line when TYPEC_SPARE_CFG_BIT (CC pin selection s/w override)
2743 * is set or when VCONN_EN_VALUE_BIT is set.
2744 */
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002745 orientation = chg->typec_status[3] & CC_ORIENTATION_BIT;
Harry Yang88acff42016-09-21 14:56:06 -07002746 rc = smblib_masked_write(chg,
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07002747 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2748 VCONN_EN_ORIENTATION_BIT,
2749 orientation ? 0 : VCONN_EN_ORIENTATION_BIT);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002750 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002751 smblib_err(chg,
Harry Yang88acff42016-09-21 14:56:06 -07002752 "Couldn't enable vconn on CC line rc=%d\n", rc);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002753
2754 /* SW controlled CC_OUT */
2755 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
2756 TYPEC_SPARE_CFG_BIT, TYPEC_SPARE_CFG_BIT);
2757 if (rc < 0)
2758 smblib_err(chg, "Couldn't enable SW cc_out rc=%d\n",
2759 rc);
2760
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302761 /*
2762 * Enforce 500mA for PD until the real vote comes in later.
2763 * It is guaranteed that pd_active is set prior to
2764 * pd_current_max
2765 */
Harry Yangcd995202016-11-07 13:32:52 -08002766 rc = vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002767 if (rc < 0)
Harry Yangcd995202016-11-07 13:32:52 -08002768 smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n",
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002769 rc);
Harry Yangcd995202016-11-07 13:32:52 -08002770
Nicholas Troastf9e44992017-03-14 09:06:56 -07002771 /* since PD was found the cable must be non-legacy */
2772 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
2773
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002774 /* clear USB ICL vote for DCP_VOTER */
Harry Yang631b99e2016-11-17 11:24:25 -08002775 rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002776 if (rc < 0)
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002777 smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n",
2778 rc);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002779
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302780 /* remove USB_PSY_VOTER */
2781 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002782 if (rc < 0)
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302783 smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002784 } else {
Nicholas Troaste1932e42017-04-12 12:38:18 -07002785 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
2786 if (rc < 0) {
2787 smblib_err(chg, "Couldn't read APSD status rc=%d\n",
2788 rc);
2789 return rc;
2790 }
2791
2792 hvdcp = stat & QC_CHARGER_BIT;
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002793 vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
2794 vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
Harry Yang7b429572017-09-12 11:15:04 -07002795 vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002796 vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER,
2797 false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002798
2799 /* HW controlled CC_OUT */
2800 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
2801 TYPEC_SPARE_CFG_BIT, 0);
2802 if (rc < 0)
2803 smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n",
2804 rc);
2805
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002806 /*
2807 * This WA should only run for HVDCP. Non-legacy SDP/CDP could
2808 * draw more, but this WA will remove Rd causing VBUS to drop,
2809 * and data could be interrupted. Non-legacy DCP could also draw
2810 * more, but it may impact compliance.
2811 */
Nicholas Troaste1932e42017-04-12 12:38:18 -07002812 sink_attached = chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT;
2813 if (!chg->typec_legacy_valid && !sink_attached && hvdcp)
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002814 schedule_work(&chg->legacy_detection_work);
Harry Yang88acff42016-09-21 14:56:06 -07002815 }
2816
Harry Yang6607b4a2016-05-17 17:50:09 -07002817 smblib_update_usb_type(chg);
Abhijeet Dharmapurikar76e2af52016-10-06 17:25:01 -07002818 power_supply_changed(chg->usb_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07002819 return rc;
2820}
2821
Fenglin Wuedd70792016-11-22 13:16:19 +08002822int smblib_set_prop_ship_mode(struct smb_charger *chg,
2823 const union power_supply_propval *val)
2824{
2825 int rc;
2826
2827 smblib_dbg(chg, PR_MISC, "Set ship mode: %d!!\n", !!val->intval);
2828
2829 rc = smblib_masked_write(chg, SHIP_MODE_REG, SHIP_MODE_EN_BIT,
2830 !!val->intval ? SHIP_MODE_EN_BIT : 0);
2831 if (rc < 0)
2832 dev_err(chg->dev, "Couldn't %s ship mode, rc=%d\n",
2833 !!val->intval ? "enable" : "disable", rc);
2834
2835 return rc;
2836}
2837
Harry Yang5e2bb712016-10-18 16:47:48 -07002838int smblib_reg_block_update(struct smb_charger *chg,
2839 struct reg_info *entry)
2840{
2841 int rc = 0;
2842
2843 while (entry && entry->reg) {
2844 rc = smblib_read(chg, entry->reg, &entry->bak);
2845 if (rc < 0) {
2846 dev_err(chg->dev, "Error in reading %s rc=%d\n",
2847 entry->desc, rc);
2848 break;
2849 }
2850 entry->bak &= entry->mask;
2851
2852 rc = smblib_masked_write(chg, entry->reg,
2853 entry->mask, entry->val);
2854 if (rc < 0) {
2855 dev_err(chg->dev, "Error in writing %s rc=%d\n",
2856 entry->desc, rc);
2857 break;
2858 }
2859 entry++;
2860 }
2861
2862 return rc;
2863}
2864
2865int smblib_reg_block_restore(struct smb_charger *chg,
2866 struct reg_info *entry)
2867{
2868 int rc = 0;
2869
2870 while (entry && entry->reg) {
2871 rc = smblib_masked_write(chg, entry->reg,
2872 entry->mask, entry->bak);
2873 if (rc < 0) {
2874 dev_err(chg->dev, "Error in writing %s rc=%d\n",
2875 entry->desc, rc);
2876 break;
2877 }
2878 entry++;
2879 }
2880
2881 return rc;
2882}
2883
Harry Yang755a34b2016-11-01 01:18:51 -07002884static struct reg_info cc2_detach_settings[] = {
2885 {
2886 .reg = TYPE_C_CFG_2_REG,
2887 .mask = TYPE_C_UFP_MODE_BIT | EN_TRY_SOURCE_MODE_BIT,
2888 .val = TYPE_C_UFP_MODE_BIT,
2889 .desc = "TYPE_C_CFG_2_REG",
2890 },
2891 {
2892 .reg = TYPE_C_CFG_3_REG,
2893 .mask = EN_TRYSINK_MODE_BIT,
2894 .val = 0,
2895 .desc = "TYPE_C_CFG_3_REG",
2896 },
2897 {
2898 .reg = TAPER_TIMER_SEL_CFG_REG,
2899 .mask = TYPEC_SPARE_CFG_BIT,
2900 .val = TYPEC_SPARE_CFG_BIT,
2901 .desc = "TAPER_TIMER_SEL_CFG_REG",
2902 },
2903 {
2904 .reg = TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2905 .mask = VCONN_EN_ORIENTATION_BIT,
2906 .val = 0,
2907 .desc = "TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG",
2908 },
2909 {
2910 .reg = MISC_CFG_REG,
2911 .mask = TCC_DEBOUNCE_20MS_BIT,
2912 .val = TCC_DEBOUNCE_20MS_BIT,
2913 .desc = "Tccdebounce time"
2914 },
2915 {
2916 },
2917};
2918
2919static int smblib_cc2_sink_removal_enter(struct smb_charger *chg)
2920{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002921 int rc, ccout, ufp_mode;
2922 u8 stat;
Harry Yang755a34b2016-11-01 01:18:51 -07002923
2924 if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002925 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002926
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002927 if (chg->cc2_detach_wa_active)
2928 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002929
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002930 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
Harry Yang755a34b2016-11-01 01:18:51 -07002931 if (rc < 0) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002932 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
Harry Yang755a34b2016-11-01 01:18:51 -07002933 return rc;
2934 }
Nicholas Troaste1932e42017-04-12 12:38:18 -07002935
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002936 ccout = (stat & CC_ATTACHED_BIT) ?
2937 (!!(stat & CC_ORIENTATION_BIT) + 1) : 0;
2938 ufp_mode = (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT) ?
2939 !(stat & UFP_DFP_MODE_STATUS_BIT) : 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002940
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002941 if (ccout != 2)
2942 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002943
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002944 if (!ufp_mode)
2945 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002946
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002947 chg->cc2_detach_wa_active = true;
2948 /* The CC2 removal WA will cause a type-c-change IRQ storm */
2949 smblib_reg_block_update(chg, cc2_detach_settings);
2950 schedule_work(&chg->rdstd_cc2_detach_work);
Harry Yang755a34b2016-11-01 01:18:51 -07002951 return rc;
2952}
2953
2954static int smblib_cc2_sink_removal_exit(struct smb_charger *chg)
2955{
Harry Yang755a34b2016-11-01 01:18:51 -07002956 if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002957 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002958
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002959 if (!chg->cc2_detach_wa_active)
2960 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002961
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002962 chg->cc2_detach_wa_active = false;
2963 cancel_work_sync(&chg->rdstd_cc2_detach_work);
2964 smblib_reg_block_restore(chg, cc2_detach_settings);
2965 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002966}
2967
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002968int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
2969 const union power_supply_propval *val)
2970{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002971 int rc = 0;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002972
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002973 if (chg->pd_hard_reset == val->intval)
2974 return rc;
2975
2976 chg->pd_hard_reset = val->intval;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002977 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002978 EXIT_SNK_BASED_ON_CC_BIT,
2979 (chg->pd_hard_reset) ? EXIT_SNK_BASED_ON_CC_BIT : 0);
2980 if (rc < 0)
2981 smblib_err(chg, "Couldn't set EXIT_SNK_BASED_ON_CC rc=%d\n",
Harry Yang755a34b2016-11-01 01:18:51 -07002982 rc);
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002983
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002984 vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER,
2985 chg->pd_hard_reset, 0);
Harry Yang755a34b2016-11-01 01:18:51 -07002986
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002987 return rc;
2988}
2989
Anirudh Ghayal941acaa2017-07-19 16:04:44 +05302990static int smblib_recover_from_soft_jeita(struct smb_charger *chg)
2991{
2992 u8 stat_1, stat_2;
2993 int rc;
2994
2995 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat_1);
2996 if (rc < 0) {
2997 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
2998 rc);
2999 return rc;
3000 }
3001
3002 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat_2);
3003 if (rc < 0) {
3004 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
3005 rc);
3006 return rc;
3007 }
3008
3009 if ((chg->jeita_status && !(stat_2 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK) &&
3010 ((stat_1 & BATTERY_CHARGER_STATUS_MASK) == TERMINATE_CHARGE))) {
3011 /*
3012 * We are moving from JEITA soft -> Normal and charging
3013 * is terminated
3014 */
3015 rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG, 0);
3016 if (rc < 0) {
3017 smblib_err(chg, "Couldn't disable charging rc=%d\n",
3018 rc);
3019 return rc;
3020 }
3021 rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG,
3022 CHARGING_ENABLE_CMD_BIT);
3023 if (rc < 0) {
3024 smblib_err(chg, "Couldn't enable charging rc=%d\n",
3025 rc);
3026 return rc;
3027 }
3028 }
3029
3030 chg->jeita_status = stat_2 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK;
3031
3032 return 0;
3033}
3034
Nicholas Troast7dbcad22016-10-05 13:30:18 -07003035/************************
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003036 * USB MAIN PSY GETTERS *
3037 ************************/
3038int smblib_get_prop_fcc_delta(struct smb_charger *chg,
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05303039 union power_supply_propval *val)
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003040{
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05303041 int rc, jeita_cc_delta_ua = 0;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003042
3043 rc = smblib_get_jeita_cc_delta(chg, &jeita_cc_delta_ua);
3044 if (rc < 0) {
3045 smblib_err(chg, "Couldn't get jeita cc delta rc=%d\n", rc);
3046 jeita_cc_delta_ua = 0;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003047 }
3048
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05303049 val->intval = jeita_cc_delta_ua;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003050 return 0;
3051}
3052
3053/************************
3054 * USB MAIN PSY SETTERS *
3055 ************************/
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003056int smblib_get_charge_current(struct smb_charger *chg,
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003057 int *total_current_ua)
3058{
Ashay Jaiswal7b6eb962017-04-26 14:34:29 +05303059 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003060 union power_supply_propval val = {0, };
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003061 int rc = 0, typec_source_rd, current_ua;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003062 bool non_compliant;
3063 u8 stat5;
3064
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003065 if (chg->pd_active) {
3066 *total_current_ua =
3067 get_client_vote_locked(chg->usb_icl_votable, PD_VOTER);
3068 return rc;
3069 }
3070
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003071 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
3072 if (rc < 0) {
3073 smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc);
3074 return rc;
3075 }
3076 non_compliant = stat5 & TYPEC_NONCOMP_LEGACY_CABLE_STATUS_BIT;
3077
3078 /* get settled ICL */
3079 rc = smblib_get_prop_input_current_settled(chg, &val);
3080 if (rc < 0) {
3081 smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
3082 return rc;
3083 }
3084
3085 typec_source_rd = smblib_get_prop_ufp_mode(chg);
3086
3087 /* QC 2.0/3.0 adapter */
3088 if (apsd_result->bit & (QC_3P0_BIT | QC_2P0_BIT)) {
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303089 *total_current_ua = HVDCP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003090 return 0;
3091 }
3092
3093 if (non_compliant) {
3094 switch (apsd_result->bit) {
3095 case CDP_CHARGER_BIT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303096 current_ua = CDP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003097 break;
3098 case DCP_CHARGER_BIT:
3099 case OCP_CHARGER_BIT:
3100 case FLOAT_CHARGER_BIT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303101 current_ua = DCP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003102 break;
3103 default:
3104 current_ua = 0;
3105 break;
3106 }
3107
3108 *total_current_ua = max(current_ua, val.intval);
3109 return 0;
3110 }
3111
3112 switch (typec_source_rd) {
3113 case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
3114 switch (apsd_result->bit) {
3115 case CDP_CHARGER_BIT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303116 current_ua = CDP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003117 break;
3118 case DCP_CHARGER_BIT:
3119 case OCP_CHARGER_BIT:
3120 case FLOAT_CHARGER_BIT:
3121 current_ua = chg->default_icl_ua;
3122 break;
3123 default:
3124 current_ua = 0;
3125 break;
3126 }
3127 break;
3128 case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303129 current_ua = TYPEC_MEDIUM_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003130 break;
3131 case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303132 current_ua = TYPEC_HIGH_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003133 break;
3134 case POWER_SUPPLY_TYPEC_NON_COMPLIANT:
3135 case POWER_SUPPLY_TYPEC_NONE:
3136 default:
3137 current_ua = 0;
3138 break;
3139 }
3140
3141 *total_current_ua = max(current_ua, val.intval);
3142 return 0;
3143}
3144
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003145/************************
Nicholas Troast7dbcad22016-10-05 13:30:18 -07003146 * PARALLEL PSY GETTERS *
3147 ************************/
3148
3149int smblib_get_prop_slave_current_now(struct smb_charger *chg,
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003150 union power_supply_propval *pval)
Nicholas Troast7dbcad22016-10-05 13:30:18 -07003151{
3152 if (IS_ERR_OR_NULL(chg->iio.batt_i_chan))
3153 chg->iio.batt_i_chan = iio_channel_get(chg->dev, "batt_i");
3154
3155 if (IS_ERR(chg->iio.batt_i_chan))
3156 return PTR_ERR(chg->iio.batt_i_chan);
3157
3158 return iio_read_channel_processed(chg->iio.batt_i_chan, &pval->intval);
3159}
3160
Nicholas Troast34db5032016-03-28 12:26:44 -07003161/**********************
3162 * INTERRUPT HANDLERS *
3163 **********************/
3164
3165irqreturn_t smblib_handle_debug(int irq, void *data)
3166{
3167 struct smb_irq_data *irq_data = data;
3168 struct smb_charger *chg = irq_data->parent_data;
3169
3170 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003171 return IRQ_HANDLED;
3172}
3173
Nicholas Troast8995a702016-12-05 10:22:22 -08003174irqreturn_t smblib_handle_otg_overcurrent(int irq, void *data)
3175{
3176 struct smb_irq_data *irq_data = data;
3177 struct smb_charger *chg = irq_data->parent_data;
3178 int rc;
3179 u8 stat;
3180
3181 rc = smblib_read(chg, OTG_BASE + INT_RT_STS_OFFSET, &stat);
3182 if (rc < 0) {
3183 dev_err(chg->dev, "Couldn't read OTG_INT_RT_STS rc=%d\n", rc);
3184 return IRQ_HANDLED;
3185 }
3186
Ashay Jaiswal7c241382017-03-06 15:26:38 +05303187 if (chg->wa_flags & OTG_WA) {
3188 if (stat & OTG_OC_DIS_SW_STS_RT_STS_BIT)
3189 smblib_err(chg, "OTG disabled by hw\n");
3190
3191 /* not handling software based hiccups for PM660 */
3192 return IRQ_HANDLED;
3193 }
3194
Nicholas Troastb11015f2017-01-17 17:56:45 -08003195 if (stat & OTG_OVERCURRENT_RT_STS_BIT)
3196 schedule_work(&chg->otg_oc_work);
Nicholas Troast8995a702016-12-05 10:22:22 -08003197
Nicholas Troast8995a702016-12-05 10:22:22 -08003198 return IRQ_HANDLED;
3199}
3200
Harry Yang6fe72ab2016-06-14 16:21:39 -07003201irqreturn_t smblib_handle_chg_state_change(int irq, void *data)
3202{
3203 struct smb_irq_data *irq_data = data;
3204 struct smb_charger *chg = irq_data->parent_data;
Nicholas Troast8cb77552016-09-23 11:50:18 -07003205 u8 stat;
Harry Yang1d1034c2016-06-15 12:09:42 -07003206 int rc;
Harry Yang6fe72ab2016-06-14 16:21:39 -07003207
3208 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3209
Nicholas Troast8cb77552016-09-23 11:50:18 -07003210 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
Harry Yang1d1034c2016-06-15 12:09:42 -07003211 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003212 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003213 rc);
Harry Yang1d1034c2016-06-15 12:09:42 -07003214 return IRQ_HANDLED;
3215 }
3216
Nicholas Troast8cb77552016-09-23 11:50:18 -07003217 stat = stat & BATTERY_CHARGER_STATUS_MASK;
Nicholas Troast8cb77552016-09-23 11:50:18 -07003218 power_supply_changed(chg->batt_psy);
Harry Yang6fe72ab2016-06-14 16:21:39 -07003219 return IRQ_HANDLED;
3220}
3221
Abhijeet Dharmapurikar2644cd62016-07-20 16:54:55 -07003222irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data)
3223{
3224 struct smb_irq_data *irq_data = data;
3225 struct smb_charger *chg = irq_data->parent_data;
Anirudh Ghayal941acaa2017-07-19 16:04:44 +05303226 int rc;
3227
3228 rc = smblib_recover_from_soft_jeita(chg);
3229 if (rc < 0) {
3230 smblib_err(chg, "Couldn't recover chg from soft jeita rc=%d\n",
3231 rc);
3232 return IRQ_HANDLED;
3233 }
Abhijeet Dharmapurikar2644cd62016-07-20 16:54:55 -07003234
3235 rerun_election(chg->fcc_votable);
3236 power_supply_changed(chg->batt_psy);
3237 return IRQ_HANDLED;
3238}
3239
Nicholas Troast34db5032016-03-28 12:26:44 -07003240irqreturn_t smblib_handle_batt_psy_changed(int irq, void *data)
3241{
3242 struct smb_irq_data *irq_data = data;
3243 struct smb_charger *chg = irq_data->parent_data;
3244
Nicholas Troast47ae4612016-08-03 09:49:36 -07003245 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003246 power_supply_changed(chg->batt_psy);
3247 return IRQ_HANDLED;
3248}
3249
3250irqreturn_t smblib_handle_usb_psy_changed(int irq, void *data)
3251{
3252 struct smb_irq_data *irq_data = data;
3253 struct smb_charger *chg = irq_data->parent_data;
3254
Nicholas Troast47ae4612016-08-03 09:49:36 -07003255 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003256 power_supply_changed(chg->usb_psy);
3257 return IRQ_HANDLED;
3258}
3259
Subbaraman Narayanamurthy09327482017-02-06 16:33:12 -08003260irqreturn_t smblib_handle_usbin_uv(int irq, void *data)
3261{
3262 struct smb_irq_data *irq_data = data;
3263 struct smb_charger *chg = irq_data->parent_data;
3264 struct storm_watch *wdata;
3265
3266 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3267 if (!chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data)
3268 return IRQ_HANDLED;
3269
3270 wdata = &chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data->storm_data;
3271 reset_storm_count(wdata);
3272 return IRQ_HANDLED;
3273}
3274
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003275static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising)
3276{
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003277 if (vbus_rising) {
3278 /* use the typec flag even though its not typec */
3279 chg->typec_present = 1;
3280 } else {
3281 chg->typec_present = 0;
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003282 smblib_update_usb_type(chg);
3283 extcon_set_cable_state_(chg->extcon, EXTCON_USB, false);
3284 smblib_uusb_removal(chg);
3285 }
3286}
3287
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003288void smblib_usb_plugin_hard_reset_locked(struct smb_charger *chg)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003289{
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003290 int rc;
3291 u8 stat;
3292 bool vbus_rising;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303293 struct smb_irq_data *data;
3294 struct storm_watch *wdata;
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003295
3296 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
3297 if (rc < 0) {
3298 smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
3299 return;
3300 }
3301
3302 vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
3303
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303304 if (vbus_rising) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003305 smblib_cc2_sink_removal_exit(chg);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303306 } else {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003307 smblib_cc2_sink_removal_enter(chg);
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303308 if (chg->wa_flags & BOOST_BACK_WA) {
3309 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
3310 if (data) {
3311 wdata = &data->storm_data;
3312 update_storm_count(wdata,
3313 WEAK_CHG_STORM_COUNT);
3314 vote(chg->usb_icl_votable, BOOST_BACK_VOTER,
3315 false, 0);
3316 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
3317 false, 0);
3318 }
3319 }
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303320 }
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003321
3322 power_supply_changed(chg->usb_psy);
3323 smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
3324 vbus_rising ? "attached" : "detached");
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003325}
3326
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303327#define PL_DELAY_MS 30000
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003328void smblib_usb_plugin_locked(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07003329{
Nicholas Troast34db5032016-03-28 12:26:44 -07003330 int rc;
3331 u8 stat;
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003332 bool vbus_rising;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303333 struct smb_irq_data *data;
3334 struct storm_watch *wdata;
Nicholas Troast34db5032016-03-28 12:26:44 -07003335
Harry Yangcdad2bf2016-10-04 17:03:56 -07003336 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
3337 if (rc < 0) {
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003338 smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
3339 return;
Harry Yangcdad2bf2016-10-04 17:03:56 -07003340 }
3341
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003342 vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003343 smblib_set_opt_freq_buck(chg, vbus_rising ? chg->chg_freq.freq_5V :
3344 chg->chg_freq.freq_removal);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003345
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003346 if (vbus_rising) {
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05303347 rc = smblib_request_dpdm(chg, true);
3348 if (rc < 0)
3349 smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303350
3351 /* Schedule work to enable parallel charger */
3352 vote(chg->awake_votable, PL_DELAY_VOTER, true, 0);
3353 schedule_delayed_work(&chg->pl_enable_work,
3354 msecs_to_jiffies(PL_DELAY_MS));
Harry Yang1ed7f162017-08-25 11:26:51 -07003355 /* vbus rising when APSD was disabled and PD_ACTIVE = 0 */
3356 if (get_effective_result(chg->apsd_disable_votable) &&
3357 !chg->pd_active)
3358 pr_err("APSD disabled on vbus rising without PD\n");
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07003359 } else {
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303360 if (chg->wa_flags & BOOST_BACK_WA) {
3361 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
3362 if (data) {
3363 wdata = &data->storm_data;
3364 update_storm_count(wdata,
3365 WEAK_CHG_STORM_COUNT);
3366 vote(chg->usb_icl_votable, BOOST_BACK_VOTER,
3367 false, 0);
3368 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
3369 false, 0);
3370 }
3371 }
Nicholas Troastabedaf72016-09-16 11:07:45 -07003372
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05303373 rc = smblib_request_dpdm(chg, false);
3374 if (rc < 0)
3375 smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07003376 }
3377
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003378 if (chg->micro_usb_mode)
3379 smblib_micro_usb_plugin(chg, vbus_rising);
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003380
Nicholas Troast62d86622016-09-22 11:41:33 -07003381 power_supply_changed(chg->usb_psy);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003382 smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
3383 vbus_rising ? "attached" : "detached");
3384}
3385
3386irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
3387{
3388 struct smb_irq_data *irq_data = data;
3389 struct smb_charger *chg = irq_data->parent_data;
3390
3391 mutex_lock(&chg->lock);
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003392 if (chg->pd_hard_reset)
3393 smblib_usb_plugin_hard_reset_locked(chg);
3394 else
3395 smblib_usb_plugin_locked(chg);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003396 mutex_unlock(&chg->lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07003397 return IRQ_HANDLED;
3398}
3399
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -07003400#define USB_WEAK_INPUT_UA 1400000
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303401#define ICL_CHANGE_DELAY_MS 1000
Harry Yang6fe72ab2016-06-14 16:21:39 -07003402irqreturn_t smblib_handle_icl_change(int irq, void *data)
3403{
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303404 u8 stat;
3405 int rc, settled_ua, delay = ICL_CHANGE_DELAY_MS;
Harry Yang6fe72ab2016-06-14 16:21:39 -07003406 struct smb_irq_data *irq_data = data;
3407 struct smb_charger *chg = irq_data->parent_data;
3408
Nicholas Troastbb9e1a32017-02-09 10:57:28 -08003409 if (chg->mode == PARALLEL_MASTER) {
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303410 rc = smblib_read(chg, AICL_STATUS_REG, &stat);
3411 if (rc < 0) {
3412 smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n",
3413 rc);
3414 return IRQ_HANDLED;
3415 }
3416
3417 rc = smblib_get_charge_param(chg, &chg->param.icl_stat,
3418 &settled_ua);
3419 if (rc < 0) {
3420 smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
3421 return IRQ_HANDLED;
3422 }
3423
3424 /* If AICL settled then schedule work now */
3425 if ((settled_ua == get_effective_result(chg->usb_icl_votable))
3426 || (stat & AICL_DONE_BIT))
3427 delay = 0;
3428
Ashay Jaiswalac854862017-03-06 23:58:55 +05303429 cancel_delayed_work_sync(&chg->icl_change_work);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303430 schedule_delayed_work(&chg->icl_change_work,
3431 msecs_to_jiffies(delay));
Nicholas Troastbb9e1a32017-02-09 10:57:28 -08003432 }
Harry Yang1d1034c2016-06-15 12:09:42 -07003433
Harry Yang6fe72ab2016-06-14 16:21:39 -07003434 return IRQ_HANDLED;
3435}
3436
Nicholas Troast34db5032016-03-28 12:26:44 -07003437static void smblib_handle_slow_plugin_timeout(struct smb_charger *chg,
3438 bool rising)
3439{
3440 smblib_dbg(chg, PR_INTERRUPT, "IRQ: slow-plugin-timeout %s\n",
3441 rising ? "rising" : "falling");
3442}
3443
3444static void smblib_handle_sdp_enumeration_done(struct smb_charger *chg,
3445 bool rising)
3446{
3447 smblib_dbg(chg, PR_INTERRUPT, "IRQ: sdp-enumeration-done %s\n",
3448 rising ? "rising" : "falling");
3449}
3450
Harry Yangcdad2bf2016-10-04 17:03:56 -07003451#define QC3_PULSES_FOR_6V 5
3452#define QC3_PULSES_FOR_9V 20
3453#define QC3_PULSES_FOR_12V 35
3454static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg)
3455{
3456 int rc;
3457 u8 stat;
3458 int pulses;
3459
Fenglin Wuef4730e2017-01-11 18:16:25 +08003460 power_supply_changed(chg->usb_main_psy);
Fenglin Wu80826e02017-04-25 21:45:08 +08003461 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP) {
Harry Yangcdad2bf2016-10-04 17:03:56 -07003462 rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat);
3463 if (rc < 0) {
3464 smblib_err(chg,
3465 "Couldn't read QC_CHANGE_STATUS rc=%d\n", rc);
3466 return;
3467 }
3468
3469 switch (stat & QC_2P0_STATUS_MASK) {
3470 case QC_5V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303471 smblib_set_opt_freq_buck(chg,
3472 chg->chg_freq.freq_5V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003473 break;
3474 case QC_9V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303475 smblib_set_opt_freq_buck(chg,
3476 chg->chg_freq.freq_9V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003477 break;
3478 case QC_12V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303479 smblib_set_opt_freq_buck(chg,
3480 chg->chg_freq.freq_12V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003481 break;
3482 default:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303483 smblib_set_opt_freq_buck(chg,
3484 chg->chg_freq.freq_removal);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003485 break;
3486 }
3487 }
3488
Fenglin Wu80826e02017-04-25 21:45:08 +08003489 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP_3) {
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +05303490 rc = smblib_get_pulse_cnt(chg, &pulses);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003491 if (rc < 0) {
3492 smblib_err(chg,
3493 "Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
3494 return;
3495 }
Harry Yangcdad2bf2016-10-04 17:03:56 -07003496
3497 if (pulses < QC3_PULSES_FOR_6V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303498 smblib_set_opt_freq_buck(chg,
3499 chg->chg_freq.freq_5V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003500 else if (pulses < QC3_PULSES_FOR_9V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303501 smblib_set_opt_freq_buck(chg,
3502 chg->chg_freq.freq_6V_8V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003503 else if (pulses < QC3_PULSES_FOR_12V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303504 smblib_set_opt_freq_buck(chg,
3505 chg->chg_freq.freq_9V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003506 else
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303507 smblib_set_opt_freq_buck(chg,
3508 chg->chg_freq.freq_12V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003509 }
3510}
3511
Nicholas Troast34db5032016-03-28 12:26:44 -07003512/* triggers when HVDCP 3.0 authentication has finished */
3513static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
3514 bool rising)
3515{
3516 const struct apsd_result *apsd_result;
Harry Yangcdad2bf2016-10-04 17:03:56 -07003517 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07003518
3519 if (!rising)
3520 return;
3521
Ashay Jaiswal67ec7072017-02-16 14:14:58 +05303522 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
3523 /*
3524 * Disable AUTH_IRQ_EN_CFG_BIT to receive adapter voltage
3525 * change interrupt.
3526 */
3527 rc = smblib_masked_write(chg,
3528 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
3529 AUTH_IRQ_EN_CFG_BIT, 0);
3530 if (rc < 0)
3531 smblib_err(chg,
3532 "Couldn't enable QC auth setting rc=%d\n", rc);
3533 }
Harry Yangcdad2bf2016-10-04 17:03:56 -07003534
Harry Yangaba1f5f2016-09-28 10:47:29 -07003535 if (chg->mode == PARALLEL_MASTER)
3536 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0);
3537
Ashay Jaiswalac854862017-03-06 23:58:55 +05303538 /* the APSD done handler will set the USB supply type */
3539 apsd_result = smblib_get_apsd_result(chg);
3540 if (get_effective_result(chg->hvdcp_hw_inov_dis_votable)) {
3541 if (apsd_result->pst == POWER_SUPPLY_TYPE_USB_HVDCP) {
3542 /* force HVDCP2 to 9V if INOV is disabled */
3543 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG,
3544 FORCE_9V_BIT, FORCE_9V_BIT);
3545 if (rc < 0)
3546 smblib_err(chg,
3547 "Couldn't force 9V HVDCP rc=%d\n", rc);
3548 }
3549 }
3550
Nicholas Troast34db5032016-03-28 12:26:44 -07003551 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n",
3552 apsd_result->name);
3553}
3554
Harry Yang1369b7a2016-09-27 15:59:50 -07003555static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
3556 bool rising, bool qc_charger)
3557{
Ashay Jaiswal7b6eb962017-04-26 14:34:29 +05303558 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05303559
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003560 /* Hold off PD only until hvdcp 2.0 detection timeout */
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003561 if (rising) {
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003562 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003563 false, 0);
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -08003564
Harry Yang4bf7d962017-03-13 16:51:43 -07003565 /* enable HDC and ICL irq for QC2/3 charger */
3566 if (qc_charger)
3567 vote(chg->usb_irq_enable_votable, QC_VOTER, true, 0);
3568
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -08003569 /*
3570 * HVDCP detection timeout done
3571 * If adapter is not QC2.0/QC3.0 - it is a plain old DCP.
3572 */
3573 if (!qc_charger && (apsd_result->bit & DCP_CHARGER_BIT))
3574 /* enforce DCP ICL if specified */
3575 vote(chg->usb_icl_votable, DCP_VOTER,
3576 chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua);
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003577 }
Harry Yang1369b7a2016-09-27 15:59:50 -07003578
3579 smblib_dbg(chg, PR_INTERRUPT, "IRQ: smblib_handle_hvdcp_check_timeout %s\n",
3580 rising ? "rising" : "falling");
3581}
3582
Nicholas Troast34db5032016-03-28 12:26:44 -07003583/* triggers when HVDCP is detected */
3584static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg,
3585 bool rising)
3586{
3587 if (!rising)
3588 return;
3589
3590 /* the APSD done handler will set the USB supply type */
3591 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
3592 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-detect-done %s\n",
3593 rising ? "rising" : "falling");
3594}
3595
Nicholas Troastf9e44992017-03-14 09:06:56 -07003596static void smblib_force_legacy_icl(struct smb_charger *chg, int pst)
3597{
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303598 int typec_mode;
3599 int rp_ua;
3600
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003601 /* while PD is active it should have complete ICL control */
3602 if (chg->pd_active)
3603 return;
3604
Nicholas Troastf9e44992017-03-14 09:06:56 -07003605 switch (pst) {
3606 case POWER_SUPPLY_TYPE_USB:
3607 /*
3608 * USB_PSY will vote to increase the current to 500/900mA once
3609 * enumeration is done. Ensure that USB_PSY has at least voted
3610 * for 100mA before releasing the LEGACY_UNKNOWN vote
3611 */
3612 if (!is_client_vote_enabled(chg->usb_icl_votable,
3613 USB_PSY_VOTER))
3614 vote(chg->usb_icl_votable, USB_PSY_VOTER, true, 100000);
3615 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
3616 break;
3617 case POWER_SUPPLY_TYPE_USB_CDP:
3618 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1500000);
3619 break;
3620 case POWER_SUPPLY_TYPE_USB_DCP:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303621 typec_mode = smblib_get_prop_typec_mode(chg);
3622 rp_ua = get_rp_based_dcp_current(chg, typec_mode);
3623 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua);
Nicholas Troastf9e44992017-03-14 09:06:56 -07003624 break;
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05303625 case POWER_SUPPLY_TYPE_USB_FLOAT:
3626 /*
3627 * limit ICL to 100mA, the USB driver will enumerate to check
3628 * if this is a SDP and appropriately set the current
3629 */
3630 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
3631 break;
Nicholas Troastf9e44992017-03-14 09:06:56 -07003632 case POWER_SUPPLY_TYPE_USB_HVDCP:
3633 case POWER_SUPPLY_TYPE_USB_HVDCP_3:
3634 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 3000000);
3635 break;
3636 default:
3637 smblib_err(chg, "Unknown APSD %d; forcing 500mA\n", pst);
3638 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 500000);
3639 break;
3640 }
3641}
3642
Ankit Sharmade321e12017-09-01 20:17:45 +05303643static void smblib_notify_extcon_props(struct smb_charger *chg, int id)
3644{
3645 union extcon_property_value val;
3646 union power_supply_propval prop_val;
3647
3648 smblib_get_prop_typec_cc_orientation(chg, &prop_val);
3649 val.intval = ((prop_val.intval == 2) ? 1 : 0);
3650 extcon_set_property(chg->extcon, id,
3651 EXTCON_PROP_USB_TYPEC_POLARITY, val);
3652
3653 val.intval = true;
3654 extcon_set_property(chg->extcon, id,
3655 EXTCON_PROP_USB_SS, val);
3656}
3657
3658static void smblib_notify_device_mode(struct smb_charger *chg, bool enable)
3659{
3660 if (enable)
3661 smblib_notify_extcon_props(chg, EXTCON_USB);
3662
3663 extcon_set_state_sync(chg->extcon, EXTCON_USB, enable);
3664}
3665
3666static void smblib_notify_usb_host(struct smb_charger *chg, bool enable)
3667{
3668 if (enable)
3669 smblib_notify_extcon_props(chg, EXTCON_USB_HOST);
3670
3671 extcon_set_state_sync(chg->extcon, EXTCON_USB_HOST, enable);
3672}
3673
Nicholas Troast34db5032016-03-28 12:26:44 -07003674#define HVDCP_DET_MS 2500
3675static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
3676{
Nicholas Troast34db5032016-03-28 12:26:44 -07003677 const struct apsd_result *apsd_result;
3678
3679 if (!rising)
3680 return;
3681
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07003682 apsd_result = smblib_update_usb_type(chg);
Nicholas Troastf9e44992017-03-14 09:06:56 -07003683
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003684 if (!chg->typec_legacy_valid)
Nicholas Troastf9e44992017-03-14 09:06:56 -07003685 smblib_force_legacy_icl(chg, apsd_result->pst);
3686
Nicholas Troast34db5032016-03-28 12:26:44 -07003687 switch (apsd_result->bit) {
3688 case SDP_CHARGER_BIT:
3689 case CDP_CHARGER_BIT:
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05303690 if (chg->micro_usb_mode)
3691 extcon_set_cable_state_(chg->extcon, EXTCON_USB,
3692 true);
Abhijeet Dharmapurikarbb9505f2017-03-22 18:31:28 -07003693 /* if not DCP then no hvdcp timeout happens. Enable pd here */
3694 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3695 false, 0);
Ankit Sharmade321e12017-09-01 20:17:45 +05303696 if (chg->use_extcon)
3697 smblib_notify_device_mode(chg, true);
Abhijeet Dharmapurikarbb9505f2017-03-22 18:31:28 -07003698 break;
Nicholas Troast34db5032016-03-28 12:26:44 -07003699 case OCP_CHARGER_BIT:
3700 case FLOAT_CHARGER_BIT:
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303701 /* if not DCP then no hvdcp timeout happens, Enable pd here. */
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003702 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3703 false, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07003704 break;
3705 case DCP_CHARGER_BIT:
Harry Yang1369b7a2016-09-27 15:59:50 -07003706 if (chg->wa_flags & QC_CHARGER_DETECTION_WA_BIT)
3707 schedule_delayed_work(&chg->hvdcp_detect_work,
3708 msecs_to_jiffies(HVDCP_DET_MS));
Nicholas Troast34db5032016-03-28 12:26:44 -07003709 break;
3710 default:
3711 break;
3712 }
3713
Nicholas Troast34db5032016-03-28 12:26:44 -07003714 smblib_dbg(chg, PR_INTERRUPT, "IRQ: apsd-done rising; %s detected\n",
3715 apsd_result->name);
3716}
3717
3718irqreturn_t smblib_handle_usb_source_change(int irq, void *data)
3719{
3720 struct smb_irq_data *irq_data = data;
3721 struct smb_charger *chg = irq_data->parent_data;
3722 int rc = 0;
3723 u8 stat;
3724
3725 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
3726 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003727 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07003728 return IRQ_HANDLED;
3729 }
3730 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
3731
Ashay Jaiswal8507aa52017-04-14 09:42:32 +05303732 if (chg->micro_usb_mode && (stat & APSD_DTC_STATUS_DONE_BIT)
3733 && !chg->uusb_apsd_rerun_done) {
3734 /*
3735 * Force re-run APSD to handle slow insertion related
3736 * charger-mis-detection.
3737 */
3738 chg->uusb_apsd_rerun_done = true;
3739 smblib_rerun_apsd(chg);
3740 return IRQ_HANDLED;
3741 }
3742
Nicholas Troast34db5032016-03-28 12:26:44 -07003743 smblib_handle_apsd_done(chg,
3744 (bool)(stat & APSD_DTC_STATUS_DONE_BIT));
3745
3746 smblib_handle_hvdcp_detect_done(chg,
3747 (bool)(stat & QC_CHARGER_BIT));
3748
Harry Yang1369b7a2016-09-27 15:59:50 -07003749 smblib_handle_hvdcp_check_timeout(chg,
3750 (bool)(stat & HVDCP_CHECK_TIMEOUT_BIT),
3751 (bool)(stat & QC_CHARGER_BIT));
3752
Nicholas Troast34db5032016-03-28 12:26:44 -07003753 smblib_handle_hvdcp_3p0_auth_done(chg,
3754 (bool)(stat & QC_AUTH_DONE_STATUS_BIT));
3755
Nicholas Troast34db5032016-03-28 12:26:44 -07003756 smblib_handle_sdp_enumeration_done(chg,
3757 (bool)(stat & ENUMERATION_DONE_BIT));
3758
3759 smblib_handle_slow_plugin_timeout(chg,
3760 (bool)(stat & SLOW_PLUGIN_TIMEOUT_BIT));
3761
Harry Yangcdad2bf2016-10-04 17:03:56 -07003762 smblib_hvdcp_adaptive_voltage_change(chg);
3763
Nicholas Troast34db5032016-03-28 12:26:44 -07003764 power_supply_changed(chg->usb_psy);
3765
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08003766 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
3767 if (rc < 0) {
3768 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
3769 return IRQ_HANDLED;
3770 }
3771 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
3772
Nicholas Troast34db5032016-03-28 12:26:44 -07003773 return IRQ_HANDLED;
3774}
3775
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003776static void typec_sink_insertion(struct smb_charger *chg)
3777{
3778 /* when a sink is inserted we should not wait on hvdcp timeout to
3779 * enable pd
3780 */
3781 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3782 false, 0);
Ankit Sharmade321e12017-09-01 20:17:45 +05303783 if (chg->use_extcon) {
3784 smblib_notify_usb_host(chg, true);
3785 chg->otg_present = true;
3786 }
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003787}
Nicholas Troast34db5032016-03-28 12:26:44 -07003788
Harry Yangd89ff1f2016-12-05 14:59:11 -08003789static void typec_sink_removal(struct smb_charger *chg)
3790{
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303791 smblib_set_charge_param(chg, &chg->param.freq_boost,
3792 chg->chg_freq.freq_above_otg_threshold);
Harry Yangd89ff1f2016-12-05 14:59:11 -08003793 chg->boost_current_ua = 0;
3794}
3795
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003796static void smblib_handle_typec_removal(struct smb_charger *chg)
3797{
Nicholas Troastfe74c592017-03-14 09:20:55 -07003798 int rc;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303799 struct smb_irq_data *data;
3800 struct storm_watch *wdata;
Nicholas Troastfe74c592017-03-14 09:20:55 -07003801
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003802 chg->cc2_detach_wa_active = false;
3803
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05303804 rc = smblib_request_dpdm(chg, false);
3805 if (rc < 0)
3806 smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303807
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303808 if (chg->wa_flags & BOOST_BACK_WA) {
3809 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
3810 if (data) {
3811 wdata = &data->storm_data;
3812 update_storm_count(wdata, WEAK_CHG_STORM_COUNT);
3813 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
3814 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
3815 false, 0);
3816 }
3817 }
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303818
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003819 /* reset APSD voters */
3820 vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, false, 0);
3821 vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303822
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003823 cancel_delayed_work_sync(&chg->pl_enable_work);
3824 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
3825
3826 /* reset input current limit voters */
3827 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
3828 vote(chg->usb_icl_votable, PD_VOTER, false, 0);
3829 vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
3830 vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
3831 vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
Ashay Jaiswalae23a042017-05-18 15:28:31 +05303832 vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
Abhijeet Dharmapurikar66d2c442017-07-12 11:55:36 -07003833 vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003834
3835 /* reset hvdcp voters */
3836 vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, true, 0);
3837 vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER, true, 0);
3838
3839 /* reset power delivery voters */
3840 vote(chg->pd_allowed_votable, PD_VOTER, false, 0);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003841 vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0);
3842 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER, true, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003843
3844 /* reset usb irq voters */
Harry Yang4bf7d962017-03-13 16:51:43 -07003845 vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
3846 vote(chg->usb_irq_enable_votable, QC_VOTER, false, 0);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003847
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003848 /* reset parallel voters */
3849 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
Harry Yanga796cf72017-07-19 19:26:45 -07003850 vote(chg->pl_disable_votable, FCC_CHANGE_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003851 vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
3852 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
3853 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
Harry Yang1d1034c2016-06-15 12:09:42 -07003854
Nicholas Troast8995a702016-12-05 10:22:22 -08003855 chg->vconn_attempts = 0;
3856 chg->otg_attempts = 0;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05303857 chg->pulse_cnt = 0;
3858 chg->usb_icl_delta_ua = 0;
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003859 chg->voltage_min_uv = MICRO_5V;
3860 chg->voltage_max_uv = MICRO_5V;
3861 chg->pd_active = 0;
3862 chg->pd_hard_reset = 0;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003863 chg->typec_legacy_valid = false;
Harry Yang3b113a52016-12-08 12:37:40 -08003864
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05303865 /* write back the default FLOAT charger configuration */
3866 rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
3867 (u8)FLOAT_OPTIONS_MASK, chg->float_cfg);
3868 if (rc < 0)
3869 smblib_err(chg, "Couldn't write float charger options rc=%d\n",
3870 rc);
3871
Abhijeet Dharmapurikar676bd792017-05-31 16:21:57 -07003872 /* reset back to 120mS tCC debounce */
3873 rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT, 0);
3874 if (rc < 0)
3875 smblib_err(chg, "Couldn't set 120mS tCC debounce rc=%d\n", rc);
3876
Nicholas Troastfe74c592017-03-14 09:20:55 -07003877 /* enable APSD CC trigger for next insertion */
3878 rc = smblib_masked_write(chg, TYPE_C_CFG_REG,
3879 APSD_START_ON_CC_BIT, APSD_START_ON_CC_BIT);
3880 if (rc < 0)
3881 smblib_err(chg, "Couldn't enable APSD_START_ON_CC rc=%d\n", rc);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08003882
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003883 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
3884 /* re-enable AUTH_IRQ_EN_CFG_BIT */
3885 rc = smblib_masked_write(chg,
3886 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
3887 AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
3888 if (rc < 0)
3889 smblib_err(chg,
3890 "Couldn't enable QC auth setting rc=%d\n", rc);
3891 }
3892
3893 /* reconfigure allowed voltage for HVDCP */
3894 rc = smblib_set_adapter_allowance(chg,
3895 USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
3896 if (rc < 0)
3897 smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
3898 rc);
3899
3900 /* enable DRP */
3901 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
3902 TYPEC_POWER_ROLE_CMD_MASK, 0);
3903 if (rc < 0)
3904 smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc);
3905
3906 /* HW controlled CC_OUT */
3907 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
3908 TYPEC_SPARE_CFG_BIT, 0);
3909 if (rc < 0)
3910 smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n", rc);
3911
3912 /* restore crude sensor */
3913 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
3914 if (rc < 0)
3915 smblib_err(chg, "Couldn't restore crude sensor rc=%d\n", rc);
3916
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07003917 mutex_lock(&chg->vconn_oc_lock);
3918 if (!chg->vconn_en)
3919 goto unlock;
3920
3921 smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
3922 VCONN_EN_VALUE_BIT, 0);
3923 chg->vconn_en = false;
3924
3925unlock:
3926 mutex_unlock(&chg->vconn_oc_lock);
3927
Abhijeet Dharmapurikar319d6942017-06-05 17:14:17 -07003928 /* clear exit sink based on cc */
3929 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
3930 EXIT_SNK_BASED_ON_CC_BIT, 0);
3931 if (rc < 0)
3932 smblib_err(chg, "Couldn't clear exit_sink_based_on_cc rc=%d\n",
3933 rc);
3934
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08003935 typec_sink_removal(chg);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003936 smblib_update_usb_type(chg);
Ankit Sharmade321e12017-09-01 20:17:45 +05303937
3938 if (chg->use_extcon) {
3939 if (chg->otg_present)
3940 smblib_notify_usb_host(chg, false);
3941 else
3942 smblib_notify_device_mode(chg, false);
3943 }
3944 chg->otg_present = false;
Nicholas Troast34db5032016-03-28 12:26:44 -07003945}
3946
Nicholas Troaste1932e42017-04-12 12:38:18 -07003947static void smblib_handle_typec_insertion(struct smb_charger *chg)
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003948{
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003949 int rc;
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003950
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003951 vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, false, 0);
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003952
Nicholas Troastfe74c592017-03-14 09:20:55 -07003953 /* disable APSD CC trigger since CC is attached */
3954 rc = smblib_masked_write(chg, TYPE_C_CFG_REG, APSD_START_ON_CC_BIT, 0);
3955 if (rc < 0)
3956 smblib_err(chg, "Couldn't disable APSD_START_ON_CC rc=%d\n",
3957 rc);
3958
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05303959 if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT) {
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003960 typec_sink_insertion(chg);
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05303961 } else {
3962 rc = smblib_request_dpdm(chg, true);
3963 if (rc < 0)
3964 smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
Harry Yangd89ff1f2016-12-05 14:59:11 -08003965 typec_sink_removal(chg);
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05303966 }
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003967}
3968
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303969static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode)
3970{
3971 int rp_ua;
3972 const struct apsd_result *apsd = smblib_get_apsd_result(chg);
3973
3974 if ((apsd->pst != POWER_SUPPLY_TYPE_USB_DCP)
3975 && (apsd->pst != POWER_SUPPLY_TYPE_USB_FLOAT))
3976 return;
3977
3978 /*
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05303979 * if APSD indicates FLOAT and the USB stack had detected SDP,
3980 * do not respond to Rp changes as we do not confirm that its
3981 * a legacy cable
3982 */
3983 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
3984 return;
3985 /*
3986 * We want the ICL vote @ 100mA for a FLOAT charger
3987 * until the detection by the USB stack is complete.
3988 * Ignore the Rp changes unless there is a
3989 * pre-existing valid vote.
3990 */
3991 if (apsd->pst == POWER_SUPPLY_TYPE_USB_FLOAT &&
3992 get_client_vote(chg->usb_icl_votable,
3993 LEGACY_UNKNOWN_VOTER) <= 100000)
3994 return;
3995
3996 /*
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303997 * handle Rp change for DCP/FLOAT/OCP.
3998 * Update the current only if the Rp is different from
3999 * the last Rp value.
4000 */
4001 smblib_dbg(chg, PR_MISC, "CC change old_mode=%d new_mode=%d\n",
4002 chg->typec_mode, typec_mode);
4003
4004 rp_ua = get_rp_based_dcp_current(chg, typec_mode);
4005 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua);
4006}
4007
Nicholas Troaste1932e42017-04-12 12:38:18 -07004008static void smblib_handle_typec_cc_state_change(struct smb_charger *chg)
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004009{
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05304010 int typec_mode;
4011
Nicholas Troaste1932e42017-04-12 12:38:18 -07004012 if (chg->pr_swap_in_progress)
4013 return;
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004014
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05304015 typec_mode = smblib_get_prop_typec_mode(chg);
4016 if (chg->typec_present && (typec_mode != chg->typec_mode))
4017 smblib_handle_rp_change(chg, typec_mode);
4018
4019 chg->typec_mode = typec_mode;
4020
Nicholas Troaste1932e42017-04-12 12:38:18 -07004021 if (!chg->typec_present && chg->typec_mode != POWER_SUPPLY_TYPEC_NONE) {
4022 chg->typec_present = true;
4023 smblib_dbg(chg, PR_MISC, "TypeC %s insertion\n",
4024 smblib_typec_mode_name[chg->typec_mode]);
4025 smblib_handle_typec_insertion(chg);
4026 } else if (chg->typec_present &&
4027 chg->typec_mode == POWER_SUPPLY_TYPEC_NONE) {
4028 chg->typec_present = false;
4029 smblib_dbg(chg, PR_MISC, "TypeC removal\n");
4030 smblib_handle_typec_removal(chg);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004031 }
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004032
Abhijeet Dharmapurikar66d2c442017-07-12 11:55:36 -07004033 /* suspend usb if sink */
Harry Yangca0664e2017-08-18 11:40:06 -07004034 if ((chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
4035 && chg->typec_present)
Abhijeet Dharmapurikar66d2c442017-07-12 11:55:36 -07004036 vote(chg->usb_icl_votable, OTG_VOTER, true, 0);
4037 else
4038 vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
4039
Nicholas Troaste1932e42017-04-12 12:38:18 -07004040 smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n",
4041 smblib_typec_mode_name[chg->typec_mode]);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004042}
4043
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004044static void smblib_usb_typec_change(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07004045{
Nicholas Troast34db5032016-03-28 12:26:44 -07004046 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07004047
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07004048 rc = smblib_multibyte_read(chg, TYPE_C_STATUS_1_REG,
4049 chg->typec_status, 5);
Nicholas Troast34db5032016-03-28 12:26:44 -07004050 if (rc < 0) {
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07004051 smblib_err(chg, "Couldn't cache USB Type-C status rc=%d\n", rc);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004052 return;
Nicholas Troast34db5032016-03-28 12:26:44 -07004053 }
Nicholas Troast34db5032016-03-28 12:26:44 -07004054
Nicholas Troaste1932e42017-04-12 12:38:18 -07004055 smblib_handle_typec_cc_state_change(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07004056
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07004057 if (chg->typec_status[3] & TYPEC_VBUS_ERROR_STATUS_BIT)
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004058 smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n");
Harry Yangd757c0f2016-09-23 10:52:05 -07004059
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07004060 if (chg->typec_status[3] & TYPEC_VCONN_OVERCURR_STATUS_BIT)
Nicholas Troastb11015f2017-01-17 17:56:45 -08004061 schedule_work(&chg->vconn_oc_work);
Nicholas Troast8995a702016-12-05 10:22:22 -08004062
Nicholas Troastb1486552016-11-10 08:20:11 -08004063 power_supply_changed(chg->usb_psy);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004064}
4065
4066irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
4067{
4068 struct smb_irq_data *irq_data = data;
4069 struct smb_charger *chg = irq_data->parent_data;
4070
4071 if (chg->micro_usb_mode) {
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05304072 cancel_delayed_work_sync(&chg->uusb_otg_work);
4073 vote(chg->awake_votable, OTG_DELAY_VOTER, true, 0);
4074 smblib_dbg(chg, PR_INTERRUPT, "Scheduling OTG work\n");
4075 schedule_delayed_work(&chg->uusb_otg_work,
4076 msecs_to_jiffies(chg->otg_delay_ms));
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004077 return IRQ_HANDLED;
4078 }
4079
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004080 if (chg->cc2_detach_wa_active || chg->typec_en_dis_active) {
4081 smblib_dbg(chg, PR_INTERRUPT, "Ignoring since %s active\n",
4082 chg->cc2_detach_wa_active ?
4083 "cc2_detach_wa" : "typec_en_dis");
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004084 return IRQ_HANDLED;
4085 }
4086
Abhijeet Dharmapurikar049b2552017-07-12 11:27:51 -07004087 if (chg->pr_swap_in_progress) {
4088 smblib_dbg(chg, PR_INTERRUPT,
4089 "Ignoring since pr_swap_in_progress\n");
4090 return IRQ_HANDLED;
4091 }
4092
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004093 mutex_lock(&chg->lock);
4094 smblib_usb_typec_change(chg);
4095 mutex_unlock(&chg->lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07004096 return IRQ_HANDLED;
4097}
4098
Abhijeet Dharmapurikar23916642016-10-03 10:38:50 -07004099irqreturn_t smblib_handle_dc_plugin(int irq, void *data)
4100{
4101 struct smb_irq_data *irq_data = data;
4102 struct smb_charger *chg = irq_data->parent_data;
4103
4104 power_supply_changed(chg->dc_psy);
4105 return IRQ_HANDLED;
4106}
4107
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004108irqreturn_t smblib_handle_high_duty_cycle(int irq, void *data)
4109{
4110 struct smb_irq_data *irq_data = data;
4111 struct smb_charger *chg = irq_data->parent_data;
4112
4113 chg->is_hdc = true;
Fenglin Wu4f4dcc12017-08-24 14:28:54 +08004114 /*
4115 * Disable usb IRQs after the flag set and re-enable IRQs after
4116 * the flag cleared in the delayed work queue, to avoid any IRQ
4117 * storming during the delays
4118 */
4119 if (chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq)
4120 disable_irq_nosync(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
4121
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004122 schedule_delayed_work(&chg->clear_hdc_work, msecs_to_jiffies(60));
4123
4124 return IRQ_HANDLED;
4125}
4126
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05304127static void smblib_bb_removal_work(struct work_struct *work)
4128{
4129 struct smb_charger *chg = container_of(work, struct smb_charger,
4130 bb_removal_work.work);
4131
4132 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
4133 vote(chg->awake_votable, BOOST_BACK_VOTER, false, 0);
4134}
4135
4136#define BOOST_BACK_UNVOTE_DELAY_MS 750
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304137#define BOOST_BACK_STORM_COUNT 3
4138#define WEAK_CHG_STORM_COUNT 8
Nicholas Troastabedaf72016-09-16 11:07:45 -07004139irqreturn_t smblib_handle_switcher_power_ok(int irq, void *data)
4140{
4141 struct smb_irq_data *irq_data = data;
4142 struct smb_charger *chg = irq_data->parent_data;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304143 struct storm_watch *wdata = &irq_data->storm_data;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004144 int rc, usb_icl;
Nicholas Troastabedaf72016-09-16 11:07:45 -07004145 u8 stat;
4146
4147 if (!(chg->wa_flags & BOOST_BACK_WA))
4148 return IRQ_HANDLED;
4149
4150 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
4151 if (rc < 0) {
4152 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n", rc);
4153 return IRQ_HANDLED;
4154 }
4155
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004156 /* skip suspending input if its already suspended by some other voter */
4157 usb_icl = get_effective_result(chg->usb_icl_votable);
Harry Yang379484a2017-08-29 10:26:14 -07004158 if ((stat & USE_USBIN_BIT) && usb_icl >= 0 && usb_icl <= USBIN_25MA)
Nicholas Troastabedaf72016-09-16 11:07:45 -07004159 return IRQ_HANDLED;
4160
Abhijeet Dharmapurikar2823fe32016-12-05 17:52:11 -08004161 if (stat & USE_DCIN_BIT)
Nicholas Troastabedaf72016-09-16 11:07:45 -07004162 return IRQ_HANDLED;
4163
4164 if (is_storming(&irq_data->storm_data)) {
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304165 /* This could be a weak charger reduce ICL */
4166 if (!is_client_vote_enabled(chg->usb_icl_votable,
4167 WEAK_CHARGER_VOTER)) {
4168 smblib_err(chg,
4169 "Weak charger detected: voting %dmA ICL\n",
4170 *chg->weak_chg_icl_ua / 1000);
4171 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
4172 true, *chg->weak_chg_icl_ua);
4173 /*
4174 * reset storm data and set the storm threshold
4175 * to 3 for reverse boost detection.
4176 */
4177 update_storm_count(wdata, BOOST_BACK_STORM_COUNT);
4178 } else {
4179 smblib_err(chg,
4180 "Reverse boost detected: voting 0mA to suspend input\n");
4181 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, true, 0);
4182 vote(chg->awake_votable, BOOST_BACK_VOTER, true, 0);
4183 /*
4184 * Remove the boost-back vote after a delay, to avoid
4185 * permanently suspending the input if the boost-back
4186 * condition is unintentionally hit.
4187 */
4188 schedule_delayed_work(&chg->bb_removal_work,
4189 msecs_to_jiffies(BOOST_BACK_UNVOTE_DELAY_MS));
4190 }
Nicholas Troastabedaf72016-09-16 11:07:45 -07004191 }
4192
4193 return IRQ_HANDLED;
4194}
4195
Nicholas Troast15dc0c82016-10-18 15:15:21 -07004196irqreturn_t smblib_handle_wdog_bark(int irq, void *data)
4197{
4198 struct smb_irq_data *irq_data = data;
4199 struct smb_charger *chg = irq_data->parent_data;
4200 int rc;
4201
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05304202 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
4203
Nicholas Troast15dc0c82016-10-18 15:15:21 -07004204 rc = smblib_write(chg, BARK_BITE_WDOG_PET_REG, BARK_BITE_WDOG_PET_BIT);
4205 if (rc < 0)
4206 smblib_err(chg, "Couldn't pet the dog rc=%d\n", rc);
4207
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +05304208 if (chg->step_chg_enabled || chg->sw_jeita_enabled)
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05304209 power_supply_changed(chg->batt_psy);
4210
Nicholas Troast15dc0c82016-10-18 15:15:21 -07004211 return IRQ_HANDLED;
4212}
4213
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004214/**************
4215 * Additional USB PSY getters/setters
4216 * that call interrupt functions
4217 ***************/
4218
4219int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg,
4220 union power_supply_propval *val)
4221{
4222 val->intval = chg->pr_swap_in_progress;
4223 return 0;
4224}
4225
4226int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg,
4227 const union power_supply_propval *val)
4228{
Abhijeet Dharmapurikar676bd792017-05-31 16:21:57 -07004229 int rc;
4230
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004231 chg->pr_swap_in_progress = val->intval;
4232 /*
4233 * call the cc changed irq to handle real removals while
4234 * PR_SWAP was in progress
4235 */
4236 smblib_usb_typec_change(chg);
Abhijeet Dharmapurikar676bd792017-05-31 16:21:57 -07004237 rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT,
4238 val->intval ? TCC_DEBOUNCE_20MS_BIT : 0);
4239 if (rc < 0)
4240 smblib_err(chg, "Couldn't set tCC debounce rc=%d\n", rc);
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004241 return 0;
4242}
4243
Nicholas Troast34db5032016-03-28 12:26:44 -07004244/***************
4245 * Work Queues *
4246 ***************/
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05304247static void smblib_uusb_otg_work(struct work_struct *work)
4248{
4249 struct smb_charger *chg = container_of(work, struct smb_charger,
4250 uusb_otg_work.work);
4251 int rc;
4252 u8 stat;
4253 bool otg;
4254
4255 rc = smblib_read(chg, TYPE_C_STATUS_3_REG, &stat);
4256 if (rc < 0) {
4257 smblib_err(chg, "Couldn't read TYPE_C_STATUS_3 rc=%d\n", rc);
4258 goto out;
4259 }
4260
4261 otg = !!(stat & (U_USB_GND_NOVBUS_BIT | U_USB_GND_BIT));
4262 extcon_set_cable_state_(chg->extcon, EXTCON_USB_HOST, otg);
4263 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_3 = 0x%02x OTG=%d\n",
4264 stat, otg);
4265 power_supply_changed(chg->usb_psy);
4266
4267out:
4268 vote(chg->awake_votable, OTG_DELAY_VOTER, false, 0);
4269}
4270
Nicholas Troast34db5032016-03-28 12:26:44 -07004271
4272static void smblib_hvdcp_detect_work(struct work_struct *work)
4273{
4274 struct smb_charger *chg = container_of(work, struct smb_charger,
4275 hvdcp_detect_work.work);
Nicholas Troast34db5032016-03-28 12:26:44 -07004276
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07004277 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
4278 false, 0);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004279 power_supply_changed(chg->usb_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07004280}
4281
Harry Yangfe913842016-08-10 12:27:28 -07004282static void bms_update_work(struct work_struct *work)
Harry Yang5e1a5222016-07-26 15:16:04 -07004283{
4284 struct smb_charger *chg = container_of(work, struct smb_charger,
4285 bms_update_work);
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05304286
4287 smblib_suspend_on_debug_battery(chg);
4288
4289 if (chg->batt_psy)
4290 power_supply_changed(chg->batt_psy);
Harry Yang5e1a5222016-07-26 15:16:04 -07004291}
4292
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004293static void clear_hdc_work(struct work_struct *work)
4294{
4295 struct smb_charger *chg = container_of(work, struct smb_charger,
4296 clear_hdc_work.work);
4297
4298 chg->is_hdc = 0;
Fenglin Wu4f4dcc12017-08-24 14:28:54 +08004299 if (chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq)
4300 enable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004301}
4302
Harry Yang755a34b2016-11-01 01:18:51 -07004303static void rdstd_cc2_detach_work(struct work_struct *work)
4304{
4305 int rc;
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004306 u8 stat4, stat5;
Harry Yang755a34b2016-11-01 01:18:51 -07004307 struct smb_charger *chg = container_of(work, struct smb_charger,
4308 rdstd_cc2_detach_work);
4309
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004310 if (!chg->cc2_detach_wa_active)
4311 return;
4312
Harry Yang755a34b2016-11-01 01:18:51 -07004313 /*
4314 * WA steps -
4315 * 1. Enable both UFP and DFP, wait for 10ms.
4316 * 2. Disable DFP, wait for 30ms.
4317 * 3. Removal detected if both TYPEC_DEBOUNCE_DONE_STATUS
4318 * and TIMER_STAGE bits are gone, otherwise repeat all by
4319 * work rescheduling.
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004320 * Note, work will be cancelled when USB_PLUGIN rises.
Harry Yang755a34b2016-11-01 01:18:51 -07004321 */
4322
4323 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4324 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT,
4325 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT);
4326 if (rc < 0) {
4327 smblib_err(chg, "Couldn't write TYPE_C_CTRL_REG rc=%d\n", rc);
4328 return;
4329 }
4330
4331 usleep_range(10000, 11000);
4332
4333 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4334 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT,
4335 UFP_EN_CMD_BIT);
4336 if (rc < 0) {
4337 smblib_err(chg, "Couldn't write TYPE_C_CTRL_REG rc=%d\n", rc);
4338 return;
4339 }
4340
4341 usleep_range(30000, 31000);
4342
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004343 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
Harry Yang755a34b2016-11-01 01:18:51 -07004344 if (rc < 0) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004345 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
Harry Yang755a34b2016-11-01 01:18:51 -07004346 return;
4347 }
Harry Yang755a34b2016-11-01 01:18:51 -07004348
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004349 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
Harry Yang755a34b2016-11-01 01:18:51 -07004350 if (rc < 0) {
4351 smblib_err(chg,
4352 "Couldn't read TYPE_C_STATUS_5_REG rc=%d\n", rc);
4353 return;
4354 }
Harry Yang755a34b2016-11-01 01:18:51 -07004355
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004356 if ((stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT)
4357 || (stat5 & TIMER_STAGE_2_BIT)) {
4358 smblib_dbg(chg, PR_MISC, "rerunning DD=%d TS2BIT=%d\n",
4359 (int)(stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT),
4360 (int)(stat5 & TIMER_STAGE_2_BIT));
4361 goto rerun;
4362 }
4363
4364 smblib_dbg(chg, PR_MISC, "Bingo CC2 Removal detected\n");
4365 chg->cc2_detach_wa_active = false;
4366 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4367 EXIT_SNK_BASED_ON_CC_BIT, 0);
Harry Yang755a34b2016-11-01 01:18:51 -07004368 smblib_reg_block_restore(chg, cc2_detach_settings);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004369 mutex_lock(&chg->lock);
4370 smblib_usb_typec_change(chg);
4371 mutex_unlock(&chg->lock);
Harry Yang755a34b2016-11-01 01:18:51 -07004372 return;
4373
4374rerun:
4375 schedule_work(&chg->rdstd_cc2_detach_work);
4376}
4377
Nicholas Troastb11015f2017-01-17 17:56:45 -08004378static void smblib_otg_oc_exit(struct smb_charger *chg, bool success)
4379{
4380 int rc;
4381
4382 chg->otg_attempts = 0;
4383 if (!success) {
4384 smblib_err(chg, "OTG soft start failed\n");
4385 chg->otg_en = false;
4386 }
4387
4388 smblib_dbg(chg, PR_OTG, "enabling VBUS < 1V check\n");
4389 rc = smblib_masked_write(chg, OTG_CFG_REG,
4390 QUICKSTART_OTG_FASTROLESWAP_BIT, 0);
4391 if (rc < 0)
4392 smblib_err(chg, "Couldn't enable VBUS < 1V check rc=%d\n", rc);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004393}
4394
4395#define MAX_OC_FALLING_TRIES 10
4396static void smblib_otg_oc_work(struct work_struct *work)
4397{
4398 struct smb_charger *chg = container_of(work, struct smb_charger,
4399 otg_oc_work);
4400 int rc, i;
4401 u8 stat;
4402
4403 if (!chg->vbus_vreg || !chg->vbus_vreg->rdev)
4404 return;
4405
4406 smblib_err(chg, "over-current detected on VBUS\n");
4407 mutex_lock(&chg->otg_oc_lock);
4408 if (!chg->otg_en)
4409 goto unlock;
4410
4411 smblib_dbg(chg, PR_OTG, "disabling VBUS < 1V check\n");
4412 smblib_masked_write(chg, OTG_CFG_REG,
4413 QUICKSTART_OTG_FASTROLESWAP_BIT,
4414 QUICKSTART_OTG_FASTROLESWAP_BIT);
4415
4416 /*
4417 * If 500ms has passed and another over-current interrupt has not
4418 * triggered then it is likely that the software based soft start was
4419 * successful and the VBUS < 1V restriction should be re-enabled.
4420 */
4421 schedule_delayed_work(&chg->otg_ss_done_work, msecs_to_jiffies(500));
4422
4423 rc = _smblib_vbus_regulator_disable(chg->vbus_vreg->rdev);
4424 if (rc < 0) {
4425 smblib_err(chg, "Couldn't disable VBUS rc=%d\n", rc);
4426 goto unlock;
4427 }
4428
4429 if (++chg->otg_attempts > OTG_MAX_ATTEMPTS) {
4430 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4431 smblib_err(chg, "OTG failed to enable after %d attempts\n",
4432 chg->otg_attempts - 1);
4433 smblib_otg_oc_exit(chg, false);
4434 goto unlock;
4435 }
4436
4437 /*
4438 * The real time status should go low within 10ms. Poll every 1-2ms to
4439 * minimize the delay when re-enabling OTG.
4440 */
4441 for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) {
4442 usleep_range(1000, 2000);
4443 rc = smblib_read(chg, OTG_BASE + INT_RT_STS_OFFSET, &stat);
4444 if (rc >= 0 && !(stat & OTG_OVERCURRENT_RT_STS_BIT))
4445 break;
4446 }
4447
4448 if (i >= MAX_OC_FALLING_TRIES) {
4449 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4450 smblib_err(chg, "OTG OC did not fall after %dms\n",
4451 2 * MAX_OC_FALLING_TRIES);
4452 smblib_otg_oc_exit(chg, false);
4453 goto unlock;
4454 }
4455
4456 smblib_dbg(chg, PR_OTG, "OTG OC fell after %dms\n", 2 * i + 1);
4457 rc = _smblib_vbus_regulator_enable(chg->vbus_vreg->rdev);
4458 if (rc < 0) {
4459 smblib_err(chg, "Couldn't enable VBUS rc=%d\n", rc);
4460 goto unlock;
4461 }
4462
4463unlock:
4464 mutex_unlock(&chg->otg_oc_lock);
4465}
4466
4467static void smblib_vconn_oc_work(struct work_struct *work)
4468{
4469 struct smb_charger *chg = container_of(work, struct smb_charger,
4470 vconn_oc_work);
4471 int rc, i;
4472 u8 stat;
4473
Ashay Jaiswal15edce42017-03-31 23:29:58 +05304474 if (chg->micro_usb_mode)
4475 return;
4476
Nicholas Troastb11015f2017-01-17 17:56:45 -08004477 smblib_err(chg, "over-current detected on VCONN\n");
4478 if (!chg->vconn_vreg || !chg->vconn_vreg->rdev)
4479 return;
4480
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07004481 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004482 rc = _smblib_vconn_regulator_disable(chg->vconn_vreg->rdev);
4483 if (rc < 0) {
4484 smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc);
4485 goto unlock;
4486 }
4487
4488 if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
4489 smblib_err(chg, "VCONN failed to enable after %d attempts\n",
4490 chg->otg_attempts - 1);
4491 chg->vconn_en = false;
4492 chg->vconn_attempts = 0;
4493 goto unlock;
4494 }
4495
4496 /*
4497 * The real time status should go low within 10ms. Poll every 1-2ms to
4498 * minimize the delay when re-enabling OTG.
4499 */
4500 for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) {
4501 usleep_range(1000, 2000);
4502 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
4503 if (rc >= 0 && !(stat & TYPEC_VCONN_OVERCURR_STATUS_BIT))
4504 break;
4505 }
4506
4507 if (i >= MAX_OC_FALLING_TRIES) {
4508 smblib_err(chg, "VCONN OC did not fall after %dms\n",
4509 2 * MAX_OC_FALLING_TRIES);
4510 chg->vconn_en = false;
4511 chg->vconn_attempts = 0;
4512 goto unlock;
4513 }
4514
4515 smblib_dbg(chg, PR_OTG, "VCONN OC fell after %dms\n", 2 * i + 1);
4516 if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
4517 smblib_err(chg, "VCONN failed to enable after %d attempts\n",
4518 chg->vconn_attempts - 1);
4519 chg->vconn_en = false;
4520 goto unlock;
4521 }
4522
4523 rc = _smblib_vconn_regulator_enable(chg->vconn_vreg->rdev);
4524 if (rc < 0) {
4525 smblib_err(chg, "Couldn't enable VCONN rc=%d\n", rc);
4526 goto unlock;
4527 }
4528
4529unlock:
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07004530 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004531}
4532
4533static void smblib_otg_ss_done_work(struct work_struct *work)
4534{
4535 struct smb_charger *chg = container_of(work, struct smb_charger,
4536 otg_ss_done_work.work);
4537 int rc;
4538 bool success = false;
4539 u8 stat;
4540
4541 mutex_lock(&chg->otg_oc_lock);
4542 rc = smblib_read(chg, OTG_STATUS_REG, &stat);
4543 if (rc < 0)
4544 smblib_err(chg, "Couldn't read OTG status rc=%d\n", rc);
4545 else if (stat & BOOST_SOFTSTART_DONE_BIT)
4546 success = true;
4547
4548 smblib_otg_oc_exit(chg, success);
4549 mutex_unlock(&chg->otg_oc_lock);
4550}
4551
Ashay Jaiswal4d825782017-02-18 10:11:34 +05304552static void smblib_icl_change_work(struct work_struct *work)
4553{
4554 struct smb_charger *chg = container_of(work, struct smb_charger,
4555 icl_change_work.work);
4556 int rc, settled_ua;
4557
4558 rc = smblib_get_charge_param(chg, &chg->param.icl_stat, &settled_ua);
4559 if (rc < 0) {
4560 smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
4561 return;
4562 }
4563
4564 power_supply_changed(chg->usb_main_psy);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05304565
4566 smblib_dbg(chg, PR_INTERRUPT, "icl_settled=%d\n", settled_ua);
4567}
4568
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304569static void smblib_pl_enable_work(struct work_struct *work)
4570{
4571 struct smb_charger *chg = container_of(work, struct smb_charger,
4572 pl_enable_work.work);
4573
4574 smblib_dbg(chg, PR_PARALLEL, "timer expired, enabling parallel\n");
4575 vote(chg->pl_disable_votable, PL_DELAY_VOTER, false, 0);
4576 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
4577}
4578
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004579static void smblib_legacy_detection_work(struct work_struct *work)
4580{
4581 struct smb_charger *chg = container_of(work, struct smb_charger,
4582 legacy_detection_work);
4583 int rc;
4584 u8 stat;
4585 bool legacy, rp_high;
4586
4587 mutex_lock(&chg->lock);
4588 chg->typec_en_dis_active = 1;
4589 smblib_dbg(chg, PR_MISC, "running legacy unknown workaround\n");
4590 rc = smblib_masked_write(chg,
4591 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4592 TYPEC_DISABLE_CMD_BIT,
4593 TYPEC_DISABLE_CMD_BIT);
4594 if (rc < 0)
4595 smblib_err(chg, "Couldn't disable type-c rc=%d\n", rc);
4596
4597 /* wait for the adapter to turn off VBUS */
4598 msleep(500);
4599
4600 rc = smblib_masked_write(chg,
4601 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4602 TYPEC_DISABLE_CMD_BIT, 0);
4603 if (rc < 0)
4604 smblib_err(chg, "Couldn't enable type-c rc=%d\n", rc);
4605
4606 /* wait for type-c detection to complete */
4607 msleep(100);
4608
4609 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat);
4610 if (rc < 0) {
4611 smblib_err(chg, "Couldn't read typec stat5 rc = %d\n", rc);
4612 goto unlock;
4613 }
4614
4615 chg->typec_legacy_valid = true;
4616 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
4617 legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT;
Nicholas Troaste1932e42017-04-12 12:38:18 -07004618 rp_high = chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004619 if (!legacy || !rp_high)
4620 vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
4621 false, 0);
4622
4623unlock:
4624 chg->typec_en_dis_active = 0;
Nicholas Troast6439e172017-06-02 14:45:39 -07004625 smblib_usb_typec_change(chg);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004626 mutex_unlock(&chg->lock);
4627}
4628
Harry Yangba874ce2016-08-19 14:17:01 -07004629static int smblib_create_votables(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07004630{
4631 int rc = 0;
4632
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304633 chg->fcc_votable = find_votable("FCC");
Harry Yang0c35ff62017-04-06 00:02:30 -07004634 if (chg->fcc_votable == NULL) {
4635 rc = -EINVAL;
4636 smblib_err(chg, "Couldn't find FCC votable rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304637 return rc;
4638 }
4639
4640 chg->fv_votable = find_votable("FV");
Harry Yang0c35ff62017-04-06 00:02:30 -07004641 if (chg->fv_votable == NULL) {
4642 rc = -EINVAL;
4643 smblib_err(chg, "Couldn't find FV votable rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304644 return rc;
4645 }
4646
Ashay Jaiswalae1586d2017-03-22 23:18:51 +05304647 chg->usb_icl_votable = find_votable("USB_ICL");
4648 if (!chg->usb_icl_votable) {
Harry Yang0c35ff62017-04-06 00:02:30 -07004649 rc = -EINVAL;
4650 smblib_err(chg, "Couldn't find USB_ICL votable rc=%d\n", rc);
Ashay Jaiswalae1586d2017-03-22 23:18:51 +05304651 return rc;
4652 }
4653
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304654 chg->pl_disable_votable = find_votable("PL_DISABLE");
Harry Yang0c35ff62017-04-06 00:02:30 -07004655 if (chg->pl_disable_votable == NULL) {
4656 rc = -EINVAL;
4657 smblib_err(chg, "Couldn't find votable PL_DISABLE rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304658 return rc;
4659 }
Abhijeet Dharmapurikar38ef1422017-05-18 15:37:56 -07004660
4661 chg->pl_enable_votable_indirect = find_votable("PL_ENABLE_INDIRECT");
4662 if (chg->pl_enable_votable_indirect == NULL) {
4663 rc = -EINVAL;
4664 smblib_err(chg,
4665 "Couldn't find votable PL_ENABLE_INDIRECT rc=%d\n",
4666 rc);
4667 return rc;
4668 }
4669
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304670 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304671
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004672 chg->dc_suspend_votable = create_votable("DC_SUSPEND", VOTE_SET_ANY,
4673 smblib_dc_suspend_vote_callback,
4674 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07004675 if (IS_ERR(chg->dc_suspend_votable)) {
4676 rc = PTR_ERR(chg->dc_suspend_votable);
4677 return rc;
4678 }
4679
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004680 chg->dc_icl_votable = create_votable("DC_ICL", VOTE_MIN,
4681 smblib_dc_icl_vote_callback,
4682 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07004683 if (IS_ERR(chg->dc_icl_votable)) {
4684 rc = PTR_ERR(chg->dc_icl_votable);
4685 return rc;
4686 }
4687
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07004688 chg->pd_disallowed_votable_indirect
4689 = create_votable("PD_DISALLOWED_INDIRECT", VOTE_SET_ANY,
4690 smblib_pd_disallowed_votable_indirect_callback, chg);
4691 if (IS_ERR(chg->pd_disallowed_votable_indirect)) {
4692 rc = PTR_ERR(chg->pd_disallowed_votable_indirect);
4693 return rc;
4694 }
4695
4696 chg->pd_allowed_votable = create_votable("PD_ALLOWED",
4697 VOTE_SET_ANY, NULL, NULL);
Nicholas Troast34db5032016-03-28 12:26:44 -07004698 if (IS_ERR(chg->pd_allowed_votable)) {
4699 rc = PTR_ERR(chg->pd_allowed_votable);
4700 return rc;
4701 }
4702
Harry Yang223c6282016-06-14 15:48:36 -07004703 chg->awake_votable = create_votable("AWAKE", VOTE_SET_ANY,
4704 smblib_awake_vote_callback,
4705 chg);
4706 if (IS_ERR(chg->awake_votable)) {
4707 rc = PTR_ERR(chg->awake_votable);
4708 return rc;
4709 }
4710
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07004711 chg->chg_disable_votable = create_votable("CHG_DISABLE", VOTE_SET_ANY,
4712 smblib_chg_disable_vote_callback,
4713 chg);
4714 if (IS_ERR(chg->chg_disable_votable)) {
4715 rc = PTR_ERR(chg->chg_disable_votable);
4716 return rc;
4717 }
4718
Harry Yangaba1f5f2016-09-28 10:47:29 -07004719
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05304720 chg->hvdcp_disable_votable_indirect = create_votable(
4721 "HVDCP_DISABLE_INDIRECT",
4722 VOTE_SET_ANY,
4723 smblib_hvdcp_disable_indirect_vote_callback,
4724 chg);
4725 if (IS_ERR(chg->hvdcp_disable_votable_indirect)) {
4726 rc = PTR_ERR(chg->hvdcp_disable_votable_indirect);
4727 return rc;
4728 }
4729
4730 chg->hvdcp_enable_votable = create_votable("HVDCP_ENABLE",
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07004731 VOTE_SET_ANY,
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05304732 smblib_hvdcp_enable_vote_callback,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07004733 chg);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05304734 if (IS_ERR(chg->hvdcp_enable_votable)) {
4735 rc = PTR_ERR(chg->hvdcp_enable_votable);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07004736 return rc;
4737 }
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07004738
4739 chg->apsd_disable_votable = create_votable("APSD_DISABLE",
4740 VOTE_SET_ANY,
4741 smblib_apsd_disable_vote_callback,
4742 chg);
4743 if (IS_ERR(chg->apsd_disable_votable)) {
4744 rc = PTR_ERR(chg->apsd_disable_votable);
4745 return rc;
4746 }
4747
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05304748 chg->hvdcp_hw_inov_dis_votable = create_votable("HVDCP_HW_INOV_DIS",
4749 VOTE_SET_ANY,
4750 smblib_hvdcp_hw_inov_dis_vote_callback,
4751 chg);
4752 if (IS_ERR(chg->hvdcp_hw_inov_dis_votable)) {
4753 rc = PTR_ERR(chg->hvdcp_hw_inov_dis_votable);
4754 return rc;
4755 }
4756
Harry Yang4bf7d962017-03-13 16:51:43 -07004757 chg->usb_irq_enable_votable = create_votable("USB_IRQ_DISABLE",
4758 VOTE_SET_ANY,
4759 smblib_usb_irq_enable_vote_callback,
4760 chg);
4761 if (IS_ERR(chg->usb_irq_enable_votable)) {
4762 rc = PTR_ERR(chg->usb_irq_enable_votable);
4763 return rc;
4764 }
4765
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004766 chg->typec_irq_disable_votable = create_votable("TYPEC_IRQ_DISABLE",
4767 VOTE_SET_ANY,
4768 smblib_typec_irq_disable_vote_callback,
4769 chg);
4770 if (IS_ERR(chg->typec_irq_disable_votable)) {
4771 rc = PTR_ERR(chg->typec_irq_disable_votable);
4772 return rc;
4773 }
4774
Nicholas Troast320839e2016-06-03 10:18:00 -07004775 return rc;
4776}
4777
Harry Yangba874ce2016-08-19 14:17:01 -07004778static void smblib_destroy_votables(struct smb_charger *chg)
4779{
Harry Yangba874ce2016-08-19 14:17:01 -07004780 if (chg->dc_suspend_votable)
4781 destroy_votable(chg->dc_suspend_votable);
Harry Yangba874ce2016-08-19 14:17:01 -07004782 if (chg->usb_icl_votable)
4783 destroy_votable(chg->usb_icl_votable);
4784 if (chg->dc_icl_votable)
4785 destroy_votable(chg->dc_icl_votable);
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07004786 if (chg->pd_disallowed_votable_indirect)
4787 destroy_votable(chg->pd_disallowed_votable_indirect);
Harry Yangba874ce2016-08-19 14:17:01 -07004788 if (chg->pd_allowed_votable)
4789 destroy_votable(chg->pd_allowed_votable);
4790 if (chg->awake_votable)
4791 destroy_votable(chg->awake_votable);
Harry Yangaba1f5f2016-09-28 10:47:29 -07004792 if (chg->chg_disable_votable)
4793 destroy_votable(chg->chg_disable_votable);
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07004794 if (chg->apsd_disable_votable)
4795 destroy_votable(chg->apsd_disable_votable);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05304796 if (chg->hvdcp_hw_inov_dis_votable)
4797 destroy_votable(chg->hvdcp_hw_inov_dis_votable);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004798 if (chg->typec_irq_disable_votable)
4799 destroy_votable(chg->typec_irq_disable_votable);
Harry Yangba874ce2016-08-19 14:17:01 -07004800}
4801
4802static void smblib_iio_deinit(struct smb_charger *chg)
4803{
4804 if (!IS_ERR_OR_NULL(chg->iio.temp_chan))
4805 iio_channel_release(chg->iio.temp_chan);
4806 if (!IS_ERR_OR_NULL(chg->iio.temp_max_chan))
4807 iio_channel_release(chg->iio.temp_max_chan);
4808 if (!IS_ERR_OR_NULL(chg->iio.usbin_i_chan))
4809 iio_channel_release(chg->iio.usbin_i_chan);
4810 if (!IS_ERR_OR_NULL(chg->iio.usbin_v_chan))
4811 iio_channel_release(chg->iio.usbin_v_chan);
Nicholas Troast7dbcad22016-10-05 13:30:18 -07004812 if (!IS_ERR_OR_NULL(chg->iio.batt_i_chan))
4813 iio_channel_release(chg->iio.batt_i_chan);
Harry Yangba874ce2016-08-19 14:17:01 -07004814}
4815
Nicholas Troast320839e2016-06-03 10:18:00 -07004816int smblib_init(struct smb_charger *chg)
4817{
4818 int rc = 0;
4819
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004820 mutex_init(&chg->lock);
Nicholas Troast320839e2016-06-03 10:18:00 -07004821 mutex_init(&chg->write_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004822 mutex_init(&chg->otg_oc_lock);
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07004823 mutex_init(&chg->vconn_oc_lock);
Harry Yangfe913842016-08-10 12:27:28 -07004824 INIT_WORK(&chg->bms_update_work, bms_update_work);
Harry Yang755a34b2016-11-01 01:18:51 -07004825 INIT_WORK(&chg->rdstd_cc2_detach_work, rdstd_cc2_detach_work);
Nicholas Troast320839e2016-06-03 10:18:00 -07004826 INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004827 INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004828 INIT_WORK(&chg->otg_oc_work, smblib_otg_oc_work);
4829 INIT_WORK(&chg->vconn_oc_work, smblib_vconn_oc_work);
4830 INIT_DELAYED_WORK(&chg->otg_ss_done_work, smblib_otg_ss_done_work);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05304831 INIT_DELAYED_WORK(&chg->icl_change_work, smblib_icl_change_work);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304832 INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004833 INIT_WORK(&chg->legacy_detection_work, smblib_legacy_detection_work);
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05304834 INIT_DELAYED_WORK(&chg->uusb_otg_work, smblib_uusb_otg_work);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05304835 INIT_DELAYED_WORK(&chg->bb_removal_work, smblib_bb_removal_work);
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07004836 chg->fake_capacity = -EINVAL;
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07004837 chg->fake_input_current_limited = -EINVAL;
Harry Yang589dd422017-07-28 18:41:42 -07004838 chg->fake_batt_status = -EINVAL;
Nicholas Troast320839e2016-06-03 10:18:00 -07004839
4840 switch (chg->mode) {
4841 case PARALLEL_MASTER:
Harry Yang0c35ff62017-04-06 00:02:30 -07004842 rc = qcom_batt_init();
4843 if (rc < 0) {
4844 smblib_err(chg, "Couldn't init qcom_batt_init rc=%d\n",
4845 rc);
4846 return rc;
4847 }
4848
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +05304849 rc = qcom_step_chg_init(chg->step_chg_enabled,
4850 chg->sw_jeita_enabled);
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05304851 if (rc < 0) {
4852 smblib_err(chg, "Couldn't init qcom_step_chg_init rc=%d\n",
4853 rc);
4854 return rc;
4855 }
4856
Nicholas Troast320839e2016-06-03 10:18:00 -07004857 rc = smblib_create_votables(chg);
4858 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004859 smblib_err(chg, "Couldn't create votables rc=%d\n",
Nicholas Troast320839e2016-06-03 10:18:00 -07004860 rc);
Harry Yang58a9e7a2016-06-23 14:54:43 -07004861 return rc;
Nicholas Troast320839e2016-06-03 10:18:00 -07004862 }
Harry Yang58a9e7a2016-06-23 14:54:43 -07004863
Harry Yang5e1a5222016-07-26 15:16:04 -07004864 rc = smblib_register_notifier(chg);
4865 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004866 smblib_err(chg,
Harry Yang5e1a5222016-07-26 15:16:04 -07004867 "Couldn't register notifier rc=%d\n", rc);
4868 return rc;
Harry Yang58a9e7a2016-06-23 14:54:43 -07004869 }
4870
Harry Yang995b7422016-08-29 16:06:50 -07004871 chg->bms_psy = power_supply_get_by_name("bms");
Ashay Jaiswal8afedfc2017-02-03 11:18:22 +05304872 chg->pl.psy = power_supply_get_by_name("parallel");
Nicholas Troast320839e2016-06-03 10:18:00 -07004873 break;
4874 case PARALLEL_SLAVE:
4875 break;
4876 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004877 smblib_err(chg, "Unsupported mode %d\n", chg->mode);
Nicholas Troast320839e2016-06-03 10:18:00 -07004878 return -EINVAL;
4879 }
4880
4881 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07004882}
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004883
4884int smblib_deinit(struct smb_charger *chg)
4885{
Harry Yangba874ce2016-08-19 14:17:01 -07004886 switch (chg->mode) {
4887 case PARALLEL_MASTER:
Harry Yang0c35ff62017-04-06 00:02:30 -07004888 cancel_work_sync(&chg->bms_update_work);
4889 cancel_work_sync(&chg->rdstd_cc2_detach_work);
4890 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
Harry Yang0c35ff62017-04-06 00:02:30 -07004891 cancel_delayed_work_sync(&chg->clear_hdc_work);
4892 cancel_work_sync(&chg->otg_oc_work);
4893 cancel_work_sync(&chg->vconn_oc_work);
4894 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4895 cancel_delayed_work_sync(&chg->icl_change_work);
4896 cancel_delayed_work_sync(&chg->pl_enable_work);
4897 cancel_work_sync(&chg->legacy_detection_work);
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05304898 cancel_delayed_work_sync(&chg->uusb_otg_work);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05304899 cancel_delayed_work_sync(&chg->bb_removal_work);
Harry Yangba874ce2016-08-19 14:17:01 -07004900 power_supply_unreg_notifier(&chg->nb);
4901 smblib_destroy_votables(chg);
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05304902 qcom_step_chg_deinit();
Harry Yang0c35ff62017-04-06 00:02:30 -07004903 qcom_batt_deinit();
Harry Yangba874ce2016-08-19 14:17:01 -07004904 break;
4905 case PARALLEL_SLAVE:
4906 break;
4907 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004908 smblib_err(chg, "Unsupported mode %d\n", chg->mode);
Harry Yangba874ce2016-08-19 14:17:01 -07004909 return -EINVAL;
4910 }
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004911
Harry Yangba874ce2016-08-19 14:17:01 -07004912 smblib_iio_deinit(chg);
Harry Yang5e1a5222016-07-26 15:16:04 -07004913
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004914 return 0;
4915}