blob: bca4be3f066b806e5a0a47a3796b37b0fbf9492c [file] [log] [blame]
Harry Yang3b113a52016-12-08 12:37:40 -08001/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
Nicholas Troast34db5032016-03-28 12:26:44 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/device.h>
14#include <linux/regmap.h>
Harry Yang360bd532016-09-26 11:03:22 -070015#include <linux/delay.h>
Harry Yangba874ce2016-08-19 14:17:01 -070016#include <linux/iio/consumer.h>
Nicholas Troast34db5032016-03-28 12:26:44 -070017#include <linux/power_supply.h>
18#include <linux/regulator/driver.h>
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -080019#include <linux/qpnp/qpnp-revid.h>
Nicholas Troast34db5032016-03-28 12:26:44 -070020#include <linux/irq.h>
Harry Yang0c35ff62017-04-06 00:02:30 -070021#include <linux/pmic-voter.h>
Nicholas Troast34db5032016-03-28 12:26:44 -070022#include "smb-lib.h"
23#include "smb-reg.h"
Harry Yang0c35ff62017-04-06 00:02:30 -070024#include "battery.h"
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +053025#include "step-chg-jeita.h"
Nicholas Troast47ae4612016-08-03 09:49:36 -070026#include "storm-watch.h"
Nicholas Troast34db5032016-03-28 12:26:44 -070027
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -070028#define smblib_err(chg, fmt, ...) \
29 pr_err("%s: %s: " fmt, chg->name, \
30 __func__, ##__VA_ARGS__) \
31
Nicholas Troast34db5032016-03-28 12:26:44 -070032#define smblib_dbg(chg, reason, fmt, ...) \
33 do { \
34 if (*chg->debug_mask & (reason)) \
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -070035 pr_info("%s: %s: " fmt, chg->name, \
36 __func__, ##__VA_ARGS__); \
Nicholas Troast34db5032016-03-28 12:26:44 -070037 else \
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -070038 pr_debug("%s: %s: " fmt, chg->name, \
39 __func__, ##__VA_ARGS__); \
Nicholas Troast34db5032016-03-28 12:26:44 -070040 } while (0)
41
42static bool is_secure(struct smb_charger *chg, int addr)
43{
Anirudh Ghayal4da3df92017-01-25 18:55:57 +053044 if (addr == SHIP_MODE_REG || addr == FREQ_CLK_DIV_REG)
Fenglin Wuedd70792016-11-22 13:16:19 +080045 return true;
Harry Yang47bd3852016-10-17 10:37:12 -070046 /* assume everything above 0xA0 is secure */
47 return (bool)((addr & 0xFF) >= 0xA0);
Nicholas Troast34db5032016-03-28 12:26:44 -070048}
49
50int smblib_read(struct smb_charger *chg, u16 addr, u8 *val)
51{
52 unsigned int temp;
53 int rc = 0;
54
55 rc = regmap_read(chg->regmap, addr, &temp);
56 if (rc >= 0)
57 *val = (u8)temp;
58
59 return rc;
60}
61
Ashay Jaiswal6d308da2017-02-18 09:59:23 +053062int smblib_multibyte_read(struct smb_charger *chg, u16 addr, u8 *val,
63 int count)
64{
65 return regmap_bulk_read(chg->regmap, addr, val, count);
66}
67
Nicholas Troast34db5032016-03-28 12:26:44 -070068int smblib_masked_write(struct smb_charger *chg, u16 addr, u8 mask, u8 val)
69{
Nicholas Troast34db5032016-03-28 12:26:44 -070070 int rc = 0;
71
Harry Yangbacd2222016-05-11 16:43:51 -070072 mutex_lock(&chg->write_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -070073 if (is_secure(chg, addr)) {
74 rc = regmap_write(chg->regmap, (addr & 0xFF00) | 0xD0, 0xA5);
75 if (rc < 0)
76 goto unlock;
77 }
78
79 rc = regmap_update_bits(chg->regmap, addr, mask, val);
80
81unlock:
Harry Yangbacd2222016-05-11 16:43:51 -070082 mutex_unlock(&chg->write_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -070083 return rc;
84}
85
86int smblib_write(struct smb_charger *chg, u16 addr, u8 val)
87{
Nicholas Troast34db5032016-03-28 12:26:44 -070088 int rc = 0;
89
Harry Yangbacd2222016-05-11 16:43:51 -070090 mutex_lock(&chg->write_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -070091
92 if (is_secure(chg, addr)) {
93 rc = regmap_write(chg->regmap, (addr & ~(0xFF)) | 0xD0, 0xA5);
94 if (rc < 0)
95 goto unlock;
96 }
97
98 rc = regmap_write(chg->regmap, addr, val);
99
100unlock:
Harry Yangbacd2222016-05-11 16:43:51 -0700101 mutex_unlock(&chg->write_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -0700102 return rc;
103}
104
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -0700105static int smblib_get_jeita_cc_delta(struct smb_charger *chg, int *cc_delta_ua)
106{
107 int rc, cc_minus_ua;
108 u8 stat;
Harry Yangfe913842016-08-10 12:27:28 -0700109
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -0700110 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat);
111 if (rc < 0) {
112 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
113 rc);
114 return rc;
115 }
116
117 if (!(stat & BAT_TEMP_STATUS_SOFT_LIMIT_MASK)) {
118 *cc_delta_ua = 0;
119 return 0;
120 }
121
122 rc = smblib_get_charge_param(chg, &chg->param.jeita_cc_comp,
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +0530123 &cc_minus_ua);
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -0700124 if (rc < 0) {
125 smblib_err(chg, "Couldn't get jeita cc minus rc=%d\n", rc);
126 return rc;
127 }
128
129 *cc_delta_ua = -cc_minus_ua;
130 return 0;
131}
132
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800133int smblib_icl_override(struct smb_charger *chg, bool override)
134{
135 int rc;
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800136
Nicholas Troast11af51b2017-03-15 10:45:28 -0700137 rc = smblib_masked_write(chg, USBIN_LOAD_CFG_REG,
138 ICL_OVERRIDE_AFTER_APSD_BIT,
139 override ? ICL_OVERRIDE_AFTER_APSD_BIT : 0);
140 if (rc < 0)
141 smblib_err(chg, "Couldn't override ICL rc=%d\n", rc);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -0800142
Nicholas Troast11af51b2017-03-15 10:45:28 -0700143 return rc;
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800144}
145
Harry Yang166b15d2017-08-28 13:00:40 -0700146int smblib_stat_sw_override_cfg(struct smb_charger *chg, bool override)
147{
148 int rc;
149
150 /* override = 1, SW STAT override; override = 0, HW auto mode */
151 rc = smblib_masked_write(chg, STAT_CFG_REG,
152 STAT_SW_OVERRIDE_CFG_BIT,
153 override ? STAT_SW_OVERRIDE_CFG_BIT : 0);
154 if (rc < 0) {
155 dev_err(chg->dev, "Couldn't configure SW STAT override rc=%d\n",
156 rc);
157 return rc;
158 }
159
160 return rc;
161}
162
Nicholas Troast34db5032016-03-28 12:26:44 -0700163/********************
164 * REGISTER GETTERS *
165 ********************/
166
Nicholas Troast4c310492016-05-12 17:56:35 -0700167int smblib_get_charge_param(struct smb_charger *chg,
168 struct smb_chg_param *param, int *val_u)
169{
170 int rc = 0;
171 u8 val_raw;
172
173 rc = smblib_read(chg, param->reg, &val_raw);
174 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700175 smblib_err(chg, "%s: Couldn't read from 0x%04x rc=%d\n",
Nicholas Troast4c310492016-05-12 17:56:35 -0700176 param->name, param->reg, rc);
177 return rc;
178 }
179
Harry Yangf8b41252016-08-10 14:21:10 -0700180 if (param->get_proc)
181 *val_u = param->get_proc(param, val_raw);
182 else
183 *val_u = val_raw * param->step_u + param->min_u;
Nicholas Troast4c310492016-05-12 17:56:35 -0700184 smblib_dbg(chg, PR_REGISTER, "%s = %d (0x%02x)\n",
185 param->name, *val_u, val_raw);
186
187 return rc;
188}
189
190int smblib_get_usb_suspend(struct smb_charger *chg, int *suspend)
191{
192 int rc = 0;
193 u8 temp;
194
195 rc = smblib_read(chg, USBIN_CMD_IL_REG, &temp);
196 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700197 smblib_err(chg, "Couldn't read USBIN_CMD_IL rc=%d\n", rc);
Nicholas Troast4c310492016-05-12 17:56:35 -0700198 return rc;
199 }
200 *suspend = temp & USBIN_SUSPEND_BIT;
201
202 return rc;
203}
204
Nicholas Troast34db5032016-03-28 12:26:44 -0700205struct apsd_result {
206 const char * const name;
207 const u8 bit;
208 const enum power_supply_type pst;
209};
210
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700211enum {
212 UNKNOWN,
213 SDP,
214 CDP,
215 DCP,
216 OCP,
217 FLOAT,
218 HVDCP2,
219 HVDCP3,
220 MAX_TYPES
221};
222
Nicholas Troast34db5032016-03-28 12:26:44 -0700223static const struct apsd_result const smblib_apsd_results[] = {
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700224 [UNKNOWN] = {
225 .name = "UNKNOWN",
226 .bit = 0,
227 .pst = POWER_SUPPLY_TYPE_UNKNOWN
228 },
229 [SDP] = {
230 .name = "SDP",
231 .bit = SDP_CHARGER_BIT,
232 .pst = POWER_SUPPLY_TYPE_USB
233 },
234 [CDP] = {
235 .name = "CDP",
236 .bit = CDP_CHARGER_BIT,
237 .pst = POWER_SUPPLY_TYPE_USB_CDP
238 },
239 [DCP] = {
240 .name = "DCP",
241 .bit = DCP_CHARGER_BIT,
242 .pst = POWER_SUPPLY_TYPE_USB_DCP
243 },
244 [OCP] = {
245 .name = "OCP",
246 .bit = OCP_CHARGER_BIT,
247 .pst = POWER_SUPPLY_TYPE_USB_DCP
248 },
249 [FLOAT] = {
250 .name = "FLOAT",
251 .bit = FLOAT_CHARGER_BIT,
Ashay Jaiswalb9b2d2f2017-06-21 12:08:38 +0530252 .pst = POWER_SUPPLY_TYPE_USB_FLOAT
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700253 },
254 [HVDCP2] = {
255 .name = "HVDCP2",
256 .bit = DCP_CHARGER_BIT | QC_2P0_BIT,
257 .pst = POWER_SUPPLY_TYPE_USB_HVDCP
258 },
259 [HVDCP3] = {
260 .name = "HVDCP3",
261 .bit = DCP_CHARGER_BIT | QC_3P0_BIT,
262 .pst = POWER_SUPPLY_TYPE_USB_HVDCP_3,
263 },
Nicholas Troast34db5032016-03-28 12:26:44 -0700264};
265
266static const struct apsd_result *smblib_get_apsd_result(struct smb_charger *chg)
267{
268 int rc, i;
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700269 u8 apsd_stat, stat;
270 const struct apsd_result *result = &smblib_apsd_results[UNKNOWN];
Nicholas Troast34db5032016-03-28 12:26:44 -0700271
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700272 rc = smblib_read(chg, APSD_STATUS_REG, &apsd_stat);
Nicholas Troast34db5032016-03-28 12:26:44 -0700273 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700274 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700275 return result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700276 }
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700277 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", apsd_stat);
Nicholas Troast34db5032016-03-28 12:26:44 -0700278
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700279 if (!(apsd_stat & APSD_DTC_STATUS_DONE_BIT))
280 return result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700281
282 rc = smblib_read(chg, APSD_RESULT_STATUS_REG, &stat);
283 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700284 smblib_err(chg, "Couldn't read APSD_RESULT_STATUS rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700285 rc);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700286 return result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700287 }
288 stat &= APSD_RESULT_STATUS_MASK;
289
290 for (i = 0; i < ARRAY_SIZE(smblib_apsd_results); i++) {
291 if (smblib_apsd_results[i].bit == stat)
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700292 result = &smblib_apsd_results[i];
Nicholas Troast34db5032016-03-28 12:26:44 -0700293 }
294
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700295 if (apsd_stat & QC_CHARGER_BIT) {
296 /* since its a qc_charger, either return HVDCP3 or HVDCP2 */
297 if (result != &smblib_apsd_results[HVDCP3])
298 result = &smblib_apsd_results[HVDCP2];
299 }
300
301 return result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700302}
303
Nicholas Troast34db5032016-03-28 12:26:44 -0700304/********************
305 * REGISTER SETTERS *
306 ********************/
307
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530308static int chg_freq_list[] = {
309 9600, 9600, 6400, 4800, 3800, 3200, 2700, 2400, 2100, 1900, 1700,
310 1600, 1500, 1400, 1300, 1200,
311};
312
313int smblib_set_chg_freq(struct smb_chg_param *param,
314 int val_u, u8 *val_raw)
315{
316 u8 i;
317
318 if (val_u > param->max_u || val_u < param->min_u)
319 return -EINVAL;
320
321 /* Charger FSW is the configured freqency / 2 */
322 val_u *= 2;
323 for (i = 0; i < ARRAY_SIZE(chg_freq_list); i++) {
324 if (chg_freq_list[i] == val_u)
325 break;
326 }
327 if (i == ARRAY_SIZE(chg_freq_list)) {
328 pr_err("Invalid frequency %d Hz\n", val_u / 2);
329 return -EINVAL;
330 }
331
332 *val_raw = i;
333
334 return 0;
335}
336
337static int smblib_set_opt_freq_buck(struct smb_charger *chg, int fsw_khz)
338{
339 union power_supply_propval pval = {0, };
340 int rc = 0;
341
342 rc = smblib_set_charge_param(chg, &chg->param.freq_buck, fsw_khz);
343 if (rc < 0)
344 dev_err(chg->dev, "Error in setting freq_buck rc=%d\n", rc);
345
346 if (chg->mode == PARALLEL_MASTER && chg->pl.psy) {
347 pval.intval = fsw_khz;
Abhijeet Dharmapurikare9fd08d2017-02-27 11:05:28 -0800348 /*
349 * Some parallel charging implementations may not have
350 * PROP_BUCK_FREQ property - they could be running
351 * with a fixed frequency
352 */
353 power_supply_set_property(chg->pl.psy,
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530354 POWER_SUPPLY_PROP_BUCK_FREQ, &pval);
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530355 }
356
357 return rc;
358}
359
Nicholas Troast4c310492016-05-12 17:56:35 -0700360int smblib_set_charge_param(struct smb_charger *chg,
361 struct smb_chg_param *param, int val_u)
Nicholas Troast34db5032016-03-28 12:26:44 -0700362{
363 int rc = 0;
364 u8 val_raw;
365
Harry Yangf8b41252016-08-10 14:21:10 -0700366 if (param->set_proc) {
367 rc = param->set_proc(param, val_u, &val_raw);
368 if (rc < 0)
369 return -EINVAL;
370 } else {
371 if (val_u > param->max_u || val_u < param->min_u) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700372 smblib_err(chg, "%s: %d is out of range [%d, %d]\n",
Harry Yangf8b41252016-08-10 14:21:10 -0700373 param->name, val_u, param->min_u, param->max_u);
374 return -EINVAL;
375 }
376
377 val_raw = (val_u - param->min_u) / param->step_u;
Nicholas Troast34db5032016-03-28 12:26:44 -0700378 }
379
Nicholas Troast34db5032016-03-28 12:26:44 -0700380 rc = smblib_write(chg, param->reg, val_raw);
381 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700382 smblib_err(chg, "%s: Couldn't write 0x%02x to 0x%04x rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700383 param->name, val_raw, param->reg, rc);
384 return rc;
385 }
386
387 smblib_dbg(chg, PR_REGISTER, "%s = %d (0x%02x)\n",
388 param->name, val_u, val_raw);
389
390 return rc;
391}
392
Nicholas Troast4c310492016-05-12 17:56:35 -0700393int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend)
Nicholas Troast34db5032016-03-28 12:26:44 -0700394{
395 int rc = 0;
Abhijeet Dharmapurikar109802f712017-07-07 18:30:54 -0700396 int irq = chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq;
397
398 if (suspend && irq) {
399 if (chg->usb_icl_change_irq_enabled) {
400 disable_irq_nosync(irq);
401 chg->usb_icl_change_irq_enabled = false;
402 }
403 }
Nicholas Troast34db5032016-03-28 12:26:44 -0700404
405 rc = smblib_masked_write(chg, USBIN_CMD_IL_REG, USBIN_SUSPEND_BIT,
406 suspend ? USBIN_SUSPEND_BIT : 0);
407 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700408 smblib_err(chg, "Couldn't write %s to USBIN_SUSPEND_BIT rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700409 suspend ? "suspend" : "resume", rc);
410
Abhijeet Dharmapurikar109802f712017-07-07 18:30:54 -0700411 if (!suspend && irq) {
412 if (!chg->usb_icl_change_irq_enabled) {
413 enable_irq(irq);
414 chg->usb_icl_change_irq_enabled = true;
415 }
416 }
417
Nicholas Troast34db5032016-03-28 12:26:44 -0700418 return rc;
419}
420
Nicholas Troast4c310492016-05-12 17:56:35 -0700421int smblib_set_dc_suspend(struct smb_charger *chg, bool suspend)
Nicholas Troast34db5032016-03-28 12:26:44 -0700422{
423 int rc = 0;
424
425 rc = smblib_masked_write(chg, DCIN_CMD_IL_REG, DCIN_SUSPEND_BIT,
426 suspend ? DCIN_SUSPEND_BIT : 0);
427 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700428 smblib_err(chg, "Couldn't write %s to DCIN_SUSPEND_BIT rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700429 suspend ? "suspend" : "resume", rc);
430
431 return rc;
432}
433
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530434static int smblib_set_adapter_allowance(struct smb_charger *chg,
435 u8 allowed_voltage)
436{
437 int rc = 0;
438
Nicholas Troast7f55c922017-07-25 13:18:03 -0700439 /* PM660 only support max. 9V */
440 if (chg->smb_version == PM660_SUBTYPE) {
441 switch (allowed_voltage) {
442 case USBIN_ADAPTER_ALLOW_12V:
443 case USBIN_ADAPTER_ALLOW_9V_TO_12V:
444 allowed_voltage = USBIN_ADAPTER_ALLOW_9V;
445 break;
446 case USBIN_ADAPTER_ALLOW_5V_OR_12V:
447 case USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V:
448 allowed_voltage = USBIN_ADAPTER_ALLOW_5V_OR_9V;
449 break;
450 case USBIN_ADAPTER_ALLOW_5V_TO_12V:
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530451 allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_9V;
Nicholas Troast7f55c922017-07-25 13:18:03 -0700452 break;
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530453 }
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530454 }
455
456 rc = smblib_write(chg, USBIN_ADAPTER_ALLOW_CFG_REG, allowed_voltage);
457 if (rc < 0) {
458 smblib_err(chg, "Couldn't write 0x%02x to USBIN_ADAPTER_ALLOW_CFG rc=%d\n",
459 allowed_voltage, rc);
460 return rc;
461 }
462
463 return rc;
464}
465
Nicholas Troast34db5032016-03-28 12:26:44 -0700466#define MICRO_5V 5000000
467#define MICRO_9V 9000000
468#define MICRO_12V 12000000
469static int smblib_set_usb_pd_allowed_voltage(struct smb_charger *chg,
470 int min_allowed_uv, int max_allowed_uv)
471{
472 int rc;
473 u8 allowed_voltage;
474
475 if (min_allowed_uv == MICRO_5V && max_allowed_uv == MICRO_5V) {
476 allowed_voltage = USBIN_ADAPTER_ALLOW_5V;
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530477 smblib_set_opt_freq_buck(chg, chg->chg_freq.freq_5V);
Nicholas Troast34db5032016-03-28 12:26:44 -0700478 } else if (min_allowed_uv == MICRO_9V && max_allowed_uv == MICRO_9V) {
479 allowed_voltage = USBIN_ADAPTER_ALLOW_9V;
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530480 smblib_set_opt_freq_buck(chg, chg->chg_freq.freq_9V);
Nicholas Troast34db5032016-03-28 12:26:44 -0700481 } else if (min_allowed_uv == MICRO_12V && max_allowed_uv == MICRO_12V) {
482 allowed_voltage = USBIN_ADAPTER_ALLOW_12V;
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530483 smblib_set_opt_freq_buck(chg, chg->chg_freq.freq_12V);
Nicholas Troast34db5032016-03-28 12:26:44 -0700484 } else if (min_allowed_uv < MICRO_9V && max_allowed_uv <= MICRO_9V) {
485 allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_9V;
486 } else if (min_allowed_uv < MICRO_9V && max_allowed_uv <= MICRO_12V) {
487 allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_12V;
488 } else if (min_allowed_uv < MICRO_12V && max_allowed_uv <= MICRO_12V) {
489 allowed_voltage = USBIN_ADAPTER_ALLOW_9V_TO_12V;
490 } else {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700491 smblib_err(chg, "invalid allowed voltage [%d, %d]\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700492 min_allowed_uv, max_allowed_uv);
493 return -EINVAL;
494 }
495
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530496 rc = smblib_set_adapter_allowance(chg, allowed_voltage);
Nicholas Troast34db5032016-03-28 12:26:44 -0700497 if (rc < 0) {
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530498 smblib_err(chg, "Couldn't configure adapter allowance rc=%d\n",
499 rc);
Nicholas Troast34db5032016-03-28 12:26:44 -0700500 return rc;
501 }
502
503 return rc;
504}
505
506/********************
507 * HELPER FUNCTIONS *
508 ********************/
Ashay Jaiswal13a1b812017-07-17 14:49:05 +0530509static int smblib_request_dpdm(struct smb_charger *chg, bool enable)
510{
511 int rc = 0;
512
513 /* fetch the DPDM regulator */
514 if (!chg->dpdm_reg && of_get_property(chg->dev->of_node,
515 "dpdm-supply", NULL)) {
516 chg->dpdm_reg = devm_regulator_get(chg->dev, "dpdm");
517 if (IS_ERR(chg->dpdm_reg)) {
518 rc = PTR_ERR(chg->dpdm_reg);
519 smblib_err(chg, "Couldn't get dpdm regulator rc=%d\n",
520 rc);
521 chg->dpdm_reg = NULL;
522 return rc;
523 }
524 }
525
526 if (enable) {
527 if (chg->dpdm_reg && !regulator_is_enabled(chg->dpdm_reg)) {
528 smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n");
529 rc = regulator_enable(chg->dpdm_reg);
530 if (rc < 0)
531 smblib_err(chg,
532 "Couldn't enable dpdm regulator rc=%d\n",
533 rc);
534 }
535 } else {
536 if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) {
537 smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n");
538 rc = regulator_disable(chg->dpdm_reg);
539 if (rc < 0)
540 smblib_err(chg,
541 "Couldn't disable dpdm regulator rc=%d\n",
542 rc);
543 }
544 }
545
546 return rc;
547}
Nicholas Troast34db5032016-03-28 12:26:44 -0700548
Nicholas Troast93fb0f02017-03-01 10:17:13 -0800549static void smblib_rerun_apsd(struct smb_charger *chg)
550{
551 int rc;
552
553 smblib_dbg(chg, PR_MISC, "re-running APSD\n");
554 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
555 rc = smblib_masked_write(chg,
556 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
557 AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
558 if (rc < 0)
559 smblib_err(chg, "Couldn't enable HVDCP auth IRQ rc=%d\n",
560 rc);
561 }
562
563 rc = smblib_masked_write(chg, CMD_APSD_REG,
564 APSD_RERUN_BIT, APSD_RERUN_BIT);
565 if (rc < 0)
566 smblib_err(chg, "Couldn't re-run APSD rc=%d\n", rc);
567}
568
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -0700569static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -0700570{
Abhijeet Dharmapurikareda08222016-11-01 11:35:29 -0700571 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -0700572
Jack Pham9696e252016-05-23 11:15:15 -0700573 /* if PD is active, APSD is disabled so won't have a valid result */
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +0530574 if (chg->pd_active) {
Fenglin Wu80826e02017-04-25 21:45:08 +0800575 chg->real_charger_type = POWER_SUPPLY_TYPE_USB_PD;
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +0530576 } else {
577 /*
578 * Update real charger type only if its not FLOAT
579 * detected as as SDP
580 */
581 if (!(apsd_result->pst == POWER_SUPPLY_TYPE_USB_FLOAT &&
582 chg->real_charger_type == POWER_SUPPLY_TYPE_USB))
Fenglin Wu80826e02017-04-25 21:45:08 +0800583 chg->real_charger_type = apsd_result->pst;
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +0530584 }
Nicholas Troast34db5032016-03-28 12:26:44 -0700585
Nicholas Troast93fb0f02017-03-01 10:17:13 -0800586 smblib_dbg(chg, PR_MISC, "APSD=%s PD=%d\n",
587 apsd_result->name, chg->pd_active);
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -0700588 return apsd_result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700589}
590
Harry Yang5e1a5222016-07-26 15:16:04 -0700591static int smblib_notifier_call(struct notifier_block *nb,
Harry Yang58a9e7a2016-06-23 14:54:43 -0700592 unsigned long ev, void *v)
Harry Yang1d1034c2016-06-15 12:09:42 -0700593{
Harry Yang58a9e7a2016-06-23 14:54:43 -0700594 struct power_supply *psy = v;
Harry Yang5e1a5222016-07-26 15:16:04 -0700595 struct smb_charger *chg = container_of(nb, struct smb_charger, nb);
Harry Yang1d1034c2016-06-15 12:09:42 -0700596
Harry Yang5e1a5222016-07-26 15:16:04 -0700597 if (!strcmp(psy->desc->name, "bms")) {
598 if (!chg->bms_psy)
599 chg->bms_psy = psy;
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530600 if (ev == PSY_EVENT_PROP_CHANGED)
Harry Yang5e1a5222016-07-26 15:16:04 -0700601 schedule_work(&chg->bms_update_work);
602 }
603
Harry Yang166b15d2017-08-28 13:00:40 -0700604 if (!chg->pl.psy && !strcmp(psy->desc->name, "parallel")) {
Harry Yang58a9e7a2016-06-23 14:54:43 -0700605 chg->pl.psy = psy;
Harry Yang166b15d2017-08-28 13:00:40 -0700606 schedule_work(&chg->pl_update_work);
607 }
Harry Yang1d1034c2016-06-15 12:09:42 -0700608
Harry Yang58a9e7a2016-06-23 14:54:43 -0700609 return NOTIFY_OK;
610}
611
Harry Yang5e1a5222016-07-26 15:16:04 -0700612static int smblib_register_notifier(struct smb_charger *chg)
Harry Yang58a9e7a2016-06-23 14:54:43 -0700613{
614 int rc;
615
Harry Yang5e1a5222016-07-26 15:16:04 -0700616 chg->nb.notifier_call = smblib_notifier_call;
617 rc = power_supply_reg_notifier(&chg->nb);
Harry Yang58a9e7a2016-06-23 14:54:43 -0700618 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700619 smblib_err(chg, "Couldn't register psy notifier rc = %d\n", rc);
Harry Yang58a9e7a2016-06-23 14:54:43 -0700620 return rc;
621 }
622
623 return 0;
Harry Yang1d1034c2016-06-15 12:09:42 -0700624}
625
Harry Yangfe913842016-08-10 12:27:28 -0700626int smblib_mapping_soc_from_field_value(struct smb_chg_param *param,
627 int val_u, u8 *val_raw)
628{
629 if (val_u > param->max_u || val_u < param->min_u)
630 return -EINVAL;
631
632 *val_raw = val_u << 1;
633
634 return 0;
635}
636
637int smblib_mapping_cc_delta_to_field_value(struct smb_chg_param *param,
638 u8 val_raw)
639{
640 int val_u = val_raw * param->step_u + param->min_u;
641
642 if (val_u > param->max_u)
643 val_u -= param->max_u * 2;
644
645 return val_u;
646}
647
648int smblib_mapping_cc_delta_from_field_value(struct smb_chg_param *param,
649 int val_u, u8 *val_raw)
650{
651 if (val_u > param->max_u || val_u < param->min_u - param->max_u)
652 return -EINVAL;
653
654 val_u += param->max_u * 2 - param->min_u;
655 val_u %= param->max_u * 2;
656 *val_raw = val_u / param->step_u;
657
658 return 0;
659}
660
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530661static void smblib_uusb_removal(struct smb_charger *chg)
662{
663 int rc;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +0530664 struct smb_irq_data *data;
665 struct storm_watch *wdata;
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530666
Ashay Jaiswalc0361672017-03-21 12:24:16 +0530667 cancel_delayed_work_sync(&chg->pl_enable_work);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +0530668
Ashay Jaiswal13a1b812017-07-17 14:49:05 +0530669 rc = smblib_request_dpdm(chg, false);
670 if (rc < 0)
671 smblib_err(chg, "Couldn't to disable DPDM rc=%d\n", rc);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +0530672
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +0530673 if (chg->wa_flags & BOOST_BACK_WA) {
674 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
675 if (data) {
676 wdata = &data->storm_data;
677 update_storm_count(wdata, WEAK_CHG_STORM_COUNT);
678 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
679 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
680 false, 0);
681 }
682 }
Ashay Jaiswalc0361672017-03-21 12:24:16 +0530683 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
684 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
685
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530686 /* reset both usbin current and voltage votes */
687 vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
688 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
Ashay Jaiswalae23a042017-05-18 15:28:31 +0530689 vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530690
691 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
692
Ashay Jaiswal67ec7072017-02-16 14:14:58 +0530693 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
694 /* re-enable AUTH_IRQ_EN_CFG_BIT */
695 rc = smblib_masked_write(chg,
696 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
697 AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
698 if (rc < 0)
699 smblib_err(chg,
700 "Couldn't enable QC auth setting rc=%d\n", rc);
701 }
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530702
703 /* reconfigure allowed voltage for HVDCP */
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530704 rc = smblib_set_adapter_allowance(chg,
705 USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530706 if (rc < 0)
707 smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
708 rc);
709
710 chg->voltage_min_uv = MICRO_5V;
711 chg->voltage_max_uv = MICRO_5V;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +0530712 chg->usb_icl_delta_ua = 0;
713 chg->pulse_cnt = 0;
Ashay Jaiswal8507aa52017-04-14 09:42:32 +0530714 chg->uusb_apsd_rerun_done = false;
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530715
716 /* clear USB ICL vote for USB_PSY_VOTER */
717 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
718 if (rc < 0)
719 smblib_err(chg, "Couldn't un-vote for USB ICL rc=%d\n", rc);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -0800720
721 /* clear USB ICL vote for DCP_VOTER */
722 rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
723 if (rc < 0)
724 smblib_err(chg,
725 "Couldn't un-vote DCP from USB ICL rc=%d\n", rc);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530726}
727
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530728void smblib_suspend_on_debug_battery(struct smb_charger *chg)
729{
730 int rc;
731 union power_supply_propval val;
732
Ashay Jaiswalda8669b2017-02-10 23:24:23 +0530733 if (!chg->suspend_input_on_debug_batt)
734 return;
735
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530736 rc = power_supply_get_property(chg->bms_psy,
737 POWER_SUPPLY_PROP_DEBUG_BATTERY, &val);
738 if (rc < 0) {
739 smblib_err(chg, "Couldn't get debug battery prop rc=%d\n", rc);
740 return;
741 }
742
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800743 vote(chg->usb_icl_votable, DEBUG_BOARD_VOTER, val.intval, 0);
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530744 vote(chg->dc_suspend_votable, DEBUG_BOARD_VOTER, val.intval, 0);
745 if (val.intval)
746 pr_info("Input suspended: Fake battery\n");
747}
748
Abhijeet Dharmapurikar9dd61292017-01-25 16:40:08 -0800749int smblib_rerun_apsd_if_required(struct smb_charger *chg)
750{
Abhijeet Dharmapurikar9dd61292017-01-25 16:40:08 -0800751 union power_supply_propval val;
752 int rc;
753
754 rc = smblib_get_prop_usb_present(chg, &val);
755 if (rc < 0) {
756 smblib_err(chg, "Couldn't get usb present rc = %d\n", rc);
757 return rc;
758 }
759
760 if (!val.intval)
761 return 0;
762
Ashay Jaiswal13a1b812017-07-17 14:49:05 +0530763 rc = smblib_request_dpdm(chg, true);
764 if (rc < 0)
765 smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
Abhijeet Dharmapurikar025e63a2017-02-24 14:06:22 -0800766
Ashay Jaiswal8507aa52017-04-14 09:42:32 +0530767 chg->uusb_apsd_rerun_done = true;
Abhijeet Dharmapurikar025e63a2017-02-24 14:06:22 -0800768 smblib_rerun_apsd(chg);
769
Abhijeet Dharmapurikar9dd61292017-01-25 16:40:08 -0800770 return 0;
771}
772
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +0530773static int smblib_get_hw_pulse_cnt(struct smb_charger *chg, int *count)
Ashay Jaiswal6d308da2017-02-18 09:59:23 +0530774{
775 int rc;
776 u8 val[2];
777
778 switch (chg->smb_version) {
779 case PMI8998_SUBTYPE:
780 rc = smblib_read(chg, QC_PULSE_COUNT_STATUS_REG, val);
781 if (rc) {
782 pr_err("failed to read QC_PULSE_COUNT_STATUS_REG rc=%d\n",
783 rc);
784 return rc;
785 }
786 *count = val[0] & QC_PULSE_COUNT_MASK;
787 break;
788 case PM660_SUBTYPE:
789 rc = smblib_multibyte_read(chg,
790 QC_PULSE_COUNT_STATUS_1_REG, val, 2);
791 if (rc) {
792 pr_err("failed to read QC_PULSE_COUNT_STATUS_1_REG rc=%d\n",
793 rc);
794 return rc;
795 }
796 *count = (val[1] << 8) | val[0];
797 break;
798 default:
799 smblib_dbg(chg, PR_PARALLEL, "unknown SMB chip %d\n",
800 chg->smb_version);
801 return -EINVAL;
802 }
803
804 return 0;
805}
806
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +0530807static int smblib_get_pulse_cnt(struct smb_charger *chg, int *count)
808{
809 int rc;
810
811 /* Use software based pulse count if HW INOV is disabled */
812 if (get_effective_result(chg->hvdcp_hw_inov_dis_votable) > 0) {
813 *count = chg->pulse_cnt;
814 return 0;
815 }
816
817 /* Use h/w pulse count if autonomous mode is enabled */
818 rc = smblib_get_hw_pulse_cnt(chg, count);
819 if (rc < 0)
820 smblib_err(chg, "failed to read h/w pulse count rc=%d\n", rc);
821
822 return rc;
823}
824
Nicholas Troastbb76a142016-09-23 11:23:23 -0700825#define USBIN_25MA 25000
826#define USBIN_100MA 100000
827#define USBIN_150MA 150000
828#define USBIN_500MA 500000
829#define USBIN_900MA 900000
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800830
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800831static int set_sdp_current(struct smb_charger *chg, int icl_ua)
Nicholas Troast34db5032016-03-28 12:26:44 -0700832{
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800833 int rc;
834 u8 icl_options;
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +0530835 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700836
Nicholas Troastbb76a142016-09-23 11:23:23 -0700837 /* power source is SDP */
838 switch (icl_ua) {
839 case USBIN_100MA:
840 /* USB 2.0 100mA */
841 icl_options = 0;
842 break;
843 case USBIN_150MA:
844 /* USB 3.0 150mA */
845 icl_options = CFG_USB3P0_SEL_BIT;
846 break;
847 case USBIN_500MA:
848 /* USB 2.0 500mA */
849 icl_options = USB51_MODE_BIT;
850 break;
851 case USBIN_900MA:
852 /* USB 3.0 900mA */
853 icl_options = CFG_USB3P0_SEL_BIT | USB51_MODE_BIT;
854 break;
855 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700856 smblib_err(chg, "ICL %duA isn't supported for SDP\n", icl_ua);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800857 return -EINVAL;
Nicholas Troastbb76a142016-09-23 11:23:23 -0700858 }
Nicholas Troast34db5032016-03-28 12:26:44 -0700859
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +0530860 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB &&
861 apsd_result->pst == POWER_SUPPLY_TYPE_USB_FLOAT) {
862 /*
863 * change the float charger configuration to SDP, if this
864 * is the case of SDP being detected as FLOAT
865 */
866 rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
867 FORCE_FLOAT_SDP_CFG_BIT, FORCE_FLOAT_SDP_CFG_BIT);
868 if (rc < 0) {
869 smblib_err(chg, "Couldn't set float ICL options rc=%d\n",
870 rc);
871 return rc;
872 }
873 }
874
Nicholas Troastbb76a142016-09-23 11:23:23 -0700875 rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800876 CFG_USB3P0_SEL_BIT | USB51_MODE_BIT, icl_options);
Nicholas Troast34db5032016-03-28 12:26:44 -0700877 if (rc < 0) {
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800878 smblib_err(chg, "Couldn't set ICL options rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -0700879 return rc;
880 }
881
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800882 return rc;
883}
884
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700885static int get_sdp_current(struct smb_charger *chg, int *icl_ua)
886{
887 int rc;
888 u8 icl_options;
889 bool usb3 = false;
890
891 rc = smblib_read(chg, USBIN_ICL_OPTIONS_REG, &icl_options);
892 if (rc < 0) {
893 smblib_err(chg, "Couldn't get ICL options rc=%d\n", rc);
894 return rc;
895 }
896
897 usb3 = (icl_options & CFG_USB3P0_SEL_BIT);
898
899 if (icl_options & USB51_MODE_BIT)
900 *icl_ua = usb3 ? USBIN_900MA : USBIN_500MA;
901 else
902 *icl_ua = usb3 ? USBIN_150MA : USBIN_100MA;
903
904 return rc;
905}
906
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530907int smblib_set_icl_current(struct smb_charger *chg, int icl_ua)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800908{
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800909 int rc = 0;
910 bool override;
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800911
912 /* suspend and return if 25mA or less is requested */
Harry Yang379484a2017-08-29 10:26:14 -0700913 if (icl_ua <= USBIN_25MA)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800914 return smblib_set_usb_suspend(chg, true);
915
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530916 if (icl_ua == INT_MAX)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800917 goto override_suspend_config;
918
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800919 /* configure current */
Nicholas Troaste1932e42017-04-12 12:38:18 -0700920 if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
Fenglin Wu80826e02017-04-25 21:45:08 +0800921 && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) {
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800922 rc = set_sdp_current(chg, icl_ua);
923 if (rc < 0) {
924 smblib_err(chg, "Couldn't set SDP ICL rc=%d\n", rc);
925 goto enable_icl_changed_interrupt;
926 }
927 } else {
Abhijeet Dharmapurikar949d67e2017-05-25 15:10:56 -0700928 set_sdp_current(chg, 100000);
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -0700929 rc = smblib_set_charge_param(chg, &chg->param.usb_icl, icl_ua);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800930 if (rc < 0) {
931 smblib_err(chg, "Couldn't set HC ICL rc=%d\n", rc);
932 goto enable_icl_changed_interrupt;
933 }
934 }
935
936override_suspend_config:
937 /* determine if override needs to be enforced */
938 override = true;
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530939 if (icl_ua == INT_MAX) {
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800940 /* remove override if no voters - hw defaults is desired */
941 override = false;
Nicholas Troaste1932e42017-04-12 12:38:18 -0700942 } else if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
Fenglin Wu80826e02017-04-25 21:45:08 +0800943 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800944 /* For std cable with type = SDP never override */
945 override = false;
Fenglin Wu80826e02017-04-25 21:45:08 +0800946 else if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_CDP
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -0700947 && icl_ua == 1500000)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800948 /*
949 * For std cable with type = CDP override only if
950 * current is not 1500mA
951 */
952 override = false;
953 }
954
955 /* enforce override */
956 rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
957 USBIN_MODE_CHG_BIT, override ? USBIN_MODE_CHG_BIT : 0);
958
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800959 rc = smblib_icl_override(chg, override);
960 if (rc < 0) {
961 smblib_err(chg, "Couldn't set ICL override rc=%d\n", rc);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800962 goto enable_icl_changed_interrupt;
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800963 }
964
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800965 /* unsuspend after configuring current and override */
966 rc = smblib_set_usb_suspend(chg, false);
967 if (rc < 0) {
968 smblib_err(chg, "Couldn't resume input rc=%d\n", rc);
969 goto enable_icl_changed_interrupt;
970 }
971
972enable_icl_changed_interrupt:
Nicholas Troast34db5032016-03-28 12:26:44 -0700973 return rc;
974}
975
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700976int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua)
977{
978 int rc = 0;
979 u8 load_cfg;
980 bool override;
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700981
Ashay Jaiswal0ce2c7c2017-11-14 12:29:02 +0530982 if (((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT)
983 || (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB))
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700984 && (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)) {
985 rc = get_sdp_current(chg, icl_ua);
986 if (rc < 0) {
987 smblib_err(chg, "Couldn't get SDP ICL rc=%d\n", rc);
988 return rc;
989 }
990 } else {
991 rc = smblib_read(chg, USBIN_LOAD_CFG_REG, &load_cfg);
992 if (rc < 0) {
993 smblib_err(chg, "Couldn't get load cfg rc=%d\n", rc);
994 return rc;
995 }
996 override = load_cfg & ICL_OVERRIDE_AFTER_APSD_BIT;
997 if (!override)
998 return INT_MAX;
999
1000 /* override is set */
1001 rc = smblib_get_charge_param(chg, &chg->param.usb_icl, icl_ua);
1002 if (rc < 0) {
1003 smblib_err(chg, "Couldn't get HC ICL rc=%d\n", rc);
1004 return rc;
1005 }
1006 }
1007
1008 return 0;
1009}
1010
Ashay Jaiswalae1586d2017-03-22 23:18:51 +05301011/*********************
1012 * VOTABLE CALLBACKS *
1013 *********************/
1014
1015static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data,
1016 int suspend, const char *client)
1017{
1018 struct smb_charger *chg = data;
1019
1020 /* resume input if suspend is invalid */
1021 if (suspend < 0)
1022 suspend = 0;
1023
1024 return smblib_set_dc_suspend(chg, (bool)suspend);
1025}
1026
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001027static int smblib_dc_icl_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -07001028 int icl_ua, const char *client)
Nicholas Troast34db5032016-03-28 12:26:44 -07001029{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001030 struct smb_charger *chg = data;
Nicholas Troast34db5032016-03-28 12:26:44 -07001031 int rc = 0;
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001032 bool suspend;
1033
1034 if (icl_ua < 0) {
1035 smblib_dbg(chg, PR_MISC, "No Voter hence suspending\n");
1036 icl_ua = 0;
1037 }
1038
Harry Yang379484a2017-08-29 10:26:14 -07001039 suspend = (icl_ua <= USBIN_25MA);
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001040 if (suspend)
1041 goto suspend;
Nicholas Troast34db5032016-03-28 12:26:44 -07001042
1043 rc = smblib_set_charge_param(chg, &chg->param.dc_icl, icl_ua);
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001044 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001045 smblib_err(chg, "Couldn't set DC input current limit rc=%d\n",
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001046 rc);
1047 return rc;
1048 }
1049
1050suspend:
1051 rc = vote(chg->dc_suspend_votable, USER_VOTER, suspend, 0);
1052 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001053 smblib_err(chg, "Couldn't vote to %s DC rc=%d\n",
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001054 suspend ? "suspend" : "resume", rc);
1055 return rc;
1056 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001057 return rc;
1058}
1059
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07001060static int smblib_pd_disallowed_votable_indirect_callback(
1061 struct votable *votable, void *data, int disallowed, const char *client)
1062{
1063 struct smb_charger *chg = data;
1064 int rc;
1065
1066 rc = vote(chg->pd_allowed_votable, PD_DISALLOWED_INDIRECT_VOTER,
1067 !disallowed, 0);
1068
1069 return rc;
1070}
1071
Harry Yang223c6282016-06-14 15:48:36 -07001072static int smblib_awake_vote_callback(struct votable *votable, void *data,
1073 int awake, const char *client)
1074{
1075 struct smb_charger *chg = data;
1076
1077 if (awake)
1078 pm_stay_awake(chg->dev);
1079 else
1080 pm_relax(chg->dev);
1081
1082 return 0;
1083}
1084
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07001085static int smblib_chg_disable_vote_callback(struct votable *votable, void *data,
1086 int chg_disable, const char *client)
1087{
1088 struct smb_charger *chg = data;
1089 int rc;
1090
1091 rc = smblib_masked_write(chg, CHARGING_ENABLE_CMD_REG,
1092 CHARGING_ENABLE_CMD_BIT,
1093 chg_disable ? 0 : CHARGING_ENABLE_CMD_BIT);
1094 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001095 smblib_err(chg, "Couldn't %s charging rc=%d\n",
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07001096 chg_disable ? "disable" : "enable", rc);
1097 return rc;
1098 }
1099
1100 return 0;
1101}
Harry Yangaba1f5f2016-09-28 10:47:29 -07001102
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301103static int smblib_hvdcp_enable_vote_callback(struct votable *votable,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001104 void *data,
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301105 int hvdcp_enable, const char *client)
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001106{
1107 struct smb_charger *chg = data;
1108 int rc;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301109 u8 val = HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_EN_BIT;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07001110 u8 stat;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301111
1112 /* vote to enable/disable HW autonomous INOV */
1113 vote(chg->hvdcp_hw_inov_dis_votable, client, !hvdcp_enable, 0);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001114
1115 /*
1116 * Disable the autonomous bit and auth bit for disabling hvdcp.
1117 * This ensures only qc 2.0 detection runs but no vbus
1118 * negotiation happens.
1119 */
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301120 if (!hvdcp_enable)
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001121 val = HVDCP_EN_BIT;
1122
1123 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301124 HVDCP_EN_BIT | HVDCP_AUTH_ALG_EN_CFG_BIT,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001125 val);
1126 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001127 smblib_err(chg, "Couldn't %s hvdcp rc=%d\n",
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301128 hvdcp_enable ? "enable" : "disable", rc);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001129 return rc;
1130 }
1131
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07001132 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
1133 if (rc < 0) {
1134 smblib_err(chg, "Couldn't read APSD status rc=%d\n", rc);
1135 return rc;
1136 }
1137
1138 /* re-run APSD if HVDCP was detected */
1139 if (stat & QC_CHARGER_BIT)
1140 smblib_rerun_apsd(chg);
1141
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001142 return 0;
1143}
1144
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301145static int smblib_hvdcp_disable_indirect_vote_callback(struct votable *votable,
1146 void *data, int hvdcp_disable, const char *client)
1147{
1148 struct smb_charger *chg = data;
1149
1150 vote(chg->hvdcp_enable_votable, HVDCP_INDIRECT_VOTER,
1151 !hvdcp_disable, 0);
1152
1153 return 0;
1154}
1155
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07001156static int smblib_apsd_disable_vote_callback(struct votable *votable,
1157 void *data,
1158 int apsd_disable, const char *client)
1159{
1160 struct smb_charger *chg = data;
1161 int rc;
1162
Nicholas Troastec4703c2017-01-30 14:52:33 -08001163 if (apsd_disable) {
Nicholas Troastec4703c2017-01-30 14:52:33 -08001164 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1165 AUTO_SRC_DETECT_BIT,
1166 0);
1167 if (rc < 0) {
1168 smblib_err(chg, "Couldn't disable APSD rc=%d\n", rc);
1169 return rc;
1170 }
1171 } else {
1172 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1173 AUTO_SRC_DETECT_BIT,
1174 AUTO_SRC_DETECT_BIT);
1175 if (rc < 0) {
1176 smblib_err(chg, "Couldn't enable APSD rc=%d\n", rc);
1177 return rc;
1178 }
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07001179 }
1180
1181 return 0;
1182}
Nicholas Troast8995a702016-12-05 10:22:22 -08001183
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301184static int smblib_hvdcp_hw_inov_dis_vote_callback(struct votable *votable,
1185 void *data, int disable, const char *client)
1186{
1187 struct smb_charger *chg = data;
1188 int rc;
1189
1190 if (disable) {
1191 /*
1192 * the pulse count register get zeroed when autonomous mode is
1193 * disabled. Track that in variables before disabling
1194 */
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +05301195 rc = smblib_get_hw_pulse_cnt(chg, &chg->pulse_cnt);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301196 if (rc < 0) {
1197 pr_err("failed to read QC_PULSE_COUNT_STATUS_REG rc=%d\n",
1198 rc);
1199 return rc;
1200 }
1201 }
1202
1203 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1204 HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT,
1205 disable ? 0 : HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT);
1206 if (rc < 0) {
1207 smblib_err(chg, "Couldn't %s hvdcp rc=%d\n",
1208 disable ? "disable" : "enable", rc);
1209 return rc;
1210 }
1211
1212 return rc;
1213}
1214
Harry Yang4bf7d962017-03-13 16:51:43 -07001215static int smblib_usb_irq_enable_vote_callback(struct votable *votable,
1216 void *data, int enable, const char *client)
1217{
1218 struct smb_charger *chg = data;
1219
1220 if (!chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq ||
1221 !chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq)
1222 return 0;
1223
1224 if (enable) {
1225 enable_irq(chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq);
1226 enable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
1227 } else {
1228 disable_irq(chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq);
1229 disable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
1230 }
1231
1232 return 0;
1233}
1234
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07001235static int smblib_typec_irq_disable_vote_callback(struct votable *votable,
1236 void *data, int disable, const char *client)
1237{
1238 struct smb_charger *chg = data;
1239
1240 if (!chg->irq_info[TYPE_C_CHANGE_IRQ].irq)
1241 return 0;
1242
1243 if (disable)
1244 disable_irq_nosync(chg->irq_info[TYPE_C_CHANGE_IRQ].irq);
1245 else
1246 enable_irq(chg->irq_info[TYPE_C_CHANGE_IRQ].irq);
1247
1248 return 0;
1249}
1250
Nicholas Troast8995a702016-12-05 10:22:22 -08001251/*******************
1252 * VCONN REGULATOR *
1253 * *****************/
1254
Nicholas Troastb11015f2017-01-17 17:56:45 -08001255#define MAX_OTG_SS_TRIES 2
Nicholas Troast8995a702016-12-05 10:22:22 -08001256static int _smblib_vconn_regulator_enable(struct regulator_dev *rdev)
1257{
1258 struct smb_charger *chg = rdev_get_drvdata(rdev);
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001259 int rc = 0;
1260 u8 val;
Nicholas Troast8995a702016-12-05 10:22:22 -08001261
1262 /*
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001263 * When enabling VCONN using the command register the CC pin must be
1264 * selected. VCONN should be supplied to the inactive CC pin hence using
1265 * the opposite of the CC_ORIENTATION_BIT.
Nicholas Troast8995a702016-12-05 10:22:22 -08001266 */
Nicholas Troastb11015f2017-01-17 17:56:45 -08001267 smblib_dbg(chg, PR_OTG, "enabling VCONN\n");
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07001268 val = chg->typec_status[3] &
1269 CC_ORIENTATION_BIT ? 0 : VCONN_EN_ORIENTATION_BIT;
Nicholas Troast8995a702016-12-05 10:22:22 -08001270 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1271 VCONN_EN_VALUE_BIT | VCONN_EN_ORIENTATION_BIT,
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07001272 VCONN_EN_VALUE_BIT | val);
Nicholas Troast8995a702016-12-05 10:22:22 -08001273 if (rc < 0) {
1274 smblib_err(chg, "Couldn't enable vconn setting rc=%d\n", rc);
1275 return rc;
1276 }
1277
1278 return rc;
1279}
1280
1281int smblib_vconn_regulator_enable(struct regulator_dev *rdev)
1282{
1283 struct smb_charger *chg = rdev_get_drvdata(rdev);
1284 int rc = 0;
1285
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001286 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001287 if (chg->vconn_en)
1288 goto unlock;
1289
1290 rc = _smblib_vconn_regulator_enable(rdev);
1291 if (rc >= 0)
1292 chg->vconn_en = true;
1293
1294unlock:
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001295 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001296 return rc;
1297}
1298
1299static int _smblib_vconn_regulator_disable(struct regulator_dev *rdev)
1300{
1301 struct smb_charger *chg = rdev_get_drvdata(rdev);
1302 int rc = 0;
1303
Nicholas Troastb11015f2017-01-17 17:56:45 -08001304 smblib_dbg(chg, PR_OTG, "disabling VCONN\n");
Nicholas Troast8995a702016-12-05 10:22:22 -08001305 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1306 VCONN_EN_VALUE_BIT, 0);
1307 if (rc < 0)
1308 smblib_err(chg, "Couldn't disable vconn regulator rc=%d\n", rc);
1309
1310 return rc;
1311}
1312
1313int smblib_vconn_regulator_disable(struct regulator_dev *rdev)
1314{
1315 struct smb_charger *chg = rdev_get_drvdata(rdev);
1316 int rc = 0;
1317
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001318 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001319 if (!chg->vconn_en)
1320 goto unlock;
1321
1322 rc = _smblib_vconn_regulator_disable(rdev);
1323 if (rc >= 0)
1324 chg->vconn_en = false;
1325
1326unlock:
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001327 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001328 return rc;
1329}
1330
1331int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev)
1332{
1333 struct smb_charger *chg = rdev_get_drvdata(rdev);
1334 int ret;
1335
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001336 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001337 ret = chg->vconn_en;
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001338 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001339 return ret;
1340}
1341
Nicholas Troast34db5032016-03-28 12:26:44 -07001342/*****************
1343 * OTG REGULATOR *
1344 *****************/
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301345#define MAX_RETRY 15
1346#define MIN_DELAY_US 2000
1347#define MAX_DELAY_US 9000
Anirudh Ghayaladf20da2017-07-03 10:52:29 +05301348static int otg_current[] = {250000, 500000, 1000000, 1500000};
1349static int smblib_enable_otg_wa(struct smb_charger *chg)
1350{
1351 u8 stat;
1352 int rc, i, retry_count = 0, min_delay = MIN_DELAY_US;
1353
1354 for (i = 0; i < ARRAY_SIZE(otg_current); i++) {
1355 smblib_dbg(chg, PR_OTG, "enabling OTG with %duA\n",
1356 otg_current[i]);
1357 rc = smblib_set_charge_param(chg, &chg->param.otg_cl,
1358 otg_current[i]);
1359 if (rc < 0) {
1360 smblib_err(chg, "Couldn't set otg limit rc=%d\n", rc);
1361 return rc;
1362 }
1363
1364 rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT);
1365 if (rc < 0) {
1366 smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc);
1367 return rc;
1368 }
1369
1370 retry_count = 0;
1371 min_delay = MIN_DELAY_US;
1372 do {
1373 usleep_range(min_delay, min_delay + 100);
1374 rc = smblib_read(chg, OTG_STATUS_REG, &stat);
1375 if (rc < 0) {
1376 smblib_err(chg, "Couldn't read OTG status rc=%d\n",
1377 rc);
1378 goto out;
1379 }
1380
1381 if (stat & BOOST_SOFTSTART_DONE_BIT) {
1382 rc = smblib_set_charge_param(chg,
1383 &chg->param.otg_cl, chg->otg_cl_ua);
1384 if (rc < 0) {
1385 smblib_err(chg, "Couldn't set otg limit rc=%d\n",
1386 rc);
1387 goto out;
1388 }
1389 break;
1390 }
1391 /* increase the delay for following iterations */
1392 if (retry_count > 5)
1393 min_delay = MAX_DELAY_US;
1394
1395 } while (retry_count++ < MAX_RETRY);
1396
1397 if (retry_count >= MAX_RETRY) {
1398 smblib_dbg(chg, PR_OTG, "OTG enable failed with %duA\n",
1399 otg_current[i]);
1400 rc = smblib_write(chg, CMD_OTG_REG, 0);
1401 if (rc < 0) {
1402 smblib_err(chg, "disable OTG rc=%d\n", rc);
1403 goto out;
1404 }
1405 } else {
1406 smblib_dbg(chg, PR_OTG, "OTG enabled\n");
1407 return 0;
1408 }
1409 }
1410
1411 if (i == ARRAY_SIZE(otg_current)) {
1412 rc = -EINVAL;
1413 goto out;
1414 }
1415
1416 return 0;
1417out:
1418 smblib_write(chg, CMD_OTG_REG, 0);
1419 return rc;
1420}
1421
Nicholas Troast8995a702016-12-05 10:22:22 -08001422static int _smblib_vbus_regulator_enable(struct regulator_dev *rdev)
Nicholas Troast34db5032016-03-28 12:26:44 -07001423{
1424 struct smb_charger *chg = rdev_get_drvdata(rdev);
Anirudh Ghayaladf20da2017-07-03 10:52:29 +05301425 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001426
Nicholas Troastb11015f2017-01-17 17:56:45 -08001427 smblib_dbg(chg, PR_OTG, "halt 1 in 8 mode\n");
Harry Yang360bd532016-09-26 11:03:22 -07001428 rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
1429 ENG_BUCKBOOST_HALT1_8_MODE_BIT,
1430 ENG_BUCKBOOST_HALT1_8_MODE_BIT);
1431 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001432 smblib_err(chg, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n",
Harry Yang360bd532016-09-26 11:03:22 -07001433 rc);
1434 return rc;
1435 }
1436
Nicholas Troastb11015f2017-01-17 17:56:45 -08001437 smblib_dbg(chg, PR_OTG, "enabling OTG\n");
Harry Yang360bd532016-09-26 11:03:22 -07001438
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301439 if (chg->wa_flags & OTG_WA) {
Anirudh Ghayaladf20da2017-07-03 10:52:29 +05301440 rc = smblib_enable_otg_wa(chg);
1441 if (rc < 0)
1442 smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc);
1443 } else {
1444 rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT);
1445 if (rc < 0)
1446 smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc);
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301447 }
1448
Nicholas Troast34db5032016-03-28 12:26:44 -07001449 return rc;
1450}
1451
Nicholas Troast8995a702016-12-05 10:22:22 -08001452int smblib_vbus_regulator_enable(struct regulator_dev *rdev)
Nicholas Troast34db5032016-03-28 12:26:44 -07001453{
1454 struct smb_charger *chg = rdev_get_drvdata(rdev);
1455 int rc = 0;
1456
Nicholas Troastb11015f2017-01-17 17:56:45 -08001457 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001458 if (chg->otg_en)
1459 goto unlock;
1460
Harry Yanga2fb0e32017-03-22 22:45:25 -07001461 if (!chg->usb_icl_votable) {
1462 chg->usb_icl_votable = find_votable("USB_ICL");
1463
1464 if (!chg->usb_icl_votable)
1465 return -EINVAL;
1466 }
1467 vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, true, 0);
1468
Nicholas Troast8995a702016-12-05 10:22:22 -08001469 rc = _smblib_vbus_regulator_enable(rdev);
1470 if (rc >= 0)
1471 chg->otg_en = true;
1472
1473unlock:
Nicholas Troastb11015f2017-01-17 17:56:45 -08001474 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001475 return rc;
1476}
1477
1478static int _smblib_vbus_regulator_disable(struct regulator_dev *rdev)
1479{
1480 struct smb_charger *chg = rdev_get_drvdata(rdev);
1481 int rc;
Nicholas Troast8995a702016-12-05 10:22:22 -08001482
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301483 if (chg->wa_flags & OTG_WA) {
1484 /* set OTG current limit to minimum value */
1485 rc = smblib_set_charge_param(chg, &chg->param.otg_cl,
1486 chg->param.otg_cl.min_u);
1487 if (rc < 0) {
1488 smblib_err(chg,
1489 "Couldn't set otg current limit rc=%d\n", rc);
1490 return rc;
1491 }
1492 }
1493
Nicholas Troastb11015f2017-01-17 17:56:45 -08001494 smblib_dbg(chg, PR_OTG, "disabling OTG\n");
Harry Yang360bd532016-09-26 11:03:22 -07001495 rc = smblib_write(chg, CMD_OTG_REG, 0);
1496 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001497 smblib_err(chg, "Couldn't disable OTG regulator rc=%d\n", rc);
Harry Yang360bd532016-09-26 11:03:22 -07001498 return rc;
1499 }
1500
Nicholas Troastb11015f2017-01-17 17:56:45 -08001501 smblib_dbg(chg, PR_OTG, "start 1 in 8 mode\n");
Harry Yang360bd532016-09-26 11:03:22 -07001502 rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
1503 ENG_BUCKBOOST_HALT1_8_MODE_BIT, 0);
1504 if (rc < 0) {
Nicholas Troast8995a702016-12-05 10:22:22 -08001505 smblib_err(chg, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n", rc);
Harry Yang360bd532016-09-26 11:03:22 -07001506 return rc;
1507 }
1508
Nicholas Troast8995a702016-12-05 10:22:22 -08001509 return 0;
1510}
Nicholas Troast34db5032016-03-28 12:26:44 -07001511
Nicholas Troast8995a702016-12-05 10:22:22 -08001512int smblib_vbus_regulator_disable(struct regulator_dev *rdev)
1513{
1514 struct smb_charger *chg = rdev_get_drvdata(rdev);
1515 int rc = 0;
1516
Nicholas Troastb11015f2017-01-17 17:56:45 -08001517 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001518 if (!chg->otg_en)
1519 goto unlock;
1520
1521 rc = _smblib_vbus_regulator_disable(rdev);
1522 if (rc >= 0)
1523 chg->otg_en = false;
1524
Harry Yanga2fb0e32017-03-22 22:45:25 -07001525 if (chg->usb_icl_votable)
1526 vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0);
Nicholas Troast8995a702016-12-05 10:22:22 -08001527unlock:
Nicholas Troastb11015f2017-01-17 17:56:45 -08001528 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07001529 return rc;
1530}
1531
1532int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev)
1533{
1534 struct smb_charger *chg = rdev_get_drvdata(rdev);
Nicholas Troast8995a702016-12-05 10:22:22 -08001535 int ret;
Nicholas Troast34db5032016-03-28 12:26:44 -07001536
Nicholas Troastb11015f2017-01-17 17:56:45 -08001537 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001538 ret = chg->otg_en;
Nicholas Troastb11015f2017-01-17 17:56:45 -08001539 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001540 return ret;
Nicholas Troast34db5032016-03-28 12:26:44 -07001541}
1542
1543/********************
1544 * BATT PSY GETTERS *
1545 ********************/
1546
1547int smblib_get_prop_input_suspend(struct smb_charger *chg,
1548 union power_supply_propval *val)
1549{
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08001550 val->intval
1551 = (get_client_vote(chg->usb_icl_votable, USER_VOTER) == 0)
1552 && get_client_vote(chg->dc_suspend_votable, USER_VOTER);
Nicholas Troast34db5032016-03-28 12:26:44 -07001553 return 0;
1554}
1555
1556int smblib_get_prop_batt_present(struct smb_charger *chg,
1557 union power_supply_propval *val)
1558{
1559 int rc;
1560 u8 stat;
1561
1562 rc = smblib_read(chg, BATIF_BASE + INT_RT_STS_OFFSET, &stat);
1563 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001564 smblib_err(chg, "Couldn't read BATIF_INT_RT_STS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07001565 return rc;
1566 }
1567
1568 val->intval = !(stat & (BAT_THERM_OR_ID_MISSING_RT_STS_BIT
1569 | BAT_TERMINAL_MISSING_RT_STS_BIT));
1570
1571 return rc;
1572}
1573
1574int smblib_get_prop_batt_capacity(struct smb_charger *chg,
1575 union power_supply_propval *val)
1576{
Harry Yang5e1a5222016-07-26 15:16:04 -07001577 int rc = -EINVAL;
1578
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07001579 if (chg->fake_capacity >= 0) {
1580 val->intval = chg->fake_capacity;
1581 return 0;
1582 }
1583
Harry Yang5e1a5222016-07-26 15:16:04 -07001584 if (chg->bms_psy)
1585 rc = power_supply_get_property(chg->bms_psy,
1586 POWER_SUPPLY_PROP_CAPACITY, val);
1587 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001588}
1589
1590int smblib_get_prop_batt_status(struct smb_charger *chg,
1591 union power_supply_propval *val)
1592{
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001593 union power_supply_propval pval = {0, };
Abhijeet Dharmapurikard97b2bf2017-07-06 17:03:00 -07001594 bool usb_online, dc_online, qnovo_en;
1595 u8 stat, pt_en_cmd;
Nicholas Troast8cb77552016-09-23 11:50:18 -07001596 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001597
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001598 rc = smblib_get_prop_usb_online(chg, &pval);
1599 if (rc < 0) {
1600 smblib_err(chg, "Couldn't get usb online property rc=%d\n",
1601 rc);
1602 return rc;
1603 }
1604 usb_online = (bool)pval.intval;
1605
1606 rc = smblib_get_prop_dc_online(chg, &pval);
1607 if (rc < 0) {
1608 smblib_err(chg, "Couldn't get dc online property rc=%d\n",
1609 rc);
1610 return rc;
1611 }
1612 dc_online = (bool)pval.intval;
1613
Nicholas Troast34db5032016-03-28 12:26:44 -07001614 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1615 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001616 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001617 rc);
1618 return rc;
1619 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001620 stat = stat & BATTERY_CHARGER_STATUS_MASK;
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001621
1622 if (!usb_online && !dc_online) {
1623 switch (stat) {
1624 case TERMINATE_CHARGE:
1625 case INHIBIT_CHARGE:
1626 val->intval = POWER_SUPPLY_STATUS_FULL;
1627 break;
1628 default:
1629 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
1630 break;
1631 }
1632 return rc;
1633 }
1634
Nicholas Troast8cb77552016-09-23 11:50:18 -07001635 switch (stat) {
1636 case TRICKLE_CHARGE:
1637 case PRE_CHARGE:
1638 case FAST_CHARGE:
1639 case FULLON_CHARGE:
1640 case TAPER_CHARGE:
Nicholas Troast34db5032016-03-28 12:26:44 -07001641 val->intval = POWER_SUPPLY_STATUS_CHARGING;
Nicholas Troast8cb77552016-09-23 11:50:18 -07001642 break;
1643 case TERMINATE_CHARGE:
1644 case INHIBIT_CHARGE:
1645 val->intval = POWER_SUPPLY_STATUS_FULL;
1646 break;
1647 case DISABLE_CHARGE:
1648 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
1649 break;
1650 default:
1651 val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
1652 break;
1653 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001654
Harry Yang7ecc1a12017-04-06 12:24:56 -07001655 if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
1656 return 0;
1657
Harry Yang589dd422017-07-28 18:41:42 -07001658 if (!usb_online && dc_online
1659 && chg->fake_batt_status == POWER_SUPPLY_STATUS_FULL) {
1660 val->intval = POWER_SUPPLY_STATUS_FULL;
1661 return 0;
1662 }
1663
Harry Yangc3c28d12017-04-17 16:41:19 -07001664 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_7_REG, &stat);
Harry Yang7ecc1a12017-04-06 12:24:56 -07001665 if (rc < 0) {
1666 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
1667 rc);
1668 return rc;
Abhijeet Dharmapurikard97b2bf2017-07-06 17:03:00 -07001669 }
Harry Yang7ecc1a12017-04-06 12:24:56 -07001670
Harry Yangc3c28d12017-04-17 16:41:19 -07001671 stat &= ENABLE_TRICKLE_BIT | ENABLE_PRE_CHARGING_BIT |
1672 ENABLE_FAST_CHARGING_BIT | ENABLE_FULLON_MODE_BIT;
Abhijeet Dharmapurikard97b2bf2017-07-06 17:03:00 -07001673
1674 rc = smblib_read(chg, QNOVO_PT_ENABLE_CMD_REG, &pt_en_cmd);
1675 if (rc < 0) {
1676 smblib_err(chg, "Couldn't read QNOVO_PT_ENABLE_CMD_REG rc=%d\n",
1677 rc);
1678 return rc;
1679 }
1680
1681 qnovo_en = (bool)(pt_en_cmd & QNOVO_PT_ENABLE_CMD_BIT);
1682
1683 /* ignore stat7 when qnovo is enabled */
1684 if (!qnovo_en && !stat)
Harry Yang7ecc1a12017-04-06 12:24:56 -07001685 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
1686
Nicholas Troast8cb77552016-09-23 11:50:18 -07001687 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07001688}
1689
1690int smblib_get_prop_batt_charge_type(struct smb_charger *chg,
1691 union power_supply_propval *val)
1692{
1693 int rc;
1694 u8 stat;
1695
1696 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1697 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001698 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001699 rc);
1700 return rc;
1701 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001702
1703 switch (stat & BATTERY_CHARGER_STATUS_MASK) {
1704 case TRICKLE_CHARGE:
1705 case PRE_CHARGE:
1706 val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1707 break;
1708 case FAST_CHARGE:
1709 case FULLON_CHARGE:
1710 val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
1711 break;
1712 case TAPER_CHARGE:
1713 val->intval = POWER_SUPPLY_CHARGE_TYPE_TAPER;
1714 break;
1715 default:
1716 val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
1717 }
1718
1719 return rc;
1720}
1721
1722int smblib_get_prop_batt_health(struct smb_charger *chg,
1723 union power_supply_propval *val)
1724{
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001725 union power_supply_propval pval;
Nicholas Troast34db5032016-03-28 12:26:44 -07001726 int rc;
Abhijeet Dharmapurikar33d18462017-05-15 13:38:53 -07001727 int effective_fv_uv;
Nicholas Troast34db5032016-03-28 12:26:44 -07001728 u8 stat;
1729
1730 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat);
1731 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001732 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001733 rc);
1734 return rc;
1735 }
1736 smblib_dbg(chg, PR_REGISTER, "BATTERY_CHARGER_STATUS_2 = 0x%02x\n",
1737 stat);
1738
1739 if (stat & CHARGER_ERROR_STATUS_BAT_OV_BIT) {
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001740 rc = smblib_get_prop_batt_voltage_now(chg, &pval);
1741 if (!rc) {
1742 /*
1743 * If Vbatt is within 40mV above Vfloat, then don't
1744 * treat it as overvoltage.
1745 */
Abhijeet Dharmapurikar33d18462017-05-15 13:38:53 -07001746 effective_fv_uv = get_effective_result(chg->fv_votable);
1747 if (pval.intval >= effective_fv_uv + 40000) {
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001748 val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
Abhijeet Dharmapurikar33d18462017-05-15 13:38:53 -07001749 smblib_err(chg, "battery over-voltage vbat_fg = %duV, fv = %duV\n",
1750 pval.intval, effective_fv_uv);
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001751 goto done;
1752 }
1753 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001754 }
1755
Harry Yang668fc5e2016-07-12 16:51:47 -07001756 if (stat & BAT_TEMP_STATUS_TOO_COLD_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001757 val->intval = POWER_SUPPLY_HEALTH_COLD;
Harry Yang668fc5e2016-07-12 16:51:47 -07001758 else if (stat & BAT_TEMP_STATUS_TOO_HOT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001759 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
Harry Yang668fc5e2016-07-12 16:51:47 -07001760 else if (stat & BAT_TEMP_STATUS_COLD_SOFT_LIMIT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001761 val->intval = POWER_SUPPLY_HEALTH_COOL;
Harry Yang668fc5e2016-07-12 16:51:47 -07001762 else if (stat & BAT_TEMP_STATUS_HOT_SOFT_LIMIT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001763 val->intval = POWER_SUPPLY_HEALTH_WARM;
Harry Yang668fc5e2016-07-12 16:51:47 -07001764 else
Nicholas Troast34db5032016-03-28 12:26:44 -07001765 val->intval = POWER_SUPPLY_HEALTH_GOOD;
Nicholas Troast34db5032016-03-28 12:26:44 -07001766
1767done:
1768 return rc;
1769}
1770
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001771int smblib_get_prop_system_temp_level(struct smb_charger *chg,
1772 union power_supply_propval *val)
1773{
1774 val->intval = chg->system_temp_level;
1775 return 0;
1776}
1777
Abhijeet Dharmapurikaracf32002017-05-11 11:54:17 -07001778int smblib_get_prop_system_temp_level_max(struct smb_charger *chg,
1779 union power_supply_propval *val)
1780{
1781 val->intval = chg->thermal_levels;
1782 return 0;
1783}
1784
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001785int smblib_get_prop_input_current_limited(struct smb_charger *chg,
1786 union power_supply_propval *val)
1787{
1788 u8 stat;
1789 int rc;
1790
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07001791 if (chg->fake_input_current_limited >= 0) {
1792 val->intval = chg->fake_input_current_limited;
1793 return 0;
1794 }
1795
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001796 rc = smblib_read(chg, AICL_STATUS_REG, &stat);
1797 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001798 smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n", rc);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001799 return rc;
1800 }
1801 val->intval = (stat & SOFT_ILIMIT_BIT) || chg->is_hdc;
1802 return 0;
1803}
1804
Nicholas Troast66b21d72016-09-20 15:33:20 -07001805int smblib_get_prop_batt_voltage_now(struct smb_charger *chg,
1806 union power_supply_propval *val)
1807{
1808 int rc;
1809
1810 if (!chg->bms_psy)
1811 return -EINVAL;
1812
1813 rc = power_supply_get_property(chg->bms_psy,
1814 POWER_SUPPLY_PROP_VOLTAGE_NOW, val);
1815 return rc;
1816}
1817
1818int smblib_get_prop_batt_current_now(struct smb_charger *chg,
1819 union power_supply_propval *val)
1820{
1821 int rc;
1822
1823 if (!chg->bms_psy)
1824 return -EINVAL;
1825
1826 rc = power_supply_get_property(chg->bms_psy,
1827 POWER_SUPPLY_PROP_CURRENT_NOW, val);
1828 return rc;
1829}
1830
1831int smblib_get_prop_batt_temp(struct smb_charger *chg,
1832 union power_supply_propval *val)
1833{
1834 int rc;
1835
1836 if (!chg->bms_psy)
1837 return -EINVAL;
1838
1839 rc = power_supply_get_property(chg->bms_psy,
1840 POWER_SUPPLY_PROP_TEMP, val);
1841 return rc;
1842}
1843
Subbaraman Narayanamurthyb491d022016-10-10 20:22:48 -07001844int smblib_get_prop_batt_charge_done(struct smb_charger *chg,
1845 union power_supply_propval *val)
1846{
1847 int rc;
1848 u8 stat;
1849
1850 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1851 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001852 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Subbaraman Narayanamurthyb491d022016-10-10 20:22:48 -07001853 rc);
1854 return rc;
1855 }
1856
1857 stat = stat & BATTERY_CHARGER_STATUS_MASK;
1858 val->intval = (stat == TERMINATE_CHARGE);
1859 return 0;
1860}
1861
Harry Yang40192cb2017-02-25 23:25:17 -08001862int smblib_get_prop_charge_qnovo_enable(struct smb_charger *chg,
1863 union power_supply_propval *val)
1864{
1865 int rc;
1866 u8 stat;
1867
1868 rc = smblib_read(chg, QNOVO_PT_ENABLE_CMD_REG, &stat);
1869 if (rc < 0) {
1870 smblib_err(chg, "Couldn't read QNOVO_PT_ENABLE_CMD rc=%d\n",
1871 rc);
1872 return rc;
1873 }
1874
1875 val->intval = (bool)(stat & QNOVO_PT_ENABLE_CMD_BIT);
1876 return 0;
1877}
1878
Nicholas Troast4fe68d02017-07-26 14:17:34 -07001879int smblib_get_prop_batt_charge_counter(struct smb_charger *chg,
1880 union power_supply_propval *val)
1881{
1882 int rc;
1883
1884 if (!chg->bms_psy)
1885 return -EINVAL;
1886
1887 rc = power_supply_get_property(chg->bms_psy,
1888 POWER_SUPPLY_PROP_CHARGE_COUNTER, val);
1889 return rc;
1890}
1891
Nicholas Troast34db5032016-03-28 12:26:44 -07001892/***********************
1893 * BATTERY PSY SETTERS *
1894 ***********************/
1895
1896int smblib_set_prop_input_suspend(struct smb_charger *chg,
1897 const union power_supply_propval *val)
1898{
1899 int rc;
1900
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08001901 /* vote 0mA when suspended */
1902 rc = vote(chg->usb_icl_votable, USER_VOTER, (bool)val->intval, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07001903 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001904 smblib_err(chg, "Couldn't vote to %s USB rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001905 (bool)val->intval ? "suspend" : "resume", rc);
1906 return rc;
1907 }
1908
1909 rc = vote(chg->dc_suspend_votable, USER_VOTER, (bool)val->intval, 0);
1910 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001911 smblib_err(chg, "Couldn't vote to %s DC rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001912 (bool)val->intval ? "suspend" : "resume", rc);
1913 return rc;
1914 }
1915
Nicholas Troast61ff40f2016-07-08 10:59:22 -07001916 power_supply_changed(chg->batt_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07001917 return rc;
1918}
1919
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07001920int smblib_set_prop_batt_capacity(struct smb_charger *chg,
1921 const union power_supply_propval *val)
1922{
1923 chg->fake_capacity = val->intval;
1924
1925 power_supply_changed(chg->batt_psy);
1926
1927 return 0;
1928}
1929
Harry Yang589dd422017-07-28 18:41:42 -07001930int smblib_set_prop_batt_status(struct smb_charger *chg,
1931 const union power_supply_propval *val)
1932{
1933 /* Faking battery full */
1934 if (val->intval == POWER_SUPPLY_STATUS_FULL)
1935 chg->fake_batt_status = val->intval;
1936 else
1937 chg->fake_batt_status = -EINVAL;
1938
1939 power_supply_changed(chg->batt_psy);
1940
1941 return 0;
1942}
1943
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001944int smblib_set_prop_system_temp_level(struct smb_charger *chg,
1945 const union power_supply_propval *val)
1946{
1947 if (val->intval < 0)
1948 return -EINVAL;
1949
1950 if (chg->thermal_levels <= 0)
1951 return -EINVAL;
1952
1953 if (val->intval > chg->thermal_levels)
1954 return -EINVAL;
1955
1956 chg->system_temp_level = val->intval;
Ashay Jaiswal147a6c32017-03-28 17:19:47 +05301957 /* disable parallel charge in case of system temp level */
1958 vote(chg->pl_disable_votable, THERMAL_DAEMON_VOTER,
1959 chg->system_temp_level ? true : false, 0);
1960
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001961 if (chg->system_temp_level == chg->thermal_levels)
Harry Yangaba1f5f2016-09-28 10:47:29 -07001962 return vote(chg->chg_disable_votable,
1963 THERMAL_DAEMON_VOTER, true, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001964
Harry Yangaba1f5f2016-09-28 10:47:29 -07001965 vote(chg->chg_disable_votable, THERMAL_DAEMON_VOTER, false, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001966 if (chg->system_temp_level == 0)
Harry Yangaba1f5f2016-09-28 10:47:29 -07001967 return vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, false, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001968
Harry Yangaba1f5f2016-09-28 10:47:29 -07001969 vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, true,
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001970 chg->thermal_mitigation[chg->system_temp_level]);
1971 return 0;
1972}
1973
Harry Yang40192cb2017-02-25 23:25:17 -08001974int smblib_set_prop_charge_qnovo_enable(struct smb_charger *chg,
1975 const union power_supply_propval *val)
1976{
1977 int rc = 0;
1978
1979 rc = smblib_masked_write(chg, QNOVO_PT_ENABLE_CMD_REG,
1980 QNOVO_PT_ENABLE_CMD_BIT,
1981 val->intval ? QNOVO_PT_ENABLE_CMD_BIT : 0);
1982 if (rc < 0) {
1983 dev_err(chg->dev, "Couldn't enable qnovo rc=%d\n", rc);
1984 return rc;
1985 }
1986
1987 return rc;
1988}
1989
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07001990int smblib_set_prop_input_current_limited(struct smb_charger *chg,
1991 const union power_supply_propval *val)
1992{
1993 chg->fake_input_current_limited = val->intval;
1994 return 0;
1995}
1996
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301997int smblib_rerun_aicl(struct smb_charger *chg)
1998{
Nicholas Troast20ae1912017-02-15 10:15:32 -08001999 int rc, settled_icl_ua;
2000 u8 stat;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302001
Nicholas Troast20ae1912017-02-15 10:15:32 -08002002 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
2003 if (rc < 0) {
2004 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
2005 rc);
2006 return rc;
2007 }
2008
2009 /* USB is suspended so skip re-running AICL */
2010 if (stat & USBIN_SUSPEND_STS_BIT)
2011 return rc;
2012
2013 smblib_dbg(chg, PR_MISC, "re-running AICL\n");
Ashay Jaiswal59a14122017-05-16 13:38:52 +05302014 rc = smblib_get_charge_param(chg, &chg->param.icl_stat,
2015 &settled_icl_ua);
2016 if (rc < 0) {
2017 smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
2018 return rc;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302019 }
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302020
Ashay Jaiswal59a14122017-05-16 13:38:52 +05302021 vote(chg->usb_icl_votable, AICL_RERUN_VOTER, true,
2022 max(settled_icl_ua - chg->param.usb_icl.step_u,
2023 chg->param.usb_icl.step_u));
2024 vote(chg->usb_icl_votable, AICL_RERUN_VOTER, false, 0);
2025
Nicholas Troast20ae1912017-02-15 10:15:32 -08002026 return 0;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302027}
2028
2029static int smblib_dp_pulse(struct smb_charger *chg)
2030{
2031 int rc;
2032
2033 /* QC 3.0 increment */
2034 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, SINGLE_INCREMENT_BIT,
2035 SINGLE_INCREMENT_BIT);
2036 if (rc < 0)
2037 smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
2038 rc);
2039
2040 return rc;
2041}
2042
2043static int smblib_dm_pulse(struct smb_charger *chg)
2044{
2045 int rc;
2046
2047 /* QC 3.0 decrement */
2048 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, SINGLE_DECREMENT_BIT,
2049 SINGLE_DECREMENT_BIT);
2050 if (rc < 0)
2051 smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
2052 rc);
2053
2054 return rc;
2055}
2056
Ashay Jaiswalcf243372017-10-31 14:33:27 +05302057static int smblib_force_vbus_voltage(struct smb_charger *chg, u8 val)
2058{
2059 int rc;
2060
2061 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, val, val);
2062 if (rc < 0)
2063 smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
2064 rc);
2065
2066 return rc;
2067}
2068
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302069int smblib_dp_dm(struct smb_charger *chg, int val)
2070{
2071 int target_icl_ua, rc = 0;
Ashay Jaiswalae23a042017-05-18 15:28:31 +05302072 union power_supply_propval pval;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302073
2074 switch (val) {
2075 case POWER_SUPPLY_DP_DM_DP_PULSE:
2076 rc = smblib_dp_pulse(chg);
2077 if (!rc)
2078 chg->pulse_cnt++;
2079 smblib_dbg(chg, PR_PARALLEL, "DP_DM_DP_PULSE rc=%d cnt=%d\n",
2080 rc, chg->pulse_cnt);
2081 break;
2082 case POWER_SUPPLY_DP_DM_DM_PULSE:
2083 rc = smblib_dm_pulse(chg);
2084 if (!rc && chg->pulse_cnt)
2085 chg->pulse_cnt--;
2086 smblib_dbg(chg, PR_PARALLEL, "DP_DM_DM_PULSE rc=%d cnt=%d\n",
2087 rc, chg->pulse_cnt);
2088 break;
2089 case POWER_SUPPLY_DP_DM_ICL_DOWN:
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302090 target_icl_ua = get_effective_result(chg->usb_icl_votable);
Ashay Jaiswalae23a042017-05-18 15:28:31 +05302091 if (target_icl_ua < 0) {
2092 /* no client vote, get the ICL from charger */
2093 rc = power_supply_get_property(chg->usb_psy,
2094 POWER_SUPPLY_PROP_HW_CURRENT_MAX,
2095 &pval);
2096 if (rc < 0) {
2097 smblib_err(chg,
2098 "Couldn't get max current rc=%d\n",
2099 rc);
2100 return rc;
2101 }
2102 target_icl_ua = pval.intval;
2103 }
2104
2105 /*
2106 * Check if any other voter voted on USB_ICL in case of
2107 * voter other than SW_QC3_VOTER reset and restart reduction
2108 * again.
2109 */
2110 if (target_icl_ua != get_client_vote(chg->usb_icl_votable,
2111 SW_QC3_VOTER))
2112 chg->usb_icl_delta_ua = 0;
2113
2114 chg->usb_icl_delta_ua += 100000;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302115 vote(chg->usb_icl_votable, SW_QC3_VOTER, true,
Ashay Jaiswalae23a042017-05-18 15:28:31 +05302116 target_icl_ua - 100000);
2117 smblib_dbg(chg, PR_PARALLEL, "ICL DOWN ICL=%d reduction=%d\n",
2118 target_icl_ua, chg->usb_icl_delta_ua);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302119 break;
Ashay Jaiswalcf243372017-10-31 14:33:27 +05302120 case POWER_SUPPLY_DP_DM_FORCE_5V:
2121 rc = smblib_force_vbus_voltage(chg, FORCE_5V_BIT);
2122 if (rc < 0)
2123 pr_err("Failed to force 5V\n");
2124 break;
2125 case POWER_SUPPLY_DP_DM_FORCE_9V:
2126 rc = smblib_force_vbus_voltage(chg, FORCE_9V_BIT);
2127 if (rc < 0)
2128 pr_err("Failed to force 9V\n");
2129 break;
2130 case POWER_SUPPLY_DP_DM_FORCE_12V:
2131 rc = smblib_force_vbus_voltage(chg, FORCE_12V_BIT);
2132 if (rc < 0)
2133 pr_err("Failed to force 12V\n");
2134 break;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302135 case POWER_SUPPLY_DP_DM_ICL_UP:
2136 default:
2137 break;
2138 }
2139
2140 return rc;
2141}
2142
Abhijeet Dharmapurikar3a580042017-07-24 09:43:00 -07002143int smblib_disable_hw_jeita(struct smb_charger *chg, bool disable)
2144{
2145 int rc;
2146 u8 mask;
2147
2148 /*
2149 * Disable h/w base JEITA compensation if s/w JEITA is enabled
2150 */
2151 mask = JEITA_EN_COLD_SL_FCV_BIT
2152 | JEITA_EN_HOT_SL_FCV_BIT
2153 | JEITA_EN_HOT_SL_CCC_BIT
2154 | JEITA_EN_COLD_SL_CCC_BIT,
2155 rc = smblib_masked_write(chg, JEITA_EN_CFG_REG, mask,
2156 disable ? 0 : mask);
2157 if (rc < 0) {
2158 dev_err(chg->dev,
2159 "Couldn't configure s/w jeita rc=%d\n",
2160 rc);
2161 return rc;
2162 }
2163 return 0;
2164}
2165
Nicholas Troast34db5032016-03-28 12:26:44 -07002166/*******************
Harry Yangf3023592016-07-20 14:56:41 -07002167 * DC PSY GETTERS *
2168 *******************/
2169
2170int smblib_get_prop_dc_present(struct smb_charger *chg,
2171 union power_supply_propval *val)
2172{
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002173 int rc;
Harry Yangf3023592016-07-20 14:56:41 -07002174 u8 stat;
2175
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002176 rc = smblib_read(chg, DCIN_BASE + INT_RT_STS_OFFSET, &stat);
Harry Yangf3023592016-07-20 14:56:41 -07002177 if (rc < 0) {
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002178 smblib_err(chg, "Couldn't read DCIN_RT_STS rc=%d\n", rc);
Harry Yangf3023592016-07-20 14:56:41 -07002179 return rc;
2180 }
Harry Yangf3023592016-07-20 14:56:41 -07002181
2182 val->intval = (bool)(stat & DCIN_PLUGIN_RT_STS_BIT);
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002183 return 0;
Harry Yangf3023592016-07-20 14:56:41 -07002184}
2185
2186int smblib_get_prop_dc_online(struct smb_charger *chg,
2187 union power_supply_propval *val)
2188{
2189 int rc = 0;
2190 u8 stat;
2191
2192 if (get_client_vote(chg->dc_suspend_votable, USER_VOTER)) {
2193 val->intval = false;
2194 return rc;
2195 }
2196
2197 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
2198 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002199 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
Harry Yangf3023592016-07-20 14:56:41 -07002200 rc);
2201 return rc;
2202 }
2203 smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
2204 stat);
2205
2206 val->intval = (stat & USE_DCIN_BIT) &&
Vic Wei7ade2842016-12-14 18:47:49 -08002207 (stat & VALID_INPUT_POWER_SOURCE_STS_BIT);
Harry Yangf3023592016-07-20 14:56:41 -07002208
2209 return rc;
2210}
2211
2212int smblib_get_prop_dc_current_max(struct smb_charger *chg,
2213 union power_supply_propval *val)
2214{
2215 val->intval = get_effective_result_locked(chg->dc_icl_votable);
2216 return 0;
2217}
2218
2219/*******************
Harry Yangd89ff1f2016-12-05 14:59:11 -08002220 * DC PSY SETTERS *
Harry Yangf3023592016-07-20 14:56:41 -07002221 * *****************/
2222
2223int smblib_set_prop_dc_current_max(struct smb_charger *chg,
2224 const union power_supply_propval *val)
2225{
2226 int rc;
2227
2228 rc = vote(chg->dc_icl_votable, USER_VOTER, true, val->intval);
2229 return rc;
2230}
2231
2232/*******************
Nicholas Troast34db5032016-03-28 12:26:44 -07002233 * USB PSY GETTERS *
2234 *******************/
2235
2236int smblib_get_prop_usb_present(struct smb_charger *chg,
2237 union power_supply_propval *val)
2238{
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002239 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07002240 u8 stat;
2241
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002242 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
Nicholas Troast34db5032016-03-28 12:26:44 -07002243 if (rc < 0) {
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002244 smblib_err(chg, "Couldn't read USBIN_RT_STS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07002245 return rc;
2246 }
Nicholas Troast34db5032016-03-28 12:26:44 -07002247
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002248 val->intval = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
2249 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002250}
2251
2252int smblib_get_prop_usb_online(struct smb_charger *chg,
2253 union power_supply_propval *val)
2254{
2255 int rc = 0;
2256 u8 stat;
2257
Abhijeet Dharmapurikar84923af2017-03-23 14:07:07 -07002258 if (get_client_vote_locked(chg->usb_icl_votable, USER_VOTER) == 0) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002259 val->intval = false;
2260 return rc;
2261 }
2262
2263 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
2264 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002265 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002266 rc);
2267 return rc;
2268 }
2269 smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
2270 stat);
2271
2272 val->intval = (stat & USE_USBIN_BIT) &&
Vic Wei7ade2842016-12-14 18:47:49 -08002273 (stat & VALID_INPUT_POWER_SOURCE_STS_BIT);
Nicholas Troast34db5032016-03-28 12:26:44 -07002274 return rc;
2275}
2276
Nicholas Troast7f55c922017-07-25 13:18:03 -07002277int smblib_get_prop_usb_voltage_max(struct smb_charger *chg,
2278 union power_supply_propval *val)
2279{
2280 switch (chg->real_charger_type) {
2281 case POWER_SUPPLY_TYPE_USB_HVDCP:
Ashay Jaiswal3c82d282017-11-28 22:07:36 +05302282 case POWER_SUPPLY_TYPE_USB_HVDCP_3:
Nicholas Troast7f55c922017-07-25 13:18:03 -07002283 case POWER_SUPPLY_TYPE_USB_PD:
2284 if (chg->smb_version == PM660_SUBTYPE)
2285 val->intval = MICRO_9V;
2286 else
2287 val->intval = MICRO_12V;
2288 break;
2289 default:
2290 val->intval = MICRO_5V;
2291 break;
2292 }
2293
2294 return 0;
2295}
2296
Nicholas Troast34db5032016-03-28 12:26:44 -07002297int smblib_get_prop_usb_voltage_now(struct smb_charger *chg,
2298 union power_supply_propval *val)
2299{
Harry Yangba874ce2016-08-19 14:17:01 -07002300 if (!chg->iio.usbin_v_chan ||
2301 PTR_ERR(chg->iio.usbin_v_chan) == -EPROBE_DEFER)
2302 chg->iio.usbin_v_chan = iio_channel_get(chg->dev, "usbin_v");
2303
2304 if (IS_ERR(chg->iio.usbin_v_chan))
2305 return PTR_ERR(chg->iio.usbin_v_chan);
2306
2307 return iio_read_channel_processed(chg->iio.usbin_v_chan, &val->intval);
Nicholas Troast34db5032016-03-28 12:26:44 -07002308}
2309
Harry Yangba874ce2016-08-19 14:17:01 -07002310int smblib_get_prop_usb_current_now(struct smb_charger *chg,
2311 union power_supply_propval *val)
2312{
2313 int rc = 0;
2314
2315 rc = smblib_get_prop_usb_present(chg, val);
2316 if (rc < 0 || !val->intval)
2317 return rc;
2318
2319 if (!chg->iio.usbin_i_chan ||
2320 PTR_ERR(chg->iio.usbin_i_chan) == -EPROBE_DEFER)
2321 chg->iio.usbin_i_chan = iio_channel_get(chg->dev, "usbin_i");
2322
2323 if (IS_ERR(chg->iio.usbin_i_chan))
2324 return PTR_ERR(chg->iio.usbin_i_chan);
2325
2326 return iio_read_channel_processed(chg->iio.usbin_i_chan, &val->intval);
2327}
2328
2329int smblib_get_prop_charger_temp(struct smb_charger *chg,
2330 union power_supply_propval *val)
2331{
2332 int rc;
2333
2334 if (!chg->iio.temp_chan ||
2335 PTR_ERR(chg->iio.temp_chan) == -EPROBE_DEFER)
2336 chg->iio.temp_chan = iio_channel_get(chg->dev, "charger_temp");
2337
2338 if (IS_ERR(chg->iio.temp_chan))
2339 return PTR_ERR(chg->iio.temp_chan);
2340
2341 rc = iio_read_channel_processed(chg->iio.temp_chan, &val->intval);
2342 val->intval /= 100;
2343 return rc;
2344}
2345
2346int smblib_get_prop_charger_temp_max(struct smb_charger *chg,
2347 union power_supply_propval *val)
2348{
2349 int rc;
2350
2351 if (!chg->iio.temp_max_chan ||
2352 PTR_ERR(chg->iio.temp_max_chan) == -EPROBE_DEFER)
2353 chg->iio.temp_max_chan = iio_channel_get(chg->dev,
2354 "charger_temp_max");
2355 if (IS_ERR(chg->iio.temp_max_chan))
2356 return PTR_ERR(chg->iio.temp_max_chan);
2357
2358 rc = iio_read_channel_processed(chg->iio.temp_max_chan, &val->intval);
2359 val->intval /= 100;
2360 return rc;
2361}
2362
Nicholas Troast34db5032016-03-28 12:26:44 -07002363int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
2364 union power_supply_propval *val)
2365{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002366 if (chg->typec_status[3] & CC_ATTACHED_BIT)
2367 val->intval =
2368 (bool)(chg->typec_status[3] & CC_ORIENTATION_BIT) + 1;
Nicholas Troast34db5032016-03-28 12:26:44 -07002369 else
2370 val->intval = 0;
2371
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002372 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002373}
2374
2375static const char * const smblib_typec_mode_name[] = {
2376 [POWER_SUPPLY_TYPEC_NONE] = "NONE",
2377 [POWER_SUPPLY_TYPEC_SOURCE_DEFAULT] = "SOURCE_DEFAULT",
2378 [POWER_SUPPLY_TYPEC_SOURCE_MEDIUM] = "SOURCE_MEDIUM",
2379 [POWER_SUPPLY_TYPEC_SOURCE_HIGH] = "SOURCE_HIGH",
2380 [POWER_SUPPLY_TYPEC_NON_COMPLIANT] = "NON_COMPLIANT",
2381 [POWER_SUPPLY_TYPEC_SINK] = "SINK",
2382 [POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE] = "SINK_POWERED_CABLE",
2383 [POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY] = "SINK_DEBUG_ACCESSORY",
2384 [POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER] = "SINK_AUDIO_ADAPTER",
2385 [POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY] = "POWERED_CABLE_ONLY",
2386};
2387
2388static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
2389{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002390 switch (chg->typec_status[0]) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002391 case UFP_TYPEC_RDSTD_BIT:
2392 return POWER_SUPPLY_TYPEC_SOURCE_DEFAULT;
2393 case UFP_TYPEC_RD1P5_BIT:
2394 return POWER_SUPPLY_TYPEC_SOURCE_MEDIUM;
2395 case UFP_TYPEC_RD3P0_BIT:
2396 return POWER_SUPPLY_TYPEC_SOURCE_HIGH;
2397 default:
2398 break;
2399 }
2400
Nicholas Troaste1932e42017-04-12 12:38:18 -07002401 return POWER_SUPPLY_TYPEC_NONE;
Nicholas Troast34db5032016-03-28 12:26:44 -07002402}
2403
2404static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
2405{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002406 switch (chg->typec_status[1] & DFP_TYPEC_MASK) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002407 case DFP_RA_RA_BIT:
2408 return POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER;
2409 case DFP_RD_RD_BIT:
2410 return POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY;
2411 case DFP_RD_RA_VCONN_BIT:
2412 return POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE;
2413 case DFP_RD_OPEN_BIT:
2414 return POWER_SUPPLY_TYPEC_SINK;
Nicholas Troast34db5032016-03-28 12:26:44 -07002415 default:
2416 break;
2417 }
2418
2419 return POWER_SUPPLY_TYPEC_NONE;
2420}
2421
Nicholas Troaste1932e42017-04-12 12:38:18 -07002422static int smblib_get_prop_typec_mode(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07002423{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002424 if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
Nicholas Troaste1932e42017-04-12 12:38:18 -07002425 return smblib_get_prop_dfp_mode(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07002426 else
Nicholas Troaste1932e42017-04-12 12:38:18 -07002427 return smblib_get_prop_ufp_mode(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07002428}
2429
2430int smblib_get_prop_typec_power_role(struct smb_charger *chg,
2431 union power_supply_propval *val)
2432{
2433 int rc = 0;
2434 u8 ctrl;
2435
2436 rc = smblib_read(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &ctrl);
2437 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002438 smblib_err(chg, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002439 rc);
2440 return rc;
2441 }
2442 smblib_dbg(chg, PR_REGISTER, "TYPE_C_INTRPT_ENB_SOFTWARE_CTRL = 0x%02x\n",
2443 ctrl);
2444
2445 if (ctrl & TYPEC_DISABLE_CMD_BIT) {
2446 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
2447 return rc;
2448 }
2449
2450 switch (ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT)) {
2451 case 0:
2452 val->intval = POWER_SUPPLY_TYPEC_PR_DUAL;
2453 break;
2454 case DFP_EN_CMD_BIT:
2455 val->intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
2456 break;
2457 case UFP_EN_CMD_BIT:
2458 val->intval = POWER_SUPPLY_TYPEC_PR_SINK;
2459 break;
2460 default:
2461 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002462 smblib_err(chg, "unsupported power role 0x%02lx\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002463 ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT));
2464 return -EINVAL;
2465 }
2466
2467 return rc;
2468}
2469
2470int smblib_get_prop_pd_allowed(struct smb_charger *chg,
2471 union power_supply_propval *val)
2472{
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07002473 val->intval = get_effective_result(chg->pd_allowed_votable);
Nicholas Troast34db5032016-03-28 12:26:44 -07002474 return 0;
2475}
2476
Nicholas Troast133a7f52016-06-29 13:48:20 -07002477int smblib_get_prop_input_current_settled(struct smb_charger *chg,
2478 union power_supply_propval *val)
2479{
2480 return smblib_get_charge_param(chg, &chg->param.icl_stat, &val->intval);
2481}
2482
Fenglin Wuef4730e2017-01-11 18:16:25 +08002483#define HVDCP3_STEP_UV 200000
2484int smblib_get_prop_input_voltage_settled(struct smb_charger *chg,
2485 union power_supply_propval *val)
2486{
Fenglin Wuef4730e2017-01-11 18:16:25 +08002487 int rc, pulses;
Fenglin Wuef4730e2017-01-11 18:16:25 +08002488
Nicholas Troast5f314c12017-05-25 11:58:02 -07002489 switch (chg->real_charger_type) {
Fenglin Wuef4730e2017-01-11 18:16:25 +08002490 case POWER_SUPPLY_TYPE_USB_HVDCP_3:
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +05302491 rc = smblib_get_pulse_cnt(chg, &pulses);
Fenglin Wuef4730e2017-01-11 18:16:25 +08002492 if (rc < 0) {
2493 smblib_err(chg,
2494 "Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
2495 return 0;
2496 }
Fenglin Wuef4730e2017-01-11 18:16:25 +08002497 val->intval = MICRO_5V + HVDCP3_STEP_UV * pulses;
2498 break;
Nicholas Troast5f314c12017-05-25 11:58:02 -07002499 case POWER_SUPPLY_TYPE_USB_PD:
2500 val->intval = chg->voltage_min_uv;
2501 break;
Fenglin Wuef4730e2017-01-11 18:16:25 +08002502 default:
2503 val->intval = MICRO_5V;
2504 break;
2505 }
2506
2507 return 0;
2508}
2509
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002510int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg,
2511 union power_supply_propval *val)
2512{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002513 val->intval = chg->pd_hard_reset;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002514 return 0;
2515}
2516
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07002517int smblib_get_pe_start(struct smb_charger *chg,
2518 union power_supply_propval *val)
2519{
2520 /*
2521 * hvdcp timeout voter is the last one to allow pd. Use its vote
2522 * to indicate start of pe engine
2523 */
2524 val->intval
2525 = !get_client_vote_locked(chg->pd_disallowed_votable_indirect,
2526 HVDCP_TIMEOUT_VOTER);
2527 return 0;
2528}
2529
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002530int smblib_get_prop_die_health(struct smb_charger *chg,
Nicholas Troastb021dd92017-01-31 18:43:38 -08002531 union power_supply_propval *val)
2532{
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002533 int rc;
Nicholas Troastb021dd92017-01-31 18:43:38 -08002534 u8 stat;
2535
2536 rc = smblib_read(chg, TEMP_RANGE_STATUS_REG, &stat);
2537 if (rc < 0) {
2538 smblib_err(chg, "Couldn't read TEMP_RANGE_STATUS_REG rc=%d\n",
2539 rc);
2540 return rc;
2541 }
2542
Harry Yang6ed35462017-11-16 23:01:39 -08002543 if (stat & ALERT_LEVEL_BIT)
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002544 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
Harry Yang6ed35462017-11-16 23:01:39 -08002545 else if (stat & TEMP_ABOVE_RANGE_BIT)
2546 val->intval = POWER_SUPPLY_HEALTH_HOT;
2547 else if (stat & TEMP_WITHIN_RANGE_BIT)
2548 val->intval = POWER_SUPPLY_HEALTH_WARM;
2549 else if (stat & TEMP_BELOW_RANGE_BIT)
2550 val->intval = POWER_SUPPLY_HEALTH_COOL;
2551 else
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002552 val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
Nicholas Troastb021dd92017-01-31 18:43:38 -08002553
Nicholas Troastb021dd92017-01-31 18:43:38 -08002554 return 0;
2555}
2556
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05302557#define SDP_CURRENT_UA 500000
2558#define CDP_CURRENT_UA 1500000
2559#define DCP_CURRENT_UA 1500000
2560#define HVDCP_CURRENT_UA 3000000
2561#define TYPEC_DEFAULT_CURRENT_UA 900000
2562#define TYPEC_MEDIUM_CURRENT_UA 1500000
2563#define TYPEC_HIGH_CURRENT_UA 3000000
2564static int get_rp_based_dcp_current(struct smb_charger *chg, int typec_mode)
2565{
2566 int rp_ua;
2567
2568 switch (typec_mode) {
2569 case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
2570 rp_ua = TYPEC_HIGH_CURRENT_UA;
2571 break;
2572 case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
2573 case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
2574 /* fall through */
2575 default:
2576 rp_ua = DCP_CURRENT_UA;
2577 }
2578
2579 return rp_ua;
2580}
2581
Nicholas Troast34db5032016-03-28 12:26:44 -07002582/*******************
2583 * USB PSY SETTERS *
2584 * *****************/
2585
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002586int smblib_set_prop_pd_current_max(struct smb_charger *chg,
2587 const union power_supply_propval *val)
2588{
2589 int rc;
2590
2591 if (chg->pd_active)
2592 rc = vote(chg->usb_icl_votable, PD_VOTER, true, val->intval);
2593 else
2594 rc = -EPERM;
2595
2596 return rc;
2597}
2598
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05302599static int smblib_handle_usb_current(struct smb_charger *chg,
2600 int usb_current)
2601{
2602 int rc = 0, rp_ua, typec_mode;
2603
2604 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_FLOAT) {
2605 if (usb_current == -ETIMEDOUT) {
2606 /*
2607 * Valid FLOAT charger, report the current based
2608 * of Rp
2609 */
2610 typec_mode = smblib_get_prop_typec_mode(chg);
2611 rp_ua = get_rp_based_dcp_current(chg, typec_mode);
2612 rc = vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER,
2613 true, rp_ua);
2614 if (rc < 0)
2615 return rc;
2616 } else {
2617 /*
2618 * FLOAT charger detected as SDP by USB driver,
2619 * charge with the requested current and update the
2620 * real_charger_type
2621 */
2622 chg->real_charger_type = POWER_SUPPLY_TYPE_USB;
2623 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
2624 true, usb_current);
2625 if (rc < 0)
2626 return rc;
2627 rc = vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER,
2628 false, 0);
2629 if (rc < 0)
2630 return rc;
2631 }
2632 } else {
2633 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
2634 true, usb_current);
2635 }
2636
2637 return rc;
2638}
2639
Nicholas Troast7f55c922017-07-25 13:18:03 -07002640int smblib_set_prop_sdp_current_max(struct smb_charger *chg,
Nicholas Troast34db5032016-03-28 12:26:44 -07002641 const union power_supply_propval *val)
2642{
Nicholas Troast8d33b7d2017-01-16 11:18:38 -08002643 int rc = 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002644
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002645 if (!chg->pd_active) {
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05302646 rc = smblib_handle_usb_current(chg, val->intval);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002647 } else if (chg->system_suspend_supported) {
2648 if (val->intval <= USBIN_25MA)
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302649 rc = vote(chg->usb_icl_votable,
2650 PD_SUSPEND_SUPPORTED_VOTER, true, val->intval);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002651 else
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302652 rc = vote(chg->usb_icl_votable,
2653 PD_SUSPEND_SUPPORTED_VOTER, false, 0);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002654 }
Nicholas Troast34db5032016-03-28 12:26:44 -07002655 return rc;
2656}
2657
Harry Yangd89ff1f2016-12-05 14:59:11 -08002658int smblib_set_prop_boost_current(struct smb_charger *chg,
2659 const union power_supply_propval *val)
2660{
2661 int rc = 0;
2662
2663 rc = smblib_set_charge_param(chg, &chg->param.freq_boost,
2664 val->intval <= chg->boost_threshold_ua ?
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05302665 chg->chg_freq.freq_below_otg_threshold :
2666 chg->chg_freq.freq_above_otg_threshold);
Harry Yangd89ff1f2016-12-05 14:59:11 -08002667 if (rc < 0) {
2668 dev_err(chg->dev, "Error in setting freq_boost rc=%d\n", rc);
2669 return rc;
2670 }
2671
2672 chg->boost_current_ua = val->intval;
2673 return rc;
2674}
2675
Nicholas Troast34db5032016-03-28 12:26:44 -07002676int smblib_set_prop_typec_power_role(struct smb_charger *chg,
2677 const union power_supply_propval *val)
2678{
2679 int rc = 0;
2680 u8 power_role;
2681
2682 switch (val->intval) {
2683 case POWER_SUPPLY_TYPEC_PR_NONE:
2684 power_role = TYPEC_DISABLE_CMD_BIT;
2685 break;
2686 case POWER_SUPPLY_TYPEC_PR_DUAL:
2687 power_role = 0;
2688 break;
2689 case POWER_SUPPLY_TYPEC_PR_SINK:
2690 power_role = UFP_EN_CMD_BIT;
2691 break;
2692 case POWER_SUPPLY_TYPEC_PR_SOURCE:
2693 power_role = DFP_EN_CMD_BIT;
2694 break;
2695 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002696 smblib_err(chg, "power role %d not supported\n", val->intval);
Nicholas Troast34db5032016-03-28 12:26:44 -07002697 return -EINVAL;
2698 }
2699
Jack Pham54a39bd2017-03-29 18:59:37 -07002700 if (power_role == UFP_EN_CMD_BIT) {
2701 /* disable PBS workaround when forcing sink mode */
2702 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0x0);
2703 if (rc < 0) {
2704 smblib_err(chg, "Couldn't write to TM_IO_DTEST4_SEL rc=%d\n",
2705 rc);
2706 }
2707 } else {
2708 /* restore it back to 0xA5 */
2709 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
2710 if (rc < 0) {
2711 smblib_err(chg, "Couldn't write to TM_IO_DTEST4_SEL rc=%d\n",
2712 rc);
2713 }
2714 }
2715
Nicholas Troast34db5032016-03-28 12:26:44 -07002716 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2717 TYPEC_POWER_ROLE_CMD_MASK, power_role);
2718 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002719 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 -07002720 power_role, rc);
2721 return rc;
2722 }
2723
2724 return rc;
2725}
2726
Nicholas Troast7f55c922017-07-25 13:18:03 -07002727int smblib_set_prop_pd_voltage_min(struct smb_charger *chg,
Nicholas Troast34db5032016-03-28 12:26:44 -07002728 const union power_supply_propval *val)
2729{
2730 int rc, min_uv;
2731
2732 min_uv = min(val->intval, chg->voltage_max_uv);
2733 rc = smblib_set_usb_pd_allowed_voltage(chg, min_uv,
2734 chg->voltage_max_uv);
2735 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002736 smblib_err(chg, "invalid max voltage %duV rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002737 val->intval, rc);
2738 return rc;
2739 }
2740
Harry Yangaba1f5f2016-09-28 10:47:29 -07002741 chg->voltage_min_uv = min_uv;
Nicholas Troast5f314c12017-05-25 11:58:02 -07002742 power_supply_changed(chg->usb_main_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07002743 return rc;
2744}
2745
Nicholas Troast7f55c922017-07-25 13:18:03 -07002746int smblib_set_prop_pd_voltage_max(struct smb_charger *chg,
Nicholas Troast34db5032016-03-28 12:26:44 -07002747 const union power_supply_propval *val)
2748{
2749 int rc, max_uv;
2750
2751 max_uv = max(val->intval, chg->voltage_min_uv);
2752 rc = smblib_set_usb_pd_allowed_voltage(chg, chg->voltage_min_uv,
2753 max_uv);
2754 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002755 smblib_err(chg, "invalid min voltage %duV rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002756 val->intval, rc);
2757 return rc;
2758 }
2759
Harry Yangaba1f5f2016-09-28 10:47:29 -07002760 chg->voltage_max_uv = max_uv;
Nicholas Troast34db5032016-03-28 12:26:44 -07002761 return rc;
2762}
2763
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07002764static int __smblib_set_prop_pd_active(struct smb_charger *chg, bool pd_active)
Nicholas Troast34db5032016-03-28 12:26:44 -07002765{
2766 int rc;
Nicholas Troaste1932e42017-04-12 12:38:18 -07002767 bool orientation, sink_attached, hvdcp;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002768 u8 stat;
Nicholas Troast34db5032016-03-28 12:26:44 -07002769
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07002770 chg->pd_active = pd_active;
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002771 if (chg->pd_active) {
2772 vote(chg->apsd_disable_votable, PD_VOTER, true, 0);
2773 vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
2774 vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
2775
2776 /*
2777 * VCONN_EN_ORIENTATION_BIT controls whether to use CC1 or CC2
2778 * line when TYPEC_SPARE_CFG_BIT (CC pin selection s/w override)
2779 * is set or when VCONN_EN_VALUE_BIT is set.
2780 */
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002781 orientation = chg->typec_status[3] & CC_ORIENTATION_BIT;
Harry Yang88acff42016-09-21 14:56:06 -07002782 rc = smblib_masked_write(chg,
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07002783 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2784 VCONN_EN_ORIENTATION_BIT,
2785 orientation ? 0 : VCONN_EN_ORIENTATION_BIT);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002786 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002787 smblib_err(chg,
Harry Yang88acff42016-09-21 14:56:06 -07002788 "Couldn't enable vconn on CC line rc=%d\n", rc);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002789
2790 /* SW controlled CC_OUT */
2791 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
2792 TYPEC_SPARE_CFG_BIT, TYPEC_SPARE_CFG_BIT);
2793 if (rc < 0)
2794 smblib_err(chg, "Couldn't enable SW cc_out rc=%d\n",
2795 rc);
2796
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302797 /*
2798 * Enforce 500mA for PD until the real vote comes in later.
2799 * It is guaranteed that pd_active is set prior to
2800 * pd_current_max
2801 */
Harry Yangcd995202016-11-07 13:32:52 -08002802 rc = vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002803 if (rc < 0)
Harry Yangcd995202016-11-07 13:32:52 -08002804 smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n",
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002805 rc);
Harry Yangcd995202016-11-07 13:32:52 -08002806
Nicholas Troastf9e44992017-03-14 09:06:56 -07002807 /* since PD was found the cable must be non-legacy */
2808 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
2809
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002810 /* clear USB ICL vote for DCP_VOTER */
Harry Yang631b99e2016-11-17 11:24:25 -08002811 rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002812 if (rc < 0)
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002813 smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n",
2814 rc);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002815
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302816 /* remove USB_PSY_VOTER */
2817 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002818 if (rc < 0)
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302819 smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002820 } else {
Nicholas Troaste1932e42017-04-12 12:38:18 -07002821 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
2822 if (rc < 0) {
2823 smblib_err(chg, "Couldn't read APSD status rc=%d\n",
2824 rc);
2825 return rc;
2826 }
2827
2828 hvdcp = stat & QC_CHARGER_BIT;
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002829 vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
2830 vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
Harry Yang7b429572017-09-12 11:15:04 -07002831 vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002832 vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER,
2833 false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002834
2835 /* HW controlled CC_OUT */
2836 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
2837 TYPEC_SPARE_CFG_BIT, 0);
2838 if (rc < 0)
2839 smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n",
2840 rc);
2841
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002842 /*
2843 * This WA should only run for HVDCP. Non-legacy SDP/CDP could
2844 * draw more, but this WA will remove Rd causing VBUS to drop,
2845 * and data could be interrupted. Non-legacy DCP could also draw
2846 * more, but it may impact compliance.
2847 */
Nicholas Troaste1932e42017-04-12 12:38:18 -07002848 sink_attached = chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT;
Ashay Jaiswal8207ee42017-11-27 11:41:27 +05302849 if ((chg->connector_type != POWER_SUPPLY_CONNECTOR_MICRO_USB)
2850 && !chg->typec_legacy_valid
2851 && !sink_attached && hvdcp)
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002852 schedule_work(&chg->legacy_detection_work);
Harry Yang88acff42016-09-21 14:56:06 -07002853 }
2854
Harry Yang6607b4a2016-05-17 17:50:09 -07002855 smblib_update_usb_type(chg);
Abhijeet Dharmapurikar76e2af52016-10-06 17:25:01 -07002856 power_supply_changed(chg->usb_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07002857 return rc;
2858}
2859
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07002860int smblib_set_prop_pd_active(struct smb_charger *chg,
2861 const union power_supply_propval *val)
2862{
2863 if (!get_effective_result(chg->pd_allowed_votable))
2864 return -EINVAL;
2865
2866 return __smblib_set_prop_pd_active(chg, val->intval);
2867}
2868
Fenglin Wuedd70792016-11-22 13:16:19 +08002869int smblib_set_prop_ship_mode(struct smb_charger *chg,
2870 const union power_supply_propval *val)
2871{
2872 int rc;
2873
2874 smblib_dbg(chg, PR_MISC, "Set ship mode: %d!!\n", !!val->intval);
2875
2876 rc = smblib_masked_write(chg, SHIP_MODE_REG, SHIP_MODE_EN_BIT,
2877 !!val->intval ? SHIP_MODE_EN_BIT : 0);
2878 if (rc < 0)
2879 dev_err(chg->dev, "Couldn't %s ship mode, rc=%d\n",
2880 !!val->intval ? "enable" : "disable", rc);
2881
2882 return rc;
2883}
2884
Harry Yang5e2bb712016-10-18 16:47:48 -07002885int smblib_reg_block_update(struct smb_charger *chg,
2886 struct reg_info *entry)
2887{
2888 int rc = 0;
2889
2890 while (entry && entry->reg) {
2891 rc = smblib_read(chg, entry->reg, &entry->bak);
2892 if (rc < 0) {
2893 dev_err(chg->dev, "Error in reading %s rc=%d\n",
2894 entry->desc, rc);
2895 break;
2896 }
2897 entry->bak &= entry->mask;
2898
2899 rc = smblib_masked_write(chg, entry->reg,
2900 entry->mask, entry->val);
2901 if (rc < 0) {
2902 dev_err(chg->dev, "Error in writing %s rc=%d\n",
2903 entry->desc, rc);
2904 break;
2905 }
2906 entry++;
2907 }
2908
2909 return rc;
2910}
2911
2912int smblib_reg_block_restore(struct smb_charger *chg,
2913 struct reg_info *entry)
2914{
2915 int rc = 0;
2916
2917 while (entry && entry->reg) {
2918 rc = smblib_masked_write(chg, entry->reg,
2919 entry->mask, entry->bak);
2920 if (rc < 0) {
2921 dev_err(chg->dev, "Error in writing %s rc=%d\n",
2922 entry->desc, rc);
2923 break;
2924 }
2925 entry++;
2926 }
2927
2928 return rc;
2929}
2930
Harry Yang755a34b2016-11-01 01:18:51 -07002931static struct reg_info cc2_detach_settings[] = {
2932 {
2933 .reg = TYPE_C_CFG_2_REG,
2934 .mask = TYPE_C_UFP_MODE_BIT | EN_TRY_SOURCE_MODE_BIT,
2935 .val = TYPE_C_UFP_MODE_BIT,
2936 .desc = "TYPE_C_CFG_2_REG",
2937 },
2938 {
2939 .reg = TYPE_C_CFG_3_REG,
2940 .mask = EN_TRYSINK_MODE_BIT,
2941 .val = 0,
2942 .desc = "TYPE_C_CFG_3_REG",
2943 },
2944 {
2945 .reg = TAPER_TIMER_SEL_CFG_REG,
2946 .mask = TYPEC_SPARE_CFG_BIT,
2947 .val = TYPEC_SPARE_CFG_BIT,
2948 .desc = "TAPER_TIMER_SEL_CFG_REG",
2949 },
2950 {
2951 .reg = TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2952 .mask = VCONN_EN_ORIENTATION_BIT,
2953 .val = 0,
2954 .desc = "TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG",
2955 },
2956 {
2957 .reg = MISC_CFG_REG,
2958 .mask = TCC_DEBOUNCE_20MS_BIT,
2959 .val = TCC_DEBOUNCE_20MS_BIT,
2960 .desc = "Tccdebounce time"
2961 },
2962 {
2963 },
2964};
2965
2966static int smblib_cc2_sink_removal_enter(struct smb_charger *chg)
2967{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002968 int rc, ccout, ufp_mode;
2969 u8 stat;
Harry Yang755a34b2016-11-01 01:18:51 -07002970
2971 if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002972 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002973
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002974 if (chg->cc2_detach_wa_active)
2975 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002976
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002977 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
Harry Yang755a34b2016-11-01 01:18:51 -07002978 if (rc < 0) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002979 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
Harry Yang755a34b2016-11-01 01:18:51 -07002980 return rc;
2981 }
Nicholas Troaste1932e42017-04-12 12:38:18 -07002982
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002983 ccout = (stat & CC_ATTACHED_BIT) ?
2984 (!!(stat & CC_ORIENTATION_BIT) + 1) : 0;
2985 ufp_mode = (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT) ?
2986 !(stat & UFP_DFP_MODE_STATUS_BIT) : 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002987
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002988 if (ccout != 2)
2989 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002990
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002991 if (!ufp_mode)
2992 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002993
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002994 chg->cc2_detach_wa_active = true;
2995 /* The CC2 removal WA will cause a type-c-change IRQ storm */
2996 smblib_reg_block_update(chg, cc2_detach_settings);
2997 schedule_work(&chg->rdstd_cc2_detach_work);
Harry Yang755a34b2016-11-01 01:18:51 -07002998 return rc;
2999}
3000
3001static int smblib_cc2_sink_removal_exit(struct smb_charger *chg)
3002{
Harry Yang755a34b2016-11-01 01:18:51 -07003003 if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003004 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07003005
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003006 if (!chg->cc2_detach_wa_active)
3007 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07003008
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003009 chg->cc2_detach_wa_active = false;
3010 cancel_work_sync(&chg->rdstd_cc2_detach_work);
3011 smblib_reg_block_restore(chg, cc2_detach_settings);
3012 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07003013}
3014
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07003015int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
3016 const union power_supply_propval *val)
3017{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003018 int rc = 0;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07003019
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003020 if (chg->pd_hard_reset == val->intval)
3021 return rc;
3022
3023 chg->pd_hard_reset = val->intval;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07003024 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003025 EXIT_SNK_BASED_ON_CC_BIT,
3026 (chg->pd_hard_reset) ? EXIT_SNK_BASED_ON_CC_BIT : 0);
3027 if (rc < 0)
3028 smblib_err(chg, "Couldn't set EXIT_SNK_BASED_ON_CC rc=%d\n",
Harry Yang755a34b2016-11-01 01:18:51 -07003029 rc);
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07003030
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003031 vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER,
3032 chg->pd_hard_reset, 0);
Harry Yang755a34b2016-11-01 01:18:51 -07003033
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07003034 return rc;
3035}
3036
Anirudh Ghayal941acaa2017-07-19 16:04:44 +05303037static int smblib_recover_from_soft_jeita(struct smb_charger *chg)
3038{
3039 u8 stat_1, stat_2;
3040 int rc;
3041
3042 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat_1);
3043 if (rc < 0) {
3044 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
3045 rc);
3046 return rc;
3047 }
3048
3049 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat_2);
3050 if (rc < 0) {
3051 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
3052 rc);
3053 return rc;
3054 }
3055
3056 if ((chg->jeita_status && !(stat_2 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK) &&
3057 ((stat_1 & BATTERY_CHARGER_STATUS_MASK) == TERMINATE_CHARGE))) {
3058 /*
3059 * We are moving from JEITA soft -> Normal and charging
3060 * is terminated
3061 */
3062 rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG, 0);
3063 if (rc < 0) {
3064 smblib_err(chg, "Couldn't disable charging rc=%d\n",
3065 rc);
3066 return rc;
3067 }
3068 rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG,
3069 CHARGING_ENABLE_CMD_BIT);
3070 if (rc < 0) {
3071 smblib_err(chg, "Couldn't enable charging rc=%d\n",
3072 rc);
3073 return rc;
3074 }
3075 }
3076
3077 chg->jeita_status = stat_2 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK;
3078
3079 return 0;
3080}
3081
Nicholas Troast7dbcad22016-10-05 13:30:18 -07003082/************************
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003083 * USB MAIN PSY GETTERS *
3084 ************************/
3085int smblib_get_prop_fcc_delta(struct smb_charger *chg,
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05303086 union power_supply_propval *val)
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003087{
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05303088 int rc, jeita_cc_delta_ua = 0;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003089
Harry Yang0d189772017-10-06 12:42:10 -07003090 if (chg->sw_jeita_enabled) {
3091 val->intval = 0;
3092 return 0;
3093 }
3094
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003095 rc = smblib_get_jeita_cc_delta(chg, &jeita_cc_delta_ua);
3096 if (rc < 0) {
3097 smblib_err(chg, "Couldn't get jeita cc delta rc=%d\n", rc);
3098 jeita_cc_delta_ua = 0;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003099 }
3100
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05303101 val->intval = jeita_cc_delta_ua;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003102 return 0;
3103}
3104
3105/************************
3106 * USB MAIN PSY SETTERS *
3107 ************************/
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003108int smblib_get_charge_current(struct smb_charger *chg,
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003109 int *total_current_ua)
3110{
Ashay Jaiswal7b6eb962017-04-26 14:34:29 +05303111 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003112 union power_supply_propval val = {0, };
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003113 int rc = 0, typec_source_rd, current_ua;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003114 bool non_compliant;
3115 u8 stat5;
3116
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003117 if (chg->pd_active) {
3118 *total_current_ua =
3119 get_client_vote_locked(chg->usb_icl_votable, PD_VOTER);
3120 return rc;
3121 }
3122
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003123 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
3124 if (rc < 0) {
3125 smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc);
3126 return rc;
3127 }
3128 non_compliant = stat5 & TYPEC_NONCOMP_LEGACY_CABLE_STATUS_BIT;
3129
3130 /* get settled ICL */
3131 rc = smblib_get_prop_input_current_settled(chg, &val);
3132 if (rc < 0) {
3133 smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
3134 return rc;
3135 }
3136
3137 typec_source_rd = smblib_get_prop_ufp_mode(chg);
3138
3139 /* QC 2.0/3.0 adapter */
3140 if (apsd_result->bit & (QC_3P0_BIT | QC_2P0_BIT)) {
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303141 *total_current_ua = HVDCP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003142 return 0;
3143 }
3144
3145 if (non_compliant) {
3146 switch (apsd_result->bit) {
3147 case CDP_CHARGER_BIT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303148 current_ua = CDP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003149 break;
3150 case DCP_CHARGER_BIT:
3151 case OCP_CHARGER_BIT:
3152 case FLOAT_CHARGER_BIT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303153 current_ua = DCP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003154 break;
3155 default:
3156 current_ua = 0;
3157 break;
3158 }
3159
3160 *total_current_ua = max(current_ua, val.intval);
3161 return 0;
3162 }
3163
3164 switch (typec_source_rd) {
3165 case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
3166 switch (apsd_result->bit) {
3167 case CDP_CHARGER_BIT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303168 current_ua = CDP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003169 break;
3170 case DCP_CHARGER_BIT:
3171 case OCP_CHARGER_BIT:
3172 case FLOAT_CHARGER_BIT:
3173 current_ua = chg->default_icl_ua;
3174 break;
3175 default:
3176 current_ua = 0;
3177 break;
3178 }
3179 break;
3180 case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303181 current_ua = TYPEC_MEDIUM_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003182 break;
3183 case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303184 current_ua = TYPEC_HIGH_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003185 break;
3186 case POWER_SUPPLY_TYPEC_NON_COMPLIANT:
3187 case POWER_SUPPLY_TYPEC_NONE:
3188 default:
3189 current_ua = 0;
3190 break;
3191 }
3192
3193 *total_current_ua = max(current_ua, val.intval);
3194 return 0;
3195}
3196
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003197/************************
Nicholas Troast7dbcad22016-10-05 13:30:18 -07003198 * PARALLEL PSY GETTERS *
3199 ************************/
3200
3201int smblib_get_prop_slave_current_now(struct smb_charger *chg,
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003202 union power_supply_propval *pval)
Nicholas Troast7dbcad22016-10-05 13:30:18 -07003203{
3204 if (IS_ERR_OR_NULL(chg->iio.batt_i_chan))
3205 chg->iio.batt_i_chan = iio_channel_get(chg->dev, "batt_i");
3206
3207 if (IS_ERR(chg->iio.batt_i_chan))
3208 return PTR_ERR(chg->iio.batt_i_chan);
3209
3210 return iio_read_channel_processed(chg->iio.batt_i_chan, &pval->intval);
3211}
3212
Nicholas Troast34db5032016-03-28 12:26:44 -07003213/**********************
3214 * INTERRUPT HANDLERS *
3215 **********************/
3216
3217irqreturn_t smblib_handle_debug(int irq, void *data)
3218{
3219 struct smb_irq_data *irq_data = data;
3220 struct smb_charger *chg = irq_data->parent_data;
3221
3222 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003223 return IRQ_HANDLED;
3224}
3225
Nicholas Troast8995a702016-12-05 10:22:22 -08003226irqreturn_t smblib_handle_otg_overcurrent(int irq, void *data)
3227{
3228 struct smb_irq_data *irq_data = data;
3229 struct smb_charger *chg = irq_data->parent_data;
3230 int rc;
3231 u8 stat;
3232
3233 rc = smblib_read(chg, OTG_BASE + INT_RT_STS_OFFSET, &stat);
3234 if (rc < 0) {
3235 dev_err(chg->dev, "Couldn't read OTG_INT_RT_STS rc=%d\n", rc);
3236 return IRQ_HANDLED;
3237 }
3238
Ashay Jaiswal7c241382017-03-06 15:26:38 +05303239 if (chg->wa_flags & OTG_WA) {
3240 if (stat & OTG_OC_DIS_SW_STS_RT_STS_BIT)
3241 smblib_err(chg, "OTG disabled by hw\n");
3242
3243 /* not handling software based hiccups for PM660 */
3244 return IRQ_HANDLED;
3245 }
3246
Nicholas Troastb11015f2017-01-17 17:56:45 -08003247 if (stat & OTG_OVERCURRENT_RT_STS_BIT)
3248 schedule_work(&chg->otg_oc_work);
Nicholas Troast8995a702016-12-05 10:22:22 -08003249
Nicholas Troast8995a702016-12-05 10:22:22 -08003250 return IRQ_HANDLED;
3251}
3252
Harry Yang6fe72ab2016-06-14 16:21:39 -07003253irqreturn_t smblib_handle_chg_state_change(int irq, void *data)
3254{
3255 struct smb_irq_data *irq_data = data;
3256 struct smb_charger *chg = irq_data->parent_data;
Nicholas Troast8cb77552016-09-23 11:50:18 -07003257 u8 stat;
Harry Yang1d1034c2016-06-15 12:09:42 -07003258 int rc;
Harry Yang6fe72ab2016-06-14 16:21:39 -07003259
3260 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3261
Nicholas Troast8cb77552016-09-23 11:50:18 -07003262 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
Harry Yang1d1034c2016-06-15 12:09:42 -07003263 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003264 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003265 rc);
Harry Yang1d1034c2016-06-15 12:09:42 -07003266 return IRQ_HANDLED;
3267 }
3268
Nicholas Troast8cb77552016-09-23 11:50:18 -07003269 stat = stat & BATTERY_CHARGER_STATUS_MASK;
Nicholas Troast8cb77552016-09-23 11:50:18 -07003270 power_supply_changed(chg->batt_psy);
Harry Yang6fe72ab2016-06-14 16:21:39 -07003271 return IRQ_HANDLED;
3272}
3273
Abhijeet Dharmapurikar2644cd62016-07-20 16:54:55 -07003274irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data)
3275{
3276 struct smb_irq_data *irq_data = data;
3277 struct smb_charger *chg = irq_data->parent_data;
Anirudh Ghayal941acaa2017-07-19 16:04:44 +05303278 int rc;
3279
3280 rc = smblib_recover_from_soft_jeita(chg);
3281 if (rc < 0) {
3282 smblib_err(chg, "Couldn't recover chg from soft jeita rc=%d\n",
3283 rc);
3284 return IRQ_HANDLED;
3285 }
Abhijeet Dharmapurikar2644cd62016-07-20 16:54:55 -07003286
3287 rerun_election(chg->fcc_votable);
3288 power_supply_changed(chg->batt_psy);
3289 return IRQ_HANDLED;
3290}
3291
Nicholas Troast34db5032016-03-28 12:26:44 -07003292irqreturn_t smblib_handle_batt_psy_changed(int irq, void *data)
3293{
3294 struct smb_irq_data *irq_data = data;
3295 struct smb_charger *chg = irq_data->parent_data;
3296
Nicholas Troast47ae4612016-08-03 09:49:36 -07003297 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003298 power_supply_changed(chg->batt_psy);
3299 return IRQ_HANDLED;
3300}
3301
3302irqreturn_t smblib_handle_usb_psy_changed(int irq, void *data)
3303{
3304 struct smb_irq_data *irq_data = data;
3305 struct smb_charger *chg = irq_data->parent_data;
3306
Nicholas Troast47ae4612016-08-03 09:49:36 -07003307 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003308 power_supply_changed(chg->usb_psy);
3309 return IRQ_HANDLED;
3310}
3311
Subbaraman Narayanamurthy09327482017-02-06 16:33:12 -08003312irqreturn_t smblib_handle_usbin_uv(int irq, void *data)
3313{
3314 struct smb_irq_data *irq_data = data;
3315 struct smb_charger *chg = irq_data->parent_data;
3316 struct storm_watch *wdata;
3317
3318 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3319 if (!chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data)
3320 return IRQ_HANDLED;
3321
3322 wdata = &chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data->storm_data;
3323 reset_storm_count(wdata);
3324 return IRQ_HANDLED;
3325}
3326
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003327static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising)
3328{
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003329 if (vbus_rising) {
3330 /* use the typec flag even though its not typec */
3331 chg->typec_present = 1;
3332 } else {
3333 chg->typec_present = 0;
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003334 smblib_update_usb_type(chg);
3335 extcon_set_cable_state_(chg->extcon, EXTCON_USB, false);
3336 smblib_uusb_removal(chg);
3337 }
3338}
3339
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003340void smblib_usb_plugin_hard_reset_locked(struct smb_charger *chg)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003341{
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003342 int rc;
3343 u8 stat;
3344 bool vbus_rising;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303345 struct smb_irq_data *data;
3346 struct storm_watch *wdata;
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003347
3348 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
3349 if (rc < 0) {
3350 smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
3351 return;
3352 }
3353
3354 vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
3355
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303356 if (vbus_rising) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003357 smblib_cc2_sink_removal_exit(chg);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303358 } else {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003359 smblib_cc2_sink_removal_enter(chg);
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303360 if (chg->wa_flags & BOOST_BACK_WA) {
3361 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
3362 if (data) {
3363 wdata = &data->storm_data;
3364 update_storm_count(wdata,
3365 WEAK_CHG_STORM_COUNT);
3366 vote(chg->usb_icl_votable, BOOST_BACK_VOTER,
3367 false, 0);
3368 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
3369 false, 0);
3370 }
3371 }
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303372 }
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003373
3374 power_supply_changed(chg->usb_psy);
3375 smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
3376 vbus_rising ? "attached" : "detached");
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003377}
3378
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303379#define PL_DELAY_MS 30000
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003380void smblib_usb_plugin_locked(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07003381{
Nicholas Troast34db5032016-03-28 12:26:44 -07003382 int rc;
3383 u8 stat;
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003384 bool vbus_rising;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303385 struct smb_irq_data *data;
3386 struct storm_watch *wdata;
Nicholas Troast34db5032016-03-28 12:26:44 -07003387
Harry Yangcdad2bf2016-10-04 17:03:56 -07003388 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
3389 if (rc < 0) {
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003390 smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
3391 return;
Harry Yangcdad2bf2016-10-04 17:03:56 -07003392 }
3393
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003394 vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003395 smblib_set_opt_freq_buck(chg, vbus_rising ? chg->chg_freq.freq_5V :
3396 chg->chg_freq.freq_removal);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003397
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003398 if (vbus_rising) {
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05303399 rc = smblib_request_dpdm(chg, true);
3400 if (rc < 0)
3401 smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303402
3403 /* Schedule work to enable parallel charger */
3404 vote(chg->awake_votable, PL_DELAY_VOTER, true, 0);
3405 schedule_delayed_work(&chg->pl_enable_work,
3406 msecs_to_jiffies(PL_DELAY_MS));
Harry Yang1ed7f162017-08-25 11:26:51 -07003407 /* vbus rising when APSD was disabled and PD_ACTIVE = 0 */
3408 if (get_effective_result(chg->apsd_disable_votable) &&
3409 !chg->pd_active)
3410 pr_err("APSD disabled on vbus rising without PD\n");
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07003411 } else {
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303412 if (chg->wa_flags & BOOST_BACK_WA) {
3413 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
3414 if (data) {
3415 wdata = &data->storm_data;
3416 update_storm_count(wdata,
3417 WEAK_CHG_STORM_COUNT);
3418 vote(chg->usb_icl_votable, BOOST_BACK_VOTER,
3419 false, 0);
3420 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
3421 false, 0);
3422 }
3423 }
Nicholas Troastabedaf72016-09-16 11:07:45 -07003424
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05303425 rc = smblib_request_dpdm(chg, false);
3426 if (rc < 0)
3427 smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07003428 }
3429
Ashay Jaiswal0ce2c7c2017-11-14 12:29:02 +05303430 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003431 smblib_micro_usb_plugin(chg, vbus_rising);
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003432
Nicholas Troast62d86622016-09-22 11:41:33 -07003433 power_supply_changed(chg->usb_psy);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003434 smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
3435 vbus_rising ? "attached" : "detached");
3436}
3437
3438irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
3439{
3440 struct smb_irq_data *irq_data = data;
3441 struct smb_charger *chg = irq_data->parent_data;
3442
3443 mutex_lock(&chg->lock);
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003444 if (chg->pd_hard_reset)
3445 smblib_usb_plugin_hard_reset_locked(chg);
3446 else
3447 smblib_usb_plugin_locked(chg);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003448 mutex_unlock(&chg->lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07003449 return IRQ_HANDLED;
3450}
3451
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -07003452#define USB_WEAK_INPUT_UA 1400000
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303453#define ICL_CHANGE_DELAY_MS 1000
Harry Yang6fe72ab2016-06-14 16:21:39 -07003454irqreturn_t smblib_handle_icl_change(int irq, void *data)
3455{
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303456 u8 stat;
3457 int rc, settled_ua, delay = ICL_CHANGE_DELAY_MS;
Harry Yang6fe72ab2016-06-14 16:21:39 -07003458 struct smb_irq_data *irq_data = data;
3459 struct smb_charger *chg = irq_data->parent_data;
3460
Nicholas Troastbb9e1a32017-02-09 10:57:28 -08003461 if (chg->mode == PARALLEL_MASTER) {
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303462 rc = smblib_read(chg, AICL_STATUS_REG, &stat);
3463 if (rc < 0) {
3464 smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n",
3465 rc);
3466 return IRQ_HANDLED;
3467 }
3468
3469 rc = smblib_get_charge_param(chg, &chg->param.icl_stat,
3470 &settled_ua);
3471 if (rc < 0) {
3472 smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
3473 return IRQ_HANDLED;
3474 }
3475
3476 /* If AICL settled then schedule work now */
3477 if ((settled_ua == get_effective_result(chg->usb_icl_votable))
3478 || (stat & AICL_DONE_BIT))
3479 delay = 0;
3480
Ashay Jaiswalac854862017-03-06 23:58:55 +05303481 cancel_delayed_work_sync(&chg->icl_change_work);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303482 schedule_delayed_work(&chg->icl_change_work,
3483 msecs_to_jiffies(delay));
Nicholas Troastbb9e1a32017-02-09 10:57:28 -08003484 }
Harry Yang1d1034c2016-06-15 12:09:42 -07003485
Harry Yang6fe72ab2016-06-14 16:21:39 -07003486 return IRQ_HANDLED;
3487}
3488
Nicholas Troast34db5032016-03-28 12:26:44 -07003489static void smblib_handle_slow_plugin_timeout(struct smb_charger *chg,
3490 bool rising)
3491{
3492 smblib_dbg(chg, PR_INTERRUPT, "IRQ: slow-plugin-timeout %s\n",
3493 rising ? "rising" : "falling");
3494}
3495
3496static void smblib_handle_sdp_enumeration_done(struct smb_charger *chg,
3497 bool rising)
3498{
3499 smblib_dbg(chg, PR_INTERRUPT, "IRQ: sdp-enumeration-done %s\n",
3500 rising ? "rising" : "falling");
3501}
3502
Harry Yangcdad2bf2016-10-04 17:03:56 -07003503#define QC3_PULSES_FOR_6V 5
3504#define QC3_PULSES_FOR_9V 20
3505#define QC3_PULSES_FOR_12V 35
3506static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg)
3507{
3508 int rc;
3509 u8 stat;
3510 int pulses;
3511
Fenglin Wuef4730e2017-01-11 18:16:25 +08003512 power_supply_changed(chg->usb_main_psy);
Fenglin Wu80826e02017-04-25 21:45:08 +08003513 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP) {
Harry Yangcdad2bf2016-10-04 17:03:56 -07003514 rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat);
3515 if (rc < 0) {
3516 smblib_err(chg,
3517 "Couldn't read QC_CHANGE_STATUS rc=%d\n", rc);
3518 return;
3519 }
3520
3521 switch (stat & QC_2P0_STATUS_MASK) {
3522 case QC_5V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303523 smblib_set_opt_freq_buck(chg,
3524 chg->chg_freq.freq_5V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003525 break;
3526 case QC_9V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303527 smblib_set_opt_freq_buck(chg,
3528 chg->chg_freq.freq_9V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003529 break;
3530 case QC_12V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303531 smblib_set_opt_freq_buck(chg,
3532 chg->chg_freq.freq_12V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003533 break;
3534 default:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303535 smblib_set_opt_freq_buck(chg,
3536 chg->chg_freq.freq_removal);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003537 break;
3538 }
3539 }
3540
Fenglin Wu80826e02017-04-25 21:45:08 +08003541 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP_3) {
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +05303542 rc = smblib_get_pulse_cnt(chg, &pulses);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003543 if (rc < 0) {
3544 smblib_err(chg,
3545 "Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
3546 return;
3547 }
Harry Yangcdad2bf2016-10-04 17:03:56 -07003548
3549 if (pulses < QC3_PULSES_FOR_6V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303550 smblib_set_opt_freq_buck(chg,
3551 chg->chg_freq.freq_5V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003552 else if (pulses < QC3_PULSES_FOR_9V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303553 smblib_set_opt_freq_buck(chg,
3554 chg->chg_freq.freq_6V_8V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003555 else if (pulses < QC3_PULSES_FOR_12V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303556 smblib_set_opt_freq_buck(chg,
3557 chg->chg_freq.freq_9V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003558 else
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303559 smblib_set_opt_freq_buck(chg,
3560 chg->chg_freq.freq_12V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003561 }
3562}
3563
Nicholas Troast34db5032016-03-28 12:26:44 -07003564/* triggers when HVDCP 3.0 authentication has finished */
3565static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
3566 bool rising)
3567{
3568 const struct apsd_result *apsd_result;
Harry Yangcdad2bf2016-10-04 17:03:56 -07003569 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07003570
3571 if (!rising)
3572 return;
3573
Ashay Jaiswal67ec7072017-02-16 14:14:58 +05303574 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
3575 /*
3576 * Disable AUTH_IRQ_EN_CFG_BIT to receive adapter voltage
3577 * change interrupt.
3578 */
3579 rc = smblib_masked_write(chg,
3580 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
3581 AUTH_IRQ_EN_CFG_BIT, 0);
3582 if (rc < 0)
3583 smblib_err(chg,
3584 "Couldn't enable QC auth setting rc=%d\n", rc);
3585 }
Harry Yangcdad2bf2016-10-04 17:03:56 -07003586
Harry Yangaba1f5f2016-09-28 10:47:29 -07003587 if (chg->mode == PARALLEL_MASTER)
3588 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0);
3589
Ashay Jaiswalac854862017-03-06 23:58:55 +05303590 /* the APSD done handler will set the USB supply type */
3591 apsd_result = smblib_get_apsd_result(chg);
Ashay Jaiswalac854862017-03-06 23:58:55 +05303592
Nicholas Troast34db5032016-03-28 12:26:44 -07003593 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n",
3594 apsd_result->name);
3595}
3596
Harry Yang1369b7a2016-09-27 15:59:50 -07003597static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
3598 bool rising, bool qc_charger)
3599{
Ashay Jaiswal7b6eb962017-04-26 14:34:29 +05303600 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05303601
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003602 /* Hold off PD only until hvdcp 2.0 detection timeout */
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003603 if (rising) {
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003604 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003605 false, 0);
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -08003606
Harry Yang4bf7d962017-03-13 16:51:43 -07003607 /* enable HDC and ICL irq for QC2/3 charger */
3608 if (qc_charger)
3609 vote(chg->usb_irq_enable_votable, QC_VOTER, true, 0);
3610
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -08003611 /*
3612 * HVDCP detection timeout done
3613 * If adapter is not QC2.0/QC3.0 - it is a plain old DCP.
3614 */
3615 if (!qc_charger && (apsd_result->bit & DCP_CHARGER_BIT))
3616 /* enforce DCP ICL if specified */
3617 vote(chg->usb_icl_votable, DCP_VOTER,
3618 chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua);
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07003619
3620 /*
3621 * if pd is not allowed, then set pd_active = false right here,
3622 * so that it starts the hvdcp engine
3623 */
3624 if (!get_effective_result(chg->pd_allowed_votable))
3625 __smblib_set_prop_pd_active(chg, 0);
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003626 }
Harry Yang1369b7a2016-09-27 15:59:50 -07003627
3628 smblib_dbg(chg, PR_INTERRUPT, "IRQ: smblib_handle_hvdcp_check_timeout %s\n",
3629 rising ? "rising" : "falling");
3630}
3631
Nicholas Troast34db5032016-03-28 12:26:44 -07003632/* triggers when HVDCP is detected */
3633static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg,
3634 bool rising)
3635{
3636 if (!rising)
3637 return;
3638
3639 /* the APSD done handler will set the USB supply type */
3640 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
3641 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-detect-done %s\n",
3642 rising ? "rising" : "falling");
3643}
3644
Nicholas Troastf9e44992017-03-14 09:06:56 -07003645static void smblib_force_legacy_icl(struct smb_charger *chg, int pst)
3646{
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303647 int typec_mode;
3648 int rp_ua;
3649
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003650 /* while PD is active it should have complete ICL control */
3651 if (chg->pd_active)
3652 return;
3653
Nicholas Troastf9e44992017-03-14 09:06:56 -07003654 switch (pst) {
3655 case POWER_SUPPLY_TYPE_USB:
3656 /*
3657 * USB_PSY will vote to increase the current to 500/900mA once
3658 * enumeration is done. Ensure that USB_PSY has at least voted
3659 * for 100mA before releasing the LEGACY_UNKNOWN vote
3660 */
3661 if (!is_client_vote_enabled(chg->usb_icl_votable,
3662 USB_PSY_VOTER))
3663 vote(chg->usb_icl_votable, USB_PSY_VOTER, true, 100000);
3664 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
3665 break;
3666 case POWER_SUPPLY_TYPE_USB_CDP:
3667 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1500000);
3668 break;
3669 case POWER_SUPPLY_TYPE_USB_DCP:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303670 typec_mode = smblib_get_prop_typec_mode(chg);
3671 rp_ua = get_rp_based_dcp_current(chg, typec_mode);
3672 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua);
Nicholas Troastf9e44992017-03-14 09:06:56 -07003673 break;
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05303674 case POWER_SUPPLY_TYPE_USB_FLOAT:
3675 /*
3676 * limit ICL to 100mA, the USB driver will enumerate to check
3677 * if this is a SDP and appropriately set the current
3678 */
3679 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
3680 break;
Nicholas Troastf9e44992017-03-14 09:06:56 -07003681 case POWER_SUPPLY_TYPE_USB_HVDCP:
3682 case POWER_SUPPLY_TYPE_USB_HVDCP_3:
3683 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 3000000);
3684 break;
3685 default:
3686 smblib_err(chg, "Unknown APSD %d; forcing 500mA\n", pst);
3687 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 500000);
3688 break;
3689 }
3690}
3691
Ankit Sharmade321e12017-09-01 20:17:45 +05303692static void smblib_notify_extcon_props(struct smb_charger *chg, int id)
3693{
3694 union extcon_property_value val;
3695 union power_supply_propval prop_val;
3696
3697 smblib_get_prop_typec_cc_orientation(chg, &prop_val);
3698 val.intval = ((prop_val.intval == 2) ? 1 : 0);
3699 extcon_set_property(chg->extcon, id,
3700 EXTCON_PROP_USB_TYPEC_POLARITY, val);
3701
3702 val.intval = true;
3703 extcon_set_property(chg->extcon, id,
3704 EXTCON_PROP_USB_SS, val);
3705}
3706
3707static void smblib_notify_device_mode(struct smb_charger *chg, bool enable)
3708{
3709 if (enable)
3710 smblib_notify_extcon_props(chg, EXTCON_USB);
3711
3712 extcon_set_state_sync(chg->extcon, EXTCON_USB, enable);
3713}
3714
3715static void smblib_notify_usb_host(struct smb_charger *chg, bool enable)
3716{
3717 if (enable)
3718 smblib_notify_extcon_props(chg, EXTCON_USB_HOST);
3719
3720 extcon_set_state_sync(chg->extcon, EXTCON_USB_HOST, enable);
3721}
3722
Nicholas Troast34db5032016-03-28 12:26:44 -07003723#define HVDCP_DET_MS 2500
3724static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
3725{
Nicholas Troast34db5032016-03-28 12:26:44 -07003726 const struct apsd_result *apsd_result;
3727
3728 if (!rising)
3729 return;
3730
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07003731 apsd_result = smblib_update_usb_type(chg);
Nicholas Troastf9e44992017-03-14 09:06:56 -07003732
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003733 if (!chg->typec_legacy_valid)
Nicholas Troastf9e44992017-03-14 09:06:56 -07003734 smblib_force_legacy_icl(chg, apsd_result->pst);
3735
Nicholas Troast34db5032016-03-28 12:26:44 -07003736 switch (apsd_result->bit) {
3737 case SDP_CHARGER_BIT:
3738 case CDP_CHARGER_BIT:
Ashay Jaiswal0ce2c7c2017-11-14 12:29:02 +05303739 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05303740 extcon_set_cable_state_(chg->extcon, EXTCON_USB,
3741 true);
Abhijeet Dharmapurikarbb9505f2017-03-22 18:31:28 -07003742 /* if not DCP then no hvdcp timeout happens. Enable pd here */
3743 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3744 false, 0);
Ankit Sharmade321e12017-09-01 20:17:45 +05303745 if (chg->use_extcon)
3746 smblib_notify_device_mode(chg, true);
Abhijeet Dharmapurikarbb9505f2017-03-22 18:31:28 -07003747 break;
Nicholas Troast34db5032016-03-28 12:26:44 -07003748 case OCP_CHARGER_BIT:
3749 case FLOAT_CHARGER_BIT:
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303750 /* if not DCP then no hvdcp timeout happens, Enable pd here. */
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003751 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3752 false, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07003753 break;
3754 case DCP_CHARGER_BIT:
Harry Yang1369b7a2016-09-27 15:59:50 -07003755 if (chg->wa_flags & QC_CHARGER_DETECTION_WA_BIT)
3756 schedule_delayed_work(&chg->hvdcp_detect_work,
3757 msecs_to_jiffies(HVDCP_DET_MS));
Nicholas Troast34db5032016-03-28 12:26:44 -07003758 break;
3759 default:
3760 break;
3761 }
3762
Nicholas Troast34db5032016-03-28 12:26:44 -07003763 smblib_dbg(chg, PR_INTERRUPT, "IRQ: apsd-done rising; %s detected\n",
3764 apsd_result->name);
3765}
3766
3767irqreturn_t smblib_handle_usb_source_change(int irq, void *data)
3768{
3769 struct smb_irq_data *irq_data = data;
3770 struct smb_charger *chg = irq_data->parent_data;
3771 int rc = 0;
3772 u8 stat;
3773
3774 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
3775 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003776 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07003777 return IRQ_HANDLED;
3778 }
3779 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
3780
Ashay Jaiswal0ce2c7c2017-11-14 12:29:02 +05303781 if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
3782 && (stat & APSD_DTC_STATUS_DONE_BIT)
Ashay Jaiswal8507aa52017-04-14 09:42:32 +05303783 && !chg->uusb_apsd_rerun_done) {
3784 /*
3785 * Force re-run APSD to handle slow insertion related
3786 * charger-mis-detection.
3787 */
3788 chg->uusb_apsd_rerun_done = true;
3789 smblib_rerun_apsd(chg);
3790 return IRQ_HANDLED;
3791 }
3792
Nicholas Troast34db5032016-03-28 12:26:44 -07003793 smblib_handle_apsd_done(chg,
3794 (bool)(stat & APSD_DTC_STATUS_DONE_BIT));
3795
3796 smblib_handle_hvdcp_detect_done(chg,
3797 (bool)(stat & QC_CHARGER_BIT));
3798
Harry Yang1369b7a2016-09-27 15:59:50 -07003799 smblib_handle_hvdcp_check_timeout(chg,
3800 (bool)(stat & HVDCP_CHECK_TIMEOUT_BIT),
3801 (bool)(stat & QC_CHARGER_BIT));
3802
Nicholas Troast34db5032016-03-28 12:26:44 -07003803 smblib_handle_hvdcp_3p0_auth_done(chg,
3804 (bool)(stat & QC_AUTH_DONE_STATUS_BIT));
3805
Nicholas Troast34db5032016-03-28 12:26:44 -07003806 smblib_handle_sdp_enumeration_done(chg,
3807 (bool)(stat & ENUMERATION_DONE_BIT));
3808
3809 smblib_handle_slow_plugin_timeout(chg,
3810 (bool)(stat & SLOW_PLUGIN_TIMEOUT_BIT));
3811
Harry Yangcdad2bf2016-10-04 17:03:56 -07003812 smblib_hvdcp_adaptive_voltage_change(chg);
3813
Nicholas Troast34db5032016-03-28 12:26:44 -07003814 power_supply_changed(chg->usb_psy);
3815
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08003816 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
3817 if (rc < 0) {
3818 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
3819 return IRQ_HANDLED;
3820 }
3821 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
3822
Nicholas Troast34db5032016-03-28 12:26:44 -07003823 return IRQ_HANDLED;
3824}
3825
Harry Yang29f23822017-09-09 00:09:36 -07003826static int typec_try_sink(struct smb_charger *chg)
3827{
3828 union power_supply_propval val;
3829 bool debounce_done, vbus_detected, sink;
3830 u8 stat;
3831 int exit_mode = ATTACHED_SRC, rc;
Abhijeet Dharmapurikarb0eb10d2017-11-13 18:42:40 -08003832 int typec_mode;
3833
3834 if (!(*chg->try_sink_enabled))
3835 return ATTACHED_SRC;
3836
3837 typec_mode = smblib_get_prop_typec_mode(chg);
3838 if (typec_mode == POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER
3839 || typec_mode == POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY)
3840 return ATTACHED_SRC;
3841
3842 /*
3843 * Try.SNK entry status - ATTACHWAIT.SRC state and detected Rd-open
3844 * or RD-Ra for TccDebounce time.
3845 */
Harry Yang29f23822017-09-09 00:09:36 -07003846
3847 /* ignore typec interrupt while try.snk WIP */
3848 chg->try_sink_active = true;
3849
3850 /* force SNK mode */
3851 val.intval = POWER_SUPPLY_TYPEC_PR_SINK;
3852 rc = smblib_set_prop_typec_power_role(chg, &val);
3853 if (rc < 0) {
3854 smblib_err(chg, "Couldn't set UFP mode rc=%d\n", rc);
3855 goto try_sink_exit;
3856 }
3857
3858 /* reduce Tccdebounce time to ~20ms */
3859 rc = smblib_masked_write(chg, MISC_CFG_REG,
3860 TCC_DEBOUNCE_20MS_BIT, TCC_DEBOUNCE_20MS_BIT);
3861 if (rc < 0) {
3862 smblib_err(chg, "Couldn't set MISC_CFG_REG rc=%d\n", rc);
3863 goto try_sink_exit;
3864 }
3865
3866 /*
3867 * give opportunity to the other side to be a SRC,
3868 * for tDRPTRY + Tccdebounce time
3869 */
Harry Yang692cec42017-10-16 16:21:19 -07003870 msleep(120);
Harry Yang29f23822017-09-09 00:09:36 -07003871
3872 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
3873 if (rc < 0) {
3874 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
3875 rc);
3876 goto try_sink_exit;
3877 }
3878
3879 debounce_done = stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT;
3880
3881 if (!debounce_done)
3882 /*
3883 * The other side didn't switch to source, either it
3884 * is an adamant sink or is removed go back to showing Rp
3885 */
3886 goto try_wait_src;
3887
3888 /*
3889 * We are in force sink mode and the other side has switched to
3890 * showing Rp. Config DRP in case the other side removes Rp so we
3891 * can quickly (20ms) switch to showing our Rp. Note that the spec
3892 * needs us to show Rp for 80mS while the drp DFP residency is just
3893 * 54mS. But 54mS is plenty time for us to react and force Rp for
3894 * the remaining 26mS.
3895 */
3896 val.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
3897 rc = smblib_set_prop_typec_power_role(chg, &val);
3898 if (rc < 0) {
3899 smblib_err(chg, "Couldn't set DFP mode rc=%d\n",
3900 rc);
3901 goto try_sink_exit;
3902 }
3903
3904 /*
3905 * while other side is Rp, wait for VBUS from it; exit if other side
3906 * removes Rp
3907 */
3908 do {
3909 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
3910 if (rc < 0) {
3911 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
3912 rc);
3913 goto try_sink_exit;
3914 }
3915
3916 debounce_done = stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT;
3917 vbus_detected = stat & TYPEC_VBUS_STATUS_BIT;
3918
3919 /* Successfully transitioned to ATTACHED.SNK */
3920 if (vbus_detected && debounce_done) {
3921 exit_mode = ATTACHED_SINK;
3922 goto try_sink_exit;
3923 }
3924
3925 /*
3926 * Ensure sink since drp may put us in source if other
3927 * side switches back to Rd
3928 */
3929 sink = !(stat & UFP_DFP_MODE_STATUS_BIT);
3930
3931 usleep_range(1000, 2000);
3932 } while (debounce_done && sink);
3933
3934try_wait_src:
3935 /*
3936 * Transition to trywait.SRC state. check if other side still wants
3937 * to be SNK or has been removed.
3938 */
3939 val.intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
3940 rc = smblib_set_prop_typec_power_role(chg, &val);
3941 if (rc < 0) {
3942 smblib_err(chg, "Couldn't set UFP mode rc=%d\n", rc);
3943 goto try_sink_exit;
3944 }
3945
3946 /* Need to be in this state for tDRPTRY time, 75ms~150ms */
3947 msleep(80);
3948
3949 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
3950 if (rc < 0) {
3951 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
3952 goto try_sink_exit;
3953 }
3954
3955 debounce_done = stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT;
3956
3957 if (debounce_done)
3958 /* the other side wants to be a sink */
3959 exit_mode = ATTACHED_SRC;
3960 else
3961 /* the other side is detached */
3962 exit_mode = UNATTACHED_SINK;
3963
3964try_sink_exit:
3965 /* release forcing of SRC/SNK mode */
3966 val.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
3967 rc = smblib_set_prop_typec_power_role(chg, &val);
3968 if (rc < 0)
3969 smblib_err(chg, "Couldn't set DFP mode rc=%d\n", rc);
3970
3971 /* revert Tccdebounce time back to ~120ms */
3972 rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT, 0);
3973 if (rc < 0)
3974 smblib_err(chg, "Couldn't set MISC_CFG_REG rc=%d\n", rc);
3975
3976 chg->try_sink_active = false;
3977
3978 return exit_mode;
3979}
3980
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003981static void typec_sink_insertion(struct smb_charger *chg)
3982{
Harry Yang29f23822017-09-09 00:09:36 -07003983 int exit_mode;
Abhijeet Dharmapurikarb0eb10d2017-11-13 18:42:40 -08003984 int typec_mode;
Harry Yang29f23822017-09-09 00:09:36 -07003985
Abhijeet Dharmapurikarb0eb10d2017-11-13 18:42:40 -08003986 exit_mode = typec_try_sink(chg);
Harry Yang29f23822017-09-09 00:09:36 -07003987
Abhijeet Dharmapurikarb0eb10d2017-11-13 18:42:40 -08003988 if (exit_mode != ATTACHED_SRC) {
3989 smblib_usb_typec_change(chg);
3990 return;
Harry Yang29f23822017-09-09 00:09:36 -07003991 }
3992
Abhijeet Dharmapurikarb0eb10d2017-11-13 18:42:40 -08003993 typec_mode = smblib_get_prop_typec_mode(chg);
3994 if (typec_mode == POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER)
3995 chg->is_audio_adapter = true;
3996
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003997 /* when a sink is inserted we should not wait on hvdcp timeout to
3998 * enable pd
3999 */
4000 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
4001 false, 0);
Ankit Sharmade321e12017-09-01 20:17:45 +05304002 if (chg->use_extcon) {
4003 smblib_notify_usb_host(chg, true);
4004 chg->otg_present = true;
4005 }
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004006}
Nicholas Troast34db5032016-03-28 12:26:44 -07004007
Harry Yangd89ff1f2016-12-05 14:59:11 -08004008static void typec_sink_removal(struct smb_charger *chg)
4009{
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05304010 smblib_set_charge_param(chg, &chg->param.freq_boost,
4011 chg->chg_freq.freq_above_otg_threshold);
Harry Yangd89ff1f2016-12-05 14:59:11 -08004012 chg->boost_current_ua = 0;
4013}
4014
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004015static void smblib_handle_typec_removal(struct smb_charger *chg)
4016{
Nicholas Troastfe74c592017-03-14 09:20:55 -07004017 int rc;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304018 struct smb_irq_data *data;
4019 struct storm_watch *wdata;
Nicholas Troastfe74c592017-03-14 09:20:55 -07004020
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004021 chg->cc2_detach_wa_active = false;
4022
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05304023 rc = smblib_request_dpdm(chg, false);
4024 if (rc < 0)
4025 smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05304026
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304027 if (chg->wa_flags & BOOST_BACK_WA) {
4028 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
4029 if (data) {
4030 wdata = &data->storm_data;
4031 update_storm_count(wdata, WEAK_CHG_STORM_COUNT);
4032 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
4033 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
4034 false, 0);
4035 }
4036 }
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05304037
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004038 /* reset APSD voters */
4039 vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, false, 0);
4040 vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304041
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004042 cancel_delayed_work_sync(&chg->pl_enable_work);
4043 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
4044
4045 /* reset input current limit voters */
4046 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
4047 vote(chg->usb_icl_votable, PD_VOTER, false, 0);
4048 vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
4049 vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
4050 vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
Ashay Jaiswalae23a042017-05-18 15:28:31 +05304051 vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
Abhijeet Dharmapurikar66d2c442017-07-12 11:55:36 -07004052 vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
Harry Yangfeb95002017-10-06 12:11:42 -07004053 vote(chg->usb_icl_votable, CTM_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004054
4055 /* reset hvdcp voters */
4056 vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, true, 0);
4057 vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER, true, 0);
4058
4059 /* reset power delivery voters */
4060 vote(chg->pd_allowed_votable, PD_VOTER, false, 0);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004061 vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0);
4062 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER, true, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004063
4064 /* reset usb irq voters */
Harry Yang4bf7d962017-03-13 16:51:43 -07004065 vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
4066 vote(chg->usb_irq_enable_votable, QC_VOTER, false, 0);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004067
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004068 /* reset parallel voters */
4069 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
Abhijeet Dharmapurikar004f7ba2017-09-26 16:23:51 -07004070 vote(chg->pl_disable_votable, PL_FCC_LOW_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004071 vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
4072 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
4073 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
Harry Yang1d1034c2016-06-15 12:09:42 -07004074
Nicholas Troast8995a702016-12-05 10:22:22 -08004075 chg->vconn_attempts = 0;
4076 chg->otg_attempts = 0;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05304077 chg->pulse_cnt = 0;
4078 chg->usb_icl_delta_ua = 0;
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004079 chg->voltage_min_uv = MICRO_5V;
4080 chg->voltage_max_uv = MICRO_5V;
4081 chg->pd_active = 0;
4082 chg->pd_hard_reset = 0;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004083 chg->typec_legacy_valid = false;
Harry Yang3b113a52016-12-08 12:37:40 -08004084
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05304085 /* write back the default FLOAT charger configuration */
4086 rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
4087 (u8)FLOAT_OPTIONS_MASK, chg->float_cfg);
4088 if (rc < 0)
4089 smblib_err(chg, "Couldn't write float charger options rc=%d\n",
4090 rc);
4091
Abhijeet Dharmapurikar676bd792017-05-31 16:21:57 -07004092 /* reset back to 120mS tCC debounce */
4093 rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT, 0);
4094 if (rc < 0)
4095 smblib_err(chg, "Couldn't set 120mS tCC debounce rc=%d\n", rc);
4096
Nicholas Troastfe74c592017-03-14 09:20:55 -07004097 /* enable APSD CC trigger for next insertion */
4098 rc = smblib_masked_write(chg, TYPE_C_CFG_REG,
4099 APSD_START_ON_CC_BIT, APSD_START_ON_CC_BIT);
4100 if (rc < 0)
4101 smblib_err(chg, "Couldn't enable APSD_START_ON_CC rc=%d\n", rc);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08004102
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004103 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
4104 /* re-enable AUTH_IRQ_EN_CFG_BIT */
4105 rc = smblib_masked_write(chg,
4106 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
4107 AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
4108 if (rc < 0)
4109 smblib_err(chg,
4110 "Couldn't enable QC auth setting rc=%d\n", rc);
4111 }
4112
4113 /* reconfigure allowed voltage for HVDCP */
4114 rc = smblib_set_adapter_allowance(chg,
4115 USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
4116 if (rc < 0)
4117 smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
4118 rc);
4119
Abhijeet Dharmapurikarb0eb10d2017-11-13 18:42:40 -08004120 if (chg->is_audio_adapter == true)
4121 /* wait for the audio driver to lower its en gpio */
4122 msleep(*chg->audio_headset_drp_wait_ms);
4123
4124 chg->is_audio_adapter = false;
4125
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004126 /* enable DRP */
4127 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4128 TYPEC_POWER_ROLE_CMD_MASK, 0);
4129 if (rc < 0)
4130 smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc);
4131
4132 /* HW controlled CC_OUT */
4133 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
4134 TYPEC_SPARE_CFG_BIT, 0);
4135 if (rc < 0)
4136 smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n", rc);
4137
4138 /* restore crude sensor */
4139 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
4140 if (rc < 0)
4141 smblib_err(chg, "Couldn't restore crude sensor rc=%d\n", rc);
4142
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004143 mutex_lock(&chg->vconn_oc_lock);
4144 if (!chg->vconn_en)
4145 goto unlock;
4146
4147 smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4148 VCONN_EN_VALUE_BIT, 0);
4149 chg->vconn_en = false;
4150
4151unlock:
4152 mutex_unlock(&chg->vconn_oc_lock);
4153
Abhijeet Dharmapurikar319d6942017-06-05 17:14:17 -07004154 /* clear exit sink based on cc */
4155 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4156 EXIT_SNK_BASED_ON_CC_BIT, 0);
4157 if (rc < 0)
4158 smblib_err(chg, "Couldn't clear exit_sink_based_on_cc rc=%d\n",
4159 rc);
4160
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08004161 typec_sink_removal(chg);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004162 smblib_update_usb_type(chg);
Ankit Sharmade321e12017-09-01 20:17:45 +05304163
4164 if (chg->use_extcon) {
4165 if (chg->otg_present)
4166 smblib_notify_usb_host(chg, false);
4167 else
4168 smblib_notify_device_mode(chg, false);
4169 }
4170 chg->otg_present = false;
Nicholas Troast34db5032016-03-28 12:26:44 -07004171}
4172
Nicholas Troaste1932e42017-04-12 12:38:18 -07004173static void smblib_handle_typec_insertion(struct smb_charger *chg)
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07004174{
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004175 int rc;
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07004176
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004177 vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, false, 0);
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07004178
Nicholas Troastfe74c592017-03-14 09:20:55 -07004179 /* disable APSD CC trigger since CC is attached */
4180 rc = smblib_masked_write(chg, TYPE_C_CFG_REG, APSD_START_ON_CC_BIT, 0);
4181 if (rc < 0)
4182 smblib_err(chg, "Couldn't disable APSD_START_ON_CC rc=%d\n",
4183 rc);
4184
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05304185 if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT) {
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004186 typec_sink_insertion(chg);
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05304187 } else {
4188 rc = smblib_request_dpdm(chg, true);
4189 if (rc < 0)
4190 smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
Harry Yangd89ff1f2016-12-05 14:59:11 -08004191 typec_sink_removal(chg);
Ashay Jaiswal13a1b812017-07-17 14:49:05 +05304192 }
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07004193}
4194
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05304195static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode)
4196{
4197 int rp_ua;
4198 const struct apsd_result *apsd = smblib_get_apsd_result(chg);
4199
4200 if ((apsd->pst != POWER_SUPPLY_TYPE_USB_DCP)
4201 && (apsd->pst != POWER_SUPPLY_TYPE_USB_FLOAT))
4202 return;
4203
4204 /*
Anirudh Ghayal1121f5d2017-07-26 20:26:20 +05304205 * if APSD indicates FLOAT and the USB stack had detected SDP,
4206 * do not respond to Rp changes as we do not confirm that its
4207 * a legacy cable
4208 */
4209 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
4210 return;
4211 /*
4212 * We want the ICL vote @ 100mA for a FLOAT charger
4213 * until the detection by the USB stack is complete.
4214 * Ignore the Rp changes unless there is a
4215 * pre-existing valid vote.
4216 */
4217 if (apsd->pst == POWER_SUPPLY_TYPE_USB_FLOAT &&
4218 get_client_vote(chg->usb_icl_votable,
4219 LEGACY_UNKNOWN_VOTER) <= 100000)
4220 return;
4221
4222 /*
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05304223 * handle Rp change for DCP/FLOAT/OCP.
4224 * Update the current only if the Rp is different from
4225 * the last Rp value.
4226 */
4227 smblib_dbg(chg, PR_MISC, "CC change old_mode=%d new_mode=%d\n",
4228 chg->typec_mode, typec_mode);
4229
4230 rp_ua = get_rp_based_dcp_current(chg, typec_mode);
4231 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua);
4232}
4233
Nicholas Troaste1932e42017-04-12 12:38:18 -07004234static void smblib_handle_typec_cc_state_change(struct smb_charger *chg)
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004235{
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05304236 int typec_mode;
4237
Nicholas Troaste1932e42017-04-12 12:38:18 -07004238 if (chg->pr_swap_in_progress)
4239 return;
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004240
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05304241 typec_mode = smblib_get_prop_typec_mode(chg);
4242 if (chg->typec_present && (typec_mode != chg->typec_mode))
4243 smblib_handle_rp_change(chg, typec_mode);
4244
4245 chg->typec_mode = typec_mode;
4246
Nicholas Troaste1932e42017-04-12 12:38:18 -07004247 if (!chg->typec_present && chg->typec_mode != POWER_SUPPLY_TYPEC_NONE) {
4248 chg->typec_present = true;
4249 smblib_dbg(chg, PR_MISC, "TypeC %s insertion\n",
4250 smblib_typec_mode_name[chg->typec_mode]);
4251 smblib_handle_typec_insertion(chg);
4252 } else if (chg->typec_present &&
4253 chg->typec_mode == POWER_SUPPLY_TYPEC_NONE) {
4254 chg->typec_present = false;
4255 smblib_dbg(chg, PR_MISC, "TypeC removal\n");
4256 smblib_handle_typec_removal(chg);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07004257 }
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004258
Abhijeet Dharmapurikar66d2c442017-07-12 11:55:36 -07004259 /* suspend usb if sink */
Harry Yangca0664e2017-08-18 11:40:06 -07004260 if ((chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
4261 && chg->typec_present)
Abhijeet Dharmapurikar66d2c442017-07-12 11:55:36 -07004262 vote(chg->usb_icl_votable, OTG_VOTER, true, 0);
4263 else
4264 vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
4265
Nicholas Troaste1932e42017-04-12 12:38:18 -07004266 smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n",
4267 smblib_typec_mode_name[chg->typec_mode]);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07004268}
4269
Harry Yang29f23822017-09-09 00:09:36 -07004270void smblib_usb_typec_change(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07004271{
Nicholas Troast34db5032016-03-28 12:26:44 -07004272 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07004273
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07004274 rc = smblib_multibyte_read(chg, TYPE_C_STATUS_1_REG,
4275 chg->typec_status, 5);
Nicholas Troast34db5032016-03-28 12:26:44 -07004276 if (rc < 0) {
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07004277 smblib_err(chg, "Couldn't cache USB Type-C status rc=%d\n", rc);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004278 return;
Nicholas Troast34db5032016-03-28 12:26:44 -07004279 }
Nicholas Troast34db5032016-03-28 12:26:44 -07004280
Nicholas Troaste1932e42017-04-12 12:38:18 -07004281 smblib_handle_typec_cc_state_change(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07004282
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07004283 if (chg->typec_status[3] & TYPEC_VBUS_ERROR_STATUS_BIT)
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004284 smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n");
Harry Yangd757c0f2016-09-23 10:52:05 -07004285
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07004286 if (chg->typec_status[3] & TYPEC_VCONN_OVERCURR_STATUS_BIT)
Nicholas Troastb11015f2017-01-17 17:56:45 -08004287 schedule_work(&chg->vconn_oc_work);
Nicholas Troast8995a702016-12-05 10:22:22 -08004288
Nicholas Troastb1486552016-11-10 08:20:11 -08004289 power_supply_changed(chg->usb_psy);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004290}
4291
4292irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
4293{
4294 struct smb_irq_data *irq_data = data;
4295 struct smb_charger *chg = irq_data->parent_data;
4296
Ashay Jaiswal0ce2c7c2017-11-14 12:29:02 +05304297 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) {
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05304298 cancel_delayed_work_sync(&chg->uusb_otg_work);
4299 vote(chg->awake_votable, OTG_DELAY_VOTER, true, 0);
4300 smblib_dbg(chg, PR_INTERRUPT, "Scheduling OTG work\n");
4301 schedule_delayed_work(&chg->uusb_otg_work,
4302 msecs_to_jiffies(chg->otg_delay_ms));
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004303 return IRQ_HANDLED;
4304 }
4305
Harry Yang29f23822017-09-09 00:09:36 -07004306 if (chg->cc2_detach_wa_active || chg->typec_en_dis_active ||
4307 chg->try_sink_active) {
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07004308 smblib_dbg(chg, PR_MISC | PR_INTERRUPT, "Ignoring since %s active\n",
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004309 chg->cc2_detach_wa_active ?
4310 "cc2_detach_wa" : "typec_en_dis");
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004311 return IRQ_HANDLED;
4312 }
4313
Abhijeet Dharmapurikar049b2552017-07-12 11:27:51 -07004314 if (chg->pr_swap_in_progress) {
4315 smblib_dbg(chg, PR_INTERRUPT,
4316 "Ignoring since pr_swap_in_progress\n");
4317 return IRQ_HANDLED;
4318 }
4319
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004320 mutex_lock(&chg->lock);
4321 smblib_usb_typec_change(chg);
4322 mutex_unlock(&chg->lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07004323 return IRQ_HANDLED;
4324}
4325
Abhijeet Dharmapurikar23916642016-10-03 10:38:50 -07004326irqreturn_t smblib_handle_dc_plugin(int irq, void *data)
4327{
4328 struct smb_irq_data *irq_data = data;
4329 struct smb_charger *chg = irq_data->parent_data;
4330
4331 power_supply_changed(chg->dc_psy);
4332 return IRQ_HANDLED;
4333}
4334
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004335irqreturn_t smblib_handle_high_duty_cycle(int irq, void *data)
4336{
4337 struct smb_irq_data *irq_data = data;
4338 struct smb_charger *chg = irq_data->parent_data;
4339
4340 chg->is_hdc = true;
Fenglin Wu4f4dcc12017-08-24 14:28:54 +08004341 /*
4342 * Disable usb IRQs after the flag set and re-enable IRQs after
4343 * the flag cleared in the delayed work queue, to avoid any IRQ
4344 * storming during the delays
4345 */
4346 if (chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq)
4347 disable_irq_nosync(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
4348
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004349 schedule_delayed_work(&chg->clear_hdc_work, msecs_to_jiffies(60));
4350
4351 return IRQ_HANDLED;
4352}
4353
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05304354static void smblib_bb_removal_work(struct work_struct *work)
4355{
4356 struct smb_charger *chg = container_of(work, struct smb_charger,
4357 bb_removal_work.work);
4358
4359 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
4360 vote(chg->awake_votable, BOOST_BACK_VOTER, false, 0);
4361}
4362
4363#define BOOST_BACK_UNVOTE_DELAY_MS 750
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304364#define BOOST_BACK_STORM_COUNT 3
4365#define WEAK_CHG_STORM_COUNT 8
Nicholas Troastabedaf72016-09-16 11:07:45 -07004366irqreturn_t smblib_handle_switcher_power_ok(int irq, void *data)
4367{
4368 struct smb_irq_data *irq_data = data;
4369 struct smb_charger *chg = irq_data->parent_data;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304370 struct storm_watch *wdata = &irq_data->storm_data;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004371 int rc, usb_icl;
Nicholas Troastabedaf72016-09-16 11:07:45 -07004372 u8 stat;
4373
4374 if (!(chg->wa_flags & BOOST_BACK_WA))
4375 return IRQ_HANDLED;
4376
4377 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
4378 if (rc < 0) {
4379 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n", rc);
4380 return IRQ_HANDLED;
4381 }
4382
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004383 /* skip suspending input if its already suspended by some other voter */
4384 usb_icl = get_effective_result(chg->usb_icl_votable);
Harry Yang379484a2017-08-29 10:26:14 -07004385 if ((stat & USE_USBIN_BIT) && usb_icl >= 0 && usb_icl <= USBIN_25MA)
Nicholas Troastabedaf72016-09-16 11:07:45 -07004386 return IRQ_HANDLED;
4387
Abhijeet Dharmapurikar2823fe32016-12-05 17:52:11 -08004388 if (stat & USE_DCIN_BIT)
Nicholas Troastabedaf72016-09-16 11:07:45 -07004389 return IRQ_HANDLED;
4390
4391 if (is_storming(&irq_data->storm_data)) {
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304392 /* This could be a weak charger reduce ICL */
4393 if (!is_client_vote_enabled(chg->usb_icl_votable,
4394 WEAK_CHARGER_VOTER)) {
4395 smblib_err(chg,
4396 "Weak charger detected: voting %dmA ICL\n",
4397 *chg->weak_chg_icl_ua / 1000);
4398 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
4399 true, *chg->weak_chg_icl_ua);
4400 /*
4401 * reset storm data and set the storm threshold
4402 * to 3 for reverse boost detection.
4403 */
4404 update_storm_count(wdata, BOOST_BACK_STORM_COUNT);
4405 } else {
4406 smblib_err(chg,
4407 "Reverse boost detected: voting 0mA to suspend input\n");
4408 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, true, 0);
4409 vote(chg->awake_votable, BOOST_BACK_VOTER, true, 0);
4410 /*
4411 * Remove the boost-back vote after a delay, to avoid
4412 * permanently suspending the input if the boost-back
4413 * condition is unintentionally hit.
4414 */
4415 schedule_delayed_work(&chg->bb_removal_work,
4416 msecs_to_jiffies(BOOST_BACK_UNVOTE_DELAY_MS));
4417 }
Nicholas Troastabedaf72016-09-16 11:07:45 -07004418 }
4419
4420 return IRQ_HANDLED;
4421}
4422
Nicholas Troast15dc0c82016-10-18 15:15:21 -07004423irqreturn_t smblib_handle_wdog_bark(int irq, void *data)
4424{
4425 struct smb_irq_data *irq_data = data;
4426 struct smb_charger *chg = irq_data->parent_data;
4427 int rc;
4428
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05304429 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
4430
Nicholas Troast15dc0c82016-10-18 15:15:21 -07004431 rc = smblib_write(chg, BARK_BITE_WDOG_PET_REG, BARK_BITE_WDOG_PET_BIT);
4432 if (rc < 0)
4433 smblib_err(chg, "Couldn't pet the dog rc=%d\n", rc);
4434
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +05304435 if (chg->step_chg_enabled || chg->sw_jeita_enabled)
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05304436 power_supply_changed(chg->batt_psy);
4437
Nicholas Troast15dc0c82016-10-18 15:15:21 -07004438 return IRQ_HANDLED;
4439}
4440
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004441/**************
4442 * Additional USB PSY getters/setters
4443 * that call interrupt functions
4444 ***************/
4445
4446int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg,
4447 union power_supply_propval *val)
4448{
4449 val->intval = chg->pr_swap_in_progress;
4450 return 0;
4451}
4452
4453int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg,
4454 const union power_supply_propval *val)
4455{
Abhijeet Dharmapurikar676bd792017-05-31 16:21:57 -07004456 int rc;
4457
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004458 chg->pr_swap_in_progress = val->intval;
4459 /*
4460 * call the cc changed irq to handle real removals while
4461 * PR_SWAP was in progress
4462 */
4463 smblib_usb_typec_change(chg);
Abhijeet Dharmapurikar676bd792017-05-31 16:21:57 -07004464 rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT,
4465 val->intval ? TCC_DEBOUNCE_20MS_BIT : 0);
4466 if (rc < 0)
4467 smblib_err(chg, "Couldn't set tCC debounce rc=%d\n", rc);
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004468 return 0;
4469}
4470
Nicholas Troast34db5032016-03-28 12:26:44 -07004471/***************
4472 * Work Queues *
4473 ***************/
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05304474static void smblib_uusb_otg_work(struct work_struct *work)
4475{
4476 struct smb_charger *chg = container_of(work, struct smb_charger,
4477 uusb_otg_work.work);
4478 int rc;
4479 u8 stat;
4480 bool otg;
4481
4482 rc = smblib_read(chg, TYPE_C_STATUS_3_REG, &stat);
4483 if (rc < 0) {
4484 smblib_err(chg, "Couldn't read TYPE_C_STATUS_3 rc=%d\n", rc);
4485 goto out;
4486 }
4487
4488 otg = !!(stat & (U_USB_GND_NOVBUS_BIT | U_USB_GND_BIT));
4489 extcon_set_cable_state_(chg->extcon, EXTCON_USB_HOST, otg);
4490 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_3 = 0x%02x OTG=%d\n",
4491 stat, otg);
4492 power_supply_changed(chg->usb_psy);
4493
4494out:
4495 vote(chg->awake_votable, OTG_DELAY_VOTER, false, 0);
4496}
4497
Nicholas Troast34db5032016-03-28 12:26:44 -07004498
4499static void smblib_hvdcp_detect_work(struct work_struct *work)
4500{
4501 struct smb_charger *chg = container_of(work, struct smb_charger,
4502 hvdcp_detect_work.work);
Nicholas Troast34db5032016-03-28 12:26:44 -07004503
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07004504 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
4505 false, 0);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004506 power_supply_changed(chg->usb_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07004507}
4508
Harry Yangfe913842016-08-10 12:27:28 -07004509static void bms_update_work(struct work_struct *work)
Harry Yang5e1a5222016-07-26 15:16:04 -07004510{
4511 struct smb_charger *chg = container_of(work, struct smb_charger,
4512 bms_update_work);
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05304513
4514 smblib_suspend_on_debug_battery(chg);
4515
4516 if (chg->batt_psy)
4517 power_supply_changed(chg->batt_psy);
Harry Yang5e1a5222016-07-26 15:16:04 -07004518}
4519
Harry Yang166b15d2017-08-28 13:00:40 -07004520static void pl_update_work(struct work_struct *work)
4521{
4522 struct smb_charger *chg = container_of(work, struct smb_charger,
4523 pl_update_work);
4524
4525 smblib_stat_sw_override_cfg(chg, false);
4526}
4527
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004528static void clear_hdc_work(struct work_struct *work)
4529{
4530 struct smb_charger *chg = container_of(work, struct smb_charger,
4531 clear_hdc_work.work);
4532
4533 chg->is_hdc = 0;
Fenglin Wu4f4dcc12017-08-24 14:28:54 +08004534 if (chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq)
4535 enable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004536}
4537
Harry Yang755a34b2016-11-01 01:18:51 -07004538static void rdstd_cc2_detach_work(struct work_struct *work)
4539{
4540 int rc;
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004541 u8 stat4, stat5;
Harry Yang755a34b2016-11-01 01:18:51 -07004542 struct smb_charger *chg = container_of(work, struct smb_charger,
4543 rdstd_cc2_detach_work);
4544
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004545 if (!chg->cc2_detach_wa_active)
4546 return;
4547
Harry Yang755a34b2016-11-01 01:18:51 -07004548 /*
4549 * WA steps -
4550 * 1. Enable both UFP and DFP, wait for 10ms.
4551 * 2. Disable DFP, wait for 30ms.
4552 * 3. Removal detected if both TYPEC_DEBOUNCE_DONE_STATUS
4553 * and TIMER_STAGE bits are gone, otherwise repeat all by
4554 * work rescheduling.
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004555 * Note, work will be cancelled when USB_PLUGIN rises.
Harry Yang755a34b2016-11-01 01:18:51 -07004556 */
4557
4558 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4559 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT,
4560 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT);
4561 if (rc < 0) {
4562 smblib_err(chg, "Couldn't write TYPE_C_CTRL_REG rc=%d\n", rc);
4563 return;
4564 }
4565
4566 usleep_range(10000, 11000);
4567
4568 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4569 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT,
4570 UFP_EN_CMD_BIT);
4571 if (rc < 0) {
4572 smblib_err(chg, "Couldn't write TYPE_C_CTRL_REG rc=%d\n", rc);
4573 return;
4574 }
4575
4576 usleep_range(30000, 31000);
4577
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004578 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
Harry Yang755a34b2016-11-01 01:18:51 -07004579 if (rc < 0) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004580 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
Harry Yang755a34b2016-11-01 01:18:51 -07004581 return;
4582 }
Harry Yang755a34b2016-11-01 01:18:51 -07004583
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004584 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
Harry Yang755a34b2016-11-01 01:18:51 -07004585 if (rc < 0) {
4586 smblib_err(chg,
4587 "Couldn't read TYPE_C_STATUS_5_REG rc=%d\n", rc);
4588 return;
4589 }
Harry Yang755a34b2016-11-01 01:18:51 -07004590
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004591 if ((stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT)
4592 || (stat5 & TIMER_STAGE_2_BIT)) {
4593 smblib_dbg(chg, PR_MISC, "rerunning DD=%d TS2BIT=%d\n",
4594 (int)(stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT),
4595 (int)(stat5 & TIMER_STAGE_2_BIT));
4596 goto rerun;
4597 }
4598
4599 smblib_dbg(chg, PR_MISC, "Bingo CC2 Removal detected\n");
4600 chg->cc2_detach_wa_active = false;
4601 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4602 EXIT_SNK_BASED_ON_CC_BIT, 0);
Harry Yang755a34b2016-11-01 01:18:51 -07004603 smblib_reg_block_restore(chg, cc2_detach_settings);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004604 mutex_lock(&chg->lock);
4605 smblib_usb_typec_change(chg);
4606 mutex_unlock(&chg->lock);
Harry Yang755a34b2016-11-01 01:18:51 -07004607 return;
4608
4609rerun:
4610 schedule_work(&chg->rdstd_cc2_detach_work);
4611}
4612
Nicholas Troastb11015f2017-01-17 17:56:45 -08004613static void smblib_otg_oc_exit(struct smb_charger *chg, bool success)
4614{
4615 int rc;
4616
4617 chg->otg_attempts = 0;
4618 if (!success) {
4619 smblib_err(chg, "OTG soft start failed\n");
4620 chg->otg_en = false;
4621 }
4622
4623 smblib_dbg(chg, PR_OTG, "enabling VBUS < 1V check\n");
4624 rc = smblib_masked_write(chg, OTG_CFG_REG,
4625 QUICKSTART_OTG_FASTROLESWAP_BIT, 0);
4626 if (rc < 0)
4627 smblib_err(chg, "Couldn't enable VBUS < 1V check rc=%d\n", rc);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004628}
4629
4630#define MAX_OC_FALLING_TRIES 10
4631static void smblib_otg_oc_work(struct work_struct *work)
4632{
4633 struct smb_charger *chg = container_of(work, struct smb_charger,
4634 otg_oc_work);
4635 int rc, i;
4636 u8 stat;
4637
4638 if (!chg->vbus_vreg || !chg->vbus_vreg->rdev)
4639 return;
4640
4641 smblib_err(chg, "over-current detected on VBUS\n");
4642 mutex_lock(&chg->otg_oc_lock);
4643 if (!chg->otg_en)
4644 goto unlock;
4645
4646 smblib_dbg(chg, PR_OTG, "disabling VBUS < 1V check\n");
4647 smblib_masked_write(chg, OTG_CFG_REG,
4648 QUICKSTART_OTG_FASTROLESWAP_BIT,
4649 QUICKSTART_OTG_FASTROLESWAP_BIT);
4650
4651 /*
4652 * If 500ms has passed and another over-current interrupt has not
4653 * triggered then it is likely that the software based soft start was
4654 * successful and the VBUS < 1V restriction should be re-enabled.
4655 */
4656 schedule_delayed_work(&chg->otg_ss_done_work, msecs_to_jiffies(500));
4657
4658 rc = _smblib_vbus_regulator_disable(chg->vbus_vreg->rdev);
4659 if (rc < 0) {
4660 smblib_err(chg, "Couldn't disable VBUS rc=%d\n", rc);
4661 goto unlock;
4662 }
4663
4664 if (++chg->otg_attempts > OTG_MAX_ATTEMPTS) {
4665 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4666 smblib_err(chg, "OTG failed to enable after %d attempts\n",
4667 chg->otg_attempts - 1);
4668 smblib_otg_oc_exit(chg, false);
4669 goto unlock;
4670 }
4671
4672 /*
4673 * The real time status should go low within 10ms. Poll every 1-2ms to
4674 * minimize the delay when re-enabling OTG.
4675 */
4676 for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) {
4677 usleep_range(1000, 2000);
4678 rc = smblib_read(chg, OTG_BASE + INT_RT_STS_OFFSET, &stat);
4679 if (rc >= 0 && !(stat & OTG_OVERCURRENT_RT_STS_BIT))
4680 break;
4681 }
4682
4683 if (i >= MAX_OC_FALLING_TRIES) {
4684 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4685 smblib_err(chg, "OTG OC did not fall after %dms\n",
4686 2 * MAX_OC_FALLING_TRIES);
4687 smblib_otg_oc_exit(chg, false);
4688 goto unlock;
4689 }
4690
4691 smblib_dbg(chg, PR_OTG, "OTG OC fell after %dms\n", 2 * i + 1);
4692 rc = _smblib_vbus_regulator_enable(chg->vbus_vreg->rdev);
4693 if (rc < 0) {
4694 smblib_err(chg, "Couldn't enable VBUS rc=%d\n", rc);
4695 goto unlock;
4696 }
4697
4698unlock:
4699 mutex_unlock(&chg->otg_oc_lock);
4700}
4701
4702static void smblib_vconn_oc_work(struct work_struct *work)
4703{
4704 struct smb_charger *chg = container_of(work, struct smb_charger,
4705 vconn_oc_work);
4706 int rc, i;
4707 u8 stat;
4708
Ashay Jaiswal0ce2c7c2017-11-14 12:29:02 +05304709 if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
Ashay Jaiswal15edce42017-03-31 23:29:58 +05304710 return;
4711
Nicholas Troastb11015f2017-01-17 17:56:45 -08004712 smblib_err(chg, "over-current detected on VCONN\n");
4713 if (!chg->vconn_vreg || !chg->vconn_vreg->rdev)
4714 return;
4715
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07004716 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004717 rc = _smblib_vconn_regulator_disable(chg->vconn_vreg->rdev);
4718 if (rc < 0) {
4719 smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc);
4720 goto unlock;
4721 }
4722
4723 if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
4724 smblib_err(chg, "VCONN failed to enable after %d attempts\n",
4725 chg->otg_attempts - 1);
4726 chg->vconn_en = false;
4727 chg->vconn_attempts = 0;
4728 goto unlock;
4729 }
4730
4731 /*
4732 * The real time status should go low within 10ms. Poll every 1-2ms to
4733 * minimize the delay when re-enabling OTG.
4734 */
4735 for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) {
4736 usleep_range(1000, 2000);
4737 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
4738 if (rc >= 0 && !(stat & TYPEC_VCONN_OVERCURR_STATUS_BIT))
4739 break;
4740 }
4741
4742 if (i >= MAX_OC_FALLING_TRIES) {
4743 smblib_err(chg, "VCONN OC did not fall after %dms\n",
4744 2 * MAX_OC_FALLING_TRIES);
4745 chg->vconn_en = false;
4746 chg->vconn_attempts = 0;
4747 goto unlock;
4748 }
4749
4750 smblib_dbg(chg, PR_OTG, "VCONN OC fell after %dms\n", 2 * i + 1);
4751 if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
4752 smblib_err(chg, "VCONN failed to enable after %d attempts\n",
4753 chg->vconn_attempts - 1);
4754 chg->vconn_en = false;
4755 goto unlock;
4756 }
4757
4758 rc = _smblib_vconn_regulator_enable(chg->vconn_vreg->rdev);
4759 if (rc < 0) {
4760 smblib_err(chg, "Couldn't enable VCONN rc=%d\n", rc);
4761 goto unlock;
4762 }
4763
4764unlock:
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07004765 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004766}
4767
4768static void smblib_otg_ss_done_work(struct work_struct *work)
4769{
4770 struct smb_charger *chg = container_of(work, struct smb_charger,
4771 otg_ss_done_work.work);
4772 int rc;
4773 bool success = false;
4774 u8 stat;
4775
4776 mutex_lock(&chg->otg_oc_lock);
4777 rc = smblib_read(chg, OTG_STATUS_REG, &stat);
4778 if (rc < 0)
4779 smblib_err(chg, "Couldn't read OTG status rc=%d\n", rc);
4780 else if (stat & BOOST_SOFTSTART_DONE_BIT)
4781 success = true;
4782
4783 smblib_otg_oc_exit(chg, success);
4784 mutex_unlock(&chg->otg_oc_lock);
4785}
4786
Ashay Jaiswal4d825782017-02-18 10:11:34 +05304787static void smblib_icl_change_work(struct work_struct *work)
4788{
4789 struct smb_charger *chg = container_of(work, struct smb_charger,
4790 icl_change_work.work);
4791 int rc, settled_ua;
4792
4793 rc = smblib_get_charge_param(chg, &chg->param.icl_stat, &settled_ua);
4794 if (rc < 0) {
4795 smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
4796 return;
4797 }
4798
4799 power_supply_changed(chg->usb_main_psy);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05304800
4801 smblib_dbg(chg, PR_INTERRUPT, "icl_settled=%d\n", settled_ua);
4802}
4803
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304804static void smblib_pl_enable_work(struct work_struct *work)
4805{
4806 struct smb_charger *chg = container_of(work, struct smb_charger,
4807 pl_enable_work.work);
4808
4809 smblib_dbg(chg, PR_PARALLEL, "timer expired, enabling parallel\n");
4810 vote(chg->pl_disable_votable, PL_DELAY_VOTER, false, 0);
4811 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
4812}
4813
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004814static void smblib_legacy_detection_work(struct work_struct *work)
4815{
4816 struct smb_charger *chg = container_of(work, struct smb_charger,
4817 legacy_detection_work);
4818 int rc;
4819 u8 stat;
4820 bool legacy, rp_high;
4821
4822 mutex_lock(&chg->lock);
4823 chg->typec_en_dis_active = 1;
4824 smblib_dbg(chg, PR_MISC, "running legacy unknown workaround\n");
4825 rc = smblib_masked_write(chg,
4826 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4827 TYPEC_DISABLE_CMD_BIT,
4828 TYPEC_DISABLE_CMD_BIT);
4829 if (rc < 0)
4830 smblib_err(chg, "Couldn't disable type-c rc=%d\n", rc);
4831
4832 /* wait for the adapter to turn off VBUS */
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07004833 msleep(1000);
4834
4835 smblib_dbg(chg, PR_MISC, "legacy workaround enabling typec\n");
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004836
4837 rc = smblib_masked_write(chg,
4838 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4839 TYPEC_DISABLE_CMD_BIT, 0);
4840 if (rc < 0)
4841 smblib_err(chg, "Couldn't enable type-c rc=%d\n", rc);
4842
4843 /* wait for type-c detection to complete */
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07004844 msleep(400);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004845
4846 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat);
4847 if (rc < 0) {
4848 smblib_err(chg, "Couldn't read typec stat5 rc = %d\n", rc);
4849 goto unlock;
4850 }
4851
4852 chg->typec_legacy_valid = true;
4853 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
4854 legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT;
Nicholas Troaste1932e42017-04-12 12:38:18 -07004855 rp_high = chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH;
Abhijeet Dharmapurikarbb4d39d2017-08-25 14:23:09 -07004856 smblib_dbg(chg, PR_MISC, "legacy workaround done legacy = %d rp_high = %d\n",
4857 legacy, rp_high);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004858 if (!legacy || !rp_high)
4859 vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
4860 false, 0);
4861
4862unlock:
4863 chg->typec_en_dis_active = 0;
Nicholas Troast6439e172017-06-02 14:45:39 -07004864 smblib_usb_typec_change(chg);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004865 mutex_unlock(&chg->lock);
4866}
4867
Harry Yangba874ce2016-08-19 14:17:01 -07004868static int smblib_create_votables(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07004869{
4870 int rc = 0;
4871
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304872 chg->fcc_votable = find_votable("FCC");
Harry Yang0c35ff62017-04-06 00:02:30 -07004873 if (chg->fcc_votable == NULL) {
4874 rc = -EINVAL;
4875 smblib_err(chg, "Couldn't find FCC votable rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304876 return rc;
4877 }
4878
4879 chg->fv_votable = find_votable("FV");
Harry Yang0c35ff62017-04-06 00:02:30 -07004880 if (chg->fv_votable == NULL) {
4881 rc = -EINVAL;
4882 smblib_err(chg, "Couldn't find FV votable rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304883 return rc;
4884 }
4885
Ashay Jaiswalae1586d2017-03-22 23:18:51 +05304886 chg->usb_icl_votable = find_votable("USB_ICL");
4887 if (!chg->usb_icl_votable) {
Harry Yang0c35ff62017-04-06 00:02:30 -07004888 rc = -EINVAL;
4889 smblib_err(chg, "Couldn't find USB_ICL votable rc=%d\n", rc);
Ashay Jaiswalae1586d2017-03-22 23:18:51 +05304890 return rc;
4891 }
4892
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304893 chg->pl_disable_votable = find_votable("PL_DISABLE");
Harry Yang0c35ff62017-04-06 00:02:30 -07004894 if (chg->pl_disable_votable == NULL) {
4895 rc = -EINVAL;
4896 smblib_err(chg, "Couldn't find votable PL_DISABLE rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304897 return rc;
4898 }
Abhijeet Dharmapurikar38ef1422017-05-18 15:37:56 -07004899
4900 chg->pl_enable_votable_indirect = find_votable("PL_ENABLE_INDIRECT");
4901 if (chg->pl_enable_votable_indirect == NULL) {
4902 rc = -EINVAL;
4903 smblib_err(chg,
4904 "Couldn't find votable PL_ENABLE_INDIRECT rc=%d\n",
4905 rc);
4906 return rc;
4907 }
4908
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304909 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304910
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004911 chg->dc_suspend_votable = create_votable("DC_SUSPEND", VOTE_SET_ANY,
4912 smblib_dc_suspend_vote_callback,
4913 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07004914 if (IS_ERR(chg->dc_suspend_votable)) {
4915 rc = PTR_ERR(chg->dc_suspend_votable);
4916 return rc;
4917 }
4918
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004919 chg->dc_icl_votable = create_votable("DC_ICL", VOTE_MIN,
4920 smblib_dc_icl_vote_callback,
4921 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07004922 if (IS_ERR(chg->dc_icl_votable)) {
4923 rc = PTR_ERR(chg->dc_icl_votable);
4924 return rc;
4925 }
4926
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07004927 chg->pd_disallowed_votable_indirect
4928 = create_votable("PD_DISALLOWED_INDIRECT", VOTE_SET_ANY,
4929 smblib_pd_disallowed_votable_indirect_callback, chg);
4930 if (IS_ERR(chg->pd_disallowed_votable_indirect)) {
4931 rc = PTR_ERR(chg->pd_disallowed_votable_indirect);
4932 return rc;
4933 }
4934
4935 chg->pd_allowed_votable = create_votable("PD_ALLOWED",
4936 VOTE_SET_ANY, NULL, NULL);
Nicholas Troast34db5032016-03-28 12:26:44 -07004937 if (IS_ERR(chg->pd_allowed_votable)) {
4938 rc = PTR_ERR(chg->pd_allowed_votable);
4939 return rc;
4940 }
4941
Harry Yang223c6282016-06-14 15:48:36 -07004942 chg->awake_votable = create_votable("AWAKE", VOTE_SET_ANY,
4943 smblib_awake_vote_callback,
4944 chg);
4945 if (IS_ERR(chg->awake_votable)) {
4946 rc = PTR_ERR(chg->awake_votable);
4947 return rc;
4948 }
4949
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07004950 chg->chg_disable_votable = create_votable("CHG_DISABLE", VOTE_SET_ANY,
4951 smblib_chg_disable_vote_callback,
4952 chg);
4953 if (IS_ERR(chg->chg_disable_votable)) {
4954 rc = PTR_ERR(chg->chg_disable_votable);
4955 return rc;
4956 }
4957
Harry Yangaba1f5f2016-09-28 10:47:29 -07004958
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05304959 chg->hvdcp_disable_votable_indirect = create_votable(
4960 "HVDCP_DISABLE_INDIRECT",
4961 VOTE_SET_ANY,
4962 smblib_hvdcp_disable_indirect_vote_callback,
4963 chg);
4964 if (IS_ERR(chg->hvdcp_disable_votable_indirect)) {
4965 rc = PTR_ERR(chg->hvdcp_disable_votable_indirect);
4966 return rc;
4967 }
4968
4969 chg->hvdcp_enable_votable = create_votable("HVDCP_ENABLE",
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07004970 VOTE_SET_ANY,
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05304971 smblib_hvdcp_enable_vote_callback,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07004972 chg);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05304973 if (IS_ERR(chg->hvdcp_enable_votable)) {
4974 rc = PTR_ERR(chg->hvdcp_enable_votable);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07004975 return rc;
4976 }
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07004977
4978 chg->apsd_disable_votable = create_votable("APSD_DISABLE",
4979 VOTE_SET_ANY,
4980 smblib_apsd_disable_vote_callback,
4981 chg);
4982 if (IS_ERR(chg->apsd_disable_votable)) {
4983 rc = PTR_ERR(chg->apsd_disable_votable);
4984 return rc;
4985 }
4986
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05304987 chg->hvdcp_hw_inov_dis_votable = create_votable("HVDCP_HW_INOV_DIS",
4988 VOTE_SET_ANY,
4989 smblib_hvdcp_hw_inov_dis_vote_callback,
4990 chg);
4991 if (IS_ERR(chg->hvdcp_hw_inov_dis_votable)) {
4992 rc = PTR_ERR(chg->hvdcp_hw_inov_dis_votable);
4993 return rc;
4994 }
4995
Harry Yang4bf7d962017-03-13 16:51:43 -07004996 chg->usb_irq_enable_votable = create_votable("USB_IRQ_DISABLE",
4997 VOTE_SET_ANY,
4998 smblib_usb_irq_enable_vote_callback,
4999 chg);
5000 if (IS_ERR(chg->usb_irq_enable_votable)) {
5001 rc = PTR_ERR(chg->usb_irq_enable_votable);
5002 return rc;
5003 }
5004
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07005005 chg->typec_irq_disable_votable = create_votable("TYPEC_IRQ_DISABLE",
5006 VOTE_SET_ANY,
5007 smblib_typec_irq_disable_vote_callback,
5008 chg);
5009 if (IS_ERR(chg->typec_irq_disable_votable)) {
5010 rc = PTR_ERR(chg->typec_irq_disable_votable);
5011 return rc;
5012 }
5013
Nicholas Troast320839e2016-06-03 10:18:00 -07005014 return rc;
5015}
5016
Harry Yangba874ce2016-08-19 14:17:01 -07005017static void smblib_destroy_votables(struct smb_charger *chg)
5018{
Harry Yangba874ce2016-08-19 14:17:01 -07005019 if (chg->dc_suspend_votable)
5020 destroy_votable(chg->dc_suspend_votable);
Harry Yangba874ce2016-08-19 14:17:01 -07005021 if (chg->usb_icl_votable)
5022 destroy_votable(chg->usb_icl_votable);
5023 if (chg->dc_icl_votable)
5024 destroy_votable(chg->dc_icl_votable);
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07005025 if (chg->pd_disallowed_votable_indirect)
5026 destroy_votable(chg->pd_disallowed_votable_indirect);
Harry Yangba874ce2016-08-19 14:17:01 -07005027 if (chg->pd_allowed_votable)
5028 destroy_votable(chg->pd_allowed_votable);
5029 if (chg->awake_votable)
5030 destroy_votable(chg->awake_votable);
Harry Yangaba1f5f2016-09-28 10:47:29 -07005031 if (chg->chg_disable_votable)
5032 destroy_votable(chg->chg_disable_votable);
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07005033 if (chg->apsd_disable_votable)
5034 destroy_votable(chg->apsd_disable_votable);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05305035 if (chg->hvdcp_hw_inov_dis_votable)
5036 destroy_votable(chg->hvdcp_hw_inov_dis_votable);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07005037 if (chg->typec_irq_disable_votable)
5038 destroy_votable(chg->typec_irq_disable_votable);
Harry Yangba874ce2016-08-19 14:17:01 -07005039}
5040
5041static void smblib_iio_deinit(struct smb_charger *chg)
5042{
5043 if (!IS_ERR_OR_NULL(chg->iio.temp_chan))
5044 iio_channel_release(chg->iio.temp_chan);
5045 if (!IS_ERR_OR_NULL(chg->iio.temp_max_chan))
5046 iio_channel_release(chg->iio.temp_max_chan);
5047 if (!IS_ERR_OR_NULL(chg->iio.usbin_i_chan))
5048 iio_channel_release(chg->iio.usbin_i_chan);
5049 if (!IS_ERR_OR_NULL(chg->iio.usbin_v_chan))
5050 iio_channel_release(chg->iio.usbin_v_chan);
Nicholas Troast7dbcad22016-10-05 13:30:18 -07005051 if (!IS_ERR_OR_NULL(chg->iio.batt_i_chan))
5052 iio_channel_release(chg->iio.batt_i_chan);
Harry Yangba874ce2016-08-19 14:17:01 -07005053}
5054
Nicholas Troast320839e2016-06-03 10:18:00 -07005055int smblib_init(struct smb_charger *chg)
5056{
5057 int rc = 0;
5058
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07005059 mutex_init(&chg->lock);
Nicholas Troast320839e2016-06-03 10:18:00 -07005060 mutex_init(&chg->write_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08005061 mutex_init(&chg->otg_oc_lock);
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07005062 mutex_init(&chg->vconn_oc_lock);
Harry Yangfe913842016-08-10 12:27:28 -07005063 INIT_WORK(&chg->bms_update_work, bms_update_work);
Harry Yang166b15d2017-08-28 13:00:40 -07005064 INIT_WORK(&chg->pl_update_work, pl_update_work);
Harry Yang755a34b2016-11-01 01:18:51 -07005065 INIT_WORK(&chg->rdstd_cc2_detach_work, rdstd_cc2_detach_work);
Nicholas Troast320839e2016-06-03 10:18:00 -07005066 INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07005067 INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work);
Nicholas Troastb11015f2017-01-17 17:56:45 -08005068 INIT_WORK(&chg->otg_oc_work, smblib_otg_oc_work);
5069 INIT_WORK(&chg->vconn_oc_work, smblib_vconn_oc_work);
5070 INIT_DELAYED_WORK(&chg->otg_ss_done_work, smblib_otg_ss_done_work);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05305071 INIT_DELAYED_WORK(&chg->icl_change_work, smblib_icl_change_work);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05305072 INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07005073 INIT_WORK(&chg->legacy_detection_work, smblib_legacy_detection_work);
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05305074 INIT_DELAYED_WORK(&chg->uusb_otg_work, smblib_uusb_otg_work);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05305075 INIT_DELAYED_WORK(&chg->bb_removal_work, smblib_bb_removal_work);
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07005076 chg->fake_capacity = -EINVAL;
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07005077 chg->fake_input_current_limited = -EINVAL;
Harry Yang589dd422017-07-28 18:41:42 -07005078 chg->fake_batt_status = -EINVAL;
Nicholas Troast320839e2016-06-03 10:18:00 -07005079
5080 switch (chg->mode) {
5081 case PARALLEL_MASTER:
Harry Yang0c35ff62017-04-06 00:02:30 -07005082 rc = qcom_batt_init();
5083 if (rc < 0) {
5084 smblib_err(chg, "Couldn't init qcom_batt_init rc=%d\n",
5085 rc);
5086 return rc;
5087 }
5088
Fenglin Wudd8f4cb2017-10-17 11:09:46 +08005089 rc = qcom_step_chg_init(chg->dev, chg->step_chg_enabled,
Ashay Jaiswal9aba44a2017-07-20 17:41:36 +05305090 chg->sw_jeita_enabled);
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05305091 if (rc < 0) {
5092 smblib_err(chg, "Couldn't init qcom_step_chg_init rc=%d\n",
5093 rc);
5094 return rc;
5095 }
5096
Nicholas Troast320839e2016-06-03 10:18:00 -07005097 rc = smblib_create_votables(chg);
5098 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07005099 smblib_err(chg, "Couldn't create votables rc=%d\n",
Nicholas Troast320839e2016-06-03 10:18:00 -07005100 rc);
Harry Yang58a9e7a2016-06-23 14:54:43 -07005101 return rc;
Nicholas Troast320839e2016-06-03 10:18:00 -07005102 }
Harry Yang58a9e7a2016-06-23 14:54:43 -07005103
Harry Yang5e1a5222016-07-26 15:16:04 -07005104 rc = smblib_register_notifier(chg);
5105 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07005106 smblib_err(chg,
Harry Yang5e1a5222016-07-26 15:16:04 -07005107 "Couldn't register notifier rc=%d\n", rc);
5108 return rc;
Harry Yang58a9e7a2016-06-23 14:54:43 -07005109 }
5110
Harry Yang995b7422016-08-29 16:06:50 -07005111 chg->bms_psy = power_supply_get_by_name("bms");
Ashay Jaiswal8afedfc2017-02-03 11:18:22 +05305112 chg->pl.psy = power_supply_get_by_name("parallel");
Harry Yang166b15d2017-08-28 13:00:40 -07005113 if (chg->pl.psy) {
5114 rc = smblib_stat_sw_override_cfg(chg, false);
5115 if (rc < 0) {
5116 smblib_err(chg,
5117 "Couldn't config stat sw rc=%d\n", rc);
5118 return rc;
5119 }
5120 }
Nicholas Troast320839e2016-06-03 10:18:00 -07005121 break;
5122 case PARALLEL_SLAVE:
5123 break;
5124 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07005125 smblib_err(chg, "Unsupported mode %d\n", chg->mode);
Nicholas Troast320839e2016-06-03 10:18:00 -07005126 return -EINVAL;
5127 }
5128
5129 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07005130}
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07005131
5132int smblib_deinit(struct smb_charger *chg)
5133{
Harry Yangba874ce2016-08-19 14:17:01 -07005134 switch (chg->mode) {
5135 case PARALLEL_MASTER:
Harry Yang0c35ff62017-04-06 00:02:30 -07005136 cancel_work_sync(&chg->bms_update_work);
Harry Yang166b15d2017-08-28 13:00:40 -07005137 cancel_work_sync(&chg->pl_update_work);
Harry Yang0c35ff62017-04-06 00:02:30 -07005138 cancel_work_sync(&chg->rdstd_cc2_detach_work);
5139 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
Harry Yang0c35ff62017-04-06 00:02:30 -07005140 cancel_delayed_work_sync(&chg->clear_hdc_work);
5141 cancel_work_sync(&chg->otg_oc_work);
5142 cancel_work_sync(&chg->vconn_oc_work);
5143 cancel_delayed_work_sync(&chg->otg_ss_done_work);
5144 cancel_delayed_work_sync(&chg->icl_change_work);
5145 cancel_delayed_work_sync(&chg->pl_enable_work);
5146 cancel_work_sync(&chg->legacy_detection_work);
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05305147 cancel_delayed_work_sync(&chg->uusb_otg_work);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05305148 cancel_delayed_work_sync(&chg->bb_removal_work);
Harry Yangba874ce2016-08-19 14:17:01 -07005149 power_supply_unreg_notifier(&chg->nb);
5150 smblib_destroy_votables(chg);
Anirudh Ghayal9d0196d2017-07-23 23:02:48 +05305151 qcom_step_chg_deinit();
Harry Yang0c35ff62017-04-06 00:02:30 -07005152 qcom_batt_deinit();
Harry Yangba874ce2016-08-19 14:17:01 -07005153 break;
5154 case PARALLEL_SLAVE:
5155 break;
5156 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07005157 smblib_err(chg, "Unsupported mode %d\n", chg->mode);
Harry Yangba874ce2016-08-19 14:17:01 -07005158 return -EINVAL;
5159 }
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07005160
Harry Yangba874ce2016-08-19 14:17:01 -07005161 smblib_iio_deinit(chg);
Harry Yang5e1a5222016-07-26 15:16:04 -07005162
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07005163 return 0;
5164}