blob: b1070e82b66a2da67af05c0ac6a17c054d7f5d4c [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);
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07001215 u8 otg_stat, val;
Nicholas Troastb11015f2017-01-17 17:56:45 -08001216 int rc = 0, i;
Nicholas Troast8995a702016-12-05 10:22:22 -08001217
1218 if (!chg->external_vconn) {
Nicholas Troastb11015f2017-01-17 17:56:45 -08001219 /*
1220 * Hardware based OTG soft start should complete within 1ms, so
1221 * wait for 2ms in the worst case.
1222 */
1223 for (i = 0; i < MAX_OTG_SS_TRIES; ++i) {
1224 usleep_range(1000, 1100);
1225 rc = smblib_read(chg, OTG_STATUS_REG, &otg_stat);
1226 if (rc < 0) {
1227 smblib_err(chg, "Couldn't read OTG status rc=%d\n",
1228 rc);
1229 return rc;
1230 }
1231
1232 if (otg_stat & BOOST_SOFTSTART_DONE_BIT)
1233 break;
Nicholas Troast8995a702016-12-05 10:22:22 -08001234 }
1235
Nicholas Troastb11015f2017-01-17 17:56:45 -08001236 if (!(otg_stat & BOOST_SOFTSTART_DONE_BIT)) {
1237 smblib_err(chg, "Couldn't enable VCONN; OTG soft start failed\n");
Nicholas Troast8995a702016-12-05 10:22:22 -08001238 return -EAGAIN;
1239 }
1240 }
1241
1242 /*
1243 * VCONN_EN_ORIENTATION is overloaded with overriding the CC pin used
1244 * for Vconn, and it should be set with reverse polarity of CC_OUT.
1245 */
Nicholas Troastb11015f2017-01-17 17:56:45 -08001246 smblib_dbg(chg, PR_OTG, "enabling VCONN\n");
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07001247 val = chg->typec_status[3] &
1248 CC_ORIENTATION_BIT ? 0 : VCONN_EN_ORIENTATION_BIT;
Nicholas Troast8995a702016-12-05 10:22:22 -08001249 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1250 VCONN_EN_VALUE_BIT | VCONN_EN_ORIENTATION_BIT,
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07001251 VCONN_EN_VALUE_BIT | val);
Nicholas Troast8995a702016-12-05 10:22:22 -08001252 if (rc < 0) {
1253 smblib_err(chg, "Couldn't enable vconn setting rc=%d\n", rc);
1254 return rc;
1255 }
1256
1257 return rc;
1258}
1259
1260int smblib_vconn_regulator_enable(struct regulator_dev *rdev)
1261{
1262 struct smb_charger *chg = rdev_get_drvdata(rdev);
1263 int rc = 0;
1264
Nicholas Troastb11015f2017-01-17 17:56:45 -08001265 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001266 if (chg->vconn_en)
1267 goto unlock;
1268
1269 rc = _smblib_vconn_regulator_enable(rdev);
1270 if (rc >= 0)
1271 chg->vconn_en = true;
1272
1273unlock:
Nicholas Troastb11015f2017-01-17 17:56:45 -08001274 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001275 return rc;
1276}
1277
1278static int _smblib_vconn_regulator_disable(struct regulator_dev *rdev)
1279{
1280 struct smb_charger *chg = rdev_get_drvdata(rdev);
1281 int rc = 0;
1282
Nicholas Troastb11015f2017-01-17 17:56:45 -08001283 smblib_dbg(chg, PR_OTG, "disabling VCONN\n");
Nicholas Troast8995a702016-12-05 10:22:22 -08001284 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1285 VCONN_EN_VALUE_BIT, 0);
1286 if (rc < 0)
1287 smblib_err(chg, "Couldn't disable vconn regulator rc=%d\n", rc);
1288
1289 return rc;
1290}
1291
1292int smblib_vconn_regulator_disable(struct regulator_dev *rdev)
1293{
1294 struct smb_charger *chg = rdev_get_drvdata(rdev);
1295 int rc = 0;
1296
Nicholas Troastb11015f2017-01-17 17:56:45 -08001297 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001298 if (!chg->vconn_en)
1299 goto unlock;
1300
1301 rc = _smblib_vconn_regulator_disable(rdev);
1302 if (rc >= 0)
1303 chg->vconn_en = false;
1304
1305unlock:
Nicholas Troastb11015f2017-01-17 17:56:45 -08001306 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001307 return rc;
1308}
1309
1310int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev)
1311{
1312 struct smb_charger *chg = rdev_get_drvdata(rdev);
1313 int ret;
1314
Nicholas Troastb11015f2017-01-17 17:56:45 -08001315 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001316 ret = chg->vconn_en;
Nicholas Troastb11015f2017-01-17 17:56:45 -08001317 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001318 return ret;
1319}
1320
Nicholas Troast34db5032016-03-28 12:26:44 -07001321/*****************
1322 * OTG REGULATOR *
1323 *****************/
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301324#define MAX_RETRY 15
1325#define MIN_DELAY_US 2000
1326#define MAX_DELAY_US 9000
Nicholas Troast8995a702016-12-05 10:22:22 -08001327static int _smblib_vbus_regulator_enable(struct regulator_dev *rdev)
Nicholas Troast34db5032016-03-28 12:26:44 -07001328{
1329 struct smb_charger *chg = rdev_get_drvdata(rdev);
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301330 int rc, retry_count = 0, min_delay = MIN_DELAY_US;
1331 u8 stat;
Nicholas Troast34db5032016-03-28 12:26:44 -07001332
Nicholas Troastb11015f2017-01-17 17:56:45 -08001333 smblib_dbg(chg, PR_OTG, "halt 1 in 8 mode\n");
Harry Yang360bd532016-09-26 11:03:22 -07001334 rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
1335 ENG_BUCKBOOST_HALT1_8_MODE_BIT,
1336 ENG_BUCKBOOST_HALT1_8_MODE_BIT);
1337 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001338 smblib_err(chg, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n",
Harry Yang360bd532016-09-26 11:03:22 -07001339 rc);
1340 return rc;
1341 }
1342
Nicholas Troastb11015f2017-01-17 17:56:45 -08001343 smblib_dbg(chg, PR_OTG, "enabling OTG\n");
Harry Yang360bd532016-09-26 11:03:22 -07001344 rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT);
1345 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001346 smblib_err(chg, "Couldn't enable OTG regulator rc=%d\n", rc);
Harry Yang360bd532016-09-26 11:03:22 -07001347 return rc;
1348 }
1349
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301350 if (chg->wa_flags & OTG_WA) {
1351 /* check for softstart */
1352 do {
1353 usleep_range(min_delay, min_delay + 100);
1354 rc = smblib_read(chg, OTG_STATUS_REG, &stat);
1355 if (rc < 0) {
1356 smblib_err(chg,
1357 "Couldn't read OTG status rc=%d\n",
1358 rc);
1359 goto out;
1360 }
1361
1362 if (stat & BOOST_SOFTSTART_DONE_BIT) {
1363 rc = smblib_set_charge_param(chg,
1364 &chg->param.otg_cl, chg->otg_cl_ua);
1365 if (rc < 0)
1366 smblib_err(chg,
1367 "Couldn't set otg limit\n");
1368 break;
1369 }
1370
1371 /* increase the delay for following iterations */
1372 if (retry_count > 5)
1373 min_delay = MAX_DELAY_US;
1374 } while (retry_count++ < MAX_RETRY);
1375
1376 if (retry_count >= MAX_RETRY) {
1377 smblib_dbg(chg, PR_OTG, "Boost Softstart not done\n");
1378 goto out;
1379 }
1380 }
1381
1382 return 0;
1383out:
1384 /* disable OTG if softstart failed */
1385 smblib_write(chg, CMD_OTG_REG, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07001386 return rc;
1387}
1388
Nicholas Troast8995a702016-12-05 10:22:22 -08001389int smblib_vbus_regulator_enable(struct regulator_dev *rdev)
Nicholas Troast34db5032016-03-28 12:26:44 -07001390{
1391 struct smb_charger *chg = rdev_get_drvdata(rdev);
1392 int rc = 0;
1393
Nicholas Troastb11015f2017-01-17 17:56:45 -08001394 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001395 if (chg->otg_en)
1396 goto unlock;
1397
Harry Yanga2fb0e32017-03-22 22:45:25 -07001398 if (!chg->usb_icl_votable) {
1399 chg->usb_icl_votable = find_votable("USB_ICL");
1400
1401 if (!chg->usb_icl_votable)
1402 return -EINVAL;
1403 }
1404 vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, true, 0);
1405
Nicholas Troast8995a702016-12-05 10:22:22 -08001406 rc = _smblib_vbus_regulator_enable(rdev);
1407 if (rc >= 0)
1408 chg->otg_en = true;
1409
1410unlock:
Nicholas Troastb11015f2017-01-17 17:56:45 -08001411 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001412 return rc;
1413}
1414
1415static int _smblib_vbus_regulator_disable(struct regulator_dev *rdev)
1416{
1417 struct smb_charger *chg = rdev_get_drvdata(rdev);
1418 int rc;
Nicholas Troast8995a702016-12-05 10:22:22 -08001419
Nicholas Troastb11015f2017-01-17 17:56:45 -08001420 if (!chg->external_vconn && chg->vconn_en) {
1421 smblib_dbg(chg, PR_OTG, "Killing VCONN before disabling OTG\n");
1422 rc = _smblib_vconn_regulator_disable(rdev);
Nicholas Troast07a69002017-01-20 13:52:10 -08001423 if (rc < 0)
Nicholas Troastb11015f2017-01-17 17:56:45 -08001424 smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc);
Nicholas Troast8995a702016-12-05 10:22:22 -08001425 }
1426
Ashay Jaiswal7c241382017-03-06 15:26:38 +05301427 if (chg->wa_flags & OTG_WA) {
1428 /* set OTG current limit to minimum value */
1429 rc = smblib_set_charge_param(chg, &chg->param.otg_cl,
1430 chg->param.otg_cl.min_u);
1431 if (rc < 0) {
1432 smblib_err(chg,
1433 "Couldn't set otg current limit rc=%d\n", rc);
1434 return rc;
1435 }
1436 }
1437
Nicholas Troastb11015f2017-01-17 17:56:45 -08001438 smblib_dbg(chg, PR_OTG, "disabling OTG\n");
Harry Yang360bd532016-09-26 11:03:22 -07001439 rc = smblib_write(chg, CMD_OTG_REG, 0);
1440 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001441 smblib_err(chg, "Couldn't disable OTG regulator rc=%d\n", rc);
Harry Yang360bd532016-09-26 11:03:22 -07001442 return rc;
1443 }
1444
Nicholas Troastb11015f2017-01-17 17:56:45 -08001445 smblib_dbg(chg, PR_OTG, "start 1 in 8 mode\n");
Harry Yang360bd532016-09-26 11:03:22 -07001446 rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
1447 ENG_BUCKBOOST_HALT1_8_MODE_BIT, 0);
1448 if (rc < 0) {
Nicholas Troast8995a702016-12-05 10:22:22 -08001449 smblib_err(chg, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n", rc);
Harry Yang360bd532016-09-26 11:03:22 -07001450 return rc;
1451 }
1452
Nicholas Troast8995a702016-12-05 10:22:22 -08001453 return 0;
1454}
Nicholas Troast34db5032016-03-28 12:26:44 -07001455
Nicholas Troast8995a702016-12-05 10:22:22 -08001456int smblib_vbus_regulator_disable(struct regulator_dev *rdev)
1457{
1458 struct smb_charger *chg = rdev_get_drvdata(rdev);
1459 int rc = 0;
1460
Nicholas Troastb11015f2017-01-17 17:56:45 -08001461 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001462 if (!chg->otg_en)
1463 goto unlock;
1464
1465 rc = _smblib_vbus_regulator_disable(rdev);
1466 if (rc >= 0)
1467 chg->otg_en = false;
1468
Harry Yanga2fb0e32017-03-22 22:45:25 -07001469 if (chg->usb_icl_votable)
1470 vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0);
Nicholas Troast8995a702016-12-05 10:22:22 -08001471unlock:
Nicholas Troastb11015f2017-01-17 17:56:45 -08001472 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07001473 return rc;
1474}
1475
1476int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev)
1477{
1478 struct smb_charger *chg = rdev_get_drvdata(rdev);
Nicholas Troast8995a702016-12-05 10:22:22 -08001479 int ret;
Nicholas Troast34db5032016-03-28 12:26:44 -07001480
Nicholas Troastb11015f2017-01-17 17:56:45 -08001481 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001482 ret = chg->otg_en;
Nicholas Troastb11015f2017-01-17 17:56:45 -08001483 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001484 return ret;
Nicholas Troast34db5032016-03-28 12:26:44 -07001485}
1486
1487/********************
1488 * BATT PSY GETTERS *
1489 ********************/
1490
1491int smblib_get_prop_input_suspend(struct smb_charger *chg,
1492 union power_supply_propval *val)
1493{
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08001494 val->intval
1495 = (get_client_vote(chg->usb_icl_votable, USER_VOTER) == 0)
1496 && get_client_vote(chg->dc_suspend_votable, USER_VOTER);
Nicholas Troast34db5032016-03-28 12:26:44 -07001497 return 0;
1498}
1499
1500int smblib_get_prop_batt_present(struct smb_charger *chg,
1501 union power_supply_propval *val)
1502{
1503 int rc;
1504 u8 stat;
1505
1506 rc = smblib_read(chg, BATIF_BASE + INT_RT_STS_OFFSET, &stat);
1507 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001508 smblib_err(chg, "Couldn't read BATIF_INT_RT_STS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07001509 return rc;
1510 }
1511
1512 val->intval = !(stat & (BAT_THERM_OR_ID_MISSING_RT_STS_BIT
1513 | BAT_TERMINAL_MISSING_RT_STS_BIT));
1514
1515 return rc;
1516}
1517
1518int smblib_get_prop_batt_capacity(struct smb_charger *chg,
1519 union power_supply_propval *val)
1520{
Harry Yang5e1a5222016-07-26 15:16:04 -07001521 int rc = -EINVAL;
1522
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07001523 if (chg->fake_capacity >= 0) {
1524 val->intval = chg->fake_capacity;
1525 return 0;
1526 }
1527
Harry Yang5e1a5222016-07-26 15:16:04 -07001528 if (chg->bms_psy)
1529 rc = power_supply_get_property(chg->bms_psy,
1530 POWER_SUPPLY_PROP_CAPACITY, val);
1531 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001532}
1533
1534int smblib_get_prop_batt_status(struct smb_charger *chg,
1535 union power_supply_propval *val)
1536{
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001537 union power_supply_propval pval = {0, };
1538 bool usb_online, dc_online;
Nicholas Troast8cb77552016-09-23 11:50:18 -07001539 u8 stat;
1540 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001541
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001542 rc = smblib_get_prop_usb_online(chg, &pval);
1543 if (rc < 0) {
1544 smblib_err(chg, "Couldn't get usb online property rc=%d\n",
1545 rc);
1546 return rc;
1547 }
1548 usb_online = (bool)pval.intval;
1549
1550 rc = smblib_get_prop_dc_online(chg, &pval);
1551 if (rc < 0) {
1552 smblib_err(chg, "Couldn't get dc online property rc=%d\n",
1553 rc);
1554 return rc;
1555 }
1556 dc_online = (bool)pval.intval;
1557
Nicholas Troast34db5032016-03-28 12:26:44 -07001558 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1559 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001560 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001561 rc);
1562 return rc;
1563 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001564 stat = stat & BATTERY_CHARGER_STATUS_MASK;
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001565
1566 if (!usb_online && !dc_online) {
1567 switch (stat) {
1568 case TERMINATE_CHARGE:
1569 case INHIBIT_CHARGE:
1570 val->intval = POWER_SUPPLY_STATUS_FULL;
1571 break;
1572 default:
1573 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
1574 break;
1575 }
1576 return rc;
1577 }
1578
Nicholas Troast8cb77552016-09-23 11:50:18 -07001579 switch (stat) {
1580 case TRICKLE_CHARGE:
1581 case PRE_CHARGE:
1582 case FAST_CHARGE:
1583 case FULLON_CHARGE:
1584 case TAPER_CHARGE:
Nicholas Troast34db5032016-03-28 12:26:44 -07001585 val->intval = POWER_SUPPLY_STATUS_CHARGING;
Nicholas Troast8cb77552016-09-23 11:50:18 -07001586 break;
1587 case TERMINATE_CHARGE:
1588 case INHIBIT_CHARGE:
1589 val->intval = POWER_SUPPLY_STATUS_FULL;
1590 break;
1591 case DISABLE_CHARGE:
1592 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
1593 break;
1594 default:
1595 val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
1596 break;
1597 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001598
Harry Yang7ecc1a12017-04-06 12:24:56 -07001599 if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
1600 return 0;
1601
Harry Yangc3c28d12017-04-17 16:41:19 -07001602 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_7_REG, &stat);
Harry Yang7ecc1a12017-04-06 12:24:56 -07001603 if (rc < 0) {
1604 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
1605 rc);
1606 return rc;
1607 }
1608
Harry Yangc3c28d12017-04-17 16:41:19 -07001609 stat &= ENABLE_TRICKLE_BIT | ENABLE_PRE_CHARGING_BIT |
1610 ENABLE_FAST_CHARGING_BIT | ENABLE_FULLON_MODE_BIT;
1611 if (!stat)
Harry Yang7ecc1a12017-04-06 12:24:56 -07001612 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
1613
Nicholas Troast8cb77552016-09-23 11:50:18 -07001614 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07001615}
1616
1617int smblib_get_prop_batt_charge_type(struct smb_charger *chg,
1618 union power_supply_propval *val)
1619{
1620 int rc;
1621 u8 stat;
1622
1623 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1624 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001625 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001626 rc);
1627 return rc;
1628 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001629
1630 switch (stat & BATTERY_CHARGER_STATUS_MASK) {
1631 case TRICKLE_CHARGE:
1632 case PRE_CHARGE:
1633 val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1634 break;
1635 case FAST_CHARGE:
1636 case FULLON_CHARGE:
1637 val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
1638 break;
1639 case TAPER_CHARGE:
1640 val->intval = POWER_SUPPLY_CHARGE_TYPE_TAPER;
1641 break;
1642 default:
1643 val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
1644 }
1645
1646 return rc;
1647}
1648
1649int smblib_get_prop_batt_health(struct smb_charger *chg,
1650 union power_supply_propval *val)
1651{
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001652 union power_supply_propval pval;
Nicholas Troast34db5032016-03-28 12:26:44 -07001653 int rc;
1654 u8 stat;
1655
1656 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat);
1657 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001658 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001659 rc);
1660 return rc;
1661 }
1662 smblib_dbg(chg, PR_REGISTER, "BATTERY_CHARGER_STATUS_2 = 0x%02x\n",
1663 stat);
1664
1665 if (stat & CHARGER_ERROR_STATUS_BAT_OV_BIT) {
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001666 rc = smblib_get_prop_batt_voltage_now(chg, &pval);
1667 if (!rc) {
1668 /*
1669 * If Vbatt is within 40mV above Vfloat, then don't
1670 * treat it as overvoltage.
1671 */
1672 if (pval.intval >=
1673 get_effective_result(chg->fv_votable) + 40000) {
1674 val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
1675 smblib_err(chg, "battery over-voltage\n");
1676 goto done;
1677 }
1678 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001679 }
1680
Harry Yang668fc5e2016-07-12 16:51:47 -07001681 if (stat & BAT_TEMP_STATUS_TOO_COLD_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001682 val->intval = POWER_SUPPLY_HEALTH_COLD;
Harry Yang668fc5e2016-07-12 16:51:47 -07001683 else if (stat & BAT_TEMP_STATUS_TOO_HOT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001684 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
Harry Yang668fc5e2016-07-12 16:51:47 -07001685 else if (stat & BAT_TEMP_STATUS_COLD_SOFT_LIMIT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001686 val->intval = POWER_SUPPLY_HEALTH_COOL;
Harry Yang668fc5e2016-07-12 16:51:47 -07001687 else if (stat & BAT_TEMP_STATUS_HOT_SOFT_LIMIT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001688 val->intval = POWER_SUPPLY_HEALTH_WARM;
Harry Yang668fc5e2016-07-12 16:51:47 -07001689 else
Nicholas Troast34db5032016-03-28 12:26:44 -07001690 val->intval = POWER_SUPPLY_HEALTH_GOOD;
Nicholas Troast34db5032016-03-28 12:26:44 -07001691
1692done:
1693 return rc;
1694}
1695
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001696int smblib_get_prop_system_temp_level(struct smb_charger *chg,
1697 union power_supply_propval *val)
1698{
1699 val->intval = chg->system_temp_level;
1700 return 0;
1701}
1702
Abhijeet Dharmapurikaracf32002017-05-11 11:54:17 -07001703int smblib_get_prop_system_temp_level_max(struct smb_charger *chg,
1704 union power_supply_propval *val)
1705{
1706 val->intval = chg->thermal_levels;
1707 return 0;
1708}
1709
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001710int smblib_get_prop_input_current_limited(struct smb_charger *chg,
1711 union power_supply_propval *val)
1712{
1713 u8 stat;
1714 int rc;
1715
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07001716 if (chg->fake_input_current_limited >= 0) {
1717 val->intval = chg->fake_input_current_limited;
1718 return 0;
1719 }
1720
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001721 rc = smblib_read(chg, AICL_STATUS_REG, &stat);
1722 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001723 smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n", rc);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001724 return rc;
1725 }
1726 val->intval = (stat & SOFT_ILIMIT_BIT) || chg->is_hdc;
1727 return 0;
1728}
1729
Nicholas Troast66b21d72016-09-20 15:33:20 -07001730int smblib_get_prop_batt_voltage_now(struct smb_charger *chg,
1731 union power_supply_propval *val)
1732{
1733 int rc;
1734
1735 if (!chg->bms_psy)
1736 return -EINVAL;
1737
1738 rc = power_supply_get_property(chg->bms_psy,
1739 POWER_SUPPLY_PROP_VOLTAGE_NOW, val);
1740 return rc;
1741}
1742
1743int smblib_get_prop_batt_current_now(struct smb_charger *chg,
1744 union power_supply_propval *val)
1745{
1746 int rc;
1747
1748 if (!chg->bms_psy)
1749 return -EINVAL;
1750
1751 rc = power_supply_get_property(chg->bms_psy,
1752 POWER_SUPPLY_PROP_CURRENT_NOW, val);
1753 return rc;
1754}
1755
1756int smblib_get_prop_batt_temp(struct smb_charger *chg,
1757 union power_supply_propval *val)
1758{
1759 int rc;
1760
1761 if (!chg->bms_psy)
1762 return -EINVAL;
1763
1764 rc = power_supply_get_property(chg->bms_psy,
1765 POWER_SUPPLY_PROP_TEMP, val);
1766 return rc;
1767}
1768
Harry Yangbedee332016-08-31 16:14:29 -07001769int smblib_get_prop_step_chg_step(struct smb_charger *chg,
1770 union power_supply_propval *val)
1771{
1772 int rc;
1773 u8 stat;
1774
1775 if (!chg->step_chg_enabled) {
1776 val->intval = -1;
1777 return 0;
1778 }
1779
1780 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1781 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001782 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Harry Yangbedee332016-08-31 16:14:29 -07001783 rc);
1784 return rc;
1785 }
1786
1787 val->intval = (stat & STEP_CHARGING_STATUS_MASK) >>
1788 STEP_CHARGING_STATUS_SHIFT;
1789
1790 return rc;
1791}
1792
Subbaraman Narayanamurthyb491d022016-10-10 20:22:48 -07001793int smblib_get_prop_batt_charge_done(struct smb_charger *chg,
1794 union power_supply_propval *val)
1795{
1796 int rc;
1797 u8 stat;
1798
1799 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1800 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001801 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Subbaraman Narayanamurthyb491d022016-10-10 20:22:48 -07001802 rc);
1803 return rc;
1804 }
1805
1806 stat = stat & BATTERY_CHARGER_STATUS_MASK;
1807 val->intval = (stat == TERMINATE_CHARGE);
1808 return 0;
1809}
1810
Harry Yang40192cb2017-02-25 23:25:17 -08001811int smblib_get_prop_charge_qnovo_enable(struct smb_charger *chg,
1812 union power_supply_propval *val)
1813{
1814 int rc;
1815 u8 stat;
1816
1817 rc = smblib_read(chg, QNOVO_PT_ENABLE_CMD_REG, &stat);
1818 if (rc < 0) {
1819 smblib_err(chg, "Couldn't read QNOVO_PT_ENABLE_CMD rc=%d\n",
1820 rc);
1821 return rc;
1822 }
1823
1824 val->intval = (bool)(stat & QNOVO_PT_ENABLE_CMD_BIT);
1825 return 0;
1826}
1827
Nicholas Troast34db5032016-03-28 12:26:44 -07001828/***********************
1829 * BATTERY PSY SETTERS *
1830 ***********************/
1831
1832int smblib_set_prop_input_suspend(struct smb_charger *chg,
1833 const union power_supply_propval *val)
1834{
1835 int rc;
1836
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08001837 /* vote 0mA when suspended */
1838 rc = vote(chg->usb_icl_votable, USER_VOTER, (bool)val->intval, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07001839 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001840 smblib_err(chg, "Couldn't vote to %s USB rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001841 (bool)val->intval ? "suspend" : "resume", rc);
1842 return rc;
1843 }
1844
1845 rc = vote(chg->dc_suspend_votable, USER_VOTER, (bool)val->intval, 0);
1846 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001847 smblib_err(chg, "Couldn't vote to %s DC rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001848 (bool)val->intval ? "suspend" : "resume", rc);
1849 return rc;
1850 }
1851
Nicholas Troast61ff40f2016-07-08 10:59:22 -07001852 power_supply_changed(chg->batt_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07001853 return rc;
1854}
1855
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07001856int smblib_set_prop_batt_capacity(struct smb_charger *chg,
1857 const union power_supply_propval *val)
1858{
1859 chg->fake_capacity = val->intval;
1860
1861 power_supply_changed(chg->batt_psy);
1862
1863 return 0;
1864}
1865
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001866int smblib_set_prop_system_temp_level(struct smb_charger *chg,
1867 const union power_supply_propval *val)
1868{
1869 if (val->intval < 0)
1870 return -EINVAL;
1871
1872 if (chg->thermal_levels <= 0)
1873 return -EINVAL;
1874
1875 if (val->intval > chg->thermal_levels)
1876 return -EINVAL;
1877
1878 chg->system_temp_level = val->intval;
Ashay Jaiswal147a6c32017-03-28 17:19:47 +05301879 /* disable parallel charge in case of system temp level */
1880 vote(chg->pl_disable_votable, THERMAL_DAEMON_VOTER,
1881 chg->system_temp_level ? true : false, 0);
1882
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001883 if (chg->system_temp_level == chg->thermal_levels)
Harry Yangaba1f5f2016-09-28 10:47:29 -07001884 return vote(chg->chg_disable_votable,
1885 THERMAL_DAEMON_VOTER, true, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001886
Harry Yangaba1f5f2016-09-28 10:47:29 -07001887 vote(chg->chg_disable_votable, THERMAL_DAEMON_VOTER, false, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001888 if (chg->system_temp_level == 0)
Harry Yangaba1f5f2016-09-28 10:47:29 -07001889 return vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, false, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001890
Harry Yangaba1f5f2016-09-28 10:47:29 -07001891 vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, true,
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001892 chg->thermal_mitigation[chg->system_temp_level]);
1893 return 0;
1894}
1895
Harry Yang40192cb2017-02-25 23:25:17 -08001896int smblib_set_prop_charge_qnovo_enable(struct smb_charger *chg,
1897 const union power_supply_propval *val)
1898{
1899 int rc = 0;
1900
1901 rc = smblib_masked_write(chg, QNOVO_PT_ENABLE_CMD_REG,
1902 QNOVO_PT_ENABLE_CMD_BIT,
1903 val->intval ? QNOVO_PT_ENABLE_CMD_BIT : 0);
1904 if (rc < 0) {
1905 dev_err(chg->dev, "Couldn't enable qnovo rc=%d\n", rc);
1906 return rc;
1907 }
1908
1909 return rc;
1910}
1911
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07001912int smblib_set_prop_input_current_limited(struct smb_charger *chg,
1913 const union power_supply_propval *val)
1914{
1915 chg->fake_input_current_limited = val->intval;
1916 return 0;
1917}
1918
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301919int smblib_rerun_aicl(struct smb_charger *chg)
1920{
Nicholas Troast20ae1912017-02-15 10:15:32 -08001921 int rc, settled_icl_ua;
1922 u8 stat;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301923
Nicholas Troast20ae1912017-02-15 10:15:32 -08001924 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
1925 if (rc < 0) {
1926 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
1927 rc);
1928 return rc;
1929 }
1930
1931 /* USB is suspended so skip re-running AICL */
1932 if (stat & USBIN_SUSPEND_STS_BIT)
1933 return rc;
1934
1935 smblib_dbg(chg, PR_MISC, "re-running AICL\n");
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301936 switch (chg->smb_version) {
1937 case PMI8998_SUBTYPE:
Nicholas Troast20ae1912017-02-15 10:15:32 -08001938 rc = smblib_get_charge_param(chg, &chg->param.icl_stat,
1939 &settled_icl_ua);
1940 if (rc < 0) {
1941 smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
1942 return rc;
1943 }
1944
1945 vote(chg->usb_icl_votable, AICL_RERUN_VOTER, true,
1946 max(settled_icl_ua - chg->param.usb_icl.step_u,
1947 chg->param.usb_icl.step_u));
1948 vote(chg->usb_icl_votable, AICL_RERUN_VOTER, false, 0);
1949 break;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301950 case PM660_SUBTYPE:
Nicholas Troast20ae1912017-02-15 10:15:32 -08001951 /*
1952 * Use restart_AICL instead of trigger_AICL as it runs the
1953 * complete AICL instead of starting from the last settled
1954 * value.
1955 */
1956 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG,
1957 RESTART_AICL_BIT, RESTART_AICL_BIT);
1958 if (rc < 0)
1959 smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
1960 rc);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301961 break;
1962 default:
1963 smblib_dbg(chg, PR_PARALLEL, "unknown SMB chip %d\n",
1964 chg->smb_version);
1965 return -EINVAL;
1966 }
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301967
Nicholas Troast20ae1912017-02-15 10:15:32 -08001968 return 0;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05301969}
1970
1971static int smblib_dp_pulse(struct smb_charger *chg)
1972{
1973 int rc;
1974
1975 /* QC 3.0 increment */
1976 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, SINGLE_INCREMENT_BIT,
1977 SINGLE_INCREMENT_BIT);
1978 if (rc < 0)
1979 smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
1980 rc);
1981
1982 return rc;
1983}
1984
1985static int smblib_dm_pulse(struct smb_charger *chg)
1986{
1987 int rc;
1988
1989 /* QC 3.0 decrement */
1990 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, SINGLE_DECREMENT_BIT,
1991 SINGLE_DECREMENT_BIT);
1992 if (rc < 0)
1993 smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
1994 rc);
1995
1996 return rc;
1997}
1998
1999int smblib_dp_dm(struct smb_charger *chg, int val)
2000{
2001 int target_icl_ua, rc = 0;
2002
2003 switch (val) {
2004 case POWER_SUPPLY_DP_DM_DP_PULSE:
2005 rc = smblib_dp_pulse(chg);
2006 if (!rc)
2007 chg->pulse_cnt++;
2008 smblib_dbg(chg, PR_PARALLEL, "DP_DM_DP_PULSE rc=%d cnt=%d\n",
2009 rc, chg->pulse_cnt);
2010 break;
2011 case POWER_SUPPLY_DP_DM_DM_PULSE:
2012 rc = smblib_dm_pulse(chg);
2013 if (!rc && chg->pulse_cnt)
2014 chg->pulse_cnt--;
2015 smblib_dbg(chg, PR_PARALLEL, "DP_DM_DM_PULSE rc=%d cnt=%d\n",
2016 rc, chg->pulse_cnt);
2017 break;
2018 case POWER_SUPPLY_DP_DM_ICL_DOWN:
2019 chg->usb_icl_delta_ua -= 100000;
2020 target_icl_ua = get_effective_result(chg->usb_icl_votable);
2021 vote(chg->usb_icl_votable, SW_QC3_VOTER, true,
2022 target_icl_ua + chg->usb_icl_delta_ua);
2023 break;
2024 case POWER_SUPPLY_DP_DM_ICL_UP:
2025 default:
2026 break;
2027 }
2028
2029 return rc;
2030}
2031
Nicholas Troast34db5032016-03-28 12:26:44 -07002032/*******************
Harry Yangf3023592016-07-20 14:56:41 -07002033 * DC PSY GETTERS *
2034 *******************/
2035
2036int smblib_get_prop_dc_present(struct smb_charger *chg,
2037 union power_supply_propval *val)
2038{
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002039 int rc;
Harry Yangf3023592016-07-20 14:56:41 -07002040 u8 stat;
2041
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002042 rc = smblib_read(chg, DCIN_BASE + INT_RT_STS_OFFSET, &stat);
Harry Yangf3023592016-07-20 14:56:41 -07002043 if (rc < 0) {
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002044 smblib_err(chg, "Couldn't read DCIN_RT_STS rc=%d\n", rc);
Harry Yangf3023592016-07-20 14:56:41 -07002045 return rc;
2046 }
Harry Yangf3023592016-07-20 14:56:41 -07002047
2048 val->intval = (bool)(stat & DCIN_PLUGIN_RT_STS_BIT);
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002049 return 0;
Harry Yangf3023592016-07-20 14:56:41 -07002050}
2051
2052int smblib_get_prop_dc_online(struct smb_charger *chg,
2053 union power_supply_propval *val)
2054{
2055 int rc = 0;
2056 u8 stat;
2057
2058 if (get_client_vote(chg->dc_suspend_votable, USER_VOTER)) {
2059 val->intval = false;
2060 return rc;
2061 }
2062
2063 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
2064 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002065 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
Harry Yangf3023592016-07-20 14:56:41 -07002066 rc);
2067 return rc;
2068 }
2069 smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
2070 stat);
2071
2072 val->intval = (stat & USE_DCIN_BIT) &&
Vic Wei7ade2842016-12-14 18:47:49 -08002073 (stat & VALID_INPUT_POWER_SOURCE_STS_BIT);
Harry Yangf3023592016-07-20 14:56:41 -07002074
2075 return rc;
2076}
2077
2078int smblib_get_prop_dc_current_max(struct smb_charger *chg,
2079 union power_supply_propval *val)
2080{
2081 val->intval = get_effective_result_locked(chg->dc_icl_votable);
2082 return 0;
2083}
2084
2085/*******************
Harry Yangd89ff1f2016-12-05 14:59:11 -08002086 * DC PSY SETTERS *
Harry Yangf3023592016-07-20 14:56:41 -07002087 * *****************/
2088
2089int smblib_set_prop_dc_current_max(struct smb_charger *chg,
2090 const union power_supply_propval *val)
2091{
2092 int rc;
2093
2094 rc = vote(chg->dc_icl_votable, USER_VOTER, true, val->intval);
2095 return rc;
2096}
2097
2098/*******************
Nicholas Troast34db5032016-03-28 12:26:44 -07002099 * USB PSY GETTERS *
2100 *******************/
2101
2102int smblib_get_prop_usb_present(struct smb_charger *chg,
2103 union power_supply_propval *val)
2104{
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002105 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07002106 u8 stat;
2107
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002108 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
Nicholas Troast34db5032016-03-28 12:26:44 -07002109 if (rc < 0) {
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002110 smblib_err(chg, "Couldn't read USBIN_RT_STS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07002111 return rc;
2112 }
Nicholas Troast34db5032016-03-28 12:26:44 -07002113
Nicholas Troastdeae99c2016-11-14 09:13:01 -08002114 val->intval = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
2115 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002116}
2117
2118int smblib_get_prop_usb_online(struct smb_charger *chg,
2119 union power_supply_propval *val)
2120{
2121 int rc = 0;
2122 u8 stat;
2123
Abhijeet Dharmapurikar84923af2017-03-23 14:07:07 -07002124 if (get_client_vote_locked(chg->usb_icl_votable, USER_VOTER) == 0) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002125 val->intval = false;
2126 return rc;
2127 }
2128
2129 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
2130 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002131 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002132 rc);
2133 return rc;
2134 }
2135 smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
2136 stat);
2137
2138 val->intval = (stat & USE_USBIN_BIT) &&
Vic Wei7ade2842016-12-14 18:47:49 -08002139 (stat & VALID_INPUT_POWER_SOURCE_STS_BIT);
Nicholas Troast34db5032016-03-28 12:26:44 -07002140 return rc;
2141}
2142
2143int smblib_get_prop_usb_voltage_now(struct smb_charger *chg,
2144 union power_supply_propval *val)
2145{
Harry Yangba874ce2016-08-19 14:17:01 -07002146 int rc = 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002147
Harry Yangba874ce2016-08-19 14:17:01 -07002148 rc = smblib_get_prop_usb_present(chg, val);
2149 if (rc < 0 || !val->intval)
2150 return rc;
2151
2152 if (!chg->iio.usbin_v_chan ||
2153 PTR_ERR(chg->iio.usbin_v_chan) == -EPROBE_DEFER)
2154 chg->iio.usbin_v_chan = iio_channel_get(chg->dev, "usbin_v");
2155
2156 if (IS_ERR(chg->iio.usbin_v_chan))
2157 return PTR_ERR(chg->iio.usbin_v_chan);
2158
2159 return iio_read_channel_processed(chg->iio.usbin_v_chan, &val->intval);
Nicholas Troast34db5032016-03-28 12:26:44 -07002160}
2161
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002162int smblib_get_prop_pd_current_max(struct smb_charger *chg,
2163 union power_supply_propval *val)
2164{
2165 val->intval = get_client_vote_locked(chg->usb_icl_votable, PD_VOTER);
2166 return 0;
2167}
2168
Nicholas Troast34db5032016-03-28 12:26:44 -07002169int smblib_get_prop_usb_current_max(struct smb_charger *chg,
2170 union power_supply_propval *val)
2171{
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002172 val->intval = get_client_vote_locked(chg->usb_icl_votable,
2173 USB_PSY_VOTER);
Nicholas Troast34db5032016-03-28 12:26:44 -07002174 return 0;
2175}
2176
Harry Yangba874ce2016-08-19 14:17:01 -07002177int smblib_get_prop_usb_current_now(struct smb_charger *chg,
2178 union power_supply_propval *val)
2179{
2180 int rc = 0;
2181
2182 rc = smblib_get_prop_usb_present(chg, val);
2183 if (rc < 0 || !val->intval)
2184 return rc;
2185
2186 if (!chg->iio.usbin_i_chan ||
2187 PTR_ERR(chg->iio.usbin_i_chan) == -EPROBE_DEFER)
2188 chg->iio.usbin_i_chan = iio_channel_get(chg->dev, "usbin_i");
2189
2190 if (IS_ERR(chg->iio.usbin_i_chan))
2191 return PTR_ERR(chg->iio.usbin_i_chan);
2192
2193 return iio_read_channel_processed(chg->iio.usbin_i_chan, &val->intval);
2194}
2195
2196int smblib_get_prop_charger_temp(struct smb_charger *chg,
2197 union power_supply_propval *val)
2198{
2199 int rc;
2200
2201 if (!chg->iio.temp_chan ||
2202 PTR_ERR(chg->iio.temp_chan) == -EPROBE_DEFER)
2203 chg->iio.temp_chan = iio_channel_get(chg->dev, "charger_temp");
2204
2205 if (IS_ERR(chg->iio.temp_chan))
2206 return PTR_ERR(chg->iio.temp_chan);
2207
2208 rc = iio_read_channel_processed(chg->iio.temp_chan, &val->intval);
2209 val->intval /= 100;
2210 return rc;
2211}
2212
2213int smblib_get_prop_charger_temp_max(struct smb_charger *chg,
2214 union power_supply_propval *val)
2215{
2216 int rc;
2217
2218 if (!chg->iio.temp_max_chan ||
2219 PTR_ERR(chg->iio.temp_max_chan) == -EPROBE_DEFER)
2220 chg->iio.temp_max_chan = iio_channel_get(chg->dev,
2221 "charger_temp_max");
2222 if (IS_ERR(chg->iio.temp_max_chan))
2223 return PTR_ERR(chg->iio.temp_max_chan);
2224
2225 rc = iio_read_channel_processed(chg->iio.temp_max_chan, &val->intval);
2226 val->intval /= 100;
2227 return rc;
2228}
2229
Nicholas Troast34db5032016-03-28 12:26:44 -07002230int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
2231 union power_supply_propval *val)
2232{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002233 if (chg->typec_status[3] & CC_ATTACHED_BIT)
2234 val->intval =
2235 (bool)(chg->typec_status[3] & CC_ORIENTATION_BIT) + 1;
Nicholas Troast34db5032016-03-28 12:26:44 -07002236 else
2237 val->intval = 0;
2238
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002239 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002240}
2241
2242static const char * const smblib_typec_mode_name[] = {
2243 [POWER_SUPPLY_TYPEC_NONE] = "NONE",
2244 [POWER_SUPPLY_TYPEC_SOURCE_DEFAULT] = "SOURCE_DEFAULT",
2245 [POWER_SUPPLY_TYPEC_SOURCE_MEDIUM] = "SOURCE_MEDIUM",
2246 [POWER_SUPPLY_TYPEC_SOURCE_HIGH] = "SOURCE_HIGH",
2247 [POWER_SUPPLY_TYPEC_NON_COMPLIANT] = "NON_COMPLIANT",
2248 [POWER_SUPPLY_TYPEC_SINK] = "SINK",
2249 [POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE] = "SINK_POWERED_CABLE",
2250 [POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY] = "SINK_DEBUG_ACCESSORY",
2251 [POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER] = "SINK_AUDIO_ADAPTER",
2252 [POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY] = "POWERED_CABLE_ONLY",
2253};
2254
2255static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
2256{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002257 switch (chg->typec_status[0]) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002258 case 0:
2259 return POWER_SUPPLY_TYPEC_NONE;
2260 case UFP_TYPEC_RDSTD_BIT:
2261 return POWER_SUPPLY_TYPEC_SOURCE_DEFAULT;
2262 case UFP_TYPEC_RD1P5_BIT:
2263 return POWER_SUPPLY_TYPEC_SOURCE_MEDIUM;
2264 case UFP_TYPEC_RD3P0_BIT:
2265 return POWER_SUPPLY_TYPEC_SOURCE_HIGH;
2266 default:
2267 break;
2268 }
2269
2270 return POWER_SUPPLY_TYPEC_NON_COMPLIANT;
2271}
2272
2273static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
2274{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002275 switch (chg->typec_status[1] & DFP_TYPEC_MASK) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002276 case DFP_RA_RA_BIT:
2277 return POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER;
2278 case DFP_RD_RD_BIT:
2279 return POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY;
2280 case DFP_RD_RA_VCONN_BIT:
2281 return POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE;
2282 case DFP_RD_OPEN_BIT:
2283 return POWER_SUPPLY_TYPEC_SINK;
2284 case DFP_RA_OPEN_BIT:
2285 return POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY;
2286 default:
2287 break;
2288 }
2289
2290 return POWER_SUPPLY_TYPEC_NONE;
2291}
2292
2293int smblib_get_prop_typec_mode(struct smb_charger *chg,
2294 union power_supply_propval *val)
2295{
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002296 if (!(chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT)) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002297 val->intval = POWER_SUPPLY_TYPEC_NONE;
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002298 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002299 }
2300
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002301 if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07002302 val->intval = smblib_get_prop_dfp_mode(chg);
2303 else
2304 val->intval = smblib_get_prop_ufp_mode(chg);
2305
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002306 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002307}
2308
2309int smblib_get_prop_typec_power_role(struct smb_charger *chg,
2310 union power_supply_propval *val)
2311{
2312 int rc = 0;
2313 u8 ctrl;
2314
2315 rc = smblib_read(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &ctrl);
2316 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002317 smblib_err(chg, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002318 rc);
2319 return rc;
2320 }
2321 smblib_dbg(chg, PR_REGISTER, "TYPE_C_INTRPT_ENB_SOFTWARE_CTRL = 0x%02x\n",
2322 ctrl);
2323
2324 if (ctrl & TYPEC_DISABLE_CMD_BIT) {
2325 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
2326 return rc;
2327 }
2328
2329 switch (ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT)) {
2330 case 0:
2331 val->intval = POWER_SUPPLY_TYPEC_PR_DUAL;
2332 break;
2333 case DFP_EN_CMD_BIT:
2334 val->intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
2335 break;
2336 case UFP_EN_CMD_BIT:
2337 val->intval = POWER_SUPPLY_TYPEC_PR_SINK;
2338 break;
2339 default:
2340 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002341 smblib_err(chg, "unsupported power role 0x%02lx\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002342 ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT));
2343 return -EINVAL;
2344 }
2345
2346 return rc;
2347}
2348
2349int smblib_get_prop_pd_allowed(struct smb_charger *chg,
2350 union power_supply_propval *val)
2351{
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07002352 val->intval = get_effective_result(chg->pd_allowed_votable);
Nicholas Troast34db5032016-03-28 12:26:44 -07002353 return 0;
2354}
2355
Nicholas Troast133a7f52016-06-29 13:48:20 -07002356int smblib_get_prop_input_current_settled(struct smb_charger *chg,
2357 union power_supply_propval *val)
2358{
2359 return smblib_get_charge_param(chg, &chg->param.icl_stat, &val->intval);
2360}
2361
Fenglin Wuef4730e2017-01-11 18:16:25 +08002362#define HVDCP3_STEP_UV 200000
2363int smblib_get_prop_input_voltage_settled(struct smb_charger *chg,
2364 union power_supply_propval *val)
2365{
2366 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
2367 int rc, pulses;
2368 u8 stat;
2369
2370 val->intval = MICRO_5V;
2371 if (apsd_result == NULL) {
2372 smblib_err(chg, "APSD result is NULL\n");
2373 return 0;
2374 }
2375
2376 switch (apsd_result->pst) {
2377 case POWER_SUPPLY_TYPE_USB_HVDCP_3:
2378 rc = smblib_read(chg, QC_PULSE_COUNT_STATUS_REG, &stat);
2379 if (rc < 0) {
2380 smblib_err(chg,
2381 "Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
2382 return 0;
2383 }
2384 pulses = (stat & QC_PULSE_COUNT_MASK);
2385 val->intval = MICRO_5V + HVDCP3_STEP_UV * pulses;
2386 break;
2387 default:
2388 val->intval = MICRO_5V;
2389 break;
2390 }
2391
2392 return 0;
2393}
2394
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002395int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg,
2396 union power_supply_propval *val)
2397{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002398 val->intval = chg->pd_hard_reset;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002399 return 0;
2400}
2401
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07002402int smblib_get_pe_start(struct smb_charger *chg,
2403 union power_supply_propval *val)
2404{
2405 /*
2406 * hvdcp timeout voter is the last one to allow pd. Use its vote
2407 * to indicate start of pe engine
2408 */
2409 val->intval
2410 = !get_client_vote_locked(chg->pd_disallowed_votable_indirect,
2411 HVDCP_TIMEOUT_VOTER);
2412 return 0;
2413}
2414
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002415int smblib_get_prop_die_health(struct smb_charger *chg,
Nicholas Troastb021dd92017-01-31 18:43:38 -08002416 union power_supply_propval *val)
2417{
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002418 int rc;
Nicholas Troastb021dd92017-01-31 18:43:38 -08002419 u8 stat;
2420
2421 rc = smblib_read(chg, TEMP_RANGE_STATUS_REG, &stat);
2422 if (rc < 0) {
2423 smblib_err(chg, "Couldn't read TEMP_RANGE_STATUS_REG rc=%d\n",
2424 rc);
2425 return rc;
2426 }
2427
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002428 /* TEMP_RANGE bits are mutually exclusive */
2429 switch (stat & TEMP_RANGE_MASK) {
2430 case TEMP_BELOW_RANGE_BIT:
2431 val->intval = POWER_SUPPLY_HEALTH_COOL;
2432 break;
2433 case TEMP_WITHIN_RANGE_BIT:
2434 val->intval = POWER_SUPPLY_HEALTH_WARM;
2435 break;
2436 case TEMP_ABOVE_RANGE_BIT:
2437 val->intval = POWER_SUPPLY_HEALTH_HOT;
2438 break;
2439 case ALERT_LEVEL_BIT:
2440 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
2441 break;
2442 default:
2443 val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
Nicholas Troastb021dd92017-01-31 18:43:38 -08002444 }
2445
Nicholas Troastb021dd92017-01-31 18:43:38 -08002446 return 0;
2447}
2448
Nicholas Troast34db5032016-03-28 12:26:44 -07002449/*******************
2450 * USB PSY SETTERS *
2451 * *****************/
2452
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002453int smblib_set_prop_pd_current_max(struct smb_charger *chg,
2454 const union power_supply_propval *val)
2455{
2456 int rc;
2457
2458 if (chg->pd_active)
2459 rc = vote(chg->usb_icl_votable, PD_VOTER, true, val->intval);
2460 else
2461 rc = -EPERM;
2462
2463 return rc;
2464}
2465
Nicholas Troast34db5032016-03-28 12:26:44 -07002466int smblib_set_prop_usb_current_max(struct smb_charger *chg,
2467 const union power_supply_propval *val)
2468{
Nicholas Troast8d33b7d2017-01-16 11:18:38 -08002469 int rc = 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002470
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002471 if (!chg->pd_active) {
2472 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
2473 true, val->intval);
2474 } else if (chg->system_suspend_supported) {
2475 if (val->intval <= USBIN_25MA)
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302476 rc = vote(chg->usb_icl_votable,
2477 PD_SUSPEND_SUPPORTED_VOTER, true, val->intval);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002478 else
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302479 rc = vote(chg->usb_icl_votable,
2480 PD_SUSPEND_SUPPORTED_VOTER, false, 0);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002481 }
Nicholas Troast34db5032016-03-28 12:26:44 -07002482 return rc;
2483}
2484
Harry Yangd89ff1f2016-12-05 14:59:11 -08002485int smblib_set_prop_boost_current(struct smb_charger *chg,
2486 const union power_supply_propval *val)
2487{
2488 int rc = 0;
2489
2490 rc = smblib_set_charge_param(chg, &chg->param.freq_boost,
2491 val->intval <= chg->boost_threshold_ua ?
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05302492 chg->chg_freq.freq_below_otg_threshold :
2493 chg->chg_freq.freq_above_otg_threshold);
Harry Yangd89ff1f2016-12-05 14:59:11 -08002494 if (rc < 0) {
2495 dev_err(chg->dev, "Error in setting freq_boost rc=%d\n", rc);
2496 return rc;
2497 }
2498
2499 chg->boost_current_ua = val->intval;
2500 return rc;
2501}
2502
Nicholas Troast34db5032016-03-28 12:26:44 -07002503int smblib_set_prop_typec_power_role(struct smb_charger *chg,
2504 const union power_supply_propval *val)
2505{
2506 int rc = 0;
2507 u8 power_role;
2508
2509 switch (val->intval) {
2510 case POWER_SUPPLY_TYPEC_PR_NONE:
2511 power_role = TYPEC_DISABLE_CMD_BIT;
2512 break;
2513 case POWER_SUPPLY_TYPEC_PR_DUAL:
2514 power_role = 0;
2515 break;
2516 case POWER_SUPPLY_TYPEC_PR_SINK:
2517 power_role = UFP_EN_CMD_BIT;
2518 break;
2519 case POWER_SUPPLY_TYPEC_PR_SOURCE:
2520 power_role = DFP_EN_CMD_BIT;
2521 break;
2522 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002523 smblib_err(chg, "power role %d not supported\n", val->intval);
Nicholas Troast34db5032016-03-28 12:26:44 -07002524 return -EINVAL;
2525 }
2526
Jack Pham54a39bd2017-03-29 18:59:37 -07002527 if (power_role == UFP_EN_CMD_BIT) {
2528 /* disable PBS workaround when forcing sink mode */
2529 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0x0);
2530 if (rc < 0) {
2531 smblib_err(chg, "Couldn't write to TM_IO_DTEST4_SEL rc=%d\n",
2532 rc);
2533 }
2534 } else {
2535 /* restore it back to 0xA5 */
2536 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
2537 if (rc < 0) {
2538 smblib_err(chg, "Couldn't write to TM_IO_DTEST4_SEL rc=%d\n",
2539 rc);
2540 }
2541 }
2542
Nicholas Troast34db5032016-03-28 12:26:44 -07002543 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2544 TYPEC_POWER_ROLE_CMD_MASK, power_role);
2545 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002546 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 -07002547 power_role, rc);
2548 return rc;
2549 }
2550
2551 return rc;
2552}
2553
2554int smblib_set_prop_usb_voltage_min(struct smb_charger *chg,
2555 const union power_supply_propval *val)
2556{
2557 int rc, min_uv;
2558
2559 min_uv = min(val->intval, chg->voltage_max_uv);
2560 rc = smblib_set_usb_pd_allowed_voltage(chg, min_uv,
2561 chg->voltage_max_uv);
2562 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002563 smblib_err(chg, "invalid max voltage %duV rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002564 val->intval, rc);
2565 return rc;
2566 }
2567
Harry Yangaba1f5f2016-09-28 10:47:29 -07002568 chg->voltage_min_uv = min_uv;
Nicholas Troast34db5032016-03-28 12:26:44 -07002569 return rc;
2570}
2571
2572int smblib_set_prop_usb_voltage_max(struct smb_charger *chg,
2573 const union power_supply_propval *val)
2574{
2575 int rc, max_uv;
2576
2577 max_uv = max(val->intval, chg->voltage_min_uv);
2578 rc = smblib_set_usb_pd_allowed_voltage(chg, chg->voltage_min_uv,
2579 max_uv);
2580 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002581 smblib_err(chg, "invalid min voltage %duV rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002582 val->intval, rc);
2583 return rc;
2584 }
2585
Harry Yangaba1f5f2016-09-28 10:47:29 -07002586 chg->voltage_max_uv = max_uv;
Nicholas Troast34db5032016-03-28 12:26:44 -07002587 return rc;
2588}
2589
2590int smblib_set_prop_pd_active(struct smb_charger *chg,
2591 const union power_supply_propval *val)
2592{
2593 int rc;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002594 bool orientation, cc_debounced, sink_attached, hvdcp;
2595 u8 stat;
Nicholas Troast34db5032016-03-28 12:26:44 -07002596
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002597 if (!get_effective_result(chg->pd_allowed_votable))
Nicholas Troast34db5032016-03-28 12:26:44 -07002598 return -EINVAL;
Nicholas Troast34db5032016-03-28 12:26:44 -07002599
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002600 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
2601 if (rc < 0) {
2602 smblib_err(chg, "Couldn't read APSD status rc=%d\n", rc);
2603 return rc;
2604 }
2605
2606 cc_debounced = (bool)
2607 (chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
2608 sink_attached = (bool)
2609 (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT);
2610 hvdcp = stat & QC_CHARGER_BIT;
2611
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002612 chg->pd_active = val->intval;
2613 if (chg->pd_active) {
2614 vote(chg->apsd_disable_votable, PD_VOTER, true, 0);
2615 vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
2616 vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
2617
2618 /*
2619 * VCONN_EN_ORIENTATION_BIT controls whether to use CC1 or CC2
2620 * line when TYPEC_SPARE_CFG_BIT (CC pin selection s/w override)
2621 * is set or when VCONN_EN_VALUE_BIT is set.
2622 */
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07002623 orientation = chg->typec_status[3] & CC_ORIENTATION_BIT;
Harry Yang88acff42016-09-21 14:56:06 -07002624 rc = smblib_masked_write(chg,
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07002625 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2626 VCONN_EN_ORIENTATION_BIT,
2627 orientation ? 0 : VCONN_EN_ORIENTATION_BIT);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002628 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002629 smblib_err(chg,
Harry Yang88acff42016-09-21 14:56:06 -07002630 "Couldn't enable vconn on CC line rc=%d\n", rc);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002631
2632 /* SW controlled CC_OUT */
2633 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
2634 TYPEC_SPARE_CFG_BIT, TYPEC_SPARE_CFG_BIT);
2635 if (rc < 0)
2636 smblib_err(chg, "Couldn't enable SW cc_out rc=%d\n",
2637 rc);
2638
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302639 /*
2640 * Enforce 500mA for PD until the real vote comes in later.
2641 * It is guaranteed that pd_active is set prior to
2642 * pd_current_max
2643 */
Harry Yangcd995202016-11-07 13:32:52 -08002644 rc = vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002645 if (rc < 0)
Harry Yangcd995202016-11-07 13:32:52 -08002646 smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n",
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002647 rc);
Harry Yangcd995202016-11-07 13:32:52 -08002648
Nicholas Troastf9e44992017-03-14 09:06:56 -07002649 /* since PD was found the cable must be non-legacy */
2650 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
2651
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002652 /* clear USB ICL vote for DCP_VOTER */
Harry Yang631b99e2016-11-17 11:24:25 -08002653 rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002654 if (rc < 0)
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002655 smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n",
2656 rc);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002657
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302658 /* remove USB_PSY_VOTER */
2659 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002660 if (rc < 0)
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302661 smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002662 } else {
2663 vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
2664 vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
2665 vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002666 vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER,
2667 false, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07002668
2669 /* HW controlled CC_OUT */
2670 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
2671 TYPEC_SPARE_CFG_BIT, 0);
2672 if (rc < 0)
2673 smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n",
2674 rc);
2675
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07002676 /*
2677 * This WA should only run for HVDCP. Non-legacy SDP/CDP could
2678 * draw more, but this WA will remove Rd causing VBUS to drop,
2679 * and data could be interrupted. Non-legacy DCP could also draw
2680 * more, but it may impact compliance.
2681 */
2682 if (!chg->typec_legacy_valid && cc_debounced &&
2683 !sink_attached && hvdcp)
2684 schedule_work(&chg->legacy_detection_work);
Harry Yang88acff42016-09-21 14:56:06 -07002685 }
2686
Harry Yang6607b4a2016-05-17 17:50:09 -07002687 smblib_update_usb_type(chg);
Abhijeet Dharmapurikar76e2af52016-10-06 17:25:01 -07002688 power_supply_changed(chg->usb_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07002689 return rc;
2690}
2691
Fenglin Wuedd70792016-11-22 13:16:19 +08002692int smblib_set_prop_ship_mode(struct smb_charger *chg,
2693 const union power_supply_propval *val)
2694{
2695 int rc;
2696
2697 smblib_dbg(chg, PR_MISC, "Set ship mode: %d!!\n", !!val->intval);
2698
2699 rc = smblib_masked_write(chg, SHIP_MODE_REG, SHIP_MODE_EN_BIT,
2700 !!val->intval ? SHIP_MODE_EN_BIT : 0);
2701 if (rc < 0)
2702 dev_err(chg->dev, "Couldn't %s ship mode, rc=%d\n",
2703 !!val->intval ? "enable" : "disable", rc);
2704
2705 return rc;
2706}
2707
Harry Yang5e2bb712016-10-18 16:47:48 -07002708int smblib_reg_block_update(struct smb_charger *chg,
2709 struct reg_info *entry)
2710{
2711 int rc = 0;
2712
2713 while (entry && entry->reg) {
2714 rc = smblib_read(chg, entry->reg, &entry->bak);
2715 if (rc < 0) {
2716 dev_err(chg->dev, "Error in reading %s rc=%d\n",
2717 entry->desc, rc);
2718 break;
2719 }
2720 entry->bak &= entry->mask;
2721
2722 rc = smblib_masked_write(chg, entry->reg,
2723 entry->mask, entry->val);
2724 if (rc < 0) {
2725 dev_err(chg->dev, "Error in writing %s rc=%d\n",
2726 entry->desc, rc);
2727 break;
2728 }
2729 entry++;
2730 }
2731
2732 return rc;
2733}
2734
2735int smblib_reg_block_restore(struct smb_charger *chg,
2736 struct reg_info *entry)
2737{
2738 int rc = 0;
2739
2740 while (entry && entry->reg) {
2741 rc = smblib_masked_write(chg, entry->reg,
2742 entry->mask, entry->bak);
2743 if (rc < 0) {
2744 dev_err(chg->dev, "Error in writing %s rc=%d\n",
2745 entry->desc, rc);
2746 break;
2747 }
2748 entry++;
2749 }
2750
2751 return rc;
2752}
2753
Harry Yang755a34b2016-11-01 01:18:51 -07002754static struct reg_info cc2_detach_settings[] = {
2755 {
2756 .reg = TYPE_C_CFG_2_REG,
2757 .mask = TYPE_C_UFP_MODE_BIT | EN_TRY_SOURCE_MODE_BIT,
2758 .val = TYPE_C_UFP_MODE_BIT,
2759 .desc = "TYPE_C_CFG_2_REG",
2760 },
2761 {
2762 .reg = TYPE_C_CFG_3_REG,
2763 .mask = EN_TRYSINK_MODE_BIT,
2764 .val = 0,
2765 .desc = "TYPE_C_CFG_3_REG",
2766 },
2767 {
2768 .reg = TAPER_TIMER_SEL_CFG_REG,
2769 .mask = TYPEC_SPARE_CFG_BIT,
2770 .val = TYPEC_SPARE_CFG_BIT,
2771 .desc = "TAPER_TIMER_SEL_CFG_REG",
2772 },
2773 {
2774 .reg = TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2775 .mask = VCONN_EN_ORIENTATION_BIT,
2776 .val = 0,
2777 .desc = "TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG",
2778 },
2779 {
2780 .reg = MISC_CFG_REG,
2781 .mask = TCC_DEBOUNCE_20MS_BIT,
2782 .val = TCC_DEBOUNCE_20MS_BIT,
2783 .desc = "Tccdebounce time"
2784 },
2785 {
2786 },
2787};
2788
2789static int smblib_cc2_sink_removal_enter(struct smb_charger *chg)
2790{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002791 int rc, ccout, ufp_mode;
2792 u8 stat;
Harry Yang755a34b2016-11-01 01:18:51 -07002793
2794 if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002795 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002796
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002797 if (chg->cc2_detach_wa_active)
2798 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002799
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002800 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
Harry Yang755a34b2016-11-01 01:18:51 -07002801 if (rc < 0) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002802 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
Harry Yang755a34b2016-11-01 01:18:51 -07002803 return rc;
2804 }
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002805 ccout = (stat & CC_ATTACHED_BIT) ?
2806 (!!(stat & CC_ORIENTATION_BIT) + 1) : 0;
2807 ufp_mode = (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT) ?
2808 !(stat & UFP_DFP_MODE_STATUS_BIT) : 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002809
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002810 if (ccout != 2)
2811 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002812
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002813 if (!ufp_mode)
2814 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002815
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002816 chg->cc2_detach_wa_active = true;
2817 /* The CC2 removal WA will cause a type-c-change IRQ storm */
2818 smblib_reg_block_update(chg, cc2_detach_settings);
2819 schedule_work(&chg->rdstd_cc2_detach_work);
Harry Yang755a34b2016-11-01 01:18:51 -07002820 return rc;
2821}
2822
2823static int smblib_cc2_sink_removal_exit(struct smb_charger *chg)
2824{
Harry Yang755a34b2016-11-01 01:18:51 -07002825 if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002826 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002827
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002828 if (!chg->cc2_detach_wa_active)
2829 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002830
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002831 chg->cc2_detach_wa_active = false;
2832 cancel_work_sync(&chg->rdstd_cc2_detach_work);
2833 smblib_reg_block_restore(chg, cc2_detach_settings);
2834 return 0;
Harry Yang755a34b2016-11-01 01:18:51 -07002835}
2836
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002837int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
2838 const union power_supply_propval *val)
2839{
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002840 int rc = 0;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002841
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002842 if (chg->pd_hard_reset == val->intval)
2843 return rc;
2844
2845 chg->pd_hard_reset = val->intval;
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002846 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002847 EXIT_SNK_BASED_ON_CC_BIT,
2848 (chg->pd_hard_reset) ? EXIT_SNK_BASED_ON_CC_BIT : 0);
2849 if (rc < 0)
2850 smblib_err(chg, "Couldn't set EXIT_SNK_BASED_ON_CC rc=%d\n",
Harry Yang755a34b2016-11-01 01:18:51 -07002851 rc);
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002852
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07002853 vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER,
2854 chg->pd_hard_reset, 0);
Harry Yang755a34b2016-11-01 01:18:51 -07002855
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002856 return rc;
2857}
2858
Nicholas Troast7dbcad22016-10-05 13:30:18 -07002859/************************
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002860 * USB MAIN PSY GETTERS *
2861 ************************/
2862int smblib_get_prop_fcc_delta(struct smb_charger *chg,
2863 union power_supply_propval *val)
2864{
2865 int rc, jeita_cc_delta_ua, step_cc_delta_ua, hw_cc_delta_ua = 0;
2866
2867 rc = smblib_get_step_cc_delta(chg, &step_cc_delta_ua);
2868 if (rc < 0) {
2869 smblib_err(chg, "Couldn't get step cc delta rc=%d\n", rc);
2870 step_cc_delta_ua = 0;
2871 } else {
2872 hw_cc_delta_ua = step_cc_delta_ua;
2873 }
2874
2875 rc = smblib_get_jeita_cc_delta(chg, &jeita_cc_delta_ua);
2876 if (rc < 0) {
2877 smblib_err(chg, "Couldn't get jeita cc delta rc=%d\n", rc);
2878 jeita_cc_delta_ua = 0;
2879 } else if (jeita_cc_delta_ua < 0) {
2880 /* HW will take the min between JEITA and step charge */
2881 hw_cc_delta_ua = min(hw_cc_delta_ua, jeita_cc_delta_ua);
2882 }
2883
2884 val->intval = hw_cc_delta_ua;
2885 return 0;
2886}
2887
2888/************************
2889 * USB MAIN PSY SETTERS *
2890 ************************/
2891
2892#define SDP_CURRENT_MA 500000
2893#define CDP_CURRENT_MA 1500000
2894#define DCP_CURRENT_MA 1500000
2895#define HVDCP_CURRENT_MA 3000000
2896#define TYPEC_DEFAULT_CURRENT_MA 900000
2897#define TYPEC_MEDIUM_CURRENT_MA 1500000
2898#define TYPEC_HIGH_CURRENT_MA 3000000
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07002899int smblib_get_charge_current(struct smb_charger *chg,
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002900 int *total_current_ua)
2901{
Ashay Jaiswal7b6eb962017-04-26 14:34:29 +05302902 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002903 union power_supply_propval val = {0, };
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07002904 int rc = 0, typec_source_rd, current_ua;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002905 bool non_compliant;
2906 u8 stat5;
2907
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07002908 if (chg->pd_active) {
2909 *total_current_ua =
2910 get_client_vote_locked(chg->usb_icl_votable, PD_VOTER);
2911 return rc;
2912 }
2913
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002914 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
2915 if (rc < 0) {
2916 smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc);
2917 return rc;
2918 }
2919 non_compliant = stat5 & TYPEC_NONCOMP_LEGACY_CABLE_STATUS_BIT;
2920
2921 /* get settled ICL */
2922 rc = smblib_get_prop_input_current_settled(chg, &val);
2923 if (rc < 0) {
2924 smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
2925 return rc;
2926 }
2927
2928 typec_source_rd = smblib_get_prop_ufp_mode(chg);
2929
2930 /* QC 2.0/3.0 adapter */
2931 if (apsd_result->bit & (QC_3P0_BIT | QC_2P0_BIT)) {
2932 *total_current_ua = HVDCP_CURRENT_MA;
2933 return 0;
2934 }
2935
2936 if (non_compliant) {
2937 switch (apsd_result->bit) {
2938 case CDP_CHARGER_BIT:
2939 current_ua = CDP_CURRENT_MA;
2940 break;
2941 case DCP_CHARGER_BIT:
2942 case OCP_CHARGER_BIT:
2943 case FLOAT_CHARGER_BIT:
2944 current_ua = DCP_CURRENT_MA;
2945 break;
2946 default:
2947 current_ua = 0;
2948 break;
2949 }
2950
2951 *total_current_ua = max(current_ua, val.intval);
2952 return 0;
2953 }
2954
2955 switch (typec_source_rd) {
2956 case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
2957 switch (apsd_result->bit) {
2958 case CDP_CHARGER_BIT:
2959 current_ua = CDP_CURRENT_MA;
2960 break;
2961 case DCP_CHARGER_BIT:
2962 case OCP_CHARGER_BIT:
2963 case FLOAT_CHARGER_BIT:
2964 current_ua = chg->default_icl_ua;
2965 break;
2966 default:
2967 current_ua = 0;
2968 break;
2969 }
2970 break;
2971 case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
2972 current_ua = TYPEC_MEDIUM_CURRENT_MA;
2973 break;
2974 case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
2975 current_ua = TYPEC_HIGH_CURRENT_MA;
2976 break;
2977 case POWER_SUPPLY_TYPEC_NON_COMPLIANT:
2978 case POWER_SUPPLY_TYPEC_NONE:
2979 default:
2980 current_ua = 0;
2981 break;
2982 }
2983
2984 *total_current_ua = max(current_ua, val.intval);
2985 return 0;
2986}
2987
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002988/************************
Nicholas Troast7dbcad22016-10-05 13:30:18 -07002989 * PARALLEL PSY GETTERS *
2990 ************************/
2991
2992int smblib_get_prop_slave_current_now(struct smb_charger *chg,
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07002993 union power_supply_propval *pval)
Nicholas Troast7dbcad22016-10-05 13:30:18 -07002994{
2995 if (IS_ERR_OR_NULL(chg->iio.batt_i_chan))
2996 chg->iio.batt_i_chan = iio_channel_get(chg->dev, "batt_i");
2997
2998 if (IS_ERR(chg->iio.batt_i_chan))
2999 return PTR_ERR(chg->iio.batt_i_chan);
3000
3001 return iio_read_channel_processed(chg->iio.batt_i_chan, &pval->intval);
3002}
3003
Nicholas Troast34db5032016-03-28 12:26:44 -07003004/**********************
3005 * INTERRUPT HANDLERS *
3006 **********************/
3007
3008irqreturn_t smblib_handle_debug(int irq, void *data)
3009{
3010 struct smb_irq_data *irq_data = data;
3011 struct smb_charger *chg = irq_data->parent_data;
3012
3013 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003014 return IRQ_HANDLED;
3015}
3016
Nicholas Troast8995a702016-12-05 10:22:22 -08003017irqreturn_t smblib_handle_otg_overcurrent(int irq, void *data)
3018{
3019 struct smb_irq_data *irq_data = data;
3020 struct smb_charger *chg = irq_data->parent_data;
3021 int rc;
3022 u8 stat;
3023
3024 rc = smblib_read(chg, OTG_BASE + INT_RT_STS_OFFSET, &stat);
3025 if (rc < 0) {
3026 dev_err(chg->dev, "Couldn't read OTG_INT_RT_STS rc=%d\n", rc);
3027 return IRQ_HANDLED;
3028 }
3029
Ashay Jaiswal7c241382017-03-06 15:26:38 +05303030 if (chg->wa_flags & OTG_WA) {
3031 if (stat & OTG_OC_DIS_SW_STS_RT_STS_BIT)
3032 smblib_err(chg, "OTG disabled by hw\n");
3033
3034 /* not handling software based hiccups for PM660 */
3035 return IRQ_HANDLED;
3036 }
3037
Nicholas Troastb11015f2017-01-17 17:56:45 -08003038 if (stat & OTG_OVERCURRENT_RT_STS_BIT)
3039 schedule_work(&chg->otg_oc_work);
Nicholas Troast8995a702016-12-05 10:22:22 -08003040
Nicholas Troast8995a702016-12-05 10:22:22 -08003041 return IRQ_HANDLED;
3042}
3043
Harry Yang6fe72ab2016-06-14 16:21:39 -07003044irqreturn_t smblib_handle_chg_state_change(int irq, void *data)
3045{
3046 struct smb_irq_data *irq_data = data;
3047 struct smb_charger *chg = irq_data->parent_data;
Nicholas Troast8cb77552016-09-23 11:50:18 -07003048 u8 stat;
Harry Yang1d1034c2016-06-15 12:09:42 -07003049 int rc;
Harry Yang6fe72ab2016-06-14 16:21:39 -07003050
3051 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3052
Nicholas Troast8cb77552016-09-23 11:50:18 -07003053 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
Harry Yang1d1034c2016-06-15 12:09:42 -07003054 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003055 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Abhijeet Dharmapurikarf59c8352017-03-23 14:04:05 -07003056 rc);
Harry Yang1d1034c2016-06-15 12:09:42 -07003057 return IRQ_HANDLED;
3058 }
3059
Nicholas Troast8cb77552016-09-23 11:50:18 -07003060 stat = stat & BATTERY_CHARGER_STATUS_MASK;
Nicholas Troast8cb77552016-09-23 11:50:18 -07003061 power_supply_changed(chg->batt_psy);
Harry Yang6fe72ab2016-06-14 16:21:39 -07003062 return IRQ_HANDLED;
3063}
3064
Harry Yangfe913842016-08-10 12:27:28 -07003065irqreturn_t smblib_handle_step_chg_state_change(int irq, void *data)
3066{
3067 struct smb_irq_data *irq_data = data;
3068 struct smb_charger *chg = irq_data->parent_data;
3069
3070 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3071
3072 if (chg->step_chg_enabled)
3073 rerun_election(chg->fcc_votable);
3074
3075 return IRQ_HANDLED;
3076}
3077
3078irqreturn_t smblib_handle_step_chg_soc_update_fail(int irq, void *data)
3079{
3080 struct smb_irq_data *irq_data = data;
3081 struct smb_charger *chg = irq_data->parent_data;
3082
3083 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3084
3085 if (chg->step_chg_enabled)
3086 rerun_election(chg->fcc_votable);
3087
3088 return IRQ_HANDLED;
3089}
3090
3091#define STEP_SOC_REQ_MS 3000
3092irqreturn_t smblib_handle_step_chg_soc_update_request(int irq, void *data)
3093{
3094 struct smb_irq_data *irq_data = data;
3095 struct smb_charger *chg = irq_data->parent_data;
3096 int rc;
3097 union power_supply_propval pval = {0, };
3098
3099 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3100
3101 if (!chg->bms_psy) {
3102 schedule_delayed_work(&chg->step_soc_req_work,
3103 msecs_to_jiffies(STEP_SOC_REQ_MS));
3104 return IRQ_HANDLED;
3105 }
3106
3107 rc = smblib_get_prop_batt_capacity(chg, &pval);
3108 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003109 smblib_err(chg, "Couldn't get batt capacity rc=%d\n", rc);
Harry Yangfe913842016-08-10 12:27:28 -07003110 else
3111 step_charge_soc_update(chg, pval.intval);
3112
3113 return IRQ_HANDLED;
3114}
3115
Abhijeet Dharmapurikar2644cd62016-07-20 16:54:55 -07003116irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data)
3117{
3118 struct smb_irq_data *irq_data = data;
3119 struct smb_charger *chg = irq_data->parent_data;
3120
3121 rerun_election(chg->fcc_votable);
3122 power_supply_changed(chg->batt_psy);
3123 return IRQ_HANDLED;
3124}
3125
Nicholas Troast34db5032016-03-28 12:26:44 -07003126irqreturn_t smblib_handle_batt_psy_changed(int irq, void *data)
3127{
3128 struct smb_irq_data *irq_data = data;
3129 struct smb_charger *chg = irq_data->parent_data;
3130
Nicholas Troast47ae4612016-08-03 09:49:36 -07003131 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003132 power_supply_changed(chg->batt_psy);
3133 return IRQ_HANDLED;
3134}
3135
3136irqreturn_t smblib_handle_usb_psy_changed(int irq, void *data)
3137{
3138 struct smb_irq_data *irq_data = data;
3139 struct smb_charger *chg = irq_data->parent_data;
3140
Nicholas Troast47ae4612016-08-03 09:49:36 -07003141 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07003142 power_supply_changed(chg->usb_psy);
3143 return IRQ_HANDLED;
3144}
3145
Subbaraman Narayanamurthy09327482017-02-06 16:33:12 -08003146irqreturn_t smblib_handle_usbin_uv(int irq, void *data)
3147{
3148 struct smb_irq_data *irq_data = data;
3149 struct smb_charger *chg = irq_data->parent_data;
3150 struct storm_watch *wdata;
3151
3152 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
3153 if (!chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data)
3154 return IRQ_HANDLED;
3155
3156 wdata = &chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data->storm_data;
3157 reset_storm_count(wdata);
3158 return IRQ_HANDLED;
3159}
3160
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003161static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising)
3162{
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003163 if (vbus_rising) {
3164 /* use the typec flag even though its not typec */
3165 chg->typec_present = 1;
3166 } else {
3167 chg->typec_present = 0;
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003168 smblib_update_usb_type(chg);
3169 extcon_set_cable_state_(chg->extcon, EXTCON_USB, false);
3170 smblib_uusb_removal(chg);
3171 }
3172}
3173
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003174void smblib_usb_plugin_hard_reset_locked(struct smb_charger *chg)
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003175{
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003176 int rc;
3177 u8 stat;
3178 bool vbus_rising;
3179
3180 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
3181 if (rc < 0) {
3182 smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
3183 return;
3184 }
3185
3186 vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
3187
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003188 if (vbus_rising)
3189 smblib_cc2_sink_removal_exit(chg);
3190 else
3191 smblib_cc2_sink_removal_enter(chg);
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003192
3193 power_supply_changed(chg->usb_psy);
3194 smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
3195 vbus_rising ? "attached" : "detached");
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003196}
3197
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303198#define PL_DELAY_MS 30000
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003199void smblib_usb_plugin_locked(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07003200{
Nicholas Troast34db5032016-03-28 12:26:44 -07003201 int rc;
3202 u8 stat;
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003203 bool vbus_rising;
Nicholas Troast34db5032016-03-28 12:26:44 -07003204
Harry Yangcdad2bf2016-10-04 17:03:56 -07003205 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
3206 if (rc < 0) {
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003207 smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
3208 return;
Harry Yangcdad2bf2016-10-04 17:03:56 -07003209 }
3210
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003211 vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003212 smblib_set_opt_freq_buck(chg, vbus_rising ? chg->chg_freq.freq_5V :
3213 chg->chg_freq.freq_removal);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003214
Nicholas Troast34db5032016-03-28 12:26:44 -07003215 /* fetch the DPDM regulator */
3216 if (!chg->dpdm_reg && of_get_property(chg->dev->of_node,
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05303217 "dpdm-supply", NULL)) {
Nicholas Troast34db5032016-03-28 12:26:44 -07003218 chg->dpdm_reg = devm_regulator_get(chg->dev, "dpdm");
3219 if (IS_ERR(chg->dpdm_reg)) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003220 smblib_err(chg, "Couldn't get dpdm regulator rc=%ld\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07003221 PTR_ERR(chg->dpdm_reg));
3222 chg->dpdm_reg = NULL;
3223 }
3224 }
3225
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08003226 if (vbus_rising) {
Nicholas Troastabedaf72016-09-16 11:07:45 -07003227 if (chg->dpdm_reg && !regulator_is_enabled(chg->dpdm_reg)) {
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07003228 smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n");
3229 rc = regulator_enable(chg->dpdm_reg);
3230 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003231 smblib_err(chg, "Couldn't enable dpdm regulator rc=%d\n",
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07003232 rc);
3233 }
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303234
3235 /* Schedule work to enable parallel charger */
3236 vote(chg->awake_votable, PL_DELAY_VOTER, true, 0);
3237 schedule_delayed_work(&chg->pl_enable_work,
3238 msecs_to_jiffies(PL_DELAY_MS));
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07003239 } else {
Abhijeet Dharmapurikar2823fe32016-12-05 17:52:11 -08003240 if (chg->wa_flags & BOOST_BACK_WA)
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08003241 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
Nicholas Troastabedaf72016-09-16 11:07:45 -07003242
3243 if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) {
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07003244 smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n");
3245 rc = regulator_disable(chg->dpdm_reg);
3246 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003247 smblib_err(chg, "Couldn't disable dpdm regulator rc=%d\n",
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07003248 rc);
3249 }
Nicholas Troast34db5032016-03-28 12:26:44 -07003250 }
3251
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003252 if (chg->micro_usb_mode)
3253 smblib_micro_usb_plugin(chg, vbus_rising);
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003254
Nicholas Troast62d86622016-09-22 11:41:33 -07003255 power_supply_changed(chg->usb_psy);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003256 smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
3257 vbus_rising ? "attached" : "detached");
3258}
3259
3260irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
3261{
3262 struct smb_irq_data *irq_data = data;
3263 struct smb_charger *chg = irq_data->parent_data;
3264
3265 mutex_lock(&chg->lock);
Abhijeet Dharmapurikar95c95082017-04-24 14:06:54 -07003266 if (chg->pd_hard_reset)
3267 smblib_usb_plugin_hard_reset_locked(chg);
3268 else
3269 smblib_usb_plugin_locked(chg);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003270 mutex_unlock(&chg->lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07003271 return IRQ_HANDLED;
3272}
3273
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -07003274#define USB_WEAK_INPUT_UA 1400000
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303275#define ICL_CHANGE_DELAY_MS 1000
Harry Yang6fe72ab2016-06-14 16:21:39 -07003276irqreturn_t smblib_handle_icl_change(int irq, void *data)
3277{
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303278 u8 stat;
3279 int rc, settled_ua, delay = ICL_CHANGE_DELAY_MS;
Harry Yang6fe72ab2016-06-14 16:21:39 -07003280 struct smb_irq_data *irq_data = data;
3281 struct smb_charger *chg = irq_data->parent_data;
3282
Nicholas Troastbb9e1a32017-02-09 10:57:28 -08003283 if (chg->mode == PARALLEL_MASTER) {
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303284 rc = smblib_read(chg, AICL_STATUS_REG, &stat);
3285 if (rc < 0) {
3286 smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n",
3287 rc);
3288 return IRQ_HANDLED;
3289 }
3290
3291 rc = smblib_get_charge_param(chg, &chg->param.icl_stat,
3292 &settled_ua);
3293 if (rc < 0) {
3294 smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
3295 return IRQ_HANDLED;
3296 }
3297
3298 /* If AICL settled then schedule work now */
3299 if ((settled_ua == get_effective_result(chg->usb_icl_votable))
3300 || (stat & AICL_DONE_BIT))
3301 delay = 0;
3302
Ashay Jaiswalac854862017-03-06 23:58:55 +05303303 cancel_delayed_work_sync(&chg->icl_change_work);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05303304 schedule_delayed_work(&chg->icl_change_work,
3305 msecs_to_jiffies(delay));
Nicholas Troastbb9e1a32017-02-09 10:57:28 -08003306 }
Harry Yang1d1034c2016-06-15 12:09:42 -07003307
Harry Yang6fe72ab2016-06-14 16:21:39 -07003308 return IRQ_HANDLED;
3309}
3310
Nicholas Troast34db5032016-03-28 12:26:44 -07003311static void smblib_handle_slow_plugin_timeout(struct smb_charger *chg,
3312 bool rising)
3313{
3314 smblib_dbg(chg, PR_INTERRUPT, "IRQ: slow-plugin-timeout %s\n",
3315 rising ? "rising" : "falling");
3316}
3317
3318static void smblib_handle_sdp_enumeration_done(struct smb_charger *chg,
3319 bool rising)
3320{
3321 smblib_dbg(chg, PR_INTERRUPT, "IRQ: sdp-enumeration-done %s\n",
3322 rising ? "rising" : "falling");
3323}
3324
Harry Yangcdad2bf2016-10-04 17:03:56 -07003325#define QC3_PULSES_FOR_6V 5
3326#define QC3_PULSES_FOR_9V 20
3327#define QC3_PULSES_FOR_12V 35
3328static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg)
3329{
3330 int rc;
3331 u8 stat;
3332 int pulses;
3333
Fenglin Wuef4730e2017-01-11 18:16:25 +08003334 power_supply_changed(chg->usb_main_psy);
Fenglin Wu80826e02017-04-25 21:45:08 +08003335 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP) {
Harry Yangcdad2bf2016-10-04 17:03:56 -07003336 rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat);
3337 if (rc < 0) {
3338 smblib_err(chg,
3339 "Couldn't read QC_CHANGE_STATUS rc=%d\n", rc);
3340 return;
3341 }
3342
3343 switch (stat & QC_2P0_STATUS_MASK) {
3344 case QC_5V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303345 smblib_set_opt_freq_buck(chg,
3346 chg->chg_freq.freq_5V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003347 break;
3348 case QC_9V_BIT:
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 break;
3352 case QC_12V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303353 smblib_set_opt_freq_buck(chg,
3354 chg->chg_freq.freq_12V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003355 break;
3356 default:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303357 smblib_set_opt_freq_buck(chg,
3358 chg->chg_freq.freq_removal);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003359 break;
3360 }
3361 }
3362
Fenglin Wu80826e02017-04-25 21:45:08 +08003363 if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP_3) {
Harry Yangcdad2bf2016-10-04 17:03:56 -07003364 rc = smblib_read(chg, QC_PULSE_COUNT_STATUS_REG, &stat);
3365 if (rc < 0) {
3366 smblib_err(chg,
3367 "Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
3368 return;
3369 }
3370 pulses = (stat & QC_PULSE_COUNT_MASK);
3371
3372 if (pulses < QC3_PULSES_FOR_6V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303373 smblib_set_opt_freq_buck(chg,
3374 chg->chg_freq.freq_5V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003375 else if (pulses < QC3_PULSES_FOR_9V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303376 smblib_set_opt_freq_buck(chg,
3377 chg->chg_freq.freq_6V_8V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003378 else if (pulses < QC3_PULSES_FOR_12V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303379 smblib_set_opt_freq_buck(chg,
3380 chg->chg_freq.freq_9V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003381 else
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303382 smblib_set_opt_freq_buck(chg,
3383 chg->chg_freq.freq_12V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07003384 }
3385}
3386
Nicholas Troast34db5032016-03-28 12:26:44 -07003387/* triggers when HVDCP 3.0 authentication has finished */
3388static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
3389 bool rising)
3390{
3391 const struct apsd_result *apsd_result;
Harry Yangcdad2bf2016-10-04 17:03:56 -07003392 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07003393
3394 if (!rising)
3395 return;
3396
Ashay Jaiswal67ec7072017-02-16 14:14:58 +05303397 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
3398 /*
3399 * Disable AUTH_IRQ_EN_CFG_BIT to receive adapter voltage
3400 * change interrupt.
3401 */
3402 rc = smblib_masked_write(chg,
3403 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
3404 AUTH_IRQ_EN_CFG_BIT, 0);
3405 if (rc < 0)
3406 smblib_err(chg,
3407 "Couldn't enable QC auth setting rc=%d\n", rc);
3408 }
Harry Yangcdad2bf2016-10-04 17:03:56 -07003409
Harry Yangaba1f5f2016-09-28 10:47:29 -07003410 if (chg->mode == PARALLEL_MASTER)
3411 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0);
3412
Ashay Jaiswalac854862017-03-06 23:58:55 +05303413 /* the APSD done handler will set the USB supply type */
3414 apsd_result = smblib_get_apsd_result(chg);
3415 if (get_effective_result(chg->hvdcp_hw_inov_dis_votable)) {
3416 if (apsd_result->pst == POWER_SUPPLY_TYPE_USB_HVDCP) {
3417 /* force HVDCP2 to 9V if INOV is disabled */
3418 rc = smblib_masked_write(chg, CMD_HVDCP_2_REG,
3419 FORCE_9V_BIT, FORCE_9V_BIT);
3420 if (rc < 0)
3421 smblib_err(chg,
3422 "Couldn't force 9V HVDCP rc=%d\n", rc);
3423 }
3424 }
3425
Nicholas Troast34db5032016-03-28 12:26:44 -07003426 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n",
3427 apsd_result->name);
3428}
3429
Harry Yang1369b7a2016-09-27 15:59:50 -07003430static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
3431 bool rising, bool qc_charger)
3432{
Ashay Jaiswal7b6eb962017-04-26 14:34:29 +05303433 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05303434
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003435 /* Hold off PD only until hvdcp 2.0 detection timeout */
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003436 if (rising) {
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003437 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003438 false, 0);
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -08003439
Harry Yang4bf7d962017-03-13 16:51:43 -07003440 /* enable HDC and ICL irq for QC2/3 charger */
3441 if (qc_charger)
3442 vote(chg->usb_irq_enable_votable, QC_VOTER, true, 0);
3443
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -08003444 /*
3445 * HVDCP detection timeout done
3446 * If adapter is not QC2.0/QC3.0 - it is a plain old DCP.
3447 */
3448 if (!qc_charger && (apsd_result->bit & DCP_CHARGER_BIT))
3449 /* enforce DCP ICL if specified */
3450 vote(chg->usb_icl_votable, DCP_VOTER,
3451 chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua);
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003452 }
Harry Yang1369b7a2016-09-27 15:59:50 -07003453
3454 smblib_dbg(chg, PR_INTERRUPT, "IRQ: smblib_handle_hvdcp_check_timeout %s\n",
3455 rising ? "rising" : "falling");
3456}
3457
Nicholas Troast34db5032016-03-28 12:26:44 -07003458/* triggers when HVDCP is detected */
3459static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg,
3460 bool rising)
3461{
3462 if (!rising)
3463 return;
3464
3465 /* the APSD done handler will set the USB supply type */
3466 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
3467 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-detect-done %s\n",
3468 rising ? "rising" : "falling");
3469}
3470
Nicholas Troastf9e44992017-03-14 09:06:56 -07003471static void smblib_force_legacy_icl(struct smb_charger *chg, int pst)
3472{
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003473 /* while PD is active it should have complete ICL control */
3474 if (chg->pd_active)
3475 return;
3476
Nicholas Troastf9e44992017-03-14 09:06:56 -07003477 switch (pst) {
3478 case POWER_SUPPLY_TYPE_USB:
3479 /*
3480 * USB_PSY will vote to increase the current to 500/900mA once
3481 * enumeration is done. Ensure that USB_PSY has at least voted
3482 * for 100mA before releasing the LEGACY_UNKNOWN vote
3483 */
3484 if (!is_client_vote_enabled(chg->usb_icl_votable,
3485 USB_PSY_VOTER))
3486 vote(chg->usb_icl_votable, USB_PSY_VOTER, true, 100000);
3487 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
3488 break;
3489 case POWER_SUPPLY_TYPE_USB_CDP:
3490 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1500000);
3491 break;
3492 case POWER_SUPPLY_TYPE_USB_DCP:
3493 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 1500000);
3494 break;
3495 case POWER_SUPPLY_TYPE_USB_HVDCP:
3496 case POWER_SUPPLY_TYPE_USB_HVDCP_3:
3497 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 3000000);
3498 break;
3499 default:
3500 smblib_err(chg, "Unknown APSD %d; forcing 500mA\n", pst);
3501 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 500000);
3502 break;
3503 }
3504}
3505
Nicholas Troast34db5032016-03-28 12:26:44 -07003506#define HVDCP_DET_MS 2500
3507static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
3508{
Nicholas Troast34db5032016-03-28 12:26:44 -07003509 const struct apsd_result *apsd_result;
3510
3511 if (!rising)
3512 return;
3513
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07003514 apsd_result = smblib_update_usb_type(chg);
Nicholas Troastf9e44992017-03-14 09:06:56 -07003515
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003516 if (!chg->typec_legacy_valid)
Nicholas Troastf9e44992017-03-14 09:06:56 -07003517 smblib_force_legacy_icl(chg, apsd_result->pst);
3518
Nicholas Troast34db5032016-03-28 12:26:44 -07003519 switch (apsd_result->bit) {
3520 case SDP_CHARGER_BIT:
3521 case CDP_CHARGER_BIT:
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05303522 if (chg->micro_usb_mode)
3523 extcon_set_cable_state_(chg->extcon, EXTCON_USB,
3524 true);
Abhijeet Dharmapurikarbb9505f2017-03-22 18:31:28 -07003525 /* if not DCP then no hvdcp timeout happens. Enable pd here */
3526 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3527 false, 0);
3528 break;
Nicholas Troast34db5032016-03-28 12:26:44 -07003529 case OCP_CHARGER_BIT:
3530 case FLOAT_CHARGER_BIT:
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303531 /* if not DCP then no hvdcp timeout happens, Enable pd here. */
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003532 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3533 false, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07003534 break;
3535 case DCP_CHARGER_BIT:
Harry Yang1369b7a2016-09-27 15:59:50 -07003536 if (chg->wa_flags & QC_CHARGER_DETECTION_WA_BIT)
3537 schedule_delayed_work(&chg->hvdcp_detect_work,
3538 msecs_to_jiffies(HVDCP_DET_MS));
Nicholas Troast34db5032016-03-28 12:26:44 -07003539 break;
3540 default:
3541 break;
3542 }
3543
Nicholas Troast34db5032016-03-28 12:26:44 -07003544 smblib_dbg(chg, PR_INTERRUPT, "IRQ: apsd-done rising; %s detected\n",
3545 apsd_result->name);
3546}
3547
3548irqreturn_t smblib_handle_usb_source_change(int irq, void *data)
3549{
3550 struct smb_irq_data *irq_data = data;
3551 struct smb_charger *chg = irq_data->parent_data;
3552 int rc = 0;
3553 u8 stat;
3554
3555 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
3556 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003557 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07003558 return IRQ_HANDLED;
3559 }
3560 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
3561
Ashay Jaiswal8507aa52017-04-14 09:42:32 +05303562 if (chg->micro_usb_mode && (stat & APSD_DTC_STATUS_DONE_BIT)
3563 && !chg->uusb_apsd_rerun_done) {
3564 /*
3565 * Force re-run APSD to handle slow insertion related
3566 * charger-mis-detection.
3567 */
3568 chg->uusb_apsd_rerun_done = true;
3569 smblib_rerun_apsd(chg);
3570 return IRQ_HANDLED;
3571 }
3572
Nicholas Troast34db5032016-03-28 12:26:44 -07003573 smblib_handle_apsd_done(chg,
3574 (bool)(stat & APSD_DTC_STATUS_DONE_BIT));
3575
3576 smblib_handle_hvdcp_detect_done(chg,
3577 (bool)(stat & QC_CHARGER_BIT));
3578
Harry Yang1369b7a2016-09-27 15:59:50 -07003579 smblib_handle_hvdcp_check_timeout(chg,
3580 (bool)(stat & HVDCP_CHECK_TIMEOUT_BIT),
3581 (bool)(stat & QC_CHARGER_BIT));
3582
Nicholas Troast34db5032016-03-28 12:26:44 -07003583 smblib_handle_hvdcp_3p0_auth_done(chg,
3584 (bool)(stat & QC_AUTH_DONE_STATUS_BIT));
3585
Nicholas Troast34db5032016-03-28 12:26:44 -07003586 smblib_handle_sdp_enumeration_done(chg,
3587 (bool)(stat & ENUMERATION_DONE_BIT));
3588
3589 smblib_handle_slow_plugin_timeout(chg,
3590 (bool)(stat & SLOW_PLUGIN_TIMEOUT_BIT));
3591
Harry Yangcdad2bf2016-10-04 17:03:56 -07003592 smblib_hvdcp_adaptive_voltage_change(chg);
3593
Nicholas Troast34db5032016-03-28 12:26:44 -07003594 power_supply_changed(chg->usb_psy);
3595
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08003596 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
3597 if (rc < 0) {
3598 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
3599 return IRQ_HANDLED;
3600 }
3601 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
3602
Nicholas Troast34db5032016-03-28 12:26:44 -07003603 return IRQ_HANDLED;
3604}
3605
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003606static void typec_sink_insertion(struct smb_charger *chg)
3607{
3608 /* when a sink is inserted we should not wait on hvdcp timeout to
3609 * enable pd
3610 */
3611 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3612 false, 0);
3613}
Nicholas Troast34db5032016-03-28 12:26:44 -07003614
Harry Yangd89ff1f2016-12-05 14:59:11 -08003615static void typec_sink_removal(struct smb_charger *chg)
3616{
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303617 smblib_set_charge_param(chg, &chg->param.freq_boost,
3618 chg->chg_freq.freq_above_otg_threshold);
Harry Yangd89ff1f2016-12-05 14:59:11 -08003619 chg->boost_current_ua = 0;
3620}
3621
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003622static void smblib_handle_typec_removal(struct smb_charger *chg)
3623{
Nicholas Troastfe74c592017-03-14 09:20:55 -07003624 int rc;
3625
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003626 chg->cc2_detach_wa_active = false;
3627
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003628 /* reset APSD voters */
3629 vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, false, 0);
3630 vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05303631
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003632 cancel_delayed_work_sync(&chg->pl_enable_work);
3633 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
3634
3635 /* reset input current limit voters */
3636 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
3637 vote(chg->usb_icl_votable, PD_VOTER, false, 0);
3638 vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
3639 vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
3640 vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
3641
3642 /* reset hvdcp voters */
3643 vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, true, 0);
3644 vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER, true, 0);
3645
3646 /* reset power delivery voters */
3647 vote(chg->pd_allowed_votable, PD_VOTER, false, 0);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003648 vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0);
3649 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER, true, 0);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003650
3651 /* reset usb irq voters */
Harry Yang4bf7d962017-03-13 16:51:43 -07003652 vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
3653 vote(chg->usb_irq_enable_votable, QC_VOTER, false, 0);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003654
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003655 /* reset parallel voters */
3656 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
3657 vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
3658 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
3659 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
Harry Yang1d1034c2016-06-15 12:09:42 -07003660
Nicholas Troast8995a702016-12-05 10:22:22 -08003661 chg->vconn_attempts = 0;
3662 chg->otg_attempts = 0;
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05303663 chg->pulse_cnt = 0;
3664 chg->usb_icl_delta_ua = 0;
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003665 chg->voltage_min_uv = MICRO_5V;
3666 chg->voltage_max_uv = MICRO_5V;
3667 chg->pd_active = 0;
3668 chg->pd_hard_reset = 0;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003669 chg->typec_legacy_valid = false;
Harry Yang3b113a52016-12-08 12:37:40 -08003670
Nicholas Troastfe74c592017-03-14 09:20:55 -07003671 /* enable APSD CC trigger for next insertion */
3672 rc = smblib_masked_write(chg, TYPE_C_CFG_REG,
3673 APSD_START_ON_CC_BIT, APSD_START_ON_CC_BIT);
3674 if (rc < 0)
3675 smblib_err(chg, "Couldn't enable APSD_START_ON_CC rc=%d\n", rc);
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08003676
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003677 if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
3678 /* re-enable AUTH_IRQ_EN_CFG_BIT */
3679 rc = smblib_masked_write(chg,
3680 USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
3681 AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
3682 if (rc < 0)
3683 smblib_err(chg,
3684 "Couldn't enable QC auth setting rc=%d\n", rc);
3685 }
3686
3687 /* reconfigure allowed voltage for HVDCP */
3688 rc = smblib_set_adapter_allowance(chg,
3689 USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
3690 if (rc < 0)
3691 smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
3692 rc);
3693
3694 /* enable DRP */
3695 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
3696 TYPEC_POWER_ROLE_CMD_MASK, 0);
3697 if (rc < 0)
3698 smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc);
3699
3700 /* HW controlled CC_OUT */
3701 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
3702 TYPEC_SPARE_CFG_BIT, 0);
3703 if (rc < 0)
3704 smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n", rc);
3705
3706 /* restore crude sensor */
3707 rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
3708 if (rc < 0)
3709 smblib_err(chg, "Couldn't restore crude sensor rc=%d\n", rc);
3710
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08003711 typec_sink_removal(chg);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003712 smblib_update_usb_type(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07003713}
3714
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003715static void smblib_handle_typec_insertion(struct smb_charger *chg,
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003716 bool sink_attached)
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003717{
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003718 int rc;
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003719
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003720 vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, false, 0);
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003721
Nicholas Troastfe74c592017-03-14 09:20:55 -07003722 /* disable APSD CC trigger since CC is attached */
3723 rc = smblib_masked_write(chg, TYPE_C_CFG_REG, APSD_START_ON_CC_BIT, 0);
3724 if (rc < 0)
3725 smblib_err(chg, "Couldn't disable APSD_START_ON_CC rc=%d\n",
3726 rc);
3727
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003728 if (sink_attached)
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003729 typec_sink_insertion(chg);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003730 else
Harry Yangd89ff1f2016-12-05 14:59:11 -08003731 typec_sink_removal(chg);
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003732}
3733
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003734static void smblib_handle_typec_debounce_done(struct smb_charger *chg,
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003735 bool rising, bool sink_attached)
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003736{
3737 int rc;
3738 union power_supply_propval pval = {0, };
3739
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003740 if (rising) {
3741 if (!chg->typec_present) {
3742 chg->typec_present = true;
3743 smblib_dbg(chg, PR_MISC, "TypeC insertion\n");
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003744 smblib_handle_typec_insertion(chg, sink_attached);
Nicholas Troast8c28e0f2017-03-22 14:44:49 -07003745 }
3746 } else {
3747 if (chg->typec_present) {
3748 chg->typec_present = false;
3749 smblib_dbg(chg, PR_MISC, "TypeC removal\n");
3750 smblib_handle_typec_removal(chg);
3751 }
3752 }
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003753
3754 rc = smblib_get_prop_typec_mode(chg, &pval);
3755 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003756 smblib_err(chg, "Couldn't get prop typec mode rc=%d\n", rc);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003757
3758 smblib_dbg(chg, PR_INTERRUPT, "IRQ: debounce-done %s; Type-C %s detected\n",
3759 rising ? "rising" : "falling",
3760 smblib_typec_mode_name[pval.intval]);
3761}
3762
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05303763irqreturn_t smblib_handle_usb_typec_change_for_uusb(struct smb_charger *chg)
3764{
3765 int rc;
3766 u8 stat;
3767
3768 rc = smblib_read(chg, TYPE_C_STATUS_3_REG, &stat);
3769 if (rc < 0) {
3770 smblib_err(chg, "Couldn't read TYPE_C_STATUS_3 rc=%d\n", rc);
3771 return IRQ_HANDLED;
3772 }
3773 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_3 = 0x%02x OTG=%d\n",
3774 stat, !!(stat & (U_USB_GND_NOVBUS_BIT | U_USB_GND_BIT)));
3775
3776 extcon_set_cable_state_(chg->extcon, EXTCON_USB_HOST,
3777 !!(stat & (U_USB_GND_NOVBUS_BIT | U_USB_GND_BIT)));
3778 power_supply_changed(chg->usb_psy);
3779
3780 return IRQ_HANDLED;
3781}
3782
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003783static void smblib_usb_typec_change(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07003784{
Nicholas Troast34db5032016-03-28 12:26:44 -07003785 int rc;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003786 bool debounce_done, sink_attached;
Nicholas Troast34db5032016-03-28 12:26:44 -07003787
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07003788 rc = smblib_multibyte_read(chg, TYPE_C_STATUS_1_REG,
3789 chg->typec_status, 5);
Nicholas Troast34db5032016-03-28 12:26:44 -07003790 if (rc < 0) {
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07003791 smblib_err(chg, "Couldn't cache USB Type-C status rc=%d\n", rc);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003792 return;
Nicholas Troast34db5032016-03-28 12:26:44 -07003793 }
Nicholas Troast34db5032016-03-28 12:26:44 -07003794
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07003795 debounce_done =
3796 (bool)(chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
3797 sink_attached =
3798 (bool)(chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003799
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003800 smblib_handle_typec_debounce_done(chg, debounce_done, sink_attached);
Nicholas Troast34db5032016-03-28 12:26:44 -07003801
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07003802 if (chg->typec_status[3] & TYPEC_VBUS_ERROR_STATUS_BIT)
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003803 smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n");
Harry Yangd757c0f2016-09-23 10:52:05 -07003804
Abhijeet Dharmapurikarb0403c42017-04-17 12:26:26 -07003805 if (chg->typec_status[3] & TYPEC_VCONN_OVERCURR_STATUS_BIT)
Nicholas Troastb11015f2017-01-17 17:56:45 -08003806 schedule_work(&chg->vconn_oc_work);
Nicholas Troast8995a702016-12-05 10:22:22 -08003807
Nicholas Troastb1486552016-11-10 08:20:11 -08003808 power_supply_changed(chg->usb_psy);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003809}
3810
3811irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
3812{
3813 struct smb_irq_data *irq_data = data;
3814 struct smb_charger *chg = irq_data->parent_data;
3815
3816 if (chg->micro_usb_mode) {
3817 smblib_handle_usb_typec_change_for_uusb(chg);
3818 return IRQ_HANDLED;
3819 }
3820
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003821 if (chg->cc2_detach_wa_active || chg->typec_en_dis_active) {
3822 smblib_dbg(chg, PR_INTERRUPT, "Ignoring since %s active\n",
3823 chg->cc2_detach_wa_active ?
3824 "cc2_detach_wa" : "typec_en_dis");
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07003825 return IRQ_HANDLED;
3826 }
3827
3828 mutex_lock(&chg->lock);
3829 smblib_usb_typec_change(chg);
3830 mutex_unlock(&chg->lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07003831 return IRQ_HANDLED;
3832}
3833
Abhijeet Dharmapurikar23916642016-10-03 10:38:50 -07003834irqreturn_t smblib_handle_dc_plugin(int irq, void *data)
3835{
3836 struct smb_irq_data *irq_data = data;
3837 struct smb_charger *chg = irq_data->parent_data;
3838
3839 power_supply_changed(chg->dc_psy);
3840 return IRQ_HANDLED;
3841}
3842
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07003843irqreturn_t smblib_handle_high_duty_cycle(int irq, void *data)
3844{
3845 struct smb_irq_data *irq_data = data;
3846 struct smb_charger *chg = irq_data->parent_data;
3847
3848 chg->is_hdc = true;
3849 schedule_delayed_work(&chg->clear_hdc_work, msecs_to_jiffies(60));
3850
3851 return IRQ_HANDLED;
3852}
3853
Nicholas Troastabedaf72016-09-16 11:07:45 -07003854irqreturn_t smblib_handle_switcher_power_ok(int irq, void *data)
3855{
3856 struct smb_irq_data *irq_data = data;
3857 struct smb_charger *chg = irq_data->parent_data;
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003858 int rc, usb_icl;
Nicholas Troastabedaf72016-09-16 11:07:45 -07003859 u8 stat;
3860
3861 if (!(chg->wa_flags & BOOST_BACK_WA))
3862 return IRQ_HANDLED;
3863
3864 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
3865 if (rc < 0) {
3866 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n", rc);
3867 return IRQ_HANDLED;
3868 }
3869
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003870 /* skip suspending input if its already suspended by some other voter */
3871 usb_icl = get_effective_result(chg->usb_icl_votable);
3872 if ((stat & USE_USBIN_BIT) && usb_icl >= 0 && usb_icl < USBIN_25MA)
Nicholas Troastabedaf72016-09-16 11:07:45 -07003873 return IRQ_HANDLED;
3874
Abhijeet Dharmapurikar2823fe32016-12-05 17:52:11 -08003875 if (stat & USE_DCIN_BIT)
Nicholas Troastabedaf72016-09-16 11:07:45 -07003876 return IRQ_HANDLED;
3877
3878 if (is_storming(&irq_data->storm_data)) {
Abhijeet Dharmapurikar5e0bfbe2017-02-12 19:16:15 -08003879 smblib_err(chg, "Reverse boost detected: voting 0mA to suspend input\n");
3880 vote(chg->usb_icl_votable, BOOST_BACK_VOTER, true, 0);
Nicholas Troastabedaf72016-09-16 11:07:45 -07003881 }
3882
3883 return IRQ_HANDLED;
3884}
3885
Nicholas Troast15dc0c82016-10-18 15:15:21 -07003886irqreturn_t smblib_handle_wdog_bark(int irq, void *data)
3887{
3888 struct smb_irq_data *irq_data = data;
3889 struct smb_charger *chg = irq_data->parent_data;
3890 int rc;
3891
3892 rc = smblib_write(chg, BARK_BITE_WDOG_PET_REG, BARK_BITE_WDOG_PET_BIT);
3893 if (rc < 0)
3894 smblib_err(chg, "Couldn't pet the dog rc=%d\n", rc);
3895
3896 return IRQ_HANDLED;
3897}
3898
Nicholas Troast34db5032016-03-28 12:26:44 -07003899/***************
3900 * Work Queues *
3901 ***************/
3902
3903static void smblib_hvdcp_detect_work(struct work_struct *work)
3904{
3905 struct smb_charger *chg = container_of(work, struct smb_charger,
3906 hvdcp_detect_work.work);
Nicholas Troast34db5032016-03-28 12:26:44 -07003907
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003908 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3909 false, 0);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07003910 power_supply_changed(chg->usb_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07003911}
3912
Harry Yangfe913842016-08-10 12:27:28 -07003913static void bms_update_work(struct work_struct *work)
Harry Yang5e1a5222016-07-26 15:16:04 -07003914{
3915 struct smb_charger *chg = container_of(work, struct smb_charger,
3916 bms_update_work);
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05303917
3918 smblib_suspend_on_debug_battery(chg);
3919
3920 if (chg->batt_psy)
3921 power_supply_changed(chg->batt_psy);
Harry Yang5e1a5222016-07-26 15:16:04 -07003922}
3923
Harry Yangfe913842016-08-10 12:27:28 -07003924static void step_soc_req_work(struct work_struct *work)
3925{
3926 struct smb_charger *chg = container_of(work, struct smb_charger,
3927 step_soc_req_work.work);
3928 union power_supply_propval pval = {0, };
3929 int rc;
3930
3931 rc = smblib_get_prop_batt_capacity(chg, &pval);
3932 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003933 smblib_err(chg, "Couldn't get batt capacity rc=%d\n", rc);
Harry Yangfe913842016-08-10 12:27:28 -07003934 return;
3935 }
3936
3937 step_charge_soc_update(chg, pval.intval);
3938}
3939
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07003940static void clear_hdc_work(struct work_struct *work)
3941{
3942 struct smb_charger *chg = container_of(work, struct smb_charger,
3943 clear_hdc_work.work);
3944
3945 chg->is_hdc = 0;
3946}
3947
Harry Yang755a34b2016-11-01 01:18:51 -07003948static void rdstd_cc2_detach_work(struct work_struct *work)
3949{
3950 int rc;
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003951 u8 stat4, stat5;
Harry Yang755a34b2016-11-01 01:18:51 -07003952 struct smb_charger *chg = container_of(work, struct smb_charger,
3953 rdstd_cc2_detach_work);
3954
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003955 if (!chg->cc2_detach_wa_active)
3956 return;
3957
Harry Yang755a34b2016-11-01 01:18:51 -07003958 /*
3959 * WA steps -
3960 * 1. Enable both UFP and DFP, wait for 10ms.
3961 * 2. Disable DFP, wait for 30ms.
3962 * 3. Removal detected if both TYPEC_DEBOUNCE_DONE_STATUS
3963 * and TIMER_STAGE bits are gone, otherwise repeat all by
3964 * work rescheduling.
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003965 * Note, work will be cancelled when USB_PLUGIN rises.
Harry Yang755a34b2016-11-01 01:18:51 -07003966 */
3967
3968 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
3969 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT,
3970 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT);
3971 if (rc < 0) {
3972 smblib_err(chg, "Couldn't write TYPE_C_CTRL_REG rc=%d\n", rc);
3973 return;
3974 }
3975
3976 usleep_range(10000, 11000);
3977
3978 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
3979 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT,
3980 UFP_EN_CMD_BIT);
3981 if (rc < 0) {
3982 smblib_err(chg, "Couldn't write TYPE_C_CTRL_REG rc=%d\n", rc);
3983 return;
3984 }
3985
3986 usleep_range(30000, 31000);
3987
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003988 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
Harry Yang755a34b2016-11-01 01:18:51 -07003989 if (rc < 0) {
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003990 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
Harry Yang755a34b2016-11-01 01:18:51 -07003991 return;
3992 }
Harry Yang755a34b2016-11-01 01:18:51 -07003993
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07003994 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
Harry Yang755a34b2016-11-01 01:18:51 -07003995 if (rc < 0) {
3996 smblib_err(chg,
3997 "Couldn't read TYPE_C_STATUS_5_REG rc=%d\n", rc);
3998 return;
3999 }
Harry Yang755a34b2016-11-01 01:18:51 -07004000
Abhijeet Dharmapurikar0e432812017-04-17 14:52:46 -07004001 if ((stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT)
4002 || (stat5 & TIMER_STAGE_2_BIT)) {
4003 smblib_dbg(chg, PR_MISC, "rerunning DD=%d TS2BIT=%d\n",
4004 (int)(stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT),
4005 (int)(stat5 & TIMER_STAGE_2_BIT));
4006 goto rerun;
4007 }
4008
4009 smblib_dbg(chg, PR_MISC, "Bingo CC2 Removal detected\n");
4010 chg->cc2_detach_wa_active = false;
4011 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4012 EXIT_SNK_BASED_ON_CC_BIT, 0);
Harry Yang755a34b2016-11-01 01:18:51 -07004013 smblib_reg_block_restore(chg, cc2_detach_settings);
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004014 mutex_lock(&chg->lock);
4015 smblib_usb_typec_change(chg);
4016 mutex_unlock(&chg->lock);
Harry Yang755a34b2016-11-01 01:18:51 -07004017 return;
4018
4019rerun:
4020 schedule_work(&chg->rdstd_cc2_detach_work);
4021}
4022
Nicholas Troastb11015f2017-01-17 17:56:45 -08004023static void smblib_otg_oc_exit(struct smb_charger *chg, bool success)
4024{
4025 int rc;
4026
4027 chg->otg_attempts = 0;
4028 if (!success) {
4029 smblib_err(chg, "OTG soft start failed\n");
4030 chg->otg_en = false;
4031 }
4032
4033 smblib_dbg(chg, PR_OTG, "enabling VBUS < 1V check\n");
4034 rc = smblib_masked_write(chg, OTG_CFG_REG,
4035 QUICKSTART_OTG_FASTROLESWAP_BIT, 0);
4036 if (rc < 0)
4037 smblib_err(chg, "Couldn't enable VBUS < 1V check rc=%d\n", rc);
4038
4039 if (!chg->external_vconn && chg->vconn_en) {
4040 chg->vconn_attempts = 0;
4041 if (success) {
4042 rc = _smblib_vconn_regulator_enable(
4043 chg->vconn_vreg->rdev);
4044 if (rc < 0)
4045 smblib_err(chg, "Couldn't enable VCONN rc=%d\n",
4046 rc);
4047 } else {
4048 chg->vconn_en = false;
4049 }
4050 }
4051}
4052
4053#define MAX_OC_FALLING_TRIES 10
4054static void smblib_otg_oc_work(struct work_struct *work)
4055{
4056 struct smb_charger *chg = container_of(work, struct smb_charger,
4057 otg_oc_work);
4058 int rc, i;
4059 u8 stat;
4060
4061 if (!chg->vbus_vreg || !chg->vbus_vreg->rdev)
4062 return;
4063
4064 smblib_err(chg, "over-current detected on VBUS\n");
4065 mutex_lock(&chg->otg_oc_lock);
4066 if (!chg->otg_en)
4067 goto unlock;
4068
4069 smblib_dbg(chg, PR_OTG, "disabling VBUS < 1V check\n");
4070 smblib_masked_write(chg, OTG_CFG_REG,
4071 QUICKSTART_OTG_FASTROLESWAP_BIT,
4072 QUICKSTART_OTG_FASTROLESWAP_BIT);
4073
4074 /*
4075 * If 500ms has passed and another over-current interrupt has not
4076 * triggered then it is likely that the software based soft start was
4077 * successful and the VBUS < 1V restriction should be re-enabled.
4078 */
4079 schedule_delayed_work(&chg->otg_ss_done_work, msecs_to_jiffies(500));
4080
4081 rc = _smblib_vbus_regulator_disable(chg->vbus_vreg->rdev);
4082 if (rc < 0) {
4083 smblib_err(chg, "Couldn't disable VBUS rc=%d\n", rc);
4084 goto unlock;
4085 }
4086
4087 if (++chg->otg_attempts > OTG_MAX_ATTEMPTS) {
4088 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4089 smblib_err(chg, "OTG failed to enable after %d attempts\n",
4090 chg->otg_attempts - 1);
4091 smblib_otg_oc_exit(chg, false);
4092 goto unlock;
4093 }
4094
4095 /*
4096 * The real time status should go low within 10ms. Poll every 1-2ms to
4097 * minimize the delay when re-enabling OTG.
4098 */
4099 for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) {
4100 usleep_range(1000, 2000);
4101 rc = smblib_read(chg, OTG_BASE + INT_RT_STS_OFFSET, &stat);
4102 if (rc >= 0 && !(stat & OTG_OVERCURRENT_RT_STS_BIT))
4103 break;
4104 }
4105
4106 if (i >= MAX_OC_FALLING_TRIES) {
4107 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4108 smblib_err(chg, "OTG OC did not fall after %dms\n",
4109 2 * MAX_OC_FALLING_TRIES);
4110 smblib_otg_oc_exit(chg, false);
4111 goto unlock;
4112 }
4113
4114 smblib_dbg(chg, PR_OTG, "OTG OC fell after %dms\n", 2 * i + 1);
4115 rc = _smblib_vbus_regulator_enable(chg->vbus_vreg->rdev);
4116 if (rc < 0) {
4117 smblib_err(chg, "Couldn't enable VBUS rc=%d\n", rc);
4118 goto unlock;
4119 }
4120
4121unlock:
4122 mutex_unlock(&chg->otg_oc_lock);
4123}
4124
4125static void smblib_vconn_oc_work(struct work_struct *work)
4126{
4127 struct smb_charger *chg = container_of(work, struct smb_charger,
4128 vconn_oc_work);
4129 int rc, i;
4130 u8 stat;
4131
Ashay Jaiswal15edce42017-03-31 23:29:58 +05304132 if (chg->micro_usb_mode)
4133 return;
4134
Nicholas Troastb11015f2017-01-17 17:56:45 -08004135 smblib_err(chg, "over-current detected on VCONN\n");
4136 if (!chg->vconn_vreg || !chg->vconn_vreg->rdev)
4137 return;
4138
4139 mutex_lock(&chg->otg_oc_lock);
4140 rc = _smblib_vconn_regulator_disable(chg->vconn_vreg->rdev);
4141 if (rc < 0) {
4142 smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc);
4143 goto unlock;
4144 }
4145
4146 if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
4147 smblib_err(chg, "VCONN failed to enable after %d attempts\n",
4148 chg->otg_attempts - 1);
4149 chg->vconn_en = false;
4150 chg->vconn_attempts = 0;
4151 goto unlock;
4152 }
4153
4154 /*
4155 * The real time status should go low within 10ms. Poll every 1-2ms to
4156 * minimize the delay when re-enabling OTG.
4157 */
4158 for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) {
4159 usleep_range(1000, 2000);
4160 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
4161 if (rc >= 0 && !(stat & TYPEC_VCONN_OVERCURR_STATUS_BIT))
4162 break;
4163 }
4164
4165 if (i >= MAX_OC_FALLING_TRIES) {
4166 smblib_err(chg, "VCONN OC did not fall after %dms\n",
4167 2 * MAX_OC_FALLING_TRIES);
4168 chg->vconn_en = false;
4169 chg->vconn_attempts = 0;
4170 goto unlock;
4171 }
4172
4173 smblib_dbg(chg, PR_OTG, "VCONN OC fell after %dms\n", 2 * i + 1);
4174 if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
4175 smblib_err(chg, "VCONN failed to enable after %d attempts\n",
4176 chg->vconn_attempts - 1);
4177 chg->vconn_en = false;
4178 goto unlock;
4179 }
4180
4181 rc = _smblib_vconn_regulator_enable(chg->vconn_vreg->rdev);
4182 if (rc < 0) {
4183 smblib_err(chg, "Couldn't enable VCONN rc=%d\n", rc);
4184 goto unlock;
4185 }
4186
4187unlock:
4188 mutex_unlock(&chg->otg_oc_lock);
4189}
4190
4191static void smblib_otg_ss_done_work(struct work_struct *work)
4192{
4193 struct smb_charger *chg = container_of(work, struct smb_charger,
4194 otg_ss_done_work.work);
4195 int rc;
4196 bool success = false;
4197 u8 stat;
4198
4199 mutex_lock(&chg->otg_oc_lock);
4200 rc = smblib_read(chg, OTG_STATUS_REG, &stat);
4201 if (rc < 0)
4202 smblib_err(chg, "Couldn't read OTG status rc=%d\n", rc);
4203 else if (stat & BOOST_SOFTSTART_DONE_BIT)
4204 success = true;
4205
4206 smblib_otg_oc_exit(chg, success);
4207 mutex_unlock(&chg->otg_oc_lock);
4208}
4209
Ashay Jaiswal4d825782017-02-18 10:11:34 +05304210static void smblib_icl_change_work(struct work_struct *work)
4211{
4212 struct smb_charger *chg = container_of(work, struct smb_charger,
4213 icl_change_work.work);
4214 int rc, settled_ua;
4215
4216 rc = smblib_get_charge_param(chg, &chg->param.icl_stat, &settled_ua);
4217 if (rc < 0) {
4218 smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
4219 return;
4220 }
4221
4222 power_supply_changed(chg->usb_main_psy);
4223 vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER,
4224 settled_ua >= USB_WEAK_INPUT_UA, 0);
4225
4226 smblib_dbg(chg, PR_INTERRUPT, "icl_settled=%d\n", settled_ua);
4227}
4228
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304229static void smblib_pl_enable_work(struct work_struct *work)
4230{
4231 struct smb_charger *chg = container_of(work, struct smb_charger,
4232 pl_enable_work.work);
4233
4234 smblib_dbg(chg, PR_PARALLEL, "timer expired, enabling parallel\n");
4235 vote(chg->pl_disable_votable, PL_DELAY_VOTER, false, 0);
4236 vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
4237}
4238
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004239static void smblib_legacy_detection_work(struct work_struct *work)
4240{
4241 struct smb_charger *chg = container_of(work, struct smb_charger,
4242 legacy_detection_work);
4243 int rc;
4244 u8 stat;
4245 bool legacy, rp_high;
4246
4247 mutex_lock(&chg->lock);
4248 chg->typec_en_dis_active = 1;
4249 smblib_dbg(chg, PR_MISC, "running legacy unknown workaround\n");
4250 rc = smblib_masked_write(chg,
4251 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4252 TYPEC_DISABLE_CMD_BIT,
4253 TYPEC_DISABLE_CMD_BIT);
4254 if (rc < 0)
4255 smblib_err(chg, "Couldn't disable type-c rc=%d\n", rc);
4256
4257 /* wait for the adapter to turn off VBUS */
4258 msleep(500);
4259
4260 rc = smblib_masked_write(chg,
4261 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
4262 TYPEC_DISABLE_CMD_BIT, 0);
4263 if (rc < 0)
4264 smblib_err(chg, "Couldn't enable type-c rc=%d\n", rc);
4265
4266 /* wait for type-c detection to complete */
4267 msleep(100);
4268
4269 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat);
4270 if (rc < 0) {
4271 smblib_err(chg, "Couldn't read typec stat5 rc = %d\n", rc);
4272 goto unlock;
4273 }
4274
4275 chg->typec_legacy_valid = true;
4276 vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
4277 legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT;
4278 rp_high = smblib_get_prop_ufp_mode(chg) ==
4279 POWER_SUPPLY_TYPEC_SOURCE_HIGH;
4280 if (!legacy || !rp_high)
4281 vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
4282 false, 0);
4283
4284unlock:
4285 chg->typec_en_dis_active = 0;
4286 mutex_unlock(&chg->lock);
4287}
4288
Harry Yangba874ce2016-08-19 14:17:01 -07004289static int smblib_create_votables(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07004290{
4291 int rc = 0;
4292
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304293 chg->fcc_votable = find_votable("FCC");
Harry Yang0c35ff62017-04-06 00:02:30 -07004294 if (chg->fcc_votable == NULL) {
4295 rc = -EINVAL;
4296 smblib_err(chg, "Couldn't find FCC votable rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304297 return rc;
4298 }
4299
4300 chg->fv_votable = find_votable("FV");
Harry Yang0c35ff62017-04-06 00:02:30 -07004301 if (chg->fv_votable == NULL) {
4302 rc = -EINVAL;
4303 smblib_err(chg, "Couldn't find FV votable rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304304 return rc;
4305 }
4306
Ashay Jaiswalae1586d2017-03-22 23:18:51 +05304307 chg->usb_icl_votable = find_votable("USB_ICL");
4308 if (!chg->usb_icl_votable) {
Harry Yang0c35ff62017-04-06 00:02:30 -07004309 rc = -EINVAL;
4310 smblib_err(chg, "Couldn't find USB_ICL votable rc=%d\n", rc);
Ashay Jaiswalae1586d2017-03-22 23:18:51 +05304311 return rc;
4312 }
4313
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304314 chg->pl_disable_votable = find_votable("PL_DISABLE");
Harry Yang0c35ff62017-04-06 00:02:30 -07004315 if (chg->pl_disable_votable == NULL) {
4316 rc = -EINVAL;
4317 smblib_err(chg, "Couldn't find votable PL_DISABLE rc=%d\n", rc);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304318 return rc;
4319 }
4320 vote(chg->pl_disable_votable, PL_INDIRECT_VOTER, true, 0);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304321 vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05304322
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004323 chg->dc_suspend_votable = create_votable("DC_SUSPEND", VOTE_SET_ANY,
4324 smblib_dc_suspend_vote_callback,
4325 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07004326 if (IS_ERR(chg->dc_suspend_votable)) {
4327 rc = PTR_ERR(chg->dc_suspend_votable);
4328 return rc;
4329 }
4330
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004331 chg->dc_icl_votable = create_votable("DC_ICL", VOTE_MIN,
4332 smblib_dc_icl_vote_callback,
4333 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07004334 if (IS_ERR(chg->dc_icl_votable)) {
4335 rc = PTR_ERR(chg->dc_icl_votable);
4336 return rc;
4337 }
4338
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07004339 chg->pd_disallowed_votable_indirect
4340 = create_votable("PD_DISALLOWED_INDIRECT", VOTE_SET_ANY,
4341 smblib_pd_disallowed_votable_indirect_callback, chg);
4342 if (IS_ERR(chg->pd_disallowed_votable_indirect)) {
4343 rc = PTR_ERR(chg->pd_disallowed_votable_indirect);
4344 return rc;
4345 }
4346
4347 chg->pd_allowed_votable = create_votable("PD_ALLOWED",
4348 VOTE_SET_ANY, NULL, NULL);
Nicholas Troast34db5032016-03-28 12:26:44 -07004349 if (IS_ERR(chg->pd_allowed_votable)) {
4350 rc = PTR_ERR(chg->pd_allowed_votable);
4351 return rc;
4352 }
4353
Harry Yang223c6282016-06-14 15:48:36 -07004354 chg->awake_votable = create_votable("AWAKE", VOTE_SET_ANY,
4355 smblib_awake_vote_callback,
4356 chg);
4357 if (IS_ERR(chg->awake_votable)) {
4358 rc = PTR_ERR(chg->awake_votable);
4359 return rc;
4360 }
4361
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07004362 chg->chg_disable_votable = create_votable("CHG_DISABLE", VOTE_SET_ANY,
4363 smblib_chg_disable_vote_callback,
4364 chg);
4365 if (IS_ERR(chg->chg_disable_votable)) {
4366 rc = PTR_ERR(chg->chg_disable_votable);
4367 return rc;
4368 }
4369
Harry Yangaba1f5f2016-09-28 10:47:29 -07004370 chg->pl_enable_votable_indirect = create_votable("PL_ENABLE_INDIRECT",
4371 VOTE_SET_ANY,
4372 smblib_pl_enable_indirect_vote_callback,
4373 chg);
4374 if (IS_ERR(chg->pl_enable_votable_indirect)) {
4375 rc = PTR_ERR(chg->pl_enable_votable_indirect);
4376 return rc;
4377 }
4378
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05304379 chg->hvdcp_disable_votable_indirect = create_votable(
4380 "HVDCP_DISABLE_INDIRECT",
4381 VOTE_SET_ANY,
4382 smblib_hvdcp_disable_indirect_vote_callback,
4383 chg);
4384 if (IS_ERR(chg->hvdcp_disable_votable_indirect)) {
4385 rc = PTR_ERR(chg->hvdcp_disable_votable_indirect);
4386 return rc;
4387 }
4388
4389 chg->hvdcp_enable_votable = create_votable("HVDCP_ENABLE",
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07004390 VOTE_SET_ANY,
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05304391 smblib_hvdcp_enable_vote_callback,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07004392 chg);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05304393 if (IS_ERR(chg->hvdcp_enable_votable)) {
4394 rc = PTR_ERR(chg->hvdcp_enable_votable);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07004395 return rc;
4396 }
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07004397
4398 chg->apsd_disable_votable = create_votable("APSD_DISABLE",
4399 VOTE_SET_ANY,
4400 smblib_apsd_disable_vote_callback,
4401 chg);
4402 if (IS_ERR(chg->apsd_disable_votable)) {
4403 rc = PTR_ERR(chg->apsd_disable_votable);
4404 return rc;
4405 }
4406
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05304407 chg->hvdcp_hw_inov_dis_votable = create_votable("HVDCP_HW_INOV_DIS",
4408 VOTE_SET_ANY,
4409 smblib_hvdcp_hw_inov_dis_vote_callback,
4410 chg);
4411 if (IS_ERR(chg->hvdcp_hw_inov_dis_votable)) {
4412 rc = PTR_ERR(chg->hvdcp_hw_inov_dis_votable);
4413 return rc;
4414 }
4415
Harry Yang4bf7d962017-03-13 16:51:43 -07004416 chg->usb_irq_enable_votable = create_votable("USB_IRQ_DISABLE",
4417 VOTE_SET_ANY,
4418 smblib_usb_irq_enable_vote_callback,
4419 chg);
4420 if (IS_ERR(chg->usb_irq_enable_votable)) {
4421 rc = PTR_ERR(chg->usb_irq_enable_votable);
4422 return rc;
4423 }
4424
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004425 chg->typec_irq_disable_votable = create_votable("TYPEC_IRQ_DISABLE",
4426 VOTE_SET_ANY,
4427 smblib_typec_irq_disable_vote_callback,
4428 chg);
4429 if (IS_ERR(chg->typec_irq_disable_votable)) {
4430 rc = PTR_ERR(chg->typec_irq_disable_votable);
4431 return rc;
4432 }
4433
Nicholas Troast320839e2016-06-03 10:18:00 -07004434 return rc;
4435}
4436
Harry Yangba874ce2016-08-19 14:17:01 -07004437static void smblib_destroy_votables(struct smb_charger *chg)
4438{
Harry Yangba874ce2016-08-19 14:17:01 -07004439 if (chg->dc_suspend_votable)
4440 destroy_votable(chg->dc_suspend_votable);
Harry Yangba874ce2016-08-19 14:17:01 -07004441 if (chg->usb_icl_votable)
4442 destroy_votable(chg->usb_icl_votable);
4443 if (chg->dc_icl_votable)
4444 destroy_votable(chg->dc_icl_votable);
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07004445 if (chg->pd_disallowed_votable_indirect)
4446 destroy_votable(chg->pd_disallowed_votable_indirect);
Harry Yangba874ce2016-08-19 14:17:01 -07004447 if (chg->pd_allowed_votable)
4448 destroy_votable(chg->pd_allowed_votable);
4449 if (chg->awake_votable)
4450 destroy_votable(chg->awake_votable);
Harry Yangaba1f5f2016-09-28 10:47:29 -07004451 if (chg->chg_disable_votable)
4452 destroy_votable(chg->chg_disable_votable);
4453 if (chg->pl_enable_votable_indirect)
4454 destroy_votable(chg->pl_enable_votable_indirect);
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07004455 if (chg->apsd_disable_votable)
4456 destroy_votable(chg->apsd_disable_votable);
Ashay Jaiswal6d308da2017-02-18 09:59:23 +05304457 if (chg->hvdcp_hw_inov_dis_votable)
4458 destroy_votable(chg->hvdcp_hw_inov_dis_votable);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004459 if (chg->typec_irq_disable_votable)
4460 destroy_votable(chg->typec_irq_disable_votable);
Harry Yangba874ce2016-08-19 14:17:01 -07004461}
4462
4463static void smblib_iio_deinit(struct smb_charger *chg)
4464{
4465 if (!IS_ERR_OR_NULL(chg->iio.temp_chan))
4466 iio_channel_release(chg->iio.temp_chan);
4467 if (!IS_ERR_OR_NULL(chg->iio.temp_max_chan))
4468 iio_channel_release(chg->iio.temp_max_chan);
4469 if (!IS_ERR_OR_NULL(chg->iio.usbin_i_chan))
4470 iio_channel_release(chg->iio.usbin_i_chan);
4471 if (!IS_ERR_OR_NULL(chg->iio.usbin_v_chan))
4472 iio_channel_release(chg->iio.usbin_v_chan);
Nicholas Troast7dbcad22016-10-05 13:30:18 -07004473 if (!IS_ERR_OR_NULL(chg->iio.batt_i_chan))
4474 iio_channel_release(chg->iio.batt_i_chan);
Harry Yangba874ce2016-08-19 14:17:01 -07004475}
4476
Nicholas Troast320839e2016-06-03 10:18:00 -07004477int smblib_init(struct smb_charger *chg)
4478{
4479 int rc = 0;
4480
Abhijeet Dharmapurikar11330d92017-04-17 12:15:19 -07004481 mutex_init(&chg->lock);
Nicholas Troast320839e2016-06-03 10:18:00 -07004482 mutex_init(&chg->write_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004483 mutex_init(&chg->otg_oc_lock);
Harry Yangfe913842016-08-10 12:27:28 -07004484 INIT_WORK(&chg->bms_update_work, bms_update_work);
Harry Yang755a34b2016-11-01 01:18:51 -07004485 INIT_WORK(&chg->rdstd_cc2_detach_work, rdstd_cc2_detach_work);
Nicholas Troast320839e2016-06-03 10:18:00 -07004486 INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work);
Harry Yangfe913842016-08-10 12:27:28 -07004487 INIT_DELAYED_WORK(&chg->step_soc_req_work, step_soc_req_work);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07004488 INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work);
Nicholas Troastb11015f2017-01-17 17:56:45 -08004489 INIT_WORK(&chg->otg_oc_work, smblib_otg_oc_work);
4490 INIT_WORK(&chg->vconn_oc_work, smblib_vconn_oc_work);
4491 INIT_DELAYED_WORK(&chg->otg_ss_done_work, smblib_otg_ss_done_work);
Ashay Jaiswal4d825782017-02-18 10:11:34 +05304492 INIT_DELAYED_WORK(&chg->icl_change_work, smblib_icl_change_work);
Ashay Jaiswalc0361672017-03-21 12:24:16 +05304493 INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work);
Abhijeet Dharmapurikar3c93db32017-04-17 17:36:14 -07004494 INIT_WORK(&chg->legacy_detection_work, smblib_legacy_detection_work);
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07004495 chg->fake_capacity = -EINVAL;
Abhijeet Dharmapurikar2ec2a792017-05-01 20:00:25 -07004496 chg->fake_input_current_limited = -EINVAL;
Nicholas Troast320839e2016-06-03 10:18:00 -07004497
4498 switch (chg->mode) {
4499 case PARALLEL_MASTER:
Harry Yang0c35ff62017-04-06 00:02:30 -07004500 rc = qcom_batt_init();
4501 if (rc < 0) {
4502 smblib_err(chg, "Couldn't init qcom_batt_init rc=%d\n",
4503 rc);
4504 return rc;
4505 }
4506
Nicholas Troast320839e2016-06-03 10:18:00 -07004507 rc = smblib_create_votables(chg);
4508 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004509 smblib_err(chg, "Couldn't create votables rc=%d\n",
Nicholas Troast320839e2016-06-03 10:18:00 -07004510 rc);
Harry Yang58a9e7a2016-06-23 14:54:43 -07004511 return rc;
Nicholas Troast320839e2016-06-03 10:18:00 -07004512 }
Harry Yang58a9e7a2016-06-23 14:54:43 -07004513
Harry Yang5e1a5222016-07-26 15:16:04 -07004514 rc = smblib_register_notifier(chg);
4515 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004516 smblib_err(chg,
Harry Yang5e1a5222016-07-26 15:16:04 -07004517 "Couldn't register notifier rc=%d\n", rc);
4518 return rc;
Harry Yang58a9e7a2016-06-23 14:54:43 -07004519 }
4520
Harry Yang995b7422016-08-29 16:06:50 -07004521 chg->bms_psy = power_supply_get_by_name("bms");
Ashay Jaiswal8afedfc2017-02-03 11:18:22 +05304522 chg->pl.psy = power_supply_get_by_name("parallel");
Nicholas Troast320839e2016-06-03 10:18:00 -07004523 break;
4524 case PARALLEL_SLAVE:
4525 break;
4526 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004527 smblib_err(chg, "Unsupported mode %d\n", chg->mode);
Nicholas Troast320839e2016-06-03 10:18:00 -07004528 return -EINVAL;
4529 }
4530
4531 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07004532}
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004533
4534int smblib_deinit(struct smb_charger *chg)
4535{
Harry Yangba874ce2016-08-19 14:17:01 -07004536 switch (chg->mode) {
4537 case PARALLEL_MASTER:
Harry Yang0c35ff62017-04-06 00:02:30 -07004538 cancel_work_sync(&chg->bms_update_work);
4539 cancel_work_sync(&chg->rdstd_cc2_detach_work);
4540 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
4541 cancel_delayed_work_sync(&chg->step_soc_req_work);
4542 cancel_delayed_work_sync(&chg->clear_hdc_work);
4543 cancel_work_sync(&chg->otg_oc_work);
4544 cancel_work_sync(&chg->vconn_oc_work);
4545 cancel_delayed_work_sync(&chg->otg_ss_done_work);
4546 cancel_delayed_work_sync(&chg->icl_change_work);
4547 cancel_delayed_work_sync(&chg->pl_enable_work);
4548 cancel_work_sync(&chg->legacy_detection_work);
Harry Yangba874ce2016-08-19 14:17:01 -07004549 power_supply_unreg_notifier(&chg->nb);
4550 smblib_destroy_votables(chg);
Harry Yang0c35ff62017-04-06 00:02:30 -07004551 qcom_batt_deinit();
Harry Yangba874ce2016-08-19 14:17:01 -07004552 break;
4553 case PARALLEL_SLAVE:
4554 break;
4555 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07004556 smblib_err(chg, "Unsupported mode %d\n", chg->mode);
Harry Yangba874ce2016-08-19 14:17:01 -07004557 return -EINVAL;
4558 }
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004559
Harry Yangba874ce2016-08-19 14:17:01 -07004560 smblib_iio_deinit(chg);
Harry Yang5e1a5222016-07-26 15:16:04 -07004561
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07004562 return 0;
4563}