blob: a62b047a06e14910c3ed819303b4f0ecd36ace61 [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>
15#include <linux/power_supply.h>
16#include <linux/regulator/driver.h>
17#include <linux/irq.h>
18#include "smb-lib.h"
19#include "smb-reg.h"
20#include "pmic-voter.h"
21
22#define smblib_dbg(chg, reason, fmt, ...) \
23 do { \
24 if (*chg->debug_mask & (reason)) \
25 dev_info(chg->dev, fmt, ##__VA_ARGS__); \
26 else \
27 dev_dbg(chg->dev, fmt, ##__VA_ARGS__); \
28 } while (0)
29
30static bool is_secure(struct smb_charger *chg, int addr)
31{
32 /* assume everything above 0xC0 is secure */
33 return (bool)(addr >= 0xC0);
34}
35
36int smblib_read(struct smb_charger *chg, u16 addr, u8 *val)
37{
38 unsigned int temp;
39 int rc = 0;
40
41 rc = regmap_read(chg->regmap, addr, &temp);
42 if (rc >= 0)
43 *val = (u8)temp;
44
45 return rc;
46}
47
48int smblib_masked_write(struct smb_charger *chg, u16 addr, u8 mask, u8 val)
49{
Nicholas Troast34db5032016-03-28 12:26:44 -070050 int rc = 0;
51
Harry Yangbacd2222016-05-11 16:43:51 -070052 mutex_lock(&chg->write_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -070053 if (is_secure(chg, addr)) {
54 rc = regmap_write(chg->regmap, (addr & 0xFF00) | 0xD0, 0xA5);
55 if (rc < 0)
56 goto unlock;
57 }
58
59 rc = regmap_update_bits(chg->regmap, addr, mask, val);
60
61unlock:
Harry Yangbacd2222016-05-11 16:43:51 -070062 mutex_unlock(&chg->write_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -070063 return rc;
64}
65
66int smblib_write(struct smb_charger *chg, u16 addr, u8 val)
67{
Nicholas Troast34db5032016-03-28 12:26:44 -070068 int rc = 0;
69
Harry Yangbacd2222016-05-11 16:43:51 -070070 mutex_lock(&chg->write_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -070071
72 if (is_secure(chg, addr)) {
73 rc = regmap_write(chg->regmap, (addr & ~(0xFF)) | 0xD0, 0xA5);
74 if (rc < 0)
75 goto unlock;
76 }
77
78 rc = regmap_write(chg->regmap, addr, val);
79
80unlock:
Harry Yangbacd2222016-05-11 16:43:51 -070081 mutex_unlock(&chg->write_lock);
Nicholas Troast34db5032016-03-28 12:26:44 -070082 return rc;
83}
84
Harry Yang1d1034c2016-06-15 12:09:42 -070085static void smblib_fcc_split_ua(struct smb_charger *chg, int total_fcc,
86 int *master_ua, int *slave_ua)
87{
88 int master_percent = min(max(*chg->pl.master_percent, 0), 100);
89
90 *master_ua = (total_fcc * master_percent) / 100;
91 *slave_ua = (total_fcc - *master_ua) * chg->pl.taper_percent / 100;
92}
93
Nicholas Troast34db5032016-03-28 12:26:44 -070094/********************
95 * REGISTER GETTERS *
96 ********************/
97
Nicholas Troast4c310492016-05-12 17:56:35 -070098int smblib_get_charge_param(struct smb_charger *chg,
99 struct smb_chg_param *param, int *val_u)
100{
101 int rc = 0;
102 u8 val_raw;
103
104 rc = smblib_read(chg, param->reg, &val_raw);
105 if (rc < 0) {
106 dev_err(chg->dev, "%s: Couldn't read from 0x%04x rc=%d\n",
107 param->name, param->reg, rc);
108 return rc;
109 }
110
111 *val_u = val_raw * param->step_u + param->min_u;
112 smblib_dbg(chg, PR_REGISTER, "%s = %d (0x%02x)\n",
113 param->name, *val_u, val_raw);
114
115 return rc;
116}
117
118int smblib_get_usb_suspend(struct smb_charger *chg, int *suspend)
119{
120 int rc = 0;
121 u8 temp;
122
123 rc = smblib_read(chg, USBIN_CMD_IL_REG, &temp);
124 if (rc < 0) {
125 dev_err(chg->dev, "Couldn't read USBIN_CMD_IL rc=%d\n", rc);
126 return rc;
127 }
128 *suspend = temp & USBIN_SUSPEND_BIT;
129
130 return rc;
131}
132
Nicholas Troast34db5032016-03-28 12:26:44 -0700133struct apsd_result {
134 const char * const name;
135 const u8 bit;
136 const enum power_supply_type pst;
137};
138
139static const struct apsd_result const smblib_apsd_results[] = {
140 {"UNKNOWN", 0, POWER_SUPPLY_TYPE_UNKNOWN},
141 {"SDP", SDP_CHARGER_BIT, POWER_SUPPLY_TYPE_USB},
142 {"CDP", CDP_CHARGER_BIT, POWER_SUPPLY_TYPE_USB_CDP},
143 {"DCP", DCP_CHARGER_BIT, POWER_SUPPLY_TYPE_USB_DCP},
144 {"OCP", OCP_CHARGER_BIT, POWER_SUPPLY_TYPE_USB_DCP},
145 {"FLOAT", FLOAT_CHARGER_BIT, POWER_SUPPLY_TYPE_USB_DCP},
146 {"HVDCP2", DCP_CHARGER_BIT | QC_2P0_BIT, POWER_SUPPLY_TYPE_USB_HVDCP},
147 {"HVDCP3", DCP_CHARGER_BIT | QC_3P0_BIT, POWER_SUPPLY_TYPE_USB_HVDCP_3},
148};
149
150static const struct apsd_result *smblib_get_apsd_result(struct smb_charger *chg)
151{
152 int rc, i;
153 u8 stat;
154
155 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
156 if (rc < 0) {
157 dev_err(chg->dev, "Couldn't read APSD_STATUS rc=%d\n", rc);
158 return &smblib_apsd_results[0];
159 }
160 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
161
162 if (!(stat & APSD_DTC_STATUS_DONE_BIT))
163 return &smblib_apsd_results[0];
164
165 rc = smblib_read(chg, APSD_RESULT_STATUS_REG, &stat);
166 if (rc < 0) {
167 dev_err(chg->dev, "Couldn't read APSD_RESULT_STATUS rc=%d\n",
168 rc);
169 return &smblib_apsd_results[0];
170 }
171 stat &= APSD_RESULT_STATUS_MASK;
172
173 for (i = 0; i < ARRAY_SIZE(smblib_apsd_results); i++) {
174 if (smblib_apsd_results[i].bit == stat)
175 return &smblib_apsd_results[i];
176 }
177
178 dev_err(chg->dev, "Couldn't find an APSD result for 0x%02x\n", stat);
179 return &smblib_apsd_results[0];
180}
181
182
183/********************
184 * REGISTER SETTERS *
185 ********************/
186
187int smblib_enable_charging(struct smb_charger *chg, bool enable)
188{
189 int rc = 0;
190
191 rc = smblib_masked_write(chg, CHARGING_ENABLE_CMD_REG,
192 CHARGING_ENABLE_CMD_BIT,
193 enable ? CHARGING_ENABLE_CMD_BIT : 0);
194 if (rc < 0) {
195 dev_err(chg->dev, "Couldn't %s charging rc=%d\n",
196 enable ? "enable" : "disable", rc);
197 return rc;
198 }
199
200 return rc;
201}
202
Nicholas Troast4c310492016-05-12 17:56:35 -0700203int smblib_set_charge_param(struct smb_charger *chg,
204 struct smb_chg_param *param, int val_u)
Nicholas Troast34db5032016-03-28 12:26:44 -0700205{
206 int rc = 0;
207 u8 val_raw;
208
209 if (val_u > param->max_u || val_u < param->min_u) {
210 dev_err(chg->dev, "%s: %d is out of range [%d, %d]\n",
211 param->name, val_u, param->min_u, param->max_u);
212 return -EINVAL;
213 }
214
215 val_raw = (val_u - param->min_u) / param->step_u;
216 rc = smblib_write(chg, param->reg, val_raw);
217 if (rc < 0) {
218 dev_err(chg->dev, "%s: Couldn't write 0x%02x to 0x%04x rc=%d\n",
219 param->name, val_raw, param->reg, rc);
220 return rc;
221 }
222
223 smblib_dbg(chg, PR_REGISTER, "%s = %d (0x%02x)\n",
224 param->name, val_u, val_raw);
225
226 return rc;
227}
228
Nicholas Troast4c310492016-05-12 17:56:35 -0700229int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend)
Nicholas Troast34db5032016-03-28 12:26:44 -0700230{
231 int rc = 0;
232
233 rc = smblib_masked_write(chg, USBIN_CMD_IL_REG, USBIN_SUSPEND_BIT,
234 suspend ? USBIN_SUSPEND_BIT : 0);
235 if (rc < 0)
236 dev_err(chg->dev, "Couldn't write %s to USBIN_SUSPEND_BIT rc=%d\n",
237 suspend ? "suspend" : "resume", rc);
238
239 return rc;
240}
241
Nicholas Troast4c310492016-05-12 17:56:35 -0700242int smblib_set_dc_suspend(struct smb_charger *chg, bool suspend)
Nicholas Troast34db5032016-03-28 12:26:44 -0700243{
244 int rc = 0;
245
246 rc = smblib_masked_write(chg, DCIN_CMD_IL_REG, DCIN_SUSPEND_BIT,
247 suspend ? DCIN_SUSPEND_BIT : 0);
248 if (rc < 0)
249 dev_err(chg->dev, "Couldn't write %s to DCIN_SUSPEND_BIT rc=%d\n",
250 suspend ? "suspend" : "resume", rc);
251
252 return rc;
253}
254
255#define MICRO_5V 5000000
256#define MICRO_9V 9000000
257#define MICRO_12V 12000000
258static int smblib_set_usb_pd_allowed_voltage(struct smb_charger *chg,
259 int min_allowed_uv, int max_allowed_uv)
260{
261 int rc;
262 u8 allowed_voltage;
263
264 if (min_allowed_uv == MICRO_5V && max_allowed_uv == MICRO_5V) {
265 allowed_voltage = USBIN_ADAPTER_ALLOW_5V;
266 } else if (min_allowed_uv == MICRO_9V && max_allowed_uv == MICRO_9V) {
267 allowed_voltage = USBIN_ADAPTER_ALLOW_9V;
268 } else if (min_allowed_uv == MICRO_12V && max_allowed_uv == MICRO_12V) {
269 allowed_voltage = USBIN_ADAPTER_ALLOW_12V;
270 } else if (min_allowed_uv < MICRO_9V && max_allowed_uv <= MICRO_9V) {
271 allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_9V;
272 } else if (min_allowed_uv < MICRO_9V && max_allowed_uv <= MICRO_12V) {
273 allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_12V;
274 } else if (min_allowed_uv < MICRO_12V && max_allowed_uv <= MICRO_12V) {
275 allowed_voltage = USBIN_ADAPTER_ALLOW_9V_TO_12V;
276 } else {
277 dev_err(chg->dev, "invalid allowed voltage [%d, %d]\n",
278 min_allowed_uv, max_allowed_uv);
279 return -EINVAL;
280 }
281
282 rc = smblib_write(chg, USBIN_ADAPTER_ALLOW_CFG_REG, allowed_voltage);
283 if (rc < 0) {
284 dev_err(chg->dev, "Couldn't write 0x%02x to USBIN_ADAPTER_ALLOW_CFG rc=%d\n",
285 allowed_voltage, rc);
286 return rc;
287 }
288
289 return rc;
290}
291
292/********************
293 * HELPER FUNCTIONS *
294 ********************/
295
296static int smblib_update_usb_type(struct smb_charger *chg)
297{
298 int rc = 0;
299 const struct apsd_result *apsd_result;
300
Jack Pham9696e252016-05-23 11:15:15 -0700301 /* if PD is active, APSD is disabled so won't have a valid result */
302 if (chg->pd_active)
Nicholas Troast34db5032016-03-28 12:26:44 -0700303 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -0700304
305 apsd_result = smblib_get_apsd_result(chg);
306 chg->usb_psy_desc.type = apsd_result->pst;
307 return rc;
308}
309
310static int smblib_detach_usb(struct smb_charger *chg)
311{
312 int rc;
313
314 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
Jack Pham9696e252016-05-23 11:15:15 -0700315 chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_UNKNOWN;
Nicholas Troast34db5032016-03-28 12:26:44 -0700316
317 /* reconfigure allowed voltage for HVDCP */
318 rc = smblib_write(chg, USBIN_ADAPTER_ALLOW_CFG_REG,
319 USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
320 if (rc < 0) {
321 dev_err(chg->dev, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
322 rc);
323 return rc;
324 }
325
326 chg->voltage_min_uv = MICRO_5V;
327 chg->voltage_max_uv = MICRO_5V;
328
329 /* clear USB ICL vote for PD_VOTER */
330 rc = vote(chg->usb_icl_votable, PD_VOTER, false, 0);
331 if (rc < 0) {
332 dev_err(chg->dev, "Couldn't vote for USB ICL rc=%d\n",
333 rc);
334 return rc;
335 }
336
337 vote(chg->pd_allowed_votable, DEFAULT_VOTER, false, 0);
338
339 return rc;
340}
341
Harry Yang1d1034c2016-06-15 12:09:42 -0700342static struct power_supply *get_parallel_psy(struct smb_charger *chg)
343{
344 if (chg->pl.psy)
345 return chg->pl.psy;
346
347 chg->pl.psy = power_supply_get_by_name("parallel");
348 if (!chg->pl.psy)
349 smblib_dbg(chg, PR_MISC, "parallel charger not found\n");
350
351 return chg->pl.psy;
352}
353
Nicholas Troast34db5032016-03-28 12:26:44 -0700354/*********************
355 * VOTABLE CALLBACKS *
356 *********************/
357
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700358static int smblib_usb_suspend_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -0700359 int suspend, const char *client)
Nicholas Troast34db5032016-03-28 12:26:44 -0700360{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700361 struct smb_charger *chg = data;
Nicholas Troast34db5032016-03-28 12:26:44 -0700362
363 return smblib_set_usb_suspend(chg, suspend);
364}
365
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700366static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -0700367 int suspend, const char *client)
Nicholas Troast34db5032016-03-28 12:26:44 -0700368{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700369 struct smb_charger *chg = data;
Nicholas Troast34db5032016-03-28 12:26:44 -0700370
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700371 if (suspend < 0)
372 suspend = false;
373
Nicholas Troast34db5032016-03-28 12:26:44 -0700374 return smblib_set_dc_suspend(chg, suspend);
375}
376
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700377static int smblib_fcc_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -0700378 int fcc_ua, const char *client)
Nicholas Troast34db5032016-03-28 12:26:44 -0700379{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700380 struct smb_charger *chg = data;
Nicholas Troast34db5032016-03-28 12:26:44 -0700381 int rc = 0;
Harry Yang1d1034c2016-06-15 12:09:42 -0700382 union power_supply_propval pval = {0, };
383 int master_ua = fcc_ua, slave_ua;
Nicholas Troast34db5032016-03-28 12:26:44 -0700384
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700385 if (fcc_ua < 0) {
386 smblib_dbg(chg, PR_MISC, "No Voter\n");
387 return 0;
388 }
389
Harry Yang1d1034c2016-06-15 12:09:42 -0700390 if (chg->mode == PARALLEL_MASTER
391 && !get_effective_result_locked(chg->pl_disable_votable)) {
392 smblib_fcc_split_ua(chg, fcc_ua, &master_ua, &slave_ua);
393
394 /*
395 * parallel charger is not disabled, implying that
396 * chg->pl.psy exists
397 */
398 pval.intval = slave_ua;
399 rc = power_supply_set_property(chg->pl.psy,
400 POWER_SUPPLY_PROP_CURRENT_MAX, &pval);
401 if (rc < 0) {
402 dev_err(chg->dev, "Could not set parallel fcc, rc=%d\n",
403 rc);
404 return rc;
405 }
406
407 chg->pl.slave_fcc = slave_ua;
408 }
409
410 rc = smblib_set_charge_param(chg, &chg->param.fcc, master_ua);
411 if (rc < 0) {
412 dev_err(chg->dev, "Error in setting fcc, rc=%d\n", rc);
413 return rc;
414 }
415
416 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -0700417}
418
Harry Yang1d1034c2016-06-15 12:09:42 -0700419#define PARALLEL_FLOAT_VOLTAGE_DELTA_UV 50000
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700420static int smblib_fv_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -0700421 int fv_uv, const char *client)
Abhijeet Dharmapurikarf9805d42016-05-17 18:38:42 -0700422{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700423 struct smb_charger *chg = data;
Harry Yang1d1034c2016-06-15 12:09:42 -0700424 union power_supply_propval pval = {0, };
Abhijeet Dharmapurikarf9805d42016-05-17 18:38:42 -0700425 int rc = 0;
426
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700427 if (fv_uv < 0) {
428 smblib_dbg(chg, PR_MISC, "No Voter\n");
429 return 0;
430 }
431
Abhijeet Dharmapurikarf9805d42016-05-17 18:38:42 -0700432 rc = smblib_set_charge_param(chg, &chg->param.fv, fv_uv);
Harry Yang1d1034c2016-06-15 12:09:42 -0700433 if (rc < 0) {
434 dev_err(chg->dev,
435 "Couldn't set floating voltage rc=%d\n", rc);
436 return rc;
437 }
438
439 if (chg->mode == PARALLEL_MASTER && get_parallel_psy(chg)) {
440 pval.intval = fv_uv + PARALLEL_FLOAT_VOLTAGE_DELTA_UV;
441 rc = power_supply_set_property(chg->pl.psy,
442 POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval);
443 if (rc < 0) {
444 dev_err(chg->dev,
445 "Couldn't set float on parallel rc=%d\n", rc);
446 return rc;
447 }
448 }
449
450 return 0;
Abhijeet Dharmapurikarf9805d42016-05-17 18:38:42 -0700451}
452
Nicholas Troast34db5032016-03-28 12:26:44 -0700453#define USBIN_25MA 25000
454#define USBIN_100MA 100000
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700455static int smblib_usb_icl_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -0700456 int icl_ua, const char *client)
Nicholas Troast34db5032016-03-28 12:26:44 -0700457{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700458 struct smb_charger *chg = data;
Nicholas Troast34db5032016-03-28 12:26:44 -0700459 int rc = 0;
460 bool suspend;
461
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700462 if (icl_ua < 0) {
463 smblib_dbg(chg, PR_MISC, "No Voter hence suspending\n");
464 icl_ua = 0;
465 }
466
Nicholas Troast34db5032016-03-28 12:26:44 -0700467 suspend = (icl_ua < USBIN_25MA);
468 if (suspend)
469 goto suspend;
470
471 if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)
472 rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
473 USB51_MODE_BIT,
474 (icl_ua > USBIN_100MA) ? USB51_MODE_BIT : 0);
475 else
476 rc = smblib_set_charge_param(chg, &chg->param.usb_icl, icl_ua);
477
478 if (rc < 0) {
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700479 dev_err(chg->dev,
480 "Couldn't set USB input current limit rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -0700481 return rc;
482 }
483
484suspend:
485 rc = vote(chg->usb_suspend_votable, PD_VOTER, suspend, 0);
486 if (rc < 0) {
487 dev_err(chg->dev, "Couldn't %s input rc=%d\n",
488 suspend ? "suspend" : "resume", rc);
489 return rc;
490 }
491
492 return rc;
493}
494
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700495static int smblib_dc_icl_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -0700496 int icl_ua, const char *client)
Nicholas Troast34db5032016-03-28 12:26:44 -0700497{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700498 struct smb_charger *chg = data;
Nicholas Troast34db5032016-03-28 12:26:44 -0700499 int rc = 0;
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700500 bool suspend;
501
502 if (icl_ua < 0) {
503 smblib_dbg(chg, PR_MISC, "No Voter hence suspending\n");
504 icl_ua = 0;
505 }
506
507 suspend = (icl_ua < USBIN_25MA);
508 if (suspend)
509 goto suspend;
Nicholas Troast34db5032016-03-28 12:26:44 -0700510
511 rc = smblib_set_charge_param(chg, &chg->param.dc_icl, icl_ua);
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700512 if (rc < 0) {
513 dev_err(chg->dev, "Couldn't set DC input current limit rc=%d\n",
514 rc);
515 return rc;
516 }
517
518suspend:
519 rc = vote(chg->dc_suspend_votable, USER_VOTER, suspend, 0);
520 if (rc < 0) {
521 dev_err(chg->dev, "Couldn't vote to %s DC rc=%d\n",
522 suspend ? "suspend" : "resume", rc);
523 return rc;
524 }
Nicholas Troast34db5032016-03-28 12:26:44 -0700525 return rc;
526}
527
Harry Yang223c6282016-06-14 15:48:36 -0700528static int smblib_awake_vote_callback(struct votable *votable, void *data,
529 int awake, const char *client)
530{
531 struct smb_charger *chg = data;
532
533 if (awake)
534 pm_stay_awake(chg->dev);
535 else
536 pm_relax(chg->dev);
537
538 return 0;
539}
540
Harry Yang3c4c22d2016-06-15 11:40:54 -0700541static int smblib_pl_disable_vote_callback(struct votable *votable, void *data,
542 int pl_disable, const char *client)
543{
Harry Yang1d1034c2016-06-15 12:09:42 -0700544 struct smb_charger *chg = data;
545 union power_supply_propval pval = {0, };
546 int rc;
547
548 if (chg->mode != PARALLEL_MASTER || !get_parallel_psy(chg))
549 return 0;
550
551 chg->pl.taper_percent = 100;
552 rerun_election(chg->fv_votable);
553 rerun_election(chg->fcc_votable);
554
555 pval.intval = pl_disable;
556 rc = power_supply_set_property(chg->pl.psy,
557 POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval);
558 if (rc < 0) {
559 dev_err(chg->dev,
560 "Couldn't change slave suspend state rc=%d\n", rc);
561 return rc;
562 }
563
Harry Yang3c4c22d2016-06-15 11:40:54 -0700564 return 0;
565}
566
Nicholas Troast34db5032016-03-28 12:26:44 -0700567/*****************
568 * OTG REGULATOR *
569 *****************/
570
571int smblib_vbus_regulator_enable(struct regulator_dev *rdev)
572{
573 struct smb_charger *chg = rdev_get_drvdata(rdev);
574 int rc = 0;
575
576 rc = regmap_write(chg->regmap, CMD_OTG_REG, OTG_EN_BIT);
577 if (rc < 0)
578 dev_err(chg->dev, "Couldn't enable OTG regulator rc=%d\n", rc);
579
580 return rc;
581}
582
583int smblib_vbus_regulator_disable(struct regulator_dev *rdev)
584{
585 struct smb_charger *chg = rdev_get_drvdata(rdev);
586 int rc = 0;
587
588 rc = regmap_write(chg->regmap, CMD_OTG_REG, 0);
589 if (rc < 0)
590 dev_err(chg->dev, "Couldn't disable OTG regulator rc=%d\n", rc);
591
592 return rc;
593}
594
595int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev)
596{
597 struct smb_charger *chg = rdev_get_drvdata(rdev);
598 int rc = 0;
599 u8 cmd;
600
601 rc = smblib_read(chg, CMD_OTG_REG, &cmd);
602 if (rc < 0) {
603 dev_err(chg->dev, "Couldn't read CMD_OTG rc=%d", rc);
604 return rc;
605 }
606
607 return (cmd & OTG_EN_BIT) ? 1 : 0;
608}
609
610/*******************
611 * VCONN REGULATOR *
612 * *****************/
613
614int smblib_vconn_regulator_enable(struct regulator_dev *rdev)
615{
616 struct smb_charger *chg = rdev_get_drvdata(rdev);
617 int rc = 0;
618
619 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
620 VCONN_EN_VALUE_BIT, VCONN_EN_VALUE_BIT);
621 if (rc < 0)
622 dev_err(chg->dev, "Couldn't enable vconn regulator rc=%d\n",
623 rc);
624
625 return rc;
626}
627
628int smblib_vconn_regulator_disable(struct regulator_dev *rdev)
629{
630 struct smb_charger *chg = rdev_get_drvdata(rdev);
631 int rc = 0;
632
633 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
634 VCONN_EN_VALUE_BIT, 0);
635 if (rc < 0)
636 dev_err(chg->dev, "Couldn't disable vconn regulator rc=%d\n",
637 rc);
638
639 return rc;
640}
641
642int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev)
643{
644 struct smb_charger *chg = rdev_get_drvdata(rdev);
645 int rc = 0;
646 u8 cmd;
647
648 rc = smblib_read(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &cmd);
649 if (rc < 0) {
650 dev_err(chg->dev, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
651 rc);
652 return rc;
653 }
654
655 return (cmd & VCONN_EN_VALUE_BIT) ? 1 : 0;
656}
657
658/********************
659 * BATT PSY GETTERS *
660 ********************/
661
662int smblib_get_prop_input_suspend(struct smb_charger *chg,
663 union power_supply_propval *val)
664{
665 val->intval = get_client_vote(chg->usb_suspend_votable, USER_VOTER);
666 return 0;
667}
668
669int smblib_get_prop_batt_present(struct smb_charger *chg,
670 union power_supply_propval *val)
671{
672 int rc;
673 u8 stat;
674
675 rc = smblib_read(chg, BATIF_BASE + INT_RT_STS_OFFSET, &stat);
676 if (rc < 0) {
677 dev_err(chg->dev, "Couldn't read BATIF_INT_RT_STS rc=%d\n",
678 rc);
679 return rc;
680 }
681
682 val->intval = !(stat & (BAT_THERM_OR_ID_MISSING_RT_STS_BIT
683 | BAT_TERMINAL_MISSING_RT_STS_BIT));
684
685 return rc;
686}
687
688int smblib_get_prop_batt_capacity(struct smb_charger *chg,
689 union power_supply_propval *val)
690{
691 val->intval = 50;
692 return 0;
693}
694
695int smblib_get_prop_batt_status(struct smb_charger *chg,
696 union power_supply_propval *val)
697{
698 int rc;
699 u8 stat;
700 union power_supply_propval online_pval = {0, };
701
702 rc = smblib_get_prop_usb_online(chg, &online_pval);
703 if (rc < 0) {
704 dev_err(chg->dev, "Couldn't get prop usb online rc=%d\n", rc);
705 return rc;
706 }
707
708 if (!online_pval.intval) {
709 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
710 return rc;
711 }
712
713 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
714 if (rc < 0) {
715 dev_err(chg->dev, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
716 rc);
717 return rc;
718 }
719 smblib_dbg(chg, PR_REGISTER, "BATTERY_CHARGER_STATUS_1 = 0x%02x\n",
720 stat);
721
722 stat = stat & BATTERY_CHARGER_STATUS_MASK;
Harry Yang1d1034c2016-06-15 12:09:42 -0700723 if (stat == COMPLETED_CHARGE || stat == INHIBIT_CHARGE)
Nicholas Troast34db5032016-03-28 12:26:44 -0700724 val->intval = POWER_SUPPLY_STATUS_FULL;
725 else
726 val->intval = POWER_SUPPLY_STATUS_CHARGING;
727
728 return rc;
729}
730
731int smblib_get_prop_batt_charge_type(struct smb_charger *chg,
732 union power_supply_propval *val)
733{
734 int rc;
735 u8 stat;
736
737 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
738 if (rc < 0) {
739 dev_err(chg->dev, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
740 rc);
741 return rc;
742 }
743 smblib_dbg(chg, PR_REGISTER, "BATTERY_CHARGER_STATUS_1 = 0x%02x\n",
744 stat);
745
746 switch (stat & BATTERY_CHARGER_STATUS_MASK) {
747 case TRICKLE_CHARGE:
748 case PRE_CHARGE:
749 val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
750 break;
751 case FAST_CHARGE:
752 case FULLON_CHARGE:
753 val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
754 break;
755 case TAPER_CHARGE:
756 val->intval = POWER_SUPPLY_CHARGE_TYPE_TAPER;
757 break;
758 default:
759 val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
760 }
761
762 return rc;
763}
764
765int smblib_get_prop_batt_health(struct smb_charger *chg,
766 union power_supply_propval *val)
767{
768 int rc;
769 u8 stat;
770
771 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat);
772 if (rc < 0) {
773 dev_err(chg->dev, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
774 rc);
775 return rc;
776 }
777 smblib_dbg(chg, PR_REGISTER, "BATTERY_CHARGER_STATUS_2 = 0x%02x\n",
778 stat);
779
780 if (stat & CHARGER_ERROR_STATUS_BAT_OV_BIT) {
781 dev_err(chg->dev, "battery over-voltage\n");
782 val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
783 goto done;
784 }
785
786 switch (stat & BAT_TEMP_STATUS_MASK) {
787 case BAT_TEMP_STATUS_TOO_COLD_BIT:
788 val->intval = POWER_SUPPLY_HEALTH_COLD;
789 break;
790 case BAT_TEMP_STATUS_TOO_HOT_BIT:
791 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
792 break;
793 case BAT_TEMP_STATUS_COLD_SOFT_LIMIT_BIT:
794 val->intval = POWER_SUPPLY_HEALTH_COOL;
795 break;
796 case BAT_TEMP_STATUS_HOT_SOFT_LIMIT_BIT:
797 val->intval = POWER_SUPPLY_HEALTH_WARM;
798 break;
799 default:
800 val->intval = POWER_SUPPLY_HEALTH_GOOD;
801 }
802
803done:
804 return rc;
805}
806
807/***********************
808 * BATTERY PSY SETTERS *
809 ***********************/
810
811int smblib_set_prop_input_suspend(struct smb_charger *chg,
812 const union power_supply_propval *val)
813{
814 int rc;
815
816 rc = vote(chg->usb_suspend_votable, USER_VOTER, (bool)val->intval, 0);
817 if (rc < 0) {
818 dev_err(chg->dev, "Couldn't vote to %s USB rc=%d\n",
819 (bool)val->intval ? "suspend" : "resume", rc);
820 return rc;
821 }
822
823 rc = vote(chg->dc_suspend_votable, USER_VOTER, (bool)val->intval, 0);
824 if (rc < 0) {
825 dev_err(chg->dev, "Couldn't vote to %s DC rc=%d\n",
826 (bool)val->intval ? "suspend" : "resume", rc);
827 return rc;
828 }
829
Nicholas Troast61ff40f2016-07-08 10:59:22 -0700830 power_supply_changed(chg->batt_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -0700831 return rc;
832}
833
834/*******************
835 * USB PSY GETTERS *
836 *******************/
837
838int smblib_get_prop_usb_present(struct smb_charger *chg,
839 union power_supply_propval *val)
840{
841 int rc = 0;
842 u8 stat;
843
844 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
845 if (rc < 0) {
846 dev_err(chg->dev, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
847 rc);
848 return rc;
849 }
850 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n",
851 stat);
852
853 val->intval = (bool)(stat & CC_ATTACHED_BIT);
854
855 return rc;
856}
857
858int smblib_get_prop_usb_online(struct smb_charger *chg,
859 union power_supply_propval *val)
860{
861 int rc = 0;
862 u8 stat;
863
864 if (get_client_vote(chg->usb_suspend_votable, USER_VOTER)) {
865 val->intval = false;
866 return rc;
867 }
868
869 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
870 if (rc < 0) {
871 dev_err(chg->dev, "Couldn't read POWER_PATH_STATUS rc=%d\n",
872 rc);
873 return rc;
874 }
875 smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
876 stat);
877
878 val->intval = (stat & USE_USBIN_BIT) &&
879 (stat & VALID_INPUT_POWER_SOURCE_BIT);
880
881 return rc;
882}
883
884int smblib_get_prop_usb_voltage_now(struct smb_charger *chg,
885 union power_supply_propval *val)
886{
887 if (chg->vbus_present)
888 val->intval = MICRO_5V;
889 else
890 val->intval = 0;
891
892 return 0;
893}
894
895int smblib_get_prop_usb_current_max(struct smb_charger *chg,
896 union power_supply_propval *val)
897{
898 val->intval = get_effective_result_locked(chg->usb_icl_votable);
899 return 0;
900}
901
902int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
903 union power_supply_propval *val)
904{
905 int rc = 0;
906 u8 stat;
907
908 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
909 if (rc < 0) {
910 dev_err(chg->dev, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
911 rc);
912 return rc;
913 }
914 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n",
915 stat);
916
917 if (stat & CC_ATTACHED_BIT)
918 val->intval = (bool)(stat & CC_ORIENTATION_BIT) + 1;
919 else
920 val->intval = 0;
921
922 return rc;
923}
924
925static const char * const smblib_typec_mode_name[] = {
926 [POWER_SUPPLY_TYPEC_NONE] = "NONE",
927 [POWER_SUPPLY_TYPEC_SOURCE_DEFAULT] = "SOURCE_DEFAULT",
928 [POWER_SUPPLY_TYPEC_SOURCE_MEDIUM] = "SOURCE_MEDIUM",
929 [POWER_SUPPLY_TYPEC_SOURCE_HIGH] = "SOURCE_HIGH",
930 [POWER_SUPPLY_TYPEC_NON_COMPLIANT] = "NON_COMPLIANT",
931 [POWER_SUPPLY_TYPEC_SINK] = "SINK",
932 [POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE] = "SINK_POWERED_CABLE",
933 [POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY] = "SINK_DEBUG_ACCESSORY",
934 [POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER] = "SINK_AUDIO_ADAPTER",
935 [POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY] = "POWERED_CABLE_ONLY",
936};
937
938static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
939{
940 int rc;
941 u8 stat;
942
943 rc = smblib_read(chg, TYPE_C_STATUS_1_REG, &stat);
944 if (rc < 0) {
945 dev_err(chg->dev, "Couldn't read TYPE_C_STATUS_1 rc=%d\n", rc);
946 return POWER_SUPPLY_TYPEC_NONE;
947 }
948 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_1 = 0x%02x\n", stat);
949
950 switch (stat) {
951 case 0:
952 return POWER_SUPPLY_TYPEC_NONE;
953 case UFP_TYPEC_RDSTD_BIT:
954 return POWER_SUPPLY_TYPEC_SOURCE_DEFAULT;
955 case UFP_TYPEC_RD1P5_BIT:
956 return POWER_SUPPLY_TYPEC_SOURCE_MEDIUM;
957 case UFP_TYPEC_RD3P0_BIT:
958 return POWER_SUPPLY_TYPEC_SOURCE_HIGH;
959 default:
960 break;
961 }
962
963 return POWER_SUPPLY_TYPEC_NON_COMPLIANT;
964}
965
966static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
967{
968 int rc;
969 u8 stat;
970
971 rc = smblib_read(chg, TYPE_C_STATUS_2_REG, &stat);
972 if (rc < 0) {
973 dev_err(chg->dev, "Couldn't read TYPE_C_STATUS_2 rc=%d\n", rc);
974 return POWER_SUPPLY_TYPEC_NONE;
975 }
976 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_2 = 0x%02x\n", stat);
977
978 switch (stat & DFP_TYPEC_MASK) {
979 case DFP_RA_RA_BIT:
980 return POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER;
981 case DFP_RD_RD_BIT:
982 return POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY;
983 case DFP_RD_RA_VCONN_BIT:
984 return POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE;
985 case DFP_RD_OPEN_BIT:
986 return POWER_SUPPLY_TYPEC_SINK;
987 case DFP_RA_OPEN_BIT:
988 return POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY;
989 default:
990 break;
991 }
992
993 return POWER_SUPPLY_TYPEC_NONE;
994}
995
996int smblib_get_prop_typec_mode(struct smb_charger *chg,
997 union power_supply_propval *val)
998{
999 int rc;
1000 u8 stat;
1001
1002 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
1003 if (rc < 0) {
1004 dev_err(chg->dev, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
1005 val->intval = POWER_SUPPLY_TYPEC_NONE;
1006 return rc;
1007 }
1008 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat);
1009
1010 if (!(stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT)) {
1011 val->intval = POWER_SUPPLY_TYPEC_NONE;
1012 return rc;
1013 }
1014
1015 if (stat & UFP_DFP_MODE_STATUS_BIT)
1016 val->intval = smblib_get_prop_dfp_mode(chg);
1017 else
1018 val->intval = smblib_get_prop_ufp_mode(chg);
1019
1020 return rc;
1021}
1022
1023int smblib_get_prop_typec_power_role(struct smb_charger *chg,
1024 union power_supply_propval *val)
1025{
1026 int rc = 0;
1027 u8 ctrl;
1028
1029 rc = smblib_read(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &ctrl);
1030 if (rc < 0) {
1031 dev_err(chg->dev, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
1032 rc);
1033 return rc;
1034 }
1035 smblib_dbg(chg, PR_REGISTER, "TYPE_C_INTRPT_ENB_SOFTWARE_CTRL = 0x%02x\n",
1036 ctrl);
1037
1038 if (ctrl & TYPEC_DISABLE_CMD_BIT) {
1039 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
1040 return rc;
1041 }
1042
1043 switch (ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT)) {
1044 case 0:
1045 val->intval = POWER_SUPPLY_TYPEC_PR_DUAL;
1046 break;
1047 case DFP_EN_CMD_BIT:
1048 val->intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
1049 break;
1050 case UFP_EN_CMD_BIT:
1051 val->intval = POWER_SUPPLY_TYPEC_PR_SINK;
1052 break;
1053 default:
1054 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
1055 dev_err(chg->dev, "unsupported power role 0x%02lx\n",
1056 ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT));
1057 return -EINVAL;
1058 }
1059
1060 return rc;
1061}
1062
1063int smblib_get_prop_pd_allowed(struct smb_charger *chg,
1064 union power_supply_propval *val)
1065{
1066 val->intval = get_effective_result_locked(chg->pd_allowed_votable);
1067 return 0;
1068}
1069
Nicholas Troast133a7f52016-06-29 13:48:20 -07001070int smblib_get_prop_input_current_settled(struct smb_charger *chg,
1071 union power_supply_propval *val)
1072{
1073 return smblib_get_charge_param(chg, &chg->param.icl_stat, &val->intval);
1074}
1075
Nicholas Troast34db5032016-03-28 12:26:44 -07001076/*******************
1077 * USB PSY SETTERS *
1078 * *****************/
1079
1080int smblib_set_prop_usb_current_max(struct smb_charger *chg,
1081 const union power_supply_propval *val)
1082{
1083 int rc;
1084
1085 rc = vote(chg->usb_icl_votable, PD_VOTER, true, val->intval);
1086 return rc;
1087}
1088
1089int smblib_set_prop_typec_power_role(struct smb_charger *chg,
1090 const union power_supply_propval *val)
1091{
1092 int rc = 0;
1093 u8 power_role;
1094
1095 switch (val->intval) {
1096 case POWER_SUPPLY_TYPEC_PR_NONE:
1097 power_role = TYPEC_DISABLE_CMD_BIT;
1098 break;
1099 case POWER_SUPPLY_TYPEC_PR_DUAL:
1100 power_role = 0;
1101 break;
1102 case POWER_SUPPLY_TYPEC_PR_SINK:
1103 power_role = UFP_EN_CMD_BIT;
1104 break;
1105 case POWER_SUPPLY_TYPEC_PR_SOURCE:
1106 power_role = DFP_EN_CMD_BIT;
1107 break;
1108 default:
1109 dev_err(chg->dev, "power role %d not supported\n", val->intval);
1110 return -EINVAL;
1111 }
1112
1113 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1114 TYPEC_POWER_ROLE_CMD_MASK, power_role);
1115 if (rc < 0) {
1116 dev_err(chg->dev, "Couldn't write 0x%02x to TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
1117 power_role, rc);
1118 return rc;
1119 }
1120
1121 return rc;
1122}
1123
1124int smblib_set_prop_usb_voltage_min(struct smb_charger *chg,
1125 const union power_supply_propval *val)
1126{
1127 int rc, min_uv;
1128
1129 min_uv = min(val->intval, chg->voltage_max_uv);
1130 rc = smblib_set_usb_pd_allowed_voltage(chg, min_uv,
1131 chg->voltage_max_uv);
1132 if (rc < 0) {
1133 dev_err(chg->dev, "invalid max voltage %duV rc=%d\n",
1134 val->intval, rc);
1135 return rc;
1136 }
1137
1138 chg->voltage_min_uv = val->intval;
1139 return rc;
1140}
1141
1142int smblib_set_prop_usb_voltage_max(struct smb_charger *chg,
1143 const union power_supply_propval *val)
1144{
1145 int rc, max_uv;
1146
1147 max_uv = max(val->intval, chg->voltage_min_uv);
1148 rc = smblib_set_usb_pd_allowed_voltage(chg, chg->voltage_min_uv,
1149 max_uv);
1150 if (rc < 0) {
1151 dev_err(chg->dev, "invalid min voltage %duV rc=%d\n",
1152 val->intval, rc);
1153 return rc;
1154 }
1155
1156 chg->voltage_max_uv = val->intval;
1157 return rc;
1158}
1159
1160int smblib_set_prop_pd_active(struct smb_charger *chg,
1161 const union power_supply_propval *val)
1162{
1163 int rc;
1164
1165 if (!get_effective_result(chg->pd_allowed_votable)) {
1166 dev_err(chg->dev, "PD is not allowed\n");
1167 return -EINVAL;
1168 }
1169
1170 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1171 AUTO_SRC_DETECT_BIT,
1172 val->intval ? 0 : AUTO_SRC_DETECT_BIT);
1173 if (rc < 0) {
1174 dev_err(chg->dev, "Couldn't %s APSD rc=%d\n",
1175 val->intval ? "disable" : "enable", rc);
1176 return rc;
1177 }
1178
1179 vote(chg->pd_allowed_votable, PD_VOTER, val->intval, 0);
1180
1181 chg->pd_active = (bool)val->intval;
Harry Yang6607b4a2016-05-17 17:50:09 -07001182 smblib_update_usb_type(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07001183 return rc;
1184}
1185
1186/**********************
1187 * INTERRUPT HANDLERS *
1188 **********************/
1189
1190irqreturn_t smblib_handle_debug(int irq, void *data)
1191{
1192 struct smb_irq_data *irq_data = data;
1193 struct smb_charger *chg = irq_data->parent_data;
1194
1195 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
1196
1197 return IRQ_HANDLED;
1198}
1199
Harry Yang6fe72ab2016-06-14 16:21:39 -07001200irqreturn_t smblib_handle_chg_state_change(int irq, void *data)
1201{
1202 struct smb_irq_data *irq_data = data;
1203 struct smb_charger *chg = irq_data->parent_data;
Harry Yang1d1034c2016-06-15 12:09:42 -07001204 union power_supply_propval pval = {0, };
1205 int rc;
Harry Yang6fe72ab2016-06-14 16:21:39 -07001206
1207 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
1208
Harry Yang1d1034c2016-06-15 12:09:42 -07001209 if (chg->mode != PARALLEL_MASTER || !get_parallel_psy(chg))
1210 return IRQ_HANDLED;
1211
1212 rc = smblib_get_prop_batt_charge_type(chg, &pval);
1213 if (rc < 0) {
1214 dev_err(chg->dev, "Couldn't get batt charge type rc=%d\n", rc);
1215 return IRQ_HANDLED;
1216 }
1217
1218 if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_FAST)
1219 vote(chg->pl_disable_votable, CHG_STATE_VOTER, false, 0);
1220
1221 if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER
1222 && !get_effective_result_locked(chg->pl_disable_votable)) {
1223 cancel_delayed_work_sync(&chg->pl_taper_work);
1224 schedule_delayed_work(&chg->pl_taper_work, 0);
1225 }
1226
1227 rc = smblib_get_prop_batt_status(chg, &pval);
1228 if (rc < 0) {
1229 dev_err(chg->dev, "Couldn't get batt status type rc=%d\n", rc);
1230 return IRQ_HANDLED;
1231 }
1232 if (pval.intval == POWER_SUPPLY_STATUS_FULL)
1233 vote(chg->pl_disable_votable, TAPER_END_VOTER, false, 0);
1234
Harry Yang6fe72ab2016-06-14 16:21:39 -07001235 return IRQ_HANDLED;
1236}
1237
Nicholas Troast34db5032016-03-28 12:26:44 -07001238irqreturn_t smblib_handle_batt_psy_changed(int irq, void *data)
1239{
1240 struct smb_irq_data *irq_data = data;
1241 struct smb_charger *chg = irq_data->parent_data;
1242
1243 smblib_handle_debug(irq, data);
1244 power_supply_changed(chg->batt_psy);
1245 return IRQ_HANDLED;
1246}
1247
1248irqreturn_t smblib_handle_usb_psy_changed(int irq, void *data)
1249{
1250 struct smb_irq_data *irq_data = data;
1251 struct smb_charger *chg = irq_data->parent_data;
1252
1253 smblib_handle_debug(irq, data);
1254 power_supply_changed(chg->usb_psy);
1255 return IRQ_HANDLED;
1256}
1257
1258irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
1259{
1260 struct smb_irq_data *irq_data = data;
1261 struct smb_charger *chg = irq_data->parent_data;
1262 int rc;
1263 u8 stat;
1264
1265 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
1266 if (rc < 0) {
1267 dev_err(chg->dev, "Couldn't read USB_INT_RT_STS rc=%d\n",
1268 rc);
1269 return IRQ_HANDLED;
1270 }
1271
1272 chg->vbus_present = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
1273
1274 /* fetch the DPDM regulator */
1275 if (!chg->dpdm_reg && of_get_property(chg->dev->of_node,
1276 "dpdm-supply", NULL)) {
1277 chg->dpdm_reg = devm_regulator_get(chg->dev, "dpdm");
1278 if (IS_ERR(chg->dpdm_reg)) {
1279 dev_err(chg->dev, "Couldn't get dpdm regulator rc=%ld\n",
1280 PTR_ERR(chg->dpdm_reg));
1281 chg->dpdm_reg = NULL;
1282 }
1283 }
1284
1285 if (!chg->dpdm_reg)
1286 goto skip_dpdm_float;
1287
1288 if (chg->vbus_present && !regulator_is_enabled(chg->dpdm_reg)) {
1289 smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n");
1290 rc = regulator_enable(chg->dpdm_reg);
1291 if (rc < 0)
1292 dev_err(chg->dev, "Couldn't enable dpdm regulator rc=%d\n",
1293 rc);
1294 } else if (regulator_is_enabled(chg->dpdm_reg)) {
1295 smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n");
1296 rc = regulator_disable(chg->dpdm_reg);
1297 if (rc < 0)
1298 dev_err(chg->dev, "Couldn't disable dpdm regulator rc=%d\n",
1299 rc);
1300 }
1301
1302skip_dpdm_float:
1303 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n",
1304 irq_data->name, chg->vbus_present ? "attached" : "detached");
1305 return IRQ_HANDLED;
1306}
1307
Harry Yang1d1034c2016-06-15 12:09:42 -07001308#define MICRO_5P5V 5500000
1309#define USB_WEAK_INPUT_MA 1500000
1310static bool is_icl_pl_ready(struct smb_charger *chg)
1311{
1312 union power_supply_propval pval = {0, };
1313 int icl_ma;
1314 int rc;
1315
1316 rc = smblib_get_prop_usb_voltage_now(chg, &pval);
1317 if (rc < 0) {
1318 dev_err(chg->dev, "Couldn't get prop usb voltage rc=%d\n", rc);
1319 return false;
1320 }
1321
1322 if (pval.intval <= MICRO_5P5V) {
1323 rc = smblib_get_charge_param(chg,
1324 &chg->param.icl_stat, &icl_ma);
1325 if (rc < 0) {
1326 dev_err(chg->dev, "Couldn't get ICL status rc=%d\n",
1327 rc);
1328 return false;
1329 }
1330
1331 if (icl_ma < USB_WEAK_INPUT_MA)
1332 return false;
1333 }
1334
1335 /*
1336 * Always enable parallel charging when USB INPUT is higher than 5V
1337 * regardless of the AICL results. Assume chargers above 5V are strong
1338 */
1339
1340 return true;
1341}
1342
Harry Yang6fe72ab2016-06-14 16:21:39 -07001343irqreturn_t smblib_handle_icl_change(int irq, void *data)
1344{
1345 struct smb_irq_data *irq_data = data;
1346 struct smb_charger *chg = irq_data->parent_data;
1347
Harry Yang1d1034c2016-06-15 12:09:42 -07001348 if (chg->mode == PARALLEL_MASTER)
1349 vote(chg->pl_disable_votable, USBIN_ICL_VOTER,
1350 !is_icl_pl_ready(chg), 0);
1351
Harry Yang6fe72ab2016-06-14 16:21:39 -07001352 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
1353
1354 return IRQ_HANDLED;
1355}
1356
Nicholas Troast34db5032016-03-28 12:26:44 -07001357static void smblib_handle_slow_plugin_timeout(struct smb_charger *chg,
1358 bool rising)
1359{
1360 smblib_dbg(chg, PR_INTERRUPT, "IRQ: slow-plugin-timeout %s\n",
1361 rising ? "rising" : "falling");
1362}
1363
1364static void smblib_handle_sdp_enumeration_done(struct smb_charger *chg,
1365 bool rising)
1366{
1367 smblib_dbg(chg, PR_INTERRUPT, "IRQ: sdp-enumeration-done %s\n",
1368 rising ? "rising" : "falling");
1369}
1370
1371static void smblib_handle_adaptive_voltage_done(struct smb_charger *chg,
1372 bool rising)
1373{
1374 smblib_dbg(chg, PR_INTERRUPT, "IRQ: adaptive-voltage-done %s\n",
1375 rising ? "rising" : "falling");
1376}
1377
1378/* triggers when HVDCP 3.0 authentication has finished */
1379static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
1380 bool rising)
1381{
1382 const struct apsd_result *apsd_result;
1383
1384 if (!rising)
1385 return;
1386
1387 /* the APSD done handler will set the USB supply type */
1388 apsd_result = smblib_get_apsd_result(chg);
1389 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n",
1390 apsd_result->name);
1391}
1392
1393/* triggers when HVDCP is detected */
1394static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg,
1395 bool rising)
1396{
1397 if (!rising)
1398 return;
1399
1400 /* the APSD done handler will set the USB supply type */
1401 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
1402 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-detect-done %s\n",
1403 rising ? "rising" : "falling");
1404}
1405
1406#define HVDCP_DET_MS 2500
1407static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
1408{
1409 int rc;
1410 const struct apsd_result *apsd_result;
1411
1412 if (!rising)
1413 return;
1414
1415 apsd_result = smblib_get_apsd_result(chg);
1416 switch (apsd_result->bit) {
1417 case SDP_CHARGER_BIT:
1418 case CDP_CHARGER_BIT:
1419 case OCP_CHARGER_BIT:
1420 case FLOAT_CHARGER_BIT:
1421 vote(chg->pd_allowed_votable, DEFAULT_VOTER, true, 0);
1422 break;
1423 case DCP_CHARGER_BIT:
1424 schedule_delayed_work(&chg->hvdcp_detect_work,
1425 msecs_to_jiffies(HVDCP_DET_MS));
1426 break;
1427 default:
1428 break;
1429 }
1430
1431 rc = smblib_update_usb_type(chg);
1432 if (rc < 0)
1433 dev_err(chg->dev, "Couldn't update usb type rc=%d\n", rc);
1434
1435 smblib_dbg(chg, PR_INTERRUPT, "IRQ: apsd-done rising; %s detected\n",
1436 apsd_result->name);
1437}
1438
1439irqreturn_t smblib_handle_usb_source_change(int irq, void *data)
1440{
1441 struct smb_irq_data *irq_data = data;
1442 struct smb_charger *chg = irq_data->parent_data;
1443 int rc = 0;
1444 u8 stat;
1445
1446 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
1447 if (rc < 0) {
1448 dev_err(chg->dev, "Couldn't read APSD_STATUS rc=%d\n", rc);
1449 return IRQ_HANDLED;
1450 }
1451 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
1452
1453 smblib_handle_apsd_done(chg,
1454 (bool)(stat & APSD_DTC_STATUS_DONE_BIT));
1455
1456 smblib_handle_hvdcp_detect_done(chg,
1457 (bool)(stat & QC_CHARGER_BIT));
1458
1459 smblib_handle_hvdcp_3p0_auth_done(chg,
1460 (bool)(stat & QC_AUTH_DONE_STATUS_BIT));
1461
1462 smblib_handle_adaptive_voltage_done(chg,
1463 (bool)(stat & VADP_CHANGE_DONE_AFTER_AUTH_BIT));
1464
1465 smblib_handle_sdp_enumeration_done(chg,
1466 (bool)(stat & ENUMERATION_DONE_BIT));
1467
1468 smblib_handle_slow_plugin_timeout(chg,
1469 (bool)(stat & SLOW_PLUGIN_TIMEOUT_BIT));
1470
1471 power_supply_changed(chg->usb_psy);
1472
1473 return IRQ_HANDLED;
1474}
1475
1476static void smblib_handle_typec_cc(struct smb_charger *chg, bool attached)
1477{
1478 int rc;
1479
1480 if (!attached) {
1481 rc = smblib_detach_usb(chg);
1482 if (rc < 0)
1483 dev_err(chg->dev, "Couldn't detach USB rc=%d\n", rc);
1484 }
1485
1486 smblib_dbg(chg, PR_INTERRUPT, "IRQ: CC %s\n",
1487 attached ? "attached" : "detached");
1488}
1489
1490static void smblib_handle_typec_debounce_done(struct smb_charger *chg,
1491 bool rising, bool sink_attached)
1492{
1493 int rc;
1494 union power_supply_propval pval = {0, };
1495
1496 /* allow PD for attached sinks */
1497 if (rising && sink_attached)
1498 vote(chg->pd_allowed_votable, DEFAULT_VOTER, true, 0);
1499
1500 rc = smblib_get_prop_typec_mode(chg, &pval);
1501 if (rc < 0)
1502 dev_err(chg->dev, "Couldn't get prop typec mode rc=%d\n", rc);
1503
Harry Yang1d1034c2016-06-15 12:09:42 -07001504 /*
1505 * vote to enable parallel charging if a source is attached, and disable
1506 * otherwise
1507 */
1508 vote(chg->pl_disable_votable, TYPEC_SRC_VOTER,
1509 !rising || sink_attached, 0);
1510
1511 /* reset taper_end voter here */
1512 if (!rising || sink_attached)
1513 vote(chg->pl_disable_votable, TAPER_END_VOTER, false, 0);
1514
Nicholas Troast34db5032016-03-28 12:26:44 -07001515 smblib_dbg(chg, PR_INTERRUPT, "IRQ: debounce-done %s; Type-C %s detected\n",
1516 rising ? "rising" : "falling",
1517 smblib_typec_mode_name[pval.intval]);
1518}
1519
1520irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
1521{
1522 struct smb_irq_data *irq_data = data;
1523 struct smb_charger *chg = irq_data->parent_data;
1524 int rc;
1525 u8 stat;
1526
1527 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
1528 if (rc < 0) {
1529 dev_err(chg->dev, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
1530 rc);
1531 return IRQ_HANDLED;
1532 }
1533 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat);
1534
1535 if (stat & TYPEC_VBUS_ERROR_STATUS_BIT) {
1536 dev_err(chg->dev, "IRQ: vbus-error rising\n");
1537 return IRQ_HANDLED;
1538 }
1539
1540 smblib_handle_typec_cc(chg,
1541 (bool)(stat & CC_ATTACHED_BIT));
1542 smblib_handle_typec_debounce_done(chg,
1543 (bool)(stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT),
1544 (bool)(stat & UFP_DFP_MODE_STATUS_BIT));
1545
1546 power_supply_changed(chg->usb_psy);
1547
1548 return IRQ_HANDLED;
1549}
1550
1551/***************
1552 * Work Queues *
1553 ***************/
1554
1555static void smblib_hvdcp_detect_work(struct work_struct *work)
1556{
1557 struct smb_charger *chg = container_of(work, struct smb_charger,
1558 hvdcp_detect_work.work);
1559 const struct apsd_result *apsd_result;
1560
1561 apsd_result = smblib_get_apsd_result(chg);
1562 if (apsd_result->bit &&
1563 !(apsd_result->bit & (QC_2P0_BIT | QC_3P0_BIT))) {
1564 vote(chg->pd_allowed_votable, DEFAULT_VOTER, true, 0);
1565 power_supply_changed(chg->usb_psy);
1566 }
1567}
1568
Harry Yang1d1034c2016-06-15 12:09:42 -07001569#define MINIMUM_PARALLEL_FCC_UA 500000
1570#define PL_TAPER_WORK_DELAY_MS 100
1571#define TAPER_RESIDUAL_PERCENT 75
1572static void smblib_pl_taper_work(struct work_struct *work)
1573{
1574 struct smb_charger *chg = container_of(work, struct smb_charger,
1575 pl_taper_work.work);
1576 union power_supply_propval pval = {0, };
1577 int rc;
1578
1579 if (chg->pl.slave_fcc < MINIMUM_PARALLEL_FCC_UA) {
1580 vote(chg->pl_disable_votable, TAPER_END_VOTER, true, 0);
1581 goto done;
1582 }
1583
1584 rc = smblib_get_prop_batt_charge_type(chg, &pval);
1585 if (rc < 0) {
1586 dev_err(chg->dev, "Couldn't get batt charge type rc=%d\n", rc);
1587 goto done;
1588 }
1589
1590 if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER) {
1591 vote(chg->awake_votable, PL_VOTER, true, 0);
1592 /* Reduce the taper percent by 25 percent */
1593 chg->pl.taper_percent = chg->pl.taper_percent
1594 * TAPER_RESIDUAL_PERCENT / 100;
1595 rerun_election(chg->fcc_votable);
1596 schedule_delayed_work(&chg->pl_taper_work,
1597 msecs_to_jiffies(PL_TAPER_WORK_DELAY_MS));
1598 return;
1599 }
1600
1601 /*
1602 * Master back to Fast Charge, get out of this round of taper reduction
1603 */
1604done:
1605 vote(chg->awake_votable, PL_VOTER, false, 0);
1606}
1607
Nicholas Troast320839e2016-06-03 10:18:00 -07001608int smblib_create_votables(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07001609{
1610 int rc = 0;
1611
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001612 chg->usb_suspend_votable = create_votable("INPUT_SUSPEND", VOTE_SET_ANY,
1613 smblib_usb_suspend_vote_callback,
1614 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07001615 if (IS_ERR(chg->usb_suspend_votable)) {
1616 rc = PTR_ERR(chg->usb_suspend_votable);
1617 return rc;
1618 }
1619
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001620 chg->dc_suspend_votable = create_votable("DC_SUSPEND", VOTE_SET_ANY,
1621 smblib_dc_suspend_vote_callback,
1622 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07001623 if (IS_ERR(chg->dc_suspend_votable)) {
1624 rc = PTR_ERR(chg->dc_suspend_votable);
1625 return rc;
1626 }
1627
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001628 chg->fcc_votable = create_votable("FCC", VOTE_MAX,
1629 smblib_fcc_vote_callback,
1630 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07001631 if (IS_ERR(chg->fcc_votable)) {
1632 rc = PTR_ERR(chg->fcc_votable);
1633 return rc;
1634 }
1635
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001636 chg->fv_votable = create_votable("FV", VOTE_MAX,
1637 smblib_fv_vote_callback,
1638 chg);
Abhijeet Dharmapurikarf9805d42016-05-17 18:38:42 -07001639 if (IS_ERR(chg->fv_votable)) {
1640 rc = PTR_ERR(chg->fv_votable);
1641 return rc;
1642 }
1643
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001644 chg->usb_icl_votable = create_votable("USB_ICL", VOTE_MIN,
1645 smblib_usb_icl_vote_callback,
1646 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07001647 if (IS_ERR(chg->usb_icl_votable)) {
1648 rc = PTR_ERR(chg->usb_icl_votable);
1649 return rc;
1650 }
1651
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001652 chg->dc_icl_votable = create_votable("DC_ICL", VOTE_MIN,
1653 smblib_dc_icl_vote_callback,
1654 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07001655 if (IS_ERR(chg->dc_icl_votable)) {
1656 rc = PTR_ERR(chg->dc_icl_votable);
1657 return rc;
1658 }
1659
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001660 chg->pd_allowed_votable = create_votable("PD_ALLOWED", VOTE_SET_ANY,
1661 NULL, NULL);
Nicholas Troast34db5032016-03-28 12:26:44 -07001662 if (IS_ERR(chg->pd_allowed_votable)) {
1663 rc = PTR_ERR(chg->pd_allowed_votable);
1664 return rc;
1665 }
1666
Harry Yang223c6282016-06-14 15:48:36 -07001667 chg->awake_votable = create_votable("AWAKE", VOTE_SET_ANY,
1668 smblib_awake_vote_callback,
1669 chg);
1670 if (IS_ERR(chg->awake_votable)) {
1671 rc = PTR_ERR(chg->awake_votable);
1672 return rc;
1673 }
1674
Harry Yang3c4c22d2016-06-15 11:40:54 -07001675 chg->pl_disable_votable = create_votable("PL_DISABLE", VOTE_SET_ANY,
1676 smblib_pl_disable_vote_callback,
1677 chg);
1678 if (IS_ERR(chg->pl_disable_votable)) {
1679 rc = PTR_ERR(chg->pl_disable_votable);
1680 return rc;
1681 }
1682
Nicholas Troast320839e2016-06-03 10:18:00 -07001683 return rc;
1684}
1685
1686int smblib_init(struct smb_charger *chg)
1687{
1688 int rc = 0;
1689
1690 mutex_init(&chg->write_lock);
1691 INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work);
Harry Yang1d1034c2016-06-15 12:09:42 -07001692 INIT_DELAYED_WORK(&chg->pl_taper_work, smblib_pl_taper_work);
Nicholas Troast320839e2016-06-03 10:18:00 -07001693
1694 switch (chg->mode) {
1695 case PARALLEL_MASTER:
1696 rc = smblib_create_votables(chg);
1697 if (rc < 0) {
1698 dev_err(chg->dev, "Couldn't create votables rc=%d\n",
1699 rc);
1700 }
1701 break;
1702 case PARALLEL_SLAVE:
1703 break;
1704 default:
1705 dev_err(chg->dev, "Unsupported mode %d\n", chg->mode);
1706 return -EINVAL;
1707 }
1708
1709 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001710}
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001711
1712int smblib_deinit(struct smb_charger *chg)
1713{
1714 destroy_votable(chg->usb_suspend_votable);
1715 destroy_votable(chg->dc_suspend_votable);
1716 destroy_votable(chg->fcc_votable);
1717 destroy_votable(chg->fv_votable);
1718 destroy_votable(chg->usb_icl_votable);
1719 destroy_votable(chg->dc_icl_votable);
1720 destroy_votable(chg->pd_allowed_votable);
Harry Yang223c6282016-06-14 15:48:36 -07001721 destroy_votable(chg->awake_votable);
Harry Yang3c4c22d2016-06-15 11:40:54 -07001722 destroy_votable(chg->pl_disable_votable);
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001723
1724 return 0;
1725}