1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include <linux/module.h>
18#include <linux/device.h>
19#include <linux/regmap.h>
20#include <linux/workqueue.h>
21#include <linux/delay.h>
22#include <linux/platform_device.h>
23#include <linux/usb/otg.h>
24#include <linux/notifier.h>
25#include <linux/power_supply.h>
26#include <linux/notifier.h>
27#include <linux/property.h>
28#include <linux/mfd/axp20x.h>
29#include <linux/extcon.h>
30
31#define PS_STAT_VBUS_TRIGGER (1 << 0)
32#define PS_STAT_BAT_CHRG_DIR (1 << 2)
33#define PS_STAT_VBAT_ABOVE_VHOLD (1 << 3)
34#define PS_STAT_VBUS_VALID (1 << 4)
35#define PS_STAT_VBUS_PRESENT (1 << 5)
36
37#define CHRG_STAT_BAT_SAFE_MODE (1 << 3)
38#define CHRG_STAT_BAT_VALID (1 << 4)
39#define CHRG_STAT_BAT_PRESENT (1 << 5)
40#define CHRG_STAT_CHARGING (1 << 6)
41#define CHRG_STAT_PMIC_OTP (1 << 7)
42
43#define VBUS_ISPOUT_CUR_LIM_MASK 0x03
44#define VBUS_ISPOUT_CUR_LIM_BIT_POS 0
45#define VBUS_ISPOUT_CUR_LIM_900MA 0x0
46#define VBUS_ISPOUT_CUR_LIM_1500MA 0x1
47#define VBUS_ISPOUT_CUR_LIM_2000MA 0x2
48#define VBUS_ISPOUT_CUR_NO_LIM 0x3
49#define VBUS_ISPOUT_VHOLD_SET_MASK 0x31
50#define VBUS_ISPOUT_VHOLD_SET_BIT_POS 0x3
51#define VBUS_ISPOUT_VHOLD_SET_OFFSET 4000
52#define VBUS_ISPOUT_VHOLD_SET_LSB_RES 100
53#define VBUS_ISPOUT_VHOLD_SET_4300MV 0x3
54#define VBUS_ISPOUT_VBUS_PATH_DIS (1 << 7)
55
56#define CHRG_CCCV_CC_MASK 0xf
57#define CHRG_CCCV_CC_BIT_POS 0
58#define CHRG_CCCV_CC_OFFSET 200
59#define CHRG_CCCV_CC_LSB_RES 200
60#define CHRG_CCCV_ITERM_20P (1 << 4)
61#define CHRG_CCCV_CV_MASK 0x60
62#define CHRG_CCCV_CV_BIT_POS 5
63#define CHRG_CCCV_CV_4100MV 0x0
64#define CHRG_CCCV_CV_4150MV 0x1
65#define CHRG_CCCV_CV_4200MV 0x2
66#define CHRG_CCCV_CV_4350MV 0x3
67#define CHRG_CCCV_CHG_EN (1 << 7)
68
69#define CNTL2_CC_TIMEOUT_MASK 0x3
70#define CNTL2_CC_TIMEOUT_OFFSET 6
71#define CNTL2_CC_TIMEOUT_LSB_RES 2
72#define CNTL2_CC_TIMEOUT_12HRS 0x3
73#define CNTL2_CHGLED_TYPEB (1 << 4)
74#define CNTL2_CHG_OUT_TURNON (1 << 5)
75#define CNTL2_PC_TIMEOUT_MASK 0xC0
76#define CNTL2_PC_TIMEOUT_OFFSET 40
77#define CNTL2_PC_TIMEOUT_LSB_RES 10
78#define CNTL2_PC_TIMEOUT_70MINS 0x3
79
80#define CHRG_ILIM_TEMP_LOOP_EN (1 << 3)
81#define CHRG_VBUS_ILIM_MASK 0xf0
82#define CHRG_VBUS_ILIM_BIT_POS 4
83#define CHRG_VBUS_ILIM_100MA 0x0
84#define CHRG_VBUS_ILIM_500MA 0x1
85#define CHRG_VBUS_ILIM_900MA 0x2
86#define CHRG_VBUS_ILIM_1500MA 0x3
87#define CHRG_VBUS_ILIM_2000MA 0x4
88#define CHRG_VBUS_ILIM_2500MA 0x5
89#define CHRG_VBUS_ILIM_3000MA 0x6
90
91#define CHRG_VLTFC_0C 0xA5
92#define CHRG_VHTFC_45C 0x1F
93
94#define BAT_IRQ_CFG_CHRG_DONE (1 << 2)
95#define BAT_IRQ_CFG_CHRG_START (1 << 3)
96#define BAT_IRQ_CFG_BAT_SAFE_EXIT (1 << 4)
97#define BAT_IRQ_CFG_BAT_SAFE_ENTER (1 << 5)
98#define BAT_IRQ_CFG_BAT_DISCON (1 << 6)
99#define BAT_IRQ_CFG_BAT_CONN (1 << 7)
100#define BAT_IRQ_CFG_BAT_MASK 0xFC
101
102#define TEMP_IRQ_CFG_QCBTU (1 << 4)
103#define TEMP_IRQ_CFG_CBTU (1 << 5)
104#define TEMP_IRQ_CFG_QCBTO (1 << 6)
105#define TEMP_IRQ_CFG_CBTO (1 << 7)
106#define TEMP_IRQ_CFG_MASK 0xF0
107
108#define FG_CNTL_OCV_ADJ_EN (1 << 3)
109
110#define CV_4100MV 4100
111#define CV_4150MV 4150
112#define CV_4200MV 4200
113#define CV_4350MV 4350
114
115#define CC_200MA 200
116#define CC_600MA 600
117#define CC_800MA 800
118#define CC_1000MA 1000
119#define CC_1600MA 1600
120#define CC_2000MA 2000
121
122#define ILIM_100MA 100
123#define ILIM_500MA 500
124#define ILIM_900MA 900
125#define ILIM_1500MA 1500
126#define ILIM_2000MA 2000
127#define ILIM_2500MA 2500
128#define ILIM_3000MA 3000
129
130#define AXP288_EXTCON_DEV_NAME "axp288_extcon"
131
132#define AXP288_EXTCON_SLOW_CHARGER "SLOW-CHARGER"
133#define AXP288_EXTCON_DOWNSTREAM_CHARGER "CHARGE-DOWNSTREAM"
134#define AXP288_EXTCON_FAST_CHARGER "FAST-CHARGER"
135
136enum {
137 VBUS_OV_IRQ = 0,
138 CHARGE_DONE_IRQ,
139 CHARGE_CHARGING_IRQ,
140 BAT_SAFE_QUIT_IRQ,
141 BAT_SAFE_ENTER_IRQ,
142 QCBTU_IRQ,
143 CBTU_IRQ,
144 QCBTO_IRQ,
145 CBTO_IRQ,
146 CHRG_INTR_END,
147};
148
149struct axp288_chrg_info {
150 struct platform_device *pdev;
151 struct axp20x_chrg_pdata *pdata;
152 struct regmap *regmap;
153 struct regmap_irq_chip_data *regmap_irqc;
154 int irq[CHRG_INTR_END];
155 struct power_supply *psy_usb;
156 struct mutex lock;
157
158
159 struct {
160 struct work_struct work;
161 struct extcon_specific_cable_nb cable;
162 struct notifier_block id_nb;
163 bool id_short;
164 } otg;
165
166
167 struct {
168 struct extcon_dev *edev;
169 bool connected;
170 enum power_supply_type chg_type;
171 struct notifier_block nb;
172 struct work_struct work;
173 } cable;
174
175 int health;
176 int inlmt;
177 int cc;
178 int cv;
179 int max_cc;
180 int max_cv;
181 bool online;
182 bool present;
183 bool enable_charger;
184 bool is_charger_enabled;
185};
186
187static inline int axp288_charger_set_cc(struct axp288_chrg_info *info, int cc)
188{
189 u8 reg_val;
190 int ret;
191
192 if (cc < CHRG_CCCV_CC_OFFSET)
193 cc = CHRG_CCCV_CC_OFFSET;
194 else if (cc > info->max_cc)
195 cc = info->max_cc;
196
197 reg_val = (cc - CHRG_CCCV_CC_OFFSET) / CHRG_CCCV_CC_LSB_RES;
198 cc = (reg_val * CHRG_CCCV_CC_LSB_RES) + CHRG_CCCV_CC_OFFSET;
199 reg_val = reg_val << CHRG_CCCV_CC_BIT_POS;
200
201 ret = regmap_update_bits(info->regmap,
202 AXP20X_CHRG_CTRL1,
203 CHRG_CCCV_CC_MASK, reg_val);
204 if (ret >= 0)
205 info->cc = cc;
206
207 return ret;
208}
209
210static inline int axp288_charger_set_cv(struct axp288_chrg_info *info, int cv)
211{
212 u8 reg_val;
213 int ret;
214
215 if (cv <= CV_4100MV) {
216 reg_val = CHRG_CCCV_CV_4100MV;
217 cv = CV_4100MV;
218 } else if (cv <= CV_4150MV) {
219 reg_val = CHRG_CCCV_CV_4150MV;
220 cv = CV_4150MV;
221 } else if (cv <= CV_4200MV) {
222 reg_val = CHRG_CCCV_CV_4200MV;
223 cv = CV_4200MV;
224 } else {
225 reg_val = CHRG_CCCV_CV_4350MV;
226 cv = CV_4350MV;
227 }
228
229 reg_val = reg_val << CHRG_CCCV_CV_BIT_POS;
230
231 ret = regmap_update_bits(info->regmap,
232 AXP20X_CHRG_CTRL1,
233 CHRG_CCCV_CV_MASK, reg_val);
234
235 if (ret >= 0)
236 info->cv = cv;
237
238 return ret;
239}
240
241static inline int axp288_charger_set_vbus_inlmt(struct axp288_chrg_info *info,
242 int inlmt)
243{
244 int ret;
245 unsigned int val;
246 u8 reg_val;
247
248
249 ret = regmap_read(info->regmap, AXP20X_CHRG_BAK_CTRL, &val);
250 if (ret < 0)
251 goto set_inlmt_fail;
252
253 if (inlmt <= ILIM_100MA) {
254 reg_val = CHRG_VBUS_ILIM_100MA;
255 inlmt = ILIM_100MA;
256 } else if (inlmt <= ILIM_500MA) {
257 reg_val = CHRG_VBUS_ILIM_500MA;
258 inlmt = ILIM_500MA;
259 } else if (inlmt <= ILIM_900MA) {
260 reg_val = CHRG_VBUS_ILIM_900MA;
261 inlmt = ILIM_900MA;
262 } else if (inlmt <= ILIM_1500MA) {
263 reg_val = CHRG_VBUS_ILIM_1500MA;
264 inlmt = ILIM_1500MA;
265 } else if (inlmt <= ILIM_2000MA) {
266 reg_val = CHRG_VBUS_ILIM_2000MA;
267 inlmt = ILIM_2000MA;
268 } else if (inlmt <= ILIM_2500MA) {
269 reg_val = CHRG_VBUS_ILIM_2500MA;
270 inlmt = ILIM_2500MA;
271 } else {
272 reg_val = CHRG_VBUS_ILIM_3000MA;
273 inlmt = ILIM_3000MA;
274 }
275
276 reg_val = (val & ~CHRG_VBUS_ILIM_MASK)
277 | (reg_val << CHRG_VBUS_ILIM_BIT_POS);
278 ret = regmap_write(info->regmap, AXP20X_CHRG_BAK_CTRL, reg_val);
279 if (ret >= 0)
280 info->inlmt = inlmt;
281 else
282 dev_err(&info->pdev->dev, "charger BAK control %d\n", ret);
283
284
285set_inlmt_fail:
286 return ret;
287}
288
289static int axp288_charger_vbus_path_select(struct axp288_chrg_info *info,
290 bool enable)
291{
292 int ret;
293
294 if (enable)
295 ret = regmap_update_bits(info->regmap, AXP20X_VBUS_IPSOUT_MGMT,
296 VBUS_ISPOUT_VBUS_PATH_DIS, 0);
297 else
298 ret = regmap_update_bits(info->regmap, AXP20X_VBUS_IPSOUT_MGMT,
299 VBUS_ISPOUT_VBUS_PATH_DIS, VBUS_ISPOUT_VBUS_PATH_DIS);
300
301 if (ret < 0)
302 dev_err(&info->pdev->dev, "axp288 vbus path select %d\n", ret);
303
304
305 return ret;
306}
307
308static int axp288_charger_enable_charger(struct axp288_chrg_info *info,
309 bool enable)
310{
311 int ret;
312
313 if (enable)
314 ret = regmap_update_bits(info->regmap, AXP20X_CHRG_CTRL1,
315 CHRG_CCCV_CHG_EN, CHRG_CCCV_CHG_EN);
316 else
317 ret = regmap_update_bits(info->regmap, AXP20X_CHRG_CTRL1,
318 CHRG_CCCV_CHG_EN, 0);
319 if (ret < 0)
320 dev_err(&info->pdev->dev, "axp288 enable charger %d\n", ret);
321 else
322 info->is_charger_enabled = enable;
323
324 return ret;
325}
326
327static int axp288_charger_is_present(struct axp288_chrg_info *info)
328{
329 int ret, present = 0;
330 unsigned int val;
331
332 ret = regmap_read(info->regmap, AXP20X_PWR_INPUT_STATUS, &val);
333 if (ret < 0)
334 return ret;
335
336 if (val & PS_STAT_VBUS_PRESENT)
337 present = 1;
338 return present;
339}
340
341static int axp288_charger_is_online(struct axp288_chrg_info *info)
342{
343 int ret, online = 0;
344 unsigned int val;
345
346 ret = regmap_read(info->regmap, AXP20X_PWR_INPUT_STATUS, &val);
347 if (ret < 0)
348 return ret;
349
350 if (val & PS_STAT_VBUS_VALID)
351 online = 1;
352 return online;
353}
354
355static int axp288_get_charger_health(struct axp288_chrg_info *info)
356{
357 int ret, pwr_stat, chrg_stat;
358 int health = POWER_SUPPLY_HEALTH_UNKNOWN;
359 unsigned int val;
360
361 ret = regmap_read(info->regmap, AXP20X_PWR_INPUT_STATUS, &val);
362 if ((ret < 0) || !(val & PS_STAT_VBUS_PRESENT))
363 goto health_read_fail;
364 else
365 pwr_stat = val;
366
367 ret = regmap_read(info->regmap, AXP20X_PWR_OP_MODE, &val);
368 if (ret < 0)
369 goto health_read_fail;
370 else
371 chrg_stat = val;
372
373 if (!(pwr_stat & PS_STAT_VBUS_VALID))
374 health = POWER_SUPPLY_HEALTH_DEAD;
375 else if (chrg_stat & CHRG_STAT_PMIC_OTP)
376 health = POWER_SUPPLY_HEALTH_OVERHEAT;
377 else if (chrg_stat & CHRG_STAT_BAT_SAFE_MODE)
378 health = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
379 else
380 health = POWER_SUPPLY_HEALTH_GOOD;
381
382health_read_fail:
383 return health;
384}
385
386static int axp288_charger_usb_set_property(struct power_supply *psy,
387 enum power_supply_property psp,
388 const union power_supply_propval *val)
389{
390 struct axp288_chrg_info *info = power_supply_get_drvdata(psy);
391 int ret = 0;
392 int scaled_val;
393
394 mutex_lock(&info->lock);
395
396 switch (psp) {
397 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
398 scaled_val = min(val->intval, info->max_cc);
399 scaled_val = DIV_ROUND_CLOSEST(scaled_val, 1000);
400 ret = axp288_charger_set_cc(info, scaled_val);
401 if (ret < 0)
402 dev_warn(&info->pdev->dev, "set charge current failed\n");
403 break;
404 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
405 scaled_val = min(val->intval, info->max_cv);
406 scaled_val = DIV_ROUND_CLOSEST(scaled_val, 1000);
407 ret = axp288_charger_set_cv(info, scaled_val);
408 if (ret < 0)
409 dev_warn(&info->pdev->dev, "set charge voltage failed\n");
410 break;
411 default:
412 ret = -EINVAL;
413 }
414
415 mutex_unlock(&info->lock);
416 return ret;
417}
418
419static int axp288_charger_usb_get_property(struct power_supply *psy,
420 enum power_supply_property psp,
421 union power_supply_propval *val)
422{
423 struct axp288_chrg_info *info = power_supply_get_drvdata(psy);
424 int ret = 0;
425
426 mutex_lock(&info->lock);
427
428 switch (psp) {
429 case POWER_SUPPLY_PROP_PRESENT:
430
431 if (info->otg.id_short) {
432 val->intval = 0;
433 break;
434 }
435 ret = axp288_charger_is_present(info);
436 if (ret < 0)
437 goto psy_get_prop_fail;
438 info->present = ret;
439 val->intval = info->present;
440 break;
441 case POWER_SUPPLY_PROP_ONLINE:
442
443 if (info->otg.id_short) {
444 val->intval = 0;
445 break;
446 }
447 ret = axp288_charger_is_online(info);
448 if (ret < 0)
449 goto psy_get_prop_fail;
450 info->online = ret;
451 val->intval = info->online;
452 break;
453 case POWER_SUPPLY_PROP_HEALTH:
454 val->intval = axp288_get_charger_health(info);
455 break;
456 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
457 val->intval = info->cc * 1000;
458 break;
459 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
460 val->intval = info->max_cc * 1000;
461 break;
462 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
463 val->intval = info->cv * 1000;
464 break;
465 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
466 val->intval = info->max_cv * 1000;
467 break;
468 case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
469 val->intval = info->inlmt * 1000;
470 break;
471 default:
472 ret = -EINVAL;
473 goto psy_get_prop_fail;
474 }
475
476psy_get_prop_fail:
477 mutex_unlock(&info->lock);
478 return ret;
479}
480
481static int axp288_charger_property_is_writeable(struct power_supply *psy,
482 enum power_supply_property psp)
483{
484 int ret;
485
486 switch (psp) {
487 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
488 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
489 ret = 1;
490 break;
491 default:
492 ret = 0;
493 }
494
495 return ret;
496}
497
498static enum power_supply_property axp288_usb_props[] = {
499 POWER_SUPPLY_PROP_PRESENT,
500 POWER_SUPPLY_PROP_ONLINE,
501 POWER_SUPPLY_PROP_TYPE,
502 POWER_SUPPLY_PROP_HEALTH,
503 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
504 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
505 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
506 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
507 POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
508};
509
510static const struct power_supply_desc axp288_charger_desc = {
511 .name = "axp288_charger",
512 .type = POWER_SUPPLY_TYPE_USB,
513 .properties = axp288_usb_props,
514 .num_properties = ARRAY_SIZE(axp288_usb_props),
515 .get_property = axp288_charger_usb_get_property,
516 .set_property = axp288_charger_usb_set_property,
517 .property_is_writeable = axp288_charger_property_is_writeable,
518};
519
520static irqreturn_t axp288_charger_irq_thread_handler(int irq, void *dev)
521{
522 struct axp288_chrg_info *info = dev;
523 int i;
524
525 for (i = 0; i < CHRG_INTR_END; i++) {
526 if (info->irq[i] == irq)
527 break;
528 }
529
530 if (i >= CHRG_INTR_END) {
531 dev_warn(&info->pdev->dev, "spurious interrupt!!\n");
532 return IRQ_NONE;
533 }
534
535 switch (i) {
536 case VBUS_OV_IRQ:
537 dev_dbg(&info->pdev->dev, "VBUS Over Voltage INTR\n");
538 break;
539 case CHARGE_DONE_IRQ:
540 dev_dbg(&info->pdev->dev, "Charging Done INTR\n");
541 break;
542 case CHARGE_CHARGING_IRQ:
543 dev_dbg(&info->pdev->dev, "Start Charging IRQ\n");
544 break;
545 case BAT_SAFE_QUIT_IRQ:
546 dev_dbg(&info->pdev->dev,
547 "Quit Safe Mode(restart timer) Charging IRQ\n");
548 break;
549 case BAT_SAFE_ENTER_IRQ:
550 dev_dbg(&info->pdev->dev,
551 "Enter Safe Mode(timer expire) Charging IRQ\n");
552 break;
553 case QCBTU_IRQ:
554 dev_dbg(&info->pdev->dev,
555 "Quit Battery Under Temperature(CHRG) INTR\n");
556 break;
557 case CBTU_IRQ:
558 dev_dbg(&info->pdev->dev,
559 "Hit Battery Under Temperature(CHRG) INTR\n");
560 break;
561 case QCBTO_IRQ:
562 dev_dbg(&info->pdev->dev,
563 "Quit Battery Over Temperature(CHRG) INTR\n");
564 break;
565 case CBTO_IRQ:
566 dev_dbg(&info->pdev->dev,
567 "Hit Battery Over Temperature(CHRG) INTR\n");
568 break;
569 default:
570 dev_warn(&info->pdev->dev, "Spurious Interrupt!!!\n");
571 goto out;
572 }
573
574 power_supply_changed(info->psy_usb);
575out:
576 return IRQ_HANDLED;
577}
578
579static void axp288_charger_extcon_evt_worker(struct work_struct *work)
580{
581 struct axp288_chrg_info *info =
582 container_of(work, struct axp288_chrg_info, cable.work);
583 int ret, current_limit;
584 bool changed = false;
585 struct extcon_dev *edev = info->cable.edev;
586 bool old_connected = info->cable.connected;
587
588
589 if (extcon_get_cable_state(edev, AXP288_EXTCON_SLOW_CHARGER) > 0) {
590 dev_dbg(&info->pdev->dev, "USB SDP charger is connected");
591 info->cable.connected = true;
592 info->cable.chg_type = POWER_SUPPLY_TYPE_USB;
593 } else if (extcon_get_cable_state(edev,
594 AXP288_EXTCON_DOWNSTREAM_CHARGER) > 0) {
595 dev_dbg(&info->pdev->dev, "USB CDP charger is connected");
596 info->cable.connected = true;
597 info->cable.chg_type = POWER_SUPPLY_TYPE_USB_CDP;
598 } else if (extcon_get_cable_state(edev,
599 AXP288_EXTCON_FAST_CHARGER) > 0) {
600 dev_dbg(&info->pdev->dev, "USB DCP charger is connected");
601 info->cable.connected = true;
602 info->cable.chg_type = POWER_SUPPLY_TYPE_USB_DCP;
603 } else {
604 if (old_connected)
605 dev_dbg(&info->pdev->dev, "USB charger disconnected");
606 info->cable.connected = false;
607 info->cable.chg_type = POWER_SUPPLY_TYPE_USB;
608 }
609
610
611 if (old_connected != info->cable.connected)
612 changed = true;
613
614 if (!changed)
615 return;
616
617 mutex_lock(&info->lock);
618
619 if (info->is_charger_enabled && !info->cable.connected) {
620 info->enable_charger = false;
621 ret = axp288_charger_enable_charger(info, info->enable_charger);
622 if (ret < 0)
623 dev_err(&info->pdev->dev,
624 "cannot disable charger (%d)", ret);
625
626 } else if (!info->is_charger_enabled && info->cable.connected) {
627 switch (info->cable.chg_type) {
628 case POWER_SUPPLY_TYPE_USB:
629 current_limit = ILIM_500MA;
630 break;
631 case POWER_SUPPLY_TYPE_USB_CDP:
632 current_limit = ILIM_1500MA;
633 break;
634 case POWER_SUPPLY_TYPE_USB_DCP:
635 current_limit = ILIM_2000MA;
636 break;
637 default:
638
639 current_limit = 0;
640 break;
641 }
642
643
644 ret = axp288_charger_set_vbus_inlmt(info, current_limit);
645 if (ret < 0) {
646 dev_err(&info->pdev->dev,
647 "error setting current limit (%d)", ret);
648 } else {
649 info->enable_charger = (current_limit > 0);
650 ret = axp288_charger_enable_charger(info,
651 info->enable_charger);
652 if (ret < 0)
653 dev_err(&info->pdev->dev,
654 "cannot enable charger (%d)", ret);
655 }
656 }
657
658 if (changed)
659 info->health = axp288_get_charger_health(info);
660
661 mutex_unlock(&info->lock);
662
663 if (changed)
664 power_supply_changed(info->psy_usb);
665}
666
667static int axp288_charger_handle_cable_evt(struct notifier_block *nb,
668 unsigned long event, void *param)
669{
670 struct axp288_chrg_info *info =
671 container_of(nb, struct axp288_chrg_info, cable.nb);
672
673 schedule_work(&info->cable.work);
674
675 return NOTIFY_OK;
676}
677
678static void axp288_charger_otg_evt_worker(struct work_struct *work)
679{
680 struct axp288_chrg_info *info =
681 container_of(work, struct axp288_chrg_info, otg.work);
682 int ret;
683
684
685 ret = axp288_charger_vbus_path_select(info, !info->otg.id_short);
686 if (ret < 0)
687 dev_warn(&info->pdev->dev, "vbus path disable failed\n");
688}
689
690static int axp288_charger_handle_otg_evt(struct notifier_block *nb,
691 unsigned long event, void *param)
692{
693 struct axp288_chrg_info *info =
694 container_of(nb, struct axp288_chrg_info, otg.id_nb);
695 struct extcon_dev *edev = param;
696 int usb_host = extcon_get_cable_state(edev, "USB-Host");
697
698 dev_dbg(&info->pdev->dev, "external connector USB-Host is %s\n",
699 usb_host ? "attached" : "detached");
700
701
702
703
704
705 info->otg.id_short = usb_host;
706 schedule_work(&info->otg.work);
707
708 return NOTIFY_OK;
709}
710
711static void charger_init_hw_regs(struct axp288_chrg_info *info)
712{
713 int ret, cc, cv;
714 unsigned int val;
715
716
717 ret = regmap_write(info->regmap, AXP20X_V_LTF_CHRG, CHRG_VLTFC_0C);
718 if (ret < 0)
719 dev_warn(&info->pdev->dev, "register(%x) write error(%d)\n",
720 AXP20X_V_LTF_CHRG, ret);
721
722 ret = regmap_write(info->regmap, AXP20X_V_HTF_CHRG, CHRG_VHTFC_45C);
723 if (ret < 0)
724 dev_warn(&info->pdev->dev, "register(%x) write error(%d)\n",
725 AXP20X_V_HTF_CHRG, ret);
726
727
728 ret = regmap_update_bits(info->regmap,
729 AXP20X_CHRG_CTRL2,
730 CNTL2_CHG_OUT_TURNON, 1);
731 if (ret < 0)
732 dev_warn(&info->pdev->dev, "register(%x) write error(%d)\n",
733 AXP20X_CHRG_CTRL2, ret);
734
735
736 ret = regmap_update_bits(info->regmap,
737 AXP20X_IRQ2_EN,
738 BAT_IRQ_CFG_BAT_MASK, 1);
739 if (ret < 0)
740 dev_warn(&info->pdev->dev, "register(%x) write error(%d)\n",
741 AXP20X_IRQ2_EN, ret);
742
743 ret = regmap_update_bits(info->regmap, AXP20X_IRQ3_EN,
744 TEMP_IRQ_CFG_MASK, 1);
745 if (ret < 0)
746 dev_warn(&info->pdev->dev, "register(%x) write error(%d)\n",
747 AXP20X_IRQ3_EN, ret);
748
749
750 ret = regmap_update_bits(info->regmap,
751 AXP20X_CHRG_CTRL1,
752 CHRG_CCCV_ITERM_20P, 0);
753 if (ret < 0)
754 dev_warn(&info->pdev->dev, "register(%x) write error(%d)\n",
755 AXP20X_CHRG_CTRL1, ret);
756
757
758 ret = regmap_update_bits(info->regmap,
759 AXP20X_CC_CTRL,
760 FG_CNTL_OCV_ADJ_EN, 0);
761 if (ret < 0)
762 dev_warn(&info->pdev->dev, "register(%x) write error(%d)\n",
763 AXP20X_CC_CTRL, ret);
764
765
766 info->max_cc = info->pdata->max_cc;
767 info->max_cv = info->pdata->max_cv;
768
769
770 ret = regmap_read(info->regmap, AXP20X_CHRG_CTRL1, &val);
771 if (ret < 0) {
772
773 info->cc = info->pdata->def_cc;
774 info->cv = info->pdata->def_cv;
775 } else {
776
777 cv = (val & CHRG_CCCV_CV_MASK) >> CHRG_CCCV_CV_BIT_POS;
778 switch (cv) {
779 case CHRG_CCCV_CV_4100MV:
780 info->cv = CV_4100MV;
781 break;
782 case CHRG_CCCV_CV_4150MV:
783 info->cv = CV_4150MV;
784 break;
785 case CHRG_CCCV_CV_4200MV:
786 info->cv = CV_4200MV;
787 break;
788 case CHRG_CCCV_CV_4350MV:
789 info->cv = CV_4350MV;
790 break;
791 default:
792 info->cv = INT_MAX;
793 break;
794 }
795
796
797 cc = (ret & CHRG_CCCV_CC_MASK) >> CHRG_CCCV_CC_BIT_POS;
798 cc = (cc * CHRG_CCCV_CC_LSB_RES) + CHRG_CCCV_CC_OFFSET;
799 info->cc = cc;
800
801
802 cc = min(info->pdata->def_cc, info->max_cc);
803 cv = min(info->pdata->def_cv, info->max_cv);
804
805 ret = axp288_charger_set_cc(info, cc);
806 if (ret < 0)
807 dev_warn(&info->pdev->dev,
808 "error(%d) in setting CC\n", ret);
809
810 ret = axp288_charger_set_cv(info, cv);
811 if (ret < 0)
812 dev_warn(&info->pdev->dev,
813 "error(%d) in setting CV\n", ret);
814 }
815}
816
817static int axp288_charger_probe(struct platform_device *pdev)
818{
819 int ret, i, pirq;
820 struct axp288_chrg_info *info;
821 struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
822 struct power_supply_config charger_cfg = {};
823
824 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
825 if (!info)
826 return -ENOMEM;
827
828 info->pdev = pdev;
829 info->regmap = axp20x->regmap;
830 info->regmap_irqc = axp20x->regmap_irqc;
831 info->pdata = pdev->dev.platform_data;
832
833 if (!info->pdata) {
834
835 if (!device_property_present(&pdev->dev,
836 "axp288_charger_data\n"))
837 dev_err(&pdev->dev, "failed to get platform data\n");
838 return -ENODEV;
839 }
840
841 info->cable.edev = extcon_get_extcon_dev(AXP288_EXTCON_DEV_NAME);
842 if (info->cable.edev == NULL) {
843 dev_dbg(&pdev->dev, "%s is not ready, probe deferred\n",
844 AXP288_EXTCON_DEV_NAME);
845 return -EPROBE_DEFER;
846 }
847
848
849 INIT_WORK(&info->cable.work, axp288_charger_extcon_evt_worker);
850 info->cable.nb.notifier_call = axp288_charger_handle_cable_evt;
851 ret = extcon_register_notifier(info->cable.edev, EXTCON_NONE, &info->cable.nb);
852 if (ret) {
853 dev_err(&info->pdev->dev,
854 "failed to register extcon notifier %d\n", ret);
855 return ret;
856 }
857
858 platform_set_drvdata(pdev, info);
859 mutex_init(&info->lock);
860
861
862 charger_cfg.drv_data = info;
863 info->psy_usb = power_supply_register(&pdev->dev, &axp288_charger_desc,
864 &charger_cfg);
865 if (IS_ERR(info->psy_usb)) {
866 dev_err(&pdev->dev, "failed to register power supply charger\n");
867 ret = PTR_ERR(info->psy_usb);
868 goto psy_reg_failed;
869 }
870
871
872 INIT_WORK(&info->otg.work, axp288_charger_otg_evt_worker);
873 info->otg.id_nb.notifier_call = axp288_charger_handle_otg_evt;
874 ret = extcon_register_interest(&info->otg.cable, NULL, "USB-Host",
875 &info->otg.id_nb);
876 if (ret)
877 dev_warn(&pdev->dev, "failed to register otg notifier\n");
878
879 if (info->otg.cable.edev)
880 info->otg.id_short = extcon_get_cable_state(
881 info->otg.cable.edev, "USB-Host");
882
883
884 for (i = 0; i < CHRG_INTR_END; i++) {
885 pirq = platform_get_irq(info->pdev, i);
886 info->irq[i] = regmap_irq_get_virq(info->regmap_irqc, pirq);
887 if (info->irq[i] < 0) {
888 dev_warn(&info->pdev->dev,
889 "failed to get virtual interrupt=%d\n", pirq);
890 ret = info->irq[i];
891 goto intr_reg_failed;
892 }
893 ret = devm_request_threaded_irq(&info->pdev->dev, info->irq[i],
894 NULL, axp288_charger_irq_thread_handler,
895 IRQF_ONESHOT, info->pdev->name, info);
896 if (ret) {
897 dev_err(&pdev->dev, "failed to request interrupt=%d\n",
898 info->irq[i]);
899 goto intr_reg_failed;
900 }
901 }
902
903 charger_init_hw_regs(info);
904
905 return 0;
906
907intr_reg_failed:
908 if (info->otg.cable.edev)
909 extcon_unregister_interest(&info->otg.cable);
910 power_supply_unregister(info->psy_usb);
911psy_reg_failed:
912 extcon_unregister_notifier(info->cable.edev, EXTCON_NONE, &info->cable.nb);
913 return ret;
914}
915
916static int axp288_charger_remove(struct platform_device *pdev)
917{
918 struct axp288_chrg_info *info = dev_get_drvdata(&pdev->dev);
919
920 if (info->otg.cable.edev)
921 extcon_unregister_interest(&info->otg.cable);
922
923 extcon_unregister_notifier(info->cable.edev, EXTCON_NONE, &info->cable.nb);
924 power_supply_unregister(info->psy_usb);
925
926 return 0;
927}
928
929static struct platform_driver axp288_charger_driver = {
930 .probe = axp288_charger_probe,
931 .remove = axp288_charger_remove,
932 .driver = {
933 .name = "axp288_charger",
934 },
935};
936
937module_platform_driver(axp288_charger_driver);
938
939MODULE_AUTHOR("Ramakrishna Pallala <ramakrishna.pallala@intel.com>");
940MODULE_DESCRIPTION("X-power AXP288 Charger Driver");
941MODULE_LICENSE("GPL v2");
942