blob: 69d509ebc01d724bf8b22e3ee08cc160f18bdb71 [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,
263 .pst = POWER_SUPPLY_TYPE_USB_DCP
264 },
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;
632
Ashay Jaiswalc0361672017-03-21 12:24:16 +0530633 cancel_delayed_work_sync(&chg->pl_enable_work);
634 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
635 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
636
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530637 /* reset both usbin current and voltage votes */
638 vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
639 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530640
641 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
642
Ashay Jaiswal67ec7072017-02-16 14:14:58 +0530643 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
644 /* re-enable AUTH_IRQ_EN_CFG_BIT */
645 rc = smblib_masked_write(chg,
646 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
647 AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
648 if (rc < 0)
649 smblib_err(chg,
650 "Couldn't enable QC auth setting rc=%d\n", rc);
651 }
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530652
653 /* reconfigure allowed voltage for HVDCP */
Ashay Jaiswalb3101012017-03-01 10:18:04 +0530654 rc = smblib_set_adapter_allowance(chg,
655 USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530656 if (rc < 0)
657 smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
658 rc);
659
660 chg->voltage_min_uv = MICRO_5V;
661 chg->voltage_max_uv = MICRO_5V;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +0530662 chg->usb_icl_delta_ua = 0;
663 chg->pulse_cnt = 0;
Ashay Jaiswal8507aa52017-04-14 09:42:32 +0530664 chg->uusb_apsd_rerun_done = false;
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530665
666 /* clear USB ICL vote for USB_PSY_VOTER */
667 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
668 if (rc < 0)
669 smblib_err(chg, "Couldn't un-vote for USB ICL rc=%d\n", rc);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -0800670
671 /* clear USB ICL vote for DCP_VOTER */
672 rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
673 if (rc < 0)
674 smblib_err(chg,
675 "Couldn't un-vote DCP from USB ICL rc=%d\n", rc);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530676}
677
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530678void smblib_suspend_on_debug_battery(struct smb_charger *chg)
679{
680 int rc;
681 union power_supply_propval val;
682
Ashay Jaiswalda8669b2017-02-10 23:24:23 +0530683 if (!chg->suspend_input_on_debug_batt)
684 return;
685
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530686 rc = power_supply_get_property(chg->bms_psy,
687 POWER_SUPPLY_PROP_DEBUG_BATTERY, &val);
688 if (rc < 0) {
689 smblib_err(chg, "Couldn't get debug battery prop rc=%d\n", rc);
690 return;
691 }
692
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800693 vote(chg->usb_icl_votable, DEBUG_BOARD_VOTER, val.intval, 0);
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530694 vote(chg->dc_suspend_votable, DEBUG_BOARD_VOTER, val.intval, 0);
695 if (val.intval)
696 pr_info("Input suspended: Fake battery\n");
697}
698
Abhijeet Dharmapurikar9dd61292017-01-25 16:40:08 -0800699int smblib_rerun_apsd_if_required(struct smb_charger *chg)
700{
Abhijeet Dharmapurikar9dd61292017-01-25 16:40:08 -0800701 union power_supply_propval val;
702 int rc;
703
704 rc = smblib_get_prop_usb_present(chg, &val);
705 if (rc < 0) {
706 smblib_err(chg, "Couldn't get usb present rc = %d\n", rc);
707 return rc;
708 }
709
710 if (!val.intval)
711 return 0;
712
Abhijeet Dharmapurikar025e63a2017-02-24 14:06:22 -0800713 /* fetch the DPDM regulator */
714 if (!chg->dpdm_reg && of_get_property(chg->dev->of_node,
715 "dpdm-supply", NULL)) {
716 chg->dpdm_reg = devm_regulator_get(chg->dev, "dpdm");
717 if (IS_ERR(chg->dpdm_reg)) {
718 smblib_err(chg, "Couldn't get dpdm regulator rc=%ld\n",
719 PTR_ERR(chg->dpdm_reg));
720 chg->dpdm_reg = NULL;
721 }
Abhijeet Dharmapurikar9dd61292017-01-25 16:40:08 -0800722 }
723
Abhijeet Dharmapurikar025e63a2017-02-24 14:06:22 -0800724 if (chg->dpdm_reg && !regulator_is_enabled(chg->dpdm_reg)) {
725 smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n");
726 rc = regulator_enable(chg->dpdm_reg);
727 if (rc < 0)
728 smblib_err(chg, "Couldn't enable dpdm regulator rc=%d\n",
729 rc);
730 }
731
Ashay Jaiswal8507aa52017-04-14 09:42:32 +0530732 chg->uusb_apsd_rerun_done = true;
Abhijeet Dharmapurikar025e63a2017-02-24 14:06:22 -0800733 smblib_rerun_apsd(chg);
734
Abhijeet Dharmapurikar9dd61292017-01-25 16:40:08 -0800735 return 0;
736}
737
Ashay Jaiswal6d308da2017-02-18 09:59:23 +0530738static int smblib_get_pulse_cnt(struct smb_charger *chg, int *count)
739{
740 int rc;
741 u8 val[2];
742
743 switch (chg->smb_version) {
744 case PMI8998_SUBTYPE:
745 rc = smblib_read(chg, QC_PULSE_COUNT_STATUS_REG, val);
746 if (rc) {
747 pr_err("failed to read QC_PULSE_COUNT_STATUS_REG rc=%d\n",
748 rc);
749 return rc;
750 }
751 *count = val[0] & QC_PULSE_COUNT_MASK;
752 break;
753 case PM660_SUBTYPE:
754 rc = smblib_multibyte_read(chg,
755 QC_PULSE_COUNT_STATUS_1_REG, val, 2);
756 if (rc) {
757 pr_err("failed to read QC_PULSE_COUNT_STATUS_1_REG rc=%d\n",
758 rc);
759 return rc;
760 }
761 *count = (val[1] << 8) | val[0];
762 break;
763 default:
764 smblib_dbg(chg, PR_PARALLEL, "unknown SMB chip %d\n",
765 chg->smb_version);
766 return -EINVAL;
767 }
768
769 return 0;
770}
771
Nicholas Troastbb76a142016-09-23 11:23:23 -0700772#define USBIN_25MA 25000
773#define USBIN_100MA 100000
774#define USBIN_150MA 150000
775#define USBIN_500MA 500000
776#define USBIN_900MA 900000
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800777
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800778static int set_sdp_current(struct smb_charger *chg, int icl_ua)
Nicholas Troast34db5032016-03-28 12:26:44 -0700779{
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800780 int rc;
781 u8 icl_options;
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700782
Nicholas Troastbb76a142016-09-23 11:23:23 -0700783 /* power source is SDP */
784 switch (icl_ua) {
785 case USBIN_100MA:
786 /* USB 2.0 100mA */
787 icl_options = 0;
788 break;
789 case USBIN_150MA:
790 /* USB 3.0 150mA */
791 icl_options = CFG_USB3P0_SEL_BIT;
792 break;
793 case USBIN_500MA:
794 /* USB 2.0 500mA */
795 icl_options = USB51_MODE_BIT;
796 break;
797 case USBIN_900MA:
798 /* USB 3.0 900mA */
799 icl_options = CFG_USB3P0_SEL_BIT | USB51_MODE_BIT;
800 break;
801 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700802 smblib_err(chg, "ICL %duA isn't supported for SDP\n", icl_ua);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800803 return -EINVAL;
Nicholas Troastbb76a142016-09-23 11:23:23 -0700804 }
Nicholas Troast34db5032016-03-28 12:26:44 -0700805
Nicholas Troastbb76a142016-09-23 11:23:23 -0700806 rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800807 CFG_USB3P0_SEL_BIT | USB51_MODE_BIT, icl_options);
Nicholas Troast34db5032016-03-28 12:26:44 -0700808 if (rc < 0) {
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800809 smblib_err(chg, "Couldn't set ICL options rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -0700810 return rc;
811 }
812
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800813 return rc;
814}
815
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700816static int get_sdp_current(struct smb_charger *chg, int *icl_ua)
817{
818 int rc;
819 u8 icl_options;
820 bool usb3 = false;
821
822 rc = smblib_read(chg, USBIN_ICL_OPTIONS_REG, &icl_options);
823 if (rc < 0) {
824 smblib_err(chg, "Couldn't get ICL options rc=%d\n", rc);
825 return rc;
826 }
827
828 usb3 = (icl_options & CFG_USB3P0_SEL_BIT);
829
830 if (icl_options & USB51_MODE_BIT)
831 *icl_ua = usb3 ? USBIN_900MA : USBIN_500MA;
832 else
833 *icl_ua = usb3 ? USBIN_150MA : USBIN_100MA;
834
835 return rc;
836}
837
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530838int smblib_set_icl_current(struct smb_charger *chg, int icl_ua)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800839{
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800840 int rc = 0;
841 bool override;
842 union power_supply_propval pval;
843
844 /* suspend and return if 25mA or less is requested */
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530845 if (icl_ua < USBIN_25MA)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800846 return smblib_set_usb_suspend(chg, true);
847
848 disable_irq_nosync(chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq);
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530849 if (icl_ua == INT_MAX)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800850 goto override_suspend_config;
851
852 rc = smblib_get_prop_typec_mode(chg, &pval);
Nicholas Troast34db5032016-03-28 12:26:44 -0700853 if (rc < 0) {
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800854 smblib_err(chg, "Couldn't get typeC mode rc = %d\n", rc);
855 goto enable_icl_changed_interrupt;
Nicholas Troast34db5032016-03-28 12:26:44 -0700856 }
857
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800858 /* configure current */
859 if (pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
Fenglin Wu80826e02017-04-25 21:45:08 +0800860 && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) {
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800861 rc = set_sdp_current(chg, icl_ua);
862 if (rc < 0) {
863 smblib_err(chg, "Couldn't set SDP ICL rc=%d\n", rc);
864 goto enable_icl_changed_interrupt;
865 }
866 } else {
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -0700867 rc = smblib_set_charge_param(chg, &chg->param.usb_icl, icl_ua);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800868 if (rc < 0) {
869 smblib_err(chg, "Couldn't set HC ICL rc=%d\n", rc);
870 goto enable_icl_changed_interrupt;
871 }
872 }
873
874override_suspend_config:
875 /* determine if override needs to be enforced */
876 override = true;
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530877 if (icl_ua == INT_MAX) {
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800878 /* remove override if no voters - hw defaults is desired */
879 override = false;
880 } else if (pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
Fenglin Wu80826e02017-04-25 21:45:08 +0800881 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800882 /* For std cable with type = SDP never override */
883 override = false;
Fenglin Wu80826e02017-04-25 21:45:08 +0800884 else if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_CDP
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -0700885 && icl_ua == 1500000)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800886 /*
887 * For std cable with type = CDP override only if
888 * current is not 1500mA
889 */
890 override = false;
891 }
892
893 /* enforce override */
894 rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
895 USBIN_MODE_CHG_BIT, override ? USBIN_MODE_CHG_BIT : 0);
896
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800897 rc = smblib_icl_override(chg, override);
898 if (rc < 0) {
899 smblib_err(chg, "Couldn't set ICL override rc=%d\n", rc);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800900 goto enable_icl_changed_interrupt;
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800901 }
902
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -0800903 /* unsuspend after configuring current and override */
904 rc = smblib_set_usb_suspend(chg, false);
905 if (rc < 0) {
906 smblib_err(chg, "Couldn't resume input rc=%d\n", rc);
907 goto enable_icl_changed_interrupt;
908 }
909
910enable_icl_changed_interrupt:
911 enable_irq(chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq);
Nicholas Troast34db5032016-03-28 12:26:44 -0700912 return rc;
913}
914
Abhijeet Dharmapurikareecf5582017-04-24 13:33:07 -0700915int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua)
916{
917 int rc = 0;
918 u8 load_cfg;
919 bool override;
920 union power_supply_propval pval;
921
922 rc = smblib_get_prop_typec_mode(chg, &pval);
923 if (rc < 0) {
924 smblib_err(chg, "Couldn't get typeC mode rc = %d\n", rc);
925 return rc;
926 }
927
928 if ((pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
929 || chg->micro_usb_mode)
930 && (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)) {
931 rc = get_sdp_current(chg, icl_ua);
932 if (rc < 0) {
933 smblib_err(chg, "Couldn't get SDP ICL rc=%d\n", rc);
934 return rc;
935 }
936 } else {
937 rc = smblib_read(chg, USBIN_LOAD_CFG_REG, &load_cfg);
938 if (rc < 0) {
939 smblib_err(chg, "Couldn't get load cfg rc=%d\n", rc);
940 return rc;
941 }
942 override = load_cfg & ICL_OVERRIDE_AFTER_APSD_BIT;
943 if (!override)
944 return INT_MAX;
945
946 /* override is set */
947 rc = smblib_get_charge_param(chg, &chg->param.usb_icl, icl_ua);
948 if (rc < 0) {
949 smblib_err(chg, "Couldn't get HC ICL rc=%d\n", rc);
950 return rc;
951 }
952 }
953
954 return 0;
955}
956
Ashay Jaiswalae1586d2017-03-22 23:18:51 +0530957/*********************
958 * VOTABLE CALLBACKS *
959 *********************/
960
961static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data,
962 int suspend, const char *client)
963{
964 struct smb_charger *chg = data;
965
966 /* resume input if suspend is invalid */
967 if (suspend < 0)
968 suspend = 0;
969
970 return smblib_set_dc_suspend(chg, (bool)suspend);
971}
972
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700973static int smblib_dc_icl_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -0700974 int icl_ua, const char *client)
Nicholas Troast34db5032016-03-28 12:26:44 -0700975{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700976 struct smb_charger *chg = data;
Nicholas Troast34db5032016-03-28 12:26:44 -0700977 int rc = 0;
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700978 bool suspend;
979
980 if (icl_ua < 0) {
981 smblib_dbg(chg, PR_MISC, "No Voter hence suspending\n");
982 icl_ua = 0;
983 }
984
985 suspend = (icl_ua < USBIN_25MA);
986 if (suspend)
987 goto suspend;
Nicholas Troast34db5032016-03-28 12:26:44 -0700988
989 rc = smblib_set_charge_param(chg, &chg->param.dc_icl, icl_ua);
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700990 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700991 smblib_err(chg, "Couldn't set DC input current limit rc=%d\n",
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700992 rc);
993 return rc;
994 }
995
996suspend:
997 rc = vote(chg->dc_suspend_votable, USER_VOTER, suspend, 0);
998 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700999 smblib_err(chg, "Couldn't vote to %s DC rc=%d\n",
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -07001000 suspend ? "suspend" : "resume", rc);
1001 return rc;
1002 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001003 return rc;
1004}
1005
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07001006static int smblib_pd_disallowed_votable_indirect_callback(
1007 struct votable *votable, void *data, int disallowed, const char *client)
1008{
1009 struct smb_charger *chg = data;
1010 int rc;
1011
1012 rc = vote(chg->pd_allowed_votable, PD_DISALLOWED_INDIRECT_VOTER,
1013 !disallowed, 0);
1014
1015 return rc;
1016}
1017
Harry Yang223c6282016-06-14 15:48:36 -07001018static int smblib_awake_vote_callback(struct votable *votable, void *data,
1019 int awake, const char *client)
1020{
1021 struct smb_charger *chg = data;
1022
1023 if (awake)
1024 pm_stay_awake(chg->dev);
1025 else
1026 pm_relax(chg->dev);
1027
1028 return 0;
1029}
1030
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07001031static int smblib_chg_disable_vote_callback(struct votable *votable, void *data,
1032 int chg_disable, const char *client)
1033{
1034 struct smb_charger *chg = data;
1035 int rc;
1036
1037 rc = smblib_masked_write(chg, CHARGING_ENABLE_CMD_REG,
1038 CHARGING_ENABLE_CMD_BIT,
1039 chg_disable ? 0 : CHARGING_ENABLE_CMD_BIT);
1040 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001041 smblib_err(chg, "Couldn't %s charging rc=%d\n",
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07001042 chg_disable ? "disable" : "enable", rc);
1043 return rc;
1044 }
1045
1046 return 0;
1047}
Harry Yangaba1f5f2016-09-28 10:47:29 -07001048
1049static int smblib_pl_enable_indirect_vote_callback(struct votable *votable,
1050 void *data, int chg_enable, const char *client)
1051{
1052 struct smb_charger *chg = data;
1053
1054 vote(chg->pl_disable_votable, PL_INDIRECT_VOTER, !chg_enable, 0);
1055
1056 return 0;
1057}
1058
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301059static int smblib_hvdcp_enable_vote_callback(struct votable *votable,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001060 void *data,
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301061 int hvdcp_enable, const char *client)
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001062{
1063 struct smb_charger *chg = data;
1064 int rc;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301065 u8 val = HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_EN_BIT;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07001066 u8 stat;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301067
1068 /* vote to enable/disable HW autonomous INOV */
1069 vote(chg->hvdcp_hw_inov_dis_votable, client, !hvdcp_enable, 0);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001070
1071 /*
1072 * Disable the autonomous bit and auth bit for disabling hvdcp.
1073 * This ensures only qc 2.0 detection runs but no vbus
1074 * negotiation happens.
1075 */
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301076 if (!hvdcp_enable)
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001077 val = HVDCP_EN_BIT;
1078
1079 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301080 HVDCP_EN_BIT | HVDCP_AUTH_ALG_EN_CFG_BIT,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001081 val);
1082 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001083 smblib_err(chg, "Couldn't %s hvdcp rc=%d\n",
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301084 hvdcp_enable ? "enable" : "disable", rc);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001085 return rc;
1086 }
1087
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07001088 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
1089 if (rc < 0) {
1090 smblib_err(chg, "Couldn't read APSD status rc=%d\n", rc);
1091 return rc;
1092 }
1093
1094 /* re-run APSD if HVDCP was detected */
1095 if (stat & QC_CHARGER_BIT)
1096 smblib_rerun_apsd(chg);
1097
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07001098 return 0;
1099}
1100
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05301101static int smblib_hvdcp_disable_indirect_vote_callback(struct votable *votable,
1102 void *data, int hvdcp_disable, const char *client)
1103{
1104 struct smb_charger *chg = data;
1105
1106 vote(chg->hvdcp_enable_votable, HVDCP_INDIRECT_VOTER,
1107 !hvdcp_disable, 0);
1108
1109 return 0;
1110}
1111
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07001112static int smblib_apsd_disable_vote_callback(struct votable *votable,
1113 void *data,
1114 int apsd_disable, const char *client)
1115{
1116 struct smb_charger *chg = data;
1117 int rc;
1118
Nicholas Troastec4703c2017-01-30 14:52:33 -08001119 if (apsd_disable) {
Nicholas Troastec4703c2017-01-30 14:52:33 -08001120 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1121 AUTO_SRC_DETECT_BIT,
1122 0);
1123 if (rc < 0) {
1124 smblib_err(chg, "Couldn't disable APSD rc=%d\n", rc);
1125 return rc;
1126 }
1127 } else {
1128 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1129 AUTO_SRC_DETECT_BIT,
1130 AUTO_SRC_DETECT_BIT);
1131 if (rc < 0) {
1132 smblib_err(chg, "Couldn't enable APSD rc=%d\n", rc);
1133 return rc;
1134 }
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07001135 }
1136
1137 return 0;
1138}
Nicholas Troast8995a702016-12-05 10:22:22 -08001139
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301140static int smblib_hvdcp_hw_inov_dis_vote_callback(struct votable *votable,
1141 void *data, int disable, const char *client)
1142{
1143 struct smb_charger *chg = data;
1144 int rc;
1145
1146 if (disable) {
1147 /*
1148 * the pulse count register get zeroed when autonomous mode is
1149 * disabled. Track that in variables before disabling
1150 */
1151 rc = smblib_get_pulse_cnt(chg, &chg->pulse_cnt);
1152 if (rc < 0) {
1153 pr_err("failed to read QC_PULSE_COUNT_STATUS_REG rc=%d\n",
1154 rc);
1155 return rc;
1156 }
1157 }
1158
1159 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1160 HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT,
1161 disable ? 0 : HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT);
1162 if (rc < 0) {
1163 smblib_err(chg, "Couldn't %s hvdcp rc=%d\n",
1164 disable ? "disable" : "enable", rc);
1165 return rc;
1166 }
1167
1168 return rc;
1169}
1170
Harry Yang4bf7d962017-03-13 16:51:43 -07001171static int smblib_usb_irq_enable_vote_callback(struct votable *votable,
1172 void *data, int enable, const char *client)
1173{
1174 struct smb_charger *chg = data;
1175
1176 if (!chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq ||
1177 !chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq)
1178 return 0;
1179
1180 if (enable) {
1181 enable_irq(chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq);
1182 enable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
1183 } else {
1184 disable_irq(chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq);
1185 disable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
1186 }
1187
1188 return 0;
1189}
1190
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07001191static int smblib_typec_irq_disable_vote_callback(struct votable *votable,
1192 void *data, int disable, const char *client)
1193{
1194 struct smb_charger *chg = data;
1195
1196 if (!chg->irq_info[TYPE_C_CHANGE_IRQ].irq)
1197 return 0;
1198
1199 if (disable)
1200 disable_irq_nosync(chg->irq_info[TYPE_C_CHANGE_IRQ].irq);
1201 else
1202 enable_irq(chg->irq_info[TYPE_C_CHANGE_IRQ].irq);
1203
1204 return 0;
1205}
1206
Nicholas Troast8995a702016-12-05 10:22:22 -08001207/*******************
1208 * VCONN REGULATOR *
1209 * *****************/
1210
Nicholas Troastb11015f2017-01-17 17:56:45 -08001211#define MAX_OTG_SS_TRIES 2
Nicholas Troast8995a702016-12-05 10:22:22 -08001212static int _smblib_vconn_regulator_enable(struct regulator_dev *rdev)
1213{
1214 struct smb_charger *chg = rdev_get_drvdata(rdev);
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001215 int rc = 0;
1216 u8 val;
Nicholas Troast8995a702016-12-05 10:22:22 -08001217
1218 /*
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001219 * When enabling VCONN using the command register the CC pin must be
1220 * selected. VCONN should be supplied to the inactive CC pin hence using
1221 * the opposite of the CC_ORIENTATION_BIT.
Nicholas Troast8995a702016-12-05 10:22:22 -08001222 */
Nicholas Troastb11015f2017-01-17 17:56:45 -08001223 smblib_dbg(chg, PR_OTG, "enabling VCONN\n");
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07001224 val = chg->typec_status[3] &
1225 CC_ORIENTATION_BIT ? 0 : VCONN_EN_ORIENTATION_BIT;
Nicholas Troast8995a702016-12-05 10:22:22 -08001226 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1227 VCONN_EN_VALUE_BIT | VCONN_EN_ORIENTATION_BIT,
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07001228 VCONN_EN_VALUE_BIT | val);
Nicholas Troast8995a702016-12-05 10:22:22 -08001229 if (rc < 0) {
1230 smblib_err(chg, "Couldn't enable vconn setting rc=%d\n", rc);
1231 return rc;
1232 }
1233
1234 return rc;
1235}
1236
1237int smblib_vconn_regulator_enable(struct regulator_dev *rdev)
1238{
1239 struct smb_charger *chg = rdev_get_drvdata(rdev);
1240 int rc = 0;
1241
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001242 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001243 if (chg->vconn_en)
1244 goto unlock;
1245
1246 rc = _smblib_vconn_regulator_enable(rdev);
1247 if (rc >= 0)
1248 chg->vconn_en = true;
1249
1250unlock:
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001251 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001252 return rc;
1253}
1254
1255static int _smblib_vconn_regulator_disable(struct regulator_dev *rdev)
1256{
1257 struct smb_charger *chg = rdev_get_drvdata(rdev);
1258 int rc = 0;
1259
Nicholas Troastb11015f2017-01-17 17:56:45 -08001260 smblib_dbg(chg, PR_OTG, "disabling VCONN\n");
Nicholas Troast8995a702016-12-05 10:22:22 -08001261 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1262 VCONN_EN_VALUE_BIT, 0);
1263 if (rc < 0)
1264 smblib_err(chg, "Couldn't disable vconn regulator rc=%d\n", rc);
1265
1266 return rc;
1267}
1268
1269int smblib_vconn_regulator_disable(struct regulator_dev *rdev)
1270{
1271 struct smb_charger *chg = rdev_get_drvdata(rdev);
1272 int rc = 0;
1273
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001274 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001275 if (!chg->vconn_en)
1276 goto unlock;
1277
1278 rc = _smblib_vconn_regulator_disable(rdev);
1279 if (rc >= 0)
1280 chg->vconn_en = false;
1281
1282unlock:
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001283 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001284 return rc;
1285}
1286
1287int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev)
1288{
1289 struct smb_charger *chg = rdev_get_drvdata(rdev);
1290 int ret;
1291
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001292 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001293 ret = chg->vconn_en;
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07001294 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001295 return ret;
1296}
1297
Nicholas Troast34db5032016-03-28 12:26:44 -07001298/*****************
1299 * OTG REGULATOR *
1300 *****************/
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301301#define MAX_RETRY 15
1302#define MIN_DELAY_US 2000
1303#define MAX_DELAY_US 9000
Nicholas Troast8995a702016-12-05 10:22:22 -08001304static int _smblib_vbus_regulator_enable(struct regulator_dev *rdev)
Nicholas Troast34db5032016-03-28 12:26:44 -07001305{
1306 struct smb_charger *chg = rdev_get_drvdata(rdev);
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301307 int rc, retry_count = 0, min_delay = MIN_DELAY_US;
1308 u8 stat;
Nicholas Troast34db5032016-03-28 12:26:44 -07001309
Nicholas Troastb11015f2017-01-17 17:56:45 -08001310 smblib_dbg(chg, PR_OTG, "halt 1 in 8 mode\n");
Harry Yang360bd532016-09-26 11:03:22 -07001311 rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
1312 ENG_BUCKBOOST_HALT1_8_MODE_BIT,
1313 ENG_BUCKBOOST_HALT1_8_MODE_BIT);
1314 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001315 smblib_err(chg, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n",
Harry Yang360bd532016-09-26 11:03:22 -07001316 rc);
1317 return rc;
1318 }
1319
Nicholas Troastb11015f2017-01-17 17:56:45 -08001320 smblib_dbg(chg, PR_OTG, "enabling OTG\n");
Harry Yang360bd532016-09-26 11:03:22 -07001321 rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT);
1322 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001323 smblib_err(chg, "Couldn't enable OTG regulator rc=%d\n", rc);
Harry Yang360bd532016-09-26 11:03:22 -07001324 return rc;
1325 }
1326
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301327 if (chg->wa_flags & OTG_WA) {
1328 /* check for softstart */
1329 do {
1330 usleep_range(min_delay, min_delay + 100);
1331 rc = smblib_read(chg, OTG_STATUS_REG, &stat);
1332 if (rc < 0) {
1333 smblib_err(chg,
1334 "Couldn't read OTG status rc=%d\n",
1335 rc);
1336 goto out;
1337 }
1338
1339 if (stat & BOOST_SOFTSTART_DONE_BIT) {
1340 rc = smblib_set_charge_param(chg,
1341 &chg->param.otg_cl, chg->otg_cl_ua);
1342 if (rc < 0)
1343 smblib_err(chg,
1344 "Couldn't set otg limit\n");
1345 break;
1346 }
1347
1348 /* increase the delay for following iterations */
1349 if (retry_count > 5)
1350 min_delay = MAX_DELAY_US;
1351 } while (retry_count++ < MAX_RETRY);
1352
1353 if (retry_count >= MAX_RETRY) {
1354 smblib_dbg(chg, PR_OTG, "Boost Softstart not done\n");
1355 goto out;
1356 }
1357 }
1358
1359 return 0;
1360out:
1361 /* disable OTG if softstart failed */
1362 smblib_write(chg, CMD_OTG_REG, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07001363 return rc;
1364}
1365
Nicholas Troast8995a702016-12-05 10:22:22 -08001366int smblib_vbus_regulator_enable(struct regulator_dev *rdev)
Nicholas Troast34db5032016-03-28 12:26:44 -07001367{
1368 struct smb_charger *chg = rdev_get_drvdata(rdev);
1369 int rc = 0;
1370
Nicholas Troastb11015f2017-01-17 17:56:45 -08001371 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001372 if (chg->otg_en)
1373 goto unlock;
1374
Harry Yanga2fb0e32017-03-22 22:45:25 -07001375 if (!chg->usb_icl_votable) {
1376 chg->usb_icl_votable = find_votable("USB_ICL");
1377
1378 if (!chg->usb_icl_votable)
1379 return -EINVAL;
1380 }
1381 vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, true, 0);
1382
Nicholas Troast8995a702016-12-05 10:22:22 -08001383 rc = _smblib_vbus_regulator_enable(rdev);
1384 if (rc >= 0)
1385 chg->otg_en = true;
1386
1387unlock:
Nicholas Troastb11015f2017-01-17 17:56:45 -08001388 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001389 return rc;
1390}
1391
1392static int _smblib_vbus_regulator_disable(struct regulator_dev *rdev)
1393{
1394 struct smb_charger *chg = rdev_get_drvdata(rdev);
1395 int rc;
Nicholas Troast8995a702016-12-05 10:22:22 -08001396
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301397 if (chg->wa_flags & OTG_WA) {
1398 /* set OTG current limit to minimum value */
1399 rc = smblib_set_charge_param(chg, &chg->param.otg_cl,
1400 chg->param.otg_cl.min_u);
1401 if (rc < 0) {
1402 smblib_err(chg,
1403 "Couldn't set otg current limit rc=%d\n", rc);
1404 return rc;
1405 }
1406 }
1407
Nicholas Troastb11015f2017-01-17 17:56:45 -08001408 smblib_dbg(chg, PR_OTG, "disabling OTG\n");
Harry Yang360bd532016-09-26 11:03:22 -07001409 rc = smblib_write(chg, CMD_OTG_REG, 0);
1410 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001411 smblib_err(chg, "Couldn't disable OTG regulator rc=%d\n", rc);
Harry Yang360bd532016-09-26 11:03:22 -07001412 return rc;
1413 }
1414
Nicholas Troastb11015f2017-01-17 17:56:45 -08001415 smblib_dbg(chg, PR_OTG, "start 1 in 8 mode\n");
Harry Yang360bd532016-09-26 11:03:22 -07001416 rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
1417 ENG_BUCKBOOST_HALT1_8_MODE_BIT, 0);
1418 if (rc < 0) {
Nicholas Troast8995a702016-12-05 10:22:22 -08001419 smblib_err(chg, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n", rc);
Harry Yang360bd532016-09-26 11:03:22 -07001420 return rc;
1421 }
1422
Nicholas Troast8995a702016-12-05 10:22:22 -08001423 return 0;
1424}
Nicholas Troast34db5032016-03-28 12:26:44 -07001425
Nicholas Troast8995a702016-12-05 10:22:22 -08001426int smblib_vbus_regulator_disable(struct regulator_dev *rdev)
1427{
1428 struct smb_charger *chg = rdev_get_drvdata(rdev);
1429 int rc = 0;
1430
Nicholas Troastb11015f2017-01-17 17:56:45 -08001431 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001432 if (!chg->otg_en)
1433 goto unlock;
1434
1435 rc = _smblib_vbus_regulator_disable(rdev);
1436 if (rc >= 0)
1437 chg->otg_en = false;
1438
Harry Yanga2fb0e32017-03-22 22:45:25 -07001439 if (chg->usb_icl_votable)
1440 vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0);
Nicholas Troast8995a702016-12-05 10:22:22 -08001441unlock:
Nicholas Troastb11015f2017-01-17 17:56:45 -08001442 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07001443 return rc;
1444}
1445
1446int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev)
1447{
1448 struct smb_charger *chg = rdev_get_drvdata(rdev);
Nicholas Troast8995a702016-12-05 10:22:22 -08001449 int ret;
Nicholas Troast34db5032016-03-28 12:26:44 -07001450
Nicholas Troastb11015f2017-01-17 17:56:45 -08001451 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001452 ret = chg->otg_en;
Nicholas Troastb11015f2017-01-17 17:56:45 -08001453 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001454 return ret;
Nicholas Troast34db5032016-03-28 12:26:44 -07001455}
1456
1457/********************
1458 * BATT PSY GETTERS *
1459 ********************/
1460
1461int smblib_get_prop_input_suspend(struct smb_charger *chg,
1462 union power_supply_propval *val)
1463{
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08001464 val->intval
1465 = (get_client_vote(chg->usb_icl_votable, USER_VOTER) == 0)
1466 && get_client_vote(chg->dc_suspend_votable, USER_VOTER);
Nicholas Troast34db5032016-03-28 12:26:44 -07001467 return 0;
1468}
1469
1470int smblib_get_prop_batt_present(struct smb_charger *chg,
1471 union power_supply_propval *val)
1472{
1473 int rc;
1474 u8 stat;
1475
1476 rc = smblib_read(chg, BATIF_BASE + INT_RT_STS_OFFSET, &stat);
1477 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001478 smblib_err(chg, "Couldn't read BATIF_INT_RT_STS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07001479 return rc;
1480 }
1481
1482 val->intval = !(stat & (BAT_THERM_OR_ID_MISSING_RT_STS_BIT
1483 | BAT_TERMINAL_MISSING_RT_STS_BIT));
1484
1485 return rc;
1486}
1487
1488int smblib_get_prop_batt_capacity(struct smb_charger *chg,
1489 union power_supply_propval *val)
1490{
Harry Yang5e1a5222016-07-26 15:16:04 -07001491 int rc = -EINVAL;
1492
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07001493 if (chg->fake_capacity >= 0) {
1494 val->intval = chg->fake_capacity;
1495 return 0;
1496 }
1497
Harry Yang5e1a5222016-07-26 15:16:04 -07001498 if (chg->bms_psy)
1499 rc = power_supply_get_property(chg->bms_psy,
1500 POWER_SUPPLY_PROP_CAPACITY, val);
1501 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001502}
1503
1504int smblib_get_prop_batt_status(struct smb_charger *chg,
1505 union power_supply_propval *val)
1506{
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001507 union power_supply_propval pval = {0, };
1508 bool usb_online, dc_online;
Nicholas Troast8cb77552016-09-23 11:50:18 -07001509 u8 stat;
1510 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001511
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001512 rc = smblib_get_prop_usb_online(chg, &pval);
1513 if (rc < 0) {
1514 smblib_err(chg, "Couldn't get usb online property rc=%d\n",
1515 rc);
1516 return rc;
1517 }
1518 usb_online = (bool)pval.intval;
1519
1520 rc = smblib_get_prop_dc_online(chg, &pval);
1521 if (rc < 0) {
1522 smblib_err(chg, "Couldn't get dc online property rc=%d\n",
1523 rc);
1524 return rc;
1525 }
1526 dc_online = (bool)pval.intval;
1527
Nicholas Troast34db5032016-03-28 12:26:44 -07001528 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1529 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001530 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001531 rc);
1532 return rc;
1533 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001534 stat = stat & BATTERY_CHARGER_STATUS_MASK;
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001535
1536 if (!usb_online && !dc_online) {
1537 switch (stat) {
1538 case TERMINATE_CHARGE:
1539 case INHIBIT_CHARGE:
1540 val->intval = POWER_SUPPLY_STATUS_FULL;
1541 break;
1542 default:
1543 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
1544 break;
1545 }
1546 return rc;
1547 }
1548
Nicholas Troast8cb77552016-09-23 11:50:18 -07001549 switch (stat) {
1550 case TRICKLE_CHARGE:
1551 case PRE_CHARGE:
1552 case FAST_CHARGE:
1553 case FULLON_CHARGE:
1554 case TAPER_CHARGE:
Nicholas Troast34db5032016-03-28 12:26:44 -07001555 val->intval = POWER_SUPPLY_STATUS_CHARGING;
Nicholas Troast8cb77552016-09-23 11:50:18 -07001556 break;
1557 case TERMINATE_CHARGE:
1558 case INHIBIT_CHARGE:
1559 val->intval = POWER_SUPPLY_STATUS_FULL;
1560 break;
1561 case DISABLE_CHARGE:
1562 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
1563 break;
1564 default:
1565 val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
1566 break;
1567 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001568
Harry Yang7ecc1a12017-04-06 12:24:56 -07001569 if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
1570 return 0;
1571
Harry Yangc3c28d12017-04-17 16:41:19 -07001572 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_7_REG, &stat);
Harry Yang7ecc1a12017-04-06 12:24:56 -07001573 if (rc < 0) {
1574 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
1575 rc);
1576 return rc;
1577 }
1578
Harry Yangc3c28d12017-04-17 16:41:19 -07001579 stat &= ENABLE_TRICKLE_BIT | ENABLE_PRE_CHARGING_BIT |
1580 ENABLE_FAST_CHARGING_BIT | ENABLE_FULLON_MODE_BIT;
1581 if (!stat)
Harry Yang7ecc1a12017-04-06 12:24:56 -07001582 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
1583
Nicholas Troast8cb77552016-09-23 11:50:18 -07001584 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07001585}
1586
1587int smblib_get_prop_batt_charge_type(struct smb_charger *chg,
1588 union power_supply_propval *val)
1589{
1590 int rc;
1591 u8 stat;
1592
1593 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1594 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001595 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001596 rc);
1597 return rc;
1598 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001599
1600 switch (stat & BATTERY_CHARGER_STATUS_MASK) {
1601 case TRICKLE_CHARGE:
1602 case PRE_CHARGE:
1603 val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1604 break;
1605 case FAST_CHARGE:
1606 case FULLON_CHARGE:
1607 val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
1608 break;
1609 case TAPER_CHARGE:
1610 val->intval = POWER_SUPPLY_CHARGE_TYPE_TAPER;
1611 break;
1612 default:
1613 val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
1614 }
1615
1616 return rc;
1617}
1618
1619int smblib_get_prop_batt_health(struct smb_charger *chg,
1620 union power_supply_propval *val)
1621{
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001622 union power_supply_propval pval;
Nicholas Troast34db5032016-03-28 12:26:44 -07001623 int rc;
1624 u8 stat;
1625
1626 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat);
1627 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001628 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001629 rc);
1630 return rc;
1631 }
1632 smblib_dbg(chg, PR_REGISTER, "BATTERY_CHARGER_STATUS_2 = 0x%02x\n",
1633 stat);
1634
1635 if (stat & CHARGER_ERROR_STATUS_BAT_OV_BIT) {
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001636 rc = smblib_get_prop_batt_voltage_now(chg, &pval);
1637 if (!rc) {
1638 /*
1639 * If Vbatt is within 40mV above Vfloat, then don't
1640 * treat it as overvoltage.
1641 */
1642 if (pval.intval >=
1643 get_effective_result(chg->fv_votable) + 40000) {
1644 val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
1645 smblib_err(chg, "battery over-voltage\n");
1646 goto done;
1647 }
1648 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001649 }
1650
Harry Yang668fc5e2016-07-12 16:51:47 -07001651 if (stat & BAT_TEMP_STATUS_TOO_COLD_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001652 val->intval = POWER_SUPPLY_HEALTH_COLD;
Harry Yang668fc5e2016-07-12 16:51:47 -07001653 else if (stat & BAT_TEMP_STATUS_TOO_HOT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001654 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
Harry Yang668fc5e2016-07-12 16:51:47 -07001655 else if (stat & BAT_TEMP_STATUS_COLD_SOFT_LIMIT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001656 val->intval = POWER_SUPPLY_HEALTH_COOL;
Harry Yang668fc5e2016-07-12 16:51:47 -07001657 else if (stat & BAT_TEMP_STATUS_HOT_SOFT_LIMIT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001658 val->intval = POWER_SUPPLY_HEALTH_WARM;
Harry Yang668fc5e2016-07-12 16:51:47 -07001659 else
Nicholas Troast34db5032016-03-28 12:26:44 -07001660 val->intval = POWER_SUPPLY_HEALTH_GOOD;
Nicholas Troast34db5032016-03-28 12:26:44 -07001661
1662done:
1663 return rc;
1664}
1665
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001666int smblib_get_prop_system_temp_level(struct smb_charger *chg,
1667 union power_supply_propval *val)
1668{
1669 val->intval = chg->system_temp_level;
1670 return 0;
1671}
1672
Abhijeet Dharmapurikaracf32002017-05-11 11:54:17 -07001673int smblib_get_prop_system_temp_level_max(struct smb_charger *chg,
1674 union power_supply_propval *val)
1675{
1676 val->intval = chg->thermal_levels;
1677 return 0;
1678}
1679
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001680int smblib_get_prop_input_current_limited(struct smb_charger *chg,
1681 union power_supply_propval *val)
1682{
1683 u8 stat;
1684 int rc;
1685
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07001686 if (chg->fake_input_current_limited >= 0) {
1687 val->intval = chg->fake_input_current_limited;
1688 return 0;
1689 }
1690
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001691 rc = smblib_read(chg, AICL_STATUS_REG, &stat);
1692 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001693 smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n", rc);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001694 return rc;
1695 }
1696 val->intval = (stat & SOFT_ILIMIT_BIT) || chg->is_hdc;
1697 return 0;
1698}
1699
Nicholas Troast66b21d72016-09-20 15:33:20 -07001700int smblib_get_prop_batt_voltage_now(struct smb_charger *chg,
1701 union power_supply_propval *val)
1702{
1703 int rc;
1704
1705 if (!chg->bms_psy)
1706 return -EINVAL;
1707
1708 rc = power_supply_get_property(chg->bms_psy,
1709 POWER_SUPPLY_PROP_VOLTAGE_NOW, val);
1710 return rc;
1711}
1712
1713int smblib_get_prop_batt_current_now(struct smb_charger *chg,
1714 union power_supply_propval *val)
1715{
1716 int rc;
1717
1718 if (!chg->bms_psy)
1719 return -EINVAL;
1720
1721 rc = power_supply_get_property(chg->bms_psy,
1722 POWER_SUPPLY_PROP_CURRENT_NOW, val);
1723 return rc;
1724}
1725
1726int smblib_get_prop_batt_temp(struct smb_charger *chg,
1727 union power_supply_propval *val)
1728{
1729 int rc;
1730
1731 if (!chg->bms_psy)
1732 return -EINVAL;
1733
1734 rc = power_supply_get_property(chg->bms_psy,
1735 POWER_SUPPLY_PROP_TEMP, val);
1736 return rc;
1737}
1738
Harry Yangbedee332016-08-31 16:14:29 -07001739int smblib_get_prop_step_chg_step(struct smb_charger *chg,
1740 union power_supply_propval *val)
1741{
1742 int rc;
1743 u8 stat;
1744
1745 if (!chg->step_chg_enabled) {
1746 val->intval = -1;
1747 return 0;
1748 }
1749
1750 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1751 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001752 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Harry Yangbedee332016-08-31 16:14:29 -07001753 rc);
1754 return rc;
1755 }
1756
1757 val->intval = (stat & STEP_CHARGING_STATUS_MASK) >>
1758 STEP_CHARGING_STATUS_SHIFT;
1759
1760 return rc;
1761}
1762
Subbaraman Narayanamurthyb491d022016-10-10 20:22:48 -07001763int smblib_get_prop_batt_charge_done(struct smb_charger *chg,
1764 union power_supply_propval *val)
1765{
1766 int rc;
1767 u8 stat;
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",
Subbaraman Narayanamurthyb491d022016-10-10 20:22:48 -07001772 rc);
1773 return rc;
1774 }
1775
1776 stat = stat & BATTERY_CHARGER_STATUS_MASK;
1777 val->intval = (stat == TERMINATE_CHARGE);
1778 return 0;
1779}
1780
Harry Yang40192cb2017-02-25 23:25:17 -08001781int smblib_get_prop_charge_qnovo_enable(struct smb_charger *chg,
1782 union power_supply_propval *val)
1783{
1784 int rc;
1785 u8 stat;
1786
1787 rc = smblib_read(chg, QNOVO_PT_ENABLE_CMD_REG, &stat);
1788 if (rc < 0) {
1789 smblib_err(chg, "Couldn't read QNOVO_PT_ENABLE_CMD rc=%d\n",
1790 rc);
1791 return rc;
1792 }
1793
1794 val->intval = (bool)(stat & QNOVO_PT_ENABLE_CMD_BIT);
1795 return 0;
1796}
1797
Nicholas Troast34db5032016-03-28 12:26:44 -07001798/***********************
1799 * BATTERY PSY SETTERS *
1800 ***********************/
1801
1802int smblib_set_prop_input_suspend(struct smb_charger *chg,
1803 const union power_supply_propval *val)
1804{
1805 int rc;
1806
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08001807 /* vote 0mA when suspended */
1808 rc = vote(chg->usb_icl_votable, USER_VOTER, (bool)val->intval, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07001809 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001810 smblib_err(chg, "Couldn't vote to %s USB rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001811 (bool)val->intval ? "suspend" : "resume", rc);
1812 return rc;
1813 }
1814
1815 rc = vote(chg->dc_suspend_votable, USER_VOTER, (bool)val->intval, 0);
1816 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001817 smblib_err(chg, "Couldn't vote to %s DC rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001818 (bool)val->intval ? "suspend" : "resume", rc);
1819 return rc;
1820 }
1821
Nicholas Troast61ff40f2016-07-08 10:59:22 -07001822 power_supply_changed(chg->batt_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07001823 return rc;
1824}
1825
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07001826int smblib_set_prop_batt_capacity(struct smb_charger *chg,
1827 const union power_supply_propval *val)
1828{
1829 chg->fake_capacity = val->intval;
1830
1831 power_supply_changed(chg->batt_psy);
1832
1833 return 0;
1834}
1835
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001836int smblib_set_prop_system_temp_level(struct smb_charger *chg,
1837 const union power_supply_propval *val)
1838{
1839 if (val->intval < 0)
1840 return -EINVAL;
1841
1842 if (chg->thermal_levels <= 0)
1843 return -EINVAL;
1844
1845 if (val->intval > chg->thermal_levels)
1846 return -EINVAL;
1847
1848 chg->system_temp_level = val->intval;
Ashay Jaiswal147a6c32017-03-28 17:19:47 +05301849 /* disable parallel charge in case of system temp level */
1850 vote(chg->pl_disable_votable, THERMAL_DAEMON_VOTER,
1851 chg->system_temp_level ? true : false, 0);
1852
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001853 if (chg->system_temp_level == chg->thermal_levels)
Harry Yangaba1f5f2016-09-28 10:47:29 -07001854 return vote(chg->chg_disable_votable,
1855 THERMAL_DAEMON_VOTER, true, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001856
Harry Yangaba1f5f2016-09-28 10:47:29 -07001857 vote(chg->chg_disable_votable, THERMAL_DAEMON_VOTER, false, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001858 if (chg->system_temp_level == 0)
Harry Yangaba1f5f2016-09-28 10:47:29 -07001859 return vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, false, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001860
Harry Yangaba1f5f2016-09-28 10:47:29 -07001861 vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, true,
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001862 chg->thermal_mitigation[chg->system_temp_level]);
1863 return 0;
1864}
1865
Harry Yang40192cb2017-02-25 23:25:17 -08001866int smblib_set_prop_charge_qnovo_enable(struct smb_charger *chg,
1867 const union power_supply_propval *val)
1868{
1869 int rc = 0;
1870
1871 rc = smblib_masked_write(chg, QNOVO_PT_ENABLE_CMD_REG,
1872 QNOVO_PT_ENABLE_CMD_BIT,
1873 val->intval ? QNOVO_PT_ENABLE_CMD_BIT : 0);
1874 if (rc < 0) {
1875 dev_err(chg->dev, "Couldn't enable qnovo rc=%d\n", rc);
1876 return rc;
1877 }
1878
1879 return rc;
1880}
1881
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07001882int smblib_set_prop_input_current_limited(struct smb_charger *chg,
1883 const union power_supply_propval *val)
1884{
1885 chg->fake_input_current_limited = val->intval;
1886 return 0;
1887}
1888
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301889int smblib_rerun_aicl(struct smb_charger *chg)
1890{
Nicholas Troast20ae1912017-02-15 10:15:32 -08001891 int rc, settled_icl_ua;
1892 u8 stat;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301893
Nicholas Troast20ae1912017-02-15 10:15:32 -08001894 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
1895 if (rc < 0) {
1896 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
1897 rc);
1898 return rc;
1899 }
1900
1901 /* USB is suspended so skip re-running AICL */
1902 if (stat & USBIN_SUSPEND_STS_BIT)
1903 return rc;
1904
1905 smblib_dbg(chg, PR_MISC, "re-running AICL\n");
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301906 switch (chg->smb_version) {
1907 case PMI8998_SUBTYPE:
Nicholas Troast20ae1912017-02-15 10:15:32 -08001908 rc = smblib_get_charge_param(chg, &chg->param.icl_stat,
1909 &settled_icl_ua);
1910 if (rc < 0) {
1911 smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
1912 return rc;
1913 }
1914
1915 vote(chg->usb_icl_votable, AICL_RERUN_VOTER, true,
1916 max(settled_icl_ua - chg->param.usb_icl.step_u,
1917 chg->param.usb_icl.step_u));
1918 vote(chg->usb_icl_votable, AICL_RERUN_VOTER, false, 0);
1919 break;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301920 case PM660_SUBTYPE:
Nicholas Troast20ae1912017-02-15 10:15:32 -08001921 /*
1922 * Use restart_AICL instead of trigger_AICL as it runs the
1923 * complete AICL instead of starting from the last settled
1924 * value.
1925 */
1926 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG,
1927 RESTART_AICL_BIT, RESTART_AICL_BIT);
1928 if (rc < 0)
1929 smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
1930 rc);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301931 break;
1932 default:
1933 smblib_dbg(chg, PR_PARALLEL, "unknown SMB chip %d\n",
1934 chg->smb_version);
1935 return -EINVAL;
1936 }
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301937
Nicholas Troast20ae1912017-02-15 10:15:32 -08001938 return 0;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301939}
1940
1941static int smblib_dp_pulse(struct smb_charger *chg)
1942{
1943 int rc;
1944
1945 /* QC 3.0 increment */
1946 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, SINGLE_INCREMENT_BIT,
1947 SINGLE_INCREMENT_BIT);
1948 if (rc < 0)
1949 smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
1950 rc);
1951
1952 return rc;
1953}
1954
1955static int smblib_dm_pulse(struct smb_charger *chg)
1956{
1957 int rc;
1958
1959 /* QC 3.0 decrement */
1960 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, SINGLE_DECREMENT_BIT,
1961 SINGLE_DECREMENT_BIT);
1962 if (rc < 0)
1963 smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
1964 rc);
1965
1966 return rc;
1967}
1968
1969int smblib_dp_dm(struct smb_charger *chg, int val)
1970{
1971 int target_icl_ua, rc = 0;
1972
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:
1989 chg->usb_icl_delta_ua -= 100000;
1990 target_icl_ua = get_effective_result(chg->usb_icl_votable);
1991 vote(chg->usb_icl_votable, SW_QC3_VOTER, true,
1992 target_icl_ua + chg->usb_icl_delta_ua);
1993 break;
1994 case POWER_SUPPLY_DP_DM_ICL_UP:
1995 default:
1996 break;
1997 }
1998
1999 return rc;
2000}
2001
Nicholas Troast34db5032016-03-28 12:26:44 -07002002/*******************
Harry Yangf3023592016-07-20 14:56:41 -07002003 * DC PSY GETTERS *
2004 *******************/
2005
2006int smblib_get_prop_dc_present(struct smb_charger *chg,
2007 union power_supply_propval *val)
2008{
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002009 int rc;
Harry Yangf3023592016-07-20 14:56:41 -07002010 u8 stat;
2011
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002012 rc = smblib_read(chg, DCIN_BASE + INT_RT_STS_OFFSET, &stat);
Harry Yangf3023592016-07-20 14:56:41 -07002013 if (rc < 0) {
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002014 smblib_err(chg, "Couldn't read DCIN_RT_STS rc=%d\n", rc);
Harry Yangf3023592016-07-20 14:56:41 -07002015 return rc;
2016 }
Harry Yangf3023592016-07-20 14:56:41 -07002017
2018 val->intval = (bool)(stat & DCIN_PLUGIN_RT_STS_BIT);
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002019 return 0;
Harry Yangf3023592016-07-20 14:56:41 -07002020}
2021
2022int smblib_get_prop_dc_online(struct smb_charger *chg,
2023 union power_supply_propval *val)
2024{
2025 int rc = 0;
2026 u8 stat;
2027
2028 if (get_client_vote(chg->dc_suspend_votable, USER_VOTER)) {
2029 val->intval = false;
2030 return rc;
2031 }
2032
2033 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
2034 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002035 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
Harry Yangf3023592016-07-20 14:56:41 -07002036 rc);
2037 return rc;
2038 }
2039 smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
2040 stat);
2041
2042 val->intval = (stat & USE_DCIN_BIT) &&
Vic Wei7ade2842016-12-14 18:47:49 -08002043 (stat & VALID_INPUT_POWER_SOURCE_STS_BIT);
Harry Yangf3023592016-07-20 14:56:41 -07002044
2045 return rc;
2046}
2047
2048int smblib_get_prop_dc_current_max(struct smb_charger *chg,
2049 union power_supply_propval *val)
2050{
2051 val->intval = get_effective_result_locked(chg->dc_icl_votable);
2052 return 0;
2053}
2054
2055/*******************
Harry Yangd89ff1f2016-12-05 14:59:11 -08002056 * DC PSY SETTERS *
Harry Yangf3023592016-07-20 14:56:41 -07002057 * *****************/
2058
2059int smblib_set_prop_dc_current_max(struct smb_charger *chg,
2060 const union power_supply_propval *val)
2061{
2062 int rc;
2063
2064 rc = vote(chg->dc_icl_votable, USER_VOTER, true, val->intval);
2065 return rc;
2066}
2067
2068/*******************
Nicholas Troast34db5032016-03-28 12:26:44 -07002069 * USB PSY GETTERS *
2070 *******************/
2071
2072int smblib_get_prop_usb_present(struct smb_charger *chg,
2073 union power_supply_propval *val)
2074{
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002075 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07002076 u8 stat;
2077
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002078 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
Nicholas Troast34db5032016-03-28 12:26:44 -07002079 if (rc < 0) {
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002080 smblib_err(chg, "Couldn't read USBIN_RT_STS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07002081 return rc;
2082 }
Nicholas Troast34db5032016-03-28 12:26:44 -07002083
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002084 val->intval = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
2085 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002086}
2087
2088int smblib_get_prop_usb_online(struct smb_charger *chg,
2089 union power_supply_propval *val)
2090{
2091 int rc = 0;
2092 u8 stat;
2093
Abhijeet Dharmapurikar84923af2017-03-23 14:07:07 -07002094 if (get_client_vote_locked(chg->usb_icl_votable, USER_VOTER) == 0) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002095 val->intval = false;
2096 return rc;
2097 }
2098
2099 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
2100 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002101 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002102 rc);
2103 return rc;
2104 }
2105 smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
2106 stat);
2107
2108 val->intval = (stat & USE_USBIN_BIT) &&
Vic Wei7ade2842016-12-14 18:47:49 -08002109 (stat & VALID_INPUT_POWER_SOURCE_STS_BIT);
Nicholas Troast34db5032016-03-28 12:26:44 -07002110 return rc;
2111}
2112
2113int smblib_get_prop_usb_voltage_now(struct smb_charger *chg,
2114 union power_supply_propval *val)
2115{
Harry Yangba874ce2016-08-19 14:17:01 -07002116 int rc = 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002117
Harry Yangba874ce2016-08-19 14:17:01 -07002118 rc = smblib_get_prop_usb_present(chg, val);
2119 if (rc < 0 || !val->intval)
2120 return rc;
2121
2122 if (!chg->iio.usbin_v_chan ||
2123 PTR_ERR(chg->iio.usbin_v_chan) == -EPROBE_DEFER)
2124 chg->iio.usbin_v_chan = iio_channel_get(chg->dev, "usbin_v");
2125
2126 if (IS_ERR(chg->iio.usbin_v_chan))
2127 return PTR_ERR(chg->iio.usbin_v_chan);
2128
2129 return iio_read_channel_processed(chg->iio.usbin_v_chan, &val->intval);
Nicholas Troast34db5032016-03-28 12:26:44 -07002130}
2131
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002132int smblib_get_prop_pd_current_max(struct smb_charger *chg,
2133 union power_supply_propval *val)
2134{
2135 val->intval = get_client_vote_locked(chg->usb_icl_votable, PD_VOTER);
2136 return 0;
2137}
2138
Nicholas Troast34db5032016-03-28 12:26:44 -07002139int smblib_get_prop_usb_current_max(struct smb_charger *chg,
2140 union power_supply_propval *val)
2141{
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002142 val->intval = get_client_vote_locked(chg->usb_icl_votable,
2143 USB_PSY_VOTER);
Nicholas Troast34db5032016-03-28 12:26:44 -07002144 return 0;
2145}
2146
Harry Yangba874ce2016-08-19 14:17:01 -07002147int smblib_get_prop_usb_current_now(struct smb_charger *chg,
2148 union power_supply_propval *val)
2149{
2150 int rc = 0;
2151
2152 rc = smblib_get_prop_usb_present(chg, val);
2153 if (rc < 0 || !val->intval)
2154 return rc;
2155
2156 if (!chg->iio.usbin_i_chan ||
2157 PTR_ERR(chg->iio.usbin_i_chan) == -EPROBE_DEFER)
2158 chg->iio.usbin_i_chan = iio_channel_get(chg->dev, "usbin_i");
2159
2160 if (IS_ERR(chg->iio.usbin_i_chan))
2161 return PTR_ERR(chg->iio.usbin_i_chan);
2162
2163 return iio_read_channel_processed(chg->iio.usbin_i_chan, &val->intval);
2164}
2165
2166int smblib_get_prop_charger_temp(struct smb_charger *chg,
2167 union power_supply_propval *val)
2168{
2169 int rc;
2170
2171 if (!chg->iio.temp_chan ||
2172 PTR_ERR(chg->iio.temp_chan) == -EPROBE_DEFER)
2173 chg->iio.temp_chan = iio_channel_get(chg->dev, "charger_temp");
2174
2175 if (IS_ERR(chg->iio.temp_chan))
2176 return PTR_ERR(chg->iio.temp_chan);
2177
2178 rc = iio_read_channel_processed(chg->iio.temp_chan, &val->intval);
2179 val->intval /= 100;
2180 return rc;
2181}
2182
2183int smblib_get_prop_charger_temp_max(struct smb_charger *chg,
2184 union power_supply_propval *val)
2185{
2186 int rc;
2187
2188 if (!chg->iio.temp_max_chan ||
2189 PTR_ERR(chg->iio.temp_max_chan) == -EPROBE_DEFER)
2190 chg->iio.temp_max_chan = iio_channel_get(chg->dev,
2191 "charger_temp_max");
2192 if (IS_ERR(chg->iio.temp_max_chan))
2193 return PTR_ERR(chg->iio.temp_max_chan);
2194
2195 rc = iio_read_channel_processed(chg->iio.temp_max_chan, &val->intval);
2196 val->intval /= 100;
2197 return rc;
2198}
2199
Nicholas Troast34db5032016-03-28 12:26:44 -07002200int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
2201 union power_supply_propval *val)
2202{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002203 if (chg->typec_status[3] & CC_ATTACHED_BIT)
2204 val->intval =
2205 (bool)(chg->typec_status[3] & CC_ORIENTATION_BIT) + 1;
Nicholas Troast34db5032016-03-28 12:26:44 -07002206 else
2207 val->intval = 0;
2208
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002209 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002210}
2211
2212static const char * const smblib_typec_mode_name[] = {
2213 [POWER_SUPPLY_TYPEC_NONE] = "NONE",
2214 [POWER_SUPPLY_TYPEC_SOURCE_DEFAULT] = "SOURCE_DEFAULT",
2215 [POWER_SUPPLY_TYPEC_SOURCE_MEDIUM] = "SOURCE_MEDIUM",
2216 [POWER_SUPPLY_TYPEC_SOURCE_HIGH] = "SOURCE_HIGH",
2217 [POWER_SUPPLY_TYPEC_NON_COMPLIANT] = "NON_COMPLIANT",
2218 [POWER_SUPPLY_TYPEC_SINK] = "SINK",
2219 [POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE] = "SINK_POWERED_CABLE",
2220 [POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY] = "SINK_DEBUG_ACCESSORY",
2221 [POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER] = "SINK_AUDIO_ADAPTER",
2222 [POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY] = "POWERED_CABLE_ONLY",
2223};
2224
2225static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
2226{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002227 switch (chg->typec_status[0]) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002228 case 0:
2229 return POWER_SUPPLY_TYPEC_NONE;
2230 case UFP_TYPEC_RDSTD_BIT:
2231 return POWER_SUPPLY_TYPEC_SOURCE_DEFAULT;
2232 case UFP_TYPEC_RD1P5_BIT:
2233 return POWER_SUPPLY_TYPEC_SOURCE_MEDIUM;
2234 case UFP_TYPEC_RD3P0_BIT:
2235 return POWER_SUPPLY_TYPEC_SOURCE_HIGH;
2236 default:
2237 break;
2238 }
2239
2240 return POWER_SUPPLY_TYPEC_NON_COMPLIANT;
2241}
2242
2243static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
2244{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002245 switch (chg->typec_status[1] & DFP_TYPEC_MASK) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002246 case DFP_RA_RA_BIT:
2247 return POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER;
2248 case DFP_RD_RD_BIT:
2249 return POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY;
2250 case DFP_RD_RA_VCONN_BIT:
2251 return POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE;
2252 case DFP_RD_OPEN_BIT:
2253 return POWER_SUPPLY_TYPEC_SINK;
2254 case DFP_RA_OPEN_BIT:
2255 return POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY;
2256 default:
2257 break;
2258 }
2259
2260 return POWER_SUPPLY_TYPEC_NONE;
2261}
2262
2263int smblib_get_prop_typec_mode(struct smb_charger *chg,
2264 union power_supply_propval *val)
2265{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002266 if (!(chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT)) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002267 val->intval = POWER_SUPPLY_TYPEC_NONE;
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002268 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002269 }
2270
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002271 if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07002272 val->intval = smblib_get_prop_dfp_mode(chg);
2273 else
2274 val->intval = smblib_get_prop_ufp_mode(chg);
2275
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002276 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002277}
2278
2279int smblib_get_prop_typec_power_role(struct smb_charger *chg,
2280 union power_supply_propval *val)
2281{
2282 int rc = 0;
2283 u8 ctrl;
2284
2285 rc = smblib_read(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &ctrl);
2286 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002287 smblib_err(chg, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002288 rc);
2289 return rc;
2290 }
2291 smblib_dbg(chg, PR_REGISTER, "TYPE_C_INTRPT_ENB_SOFTWARE_CTRL = 0x%02x\n",
2292 ctrl);
2293
2294 if (ctrl & TYPEC_DISABLE_CMD_BIT) {
2295 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
2296 return rc;
2297 }
2298
2299 switch (ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT)) {
2300 case 0:
2301 val->intval = POWER_SUPPLY_TYPEC_PR_DUAL;
2302 break;
2303 case DFP_EN_CMD_BIT:
2304 val->intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
2305 break;
2306 case UFP_EN_CMD_BIT:
2307 val->intval = POWER_SUPPLY_TYPEC_PR_SINK;
2308 break;
2309 default:
2310 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002311 smblib_err(chg, "unsupported power role 0x%02lx\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002312 ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT));
2313 return -EINVAL;
2314 }
2315
2316 return rc;
2317}
2318
2319int smblib_get_prop_pd_allowed(struct smb_charger *chg,
2320 union power_supply_propval *val)
2321{
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07002322 val->intval = get_effective_result(chg->pd_allowed_votable);
Nicholas Troast34db5032016-03-28 12:26:44 -07002323 return 0;
2324}
2325
Nicholas Troast133a7f52016-06-29 13:48:20 -07002326int smblib_get_prop_input_current_settled(struct smb_charger *chg,
2327 union power_supply_propval *val)
2328{
2329 return smblib_get_charge_param(chg, &chg->param.icl_stat, &val->intval);
2330}
2331
Fenglin Wuef4730e2017-01-11 18:16:25 +08002332#define HVDCP3_STEP_UV 200000
2333int smblib_get_prop_input_voltage_settled(struct smb_charger *chg,
2334 union power_supply_propval *val)
2335{
2336 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
2337 int rc, pulses;
2338 u8 stat;
2339
2340 val->intval = MICRO_5V;
2341 if (apsd_result == NULL) {
2342 smblib_err(chg, "APSD result is NULL\n");
2343 return 0;
2344 }
2345
2346 switch (apsd_result->pst) {
2347 case POWER_SUPPLY_TYPE_USB_HVDCP_3:
2348 rc = smblib_read(chg, QC_PULSE_COUNT_STATUS_REG, &stat);
2349 if (rc < 0) {
2350 smblib_err(chg,
2351 "Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
2352 return 0;
2353 }
2354 pulses = (stat & QC_PULSE_COUNT_MASK);
2355 val->intval = MICRO_5V + HVDCP3_STEP_UV * pulses;
2356 break;
2357 default:
2358 val->intval = MICRO_5V;
2359 break;
2360 }
2361
2362 return 0;
2363}
2364
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002365int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg,
2366 union power_supply_propval *val)
2367{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002368 val->intval = chg->pd_hard_reset;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002369 return 0;
2370}
2371
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07002372int smblib_get_pe_start(struct smb_charger *chg,
2373 union power_supply_propval *val)
2374{
2375 /*
2376 * hvdcp timeout voter is the last one to allow pd. Use its vote
2377 * to indicate start of pe engine
2378 */
2379 val->intval
2380 = !get_client_vote_locked(chg->pd_disallowed_votable_indirect,
2381 HVDCP_TIMEOUT_VOTER);
2382 return 0;
2383}
2384
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002385int smblib_get_prop_die_health(struct smb_charger *chg,
Nicholas Troastb021dd92017-01-31 18:43:38 -08002386 union power_supply_propval *val)
2387{
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002388 int rc;
Nicholas Troastb021dd92017-01-31 18:43:38 -08002389 u8 stat;
2390
2391 rc = smblib_read(chg, TEMP_RANGE_STATUS_REG, &stat);
2392 if (rc < 0) {
2393 smblib_err(chg, "Couldn't read TEMP_RANGE_STATUS_REG rc=%d\n",
2394 rc);
2395 return rc;
2396 }
2397
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002398 /* TEMP_RANGE bits are mutually exclusive */
2399 switch (stat & TEMP_RANGE_MASK) {
2400 case TEMP_BELOW_RANGE_BIT:
2401 val->intval = POWER_SUPPLY_HEALTH_COOL;
2402 break;
2403 case TEMP_WITHIN_RANGE_BIT:
2404 val->intval = POWER_SUPPLY_HEALTH_WARM;
2405 break;
2406 case TEMP_ABOVE_RANGE_BIT:
2407 val->intval = POWER_SUPPLY_HEALTH_HOT;
2408 break;
2409 case ALERT_LEVEL_BIT:
2410 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
2411 break;
2412 default:
2413 val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
Nicholas Troastb021dd92017-01-31 18:43:38 -08002414 }
2415
Nicholas Troastb021dd92017-01-31 18:43:38 -08002416 return 0;
2417}
2418
Nicholas Troast34db5032016-03-28 12:26:44 -07002419/*******************
2420 * USB PSY SETTERS *
2421 * *****************/
2422
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002423int smblib_set_prop_pd_current_max(struct smb_charger *chg,
2424 const union power_supply_propval *val)
2425{
2426 int rc;
2427
2428 if (chg->pd_active)
2429 rc = vote(chg->usb_icl_votable, PD_VOTER, true, val->intval);
2430 else
2431 rc = -EPERM;
2432
2433 return rc;
2434}
2435
Nicholas Troast34db5032016-03-28 12:26:44 -07002436int smblib_set_prop_usb_current_max(struct smb_charger *chg,
2437 const union power_supply_propval *val)
2438{
Nicholas Troast8d33b7d2017-01-16 11:18:38 -08002439 int rc = 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002440
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002441 if (!chg->pd_active) {
2442 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
2443 true, val->intval);
2444 } else if (chg->system_suspend_supported) {
2445 if (val->intval <= USBIN_25MA)
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302446 rc = vote(chg->usb_icl_votable,
2447 PD_SUSPEND_SUPPORTED_VOTER, true, val->intval);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002448 else
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302449 rc = vote(chg->usb_icl_votable,
2450 PD_SUSPEND_SUPPORTED_VOTER, false, 0);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002451 }
Nicholas Troast34db5032016-03-28 12:26:44 -07002452 return rc;
2453}
2454
Harry Yangd89ff1f2016-12-05 14:59:11 -08002455int smblib_set_prop_boost_current(struct smb_charger *chg,
2456 const union power_supply_propval *val)
2457{
2458 int rc = 0;
2459
2460 rc = smblib_set_charge_param(chg, &chg->param.freq_boost,
2461 val->intval <= chg->boost_threshold_ua ?
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05302462 chg->chg_freq.freq_below_otg_threshold :
2463 chg->chg_freq.freq_above_otg_threshold);
Harry Yangd89ff1f2016-12-05 14:59:11 -08002464 if (rc < 0) {
2465 dev_err(chg->dev, "Error in setting freq_boost rc=%d\n", rc);
2466 return rc;
2467 }
2468
2469 chg->boost_current_ua = val->intval;
2470 return rc;
2471}
2472
Nicholas Troast34db5032016-03-28 12:26:44 -07002473int smblib_set_prop_typec_power_role(struct smb_charger *chg,
2474 const union power_supply_propval *val)
2475{
2476 int rc = 0;
2477 u8 power_role;
2478
2479 switch (val->intval) {
2480 case POWER_SUPPLY_TYPEC_PR_NONE:
2481 power_role = TYPEC_DISABLE_CMD_BIT;
2482 break;
2483 case POWER_SUPPLY_TYPEC_PR_DUAL:
2484 power_role = 0;
2485 break;
2486 case POWER_SUPPLY_TYPEC_PR_SINK:
2487 power_role = UFP_EN_CMD_BIT;
2488 break;
2489 case POWER_SUPPLY_TYPEC_PR_SOURCE:
2490 power_role = DFP_EN_CMD_BIT;
2491 break;
2492 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002493 smblib_err(chg, "power role %d not supported\n", val->intval);
Nicholas Troast34db5032016-03-28 12:26:44 -07002494 return -EINVAL;
2495 }
2496
Jack Pham54a39bd2017-03-29 18:59:37 -07002497 if (power_role == UFP_EN_CMD_BIT) {
2498 /* disable PBS workaround when forcing sink mode */
2499 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0x0);
2500 if (rc < 0) {
2501 smblib_err(chg, "Couldn't write to TM_IO_DTEST4_SEL rc=%d\n",
2502 rc);
2503 }
2504 } else {
2505 /* restore it back to 0xA5 */
2506 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
2507 if (rc < 0) {
2508 smblib_err(chg, "Couldn't write to TM_IO_DTEST4_SEL rc=%d\n",
2509 rc);
2510 }
2511 }
2512
Nicholas Troast34db5032016-03-28 12:26:44 -07002513 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2514 TYPEC_POWER_ROLE_CMD_MASK, power_role);
2515 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002516 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 -07002517 power_role, rc);
2518 return rc;
2519 }
2520
2521 return rc;
2522}
2523
2524int smblib_set_prop_usb_voltage_min(struct smb_charger *chg,
2525 const union power_supply_propval *val)
2526{
2527 int rc, min_uv;
2528
2529 min_uv = min(val->intval, chg->voltage_max_uv);
2530 rc = smblib_set_usb_pd_allowed_voltage(chg, min_uv,
2531 chg->voltage_max_uv);
2532 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002533 smblib_err(chg, "invalid max voltage %duV rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002534 val->intval, rc);
2535 return rc;
2536 }
2537
Harry Yangaba1f5f2016-09-28 10:47:29 -07002538 chg->voltage_min_uv = min_uv;
Nicholas Troast34db5032016-03-28 12:26:44 -07002539 return rc;
2540}
2541
2542int smblib_set_prop_usb_voltage_max(struct smb_charger *chg,
2543 const union power_supply_propval *val)
2544{
2545 int rc, max_uv;
2546
2547 max_uv = max(val->intval, chg->voltage_min_uv);
2548 rc = smblib_set_usb_pd_allowed_voltage(chg, chg->voltage_min_uv,
2549 max_uv);
2550 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002551 smblib_err(chg, "invalid min voltage %duV rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002552 val->intval, rc);
2553 return rc;
2554 }
2555
Harry Yangaba1f5f2016-09-28 10:47:29 -07002556 chg->voltage_max_uv = max_uv;
Nicholas Troast34db5032016-03-28 12:26:44 -07002557 return rc;
2558}
2559
2560int smblib_set_prop_pd_active(struct smb_charger *chg,
2561 const union power_supply_propval *val)
2562{
2563 int rc;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002564 bool orientation, cc_debounced, sink_attached, hvdcp;
2565 u8 stat;
Nicholas Troast34db5032016-03-28 12:26:44 -07002566
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002567 if (!get_effective_result(chg->pd_allowed_votable))
Nicholas Troast34db5032016-03-28 12:26:44 -07002568 return -EINVAL;
Nicholas Troast34db5032016-03-28 12:26:44 -07002569
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002570 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
2571 if (rc < 0) {
2572 smblib_err(chg, "Couldn't read APSD status rc=%d\n", rc);
2573 return rc;
2574 }
2575
2576 cc_debounced = (bool)
2577 (chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
2578 sink_attached = (bool)
2579 (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT);
2580 hvdcp = stat & QC_CHARGER_BIT;
2581
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002582 chg->pd_active = val->intval;
2583 if (chg->pd_active) {
2584 vote(chg->apsd_disable_votable, PD_VOTER, true, 0);
2585 vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
2586 vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
2587
2588 /*
2589 * VCONN_EN_ORIENTATION_BIT controls whether to use CC1 or CC2
2590 * line when TYPEC_SPARE_CFG_BIT (CC pin selection s/w override)
2591 * is set or when VCONN_EN_VALUE_BIT is set.
2592 */
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002593 orientation = chg->typec_status[3] & CC_ORIENTATION_BIT;
Harry Yang88acff42016-09-21 14:56:06 -07002594 rc = smblib_masked_write(chg,
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07002595 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2596 VCONN_EN_ORIENTATION_BIT,
2597 orientation ? 0 : VCONN_EN_ORIENTATION_BIT);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002598 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002599 smblib_err(chg,
Harry Yang88acff42016-09-21 14:56:06 -07002600 "Couldn't enable vconn on CC line rc=%d\n", rc);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002601
2602 /* SW controlled CC_OUT */
2603 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
2604 TYPEC_SPARE_CFG_BIT, TYPEC_SPARE_CFG_BIT);
2605 if (rc < 0)
2606 smblib_err(chg, "Couldn't enable SW cc_out rc=%d\n",
2607 rc);
2608
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302609 /*
2610 * Enforce 500mA for PD until the real vote comes in later.
2611 * It is guaranteed that pd_active is set prior to
2612 * pd_current_max
2613 */
Harry Yangcd995202016-11-07 13:32:52 -08002614 rc = vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002615 if (rc < 0)
Harry Yangcd995202016-11-07 13:32:52 -08002616 smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n",
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002617 rc);
Harry Yangcd995202016-11-07 13:32:52 -08002618
Nicholas Troastf9e44992017-03-14 09:06:56 -07002619 /* since PD was found the cable must be non-legacy */
2620 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
2621
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002622 /* clear USB ICL vote for DCP_VOTER */
Harry Yang631b99e2016-11-17 11:24:25 -08002623 rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002624 if (rc < 0)
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002625 smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n",
2626 rc);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002627
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302628 /* remove USB_PSY_VOTER */
2629 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002630 if (rc < 0)
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302631 smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002632 } else {
2633 vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
2634 vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
2635 vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002636 vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER,
2637 false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002638
2639 /* HW controlled CC_OUT */
2640 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
2641 TYPEC_SPARE_CFG_BIT, 0);
2642 if (rc < 0)
2643 smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n",
2644 rc);
2645
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002646 /*
2647 * This WA should only run for HVDCP. Non-legacy SDP/CDP could
2648 * draw more, but this WA will remove Rd causing VBUS to drop,
2649 * and data could be interrupted. Non-legacy DCP could also draw
2650 * more, but it may impact compliance.
2651 */
2652 if (!chg->typec_legacy_valid && cc_debounced &&
2653 !sink_attached && hvdcp)
2654 schedule_work(&chg->legacy_detection_work);
Harry Yang88acff42016-09-21 14:56:06 -07002655 }
2656
Harry Yang6607b4a2016-05-17 17:50:09 -07002657 smblib_update_usb_type(chg);
Abhijeet Dharmapurikar76e2af52016-10-06 17:25:01 -07002658 power_supply_changed(chg->usb_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07002659 return rc;
2660}
2661
Fenglin Wuedd70792016-11-22 13:16:19 +08002662int smblib_set_prop_ship_mode(struct smb_charger *chg,
2663 const union power_supply_propval *val)
2664{
2665 int rc;
2666
2667 smblib_dbg(chg, PR_MISC, "Set ship mode: %d!!\n", !!val->intval);
2668
2669 rc = smblib_masked_write(chg, SHIP_MODE_REG, SHIP_MODE_EN_BIT,
2670 !!val->intval ? SHIP_MODE_EN_BIT : 0);
2671 if (rc < 0)
2672 dev_err(chg->dev, "Couldn't %s ship mode, rc=%d\n",
2673 !!val->intval ? "enable" : "disable", rc);
2674
2675 return rc;
2676}
2677
Harry Yang5e2bb712016-10-18 16:47:48 -07002678int smblib_reg_block_update(struct smb_charger *chg,
2679 struct reg_info *entry)
2680{
2681 int rc = 0;
2682
2683 while (entry && entry->reg) {
2684 rc = smblib_read(chg, entry->reg, &entry->bak);
2685 if (rc < 0) {
2686 dev_err(chg->dev, "Error in reading %s rc=%d\n",
2687 entry->desc, rc);
2688 break;
2689 }
2690 entry->bak &= entry->mask;
2691
2692 rc = smblib_masked_write(chg, entry->reg,
2693 entry->mask, entry->val);
2694 if (rc < 0) {
2695 dev_err(chg->dev, "Error in writing %s rc=%d\n",
2696 entry->desc, rc);
2697 break;
2698 }
2699 entry++;
2700 }
2701
2702 return rc;
2703}
2704
2705int smblib_reg_block_restore(struct smb_charger *chg,
2706 struct reg_info *entry)
2707{
2708 int rc = 0;
2709
2710 while (entry && entry->reg) {
2711 rc = smblib_masked_write(chg, entry->reg,
2712 entry->mask, entry->bak);
2713 if (rc < 0) {
2714 dev_err(chg->dev, "Error in writing %s rc=%d\n",
2715 entry->desc, rc);
2716 break;
2717 }
2718 entry++;
2719 }
2720
2721 return rc;
2722}
2723
Harry Yang755a34b2016-11-01 01:18:51 -07002724static struct reg_info cc2_detach_settings[] = {
2725 {
2726 .reg = TYPE_C_CFG_2_REG,
2727 .mask = TYPE_C_UFP_MODE_BIT | EN_TRY_SOURCE_MODE_BIT,
2728 .val = TYPE_C_UFP_MODE_BIT,
2729 .desc = "TYPE_C_CFG_2_REG",
2730 },
2731 {
2732 .reg = TYPE_C_CFG_3_REG,
2733 .mask = EN_TRYSINK_MODE_BIT,
2734 .val = 0,
2735 .desc = "TYPE_C_CFG_3_REG",
2736 },
2737 {
2738 .reg = TAPER_TIMER_SEL_CFG_REG,
2739 .mask = TYPEC_SPARE_CFG_BIT,
2740 .val = TYPEC_SPARE_CFG_BIT,
2741 .desc = "TAPER_TIMER_SEL_CFG_REG",
2742 },
2743 {
2744 .reg = TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2745 .mask = VCONN_EN_ORIENTATION_BIT,
2746 .val = 0,
2747 .desc = "TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG",
2748 },
2749 {
2750 .reg = MISC_CFG_REG,
2751 .mask = TCC_DEBOUNCE_20MS_BIT,
2752 .val = TCC_DEBOUNCE_20MS_BIT,
2753 .desc = "Tccdebounce time"
2754 },
2755 {
2756 },
2757};
2758
2759static int smblib_cc2_sink_removal_enter(struct smb_charger *chg)
2760{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002761 int rc, ccout, ufp_mode;
2762 u8 stat;
Harry Yang755a34b2016-11-01 01:18:51 -07002763
2764 if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002765 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002766
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002767 if (chg->cc2_detach_wa_active)
2768 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002769
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002770 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
Harry Yang755a34b2016-11-01 01:18:51 -07002771 if (rc < 0) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002772 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
Harry Yang755a34b2016-11-01 01:18:51 -07002773 return rc;
2774 }
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002775 ccout = (stat & CC_ATTACHED_BIT) ?
2776 (!!(stat & CC_ORIENTATION_BIT) + 1) : 0;
2777 ufp_mode = (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT) ?
2778 !(stat & UFP_DFP_MODE_STATUS_BIT) : 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002779
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002780 if (ccout != 2)
2781 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002782
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002783 if (!ufp_mode)
2784 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002785
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002786 chg->cc2_detach_wa_active = true;
2787 /* The CC2 removal WA will cause a type-c-change IRQ storm */
2788 smblib_reg_block_update(chg, cc2_detach_settings);
2789 schedule_work(&chg->rdstd_cc2_detach_work);
Harry Yang755a34b2016-11-01 01:18:51 -07002790 return rc;
2791}
2792
2793static int smblib_cc2_sink_removal_exit(struct smb_charger *chg)
2794{
Harry Yang755a34b2016-11-01 01:18:51 -07002795 if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002796 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002797
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002798 if (!chg->cc2_detach_wa_active)
2799 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002800
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002801 chg->cc2_detach_wa_active = false;
2802 cancel_work_sync(&chg->rdstd_cc2_detach_work);
2803 smblib_reg_block_restore(chg, cc2_detach_settings);
2804 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002805}
2806
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002807int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
2808 const union power_supply_propval *val)
2809{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002810 int rc = 0;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002811
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002812 if (chg->pd_hard_reset == val->intval)
2813 return rc;
2814
2815 chg->pd_hard_reset = val->intval;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002816 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002817 EXIT_SNK_BASED_ON_CC_BIT,
2818 (chg->pd_hard_reset) ? EXIT_SNK_BASED_ON_CC_BIT : 0);
2819 if (rc < 0)
2820 smblib_err(chg, "Couldn't set EXIT_SNK_BASED_ON_CC rc=%d\n",
Harry Yang755a34b2016-11-01 01:18:51 -07002821 rc);
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002822
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002823 vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER,
2824 chg->pd_hard_reset, 0);
Harry Yang755a34b2016-11-01 01:18:51 -07002825
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002826 return rc;
2827}
2828
Nicholas Troast7dbcad22016-10-05 13:30:18 -07002829/************************
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002830 * USB MAIN PSY GETTERS *
2831 ************************/
2832int smblib_get_prop_fcc_delta(struct smb_charger *chg,
2833 union power_supply_propval *val)
2834{
2835 int rc, jeita_cc_delta_ua, step_cc_delta_ua, hw_cc_delta_ua = 0;
2836
2837 rc = smblib_get_step_cc_delta(chg, &step_cc_delta_ua);
2838 if (rc < 0) {
2839 smblib_err(chg, "Couldn't get step cc delta rc=%d\n", rc);
2840 step_cc_delta_ua = 0;
2841 } else {
2842 hw_cc_delta_ua = step_cc_delta_ua;
2843 }
2844
2845 rc = smblib_get_jeita_cc_delta(chg, &jeita_cc_delta_ua);
2846 if (rc < 0) {
2847 smblib_err(chg, "Couldn't get jeita cc delta rc=%d\n", rc);
2848 jeita_cc_delta_ua = 0;
2849 } else if (jeita_cc_delta_ua < 0) {
2850 /* HW will take the min between JEITA and step charge */
2851 hw_cc_delta_ua = min(hw_cc_delta_ua, jeita_cc_delta_ua);
2852 }
2853
2854 val->intval = hw_cc_delta_ua;
2855 return 0;
2856}
2857
2858/************************
2859 * USB MAIN PSY SETTERS *
2860 ************************/
2861
2862#define SDP_CURRENT_MA 500000
2863#define CDP_CURRENT_MA 1500000
2864#define DCP_CURRENT_MA 1500000
2865#define HVDCP_CURRENT_MA 3000000
2866#define TYPEC_DEFAULT_CURRENT_MA 900000
2867#define TYPEC_MEDIUM_CURRENT_MA 1500000
2868#define TYPEC_HIGH_CURRENT_MA 3000000
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07002869int smblib_get_charge_current(struct smb_charger *chg,
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002870 int *total_current_ua)
2871{
Ashay Jaiswal7b6eb962017-04-26 14:34:29 +05302872 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002873 union power_supply_propval val = {0, };
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07002874 int rc = 0, typec_source_rd, current_ua;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002875 bool non_compliant;
2876 u8 stat5;
2877
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07002878 if (chg->pd_active) {
2879 *total_current_ua =
2880 get_client_vote_locked(chg->usb_icl_votable, PD_VOTER);
2881 return rc;
2882 }
2883
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002884 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
2885 if (rc < 0) {
2886 smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc);
2887 return rc;
2888 }
2889 non_compliant = stat5 & TYPEC_NONCOMP_LEGACY_CABLE_STATUS_BIT;
2890
2891 /* get settled ICL */
2892 rc = smblib_get_prop_input_current_settled(chg, &val);
2893 if (rc < 0) {
2894 smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
2895 return rc;
2896 }
2897
2898 typec_source_rd = smblib_get_prop_ufp_mode(chg);
2899
2900 /* QC 2.0/3.0 adapter */
2901 if (apsd_result->bit & (QC_3P0_BIT | QC_2P0_BIT)) {
2902 *total_current_ua = HVDCP_CURRENT_MA;
2903 return 0;
2904 }
2905
2906 if (non_compliant) {
2907 switch (apsd_result->bit) {
2908 case CDP_CHARGER_BIT:
2909 current_ua = CDP_CURRENT_MA;
2910 break;
2911 case DCP_CHARGER_BIT:
2912 case OCP_CHARGER_BIT:
2913 case FLOAT_CHARGER_BIT:
2914 current_ua = DCP_CURRENT_MA;
2915 break;
2916 default:
2917 current_ua = 0;
2918 break;
2919 }
2920
2921 *total_current_ua = max(current_ua, val.intval);
2922 return 0;
2923 }
2924
2925 switch (typec_source_rd) {
2926 case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
2927 switch (apsd_result->bit) {
2928 case CDP_CHARGER_BIT:
2929 current_ua = CDP_CURRENT_MA;
2930 break;
2931 case DCP_CHARGER_BIT:
2932 case OCP_CHARGER_BIT:
2933 case FLOAT_CHARGER_BIT:
2934 current_ua = chg->default_icl_ua;
2935 break;
2936 default:
2937 current_ua = 0;
2938 break;
2939 }
2940 break;
2941 case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
2942 current_ua = TYPEC_MEDIUM_CURRENT_MA;
2943 break;
2944 case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
2945 current_ua = TYPEC_HIGH_CURRENT_MA;
2946 break;
2947 case POWER_SUPPLY_TYPEC_NON_COMPLIANT:
2948 case POWER_SUPPLY_TYPEC_NONE:
2949 default:
2950 current_ua = 0;
2951 break;
2952 }
2953
2954 *total_current_ua = max(current_ua, val.intval);
2955 return 0;
2956}
2957
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002958/************************
Nicholas Troast7dbcad22016-10-05 13:30:18 -07002959 * PARALLEL PSY GETTERS *
2960 ************************/
2961
2962int smblib_get_prop_slave_current_now(struct smb_charger *chg,
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07002963 union power_supply_propval *pval)
Nicholas Troast7dbcad22016-10-05 13:30:18 -07002964{
2965 if (IS_ERR_OR_NULL(chg->iio.batt_i_chan))
2966 chg->iio.batt_i_chan = iio_channel_get(chg->dev, "batt_i");
2967
2968 if (IS_ERR(chg->iio.batt_i_chan))
2969 return PTR_ERR(chg->iio.batt_i_chan);
2970
2971 return iio_read_channel_processed(chg->iio.batt_i_chan, &pval->intval);
2972}
2973
Nicholas Troast34db5032016-03-28 12:26:44 -07002974/**********************
2975 * INTERRUPT HANDLERS *
2976 **********************/
2977
2978irqreturn_t smblib_handle_debug(int irq, void *data)
2979{
2980 struct smb_irq_data *irq_data = data;
2981 struct smb_charger *chg = irq_data->parent_data;
2982
2983 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07002984 return IRQ_HANDLED;
2985}
2986
Nicholas Troast8995a702016-12-05 10:22:22 -08002987irqreturn_t smblib_handle_otg_overcurrent(int irq, void *data)
2988{
2989 struct smb_irq_data *irq_data = data;
2990 struct smb_charger *chg = irq_data->parent_data;
2991 int rc;
2992 u8 stat;
2993
2994 rc = smblib_read(chg, OTG_BASE + INT_RT_STS_OFFSET, &stat);
2995 if (rc < 0) {
2996 dev_err(chg->dev, "Couldn't read OTG_INT_RT_STS rc=%d\n", rc);
2997 return IRQ_HANDLED;
2998 }
2999
Ashay Jaiswal7c241382017-03-06 15:26:38 +05303000 if (chg->wa_flags & OTG_WA) {
3001 if (stat & OTG_OC_DIS_SW_STS_RT_STS_BIT)
3002 smblib_err(chg, "OTG disabled by hw\n");
3003
3004 /* not handling software based hiccups for PM660 */
3005 return IRQ_HANDLED;
3006 }
3007
Nicholas Troastb11015f2017-01-17 17:56:45 -08003008 if (stat & OTG_OVERCURRENT_RT_STS_BIT)
3009 schedule_work(&chg->otg_oc_work);
Nicholas Troast8995a702016-12-05 10:22:22 -08003010
Nicholas Troast8995a702016-12-05 10:22:22 -08003011 return IRQ_HANDLED;
3012}
3013
Harry Yang6fe72ab2016-06-14 16:21:39 -07003014irqreturn_t smblib_handle_chg_state_change(int irq, void *data)
3015{
3016 struct smb_irq_data *irq_data = data;
3017 struct smb_charger *chg = irq_data->parent_data;
Nicholas Troast8cb77552016-09-23 11:50:18 -07003018 u8 stat;
Harry Yang1d1034c2016-06-15 12:09:42 -07003019 int rc;
Harry Yang6fe72ab2016-06-14 16:21:39 -07003020
3021 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3022
Nicholas Troast8cb77552016-09-23 11:50:18 -07003023 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
Harry Yang1d1034c2016-06-15 12:09:42 -07003024 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003025 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003026 rc);
Harry Yang1d1034c2016-06-15 12:09:42 -07003027 return IRQ_HANDLED;
3028 }
3029
Nicholas Troast8cb77552016-09-23 11:50:18 -07003030 stat = stat & BATTERY_CHARGER_STATUS_MASK;
Nicholas Troast8cb77552016-09-23 11:50:18 -07003031 power_supply_changed(chg->batt_psy);
Harry Yang6fe72ab2016-06-14 16:21:39 -07003032 return IRQ_HANDLED;
3033}
3034
Harry Yangfe913842016-08-10 12:27:28 -07003035irqreturn_t smblib_handle_step_chg_state_change(int irq, void *data)
3036{
3037 struct smb_irq_data *irq_data = data;
3038 struct smb_charger *chg = irq_data->parent_data;
3039
3040 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3041
3042 if (chg->step_chg_enabled)
3043 rerun_election(chg->fcc_votable);
3044
3045 return IRQ_HANDLED;
3046}
3047
3048irqreturn_t smblib_handle_step_chg_soc_update_fail(int irq, void *data)
3049{
3050 struct smb_irq_data *irq_data = data;
3051 struct smb_charger *chg = irq_data->parent_data;
3052
3053 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3054
3055 if (chg->step_chg_enabled)
3056 rerun_election(chg->fcc_votable);
3057
3058 return IRQ_HANDLED;
3059}
3060
3061#define STEP_SOC_REQ_MS 3000
3062irqreturn_t smblib_handle_step_chg_soc_update_request(int irq, void *data)
3063{
3064 struct smb_irq_data *irq_data = data;
3065 struct smb_charger *chg = irq_data->parent_data;
3066 int rc;
3067 union power_supply_propval pval = {0, };
3068
3069 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3070
3071 if (!chg->bms_psy) {
3072 schedule_delayed_work(&chg->step_soc_req_work,
3073 msecs_to_jiffies(STEP_SOC_REQ_MS));
3074 return IRQ_HANDLED;
3075 }
3076
3077 rc = smblib_get_prop_batt_capacity(chg, &pval);
3078 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003079 smblib_err(chg, "Couldn't get batt capacity rc=%d\n", rc);
Harry Yangfe913842016-08-10 12:27:28 -07003080 else
3081 step_charge_soc_update(chg, pval.intval);
3082
3083 return IRQ_HANDLED;
3084}
3085
Abhijeet Dharmapurikar2644cd62016-07-20 16:54:55 -07003086irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data)
3087{
3088 struct smb_irq_data *irq_data = data;
3089 struct smb_charger *chg = irq_data->parent_data;
3090
3091 rerun_election(chg->fcc_votable);
3092 power_supply_changed(chg->batt_psy);
3093 return IRQ_HANDLED;
3094}
3095
Nicholas Troast34db5032016-03-28 12:26:44 -07003096irqreturn_t smblib_handle_batt_psy_changed(int irq, void *data)
3097{
3098 struct smb_irq_data *irq_data = data;
3099 struct smb_charger *chg = irq_data->parent_data;
3100
Nicholas Troast47ae4612016-08-03 09:49:36 -07003101 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003102 power_supply_changed(chg->batt_psy);
3103 return IRQ_HANDLED;
3104}
3105
3106irqreturn_t smblib_handle_usb_psy_changed(int irq, void *data)
3107{
3108 struct smb_irq_data *irq_data = data;
3109 struct smb_charger *chg = irq_data->parent_data;
3110
Nicholas Troast47ae4612016-08-03 09:49:36 -07003111 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003112 power_supply_changed(chg->usb_psy);
3113 return IRQ_HANDLED;
3114}
3115
Subbaraman Narayanamurthy09327482017-02-06 16:33:12 -08003116irqreturn_t smblib_handle_usbin_uv(int irq, void *data)
3117{
3118 struct smb_irq_data *irq_data = data;
3119 struct smb_charger *chg = irq_data->parent_data;
3120 struct storm_watch *wdata;
3121
3122 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3123 if (!chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data)
3124 return IRQ_HANDLED;
3125
3126 wdata = &chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data->storm_data;
3127 reset_storm_count(wdata);
3128 return IRQ_HANDLED;
3129}
3130
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003131static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising)
3132{
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003133 if (vbus_rising) {
3134 /* use the typec flag even though its not typec */
3135 chg->typec_present = 1;
3136 } else {
3137 chg->typec_present = 0;
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003138 smblib_update_usb_type(chg);
3139 extcon_set_cable_state_(chg->extcon, EXTCON_USB, false);
3140 smblib_uusb_removal(chg);
3141 }
3142}
3143
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003144void smblib_usb_plugin_hard_reset_locked(struct smb_charger *chg)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003145{
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003146 int rc;
3147 u8 stat;
3148 bool vbus_rising;
3149
3150 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
3151 if (rc < 0) {
3152 smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
3153 return;
3154 }
3155
3156 vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
3157
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003158 if (vbus_rising)
3159 smblib_cc2_sink_removal_exit(chg);
3160 else
3161 smblib_cc2_sink_removal_enter(chg);
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003162
3163 power_supply_changed(chg->usb_psy);
3164 smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
3165 vbus_rising ? "attached" : "detached");
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003166}
3167
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303168#define PL_DELAY_MS 30000
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003169void smblib_usb_plugin_locked(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07003170{
Nicholas Troast34db5032016-03-28 12:26:44 -07003171 int rc;
3172 u8 stat;
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003173 bool vbus_rising;
Nicholas Troast34db5032016-03-28 12:26:44 -07003174
Harry Yangcdad2bf2016-10-04 17:03:56 -07003175 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
3176 if (rc < 0) {
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003177 smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
3178 return;
Harry Yangcdad2bf2016-10-04 17:03:56 -07003179 }
3180
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003181 vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003182 smblib_set_opt_freq_buck(chg, vbus_rising ? chg->chg_freq.freq_5V :
3183 chg->chg_freq.freq_removal);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003184
Nicholas Troast34db5032016-03-28 12:26:44 -07003185 /* fetch the DPDM regulator */
3186 if (!chg->dpdm_reg && of_get_property(chg->dev->of_node,
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05303187 "dpdm-supply", NULL)) {
Nicholas Troast34db5032016-03-28 12:26:44 -07003188 chg->dpdm_reg = devm_regulator_get(chg->dev, "dpdm");
3189 if (IS_ERR(chg->dpdm_reg)) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003190 smblib_err(chg, "Couldn't get dpdm regulator rc=%ld\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07003191 PTR_ERR(chg->dpdm_reg));
3192 chg->dpdm_reg = NULL;
3193 }
3194 }
3195
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003196 if (vbus_rising) {
Nicholas Troastabedaf72016-09-16 11:07:45 -07003197 if (chg->dpdm_reg && !regulator_is_enabled(chg->dpdm_reg)) {
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07003198 smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n");
3199 rc = regulator_enable(chg->dpdm_reg);
3200 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003201 smblib_err(chg, "Couldn't enable dpdm regulator rc=%d\n",
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07003202 rc);
3203 }
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303204
3205 /* Schedule work to enable parallel charger */
3206 vote(chg->awake_votable, PL_DELAY_VOTER, true, 0);
3207 schedule_delayed_work(&chg->pl_enable_work,
3208 msecs_to_jiffies(PL_DELAY_MS));
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07003209 } else {
Abhijeet Dharmapurikar2823fe32016-12-05 17:52:11 -08003210 if (chg->wa_flags & BOOST_BACK_WA)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08003211 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
Nicholas Troastabedaf72016-09-16 11:07:45 -07003212
3213 if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) {
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07003214 smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n");
3215 rc = regulator_disable(chg->dpdm_reg);
3216 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003217 smblib_err(chg, "Couldn't disable dpdm regulator rc=%d\n",
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07003218 rc);
3219 }
Nicholas Troast34db5032016-03-28 12:26:44 -07003220 }
3221
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003222 if (chg->micro_usb_mode)
3223 smblib_micro_usb_plugin(chg, vbus_rising);
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003224
Nicholas Troast62d86622016-09-22 11:41:33 -07003225 power_supply_changed(chg->usb_psy);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003226 smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
3227 vbus_rising ? "attached" : "detached");
3228}
3229
3230irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
3231{
3232 struct smb_irq_data *irq_data = data;
3233 struct smb_charger *chg = irq_data->parent_data;
3234
3235 mutex_lock(&chg->lock);
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003236 if (chg->pd_hard_reset)
3237 smblib_usb_plugin_hard_reset_locked(chg);
3238 else
3239 smblib_usb_plugin_locked(chg);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003240 mutex_unlock(&chg->lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07003241 return IRQ_HANDLED;
3242}
3243
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -07003244#define USB_WEAK_INPUT_UA 1400000
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303245#define ICL_CHANGE_DELAY_MS 1000
Harry Yang6fe72ab2016-06-14 16:21:39 -07003246irqreturn_t smblib_handle_icl_change(int irq, void *data)
3247{
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303248 u8 stat;
3249 int rc, settled_ua, delay = ICL_CHANGE_DELAY_MS;
Harry Yang6fe72ab2016-06-14 16:21:39 -07003250 struct smb_irq_data *irq_data = data;
3251 struct smb_charger *chg = irq_data->parent_data;
3252
Nicholas Troastbb9e1a32017-02-09 10:57:28 -08003253 if (chg->mode == PARALLEL_MASTER) {
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303254 rc = smblib_read(chg, AICL_STATUS_REG, &stat);
3255 if (rc < 0) {
3256 smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n",
3257 rc);
3258 return IRQ_HANDLED;
3259 }
3260
3261 rc = smblib_get_charge_param(chg, &chg->param.icl_stat,
3262 &settled_ua);
3263 if (rc < 0) {
3264 smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
3265 return IRQ_HANDLED;
3266 }
3267
3268 /* If AICL settled then schedule work now */
3269 if ((settled_ua == get_effective_result(chg->usb_icl_votable))
3270 || (stat & AICL_DONE_BIT))
3271 delay = 0;
3272
Ashay Jaiswalac854862017-03-06 23:58:55 +05303273 cancel_delayed_work_sync(&chg->icl_change_work);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303274 schedule_delayed_work(&chg->icl_change_work,
3275 msecs_to_jiffies(delay));
Nicholas Troastbb9e1a32017-02-09 10:57:28 -08003276 }
Harry Yang1d1034c2016-06-15 12:09:42 -07003277
Harry Yang6fe72ab2016-06-14 16:21:39 -07003278 return IRQ_HANDLED;
3279}
3280
Nicholas Troast34db5032016-03-28 12:26:44 -07003281static void smblib_handle_slow_plugin_timeout(struct smb_charger *chg,
3282 bool rising)
3283{
3284 smblib_dbg(chg, PR_INTERRUPT, "IRQ: slow-plugin-timeout %s\n",
3285 rising ? "rising" : "falling");
3286}
3287
3288static void smblib_handle_sdp_enumeration_done(struct smb_charger *chg,
3289 bool rising)
3290{
3291 smblib_dbg(chg, PR_INTERRUPT, "IRQ: sdp-enumeration-done %s\n",
3292 rising ? "rising" : "falling");
3293}
3294
Harry Yangcdad2bf2016-10-04 17:03:56 -07003295#define QC3_PULSES_FOR_6V 5
3296#define QC3_PULSES_FOR_9V 20
3297#define QC3_PULSES_FOR_12V 35
3298static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg)
3299{
3300 int rc;
3301 u8 stat;
3302 int pulses;
3303
Fenglin Wuef4730e2017-01-11 18:16:25 +08003304 power_supply_changed(chg->usb_main_psy);
Fenglin Wu80826e02017-04-25 21:45:08 +08003305 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP) {
Harry Yangcdad2bf2016-10-04 17:03:56 -07003306 rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat);
3307 if (rc < 0) {
3308 smblib_err(chg,
3309 "Couldn't read QC_CHANGE_STATUS rc=%d\n", rc);
3310 return;
3311 }
3312
3313 switch (stat & QC_2P0_STATUS_MASK) {
3314 case QC_5V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303315 smblib_set_opt_freq_buck(chg,
3316 chg->chg_freq.freq_5V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003317 break;
3318 case QC_9V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303319 smblib_set_opt_freq_buck(chg,
3320 chg->chg_freq.freq_9V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003321 break;
3322 case QC_12V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303323 smblib_set_opt_freq_buck(chg,
3324 chg->chg_freq.freq_12V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003325 break;
3326 default:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303327 smblib_set_opt_freq_buck(chg,
3328 chg->chg_freq.freq_removal);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003329 break;
3330 }
3331 }
3332
Fenglin Wu80826e02017-04-25 21:45:08 +08003333 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP_3) {
Harry Yangcdad2bf2016-10-04 17:03:56 -07003334 rc = smblib_read(chg, QC_PULSE_COUNT_STATUS_REG, &stat);
3335 if (rc < 0) {
3336 smblib_err(chg,
3337 "Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
3338 return;
3339 }
3340 pulses = (stat & QC_PULSE_COUNT_MASK);
3341
3342 if (pulses < QC3_PULSES_FOR_6V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303343 smblib_set_opt_freq_buck(chg,
3344 chg->chg_freq.freq_5V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003345 else if (pulses < QC3_PULSES_FOR_9V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303346 smblib_set_opt_freq_buck(chg,
3347 chg->chg_freq.freq_6V_8V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003348 else if (pulses < QC3_PULSES_FOR_12V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303349 smblib_set_opt_freq_buck(chg,
3350 chg->chg_freq.freq_9V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003351 else
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303352 smblib_set_opt_freq_buck(chg,
3353 chg->chg_freq.freq_12V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003354 }
3355}
3356
Nicholas Troast34db5032016-03-28 12:26:44 -07003357/* triggers when HVDCP 3.0 authentication has finished */
3358static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
3359 bool rising)
3360{
3361 const struct apsd_result *apsd_result;
Harry Yangcdad2bf2016-10-04 17:03:56 -07003362 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07003363
3364 if (!rising)
3365 return;
3366
Ashay Jaiswal67ec7072017-02-16 14:14:58 +05303367 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
3368 /*
3369 * Disable AUTH_IRQ_EN_CFG_BIT to receive adapter voltage
3370 * change interrupt.
3371 */
3372 rc = smblib_masked_write(chg,
3373 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
3374 AUTH_IRQ_EN_CFG_BIT, 0);
3375 if (rc < 0)
3376 smblib_err(chg,
3377 "Couldn't enable QC auth setting rc=%d\n", rc);
3378 }
Harry Yangcdad2bf2016-10-04 17:03:56 -07003379
Harry Yangaba1f5f2016-09-28 10:47:29 -07003380 if (chg->mode == PARALLEL_MASTER)
3381 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0);
3382
Ashay Jaiswalac854862017-03-06 23:58:55 +05303383 /* the APSD done handler will set the USB supply type */
3384 apsd_result = smblib_get_apsd_result(chg);
3385 if (get_effective_result(chg->hvdcp_hw_inov_dis_votable)) {
3386 if (apsd_result->pst == POWER_SUPPLY_TYPE_USB_HVDCP) {
3387 /* force HVDCP2 to 9V if INOV is disabled */
3388 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG,
3389 FORCE_9V_BIT, FORCE_9V_BIT);
3390 if (rc < 0)
3391 smblib_err(chg,
3392 "Couldn't force 9V HVDCP rc=%d\n", rc);
3393 }
3394 }
3395
Nicholas Troast34db5032016-03-28 12:26:44 -07003396 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n",
3397 apsd_result->name);
3398}
3399
Harry Yang1369b7a2016-09-27 15:59:50 -07003400static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
3401 bool rising, bool qc_charger)
3402{
Ashay Jaiswal7b6eb962017-04-26 14:34:29 +05303403 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05303404
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003405 /* Hold off PD only until hvdcp 2.0 detection timeout */
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003406 if (rising) {
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003407 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003408 false, 0);
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -08003409
Harry Yang4bf7d962017-03-13 16:51:43 -07003410 /* enable HDC and ICL irq for QC2/3 charger */
3411 if (qc_charger)
3412 vote(chg->usb_irq_enable_votable, QC_VOTER, true, 0);
3413
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -08003414 /*
3415 * HVDCP detection timeout done
3416 * If adapter is not QC2.0/QC3.0 - it is a plain old DCP.
3417 */
3418 if (!qc_charger && (apsd_result->bit & DCP_CHARGER_BIT))
3419 /* enforce DCP ICL if specified */
3420 vote(chg->usb_icl_votable, DCP_VOTER,
3421 chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua);
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003422 }
Harry Yang1369b7a2016-09-27 15:59:50 -07003423
3424 smblib_dbg(chg, PR_INTERRUPT, "IRQ: smblib_handle_hvdcp_check_timeout %s\n",
3425 rising ? "rising" : "falling");
3426}
3427
Nicholas Troast34db5032016-03-28 12:26:44 -07003428/* triggers when HVDCP is detected */
3429static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg,
3430 bool rising)
3431{
3432 if (!rising)
3433 return;
3434
3435 /* the APSD done handler will set the USB supply type */
3436 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
3437 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-detect-done %s\n",
3438 rising ? "rising" : "falling");
3439}
3440
Nicholas Troastf9e44992017-03-14 09:06:56 -07003441static void smblib_force_legacy_icl(struct smb_charger *chg, int pst)
3442{
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003443 /* while PD is active it should have complete ICL control */
3444 if (chg->pd_active)
3445 return;
3446
Nicholas Troastf9e44992017-03-14 09:06:56 -07003447 switch (pst) {
3448 case POWER_SUPPLY_TYPE_USB:
3449 /*
3450 * USB_PSY will vote to increase the current to 500/900mA once
3451 * enumeration is done. Ensure that USB_PSY has at least voted
3452 * for 100mA before releasing the LEGACY_UNKNOWN vote
3453 */
3454 if (!is_client_vote_enabled(chg->usb_icl_votable,
3455 USB_PSY_VOTER))
3456 vote(chg->usb_icl_votable, USB_PSY_VOTER, true, 100000);
3457 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
3458 break;
3459 case POWER_SUPPLY_TYPE_USB_CDP:
3460 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1500000);
3461 break;
3462 case POWER_SUPPLY_TYPE_USB_DCP:
3463 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1500000);
3464 break;
3465 case POWER_SUPPLY_TYPE_USB_HVDCP:
3466 case POWER_SUPPLY_TYPE_USB_HVDCP_3:
3467 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 3000000);
3468 break;
3469 default:
3470 smblib_err(chg, "Unknown APSD %d; forcing 500mA\n", pst);
3471 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 500000);
3472 break;
3473 }
3474}
3475
Nicholas Troast34db5032016-03-28 12:26:44 -07003476#define HVDCP_DET_MS 2500
3477static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
3478{
Nicholas Troast34db5032016-03-28 12:26:44 -07003479 const struct apsd_result *apsd_result;
3480
3481 if (!rising)
3482 return;
3483
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07003484 apsd_result = smblib_update_usb_type(chg);
Nicholas Troastf9e44992017-03-14 09:06:56 -07003485
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003486 if (!chg->typec_legacy_valid)
Nicholas Troastf9e44992017-03-14 09:06:56 -07003487 smblib_force_legacy_icl(chg, apsd_result->pst);
3488
Nicholas Troast34db5032016-03-28 12:26:44 -07003489 switch (apsd_result->bit) {
3490 case SDP_CHARGER_BIT:
3491 case CDP_CHARGER_BIT:
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05303492 if (chg->micro_usb_mode)
3493 extcon_set_cable_state_(chg->extcon, EXTCON_USB,
3494 true);
Abhijeet Dharmapurikarbb9505f2017-03-22 18:31:28 -07003495 /* if not DCP then no hvdcp timeout happens. Enable pd here */
3496 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3497 false, 0);
3498 break;
Nicholas Troast34db5032016-03-28 12:26:44 -07003499 case OCP_CHARGER_BIT:
3500 case FLOAT_CHARGER_BIT:
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303501 /* if not DCP then no hvdcp timeout happens, Enable pd here. */
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003502 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3503 false, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07003504 break;
3505 case DCP_CHARGER_BIT:
Harry Yang1369b7a2016-09-27 15:59:50 -07003506 if (chg->wa_flags & QC_CHARGER_DETECTION_WA_BIT)
3507 schedule_delayed_work(&chg->hvdcp_detect_work,
3508 msecs_to_jiffies(HVDCP_DET_MS));
Nicholas Troast34db5032016-03-28 12:26:44 -07003509 break;
3510 default:
3511 break;
3512 }
3513
Nicholas Troast34db5032016-03-28 12:26:44 -07003514 smblib_dbg(chg, PR_INTERRUPT, "IRQ: apsd-done rising; %s detected\n",
3515 apsd_result->name);
3516}
3517
3518irqreturn_t smblib_handle_usb_source_change(int irq, void *data)
3519{
3520 struct smb_irq_data *irq_data = data;
3521 struct smb_charger *chg = irq_data->parent_data;
3522 int rc = 0;
3523 u8 stat;
3524
3525 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
3526 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003527 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07003528 return IRQ_HANDLED;
3529 }
3530 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
3531
Ashay Jaiswal8507aa52017-04-14 09:42:32 +05303532 if (chg->micro_usb_mode && (stat & APSD_DTC_STATUS_DONE_BIT)
3533 && !chg->uusb_apsd_rerun_done) {
3534 /*
3535 * Force re-run APSD to handle slow insertion related
3536 * charger-mis-detection.
3537 */
3538 chg->uusb_apsd_rerun_done = true;
3539 smblib_rerun_apsd(chg);
3540 return IRQ_HANDLED;
3541 }
3542
Nicholas Troast34db5032016-03-28 12:26:44 -07003543 smblib_handle_apsd_done(chg,
3544 (bool)(stat & APSD_DTC_STATUS_DONE_BIT));
3545
3546 smblib_handle_hvdcp_detect_done(chg,
3547 (bool)(stat & QC_CHARGER_BIT));
3548
Harry Yang1369b7a2016-09-27 15:59:50 -07003549 smblib_handle_hvdcp_check_timeout(chg,
3550 (bool)(stat & HVDCP_CHECK_TIMEOUT_BIT),
3551 (bool)(stat & QC_CHARGER_BIT));
3552
Nicholas Troast34db5032016-03-28 12:26:44 -07003553 smblib_handle_hvdcp_3p0_auth_done(chg,
3554 (bool)(stat & QC_AUTH_DONE_STATUS_BIT));
3555
Nicholas Troast34db5032016-03-28 12:26:44 -07003556 smblib_handle_sdp_enumeration_done(chg,
3557 (bool)(stat & ENUMERATION_DONE_BIT));
3558
3559 smblib_handle_slow_plugin_timeout(chg,
3560 (bool)(stat & SLOW_PLUGIN_TIMEOUT_BIT));
3561
Harry Yangcdad2bf2016-10-04 17:03:56 -07003562 smblib_hvdcp_adaptive_voltage_change(chg);
3563
Nicholas Troast34db5032016-03-28 12:26:44 -07003564 power_supply_changed(chg->usb_psy);
3565
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08003566 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
3567 if (rc < 0) {
3568 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
3569 return IRQ_HANDLED;
3570 }
3571 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
3572
Nicholas Troast34db5032016-03-28 12:26:44 -07003573 return IRQ_HANDLED;
3574}
3575
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003576static void typec_sink_insertion(struct smb_charger *chg)
3577{
3578 /* when a sink is inserted we should not wait on hvdcp timeout to
3579 * enable pd
3580 */
3581 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3582 false, 0);
3583}
Nicholas Troast34db5032016-03-28 12:26:44 -07003584
Harry Yangd89ff1f2016-12-05 14:59:11 -08003585static void typec_sink_removal(struct smb_charger *chg)
3586{
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303587 smblib_set_charge_param(chg, &chg->param.freq_boost,
3588 chg->chg_freq.freq_above_otg_threshold);
Harry Yangd89ff1f2016-12-05 14:59:11 -08003589 chg->boost_current_ua = 0;
3590}
3591
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003592static void smblib_handle_typec_removal(struct smb_charger *chg)
3593{
Nicholas Troastfe74c592017-03-14 09:20:55 -07003594 int rc;
3595
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003596 chg->cc2_detach_wa_active = false;
3597
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003598 /* reset APSD voters */
3599 vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, false, 0);
3600 vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303601
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003602 cancel_delayed_work_sync(&chg->pl_enable_work);
3603 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
3604
3605 /* reset input current limit voters */
3606 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
3607 vote(chg->usb_icl_votable, PD_VOTER, false, 0);
3608 vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
3609 vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
3610 vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
3611
3612 /* reset hvdcp voters */
3613 vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, true, 0);
3614 vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER, true, 0);
3615
3616 /* reset power delivery voters */
3617 vote(chg->pd_allowed_votable, PD_VOTER, false, 0);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003618 vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0);
3619 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER, true, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003620
3621 /* reset usb irq voters */
Harry Yang4bf7d962017-03-13 16:51:43 -07003622 vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
3623 vote(chg->usb_irq_enable_votable, QC_VOTER, false, 0);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003624
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003625 /* reset parallel voters */
3626 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
3627 vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
3628 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
3629 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
Harry Yang1d1034c2016-06-15 12:09:42 -07003630
Nicholas Troast8995a702016-12-05 10:22:22 -08003631 chg->vconn_attempts = 0;
3632 chg->otg_attempts = 0;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05303633 chg->pulse_cnt = 0;
3634 chg->usb_icl_delta_ua = 0;
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003635 chg->voltage_min_uv = MICRO_5V;
3636 chg->voltage_max_uv = MICRO_5V;
3637 chg->pd_active = 0;
3638 chg->pd_hard_reset = 0;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003639 chg->typec_legacy_valid = false;
Harry Yang3b113a52016-12-08 12:37:40 -08003640
Nicholas Troastfe74c592017-03-14 09:20:55 -07003641 /* enable APSD CC trigger for next insertion */
3642 rc = smblib_masked_write(chg, TYPE_C_CFG_REG,
3643 APSD_START_ON_CC_BIT, APSD_START_ON_CC_BIT);
3644 if (rc < 0)
3645 smblib_err(chg, "Couldn't enable APSD_START_ON_CC rc=%d\n", rc);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08003646
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003647 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
3648 /* re-enable AUTH_IRQ_EN_CFG_BIT */
3649 rc = smblib_masked_write(chg,
3650 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
3651 AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
3652 if (rc < 0)
3653 smblib_err(chg,
3654 "Couldn't enable QC auth setting rc=%d\n", rc);
3655 }
3656
3657 /* reconfigure allowed voltage for HVDCP */
3658 rc = smblib_set_adapter_allowance(chg,
3659 USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
3660 if (rc < 0)
3661 smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
3662 rc);
3663
3664 /* enable DRP */
3665 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
3666 TYPEC_POWER_ROLE_CMD_MASK, 0);
3667 if (rc < 0)
3668 smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc);
3669
3670 /* HW controlled CC_OUT */
3671 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
3672 TYPEC_SPARE_CFG_BIT, 0);
3673 if (rc < 0)
3674 smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n", rc);
3675
3676 /* restore crude sensor */
3677 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
3678 if (rc < 0)
3679 smblib_err(chg, "Couldn't restore crude sensor rc=%d\n", rc);
3680
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08003681 typec_sink_removal(chg);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003682 smblib_update_usb_type(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07003683}
3684
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003685static void smblib_handle_typec_insertion(struct smb_charger *chg,
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003686 bool sink_attached)
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003687{
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003688 int rc;
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003689
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003690 vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, false, 0);
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003691
Nicholas Troastfe74c592017-03-14 09:20:55 -07003692 /* disable APSD CC trigger since CC is attached */
3693 rc = smblib_masked_write(chg, TYPE_C_CFG_REG, APSD_START_ON_CC_BIT, 0);
3694 if (rc < 0)
3695 smblib_err(chg, "Couldn't disable APSD_START_ON_CC rc=%d\n",
3696 rc);
3697
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003698 if (sink_attached)
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003699 typec_sink_insertion(chg);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003700 else
Harry Yangd89ff1f2016-12-05 14:59:11 -08003701 typec_sink_removal(chg);
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003702}
3703
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003704static void smblib_handle_typec_debounce_done(struct smb_charger *chg,
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003705 bool rising, bool sink_attached)
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003706{
3707 int rc;
3708 union power_supply_propval pval = {0, };
3709
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003710 if (rising) {
3711 if (!chg->typec_present) {
3712 chg->typec_present = true;
3713 smblib_dbg(chg, PR_MISC, "TypeC insertion\n");
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003714 smblib_handle_typec_insertion(chg, sink_attached);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003715 }
3716 } else {
3717 if (chg->typec_present) {
3718 chg->typec_present = false;
3719 smblib_dbg(chg, PR_MISC, "TypeC removal\n");
3720 smblib_handle_typec_removal(chg);
3721 }
3722 }
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003723
3724 rc = smblib_get_prop_typec_mode(chg, &pval);
3725 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003726 smblib_err(chg, "Couldn't get prop typec mode rc=%d\n", rc);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003727
3728 smblib_dbg(chg, PR_INTERRUPT, "IRQ: debounce-done %s; Type-C %s detected\n",
3729 rising ? "rising" : "falling",
3730 smblib_typec_mode_name[pval.intval]);
3731}
3732
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05303733irqreturn_t smblib_handle_usb_typec_change_for_uusb(struct smb_charger *chg)
3734{
3735 int rc;
3736 u8 stat;
3737
3738 rc = smblib_read(chg, TYPE_C_STATUS_3_REG, &stat);
3739 if (rc < 0) {
3740 smblib_err(chg, "Couldn't read TYPE_C_STATUS_3 rc=%d\n", rc);
3741 return IRQ_HANDLED;
3742 }
3743 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_3 = 0x%02x OTG=%d\n",
3744 stat, !!(stat & (U_USB_GND_NOVBUS_BIT | U_USB_GND_BIT)));
3745
3746 extcon_set_cable_state_(chg->extcon, EXTCON_USB_HOST,
3747 !!(stat & (U_USB_GND_NOVBUS_BIT | U_USB_GND_BIT)));
3748 power_supply_changed(chg->usb_psy);
3749
3750 return IRQ_HANDLED;
3751}
3752
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003753static void smblib_usb_typec_change(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07003754{
Nicholas Troast34db5032016-03-28 12:26:44 -07003755 int rc;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003756 bool debounce_done, sink_attached;
Nicholas Troast34db5032016-03-28 12:26:44 -07003757
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07003758 rc = smblib_multibyte_read(chg, TYPE_C_STATUS_1_REG,
3759 chg->typec_status, 5);
Nicholas Troast34db5032016-03-28 12:26:44 -07003760 if (rc < 0) {
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07003761 smblib_err(chg, "Couldn't cache USB Type-C status rc=%d\n", rc);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003762 return;
Nicholas Troast34db5032016-03-28 12:26:44 -07003763 }
Nicholas Troast34db5032016-03-28 12:26:44 -07003764
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07003765 debounce_done =
3766 (bool)(chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
3767 sink_attached =
3768 (bool)(chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003769
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003770 smblib_handle_typec_debounce_done(chg, debounce_done, sink_attached);
Nicholas Troast34db5032016-03-28 12:26:44 -07003771
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07003772 if (chg->typec_status[3] & TYPEC_VBUS_ERROR_STATUS_BIT)
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003773 smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n");
Harry Yangd757c0f2016-09-23 10:52:05 -07003774
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07003775 if (chg->typec_status[3] & TYPEC_VCONN_OVERCURR_STATUS_BIT)
Nicholas Troastb11015f2017-01-17 17:56:45 -08003776 schedule_work(&chg->vconn_oc_work);
Nicholas Troast8995a702016-12-05 10:22:22 -08003777
Nicholas Troastb1486552016-11-10 08:20:11 -08003778 power_supply_changed(chg->usb_psy);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003779}
3780
3781irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
3782{
3783 struct smb_irq_data *irq_data = data;
3784 struct smb_charger *chg = irq_data->parent_data;
3785
3786 if (chg->micro_usb_mode) {
3787 smblib_handle_usb_typec_change_for_uusb(chg);
3788 return IRQ_HANDLED;
3789 }
3790
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003791 if (chg->cc2_detach_wa_active || chg->typec_en_dis_active) {
3792 smblib_dbg(chg, PR_INTERRUPT, "Ignoring since %s active\n",
3793 chg->cc2_detach_wa_active ?
3794 "cc2_detach_wa" : "typec_en_dis");
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003795 return IRQ_HANDLED;
3796 }
3797
3798 mutex_lock(&chg->lock);
3799 smblib_usb_typec_change(chg);
3800 mutex_unlock(&chg->lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07003801 return IRQ_HANDLED;
3802}
3803
Abhijeet Dharmapurikar23916642016-10-03 10:38:50 -07003804irqreturn_t smblib_handle_dc_plugin(int irq, void *data)
3805{
3806 struct smb_irq_data *irq_data = data;
3807 struct smb_charger *chg = irq_data->parent_data;
3808
3809 power_supply_changed(chg->dc_psy);
3810 return IRQ_HANDLED;
3811}
3812
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07003813irqreturn_t smblib_handle_high_duty_cycle(int irq, void *data)
3814{
3815 struct smb_irq_data *irq_data = data;
3816 struct smb_charger *chg = irq_data->parent_data;
3817
3818 chg->is_hdc = true;
3819 schedule_delayed_work(&chg->clear_hdc_work, msecs_to_jiffies(60));
3820
3821 return IRQ_HANDLED;
3822}
3823
Nicholas Troastabedaf72016-09-16 11:07:45 -07003824irqreturn_t smblib_handle_switcher_power_ok(int irq, void *data)
3825{
3826 struct smb_irq_data *irq_data = data;
3827 struct smb_charger *chg = irq_data->parent_data;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003828 int rc, usb_icl;
Nicholas Troastabedaf72016-09-16 11:07:45 -07003829 u8 stat;
3830
3831 if (!(chg->wa_flags & BOOST_BACK_WA))
3832 return IRQ_HANDLED;
3833
3834 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
3835 if (rc < 0) {
3836 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n", rc);
3837 return IRQ_HANDLED;
3838 }
3839
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003840 /* skip suspending input if its already suspended by some other voter */
3841 usb_icl = get_effective_result(chg->usb_icl_votable);
3842 if ((stat & USE_USBIN_BIT) && usb_icl >= 0 && usb_icl < USBIN_25MA)
Nicholas Troastabedaf72016-09-16 11:07:45 -07003843 return IRQ_HANDLED;
3844
Abhijeet Dharmapurikar2823fe32016-12-05 17:52:11 -08003845 if (stat & USE_DCIN_BIT)
Nicholas Troastabedaf72016-09-16 11:07:45 -07003846 return IRQ_HANDLED;
3847
3848 if (is_storming(&irq_data->storm_data)) {
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08003849 smblib_err(chg, "Reverse boost detected: voting 0mA to suspend input\n");
3850 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, true, 0);
Nicholas Troastabedaf72016-09-16 11:07:45 -07003851 }
3852
3853 return IRQ_HANDLED;
3854}
3855
Nicholas Troast15dc0c82016-10-18 15:15:21 -07003856irqreturn_t smblib_handle_wdog_bark(int irq, void *data)
3857{
3858 struct smb_irq_data *irq_data = data;
3859 struct smb_charger *chg = irq_data->parent_data;
3860 int rc;
3861
3862 rc = smblib_write(chg, BARK_BITE_WDOG_PET_REG, BARK_BITE_WDOG_PET_BIT);
3863 if (rc < 0)
3864 smblib_err(chg, "Couldn't pet the dog rc=%d\n", rc);
3865
3866 return IRQ_HANDLED;
3867}
3868
Nicholas Troast34db5032016-03-28 12:26:44 -07003869/***************
3870 * Work Queues *
3871 ***************/
3872
3873static void smblib_hvdcp_detect_work(struct work_struct *work)
3874{
3875 struct smb_charger *chg = container_of(work, struct smb_charger,
3876 hvdcp_detect_work.work);
Nicholas Troast34db5032016-03-28 12:26:44 -07003877
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003878 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3879 false, 0);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003880 power_supply_changed(chg->usb_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07003881}
3882
Harry Yangfe913842016-08-10 12:27:28 -07003883static void bms_update_work(struct work_struct *work)
Harry Yang5e1a5222016-07-26 15:16:04 -07003884{
3885 struct smb_charger *chg = container_of(work, struct smb_charger,
3886 bms_update_work);
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05303887
3888 smblib_suspend_on_debug_battery(chg);
3889
3890 if (chg->batt_psy)
3891 power_supply_changed(chg->batt_psy);
Harry Yang5e1a5222016-07-26 15:16:04 -07003892}
3893
Harry Yangfe913842016-08-10 12:27:28 -07003894static void step_soc_req_work(struct work_struct *work)
3895{
3896 struct smb_charger *chg = container_of(work, struct smb_charger,
3897 step_soc_req_work.work);
3898 union power_supply_propval pval = {0, };
3899 int rc;
3900
3901 rc = smblib_get_prop_batt_capacity(chg, &pval);
3902 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003903 smblib_err(chg, "Couldn't get batt capacity rc=%d\n", rc);
Harry Yangfe913842016-08-10 12:27:28 -07003904 return;
3905 }
3906
3907 step_charge_soc_update(chg, pval.intval);
3908}
3909
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07003910static void clear_hdc_work(struct work_struct *work)
3911{
3912 struct smb_charger *chg = container_of(work, struct smb_charger,
3913 clear_hdc_work.work);
3914
3915 chg->is_hdc = 0;
3916}
3917
Harry Yang755a34b2016-11-01 01:18:51 -07003918static void rdstd_cc2_detach_work(struct work_struct *work)
3919{
3920 int rc;
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003921 u8 stat4, stat5;
Harry Yang755a34b2016-11-01 01:18:51 -07003922 struct smb_charger *chg = container_of(work, struct smb_charger,
3923 rdstd_cc2_detach_work);
3924
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003925 if (!chg->cc2_detach_wa_active)
3926 return;
3927
Harry Yang755a34b2016-11-01 01:18:51 -07003928 /*
3929 * WA steps -
3930 * 1. Enable both UFP and DFP, wait for 10ms.
3931 * 2. Disable DFP, wait for 30ms.
3932 * 3. Removal detected if both TYPEC_DEBOUNCE_DONE_STATUS
3933 * and TIMER_STAGE bits are gone, otherwise repeat all by
3934 * work rescheduling.
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003935 * Note, work will be cancelled when USB_PLUGIN rises.
Harry Yang755a34b2016-11-01 01:18:51 -07003936 */
3937
3938 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
3939 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT,
3940 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT);
3941 if (rc < 0) {
3942 smblib_err(chg, "Couldn't write TYPE_C_CTRL_REG rc=%d\n", rc);
3943 return;
3944 }
3945
3946 usleep_range(10000, 11000);
3947
3948 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
3949 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT,
3950 UFP_EN_CMD_BIT);
3951 if (rc < 0) {
3952 smblib_err(chg, "Couldn't write TYPE_C_CTRL_REG rc=%d\n", rc);
3953 return;
3954 }
3955
3956 usleep_range(30000, 31000);
3957
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003958 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
Harry Yang755a34b2016-11-01 01:18:51 -07003959 if (rc < 0) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003960 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
Harry Yang755a34b2016-11-01 01:18:51 -07003961 return;
3962 }
Harry Yang755a34b2016-11-01 01:18:51 -07003963
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003964 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
Harry Yang755a34b2016-11-01 01:18:51 -07003965 if (rc < 0) {
3966 smblib_err(chg,
3967 "Couldn't read TYPE_C_STATUS_5_REG rc=%d\n", rc);
3968 return;
3969 }
Harry Yang755a34b2016-11-01 01:18:51 -07003970
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003971 if ((stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT)
3972 || (stat5 & TIMER_STAGE_2_BIT)) {
3973 smblib_dbg(chg, PR_MISC, "rerunning DD=%d TS2BIT=%d\n",
3974 (int)(stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT),
3975 (int)(stat5 & TIMER_STAGE_2_BIT));
3976 goto rerun;
3977 }
3978
3979 smblib_dbg(chg, PR_MISC, "Bingo CC2 Removal detected\n");
3980 chg->cc2_detach_wa_active = false;
3981 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
3982 EXIT_SNK_BASED_ON_CC_BIT, 0);
Harry Yang755a34b2016-11-01 01:18:51 -07003983 smblib_reg_block_restore(chg, cc2_detach_settings);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003984 mutex_lock(&chg->lock);
3985 smblib_usb_typec_change(chg);
3986 mutex_unlock(&chg->lock);
Harry Yang755a34b2016-11-01 01:18:51 -07003987 return;
3988
3989rerun:
3990 schedule_work(&chg->rdstd_cc2_detach_work);
3991}
3992
Nicholas Troastb11015f2017-01-17 17:56:45 -08003993static void smblib_otg_oc_exit(struct smb_charger *chg, bool success)
3994{
3995 int rc;
3996
3997 chg->otg_attempts = 0;
3998 if (!success) {
3999 smblib_err(chg, "OTG soft start failed\n");
4000 chg->otg_en = false;
4001 }
4002
4003 smblib_dbg(chg, PR_OTG, "enabling VBUS < 1V check\n");
4004 rc = smblib_masked_write(chg, OTG_CFG_REG,
4005 QUICKSTART_OTG_FASTROLESWAP_BIT, 0);
4006 if (rc < 0)
4007 smblib_err(chg, "Couldn't enable VBUS < 1V check rc=%d\n", rc);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004008}
4009
4010#define MAX_OC_FALLING_TRIES 10
4011static void smblib_otg_oc_work(struct work_struct *work)
4012{
4013 struct smb_charger *chg = container_of(work, struct smb_charger,
4014 otg_oc_work);
4015 int rc, i;
4016 u8 stat;
4017
4018 if (!chg->vbus_vreg || !chg->vbus_vreg->rdev)
4019 return;
4020
4021 smblib_err(chg, "over-current detected on VBUS\n");
4022 mutex_lock(&chg->otg_oc_lock);
4023 if (!chg->otg_en)
4024 goto unlock;
4025
4026 smblib_dbg(chg, PR_OTG, "disabling VBUS < 1V check\n");
4027 smblib_masked_write(chg, OTG_CFG_REG,
4028 QUICKSTART_OTG_FASTROLESWAP_BIT,
4029 QUICKSTART_OTG_FASTROLESWAP_BIT);
4030
4031 /*
4032 * If 500ms has passed and another over-current interrupt has not
4033 * triggered then it is likely that the software based soft start was
4034 * successful and the VBUS < 1V restriction should be re-enabled.
4035 */
4036 schedule_delayed_work(&chg->otg_ss_done_work, msecs_to_jiffies(500));
4037
4038 rc = _smblib_vbus_regulator_disable(chg->vbus_vreg->rdev);
4039 if (rc < 0) {
4040 smblib_err(chg, "Couldn't disable VBUS rc=%d\n", rc);
4041 goto unlock;
4042 }
4043
4044 if (++chg->otg_attempts > OTG_MAX_ATTEMPTS) {
4045 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4046 smblib_err(chg, "OTG failed to enable after %d attempts\n",
4047 chg->otg_attempts - 1);
4048 smblib_otg_oc_exit(chg, false);
4049 goto unlock;
4050 }
4051
4052 /*
4053 * The real time status should go low within 10ms. Poll every 1-2ms to
4054 * minimize the delay when re-enabling OTG.
4055 */
4056 for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) {
4057 usleep_range(1000, 2000);
4058 rc = smblib_read(chg, OTG_BASE + INT_RT_STS_OFFSET, &stat);
4059 if (rc >= 0 && !(stat & OTG_OVERCURRENT_RT_STS_BIT))
4060 break;
4061 }
4062
4063 if (i >= MAX_OC_FALLING_TRIES) {
4064 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4065 smblib_err(chg, "OTG OC did not fall after %dms\n",
4066 2 * MAX_OC_FALLING_TRIES);
4067 smblib_otg_oc_exit(chg, false);
4068 goto unlock;
4069 }
4070
4071 smblib_dbg(chg, PR_OTG, "OTG OC fell after %dms\n", 2 * i + 1);
4072 rc = _smblib_vbus_regulator_enable(chg->vbus_vreg->rdev);
4073 if (rc < 0) {
4074 smblib_err(chg, "Couldn't enable VBUS rc=%d\n", rc);
4075 goto unlock;
4076 }
4077
4078unlock:
4079 mutex_unlock(&chg->otg_oc_lock);
4080}
4081
4082static void smblib_vconn_oc_work(struct work_struct *work)
4083{
4084 struct smb_charger *chg = container_of(work, struct smb_charger,
4085 vconn_oc_work);
4086 int rc, i;
4087 u8 stat;
4088
Ashay Jaiswal15edce42017-03-31 23:29:58 +05304089 if (chg->micro_usb_mode)
4090 return;
4091
Nicholas Troastb11015f2017-01-17 17:56:45 -08004092 smblib_err(chg, "over-current detected on VCONN\n");
4093 if (!chg->vconn_vreg || !chg->vconn_vreg->rdev)
4094 return;
4095
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07004096 mutex_lock(&chg->vconn_oc_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004097 rc = _smblib_vconn_regulator_disable(chg->vconn_vreg->rdev);
4098 if (rc < 0) {
4099 smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc);
4100 goto unlock;
4101 }
4102
4103 if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
4104 smblib_err(chg, "VCONN failed to enable after %d attempts\n",
4105 chg->otg_attempts - 1);
4106 chg->vconn_en = false;
4107 chg->vconn_attempts = 0;
4108 goto unlock;
4109 }
4110
4111 /*
4112 * The real time status should go low within 10ms. Poll every 1-2ms to
4113 * minimize the delay when re-enabling OTG.
4114 */
4115 for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) {
4116 usleep_range(1000, 2000);
4117 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
4118 if (rc >= 0 && !(stat & TYPEC_VCONN_OVERCURR_STATUS_BIT))
4119 break;
4120 }
4121
4122 if (i >= MAX_OC_FALLING_TRIES) {
4123 smblib_err(chg, "VCONN OC did not fall after %dms\n",
4124 2 * MAX_OC_FALLING_TRIES);
4125 chg->vconn_en = false;
4126 chg->vconn_attempts = 0;
4127 goto unlock;
4128 }
4129
4130 smblib_dbg(chg, PR_OTG, "VCONN OC fell after %dms\n", 2 * i + 1);
4131 if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
4132 smblib_err(chg, "VCONN failed to enable after %d attempts\n",
4133 chg->vconn_attempts - 1);
4134 chg->vconn_en = false;
4135 goto unlock;
4136 }
4137
4138 rc = _smblib_vconn_regulator_enable(chg->vconn_vreg->rdev);
4139 if (rc < 0) {
4140 smblib_err(chg, "Couldn't enable VCONN rc=%d\n", rc);
4141 goto unlock;
4142 }
4143
4144unlock:
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07004145 mutex_unlock(&chg->vconn_oc_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004146}
4147
4148static void smblib_otg_ss_done_work(struct work_struct *work)
4149{
4150 struct smb_charger *chg = container_of(work, struct smb_charger,
4151 otg_ss_done_work.work);
4152 int rc;
4153 bool success = false;
4154 u8 stat;
4155
4156 mutex_lock(&chg->otg_oc_lock);
4157 rc = smblib_read(chg, OTG_STATUS_REG, &stat);
4158 if (rc < 0)
4159 smblib_err(chg, "Couldn't read OTG status rc=%d\n", rc);
4160 else if (stat & BOOST_SOFTSTART_DONE_BIT)
4161 success = true;
4162
4163 smblib_otg_oc_exit(chg, success);
4164 mutex_unlock(&chg->otg_oc_lock);
4165}
4166
Ashay Jaiswal4d825782017-02-18 10:11:34 +05304167static void smblib_icl_change_work(struct work_struct *work)
4168{
4169 struct smb_charger *chg = container_of(work, struct smb_charger,
4170 icl_change_work.work);
4171 int rc, settled_ua;
4172
4173 rc = smblib_get_charge_param(chg, &chg->param.icl_stat, &settled_ua);
4174 if (rc < 0) {
4175 smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
4176 return;
4177 }
4178
4179 power_supply_changed(chg->usb_main_psy);
4180 vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER,
4181 settled_ua >= USB_WEAK_INPUT_UA, 0);
4182
4183 smblib_dbg(chg, PR_INTERRUPT, "icl_settled=%d\n", settled_ua);
4184}
4185
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304186static void smblib_pl_enable_work(struct work_struct *work)
4187{
4188 struct smb_charger *chg = container_of(work, struct smb_charger,
4189 pl_enable_work.work);
4190
4191 smblib_dbg(chg, PR_PARALLEL, "timer expired, enabling parallel\n");
4192 vote(chg->pl_disable_votable, PL_DELAY_VOTER, false, 0);
4193 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
4194}
4195
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004196static void smblib_legacy_detection_work(struct work_struct *work)
4197{
4198 struct smb_charger *chg = container_of(work, struct smb_charger,
4199 legacy_detection_work);
4200 int rc;
4201 u8 stat;
4202 bool legacy, rp_high;
4203
4204 mutex_lock(&chg->lock);
4205 chg->typec_en_dis_active = 1;
4206 smblib_dbg(chg, PR_MISC, "running legacy unknown workaround\n");
4207 rc = smblib_masked_write(chg,
4208 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4209 TYPEC_DISABLE_CMD_BIT,
4210 TYPEC_DISABLE_CMD_BIT);
4211 if (rc < 0)
4212 smblib_err(chg, "Couldn't disable type-c rc=%d\n", rc);
4213
4214 /* wait for the adapter to turn off VBUS */
4215 msleep(500);
4216
4217 rc = smblib_masked_write(chg,
4218 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4219 TYPEC_DISABLE_CMD_BIT, 0);
4220 if (rc < 0)
4221 smblib_err(chg, "Couldn't enable type-c rc=%d\n", rc);
4222
4223 /* wait for type-c detection to complete */
4224 msleep(100);
4225
4226 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat);
4227 if (rc < 0) {
4228 smblib_err(chg, "Couldn't read typec stat5 rc = %d\n", rc);
4229 goto unlock;
4230 }
4231
4232 chg->typec_legacy_valid = true;
4233 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
4234 legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT;
4235 rp_high = smblib_get_prop_ufp_mode(chg) ==
4236 POWER_SUPPLY_TYPEC_SOURCE_HIGH;
4237 if (!legacy || !rp_high)
4238 vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
4239 false, 0);
4240
4241unlock:
4242 chg->typec_en_dis_active = 0;
4243 mutex_unlock(&chg->lock);
4244}
4245
Harry Yangba874ce2016-08-19 14:17:01 -07004246static int smblib_create_votables(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07004247{
4248 int rc = 0;
4249
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304250 chg->fcc_votable = find_votable("FCC");
Harry Yang0c35ff62017-04-06 00:02:30 -07004251 if (chg->fcc_votable == NULL) {
4252 rc = -EINVAL;
4253 smblib_err(chg, "Couldn't find FCC votable rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304254 return rc;
4255 }
4256
4257 chg->fv_votable = find_votable("FV");
Harry Yang0c35ff62017-04-06 00:02:30 -07004258 if (chg->fv_votable == NULL) {
4259 rc = -EINVAL;
4260 smblib_err(chg, "Couldn't find FV votable rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304261 return rc;
4262 }
4263
Ashay Jaiswalae1586d2017-03-22 23:18:51 +05304264 chg->usb_icl_votable = find_votable("USB_ICL");
4265 if (!chg->usb_icl_votable) {
Harry Yang0c35ff62017-04-06 00:02:30 -07004266 rc = -EINVAL;
4267 smblib_err(chg, "Couldn't find USB_ICL votable rc=%d\n", rc);
Ashay Jaiswalae1586d2017-03-22 23:18:51 +05304268 return rc;
4269 }
4270
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304271 chg->pl_disable_votable = find_votable("PL_DISABLE");
Harry Yang0c35ff62017-04-06 00:02:30 -07004272 if (chg->pl_disable_votable == NULL) {
4273 rc = -EINVAL;
4274 smblib_err(chg, "Couldn't find votable PL_DISABLE rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304275 return rc;
4276 }
4277 vote(chg->pl_disable_votable, PL_INDIRECT_VOTER, true, 0);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304278 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304279
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004280 chg->dc_suspend_votable = create_votable("DC_SUSPEND", VOTE_SET_ANY,
4281 smblib_dc_suspend_vote_callback,
4282 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07004283 if (IS_ERR(chg->dc_suspend_votable)) {
4284 rc = PTR_ERR(chg->dc_suspend_votable);
4285 return rc;
4286 }
4287
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004288 chg->dc_icl_votable = create_votable("DC_ICL", VOTE_MIN,
4289 smblib_dc_icl_vote_callback,
4290 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07004291 if (IS_ERR(chg->dc_icl_votable)) {
4292 rc = PTR_ERR(chg->dc_icl_votable);
4293 return rc;
4294 }
4295
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07004296 chg->pd_disallowed_votable_indirect
4297 = create_votable("PD_DISALLOWED_INDIRECT", VOTE_SET_ANY,
4298 smblib_pd_disallowed_votable_indirect_callback, chg);
4299 if (IS_ERR(chg->pd_disallowed_votable_indirect)) {
4300 rc = PTR_ERR(chg->pd_disallowed_votable_indirect);
4301 return rc;
4302 }
4303
4304 chg->pd_allowed_votable = create_votable("PD_ALLOWED",
4305 VOTE_SET_ANY, NULL, NULL);
Nicholas Troast34db5032016-03-28 12:26:44 -07004306 if (IS_ERR(chg->pd_allowed_votable)) {
4307 rc = PTR_ERR(chg->pd_allowed_votable);
4308 return rc;
4309 }
4310
Harry Yang223c6282016-06-14 15:48:36 -07004311 chg->awake_votable = create_votable("AWAKE", VOTE_SET_ANY,
4312 smblib_awake_vote_callback,
4313 chg);
4314 if (IS_ERR(chg->awake_votable)) {
4315 rc = PTR_ERR(chg->awake_votable);
4316 return rc;
4317 }
4318
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07004319 chg->chg_disable_votable = create_votable("CHG_DISABLE", VOTE_SET_ANY,
4320 smblib_chg_disable_vote_callback,
4321 chg);
4322 if (IS_ERR(chg->chg_disable_votable)) {
4323 rc = PTR_ERR(chg->chg_disable_votable);
4324 return rc;
4325 }
4326
Harry Yangaba1f5f2016-09-28 10:47:29 -07004327 chg->pl_enable_votable_indirect = create_votable("PL_ENABLE_INDIRECT",
4328 VOTE_SET_ANY,
4329 smblib_pl_enable_indirect_vote_callback,
4330 chg);
4331 if (IS_ERR(chg->pl_enable_votable_indirect)) {
4332 rc = PTR_ERR(chg->pl_enable_votable_indirect);
4333 return rc;
4334 }
4335
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05304336 chg->hvdcp_disable_votable_indirect = create_votable(
4337 "HVDCP_DISABLE_INDIRECT",
4338 VOTE_SET_ANY,
4339 smblib_hvdcp_disable_indirect_vote_callback,
4340 chg);
4341 if (IS_ERR(chg->hvdcp_disable_votable_indirect)) {
4342 rc = PTR_ERR(chg->hvdcp_disable_votable_indirect);
4343 return rc;
4344 }
4345
4346 chg->hvdcp_enable_votable = create_votable("HVDCP_ENABLE",
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07004347 VOTE_SET_ANY,
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05304348 smblib_hvdcp_enable_vote_callback,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07004349 chg);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05304350 if (IS_ERR(chg->hvdcp_enable_votable)) {
4351 rc = PTR_ERR(chg->hvdcp_enable_votable);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07004352 return rc;
4353 }
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07004354
4355 chg->apsd_disable_votable = create_votable("APSD_DISABLE",
4356 VOTE_SET_ANY,
4357 smblib_apsd_disable_vote_callback,
4358 chg);
4359 if (IS_ERR(chg->apsd_disable_votable)) {
4360 rc = PTR_ERR(chg->apsd_disable_votable);
4361 return rc;
4362 }
4363
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05304364 chg->hvdcp_hw_inov_dis_votable = create_votable("HVDCP_HW_INOV_DIS",
4365 VOTE_SET_ANY,
4366 smblib_hvdcp_hw_inov_dis_vote_callback,
4367 chg);
4368 if (IS_ERR(chg->hvdcp_hw_inov_dis_votable)) {
4369 rc = PTR_ERR(chg->hvdcp_hw_inov_dis_votable);
4370 return rc;
4371 }
4372
Harry Yang4bf7d962017-03-13 16:51:43 -07004373 chg->usb_irq_enable_votable = create_votable("USB_IRQ_DISABLE",
4374 VOTE_SET_ANY,
4375 smblib_usb_irq_enable_vote_callback,
4376 chg);
4377 if (IS_ERR(chg->usb_irq_enable_votable)) {
4378 rc = PTR_ERR(chg->usb_irq_enable_votable);
4379 return rc;
4380 }
4381
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004382 chg->typec_irq_disable_votable = create_votable("TYPEC_IRQ_DISABLE",
4383 VOTE_SET_ANY,
4384 smblib_typec_irq_disable_vote_callback,
4385 chg);
4386 if (IS_ERR(chg->typec_irq_disable_votable)) {
4387 rc = PTR_ERR(chg->typec_irq_disable_votable);
4388 return rc;
4389 }
4390
Nicholas Troast320839e2016-06-03 10:18:00 -07004391 return rc;
4392}
4393
Harry Yangba874ce2016-08-19 14:17:01 -07004394static void smblib_destroy_votables(struct smb_charger *chg)
4395{
Harry Yangba874ce2016-08-19 14:17:01 -07004396 if (chg->dc_suspend_votable)
4397 destroy_votable(chg->dc_suspend_votable);
Harry Yangba874ce2016-08-19 14:17:01 -07004398 if (chg->usb_icl_votable)
4399 destroy_votable(chg->usb_icl_votable);
4400 if (chg->dc_icl_votable)
4401 destroy_votable(chg->dc_icl_votable);
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07004402 if (chg->pd_disallowed_votable_indirect)
4403 destroy_votable(chg->pd_disallowed_votable_indirect);
Harry Yangba874ce2016-08-19 14:17:01 -07004404 if (chg->pd_allowed_votable)
4405 destroy_votable(chg->pd_allowed_votable);
4406 if (chg->awake_votable)
4407 destroy_votable(chg->awake_votable);
Harry Yangaba1f5f2016-09-28 10:47:29 -07004408 if (chg->chg_disable_votable)
4409 destroy_votable(chg->chg_disable_votable);
4410 if (chg->pl_enable_votable_indirect)
4411 destroy_votable(chg->pl_enable_votable_indirect);
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07004412 if (chg->apsd_disable_votable)
4413 destroy_votable(chg->apsd_disable_votable);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05304414 if (chg->hvdcp_hw_inov_dis_votable)
4415 destroy_votable(chg->hvdcp_hw_inov_dis_votable);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004416 if (chg->typec_irq_disable_votable)
4417 destroy_votable(chg->typec_irq_disable_votable);
Harry Yangba874ce2016-08-19 14:17:01 -07004418}
4419
4420static void smblib_iio_deinit(struct smb_charger *chg)
4421{
4422 if (!IS_ERR_OR_NULL(chg->iio.temp_chan))
4423 iio_channel_release(chg->iio.temp_chan);
4424 if (!IS_ERR_OR_NULL(chg->iio.temp_max_chan))
4425 iio_channel_release(chg->iio.temp_max_chan);
4426 if (!IS_ERR_OR_NULL(chg->iio.usbin_i_chan))
4427 iio_channel_release(chg->iio.usbin_i_chan);
4428 if (!IS_ERR_OR_NULL(chg->iio.usbin_v_chan))
4429 iio_channel_release(chg->iio.usbin_v_chan);
Nicholas Troast7dbcad22016-10-05 13:30:18 -07004430 if (!IS_ERR_OR_NULL(chg->iio.batt_i_chan))
4431 iio_channel_release(chg->iio.batt_i_chan);
Harry Yangba874ce2016-08-19 14:17:01 -07004432}
4433
Nicholas Troast320839e2016-06-03 10:18:00 -07004434int smblib_init(struct smb_charger *chg)
4435{
4436 int rc = 0;
4437
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004438 mutex_init(&chg->lock);
Nicholas Troast320839e2016-06-03 10:18:00 -07004439 mutex_init(&chg->write_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004440 mutex_init(&chg->otg_oc_lock);
Nicholas Troast85d3a5a2017-05-03 10:19:43 -07004441 mutex_init(&chg->vconn_oc_lock);
Harry Yangfe913842016-08-10 12:27:28 -07004442 INIT_WORK(&chg->bms_update_work, bms_update_work);
Harry Yang755a34b2016-11-01 01:18:51 -07004443 INIT_WORK(&chg->rdstd_cc2_detach_work, rdstd_cc2_detach_work);
Nicholas Troast320839e2016-06-03 10:18:00 -07004444 INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work);
Harry Yangfe913842016-08-10 12:27:28 -07004445 INIT_DELAYED_WORK(&chg->step_soc_req_work, step_soc_req_work);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004446 INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004447 INIT_WORK(&chg->otg_oc_work, smblib_otg_oc_work);
4448 INIT_WORK(&chg->vconn_oc_work, smblib_vconn_oc_work);
4449 INIT_DELAYED_WORK(&chg->otg_ss_done_work, smblib_otg_ss_done_work);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05304450 INIT_DELAYED_WORK(&chg->icl_change_work, smblib_icl_change_work);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304451 INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004452 INIT_WORK(&chg->legacy_detection_work, smblib_legacy_detection_work);
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07004453 chg->fake_capacity = -EINVAL;
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07004454 chg->fake_input_current_limited = -EINVAL;
Nicholas Troast320839e2016-06-03 10:18:00 -07004455
4456 switch (chg->mode) {
4457 case PARALLEL_MASTER:
Harry Yang0c35ff62017-04-06 00:02:30 -07004458 rc = qcom_batt_init();
4459 if (rc < 0) {
4460 smblib_err(chg, "Couldn't init qcom_batt_init rc=%d\n",
4461 rc);
4462 return rc;
4463 }
4464
Nicholas Troast320839e2016-06-03 10:18:00 -07004465 rc = smblib_create_votables(chg);
4466 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004467 smblib_err(chg, "Couldn't create votables rc=%d\n",
Nicholas Troast320839e2016-06-03 10:18:00 -07004468 rc);
Harry Yang58a9e7a2016-06-23 14:54:43 -07004469 return rc;
Nicholas Troast320839e2016-06-03 10:18:00 -07004470 }
Harry Yang58a9e7a2016-06-23 14:54:43 -07004471
Harry Yang5e1a5222016-07-26 15:16:04 -07004472 rc = smblib_register_notifier(chg);
4473 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004474 smblib_err(chg,
Harry Yang5e1a5222016-07-26 15:16:04 -07004475 "Couldn't register notifier rc=%d\n", rc);
4476 return rc;
Harry Yang58a9e7a2016-06-23 14:54:43 -07004477 }
4478
Harry Yang995b7422016-08-29 16:06:50 -07004479 chg->bms_psy = power_supply_get_by_name("bms");
Ashay Jaiswal8afedfc2017-02-03 11:18:22 +05304480 chg->pl.psy = power_supply_get_by_name("parallel");
Nicholas Troast320839e2016-06-03 10:18:00 -07004481 break;
4482 case PARALLEL_SLAVE:
4483 break;
4484 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004485 smblib_err(chg, "Unsupported mode %d\n", chg->mode);
Nicholas Troast320839e2016-06-03 10:18:00 -07004486 return -EINVAL;
4487 }
4488
4489 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07004490}
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004491
4492int smblib_deinit(struct smb_charger *chg)
4493{
Harry Yangba874ce2016-08-19 14:17:01 -07004494 switch (chg->mode) {
4495 case PARALLEL_MASTER:
Harry Yang0c35ff62017-04-06 00:02:30 -07004496 cancel_work_sync(&chg->bms_update_work);
4497 cancel_work_sync(&chg->rdstd_cc2_detach_work);
4498 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
4499 cancel_delayed_work_sync(&chg->step_soc_req_work);
4500 cancel_delayed_work_sync(&chg->clear_hdc_work);
4501 cancel_work_sync(&chg->otg_oc_work);
4502 cancel_work_sync(&chg->vconn_oc_work);
4503 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4504 cancel_delayed_work_sync(&chg->icl_change_work);
4505 cancel_delayed_work_sync(&chg->pl_enable_work);
4506 cancel_work_sync(&chg->legacy_detection_work);
Harry Yangba874ce2016-08-19 14:17:01 -07004507 power_supply_unreg_notifier(&chg->nb);
4508 smblib_destroy_votables(chg);
Harry Yang0c35ff62017-04-06 00:02:30 -07004509 qcom_batt_deinit();
Harry Yangba874ce2016-08-19 14:17:01 -07004510 break;
4511 case PARALLEL_SLAVE:
4512 break;
4513 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004514 smblib_err(chg, "Unsupported mode %d\n", chg->mode);
Harry Yangba874ce2016-08-19 14:17:01 -07004515 return -EINVAL;
4516 }
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004517
Harry Yangba874ce2016-08-19 14:17:01 -07004518 smblib_iio_deinit(chg);
Harry Yang5e1a5222016-07-26 15:16:04 -07004519
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004520 return 0;
4521}