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