aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power
diff options
context:
space:
mode:
authorDonggeun Kim <dg77.kim@samsung.com>2011-12-27 04:47:49 -0500
committerAnton Vorontsov <cbouatmailru@gmail.com>2012-01-03 23:08:45 -0500
commitad3d13eee78ec44194bf919a37e2f711e53cbdf0 (patch)
treee7a950b1e1d2642c4fae0a7019ac7ceed5241104 /drivers/power
parent3bb3dbbd56ea39e5537db8f8041ea95d28f16a7f (diff)
power_supply: Charger-Manager: Add properties for power-supply-class
Charger Manager provides power-supply-class aggregating information from multiple chargers and a fuel-gauge. Signed-off-by: Donggeun Kim <dg77.kim@samsung.com> Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: Anton Vorontsov <cbouatmailru@gmail.com>
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/charger-manager.c295
1 files changed, 294 insertions, 1 deletions
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);