blob: 1e5e1369f2f19d665fbe512cc1b12aa9f045d8be [file] [log] [blame]
Harry Yang3b113a52016-12-08 12:37:40 -08001/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
Nicholas Troast34db5032016-03-28 12:26:44 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/device.h>
14#include <linux/regmap.h>
Harry Yang360bd532016-09-26 11:03:22 -070015#include <linux/delay.h>
Harry Yangba874ce2016-08-19 14:17:01 -070016#include <linux/iio/consumer.h>
Nicholas Troast34db5032016-03-28 12:26:44 -070017#include <linux/power_supply.h>
18#include <linux/regulator/driver.h>
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -080019#include <linux/qpnp/qpnp-revid.h>
Nicholas Troast34db5032016-03-28 12:26:44 -070020#include <linux/irq.h>
Harry Yang0c35ff62017-04-06 00:02:30 -070021#include <linux/pmic-voter.h>
Nicholas Troast34db5032016-03-28 12:26:44 -070022#include "smb-lib.h"
23#include "smb-reg.h"
Harry Yang0c35ff62017-04-06 00:02:30 -070024#include "battery.h"
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +053025#include "step-chg-jeita.h"
Nicholas Troast47ae4612016-08-03 09:49:36 -070026#include "storm-watch.h"
Nicholas Troast34db5032016-03-28 12:26:44 -070027
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -070028#define smblib_err(chg, fmt, ...) \
29 pr_err("%s: %s: " fmt, chg->name, \
30 __func__, ##__VA_ARGS__) \
31
Nicholas Troast34db5032016-03-28 12:26:44 -070032#define smblib_dbg(chg, reason, fmt, ...) \
33 do { \
34 if (*chg->debug_mask & (reason)) \
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -070035 pr_info("%s: %s: " fmt, chg->name, \
36 __func__, ##__VA_ARGS__); \
Nicholas Troast34db5032016-03-28 12:26:44 -070037 else \
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -070038 pr_debug("%s: %s: " fmt, chg->name, \
39 __func__, ##__VA_ARGS__); \
Nicholas Troast34db5032016-03-28 12:26:44 -070040 } while (0)
41
42static bool is_secure(struct smb_charger *chg, int addr)
43{
Anirudh Ghayal4da3df92017-01-25 18:55:57 +053044 if (addr == SHIP_MODE_REG || addr == FREQ_CLK_DIV_REG)
Fenglin Wuedd70792016-11-22 13:16:19 +080045 return true;
Harry Yang47bd3852016-10-17 10:37:12 -070046 /* assume everything above 0xA0 is secure */
47 return (bool)((addr & 0xFF) >= 0xA0);
Nicholas Troast34db5032016-03-28 12:26:44 -070048}
49
50int smblib_read(struct smb_charger *chg, u16 addr, u8 *val)
51{
52 unsigned int temp;
53 int rc = 0;
54
55 rc = regmap_read(chg->regmap, addr, &temp);
56 if (rc >= 0)
57 *val = (u8)temp;
58
59 return rc;
60}
61
Ashay Jaiswal6d308da2017-02-18 09:59:23 +053062int smblib_multibyte_read(struct smb_charger *chg, u16 addr, u8 *val,
63 int count)
64{
65 return regmap_bulk_read(chg->regmap, addr, val, count);
66}
67
Nicholas Troast34db5032016-03-28 12:26:44 -070068int smblib_masked_write(struct smb_charger *chg, u16 addr, u8 mask, u8 val)
69{
Nicholas Troast34db5032016-03-28 12:26:44 -070070 int rc = 0;
71
Harry Yangbacd2222016-05-11 16:43:51 -070072 mutex_lock(&chg->write_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -070073 if (is_secure(chg, addr)) {
74 rc = regmap_write(chg->regmap, (addr & 0xFF00) | 0xD0, 0xA5);
75 if (rc < 0)
76 goto unlock;
77 }
78
79 rc = regmap_update_bits(chg->regmap, addr, mask, val);
80
81unlock:
Harry Yangbacd2222016-05-11 16:43:51 -070082 mutex_unlock(&chg->write_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -070083 return rc;
84}
85
86int smblib_write(struct smb_charger *chg, u16 addr, u8 val)
87{
Nicholas Troast34db5032016-03-28 12:26:44 -070088 int rc = 0;
89
Harry Yangbacd2222016-05-11 16:43:51 -070090 mutex_lock(&chg->write_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -070091
92 if (is_secure(chg, addr)) {
93 rc = regmap_write(chg->regmap, (addr & ~(0xFF)) | 0xD0, 0xA5);
94 if (rc < 0)
95 goto unlock;
96 }
97
98 rc = regmap_write(chg->regmap, addr, val);
99
100unlock:
Harry Yangbacd2222016-05-11 16:43:51 -0700101 mutex_unlock(&chg->write_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -0700102 return rc;
103}
104
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -0700105static int smblib_get_jeita_cc_delta(struct smb_charger *chg, int *cc_delta_ua)
106{
107 int rc, cc_minus_ua;
108 u8 stat;
Harry Yangfe913842016-08-10 12:27:28 -0700109
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -0700110 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat);
111 if (rc < 0) {
112 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
113 rc);
114 return rc;
115 }
116
117 if (!(stat & BAT_TEMP_STATUS_SOFT_LIMIT_MASK)) {
118 *cc_delta_ua = 0;
119 return 0;
120 }
121
122 rc = smblib_get_charge_param(chg, &chg->param.jeita_cc_comp,
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +0530123 &cc_minus_ua);
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -0700124 if (rc < 0) {
125 smblib_err(chg, "Couldn't get jeita cc minus rc=%d\n", rc);
126 return rc;
127 }
128
129 *cc_delta_ua = -cc_minus_ua;
130 return 0;
131}
132
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800133int smblib_icl_override(struct smb_charger *chg, bool override)
134{
135 int rc;
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800136
Nicholas Troast11af51b2017-03-15 10:45:28 -0700137 rc = smblib_masked_write(chg, USBIN_LOAD_CFG_REG,
138 ICL_OVERRIDE_AFTER_APSD_BIT,
139 override ? ICL_OVERRIDE_AFTER_APSD_BIT : 0);
140 if (rc < 0)
141 smblib_err(chg, "Couldn't override ICL rc=%d\n", rc);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -0800142
Nicholas Troast11af51b2017-03-15 10:45:28 -0700143 return rc;
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800144}
145
Harry Yang166b15d2017-08-28 13:00:40 -0700146int smblib_stat_sw_override_cfg(struct smb_charger *chg, bool override)
147{
148 int rc;
149
150 /* override = 1, SW STAT override; override = 0, HW auto mode */
151 rc = smblib_masked_write(chg, STAT_CFG_REG,
152 STAT_SW_OVERRIDE_CFG_BIT,
153 override ? STAT_SW_OVERRIDE_CFG_BIT : 0);
154 if (rc < 0) {
155 dev_err(chg->dev, "Couldn't configure SW STAT override rc=%d\n",
156 rc);
157 return rc;
158 }
159
160 return rc;
161}
162
Nicholas Troast34db5032016-03-28 12:26:44 -0700163/********************
164 * REGISTER GETTERS *
165 ********************/
166
Nicholas Troast4c310492016-05-12 17:56:35 -0700167int smblib_get_charge_param(struct smb_charger *chg,
168 struct smb_chg_param *param, int *val_u)
169{
170 int rc = 0;
171 u8 val_raw;
172
173 rc = smblib_read(chg, param->reg, &val_raw);
174 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700175 smblib_err(chg, "%s: Couldn't read from 0x%04x rc=%d\n",
Nicholas Troast4c310492016-05-12 17:56:35 -0700176 param->name, param->reg, rc);
177 return rc;
178 }
179
Harry Yangf8b41252016-08-10 14:21:10 -0700180 if (param->get_proc)
181 *val_u = param->get_proc(param, val_raw);
182 else
183 *val_u = val_raw * param->step_u + param->min_u;
Nicholas Troast4c310492016-05-12 17:56:35 -0700184 smblib_dbg(chg, PR_REGISTER, "%s = %d (0x%02x)\n",
185 param->name, *val_u, val_raw);
186
187 return rc;
188}
189
190int smblib_get_usb_suspend(struct smb_charger *chg, int *suspend)
191{
192 int rc = 0;
193 u8 temp;
194
195 rc = smblib_read(chg, USBIN_CMD_IL_REG, &temp);
196 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700197 smblib_err(chg, "Couldn't read USBIN_CMD_IL rc=%d\n", rc);
Nicholas Troast4c310492016-05-12 17:56:35 -0700198 return rc;
199 }
200 *suspend = temp & USBIN_SUSPEND_BIT;
201
202 return rc;
203}
204
Nicholas Troast34db5032016-03-28 12:26:44 -0700205struct apsd_result {
206 const char * const name;
207 const u8 bit;
208 const enum power_supply_type pst;
209};
210
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700211enum {
212 UNKNOWN,
213 SDP,
214 CDP,
215 DCP,
216 OCP,
217 FLOAT,
218 HVDCP2,
219 HVDCP3,
220 MAX_TYPES
221};
222
Nicholas Troast34db5032016-03-28 12:26:44 -0700223static const struct apsd_result const smblib_apsd_results[] = {
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700224 [UNKNOWN] = {
225 .name = "UNKNOWN",
226 .bit = 0,
227 .pst = POWER_SUPPLY_TYPE_UNKNOWN
228 },
229 [SDP] = {
230 .name = "SDP",
231 .bit = SDP_CHARGER_BIT,
232 .pst = POWER_SUPPLY_TYPE_USB
233 },
234 [CDP] = {
235 .name = "CDP",
236 .bit = CDP_CHARGER_BIT,
237 .pst = POWER_SUPPLY_TYPE_USB_CDP
238 },
239 [DCP] = {
240 .name = "DCP",
241 .bit = DCP_CHARGER_BIT,
242 .pst = POWER_SUPPLY_TYPE_USB_DCP
243 },
244 [OCP] = {
245 .name = "OCP",
246 .bit = OCP_CHARGER_BIT,
247 .pst = POWER_SUPPLY_TYPE_USB_DCP
248 },
249 [FLOAT] = {
250 .name = "FLOAT",
251 .bit = FLOAT_CHARGER_BIT,
Ashay Jaiswalb9b2d2f2017-06-21 12:08:38 +0530252 .pst = POWER_SUPPLY_TYPE_USB_FLOAT
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700253 },
254 [HVDCP2] = {
255 .name = "HVDCP2",
256 .bit = DCP_CHARGER_BIT | QC_2P0_BIT,
257 .pst = POWER_SUPPLY_TYPE_USB_HVDCP
258 },
259 [HVDCP3] = {
260 .name = "HVDCP3",
261 .bit = DCP_CHARGER_BIT | QC_3P0_BIT,
262 .pst = POWER_SUPPLY_TYPE_USB_HVDCP_3,
263 },
Nicholas Troast34db5032016-03-28 12:26:44 -0700264};
265
266static const struct apsd_result *smblib_get_apsd_result(struct smb_charger *chg)
267{
268 int rc, i;
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700269 u8 apsd_stat, stat;
270 const struct apsd_result *result = &smblib_apsd_results[UNKNOWN];
Nicholas Troast34db5032016-03-28 12:26:44 -0700271
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700272 rc = smblib_read(chg, APSD_STATUS_REG, &apsd_stat);
Nicholas Troast34db5032016-03-28 12:26:44 -0700273 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700274 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700275 return result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700276 }
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700277 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", apsd_stat);
Nicholas Troast34db5032016-03-28 12:26:44 -0700278
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700279 if (!(apsd_stat & APSD_DTC_STATUS_DONE_BIT))
280 return result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700281
282 rc = smblib_read(chg, APSD_RESULT_STATUS_REG, &stat);
283 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700284 smblib_err(chg, "Couldn't read APSD_RESULT_STATUS rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700285 rc);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700286 return result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700287 }
288 stat &= APSD_RESULT_STATUS_MASK;
289
290 for (i = 0; i < ARRAY_SIZE(smblib_apsd_results); i++) {
291 if (smblib_apsd_results[i].bit == stat)
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700292 result = &smblib_apsd_results[i];
Nicholas Troast34db5032016-03-28 12:26:44 -0700293 }
294
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700295 if (apsd_stat & QC_CHARGER_BIT) {
296 /* since its a qc_charger, either return HVDCP3 or HVDCP2 */
297 if (result != &smblib_apsd_results[HVDCP3])
298 result = &smblib_apsd_results[HVDCP2];
299 }
300
301 return result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700302}
303
Nicholas Troast34db5032016-03-28 12:26:44 -0700304/********************
305 * REGISTER SETTERS *
306 ********************/
307
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530308static int chg_freq_list[] = {
309 9600, 9600, 6400, 4800, 3800, 3200, 2700, 2400, 2100, 1900, 1700,
310 1600, 1500, 1400, 1300, 1200,
311};
312
313int smblib_set_chg_freq(struct smb_chg_param *param,
314 int val_u, u8 *val_raw)
315{
316 u8 i;
317
318 if (val_u > param->max_u || val_u < param->min_u)
319 return -EINVAL;
320
321 /* Charger FSW is the configured freqency / 2 */
322 val_u *= 2;
323 for (i = 0; i < ARRAY_SIZE(chg_freq_list); i++) {
324 if (chg_freq_list[i] == val_u)
325 break;
326 }
327 if (i == ARRAY_SIZE(chg_freq_list)) {
328 pr_err("Invalid frequency %d Hz\n", val_u / 2);
329 return -EINVAL;
330 }
331
332 *val_raw = i;
333
334 return 0;
335}
336
337static int smblib_set_opt_freq_buck(struct smb_charger *chg, int fsw_khz)
338{
339 union power_supply_propval pval = {0, };
340 int rc = 0;
341
342 rc = smblib_set_charge_param(chg, &chg->param.freq_buck, fsw_khz);
343 if (rc < 0)
344 dev_err(chg->dev, "Error in setting freq_buck rc=%d\n", rc);
345
346 if (chg->mode == PARALLEL_MASTER && chg->pl.psy) {
347 pval.intval = fsw_khz;
Abhijeet Dharmapurikare9fd08d2017-02-27 11:05:28 -0800348 /*
349 * Some parallel charging implementations may not have
350 * PROP_BUCK_FREQ property - they could be running
351 * with a fixed frequency
352 */
353 power_supply_set_property(chg->pl.psy,
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530354 POWER_SUPPLY_PROP_BUCK_FREQ, &pval);
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530355 }
356
357 return rc;
358}
359
Nicholas Troast4c310492016-05-12 17:56:35 -0700360int smblib_set_charge_param(struct smb_charger *chg,
361 struct smb_chg_param *param, int val_u)
Nicholas Troast34db5032016-03-28 12:26:44 -0700362{
363 int rc = 0;
364 u8 val_raw;
365
Harry Yangf8b41252016-08-10 14:21:10 -0700366 if (param->set_proc) {
367 rc = param->set_proc(param, val_u, &val_raw);
368 if (rc < 0)
369 return -EINVAL;
370 } else {
371 if (val_u > param->max_u || val_u < param->min_u) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700372 smblib_err(chg, "%s: %d is out of range [%d, %d]\n",
Harry Yangf8b41252016-08-10 14:21:10 -0700373 param->name, val_u, param->min_u, param->max_u);
374 return -EINVAL;
375 }
376
377 val_raw = (val_u - param->min_u) / param->step_u;
Nicholas Troast34db5032016-03-28 12:26:44 -0700378 }
379
Nicholas Troast34db5032016-03-28 12:26:44 -0700380 rc = smblib_write(chg, param->reg, val_raw);
381 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700382 smblib_err(chg, "%s: Couldn't write 0x%02x to 0x%04x rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700383 param->name, val_raw, param->reg, rc);
384 return rc;
385 }
386
387 smblib_dbg(chg, PR_REGISTER, "%s = %d (0x%02x)\n",
388 param->name, val_u, val_raw);
389
390 return rc;
391}
392
Nicholas Troast4c310492016-05-12 17:56:35 -0700393int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend)
Nicholas Troast34db5032016-03-28 12:26:44 -0700394{
395 int rc = 0;
Abhijeet Dharmapurikar109802f712017-07-07 18:30:54 -0700396 int irq = chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq;
397
398 if (suspend && irq) {
399 if (chg->usb_icl_change_irq_enabled) {
400 disable_irq_nosync(irq);
401 chg->usb_icl_change_irq_enabled = false;
402 }
403 }
Nicholas Troast34db5032016-03-28 12:26:44 -0700404
405 rc = smblib_masked_write(chg, USBIN_CMD_IL_REG, USBIN_SUSPEND_BIT,
406 suspend ? USBIN_SUSPEND_BIT : 0);
407 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700408 smblib_err(chg, "Couldn't write %s to USBIN_SUSPEND_BIT rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700409 suspend ? "suspend" : "resume", rc);
410
Abhijeet Dharmapurikar109802f712017-07-07 18:30:54 -0700411 if (!suspend && irq) {
412 if (!chg->usb_icl_change_irq_enabled) {
413 enable_irq(irq);
414 chg->usb_icl_change_irq_enabled = true;
415 }
416 }
417
Nicholas Troast34db5032016-03-28 12:26:44 -0700418 return rc;
419}
420
Nicholas Troast4c310492016-05-12 17:56:35 -0700421int smblib_set_dc_suspend(struct smb_charger *chg, bool suspend)
Nicholas Troast34db5032016-03-28 12:26:44 -0700422{
423 int rc = 0;
424
425 rc = smblib_masked_write(chg, DCIN_CMD_IL_REG, DCIN_SUSPEND_BIT,
426 suspend ? DCIN_SUSPEND_BIT : 0);
427 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700428 smblib_err(chg, "Couldn't write %s to DCIN_SUSPEND_BIT rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700429 suspend ? "suspend" : "resume", rc);
430
431 return rc;
432}
433
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530434static int smblib_set_adapter_allowance(struct smb_charger *chg,
435 u8 allowed_voltage)
436{
437 int rc = 0;
438
Nicholas Troast7f55c922017-07-25 13:18:03 -0700439 /* PM660 only support max. 9V */
440 if (chg->smb_version == PM660_SUBTYPE) {
441 switch (allowed_voltage) {
442 case USBIN_ADAPTER_ALLOW_12V:
443 case USBIN_ADAPTER_ALLOW_9V_TO_12V:
444 allowed_voltage = USBIN_ADAPTER_ALLOW_9V;
445 break;
446 case USBIN_ADAPTER_ALLOW_5V_OR_12V:
447 case USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V:
448 allowed_voltage = USBIN_ADAPTER_ALLOW_5V_OR_9V;
449 break;
450 case USBIN_ADAPTER_ALLOW_5V_TO_12V:
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530451 allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_9V;
Nicholas Troast7f55c922017-07-25 13:18:03 -0700452 break;
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530453 }
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530454 }
455
456 rc = smblib_write(chg, USBIN_ADAPTER_ALLOW_CFG_REG, allowed_voltage);
457 if (rc < 0) {
458 smblib_err(chg, "Couldn't write 0x%02x to USBIN_ADAPTER_ALLOW_CFG rc=%d\n",
459 allowed_voltage, rc);
460 return rc;
461 }
462
463 return rc;
464}
465
Nicholas Troast34db5032016-03-28 12:26:44 -0700466#define MICRO_5V 5000000
467#define MICRO_9V 9000000
468#define MICRO_12V 12000000
469static int smblib_set_usb_pd_allowed_voltage(struct smb_charger *chg,
470 int min_allowed_uv, int max_allowed_uv)
471{
472 int rc;
473 u8 allowed_voltage;
474
475 if (min_allowed_uv == MICRO_5V && max_allowed_uv == MICRO_5V) {
476 allowed_voltage = USBIN_ADAPTER_ALLOW_5V;
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530477 smblib_set_opt_freq_buck(chg, chg->chg_freq.freq_5V);
Nicholas Troast34db5032016-03-28 12:26:44 -0700478 } else if (min_allowed_uv == MICRO_9V && max_allowed_uv == MICRO_9V) {
479 allowed_voltage = USBIN_ADAPTER_ALLOW_9V;
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530480 smblib_set_opt_freq_buck(chg, chg->chg_freq.freq_9V);
Nicholas Troast34db5032016-03-28 12:26:44 -0700481 } else if (min_allowed_uv == MICRO_12V && max_allowed_uv == MICRO_12V) {
482 allowed_voltage = USBIN_ADAPTER_ALLOW_12V;
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530483 smblib_set_opt_freq_buck(chg, chg->chg_freq.freq_12V);
Nicholas Troast34db5032016-03-28 12:26:44 -0700484 } else if (min_allowed_uv < MICRO_9V && max_allowed_uv <= MICRO_9V) {
485 allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_9V;
486 } else if (min_allowed_uv < MICRO_9V && max_allowed_uv <= MICRO_12V) {
487 allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_12V;
488 } else if (min_allowed_uv < MICRO_12V && max_allowed_uv <= MICRO_12V) {
489 allowed_voltage = USBIN_ADAPTER_ALLOW_9V_TO_12V;
490 } else {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700491 smblib_err(chg, "invalid allowed voltage [%d, %d]\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700492 min_allowed_uv, max_allowed_uv);
493 return -EINVAL;
494 }
495
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530496 rc = smblib_set_adapter_allowance(chg, allowed_voltage);
Nicholas Troast34db5032016-03-28 12:26:44 -0700497 if (rc < 0) {
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530498 smblib_err(chg, "Couldn't configure adapter allowance rc=%d\n",
499 rc);
Nicholas Troast34db5032016-03-28 12:26:44 -0700500 return rc;
501 }
502
503 return rc;
504}
505
506/********************
507 * HELPER FUNCTIONS *
508 ********************/
Ashay Jaiswal13a1b812017-07-17 14:49:05 +0530509static int smblib_request_dpdm(struct smb_charger *chg, bool enable)
510{
511 int rc = 0;
512
513 /* fetch the DPDM regulator */
514 if (!chg->dpdm_reg && of_get_property(chg->dev->of_node,
515 "dpdm-supply", NULL)) {
516 chg->dpdm_reg = devm_regulator_get(chg->dev, "dpdm");
517 if (IS_ERR(chg->dpdm_reg)) {
518 rc = PTR_ERR(chg->dpdm_reg);
519 smblib_err(chg, "Couldn't get dpdm regulator rc=%d\n",
520 rc);
521 chg->dpdm_reg = NULL;
522 return rc;
523 }
524 }
525
526 if (enable) {
527 if (chg->dpdm_reg && !regulator_is_enabled(chg->dpdm_reg)) {
528 smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n");
529 rc = regulator_enable(chg->dpdm_reg);
530 if (rc < 0)
531 smblib_err(chg,
532 "Couldn't enable dpdm regulator rc=%d\n",
533 rc);
534 }
535 } else {
536 if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) {
537 smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n");
538 rc = regulator_disable(chg->dpdm_reg);
539 if (rc < 0)
540 smblib_err(chg,
541 "Couldn't disable dpdm regulator rc=%d\n",
542 rc);
543 }
544 }
545
546 return rc;
547}
Nicholas Troast34db5032016-03-28 12:26:44 -0700548
Nicholas Troast93fb0f02017-03-01 10:17:13 -0800549static void smblib_rerun_apsd(struct smb_charger *chg)
550{
551 int rc;
552
553 smblib_dbg(chg, PR_MISC, "re-running APSD\n");
554 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
555 rc = smblib_masked_write(chg,
556 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
557 AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
558 if (rc < 0)
559 smblib_err(chg, "Couldn't enable HVDCP auth IRQ rc=%d\n",
560 rc);
561 }
562
563 rc = smblib_masked_write(chg, CMD_APSD_REG,
564 APSD_RERUN_BIT, APSD_RERUN_BIT);
565 if (rc < 0)
566 smblib_err(chg, "Couldn't re-run APSD rc=%d\n", rc);
567}
568
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -0700569static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -0700570{
Abhijeet Dharmapurikareda08222016-11-01 11:35:29 -0700571 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -0700572
Jack Pham9696e252016-05-23 11:15:15 -0700573 /* if PD is active, APSD is disabled so won't have a valid result */
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +0530574 if (chg->pd_active) {
Fenglin Wu80826e02017-04-25 21:45:08 +0800575 chg->real_charger_type = POWER_SUPPLY_TYPE_USB_PD;
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +0530576 } else {
577 /*
578 * Update real charger type only if its not FLOAT
579 * detected as as SDP
580 */
581 if (!(apsd_result->pst == POWER_SUPPLY_TYPE_USB_FLOAT &&
582 chg->real_charger_type == POWER_SUPPLY_TYPE_USB))
Fenglin Wu80826e02017-04-25 21:45:08 +0800583 chg->real_charger_type = apsd_result->pst;
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +0530584 }
Nicholas Troast34db5032016-03-28 12:26:44 -0700585
Nicholas Troast93fb0f02017-03-01 10:17:13 -0800586 smblib_dbg(chg, PR_MISC, "APSD=%s PD=%d\n",
587 apsd_result->name, chg->pd_active);
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -0700588 return apsd_result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700589}
590
Harry Yang5e1a5222016-07-26 15:16:04 -0700591static int smblib_notifier_call(struct notifier_block *nb,
Harry Yang58a9e7a2016-06-23 14:54:43 -0700592 unsigned long ev, void *v)
Harry Yang1d1034c2016-06-15 12:09:42 -0700593{
Harry Yang58a9e7a2016-06-23 14:54:43 -0700594 struct power_supply *psy = v;
Harry Yang5e1a5222016-07-26 15:16:04 -0700595 struct smb_charger *chg = container_of(nb, struct smb_charger, nb);
Harry Yang1d1034c2016-06-15 12:09:42 -0700596
Harry Yang5e1a5222016-07-26 15:16:04 -0700597 if (!strcmp(psy->desc->name, "bms")) {
598 if (!chg->bms_psy)
599 chg->bms_psy = psy;
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530600 if (ev == PSY_EVENT_PROP_CHANGED)
Harry Yang5e1a5222016-07-26 15:16:04 -0700601 schedule_work(&chg->bms_update_work);
602 }
603
Harry Yang166b15d2017-08-28 13:00:40 -0700604 if (!chg->pl.psy && !strcmp(psy->desc->name, "parallel")) {
Harry Yang58a9e7a2016-06-23 14:54:43 -0700605 chg->pl.psy = psy;
Harry Yang166b15d2017-08-28 13:00:40 -0700606 schedule_work(&chg->pl_update_work);
607 }
Harry Yang1d1034c2016-06-15 12:09:42 -0700608
Harry Yang58a9e7a2016-06-23 14:54:43 -0700609 return NOTIFY_OK;
610}
611
Harry Yang5e1a5222016-07-26 15:16:04 -0700612static int smblib_register_notifier(struct smb_charger *chg)
Harry Yang58a9e7a2016-06-23 14:54:43 -0700613{
614 int rc;
615
Harry Yang5e1a5222016-07-26 15:16:04 -0700616 chg->nb.notifier_call = smblib_notifier_call;
617 rc = power_supply_reg_notifier(&chg->nb);
Harry Yang58a9e7a2016-06-23 14:54:43 -0700618 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700619 smblib_err(chg, "Couldn't register psy notifier rc = %d\n", rc);
Harry Yang58a9e7a2016-06-23 14:54:43 -0700620 return rc;
621 }
622
623 return 0;
Harry Yang1d1034c2016-06-15 12:09:42 -0700624}
625
Harry Yangfe913842016-08-10 12:27:28 -0700626int smblib_mapping_soc_from_field_value(struct smb_chg_param *param,
627 int val_u, u8 *val_raw)
628{
629 if (val_u > param->max_u || val_u < param->min_u)
630 return -EINVAL;
631
632 *val_raw = val_u << 1;
633
634 return 0;
635}
636
637int smblib_mapping_cc_delta_to_field_value(struct smb_chg_param *param,
638 u8 val_raw)
639{
640 int val_u = val_raw * param->step_u + param->min_u;
641
642 if (val_u > param->max_u)
643 val_u -= param->max_u * 2;
644
645 return val_u;
646}
647
648int smblib_mapping_cc_delta_from_field_value(struct smb_chg_param *param,
649 int val_u, u8 *val_raw)
650{
651 if (val_u > param->max_u || val_u < param->min_u - param->max_u)
652 return -EINVAL;
653
654 val_u += param->max_u * 2 - param->min_u;
655 val_u %= param->max_u * 2;
656 *val_raw = val_u / param->step_u;
657
658 return 0;
659}
660
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530661static void smblib_uusb_removal(struct smb_charger *chg)
662{
663 int rc;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +0530664 struct smb_irq_data *data;
665 struct storm_watch *wdata;
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530666
Ashay Jaiswalc0361672017-03-21 12:24:16 +0530667 cancel_delayed_work_sync(&chg->pl_enable_work);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +0530668
Ashay Jaiswal13a1b812017-07-17 14:49:05 +0530669 rc = smblib_request_dpdm(chg, false);
670 if (rc < 0)
671 smblib_err(chg, "Couldn't to disable DPDM rc=%d\n", rc);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +0530672
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +0530673 if (chg->wa_flags & BOOST_BACK_WA) {
674 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
675 if (data) {
676 wdata = &data->storm_data;
677 update_storm_count(wdata, WEAK_CHG_STORM_COUNT);
678 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
679 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
680 false, 0);
681 }
682 }
Ashay Jaiswalc0361672017-03-21 12:24:16 +0530683 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
684 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
685
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530686 /* reset both usbin current and voltage votes */
687 vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
688 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
Ashay Jaiswalae23a042017-05-18 15:28:31 +0530689 vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
Ashay Jaiswal3d22f4b2017-11-15 18:09:19 +0530690 vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530691
692 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
693
Ashay Jaiswal67ec7072017-02-16 14:14:58 +0530694 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
695 /* re-enable AUTH_IRQ_EN_CFG_BIT */
696 rc = smblib_masked_write(chg,
697 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
698 AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
699 if (rc < 0)
700 smblib_err(chg,
701 "Couldn't enable QC auth setting rc=%d\n", rc);
702 }
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530703
704 /* reconfigure allowed voltage for HVDCP */
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530705 rc = smblib_set_adapter_allowance(chg,
706 USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530707 if (rc < 0)
708 smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
709 rc);
710
711 chg->voltage_min_uv = MICRO_5V;
712 chg->voltage_max_uv = MICRO_5V;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +0530713 chg->usb_icl_delta_ua = 0;
714 chg->pulse_cnt = 0;
Ashay Jaiswal8507aa52017-04-14 09:42:32 +0530715 chg->uusb_apsd_rerun_done = false;
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530716
717 /* clear USB ICL vote for USB_PSY_VOTER */
718 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
719 if (rc < 0)
720 smblib_err(chg, "Couldn't un-vote for USB ICL rc=%d\n", rc);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -0800721
722 /* clear USB ICL vote for DCP_VOTER */
723 rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
724 if (rc < 0)
725 smblib_err(chg,
726 "Couldn't un-vote DCP from USB ICL rc=%d\n", rc);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530727}
728
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530729void smblib_suspend_on_debug_battery(struct smb_charger *chg)
730{
731 int rc;
732 union power_supply_propval val;
733
Ashay Jaiswalda8669b2017-02-10 23:24:23 +0530734 if (!chg->suspend_input_on_debug_batt)
735 return;
736
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530737 rc = power_supply_get_property(chg->bms_psy,
738 POWER_SUPPLY_PROP_DEBUG_BATTERY, &val);
739 if (rc < 0) {
740 smblib_err(chg, "Couldn't get debug battery prop rc=%d\n", rc);
741 return;
742 }
743
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800744 vote(chg->usb_icl_votable, DEBUG_BOARD_VOTER, val.intval, 0);
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530745 vote(chg->dc_suspend_votable, DEBUG_BOARD_VOTER, val.intval, 0);
746 if (val.intval)
747 pr_info("Input suspended: Fake battery\n");
748}
749
Abhijeet Dharmapurikar9dd61292017-01-25 16:40:08 -0800750int smblib_rerun_apsd_if_required(struct smb_charger *chg)
751{
Abhijeet Dharmapurikar9dd61292017-01-25 16:40:08 -0800752 union power_supply_propval val;
753 int rc;
754
755 rc = smblib_get_prop_usb_present(chg, &val);
756 if (rc < 0) {
757 smblib_err(chg, "Couldn't get usb present rc = %d\n", rc);
758 return rc;
759 }
760
761 if (!val.intval)
762 return 0;
763
Ashay Jaiswal13a1b812017-07-17 14:49:05 +0530764 rc = smblib_request_dpdm(chg, true);
765 if (rc < 0)
766 smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
Abhijeet Dharmapurikar025e63a2017-02-24 14:06:22 -0800767
Ashay Jaiswal8507aa52017-04-14 09:42:32 +0530768 chg->uusb_apsd_rerun_done = true;
Abhijeet Dharmapurikar025e63a2017-02-24 14:06:22 -0800769 smblib_rerun_apsd(chg);
770
Abhijeet Dharmapurikar9dd61292017-01-25 16:40:08 -0800771 return 0;
772}
773
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +0530774static int smblib_get_hw_pulse_cnt(struct smb_charger *chg, int *count)
Ashay Jaiswal6d308da2017-02-18 09:59:23 +0530775{
776 int rc;
777 u8 val[2];
778
779 switch (chg->smb_version) {
780 case PMI8998_SUBTYPE:
781 rc = smblib_read(chg, QC_PULSE_COUNT_STATUS_REG, val);
782 if (rc) {
783 pr_err("failed to read QC_PULSE_COUNT_STATUS_REG rc=%d\n",
784 rc);
785 return rc;
786 }
787 *count = val[0] & QC_PULSE_COUNT_MASK;
788 break;
789 case PM660_SUBTYPE:
790 rc = smblib_multibyte_read(chg,
791 QC_PULSE_COUNT_STATUS_1_REG, val, 2);
792 if (rc) {
793 pr_err("failed to read QC_PULSE_COUNT_STATUS_1_REG rc=%d\n",
794 rc);
795 return rc;
796 }
797 *count = (val[1] << 8) | val[0];
798 break;
799 default:
800 smblib_dbg(chg, PR_PARALLEL, "unknown SMB chip %d\n",
801 chg->smb_version);
802 return -EINVAL;
803 }
804
805 return 0;
806}
807
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +0530808static int smblib_get_pulse_cnt(struct smb_charger *chg, int *count)
809{
810 int rc;
811
812 /* Use software based pulse count if HW INOV is disabled */
813 if (get_effective_result(chg->hvdcp_hw_inov_dis_votable) > 0) {
814 *count = chg->pulse_cnt;
815 return 0;
816 }
817
818 /* Use h/w pulse count if autonomous mode is enabled */
819 rc = smblib_get_hw_pulse_cnt(chg, count);
820 if (rc < 0)
821 smblib_err(chg, "failed to read h/w pulse count rc=%d\n", rc);
822
823 return rc;
824}
825
Nicholas Troastbb76a142016-09-23 11:23:23 -0700826#define USBIN_25MA 25000
827#define USBIN_100MA 100000
828#define USBIN_150MA 150000
829#define USBIN_500MA 500000
830#define USBIN_900MA 900000
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800831
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800832static int set_sdp_current(struct smb_charger *chg, int icl_ua)
Nicholas Troast34db5032016-03-28 12:26:44 -0700833{
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800834 int rc;
835 u8 icl_options;
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +0530836 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700837
Nicholas Troastbb76a142016-09-23 11:23:23 -0700838 /* power source is SDP */
839 switch (icl_ua) {
840 case USBIN_100MA:
841 /* USB 2.0 100mA */
842 icl_options = 0;
843 break;
844 case USBIN_150MA:
845 /* USB 3.0 150mA */
846 icl_options = CFG_USB3P0_SEL_BIT;
847 break;
848 case USBIN_500MA:
849 /* USB 2.0 500mA */
850 icl_options = USB51_MODE_BIT;
851 break;
852 case USBIN_900MA:
853 /* USB 3.0 900mA */
854 icl_options = CFG_USB3P0_SEL_BIT | USB51_MODE_BIT;
855 break;
856 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700857 smblib_err(chg, "ICL %duA isn't supported for SDP\n", icl_ua);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800858 return -EINVAL;
Nicholas Troastbb76a142016-09-23 11:23:23 -0700859 }
Nicholas Troast34db5032016-03-28 12:26:44 -0700860
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +0530861 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB &&
862 apsd_result->pst == POWER_SUPPLY_TYPE_USB_FLOAT) {
863 /*
864 * change the float charger configuration to SDP, if this
865 * is the case of SDP being detected as FLOAT
866 */
867 rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
868 FORCE_FLOAT_SDP_CFG_BIT, FORCE_FLOAT_SDP_CFG_BIT);
869 if (rc < 0) {
870 smblib_err(chg, "Couldn't set float ICL options rc=%d\n",
871 rc);
872 return rc;
873 }
874 }
875
Nicholas Troastbb76a142016-09-23 11:23:23 -0700876 rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800877 CFG_USB3P0_SEL_BIT | USB51_MODE_BIT, icl_options);
Nicholas Troast34db5032016-03-28 12:26:44 -0700878 if (rc < 0) {
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800879 smblib_err(chg, "Couldn't set ICL options rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -0700880 return rc;
881 }
882
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800883 return rc;
884}
885
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700886static int get_sdp_current(struct smb_charger *chg, int *icl_ua)
887{
888 int rc;
889 u8 icl_options;
890 bool usb3 = false;
891
892 rc = smblib_read(chg, USBIN_ICL_OPTIONS_REG, &icl_options);
893 if (rc < 0) {
894 smblib_err(chg, "Couldn't get ICL options rc=%d\n", rc);
895 return rc;
896 }
897
898 usb3 = (icl_options & CFG_USB3P0_SEL_BIT);
899
900 if (icl_options & USB51_MODE_BIT)
901 *icl_ua = usb3 ? USBIN_900MA : USBIN_500MA;
902 else
903 *icl_ua = usb3 ? USBIN_150MA : USBIN_100MA;
904
905 return rc;
906}
907
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530908int smblib_set_icl_current(struct smb_charger *chg, int icl_ua)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800909{
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800910 int rc = 0;
911 bool override;
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800912
913 /* suspend and return if 25mA or less is requested */
Harry Yang379484a2017-08-29 10:26:14 -0700914 if (icl_ua <= USBIN_25MA)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800915 return smblib_set_usb_suspend(chg, true);
916
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530917 if (icl_ua == INT_MAX)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800918 goto override_suspend_config;
919
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800920 /* configure current */
Nicholas Troaste1932e42017-04-12 12:38:18 -0700921 if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
Fenglin Wu80826e02017-04-25 21:45:08 +0800922 && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) {
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800923 rc = set_sdp_current(chg, icl_ua);
924 if (rc < 0) {
925 smblib_err(chg, "Couldn't set SDP ICL rc=%d\n", rc);
926 goto enable_icl_changed_interrupt;
927 }
928 } else {
Abhijeet Dharmapurikar949d67e2017-05-25 15:10:56 -0700929 set_sdp_current(chg, 100000);
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -0700930 rc = smblib_set_charge_param(chg, &chg->param.usb_icl, icl_ua);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800931 if (rc < 0) {
932 smblib_err(chg, "Couldn't set HC ICL rc=%d\n", rc);
933 goto enable_icl_changed_interrupt;
934 }
935 }
936
937override_suspend_config:
938 /* determine if override needs to be enforced */
939 override = true;
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530940 if (icl_ua == INT_MAX) {
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800941 /* remove override if no voters - hw defaults is desired */
942 override = false;
Nicholas Troaste1932e42017-04-12 12:38:18 -0700943 } else if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
Fenglin Wu80826e02017-04-25 21:45:08 +0800944 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800945 /* For std cable with type = SDP never override */
946 override = false;
Fenglin Wu80826e02017-04-25 21:45:08 +0800947 else if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_CDP
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -0700948 && icl_ua == 1500000)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800949 /*
950 * For std cable with type = CDP override only if
951 * current is not 1500mA
952 */
953 override = false;
954 }
955
956 /* enforce override */
957 rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
958 USBIN_MODE_CHG_BIT, override ? USBIN_MODE_CHG_BIT : 0);
959
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800960 rc = smblib_icl_override(chg, override);
961 if (rc < 0) {
962 smblib_err(chg, "Couldn't set ICL override rc=%d\n", rc);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800963 goto enable_icl_changed_interrupt;
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800964 }
965
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800966 /* unsuspend after configuring current and override */
967 rc = smblib_set_usb_suspend(chg, false);
968 if (rc < 0) {
969 smblib_err(chg, "Couldn't resume input rc=%d\n", rc);
970 goto enable_icl_changed_interrupt;
971 }
972
973enable_icl_changed_interrupt:
Nicholas Troast34db5032016-03-28 12:26:44 -0700974 return rc;
975}
976
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700977int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua)
978{
979 int rc = 0;
980 u8 load_cfg;
981 bool override;
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700982
Ashay Jaiswal0ce2c7c2017-11-14 12:29:02 +0530983 if (((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT)
984 || (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB))
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700985 && (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)) {
986 rc = get_sdp_current(chg, icl_ua);
987 if (rc < 0) {
988 smblib_err(chg, "Couldn't get SDP ICL rc=%d\n", rc);
989 return rc;
990 }
991 } else {
992 rc = smblib_read(chg, USBIN_LOAD_CFG_REG, &load_cfg);
993 if (rc < 0) {
994 smblib_err(chg, "Couldn't get load cfg rc=%d\n", rc);
995 return rc;
996 }
997 override = load_cfg & ICL_OVERRIDE_AFTER_APSD_BIT;
998 if (!override)
999 return INT_MAX;
1000
1001 /* override is set */
1002 rc = smblib_get_charge_param(chg, &chg->param.usb_icl, icl_ua);
1003 if (rc < 0) {
1004 smblib_err(chg, "Couldn't get HC ICL rc=%d\n", rc);
1005 return rc;
1006 }
1007 }
1008
1009 return 0;
1010}
1011
Ashay Jaiswalae1586d2017-03-22 23:18:51 +05301012/*********************
1013 * VOTABLE CALLBACKS *
1014 *********************/
1015
1016static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data,
1017 int suspend, const char *client)
1018{
1019 struct smb_charger *chg = data;
1020
1021 /* resume input if suspend is invalid */
1022 if (suspend < 0)
1023 suspend = 0;
1024
1025 return smblib_set_dc_suspend(chg, (bool)suspend);
1026}
1027
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001028static int smblib_dc_icl_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -07001029 int icl_ua, const char *client)
Nicholas Troast34db5032016-03-28 12:26:44 -07001030{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001031 struct smb_charger *chg = data;
Nicholas Troast34db5032016-03-28 12:26:44 -07001032 int rc = 0;
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001033 bool suspend;
1034
1035 if (icl_ua < 0) {
1036 smblib_dbg(chg, PR_MISC, "No Voter hence suspending\n");
1037 icl_ua = 0;
1038 }
1039
Harry Yang379484a2017-08-29 10:26:14 -07001040 suspend = (icl_ua <= USBIN_25MA);
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001041 if (suspend)
1042 goto suspend;
Nicholas Troast34db5032016-03-28 12:26:44 -07001043
1044 rc = smblib_set_charge_param(chg, &chg->param.dc_icl, icl_ua);
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001045 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001046 smblib_err(chg, "Couldn't set DC input current limit rc=%d\n",
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001047 rc);
1048 return rc;
1049 }
1050
1051suspend:
1052 rc = vote(chg->dc_suspend_votable, USER_VOTER, suspend, 0);
1053 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001054 smblib_err(chg, "Couldn't vote to %s DC rc=%d\n",
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001055 suspend ? "suspend" : "resume", rc);
1056 return rc;
1057 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001058 return rc;
1059}
1060
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07001061static int smblib_pd_disallowed_votable_indirect_callback(
1062 struct votable *votable, void *data, int disallowed, const char *client)
1063{
1064 struct smb_charger *chg = data;
1065 int rc;
1066
1067 rc = vote(chg->pd_allowed_votable, PD_DISALLOWED_INDIRECT_VOTER,
1068 !disallowed, 0);
1069
1070 return rc;
1071}
1072
Harry Yang223c6282016-06-14 15:48:36 -07001073static int smblib_awake_vote_callback(struct votable *votable, void *data,
1074 int awake, const char *client)
1075{
1076 struct smb_charger *chg = data;
1077
1078 if (awake)
1079 pm_stay_awake(chg->dev);
1080 else
1081 pm_relax(chg->dev);
1082
1083 return 0;
1084}
1085
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07001086static int smblib_chg_disable_vote_callback(struct votable *votable, void *data,
1087 int chg_disable, const char *client)
1088{
1089 struct smb_charger *chg = data;
1090 int rc;
1091
1092 rc = smblib_masked_write(chg, CHARGING_ENABLE_CMD_REG,
1093 CHARGING_ENABLE_CMD_BIT,
1094 chg_disable ? 0 : CHARGING_ENABLE_CMD_BIT);
1095 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001096 smblib_err(chg, "Couldn't %s charging rc=%d\n",
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07001097 chg_disable ? "disable" : "enable", rc);
1098 return rc;
1099 }
1100
1101 return 0;
1102}
Harry Yangaba1f5f2016-09-28 10:47:29 -07001103
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301104static int smblib_hvdcp_enable_vote_callback(struct votable *votable,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001105 void *data,
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301106 int hvdcp_enable, const char *client)
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001107{
1108 struct smb_charger *chg = data;
1109 int rc;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301110 u8 val = HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_EN_BIT;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07001111 u8 stat;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301112
1113 /* vote to enable/disable HW autonomous INOV */
1114 vote(chg->hvdcp_hw_inov_dis_votable, client, !hvdcp_enable, 0);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001115
1116 /*
1117 * Disable the autonomous bit and auth bit for disabling hvdcp.
1118 * This ensures only qc 2.0 detection runs but no vbus
1119 * negotiation happens.
1120 */
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301121 if (!hvdcp_enable)
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001122 val = HVDCP_EN_BIT;
1123
1124 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301125 HVDCP_EN_BIT | HVDCP_AUTH_ALG_EN_CFG_BIT,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001126 val);
1127 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001128 smblib_err(chg, "Couldn't %s hvdcp rc=%d\n",
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301129 hvdcp_enable ? "enable" : "disable", rc);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001130 return rc;
1131 }
1132
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07001133 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
1134 if (rc < 0) {
1135 smblib_err(chg, "Couldn't read APSD status rc=%d\n", rc);
1136 return rc;
1137 }
1138
1139 /* re-run APSD if HVDCP was detected */
1140 if (stat & QC_CHARGER_BIT)
1141 smblib_rerun_apsd(chg);
1142
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001143 return 0;
1144}
1145
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301146static int smblib_hvdcp_disable_indirect_vote_callback(struct votable *votable,
1147 void *data, int hvdcp_disable, const char *client)
1148{
1149 struct smb_charger *chg = data;
1150
1151 vote(chg->hvdcp_enable_votable, HVDCP_INDIRECT_VOTER,
1152 !hvdcp_disable, 0);
1153
1154 return 0;
1155}
1156
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07001157static int smblib_apsd_disable_vote_callback(struct votable *votable,
1158 void *data,
1159 int apsd_disable, const char *client)
1160{
1161 struct smb_charger *chg = data;
1162 int rc;
1163
Nicholas Troastec4703c2017-01-30 14:52:33 -08001164 if (apsd_disable) {
Nicholas Troastec4703c2017-01-30 14:52:33 -08001165 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1166 AUTO_SRC_DETECT_BIT,
1167 0);
1168 if (rc < 0) {
1169 smblib_err(chg, "Couldn't disable APSD rc=%d\n", rc);
1170 return rc;
1171 }
1172 } else {
1173 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1174 AUTO_SRC_DETECT_BIT,
1175 AUTO_SRC_DETECT_BIT);
1176 if (rc < 0) {
1177 smblib_err(chg, "Couldn't enable APSD rc=%d\n", rc);
1178 return rc;
1179 }
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07001180 }
1181
1182 return 0;
1183}
Nicholas Troast8995a702016-12-05 10:22:22 -08001184
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301185static int smblib_hvdcp_hw_inov_dis_vote_callback(struct votable *votable,
1186 void *data, int disable, const char *client)
1187{
1188 struct smb_charger *chg = data;
1189 int rc;
1190
1191 if (disable) {
1192 /*
1193 * the pulse count register get zeroed when autonomous mode is
1194 * disabled. Track that in variables before disabling
1195 */
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +05301196 rc = smblib_get_hw_pulse_cnt(chg, &chg->pulse_cnt);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301197 if (rc < 0) {
1198 pr_err("failed to read QC_PULSE_COUNT_STATUS_REG rc=%d\n",
1199 rc);
1200 return rc;
1201 }
1202 }
1203
1204 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1205 HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT,
1206 disable ? 0 : HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT);
1207 if (rc < 0) {
1208 smblib_err(chg, "Couldn't %s hvdcp rc=%d\n",
1209 disable ? "disable" : "enable", rc);
1210 return rc;
1211 }
1212
1213 return rc;
1214}
1215
Harry Yang4bf7d962017-03-13 16:51:43 -07001216static int smblib_usb_irq_enable_vote_callback(struct votable *votable,
1217 void *data, int enable, const char *client)
1218{
1219 struct smb_charger *chg = data;
1220
1221 if (!chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq ||
1222 !chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq)
1223 return 0;
1224
1225 if (enable) {
1226 enable_irq(chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq);
1227 enable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
1228 } else {
1229 disable_irq(chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq);
1230 disable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
1231 }
1232
1233 return 0;
1234}
1235
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07001236static int smblib_typec_irq_disable_vote_callback(struct votable *votable,
1237 void *data, int disable, const char *client)
1238{
1239 struct smb_charger *chg = data;
1240
1241 if (!chg->irq_info[TYPE_C_CHANGE_IRQ].irq)
1242 return 0;
1243
1244 if (disable)
1245 disable_irq_nosync(chg->irq_info[TYPE_C_CHANGE_IRQ].irq);
1246 else
1247 enable_irq(chg->irq_info[TYPE_C_CHANGE_IRQ].irq);
1248
1249 return 0;
1250}
1251
Nicholas Troast8995a702016-12-05 10:22:22 -08001252/*******************
1253 * VCONN REGULATOR *
1254 * *****************/
1255
Nicholas Troastb11015f2017-01-17 17:56:45 -08001256#define MAX_OTG_SS_TRIES 2
Nicholas Troast8995a702016-12-05 10:22:22 -08001257static int _smblib_vconn_regulator_enable(struct regulator_dev *rdev)
1258{
1259 struct smb_charger *chg = rdev_get_drvdata(rdev);
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001260 int rc = 0;
1261 u8 val;
Nicholas Troast8995a702016-12-05 10:22:22 -08001262
1263 /*
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001264 * When enabling VCONN using the command register the CC pin must be
1265 * selected. VCONN should be supplied to the inactive CC pin hence using
1266 * the opposite of the CC_ORIENTATION_BIT.
Nicholas Troast8995a702016-12-05 10:22:22 -08001267 */
Nicholas Troastb11015f2017-01-17 17:56:45 -08001268 smblib_dbg(chg, PR_OTG, "enabling VCONN\n");
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07001269 val = chg->typec_status[3] &
1270 CC_ORIENTATION_BIT ? 0 : VCONN_EN_ORIENTATION_BIT;
Nicholas Troast8995a702016-12-05 10:22:22 -08001271 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1272 VCONN_EN_VALUE_BIT | VCONN_EN_ORIENTATION_BIT,
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07001273 VCONN_EN_VALUE_BIT | val);
Nicholas Troast8995a702016-12-05 10:22:22 -08001274 if (rc < 0) {
1275 smblib_err(chg, "Couldn't enable vconn setting rc=%d\n", rc);
1276 return rc;
1277 }
1278
1279 return rc;
1280}
1281
1282int smblib_vconn_regulator_enable(struct regulator_dev *rdev)
1283{
1284 struct smb_charger *chg = rdev_get_drvdata(rdev);
1285 int rc = 0;
1286
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001287 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001288 if (chg->vconn_en)
1289 goto unlock;
1290
1291 rc = _smblib_vconn_regulator_enable(rdev);
1292 if (rc >= 0)
1293 chg->vconn_en = true;
1294
1295unlock:
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001296 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001297 return rc;
1298}
1299
1300static int _smblib_vconn_regulator_disable(struct regulator_dev *rdev)
1301{
1302 struct smb_charger *chg = rdev_get_drvdata(rdev);
1303 int rc = 0;
1304
Nicholas Troastb11015f2017-01-17 17:56:45 -08001305 smblib_dbg(chg, PR_OTG, "disabling VCONN\n");
Nicholas Troast8995a702016-12-05 10:22:22 -08001306 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1307 VCONN_EN_VALUE_BIT, 0);
1308 if (rc < 0)
1309 smblib_err(chg, "Couldn't disable vconn regulator rc=%d\n", rc);
1310
1311 return rc;
1312}
1313
1314int smblib_vconn_regulator_disable(struct regulator_dev *rdev)
1315{
1316 struct smb_charger *chg = rdev_get_drvdata(rdev);
1317 int rc = 0;
1318
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001319 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001320 if (!chg->vconn_en)
1321 goto unlock;
1322
1323 rc = _smblib_vconn_regulator_disable(rdev);
1324 if (rc >= 0)
1325 chg->vconn_en = false;
1326
1327unlock:
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001328 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001329 return rc;
1330}
1331
1332int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev)
1333{
1334 struct smb_charger *chg = rdev_get_drvdata(rdev);
1335 int ret;
1336
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001337 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001338 ret = chg->vconn_en;
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001339 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001340 return ret;
1341}
1342
Nicholas Troast34db5032016-03-28 12:26:44 -07001343/*****************
1344 * OTG REGULATOR *
1345 *****************/
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301346#define MAX_RETRY 15
1347#define MIN_DELAY_US 2000
1348#define MAX_DELAY_US 9000
Anirudh Ghayaladf20da2017-07-03 10:52:29 +05301349static int otg_current[] = {250000, 500000, 1000000, 1500000};
1350static int smblib_enable_otg_wa(struct smb_charger *chg)
1351{
1352 u8 stat;
1353 int rc, i, retry_count = 0, min_delay = MIN_DELAY_US;
1354
1355 for (i = 0; i < ARRAY_SIZE(otg_current); i++) {
1356 smblib_dbg(chg, PR_OTG, "enabling OTG with %duA\n",
1357 otg_current[i]);
1358 rc = smblib_set_charge_param(chg, &chg->param.otg_cl,
1359 otg_current[i]);
1360 if (rc < 0) {
1361 smblib_err(chg, "Couldn't set otg limit rc=%d\n", rc);
1362 return rc;
1363 }
1364
1365 rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT);
1366 if (rc < 0) {
1367 smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc);
1368 return rc;
1369 }
1370
1371 retry_count = 0;
1372 min_delay = MIN_DELAY_US;
1373 do {
1374 usleep_range(min_delay, min_delay + 100);
1375 rc = smblib_read(chg, OTG_STATUS_REG, &stat);
1376 if (rc < 0) {
1377 smblib_err(chg, "Couldn't read OTG status rc=%d\n",
1378 rc);
1379 goto out;
1380 }
1381
1382 if (stat & BOOST_SOFTSTART_DONE_BIT) {
1383 rc = smblib_set_charge_param(chg,
1384 &chg->param.otg_cl, chg->otg_cl_ua);
1385 if (rc < 0) {
1386 smblib_err(chg, "Couldn't set otg limit rc=%d\n",
1387 rc);
1388 goto out;
1389 }
1390 break;
1391 }
1392 /* increase the delay for following iterations */
1393 if (retry_count > 5)
1394 min_delay = MAX_DELAY_US;
1395
1396 } while (retry_count++ < MAX_RETRY);
1397
1398 if (retry_count >= MAX_RETRY) {
1399 smblib_dbg(chg, PR_OTG, "OTG enable failed with %duA\n",
1400 otg_current[i]);
1401 rc = smblib_write(chg, CMD_OTG_REG, 0);
1402 if (rc < 0) {
1403 smblib_err(chg, "disable OTG rc=%d\n", rc);
1404 goto out;
1405 }
1406 } else {
1407 smblib_dbg(chg, PR_OTG, "OTG enabled\n");
1408 return 0;
1409 }
1410 }
1411
1412 if (i == ARRAY_SIZE(otg_current)) {
1413 rc = -EINVAL;
1414 goto out;
1415 }
1416
1417 return 0;
1418out:
1419 smblib_write(chg, CMD_OTG_REG, 0);
1420 return rc;
1421}
1422
Nicholas Troast8995a702016-12-05 10:22:22 -08001423static int _smblib_vbus_regulator_enable(struct regulator_dev *rdev)
Nicholas Troast34db5032016-03-28 12:26:44 -07001424{
1425 struct smb_charger *chg = rdev_get_drvdata(rdev);
Anirudh Ghayaladf20da2017-07-03 10:52:29 +05301426 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001427
Nicholas Troastb11015f2017-01-17 17:56:45 -08001428 smblib_dbg(chg, PR_OTG, "halt 1 in 8 mode\n");
Harry Yang360bd532016-09-26 11:03:22 -07001429 rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
1430 ENG_BUCKBOOST_HALT1_8_MODE_BIT,
1431 ENG_BUCKBOOST_HALT1_8_MODE_BIT);
1432 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001433 smblib_err(chg, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n",
Harry Yang360bd532016-09-26 11:03:22 -07001434 rc);
1435 return rc;
1436 }
1437
Nicholas Troastb11015f2017-01-17 17:56:45 -08001438 smblib_dbg(chg, PR_OTG, "enabling OTG\n");
Harry Yang360bd532016-09-26 11:03:22 -07001439
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301440 if (chg->wa_flags & OTG_WA) {
Anirudh Ghayaladf20da2017-07-03 10:52:29 +05301441 rc = smblib_enable_otg_wa(chg);
1442 if (rc < 0)
1443 smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc);
1444 } else {
1445 rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT);
1446 if (rc < 0)
1447 smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc);
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301448 }
1449
Nicholas Troast34db5032016-03-28 12:26:44 -07001450 return rc;
1451}
1452
Nicholas Troast8995a702016-12-05 10:22:22 -08001453int smblib_vbus_regulator_enable(struct regulator_dev *rdev)
Nicholas Troast34db5032016-03-28 12:26:44 -07001454{
1455 struct smb_charger *chg = rdev_get_drvdata(rdev);
1456 int rc = 0;
1457
Nicholas Troastb11015f2017-01-17 17:56:45 -08001458 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001459 if (chg->otg_en)
1460 goto unlock;
1461
Harry Yanga2fb0e32017-03-22 22:45:25 -07001462 if (!chg->usb_icl_votable) {
1463 chg->usb_icl_votable = find_votable("USB_ICL");
1464
Harry Yang4e619b42017-12-06 10:13:21 -08001465 if (!chg->usb_icl_votable) {
1466 rc = -EINVAL;
1467 goto unlock;
1468 }
Harry Yanga2fb0e32017-03-22 22:45:25 -07001469 }
1470 vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, true, 0);
1471
Nicholas Troast8995a702016-12-05 10:22:22 -08001472 rc = _smblib_vbus_regulator_enable(rdev);
1473 if (rc >= 0)
1474 chg->otg_en = true;
Ashay Jaiswal3d22f4b2017-11-15 18:09:19 +05301475 else
1476 vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0);
Nicholas Troast8995a702016-12-05 10:22:22 -08001477
1478unlock:
Nicholas Troastb11015f2017-01-17 17:56:45 -08001479 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001480 return rc;
1481}
1482
1483static int _smblib_vbus_regulator_disable(struct regulator_dev *rdev)
1484{
1485 struct smb_charger *chg = rdev_get_drvdata(rdev);
1486 int rc;
Nicholas Troast8995a702016-12-05 10:22:22 -08001487
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301488 if (chg->wa_flags & OTG_WA) {
1489 /* set OTG current limit to minimum value */
1490 rc = smblib_set_charge_param(chg, &chg->param.otg_cl,
1491 chg->param.otg_cl.min_u);
1492 if (rc < 0) {
1493 smblib_err(chg,
1494 "Couldn't set otg current limit rc=%d\n", rc);
1495 return rc;
1496 }
1497 }
1498
Nicholas Troastb11015f2017-01-17 17:56:45 -08001499 smblib_dbg(chg, PR_OTG, "disabling OTG\n");
Harry Yang360bd532016-09-26 11:03:22 -07001500 rc = smblib_write(chg, CMD_OTG_REG, 0);
1501 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001502 smblib_err(chg, "Couldn't disable OTG regulator rc=%d\n", rc);
Harry Yang360bd532016-09-26 11:03:22 -07001503 return rc;
1504 }
1505
Nicholas Troastb11015f2017-01-17 17:56:45 -08001506 smblib_dbg(chg, PR_OTG, "start 1 in 8 mode\n");
Harry Yang360bd532016-09-26 11:03:22 -07001507 rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
1508 ENG_BUCKBOOST_HALT1_8_MODE_BIT, 0);
1509 if (rc < 0) {
Nicholas Troast8995a702016-12-05 10:22:22 -08001510 smblib_err(chg, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n", rc);
Harry Yang360bd532016-09-26 11:03:22 -07001511 return rc;
1512 }
1513
Nicholas Troast8995a702016-12-05 10:22:22 -08001514 return 0;
1515}
Nicholas Troast34db5032016-03-28 12:26:44 -07001516
Nicholas Troast8995a702016-12-05 10:22:22 -08001517int smblib_vbus_regulator_disable(struct regulator_dev *rdev)
1518{
1519 struct smb_charger *chg = rdev_get_drvdata(rdev);
1520 int rc = 0;
1521
Nicholas Troastb11015f2017-01-17 17:56:45 -08001522 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001523 if (!chg->otg_en)
1524 goto unlock;
1525
1526 rc = _smblib_vbus_regulator_disable(rdev);
1527 if (rc >= 0)
1528 chg->otg_en = false;
1529
Harry Yanga2fb0e32017-03-22 22:45:25 -07001530 if (chg->usb_icl_votable)
1531 vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0);
Nicholas Troast8995a702016-12-05 10:22:22 -08001532unlock:
Nicholas Troastb11015f2017-01-17 17:56:45 -08001533 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07001534 return rc;
1535}
1536
1537int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev)
1538{
1539 struct smb_charger *chg = rdev_get_drvdata(rdev);
Nicholas Troast8995a702016-12-05 10:22:22 -08001540 int ret;
Nicholas Troast34db5032016-03-28 12:26:44 -07001541
Nicholas Troastb11015f2017-01-17 17:56:45 -08001542 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001543 ret = chg->otg_en;
Nicholas Troastb11015f2017-01-17 17:56:45 -08001544 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001545 return ret;
Nicholas Troast34db5032016-03-28 12:26:44 -07001546}
1547
1548/********************
1549 * BATT PSY GETTERS *
1550 ********************/
1551
1552int smblib_get_prop_input_suspend(struct smb_charger *chg,
1553 union power_supply_propval *val)
1554{
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08001555 val->intval
1556 = (get_client_vote(chg->usb_icl_votable, USER_VOTER) == 0)
1557 && get_client_vote(chg->dc_suspend_votable, USER_VOTER);
Nicholas Troast34db5032016-03-28 12:26:44 -07001558 return 0;
1559}
1560
1561int smblib_get_prop_batt_present(struct smb_charger *chg,
1562 union power_supply_propval *val)
1563{
1564 int rc;
1565 u8 stat;
1566
1567 rc = smblib_read(chg, BATIF_BASE + INT_RT_STS_OFFSET, &stat);
1568 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001569 smblib_err(chg, "Couldn't read BATIF_INT_RT_STS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07001570 return rc;
1571 }
1572
1573 val->intval = !(stat & (BAT_THERM_OR_ID_MISSING_RT_STS_BIT
1574 | BAT_TERMINAL_MISSING_RT_STS_BIT));
1575
1576 return rc;
1577}
1578
1579int smblib_get_prop_batt_capacity(struct smb_charger *chg,
1580 union power_supply_propval *val)
1581{
Harry Yang5e1a5222016-07-26 15:16:04 -07001582 int rc = -EINVAL;
1583
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07001584 if (chg->fake_capacity >= 0) {
1585 val->intval = chg->fake_capacity;
1586 return 0;
1587 }
1588
Harry Yang5e1a5222016-07-26 15:16:04 -07001589 if (chg->bms_psy)
1590 rc = power_supply_get_property(chg->bms_psy,
1591 POWER_SUPPLY_PROP_CAPACITY, val);
1592 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001593}
1594
1595int smblib_get_prop_batt_status(struct smb_charger *chg,
1596 union power_supply_propval *val)
1597{
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001598 union power_supply_propval pval = {0, };
Abhijeet Dharmapurikard97b2bf2017-07-06 17:03:00 -07001599 bool usb_online, dc_online, qnovo_en;
1600 u8 stat, pt_en_cmd;
Nicholas Troast8cb77552016-09-23 11:50:18 -07001601 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001602
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001603 rc = smblib_get_prop_usb_online(chg, &pval);
1604 if (rc < 0) {
1605 smblib_err(chg, "Couldn't get usb online property rc=%d\n",
1606 rc);
1607 return rc;
1608 }
1609 usb_online = (bool)pval.intval;
1610
1611 rc = smblib_get_prop_dc_online(chg, &pval);
1612 if (rc < 0) {
1613 smblib_err(chg, "Couldn't get dc online property rc=%d\n",
1614 rc);
1615 return rc;
1616 }
1617 dc_online = (bool)pval.intval;
1618
Nicholas Troast34db5032016-03-28 12:26:44 -07001619 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1620 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001621 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001622 rc);
1623 return rc;
1624 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001625 stat = stat & BATTERY_CHARGER_STATUS_MASK;
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001626
1627 if (!usb_online && !dc_online) {
1628 switch (stat) {
1629 case TERMINATE_CHARGE:
1630 case INHIBIT_CHARGE:
1631 val->intval = POWER_SUPPLY_STATUS_FULL;
1632 break;
1633 default:
1634 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
1635 break;
1636 }
1637 return rc;
1638 }
1639
Nicholas Troast8cb77552016-09-23 11:50:18 -07001640 switch (stat) {
1641 case TRICKLE_CHARGE:
1642 case PRE_CHARGE:
1643 case FAST_CHARGE:
1644 case FULLON_CHARGE:
1645 case TAPER_CHARGE:
Nicholas Troast34db5032016-03-28 12:26:44 -07001646 val->intval = POWER_SUPPLY_STATUS_CHARGING;
Nicholas Troast8cb77552016-09-23 11:50:18 -07001647 break;
1648 case TERMINATE_CHARGE:
1649 case INHIBIT_CHARGE:
1650 val->intval = POWER_SUPPLY_STATUS_FULL;
1651 break;
1652 case DISABLE_CHARGE:
1653 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
1654 break;
1655 default:
1656 val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
1657 break;
1658 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001659
Harry Yang7ecc1a12017-04-06 12:24:56 -07001660 if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
1661 return 0;
1662
Harry Yang589dd422017-07-28 18:41:42 -07001663 if (!usb_online && dc_online
1664 && chg->fake_batt_status == POWER_SUPPLY_STATUS_FULL) {
1665 val->intval = POWER_SUPPLY_STATUS_FULL;
1666 return 0;
1667 }
1668
Harry Yangc3c28d12017-04-17 16:41:19 -07001669 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_7_REG, &stat);
Harry Yang7ecc1a12017-04-06 12:24:56 -07001670 if (rc < 0) {
1671 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
1672 rc);
1673 return rc;
Abhijeet Dharmapurikard97b2bf2017-07-06 17:03:00 -07001674 }
Harry Yang7ecc1a12017-04-06 12:24:56 -07001675
Harry Yangc3c28d12017-04-17 16:41:19 -07001676 stat &= ENABLE_TRICKLE_BIT | ENABLE_PRE_CHARGING_BIT |
1677 ENABLE_FAST_CHARGING_BIT | ENABLE_FULLON_MODE_BIT;
Abhijeet Dharmapurikard97b2bf2017-07-06 17:03:00 -07001678
1679 rc = smblib_read(chg, QNOVO_PT_ENABLE_CMD_REG, &pt_en_cmd);
1680 if (rc < 0) {
1681 smblib_err(chg, "Couldn't read QNOVO_PT_ENABLE_CMD_REG rc=%d\n",
1682 rc);
1683 return rc;
1684 }
1685
1686 qnovo_en = (bool)(pt_en_cmd & QNOVO_PT_ENABLE_CMD_BIT);
1687
1688 /* ignore stat7 when qnovo is enabled */
1689 if (!qnovo_en && !stat)
Harry Yang7ecc1a12017-04-06 12:24:56 -07001690 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
1691
Nicholas Troast8cb77552016-09-23 11:50:18 -07001692 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07001693}
1694
1695int smblib_get_prop_batt_charge_type(struct smb_charger *chg,
1696 union power_supply_propval *val)
1697{
1698 int rc;
1699 u8 stat;
1700
1701 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1702 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001703 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001704 rc);
1705 return rc;
1706 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001707
1708 switch (stat & BATTERY_CHARGER_STATUS_MASK) {
1709 case TRICKLE_CHARGE:
1710 case PRE_CHARGE:
1711 val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1712 break;
1713 case FAST_CHARGE:
1714 case FULLON_CHARGE:
1715 val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
1716 break;
1717 case TAPER_CHARGE:
1718 val->intval = POWER_SUPPLY_CHARGE_TYPE_TAPER;
1719 break;
1720 default:
1721 val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
1722 }
1723
1724 return rc;
1725}
1726
1727int smblib_get_prop_batt_health(struct smb_charger *chg,
1728 union power_supply_propval *val)
1729{
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001730 union power_supply_propval pval;
Nicholas Troast34db5032016-03-28 12:26:44 -07001731 int rc;
Abhijeet Dharmapurikar33d18462017-05-15 13:38:53 -07001732 int effective_fv_uv;
Nicholas Troast34db5032016-03-28 12:26:44 -07001733 u8 stat;
1734
1735 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat);
1736 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001737 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001738 rc);
1739 return rc;
1740 }
1741 smblib_dbg(chg, PR_REGISTER, "BATTERY_CHARGER_STATUS_2 = 0x%02x\n",
1742 stat);
1743
1744 if (stat & CHARGER_ERROR_STATUS_BAT_OV_BIT) {
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001745 rc = smblib_get_prop_batt_voltage_now(chg, &pval);
1746 if (!rc) {
1747 /*
1748 * If Vbatt is within 40mV above Vfloat, then don't
1749 * treat it as overvoltage.
1750 */
Abhijeet Dharmapurikar33d18462017-05-15 13:38:53 -07001751 effective_fv_uv = get_effective_result(chg->fv_votable);
1752 if (pval.intval >= effective_fv_uv + 40000) {
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001753 val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
Abhijeet Dharmapurikar33d18462017-05-15 13:38:53 -07001754 smblib_err(chg, "battery over-voltage vbat_fg = %duV, fv = %duV\n",
1755 pval.intval, effective_fv_uv);
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001756 goto done;
1757 }
1758 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001759 }
1760
Harry Yang668fc5e2016-07-12 16:51:47 -07001761 if (stat & BAT_TEMP_STATUS_TOO_COLD_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001762 val->intval = POWER_SUPPLY_HEALTH_COLD;
Harry Yang668fc5e2016-07-12 16:51:47 -07001763 else if (stat & BAT_TEMP_STATUS_TOO_HOT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001764 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
Harry Yang668fc5e2016-07-12 16:51:47 -07001765 else if (stat & BAT_TEMP_STATUS_COLD_SOFT_LIMIT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001766 val->intval = POWER_SUPPLY_HEALTH_COOL;
Harry Yang668fc5e2016-07-12 16:51:47 -07001767 else if (stat & BAT_TEMP_STATUS_HOT_SOFT_LIMIT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001768 val->intval = POWER_SUPPLY_HEALTH_WARM;
Harry Yang668fc5e2016-07-12 16:51:47 -07001769 else
Nicholas Troast34db5032016-03-28 12:26:44 -07001770 val->intval = POWER_SUPPLY_HEALTH_GOOD;
Nicholas Troast34db5032016-03-28 12:26:44 -07001771
1772done:
1773 return rc;
1774}
1775
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001776int smblib_get_prop_system_temp_level(struct smb_charger *chg,
1777 union power_supply_propval *val)
1778{
1779 val->intval = chg->system_temp_level;
1780 return 0;
1781}
1782
Abhijeet Dharmapurikaracf32002017-05-11 11:54:17 -07001783int smblib_get_prop_system_temp_level_max(struct smb_charger *chg,
1784 union power_supply_propval *val)
1785{
1786 val->intval = chg->thermal_levels;
1787 return 0;
1788}
1789
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001790int smblib_get_prop_input_current_limited(struct smb_charger *chg,
1791 union power_supply_propval *val)
1792{
1793 u8 stat;
1794 int rc;
1795
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07001796 if (chg->fake_input_current_limited >= 0) {
1797 val->intval = chg->fake_input_current_limited;
1798 return 0;
1799 }
1800
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001801 rc = smblib_read(chg, AICL_STATUS_REG, &stat);
1802 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001803 smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n", rc);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001804 return rc;
1805 }
1806 val->intval = (stat & SOFT_ILIMIT_BIT) || chg->is_hdc;
1807 return 0;
1808}
1809
Nicholas Troast66b21d72016-09-20 15:33:20 -07001810int smblib_get_prop_batt_voltage_now(struct smb_charger *chg,
1811 union power_supply_propval *val)
1812{
1813 int rc;
1814
1815 if (!chg->bms_psy)
1816 return -EINVAL;
1817
1818 rc = power_supply_get_property(chg->bms_psy,
1819 POWER_SUPPLY_PROP_VOLTAGE_NOW, val);
1820 return rc;
1821}
1822
1823int smblib_get_prop_batt_current_now(struct smb_charger *chg,
1824 union power_supply_propval *val)
1825{
1826 int rc;
1827
1828 if (!chg->bms_psy)
1829 return -EINVAL;
1830
1831 rc = power_supply_get_property(chg->bms_psy,
1832 POWER_SUPPLY_PROP_CURRENT_NOW, val);
1833 return rc;
1834}
1835
1836int smblib_get_prop_batt_temp(struct smb_charger *chg,
1837 union power_supply_propval *val)
1838{
1839 int rc;
1840
1841 if (!chg->bms_psy)
1842 return -EINVAL;
1843
1844 rc = power_supply_get_property(chg->bms_psy,
1845 POWER_SUPPLY_PROP_TEMP, val);
1846 return rc;
1847}
1848
Subbaraman Narayanamurthyb491d022016-10-10 20:22:48 -07001849int smblib_get_prop_batt_charge_done(struct smb_charger *chg,
1850 union power_supply_propval *val)
1851{
1852 int rc;
1853 u8 stat;
1854
1855 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1856 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001857 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Subbaraman Narayanamurthyb491d022016-10-10 20:22:48 -07001858 rc);
1859 return rc;
1860 }
1861
1862 stat = stat & BATTERY_CHARGER_STATUS_MASK;
1863 val->intval = (stat == TERMINATE_CHARGE);
1864 return 0;
1865}
1866
Harry Yang40192cb2017-02-25 23:25:17 -08001867int smblib_get_prop_charge_qnovo_enable(struct smb_charger *chg,
1868 union power_supply_propval *val)
1869{
1870 int rc;
1871 u8 stat;
1872
1873 rc = smblib_read(chg, QNOVO_PT_ENABLE_CMD_REG, &stat);
1874 if (rc < 0) {
1875 smblib_err(chg, "Couldn't read QNOVO_PT_ENABLE_CMD rc=%d\n",
1876 rc);
1877 return rc;
1878 }
1879
1880 val->intval = (bool)(stat & QNOVO_PT_ENABLE_CMD_BIT);
1881 return 0;
1882}
1883
Nicholas Troast4fe68d02017-07-26 14:17:34 -07001884int smblib_get_prop_batt_charge_counter(struct smb_charger *chg,
1885 union power_supply_propval *val)
1886{
1887 int rc;
1888
1889 if (!chg->bms_psy)
1890 return -EINVAL;
1891
1892 rc = power_supply_get_property(chg->bms_psy,
1893 POWER_SUPPLY_PROP_CHARGE_COUNTER, val);
1894 return rc;
1895}
1896
Nicholas Troast34db5032016-03-28 12:26:44 -07001897/***********************
1898 * BATTERY PSY SETTERS *
1899 ***********************/
1900
1901int smblib_set_prop_input_suspend(struct smb_charger *chg,
1902 const union power_supply_propval *val)
1903{
1904 int rc;
1905
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08001906 /* vote 0mA when suspended */
1907 rc = vote(chg->usb_icl_votable, USER_VOTER, (bool)val->intval, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07001908 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001909 smblib_err(chg, "Couldn't vote to %s USB rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001910 (bool)val->intval ? "suspend" : "resume", rc);
1911 return rc;
1912 }
1913
1914 rc = vote(chg->dc_suspend_votable, USER_VOTER, (bool)val->intval, 0);
1915 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001916 smblib_err(chg, "Couldn't vote to %s DC rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001917 (bool)val->intval ? "suspend" : "resume", rc);
1918 return rc;
1919 }
1920
Nicholas Troast61ff40f2016-07-08 10:59:22 -07001921 power_supply_changed(chg->batt_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07001922 return rc;
1923}
1924
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07001925int smblib_set_prop_batt_capacity(struct smb_charger *chg,
1926 const union power_supply_propval *val)
1927{
1928 chg->fake_capacity = val->intval;
1929
1930 power_supply_changed(chg->batt_psy);
1931
1932 return 0;
1933}
1934
Harry Yang589dd422017-07-28 18:41:42 -07001935int smblib_set_prop_batt_status(struct smb_charger *chg,
1936 const union power_supply_propval *val)
1937{
1938 /* Faking battery full */
1939 if (val->intval == POWER_SUPPLY_STATUS_FULL)
1940 chg->fake_batt_status = val->intval;
1941 else
1942 chg->fake_batt_status = -EINVAL;
1943
1944 power_supply_changed(chg->batt_psy);
1945
1946 return 0;
1947}
1948
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001949int smblib_set_prop_system_temp_level(struct smb_charger *chg,
1950 const union power_supply_propval *val)
1951{
1952 if (val->intval < 0)
1953 return -EINVAL;
1954
1955 if (chg->thermal_levels <= 0)
1956 return -EINVAL;
1957
1958 if (val->intval > chg->thermal_levels)
1959 return -EINVAL;
1960
1961 chg->system_temp_level = val->intval;
Ashay Jaiswal147a6c32017-03-28 17:19:47 +05301962 /* disable parallel charge in case of system temp level */
1963 vote(chg->pl_disable_votable, THERMAL_DAEMON_VOTER,
1964 chg->system_temp_level ? true : false, 0);
1965
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001966 if (chg->system_temp_level == chg->thermal_levels)
Harry Yangaba1f5f2016-09-28 10:47:29 -07001967 return vote(chg->chg_disable_votable,
1968 THERMAL_DAEMON_VOTER, true, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001969
Harry Yangaba1f5f2016-09-28 10:47:29 -07001970 vote(chg->chg_disable_votable, THERMAL_DAEMON_VOTER, false, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001971 if (chg->system_temp_level == 0)
Harry Yangaba1f5f2016-09-28 10:47:29 -07001972 return vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, false, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001973
Harry Yangaba1f5f2016-09-28 10:47:29 -07001974 vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, true,
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001975 chg->thermal_mitigation[chg->system_temp_level]);
1976 return 0;
1977}
1978
Harry Yang40192cb2017-02-25 23:25:17 -08001979int smblib_set_prop_charge_qnovo_enable(struct smb_charger *chg,
1980 const union power_supply_propval *val)
1981{
1982 int rc = 0;
1983
1984 rc = smblib_masked_write(chg, QNOVO_PT_ENABLE_CMD_REG,
1985 QNOVO_PT_ENABLE_CMD_BIT,
1986 val->intval ? QNOVO_PT_ENABLE_CMD_BIT : 0);
1987 if (rc < 0) {
1988 dev_err(chg->dev, "Couldn't enable qnovo rc=%d\n", rc);
1989 return rc;
1990 }
1991
1992 return rc;
1993}
1994
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07001995int smblib_set_prop_input_current_limited(struct smb_charger *chg,
1996 const union power_supply_propval *val)
1997{
1998 chg->fake_input_current_limited = val->intval;
1999 return 0;
2000}
2001
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302002int smblib_rerun_aicl(struct smb_charger *chg)
2003{
Nicholas Troast20ae1912017-02-15 10:15:32 -08002004 int rc, settled_icl_ua;
2005 u8 stat;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302006
Nicholas Troast20ae1912017-02-15 10:15:32 -08002007 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
2008 if (rc < 0) {
2009 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
2010 rc);
2011 return rc;
2012 }
2013
2014 /* USB is suspended so skip re-running AICL */
2015 if (stat & USBIN_SUSPEND_STS_BIT)
2016 return rc;
2017
2018 smblib_dbg(chg, PR_MISC, "re-running AICL\n");
Ashay Jaiswal59a14122017-05-16 13:38:52 +05302019 rc = smblib_get_charge_param(chg, &chg->param.icl_stat,
2020 &settled_icl_ua);
2021 if (rc < 0) {
2022 smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
2023 return rc;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302024 }
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302025
Ashay Jaiswal59a14122017-05-16 13:38:52 +05302026 vote(chg->usb_icl_votable, AICL_RERUN_VOTER, true,
2027 max(settled_icl_ua - chg->param.usb_icl.step_u,
2028 chg->param.usb_icl.step_u));
2029 vote(chg->usb_icl_votable, AICL_RERUN_VOTER, false, 0);
2030
Nicholas Troast20ae1912017-02-15 10:15:32 -08002031 return 0;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302032}
2033
2034static int smblib_dp_pulse(struct smb_charger *chg)
2035{
2036 int rc;
2037
2038 /* QC 3.0 increment */
2039 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, SINGLE_INCREMENT_BIT,
2040 SINGLE_INCREMENT_BIT);
2041 if (rc < 0)
2042 smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
2043 rc);
2044
2045 return rc;
2046}
2047
2048static int smblib_dm_pulse(struct smb_charger *chg)
2049{
2050 int rc;
2051
2052 /* QC 3.0 decrement */
2053 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, SINGLE_DECREMENT_BIT,
2054 SINGLE_DECREMENT_BIT);
2055 if (rc < 0)
2056 smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
2057 rc);
2058
2059 return rc;
2060}
2061
Ashay Jaiswalcf243372017-10-31 14:33:27 +05302062static int smblib_force_vbus_voltage(struct smb_charger *chg, u8 val)
2063{
2064 int rc;
2065
2066 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, val, val);
2067 if (rc < 0)
2068 smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
2069 rc);
2070
2071 return rc;
2072}
2073
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302074int smblib_dp_dm(struct smb_charger *chg, int val)
2075{
2076 int target_icl_ua, rc = 0;
Ashay Jaiswalae23a042017-05-18 15:28:31 +05302077 union power_supply_propval pval;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302078
2079 switch (val) {
2080 case POWER_SUPPLY_DP_DM_DP_PULSE:
2081 rc = smblib_dp_pulse(chg);
2082 if (!rc)
2083 chg->pulse_cnt++;
2084 smblib_dbg(chg, PR_PARALLEL, "DP_DM_DP_PULSE rc=%d cnt=%d\n",
2085 rc, chg->pulse_cnt);
2086 break;
2087 case POWER_SUPPLY_DP_DM_DM_PULSE:
2088 rc = smblib_dm_pulse(chg);
2089 if (!rc && chg->pulse_cnt)
2090 chg->pulse_cnt--;
2091 smblib_dbg(chg, PR_PARALLEL, "DP_DM_DM_PULSE rc=%d cnt=%d\n",
2092 rc, chg->pulse_cnt);
2093 break;
2094 case POWER_SUPPLY_DP_DM_ICL_DOWN:
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302095 target_icl_ua = get_effective_result(chg->usb_icl_votable);
Ashay Jaiswalae23a042017-05-18 15:28:31 +05302096 if (target_icl_ua < 0) {
2097 /* no client vote, get the ICL from charger */
2098 rc = power_supply_get_property(chg->usb_psy,
2099 POWER_SUPPLY_PROP_HW_CURRENT_MAX,
2100 &pval);
2101 if (rc < 0) {
2102 smblib_err(chg,
2103 "Couldn't get max current rc=%d\n",
2104 rc);
2105 return rc;
2106 }
2107 target_icl_ua = pval.intval;
2108 }
2109
2110 /*
2111 * Check if any other voter voted on USB_ICL in case of
2112 * voter other than SW_QC3_VOTER reset and restart reduction
2113 * again.
2114 */
2115 if (target_icl_ua != get_client_vote(chg->usb_icl_votable,
2116 SW_QC3_VOTER))
2117 chg->usb_icl_delta_ua = 0;
2118
2119 chg->usb_icl_delta_ua += 100000;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302120 vote(chg->usb_icl_votable, SW_QC3_VOTER, true,
Ashay Jaiswalae23a042017-05-18 15:28:31 +05302121 target_icl_ua - 100000);
2122 smblib_dbg(chg, PR_PARALLEL, "ICL DOWN ICL=%d reduction=%d\n",
2123 target_icl_ua, chg->usb_icl_delta_ua);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302124 break;
Ashay Jaiswalcf243372017-10-31 14:33:27 +05302125 case POWER_SUPPLY_DP_DM_FORCE_5V:
2126 rc = smblib_force_vbus_voltage(chg, FORCE_5V_BIT);
2127 if (rc < 0)
2128 pr_err("Failed to force 5V\n");
2129 break;
2130 case POWER_SUPPLY_DP_DM_FORCE_9V:
2131 rc = smblib_force_vbus_voltage(chg, FORCE_9V_BIT);
2132 if (rc < 0)
2133 pr_err("Failed to force 9V\n");
2134 break;
2135 case POWER_SUPPLY_DP_DM_FORCE_12V:
2136 rc = smblib_force_vbus_voltage(chg, FORCE_12V_BIT);
2137 if (rc < 0)
2138 pr_err("Failed to force 12V\n");
2139 break;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302140 case POWER_SUPPLY_DP_DM_ICL_UP:
2141 default:
2142 break;
2143 }
2144
2145 return rc;
2146}
2147
Abhijeet Dharmapurikar3a580042017-07-24 09:43:00 -07002148int smblib_disable_hw_jeita(struct smb_charger *chg, bool disable)
2149{
2150 int rc;
2151 u8 mask;
2152
2153 /*
2154 * Disable h/w base JEITA compensation if s/w JEITA is enabled
2155 */
2156 mask = JEITA_EN_COLD_SL_FCV_BIT
2157 | JEITA_EN_HOT_SL_FCV_BIT
2158 | JEITA_EN_HOT_SL_CCC_BIT
2159 | JEITA_EN_COLD_SL_CCC_BIT,
2160 rc = smblib_masked_write(chg, JEITA_EN_CFG_REG, mask,
2161 disable ? 0 : mask);
2162 if (rc < 0) {
2163 dev_err(chg->dev,
2164 "Couldn't configure s/w jeita rc=%d\n",
2165 rc);
2166 return rc;
2167 }
2168 return 0;
2169}
2170
Nicholas Troast34db5032016-03-28 12:26:44 -07002171/*******************
Harry Yangf3023592016-07-20 14:56:41 -07002172 * DC PSY GETTERS *
2173 *******************/
2174
2175int smblib_get_prop_dc_present(struct smb_charger *chg,
2176 union power_supply_propval *val)
2177{
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002178 int rc;
Harry Yangf3023592016-07-20 14:56:41 -07002179 u8 stat;
2180
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002181 rc = smblib_read(chg, DCIN_BASE + INT_RT_STS_OFFSET, &stat);
Harry Yangf3023592016-07-20 14:56:41 -07002182 if (rc < 0) {
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002183 smblib_err(chg, "Couldn't read DCIN_RT_STS rc=%d\n", rc);
Harry Yangf3023592016-07-20 14:56:41 -07002184 return rc;
2185 }
Harry Yangf3023592016-07-20 14:56:41 -07002186
2187 val->intval = (bool)(stat & DCIN_PLUGIN_RT_STS_BIT);
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002188 return 0;
Harry Yangf3023592016-07-20 14:56:41 -07002189}
2190
2191int smblib_get_prop_dc_online(struct smb_charger *chg,
2192 union power_supply_propval *val)
2193{
2194 int rc = 0;
2195 u8 stat;
2196
2197 if (get_client_vote(chg->dc_suspend_votable, USER_VOTER)) {
2198 val->intval = false;
2199 return rc;
2200 }
2201
2202 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
2203 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002204 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
Harry Yangf3023592016-07-20 14:56:41 -07002205 rc);
2206 return rc;
2207 }
2208 smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
2209 stat);
2210
2211 val->intval = (stat & USE_DCIN_BIT) &&
Vic Wei7ade2842016-12-14 18:47:49 -08002212 (stat & VALID_INPUT_POWER_SOURCE_STS_BIT);
Harry Yangf3023592016-07-20 14:56:41 -07002213
2214 return rc;
2215}
2216
2217int smblib_get_prop_dc_current_max(struct smb_charger *chg,
2218 union power_supply_propval *val)
2219{
2220 val->intval = get_effective_result_locked(chg->dc_icl_votable);
2221 return 0;
2222}
2223
2224/*******************
Harry Yangd89ff1f2016-12-05 14:59:11 -08002225 * DC PSY SETTERS *
Harry Yangf3023592016-07-20 14:56:41 -07002226 * *****************/
2227
2228int smblib_set_prop_dc_current_max(struct smb_charger *chg,
2229 const union power_supply_propval *val)
2230{
2231 int rc;
2232
2233 rc = vote(chg->dc_icl_votable, USER_VOTER, true, val->intval);
2234 return rc;
2235}
2236
2237/*******************
Nicholas Troast34db5032016-03-28 12:26:44 -07002238 * USB PSY GETTERS *
2239 *******************/
2240
2241int smblib_get_prop_usb_present(struct smb_charger *chg,
2242 union power_supply_propval *val)
2243{
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002244 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07002245 u8 stat;
2246
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002247 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
Nicholas Troast34db5032016-03-28 12:26:44 -07002248 if (rc < 0) {
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002249 smblib_err(chg, "Couldn't read USBIN_RT_STS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07002250 return rc;
2251 }
Nicholas Troast34db5032016-03-28 12:26:44 -07002252
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002253 val->intval = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
2254 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002255}
2256
2257int smblib_get_prop_usb_online(struct smb_charger *chg,
2258 union power_supply_propval *val)
2259{
2260 int rc = 0;
2261 u8 stat;
2262
Abhijeet Dharmapurikar84923af2017-03-23 14:07:07 -07002263 if (get_client_vote_locked(chg->usb_icl_votable, USER_VOTER) == 0) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002264 val->intval = false;
2265 return rc;
2266 }
2267
2268 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
2269 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002270 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002271 rc);
2272 return rc;
2273 }
2274 smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
2275 stat);
2276
2277 val->intval = (stat & USE_USBIN_BIT) &&
Vic Wei7ade2842016-12-14 18:47:49 -08002278 (stat & VALID_INPUT_POWER_SOURCE_STS_BIT);
Nicholas Troast34db5032016-03-28 12:26:44 -07002279 return rc;
2280}
2281
Nicholas Troast7f55c922017-07-25 13:18:03 -07002282int smblib_get_prop_usb_voltage_max(struct smb_charger *chg,
2283 union power_supply_propval *val)
2284{
2285 switch (chg->real_charger_type) {
2286 case POWER_SUPPLY_TYPE_USB_HVDCP:
Ashay Jaiswal3c82d282017-11-28 22:07:36 +05302287 case POWER_SUPPLY_TYPE_USB_HVDCP_3:
Nicholas Troast7f55c922017-07-25 13:18:03 -07002288 case POWER_SUPPLY_TYPE_USB_PD:
2289 if (chg->smb_version == PM660_SUBTYPE)
2290 val->intval = MICRO_9V;
2291 else
2292 val->intval = MICRO_12V;
2293 break;
2294 default:
2295 val->intval = MICRO_5V;
2296 break;
2297 }
2298
2299 return 0;
2300}
2301
Nicholas Troast34db5032016-03-28 12:26:44 -07002302int smblib_get_prop_usb_voltage_now(struct smb_charger *chg,
2303 union power_supply_propval *val)
2304{
Harry Yangba874ce2016-08-19 14:17:01 -07002305 if (!chg->iio.usbin_v_chan ||
2306 PTR_ERR(chg->iio.usbin_v_chan) == -EPROBE_DEFER)
2307 chg->iio.usbin_v_chan = iio_channel_get(chg->dev, "usbin_v");
2308
2309 if (IS_ERR(chg->iio.usbin_v_chan))
2310 return PTR_ERR(chg->iio.usbin_v_chan);
2311
2312 return iio_read_channel_processed(chg->iio.usbin_v_chan, &val->intval);
Nicholas Troast34db5032016-03-28 12:26:44 -07002313}
2314
Harry Yangba874ce2016-08-19 14:17:01 -07002315int smblib_get_prop_usb_current_now(struct smb_charger *chg,
2316 union power_supply_propval *val)
2317{
2318 int rc = 0;
2319
2320 rc = smblib_get_prop_usb_present(chg, val);
2321 if (rc < 0 || !val->intval)
2322 return rc;
2323
2324 if (!chg->iio.usbin_i_chan ||
2325 PTR_ERR(chg->iio.usbin_i_chan) == -EPROBE_DEFER)
2326 chg->iio.usbin_i_chan = iio_channel_get(chg->dev, "usbin_i");
2327
2328 if (IS_ERR(chg->iio.usbin_i_chan))
2329 return PTR_ERR(chg->iio.usbin_i_chan);
2330
2331 return iio_read_channel_processed(chg->iio.usbin_i_chan, &val->intval);
2332}
2333
2334int smblib_get_prop_charger_temp(struct smb_charger *chg,
2335 union power_supply_propval *val)
2336{
2337 int rc;
2338
2339 if (!chg->iio.temp_chan ||
2340 PTR_ERR(chg->iio.temp_chan) == -EPROBE_DEFER)
2341 chg->iio.temp_chan = iio_channel_get(chg->dev, "charger_temp");
2342
2343 if (IS_ERR(chg->iio.temp_chan))
2344 return PTR_ERR(chg->iio.temp_chan);
2345
2346 rc = iio_read_channel_processed(chg->iio.temp_chan, &val->intval);
2347 val->intval /= 100;
2348 return rc;
2349}
2350
2351int smblib_get_prop_charger_temp_max(struct smb_charger *chg,
2352 union power_supply_propval *val)
2353{
2354 int rc;
2355
2356 if (!chg->iio.temp_max_chan ||
2357 PTR_ERR(chg->iio.temp_max_chan) == -EPROBE_DEFER)
2358 chg->iio.temp_max_chan = iio_channel_get(chg->dev,
2359 "charger_temp_max");
2360 if (IS_ERR(chg->iio.temp_max_chan))
2361 return PTR_ERR(chg->iio.temp_max_chan);
2362
2363 rc = iio_read_channel_processed(chg->iio.temp_max_chan, &val->intval);
2364 val->intval /= 100;
2365 return rc;
2366}
2367
Nicholas Troast34db5032016-03-28 12:26:44 -07002368int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
2369 union power_supply_propval *val)
2370{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002371 if (chg->typec_status[3] & CC_ATTACHED_BIT)
2372 val->intval =
2373 (bool)(chg->typec_status[3] & CC_ORIENTATION_BIT) + 1;
Nicholas Troast34db5032016-03-28 12:26:44 -07002374 else
2375 val->intval = 0;
2376
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002377 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002378}
2379
2380static const char * const smblib_typec_mode_name[] = {
2381 [POWER_SUPPLY_TYPEC_NONE] = "NONE",
2382 [POWER_SUPPLY_TYPEC_SOURCE_DEFAULT] = "SOURCE_DEFAULT",
2383 [POWER_SUPPLY_TYPEC_SOURCE_MEDIUM] = "SOURCE_MEDIUM",
2384 [POWER_SUPPLY_TYPEC_SOURCE_HIGH] = "SOURCE_HIGH",
2385 [POWER_SUPPLY_TYPEC_NON_COMPLIANT] = "NON_COMPLIANT",
2386 [POWER_SUPPLY_TYPEC_SINK] = "SINK",
2387 [POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE] = "SINK_POWERED_CABLE",
2388 [POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY] = "SINK_DEBUG_ACCESSORY",
2389 [POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER] = "SINK_AUDIO_ADAPTER",
2390 [POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY] = "POWERED_CABLE_ONLY",
2391};
2392
2393static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
2394{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002395 switch (chg->typec_status[0]) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002396 case UFP_TYPEC_RDSTD_BIT:
2397 return POWER_SUPPLY_TYPEC_SOURCE_DEFAULT;
2398 case UFP_TYPEC_RD1P5_BIT:
2399 return POWER_SUPPLY_TYPEC_SOURCE_MEDIUM;
2400 case UFP_TYPEC_RD3P0_BIT:
2401 return POWER_SUPPLY_TYPEC_SOURCE_HIGH;
2402 default:
2403 break;
2404 }
2405
Nicholas Troaste1932e42017-04-12 12:38:18 -07002406 return POWER_SUPPLY_TYPEC_NONE;
Nicholas Troast34db5032016-03-28 12:26:44 -07002407}
2408
2409static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
2410{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002411 switch (chg->typec_status[1] & DFP_TYPEC_MASK) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002412 case DFP_RA_RA_BIT:
2413 return POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER;
2414 case DFP_RD_RD_BIT:
2415 return POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY;
2416 case DFP_RD_RA_VCONN_BIT:
2417 return POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE;
2418 case DFP_RD_OPEN_BIT:
2419 return POWER_SUPPLY_TYPEC_SINK;
Nicholas Troast34db5032016-03-28 12:26:44 -07002420 default:
2421 break;
2422 }
2423
2424 return POWER_SUPPLY_TYPEC_NONE;
2425}
2426
Nicholas Troaste1932e42017-04-12 12:38:18 -07002427static int smblib_get_prop_typec_mode(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07002428{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002429 if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
Nicholas Troaste1932e42017-04-12 12:38:18 -07002430 return smblib_get_prop_dfp_mode(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07002431 else
Nicholas Troaste1932e42017-04-12 12:38:18 -07002432 return smblib_get_prop_ufp_mode(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07002433}
2434
2435int smblib_get_prop_typec_power_role(struct smb_charger *chg,
2436 union power_supply_propval *val)
2437{
2438 int rc = 0;
2439 u8 ctrl;
2440
2441 rc = smblib_read(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &ctrl);
2442 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002443 smblib_err(chg, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002444 rc);
2445 return rc;
2446 }
2447 smblib_dbg(chg, PR_REGISTER, "TYPE_C_INTRPT_ENB_SOFTWARE_CTRL = 0x%02x\n",
2448 ctrl);
2449
2450 if (ctrl & TYPEC_DISABLE_CMD_BIT) {
2451 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
2452 return rc;
2453 }
2454
2455 switch (ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT)) {
2456 case 0:
2457 val->intval = POWER_SUPPLY_TYPEC_PR_DUAL;
2458 break;
2459 case DFP_EN_CMD_BIT:
2460 val->intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
2461 break;
2462 case UFP_EN_CMD_BIT:
2463 val->intval = POWER_SUPPLY_TYPEC_PR_SINK;
2464 break;
2465 default:
2466 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002467 smblib_err(chg, "unsupported power role 0x%02lx\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002468 ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT));
2469 return -EINVAL;
2470 }
2471
2472 return rc;
2473}
2474
2475int smblib_get_prop_pd_allowed(struct smb_charger *chg,
2476 union power_supply_propval *val)
2477{
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07002478 val->intval = get_effective_result(chg->pd_allowed_votable);
Nicholas Troast34db5032016-03-28 12:26:44 -07002479 return 0;
2480}
2481
Nicholas Troast133a7f52016-06-29 13:48:20 -07002482int smblib_get_prop_input_current_settled(struct smb_charger *chg,
2483 union power_supply_propval *val)
2484{
2485 return smblib_get_charge_param(chg, &chg->param.icl_stat, &val->intval);
2486}
2487
Fenglin Wuef4730e2017-01-11 18:16:25 +08002488#define HVDCP3_STEP_UV 200000
2489int smblib_get_prop_input_voltage_settled(struct smb_charger *chg,
2490 union power_supply_propval *val)
2491{
Fenglin Wuef4730e2017-01-11 18:16:25 +08002492 int rc, pulses;
Fenglin Wuef4730e2017-01-11 18:16:25 +08002493
Nicholas Troast5f314c12017-05-25 11:58:02 -07002494 switch (chg->real_charger_type) {
Fenglin Wuef4730e2017-01-11 18:16:25 +08002495 case POWER_SUPPLY_TYPE_USB_HVDCP_3:
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +05302496 rc = smblib_get_pulse_cnt(chg, &pulses);
Fenglin Wuef4730e2017-01-11 18:16:25 +08002497 if (rc < 0) {
2498 smblib_err(chg,
2499 "Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
2500 return 0;
2501 }
Fenglin Wuef4730e2017-01-11 18:16:25 +08002502 val->intval = MICRO_5V + HVDCP3_STEP_UV * pulses;
2503 break;
Nicholas Troast5f314c12017-05-25 11:58:02 -07002504 case POWER_SUPPLY_TYPE_USB_PD:
2505 val->intval = chg->voltage_min_uv;
2506 break;
Fenglin Wuef4730e2017-01-11 18:16:25 +08002507 default:
2508 val->intval = MICRO_5V;
2509 break;
2510 }
2511
2512 return 0;
2513}
2514
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002515int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg,
2516 union power_supply_propval *val)
2517{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002518 val->intval = chg->pd_hard_reset;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002519 return 0;
2520}
2521
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07002522int smblib_get_pe_start(struct smb_charger *chg,
2523 union power_supply_propval *val)
2524{
2525 /*
2526 * hvdcp timeout voter is the last one to allow pd. Use its vote
2527 * to indicate start of pe engine
2528 */
2529 val->intval
2530 = !get_client_vote_locked(chg->pd_disallowed_votable_indirect,
2531 HVDCP_TIMEOUT_VOTER);
2532 return 0;
2533}
2534
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002535int smblib_get_prop_die_health(struct smb_charger *chg,
Nicholas Troastb021dd92017-01-31 18:43:38 -08002536 union power_supply_propval *val)
2537{
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002538 int rc;
Nicholas Troastb021dd92017-01-31 18:43:38 -08002539 u8 stat;
2540
2541 rc = smblib_read(chg, TEMP_RANGE_STATUS_REG, &stat);
2542 if (rc < 0) {
2543 smblib_err(chg, "Couldn't read TEMP_RANGE_STATUS_REG rc=%d\n",
2544 rc);
2545 return rc;
2546 }
2547
Harry Yang6ed35462017-11-16 23:01:39 -08002548 if (stat & ALERT_LEVEL_BIT)
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002549 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
Harry Yang6ed35462017-11-16 23:01:39 -08002550 else if (stat & TEMP_ABOVE_RANGE_BIT)
2551 val->intval = POWER_SUPPLY_HEALTH_HOT;
2552 else if (stat & TEMP_WITHIN_RANGE_BIT)
2553 val->intval = POWER_SUPPLY_HEALTH_WARM;
2554 else if (stat & TEMP_BELOW_RANGE_BIT)
2555 val->intval = POWER_SUPPLY_HEALTH_COOL;
2556 else
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002557 val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
Nicholas Troastb021dd92017-01-31 18:43:38 -08002558
Nicholas Troastb021dd92017-01-31 18:43:38 -08002559 return 0;
2560}
2561
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05302562#define SDP_CURRENT_UA 500000
2563#define CDP_CURRENT_UA 1500000
2564#define DCP_CURRENT_UA 1500000
2565#define HVDCP_CURRENT_UA 3000000
2566#define TYPEC_DEFAULT_CURRENT_UA 900000
2567#define TYPEC_MEDIUM_CURRENT_UA 1500000
2568#define TYPEC_HIGH_CURRENT_UA 3000000
2569static int get_rp_based_dcp_current(struct smb_charger *chg, int typec_mode)
2570{
2571 int rp_ua;
2572
2573 switch (typec_mode) {
2574 case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
2575 rp_ua = TYPEC_HIGH_CURRENT_UA;
2576 break;
2577 case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
2578 case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
2579 /* fall through */
2580 default:
2581 rp_ua = DCP_CURRENT_UA;
2582 }
2583
2584 return rp_ua;
2585}
2586
Nicholas Troast34db5032016-03-28 12:26:44 -07002587/*******************
2588 * USB PSY SETTERS *
2589 * *****************/
2590
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002591int smblib_set_prop_pd_current_max(struct smb_charger *chg,
2592 const union power_supply_propval *val)
2593{
2594 int rc;
2595
2596 if (chg->pd_active)
2597 rc = vote(chg->usb_icl_votable, PD_VOTER, true, val->intval);
2598 else
2599 rc = -EPERM;
2600
2601 return rc;
2602}
2603
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05302604static int smblib_handle_usb_current(struct smb_charger *chg,
2605 int usb_current)
2606{
2607 int rc = 0, rp_ua, typec_mode;
2608
2609 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_FLOAT) {
2610 if (usb_current == -ETIMEDOUT) {
2611 /*
2612 * Valid FLOAT charger, report the current based
2613 * of Rp
2614 */
2615 typec_mode = smblib_get_prop_typec_mode(chg);
2616 rp_ua = get_rp_based_dcp_current(chg, typec_mode);
2617 rc = vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER,
2618 true, rp_ua);
2619 if (rc < 0)
2620 return rc;
2621 } else {
2622 /*
2623 * FLOAT charger detected as SDP by USB driver,
2624 * charge with the requested current and update the
2625 * real_charger_type
2626 */
2627 chg->real_charger_type = POWER_SUPPLY_TYPE_USB;
2628 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
2629 true, usb_current);
2630 if (rc < 0)
2631 return rc;
2632 rc = vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER,
2633 false, 0);
2634 if (rc < 0)
2635 return rc;
2636 }
2637 } else {
2638 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
2639 true, usb_current);
2640 }
2641
2642 return rc;
2643}
2644
Nicholas Troast7f55c922017-07-25 13:18:03 -07002645int smblib_set_prop_sdp_current_max(struct smb_charger *chg,
Nicholas Troast34db5032016-03-28 12:26:44 -07002646 const union power_supply_propval *val)
2647{
Nicholas Troast8d33b7d2017-01-16 11:18:38 -08002648 int rc = 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002649
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002650 if (!chg->pd_active) {
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05302651 rc = smblib_handle_usb_current(chg, val->intval);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002652 } else if (chg->system_suspend_supported) {
2653 if (val->intval <= USBIN_25MA)
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302654 rc = vote(chg->usb_icl_votable,
2655 PD_SUSPEND_SUPPORTED_VOTER, true, val->intval);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002656 else
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302657 rc = vote(chg->usb_icl_votable,
2658 PD_SUSPEND_SUPPORTED_VOTER, false, 0);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002659 }
Nicholas Troast34db5032016-03-28 12:26:44 -07002660 return rc;
2661}
2662
Harry Yangd89ff1f2016-12-05 14:59:11 -08002663int smblib_set_prop_boost_current(struct smb_charger *chg,
2664 const union power_supply_propval *val)
2665{
2666 int rc = 0;
2667
2668 rc = smblib_set_charge_param(chg, &chg->param.freq_boost,
2669 val->intval <= chg->boost_threshold_ua ?
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05302670 chg->chg_freq.freq_below_otg_threshold :
2671 chg->chg_freq.freq_above_otg_threshold);
Harry Yangd89ff1f2016-12-05 14:59:11 -08002672 if (rc < 0) {
2673 dev_err(chg->dev, "Error in setting freq_boost rc=%d\n", rc);
2674 return rc;
2675 }
2676
2677 chg->boost_current_ua = val->intval;
2678 return rc;
2679}
2680
Nicholas Troast34db5032016-03-28 12:26:44 -07002681int smblib_set_prop_typec_power_role(struct smb_charger *chg,
2682 const union power_supply_propval *val)
2683{
2684 int rc = 0;
2685 u8 power_role;
2686
2687 switch (val->intval) {
2688 case POWER_SUPPLY_TYPEC_PR_NONE:
2689 power_role = TYPEC_DISABLE_CMD_BIT;
2690 break;
2691 case POWER_SUPPLY_TYPEC_PR_DUAL:
2692 power_role = 0;
2693 break;
2694 case POWER_SUPPLY_TYPEC_PR_SINK:
2695 power_role = UFP_EN_CMD_BIT;
2696 break;
2697 case POWER_SUPPLY_TYPEC_PR_SOURCE:
2698 power_role = DFP_EN_CMD_BIT;
2699 break;
2700 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002701 smblib_err(chg, "power role %d not supported\n", val->intval);
Nicholas Troast34db5032016-03-28 12:26:44 -07002702 return -EINVAL;
2703 }
2704
Jack Pham54a39bd2017-03-29 18:59:37 -07002705 if (power_role == UFP_EN_CMD_BIT) {
2706 /* disable PBS workaround when forcing sink mode */
2707 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0x0);
2708 if (rc < 0) {
2709 smblib_err(chg, "Couldn't write to TM_IO_DTEST4_SEL rc=%d\n",
2710 rc);
2711 }
2712 } else {
2713 /* restore it back to 0xA5 */
2714 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
2715 if (rc < 0) {
2716 smblib_err(chg, "Couldn't write to TM_IO_DTEST4_SEL rc=%d\n",
2717 rc);
2718 }
2719 }
2720
Nicholas Troast34db5032016-03-28 12:26:44 -07002721 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2722 TYPEC_POWER_ROLE_CMD_MASK, power_role);
2723 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002724 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 -07002725 power_role, rc);
2726 return rc;
2727 }
2728
2729 return rc;
2730}
2731
Nicholas Troast7f55c922017-07-25 13:18:03 -07002732int smblib_set_prop_pd_voltage_min(struct smb_charger *chg,
Nicholas Troast34db5032016-03-28 12:26:44 -07002733 const union power_supply_propval *val)
2734{
2735 int rc, min_uv;
2736
2737 min_uv = min(val->intval, chg->voltage_max_uv);
2738 rc = smblib_set_usb_pd_allowed_voltage(chg, min_uv,
2739 chg->voltage_max_uv);
2740 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002741 smblib_err(chg, "invalid max voltage %duV rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002742 val->intval, rc);
2743 return rc;
2744 }
2745
Harry Yangaba1f5f2016-09-28 10:47:29 -07002746 chg->voltage_min_uv = min_uv;
Nicholas Troast5f314c12017-05-25 11:58:02 -07002747 power_supply_changed(chg->usb_main_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07002748 return rc;
2749}
2750
Nicholas Troast7f55c922017-07-25 13:18:03 -07002751int smblib_set_prop_pd_voltage_max(struct smb_charger *chg,
Nicholas Troast34db5032016-03-28 12:26:44 -07002752 const union power_supply_propval *val)
2753{
2754 int rc, max_uv;
2755
2756 max_uv = max(val->intval, chg->voltage_min_uv);
2757 rc = smblib_set_usb_pd_allowed_voltage(chg, chg->voltage_min_uv,
2758 max_uv);
2759 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002760 smblib_err(chg, "invalid min voltage %duV rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002761 val->intval, rc);
2762 return rc;
2763 }
2764
Harry Yangaba1f5f2016-09-28 10:47:29 -07002765 chg->voltage_max_uv = max_uv;
Nicholas Troast34db5032016-03-28 12:26:44 -07002766 return rc;
2767}
2768
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07002769static int __smblib_set_prop_pd_active(struct smb_charger *chg, bool pd_active)
Nicholas Troast34db5032016-03-28 12:26:44 -07002770{
2771 int rc;
Nicholas Troaste1932e42017-04-12 12:38:18 -07002772 bool orientation, sink_attached, hvdcp;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002773 u8 stat;
Nicholas Troast34db5032016-03-28 12:26:44 -07002774
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07002775 chg->pd_active = pd_active;
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002776 if (chg->pd_active) {
2777 vote(chg->apsd_disable_votable, PD_VOTER, true, 0);
2778 vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
2779 vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
2780
2781 /*
2782 * VCONN_EN_ORIENTATION_BIT controls whether to use CC1 or CC2
2783 * line when TYPEC_SPARE_CFG_BIT (CC pin selection s/w override)
2784 * is set or when VCONN_EN_VALUE_BIT is set.
2785 */
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002786 orientation = chg->typec_status[3] & CC_ORIENTATION_BIT;
Harry Yang88acff42016-09-21 14:56:06 -07002787 rc = smblib_masked_write(chg,
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07002788 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2789 VCONN_EN_ORIENTATION_BIT,
2790 orientation ? 0 : VCONN_EN_ORIENTATION_BIT);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002791 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002792 smblib_err(chg,
Harry Yang88acff42016-09-21 14:56:06 -07002793 "Couldn't enable vconn on CC line rc=%d\n", rc);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002794
2795 /* SW controlled CC_OUT */
2796 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
2797 TYPEC_SPARE_CFG_BIT, TYPEC_SPARE_CFG_BIT);
2798 if (rc < 0)
2799 smblib_err(chg, "Couldn't enable SW cc_out rc=%d\n",
2800 rc);
2801
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302802 /*
2803 * Enforce 500mA for PD until the real vote comes in later.
2804 * It is guaranteed that pd_active is set prior to
2805 * pd_current_max
2806 */
Harry Yangcd995202016-11-07 13:32:52 -08002807 rc = vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002808 if (rc < 0)
Harry Yangcd995202016-11-07 13:32:52 -08002809 smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n",
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002810 rc);
Harry Yangcd995202016-11-07 13:32:52 -08002811
Nicholas Troastf9e44992017-03-14 09:06:56 -07002812 /* since PD was found the cable must be non-legacy */
2813 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
2814
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002815 /* clear USB ICL vote for DCP_VOTER */
Harry Yang631b99e2016-11-17 11:24:25 -08002816 rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002817 if (rc < 0)
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002818 smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n",
2819 rc);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002820
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302821 /* remove USB_PSY_VOTER */
2822 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002823 if (rc < 0)
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302824 smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002825 } else {
Nicholas Troaste1932e42017-04-12 12:38:18 -07002826 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
2827 if (rc < 0) {
2828 smblib_err(chg, "Couldn't read APSD status rc=%d\n",
2829 rc);
2830 return rc;
2831 }
2832
2833 hvdcp = stat & QC_CHARGER_BIT;
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002834 vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
2835 vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
Harry Yang7b429572017-09-12 11:15:04 -07002836 vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002837 vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER,
2838 false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002839
2840 /* HW controlled CC_OUT */
2841 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
2842 TYPEC_SPARE_CFG_BIT, 0);
2843 if (rc < 0)
2844 smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n",
2845 rc);
2846
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002847 /*
2848 * This WA should only run for HVDCP. Non-legacy SDP/CDP could
2849 * draw more, but this WA will remove Rd causing VBUS to drop,
2850 * and data could be interrupted. Non-legacy DCP could also draw
2851 * more, but it may impact compliance.
2852 */
Nicholas Troaste1932e42017-04-12 12:38:18 -07002853 sink_attached = chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT;
Ashay Jaiswal8207ee42017-11-27 11:41:27 +05302854 if ((chg->connector_type != POWER_SUPPLY_CONNECTOR_MICRO_USB)
2855 && !chg->typec_legacy_valid
2856 && !sink_attached && hvdcp)
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002857 schedule_work(&chg->legacy_detection_work);
Harry Yang88acff42016-09-21 14:56:06 -07002858 }
2859
Harry Yang6607b4a2016-05-17 17:50:09 -07002860 smblib_update_usb_type(chg);
Abhijeet Dharmapurikar76e2af52016-10-06 17:25:01 -07002861 power_supply_changed(chg->usb_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07002862 return rc;
2863}
2864
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07002865int smblib_set_prop_pd_active(struct smb_charger *chg,
2866 const union power_supply_propval *val)
2867{
2868 if (!get_effective_result(chg->pd_allowed_votable))
2869 return -EINVAL;
2870
2871 return __smblib_set_prop_pd_active(chg, val->intval);
2872}
2873
Fenglin Wuedd70792016-11-22 13:16:19 +08002874int smblib_set_prop_ship_mode(struct smb_charger *chg,
2875 const union power_supply_propval *val)
2876{
2877 int rc;
2878
2879 smblib_dbg(chg, PR_MISC, "Set ship mode: %d!!\n", !!val->intval);
2880
2881 rc = smblib_masked_write(chg, SHIP_MODE_REG, SHIP_MODE_EN_BIT,
2882 !!val->intval ? SHIP_MODE_EN_BIT : 0);
2883 if (rc < 0)
2884 dev_err(chg->dev, "Couldn't %s ship mode, rc=%d\n",
2885 !!val->intval ? "enable" : "disable", rc);
2886
2887 return rc;
2888}
2889
Harry Yang5e2bb712016-10-18 16:47:48 -07002890int smblib_reg_block_update(struct smb_charger *chg,
2891 struct reg_info *entry)
2892{
2893 int rc = 0;
2894
2895 while (entry && entry->reg) {
2896 rc = smblib_read(chg, entry->reg, &entry->bak);
2897 if (rc < 0) {
2898 dev_err(chg->dev, "Error in reading %s rc=%d\n",
2899 entry->desc, rc);
2900 break;
2901 }
2902 entry->bak &= entry->mask;
2903
2904 rc = smblib_masked_write(chg, entry->reg,
2905 entry->mask, entry->val);
2906 if (rc < 0) {
2907 dev_err(chg->dev, "Error in writing %s rc=%d\n",
2908 entry->desc, rc);
2909 break;
2910 }
2911 entry++;
2912 }
2913
2914 return rc;
2915}
2916
2917int smblib_reg_block_restore(struct smb_charger *chg,
2918 struct reg_info *entry)
2919{
2920 int rc = 0;
2921
2922 while (entry && entry->reg) {
2923 rc = smblib_masked_write(chg, entry->reg,
2924 entry->mask, entry->bak);
2925 if (rc < 0) {
2926 dev_err(chg->dev, "Error in writing %s rc=%d\n",
2927 entry->desc, rc);
2928 break;
2929 }
2930 entry++;
2931 }
2932
2933 return rc;
2934}
2935
Harry Yang755a34b2016-11-01 01:18:51 -07002936static struct reg_info cc2_detach_settings[] = {
2937 {
2938 .reg = TYPE_C_CFG_2_REG,
2939 .mask = TYPE_C_UFP_MODE_BIT | EN_TRY_SOURCE_MODE_BIT,
2940 .val = TYPE_C_UFP_MODE_BIT,
2941 .desc = "TYPE_C_CFG_2_REG",
2942 },
2943 {
2944 .reg = TYPE_C_CFG_3_REG,
2945 .mask = EN_TRYSINK_MODE_BIT,
2946 .val = 0,
2947 .desc = "TYPE_C_CFG_3_REG",
2948 },
2949 {
2950 .reg = TAPER_TIMER_SEL_CFG_REG,
2951 .mask = TYPEC_SPARE_CFG_BIT,
2952 .val = TYPEC_SPARE_CFG_BIT,
2953 .desc = "TAPER_TIMER_SEL_CFG_REG",
2954 },
2955 {
2956 .reg = TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2957 .mask = VCONN_EN_ORIENTATION_BIT,
2958 .val = 0,
2959 .desc = "TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG",
2960 },
2961 {
2962 .reg = MISC_CFG_REG,
2963 .mask = TCC_DEBOUNCE_20MS_BIT,
2964 .val = TCC_DEBOUNCE_20MS_BIT,
2965 .desc = "Tccdebounce time"
2966 },
2967 {
2968 },
2969};
2970
2971static int smblib_cc2_sink_removal_enter(struct smb_charger *chg)
2972{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002973 int rc, ccout, ufp_mode;
2974 u8 stat;
Harry Yang755a34b2016-11-01 01:18:51 -07002975
2976 if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002977 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002978
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002979 if (chg->cc2_detach_wa_active)
2980 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002981
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002982 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
Harry Yang755a34b2016-11-01 01:18:51 -07002983 if (rc < 0) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002984 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
Harry Yang755a34b2016-11-01 01:18:51 -07002985 return rc;
2986 }
Nicholas Troaste1932e42017-04-12 12:38:18 -07002987
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002988 ccout = (stat & CC_ATTACHED_BIT) ?
2989 (!!(stat & CC_ORIENTATION_BIT) + 1) : 0;
2990 ufp_mode = (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT) ?
2991 !(stat & UFP_DFP_MODE_STATUS_BIT) : 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002992
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002993 if (ccout != 2)
2994 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002995
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002996 if (!ufp_mode)
2997 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002998
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002999 chg->cc2_detach_wa_active = true;
3000 /* The CC2 removal WA will cause a type-c-change IRQ storm */
3001 smblib_reg_block_update(chg, cc2_detach_settings);
3002 schedule_work(&chg->rdstd_cc2_detach_work);
Harry Yang755a34b2016-11-01 01:18:51 -07003003 return rc;
3004}
3005
3006static int smblib_cc2_sink_removal_exit(struct smb_charger *chg)
3007{
Harry Yang755a34b2016-11-01 01:18:51 -07003008 if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003009 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07003010
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003011 if (!chg->cc2_detach_wa_active)
3012 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07003013
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003014 chg->cc2_detach_wa_active = false;
3015 cancel_work_sync(&chg->rdstd_cc2_detach_work);
3016 smblib_reg_block_restore(chg, cc2_detach_settings);
3017 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07003018}
3019
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07003020int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
3021 const union power_supply_propval *val)
3022{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003023 int rc = 0;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07003024
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003025 if (chg->pd_hard_reset == val->intval)
3026 return rc;
3027
3028 chg->pd_hard_reset = val->intval;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07003029 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003030 EXIT_SNK_BASED_ON_CC_BIT,
3031 (chg->pd_hard_reset) ? EXIT_SNK_BASED_ON_CC_BIT : 0);
3032 if (rc < 0)
3033 smblib_err(chg, "Couldn't set EXIT_SNK_BASED_ON_CC rc=%d\n",
Harry Yang755a34b2016-11-01 01:18:51 -07003034 rc);
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07003035
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003036 vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER,
3037 chg->pd_hard_reset, 0);
Harry Yang755a34b2016-11-01 01:18:51 -07003038
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07003039 return rc;
3040}
3041
Anirudh Ghayal941acaa2017-07-19 16:04:44 +05303042static int smblib_recover_from_soft_jeita(struct smb_charger *chg)
3043{
3044 u8 stat_1, stat_2;
3045 int rc;
3046
3047 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat_1);
3048 if (rc < 0) {
3049 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
3050 rc);
3051 return rc;
3052 }
3053
3054 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat_2);
3055 if (rc < 0) {
3056 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
3057 rc);
3058 return rc;
3059 }
3060
3061 if ((chg->jeita_status && !(stat_2 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK) &&
3062 ((stat_1 & BATTERY_CHARGER_STATUS_MASK) == TERMINATE_CHARGE))) {
3063 /*
3064 * We are moving from JEITA soft -> Normal and charging
3065 * is terminated
3066 */
3067 rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG, 0);
3068 if (rc < 0) {
3069 smblib_err(chg, "Couldn't disable charging rc=%d\n",
3070 rc);
3071 return rc;
3072 }
3073 rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG,
3074 CHARGING_ENABLE_CMD_BIT);
3075 if (rc < 0) {
3076 smblib_err(chg, "Couldn't enable charging rc=%d\n",
3077 rc);
3078 return rc;
3079 }
3080 }
3081
3082 chg->jeita_status = stat_2 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK;
3083
3084 return 0;
3085}
3086
Nicholas Troast7dbcad22016-10-05 13:30:18 -07003087/************************
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003088 * USB MAIN PSY GETTERS *
3089 ************************/
3090int smblib_get_prop_fcc_delta(struct smb_charger *chg,
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05303091 union power_supply_propval *val)
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003092{
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05303093 int rc, jeita_cc_delta_ua = 0;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003094
Harry Yang0d189772017-10-06 12:42:10 -07003095 if (chg->sw_jeita_enabled) {
3096 val->intval = 0;
3097 return 0;
3098 }
3099
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003100 rc = smblib_get_jeita_cc_delta(chg, &jeita_cc_delta_ua);
3101 if (rc < 0) {
3102 smblib_err(chg, "Couldn't get jeita cc delta rc=%d\n", rc);
3103 jeita_cc_delta_ua = 0;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003104 }
3105
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05303106 val->intval = jeita_cc_delta_ua;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003107 return 0;
3108}
3109
3110/************************
3111 * USB MAIN PSY SETTERS *
3112 ************************/
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003113int smblib_get_charge_current(struct smb_charger *chg,
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003114 int *total_current_ua)
3115{
Ashay Jaiswal7b6eb962017-04-26 14:34:29 +05303116 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003117 union power_supply_propval val = {0, };
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003118 int rc = 0, typec_source_rd, current_ua;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003119 bool non_compliant;
3120 u8 stat5;
3121
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003122 if (chg->pd_active) {
3123 *total_current_ua =
3124 get_client_vote_locked(chg->usb_icl_votable, PD_VOTER);
3125 return rc;
3126 }
3127
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003128 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
3129 if (rc < 0) {
3130 smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc);
3131 return rc;
3132 }
3133 non_compliant = stat5 & TYPEC_NONCOMP_LEGACY_CABLE_STATUS_BIT;
3134
3135 /* get settled ICL */
3136 rc = smblib_get_prop_input_current_settled(chg, &val);
3137 if (rc < 0) {
3138 smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
3139 return rc;
3140 }
3141
3142 typec_source_rd = smblib_get_prop_ufp_mode(chg);
3143
3144 /* QC 2.0/3.0 adapter */
3145 if (apsd_result->bit & (QC_3P0_BIT | QC_2P0_BIT)) {
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303146 *total_current_ua = HVDCP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003147 return 0;
3148 }
3149
3150 if (non_compliant) {
3151 switch (apsd_result->bit) {
3152 case CDP_CHARGER_BIT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303153 current_ua = CDP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003154 break;
3155 case DCP_CHARGER_BIT:
3156 case OCP_CHARGER_BIT:
3157 case FLOAT_CHARGER_BIT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303158 current_ua = DCP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003159 break;
3160 default:
3161 current_ua = 0;
3162 break;
3163 }
3164
3165 *total_current_ua = max(current_ua, val.intval);
3166 return 0;
3167 }
3168
3169 switch (typec_source_rd) {
3170 case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
3171 switch (apsd_result->bit) {
3172 case CDP_CHARGER_BIT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303173 current_ua = CDP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003174 break;
3175 case DCP_CHARGER_BIT:
3176 case OCP_CHARGER_BIT:
3177 case FLOAT_CHARGER_BIT:
3178 current_ua = chg->default_icl_ua;
3179 break;
3180 default:
3181 current_ua = 0;
3182 break;
3183 }
3184 break;
3185 case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303186 current_ua = TYPEC_MEDIUM_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003187 break;
3188 case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303189 current_ua = TYPEC_HIGH_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003190 break;
3191 case POWER_SUPPLY_TYPEC_NON_COMPLIANT:
3192 case POWER_SUPPLY_TYPEC_NONE:
3193 default:
3194 current_ua = 0;
3195 break;
3196 }
3197
3198 *total_current_ua = max(current_ua, val.intval);
3199 return 0;
3200}
3201
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003202/************************
Nicholas Troast7dbcad22016-10-05 13:30:18 -07003203 * PARALLEL PSY GETTERS *
3204 ************************/
3205
3206int smblib_get_prop_slave_current_now(struct smb_charger *chg,
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003207 union power_supply_propval *pval)
Nicholas Troast7dbcad22016-10-05 13:30:18 -07003208{
3209 if (IS_ERR_OR_NULL(chg->iio.batt_i_chan))
3210 chg->iio.batt_i_chan = iio_channel_get(chg->dev, "batt_i");
3211
3212 if (IS_ERR(chg->iio.batt_i_chan))
3213 return PTR_ERR(chg->iio.batt_i_chan);
3214
3215 return iio_read_channel_processed(chg->iio.batt_i_chan, &pval->intval);
3216}
3217
Nicholas Troast34db5032016-03-28 12:26:44 -07003218/**********************
3219 * INTERRUPT HANDLERS *
3220 **********************/
3221
3222irqreturn_t smblib_handle_debug(int irq, void *data)
3223{
3224 struct smb_irq_data *irq_data = data;
3225 struct smb_charger *chg = irq_data->parent_data;
3226
3227 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003228 return IRQ_HANDLED;
3229}
3230
Nicholas Troast8995a702016-12-05 10:22:22 -08003231irqreturn_t smblib_handle_otg_overcurrent(int irq, void *data)
3232{
3233 struct smb_irq_data *irq_data = data;
3234 struct smb_charger *chg = irq_data->parent_data;
3235 int rc;
3236 u8 stat;
3237
3238 rc = smblib_read(chg, OTG_BASE + INT_RT_STS_OFFSET, &stat);
3239 if (rc < 0) {
3240 dev_err(chg->dev, "Couldn't read OTG_INT_RT_STS rc=%d\n", rc);
3241 return IRQ_HANDLED;
3242 }
3243
Ashay Jaiswal7c241382017-03-06 15:26:38 +05303244 if (chg->wa_flags & OTG_WA) {
3245 if (stat & OTG_OC_DIS_SW_STS_RT_STS_BIT)
3246 smblib_err(chg, "OTG disabled by hw\n");
3247
3248 /* not handling software based hiccups for PM660 */
3249 return IRQ_HANDLED;
3250 }
3251
Nicholas Troastb11015f2017-01-17 17:56:45 -08003252 if (stat & OTG_OVERCURRENT_RT_STS_BIT)
3253 schedule_work(&chg->otg_oc_work);
Nicholas Troast8995a702016-12-05 10:22:22 -08003254
Nicholas Troast8995a702016-12-05 10:22:22 -08003255 return IRQ_HANDLED;
3256}
3257
Harry Yang6fe72ab2016-06-14 16:21:39 -07003258irqreturn_t smblib_handle_chg_state_change(int irq, void *data)
3259{
3260 struct smb_irq_data *irq_data = data;
3261 struct smb_charger *chg = irq_data->parent_data;
Nicholas Troast8cb77552016-09-23 11:50:18 -07003262 u8 stat;
Harry Yang1d1034c2016-06-15 12:09:42 -07003263 int rc;
Harry Yang6fe72ab2016-06-14 16:21:39 -07003264
3265 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3266
Nicholas Troast8cb77552016-09-23 11:50:18 -07003267 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
Harry Yang1d1034c2016-06-15 12:09:42 -07003268 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003269 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003270 rc);
Harry Yang1d1034c2016-06-15 12:09:42 -07003271 return IRQ_HANDLED;
3272 }
3273
Nicholas Troast8cb77552016-09-23 11:50:18 -07003274 stat = stat & BATTERY_CHARGER_STATUS_MASK;
Nicholas Troast8cb77552016-09-23 11:50:18 -07003275 power_supply_changed(chg->batt_psy);
Harry Yang6fe72ab2016-06-14 16:21:39 -07003276 return IRQ_HANDLED;
3277}
3278
Abhijeet Dharmapurikar2644cd62016-07-20 16:54:55 -07003279irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data)
3280{
3281 struct smb_irq_data *irq_data = data;
3282 struct smb_charger *chg = irq_data->parent_data;
Anirudh Ghayal941acaa2017-07-19 16:04:44 +05303283 int rc;
3284
3285 rc = smblib_recover_from_soft_jeita(chg);
3286 if (rc < 0) {
3287 smblib_err(chg, "Couldn't recover chg from soft jeita rc=%d\n",
3288 rc);
3289 return IRQ_HANDLED;
3290 }
Abhijeet Dharmapurikar2644cd62016-07-20 16:54:55 -07003291
3292 rerun_election(chg->fcc_votable);
3293 power_supply_changed(chg->batt_psy);
3294 return IRQ_HANDLED;
3295}
3296
Nicholas Troast34db5032016-03-28 12:26:44 -07003297irqreturn_t smblib_handle_batt_psy_changed(int irq, void *data)
3298{
3299 struct smb_irq_data *irq_data = data;
3300 struct smb_charger *chg = irq_data->parent_data;
3301
Nicholas Troast47ae4612016-08-03 09:49:36 -07003302 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003303 power_supply_changed(chg->batt_psy);
3304 return IRQ_HANDLED;
3305}
3306
3307irqreturn_t smblib_handle_usb_psy_changed(int irq, void *data)
3308{
3309 struct smb_irq_data *irq_data = data;
3310 struct smb_charger *chg = irq_data->parent_data;
3311
Nicholas Troast47ae4612016-08-03 09:49:36 -07003312 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003313 power_supply_changed(chg->usb_psy);
3314 return IRQ_HANDLED;
3315}
3316
Subbaraman Narayanamurthy09327482017-02-06 16:33:12 -08003317irqreturn_t smblib_handle_usbin_uv(int irq, void *data)
3318{
3319 struct smb_irq_data *irq_data = data;
3320 struct smb_charger *chg = irq_data->parent_data;
3321 struct storm_watch *wdata;
3322
3323 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3324 if (!chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data)
3325 return IRQ_HANDLED;
3326
3327 wdata = &chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data->storm_data;
3328 reset_storm_count(wdata);
3329 return IRQ_HANDLED;
3330}
3331
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003332static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising)
3333{
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003334 if (vbus_rising) {
3335 /* use the typec flag even though its not typec */
3336 chg->typec_present = 1;
3337 } else {
3338 chg->typec_present = 0;
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003339 smblib_update_usb_type(chg);
3340 extcon_set_cable_state_(chg->extcon, EXTCON_USB, false);
3341 smblib_uusb_removal(chg);
3342 }
3343}
3344
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003345void smblib_usb_plugin_hard_reset_locked(struct smb_charger *chg)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003346{
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003347 int rc;
3348 u8 stat;
3349 bool vbus_rising;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303350 struct smb_irq_data *data;
3351 struct storm_watch *wdata;
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003352
3353 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
3354 if (rc < 0) {
3355 smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
3356 return;
3357 }
3358
3359 vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
3360
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303361 if (vbus_rising) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003362 smblib_cc2_sink_removal_exit(chg);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303363 } else {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003364 smblib_cc2_sink_removal_enter(chg);
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303365 if (chg->wa_flags & BOOST_BACK_WA) {
3366 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
3367 if (data) {
3368 wdata = &data->storm_data;
3369 update_storm_count(wdata,
3370 WEAK_CHG_STORM_COUNT);
3371 vote(chg->usb_icl_votable, BOOST_BACK_VOTER,
3372 false, 0);
3373 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
3374 false, 0);
3375 }
3376 }
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303377 }
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003378
3379 power_supply_changed(chg->usb_psy);
3380 smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
3381 vbus_rising ? "attached" : "detached");
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003382}
3383
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303384#define PL_DELAY_MS 30000
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003385void smblib_usb_plugin_locked(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07003386{
Nicholas Troast34db5032016-03-28 12:26:44 -07003387 int rc;
3388 u8 stat;
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003389 bool vbus_rising;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303390 struct smb_irq_data *data;
3391 struct storm_watch *wdata;
Nicholas Troast34db5032016-03-28 12:26:44 -07003392
Harry Yangcdad2bf2016-10-04 17:03:56 -07003393 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
3394 if (rc < 0) {
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003395 smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
3396 return;
Harry Yangcdad2bf2016-10-04 17:03:56 -07003397 }
3398
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003399 vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003400 smblib_set_opt_freq_buck(chg, vbus_rising ? chg->chg_freq.freq_5V :
3401 chg->chg_freq.freq_removal);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003402
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003403 if (vbus_rising) {
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05303404 rc = smblib_request_dpdm(chg, true);
3405 if (rc < 0)
3406 smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303407
3408 /* Schedule work to enable parallel charger */
3409 vote(chg->awake_votable, PL_DELAY_VOTER, true, 0);
3410 schedule_delayed_work(&chg->pl_enable_work,
3411 msecs_to_jiffies(PL_DELAY_MS));
Harry Yang1ed7f162017-08-25 11:26:51 -07003412 /* vbus rising when APSD was disabled and PD_ACTIVE = 0 */
3413 if (get_effective_result(chg->apsd_disable_votable) &&
3414 !chg->pd_active)
3415 pr_err("APSD disabled on vbus rising without PD\n");
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07003416 } else {
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303417 if (chg->wa_flags & BOOST_BACK_WA) {
3418 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
3419 if (data) {
3420 wdata = &data->storm_data;
3421 update_storm_count(wdata,
3422 WEAK_CHG_STORM_COUNT);
3423 vote(chg->usb_icl_votable, BOOST_BACK_VOTER,
3424 false, 0);
3425 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
3426 false, 0);
3427 }
3428 }
Nicholas Troastabedaf72016-09-16 11:07:45 -07003429
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05303430 rc = smblib_request_dpdm(chg, false);
3431 if (rc < 0)
3432 smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07003433 }
3434
Ashay Jaiswal0ce2c7c2017-11-14 12:29:02 +05303435 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003436 smblib_micro_usb_plugin(chg, vbus_rising);
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003437
Nicholas Troast62d86622016-09-22 11:41:33 -07003438 power_supply_changed(chg->usb_psy);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003439 smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
3440 vbus_rising ? "attached" : "detached");
3441}
3442
3443irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
3444{
3445 struct smb_irq_data *irq_data = data;
3446 struct smb_charger *chg = irq_data->parent_data;
3447
3448 mutex_lock(&chg->lock);
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003449 if (chg->pd_hard_reset)
3450 smblib_usb_plugin_hard_reset_locked(chg);
3451 else
3452 smblib_usb_plugin_locked(chg);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003453 mutex_unlock(&chg->lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07003454 return IRQ_HANDLED;
3455}
3456
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -07003457#define USB_WEAK_INPUT_UA 1400000
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303458#define ICL_CHANGE_DELAY_MS 1000
Harry Yang6fe72ab2016-06-14 16:21:39 -07003459irqreturn_t smblib_handle_icl_change(int irq, void *data)
3460{
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303461 u8 stat;
3462 int rc, settled_ua, delay = ICL_CHANGE_DELAY_MS;
Harry Yang6fe72ab2016-06-14 16:21:39 -07003463 struct smb_irq_data *irq_data = data;
3464 struct smb_charger *chg = irq_data->parent_data;
3465
Nicholas Troastbb9e1a32017-02-09 10:57:28 -08003466 if (chg->mode == PARALLEL_MASTER) {
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303467 rc = smblib_read(chg, AICL_STATUS_REG, &stat);
3468 if (rc < 0) {
3469 smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n",
3470 rc);
3471 return IRQ_HANDLED;
3472 }
3473
3474 rc = smblib_get_charge_param(chg, &chg->param.icl_stat,
3475 &settled_ua);
3476 if (rc < 0) {
3477 smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
3478 return IRQ_HANDLED;
3479 }
3480
3481 /* If AICL settled then schedule work now */
3482 if ((settled_ua == get_effective_result(chg->usb_icl_votable))
3483 || (stat & AICL_DONE_BIT))
3484 delay = 0;
3485
Ashay Jaiswalac854862017-03-06 23:58:55 +05303486 cancel_delayed_work_sync(&chg->icl_change_work);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303487 schedule_delayed_work(&chg->icl_change_work,
3488 msecs_to_jiffies(delay));
Nicholas Troastbb9e1a32017-02-09 10:57:28 -08003489 }
Harry Yang1d1034c2016-06-15 12:09:42 -07003490
Harry Yang6fe72ab2016-06-14 16:21:39 -07003491 return IRQ_HANDLED;
3492}
3493
Nicholas Troast34db5032016-03-28 12:26:44 -07003494static void smblib_handle_slow_plugin_timeout(struct smb_charger *chg,
3495 bool rising)
3496{
3497 smblib_dbg(chg, PR_INTERRUPT, "IRQ: slow-plugin-timeout %s\n",
3498 rising ? "rising" : "falling");
3499}
3500
3501static void smblib_handle_sdp_enumeration_done(struct smb_charger *chg,
3502 bool rising)
3503{
3504 smblib_dbg(chg, PR_INTERRUPT, "IRQ: sdp-enumeration-done %s\n",
3505 rising ? "rising" : "falling");
3506}
3507
Harry Yangcdad2bf2016-10-04 17:03:56 -07003508#define QC3_PULSES_FOR_6V 5
3509#define QC3_PULSES_FOR_9V 20
3510#define QC3_PULSES_FOR_12V 35
3511static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg)
3512{
3513 int rc;
3514 u8 stat;
3515 int pulses;
3516
Fenglin Wuef4730e2017-01-11 18:16:25 +08003517 power_supply_changed(chg->usb_main_psy);
Fenglin Wu80826e02017-04-25 21:45:08 +08003518 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP) {
Harry Yangcdad2bf2016-10-04 17:03:56 -07003519 rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat);
3520 if (rc < 0) {
3521 smblib_err(chg,
3522 "Couldn't read QC_CHANGE_STATUS rc=%d\n", rc);
3523 return;
3524 }
3525
3526 switch (stat & QC_2P0_STATUS_MASK) {
3527 case QC_5V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303528 smblib_set_opt_freq_buck(chg,
3529 chg->chg_freq.freq_5V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003530 break;
3531 case QC_9V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303532 smblib_set_opt_freq_buck(chg,
3533 chg->chg_freq.freq_9V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003534 break;
3535 case QC_12V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303536 smblib_set_opt_freq_buck(chg,
3537 chg->chg_freq.freq_12V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003538 break;
3539 default:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303540 smblib_set_opt_freq_buck(chg,
3541 chg->chg_freq.freq_removal);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003542 break;
3543 }
3544 }
3545
Fenglin Wu80826e02017-04-25 21:45:08 +08003546 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP_3) {
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +05303547 rc = smblib_get_pulse_cnt(chg, &pulses);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003548 if (rc < 0) {
3549 smblib_err(chg,
3550 "Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
3551 return;
3552 }
Harry Yangcdad2bf2016-10-04 17:03:56 -07003553
3554 if (pulses < QC3_PULSES_FOR_6V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303555 smblib_set_opt_freq_buck(chg,
3556 chg->chg_freq.freq_5V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003557 else if (pulses < QC3_PULSES_FOR_9V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303558 smblib_set_opt_freq_buck(chg,
3559 chg->chg_freq.freq_6V_8V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003560 else if (pulses < QC3_PULSES_FOR_12V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303561 smblib_set_opt_freq_buck(chg,
3562 chg->chg_freq.freq_9V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003563 else
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303564 smblib_set_opt_freq_buck(chg,
3565 chg->chg_freq.freq_12V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003566 }
3567}
3568
Nicholas Troast34db5032016-03-28 12:26:44 -07003569/* triggers when HVDCP 3.0 authentication has finished */
3570static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
3571 bool rising)
3572{
3573 const struct apsd_result *apsd_result;
Harry Yangcdad2bf2016-10-04 17:03:56 -07003574 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07003575
3576 if (!rising)
3577 return;
3578
Ashay Jaiswal67ec7072017-02-16 14:14:58 +05303579 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
3580 /*
3581 * Disable AUTH_IRQ_EN_CFG_BIT to receive adapter voltage
3582 * change interrupt.
3583 */
3584 rc = smblib_masked_write(chg,
3585 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
3586 AUTH_IRQ_EN_CFG_BIT, 0);
3587 if (rc < 0)
3588 smblib_err(chg,
3589 "Couldn't enable QC auth setting rc=%d\n", rc);
3590 }
Harry Yangcdad2bf2016-10-04 17:03:56 -07003591
Harry Yangaba1f5f2016-09-28 10:47:29 -07003592 if (chg->mode == PARALLEL_MASTER)
3593 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0);
3594
Ashay Jaiswalac854862017-03-06 23:58:55 +05303595 /* the APSD done handler will set the USB supply type */
3596 apsd_result = smblib_get_apsd_result(chg);
Ashay Jaiswalac854862017-03-06 23:58:55 +05303597
Nicholas Troast34db5032016-03-28 12:26:44 -07003598 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n",
3599 apsd_result->name);
3600}
3601
Harry Yang1369b7a2016-09-27 15:59:50 -07003602static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
3603 bool rising, bool qc_charger)
3604{
Ashay Jaiswal7b6eb962017-04-26 14:34:29 +05303605 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05303606
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003607 /* Hold off PD only until hvdcp 2.0 detection timeout */
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003608 if (rising) {
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003609 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003610 false, 0);
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -08003611
Harry Yang4bf7d962017-03-13 16:51:43 -07003612 /* enable HDC and ICL irq for QC2/3 charger */
3613 if (qc_charger)
3614 vote(chg->usb_irq_enable_votable, QC_VOTER, true, 0);
3615
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -08003616 /*
3617 * HVDCP detection timeout done
3618 * If adapter is not QC2.0/QC3.0 - it is a plain old DCP.
3619 */
3620 if (!qc_charger && (apsd_result->bit & DCP_CHARGER_BIT))
3621 /* enforce DCP ICL if specified */
3622 vote(chg->usb_icl_votable, DCP_VOTER,
3623 chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua);
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07003624
3625 /*
3626 * if pd is not allowed, then set pd_active = false right here,
3627 * so that it starts the hvdcp engine
3628 */
3629 if (!get_effective_result(chg->pd_allowed_votable))
3630 __smblib_set_prop_pd_active(chg, 0);
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003631 }
Harry Yang1369b7a2016-09-27 15:59:50 -07003632
3633 smblib_dbg(chg, PR_INTERRUPT, "IRQ: smblib_handle_hvdcp_check_timeout %s\n",
3634 rising ? "rising" : "falling");
3635}
3636
Nicholas Troast34db5032016-03-28 12:26:44 -07003637/* triggers when HVDCP is detected */
3638static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg,
3639 bool rising)
3640{
3641 if (!rising)
3642 return;
3643
3644 /* the APSD done handler will set the USB supply type */
3645 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
3646 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-detect-done %s\n",
3647 rising ? "rising" : "falling");
3648}
3649
Nicholas Troastf9e44992017-03-14 09:06:56 -07003650static void smblib_force_legacy_icl(struct smb_charger *chg, int pst)
3651{
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303652 int typec_mode;
3653 int rp_ua;
3654
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003655 /* while PD is active it should have complete ICL control */
3656 if (chg->pd_active)
3657 return;
3658
Nicholas Troastf9e44992017-03-14 09:06:56 -07003659 switch (pst) {
3660 case POWER_SUPPLY_TYPE_USB:
3661 /*
3662 * USB_PSY will vote to increase the current to 500/900mA once
3663 * enumeration is done. Ensure that USB_PSY has at least voted
3664 * for 100mA before releasing the LEGACY_UNKNOWN vote
3665 */
3666 if (!is_client_vote_enabled(chg->usb_icl_votable,
3667 USB_PSY_VOTER))
3668 vote(chg->usb_icl_votable, USB_PSY_VOTER, true, 100000);
3669 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
3670 break;
3671 case POWER_SUPPLY_TYPE_USB_CDP:
3672 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1500000);
3673 break;
3674 case POWER_SUPPLY_TYPE_USB_DCP:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303675 typec_mode = smblib_get_prop_typec_mode(chg);
3676 rp_ua = get_rp_based_dcp_current(chg, typec_mode);
3677 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua);
Nicholas Troastf9e44992017-03-14 09:06:56 -07003678 break;
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05303679 case POWER_SUPPLY_TYPE_USB_FLOAT:
3680 /*
3681 * limit ICL to 100mA, the USB driver will enumerate to check
3682 * if this is a SDP and appropriately set the current
3683 */
3684 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
3685 break;
Nicholas Troastf9e44992017-03-14 09:06:56 -07003686 case POWER_SUPPLY_TYPE_USB_HVDCP:
3687 case POWER_SUPPLY_TYPE_USB_HVDCP_3:
3688 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 3000000);
3689 break;
3690 default:
3691 smblib_err(chg, "Unknown APSD %d; forcing 500mA\n", pst);
3692 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 500000);
3693 break;
3694 }
3695}
3696
Ankit Sharmade321e12017-09-01 20:17:45 +05303697static void smblib_notify_extcon_props(struct smb_charger *chg, int id)
3698{
3699 union extcon_property_value val;
3700 union power_supply_propval prop_val;
3701
3702 smblib_get_prop_typec_cc_orientation(chg, &prop_val);
3703 val.intval = ((prop_val.intval == 2) ? 1 : 0);
3704 extcon_set_property(chg->extcon, id,
3705 EXTCON_PROP_USB_TYPEC_POLARITY, val);
3706
3707 val.intval = true;
3708 extcon_set_property(chg->extcon, id,
3709 EXTCON_PROP_USB_SS, val);
3710}
3711
3712static void smblib_notify_device_mode(struct smb_charger *chg, bool enable)
3713{
3714 if (enable)
3715 smblib_notify_extcon_props(chg, EXTCON_USB);
3716
3717 extcon_set_state_sync(chg->extcon, EXTCON_USB, enable);
3718}
3719
3720static void smblib_notify_usb_host(struct smb_charger *chg, bool enable)
3721{
3722 if (enable)
3723 smblib_notify_extcon_props(chg, EXTCON_USB_HOST);
3724
3725 extcon_set_state_sync(chg->extcon, EXTCON_USB_HOST, enable);
3726}
3727
Nicholas Troast34db5032016-03-28 12:26:44 -07003728#define HVDCP_DET_MS 2500
3729static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
3730{
Nicholas Troast34db5032016-03-28 12:26:44 -07003731 const struct apsd_result *apsd_result;
3732
3733 if (!rising)
3734 return;
3735
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07003736 apsd_result = smblib_update_usb_type(chg);
Nicholas Troastf9e44992017-03-14 09:06:56 -07003737
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003738 if (!chg->typec_legacy_valid)
Nicholas Troastf9e44992017-03-14 09:06:56 -07003739 smblib_force_legacy_icl(chg, apsd_result->pst);
3740
Nicholas Troast34db5032016-03-28 12:26:44 -07003741 switch (apsd_result->bit) {
3742 case SDP_CHARGER_BIT:
3743 case CDP_CHARGER_BIT:
Ashay Jaiswal0ce2c7c2017-11-14 12:29:02 +05303744 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05303745 extcon_set_cable_state_(chg->extcon, EXTCON_USB,
3746 true);
Abhijeet Dharmapurikarbb9505f2017-03-22 18:31:28 -07003747 /* if not DCP then no hvdcp timeout happens. Enable pd here */
3748 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3749 false, 0);
Ankit Sharmade321e12017-09-01 20:17:45 +05303750 if (chg->use_extcon)
3751 smblib_notify_device_mode(chg, true);
Abhijeet Dharmapurikarbb9505f2017-03-22 18:31:28 -07003752 break;
Nicholas Troast34db5032016-03-28 12:26:44 -07003753 case OCP_CHARGER_BIT:
3754 case FLOAT_CHARGER_BIT:
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303755 /* if not DCP then no hvdcp timeout happens, Enable pd here. */
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003756 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3757 false, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07003758 break;
3759 case DCP_CHARGER_BIT:
Harry Yang1369b7a2016-09-27 15:59:50 -07003760 if (chg->wa_flags & QC_CHARGER_DETECTION_WA_BIT)
3761 schedule_delayed_work(&chg->hvdcp_detect_work,
3762 msecs_to_jiffies(HVDCP_DET_MS));
Nicholas Troast34db5032016-03-28 12:26:44 -07003763 break;
3764 default:
3765 break;
3766 }
3767
Nicholas Troast34db5032016-03-28 12:26:44 -07003768 smblib_dbg(chg, PR_INTERRUPT, "IRQ: apsd-done rising; %s detected\n",
3769 apsd_result->name);
3770}
3771
3772irqreturn_t smblib_handle_usb_source_change(int irq, void *data)
3773{
3774 struct smb_irq_data *irq_data = data;
3775 struct smb_charger *chg = irq_data->parent_data;
3776 int rc = 0;
3777 u8 stat;
3778
3779 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
3780 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003781 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07003782 return IRQ_HANDLED;
3783 }
3784 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
3785
Ashay Jaiswal0ce2c7c2017-11-14 12:29:02 +05303786 if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
3787 && (stat & APSD_DTC_STATUS_DONE_BIT)
Ashay Jaiswal8507aa52017-04-14 09:42:32 +05303788 && !chg->uusb_apsd_rerun_done) {
3789 /*
3790 * Force re-run APSD to handle slow insertion related
3791 * charger-mis-detection.
3792 */
3793 chg->uusb_apsd_rerun_done = true;
3794 smblib_rerun_apsd(chg);
3795 return IRQ_HANDLED;
3796 }
3797
Nicholas Troast34db5032016-03-28 12:26:44 -07003798 smblib_handle_apsd_done(chg,
3799 (bool)(stat & APSD_DTC_STATUS_DONE_BIT));
3800
3801 smblib_handle_hvdcp_detect_done(chg,
3802 (bool)(stat & QC_CHARGER_BIT));
3803
Harry Yang1369b7a2016-09-27 15:59:50 -07003804 smblib_handle_hvdcp_check_timeout(chg,
3805 (bool)(stat & HVDCP_CHECK_TIMEOUT_BIT),
3806 (bool)(stat & QC_CHARGER_BIT));
3807
Nicholas Troast34db5032016-03-28 12:26:44 -07003808 smblib_handle_hvdcp_3p0_auth_done(chg,
3809 (bool)(stat & QC_AUTH_DONE_STATUS_BIT));
3810
Nicholas Troast34db5032016-03-28 12:26:44 -07003811 smblib_handle_sdp_enumeration_done(chg,
3812 (bool)(stat & ENUMERATION_DONE_BIT));
3813
3814 smblib_handle_slow_plugin_timeout(chg,
3815 (bool)(stat & SLOW_PLUGIN_TIMEOUT_BIT));
3816
Harry Yangcdad2bf2016-10-04 17:03:56 -07003817 smblib_hvdcp_adaptive_voltage_change(chg);
3818
Nicholas Troast34db5032016-03-28 12:26:44 -07003819 power_supply_changed(chg->usb_psy);
3820
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08003821 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
3822 if (rc < 0) {
3823 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
3824 return IRQ_HANDLED;
3825 }
3826 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
3827
Nicholas Troast34db5032016-03-28 12:26:44 -07003828 return IRQ_HANDLED;
3829}
3830
Harry Yang29f23822017-09-09 00:09:36 -07003831static int typec_try_sink(struct smb_charger *chg)
3832{
3833 union power_supply_propval val;
3834 bool debounce_done, vbus_detected, sink;
3835 u8 stat;
3836 int exit_mode = ATTACHED_SRC, rc;
Abhijeet Dharmapurikarb0eb10d2017-11-13 18:42:40 -08003837 int typec_mode;
3838
3839 if (!(*chg->try_sink_enabled))
3840 return ATTACHED_SRC;
3841
3842 typec_mode = smblib_get_prop_typec_mode(chg);
3843 if (typec_mode == POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER
3844 || typec_mode == POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY)
3845 return ATTACHED_SRC;
3846
3847 /*
3848 * Try.SNK entry status - ATTACHWAIT.SRC state and detected Rd-open
3849 * or RD-Ra for TccDebounce time.
3850 */
Harry Yang29f23822017-09-09 00:09:36 -07003851
3852 /* ignore typec interrupt while try.snk WIP */
3853 chg->try_sink_active = true;
3854
3855 /* force SNK mode */
3856 val.intval = POWER_SUPPLY_TYPEC_PR_SINK;
3857 rc = smblib_set_prop_typec_power_role(chg, &val);
3858 if (rc < 0) {
3859 smblib_err(chg, "Couldn't set UFP mode rc=%d\n", rc);
3860 goto try_sink_exit;
3861 }
3862
3863 /* reduce Tccdebounce time to ~20ms */
3864 rc = smblib_masked_write(chg, MISC_CFG_REG,
3865 TCC_DEBOUNCE_20MS_BIT, TCC_DEBOUNCE_20MS_BIT);
3866 if (rc < 0) {
3867 smblib_err(chg, "Couldn't set MISC_CFG_REG rc=%d\n", rc);
3868 goto try_sink_exit;
3869 }
3870
3871 /*
3872 * give opportunity to the other side to be a SRC,
3873 * for tDRPTRY + Tccdebounce time
3874 */
Harry Yang692cec42017-10-16 16:21:19 -07003875 msleep(120);
Harry Yang29f23822017-09-09 00:09:36 -07003876
3877 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
3878 if (rc < 0) {
3879 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
3880 rc);
3881 goto try_sink_exit;
3882 }
3883
3884 debounce_done = stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT;
3885
3886 if (!debounce_done)
3887 /*
3888 * The other side didn't switch to source, either it
3889 * is an adamant sink or is removed go back to showing Rp
3890 */
3891 goto try_wait_src;
3892
3893 /*
3894 * We are in force sink mode and the other side has switched to
3895 * showing Rp. Config DRP in case the other side removes Rp so we
3896 * can quickly (20ms) switch to showing our Rp. Note that the spec
3897 * needs us to show Rp for 80mS while the drp DFP residency is just
3898 * 54mS. But 54mS is plenty time for us to react and force Rp for
3899 * the remaining 26mS.
3900 */
3901 val.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
3902 rc = smblib_set_prop_typec_power_role(chg, &val);
3903 if (rc < 0) {
3904 smblib_err(chg, "Couldn't set DFP mode rc=%d\n",
3905 rc);
3906 goto try_sink_exit;
3907 }
3908
3909 /*
3910 * while other side is Rp, wait for VBUS from it; exit if other side
3911 * removes Rp
3912 */
3913 do {
3914 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
3915 if (rc < 0) {
3916 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
3917 rc);
3918 goto try_sink_exit;
3919 }
3920
3921 debounce_done = stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT;
3922 vbus_detected = stat & TYPEC_VBUS_STATUS_BIT;
3923
3924 /* Successfully transitioned to ATTACHED.SNK */
3925 if (vbus_detected && debounce_done) {
3926 exit_mode = ATTACHED_SINK;
3927 goto try_sink_exit;
3928 }
3929
3930 /*
3931 * Ensure sink since drp may put us in source if other
3932 * side switches back to Rd
3933 */
3934 sink = !(stat & UFP_DFP_MODE_STATUS_BIT);
3935
3936 usleep_range(1000, 2000);
3937 } while (debounce_done && sink);
3938
3939try_wait_src:
3940 /*
3941 * Transition to trywait.SRC state. check if other side still wants
3942 * to be SNK or has been removed.
3943 */
3944 val.intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
3945 rc = smblib_set_prop_typec_power_role(chg, &val);
3946 if (rc < 0) {
3947 smblib_err(chg, "Couldn't set UFP mode rc=%d\n", rc);
3948 goto try_sink_exit;
3949 }
3950
3951 /* Need to be in this state for tDRPTRY time, 75ms~150ms */
3952 msleep(80);
3953
3954 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
3955 if (rc < 0) {
3956 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
3957 goto try_sink_exit;
3958 }
3959
3960 debounce_done = stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT;
3961
3962 if (debounce_done)
3963 /* the other side wants to be a sink */
3964 exit_mode = ATTACHED_SRC;
3965 else
3966 /* the other side is detached */
3967 exit_mode = UNATTACHED_SINK;
3968
3969try_sink_exit:
3970 /* release forcing of SRC/SNK mode */
3971 val.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
3972 rc = smblib_set_prop_typec_power_role(chg, &val);
3973 if (rc < 0)
3974 smblib_err(chg, "Couldn't set DFP mode rc=%d\n", rc);
3975
3976 /* revert Tccdebounce time back to ~120ms */
3977 rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT, 0);
3978 if (rc < 0)
3979 smblib_err(chg, "Couldn't set MISC_CFG_REG rc=%d\n", rc);
3980
3981 chg->try_sink_active = false;
3982
3983 return exit_mode;
3984}
3985
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003986static void typec_sink_insertion(struct smb_charger *chg)
3987{
Harry Yang29f23822017-09-09 00:09:36 -07003988 int exit_mode;
Abhijeet Dharmapurikarb0eb10d2017-11-13 18:42:40 -08003989 int typec_mode;
Harry Yang29f23822017-09-09 00:09:36 -07003990
Abhijeet Dharmapurikarb0eb10d2017-11-13 18:42:40 -08003991 exit_mode = typec_try_sink(chg);
Harry Yang29f23822017-09-09 00:09:36 -07003992
Abhijeet Dharmapurikarb0eb10d2017-11-13 18:42:40 -08003993 if (exit_mode != ATTACHED_SRC) {
3994 smblib_usb_typec_change(chg);
3995 return;
Harry Yang29f23822017-09-09 00:09:36 -07003996 }
3997
Abhijeet Dharmapurikarb0eb10d2017-11-13 18:42:40 -08003998 typec_mode = smblib_get_prop_typec_mode(chg);
3999 if (typec_mode == POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER)
4000 chg->is_audio_adapter = true;
4001
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004002 /* when a sink is inserted we should not wait on hvdcp timeout to
4003 * enable pd
4004 */
4005 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
4006 false, 0);
Ankit Sharmade321e12017-09-01 20:17:45 +05304007 if (chg->use_extcon) {
4008 smblib_notify_usb_host(chg, true);
4009 chg->otg_present = true;
4010 }
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004011}
Nicholas Troast34db5032016-03-28 12:26:44 -07004012
Harry Yangd89ff1f2016-12-05 14:59:11 -08004013static void typec_sink_removal(struct smb_charger *chg)
4014{
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05304015 smblib_set_charge_param(chg, &chg->param.freq_boost,
4016 chg->chg_freq.freq_above_otg_threshold);
Harry Yangd89ff1f2016-12-05 14:59:11 -08004017 chg->boost_current_ua = 0;
4018}
4019
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004020static void smblib_handle_typec_removal(struct smb_charger *chg)
4021{
Nicholas Troastfe74c592017-03-14 09:20:55 -07004022 int rc;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304023 struct smb_irq_data *data;
4024 struct storm_watch *wdata;
Nicholas Troastfe74c592017-03-14 09:20:55 -07004025
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004026 chg->cc2_detach_wa_active = false;
4027
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05304028 rc = smblib_request_dpdm(chg, false);
4029 if (rc < 0)
4030 smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05304031
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304032 if (chg->wa_flags & BOOST_BACK_WA) {
4033 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
4034 if (data) {
4035 wdata = &data->storm_data;
4036 update_storm_count(wdata, WEAK_CHG_STORM_COUNT);
4037 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
4038 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
4039 false, 0);
4040 }
4041 }
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05304042
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004043 /* reset APSD voters */
4044 vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, false, 0);
4045 vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304046
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004047 cancel_delayed_work_sync(&chg->pl_enable_work);
4048 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
4049
4050 /* reset input current limit voters */
4051 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
4052 vote(chg->usb_icl_votable, PD_VOTER, false, 0);
4053 vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
4054 vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
4055 vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
Ashay Jaiswalae23a042017-05-18 15:28:31 +05304056 vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
Abhijeet Dharmapurikar66d2c442017-07-12 11:55:36 -07004057 vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
Harry Yangfeb95002017-10-06 12:11:42 -07004058 vote(chg->usb_icl_votable, CTM_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004059
4060 /* reset hvdcp voters */
4061 vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, true, 0);
4062 vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER, true, 0);
4063
4064 /* reset power delivery voters */
4065 vote(chg->pd_allowed_votable, PD_VOTER, false, 0);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004066 vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0);
4067 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER, true, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004068
4069 /* reset usb irq voters */
Harry Yang4bf7d962017-03-13 16:51:43 -07004070 vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
4071 vote(chg->usb_irq_enable_votable, QC_VOTER, false, 0);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004072
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004073 /* reset parallel voters */
4074 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
Abhijeet Dharmapurikar004f7ba2017-09-26 16:23:51 -07004075 vote(chg->pl_disable_votable, PL_FCC_LOW_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004076 vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
4077 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
4078 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
Harry Yang1d1034c2016-06-15 12:09:42 -07004079
Ashay Jaiswal3d22f4b2017-11-15 18:09:19 +05304080 vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0);
Nicholas Troast8995a702016-12-05 10:22:22 -08004081 chg->vconn_attempts = 0;
4082 chg->otg_attempts = 0;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05304083 chg->pulse_cnt = 0;
4084 chg->usb_icl_delta_ua = 0;
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004085 chg->voltage_min_uv = MICRO_5V;
4086 chg->voltage_max_uv = MICRO_5V;
4087 chg->pd_active = 0;
4088 chg->pd_hard_reset = 0;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004089 chg->typec_legacy_valid = false;
Harry Yang3b113a52016-12-08 12:37:40 -08004090
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05304091 /* write back the default FLOAT charger configuration */
4092 rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
4093 (u8)FLOAT_OPTIONS_MASK, chg->float_cfg);
4094 if (rc < 0)
4095 smblib_err(chg, "Couldn't write float charger options rc=%d\n",
4096 rc);
4097
Abhijeet Dharmapurikar676bd792017-05-31 16:21:57 -07004098 /* reset back to 120mS tCC debounce */
4099 rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT, 0);
4100 if (rc < 0)
4101 smblib_err(chg, "Couldn't set 120mS tCC debounce rc=%d\n", rc);
4102
Nicholas Troastfe74c592017-03-14 09:20:55 -07004103 /* enable APSD CC trigger for next insertion */
4104 rc = smblib_masked_write(chg, TYPE_C_CFG_REG,
4105 APSD_START_ON_CC_BIT, APSD_START_ON_CC_BIT);
4106 if (rc < 0)
4107 smblib_err(chg, "Couldn't enable APSD_START_ON_CC rc=%d\n", rc);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08004108
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004109 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
4110 /* re-enable AUTH_IRQ_EN_CFG_BIT */
4111 rc = smblib_masked_write(chg,
4112 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
4113 AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
4114 if (rc < 0)
4115 smblib_err(chg,
4116 "Couldn't enable QC auth setting rc=%d\n", rc);
4117 }
4118
4119 /* reconfigure allowed voltage for HVDCP */
4120 rc = smblib_set_adapter_allowance(chg,
4121 USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
4122 if (rc < 0)
4123 smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
4124 rc);
4125
Abhijeet Dharmapurikarb0eb10d2017-11-13 18:42:40 -08004126 if (chg->is_audio_adapter == true)
4127 /* wait for the audio driver to lower its en gpio */
4128 msleep(*chg->audio_headset_drp_wait_ms);
4129
4130 chg->is_audio_adapter = false;
4131
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004132 /* enable DRP */
4133 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4134 TYPEC_POWER_ROLE_CMD_MASK, 0);
4135 if (rc < 0)
4136 smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc);
4137
4138 /* HW controlled CC_OUT */
4139 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
4140 TYPEC_SPARE_CFG_BIT, 0);
4141 if (rc < 0)
4142 smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n", rc);
4143
4144 /* restore crude sensor */
4145 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
4146 if (rc < 0)
4147 smblib_err(chg, "Couldn't restore crude sensor rc=%d\n", rc);
4148
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004149 mutex_lock(&chg->vconn_oc_lock);
4150 if (!chg->vconn_en)
4151 goto unlock;
4152
4153 smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4154 VCONN_EN_VALUE_BIT, 0);
4155 chg->vconn_en = false;
4156
4157unlock:
4158 mutex_unlock(&chg->vconn_oc_lock);
4159
Abhijeet Dharmapurikar319d6942017-06-05 17:14:17 -07004160 /* clear exit sink based on cc */
4161 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4162 EXIT_SNK_BASED_ON_CC_BIT, 0);
4163 if (rc < 0)
4164 smblib_err(chg, "Couldn't clear exit_sink_based_on_cc rc=%d\n",
4165 rc);
4166
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08004167 typec_sink_removal(chg);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004168 smblib_update_usb_type(chg);
Ankit Sharmade321e12017-09-01 20:17:45 +05304169
4170 if (chg->use_extcon) {
4171 if (chg->otg_present)
4172 smblib_notify_usb_host(chg, false);
4173 else
4174 smblib_notify_device_mode(chg, false);
4175 }
4176 chg->otg_present = false;
Nicholas Troast34db5032016-03-28 12:26:44 -07004177}
4178
Nicholas Troaste1932e42017-04-12 12:38:18 -07004179static void smblib_handle_typec_insertion(struct smb_charger *chg)
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07004180{
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004181 int rc;
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07004182
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004183 vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, false, 0);
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07004184
Nicholas Troastfe74c592017-03-14 09:20:55 -07004185 /* disable APSD CC trigger since CC is attached */
4186 rc = smblib_masked_write(chg, TYPE_C_CFG_REG, APSD_START_ON_CC_BIT, 0);
4187 if (rc < 0)
4188 smblib_err(chg, "Couldn't disable APSD_START_ON_CC rc=%d\n",
4189 rc);
4190
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05304191 if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT) {
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004192 typec_sink_insertion(chg);
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05304193 } else {
4194 rc = smblib_request_dpdm(chg, true);
4195 if (rc < 0)
4196 smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
Harry Yangd89ff1f2016-12-05 14:59:11 -08004197 typec_sink_removal(chg);
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05304198 }
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07004199}
4200
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05304201static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode)
4202{
4203 int rp_ua;
4204 const struct apsd_result *apsd = smblib_get_apsd_result(chg);
4205
4206 if ((apsd->pst != POWER_SUPPLY_TYPE_USB_DCP)
4207 && (apsd->pst != POWER_SUPPLY_TYPE_USB_FLOAT))
4208 return;
4209
4210 /*
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05304211 * if APSD indicates FLOAT and the USB stack had detected SDP,
4212 * do not respond to Rp changes as we do not confirm that its
4213 * a legacy cable
4214 */
4215 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
4216 return;
4217 /*
4218 * We want the ICL vote @ 100mA for a FLOAT charger
4219 * until the detection by the USB stack is complete.
4220 * Ignore the Rp changes unless there is a
4221 * pre-existing valid vote.
4222 */
4223 if (apsd->pst == POWER_SUPPLY_TYPE_USB_FLOAT &&
4224 get_client_vote(chg->usb_icl_votable,
4225 LEGACY_UNKNOWN_VOTER) <= 100000)
4226 return;
4227
4228 /*
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05304229 * handle Rp change for DCP/FLOAT/OCP.
4230 * Update the current only if the Rp is different from
4231 * the last Rp value.
4232 */
4233 smblib_dbg(chg, PR_MISC, "CC change old_mode=%d new_mode=%d\n",
4234 chg->typec_mode, typec_mode);
4235
4236 rp_ua = get_rp_based_dcp_current(chg, typec_mode);
4237 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua);
4238}
4239
Nicholas Troaste1932e42017-04-12 12:38:18 -07004240static void smblib_handle_typec_cc_state_change(struct smb_charger *chg)
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004241{
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05304242 int typec_mode;
4243
Nicholas Troaste1932e42017-04-12 12:38:18 -07004244 if (chg->pr_swap_in_progress)
4245 return;
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004246
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05304247 typec_mode = smblib_get_prop_typec_mode(chg);
4248 if (chg->typec_present && (typec_mode != chg->typec_mode))
4249 smblib_handle_rp_change(chg, typec_mode);
4250
4251 chg->typec_mode = typec_mode;
4252
Nicholas Troaste1932e42017-04-12 12:38:18 -07004253 if (!chg->typec_present && chg->typec_mode != POWER_SUPPLY_TYPEC_NONE) {
4254 chg->typec_present = true;
4255 smblib_dbg(chg, PR_MISC, "TypeC %s insertion\n",
4256 smblib_typec_mode_name[chg->typec_mode]);
4257 smblib_handle_typec_insertion(chg);
4258 } else if (chg->typec_present &&
4259 chg->typec_mode == POWER_SUPPLY_TYPEC_NONE) {
4260 chg->typec_present = false;
4261 smblib_dbg(chg, PR_MISC, "TypeC removal\n");
4262 smblib_handle_typec_removal(chg);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004263 }
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004264
Abhijeet Dharmapurikar66d2c442017-07-12 11:55:36 -07004265 /* suspend usb if sink */
Harry Yangca0664e2017-08-18 11:40:06 -07004266 if ((chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
4267 && chg->typec_present)
Abhijeet Dharmapurikar66d2c442017-07-12 11:55:36 -07004268 vote(chg->usb_icl_votable, OTG_VOTER, true, 0);
4269 else
4270 vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
4271
Nicholas Troaste1932e42017-04-12 12:38:18 -07004272 smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n",
4273 smblib_typec_mode_name[chg->typec_mode]);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004274}
4275
Harry Yang29f23822017-09-09 00:09:36 -07004276void smblib_usb_typec_change(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07004277{
Nicholas Troast34db5032016-03-28 12:26:44 -07004278 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07004279
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07004280 rc = smblib_multibyte_read(chg, TYPE_C_STATUS_1_REG,
4281 chg->typec_status, 5);
Nicholas Troast34db5032016-03-28 12:26:44 -07004282 if (rc < 0) {
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07004283 smblib_err(chg, "Couldn't cache USB Type-C status rc=%d\n", rc);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004284 return;
Nicholas Troast34db5032016-03-28 12:26:44 -07004285 }
Nicholas Troast34db5032016-03-28 12:26:44 -07004286
Nicholas Troaste1932e42017-04-12 12:38:18 -07004287 smblib_handle_typec_cc_state_change(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07004288
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07004289 if (chg->typec_status[3] & TYPEC_VBUS_ERROR_STATUS_BIT)
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004290 smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n");
Harry Yangd757c0f2016-09-23 10:52:05 -07004291
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07004292 if (chg->typec_status[3] & TYPEC_VCONN_OVERCURR_STATUS_BIT)
Nicholas Troastb11015f2017-01-17 17:56:45 -08004293 schedule_work(&chg->vconn_oc_work);
Nicholas Troast8995a702016-12-05 10:22:22 -08004294
Nicholas Troastb1486552016-11-10 08:20:11 -08004295 power_supply_changed(chg->usb_psy);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004296}
4297
4298irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
4299{
4300 struct smb_irq_data *irq_data = data;
4301 struct smb_charger *chg = irq_data->parent_data;
4302
Ashay Jaiswal0ce2c7c2017-11-14 12:29:02 +05304303 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) {
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05304304 cancel_delayed_work_sync(&chg->uusb_otg_work);
4305 vote(chg->awake_votable, OTG_DELAY_VOTER, true, 0);
4306 smblib_dbg(chg, PR_INTERRUPT, "Scheduling OTG work\n");
4307 schedule_delayed_work(&chg->uusb_otg_work,
4308 msecs_to_jiffies(chg->otg_delay_ms));
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004309 return IRQ_HANDLED;
4310 }
4311
Harry Yang29f23822017-09-09 00:09:36 -07004312 if (chg->cc2_detach_wa_active || chg->typec_en_dis_active ||
4313 chg->try_sink_active) {
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07004314 smblib_dbg(chg, PR_MISC | PR_INTERRUPT, "Ignoring since %s active\n",
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004315 chg->cc2_detach_wa_active ?
4316 "cc2_detach_wa" : "typec_en_dis");
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004317 return IRQ_HANDLED;
4318 }
4319
Abhijeet Dharmapurikar049b2552017-07-12 11:27:51 -07004320 if (chg->pr_swap_in_progress) {
4321 smblib_dbg(chg, PR_INTERRUPT,
4322 "Ignoring since pr_swap_in_progress\n");
4323 return IRQ_HANDLED;
4324 }
4325
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004326 mutex_lock(&chg->lock);
4327 smblib_usb_typec_change(chg);
4328 mutex_unlock(&chg->lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07004329 return IRQ_HANDLED;
4330}
4331
Abhijeet Dharmapurikar23916642016-10-03 10:38:50 -07004332irqreturn_t smblib_handle_dc_plugin(int irq, void *data)
4333{
4334 struct smb_irq_data *irq_data = data;
4335 struct smb_charger *chg = irq_data->parent_data;
4336
4337 power_supply_changed(chg->dc_psy);
4338 return IRQ_HANDLED;
4339}
4340
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004341irqreturn_t smblib_handle_high_duty_cycle(int irq, void *data)
4342{
4343 struct smb_irq_data *irq_data = data;
4344 struct smb_charger *chg = irq_data->parent_data;
4345
4346 chg->is_hdc = true;
Fenglin Wu4f4dcc12017-08-24 14:28:54 +08004347 /*
4348 * Disable usb IRQs after the flag set and re-enable IRQs after
4349 * the flag cleared in the delayed work queue, to avoid any IRQ
4350 * storming during the delays
4351 */
4352 if (chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq)
4353 disable_irq_nosync(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
4354
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004355 schedule_delayed_work(&chg->clear_hdc_work, msecs_to_jiffies(60));
4356
4357 return IRQ_HANDLED;
4358}
4359
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05304360static void smblib_bb_removal_work(struct work_struct *work)
4361{
4362 struct smb_charger *chg = container_of(work, struct smb_charger,
4363 bb_removal_work.work);
4364
4365 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
4366 vote(chg->awake_votable, BOOST_BACK_VOTER, false, 0);
4367}
4368
4369#define BOOST_BACK_UNVOTE_DELAY_MS 750
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304370#define BOOST_BACK_STORM_COUNT 3
4371#define WEAK_CHG_STORM_COUNT 8
Nicholas Troastabedaf72016-09-16 11:07:45 -07004372irqreturn_t smblib_handle_switcher_power_ok(int irq, void *data)
4373{
4374 struct smb_irq_data *irq_data = data;
4375 struct smb_charger *chg = irq_data->parent_data;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304376 struct storm_watch *wdata = &irq_data->storm_data;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004377 int rc, usb_icl;
Nicholas Troastabedaf72016-09-16 11:07:45 -07004378 u8 stat;
4379
4380 if (!(chg->wa_flags & BOOST_BACK_WA))
4381 return IRQ_HANDLED;
4382
4383 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
4384 if (rc < 0) {
4385 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n", rc);
4386 return IRQ_HANDLED;
4387 }
4388
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004389 /* skip suspending input if its already suspended by some other voter */
4390 usb_icl = get_effective_result(chg->usb_icl_votable);
Harry Yang379484a2017-08-29 10:26:14 -07004391 if ((stat & USE_USBIN_BIT) && usb_icl >= 0 && usb_icl <= USBIN_25MA)
Nicholas Troastabedaf72016-09-16 11:07:45 -07004392 return IRQ_HANDLED;
4393
Abhijeet Dharmapurikar2823fe32016-12-05 17:52:11 -08004394 if (stat & USE_DCIN_BIT)
Nicholas Troastabedaf72016-09-16 11:07:45 -07004395 return IRQ_HANDLED;
4396
4397 if (is_storming(&irq_data->storm_data)) {
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304398 /* This could be a weak charger reduce ICL */
4399 if (!is_client_vote_enabled(chg->usb_icl_votable,
4400 WEAK_CHARGER_VOTER)) {
4401 smblib_err(chg,
4402 "Weak charger detected: voting %dmA ICL\n",
4403 *chg->weak_chg_icl_ua / 1000);
4404 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
4405 true, *chg->weak_chg_icl_ua);
4406 /*
4407 * reset storm data and set the storm threshold
4408 * to 3 for reverse boost detection.
4409 */
4410 update_storm_count(wdata, BOOST_BACK_STORM_COUNT);
4411 } else {
4412 smblib_err(chg,
4413 "Reverse boost detected: voting 0mA to suspend input\n");
4414 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, true, 0);
4415 vote(chg->awake_votable, BOOST_BACK_VOTER, true, 0);
4416 /*
4417 * Remove the boost-back vote after a delay, to avoid
4418 * permanently suspending the input if the boost-back
4419 * condition is unintentionally hit.
4420 */
4421 schedule_delayed_work(&chg->bb_removal_work,
4422 msecs_to_jiffies(BOOST_BACK_UNVOTE_DELAY_MS));
4423 }
Nicholas Troastabedaf72016-09-16 11:07:45 -07004424 }
4425
4426 return IRQ_HANDLED;
4427}
4428
Nicholas Troast15dc0c82016-10-18 15:15:21 -07004429irqreturn_t smblib_handle_wdog_bark(int irq, void *data)
4430{
4431 struct smb_irq_data *irq_data = data;
4432 struct smb_charger *chg = irq_data->parent_data;
4433 int rc;
4434
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05304435 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
4436
Nicholas Troast15dc0c82016-10-18 15:15:21 -07004437 rc = smblib_write(chg, BARK_BITE_WDOG_PET_REG, BARK_BITE_WDOG_PET_BIT);
4438 if (rc < 0)
4439 smblib_err(chg, "Couldn't pet the dog rc=%d\n", rc);
4440
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +05304441 if (chg->step_chg_enabled || chg->sw_jeita_enabled)
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05304442 power_supply_changed(chg->batt_psy);
4443
Nicholas Troast15dc0c82016-10-18 15:15:21 -07004444 return IRQ_HANDLED;
4445}
4446
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004447/**************
4448 * Additional USB PSY getters/setters
4449 * that call interrupt functions
4450 ***************/
4451
4452int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg,
4453 union power_supply_propval *val)
4454{
4455 val->intval = chg->pr_swap_in_progress;
4456 return 0;
4457}
4458
4459int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg,
4460 const union power_supply_propval *val)
4461{
Abhijeet Dharmapurikar676bd792017-05-31 16:21:57 -07004462 int rc;
4463
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004464 chg->pr_swap_in_progress = val->intval;
4465 /*
4466 * call the cc changed irq to handle real removals while
4467 * PR_SWAP was in progress
4468 */
4469 smblib_usb_typec_change(chg);
Abhijeet Dharmapurikar676bd792017-05-31 16:21:57 -07004470 rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT,
4471 val->intval ? TCC_DEBOUNCE_20MS_BIT : 0);
4472 if (rc < 0)
4473 smblib_err(chg, "Couldn't set tCC debounce rc=%d\n", rc);
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004474 return 0;
4475}
4476
Nicholas Troast34db5032016-03-28 12:26:44 -07004477/***************
4478 * Work Queues *
4479 ***************/
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05304480static void smblib_uusb_otg_work(struct work_struct *work)
4481{
4482 struct smb_charger *chg = container_of(work, struct smb_charger,
4483 uusb_otg_work.work);
4484 int rc;
4485 u8 stat;
4486 bool otg;
4487
4488 rc = smblib_read(chg, TYPE_C_STATUS_3_REG, &stat);
4489 if (rc < 0) {
4490 smblib_err(chg, "Couldn't read TYPE_C_STATUS_3 rc=%d\n", rc);
4491 goto out;
4492 }
4493
4494 otg = !!(stat & (U_USB_GND_NOVBUS_BIT | U_USB_GND_BIT));
4495 extcon_set_cable_state_(chg->extcon, EXTCON_USB_HOST, otg);
4496 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_3 = 0x%02x OTG=%d\n",
4497 stat, otg);
4498 power_supply_changed(chg->usb_psy);
4499
4500out:
4501 vote(chg->awake_votable, OTG_DELAY_VOTER, false, 0);
4502}
4503
Nicholas Troast34db5032016-03-28 12:26:44 -07004504
4505static void smblib_hvdcp_detect_work(struct work_struct *work)
4506{
4507 struct smb_charger *chg = container_of(work, struct smb_charger,
4508 hvdcp_detect_work.work);
Nicholas Troast34db5032016-03-28 12:26:44 -07004509
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07004510 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
4511 false, 0);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004512 power_supply_changed(chg->usb_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07004513}
4514
Harry Yangfe913842016-08-10 12:27:28 -07004515static void bms_update_work(struct work_struct *work)
Harry Yang5e1a5222016-07-26 15:16:04 -07004516{
4517 struct smb_charger *chg = container_of(work, struct smb_charger,
4518 bms_update_work);
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05304519
4520 smblib_suspend_on_debug_battery(chg);
4521
4522 if (chg->batt_psy)
4523 power_supply_changed(chg->batt_psy);
Harry Yang5e1a5222016-07-26 15:16:04 -07004524}
4525
Harry Yang166b15d2017-08-28 13:00:40 -07004526static void pl_update_work(struct work_struct *work)
4527{
4528 struct smb_charger *chg = container_of(work, struct smb_charger,
4529 pl_update_work);
4530
4531 smblib_stat_sw_override_cfg(chg, false);
4532}
4533
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004534static void clear_hdc_work(struct work_struct *work)
4535{
4536 struct smb_charger *chg = container_of(work, struct smb_charger,
4537 clear_hdc_work.work);
4538
4539 chg->is_hdc = 0;
Fenglin Wu4f4dcc12017-08-24 14:28:54 +08004540 if (chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq)
4541 enable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004542}
4543
Harry Yang755a34b2016-11-01 01:18:51 -07004544static void rdstd_cc2_detach_work(struct work_struct *work)
4545{
4546 int rc;
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004547 u8 stat4, stat5;
Harry Yang755a34b2016-11-01 01:18:51 -07004548 struct smb_charger *chg = container_of(work, struct smb_charger,
4549 rdstd_cc2_detach_work);
4550
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004551 if (!chg->cc2_detach_wa_active)
4552 return;
4553
Harry Yang755a34b2016-11-01 01:18:51 -07004554 /*
4555 * WA steps -
4556 * 1. Enable both UFP and DFP, wait for 10ms.
4557 * 2. Disable DFP, wait for 30ms.
4558 * 3. Removal detected if both TYPEC_DEBOUNCE_DONE_STATUS
4559 * and TIMER_STAGE bits are gone, otherwise repeat all by
4560 * work rescheduling.
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004561 * Note, work will be cancelled when USB_PLUGIN rises.
Harry Yang755a34b2016-11-01 01:18:51 -07004562 */
4563
4564 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4565 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT,
4566 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT);
4567 if (rc < 0) {
4568 smblib_err(chg, "Couldn't write TYPE_C_CTRL_REG rc=%d\n", rc);
4569 return;
4570 }
4571
4572 usleep_range(10000, 11000);
4573
4574 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4575 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT,
4576 UFP_EN_CMD_BIT);
4577 if (rc < 0) {
4578 smblib_err(chg, "Couldn't write TYPE_C_CTRL_REG rc=%d\n", rc);
4579 return;
4580 }
4581
4582 usleep_range(30000, 31000);
4583
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004584 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
Harry Yang755a34b2016-11-01 01:18:51 -07004585 if (rc < 0) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004586 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
Harry Yang755a34b2016-11-01 01:18:51 -07004587 return;
4588 }
Harry Yang755a34b2016-11-01 01:18:51 -07004589
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004590 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
Harry Yang755a34b2016-11-01 01:18:51 -07004591 if (rc < 0) {
4592 smblib_err(chg,
4593 "Couldn't read TYPE_C_STATUS_5_REG rc=%d\n", rc);
4594 return;
4595 }
Harry Yang755a34b2016-11-01 01:18:51 -07004596
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004597 if ((stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT)
4598 || (stat5 & TIMER_STAGE_2_BIT)) {
4599 smblib_dbg(chg, PR_MISC, "rerunning DD=%d TS2BIT=%d\n",
4600 (int)(stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT),
4601 (int)(stat5 & TIMER_STAGE_2_BIT));
4602 goto rerun;
4603 }
4604
4605 smblib_dbg(chg, PR_MISC, "Bingo CC2 Removal detected\n");
4606 chg->cc2_detach_wa_active = false;
4607 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4608 EXIT_SNK_BASED_ON_CC_BIT, 0);
Harry Yang755a34b2016-11-01 01:18:51 -07004609 smblib_reg_block_restore(chg, cc2_detach_settings);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004610 mutex_lock(&chg->lock);
4611 smblib_usb_typec_change(chg);
4612 mutex_unlock(&chg->lock);
Harry Yang755a34b2016-11-01 01:18:51 -07004613 return;
4614
4615rerun:
4616 schedule_work(&chg->rdstd_cc2_detach_work);
4617}
4618
Nicholas Troastb11015f2017-01-17 17:56:45 -08004619static void smblib_otg_oc_exit(struct smb_charger *chg, bool success)
4620{
4621 int rc;
4622
4623 chg->otg_attempts = 0;
4624 if (!success) {
4625 smblib_err(chg, "OTG soft start failed\n");
4626 chg->otg_en = false;
4627 }
4628
4629 smblib_dbg(chg, PR_OTG, "enabling VBUS < 1V check\n");
4630 rc = smblib_masked_write(chg, OTG_CFG_REG,
4631 QUICKSTART_OTG_FASTROLESWAP_BIT, 0);
4632 if (rc < 0)
4633 smblib_err(chg, "Couldn't enable VBUS < 1V check rc=%d\n", rc);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004634}
4635
4636#define MAX_OC_FALLING_TRIES 10
4637static void smblib_otg_oc_work(struct work_struct *work)
4638{
4639 struct smb_charger *chg = container_of(work, struct smb_charger,
4640 otg_oc_work);
4641 int rc, i;
4642 u8 stat;
4643
4644 if (!chg->vbus_vreg || !chg->vbus_vreg->rdev)
4645 return;
4646
4647 smblib_err(chg, "over-current detected on VBUS\n");
4648 mutex_lock(&chg->otg_oc_lock);
4649 if (!chg->otg_en)
4650 goto unlock;
4651
4652 smblib_dbg(chg, PR_OTG, "disabling VBUS < 1V check\n");
4653 smblib_masked_write(chg, OTG_CFG_REG,
4654 QUICKSTART_OTG_FASTROLESWAP_BIT,
4655 QUICKSTART_OTG_FASTROLESWAP_BIT);
4656
4657 /*
4658 * If 500ms has passed and another over-current interrupt has not
4659 * triggered then it is likely that the software based soft start was
4660 * successful and the VBUS < 1V restriction should be re-enabled.
4661 */
4662 schedule_delayed_work(&chg->otg_ss_done_work, msecs_to_jiffies(500));
4663
4664 rc = _smblib_vbus_regulator_disable(chg->vbus_vreg->rdev);
4665 if (rc < 0) {
4666 smblib_err(chg, "Couldn't disable VBUS rc=%d\n", rc);
4667 goto unlock;
4668 }
4669
4670 if (++chg->otg_attempts > OTG_MAX_ATTEMPTS) {
4671 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4672 smblib_err(chg, "OTG failed to enable after %d attempts\n",
4673 chg->otg_attempts - 1);
4674 smblib_otg_oc_exit(chg, false);
4675 goto unlock;
4676 }
4677
4678 /*
4679 * The real time status should go low within 10ms. Poll every 1-2ms to
4680 * minimize the delay when re-enabling OTG.
4681 */
4682 for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) {
4683 usleep_range(1000, 2000);
4684 rc = smblib_read(chg, OTG_BASE + INT_RT_STS_OFFSET, &stat);
4685 if (rc >= 0 && !(stat & OTG_OVERCURRENT_RT_STS_BIT))
4686 break;
4687 }
4688
4689 if (i >= MAX_OC_FALLING_TRIES) {
4690 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4691 smblib_err(chg, "OTG OC did not fall after %dms\n",
4692 2 * MAX_OC_FALLING_TRIES);
4693 smblib_otg_oc_exit(chg, false);
4694 goto unlock;
4695 }
4696
4697 smblib_dbg(chg, PR_OTG, "OTG OC fell after %dms\n", 2 * i + 1);
4698 rc = _smblib_vbus_regulator_enable(chg->vbus_vreg->rdev);
4699 if (rc < 0) {
4700 smblib_err(chg, "Couldn't enable VBUS rc=%d\n", rc);
4701 goto unlock;
4702 }
4703
4704unlock:
4705 mutex_unlock(&chg->otg_oc_lock);
4706}
4707
4708static void smblib_vconn_oc_work(struct work_struct *work)
4709{
4710 struct smb_charger *chg = container_of(work, struct smb_charger,
4711 vconn_oc_work);
4712 int rc, i;
4713 u8 stat;
4714
Ashay Jaiswal0ce2c7c2017-11-14 12:29:02 +05304715 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
Ashay Jaiswal15edce42017-03-31 23:29:58 +05304716 return;
4717
Nicholas Troastb11015f2017-01-17 17:56:45 -08004718 smblib_err(chg, "over-current detected on VCONN\n");
4719 if (!chg->vconn_vreg || !chg->vconn_vreg->rdev)
4720 return;
4721
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07004722 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004723 rc = _smblib_vconn_regulator_disable(chg->vconn_vreg->rdev);
4724 if (rc < 0) {
4725 smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc);
4726 goto unlock;
4727 }
4728
4729 if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
4730 smblib_err(chg, "VCONN failed to enable after %d attempts\n",
4731 chg->otg_attempts - 1);
4732 chg->vconn_en = false;
4733 chg->vconn_attempts = 0;
4734 goto unlock;
4735 }
4736
4737 /*
4738 * The real time status should go low within 10ms. Poll every 1-2ms to
4739 * minimize the delay when re-enabling OTG.
4740 */
4741 for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) {
4742 usleep_range(1000, 2000);
4743 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
4744 if (rc >= 0 && !(stat & TYPEC_VCONN_OVERCURR_STATUS_BIT))
4745 break;
4746 }
4747
4748 if (i >= MAX_OC_FALLING_TRIES) {
4749 smblib_err(chg, "VCONN OC did not fall after %dms\n",
4750 2 * MAX_OC_FALLING_TRIES);
4751 chg->vconn_en = false;
4752 chg->vconn_attempts = 0;
4753 goto unlock;
4754 }
4755
4756 smblib_dbg(chg, PR_OTG, "VCONN OC fell after %dms\n", 2 * i + 1);
4757 if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
4758 smblib_err(chg, "VCONN failed to enable after %d attempts\n",
4759 chg->vconn_attempts - 1);
4760 chg->vconn_en = false;
4761 goto unlock;
4762 }
4763
4764 rc = _smblib_vconn_regulator_enable(chg->vconn_vreg->rdev);
4765 if (rc < 0) {
4766 smblib_err(chg, "Couldn't enable VCONN rc=%d\n", rc);
4767 goto unlock;
4768 }
4769
4770unlock:
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07004771 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004772}
4773
4774static void smblib_otg_ss_done_work(struct work_struct *work)
4775{
4776 struct smb_charger *chg = container_of(work, struct smb_charger,
4777 otg_ss_done_work.work);
4778 int rc;
4779 bool success = false;
4780 u8 stat;
4781
4782 mutex_lock(&chg->otg_oc_lock);
4783 rc = smblib_read(chg, OTG_STATUS_REG, &stat);
4784 if (rc < 0)
4785 smblib_err(chg, "Couldn't read OTG status rc=%d\n", rc);
4786 else if (stat & BOOST_SOFTSTART_DONE_BIT)
4787 success = true;
4788
4789 smblib_otg_oc_exit(chg, success);
4790 mutex_unlock(&chg->otg_oc_lock);
4791}
4792
Ashay Jaiswal4d825782017-02-18 10:11:34 +05304793static void smblib_icl_change_work(struct work_struct *work)
4794{
4795 struct smb_charger *chg = container_of(work, struct smb_charger,
4796 icl_change_work.work);
4797 int rc, settled_ua;
4798
4799 rc = smblib_get_charge_param(chg, &chg->param.icl_stat, &settled_ua);
4800 if (rc < 0) {
4801 smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
4802 return;
4803 }
4804
4805 power_supply_changed(chg->usb_main_psy);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05304806
4807 smblib_dbg(chg, PR_INTERRUPT, "icl_settled=%d\n", settled_ua);
4808}
4809
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304810static void smblib_pl_enable_work(struct work_struct *work)
4811{
4812 struct smb_charger *chg = container_of(work, struct smb_charger,
4813 pl_enable_work.work);
4814
4815 smblib_dbg(chg, PR_PARALLEL, "timer expired, enabling parallel\n");
4816 vote(chg->pl_disable_votable, PL_DELAY_VOTER, false, 0);
4817 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
4818}
4819
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004820static void smblib_legacy_detection_work(struct work_struct *work)
4821{
4822 struct smb_charger *chg = container_of(work, struct smb_charger,
4823 legacy_detection_work);
4824 int rc;
4825 u8 stat;
4826 bool legacy, rp_high;
4827
4828 mutex_lock(&chg->lock);
4829 chg->typec_en_dis_active = 1;
4830 smblib_dbg(chg, PR_MISC, "running legacy unknown workaround\n");
4831 rc = smblib_masked_write(chg,
4832 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4833 TYPEC_DISABLE_CMD_BIT,
4834 TYPEC_DISABLE_CMD_BIT);
4835 if (rc < 0)
4836 smblib_err(chg, "Couldn't disable type-c rc=%d\n", rc);
4837
4838 /* wait for the adapter to turn off VBUS */
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07004839 msleep(1000);
4840
4841 smblib_dbg(chg, PR_MISC, "legacy workaround enabling typec\n");
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004842
4843 rc = smblib_masked_write(chg,
4844 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4845 TYPEC_DISABLE_CMD_BIT, 0);
4846 if (rc < 0)
4847 smblib_err(chg, "Couldn't enable type-c rc=%d\n", rc);
4848
4849 /* wait for type-c detection to complete */
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07004850 msleep(400);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004851
4852 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat);
4853 if (rc < 0) {
4854 smblib_err(chg, "Couldn't read typec stat5 rc = %d\n", rc);
4855 goto unlock;
4856 }
4857
4858 chg->typec_legacy_valid = true;
4859 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
4860 legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT;
Nicholas Troaste1932e42017-04-12 12:38:18 -07004861 rp_high = chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH;
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07004862 smblib_dbg(chg, PR_MISC, "legacy workaround done legacy = %d rp_high = %d\n",
4863 legacy, rp_high);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004864 if (!legacy || !rp_high)
4865 vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
4866 false, 0);
4867
4868unlock:
4869 chg->typec_en_dis_active = 0;
Nicholas Troast6439e172017-06-02 14:45:39 -07004870 smblib_usb_typec_change(chg);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004871 mutex_unlock(&chg->lock);
4872}
4873
Harry Yangba874ce2016-08-19 14:17:01 -07004874static int smblib_create_votables(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07004875{
4876 int rc = 0;
4877
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304878 chg->fcc_votable = find_votable("FCC");
Harry Yang0c35ff62017-04-06 00:02:30 -07004879 if (chg->fcc_votable == NULL) {
4880 rc = -EINVAL;
4881 smblib_err(chg, "Couldn't find FCC votable rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304882 return rc;
4883 }
4884
4885 chg->fv_votable = find_votable("FV");
Harry Yang0c35ff62017-04-06 00:02:30 -07004886 if (chg->fv_votable == NULL) {
4887 rc = -EINVAL;
4888 smblib_err(chg, "Couldn't find FV votable rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304889 return rc;
4890 }
4891
Ashay Jaiswalae1586d2017-03-22 23:18:51 +05304892 chg->usb_icl_votable = find_votable("USB_ICL");
4893 if (!chg->usb_icl_votable) {
Harry Yang0c35ff62017-04-06 00:02:30 -07004894 rc = -EINVAL;
4895 smblib_err(chg, "Couldn't find USB_ICL votable rc=%d\n", rc);
Ashay Jaiswalae1586d2017-03-22 23:18:51 +05304896 return rc;
4897 }
4898
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304899 chg->pl_disable_votable = find_votable("PL_DISABLE");
Harry Yang0c35ff62017-04-06 00:02:30 -07004900 if (chg->pl_disable_votable == NULL) {
4901 rc = -EINVAL;
4902 smblib_err(chg, "Couldn't find votable PL_DISABLE rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304903 return rc;
4904 }
Abhijeet Dharmapurikar38ef1422017-05-18 15:37:56 -07004905
4906 chg->pl_enable_votable_indirect = find_votable("PL_ENABLE_INDIRECT");
4907 if (chg->pl_enable_votable_indirect == NULL) {
4908 rc = -EINVAL;
4909 smblib_err(chg,
4910 "Couldn't find votable PL_ENABLE_INDIRECT rc=%d\n",
4911 rc);
4912 return rc;
4913 }
4914
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304915 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304916
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004917 chg->dc_suspend_votable = create_votable("DC_SUSPEND", VOTE_SET_ANY,
4918 smblib_dc_suspend_vote_callback,
4919 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07004920 if (IS_ERR(chg->dc_suspend_votable)) {
4921 rc = PTR_ERR(chg->dc_suspend_votable);
4922 return rc;
4923 }
4924
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004925 chg->dc_icl_votable = create_votable("DC_ICL", VOTE_MIN,
4926 smblib_dc_icl_vote_callback,
4927 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07004928 if (IS_ERR(chg->dc_icl_votable)) {
4929 rc = PTR_ERR(chg->dc_icl_votable);
4930 return rc;
4931 }
4932
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07004933 chg->pd_disallowed_votable_indirect
4934 = create_votable("PD_DISALLOWED_INDIRECT", VOTE_SET_ANY,
4935 smblib_pd_disallowed_votable_indirect_callback, chg);
4936 if (IS_ERR(chg->pd_disallowed_votable_indirect)) {
4937 rc = PTR_ERR(chg->pd_disallowed_votable_indirect);
4938 return rc;
4939 }
4940
4941 chg->pd_allowed_votable = create_votable("PD_ALLOWED",
4942 VOTE_SET_ANY, NULL, NULL);
Nicholas Troast34db5032016-03-28 12:26:44 -07004943 if (IS_ERR(chg->pd_allowed_votable)) {
4944 rc = PTR_ERR(chg->pd_allowed_votable);
4945 return rc;
4946 }
4947
Harry Yang223c6282016-06-14 15:48:36 -07004948 chg->awake_votable = create_votable("AWAKE", VOTE_SET_ANY,
4949 smblib_awake_vote_callback,
4950 chg);
4951 if (IS_ERR(chg->awake_votable)) {
4952 rc = PTR_ERR(chg->awake_votable);
4953 return rc;
4954 }
4955
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07004956 chg->chg_disable_votable = create_votable("CHG_DISABLE", VOTE_SET_ANY,
4957 smblib_chg_disable_vote_callback,
4958 chg);
4959 if (IS_ERR(chg->chg_disable_votable)) {
4960 rc = PTR_ERR(chg->chg_disable_votable);
4961 return rc;
4962 }
4963
Harry Yangaba1f5f2016-09-28 10:47:29 -07004964
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05304965 chg->hvdcp_disable_votable_indirect = create_votable(
4966 "HVDCP_DISABLE_INDIRECT",
4967 VOTE_SET_ANY,
4968 smblib_hvdcp_disable_indirect_vote_callback,
4969 chg);
4970 if (IS_ERR(chg->hvdcp_disable_votable_indirect)) {
4971 rc = PTR_ERR(chg->hvdcp_disable_votable_indirect);
4972 return rc;
4973 }
4974
4975 chg->hvdcp_enable_votable = create_votable("HVDCP_ENABLE",
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07004976 VOTE_SET_ANY,
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05304977 smblib_hvdcp_enable_vote_callback,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07004978 chg);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05304979 if (IS_ERR(chg->hvdcp_enable_votable)) {
4980 rc = PTR_ERR(chg->hvdcp_enable_votable);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07004981 return rc;
4982 }
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07004983
4984 chg->apsd_disable_votable = create_votable("APSD_DISABLE",
4985 VOTE_SET_ANY,
4986 smblib_apsd_disable_vote_callback,
4987 chg);
4988 if (IS_ERR(chg->apsd_disable_votable)) {
4989 rc = PTR_ERR(chg->apsd_disable_votable);
4990 return rc;
4991 }
4992
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05304993 chg->hvdcp_hw_inov_dis_votable = create_votable("HVDCP_HW_INOV_DIS",
4994 VOTE_SET_ANY,
4995 smblib_hvdcp_hw_inov_dis_vote_callback,
4996 chg);
4997 if (IS_ERR(chg->hvdcp_hw_inov_dis_votable)) {
4998 rc = PTR_ERR(chg->hvdcp_hw_inov_dis_votable);
4999 return rc;
5000 }
5001
Harry Yang4bf7d962017-03-13 16:51:43 -07005002 chg->usb_irq_enable_votable = create_votable("USB_IRQ_DISABLE",
5003 VOTE_SET_ANY,
5004 smblib_usb_irq_enable_vote_callback,
5005 chg);
5006 if (IS_ERR(chg->usb_irq_enable_votable)) {
5007 rc = PTR_ERR(chg->usb_irq_enable_votable);
5008 return rc;
5009 }
5010
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07005011 chg->typec_irq_disable_votable = create_votable("TYPEC_IRQ_DISABLE",
5012 VOTE_SET_ANY,
5013 smblib_typec_irq_disable_vote_callback,
5014 chg);
5015 if (IS_ERR(chg->typec_irq_disable_votable)) {
5016 rc = PTR_ERR(chg->typec_irq_disable_votable);
5017 return rc;
5018 }
5019
Nicholas Troast320839e2016-06-03 10:18:00 -07005020 return rc;
5021}
5022
Harry Yangba874ce2016-08-19 14:17:01 -07005023static void smblib_destroy_votables(struct smb_charger *chg)
5024{
Harry Yangba874ce2016-08-19 14:17:01 -07005025 if (chg->dc_suspend_votable)
5026 destroy_votable(chg->dc_suspend_votable);
Harry Yangba874ce2016-08-19 14:17:01 -07005027 if (chg->usb_icl_votable)
5028 destroy_votable(chg->usb_icl_votable);
5029 if (chg->dc_icl_votable)
5030 destroy_votable(chg->dc_icl_votable);
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07005031 if (chg->pd_disallowed_votable_indirect)
5032 destroy_votable(chg->pd_disallowed_votable_indirect);
Harry Yangba874ce2016-08-19 14:17:01 -07005033 if (chg->pd_allowed_votable)
5034 destroy_votable(chg->pd_allowed_votable);
5035 if (chg->awake_votable)
5036 destroy_votable(chg->awake_votable);
Harry Yangaba1f5f2016-09-28 10:47:29 -07005037 if (chg->chg_disable_votable)
5038 destroy_votable(chg->chg_disable_votable);
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07005039 if (chg->apsd_disable_votable)
5040 destroy_votable(chg->apsd_disable_votable);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05305041 if (chg->hvdcp_hw_inov_dis_votable)
5042 destroy_votable(chg->hvdcp_hw_inov_dis_votable);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07005043 if (chg->typec_irq_disable_votable)
5044 destroy_votable(chg->typec_irq_disable_votable);
Harry Yangba874ce2016-08-19 14:17:01 -07005045}
5046
5047static void smblib_iio_deinit(struct smb_charger *chg)
5048{
5049 if (!IS_ERR_OR_NULL(chg->iio.temp_chan))
5050 iio_channel_release(chg->iio.temp_chan);
5051 if (!IS_ERR_OR_NULL(chg->iio.temp_max_chan))
5052 iio_channel_release(chg->iio.temp_max_chan);
5053 if (!IS_ERR_OR_NULL(chg->iio.usbin_i_chan))
5054 iio_channel_release(chg->iio.usbin_i_chan);
5055 if (!IS_ERR_OR_NULL(chg->iio.usbin_v_chan))
5056 iio_channel_release(chg->iio.usbin_v_chan);
Nicholas Troast7dbcad22016-10-05 13:30:18 -07005057 if (!IS_ERR_OR_NULL(chg->iio.batt_i_chan))
5058 iio_channel_release(chg->iio.batt_i_chan);
Harry Yangba874ce2016-08-19 14:17:01 -07005059}
5060
Nicholas Troast320839e2016-06-03 10:18:00 -07005061int smblib_init(struct smb_charger *chg)
5062{
5063 int rc = 0;
5064
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07005065 mutex_init(&chg->lock);
Nicholas Troast320839e2016-06-03 10:18:00 -07005066 mutex_init(&chg->write_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08005067 mutex_init(&chg->otg_oc_lock);
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07005068 mutex_init(&chg->vconn_oc_lock);
Harry Yangfe913842016-08-10 12:27:28 -07005069 INIT_WORK(&chg->bms_update_work, bms_update_work);
Harry Yang166b15d2017-08-28 13:00:40 -07005070 INIT_WORK(&chg->pl_update_work, pl_update_work);
Harry Yang755a34b2016-11-01 01:18:51 -07005071 INIT_WORK(&chg->rdstd_cc2_detach_work, rdstd_cc2_detach_work);
Nicholas Troast320839e2016-06-03 10:18:00 -07005072 INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07005073 INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work);
Nicholas Troastb11015f2017-01-17 17:56:45 -08005074 INIT_WORK(&chg->otg_oc_work, smblib_otg_oc_work);
5075 INIT_WORK(&chg->vconn_oc_work, smblib_vconn_oc_work);
5076 INIT_DELAYED_WORK(&chg->otg_ss_done_work, smblib_otg_ss_done_work);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05305077 INIT_DELAYED_WORK(&chg->icl_change_work, smblib_icl_change_work);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05305078 INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07005079 INIT_WORK(&chg->legacy_detection_work, smblib_legacy_detection_work);
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05305080 INIT_DELAYED_WORK(&chg->uusb_otg_work, smblib_uusb_otg_work);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05305081 INIT_DELAYED_WORK(&chg->bb_removal_work, smblib_bb_removal_work);
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07005082 chg->fake_capacity = -EINVAL;
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07005083 chg->fake_input_current_limited = -EINVAL;
Harry Yang589dd422017-07-28 18:41:42 -07005084 chg->fake_batt_status = -EINVAL;
Nicholas Troast320839e2016-06-03 10:18:00 -07005085
5086 switch (chg->mode) {
5087 case PARALLEL_MASTER:
Harry Yang0c35ff62017-04-06 00:02:30 -07005088 rc = qcom_batt_init();
5089 if (rc < 0) {
5090 smblib_err(chg, "Couldn't init qcom_batt_init rc=%d\n",
5091 rc);
5092 return rc;
5093 }
5094
Fenglin Wudd8f4cb2017-10-17 11:09:46 +08005095 rc = qcom_step_chg_init(chg->dev, chg->step_chg_enabled,
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +05305096 chg->sw_jeita_enabled);
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05305097 if (rc < 0) {
5098 smblib_err(chg, "Couldn't init qcom_step_chg_init rc=%d\n",
5099 rc);
5100 return rc;
5101 }
5102
Nicholas Troast320839e2016-06-03 10:18:00 -07005103 rc = smblib_create_votables(chg);
5104 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07005105 smblib_err(chg, "Couldn't create votables rc=%d\n",
Nicholas Troast320839e2016-06-03 10:18:00 -07005106 rc);
Harry Yang58a9e7a2016-06-23 14:54:43 -07005107 return rc;
Nicholas Troast320839e2016-06-03 10:18:00 -07005108 }
Harry Yang58a9e7a2016-06-23 14:54:43 -07005109
Harry Yang5e1a5222016-07-26 15:16:04 -07005110 rc = smblib_register_notifier(chg);
5111 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07005112 smblib_err(chg,
Harry Yang5e1a5222016-07-26 15:16:04 -07005113 "Couldn't register notifier rc=%d\n", rc);
5114 return rc;
Harry Yang58a9e7a2016-06-23 14:54:43 -07005115 }
5116
Harry Yang995b7422016-08-29 16:06:50 -07005117 chg->bms_psy = power_supply_get_by_name("bms");
Ashay Jaiswal8afedfc2017-02-03 11:18:22 +05305118 chg->pl.psy = power_supply_get_by_name("parallel");
Harry Yang166b15d2017-08-28 13:00:40 -07005119 if (chg->pl.psy) {
5120 rc = smblib_stat_sw_override_cfg(chg, false);
5121 if (rc < 0) {
5122 smblib_err(chg,
5123 "Couldn't config stat sw rc=%d\n", rc);
5124 return rc;
5125 }
5126 }
Nicholas Troast320839e2016-06-03 10:18:00 -07005127 break;
5128 case PARALLEL_SLAVE:
5129 break;
5130 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07005131 smblib_err(chg, "Unsupported mode %d\n", chg->mode);
Nicholas Troast320839e2016-06-03 10:18:00 -07005132 return -EINVAL;
5133 }
5134
5135 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07005136}
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07005137
5138int smblib_deinit(struct smb_charger *chg)
5139{
Harry Yangba874ce2016-08-19 14:17:01 -07005140 switch (chg->mode) {
5141 case PARALLEL_MASTER:
Harry Yang0c35ff62017-04-06 00:02:30 -07005142 cancel_work_sync(&chg->bms_update_work);
Harry Yang166b15d2017-08-28 13:00:40 -07005143 cancel_work_sync(&chg->pl_update_work);
Harry Yang0c35ff62017-04-06 00:02:30 -07005144 cancel_work_sync(&chg->rdstd_cc2_detach_work);
5145 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
Harry Yang0c35ff62017-04-06 00:02:30 -07005146 cancel_delayed_work_sync(&chg->clear_hdc_work);
5147 cancel_work_sync(&chg->otg_oc_work);
5148 cancel_work_sync(&chg->vconn_oc_work);
5149 cancel_delayed_work_sync(&chg->otg_ss_done_work);
5150 cancel_delayed_work_sync(&chg->icl_change_work);
5151 cancel_delayed_work_sync(&chg->pl_enable_work);
5152 cancel_work_sync(&chg->legacy_detection_work);
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05305153 cancel_delayed_work_sync(&chg->uusb_otg_work);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05305154 cancel_delayed_work_sync(&chg->bb_removal_work);
Harry Yangba874ce2016-08-19 14:17:01 -07005155 power_supply_unreg_notifier(&chg->nb);
5156 smblib_destroy_votables(chg);
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05305157 qcom_step_chg_deinit();
Harry Yang0c35ff62017-04-06 00:02:30 -07005158 qcom_batt_deinit();
Harry Yangba874ce2016-08-19 14:17:01 -07005159 break;
5160 case PARALLEL_SLAVE:
5161 break;
5162 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07005163 smblib_err(chg, "Unsupported mode %d\n", chg->mode);
Harry Yangba874ce2016-08-19 14:17:01 -07005164 return -EINVAL;
5165 }
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07005166
Harry Yangba874ce2016-08-19 14:17:01 -07005167 smblib_iio_deinit(chg);
Harry Yang5e1a5222016-07-26 15:16:04 -07005168
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07005169 return 0;
5170}