blob: d0b364e8fab514b69ec324517e955b3a4bc85507 [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 */
Nicholas Troast26b01da2016-07-18 13:40:25 -070033 return (bool)((addr & 0xFF) >= 0xC0);
Nicholas Troast34db5032016-03-28 12:26:44 -070034}
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 Yang58a9e7a2016-06-23 14:54:43 -0700342static int pl_notifier_call(struct notifier_block *nb,
343 unsigned long ev, void *v)
Harry Yang1d1034c2016-06-15 12:09:42 -0700344{
Harry Yang58a9e7a2016-06-23 14:54:43 -0700345 struct power_supply *psy = v;
346 struct smb_charger *chg = container_of(nb, struct smb_charger, pl.nb);
Harry Yang1d1034c2016-06-15 12:09:42 -0700347
Harry Yang58a9e7a2016-06-23 14:54:43 -0700348 if (strcmp(psy->desc->name, "parallel") == 0) {
349 chg->pl.psy = psy;
350 schedule_work(&chg->pl_detect_work);
351 }
Harry Yang1d1034c2016-06-15 12:09:42 -0700352
Harry Yang58a9e7a2016-06-23 14:54:43 -0700353 return NOTIFY_OK;
354}
355
356static int register_pl_notifier(struct smb_charger *chg)
357{
358 int rc;
359
360 chg->pl.nb.notifier_call = pl_notifier_call;
361 rc = power_supply_reg_notifier(&chg->pl.nb);
362 if (rc < 0) {
363 pr_err("Couldn't register psy notifier rc = %d\n", rc);
364 return rc;
365 }
366
367 return 0;
Harry Yang1d1034c2016-06-15 12:09:42 -0700368}
369
Nicholas Troast34db5032016-03-28 12:26:44 -0700370/*********************
371 * VOTABLE CALLBACKS *
372 *********************/
373
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700374static int smblib_usb_suspend_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -0700375 int suspend, const char *client)
Nicholas Troast34db5032016-03-28 12:26:44 -0700376{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700377 struct smb_charger *chg = data;
Nicholas Troast34db5032016-03-28 12:26:44 -0700378
379 return smblib_set_usb_suspend(chg, suspend);
380}
381
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700382static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -0700383 int suspend, const char *client)
Nicholas Troast34db5032016-03-28 12:26:44 -0700384{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700385 struct smb_charger *chg = data;
Nicholas Troast34db5032016-03-28 12:26:44 -0700386
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700387 if (suspend < 0)
388 suspend = false;
389
Nicholas Troast34db5032016-03-28 12:26:44 -0700390 return smblib_set_dc_suspend(chg, suspend);
391}
392
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700393static int smblib_fcc_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -0700394 int fcc_ua, const char *client)
Nicholas Troast34db5032016-03-28 12:26:44 -0700395{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700396 struct smb_charger *chg = data;
Nicholas Troast34db5032016-03-28 12:26:44 -0700397 int rc = 0;
Harry Yang1d1034c2016-06-15 12:09:42 -0700398 union power_supply_propval pval = {0, };
399 int master_ua = fcc_ua, slave_ua;
Nicholas Troast34db5032016-03-28 12:26:44 -0700400
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700401 if (fcc_ua < 0) {
402 smblib_dbg(chg, PR_MISC, "No Voter\n");
403 return 0;
404 }
405
Harry Yang1d1034c2016-06-15 12:09:42 -0700406 if (chg->mode == PARALLEL_MASTER
407 && !get_effective_result_locked(chg->pl_disable_votable)) {
408 smblib_fcc_split_ua(chg, fcc_ua, &master_ua, &slave_ua);
409
410 /*
411 * parallel charger is not disabled, implying that
412 * chg->pl.psy exists
413 */
414 pval.intval = slave_ua;
415 rc = power_supply_set_property(chg->pl.psy,
416 POWER_SUPPLY_PROP_CURRENT_MAX, &pval);
417 if (rc < 0) {
418 dev_err(chg->dev, "Could not set parallel fcc, rc=%d\n",
419 rc);
420 return rc;
421 }
422
423 chg->pl.slave_fcc = slave_ua;
424 }
425
426 rc = smblib_set_charge_param(chg, &chg->param.fcc, master_ua);
427 if (rc < 0) {
428 dev_err(chg->dev, "Error in setting fcc, rc=%d\n", rc);
429 return rc;
430 }
431
432 return 0;
Nicholas Troast34db5032016-03-28 12:26:44 -0700433}
434
Harry Yang1d1034c2016-06-15 12:09:42 -0700435#define PARALLEL_FLOAT_VOLTAGE_DELTA_UV 50000
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700436static int smblib_fv_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -0700437 int fv_uv, const char *client)
Abhijeet Dharmapurikarf9805d42016-05-17 18:38:42 -0700438{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700439 struct smb_charger *chg = data;
Harry Yang1d1034c2016-06-15 12:09:42 -0700440 union power_supply_propval pval = {0, };
Abhijeet Dharmapurikarf9805d42016-05-17 18:38:42 -0700441 int rc = 0;
442
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700443 if (fv_uv < 0) {
444 smblib_dbg(chg, PR_MISC, "No Voter\n");
445 return 0;
446 }
447
Abhijeet Dharmapurikarf9805d42016-05-17 18:38:42 -0700448 rc = smblib_set_charge_param(chg, &chg->param.fv, fv_uv);
Harry Yang1d1034c2016-06-15 12:09:42 -0700449 if (rc < 0) {
450 dev_err(chg->dev,
451 "Couldn't set floating voltage rc=%d\n", rc);
452 return rc;
453 }
454
Harry Yang58a9e7a2016-06-23 14:54:43 -0700455 if (chg->mode == PARALLEL_MASTER && chg->pl.psy) {
Harry Yang1d1034c2016-06-15 12:09:42 -0700456 pval.intval = fv_uv + PARALLEL_FLOAT_VOLTAGE_DELTA_UV;
457 rc = power_supply_set_property(chg->pl.psy,
458 POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval);
459 if (rc < 0) {
460 dev_err(chg->dev,
461 "Couldn't set float on parallel rc=%d\n", rc);
462 return rc;
463 }
464 }
465
466 return 0;
Abhijeet Dharmapurikarf9805d42016-05-17 18:38:42 -0700467}
468
Nicholas Troast34db5032016-03-28 12:26:44 -0700469#define USBIN_25MA 25000
470#define USBIN_100MA 100000
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700471static int smblib_usb_icl_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -0700472 int icl_ua, const char *client)
Nicholas Troast34db5032016-03-28 12:26:44 -0700473{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700474 struct smb_charger *chg = data;
Nicholas Troast34db5032016-03-28 12:26:44 -0700475 int rc = 0;
476 bool suspend;
477
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700478 if (icl_ua < 0) {
479 smblib_dbg(chg, PR_MISC, "No Voter hence suspending\n");
480 icl_ua = 0;
481 }
482
Nicholas Troast34db5032016-03-28 12:26:44 -0700483 suspend = (icl_ua < USBIN_25MA);
484 if (suspend)
485 goto suspend;
486
487 if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)
488 rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
489 USB51_MODE_BIT,
490 (icl_ua > USBIN_100MA) ? USB51_MODE_BIT : 0);
491 else
492 rc = smblib_set_charge_param(chg, &chg->param.usb_icl, icl_ua);
493
494 if (rc < 0) {
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700495 dev_err(chg->dev,
496 "Couldn't set USB input current limit rc=%d\n", rc);
Nicholas Troast34db5032016-03-28 12:26:44 -0700497 return rc;
498 }
499
500suspend:
501 rc = vote(chg->usb_suspend_votable, PD_VOTER, suspend, 0);
502 if (rc < 0) {
503 dev_err(chg->dev, "Couldn't %s input rc=%d\n",
504 suspend ? "suspend" : "resume", rc);
505 return rc;
506 }
507
508 return rc;
509}
510
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700511static int smblib_dc_icl_vote_callback(struct votable *votable, void *data,
Abhijeet Dharmapurikarebb5e5c2016-05-17 20:09:16 -0700512 int icl_ua, const char *client)
Nicholas Troast34db5032016-03-28 12:26:44 -0700513{
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -0700514 struct smb_charger *chg = data;
Nicholas Troast34db5032016-03-28 12:26:44 -0700515 int rc = 0;
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700516 bool suspend;
517
518 if (icl_ua < 0) {
519 smblib_dbg(chg, PR_MISC, "No Voter hence suspending\n");
520 icl_ua = 0;
521 }
522
523 suspend = (icl_ua < USBIN_25MA);
524 if (suspend)
525 goto suspend;
Nicholas Troast34db5032016-03-28 12:26:44 -0700526
527 rc = smblib_set_charge_param(chg, &chg->param.dc_icl, icl_ua);
Abhijeet Dharmapurikarc0ff65a2016-06-06 16:45:34 -0700528 if (rc < 0) {
529 dev_err(chg->dev, "Couldn't set DC input current limit rc=%d\n",
530 rc);
531 return rc;
532 }
533
534suspend:
535 rc = vote(chg->dc_suspend_votable, USER_VOTER, suspend, 0);
536 if (rc < 0) {
537 dev_err(chg->dev, "Couldn't vote to %s DC rc=%d\n",
538 suspend ? "suspend" : "resume", rc);
539 return rc;
540 }
Nicholas Troast34db5032016-03-28 12:26:44 -0700541 return rc;
542}
543
Harry Yang223c6282016-06-14 15:48:36 -0700544static int smblib_awake_vote_callback(struct votable *votable, void *data,
545 int awake, const char *client)
546{
547 struct smb_charger *chg = data;
548
549 if (awake)
550 pm_stay_awake(chg->dev);
551 else
552 pm_relax(chg->dev);
553
554 return 0;
555}
556
Harry Yang3c4c22d2016-06-15 11:40:54 -0700557static int smblib_pl_disable_vote_callback(struct votable *votable, void *data,
558 int pl_disable, const char *client)
559{
Harry Yang1d1034c2016-06-15 12:09:42 -0700560 struct smb_charger *chg = data;
561 union power_supply_propval pval = {0, };
562 int rc;
563
Harry Yang58a9e7a2016-06-23 14:54:43 -0700564 if (chg->mode != PARALLEL_MASTER || !chg->pl.psy)
Harry Yang1d1034c2016-06-15 12:09:42 -0700565 return 0;
566
567 chg->pl.taper_percent = 100;
568 rerun_election(chg->fv_votable);
569 rerun_election(chg->fcc_votable);
570
571 pval.intval = pl_disable;
572 rc = power_supply_set_property(chg->pl.psy,
573 POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval);
574 if (rc < 0) {
575 dev_err(chg->dev,
576 "Couldn't change slave suspend state rc=%d\n", rc);
577 return rc;
578 }
579
Harry Yang3c4c22d2016-06-15 11:40:54 -0700580 return 0;
581}
582
Nicholas Troast34db5032016-03-28 12:26:44 -0700583/*****************
584 * OTG REGULATOR *
585 *****************/
586
587int smblib_vbus_regulator_enable(struct regulator_dev *rdev)
588{
589 struct smb_charger *chg = rdev_get_drvdata(rdev);
590 int rc = 0;
591
592 rc = regmap_write(chg->regmap, CMD_OTG_REG, OTG_EN_BIT);
593 if (rc < 0)
594 dev_err(chg->dev, "Couldn't enable OTG regulator rc=%d\n", rc);
595
596 return rc;
597}
598
599int smblib_vbus_regulator_disable(struct regulator_dev *rdev)
600{
601 struct smb_charger *chg = rdev_get_drvdata(rdev);
602 int rc = 0;
603
604 rc = regmap_write(chg->regmap, CMD_OTG_REG, 0);
605 if (rc < 0)
606 dev_err(chg->dev, "Couldn't disable OTG regulator rc=%d\n", rc);
607
608 return rc;
609}
610
611int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev)
612{
613 struct smb_charger *chg = rdev_get_drvdata(rdev);
614 int rc = 0;
615 u8 cmd;
616
617 rc = smblib_read(chg, CMD_OTG_REG, &cmd);
618 if (rc < 0) {
619 dev_err(chg->dev, "Couldn't read CMD_OTG rc=%d", rc);
620 return rc;
621 }
622
623 return (cmd & OTG_EN_BIT) ? 1 : 0;
624}
625
626/*******************
627 * VCONN REGULATOR *
628 * *****************/
629
630int smblib_vconn_regulator_enable(struct regulator_dev *rdev)
631{
632 struct smb_charger *chg = rdev_get_drvdata(rdev);
633 int rc = 0;
634
635 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
636 VCONN_EN_VALUE_BIT, VCONN_EN_VALUE_BIT);
637 if (rc < 0)
638 dev_err(chg->dev, "Couldn't enable vconn regulator rc=%d\n",
639 rc);
640
641 return rc;
642}
643
644int smblib_vconn_regulator_disable(struct regulator_dev *rdev)
645{
646 struct smb_charger *chg = rdev_get_drvdata(rdev);
647 int rc = 0;
648
649 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
650 VCONN_EN_VALUE_BIT, 0);
651 if (rc < 0)
652 dev_err(chg->dev, "Couldn't disable vconn regulator rc=%d\n",
653 rc);
654
655 return rc;
656}
657
658int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev)
659{
660 struct smb_charger *chg = rdev_get_drvdata(rdev);
661 int rc = 0;
662 u8 cmd;
663
664 rc = smblib_read(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &cmd);
665 if (rc < 0) {
666 dev_err(chg->dev, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
667 rc);
668 return rc;
669 }
670
671 return (cmd & VCONN_EN_VALUE_BIT) ? 1 : 0;
672}
673
674/********************
675 * BATT PSY GETTERS *
676 ********************/
677
678int smblib_get_prop_input_suspend(struct smb_charger *chg,
679 union power_supply_propval *val)
680{
Harry Yang7db58c22016-06-27 17:58:51 -0700681 val->intval = get_client_vote(chg->usb_suspend_votable, USER_VOTER) &&
682 get_client_vote(chg->dc_suspend_votable, USER_VOTER);
Nicholas Troast34db5032016-03-28 12:26:44 -0700683 return 0;
684}
685
686int smblib_get_prop_batt_present(struct smb_charger *chg,
687 union power_supply_propval *val)
688{
689 int rc;
690 u8 stat;
691
692 rc = smblib_read(chg, BATIF_BASE + INT_RT_STS_OFFSET, &stat);
693 if (rc < 0) {
694 dev_err(chg->dev, "Couldn't read BATIF_INT_RT_STS rc=%d\n",
695 rc);
696 return rc;
697 }
698
699 val->intval = !(stat & (BAT_THERM_OR_ID_MISSING_RT_STS_BIT
700 | BAT_TERMINAL_MISSING_RT_STS_BIT));
701
702 return rc;
703}
704
705int smblib_get_prop_batt_capacity(struct smb_charger *chg,
706 union power_supply_propval *val)
707{
708 val->intval = 50;
709 return 0;
710}
711
712int smblib_get_prop_batt_status(struct smb_charger *chg,
713 union power_supply_propval *val)
714{
715 int rc;
716 u8 stat;
Harry Yang7db58c22016-06-27 17:58:51 -0700717 union power_supply_propval pval = {0, };
Nicholas Troast34db5032016-03-28 12:26:44 -0700718
Harry Yang7db58c22016-06-27 17:58:51 -0700719 smblib_get_prop_input_suspend(chg, &pval);
720 if (pval.intval) {
721 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
Nicholas Troast34db5032016-03-28 12:26:44 -0700722 return rc;
723 }
724
Harry Yang7db58c22016-06-27 17:58:51 -0700725 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
726 if (rc < 0) {
727 dev_err(chg->dev, "Couldn't read POWER_PATH_STATUS rc=%d\n",
728 rc);
729 return rc;
730 }
731
732 if (!(stat & (USE_USBIN_BIT | USE_DCIN_BIT)) ||
733 !(stat & VALID_INPUT_POWER_SOURCE_BIT)) {
Nicholas Troast34db5032016-03-28 12:26:44 -0700734 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
735 return rc;
736 }
737
738 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
739 if (rc < 0) {
740 dev_err(chg->dev, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
741 rc);
742 return rc;
743 }
744 smblib_dbg(chg, PR_REGISTER, "BATTERY_CHARGER_STATUS_1 = 0x%02x\n",
745 stat);
746
747 stat = stat & BATTERY_CHARGER_STATUS_MASK;
Harry Yang7db58c22016-06-27 17:58:51 -0700748 if (stat >= COMPLETED_CHARGE)
Nicholas Troast34db5032016-03-28 12:26:44 -0700749 val->intval = POWER_SUPPLY_STATUS_FULL;
750 else
751 val->intval = POWER_SUPPLY_STATUS_CHARGING;
752
753 return rc;
754}
755
756int smblib_get_prop_batt_charge_type(struct smb_charger *chg,
757 union power_supply_propval *val)
758{
759 int rc;
760 u8 stat;
761
762 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
763 if (rc < 0) {
764 dev_err(chg->dev, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
765 rc);
766 return rc;
767 }
768 smblib_dbg(chg, PR_REGISTER, "BATTERY_CHARGER_STATUS_1 = 0x%02x\n",
769 stat);
770
771 switch (stat & BATTERY_CHARGER_STATUS_MASK) {
772 case TRICKLE_CHARGE:
773 case PRE_CHARGE:
774 val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
775 break;
776 case FAST_CHARGE:
777 case FULLON_CHARGE:
778 val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
779 break;
780 case TAPER_CHARGE:
781 val->intval = POWER_SUPPLY_CHARGE_TYPE_TAPER;
782 break;
783 default:
784 val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
785 }
786
787 return rc;
788}
789
790int smblib_get_prop_batt_health(struct smb_charger *chg,
791 union power_supply_propval *val)
792{
793 int rc;
794 u8 stat;
795
796 rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat);
797 if (rc < 0) {
798 dev_err(chg->dev, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
799 rc);
800 return rc;
801 }
802 smblib_dbg(chg, PR_REGISTER, "BATTERY_CHARGER_STATUS_2 = 0x%02x\n",
803 stat);
804
805 if (stat & CHARGER_ERROR_STATUS_BAT_OV_BIT) {
806 dev_err(chg->dev, "battery over-voltage\n");
807 val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
808 goto done;
809 }
810
Harry Yang668fc5e2016-07-12 16:51:47 -0700811 if (stat & BAT_TEMP_STATUS_TOO_COLD_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -0700812 val->intval = POWER_SUPPLY_HEALTH_COLD;
Harry Yang668fc5e2016-07-12 16:51:47 -0700813 else if (stat & BAT_TEMP_STATUS_TOO_HOT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -0700814 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
Harry Yang668fc5e2016-07-12 16:51:47 -0700815 else if (stat & BAT_TEMP_STATUS_COLD_SOFT_LIMIT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -0700816 val->intval = POWER_SUPPLY_HEALTH_COOL;
Harry Yang668fc5e2016-07-12 16:51:47 -0700817 else if (stat & BAT_TEMP_STATUS_HOT_SOFT_LIMIT_BIT)
Nicholas Troast34db5032016-03-28 12:26:44 -0700818 val->intval = POWER_SUPPLY_HEALTH_WARM;
Harry Yang668fc5e2016-07-12 16:51:47 -0700819 else
Nicholas Troast34db5032016-03-28 12:26:44 -0700820 val->intval = POWER_SUPPLY_HEALTH_GOOD;
Nicholas Troast34db5032016-03-28 12:26:44 -0700821
822done:
823 return rc;
824}
825
826/***********************
827 * BATTERY PSY SETTERS *
828 ***********************/
829
830int smblib_set_prop_input_suspend(struct smb_charger *chg,
831 const union power_supply_propval *val)
832{
833 int rc;
834
835 rc = vote(chg->usb_suspend_votable, USER_VOTER, (bool)val->intval, 0);
836 if (rc < 0) {
837 dev_err(chg->dev, "Couldn't vote to %s USB rc=%d\n",
838 (bool)val->intval ? "suspend" : "resume", rc);
839 return rc;
840 }
841
842 rc = vote(chg->dc_suspend_votable, USER_VOTER, (bool)val->intval, 0);
843 if (rc < 0) {
844 dev_err(chg->dev, "Couldn't vote to %s DC rc=%d\n",
845 (bool)val->intval ? "suspend" : "resume", rc);
846 return rc;
847 }
848
Nicholas Troast61ff40f2016-07-08 10:59:22 -0700849 power_supply_changed(chg->batt_psy);
Nicholas Troast34db5032016-03-28 12:26:44 -0700850 return rc;
851}
852
853/*******************
854 * USB PSY GETTERS *
855 *******************/
856
857int smblib_get_prop_usb_present(struct smb_charger *chg,
858 union power_supply_propval *val)
859{
860 int rc = 0;
861 u8 stat;
862
863 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
864 if (rc < 0) {
865 dev_err(chg->dev, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
866 rc);
867 return rc;
868 }
869 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n",
870 stat);
871
872 val->intval = (bool)(stat & CC_ATTACHED_BIT);
873
874 return rc;
875}
876
877int smblib_get_prop_usb_online(struct smb_charger *chg,
878 union power_supply_propval *val)
879{
880 int rc = 0;
881 u8 stat;
882
883 if (get_client_vote(chg->usb_suspend_votable, USER_VOTER)) {
884 val->intval = false;
885 return rc;
886 }
887
888 rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
889 if (rc < 0) {
890 dev_err(chg->dev, "Couldn't read POWER_PATH_STATUS rc=%d\n",
891 rc);
892 return rc;
893 }
894 smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
895 stat);
896
897 val->intval = (stat & USE_USBIN_BIT) &&
898 (stat & VALID_INPUT_POWER_SOURCE_BIT);
899
900 return rc;
901}
902
903int smblib_get_prop_usb_voltage_now(struct smb_charger *chg,
904 union power_supply_propval *val)
905{
906 if (chg->vbus_present)
907 val->intval = MICRO_5V;
908 else
909 val->intval = 0;
910
911 return 0;
912}
913
914int smblib_get_prop_usb_current_max(struct smb_charger *chg,
915 union power_supply_propval *val)
916{
917 val->intval = get_effective_result_locked(chg->usb_icl_votable);
918 return 0;
919}
920
921int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
922 union power_supply_propval *val)
923{
924 int rc = 0;
925 u8 stat;
926
927 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
928 if (rc < 0) {
929 dev_err(chg->dev, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
930 rc);
931 return rc;
932 }
933 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n",
934 stat);
935
936 if (stat & CC_ATTACHED_BIT)
937 val->intval = (bool)(stat & CC_ORIENTATION_BIT) + 1;
938 else
939 val->intval = 0;
940
941 return rc;
942}
943
944static const char * const smblib_typec_mode_name[] = {
945 [POWER_SUPPLY_TYPEC_NONE] = "NONE",
946 [POWER_SUPPLY_TYPEC_SOURCE_DEFAULT] = "SOURCE_DEFAULT",
947 [POWER_SUPPLY_TYPEC_SOURCE_MEDIUM] = "SOURCE_MEDIUM",
948 [POWER_SUPPLY_TYPEC_SOURCE_HIGH] = "SOURCE_HIGH",
949 [POWER_SUPPLY_TYPEC_NON_COMPLIANT] = "NON_COMPLIANT",
950 [POWER_SUPPLY_TYPEC_SINK] = "SINK",
951 [POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE] = "SINK_POWERED_CABLE",
952 [POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY] = "SINK_DEBUG_ACCESSORY",
953 [POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER] = "SINK_AUDIO_ADAPTER",
954 [POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY] = "POWERED_CABLE_ONLY",
955};
956
957static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
958{
959 int rc;
960 u8 stat;
961
962 rc = smblib_read(chg, TYPE_C_STATUS_1_REG, &stat);
963 if (rc < 0) {
964 dev_err(chg->dev, "Couldn't read TYPE_C_STATUS_1 rc=%d\n", rc);
965 return POWER_SUPPLY_TYPEC_NONE;
966 }
967 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_1 = 0x%02x\n", stat);
968
969 switch (stat) {
970 case 0:
971 return POWER_SUPPLY_TYPEC_NONE;
972 case UFP_TYPEC_RDSTD_BIT:
973 return POWER_SUPPLY_TYPEC_SOURCE_DEFAULT;
974 case UFP_TYPEC_RD1P5_BIT:
975 return POWER_SUPPLY_TYPEC_SOURCE_MEDIUM;
976 case UFP_TYPEC_RD3P0_BIT:
977 return POWER_SUPPLY_TYPEC_SOURCE_HIGH;
978 default:
979 break;
980 }
981
982 return POWER_SUPPLY_TYPEC_NON_COMPLIANT;
983}
984
985static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
986{
987 int rc;
988 u8 stat;
989
990 rc = smblib_read(chg, TYPE_C_STATUS_2_REG, &stat);
991 if (rc < 0) {
992 dev_err(chg->dev, "Couldn't read TYPE_C_STATUS_2 rc=%d\n", rc);
993 return POWER_SUPPLY_TYPEC_NONE;
994 }
995 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_2 = 0x%02x\n", stat);
996
997 switch (stat & DFP_TYPEC_MASK) {
998 case DFP_RA_RA_BIT:
999 return POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER;
1000 case DFP_RD_RD_BIT:
1001 return POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY;
1002 case DFP_RD_RA_VCONN_BIT:
1003 return POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE;
1004 case DFP_RD_OPEN_BIT:
1005 return POWER_SUPPLY_TYPEC_SINK;
1006 case DFP_RA_OPEN_BIT:
1007 return POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY;
1008 default:
1009 break;
1010 }
1011
1012 return POWER_SUPPLY_TYPEC_NONE;
1013}
1014
1015int smblib_get_prop_typec_mode(struct smb_charger *chg,
1016 union power_supply_propval *val)
1017{
1018 int rc;
1019 u8 stat;
1020
1021 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
1022 if (rc < 0) {
1023 dev_err(chg->dev, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
1024 val->intval = POWER_SUPPLY_TYPEC_NONE;
1025 return rc;
1026 }
1027 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat);
1028
1029 if (!(stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT)) {
1030 val->intval = POWER_SUPPLY_TYPEC_NONE;
1031 return rc;
1032 }
1033
1034 if (stat & UFP_DFP_MODE_STATUS_BIT)
1035 val->intval = smblib_get_prop_dfp_mode(chg);
1036 else
1037 val->intval = smblib_get_prop_ufp_mode(chg);
1038
1039 return rc;
1040}
1041
1042int smblib_get_prop_typec_power_role(struct smb_charger *chg,
1043 union power_supply_propval *val)
1044{
1045 int rc = 0;
1046 u8 ctrl;
1047
1048 rc = smblib_read(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &ctrl);
1049 if (rc < 0) {
1050 dev_err(chg->dev, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
1051 rc);
1052 return rc;
1053 }
1054 smblib_dbg(chg, PR_REGISTER, "TYPE_C_INTRPT_ENB_SOFTWARE_CTRL = 0x%02x\n",
1055 ctrl);
1056
1057 if (ctrl & TYPEC_DISABLE_CMD_BIT) {
1058 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
1059 return rc;
1060 }
1061
1062 switch (ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT)) {
1063 case 0:
1064 val->intval = POWER_SUPPLY_TYPEC_PR_DUAL;
1065 break;
1066 case DFP_EN_CMD_BIT:
1067 val->intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
1068 break;
1069 case UFP_EN_CMD_BIT:
1070 val->intval = POWER_SUPPLY_TYPEC_PR_SINK;
1071 break;
1072 default:
1073 val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
1074 dev_err(chg->dev, "unsupported power role 0x%02lx\n",
1075 ctrl & (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT));
1076 return -EINVAL;
1077 }
1078
1079 return rc;
1080}
1081
1082int smblib_get_prop_pd_allowed(struct smb_charger *chg,
1083 union power_supply_propval *val)
1084{
1085 val->intval = get_effective_result_locked(chg->pd_allowed_votable);
1086 return 0;
1087}
1088
Nicholas Troast133a7f52016-06-29 13:48:20 -07001089int smblib_get_prop_input_current_settled(struct smb_charger *chg,
1090 union power_supply_propval *val)
1091{
1092 return smblib_get_charge_param(chg, &chg->param.icl_stat, &val->intval);
1093}
1094
Nicholas Troast34db5032016-03-28 12:26:44 -07001095/*******************
1096 * USB PSY SETTERS *
1097 * *****************/
1098
1099int smblib_set_prop_usb_current_max(struct smb_charger *chg,
1100 const union power_supply_propval *val)
1101{
1102 int rc;
1103
1104 rc = vote(chg->usb_icl_votable, PD_VOTER, true, val->intval);
1105 return rc;
1106}
1107
1108int smblib_set_prop_typec_power_role(struct smb_charger *chg,
1109 const union power_supply_propval *val)
1110{
1111 int rc = 0;
1112 u8 power_role;
1113
1114 switch (val->intval) {
1115 case POWER_SUPPLY_TYPEC_PR_NONE:
1116 power_role = TYPEC_DISABLE_CMD_BIT;
1117 break;
1118 case POWER_SUPPLY_TYPEC_PR_DUAL:
1119 power_role = 0;
1120 break;
1121 case POWER_SUPPLY_TYPEC_PR_SINK:
1122 power_role = UFP_EN_CMD_BIT;
1123 break;
1124 case POWER_SUPPLY_TYPEC_PR_SOURCE:
1125 power_role = DFP_EN_CMD_BIT;
1126 break;
1127 default:
1128 dev_err(chg->dev, "power role %d not supported\n", val->intval);
1129 return -EINVAL;
1130 }
1131
1132 rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
1133 TYPEC_POWER_ROLE_CMD_MASK, power_role);
1134 if (rc < 0) {
1135 dev_err(chg->dev, "Couldn't write 0x%02x to TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
1136 power_role, rc);
1137 return rc;
1138 }
1139
1140 return rc;
1141}
1142
1143int smblib_set_prop_usb_voltage_min(struct smb_charger *chg,
1144 const union power_supply_propval *val)
1145{
1146 int rc, min_uv;
1147
1148 min_uv = min(val->intval, chg->voltage_max_uv);
1149 rc = smblib_set_usb_pd_allowed_voltage(chg, min_uv,
1150 chg->voltage_max_uv);
1151 if (rc < 0) {
1152 dev_err(chg->dev, "invalid max voltage %duV rc=%d\n",
1153 val->intval, rc);
1154 return rc;
1155 }
1156
1157 chg->voltage_min_uv = val->intval;
1158 return rc;
1159}
1160
1161int smblib_set_prop_usb_voltage_max(struct smb_charger *chg,
1162 const union power_supply_propval *val)
1163{
1164 int rc, max_uv;
1165
1166 max_uv = max(val->intval, chg->voltage_min_uv);
1167 rc = smblib_set_usb_pd_allowed_voltage(chg, chg->voltage_min_uv,
1168 max_uv);
1169 if (rc < 0) {
1170 dev_err(chg->dev, "invalid min voltage %duV rc=%d\n",
1171 val->intval, rc);
1172 return rc;
1173 }
1174
1175 chg->voltage_max_uv = val->intval;
1176 return rc;
1177}
1178
1179int smblib_set_prop_pd_active(struct smb_charger *chg,
1180 const union power_supply_propval *val)
1181{
1182 int rc;
1183
1184 if (!get_effective_result(chg->pd_allowed_votable)) {
1185 dev_err(chg->dev, "PD is not allowed\n");
1186 return -EINVAL;
1187 }
1188
1189 rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
1190 AUTO_SRC_DETECT_BIT,
1191 val->intval ? 0 : AUTO_SRC_DETECT_BIT);
1192 if (rc < 0) {
1193 dev_err(chg->dev, "Couldn't %s APSD rc=%d\n",
1194 val->intval ? "disable" : "enable", rc);
1195 return rc;
1196 }
1197
1198 vote(chg->pd_allowed_votable, PD_VOTER, val->intval, 0);
1199
1200 chg->pd_active = (bool)val->intval;
Harry Yang6607b4a2016-05-17 17:50:09 -07001201 smblib_update_usb_type(chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07001202 return rc;
1203}
1204
1205/**********************
1206 * INTERRUPT HANDLERS *
1207 **********************/
1208
1209irqreturn_t smblib_handle_debug(int irq, void *data)
1210{
1211 struct smb_irq_data *irq_data = data;
1212 struct smb_charger *chg = irq_data->parent_data;
1213
1214 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
1215
1216 return IRQ_HANDLED;
1217}
1218
Harry Yang6fe72ab2016-06-14 16:21:39 -07001219irqreturn_t smblib_handle_chg_state_change(int irq, void *data)
1220{
1221 struct smb_irq_data *irq_data = data;
1222 struct smb_charger *chg = irq_data->parent_data;
Harry Yang1d1034c2016-06-15 12:09:42 -07001223 union power_supply_propval pval = {0, };
1224 int rc;
Harry Yang6fe72ab2016-06-14 16:21:39 -07001225
1226 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
1227
Harry Yang58a9e7a2016-06-23 14:54:43 -07001228 if (chg->mode != PARALLEL_MASTER)
Harry Yang1d1034c2016-06-15 12:09:42 -07001229 return IRQ_HANDLED;
1230
1231 rc = smblib_get_prop_batt_charge_type(chg, &pval);
1232 if (rc < 0) {
1233 dev_err(chg->dev, "Couldn't get batt charge type rc=%d\n", rc);
1234 return IRQ_HANDLED;
1235 }
1236
1237 if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_FAST)
1238 vote(chg->pl_disable_votable, CHG_STATE_VOTER, false, 0);
1239
1240 if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER
1241 && !get_effective_result_locked(chg->pl_disable_votable)) {
1242 cancel_delayed_work_sync(&chg->pl_taper_work);
1243 schedule_delayed_work(&chg->pl_taper_work, 0);
1244 }
1245
1246 rc = smblib_get_prop_batt_status(chg, &pval);
1247 if (rc < 0) {
1248 dev_err(chg->dev, "Couldn't get batt status type rc=%d\n", rc);
1249 return IRQ_HANDLED;
1250 }
1251 if (pval.intval == POWER_SUPPLY_STATUS_FULL)
1252 vote(chg->pl_disable_votable, TAPER_END_VOTER, false, 0);
1253
Harry Yang6fe72ab2016-06-14 16:21:39 -07001254 return IRQ_HANDLED;
1255}
1256
Nicholas Troast34db5032016-03-28 12:26:44 -07001257irqreturn_t smblib_handle_batt_psy_changed(int irq, void *data)
1258{
1259 struct smb_irq_data *irq_data = data;
1260 struct smb_charger *chg = irq_data->parent_data;
1261
1262 smblib_handle_debug(irq, data);
1263 power_supply_changed(chg->batt_psy);
1264 return IRQ_HANDLED;
1265}
1266
1267irqreturn_t smblib_handle_usb_psy_changed(int irq, void *data)
1268{
1269 struct smb_irq_data *irq_data = data;
1270 struct smb_charger *chg = irq_data->parent_data;
1271
1272 smblib_handle_debug(irq, data);
1273 power_supply_changed(chg->usb_psy);
1274 return IRQ_HANDLED;
1275}
1276
1277irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
1278{
1279 struct smb_irq_data *irq_data = data;
1280 struct smb_charger *chg = irq_data->parent_data;
1281 int rc;
1282 u8 stat;
1283
1284 rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
1285 if (rc < 0) {
1286 dev_err(chg->dev, "Couldn't read USB_INT_RT_STS rc=%d\n",
1287 rc);
1288 return IRQ_HANDLED;
1289 }
1290
1291 chg->vbus_present = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
1292
1293 /* fetch the DPDM regulator */
1294 if (!chg->dpdm_reg && of_get_property(chg->dev->of_node,
1295 "dpdm-supply", NULL)) {
1296 chg->dpdm_reg = devm_regulator_get(chg->dev, "dpdm");
1297 if (IS_ERR(chg->dpdm_reg)) {
1298 dev_err(chg->dev, "Couldn't get dpdm regulator rc=%ld\n",
1299 PTR_ERR(chg->dpdm_reg));
1300 chg->dpdm_reg = NULL;
1301 }
1302 }
1303
1304 if (!chg->dpdm_reg)
1305 goto skip_dpdm_float;
1306
1307 if (chg->vbus_present && !regulator_is_enabled(chg->dpdm_reg)) {
1308 smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n");
1309 rc = regulator_enable(chg->dpdm_reg);
1310 if (rc < 0)
1311 dev_err(chg->dev, "Couldn't enable dpdm regulator rc=%d\n",
1312 rc);
1313 } else if (regulator_is_enabled(chg->dpdm_reg)) {
1314 smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n");
1315 rc = regulator_disable(chg->dpdm_reg);
1316 if (rc < 0)
1317 dev_err(chg->dev, "Couldn't disable dpdm regulator rc=%d\n",
1318 rc);
1319 }
1320
1321skip_dpdm_float:
1322 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n",
1323 irq_data->name, chg->vbus_present ? "attached" : "detached");
1324 return IRQ_HANDLED;
1325}
1326
Harry Yang1d1034c2016-06-15 12:09:42 -07001327#define MICRO_5P5V 5500000
1328#define USB_WEAK_INPUT_MA 1500000
1329static bool is_icl_pl_ready(struct smb_charger *chg)
1330{
1331 union power_supply_propval pval = {0, };
1332 int icl_ma;
1333 int rc;
1334
1335 rc = smblib_get_prop_usb_voltage_now(chg, &pval);
1336 if (rc < 0) {
1337 dev_err(chg->dev, "Couldn't get prop usb voltage rc=%d\n", rc);
1338 return false;
1339 }
1340
1341 if (pval.intval <= MICRO_5P5V) {
1342 rc = smblib_get_charge_param(chg,
1343 &chg->param.icl_stat, &icl_ma);
1344 if (rc < 0) {
1345 dev_err(chg->dev, "Couldn't get ICL status rc=%d\n",
1346 rc);
1347 return false;
1348 }
1349
1350 if (icl_ma < USB_WEAK_INPUT_MA)
1351 return false;
1352 }
1353
1354 /*
1355 * Always enable parallel charging when USB INPUT is higher than 5V
1356 * regardless of the AICL results. Assume chargers above 5V are strong
1357 */
1358
1359 return true;
1360}
1361
Harry Yang6fe72ab2016-06-14 16:21:39 -07001362irqreturn_t smblib_handle_icl_change(int irq, void *data)
1363{
1364 struct smb_irq_data *irq_data = data;
1365 struct smb_charger *chg = irq_data->parent_data;
1366
Harry Yang1d1034c2016-06-15 12:09:42 -07001367 if (chg->mode == PARALLEL_MASTER)
1368 vote(chg->pl_disable_votable, USBIN_ICL_VOTER,
1369 !is_icl_pl_ready(chg), 0);
1370
Harry Yang6fe72ab2016-06-14 16:21:39 -07001371 smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
1372
1373 return IRQ_HANDLED;
1374}
1375
Nicholas Troast34db5032016-03-28 12:26:44 -07001376static void smblib_handle_slow_plugin_timeout(struct smb_charger *chg,
1377 bool rising)
1378{
1379 smblib_dbg(chg, PR_INTERRUPT, "IRQ: slow-plugin-timeout %s\n",
1380 rising ? "rising" : "falling");
1381}
1382
1383static void smblib_handle_sdp_enumeration_done(struct smb_charger *chg,
1384 bool rising)
1385{
1386 smblib_dbg(chg, PR_INTERRUPT, "IRQ: sdp-enumeration-done %s\n",
1387 rising ? "rising" : "falling");
1388}
1389
1390static void smblib_handle_adaptive_voltage_done(struct smb_charger *chg,
1391 bool rising)
1392{
1393 smblib_dbg(chg, PR_INTERRUPT, "IRQ: adaptive-voltage-done %s\n",
1394 rising ? "rising" : "falling");
1395}
1396
1397/* triggers when HVDCP 3.0 authentication has finished */
1398static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
1399 bool rising)
1400{
1401 const struct apsd_result *apsd_result;
1402
1403 if (!rising)
1404 return;
1405
1406 /* the APSD done handler will set the USB supply type */
1407 apsd_result = smblib_get_apsd_result(chg);
1408 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n",
1409 apsd_result->name);
1410}
1411
1412/* triggers when HVDCP is detected */
1413static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg,
1414 bool rising)
1415{
1416 if (!rising)
1417 return;
1418
1419 /* the APSD done handler will set the USB supply type */
1420 cancel_delayed_work_sync(&chg->hvdcp_detect_work);
1421 smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-detect-done %s\n",
1422 rising ? "rising" : "falling");
1423}
1424
1425#define HVDCP_DET_MS 2500
1426static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
1427{
1428 int rc;
1429 const struct apsd_result *apsd_result;
1430
1431 if (!rising)
1432 return;
1433
1434 apsd_result = smblib_get_apsd_result(chg);
1435 switch (apsd_result->bit) {
1436 case SDP_CHARGER_BIT:
1437 case CDP_CHARGER_BIT:
1438 case OCP_CHARGER_BIT:
1439 case FLOAT_CHARGER_BIT:
1440 vote(chg->pd_allowed_votable, DEFAULT_VOTER, true, 0);
1441 break;
1442 case DCP_CHARGER_BIT:
1443 schedule_delayed_work(&chg->hvdcp_detect_work,
1444 msecs_to_jiffies(HVDCP_DET_MS));
1445 break;
1446 default:
1447 break;
1448 }
1449
1450 rc = smblib_update_usb_type(chg);
1451 if (rc < 0)
1452 dev_err(chg->dev, "Couldn't update usb type rc=%d\n", rc);
1453
1454 smblib_dbg(chg, PR_INTERRUPT, "IRQ: apsd-done rising; %s detected\n",
1455 apsd_result->name);
1456}
1457
1458irqreturn_t smblib_handle_usb_source_change(int irq, void *data)
1459{
1460 struct smb_irq_data *irq_data = data;
1461 struct smb_charger *chg = irq_data->parent_data;
1462 int rc = 0;
1463 u8 stat;
1464
1465 rc = smblib_read(chg, APSD_STATUS_REG, &stat);
1466 if (rc < 0) {
1467 dev_err(chg->dev, "Couldn't read APSD_STATUS rc=%d\n", rc);
1468 return IRQ_HANDLED;
1469 }
1470 smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
1471
1472 smblib_handle_apsd_done(chg,
1473 (bool)(stat & APSD_DTC_STATUS_DONE_BIT));
1474
1475 smblib_handle_hvdcp_detect_done(chg,
1476 (bool)(stat & QC_CHARGER_BIT));
1477
1478 smblib_handle_hvdcp_3p0_auth_done(chg,
1479 (bool)(stat & QC_AUTH_DONE_STATUS_BIT));
1480
1481 smblib_handle_adaptive_voltage_done(chg,
1482 (bool)(stat & VADP_CHANGE_DONE_AFTER_AUTH_BIT));
1483
1484 smblib_handle_sdp_enumeration_done(chg,
1485 (bool)(stat & ENUMERATION_DONE_BIT));
1486
1487 smblib_handle_slow_plugin_timeout(chg,
1488 (bool)(stat & SLOW_PLUGIN_TIMEOUT_BIT));
1489
1490 power_supply_changed(chg->usb_psy);
1491
1492 return IRQ_HANDLED;
1493}
1494
1495static void smblib_handle_typec_cc(struct smb_charger *chg, bool attached)
1496{
1497 int rc;
1498
1499 if (!attached) {
1500 rc = smblib_detach_usb(chg);
1501 if (rc < 0)
1502 dev_err(chg->dev, "Couldn't detach USB rc=%d\n", rc);
1503 }
1504
1505 smblib_dbg(chg, PR_INTERRUPT, "IRQ: CC %s\n",
1506 attached ? "attached" : "detached");
1507}
1508
1509static void smblib_handle_typec_debounce_done(struct smb_charger *chg,
1510 bool rising, bool sink_attached)
1511{
1512 int rc;
1513 union power_supply_propval pval = {0, };
1514
1515 /* allow PD for attached sinks */
1516 if (rising && sink_attached)
1517 vote(chg->pd_allowed_votable, DEFAULT_VOTER, true, 0);
1518
1519 rc = smblib_get_prop_typec_mode(chg, &pval);
1520 if (rc < 0)
1521 dev_err(chg->dev, "Couldn't get prop typec mode rc=%d\n", rc);
1522
Harry Yang1d1034c2016-06-15 12:09:42 -07001523 /*
1524 * vote to enable parallel charging if a source is attached, and disable
1525 * otherwise
1526 */
1527 vote(chg->pl_disable_votable, TYPEC_SRC_VOTER,
1528 !rising || sink_attached, 0);
1529
1530 /* reset taper_end voter here */
1531 if (!rising || sink_attached)
1532 vote(chg->pl_disable_votable, TAPER_END_VOTER, false, 0);
1533
Nicholas Troast34db5032016-03-28 12:26:44 -07001534 smblib_dbg(chg, PR_INTERRUPT, "IRQ: debounce-done %s; Type-C %s detected\n",
1535 rising ? "rising" : "falling",
1536 smblib_typec_mode_name[pval.intval]);
1537}
1538
1539irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
1540{
1541 struct smb_irq_data *irq_data = data;
1542 struct smb_charger *chg = irq_data->parent_data;
1543 int rc;
1544 u8 stat;
1545
1546 rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
1547 if (rc < 0) {
1548 dev_err(chg->dev, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
1549 rc);
1550 return IRQ_HANDLED;
1551 }
1552 smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat);
1553
1554 if (stat & TYPEC_VBUS_ERROR_STATUS_BIT) {
1555 dev_err(chg->dev, "IRQ: vbus-error rising\n");
1556 return IRQ_HANDLED;
1557 }
1558
1559 smblib_handle_typec_cc(chg,
1560 (bool)(stat & CC_ATTACHED_BIT));
1561 smblib_handle_typec_debounce_done(chg,
1562 (bool)(stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT),
1563 (bool)(stat & UFP_DFP_MODE_STATUS_BIT));
1564
1565 power_supply_changed(chg->usb_psy);
1566
1567 return IRQ_HANDLED;
1568}
1569
1570/***************
1571 * Work Queues *
1572 ***************/
1573
1574static void smblib_hvdcp_detect_work(struct work_struct *work)
1575{
1576 struct smb_charger *chg = container_of(work, struct smb_charger,
1577 hvdcp_detect_work.work);
1578 const struct apsd_result *apsd_result;
1579
1580 apsd_result = smblib_get_apsd_result(chg);
1581 if (apsd_result->bit &&
1582 !(apsd_result->bit & (QC_2P0_BIT | QC_3P0_BIT))) {
1583 vote(chg->pd_allowed_votable, DEFAULT_VOTER, true, 0);
1584 power_supply_changed(chg->usb_psy);
1585 }
1586}
1587
Harry Yang58a9e7a2016-06-23 14:54:43 -07001588static void smblib_pl_detect_work(struct work_struct *work)
1589{
1590 struct smb_charger *chg = container_of(work, struct smb_charger,
1591 pl_detect_work);
1592
1593 power_supply_unreg_notifier(&chg->pl.nb);
1594
1595 if (!get_effective_result_locked(chg->pl_disable_votable))
1596 rerun_election(chg->pl_disable_votable);
1597}
1598
Harry Yang1d1034c2016-06-15 12:09:42 -07001599#define MINIMUM_PARALLEL_FCC_UA 500000
1600#define PL_TAPER_WORK_DELAY_MS 100
1601#define TAPER_RESIDUAL_PERCENT 75
1602static void smblib_pl_taper_work(struct work_struct *work)
1603{
1604 struct smb_charger *chg = container_of(work, struct smb_charger,
1605 pl_taper_work.work);
1606 union power_supply_propval pval = {0, };
1607 int rc;
1608
1609 if (chg->pl.slave_fcc < MINIMUM_PARALLEL_FCC_UA) {
1610 vote(chg->pl_disable_votable, TAPER_END_VOTER, true, 0);
1611 goto done;
1612 }
1613
1614 rc = smblib_get_prop_batt_charge_type(chg, &pval);
1615 if (rc < 0) {
1616 dev_err(chg->dev, "Couldn't get batt charge type rc=%d\n", rc);
1617 goto done;
1618 }
1619
1620 if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER) {
1621 vote(chg->awake_votable, PL_VOTER, true, 0);
1622 /* Reduce the taper percent by 25 percent */
1623 chg->pl.taper_percent = chg->pl.taper_percent
1624 * TAPER_RESIDUAL_PERCENT / 100;
1625 rerun_election(chg->fcc_votable);
1626 schedule_delayed_work(&chg->pl_taper_work,
1627 msecs_to_jiffies(PL_TAPER_WORK_DELAY_MS));
1628 return;
1629 }
1630
1631 /*
1632 * Master back to Fast Charge, get out of this round of taper reduction
1633 */
1634done:
1635 vote(chg->awake_votable, PL_VOTER, false, 0);
1636}
1637
Nicholas Troast320839e2016-06-03 10:18:00 -07001638int smblib_create_votables(struct smb_charger *chg)
Nicholas Troast34db5032016-03-28 12:26:44 -07001639{
1640 int rc = 0;
1641
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001642 chg->usb_suspend_votable = create_votable("INPUT_SUSPEND", VOTE_SET_ANY,
1643 smblib_usb_suspend_vote_callback,
1644 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07001645 if (IS_ERR(chg->usb_suspend_votable)) {
1646 rc = PTR_ERR(chg->usb_suspend_votable);
1647 return rc;
1648 }
1649
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001650 chg->dc_suspend_votable = create_votable("DC_SUSPEND", VOTE_SET_ANY,
1651 smblib_dc_suspend_vote_callback,
1652 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07001653 if (IS_ERR(chg->dc_suspend_votable)) {
1654 rc = PTR_ERR(chg->dc_suspend_votable);
1655 return rc;
1656 }
1657
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001658 chg->fcc_votable = create_votable("FCC", VOTE_MAX,
1659 smblib_fcc_vote_callback,
1660 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07001661 if (IS_ERR(chg->fcc_votable)) {
1662 rc = PTR_ERR(chg->fcc_votable);
1663 return rc;
1664 }
1665
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001666 chg->fv_votable = create_votable("FV", VOTE_MAX,
1667 smblib_fv_vote_callback,
1668 chg);
Abhijeet Dharmapurikarf9805d42016-05-17 18:38:42 -07001669 if (IS_ERR(chg->fv_votable)) {
1670 rc = PTR_ERR(chg->fv_votable);
1671 return rc;
1672 }
1673
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001674 chg->usb_icl_votable = create_votable("USB_ICL", VOTE_MIN,
1675 smblib_usb_icl_vote_callback,
1676 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07001677 if (IS_ERR(chg->usb_icl_votable)) {
1678 rc = PTR_ERR(chg->usb_icl_votable);
1679 return rc;
1680 }
1681
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001682 chg->dc_icl_votable = create_votable("DC_ICL", VOTE_MIN,
1683 smblib_dc_icl_vote_callback,
1684 chg);
Nicholas Troast34db5032016-03-28 12:26:44 -07001685 if (IS_ERR(chg->dc_icl_votable)) {
1686 rc = PTR_ERR(chg->dc_icl_votable);
1687 return rc;
1688 }
1689
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001690 chg->pd_allowed_votable = create_votable("PD_ALLOWED", VOTE_SET_ANY,
1691 NULL, NULL);
Nicholas Troast34db5032016-03-28 12:26:44 -07001692 if (IS_ERR(chg->pd_allowed_votable)) {
1693 rc = PTR_ERR(chg->pd_allowed_votable);
1694 return rc;
1695 }
1696
Harry Yang223c6282016-06-14 15:48:36 -07001697 chg->awake_votable = create_votable("AWAKE", VOTE_SET_ANY,
1698 smblib_awake_vote_callback,
1699 chg);
1700 if (IS_ERR(chg->awake_votable)) {
1701 rc = PTR_ERR(chg->awake_votable);
1702 return rc;
1703 }
1704
Harry Yang3c4c22d2016-06-15 11:40:54 -07001705 chg->pl_disable_votable = create_votable("PL_DISABLE", VOTE_SET_ANY,
1706 smblib_pl_disable_vote_callback,
1707 chg);
1708 if (IS_ERR(chg->pl_disable_votable)) {
1709 rc = PTR_ERR(chg->pl_disable_votable);
1710 return rc;
1711 }
1712
Nicholas Troast320839e2016-06-03 10:18:00 -07001713 return rc;
1714}
1715
1716int smblib_init(struct smb_charger *chg)
1717{
1718 int rc = 0;
1719
1720 mutex_init(&chg->write_lock);
Harry Yang58a9e7a2016-06-23 14:54:43 -07001721 INIT_WORK(&chg->pl_detect_work, smblib_pl_detect_work);
Nicholas Troast320839e2016-06-03 10:18:00 -07001722 INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work);
Harry Yang1d1034c2016-06-15 12:09:42 -07001723 INIT_DELAYED_WORK(&chg->pl_taper_work, smblib_pl_taper_work);
Nicholas Troast320839e2016-06-03 10:18:00 -07001724
1725 switch (chg->mode) {
1726 case PARALLEL_MASTER:
1727 rc = smblib_create_votables(chg);
1728 if (rc < 0) {
1729 dev_err(chg->dev, "Couldn't create votables rc=%d\n",
1730 rc);
Harry Yang58a9e7a2016-06-23 14:54:43 -07001731 return rc;
Nicholas Troast320839e2016-06-03 10:18:00 -07001732 }
Harry Yang58a9e7a2016-06-23 14:54:43 -07001733
1734 chg->pl.psy = power_supply_get_by_name("parallel");
1735 if (!chg->pl.psy) {
1736 rc = register_pl_notifier(chg);
1737 if (rc < 0) {
1738 dev_err(chg->dev,
1739 "Couldn't register notifier rc=%d\n",
1740 rc);
1741 return rc;
1742 }
1743 }
1744
Nicholas Troast320839e2016-06-03 10:18:00 -07001745 break;
1746 case PARALLEL_SLAVE:
1747 break;
1748 default:
1749 dev_err(chg->dev, "Unsupported mode %d\n", chg->mode);
1750 return -EINVAL;
1751 }
1752
1753 return rc;
Nicholas Troast34db5032016-03-28 12:26:44 -07001754}
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001755
1756int smblib_deinit(struct smb_charger *chg)
1757{
1758 destroy_votable(chg->usb_suspend_votable);
1759 destroy_votable(chg->dc_suspend_votable);
1760 destroy_votable(chg->fcc_votable);
1761 destroy_votable(chg->fv_votable);
1762 destroy_votable(chg->usb_icl_votable);
1763 destroy_votable(chg->dc_icl_votable);
1764 destroy_votable(chg->pd_allowed_votable);
Harry Yang223c6282016-06-14 15:48:36 -07001765 destroy_votable(chg->awake_votable);
Harry Yang3c4c22d2016-06-15 11:40:54 -07001766 destroy_votable(chg->pl_disable_votable);
Abhijeet Dharmapurikar8e9e7572016-06-06 16:13:14 -07001767
1768 return 0;
1769}