blob: ae44f01ce99b04fe1b2a5a6ec2851ed75e765c1e [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;
429
430 rc = smblib_masked_write(chg, USBIN_CMD_IL_REG, USBIN_SUSPEND_BIT,
431 suspend ? USBIN_SUSPEND_BIT : 0);
432 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700433 smblib_err(chg, "Couldn't write %s to USBIN_SUSPEND_BIT rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700434 suspend ? "suspend" : "resume", rc);
435
436 return rc;
437}
438
Nicholas Troast4c310492016-05-12 17:56:35 -0700439int smblib_set_dc_suspend(struct smb_charger *chg, bool suspend)
Nicholas Troast34db5032016-03-28 12:26:44 -0700440{
441 int rc = 0;
442
443 rc = smblib_masked_write(chg, DCIN_CMD_IL_REG, DCIN_SUSPEND_BIT,
444 suspend ? DCIN_SUSPEND_BIT : 0);
445 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700446 smblib_err(chg, "Couldn't write %s to DCIN_SUSPEND_BIT rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700447 suspend ? "suspend" : "resume", rc);
448
449 return rc;
450}
451
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530452static int smblib_set_adapter_allowance(struct smb_charger *chg,
453 u8 allowed_voltage)
454{
455 int rc = 0;
456
457 switch (allowed_voltage) {
458 case USBIN_ADAPTER_ALLOW_12V:
459 case USBIN_ADAPTER_ALLOW_5V_OR_12V:
460 case USBIN_ADAPTER_ALLOW_9V_TO_12V:
461 case USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V:
462 case USBIN_ADAPTER_ALLOW_5V_TO_12V:
463 /* PM660 only support max. 9V */
464 if (chg->smb_version == PM660_SUBTYPE) {
465 smblib_dbg(chg, PR_MISC, "voltage not supported=%d\n",
466 allowed_voltage);
467 allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_9V;
468 }
469 break;
470 }
471
472 rc = smblib_write(chg, USBIN_ADAPTER_ALLOW_CFG_REG, allowed_voltage);
473 if (rc < 0) {
474 smblib_err(chg, "Couldn't write 0x%02x to USBIN_ADAPTER_ALLOW_CFG rc=%d\n",
475 allowed_voltage, rc);
476 return rc;
477 }
478
479 return rc;
480}
481
Nicholas Troast34db5032016-03-28 12:26:44 -0700482#define MICRO_5V 5000000
483#define MICRO_9V 9000000
484#define MICRO_12V 12000000
485static int smblib_set_usb_pd_allowed_voltage(struct smb_charger *chg,
486 int min_allowed_uv, int max_allowed_uv)
487{
488 int rc;
489 u8 allowed_voltage;
490
491 if (min_allowed_uv == MICRO_5V && max_allowed_uv == MICRO_5V) {
492 allowed_voltage = USBIN_ADAPTER_ALLOW_5V;
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530493 smblib_set_opt_freq_buck(chg, chg->chg_freq.freq_5V);
Nicholas Troast34db5032016-03-28 12:26:44 -0700494 } else if (min_allowed_uv == MICRO_9V && max_allowed_uv == MICRO_9V) {
495 allowed_voltage = USBIN_ADAPTER_ALLOW_9V;
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530496 smblib_set_opt_freq_buck(chg, chg->chg_freq.freq_9V);
Nicholas Troast34db5032016-03-28 12:26:44 -0700497 } else if (min_allowed_uv == MICRO_12V && max_allowed_uv == MICRO_12V) {
498 allowed_voltage = USBIN_ADAPTER_ALLOW_12V;
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530499 smblib_set_opt_freq_buck(chg, chg->chg_freq.freq_12V);
Nicholas Troast34db5032016-03-28 12:26:44 -0700500 } else if (min_allowed_uv < MICRO_9V && max_allowed_uv <= MICRO_9V) {
501 allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_9V;
502 } else if (min_allowed_uv < MICRO_9V && max_allowed_uv <= MICRO_12V) {
503 allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_12V;
504 } else if (min_allowed_uv < MICRO_12V && max_allowed_uv <= MICRO_12V) {
505 allowed_voltage = USBIN_ADAPTER_ALLOW_9V_TO_12V;
506 } else {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700507 smblib_err(chg, "invalid allowed voltage [%d, %d]\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700508 min_allowed_uv, max_allowed_uv);
509 return -EINVAL;
510 }
511
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530512 rc = smblib_set_adapter_allowance(chg, allowed_voltage);
Nicholas Troast34db5032016-03-28 12:26:44 -0700513 if (rc < 0) {
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530514 smblib_err(chg, "Couldn't configure adapter allowance rc=%d\n",
515 rc);
Nicholas Troast34db5032016-03-28 12:26:44 -0700516 return rc;
517 }
518
519 return rc;
520}
521
522/********************
523 * HELPER FUNCTIONS *
524 ********************/
525
Nicholas Troast93fb0f02017-03-01 10:17:13 -0800526static void smblib_rerun_apsd(struct smb_charger *chg)
527{
528 int rc;
529
530 smblib_dbg(chg, PR_MISC, "re-running APSD\n");
531 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
532 rc = smblib_masked_write(chg,
533 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
534 AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
535 if (rc < 0)
536 smblib_err(chg, "Couldn't enable HVDCP auth IRQ rc=%d\n",
537 rc);
538 }
539
540 rc = smblib_masked_write(chg, CMD_APSD_REG,
541 APSD_RERUN_BIT, APSD_RERUN_BIT);
542 if (rc < 0)
543 smblib_err(chg, "Couldn't re-run APSD rc=%d\n", rc);
544}
545
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -0700546static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -0700547{
Abhijeet Dharmapurikareda08222016-11-01 11:35:29 -0700548 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -0700549
Jack Pham9696e252016-05-23 11:15:15 -0700550 /* if PD is active, APSD is disabled so won't have a valid result */
Nicholas Troast93fb0f02017-03-01 10:17:13 -0800551 if (chg->pd_active)
Fenglin Wu80826e02017-04-25 21:45:08 +0800552 chg->real_charger_type = POWER_SUPPLY_TYPE_USB_PD;
Nicholas Troast93fb0f02017-03-01 10:17:13 -0800553 else
Fenglin Wu80826e02017-04-25 21:45:08 +0800554 chg->real_charger_type = apsd_result->pst;
Nicholas Troast34db5032016-03-28 12:26:44 -0700555
Nicholas Troast93fb0f02017-03-01 10:17:13 -0800556 smblib_dbg(chg, PR_MISC, "APSD=%s PD=%d\n",
557 apsd_result->name, chg->pd_active);
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -0700558 return apsd_result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700559}
560
Harry Yang5e1a5222016-07-26 15:16:04 -0700561static int smblib_notifier_call(struct notifier_block *nb,
Harry Yang58a9e7a2016-06-23 14:54:43 -0700562 unsigned long ev, void *v)
Harry Yang1d1034c2016-06-15 12:09:42 -0700563{
Harry Yang58a9e7a2016-06-23 14:54:43 -0700564 struct power_supply *psy = v;
Harry Yang5e1a5222016-07-26 15:16:04 -0700565 struct smb_charger *chg = container_of(nb, struct smb_charger, nb);
Harry Yang1d1034c2016-06-15 12:09:42 -0700566
Harry Yang5e1a5222016-07-26 15:16:04 -0700567 if (!strcmp(psy->desc->name, "bms")) {
568 if (!chg->bms_psy)
569 chg->bms_psy = psy;
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530570 if (ev == PSY_EVENT_PROP_CHANGED)
Harry Yang5e1a5222016-07-26 15:16:04 -0700571 schedule_work(&chg->bms_update_work);
572 }
573
Ashay Jaiswal8afedfc2017-02-03 11:18:22 +0530574 if (!chg->pl.psy && !strcmp(psy->desc->name, "parallel"))
Harry Yang58a9e7a2016-06-23 14:54:43 -0700575 chg->pl.psy = psy;
Harry Yang1d1034c2016-06-15 12:09:42 -0700576
Harry Yang58a9e7a2016-06-23 14:54:43 -0700577 return NOTIFY_OK;
578}
579
Harry Yang5e1a5222016-07-26 15:16:04 -0700580static int smblib_register_notifier(struct smb_charger *chg)
Harry Yang58a9e7a2016-06-23 14:54:43 -0700581{
582 int rc;
583
Harry Yang5e1a5222016-07-26 15:16:04 -0700584 chg->nb.notifier_call = smblib_notifier_call;
585 rc = power_supply_reg_notifier(&chg->nb);
Harry Yang58a9e7a2016-06-23 14:54:43 -0700586 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700587 smblib_err(chg, "Couldn't register psy notifier rc = %d\n", rc);
Harry Yang58a9e7a2016-06-23 14:54:43 -0700588 return rc;
589 }
590
591 return 0;
Harry Yang1d1034c2016-06-15 12:09:42 -0700592}
593
Harry Yangfe913842016-08-10 12:27:28 -0700594int smblib_mapping_soc_from_field_value(struct smb_chg_param *param,
595 int val_u, u8 *val_raw)
596{
597 if (val_u > param->max_u || val_u < param->min_u)
598 return -EINVAL;
599
600 *val_raw = val_u << 1;
601
602 return 0;
603}
604
605int smblib_mapping_cc_delta_to_field_value(struct smb_chg_param *param,
606 u8 val_raw)
607{
608 int val_u = val_raw * param->step_u + param->min_u;
609
610 if (val_u > param->max_u)
611 val_u -= param->max_u * 2;
612
613 return val_u;
614}
615
616int smblib_mapping_cc_delta_from_field_value(struct smb_chg_param *param,
617 int val_u, u8 *val_raw)
618{
619 if (val_u > param->max_u || val_u < param->min_u - param->max_u)
620 return -EINVAL;
621
622 val_u += param->max_u * 2 - param->min_u;
623 val_u %= param->max_u * 2;
624 *val_raw = val_u / param->step_u;
625
626 return 0;
627}
628
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530629static void smblib_uusb_removal(struct smb_charger *chg)
630{
631 int rc;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +0530632 struct smb_irq_data *data;
633 struct storm_watch *wdata;
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530634
Ashay Jaiswalc0361672017-03-21 12:24:16 +0530635 cancel_delayed_work_sync(&chg->pl_enable_work);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +0530636
637 if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) {
638 smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n");
639 rc = regulator_disable(chg->dpdm_reg);
640 if (rc < 0)
641 smblib_err(chg, "Couldn't disable dpdm regulator rc=%d\n",
642 rc);
643 }
644
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +0530645 if (chg->wa_flags & BOOST_BACK_WA) {
646 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
647 if (data) {
648 wdata = &data->storm_data;
649 update_storm_count(wdata, WEAK_CHG_STORM_COUNT);
650 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
651 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
652 false, 0);
653 }
654 }
Ashay Jaiswalc0361672017-03-21 12:24:16 +0530655 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
656 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
657
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530658 /* reset both usbin current and voltage votes */
659 vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
660 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
Ashay Jaiswalae23a042017-05-18 15:28:31 +0530661 vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530662
663 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
664
Ashay Jaiswal67ec7072017-02-16 14:14:58 +0530665 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
666 /* re-enable AUTH_IRQ_EN_CFG_BIT */
667 rc = smblib_masked_write(chg,
668 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
669 AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
670 if (rc < 0)
671 smblib_err(chg,
672 "Couldn't enable QC auth setting rc=%d\n", rc);
673 }
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530674
675 /* reconfigure allowed voltage for HVDCP */
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530676 rc = smblib_set_adapter_allowance(chg,
677 USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530678 if (rc < 0)
679 smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
680 rc);
681
682 chg->voltage_min_uv = MICRO_5V;
683 chg->voltage_max_uv = MICRO_5V;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +0530684 chg->usb_icl_delta_ua = 0;
685 chg->pulse_cnt = 0;
Ashay Jaiswal8507aa52017-04-14 09:42:32 +0530686 chg->uusb_apsd_rerun_done = false;
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530687
688 /* clear USB ICL vote for USB_PSY_VOTER */
689 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
690 if (rc < 0)
691 smblib_err(chg, "Couldn't un-vote for USB ICL rc=%d\n", rc);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -0800692
693 /* clear USB ICL vote for DCP_VOTER */
694 rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
695 if (rc < 0)
696 smblib_err(chg,
697 "Couldn't un-vote DCP from USB ICL rc=%d\n", rc);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530698}
699
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530700void smblib_suspend_on_debug_battery(struct smb_charger *chg)
701{
702 int rc;
703 union power_supply_propval val;
704
Ashay Jaiswalda8669b2017-02-10 23:24:23 +0530705 if (!chg->suspend_input_on_debug_batt)
706 return;
707
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530708 rc = power_supply_get_property(chg->bms_psy,
709 POWER_SUPPLY_PROP_DEBUG_BATTERY, &val);
710 if (rc < 0) {
711 smblib_err(chg, "Couldn't get debug battery prop rc=%d\n", rc);
712 return;
713 }
714
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800715 vote(chg->usb_icl_votable, DEBUG_BOARD_VOTER, val.intval, 0);
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530716 vote(chg->dc_suspend_votable, DEBUG_BOARD_VOTER, val.intval, 0);
717 if (val.intval)
718 pr_info("Input suspended: Fake battery\n");
719}
720
Abhijeet Dharmapurikar9dd61292017-01-25 16:40:08 -0800721int smblib_rerun_apsd_if_required(struct smb_charger *chg)
722{
Abhijeet Dharmapurikar9dd61292017-01-25 16:40:08 -0800723 union power_supply_propval val;
724 int rc;
725
726 rc = smblib_get_prop_usb_present(chg, &val);
727 if (rc < 0) {
728 smblib_err(chg, "Couldn't get usb present rc = %d\n", rc);
729 return rc;
730 }
731
732 if (!val.intval)
733 return 0;
734
Abhijeet Dharmapurikar025e63a2017-02-24 14:06:22 -0800735 /* fetch the DPDM regulator */
736 if (!chg->dpdm_reg && of_get_property(chg->dev->of_node,
737 "dpdm-supply", NULL)) {
738 chg->dpdm_reg = devm_regulator_get(chg->dev, "dpdm");
739 if (IS_ERR(chg->dpdm_reg)) {
740 smblib_err(chg, "Couldn't get dpdm regulator rc=%ld\n",
741 PTR_ERR(chg->dpdm_reg));
742 chg->dpdm_reg = NULL;
743 }
Abhijeet Dharmapurikar9dd61292017-01-25 16:40:08 -0800744 }
745
Abhijeet Dharmapurikar025e63a2017-02-24 14:06:22 -0800746 if (chg->dpdm_reg && !regulator_is_enabled(chg->dpdm_reg)) {
747 smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n");
748 rc = regulator_enable(chg->dpdm_reg);
749 if (rc < 0)
750 smblib_err(chg, "Couldn't enable dpdm regulator rc=%d\n",
751 rc);
752 }
753
Ashay Jaiswal8507aa52017-04-14 09:42:32 +0530754 chg->uusb_apsd_rerun_done = true;
Abhijeet Dharmapurikar025e63a2017-02-24 14:06:22 -0800755 smblib_rerun_apsd(chg);
756
Abhijeet Dharmapurikar9dd61292017-01-25 16:40:08 -0800757 return 0;
758}
759
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +0530760static int smblib_get_hw_pulse_cnt(struct smb_charger *chg, int *count)
Ashay Jaiswal6d308da2017-02-18 09:59:23 +0530761{
762 int rc;
763 u8 val[2];
764
765 switch (chg->smb_version) {
766 case PMI8998_SUBTYPE:
767 rc = smblib_read(chg, QC_PULSE_COUNT_STATUS_REG, val);
768 if (rc) {
769 pr_err("failed to read QC_PULSE_COUNT_STATUS_REG rc=%d\n",
770 rc);
771 return rc;
772 }
773 *count = val[0] & QC_PULSE_COUNT_MASK;
774 break;
775 case PM660_SUBTYPE:
776 rc = smblib_multibyte_read(chg,
777 QC_PULSE_COUNT_STATUS_1_REG, val, 2);
778 if (rc) {
779 pr_err("failed to read QC_PULSE_COUNT_STATUS_1_REG rc=%d\n",
780 rc);
781 return rc;
782 }
783 *count = (val[1] << 8) | val[0];
784 break;
785 default:
786 smblib_dbg(chg, PR_PARALLEL, "unknown SMB chip %d\n",
787 chg->smb_version);
788 return -EINVAL;
789 }
790
791 return 0;
792}
793
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +0530794static int smblib_get_pulse_cnt(struct smb_charger *chg, int *count)
795{
796 int rc;
797
798 /* Use software based pulse count if HW INOV is disabled */
799 if (get_effective_result(chg->hvdcp_hw_inov_dis_votable) > 0) {
800 *count = chg->pulse_cnt;
801 return 0;
802 }
803
804 /* Use h/w pulse count if autonomous mode is enabled */
805 rc = smblib_get_hw_pulse_cnt(chg, count);
806 if (rc < 0)
807 smblib_err(chg, "failed to read h/w pulse count rc=%d\n", rc);
808
809 return rc;
810}
811
Nicholas Troastbb76a142016-09-23 11:23:23 -0700812#define USBIN_25MA 25000
813#define USBIN_100MA 100000
814#define USBIN_150MA 150000
815#define USBIN_500MA 500000
816#define USBIN_900MA 900000
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800817
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800818static int set_sdp_current(struct smb_charger *chg, int icl_ua)
Nicholas Troast34db5032016-03-28 12:26:44 -0700819{
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800820 int rc;
821 u8 icl_options;
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700822
Nicholas Troastbb76a142016-09-23 11:23:23 -0700823 /* power source is SDP */
824 switch (icl_ua) {
825 case USBIN_100MA:
826 /* USB 2.0 100mA */
827 icl_options = 0;
828 break;
829 case USBIN_150MA:
830 /* USB 3.0 150mA */
831 icl_options = CFG_USB3P0_SEL_BIT;
832 break;
833 case USBIN_500MA:
834 /* USB 2.0 500mA */
835 icl_options = USB51_MODE_BIT;
836 break;
837 case USBIN_900MA:
838 /* USB 3.0 900mA */
839 icl_options = CFG_USB3P0_SEL_BIT | USB51_MODE_BIT;
840 break;
841 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700842 smblib_err(chg, "ICL %duA isn't supported for SDP\n", icl_ua);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800843 return -EINVAL;
Nicholas Troastbb76a142016-09-23 11:23:23 -0700844 }
Nicholas Troast34db5032016-03-28 12:26:44 -0700845
Nicholas Troastbb76a142016-09-23 11:23:23 -0700846 rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800847 CFG_USB3P0_SEL_BIT | USB51_MODE_BIT, icl_options);
Nicholas Troast34db5032016-03-28 12:26:44 -0700848 if (rc < 0) {
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800849 smblib_err(chg, "Couldn't set ICL options rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -0700850 return rc;
851 }
852
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800853 return rc;
854}
855
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700856static int get_sdp_current(struct smb_charger *chg, int *icl_ua)
857{
858 int rc;
859 u8 icl_options;
860 bool usb3 = false;
861
862 rc = smblib_read(chg, USBIN_ICL_OPTIONS_REG, &icl_options);
863 if (rc < 0) {
864 smblib_err(chg, "Couldn't get ICL options rc=%d\n", rc);
865 return rc;
866 }
867
868 usb3 = (icl_options & CFG_USB3P0_SEL_BIT);
869
870 if (icl_options & USB51_MODE_BIT)
871 *icl_ua = usb3 ? USBIN_900MA : USBIN_500MA;
872 else
873 *icl_ua = usb3 ? USBIN_150MA : USBIN_100MA;
874
875 return rc;
876}
877
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530878int smblib_set_icl_current(struct smb_charger *chg, int icl_ua)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800879{
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800880 int rc = 0;
881 bool override;
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800882
883 /* suspend and return if 25mA or less is requested */
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530884 if (icl_ua < USBIN_25MA)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800885 return smblib_set_usb_suspend(chg, true);
886
887 disable_irq_nosync(chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq);
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530888 if (icl_ua == INT_MAX)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800889 goto override_suspend_config;
890
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800891 /* configure current */
Nicholas Troaste1932e42017-04-12 12:38:18 -0700892 if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
Fenglin Wu80826e02017-04-25 21:45:08 +0800893 && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) {
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800894 rc = set_sdp_current(chg, icl_ua);
895 if (rc < 0) {
896 smblib_err(chg, "Couldn't set SDP ICL rc=%d\n", rc);
897 goto enable_icl_changed_interrupt;
898 }
899 } else {
Abhijeet Dharmapurikar949d67e2017-05-25 15:10:56 -0700900 set_sdp_current(chg, 100000);
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -0700901 rc = smblib_set_charge_param(chg, &chg->param.usb_icl, icl_ua);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800902 if (rc < 0) {
903 smblib_err(chg, "Couldn't set HC ICL rc=%d\n", rc);
904 goto enable_icl_changed_interrupt;
905 }
906 }
907
908override_suspend_config:
909 /* determine if override needs to be enforced */
910 override = true;
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530911 if (icl_ua == INT_MAX) {
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800912 /* remove override if no voters - hw defaults is desired */
913 override = false;
Nicholas Troaste1932e42017-04-12 12:38:18 -0700914 } else if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
Fenglin Wu80826e02017-04-25 21:45:08 +0800915 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800916 /* For std cable with type = SDP never override */
917 override = false;
Fenglin Wu80826e02017-04-25 21:45:08 +0800918 else if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_CDP
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -0700919 && icl_ua == 1500000)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800920 /*
921 * For std cable with type = CDP override only if
922 * current is not 1500mA
923 */
924 override = false;
925 }
926
927 /* enforce override */
928 rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
929 USBIN_MODE_CHG_BIT, override ? USBIN_MODE_CHG_BIT : 0);
930
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800931 rc = smblib_icl_override(chg, override);
932 if (rc < 0) {
933 smblib_err(chg, "Couldn't set ICL override rc=%d\n", rc);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800934 goto enable_icl_changed_interrupt;
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800935 }
936
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800937 /* unsuspend after configuring current and override */
938 rc = smblib_set_usb_suspend(chg, false);
939 if (rc < 0) {
940 smblib_err(chg, "Couldn't resume input rc=%d\n", rc);
941 goto enable_icl_changed_interrupt;
942 }
943
944enable_icl_changed_interrupt:
945 enable_irq(chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq);
Nicholas Troast34db5032016-03-28 12:26:44 -0700946 return rc;
947}
948
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700949int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua)
950{
951 int rc = 0;
952 u8 load_cfg;
953 bool override;
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700954
Nicholas Troaste1932e42017-04-12 12:38:18 -0700955 if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700956 || chg->micro_usb_mode)
957 && (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)) {
958 rc = get_sdp_current(chg, icl_ua);
959 if (rc < 0) {
960 smblib_err(chg, "Couldn't get SDP ICL rc=%d\n", rc);
961 return rc;
962 }
963 } else {
964 rc = smblib_read(chg, USBIN_LOAD_CFG_REG, &load_cfg);
965 if (rc < 0) {
966 smblib_err(chg, "Couldn't get load cfg rc=%d\n", rc);
967 return rc;
968 }
969 override = load_cfg & ICL_OVERRIDE_AFTER_APSD_BIT;
970 if (!override)
971 return INT_MAX;
972
973 /* override is set */
974 rc = smblib_get_charge_param(chg, &chg->param.usb_icl, icl_ua);
975 if (rc < 0) {
976 smblib_err(chg, "Couldn't get HC ICL rc=%d\n", rc);
977 return rc;
978 }
979 }
980
981 return 0;
982}
983
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530984/*********************
985 * VOTABLE CALLBACKS *
986 *********************/
987
988static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data,
989 int suspend, const char *client)
990{
991 struct smb_charger *chg = data;
992
993 /* resume input if suspend is invalid */
994 if (suspend < 0)
995 suspend = 0;
996
997 return smblib_set_dc_suspend(chg, (bool)suspend);
998}
999
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001000static int smblib_dc_icl_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -07001001 int icl_ua, const char *client)
Nicholas Troast34db5032016-03-28 12:26:44 -07001002{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001003 struct smb_charger *chg = data;
Nicholas Troast34db5032016-03-28 12:26:44 -07001004 int rc = 0;
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001005 bool suspend;
1006
1007 if (icl_ua < 0) {
1008 smblib_dbg(chg, PR_MISC, "No Voter hence suspending\n");
1009 icl_ua = 0;
1010 }
1011
1012 suspend = (icl_ua < USBIN_25MA);
1013 if (suspend)
1014 goto suspend;
Nicholas Troast34db5032016-03-28 12:26:44 -07001015
1016 rc = smblib_set_charge_param(chg, &chg->param.dc_icl, icl_ua);
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001017 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001018 smblib_err(chg, "Couldn't set DC input current limit rc=%d\n",
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001019 rc);
1020 return rc;
1021 }
1022
1023suspend:
1024 rc = vote(chg->dc_suspend_votable, USER_VOTER, suspend, 0);
1025 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001026 smblib_err(chg, "Couldn't vote to %s DC rc=%d\n",
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001027 suspend ? "suspend" : "resume", rc);
1028 return rc;
1029 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001030 return rc;
1031}
1032
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07001033static int smblib_pd_disallowed_votable_indirect_callback(
1034 struct votable *votable, void *data, int disallowed, const char *client)
1035{
1036 struct smb_charger *chg = data;
1037 int rc;
1038
1039 rc = vote(chg->pd_allowed_votable, PD_DISALLOWED_INDIRECT_VOTER,
1040 !disallowed, 0);
1041
1042 return rc;
1043}
1044
Harry Yang223c6282016-06-14 15:48:36 -07001045static int smblib_awake_vote_callback(struct votable *votable, void *data,
1046 int awake, const char *client)
1047{
1048 struct smb_charger *chg = data;
1049
1050 if (awake)
1051 pm_stay_awake(chg->dev);
1052 else
1053 pm_relax(chg->dev);
1054
1055 return 0;
1056}
1057
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07001058static int smblib_chg_disable_vote_callback(struct votable *votable, void *data,
1059 int chg_disable, const char *client)
1060{
1061 struct smb_charger *chg = data;
1062 int rc;
1063
1064 rc = smblib_masked_write(chg, CHARGING_ENABLE_CMD_REG,
1065 CHARGING_ENABLE_CMD_BIT,
1066 chg_disable ? 0 : CHARGING_ENABLE_CMD_BIT);
1067 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001068 smblib_err(chg, "Couldn't %s charging rc=%d\n",
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07001069 chg_disable ? "disable" : "enable", rc);
1070 return rc;
1071 }
1072
1073 return 0;
1074}
Harry Yangaba1f5f2016-09-28 10:47:29 -07001075
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301076static int smblib_hvdcp_enable_vote_callback(struct votable *votable,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001077 void *data,
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301078 int hvdcp_enable, const char *client)
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001079{
1080 struct smb_charger *chg = data;
1081 int rc;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301082 u8 val = HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_EN_BIT;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07001083 u8 stat;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301084
1085 /* vote to enable/disable HW autonomous INOV */
1086 vote(chg->hvdcp_hw_inov_dis_votable, client, !hvdcp_enable, 0);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001087
1088 /*
1089 * Disable the autonomous bit and auth bit for disabling hvdcp.
1090 * This ensures only qc 2.0 detection runs but no vbus
1091 * negotiation happens.
1092 */
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301093 if (!hvdcp_enable)
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001094 val = HVDCP_EN_BIT;
1095
1096 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301097 HVDCP_EN_BIT | HVDCP_AUTH_ALG_EN_CFG_BIT,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001098 val);
1099 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001100 smblib_err(chg, "Couldn't %s hvdcp rc=%d\n",
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301101 hvdcp_enable ? "enable" : "disable", rc);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001102 return rc;
1103 }
1104
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07001105 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
1106 if (rc < 0) {
1107 smblib_err(chg, "Couldn't read APSD status rc=%d\n", rc);
1108 return rc;
1109 }
1110
1111 /* re-run APSD if HVDCP was detected */
1112 if (stat & QC_CHARGER_BIT)
1113 smblib_rerun_apsd(chg);
1114
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001115 return 0;
1116}
1117
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301118static int smblib_hvdcp_disable_indirect_vote_callback(struct votable *votable,
1119 void *data, int hvdcp_disable, const char *client)
1120{
1121 struct smb_charger *chg = data;
1122
1123 vote(chg->hvdcp_enable_votable, HVDCP_INDIRECT_VOTER,
1124 !hvdcp_disable, 0);
1125
1126 return 0;
1127}
1128
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07001129static int smblib_apsd_disable_vote_callback(struct votable *votable,
1130 void *data,
1131 int apsd_disable, const char *client)
1132{
1133 struct smb_charger *chg = data;
1134 int rc;
1135
Nicholas Troastec4703c2017-01-30 14:52:33 -08001136 if (apsd_disable) {
Nicholas Troastec4703c2017-01-30 14:52:33 -08001137 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1138 AUTO_SRC_DETECT_BIT,
1139 0);
1140 if (rc < 0) {
1141 smblib_err(chg, "Couldn't disable APSD rc=%d\n", rc);
1142 return rc;
1143 }
1144 } else {
1145 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1146 AUTO_SRC_DETECT_BIT,
1147 AUTO_SRC_DETECT_BIT);
1148 if (rc < 0) {
1149 smblib_err(chg, "Couldn't enable APSD rc=%d\n", rc);
1150 return rc;
1151 }
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07001152 }
1153
1154 return 0;
1155}
Nicholas Troast8995a702016-12-05 10:22:22 -08001156
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301157static int smblib_hvdcp_hw_inov_dis_vote_callback(struct votable *votable,
1158 void *data, int disable, const char *client)
1159{
1160 struct smb_charger *chg = data;
1161 int rc;
1162
1163 if (disable) {
1164 /*
1165 * the pulse count register get zeroed when autonomous mode is
1166 * disabled. Track that in variables before disabling
1167 */
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +05301168 rc = smblib_get_hw_pulse_cnt(chg, &chg->pulse_cnt);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301169 if (rc < 0) {
1170 pr_err("failed to read QC_PULSE_COUNT_STATUS_REG rc=%d\n",
1171 rc);
1172 return rc;
1173 }
1174 }
1175
1176 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1177 HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT,
1178 disable ? 0 : HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT);
1179 if (rc < 0) {
1180 smblib_err(chg, "Couldn't %s hvdcp rc=%d\n",
1181 disable ? "disable" : "enable", rc);
1182 return rc;
1183 }
1184
1185 return rc;
1186}
1187
Harry Yang4bf7d962017-03-13 16:51:43 -07001188static int smblib_usb_irq_enable_vote_callback(struct votable *votable,
1189 void *data, int enable, const char *client)
1190{
1191 struct smb_charger *chg = data;
1192
1193 if (!chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq ||
1194 !chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq)
1195 return 0;
1196
1197 if (enable) {
1198 enable_irq(chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq);
1199 enable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
1200 } else {
1201 disable_irq(chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq);
1202 disable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
1203 }
1204
1205 return 0;
1206}
1207
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07001208static int smblib_typec_irq_disable_vote_callback(struct votable *votable,
1209 void *data, int disable, const char *client)
1210{
1211 struct smb_charger *chg = data;
1212
1213 if (!chg->irq_info[TYPE_C_CHANGE_IRQ].irq)
1214 return 0;
1215
1216 if (disable)
1217 disable_irq_nosync(chg->irq_info[TYPE_C_CHANGE_IRQ].irq);
1218 else
1219 enable_irq(chg->irq_info[TYPE_C_CHANGE_IRQ].irq);
1220
1221 return 0;
1222}
1223
Nicholas Troast8995a702016-12-05 10:22:22 -08001224/*******************
1225 * VCONN REGULATOR *
1226 * *****************/
1227
Nicholas Troastb11015f2017-01-17 17:56:45 -08001228#define MAX_OTG_SS_TRIES 2
Nicholas Troast8995a702016-12-05 10:22:22 -08001229static int _smblib_vconn_regulator_enable(struct regulator_dev *rdev)
1230{
1231 struct smb_charger *chg = rdev_get_drvdata(rdev);
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001232 int rc = 0;
1233 u8 val;
Nicholas Troast8995a702016-12-05 10:22:22 -08001234
1235 /*
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001236 * When enabling VCONN using the command register the CC pin must be
1237 * selected. VCONN should be supplied to the inactive CC pin hence using
1238 * the opposite of the CC_ORIENTATION_BIT.
Nicholas Troast8995a702016-12-05 10:22:22 -08001239 */
Nicholas Troastb11015f2017-01-17 17:56:45 -08001240 smblib_dbg(chg, PR_OTG, "enabling VCONN\n");
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07001241 val = chg->typec_status[3] &
1242 CC_ORIENTATION_BIT ? 0 : VCONN_EN_ORIENTATION_BIT;
Nicholas Troast8995a702016-12-05 10:22:22 -08001243 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1244 VCONN_EN_VALUE_BIT | VCONN_EN_ORIENTATION_BIT,
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07001245 VCONN_EN_VALUE_BIT | val);
Nicholas Troast8995a702016-12-05 10:22:22 -08001246 if (rc < 0) {
1247 smblib_err(chg, "Couldn't enable vconn setting rc=%d\n", rc);
1248 return rc;
1249 }
1250
1251 return rc;
1252}
1253
1254int smblib_vconn_regulator_enable(struct regulator_dev *rdev)
1255{
1256 struct smb_charger *chg = rdev_get_drvdata(rdev);
1257 int rc = 0;
1258
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001259 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001260 if (chg->vconn_en)
1261 goto unlock;
1262
1263 rc = _smblib_vconn_regulator_enable(rdev);
1264 if (rc >= 0)
1265 chg->vconn_en = true;
1266
1267unlock:
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001268 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001269 return rc;
1270}
1271
1272static int _smblib_vconn_regulator_disable(struct regulator_dev *rdev)
1273{
1274 struct smb_charger *chg = rdev_get_drvdata(rdev);
1275 int rc = 0;
1276
Nicholas Troastb11015f2017-01-17 17:56:45 -08001277 smblib_dbg(chg, PR_OTG, "disabling VCONN\n");
Nicholas Troast8995a702016-12-05 10:22:22 -08001278 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1279 VCONN_EN_VALUE_BIT, 0);
1280 if (rc < 0)
1281 smblib_err(chg, "Couldn't disable vconn regulator rc=%d\n", rc);
1282
1283 return rc;
1284}
1285
1286int smblib_vconn_regulator_disable(struct regulator_dev *rdev)
1287{
1288 struct smb_charger *chg = rdev_get_drvdata(rdev);
1289 int rc = 0;
1290
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001291 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001292 if (!chg->vconn_en)
1293 goto unlock;
1294
1295 rc = _smblib_vconn_regulator_disable(rdev);
1296 if (rc >= 0)
1297 chg->vconn_en = false;
1298
1299unlock:
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001300 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001301 return rc;
1302}
1303
1304int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev)
1305{
1306 struct smb_charger *chg = rdev_get_drvdata(rdev);
1307 int ret;
1308
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001309 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001310 ret = chg->vconn_en;
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001311 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001312 return ret;
1313}
1314
Nicholas Troast34db5032016-03-28 12:26:44 -07001315/*****************
1316 * OTG REGULATOR *
1317 *****************/
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301318#define MAX_RETRY 15
1319#define MIN_DELAY_US 2000
1320#define MAX_DELAY_US 9000
Nicholas Troast8995a702016-12-05 10:22:22 -08001321static int _smblib_vbus_regulator_enable(struct regulator_dev *rdev)
Nicholas Troast34db5032016-03-28 12:26:44 -07001322{
1323 struct smb_charger *chg = rdev_get_drvdata(rdev);
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301324 int rc, retry_count = 0, min_delay = MIN_DELAY_US;
1325 u8 stat;
Nicholas Troast34db5032016-03-28 12:26:44 -07001326
Nicholas Troastb11015f2017-01-17 17:56:45 -08001327 smblib_dbg(chg, PR_OTG, "halt 1 in 8 mode\n");
Harry Yang360bd532016-09-26 11:03:22 -07001328 rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
1329 ENG_BUCKBOOST_HALT1_8_MODE_BIT,
1330 ENG_BUCKBOOST_HALT1_8_MODE_BIT);
1331 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001332 smblib_err(chg, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n",
Harry Yang360bd532016-09-26 11:03:22 -07001333 rc);
1334 return rc;
1335 }
1336
Nicholas Troastb11015f2017-01-17 17:56:45 -08001337 smblib_dbg(chg, PR_OTG, "enabling OTG\n");
Harry Yang360bd532016-09-26 11:03:22 -07001338 rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT);
1339 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001340 smblib_err(chg, "Couldn't enable OTG regulator rc=%d\n", rc);
Harry Yang360bd532016-09-26 11:03:22 -07001341 return rc;
1342 }
1343
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301344 if (chg->wa_flags & OTG_WA) {
1345 /* check for softstart */
1346 do {
1347 usleep_range(min_delay, min_delay + 100);
1348 rc = smblib_read(chg, OTG_STATUS_REG, &stat);
1349 if (rc < 0) {
1350 smblib_err(chg,
1351 "Couldn't read OTG status rc=%d\n",
1352 rc);
1353 goto out;
1354 }
1355
1356 if (stat & BOOST_SOFTSTART_DONE_BIT) {
1357 rc = smblib_set_charge_param(chg,
1358 &chg->param.otg_cl, chg->otg_cl_ua);
1359 if (rc < 0)
1360 smblib_err(chg,
1361 "Couldn't set otg limit\n");
1362 break;
1363 }
1364
1365 /* increase the delay for following iterations */
1366 if (retry_count > 5)
1367 min_delay = MAX_DELAY_US;
1368 } while (retry_count++ < MAX_RETRY);
1369
1370 if (retry_count >= MAX_RETRY) {
1371 smblib_dbg(chg, PR_OTG, "Boost Softstart not done\n");
1372 goto out;
1373 }
1374 }
1375
1376 return 0;
1377out:
1378 /* disable OTG if softstart failed */
1379 smblib_write(chg, CMD_OTG_REG, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07001380 return rc;
1381}
1382
Nicholas Troast8995a702016-12-05 10:22:22 -08001383int smblib_vbus_regulator_enable(struct regulator_dev *rdev)
Nicholas Troast34db5032016-03-28 12:26:44 -07001384{
1385 struct smb_charger *chg = rdev_get_drvdata(rdev);
1386 int rc = 0;
1387
Nicholas Troastb11015f2017-01-17 17:56:45 -08001388 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001389 if (chg->otg_en)
1390 goto unlock;
1391
Harry Yanga2fb0e32017-03-22 22:45:25 -07001392 if (!chg->usb_icl_votable) {
1393 chg->usb_icl_votable = find_votable("USB_ICL");
1394
1395 if (!chg->usb_icl_votable)
1396 return -EINVAL;
1397 }
1398 vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, true, 0);
1399
Nicholas Troast8995a702016-12-05 10:22:22 -08001400 rc = _smblib_vbus_regulator_enable(rdev);
1401 if (rc >= 0)
1402 chg->otg_en = true;
1403
1404unlock:
Nicholas Troastb11015f2017-01-17 17:56:45 -08001405 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001406 return rc;
1407}
1408
1409static int _smblib_vbus_regulator_disable(struct regulator_dev *rdev)
1410{
1411 struct smb_charger *chg = rdev_get_drvdata(rdev);
1412 int rc;
Nicholas Troast8995a702016-12-05 10:22:22 -08001413
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301414 if (chg->wa_flags & OTG_WA) {
1415 /* set OTG current limit to minimum value */
1416 rc = smblib_set_charge_param(chg, &chg->param.otg_cl,
1417 chg->param.otg_cl.min_u);
1418 if (rc < 0) {
1419 smblib_err(chg,
1420 "Couldn't set otg current limit rc=%d\n", rc);
1421 return rc;
1422 }
1423 }
1424
Nicholas Troastb11015f2017-01-17 17:56:45 -08001425 smblib_dbg(chg, PR_OTG, "disabling OTG\n");
Harry Yang360bd532016-09-26 11:03:22 -07001426 rc = smblib_write(chg, CMD_OTG_REG, 0);
1427 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001428 smblib_err(chg, "Couldn't disable OTG regulator rc=%d\n", rc);
Harry Yang360bd532016-09-26 11:03:22 -07001429 return rc;
1430 }
1431
Nicholas Troastb11015f2017-01-17 17:56:45 -08001432 smblib_dbg(chg, PR_OTG, "start 1 in 8 mode\n");
Harry Yang360bd532016-09-26 11:03:22 -07001433 rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
1434 ENG_BUCKBOOST_HALT1_8_MODE_BIT, 0);
1435 if (rc < 0) {
Nicholas Troast8995a702016-12-05 10:22:22 -08001436 smblib_err(chg, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n", rc);
Harry Yang360bd532016-09-26 11:03:22 -07001437 return rc;
1438 }
1439
Nicholas Troast8995a702016-12-05 10:22:22 -08001440 return 0;
1441}
Nicholas Troast34db5032016-03-28 12:26:44 -07001442
Nicholas Troast8995a702016-12-05 10:22:22 -08001443int smblib_vbus_regulator_disable(struct regulator_dev *rdev)
1444{
1445 struct smb_charger *chg = rdev_get_drvdata(rdev);
1446 int rc = 0;
1447
Nicholas Troastb11015f2017-01-17 17:56:45 -08001448 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001449 if (!chg->otg_en)
1450 goto unlock;
1451
1452 rc = _smblib_vbus_regulator_disable(rdev);
1453 if (rc >= 0)
1454 chg->otg_en = false;
1455
Harry Yanga2fb0e32017-03-22 22:45:25 -07001456 if (chg->usb_icl_votable)
1457 vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0);
Nicholas Troast8995a702016-12-05 10:22:22 -08001458unlock:
Nicholas Troastb11015f2017-01-17 17:56:45 -08001459 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07001460 return rc;
1461}
1462
1463int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev)
1464{
1465 struct smb_charger *chg = rdev_get_drvdata(rdev);
Nicholas Troast8995a702016-12-05 10:22:22 -08001466 int ret;
Nicholas Troast34db5032016-03-28 12:26:44 -07001467
Nicholas Troastb11015f2017-01-17 17:56:45 -08001468 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001469 ret = chg->otg_en;
Nicholas Troastb11015f2017-01-17 17:56:45 -08001470 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001471 return ret;
Nicholas Troast34db5032016-03-28 12:26:44 -07001472}
1473
1474/********************
1475 * BATT PSY GETTERS *
1476 ********************/
1477
1478int smblib_get_prop_input_suspend(struct smb_charger *chg,
1479 union power_supply_propval *val)
1480{
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08001481 val->intval
1482 = (get_client_vote(chg->usb_icl_votable, USER_VOTER) == 0)
1483 && get_client_vote(chg->dc_suspend_votable, USER_VOTER);
Nicholas Troast34db5032016-03-28 12:26:44 -07001484 return 0;
1485}
1486
1487int smblib_get_prop_batt_present(struct smb_charger *chg,
1488 union power_supply_propval *val)
1489{
1490 int rc;
1491 u8 stat;
1492
1493 rc = smblib_read(chg, BATIF_BASE + INT_RT_STS_OFFSET, &stat);
1494 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001495 smblib_err(chg, "Couldn't read BATIF_INT_RT_STS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07001496 return rc;
1497 }
1498
1499 val->intval = !(stat & (BAT_THERM_OR_ID_MISSING_RT_STS_BIT
1500 | BAT_TERMINAL_MISSING_RT_STS_BIT));
1501
1502 return rc;
1503}
1504
1505int smblib_get_prop_batt_capacity(struct smb_charger *chg,
1506 union power_supply_propval *val)
1507{
Harry Yang5e1a5222016-07-26 15:16:04 -07001508 int rc = -EINVAL;
1509
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07001510 if (chg->fake_capacity >= 0) {
1511 val->intval = chg->fake_capacity;
1512 return 0;
1513 }
1514
Harry Yang5e1a5222016-07-26 15:16:04 -07001515 if (chg->bms_psy)
1516 rc = power_supply_get_property(chg->bms_psy,
1517 POWER_SUPPLY_PROP_CAPACITY, val);
1518 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001519}
1520
1521int smblib_get_prop_batt_status(struct smb_charger *chg,
1522 union power_supply_propval *val)
1523{
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001524 union power_supply_propval pval = {0, };
1525 bool usb_online, dc_online;
Nicholas Troast8cb77552016-09-23 11:50:18 -07001526 u8 stat;
1527 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001528
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001529 rc = smblib_get_prop_usb_online(chg, &pval);
1530 if (rc < 0) {
1531 smblib_err(chg, "Couldn't get usb online property rc=%d\n",
1532 rc);
1533 return rc;
1534 }
1535 usb_online = (bool)pval.intval;
1536
1537 rc = smblib_get_prop_dc_online(chg, &pval);
1538 if (rc < 0) {
1539 smblib_err(chg, "Couldn't get dc online property rc=%d\n",
1540 rc);
1541 return rc;
1542 }
1543 dc_online = (bool)pval.intval;
1544
Nicholas Troast34db5032016-03-28 12:26:44 -07001545 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1546 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001547 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001548 rc);
1549 return rc;
1550 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001551 stat = stat & BATTERY_CHARGER_STATUS_MASK;
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001552
1553 if (!usb_online && !dc_online) {
1554 switch (stat) {
1555 case TERMINATE_CHARGE:
1556 case INHIBIT_CHARGE:
1557 val->intval = POWER_SUPPLY_STATUS_FULL;
1558 break;
1559 default:
1560 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
1561 break;
1562 }
1563 return rc;
1564 }
1565
Nicholas Troast8cb77552016-09-23 11:50:18 -07001566 switch (stat) {
1567 case TRICKLE_CHARGE:
1568 case PRE_CHARGE:
1569 case FAST_CHARGE:
1570 case FULLON_CHARGE:
1571 case TAPER_CHARGE:
Nicholas Troast34db5032016-03-28 12:26:44 -07001572 val->intval = POWER_SUPPLY_STATUS_CHARGING;
Nicholas Troast8cb77552016-09-23 11:50:18 -07001573 break;
1574 case TERMINATE_CHARGE:
1575 case INHIBIT_CHARGE:
1576 val->intval = POWER_SUPPLY_STATUS_FULL;
1577 break;
1578 case DISABLE_CHARGE:
1579 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
1580 break;
1581 default:
1582 val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
1583 break;
1584 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001585
Harry Yang7ecc1a12017-04-06 12:24:56 -07001586 if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
1587 return 0;
1588
Harry Yangc3c28d12017-04-17 16:41:19 -07001589 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_7_REG, &stat);
Harry Yang7ecc1a12017-04-06 12:24:56 -07001590 if (rc < 0) {
1591 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
1592 rc);
1593 return rc;
1594 }
1595
Harry Yangc3c28d12017-04-17 16:41:19 -07001596 stat &= ENABLE_TRICKLE_BIT | ENABLE_PRE_CHARGING_BIT |
1597 ENABLE_FAST_CHARGING_BIT | ENABLE_FULLON_MODE_BIT;
1598 if (!stat)
Harry Yang7ecc1a12017-04-06 12:24:56 -07001599 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
1600
Nicholas Troast8cb77552016-09-23 11:50:18 -07001601 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07001602}
1603
1604int smblib_get_prop_batt_charge_type(struct smb_charger *chg,
1605 union power_supply_propval *val)
1606{
1607 int rc;
1608 u8 stat;
1609
1610 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1611 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001612 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001613 rc);
1614 return rc;
1615 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001616
1617 switch (stat & BATTERY_CHARGER_STATUS_MASK) {
1618 case TRICKLE_CHARGE:
1619 case PRE_CHARGE:
1620 val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1621 break;
1622 case FAST_CHARGE:
1623 case FULLON_CHARGE:
1624 val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
1625 break;
1626 case TAPER_CHARGE:
1627 val->intval = POWER_SUPPLY_CHARGE_TYPE_TAPER;
1628 break;
1629 default:
1630 val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
1631 }
1632
1633 return rc;
1634}
1635
1636int smblib_get_prop_batt_health(struct smb_charger *chg,
1637 union power_supply_propval *val)
1638{
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001639 union power_supply_propval pval;
Nicholas Troast34db5032016-03-28 12:26:44 -07001640 int rc;
Abhijeet Dharmapurikar33d18462017-05-15 13:38:53 -07001641 int effective_fv_uv;
Nicholas Troast34db5032016-03-28 12:26:44 -07001642 u8 stat;
1643
1644 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat);
1645 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001646 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001647 rc);
1648 return rc;
1649 }
1650 smblib_dbg(chg, PR_REGISTER, "BATTERY_CHARGER_STATUS_2 = 0x%02x\n",
1651 stat);
1652
1653 if (stat & CHARGER_ERROR_STATUS_BAT_OV_BIT) {
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001654 rc = smblib_get_prop_batt_voltage_now(chg, &pval);
1655 if (!rc) {
1656 /*
1657 * If Vbatt is within 40mV above Vfloat, then don't
1658 * treat it as overvoltage.
1659 */
Abhijeet Dharmapurikar33d18462017-05-15 13:38:53 -07001660 effective_fv_uv = get_effective_result(chg->fv_votable);
1661 if (pval.intval >= effective_fv_uv + 40000) {
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001662 val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
Abhijeet Dharmapurikar33d18462017-05-15 13:38:53 -07001663 smblib_err(chg, "battery over-voltage vbat_fg = %duV, fv = %duV\n",
1664 pval.intval, effective_fv_uv);
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001665 goto done;
1666 }
1667 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001668 }
1669
Harry Yang668fc5e2016-07-12 16:51:47 -07001670 if (stat & BAT_TEMP_STATUS_TOO_COLD_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001671 val->intval = POWER_SUPPLY_HEALTH_COLD;
Harry Yang668fc5e2016-07-12 16:51:47 -07001672 else if (stat & BAT_TEMP_STATUS_TOO_HOT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001673 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
Harry Yang668fc5e2016-07-12 16:51:47 -07001674 else if (stat & BAT_TEMP_STATUS_COLD_SOFT_LIMIT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001675 val->intval = POWER_SUPPLY_HEALTH_COOL;
Harry Yang668fc5e2016-07-12 16:51:47 -07001676 else if (stat & BAT_TEMP_STATUS_HOT_SOFT_LIMIT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001677 val->intval = POWER_SUPPLY_HEALTH_WARM;
Harry Yang668fc5e2016-07-12 16:51:47 -07001678 else
Nicholas Troast34db5032016-03-28 12:26:44 -07001679 val->intval = POWER_SUPPLY_HEALTH_GOOD;
Nicholas Troast34db5032016-03-28 12:26:44 -07001680
1681done:
1682 return rc;
1683}
1684
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001685int smblib_get_prop_system_temp_level(struct smb_charger *chg,
1686 union power_supply_propval *val)
1687{
1688 val->intval = chg->system_temp_level;
1689 return 0;
1690}
1691
Abhijeet Dharmapurikaracf32002017-05-11 11:54:17 -07001692int smblib_get_prop_system_temp_level_max(struct smb_charger *chg,
1693 union power_supply_propval *val)
1694{
1695 val->intval = chg->thermal_levels;
1696 return 0;
1697}
1698
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001699int smblib_get_prop_input_current_limited(struct smb_charger *chg,
1700 union power_supply_propval *val)
1701{
1702 u8 stat;
1703 int rc;
1704
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07001705 if (chg->fake_input_current_limited >= 0) {
1706 val->intval = chg->fake_input_current_limited;
1707 return 0;
1708 }
1709
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001710 rc = smblib_read(chg, AICL_STATUS_REG, &stat);
1711 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001712 smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n", rc);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001713 return rc;
1714 }
1715 val->intval = (stat & SOFT_ILIMIT_BIT) || chg->is_hdc;
1716 return 0;
1717}
1718
Nicholas Troast66b21d72016-09-20 15:33:20 -07001719int smblib_get_prop_batt_voltage_now(struct smb_charger *chg,
1720 union power_supply_propval *val)
1721{
1722 int rc;
1723
1724 if (!chg->bms_psy)
1725 return -EINVAL;
1726
1727 rc = power_supply_get_property(chg->bms_psy,
1728 POWER_SUPPLY_PROP_VOLTAGE_NOW, val);
1729 return rc;
1730}
1731
1732int smblib_get_prop_batt_current_now(struct smb_charger *chg,
1733 union power_supply_propval *val)
1734{
1735 int rc;
1736
1737 if (!chg->bms_psy)
1738 return -EINVAL;
1739
1740 rc = power_supply_get_property(chg->bms_psy,
1741 POWER_SUPPLY_PROP_CURRENT_NOW, val);
1742 return rc;
1743}
1744
1745int smblib_get_prop_batt_temp(struct smb_charger *chg,
1746 union power_supply_propval *val)
1747{
1748 int rc;
1749
1750 if (!chg->bms_psy)
1751 return -EINVAL;
1752
1753 rc = power_supply_get_property(chg->bms_psy,
1754 POWER_SUPPLY_PROP_TEMP, val);
1755 return rc;
1756}
1757
Harry Yangbedee332016-08-31 16:14:29 -07001758int smblib_get_prop_step_chg_step(struct smb_charger *chg,
1759 union power_supply_propval *val)
1760{
1761 int rc;
1762 u8 stat;
1763
1764 if (!chg->step_chg_enabled) {
1765 val->intval = -1;
1766 return 0;
1767 }
1768
1769 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1770 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001771 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Harry Yangbedee332016-08-31 16:14:29 -07001772 rc);
1773 return rc;
1774 }
1775
1776 val->intval = (stat & STEP_CHARGING_STATUS_MASK) >>
1777 STEP_CHARGING_STATUS_SHIFT;
1778
1779 return rc;
1780}
1781
Subbaraman Narayanamurthyb491d022016-10-10 20:22:48 -07001782int smblib_get_prop_batt_charge_done(struct smb_charger *chg,
1783 union power_supply_propval *val)
1784{
1785 int rc;
1786 u8 stat;
1787
1788 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1789 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001790 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Subbaraman Narayanamurthyb491d022016-10-10 20:22:48 -07001791 rc);
1792 return rc;
1793 }
1794
1795 stat = stat & BATTERY_CHARGER_STATUS_MASK;
1796 val->intval = (stat == TERMINATE_CHARGE);
1797 return 0;
1798}
1799
Harry Yang40192cb2017-02-25 23:25:17 -08001800int smblib_get_prop_charge_qnovo_enable(struct smb_charger *chg,
1801 union power_supply_propval *val)
1802{
1803 int rc;
1804 u8 stat;
1805
1806 rc = smblib_read(chg, QNOVO_PT_ENABLE_CMD_REG, &stat);
1807 if (rc < 0) {
1808 smblib_err(chg, "Couldn't read QNOVO_PT_ENABLE_CMD rc=%d\n",
1809 rc);
1810 return rc;
1811 }
1812
1813 val->intval = (bool)(stat & QNOVO_PT_ENABLE_CMD_BIT);
1814 return 0;
1815}
1816
Nicholas Troast34db5032016-03-28 12:26:44 -07001817/***********************
1818 * BATTERY PSY SETTERS *
1819 ***********************/
1820
1821int smblib_set_prop_input_suspend(struct smb_charger *chg,
1822 const union power_supply_propval *val)
1823{
1824 int rc;
1825
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08001826 /* vote 0mA when suspended */
1827 rc = vote(chg->usb_icl_votable, USER_VOTER, (bool)val->intval, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07001828 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001829 smblib_err(chg, "Couldn't vote to %s USB rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001830 (bool)val->intval ? "suspend" : "resume", rc);
1831 return rc;
1832 }
1833
1834 rc = vote(chg->dc_suspend_votable, USER_VOTER, (bool)val->intval, 0);
1835 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001836 smblib_err(chg, "Couldn't vote to %s DC rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001837 (bool)val->intval ? "suspend" : "resume", rc);
1838 return rc;
1839 }
1840
Nicholas Troast61ff40f2016-07-08 10:59:22 -07001841 power_supply_changed(chg->batt_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07001842 return rc;
1843}
1844
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07001845int smblib_set_prop_batt_capacity(struct smb_charger *chg,
1846 const union power_supply_propval *val)
1847{
1848 chg->fake_capacity = val->intval;
1849
1850 power_supply_changed(chg->batt_psy);
1851
1852 return 0;
1853}
1854
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001855int smblib_set_prop_system_temp_level(struct smb_charger *chg,
1856 const union power_supply_propval *val)
1857{
1858 if (val->intval < 0)
1859 return -EINVAL;
1860
1861 if (chg->thermal_levels <= 0)
1862 return -EINVAL;
1863
1864 if (val->intval > chg->thermal_levels)
1865 return -EINVAL;
1866
1867 chg->system_temp_level = val->intval;
Ashay Jaiswal147a6c32017-03-28 17:19:47 +05301868 /* disable parallel charge in case of system temp level */
1869 vote(chg->pl_disable_votable, THERMAL_DAEMON_VOTER,
1870 chg->system_temp_level ? true : false, 0);
1871
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001872 if (chg->system_temp_level == chg->thermal_levels)
Harry Yangaba1f5f2016-09-28 10:47:29 -07001873 return vote(chg->chg_disable_votable,
1874 THERMAL_DAEMON_VOTER, true, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001875
Harry Yangaba1f5f2016-09-28 10:47:29 -07001876 vote(chg->chg_disable_votable, THERMAL_DAEMON_VOTER, false, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001877 if (chg->system_temp_level == 0)
Harry Yangaba1f5f2016-09-28 10:47:29 -07001878 return vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, false, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001879
Harry Yangaba1f5f2016-09-28 10:47:29 -07001880 vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, true,
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001881 chg->thermal_mitigation[chg->system_temp_level]);
1882 return 0;
1883}
1884
Harry Yang40192cb2017-02-25 23:25:17 -08001885int smblib_set_prop_charge_qnovo_enable(struct smb_charger *chg,
1886 const union power_supply_propval *val)
1887{
1888 int rc = 0;
1889
1890 rc = smblib_masked_write(chg, QNOVO_PT_ENABLE_CMD_REG,
1891 QNOVO_PT_ENABLE_CMD_BIT,
1892 val->intval ? QNOVO_PT_ENABLE_CMD_BIT : 0);
1893 if (rc < 0) {
1894 dev_err(chg->dev, "Couldn't enable qnovo rc=%d\n", rc);
1895 return rc;
1896 }
1897
1898 return rc;
1899}
1900
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07001901int smblib_set_prop_input_current_limited(struct smb_charger *chg,
1902 const union power_supply_propval *val)
1903{
1904 chg->fake_input_current_limited = val->intval;
1905 return 0;
1906}
1907
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301908int smblib_rerun_aicl(struct smb_charger *chg)
1909{
Nicholas Troast20ae1912017-02-15 10:15:32 -08001910 int rc, settled_icl_ua;
1911 u8 stat;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301912
Nicholas Troast20ae1912017-02-15 10:15:32 -08001913 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
1914 if (rc < 0) {
1915 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
1916 rc);
1917 return rc;
1918 }
1919
1920 /* USB is suspended so skip re-running AICL */
1921 if (stat & USBIN_SUSPEND_STS_BIT)
1922 return rc;
1923
1924 smblib_dbg(chg, PR_MISC, "re-running AICL\n");
Ashay Jaiswal59a14122017-05-16 13:38:52 +05301925 rc = smblib_get_charge_param(chg, &chg->param.icl_stat,
1926 &settled_icl_ua);
1927 if (rc < 0) {
1928 smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
1929 return rc;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301930 }
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301931
Ashay Jaiswal59a14122017-05-16 13:38:52 +05301932 vote(chg->usb_icl_votable, AICL_RERUN_VOTER, true,
1933 max(settled_icl_ua - chg->param.usb_icl.step_u,
1934 chg->param.usb_icl.step_u));
1935 vote(chg->usb_icl_votable, AICL_RERUN_VOTER, false, 0);
1936
Nicholas Troast20ae1912017-02-15 10:15:32 -08001937 return 0;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301938}
1939
1940static int smblib_dp_pulse(struct smb_charger *chg)
1941{
1942 int rc;
1943
1944 /* QC 3.0 increment */
1945 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, SINGLE_INCREMENT_BIT,
1946 SINGLE_INCREMENT_BIT);
1947 if (rc < 0)
1948 smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
1949 rc);
1950
1951 return rc;
1952}
1953
1954static int smblib_dm_pulse(struct smb_charger *chg)
1955{
1956 int rc;
1957
1958 /* QC 3.0 decrement */
1959 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, SINGLE_DECREMENT_BIT,
1960 SINGLE_DECREMENT_BIT);
1961 if (rc < 0)
1962 smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
1963 rc);
1964
1965 return rc;
1966}
1967
1968int smblib_dp_dm(struct smb_charger *chg, int val)
1969{
1970 int target_icl_ua, rc = 0;
Ashay Jaiswalae23a042017-05-18 15:28:31 +05301971 union power_supply_propval pval;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301972
1973 switch (val) {
1974 case POWER_SUPPLY_DP_DM_DP_PULSE:
1975 rc = smblib_dp_pulse(chg);
1976 if (!rc)
1977 chg->pulse_cnt++;
1978 smblib_dbg(chg, PR_PARALLEL, "DP_DM_DP_PULSE rc=%d cnt=%d\n",
1979 rc, chg->pulse_cnt);
1980 break;
1981 case POWER_SUPPLY_DP_DM_DM_PULSE:
1982 rc = smblib_dm_pulse(chg);
1983 if (!rc && chg->pulse_cnt)
1984 chg->pulse_cnt--;
1985 smblib_dbg(chg, PR_PARALLEL, "DP_DM_DM_PULSE rc=%d cnt=%d\n",
1986 rc, chg->pulse_cnt);
1987 break;
1988 case POWER_SUPPLY_DP_DM_ICL_DOWN:
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301989 target_icl_ua = get_effective_result(chg->usb_icl_votable);
Ashay Jaiswalae23a042017-05-18 15:28:31 +05301990 if (target_icl_ua < 0) {
1991 /* no client vote, get the ICL from charger */
1992 rc = power_supply_get_property(chg->usb_psy,
1993 POWER_SUPPLY_PROP_HW_CURRENT_MAX,
1994 &pval);
1995 if (rc < 0) {
1996 smblib_err(chg,
1997 "Couldn't get max current rc=%d\n",
1998 rc);
1999 return rc;
2000 }
2001 target_icl_ua = pval.intval;
2002 }
2003
2004 /*
2005 * Check if any other voter voted on USB_ICL in case of
2006 * voter other than SW_QC3_VOTER reset and restart reduction
2007 * again.
2008 */
2009 if (target_icl_ua != get_client_vote(chg->usb_icl_votable,
2010 SW_QC3_VOTER))
2011 chg->usb_icl_delta_ua = 0;
2012
2013 chg->usb_icl_delta_ua += 100000;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302014 vote(chg->usb_icl_votable, SW_QC3_VOTER, true,
Ashay Jaiswalae23a042017-05-18 15:28:31 +05302015 target_icl_ua - 100000);
2016 smblib_dbg(chg, PR_PARALLEL, "ICL DOWN ICL=%d reduction=%d\n",
2017 target_icl_ua, chg->usb_icl_delta_ua);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05302018 break;
2019 case POWER_SUPPLY_DP_DM_ICL_UP:
2020 default:
2021 break;
2022 }
2023
2024 return rc;
2025}
2026
Nicholas Troast34db5032016-03-28 12:26:44 -07002027/*******************
Harry Yangf3023592016-07-20 14:56:41 -07002028 * DC PSY GETTERS *
2029 *******************/
2030
2031int smblib_get_prop_dc_present(struct smb_charger *chg,
2032 union power_supply_propval *val)
2033{
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002034 int rc;
Harry Yangf3023592016-07-20 14:56:41 -07002035 u8 stat;
2036
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002037 rc = smblib_read(chg, DCIN_BASE + INT_RT_STS_OFFSET, &stat);
Harry Yangf3023592016-07-20 14:56:41 -07002038 if (rc < 0) {
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002039 smblib_err(chg, "Couldn't read DCIN_RT_STS rc=%d\n", rc);
Harry Yangf3023592016-07-20 14:56:41 -07002040 return rc;
2041 }
Harry Yangf3023592016-07-20 14:56:41 -07002042
2043 val->intval = (bool)(stat & DCIN_PLUGIN_RT_STS_BIT);
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002044 return 0;
Harry Yangf3023592016-07-20 14:56:41 -07002045}
2046
2047int smblib_get_prop_dc_online(struct smb_charger *chg,
2048 union power_supply_propval *val)
2049{
2050 int rc = 0;
2051 u8 stat;
2052
2053 if (get_client_vote(chg->dc_suspend_votable, USER_VOTER)) {
2054 val->intval = false;
2055 return rc;
2056 }
2057
2058 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
2059 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002060 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
Harry Yangf3023592016-07-20 14:56:41 -07002061 rc);
2062 return rc;
2063 }
2064 smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
2065 stat);
2066
2067 val->intval = (stat & USE_DCIN_BIT) &&
Vic Wei7ade2842016-12-14 18:47:49 -08002068 (stat & VALID_INPUT_POWER_SOURCE_STS_BIT);
Harry Yangf3023592016-07-20 14:56:41 -07002069
2070 return rc;
2071}
2072
2073int smblib_get_prop_dc_current_max(struct smb_charger *chg,
2074 union power_supply_propval *val)
2075{
2076 val->intval = get_effective_result_locked(chg->dc_icl_votable);
2077 return 0;
2078}
2079
2080/*******************
Harry Yangd89ff1f2016-12-05 14:59:11 -08002081 * DC PSY SETTERS *
Harry Yangf3023592016-07-20 14:56:41 -07002082 * *****************/
2083
2084int smblib_set_prop_dc_current_max(struct smb_charger *chg,
2085 const union power_supply_propval *val)
2086{
2087 int rc;
2088
2089 rc = vote(chg->dc_icl_votable, USER_VOTER, true, val->intval);
2090 return rc;
2091}
2092
2093/*******************
Nicholas Troast34db5032016-03-28 12:26:44 -07002094 * USB PSY GETTERS *
2095 *******************/
2096
2097int smblib_get_prop_usb_present(struct smb_charger *chg,
2098 union power_supply_propval *val)
2099{
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002100 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07002101 u8 stat;
2102
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002103 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
Nicholas Troast34db5032016-03-28 12:26:44 -07002104 if (rc < 0) {
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002105 smblib_err(chg, "Couldn't read USBIN_RT_STS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07002106 return rc;
2107 }
Nicholas Troast34db5032016-03-28 12:26:44 -07002108
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002109 val->intval = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
2110 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002111}
2112
2113int smblib_get_prop_usb_online(struct smb_charger *chg,
2114 union power_supply_propval *val)
2115{
2116 int rc = 0;
2117 u8 stat;
2118
Abhijeet Dharmapurikar84923af2017-03-23 14:07:07 -07002119 if (get_client_vote_locked(chg->usb_icl_votable, USER_VOTER) == 0) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002120 val->intval = false;
2121 return rc;
2122 }
2123
2124 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
2125 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002126 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002127 rc);
2128 return rc;
2129 }
2130 smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
2131 stat);
2132
2133 val->intval = (stat & USE_USBIN_BIT) &&
Vic Wei7ade2842016-12-14 18:47:49 -08002134 (stat & VALID_INPUT_POWER_SOURCE_STS_BIT);
Nicholas Troast34db5032016-03-28 12:26:44 -07002135 return rc;
2136}
2137
2138int smblib_get_prop_usb_voltage_now(struct smb_charger *chg,
2139 union power_supply_propval *val)
2140{
Harry Yangba874ce2016-08-19 14:17:01 -07002141 int rc = 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002142
Harry Yangba874ce2016-08-19 14:17:01 -07002143 rc = smblib_get_prop_usb_present(chg, val);
2144 if (rc < 0 || !val->intval)
2145 return rc;
2146
2147 if (!chg->iio.usbin_v_chan ||
2148 PTR_ERR(chg->iio.usbin_v_chan) == -EPROBE_DEFER)
2149 chg->iio.usbin_v_chan = iio_channel_get(chg->dev, "usbin_v");
2150
2151 if (IS_ERR(chg->iio.usbin_v_chan))
2152 return PTR_ERR(chg->iio.usbin_v_chan);
2153
2154 return iio_read_channel_processed(chg->iio.usbin_v_chan, &val->intval);
Nicholas Troast34db5032016-03-28 12:26:44 -07002155}
2156
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002157int smblib_get_prop_pd_current_max(struct smb_charger *chg,
2158 union power_supply_propval *val)
2159{
2160 val->intval = get_client_vote_locked(chg->usb_icl_votable, PD_VOTER);
2161 return 0;
2162}
2163
Nicholas Troast34db5032016-03-28 12:26:44 -07002164int smblib_get_prop_usb_current_max(struct smb_charger *chg,
2165 union power_supply_propval *val)
2166{
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002167 val->intval = get_client_vote_locked(chg->usb_icl_votable,
2168 USB_PSY_VOTER);
Nicholas Troast34db5032016-03-28 12:26:44 -07002169 return 0;
2170}
2171
Harry Yangba874ce2016-08-19 14:17:01 -07002172int smblib_get_prop_usb_current_now(struct smb_charger *chg,
2173 union power_supply_propval *val)
2174{
2175 int rc = 0;
2176
2177 rc = smblib_get_prop_usb_present(chg, val);
2178 if (rc < 0 || !val->intval)
2179 return rc;
2180
2181 if (!chg->iio.usbin_i_chan ||
2182 PTR_ERR(chg->iio.usbin_i_chan) == -EPROBE_DEFER)
2183 chg->iio.usbin_i_chan = iio_channel_get(chg->dev, "usbin_i");
2184
2185 if (IS_ERR(chg->iio.usbin_i_chan))
2186 return PTR_ERR(chg->iio.usbin_i_chan);
2187
2188 return iio_read_channel_processed(chg->iio.usbin_i_chan, &val->intval);
2189}
2190
2191int smblib_get_prop_charger_temp(struct smb_charger *chg,
2192 union power_supply_propval *val)
2193{
2194 int rc;
2195
2196 if (!chg->iio.temp_chan ||
2197 PTR_ERR(chg->iio.temp_chan) == -EPROBE_DEFER)
2198 chg->iio.temp_chan = iio_channel_get(chg->dev, "charger_temp");
2199
2200 if (IS_ERR(chg->iio.temp_chan))
2201 return PTR_ERR(chg->iio.temp_chan);
2202
2203 rc = iio_read_channel_processed(chg->iio.temp_chan, &val->intval);
2204 val->intval /= 100;
2205 return rc;
2206}
2207
2208int smblib_get_prop_charger_temp_max(struct smb_charger *chg,
2209 union power_supply_propval *val)
2210{
2211 int rc;
2212
2213 if (!chg->iio.temp_max_chan ||
2214 PTR_ERR(chg->iio.temp_max_chan) == -EPROBE_DEFER)
2215 chg->iio.temp_max_chan = iio_channel_get(chg->dev,
2216 "charger_temp_max");
2217 if (IS_ERR(chg->iio.temp_max_chan))
2218 return PTR_ERR(chg->iio.temp_max_chan);
2219
2220 rc = iio_read_channel_processed(chg->iio.temp_max_chan, &val->intval);
2221 val->intval /= 100;
2222 return rc;
2223}
2224
Nicholas Troast34db5032016-03-28 12:26:44 -07002225int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
2226 union power_supply_propval *val)
2227{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002228 if (chg->typec_status[3] & CC_ATTACHED_BIT)
2229 val->intval =
2230 (bool)(chg->typec_status[3] & CC_ORIENTATION_BIT) + 1;
Nicholas Troast34db5032016-03-28 12:26:44 -07002231 else
2232 val->intval = 0;
2233
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002234 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002235}
2236
2237static const char * const smblib_typec_mode_name[] = {
2238 [POWER_SUPPLY_TYPEC_NONE] = "NONE",
2239 [POWER_SUPPLY_TYPEC_SOURCE_DEFAULT] = "SOURCE_DEFAULT",
2240 [POWER_SUPPLY_TYPEC_SOURCE_MEDIUM] = "SOURCE_MEDIUM",
2241 [POWER_SUPPLY_TYPEC_SOURCE_HIGH] = "SOURCE_HIGH",
2242 [POWER_SUPPLY_TYPEC_NON_COMPLIANT] = "NON_COMPLIANT",
2243 [POWER_SUPPLY_TYPEC_SINK] = "SINK",
2244 [POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE] = "SINK_POWERED_CABLE",
2245 [POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY] = "SINK_DEBUG_ACCESSORY",
2246 [POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER] = "SINK_AUDIO_ADAPTER",
2247 [POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY] = "POWERED_CABLE_ONLY",
2248};
2249
2250static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
2251{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002252 switch (chg->typec_status[0]) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002253 case UFP_TYPEC_RDSTD_BIT:
2254 return POWER_SUPPLY_TYPEC_SOURCE_DEFAULT;
2255 case UFP_TYPEC_RD1P5_BIT:
2256 return POWER_SUPPLY_TYPEC_SOURCE_MEDIUM;
2257 case UFP_TYPEC_RD3P0_BIT:
2258 return POWER_SUPPLY_TYPEC_SOURCE_HIGH;
2259 default:
2260 break;
2261 }
2262
Nicholas Troaste1932e42017-04-12 12:38:18 -07002263 return POWER_SUPPLY_TYPEC_NONE;
Nicholas Troast34db5032016-03-28 12:26:44 -07002264}
2265
2266static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
2267{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002268 switch (chg->typec_status[1] & DFP_TYPEC_MASK) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002269 case DFP_RA_RA_BIT:
2270 return POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER;
2271 case DFP_RD_RD_BIT:
2272 return POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY;
2273 case DFP_RD_RA_VCONN_BIT:
2274 return POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE;
2275 case DFP_RD_OPEN_BIT:
2276 return POWER_SUPPLY_TYPEC_SINK;
Nicholas Troast34db5032016-03-28 12:26:44 -07002277 default:
2278 break;
2279 }
2280
2281 return POWER_SUPPLY_TYPEC_NONE;
2282}
2283
Nicholas Troaste1932e42017-04-12 12:38:18 -07002284static int smblib_get_prop_typec_mode(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07002285{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002286 if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
Nicholas Troaste1932e42017-04-12 12:38:18 -07002287 return smblib_get_prop_dfp_mode(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07002288 else
Nicholas Troaste1932e42017-04-12 12:38:18 -07002289 return smblib_get_prop_ufp_mode(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07002290}
2291
2292int smblib_get_prop_typec_power_role(struct smb_charger *chg,
2293 union power_supply_propval *val)
2294{
2295 int rc = 0;
2296 u8 ctrl;
2297
2298 rc = smblib_read(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &ctrl);
2299 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002300 smblib_err(chg, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002301 rc);
2302 return rc;
2303 }
2304 smblib_dbg(chg, PR_REGISTER, "TYPE_C_INTRPT_ENB_SOFTWARE_CTRL = 0x%02x\n",
2305 ctrl);
2306
2307 if (ctrl & TYPEC_DISABLE_CMD_BIT) {
2308 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
2309 return rc;
2310 }
2311
2312 switch (ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT)) {
2313 case 0:
2314 val->intval = POWER_SUPPLY_TYPEC_PR_DUAL;
2315 break;
2316 case DFP_EN_CMD_BIT:
2317 val->intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
2318 break;
2319 case UFP_EN_CMD_BIT:
2320 val->intval = POWER_SUPPLY_TYPEC_PR_SINK;
2321 break;
2322 default:
2323 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002324 smblib_err(chg, "unsupported power role 0x%02lx\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002325 ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT));
2326 return -EINVAL;
2327 }
2328
2329 return rc;
2330}
2331
2332int smblib_get_prop_pd_allowed(struct smb_charger *chg,
2333 union power_supply_propval *val)
2334{
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07002335 val->intval = get_effective_result(chg->pd_allowed_votable);
Nicholas Troast34db5032016-03-28 12:26:44 -07002336 return 0;
2337}
2338
Nicholas Troast133a7f52016-06-29 13:48:20 -07002339int smblib_get_prop_input_current_settled(struct smb_charger *chg,
2340 union power_supply_propval *val)
2341{
2342 return smblib_get_charge_param(chg, &chg->param.icl_stat, &val->intval);
2343}
2344
Fenglin Wuef4730e2017-01-11 18:16:25 +08002345#define HVDCP3_STEP_UV 200000
2346int smblib_get_prop_input_voltage_settled(struct smb_charger *chg,
2347 union power_supply_propval *val)
2348{
2349 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
2350 int rc, pulses;
Fenglin Wuef4730e2017-01-11 18:16:25 +08002351
2352 val->intval = MICRO_5V;
2353 if (apsd_result == NULL) {
2354 smblib_err(chg, "APSD result is NULL\n");
2355 return 0;
2356 }
2357
2358 switch (apsd_result->pst) {
2359 case POWER_SUPPLY_TYPE_USB_HVDCP_3:
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +05302360 rc = smblib_get_pulse_cnt(chg, &pulses);
Fenglin Wuef4730e2017-01-11 18:16:25 +08002361 if (rc < 0) {
2362 smblib_err(chg,
2363 "Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
2364 return 0;
2365 }
Fenglin Wuef4730e2017-01-11 18:16:25 +08002366 val->intval = MICRO_5V + HVDCP3_STEP_UV * pulses;
2367 break;
2368 default:
2369 val->intval = MICRO_5V;
2370 break;
2371 }
2372
2373 return 0;
2374}
2375
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002376int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg,
2377 union power_supply_propval *val)
2378{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002379 val->intval = chg->pd_hard_reset;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002380 return 0;
2381}
2382
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07002383int smblib_get_pe_start(struct smb_charger *chg,
2384 union power_supply_propval *val)
2385{
2386 /*
2387 * hvdcp timeout voter is the last one to allow pd. Use its vote
2388 * to indicate start of pe engine
2389 */
2390 val->intval
2391 = !get_client_vote_locked(chg->pd_disallowed_votable_indirect,
2392 HVDCP_TIMEOUT_VOTER);
2393 return 0;
2394}
2395
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002396int smblib_get_prop_die_health(struct smb_charger *chg,
Nicholas Troastb021dd92017-01-31 18:43:38 -08002397 union power_supply_propval *val)
2398{
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002399 int rc;
Nicholas Troastb021dd92017-01-31 18:43:38 -08002400 u8 stat;
2401
2402 rc = smblib_read(chg, TEMP_RANGE_STATUS_REG, &stat);
2403 if (rc < 0) {
2404 smblib_err(chg, "Couldn't read TEMP_RANGE_STATUS_REG rc=%d\n",
2405 rc);
2406 return rc;
2407 }
2408
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002409 /* TEMP_RANGE bits are mutually exclusive */
2410 switch (stat & TEMP_RANGE_MASK) {
2411 case TEMP_BELOW_RANGE_BIT:
2412 val->intval = POWER_SUPPLY_HEALTH_COOL;
2413 break;
2414 case TEMP_WITHIN_RANGE_BIT:
2415 val->intval = POWER_SUPPLY_HEALTH_WARM;
2416 break;
2417 case TEMP_ABOVE_RANGE_BIT:
2418 val->intval = POWER_SUPPLY_HEALTH_HOT;
2419 break;
2420 case ALERT_LEVEL_BIT:
2421 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
2422 break;
2423 default:
2424 val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
Nicholas Troastb021dd92017-01-31 18:43:38 -08002425 }
2426
Nicholas Troastb021dd92017-01-31 18:43:38 -08002427 return 0;
2428}
2429
Nicholas Troast34db5032016-03-28 12:26:44 -07002430/*******************
2431 * USB PSY SETTERS *
2432 * *****************/
2433
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002434int smblib_set_prop_pd_current_max(struct smb_charger *chg,
2435 const union power_supply_propval *val)
2436{
2437 int rc;
2438
2439 if (chg->pd_active)
2440 rc = vote(chg->usb_icl_votable, PD_VOTER, true, val->intval);
2441 else
2442 rc = -EPERM;
2443
2444 return rc;
2445}
2446
Nicholas Troast34db5032016-03-28 12:26:44 -07002447int smblib_set_prop_usb_current_max(struct smb_charger *chg,
2448 const union power_supply_propval *val)
2449{
Nicholas Troast8d33b7d2017-01-16 11:18:38 -08002450 int rc = 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002451
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002452 if (!chg->pd_active) {
2453 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
2454 true, val->intval);
2455 } else if (chg->system_suspend_supported) {
2456 if (val->intval <= USBIN_25MA)
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302457 rc = vote(chg->usb_icl_votable,
2458 PD_SUSPEND_SUPPORTED_VOTER, true, val->intval);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002459 else
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302460 rc = vote(chg->usb_icl_votable,
2461 PD_SUSPEND_SUPPORTED_VOTER, false, 0);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002462 }
Nicholas Troast34db5032016-03-28 12:26:44 -07002463 return rc;
2464}
2465
Harry Yangd89ff1f2016-12-05 14:59:11 -08002466int smblib_set_prop_boost_current(struct smb_charger *chg,
2467 const union power_supply_propval *val)
2468{
2469 int rc = 0;
2470
2471 rc = smblib_set_charge_param(chg, &chg->param.freq_boost,
2472 val->intval <= chg->boost_threshold_ua ?
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05302473 chg->chg_freq.freq_below_otg_threshold :
2474 chg->chg_freq.freq_above_otg_threshold);
Harry Yangd89ff1f2016-12-05 14:59:11 -08002475 if (rc < 0) {
2476 dev_err(chg->dev, "Error in setting freq_boost rc=%d\n", rc);
2477 return rc;
2478 }
2479
2480 chg->boost_current_ua = val->intval;
2481 return rc;
2482}
2483
Nicholas Troast34db5032016-03-28 12:26:44 -07002484int smblib_set_prop_typec_power_role(struct smb_charger *chg,
2485 const union power_supply_propval *val)
2486{
2487 int rc = 0;
2488 u8 power_role;
2489
2490 switch (val->intval) {
2491 case POWER_SUPPLY_TYPEC_PR_NONE:
2492 power_role = TYPEC_DISABLE_CMD_BIT;
2493 break;
2494 case POWER_SUPPLY_TYPEC_PR_DUAL:
2495 power_role = 0;
2496 break;
2497 case POWER_SUPPLY_TYPEC_PR_SINK:
2498 power_role = UFP_EN_CMD_BIT;
2499 break;
2500 case POWER_SUPPLY_TYPEC_PR_SOURCE:
2501 power_role = DFP_EN_CMD_BIT;
2502 break;
2503 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002504 smblib_err(chg, "power role %d not supported\n", val->intval);
Nicholas Troast34db5032016-03-28 12:26:44 -07002505 return -EINVAL;
2506 }
2507
Jack Pham54a39bd2017-03-29 18:59:37 -07002508 if (power_role == UFP_EN_CMD_BIT) {
2509 /* disable PBS workaround when forcing sink mode */
2510 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0x0);
2511 if (rc < 0) {
2512 smblib_err(chg, "Couldn't write to TM_IO_DTEST4_SEL rc=%d\n",
2513 rc);
2514 }
2515 } else {
2516 /* restore it back to 0xA5 */
2517 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
2518 if (rc < 0) {
2519 smblib_err(chg, "Couldn't write to TM_IO_DTEST4_SEL rc=%d\n",
2520 rc);
2521 }
2522 }
2523
Nicholas Troast34db5032016-03-28 12:26:44 -07002524 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2525 TYPEC_POWER_ROLE_CMD_MASK, power_role);
2526 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002527 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 -07002528 power_role, rc);
2529 return rc;
2530 }
2531
2532 return rc;
2533}
2534
2535int smblib_set_prop_usb_voltage_min(struct smb_charger *chg,
2536 const union power_supply_propval *val)
2537{
2538 int rc, min_uv;
2539
2540 min_uv = min(val->intval, chg->voltage_max_uv);
2541 rc = smblib_set_usb_pd_allowed_voltage(chg, min_uv,
2542 chg->voltage_max_uv);
2543 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002544 smblib_err(chg, "invalid max voltage %duV rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002545 val->intval, rc);
2546 return rc;
2547 }
2548
Harry Yangaba1f5f2016-09-28 10:47:29 -07002549 chg->voltage_min_uv = min_uv;
Nicholas Troast34db5032016-03-28 12:26:44 -07002550 return rc;
2551}
2552
2553int smblib_set_prop_usb_voltage_max(struct smb_charger *chg,
2554 const union power_supply_propval *val)
2555{
2556 int rc, max_uv;
2557
2558 max_uv = max(val->intval, chg->voltage_min_uv);
2559 rc = smblib_set_usb_pd_allowed_voltage(chg, chg->voltage_min_uv,
2560 max_uv);
2561 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002562 smblib_err(chg, "invalid min voltage %duV rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002563 val->intval, rc);
2564 return rc;
2565 }
2566
Harry Yangaba1f5f2016-09-28 10:47:29 -07002567 chg->voltage_max_uv = max_uv;
Nicholas Troast34db5032016-03-28 12:26:44 -07002568 return rc;
2569}
2570
2571int smblib_set_prop_pd_active(struct smb_charger *chg,
2572 const union power_supply_propval *val)
2573{
2574 int rc;
Nicholas Troaste1932e42017-04-12 12:38:18 -07002575 bool orientation, sink_attached, hvdcp;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002576 u8 stat;
Nicholas Troast34db5032016-03-28 12:26:44 -07002577
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002578 if (!get_effective_result(chg->pd_allowed_votable))
Nicholas Troast34db5032016-03-28 12:26:44 -07002579 return -EINVAL;
Nicholas Troast34db5032016-03-28 12:26:44 -07002580
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002581 chg->pd_active = val->intval;
2582 if (chg->pd_active) {
2583 vote(chg->apsd_disable_votable, PD_VOTER, true, 0);
2584 vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
2585 vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
2586
2587 /*
2588 * VCONN_EN_ORIENTATION_BIT controls whether to use CC1 or CC2
2589 * line when TYPEC_SPARE_CFG_BIT (CC pin selection s/w override)
2590 * is set or when VCONN_EN_VALUE_BIT is set.
2591 */
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002592 orientation = chg->typec_status[3] & CC_ORIENTATION_BIT;
Harry Yang88acff42016-09-21 14:56:06 -07002593 rc = smblib_masked_write(chg,
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07002594 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2595 VCONN_EN_ORIENTATION_BIT,
2596 orientation ? 0 : VCONN_EN_ORIENTATION_BIT);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002597 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002598 smblib_err(chg,
Harry Yang88acff42016-09-21 14:56:06 -07002599 "Couldn't enable vconn on CC line rc=%d\n", rc);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002600
2601 /* SW controlled CC_OUT */
2602 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
2603 TYPEC_SPARE_CFG_BIT, TYPEC_SPARE_CFG_BIT);
2604 if (rc < 0)
2605 smblib_err(chg, "Couldn't enable SW cc_out rc=%d\n",
2606 rc);
2607
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302608 /*
2609 * Enforce 500mA for PD until the real vote comes in later.
2610 * It is guaranteed that pd_active is set prior to
2611 * pd_current_max
2612 */
Harry Yangcd995202016-11-07 13:32:52 -08002613 rc = vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002614 if (rc < 0)
Harry Yangcd995202016-11-07 13:32:52 -08002615 smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n",
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002616 rc);
Harry Yangcd995202016-11-07 13:32:52 -08002617
Nicholas Troastf9e44992017-03-14 09:06:56 -07002618 /* since PD was found the cable must be non-legacy */
2619 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
2620
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002621 /* clear USB ICL vote for DCP_VOTER */
Harry Yang631b99e2016-11-17 11:24:25 -08002622 rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002623 if (rc < 0)
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002624 smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n",
2625 rc);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002626
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302627 /* remove USB_PSY_VOTER */
2628 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002629 if (rc < 0)
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302630 smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002631 } else {
Nicholas Troaste1932e42017-04-12 12:38:18 -07002632 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
2633 if (rc < 0) {
2634 smblib_err(chg, "Couldn't read APSD status rc=%d\n",
2635 rc);
2636 return rc;
2637 }
2638
2639 hvdcp = stat & QC_CHARGER_BIT;
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002640 vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
2641 vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
2642 vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002643 vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER,
2644 false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002645
2646 /* HW controlled CC_OUT */
2647 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
2648 TYPEC_SPARE_CFG_BIT, 0);
2649 if (rc < 0)
2650 smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n",
2651 rc);
2652
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002653 /*
2654 * This WA should only run for HVDCP. Non-legacy SDP/CDP could
2655 * draw more, but this WA will remove Rd causing VBUS to drop,
2656 * and data could be interrupted. Non-legacy DCP could also draw
2657 * more, but it may impact compliance.
2658 */
Nicholas Troaste1932e42017-04-12 12:38:18 -07002659 sink_attached = chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT;
2660 if (!chg->typec_legacy_valid && !sink_attached && hvdcp)
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002661 schedule_work(&chg->legacy_detection_work);
Harry Yang88acff42016-09-21 14:56:06 -07002662 }
2663
Harry Yang6607b4a2016-05-17 17:50:09 -07002664 smblib_update_usb_type(chg);
Abhijeet Dharmapurikar76e2af52016-10-06 17:25:01 -07002665 power_supply_changed(chg->usb_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07002666 return rc;
2667}
2668
Fenglin Wuedd70792016-11-22 13:16:19 +08002669int smblib_set_prop_ship_mode(struct smb_charger *chg,
2670 const union power_supply_propval *val)
2671{
2672 int rc;
2673
2674 smblib_dbg(chg, PR_MISC, "Set ship mode: %d!!\n", !!val->intval);
2675
2676 rc = smblib_masked_write(chg, SHIP_MODE_REG, SHIP_MODE_EN_BIT,
2677 !!val->intval ? SHIP_MODE_EN_BIT : 0);
2678 if (rc < 0)
2679 dev_err(chg->dev, "Couldn't %s ship mode, rc=%d\n",
2680 !!val->intval ? "enable" : "disable", rc);
2681
2682 return rc;
2683}
2684
Harry Yang5e2bb712016-10-18 16:47:48 -07002685int smblib_reg_block_update(struct smb_charger *chg,
2686 struct reg_info *entry)
2687{
2688 int rc = 0;
2689
2690 while (entry && entry->reg) {
2691 rc = smblib_read(chg, entry->reg, &entry->bak);
2692 if (rc < 0) {
2693 dev_err(chg->dev, "Error in reading %s rc=%d\n",
2694 entry->desc, rc);
2695 break;
2696 }
2697 entry->bak &= entry->mask;
2698
2699 rc = smblib_masked_write(chg, entry->reg,
2700 entry->mask, entry->val);
2701 if (rc < 0) {
2702 dev_err(chg->dev, "Error in writing %s rc=%d\n",
2703 entry->desc, rc);
2704 break;
2705 }
2706 entry++;
2707 }
2708
2709 return rc;
2710}
2711
2712int smblib_reg_block_restore(struct smb_charger *chg,
2713 struct reg_info *entry)
2714{
2715 int rc = 0;
2716
2717 while (entry && entry->reg) {
2718 rc = smblib_masked_write(chg, entry->reg,
2719 entry->mask, entry->bak);
2720 if (rc < 0) {
2721 dev_err(chg->dev, "Error in writing %s rc=%d\n",
2722 entry->desc, rc);
2723 break;
2724 }
2725 entry++;
2726 }
2727
2728 return rc;
2729}
2730
Harry Yang755a34b2016-11-01 01:18:51 -07002731static struct reg_info cc2_detach_settings[] = {
2732 {
2733 .reg = TYPE_C_CFG_2_REG,
2734 .mask = TYPE_C_UFP_MODE_BIT | EN_TRY_SOURCE_MODE_BIT,
2735 .val = TYPE_C_UFP_MODE_BIT,
2736 .desc = "TYPE_C_CFG_2_REG",
2737 },
2738 {
2739 .reg = TYPE_C_CFG_3_REG,
2740 .mask = EN_TRYSINK_MODE_BIT,
2741 .val = 0,
2742 .desc = "TYPE_C_CFG_3_REG",
2743 },
2744 {
2745 .reg = TAPER_TIMER_SEL_CFG_REG,
2746 .mask = TYPEC_SPARE_CFG_BIT,
2747 .val = TYPEC_SPARE_CFG_BIT,
2748 .desc = "TAPER_TIMER_SEL_CFG_REG",
2749 },
2750 {
2751 .reg = TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2752 .mask = VCONN_EN_ORIENTATION_BIT,
2753 .val = 0,
2754 .desc = "TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG",
2755 },
2756 {
2757 .reg = MISC_CFG_REG,
2758 .mask = TCC_DEBOUNCE_20MS_BIT,
2759 .val = TCC_DEBOUNCE_20MS_BIT,
2760 .desc = "Tccdebounce time"
2761 },
2762 {
2763 },
2764};
2765
2766static int smblib_cc2_sink_removal_enter(struct smb_charger *chg)
2767{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002768 int rc, ccout, ufp_mode;
2769 u8 stat;
Harry Yang755a34b2016-11-01 01:18:51 -07002770
2771 if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002772 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002773
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002774 if (chg->cc2_detach_wa_active)
2775 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002776
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002777 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
Harry Yang755a34b2016-11-01 01:18:51 -07002778 if (rc < 0) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002779 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
Harry Yang755a34b2016-11-01 01:18:51 -07002780 return rc;
2781 }
Nicholas Troaste1932e42017-04-12 12:38:18 -07002782
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002783 ccout = (stat & CC_ATTACHED_BIT) ?
2784 (!!(stat & CC_ORIENTATION_BIT) + 1) : 0;
2785 ufp_mode = (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT) ?
2786 !(stat & UFP_DFP_MODE_STATUS_BIT) : 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002787
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002788 if (ccout != 2)
2789 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002790
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002791 if (!ufp_mode)
2792 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002793
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002794 chg->cc2_detach_wa_active = true;
2795 /* The CC2 removal WA will cause a type-c-change IRQ storm */
2796 smblib_reg_block_update(chg, cc2_detach_settings);
2797 schedule_work(&chg->rdstd_cc2_detach_work);
Harry Yang755a34b2016-11-01 01:18:51 -07002798 return rc;
2799}
2800
2801static int smblib_cc2_sink_removal_exit(struct smb_charger *chg)
2802{
Harry Yang755a34b2016-11-01 01:18:51 -07002803 if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002804 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002805
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002806 if (!chg->cc2_detach_wa_active)
2807 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002808
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002809 chg->cc2_detach_wa_active = false;
2810 cancel_work_sync(&chg->rdstd_cc2_detach_work);
2811 smblib_reg_block_restore(chg, cc2_detach_settings);
2812 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002813}
2814
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002815int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
2816 const union power_supply_propval *val)
2817{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002818 int rc = 0;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002819
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002820 if (chg->pd_hard_reset == val->intval)
2821 return rc;
2822
2823 chg->pd_hard_reset = val->intval;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002824 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002825 EXIT_SNK_BASED_ON_CC_BIT,
2826 (chg->pd_hard_reset) ? EXIT_SNK_BASED_ON_CC_BIT : 0);
2827 if (rc < 0)
2828 smblib_err(chg, "Couldn't set EXIT_SNK_BASED_ON_CC rc=%d\n",
Harry Yang755a34b2016-11-01 01:18:51 -07002829 rc);
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002830
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002831 vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER,
2832 chg->pd_hard_reset, 0);
Harry Yang755a34b2016-11-01 01:18:51 -07002833
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002834 return rc;
2835}
2836
Nicholas Troast7dbcad22016-10-05 13:30:18 -07002837/************************
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002838 * USB MAIN PSY GETTERS *
2839 ************************/
2840int smblib_get_prop_fcc_delta(struct smb_charger *chg,
2841 union power_supply_propval *val)
2842{
2843 int rc, jeita_cc_delta_ua, step_cc_delta_ua, hw_cc_delta_ua = 0;
2844
2845 rc = smblib_get_step_cc_delta(chg, &step_cc_delta_ua);
2846 if (rc < 0) {
2847 smblib_err(chg, "Couldn't get step cc delta rc=%d\n", rc);
2848 step_cc_delta_ua = 0;
2849 } else {
2850 hw_cc_delta_ua = step_cc_delta_ua;
2851 }
2852
2853 rc = smblib_get_jeita_cc_delta(chg, &jeita_cc_delta_ua);
2854 if (rc < 0) {
2855 smblib_err(chg, "Couldn't get jeita cc delta rc=%d\n", rc);
2856 jeita_cc_delta_ua = 0;
2857 } else if (jeita_cc_delta_ua < 0) {
2858 /* HW will take the min between JEITA and step charge */
2859 hw_cc_delta_ua = min(hw_cc_delta_ua, jeita_cc_delta_ua);
2860 }
2861
2862 val->intval = hw_cc_delta_ua;
2863 return 0;
2864}
2865
2866/************************
2867 * USB MAIN PSY SETTERS *
2868 ************************/
2869
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05302870#define SDP_CURRENT_UA 500000
2871#define CDP_CURRENT_UA 1500000
2872#define DCP_CURRENT_UA 1500000
2873#define HVDCP_CURRENT_UA 3000000
2874#define TYPEC_DEFAULT_CURRENT_UA 900000
2875#define TYPEC_MEDIUM_CURRENT_UA 1500000
2876#define TYPEC_HIGH_CURRENT_UA 3000000
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07002877int smblib_get_charge_current(struct smb_charger *chg,
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002878 int *total_current_ua)
2879{
Ashay Jaiswal7b6eb962017-04-26 14:34:29 +05302880 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002881 union power_supply_propval val = {0, };
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07002882 int rc = 0, typec_source_rd, current_ua;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002883 bool non_compliant;
2884 u8 stat5;
2885
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07002886 if (chg->pd_active) {
2887 *total_current_ua =
2888 get_client_vote_locked(chg->usb_icl_votable, PD_VOTER);
2889 return rc;
2890 }
2891
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002892 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
2893 if (rc < 0) {
2894 smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc);
2895 return rc;
2896 }
2897 non_compliant = stat5 & TYPEC_NONCOMP_LEGACY_CABLE_STATUS_BIT;
2898
2899 /* get settled ICL */
2900 rc = smblib_get_prop_input_current_settled(chg, &val);
2901 if (rc < 0) {
2902 smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
2903 return rc;
2904 }
2905
2906 typec_source_rd = smblib_get_prop_ufp_mode(chg);
2907
2908 /* QC 2.0/3.0 adapter */
2909 if (apsd_result->bit & (QC_3P0_BIT | QC_2P0_BIT)) {
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05302910 *total_current_ua = HVDCP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002911 return 0;
2912 }
2913
2914 if (non_compliant) {
2915 switch (apsd_result->bit) {
2916 case CDP_CHARGER_BIT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05302917 current_ua = CDP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002918 break;
2919 case DCP_CHARGER_BIT:
2920 case OCP_CHARGER_BIT:
2921 case FLOAT_CHARGER_BIT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05302922 current_ua = DCP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002923 break;
2924 default:
2925 current_ua = 0;
2926 break;
2927 }
2928
2929 *total_current_ua = max(current_ua, val.intval);
2930 return 0;
2931 }
2932
2933 switch (typec_source_rd) {
2934 case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
2935 switch (apsd_result->bit) {
2936 case CDP_CHARGER_BIT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05302937 current_ua = CDP_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002938 break;
2939 case DCP_CHARGER_BIT:
2940 case OCP_CHARGER_BIT:
2941 case FLOAT_CHARGER_BIT:
2942 current_ua = chg->default_icl_ua;
2943 break;
2944 default:
2945 current_ua = 0;
2946 break;
2947 }
2948 break;
2949 case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05302950 current_ua = TYPEC_MEDIUM_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002951 break;
2952 case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05302953 current_ua = TYPEC_HIGH_CURRENT_UA;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002954 break;
2955 case POWER_SUPPLY_TYPEC_NON_COMPLIANT:
2956 case POWER_SUPPLY_TYPEC_NONE:
2957 default:
2958 current_ua = 0;
2959 break;
2960 }
2961
2962 *total_current_ua = max(current_ua, val.intval);
2963 return 0;
2964}
2965
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002966/************************
Nicholas Troast7dbcad22016-10-05 13:30:18 -07002967 * PARALLEL PSY GETTERS *
2968 ************************/
2969
2970int smblib_get_prop_slave_current_now(struct smb_charger *chg,
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07002971 union power_supply_propval *pval)
Nicholas Troast7dbcad22016-10-05 13:30:18 -07002972{
2973 if (IS_ERR_OR_NULL(chg->iio.batt_i_chan))
2974 chg->iio.batt_i_chan = iio_channel_get(chg->dev, "batt_i");
2975
2976 if (IS_ERR(chg->iio.batt_i_chan))
2977 return PTR_ERR(chg->iio.batt_i_chan);
2978
2979 return iio_read_channel_processed(chg->iio.batt_i_chan, &pval->intval);
2980}
2981
Nicholas Troast34db5032016-03-28 12:26:44 -07002982/**********************
2983 * INTERRUPT HANDLERS *
2984 **********************/
2985
2986irqreturn_t smblib_handle_debug(int irq, void *data)
2987{
2988 struct smb_irq_data *irq_data = data;
2989 struct smb_charger *chg = irq_data->parent_data;
2990
2991 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07002992 return IRQ_HANDLED;
2993}
2994
Nicholas Troast8995a702016-12-05 10:22:22 -08002995irqreturn_t smblib_handle_otg_overcurrent(int irq, void *data)
2996{
2997 struct smb_irq_data *irq_data = data;
2998 struct smb_charger *chg = irq_data->parent_data;
2999 int rc;
3000 u8 stat;
3001
3002 rc = smblib_read(chg, OTG_BASE + INT_RT_STS_OFFSET, &stat);
3003 if (rc < 0) {
3004 dev_err(chg->dev, "Couldn't read OTG_INT_RT_STS rc=%d\n", rc);
3005 return IRQ_HANDLED;
3006 }
3007
Ashay Jaiswal7c241382017-03-06 15:26:38 +05303008 if (chg->wa_flags & OTG_WA) {
3009 if (stat & OTG_OC_DIS_SW_STS_RT_STS_BIT)
3010 smblib_err(chg, "OTG disabled by hw\n");
3011
3012 /* not handling software based hiccups for PM660 */
3013 return IRQ_HANDLED;
3014 }
3015
Nicholas Troastb11015f2017-01-17 17:56:45 -08003016 if (stat & OTG_OVERCURRENT_RT_STS_BIT)
3017 schedule_work(&chg->otg_oc_work);
Nicholas Troast8995a702016-12-05 10:22:22 -08003018
Nicholas Troast8995a702016-12-05 10:22:22 -08003019 return IRQ_HANDLED;
3020}
3021
Harry Yang6fe72ab2016-06-14 16:21:39 -07003022irqreturn_t smblib_handle_chg_state_change(int irq, void *data)
3023{
3024 struct smb_irq_data *irq_data = data;
3025 struct smb_charger *chg = irq_data->parent_data;
Nicholas Troast8cb77552016-09-23 11:50:18 -07003026 u8 stat;
Harry Yang1d1034c2016-06-15 12:09:42 -07003027 int rc;
Harry Yang6fe72ab2016-06-14 16:21:39 -07003028
3029 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3030
Nicholas Troast8cb77552016-09-23 11:50:18 -07003031 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
Harry Yang1d1034c2016-06-15 12:09:42 -07003032 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003033 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003034 rc);
Harry Yang1d1034c2016-06-15 12:09:42 -07003035 return IRQ_HANDLED;
3036 }
3037
Nicholas Troast8cb77552016-09-23 11:50:18 -07003038 stat = stat & BATTERY_CHARGER_STATUS_MASK;
Nicholas Troast8cb77552016-09-23 11:50:18 -07003039 power_supply_changed(chg->batt_psy);
Harry Yang6fe72ab2016-06-14 16:21:39 -07003040 return IRQ_HANDLED;
3041}
3042
Harry Yangfe913842016-08-10 12:27:28 -07003043irqreturn_t smblib_handle_step_chg_state_change(int irq, void *data)
3044{
3045 struct smb_irq_data *irq_data = data;
3046 struct smb_charger *chg = irq_data->parent_data;
3047
3048 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3049
3050 if (chg->step_chg_enabled)
3051 rerun_election(chg->fcc_votable);
3052
3053 return IRQ_HANDLED;
3054}
3055
3056irqreturn_t smblib_handle_step_chg_soc_update_fail(int irq, void *data)
3057{
3058 struct smb_irq_data *irq_data = data;
3059 struct smb_charger *chg = irq_data->parent_data;
3060
3061 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3062
3063 if (chg->step_chg_enabled)
3064 rerun_election(chg->fcc_votable);
3065
3066 return IRQ_HANDLED;
3067}
3068
3069#define STEP_SOC_REQ_MS 3000
3070irqreturn_t smblib_handle_step_chg_soc_update_request(int irq, void *data)
3071{
3072 struct smb_irq_data *irq_data = data;
3073 struct smb_charger *chg = irq_data->parent_data;
3074 int rc;
3075 union power_supply_propval pval = {0, };
3076
3077 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3078
3079 if (!chg->bms_psy) {
3080 schedule_delayed_work(&chg->step_soc_req_work,
3081 msecs_to_jiffies(STEP_SOC_REQ_MS));
3082 return IRQ_HANDLED;
3083 }
3084
3085 rc = smblib_get_prop_batt_capacity(chg, &pval);
3086 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003087 smblib_err(chg, "Couldn't get batt capacity rc=%d\n", rc);
Harry Yangfe913842016-08-10 12:27:28 -07003088 else
3089 step_charge_soc_update(chg, pval.intval);
3090
3091 return IRQ_HANDLED;
3092}
3093
Abhijeet Dharmapurikar2644cd62016-07-20 16:54:55 -07003094irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data)
3095{
3096 struct smb_irq_data *irq_data = data;
3097 struct smb_charger *chg = irq_data->parent_data;
3098
3099 rerun_election(chg->fcc_votable);
3100 power_supply_changed(chg->batt_psy);
3101 return IRQ_HANDLED;
3102}
3103
Nicholas Troast34db5032016-03-28 12:26:44 -07003104irqreturn_t smblib_handle_batt_psy_changed(int irq, void *data)
3105{
3106 struct smb_irq_data *irq_data = data;
3107 struct smb_charger *chg = irq_data->parent_data;
3108
Nicholas Troast47ae4612016-08-03 09:49:36 -07003109 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003110 power_supply_changed(chg->batt_psy);
3111 return IRQ_HANDLED;
3112}
3113
3114irqreturn_t smblib_handle_usb_psy_changed(int irq, void *data)
3115{
3116 struct smb_irq_data *irq_data = data;
3117 struct smb_charger *chg = irq_data->parent_data;
3118
Nicholas Troast47ae4612016-08-03 09:49:36 -07003119 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003120 power_supply_changed(chg->usb_psy);
3121 return IRQ_HANDLED;
3122}
3123
Subbaraman Narayanamurthy09327482017-02-06 16:33:12 -08003124irqreturn_t smblib_handle_usbin_uv(int irq, void *data)
3125{
3126 struct smb_irq_data *irq_data = data;
3127 struct smb_charger *chg = irq_data->parent_data;
3128 struct storm_watch *wdata;
3129
3130 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3131 if (!chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data)
3132 return IRQ_HANDLED;
3133
3134 wdata = &chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data->storm_data;
3135 reset_storm_count(wdata);
3136 return IRQ_HANDLED;
3137}
3138
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003139static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising)
3140{
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003141 if (vbus_rising) {
3142 /* use the typec flag even though its not typec */
3143 chg->typec_present = 1;
3144 } else {
3145 chg->typec_present = 0;
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003146 smblib_update_usb_type(chg);
3147 extcon_set_cable_state_(chg->extcon, EXTCON_USB, false);
3148 smblib_uusb_removal(chg);
3149 }
3150}
3151
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003152void smblib_usb_plugin_hard_reset_locked(struct smb_charger *chg)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003153{
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003154 int rc;
3155 u8 stat;
3156 bool vbus_rising;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303157 struct smb_irq_data *data;
3158 struct storm_watch *wdata;
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003159
3160 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
3161 if (rc < 0) {
3162 smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
3163 return;
3164 }
3165
3166 vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
3167
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303168 if (vbus_rising) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003169 smblib_cc2_sink_removal_exit(chg);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303170 } else {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003171 smblib_cc2_sink_removal_enter(chg);
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303172 if (chg->wa_flags & BOOST_BACK_WA) {
3173 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
3174 if (data) {
3175 wdata = &data->storm_data;
3176 update_storm_count(wdata,
3177 WEAK_CHG_STORM_COUNT);
3178 vote(chg->usb_icl_votable, BOOST_BACK_VOTER,
3179 false, 0);
3180 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
3181 false, 0);
3182 }
3183 }
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303184 }
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003185
3186 power_supply_changed(chg->usb_psy);
3187 smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
3188 vbus_rising ? "attached" : "detached");
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003189}
3190
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303191#define PL_DELAY_MS 30000
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003192void smblib_usb_plugin_locked(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07003193{
Nicholas Troast34db5032016-03-28 12:26:44 -07003194 int rc;
3195 u8 stat;
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003196 bool vbus_rising;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303197 struct smb_irq_data *data;
3198 struct storm_watch *wdata;
Nicholas Troast34db5032016-03-28 12:26:44 -07003199
Harry Yangcdad2bf2016-10-04 17:03:56 -07003200 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
3201 if (rc < 0) {
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003202 smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
3203 return;
Harry Yangcdad2bf2016-10-04 17:03:56 -07003204 }
3205
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003206 vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003207 smblib_set_opt_freq_buck(chg, vbus_rising ? chg->chg_freq.freq_5V :
3208 chg->chg_freq.freq_removal);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003209
Nicholas Troast34db5032016-03-28 12:26:44 -07003210 /* fetch the DPDM regulator */
3211 if (!chg->dpdm_reg && of_get_property(chg->dev->of_node,
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05303212 "dpdm-supply", NULL)) {
Nicholas Troast34db5032016-03-28 12:26:44 -07003213 chg->dpdm_reg = devm_regulator_get(chg->dev, "dpdm");
3214 if (IS_ERR(chg->dpdm_reg)) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003215 smblib_err(chg, "Couldn't get dpdm regulator rc=%ld\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07003216 PTR_ERR(chg->dpdm_reg));
3217 chg->dpdm_reg = NULL;
3218 }
3219 }
3220
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003221 if (vbus_rising) {
Nicholas Troastabedaf72016-09-16 11:07:45 -07003222 if (chg->dpdm_reg && !regulator_is_enabled(chg->dpdm_reg)) {
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07003223 smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n");
3224 rc = regulator_enable(chg->dpdm_reg);
3225 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003226 smblib_err(chg, "Couldn't enable dpdm regulator rc=%d\n",
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07003227 rc);
3228 }
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303229
3230 /* Schedule work to enable parallel charger */
3231 vote(chg->awake_votable, PL_DELAY_VOTER, true, 0);
3232 schedule_delayed_work(&chg->pl_enable_work,
3233 msecs_to_jiffies(PL_DELAY_MS));
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07003234 } else {
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303235 if (chg->wa_flags & BOOST_BACK_WA) {
3236 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
3237 if (data) {
3238 wdata = &data->storm_data;
3239 update_storm_count(wdata,
3240 WEAK_CHG_STORM_COUNT);
3241 vote(chg->usb_icl_votable, BOOST_BACK_VOTER,
3242 false, 0);
3243 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
3244 false, 0);
3245 }
3246 }
Nicholas Troastabedaf72016-09-16 11:07:45 -07003247
3248 if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) {
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07003249 smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n");
3250 rc = regulator_disable(chg->dpdm_reg);
3251 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003252 smblib_err(chg, "Couldn't disable dpdm regulator rc=%d\n",
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07003253 rc);
3254 }
Nicholas Troast34db5032016-03-28 12:26:44 -07003255 }
3256
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003257 if (chg->micro_usb_mode)
3258 smblib_micro_usb_plugin(chg, vbus_rising);
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003259
Nicholas Troast62d86622016-09-22 11:41:33 -07003260 power_supply_changed(chg->usb_psy);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003261 smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
3262 vbus_rising ? "attached" : "detached");
3263}
3264
3265irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
3266{
3267 struct smb_irq_data *irq_data = data;
3268 struct smb_charger *chg = irq_data->parent_data;
3269
3270 mutex_lock(&chg->lock);
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003271 if (chg->pd_hard_reset)
3272 smblib_usb_plugin_hard_reset_locked(chg);
3273 else
3274 smblib_usb_plugin_locked(chg);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003275 mutex_unlock(&chg->lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07003276 return IRQ_HANDLED;
3277}
3278
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -07003279#define USB_WEAK_INPUT_UA 1400000
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303280#define ICL_CHANGE_DELAY_MS 1000
Harry Yang6fe72ab2016-06-14 16:21:39 -07003281irqreturn_t smblib_handle_icl_change(int irq, void *data)
3282{
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303283 u8 stat;
3284 int rc, settled_ua, delay = ICL_CHANGE_DELAY_MS;
Harry Yang6fe72ab2016-06-14 16:21:39 -07003285 struct smb_irq_data *irq_data = data;
3286 struct smb_charger *chg = irq_data->parent_data;
3287
Nicholas Troastbb9e1a32017-02-09 10:57:28 -08003288 if (chg->mode == PARALLEL_MASTER) {
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303289 rc = smblib_read(chg, AICL_STATUS_REG, &stat);
3290 if (rc < 0) {
3291 smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n",
3292 rc);
3293 return IRQ_HANDLED;
3294 }
3295
3296 rc = smblib_get_charge_param(chg, &chg->param.icl_stat,
3297 &settled_ua);
3298 if (rc < 0) {
3299 smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
3300 return IRQ_HANDLED;
3301 }
3302
3303 /* If AICL settled then schedule work now */
3304 if ((settled_ua == get_effective_result(chg->usb_icl_votable))
3305 || (stat & AICL_DONE_BIT))
3306 delay = 0;
3307
Ashay Jaiswalac854862017-03-06 23:58:55 +05303308 cancel_delayed_work_sync(&chg->icl_change_work);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303309 schedule_delayed_work(&chg->icl_change_work,
3310 msecs_to_jiffies(delay));
Nicholas Troastbb9e1a32017-02-09 10:57:28 -08003311 }
Harry Yang1d1034c2016-06-15 12:09:42 -07003312
Harry Yang6fe72ab2016-06-14 16:21:39 -07003313 return IRQ_HANDLED;
3314}
3315
Nicholas Troast34db5032016-03-28 12:26:44 -07003316static void smblib_handle_slow_plugin_timeout(struct smb_charger *chg,
3317 bool rising)
3318{
3319 smblib_dbg(chg, PR_INTERRUPT, "IRQ: slow-plugin-timeout %s\n",
3320 rising ? "rising" : "falling");
3321}
3322
3323static void smblib_handle_sdp_enumeration_done(struct smb_charger *chg,
3324 bool rising)
3325{
3326 smblib_dbg(chg, PR_INTERRUPT, "IRQ: sdp-enumeration-done %s\n",
3327 rising ? "rising" : "falling");
3328}
3329
Harry Yangcdad2bf2016-10-04 17:03:56 -07003330#define QC3_PULSES_FOR_6V 5
3331#define QC3_PULSES_FOR_9V 20
3332#define QC3_PULSES_FOR_12V 35
3333static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg)
3334{
3335 int rc;
3336 u8 stat;
3337 int pulses;
3338
Fenglin Wuef4730e2017-01-11 18:16:25 +08003339 power_supply_changed(chg->usb_main_psy);
Fenglin Wu80826e02017-04-25 21:45:08 +08003340 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP) {
Harry Yangcdad2bf2016-10-04 17:03:56 -07003341 rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat);
3342 if (rc < 0) {
3343 smblib_err(chg,
3344 "Couldn't read QC_CHANGE_STATUS rc=%d\n", rc);
3345 return;
3346 }
3347
3348 switch (stat & QC_2P0_STATUS_MASK) {
3349 case QC_5V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303350 smblib_set_opt_freq_buck(chg,
3351 chg->chg_freq.freq_5V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003352 break;
3353 case QC_9V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303354 smblib_set_opt_freq_buck(chg,
3355 chg->chg_freq.freq_9V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003356 break;
3357 case QC_12V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303358 smblib_set_opt_freq_buck(chg,
3359 chg->chg_freq.freq_12V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003360 break;
3361 default:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303362 smblib_set_opt_freq_buck(chg,
3363 chg->chg_freq.freq_removal);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003364 break;
3365 }
3366 }
3367
Fenglin Wu80826e02017-04-25 21:45:08 +08003368 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP_3) {
Ashay Jaiswalcda0d1c2017-05-15 17:15:29 +05303369 rc = smblib_get_pulse_cnt(chg, &pulses);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003370 if (rc < 0) {
3371 smblib_err(chg,
3372 "Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
3373 return;
3374 }
Harry Yangcdad2bf2016-10-04 17:03:56 -07003375
3376 if (pulses < QC3_PULSES_FOR_6V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303377 smblib_set_opt_freq_buck(chg,
3378 chg->chg_freq.freq_5V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003379 else if (pulses < QC3_PULSES_FOR_9V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303380 smblib_set_opt_freq_buck(chg,
3381 chg->chg_freq.freq_6V_8V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003382 else if (pulses < QC3_PULSES_FOR_12V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303383 smblib_set_opt_freq_buck(chg,
3384 chg->chg_freq.freq_9V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003385 else
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303386 smblib_set_opt_freq_buck(chg,
3387 chg->chg_freq.freq_12V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003388 }
3389}
3390
Nicholas Troast34db5032016-03-28 12:26:44 -07003391/* triggers when HVDCP 3.0 authentication has finished */
3392static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
3393 bool rising)
3394{
3395 const struct apsd_result *apsd_result;
Harry Yangcdad2bf2016-10-04 17:03:56 -07003396 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07003397
3398 if (!rising)
3399 return;
3400
Ashay Jaiswal67ec7072017-02-16 14:14:58 +05303401 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
3402 /*
3403 * Disable AUTH_IRQ_EN_CFG_BIT to receive adapter voltage
3404 * change interrupt.
3405 */
3406 rc = smblib_masked_write(chg,
3407 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
3408 AUTH_IRQ_EN_CFG_BIT, 0);
3409 if (rc < 0)
3410 smblib_err(chg,
3411 "Couldn't enable QC auth setting rc=%d\n", rc);
3412 }
Harry Yangcdad2bf2016-10-04 17:03:56 -07003413
Harry Yangaba1f5f2016-09-28 10:47:29 -07003414 if (chg->mode == PARALLEL_MASTER)
3415 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0);
3416
Ashay Jaiswalac854862017-03-06 23:58:55 +05303417 /* the APSD done handler will set the USB supply type */
3418 apsd_result = smblib_get_apsd_result(chg);
3419 if (get_effective_result(chg->hvdcp_hw_inov_dis_votable)) {
3420 if (apsd_result->pst == POWER_SUPPLY_TYPE_USB_HVDCP) {
3421 /* force HVDCP2 to 9V if INOV is disabled */
3422 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG,
3423 FORCE_9V_BIT, FORCE_9V_BIT);
3424 if (rc < 0)
3425 smblib_err(chg,
3426 "Couldn't force 9V HVDCP rc=%d\n", rc);
3427 }
3428 }
3429
Nicholas Troast34db5032016-03-28 12:26:44 -07003430 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n",
3431 apsd_result->name);
3432}
3433
Harry Yang1369b7a2016-09-27 15:59:50 -07003434static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
3435 bool rising, bool qc_charger)
3436{
Ashay Jaiswal7b6eb962017-04-26 14:34:29 +05303437 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05303438
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003439 /* Hold off PD only until hvdcp 2.0 detection timeout */
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003440 if (rising) {
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003441 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003442 false, 0);
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -08003443
Harry Yang4bf7d962017-03-13 16:51:43 -07003444 /* enable HDC and ICL irq for QC2/3 charger */
3445 if (qc_charger)
3446 vote(chg->usb_irq_enable_votable, QC_VOTER, true, 0);
3447
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -08003448 /*
3449 * HVDCP detection timeout done
3450 * If adapter is not QC2.0/QC3.0 - it is a plain old DCP.
3451 */
3452 if (!qc_charger && (apsd_result->bit & DCP_CHARGER_BIT))
3453 /* enforce DCP ICL if specified */
3454 vote(chg->usb_icl_votable, DCP_VOTER,
3455 chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua);
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003456 }
Harry Yang1369b7a2016-09-27 15:59:50 -07003457
3458 smblib_dbg(chg, PR_INTERRUPT, "IRQ: smblib_handle_hvdcp_check_timeout %s\n",
3459 rising ? "rising" : "falling");
3460}
3461
Nicholas Troast34db5032016-03-28 12:26:44 -07003462/* triggers when HVDCP is detected */
3463static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg,
3464 bool rising)
3465{
3466 if (!rising)
3467 return;
3468
3469 /* the APSD done handler will set the USB supply type */
3470 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
3471 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-detect-done %s\n",
3472 rising ? "rising" : "falling");
3473}
3474
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303475static int get_rp_based_dcp_current(struct smb_charger *chg, int typec_mode)
3476{
3477 int rp_ua;
3478
3479 switch (typec_mode) {
3480 case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
3481 rp_ua = TYPEC_HIGH_CURRENT_UA;
3482 break;
3483 case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
3484 case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
3485 /* fall through */
3486 default:
3487 rp_ua = DCP_CURRENT_UA;
3488 }
3489
3490 return rp_ua;
3491}
3492
Nicholas Troastf9e44992017-03-14 09:06:56 -07003493static void smblib_force_legacy_icl(struct smb_charger *chg, int pst)
3494{
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303495 int typec_mode;
3496 int rp_ua;
3497
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003498 /* while PD is active it should have complete ICL control */
3499 if (chg->pd_active)
3500 return;
3501
Nicholas Troastf9e44992017-03-14 09:06:56 -07003502 switch (pst) {
3503 case POWER_SUPPLY_TYPE_USB:
3504 /*
3505 * USB_PSY will vote to increase the current to 500/900mA once
3506 * enumeration is done. Ensure that USB_PSY has at least voted
3507 * for 100mA before releasing the LEGACY_UNKNOWN vote
3508 */
3509 if (!is_client_vote_enabled(chg->usb_icl_votable,
3510 USB_PSY_VOTER))
3511 vote(chg->usb_icl_votable, USB_PSY_VOTER, true, 100000);
3512 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
3513 break;
3514 case POWER_SUPPLY_TYPE_USB_CDP:
3515 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1500000);
3516 break;
3517 case POWER_SUPPLY_TYPE_USB_DCP:
Ashay Jaiswalb9b2d2f2017-06-21 12:08:38 +05303518 case POWER_SUPPLY_TYPE_USB_FLOAT:
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303519 typec_mode = smblib_get_prop_typec_mode(chg);
3520 rp_ua = get_rp_based_dcp_current(chg, typec_mode);
3521 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua);
Nicholas Troastf9e44992017-03-14 09:06:56 -07003522 break;
3523 case POWER_SUPPLY_TYPE_USB_HVDCP:
3524 case POWER_SUPPLY_TYPE_USB_HVDCP_3:
3525 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 3000000);
3526 break;
3527 default:
3528 smblib_err(chg, "Unknown APSD %d; forcing 500mA\n", pst);
3529 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 500000);
3530 break;
3531 }
3532}
3533
Nicholas Troast34db5032016-03-28 12:26:44 -07003534#define HVDCP_DET_MS 2500
3535static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
3536{
Nicholas Troast34db5032016-03-28 12:26:44 -07003537 const struct apsd_result *apsd_result;
3538
3539 if (!rising)
3540 return;
3541
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07003542 apsd_result = smblib_update_usb_type(chg);
Nicholas Troastf9e44992017-03-14 09:06:56 -07003543
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003544 if (!chg->typec_legacy_valid)
Nicholas Troastf9e44992017-03-14 09:06:56 -07003545 smblib_force_legacy_icl(chg, apsd_result->pst);
3546
Nicholas Troast34db5032016-03-28 12:26:44 -07003547 switch (apsd_result->bit) {
3548 case SDP_CHARGER_BIT:
3549 case CDP_CHARGER_BIT:
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05303550 if (chg->micro_usb_mode)
3551 extcon_set_cable_state_(chg->extcon, EXTCON_USB,
3552 true);
Abhijeet Dharmapurikarbb9505f2017-03-22 18:31:28 -07003553 /* if not DCP then no hvdcp timeout happens. Enable pd here */
3554 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3555 false, 0);
3556 break;
Nicholas Troast34db5032016-03-28 12:26:44 -07003557 case OCP_CHARGER_BIT:
3558 case FLOAT_CHARGER_BIT:
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303559 /* if not DCP then no hvdcp timeout happens, Enable pd here. */
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003560 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3561 false, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07003562 break;
3563 case DCP_CHARGER_BIT:
Harry Yang1369b7a2016-09-27 15:59:50 -07003564 if (chg->wa_flags & QC_CHARGER_DETECTION_WA_BIT)
3565 schedule_delayed_work(&chg->hvdcp_detect_work,
3566 msecs_to_jiffies(HVDCP_DET_MS));
Nicholas Troast34db5032016-03-28 12:26:44 -07003567 break;
3568 default:
3569 break;
3570 }
3571
Nicholas Troast34db5032016-03-28 12:26:44 -07003572 smblib_dbg(chg, PR_INTERRUPT, "IRQ: apsd-done rising; %s detected\n",
3573 apsd_result->name);
3574}
3575
3576irqreturn_t smblib_handle_usb_source_change(int irq, void *data)
3577{
3578 struct smb_irq_data *irq_data = data;
3579 struct smb_charger *chg = irq_data->parent_data;
3580 int rc = 0;
3581 u8 stat;
3582
3583 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
3584 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003585 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07003586 return IRQ_HANDLED;
3587 }
3588 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
3589
Ashay Jaiswal8507aa52017-04-14 09:42:32 +05303590 if (chg->micro_usb_mode && (stat & APSD_DTC_STATUS_DONE_BIT)
3591 && !chg->uusb_apsd_rerun_done) {
3592 /*
3593 * Force re-run APSD to handle slow insertion related
3594 * charger-mis-detection.
3595 */
3596 chg->uusb_apsd_rerun_done = true;
3597 smblib_rerun_apsd(chg);
3598 return IRQ_HANDLED;
3599 }
3600
Nicholas Troast34db5032016-03-28 12:26:44 -07003601 smblib_handle_apsd_done(chg,
3602 (bool)(stat & APSD_DTC_STATUS_DONE_BIT));
3603
3604 smblib_handle_hvdcp_detect_done(chg,
3605 (bool)(stat & QC_CHARGER_BIT));
3606
Harry Yang1369b7a2016-09-27 15:59:50 -07003607 smblib_handle_hvdcp_check_timeout(chg,
3608 (bool)(stat & HVDCP_CHECK_TIMEOUT_BIT),
3609 (bool)(stat & QC_CHARGER_BIT));
3610
Nicholas Troast34db5032016-03-28 12:26:44 -07003611 smblib_handle_hvdcp_3p0_auth_done(chg,
3612 (bool)(stat & QC_AUTH_DONE_STATUS_BIT));
3613
Nicholas Troast34db5032016-03-28 12:26:44 -07003614 smblib_handle_sdp_enumeration_done(chg,
3615 (bool)(stat & ENUMERATION_DONE_BIT));
3616
3617 smblib_handle_slow_plugin_timeout(chg,
3618 (bool)(stat & SLOW_PLUGIN_TIMEOUT_BIT));
3619
Harry Yangcdad2bf2016-10-04 17:03:56 -07003620 smblib_hvdcp_adaptive_voltage_change(chg);
3621
Nicholas Troast34db5032016-03-28 12:26:44 -07003622 power_supply_changed(chg->usb_psy);
3623
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08003624 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
3625 if (rc < 0) {
3626 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
3627 return IRQ_HANDLED;
3628 }
3629 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
3630
Nicholas Troast34db5032016-03-28 12:26:44 -07003631 return IRQ_HANDLED;
3632}
3633
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003634static void typec_sink_insertion(struct smb_charger *chg)
3635{
3636 /* when a sink is inserted we should not wait on hvdcp timeout to
3637 * enable pd
3638 */
3639 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3640 false, 0);
3641}
Nicholas Troast34db5032016-03-28 12:26:44 -07003642
Harry Yangd89ff1f2016-12-05 14:59:11 -08003643static void typec_sink_removal(struct smb_charger *chg)
3644{
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303645 smblib_set_charge_param(chg, &chg->param.freq_boost,
3646 chg->chg_freq.freq_above_otg_threshold);
Harry Yangd89ff1f2016-12-05 14:59:11 -08003647 chg->boost_current_ua = 0;
3648}
3649
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003650static void smblib_handle_typec_removal(struct smb_charger *chg)
3651{
Nicholas Troastfe74c592017-03-14 09:20:55 -07003652 int rc;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303653 struct smb_irq_data *data;
3654 struct storm_watch *wdata;
Nicholas Troastfe74c592017-03-14 09:20:55 -07003655
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003656 chg->cc2_detach_wa_active = false;
3657
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303658 if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) {
3659 smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n");
3660 rc = regulator_disable(chg->dpdm_reg);
3661 if (rc < 0)
3662 smblib_err(chg, "Couldn't disable dpdm regulator rc=%d\n",
3663 rc);
3664 }
3665
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303666 if (chg->wa_flags & BOOST_BACK_WA) {
3667 data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
3668 if (data) {
3669 wdata = &data->storm_data;
3670 update_storm_count(wdata, WEAK_CHG_STORM_COUNT);
3671 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
3672 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
3673 false, 0);
3674 }
3675 }
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303676
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003677 /* reset APSD voters */
3678 vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, false, 0);
3679 vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303680
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003681 cancel_delayed_work_sync(&chg->pl_enable_work);
3682 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
3683
3684 /* reset input current limit voters */
3685 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
3686 vote(chg->usb_icl_votable, PD_VOTER, false, 0);
3687 vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
3688 vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
3689 vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
Ashay Jaiswalae23a042017-05-18 15:28:31 +05303690 vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
Abhijeet Dharmapurikar66d2c442017-07-12 11:55:36 -07003691 vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003692
3693 /* reset hvdcp voters */
3694 vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, true, 0);
3695 vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER, true, 0);
3696
3697 /* reset power delivery voters */
3698 vote(chg->pd_allowed_votable, PD_VOTER, false, 0);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003699 vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0);
3700 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER, true, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003701
3702 /* reset usb irq voters */
Harry Yang4bf7d962017-03-13 16:51:43 -07003703 vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
3704 vote(chg->usb_irq_enable_votable, QC_VOTER, false, 0);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003705
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003706 /* reset parallel voters */
3707 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
3708 vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
3709 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
3710 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
Harry Yang1d1034c2016-06-15 12:09:42 -07003711
Nicholas Troast8995a702016-12-05 10:22:22 -08003712 chg->vconn_attempts = 0;
3713 chg->otg_attempts = 0;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05303714 chg->pulse_cnt = 0;
3715 chg->usb_icl_delta_ua = 0;
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003716 chg->voltage_min_uv = MICRO_5V;
3717 chg->voltage_max_uv = MICRO_5V;
3718 chg->pd_active = 0;
3719 chg->pd_hard_reset = 0;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003720 chg->typec_legacy_valid = false;
Harry Yang3b113a52016-12-08 12:37:40 -08003721
Abhijeet Dharmapurikar676bd792017-05-31 16:21:57 -07003722 /* reset back to 120mS tCC debounce */
3723 rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT, 0);
3724 if (rc < 0)
3725 smblib_err(chg, "Couldn't set 120mS tCC debounce rc=%d\n", rc);
3726
Nicholas Troastfe74c592017-03-14 09:20:55 -07003727 /* enable APSD CC trigger for next insertion */
3728 rc = smblib_masked_write(chg, TYPE_C_CFG_REG,
3729 APSD_START_ON_CC_BIT, APSD_START_ON_CC_BIT);
3730 if (rc < 0)
3731 smblib_err(chg, "Couldn't enable APSD_START_ON_CC rc=%d\n", rc);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08003732
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003733 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
3734 /* re-enable AUTH_IRQ_EN_CFG_BIT */
3735 rc = smblib_masked_write(chg,
3736 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
3737 AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
3738 if (rc < 0)
3739 smblib_err(chg,
3740 "Couldn't enable QC auth setting rc=%d\n", rc);
3741 }
3742
3743 /* reconfigure allowed voltage for HVDCP */
3744 rc = smblib_set_adapter_allowance(chg,
3745 USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
3746 if (rc < 0)
3747 smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
3748 rc);
3749
3750 /* enable DRP */
3751 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
3752 TYPEC_POWER_ROLE_CMD_MASK, 0);
3753 if (rc < 0)
3754 smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc);
3755
3756 /* HW controlled CC_OUT */
3757 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
3758 TYPEC_SPARE_CFG_BIT, 0);
3759 if (rc < 0)
3760 smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n", rc);
3761
3762 /* restore crude sensor */
3763 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
3764 if (rc < 0)
3765 smblib_err(chg, "Couldn't restore crude sensor rc=%d\n", rc);
3766
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07003767 mutex_lock(&chg->vconn_oc_lock);
3768 if (!chg->vconn_en)
3769 goto unlock;
3770
3771 smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
3772 VCONN_EN_VALUE_BIT, 0);
3773 chg->vconn_en = false;
3774
3775unlock:
3776 mutex_unlock(&chg->vconn_oc_lock);
3777
Abhijeet Dharmapurikar319d6942017-06-05 17:14:17 -07003778 /* clear exit sink based on cc */
3779 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
3780 EXIT_SNK_BASED_ON_CC_BIT, 0);
3781 if (rc < 0)
3782 smblib_err(chg, "Couldn't clear exit_sink_based_on_cc rc=%d\n",
3783 rc);
3784
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08003785 typec_sink_removal(chg);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003786 smblib_update_usb_type(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07003787}
3788
Nicholas Troaste1932e42017-04-12 12:38:18 -07003789static void smblib_handle_typec_insertion(struct smb_charger *chg)
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003790{
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003791 int rc;
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003792
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003793 vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, false, 0);
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003794
Nicholas Troastfe74c592017-03-14 09:20:55 -07003795 /* disable APSD CC trigger since CC is attached */
3796 rc = smblib_masked_write(chg, TYPE_C_CFG_REG, APSD_START_ON_CC_BIT, 0);
3797 if (rc < 0)
3798 smblib_err(chg, "Couldn't disable APSD_START_ON_CC rc=%d\n",
3799 rc);
3800
Nicholas Troaste1932e42017-04-12 12:38:18 -07003801 if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003802 typec_sink_insertion(chg);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003803 else
Harry Yangd89ff1f2016-12-05 14:59:11 -08003804 typec_sink_removal(chg);
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003805}
3806
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303807static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode)
3808{
3809 int rp_ua;
3810 const struct apsd_result *apsd = smblib_get_apsd_result(chg);
3811
3812 if ((apsd->pst != POWER_SUPPLY_TYPE_USB_DCP)
3813 && (apsd->pst != POWER_SUPPLY_TYPE_USB_FLOAT))
3814 return;
3815
3816 /*
3817 * handle Rp change for DCP/FLOAT/OCP.
3818 * Update the current only if the Rp is different from
3819 * the last Rp value.
3820 */
3821 smblib_dbg(chg, PR_MISC, "CC change old_mode=%d new_mode=%d\n",
3822 chg->typec_mode, typec_mode);
3823
3824 rp_ua = get_rp_based_dcp_current(chg, typec_mode);
3825 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua);
3826}
3827
Nicholas Troaste1932e42017-04-12 12:38:18 -07003828static void smblib_handle_typec_cc_state_change(struct smb_charger *chg)
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003829{
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303830 int typec_mode;
3831
Nicholas Troaste1932e42017-04-12 12:38:18 -07003832 if (chg->pr_swap_in_progress)
3833 return;
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003834
Ashay Jaiswaldd08c622017-06-29 16:25:23 +05303835 typec_mode = smblib_get_prop_typec_mode(chg);
3836 if (chg->typec_present && (typec_mode != chg->typec_mode))
3837 smblib_handle_rp_change(chg, typec_mode);
3838
3839 chg->typec_mode = typec_mode;
3840
Nicholas Troaste1932e42017-04-12 12:38:18 -07003841 if (!chg->typec_present && chg->typec_mode != POWER_SUPPLY_TYPEC_NONE) {
3842 chg->typec_present = true;
3843 smblib_dbg(chg, PR_MISC, "TypeC %s insertion\n",
3844 smblib_typec_mode_name[chg->typec_mode]);
3845 smblib_handle_typec_insertion(chg);
3846 } else if (chg->typec_present &&
3847 chg->typec_mode == POWER_SUPPLY_TYPEC_NONE) {
3848 chg->typec_present = false;
3849 smblib_dbg(chg, PR_MISC, "TypeC removal\n");
3850 smblib_handle_typec_removal(chg);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003851 }
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003852
Abhijeet Dharmapurikar66d2c442017-07-12 11:55:36 -07003853 /* suspend usb if sink */
3854 if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
3855 vote(chg->usb_icl_votable, OTG_VOTER, true, 0);
3856 else
3857 vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
3858
Nicholas Troaste1932e42017-04-12 12:38:18 -07003859 smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n",
3860 smblib_typec_mode_name[chg->typec_mode]);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003861}
3862
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003863static void smblib_usb_typec_change(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07003864{
Nicholas Troast34db5032016-03-28 12:26:44 -07003865 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07003866
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07003867 rc = smblib_multibyte_read(chg, TYPE_C_STATUS_1_REG,
3868 chg->typec_status, 5);
Nicholas Troast34db5032016-03-28 12:26:44 -07003869 if (rc < 0) {
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07003870 smblib_err(chg, "Couldn't cache USB Type-C status rc=%d\n", rc);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003871 return;
Nicholas Troast34db5032016-03-28 12:26:44 -07003872 }
Nicholas Troast34db5032016-03-28 12:26:44 -07003873
Nicholas Troaste1932e42017-04-12 12:38:18 -07003874 smblib_handle_typec_cc_state_change(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07003875
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07003876 if (chg->typec_status[3] & TYPEC_VBUS_ERROR_STATUS_BIT)
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003877 smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n");
Harry Yangd757c0f2016-09-23 10:52:05 -07003878
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07003879 if (chg->typec_status[3] & TYPEC_VCONN_OVERCURR_STATUS_BIT)
Nicholas Troastb11015f2017-01-17 17:56:45 -08003880 schedule_work(&chg->vconn_oc_work);
Nicholas Troast8995a702016-12-05 10:22:22 -08003881
Nicholas Troastb1486552016-11-10 08:20:11 -08003882 power_supply_changed(chg->usb_psy);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003883}
3884
3885irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
3886{
3887 struct smb_irq_data *irq_data = data;
3888 struct smb_charger *chg = irq_data->parent_data;
3889
3890 if (chg->micro_usb_mode) {
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05303891 cancel_delayed_work_sync(&chg->uusb_otg_work);
3892 vote(chg->awake_votable, OTG_DELAY_VOTER, true, 0);
3893 smblib_dbg(chg, PR_INTERRUPT, "Scheduling OTG work\n");
3894 schedule_delayed_work(&chg->uusb_otg_work,
3895 msecs_to_jiffies(chg->otg_delay_ms));
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003896 return IRQ_HANDLED;
3897 }
3898
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003899 if (chg->cc2_detach_wa_active || chg->typec_en_dis_active) {
3900 smblib_dbg(chg, PR_INTERRUPT, "Ignoring since %s active\n",
3901 chg->cc2_detach_wa_active ?
3902 "cc2_detach_wa" : "typec_en_dis");
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003903 return IRQ_HANDLED;
3904 }
3905
Abhijeet Dharmapurikar049b2552017-07-12 11:27:51 -07003906 if (chg->pr_swap_in_progress) {
3907 smblib_dbg(chg, PR_INTERRUPT,
3908 "Ignoring since pr_swap_in_progress\n");
3909 return IRQ_HANDLED;
3910 }
3911
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003912 mutex_lock(&chg->lock);
3913 smblib_usb_typec_change(chg);
3914 mutex_unlock(&chg->lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07003915 return IRQ_HANDLED;
3916}
3917
Abhijeet Dharmapurikar23916642016-10-03 10:38:50 -07003918irqreturn_t smblib_handle_dc_plugin(int irq, void *data)
3919{
3920 struct smb_irq_data *irq_data = data;
3921 struct smb_charger *chg = irq_data->parent_data;
3922
3923 power_supply_changed(chg->dc_psy);
3924 return IRQ_HANDLED;
3925}
3926
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07003927irqreturn_t smblib_handle_high_duty_cycle(int irq, void *data)
3928{
3929 struct smb_irq_data *irq_data = data;
3930 struct smb_charger *chg = irq_data->parent_data;
3931
3932 chg->is_hdc = true;
3933 schedule_delayed_work(&chg->clear_hdc_work, msecs_to_jiffies(60));
3934
3935 return IRQ_HANDLED;
3936}
3937
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05303938static void smblib_bb_removal_work(struct work_struct *work)
3939{
3940 struct smb_charger *chg = container_of(work, struct smb_charger,
3941 bb_removal_work.work);
3942
3943 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
3944 vote(chg->awake_votable, BOOST_BACK_VOTER, false, 0);
3945}
3946
3947#define BOOST_BACK_UNVOTE_DELAY_MS 750
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303948#define BOOST_BACK_STORM_COUNT 3
3949#define WEAK_CHG_STORM_COUNT 8
Nicholas Troastabedaf72016-09-16 11:07:45 -07003950irqreturn_t smblib_handle_switcher_power_ok(int irq, void *data)
3951{
3952 struct smb_irq_data *irq_data = data;
3953 struct smb_charger *chg = irq_data->parent_data;
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303954 struct storm_watch *wdata = &irq_data->storm_data;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003955 int rc, usb_icl;
Nicholas Troastabedaf72016-09-16 11:07:45 -07003956 u8 stat;
3957
3958 if (!(chg->wa_flags & BOOST_BACK_WA))
3959 return IRQ_HANDLED;
3960
3961 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
3962 if (rc < 0) {
3963 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n", rc);
3964 return IRQ_HANDLED;
3965 }
3966
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003967 /* skip suspending input if its already suspended by some other voter */
3968 usb_icl = get_effective_result(chg->usb_icl_votable);
3969 if ((stat & USE_USBIN_BIT) && usb_icl >= 0 && usb_icl < USBIN_25MA)
Nicholas Troastabedaf72016-09-16 11:07:45 -07003970 return IRQ_HANDLED;
3971
Abhijeet Dharmapurikar2823fe32016-12-05 17:52:11 -08003972 if (stat & USE_DCIN_BIT)
Nicholas Troastabedaf72016-09-16 11:07:45 -07003973 return IRQ_HANDLED;
3974
3975 if (is_storming(&irq_data->storm_data)) {
Ashay Jaiswal2f3b0c12017-06-14 16:04:45 +05303976 /* This could be a weak charger reduce ICL */
3977 if (!is_client_vote_enabled(chg->usb_icl_votable,
3978 WEAK_CHARGER_VOTER)) {
3979 smblib_err(chg,
3980 "Weak charger detected: voting %dmA ICL\n",
3981 *chg->weak_chg_icl_ua / 1000);
3982 vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
3983 true, *chg->weak_chg_icl_ua);
3984 /*
3985 * reset storm data and set the storm threshold
3986 * to 3 for reverse boost detection.
3987 */
3988 update_storm_count(wdata, BOOST_BACK_STORM_COUNT);
3989 } else {
3990 smblib_err(chg,
3991 "Reverse boost detected: voting 0mA to suspend input\n");
3992 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, true, 0);
3993 vote(chg->awake_votable, BOOST_BACK_VOTER, true, 0);
3994 /*
3995 * Remove the boost-back vote after a delay, to avoid
3996 * permanently suspending the input if the boost-back
3997 * condition is unintentionally hit.
3998 */
3999 schedule_delayed_work(&chg->bb_removal_work,
4000 msecs_to_jiffies(BOOST_BACK_UNVOTE_DELAY_MS));
4001 }
Nicholas Troastabedaf72016-09-16 11:07:45 -07004002 }
4003
4004 return IRQ_HANDLED;
4005}
4006
Nicholas Troast15dc0c82016-10-18 15:15:21 -07004007irqreturn_t smblib_handle_wdog_bark(int irq, void *data)
4008{
4009 struct smb_irq_data *irq_data = data;
4010 struct smb_charger *chg = irq_data->parent_data;
4011 int rc;
4012
4013 rc = smblib_write(chg, BARK_BITE_WDOG_PET_REG, BARK_BITE_WDOG_PET_BIT);
4014 if (rc < 0)
4015 smblib_err(chg, "Couldn't pet the dog rc=%d\n", rc);
4016
4017 return IRQ_HANDLED;
4018}
4019
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004020/**************
4021 * Additional USB PSY getters/setters
4022 * that call interrupt functions
4023 ***************/
4024
4025int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg,
4026 union power_supply_propval *val)
4027{
4028 val->intval = chg->pr_swap_in_progress;
4029 return 0;
4030}
4031
4032int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg,
4033 const union power_supply_propval *val)
4034{
Abhijeet Dharmapurikar676bd792017-05-31 16:21:57 -07004035 int rc;
4036
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004037 chg->pr_swap_in_progress = val->intval;
4038 /*
4039 * call the cc changed irq to handle real removals while
4040 * PR_SWAP was in progress
4041 */
4042 smblib_usb_typec_change(chg);
Abhijeet Dharmapurikar676bd792017-05-31 16:21:57 -07004043 rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT,
4044 val->intval ? TCC_DEBOUNCE_20MS_BIT : 0);
4045 if (rc < 0)
4046 smblib_err(chg, "Couldn't set tCC debounce rc=%d\n", rc);
Abhijeet Dharmapurikar255da952017-05-24 20:52:09 -07004047 return 0;
4048}
4049
Nicholas Troast34db5032016-03-28 12:26:44 -07004050/***************
4051 * Work Queues *
4052 ***************/
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05304053static void smblib_uusb_otg_work(struct work_struct *work)
4054{
4055 struct smb_charger *chg = container_of(work, struct smb_charger,
4056 uusb_otg_work.work);
4057 int rc;
4058 u8 stat;
4059 bool otg;
4060
4061 rc = smblib_read(chg, TYPE_C_STATUS_3_REG, &stat);
4062 if (rc < 0) {
4063 smblib_err(chg, "Couldn't read TYPE_C_STATUS_3 rc=%d\n", rc);
4064 goto out;
4065 }
4066
4067 otg = !!(stat & (U_USB_GND_NOVBUS_BIT | U_USB_GND_BIT));
4068 extcon_set_cable_state_(chg->extcon, EXTCON_USB_HOST, otg);
4069 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_3 = 0x%02x OTG=%d\n",
4070 stat, otg);
4071 power_supply_changed(chg->usb_psy);
4072
4073out:
4074 vote(chg->awake_votable, OTG_DELAY_VOTER, false, 0);
4075}
4076
Nicholas Troast34db5032016-03-28 12:26:44 -07004077
4078static void smblib_hvdcp_detect_work(struct work_struct *work)
4079{
4080 struct smb_charger *chg = container_of(work, struct smb_charger,
4081 hvdcp_detect_work.work);
Nicholas Troast34db5032016-03-28 12:26:44 -07004082
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07004083 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
4084 false, 0);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004085 power_supply_changed(chg->usb_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07004086}
4087
Harry Yangfe913842016-08-10 12:27:28 -07004088static void bms_update_work(struct work_struct *work)
Harry Yang5e1a5222016-07-26 15:16:04 -07004089{
4090 struct smb_charger *chg = container_of(work, struct smb_charger,
4091 bms_update_work);
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05304092
4093 smblib_suspend_on_debug_battery(chg);
4094
4095 if (chg->batt_psy)
4096 power_supply_changed(chg->batt_psy);
Harry Yang5e1a5222016-07-26 15:16:04 -07004097}
4098
Harry Yangfe913842016-08-10 12:27:28 -07004099static void step_soc_req_work(struct work_struct *work)
4100{
4101 struct smb_charger *chg = container_of(work, struct smb_charger,
4102 step_soc_req_work.work);
4103 union power_supply_propval pval = {0, };
4104 int rc;
4105
4106 rc = smblib_get_prop_batt_capacity(chg, &pval);
4107 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004108 smblib_err(chg, "Couldn't get batt capacity rc=%d\n", rc);
Harry Yangfe913842016-08-10 12:27:28 -07004109 return;
4110 }
4111
4112 step_charge_soc_update(chg, pval.intval);
4113}
4114
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004115static void clear_hdc_work(struct work_struct *work)
4116{
4117 struct smb_charger *chg = container_of(work, struct smb_charger,
4118 clear_hdc_work.work);
4119
4120 chg->is_hdc = 0;
4121}
4122
Harry Yang755a34b2016-11-01 01:18:51 -07004123static void rdstd_cc2_detach_work(struct work_struct *work)
4124{
4125 int rc;
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004126 u8 stat4, stat5;
Harry Yang755a34b2016-11-01 01:18:51 -07004127 struct smb_charger *chg = container_of(work, struct smb_charger,
4128 rdstd_cc2_detach_work);
4129
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004130 if (!chg->cc2_detach_wa_active)
4131 return;
4132
Harry Yang755a34b2016-11-01 01:18:51 -07004133 /*
4134 * WA steps -
4135 * 1. Enable both UFP and DFP, wait for 10ms.
4136 * 2. Disable DFP, wait for 30ms.
4137 * 3. Removal detected if both TYPEC_DEBOUNCE_DONE_STATUS
4138 * and TIMER_STAGE bits are gone, otherwise repeat all by
4139 * work rescheduling.
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004140 * Note, work will be cancelled when USB_PLUGIN rises.
Harry Yang755a34b2016-11-01 01:18:51 -07004141 */
4142
4143 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4144 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT,
4145 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT);
4146 if (rc < 0) {
4147 smblib_err(chg, "Couldn't write TYPE_C_CTRL_REG rc=%d\n", rc);
4148 return;
4149 }
4150
4151 usleep_range(10000, 11000);
4152
4153 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4154 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT,
4155 UFP_EN_CMD_BIT);
4156 if (rc < 0) {
4157 smblib_err(chg, "Couldn't write TYPE_C_CTRL_REG rc=%d\n", rc);
4158 return;
4159 }
4160
4161 usleep_range(30000, 31000);
4162
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004163 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
Harry Yang755a34b2016-11-01 01:18:51 -07004164 if (rc < 0) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004165 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
Harry Yang755a34b2016-11-01 01:18:51 -07004166 return;
4167 }
Harry Yang755a34b2016-11-01 01:18:51 -07004168
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004169 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
Harry Yang755a34b2016-11-01 01:18:51 -07004170 if (rc < 0) {
4171 smblib_err(chg,
4172 "Couldn't read TYPE_C_STATUS_5_REG rc=%d\n", rc);
4173 return;
4174 }
Harry Yang755a34b2016-11-01 01:18:51 -07004175
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004176 if ((stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT)
4177 || (stat5 & TIMER_STAGE_2_BIT)) {
4178 smblib_dbg(chg, PR_MISC, "rerunning DD=%d TS2BIT=%d\n",
4179 (int)(stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT),
4180 (int)(stat5 & TIMER_STAGE_2_BIT));
4181 goto rerun;
4182 }
4183
4184 smblib_dbg(chg, PR_MISC, "Bingo CC2 Removal detected\n");
4185 chg->cc2_detach_wa_active = false;
4186 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4187 EXIT_SNK_BASED_ON_CC_BIT, 0);
Harry Yang755a34b2016-11-01 01:18:51 -07004188 smblib_reg_block_restore(chg, cc2_detach_settings);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004189 mutex_lock(&chg->lock);
4190 smblib_usb_typec_change(chg);
4191 mutex_unlock(&chg->lock);
Harry Yang755a34b2016-11-01 01:18:51 -07004192 return;
4193
4194rerun:
4195 schedule_work(&chg->rdstd_cc2_detach_work);
4196}
4197
Nicholas Troastb11015f2017-01-17 17:56:45 -08004198static void smblib_otg_oc_exit(struct smb_charger *chg, bool success)
4199{
4200 int rc;
4201
4202 chg->otg_attempts = 0;
4203 if (!success) {
4204 smblib_err(chg, "OTG soft start failed\n");
4205 chg->otg_en = false;
4206 }
4207
4208 smblib_dbg(chg, PR_OTG, "enabling VBUS < 1V check\n");
4209 rc = smblib_masked_write(chg, OTG_CFG_REG,
4210 QUICKSTART_OTG_FASTROLESWAP_BIT, 0);
4211 if (rc < 0)
4212 smblib_err(chg, "Couldn't enable VBUS < 1V check rc=%d\n", rc);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004213}
4214
4215#define MAX_OC_FALLING_TRIES 10
4216static void smblib_otg_oc_work(struct work_struct *work)
4217{
4218 struct smb_charger *chg = container_of(work, struct smb_charger,
4219 otg_oc_work);
4220 int rc, i;
4221 u8 stat;
4222
4223 if (!chg->vbus_vreg || !chg->vbus_vreg->rdev)
4224 return;
4225
4226 smblib_err(chg, "over-current detected on VBUS\n");
4227 mutex_lock(&chg->otg_oc_lock);
4228 if (!chg->otg_en)
4229 goto unlock;
4230
4231 smblib_dbg(chg, PR_OTG, "disabling VBUS < 1V check\n");
4232 smblib_masked_write(chg, OTG_CFG_REG,
4233 QUICKSTART_OTG_FASTROLESWAP_BIT,
4234 QUICKSTART_OTG_FASTROLESWAP_BIT);
4235
4236 /*
4237 * If 500ms has passed and another over-current interrupt has not
4238 * triggered then it is likely that the software based soft start was
4239 * successful and the VBUS < 1V restriction should be re-enabled.
4240 */
4241 schedule_delayed_work(&chg->otg_ss_done_work, msecs_to_jiffies(500));
4242
4243 rc = _smblib_vbus_regulator_disable(chg->vbus_vreg->rdev);
4244 if (rc < 0) {
4245 smblib_err(chg, "Couldn't disable VBUS rc=%d\n", rc);
4246 goto unlock;
4247 }
4248
4249 if (++chg->otg_attempts > OTG_MAX_ATTEMPTS) {
4250 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4251 smblib_err(chg, "OTG failed to enable after %d attempts\n",
4252 chg->otg_attempts - 1);
4253 smblib_otg_oc_exit(chg, false);
4254 goto unlock;
4255 }
4256
4257 /*
4258 * The real time status should go low within 10ms. Poll every 1-2ms to
4259 * minimize the delay when re-enabling OTG.
4260 */
4261 for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) {
4262 usleep_range(1000, 2000);
4263 rc = smblib_read(chg, OTG_BASE + INT_RT_STS_OFFSET, &stat);
4264 if (rc >= 0 && !(stat & OTG_OVERCURRENT_RT_STS_BIT))
4265 break;
4266 }
4267
4268 if (i >= MAX_OC_FALLING_TRIES) {
4269 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4270 smblib_err(chg, "OTG OC did not fall after %dms\n",
4271 2 * MAX_OC_FALLING_TRIES);
4272 smblib_otg_oc_exit(chg, false);
4273 goto unlock;
4274 }
4275
4276 smblib_dbg(chg, PR_OTG, "OTG OC fell after %dms\n", 2 * i + 1);
4277 rc = _smblib_vbus_regulator_enable(chg->vbus_vreg->rdev);
4278 if (rc < 0) {
4279 smblib_err(chg, "Couldn't enable VBUS rc=%d\n", rc);
4280 goto unlock;
4281 }
4282
4283unlock:
4284 mutex_unlock(&chg->otg_oc_lock);
4285}
4286
4287static void smblib_vconn_oc_work(struct work_struct *work)
4288{
4289 struct smb_charger *chg = container_of(work, struct smb_charger,
4290 vconn_oc_work);
4291 int rc, i;
4292 u8 stat;
4293
Ashay Jaiswal15edce42017-03-31 23:29:58 +05304294 if (chg->micro_usb_mode)
4295 return;
4296
Nicholas Troastb11015f2017-01-17 17:56:45 -08004297 smblib_err(chg, "over-current detected on VCONN\n");
4298 if (!chg->vconn_vreg || !chg->vconn_vreg->rdev)
4299 return;
4300
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07004301 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004302 rc = _smblib_vconn_regulator_disable(chg->vconn_vreg->rdev);
4303 if (rc < 0) {
4304 smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc);
4305 goto unlock;
4306 }
4307
4308 if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
4309 smblib_err(chg, "VCONN failed to enable after %d attempts\n",
4310 chg->otg_attempts - 1);
4311 chg->vconn_en = false;
4312 chg->vconn_attempts = 0;
4313 goto unlock;
4314 }
4315
4316 /*
4317 * The real time status should go low within 10ms. Poll every 1-2ms to
4318 * minimize the delay when re-enabling OTG.
4319 */
4320 for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) {
4321 usleep_range(1000, 2000);
4322 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
4323 if (rc >= 0 && !(stat & TYPEC_VCONN_OVERCURR_STATUS_BIT))
4324 break;
4325 }
4326
4327 if (i >= MAX_OC_FALLING_TRIES) {
4328 smblib_err(chg, "VCONN OC did not fall after %dms\n",
4329 2 * MAX_OC_FALLING_TRIES);
4330 chg->vconn_en = false;
4331 chg->vconn_attempts = 0;
4332 goto unlock;
4333 }
4334
4335 smblib_dbg(chg, PR_OTG, "VCONN OC fell after %dms\n", 2 * i + 1);
4336 if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
4337 smblib_err(chg, "VCONN failed to enable after %d attempts\n",
4338 chg->vconn_attempts - 1);
4339 chg->vconn_en = false;
4340 goto unlock;
4341 }
4342
4343 rc = _smblib_vconn_regulator_enable(chg->vconn_vreg->rdev);
4344 if (rc < 0) {
4345 smblib_err(chg, "Couldn't enable VCONN rc=%d\n", rc);
4346 goto unlock;
4347 }
4348
4349unlock:
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07004350 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004351}
4352
4353static void smblib_otg_ss_done_work(struct work_struct *work)
4354{
4355 struct smb_charger *chg = container_of(work, struct smb_charger,
4356 otg_ss_done_work.work);
4357 int rc;
4358 bool success = false;
4359 u8 stat;
4360
4361 mutex_lock(&chg->otg_oc_lock);
4362 rc = smblib_read(chg, OTG_STATUS_REG, &stat);
4363 if (rc < 0)
4364 smblib_err(chg, "Couldn't read OTG status rc=%d\n", rc);
4365 else if (stat & BOOST_SOFTSTART_DONE_BIT)
4366 success = true;
4367
4368 smblib_otg_oc_exit(chg, success);
4369 mutex_unlock(&chg->otg_oc_lock);
4370}
4371
Ashay Jaiswal4d825782017-02-18 10:11:34 +05304372static void smblib_icl_change_work(struct work_struct *work)
4373{
4374 struct smb_charger *chg = container_of(work, struct smb_charger,
4375 icl_change_work.work);
4376 int rc, settled_ua;
4377
4378 rc = smblib_get_charge_param(chg, &chg->param.icl_stat, &settled_ua);
4379 if (rc < 0) {
4380 smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
4381 return;
4382 }
4383
4384 power_supply_changed(chg->usb_main_psy);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05304385
4386 smblib_dbg(chg, PR_INTERRUPT, "icl_settled=%d\n", settled_ua);
4387}
4388
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304389static void smblib_pl_enable_work(struct work_struct *work)
4390{
4391 struct smb_charger *chg = container_of(work, struct smb_charger,
4392 pl_enable_work.work);
4393
4394 smblib_dbg(chg, PR_PARALLEL, "timer expired, enabling parallel\n");
4395 vote(chg->pl_disable_votable, PL_DELAY_VOTER, false, 0);
4396 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
4397}
4398
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004399static void smblib_legacy_detection_work(struct work_struct *work)
4400{
4401 struct smb_charger *chg = container_of(work, struct smb_charger,
4402 legacy_detection_work);
4403 int rc;
4404 u8 stat;
4405 bool legacy, rp_high;
4406
4407 mutex_lock(&chg->lock);
4408 chg->typec_en_dis_active = 1;
4409 smblib_dbg(chg, PR_MISC, "running legacy unknown workaround\n");
4410 rc = smblib_masked_write(chg,
4411 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4412 TYPEC_DISABLE_CMD_BIT,
4413 TYPEC_DISABLE_CMD_BIT);
4414 if (rc < 0)
4415 smblib_err(chg, "Couldn't disable type-c rc=%d\n", rc);
4416
4417 /* wait for the adapter to turn off VBUS */
4418 msleep(500);
4419
4420 rc = smblib_masked_write(chg,
4421 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4422 TYPEC_DISABLE_CMD_BIT, 0);
4423 if (rc < 0)
4424 smblib_err(chg, "Couldn't enable type-c rc=%d\n", rc);
4425
4426 /* wait for type-c detection to complete */
4427 msleep(100);
4428
4429 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat);
4430 if (rc < 0) {
4431 smblib_err(chg, "Couldn't read typec stat5 rc = %d\n", rc);
4432 goto unlock;
4433 }
4434
4435 chg->typec_legacy_valid = true;
4436 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
4437 legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT;
Nicholas Troaste1932e42017-04-12 12:38:18 -07004438 rp_high = chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004439 if (!legacy || !rp_high)
4440 vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
4441 false, 0);
4442
4443unlock:
4444 chg->typec_en_dis_active = 0;
Nicholas Troast6439e172017-06-02 14:45:39 -07004445 smblib_usb_typec_change(chg);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004446 mutex_unlock(&chg->lock);
4447}
4448
Harry Yangba874ce2016-08-19 14:17:01 -07004449static int smblib_create_votables(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07004450{
4451 int rc = 0;
4452
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304453 chg->fcc_votable = find_votable("FCC");
Harry Yang0c35ff62017-04-06 00:02:30 -07004454 if (chg->fcc_votable == NULL) {
4455 rc = -EINVAL;
4456 smblib_err(chg, "Couldn't find FCC votable rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304457 return rc;
4458 }
4459
4460 chg->fv_votable = find_votable("FV");
Harry Yang0c35ff62017-04-06 00:02:30 -07004461 if (chg->fv_votable == NULL) {
4462 rc = -EINVAL;
4463 smblib_err(chg, "Couldn't find FV votable rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304464 return rc;
4465 }
4466
Ashay Jaiswalae1586d2017-03-22 23:18:51 +05304467 chg->usb_icl_votable = find_votable("USB_ICL");
4468 if (!chg->usb_icl_votable) {
Harry Yang0c35ff62017-04-06 00:02:30 -07004469 rc = -EINVAL;
4470 smblib_err(chg, "Couldn't find USB_ICL votable rc=%d\n", rc);
Ashay Jaiswalae1586d2017-03-22 23:18:51 +05304471 return rc;
4472 }
4473
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304474 chg->pl_disable_votable = find_votable("PL_DISABLE");
Harry Yang0c35ff62017-04-06 00:02:30 -07004475 if (chg->pl_disable_votable == NULL) {
4476 rc = -EINVAL;
4477 smblib_err(chg, "Couldn't find votable PL_DISABLE rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304478 return rc;
4479 }
Abhijeet Dharmapurikar38ef1422017-05-18 15:37:56 -07004480
4481 chg->pl_enable_votable_indirect = find_votable("PL_ENABLE_INDIRECT");
4482 if (chg->pl_enable_votable_indirect == NULL) {
4483 rc = -EINVAL;
4484 smblib_err(chg,
4485 "Couldn't find votable PL_ENABLE_INDIRECT rc=%d\n",
4486 rc);
4487 return rc;
4488 }
4489
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304490 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304491
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004492 chg->dc_suspend_votable = create_votable("DC_SUSPEND", VOTE_SET_ANY,
4493 smblib_dc_suspend_vote_callback,
4494 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07004495 if (IS_ERR(chg->dc_suspend_votable)) {
4496 rc = PTR_ERR(chg->dc_suspend_votable);
4497 return rc;
4498 }
4499
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004500 chg->dc_icl_votable = create_votable("DC_ICL", VOTE_MIN,
4501 smblib_dc_icl_vote_callback,
4502 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07004503 if (IS_ERR(chg->dc_icl_votable)) {
4504 rc = PTR_ERR(chg->dc_icl_votable);
4505 return rc;
4506 }
4507
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07004508 chg->pd_disallowed_votable_indirect
4509 = create_votable("PD_DISALLOWED_INDIRECT", VOTE_SET_ANY,
4510 smblib_pd_disallowed_votable_indirect_callback, chg);
4511 if (IS_ERR(chg->pd_disallowed_votable_indirect)) {
4512 rc = PTR_ERR(chg->pd_disallowed_votable_indirect);
4513 return rc;
4514 }
4515
4516 chg->pd_allowed_votable = create_votable("PD_ALLOWED",
4517 VOTE_SET_ANY, NULL, NULL);
Nicholas Troast34db5032016-03-28 12:26:44 -07004518 if (IS_ERR(chg->pd_allowed_votable)) {
4519 rc = PTR_ERR(chg->pd_allowed_votable);
4520 return rc;
4521 }
4522
Harry Yang223c6282016-06-14 15:48:36 -07004523 chg->awake_votable = create_votable("AWAKE", VOTE_SET_ANY,
4524 smblib_awake_vote_callback,
4525 chg);
4526 if (IS_ERR(chg->awake_votable)) {
4527 rc = PTR_ERR(chg->awake_votable);
4528 return rc;
4529 }
4530
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07004531 chg->chg_disable_votable = create_votable("CHG_DISABLE", VOTE_SET_ANY,
4532 smblib_chg_disable_vote_callback,
4533 chg);
4534 if (IS_ERR(chg->chg_disable_votable)) {
4535 rc = PTR_ERR(chg->chg_disable_votable);
4536 return rc;
4537 }
4538
Harry Yangaba1f5f2016-09-28 10:47:29 -07004539
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05304540 chg->hvdcp_disable_votable_indirect = create_votable(
4541 "HVDCP_DISABLE_INDIRECT",
4542 VOTE_SET_ANY,
4543 smblib_hvdcp_disable_indirect_vote_callback,
4544 chg);
4545 if (IS_ERR(chg->hvdcp_disable_votable_indirect)) {
4546 rc = PTR_ERR(chg->hvdcp_disable_votable_indirect);
4547 return rc;
4548 }
4549
4550 chg->hvdcp_enable_votable = create_votable("HVDCP_ENABLE",
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07004551 VOTE_SET_ANY,
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05304552 smblib_hvdcp_enable_vote_callback,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07004553 chg);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05304554 if (IS_ERR(chg->hvdcp_enable_votable)) {
4555 rc = PTR_ERR(chg->hvdcp_enable_votable);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07004556 return rc;
4557 }
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07004558
4559 chg->apsd_disable_votable = create_votable("APSD_DISABLE",
4560 VOTE_SET_ANY,
4561 smblib_apsd_disable_vote_callback,
4562 chg);
4563 if (IS_ERR(chg->apsd_disable_votable)) {
4564 rc = PTR_ERR(chg->apsd_disable_votable);
4565 return rc;
4566 }
4567
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05304568 chg->hvdcp_hw_inov_dis_votable = create_votable("HVDCP_HW_INOV_DIS",
4569 VOTE_SET_ANY,
4570 smblib_hvdcp_hw_inov_dis_vote_callback,
4571 chg);
4572 if (IS_ERR(chg->hvdcp_hw_inov_dis_votable)) {
4573 rc = PTR_ERR(chg->hvdcp_hw_inov_dis_votable);
4574 return rc;
4575 }
4576
Harry Yang4bf7d962017-03-13 16:51:43 -07004577 chg->usb_irq_enable_votable = create_votable("USB_IRQ_DISABLE",
4578 VOTE_SET_ANY,
4579 smblib_usb_irq_enable_vote_callback,
4580 chg);
4581 if (IS_ERR(chg->usb_irq_enable_votable)) {
4582 rc = PTR_ERR(chg->usb_irq_enable_votable);
4583 return rc;
4584 }
4585
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004586 chg->typec_irq_disable_votable = create_votable("TYPEC_IRQ_DISABLE",
4587 VOTE_SET_ANY,
4588 smblib_typec_irq_disable_vote_callback,
4589 chg);
4590 if (IS_ERR(chg->typec_irq_disable_votable)) {
4591 rc = PTR_ERR(chg->typec_irq_disable_votable);
4592 return rc;
4593 }
4594
Nicholas Troast320839e2016-06-03 10:18:00 -07004595 return rc;
4596}
4597
Harry Yangba874ce2016-08-19 14:17:01 -07004598static void smblib_destroy_votables(struct smb_charger *chg)
4599{
Harry Yangba874ce2016-08-19 14:17:01 -07004600 if (chg->dc_suspend_votable)
4601 destroy_votable(chg->dc_suspend_votable);
Harry Yangba874ce2016-08-19 14:17:01 -07004602 if (chg->usb_icl_votable)
4603 destroy_votable(chg->usb_icl_votable);
4604 if (chg->dc_icl_votable)
4605 destroy_votable(chg->dc_icl_votable);
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07004606 if (chg->pd_disallowed_votable_indirect)
4607 destroy_votable(chg->pd_disallowed_votable_indirect);
Harry Yangba874ce2016-08-19 14:17:01 -07004608 if (chg->pd_allowed_votable)
4609 destroy_votable(chg->pd_allowed_votable);
4610 if (chg->awake_votable)
4611 destroy_votable(chg->awake_votable);
Harry Yangaba1f5f2016-09-28 10:47:29 -07004612 if (chg->chg_disable_votable)
4613 destroy_votable(chg->chg_disable_votable);
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07004614 if (chg->apsd_disable_votable)
4615 destroy_votable(chg->apsd_disable_votable);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05304616 if (chg->hvdcp_hw_inov_dis_votable)
4617 destroy_votable(chg->hvdcp_hw_inov_dis_votable);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004618 if (chg->typec_irq_disable_votable)
4619 destroy_votable(chg->typec_irq_disable_votable);
Harry Yangba874ce2016-08-19 14:17:01 -07004620}
4621
4622static void smblib_iio_deinit(struct smb_charger *chg)
4623{
4624 if (!IS_ERR_OR_NULL(chg->iio.temp_chan))
4625 iio_channel_release(chg->iio.temp_chan);
4626 if (!IS_ERR_OR_NULL(chg->iio.temp_max_chan))
4627 iio_channel_release(chg->iio.temp_max_chan);
4628 if (!IS_ERR_OR_NULL(chg->iio.usbin_i_chan))
4629 iio_channel_release(chg->iio.usbin_i_chan);
4630 if (!IS_ERR_OR_NULL(chg->iio.usbin_v_chan))
4631 iio_channel_release(chg->iio.usbin_v_chan);
Nicholas Troast7dbcad22016-10-05 13:30:18 -07004632 if (!IS_ERR_OR_NULL(chg->iio.batt_i_chan))
4633 iio_channel_release(chg->iio.batt_i_chan);
Harry Yangba874ce2016-08-19 14:17:01 -07004634}
4635
Nicholas Troast320839e2016-06-03 10:18:00 -07004636int smblib_init(struct smb_charger *chg)
4637{
4638 int rc = 0;
4639
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004640 mutex_init(&chg->lock);
Nicholas Troast320839e2016-06-03 10:18:00 -07004641 mutex_init(&chg->write_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004642 mutex_init(&chg->otg_oc_lock);
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07004643 mutex_init(&chg->vconn_oc_lock);
Harry Yangfe913842016-08-10 12:27:28 -07004644 INIT_WORK(&chg->bms_update_work, bms_update_work);
Harry Yang755a34b2016-11-01 01:18:51 -07004645 INIT_WORK(&chg->rdstd_cc2_detach_work, rdstd_cc2_detach_work);
Nicholas Troast320839e2016-06-03 10:18:00 -07004646 INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work);
Harry Yangfe913842016-08-10 12:27:28 -07004647 INIT_DELAYED_WORK(&chg->step_soc_req_work, step_soc_req_work);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004648 INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004649 INIT_WORK(&chg->otg_oc_work, smblib_otg_oc_work);
4650 INIT_WORK(&chg->vconn_oc_work, smblib_vconn_oc_work);
4651 INIT_DELAYED_WORK(&chg->otg_ss_done_work, smblib_otg_ss_done_work);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05304652 INIT_DELAYED_WORK(&chg->icl_change_work, smblib_icl_change_work);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304653 INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004654 INIT_WORK(&chg->legacy_detection_work, smblib_legacy_detection_work);
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05304655 INIT_DELAYED_WORK(&chg->uusb_otg_work, smblib_uusb_otg_work);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05304656 INIT_DELAYED_WORK(&chg->bb_removal_work, smblib_bb_removal_work);
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07004657 chg->fake_capacity = -EINVAL;
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07004658 chg->fake_input_current_limited = -EINVAL;
Nicholas Troast320839e2016-06-03 10:18:00 -07004659
4660 switch (chg->mode) {
4661 case PARALLEL_MASTER:
Harry Yang0c35ff62017-04-06 00:02:30 -07004662 rc = qcom_batt_init();
4663 if (rc < 0) {
4664 smblib_err(chg, "Couldn't init qcom_batt_init rc=%d\n",
4665 rc);
4666 return rc;
4667 }
4668
Nicholas Troast320839e2016-06-03 10:18:00 -07004669 rc = smblib_create_votables(chg);
4670 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004671 smblib_err(chg, "Couldn't create votables rc=%d\n",
Nicholas Troast320839e2016-06-03 10:18:00 -07004672 rc);
Harry Yang58a9e7a2016-06-23 14:54:43 -07004673 return rc;
Nicholas Troast320839e2016-06-03 10:18:00 -07004674 }
Harry Yang58a9e7a2016-06-23 14:54:43 -07004675
Harry Yang5e1a5222016-07-26 15:16:04 -07004676 rc = smblib_register_notifier(chg);
4677 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004678 smblib_err(chg,
Harry Yang5e1a5222016-07-26 15:16:04 -07004679 "Couldn't register notifier rc=%d\n", rc);
4680 return rc;
Harry Yang58a9e7a2016-06-23 14:54:43 -07004681 }
4682
Harry Yang995b7422016-08-29 16:06:50 -07004683 chg->bms_psy = power_supply_get_by_name("bms");
Ashay Jaiswal8afedfc2017-02-03 11:18:22 +05304684 chg->pl.psy = power_supply_get_by_name("parallel");
Nicholas Troast320839e2016-06-03 10:18:00 -07004685 break;
4686 case PARALLEL_SLAVE:
4687 break;
4688 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004689 smblib_err(chg, "Unsupported mode %d\n", chg->mode);
Nicholas Troast320839e2016-06-03 10:18:00 -07004690 return -EINVAL;
4691 }
4692
4693 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07004694}
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004695
4696int smblib_deinit(struct smb_charger *chg)
4697{
Harry Yangba874ce2016-08-19 14:17:01 -07004698 switch (chg->mode) {
4699 case PARALLEL_MASTER:
Harry Yang0c35ff62017-04-06 00:02:30 -07004700 cancel_work_sync(&chg->bms_update_work);
4701 cancel_work_sync(&chg->rdstd_cc2_detach_work);
4702 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
4703 cancel_delayed_work_sync(&chg->step_soc_req_work);
4704 cancel_delayed_work_sync(&chg->clear_hdc_work);
4705 cancel_work_sync(&chg->otg_oc_work);
4706 cancel_work_sync(&chg->vconn_oc_work);
4707 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4708 cancel_delayed_work_sync(&chg->icl_change_work);
4709 cancel_delayed_work_sync(&chg->pl_enable_work);
4710 cancel_work_sync(&chg->legacy_detection_work);
Ashay Jaiswal1bf41332017-05-03 15:10:25 +05304711 cancel_delayed_work_sync(&chg->uusb_otg_work);
Anirudh Ghayal36feefe2017-05-26 09:41:25 +05304712 cancel_delayed_work_sync(&chg->bb_removal_work);
Harry Yangba874ce2016-08-19 14:17:01 -07004713 power_supply_unreg_notifier(&chg->nb);
4714 smblib_destroy_votables(chg);
Harry Yang0c35ff62017-04-06 00:02:30 -07004715 qcom_batt_deinit();
Harry Yangba874ce2016-08-19 14:17:01 -07004716 break;
4717 case PARALLEL_SLAVE:
4718 break;
4719 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004720 smblib_err(chg, "Unsupported mode %d\n", chg->mode);
Harry Yangba874ce2016-08-19 14:17:01 -07004721 return -EINVAL;
4722 }
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004723
Harry Yangba874ce2016-08-19 14:17:01 -07004724 smblib_iio_deinit(chg);
Harry Yang5e1a5222016-07-26 15:16:04 -07004725
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004726 return 0;
4727}