blob: eddca6a9dd4cc259a4fd06752cfcd1f56a74cdf3 [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"
Nicholas Troast47ae4612016-08-03 09:49:36 -070025#include "storm-watch.h"
Nicholas Troast34db5032016-03-28 12:26:44 -070026
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -070027#define smblib_err(chg, fmt, ...) \
28 pr_err("%s: %s: " fmt, chg->name, \
29 __func__, ##__VA_ARGS__) \
30
Nicholas Troast34db5032016-03-28 12:26:44 -070031#define smblib_dbg(chg, reason, fmt, ...) \
32 do { \
33 if (*chg->debug_mask & (reason)) \
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -070034 pr_info("%s: %s: " fmt, chg->name, \
35 __func__, ##__VA_ARGS__); \
Nicholas Troast34db5032016-03-28 12:26:44 -070036 else \
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -070037 pr_debug("%s: %s: " fmt, chg->name, \
38 __func__, ##__VA_ARGS__); \
Nicholas Troast34db5032016-03-28 12:26:44 -070039 } while (0)
40
41static bool is_secure(struct smb_charger *chg, int addr)
42{
Anirudh Ghayal4da3df92017-01-25 18:55:57 +053043 if (addr == SHIP_MODE_REG || addr == FREQ_CLK_DIV_REG)
Fenglin Wuedd70792016-11-22 13:16:19 +080044 return true;
Harry Yang47bd3852016-10-17 10:37:12 -070045 /* assume everything above 0xA0 is secure */
46 return (bool)((addr & 0xFF) >= 0xA0);
Nicholas Troast34db5032016-03-28 12:26:44 -070047}
48
49int smblib_read(struct smb_charger *chg, u16 addr, u8 *val)
50{
51 unsigned int temp;
52 int rc = 0;
53
54 rc = regmap_read(chg->regmap, addr, &temp);
55 if (rc >= 0)
56 *val = (u8)temp;
57
58 return rc;
59}
60
Ashay Jaiswal6d308da2017-02-18 09:59:23 +053061int smblib_multibyte_read(struct smb_charger *chg, u16 addr, u8 *val,
62 int count)
63{
64 return regmap_bulk_read(chg->regmap, addr, val, count);
65}
66
Nicholas Troast34db5032016-03-28 12:26:44 -070067int smblib_masked_write(struct smb_charger *chg, u16 addr, u8 mask, u8 val)
68{
Nicholas Troast34db5032016-03-28 12:26:44 -070069 int rc = 0;
70
Harry Yangbacd2222016-05-11 16:43:51 -070071 mutex_lock(&chg->write_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -070072 if (is_secure(chg, addr)) {
73 rc = regmap_write(chg->regmap, (addr & 0xFF00) | 0xD0, 0xA5);
74 if (rc < 0)
75 goto unlock;
76 }
77
78 rc = regmap_update_bits(chg->regmap, addr, mask, val);
79
80unlock:
Harry Yangbacd2222016-05-11 16:43:51 -070081 mutex_unlock(&chg->write_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -070082 return rc;
83}
84
85int smblib_write(struct smb_charger *chg, u16 addr, u8 val)
86{
Nicholas Troast34db5032016-03-28 12:26:44 -070087 int rc = 0;
88
Harry Yangbacd2222016-05-11 16:43:51 -070089 mutex_lock(&chg->write_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -070090
91 if (is_secure(chg, addr)) {
92 rc = regmap_write(chg->regmap, (addr & ~(0xFF)) | 0xD0, 0xA5);
93 if (rc < 0)
94 goto unlock;
95 }
96
97 rc = regmap_write(chg->regmap, addr, val);
98
99unlock:
Harry Yangbacd2222016-05-11 16:43:51 -0700100 mutex_unlock(&chg->write_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -0700101 return rc;
102}
103
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -0700104static int smblib_get_step_cc_delta(struct smb_charger *chg, int *cc_delta_ua)
Harry Yangfe913842016-08-10 12:27:28 -0700105{
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -0700106 int rc, step_state;
Harry Yangfe913842016-08-10 12:27:28 -0700107 u8 stat;
108
109 if (!chg->step_chg_enabled) {
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -0700110 *cc_delta_ua = 0;
Harry Yangfe913842016-08-10 12:27:28 -0700111 return 0;
112 }
113
114 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
115 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700116 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Harry Yangfe913842016-08-10 12:27:28 -0700117 rc);
118 return rc;
119 }
120
Harry Yangbedee332016-08-31 16:14:29 -0700121 step_state = (stat & STEP_CHARGING_STATUS_MASK) >>
122 STEP_CHARGING_STATUS_SHIFT;
Harry Yangfe913842016-08-10 12:27:28 -0700123 rc = smblib_get_charge_param(chg, &chg->param.step_cc_delta[step_state],
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -0700124 cc_delta_ua);
125 if (rc < 0) {
126 smblib_err(chg, "Couldn't get step cc delta rc=%d\n", rc);
127 return rc;
Abhijeet Dharmapurikar2644cd62016-07-20 16:54:55 -0700128 }
129
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -0700130 return 0;
131}
Harry Yangfe913842016-08-10 12:27:28 -0700132
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -0700133static int smblib_get_jeita_cc_delta(struct smb_charger *chg, int *cc_delta_ua)
134{
135 int rc, cc_minus_ua;
136 u8 stat;
Harry Yangfe913842016-08-10 12:27:28 -0700137
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -0700138 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat);
139 if (rc < 0) {
140 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
141 rc);
142 return rc;
143 }
144
145 if (!(stat & BAT_TEMP_STATUS_SOFT_LIMIT_MASK)) {
146 *cc_delta_ua = 0;
147 return 0;
148 }
149
150 rc = smblib_get_charge_param(chg, &chg->param.jeita_cc_comp,
151 &cc_minus_ua);
152 if (rc < 0) {
153 smblib_err(chg, "Couldn't get jeita cc minus rc=%d\n", rc);
154 return rc;
155 }
156
157 *cc_delta_ua = -cc_minus_ua;
158 return 0;
159}
160
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800161int smblib_icl_override(struct smb_charger *chg, bool override)
162{
163 int rc;
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800164
Nicholas Troast11af51b2017-03-15 10:45:28 -0700165 rc = smblib_masked_write(chg, USBIN_LOAD_CFG_REG,
166 ICL_OVERRIDE_AFTER_APSD_BIT,
167 override ? ICL_OVERRIDE_AFTER_APSD_BIT : 0);
168 if (rc < 0)
169 smblib_err(chg, "Couldn't override ICL rc=%d\n", rc);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -0800170
Nicholas Troast11af51b2017-03-15 10:45:28 -0700171 return rc;
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800172}
173
Nicholas Troast34db5032016-03-28 12:26:44 -0700174/********************
175 * REGISTER GETTERS *
176 ********************/
177
Nicholas Troast4c310492016-05-12 17:56:35 -0700178int smblib_get_charge_param(struct smb_charger *chg,
179 struct smb_chg_param *param, int *val_u)
180{
181 int rc = 0;
182 u8 val_raw;
183
184 rc = smblib_read(chg, param->reg, &val_raw);
185 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700186 smblib_err(chg, "%s: Couldn't read from 0x%04x rc=%d\n",
Nicholas Troast4c310492016-05-12 17:56:35 -0700187 param->name, param->reg, rc);
188 return rc;
189 }
190
Harry Yangf8b41252016-08-10 14:21:10 -0700191 if (param->get_proc)
192 *val_u = param->get_proc(param, val_raw);
193 else
194 *val_u = val_raw * param->step_u + param->min_u;
Nicholas Troast4c310492016-05-12 17:56:35 -0700195 smblib_dbg(chg, PR_REGISTER, "%s = %d (0x%02x)\n",
196 param->name, *val_u, val_raw);
197
198 return rc;
199}
200
201int smblib_get_usb_suspend(struct smb_charger *chg, int *suspend)
202{
203 int rc = 0;
204 u8 temp;
205
206 rc = smblib_read(chg, USBIN_CMD_IL_REG, &temp);
207 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700208 smblib_err(chg, "Couldn't read USBIN_CMD_IL rc=%d\n", rc);
Nicholas Troast4c310492016-05-12 17:56:35 -0700209 return rc;
210 }
211 *suspend = temp & USBIN_SUSPEND_BIT;
212
213 return rc;
214}
215
Nicholas Troast34db5032016-03-28 12:26:44 -0700216struct apsd_result {
217 const char * const name;
218 const u8 bit;
219 const enum power_supply_type pst;
220};
221
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700222enum {
223 UNKNOWN,
224 SDP,
225 CDP,
226 DCP,
227 OCP,
228 FLOAT,
229 HVDCP2,
230 HVDCP3,
231 MAX_TYPES
232};
233
Nicholas Troast34db5032016-03-28 12:26:44 -0700234static const struct apsd_result const smblib_apsd_results[] = {
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700235 [UNKNOWN] = {
236 .name = "UNKNOWN",
237 .bit = 0,
238 .pst = POWER_SUPPLY_TYPE_UNKNOWN
239 },
240 [SDP] = {
241 .name = "SDP",
242 .bit = SDP_CHARGER_BIT,
243 .pst = POWER_SUPPLY_TYPE_USB
244 },
245 [CDP] = {
246 .name = "CDP",
247 .bit = CDP_CHARGER_BIT,
248 .pst = POWER_SUPPLY_TYPE_USB_CDP
249 },
250 [DCP] = {
251 .name = "DCP",
252 .bit = DCP_CHARGER_BIT,
253 .pst = POWER_SUPPLY_TYPE_USB_DCP
254 },
255 [OCP] = {
256 .name = "OCP",
257 .bit = OCP_CHARGER_BIT,
258 .pst = POWER_SUPPLY_TYPE_USB_DCP
259 },
260 [FLOAT] = {
261 .name = "FLOAT",
262 .bit = FLOAT_CHARGER_BIT,
Ashay Jaiswalb9b2d2f2017-06-21 12:08:38 +0530263 .pst = POWER_SUPPLY_TYPE_USB_FLOAT
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700264 },
265 [HVDCP2] = {
266 .name = "HVDCP2",
267 .bit = DCP_CHARGER_BIT | QC_2P0_BIT,
268 .pst = POWER_SUPPLY_TYPE_USB_HVDCP
269 },
270 [HVDCP3] = {
271 .name = "HVDCP3",
272 .bit = DCP_CHARGER_BIT | QC_3P0_BIT,
273 .pst = POWER_SUPPLY_TYPE_USB_HVDCP_3,
274 },
Nicholas Troast34db5032016-03-28 12:26:44 -0700275};
276
277static const struct apsd_result *smblib_get_apsd_result(struct smb_charger *chg)
278{
279 int rc, i;
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700280 u8 apsd_stat, stat;
281 const struct apsd_result *result = &smblib_apsd_results[UNKNOWN];
Nicholas Troast34db5032016-03-28 12:26:44 -0700282
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700283 rc = smblib_read(chg, APSD_STATUS_REG, &apsd_stat);
Nicholas Troast34db5032016-03-28 12:26:44 -0700284 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700285 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700286 return result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700287 }
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700288 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", apsd_stat);
Nicholas Troast34db5032016-03-28 12:26:44 -0700289
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700290 if (!(apsd_stat & APSD_DTC_STATUS_DONE_BIT))
291 return result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700292
293 rc = smblib_read(chg, APSD_RESULT_STATUS_REG, &stat);
294 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700295 smblib_err(chg, "Couldn't read APSD_RESULT_STATUS rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700296 rc);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700297 return result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700298 }
299 stat &= APSD_RESULT_STATUS_MASK;
300
301 for (i = 0; i < ARRAY_SIZE(smblib_apsd_results); i++) {
302 if (smblib_apsd_results[i].bit == stat)
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700303 result = &smblib_apsd_results[i];
Nicholas Troast34db5032016-03-28 12:26:44 -0700304 }
305
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700306 if (apsd_stat & QC_CHARGER_BIT) {
307 /* since its a qc_charger, either return HVDCP3 or HVDCP2 */
308 if (result != &smblib_apsd_results[HVDCP3])
309 result = &smblib_apsd_results[HVDCP2];
310 }
311
312 return result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700313}
314
Nicholas Troast34db5032016-03-28 12:26:44 -0700315/********************
316 * REGISTER SETTERS *
317 ********************/
318
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530319static int chg_freq_list[] = {
320 9600, 9600, 6400, 4800, 3800, 3200, 2700, 2400, 2100, 1900, 1700,
321 1600, 1500, 1400, 1300, 1200,
322};
323
324int smblib_set_chg_freq(struct smb_chg_param *param,
325 int val_u, u8 *val_raw)
326{
327 u8 i;
328
329 if (val_u > param->max_u || val_u < param->min_u)
330 return -EINVAL;
331
332 /* Charger FSW is the configured freqency / 2 */
333 val_u *= 2;
334 for (i = 0; i < ARRAY_SIZE(chg_freq_list); i++) {
335 if (chg_freq_list[i] == val_u)
336 break;
337 }
338 if (i == ARRAY_SIZE(chg_freq_list)) {
339 pr_err("Invalid frequency %d Hz\n", val_u / 2);
340 return -EINVAL;
341 }
342
343 *val_raw = i;
344
345 return 0;
346}
347
348static int smblib_set_opt_freq_buck(struct smb_charger *chg, int fsw_khz)
349{
350 union power_supply_propval pval = {0, };
351 int rc = 0;
352
353 rc = smblib_set_charge_param(chg, &chg->param.freq_buck, fsw_khz);
354 if (rc < 0)
355 dev_err(chg->dev, "Error in setting freq_buck rc=%d\n", rc);
356
357 if (chg->mode == PARALLEL_MASTER && chg->pl.psy) {
358 pval.intval = fsw_khz;
Abhijeet Dharmapurikare9fd08d2017-02-27 11:05:28 -0800359 /*
360 * Some parallel charging implementations may not have
361 * PROP_BUCK_FREQ property - they could be running
362 * with a fixed frequency
363 */
364 power_supply_set_property(chg->pl.psy,
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530365 POWER_SUPPLY_PROP_BUCK_FREQ, &pval);
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530366 }
367
368 return rc;
369}
370
Nicholas Troast4c310492016-05-12 17:56:35 -0700371int smblib_set_charge_param(struct smb_charger *chg,
372 struct smb_chg_param *param, int val_u)
Nicholas Troast34db5032016-03-28 12:26:44 -0700373{
374 int rc = 0;
375 u8 val_raw;
376
Harry Yangf8b41252016-08-10 14:21:10 -0700377 if (param->set_proc) {
378 rc = param->set_proc(param, val_u, &val_raw);
379 if (rc < 0)
380 return -EINVAL;
381 } else {
382 if (val_u > param->max_u || val_u < param->min_u) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700383 smblib_err(chg, "%s: %d is out of range [%d, %d]\n",
Harry Yangf8b41252016-08-10 14:21:10 -0700384 param->name, val_u, param->min_u, param->max_u);
385 return -EINVAL;
386 }
387
388 val_raw = (val_u - param->min_u) / param->step_u;
Nicholas Troast34db5032016-03-28 12:26:44 -0700389 }
390
Nicholas Troast34db5032016-03-28 12:26:44 -0700391 rc = smblib_write(chg, param->reg, val_raw);
392 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700393 smblib_err(chg, "%s: Couldn't write 0x%02x to 0x%04x rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700394 param->name, val_raw, param->reg, rc);
395 return rc;
396 }
397
398 smblib_dbg(chg, PR_REGISTER, "%s = %d (0x%02x)\n",
399 param->name, val_u, val_raw);
400
401 return rc;
402}
403
Harry Yangfe913842016-08-10 12:27:28 -0700404static int step_charge_soc_update(struct smb_charger *chg, int capacity)
405{
406 int rc = 0;
407
408 rc = smblib_set_charge_param(chg, &chg->param.step_soc, capacity);
409 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700410 smblib_err(chg, "Error in updating soc, rc=%d\n", rc);
Harry Yangfe913842016-08-10 12:27:28 -0700411 return rc;
412 }
413
414 rc = smblib_write(chg, STEP_CHG_SOC_VBATT_V_UPDATE_REG,
415 STEP_CHG_SOC_VBATT_V_UPDATE_BIT);
416 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700417 smblib_err(chg,
Harry Yangfe913842016-08-10 12:27:28 -0700418 "Couldn't set STEP_CHG_SOC_VBATT_V_UPDATE_REG rc=%d\n",
419 rc);
420 return rc;
421 }
422
423 return rc;
424}
425
Nicholas Troast4c310492016-05-12 17:56:35 -0700426int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend)
Nicholas Troast34db5032016-03-28 12:26:44 -0700427{
428 int rc = 0;
Abhijeet Dharmapurikar109802f712017-07-07 18:30:54 -0700429 int irq = chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq;
430
431 if (suspend && irq) {
432 if (chg->usb_icl_change_irq_enabled) {
433 disable_irq_nosync(irq);
434 chg->usb_icl_change_irq_enabled = false;
435 }
436 }
Nicholas Troast34db5032016-03-28 12:26:44 -0700437
438 rc = smblib_masked_write(chg, USBIN_CMD_IL_REG, USBIN_SUSPEND_BIT,
439 suspend ? USBIN_SUSPEND_BIT : 0);
440 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700441 smblib_err(chg, "Couldn't write %s to USBIN_SUSPEND_BIT rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700442 suspend ? "suspend" : "resume", rc);
443
Abhijeet Dharmapurikar109802f712017-07-07 18:30:54 -0700444 if (!suspend && irq) {
445 if (!chg->usb_icl_change_irq_enabled) {
446 enable_irq(irq);
447 chg->usb_icl_change_irq_enabled = true;
448 }
449 }
450
Nicholas Troast34db5032016-03-28 12:26:44 -0700451 return rc;
452}
453
Nicholas Troast4c310492016-05-12 17:56:35 -0700454int smblib_set_dc_suspend(struct smb_charger *chg, bool suspend)
Nicholas Troast34db5032016-03-28 12:26:44 -0700455{
456 int rc = 0;
457
458 rc = smblib_masked_write(chg, DCIN_CMD_IL_REG, DCIN_SUSPEND_BIT,
459 suspend ? DCIN_SUSPEND_BIT : 0);
460 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700461 smblib_err(chg, "Couldn't write %s to DCIN_SUSPEND_BIT rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700462 suspend ? "suspend" : "resume", rc);
463
464 return rc;
465}
466
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530467static int smblib_set_adapter_allowance(struct smb_charger *chg,
468 u8 allowed_voltage)
469{
470 int rc = 0;
471
472 switch (allowed_voltage) {
473 case USBIN_ADAPTER_ALLOW_12V:
474 case USBIN_ADAPTER_ALLOW_5V_OR_12V:
475 case USBIN_ADAPTER_ALLOW_9V_TO_12V:
476 case USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V:
477 case USBIN_ADAPTER_ALLOW_5V_TO_12V:
478 /* PM660 only support max. 9V */
479 if (chg->smb_version == PM660_SUBTYPE) {
480 smblib_dbg(chg, PR_MISC, "voltage not supported=%d\n",
481 allowed_voltage);
482 allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_9V;
483 }
484 break;
485 }
486
487 rc = smblib_write(chg, USBIN_ADAPTER_ALLOW_CFG_REG, allowed_voltage);
488 if (rc < 0) {
489 smblib_err(chg, "Couldn't write 0x%02x to USBIN_ADAPTER_ALLOW_CFG rc=%d\n",
490 allowed_voltage, rc);
491 return rc;
492 }
493
494 return rc;
495}
496
Nicholas Troast34db5032016-03-28 12:26:44 -0700497#define MICRO_5V 5000000
498#define MICRO_9V 9000000
499#define MICRO_12V 12000000
500static int smblib_set_usb_pd_allowed_voltage(struct smb_charger *chg,
501 int min_allowed_uv, int max_allowed_uv)
502{
503 int rc;
504 u8 allowed_voltage;
505
506 if (min_allowed_uv == MICRO_5V && max_allowed_uv == MICRO_5V) {
507 allowed_voltage = USBIN_ADAPTER_ALLOW_5V;
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530508 smblib_set_opt_freq_buck(chg, chg->chg_freq.freq_5V);
Nicholas Troast34db5032016-03-28 12:26:44 -0700509 } else if (min_allowed_uv == MICRO_9V && max_allowed_uv == MICRO_9V) {
510 allowed_voltage = USBIN_ADAPTER_ALLOW_9V;
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530511 smblib_set_opt_freq_buck(chg, chg->chg_freq.freq_9V);
Nicholas Troast34db5032016-03-28 12:26:44 -0700512 } else if (min_allowed_uv == MICRO_12V && max_allowed_uv == MICRO_12V) {
513 allowed_voltage = USBIN_ADAPTER_ALLOW_12V;
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530514 smblib_set_opt_freq_buck(chg, chg->chg_freq.freq_12V);
Nicholas Troast34db5032016-03-28 12:26:44 -0700515 } else if (min_allowed_uv < MICRO_9V && max_allowed_uv <= MICRO_9V) {
516 allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_9V;
517 } else if (min_allowed_uv < MICRO_9V && max_allowed_uv <= MICRO_12V) {
518 allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_12V;
519 } else if (min_allowed_uv < MICRO_12V && max_allowed_uv <= MICRO_12V) {
520 allowed_voltage = USBIN_ADAPTER_ALLOW_9V_TO_12V;
521 } else {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700522 smblib_err(chg, "invalid allowed voltage [%d, %d]\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700523 min_allowed_uv, max_allowed_uv);
524 return -EINVAL;
525 }
526
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530527 rc = smblib_set_adapter_allowance(chg, allowed_voltage);
Nicholas Troast34db5032016-03-28 12:26:44 -0700528 if (rc < 0) {
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530529 smblib_err(chg, "Couldn't configure adapter allowance rc=%d\n",
530 rc);
Nicholas Troast34db5032016-03-28 12:26:44 -0700531 return rc;
532 }
533
534 return rc;
535}
536
537/********************
538 * HELPER FUNCTIONS *
539 ********************/
540
Nicholas Troast93fb0f02017-03-01 10:17:13 -0800541static void smblib_rerun_apsd(struct smb_charger *chg)
542{
543 int rc;
544
545 smblib_dbg(chg, PR_MISC, "re-running APSD\n");
546 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
547 rc = smblib_masked_write(chg,
548 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
549 AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
550 if (rc < 0)
551 smblib_err(chg, "Couldn't enable HVDCP auth IRQ rc=%d\n",
552 rc);
553 }
554
555 rc = smblib_masked_write(chg, CMD_APSD_REG,
556 APSD_RERUN_BIT, APSD_RERUN_BIT);
557 if (rc < 0)
558 smblib_err(chg, "Couldn't re-run APSD rc=%d\n", rc);
559}
560
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -0700561static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -0700562{
Abhijeet Dharmapurikareda08222016-11-01 11:35:29 -0700563 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -0700564
Jack Pham9696e252016-05-23 11:15:15 -0700565 /* if PD is active, APSD is disabled so won't have a valid result */
Nicholas Troast93fb0f02017-03-01 10:17:13 -0800566 if (chg->pd_active)
Fenglin Wu80826e02017-04-25 21:45:08 +0800567 chg->real_charger_type = POWER_SUPPLY_TYPE_USB_PD;
Nicholas Troast93fb0f02017-03-01 10:17:13 -0800568 else
Fenglin Wu80826e02017-04-25 21:45:08 +0800569 chg->real_charger_type = apsd_result->pst;
Nicholas Troast34db5032016-03-28 12:26:44 -0700570
Nicholas Troast93fb0f02017-03-01 10:17:13 -0800571 smblib_dbg(chg, PR_MISC, "APSD=%s PD=%d\n",
572 apsd_result->name, chg->pd_active);
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -0700573 return apsd_result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700574}
575
Harry Yang5e1a5222016-07-26 15:16:04 -0700576static int smblib_notifier_call(struct notifier_block *nb,
Harry Yang58a9e7a2016-06-23 14:54:43 -0700577 unsigned long ev, void *v)
Harry Yang1d1034c2016-06-15 12:09:42 -0700578{
Harry Yang58a9e7a2016-06-23 14:54:43 -0700579 struct power_supply *psy = v;
Harry Yang5e1a5222016-07-26 15:16:04 -0700580 struct smb_charger *chg = container_of(nb, struct smb_charger, nb);
Harry Yang1d1034c2016-06-15 12:09:42 -0700581
Harry Yang5e1a5222016-07-26 15:16:04 -0700582 if (!strcmp(psy->desc->name, "bms")) {
583 if (!chg->bms_psy)
584 chg->bms_psy = psy;
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530585 if (ev == PSY_EVENT_PROP_CHANGED)
Harry Yang5e1a5222016-07-26 15:16:04 -0700586 schedule_work(&chg->bms_update_work);
587 }
588
Ashay Jaiswal8afedfc2017-02-03 11:18:22 +0530589 if (!chg->pl.psy && !strcmp(psy->desc->name, "parallel"))
Harry Yang58a9e7a2016-06-23 14:54:43 -0700590 chg->pl.psy = psy;
Harry Yang1d1034c2016-06-15 12:09:42 -0700591
Harry Yang58a9e7a2016-06-23 14:54:43 -0700592 return NOTIFY_OK;
593}
594
Harry Yang5e1a5222016-07-26 15:16:04 -0700595static int smblib_register_notifier(struct smb_charger *chg)
Harry Yang58a9e7a2016-06-23 14:54:43 -0700596{
597 int rc;
598
Harry Yang5e1a5222016-07-26 15:16:04 -0700599 chg->nb.notifier_call = smblib_notifier_call;
600 rc = power_supply_reg_notifier(&chg->nb);
Harry Yang58a9e7a2016-06-23 14:54:43 -0700601 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700602 smblib_err(chg, "Couldn't register psy notifier rc = %d\n", rc);
Harry Yang58a9e7a2016-06-23 14:54:43 -0700603 return rc;
604 }
605
606 return 0;
Harry Yang1d1034c2016-06-15 12:09:42 -0700607}
608
Harry Yangfe913842016-08-10 12:27:28 -0700609int smblib_mapping_soc_from_field_value(struct smb_chg_param *param,
610 int val_u, u8 *val_raw)
611{
612 if (val_u > param->max_u || val_u < param->min_u)
613 return -EINVAL;
614
615 *val_raw = val_u << 1;
616
617 return 0;
618}
619
620int smblib_mapping_cc_delta_to_field_value(struct smb_chg_param *param,
621 u8 val_raw)
622{
623 int val_u = val_raw * param->step_u + param->min_u;
624
625 if (val_u > param->max_u)
626 val_u -= param->max_u * 2;
627
628 return val_u;
629}
630
631int smblib_mapping_cc_delta_from_field_value(struct smb_chg_param *param,
632 int val_u, u8 *val_raw)
633{
634 if (val_u > param->max_u || val_u < param->min_u - param->max_u)
635 return -EINVAL;
636
637 val_u += param->max_u * 2 - param->min_u;
638 val_u %= param->max_u * 2;
639 *val_raw = val_u / param->step_u;
640
641 return 0;
642}
643
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530644static void smblib_uusb_removal(struct smb_charger *chg)
645{
646 int rc;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +0530647 struct smb_irq_data *data;
648 struct storm_watch *wdata;
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530649
Ashay Jaiswalc0361672017-03-21 12:24:16 +0530650 cancel_delayed_work_sync(&chg->pl_enable_work);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +0530651
652 if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) {
653 smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n");
654 rc = regulator_disable(chg->dpdm_reg);
655 if (rc < 0)
656 smblib_err(chg, "Couldn't disable dpdm regulator rc=%d\n",
657 rc);
658 }
659
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +0530660 if (chg->wa_flags & BOOST_BACK_WA) {
661 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
662 if (data) {
663 wdata = &data->storm_data;
664 update_storm_count(wdata, WEAK_CHG_STORM_COUNT);
665 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
666 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
667 false, 0);
668 }
669 }
Ashay Jaiswalc0361672017-03-21 12:24:16 +0530670 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
671 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
672
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530673 /* reset both usbin current and voltage votes */
674 vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
675 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
Ashay Jaiswalae23a042017-05-18 15:28:31 +0530676 vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530677
678 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
679
Ashay Jaiswal67ec7072017-02-16 14:14:58 +0530680 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
681 /* re-enable AUTH_IRQ_EN_CFG_BIT */
682 rc = smblib_masked_write(chg,
683 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
684 AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
685 if (rc < 0)
686 smblib_err(chg,
687 "Couldn't enable QC auth setting rc=%d\n", rc);
688 }
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530689
690 /* reconfigure allowed voltage for HVDCP */
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530691 rc = smblib_set_adapter_allowance(chg,
692 USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530693 if (rc < 0)
694 smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
695 rc);
696
697 chg->voltage_min_uv = MICRO_5V;
698 chg->voltage_max_uv = MICRO_5V;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +0530699 chg->usb_icl_delta_ua = 0;
700 chg->pulse_cnt = 0;
Ashay Jaiswal8507aa52017-04-14 09:42:32 +0530701 chg->uusb_apsd_rerun_done = false;
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530702
703 /* clear USB ICL vote for USB_PSY_VOTER */
704 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
705 if (rc < 0)
706 smblib_err(chg, "Couldn't un-vote for USB ICL rc=%d\n", rc);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -0800707
708 /* clear USB ICL vote for DCP_VOTER */
709 rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
710 if (rc < 0)
711 smblib_err(chg,
712 "Couldn't un-vote DCP from USB ICL rc=%d\n", rc);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530713}
714
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530715void smblib_suspend_on_debug_battery(struct smb_charger *chg)
716{
717 int rc;
718 union power_supply_propval val;
719
Ashay Jaiswalda8669b2017-02-10 23:24:23 +0530720 if (!chg->suspend_input_on_debug_batt)
721 return;
722
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530723 rc = power_supply_get_property(chg->bms_psy,
724 POWER_SUPPLY_PROP_DEBUG_BATTERY, &val);
725 if (rc < 0) {
726 smblib_err(chg, "Couldn't get debug battery prop rc=%d\n", rc);
727 return;
728 }
729
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800730 vote(chg->usb_icl_votable, DEBUG_BOARD_VOTER, val.intval, 0);
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530731 vote(chg->dc_suspend_votable, DEBUG_BOARD_VOTER, val.intval, 0);
732 if (val.intval)
733 pr_info("Input suspended: Fake battery\n");
734}
735
Abhijeet Dharmapurikar9dd61292017-01-25 16:40:08 -0800736int smblib_rerun_apsd_if_required(struct smb_charger *chg)
737{
Abhijeet Dharmapurikar9dd61292017-01-25 16:40:08 -0800738 union power_supply_propval val;
739 int rc;
740
741 rc = smblib_get_prop_usb_present(chg, &val);
742 if (rc < 0) {
743 smblib_err(chg, "Couldn't get usb present rc = %d\n", rc);
744 return rc;
745 }
746
747 if (!val.intval)
748 return 0;
749
Abhijeet Dharmapurikar025e63a2017-02-24 14:06:22 -0800750 /* fetch the DPDM regulator */
751 if (!chg->dpdm_reg && of_get_property(chg->dev->of_node,
752 "dpdm-supply", NULL)) {
753 chg->dpdm_reg = devm_regulator_get(chg->dev, "dpdm");
754 if (IS_ERR(chg->dpdm_reg)) {
755 smblib_err(chg, "Couldn't get dpdm regulator rc=%ld\n",
756 PTR_ERR(chg->dpdm_reg));
757 chg->dpdm_reg = NULL;
758 }
Abhijeet Dharmapurikar9dd61292017-01-25 16:40:08 -0800759 }
760
Abhijeet Dharmapurikar025e63a2017-02-24 14:06:22 -0800761 if (chg->dpdm_reg && !regulator_is_enabled(chg->dpdm_reg)) {
762 smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n");
763 rc = regulator_enable(chg->dpdm_reg);
764 if (rc < 0)
765 smblib_err(chg, "Couldn't enable dpdm regulator rc=%d\n",
766 rc);
767 }
768
Ashay Jaiswal8507aa52017-04-14 09:42:32 +0530769 chg->uusb_apsd_rerun_done = true;
Abhijeet Dharmapurikar025e63a2017-02-24 14:06:22 -0800770 smblib_rerun_apsd(chg);
771
Abhijeet Dharmapurikar9dd61292017-01-25 16:40:08 -0800772 return 0;
773}
774
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +0530775static int smblib_get_hw_pulse_cnt(struct smb_charger *chg, int *count)
Ashay Jaiswal6d308da2017-02-18 09:59:23 +0530776{
777 int rc;
778 u8 val[2];
779
780 switch (chg->smb_version) {
781 case PMI8998_SUBTYPE:
782 rc = smblib_read(chg, QC_PULSE_COUNT_STATUS_REG, val);
783 if (rc) {
784 pr_err("failed to read QC_PULSE_COUNT_STATUS_REG rc=%d\n",
785 rc);
786 return rc;
787 }
788 *count = val[0] & QC_PULSE_COUNT_MASK;
789 break;
790 case PM660_SUBTYPE:
791 rc = smblib_multibyte_read(chg,
792 QC_PULSE_COUNT_STATUS_1_REG, val, 2);
793 if (rc) {
794 pr_err("failed to read QC_PULSE_COUNT_STATUS_1_REG rc=%d\n",
795 rc);
796 return rc;
797 }
798 *count = (val[1] << 8) | val[0];
799 break;
800 default:
801 smblib_dbg(chg, PR_PARALLEL, "unknown SMB chip %d\n",
802 chg->smb_version);
803 return -EINVAL;
804 }
805
806 return 0;
807}
808
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +0530809static int smblib_get_pulse_cnt(struct smb_charger *chg, int *count)
810{
811 int rc;
812
813 /* Use software based pulse count if HW INOV is disabled */
814 if (get_effective_result(chg->hvdcp_hw_inov_dis_votable) > 0) {
815 *count = chg->pulse_cnt;
816 return 0;
817 }
818
819 /* Use h/w pulse count if autonomous mode is enabled */
820 rc = smblib_get_hw_pulse_cnt(chg, count);
821 if (rc < 0)
822 smblib_err(chg, "failed to read h/w pulse count rc=%d\n", rc);
823
824 return rc;
825}
826
Nicholas Troastbb76a142016-09-23 11:23:23 -0700827#define USBIN_25MA 25000
828#define USBIN_100MA 100000
829#define USBIN_150MA 150000
830#define USBIN_500MA 500000
831#define USBIN_900MA 900000
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800832
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800833static int set_sdp_current(struct smb_charger *chg, int icl_ua)
Nicholas Troast34db5032016-03-28 12:26:44 -0700834{
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800835 int rc;
836 u8 icl_options;
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700837
Nicholas Troastbb76a142016-09-23 11:23:23 -0700838 /* power source is SDP */
839 switch (icl_ua) {
840 case USBIN_100MA:
841 /* USB 2.0 100mA */
842 icl_options = 0;
843 break;
844 case USBIN_150MA:
845 /* USB 3.0 150mA */
846 icl_options = CFG_USB3P0_SEL_BIT;
847 break;
848 case USBIN_500MA:
849 /* USB 2.0 500mA */
850 icl_options = USB51_MODE_BIT;
851 break;
852 case USBIN_900MA:
853 /* USB 3.0 900mA */
854 icl_options = CFG_USB3P0_SEL_BIT | USB51_MODE_BIT;
855 break;
856 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700857 smblib_err(chg, "ICL %duA isn't supported for SDP\n", icl_ua);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800858 return -EINVAL;
Nicholas Troastbb76a142016-09-23 11:23:23 -0700859 }
Nicholas Troast34db5032016-03-28 12:26:44 -0700860
Nicholas Troastbb76a142016-09-23 11:23:23 -0700861 rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800862 CFG_USB3P0_SEL_BIT | USB51_MODE_BIT, icl_options);
Nicholas Troast34db5032016-03-28 12:26:44 -0700863 if (rc < 0) {
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800864 smblib_err(chg, "Couldn't set ICL options rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -0700865 return rc;
866 }
867
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800868 return rc;
869}
870
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700871static int get_sdp_current(struct smb_charger *chg, int *icl_ua)
872{
873 int rc;
874 u8 icl_options;
875 bool usb3 = false;
876
877 rc = smblib_read(chg, USBIN_ICL_OPTIONS_REG, &icl_options);
878 if (rc < 0) {
879 smblib_err(chg, "Couldn't get ICL options rc=%d\n", rc);
880 return rc;
881 }
882
883 usb3 = (icl_options & CFG_USB3P0_SEL_BIT);
884
885 if (icl_options & USB51_MODE_BIT)
886 *icl_ua = usb3 ? USBIN_900MA : USBIN_500MA;
887 else
888 *icl_ua = usb3 ? USBIN_150MA : USBIN_100MA;
889
890 return rc;
891}
892
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530893int smblib_set_icl_current(struct smb_charger *chg, int icl_ua)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800894{
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800895 int rc = 0;
896 bool override;
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800897
898 /* suspend and return if 25mA or less is requested */
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530899 if (icl_ua < USBIN_25MA)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800900 return smblib_set_usb_suspend(chg, true);
901
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530902 if (icl_ua == INT_MAX)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800903 goto override_suspend_config;
904
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800905 /* configure current */
Nicholas Troaste1932e42017-04-12 12:38:18 -0700906 if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
Fenglin Wu80826e02017-04-25 21:45:08 +0800907 && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) {
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800908 rc = set_sdp_current(chg, icl_ua);
909 if (rc < 0) {
910 smblib_err(chg, "Couldn't set SDP ICL rc=%d\n", rc);
911 goto enable_icl_changed_interrupt;
912 }
913 } else {
Abhijeet Dharmapurikar949d67e2017-05-25 15:10:56 -0700914 set_sdp_current(chg, 100000);
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -0700915 rc = smblib_set_charge_param(chg, &chg->param.usb_icl, icl_ua);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800916 if (rc < 0) {
917 smblib_err(chg, "Couldn't set HC ICL rc=%d\n", rc);
918 goto enable_icl_changed_interrupt;
919 }
920 }
921
922override_suspend_config:
923 /* determine if override needs to be enforced */
924 override = true;
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530925 if (icl_ua == INT_MAX) {
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800926 /* remove override if no voters - hw defaults is desired */
927 override = false;
Nicholas Troaste1932e42017-04-12 12:38:18 -0700928 } else if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
Fenglin Wu80826e02017-04-25 21:45:08 +0800929 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800930 /* For std cable with type = SDP never override */
931 override = false;
Fenglin Wu80826e02017-04-25 21:45:08 +0800932 else if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_CDP
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -0700933 && icl_ua == 1500000)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800934 /*
935 * For std cable with type = CDP override only if
936 * current is not 1500mA
937 */
938 override = false;
939 }
940
941 /* enforce override */
942 rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
943 USBIN_MODE_CHG_BIT, override ? USBIN_MODE_CHG_BIT : 0);
944
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800945 rc = smblib_icl_override(chg, override);
946 if (rc < 0) {
947 smblib_err(chg, "Couldn't set ICL override rc=%d\n", rc);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800948 goto enable_icl_changed_interrupt;
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800949 }
950
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800951 /* unsuspend after configuring current and override */
952 rc = smblib_set_usb_suspend(chg, false);
953 if (rc < 0) {
954 smblib_err(chg, "Couldn't resume input rc=%d\n", rc);
955 goto enable_icl_changed_interrupt;
956 }
957
958enable_icl_changed_interrupt:
Nicholas Troast34db5032016-03-28 12:26:44 -0700959 return rc;
960}
961
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700962int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua)
963{
964 int rc = 0;
965 u8 load_cfg;
966 bool override;
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700967
Nicholas Troaste1932e42017-04-12 12:38:18 -0700968 if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700969 || chg->micro_usb_mode)
970 && (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)) {
971 rc = get_sdp_current(chg, icl_ua);
972 if (rc < 0) {
973 smblib_err(chg, "Couldn't get SDP ICL rc=%d\n", rc);
974 return rc;
975 }
976 } else {
977 rc = smblib_read(chg, USBIN_LOAD_CFG_REG, &load_cfg);
978 if (rc < 0) {
979 smblib_err(chg, "Couldn't get load cfg rc=%d\n", rc);
980 return rc;
981 }
982 override = load_cfg & ICL_OVERRIDE_AFTER_APSD_BIT;
983 if (!override)
984 return INT_MAX;
985
986 /* override is set */
987 rc = smblib_get_charge_param(chg, &chg->param.usb_icl, icl_ua);
988 if (rc < 0) {
989 smblib_err(chg, "Couldn't get HC ICL rc=%d\n", rc);
990 return rc;
991 }
992 }
993
994 return 0;
995}
996
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530997/*********************
998 * VOTABLE CALLBACKS *
999 *********************/
1000
1001static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data,
1002 int suspend, const char *client)
1003{
1004 struct smb_charger *chg = data;
1005
1006 /* resume input if suspend is invalid */
1007 if (suspend < 0)
1008 suspend = 0;
1009
1010 return smblib_set_dc_suspend(chg, (bool)suspend);
1011}
1012
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001013static int smblib_dc_icl_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -07001014 int icl_ua, const char *client)
Nicholas Troast34db5032016-03-28 12:26:44 -07001015{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001016 struct smb_charger *chg = data;
Nicholas Troast34db5032016-03-28 12:26:44 -07001017 int rc = 0;
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001018 bool suspend;
1019
1020 if (icl_ua < 0) {
1021 smblib_dbg(chg, PR_MISC, "No Voter hence suspending\n");
1022 icl_ua = 0;
1023 }
1024
1025 suspend = (icl_ua < USBIN_25MA);
1026 if (suspend)
1027 goto suspend;
Nicholas Troast34db5032016-03-28 12:26:44 -07001028
1029 rc = smblib_set_charge_param(chg, &chg->param.dc_icl, icl_ua);
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001030 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001031 smblib_err(chg, "Couldn't set DC input current limit rc=%d\n",
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001032 rc);
1033 return rc;
1034 }
1035
1036suspend:
1037 rc = vote(chg->dc_suspend_votable, USER_VOTER, suspend, 0);
1038 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001039 smblib_err(chg, "Couldn't vote to %s DC rc=%d\n",
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001040 suspend ? "suspend" : "resume", rc);
1041 return rc;
1042 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001043 return rc;
1044}
1045
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07001046static int smblib_pd_disallowed_votable_indirect_callback(
1047 struct votable *votable, void *data, int disallowed, const char *client)
1048{
1049 struct smb_charger *chg = data;
1050 int rc;
1051
1052 rc = vote(chg->pd_allowed_votable, PD_DISALLOWED_INDIRECT_VOTER,
1053 !disallowed, 0);
1054
1055 return rc;
1056}
1057
Harry Yang223c6282016-06-14 15:48:36 -07001058static int smblib_awake_vote_callback(struct votable *votable, void *data,
1059 int awake, const char *client)
1060{
1061 struct smb_charger *chg = data;
1062
1063 if (awake)
1064 pm_stay_awake(chg->dev);
1065 else
1066 pm_relax(chg->dev);
1067
1068 return 0;
1069}
1070
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07001071static int smblib_chg_disable_vote_callback(struct votable *votable, void *data,
1072 int chg_disable, const char *client)
1073{
1074 struct smb_charger *chg = data;
1075 int rc;
1076
1077 rc = smblib_masked_write(chg, CHARGING_ENABLE_CMD_REG,
1078 CHARGING_ENABLE_CMD_BIT,
1079 chg_disable ? 0 : CHARGING_ENABLE_CMD_BIT);
1080 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001081 smblib_err(chg, "Couldn't %s charging rc=%d\n",
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07001082 chg_disable ? "disable" : "enable", rc);
1083 return rc;
1084 }
1085
1086 return 0;
1087}
Harry Yangaba1f5f2016-09-28 10:47:29 -07001088
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301089static int smblib_hvdcp_enable_vote_callback(struct votable *votable,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001090 void *data,
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301091 int hvdcp_enable, const char *client)
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001092{
1093 struct smb_charger *chg = data;
1094 int rc;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301095 u8 val = HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_EN_BIT;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07001096 u8 stat;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301097
1098 /* vote to enable/disable HW autonomous INOV */
1099 vote(chg->hvdcp_hw_inov_dis_votable, client, !hvdcp_enable, 0);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001100
1101 /*
1102 * Disable the autonomous bit and auth bit for disabling hvdcp.
1103 * This ensures only qc 2.0 detection runs but no vbus
1104 * negotiation happens.
1105 */
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301106 if (!hvdcp_enable)
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001107 val = HVDCP_EN_BIT;
1108
1109 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301110 HVDCP_EN_BIT | HVDCP_AUTH_ALG_EN_CFG_BIT,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001111 val);
1112 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001113 smblib_err(chg, "Couldn't %s hvdcp rc=%d\n",
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301114 hvdcp_enable ? "enable" : "disable", rc);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001115 return rc;
1116 }
1117
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07001118 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
1119 if (rc < 0) {
1120 smblib_err(chg, "Couldn't read APSD status rc=%d\n", rc);
1121 return rc;
1122 }
1123
1124 /* re-run APSD if HVDCP was detected */
1125 if (stat & QC_CHARGER_BIT)
1126 smblib_rerun_apsd(chg);
1127
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001128 return 0;
1129}
1130
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301131static int smblib_hvdcp_disable_indirect_vote_callback(struct votable *votable,
1132 void *data, int hvdcp_disable, const char *client)
1133{
1134 struct smb_charger *chg = data;
1135
1136 vote(chg->hvdcp_enable_votable, HVDCP_INDIRECT_VOTER,
1137 !hvdcp_disable, 0);
1138
1139 return 0;
1140}
1141
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07001142static int smblib_apsd_disable_vote_callback(struct votable *votable,
1143 void *data,
1144 int apsd_disable, const char *client)
1145{
1146 struct smb_charger *chg = data;
1147 int rc;
1148
Nicholas Troastec4703c2017-01-30 14:52:33 -08001149 if (apsd_disable) {
Nicholas Troastec4703c2017-01-30 14:52:33 -08001150 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1151 AUTO_SRC_DETECT_BIT,
1152 0);
1153 if (rc < 0) {
1154 smblib_err(chg, "Couldn't disable APSD rc=%d\n", rc);
1155 return rc;
1156 }
1157 } else {
1158 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1159 AUTO_SRC_DETECT_BIT,
1160 AUTO_SRC_DETECT_BIT);
1161 if (rc < 0) {
1162 smblib_err(chg, "Couldn't enable APSD rc=%d\n", rc);
1163 return rc;
1164 }
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07001165 }
1166
1167 return 0;
1168}
Nicholas Troast8995a702016-12-05 10:22:22 -08001169
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301170static int smblib_hvdcp_hw_inov_dis_vote_callback(struct votable *votable,
1171 void *data, int disable, const char *client)
1172{
1173 struct smb_charger *chg = data;
1174 int rc;
1175
1176 if (disable) {
1177 /*
1178 * the pulse count register get zeroed when autonomous mode is
1179 * disabled. Track that in variables before disabling
1180 */
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +05301181 rc = smblib_get_hw_pulse_cnt(chg, &chg->pulse_cnt);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301182 if (rc < 0) {
1183 pr_err("failed to read QC_PULSE_COUNT_STATUS_REG rc=%d\n",
1184 rc);
1185 return rc;
1186 }
1187 }
1188
1189 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1190 HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT,
1191 disable ? 0 : HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT);
1192 if (rc < 0) {
1193 smblib_err(chg, "Couldn't %s hvdcp rc=%d\n",
1194 disable ? "disable" : "enable", rc);
1195 return rc;
1196 }
1197
1198 return rc;
1199}
1200
Harry Yang4bf7d962017-03-13 16:51:43 -07001201static int smblib_usb_irq_enable_vote_callback(struct votable *votable,
1202 void *data, int enable, const char *client)
1203{
1204 struct smb_charger *chg = data;
1205
1206 if (!chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq ||
1207 !chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq)
1208 return 0;
1209
1210 if (enable) {
1211 enable_irq(chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq);
1212 enable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
1213 } else {
1214 disable_irq(chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq);
1215 disable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
1216 }
1217
1218 return 0;
1219}
1220
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07001221static int smblib_typec_irq_disable_vote_callback(struct votable *votable,
1222 void *data, int disable, const char *client)
1223{
1224 struct smb_charger *chg = data;
1225
1226 if (!chg->irq_info[TYPE_C_CHANGE_IRQ].irq)
1227 return 0;
1228
1229 if (disable)
1230 disable_irq_nosync(chg->irq_info[TYPE_C_CHANGE_IRQ].irq);
1231 else
1232 enable_irq(chg->irq_info[TYPE_C_CHANGE_IRQ].irq);
1233
1234 return 0;
1235}
1236
Nicholas Troast8995a702016-12-05 10:22:22 -08001237/*******************
1238 * VCONN REGULATOR *
1239 * *****************/
1240
Nicholas Troastb11015f2017-01-17 17:56:45 -08001241#define MAX_OTG_SS_TRIES 2
Nicholas Troast8995a702016-12-05 10:22:22 -08001242static int _smblib_vconn_regulator_enable(struct regulator_dev *rdev)
1243{
1244 struct smb_charger *chg = rdev_get_drvdata(rdev);
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001245 int rc = 0;
1246 u8 val;
Nicholas Troast8995a702016-12-05 10:22:22 -08001247
1248 /*
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001249 * When enabling VCONN using the command register the CC pin must be
1250 * selected. VCONN should be supplied to the inactive CC pin hence using
1251 * the opposite of the CC_ORIENTATION_BIT.
Nicholas Troast8995a702016-12-05 10:22:22 -08001252 */
Nicholas Troastb11015f2017-01-17 17:56:45 -08001253 smblib_dbg(chg, PR_OTG, "enabling VCONN\n");
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07001254 val = chg->typec_status[3] &
1255 CC_ORIENTATION_BIT ? 0 : VCONN_EN_ORIENTATION_BIT;
Nicholas Troast8995a702016-12-05 10:22:22 -08001256 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1257 VCONN_EN_VALUE_BIT | VCONN_EN_ORIENTATION_BIT,
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07001258 VCONN_EN_VALUE_BIT | val);
Nicholas Troast8995a702016-12-05 10:22:22 -08001259 if (rc < 0) {
1260 smblib_err(chg, "Couldn't enable vconn setting rc=%d\n", rc);
1261 return rc;
1262 }
1263
1264 return rc;
1265}
1266
1267int smblib_vconn_regulator_enable(struct regulator_dev *rdev)
1268{
1269 struct smb_charger *chg = rdev_get_drvdata(rdev);
1270 int rc = 0;
1271
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001272 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001273 if (chg->vconn_en)
1274 goto unlock;
1275
1276 rc = _smblib_vconn_regulator_enable(rdev);
1277 if (rc >= 0)
1278 chg->vconn_en = true;
1279
1280unlock:
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001281 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001282 return rc;
1283}
1284
1285static int _smblib_vconn_regulator_disable(struct regulator_dev *rdev)
1286{
1287 struct smb_charger *chg = rdev_get_drvdata(rdev);
1288 int rc = 0;
1289
Nicholas Troastb11015f2017-01-17 17:56:45 -08001290 smblib_dbg(chg, PR_OTG, "disabling VCONN\n");
Nicholas Troast8995a702016-12-05 10:22:22 -08001291 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1292 VCONN_EN_VALUE_BIT, 0);
1293 if (rc < 0)
1294 smblib_err(chg, "Couldn't disable vconn regulator rc=%d\n", rc);
1295
1296 return rc;
1297}
1298
1299int smblib_vconn_regulator_disable(struct regulator_dev *rdev)
1300{
1301 struct smb_charger *chg = rdev_get_drvdata(rdev);
1302 int rc = 0;
1303
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001304 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001305 if (!chg->vconn_en)
1306 goto unlock;
1307
1308 rc = _smblib_vconn_regulator_disable(rdev);
1309 if (rc >= 0)
1310 chg->vconn_en = false;
1311
1312unlock:
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001313 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001314 return rc;
1315}
1316
1317int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev)
1318{
1319 struct smb_charger *chg = rdev_get_drvdata(rdev);
1320 int ret;
1321
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001322 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001323 ret = chg->vconn_en;
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001324 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001325 return ret;
1326}
1327
Nicholas Troast34db5032016-03-28 12:26:44 -07001328/*****************
1329 * OTG REGULATOR *
1330 *****************/
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301331#define MAX_RETRY 15
1332#define MIN_DELAY_US 2000
1333#define MAX_DELAY_US 9000
Anirudh Ghayaladf20da2017-07-03 10:52:29 +05301334static int otg_current[] = {250000, 500000, 1000000, 1500000};
1335static int smblib_enable_otg_wa(struct smb_charger *chg)
1336{
1337 u8 stat;
1338 int rc, i, retry_count = 0, min_delay = MIN_DELAY_US;
1339
1340 for (i = 0; i < ARRAY_SIZE(otg_current); i++) {
1341 smblib_dbg(chg, PR_OTG, "enabling OTG with %duA\n",
1342 otg_current[i]);
1343 rc = smblib_set_charge_param(chg, &chg->param.otg_cl,
1344 otg_current[i]);
1345 if (rc < 0) {
1346 smblib_err(chg, "Couldn't set otg limit rc=%d\n", rc);
1347 return rc;
1348 }
1349
1350 rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT);
1351 if (rc < 0) {
1352 smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc);
1353 return rc;
1354 }
1355
1356 retry_count = 0;
1357 min_delay = MIN_DELAY_US;
1358 do {
1359 usleep_range(min_delay, min_delay + 100);
1360 rc = smblib_read(chg, OTG_STATUS_REG, &stat);
1361 if (rc < 0) {
1362 smblib_err(chg, "Couldn't read OTG status rc=%d\n",
1363 rc);
1364 goto out;
1365 }
1366
1367 if (stat & BOOST_SOFTSTART_DONE_BIT) {
1368 rc = smblib_set_charge_param(chg,
1369 &chg->param.otg_cl, chg->otg_cl_ua);
1370 if (rc < 0) {
1371 smblib_err(chg, "Couldn't set otg limit rc=%d\n",
1372 rc);
1373 goto out;
1374 }
1375 break;
1376 }
1377 /* increase the delay for following iterations */
1378 if (retry_count > 5)
1379 min_delay = MAX_DELAY_US;
1380
1381 } while (retry_count++ < MAX_RETRY);
1382
1383 if (retry_count >= MAX_RETRY) {
1384 smblib_dbg(chg, PR_OTG, "OTG enable failed with %duA\n",
1385 otg_current[i]);
1386 rc = smblib_write(chg, CMD_OTG_REG, 0);
1387 if (rc < 0) {
1388 smblib_err(chg, "disable OTG rc=%d\n", rc);
1389 goto out;
1390 }
1391 } else {
1392 smblib_dbg(chg, PR_OTG, "OTG enabled\n");
1393 return 0;
1394 }
1395 }
1396
1397 if (i == ARRAY_SIZE(otg_current)) {
1398 rc = -EINVAL;
1399 goto out;
1400 }
1401
1402 return 0;
1403out:
1404 smblib_write(chg, CMD_OTG_REG, 0);
1405 return rc;
1406}
1407
Nicholas Troast8995a702016-12-05 10:22:22 -08001408static int _smblib_vbus_regulator_enable(struct regulator_dev *rdev)
Nicholas Troast34db5032016-03-28 12:26:44 -07001409{
1410 struct smb_charger *chg = rdev_get_drvdata(rdev);
Anirudh Ghayaladf20da2017-07-03 10:52:29 +05301411 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001412
Nicholas Troastb11015f2017-01-17 17:56:45 -08001413 smblib_dbg(chg, PR_OTG, "halt 1 in 8 mode\n");
Harry Yang360bd532016-09-26 11:03:22 -07001414 rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
1415 ENG_BUCKBOOST_HALT1_8_MODE_BIT,
1416 ENG_BUCKBOOST_HALT1_8_MODE_BIT);
1417 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001418 smblib_err(chg, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n",
Harry Yang360bd532016-09-26 11:03:22 -07001419 rc);
1420 return rc;
1421 }
1422
Nicholas Troastb11015f2017-01-17 17:56:45 -08001423 smblib_dbg(chg, PR_OTG, "enabling OTG\n");
Harry Yang360bd532016-09-26 11:03:22 -07001424
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301425 if (chg->wa_flags & OTG_WA) {
Anirudh Ghayaladf20da2017-07-03 10:52:29 +05301426 rc = smblib_enable_otg_wa(chg);
1427 if (rc < 0)
1428 smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc);
1429 } else {
1430 rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT);
1431 if (rc < 0)
1432 smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc);
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301433 }
1434
Nicholas Troast34db5032016-03-28 12:26:44 -07001435 return rc;
1436}
1437
Nicholas Troast8995a702016-12-05 10:22:22 -08001438int smblib_vbus_regulator_enable(struct regulator_dev *rdev)
Nicholas Troast34db5032016-03-28 12:26:44 -07001439{
1440 struct smb_charger *chg = rdev_get_drvdata(rdev);
1441 int rc = 0;
1442
Nicholas Troastb11015f2017-01-17 17:56:45 -08001443 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001444 if (chg->otg_en)
1445 goto unlock;
1446
Harry Yanga2fb0e32017-03-22 22:45:25 -07001447 if (!chg->usb_icl_votable) {
1448 chg->usb_icl_votable = find_votable("USB_ICL");
1449
1450 if (!chg->usb_icl_votable)
1451 return -EINVAL;
1452 }
1453 vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, true, 0);
1454
Nicholas Troast8995a702016-12-05 10:22:22 -08001455 rc = _smblib_vbus_regulator_enable(rdev);
1456 if (rc >= 0)
1457 chg->otg_en = true;
1458
1459unlock:
Nicholas Troastb11015f2017-01-17 17:56:45 -08001460 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001461 return rc;
1462}
1463
1464static int _smblib_vbus_regulator_disable(struct regulator_dev *rdev)
1465{
1466 struct smb_charger *chg = rdev_get_drvdata(rdev);
1467 int rc;
Nicholas Troast8995a702016-12-05 10:22:22 -08001468
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301469 if (chg->wa_flags & OTG_WA) {
1470 /* set OTG current limit to minimum value */
1471 rc = smblib_set_charge_param(chg, &chg->param.otg_cl,
1472 chg->param.otg_cl.min_u);
1473 if (rc < 0) {
1474 smblib_err(chg,
1475 "Couldn't set otg current limit rc=%d\n", rc);
1476 return rc;
1477 }
1478 }
1479
Nicholas Troastb11015f2017-01-17 17:56:45 -08001480 smblib_dbg(chg, PR_OTG, "disabling OTG\n");
Harry Yang360bd532016-09-26 11:03:22 -07001481 rc = smblib_write(chg, CMD_OTG_REG, 0);
1482 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001483 smblib_err(chg, "Couldn't disable OTG regulator rc=%d\n", rc);
Harry Yang360bd532016-09-26 11:03:22 -07001484 return rc;
1485 }
1486
Nicholas Troastb11015f2017-01-17 17:56:45 -08001487 smblib_dbg(chg, PR_OTG, "start 1 in 8 mode\n");
Harry Yang360bd532016-09-26 11:03:22 -07001488 rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
1489 ENG_BUCKBOOST_HALT1_8_MODE_BIT, 0);
1490 if (rc < 0) {
Nicholas Troast8995a702016-12-05 10:22:22 -08001491 smblib_err(chg, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n", rc);
Harry Yang360bd532016-09-26 11:03:22 -07001492 return rc;
1493 }
1494
Nicholas Troast8995a702016-12-05 10:22:22 -08001495 return 0;
1496}
Nicholas Troast34db5032016-03-28 12:26:44 -07001497
Nicholas Troast8995a702016-12-05 10:22:22 -08001498int smblib_vbus_regulator_disable(struct regulator_dev *rdev)
1499{
1500 struct smb_charger *chg = rdev_get_drvdata(rdev);
1501 int rc = 0;
1502
Nicholas Troastb11015f2017-01-17 17:56:45 -08001503 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001504 if (!chg->otg_en)
1505 goto unlock;
1506
1507 rc = _smblib_vbus_regulator_disable(rdev);
1508 if (rc >= 0)
1509 chg->otg_en = false;
1510
Harry Yanga2fb0e32017-03-22 22:45:25 -07001511 if (chg->usb_icl_votable)
1512 vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0);
Nicholas Troast8995a702016-12-05 10:22:22 -08001513unlock:
Nicholas Troastb11015f2017-01-17 17:56:45 -08001514 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07001515 return rc;
1516}
1517
1518int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev)
1519{
1520 struct smb_charger *chg = rdev_get_drvdata(rdev);
Nicholas Troast8995a702016-12-05 10:22:22 -08001521 int ret;
Nicholas Troast34db5032016-03-28 12:26:44 -07001522
Nicholas Troastb11015f2017-01-17 17:56:45 -08001523 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001524 ret = chg->otg_en;
Nicholas Troastb11015f2017-01-17 17:56:45 -08001525 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001526 return ret;
Nicholas Troast34db5032016-03-28 12:26:44 -07001527}
1528
1529/********************
1530 * BATT PSY GETTERS *
1531 ********************/
1532
1533int smblib_get_prop_input_suspend(struct smb_charger *chg,
1534 union power_supply_propval *val)
1535{
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08001536 val->intval
1537 = (get_client_vote(chg->usb_icl_votable, USER_VOTER) == 0)
1538 && get_client_vote(chg->dc_suspend_votable, USER_VOTER);
Nicholas Troast34db5032016-03-28 12:26:44 -07001539 return 0;
1540}
1541
1542int smblib_get_prop_batt_present(struct smb_charger *chg,
1543 union power_supply_propval *val)
1544{
1545 int rc;
1546 u8 stat;
1547
1548 rc = smblib_read(chg, BATIF_BASE + INT_RT_STS_OFFSET, &stat);
1549 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001550 smblib_err(chg, "Couldn't read BATIF_INT_RT_STS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07001551 return rc;
1552 }
1553
1554 val->intval = !(stat & (BAT_THERM_OR_ID_MISSING_RT_STS_BIT
1555 | BAT_TERMINAL_MISSING_RT_STS_BIT));
1556
1557 return rc;
1558}
1559
1560int smblib_get_prop_batt_capacity(struct smb_charger *chg,
1561 union power_supply_propval *val)
1562{
Harry Yang5e1a5222016-07-26 15:16:04 -07001563 int rc = -EINVAL;
1564
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07001565 if (chg->fake_capacity >= 0) {
1566 val->intval = chg->fake_capacity;
1567 return 0;
1568 }
1569
Harry Yang5e1a5222016-07-26 15:16:04 -07001570 if (chg->bms_psy)
1571 rc = power_supply_get_property(chg->bms_psy,
1572 POWER_SUPPLY_PROP_CAPACITY, val);
1573 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001574}
1575
1576int smblib_get_prop_batt_status(struct smb_charger *chg,
1577 union power_supply_propval *val)
1578{
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001579 union power_supply_propval pval = {0, };
1580 bool usb_online, dc_online;
Nicholas Troast8cb77552016-09-23 11:50:18 -07001581 u8 stat;
1582 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001583
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001584 rc = smblib_get_prop_usb_online(chg, &pval);
1585 if (rc < 0) {
1586 smblib_err(chg, "Couldn't get usb online property rc=%d\n",
1587 rc);
1588 return rc;
1589 }
1590 usb_online = (bool)pval.intval;
1591
1592 rc = smblib_get_prop_dc_online(chg, &pval);
1593 if (rc < 0) {
1594 smblib_err(chg, "Couldn't get dc online property rc=%d\n",
1595 rc);
1596 return rc;
1597 }
1598 dc_online = (bool)pval.intval;
1599
Nicholas Troast34db5032016-03-28 12:26:44 -07001600 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1601 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001602 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001603 rc);
1604 return rc;
1605 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001606 stat = stat & BATTERY_CHARGER_STATUS_MASK;
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001607
1608 if (!usb_online && !dc_online) {
1609 switch (stat) {
1610 case TERMINATE_CHARGE:
1611 case INHIBIT_CHARGE:
1612 val->intval = POWER_SUPPLY_STATUS_FULL;
1613 break;
1614 default:
1615 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
1616 break;
1617 }
1618 return rc;
1619 }
1620
Nicholas Troast8cb77552016-09-23 11:50:18 -07001621 switch (stat) {
1622 case TRICKLE_CHARGE:
1623 case PRE_CHARGE:
1624 case FAST_CHARGE:
1625 case FULLON_CHARGE:
1626 case TAPER_CHARGE:
Nicholas Troast34db5032016-03-28 12:26:44 -07001627 val->intval = POWER_SUPPLY_STATUS_CHARGING;
Nicholas Troast8cb77552016-09-23 11:50:18 -07001628 break;
1629 case TERMINATE_CHARGE:
1630 case INHIBIT_CHARGE:
1631 val->intval = POWER_SUPPLY_STATUS_FULL;
1632 break;
1633 case DISABLE_CHARGE:
1634 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
1635 break;
1636 default:
1637 val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
1638 break;
1639 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001640
Harry Yang7ecc1a12017-04-06 12:24:56 -07001641 if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
1642 return 0;
1643
Harry Yangc3c28d12017-04-17 16:41:19 -07001644 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_7_REG, &stat);
Harry Yang7ecc1a12017-04-06 12:24:56 -07001645 if (rc < 0) {
1646 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
1647 rc);
1648 return rc;
1649 }
1650
Harry Yangc3c28d12017-04-17 16:41:19 -07001651 stat &= ENABLE_TRICKLE_BIT | ENABLE_PRE_CHARGING_BIT |
1652 ENABLE_FAST_CHARGING_BIT | ENABLE_FULLON_MODE_BIT;
1653 if (!stat)
Harry Yang7ecc1a12017-04-06 12:24:56 -07001654 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
1655
Nicholas Troast8cb77552016-09-23 11:50:18 -07001656 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07001657}
1658
1659int smblib_get_prop_batt_charge_type(struct smb_charger *chg,
1660 union power_supply_propval *val)
1661{
1662 int rc;
1663 u8 stat;
1664
1665 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1666 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001667 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001668 rc);
1669 return rc;
1670 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001671
1672 switch (stat & BATTERY_CHARGER_STATUS_MASK) {
1673 case TRICKLE_CHARGE:
1674 case PRE_CHARGE:
1675 val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1676 break;
1677 case FAST_CHARGE:
1678 case FULLON_CHARGE:
1679 val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
1680 break;
1681 case TAPER_CHARGE:
1682 val->intval = POWER_SUPPLY_CHARGE_TYPE_TAPER;
1683 break;
1684 default:
1685 val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
1686 }
1687
1688 return rc;
1689}
1690
1691int smblib_get_prop_batt_health(struct smb_charger *chg,
1692 union power_supply_propval *val)
1693{
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001694 union power_supply_propval pval;
Nicholas Troast34db5032016-03-28 12:26:44 -07001695 int rc;
Abhijeet Dharmapurikar33d18462017-05-15 13:38:53 -07001696 int effective_fv_uv;
Nicholas Troast34db5032016-03-28 12:26:44 -07001697 u8 stat;
1698
1699 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat);
1700 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001701 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001702 rc);
1703 return rc;
1704 }
1705 smblib_dbg(chg, PR_REGISTER, "BATTERY_CHARGER_STATUS_2 = 0x%02x\n",
1706 stat);
1707
1708 if (stat & CHARGER_ERROR_STATUS_BAT_OV_BIT) {
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001709 rc = smblib_get_prop_batt_voltage_now(chg, &pval);
1710 if (!rc) {
1711 /*
1712 * If Vbatt is within 40mV above Vfloat, then don't
1713 * treat it as overvoltage.
1714 */
Abhijeet Dharmapurikar33d18462017-05-15 13:38:53 -07001715 effective_fv_uv = get_effective_result(chg->fv_votable);
1716 if (pval.intval >= effective_fv_uv + 40000) {
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001717 val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
Abhijeet Dharmapurikar33d18462017-05-15 13:38:53 -07001718 smblib_err(chg, "battery over-voltage vbat_fg = %duV, fv = %duV\n",
1719 pval.intval, effective_fv_uv);
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001720 goto done;
1721 }
1722 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001723 }
1724
Harry Yang668fc5e2016-07-12 16:51:47 -07001725 if (stat & BAT_TEMP_STATUS_TOO_COLD_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001726 val->intval = POWER_SUPPLY_HEALTH_COLD;
Harry Yang668fc5e2016-07-12 16:51:47 -07001727 else if (stat & BAT_TEMP_STATUS_TOO_HOT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001728 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
Harry Yang668fc5e2016-07-12 16:51:47 -07001729 else if (stat & BAT_TEMP_STATUS_COLD_SOFT_LIMIT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001730 val->intval = POWER_SUPPLY_HEALTH_COOL;
Harry Yang668fc5e2016-07-12 16:51:47 -07001731 else if (stat & BAT_TEMP_STATUS_HOT_SOFT_LIMIT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001732 val->intval = POWER_SUPPLY_HEALTH_WARM;
Harry Yang668fc5e2016-07-12 16:51:47 -07001733 else
Nicholas Troast34db5032016-03-28 12:26:44 -07001734 val->intval = POWER_SUPPLY_HEALTH_GOOD;
Nicholas Troast34db5032016-03-28 12:26:44 -07001735
1736done:
1737 return rc;
1738}
1739
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001740int smblib_get_prop_system_temp_level(struct smb_charger *chg,
1741 union power_supply_propval *val)
1742{
1743 val->intval = chg->system_temp_level;
1744 return 0;
1745}
1746
Abhijeet Dharmapurikaracf32002017-05-11 11:54:17 -07001747int smblib_get_prop_system_temp_level_max(struct smb_charger *chg,
1748 union power_supply_propval *val)
1749{
1750 val->intval = chg->thermal_levels;
1751 return 0;
1752}
1753
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001754int smblib_get_prop_input_current_limited(struct smb_charger *chg,
1755 union power_supply_propval *val)
1756{
1757 u8 stat;
1758 int rc;
1759
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07001760 if (chg->fake_input_current_limited >= 0) {
1761 val->intval = chg->fake_input_current_limited;
1762 return 0;
1763 }
1764
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001765 rc = smblib_read(chg, AICL_STATUS_REG, &stat);
1766 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001767 smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n", rc);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001768 return rc;
1769 }
1770 val->intval = (stat & SOFT_ILIMIT_BIT) || chg->is_hdc;
1771 return 0;
1772}
1773
Nicholas Troast66b21d72016-09-20 15:33:20 -07001774int smblib_get_prop_batt_voltage_now(struct smb_charger *chg,
1775 union power_supply_propval *val)
1776{
1777 int rc;
1778
1779 if (!chg->bms_psy)
1780 return -EINVAL;
1781
1782 rc = power_supply_get_property(chg->bms_psy,
1783 POWER_SUPPLY_PROP_VOLTAGE_NOW, val);
1784 return rc;
1785}
1786
1787int smblib_get_prop_batt_current_now(struct smb_charger *chg,
1788 union power_supply_propval *val)
1789{
1790 int rc;
1791
1792 if (!chg->bms_psy)
1793 return -EINVAL;
1794
1795 rc = power_supply_get_property(chg->bms_psy,
1796 POWER_SUPPLY_PROP_CURRENT_NOW, val);
1797 return rc;
1798}
1799
1800int smblib_get_prop_batt_temp(struct smb_charger *chg,
1801 union power_supply_propval *val)
1802{
1803 int rc;
1804
1805 if (!chg->bms_psy)
1806 return -EINVAL;
1807
1808 rc = power_supply_get_property(chg->bms_psy,
1809 POWER_SUPPLY_PROP_TEMP, val);
1810 return rc;
1811}
1812
Harry Yangbedee332016-08-31 16:14:29 -07001813int smblib_get_prop_step_chg_step(struct smb_charger *chg,
1814 union power_supply_propval *val)
1815{
1816 int rc;
1817 u8 stat;
1818
1819 if (!chg->step_chg_enabled) {
1820 val->intval = -1;
1821 return 0;
1822 }
1823
1824 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1825 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001826 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Harry Yangbedee332016-08-31 16:14:29 -07001827 rc);
1828 return rc;
1829 }
1830
1831 val->intval = (stat & STEP_CHARGING_STATUS_MASK) >>
1832 STEP_CHARGING_STATUS_SHIFT;
1833
1834 return rc;
1835}
1836
Subbaraman Narayanamurthyb491d022016-10-10 20:22:48 -07001837int smblib_get_prop_batt_charge_done(struct smb_charger *chg,
1838 union power_supply_propval *val)
1839{
1840 int rc;
1841 u8 stat;
1842
1843 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1844 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001845 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Subbaraman Narayanamurthyb491d022016-10-10 20:22:48 -07001846 rc);
1847 return rc;
1848 }
1849
1850 stat = stat & BATTERY_CHARGER_STATUS_MASK;
1851 val->intval = (stat == TERMINATE_CHARGE);
1852 return 0;
1853}
1854
Harry Yang40192cb2017-02-25 23:25:17 -08001855int smblib_get_prop_charge_qnovo_enable(struct smb_charger *chg,
1856 union power_supply_propval *val)
1857{
1858 int rc;
1859 u8 stat;
1860
1861 rc = smblib_read(chg, QNOVO_PT_ENABLE_CMD_REG, &stat);
1862 if (rc < 0) {
1863 smblib_err(chg, "Couldn't read QNOVO_PT_ENABLE_CMD rc=%d\n",
1864 rc);
1865 return rc;
1866 }
1867
1868 val->intval = (bool)(stat & QNOVO_PT_ENABLE_CMD_BIT);
1869 return 0;
1870}
1871
Nicholas Troast34db5032016-03-28 12:26:44 -07001872/***********************
1873 * BATTERY PSY SETTERS *
1874 ***********************/
1875
1876int smblib_set_prop_input_suspend(struct smb_charger *chg,
1877 const union power_supply_propval *val)
1878{
1879 int rc;
1880
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08001881 /* vote 0mA when suspended */
1882 rc = vote(chg->usb_icl_votable, USER_VOTER, (bool)val->intval, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07001883 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001884 smblib_err(chg, "Couldn't vote to %s USB rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001885 (bool)val->intval ? "suspend" : "resume", rc);
1886 return rc;
1887 }
1888
1889 rc = vote(chg->dc_suspend_votable, USER_VOTER, (bool)val->intval, 0);
1890 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001891 smblib_err(chg, "Couldn't vote to %s DC rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001892 (bool)val->intval ? "suspend" : "resume", rc);
1893 return rc;
1894 }
1895
Nicholas Troast61ff40f2016-07-08 10:59:22 -07001896 power_supply_changed(chg->batt_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07001897 return rc;
1898}
1899
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07001900int smblib_set_prop_batt_capacity(struct smb_charger *chg,
1901 const union power_supply_propval *val)
1902{
1903 chg->fake_capacity = val->intval;
1904
1905 power_supply_changed(chg->batt_psy);
1906
1907 return 0;
1908}
1909
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001910int smblib_set_prop_system_temp_level(struct smb_charger *chg,
1911 const union power_supply_propval *val)
1912{
1913 if (val->intval < 0)
1914 return -EINVAL;
1915
1916 if (chg->thermal_levels <= 0)
1917 return -EINVAL;
1918
1919 if (val->intval > chg->thermal_levels)
1920 return -EINVAL;
1921
1922 chg->system_temp_level = val->intval;
Ashay Jaiswal147a6c32017-03-28 17:19:47 +05301923 /* disable parallel charge in case of system temp level */
1924 vote(chg->pl_disable_votable, THERMAL_DAEMON_VOTER,
1925 chg->system_temp_level ? true : false, 0);
1926
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001927 if (chg->system_temp_level == chg->thermal_levels)
Harry Yangaba1f5f2016-09-28 10:47:29 -07001928 return vote(chg->chg_disable_votable,
1929 THERMAL_DAEMON_VOTER, true, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001930
Harry Yangaba1f5f2016-09-28 10:47:29 -07001931 vote(chg->chg_disable_votable, THERMAL_DAEMON_VOTER, false, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001932 if (chg->system_temp_level == 0)
Harry Yangaba1f5f2016-09-28 10:47:29 -07001933 return vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, false, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001934
Harry Yangaba1f5f2016-09-28 10:47:29 -07001935 vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, true,
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001936 chg->thermal_mitigation[chg->system_temp_level]);
1937 return 0;
1938}
1939
Harry Yang40192cb2017-02-25 23:25:17 -08001940int smblib_set_prop_charge_qnovo_enable(struct smb_charger *chg,
1941 const union power_supply_propval *val)
1942{
1943 int rc = 0;
1944
1945 rc = smblib_masked_write(chg, QNOVO_PT_ENABLE_CMD_REG,
1946 QNOVO_PT_ENABLE_CMD_BIT,
1947 val->intval ? QNOVO_PT_ENABLE_CMD_BIT : 0);
1948 if (rc < 0) {
1949 dev_err(chg->dev, "Couldn't enable qnovo rc=%d\n", rc);
1950 return rc;
1951 }
1952
1953 return rc;
1954}
1955
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07001956int smblib_set_prop_input_current_limited(struct smb_charger *chg,
1957 const union power_supply_propval *val)
1958{
1959 chg->fake_input_current_limited = val->intval;
1960 return 0;
1961}
1962
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301963int smblib_rerun_aicl(struct smb_charger *chg)
1964{
Nicholas Troast20ae1912017-02-15 10:15:32 -08001965 int rc, settled_icl_ua;
1966 u8 stat;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301967
Nicholas Troast20ae1912017-02-15 10:15:32 -08001968 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
1969 if (rc < 0) {
1970 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
1971 rc);
1972 return rc;
1973 }
1974
1975 /* USB is suspended so skip re-running AICL */
1976 if (stat & USBIN_SUSPEND_STS_BIT)
1977 return rc;
1978
1979 smblib_dbg(chg, PR_MISC, "re-running AICL\n");
Ashay Jaiswal59a14122017-05-16 13:38:52 +05301980 rc = smblib_get_charge_param(chg, &chg->param.icl_stat,
1981 &settled_icl_ua);
1982 if (rc < 0) {
1983 smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
1984 return rc;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301985 }
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301986
Ashay Jaiswal59a14122017-05-16 13:38:52 +05301987 vote(chg->usb_icl_votable, AICL_RERUN_VOTER, true,
1988 max(settled_icl_ua - chg->param.usb_icl.step_u,
1989 chg->param.usb_icl.step_u));
1990 vote(chg->usb_icl_votable, AICL_RERUN_VOTER, false, 0);
1991
Nicholas Troast20ae1912017-02-15 10:15:32 -08001992 return 0;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301993}
1994
1995static int smblib_dp_pulse(struct smb_charger *chg)
1996{
1997 int rc;
1998
1999 /* QC 3.0 increment */
2000 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, SINGLE_INCREMENT_BIT,
2001 SINGLE_INCREMENT_BIT);
2002 if (rc < 0)
2003 smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
2004 rc);
2005
2006 return rc;
2007}
2008
2009static int smblib_dm_pulse(struct smb_charger *chg)
2010{
2011 int rc;
2012
2013 /* QC 3.0 decrement */
2014 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, SINGLE_DECREMENT_BIT,
2015 SINGLE_DECREMENT_BIT);
2016 if (rc < 0)
2017 smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
2018 rc);
2019
2020 return rc;
2021}
2022
2023int smblib_dp_dm(struct smb_charger *chg, int val)
2024{
2025 int target_icl_ua, rc = 0;
Ashay Jaiswalae23a042017-05-18 15:28:31 +05302026 union power_supply_propval pval;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302027
2028 switch (val) {
2029 case POWER_SUPPLY_DP_DM_DP_PULSE:
2030 rc = smblib_dp_pulse(chg);
2031 if (!rc)
2032 chg->pulse_cnt++;
2033 smblib_dbg(chg, PR_PARALLEL, "DP_DM_DP_PULSE rc=%d cnt=%d\n",
2034 rc, chg->pulse_cnt);
2035 break;
2036 case POWER_SUPPLY_DP_DM_DM_PULSE:
2037 rc = smblib_dm_pulse(chg);
2038 if (!rc && chg->pulse_cnt)
2039 chg->pulse_cnt--;
2040 smblib_dbg(chg, PR_PARALLEL, "DP_DM_DM_PULSE rc=%d cnt=%d\n",
2041 rc, chg->pulse_cnt);
2042 break;
2043 case POWER_SUPPLY_DP_DM_ICL_DOWN:
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302044 target_icl_ua = get_effective_result(chg->usb_icl_votable);
Ashay Jaiswalae23a042017-05-18 15:28:31 +05302045 if (target_icl_ua < 0) {
2046 /* no client vote, get the ICL from charger */
2047 rc = power_supply_get_property(chg->usb_psy,
2048 POWER_SUPPLY_PROP_HW_CURRENT_MAX,
2049 &pval);
2050 if (rc < 0) {
2051 smblib_err(chg,
2052 "Couldn't get max current rc=%d\n",
2053 rc);
2054 return rc;
2055 }
2056 target_icl_ua = pval.intval;
2057 }
2058
2059 /*
2060 * Check if any other voter voted on USB_ICL in case of
2061 * voter other than SW_QC3_VOTER reset and restart reduction
2062 * again.
2063 */
2064 if (target_icl_ua != get_client_vote(chg->usb_icl_votable,
2065 SW_QC3_VOTER))
2066 chg->usb_icl_delta_ua = 0;
2067
2068 chg->usb_icl_delta_ua += 100000;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302069 vote(chg->usb_icl_votable, SW_QC3_VOTER, true,
Ashay Jaiswalae23a042017-05-18 15:28:31 +05302070 target_icl_ua - 100000);
2071 smblib_dbg(chg, PR_PARALLEL, "ICL DOWN ICL=%d reduction=%d\n",
2072 target_icl_ua, chg->usb_icl_delta_ua);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302073 break;
2074 case POWER_SUPPLY_DP_DM_ICL_UP:
2075 default:
2076 break;
2077 }
2078
2079 return rc;
2080}
2081
Nicholas Troast34db5032016-03-28 12:26:44 -07002082/*******************
Harry Yangf3023592016-07-20 14:56:41 -07002083 * DC PSY GETTERS *
2084 *******************/
2085
2086int smblib_get_prop_dc_present(struct smb_charger *chg,
2087 union power_supply_propval *val)
2088{
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002089 int rc;
Harry Yangf3023592016-07-20 14:56:41 -07002090 u8 stat;
2091
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002092 rc = smblib_read(chg, DCIN_BASE + INT_RT_STS_OFFSET, &stat);
Harry Yangf3023592016-07-20 14:56:41 -07002093 if (rc < 0) {
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002094 smblib_err(chg, "Couldn't read DCIN_RT_STS rc=%d\n", rc);
Harry Yangf3023592016-07-20 14:56:41 -07002095 return rc;
2096 }
Harry Yangf3023592016-07-20 14:56:41 -07002097
2098 val->intval = (bool)(stat & DCIN_PLUGIN_RT_STS_BIT);
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002099 return 0;
Harry Yangf3023592016-07-20 14:56:41 -07002100}
2101
2102int smblib_get_prop_dc_online(struct smb_charger *chg,
2103 union power_supply_propval *val)
2104{
2105 int rc = 0;
2106 u8 stat;
2107
2108 if (get_client_vote(chg->dc_suspend_votable, USER_VOTER)) {
2109 val->intval = false;
2110 return rc;
2111 }
2112
2113 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
2114 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002115 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
Harry Yangf3023592016-07-20 14:56:41 -07002116 rc);
2117 return rc;
2118 }
2119 smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
2120 stat);
2121
2122 val->intval = (stat & USE_DCIN_BIT) &&
Vic Wei7ade2842016-12-14 18:47:49 -08002123 (stat & VALID_INPUT_POWER_SOURCE_STS_BIT);
Harry Yangf3023592016-07-20 14:56:41 -07002124
2125 return rc;
2126}
2127
2128int smblib_get_prop_dc_current_max(struct smb_charger *chg,
2129 union power_supply_propval *val)
2130{
2131 val->intval = get_effective_result_locked(chg->dc_icl_votable);
2132 return 0;
2133}
2134
2135/*******************
Harry Yangd89ff1f2016-12-05 14:59:11 -08002136 * DC PSY SETTERS *
Harry Yangf3023592016-07-20 14:56:41 -07002137 * *****************/
2138
2139int smblib_set_prop_dc_current_max(struct smb_charger *chg,
2140 const union power_supply_propval *val)
2141{
2142 int rc;
2143
2144 rc = vote(chg->dc_icl_votable, USER_VOTER, true, val->intval);
2145 return rc;
2146}
2147
2148/*******************
Nicholas Troast34db5032016-03-28 12:26:44 -07002149 * USB PSY GETTERS *
2150 *******************/
2151
2152int smblib_get_prop_usb_present(struct smb_charger *chg,
2153 union power_supply_propval *val)
2154{
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002155 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07002156 u8 stat;
2157
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002158 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
Nicholas Troast34db5032016-03-28 12:26:44 -07002159 if (rc < 0) {
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002160 smblib_err(chg, "Couldn't read USBIN_RT_STS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07002161 return rc;
2162 }
Nicholas Troast34db5032016-03-28 12:26:44 -07002163
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002164 val->intval = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
2165 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002166}
2167
2168int smblib_get_prop_usb_online(struct smb_charger *chg,
2169 union power_supply_propval *val)
2170{
2171 int rc = 0;
2172 u8 stat;
2173
Abhijeet Dharmapurikar84923af2017-03-23 14:07:07 -07002174 if (get_client_vote_locked(chg->usb_icl_votable, USER_VOTER) == 0) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002175 val->intval = false;
2176 return rc;
2177 }
2178
2179 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
2180 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002181 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002182 rc);
2183 return rc;
2184 }
2185 smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
2186 stat);
2187
2188 val->intval = (stat & USE_USBIN_BIT) &&
Vic Wei7ade2842016-12-14 18:47:49 -08002189 (stat & VALID_INPUT_POWER_SOURCE_STS_BIT);
Nicholas Troast34db5032016-03-28 12:26:44 -07002190 return rc;
2191}
2192
2193int smblib_get_prop_usb_voltage_now(struct smb_charger *chg,
2194 union power_supply_propval *val)
2195{
Harry Yangba874ce2016-08-19 14:17:01 -07002196 int rc = 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002197
Harry Yangba874ce2016-08-19 14:17:01 -07002198 rc = smblib_get_prop_usb_present(chg, val);
2199 if (rc < 0 || !val->intval)
2200 return rc;
2201
2202 if (!chg->iio.usbin_v_chan ||
2203 PTR_ERR(chg->iio.usbin_v_chan) == -EPROBE_DEFER)
2204 chg->iio.usbin_v_chan = iio_channel_get(chg->dev, "usbin_v");
2205
2206 if (IS_ERR(chg->iio.usbin_v_chan))
2207 return PTR_ERR(chg->iio.usbin_v_chan);
2208
2209 return iio_read_channel_processed(chg->iio.usbin_v_chan, &val->intval);
Nicholas Troast34db5032016-03-28 12:26:44 -07002210}
2211
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002212int smblib_get_prop_pd_current_max(struct smb_charger *chg,
2213 union power_supply_propval *val)
2214{
2215 val->intval = get_client_vote_locked(chg->usb_icl_votable, PD_VOTER);
2216 return 0;
2217}
2218
Nicholas Troast34db5032016-03-28 12:26:44 -07002219int smblib_get_prop_usb_current_max(struct smb_charger *chg,
2220 union power_supply_propval *val)
2221{
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002222 val->intval = get_client_vote_locked(chg->usb_icl_votable,
2223 USB_PSY_VOTER);
Nicholas Troast34db5032016-03-28 12:26:44 -07002224 return 0;
2225}
2226
Harry Yangba874ce2016-08-19 14:17:01 -07002227int smblib_get_prop_usb_current_now(struct smb_charger *chg,
2228 union power_supply_propval *val)
2229{
2230 int rc = 0;
2231
2232 rc = smblib_get_prop_usb_present(chg, val);
2233 if (rc < 0 || !val->intval)
2234 return rc;
2235
2236 if (!chg->iio.usbin_i_chan ||
2237 PTR_ERR(chg->iio.usbin_i_chan) == -EPROBE_DEFER)
2238 chg->iio.usbin_i_chan = iio_channel_get(chg->dev, "usbin_i");
2239
2240 if (IS_ERR(chg->iio.usbin_i_chan))
2241 return PTR_ERR(chg->iio.usbin_i_chan);
2242
2243 return iio_read_channel_processed(chg->iio.usbin_i_chan, &val->intval);
2244}
2245
2246int smblib_get_prop_charger_temp(struct smb_charger *chg,
2247 union power_supply_propval *val)
2248{
2249 int rc;
2250
2251 if (!chg->iio.temp_chan ||
2252 PTR_ERR(chg->iio.temp_chan) == -EPROBE_DEFER)
2253 chg->iio.temp_chan = iio_channel_get(chg->dev, "charger_temp");
2254
2255 if (IS_ERR(chg->iio.temp_chan))
2256 return PTR_ERR(chg->iio.temp_chan);
2257
2258 rc = iio_read_channel_processed(chg->iio.temp_chan, &val->intval);
2259 val->intval /= 100;
2260 return rc;
2261}
2262
2263int smblib_get_prop_charger_temp_max(struct smb_charger *chg,
2264 union power_supply_propval *val)
2265{
2266 int rc;
2267
2268 if (!chg->iio.temp_max_chan ||
2269 PTR_ERR(chg->iio.temp_max_chan) == -EPROBE_DEFER)
2270 chg->iio.temp_max_chan = iio_channel_get(chg->dev,
2271 "charger_temp_max");
2272 if (IS_ERR(chg->iio.temp_max_chan))
2273 return PTR_ERR(chg->iio.temp_max_chan);
2274
2275 rc = iio_read_channel_processed(chg->iio.temp_max_chan, &val->intval);
2276 val->intval /= 100;
2277 return rc;
2278}
2279
Nicholas Troast34db5032016-03-28 12:26:44 -07002280int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
2281 union power_supply_propval *val)
2282{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002283 if (chg->typec_status[3] & CC_ATTACHED_BIT)
2284 val->intval =
2285 (bool)(chg->typec_status[3] & CC_ORIENTATION_BIT) + 1;
Nicholas Troast34db5032016-03-28 12:26:44 -07002286 else
2287 val->intval = 0;
2288
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002289 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002290}
2291
2292static const char * const smblib_typec_mode_name[] = {
2293 [POWER_SUPPLY_TYPEC_NONE] = "NONE",
2294 [POWER_SUPPLY_TYPEC_SOURCE_DEFAULT] = "SOURCE_DEFAULT",
2295 [POWER_SUPPLY_TYPEC_SOURCE_MEDIUM] = "SOURCE_MEDIUM",
2296 [POWER_SUPPLY_TYPEC_SOURCE_HIGH] = "SOURCE_HIGH",
2297 [POWER_SUPPLY_TYPEC_NON_COMPLIANT] = "NON_COMPLIANT",
2298 [POWER_SUPPLY_TYPEC_SINK] = "SINK",
2299 [POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE] = "SINK_POWERED_CABLE",
2300 [POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY] = "SINK_DEBUG_ACCESSORY",
2301 [POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER] = "SINK_AUDIO_ADAPTER",
2302 [POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY] = "POWERED_CABLE_ONLY",
2303};
2304
2305static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
2306{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002307 switch (chg->typec_status[0]) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002308 case UFP_TYPEC_RDSTD_BIT:
2309 return POWER_SUPPLY_TYPEC_SOURCE_DEFAULT;
2310 case UFP_TYPEC_RD1P5_BIT:
2311 return POWER_SUPPLY_TYPEC_SOURCE_MEDIUM;
2312 case UFP_TYPEC_RD3P0_BIT:
2313 return POWER_SUPPLY_TYPEC_SOURCE_HIGH;
2314 default:
2315 break;
2316 }
2317
Nicholas Troaste1932e42017-04-12 12:38:18 -07002318 return POWER_SUPPLY_TYPEC_NONE;
Nicholas Troast34db5032016-03-28 12:26:44 -07002319}
2320
2321static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
2322{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002323 switch (chg->typec_status[1] & DFP_TYPEC_MASK) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002324 case DFP_RA_RA_BIT:
2325 return POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER;
2326 case DFP_RD_RD_BIT:
2327 return POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY;
2328 case DFP_RD_RA_VCONN_BIT:
2329 return POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE;
2330 case DFP_RD_OPEN_BIT:
2331 return POWER_SUPPLY_TYPEC_SINK;
Nicholas Troast34db5032016-03-28 12:26:44 -07002332 default:
2333 break;
2334 }
2335
2336 return POWER_SUPPLY_TYPEC_NONE;
2337}
2338
Nicholas Troaste1932e42017-04-12 12:38:18 -07002339static int smblib_get_prop_typec_mode(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07002340{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002341 if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
Nicholas Troaste1932e42017-04-12 12:38:18 -07002342 return smblib_get_prop_dfp_mode(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07002343 else
Nicholas Troaste1932e42017-04-12 12:38:18 -07002344 return smblib_get_prop_ufp_mode(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07002345}
2346
2347int smblib_get_prop_typec_power_role(struct smb_charger *chg,
2348 union power_supply_propval *val)
2349{
2350 int rc = 0;
2351 u8 ctrl;
2352
2353 rc = smblib_read(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &ctrl);
2354 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002355 smblib_err(chg, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002356 rc);
2357 return rc;
2358 }
2359 smblib_dbg(chg, PR_REGISTER, "TYPE_C_INTRPT_ENB_SOFTWARE_CTRL = 0x%02x\n",
2360 ctrl);
2361
2362 if (ctrl & TYPEC_DISABLE_CMD_BIT) {
2363 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
2364 return rc;
2365 }
2366
2367 switch (ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT)) {
2368 case 0:
2369 val->intval = POWER_SUPPLY_TYPEC_PR_DUAL;
2370 break;
2371 case DFP_EN_CMD_BIT:
2372 val->intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
2373 break;
2374 case UFP_EN_CMD_BIT:
2375 val->intval = POWER_SUPPLY_TYPEC_PR_SINK;
2376 break;
2377 default:
2378 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002379 smblib_err(chg, "unsupported power role 0x%02lx\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002380 ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT));
2381 return -EINVAL;
2382 }
2383
2384 return rc;
2385}
2386
2387int smblib_get_prop_pd_allowed(struct smb_charger *chg,
2388 union power_supply_propval *val)
2389{
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07002390 val->intval = get_effective_result(chg->pd_allowed_votable);
Nicholas Troast34db5032016-03-28 12:26:44 -07002391 return 0;
2392}
2393
Nicholas Troast133a7f52016-06-29 13:48:20 -07002394int smblib_get_prop_input_current_settled(struct smb_charger *chg,
2395 union power_supply_propval *val)
2396{
2397 return smblib_get_charge_param(chg, &chg->param.icl_stat, &val->intval);
2398}
2399
Fenglin Wuef4730e2017-01-11 18:16:25 +08002400#define HVDCP3_STEP_UV 200000
2401int smblib_get_prop_input_voltage_settled(struct smb_charger *chg,
2402 union power_supply_propval *val)
2403{
2404 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
2405 int rc, pulses;
Fenglin Wuef4730e2017-01-11 18:16:25 +08002406
2407 val->intval = MICRO_5V;
2408 if (apsd_result == NULL) {
2409 smblib_err(chg, "APSD result is NULL\n");
2410 return 0;
2411 }
2412
2413 switch (apsd_result->pst) {
2414 case POWER_SUPPLY_TYPE_USB_HVDCP_3:
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +05302415 rc = smblib_get_pulse_cnt(chg, &pulses);
Fenglin Wuef4730e2017-01-11 18:16:25 +08002416 if (rc < 0) {
2417 smblib_err(chg,
2418 "Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
2419 return 0;
2420 }
Fenglin Wuef4730e2017-01-11 18:16:25 +08002421 val->intval = MICRO_5V + HVDCP3_STEP_UV * pulses;
2422 break;
2423 default:
2424 val->intval = MICRO_5V;
2425 break;
2426 }
2427
2428 return 0;
2429}
2430
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002431int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg,
2432 union power_supply_propval *val)
2433{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002434 val->intval = chg->pd_hard_reset;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002435 return 0;
2436}
2437
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07002438int smblib_get_pe_start(struct smb_charger *chg,
2439 union power_supply_propval *val)
2440{
2441 /*
2442 * hvdcp timeout voter is the last one to allow pd. Use its vote
2443 * to indicate start of pe engine
2444 */
2445 val->intval
2446 = !get_client_vote_locked(chg->pd_disallowed_votable_indirect,
2447 HVDCP_TIMEOUT_VOTER);
2448 return 0;
2449}
2450
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002451int smblib_get_prop_die_health(struct smb_charger *chg,
Nicholas Troastb021dd92017-01-31 18:43:38 -08002452 union power_supply_propval *val)
2453{
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002454 int rc;
Nicholas Troastb021dd92017-01-31 18:43:38 -08002455 u8 stat;
2456
2457 rc = smblib_read(chg, TEMP_RANGE_STATUS_REG, &stat);
2458 if (rc < 0) {
2459 smblib_err(chg, "Couldn't read TEMP_RANGE_STATUS_REG rc=%d\n",
2460 rc);
2461 return rc;
2462 }
2463
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002464 /* TEMP_RANGE bits are mutually exclusive */
2465 switch (stat & TEMP_RANGE_MASK) {
2466 case TEMP_BELOW_RANGE_BIT:
2467 val->intval = POWER_SUPPLY_HEALTH_COOL;
2468 break;
2469 case TEMP_WITHIN_RANGE_BIT:
2470 val->intval = POWER_SUPPLY_HEALTH_WARM;
2471 break;
2472 case TEMP_ABOVE_RANGE_BIT:
2473 val->intval = POWER_SUPPLY_HEALTH_HOT;
2474 break;
2475 case ALERT_LEVEL_BIT:
2476 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
2477 break;
2478 default:
2479 val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
Nicholas Troastb021dd92017-01-31 18:43:38 -08002480 }
2481
Nicholas Troastb021dd92017-01-31 18:43:38 -08002482 return 0;
2483}
2484
Nicholas Troast34db5032016-03-28 12:26:44 -07002485/*******************
2486 * USB PSY SETTERS *
2487 * *****************/
2488
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002489int smblib_set_prop_pd_current_max(struct smb_charger *chg,
2490 const union power_supply_propval *val)
2491{
2492 int rc;
2493
2494 if (chg->pd_active)
2495 rc = vote(chg->usb_icl_votable, PD_VOTER, true, val->intval);
2496 else
2497 rc = -EPERM;
2498
2499 return rc;
2500}
2501
Nicholas Troast34db5032016-03-28 12:26:44 -07002502int smblib_set_prop_usb_current_max(struct smb_charger *chg,
2503 const union power_supply_propval *val)
2504{
Nicholas Troast8d33b7d2017-01-16 11:18:38 -08002505 int rc = 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002506
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002507 if (!chg->pd_active) {
2508 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
2509 true, val->intval);
2510 } else if (chg->system_suspend_supported) {
2511 if (val->intval <= USBIN_25MA)
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302512 rc = vote(chg->usb_icl_votable,
2513 PD_SUSPEND_SUPPORTED_VOTER, true, val->intval);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002514 else
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302515 rc = vote(chg->usb_icl_votable,
2516 PD_SUSPEND_SUPPORTED_VOTER, false, 0);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002517 }
Nicholas Troast34db5032016-03-28 12:26:44 -07002518 return rc;
2519}
2520
Harry Yangd89ff1f2016-12-05 14:59:11 -08002521int smblib_set_prop_boost_current(struct smb_charger *chg,
2522 const union power_supply_propval *val)
2523{
2524 int rc = 0;
2525
2526 rc = smblib_set_charge_param(chg, &chg->param.freq_boost,
2527 val->intval <= chg->boost_threshold_ua ?
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05302528 chg->chg_freq.freq_below_otg_threshold :
2529 chg->chg_freq.freq_above_otg_threshold);
Harry Yangd89ff1f2016-12-05 14:59:11 -08002530 if (rc < 0) {
2531 dev_err(chg->dev, "Error in setting freq_boost rc=%d\n", rc);
2532 return rc;
2533 }
2534
2535 chg->boost_current_ua = val->intval;
2536 return rc;
2537}
2538
Nicholas Troast34db5032016-03-28 12:26:44 -07002539int smblib_set_prop_typec_power_role(struct smb_charger *chg,
2540 const union power_supply_propval *val)
2541{
2542 int rc = 0;
2543 u8 power_role;
2544
2545 switch (val->intval) {
2546 case POWER_SUPPLY_TYPEC_PR_NONE:
2547 power_role = TYPEC_DISABLE_CMD_BIT;
2548 break;
2549 case POWER_SUPPLY_TYPEC_PR_DUAL:
2550 power_role = 0;
2551 break;
2552 case POWER_SUPPLY_TYPEC_PR_SINK:
2553 power_role = UFP_EN_CMD_BIT;
2554 break;
2555 case POWER_SUPPLY_TYPEC_PR_SOURCE:
2556 power_role = DFP_EN_CMD_BIT;
2557 break;
2558 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002559 smblib_err(chg, "power role %d not supported\n", val->intval);
Nicholas Troast34db5032016-03-28 12:26:44 -07002560 return -EINVAL;
2561 }
2562
Jack Pham54a39bd2017-03-29 18:59:37 -07002563 if (power_role == UFP_EN_CMD_BIT) {
2564 /* disable PBS workaround when forcing sink mode */
2565 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0x0);
2566 if (rc < 0) {
2567 smblib_err(chg, "Couldn't write to TM_IO_DTEST4_SEL rc=%d\n",
2568 rc);
2569 }
2570 } else {
2571 /* restore it back to 0xA5 */
2572 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
2573 if (rc < 0) {
2574 smblib_err(chg, "Couldn't write to TM_IO_DTEST4_SEL rc=%d\n",
2575 rc);
2576 }
2577 }
2578
Nicholas Troast34db5032016-03-28 12:26:44 -07002579 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2580 TYPEC_POWER_ROLE_CMD_MASK, power_role);
2581 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002582 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 -07002583 power_role, rc);
2584 return rc;
2585 }
2586
2587 return rc;
2588}
2589
2590int smblib_set_prop_usb_voltage_min(struct smb_charger *chg,
2591 const union power_supply_propval *val)
2592{
2593 int rc, min_uv;
2594
2595 min_uv = min(val->intval, chg->voltage_max_uv);
2596 rc = smblib_set_usb_pd_allowed_voltage(chg, min_uv,
2597 chg->voltage_max_uv);
2598 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002599 smblib_err(chg, "invalid max voltage %duV rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002600 val->intval, rc);
2601 return rc;
2602 }
2603
Harry Yangaba1f5f2016-09-28 10:47:29 -07002604 chg->voltage_min_uv = min_uv;
Nicholas Troast34db5032016-03-28 12:26:44 -07002605 return rc;
2606}
2607
2608int smblib_set_prop_usb_voltage_max(struct smb_charger *chg,
2609 const union power_supply_propval *val)
2610{
2611 int rc, max_uv;
2612
2613 max_uv = max(val->intval, chg->voltage_min_uv);
2614 rc = smblib_set_usb_pd_allowed_voltage(chg, chg->voltage_min_uv,
2615 max_uv);
2616 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002617 smblib_err(chg, "invalid min voltage %duV rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002618 val->intval, rc);
2619 return rc;
2620 }
2621
Harry Yangaba1f5f2016-09-28 10:47:29 -07002622 chg->voltage_max_uv = max_uv;
Nicholas Troast34db5032016-03-28 12:26:44 -07002623 return rc;
2624}
2625
2626int smblib_set_prop_pd_active(struct smb_charger *chg,
2627 const union power_supply_propval *val)
2628{
2629 int rc;
Nicholas Troaste1932e42017-04-12 12:38:18 -07002630 bool orientation, sink_attached, hvdcp;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002631 u8 stat;
Nicholas Troast34db5032016-03-28 12:26:44 -07002632
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002633 if (!get_effective_result(chg->pd_allowed_votable))
Nicholas Troast34db5032016-03-28 12:26:44 -07002634 return -EINVAL;
Nicholas Troast34db5032016-03-28 12:26:44 -07002635
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002636 chg->pd_active = val->intval;
2637 if (chg->pd_active) {
2638 vote(chg->apsd_disable_votable, PD_VOTER, true, 0);
2639 vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
2640 vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
2641
2642 /*
2643 * VCONN_EN_ORIENTATION_BIT controls whether to use CC1 or CC2
2644 * line when TYPEC_SPARE_CFG_BIT (CC pin selection s/w override)
2645 * is set or when VCONN_EN_VALUE_BIT is set.
2646 */
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002647 orientation = chg->typec_status[3] & CC_ORIENTATION_BIT;
Harry Yang88acff42016-09-21 14:56:06 -07002648 rc = smblib_masked_write(chg,
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07002649 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2650 VCONN_EN_ORIENTATION_BIT,
2651 orientation ? 0 : VCONN_EN_ORIENTATION_BIT);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002652 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002653 smblib_err(chg,
Harry Yang88acff42016-09-21 14:56:06 -07002654 "Couldn't enable vconn on CC line rc=%d\n", rc);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002655
2656 /* SW controlled CC_OUT */
2657 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
2658 TYPEC_SPARE_CFG_BIT, TYPEC_SPARE_CFG_BIT);
2659 if (rc < 0)
2660 smblib_err(chg, "Couldn't enable SW cc_out rc=%d\n",
2661 rc);
2662
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302663 /*
2664 * Enforce 500mA for PD until the real vote comes in later.
2665 * It is guaranteed that pd_active is set prior to
2666 * pd_current_max
2667 */
Harry Yangcd995202016-11-07 13:32:52 -08002668 rc = vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002669 if (rc < 0)
Harry Yangcd995202016-11-07 13:32:52 -08002670 smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n",
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002671 rc);
Harry Yangcd995202016-11-07 13:32:52 -08002672
Nicholas Troastf9e44992017-03-14 09:06:56 -07002673 /* since PD was found the cable must be non-legacy */
2674 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
2675
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002676 /* clear USB ICL vote for DCP_VOTER */
Harry Yang631b99e2016-11-17 11:24:25 -08002677 rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002678 if (rc < 0)
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002679 smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n",
2680 rc);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002681
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302682 /* remove USB_PSY_VOTER */
2683 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002684 if (rc < 0)
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302685 smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002686 } else {
Nicholas Troaste1932e42017-04-12 12:38:18 -07002687 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
2688 if (rc < 0) {
2689 smblib_err(chg, "Couldn't read APSD status rc=%d\n",
2690 rc);
2691 return rc;
2692 }
2693
2694 hvdcp = stat & QC_CHARGER_BIT;
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002695 vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
2696 vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
2697 vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002698 vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER,
2699 false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002700
2701 /* HW controlled CC_OUT */
2702 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
2703 TYPEC_SPARE_CFG_BIT, 0);
2704 if (rc < 0)
2705 smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n",
2706 rc);
2707
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002708 /*
2709 * This WA should only run for HVDCP. Non-legacy SDP/CDP could
2710 * draw more, but this WA will remove Rd causing VBUS to drop,
2711 * and data could be interrupted. Non-legacy DCP could also draw
2712 * more, but it may impact compliance.
2713 */
Nicholas Troaste1932e42017-04-12 12:38:18 -07002714 sink_attached = chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT;
2715 if (!chg->typec_legacy_valid && !sink_attached && hvdcp)
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002716 schedule_work(&chg->legacy_detection_work);
Harry Yang88acff42016-09-21 14:56:06 -07002717 }
2718
Harry Yang6607b4a2016-05-17 17:50:09 -07002719 smblib_update_usb_type(chg);
Abhijeet Dharmapurikar76e2af52016-10-06 17:25:01 -07002720 power_supply_changed(chg->usb_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07002721 return rc;
2722}
2723
Fenglin Wuedd70792016-11-22 13:16:19 +08002724int smblib_set_prop_ship_mode(struct smb_charger *chg,
2725 const union power_supply_propval *val)
2726{
2727 int rc;
2728
2729 smblib_dbg(chg, PR_MISC, "Set ship mode: %d!!\n", !!val->intval);
2730
2731 rc = smblib_masked_write(chg, SHIP_MODE_REG, SHIP_MODE_EN_BIT,
2732 !!val->intval ? SHIP_MODE_EN_BIT : 0);
2733 if (rc < 0)
2734 dev_err(chg->dev, "Couldn't %s ship mode, rc=%d\n",
2735 !!val->intval ? "enable" : "disable", rc);
2736
2737 return rc;
2738}
2739
Harry Yang5e2bb712016-10-18 16:47:48 -07002740int smblib_reg_block_update(struct smb_charger *chg,
2741 struct reg_info *entry)
2742{
2743 int rc = 0;
2744
2745 while (entry && entry->reg) {
2746 rc = smblib_read(chg, entry->reg, &entry->bak);
2747 if (rc < 0) {
2748 dev_err(chg->dev, "Error in reading %s rc=%d\n",
2749 entry->desc, rc);
2750 break;
2751 }
2752 entry->bak &= entry->mask;
2753
2754 rc = smblib_masked_write(chg, entry->reg,
2755 entry->mask, entry->val);
2756 if (rc < 0) {
2757 dev_err(chg->dev, "Error in writing %s rc=%d\n",
2758 entry->desc, rc);
2759 break;
2760 }
2761 entry++;
2762 }
2763
2764 return rc;
2765}
2766
2767int smblib_reg_block_restore(struct smb_charger *chg,
2768 struct reg_info *entry)
2769{
2770 int rc = 0;
2771
2772 while (entry && entry->reg) {
2773 rc = smblib_masked_write(chg, entry->reg,
2774 entry->mask, entry->bak);
2775 if (rc < 0) {
2776 dev_err(chg->dev, "Error in writing %s rc=%d\n",
2777 entry->desc, rc);
2778 break;
2779 }
2780 entry++;
2781 }
2782
2783 return rc;
2784}
2785
Harry Yang755a34b2016-11-01 01:18:51 -07002786static struct reg_info cc2_detach_settings[] = {
2787 {
2788 .reg = TYPE_C_CFG_2_REG,
2789 .mask = TYPE_C_UFP_MODE_BIT | EN_TRY_SOURCE_MODE_BIT,
2790 .val = TYPE_C_UFP_MODE_BIT,
2791 .desc = "TYPE_C_CFG_2_REG",
2792 },
2793 {
2794 .reg = TYPE_C_CFG_3_REG,
2795 .mask = EN_TRYSINK_MODE_BIT,
2796 .val = 0,
2797 .desc = "TYPE_C_CFG_3_REG",
2798 },
2799 {
2800 .reg = TAPER_TIMER_SEL_CFG_REG,
2801 .mask = TYPEC_SPARE_CFG_BIT,
2802 .val = TYPEC_SPARE_CFG_BIT,
2803 .desc = "TAPER_TIMER_SEL_CFG_REG",
2804 },
2805 {
2806 .reg = TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2807 .mask = VCONN_EN_ORIENTATION_BIT,
2808 .val = 0,
2809 .desc = "TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG",
2810 },
2811 {
2812 .reg = MISC_CFG_REG,
2813 .mask = TCC_DEBOUNCE_20MS_BIT,
2814 .val = TCC_DEBOUNCE_20MS_BIT,
2815 .desc = "Tccdebounce time"
2816 },
2817 {
2818 },
2819};
2820
2821static int smblib_cc2_sink_removal_enter(struct smb_charger *chg)
2822{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002823 int rc, ccout, ufp_mode;
2824 u8 stat;
Harry Yang755a34b2016-11-01 01:18:51 -07002825
2826 if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002827 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002828
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002829 if (chg->cc2_detach_wa_active)
2830 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002831
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002832 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
Harry Yang755a34b2016-11-01 01:18:51 -07002833 if (rc < 0) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002834 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
Harry Yang755a34b2016-11-01 01:18:51 -07002835 return rc;
2836 }
Nicholas Troaste1932e42017-04-12 12:38:18 -07002837
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002838 ccout = (stat & CC_ATTACHED_BIT) ?
2839 (!!(stat & CC_ORIENTATION_BIT) + 1) : 0;
2840 ufp_mode = (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT) ?
2841 !(stat & UFP_DFP_MODE_STATUS_BIT) : 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002842
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002843 if (ccout != 2)
2844 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002845
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002846 if (!ufp_mode)
2847 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002848
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002849 chg->cc2_detach_wa_active = true;
2850 /* The CC2 removal WA will cause a type-c-change IRQ storm */
2851 smblib_reg_block_update(chg, cc2_detach_settings);
2852 schedule_work(&chg->rdstd_cc2_detach_work);
Harry Yang755a34b2016-11-01 01:18:51 -07002853 return rc;
2854}
2855
2856static int smblib_cc2_sink_removal_exit(struct smb_charger *chg)
2857{
Harry Yang755a34b2016-11-01 01:18:51 -07002858 if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002859 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002860
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002861 if (!chg->cc2_detach_wa_active)
2862 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002863
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002864 chg->cc2_detach_wa_active = false;
2865 cancel_work_sync(&chg->rdstd_cc2_detach_work);
2866 smblib_reg_block_restore(chg, cc2_detach_settings);
2867 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002868}
2869
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002870int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
2871 const union power_supply_propval *val)
2872{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002873 int rc = 0;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002874
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002875 if (chg->pd_hard_reset == val->intval)
2876 return rc;
2877
2878 chg->pd_hard_reset = val->intval;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002879 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002880 EXIT_SNK_BASED_ON_CC_BIT,
2881 (chg->pd_hard_reset) ? EXIT_SNK_BASED_ON_CC_BIT : 0);
2882 if (rc < 0)
2883 smblib_err(chg, "Couldn't set EXIT_SNK_BASED_ON_CC rc=%d\n",
Harry Yang755a34b2016-11-01 01:18:51 -07002884 rc);
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002885
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002886 vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER,
2887 chg->pd_hard_reset, 0);
Harry Yang755a34b2016-11-01 01:18:51 -07002888
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002889 return rc;
2890}
2891
Anirudh Ghayal941acaa2017-07-19 16:04:44 +05302892static int smblib_recover_from_soft_jeita(struct smb_charger *chg)
2893{
2894 u8 stat_1, stat_2;
2895 int rc;
2896
2897 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat_1);
2898 if (rc < 0) {
2899 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
2900 rc);
2901 return rc;
2902 }
2903
2904 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat_2);
2905 if (rc < 0) {
2906 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
2907 rc);
2908 return rc;
2909 }
2910
2911 if ((chg->jeita_status && !(stat_2 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK) &&
2912 ((stat_1 & BATTERY_CHARGER_STATUS_MASK) == TERMINATE_CHARGE))) {
2913 /*
2914 * We are moving from JEITA soft -> Normal and charging
2915 * is terminated
2916 */
2917 rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG, 0);
2918 if (rc < 0) {
2919 smblib_err(chg, "Couldn't disable charging rc=%d\n",
2920 rc);
2921 return rc;
2922 }
2923 rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG,
2924 CHARGING_ENABLE_CMD_BIT);
2925 if (rc < 0) {
2926 smblib_err(chg, "Couldn't enable charging rc=%d\n",
2927 rc);
2928 return rc;
2929 }
2930 }
2931
2932 chg->jeita_status = stat_2 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK;
2933
2934 return 0;
2935}
2936
Nicholas Troast7dbcad22016-10-05 13:30:18 -07002937/************************
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002938 * USB MAIN PSY GETTERS *
2939 ************************/
2940int smblib_get_prop_fcc_delta(struct smb_charger *chg,
2941 union power_supply_propval *val)
2942{
2943 int rc, jeita_cc_delta_ua, step_cc_delta_ua, hw_cc_delta_ua = 0;
2944
2945 rc = smblib_get_step_cc_delta(chg, &step_cc_delta_ua);
2946 if (rc < 0) {
2947 smblib_err(chg, "Couldn't get step cc delta rc=%d\n", rc);
2948 step_cc_delta_ua = 0;
2949 } else {
2950 hw_cc_delta_ua = step_cc_delta_ua;
2951 }
2952
2953 rc = smblib_get_jeita_cc_delta(chg, &jeita_cc_delta_ua);
2954 if (rc < 0) {
2955 smblib_err(chg, "Couldn't get jeita cc delta rc=%d\n", rc);
2956 jeita_cc_delta_ua = 0;
2957 } else if (jeita_cc_delta_ua < 0) {
2958 /* HW will take the min between JEITA and step charge */
2959 hw_cc_delta_ua = min(hw_cc_delta_ua, jeita_cc_delta_ua);
2960 }
2961
2962 val->intval = hw_cc_delta_ua;
2963 return 0;
2964}
2965
2966/************************
2967 * USB MAIN PSY SETTERS *
2968 ************************/
2969
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05302970#define SDP_CURRENT_UA 500000
2971#define CDP_CURRENT_UA 1500000
2972#define DCP_CURRENT_UA 1500000
2973#define HVDCP_CURRENT_UA 3000000
2974#define TYPEC_DEFAULT_CURRENT_UA 900000
2975#define TYPEC_MEDIUM_CURRENT_UA 1500000
2976#define TYPEC_HIGH_CURRENT_UA 3000000
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07002977int smblib_get_charge_current(struct smb_charger *chg,
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002978 int *total_current_ua)
2979{
Ashay Jaiswal7b6eb962017-04-26 14:34:29 +05302980 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002981 union power_supply_propval val = {0, };
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07002982 int rc = 0, typec_source_rd, current_ua;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002983 bool non_compliant;
2984 u8 stat5;
2985
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07002986 if (chg->pd_active) {
2987 *total_current_ua =
2988 get_client_vote_locked(chg->usb_icl_votable, PD_VOTER);
2989 return rc;
2990 }
2991
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002992 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
2993 if (rc < 0) {
2994 smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc);
2995 return rc;
2996 }
2997 non_compliant = stat5 & TYPEC_NONCOMP_LEGACY_CABLE_STATUS_BIT;
2998
2999 /* get settled ICL */
3000 rc = smblib_get_prop_input_current_settled(chg, &val);
3001 if (rc < 0) {
3002 smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
3003 return rc;
3004 }
3005
3006 typec_source_rd = smblib_get_prop_ufp_mode(chg);
3007
3008 /* QC 2.0/3.0 adapter */
3009 if (apsd_result->bit & (QC_3P0_BIT | QC_2P0_BIT)) {
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303010 *total_current_ua = HVDCP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003011 return 0;
3012 }
3013
3014 if (non_compliant) {
3015 switch (apsd_result->bit) {
3016 case CDP_CHARGER_BIT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303017 current_ua = CDP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003018 break;
3019 case DCP_CHARGER_BIT:
3020 case OCP_CHARGER_BIT:
3021 case FLOAT_CHARGER_BIT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303022 current_ua = DCP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003023 break;
3024 default:
3025 current_ua = 0;
3026 break;
3027 }
3028
3029 *total_current_ua = max(current_ua, val.intval);
3030 return 0;
3031 }
3032
3033 switch (typec_source_rd) {
3034 case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
3035 switch (apsd_result->bit) {
3036 case CDP_CHARGER_BIT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303037 current_ua = CDP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003038 break;
3039 case DCP_CHARGER_BIT:
3040 case OCP_CHARGER_BIT:
3041 case FLOAT_CHARGER_BIT:
3042 current_ua = chg->default_icl_ua;
3043 break;
3044 default:
3045 current_ua = 0;
3046 break;
3047 }
3048 break;
3049 case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303050 current_ua = TYPEC_MEDIUM_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003051 break;
3052 case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303053 current_ua = TYPEC_HIGH_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003054 break;
3055 case POWER_SUPPLY_TYPEC_NON_COMPLIANT:
3056 case POWER_SUPPLY_TYPEC_NONE:
3057 default:
3058 current_ua = 0;
3059 break;
3060 }
3061
3062 *total_current_ua = max(current_ua, val.intval);
3063 return 0;
3064}
3065
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003066/************************
Nicholas Troast7dbcad22016-10-05 13:30:18 -07003067 * PARALLEL PSY GETTERS *
3068 ************************/
3069
3070int smblib_get_prop_slave_current_now(struct smb_charger *chg,
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003071 union power_supply_propval *pval)
Nicholas Troast7dbcad22016-10-05 13:30:18 -07003072{
3073 if (IS_ERR_OR_NULL(chg->iio.batt_i_chan))
3074 chg->iio.batt_i_chan = iio_channel_get(chg->dev, "batt_i");
3075
3076 if (IS_ERR(chg->iio.batt_i_chan))
3077 return PTR_ERR(chg->iio.batt_i_chan);
3078
3079 return iio_read_channel_processed(chg->iio.batt_i_chan, &pval->intval);
3080}
3081
Nicholas Troast34db5032016-03-28 12:26:44 -07003082/**********************
3083 * INTERRUPT HANDLERS *
3084 **********************/
3085
3086irqreturn_t smblib_handle_debug(int irq, void *data)
3087{
3088 struct smb_irq_data *irq_data = data;
3089 struct smb_charger *chg = irq_data->parent_data;
3090
3091 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003092 return IRQ_HANDLED;
3093}
3094
Nicholas Troast8995a702016-12-05 10:22:22 -08003095irqreturn_t smblib_handle_otg_overcurrent(int irq, void *data)
3096{
3097 struct smb_irq_data *irq_data = data;
3098 struct smb_charger *chg = irq_data->parent_data;
3099 int rc;
3100 u8 stat;
3101
3102 rc = smblib_read(chg, OTG_BASE + INT_RT_STS_OFFSET, &stat);
3103 if (rc < 0) {
3104 dev_err(chg->dev, "Couldn't read OTG_INT_RT_STS rc=%d\n", rc);
3105 return IRQ_HANDLED;
3106 }
3107
Ashay Jaiswal7c241382017-03-06 15:26:38 +05303108 if (chg->wa_flags & OTG_WA) {
3109 if (stat & OTG_OC_DIS_SW_STS_RT_STS_BIT)
3110 smblib_err(chg, "OTG disabled by hw\n");
3111
3112 /* not handling software based hiccups for PM660 */
3113 return IRQ_HANDLED;
3114 }
3115
Nicholas Troastb11015f2017-01-17 17:56:45 -08003116 if (stat & OTG_OVERCURRENT_RT_STS_BIT)
3117 schedule_work(&chg->otg_oc_work);
Nicholas Troast8995a702016-12-05 10:22:22 -08003118
Nicholas Troast8995a702016-12-05 10:22:22 -08003119 return IRQ_HANDLED;
3120}
3121
Harry Yang6fe72ab2016-06-14 16:21:39 -07003122irqreturn_t smblib_handle_chg_state_change(int irq, void *data)
3123{
3124 struct smb_irq_data *irq_data = data;
3125 struct smb_charger *chg = irq_data->parent_data;
Nicholas Troast8cb77552016-09-23 11:50:18 -07003126 u8 stat;
Harry Yang1d1034c2016-06-15 12:09:42 -07003127 int rc;
Harry Yang6fe72ab2016-06-14 16:21:39 -07003128
3129 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3130
Nicholas Troast8cb77552016-09-23 11:50:18 -07003131 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
Harry Yang1d1034c2016-06-15 12:09:42 -07003132 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003133 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003134 rc);
Harry Yang1d1034c2016-06-15 12:09:42 -07003135 return IRQ_HANDLED;
3136 }
3137
Nicholas Troast8cb77552016-09-23 11:50:18 -07003138 stat = stat & BATTERY_CHARGER_STATUS_MASK;
Nicholas Troast8cb77552016-09-23 11:50:18 -07003139 power_supply_changed(chg->batt_psy);
Harry Yang6fe72ab2016-06-14 16:21:39 -07003140 return IRQ_HANDLED;
3141}
3142
Harry Yangfe913842016-08-10 12:27:28 -07003143irqreturn_t smblib_handle_step_chg_state_change(int irq, void *data)
3144{
3145 struct smb_irq_data *irq_data = data;
3146 struct smb_charger *chg = irq_data->parent_data;
3147
3148 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3149
3150 if (chg->step_chg_enabled)
3151 rerun_election(chg->fcc_votable);
3152
3153 return IRQ_HANDLED;
3154}
3155
3156irqreturn_t smblib_handle_step_chg_soc_update_fail(int irq, void *data)
3157{
3158 struct smb_irq_data *irq_data = data;
3159 struct smb_charger *chg = irq_data->parent_data;
3160
3161 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3162
3163 if (chg->step_chg_enabled)
3164 rerun_election(chg->fcc_votable);
3165
3166 return IRQ_HANDLED;
3167}
3168
3169#define STEP_SOC_REQ_MS 3000
3170irqreturn_t smblib_handle_step_chg_soc_update_request(int irq, void *data)
3171{
3172 struct smb_irq_data *irq_data = data;
3173 struct smb_charger *chg = irq_data->parent_data;
3174 int rc;
3175 union power_supply_propval pval = {0, };
3176
3177 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3178
3179 if (!chg->bms_psy) {
3180 schedule_delayed_work(&chg->step_soc_req_work,
3181 msecs_to_jiffies(STEP_SOC_REQ_MS));
3182 return IRQ_HANDLED;
3183 }
3184
3185 rc = smblib_get_prop_batt_capacity(chg, &pval);
3186 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003187 smblib_err(chg, "Couldn't get batt capacity rc=%d\n", rc);
Harry Yangfe913842016-08-10 12:27:28 -07003188 else
3189 step_charge_soc_update(chg, pval.intval);
3190
3191 return IRQ_HANDLED;
3192}
3193
Abhijeet Dharmapurikar2644cd62016-07-20 16:54:55 -07003194irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data)
3195{
3196 struct smb_irq_data *irq_data = data;
3197 struct smb_charger *chg = irq_data->parent_data;
Anirudh Ghayal941acaa2017-07-19 16:04:44 +05303198 int rc;
3199
3200 rc = smblib_recover_from_soft_jeita(chg);
3201 if (rc < 0) {
3202 smblib_err(chg, "Couldn't recover chg from soft jeita rc=%d\n",
3203 rc);
3204 return IRQ_HANDLED;
3205 }
Abhijeet Dharmapurikar2644cd62016-07-20 16:54:55 -07003206
3207 rerun_election(chg->fcc_votable);
3208 power_supply_changed(chg->batt_psy);
3209 return IRQ_HANDLED;
3210}
3211
Nicholas Troast34db5032016-03-28 12:26:44 -07003212irqreturn_t smblib_handle_batt_psy_changed(int irq, void *data)
3213{
3214 struct smb_irq_data *irq_data = data;
3215 struct smb_charger *chg = irq_data->parent_data;
3216
Nicholas Troast47ae4612016-08-03 09:49:36 -07003217 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003218 power_supply_changed(chg->batt_psy);
3219 return IRQ_HANDLED;
3220}
3221
3222irqreturn_t smblib_handle_usb_psy_changed(int irq, void *data)
3223{
3224 struct smb_irq_data *irq_data = data;
3225 struct smb_charger *chg = irq_data->parent_data;
3226
Nicholas Troast47ae4612016-08-03 09:49:36 -07003227 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003228 power_supply_changed(chg->usb_psy);
3229 return IRQ_HANDLED;
3230}
3231
Subbaraman Narayanamurthy09327482017-02-06 16:33:12 -08003232irqreturn_t smblib_handle_usbin_uv(int irq, void *data)
3233{
3234 struct smb_irq_data *irq_data = data;
3235 struct smb_charger *chg = irq_data->parent_data;
3236 struct storm_watch *wdata;
3237
3238 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3239 if (!chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data)
3240 return IRQ_HANDLED;
3241
3242 wdata = &chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data->storm_data;
3243 reset_storm_count(wdata);
3244 return IRQ_HANDLED;
3245}
3246
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003247static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising)
3248{
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003249 if (vbus_rising) {
3250 /* use the typec flag even though its not typec */
3251 chg->typec_present = 1;
3252 } else {
3253 chg->typec_present = 0;
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003254 smblib_update_usb_type(chg);
3255 extcon_set_cable_state_(chg->extcon, EXTCON_USB, false);
3256 smblib_uusb_removal(chg);
3257 }
3258}
3259
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003260void smblib_usb_plugin_hard_reset_locked(struct smb_charger *chg)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003261{
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003262 int rc;
3263 u8 stat;
3264 bool vbus_rising;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303265 struct smb_irq_data *data;
3266 struct storm_watch *wdata;
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003267
3268 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
3269 if (rc < 0) {
3270 smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
3271 return;
3272 }
3273
3274 vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
3275
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303276 if (vbus_rising) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003277 smblib_cc2_sink_removal_exit(chg);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303278 } else {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003279 smblib_cc2_sink_removal_enter(chg);
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303280 if (chg->wa_flags & BOOST_BACK_WA) {
3281 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
3282 if (data) {
3283 wdata = &data->storm_data;
3284 update_storm_count(wdata,
3285 WEAK_CHG_STORM_COUNT);
3286 vote(chg->usb_icl_votable, BOOST_BACK_VOTER,
3287 false, 0);
3288 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
3289 false, 0);
3290 }
3291 }
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303292 }
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003293
3294 power_supply_changed(chg->usb_psy);
3295 smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
3296 vbus_rising ? "attached" : "detached");
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003297}
3298
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303299#define PL_DELAY_MS 30000
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003300void smblib_usb_plugin_locked(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07003301{
Nicholas Troast34db5032016-03-28 12:26:44 -07003302 int rc;
3303 u8 stat;
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003304 bool vbus_rising;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303305 struct smb_irq_data *data;
3306 struct storm_watch *wdata;
Nicholas Troast34db5032016-03-28 12:26:44 -07003307
Harry Yangcdad2bf2016-10-04 17:03:56 -07003308 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
3309 if (rc < 0) {
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003310 smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
3311 return;
Harry Yangcdad2bf2016-10-04 17:03:56 -07003312 }
3313
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003314 vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003315 smblib_set_opt_freq_buck(chg, vbus_rising ? chg->chg_freq.freq_5V :
3316 chg->chg_freq.freq_removal);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003317
Nicholas Troast34db5032016-03-28 12:26:44 -07003318 /* fetch the DPDM regulator */
3319 if (!chg->dpdm_reg && of_get_property(chg->dev->of_node,
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05303320 "dpdm-supply", NULL)) {
Nicholas Troast34db5032016-03-28 12:26:44 -07003321 chg->dpdm_reg = devm_regulator_get(chg->dev, "dpdm");
3322 if (IS_ERR(chg->dpdm_reg)) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003323 smblib_err(chg, "Couldn't get dpdm regulator rc=%ld\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07003324 PTR_ERR(chg->dpdm_reg));
3325 chg->dpdm_reg = NULL;
3326 }
3327 }
3328
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003329 if (vbus_rising) {
Nicholas Troastabedaf72016-09-16 11:07:45 -07003330 if (chg->dpdm_reg && !regulator_is_enabled(chg->dpdm_reg)) {
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07003331 smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n");
3332 rc = regulator_enable(chg->dpdm_reg);
3333 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003334 smblib_err(chg, "Couldn't enable dpdm regulator rc=%d\n",
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07003335 rc);
3336 }
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303337
3338 /* Schedule work to enable parallel charger */
3339 vote(chg->awake_votable, PL_DELAY_VOTER, true, 0);
3340 schedule_delayed_work(&chg->pl_enable_work,
3341 msecs_to_jiffies(PL_DELAY_MS));
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07003342 } else {
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303343 if (chg->wa_flags & BOOST_BACK_WA) {
3344 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
3345 if (data) {
3346 wdata = &data->storm_data;
3347 update_storm_count(wdata,
3348 WEAK_CHG_STORM_COUNT);
3349 vote(chg->usb_icl_votable, BOOST_BACK_VOTER,
3350 false, 0);
3351 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
3352 false, 0);
3353 }
3354 }
Nicholas Troastabedaf72016-09-16 11:07:45 -07003355
3356 if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) {
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07003357 smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n");
3358 rc = regulator_disable(chg->dpdm_reg);
3359 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003360 smblib_err(chg, "Couldn't disable dpdm regulator rc=%d\n",
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07003361 rc);
3362 }
Nicholas Troast34db5032016-03-28 12:26:44 -07003363 }
3364
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003365 if (chg->micro_usb_mode)
3366 smblib_micro_usb_plugin(chg, vbus_rising);
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003367
Nicholas Troast62d86622016-09-22 11:41:33 -07003368 power_supply_changed(chg->usb_psy);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003369 smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
3370 vbus_rising ? "attached" : "detached");
3371}
3372
3373irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
3374{
3375 struct smb_irq_data *irq_data = data;
3376 struct smb_charger *chg = irq_data->parent_data;
3377
3378 mutex_lock(&chg->lock);
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003379 if (chg->pd_hard_reset)
3380 smblib_usb_plugin_hard_reset_locked(chg);
3381 else
3382 smblib_usb_plugin_locked(chg);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003383 mutex_unlock(&chg->lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07003384 return IRQ_HANDLED;
3385}
3386
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -07003387#define USB_WEAK_INPUT_UA 1400000
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303388#define ICL_CHANGE_DELAY_MS 1000
Harry Yang6fe72ab2016-06-14 16:21:39 -07003389irqreturn_t smblib_handle_icl_change(int irq, void *data)
3390{
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303391 u8 stat;
3392 int rc, settled_ua, delay = ICL_CHANGE_DELAY_MS;
Harry Yang6fe72ab2016-06-14 16:21:39 -07003393 struct smb_irq_data *irq_data = data;
3394 struct smb_charger *chg = irq_data->parent_data;
3395
Nicholas Troastbb9e1a32017-02-09 10:57:28 -08003396 if (chg->mode == PARALLEL_MASTER) {
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303397 rc = smblib_read(chg, AICL_STATUS_REG, &stat);
3398 if (rc < 0) {
3399 smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n",
3400 rc);
3401 return IRQ_HANDLED;
3402 }
3403
3404 rc = smblib_get_charge_param(chg, &chg->param.icl_stat,
3405 &settled_ua);
3406 if (rc < 0) {
3407 smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
3408 return IRQ_HANDLED;
3409 }
3410
3411 /* If AICL settled then schedule work now */
3412 if ((settled_ua == get_effective_result(chg->usb_icl_votable))
3413 || (stat & AICL_DONE_BIT))
3414 delay = 0;
3415
Ashay Jaiswalac854862017-03-06 23:58:55 +05303416 cancel_delayed_work_sync(&chg->icl_change_work);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303417 schedule_delayed_work(&chg->icl_change_work,
3418 msecs_to_jiffies(delay));
Nicholas Troastbb9e1a32017-02-09 10:57:28 -08003419 }
Harry Yang1d1034c2016-06-15 12:09:42 -07003420
Harry Yang6fe72ab2016-06-14 16:21:39 -07003421 return IRQ_HANDLED;
3422}
3423
Nicholas Troast34db5032016-03-28 12:26:44 -07003424static void smblib_handle_slow_plugin_timeout(struct smb_charger *chg,
3425 bool rising)
3426{
3427 smblib_dbg(chg, PR_INTERRUPT, "IRQ: slow-plugin-timeout %s\n",
3428 rising ? "rising" : "falling");
3429}
3430
3431static void smblib_handle_sdp_enumeration_done(struct smb_charger *chg,
3432 bool rising)
3433{
3434 smblib_dbg(chg, PR_INTERRUPT, "IRQ: sdp-enumeration-done %s\n",
3435 rising ? "rising" : "falling");
3436}
3437
Harry Yangcdad2bf2016-10-04 17:03:56 -07003438#define QC3_PULSES_FOR_6V 5
3439#define QC3_PULSES_FOR_9V 20
3440#define QC3_PULSES_FOR_12V 35
3441static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg)
3442{
3443 int rc;
3444 u8 stat;
3445 int pulses;
3446
Fenglin Wuef4730e2017-01-11 18:16:25 +08003447 power_supply_changed(chg->usb_main_psy);
Fenglin Wu80826e02017-04-25 21:45:08 +08003448 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP) {
Harry Yangcdad2bf2016-10-04 17:03:56 -07003449 rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat);
3450 if (rc < 0) {
3451 smblib_err(chg,
3452 "Couldn't read QC_CHANGE_STATUS rc=%d\n", rc);
3453 return;
3454 }
3455
3456 switch (stat & QC_2P0_STATUS_MASK) {
3457 case QC_5V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303458 smblib_set_opt_freq_buck(chg,
3459 chg->chg_freq.freq_5V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003460 break;
3461 case QC_9V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303462 smblib_set_opt_freq_buck(chg,
3463 chg->chg_freq.freq_9V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003464 break;
3465 case QC_12V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303466 smblib_set_opt_freq_buck(chg,
3467 chg->chg_freq.freq_12V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003468 break;
3469 default:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303470 smblib_set_opt_freq_buck(chg,
3471 chg->chg_freq.freq_removal);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003472 break;
3473 }
3474 }
3475
Fenglin Wu80826e02017-04-25 21:45:08 +08003476 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP_3) {
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +05303477 rc = smblib_get_pulse_cnt(chg, &pulses);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003478 if (rc < 0) {
3479 smblib_err(chg,
3480 "Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
3481 return;
3482 }
Harry Yangcdad2bf2016-10-04 17:03:56 -07003483
3484 if (pulses < QC3_PULSES_FOR_6V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303485 smblib_set_opt_freq_buck(chg,
3486 chg->chg_freq.freq_5V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003487 else if (pulses < QC3_PULSES_FOR_9V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303488 smblib_set_opt_freq_buck(chg,
3489 chg->chg_freq.freq_6V_8V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003490 else if (pulses < QC3_PULSES_FOR_12V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303491 smblib_set_opt_freq_buck(chg,
3492 chg->chg_freq.freq_9V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003493 else
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303494 smblib_set_opt_freq_buck(chg,
3495 chg->chg_freq.freq_12V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003496 }
3497}
3498
Nicholas Troast34db5032016-03-28 12:26:44 -07003499/* triggers when HVDCP 3.0 authentication has finished */
3500static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
3501 bool rising)
3502{
3503 const struct apsd_result *apsd_result;
Harry Yangcdad2bf2016-10-04 17:03:56 -07003504 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07003505
3506 if (!rising)
3507 return;
3508
Ashay Jaiswal67ec7072017-02-16 14:14:58 +05303509 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
3510 /*
3511 * Disable AUTH_IRQ_EN_CFG_BIT to receive adapter voltage
3512 * change interrupt.
3513 */
3514 rc = smblib_masked_write(chg,
3515 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
3516 AUTH_IRQ_EN_CFG_BIT, 0);
3517 if (rc < 0)
3518 smblib_err(chg,
3519 "Couldn't enable QC auth setting rc=%d\n", rc);
3520 }
Harry Yangcdad2bf2016-10-04 17:03:56 -07003521
Harry Yangaba1f5f2016-09-28 10:47:29 -07003522 if (chg->mode == PARALLEL_MASTER)
3523 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0);
3524
Ashay Jaiswalac854862017-03-06 23:58:55 +05303525 /* the APSD done handler will set the USB supply type */
3526 apsd_result = smblib_get_apsd_result(chg);
3527 if (get_effective_result(chg->hvdcp_hw_inov_dis_votable)) {
3528 if (apsd_result->pst == POWER_SUPPLY_TYPE_USB_HVDCP) {
3529 /* force HVDCP2 to 9V if INOV is disabled */
3530 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG,
3531 FORCE_9V_BIT, FORCE_9V_BIT);
3532 if (rc < 0)
3533 smblib_err(chg,
3534 "Couldn't force 9V HVDCP rc=%d\n", rc);
3535 }
3536 }
3537
Nicholas Troast34db5032016-03-28 12:26:44 -07003538 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n",
3539 apsd_result->name);
3540}
3541
Harry Yang1369b7a2016-09-27 15:59:50 -07003542static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
3543 bool rising, bool qc_charger)
3544{
Ashay Jaiswal7b6eb962017-04-26 14:34:29 +05303545 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05303546
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003547 /* Hold off PD only until hvdcp 2.0 detection timeout */
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003548 if (rising) {
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003549 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003550 false, 0);
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -08003551
Harry Yang4bf7d962017-03-13 16:51:43 -07003552 /* enable HDC and ICL irq for QC2/3 charger */
3553 if (qc_charger)
3554 vote(chg->usb_irq_enable_votable, QC_VOTER, true, 0);
3555
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -08003556 /*
3557 * HVDCP detection timeout done
3558 * If adapter is not QC2.0/QC3.0 - it is a plain old DCP.
3559 */
3560 if (!qc_charger && (apsd_result->bit & DCP_CHARGER_BIT))
3561 /* enforce DCP ICL if specified */
3562 vote(chg->usb_icl_votable, DCP_VOTER,
3563 chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua);
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003564 }
Harry Yang1369b7a2016-09-27 15:59:50 -07003565
3566 smblib_dbg(chg, PR_INTERRUPT, "IRQ: smblib_handle_hvdcp_check_timeout %s\n",
3567 rising ? "rising" : "falling");
3568}
3569
Nicholas Troast34db5032016-03-28 12:26:44 -07003570/* triggers when HVDCP is detected */
3571static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg,
3572 bool rising)
3573{
3574 if (!rising)
3575 return;
3576
3577 /* the APSD done handler will set the USB supply type */
3578 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
3579 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-detect-done %s\n",
3580 rising ? "rising" : "falling");
3581}
3582
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303583static int get_rp_based_dcp_current(struct smb_charger *chg, int typec_mode)
3584{
3585 int rp_ua;
3586
3587 switch (typec_mode) {
3588 case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
3589 rp_ua = TYPEC_HIGH_CURRENT_UA;
3590 break;
3591 case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
3592 case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
3593 /* fall through */
3594 default:
3595 rp_ua = DCP_CURRENT_UA;
3596 }
3597
3598 return rp_ua;
3599}
3600
Nicholas Troastf9e44992017-03-14 09:06:56 -07003601static void smblib_force_legacy_icl(struct smb_charger *chg, int pst)
3602{
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303603 int typec_mode;
3604 int rp_ua;
3605
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003606 /* while PD is active it should have complete ICL control */
3607 if (chg->pd_active)
3608 return;
3609
Nicholas Troastf9e44992017-03-14 09:06:56 -07003610 switch (pst) {
3611 case POWER_SUPPLY_TYPE_USB:
3612 /*
3613 * USB_PSY will vote to increase the current to 500/900mA once
3614 * enumeration is done. Ensure that USB_PSY has at least voted
3615 * for 100mA before releasing the LEGACY_UNKNOWN vote
3616 */
3617 if (!is_client_vote_enabled(chg->usb_icl_votable,
3618 USB_PSY_VOTER))
3619 vote(chg->usb_icl_votable, USB_PSY_VOTER, true, 100000);
3620 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
3621 break;
3622 case POWER_SUPPLY_TYPE_USB_CDP:
3623 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1500000);
3624 break;
3625 case POWER_SUPPLY_TYPE_USB_DCP:
Ashay Jaiswalb9b2d2f2017-06-21 12:08:38 +05303626 case POWER_SUPPLY_TYPE_USB_FLOAT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303627 typec_mode = smblib_get_prop_typec_mode(chg);
3628 rp_ua = get_rp_based_dcp_current(chg, typec_mode);
3629 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua);
Nicholas Troastf9e44992017-03-14 09:06:56 -07003630 break;
3631 case POWER_SUPPLY_TYPE_USB_HVDCP:
3632 case POWER_SUPPLY_TYPE_USB_HVDCP_3:
3633 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 3000000);
3634 break;
3635 default:
3636 smblib_err(chg, "Unknown APSD %d; forcing 500mA\n", pst);
3637 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 500000);
3638 break;
3639 }
3640}
3641
Nicholas Troast34db5032016-03-28 12:26:44 -07003642#define HVDCP_DET_MS 2500
3643static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
3644{
Nicholas Troast34db5032016-03-28 12:26:44 -07003645 const struct apsd_result *apsd_result;
3646
3647 if (!rising)
3648 return;
3649
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07003650 apsd_result = smblib_update_usb_type(chg);
Nicholas Troastf9e44992017-03-14 09:06:56 -07003651
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003652 if (!chg->typec_legacy_valid)
Nicholas Troastf9e44992017-03-14 09:06:56 -07003653 smblib_force_legacy_icl(chg, apsd_result->pst);
3654
Nicholas Troast34db5032016-03-28 12:26:44 -07003655 switch (apsd_result->bit) {
3656 case SDP_CHARGER_BIT:
3657 case CDP_CHARGER_BIT:
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05303658 if (chg->micro_usb_mode)
3659 extcon_set_cable_state_(chg->extcon, EXTCON_USB,
3660 true);
Abhijeet Dharmapurikarbb9505f2017-03-22 18:31:28 -07003661 /* if not DCP then no hvdcp timeout happens. Enable pd here */
3662 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3663 false, 0);
3664 break;
Nicholas Troast34db5032016-03-28 12:26:44 -07003665 case OCP_CHARGER_BIT:
3666 case FLOAT_CHARGER_BIT:
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303667 /* if not DCP then no hvdcp timeout happens, Enable pd here. */
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003668 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3669 false, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07003670 break;
3671 case DCP_CHARGER_BIT:
Harry Yang1369b7a2016-09-27 15:59:50 -07003672 if (chg->wa_flags & QC_CHARGER_DETECTION_WA_BIT)
3673 schedule_delayed_work(&chg->hvdcp_detect_work,
3674 msecs_to_jiffies(HVDCP_DET_MS));
Nicholas Troast34db5032016-03-28 12:26:44 -07003675 break;
3676 default:
3677 break;
3678 }
3679
Nicholas Troast34db5032016-03-28 12:26:44 -07003680 smblib_dbg(chg, PR_INTERRUPT, "IRQ: apsd-done rising; %s detected\n",
3681 apsd_result->name);
3682}
3683
3684irqreturn_t smblib_handle_usb_source_change(int irq, void *data)
3685{
3686 struct smb_irq_data *irq_data = data;
3687 struct smb_charger *chg = irq_data->parent_data;
3688 int rc = 0;
3689 u8 stat;
3690
3691 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
3692 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003693 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07003694 return IRQ_HANDLED;
3695 }
3696 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
3697
Ashay Jaiswal8507aa52017-04-14 09:42:32 +05303698 if (chg->micro_usb_mode && (stat & APSD_DTC_STATUS_DONE_BIT)
3699 && !chg->uusb_apsd_rerun_done) {
3700 /*
3701 * Force re-run APSD to handle slow insertion related
3702 * charger-mis-detection.
3703 */
3704 chg->uusb_apsd_rerun_done = true;
3705 smblib_rerun_apsd(chg);
3706 return IRQ_HANDLED;
3707 }
3708
Nicholas Troast34db5032016-03-28 12:26:44 -07003709 smblib_handle_apsd_done(chg,
3710 (bool)(stat & APSD_DTC_STATUS_DONE_BIT));
3711
3712 smblib_handle_hvdcp_detect_done(chg,
3713 (bool)(stat & QC_CHARGER_BIT));
3714
Harry Yang1369b7a2016-09-27 15:59:50 -07003715 smblib_handle_hvdcp_check_timeout(chg,
3716 (bool)(stat & HVDCP_CHECK_TIMEOUT_BIT),
3717 (bool)(stat & QC_CHARGER_BIT));
3718
Nicholas Troast34db5032016-03-28 12:26:44 -07003719 smblib_handle_hvdcp_3p0_auth_done(chg,
3720 (bool)(stat & QC_AUTH_DONE_STATUS_BIT));
3721
Nicholas Troast34db5032016-03-28 12:26:44 -07003722 smblib_handle_sdp_enumeration_done(chg,
3723 (bool)(stat & ENUMERATION_DONE_BIT));
3724
3725 smblib_handle_slow_plugin_timeout(chg,
3726 (bool)(stat & SLOW_PLUGIN_TIMEOUT_BIT));
3727
Harry Yangcdad2bf2016-10-04 17:03:56 -07003728 smblib_hvdcp_adaptive_voltage_change(chg);
3729
Nicholas Troast34db5032016-03-28 12:26:44 -07003730 power_supply_changed(chg->usb_psy);
3731
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08003732 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
3733 if (rc < 0) {
3734 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
3735 return IRQ_HANDLED;
3736 }
3737 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
3738
Nicholas Troast34db5032016-03-28 12:26:44 -07003739 return IRQ_HANDLED;
3740}
3741
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003742static void typec_sink_insertion(struct smb_charger *chg)
3743{
3744 /* when a sink is inserted we should not wait on hvdcp timeout to
3745 * enable pd
3746 */
3747 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3748 false, 0);
3749}
Nicholas Troast34db5032016-03-28 12:26:44 -07003750
Harry Yangd89ff1f2016-12-05 14:59:11 -08003751static void typec_sink_removal(struct smb_charger *chg)
3752{
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303753 smblib_set_charge_param(chg, &chg->param.freq_boost,
3754 chg->chg_freq.freq_above_otg_threshold);
Harry Yangd89ff1f2016-12-05 14:59:11 -08003755 chg->boost_current_ua = 0;
3756}
3757
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003758static void smblib_handle_typec_removal(struct smb_charger *chg)
3759{
Nicholas Troastfe74c592017-03-14 09:20:55 -07003760 int rc;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303761 struct smb_irq_data *data;
3762 struct storm_watch *wdata;
Nicholas Troastfe74c592017-03-14 09:20:55 -07003763
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003764 chg->cc2_detach_wa_active = false;
3765
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303766 if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) {
3767 smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n");
3768 rc = regulator_disable(chg->dpdm_reg);
3769 if (rc < 0)
3770 smblib_err(chg, "Couldn't disable dpdm regulator rc=%d\n",
3771 rc);
3772 }
3773
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303774 if (chg->wa_flags & BOOST_BACK_WA) {
3775 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
3776 if (data) {
3777 wdata = &data->storm_data;
3778 update_storm_count(wdata, WEAK_CHG_STORM_COUNT);
3779 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
3780 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
3781 false, 0);
3782 }
3783 }
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303784
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003785 /* reset APSD voters */
3786 vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, false, 0);
3787 vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303788
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003789 cancel_delayed_work_sync(&chg->pl_enable_work);
3790 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
3791
3792 /* reset input current limit voters */
3793 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
3794 vote(chg->usb_icl_votable, PD_VOTER, false, 0);
3795 vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
3796 vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
3797 vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
Ashay Jaiswalae23a042017-05-18 15:28:31 +05303798 vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
Abhijeet Dharmapurikar66d2c442017-07-12 11:55:36 -07003799 vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003800
3801 /* reset hvdcp voters */
3802 vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, true, 0);
3803 vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER, true, 0);
3804
3805 /* reset power delivery voters */
3806 vote(chg->pd_allowed_votable, PD_VOTER, false, 0);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003807 vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0);
3808 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER, true, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003809
3810 /* reset usb irq voters */
Harry Yang4bf7d962017-03-13 16:51:43 -07003811 vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
3812 vote(chg->usb_irq_enable_votable, QC_VOTER, false, 0);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003813
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003814 /* reset parallel voters */
3815 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
Harry Yanga796cf72017-07-19 19:26:45 -07003816 vote(chg->pl_disable_votable, FCC_CHANGE_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003817 vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
3818 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
3819 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
Harry Yang1d1034c2016-06-15 12:09:42 -07003820
Nicholas Troast8995a702016-12-05 10:22:22 -08003821 chg->vconn_attempts = 0;
3822 chg->otg_attempts = 0;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05303823 chg->pulse_cnt = 0;
3824 chg->usb_icl_delta_ua = 0;
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003825 chg->voltage_min_uv = MICRO_5V;
3826 chg->voltage_max_uv = MICRO_5V;
3827 chg->pd_active = 0;
3828 chg->pd_hard_reset = 0;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003829 chg->typec_legacy_valid = false;
Harry Yang3b113a52016-12-08 12:37:40 -08003830
Abhijeet Dharmapurikar676bd792017-05-31 16:21:57 -07003831 /* reset back to 120mS tCC debounce */
3832 rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT, 0);
3833 if (rc < 0)
3834 smblib_err(chg, "Couldn't set 120mS tCC debounce rc=%d\n", rc);
3835
Nicholas Troastfe74c592017-03-14 09:20:55 -07003836 /* enable APSD CC trigger for next insertion */
3837 rc = smblib_masked_write(chg, TYPE_C_CFG_REG,
3838 APSD_START_ON_CC_BIT, APSD_START_ON_CC_BIT);
3839 if (rc < 0)
3840 smblib_err(chg, "Couldn't enable APSD_START_ON_CC rc=%d\n", rc);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08003841
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003842 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
3843 /* re-enable AUTH_IRQ_EN_CFG_BIT */
3844 rc = smblib_masked_write(chg,
3845 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
3846 AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
3847 if (rc < 0)
3848 smblib_err(chg,
3849 "Couldn't enable QC auth setting rc=%d\n", rc);
3850 }
3851
3852 /* reconfigure allowed voltage for HVDCP */
3853 rc = smblib_set_adapter_allowance(chg,
3854 USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
3855 if (rc < 0)
3856 smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
3857 rc);
3858
3859 /* enable DRP */
3860 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
3861 TYPEC_POWER_ROLE_CMD_MASK, 0);
3862 if (rc < 0)
3863 smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc);
3864
3865 /* HW controlled CC_OUT */
3866 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
3867 TYPEC_SPARE_CFG_BIT, 0);
3868 if (rc < 0)
3869 smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n", rc);
3870
3871 /* restore crude sensor */
3872 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
3873 if (rc < 0)
3874 smblib_err(chg, "Couldn't restore crude sensor rc=%d\n", rc);
3875
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07003876 mutex_lock(&chg->vconn_oc_lock);
3877 if (!chg->vconn_en)
3878 goto unlock;
3879
3880 smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
3881 VCONN_EN_VALUE_BIT, 0);
3882 chg->vconn_en = false;
3883
3884unlock:
3885 mutex_unlock(&chg->vconn_oc_lock);
3886
Abhijeet Dharmapurikar319d6942017-06-05 17:14:17 -07003887 /* clear exit sink based on cc */
3888 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
3889 EXIT_SNK_BASED_ON_CC_BIT, 0);
3890 if (rc < 0)
3891 smblib_err(chg, "Couldn't clear exit_sink_based_on_cc rc=%d\n",
3892 rc);
3893
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08003894 typec_sink_removal(chg);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003895 smblib_update_usb_type(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07003896}
3897
Nicholas Troaste1932e42017-04-12 12:38:18 -07003898static void smblib_handle_typec_insertion(struct smb_charger *chg)
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003899{
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003900 int rc;
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003901
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003902 vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, false, 0);
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003903
Nicholas Troastfe74c592017-03-14 09:20:55 -07003904 /* disable APSD CC trigger since CC is attached */
3905 rc = smblib_masked_write(chg, TYPE_C_CFG_REG, APSD_START_ON_CC_BIT, 0);
3906 if (rc < 0)
3907 smblib_err(chg, "Couldn't disable APSD_START_ON_CC rc=%d\n",
3908 rc);
3909
Nicholas Troaste1932e42017-04-12 12:38:18 -07003910 if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003911 typec_sink_insertion(chg);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003912 else
Harry Yangd89ff1f2016-12-05 14:59:11 -08003913 typec_sink_removal(chg);
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003914}
3915
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303916static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode)
3917{
3918 int rp_ua;
3919 const struct apsd_result *apsd = smblib_get_apsd_result(chg);
3920
3921 if ((apsd->pst != POWER_SUPPLY_TYPE_USB_DCP)
3922 && (apsd->pst != POWER_SUPPLY_TYPE_USB_FLOAT))
3923 return;
3924
3925 /*
3926 * handle Rp change for DCP/FLOAT/OCP.
3927 * Update the current only if the Rp is different from
3928 * the last Rp value.
3929 */
3930 smblib_dbg(chg, PR_MISC, "CC change old_mode=%d new_mode=%d\n",
3931 chg->typec_mode, typec_mode);
3932
3933 rp_ua = get_rp_based_dcp_current(chg, typec_mode);
3934 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua);
3935}
3936
Nicholas Troaste1932e42017-04-12 12:38:18 -07003937static void smblib_handle_typec_cc_state_change(struct smb_charger *chg)
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003938{
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303939 int typec_mode;
3940
Nicholas Troaste1932e42017-04-12 12:38:18 -07003941 if (chg->pr_swap_in_progress)
3942 return;
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003943
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303944 typec_mode = smblib_get_prop_typec_mode(chg);
3945 if (chg->typec_present && (typec_mode != chg->typec_mode))
3946 smblib_handle_rp_change(chg, typec_mode);
3947
3948 chg->typec_mode = typec_mode;
3949
Nicholas Troaste1932e42017-04-12 12:38:18 -07003950 if (!chg->typec_present && chg->typec_mode != POWER_SUPPLY_TYPEC_NONE) {
3951 chg->typec_present = true;
3952 smblib_dbg(chg, PR_MISC, "TypeC %s insertion\n",
3953 smblib_typec_mode_name[chg->typec_mode]);
3954 smblib_handle_typec_insertion(chg);
3955 } else if (chg->typec_present &&
3956 chg->typec_mode == POWER_SUPPLY_TYPEC_NONE) {
3957 chg->typec_present = false;
3958 smblib_dbg(chg, PR_MISC, "TypeC removal\n");
3959 smblib_handle_typec_removal(chg);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003960 }
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003961
Abhijeet Dharmapurikar66d2c442017-07-12 11:55:36 -07003962 /* suspend usb if sink */
3963 if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
3964 vote(chg->usb_icl_votable, OTG_VOTER, true, 0);
3965 else
3966 vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
3967
Nicholas Troaste1932e42017-04-12 12:38:18 -07003968 smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n",
3969 smblib_typec_mode_name[chg->typec_mode]);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003970}
3971
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003972static void smblib_usb_typec_change(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07003973{
Nicholas Troast34db5032016-03-28 12:26:44 -07003974 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07003975
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07003976 rc = smblib_multibyte_read(chg, TYPE_C_STATUS_1_REG,
3977 chg->typec_status, 5);
Nicholas Troast34db5032016-03-28 12:26:44 -07003978 if (rc < 0) {
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07003979 smblib_err(chg, "Couldn't cache USB Type-C status rc=%d\n", rc);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003980 return;
Nicholas Troast34db5032016-03-28 12:26:44 -07003981 }
Nicholas Troast34db5032016-03-28 12:26:44 -07003982
Nicholas Troaste1932e42017-04-12 12:38:18 -07003983 smblib_handle_typec_cc_state_change(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07003984
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07003985 if (chg->typec_status[3] & TYPEC_VBUS_ERROR_STATUS_BIT)
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003986 smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n");
Harry Yangd757c0f2016-09-23 10:52:05 -07003987
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07003988 if (chg->typec_status[3] & TYPEC_VCONN_OVERCURR_STATUS_BIT)
Nicholas Troastb11015f2017-01-17 17:56:45 -08003989 schedule_work(&chg->vconn_oc_work);
Nicholas Troast8995a702016-12-05 10:22:22 -08003990
Nicholas Troastb1486552016-11-10 08:20:11 -08003991 power_supply_changed(chg->usb_psy);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003992}
3993
3994irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
3995{
3996 struct smb_irq_data *irq_data = data;
3997 struct smb_charger *chg = irq_data->parent_data;
3998
3999 if (chg->micro_usb_mode) {
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05304000 cancel_delayed_work_sync(&chg->uusb_otg_work);
4001 vote(chg->awake_votable, OTG_DELAY_VOTER, true, 0);
4002 smblib_dbg(chg, PR_INTERRUPT, "Scheduling OTG work\n");
4003 schedule_delayed_work(&chg->uusb_otg_work,
4004 msecs_to_jiffies(chg->otg_delay_ms));
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004005 return IRQ_HANDLED;
4006 }
4007
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004008 if (chg->cc2_detach_wa_active || chg->typec_en_dis_active) {
4009 smblib_dbg(chg, PR_INTERRUPT, "Ignoring since %s active\n",
4010 chg->cc2_detach_wa_active ?
4011 "cc2_detach_wa" : "typec_en_dis");
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004012 return IRQ_HANDLED;
4013 }
4014
Abhijeet Dharmapurikar049b2552017-07-12 11:27:51 -07004015 if (chg->pr_swap_in_progress) {
4016 smblib_dbg(chg, PR_INTERRUPT,
4017 "Ignoring since pr_swap_in_progress\n");
4018 return IRQ_HANDLED;
4019 }
4020
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004021 mutex_lock(&chg->lock);
4022 smblib_usb_typec_change(chg);
4023 mutex_unlock(&chg->lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07004024 return IRQ_HANDLED;
4025}
4026
Abhijeet Dharmapurikar23916642016-10-03 10:38:50 -07004027irqreturn_t smblib_handle_dc_plugin(int irq, void *data)
4028{
4029 struct smb_irq_data *irq_data = data;
4030 struct smb_charger *chg = irq_data->parent_data;
4031
4032 power_supply_changed(chg->dc_psy);
4033 return IRQ_HANDLED;
4034}
4035
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004036irqreturn_t smblib_handle_high_duty_cycle(int irq, void *data)
4037{
4038 struct smb_irq_data *irq_data = data;
4039 struct smb_charger *chg = irq_data->parent_data;
4040
4041 chg->is_hdc = true;
4042 schedule_delayed_work(&chg->clear_hdc_work, msecs_to_jiffies(60));
4043
4044 return IRQ_HANDLED;
4045}
4046
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05304047static void smblib_bb_removal_work(struct work_struct *work)
4048{
4049 struct smb_charger *chg = container_of(work, struct smb_charger,
4050 bb_removal_work.work);
4051
4052 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
4053 vote(chg->awake_votable, BOOST_BACK_VOTER, false, 0);
4054}
4055
4056#define BOOST_BACK_UNVOTE_DELAY_MS 750
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304057#define BOOST_BACK_STORM_COUNT 3
4058#define WEAK_CHG_STORM_COUNT 8
Nicholas Troastabedaf72016-09-16 11:07:45 -07004059irqreturn_t smblib_handle_switcher_power_ok(int irq, void *data)
4060{
4061 struct smb_irq_data *irq_data = data;
4062 struct smb_charger *chg = irq_data->parent_data;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304063 struct storm_watch *wdata = &irq_data->storm_data;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004064 int rc, usb_icl;
Nicholas Troastabedaf72016-09-16 11:07:45 -07004065 u8 stat;
4066
4067 if (!(chg->wa_flags & BOOST_BACK_WA))
4068 return IRQ_HANDLED;
4069
4070 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
4071 if (rc < 0) {
4072 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n", rc);
4073 return IRQ_HANDLED;
4074 }
4075
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004076 /* skip suspending input if its already suspended by some other voter */
4077 usb_icl = get_effective_result(chg->usb_icl_votable);
4078 if ((stat & USE_USBIN_BIT) && usb_icl >= 0 && usb_icl < USBIN_25MA)
Nicholas Troastabedaf72016-09-16 11:07:45 -07004079 return IRQ_HANDLED;
4080
Abhijeet Dharmapurikar2823fe32016-12-05 17:52:11 -08004081 if (stat & USE_DCIN_BIT)
Nicholas Troastabedaf72016-09-16 11:07:45 -07004082 return IRQ_HANDLED;
4083
4084 if (is_storming(&irq_data->storm_data)) {
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05304085 /* This could be a weak charger reduce ICL */
4086 if (!is_client_vote_enabled(chg->usb_icl_votable,
4087 WEAK_CHARGER_VOTER)) {
4088 smblib_err(chg,
4089 "Weak charger detected: voting %dmA ICL\n",
4090 *chg->weak_chg_icl_ua / 1000);
4091 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
4092 true, *chg->weak_chg_icl_ua);
4093 /*
4094 * reset storm data and set the storm threshold
4095 * to 3 for reverse boost detection.
4096 */
4097 update_storm_count(wdata, BOOST_BACK_STORM_COUNT);
4098 } else {
4099 smblib_err(chg,
4100 "Reverse boost detected: voting 0mA to suspend input\n");
4101 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, true, 0);
4102 vote(chg->awake_votable, BOOST_BACK_VOTER, true, 0);
4103 /*
4104 * Remove the boost-back vote after a delay, to avoid
4105 * permanently suspending the input if the boost-back
4106 * condition is unintentionally hit.
4107 */
4108 schedule_delayed_work(&chg->bb_removal_work,
4109 msecs_to_jiffies(BOOST_BACK_UNVOTE_DELAY_MS));
4110 }
Nicholas Troastabedaf72016-09-16 11:07:45 -07004111 }
4112
4113 return IRQ_HANDLED;
4114}
4115
Nicholas Troast15dc0c82016-10-18 15:15:21 -07004116irqreturn_t smblib_handle_wdog_bark(int irq, void *data)
4117{
4118 struct smb_irq_data *irq_data = data;
4119 struct smb_charger *chg = irq_data->parent_data;
4120 int rc;
4121
4122 rc = smblib_write(chg, BARK_BITE_WDOG_PET_REG, BARK_BITE_WDOG_PET_BIT);
4123 if (rc < 0)
4124 smblib_err(chg, "Couldn't pet the dog rc=%d\n", rc);
4125
4126 return IRQ_HANDLED;
4127}
4128
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004129/**************
4130 * Additional USB PSY getters/setters
4131 * that call interrupt functions
4132 ***************/
4133
4134int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg,
4135 union power_supply_propval *val)
4136{
4137 val->intval = chg->pr_swap_in_progress;
4138 return 0;
4139}
4140
4141int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg,
4142 const union power_supply_propval *val)
4143{
Abhijeet Dharmapurikar676bd792017-05-31 16:21:57 -07004144 int rc;
4145
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004146 chg->pr_swap_in_progress = val->intval;
4147 /*
4148 * call the cc changed irq to handle real removals while
4149 * PR_SWAP was in progress
4150 */
4151 smblib_usb_typec_change(chg);
Abhijeet Dharmapurikar676bd792017-05-31 16:21:57 -07004152 rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT,
4153 val->intval ? TCC_DEBOUNCE_20MS_BIT : 0);
4154 if (rc < 0)
4155 smblib_err(chg, "Couldn't set tCC debounce rc=%d\n", rc);
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004156 return 0;
4157}
4158
Nicholas Troast34db5032016-03-28 12:26:44 -07004159/***************
4160 * Work Queues *
4161 ***************/
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05304162static void smblib_uusb_otg_work(struct work_struct *work)
4163{
4164 struct smb_charger *chg = container_of(work, struct smb_charger,
4165 uusb_otg_work.work);
4166 int rc;
4167 u8 stat;
4168 bool otg;
4169
4170 rc = smblib_read(chg, TYPE_C_STATUS_3_REG, &stat);
4171 if (rc < 0) {
4172 smblib_err(chg, "Couldn't read TYPE_C_STATUS_3 rc=%d\n", rc);
4173 goto out;
4174 }
4175
4176 otg = !!(stat & (U_USB_GND_NOVBUS_BIT | U_USB_GND_BIT));
4177 extcon_set_cable_state_(chg->extcon, EXTCON_USB_HOST, otg);
4178 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_3 = 0x%02x OTG=%d\n",
4179 stat, otg);
4180 power_supply_changed(chg->usb_psy);
4181
4182out:
4183 vote(chg->awake_votable, OTG_DELAY_VOTER, false, 0);
4184}
4185
Nicholas Troast34db5032016-03-28 12:26:44 -07004186
4187static void smblib_hvdcp_detect_work(struct work_struct *work)
4188{
4189 struct smb_charger *chg = container_of(work, struct smb_charger,
4190 hvdcp_detect_work.work);
Nicholas Troast34db5032016-03-28 12:26:44 -07004191
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07004192 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
4193 false, 0);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004194 power_supply_changed(chg->usb_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07004195}
4196
Harry Yangfe913842016-08-10 12:27:28 -07004197static void bms_update_work(struct work_struct *work)
Harry Yang5e1a5222016-07-26 15:16:04 -07004198{
4199 struct smb_charger *chg = container_of(work, struct smb_charger,
4200 bms_update_work);
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05304201
4202 smblib_suspend_on_debug_battery(chg);
4203
4204 if (chg->batt_psy)
4205 power_supply_changed(chg->batt_psy);
Harry Yang5e1a5222016-07-26 15:16:04 -07004206}
4207
Harry Yangfe913842016-08-10 12:27:28 -07004208static void step_soc_req_work(struct work_struct *work)
4209{
4210 struct smb_charger *chg = container_of(work, struct smb_charger,
4211 step_soc_req_work.work);
4212 union power_supply_propval pval = {0, };
4213 int rc;
4214
4215 rc = smblib_get_prop_batt_capacity(chg, &pval);
4216 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004217 smblib_err(chg, "Couldn't get batt capacity rc=%d\n", rc);
Harry Yangfe913842016-08-10 12:27:28 -07004218 return;
4219 }
4220
4221 step_charge_soc_update(chg, pval.intval);
4222}
4223
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004224static void clear_hdc_work(struct work_struct *work)
4225{
4226 struct smb_charger *chg = container_of(work, struct smb_charger,
4227 clear_hdc_work.work);
4228
4229 chg->is_hdc = 0;
4230}
4231
Harry Yang755a34b2016-11-01 01:18:51 -07004232static void rdstd_cc2_detach_work(struct work_struct *work)
4233{
4234 int rc;
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004235 u8 stat4, stat5;
Harry Yang755a34b2016-11-01 01:18:51 -07004236 struct smb_charger *chg = container_of(work, struct smb_charger,
4237 rdstd_cc2_detach_work);
4238
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004239 if (!chg->cc2_detach_wa_active)
4240 return;
4241
Harry Yang755a34b2016-11-01 01:18:51 -07004242 /*
4243 * WA steps -
4244 * 1. Enable both UFP and DFP, wait for 10ms.
4245 * 2. Disable DFP, wait for 30ms.
4246 * 3. Removal detected if both TYPEC_DEBOUNCE_DONE_STATUS
4247 * and TIMER_STAGE bits are gone, otherwise repeat all by
4248 * work rescheduling.
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004249 * Note, work will be cancelled when USB_PLUGIN rises.
Harry Yang755a34b2016-11-01 01:18:51 -07004250 */
4251
4252 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4253 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT,
4254 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT);
4255 if (rc < 0) {
4256 smblib_err(chg, "Couldn't write TYPE_C_CTRL_REG rc=%d\n", rc);
4257 return;
4258 }
4259
4260 usleep_range(10000, 11000);
4261
4262 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4263 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT,
4264 UFP_EN_CMD_BIT);
4265 if (rc < 0) {
4266 smblib_err(chg, "Couldn't write TYPE_C_CTRL_REG rc=%d\n", rc);
4267 return;
4268 }
4269
4270 usleep_range(30000, 31000);
4271
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004272 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
Harry Yang755a34b2016-11-01 01:18:51 -07004273 if (rc < 0) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004274 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
Harry Yang755a34b2016-11-01 01:18:51 -07004275 return;
4276 }
Harry Yang755a34b2016-11-01 01:18:51 -07004277
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004278 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
Harry Yang755a34b2016-11-01 01:18:51 -07004279 if (rc < 0) {
4280 smblib_err(chg,
4281 "Couldn't read TYPE_C_STATUS_5_REG rc=%d\n", rc);
4282 return;
4283 }
Harry Yang755a34b2016-11-01 01:18:51 -07004284
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004285 if ((stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT)
4286 || (stat5 & TIMER_STAGE_2_BIT)) {
4287 smblib_dbg(chg, PR_MISC, "rerunning DD=%d TS2BIT=%d\n",
4288 (int)(stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT),
4289 (int)(stat5 & TIMER_STAGE_2_BIT));
4290 goto rerun;
4291 }
4292
4293 smblib_dbg(chg, PR_MISC, "Bingo CC2 Removal detected\n");
4294 chg->cc2_detach_wa_active = false;
4295 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4296 EXIT_SNK_BASED_ON_CC_BIT, 0);
Harry Yang755a34b2016-11-01 01:18:51 -07004297 smblib_reg_block_restore(chg, cc2_detach_settings);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004298 mutex_lock(&chg->lock);
4299 smblib_usb_typec_change(chg);
4300 mutex_unlock(&chg->lock);
Harry Yang755a34b2016-11-01 01:18:51 -07004301 return;
4302
4303rerun:
4304 schedule_work(&chg->rdstd_cc2_detach_work);
4305}
4306
Nicholas Troastb11015f2017-01-17 17:56:45 -08004307static void smblib_otg_oc_exit(struct smb_charger *chg, bool success)
4308{
4309 int rc;
4310
4311 chg->otg_attempts = 0;
4312 if (!success) {
4313 smblib_err(chg, "OTG soft start failed\n");
4314 chg->otg_en = false;
4315 }
4316
4317 smblib_dbg(chg, PR_OTG, "enabling VBUS < 1V check\n");
4318 rc = smblib_masked_write(chg, OTG_CFG_REG,
4319 QUICKSTART_OTG_FASTROLESWAP_BIT, 0);
4320 if (rc < 0)
4321 smblib_err(chg, "Couldn't enable VBUS < 1V check rc=%d\n", rc);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004322}
4323
4324#define MAX_OC_FALLING_TRIES 10
4325static void smblib_otg_oc_work(struct work_struct *work)
4326{
4327 struct smb_charger *chg = container_of(work, struct smb_charger,
4328 otg_oc_work);
4329 int rc, i;
4330 u8 stat;
4331
4332 if (!chg->vbus_vreg || !chg->vbus_vreg->rdev)
4333 return;
4334
4335 smblib_err(chg, "over-current detected on VBUS\n");
4336 mutex_lock(&chg->otg_oc_lock);
4337 if (!chg->otg_en)
4338 goto unlock;
4339
4340 smblib_dbg(chg, PR_OTG, "disabling VBUS < 1V check\n");
4341 smblib_masked_write(chg, OTG_CFG_REG,
4342 QUICKSTART_OTG_FASTROLESWAP_BIT,
4343 QUICKSTART_OTG_FASTROLESWAP_BIT);
4344
4345 /*
4346 * If 500ms has passed and another over-current interrupt has not
4347 * triggered then it is likely that the software based soft start was
4348 * successful and the VBUS < 1V restriction should be re-enabled.
4349 */
4350 schedule_delayed_work(&chg->otg_ss_done_work, msecs_to_jiffies(500));
4351
4352 rc = _smblib_vbus_regulator_disable(chg->vbus_vreg->rdev);
4353 if (rc < 0) {
4354 smblib_err(chg, "Couldn't disable VBUS rc=%d\n", rc);
4355 goto unlock;
4356 }
4357
4358 if (++chg->otg_attempts > OTG_MAX_ATTEMPTS) {
4359 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4360 smblib_err(chg, "OTG failed to enable after %d attempts\n",
4361 chg->otg_attempts - 1);
4362 smblib_otg_oc_exit(chg, false);
4363 goto unlock;
4364 }
4365
4366 /*
4367 * The real time status should go low within 10ms. Poll every 1-2ms to
4368 * minimize the delay when re-enabling OTG.
4369 */
4370 for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) {
4371 usleep_range(1000, 2000);
4372 rc = smblib_read(chg, OTG_BASE + INT_RT_STS_OFFSET, &stat);
4373 if (rc >= 0 && !(stat & OTG_OVERCURRENT_RT_STS_BIT))
4374 break;
4375 }
4376
4377 if (i >= MAX_OC_FALLING_TRIES) {
4378 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4379 smblib_err(chg, "OTG OC did not fall after %dms\n",
4380 2 * MAX_OC_FALLING_TRIES);
4381 smblib_otg_oc_exit(chg, false);
4382 goto unlock;
4383 }
4384
4385 smblib_dbg(chg, PR_OTG, "OTG OC fell after %dms\n", 2 * i + 1);
4386 rc = _smblib_vbus_regulator_enable(chg->vbus_vreg->rdev);
4387 if (rc < 0) {
4388 smblib_err(chg, "Couldn't enable VBUS rc=%d\n", rc);
4389 goto unlock;
4390 }
4391
4392unlock:
4393 mutex_unlock(&chg->otg_oc_lock);
4394}
4395
4396static void smblib_vconn_oc_work(struct work_struct *work)
4397{
4398 struct smb_charger *chg = container_of(work, struct smb_charger,
4399 vconn_oc_work);
4400 int rc, i;
4401 u8 stat;
4402
Ashay Jaiswal15edce42017-03-31 23:29:58 +05304403 if (chg->micro_usb_mode)
4404 return;
4405
Nicholas Troastb11015f2017-01-17 17:56:45 -08004406 smblib_err(chg, "over-current detected on VCONN\n");
4407 if (!chg->vconn_vreg || !chg->vconn_vreg->rdev)
4408 return;
4409
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07004410 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004411 rc = _smblib_vconn_regulator_disable(chg->vconn_vreg->rdev);
4412 if (rc < 0) {
4413 smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc);
4414 goto unlock;
4415 }
4416
4417 if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
4418 smblib_err(chg, "VCONN failed to enable after %d attempts\n",
4419 chg->otg_attempts - 1);
4420 chg->vconn_en = false;
4421 chg->vconn_attempts = 0;
4422 goto unlock;
4423 }
4424
4425 /*
4426 * The real time status should go low within 10ms. Poll every 1-2ms to
4427 * minimize the delay when re-enabling OTG.
4428 */
4429 for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) {
4430 usleep_range(1000, 2000);
4431 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
4432 if (rc >= 0 && !(stat & TYPEC_VCONN_OVERCURR_STATUS_BIT))
4433 break;
4434 }
4435
4436 if (i >= MAX_OC_FALLING_TRIES) {
4437 smblib_err(chg, "VCONN OC did not fall after %dms\n",
4438 2 * MAX_OC_FALLING_TRIES);
4439 chg->vconn_en = false;
4440 chg->vconn_attempts = 0;
4441 goto unlock;
4442 }
4443
4444 smblib_dbg(chg, PR_OTG, "VCONN OC fell after %dms\n", 2 * i + 1);
4445 if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
4446 smblib_err(chg, "VCONN failed to enable after %d attempts\n",
4447 chg->vconn_attempts - 1);
4448 chg->vconn_en = false;
4449 goto unlock;
4450 }
4451
4452 rc = _smblib_vconn_regulator_enable(chg->vconn_vreg->rdev);
4453 if (rc < 0) {
4454 smblib_err(chg, "Couldn't enable VCONN rc=%d\n", rc);
4455 goto unlock;
4456 }
4457
4458unlock:
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07004459 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004460}
4461
4462static void smblib_otg_ss_done_work(struct work_struct *work)
4463{
4464 struct smb_charger *chg = container_of(work, struct smb_charger,
4465 otg_ss_done_work.work);
4466 int rc;
4467 bool success = false;
4468 u8 stat;
4469
4470 mutex_lock(&chg->otg_oc_lock);
4471 rc = smblib_read(chg, OTG_STATUS_REG, &stat);
4472 if (rc < 0)
4473 smblib_err(chg, "Couldn't read OTG status rc=%d\n", rc);
4474 else if (stat & BOOST_SOFTSTART_DONE_BIT)
4475 success = true;
4476
4477 smblib_otg_oc_exit(chg, success);
4478 mutex_unlock(&chg->otg_oc_lock);
4479}
4480
Ashay Jaiswal4d825782017-02-18 10:11:34 +05304481static void smblib_icl_change_work(struct work_struct *work)
4482{
4483 struct smb_charger *chg = container_of(work, struct smb_charger,
4484 icl_change_work.work);
4485 int rc, settled_ua;
4486
4487 rc = smblib_get_charge_param(chg, &chg->param.icl_stat, &settled_ua);
4488 if (rc < 0) {
4489 smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
4490 return;
4491 }
4492
4493 power_supply_changed(chg->usb_main_psy);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05304494
4495 smblib_dbg(chg, PR_INTERRUPT, "icl_settled=%d\n", settled_ua);
4496}
4497
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304498static void smblib_pl_enable_work(struct work_struct *work)
4499{
4500 struct smb_charger *chg = container_of(work, struct smb_charger,
4501 pl_enable_work.work);
4502
4503 smblib_dbg(chg, PR_PARALLEL, "timer expired, enabling parallel\n");
4504 vote(chg->pl_disable_votable, PL_DELAY_VOTER, false, 0);
4505 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
4506}
4507
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004508static void smblib_legacy_detection_work(struct work_struct *work)
4509{
4510 struct smb_charger *chg = container_of(work, struct smb_charger,
4511 legacy_detection_work);
4512 int rc;
4513 u8 stat;
4514 bool legacy, rp_high;
4515
4516 mutex_lock(&chg->lock);
4517 chg->typec_en_dis_active = 1;
4518 smblib_dbg(chg, PR_MISC, "running legacy unknown workaround\n");
4519 rc = smblib_masked_write(chg,
4520 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4521 TYPEC_DISABLE_CMD_BIT,
4522 TYPEC_DISABLE_CMD_BIT);
4523 if (rc < 0)
4524 smblib_err(chg, "Couldn't disable type-c rc=%d\n", rc);
4525
4526 /* wait for the adapter to turn off VBUS */
4527 msleep(500);
4528
4529 rc = smblib_masked_write(chg,
4530 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4531 TYPEC_DISABLE_CMD_BIT, 0);
4532 if (rc < 0)
4533 smblib_err(chg, "Couldn't enable type-c rc=%d\n", rc);
4534
4535 /* wait for type-c detection to complete */
4536 msleep(100);
4537
4538 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat);
4539 if (rc < 0) {
4540 smblib_err(chg, "Couldn't read typec stat5 rc = %d\n", rc);
4541 goto unlock;
4542 }
4543
4544 chg->typec_legacy_valid = true;
4545 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
4546 legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT;
Nicholas Troaste1932e42017-04-12 12:38:18 -07004547 rp_high = chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004548 if (!legacy || !rp_high)
4549 vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
4550 false, 0);
4551
4552unlock:
4553 chg->typec_en_dis_active = 0;
Nicholas Troast6439e172017-06-02 14:45:39 -07004554 smblib_usb_typec_change(chg);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004555 mutex_unlock(&chg->lock);
4556}
4557
Harry Yangba874ce2016-08-19 14:17:01 -07004558static int smblib_create_votables(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07004559{
4560 int rc = 0;
4561
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304562 chg->fcc_votable = find_votable("FCC");
Harry Yang0c35ff62017-04-06 00:02:30 -07004563 if (chg->fcc_votable == NULL) {
4564 rc = -EINVAL;
4565 smblib_err(chg, "Couldn't find FCC votable rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304566 return rc;
4567 }
4568
4569 chg->fv_votable = find_votable("FV");
Harry Yang0c35ff62017-04-06 00:02:30 -07004570 if (chg->fv_votable == NULL) {
4571 rc = -EINVAL;
4572 smblib_err(chg, "Couldn't find FV votable rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304573 return rc;
4574 }
4575
Ashay Jaiswalae1586d2017-03-22 23:18:51 +05304576 chg->usb_icl_votable = find_votable("USB_ICL");
4577 if (!chg->usb_icl_votable) {
Harry Yang0c35ff62017-04-06 00:02:30 -07004578 rc = -EINVAL;
4579 smblib_err(chg, "Couldn't find USB_ICL votable rc=%d\n", rc);
Ashay Jaiswalae1586d2017-03-22 23:18:51 +05304580 return rc;
4581 }
4582
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304583 chg->pl_disable_votable = find_votable("PL_DISABLE");
Harry Yang0c35ff62017-04-06 00:02:30 -07004584 if (chg->pl_disable_votable == NULL) {
4585 rc = -EINVAL;
4586 smblib_err(chg, "Couldn't find votable PL_DISABLE rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304587 return rc;
4588 }
Abhijeet Dharmapurikar38ef1422017-05-18 15:37:56 -07004589
4590 chg->pl_enable_votable_indirect = find_votable("PL_ENABLE_INDIRECT");
4591 if (chg->pl_enable_votable_indirect == NULL) {
4592 rc = -EINVAL;
4593 smblib_err(chg,
4594 "Couldn't find votable PL_ENABLE_INDIRECT rc=%d\n",
4595 rc);
4596 return rc;
4597 }
4598
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304599 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304600
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004601 chg->dc_suspend_votable = create_votable("DC_SUSPEND", VOTE_SET_ANY,
4602 smblib_dc_suspend_vote_callback,
4603 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07004604 if (IS_ERR(chg->dc_suspend_votable)) {
4605 rc = PTR_ERR(chg->dc_suspend_votable);
4606 return rc;
4607 }
4608
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004609 chg->dc_icl_votable = create_votable("DC_ICL", VOTE_MIN,
4610 smblib_dc_icl_vote_callback,
4611 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07004612 if (IS_ERR(chg->dc_icl_votable)) {
4613 rc = PTR_ERR(chg->dc_icl_votable);
4614 return rc;
4615 }
4616
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07004617 chg->pd_disallowed_votable_indirect
4618 = create_votable("PD_DISALLOWED_INDIRECT", VOTE_SET_ANY,
4619 smblib_pd_disallowed_votable_indirect_callback, chg);
4620 if (IS_ERR(chg->pd_disallowed_votable_indirect)) {
4621 rc = PTR_ERR(chg->pd_disallowed_votable_indirect);
4622 return rc;
4623 }
4624
4625 chg->pd_allowed_votable = create_votable("PD_ALLOWED",
4626 VOTE_SET_ANY, NULL, NULL);
Nicholas Troast34db5032016-03-28 12:26:44 -07004627 if (IS_ERR(chg->pd_allowed_votable)) {
4628 rc = PTR_ERR(chg->pd_allowed_votable);
4629 return rc;
4630 }
4631
Harry Yang223c6282016-06-14 15:48:36 -07004632 chg->awake_votable = create_votable("AWAKE", VOTE_SET_ANY,
4633 smblib_awake_vote_callback,
4634 chg);
4635 if (IS_ERR(chg->awake_votable)) {
4636 rc = PTR_ERR(chg->awake_votable);
4637 return rc;
4638 }
4639
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07004640 chg->chg_disable_votable = create_votable("CHG_DISABLE", VOTE_SET_ANY,
4641 smblib_chg_disable_vote_callback,
4642 chg);
4643 if (IS_ERR(chg->chg_disable_votable)) {
4644 rc = PTR_ERR(chg->chg_disable_votable);
4645 return rc;
4646 }
4647
Harry Yangaba1f5f2016-09-28 10:47:29 -07004648
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05304649 chg->hvdcp_disable_votable_indirect = create_votable(
4650 "HVDCP_DISABLE_INDIRECT",
4651 VOTE_SET_ANY,
4652 smblib_hvdcp_disable_indirect_vote_callback,
4653 chg);
4654 if (IS_ERR(chg->hvdcp_disable_votable_indirect)) {
4655 rc = PTR_ERR(chg->hvdcp_disable_votable_indirect);
4656 return rc;
4657 }
4658
4659 chg->hvdcp_enable_votable = create_votable("HVDCP_ENABLE",
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07004660 VOTE_SET_ANY,
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05304661 smblib_hvdcp_enable_vote_callback,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07004662 chg);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05304663 if (IS_ERR(chg->hvdcp_enable_votable)) {
4664 rc = PTR_ERR(chg->hvdcp_enable_votable);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07004665 return rc;
4666 }
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07004667
4668 chg->apsd_disable_votable = create_votable("APSD_DISABLE",
4669 VOTE_SET_ANY,
4670 smblib_apsd_disable_vote_callback,
4671 chg);
4672 if (IS_ERR(chg->apsd_disable_votable)) {
4673 rc = PTR_ERR(chg->apsd_disable_votable);
4674 return rc;
4675 }
4676
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05304677 chg->hvdcp_hw_inov_dis_votable = create_votable("HVDCP_HW_INOV_DIS",
4678 VOTE_SET_ANY,
4679 smblib_hvdcp_hw_inov_dis_vote_callback,
4680 chg);
4681 if (IS_ERR(chg->hvdcp_hw_inov_dis_votable)) {
4682 rc = PTR_ERR(chg->hvdcp_hw_inov_dis_votable);
4683 return rc;
4684 }
4685
Harry Yang4bf7d962017-03-13 16:51:43 -07004686 chg->usb_irq_enable_votable = create_votable("USB_IRQ_DISABLE",
4687 VOTE_SET_ANY,
4688 smblib_usb_irq_enable_vote_callback,
4689 chg);
4690 if (IS_ERR(chg->usb_irq_enable_votable)) {
4691 rc = PTR_ERR(chg->usb_irq_enable_votable);
4692 return rc;
4693 }
4694
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004695 chg->typec_irq_disable_votable = create_votable("TYPEC_IRQ_DISABLE",
4696 VOTE_SET_ANY,
4697 smblib_typec_irq_disable_vote_callback,
4698 chg);
4699 if (IS_ERR(chg->typec_irq_disable_votable)) {
4700 rc = PTR_ERR(chg->typec_irq_disable_votable);
4701 return rc;
4702 }
4703
Nicholas Troast320839e2016-06-03 10:18:00 -07004704 return rc;
4705}
4706
Harry Yangba874ce2016-08-19 14:17:01 -07004707static void smblib_destroy_votables(struct smb_charger *chg)
4708{
Harry Yangba874ce2016-08-19 14:17:01 -07004709 if (chg->dc_suspend_votable)
4710 destroy_votable(chg->dc_suspend_votable);
Harry Yangba874ce2016-08-19 14:17:01 -07004711 if (chg->usb_icl_votable)
4712 destroy_votable(chg->usb_icl_votable);
4713 if (chg->dc_icl_votable)
4714 destroy_votable(chg->dc_icl_votable);
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07004715 if (chg->pd_disallowed_votable_indirect)
4716 destroy_votable(chg->pd_disallowed_votable_indirect);
Harry Yangba874ce2016-08-19 14:17:01 -07004717 if (chg->pd_allowed_votable)
4718 destroy_votable(chg->pd_allowed_votable);
4719 if (chg->awake_votable)
4720 destroy_votable(chg->awake_votable);
Harry Yangaba1f5f2016-09-28 10:47:29 -07004721 if (chg->chg_disable_votable)
4722 destroy_votable(chg->chg_disable_votable);
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07004723 if (chg->apsd_disable_votable)
4724 destroy_votable(chg->apsd_disable_votable);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05304725 if (chg->hvdcp_hw_inov_dis_votable)
4726 destroy_votable(chg->hvdcp_hw_inov_dis_votable);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004727 if (chg->typec_irq_disable_votable)
4728 destroy_votable(chg->typec_irq_disable_votable);
Harry Yangba874ce2016-08-19 14:17:01 -07004729}
4730
4731static void smblib_iio_deinit(struct smb_charger *chg)
4732{
4733 if (!IS_ERR_OR_NULL(chg->iio.temp_chan))
4734 iio_channel_release(chg->iio.temp_chan);
4735 if (!IS_ERR_OR_NULL(chg->iio.temp_max_chan))
4736 iio_channel_release(chg->iio.temp_max_chan);
4737 if (!IS_ERR_OR_NULL(chg->iio.usbin_i_chan))
4738 iio_channel_release(chg->iio.usbin_i_chan);
4739 if (!IS_ERR_OR_NULL(chg->iio.usbin_v_chan))
4740 iio_channel_release(chg->iio.usbin_v_chan);
Nicholas Troast7dbcad22016-10-05 13:30:18 -07004741 if (!IS_ERR_OR_NULL(chg->iio.batt_i_chan))
4742 iio_channel_release(chg->iio.batt_i_chan);
Harry Yangba874ce2016-08-19 14:17:01 -07004743}
4744
Nicholas Troast320839e2016-06-03 10:18:00 -07004745int smblib_init(struct smb_charger *chg)
4746{
4747 int rc = 0;
4748
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004749 mutex_init(&chg->lock);
Nicholas Troast320839e2016-06-03 10:18:00 -07004750 mutex_init(&chg->write_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004751 mutex_init(&chg->otg_oc_lock);
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07004752 mutex_init(&chg->vconn_oc_lock);
Harry Yangfe913842016-08-10 12:27:28 -07004753 INIT_WORK(&chg->bms_update_work, bms_update_work);
Harry Yang755a34b2016-11-01 01:18:51 -07004754 INIT_WORK(&chg->rdstd_cc2_detach_work, rdstd_cc2_detach_work);
Nicholas Troast320839e2016-06-03 10:18:00 -07004755 INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work);
Harry Yangfe913842016-08-10 12:27:28 -07004756 INIT_DELAYED_WORK(&chg->step_soc_req_work, step_soc_req_work);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004757 INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004758 INIT_WORK(&chg->otg_oc_work, smblib_otg_oc_work);
4759 INIT_WORK(&chg->vconn_oc_work, smblib_vconn_oc_work);
4760 INIT_DELAYED_WORK(&chg->otg_ss_done_work, smblib_otg_ss_done_work);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05304761 INIT_DELAYED_WORK(&chg->icl_change_work, smblib_icl_change_work);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304762 INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004763 INIT_WORK(&chg->legacy_detection_work, smblib_legacy_detection_work);
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05304764 INIT_DELAYED_WORK(&chg->uusb_otg_work, smblib_uusb_otg_work);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05304765 INIT_DELAYED_WORK(&chg->bb_removal_work, smblib_bb_removal_work);
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07004766 chg->fake_capacity = -EINVAL;
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07004767 chg->fake_input_current_limited = -EINVAL;
Nicholas Troast320839e2016-06-03 10:18:00 -07004768
4769 switch (chg->mode) {
4770 case PARALLEL_MASTER:
Harry Yang0c35ff62017-04-06 00:02:30 -07004771 rc = qcom_batt_init();
4772 if (rc < 0) {
4773 smblib_err(chg, "Couldn't init qcom_batt_init rc=%d\n",
4774 rc);
4775 return rc;
4776 }
4777
Nicholas Troast320839e2016-06-03 10:18:00 -07004778 rc = smblib_create_votables(chg);
4779 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004780 smblib_err(chg, "Couldn't create votables rc=%d\n",
Nicholas Troast320839e2016-06-03 10:18:00 -07004781 rc);
Harry Yang58a9e7a2016-06-23 14:54:43 -07004782 return rc;
Nicholas Troast320839e2016-06-03 10:18:00 -07004783 }
Harry Yang58a9e7a2016-06-23 14:54:43 -07004784
Harry Yang5e1a5222016-07-26 15:16:04 -07004785 rc = smblib_register_notifier(chg);
4786 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004787 smblib_err(chg,
Harry Yang5e1a5222016-07-26 15:16:04 -07004788 "Couldn't register notifier rc=%d\n", rc);
4789 return rc;
Harry Yang58a9e7a2016-06-23 14:54:43 -07004790 }
4791
Harry Yang995b7422016-08-29 16:06:50 -07004792 chg->bms_psy = power_supply_get_by_name("bms");
Ashay Jaiswal8afedfc2017-02-03 11:18:22 +05304793 chg->pl.psy = power_supply_get_by_name("parallel");
Nicholas Troast320839e2016-06-03 10:18:00 -07004794 break;
4795 case PARALLEL_SLAVE:
4796 break;
4797 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004798 smblib_err(chg, "Unsupported mode %d\n", chg->mode);
Nicholas Troast320839e2016-06-03 10:18:00 -07004799 return -EINVAL;
4800 }
4801
4802 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07004803}
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004804
4805int smblib_deinit(struct smb_charger *chg)
4806{
Harry Yangba874ce2016-08-19 14:17:01 -07004807 switch (chg->mode) {
4808 case PARALLEL_MASTER:
Harry Yang0c35ff62017-04-06 00:02:30 -07004809 cancel_work_sync(&chg->bms_update_work);
4810 cancel_work_sync(&chg->rdstd_cc2_detach_work);
4811 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
4812 cancel_delayed_work_sync(&chg->step_soc_req_work);
4813 cancel_delayed_work_sync(&chg->clear_hdc_work);
4814 cancel_work_sync(&chg->otg_oc_work);
4815 cancel_work_sync(&chg->vconn_oc_work);
4816 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4817 cancel_delayed_work_sync(&chg->icl_change_work);
4818 cancel_delayed_work_sync(&chg->pl_enable_work);
4819 cancel_work_sync(&chg->legacy_detection_work);
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05304820 cancel_delayed_work_sync(&chg->uusb_otg_work);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05304821 cancel_delayed_work_sync(&chg->bb_removal_work);
Harry Yangba874ce2016-08-19 14:17:01 -07004822 power_supply_unreg_notifier(&chg->nb);
4823 smblib_destroy_votables(chg);
Harry Yang0c35ff62017-04-06 00:02:30 -07004824 qcom_batt_deinit();
Harry Yangba874ce2016-08-19 14:17:01 -07004825 break;
4826 case PARALLEL_SLAVE:
4827 break;
4828 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004829 smblib_err(chg, "Unsupported mode %d\n", chg->mode);
Harry Yangba874ce2016-08-19 14:17:01 -07004830 return -EINVAL;
4831 }
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004832
Harry Yangba874ce2016-08-19 14:17:01 -07004833 smblib_iio_deinit(chg);
Harry Yang5e1a5222016-07-26 15:16:04 -07004834
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004835 return 0;
4836}