blob: 50e9c97dec73a4e9b26a4f4236e0eac7686065c9 [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>
David Collins48798442017-01-05 13:03:36 -080020#include <linux/input/qpnp-power-on.h>
Nicholas Troast34db5032016-03-28 12:26:44 -070021#include <linux/irq.h>
22#include "smb-lib.h"
23#include "smb-reg.h"
Nicholas Troast47ae4612016-08-03 09:49:36 -070024#include "storm-watch.h"
Nicholas Troast34db5032016-03-28 12:26:44 -070025#include "pmic-voter.h"
26
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
61int smblib_masked_write(struct smb_charger *chg, u16 addr, u8 mask, u8 val)
62{
Nicholas Troast34db5032016-03-28 12:26:44 -070063 int rc = 0;
64
Harry Yangbacd2222016-05-11 16:43:51 -070065 mutex_lock(&chg->write_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -070066 if (is_secure(chg, addr)) {
67 rc = regmap_write(chg->regmap, (addr & 0xFF00) | 0xD0, 0xA5);
68 if (rc < 0)
69 goto unlock;
70 }
71
72 rc = regmap_update_bits(chg->regmap, addr, mask, val);
73
74unlock:
Harry Yangbacd2222016-05-11 16:43:51 -070075 mutex_unlock(&chg->write_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -070076 return rc;
77}
78
79int smblib_write(struct smb_charger *chg, u16 addr, u8 val)
80{
Nicholas Troast34db5032016-03-28 12:26:44 -070081 int rc = 0;
82
Harry Yangbacd2222016-05-11 16:43:51 -070083 mutex_lock(&chg->write_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -070084
85 if (is_secure(chg, addr)) {
86 rc = regmap_write(chg->regmap, (addr & ~(0xFF)) | 0xD0, 0xA5);
87 if (rc < 0)
88 goto unlock;
89 }
90
91 rc = regmap_write(chg->regmap, addr, val);
92
93unlock:
Harry Yangbacd2222016-05-11 16:43:51 -070094 mutex_unlock(&chg->write_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -070095 return rc;
96}
97
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -070098static int smblib_get_step_cc_delta(struct smb_charger *chg, int *cc_delta_ua)
Harry Yangfe913842016-08-10 12:27:28 -070099{
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -0700100 int rc, step_state;
Harry Yangfe913842016-08-10 12:27:28 -0700101 u8 stat;
102
103 if (!chg->step_chg_enabled) {
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -0700104 *cc_delta_ua = 0;
Harry Yangfe913842016-08-10 12:27:28 -0700105 return 0;
106 }
107
108 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
109 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700110 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Harry Yangfe913842016-08-10 12:27:28 -0700111 rc);
112 return rc;
113 }
114
Harry Yangbedee332016-08-31 16:14:29 -0700115 step_state = (stat & STEP_CHARGING_STATUS_MASK) >>
116 STEP_CHARGING_STATUS_SHIFT;
Harry Yangfe913842016-08-10 12:27:28 -0700117 rc = smblib_get_charge_param(chg, &chg->param.step_cc_delta[step_state],
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -0700118 cc_delta_ua);
119 if (rc < 0) {
120 smblib_err(chg, "Couldn't get step cc delta rc=%d\n", rc);
121 return rc;
Abhijeet Dharmapurikar2644cd62016-07-20 16:54:55 -0700122 }
123
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -0700124 return 0;
125}
Harry Yangfe913842016-08-10 12:27:28 -0700126
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -0700127static int smblib_get_jeita_cc_delta(struct smb_charger *chg, int *cc_delta_ua)
128{
129 int rc, cc_minus_ua;
130 u8 stat;
Harry Yangfe913842016-08-10 12:27:28 -0700131
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -0700132 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat);
133 if (rc < 0) {
134 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
135 rc);
136 return rc;
137 }
138
139 if (!(stat & BAT_TEMP_STATUS_SOFT_LIMIT_MASK)) {
140 *cc_delta_ua = 0;
141 return 0;
142 }
143
144 rc = smblib_get_charge_param(chg, &chg->param.jeita_cc_comp,
145 &cc_minus_ua);
146 if (rc < 0) {
147 smblib_err(chg, "Couldn't get jeita cc minus rc=%d\n", rc);
148 return rc;
149 }
150
151 *cc_delta_ua = -cc_minus_ua;
152 return 0;
153}
154
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800155int smblib_icl_override(struct smb_charger *chg, bool override)
156{
157 int rc;
158 bool override_status;
159 u8 stat;
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -0800160 u16 reg;
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800161
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -0800162 switch (chg->smb_version) {
163 case PMI8998_SUBTYPE:
164 reg = APSD_RESULT_STATUS_REG;
165 break;
166 case PM660_SUBTYPE:
167 reg = AICL_STATUS_REG;
168 break;
169 default:
170 smblib_dbg(chg, PR_MISC, "Unknown chip version=%x\n",
171 chg->smb_version);
172 return -EINVAL;
173 }
174
175 rc = smblib_read(chg, reg, &stat);
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800176 if (rc < 0) {
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -0800177 smblib_err(chg, "Couldn't read reg=%x rc=%d\n", reg, rc);
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800178 return rc;
179 }
180 override_status = (bool)(stat & ICL_OVERRIDE_LATCH_BIT);
181
182 if (override != override_status) {
183 rc = smblib_masked_write(chg, CMD_APSD_REG,
184 ICL_OVERRIDE_BIT, ICL_OVERRIDE_BIT);
185 if (rc < 0) {
186 smblib_err(chg, "Couldn't override ICL rc=%d\n", rc);
187 return rc;
188 }
189 }
190 return 0;
191}
192
Nicholas Troast34db5032016-03-28 12:26:44 -0700193/********************
194 * REGISTER GETTERS *
195 ********************/
196
Nicholas Troast4c310492016-05-12 17:56:35 -0700197int smblib_get_charge_param(struct smb_charger *chg,
198 struct smb_chg_param *param, int *val_u)
199{
200 int rc = 0;
201 u8 val_raw;
202
203 rc = smblib_read(chg, param->reg, &val_raw);
204 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700205 smblib_err(chg, "%s: Couldn't read from 0x%04x rc=%d\n",
Nicholas Troast4c310492016-05-12 17:56:35 -0700206 param->name, param->reg, rc);
207 return rc;
208 }
209
Harry Yangf8b41252016-08-10 14:21:10 -0700210 if (param->get_proc)
211 *val_u = param->get_proc(param, val_raw);
212 else
213 *val_u = val_raw * param->step_u + param->min_u;
Nicholas Troast4c310492016-05-12 17:56:35 -0700214 smblib_dbg(chg, PR_REGISTER, "%s = %d (0x%02x)\n",
215 param->name, *val_u, val_raw);
216
217 return rc;
218}
219
220int smblib_get_usb_suspend(struct smb_charger *chg, int *suspend)
221{
222 int rc = 0;
223 u8 temp;
224
225 rc = smblib_read(chg, USBIN_CMD_IL_REG, &temp);
226 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700227 smblib_err(chg, "Couldn't read USBIN_CMD_IL rc=%d\n", rc);
Nicholas Troast4c310492016-05-12 17:56:35 -0700228 return rc;
229 }
230 *suspend = temp & USBIN_SUSPEND_BIT;
231
232 return rc;
233}
234
Nicholas Troast34db5032016-03-28 12:26:44 -0700235struct apsd_result {
236 const char * const name;
237 const u8 bit;
238 const enum power_supply_type pst;
239};
240
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700241enum {
242 UNKNOWN,
243 SDP,
244 CDP,
245 DCP,
246 OCP,
247 FLOAT,
248 HVDCP2,
249 HVDCP3,
250 MAX_TYPES
251};
252
Nicholas Troast34db5032016-03-28 12:26:44 -0700253static const struct apsd_result const smblib_apsd_results[] = {
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700254 [UNKNOWN] = {
255 .name = "UNKNOWN",
256 .bit = 0,
257 .pst = POWER_SUPPLY_TYPE_UNKNOWN
258 },
259 [SDP] = {
260 .name = "SDP",
261 .bit = SDP_CHARGER_BIT,
262 .pst = POWER_SUPPLY_TYPE_USB
263 },
264 [CDP] = {
265 .name = "CDP",
266 .bit = CDP_CHARGER_BIT,
267 .pst = POWER_SUPPLY_TYPE_USB_CDP
268 },
269 [DCP] = {
270 .name = "DCP",
271 .bit = DCP_CHARGER_BIT,
272 .pst = POWER_SUPPLY_TYPE_USB_DCP
273 },
274 [OCP] = {
275 .name = "OCP",
276 .bit = OCP_CHARGER_BIT,
277 .pst = POWER_SUPPLY_TYPE_USB_DCP
278 },
279 [FLOAT] = {
280 .name = "FLOAT",
281 .bit = FLOAT_CHARGER_BIT,
282 .pst = POWER_SUPPLY_TYPE_USB_DCP
283 },
284 [HVDCP2] = {
285 .name = "HVDCP2",
286 .bit = DCP_CHARGER_BIT | QC_2P0_BIT,
287 .pst = POWER_SUPPLY_TYPE_USB_HVDCP
288 },
289 [HVDCP3] = {
290 .name = "HVDCP3",
291 .bit = DCP_CHARGER_BIT | QC_3P0_BIT,
292 .pst = POWER_SUPPLY_TYPE_USB_HVDCP_3,
293 },
Nicholas Troast34db5032016-03-28 12:26:44 -0700294};
295
296static const struct apsd_result *smblib_get_apsd_result(struct smb_charger *chg)
297{
298 int rc, i;
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700299 u8 apsd_stat, stat;
300 const struct apsd_result *result = &smblib_apsd_results[UNKNOWN];
Nicholas Troast34db5032016-03-28 12:26:44 -0700301
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700302 rc = smblib_read(chg, APSD_STATUS_REG, &apsd_stat);
Nicholas Troast34db5032016-03-28 12:26:44 -0700303 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700304 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700305 return result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700306 }
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700307 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", apsd_stat);
Nicholas Troast34db5032016-03-28 12:26:44 -0700308
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700309 if (!(apsd_stat & APSD_DTC_STATUS_DONE_BIT))
310 return result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700311
312 rc = smblib_read(chg, APSD_RESULT_STATUS_REG, &stat);
313 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700314 smblib_err(chg, "Couldn't read APSD_RESULT_STATUS rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700315 rc);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700316 return result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700317 }
318 stat &= APSD_RESULT_STATUS_MASK;
319
320 for (i = 0; i < ARRAY_SIZE(smblib_apsd_results); i++) {
321 if (smblib_apsd_results[i].bit == stat)
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700322 result = &smblib_apsd_results[i];
Nicholas Troast34db5032016-03-28 12:26:44 -0700323 }
324
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700325 if (apsd_stat & QC_CHARGER_BIT) {
326 /* since its a qc_charger, either return HVDCP3 or HVDCP2 */
327 if (result != &smblib_apsd_results[HVDCP3])
328 result = &smblib_apsd_results[HVDCP2];
329 }
330
331 return result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700332}
333
334
335/********************
336 * REGISTER SETTERS *
337 ********************/
338
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530339static int chg_freq_list[] = {
340 9600, 9600, 6400, 4800, 3800, 3200, 2700, 2400, 2100, 1900, 1700,
341 1600, 1500, 1400, 1300, 1200,
342};
343
344int smblib_set_chg_freq(struct smb_chg_param *param,
345 int val_u, u8 *val_raw)
346{
347 u8 i;
348
349 if (val_u > param->max_u || val_u < param->min_u)
350 return -EINVAL;
351
352 /* Charger FSW is the configured freqency / 2 */
353 val_u *= 2;
354 for (i = 0; i < ARRAY_SIZE(chg_freq_list); i++) {
355 if (chg_freq_list[i] == val_u)
356 break;
357 }
358 if (i == ARRAY_SIZE(chg_freq_list)) {
359 pr_err("Invalid frequency %d Hz\n", val_u / 2);
360 return -EINVAL;
361 }
362
363 *val_raw = i;
364
365 return 0;
366}
367
368static int smblib_set_opt_freq_buck(struct smb_charger *chg, int fsw_khz)
369{
370 union power_supply_propval pval = {0, };
371 int rc = 0;
372
373 rc = smblib_set_charge_param(chg, &chg->param.freq_buck, fsw_khz);
374 if (rc < 0)
375 dev_err(chg->dev, "Error in setting freq_buck rc=%d\n", rc);
376
377 if (chg->mode == PARALLEL_MASTER && chg->pl.psy) {
378 pval.intval = fsw_khz;
379 rc = power_supply_set_property(chg->pl.psy,
380 POWER_SUPPLY_PROP_BUCK_FREQ, &pval);
381 if (rc < 0) {
382 dev_err(chg->dev,
383 "Could not set parallel buck_freq rc=%d\n", rc);
384 return rc;
385 }
386 }
387
388 return rc;
389}
390
Nicholas Troast4c310492016-05-12 17:56:35 -0700391int smblib_set_charge_param(struct smb_charger *chg,
392 struct smb_chg_param *param, int val_u)
Nicholas Troast34db5032016-03-28 12:26:44 -0700393{
394 int rc = 0;
395 u8 val_raw;
396
Harry Yangf8b41252016-08-10 14:21:10 -0700397 if (param->set_proc) {
398 rc = param->set_proc(param, val_u, &val_raw);
399 if (rc < 0)
400 return -EINVAL;
401 } else {
402 if (val_u > param->max_u || val_u < param->min_u) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700403 smblib_err(chg, "%s: %d is out of range [%d, %d]\n",
Harry Yangf8b41252016-08-10 14:21:10 -0700404 param->name, val_u, param->min_u, param->max_u);
405 return -EINVAL;
406 }
407
408 val_raw = (val_u - param->min_u) / param->step_u;
Nicholas Troast34db5032016-03-28 12:26:44 -0700409 }
410
Nicholas Troast34db5032016-03-28 12:26:44 -0700411 rc = smblib_write(chg, param->reg, val_raw);
412 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700413 smblib_err(chg, "%s: Couldn't write 0x%02x to 0x%04x rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700414 param->name, val_raw, param->reg, rc);
415 return rc;
416 }
417
418 smblib_dbg(chg, PR_REGISTER, "%s = %d (0x%02x)\n",
419 param->name, val_u, val_raw);
420
421 return rc;
422}
423
Harry Yangfe913842016-08-10 12:27:28 -0700424static int step_charge_soc_update(struct smb_charger *chg, int capacity)
425{
426 int rc = 0;
427
428 rc = smblib_set_charge_param(chg, &chg->param.step_soc, capacity);
429 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700430 smblib_err(chg, "Error in updating soc, rc=%d\n", rc);
Harry Yangfe913842016-08-10 12:27:28 -0700431 return rc;
432 }
433
434 rc = smblib_write(chg, STEP_CHG_SOC_VBATT_V_UPDATE_REG,
435 STEP_CHG_SOC_VBATT_V_UPDATE_BIT);
436 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700437 smblib_err(chg,
Harry Yangfe913842016-08-10 12:27:28 -0700438 "Couldn't set STEP_CHG_SOC_VBATT_V_UPDATE_REG rc=%d\n",
439 rc);
440 return rc;
441 }
442
443 return rc;
444}
445
Nicholas Troast4c310492016-05-12 17:56:35 -0700446int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend)
Nicholas Troast34db5032016-03-28 12:26:44 -0700447{
448 int rc = 0;
449
450 rc = smblib_masked_write(chg, USBIN_CMD_IL_REG, USBIN_SUSPEND_BIT,
451 suspend ? USBIN_SUSPEND_BIT : 0);
452 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700453 smblib_err(chg, "Couldn't write %s to USBIN_SUSPEND_BIT rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700454 suspend ? "suspend" : "resume", rc);
455
456 return rc;
457}
458
Nicholas Troast4c310492016-05-12 17:56:35 -0700459int smblib_set_dc_suspend(struct smb_charger *chg, bool suspend)
Nicholas Troast34db5032016-03-28 12:26:44 -0700460{
461 int rc = 0;
462
463 rc = smblib_masked_write(chg, DCIN_CMD_IL_REG, DCIN_SUSPEND_BIT,
464 suspend ? DCIN_SUSPEND_BIT : 0);
465 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700466 smblib_err(chg, "Couldn't write %s to DCIN_SUSPEND_BIT rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700467 suspend ? "suspend" : "resume", rc);
468
469 return rc;
470}
471
472#define MICRO_5V 5000000
473#define MICRO_9V 9000000
474#define MICRO_12V 12000000
475static int smblib_set_usb_pd_allowed_voltage(struct smb_charger *chg,
476 int min_allowed_uv, int max_allowed_uv)
477{
478 int rc;
479 u8 allowed_voltage;
480
481 if (min_allowed_uv == MICRO_5V && max_allowed_uv == MICRO_5V) {
482 allowed_voltage = USBIN_ADAPTER_ALLOW_5V;
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530483 smblib_set_opt_freq_buck(chg, chg->chg_freq.freq_5V);
Nicholas Troast34db5032016-03-28 12:26:44 -0700484 } else if (min_allowed_uv == MICRO_9V && max_allowed_uv == MICRO_9V) {
485 allowed_voltage = USBIN_ADAPTER_ALLOW_9V;
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530486 smblib_set_opt_freq_buck(chg, chg->chg_freq.freq_9V);
Nicholas Troast34db5032016-03-28 12:26:44 -0700487 } else if (min_allowed_uv == MICRO_12V && max_allowed_uv == MICRO_12V) {
488 allowed_voltage = USBIN_ADAPTER_ALLOW_12V;
Anirudh Ghayal4da3df92017-01-25 18:55:57 +0530489 smblib_set_opt_freq_buck(chg, chg->chg_freq.freq_12V);
Nicholas Troast34db5032016-03-28 12:26:44 -0700490 } else if (min_allowed_uv < MICRO_9V && max_allowed_uv <= MICRO_9V) {
491 allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_9V;
492 } else if (min_allowed_uv < MICRO_9V && max_allowed_uv <= MICRO_12V) {
493 allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_12V;
494 } else if (min_allowed_uv < MICRO_12V && max_allowed_uv <= MICRO_12V) {
495 allowed_voltage = USBIN_ADAPTER_ALLOW_9V_TO_12V;
496 } else {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700497 smblib_err(chg, "invalid allowed voltage [%d, %d]\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700498 min_allowed_uv, max_allowed_uv);
499 return -EINVAL;
500 }
501
502 rc = smblib_write(chg, USBIN_ADAPTER_ALLOW_CFG_REG, allowed_voltage);
503 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700504 smblib_err(chg, "Couldn't write 0x%02x to USBIN_ADAPTER_ALLOW_CFG rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700505 allowed_voltage, rc);
506 return rc;
507 }
508
509 return rc;
510}
511
512/********************
513 * HELPER FUNCTIONS *
514 ********************/
515
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -0700516static int try_rerun_apsd_for_hvdcp(struct smb_charger *chg)
517{
518 const struct apsd_result *apsd_result;
519
520 /*
521 * PD_INACTIVE_VOTER on hvdcp_disable_votable indicates whether
522 * apsd rerun was tried earlier
523 */
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530524 if (get_client_vote(chg->hvdcp_disable_votable_indirect,
525 PD_INACTIVE_VOTER)) {
526 vote(chg->hvdcp_disable_votable_indirect,
527 PD_INACTIVE_VOTER, false, 0);
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -0700528 /* ensure hvdcp is enabled */
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530529 if (!get_effective_result(
530 chg->hvdcp_disable_votable_indirect)) {
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -0700531 apsd_result = smblib_get_apsd_result(chg);
Nicholas Troast7e7e3ef2016-10-28 10:36:45 -0700532 if (apsd_result->bit & (QC_2P0_BIT | QC_3P0_BIT)) {
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -0700533 /* rerun APSD */
534 smblib_dbg(chg, PR_MISC, "rerun APSD\n");
535 smblib_masked_write(chg, CMD_APSD_REG,
536 APSD_RERUN_BIT,
537 APSD_RERUN_BIT);
538 }
539 }
540 }
541 return 0;
542}
543
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -0700544static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -0700545{
Abhijeet Dharmapurikareda08222016-11-01 11:35:29 -0700546 const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -0700547
Jack Pham9696e252016-05-23 11:15:15 -0700548 /* if PD is active, APSD is disabled so won't have a valid result */
Abhijeet Dharmapurikar76e2af52016-10-06 17:25:01 -0700549 if (chg->pd_active) {
550 chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_USB_PD;
Abhijeet Dharmapurikareda08222016-11-01 11:35:29 -0700551 return apsd_result;
Abhijeet Dharmapurikar76e2af52016-10-06 17:25:01 -0700552 }
Nicholas Troast34db5032016-03-28 12:26:44 -0700553
Nicholas Troast34db5032016-03-28 12:26:44 -0700554 chg->usb_psy_desc.type = apsd_result->pst;
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -0700555 return apsd_result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700556}
557
Harry Yang5e1a5222016-07-26 15:16:04 -0700558static int smblib_notifier_call(struct notifier_block *nb,
Harry Yang58a9e7a2016-06-23 14:54:43 -0700559 unsigned long ev, void *v)
Harry Yang1d1034c2016-06-15 12:09:42 -0700560{
Harry Yang58a9e7a2016-06-23 14:54:43 -0700561 struct power_supply *psy = v;
Harry Yang5e1a5222016-07-26 15:16:04 -0700562 struct smb_charger *chg = container_of(nb, struct smb_charger, nb);
Harry Yang1d1034c2016-06-15 12:09:42 -0700563
Harry Yang5e1a5222016-07-26 15:16:04 -0700564 if (!strcmp(psy->desc->name, "bms")) {
565 if (!chg->bms_psy)
566 chg->bms_psy = psy;
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530567 if (ev == PSY_EVENT_PROP_CHANGED)
Harry Yang5e1a5222016-07-26 15:16:04 -0700568 schedule_work(&chg->bms_update_work);
569 }
570
Ashay Jaiswal8afedfc2017-02-03 11:18:22 +0530571 if (!chg->pl.psy && !strcmp(psy->desc->name, "parallel"))
Harry Yang58a9e7a2016-06-23 14:54:43 -0700572 chg->pl.psy = psy;
Harry Yang1d1034c2016-06-15 12:09:42 -0700573
Harry Yang58a9e7a2016-06-23 14:54:43 -0700574 return NOTIFY_OK;
575}
576
Harry Yang5e1a5222016-07-26 15:16:04 -0700577static int smblib_register_notifier(struct smb_charger *chg)
Harry Yang58a9e7a2016-06-23 14:54:43 -0700578{
579 int rc;
580
Harry Yang5e1a5222016-07-26 15:16:04 -0700581 chg->nb.notifier_call = smblib_notifier_call;
582 rc = power_supply_reg_notifier(&chg->nb);
Harry Yang58a9e7a2016-06-23 14:54:43 -0700583 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700584 smblib_err(chg, "Couldn't register psy notifier rc = %d\n", rc);
Harry Yang58a9e7a2016-06-23 14:54:43 -0700585 return rc;
586 }
587
588 return 0;
Harry Yang1d1034c2016-06-15 12:09:42 -0700589}
590
Harry Yangfe913842016-08-10 12:27:28 -0700591int smblib_mapping_soc_from_field_value(struct smb_chg_param *param,
592 int val_u, u8 *val_raw)
593{
594 if (val_u > param->max_u || val_u < param->min_u)
595 return -EINVAL;
596
597 *val_raw = val_u << 1;
598
599 return 0;
600}
601
602int smblib_mapping_cc_delta_to_field_value(struct smb_chg_param *param,
603 u8 val_raw)
604{
605 int val_u = val_raw * param->step_u + param->min_u;
606
607 if (val_u > param->max_u)
608 val_u -= param->max_u * 2;
609
610 return val_u;
611}
612
613int smblib_mapping_cc_delta_from_field_value(struct smb_chg_param *param,
614 int val_u, u8 *val_raw)
615{
616 if (val_u > param->max_u || val_u < param->min_u - param->max_u)
617 return -EINVAL;
618
619 val_u += param->max_u * 2 - param->min_u;
620 val_u %= param->max_u * 2;
621 *val_raw = val_u / param->step_u;
622
623 return 0;
624}
625
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530626static void smblib_uusb_removal(struct smb_charger *chg)
627{
628 int rc;
629
630 /* reset both usbin current and voltage votes */
631 vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
632 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
Ashay Jaiswal1829fcf2017-02-02 22:45:22 +0530633 vote(chg->pl_disable_votable, PL_DISABLE_HVDCP_VOTER, true, 0);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530634
635 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
636
637 /* reset AUTH_IRQ_EN_CFG_BIT */
638 rc = smblib_masked_write(chg, USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
639 AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
640 if (rc < 0)
641 smblib_err(chg, "Couldn't enable QC auth setting rc=%d\n", rc);
642
643 /* reconfigure allowed voltage for HVDCP */
644 rc = smblib_write(chg, USBIN_ADAPTER_ALLOW_CFG_REG,
645 USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
646 if (rc < 0)
647 smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
648 rc);
649
650 chg->voltage_min_uv = MICRO_5V;
651 chg->voltage_max_uv = MICRO_5V;
652
653 /* clear USB ICL vote for USB_PSY_VOTER */
654 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
655 if (rc < 0)
656 smblib_err(chg, "Couldn't un-vote for USB ICL rc=%d\n", rc);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -0800657
658 /* clear USB ICL vote for DCP_VOTER */
659 rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
660 if (rc < 0)
661 smblib_err(chg,
662 "Couldn't un-vote DCP from USB ICL rc=%d\n", rc);
663
664 /* clear USB ICL vote for PL_USBIN_USBIN_VOTER */
665 rc = vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
666 if (rc < 0)
667 smblib_err(chg,
668 "Couldn't un-vote PL_USBIN_USBIN from USB ICL rc=%d\n",
669 rc);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530670}
671
Harry Yang3b113a52016-12-08 12:37:40 -0800672static bool smblib_sysok_reason_usbin(struct smb_charger *chg)
673{
674 int rc;
675 u8 stat;
676
677 rc = smblib_read(chg, SYSOK_REASON_STATUS_REG, &stat);
678 if (rc < 0) {
679 smblib_err(chg, "Couldn't get SYSOK_REASON_STATUS rc=%d\n", rc);
680 /* assuming 'not usbin' in case of read failure */
681 return false;
682 }
683
684 return stat & SYSOK_REASON_USBIN_BIT;
685}
686
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530687void smblib_suspend_on_debug_battery(struct smb_charger *chg)
688{
689 int rc;
690 union power_supply_propval val;
691
Ashay Jaiswalda8669b2017-02-10 23:24:23 +0530692 if (!chg->suspend_input_on_debug_batt)
693 return;
694
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +0530695 rc = power_supply_get_property(chg->bms_psy,
696 POWER_SUPPLY_PROP_DEBUG_BATTERY, &val);
697 if (rc < 0) {
698 smblib_err(chg, "Couldn't get debug battery prop rc=%d\n", rc);
699 return;
700 }
701
702 vote(chg->usb_suspend_votable, DEBUG_BOARD_VOTER, val.intval, 0);
703 vote(chg->dc_suspend_votable, DEBUG_BOARD_VOTER, val.intval, 0);
704 if (val.intval)
705 pr_info("Input suspended: Fake battery\n");
706}
707
Abhijeet Dharmapurikar9dd61292017-01-25 16:40:08 -0800708int smblib_rerun_apsd_if_required(struct smb_charger *chg)
709{
710 const struct apsd_result *apsd_result;
711 union power_supply_propval val;
712 int rc;
713
714 rc = smblib_get_prop_usb_present(chg, &val);
715 if (rc < 0) {
716 smblib_err(chg, "Couldn't get usb present rc = %d\n", rc);
717 return rc;
718 }
719
720 if (!val.intval)
721 return 0;
722
723 apsd_result = smblib_get_apsd_result(chg);
724 if ((apsd_result->pst == POWER_SUPPLY_TYPE_UNKNOWN)
725 || (apsd_result->pst == POWER_SUPPLY_TYPE_USB)) {
726 /* rerun APSD */
727 pr_info("Reruning APSD type = %s at bootup\n",
728 apsd_result->name);
729 rc = smblib_masked_write(chg, CMD_APSD_REG,
730 APSD_RERUN_BIT,
731 APSD_RERUN_BIT);
732 if (rc < 0) {
733 smblib_err(chg, "Couldn't rerun APSD rc = %d\n", rc);
734 return rc;
735 }
736 }
737
738 return 0;
739}
740
Nicholas Troast34db5032016-03-28 12:26:44 -0700741/*********************
742 * VOTABLE CALLBACKS *
743 *********************/
744
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700745static int smblib_usb_suspend_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -0700746 int suspend, const char *client)
Nicholas Troast34db5032016-03-28 12:26:44 -0700747{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700748 struct smb_charger *chg = data;
Nicholas Troast34db5032016-03-28 12:26:44 -0700749
Nicholas Troastabedaf72016-09-16 11:07:45 -0700750 /* resume input if suspend is invalid */
751 if (suspend < 0)
752 suspend = 0;
753
754 return smblib_set_usb_suspend(chg, (bool)suspend);
Nicholas Troast34db5032016-03-28 12:26:44 -0700755}
756
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700757static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -0700758 int suspend, const char *client)
Nicholas Troast34db5032016-03-28 12:26:44 -0700759{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700760 struct smb_charger *chg = data;
Nicholas Troast34db5032016-03-28 12:26:44 -0700761
Nicholas Troastabedaf72016-09-16 11:07:45 -0700762 /* resume input if suspend is invalid */
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700763 if (suspend < 0)
Nicholas Troastabedaf72016-09-16 11:07:45 -0700764 suspend = 0;
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700765
Nicholas Troastabedaf72016-09-16 11:07:45 -0700766 return smblib_set_dc_suspend(chg, (bool)suspend);
Nicholas Troast34db5032016-03-28 12:26:44 -0700767}
768
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -0700769static int smblib_fcc_max_vote_callback(struct votable *votable, void *data,
770 int fcc_ua, const char *client)
771{
772 struct smb_charger *chg = data;
773
Harry Yangaba1f5f2016-09-28 10:47:29 -0700774 return vote(chg->fcc_votable, FCC_MAX_RESULT_VOTER, true, fcc_ua);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -0700775}
776
Nicholas Troastbb76a142016-09-23 11:23:23 -0700777#define USBIN_25MA 25000
778#define USBIN_100MA 100000
779#define USBIN_150MA 150000
780#define USBIN_500MA 500000
781#define USBIN_900MA 900000
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700782static int smblib_usb_icl_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -0700783 int icl_ua, const char *client)
Nicholas Troast34db5032016-03-28 12:26:44 -0700784{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700785 struct smb_charger *chg = data;
Nicholas Troast34db5032016-03-28 12:26:44 -0700786 int rc = 0;
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800787 bool suspend, override;
Nicholas Troastbb76a142016-09-23 11:23:23 -0700788 u8 icl_options = 0;
Nicholas Troast34db5032016-03-28 12:26:44 -0700789
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800790 override = true;
791 /* remove override if no voters or type = SDP or CDP */
792 if (client == NULL
793 || chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB
794 || chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB_CDP)
795 override = false;
796
797 suspend = false;
798 if (client && (icl_ua < USBIN_25MA))
799 suspend = true;
800
Nicholas Troastbb76a142016-09-23 11:23:23 -0700801 if (suspend)
802 goto out;
803
804 if (chg->usb_psy_desc.type != POWER_SUPPLY_TYPE_USB) {
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800805 if (client) {
806 rc = smblib_set_charge_param(chg, &chg->param.usb_icl,
Ashay Jaiswal923e6f82017-02-06 23:31:29 +0530807 icl_ua - chg->icl_reduction_ua);
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800808 if (rc < 0) {
809 smblib_err(chg, "Couldn't set HC ICL rc=%d\n",
810 rc);
811 return rc;
812 }
Nicholas Troastbb76a142016-09-23 11:23:23 -0700813 }
Ashay Jaiswal923e6f82017-02-06 23:31:29 +0530814
815 smblib_dbg(chg, PR_PARALLEL,
816 "icl_ua=%d icl_reduction=%d\n",
817 icl_ua, chg->icl_reduction_ua);
Nicholas Troastbb76a142016-09-23 11:23:23 -0700818 goto out;
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700819 }
820
Nicholas Troastbb76a142016-09-23 11:23:23 -0700821 /* power source is SDP */
822 switch (icl_ua) {
823 case USBIN_100MA:
824 /* USB 2.0 100mA */
825 icl_options = 0;
826 break;
827 case USBIN_150MA:
828 /* USB 3.0 150mA */
829 icl_options = CFG_USB3P0_SEL_BIT;
830 break;
831 case USBIN_500MA:
832 /* USB 2.0 500mA */
833 icl_options = USB51_MODE_BIT;
834 break;
835 case USBIN_900MA:
836 /* USB 3.0 900mA */
837 icl_options = CFG_USB3P0_SEL_BIT | USB51_MODE_BIT;
838 break;
839 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700840 smblib_err(chg, "ICL %duA isn't supported for SDP\n", icl_ua);
Nicholas Troastbb76a142016-09-23 11:23:23 -0700841 icl_options = 0;
842 break;
843 }
Nicholas Troast34db5032016-03-28 12:26:44 -0700844
Nicholas Troastbb76a142016-09-23 11:23:23 -0700845out:
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800846 if (override)
847 icl_options |= USBIN_MODE_CHG_BIT;
848
Nicholas Troastbb76a142016-09-23 11:23:23 -0700849 rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800850 CFG_USB3P0_SEL_BIT | USB51_MODE_BIT | USBIN_MODE_CHG_BIT,
851 icl_options);
Nicholas Troast34db5032016-03-28 12:26:44 -0700852 if (rc < 0) {
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800853 smblib_err(chg, "Couldn't set ICL options rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -0700854 return rc;
855 }
856
Nicholas Troast34db5032016-03-28 12:26:44 -0700857 rc = vote(chg->usb_suspend_votable, PD_VOTER, suspend, 0);
858 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700859 smblib_err(chg, "Couldn't %s input rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -0700860 suspend ? "suspend" : "resume", rc);
861 return rc;
862 }
863
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -0800864 rc = smblib_icl_override(chg, override);
865 if (rc < 0) {
866 smblib_err(chg, "Couldn't set ICL override rc=%d\n", rc);
867 return rc;
868 }
869
Nicholas Troast34db5032016-03-28 12:26:44 -0700870 return rc;
871}
872
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700873static int smblib_dc_icl_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -0700874 int icl_ua, const char *client)
Nicholas Troast34db5032016-03-28 12:26:44 -0700875{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700876 struct smb_charger *chg = data;
Nicholas Troast34db5032016-03-28 12:26:44 -0700877 int rc = 0;
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700878 bool suspend;
879
880 if (icl_ua < 0) {
881 smblib_dbg(chg, PR_MISC, "No Voter hence suspending\n");
882 icl_ua = 0;
883 }
884
885 suspend = (icl_ua < USBIN_25MA);
886 if (suspend)
887 goto suspend;
Nicholas Troast34db5032016-03-28 12:26:44 -0700888
889 rc = smblib_set_charge_param(chg, &chg->param.dc_icl, icl_ua);
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700890 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700891 smblib_err(chg, "Couldn't set DC input current limit rc=%d\n",
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700892 rc);
893 return rc;
894 }
895
896suspend:
897 rc = vote(chg->dc_suspend_votable, USER_VOTER, suspend, 0);
898 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700899 smblib_err(chg, "Couldn't vote to %s DC rc=%d\n",
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700900 suspend ? "suspend" : "resume", rc);
901 return rc;
902 }
Nicholas Troast34db5032016-03-28 12:26:44 -0700903 return rc;
904}
905
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -0700906static int smblib_pd_disallowed_votable_indirect_callback(
907 struct votable *votable, void *data, int disallowed, const char *client)
908{
909 struct smb_charger *chg = data;
910 int rc;
911
912 rc = vote(chg->pd_allowed_votable, PD_DISALLOWED_INDIRECT_VOTER,
913 !disallowed, 0);
914
915 return rc;
916}
917
Harry Yang223c6282016-06-14 15:48:36 -0700918static int smblib_awake_vote_callback(struct votable *votable, void *data,
919 int awake, const char *client)
920{
921 struct smb_charger *chg = data;
922
923 if (awake)
924 pm_stay_awake(chg->dev);
925 else
926 pm_relax(chg->dev);
927
928 return 0;
929}
930
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -0700931static int smblib_chg_disable_vote_callback(struct votable *votable, void *data,
932 int chg_disable, const char *client)
933{
934 struct smb_charger *chg = data;
935 int rc;
936
937 rc = smblib_masked_write(chg, CHARGING_ENABLE_CMD_REG,
938 CHARGING_ENABLE_CMD_BIT,
939 chg_disable ? 0 : CHARGING_ENABLE_CMD_BIT);
940 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700941 smblib_err(chg, "Couldn't %s charging rc=%d\n",
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -0700942 chg_disable ? "disable" : "enable", rc);
943 return rc;
944 }
945
946 return 0;
947}
Harry Yangaba1f5f2016-09-28 10:47:29 -0700948
949static int smblib_pl_enable_indirect_vote_callback(struct votable *votable,
950 void *data, int chg_enable, const char *client)
951{
952 struct smb_charger *chg = data;
953
954 vote(chg->pl_disable_votable, PL_INDIRECT_VOTER, !chg_enable, 0);
955
956 return 0;
957}
958
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530959static int smblib_hvdcp_enable_vote_callback(struct votable *votable,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700960 void *data,
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530961 int hvdcp_enable, const char *client)
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700962{
963 struct smb_charger *chg = data;
964 int rc;
965 u8 val = HVDCP_AUTH_ALG_EN_CFG_BIT
966 | HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT | HVDCP_EN_BIT;
967
968 /*
969 * Disable the autonomous bit and auth bit for disabling hvdcp.
970 * This ensures only qc 2.0 detection runs but no vbus
971 * negotiation happens.
972 */
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530973 if (!hvdcp_enable)
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700974 val = HVDCP_EN_BIT;
975
976 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
977 HVDCP_EN_BIT
978 | HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT
979 | HVDCP_AUTH_ALG_EN_CFG_BIT,
980 val);
981 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -0700982 smblib_err(chg, "Couldn't %s hvdcp rc=%d\n",
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530983 hvdcp_enable ? "enable" : "disable", rc);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700984 return rc;
985 }
986
987 return 0;
988}
989
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +0530990static int smblib_hvdcp_disable_indirect_vote_callback(struct votable *votable,
991 void *data, int hvdcp_disable, const char *client)
992{
993 struct smb_charger *chg = data;
994
995 vote(chg->hvdcp_enable_votable, HVDCP_INDIRECT_VOTER,
996 !hvdcp_disable, 0);
997
998 return 0;
999}
1000
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07001001static int smblib_apsd_disable_vote_callback(struct votable *votable,
1002 void *data,
1003 int apsd_disable, const char *client)
1004{
1005 struct smb_charger *chg = data;
1006 int rc;
1007
Nicholas Troastec4703c2017-01-30 14:52:33 -08001008 if (apsd_disable) {
1009 /* Don't run APSD on CC debounce when APSD is disabled */
1010 rc = smblib_masked_write(chg, TYPE_C_CFG_REG,
1011 APSD_START_ON_CC_BIT,
1012 0);
1013 if (rc < 0) {
1014 smblib_err(chg, "Couldn't disable APSD_START_ON_CC rc=%d\n",
1015 rc);
1016 return rc;
1017 }
1018
1019 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1020 AUTO_SRC_DETECT_BIT,
1021 0);
1022 if (rc < 0) {
1023 smblib_err(chg, "Couldn't disable APSD rc=%d\n", rc);
1024 return rc;
1025 }
1026 } else {
1027 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1028 AUTO_SRC_DETECT_BIT,
1029 AUTO_SRC_DETECT_BIT);
1030 if (rc < 0) {
1031 smblib_err(chg, "Couldn't enable APSD rc=%d\n", rc);
1032 return rc;
1033 }
1034
1035 rc = smblib_masked_write(chg, TYPE_C_CFG_REG,
1036 APSD_START_ON_CC_BIT,
1037 APSD_START_ON_CC_BIT);
1038 if (rc < 0) {
1039 smblib_err(chg, "Couldn't enable APSD_START_ON_CC rc=%d\n",
1040 rc);
1041 return rc;
1042 }
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07001043 }
1044
1045 return 0;
1046}
Nicholas Troast8995a702016-12-05 10:22:22 -08001047
1048/*******************
1049 * VCONN REGULATOR *
1050 * *****************/
1051
Nicholas Troastb11015f2017-01-17 17:56:45 -08001052#define MAX_OTG_SS_TRIES 2
Nicholas Troast8995a702016-12-05 10:22:22 -08001053static int _smblib_vconn_regulator_enable(struct regulator_dev *rdev)
1054{
1055 struct smb_charger *chg = rdev_get_drvdata(rdev);
1056 u8 otg_stat, stat4;
Nicholas Troastb11015f2017-01-17 17:56:45 -08001057 int rc = 0, i;
Nicholas Troast8995a702016-12-05 10:22:22 -08001058
1059 if (!chg->external_vconn) {
Nicholas Troastb11015f2017-01-17 17:56:45 -08001060 /*
1061 * Hardware based OTG soft start should complete within 1ms, so
1062 * wait for 2ms in the worst case.
1063 */
1064 for (i = 0; i < MAX_OTG_SS_TRIES; ++i) {
1065 usleep_range(1000, 1100);
1066 rc = smblib_read(chg, OTG_STATUS_REG, &otg_stat);
1067 if (rc < 0) {
1068 smblib_err(chg, "Couldn't read OTG status rc=%d\n",
1069 rc);
1070 return rc;
1071 }
1072
1073 if (otg_stat & BOOST_SOFTSTART_DONE_BIT)
1074 break;
Nicholas Troast8995a702016-12-05 10:22:22 -08001075 }
1076
Nicholas Troastb11015f2017-01-17 17:56:45 -08001077 if (!(otg_stat & BOOST_SOFTSTART_DONE_BIT)) {
1078 smblib_err(chg, "Couldn't enable VCONN; OTG soft start failed\n");
Nicholas Troast8995a702016-12-05 10:22:22 -08001079 return -EAGAIN;
1080 }
1081 }
1082
1083 /*
1084 * VCONN_EN_ORIENTATION is overloaded with overriding the CC pin used
1085 * for Vconn, and it should be set with reverse polarity of CC_OUT.
1086 */
1087 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
1088 if (rc < 0) {
1089 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
1090 return rc;
1091 }
1092
Nicholas Troastb11015f2017-01-17 17:56:45 -08001093 smblib_dbg(chg, PR_OTG, "enabling VCONN\n");
Nicholas Troast8995a702016-12-05 10:22:22 -08001094 stat4 = stat4 & CC_ORIENTATION_BIT ? 0 : VCONN_EN_ORIENTATION_BIT;
1095 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1096 VCONN_EN_VALUE_BIT | VCONN_EN_ORIENTATION_BIT,
1097 VCONN_EN_VALUE_BIT | stat4);
1098 if (rc < 0) {
1099 smblib_err(chg, "Couldn't enable vconn setting rc=%d\n", rc);
1100 return rc;
1101 }
1102
1103 return rc;
1104}
1105
1106int smblib_vconn_regulator_enable(struct regulator_dev *rdev)
1107{
1108 struct smb_charger *chg = rdev_get_drvdata(rdev);
1109 int rc = 0;
1110
Nicholas Troastb11015f2017-01-17 17:56:45 -08001111 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001112 if (chg->vconn_en)
1113 goto unlock;
1114
1115 rc = _smblib_vconn_regulator_enable(rdev);
1116 if (rc >= 0)
1117 chg->vconn_en = true;
1118
1119unlock:
Nicholas Troastb11015f2017-01-17 17:56:45 -08001120 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001121 return rc;
1122}
1123
1124static int _smblib_vconn_regulator_disable(struct regulator_dev *rdev)
1125{
1126 struct smb_charger *chg = rdev_get_drvdata(rdev);
1127 int rc = 0;
1128
Nicholas Troastb11015f2017-01-17 17:56:45 -08001129 smblib_dbg(chg, PR_OTG, "disabling VCONN\n");
Nicholas Troast8995a702016-12-05 10:22:22 -08001130 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1131 VCONN_EN_VALUE_BIT, 0);
1132 if (rc < 0)
1133 smblib_err(chg, "Couldn't disable vconn regulator rc=%d\n", rc);
1134
1135 return rc;
1136}
1137
1138int smblib_vconn_regulator_disable(struct regulator_dev *rdev)
1139{
1140 struct smb_charger *chg = rdev_get_drvdata(rdev);
1141 int rc = 0;
1142
Nicholas Troastb11015f2017-01-17 17:56:45 -08001143 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001144 if (!chg->vconn_en)
1145 goto unlock;
1146
1147 rc = _smblib_vconn_regulator_disable(rdev);
1148 if (rc >= 0)
1149 chg->vconn_en = false;
1150
1151unlock:
Nicholas Troastb11015f2017-01-17 17:56:45 -08001152 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001153 return rc;
1154}
1155
1156int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev)
1157{
1158 struct smb_charger *chg = rdev_get_drvdata(rdev);
1159 int ret;
1160
Nicholas Troastb11015f2017-01-17 17:56:45 -08001161 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001162 ret = chg->vconn_en;
Nicholas Troastb11015f2017-01-17 17:56:45 -08001163 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001164 return ret;
1165}
1166
Nicholas Troast34db5032016-03-28 12:26:44 -07001167/*****************
1168 * OTG REGULATOR *
1169 *****************/
1170
Nicholas Troast8995a702016-12-05 10:22:22 -08001171static int _smblib_vbus_regulator_enable(struct regulator_dev *rdev)
Nicholas Troast34db5032016-03-28 12:26:44 -07001172{
1173 struct smb_charger *chg = rdev_get_drvdata(rdev);
Nicholas Troastb11015f2017-01-17 17:56:45 -08001174 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001175
Nicholas Troastb11015f2017-01-17 17:56:45 -08001176 smblib_dbg(chg, PR_OTG, "halt 1 in 8 mode\n");
Harry Yang360bd532016-09-26 11:03:22 -07001177 rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
1178 ENG_BUCKBOOST_HALT1_8_MODE_BIT,
1179 ENG_BUCKBOOST_HALT1_8_MODE_BIT);
1180 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001181 smblib_err(chg, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n",
Harry Yang360bd532016-09-26 11:03:22 -07001182 rc);
1183 return rc;
1184 }
1185
Nicholas Troastb11015f2017-01-17 17:56:45 -08001186 smblib_dbg(chg, PR_OTG, "enabling OTG\n");
Harry Yang360bd532016-09-26 11:03:22 -07001187 rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT);
1188 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001189 smblib_err(chg, "Couldn't enable OTG regulator rc=%d\n", rc);
Harry Yang360bd532016-09-26 11:03:22 -07001190 return rc;
1191 }
1192
Nicholas Troast34db5032016-03-28 12:26:44 -07001193 return rc;
1194}
1195
Nicholas Troast8995a702016-12-05 10:22:22 -08001196int smblib_vbus_regulator_enable(struct regulator_dev *rdev)
Nicholas Troast34db5032016-03-28 12:26:44 -07001197{
1198 struct smb_charger *chg = rdev_get_drvdata(rdev);
1199 int rc = 0;
1200
Nicholas Troastb11015f2017-01-17 17:56:45 -08001201 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001202 if (chg->otg_en)
1203 goto unlock;
1204
1205 rc = _smblib_vbus_regulator_enable(rdev);
1206 if (rc >= 0)
1207 chg->otg_en = true;
1208
1209unlock:
Nicholas Troastb11015f2017-01-17 17:56:45 -08001210 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001211 return rc;
1212}
1213
1214static int _smblib_vbus_regulator_disable(struct regulator_dev *rdev)
1215{
1216 struct smb_charger *chg = rdev_get_drvdata(rdev);
1217 int rc;
Nicholas Troast8995a702016-12-05 10:22:22 -08001218
Nicholas Troastb11015f2017-01-17 17:56:45 -08001219 if (!chg->external_vconn && chg->vconn_en) {
1220 smblib_dbg(chg, PR_OTG, "Killing VCONN before disabling OTG\n");
1221 rc = _smblib_vconn_regulator_disable(rdev);
Nicholas Troast07a69002017-01-20 13:52:10 -08001222 if (rc < 0)
Nicholas Troastb11015f2017-01-17 17:56:45 -08001223 smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc);
Nicholas Troast8995a702016-12-05 10:22:22 -08001224 }
1225
Nicholas Troastb11015f2017-01-17 17:56:45 -08001226 smblib_dbg(chg, PR_OTG, "disabling OTG\n");
Harry Yang360bd532016-09-26 11:03:22 -07001227 rc = smblib_write(chg, CMD_OTG_REG, 0);
1228 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001229 smblib_err(chg, "Couldn't disable OTG regulator rc=%d\n", rc);
Harry Yang360bd532016-09-26 11:03:22 -07001230 return rc;
1231 }
1232
Nicholas Troastb11015f2017-01-17 17:56:45 -08001233 smblib_dbg(chg, PR_OTG, "start 1 in 8 mode\n");
1234 rc = smblib_write(chg, CMD_OTG_REG, 0);
Harry Yang360bd532016-09-26 11:03:22 -07001235 rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
1236 ENG_BUCKBOOST_HALT1_8_MODE_BIT, 0);
1237 if (rc < 0) {
Nicholas Troast8995a702016-12-05 10:22:22 -08001238 smblib_err(chg, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n", rc);
Harry Yang360bd532016-09-26 11:03:22 -07001239 return rc;
1240 }
1241
Nicholas Troast8995a702016-12-05 10:22:22 -08001242 return 0;
1243}
Nicholas Troast34db5032016-03-28 12:26:44 -07001244
Nicholas Troast8995a702016-12-05 10:22:22 -08001245int smblib_vbus_regulator_disable(struct regulator_dev *rdev)
1246{
1247 struct smb_charger *chg = rdev_get_drvdata(rdev);
1248 int rc = 0;
1249
Nicholas Troastb11015f2017-01-17 17:56:45 -08001250 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001251 if (!chg->otg_en)
1252 goto unlock;
1253
1254 rc = _smblib_vbus_regulator_disable(rdev);
1255 if (rc >= 0)
1256 chg->otg_en = false;
1257
1258unlock:
Nicholas Troastb11015f2017-01-17 17:56:45 -08001259 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -07001260 return rc;
1261}
1262
1263int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev)
1264{
1265 struct smb_charger *chg = rdev_get_drvdata(rdev);
Nicholas Troast8995a702016-12-05 10:22:22 -08001266 int ret;
Nicholas Troast34db5032016-03-28 12:26:44 -07001267
Nicholas Troastb11015f2017-01-17 17:56:45 -08001268 mutex_lock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001269 ret = chg->otg_en;
Nicholas Troastb11015f2017-01-17 17:56:45 -08001270 mutex_unlock(&chg->otg_oc_lock);
Nicholas Troast8995a702016-12-05 10:22:22 -08001271 return ret;
Nicholas Troast34db5032016-03-28 12:26:44 -07001272}
1273
1274/********************
1275 * BATT PSY GETTERS *
1276 ********************/
1277
1278int smblib_get_prop_input_suspend(struct smb_charger *chg,
1279 union power_supply_propval *val)
1280{
Harry Yang7db58c22016-06-27 17:58:51 -07001281 val->intval = get_client_vote(chg->usb_suspend_votable, USER_VOTER) &&
1282 get_client_vote(chg->dc_suspend_votable, USER_VOTER);
Nicholas Troast34db5032016-03-28 12:26:44 -07001283 return 0;
1284}
1285
1286int smblib_get_prop_batt_present(struct smb_charger *chg,
1287 union power_supply_propval *val)
1288{
1289 int rc;
1290 u8 stat;
1291
1292 rc = smblib_read(chg, BATIF_BASE + INT_RT_STS_OFFSET, &stat);
1293 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001294 smblib_err(chg, "Couldn't read BATIF_INT_RT_STS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07001295 return rc;
1296 }
1297
1298 val->intval = !(stat & (BAT_THERM_OR_ID_MISSING_RT_STS_BIT
1299 | BAT_TERMINAL_MISSING_RT_STS_BIT));
1300
1301 return rc;
1302}
1303
1304int smblib_get_prop_batt_capacity(struct smb_charger *chg,
1305 union power_supply_propval *val)
1306{
Harry Yang5e1a5222016-07-26 15:16:04 -07001307 int rc = -EINVAL;
1308
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07001309 if (chg->fake_capacity >= 0) {
1310 val->intval = chg->fake_capacity;
1311 return 0;
1312 }
1313
Harry Yang5e1a5222016-07-26 15:16:04 -07001314 if (chg->bms_psy)
1315 rc = power_supply_get_property(chg->bms_psy,
1316 POWER_SUPPLY_PROP_CAPACITY, val);
1317 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001318}
1319
1320int smblib_get_prop_batt_status(struct smb_charger *chg,
1321 union power_supply_propval *val)
1322{
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001323 union power_supply_propval pval = {0, };
1324 bool usb_online, dc_online;
Nicholas Troast8cb77552016-09-23 11:50:18 -07001325 u8 stat;
1326 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001327
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001328 rc = smblib_get_prop_usb_online(chg, &pval);
1329 if (rc < 0) {
1330 smblib_err(chg, "Couldn't get usb online property rc=%d\n",
1331 rc);
1332 return rc;
1333 }
1334 usb_online = (bool)pval.intval;
1335
1336 rc = smblib_get_prop_dc_online(chg, &pval);
1337 if (rc < 0) {
1338 smblib_err(chg, "Couldn't get dc online property rc=%d\n",
1339 rc);
1340 return rc;
1341 }
1342 dc_online = (bool)pval.intval;
1343
Nicholas Troast34db5032016-03-28 12:26:44 -07001344 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1345 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001346 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001347 rc);
1348 return rc;
1349 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001350 stat = stat & BATTERY_CHARGER_STATUS_MASK;
Abhijeet Dharmapurikarec43bb42017-01-17 20:00:08 -08001351
1352 if (!usb_online && !dc_online) {
1353 switch (stat) {
1354 case TERMINATE_CHARGE:
1355 case INHIBIT_CHARGE:
1356 val->intval = POWER_SUPPLY_STATUS_FULL;
1357 break;
1358 default:
1359 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
1360 break;
1361 }
1362 return rc;
1363 }
1364
Nicholas Troast8cb77552016-09-23 11:50:18 -07001365 switch (stat) {
1366 case TRICKLE_CHARGE:
1367 case PRE_CHARGE:
1368 case FAST_CHARGE:
1369 case FULLON_CHARGE:
1370 case TAPER_CHARGE:
Nicholas Troast34db5032016-03-28 12:26:44 -07001371 val->intval = POWER_SUPPLY_STATUS_CHARGING;
Nicholas Troast8cb77552016-09-23 11:50:18 -07001372 break;
1373 case TERMINATE_CHARGE:
1374 case INHIBIT_CHARGE:
1375 val->intval = POWER_SUPPLY_STATUS_FULL;
1376 break;
1377 case DISABLE_CHARGE:
1378 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
1379 break;
1380 default:
1381 val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
1382 break;
1383 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001384
Nicholas Troast8cb77552016-09-23 11:50:18 -07001385 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07001386}
1387
1388int smblib_get_prop_batt_charge_type(struct smb_charger *chg,
1389 union power_supply_propval *val)
1390{
1391 int rc;
1392 u8 stat;
1393
1394 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1395 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001396 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001397 rc);
1398 return rc;
1399 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001400
1401 switch (stat & BATTERY_CHARGER_STATUS_MASK) {
1402 case TRICKLE_CHARGE:
1403 case PRE_CHARGE:
1404 val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1405 break;
1406 case FAST_CHARGE:
1407 case FULLON_CHARGE:
1408 val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
1409 break;
1410 case TAPER_CHARGE:
1411 val->intval = POWER_SUPPLY_CHARGE_TYPE_TAPER;
1412 break;
1413 default:
1414 val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
1415 }
1416
1417 return rc;
1418}
1419
1420int smblib_get_prop_batt_health(struct smb_charger *chg,
1421 union power_supply_propval *val)
1422{
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001423 union power_supply_propval pval;
Nicholas Troast34db5032016-03-28 12:26:44 -07001424 int rc;
1425 u8 stat;
1426
1427 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat);
1428 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001429 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001430 rc);
1431 return rc;
1432 }
1433 smblib_dbg(chg, PR_REGISTER, "BATTERY_CHARGER_STATUS_2 = 0x%02x\n",
1434 stat);
1435
1436 if (stat & CHARGER_ERROR_STATUS_BAT_OV_BIT) {
Subbaraman Narayanamurthya379c4f2016-10-21 17:30:46 -07001437 rc = smblib_get_prop_batt_voltage_now(chg, &pval);
1438 if (!rc) {
1439 /*
1440 * If Vbatt is within 40mV above Vfloat, then don't
1441 * treat it as overvoltage.
1442 */
1443 if (pval.intval >=
1444 get_effective_result(chg->fv_votable) + 40000) {
1445 val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
1446 smblib_err(chg, "battery over-voltage\n");
1447 goto done;
1448 }
1449 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001450 }
1451
Harry Yang668fc5e2016-07-12 16:51:47 -07001452 if (stat & BAT_TEMP_STATUS_TOO_COLD_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001453 val->intval = POWER_SUPPLY_HEALTH_COLD;
Harry Yang668fc5e2016-07-12 16:51:47 -07001454 else if (stat & BAT_TEMP_STATUS_TOO_HOT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001455 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
Harry Yang668fc5e2016-07-12 16:51:47 -07001456 else if (stat & BAT_TEMP_STATUS_COLD_SOFT_LIMIT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001457 val->intval = POWER_SUPPLY_HEALTH_COOL;
Harry Yang668fc5e2016-07-12 16:51:47 -07001458 else if (stat & BAT_TEMP_STATUS_HOT_SOFT_LIMIT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001459 val->intval = POWER_SUPPLY_HEALTH_WARM;
Harry Yang668fc5e2016-07-12 16:51:47 -07001460 else
Nicholas Troast34db5032016-03-28 12:26:44 -07001461 val->intval = POWER_SUPPLY_HEALTH_GOOD;
Nicholas Troast34db5032016-03-28 12:26:44 -07001462
1463done:
1464 return rc;
1465}
1466
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001467int smblib_get_prop_system_temp_level(struct smb_charger *chg,
1468 union power_supply_propval *val)
1469{
1470 val->intval = chg->system_temp_level;
1471 return 0;
1472}
1473
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001474int smblib_get_prop_input_current_limited(struct smb_charger *chg,
1475 union power_supply_propval *val)
1476{
1477 u8 stat;
1478 int rc;
1479
1480 rc = smblib_read(chg, AICL_STATUS_REG, &stat);
1481 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001482 smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n", rc);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001483 return rc;
1484 }
1485 val->intval = (stat & SOFT_ILIMIT_BIT) || chg->is_hdc;
1486 return 0;
1487}
1488
Nicholas Troast66b21d72016-09-20 15:33:20 -07001489int smblib_get_prop_batt_voltage_now(struct smb_charger *chg,
1490 union power_supply_propval *val)
1491{
1492 int rc;
1493
1494 if (!chg->bms_psy)
1495 return -EINVAL;
1496
1497 rc = power_supply_get_property(chg->bms_psy,
1498 POWER_SUPPLY_PROP_VOLTAGE_NOW, val);
1499 return rc;
1500}
1501
1502int smblib_get_prop_batt_current_now(struct smb_charger *chg,
1503 union power_supply_propval *val)
1504{
1505 int rc;
1506
1507 if (!chg->bms_psy)
1508 return -EINVAL;
1509
1510 rc = power_supply_get_property(chg->bms_psy,
1511 POWER_SUPPLY_PROP_CURRENT_NOW, val);
1512 return rc;
1513}
1514
1515int smblib_get_prop_batt_temp(struct smb_charger *chg,
1516 union power_supply_propval *val)
1517{
1518 int rc;
1519
1520 if (!chg->bms_psy)
1521 return -EINVAL;
1522
1523 rc = power_supply_get_property(chg->bms_psy,
1524 POWER_SUPPLY_PROP_TEMP, val);
1525 return rc;
1526}
1527
Harry Yangbedee332016-08-31 16:14:29 -07001528int smblib_get_prop_step_chg_step(struct smb_charger *chg,
1529 union power_supply_propval *val)
1530{
1531 int rc;
1532 u8 stat;
1533
1534 if (!chg->step_chg_enabled) {
1535 val->intval = -1;
1536 return 0;
1537 }
1538
1539 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1540 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001541 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Harry Yangbedee332016-08-31 16:14:29 -07001542 rc);
1543 return rc;
1544 }
1545
1546 val->intval = (stat & STEP_CHARGING_STATUS_MASK) >>
1547 STEP_CHARGING_STATUS_SHIFT;
1548
1549 return rc;
1550}
1551
Subbaraman Narayanamurthyb491d022016-10-10 20:22:48 -07001552int smblib_get_prop_batt_charge_done(struct smb_charger *chg,
1553 union power_supply_propval *val)
1554{
1555 int rc;
1556 u8 stat;
1557
1558 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",
Subbaraman Narayanamurthyb491d022016-10-10 20:22:48 -07001561 rc);
1562 return rc;
1563 }
1564
1565 stat = stat & BATTERY_CHARGER_STATUS_MASK;
1566 val->intval = (stat == TERMINATE_CHARGE);
1567 return 0;
1568}
1569
Nicholas Troast34db5032016-03-28 12:26:44 -07001570/***********************
1571 * BATTERY PSY SETTERS *
1572 ***********************/
1573
1574int smblib_set_prop_input_suspend(struct smb_charger *chg,
1575 const union power_supply_propval *val)
1576{
1577 int rc;
1578
1579 rc = vote(chg->usb_suspend_votable, USER_VOTER, (bool)val->intval, 0);
1580 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001581 smblib_err(chg, "Couldn't vote to %s USB rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001582 (bool)val->intval ? "suspend" : "resume", rc);
1583 return rc;
1584 }
1585
1586 rc = vote(chg->dc_suspend_votable, USER_VOTER, (bool)val->intval, 0);
1587 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001588 smblib_err(chg, "Couldn't vote to %s DC rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001589 (bool)val->intval ? "suspend" : "resume", rc);
1590 return rc;
1591 }
1592
Nicholas Troast61ff40f2016-07-08 10:59:22 -07001593 power_supply_changed(chg->batt_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07001594 return rc;
1595}
1596
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07001597int smblib_set_prop_batt_capacity(struct smb_charger *chg,
1598 const union power_supply_propval *val)
1599{
1600 chg->fake_capacity = val->intval;
1601
1602 power_supply_changed(chg->batt_psy);
1603
1604 return 0;
1605}
1606
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001607int smblib_set_prop_system_temp_level(struct smb_charger *chg,
1608 const union power_supply_propval *val)
1609{
1610 if (val->intval < 0)
1611 return -EINVAL;
1612
1613 if (chg->thermal_levels <= 0)
1614 return -EINVAL;
1615
1616 if (val->intval > chg->thermal_levels)
1617 return -EINVAL;
1618
1619 chg->system_temp_level = val->intval;
1620 if (chg->system_temp_level == chg->thermal_levels)
Harry Yangaba1f5f2016-09-28 10:47:29 -07001621 return vote(chg->chg_disable_votable,
1622 THERMAL_DAEMON_VOTER, true, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001623
Harry Yangaba1f5f2016-09-28 10:47:29 -07001624 vote(chg->chg_disable_votable, THERMAL_DAEMON_VOTER, false, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001625 if (chg->system_temp_level == 0)
Harry Yangaba1f5f2016-09-28 10:47:29 -07001626 return vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, false, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001627
Harry Yangaba1f5f2016-09-28 10:47:29 -07001628 vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, true,
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001629 chg->thermal_mitigation[chg->system_temp_level]);
1630 return 0;
1631}
1632
Nicholas Troast34db5032016-03-28 12:26:44 -07001633/*******************
Harry Yangf3023592016-07-20 14:56:41 -07001634 * DC PSY GETTERS *
1635 *******************/
1636
1637int smblib_get_prop_dc_present(struct smb_charger *chg,
1638 union power_supply_propval *val)
1639{
Nicholas Troastdeae99c2016-11-14 09:13:01 -08001640 int rc;
Harry Yangf3023592016-07-20 14:56:41 -07001641 u8 stat;
1642
Nicholas Troastdeae99c2016-11-14 09:13:01 -08001643 rc = smblib_read(chg, DCIN_BASE + INT_RT_STS_OFFSET, &stat);
Harry Yangf3023592016-07-20 14:56:41 -07001644 if (rc < 0) {
Nicholas Troastdeae99c2016-11-14 09:13:01 -08001645 smblib_err(chg, "Couldn't read DCIN_RT_STS rc=%d\n", rc);
Harry Yangf3023592016-07-20 14:56:41 -07001646 return rc;
1647 }
Harry Yangf3023592016-07-20 14:56:41 -07001648
1649 val->intval = (bool)(stat & DCIN_PLUGIN_RT_STS_BIT);
Nicholas Troastdeae99c2016-11-14 09:13:01 -08001650 return 0;
Harry Yangf3023592016-07-20 14:56:41 -07001651}
1652
1653int smblib_get_prop_dc_online(struct smb_charger *chg,
1654 union power_supply_propval *val)
1655{
1656 int rc = 0;
1657 u8 stat;
1658
1659 if (get_client_vote(chg->dc_suspend_votable, USER_VOTER)) {
1660 val->intval = false;
1661 return rc;
1662 }
1663
1664 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
1665 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001666 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
Harry Yangf3023592016-07-20 14:56:41 -07001667 rc);
1668 return rc;
1669 }
1670 smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
1671 stat);
1672
1673 val->intval = (stat & USE_DCIN_BIT) &&
Vic Wei7ade2842016-12-14 18:47:49 -08001674 (stat & VALID_INPUT_POWER_SOURCE_STS_BIT);
Harry Yangf3023592016-07-20 14:56:41 -07001675
1676 return rc;
1677}
1678
1679int smblib_get_prop_dc_current_max(struct smb_charger *chg,
1680 union power_supply_propval *val)
1681{
1682 val->intval = get_effective_result_locked(chg->dc_icl_votable);
1683 return 0;
1684}
1685
1686/*******************
Harry Yangd89ff1f2016-12-05 14:59:11 -08001687 * DC PSY SETTERS *
Harry Yangf3023592016-07-20 14:56:41 -07001688 * *****************/
1689
1690int smblib_set_prop_dc_current_max(struct smb_charger *chg,
1691 const union power_supply_propval *val)
1692{
1693 int rc;
1694
1695 rc = vote(chg->dc_icl_votable, USER_VOTER, true, val->intval);
1696 return rc;
1697}
1698
1699/*******************
Nicholas Troast34db5032016-03-28 12:26:44 -07001700 * USB PSY GETTERS *
1701 *******************/
1702
1703int smblib_get_prop_usb_present(struct smb_charger *chg,
1704 union power_supply_propval *val)
1705{
Nicholas Troastdeae99c2016-11-14 09:13:01 -08001706 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001707 u8 stat;
1708
Nicholas Troastdeae99c2016-11-14 09:13:01 -08001709 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
Nicholas Troast34db5032016-03-28 12:26:44 -07001710 if (rc < 0) {
Nicholas Troastdeae99c2016-11-14 09:13:01 -08001711 smblib_err(chg, "Couldn't read USBIN_RT_STS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07001712 return rc;
1713 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001714
Nicholas Troastdeae99c2016-11-14 09:13:01 -08001715 val->intval = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
1716 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07001717}
1718
1719int smblib_get_prop_usb_online(struct smb_charger *chg,
1720 union power_supply_propval *val)
1721{
1722 int rc = 0;
1723 u8 stat;
1724
1725 if (get_client_vote(chg->usb_suspend_votable, USER_VOTER)) {
1726 val->intval = false;
1727 return rc;
1728 }
1729
1730 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
1731 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001732 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001733 rc);
1734 return rc;
1735 }
1736 smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
1737 stat);
1738
1739 val->intval = (stat & USE_USBIN_BIT) &&
Vic Wei7ade2842016-12-14 18:47:49 -08001740 (stat & VALID_INPUT_POWER_SOURCE_STS_BIT);
Nicholas Troast34db5032016-03-28 12:26:44 -07001741 return rc;
1742}
1743
1744int smblib_get_prop_usb_voltage_now(struct smb_charger *chg,
1745 union power_supply_propval *val)
1746{
Harry Yangba874ce2016-08-19 14:17:01 -07001747 int rc = 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07001748
Harry Yangba874ce2016-08-19 14:17:01 -07001749 rc = smblib_get_prop_usb_present(chg, val);
1750 if (rc < 0 || !val->intval)
1751 return rc;
1752
1753 if (!chg->iio.usbin_v_chan ||
1754 PTR_ERR(chg->iio.usbin_v_chan) == -EPROBE_DEFER)
1755 chg->iio.usbin_v_chan = iio_channel_get(chg->dev, "usbin_v");
1756
1757 if (IS_ERR(chg->iio.usbin_v_chan))
1758 return PTR_ERR(chg->iio.usbin_v_chan);
1759
1760 return iio_read_channel_processed(chg->iio.usbin_v_chan, &val->intval);
Nicholas Troast34db5032016-03-28 12:26:44 -07001761}
1762
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07001763int smblib_get_prop_pd_current_max(struct smb_charger *chg,
1764 union power_supply_propval *val)
1765{
1766 val->intval = get_client_vote_locked(chg->usb_icl_votable, PD_VOTER);
1767 return 0;
1768}
1769
Nicholas Troast34db5032016-03-28 12:26:44 -07001770int smblib_get_prop_usb_current_max(struct smb_charger *chg,
1771 union power_supply_propval *val)
1772{
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07001773 val->intval = get_client_vote_locked(chg->usb_icl_votable,
1774 USB_PSY_VOTER);
Nicholas Troast34db5032016-03-28 12:26:44 -07001775 return 0;
1776}
1777
Harry Yangba874ce2016-08-19 14:17:01 -07001778int smblib_get_prop_usb_current_now(struct smb_charger *chg,
1779 union power_supply_propval *val)
1780{
1781 int rc = 0;
1782
1783 rc = smblib_get_prop_usb_present(chg, val);
1784 if (rc < 0 || !val->intval)
1785 return rc;
1786
1787 if (!chg->iio.usbin_i_chan ||
1788 PTR_ERR(chg->iio.usbin_i_chan) == -EPROBE_DEFER)
1789 chg->iio.usbin_i_chan = iio_channel_get(chg->dev, "usbin_i");
1790
1791 if (IS_ERR(chg->iio.usbin_i_chan))
1792 return PTR_ERR(chg->iio.usbin_i_chan);
1793
1794 return iio_read_channel_processed(chg->iio.usbin_i_chan, &val->intval);
1795}
1796
1797int smblib_get_prop_charger_temp(struct smb_charger *chg,
1798 union power_supply_propval *val)
1799{
1800 int rc;
1801
1802 if (!chg->iio.temp_chan ||
1803 PTR_ERR(chg->iio.temp_chan) == -EPROBE_DEFER)
1804 chg->iio.temp_chan = iio_channel_get(chg->dev, "charger_temp");
1805
1806 if (IS_ERR(chg->iio.temp_chan))
1807 return PTR_ERR(chg->iio.temp_chan);
1808
1809 rc = iio_read_channel_processed(chg->iio.temp_chan, &val->intval);
1810 val->intval /= 100;
1811 return rc;
1812}
1813
1814int smblib_get_prop_charger_temp_max(struct smb_charger *chg,
1815 union power_supply_propval *val)
1816{
1817 int rc;
1818
1819 if (!chg->iio.temp_max_chan ||
1820 PTR_ERR(chg->iio.temp_max_chan) == -EPROBE_DEFER)
1821 chg->iio.temp_max_chan = iio_channel_get(chg->dev,
1822 "charger_temp_max");
1823 if (IS_ERR(chg->iio.temp_max_chan))
1824 return PTR_ERR(chg->iio.temp_max_chan);
1825
1826 rc = iio_read_channel_processed(chg->iio.temp_max_chan, &val->intval);
1827 val->intval /= 100;
1828 return rc;
1829}
1830
Nicholas Troast34db5032016-03-28 12:26:44 -07001831int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
1832 union power_supply_propval *val)
1833{
1834 int rc = 0;
1835 u8 stat;
1836
1837 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
1838 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001839 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07001840 return rc;
1841 }
1842 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n",
1843 stat);
1844
1845 if (stat & CC_ATTACHED_BIT)
1846 val->intval = (bool)(stat & CC_ORIENTATION_BIT) + 1;
1847 else
1848 val->intval = 0;
1849
1850 return rc;
1851}
1852
1853static const char * const smblib_typec_mode_name[] = {
1854 [POWER_SUPPLY_TYPEC_NONE] = "NONE",
1855 [POWER_SUPPLY_TYPEC_SOURCE_DEFAULT] = "SOURCE_DEFAULT",
1856 [POWER_SUPPLY_TYPEC_SOURCE_MEDIUM] = "SOURCE_MEDIUM",
1857 [POWER_SUPPLY_TYPEC_SOURCE_HIGH] = "SOURCE_HIGH",
1858 [POWER_SUPPLY_TYPEC_NON_COMPLIANT] = "NON_COMPLIANT",
1859 [POWER_SUPPLY_TYPEC_SINK] = "SINK",
1860 [POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE] = "SINK_POWERED_CABLE",
1861 [POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY] = "SINK_DEBUG_ACCESSORY",
1862 [POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER] = "SINK_AUDIO_ADAPTER",
1863 [POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY] = "POWERED_CABLE_ONLY",
1864};
1865
1866static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
1867{
1868 int rc;
1869 u8 stat;
1870
1871 rc = smblib_read(chg, TYPE_C_STATUS_1_REG, &stat);
1872 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001873 smblib_err(chg, "Couldn't read TYPE_C_STATUS_1 rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07001874 return POWER_SUPPLY_TYPEC_NONE;
1875 }
1876 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_1 = 0x%02x\n", stat);
1877
1878 switch (stat) {
1879 case 0:
1880 return POWER_SUPPLY_TYPEC_NONE;
1881 case UFP_TYPEC_RDSTD_BIT:
1882 return POWER_SUPPLY_TYPEC_SOURCE_DEFAULT;
1883 case UFP_TYPEC_RD1P5_BIT:
1884 return POWER_SUPPLY_TYPEC_SOURCE_MEDIUM;
1885 case UFP_TYPEC_RD3P0_BIT:
1886 return POWER_SUPPLY_TYPEC_SOURCE_HIGH;
1887 default:
1888 break;
1889 }
1890
1891 return POWER_SUPPLY_TYPEC_NON_COMPLIANT;
1892}
1893
1894static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
1895{
1896 int rc;
1897 u8 stat;
1898
1899 rc = smblib_read(chg, TYPE_C_STATUS_2_REG, &stat);
1900 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001901 smblib_err(chg, "Couldn't read TYPE_C_STATUS_2 rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07001902 return POWER_SUPPLY_TYPEC_NONE;
1903 }
1904 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_2 = 0x%02x\n", stat);
1905
1906 switch (stat & DFP_TYPEC_MASK) {
1907 case DFP_RA_RA_BIT:
1908 return POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER;
1909 case DFP_RD_RD_BIT:
1910 return POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY;
1911 case DFP_RD_RA_VCONN_BIT:
1912 return POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE;
1913 case DFP_RD_OPEN_BIT:
1914 return POWER_SUPPLY_TYPEC_SINK;
1915 case DFP_RA_OPEN_BIT:
1916 return POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY;
1917 default:
1918 break;
1919 }
1920
1921 return POWER_SUPPLY_TYPEC_NONE;
1922}
1923
1924int smblib_get_prop_typec_mode(struct smb_charger *chg,
1925 union power_supply_propval *val)
1926{
1927 int rc;
1928 u8 stat;
1929
1930 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
1931 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001932 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07001933 val->intval = POWER_SUPPLY_TYPEC_NONE;
1934 return rc;
1935 }
1936 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat);
1937
1938 if (!(stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT)) {
1939 val->intval = POWER_SUPPLY_TYPEC_NONE;
1940 return rc;
1941 }
1942
1943 if (stat & UFP_DFP_MODE_STATUS_BIT)
1944 val->intval = smblib_get_prop_dfp_mode(chg);
1945 else
1946 val->intval = smblib_get_prop_ufp_mode(chg);
1947
1948 return rc;
1949}
1950
1951int smblib_get_prop_typec_power_role(struct smb_charger *chg,
1952 union power_supply_propval *val)
1953{
1954 int rc = 0;
1955 u8 ctrl;
1956
1957 rc = smblib_read(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &ctrl);
1958 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001959 smblib_err(chg, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001960 rc);
1961 return rc;
1962 }
1963 smblib_dbg(chg, PR_REGISTER, "TYPE_C_INTRPT_ENB_SOFTWARE_CTRL = 0x%02x\n",
1964 ctrl);
1965
1966 if (ctrl & TYPEC_DISABLE_CMD_BIT) {
1967 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
1968 return rc;
1969 }
1970
1971 switch (ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT)) {
1972 case 0:
1973 val->intval = POWER_SUPPLY_TYPEC_PR_DUAL;
1974 break;
1975 case DFP_EN_CMD_BIT:
1976 val->intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
1977 break;
1978 case UFP_EN_CMD_BIT:
1979 val->intval = POWER_SUPPLY_TYPEC_PR_SINK;
1980 break;
1981 default:
1982 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07001983 smblib_err(chg, "unsupported power role 0x%02lx\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07001984 ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT));
1985 return -EINVAL;
1986 }
1987
1988 return rc;
1989}
1990
1991int smblib_get_prop_pd_allowed(struct smb_charger *chg,
1992 union power_supply_propval *val)
1993{
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07001994 val->intval = get_effective_result(chg->pd_allowed_votable);
Nicholas Troast34db5032016-03-28 12:26:44 -07001995 return 0;
1996}
1997
Nicholas Troast133a7f52016-06-29 13:48:20 -07001998int smblib_get_prop_input_current_settled(struct smb_charger *chg,
1999 union power_supply_propval *val)
2000{
2001 return smblib_get_charge_param(chg, &chg->param.icl_stat, &val->intval);
2002}
2003
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002004int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg,
2005 union power_supply_propval *val)
2006{
2007 int rc;
2008 u8 ctrl;
2009
2010 rc = smblib_read(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &ctrl);
2011 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002012 smblib_err(chg, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG rc=%d\n",
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002013 rc);
2014 return rc;
2015 }
2016 val->intval = ctrl & EXIT_SNK_BASED_ON_CC_BIT;
2017 return 0;
2018}
2019
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07002020int smblib_get_pe_start(struct smb_charger *chg,
2021 union power_supply_propval *val)
2022{
2023 /*
2024 * hvdcp timeout voter is the last one to allow pd. Use its vote
2025 * to indicate start of pe engine
2026 */
2027 val->intval
2028 = !get_client_vote_locked(chg->pd_disallowed_votable_indirect,
2029 HVDCP_TIMEOUT_VOTER);
2030 return 0;
2031}
2032
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002033int smblib_get_prop_die_health(struct smb_charger *chg,
Nicholas Troastb021dd92017-01-31 18:43:38 -08002034 union power_supply_propval *val)
2035{
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002036 int rc;
Nicholas Troastb021dd92017-01-31 18:43:38 -08002037 u8 stat;
2038
2039 rc = smblib_read(chg, TEMP_RANGE_STATUS_REG, &stat);
2040 if (rc < 0) {
2041 smblib_err(chg, "Couldn't read TEMP_RANGE_STATUS_REG rc=%d\n",
2042 rc);
2043 return rc;
2044 }
2045
Nicholas Troast7fdbd2e2017-02-08 10:47:37 -08002046 /* TEMP_RANGE bits are mutually exclusive */
2047 switch (stat & TEMP_RANGE_MASK) {
2048 case TEMP_BELOW_RANGE_BIT:
2049 val->intval = POWER_SUPPLY_HEALTH_COOL;
2050 break;
2051 case TEMP_WITHIN_RANGE_BIT:
2052 val->intval = POWER_SUPPLY_HEALTH_WARM;
2053 break;
2054 case TEMP_ABOVE_RANGE_BIT:
2055 val->intval = POWER_SUPPLY_HEALTH_HOT;
2056 break;
2057 case ALERT_LEVEL_BIT:
2058 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
2059 break;
2060 default:
2061 val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
Nicholas Troastb021dd92017-01-31 18:43:38 -08002062 }
2063
Nicholas Troastb021dd92017-01-31 18:43:38 -08002064 return 0;
2065}
2066
Nicholas Troast34db5032016-03-28 12:26:44 -07002067/*******************
2068 * USB PSY SETTERS *
2069 * *****************/
2070
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002071int smblib_set_prop_pd_current_max(struct smb_charger *chg,
2072 const union power_supply_propval *val)
2073{
2074 int rc;
2075
2076 if (chg->pd_active)
2077 rc = vote(chg->usb_icl_votable, PD_VOTER, true, val->intval);
2078 else
2079 rc = -EPERM;
2080
2081 return rc;
2082}
2083
Nicholas Troast34db5032016-03-28 12:26:44 -07002084int smblib_set_prop_usb_current_max(struct smb_charger *chg,
2085 const union power_supply_propval *val)
2086{
Nicholas Troast8d33b7d2017-01-16 11:18:38 -08002087 int rc = 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07002088
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002089 if (!chg->pd_active) {
2090 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
2091 true, val->intval);
2092 } else if (chg->system_suspend_supported) {
2093 if (val->intval <= USBIN_25MA)
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302094 rc = vote(chg->usb_icl_votable,
2095 PD_SUSPEND_SUPPORTED_VOTER, true, val->intval);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002096 else
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302097 rc = vote(chg->usb_icl_votable,
2098 PD_SUSPEND_SUPPORTED_VOTER, false, 0);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07002099 }
Nicholas Troast34db5032016-03-28 12:26:44 -07002100 return rc;
2101}
2102
Harry Yangd89ff1f2016-12-05 14:59:11 -08002103int smblib_set_prop_boost_current(struct smb_charger *chg,
2104 const union power_supply_propval *val)
2105{
2106 int rc = 0;
2107
2108 rc = smblib_set_charge_param(chg, &chg->param.freq_boost,
2109 val->intval <= chg->boost_threshold_ua ?
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05302110 chg->chg_freq.freq_below_otg_threshold :
2111 chg->chg_freq.freq_above_otg_threshold);
Harry Yangd89ff1f2016-12-05 14:59:11 -08002112 if (rc < 0) {
2113 dev_err(chg->dev, "Error in setting freq_boost rc=%d\n", rc);
2114 return rc;
2115 }
2116
2117 chg->boost_current_ua = val->intval;
2118 return rc;
2119}
2120
Nicholas Troast34db5032016-03-28 12:26:44 -07002121int smblib_set_prop_typec_power_role(struct smb_charger *chg,
2122 const union power_supply_propval *val)
2123{
2124 int rc = 0;
2125 u8 power_role;
2126
2127 switch (val->intval) {
2128 case POWER_SUPPLY_TYPEC_PR_NONE:
2129 power_role = TYPEC_DISABLE_CMD_BIT;
2130 break;
2131 case POWER_SUPPLY_TYPEC_PR_DUAL:
2132 power_role = 0;
2133 break;
2134 case POWER_SUPPLY_TYPEC_PR_SINK:
2135 power_role = UFP_EN_CMD_BIT;
2136 break;
2137 case POWER_SUPPLY_TYPEC_PR_SOURCE:
2138 power_role = DFP_EN_CMD_BIT;
2139 break;
2140 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002141 smblib_err(chg, "power role %d not supported\n", val->intval);
Nicholas Troast34db5032016-03-28 12:26:44 -07002142 return -EINVAL;
2143 }
2144
2145 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2146 TYPEC_POWER_ROLE_CMD_MASK, power_role);
2147 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002148 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 -07002149 power_role, rc);
2150 return rc;
2151 }
2152
2153 return rc;
2154}
2155
2156int smblib_set_prop_usb_voltage_min(struct smb_charger *chg,
2157 const union power_supply_propval *val)
2158{
2159 int rc, min_uv;
2160
2161 min_uv = min(val->intval, chg->voltage_max_uv);
2162 rc = smblib_set_usb_pd_allowed_voltage(chg, min_uv,
2163 chg->voltage_max_uv);
2164 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002165 smblib_err(chg, "invalid max voltage %duV rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002166 val->intval, rc);
2167 return rc;
2168 }
2169
Harry Yangaba1f5f2016-09-28 10:47:29 -07002170 if (chg->mode == PARALLEL_MASTER)
2171 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER,
2172 min_uv > MICRO_5V, 0);
2173
2174 chg->voltage_min_uv = min_uv;
Nicholas Troast34db5032016-03-28 12:26:44 -07002175 return rc;
2176}
2177
2178int smblib_set_prop_usb_voltage_max(struct smb_charger *chg,
2179 const union power_supply_propval *val)
2180{
2181 int rc, max_uv;
2182
2183 max_uv = max(val->intval, chg->voltage_min_uv);
2184 rc = smblib_set_usb_pd_allowed_voltage(chg, chg->voltage_min_uv,
2185 max_uv);
2186 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002187 smblib_err(chg, "invalid min voltage %duV rc=%d\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002188 val->intval, rc);
2189 return rc;
2190 }
2191
Harry Yangaba1f5f2016-09-28 10:47:29 -07002192 chg->voltage_max_uv = max_uv;
Nicholas Troast34db5032016-03-28 12:26:44 -07002193 return rc;
2194}
2195
2196int smblib_set_prop_pd_active(struct smb_charger *chg,
2197 const union power_supply_propval *val)
2198{
2199 int rc;
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07002200 u8 stat = 0;
2201 bool cc_debounced;
2202 bool orientation;
2203 bool pd_active = val->intval;
Nicholas Troast34db5032016-03-28 12:26:44 -07002204
2205 if (!get_effective_result(chg->pd_allowed_votable)) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002206 smblib_err(chg, "PD is not allowed\n");
Nicholas Troast34db5032016-03-28 12:26:44 -07002207 return -EINVAL;
2208 }
2209
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07002210 vote(chg->apsd_disable_votable, PD_VOTER, pd_active, 0);
2211 vote(chg->pd_allowed_votable, PD_VOTER, pd_active, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07002212
Harry Yang88acff42016-09-21 14:56:06 -07002213 /*
2214 * VCONN_EN_ORIENTATION_BIT controls whether to use CC1 or CC2 line
2215 * when TYPEC_SPARE_CFG_BIT (CC pin selection s/w override) is set
2216 * or when VCONN_EN_VALUE_BIT is set.
2217 */
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07002218 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
2219 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002220 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07002221 return rc;
2222 }
Harry Yang88acff42016-09-21 14:56:06 -07002223
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07002224 if (pd_active) {
2225 orientation = stat & CC_ORIENTATION_BIT;
Harry Yang88acff42016-09-21 14:56:06 -07002226 rc = smblib_masked_write(chg,
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07002227 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2228 VCONN_EN_ORIENTATION_BIT,
2229 orientation ? 0 : VCONN_EN_ORIENTATION_BIT);
2230 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002231 smblib_err(chg,
Harry Yang88acff42016-09-21 14:56:06 -07002232 "Couldn't enable vconn on CC line rc=%d\n", rc);
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07002233 return rc;
2234 }
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302235 /*
2236 * Enforce 500mA for PD until the real vote comes in later.
2237 * It is guaranteed that pd_active is set prior to
2238 * pd_current_max
2239 */
Harry Yangcd995202016-11-07 13:32:52 -08002240 rc = vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
2241 if (rc < 0) {
2242 smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n",
2243 rc);
2244 return rc;
2245 }
2246
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002247 /* clear USB ICL vote for DCP_VOTER */
Harry Yang631b99e2016-11-17 11:24:25 -08002248 rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002249 if (rc < 0)
2250 smblib_err(chg,
2251 "Couldn't un-vote DCP from USB ICL rc=%d\n",
2252 rc);
2253
2254 /* clear USB ICL vote for PL_USBIN_USBIN_VOTER */
2255 rc = vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
2256 if (rc < 0)
2257 smblib_err(chg,
2258 "Couldn't un-vote PL_USBIN_USBIN from USB ICL rc=%d\n",
2259 rc);
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302260
2261 /* remove USB_PSY_VOTER */
2262 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
2263 if (rc < 0) {
2264 smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
Harry Yang631b99e2016-11-17 11:24:25 -08002265 return rc;
2266 }
Harry Yang88acff42016-09-21 14:56:06 -07002267 }
2268
2269 /* CC pin selection s/w override in PD session; h/w otherwise. */
2270 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
2271 TYPEC_SPARE_CFG_BIT,
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07002272 pd_active ? TYPEC_SPARE_CFG_BIT : 0);
Harry Yang88acff42016-09-21 14:56:06 -07002273 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002274 smblib_err(chg, "Couldn't change cc_out ctrl to %s rc=%d\n",
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07002275 pd_active ? "SW" : "HW", rc);
Harry Yang88acff42016-09-21 14:56:06 -07002276 return rc;
2277 }
2278
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07002279 cc_debounced = (bool)(stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
2280 if (!pd_active && cc_debounced)
2281 try_rerun_apsd_for_hvdcp(chg);
2282
2283 chg->pd_active = pd_active;
Harry Yang6607b4a2016-05-17 17:50:09 -07002284 smblib_update_usb_type(chg);
Abhijeet Dharmapurikar76e2af52016-10-06 17:25:01 -07002285 power_supply_changed(chg->usb_psy);
2286
Nicholas Troast34db5032016-03-28 12:26:44 -07002287 return rc;
2288}
2289
Fenglin Wuedd70792016-11-22 13:16:19 +08002290int smblib_set_prop_ship_mode(struct smb_charger *chg,
2291 const union power_supply_propval *val)
2292{
2293 int rc;
2294
2295 smblib_dbg(chg, PR_MISC, "Set ship mode: %d!!\n", !!val->intval);
2296
2297 rc = smblib_masked_write(chg, SHIP_MODE_REG, SHIP_MODE_EN_BIT,
2298 !!val->intval ? SHIP_MODE_EN_BIT : 0);
2299 if (rc < 0)
2300 dev_err(chg->dev, "Couldn't %s ship mode, rc=%d\n",
2301 !!val->intval ? "enable" : "disable", rc);
2302
2303 return rc;
2304}
2305
Harry Yang5e2bb712016-10-18 16:47:48 -07002306int smblib_reg_block_update(struct smb_charger *chg,
2307 struct reg_info *entry)
2308{
2309 int rc = 0;
2310
2311 while (entry && entry->reg) {
2312 rc = smblib_read(chg, entry->reg, &entry->bak);
2313 if (rc < 0) {
2314 dev_err(chg->dev, "Error in reading %s rc=%d\n",
2315 entry->desc, rc);
2316 break;
2317 }
2318 entry->bak &= entry->mask;
2319
2320 rc = smblib_masked_write(chg, entry->reg,
2321 entry->mask, entry->val);
2322 if (rc < 0) {
2323 dev_err(chg->dev, "Error in writing %s rc=%d\n",
2324 entry->desc, rc);
2325 break;
2326 }
2327 entry++;
2328 }
2329
2330 return rc;
2331}
2332
2333int smblib_reg_block_restore(struct smb_charger *chg,
2334 struct reg_info *entry)
2335{
2336 int rc = 0;
2337
2338 while (entry && entry->reg) {
2339 rc = smblib_masked_write(chg, entry->reg,
2340 entry->mask, entry->bak);
2341 if (rc < 0) {
2342 dev_err(chg->dev, "Error in writing %s rc=%d\n",
2343 entry->desc, rc);
2344 break;
2345 }
2346 entry++;
2347 }
2348
2349 return rc;
2350}
2351
Harry Yang755a34b2016-11-01 01:18:51 -07002352static struct reg_info cc2_detach_settings[] = {
2353 {
Nicholas Troast62f5e142017-01-27 13:55:49 -08002354 .reg = TYPE_C_CFG_REG,
2355 .mask = APSD_START_ON_CC_BIT,
2356 .val = 0,
2357 .desc = "TYPE_C_CFG_REG",
2358 },
2359 {
Harry Yang755a34b2016-11-01 01:18:51 -07002360 .reg = TYPE_C_CFG_2_REG,
2361 .mask = TYPE_C_UFP_MODE_BIT | EN_TRY_SOURCE_MODE_BIT,
2362 .val = TYPE_C_UFP_MODE_BIT,
2363 .desc = "TYPE_C_CFG_2_REG",
2364 },
2365 {
2366 .reg = TYPE_C_CFG_3_REG,
2367 .mask = EN_TRYSINK_MODE_BIT,
2368 .val = 0,
2369 .desc = "TYPE_C_CFG_3_REG",
2370 },
2371 {
2372 .reg = TAPER_TIMER_SEL_CFG_REG,
2373 .mask = TYPEC_SPARE_CFG_BIT,
2374 .val = TYPEC_SPARE_CFG_BIT,
2375 .desc = "TAPER_TIMER_SEL_CFG_REG",
2376 },
2377 {
2378 .reg = TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2379 .mask = VCONN_EN_ORIENTATION_BIT,
2380 .val = 0,
2381 .desc = "TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG",
2382 },
2383 {
2384 .reg = MISC_CFG_REG,
2385 .mask = TCC_DEBOUNCE_20MS_BIT,
2386 .val = TCC_DEBOUNCE_20MS_BIT,
2387 .desc = "Tccdebounce time"
2388 },
2389 {
2390 },
2391};
2392
2393static int smblib_cc2_sink_removal_enter(struct smb_charger *chg)
2394{
2395 int rc = 0;
2396 union power_supply_propval cc2_val = {0, };
2397
2398 if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
2399 return rc;
2400
2401 if (chg->cc2_sink_detach_flag != CC2_SINK_NONE)
2402 return rc;
2403
2404 rc = smblib_get_prop_typec_cc_orientation(chg, &cc2_val);
2405 if (rc < 0) {
2406 smblib_err(chg, "Couldn't get cc orientation rc=%d\n", rc);
2407 return rc;
2408 }
2409 if (cc2_val.intval == 1)
2410 return rc;
2411
2412 rc = smblib_get_prop_typec_mode(chg, &cc2_val);
2413 if (rc < 0) {
2414 smblib_err(chg, "Couldn't get prop typec mode rc=%d\n", rc);
2415 return rc;
2416 }
2417
2418 switch (cc2_val.intval) {
2419 case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
2420 smblib_reg_block_update(chg, cc2_detach_settings);
2421 chg->cc2_sink_detach_flag = CC2_SINK_STD;
2422 schedule_work(&chg->rdstd_cc2_detach_work);
2423 break;
Harry Yang86e4d852016-11-07 15:08:47 -08002424 case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
2425 case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
2426 chg->cc2_sink_detach_flag = CC2_SINK_MEDIUM_HIGH;
2427 break;
Harry Yang755a34b2016-11-01 01:18:51 -07002428 default:
2429 break;
2430 }
2431
2432 return rc;
2433}
2434
2435static int smblib_cc2_sink_removal_exit(struct smb_charger *chg)
2436{
2437 int rc = 0;
2438
2439 if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
2440 return rc;
2441
2442 if (chg->cc2_sink_detach_flag == CC2_SINK_STD) {
2443 cancel_work_sync(&chg->rdstd_cc2_detach_work);
2444 smblib_reg_block_restore(chg, cc2_detach_settings);
2445 }
2446
2447 chg->cc2_sink_detach_flag = CC2_SINK_NONE;
2448
2449 return rc;
2450}
2451
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002452int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
2453 const union power_supply_propval *val)
2454{
2455 int rc;
2456
2457 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
2458 EXIT_SNK_BASED_ON_CC_BIT,
2459 (val->intval) ? EXIT_SNK_BASED_ON_CC_BIT : 0);
Harry Yang755a34b2016-11-01 01:18:51 -07002460 if (rc < 0) {
2461 smblib_err(chg, "Could not set EXIT_SNK_BASED_ON_CC rc=%d\n",
2462 rc);
2463 return rc;
2464 }
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002465
2466 vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, val->intval, 0);
2467
Harry Yang755a34b2016-11-01 01:18:51 -07002468 if (val->intval)
2469 rc = smblib_cc2_sink_removal_enter(chg);
2470 else
2471 rc = smblib_cc2_sink_removal_exit(chg);
2472
2473 if (rc < 0) {
2474 smblib_err(chg, "Could not detect cc2 removal rc=%d\n", rc);
2475 return rc;
2476 }
2477
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07002478 return rc;
2479}
2480
Nicholas Troast7dbcad22016-10-05 13:30:18 -07002481/************************
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08002482 * USB MAIN PSY GETTERS *
2483 ************************/
2484int smblib_get_prop_fcc_delta(struct smb_charger *chg,
2485 union power_supply_propval *val)
2486{
2487 int rc, jeita_cc_delta_ua, step_cc_delta_ua, hw_cc_delta_ua = 0;
2488
2489 rc = smblib_get_step_cc_delta(chg, &step_cc_delta_ua);
2490 if (rc < 0) {
2491 smblib_err(chg, "Couldn't get step cc delta rc=%d\n", rc);
2492 step_cc_delta_ua = 0;
2493 } else {
2494 hw_cc_delta_ua = step_cc_delta_ua;
2495 }
2496
2497 rc = smblib_get_jeita_cc_delta(chg, &jeita_cc_delta_ua);
2498 if (rc < 0) {
2499 smblib_err(chg, "Couldn't get jeita cc delta rc=%d\n", rc);
2500 jeita_cc_delta_ua = 0;
2501 } else if (jeita_cc_delta_ua < 0) {
2502 /* HW will take the min between JEITA and step charge */
2503 hw_cc_delta_ua = min(hw_cc_delta_ua, jeita_cc_delta_ua);
2504 }
2505
2506 val->intval = hw_cc_delta_ua;
2507 return 0;
2508}
2509
2510/************************
2511 * USB MAIN PSY SETTERS *
2512 ************************/
2513
2514#define SDP_CURRENT_MA 500000
2515#define CDP_CURRENT_MA 1500000
2516#define DCP_CURRENT_MA 1500000
2517#define HVDCP_CURRENT_MA 3000000
2518#define TYPEC_DEFAULT_CURRENT_MA 900000
2519#define TYPEC_MEDIUM_CURRENT_MA 1500000
2520#define TYPEC_HIGH_CURRENT_MA 3000000
2521static int smblib_get_charge_current(struct smb_charger *chg,
2522 int *total_current_ua)
2523{
2524 const struct apsd_result *apsd_result = smblib_update_usb_type(chg);
2525 union power_supply_propval val = {0, };
2526 int rc, typec_source_rd, current_ua;
2527 bool non_compliant;
2528 u8 stat5;
2529
2530 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
2531 if (rc < 0) {
2532 smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc);
2533 return rc;
2534 }
2535 non_compliant = stat5 & TYPEC_NONCOMP_LEGACY_CABLE_STATUS_BIT;
2536
2537 /* get settled ICL */
2538 rc = smblib_get_prop_input_current_settled(chg, &val);
2539 if (rc < 0) {
2540 smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
2541 return rc;
2542 }
2543
2544 typec_source_rd = smblib_get_prop_ufp_mode(chg);
2545
2546 /* QC 2.0/3.0 adapter */
2547 if (apsd_result->bit & (QC_3P0_BIT | QC_2P0_BIT)) {
2548 *total_current_ua = HVDCP_CURRENT_MA;
2549 return 0;
2550 }
2551
2552 if (non_compliant) {
2553 switch (apsd_result->bit) {
2554 case CDP_CHARGER_BIT:
2555 current_ua = CDP_CURRENT_MA;
2556 break;
2557 case DCP_CHARGER_BIT:
2558 case OCP_CHARGER_BIT:
2559 case FLOAT_CHARGER_BIT:
2560 current_ua = DCP_CURRENT_MA;
2561 break;
2562 default:
2563 current_ua = 0;
2564 break;
2565 }
2566
2567 *total_current_ua = max(current_ua, val.intval);
2568 return 0;
2569 }
2570
2571 switch (typec_source_rd) {
2572 case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
2573 switch (apsd_result->bit) {
2574 case CDP_CHARGER_BIT:
2575 current_ua = CDP_CURRENT_MA;
2576 break;
2577 case DCP_CHARGER_BIT:
2578 case OCP_CHARGER_BIT:
2579 case FLOAT_CHARGER_BIT:
2580 current_ua = chg->default_icl_ua;
2581 break;
2582 default:
2583 current_ua = 0;
2584 break;
2585 }
2586 break;
2587 case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
2588 current_ua = TYPEC_MEDIUM_CURRENT_MA;
2589 break;
2590 case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
2591 current_ua = TYPEC_HIGH_CURRENT_MA;
2592 break;
2593 case POWER_SUPPLY_TYPEC_NON_COMPLIANT:
2594 case POWER_SUPPLY_TYPEC_NONE:
2595 default:
2596 current_ua = 0;
2597 break;
2598 }
2599
2600 *total_current_ua = max(current_ua, val.intval);
2601 return 0;
2602}
2603
2604int smblib_set_icl_reduction(struct smb_charger *chg, int reduction_ua)
2605{
2606 int current_ua, rc;
2607
2608 if (reduction_ua == 0) {
2609 chg->icl_reduction_ua = 0;
2610 vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
2611 } else {
2612 /*
2613 * No usb_icl voter means we are defaulting to hw chosen
2614 * max limit. We need a vote from s/w to enforce the reduction.
2615 */
2616 if (get_effective_result(chg->usb_icl_votable) == -EINVAL) {
2617 rc = smblib_get_charge_current(chg, &current_ua);
2618 if (rc < 0) {
2619 pr_err("Failed to get ICL rc=%d\n", rc);
2620 return rc;
2621 }
2622 vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, true,
2623 current_ua);
2624 }
2625 }
2626
2627 return rerun_election(chg->usb_icl_votable);
2628}
2629
2630/************************
Nicholas Troast7dbcad22016-10-05 13:30:18 -07002631 * PARALLEL PSY GETTERS *
2632 ************************/
2633
2634int smblib_get_prop_slave_current_now(struct smb_charger *chg,
2635 union power_supply_propval *pval)
2636{
2637 if (IS_ERR_OR_NULL(chg->iio.batt_i_chan))
2638 chg->iio.batt_i_chan = iio_channel_get(chg->dev, "batt_i");
2639
2640 if (IS_ERR(chg->iio.batt_i_chan))
2641 return PTR_ERR(chg->iio.batt_i_chan);
2642
2643 return iio_read_channel_processed(chg->iio.batt_i_chan, &pval->intval);
2644}
2645
Nicholas Troast34db5032016-03-28 12:26:44 -07002646/**********************
2647 * INTERRUPT HANDLERS *
2648 **********************/
2649
2650irqreturn_t smblib_handle_debug(int irq, void *data)
2651{
2652 struct smb_irq_data *irq_data = data;
2653 struct smb_charger *chg = irq_data->parent_data;
2654
2655 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07002656 return IRQ_HANDLED;
2657}
2658
Nicholas Troast8995a702016-12-05 10:22:22 -08002659irqreturn_t smblib_handle_otg_overcurrent(int irq, void *data)
2660{
2661 struct smb_irq_data *irq_data = data;
2662 struct smb_charger *chg = irq_data->parent_data;
2663 int rc;
2664 u8 stat;
2665
2666 rc = smblib_read(chg, OTG_BASE + INT_RT_STS_OFFSET, &stat);
2667 if (rc < 0) {
2668 dev_err(chg->dev, "Couldn't read OTG_INT_RT_STS rc=%d\n", rc);
2669 return IRQ_HANDLED;
2670 }
2671
Nicholas Troastb11015f2017-01-17 17:56:45 -08002672 if (stat & OTG_OVERCURRENT_RT_STS_BIT)
2673 schedule_work(&chg->otg_oc_work);
Nicholas Troast8995a702016-12-05 10:22:22 -08002674
Nicholas Troast8995a702016-12-05 10:22:22 -08002675 return IRQ_HANDLED;
2676}
2677
Harry Yang6fe72ab2016-06-14 16:21:39 -07002678irqreturn_t smblib_handle_chg_state_change(int irq, void *data)
2679{
2680 struct smb_irq_data *irq_data = data;
2681 struct smb_charger *chg = irq_data->parent_data;
Nicholas Troast8cb77552016-09-23 11:50:18 -07002682 u8 stat;
Harry Yang1d1034c2016-06-15 12:09:42 -07002683 int rc;
Harry Yang6fe72ab2016-06-14 16:21:39 -07002684
2685 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
2686
Nicholas Troast8cb77552016-09-23 11:50:18 -07002687 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
Harry Yang1d1034c2016-06-15 12:09:42 -07002688 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002689 smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
Nicholas Troast8cb77552016-09-23 11:50:18 -07002690 rc);
Harry Yang1d1034c2016-06-15 12:09:42 -07002691 return IRQ_HANDLED;
2692 }
2693
Nicholas Troast8cb77552016-09-23 11:50:18 -07002694 stat = stat & BATTERY_CHARGER_STATUS_MASK;
Nicholas Troast8cb77552016-09-23 11:50:18 -07002695 power_supply_changed(chg->batt_psy);
Harry Yang6fe72ab2016-06-14 16:21:39 -07002696 return IRQ_HANDLED;
2697}
2698
Harry Yangfe913842016-08-10 12:27:28 -07002699irqreturn_t smblib_handle_step_chg_state_change(int irq, void *data)
2700{
2701 struct smb_irq_data *irq_data = data;
2702 struct smb_charger *chg = irq_data->parent_data;
2703
2704 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
2705
2706 if (chg->step_chg_enabled)
2707 rerun_election(chg->fcc_votable);
2708
2709 return IRQ_HANDLED;
2710}
2711
2712irqreturn_t smblib_handle_step_chg_soc_update_fail(int irq, void *data)
2713{
2714 struct smb_irq_data *irq_data = data;
2715 struct smb_charger *chg = irq_data->parent_data;
2716
2717 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
2718
2719 if (chg->step_chg_enabled)
2720 rerun_election(chg->fcc_votable);
2721
2722 return IRQ_HANDLED;
2723}
2724
2725#define STEP_SOC_REQ_MS 3000
2726irqreturn_t smblib_handle_step_chg_soc_update_request(int irq, void *data)
2727{
2728 struct smb_irq_data *irq_data = data;
2729 struct smb_charger *chg = irq_data->parent_data;
2730 int rc;
2731 union power_supply_propval pval = {0, };
2732
2733 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
2734
2735 if (!chg->bms_psy) {
2736 schedule_delayed_work(&chg->step_soc_req_work,
2737 msecs_to_jiffies(STEP_SOC_REQ_MS));
2738 return IRQ_HANDLED;
2739 }
2740
2741 rc = smblib_get_prop_batt_capacity(chg, &pval);
2742 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002743 smblib_err(chg, "Couldn't get batt capacity rc=%d\n", rc);
Harry Yangfe913842016-08-10 12:27:28 -07002744 else
2745 step_charge_soc_update(chg, pval.intval);
2746
2747 return IRQ_HANDLED;
2748}
2749
Abhijeet Dharmapurikar2644cd62016-07-20 16:54:55 -07002750irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data)
2751{
2752 struct smb_irq_data *irq_data = data;
2753 struct smb_charger *chg = irq_data->parent_data;
2754
2755 rerun_election(chg->fcc_votable);
2756 power_supply_changed(chg->batt_psy);
2757 return IRQ_HANDLED;
2758}
2759
Nicholas Troast34db5032016-03-28 12:26:44 -07002760irqreturn_t smblib_handle_batt_psy_changed(int irq, void *data)
2761{
2762 struct smb_irq_data *irq_data = data;
2763 struct smb_charger *chg = irq_data->parent_data;
2764
Nicholas Troast47ae4612016-08-03 09:49:36 -07002765 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07002766 power_supply_changed(chg->batt_psy);
2767 return IRQ_HANDLED;
2768}
2769
2770irqreturn_t smblib_handle_usb_psy_changed(int irq, void *data)
2771{
2772 struct smb_irq_data *irq_data = data;
2773 struct smb_charger *chg = irq_data->parent_data;
2774
Nicholas Troast47ae4612016-08-03 09:49:36 -07002775 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07002776 power_supply_changed(chg->usb_psy);
2777 return IRQ_HANDLED;
2778}
2779
2780irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
2781{
2782 struct smb_irq_data *irq_data = data;
2783 struct smb_charger *chg = irq_data->parent_data;
2784 int rc;
2785 u8 stat;
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08002786 bool vbus_rising;
Nicholas Troast34db5032016-03-28 12:26:44 -07002787
Harry Yangcdad2bf2016-10-04 17:03:56 -07002788 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
2789 if (rc < 0) {
2790 dev_err(chg->dev, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
2791 return IRQ_HANDLED;
2792 }
2793
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08002794 vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
Harry Yangcdad2bf2016-10-04 17:03:56 -07002795 smblib_set_opt_freq_buck(chg,
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05302796 vbus_rising ? chg->chg_freq.freq_5V :
2797 chg->chg_freq.freq_removal);
Harry Yangcdad2bf2016-10-04 17:03:56 -07002798
Nicholas Troast34db5032016-03-28 12:26:44 -07002799 /* fetch the DPDM regulator */
2800 if (!chg->dpdm_reg && of_get_property(chg->dev->of_node,
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05302801 "dpdm-supply", NULL)) {
Nicholas Troast34db5032016-03-28 12:26:44 -07002802 chg->dpdm_reg = devm_regulator_get(chg->dev, "dpdm");
2803 if (IS_ERR(chg->dpdm_reg)) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002804 smblib_err(chg, "Couldn't get dpdm regulator rc=%ld\n",
Nicholas Troast34db5032016-03-28 12:26:44 -07002805 PTR_ERR(chg->dpdm_reg));
2806 chg->dpdm_reg = NULL;
2807 }
2808 }
2809
Nicholas Troast7ec38eb2016-11-14 10:28:39 -08002810 if (vbus_rising) {
Nicholas Troastabedaf72016-09-16 11:07:45 -07002811 if (chg->dpdm_reg && !regulator_is_enabled(chg->dpdm_reg)) {
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07002812 smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n");
2813 rc = regulator_enable(chg->dpdm_reg);
2814 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002815 smblib_err(chg, "Couldn't enable dpdm regulator rc=%d\n",
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07002816 rc);
2817 }
2818 } else {
Abhijeet Dharmapurikar2823fe32016-12-05 17:52:11 -08002819 if (chg->wa_flags & BOOST_BACK_WA)
Nicholas Troastabedaf72016-09-16 11:07:45 -07002820 vote(chg->usb_suspend_votable,
2821 BOOST_BACK_VOTER, false, 0);
Nicholas Troastabedaf72016-09-16 11:07:45 -07002822
2823 if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) {
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07002824 smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n");
2825 rc = regulator_disable(chg->dpdm_reg);
2826 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002827 smblib_err(chg, "Couldn't disable dpdm regulator rc=%d\n",
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07002828 rc);
2829 }
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05302830
2831 if (chg->micro_usb_mode) {
2832 smblib_update_usb_type(chg);
2833 extcon_set_cable_state_(chg->extcon, EXTCON_USB, false);
2834 smblib_uusb_removal(chg);
2835 }
Nicholas Troast34db5032016-03-28 12:26:44 -07002836 }
2837
Nicholas Troast62d86622016-09-22 11:41:33 -07002838 power_supply_changed(chg->usb_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07002839 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n",
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05302840 irq_data->name, vbus_rising ? "attached" : "detached");
Nicholas Troast34db5032016-03-28 12:26:44 -07002841 return IRQ_HANDLED;
2842}
2843
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -07002844#define USB_WEAK_INPUT_UA 1400000
Harry Yang6fe72ab2016-06-14 16:21:39 -07002845irqreturn_t smblib_handle_icl_change(int irq, void *data)
2846{
2847 struct smb_irq_data *irq_data = data;
2848 struct smb_charger *chg = irq_data->parent_data;
Abhijeet Dharmapurikara8bd6f02017-01-30 15:43:04 -08002849 int rc, settled_ua;
Harry Yangaba1f5f2016-09-28 10:47:29 -07002850
Nicholas Troast87d69ba2016-10-10 19:29:47 -07002851 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Abhijeet Dharmapurikarc0b0f592016-10-14 10:55:42 -07002852
Abhijeet Dharmapurikara8bd6f02017-01-30 15:43:04 -08002853 rc = smblib_get_charge_param(chg, &chg->param.icl_stat, &settled_ua);
Harry Yangaba1f5f2016-09-28 10:47:29 -07002854 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07002855 smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
Harry Yangaba1f5f2016-09-28 10:47:29 -07002856 return IRQ_HANDLED;
2857 }
Harry Yang6fe72ab2016-06-14 16:21:39 -07002858
Nicholas Troast87d69ba2016-10-10 19:29:47 -07002859 if (chg->mode != PARALLEL_MASTER)
2860 return IRQ_HANDLED;
Harry Yang1d1034c2016-06-15 12:09:42 -07002861
Abhijeet Dharmapurikara8bd6f02017-01-30 15:43:04 -08002862 power_supply_changed(chg->usb_main_psy);
Nicholas Troast87d69ba2016-10-10 19:29:47 -07002863
2864 vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER,
Abhijeet Dharmapurikara8bd6f02017-01-30 15:43:04 -08002865 settled_ua >= USB_WEAK_INPUT_UA, 0);
Harry Yang6fe72ab2016-06-14 16:21:39 -07002866
2867 return IRQ_HANDLED;
2868}
2869
Nicholas Troast34db5032016-03-28 12:26:44 -07002870static void smblib_handle_slow_plugin_timeout(struct smb_charger *chg,
2871 bool rising)
2872{
2873 smblib_dbg(chg, PR_INTERRUPT, "IRQ: slow-plugin-timeout %s\n",
2874 rising ? "rising" : "falling");
2875}
2876
2877static void smblib_handle_sdp_enumeration_done(struct smb_charger *chg,
2878 bool rising)
2879{
2880 smblib_dbg(chg, PR_INTERRUPT, "IRQ: sdp-enumeration-done %s\n",
2881 rising ? "rising" : "falling");
2882}
2883
Harry Yangcdad2bf2016-10-04 17:03:56 -07002884#define QC3_PULSES_FOR_6V 5
2885#define QC3_PULSES_FOR_9V 20
2886#define QC3_PULSES_FOR_12V 35
2887static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg)
2888{
2889 int rc;
2890 u8 stat;
2891 int pulses;
2892
2893 if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB_HVDCP) {
2894 rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat);
2895 if (rc < 0) {
2896 smblib_err(chg,
2897 "Couldn't read QC_CHANGE_STATUS rc=%d\n", rc);
2898 return;
2899 }
2900
2901 switch (stat & QC_2P0_STATUS_MASK) {
2902 case QC_5V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05302903 smblib_set_opt_freq_buck(chg,
2904 chg->chg_freq.freq_5V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07002905 break;
2906 case QC_9V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05302907 smblib_set_opt_freq_buck(chg,
2908 chg->chg_freq.freq_9V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07002909 break;
2910 case QC_12V_BIT:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05302911 smblib_set_opt_freq_buck(chg,
2912 chg->chg_freq.freq_12V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07002913 break;
2914 default:
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05302915 smblib_set_opt_freq_buck(chg,
2916 chg->chg_freq.freq_removal);
Harry Yangcdad2bf2016-10-04 17:03:56 -07002917 break;
2918 }
2919 }
2920
2921 if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB_HVDCP_3) {
2922 rc = smblib_read(chg, QC_PULSE_COUNT_STATUS_REG, &stat);
2923 if (rc < 0) {
2924 smblib_err(chg,
2925 "Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
2926 return;
2927 }
2928 pulses = (stat & QC_PULSE_COUNT_MASK);
2929
2930 if (pulses < QC3_PULSES_FOR_6V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05302931 smblib_set_opt_freq_buck(chg,
2932 chg->chg_freq.freq_5V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07002933 else if (pulses < QC3_PULSES_FOR_9V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05302934 smblib_set_opt_freq_buck(chg,
2935 chg->chg_freq.freq_6V_8V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07002936 else if (pulses < QC3_PULSES_FOR_12V)
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05302937 smblib_set_opt_freq_buck(chg,
2938 chg->chg_freq.freq_9V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07002939 else
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05302940 smblib_set_opt_freq_buck(chg,
2941 chg->chg_freq.freq_12V);
Harry Yangcdad2bf2016-10-04 17:03:56 -07002942 }
2943}
2944
Nicholas Troast34db5032016-03-28 12:26:44 -07002945static void smblib_handle_adaptive_voltage_done(struct smb_charger *chg,
2946 bool rising)
2947{
2948 smblib_dbg(chg, PR_INTERRUPT, "IRQ: adaptive-voltage-done %s\n",
2949 rising ? "rising" : "falling");
2950}
2951
2952/* triggers when HVDCP 3.0 authentication has finished */
2953static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
2954 bool rising)
2955{
2956 const struct apsd_result *apsd_result;
Harry Yangcdad2bf2016-10-04 17:03:56 -07002957 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07002958
2959 if (!rising)
2960 return;
2961
Harry Yangcdad2bf2016-10-04 17:03:56 -07002962 /*
2963 * Disable AUTH_IRQ_EN_CFG_BIT to receive adapter voltage
2964 * change interrupt.
2965 */
2966 rc = smblib_masked_write(chg, USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
2967 AUTH_IRQ_EN_CFG_BIT, 0);
2968 if (rc < 0)
2969 smblib_err(chg, "Couldn't enable QC auth setting rc=%d\n", rc);
2970
Harry Yangaba1f5f2016-09-28 10:47:29 -07002971 if (chg->mode == PARALLEL_MASTER)
2972 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0);
2973
Ashay Jaiswal1829fcf2017-02-02 22:45:22 +05302974 /* QC authentication done, parallel charger can be enabled now */
2975 vote(chg->pl_disable_votable, PL_DISABLE_HVDCP_VOTER, false, 0);
2976
Nicholas Troast34db5032016-03-28 12:26:44 -07002977 /* the APSD done handler will set the USB supply type */
2978 apsd_result = smblib_get_apsd_result(chg);
2979 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n",
2980 apsd_result->name);
2981}
2982
Harry Yang1369b7a2016-09-27 15:59:50 -07002983static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
2984 bool rising, bool qc_charger)
2985{
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05302986 const struct apsd_result *apsd_result = smblib_update_usb_type(chg);
2987
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07002988 /* Hold off PD only until hvdcp 2.0 detection timeout */
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07002989 if (rising) {
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07002990 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07002991 false, 0);
2992 if (get_effective_result(chg->pd_disallowed_votable_indirect))
2993 /* could be a legacy cable, try doing hvdcp */
2994 try_rerun_apsd_for_hvdcp(chg);
Abhijeet Dharmapurikar74021fc2017-02-06 18:39:19 -08002995
2996 /*
2997 * HVDCP detection timeout done
2998 * If adapter is not QC2.0/QC3.0 - it is a plain old DCP.
2999 */
3000 if (!qc_charger && (apsd_result->bit & DCP_CHARGER_BIT))
3001 /* enforce DCP ICL if specified */
3002 vote(chg->usb_icl_votable, DCP_VOTER,
3003 chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua);
Ashay Jaiswal1829fcf2017-02-02 22:45:22 +05303004 /*
3005 * If adapter is not QC2.0/QC3.0 remove vote for parallel
3006 * disable.
3007 * Otherwise if adapter is QC2.0/QC3.0 wait for authentication
3008 * to complete.
3009 */
3010 if (!qc_charger)
3011 vote(chg->pl_disable_votable, PL_DISABLE_HVDCP_VOTER,
3012 false, 0);
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003013 }
Harry Yang1369b7a2016-09-27 15:59:50 -07003014
3015 smblib_dbg(chg, PR_INTERRUPT, "IRQ: smblib_handle_hvdcp_check_timeout %s\n",
3016 rising ? "rising" : "falling");
3017}
3018
Nicholas Troast34db5032016-03-28 12:26:44 -07003019/* triggers when HVDCP is detected */
3020static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg,
3021 bool rising)
3022{
3023 if (!rising)
3024 return;
3025
3026 /* the APSD done handler will set the USB supply type */
3027 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
3028 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-detect-done %s\n",
3029 rising ? "rising" : "falling");
3030}
3031
3032#define HVDCP_DET_MS 2500
3033static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
3034{
Nicholas Troast34db5032016-03-28 12:26:44 -07003035 const struct apsd_result *apsd_result;
3036
3037 if (!rising)
3038 return;
3039
Abhijeet Dharmapurikarb9598872016-10-17 16:58:58 -07003040 apsd_result = smblib_update_usb_type(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07003041 switch (apsd_result->bit) {
3042 case SDP_CHARGER_BIT:
3043 case CDP_CHARGER_BIT:
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05303044 if (chg->micro_usb_mode)
3045 extcon_set_cable_state_(chg->extcon, EXTCON_USB,
3046 true);
Abhijeet Dharmapurikarbb9505f2017-03-22 18:31:28 -07003047 /* if not DCP then no hvdcp timeout happens. Enable pd here */
3048 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3049 false, 0);
3050 break;
Nicholas Troast34db5032016-03-28 12:26:44 -07003051 case OCP_CHARGER_BIT:
3052 case FLOAT_CHARGER_BIT:
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003053 /* if not DCP then no hvdcp timeout happens. Enable pd here */
3054 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3055 false, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07003056 break;
3057 case DCP_CHARGER_BIT:
Harry Yang1369b7a2016-09-27 15:59:50 -07003058 if (chg->wa_flags & QC_CHARGER_DETECTION_WA_BIT)
3059 schedule_delayed_work(&chg->hvdcp_detect_work,
3060 msecs_to_jiffies(HVDCP_DET_MS));
Nicholas Troast34db5032016-03-28 12:26:44 -07003061 break;
3062 default:
3063 break;
3064 }
3065
Nicholas Troast34db5032016-03-28 12:26:44 -07003066 smblib_dbg(chg, PR_INTERRUPT, "IRQ: apsd-done rising; %s detected\n",
3067 apsd_result->name);
3068}
3069
3070irqreturn_t smblib_handle_usb_source_change(int irq, void *data)
3071{
3072 struct smb_irq_data *irq_data = data;
3073 struct smb_charger *chg = irq_data->parent_data;
3074 int rc = 0;
3075 u8 stat;
3076
3077 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
3078 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003079 smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07003080 return IRQ_HANDLED;
3081 }
3082 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
3083
3084 smblib_handle_apsd_done(chg,
3085 (bool)(stat & APSD_DTC_STATUS_DONE_BIT));
3086
3087 smblib_handle_hvdcp_detect_done(chg,
3088 (bool)(stat & QC_CHARGER_BIT));
3089
Harry Yang1369b7a2016-09-27 15:59:50 -07003090 smblib_handle_hvdcp_check_timeout(chg,
3091 (bool)(stat & HVDCP_CHECK_TIMEOUT_BIT),
3092 (bool)(stat & QC_CHARGER_BIT));
3093
Nicholas Troast34db5032016-03-28 12:26:44 -07003094 smblib_handle_hvdcp_3p0_auth_done(chg,
3095 (bool)(stat & QC_AUTH_DONE_STATUS_BIT));
3096
3097 smblib_handle_adaptive_voltage_done(chg,
3098 (bool)(stat & VADP_CHANGE_DONE_AFTER_AUTH_BIT));
3099
3100 smblib_handle_sdp_enumeration_done(chg,
3101 (bool)(stat & ENUMERATION_DONE_BIT));
3102
3103 smblib_handle_slow_plugin_timeout(chg,
3104 (bool)(stat & SLOW_PLUGIN_TIMEOUT_BIT));
3105
Harry Yangcdad2bf2016-10-04 17:03:56 -07003106 smblib_hvdcp_adaptive_voltage_change(chg);
3107
Nicholas Troast34db5032016-03-28 12:26:44 -07003108 power_supply_changed(chg->usb_psy);
3109
3110 return IRQ_HANDLED;
3111}
3112
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003113static void typec_source_removal(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07003114{
3115 int rc;
3116
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003117 /* reset both usbin current and voltage votes */
3118 vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
3119 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07003120
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003121 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
3122
Harry Yangcdad2bf2016-10-04 17:03:56 -07003123 /* reset AUTH_IRQ_EN_CFG_BIT */
3124 rc = smblib_masked_write(chg, USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
3125 AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
3126 if (rc < 0)
3127 smblib_err(chg, "Couldn't enable QC auth setting rc=%d\n", rc);
3128
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003129 /* reconfigure allowed voltage for HVDCP */
3130 rc = smblib_write(chg, USBIN_ADAPTER_ALLOW_CFG_REG,
3131 USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
3132 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003133 smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003134 rc);
3135
3136 chg->voltage_min_uv = MICRO_5V;
3137 chg->voltage_max_uv = MICRO_5V;
3138
3139 /* clear USB ICL vote for PD_VOTER */
3140 rc = vote(chg->usb_icl_votable, PD_VOTER, false, 0);
3141 if (rc < 0)
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05303142 smblib_err(chg, "Couldn't un-vote PD from USB ICL rc=%d\n", rc);
Abhijeet Dharmapurikard92eca62016-10-07 19:04:33 -07003143
3144 /* clear USB ICL vote for USB_PSY_VOTER */
3145 rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
3146 if (rc < 0)
Abhijeet Dharmapurikar95670872017-02-09 22:55:51 +05303147 smblib_err(chg,
3148 "Couldn't un-vote USB_PSY from USB ICL rc=%d\n", rc);
3149
3150 /* clear USB ICL vote for DCP_VOTER */
3151 rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
3152 if (rc < 0)
3153 smblib_err(chg,
3154 "Couldn't un-vote DCP from USB ICL rc=%d\n", rc);
Abhijeet Dharmapurikar7442e422017-02-08 13:35:14 -08003155
3156 /* clear USB ICL vote for PL_USBIN_USBIN_VOTER */
3157 rc = vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
3158 if (rc < 0)
3159 smblib_err(chg,
3160 "Couldn't un-vote PL_USBIN_USBIN from USB ICL rc=%d\n",
3161 rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07003162}
3163
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003164static void typec_source_insertion(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07003165{
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003166}
Nicholas Troast34db5032016-03-28 12:26:44 -07003167
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003168static void typec_sink_insertion(struct smb_charger *chg)
3169{
3170 /* when a sink is inserted we should not wait on hvdcp timeout to
3171 * enable pd
3172 */
3173 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3174 false, 0);
3175}
Nicholas Troast34db5032016-03-28 12:26:44 -07003176
Harry Yangd89ff1f2016-12-05 14:59:11 -08003177static void typec_sink_removal(struct smb_charger *chg)
3178{
Anirudh Ghayal4da3df92017-01-25 18:55:57 +05303179 smblib_set_charge_param(chg, &chg->param.freq_boost,
3180 chg->chg_freq.freq_above_otg_threshold);
Harry Yangd89ff1f2016-12-05 14:59:11 -08003181 chg->boost_current_ua = 0;
3182}
3183
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003184static void smblib_handle_typec_removal(struct smb_charger *chg)
3185{
3186 vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0);
3187 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER, true, 0);
3188 vote(chg->pd_disallowed_votable_indirect, LEGACY_CABLE_VOTER, true, 0);
3189 vote(chg->pd_disallowed_votable_indirect, VBUS_CC_SHORT_VOTER, true, 0);
Ashay Jaiswal1829fcf2017-02-02 22:45:22 +05303190 vote(chg->pl_disable_votable, PL_DISABLE_HVDCP_VOTER, true, 0);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003191
3192 /* reset votes from vbus_cc_short */
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05303193 vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
3194 true, 0);
3195 vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER,
3196 true, 0);
Harry Yang1d1034c2016-06-15 12:09:42 -07003197 /*
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003198 * cable could be removed during hard reset, remove its vote to
3199 * disable apsd
Harry Yang1d1034c2016-06-15 12:09:42 -07003200 */
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003201 vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, false, 0);
Harry Yang1d1034c2016-06-15 12:09:42 -07003202
Nicholas Troast8995a702016-12-05 10:22:22 -08003203 chg->vconn_attempts = 0;
3204 chg->otg_attempts = 0;
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003205 typec_source_removal(chg);
Harry Yangd89ff1f2016-12-05 14:59:11 -08003206 typec_sink_removal(chg);
Abhijeet Dharmapurikare4e404b2016-10-12 21:46:29 -07003207
Harry Yang3b113a52016-12-08 12:37:40 -08003208 chg->usb_ever_removed = true;
3209
Abhijeet Dharmapurikare4e404b2016-10-12 21:46:29 -07003210 smblib_update_usb_type(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07003211}
3212
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003213static void smblib_handle_typec_insertion(struct smb_charger *chg,
3214 bool sink_attached, bool legacy_cable)
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003215{
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003216 int rp;
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003217 bool vbus_cc_short = false;
Harry Yang3b113a52016-12-08 12:37:40 -08003218 bool valid_legacy_cable;
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003219
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003220 vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, false, 0);
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003221
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003222 if (sink_attached) {
3223 typec_source_removal(chg);
3224 typec_sink_insertion(chg);
3225 } else {
3226 typec_source_insertion(chg);
Harry Yangd89ff1f2016-12-05 14:59:11 -08003227 typec_sink_removal(chg);
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003228 }
3229
Harry Yang3b113a52016-12-08 12:37:40 -08003230 valid_legacy_cable = legacy_cable &&
3231 (chg->usb_ever_removed || !smblib_sysok_reason_usbin(chg));
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003232 vote(chg->pd_disallowed_votable_indirect, LEGACY_CABLE_VOTER,
Harry Yang3b113a52016-12-08 12:37:40 -08003233 valid_legacy_cable, 0);
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003234
Harry Yang3b113a52016-12-08 12:37:40 -08003235 if (valid_legacy_cable) {
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003236 rp = smblib_get_prop_ufp_mode(chg);
3237 if (rp == POWER_SUPPLY_TYPEC_SOURCE_HIGH
3238 || rp == POWER_SUPPLY_TYPEC_NON_COMPLIANT) {
3239 vbus_cc_short = true;
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003240 smblib_err(chg, "Disabling PD and HVDCP, VBUS-CC shorted, rp = %d found\n",
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003241 rp);
3242 }
3243 }
3244
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05303245 vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
3246 vbus_cc_short, 0);
Abhijeet Dharmapurikara8075d72016-10-06 12:59:04 -07003247 vote(chg->pd_disallowed_votable_indirect, VBUS_CC_SHORT_VOTER,
3248 vbus_cc_short, 0);
3249}
3250
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003251static void smblib_handle_typec_debounce_done(struct smb_charger *chg,
3252 bool rising, bool sink_attached, bool legacy_cable)
3253{
3254 int rc;
3255 union power_supply_propval pval = {0, };
3256
3257 if (rising)
3258 smblib_handle_typec_insertion(chg, sink_attached, legacy_cable);
3259 else
3260 smblib_handle_typec_removal(chg);
3261
3262 rc = smblib_get_prop_typec_mode(chg, &pval);
3263 if (rc < 0)
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003264 smblib_err(chg, "Couldn't get prop typec mode rc=%d\n", rc);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003265
Harry Yang86e4d852016-11-07 15:08:47 -08003266 /*
3267 * HW BUG - after cable is removed, medium or high rd reading
3268 * falls to std. Use it for signal of typec cc detachment in
3269 * software WA.
3270 */
3271 if (chg->cc2_sink_detach_flag == CC2_SINK_MEDIUM_HIGH
3272 && pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
3273
3274 chg->cc2_sink_detach_flag = CC2_SINK_WA_DONE;
3275
3276 rc = smblib_masked_write(chg,
3277 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
3278 EXIT_SNK_BASED_ON_CC_BIT, 0);
3279 if (rc < 0)
3280 smblib_err(chg, "Couldn't get prop typec mode rc=%d\n",
3281 rc);
3282 }
3283
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003284 smblib_dbg(chg, PR_INTERRUPT, "IRQ: debounce-done %s; Type-C %s detected\n",
3285 rising ? "rising" : "falling",
3286 smblib_typec_mode_name[pval.intval]);
3287}
3288
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05303289irqreturn_t smblib_handle_usb_typec_change_for_uusb(struct smb_charger *chg)
3290{
3291 int rc;
3292 u8 stat;
3293
3294 rc = smblib_read(chg, TYPE_C_STATUS_3_REG, &stat);
3295 if (rc < 0) {
3296 smblib_err(chg, "Couldn't read TYPE_C_STATUS_3 rc=%d\n", rc);
3297 return IRQ_HANDLED;
3298 }
3299 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_3 = 0x%02x OTG=%d\n",
3300 stat, !!(stat & (U_USB_GND_NOVBUS_BIT | U_USB_GND_BIT)));
3301
3302 extcon_set_cable_state_(chg->extcon, EXTCON_USB_HOST,
3303 !!(stat & (U_USB_GND_NOVBUS_BIT | U_USB_GND_BIT)));
3304 power_supply_changed(chg->usb_psy);
3305
3306 return IRQ_HANDLED;
3307}
3308
Nicholas Troast34db5032016-03-28 12:26:44 -07003309irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
3310{
3311 struct smb_irq_data *irq_data = data;
3312 struct smb_charger *chg = irq_data->parent_data;
3313 int rc;
Nicholas Troastb1486552016-11-10 08:20:11 -08003314 u8 stat4, stat5;
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003315 bool debounce_done, sink_attached, legacy_cable;
Nicholas Troast34db5032016-03-28 12:26:44 -07003316
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05303317 if (chg->micro_usb_mode)
3318 return smblib_handle_usb_typec_change_for_uusb(chg);
3319
Harry Yang755a34b2016-11-01 01:18:51 -07003320 /* WA - not when PD hard_reset WIP on cc2 in sink mode */
3321 if (chg->cc2_sink_detach_flag == CC2_SINK_STD)
3322 return IRQ_HANDLED;
3323
Nicholas Troastb1486552016-11-10 08:20:11 -08003324 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
Nicholas Troast34db5032016-03-28 12:26:44 -07003325 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003326 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -07003327 return IRQ_HANDLED;
3328 }
Nicholas Troast34db5032016-03-28 12:26:44 -07003329
Nicholas Troastb1486552016-11-10 08:20:11 -08003330 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003331 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003332 smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003333 return IRQ_HANDLED;
3334 }
Nicholas Troastb1486552016-11-10 08:20:11 -08003335
3336 debounce_done = (bool)(stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
3337 sink_attached = (bool)(stat4 & UFP_DFP_MODE_STATUS_BIT);
3338 legacy_cable = (bool)(stat5 & TYPEC_LEGACY_CABLE_STATUS_BIT);
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003339
Nicholas Troast34db5032016-03-28 12:26:44 -07003340 smblib_handle_typec_debounce_done(chg,
Abhijeet Dharmapurikar99ca0452016-10-13 09:50:41 -07003341 debounce_done, sink_attached, legacy_cable);
Nicholas Troast34db5032016-03-28 12:26:44 -07003342
Nicholas Troastb1486552016-11-10 08:20:11 -08003343 if (stat4 & TYPEC_VBUS_ERROR_STATUS_BIT)
Harry Yangd757c0f2016-09-23 10:52:05 -07003344 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s vbus-error\n",
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05303345 irq_data->name);
Harry Yangd757c0f2016-09-23 10:52:05 -07003346
Nicholas Troast8995a702016-12-05 10:22:22 -08003347 if (stat4 & TYPEC_VCONN_OVERCURR_STATUS_BIT)
Nicholas Troastb11015f2017-01-17 17:56:45 -08003348 schedule_work(&chg->vconn_oc_work);
Nicholas Troast8995a702016-12-05 10:22:22 -08003349
Nicholas Troastb1486552016-11-10 08:20:11 -08003350 power_supply_changed(chg->usb_psy);
3351 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat4);
3352 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_5 = 0x%02x\n", stat5);
Nicholas Troast34db5032016-03-28 12:26:44 -07003353 return IRQ_HANDLED;
3354}
3355
Abhijeet Dharmapurikar23916642016-10-03 10:38:50 -07003356irqreturn_t smblib_handle_dc_plugin(int irq, void *data)
3357{
3358 struct smb_irq_data *irq_data = data;
3359 struct smb_charger *chg = irq_data->parent_data;
3360
3361 power_supply_changed(chg->dc_psy);
3362 return IRQ_HANDLED;
3363}
3364
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07003365irqreturn_t smblib_handle_high_duty_cycle(int irq, void *data)
3366{
3367 struct smb_irq_data *irq_data = data;
3368 struct smb_charger *chg = irq_data->parent_data;
3369
3370 chg->is_hdc = true;
3371 schedule_delayed_work(&chg->clear_hdc_work, msecs_to_jiffies(60));
3372
3373 return IRQ_HANDLED;
3374}
3375
Nicholas Troastabedaf72016-09-16 11:07:45 -07003376irqreturn_t smblib_handle_switcher_power_ok(int irq, void *data)
3377{
3378 struct smb_irq_data *irq_data = data;
3379 struct smb_charger *chg = irq_data->parent_data;
3380 int rc;
3381 u8 stat;
3382
3383 if (!(chg->wa_flags & BOOST_BACK_WA))
3384 return IRQ_HANDLED;
3385
3386 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
3387 if (rc < 0) {
3388 smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n", rc);
3389 return IRQ_HANDLED;
3390 }
3391
3392 if ((stat & USE_USBIN_BIT) &&
3393 get_effective_result(chg->usb_suspend_votable))
3394 return IRQ_HANDLED;
3395
Abhijeet Dharmapurikar2823fe32016-12-05 17:52:11 -08003396 if (stat & USE_DCIN_BIT)
Nicholas Troastabedaf72016-09-16 11:07:45 -07003397 return IRQ_HANDLED;
3398
3399 if (is_storming(&irq_data->storm_data)) {
Abhijeet Dharmapurikar2823fe32016-12-05 17:52:11 -08003400 smblib_err(chg, "Reverse boost detected: suspending input\n");
Nicholas Troastabedaf72016-09-16 11:07:45 -07003401 vote(chg->usb_suspend_votable, BOOST_BACK_VOTER, true, 0);
Nicholas Troastabedaf72016-09-16 11:07:45 -07003402 }
3403
3404 return IRQ_HANDLED;
3405}
3406
Nicholas Troast15dc0c82016-10-18 15:15:21 -07003407irqreturn_t smblib_handle_wdog_bark(int irq, void *data)
3408{
3409 struct smb_irq_data *irq_data = data;
3410 struct smb_charger *chg = irq_data->parent_data;
3411 int rc;
3412
3413 rc = smblib_write(chg, BARK_BITE_WDOG_PET_REG, BARK_BITE_WDOG_PET_BIT);
3414 if (rc < 0)
3415 smblib_err(chg, "Couldn't pet the dog rc=%d\n", rc);
3416
3417 return IRQ_HANDLED;
3418}
3419
Nicholas Troast34db5032016-03-28 12:26:44 -07003420/***************
3421 * Work Queues *
3422 ***************/
3423
3424static void smblib_hvdcp_detect_work(struct work_struct *work)
3425{
3426 struct smb_charger *chg = container_of(work, struct smb_charger,
3427 hvdcp_detect_work.work);
Nicholas Troast34db5032016-03-28 12:26:44 -07003428
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003429 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
3430 false, 0);
Abhijeet Dharmapurikar716cd962016-10-14 12:50:37 -07003431 if (get_effective_result(chg->pd_disallowed_votable_indirect))
3432 /* pd is still disabled, try hvdcp */
3433 try_rerun_apsd_for_hvdcp(chg);
3434 else
3435 /* notify pd now that pd is allowed */
3436 power_supply_changed(chg->usb_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07003437}
3438
Harry Yangfe913842016-08-10 12:27:28 -07003439static void bms_update_work(struct work_struct *work)
Harry Yang5e1a5222016-07-26 15:16:04 -07003440{
3441 struct smb_charger *chg = container_of(work, struct smb_charger,
3442 bms_update_work);
Ashay Jaiswal2fb369d2017-01-12 21:38:29 +05303443
3444 smblib_suspend_on_debug_battery(chg);
3445
3446 if (chg->batt_psy)
3447 power_supply_changed(chg->batt_psy);
Harry Yang5e1a5222016-07-26 15:16:04 -07003448}
3449
Harry Yangfe913842016-08-10 12:27:28 -07003450static void step_soc_req_work(struct work_struct *work)
3451{
3452 struct smb_charger *chg = container_of(work, struct smb_charger,
3453 step_soc_req_work.work);
3454 union power_supply_propval pval = {0, };
3455 int rc;
3456
3457 rc = smblib_get_prop_batt_capacity(chg, &pval);
3458 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003459 smblib_err(chg, "Couldn't get batt capacity rc=%d\n", rc);
Harry Yangfe913842016-08-10 12:27:28 -07003460 return;
3461 }
3462
3463 step_charge_soc_update(chg, pval.intval);
3464}
3465
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07003466static void clear_hdc_work(struct work_struct *work)
3467{
3468 struct smb_charger *chg = container_of(work, struct smb_charger,
3469 clear_hdc_work.work);
3470
3471 chg->is_hdc = 0;
3472}
3473
Harry Yang755a34b2016-11-01 01:18:51 -07003474static void rdstd_cc2_detach_work(struct work_struct *work)
3475{
3476 int rc;
3477 u8 stat;
3478 struct smb_irq_data irq_data = {NULL, "cc2-removal-workaround"};
3479 struct smb_charger *chg = container_of(work, struct smb_charger,
3480 rdstd_cc2_detach_work);
3481
3482 /*
3483 * WA steps -
3484 * 1. Enable both UFP and DFP, wait for 10ms.
3485 * 2. Disable DFP, wait for 30ms.
3486 * 3. Removal detected if both TYPEC_DEBOUNCE_DONE_STATUS
3487 * and TIMER_STAGE bits are gone, otherwise repeat all by
3488 * work rescheduling.
3489 * Note, work will be cancelled when pd_hard_reset is 0.
3490 */
3491
3492 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
3493 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT,
3494 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT);
3495 if (rc < 0) {
3496 smblib_err(chg, "Couldn't write TYPE_C_CTRL_REG rc=%d\n", rc);
3497 return;
3498 }
3499
3500 usleep_range(10000, 11000);
3501
3502 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
3503 UFP_EN_CMD_BIT | DFP_EN_CMD_BIT,
3504 UFP_EN_CMD_BIT);
3505 if (rc < 0) {
3506 smblib_err(chg, "Couldn't write TYPE_C_CTRL_REG rc=%d\n", rc);
3507 return;
3508 }
3509
3510 usleep_range(30000, 31000);
3511
3512 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
3513 if (rc < 0) {
3514 smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
3515 rc);
3516 return;
3517 }
3518 if (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT)
3519 goto rerun;
3520
3521 rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat);
3522 if (rc < 0) {
3523 smblib_err(chg,
3524 "Couldn't read TYPE_C_STATUS_5_REG rc=%d\n", rc);
3525 return;
3526 }
3527 if (stat & TIMER_STAGE_2_BIT)
3528 goto rerun;
3529
3530 /* Bingo, cc2 removal detected */
3531 smblib_reg_block_restore(chg, cc2_detach_settings);
3532 chg->cc2_sink_detach_flag = CC2_SINK_WA_DONE;
3533 irq_data.parent_data = chg;
3534 smblib_handle_usb_typec_change(0, &irq_data);
3535
3536 return;
3537
3538rerun:
3539 schedule_work(&chg->rdstd_cc2_detach_work);
3540}
3541
Nicholas Troastb11015f2017-01-17 17:56:45 -08003542static void smblib_otg_oc_exit(struct smb_charger *chg, bool success)
3543{
3544 int rc;
3545
3546 chg->otg_attempts = 0;
3547 if (!success) {
3548 smblib_err(chg, "OTG soft start failed\n");
3549 chg->otg_en = false;
3550 }
3551
3552 smblib_dbg(chg, PR_OTG, "enabling VBUS < 1V check\n");
3553 rc = smblib_masked_write(chg, OTG_CFG_REG,
3554 QUICKSTART_OTG_FASTROLESWAP_BIT, 0);
3555 if (rc < 0)
3556 smblib_err(chg, "Couldn't enable VBUS < 1V check rc=%d\n", rc);
3557
3558 if (!chg->external_vconn && chg->vconn_en) {
3559 chg->vconn_attempts = 0;
3560 if (success) {
3561 rc = _smblib_vconn_regulator_enable(
3562 chg->vconn_vreg->rdev);
3563 if (rc < 0)
3564 smblib_err(chg, "Couldn't enable VCONN rc=%d\n",
3565 rc);
3566 } else {
3567 chg->vconn_en = false;
3568 }
3569 }
3570}
3571
3572#define MAX_OC_FALLING_TRIES 10
3573static void smblib_otg_oc_work(struct work_struct *work)
3574{
3575 struct smb_charger *chg = container_of(work, struct smb_charger,
3576 otg_oc_work);
3577 int rc, i;
3578 u8 stat;
3579
3580 if (!chg->vbus_vreg || !chg->vbus_vreg->rdev)
3581 return;
3582
3583 smblib_err(chg, "over-current detected on VBUS\n");
3584 mutex_lock(&chg->otg_oc_lock);
3585 if (!chg->otg_en)
3586 goto unlock;
3587
3588 smblib_dbg(chg, PR_OTG, "disabling VBUS < 1V check\n");
3589 smblib_masked_write(chg, OTG_CFG_REG,
3590 QUICKSTART_OTG_FASTROLESWAP_BIT,
3591 QUICKSTART_OTG_FASTROLESWAP_BIT);
3592
3593 /*
3594 * If 500ms has passed and another over-current interrupt has not
3595 * triggered then it is likely that the software based soft start was
3596 * successful and the VBUS < 1V restriction should be re-enabled.
3597 */
3598 schedule_delayed_work(&chg->otg_ss_done_work, msecs_to_jiffies(500));
3599
3600 rc = _smblib_vbus_regulator_disable(chg->vbus_vreg->rdev);
3601 if (rc < 0) {
3602 smblib_err(chg, "Couldn't disable VBUS rc=%d\n", rc);
3603 goto unlock;
3604 }
3605
3606 if (++chg->otg_attempts > OTG_MAX_ATTEMPTS) {
3607 cancel_delayed_work_sync(&chg->otg_ss_done_work);
3608 smblib_err(chg, "OTG failed to enable after %d attempts\n",
3609 chg->otg_attempts - 1);
3610 smblib_otg_oc_exit(chg, false);
3611 goto unlock;
3612 }
3613
3614 /*
3615 * The real time status should go low within 10ms. Poll every 1-2ms to
3616 * minimize the delay when re-enabling OTG.
3617 */
3618 for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) {
3619 usleep_range(1000, 2000);
3620 rc = smblib_read(chg, OTG_BASE + INT_RT_STS_OFFSET, &stat);
3621 if (rc >= 0 && !(stat & OTG_OVERCURRENT_RT_STS_BIT))
3622 break;
3623 }
3624
3625 if (i >= MAX_OC_FALLING_TRIES) {
3626 cancel_delayed_work_sync(&chg->otg_ss_done_work);
3627 smblib_err(chg, "OTG OC did not fall after %dms\n",
3628 2 * MAX_OC_FALLING_TRIES);
3629 smblib_otg_oc_exit(chg, false);
3630 goto unlock;
3631 }
3632
3633 smblib_dbg(chg, PR_OTG, "OTG OC fell after %dms\n", 2 * i + 1);
3634 rc = _smblib_vbus_regulator_enable(chg->vbus_vreg->rdev);
3635 if (rc < 0) {
3636 smblib_err(chg, "Couldn't enable VBUS rc=%d\n", rc);
3637 goto unlock;
3638 }
3639
3640unlock:
3641 mutex_unlock(&chg->otg_oc_lock);
3642}
3643
3644static void smblib_vconn_oc_work(struct work_struct *work)
3645{
3646 struct smb_charger *chg = container_of(work, struct smb_charger,
3647 vconn_oc_work);
3648 int rc, i;
3649 u8 stat;
3650
3651 smblib_err(chg, "over-current detected on VCONN\n");
3652 if (!chg->vconn_vreg || !chg->vconn_vreg->rdev)
3653 return;
3654
3655 mutex_lock(&chg->otg_oc_lock);
3656 rc = _smblib_vconn_regulator_disable(chg->vconn_vreg->rdev);
3657 if (rc < 0) {
3658 smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc);
3659 goto unlock;
3660 }
3661
3662 if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
3663 smblib_err(chg, "VCONN failed to enable after %d attempts\n",
3664 chg->otg_attempts - 1);
3665 chg->vconn_en = false;
3666 chg->vconn_attempts = 0;
3667 goto unlock;
3668 }
3669
3670 /*
3671 * The real time status should go low within 10ms. Poll every 1-2ms to
3672 * minimize the delay when re-enabling OTG.
3673 */
3674 for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) {
3675 usleep_range(1000, 2000);
3676 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
3677 if (rc >= 0 && !(stat & TYPEC_VCONN_OVERCURR_STATUS_BIT))
3678 break;
3679 }
3680
3681 if (i >= MAX_OC_FALLING_TRIES) {
3682 smblib_err(chg, "VCONN OC did not fall after %dms\n",
3683 2 * MAX_OC_FALLING_TRIES);
3684 chg->vconn_en = false;
3685 chg->vconn_attempts = 0;
3686 goto unlock;
3687 }
3688
3689 smblib_dbg(chg, PR_OTG, "VCONN OC fell after %dms\n", 2 * i + 1);
3690 if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
3691 smblib_err(chg, "VCONN failed to enable after %d attempts\n",
3692 chg->vconn_attempts - 1);
3693 chg->vconn_en = false;
3694 goto unlock;
3695 }
3696
3697 rc = _smblib_vconn_regulator_enable(chg->vconn_vreg->rdev);
3698 if (rc < 0) {
3699 smblib_err(chg, "Couldn't enable VCONN rc=%d\n", rc);
3700 goto unlock;
3701 }
3702
3703unlock:
3704 mutex_unlock(&chg->otg_oc_lock);
3705}
3706
3707static void smblib_otg_ss_done_work(struct work_struct *work)
3708{
3709 struct smb_charger *chg = container_of(work, struct smb_charger,
3710 otg_ss_done_work.work);
3711 int rc;
3712 bool success = false;
3713 u8 stat;
3714
3715 mutex_lock(&chg->otg_oc_lock);
3716 rc = smblib_read(chg, OTG_STATUS_REG, &stat);
3717 if (rc < 0)
3718 smblib_err(chg, "Couldn't read OTG status rc=%d\n", rc);
3719 else if (stat & BOOST_SOFTSTART_DONE_BIT)
3720 success = true;
3721
3722 smblib_otg_oc_exit(chg, success);
3723 mutex_unlock(&chg->otg_oc_lock);
3724}
3725
Harry Yangba874ce2016-08-19 14:17:01 -07003726static int smblib_create_votables(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07003727{
3728 int rc = 0;
3729
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05303730 chg->fcc_votable = find_votable("FCC");
3731 if (!chg->fcc_votable) {
3732 rc = -EPROBE_DEFER;
3733 return rc;
3734 }
3735
3736 chg->fv_votable = find_votable("FV");
3737 if (!chg->fv_votable) {
3738 rc = -EPROBE_DEFER;
3739 return rc;
3740 }
3741
3742 chg->pl_disable_votable = find_votable("PL_DISABLE");
3743 if (!chg->pl_disable_votable) {
3744 rc = -EPROBE_DEFER;
3745 return rc;
3746 }
3747 vote(chg->pl_disable_votable, PL_INDIRECT_VOTER, true, 0);
Ashay Jaiswal1829fcf2017-02-02 22:45:22 +05303748 vote(chg->pl_disable_votable, PL_DISABLE_HVDCP_VOTER, true, 0);
Ashay Jaiswal37b8ea62017-02-03 11:37:28 +05303749
Abhijeet Dharmapurikare65cb1d2016-08-24 12:29:50 -07003750 chg->usb_suspend_votable = create_votable("USB_SUSPEND", VOTE_SET_ANY,
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07003751 smblib_usb_suspend_vote_callback,
3752 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07003753 if (IS_ERR(chg->usb_suspend_votable)) {
3754 rc = PTR_ERR(chg->usb_suspend_votable);
3755 return rc;
3756 }
3757
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07003758 chg->dc_suspend_votable = create_votable("DC_SUSPEND", VOTE_SET_ANY,
3759 smblib_dc_suspend_vote_callback,
3760 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07003761 if (IS_ERR(chg->dc_suspend_votable)) {
3762 rc = PTR_ERR(chg->dc_suspend_votable);
3763 return rc;
3764 }
3765
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07003766 chg->fcc_max_votable = create_votable("FCC_MAX", VOTE_MAX,
3767 smblib_fcc_max_vote_callback,
3768 chg);
3769 if (IS_ERR(chg->fcc_max_votable)) {
3770 rc = PTR_ERR(chg->fcc_max_votable);
3771 return rc;
3772 }
3773
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07003774 chg->usb_icl_votable = create_votable("USB_ICL", VOTE_MIN,
3775 smblib_usb_icl_vote_callback,
3776 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07003777 if (IS_ERR(chg->usb_icl_votable)) {
3778 rc = PTR_ERR(chg->usb_icl_votable);
3779 return rc;
3780 }
3781
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07003782 chg->dc_icl_votable = create_votable("DC_ICL", VOTE_MIN,
3783 smblib_dc_icl_vote_callback,
3784 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07003785 if (IS_ERR(chg->dc_icl_votable)) {
3786 rc = PTR_ERR(chg->dc_icl_votable);
3787 return rc;
3788 }
3789
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003790 chg->pd_disallowed_votable_indirect
3791 = create_votable("PD_DISALLOWED_INDIRECT", VOTE_SET_ANY,
3792 smblib_pd_disallowed_votable_indirect_callback, chg);
3793 if (IS_ERR(chg->pd_disallowed_votable_indirect)) {
3794 rc = PTR_ERR(chg->pd_disallowed_votable_indirect);
3795 return rc;
3796 }
3797
3798 chg->pd_allowed_votable = create_votable("PD_ALLOWED",
3799 VOTE_SET_ANY, NULL, NULL);
Nicholas Troast34db5032016-03-28 12:26:44 -07003800 if (IS_ERR(chg->pd_allowed_votable)) {
3801 rc = PTR_ERR(chg->pd_allowed_votable);
3802 return rc;
3803 }
3804
Harry Yang223c6282016-06-14 15:48:36 -07003805 chg->awake_votable = create_votable("AWAKE", VOTE_SET_ANY,
3806 smblib_awake_vote_callback,
3807 chg);
3808 if (IS_ERR(chg->awake_votable)) {
3809 rc = PTR_ERR(chg->awake_votable);
3810 return rc;
3811 }
3812
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07003813 chg->chg_disable_votable = create_votable("CHG_DISABLE", VOTE_SET_ANY,
3814 smblib_chg_disable_vote_callback,
3815 chg);
3816 if (IS_ERR(chg->chg_disable_votable)) {
3817 rc = PTR_ERR(chg->chg_disable_votable);
3818 return rc;
3819 }
3820
Harry Yangaba1f5f2016-09-28 10:47:29 -07003821 chg->pl_enable_votable_indirect = create_votable("PL_ENABLE_INDIRECT",
3822 VOTE_SET_ANY,
3823 smblib_pl_enable_indirect_vote_callback,
3824 chg);
3825 if (IS_ERR(chg->pl_enable_votable_indirect)) {
3826 rc = PTR_ERR(chg->pl_enable_votable_indirect);
3827 return rc;
3828 }
3829
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05303830 chg->hvdcp_disable_votable_indirect = create_votable(
3831 "HVDCP_DISABLE_INDIRECT",
3832 VOTE_SET_ANY,
3833 smblib_hvdcp_disable_indirect_vote_callback,
3834 chg);
3835 if (IS_ERR(chg->hvdcp_disable_votable_indirect)) {
3836 rc = PTR_ERR(chg->hvdcp_disable_votable_indirect);
3837 return rc;
3838 }
3839
3840 chg->hvdcp_enable_votable = create_votable("HVDCP_ENABLE",
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07003841 VOTE_SET_ANY,
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05303842 smblib_hvdcp_enable_vote_callback,
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07003843 chg);
Ashay Jaiswal4aa2c0c2016-12-07 19:39:38 +05303844 if (IS_ERR(chg->hvdcp_enable_votable)) {
3845 rc = PTR_ERR(chg->hvdcp_enable_votable);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07003846 return rc;
3847 }
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07003848
3849 chg->apsd_disable_votable = create_votable("APSD_DISABLE",
3850 VOTE_SET_ANY,
3851 smblib_apsd_disable_vote_callback,
3852 chg);
3853 if (IS_ERR(chg->apsd_disable_votable)) {
3854 rc = PTR_ERR(chg->apsd_disable_votable);
3855 return rc;
3856 }
3857
Nicholas Troast320839e2016-06-03 10:18:00 -07003858 return rc;
3859}
3860
Harry Yangba874ce2016-08-19 14:17:01 -07003861static void smblib_destroy_votables(struct smb_charger *chg)
3862{
3863 if (chg->usb_suspend_votable)
3864 destroy_votable(chg->usb_suspend_votable);
3865 if (chg->dc_suspend_votable)
3866 destroy_votable(chg->dc_suspend_votable);
3867 if (chg->fcc_max_votable)
3868 destroy_votable(chg->fcc_max_votable);
Harry Yangba874ce2016-08-19 14:17:01 -07003869 if (chg->usb_icl_votable)
3870 destroy_votable(chg->usb_icl_votable);
3871 if (chg->dc_icl_votable)
3872 destroy_votable(chg->dc_icl_votable);
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07003873 if (chg->pd_disallowed_votable_indirect)
3874 destroy_votable(chg->pd_disallowed_votable_indirect);
Harry Yangba874ce2016-08-19 14:17:01 -07003875 if (chg->pd_allowed_votable)
3876 destroy_votable(chg->pd_allowed_votable);
3877 if (chg->awake_votable)
3878 destroy_votable(chg->awake_votable);
Harry Yangaba1f5f2016-09-28 10:47:29 -07003879 if (chg->chg_disable_votable)
3880 destroy_votable(chg->chg_disable_votable);
3881 if (chg->pl_enable_votable_indirect)
3882 destroy_votable(chg->pl_enable_votable_indirect);
Abhijeet Dharmapurikarf8a7a4a2016-10-07 18:46:45 -07003883 if (chg->apsd_disable_votable)
3884 destroy_votable(chg->apsd_disable_votable);
Harry Yangba874ce2016-08-19 14:17:01 -07003885}
3886
3887static void smblib_iio_deinit(struct smb_charger *chg)
3888{
3889 if (!IS_ERR_OR_NULL(chg->iio.temp_chan))
3890 iio_channel_release(chg->iio.temp_chan);
3891 if (!IS_ERR_OR_NULL(chg->iio.temp_max_chan))
3892 iio_channel_release(chg->iio.temp_max_chan);
3893 if (!IS_ERR_OR_NULL(chg->iio.usbin_i_chan))
3894 iio_channel_release(chg->iio.usbin_i_chan);
3895 if (!IS_ERR_OR_NULL(chg->iio.usbin_v_chan))
3896 iio_channel_release(chg->iio.usbin_v_chan);
Nicholas Troast7dbcad22016-10-05 13:30:18 -07003897 if (!IS_ERR_OR_NULL(chg->iio.batt_i_chan))
3898 iio_channel_release(chg->iio.batt_i_chan);
Harry Yangba874ce2016-08-19 14:17:01 -07003899}
3900
Nicholas Troast320839e2016-06-03 10:18:00 -07003901int smblib_init(struct smb_charger *chg)
3902{
3903 int rc = 0;
3904
3905 mutex_init(&chg->write_lock);
Nicholas Troastb11015f2017-01-17 17:56:45 -08003906 mutex_init(&chg->otg_oc_lock);
Harry Yangfe913842016-08-10 12:27:28 -07003907 INIT_WORK(&chg->bms_update_work, bms_update_work);
Harry Yang755a34b2016-11-01 01:18:51 -07003908 INIT_WORK(&chg->rdstd_cc2_detach_work, rdstd_cc2_detach_work);
Nicholas Troast320839e2016-06-03 10:18:00 -07003909 INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work);
Harry Yangfe913842016-08-10 12:27:28 -07003910 INIT_DELAYED_WORK(&chg->step_soc_req_work, step_soc_req_work);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07003911 INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work);
Nicholas Troastb11015f2017-01-17 17:56:45 -08003912 INIT_WORK(&chg->otg_oc_work, smblib_otg_oc_work);
3913 INIT_WORK(&chg->vconn_oc_work, smblib_vconn_oc_work);
3914 INIT_DELAYED_WORK(&chg->otg_ss_done_work, smblib_otg_ss_done_work);
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07003915 chg->fake_capacity = -EINVAL;
Nicholas Troast320839e2016-06-03 10:18:00 -07003916
3917 switch (chg->mode) {
3918 case PARALLEL_MASTER:
3919 rc = smblib_create_votables(chg);
3920 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003921 smblib_err(chg, "Couldn't create votables rc=%d\n",
Nicholas Troast320839e2016-06-03 10:18:00 -07003922 rc);
Harry Yang58a9e7a2016-06-23 14:54:43 -07003923 return rc;
Nicholas Troast320839e2016-06-03 10:18:00 -07003924 }
Harry Yang58a9e7a2016-06-23 14:54:43 -07003925
Harry Yang5e1a5222016-07-26 15:16:04 -07003926 rc = smblib_register_notifier(chg);
3927 if (rc < 0) {
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003928 smblib_err(chg,
Harry Yang5e1a5222016-07-26 15:16:04 -07003929 "Couldn't register notifier rc=%d\n", rc);
3930 return rc;
Harry Yang58a9e7a2016-06-23 14:54:43 -07003931 }
3932
Harry Yang995b7422016-08-29 16:06:50 -07003933 chg->bms_psy = power_supply_get_by_name("bms");
Ashay Jaiswal8afedfc2017-02-03 11:18:22 +05303934 chg->pl.psy = power_supply_get_by_name("parallel");
Nicholas Troast320839e2016-06-03 10:18:00 -07003935 break;
3936 case PARALLEL_SLAVE:
3937 break;
3938 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003939 smblib_err(chg, "Unsupported mode %d\n", chg->mode);
Nicholas Troast320839e2016-06-03 10:18:00 -07003940 return -EINVAL;
3941 }
3942
3943 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07003944}
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07003945
3946int smblib_deinit(struct smb_charger *chg)
3947{
Harry Yangba874ce2016-08-19 14:17:01 -07003948 switch (chg->mode) {
3949 case PARALLEL_MASTER:
3950 power_supply_unreg_notifier(&chg->nb);
3951 smblib_destroy_votables(chg);
3952 break;
3953 case PARALLEL_SLAVE:
3954 break;
3955 default:
Abhijeet Dharmapurikar31b98f32016-10-14 12:25:23 -07003956 smblib_err(chg, "Unsupported mode %d\n", chg->mode);
Harry Yangba874ce2016-08-19 14:17:01 -07003957 return -EINVAL;
3958 }
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07003959
Harry Yangba874ce2016-08-19 14:17:01 -07003960 smblib_iio_deinit(chg);
Harry Yang5e1a5222016-07-26 15:16:04 -07003961
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07003962 return 0;
3963}