aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/power/charger-manager.txt14
-rw-r--r--drivers/power/charger-manager.c295
-rw-r--r--include/linux/power/charger-manager.h17
3 files changed, 325 insertions, 1 deletions
diff --git a/Documentation/power/charger-manager.txt b/Documentation/power/charger-manager.txt
index 081489f3db2..fdcca991df3 100644
--- a/Documentation/power/charger-manager.txt
+++ b/Documentation/power/charger-manager.txt
@@ -98,6 +98,11 @@ battery), an instance of Charger Manager is attached to it.
98 98
99struct charger_desc { 99struct charger_desc {
100 100
101char *psy_name;
102 : The power-supply-class name of the battery. Default is
103 "battery" if psy_name is NULL. Users can access the psy entries
104 at "/sys/class/power_supply/[psy_name]/".
105
101enum polling_modes polling_mode; 106enum polling_modes polling_mode;
102 : CM_POLL_DISABLE: do not poll this battery. 107 : CM_POLL_DISABLE: do not poll this battery.
103 CM_POLL_ALWAYS: always poll this battery. 108 CM_POLL_ALWAYS: always poll this battery.
@@ -106,6 +111,12 @@ enum polling_modes polling_mode;
106 CM_POLL_CHARGING_ONLY: poll this battery if and only if the 111 CM_POLL_CHARGING_ONLY: poll this battery if and only if the
107 battery is being charged. 112 battery is being charged.
108 113
114unsigned int fullbatt_uV;
115 : If specified with a non-zero value, Charger Manager assumes
116 that the battery is full (capacity = 100) if the battery is not being
117 charged and the battery voltage is equal to or greater than
118 fullbatt_uV.
119
109unsigned int polling_interval_ms; 120unsigned int polling_interval_ms;
110 : Required polling interval in ms. Charger Manager will poll 121 : Required polling interval in ms. Charger Manager will poll
111 this battery every polling_interval_ms or more frequently. 122 this battery every polling_interval_ms or more frequently.
@@ -131,10 +142,13 @@ char *psy_fuel_gauge;
131 : Power-supply-class name of the fuel gauge. 142 : Power-supply-class name of the fuel gauge.
132 143
133int (*temperature_out_of_range)(int *mC); 144int (*temperature_out_of_range)(int *mC);
145bool measure_battery_temp;
134 : This callback returns 0 if the temperature is safe for charging, 146 : This callback returns 0 if the temperature is safe for charging,
135 a positive number if it is too hot to charge, and a negative number 147 a positive number if it is too hot to charge, and a negative number
136 if it is too cold to charge. With the variable mC, the callback returns 148 if it is too cold to charge. With the variable mC, the callback returns
137 the temperature in 1/1000 of centigrade. 149 the temperature in 1/1000 of centigrade.
150 The source of temperature can be battery or ambient one according to
151 the value of measure_battery_temp.
138}; 152};
139 153
1405. Other Considerations 1545. Other Considerations
diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c
index 727a259ea46..0378d019efa 100644
--- a/drivers/power/charger-manager.c
+++ b/drivers/power/charger-manager.c
@@ -122,6 +122,32 @@ static bool is_ext_pwr_online(struct charger_manager *cm)
122} 122}
123 123
124/** 124/**
125 * get_batt_uV - Get the voltage level of the battery
126 * @cm: the Charger Manager representing the battery.
127 * @uV: the voltage level returned.
128 *
129 * Returns 0 if there is no error.
130 * Returns a negative value on error.
131 */
132static int get_batt_uV(struct charger_manager *cm, int *uV)
133{
134 union power_supply_propval val;
135 int ret;
136
137 if (cm->fuel_gauge)
138 ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
139 POWER_SUPPLY_PROP_VOLTAGE_NOW, &val);
140 else
141 return -ENODEV;
142
143 if (ret)
144 return ret;
145
146 *uV = val.intval;
147 return 0;
148}
149
150/**
125 * is_charging - Returns true if the battery is being charged. 151 * is_charging - Returns true if the battery is being charged.
126 * @cm: the Charger Manager representing the battery. 152 * @cm: the Charger Manager representing the battery.
127 */ 153 */
@@ -369,6 +395,208 @@ static bool cm_monitor(void)
369 return stop; 395 return stop;
370} 396}
371 397
398static int charger_get_property(struct power_supply *psy,
399 enum power_supply_property psp,
400 union power_supply_propval *val)
401{
402 struct charger_manager *cm = container_of(psy,
403 struct charger_manager, charger_psy);
404 struct charger_desc *desc = cm->desc;
405 int i, ret = 0, uV;
406
407 switch (psp) {
408 case POWER_SUPPLY_PROP_STATUS:
409 if (is_charging(cm))
410 val->intval = POWER_SUPPLY_STATUS_CHARGING;
411 else if (is_ext_pwr_online(cm))
412 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
413 else
414 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
415 break;
416 case POWER_SUPPLY_PROP_HEALTH:
417 if (cm->emergency_stop > 0)
418 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
419 else if (cm->emergency_stop < 0)
420 val->intval = POWER_SUPPLY_HEALTH_COLD;
421 else
422 val->intval = POWER_SUPPLY_HEALTH_GOOD;
423 break;
424 case POWER_SUPPLY_PROP_PRESENT:
425 if (is_batt_present(cm))
426 val->intval = 1;
427 else
428 val->intval = 0;
429 break;
430 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
431 ret = get_batt_uV(cm, &i);
432 val->intval = i;
433 break;
434 case POWER_SUPPLY_PROP_CURRENT_NOW:
435 ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
436 POWER_SUPPLY_PROP_CURRENT_NOW, val);
437 break;
438 case POWER_SUPPLY_PROP_TEMP:
439 /* in thenth of centigrade */
440 if (cm->last_temp_mC == INT_MIN)
441 desc->temperature_out_of_range(&cm->last_temp_mC);
442 val->intval = cm->last_temp_mC / 100;
443 if (!desc->measure_battery_temp)
444 ret = -ENODEV;
445 break;
446 case POWER_SUPPLY_PROP_TEMP_AMBIENT:
447 /* in thenth of centigrade */
448 if (cm->last_temp_mC == INT_MIN)
449 desc->temperature_out_of_range(&cm->last_temp_mC);
450 val->intval = cm->last_temp_mC / 100;
451 if (desc->measure_battery_temp)
452 ret = -ENODEV;
453 break;
454 case POWER_SUPPLY_PROP_CAPACITY:
455 if (!cm->fuel_gauge) {
456 ret = -ENODEV;
457 break;
458 }
459
460 if (!is_batt_present(cm)) {
461 /* There is no battery. Assume 100% */
462 val->intval = 100;
463 break;
464 }
465
466 ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
467 POWER_SUPPLY_PROP_CAPACITY, val);
468 if (ret)
469 break;
470
471 if (val->intval > 100) {
472 val->intval = 100;
473 break;
474 }
475 if (val->intval < 0)
476 val->intval = 0;
477
478 /* Do not adjust SOC when charging: voltage is overrated */
479 if (is_charging(cm))
480 break;
481
482 /*
483 * If the capacity value is inconsistent, calibrate it base on
484 * the battery voltage values and the thresholds given as desc
485 */
486 ret = get_batt_uV(cm, &uV);
487 if (ret) {
488 /* Voltage information not available. No calibration */
489 ret = 0;
490 break;
491 }
492
493 if (desc->fullbatt_uV > 0 && uV >= desc->fullbatt_uV &&
494 !is_charging(cm)) {
495 val->intval = 100;
496 break;
497 }
498
499 break;
500 case POWER_SUPPLY_PROP_ONLINE:
501 if (is_ext_pwr_online(cm))
502 val->intval = 1;
503 else
504 val->intval = 0;
505 break;
506 case POWER_SUPPLY_PROP_CHARGE_FULL:
507 if (cm->fuel_gauge) {
508 if (cm->fuel_gauge->get_property(cm->fuel_gauge,
509 POWER_SUPPLY_PROP_CHARGE_FULL, val) == 0)
510 break;
511 }
512
513 if (is_ext_pwr_online(cm)) {
514 /* Not full if it's charging. */
515 if (is_charging(cm)) {
516 val->intval = 0;
517 break;
518 }
519 /*
520 * Full if it's powered but not charging andi
521 * not forced stop by emergency
522 */
523 if (!cm->emergency_stop) {
524 val->intval = 1;
525 break;
526 }
527 }
528
529 /* Full if it's over the fullbatt voltage */
530 ret = get_batt_uV(cm, &uV);
531 if (!ret && desc->fullbatt_uV > 0 && uV >= desc->fullbatt_uV &&
532 !is_charging(cm)) {
533 val->intval = 1;
534 break;
535 }
536
537 /* Full if the cap is 100 */
538 if (cm->fuel_gauge) {
539 ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
540 POWER_SUPPLY_PROP_CAPACITY, val);
541 if (!ret && val->intval >= 100 && !is_charging(cm)) {
542 val->intval = 1;
543 break;
544 }
545 }
546
547 val->intval = 0;
548 ret = 0;
549 break;
550 case POWER_SUPPLY_PROP_CHARGE_NOW:
551 if (is_charging(cm)) {
552 ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
553 POWER_SUPPLY_PROP_CHARGE_NOW,
554 val);
555 if (ret) {
556 val->intval = 1;
557 ret = 0;
558 } else {
559 /* If CHARGE_NOW is supplied, use it */
560 val->intval = (val->intval > 0) ?
561 val->intval : 1;
562 }
563 } else {
564 val->intval = 0;
565 }
566 break;
567 default:
568 return -EINVAL;
569 }
570 return ret;
571}
572
573#define NUM_CHARGER_PSY_OPTIONAL (4)
574static enum power_supply_property default_charger_props[] = {
575 /* Guaranteed to provide */
576 POWER_SUPPLY_PROP_STATUS,
577 POWER_SUPPLY_PROP_HEALTH,
578 POWER_SUPPLY_PROP_PRESENT,
579 POWER_SUPPLY_PROP_VOLTAGE_NOW,
580 POWER_SUPPLY_PROP_CAPACITY,
581 POWER_SUPPLY_PROP_ONLINE,
582 POWER_SUPPLY_PROP_CHARGE_FULL,
583 /*
584 * Optional properties are:
585 * POWER_SUPPLY_PROP_CHARGE_NOW,
586 * POWER_SUPPLY_PROP_CURRENT_NOW,
587 * POWER_SUPPLY_PROP_TEMP, and
588 * POWER_SUPPLY_PROP_TEMP_AMBIENT,
589 */
590};
591
592static struct power_supply psy_default = {
593 .name = "battery",
594 .type = POWER_SUPPLY_TYPE_BATTERY,
595 .properties = default_charger_props,
596 .num_properties = ARRAY_SIZE(default_charger_props),
597 .get_property = charger_get_property,
598};
599
372/** 600/**
373 * cm_setup_timer - For in-suspend monitoring setup wakeup alarm 601 * cm_setup_timer - For in-suspend monitoring setup wakeup alarm
374 * for suspend_again. 602 * for suspend_again.
@@ -532,6 +760,7 @@ static int charger_manager_probe(struct platform_device *pdev)
532 struct charger_desc *desc = dev_get_platdata(&pdev->dev); 760 struct charger_desc *desc = dev_get_platdata(&pdev->dev);
533 struct charger_manager *cm; 761 struct charger_manager *cm;
534 int ret = 0, i = 0; 762 int ret = 0, i = 0;
763 union power_supply_propval val;
535 764
536 if (g_desc && !rtc_dev && g_desc->rtc_name) { 765 if (g_desc && !rtc_dev && g_desc->rtc_name) {
537 rtc_dev = rtc_class_open(g_desc->rtc_name); 766 rtc_dev = rtc_class_open(g_desc->rtc_name);
@@ -626,11 +855,68 @@ static int charger_manager_probe(struct platform_device *pdev)
626 855
627 platform_set_drvdata(pdev, cm); 856 platform_set_drvdata(pdev, cm);
628 857
858 memcpy(&cm->charger_psy, &psy_default,
859 sizeof(psy_default));
860 if (!desc->psy_name) {
861 strncpy(cm->psy_name_buf, psy_default.name,
862 PSY_NAME_MAX);
863 } else {
864 strncpy(cm->psy_name_buf, desc->psy_name, PSY_NAME_MAX);
865 }
866 cm->charger_psy.name = cm->psy_name_buf;
867
868 /* Allocate for psy properties because they may vary */
869 cm->charger_psy.properties = kzalloc(sizeof(enum power_supply_property)
870 * (ARRAY_SIZE(default_charger_props) +
871 NUM_CHARGER_PSY_OPTIONAL),
872 GFP_KERNEL);
873 if (!cm->charger_psy.properties) {
874 dev_err(&pdev->dev, "Cannot allocate for psy properties.\n");
875 ret = -ENOMEM;
876 goto err_chg_stat;
877 }
878 memcpy(cm->charger_psy.properties, default_charger_props,
879 sizeof(enum power_supply_property) *
880 ARRAY_SIZE(default_charger_props));
881 cm->charger_psy.num_properties = psy_default.num_properties;
882
883 /* Find which optional psy-properties are available */
884 if (!cm->fuel_gauge->get_property(cm->fuel_gauge,
885 POWER_SUPPLY_PROP_CHARGE_NOW, &val)) {
886 cm->charger_psy.properties[cm->charger_psy.num_properties] =
887 POWER_SUPPLY_PROP_CHARGE_NOW;
888 cm->charger_psy.num_properties++;
889 }
890 if (!cm->fuel_gauge->get_property(cm->fuel_gauge,
891 POWER_SUPPLY_PROP_CURRENT_NOW,
892 &val)) {
893 cm->charger_psy.properties[cm->charger_psy.num_properties] =
894 POWER_SUPPLY_PROP_CURRENT_NOW;
895 cm->charger_psy.num_properties++;
896 }
897 if (!desc->measure_battery_temp) {
898 cm->charger_psy.properties[cm->charger_psy.num_properties] =
899 POWER_SUPPLY_PROP_TEMP_AMBIENT;
900 cm->charger_psy.num_properties++;
901 }
902 if (desc->measure_battery_temp) {
903 cm->charger_psy.properties[cm->charger_psy.num_properties] =
904 POWER_SUPPLY_PROP_TEMP;
905 cm->charger_psy.num_properties++;
906 }
907
908 ret = power_supply_register(NULL, &cm->charger_psy);
909 if (ret) {
910 dev_err(&pdev->dev, "Cannot register charger-manager with"
911 " name \"%s\".\n", cm->charger_psy.name);
912 goto err_register;
913 }
914
629 ret = regulator_bulk_get(&pdev->dev, desc->num_charger_regulators, 915 ret = regulator_bulk_get(&pdev->dev, desc->num_charger_regulators,
630 desc->charger_regulators); 916 desc->charger_regulators);
631 if (ret) { 917 if (ret) {
632 dev_err(&pdev->dev, "Cannot get charger regulators.\n"); 918 dev_err(&pdev->dev, "Cannot get charger regulators.\n");
633 goto err_chg_stat; 919 goto err_bulk_get;
634 } 920 }
635 921
636 ret = try_charger_enable(cm, true); 922 ret = try_charger_enable(cm, true);
@@ -650,6 +936,10 @@ err_chg_enable:
650 if (desc->charger_regulators) 936 if (desc->charger_regulators)
651 regulator_bulk_free(desc->num_charger_regulators, 937 regulator_bulk_free(desc->num_charger_regulators,
652 desc->charger_regulators); 938 desc->charger_regulators);
939err_bulk_get:
940 power_supply_unregister(&cm->charger_psy);
941err_register:
942 kfree(cm->charger_psy.properties);
653err_chg_stat: 943err_chg_stat:
654 kfree(cm->charger_stat); 944 kfree(cm->charger_stat);
655err_no_charger_stat: 945err_no_charger_stat:
@@ -674,6 +964,9 @@ static int __devexit charger_manager_remove(struct platform_device *pdev)
674 if (desc->charger_regulators) 964 if (desc->charger_regulators)
675 regulator_bulk_free(desc->num_charger_regulators, 965 regulator_bulk_free(desc->num_charger_regulators,
676 desc->charger_regulators); 966 desc->charger_regulators);
967
968 power_supply_unregister(&cm->charger_psy);
969 kfree(cm->charger_psy.properties);
677 kfree(cm->charger_stat); 970 kfree(cm->charger_stat);
678 kfree(cm->desc); 971 kfree(cm->desc);
679 kfree(cm); 972 kfree(cm);
diff --git a/include/linux/power/charger-manager.h b/include/linux/power/charger-manager.h
index 102c5b3f332..4f75e531c11 100644
--- a/include/linux/power/charger-manager.h
+++ b/include/linux/power/charger-manager.h
@@ -47,8 +47,12 @@ struct charger_global_desc {
47 47
48/** 48/**
49 * struct charger_desc 49 * struct charger_desc
50 * @psy_name: the name of power-supply-class for charger manager
50 * @polling_mode: 51 * @polling_mode:
51 * Determine which polling mode will be used 52 * Determine which polling mode will be used
53 * @fullbatt_uV: voltage in microvolt
54 * If it is not being charged and VBATT >= fullbatt_uV,
55 * it is assumed to be full.
52 * @polling_interval_ms: interval in millisecond at which 56 * @polling_interval_ms: interval in millisecond at which
53 * charger manager will monitor battery health 57 * charger manager will monitor battery health
54 * @battery_present: 58 * @battery_present:
@@ -62,11 +66,18 @@ struct charger_global_desc {
62 * return_value > 0: overheat 66 * return_value > 0: overheat
63 * return_value == 0: normal 67 * return_value == 0: normal
64 * return_value < 0: cold 68 * return_value < 0: cold
69 * @measure_battery_temp:
70 * true: measure battery temperature
71 * false: measure ambient temperature
65 */ 72 */
66struct charger_desc { 73struct charger_desc {
74 char *psy_name;
75
67 enum polling_modes polling_mode; 76 enum polling_modes polling_mode;
68 unsigned int polling_interval_ms; 77 unsigned int polling_interval_ms;
69 78
79 unsigned int fullbatt_uV;
80
70 enum data_source battery_present; 81 enum data_source battery_present;
71 82
72 char **psy_charger_stat; 83 char **psy_charger_stat;
@@ -77,6 +88,7 @@ struct charger_desc {
77 char *psy_fuel_gauge; 88 char *psy_fuel_gauge;
78 89
79 int (*temperature_out_of_range)(int *mC); 90 int (*temperature_out_of_range)(int *mC);
91 bool measure_battery_temp;
80}; 92};
81 93
82#define PSY_NAME_MAX 30 94#define PSY_NAME_MAX 30
@@ -92,6 +104,8 @@ struct charger_desc {
92 * @emergency_stop: 104 * @emergency_stop:
93 * When setting true, stop charging 105 * When setting true, stop charging
94 * @last_temp_mC: the measured temperature in milli-Celsius 106 * @last_temp_mC: the measured temperature in milli-Celsius
107 * @psy_name_buf: the name of power-supply-class for charger manager
108 * @charger_psy: power_supply for charger manager
95 * @status_save_ext_pwr_inserted: 109 * @status_save_ext_pwr_inserted:
96 * saved status of external power before entering suspend-to-RAM 110 * saved status of external power before entering suspend-to-RAM
97 * @status_save_batt: 111 * @status_save_batt:
@@ -110,6 +124,9 @@ struct charger_manager {
110 int emergency_stop; 124 int emergency_stop;
111 int last_temp_mC; 125 int last_temp_mC;
112 126
127 char psy_name_buf[PSY_NAME_MAX + 1];
128 struct power_supply charger_psy;
129
113 bool status_save_ext_pwr_inserted; 130 bool status_save_ext_pwr_inserted;
114 bool status_save_batt; 131 bool status_save_batt;
115}; 132};