.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2011 Samsung Electronics Co., Ltd. |
---|
3 | 4 | * MyungJoo Ham <myungjoo.ham@samsung.com> |
---|
4 | 5 | * |
---|
5 | 6 | * This driver enables to monitor battery health and control charger |
---|
6 | 7 | * during suspend-to-mem. |
---|
7 | | - * Charger manager depends on other devices. register this later than |
---|
| 8 | + * Charger manager depends on other devices. Register this later than |
---|
8 | 9 | * the depending devices. |
---|
9 | 10 | * |
---|
10 | | - * This program is free software; you can redistribute it and/or modify |
---|
11 | | - * it under the terms of the GNU General Public License version 2 as |
---|
12 | | - * published by the Free Software Foundation. |
---|
13 | 11 | **/ |
---|
14 | 12 | |
---|
15 | 13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
---|
.. | .. |
---|
28 | 26 | #include <linux/of.h> |
---|
29 | 27 | #include <linux/thermal.h> |
---|
30 | 28 | |
---|
| 29 | +static struct { |
---|
| 30 | + const char *name; |
---|
| 31 | + u64 extcon_type; |
---|
| 32 | +} extcon_mapping[] = { |
---|
| 33 | + /* Current textual representations */ |
---|
| 34 | + { "USB", EXTCON_USB }, |
---|
| 35 | + { "USB-HOST", EXTCON_USB_HOST }, |
---|
| 36 | + { "SDP", EXTCON_CHG_USB_SDP }, |
---|
| 37 | + { "DCP", EXTCON_CHG_USB_DCP }, |
---|
| 38 | + { "CDP", EXTCON_CHG_USB_CDP }, |
---|
| 39 | + { "ACA", EXTCON_CHG_USB_ACA }, |
---|
| 40 | + { "FAST-CHARGER", EXTCON_CHG_USB_FAST }, |
---|
| 41 | + { "SLOW-CHARGER", EXTCON_CHG_USB_SLOW }, |
---|
| 42 | + { "WPT", EXTCON_CHG_WPT }, |
---|
| 43 | + { "PD", EXTCON_CHG_USB_PD }, |
---|
| 44 | + { "DOCK", EXTCON_DOCK }, |
---|
| 45 | + { "JIG", EXTCON_JIG }, |
---|
| 46 | + { "MECHANICAL", EXTCON_MECHANICAL }, |
---|
| 47 | + /* Deprecated textual representations */ |
---|
| 48 | + { "TA", EXTCON_CHG_USB_SDP }, |
---|
| 49 | + { "CHARGE-DOWNSTREAM", EXTCON_CHG_USB_CDP }, |
---|
| 50 | +}; |
---|
| 51 | + |
---|
31 | 52 | /* |
---|
32 | | - * Default termperature threshold for charging. |
---|
| 53 | + * Default temperature threshold for charging. |
---|
33 | 54 | * Every temperature units are in tenth of centigrade. |
---|
34 | 55 | */ |
---|
35 | 56 | #define CM_DEFAULT_RECHARGE_TEMP_DIFF 50 |
---|
36 | 57 | #define CM_DEFAULT_CHARGE_TEMP_MAX 500 |
---|
37 | | - |
---|
38 | | -static const char * const default_event_names[] = { |
---|
39 | | - [CM_EVENT_UNKNOWN] = "Unknown", |
---|
40 | | - [CM_EVENT_BATT_FULL] = "Battery Full", |
---|
41 | | - [CM_EVENT_BATT_IN] = "Battery Inserted", |
---|
42 | | - [CM_EVENT_BATT_OUT] = "Battery Pulled Out", |
---|
43 | | - [CM_EVENT_BATT_OVERHEAT] = "Battery Overheat", |
---|
44 | | - [CM_EVENT_BATT_COLD] = "Battery Cold", |
---|
45 | | - [CM_EVENT_EXT_PWR_IN_OUT] = "External Power Attach/Detach", |
---|
46 | | - [CM_EVENT_CHG_START_STOP] = "Charging Start/Stop", |
---|
47 | | - [CM_EVENT_OTHERS] = "Other battery events" |
---|
48 | | -}; |
---|
49 | 58 | |
---|
50 | 59 | /* |
---|
51 | 60 | * Regard CM_JIFFIES_SMALL jiffies is small enough to ignore for |
---|
.. | .. |
---|
62 | 71 | * rtc alarm. It should be 2 or larger |
---|
63 | 72 | */ |
---|
64 | 73 | #define CM_RTC_SMALL (2) |
---|
65 | | - |
---|
66 | | -#define UEVENT_BUF_SIZE 32 |
---|
67 | 74 | |
---|
68 | 75 | static LIST_HEAD(cm_list); |
---|
69 | 76 | static DEFINE_MUTEX(cm_list_mtx); |
---|
.. | .. |
---|
287 | 294 | if (!fuel_gauge) |
---|
288 | 295 | return false; |
---|
289 | 296 | |
---|
| 297 | + /* Full, if it's over the fullbatt voltage */ |
---|
| 298 | + if (desc->fullbatt_uV > 0) { |
---|
| 299 | + ret = get_batt_uV(cm, &uV); |
---|
| 300 | + if (!ret) { |
---|
| 301 | + /* Battery is already full, checks voltage drop. */ |
---|
| 302 | + if (cm->battery_status == POWER_SUPPLY_STATUS_FULL |
---|
| 303 | + && desc->fullbatt_vchkdrop_uV) |
---|
| 304 | + uV += desc->fullbatt_vchkdrop_uV; |
---|
| 305 | + if (uV >= desc->fullbatt_uV) |
---|
| 306 | + return true; |
---|
| 307 | + } |
---|
| 308 | + } |
---|
| 309 | + |
---|
290 | 310 | if (desc->fullbatt_full_capacity > 0) { |
---|
291 | 311 | val.intval = 0; |
---|
292 | 312 | |
---|
.. | .. |
---|
294 | 314 | ret = power_supply_get_property(fuel_gauge, |
---|
295 | 315 | POWER_SUPPLY_PROP_CHARGE_FULL, &val); |
---|
296 | 316 | if (!ret && val.intval > desc->fullbatt_full_capacity) { |
---|
297 | | - is_full = true; |
---|
298 | | - goto out; |
---|
299 | | - } |
---|
300 | | - } |
---|
301 | | - |
---|
302 | | - /* Full, if it's over the fullbatt voltage */ |
---|
303 | | - if (desc->fullbatt_uV > 0) { |
---|
304 | | - ret = get_batt_uV(cm, &uV); |
---|
305 | | - if (!ret && uV >= desc->fullbatt_uV) { |
---|
306 | 317 | is_full = true; |
---|
307 | 318 | goto out; |
---|
308 | 319 | } |
---|
.. | .. |
---|
356 | 367 | * Note that Charger Manager keeps the charger enabled regardless whether |
---|
357 | 368 | * the charger is charging or not (because battery is full or no external |
---|
358 | 369 | * power source exists) except when CM needs to disable chargers forcibly |
---|
359 | | - * bacause of emergency causes; when the battery is overheated or too cold. |
---|
| 370 | + * because of emergency causes; when the battery is overheated or too cold. |
---|
360 | 371 | */ |
---|
361 | 372 | static int try_charger_enable(struct charger_manager *cm, bool enable) |
---|
362 | 373 | { |
---|
363 | 374 | int err = 0, i; |
---|
364 | 375 | struct charger_desc *desc = cm->desc; |
---|
365 | 376 | |
---|
366 | | - /* Ignore if it's redundent command */ |
---|
| 377 | + /* Ignore if it's redundant command */ |
---|
367 | 378 | if (enable == cm->charger_enabled) |
---|
368 | 379 | return 0; |
---|
369 | 380 | |
---|
.. | .. |
---|
429 | 440 | } |
---|
430 | 441 | |
---|
431 | 442 | /** |
---|
432 | | - * try_charger_restart - Restart charging. |
---|
433 | | - * @cm: the Charger Manager representing the battery. |
---|
434 | | - * |
---|
435 | | - * Restart charging by turning off and on the charger. |
---|
436 | | - */ |
---|
437 | | -static int try_charger_restart(struct charger_manager *cm) |
---|
438 | | -{ |
---|
439 | | - int err; |
---|
440 | | - |
---|
441 | | - if (cm->emergency_stop) |
---|
442 | | - return -EAGAIN; |
---|
443 | | - |
---|
444 | | - err = try_charger_enable(cm, false); |
---|
445 | | - if (err) |
---|
446 | | - return err; |
---|
447 | | - |
---|
448 | | - return try_charger_enable(cm, true); |
---|
449 | | -} |
---|
450 | | - |
---|
451 | | -/** |
---|
452 | | - * uevent_notify - Let users know something has changed. |
---|
453 | | - * @cm: the Charger Manager representing the battery. |
---|
454 | | - * @event: the event string. |
---|
455 | | - * |
---|
456 | | - * If @event is null, it implies that uevent_notify is called |
---|
457 | | - * by resume function. When called in the resume function, cm_suspended |
---|
458 | | - * should be already reset to false in order to let uevent_notify |
---|
459 | | - * notify the recent event during the suspend to users. While |
---|
460 | | - * suspended, uevent_notify does not notify users, but tracks |
---|
461 | | - * events so that uevent_notify can notify users later after resumed. |
---|
462 | | - */ |
---|
463 | | -static void uevent_notify(struct charger_manager *cm, const char *event) |
---|
464 | | -{ |
---|
465 | | - static char env_str[UEVENT_BUF_SIZE + 1] = ""; |
---|
466 | | - static char env_str_save[UEVENT_BUF_SIZE + 1] = ""; |
---|
467 | | - |
---|
468 | | - if (cm_suspended) { |
---|
469 | | - /* Nothing in suspended-event buffer */ |
---|
470 | | - if (env_str_save[0] == 0) { |
---|
471 | | - if (!strncmp(env_str, event, UEVENT_BUF_SIZE)) |
---|
472 | | - return; /* status not changed */ |
---|
473 | | - strncpy(env_str_save, event, UEVENT_BUF_SIZE); |
---|
474 | | - return; |
---|
475 | | - } |
---|
476 | | - |
---|
477 | | - if (!strncmp(env_str_save, event, UEVENT_BUF_SIZE)) |
---|
478 | | - return; /* Duplicated. */ |
---|
479 | | - strncpy(env_str_save, event, UEVENT_BUF_SIZE); |
---|
480 | | - return; |
---|
481 | | - } |
---|
482 | | - |
---|
483 | | - if (event == NULL) { |
---|
484 | | - /* No messages pending */ |
---|
485 | | - if (!env_str_save[0]) |
---|
486 | | - return; |
---|
487 | | - |
---|
488 | | - strncpy(env_str, env_str_save, UEVENT_BUF_SIZE); |
---|
489 | | - kobject_uevent(&cm->dev->kobj, KOBJ_CHANGE); |
---|
490 | | - env_str_save[0] = 0; |
---|
491 | | - |
---|
492 | | - return; |
---|
493 | | - } |
---|
494 | | - |
---|
495 | | - /* status not changed */ |
---|
496 | | - if (!strncmp(env_str, event, UEVENT_BUF_SIZE)) |
---|
497 | | - return; |
---|
498 | | - |
---|
499 | | - /* save the status and notify the update */ |
---|
500 | | - strncpy(env_str, event, UEVENT_BUF_SIZE); |
---|
501 | | - kobject_uevent(&cm->dev->kobj, KOBJ_CHANGE); |
---|
502 | | - |
---|
503 | | - dev_info(cm->dev, "%s\n", event); |
---|
504 | | -} |
---|
505 | | - |
---|
506 | | -/** |
---|
507 | | - * fullbatt_vchk - Check voltage drop some times after "FULL" event. |
---|
508 | | - * @work: the work_struct appointing the function |
---|
509 | | - * |
---|
510 | | - * If a user has designated "fullbatt_vchkdrop_ms/uV" values with |
---|
511 | | - * charger_desc, Charger Manager checks voltage drop after the battery |
---|
512 | | - * "FULL" event. It checks whether the voltage has dropped more than |
---|
513 | | - * fullbatt_vchkdrop_uV by calling this function after fullbatt_vchkrop_ms. |
---|
514 | | - */ |
---|
515 | | -static void fullbatt_vchk(struct work_struct *work) |
---|
516 | | -{ |
---|
517 | | - struct delayed_work *dwork = to_delayed_work(work); |
---|
518 | | - struct charger_manager *cm = container_of(dwork, |
---|
519 | | - struct charger_manager, fullbatt_vchk_work); |
---|
520 | | - struct charger_desc *desc = cm->desc; |
---|
521 | | - int batt_uV, err, diff; |
---|
522 | | - |
---|
523 | | - /* remove the appointment for fullbatt_vchk */ |
---|
524 | | - cm->fullbatt_vchk_jiffies_at = 0; |
---|
525 | | - |
---|
526 | | - if (!desc->fullbatt_vchkdrop_uV || !desc->fullbatt_vchkdrop_ms) |
---|
527 | | - return; |
---|
528 | | - |
---|
529 | | - err = get_batt_uV(cm, &batt_uV); |
---|
530 | | - if (err) { |
---|
531 | | - dev_err(cm->dev, "%s: get_batt_uV error(%d)\n", __func__, err); |
---|
532 | | - return; |
---|
533 | | - } |
---|
534 | | - |
---|
535 | | - diff = desc->fullbatt_uV - batt_uV; |
---|
536 | | - if (diff < 0) |
---|
537 | | - return; |
---|
538 | | - |
---|
539 | | - dev_info(cm->dev, "VBATT dropped %duV after full-batt\n", diff); |
---|
540 | | - |
---|
541 | | - if (diff > desc->fullbatt_vchkdrop_uV) { |
---|
542 | | - try_charger_restart(cm); |
---|
543 | | - uevent_notify(cm, "Recharging"); |
---|
544 | | - } |
---|
545 | | -} |
---|
546 | | - |
---|
547 | | -/** |
---|
548 | 443 | * check_charging_duration - Monitor charging/discharging duration |
---|
549 | 444 | * @cm: the Charger Manager representing the battery. |
---|
550 | 445 | * |
---|
.. | .. |
---|
571 | 466 | if (duration > desc->charging_max_duration_ms) { |
---|
572 | 467 | dev_info(cm->dev, "Charging duration exceed %ums\n", |
---|
573 | 468 | desc->charging_max_duration_ms); |
---|
574 | | - uevent_notify(cm, "Discharging"); |
---|
575 | | - try_charger_enable(cm, false); |
---|
576 | 469 | ret = true; |
---|
577 | 470 | } |
---|
578 | | - } else if (is_ext_pwr_online(cm) && !cm->charger_enabled) { |
---|
| 471 | + } else if (cm->battery_status == POWER_SUPPLY_STATUS_NOT_CHARGING) { |
---|
579 | 472 | duration = curr - cm->charging_end_time; |
---|
580 | 473 | |
---|
581 | | - if (duration > desc->discharging_max_duration_ms && |
---|
582 | | - is_ext_pwr_online(cm)) { |
---|
| 474 | + if (duration > desc->discharging_max_duration_ms) { |
---|
583 | 475 | dev_info(cm->dev, "Discharging duration exceed %ums\n", |
---|
584 | 476 | desc->discharging_max_duration_ms); |
---|
585 | | - uevent_notify(cm, "Recharging"); |
---|
586 | | - try_charger_enable(cm, true); |
---|
587 | 477 | ret = true; |
---|
588 | 478 | } |
---|
589 | 479 | } |
---|
.. | .. |
---|
643 | 533 | if (ret) { |
---|
644 | 534 | /* FIXME: |
---|
645 | 535 | * No information of battery temperature might |
---|
646 | | - * occur hazadous result. We have to handle it |
---|
| 536 | + * occur hazardous result. We have to handle it |
---|
647 | 537 | * depending on battery type. |
---|
648 | 538 | */ |
---|
649 | 539 | dev_err(cm->dev, "Failed to get battery temperature\n"); |
---|
.. | .. |
---|
659 | 549 | } |
---|
660 | 550 | |
---|
661 | 551 | if (temp > upper_limit) |
---|
662 | | - ret = CM_EVENT_BATT_OVERHEAT; |
---|
| 552 | + ret = CM_BATT_OVERHEAT; |
---|
663 | 553 | else if (temp < lower_limit) |
---|
664 | | - ret = CM_EVENT_BATT_COLD; |
---|
| 554 | + ret = CM_BATT_COLD; |
---|
| 555 | + else |
---|
| 556 | + ret = CM_BATT_OK; |
---|
| 557 | + |
---|
| 558 | + cm->emergency_stop = ret; |
---|
665 | 559 | |
---|
666 | 560 | return ret; |
---|
| 561 | +} |
---|
| 562 | + |
---|
| 563 | +/** |
---|
| 564 | + * cm_get_target_status - Check current status and get next target status. |
---|
| 565 | + * @cm: the Charger Manager representing the battery. |
---|
| 566 | + */ |
---|
| 567 | +static int cm_get_target_status(struct charger_manager *cm) |
---|
| 568 | +{ |
---|
| 569 | + if (!is_ext_pwr_online(cm)) |
---|
| 570 | + return POWER_SUPPLY_STATUS_DISCHARGING; |
---|
| 571 | + |
---|
| 572 | + if (cm_check_thermal_status(cm)) { |
---|
| 573 | + /* Check if discharging duration exeeds limit. */ |
---|
| 574 | + if (check_charging_duration(cm)) |
---|
| 575 | + goto charging_ok; |
---|
| 576 | + return POWER_SUPPLY_STATUS_NOT_CHARGING; |
---|
| 577 | + } |
---|
| 578 | + |
---|
| 579 | + switch (cm->battery_status) { |
---|
| 580 | + case POWER_SUPPLY_STATUS_CHARGING: |
---|
| 581 | + /* Check if charging duration exeeds limit. */ |
---|
| 582 | + if (check_charging_duration(cm)) |
---|
| 583 | + return POWER_SUPPLY_STATUS_FULL; |
---|
| 584 | + fallthrough; |
---|
| 585 | + case POWER_SUPPLY_STATUS_FULL: |
---|
| 586 | + if (is_full_charged(cm)) |
---|
| 587 | + return POWER_SUPPLY_STATUS_FULL; |
---|
| 588 | + fallthrough; |
---|
| 589 | + default: |
---|
| 590 | + break; |
---|
| 591 | + } |
---|
| 592 | + |
---|
| 593 | +charging_ok: |
---|
| 594 | + /* Charging is allowed. */ |
---|
| 595 | + return POWER_SUPPLY_STATUS_CHARGING; |
---|
667 | 596 | } |
---|
668 | 597 | |
---|
669 | 598 | /** |
---|
.. | .. |
---|
675 | 604 | */ |
---|
676 | 605 | static bool _cm_monitor(struct charger_manager *cm) |
---|
677 | 606 | { |
---|
678 | | - int temp_alrt; |
---|
| 607 | + int target; |
---|
679 | 608 | |
---|
680 | | - temp_alrt = cm_check_thermal_status(cm); |
---|
| 609 | + target = cm_get_target_status(cm); |
---|
681 | 610 | |
---|
682 | | - /* It has been stopped already */ |
---|
683 | | - if (temp_alrt && cm->emergency_stop) |
---|
684 | | - return false; |
---|
| 611 | + try_charger_enable(cm, (target == POWER_SUPPLY_STATUS_CHARGING)); |
---|
685 | 612 | |
---|
686 | | - /* |
---|
687 | | - * Check temperature whether overheat or cold. |
---|
688 | | - * If temperature is out of range normal state, stop charging. |
---|
689 | | - */ |
---|
690 | | - if (temp_alrt) { |
---|
691 | | - cm->emergency_stop = temp_alrt; |
---|
692 | | - if (!try_charger_enable(cm, false)) |
---|
693 | | - uevent_notify(cm, default_event_names[temp_alrt]); |
---|
694 | | - |
---|
695 | | - /* |
---|
696 | | - * Check whole charging duration and discharing duration |
---|
697 | | - * after full-batt. |
---|
698 | | - */ |
---|
699 | | - } else if (!cm->emergency_stop && check_charging_duration(cm)) { |
---|
700 | | - dev_dbg(cm->dev, |
---|
701 | | - "Charging/Discharging duration is out of range\n"); |
---|
702 | | - /* |
---|
703 | | - * Check dropped voltage of battery. If battery voltage is more |
---|
704 | | - * dropped than fullbatt_vchkdrop_uV after fully charged state, |
---|
705 | | - * charger-manager have to recharge battery. |
---|
706 | | - */ |
---|
707 | | - } else if (!cm->emergency_stop && is_ext_pwr_online(cm) && |
---|
708 | | - !cm->charger_enabled) { |
---|
709 | | - fullbatt_vchk(&cm->fullbatt_vchk_work.work); |
---|
710 | | - |
---|
711 | | - /* |
---|
712 | | - * Check whether fully charged state to protect overcharge |
---|
713 | | - * if charger-manager is charging for battery. |
---|
714 | | - */ |
---|
715 | | - } else if (!cm->emergency_stop && is_full_charged(cm) && |
---|
716 | | - cm->charger_enabled) { |
---|
717 | | - dev_info(cm->dev, "EVENT_HANDLE: Battery Fully Charged\n"); |
---|
718 | | - uevent_notify(cm, default_event_names[CM_EVENT_BATT_FULL]); |
---|
719 | | - |
---|
720 | | - try_charger_enable(cm, false); |
---|
721 | | - |
---|
722 | | - fullbatt_vchk(&cm->fullbatt_vchk_work.work); |
---|
723 | | - } else { |
---|
724 | | - cm->emergency_stop = 0; |
---|
725 | | - if (is_ext_pwr_online(cm)) { |
---|
726 | | - if (!try_charger_enable(cm, true)) |
---|
727 | | - uevent_notify(cm, "CHARGING"); |
---|
728 | | - } |
---|
| 613 | + if (cm->battery_status != target) { |
---|
| 614 | + cm->battery_status = target; |
---|
| 615 | + power_supply_changed(cm->charger_psy); |
---|
729 | 616 | } |
---|
730 | 617 | |
---|
731 | | - return true; |
---|
| 618 | + return (cm->battery_status == POWER_SUPPLY_STATUS_NOT_CHARGING); |
---|
732 | 619 | } |
---|
733 | 620 | |
---|
734 | 621 | /** |
---|
.. | .. |
---|
821 | 708 | schedule_work(&setup_polling); |
---|
822 | 709 | } |
---|
823 | 710 | |
---|
824 | | -/** |
---|
825 | | - * fullbatt_handler - Event handler for CM_EVENT_BATT_FULL |
---|
826 | | - * @cm: the Charger Manager representing the battery. |
---|
827 | | - */ |
---|
828 | | -static void fullbatt_handler(struct charger_manager *cm) |
---|
829 | | -{ |
---|
830 | | - struct charger_desc *desc = cm->desc; |
---|
831 | | - |
---|
832 | | - if (!desc->fullbatt_vchkdrop_uV || !desc->fullbatt_vchkdrop_ms) |
---|
833 | | - goto out; |
---|
834 | | - |
---|
835 | | - if (cm_suspended) |
---|
836 | | - device_set_wakeup_capable(cm->dev, true); |
---|
837 | | - |
---|
838 | | - mod_delayed_work(cm_wq, &cm->fullbatt_vchk_work, |
---|
839 | | - msecs_to_jiffies(desc->fullbatt_vchkdrop_ms)); |
---|
840 | | - cm->fullbatt_vchk_jiffies_at = jiffies + msecs_to_jiffies( |
---|
841 | | - desc->fullbatt_vchkdrop_ms); |
---|
842 | | - |
---|
843 | | - if (cm->fullbatt_vchk_jiffies_at == 0) |
---|
844 | | - cm->fullbatt_vchk_jiffies_at = 1; |
---|
845 | | - |
---|
846 | | -out: |
---|
847 | | - dev_info(cm->dev, "EVENT_HANDLE: Battery Fully Charged\n"); |
---|
848 | | - uevent_notify(cm, default_event_names[CM_EVENT_BATT_FULL]); |
---|
849 | | -} |
---|
850 | | - |
---|
851 | | -/** |
---|
852 | | - * battout_handler - Event handler for CM_EVENT_BATT_OUT |
---|
853 | | - * @cm: the Charger Manager representing the battery. |
---|
854 | | - */ |
---|
855 | | -static void battout_handler(struct charger_manager *cm) |
---|
856 | | -{ |
---|
857 | | - if (cm_suspended) |
---|
858 | | - device_set_wakeup_capable(cm->dev, true); |
---|
859 | | - |
---|
860 | | - if (!is_batt_present(cm)) { |
---|
861 | | - dev_emerg(cm->dev, "Battery Pulled Out!\n"); |
---|
862 | | - uevent_notify(cm, default_event_names[CM_EVENT_BATT_OUT]); |
---|
863 | | - } else { |
---|
864 | | - uevent_notify(cm, "Battery Reinserted?"); |
---|
865 | | - } |
---|
866 | | -} |
---|
867 | | - |
---|
868 | | -/** |
---|
869 | | - * misc_event_handler - Handler for other evnets |
---|
870 | | - * @cm: the Charger Manager representing the battery. |
---|
871 | | - * @type: the Charger Manager representing the battery. |
---|
872 | | - */ |
---|
873 | | -static void misc_event_handler(struct charger_manager *cm, |
---|
874 | | - enum cm_event_types type) |
---|
875 | | -{ |
---|
876 | | - if (cm_suspended) |
---|
877 | | - device_set_wakeup_capable(cm->dev, true); |
---|
878 | | - |
---|
879 | | - if (is_polling_required(cm) && cm->desc->polling_interval_ms) |
---|
880 | | - schedule_work(&setup_polling); |
---|
881 | | - uevent_notify(cm, default_event_names[type]); |
---|
882 | | -} |
---|
883 | | - |
---|
884 | 711 | static int charger_get_property(struct power_supply *psy, |
---|
885 | 712 | enum power_supply_property psp, |
---|
886 | 713 | union power_supply_propval *val) |
---|
.. | .. |
---|
893 | 720 | |
---|
894 | 721 | switch (psp) { |
---|
895 | 722 | case POWER_SUPPLY_PROP_STATUS: |
---|
896 | | - if (is_charging(cm)) |
---|
897 | | - val->intval = POWER_SUPPLY_STATUS_CHARGING; |
---|
898 | | - else if (is_ext_pwr_online(cm)) |
---|
899 | | - val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; |
---|
900 | | - else |
---|
901 | | - val->intval = POWER_SUPPLY_STATUS_DISCHARGING; |
---|
| 723 | + val->intval = cm->battery_status; |
---|
902 | 724 | break; |
---|
903 | 725 | case POWER_SUPPLY_PROP_HEALTH: |
---|
904 | 726 | if (cm->emergency_stop > 0) |
---|
.. | .. |
---|
927 | 749 | POWER_SUPPLY_PROP_CURRENT_NOW, val); |
---|
928 | 750 | break; |
---|
929 | 751 | case POWER_SUPPLY_PROP_TEMP: |
---|
930 | | - case POWER_SUPPLY_PROP_TEMP_AMBIENT: |
---|
931 | 752 | return cm_get_battery_temperature(cm, &val->intval); |
---|
932 | 753 | case POWER_SUPPLY_PROP_CAPACITY: |
---|
933 | 754 | if (!is_batt_present(cm)) { |
---|
.. | .. |
---|
983 | 804 | val->intval = 0; |
---|
984 | 805 | break; |
---|
985 | 806 | case POWER_SUPPLY_PROP_CHARGE_FULL: |
---|
986 | | - if (is_full_charged(cm)) |
---|
987 | | - val->intval = 1; |
---|
988 | | - else |
---|
989 | | - val->intval = 0; |
---|
990 | | - ret = 0; |
---|
991 | | - break; |
---|
992 | 807 | case POWER_SUPPLY_PROP_CHARGE_NOW: |
---|
993 | | - if (is_charging(cm)) { |
---|
994 | | - fuel_gauge = power_supply_get_by_name( |
---|
995 | | - cm->desc->psy_fuel_gauge); |
---|
996 | | - if (!fuel_gauge) { |
---|
997 | | - ret = -ENODEV; |
---|
998 | | - break; |
---|
999 | | - } |
---|
1000 | | - |
---|
1001 | | - ret = power_supply_get_property(fuel_gauge, |
---|
1002 | | - POWER_SUPPLY_PROP_CHARGE_NOW, |
---|
1003 | | - val); |
---|
1004 | | - if (ret) { |
---|
1005 | | - val->intval = 1; |
---|
1006 | | - ret = 0; |
---|
1007 | | - } else { |
---|
1008 | | - /* If CHARGE_NOW is supplied, use it */ |
---|
1009 | | - val->intval = (val->intval > 0) ? |
---|
1010 | | - val->intval : 1; |
---|
1011 | | - } |
---|
1012 | | - } else { |
---|
1013 | | - val->intval = 0; |
---|
| 808 | + fuel_gauge = power_supply_get_by_name(cm->desc->psy_fuel_gauge); |
---|
| 809 | + if (!fuel_gauge) { |
---|
| 810 | + ret = -ENODEV; |
---|
| 811 | + break; |
---|
1014 | 812 | } |
---|
| 813 | + ret = power_supply_get_property(fuel_gauge, psp, val); |
---|
1015 | 814 | break; |
---|
1016 | 815 | default: |
---|
1017 | 816 | return -EINVAL; |
---|
.. | .. |
---|
1030 | 829 | POWER_SUPPLY_PROP_VOLTAGE_NOW, |
---|
1031 | 830 | POWER_SUPPLY_PROP_CAPACITY, |
---|
1032 | 831 | POWER_SUPPLY_PROP_ONLINE, |
---|
1033 | | - POWER_SUPPLY_PROP_CHARGE_FULL, |
---|
1034 | 832 | /* |
---|
1035 | 833 | * Optional properties are: |
---|
| 834 | + * POWER_SUPPLY_PROP_CHARGE_FULL, |
---|
1036 | 835 | * POWER_SUPPLY_PROP_CHARGE_NOW, |
---|
1037 | 836 | * POWER_SUPPLY_PROP_CURRENT_NOW, |
---|
1038 | | - * POWER_SUPPLY_PROP_TEMP, and |
---|
1039 | | - * POWER_SUPPLY_PROP_TEMP_AMBIENT, |
---|
| 837 | + * POWER_SUPPLY_PROP_TEMP, |
---|
1040 | 838 | */ |
---|
1041 | 839 | }; |
---|
1042 | 840 | |
---|
.. | .. |
---|
1071 | 869 | |
---|
1072 | 870 | mutex_lock(&cm_list_mtx); |
---|
1073 | 871 | list_for_each_entry(cm, &cm_list, entry) { |
---|
1074 | | - unsigned int fbchk_ms = 0; |
---|
1075 | | - |
---|
1076 | | - /* fullbatt_vchk is required. setup timer for that */ |
---|
1077 | | - if (cm->fullbatt_vchk_jiffies_at) { |
---|
1078 | | - fbchk_ms = jiffies_to_msecs(cm->fullbatt_vchk_jiffies_at |
---|
1079 | | - - jiffies); |
---|
1080 | | - if (time_is_before_eq_jiffies( |
---|
1081 | | - cm->fullbatt_vchk_jiffies_at) || |
---|
1082 | | - msecs_to_jiffies(fbchk_ms) < CM_JIFFIES_SMALL) { |
---|
1083 | | - fullbatt_vchk(&cm->fullbatt_vchk_work.work); |
---|
1084 | | - fbchk_ms = 0; |
---|
1085 | | - } |
---|
1086 | | - } |
---|
1087 | | - CM_MIN_VALID(wakeup_ms, fbchk_ms); |
---|
1088 | | - |
---|
1089 | 872 | /* Skip if polling is not required for this CM */ |
---|
1090 | 873 | if (!is_polling_required(cm) && !cm->emergency_stop) |
---|
1091 | 874 | continue; |
---|
.. | .. |
---|
1147 | 930 | cable->min_uA, cable->max_uA); |
---|
1148 | 931 | } |
---|
1149 | 932 | |
---|
1150 | | - try_charger_enable(cable->cm, cable->attached); |
---|
| 933 | + cancel_delayed_work(&cm_monitor_work); |
---|
| 934 | + queue_delayed_work(cm_wq, &cm_monitor_work, 0); |
---|
1151 | 935 | } |
---|
1152 | 936 | |
---|
1153 | 937 | /** |
---|
.. | .. |
---|
1171 | 955 | cable->attached = event; |
---|
1172 | 956 | |
---|
1173 | 957 | /* |
---|
1174 | | - * Setup monitoring to check battery state |
---|
1175 | | - * when charger cable is attached. |
---|
1176 | | - */ |
---|
1177 | | - if (cable->attached && is_polling_required(cable->cm)) { |
---|
1178 | | - cancel_work_sync(&setup_polling); |
---|
1179 | | - schedule_work(&setup_polling); |
---|
1180 | | - } |
---|
1181 | | - |
---|
1182 | | - /* |
---|
1183 | 958 | * Setup work for controlling charger(regulator) |
---|
1184 | 959 | * according to charger cable. |
---|
1185 | 960 | */ |
---|
.. | .. |
---|
1198 | 973 | static int charger_extcon_init(struct charger_manager *cm, |
---|
1199 | 974 | struct charger_cable *cable) |
---|
1200 | 975 | { |
---|
1201 | | - int ret; |
---|
| 976 | + int ret, i; |
---|
| 977 | + u64 extcon_type = EXTCON_NONE; |
---|
1202 | 978 | |
---|
1203 | 979 | /* |
---|
1204 | 980 | * Charger manager use Extcon framework to identify |
---|
.. | .. |
---|
1207 | 983 | */ |
---|
1208 | 984 | INIT_WORK(&cable->wq, charger_extcon_work); |
---|
1209 | 985 | cable->nb.notifier_call = charger_extcon_notifier; |
---|
1210 | | - ret = extcon_register_interest(&cable->extcon_dev, |
---|
1211 | | - cable->extcon_name, cable->name, &cable->nb); |
---|
1212 | | - if (ret < 0) { |
---|
1213 | | - pr_info("Cannot register extcon_dev for %s(cable: %s)\n", |
---|
| 986 | + |
---|
| 987 | + cable->extcon_dev = extcon_get_extcon_dev(cable->extcon_name); |
---|
| 988 | + if (IS_ERR_OR_NULL(cable->extcon_dev)) { |
---|
| 989 | + pr_err("Cannot find extcon_dev for %s (cable: %s)\n", |
---|
1214 | 990 | cable->extcon_name, cable->name); |
---|
| 991 | + if (cable->extcon_dev == NULL) |
---|
| 992 | + return -EPROBE_DEFER; |
---|
| 993 | + else |
---|
| 994 | + return PTR_ERR(cable->extcon_dev); |
---|
1215 | 995 | } |
---|
1216 | 996 | |
---|
1217 | | - return ret; |
---|
| 997 | + for (i = 0; i < ARRAY_SIZE(extcon_mapping); i++) { |
---|
| 998 | + if (!strcmp(cable->name, extcon_mapping[i].name)) { |
---|
| 999 | + extcon_type = extcon_mapping[i].extcon_type; |
---|
| 1000 | + break; |
---|
| 1001 | + } |
---|
| 1002 | + } |
---|
| 1003 | + if (extcon_type == EXTCON_NONE) { |
---|
| 1004 | + pr_err("Cannot find cable for type %s", cable->name); |
---|
| 1005 | + return -EINVAL; |
---|
| 1006 | + } |
---|
| 1007 | + |
---|
| 1008 | + cable->extcon_type = extcon_type; |
---|
| 1009 | + |
---|
| 1010 | + ret = devm_extcon_register_notifier(cm->dev, cable->extcon_dev, |
---|
| 1011 | + cable->extcon_type, &cable->nb); |
---|
| 1012 | + if (ret < 0) { |
---|
| 1013 | + pr_err("Cannot register extcon_dev for %s (cable: %s)\n", |
---|
| 1014 | + cable->extcon_name, cable->name); |
---|
| 1015 | + return ret; |
---|
| 1016 | + } |
---|
| 1017 | + |
---|
| 1018 | + return 0; |
---|
1218 | 1019 | } |
---|
1219 | 1020 | |
---|
1220 | 1021 | /** |
---|
1221 | | - * charger_manager_register_extcon - Register extcon device to recevie state |
---|
| 1022 | + * charger_manager_register_extcon - Register extcon device to receive state |
---|
1222 | 1023 | * of charger cable. |
---|
1223 | 1024 | * @cm: the Charger Manager representing the battery. |
---|
1224 | 1025 | * |
---|
.. | .. |
---|
1231 | 1032 | { |
---|
1232 | 1033 | struct charger_desc *desc = cm->desc; |
---|
1233 | 1034 | struct charger_regulator *charger; |
---|
| 1035 | + unsigned long event; |
---|
1234 | 1036 | int ret; |
---|
1235 | 1037 | int i; |
---|
1236 | 1038 | int j; |
---|
.. | .. |
---|
1258 | 1060 | } |
---|
1259 | 1061 | cable->charger = charger; |
---|
1260 | 1062 | cable->cm = cm; |
---|
| 1063 | + |
---|
| 1064 | + event = extcon_get_state(cable->extcon_dev, |
---|
| 1065 | + cable->extcon_type); |
---|
| 1066 | + charger_extcon_notifier(&cable->nb, |
---|
| 1067 | + event, NULL); |
---|
1261 | 1068 | } |
---|
1262 | 1069 | } |
---|
1263 | 1070 | |
---|
.. | .. |
---|
1351 | 1158 | } |
---|
1352 | 1159 | |
---|
1353 | 1160 | /** |
---|
1354 | | - * charger_manager_register_sysfs - Register sysfs entry for each charger |
---|
| 1161 | + * charger_manager_prepare_sysfs - Prepare sysfs entry for each charger |
---|
1355 | 1162 | * @cm: the Charger Manager representing the battery. |
---|
1356 | 1163 | * |
---|
1357 | 1164 | * This function add sysfs entry for charger(regulator) to control charger from |
---|
.. | .. |
---|
1363 | 1170 | * externally_control, this charger isn't controlled from charger-manager and |
---|
1364 | 1171 | * always stay off state of regulator. |
---|
1365 | 1172 | */ |
---|
1366 | | -static int charger_manager_register_sysfs(struct charger_manager *cm) |
---|
| 1173 | +static int charger_manager_prepare_sysfs(struct charger_manager *cm) |
---|
1367 | 1174 | { |
---|
1368 | 1175 | struct charger_desc *desc = cm->desc; |
---|
1369 | 1176 | struct charger_regulator *charger; |
---|
1370 | 1177 | int chargers_externally_control = 1; |
---|
1371 | | - char buf[11]; |
---|
1372 | | - char *str; |
---|
1373 | | - int ret; |
---|
| 1178 | + char *name; |
---|
1374 | 1179 | int i; |
---|
1375 | 1180 | |
---|
1376 | 1181 | /* Create sysfs entry to control charger(regulator) */ |
---|
1377 | 1182 | for (i = 0; i < desc->num_charger_regulators; i++) { |
---|
1378 | 1183 | charger = &desc->charger_regulators[i]; |
---|
1379 | 1184 | |
---|
1380 | | - snprintf(buf, 10, "charger.%d", i); |
---|
1381 | | - str = devm_kzalloc(cm->dev, |
---|
1382 | | - strlen(buf) + 1, GFP_KERNEL); |
---|
1383 | | - if (!str) |
---|
| 1185 | + name = devm_kasprintf(cm->dev, GFP_KERNEL, "charger.%d", i); |
---|
| 1186 | + if (!name) |
---|
1384 | 1187 | return -ENOMEM; |
---|
1385 | | - |
---|
1386 | | - strcpy(str, buf); |
---|
1387 | 1188 | |
---|
1388 | 1189 | charger->attrs[0] = &charger->attr_name.attr; |
---|
1389 | 1190 | charger->attrs[1] = &charger->attr_state.attr; |
---|
1390 | 1191 | charger->attrs[2] = &charger->attr_externally_control.attr; |
---|
1391 | 1192 | charger->attrs[3] = NULL; |
---|
1392 | | - charger->attr_g.name = str; |
---|
1393 | | - charger->attr_g.attrs = charger->attrs; |
---|
| 1193 | + |
---|
| 1194 | + charger->attr_grp.name = name; |
---|
| 1195 | + charger->attr_grp.attrs = charger->attrs; |
---|
| 1196 | + desc->sysfs_groups[i] = &charger->attr_grp; |
---|
1394 | 1197 | |
---|
1395 | 1198 | sysfs_attr_init(&charger->attr_name.attr); |
---|
1396 | 1199 | charger->attr_name.attr.name = "name"; |
---|
.. | .. |
---|
1417 | 1220 | |
---|
1418 | 1221 | dev_info(cm->dev, "'%s' regulator's externally_control is %d\n", |
---|
1419 | 1222 | charger->regulator_name, charger->externally_control); |
---|
1420 | | - |
---|
1421 | | - ret = sysfs_create_group(&cm->charger_psy->dev.kobj, |
---|
1422 | | - &charger->attr_g); |
---|
1423 | | - if (ret < 0) { |
---|
1424 | | - dev_err(cm->dev, "Cannot create sysfs entry of %s regulator\n", |
---|
1425 | | - charger->regulator_name); |
---|
1426 | | - return ret; |
---|
1427 | | - } |
---|
1428 | 1223 | } |
---|
1429 | 1224 | |
---|
1430 | 1225 | if (chargers_externally_control) { |
---|
.. | .. |
---|
1436 | 1231 | } |
---|
1437 | 1232 | |
---|
1438 | 1233 | static int cm_init_thermal_data(struct charger_manager *cm, |
---|
1439 | | - struct power_supply *fuel_gauge) |
---|
| 1234 | + struct power_supply *fuel_gauge, |
---|
| 1235 | + enum power_supply_property *properties, |
---|
| 1236 | + size_t *num_properties) |
---|
1440 | 1237 | { |
---|
1441 | 1238 | struct charger_desc *desc = cm->desc; |
---|
1442 | 1239 | union power_supply_propval val; |
---|
.. | .. |
---|
1447 | 1244 | POWER_SUPPLY_PROP_TEMP, &val); |
---|
1448 | 1245 | |
---|
1449 | 1246 | if (!ret) { |
---|
1450 | | - cm->charger_psy_desc.properties[cm->charger_psy_desc.num_properties] = |
---|
1451 | | - POWER_SUPPLY_PROP_TEMP; |
---|
1452 | | - cm->charger_psy_desc.num_properties++; |
---|
| 1247 | + properties[*num_properties] = POWER_SUPPLY_PROP_TEMP; |
---|
| 1248 | + (*num_properties)++; |
---|
1453 | 1249 | cm->desc->measure_battery_temp = true; |
---|
1454 | 1250 | } |
---|
1455 | 1251 | #ifdef CONFIG_THERMAL |
---|
.. | .. |
---|
1460 | 1256 | return PTR_ERR(cm->tzd_batt); |
---|
1461 | 1257 | |
---|
1462 | 1258 | /* Use external thermometer */ |
---|
1463 | | - cm->charger_psy_desc.properties[cm->charger_psy_desc.num_properties] = |
---|
1464 | | - POWER_SUPPLY_PROP_TEMP_AMBIENT; |
---|
1465 | | - cm->charger_psy_desc.num_properties++; |
---|
| 1259 | + properties[*num_properties] = POWER_SUPPLY_PROP_TEMP; |
---|
| 1260 | + (*num_properties)++; |
---|
1466 | 1261 | cm->desc->measure_battery_temp = true; |
---|
1467 | 1262 | ret = 0; |
---|
1468 | 1263 | } |
---|
.. | .. |
---|
1506 | 1301 | of_property_read_u32(np, "cm-poll-interval", |
---|
1507 | 1302 | &desc->polling_interval_ms); |
---|
1508 | 1303 | |
---|
1509 | | - of_property_read_u32(np, "cm-fullbatt-vchkdrop-ms", |
---|
1510 | | - &desc->fullbatt_vchkdrop_ms); |
---|
1511 | 1304 | of_property_read_u32(np, "cm-fullbatt-vchkdrop-volt", |
---|
1512 | 1305 | &desc->fullbatt_vchkdrop_uV); |
---|
1513 | 1306 | of_property_read_u32(np, "cm-fullbatt-voltage", &desc->fullbatt_uV); |
---|
.. | .. |
---|
1519 | 1312 | desc->battery_present = battery_stat; |
---|
1520 | 1313 | |
---|
1521 | 1314 | /* chargers */ |
---|
1522 | | - of_property_read_u32(np, "cm-num-chargers", &num_chgs); |
---|
1523 | | - if (num_chgs) { |
---|
| 1315 | + num_chgs = of_property_count_strings(np, "cm-chargers"); |
---|
| 1316 | + if (num_chgs > 0) { |
---|
| 1317 | + int i; |
---|
| 1318 | + |
---|
1524 | 1319 | /* Allocate empty bin at the tail of array */ |
---|
1525 | 1320 | desc->psy_charger_stat = devm_kcalloc(dev, |
---|
1526 | 1321 | num_chgs + 1, |
---|
1527 | 1322 | sizeof(char *), |
---|
1528 | 1323 | GFP_KERNEL); |
---|
1529 | | - if (desc->psy_charger_stat) { |
---|
1530 | | - int i; |
---|
1531 | | - for (i = 0; i < num_chgs; i++) |
---|
1532 | | - of_property_read_string_index(np, "cm-chargers", |
---|
1533 | | - i, &desc->psy_charger_stat[i]); |
---|
1534 | | - } else { |
---|
| 1324 | + if (!desc->psy_charger_stat) |
---|
1535 | 1325 | return ERR_PTR(-ENOMEM); |
---|
1536 | | - } |
---|
| 1326 | + |
---|
| 1327 | + for (i = 0; i < num_chgs; i++) |
---|
| 1328 | + of_property_read_string_index(np, "cm-chargers", |
---|
| 1329 | + i, &desc->psy_charger_stat[i]); |
---|
1537 | 1330 | } |
---|
1538 | 1331 | |
---|
1539 | 1332 | of_property_read_string(np, "cm-fuel-gauge", &desc->psy_fuel_gauge); |
---|
.. | .. |
---|
1551 | 1344 | of_property_read_u32(np, "cm-discharging-max", |
---|
1552 | 1345 | &desc->discharging_max_duration_ms); |
---|
1553 | 1346 | |
---|
1554 | | - /* battery charger regualtors */ |
---|
| 1347 | + /* battery charger regulators */ |
---|
1555 | 1348 | desc->num_charger_regulators = of_get_child_count(np); |
---|
1556 | 1349 | if (desc->num_charger_regulators) { |
---|
1557 | 1350 | struct charger_regulator *chg_regs; |
---|
.. | .. |
---|
1565 | 1358 | return ERR_PTR(-ENOMEM); |
---|
1566 | 1359 | |
---|
1567 | 1360 | desc->charger_regulators = chg_regs; |
---|
| 1361 | + |
---|
| 1362 | + desc->sysfs_groups = devm_kcalloc(dev, |
---|
| 1363 | + desc->num_charger_regulators + 1, |
---|
| 1364 | + sizeof(*desc->sysfs_groups), |
---|
| 1365 | + GFP_KERNEL); |
---|
| 1366 | + if (!desc->sysfs_groups) |
---|
| 1367 | + return ERR_PTR(-ENOMEM); |
---|
1568 | 1368 | |
---|
1569 | 1369 | for_each_child_of_node(np, child) { |
---|
1570 | 1370 | struct charger_cable *cables; |
---|
.. | .. |
---|
1626 | 1426 | struct charger_desc *desc = cm_get_drv_data(pdev); |
---|
1627 | 1427 | struct charger_manager *cm; |
---|
1628 | 1428 | int ret, i = 0; |
---|
1629 | | - int j = 0; |
---|
1630 | 1429 | union power_supply_propval val; |
---|
1631 | 1430 | struct power_supply *fuel_gauge; |
---|
| 1431 | + enum power_supply_property *properties; |
---|
| 1432 | + size_t num_properties; |
---|
1632 | 1433 | struct power_supply_config psy_cfg = {}; |
---|
1633 | 1434 | |
---|
1634 | 1435 | if (IS_ERR(desc)) { |
---|
.. | .. |
---|
1660 | 1461 | if (desc->fullbatt_uV == 0) { |
---|
1661 | 1462 | dev_info(&pdev->dev, "Ignoring full-battery voltage threshold as it is not supplied\n"); |
---|
1662 | 1463 | } |
---|
1663 | | - if (!desc->fullbatt_vchkdrop_ms || !desc->fullbatt_vchkdrop_uV) { |
---|
| 1464 | + if (!desc->fullbatt_vchkdrop_uV) { |
---|
1664 | 1465 | dev_info(&pdev->dev, "Disabling full-battery voltage drop checking mechanism as it is not supplied\n"); |
---|
1665 | | - desc->fullbatt_vchkdrop_ms = 0; |
---|
1666 | 1466 | desc->fullbatt_vchkdrop_uV = 0; |
---|
1667 | 1467 | } |
---|
1668 | 1468 | if (desc->fullbatt_soc == 0) { |
---|
.. | .. |
---|
1686 | 1486 | dev_err(&pdev->dev, "No fuel gauge power supply defined\n"); |
---|
1687 | 1487 | return -EINVAL; |
---|
1688 | 1488 | } |
---|
1689 | | - |
---|
1690 | | - /* Counting index only */ |
---|
1691 | | - while (desc->psy_charger_stat[i]) |
---|
1692 | | - i++; |
---|
1693 | 1489 | |
---|
1694 | 1490 | /* Check if charger's supplies are present at probe */ |
---|
1695 | 1491 | for (i = 0; desc->psy_charger_stat[i]; i++) { |
---|
.. | .. |
---|
1729 | 1525 | cm->charger_psy_desc.name = cm->psy_name_buf; |
---|
1730 | 1526 | |
---|
1731 | 1527 | /* Allocate for psy properties because they may vary */ |
---|
1732 | | - cm->charger_psy_desc.properties = |
---|
1733 | | - devm_kcalloc(&pdev->dev, |
---|
| 1528 | + properties = devm_kcalloc(&pdev->dev, |
---|
1734 | 1529 | ARRAY_SIZE(default_charger_props) + |
---|
1735 | 1530 | NUM_CHARGER_PSY_OPTIONAL, |
---|
1736 | | - sizeof(enum power_supply_property), GFP_KERNEL); |
---|
1737 | | - if (!cm->charger_psy_desc.properties) |
---|
| 1531 | + sizeof(*properties), GFP_KERNEL); |
---|
| 1532 | + if (!properties) |
---|
1738 | 1533 | return -ENOMEM; |
---|
1739 | 1534 | |
---|
1740 | | - memcpy(cm->charger_psy_desc.properties, default_charger_props, |
---|
| 1535 | + memcpy(properties, default_charger_props, |
---|
1741 | 1536 | sizeof(enum power_supply_property) * |
---|
1742 | 1537 | ARRAY_SIZE(default_charger_props)); |
---|
1743 | | - cm->charger_psy_desc.num_properties = psy_default.num_properties; |
---|
| 1538 | + num_properties = ARRAY_SIZE(default_charger_props); |
---|
1744 | 1539 | |
---|
1745 | 1540 | /* Find which optional psy-properties are available */ |
---|
1746 | 1541 | fuel_gauge = power_supply_get_by_name(desc->psy_fuel_gauge); |
---|
.. | .. |
---|
1750 | 1545 | return -ENODEV; |
---|
1751 | 1546 | } |
---|
1752 | 1547 | if (!power_supply_get_property(fuel_gauge, |
---|
| 1548 | + POWER_SUPPLY_PROP_CHARGE_FULL, &val)) { |
---|
| 1549 | + properties[num_properties] = |
---|
| 1550 | + POWER_SUPPLY_PROP_CHARGE_FULL; |
---|
| 1551 | + num_properties++; |
---|
| 1552 | + } |
---|
| 1553 | + if (!power_supply_get_property(fuel_gauge, |
---|
1753 | 1554 | POWER_SUPPLY_PROP_CHARGE_NOW, &val)) { |
---|
1754 | | - cm->charger_psy_desc.properties[cm->charger_psy_desc.num_properties] = |
---|
| 1555 | + properties[num_properties] = |
---|
1755 | 1556 | POWER_SUPPLY_PROP_CHARGE_NOW; |
---|
1756 | | - cm->charger_psy_desc.num_properties++; |
---|
| 1557 | + num_properties++; |
---|
1757 | 1558 | } |
---|
1758 | 1559 | if (!power_supply_get_property(fuel_gauge, |
---|
1759 | 1560 | POWER_SUPPLY_PROP_CURRENT_NOW, |
---|
1760 | 1561 | &val)) { |
---|
1761 | | - cm->charger_psy_desc.properties[cm->charger_psy_desc.num_properties] = |
---|
| 1562 | + properties[num_properties] = |
---|
1762 | 1563 | POWER_SUPPLY_PROP_CURRENT_NOW; |
---|
1763 | | - cm->charger_psy_desc.num_properties++; |
---|
| 1564 | + num_properties++; |
---|
1764 | 1565 | } |
---|
1765 | 1566 | |
---|
1766 | | - ret = cm_init_thermal_data(cm, fuel_gauge); |
---|
| 1567 | + ret = cm_init_thermal_data(cm, fuel_gauge, properties, &num_properties); |
---|
1767 | 1568 | if (ret) { |
---|
1768 | 1569 | dev_err(&pdev->dev, "Failed to initialize thermal data\n"); |
---|
1769 | 1570 | cm->desc->measure_battery_temp = false; |
---|
1770 | 1571 | } |
---|
1771 | 1572 | power_supply_put(fuel_gauge); |
---|
1772 | 1573 | |
---|
1773 | | - INIT_DELAYED_WORK(&cm->fullbatt_vchk_work, fullbatt_vchk); |
---|
| 1574 | + cm->charger_psy_desc.properties = properties; |
---|
| 1575 | + cm->charger_psy_desc.num_properties = num_properties; |
---|
| 1576 | + |
---|
| 1577 | + /* Register sysfs entry for charger(regulator) */ |
---|
| 1578 | + ret = charger_manager_prepare_sysfs(cm); |
---|
| 1579 | + if (ret < 0) { |
---|
| 1580 | + dev_err(&pdev->dev, |
---|
| 1581 | + "Cannot prepare sysfs entry of regulators\n"); |
---|
| 1582 | + return ret; |
---|
| 1583 | + } |
---|
| 1584 | + psy_cfg.attr_grp = desc->sysfs_groups; |
---|
1774 | 1585 | |
---|
1775 | 1586 | cm->charger_psy = power_supply_register(&pdev->dev, |
---|
1776 | 1587 | &cm->charger_psy_desc, |
---|
.. | .. |
---|
1788 | 1599 | goto err_reg_extcon; |
---|
1789 | 1600 | } |
---|
1790 | 1601 | |
---|
1791 | | - /* Register sysfs entry for charger(regulator) */ |
---|
1792 | | - ret = charger_manager_register_sysfs(cm); |
---|
1793 | | - if (ret < 0) { |
---|
1794 | | - dev_err(&pdev->dev, |
---|
1795 | | - "Cannot initialize sysfs entry of regulator\n"); |
---|
1796 | | - goto err_reg_sysfs; |
---|
1797 | | - } |
---|
1798 | | - |
---|
1799 | 1602 | /* Add to the list */ |
---|
1800 | 1603 | mutex_lock(&cm_list_mtx); |
---|
1801 | 1604 | list_add(&cm->entry, &cm_list); |
---|
.. | .. |
---|
1803 | 1606 | |
---|
1804 | 1607 | /* |
---|
1805 | 1608 | * Charger-manager is capable of waking up the systme from sleep |
---|
1806 | | - * when event is happend through cm_notify_event() |
---|
| 1609 | + * when event is happened through cm_notify_event() |
---|
1807 | 1610 | */ |
---|
1808 | 1611 | device_init_wakeup(&pdev->dev, true); |
---|
1809 | 1612 | device_set_wakeup_capable(&pdev->dev, false); |
---|
1810 | 1613 | |
---|
1811 | 1614 | /* |
---|
1812 | 1615 | * Charger-manager have to check the charging state right after |
---|
1813 | | - * tialization of charger-manager and then update current charging |
---|
| 1616 | + * initialization of charger-manager and then update current charging |
---|
1814 | 1617 | * state. |
---|
1815 | 1618 | */ |
---|
1816 | 1619 | cm_monitor(); |
---|
.. | .. |
---|
1819 | 1622 | |
---|
1820 | 1623 | return 0; |
---|
1821 | 1624 | |
---|
1822 | | -err_reg_sysfs: |
---|
1823 | | - for (i = 0; i < desc->num_charger_regulators; i++) { |
---|
1824 | | - struct charger_regulator *charger; |
---|
1825 | | - |
---|
1826 | | - charger = &desc->charger_regulators[i]; |
---|
1827 | | - sysfs_remove_group(&cm->charger_psy->dev.kobj, |
---|
1828 | | - &charger->attr_g); |
---|
1829 | | - } |
---|
1830 | 1625 | err_reg_extcon: |
---|
1831 | | - for (i = 0; i < desc->num_charger_regulators; i++) { |
---|
1832 | | - struct charger_regulator *charger; |
---|
1833 | | - |
---|
1834 | | - charger = &desc->charger_regulators[i]; |
---|
1835 | | - for (j = 0; j < charger->num_cables; j++) { |
---|
1836 | | - struct charger_cable *cable = &charger->cables[j]; |
---|
1837 | | - /* Remove notifier block if only edev exists */ |
---|
1838 | | - if (cable->extcon_dev.edev) |
---|
1839 | | - extcon_unregister_interest(&cable->extcon_dev); |
---|
1840 | | - } |
---|
1841 | | - |
---|
| 1626 | + for (i = 0; i < desc->num_charger_regulators; i++) |
---|
1842 | 1627 | regulator_put(desc->charger_regulators[i].consumer); |
---|
1843 | | - } |
---|
1844 | 1628 | |
---|
1845 | 1629 | power_supply_unregister(cm->charger_psy); |
---|
1846 | 1630 | |
---|
.. | .. |
---|
1852 | 1636 | struct charger_manager *cm = platform_get_drvdata(pdev); |
---|
1853 | 1637 | struct charger_desc *desc = cm->desc; |
---|
1854 | 1638 | int i = 0; |
---|
1855 | | - int j = 0; |
---|
1856 | 1639 | |
---|
1857 | 1640 | /* Remove from the list */ |
---|
1858 | 1641 | mutex_lock(&cm_list_mtx); |
---|
.. | .. |
---|
1861 | 1644 | |
---|
1862 | 1645 | cancel_work_sync(&setup_polling); |
---|
1863 | 1646 | cancel_delayed_work_sync(&cm_monitor_work); |
---|
1864 | | - |
---|
1865 | | - for (i = 0 ; i < desc->num_charger_regulators ; i++) { |
---|
1866 | | - struct charger_regulator *charger |
---|
1867 | | - = &desc->charger_regulators[i]; |
---|
1868 | | - for (j = 0 ; j < charger->num_cables ; j++) { |
---|
1869 | | - struct charger_cable *cable = &charger->cables[j]; |
---|
1870 | | - extcon_unregister_interest(&cable->extcon_dev); |
---|
1871 | | - } |
---|
1872 | | - } |
---|
1873 | 1647 | |
---|
1874 | 1648 | for (i = 0 ; i < desc->num_charger_regulators ; i++) |
---|
1875 | 1649 | regulator_put(desc->charger_regulators[i].consumer); |
---|
.. | .. |
---|
1918 | 1692 | |
---|
1919 | 1693 | static int cm_suspend_prepare(struct device *dev) |
---|
1920 | 1694 | { |
---|
1921 | | - struct charger_manager *cm = dev_get_drvdata(dev); |
---|
1922 | | - |
---|
1923 | 1695 | if (cm_need_to_awake()) |
---|
1924 | 1696 | return -EBUSY; |
---|
1925 | 1697 | |
---|
.. | .. |
---|
1931 | 1703 | if (cm_timer_set) { |
---|
1932 | 1704 | cancel_work_sync(&setup_polling); |
---|
1933 | 1705 | cancel_delayed_work_sync(&cm_monitor_work); |
---|
1934 | | - cancel_delayed_work(&cm->fullbatt_vchk_work); |
---|
1935 | 1706 | } |
---|
1936 | 1707 | |
---|
1937 | 1708 | return 0; |
---|
.. | .. |
---|
1956 | 1727 | |
---|
1957 | 1728 | _cm_monitor(cm); |
---|
1958 | 1729 | |
---|
1959 | | - /* Re-enqueue delayed work (fullbatt_vchk_work) */ |
---|
1960 | | - if (cm->fullbatt_vchk_jiffies_at) { |
---|
1961 | | - unsigned long delay = 0; |
---|
1962 | | - unsigned long now = jiffies + CM_JIFFIES_SMALL; |
---|
1963 | | - |
---|
1964 | | - if (time_after_eq(now, cm->fullbatt_vchk_jiffies_at)) { |
---|
1965 | | - delay = (unsigned long)((long)now |
---|
1966 | | - - (long)(cm->fullbatt_vchk_jiffies_at)); |
---|
1967 | | - delay = jiffies_to_msecs(delay); |
---|
1968 | | - } else { |
---|
1969 | | - delay = 0; |
---|
1970 | | - } |
---|
1971 | | - |
---|
1972 | | - /* |
---|
1973 | | - * Account for cm_suspend_duration_ms with assuming that |
---|
1974 | | - * timer stops in suspend. |
---|
1975 | | - */ |
---|
1976 | | - if (delay > cm_suspend_duration_ms) |
---|
1977 | | - delay -= cm_suspend_duration_ms; |
---|
1978 | | - else |
---|
1979 | | - delay = 0; |
---|
1980 | | - |
---|
1981 | | - queue_delayed_work(cm_wq, &cm->fullbatt_vchk_work, |
---|
1982 | | - msecs_to_jiffies(delay)); |
---|
1983 | | - } |
---|
1984 | 1730 | device_set_wakeup_capable(cm->dev, false); |
---|
1985 | 1731 | } |
---|
1986 | 1732 | |
---|
.. | .. |
---|
2004 | 1750 | static int __init charger_manager_init(void) |
---|
2005 | 1751 | { |
---|
2006 | 1752 | cm_wq = create_freezable_workqueue("charger_manager"); |
---|
| 1753 | + if (unlikely(!cm_wq)) |
---|
| 1754 | + return -ENOMEM; |
---|
| 1755 | + |
---|
2007 | 1756 | INIT_DELAYED_WORK(&cm_monitor_work, cm_monitor_poller); |
---|
2008 | 1757 | |
---|
2009 | 1758 | return platform_driver_register(&charger_manager_driver); |
---|
.. | .. |
---|
2018 | 1767 | platform_driver_unregister(&charger_manager_driver); |
---|
2019 | 1768 | } |
---|
2020 | 1769 | module_exit(charger_manager_cleanup); |
---|
2021 | | - |
---|
2022 | | -/** |
---|
2023 | | - * cm_notify_event - charger driver notify Charger Manager of charger event |
---|
2024 | | - * @psy: pointer to instance of charger's power_supply |
---|
2025 | | - * @type: type of charger event |
---|
2026 | | - * @msg: optional message passed to uevent_notify fuction |
---|
2027 | | - */ |
---|
2028 | | -void cm_notify_event(struct power_supply *psy, enum cm_event_types type, |
---|
2029 | | - char *msg) |
---|
2030 | | -{ |
---|
2031 | | - struct charger_manager *cm; |
---|
2032 | | - bool found_power_supply = false; |
---|
2033 | | - |
---|
2034 | | - if (psy == NULL) |
---|
2035 | | - return; |
---|
2036 | | - |
---|
2037 | | - mutex_lock(&cm_list_mtx); |
---|
2038 | | - list_for_each_entry(cm, &cm_list, entry) { |
---|
2039 | | - if (match_string(cm->desc->psy_charger_stat, -1, |
---|
2040 | | - psy->desc->name) >= 0) { |
---|
2041 | | - found_power_supply = true; |
---|
2042 | | - break; |
---|
2043 | | - } |
---|
2044 | | - } |
---|
2045 | | - mutex_unlock(&cm_list_mtx); |
---|
2046 | | - |
---|
2047 | | - if (!found_power_supply) |
---|
2048 | | - return; |
---|
2049 | | - |
---|
2050 | | - switch (type) { |
---|
2051 | | - case CM_EVENT_BATT_FULL: |
---|
2052 | | - fullbatt_handler(cm); |
---|
2053 | | - break; |
---|
2054 | | - case CM_EVENT_BATT_OUT: |
---|
2055 | | - battout_handler(cm); |
---|
2056 | | - break; |
---|
2057 | | - case CM_EVENT_BATT_IN: |
---|
2058 | | - case CM_EVENT_EXT_PWR_IN_OUT ... CM_EVENT_CHG_START_STOP: |
---|
2059 | | - misc_event_handler(cm, type); |
---|
2060 | | - break; |
---|
2061 | | - case CM_EVENT_UNKNOWN: |
---|
2062 | | - case CM_EVENT_OTHERS: |
---|
2063 | | - uevent_notify(cm, msg ? msg : default_event_names[type]); |
---|
2064 | | - break; |
---|
2065 | | - default: |
---|
2066 | | - dev_err(cm->dev, "%s: type not specified\n", __func__); |
---|
2067 | | - break; |
---|
2068 | | - } |
---|
2069 | | -} |
---|
2070 | | -EXPORT_SYMBOL_GPL(cm_notify_event); |
---|
2071 | 1770 | |
---|
2072 | 1771 | MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); |
---|
2073 | 1772 | MODULE_DESCRIPTION("Charger Manager"); |
---|