blob: 3e4d3930364178b2a286c3c101a172210d5379d6 [file] [log] [blame]
Nicholas Troast34db5032016-03-28 12:26:44 -07001/* Copyright (c) 2016 The Linux Foundation. All rights reserved.
2 *
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>
19#include <linux/irq.h>
20#include "smb-lib.h"
21#include "smb-reg.h"
Nicholas Troast47ae4612016-08-03 09:49:36 -070022#include "storm-watch.h"
Nicholas Troast34db5032016-03-28 12:26:44 -070023#include "pmic-voter.h"
24
25#define smblib_dbg(chg, reason, fmt, ...) \
26 do { \
27 if (*chg->debug_mask & (reason)) \
28 dev_info(chg->dev, fmt, ##__VA_ARGS__); \
29 else \
30 dev_dbg(chg->dev, fmt, ##__VA_ARGS__); \
31 } while (0)
32
33static bool is_secure(struct smb_charger *chg, int addr)
34{
35 /* assume everything above 0xC0 is secure */
Nicholas Troast26b01da2016-07-18 13:40:25 -070036 return (bool)((addr & 0xFF) >= 0xC0);
Nicholas Troast34db5032016-03-28 12:26:44 -070037}
38
39int smblib_read(struct smb_charger *chg, u16 addr, u8 *val)
40{
41 unsigned int temp;
42 int rc = 0;
43
44 rc = regmap_read(chg->regmap, addr, &temp);
45 if (rc >= 0)
46 *val = (u8)temp;
47
48 return rc;
49}
50
51int smblib_masked_write(struct smb_charger *chg, u16 addr, u8 mask, u8 val)
52{
Nicholas Troast34db5032016-03-28 12:26:44 -070053 int rc = 0;
54
Harry Yangbacd2222016-05-11 16:43:51 -070055 mutex_lock(&chg->write_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -070056 if (is_secure(chg, addr)) {
57 rc = regmap_write(chg->regmap, (addr & 0xFF00) | 0xD0, 0xA5);
58 if (rc < 0)
59 goto unlock;
60 }
61
62 rc = regmap_update_bits(chg->regmap, addr, mask, val);
63
64unlock:
Harry Yangbacd2222016-05-11 16:43:51 -070065 mutex_unlock(&chg->write_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -070066 return rc;
67}
68
69int smblib_write(struct smb_charger *chg, u16 addr, u8 val)
70{
Nicholas Troast34db5032016-03-28 12:26:44 -070071 int rc = 0;
72
Harry Yangbacd2222016-05-11 16:43:51 -070073 mutex_lock(&chg->write_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -070074
75 if (is_secure(chg, addr)) {
76 rc = regmap_write(chg->regmap, (addr & ~(0xFF)) | 0xD0, 0xA5);
77 if (rc < 0)
78 goto unlock;
79 }
80
81 rc = regmap_write(chg->regmap, addr, val);
82
83unlock:
Harry Yangbacd2222016-05-11 16:43:51 -070084 mutex_unlock(&chg->write_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -070085 return rc;
86}
87
Harry Yangfe913842016-08-10 12:27:28 -070088static int smblib_get_step_charging_adjustment(struct smb_charger *chg,
89 int *cc_offset)
90{
91 int step_state;
92 int rc;
93 u8 stat;
94
95 if (!chg->step_chg_enabled) {
96 *cc_offset = 0;
97 return 0;
98 }
99
100 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
101 if (rc < 0) {
102 dev_err(chg->dev, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
103 rc);
104 return rc;
105 }
106
Harry Yangbedee332016-08-31 16:14:29 -0700107 step_state = (stat & STEP_CHARGING_STATUS_MASK) >>
108 STEP_CHARGING_STATUS_SHIFT;
Harry Yangfe913842016-08-10 12:27:28 -0700109 rc = smblib_get_charge_param(chg, &chg->param.step_cc_delta[step_state],
110 cc_offset);
111
112 return rc;
113}
114
Harry Yang1d1034c2016-06-15 12:09:42 -0700115static void smblib_fcc_split_ua(struct smb_charger *chg, int total_fcc,
116 int *master_ua, int *slave_ua)
117{
Abhijeet Dharmapurikar2644cd62016-07-20 16:54:55 -0700118 int rc, cc_reduction_ua = 0;
Harry Yangfe913842016-08-10 12:27:28 -0700119 int step_cc_delta;
Harry Yang1d1034c2016-06-15 12:09:42 -0700120 int master_percent = min(max(*chg->pl.master_percent, 0), 100);
Abhijeet Dharmapurikar2644cd62016-07-20 16:54:55 -0700121 union power_supply_propval pval = {0, };
Harry Yangfe913842016-08-10 12:27:28 -0700122 int effective_fcc;
Harry Yang1d1034c2016-06-15 12:09:42 -0700123
Abhijeet Dharmapurikar2644cd62016-07-20 16:54:55 -0700124 /*
125 * if master_percent is 0, s/w will configure master's fcc to zero and
126 * slave's fcc to the max. However since master's fcc is zero it
127 * disables its own charging and as a result the slave's charging is
128 * disabled via the fault line.
129 */
130
131 rc = smblib_get_prop_batt_health(chg, &pval);
132 if (rc == 0) {
133 if (pval.intval == POWER_SUPPLY_HEALTH_WARM
134 || pval.intval == POWER_SUPPLY_HEALTH_COOL) {
135 rc = smblib_get_charge_param(chg,
136 &chg->param.jeita_cc_comp,
137 &cc_reduction_ua);
138 if (rc < 0) {
139 dev_err(chg->dev, "Could not get jeita comp, rc=%d\n",
140 rc);
141 cc_reduction_ua = 0;
142 }
143 }
144 }
145
Harry Yangfe913842016-08-10 12:27:28 -0700146 rc = smblib_get_step_charging_adjustment(chg, &step_cc_delta);
147 if (rc < 0)
148 step_cc_delta = 0;
149
150 /*
151 * During JEITA condition and with step_charging enabled, PMI will
152 * pick the lower of the two value: (FCC - JEITA current compensation)
153 * or (FCC + step_charging current delta)
154 */
155
156 effective_fcc = min(max(0, total_fcc - cc_reduction_ua),
157 max(0, total_fcc + step_cc_delta));
158 *master_ua = (effective_fcc * master_percent) / 100;
159 *slave_ua = (effective_fcc - *master_ua) * chg->pl.taper_percent / 100;
160 *master_ua = max(0, *master_ua + total_fcc - effective_fcc);
Harry Yang1d1034c2016-06-15 12:09:42 -0700161}
162
Nicholas Troast34db5032016-03-28 12:26:44 -0700163/********************
164 * REGISTER GETTERS *
165 ********************/
166
Nicholas Troast4c310492016-05-12 17:56:35 -0700167int smblib_get_charge_param(struct smb_charger *chg,
168 struct smb_chg_param *param, int *val_u)
169{
170 int rc = 0;
171 u8 val_raw;
172
173 rc = smblib_read(chg, param->reg, &val_raw);
174 if (rc < 0) {
175 dev_err(chg->dev, "%s: Couldn't read from 0x%04x rc=%d\n",
176 param->name, param->reg, rc);
177 return rc;
178 }
179
Harry Yangf8b41252016-08-10 14:21:10 -0700180 if (param->get_proc)
181 *val_u = param->get_proc(param, val_raw);
182 else
183 *val_u = val_raw * param->step_u + param->min_u;
Nicholas Troast4c310492016-05-12 17:56:35 -0700184 smblib_dbg(chg, PR_REGISTER, "%s = %d (0x%02x)\n",
185 param->name, *val_u, val_raw);
186
187 return rc;
188}
189
190int smblib_get_usb_suspend(struct smb_charger *chg, int *suspend)
191{
192 int rc = 0;
193 u8 temp;
194
195 rc = smblib_read(chg, USBIN_CMD_IL_REG, &temp);
196 if (rc < 0) {
197 dev_err(chg->dev, "Couldn't read USBIN_CMD_IL rc=%d\n", rc);
198 return rc;
199 }
200 *suspend = temp & USBIN_SUSPEND_BIT;
201
202 return rc;
203}
204
Nicholas Troast34db5032016-03-28 12:26:44 -0700205struct apsd_result {
206 const char * const name;
207 const u8 bit;
208 const enum power_supply_type pst;
209};
210
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700211enum {
212 UNKNOWN,
213 SDP,
214 CDP,
215 DCP,
216 OCP,
217 FLOAT,
218 HVDCP2,
219 HVDCP3,
220 MAX_TYPES
221};
222
Nicholas Troast34db5032016-03-28 12:26:44 -0700223static const struct apsd_result const smblib_apsd_results[] = {
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700224 [UNKNOWN] = {
225 .name = "UNKNOWN",
226 .bit = 0,
227 .pst = POWER_SUPPLY_TYPE_UNKNOWN
228 },
229 [SDP] = {
230 .name = "SDP",
231 .bit = SDP_CHARGER_BIT,
232 .pst = POWER_SUPPLY_TYPE_USB
233 },
234 [CDP] = {
235 .name = "CDP",
236 .bit = CDP_CHARGER_BIT,
237 .pst = POWER_SUPPLY_TYPE_USB_CDP
238 },
239 [DCP] = {
240 .name = "DCP",
241 .bit = DCP_CHARGER_BIT,
242 .pst = POWER_SUPPLY_TYPE_USB_DCP
243 },
244 [OCP] = {
245 .name = "OCP",
246 .bit = OCP_CHARGER_BIT,
247 .pst = POWER_SUPPLY_TYPE_USB_DCP
248 },
249 [FLOAT] = {
250 .name = "FLOAT",
251 .bit = FLOAT_CHARGER_BIT,
252 .pst = POWER_SUPPLY_TYPE_USB_DCP
253 },
254 [HVDCP2] = {
255 .name = "HVDCP2",
256 .bit = DCP_CHARGER_BIT | QC_2P0_BIT,
257 .pst = POWER_SUPPLY_TYPE_USB_HVDCP
258 },
259 [HVDCP3] = {
260 .name = "HVDCP3",
261 .bit = DCP_CHARGER_BIT | QC_3P0_BIT,
262 .pst = POWER_SUPPLY_TYPE_USB_HVDCP_3,
263 },
Nicholas Troast34db5032016-03-28 12:26:44 -0700264};
265
266static const struct apsd_result *smblib_get_apsd_result(struct smb_charger *chg)
267{
268 int rc, i;
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700269 u8 apsd_stat, stat;
270 const struct apsd_result *result = &smblib_apsd_results[UNKNOWN];
Nicholas Troast34db5032016-03-28 12:26:44 -0700271
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700272 rc = smblib_read(chg, APSD_STATUS_REG, &apsd_stat);
Nicholas Troast34db5032016-03-28 12:26:44 -0700273 if (rc < 0) {
274 dev_err(chg->dev, "Couldn't read APSD_STATUS rc=%d\n", rc);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700275 return result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700276 }
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700277 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", apsd_stat);
Nicholas Troast34db5032016-03-28 12:26:44 -0700278
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700279 if (!(apsd_stat & APSD_DTC_STATUS_DONE_BIT))
280 return result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700281
282 rc = smblib_read(chg, APSD_RESULT_STATUS_REG, &stat);
283 if (rc < 0) {
284 dev_err(chg->dev, "Couldn't read APSD_RESULT_STATUS rc=%d\n",
285 rc);
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700286 return result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700287 }
288 stat &= APSD_RESULT_STATUS_MASK;
289
290 for (i = 0; i < ARRAY_SIZE(smblib_apsd_results); i++) {
291 if (smblib_apsd_results[i].bit == stat)
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700292 result = &smblib_apsd_results[i];
Nicholas Troast34db5032016-03-28 12:26:44 -0700293 }
294
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700295 if (apsd_stat & QC_CHARGER_BIT) {
296 /* since its a qc_charger, either return HVDCP3 or HVDCP2 */
297 if (result != &smblib_apsd_results[HVDCP3])
298 result = &smblib_apsd_results[HVDCP2];
299 }
300
301 return result;
Nicholas Troast34db5032016-03-28 12:26:44 -0700302}
303
304
305/********************
306 * REGISTER SETTERS *
307 ********************/
308
Nicholas Troast4c310492016-05-12 17:56:35 -0700309int smblib_set_charge_param(struct smb_charger *chg,
310 struct smb_chg_param *param, int val_u)
Nicholas Troast34db5032016-03-28 12:26:44 -0700311{
312 int rc = 0;
313 u8 val_raw;
314
Harry Yangf8b41252016-08-10 14:21:10 -0700315 if (param->set_proc) {
316 rc = param->set_proc(param, val_u, &val_raw);
317 if (rc < 0)
318 return -EINVAL;
319 } else {
320 if (val_u > param->max_u || val_u < param->min_u) {
321 dev_err(chg->dev, "%s: %d is out of range [%d, %d]\n",
322 param->name, val_u, param->min_u, param->max_u);
323 return -EINVAL;
324 }
325
326 val_raw = (val_u - param->min_u) / param->step_u;
Nicholas Troast34db5032016-03-28 12:26:44 -0700327 }
328
Nicholas Troast34db5032016-03-28 12:26:44 -0700329 rc = smblib_write(chg, param->reg, val_raw);
330 if (rc < 0) {
331 dev_err(chg->dev, "%s: Couldn't write 0x%02x to 0x%04x rc=%d\n",
332 param->name, val_raw, param->reg, rc);
333 return rc;
334 }
335
336 smblib_dbg(chg, PR_REGISTER, "%s = %d (0x%02x)\n",
337 param->name, val_u, val_raw);
338
339 return rc;
340}
341
Harry Yangfe913842016-08-10 12:27:28 -0700342static int step_charge_soc_update(struct smb_charger *chg, int capacity)
343{
344 int rc = 0;
345
346 rc = smblib_set_charge_param(chg, &chg->param.step_soc, capacity);
347 if (rc < 0) {
348 dev_err(chg->dev, "Error in updating soc, rc=%d\n", rc);
349 return rc;
350 }
351
352 rc = smblib_write(chg, STEP_CHG_SOC_VBATT_V_UPDATE_REG,
353 STEP_CHG_SOC_VBATT_V_UPDATE_BIT);
354 if (rc < 0) {
355 dev_err(chg->dev,
356 "Couldn't set STEP_CHG_SOC_VBATT_V_UPDATE_REG rc=%d\n",
357 rc);
358 return rc;
359 }
360
361 return rc;
362}
363
Nicholas Troast4c310492016-05-12 17:56:35 -0700364int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend)
Nicholas Troast34db5032016-03-28 12:26:44 -0700365{
366 int rc = 0;
367
368 rc = smblib_masked_write(chg, USBIN_CMD_IL_REG, USBIN_SUSPEND_BIT,
369 suspend ? USBIN_SUSPEND_BIT : 0);
370 if (rc < 0)
371 dev_err(chg->dev, "Couldn't write %s to USBIN_SUSPEND_BIT rc=%d\n",
372 suspend ? "suspend" : "resume", rc);
373
374 return rc;
375}
376
Nicholas Troast4c310492016-05-12 17:56:35 -0700377int smblib_set_dc_suspend(struct smb_charger *chg, bool suspend)
Nicholas Troast34db5032016-03-28 12:26:44 -0700378{
379 int rc = 0;
380
381 rc = smblib_masked_write(chg, DCIN_CMD_IL_REG, DCIN_SUSPEND_BIT,
382 suspend ? DCIN_SUSPEND_BIT : 0);
383 if (rc < 0)
384 dev_err(chg->dev, "Couldn't write %s to DCIN_SUSPEND_BIT rc=%d\n",
385 suspend ? "suspend" : "resume", rc);
386
387 return rc;
388}
389
390#define MICRO_5V 5000000
391#define MICRO_9V 9000000
392#define MICRO_12V 12000000
393static int smblib_set_usb_pd_allowed_voltage(struct smb_charger *chg,
394 int min_allowed_uv, int max_allowed_uv)
395{
396 int rc;
397 u8 allowed_voltage;
398
399 if (min_allowed_uv == MICRO_5V && max_allowed_uv == MICRO_5V) {
400 allowed_voltage = USBIN_ADAPTER_ALLOW_5V;
401 } else if (min_allowed_uv == MICRO_9V && max_allowed_uv == MICRO_9V) {
402 allowed_voltage = USBIN_ADAPTER_ALLOW_9V;
403 } else if (min_allowed_uv == MICRO_12V && max_allowed_uv == MICRO_12V) {
404 allowed_voltage = USBIN_ADAPTER_ALLOW_12V;
405 } else if (min_allowed_uv < MICRO_9V && max_allowed_uv <= MICRO_9V) {
406 allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_9V;
407 } else if (min_allowed_uv < MICRO_9V && max_allowed_uv <= MICRO_12V) {
408 allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_12V;
409 } else if (min_allowed_uv < MICRO_12V && max_allowed_uv <= MICRO_12V) {
410 allowed_voltage = USBIN_ADAPTER_ALLOW_9V_TO_12V;
411 } else {
412 dev_err(chg->dev, "invalid allowed voltage [%d, %d]\n",
413 min_allowed_uv, max_allowed_uv);
414 return -EINVAL;
415 }
416
417 rc = smblib_write(chg, USBIN_ADAPTER_ALLOW_CFG_REG, allowed_voltage);
418 if (rc < 0) {
419 dev_err(chg->dev, "Couldn't write 0x%02x to USBIN_ADAPTER_ALLOW_CFG rc=%d\n",
420 allowed_voltage, rc);
421 return rc;
422 }
423
424 return rc;
425}
426
427/********************
428 * HELPER FUNCTIONS *
429 ********************/
430
431static int smblib_update_usb_type(struct smb_charger *chg)
432{
433 int rc = 0;
434 const struct apsd_result *apsd_result;
435
Jack Pham9696e252016-05-23 11:15:15 -0700436 /* if PD is active, APSD is disabled so won't have a valid result */
437 if (chg->pd_active)
Nicholas Troast34db5032016-03-28 12:26:44 -0700438 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -0700439
440 apsd_result = smblib_get_apsd_result(chg);
441 chg->usb_psy_desc.type = apsd_result->pst;
442 return rc;
443}
444
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -0700445static int smblib_detach_typec(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -0700446{
447 int rc;
448
449 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
Jack Pham9696e252016-05-23 11:15:15 -0700450 chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_UNKNOWN;
Nicholas Troast34db5032016-03-28 12:26:44 -0700451
452 /* reconfigure allowed voltage for HVDCP */
453 rc = smblib_write(chg, USBIN_ADAPTER_ALLOW_CFG_REG,
454 USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
455 if (rc < 0) {
456 dev_err(chg->dev, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
457 rc);
458 return rc;
459 }
460
461 chg->voltage_min_uv = MICRO_5V;
462 chg->voltage_max_uv = MICRO_5V;
463
464 /* clear USB ICL vote for PD_VOTER */
465 rc = vote(chg->usb_icl_votable, PD_VOTER, false, 0);
466 if (rc < 0) {
467 dev_err(chg->dev, "Couldn't vote for USB ICL rc=%d\n",
468 rc);
469 return rc;
470 }
471
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -0700472 /* cc removed, disable pd_allowed */
473 vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0);
474 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER, true, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -0700475
476 return rc;
477}
478
Harry Yang5e1a5222016-07-26 15:16:04 -0700479static int smblib_notifier_call(struct notifier_block *nb,
Harry Yang58a9e7a2016-06-23 14:54:43 -0700480 unsigned long ev, void *v)
Harry Yang1d1034c2016-06-15 12:09:42 -0700481{
Harry Yang58a9e7a2016-06-23 14:54:43 -0700482 struct power_supply *psy = v;
Harry Yang5e1a5222016-07-26 15:16:04 -0700483 struct smb_charger *chg = container_of(nb, struct smb_charger, nb);
Harry Yang1d1034c2016-06-15 12:09:42 -0700484
Harry Yang5e1a5222016-07-26 15:16:04 -0700485 if (!strcmp(psy->desc->name, "bms")) {
486 if (!chg->bms_psy)
487 chg->bms_psy = psy;
488 if (ev == PSY_EVENT_PROP_CHANGED && chg->batt_psy)
489 schedule_work(&chg->bms_update_work);
490 }
491
492 if (!chg->pl.psy && !strcmp(psy->desc->name, "parallel")) {
Harry Yang58a9e7a2016-06-23 14:54:43 -0700493 chg->pl.psy = psy;
494 schedule_work(&chg->pl_detect_work);
495 }
Harry Yang1d1034c2016-06-15 12:09:42 -0700496
Harry Yang58a9e7a2016-06-23 14:54:43 -0700497 return NOTIFY_OK;
498}
499
Harry Yang5e1a5222016-07-26 15:16:04 -0700500static int smblib_register_notifier(struct smb_charger *chg)
Harry Yang58a9e7a2016-06-23 14:54:43 -0700501{
502 int rc;
503
Harry Yang5e1a5222016-07-26 15:16:04 -0700504 chg->nb.notifier_call = smblib_notifier_call;
505 rc = power_supply_reg_notifier(&chg->nb);
Harry Yang58a9e7a2016-06-23 14:54:43 -0700506 if (rc < 0) {
507 pr_err("Couldn't register psy notifier rc = %d\n", rc);
508 return rc;
509 }
510
511 return 0;
Harry Yang1d1034c2016-06-15 12:09:42 -0700512}
513
Harry Yangfe913842016-08-10 12:27:28 -0700514int smblib_mapping_soc_from_field_value(struct smb_chg_param *param,
515 int val_u, u8 *val_raw)
516{
517 if (val_u > param->max_u || val_u < param->min_u)
518 return -EINVAL;
519
520 *val_raw = val_u << 1;
521
522 return 0;
523}
524
525int smblib_mapping_cc_delta_to_field_value(struct smb_chg_param *param,
526 u8 val_raw)
527{
528 int val_u = val_raw * param->step_u + param->min_u;
529
530 if (val_u > param->max_u)
531 val_u -= param->max_u * 2;
532
533 return val_u;
534}
535
536int smblib_mapping_cc_delta_from_field_value(struct smb_chg_param *param,
537 int val_u, u8 *val_raw)
538{
539 if (val_u > param->max_u || val_u < param->min_u - param->max_u)
540 return -EINVAL;
541
542 val_u += param->max_u * 2 - param->min_u;
543 val_u %= param->max_u * 2;
544 *val_raw = val_u / param->step_u;
545
546 return 0;
547}
548
Nicholas Troast34db5032016-03-28 12:26:44 -0700549/*********************
550 * VOTABLE CALLBACKS *
551 *********************/
552
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700553static int smblib_usb_suspend_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -0700554 int suspend, const char *client)
Nicholas Troast34db5032016-03-28 12:26:44 -0700555{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700556 struct smb_charger *chg = data;
Nicholas Troast34db5032016-03-28 12:26:44 -0700557
558 return smblib_set_usb_suspend(chg, suspend);
559}
560
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700561static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -0700562 int suspend, const char *client)
Nicholas Troast34db5032016-03-28 12:26:44 -0700563{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700564 struct smb_charger *chg = data;
Nicholas Troast34db5032016-03-28 12:26:44 -0700565
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700566 if (suspend < 0)
567 suspend = false;
568
Nicholas Troast34db5032016-03-28 12:26:44 -0700569 return smblib_set_dc_suspend(chg, suspend);
570}
571
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -0700572static int smblib_fcc_max_vote_callback(struct votable *votable, void *data,
573 int fcc_ua, const char *client)
574{
575 struct smb_charger *chg = data;
576
Harry Yangaba1f5f2016-09-28 10:47:29 -0700577 return vote(chg->fcc_votable, FCC_MAX_RESULT_VOTER, true, fcc_ua);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -0700578}
579
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700580static int smblib_fcc_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -0700581 int fcc_ua, const char *client)
Nicholas Troast34db5032016-03-28 12:26:44 -0700582{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700583 struct smb_charger *chg = data;
Nicholas Troast34db5032016-03-28 12:26:44 -0700584 int rc = 0;
Harry Yang1d1034c2016-06-15 12:09:42 -0700585 union power_supply_propval pval = {0, };
586 int master_ua = fcc_ua, slave_ua;
Nicholas Troast34db5032016-03-28 12:26:44 -0700587
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700588 if (fcc_ua < 0) {
589 smblib_dbg(chg, PR_MISC, "No Voter\n");
590 return 0;
591 }
592
Harry Yang1d1034c2016-06-15 12:09:42 -0700593 if (chg->mode == PARALLEL_MASTER
594 && !get_effective_result_locked(chg->pl_disable_votable)) {
595 smblib_fcc_split_ua(chg, fcc_ua, &master_ua, &slave_ua);
596
597 /*
598 * parallel charger is not disabled, implying that
599 * chg->pl.psy exists
600 */
601 pval.intval = slave_ua;
602 rc = power_supply_set_property(chg->pl.psy,
603 POWER_SUPPLY_PROP_CURRENT_MAX, &pval);
604 if (rc < 0) {
605 dev_err(chg->dev, "Could not set parallel fcc, rc=%d\n",
606 rc);
607 return rc;
608 }
609
610 chg->pl.slave_fcc = slave_ua;
611 }
612
613 rc = smblib_set_charge_param(chg, &chg->param.fcc, master_ua);
614 if (rc < 0) {
615 dev_err(chg->dev, "Error in setting fcc, rc=%d\n", rc);
616 return rc;
617 }
618
619 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -0700620}
621
Harry Yang1d1034c2016-06-15 12:09:42 -0700622#define PARALLEL_FLOAT_VOLTAGE_DELTA_UV 50000
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700623static int smblib_fv_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -0700624 int fv_uv, const char *client)
Abhijeet Dharmapurikarf9805d42016-05-17 18:38:42 -0700625{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700626 struct smb_charger *chg = data;
Harry Yang1d1034c2016-06-15 12:09:42 -0700627 union power_supply_propval pval = {0, };
Abhijeet Dharmapurikarf9805d42016-05-17 18:38:42 -0700628 int rc = 0;
629
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700630 if (fv_uv < 0) {
631 smblib_dbg(chg, PR_MISC, "No Voter\n");
632 return 0;
633 }
634
Abhijeet Dharmapurikarf9805d42016-05-17 18:38:42 -0700635 rc = smblib_set_charge_param(chg, &chg->param.fv, fv_uv);
Harry Yang1d1034c2016-06-15 12:09:42 -0700636 if (rc < 0) {
637 dev_err(chg->dev,
638 "Couldn't set floating voltage rc=%d\n", rc);
639 return rc;
640 }
641
Harry Yang58a9e7a2016-06-23 14:54:43 -0700642 if (chg->mode == PARALLEL_MASTER && chg->pl.psy) {
Harry Yang1d1034c2016-06-15 12:09:42 -0700643 pval.intval = fv_uv + PARALLEL_FLOAT_VOLTAGE_DELTA_UV;
644 rc = power_supply_set_property(chg->pl.psy,
645 POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval);
646 if (rc < 0) {
647 dev_err(chg->dev,
648 "Couldn't set float on parallel rc=%d\n", rc);
649 return rc;
650 }
651 }
652
653 return 0;
Abhijeet Dharmapurikarf9805d42016-05-17 18:38:42 -0700654}
655
Nicholas Troastbb76a142016-09-23 11:23:23 -0700656#define USBIN_25MA 25000
657#define USBIN_100MA 100000
658#define USBIN_150MA 150000
659#define USBIN_500MA 500000
660#define USBIN_900MA 900000
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700661static int smblib_usb_icl_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -0700662 int icl_ua, const char *client)
Nicholas Troast34db5032016-03-28 12:26:44 -0700663{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700664 struct smb_charger *chg = data;
Nicholas Troast34db5032016-03-28 12:26:44 -0700665 int rc = 0;
Nicholas Troastbb76a142016-09-23 11:23:23 -0700666 bool suspend = (icl_ua < USBIN_25MA);
667 u8 icl_options = 0;
Nicholas Troast34db5032016-03-28 12:26:44 -0700668
Nicholas Troastbb76a142016-09-23 11:23:23 -0700669 if (suspend)
670 goto out;
671
672 if (chg->usb_psy_desc.type != POWER_SUPPLY_TYPE_USB) {
673 rc = smblib_set_charge_param(chg, &chg->param.usb_icl, icl_ua);
674 if (rc < 0) {
675 dev_err(chg->dev, "Couldn't set HC ICL rc=%d\n", rc);
676 return rc;
677 }
678
679 goto out;
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700680 }
681
Nicholas Troastbb76a142016-09-23 11:23:23 -0700682 /* power source is SDP */
683 switch (icl_ua) {
684 case USBIN_100MA:
685 /* USB 2.0 100mA */
686 icl_options = 0;
687 break;
688 case USBIN_150MA:
689 /* USB 3.0 150mA */
690 icl_options = CFG_USB3P0_SEL_BIT;
691 break;
692 case USBIN_500MA:
693 /* USB 2.0 500mA */
694 icl_options = USB51_MODE_BIT;
695 break;
696 case USBIN_900MA:
697 /* USB 3.0 900mA */
698 icl_options = CFG_USB3P0_SEL_BIT | USB51_MODE_BIT;
699 break;
700 default:
701 dev_err(chg->dev, "ICL %duA isn't supported for SDP\n", icl_ua);
702 icl_options = 0;
703 break;
704 }
Nicholas Troast34db5032016-03-28 12:26:44 -0700705
Nicholas Troastbb76a142016-09-23 11:23:23 -0700706out:
707 rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
708 CFG_USB3P0_SEL_BIT | USB51_MODE_BIT, icl_options);
Nicholas Troast34db5032016-03-28 12:26:44 -0700709 if (rc < 0) {
Nicholas Troastbb76a142016-09-23 11:23:23 -0700710 dev_err(chg->dev, "Couldn't set ICL opetions rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -0700711 return rc;
712 }
713
Nicholas Troast34db5032016-03-28 12:26:44 -0700714 rc = vote(chg->usb_suspend_votable, PD_VOTER, suspend, 0);
715 if (rc < 0) {
716 dev_err(chg->dev, "Couldn't %s input rc=%d\n",
717 suspend ? "suspend" : "resume", rc);
718 return rc;
719 }
720
721 return rc;
722}
723
Harry Yang360bd532016-09-26 11:03:22 -0700724#define MICRO_250MA 250000
725static int smblib_otg_cl_config(struct smb_charger *chg, int otg_cl_ua)
726{
727 int rc = 0;
728
729 rc = smblib_set_charge_param(chg, &chg->param.otg_cl, otg_cl_ua);
730 if (rc < 0) {
731 dev_err(chg->dev, "Couldn't set otg current limit rc=%d\n",
732 rc);
733 return rc;
734 }
735
736 /* configure PFM/PWM mode for OTG regulator */
737 rc = smblib_masked_write(chg, DC_ENG_SSUPPLY_CFG3_REG,
738 ENG_SSUPPLY_CFG_SKIP_TH_V0P2_BIT,
739 otg_cl_ua > MICRO_250MA ? 1 : 0);
740 if (rc < 0) {
741 dev_err(chg->dev,
742 "Couldn't write DC_ENG_SSUPPLY_CFG3_REG rc=%d\n", rc);
743 return rc;
744 }
745
746 return rc;
747}
748
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700749static int smblib_dc_icl_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -0700750 int icl_ua, const char *client)
Nicholas Troast34db5032016-03-28 12:26:44 -0700751{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700752 struct smb_charger *chg = data;
Nicholas Troast34db5032016-03-28 12:26:44 -0700753 int rc = 0;
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700754 bool suspend;
755
756 if (icl_ua < 0) {
757 smblib_dbg(chg, PR_MISC, "No Voter hence suspending\n");
758 icl_ua = 0;
759 }
760
761 suspend = (icl_ua < USBIN_25MA);
762 if (suspend)
763 goto suspend;
Nicholas Troast34db5032016-03-28 12:26:44 -0700764
765 rc = smblib_set_charge_param(chg, &chg->param.dc_icl, icl_ua);
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700766 if (rc < 0) {
767 dev_err(chg->dev, "Couldn't set DC input current limit rc=%d\n",
768 rc);
769 return rc;
770 }
771
772suspend:
773 rc = vote(chg->dc_suspend_votable, USER_VOTER, suspend, 0);
774 if (rc < 0) {
775 dev_err(chg->dev, "Couldn't vote to %s DC rc=%d\n",
776 suspend ? "suspend" : "resume", rc);
777 return rc;
778 }
Nicholas Troast34db5032016-03-28 12:26:44 -0700779 return rc;
780}
781
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -0700782static int smblib_pd_disallowed_votable_indirect_callback(
783 struct votable *votable, void *data, int disallowed, const char *client)
784{
785 struct smb_charger *chg = data;
786 int rc;
787
788 rc = vote(chg->pd_allowed_votable, PD_DISALLOWED_INDIRECT_VOTER,
789 !disallowed, 0);
790
791 return rc;
792}
793
Harry Yang223c6282016-06-14 15:48:36 -0700794static int smblib_awake_vote_callback(struct votable *votable, void *data,
795 int awake, const char *client)
796{
797 struct smb_charger *chg = data;
798
799 if (awake)
800 pm_stay_awake(chg->dev);
801 else
802 pm_relax(chg->dev);
803
804 return 0;
805}
806
Harry Yang3c4c22d2016-06-15 11:40:54 -0700807static int smblib_pl_disable_vote_callback(struct votable *votable, void *data,
808 int pl_disable, const char *client)
809{
Harry Yang1d1034c2016-06-15 12:09:42 -0700810 struct smb_charger *chg = data;
811 union power_supply_propval pval = {0, };
812 int rc;
813
Harry Yang58a9e7a2016-06-23 14:54:43 -0700814 if (chg->mode != PARALLEL_MASTER || !chg->pl.psy)
Harry Yang1d1034c2016-06-15 12:09:42 -0700815 return 0;
816
817 chg->pl.taper_percent = 100;
818 rerun_election(chg->fv_votable);
819 rerun_election(chg->fcc_votable);
820
821 pval.intval = pl_disable;
822 rc = power_supply_set_property(chg->pl.psy,
823 POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval);
824 if (rc < 0) {
825 dev_err(chg->dev,
826 "Couldn't change slave suspend state rc=%d\n", rc);
827 return rc;
828 }
829
Harry Yang3c4c22d2016-06-15 11:40:54 -0700830 return 0;
831}
832
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -0700833static int smblib_chg_disable_vote_callback(struct votable *votable, void *data,
834 int chg_disable, const char *client)
835{
836 struct smb_charger *chg = data;
837 int rc;
838
839 rc = smblib_masked_write(chg, CHARGING_ENABLE_CMD_REG,
840 CHARGING_ENABLE_CMD_BIT,
841 chg_disable ? 0 : CHARGING_ENABLE_CMD_BIT);
842 if (rc < 0) {
843 dev_err(chg->dev, "Couldn't %s charging rc=%d\n",
844 chg_disable ? "disable" : "enable", rc);
845 return rc;
846 }
847
848 return 0;
849}
Harry Yangaba1f5f2016-09-28 10:47:29 -0700850
851static int smblib_pl_enable_indirect_vote_callback(struct votable *votable,
852 void *data, int chg_enable, const char *client)
853{
854 struct smb_charger *chg = data;
855
856 vote(chg->pl_disable_votable, PL_INDIRECT_VOTER, !chg_enable, 0);
857
858 return 0;
859}
860
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -0700861static int smblib_hvdcp_disable_vote_callback(struct votable *votable,
862 void *data,
863 int hvdcp_disable, const char *client)
864{
865 struct smb_charger *chg = data;
866 int rc;
867 u8 val = HVDCP_AUTH_ALG_EN_CFG_BIT
868 | HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT | HVDCP_EN_BIT;
869
870 /*
871 * Disable the autonomous bit and auth bit for disabling hvdcp.
872 * This ensures only qc 2.0 detection runs but no vbus
873 * negotiation happens.
874 */
875 if (hvdcp_disable)
876 val = HVDCP_EN_BIT;
877
878 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
879 HVDCP_EN_BIT
880 | HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT
881 | HVDCP_AUTH_ALG_EN_CFG_BIT,
882 val);
883 if (rc < 0) {
884 dev_err(chg->dev, "Couldn't %s hvdcp rc=%d\n",
885 hvdcp_disable ? "disable" : "enable", rc);
886 return rc;
887 }
888
889 return 0;
890}
891
Nicholas Troast34db5032016-03-28 12:26:44 -0700892/*****************
893 * OTG REGULATOR *
894 *****************/
895
Harry Yang360bd532016-09-26 11:03:22 -0700896#define OTG_SOFT_START_DELAY_MS 20
Nicholas Troast34db5032016-03-28 12:26:44 -0700897int smblib_vbus_regulator_enable(struct regulator_dev *rdev)
898{
899 struct smb_charger *chg = rdev_get_drvdata(rdev);
Harry Yang360bd532016-09-26 11:03:22 -0700900 u8 stat;
Nicholas Troast34db5032016-03-28 12:26:44 -0700901 int rc = 0;
902
Harry Yang360bd532016-09-26 11:03:22 -0700903 rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
904 ENG_BUCKBOOST_HALT1_8_MODE_BIT,
905 ENG_BUCKBOOST_HALT1_8_MODE_BIT);
906 if (rc < 0) {
907 dev_err(chg->dev, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n",
908 rc);
909 return rc;
910 }
911
912 rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT);
913 if (rc < 0) {
Nicholas Troast34db5032016-03-28 12:26:44 -0700914 dev_err(chg->dev, "Couldn't enable OTG regulator rc=%d\n", rc);
Harry Yang360bd532016-09-26 11:03:22 -0700915 return rc;
916 }
917
918 msleep(OTG_SOFT_START_DELAY_MS);
919 rc = smblib_read(chg, OTG_STATUS_REG, &stat);
920 if (rc < 0) {
921 dev_err(chg->dev, "Couldn't read OTG_STATUS_REG rc=%d\n", rc);
922 return rc;
923 }
924 if (stat & BOOST_SOFTSTART_DONE_BIT)
925 smblib_otg_cl_config(chg, chg->otg_cl_ua);
Nicholas Troast34db5032016-03-28 12:26:44 -0700926
927 return rc;
928}
929
930int smblib_vbus_regulator_disable(struct regulator_dev *rdev)
931{
932 struct smb_charger *chg = rdev_get_drvdata(rdev);
933 int rc = 0;
934
Harry Yang360bd532016-09-26 11:03:22 -0700935 rc = smblib_write(chg, CMD_OTG_REG, 0);
936 if (rc < 0) {
Nicholas Troast34db5032016-03-28 12:26:44 -0700937 dev_err(chg->dev, "Couldn't disable OTG regulator rc=%d\n", rc);
Harry Yang360bd532016-09-26 11:03:22 -0700938 return rc;
939 }
940
941 smblib_otg_cl_config(chg, MICRO_250MA);
942
943 rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
944 ENG_BUCKBOOST_HALT1_8_MODE_BIT, 0);
945 if (rc < 0) {
946 dev_err(chg->dev, "Couldn't set OTG_ENG_OTG_CFG_REG rc=%d\n",
947 rc);
948 return rc;
949 }
950
Nicholas Troast34db5032016-03-28 12:26:44 -0700951
952 return rc;
953}
954
955int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev)
956{
957 struct smb_charger *chg = rdev_get_drvdata(rdev);
958 int rc = 0;
959 u8 cmd;
960
961 rc = smblib_read(chg, CMD_OTG_REG, &cmd);
962 if (rc < 0) {
963 dev_err(chg->dev, "Couldn't read CMD_OTG rc=%d", rc);
964 return rc;
965 }
966
967 return (cmd & OTG_EN_BIT) ? 1 : 0;
968}
969
970/*******************
971 * VCONN REGULATOR *
972 * *****************/
973
974int smblib_vconn_regulator_enable(struct regulator_dev *rdev)
975{
976 struct smb_charger *chg = rdev_get_drvdata(rdev);
Harry Yang88acff42016-09-21 14:56:06 -0700977 u8 stat;
Nicholas Troast34db5032016-03-28 12:26:44 -0700978 int rc = 0;
979
Harry Yang88acff42016-09-21 14:56:06 -0700980 /*
981 * VCONN_EN_ORIENTATION is overloaded with overriding the CC pin used
982 * for Vconn, and it should be set with reverse polarity of CC_OUT.
983 */
984 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
985 if (rc < 0) {
986 dev_err(chg->dev, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
987 return rc;
988 }
989 stat = stat & CC_ORIENTATION_BIT ? 0 : VCONN_EN_ORIENTATION_BIT;
Nicholas Troast34db5032016-03-28 12:26:44 -0700990 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
Harry Yang88acff42016-09-21 14:56:06 -0700991 VCONN_EN_VALUE_BIT | VCONN_EN_ORIENTATION_BIT,
992 VCONN_EN_VALUE_BIT | stat);
Nicholas Troast34db5032016-03-28 12:26:44 -0700993 if (rc < 0)
Harry Yang88acff42016-09-21 14:56:06 -0700994 dev_err(chg->dev, "Couldn't enable vconn setting rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -0700995
996 return rc;
997}
998
999int smblib_vconn_regulator_disable(struct regulator_dev *rdev)
1000{
1001 struct smb_charger *chg = rdev_get_drvdata(rdev);
1002 int rc = 0;
1003
1004 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1005 VCONN_EN_VALUE_BIT, 0);
1006 if (rc < 0)
1007 dev_err(chg->dev, "Couldn't disable vconn regulator rc=%d\n",
1008 rc);
1009
1010 return rc;
1011}
1012
1013int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev)
1014{
1015 struct smb_charger *chg = rdev_get_drvdata(rdev);
1016 int rc = 0;
1017 u8 cmd;
1018
1019 rc = smblib_read(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &cmd);
1020 if (rc < 0) {
1021 dev_err(chg->dev, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
1022 rc);
1023 return rc;
1024 }
1025
1026 return (cmd & VCONN_EN_VALUE_BIT) ? 1 : 0;
1027}
1028
1029/********************
1030 * BATT PSY GETTERS *
1031 ********************/
1032
1033int smblib_get_prop_input_suspend(struct smb_charger *chg,
1034 union power_supply_propval *val)
1035{
Harry Yang7db58c22016-06-27 17:58:51 -07001036 val->intval = get_client_vote(chg->usb_suspend_votable, USER_VOTER) &&
1037 get_client_vote(chg->dc_suspend_votable, USER_VOTER);
Nicholas Troast34db5032016-03-28 12:26:44 -07001038 return 0;
1039}
1040
1041int smblib_get_prop_batt_present(struct smb_charger *chg,
1042 union power_supply_propval *val)
1043{
1044 int rc;
1045 u8 stat;
1046
1047 rc = smblib_read(chg, BATIF_BASE + INT_RT_STS_OFFSET, &stat);
1048 if (rc < 0) {
1049 dev_err(chg->dev, "Couldn't read BATIF_INT_RT_STS rc=%d\n",
1050 rc);
1051 return rc;
1052 }
1053
1054 val->intval = !(stat & (BAT_THERM_OR_ID_MISSING_RT_STS_BIT
1055 | BAT_TERMINAL_MISSING_RT_STS_BIT));
1056
1057 return rc;
1058}
1059
1060int smblib_get_prop_batt_capacity(struct smb_charger *chg,
1061 union power_supply_propval *val)
1062{
Harry Yang5e1a5222016-07-26 15:16:04 -07001063 int rc = -EINVAL;
1064
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07001065 if (chg->fake_capacity >= 0) {
1066 val->intval = chg->fake_capacity;
1067 return 0;
1068 }
1069
Harry Yang5e1a5222016-07-26 15:16:04 -07001070 if (chg->bms_psy)
1071 rc = power_supply_get_property(chg->bms_psy,
1072 POWER_SUPPLY_PROP_CAPACITY, val);
1073 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001074}
1075
1076int smblib_get_prop_batt_status(struct smb_charger *chg,
1077 union power_supply_propval *val)
1078{
Harry Yang7db58c22016-06-27 17:58:51 -07001079 union power_supply_propval pval = {0, };
Nicholas Troast8cb77552016-09-23 11:50:18 -07001080 bool usb_online, dc_online;
1081 u8 stat;
1082 int rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001083
Nicholas Troast8cb77552016-09-23 11:50:18 -07001084 rc = smblib_get_prop_usb_online(chg, &pval);
Harry Yang7db58c22016-06-27 17:58:51 -07001085 if (rc < 0) {
Nicholas Troast8cb77552016-09-23 11:50:18 -07001086 dev_err(chg->dev, "Couldn't get usb online property rc=%d\n",
Harry Yang7db58c22016-06-27 17:58:51 -07001087 rc);
1088 return rc;
1089 }
Nicholas Troast8cb77552016-09-23 11:50:18 -07001090 usb_online = (bool)pval.intval;
Harry Yang7db58c22016-06-27 17:58:51 -07001091
Nicholas Troast8cb77552016-09-23 11:50:18 -07001092 rc = smblib_get_prop_dc_online(chg, &pval);
1093 if (rc < 0) {
1094 dev_err(chg->dev, "Couldn't get dc online property rc=%d\n",
1095 rc);
1096 return rc;
1097 }
1098 dc_online = (bool)pval.intval;
1099
1100 if (!usb_online && !dc_online) {
Nicholas Troast34db5032016-03-28 12:26:44 -07001101 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
1102 return rc;
1103 }
1104
1105 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1106 if (rc < 0) {
1107 dev_err(chg->dev, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
1108 rc);
1109 return rc;
1110 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001111
1112 stat = stat & BATTERY_CHARGER_STATUS_MASK;
Nicholas Troast8cb77552016-09-23 11:50:18 -07001113 switch (stat) {
1114 case TRICKLE_CHARGE:
1115 case PRE_CHARGE:
1116 case FAST_CHARGE:
1117 case FULLON_CHARGE:
1118 case TAPER_CHARGE:
Nicholas Troast34db5032016-03-28 12:26:44 -07001119 val->intval = POWER_SUPPLY_STATUS_CHARGING;
Nicholas Troast8cb77552016-09-23 11:50:18 -07001120 break;
1121 case TERMINATE_CHARGE:
1122 case INHIBIT_CHARGE:
1123 val->intval = POWER_SUPPLY_STATUS_FULL;
1124 break;
1125 case DISABLE_CHARGE:
1126 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
1127 break;
1128 default:
1129 val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
1130 break;
1131 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001132
Nicholas Troast8cb77552016-09-23 11:50:18 -07001133 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07001134}
1135
1136int smblib_get_prop_batt_charge_type(struct smb_charger *chg,
1137 union power_supply_propval *val)
1138{
1139 int rc;
1140 u8 stat;
1141
1142 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1143 if (rc < 0) {
1144 dev_err(chg->dev, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
1145 rc);
1146 return rc;
1147 }
Nicholas Troast34db5032016-03-28 12:26:44 -07001148
1149 switch (stat & BATTERY_CHARGER_STATUS_MASK) {
1150 case TRICKLE_CHARGE:
1151 case PRE_CHARGE:
1152 val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1153 break;
1154 case FAST_CHARGE:
1155 case FULLON_CHARGE:
1156 val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
1157 break;
1158 case TAPER_CHARGE:
1159 val->intval = POWER_SUPPLY_CHARGE_TYPE_TAPER;
1160 break;
1161 default:
1162 val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
1163 }
1164
1165 return rc;
1166}
1167
1168int smblib_get_prop_batt_health(struct smb_charger *chg,
1169 union power_supply_propval *val)
1170{
1171 int rc;
1172 u8 stat;
1173
1174 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat);
1175 if (rc < 0) {
1176 dev_err(chg->dev, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
1177 rc);
1178 return rc;
1179 }
1180 smblib_dbg(chg, PR_REGISTER, "BATTERY_CHARGER_STATUS_2 = 0x%02x\n",
1181 stat);
1182
1183 if (stat & CHARGER_ERROR_STATUS_BAT_OV_BIT) {
1184 dev_err(chg->dev, "battery over-voltage\n");
1185 val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
1186 goto done;
1187 }
1188
Harry Yang668fc5e2016-07-12 16:51:47 -07001189 if (stat & BAT_TEMP_STATUS_TOO_COLD_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001190 val->intval = POWER_SUPPLY_HEALTH_COLD;
Harry Yang668fc5e2016-07-12 16:51:47 -07001191 else if (stat & BAT_TEMP_STATUS_TOO_HOT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001192 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
Harry Yang668fc5e2016-07-12 16:51:47 -07001193 else if (stat & BAT_TEMP_STATUS_COLD_SOFT_LIMIT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001194 val->intval = POWER_SUPPLY_HEALTH_COOL;
Harry Yang668fc5e2016-07-12 16:51:47 -07001195 else if (stat & BAT_TEMP_STATUS_HOT_SOFT_LIMIT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -07001196 val->intval = POWER_SUPPLY_HEALTH_WARM;
Harry Yang668fc5e2016-07-12 16:51:47 -07001197 else
Nicholas Troast34db5032016-03-28 12:26:44 -07001198 val->intval = POWER_SUPPLY_HEALTH_GOOD;
Nicholas Troast34db5032016-03-28 12:26:44 -07001199
1200done:
1201 return rc;
1202}
1203
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001204int smblib_get_prop_system_temp_level(struct smb_charger *chg,
1205 union power_supply_propval *val)
1206{
1207 val->intval = chg->system_temp_level;
1208 return 0;
1209}
1210
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07001211int smblib_get_prop_input_current_limited(struct smb_charger *chg,
1212 union power_supply_propval *val)
1213{
1214 u8 stat;
1215 int rc;
1216
1217 rc = smblib_read(chg, AICL_STATUS_REG, &stat);
1218 if (rc < 0) {
1219 dev_err(chg->dev, "Couldn't read AICL_STATUS rc=%d\n", rc);
1220 return rc;
1221 }
1222 val->intval = (stat & SOFT_ILIMIT_BIT) || chg->is_hdc;
1223 return 0;
1224}
1225
Nicholas Troast66b21d72016-09-20 15:33:20 -07001226int smblib_get_prop_batt_voltage_now(struct smb_charger *chg,
1227 union power_supply_propval *val)
1228{
1229 int rc;
1230
1231 if (!chg->bms_psy)
1232 return -EINVAL;
1233
1234 rc = power_supply_get_property(chg->bms_psy,
1235 POWER_SUPPLY_PROP_VOLTAGE_NOW, val);
1236 return rc;
1237}
1238
1239int smblib_get_prop_batt_current_now(struct smb_charger *chg,
1240 union power_supply_propval *val)
1241{
1242 int rc;
1243
1244 if (!chg->bms_psy)
1245 return -EINVAL;
1246
1247 rc = power_supply_get_property(chg->bms_psy,
1248 POWER_SUPPLY_PROP_CURRENT_NOW, val);
1249 return rc;
1250}
1251
1252int smblib_get_prop_batt_temp(struct smb_charger *chg,
1253 union power_supply_propval *val)
1254{
1255 int rc;
1256
1257 if (!chg->bms_psy)
1258 return -EINVAL;
1259
1260 rc = power_supply_get_property(chg->bms_psy,
1261 POWER_SUPPLY_PROP_TEMP, val);
1262 return rc;
1263}
1264
Harry Yangbedee332016-08-31 16:14:29 -07001265int smblib_get_prop_step_chg_step(struct smb_charger *chg,
1266 union power_supply_propval *val)
1267{
1268 int rc;
1269 u8 stat;
1270
1271 if (!chg->step_chg_enabled) {
1272 val->intval = -1;
1273 return 0;
1274 }
1275
1276 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1277 if (rc < 0) {
1278 dev_err(chg->dev, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
1279 rc);
1280 return rc;
1281 }
1282
1283 val->intval = (stat & STEP_CHARGING_STATUS_MASK) >>
1284 STEP_CHARGING_STATUS_SHIFT;
1285
1286 return rc;
1287}
1288
Subbaraman Narayanamurthyb491d022016-10-10 20:22:48 -07001289int smblib_get_prop_batt_charge_done(struct smb_charger *chg,
1290 union power_supply_propval *val)
1291{
1292 int rc;
1293 u8 stat;
1294
1295 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
1296 if (rc < 0) {
1297 dev_err(chg->dev, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
1298 rc);
1299 return rc;
1300 }
1301
1302 stat = stat & BATTERY_CHARGER_STATUS_MASK;
1303 val->intval = (stat == TERMINATE_CHARGE);
1304 return 0;
1305}
1306
Nicholas Troast34db5032016-03-28 12:26:44 -07001307/***********************
1308 * BATTERY PSY SETTERS *
1309 ***********************/
1310
1311int smblib_set_prop_input_suspend(struct smb_charger *chg,
1312 const union power_supply_propval *val)
1313{
1314 int rc;
1315
1316 rc = vote(chg->usb_suspend_votable, USER_VOTER, (bool)val->intval, 0);
1317 if (rc < 0) {
1318 dev_err(chg->dev, "Couldn't vote to %s USB rc=%d\n",
1319 (bool)val->intval ? "suspend" : "resume", rc);
1320 return rc;
1321 }
1322
1323 rc = vote(chg->dc_suspend_votable, USER_VOTER, (bool)val->intval, 0);
1324 if (rc < 0) {
1325 dev_err(chg->dev, "Couldn't vote to %s DC rc=%d\n",
1326 (bool)val->intval ? "suspend" : "resume", rc);
1327 return rc;
1328 }
1329
Nicholas Troast61ff40f2016-07-08 10:59:22 -07001330 power_supply_changed(chg->batt_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07001331 return rc;
1332}
1333
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07001334int smblib_set_prop_batt_capacity(struct smb_charger *chg,
1335 const union power_supply_propval *val)
1336{
1337 chg->fake_capacity = val->intval;
1338
1339 power_supply_changed(chg->batt_psy);
1340
1341 return 0;
1342}
1343
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001344int smblib_set_prop_system_temp_level(struct smb_charger *chg,
1345 const union power_supply_propval *val)
1346{
1347 if (val->intval < 0)
1348 return -EINVAL;
1349
1350 if (chg->thermal_levels <= 0)
1351 return -EINVAL;
1352
1353 if (val->intval > chg->thermal_levels)
1354 return -EINVAL;
1355
1356 chg->system_temp_level = val->intval;
1357 if (chg->system_temp_level == chg->thermal_levels)
Harry Yangaba1f5f2016-09-28 10:47:29 -07001358 return vote(chg->chg_disable_votable,
1359 THERMAL_DAEMON_VOTER, true, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001360
Harry Yangaba1f5f2016-09-28 10:47:29 -07001361 vote(chg->chg_disable_votable, THERMAL_DAEMON_VOTER, false, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001362 if (chg->system_temp_level == 0)
Harry Yangaba1f5f2016-09-28 10:47:29 -07001363 return vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, false, 0);
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001364
Harry Yangaba1f5f2016-09-28 10:47:29 -07001365 vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, true,
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07001366 chg->thermal_mitigation[chg->system_temp_level]);
1367 return 0;
1368}
1369
Nicholas Troast34db5032016-03-28 12:26:44 -07001370/*******************
Harry Yangf3023592016-07-20 14:56:41 -07001371 * DC PSY GETTERS *
1372 *******************/
1373
1374int smblib_get_prop_dc_present(struct smb_charger *chg,
1375 union power_supply_propval *val)
1376{
1377 int rc = 0;
1378 u8 stat;
1379
1380 rc = smblib_read(chg, DC_INT_RT_STS_REG, &stat);
1381 if (rc < 0) {
1382 dev_err(chg->dev, "Couldn't read DC_INT_RT_STS_REG rc=%d\n",
1383 rc);
1384 return rc;
1385 }
1386 smblib_dbg(chg, PR_REGISTER, "DC_INT_RT_STS_REG = 0x%02x\n",
1387 stat);
1388
1389 val->intval = (bool)(stat & DCIN_PLUGIN_RT_STS_BIT);
1390
1391 return rc;
1392}
1393
1394int smblib_get_prop_dc_online(struct smb_charger *chg,
1395 union power_supply_propval *val)
1396{
1397 int rc = 0;
1398 u8 stat;
1399
1400 if (get_client_vote(chg->dc_suspend_votable, USER_VOTER)) {
1401 val->intval = false;
1402 return rc;
1403 }
1404
1405 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
1406 if (rc < 0) {
1407 dev_err(chg->dev, "Couldn't read POWER_PATH_STATUS rc=%d\n",
1408 rc);
1409 return rc;
1410 }
1411 smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
1412 stat);
1413
1414 val->intval = (stat & USE_DCIN_BIT) &&
1415 (stat & VALID_INPUT_POWER_SOURCE_BIT);
1416
1417 return rc;
1418}
1419
1420int smblib_get_prop_dc_current_max(struct smb_charger *chg,
1421 union power_supply_propval *val)
1422{
1423 val->intval = get_effective_result_locked(chg->dc_icl_votable);
1424 return 0;
1425}
1426
1427/*******************
1428 * USB PSY SETTERS *
1429 * *****************/
1430
1431int smblib_set_prop_dc_current_max(struct smb_charger *chg,
1432 const union power_supply_propval *val)
1433{
1434 int rc;
1435
1436 rc = vote(chg->dc_icl_votable, USER_VOTER, true, val->intval);
1437 return rc;
1438}
1439
1440/*******************
Nicholas Troast34db5032016-03-28 12:26:44 -07001441 * USB PSY GETTERS *
1442 *******************/
1443
1444int smblib_get_prop_usb_present(struct smb_charger *chg,
1445 union power_supply_propval *val)
1446{
1447 int rc = 0;
1448 u8 stat;
1449
1450 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
1451 if (rc < 0) {
1452 dev_err(chg->dev, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
1453 rc);
1454 return rc;
1455 }
1456 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n",
1457 stat);
1458
1459 val->intval = (bool)(stat & CC_ATTACHED_BIT);
1460
1461 return rc;
1462}
1463
1464int smblib_get_prop_usb_online(struct smb_charger *chg,
1465 union power_supply_propval *val)
1466{
1467 int rc = 0;
1468 u8 stat;
1469
1470 if (get_client_vote(chg->usb_suspend_votable, USER_VOTER)) {
1471 val->intval = false;
1472 return rc;
1473 }
1474
1475 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
1476 if (rc < 0) {
1477 dev_err(chg->dev, "Couldn't read POWER_PATH_STATUS rc=%d\n",
1478 rc);
1479 return rc;
1480 }
1481 smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
1482 stat);
1483
1484 val->intval = (stat & USE_USBIN_BIT) &&
1485 (stat & VALID_INPUT_POWER_SOURCE_BIT);
Nicholas Troast34db5032016-03-28 12:26:44 -07001486 return rc;
1487}
1488
1489int smblib_get_prop_usb_voltage_now(struct smb_charger *chg,
1490 union power_supply_propval *val)
1491{
Harry Yangba874ce2016-08-19 14:17:01 -07001492 int rc = 0;
Nicholas Troast34db5032016-03-28 12:26:44 -07001493
Harry Yangba874ce2016-08-19 14:17:01 -07001494 rc = smblib_get_prop_usb_present(chg, val);
1495 if (rc < 0 || !val->intval)
1496 return rc;
1497
1498 if (!chg->iio.usbin_v_chan ||
1499 PTR_ERR(chg->iio.usbin_v_chan) == -EPROBE_DEFER)
1500 chg->iio.usbin_v_chan = iio_channel_get(chg->dev, "usbin_v");
1501
1502 if (IS_ERR(chg->iio.usbin_v_chan))
1503 return PTR_ERR(chg->iio.usbin_v_chan);
1504
1505 return iio_read_channel_processed(chg->iio.usbin_v_chan, &val->intval);
Nicholas Troast34db5032016-03-28 12:26:44 -07001506}
1507
1508int smblib_get_prop_usb_current_max(struct smb_charger *chg,
1509 union power_supply_propval *val)
1510{
1511 val->intval = get_effective_result_locked(chg->usb_icl_votable);
1512 return 0;
1513}
1514
Harry Yangba874ce2016-08-19 14:17:01 -07001515int smblib_get_prop_usb_current_now(struct smb_charger *chg,
1516 union power_supply_propval *val)
1517{
1518 int rc = 0;
1519
1520 rc = smblib_get_prop_usb_present(chg, val);
1521 if (rc < 0 || !val->intval)
1522 return rc;
1523
1524 if (!chg->iio.usbin_i_chan ||
1525 PTR_ERR(chg->iio.usbin_i_chan) == -EPROBE_DEFER)
1526 chg->iio.usbin_i_chan = iio_channel_get(chg->dev, "usbin_i");
1527
1528 if (IS_ERR(chg->iio.usbin_i_chan))
1529 return PTR_ERR(chg->iio.usbin_i_chan);
1530
1531 return iio_read_channel_processed(chg->iio.usbin_i_chan, &val->intval);
1532}
1533
1534int smblib_get_prop_charger_temp(struct smb_charger *chg,
1535 union power_supply_propval *val)
1536{
1537 int rc;
1538
1539 if (!chg->iio.temp_chan ||
1540 PTR_ERR(chg->iio.temp_chan) == -EPROBE_DEFER)
1541 chg->iio.temp_chan = iio_channel_get(chg->dev, "charger_temp");
1542
1543 if (IS_ERR(chg->iio.temp_chan))
1544 return PTR_ERR(chg->iio.temp_chan);
1545
1546 rc = iio_read_channel_processed(chg->iio.temp_chan, &val->intval);
1547 val->intval /= 100;
1548 return rc;
1549}
1550
1551int smblib_get_prop_charger_temp_max(struct smb_charger *chg,
1552 union power_supply_propval *val)
1553{
1554 int rc;
1555
1556 if (!chg->iio.temp_max_chan ||
1557 PTR_ERR(chg->iio.temp_max_chan) == -EPROBE_DEFER)
1558 chg->iio.temp_max_chan = iio_channel_get(chg->dev,
1559 "charger_temp_max");
1560 if (IS_ERR(chg->iio.temp_max_chan))
1561 return PTR_ERR(chg->iio.temp_max_chan);
1562
1563 rc = iio_read_channel_processed(chg->iio.temp_max_chan, &val->intval);
1564 val->intval /= 100;
1565 return rc;
1566}
1567
Nicholas Troast34db5032016-03-28 12:26:44 -07001568int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
1569 union power_supply_propval *val)
1570{
1571 int rc = 0;
1572 u8 stat;
1573
1574 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
1575 if (rc < 0) {
1576 dev_err(chg->dev, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
1577 rc);
1578 return rc;
1579 }
1580 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n",
1581 stat);
1582
1583 if (stat & CC_ATTACHED_BIT)
1584 val->intval = (bool)(stat & CC_ORIENTATION_BIT) + 1;
1585 else
1586 val->intval = 0;
1587
1588 return rc;
1589}
1590
1591static const char * const smblib_typec_mode_name[] = {
1592 [POWER_SUPPLY_TYPEC_NONE] = "NONE",
1593 [POWER_SUPPLY_TYPEC_SOURCE_DEFAULT] = "SOURCE_DEFAULT",
1594 [POWER_SUPPLY_TYPEC_SOURCE_MEDIUM] = "SOURCE_MEDIUM",
1595 [POWER_SUPPLY_TYPEC_SOURCE_HIGH] = "SOURCE_HIGH",
1596 [POWER_SUPPLY_TYPEC_NON_COMPLIANT] = "NON_COMPLIANT",
1597 [POWER_SUPPLY_TYPEC_SINK] = "SINK",
1598 [POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE] = "SINK_POWERED_CABLE",
1599 [POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY] = "SINK_DEBUG_ACCESSORY",
1600 [POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER] = "SINK_AUDIO_ADAPTER",
1601 [POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY] = "POWERED_CABLE_ONLY",
1602};
1603
1604static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
1605{
1606 int rc;
1607 u8 stat;
1608
1609 rc = smblib_read(chg, TYPE_C_STATUS_1_REG, &stat);
1610 if (rc < 0) {
1611 dev_err(chg->dev, "Couldn't read TYPE_C_STATUS_1 rc=%d\n", rc);
1612 return POWER_SUPPLY_TYPEC_NONE;
1613 }
1614 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_1 = 0x%02x\n", stat);
1615
1616 switch (stat) {
1617 case 0:
1618 return POWER_SUPPLY_TYPEC_NONE;
1619 case UFP_TYPEC_RDSTD_BIT:
1620 return POWER_SUPPLY_TYPEC_SOURCE_DEFAULT;
1621 case UFP_TYPEC_RD1P5_BIT:
1622 return POWER_SUPPLY_TYPEC_SOURCE_MEDIUM;
1623 case UFP_TYPEC_RD3P0_BIT:
1624 return POWER_SUPPLY_TYPEC_SOURCE_HIGH;
1625 default:
1626 break;
1627 }
1628
1629 return POWER_SUPPLY_TYPEC_NON_COMPLIANT;
1630}
1631
1632static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
1633{
1634 int rc;
1635 u8 stat;
1636
1637 rc = smblib_read(chg, TYPE_C_STATUS_2_REG, &stat);
1638 if (rc < 0) {
1639 dev_err(chg->dev, "Couldn't read TYPE_C_STATUS_2 rc=%d\n", rc);
1640 return POWER_SUPPLY_TYPEC_NONE;
1641 }
1642 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_2 = 0x%02x\n", stat);
1643
1644 switch (stat & DFP_TYPEC_MASK) {
1645 case DFP_RA_RA_BIT:
1646 return POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER;
1647 case DFP_RD_RD_BIT:
1648 return POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY;
1649 case DFP_RD_RA_VCONN_BIT:
1650 return POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE;
1651 case DFP_RD_OPEN_BIT:
1652 return POWER_SUPPLY_TYPEC_SINK;
1653 case DFP_RA_OPEN_BIT:
1654 return POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY;
1655 default:
1656 break;
1657 }
1658
1659 return POWER_SUPPLY_TYPEC_NONE;
1660}
1661
1662int smblib_get_prop_typec_mode(struct smb_charger *chg,
1663 union power_supply_propval *val)
1664{
1665 int rc;
1666 u8 stat;
1667
1668 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
1669 if (rc < 0) {
1670 dev_err(chg->dev, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
1671 val->intval = POWER_SUPPLY_TYPEC_NONE;
1672 return rc;
1673 }
1674 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat);
1675
1676 if (!(stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT)) {
1677 val->intval = POWER_SUPPLY_TYPEC_NONE;
1678 return rc;
1679 }
1680
1681 if (stat & UFP_DFP_MODE_STATUS_BIT)
1682 val->intval = smblib_get_prop_dfp_mode(chg);
1683 else
1684 val->intval = smblib_get_prop_ufp_mode(chg);
1685
1686 return rc;
1687}
1688
1689int smblib_get_prop_typec_power_role(struct smb_charger *chg,
1690 union power_supply_propval *val)
1691{
1692 int rc = 0;
1693 u8 ctrl;
1694
1695 rc = smblib_read(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &ctrl);
1696 if (rc < 0) {
1697 dev_err(chg->dev, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
1698 rc);
1699 return rc;
1700 }
1701 smblib_dbg(chg, PR_REGISTER, "TYPE_C_INTRPT_ENB_SOFTWARE_CTRL = 0x%02x\n",
1702 ctrl);
1703
1704 if (ctrl & TYPEC_DISABLE_CMD_BIT) {
1705 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
1706 return rc;
1707 }
1708
1709 switch (ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT)) {
1710 case 0:
1711 val->intval = POWER_SUPPLY_TYPEC_PR_DUAL;
1712 break;
1713 case DFP_EN_CMD_BIT:
1714 val->intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
1715 break;
1716 case UFP_EN_CMD_BIT:
1717 val->intval = POWER_SUPPLY_TYPEC_PR_SINK;
1718 break;
1719 default:
1720 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
1721 dev_err(chg->dev, "unsupported power role 0x%02lx\n",
1722 ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT));
1723 return -EINVAL;
1724 }
1725
1726 return rc;
1727}
1728
1729int smblib_get_prop_pd_allowed(struct smb_charger *chg,
1730 union power_supply_propval *val)
1731{
1732 val->intval = get_effective_result_locked(chg->pd_allowed_votable);
1733 return 0;
1734}
1735
Nicholas Troast133a7f52016-06-29 13:48:20 -07001736int smblib_get_prop_input_current_settled(struct smb_charger *chg,
1737 union power_supply_propval *val)
1738{
1739 return smblib_get_charge_param(chg, &chg->param.icl_stat, &val->intval);
1740}
1741
Nicholas Troast34db5032016-03-28 12:26:44 -07001742/*******************
1743 * USB PSY SETTERS *
1744 * *****************/
1745
1746int smblib_set_prop_usb_current_max(struct smb_charger *chg,
1747 const union power_supply_propval *val)
1748{
1749 int rc;
1750
1751 rc = vote(chg->usb_icl_votable, PD_VOTER, true, val->intval);
1752 return rc;
1753}
1754
1755int smblib_set_prop_typec_power_role(struct smb_charger *chg,
1756 const union power_supply_propval *val)
1757{
1758 int rc = 0;
1759 u8 power_role;
1760
1761 switch (val->intval) {
1762 case POWER_SUPPLY_TYPEC_PR_NONE:
1763 power_role = TYPEC_DISABLE_CMD_BIT;
1764 break;
1765 case POWER_SUPPLY_TYPEC_PR_DUAL:
1766 power_role = 0;
1767 break;
1768 case POWER_SUPPLY_TYPEC_PR_SINK:
1769 power_role = UFP_EN_CMD_BIT;
1770 break;
1771 case POWER_SUPPLY_TYPEC_PR_SOURCE:
1772 power_role = DFP_EN_CMD_BIT;
1773 break;
1774 default:
1775 dev_err(chg->dev, "power role %d not supported\n", val->intval);
1776 return -EINVAL;
1777 }
1778
1779 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1780 TYPEC_POWER_ROLE_CMD_MASK, power_role);
1781 if (rc < 0) {
1782 dev_err(chg->dev, "Couldn't write 0x%02x to TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
1783 power_role, rc);
1784 return rc;
1785 }
1786
1787 return rc;
1788}
1789
1790int smblib_set_prop_usb_voltage_min(struct smb_charger *chg,
1791 const union power_supply_propval *val)
1792{
1793 int rc, min_uv;
1794
1795 min_uv = min(val->intval, chg->voltage_max_uv);
1796 rc = smblib_set_usb_pd_allowed_voltage(chg, min_uv,
1797 chg->voltage_max_uv);
1798 if (rc < 0) {
1799 dev_err(chg->dev, "invalid max voltage %duV rc=%d\n",
1800 val->intval, rc);
1801 return rc;
1802 }
1803
Harry Yangaba1f5f2016-09-28 10:47:29 -07001804 if (chg->mode == PARALLEL_MASTER)
1805 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER,
1806 min_uv > MICRO_5V, 0);
1807
1808 chg->voltage_min_uv = min_uv;
Nicholas Troast34db5032016-03-28 12:26:44 -07001809 return rc;
1810}
1811
1812int smblib_set_prop_usb_voltage_max(struct smb_charger *chg,
1813 const union power_supply_propval *val)
1814{
1815 int rc, max_uv;
1816
1817 max_uv = max(val->intval, chg->voltage_min_uv);
1818 rc = smblib_set_usb_pd_allowed_voltage(chg, chg->voltage_min_uv,
1819 max_uv);
1820 if (rc < 0) {
1821 dev_err(chg->dev, "invalid min voltage %duV rc=%d\n",
1822 val->intval, rc);
1823 return rc;
1824 }
1825
Harry Yangaba1f5f2016-09-28 10:47:29 -07001826 chg->voltage_max_uv = max_uv;
Nicholas Troast34db5032016-03-28 12:26:44 -07001827 return rc;
1828}
1829
1830int smblib_set_prop_pd_active(struct smb_charger *chg,
1831 const union power_supply_propval *val)
1832{
1833 int rc;
Harry Yang88acff42016-09-21 14:56:06 -07001834 u8 stat;
Nicholas Troast34db5032016-03-28 12:26:44 -07001835
1836 if (!get_effective_result(chg->pd_allowed_votable)) {
1837 dev_err(chg->dev, "PD is not allowed\n");
1838 return -EINVAL;
1839 }
1840
1841 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1842 AUTO_SRC_DETECT_BIT,
1843 val->intval ? 0 : AUTO_SRC_DETECT_BIT);
1844 if (rc < 0) {
1845 dev_err(chg->dev, "Couldn't %s APSD rc=%d\n",
1846 val->intval ? "disable" : "enable", rc);
1847 return rc;
1848 }
1849
1850 vote(chg->pd_allowed_votable, PD_VOTER, val->intval, 0);
1851
Harry Yang88acff42016-09-21 14:56:06 -07001852 /*
1853 * VCONN_EN_ORIENTATION_BIT controls whether to use CC1 or CC2 line
1854 * when TYPEC_SPARE_CFG_BIT (CC pin selection s/w override) is set
1855 * or when VCONN_EN_VALUE_BIT is set.
1856 */
1857 if (val->intval) {
1858 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
1859 if (rc < 0) {
1860 dev_err(chg->dev,
1861 "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
1862 rc);
1863 return rc;
1864 }
1865
1866 stat &= CC_ORIENTATION_BIT;
1867 rc = smblib_masked_write(chg,
1868 TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1869 VCONN_EN_ORIENTATION_BIT,
1870 stat ? 0 : VCONN_EN_ORIENTATION_BIT);
1871 if (rc < 0)
1872 dev_err(chg->dev,
1873 "Couldn't enable vconn on CC line rc=%d\n", rc);
1874 }
1875
1876 /* CC pin selection s/w override in PD session; h/w otherwise. */
1877 rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
1878 TYPEC_SPARE_CFG_BIT,
1879 val->intval ? TYPEC_SPARE_CFG_BIT : 0);
1880 if (rc < 0) {
1881 dev_err(chg->dev, "Couldn't change cc_out ctrl to %s rc=%d\n",
1882 val->intval ? "SW" : "HW", rc);
1883 return rc;
1884 }
1885
Nicholas Troast34db5032016-03-28 12:26:44 -07001886 chg->pd_active = (bool)val->intval;
Harry Yang6607b4a2016-05-17 17:50:09 -07001887 smblib_update_usb_type(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07001888 return rc;
1889}
1890
Nicholas Troast7dbcad22016-10-05 13:30:18 -07001891/************************
1892 * PARALLEL PSY GETTERS *
1893 ************************/
1894
1895int smblib_get_prop_slave_current_now(struct smb_charger *chg,
1896 union power_supply_propval *pval)
1897{
1898 if (IS_ERR_OR_NULL(chg->iio.batt_i_chan))
1899 chg->iio.batt_i_chan = iio_channel_get(chg->dev, "batt_i");
1900
1901 if (IS_ERR(chg->iio.batt_i_chan))
1902 return PTR_ERR(chg->iio.batt_i_chan);
1903
1904 return iio_read_channel_processed(chg->iio.batt_i_chan, &pval->intval);
1905}
1906
Nicholas Troast34db5032016-03-28 12:26:44 -07001907/**********************
1908 * INTERRUPT HANDLERS *
1909 **********************/
1910
1911irqreturn_t smblib_handle_debug(int irq, void *data)
1912{
1913 struct smb_irq_data *irq_data = data;
1914 struct smb_charger *chg = irq_data->parent_data;
1915
1916 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07001917 return IRQ_HANDLED;
1918}
1919
Nicholas Troast8cb77552016-09-23 11:50:18 -07001920static void smblib_pl_handle_chg_state_change(struct smb_charger *chg, u8 stat)
1921{
1922 bool pl_enabled;
1923
1924 if (chg->mode != PARALLEL_MASTER)
1925 return;
1926
1927 pl_enabled = !get_effective_result_locked(chg->pl_disable_votable);
1928 switch (stat) {
1929 case FAST_CHARGE:
1930 case FULLON_CHARGE:
1931 vote(chg->pl_disable_votable, CHG_STATE_VOTER, false, 0);
1932 break;
1933 case TAPER_CHARGE:
1934 if (pl_enabled) {
1935 cancel_delayed_work_sync(&chg->pl_taper_work);
1936 schedule_delayed_work(&chg->pl_taper_work, 0);
1937 }
1938 break;
1939 case TERMINATE_CHARGE:
1940 case INHIBIT_CHARGE:
1941 case DISABLE_CHARGE:
1942 vote(chg->pl_disable_votable, TAPER_END_VOTER, false, 0);
1943 break;
1944 default:
1945 break;
1946 }
1947}
1948
Harry Yang6fe72ab2016-06-14 16:21:39 -07001949irqreturn_t smblib_handle_chg_state_change(int irq, void *data)
1950{
1951 struct smb_irq_data *irq_data = data;
1952 struct smb_charger *chg = irq_data->parent_data;
Nicholas Troast8cb77552016-09-23 11:50:18 -07001953 u8 stat;
Harry Yang1d1034c2016-06-15 12:09:42 -07001954 int rc;
Harry Yang6fe72ab2016-06-14 16:21:39 -07001955
1956 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
1957
Nicholas Troast8cb77552016-09-23 11:50:18 -07001958 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
Harry Yang1d1034c2016-06-15 12:09:42 -07001959 if (rc < 0) {
Nicholas Troast8cb77552016-09-23 11:50:18 -07001960 dev_err(chg->dev, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
1961 rc);
Harry Yang1d1034c2016-06-15 12:09:42 -07001962 return IRQ_HANDLED;
1963 }
1964
Nicholas Troast8cb77552016-09-23 11:50:18 -07001965 stat = stat & BATTERY_CHARGER_STATUS_MASK;
1966 smblib_pl_handle_chg_state_change(chg, stat);
1967 power_supply_changed(chg->batt_psy);
Harry Yang6fe72ab2016-06-14 16:21:39 -07001968 return IRQ_HANDLED;
1969}
1970
Harry Yangfe913842016-08-10 12:27:28 -07001971irqreturn_t smblib_handle_step_chg_state_change(int irq, void *data)
1972{
1973 struct smb_irq_data *irq_data = data;
1974 struct smb_charger *chg = irq_data->parent_data;
1975
1976 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
1977
1978 if (chg->step_chg_enabled)
1979 rerun_election(chg->fcc_votable);
1980
1981 return IRQ_HANDLED;
1982}
1983
1984irqreturn_t smblib_handle_step_chg_soc_update_fail(int irq, void *data)
1985{
1986 struct smb_irq_data *irq_data = data;
1987 struct smb_charger *chg = irq_data->parent_data;
1988
1989 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
1990
1991 if (chg->step_chg_enabled)
1992 rerun_election(chg->fcc_votable);
1993
1994 return IRQ_HANDLED;
1995}
1996
1997#define STEP_SOC_REQ_MS 3000
1998irqreturn_t smblib_handle_step_chg_soc_update_request(int irq, void *data)
1999{
2000 struct smb_irq_data *irq_data = data;
2001 struct smb_charger *chg = irq_data->parent_data;
2002 int rc;
2003 union power_supply_propval pval = {0, };
2004
2005 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
2006
2007 if (!chg->bms_psy) {
2008 schedule_delayed_work(&chg->step_soc_req_work,
2009 msecs_to_jiffies(STEP_SOC_REQ_MS));
2010 return IRQ_HANDLED;
2011 }
2012
2013 rc = smblib_get_prop_batt_capacity(chg, &pval);
2014 if (rc < 0)
2015 dev_err(chg->dev, "Couldn't get batt capacity rc=%d\n", rc);
2016 else
2017 step_charge_soc_update(chg, pval.intval);
2018
2019 return IRQ_HANDLED;
2020}
2021
Abhijeet Dharmapurikar2644cd62016-07-20 16:54:55 -07002022irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data)
2023{
2024 struct smb_irq_data *irq_data = data;
2025 struct smb_charger *chg = irq_data->parent_data;
2026
2027 rerun_election(chg->fcc_votable);
2028 power_supply_changed(chg->batt_psy);
2029 return IRQ_HANDLED;
2030}
2031
Nicholas Troast34db5032016-03-28 12:26:44 -07002032irqreturn_t smblib_handle_batt_psy_changed(int irq, void *data)
2033{
2034 struct smb_irq_data *irq_data = data;
2035 struct smb_charger *chg = irq_data->parent_data;
2036
Nicholas Troast47ae4612016-08-03 09:49:36 -07002037 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07002038 power_supply_changed(chg->batt_psy);
2039 return IRQ_HANDLED;
2040}
2041
2042irqreturn_t smblib_handle_usb_psy_changed(int irq, void *data)
2043{
2044 struct smb_irq_data *irq_data = data;
2045 struct smb_charger *chg = irq_data->parent_data;
2046
Nicholas Troast47ae4612016-08-03 09:49:36 -07002047 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
Nicholas Troast34db5032016-03-28 12:26:44 -07002048 power_supply_changed(chg->usb_psy);
2049 return IRQ_HANDLED;
2050}
2051
2052irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
2053{
2054 struct smb_irq_data *irq_data = data;
2055 struct smb_charger *chg = irq_data->parent_data;
2056 int rc;
2057 u8 stat;
2058
Nicholas Troast34db5032016-03-28 12:26:44 -07002059 /* fetch the DPDM regulator */
2060 if (!chg->dpdm_reg && of_get_property(chg->dev->of_node,
2061 "dpdm-supply", NULL)) {
2062 chg->dpdm_reg = devm_regulator_get(chg->dev, "dpdm");
2063 if (IS_ERR(chg->dpdm_reg)) {
2064 dev_err(chg->dev, "Couldn't get dpdm regulator rc=%ld\n",
2065 PTR_ERR(chg->dpdm_reg));
2066 chg->dpdm_reg = NULL;
2067 }
2068 }
2069
2070 if (!chg->dpdm_reg)
2071 goto skip_dpdm_float;
2072
Abhijeet Dharmapurikar17288f22016-07-05 14:03:31 -07002073 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
2074 if (rc < 0) {
2075 dev_err(chg->dev, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
2076 return IRQ_HANDLED;
2077 }
2078
2079 chg->vbus_present = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
2080
2081 if (chg->vbus_present) {
2082 if (!regulator_is_enabled(chg->dpdm_reg)) {
2083 smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n");
2084 rc = regulator_enable(chg->dpdm_reg);
2085 if (rc < 0)
2086 dev_err(chg->dev, "Couldn't enable dpdm regulator rc=%d\n",
2087 rc);
2088 }
2089 } else {
2090 if (regulator_is_enabled(chg->dpdm_reg)) {
2091 smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n");
2092 rc = regulator_disable(chg->dpdm_reg);
2093 if (rc < 0)
2094 dev_err(chg->dev, "Couldn't disable dpdm regulator rc=%d\n",
2095 rc);
2096 }
Nicholas Troast34db5032016-03-28 12:26:44 -07002097 }
2098
2099skip_dpdm_float:
Nicholas Troast62d86622016-09-22 11:41:33 -07002100 power_supply_changed(chg->usb_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07002101 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n",
2102 irq_data->name, chg->vbus_present ? "attached" : "detached");
2103 return IRQ_HANDLED;
2104}
2105
Harry Yangaba1f5f2016-09-28 10:47:29 -07002106#define USB_WEAK_INPUT_MA 1400000
Harry Yang6fe72ab2016-06-14 16:21:39 -07002107irqreturn_t smblib_handle_icl_change(int irq, void *data)
2108{
2109 struct smb_irq_data *irq_data = data;
2110 struct smb_charger *chg = irq_data->parent_data;
Harry Yangaba1f5f2016-09-28 10:47:29 -07002111 int icl_ma;
2112 int rc;
2113
2114 rc = smblib_get_charge_param(chg, &chg->param.icl_stat, &icl_ma);
2115 if (rc < 0) {
2116 dev_err(chg->dev, "Couldn't get ICL status rc=%d\n", rc);
2117 return IRQ_HANDLED;
2118 }
Harry Yang6fe72ab2016-06-14 16:21:39 -07002119
Harry Yang1d1034c2016-06-15 12:09:42 -07002120 if (chg->mode == PARALLEL_MASTER)
Harry Yangaba1f5f2016-09-28 10:47:29 -07002121 vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER,
2122 icl_ma >= USB_WEAK_INPUT_MA, 0);
Harry Yang1d1034c2016-06-15 12:09:42 -07002123
Harry Yang6fe72ab2016-06-14 16:21:39 -07002124 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
2125
2126 return IRQ_HANDLED;
2127}
2128
Nicholas Troast34db5032016-03-28 12:26:44 -07002129static void smblib_handle_slow_plugin_timeout(struct smb_charger *chg,
2130 bool rising)
2131{
2132 smblib_dbg(chg, PR_INTERRUPT, "IRQ: slow-plugin-timeout %s\n",
2133 rising ? "rising" : "falling");
2134}
2135
2136static void smblib_handle_sdp_enumeration_done(struct smb_charger *chg,
2137 bool rising)
2138{
2139 smblib_dbg(chg, PR_INTERRUPT, "IRQ: sdp-enumeration-done %s\n",
2140 rising ? "rising" : "falling");
2141}
2142
2143static void smblib_handle_adaptive_voltage_done(struct smb_charger *chg,
2144 bool rising)
2145{
2146 smblib_dbg(chg, PR_INTERRUPT, "IRQ: adaptive-voltage-done %s\n",
2147 rising ? "rising" : "falling");
2148}
2149
2150/* triggers when HVDCP 3.0 authentication has finished */
2151static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
2152 bool rising)
2153{
2154 const struct apsd_result *apsd_result;
2155
2156 if (!rising)
2157 return;
2158
Harry Yangaba1f5f2016-09-28 10:47:29 -07002159 if (chg->mode == PARALLEL_MASTER)
2160 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0);
2161
Nicholas Troast34db5032016-03-28 12:26:44 -07002162 /* the APSD done handler will set the USB supply type */
2163 apsd_result = smblib_get_apsd_result(chg);
2164 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n",
2165 apsd_result->name);
2166}
2167
Harry Yang1369b7a2016-09-27 15:59:50 -07002168static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
2169 bool rising, bool qc_charger)
2170{
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07002171 /* Hold off PD only until hvdcp 2.0 detection timeout */
2172 if (rising)
2173 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
2174 false, 0);
Harry Yang1369b7a2016-09-27 15:59:50 -07002175
2176 smblib_dbg(chg, PR_INTERRUPT, "IRQ: smblib_handle_hvdcp_check_timeout %s\n",
2177 rising ? "rising" : "falling");
2178}
2179
Nicholas Troast34db5032016-03-28 12:26:44 -07002180/* triggers when HVDCP is detected */
2181static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg,
2182 bool rising)
2183{
2184 if (!rising)
2185 return;
2186
2187 /* the APSD done handler will set the USB supply type */
2188 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
2189 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-detect-done %s\n",
2190 rising ? "rising" : "falling");
2191}
2192
2193#define HVDCP_DET_MS 2500
2194static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
2195{
2196 int rc;
2197 const struct apsd_result *apsd_result;
2198
2199 if (!rising)
2200 return;
2201
2202 apsd_result = smblib_get_apsd_result(chg);
2203 switch (apsd_result->bit) {
2204 case SDP_CHARGER_BIT:
2205 case CDP_CHARGER_BIT:
2206 case OCP_CHARGER_BIT:
2207 case FLOAT_CHARGER_BIT:
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07002208 /* if not DCP then no hvdcp timeout happens. Enable pd here */
2209 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
2210 false, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07002211 break;
2212 case DCP_CHARGER_BIT:
Harry Yang1369b7a2016-09-27 15:59:50 -07002213 if (chg->wa_flags & QC_CHARGER_DETECTION_WA_BIT)
2214 schedule_delayed_work(&chg->hvdcp_detect_work,
2215 msecs_to_jiffies(HVDCP_DET_MS));
Nicholas Troast34db5032016-03-28 12:26:44 -07002216 break;
2217 default:
2218 break;
2219 }
2220
2221 rc = smblib_update_usb_type(chg);
2222 if (rc < 0)
2223 dev_err(chg->dev, "Couldn't update usb type rc=%d\n", rc);
2224
2225 smblib_dbg(chg, PR_INTERRUPT, "IRQ: apsd-done rising; %s detected\n",
2226 apsd_result->name);
2227}
2228
2229irqreturn_t smblib_handle_usb_source_change(int irq, void *data)
2230{
2231 struct smb_irq_data *irq_data = data;
2232 struct smb_charger *chg = irq_data->parent_data;
2233 int rc = 0;
2234 u8 stat;
2235
2236 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
2237 if (rc < 0) {
2238 dev_err(chg->dev, "Couldn't read APSD_STATUS rc=%d\n", rc);
2239 return IRQ_HANDLED;
2240 }
2241 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
2242
2243 smblib_handle_apsd_done(chg,
2244 (bool)(stat & APSD_DTC_STATUS_DONE_BIT));
2245
2246 smblib_handle_hvdcp_detect_done(chg,
2247 (bool)(stat & QC_CHARGER_BIT));
2248
Harry Yang1369b7a2016-09-27 15:59:50 -07002249 smblib_handle_hvdcp_check_timeout(chg,
2250 (bool)(stat & HVDCP_CHECK_TIMEOUT_BIT),
2251 (bool)(stat & QC_CHARGER_BIT));
2252
Nicholas Troast34db5032016-03-28 12:26:44 -07002253 smblib_handle_hvdcp_3p0_auth_done(chg,
2254 (bool)(stat & QC_AUTH_DONE_STATUS_BIT));
2255
2256 smblib_handle_adaptive_voltage_done(chg,
2257 (bool)(stat & VADP_CHANGE_DONE_AFTER_AUTH_BIT));
2258
2259 smblib_handle_sdp_enumeration_done(chg,
2260 (bool)(stat & ENUMERATION_DONE_BIT));
2261
2262 smblib_handle_slow_plugin_timeout(chg,
2263 (bool)(stat & SLOW_PLUGIN_TIMEOUT_BIT));
2264
2265 power_supply_changed(chg->usb_psy);
2266
2267 return IRQ_HANDLED;
2268}
2269
2270static void smblib_handle_typec_cc(struct smb_charger *chg, bool attached)
2271{
2272 int rc;
2273
2274 if (!attached) {
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07002275 rc = smblib_detach_typec(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07002276 if (rc < 0)
2277 dev_err(chg->dev, "Couldn't detach USB rc=%d\n", rc);
2278 }
2279
2280 smblib_dbg(chg, PR_INTERRUPT, "IRQ: CC %s\n",
2281 attached ? "attached" : "detached");
2282}
2283
2284static void smblib_handle_typec_debounce_done(struct smb_charger *chg,
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07002285 bool attached, bool rising, bool sink_attached)
Nicholas Troast34db5032016-03-28 12:26:44 -07002286{
2287 int rc;
2288 union power_supply_propval pval = {0, };
2289
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07002290 /* allow PD when cc is attached and debounced */
2291 if (attached && rising)
2292 vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER,
2293 false, 0);
Nicholas Troast34db5032016-03-28 12:26:44 -07002294
2295 rc = smblib_get_prop_typec_mode(chg, &pval);
2296 if (rc < 0)
2297 dev_err(chg->dev, "Couldn't get prop typec mode rc=%d\n", rc);
2298
Harry Yang1d1034c2016-06-15 12:09:42 -07002299 /*
2300 * vote to enable parallel charging if a source is attached, and disable
2301 * otherwise
2302 */
2303 vote(chg->pl_disable_votable, TYPEC_SRC_VOTER,
2304 !rising || sink_attached, 0);
2305
Harry Yangf6564732016-08-03 09:47:08 -07002306 if (!rising || sink_attached) {
Harry Yangaba1f5f2016-09-28 10:47:29 -07002307 /* reset both usbin current and voltage votes */
2308 vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
2309 vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
Harry Yangf6564732016-08-03 09:47:08 -07002310 /* reset taper_end voter here */
Harry Yang1d1034c2016-06-15 12:09:42 -07002311 vote(chg->pl_disable_votable, TAPER_END_VOTER, false, 0);
Harry Yangf6564732016-08-03 09:47:08 -07002312 }
Harry Yang1d1034c2016-06-15 12:09:42 -07002313
Nicholas Troast34db5032016-03-28 12:26:44 -07002314 smblib_dbg(chg, PR_INTERRUPT, "IRQ: debounce-done %s; Type-C %s detected\n",
2315 rising ? "rising" : "falling",
2316 smblib_typec_mode_name[pval.intval]);
2317}
2318
2319irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
2320{
2321 struct smb_irq_data *irq_data = data;
2322 struct smb_charger *chg = irq_data->parent_data;
2323 int rc;
2324 u8 stat;
2325
2326 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
2327 if (rc < 0) {
2328 dev_err(chg->dev, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
2329 rc);
2330 return IRQ_HANDLED;
2331 }
2332 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat);
2333
Nicholas Troast34db5032016-03-28 12:26:44 -07002334 smblib_handle_typec_cc(chg,
2335 (bool)(stat & CC_ATTACHED_BIT));
2336 smblib_handle_typec_debounce_done(chg,
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07002337 (bool)(stat & CC_ATTACHED_BIT),
Nicholas Troast34db5032016-03-28 12:26:44 -07002338 (bool)(stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT),
2339 (bool)(stat & UFP_DFP_MODE_STATUS_BIT));
2340
2341 power_supply_changed(chg->usb_psy);
2342
Harry Yangd757c0f2016-09-23 10:52:05 -07002343 if (stat & TYPEC_VBUS_ERROR_STATUS_BIT)
2344 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s vbus-error\n",
2345 irq_data->name);
2346
Nicholas Troast34db5032016-03-28 12:26:44 -07002347 return IRQ_HANDLED;
2348}
2349
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07002350irqreturn_t smblib_handle_high_duty_cycle(int irq, void *data)
2351{
2352 struct smb_irq_data *irq_data = data;
2353 struct smb_charger *chg = irq_data->parent_data;
2354
2355 chg->is_hdc = true;
2356 schedule_delayed_work(&chg->clear_hdc_work, msecs_to_jiffies(60));
2357
2358 return IRQ_HANDLED;
2359}
2360
Nicholas Troast34db5032016-03-28 12:26:44 -07002361/***************
2362 * Work Queues *
2363 ***************/
2364
2365static void smblib_hvdcp_detect_work(struct work_struct *work)
2366{
2367 struct smb_charger *chg = container_of(work, struct smb_charger,
2368 hvdcp_detect_work.work);
Nicholas Troast34db5032016-03-28 12:26:44 -07002369
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07002370 vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
2371 false, 0);
2372 power_supply_changed(chg->usb_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -07002373}
2374
Harry Yangfe913842016-08-10 12:27:28 -07002375static void bms_update_work(struct work_struct *work)
Harry Yang5e1a5222016-07-26 15:16:04 -07002376{
2377 struct smb_charger *chg = container_of(work, struct smb_charger,
2378 bms_update_work);
2379 power_supply_changed(chg->batt_psy);
2380}
2381
Harry Yangfe913842016-08-10 12:27:28 -07002382static void step_soc_req_work(struct work_struct *work)
2383{
2384 struct smb_charger *chg = container_of(work, struct smb_charger,
2385 step_soc_req_work.work);
2386 union power_supply_propval pval = {0, };
2387 int rc;
2388
2389 rc = smblib_get_prop_batt_capacity(chg, &pval);
2390 if (rc < 0) {
2391 dev_err(chg->dev, "Couldn't get batt capacity rc=%d\n", rc);
2392 return;
2393 }
2394
2395 step_charge_soc_update(chg, pval.intval);
2396}
2397
Harry Yang58a9e7a2016-06-23 14:54:43 -07002398static void smblib_pl_detect_work(struct work_struct *work)
2399{
2400 struct smb_charger *chg = container_of(work, struct smb_charger,
2401 pl_detect_work);
2402
Harry Yang995b7422016-08-29 16:06:50 -07002403 vote(chg->pl_disable_votable, PARALLEL_PSY_VOTER, false, 0);
Harry Yang58a9e7a2016-06-23 14:54:43 -07002404}
2405
Harry Yang1d1034c2016-06-15 12:09:42 -07002406#define MINIMUM_PARALLEL_FCC_UA 500000
2407#define PL_TAPER_WORK_DELAY_MS 100
2408#define TAPER_RESIDUAL_PERCENT 75
2409static void smblib_pl_taper_work(struct work_struct *work)
2410{
2411 struct smb_charger *chg = container_of(work, struct smb_charger,
2412 pl_taper_work.work);
2413 union power_supply_propval pval = {0, };
2414 int rc;
2415
2416 if (chg->pl.slave_fcc < MINIMUM_PARALLEL_FCC_UA) {
2417 vote(chg->pl_disable_votable, TAPER_END_VOTER, true, 0);
2418 goto done;
2419 }
2420
2421 rc = smblib_get_prop_batt_charge_type(chg, &pval);
2422 if (rc < 0) {
2423 dev_err(chg->dev, "Couldn't get batt charge type rc=%d\n", rc);
2424 goto done;
2425 }
2426
2427 if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER) {
Harry Yang995b7422016-08-29 16:06:50 -07002428 vote(chg->awake_votable, PL_TAPER_WORK_RUNNING_VOTER, true, 0);
Harry Yang1d1034c2016-06-15 12:09:42 -07002429 /* Reduce the taper percent by 25 percent */
2430 chg->pl.taper_percent = chg->pl.taper_percent
2431 * TAPER_RESIDUAL_PERCENT / 100;
2432 rerun_election(chg->fcc_votable);
2433 schedule_delayed_work(&chg->pl_taper_work,
2434 msecs_to_jiffies(PL_TAPER_WORK_DELAY_MS));
2435 return;
2436 }
2437
2438 /*
2439 * Master back to Fast Charge, get out of this round of taper reduction
2440 */
2441done:
Harry Yang995b7422016-08-29 16:06:50 -07002442 vote(chg->awake_votable, PL_TAPER_WORK_RUNNING_VOTER, false, 0);
Harry Yang1d1034c2016-06-15 12:09:42 -07002443}
2444
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07002445static void clear_hdc_work(struct work_struct *work)
2446{
2447 struct smb_charger *chg = container_of(work, struct smb_charger,
2448 clear_hdc_work.work);
2449
2450 chg->is_hdc = 0;
2451}
2452
Harry Yangba874ce2016-08-19 14:17:01 -07002453static int smblib_create_votables(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07002454{
2455 int rc = 0;
2456
Abhijeet Dharmapurikare65cb1d2016-08-24 12:29:50 -07002457 chg->usb_suspend_votable = create_votable("USB_SUSPEND", VOTE_SET_ANY,
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07002458 smblib_usb_suspend_vote_callback,
2459 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07002460 if (IS_ERR(chg->usb_suspend_votable)) {
2461 rc = PTR_ERR(chg->usb_suspend_votable);
2462 return rc;
2463 }
2464
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07002465 chg->dc_suspend_votable = create_votable("DC_SUSPEND", VOTE_SET_ANY,
2466 smblib_dc_suspend_vote_callback,
2467 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07002468 if (IS_ERR(chg->dc_suspend_votable)) {
2469 rc = PTR_ERR(chg->dc_suspend_votable);
2470 return rc;
2471 }
2472
Abhijeet Dharmapurikar99fb8942016-07-08 11:39:23 -07002473 chg->fcc_max_votable = create_votable("FCC_MAX", VOTE_MAX,
2474 smblib_fcc_max_vote_callback,
2475 chg);
2476 if (IS_ERR(chg->fcc_max_votable)) {
2477 rc = PTR_ERR(chg->fcc_max_votable);
2478 return rc;
2479 }
2480
2481 chg->fcc_votable = create_votable("FCC", VOTE_MIN,
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07002482 smblib_fcc_vote_callback,
2483 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07002484 if (IS_ERR(chg->fcc_votable)) {
2485 rc = PTR_ERR(chg->fcc_votable);
2486 return rc;
2487 }
2488
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07002489 chg->fv_votable = create_votable("FV", VOTE_MAX,
2490 smblib_fv_vote_callback,
2491 chg);
Abhijeet Dharmapurikarf9805d42016-05-17 18:38:42 -07002492 if (IS_ERR(chg->fv_votable)) {
2493 rc = PTR_ERR(chg->fv_votable);
2494 return rc;
2495 }
2496
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07002497 chg->usb_icl_votable = create_votable("USB_ICL", VOTE_MIN,
2498 smblib_usb_icl_vote_callback,
2499 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07002500 if (IS_ERR(chg->usb_icl_votable)) {
2501 rc = PTR_ERR(chg->usb_icl_votable);
2502 return rc;
2503 }
2504
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07002505 chg->dc_icl_votable = create_votable("DC_ICL", VOTE_MIN,
2506 smblib_dc_icl_vote_callback,
2507 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07002508 if (IS_ERR(chg->dc_icl_votable)) {
2509 rc = PTR_ERR(chg->dc_icl_votable);
2510 return rc;
2511 }
2512
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07002513 chg->pd_disallowed_votable_indirect
2514 = create_votable("PD_DISALLOWED_INDIRECT", VOTE_SET_ANY,
2515 smblib_pd_disallowed_votable_indirect_callback, chg);
2516 if (IS_ERR(chg->pd_disallowed_votable_indirect)) {
2517 rc = PTR_ERR(chg->pd_disallowed_votable_indirect);
2518 return rc;
2519 }
2520
2521 chg->pd_allowed_votable = create_votable("PD_ALLOWED",
2522 VOTE_SET_ANY, NULL, NULL);
Nicholas Troast34db5032016-03-28 12:26:44 -07002523 if (IS_ERR(chg->pd_allowed_votable)) {
2524 rc = PTR_ERR(chg->pd_allowed_votable);
2525 return rc;
2526 }
2527
Harry Yang223c6282016-06-14 15:48:36 -07002528 chg->awake_votable = create_votable("AWAKE", VOTE_SET_ANY,
2529 smblib_awake_vote_callback,
2530 chg);
2531 if (IS_ERR(chg->awake_votable)) {
2532 rc = PTR_ERR(chg->awake_votable);
2533 return rc;
2534 }
2535
Harry Yang3c4c22d2016-06-15 11:40:54 -07002536 chg->pl_disable_votable = create_votable("PL_DISABLE", VOTE_SET_ANY,
2537 smblib_pl_disable_vote_callback,
2538 chg);
2539 if (IS_ERR(chg->pl_disable_votable)) {
2540 rc = PTR_ERR(chg->pl_disable_votable);
2541 return rc;
2542 }
2543
Abhijeet Dharmapurikaree54de02016-07-08 14:51:47 -07002544 chg->chg_disable_votable = create_votable("CHG_DISABLE", VOTE_SET_ANY,
2545 smblib_chg_disable_vote_callback,
2546 chg);
2547 if (IS_ERR(chg->chg_disable_votable)) {
2548 rc = PTR_ERR(chg->chg_disable_votable);
2549 return rc;
2550 }
2551
Harry Yangaba1f5f2016-09-28 10:47:29 -07002552 chg->pl_enable_votable_indirect = create_votable("PL_ENABLE_INDIRECT",
2553 VOTE_SET_ANY,
2554 smblib_pl_enable_indirect_vote_callback,
2555 chg);
2556 if (IS_ERR(chg->pl_enable_votable_indirect)) {
2557 rc = PTR_ERR(chg->pl_enable_votable_indirect);
2558 return rc;
2559 }
2560
Abhijeet Dharmapurikarf0b0a042016-10-10 16:43:43 -07002561 chg->hvdcp_disable_votable = create_votable("HVDCP_DISABLE",
2562 VOTE_SET_ANY,
2563 smblib_hvdcp_disable_vote_callback,
2564 chg);
2565 if (IS_ERR(chg->hvdcp_disable_votable)) {
2566 rc = PTR_ERR(chg->hvdcp_disable_votable);
2567 return rc;
2568 }
Nicholas Troast320839e2016-06-03 10:18:00 -07002569 return rc;
2570}
2571
Harry Yangba874ce2016-08-19 14:17:01 -07002572static void smblib_destroy_votables(struct smb_charger *chg)
2573{
2574 if (chg->usb_suspend_votable)
2575 destroy_votable(chg->usb_suspend_votable);
2576 if (chg->dc_suspend_votable)
2577 destroy_votable(chg->dc_suspend_votable);
2578 if (chg->fcc_max_votable)
2579 destroy_votable(chg->fcc_max_votable);
2580 if (chg->fcc_votable)
2581 destroy_votable(chg->fcc_votable);
2582 if (chg->fv_votable)
2583 destroy_votable(chg->fv_votable);
2584 if (chg->usb_icl_votable)
2585 destroy_votable(chg->usb_icl_votable);
2586 if (chg->dc_icl_votable)
2587 destroy_votable(chg->dc_icl_votable);
Abhijeet Dharmapurikar4b13c6e2016-10-05 15:15:10 -07002588 if (chg->pd_disallowed_votable_indirect)
2589 destroy_votable(chg->pd_disallowed_votable_indirect);
Harry Yangba874ce2016-08-19 14:17:01 -07002590 if (chg->pd_allowed_votable)
2591 destroy_votable(chg->pd_allowed_votable);
2592 if (chg->awake_votable)
2593 destroy_votable(chg->awake_votable);
2594 if (chg->pl_disable_votable)
2595 destroy_votable(chg->pl_disable_votable);
Harry Yangaba1f5f2016-09-28 10:47:29 -07002596 if (chg->chg_disable_votable)
2597 destroy_votable(chg->chg_disable_votable);
2598 if (chg->pl_enable_votable_indirect)
2599 destroy_votable(chg->pl_enable_votable_indirect);
Harry Yangba874ce2016-08-19 14:17:01 -07002600}
2601
2602static void smblib_iio_deinit(struct smb_charger *chg)
2603{
2604 if (!IS_ERR_OR_NULL(chg->iio.temp_chan))
2605 iio_channel_release(chg->iio.temp_chan);
2606 if (!IS_ERR_OR_NULL(chg->iio.temp_max_chan))
2607 iio_channel_release(chg->iio.temp_max_chan);
2608 if (!IS_ERR_OR_NULL(chg->iio.usbin_i_chan))
2609 iio_channel_release(chg->iio.usbin_i_chan);
2610 if (!IS_ERR_OR_NULL(chg->iio.usbin_v_chan))
2611 iio_channel_release(chg->iio.usbin_v_chan);
Nicholas Troast7dbcad22016-10-05 13:30:18 -07002612 if (!IS_ERR_OR_NULL(chg->iio.batt_i_chan))
2613 iio_channel_release(chg->iio.batt_i_chan);
Harry Yangba874ce2016-08-19 14:17:01 -07002614}
2615
Nicholas Troast320839e2016-06-03 10:18:00 -07002616int smblib_init(struct smb_charger *chg)
2617{
2618 int rc = 0;
2619
2620 mutex_init(&chg->write_lock);
Harry Yangfe913842016-08-10 12:27:28 -07002621 INIT_WORK(&chg->bms_update_work, bms_update_work);
Harry Yang58a9e7a2016-06-23 14:54:43 -07002622 INIT_WORK(&chg->pl_detect_work, smblib_pl_detect_work);
Nicholas Troast320839e2016-06-03 10:18:00 -07002623 INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work);
Harry Yang1d1034c2016-06-15 12:09:42 -07002624 INIT_DELAYED_WORK(&chg->pl_taper_work, smblib_pl_taper_work);
Harry Yangfe913842016-08-10 12:27:28 -07002625 INIT_DELAYED_WORK(&chg->step_soc_req_work, step_soc_req_work);
Abhijeet Dharmapurikar0e369002016-09-07 17:25:36 -07002626 INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work);
Abhijeet Dharmapurikar9e7e48c2016-08-23 12:55:49 -07002627 chg->fake_capacity = -EINVAL;
Nicholas Troast320839e2016-06-03 10:18:00 -07002628
2629 switch (chg->mode) {
2630 case PARALLEL_MASTER:
2631 rc = smblib_create_votables(chg);
2632 if (rc < 0) {
2633 dev_err(chg->dev, "Couldn't create votables rc=%d\n",
2634 rc);
Harry Yang58a9e7a2016-06-23 14:54:43 -07002635 return rc;
Nicholas Troast320839e2016-06-03 10:18:00 -07002636 }
Harry Yang58a9e7a2016-06-23 14:54:43 -07002637
Harry Yang5e1a5222016-07-26 15:16:04 -07002638 rc = smblib_register_notifier(chg);
2639 if (rc < 0) {
2640 dev_err(chg->dev,
2641 "Couldn't register notifier rc=%d\n", rc);
2642 return rc;
Harry Yang58a9e7a2016-06-23 14:54:43 -07002643 }
2644
Harry Yang995b7422016-08-29 16:06:50 -07002645 chg->bms_psy = power_supply_get_by_name("bms");
2646 chg->pl.psy = power_supply_get_by_name("parallel");
2647 if (chg->pl.psy)
2648 vote(chg->pl_disable_votable, PARALLEL_PSY_VOTER,
2649 false, 0);
2650
Nicholas Troast320839e2016-06-03 10:18:00 -07002651 break;
2652 case PARALLEL_SLAVE:
2653 break;
2654 default:
2655 dev_err(chg->dev, "Unsupported mode %d\n", chg->mode);
2656 return -EINVAL;
2657 }
2658
2659 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07002660}
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07002661
2662int smblib_deinit(struct smb_charger *chg)
2663{
Harry Yangba874ce2016-08-19 14:17:01 -07002664 switch (chg->mode) {
2665 case PARALLEL_MASTER:
2666 power_supply_unreg_notifier(&chg->nb);
2667 smblib_destroy_votables(chg);
2668 break;
2669 case PARALLEL_SLAVE:
2670 break;
2671 default:
2672 dev_err(chg->dev, "Unsupported mode %d\n", chg->mode);
2673 return -EINVAL;
2674 }
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07002675
Harry Yangba874ce2016-08-19 14:17:01 -07002676 smblib_iio_deinit(chg);
Harry Yang5e1a5222016-07-26 15:16:04 -07002677
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07002678 return 0;
2679}