diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/SOURCES | 1 | ||||
-rw-r--r-- | firmware/export/imx233.h | 1 | ||||
-rw-r--r-- | firmware/target/arm/imx233/debug-imx233.c | 68 | ||||
-rw-r--r-- | firmware/target/arm/imx233/power-imx233.c | 123 | ||||
-rw-r--r-- | firmware/target/arm/imx233/power-imx233.h | 71 | ||||
-rw-r--r-- | firmware/target/arm/imx233/powermgmt-imx233.c | 138 | ||||
-rw-r--r-- | firmware/target/arm/imx233/sansa-fuzeplus/powermgmt-fuzeplus.c | 46 | ||||
-rw-r--r-- | firmware/target/arm/imx233/sansa-fuzeplus/powermgmt-target.h (renamed from firmware/target/arm/imx233/powermgmt-target.h) | 24 |
8 files changed, 432 insertions, 40 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES index f59475e27a..e80a7492b1 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES | |||
@@ -1382,6 +1382,7 @@ target/arm/imx233/sansa-fuzeplus/power-fuzeplus.c | |||
1382 | target/arm/imx233/sansa-fuzeplus/adc-fuzeplus.c | 1382 | target/arm/imx233/sansa-fuzeplus/adc-fuzeplus.c |
1383 | #ifndef BOOTLOADER | 1383 | #ifndef BOOTLOADER |
1384 | target/arm/imx233/sansa-fuzeplus/audio-fuzeplus.c | 1384 | target/arm/imx233/sansa-fuzeplus/audio-fuzeplus.c |
1385 | target/arm/imx233/sansa-fuzeplus/powermgmt-fuzeplus.c | ||
1385 | #endif | 1386 | #endif |
1386 | #endif | 1387 | #endif |
1387 | 1388 | ||
diff --git a/firmware/export/imx233.h b/firmware/export/imx233.h index 1fa16154c1..a68ca6df13 100644 --- a/firmware/export/imx233.h +++ b/firmware/export/imx233.h | |||
@@ -90,5 +90,6 @@ | |||
90 | 90 | ||
91 | #define __XTRACT(reg, field) ((reg & reg##__##field##_BM) >> reg##__##field##_BP) | 91 | #define __XTRACT(reg, field) ((reg & reg##__##field##_BM) >> reg##__##field##_BP) |
92 | #define __XTRACT_EX(val, field) (((val) & field##_BM) >> field##_BP) | 92 | #define __XTRACT_EX(val, field) (((val) & field##_BM) >> field##_BP) |
93 | #define __FIELD_SET(reg, field, val) reg = (reg & ~reg##__##field##_BM) | (val << reg##__##field##_BP) | ||
93 | 94 | ||
94 | #endif /* __IMX233_H__ */ | 95 | #endif /* __IMX233_H__ */ |
diff --git a/firmware/target/arm/imx233/debug-imx233.c b/firmware/target/arm/imx233/debug-imx233.c index e6b07aef58..896c5bf6c3 100644 --- a/firmware/target/arm/imx233/debug-imx233.c +++ b/firmware/target/arm/imx233/debug-imx233.c | |||
@@ -29,7 +29,7 @@ | |||
29 | #include "adc-imx233.h" | 29 | #include "adc-imx233.h" |
30 | #include "power-imx233.h" | 30 | #include "power-imx233.h" |
31 | #include "clkctrl-imx233.h" | 31 | #include "clkctrl-imx233.h" |
32 | #include "powermgmt.h" | 32 | #include "powermgmt-imx233.h" |
33 | #include "string.h" | 33 | #include "string.h" |
34 | 34 | ||
35 | static struct | 35 | static struct |
@@ -107,11 +107,22 @@ bool dbg_hw_info_power(void) | |||
107 | lcd_clear_display(); | 107 | lcd_clear_display(); |
108 | 108 | ||
109 | struct imx233_power_info_t info = imx233_power_get_info(POWER_INFO_ALL); | 109 | struct imx233_power_info_t info = imx233_power_get_info(POWER_INFO_ALL); |
110 | lcd_putsf(0, 0, "VDDD: %d mV linreg: %d", info.vddd, info.vddd_linreg); | 110 | lcd_putsf(0, 0, "VDDD: %d mV linreg: %d offset: %d", info.vddd, info.vddd_linreg, |
111 | lcd_putsf(0, 1, "VDDA: %d mV linreg: %d", info.vdda, info.vdda_linreg); | 111 | info.vddd_linreg_offset); |
112 | lcd_putsf(0, 2, "VDDIO: %d mV", info.vddio); | 112 | lcd_putsf(0, 1, "VDDA: %d mV linreg: %d offset: %d", info.vdda, info.vdda_linreg, |
113 | info.vdda_linreg_offset); | ||
114 | lcd_putsf(0, 2, "VDDIO: %d mV offset: %d", info.vddio, info.vddio_linreg_offset); | ||
113 | lcd_putsf(0, 3, "VDDMEM: %d mV linreg: %d", info.vddmem, info.vddmem_linreg); | 115 | lcd_putsf(0, 3, "VDDMEM: %d mV linreg: %d", info.vddmem, info.vddmem_linreg); |
114 | lcd_putsf(0, 4, "DC-DC: pll: %d freq: %d", info.dcdc_sel_pllclk, info.dcdc_freqsel); | 116 | lcd_putsf(0, 4, "DC-DC: pll: %d freq: %d", info.dcdc_sel_pllclk, info.dcdc_freqsel); |
117 | lcd_putsf(0, 5, "charge: %d mA stop: %d mA", info.charge_current, info.stop_current); | ||
118 | lcd_putsf(0, 6, "charging: %d bat_adj: %d", info.charging, info.batt_adj); | ||
119 | lcd_putsf(0, 7, "4.2: en: %d dcdc: %d", info._4p2_enable, info._4p2_dcdc); | ||
120 | lcd_putsf(0, 8, "4.2: cmptrip: %d dropout: %d", info._4p2_cmptrip, info._4p2_dropout); | ||
121 | lcd_putsf(0, 9, "5V: pwd_4.2_charge: %d", info._5v_pwd_charge_4p2); | ||
122 | lcd_putsf(0, 10, "5V: chargelim: %d mA", info._5v_charge_4p2_limit); | ||
123 | lcd_putsf(0, 11, "5V: dcdc: %d xfer: %d", info._5v_enable_dcdc, info._5v_dcdc_xfer); | ||
124 | lcd_putsf(0, 12, "5V: thr: %d mV use: %d cmps: %d", info._5v_vbusvalid_thr, | ||
125 | info._5v_vbusvalid_detect, info._5v_vbus_cmps); | ||
115 | 126 | ||
116 | lcd_update(); | 127 | lcd_update(); |
117 | yield(); | 128 | yield(); |
@@ -194,12 +205,6 @@ static struct | |||
194 | bool dbg_hw_info_clkctrl(void) | 205 | bool dbg_hw_info_clkctrl(void) |
195 | { | 206 | { |
196 | lcd_setfont(FONT_SYSFIXED); | 207 | lcd_setfont(FONT_SYSFIXED); |
197 | imx233_enable_auto_slow_monitor(AS_CPU_INSTR, true); | ||
198 | imx233_enable_auto_slow_monitor(AS_CPU_DATA, true); | ||
199 | imx233_enable_auto_slow_monitor(AS_TRAFFIC, true); | ||
200 | imx233_enable_auto_slow_monitor(AS_TRAFFIC_JAM, true); | ||
201 | imx233_enable_auto_slow_monitor(AS_APBXDMA, true); | ||
202 | imx233_enable_auto_slow_monitor(AS_APBHDMA, true); | ||
203 | 208 | ||
204 | while(1) | 209 | while(1) |
205 | { | 210 | { |
@@ -269,10 +274,49 @@ bool dbg_hw_info_clkctrl(void) | |||
269 | } | 274 | } |
270 | } | 275 | } |
271 | 276 | ||
277 | bool dbg_hw_info_powermgmt(void) | ||
278 | { | ||
279 | lcd_setfont(FONT_SYSFIXED); | ||
280 | |||
281 | while(1) | ||
282 | { | ||
283 | int button = get_action(CONTEXT_STD, HZ / 10); | ||
284 | switch(button) | ||
285 | { | ||
286 | case ACTION_STD_NEXT: | ||
287 | case ACTION_STD_PREV: | ||
288 | case ACTION_STD_OK: | ||
289 | case ACTION_STD_MENU: | ||
290 | lcd_setfont(FONT_UI); | ||
291 | return true; | ||
292 | case ACTION_STD_CANCEL: | ||
293 | lcd_setfont(FONT_UI); | ||
294 | return false; | ||
295 | } | ||
296 | |||
297 | lcd_clear_display(); | ||
298 | struct imx233_powermgmt_info_t info = imx233_powermgmt_get_info(); | ||
299 | |||
300 | lcd_putsf(0, 0, "state: %s", | ||
301 | info.state == CHARGE_STATE_DISABLED ? "disabled" : | ||
302 | info.state == CHARGE_STATE_ERROR ? "error" : | ||
303 | info.state == DISCHARGING ? "discharging" : | ||
304 | info.state == TRICKLE ? "trickle" : | ||
305 | info.state == TOPOFF ? "topoff" : | ||
306 | info.state == CHARGING ? "charging" : "<unknown>"); | ||
307 | lcd_putsf(0, 1, "charging tmo: %d", info.charging_timeout); | ||
308 | lcd_putsf(0, 2, "topoff tmo: %d", info.topoff_timeout); | ||
309 | lcd_putsf(0, 3, "4p2ilimit tmo: %d", info.incr_4p2_ilimit_timeout); | ||
310 | |||
311 | lcd_update(); | ||
312 | yield(); | ||
313 | } | ||
314 | } | ||
315 | |||
272 | bool dbg_hw_info(void) | 316 | bool dbg_hw_info(void) |
273 | { | 317 | { |
274 | return dbg_hw_info_clkctrl() && dbg_hw_info_dma() && dbg_hw_info_adc() && dbg_hw_info_power() && | 318 | return dbg_hw_info_clkctrl() && dbg_hw_info_dma() && dbg_hw_info_adc() && |
275 | dbg_hw_target_info(); | 319 | dbg_hw_info_power() && dbg_hw_info_powermgmt() && dbg_hw_target_info(); |
276 | } | 320 | } |
277 | 321 | ||
278 | bool dbg_ports(void) | 322 | bool dbg_ports(void) |
diff --git a/firmware/target/arm/imx233/power-imx233.c b/firmware/target/arm/imx233/power-imx233.c index 557b8521d5..ac1a407ba0 100644 --- a/firmware/target/arm/imx233/power-imx233.c +++ b/firmware/target/arm/imx233/power-imx233.c | |||
@@ -26,6 +26,43 @@ | |||
26 | #include "system-target.h" | 26 | #include "system-target.h" |
27 | #include "usb-target.h" | 27 | #include "usb-target.h" |
28 | 28 | ||
29 | struct current_step_bit_t | ||
30 | { | ||
31 | unsigned current; | ||
32 | uint32_t bit; | ||
33 | }; | ||
34 | |||
35 | /* in decreasing order */ | ||
36 | static struct current_step_bit_t g_charger_current_bits[] = | ||
37 | { | ||
38 | { 400, HW_POWER_CHARGE__BATTCHRG_I__400mA }, | ||
39 | { 200, HW_POWER_CHARGE__BATTCHRG_I__200mA }, | ||
40 | { 100, HW_POWER_CHARGE__BATTCHRG_I__100mA }, | ||
41 | { 50, HW_POWER_CHARGE__BATTCHRG_I__50mA }, | ||
42 | { 20, HW_POWER_CHARGE__BATTCHRG_I__20mA }, | ||
43 | { 10, HW_POWER_CHARGE__BATTCHRG_I__10mA } | ||
44 | }; | ||
45 | |||
46 | /* in decreasing order */ | ||
47 | static struct current_step_bit_t g_charger_stop_current_bits[] = | ||
48 | { | ||
49 | { 100, HW_POWER_CHARGE__STOP_ILIMIT__100mA }, | ||
50 | { 50, HW_POWER_CHARGE__STOP_ILIMIT__50mA }, | ||
51 | { 20, HW_POWER_CHARGE__STOP_ILIMIT__20mA }, | ||
52 | { 10, HW_POWER_CHARGE__STOP_ILIMIT__10mA } | ||
53 | }; | ||
54 | |||
55 | /* in decreasing order */ | ||
56 | static struct current_step_bit_t g_4p2_charge_limit_bits[] = | ||
57 | { | ||
58 | { 400, HW_POWER_5VCTRL__CHARGE_4P2_ILIMIT__400mA }, | ||
59 | { 200, HW_POWER_5VCTRL__CHARGE_4P2_ILIMIT__200mA }, | ||
60 | { 100, HW_POWER_5VCTRL__CHARGE_4P2_ILIMIT__100mA }, | ||
61 | { 50, HW_POWER_5VCTRL__CHARGE_4P2_ILIMIT__50mA }, | ||
62 | { 20, HW_POWER_5VCTRL__CHARGE_4P2_ILIMIT__20mA }, | ||
63 | { 10, HW_POWER_5VCTRL__CHARGE_4P2_ILIMIT__10mA } | ||
64 | }; | ||
65 | |||
29 | void INT_VDD5V(void) | 66 | void INT_VDD5V(void) |
30 | { | 67 | { |
31 | if(HW_POWER_CTRL & HW_POWER_CTRL__VBUSVALID_IRQ) | 68 | if(HW_POWER_CTRL & HW_POWER_CTRL__VBUSVALID_IRQ) |
@@ -43,6 +80,12 @@ void INT_VDD5V(void) | |||
43 | 80 | ||
44 | void power_init(void) | 81 | void power_init(void) |
45 | { | 82 | { |
83 | /* setup vbusvalid parameters: set threshold to 4v and power up comparators */ | ||
84 | __REG_CLR(HW_POWER_5VCTRL) = HW_POWER_5VCTRL__VBUSVALID_TRSH_BM; | ||
85 | __REG_SET(HW_POWER_5VCTRL) = HW_POWER_5VCTRL__VBUSVALID_TRSH_4V | | ||
86 | HW_POWER_5VCTRL__PWRUP_VBUS_CMPS; | ||
87 | /* enable vbusvalid detection method for the dcdc (improves efficiency) */ | ||
88 | __REG_SET(HW_POWER_5VCTRL) = HW_POWER_5VCTRL__VBUSVALID_5VDETECT; | ||
46 | /* clear vbusvalid irq and set correct polarity */ | 89 | /* clear vbusvalid irq and set correct polarity */ |
47 | __REG_CLR(HW_POWER_CTRL) = HW_POWER_CTRL__VBUSVALID_IRQ; | 90 | __REG_CLR(HW_POWER_CTRL) = HW_POWER_CTRL__VBUSVALID_IRQ; |
48 | if(HW_POWER_STS & HW_POWER_STS__VBUSVALID) | 91 | if(HW_POWER_STS & HW_POWER_STS__VBUSVALID) |
@@ -51,6 +94,11 @@ void power_init(void) | |||
51 | __REG_SET(HW_POWER_CTRL) = HW_POWER_CTRL__POLARITY_VBUSVALID; | 94 | __REG_SET(HW_POWER_CTRL) = HW_POWER_CTRL__POLARITY_VBUSVALID; |
52 | __REG_SET(HW_POWER_CTRL) = HW_POWER_CTRL__ENIRQ_VBUS_VALID; | 95 | __REG_SET(HW_POWER_CTRL) = HW_POWER_CTRL__ENIRQ_VBUS_VALID; |
53 | imx233_enable_interrupt(INT_SRC_VDD5V, true); | 96 | imx233_enable_interrupt(INT_SRC_VDD5V, true); |
97 | /* setup linear regulator offsets to 25 mV below to prevent contention between | ||
98 | * linear regulators and DCDC */ | ||
99 | __FIELD_SET(HW_POWER_VDDDCTRL, LINREG_OFFSET, 2); | ||
100 | __FIELD_SET(HW_POWER_VDDACTRL, LINREG_OFFSET, 2); | ||
101 | __FIELD_SET(HW_POWER_VDDIOCTRL, LINREG_OFFSET, 2); | ||
54 | } | 102 | } |
55 | 103 | ||
56 | void power_off(void) | 104 | void power_off(void) |
@@ -64,12 +112,42 @@ void power_off(void) | |||
64 | 112 | ||
65 | unsigned int power_input_status(void) | 113 | unsigned int power_input_status(void) |
66 | { | 114 | { |
67 | return POWER_INPUT_NONE; | 115 | return usb_plugged() ? POWER_INPUT_MAIN_CHARGER : POWER_INPUT_NONE; |
68 | } | 116 | } |
69 | 117 | ||
70 | bool charging_state(void) | 118 | bool charging_state(void) |
71 | { | 119 | { |
72 | return false; | 120 | return HW_POWER_STS & HW_POWER_STS__CHRGSTS; |
121 | } | ||
122 | |||
123 | void imx233_power_set_charge_current(unsigned current) | ||
124 | { | ||
125 | __REG_CLR(HW_POWER_CHARGE) = HW_POWER_CHARGE__BATTCHRG_I_BM; | ||
126 | /* find closest current LOWER THAN OR EQUAL TO the expected current */ | ||
127 | for(unsigned i = 0; i < ARRAYLEN(g_charger_current_bits); i++) | ||
128 | if(current >= g_charger_current_bits[i].current) | ||
129 | { | ||
130 | current -= g_charger_current_bits[i].current; | ||
131 | __REG_SET(HW_POWER_CHARGE) = g_charger_current_bits[i].bit; | ||
132 | } | ||
133 | } | ||
134 | |||
135 | void imx233_power_set_stop_current(unsigned current) | ||
136 | { | ||
137 | __REG_CLR(HW_POWER_CHARGE) = HW_POWER_CHARGE__STOP_ILIMIT_BM; | ||
138 | /* find closest current GREATHER THAN OR EQUAL TO the expected current */ | ||
139 | unsigned sum = 0; | ||
140 | for(unsigned i = 0; i < ARRAYLEN(g_charger_stop_current_bits); i++) | ||
141 | sum += g_charger_stop_current_bits[i].current; | ||
142 | for(unsigned i = 0; i < ARRAYLEN(g_charger_stop_current_bits); i++) | ||
143 | { | ||
144 | sum -= g_charger_stop_current_bits[i].current; | ||
145 | if(current > sum) | ||
146 | { | ||
147 | current -= g_charger_stop_current_bits[i].current; | ||
148 | __REG_SET(HW_POWER_CHARGE) = g_charger_stop_current_bits[i].bit; | ||
149 | } | ||
150 | } | ||
73 | } | 151 | } |
74 | 152 | ||
75 | struct imx233_power_info_t imx233_power_get_info(unsigned flags) | 153 | struct imx233_power_info_t imx233_power_get_info(unsigned flags) |
@@ -91,14 +169,22 @@ struct imx233_power_info_t imx233_power_get_info(unsigned flags) | |||
91 | { | 169 | { |
92 | s.vddd = HW_POWER_VDDDCTRL__TRG_MIN + HW_POWER_VDDDCTRL__TRG_STEP * __XTRACT(HW_POWER_VDDDCTRL, TRG); | 170 | s.vddd = HW_POWER_VDDDCTRL__TRG_MIN + HW_POWER_VDDDCTRL__TRG_STEP * __XTRACT(HW_POWER_VDDDCTRL, TRG); |
93 | s.vddd_linreg = HW_POWER_VDDDCTRL & HW_POWER_VDDDCTRL__ENABLE_LINREG; | 171 | s.vddd_linreg = HW_POWER_VDDDCTRL & HW_POWER_VDDDCTRL__ENABLE_LINREG; |
172 | s.vddd_linreg_offset = __XTRACT(HW_POWER_VDDDCTRL, LINREG_OFFSET) == 0 ? 0 : | ||
173 | __XTRACT(HW_POWER_VDDDCTRL, LINREG_OFFSET) == 1 ? 25 : -25; | ||
94 | } | 174 | } |
95 | if(flags & POWER_INFO_VDDA) | 175 | if(flags & POWER_INFO_VDDA) |
96 | { | 176 | { |
97 | s.vdda = HW_POWER_VDDACTRL__TRG_MIN + HW_POWER_VDDACTRL__TRG_STEP * __XTRACT(HW_POWER_VDDACTRL, TRG); | 177 | s.vdda = HW_POWER_VDDACTRL__TRG_MIN + HW_POWER_VDDACTRL__TRG_STEP * __XTRACT(HW_POWER_VDDACTRL, TRG); |
98 | s.vdda_linreg = HW_POWER_VDDACTRL & HW_POWER_VDDACTRL__ENABLE_LINREG; | 178 | s.vdda_linreg = HW_POWER_VDDACTRL & HW_POWER_VDDACTRL__ENABLE_LINREG; |
179 | s.vdda_linreg_offset = __XTRACT(HW_POWER_VDDACTRL, LINREG_OFFSET) == 0 ? 0 : | ||
180 | __XTRACT(HW_POWER_VDDACTRL, LINREG_OFFSET) == 1 ? 25 : -25; | ||
99 | } | 181 | } |
100 | if(flags & POWER_INFO_VDDIO) | 182 | if(flags & POWER_INFO_VDDIO) |
183 | { | ||
101 | s.vddio = HW_POWER_VDDIOCTRL__TRG_MIN + HW_POWER_VDDIOCTRL__TRG_STEP * __XTRACT(HW_POWER_VDDIOCTRL, TRG); | 184 | s.vddio = HW_POWER_VDDIOCTRL__TRG_MIN + HW_POWER_VDDIOCTRL__TRG_STEP * __XTRACT(HW_POWER_VDDIOCTRL, TRG); |
185 | s.vddio_linreg_offset = __XTRACT(HW_POWER_VDDIOCTRL, LINREG_OFFSET) == 0 ? 0 : | ||
186 | __XTRACT(HW_POWER_VDDIOCTRL, LINREG_OFFSET) == 1 ? 25 : -25; | ||
187 | } | ||
102 | if(flags & POWER_INFO_VDDMEM) | 188 | if(flags & POWER_INFO_VDDMEM) |
103 | { | 189 | { |
104 | s.vddmem = HW_POWER_VDDMEMCTRL__TRG_MIN + HW_POWER_VDDMEMCTRL__TRG_STEP * __XTRACT(HW_POWER_VDDMEMCTRL, TRG); | 190 | s.vddmem = HW_POWER_VDDMEMCTRL__TRG_MIN + HW_POWER_VDDMEMCTRL__TRG_STEP * __XTRACT(HW_POWER_VDDMEMCTRL, TRG); |
@@ -109,5 +195,38 @@ struct imx233_power_info_t imx233_power_get_info(unsigned flags) | |||
109 | s.dcdc_sel_pllclk = HW_POWER_MISC & HW_POWER_MISC__SEL_PLLCLK; | 195 | s.dcdc_sel_pllclk = HW_POWER_MISC & HW_POWER_MISC__SEL_PLLCLK; |
110 | s.dcdc_freqsel = dcdc_freqsel[__XTRACT(HW_POWER_MISC, FREQSEL)]; | 196 | s.dcdc_freqsel = dcdc_freqsel[__XTRACT(HW_POWER_MISC, FREQSEL)]; |
111 | } | 197 | } |
198 | if(flags & POWER_INFO_CHARGE) | ||
199 | { | ||
200 | for(unsigned i = 0; i < ARRAYLEN(g_charger_current_bits); i++) | ||
201 | if(HW_POWER_CHARGE & g_charger_current_bits[i].bit) | ||
202 | s.charge_current += g_charger_current_bits[i].current; | ||
203 | for(unsigned i = 0; i < ARRAYLEN(g_charger_stop_current_bits); i++) | ||
204 | if(HW_POWER_CHARGE & g_charger_stop_current_bits[i].bit) | ||
205 | s.stop_current += g_charger_stop_current_bits[i].current; | ||
206 | s.charging = HW_POWER_STS & HW_POWER_STS__CHRGSTS; | ||
207 | s.batt_adj = HW_POWER_BATTMONITOR & HW_POWER_BATTMONITOR__ENBATADJ; | ||
208 | } | ||
209 | if(flags & POWER_INFO_4P2) | ||
210 | { | ||
211 | s._4p2_enable = HW_POWER_DCDC4P2 & HW_POWER_DCDC4P2__ENABLE_4P2; | ||
212 | s._4p2_dcdc = HW_POWER_DCDC4P2 & HW_POWER_DCDC4P2__ENABLE_DCDC; | ||
213 | s._4p2_cmptrip = __XTRACT(HW_POWER_DCDC4P2, CMPTRIP); | ||
214 | s._4p2_dropout = __XTRACT(HW_POWER_DCDC4P2, DROPOUT_CTRL); | ||
215 | } | ||
216 | if(flags & POWER_INFO_5V) | ||
217 | { | ||
218 | s._5v_pwd_charge_4p2 = HW_POWER_5VCTRL & HW_POWER_5VCTRL__PWD_CHARGE_4P2; | ||
219 | s._5v_dcdc_xfer = HW_POWER_5VCTRL & HW_POWER_5VCTRL__DCDC_XFER; | ||
220 | s._5v_enable_dcdc = HW_POWER_5VCTRL & HW_POWER_5VCTRL__ENABLE_DCDC; | ||
221 | for(unsigned i = 0; i < ARRAYLEN(g_4p2_charge_limit_bits); i++) | ||
222 | if(HW_POWER_5VCTRL & g_4p2_charge_limit_bits[i].bit) | ||
223 | s._5v_charge_4p2_limit += g_4p2_charge_limit_bits[i].current; | ||
224 | s._5v_vbusvalid_detect = HW_POWER_5VCTRL & HW_POWER_5VCTRL__VBUSVALID_5VDETECT; | ||
225 | s._5v_vbus_cmps = HW_POWER_5VCTRL & HW_POWER_5VCTRL__PWRUP_VBUS_CMPS; | ||
226 | s._5v_vbusvalid_thr = | ||
227 | __XTRACT(HW_POWER_5VCTRL, VBUSVALID_TRSH) == 0 ? | ||
228 | 2900 | ||
229 | : 3900 + __XTRACT(HW_POWER_5VCTRL, VBUSVALID_TRSH) * 100; | ||
230 | } | ||
112 | return s; | 231 | return s; |
113 | } | 232 | } |
diff --git a/firmware/target/arm/imx233/power-imx233.h b/firmware/target/arm/imx233/power-imx233.h index a546b96117..368ca719da 100644 --- a/firmware/target/arm/imx233/power-imx233.h +++ b/firmware/target/arm/imx233/power-imx233.h | |||
@@ -33,25 +33,52 @@ | |||
33 | #define HW_POWER_CTRL__POLARITY_VBUSVALID (1 << 5) | 33 | #define HW_POWER_CTRL__POLARITY_VBUSVALID (1 << 5) |
34 | 34 | ||
35 | #define HW_POWER_5VCTRL (*(volatile uint32_t *)(HW_POWER_BASE + 0x10)) | 35 | #define HW_POWER_5VCTRL (*(volatile uint32_t *)(HW_POWER_BASE + 0x10)) |
36 | #define HW_POWER_5VCTRL__ENABLE_DCDC (1 << 0) | ||
37 | #define HW_POWER_5VCTRL__PWRUP_VBUS_CMPS (1 << 1) | ||
36 | #define HW_POWER_5VCTRL__VBUSVALID_5VDETECT (1 << 4) | 38 | #define HW_POWER_5VCTRL__VBUSVALID_5VDETECT (1 << 4) |
39 | #define HW_POWER_5VCTRL__DCDC_XFER (1 << 5) | ||
37 | #define HW_POWER_5VCTRL__VBUSVALID_TRSH_BP 8 | 40 | #define HW_POWER_5VCTRL__VBUSVALID_TRSH_BP 8 |
38 | #define HW_POWER_5VCTRL__VBUSVALID_TRSH_BM (0x7 << 8) | 41 | #define HW_POWER_5VCTRL__VBUSVALID_TRSH_BM (0x7 << 8) |
42 | #define HW_POWER_5VCTRL__VBUSVALID_TRSH_2p9 (0 << 8) | ||
43 | #define HW_POWER_5VCTRL__VBUSVALID_TRSH_4V (1 << 8) | ||
44 | #define HW_POWER_5VCTRL__CHARGE_4P2_ILIMIT_BP 12 | ||
45 | #define HW_POWER_5VCTRL__CHARGE_4P2_ILIMIT_BM (0x3f << 12) | ||
46 | #define HW_POWER_5VCTRL__CHARGE_4P2_ILIMIT__10mA (1 << 12) | ||
47 | #define HW_POWER_5VCTRL__CHARGE_4P2_ILIMIT__20mA (1 << 13) | ||
48 | #define HW_POWER_5VCTRL__CHARGE_4P2_ILIMIT__50mA (1 << 14) | ||
49 | #define HW_POWER_5VCTRL__CHARGE_4P2_ILIMIT__100mA (1 << 15) | ||
50 | #define HW_POWER_5VCTRL__CHARGE_4P2_ILIMIT__200mA (1 << 16) | ||
51 | #define HW_POWER_5VCTRL__CHARGE_4P2_ILIMIT__400mA (1 << 17) | ||
52 | #define HW_POWER_5VCTRL__PWD_CHARGE_4P2 (1 << 20) | ||
39 | 53 | ||
40 | #define HW_POWER_MINPWR (*(volatile uint32_t *)(HW_POWER_BASE + 0x20)) | 54 | #define HW_POWER_MINPWR (*(volatile uint32_t *)(HW_POWER_BASE + 0x20)) |
41 | 55 | ||
42 | #define HW_POWER_CHARGE (*(volatile uint32_t *)(HW_POWER_BASE + 0x30)) | 56 | #define HW_POWER_CHARGE (*(volatile uint32_t *)(HW_POWER_BASE + 0x30)) |
43 | #define HW_POWER_CHARGE__BATTCHRG_I_BP 0 | 57 | #define HW_POWER_CHARGE__BATTCHRG_I_BP 0 |
44 | #define HW_POWER_CHARGE__BATTCHRG_I_BM 0x3f | 58 | #define HW_POWER_CHARGE__BATTCHRG_I_BM 0x3f |
59 | #define HW_POWER_CHARGE__BATTCHRG_I__10mA (1 << 0) | ||
60 | #define HW_POWER_CHARGE__BATTCHRG_I__20mA (1 << 1) | ||
61 | #define HW_POWER_CHARGE__BATTCHRG_I__50mA (1 << 2) | ||
62 | #define HW_POWER_CHARGE__BATTCHRG_I__100mA (1 << 3) | ||
63 | #define HW_POWER_CHARGE__BATTCHRG_I__200mA (1 << 4) | ||
64 | #define HW_POWER_CHARGE__BATTCHRG_I__400mA (1 << 5) | ||
45 | #define HW_POWER_CHARGE__STOP_ILIMIT_BP 8 | 65 | #define HW_POWER_CHARGE__STOP_ILIMIT_BP 8 |
46 | #define HW_POWER_CHARGE__STOP_ILIMIT_BM 0xf00 | 66 | #define HW_POWER_CHARGE__STOP_ILIMIT_BM 0xf00 |
67 | #define HW_POWER_CHARGE__STOP_ILIMIT__10mA (1 << 8) | ||
68 | #define HW_POWER_CHARGE__STOP_ILIMIT__20mA (1 << 9) | ||
69 | #define HW_POWER_CHARGE__STOP_ILIMIT__50mA (1 << 10) | ||
70 | #define HW_POWER_CHARGE__STOP_ILIMIT__100mA (1 << 11) | ||
47 | #define HW_POWER_CHARGE__PWD_BATTCHRG (1 << 16) | 71 | #define HW_POWER_CHARGE__PWD_BATTCHRG (1 << 16) |
48 | #define HW_POWER_CHARGE__CHRG_STS_OFF (1 << 19) | 72 | #define HW_POWER_CHARGE__CHRG_STS_OFF (1 << 19) |
73 | #define HW_POWER_CHARGE__ENABLE_LOAD (1 << 22) | ||
49 | 74 | ||
50 | #define HW_POWER_VDDDCTRL (*(volatile uint32_t *)(HW_POWER_BASE + 0x40)) | 75 | #define HW_POWER_VDDDCTRL (*(volatile uint32_t *)(HW_POWER_BASE + 0x40)) |
51 | #define HW_POWER_VDDDCTRL__TRG_BP 0 | 76 | #define HW_POWER_VDDDCTRL__TRG_BP 0 |
52 | #define HW_POWER_VDDDCTRL__TRG_BM 0x1f | 77 | #define HW_POWER_VDDDCTRL__TRG_BM 0x1f |
53 | #define HW_POWER_VDDDCTRL__TRG_STEP 25 /* mV */ | 78 | #define HW_POWER_VDDDCTRL__TRG_STEP 25 /* mV */ |
54 | #define HW_POWER_VDDDCTRL__TRG_MIN 800 /* mV */ | 79 | #define HW_POWER_VDDDCTRL__TRG_MIN 800 /* mV */ |
80 | #define HW_POWER_VDDDCTRL__LINREG_OFFSET_BP 16 | ||
81 | #define HW_POWER_VDDDCTRL__LINREG_OFFSET_BM (0x3 << 16) | ||
55 | #define HW_POWER_VDDDCTRL__ENABLE_LINREG (1 << 21) | 82 | #define HW_POWER_VDDDCTRL__ENABLE_LINREG (1 << 21) |
56 | 83 | ||
57 | #define HW_POWER_VDDACTRL (*(volatile uint32_t *)(HW_POWER_BASE + 0x50)) | 84 | #define HW_POWER_VDDACTRL (*(volatile uint32_t *)(HW_POWER_BASE + 0x50)) |
@@ -59,6 +86,8 @@ | |||
59 | #define HW_POWER_VDDACTRL__TRG_BM 0x1f | 86 | #define HW_POWER_VDDACTRL__TRG_BM 0x1f |
60 | #define HW_POWER_VDDACTRL__TRG_STEP 25 /* mV */ | 87 | #define HW_POWER_VDDACTRL__TRG_STEP 25 /* mV */ |
61 | #define HW_POWER_VDDACTRL__TRG_MIN 1500 /* mV */ | 88 | #define HW_POWER_VDDACTRL__TRG_MIN 1500 /* mV */ |
89 | #define HW_POWER_VDDACTRL__LINREG_OFFSET_BP 12 | ||
90 | #define HW_POWER_VDDACTRL__LINREG_OFFSET_BM (0x3 << 12) | ||
62 | #define HW_POWER_VDDACTRL__ENABLE_LINREG (1 << 17) | 91 | #define HW_POWER_VDDACTRL__ENABLE_LINREG (1 << 17) |
63 | 92 | ||
64 | #define HW_POWER_VDDIOCTRL (*(volatile uint32_t *)(HW_POWER_BASE + 0x60)) | 93 | #define HW_POWER_VDDIOCTRL (*(volatile uint32_t *)(HW_POWER_BASE + 0x60)) |
@@ -66,6 +95,8 @@ | |||
66 | #define HW_POWER_VDDIOCTRL__TRG_BM 0x1f | 95 | #define HW_POWER_VDDIOCTRL__TRG_BM 0x1f |
67 | #define HW_POWER_VDDIOCTRL__TRG_STEP 25 /* mV */ | 96 | #define HW_POWER_VDDIOCTRL__TRG_STEP 25 /* mV */ |
68 | #define HW_POWER_VDDIOCTRL__TRG_MIN 2800 /* mV */ | 97 | #define HW_POWER_VDDIOCTRL__TRG_MIN 2800 /* mV */ |
98 | #define HW_POWER_VDDIOCTRL__LINREG_OFFSET_BP 12 | ||
99 | #define HW_POWER_VDDIOCTRL__LINREG_OFFSET_BM (0x3 << 12) | ||
69 | 100 | ||
70 | #define HW_POWER_VDDMEMCTRL (*(volatile uint32_t *)(HW_POWER_BASE + 0x70)) | 101 | #define HW_POWER_VDDMEMCTRL (*(volatile uint32_t *)(HW_POWER_BASE + 0x70)) |
71 | #define HW_POWER_VDDMEMCTRL__TRG_BP 0 | 102 | #define HW_POWER_VDDMEMCTRL__TRG_BP 0 |
@@ -74,6 +105,17 @@ | |||
74 | #define HW_POWER_VDDMEMCTRL__TRG_MIN 1700 /* mV */ | 105 | #define HW_POWER_VDDMEMCTRL__TRG_MIN 1700 /* mV */ |
75 | #define HW_POWER_VDDMEMCTRL__ENABLE_LINREG (1 << 8) | 106 | #define HW_POWER_VDDMEMCTRL__ENABLE_LINREG (1 << 8) |
76 | 107 | ||
108 | #define HW_POWER_DCDC4P2 (*(volatile uint32_t *)(HW_POWER_BASE + 0x80)) | ||
109 | #define HW_POWER_DCDC4P2__CMPTRIP_BP 0 | ||
110 | #define HW_POWER_DCDC4P2__CMPTRIP_BM 0x1f | ||
111 | #define HW_POWER_DCDC4P2__CMPTRIP__0p85 0 | ||
112 | #define HW_POWER_DCDC4P2__ENABLE_DCDC (1 << 22) | ||
113 | #define HW_POWER_DCDC4P2__ENABLE_4P2 (1 << 23) | ||
114 | #define HW_POWER_DCDC4P2__DROPOUT_CTRL_BP 28 | ||
115 | #define HW_POWER_DCDC4P2__DROPOUT_CTRL_BM (0xf << 28) | ||
116 | #define HW_POWER_DCDC4P2__DROPOUT_CTRL__200mV (3 << 30) | ||
117 | #define HW_POWER_DCDC4P2__DROPOUT_CTRL__HIGHER (2 << 28) | ||
118 | |||
77 | #define HW_POWER_MISC (*(volatile uint32_t *)(HW_POWER_BASE + 0x90)) | 119 | #define HW_POWER_MISC (*(volatile uint32_t *)(HW_POWER_BASE + 0x90)) |
78 | #define HW_POWER_MISC__SEL_PLLCLK 1 | 120 | #define HW_POWER_MISC__SEL_PLLCLK 1 |
79 | #define HW_POWER_MISC__FREQSEL_BP 4 | 121 | #define HW_POWER_MISC__FREQSEL_BP 4 |
@@ -89,10 +131,12 @@ | |||
89 | 131 | ||
90 | #define HW_POWER_STS (*(volatile uint32_t *)(HW_POWER_BASE + 0xc0)) | 132 | #define HW_POWER_STS (*(volatile uint32_t *)(HW_POWER_BASE + 0xc0)) |
91 | #define HW_POWER_STS__VBUSVALID (1 << 1) | 133 | #define HW_POWER_STS__VBUSVALID (1 << 1) |
134 | #define HW_POWER_STS__CHRGSTS (1 << 11) | ||
92 | #define HW_POWER_STS__PSWITCH_BP 20 | 135 | #define HW_POWER_STS__PSWITCH_BP 20 |
93 | #define HW_POWER_STS__PSWITCH_BM (3 << 20) | 136 | #define HW_POWER_STS__PSWITCH_BM (3 << 20) |
94 | 137 | ||
95 | #define HW_POWER_BATTMONITOR (*(volatile uint32_t *)(HW_POWER_BASE + 0xe0)) | 138 | #define HW_POWER_BATTMONITOR (*(volatile uint32_t *)(HW_POWER_BASE + 0xe0)) |
139 | #define HW_POWER_BATTMONITOR__ENBATADJ (1 << 10) | ||
96 | #define HW_POWER_BATTMONITOR__BATT_VAL_BP 16 | 140 | #define HW_POWER_BATTMONITOR__BATT_VAL_BP 16 |
97 | #define HW_POWER_BATTMONITOR__BATT_VAL_BM (0x3ff << 16) | 141 | #define HW_POWER_BATTMONITOR__BATT_VAL_BM (0x3ff << 16) |
98 | 142 | ||
@@ -100,17 +144,39 @@ | |||
100 | #define HW_POWER_RESET__UNLOCK 0x3E770000 | 144 | #define HW_POWER_RESET__UNLOCK 0x3E770000 |
101 | #define HW_POWER_RESET__PWD 0x1 | 145 | #define HW_POWER_RESET__PWD 0x1 |
102 | 146 | ||
147 | void imx233_power_set_charge_current(unsigned current); /* in mA */ | ||
148 | void imx233_power_set_stop_current(unsigned current); /* in mA */ | ||
149 | void imx233_power_enable_batadj(bool enable); | ||
150 | |||
103 | struct imx233_power_info_t | 151 | struct imx233_power_info_t |
104 | { | 152 | { |
105 | int vddd; /* in mV */ | 153 | int vddd; /* in mV */ |
106 | bool vddd_linreg; /* VDDD source: linreg from VDDA or DC-DC */ | 154 | bool vddd_linreg; /* VDDD source: linreg from VDDA or DC-DC */ |
155 | int vddd_linreg_offset; | ||
107 | int vdda; /* in mV */ | 156 | int vdda; /* in mV */ |
108 | bool vdda_linreg; /* VDDA source: linreg from VDDIO or DC-DC */ | 157 | bool vdda_linreg; /* VDDA source: linreg from VDDIO or DC-DC */ |
158 | int vdda_linreg_offset; | ||
109 | int vddio; /* in mV */ | 159 | int vddio; /* in mV */ |
160 | int vddio_linreg_offset; | ||
110 | int vddmem; /* in mV */ | 161 | int vddmem; /* in mV */ |
111 | bool vddmem_linreg; /* VDDMEM source: linreg from VDDIO or off */ | 162 | bool vddmem_linreg; /* VDDMEM source: linreg from VDDIO or off */ |
112 | bool dcdc_sel_pllclk; /* clock source of DC-DC: pll or 24MHz xtal */ | 163 | bool dcdc_sel_pllclk; /* clock source of DC-DC: pll or 24MHz xtal */ |
113 | int dcdc_freqsel; | 164 | int dcdc_freqsel; |
165 | int charge_current; | ||
166 | int stop_current; | ||
167 | bool charging; | ||
168 | bool batt_adj; | ||
169 | bool _4p2_enable; | ||
170 | bool _4p2_dcdc; | ||
171 | int _4p2_cmptrip; | ||
172 | int _4p2_dropout; | ||
173 | bool _5v_pwd_charge_4p2; | ||
174 | int _5v_charge_4p2_limit; | ||
175 | bool _5v_dcdc_xfer; | ||
176 | bool _5v_enable_dcdc; | ||
177 | int _5v_vbusvalid_thr; | ||
178 | bool _5v_vbusvalid_detect; | ||
179 | bool _5v_vbus_cmps; | ||
114 | }; | 180 | }; |
115 | 181 | ||
116 | #define POWER_INFO_VDDD (1 << 0) | 182 | #define POWER_INFO_VDDD (1 << 0) |
@@ -118,7 +184,10 @@ struct imx233_power_info_t | |||
118 | #define POWER_INFO_VDDIO (1 << 2) | 184 | #define POWER_INFO_VDDIO (1 << 2) |
119 | #define POWER_INFO_VDDMEM (1 << 3) | 185 | #define POWER_INFO_VDDMEM (1 << 3) |
120 | #define POWER_INFO_DCDC (1 << 4) | 186 | #define POWER_INFO_DCDC (1 << 4) |
121 | #define POWER_INFO_ALL 0x1f | 187 | #define POWER_INFO_CHARGE (1 << 5) |
188 | #define POWER_INFO_4P2 (1 << 6) | ||
189 | #define POWER_INFO_5V (1 << 7) | ||
190 | #define POWER_INFO_ALL 0xff | ||
122 | 191 | ||
123 | struct imx233_power_info_t imx233_power_get_info(unsigned flags); | 192 | struct imx233_power_info_t imx233_power_get_info(unsigned flags); |
124 | 193 | ||
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 | } | ||
diff --git a/firmware/target/arm/imx233/sansa-fuzeplus/powermgmt-fuzeplus.c b/firmware/target/arm/imx233/sansa-fuzeplus/powermgmt-fuzeplus.c new file mode 100644 index 0000000000..3e068f007d --- /dev/null +++ b/firmware/target/arm/imx233/sansa-fuzeplus/powermgmt-fuzeplus.c | |||
@@ -0,0 +1,46 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 by Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include "config.h" | ||
22 | #include "powermgmt-target.h" | ||
23 | |||
24 | const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] = | ||
25 | { | ||
26 | 3659 | ||
27 | }; | ||
28 | |||
29 | const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] = | ||
30 | { | ||
31 | 3630 | ||
32 | }; | ||
33 | |||
34 | /* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */ | ||
35 | const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] = | ||
36 | { | ||
37 | /* Toshiba Gigabeat S Li Ion 700mAH figured from discharge curve */ | ||
38 | { 3659, 3719, 3745, 3761, 3785, 3813, 3856, 3926, 3984, 4040, 4121 }, | ||
39 | }; | ||
40 | |||
41 | /* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */ | ||
42 | const unsigned short percent_to_volt_charge[11] = | ||
43 | { | ||
44 | /* Toshiba Gigabeat S Li Ion 700mAH figured from charge curve */ | ||
45 | 4028, 4063, 4087, 4111, 4135, 4156, 4173, 4185, 4194, 4202, 4208 | ||
46 | }; | ||
diff --git a/firmware/target/arm/imx233/powermgmt-target.h b/firmware/target/arm/imx233/sansa-fuzeplus/powermgmt-target.h index d539a66d16..34d1d00e1d 100644 --- a/firmware/target/arm/imx233/powermgmt-target.h +++ b/firmware/target/arm/imx233/sansa-fuzeplus/powermgmt-target.h | |||
@@ -22,9 +22,27 @@ | |||
22 | #define POWERMGMT_TARGET_H | 22 | #define POWERMGMT_TARGET_H |
23 | 23 | ||
24 | #include "config.h" | 24 | #include "config.h" |
25 | #include "powermgmt-imx233.h" | ||
25 | 26 | ||
26 | void powermgmt_init_target(void); | 27 | /* Fuze+ OF settings: |
27 | void charging_algorithm_step(void); | 28 | * - current ramp slope: 50 mA/s |
28 | void charging_algorithm_close(void); | 29 | * - conditioning threshold voltage: 3 V |
30 | * - conditioning max voltage: 3.1 V | ||
31 | * - conditioning current: 60 mA | ||
32 | * - conditioning timeout: 1 h | ||
33 | * - charging voltage: 4.2 V | ||
34 | * - charging current: 200 mA | ||
35 | * - charging threshold current: 30 mA | ||
36 | * - charging timeout: 4 h | ||
37 | * - top off period: 30 min | ||
38 | * - high die temperature: 71 °C | ||
39 | * - low die temperature: 56 °C | ||
40 | * - safe temperature current: 30 mA | ||
41 | */ | ||
42 | |||
43 | #define IMX233_CHARGE_CURRENT 200 | ||
44 | #define IMX233_STOP_CURRENT 30 | ||
45 | #define IMX233_TOPOFF_TIMEOUT (30 * 60 * HZ) | ||
46 | #define IMX233_CHARGING_TIMEOUT (4 * 3600 * HZ) | ||
29 | 47 | ||
30 | #endif /* POWERMGMT_TARGET_H */ | 48 | #endif /* POWERMGMT_TARGET_H */ |