summaryrefslogtreecommitdiff
path: root/firmware/target/arm/imx233/powermgmt-imx233.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/imx233/powermgmt-imx233.c')
-rw-r--r--firmware/target/arm/imx233/powermgmt-imx233.c138
1 files changed, 116 insertions, 22 deletions
diff --git a/firmware/target/arm/imx233/powermgmt-imx233.c b/firmware/target/arm/imx233/powermgmt-imx233.c
index 0f24fa41ff..97f6e08e12 100644
--- a/firmware/target/arm/imx233/powermgmt-imx233.c
+++ b/firmware/target/arm/imx233/powermgmt-imx233.c
@@ -21,30 +21,21 @@
21 21
22#include "powermgmt.h" 22#include "powermgmt.h"
23#include "power-imx233.h" 23#include "power-imx233.h"
24#include "usb-target.h"
25#include "string.h"
26//#define LOGF_ENABLE
27#include "logf.h"
24 28
25const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] = 29#if !defined(IMX233_CHARGE_CURRENT) || !defined(IMX233_STOP_CURRENT) \
26{ 30 || !defined(IMX233_CHARGING_TIMEOUT) || !defined(IMX233_TOPOFF_TIMEOUT)
27 3659 31#error You must define IMX233_CHARGE_CURRENT, IMX233_STOP_CURRENT, \
28}; 32 IMX233_CHARGING_TIMEOUT and IMX233_TOPOFF_TIMEOUT !
29 33#endif
30const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] =
31{
32 3630
33};
34
35/* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */
36const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] =
37{
38 /* Toshiba Gigabeat S Li Ion 700mAH figured from discharge curve */
39 { 3659, 3719, 3745, 3761, 3785, 3813, 3856, 3926, 3984, 4040, 4121 },
40};
41 34
42/* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */ 35/* charger state is maintained in charge_state (see powermgmt.h) */
43const unsigned short percent_to_volt_charge[11] = 36static int timeout_charging; /* timeout before charging will be declared broken */
44{ 37static int timeout_topping_off; /* timeout before stopping charging after topping off */
45 /* Toshiba Gigabeat S Li Ion 700mAH figured from charge curve */ 38static int timeout_4p2_ilimit_increase; /* timeout before increasing 4p2 ilimit */
46 4028, 4063, 4087, 4111, 4135, 4156, 4173, 4185, 4194, 4202, 4208
47};
48 39
49/* Returns battery voltage from ADC [millivolts] */ 40/* Returns battery voltage from ADC [millivolts] */
50unsigned int battery_adc_voltage(void) 41unsigned int battery_adc_voltage(void)
@@ -55,12 +46,115 @@ unsigned int battery_adc_voltage(void)
55 46
56void powermgmt_init_target(void) 47void powermgmt_init_target(void)
57{ 48{
49 imx233_power_set_charge_current(IMX233_CHARGE_CURRENT);
50 imx233_power_set_stop_current(IMX233_STOP_CURRENT);
51 /* assume that adc_init was called and battery monitoring via LRADC setup */
52 __REG_SET(HW_POWER_BATTMONITOR) = HW_POWER_BATTMONITOR__ENBATADJ;
53 /* make sure we are in a known state: disable charger and 4p2 */
54 __REG_SET(HW_POWER_CHARGE) = HW_POWER_CHARGE__PWD_BATTCHRG;
55 __REG_CLR(HW_POWER_DCDC4P2) = HW_POWER_DCDC4P2__ENABLE_DCDC |
56 HW_POWER_DCDC4P2__ENABLE_4P2;
57 __REG_SET(HW_POWER_5VCTRL) = HW_POWER_5VCTRL__PWD_CHARGE_4P2;
58 charge_state = DISCHARGING;
58} 59}
59 60
60void charging_algorithm_step(void) 61void charging_algorithm_step(void)
61{ 62{
63 bool is_5v_present = usb_plugged();
64
65 /* initial state & 5v -> battery transition */
66 if(!is_5v_present && charge_state != DISCHARGING)
67 {
68 logf("pwrmgmt: * -> discharging");
69 logf("pwrmgmt: disable charger and 4p2");
70 /* 5V has been lost: disable 4p2 power rail */
71 __REG_SET(HW_POWER_CHARGE) = HW_POWER_CHARGE__PWD_BATTCHRG;
72 __REG_CLR(HW_POWER_DCDC4P2) = HW_POWER_DCDC4P2__ENABLE_DCDC |
73 HW_POWER_DCDC4P2__ENABLE_4P2;
74 __REG_SET(HW_POWER_5VCTRL) = HW_POWER_5VCTRL__PWD_CHARGE_4P2;
75 charge_state = DISCHARGING;
76 }
77 /* battery -> 5v transition */
78 else if(is_5v_present && charge_state == DISCHARGING)
79 {
80 logf("pwrmgmt: discharging -> trickle");
81 logf("pwrmgmt: begin charging 4p2");
82 /* 5V has been detected: prepare 4.2V power rail for activation */
83 __REG_SET(HW_POWER_DCDC4P2) = HW_POWER_DCDC4P2__ENABLE_4P2;
84 __REG_SET(HW_POWER_CHARGE) = HW_POWER_CHARGE__ENABLE_LOAD;
85 __FIELD_SET(HW_POWER_5VCTRL, CHARGE_4P2_ILIMIT, 1);
86 __REG_CLR(HW_POWER_5VCTRL) = HW_POWER_5VCTRL__PWD_CHARGE_4P2;// FIXME: manual error ?
87 __REG_SET(HW_POWER_DCDC4P2) = HW_POWER_DCDC4P2__ENABLE_DCDC;
88 timeout_4p2_ilimit_increase = current_tick + HZ / 100;
89 charge_state = TRICKLE;
90 }
91 else if(charge_state == TRICKLE && TIME_AFTER(current_tick, timeout_4p2_ilimit_increase))
92 {
93 /* if 4.2V current limit has not reached 780mA, increase it slowly to
94 * charge the 4.2V capacitance */
95 if(__XTRACT(HW_POWER_5VCTRL, CHARGE_4P2_ILIMIT) != 0x3f)
96 {
97 //logf("pwrmgmt: incr 4.2 ilimit");
98 HW_POWER_5VCTRL += 1 << HW_POWER_5VCTRL__CHARGE_4P2_ILIMIT_BP;
99 timeout_4p2_ilimit_increase = current_tick + HZ / 100;
100 }
101 /* we've reached the maximum, take action */
102 else
103 {
104 logf("pwrmgmt: enable dcdc and charger");
105 logf("pwrmgmt: trickle -> charging");
106 /* adjust arbitration between 4.2 and battery */
107 __FIELD_SET(HW_POWER_DCDC4P2, CMPTRIP, 0); /* 85% */
108 __FIELD_SET(HW_POWER_DCDC4P2, DROPOUT_CTRL, 0xe); /* select greater, 200 mV drop */
109 __REG_CLR(HW_POWER_5VCTRL) = HW_POWER_5VCTRL__DCDC_XFER;
110 __REG_SET(HW_POWER_5VCTRL) = HW_POWER_5VCTRL__ENABLE_DCDC;
111 /* enable battery charging */
112 __REG_CLR(HW_POWER_CHARGE) = HW_POWER_CHARGE__PWD_BATTCHRG;
113 charge_state = CHARGING;
114 timeout_charging = current_tick + IMX233_CHARGING_TIMEOUT;
115 }
116 }
117 else if(charge_state == CHARGING && TIME_AFTER(current_tick, timeout_charging))
118 {
119 /* we have charged for a too long time, declare charger broken */
120 logf("pwrmgmt: charging timeout exceeded!");
121 logf("pwrmgmt: charging -> error");
122 /* stop charging */
123 __REG_SET(HW_POWER_5VCTRL) = HW_POWER_5VCTRL__PWD_CHARGE_4P2;
124 /* goto error state */
125 charge_state = CHARGE_STATE_ERROR;
126 }
127 else if(charge_state == CHARGING && !(HW_POWER_STS & HW_POWER_STS__CHRGSTS))
128 {
129 logf("pwrmgmt: topping off");
130 logf("pwrmgmt: charging -> topoff");
131 charge_state = TOPOFF;
132 timeout_topping_off = current_tick + IMX233_TOPOFF_TIMEOUT;
133 }
134 else if(charge_state == TOPOFF && TIME_AFTER(current_tick, timeout_topping_off))
135 {
136 logf("pwrmgmt: charging finished");
137 logf("pwrmgmt: topoff -> disabled");
138 /* stop charging */
139 __REG_SET(HW_POWER_5VCTRL) = HW_POWER_5VCTRL__PWD_CHARGE_4P2;
140 charge_state = CHARGE_STATE_DISABLED;
141 }
62} 142}
63 143
64void charging_algorithm_close(void) 144void charging_algorithm_close(void)
65{ 145{
66} 146}
147
148struct imx233_powermgmt_info_t imx233_powermgmt_get_info(void)
149{
150 struct imx233_powermgmt_info_t info;
151 memset(&info, 0, sizeof(info));
152 info.state = charge_state;
153 info.charging_timeout =
154 charge_state == CHARGING ? timeout_charging - current_tick : 0;
155 info.topoff_timeout =
156 charge_state == TOPOFF ? timeout_topping_off - current_tick : 0;
157 info.incr_4p2_ilimit_timeout =
158 charge_state == TRICKLE ? timeout_4p2_ilimit_increase - current_tick : 0;
159 return info;
160}