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