summaryrefslogtreecommitdiff
path: root/firmware/target/arm/imx233/power-imx233.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/imx233/power-imx233.c')
-rw-r--r--firmware/target/arm/imx233/power-imx233.c123
1 files changed, 121 insertions, 2 deletions
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
29struct current_step_bit_t
30{
31 unsigned current;
32 uint32_t bit;
33};
34
35/* in decreasing order */
36static 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 */
47static 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 */
56static 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
29void INT_VDD5V(void) 66void 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
44void power_init(void) 81void 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
56void power_off(void) 104void power_off(void)
@@ -64,12 +112,42 @@ void power_off(void)
64 112
65unsigned int power_input_status(void) 113unsigned 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
70bool charging_state(void) 118bool charging_state(void)
71{ 119{
72 return false; 120 return HW_POWER_STS & HW_POWER_STS__CHRGSTS;
121}
122
123void 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
135void 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
75struct imx233_power_info_t imx233_power_get_info(unsigned flags) 153struct 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}