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