diff options
Diffstat (limited to 'drivers/power/abx500_chargalg.c')
-rw-r--r-- | drivers/power/abx500_chargalg.c | 204 |
1 files changed, 123 insertions, 81 deletions
diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c index 297089146064..f043c0851a76 100644 --- a/drivers/power/abx500_chargalg.c +++ b/drivers/power/abx500_chargalg.c | |||
@@ -33,9 +33,6 @@ | |||
33 | /* End-of-charge criteria counter */ | 33 | /* End-of-charge criteria counter */ |
34 | #define EOC_COND_CNT 10 | 34 | #define EOC_COND_CNT 10 |
35 | 35 | ||
36 | /* Recharge criteria counter */ | ||
37 | #define RCH_COND_CNT 3 | ||
38 | |||
39 | #define to_abx500_chargalg_device_info(x) container_of((x), \ | 36 | #define to_abx500_chargalg_device_info(x) container_of((x), \ |
40 | struct abx500_chargalg, chargalg_psy); | 37 | struct abx500_chargalg, chargalg_psy); |
41 | 38 | ||
@@ -196,7 +193,6 @@ enum maxim_ret { | |||
196 | * @dev: pointer to the structure device | 193 | * @dev: pointer to the structure device |
197 | * @charge_status: battery operating status | 194 | * @charge_status: battery operating status |
198 | * @eoc_cnt: counter used to determine end-of_charge | 195 | * @eoc_cnt: counter used to determine end-of_charge |
199 | * @rch_cnt: counter used to determine start of recharge | ||
200 | * @maintenance_chg: indicate if maintenance charge is active | 196 | * @maintenance_chg: indicate if maintenance charge is active |
201 | * @t_hyst_norm temperature hysteresis when the temperature has been | 197 | * @t_hyst_norm temperature hysteresis when the temperature has been |
202 | * over or under normal limits | 198 | * over or under normal limits |
@@ -207,7 +203,7 @@ enum maxim_ret { | |||
207 | * @chg_info: information about connected charger types | 203 | * @chg_info: information about connected charger types |
208 | * @batt_data: data of the battery | 204 | * @batt_data: data of the battery |
209 | * @susp_status: current charger suspension status | 205 | * @susp_status: current charger suspension status |
210 | * @bat: pointer to the abx500_bm platform data | 206 | * @bm: Platform specific battery management information |
211 | * @chargalg_psy: structure that holds the battery properties exposed by | 207 | * @chargalg_psy: structure that holds the battery properties exposed by |
212 | * the charging algorithm | 208 | * the charging algorithm |
213 | * @events: structure for information about events triggered | 209 | * @events: structure for information about events triggered |
@@ -223,7 +219,6 @@ struct abx500_chargalg { | |||
223 | struct device *dev; | 219 | struct device *dev; |
224 | int charge_status; | 220 | int charge_status; |
225 | int eoc_cnt; | 221 | int eoc_cnt; |
226 | int rch_cnt; | ||
227 | bool maintenance_chg; | 222 | bool maintenance_chg; |
228 | int t_hyst_norm; | 223 | int t_hyst_norm; |
229 | int t_hyst_lowhigh; | 224 | int t_hyst_lowhigh; |
@@ -232,7 +227,7 @@ struct abx500_chargalg { | |||
232 | struct abx500_chargalg_charger_info chg_info; | 227 | struct abx500_chargalg_charger_info chg_info; |
233 | struct abx500_chargalg_battery_data batt_data; | 228 | struct abx500_chargalg_battery_data batt_data; |
234 | struct abx500_chargalg_suspension_status susp_status; | 229 | struct abx500_chargalg_suspension_status susp_status; |
235 | struct abx500_bm_data *bat; | 230 | struct abx500_bm_data *bm; |
236 | struct power_supply chargalg_psy; | 231 | struct power_supply chargalg_psy; |
237 | struct ux500_charger *ac_chg; | 232 | struct ux500_charger *ac_chg; |
238 | struct ux500_charger *usb_chg; | 233 | struct ux500_charger *usb_chg; |
@@ -367,13 +362,13 @@ static void abx500_chargalg_start_safety_timer(struct abx500_chargalg *di) | |||
367 | case AC_CHG: | 362 | case AC_CHG: |
368 | timer_expiration = | 363 | timer_expiration = |
369 | round_jiffies(jiffies + | 364 | round_jiffies(jiffies + |
370 | (di->bat->main_safety_tmr_h * 3600 * HZ)); | 365 | (di->bm->main_safety_tmr_h * 3600 * HZ)); |
371 | break; | 366 | break; |
372 | 367 | ||
373 | case USB_CHG: | 368 | case USB_CHG: |
374 | timer_expiration = | 369 | timer_expiration = |
375 | round_jiffies(jiffies + | 370 | round_jiffies(jiffies + |
376 | (di->bat->usb_safety_tmr_h * 3600 * HZ)); | 371 | (di->bm->usb_safety_tmr_h * 3600 * HZ)); |
377 | break; | 372 | break; |
378 | 373 | ||
379 | default: | 374 | default: |
@@ -450,8 +445,18 @@ static int abx500_chargalg_kick_watchdog(struct abx500_chargalg *di) | |||
450 | { | 445 | { |
451 | /* Check if charger exists and kick watchdog if charging */ | 446 | /* Check if charger exists and kick watchdog if charging */ |
452 | if (di->ac_chg && di->ac_chg->ops.kick_wd && | 447 | if (di->ac_chg && di->ac_chg->ops.kick_wd && |
453 | di->chg_info.online_chg & AC_CHG) | 448 | di->chg_info.online_chg & AC_CHG) { |
449 | /* | ||
450 | * If AB charger watchdog expired, pm2xxx charging | ||
451 | * gets disabled. To be safe, kick both AB charger watchdog | ||
452 | * and pm2xxx watchdog. | ||
453 | */ | ||
454 | if (di->ac_chg->external && | ||
455 | di->usb_chg && di->usb_chg->ops.kick_wd) | ||
456 | di->usb_chg->ops.kick_wd(di->usb_chg); | ||
457 | |||
454 | return di->ac_chg->ops.kick_wd(di->ac_chg); | 458 | return di->ac_chg->ops.kick_wd(di->ac_chg); |
459 | } | ||
455 | else if (di->usb_chg && di->usb_chg->ops.kick_wd && | 460 | else if (di->usb_chg && di->usb_chg->ops.kick_wd && |
456 | di->chg_info.online_chg & USB_CHG) | 461 | di->chg_info.online_chg & USB_CHG) |
457 | return di->usb_chg->ops.kick_wd(di->usb_chg); | 462 | return di->usb_chg->ops.kick_wd(di->usb_chg); |
@@ -608,6 +613,8 @@ static void abx500_chargalg_hold_charging(struct abx500_chargalg *di) | |||
608 | static void abx500_chargalg_start_charging(struct abx500_chargalg *di, | 613 | static void abx500_chargalg_start_charging(struct abx500_chargalg *di, |
609 | int vset, int iset) | 614 | int vset, int iset) |
610 | { | 615 | { |
616 | bool start_chargalg_wd = true; | ||
617 | |||
611 | switch (di->chg_info.charger_type) { | 618 | switch (di->chg_info.charger_type) { |
612 | case AC_CHG: | 619 | case AC_CHG: |
613 | dev_dbg(di->dev, | 620 | dev_dbg(di->dev, |
@@ -625,8 +632,12 @@ static void abx500_chargalg_start_charging(struct abx500_chargalg *di, | |||
625 | 632 | ||
626 | default: | 633 | default: |
627 | dev_err(di->dev, "Unknown charger to charge from\n"); | 634 | dev_err(di->dev, "Unknown charger to charge from\n"); |
635 | start_chargalg_wd = false; | ||
628 | break; | 636 | break; |
629 | } | 637 | } |
638 | |||
639 | if (start_chargalg_wd && !delayed_work_pending(&di->chargalg_wd_work)) | ||
640 | queue_delayed_work(di->chargalg_wq, &di->chargalg_wd_work, 0); | ||
630 | } | 641 | } |
631 | 642 | ||
632 | /** | 643 | /** |
@@ -638,32 +649,32 @@ static void abx500_chargalg_start_charging(struct abx500_chargalg *di, | |||
638 | */ | 649 | */ |
639 | static void abx500_chargalg_check_temp(struct abx500_chargalg *di) | 650 | static void abx500_chargalg_check_temp(struct abx500_chargalg *di) |
640 | { | 651 | { |
641 | if (di->batt_data.temp > (di->bat->temp_low + di->t_hyst_norm) && | 652 | if (di->batt_data.temp > (di->bm->temp_low + di->t_hyst_norm) && |
642 | di->batt_data.temp < (di->bat->temp_high - di->t_hyst_norm)) { | 653 | di->batt_data.temp < (di->bm->temp_high - di->t_hyst_norm)) { |
643 | /* Temp OK! */ | 654 | /* Temp OK! */ |
644 | di->events.btemp_underover = false; | 655 | di->events.btemp_underover = false; |
645 | di->events.btemp_lowhigh = false; | 656 | di->events.btemp_lowhigh = false; |
646 | di->t_hyst_norm = 0; | 657 | di->t_hyst_norm = 0; |
647 | di->t_hyst_lowhigh = 0; | 658 | di->t_hyst_lowhigh = 0; |
648 | } else { | 659 | } else { |
649 | if (((di->batt_data.temp >= di->bat->temp_high) && | 660 | if (((di->batt_data.temp >= di->bm->temp_high) && |
650 | (di->batt_data.temp < | 661 | (di->batt_data.temp < |
651 | (di->bat->temp_over - di->t_hyst_lowhigh))) || | 662 | (di->bm->temp_over - di->t_hyst_lowhigh))) || |
652 | ((di->batt_data.temp > | 663 | ((di->batt_data.temp > |
653 | (di->bat->temp_under + di->t_hyst_lowhigh)) && | 664 | (di->bm->temp_under + di->t_hyst_lowhigh)) && |
654 | (di->batt_data.temp <= di->bat->temp_low))) { | 665 | (di->batt_data.temp <= di->bm->temp_low))) { |
655 | /* TEMP minor!!!!! */ | 666 | /* TEMP minor!!!!! */ |
656 | di->events.btemp_underover = false; | 667 | di->events.btemp_underover = false; |
657 | di->events.btemp_lowhigh = true; | 668 | di->events.btemp_lowhigh = true; |
658 | di->t_hyst_norm = di->bat->temp_hysteresis; | 669 | di->t_hyst_norm = di->bm->temp_hysteresis; |
659 | di->t_hyst_lowhigh = 0; | 670 | di->t_hyst_lowhigh = 0; |
660 | } else if (di->batt_data.temp <= di->bat->temp_under || | 671 | } else if (di->batt_data.temp <= di->bm->temp_under || |
661 | di->batt_data.temp >= di->bat->temp_over) { | 672 | di->batt_data.temp >= di->bm->temp_over) { |
662 | /* TEMP major!!!!! */ | 673 | /* TEMP major!!!!! */ |
663 | di->events.btemp_underover = true; | 674 | di->events.btemp_underover = true; |
664 | di->events.btemp_lowhigh = false; | 675 | di->events.btemp_lowhigh = false; |
665 | di->t_hyst_norm = 0; | 676 | di->t_hyst_norm = 0; |
666 | di->t_hyst_lowhigh = di->bat->temp_hysteresis; | 677 | di->t_hyst_lowhigh = di->bm->temp_hysteresis; |
667 | } else { | 678 | } else { |
668 | /* Within hysteresis */ | 679 | /* Within hysteresis */ |
669 | dev_dbg(di->dev, "Within hysteresis limit temp: %d " | 680 | dev_dbg(di->dev, "Within hysteresis limit temp: %d " |
@@ -682,12 +693,12 @@ static void abx500_chargalg_check_temp(struct abx500_chargalg *di) | |||
682 | */ | 693 | */ |
683 | static void abx500_chargalg_check_charger_voltage(struct abx500_chargalg *di) | 694 | static void abx500_chargalg_check_charger_voltage(struct abx500_chargalg *di) |
684 | { | 695 | { |
685 | if (di->chg_info.usb_volt > di->bat->chg_params->usb_volt_max) | 696 | if (di->chg_info.usb_volt > di->bm->chg_params->usb_volt_max) |
686 | di->chg_info.usb_chg_ok = false; | 697 | di->chg_info.usb_chg_ok = false; |
687 | else | 698 | else |
688 | di->chg_info.usb_chg_ok = true; | 699 | di->chg_info.usb_chg_ok = true; |
689 | 700 | ||
690 | if (di->chg_info.ac_volt > di->bat->chg_params->ac_volt_max) | 701 | if (di->chg_info.ac_volt > di->bm->chg_params->ac_volt_max) |
691 | di->chg_info.ac_chg_ok = false; | 702 | di->chg_info.ac_chg_ok = false; |
692 | else | 703 | else |
693 | di->chg_info.ac_chg_ok = true; | 704 | di->chg_info.ac_chg_ok = true; |
@@ -707,10 +718,10 @@ static void abx500_chargalg_end_of_charge(struct abx500_chargalg *di) | |||
707 | if (di->charge_status == POWER_SUPPLY_STATUS_CHARGING && | 718 | if (di->charge_status == POWER_SUPPLY_STATUS_CHARGING && |
708 | di->charge_state == STATE_NORMAL && | 719 | di->charge_state == STATE_NORMAL && |
709 | !di->maintenance_chg && (di->batt_data.volt >= | 720 | !di->maintenance_chg && (di->batt_data.volt >= |
710 | di->bat->bat_type[di->bat->batt_id].termination_vol || | 721 | di->bm->bat_type[di->bm->batt_id].termination_vol || |
711 | di->events.usb_cv_active || di->events.ac_cv_active) && | 722 | di->events.usb_cv_active || di->events.ac_cv_active) && |
712 | di->batt_data.avg_curr < | 723 | di->batt_data.avg_curr < |
713 | di->bat->bat_type[di->bat->batt_id].termination_curr && | 724 | di->bm->bat_type[di->bm->batt_id].termination_curr && |
714 | di->batt_data.avg_curr > 0) { | 725 | di->batt_data.avg_curr > 0) { |
715 | if (++di->eoc_cnt >= EOC_COND_CNT) { | 726 | if (++di->eoc_cnt >= EOC_COND_CNT) { |
716 | di->eoc_cnt = 0; | 727 | di->eoc_cnt = 0; |
@@ -733,12 +744,12 @@ static void abx500_chargalg_end_of_charge(struct abx500_chargalg *di) | |||
733 | static void init_maxim_chg_curr(struct abx500_chargalg *di) | 744 | static void init_maxim_chg_curr(struct abx500_chargalg *di) |
734 | { | 745 | { |
735 | di->ccm.original_iset = | 746 | di->ccm.original_iset = |
736 | di->bat->bat_type[di->bat->batt_id].normal_cur_lvl; | 747 | di->bm->bat_type[di->bm->batt_id].normal_cur_lvl; |
737 | di->ccm.current_iset = | 748 | di->ccm.current_iset = |
738 | di->bat->bat_type[di->bat->batt_id].normal_cur_lvl; | 749 | di->bm->bat_type[di->bm->batt_id].normal_cur_lvl; |
739 | di->ccm.test_delta_i = di->bat->maxi->charger_curr_step; | 750 | di->ccm.test_delta_i = di->bm->maxi->charger_curr_step; |
740 | di->ccm.max_current = di->bat->maxi->chg_curr; | 751 | di->ccm.max_current = di->bm->maxi->chg_curr; |
741 | di->ccm.condition_cnt = di->bat->maxi->wait_cycles; | 752 | di->ccm.condition_cnt = di->bm->maxi->wait_cycles; |
742 | di->ccm.level = 0; | 753 | di->ccm.level = 0; |
743 | } | 754 | } |
744 | 755 | ||
@@ -755,7 +766,7 @@ static enum maxim_ret abx500_chargalg_chg_curr_maxim(struct abx500_chargalg *di) | |||
755 | { | 766 | { |
756 | int delta_i; | 767 | int delta_i; |
757 | 768 | ||
758 | if (!di->bat->maxi->ena_maxi) | 769 | if (!di->bm->maxi->ena_maxi) |
759 | return MAXIM_RET_NOACTION; | 770 | return MAXIM_RET_NOACTION; |
760 | 771 | ||
761 | delta_i = di->ccm.original_iset - di->batt_data.inst_curr; | 772 | delta_i = di->ccm.original_iset - di->batt_data.inst_curr; |
@@ -766,7 +777,7 @@ static enum maxim_ret abx500_chargalg_chg_curr_maxim(struct abx500_chargalg *di) | |||
766 | if (di->ccm.wait_cnt == 0) { | 777 | if (di->ccm.wait_cnt == 0) { |
767 | dev_dbg(di->dev, "lowering current\n"); | 778 | dev_dbg(di->dev, "lowering current\n"); |
768 | di->ccm.wait_cnt++; | 779 | di->ccm.wait_cnt++; |
769 | di->ccm.condition_cnt = di->bat->maxi->wait_cycles; | 780 | di->ccm.condition_cnt = di->bm->maxi->wait_cycles; |
770 | di->ccm.max_current = | 781 | di->ccm.max_current = |
771 | di->ccm.current_iset - di->ccm.test_delta_i; | 782 | di->ccm.current_iset - di->ccm.test_delta_i; |
772 | di->ccm.current_iset = di->ccm.max_current; | 783 | di->ccm.current_iset = di->ccm.max_current; |
@@ -791,7 +802,7 @@ static enum maxim_ret abx500_chargalg_chg_curr_maxim(struct abx500_chargalg *di) | |||
791 | if (di->ccm.current_iset == di->ccm.original_iset) | 802 | if (di->ccm.current_iset == di->ccm.original_iset) |
792 | return MAXIM_RET_NOACTION; | 803 | return MAXIM_RET_NOACTION; |
793 | 804 | ||
794 | di->ccm.condition_cnt = di->bat->maxi->wait_cycles; | 805 | di->ccm.condition_cnt = di->bm->maxi->wait_cycles; |
795 | di->ccm.current_iset = di->ccm.original_iset; | 806 | di->ccm.current_iset = di->ccm.original_iset; |
796 | di->ccm.level = 0; | 807 | di->ccm.level = 0; |
797 | 808 | ||
@@ -803,7 +814,7 @@ static enum maxim_ret abx500_chargalg_chg_curr_maxim(struct abx500_chargalg *di) | |||
803 | di->ccm.max_current) { | 814 | di->ccm.max_current) { |
804 | if (di->ccm.condition_cnt-- == 0) { | 815 | if (di->ccm.condition_cnt-- == 0) { |
805 | /* Increse the iset with cco.test_delta_i */ | 816 | /* Increse the iset with cco.test_delta_i */ |
806 | di->ccm.condition_cnt = di->bat->maxi->wait_cycles; | 817 | di->ccm.condition_cnt = di->bm->maxi->wait_cycles; |
807 | di->ccm.current_iset += di->ccm.test_delta_i; | 818 | di->ccm.current_iset += di->ccm.test_delta_i; |
808 | di->ccm.level++; | 819 | di->ccm.level++; |
809 | dev_dbg(di->dev, " Maximization needed, increase" | 820 | dev_dbg(di->dev, " Maximization needed, increase" |
@@ -818,7 +829,7 @@ static enum maxim_ret abx500_chargalg_chg_curr_maxim(struct abx500_chargalg *di) | |||
818 | return MAXIM_RET_NOACTION; | 829 | return MAXIM_RET_NOACTION; |
819 | } | 830 | } |
820 | } else { | 831 | } else { |
821 | di->ccm.condition_cnt = di->bat->maxi->wait_cycles; | 832 | di->ccm.condition_cnt = di->bm->maxi->wait_cycles; |
822 | return MAXIM_RET_NOACTION; | 833 | return MAXIM_RET_NOACTION; |
823 | } | 834 | } |
824 | } | 835 | } |
@@ -838,7 +849,7 @@ static void handle_maxim_chg_curr(struct abx500_chargalg *di) | |||
838 | break; | 849 | break; |
839 | case MAXIM_RET_IBAT_TOO_HIGH: | 850 | case MAXIM_RET_IBAT_TOO_HIGH: |
840 | result = abx500_chargalg_update_chg_curr(di, | 851 | result = abx500_chargalg_update_chg_curr(di, |
841 | di->bat->bat_type[di->bat->batt_id].normal_cur_lvl); | 852 | di->bm->bat_type[di->bm->batt_id].normal_cur_lvl); |
842 | if (result) | 853 | if (result) |
843 | dev_err(di->dev, "failed to set chg curr\n"); | 854 | dev_err(di->dev, "failed to set chg curr\n"); |
844 | break; | 855 | break; |
@@ -858,6 +869,7 @@ static int abx500_chargalg_get_ext_psy_data(struct device *dev, void *data) | |||
858 | union power_supply_propval ret; | 869 | union power_supply_propval ret; |
859 | int i, j; | 870 | int i, j; |
860 | bool psy_found = false; | 871 | bool psy_found = false; |
872 | bool capacity_updated = false; | ||
861 | 873 | ||
862 | psy = (struct power_supply *)data; | 874 | psy = (struct power_supply *)data; |
863 | ext = dev_get_drvdata(dev); | 875 | ext = dev_get_drvdata(dev); |
@@ -870,6 +882,16 @@ static int abx500_chargalg_get_ext_psy_data(struct device *dev, void *data) | |||
870 | if (!psy_found) | 882 | if (!psy_found) |
871 | return 0; | 883 | return 0; |
872 | 884 | ||
885 | /* | ||
886 | * If external is not registering 'POWER_SUPPLY_PROP_CAPACITY' to its | ||
887 | * property because of handling that sysfs entry on its own, this is | ||
888 | * the place to get the battery capacity. | ||
889 | */ | ||
890 | if (!ext->get_property(ext, POWER_SUPPLY_PROP_CAPACITY, &ret)) { | ||
891 | di->batt_data.percent = ret.intval; | ||
892 | capacity_updated = true; | ||
893 | } | ||
894 | |||
873 | /* Go through all properties for the psy */ | 895 | /* Go through all properties for the psy */ |
874 | for (j = 0; j < ext->num_properties; j++) { | 896 | for (j = 0; j < ext->num_properties; j++) { |
875 | enum power_supply_property prop; | 897 | enum power_supply_property prop; |
@@ -1154,7 +1176,8 @@ static int abx500_chargalg_get_ext_psy_data(struct device *dev, void *data) | |||
1154 | } | 1176 | } |
1155 | break; | 1177 | break; |
1156 | case POWER_SUPPLY_PROP_CAPACITY: | 1178 | case POWER_SUPPLY_PROP_CAPACITY: |
1157 | di->batt_data.percent = ret.intval; | 1179 | if (!capacity_updated) |
1180 | di->batt_data.percent = ret.intval; | ||
1158 | break; | 1181 | break; |
1159 | default: | 1182 | default: |
1160 | break; | 1183 | break; |
@@ -1210,7 +1233,7 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) | |||
1210 | * this way | 1233 | * this way |
1211 | */ | 1234 | */ |
1212 | if (!charger_status || | 1235 | if (!charger_status || |
1213 | (di->events.batt_unknown && !di->bat->chg_unknown_bat)) { | 1236 | (di->events.batt_unknown && !di->bm->chg_unknown_bat)) { |
1214 | if (di->charge_state != STATE_HANDHELD) { | 1237 | if (di->charge_state != STATE_HANDHELD) { |
1215 | di->events.safety_timer_expired = false; | 1238 | di->events.safety_timer_expired = false; |
1216 | abx500_chargalg_state_to(di, STATE_HANDHELD_INIT); | 1239 | abx500_chargalg_state_to(di, STATE_HANDHELD_INIT); |
@@ -1394,8 +1417,8 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) | |||
1394 | 1417 | ||
1395 | case STATE_NORMAL_INIT: | 1418 | case STATE_NORMAL_INIT: |
1396 | abx500_chargalg_start_charging(di, | 1419 | abx500_chargalg_start_charging(di, |
1397 | di->bat->bat_type[di->bat->batt_id].normal_vol_lvl, | 1420 | di->bm->bat_type[di->bm->batt_id].normal_vol_lvl, |
1398 | di->bat->bat_type[di->bat->batt_id].normal_cur_lvl); | 1421 | di->bm->bat_type[di->bm->batt_id].normal_cur_lvl); |
1399 | abx500_chargalg_state_to(di, STATE_NORMAL); | 1422 | abx500_chargalg_state_to(di, STATE_NORMAL); |
1400 | abx500_chargalg_start_safety_timer(di); | 1423 | abx500_chargalg_start_safety_timer(di); |
1401 | abx500_chargalg_stop_maintenance_timer(di); | 1424 | abx500_chargalg_stop_maintenance_timer(di); |
@@ -1411,7 +1434,7 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) | |||
1411 | handle_maxim_chg_curr(di); | 1434 | handle_maxim_chg_curr(di); |
1412 | if (di->charge_status == POWER_SUPPLY_STATUS_FULL && | 1435 | if (di->charge_status == POWER_SUPPLY_STATUS_FULL && |
1413 | di->maintenance_chg) { | 1436 | di->maintenance_chg) { |
1414 | if (di->bat->no_maintenance) | 1437 | if (di->bm->no_maintenance) |
1415 | abx500_chargalg_state_to(di, | 1438 | abx500_chargalg_state_to(di, |
1416 | STATE_WAIT_FOR_RECHARGE_INIT); | 1439 | STATE_WAIT_FOR_RECHARGE_INIT); |
1417 | else | 1440 | else |
@@ -1424,28 +1447,25 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) | |||
1424 | case STATE_WAIT_FOR_RECHARGE_INIT: | 1447 | case STATE_WAIT_FOR_RECHARGE_INIT: |
1425 | abx500_chargalg_hold_charging(di); | 1448 | abx500_chargalg_hold_charging(di); |
1426 | abx500_chargalg_state_to(di, STATE_WAIT_FOR_RECHARGE); | 1449 | abx500_chargalg_state_to(di, STATE_WAIT_FOR_RECHARGE); |
1427 | di->rch_cnt = RCH_COND_CNT; | ||
1428 | /* Intentional fallthrough */ | 1450 | /* Intentional fallthrough */ |
1429 | 1451 | ||
1430 | case STATE_WAIT_FOR_RECHARGE: | 1452 | case STATE_WAIT_FOR_RECHARGE: |
1431 | if (di->batt_data.volt <= | 1453 | if (di->batt_data.percent <= |
1432 | di->bat->bat_type[di->bat->batt_id].recharge_vol) { | 1454 | di->bm->bat_type[di->bm->batt_id]. |
1433 | if (di->rch_cnt-- == 0) | 1455 | recharge_cap) |
1434 | abx500_chargalg_state_to(di, STATE_NORMAL_INIT); | 1456 | abx500_chargalg_state_to(di, STATE_NORMAL_INIT); |
1435 | } else | ||
1436 | di->rch_cnt = RCH_COND_CNT; | ||
1437 | break; | 1457 | break; |
1438 | 1458 | ||
1439 | case STATE_MAINTENANCE_A_INIT: | 1459 | case STATE_MAINTENANCE_A_INIT: |
1440 | abx500_chargalg_stop_safety_timer(di); | 1460 | abx500_chargalg_stop_safety_timer(di); |
1441 | abx500_chargalg_start_maintenance_timer(di, | 1461 | abx500_chargalg_start_maintenance_timer(di, |
1442 | di->bat->bat_type[ | 1462 | di->bm->bat_type[ |
1443 | di->bat->batt_id].maint_a_chg_timer_h); | 1463 | di->bm->batt_id].maint_a_chg_timer_h); |
1444 | abx500_chargalg_start_charging(di, | 1464 | abx500_chargalg_start_charging(di, |
1445 | di->bat->bat_type[ | 1465 | di->bm->bat_type[ |
1446 | di->bat->batt_id].maint_a_vol_lvl, | 1466 | di->bm->batt_id].maint_a_vol_lvl, |
1447 | di->bat->bat_type[ | 1467 | di->bm->bat_type[ |
1448 | di->bat->batt_id].maint_a_cur_lvl); | 1468 | di->bm->batt_id].maint_a_cur_lvl); |
1449 | abx500_chargalg_state_to(di, STATE_MAINTENANCE_A); | 1469 | abx500_chargalg_state_to(di, STATE_MAINTENANCE_A); |
1450 | power_supply_changed(&di->chargalg_psy); | 1470 | power_supply_changed(&di->chargalg_psy); |
1451 | /* Intentional fallthrough*/ | 1471 | /* Intentional fallthrough*/ |
@@ -1459,13 +1479,13 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) | |||
1459 | 1479 | ||
1460 | case STATE_MAINTENANCE_B_INIT: | 1480 | case STATE_MAINTENANCE_B_INIT: |
1461 | abx500_chargalg_start_maintenance_timer(di, | 1481 | abx500_chargalg_start_maintenance_timer(di, |
1462 | di->bat->bat_type[ | 1482 | di->bm->bat_type[ |
1463 | di->bat->batt_id].maint_b_chg_timer_h); | 1483 | di->bm->batt_id].maint_b_chg_timer_h); |
1464 | abx500_chargalg_start_charging(di, | 1484 | abx500_chargalg_start_charging(di, |
1465 | di->bat->bat_type[ | 1485 | di->bm->bat_type[ |
1466 | di->bat->batt_id].maint_b_vol_lvl, | 1486 | di->bm->batt_id].maint_b_vol_lvl, |
1467 | di->bat->bat_type[ | 1487 | di->bm->bat_type[ |
1468 | di->bat->batt_id].maint_b_cur_lvl); | 1488 | di->bm->batt_id].maint_b_cur_lvl); |
1469 | abx500_chargalg_state_to(di, STATE_MAINTENANCE_B); | 1489 | abx500_chargalg_state_to(di, STATE_MAINTENANCE_B); |
1470 | power_supply_changed(&di->chargalg_psy); | 1490 | power_supply_changed(&di->chargalg_psy); |
1471 | /* Intentional fallthrough*/ | 1491 | /* Intentional fallthrough*/ |
@@ -1479,10 +1499,10 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) | |||
1479 | 1499 | ||
1480 | case STATE_TEMP_LOWHIGH_INIT: | 1500 | case STATE_TEMP_LOWHIGH_INIT: |
1481 | abx500_chargalg_start_charging(di, | 1501 | abx500_chargalg_start_charging(di, |
1482 | di->bat->bat_type[ | 1502 | di->bm->bat_type[ |
1483 | di->bat->batt_id].low_high_vol_lvl, | 1503 | di->bm->batt_id].low_high_vol_lvl, |
1484 | di->bat->bat_type[ | 1504 | di->bm->bat_type[ |
1485 | di->bat->batt_id].low_high_cur_lvl); | 1505 | di->bm->batt_id].low_high_cur_lvl); |
1486 | abx500_chargalg_stop_maintenance_timer(di); | 1506 | abx500_chargalg_stop_maintenance_timer(di); |
1487 | di->charge_status = POWER_SUPPLY_STATUS_CHARGING; | 1507 | di->charge_status = POWER_SUPPLY_STATUS_CHARGING; |
1488 | abx500_chargalg_state_to(di, STATE_TEMP_LOWHIGH); | 1508 | abx500_chargalg_state_to(di, STATE_TEMP_LOWHIGH); |
@@ -1543,11 +1563,11 @@ static void abx500_chargalg_periodic_work(struct work_struct *work) | |||
1543 | if (di->chg_info.conn_chg) | 1563 | if (di->chg_info.conn_chg) |
1544 | queue_delayed_work(di->chargalg_wq, | 1564 | queue_delayed_work(di->chargalg_wq, |
1545 | &di->chargalg_periodic_work, | 1565 | &di->chargalg_periodic_work, |
1546 | di->bat->interval_charging * HZ); | 1566 | di->bm->interval_charging * HZ); |
1547 | else | 1567 | else |
1548 | queue_delayed_work(di->chargalg_wq, | 1568 | queue_delayed_work(di->chargalg_wq, |
1549 | &di->chargalg_periodic_work, | 1569 | &di->chargalg_periodic_work, |
1550 | di->bat->interval_not_charging * HZ); | 1570 | di->bm->interval_not_charging * HZ); |
1551 | } | 1571 | } |
1552 | 1572 | ||
1553 | /** | 1573 | /** |
@@ -1614,10 +1634,13 @@ static int abx500_chargalg_get_property(struct power_supply *psy, | |||
1614 | if (di->events.batt_ovv) { | 1634 | if (di->events.batt_ovv) { |
1615 | val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; | 1635 | val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; |
1616 | } else if (di->events.btemp_underover) { | 1636 | } else if (di->events.btemp_underover) { |
1617 | if (di->batt_data.temp <= di->bat->temp_under) | 1637 | if (di->batt_data.temp <= di->bm->temp_under) |
1618 | val->intval = POWER_SUPPLY_HEALTH_COLD; | 1638 | val->intval = POWER_SUPPLY_HEALTH_COLD; |
1619 | else | 1639 | else |
1620 | val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; | 1640 | val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; |
1641 | } else if (di->charge_state == STATE_SAFETY_TIMER_EXPIRED || | ||
1642 | di->charge_state == STATE_SAFETY_TIMER_EXPIRED_INIT) { | ||
1643 | val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; | ||
1621 | } else { | 1644 | } else { |
1622 | val->intval = POWER_SUPPLY_HEALTH_GOOD; | 1645 | val->intval = POWER_SUPPLY_HEALTH_GOOD; |
1623 | } | 1646 | } |
@@ -1631,6 +1654,25 @@ static int abx500_chargalg_get_property(struct power_supply *psy, | |||
1631 | /* Exposure to the sysfs interface */ | 1654 | /* Exposure to the sysfs interface */ |
1632 | 1655 | ||
1633 | /** | 1656 | /** |
1657 | * abx500_chargalg_sysfs_show() - sysfs show operations | ||
1658 | * @kobj: pointer to the struct kobject | ||
1659 | * @attr: pointer to the struct attribute | ||
1660 | * @buf: buffer that holds the parameter to send to userspace | ||
1661 | * | ||
1662 | * Returns a buffer to be displayed in user space | ||
1663 | */ | ||
1664 | static ssize_t abx500_chargalg_sysfs_show(struct kobject *kobj, | ||
1665 | struct attribute *attr, char *buf) | ||
1666 | { | ||
1667 | struct abx500_chargalg *di = container_of(kobj, | ||
1668 | struct abx500_chargalg, chargalg_kobject); | ||
1669 | |||
1670 | return sprintf(buf, "%d\n", | ||
1671 | di->susp_status.ac_suspended && | ||
1672 | di->susp_status.usb_suspended); | ||
1673 | } | ||
1674 | |||
1675 | /** | ||
1634 | * abx500_chargalg_sysfs_charger() - sysfs store operations | 1676 | * abx500_chargalg_sysfs_charger() - sysfs store operations |
1635 | * @kobj: pointer to the struct kobject | 1677 | * @kobj: pointer to the struct kobject |
1636 | * @attr: pointer to the struct attribute | 1678 | * @attr: pointer to the struct attribute |
@@ -1698,7 +1740,7 @@ static ssize_t abx500_chargalg_sysfs_charger(struct kobject *kobj, | |||
1698 | static struct attribute abx500_chargalg_en_charger = \ | 1740 | static struct attribute abx500_chargalg_en_charger = \ |
1699 | { | 1741 | { |
1700 | .name = "chargalg", | 1742 | .name = "chargalg", |
1701 | .mode = S_IWUGO, | 1743 | .mode = S_IRUGO | S_IWUSR, |
1702 | }; | 1744 | }; |
1703 | 1745 | ||
1704 | static struct attribute *abx500_chargalg_chg[] = { | 1746 | static struct attribute *abx500_chargalg_chg[] = { |
@@ -1707,6 +1749,7 @@ static struct attribute *abx500_chargalg_chg[] = { | |||
1707 | }; | 1749 | }; |
1708 | 1750 | ||
1709 | static const struct sysfs_ops abx500_chargalg_sysfs_ops = { | 1751 | static const struct sysfs_ops abx500_chargalg_sysfs_ops = { |
1752 | .show = abx500_chargalg_sysfs_show, | ||
1710 | .store = abx500_chargalg_sysfs_charger, | 1753 | .store = abx500_chargalg_sysfs_charger, |
1711 | }; | 1754 | }; |
1712 | 1755 | ||
@@ -1806,6 +1849,7 @@ static char *supply_interface[] = { | |||
1806 | static int abx500_chargalg_probe(struct platform_device *pdev) | 1849 | static int abx500_chargalg_probe(struct platform_device *pdev) |
1807 | { | 1850 | { |
1808 | struct device_node *np = pdev->dev.of_node; | 1851 | struct device_node *np = pdev->dev.of_node; |
1852 | struct abx500_bm_data *plat = pdev->dev.platform_data; | ||
1809 | struct abx500_chargalg *di; | 1853 | struct abx500_chargalg *di; |
1810 | int ret = 0; | 1854 | int ret = 0; |
1811 | 1855 | ||
@@ -1814,21 +1858,19 @@ static int abx500_chargalg_probe(struct platform_device *pdev) | |||
1814 | dev_err(&pdev->dev, "%s no mem for ab8500_chargalg\n", __func__); | 1858 | dev_err(&pdev->dev, "%s no mem for ab8500_chargalg\n", __func__); |
1815 | return -ENOMEM; | 1859 | return -ENOMEM; |
1816 | } | 1860 | } |
1817 | di->bat = pdev->mfd_cell->platform_data; | 1861 | |
1818 | if (!di->bat) { | 1862 | if (!plat) { |
1819 | if (np) { | 1863 | dev_err(&pdev->dev, "no battery management data supplied\n"); |
1820 | ret = bmdevs_of_probe(&pdev->dev, np, &di->bat); | 1864 | return -EINVAL; |
1821 | if (ret) { | 1865 | } |
1822 | dev_err(&pdev->dev, | 1866 | di->bm = plat; |
1823 | "failed to get battery information\n"); | 1867 | |
1824 | return ret; | 1868 | if (np) { |
1825 | } | 1869 | ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm); |
1826 | } else { | 1870 | if (ret) { |
1827 | dev_err(&pdev->dev, "missing dt node for ab8500_chargalg\n"); | 1871 | dev_err(&pdev->dev, "failed to get battery information\n"); |
1828 | return -EINVAL; | 1872 | return ret; |
1829 | } | 1873 | } |
1830 | } else { | ||
1831 | dev_info(&pdev->dev, "falling back to legacy platform data\n"); | ||
1832 | } | 1874 | } |
1833 | 1875 | ||
1834 | /* get device struct */ | 1876 | /* get device struct */ |