diff options
Diffstat (limited to 'firmware/target/arm/imx233/powermgmt-imx233.c')
-rw-r--r-- | firmware/target/arm/imx233/powermgmt-imx233.c | 138 |
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 | ||
25 | const 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 | |
30 | const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] = | ||
31 | { | ||
32 | 3630 | ||
33 | }; | ||
34 | |||
35 | /* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */ | ||
36 | const 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) */ |
43 | const unsigned short percent_to_volt_charge[11] = | 36 | static int timeout_charging; /* timeout before charging will be declared broken */ |
44 | { | 37 | static int timeout_topping_off; /* timeout before stopping charging after topping off */ |
45 | /* Toshiba Gigabeat S Li Ion 700mAH figured from charge curve */ | 38 | static 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] */ |
50 | unsigned int battery_adc_voltage(void) | 41 | unsigned int battery_adc_voltage(void) |
@@ -55,12 +46,115 @@ unsigned int battery_adc_voltage(void) | |||
55 | 46 | ||
56 | void powermgmt_init_target(void) | 47 | void 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 | ||
60 | void charging_algorithm_step(void) | 61 | void 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 | ||
64 | void charging_algorithm_close(void) | 144 | void charging_algorithm_close(void) |
65 | { | 145 | { |
66 | } | 146 | } |
147 | |||
148 | struct 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 | } | ||