1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2011 by Amaury Pouly
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.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
27 #include "system-target.h"
28 #include "power-imx233.h"
29 #include "pinctrl-imx233.h"
30 #include "fmradio_i2c.h"
32 struct current_step_bit_t
38 /* in decreasing order */
39 static struct current_step_bit_t g_charger_current_bits
[] =
41 { 400, HW_POWER_CHARGE__BATTCHRG_I__400mA
},
42 { 200, HW_POWER_CHARGE__BATTCHRG_I__200mA
},
43 { 100, HW_POWER_CHARGE__BATTCHRG_I__100mA
},
44 { 50, HW_POWER_CHARGE__BATTCHRG_I__50mA
},
45 { 20, HW_POWER_CHARGE__BATTCHRG_I__20mA
},
46 { 10, HW_POWER_CHARGE__BATTCHRG_I__10mA
}
49 /* in decreasing order */
50 static struct current_step_bit_t g_charger_stop_current_bits
[] =
52 { 100, HW_POWER_CHARGE__STOP_ILIMIT__100mA
},
53 { 50, HW_POWER_CHARGE__STOP_ILIMIT__50mA
},
54 { 20, HW_POWER_CHARGE__STOP_ILIMIT__20mA
},
55 { 10, HW_POWER_CHARGE__STOP_ILIMIT__10mA
}
58 /* in decreasing order */
59 static struct current_step_bit_t g_4p2_charge_limit_bits
[] =
61 { 400, HW_POWER_5VCTRL__CHARGE_4P2_ILIMIT__400mA
},
62 { 200, HW_POWER_5VCTRL__CHARGE_4P2_ILIMIT__200mA
},
63 { 100, HW_POWER_5VCTRL__CHARGE_4P2_ILIMIT__100mA
},
64 { 50, HW_POWER_5VCTRL__CHARGE_4P2_ILIMIT__50mA
},
65 { 20, HW_POWER_5VCTRL__CHARGE_4P2_ILIMIT__20mA
},
66 { 10, HW_POWER_5VCTRL__CHARGE_4P2_ILIMIT__10mA
}
71 if(HW_POWER_CTRL
& HW_POWER_CTRL__VBUSVALID_IRQ
)
73 if(HW_POWER_STS
& HW_POWER_STS__VBUSVALID
)
77 /* reverse polarity */
78 __REG_TOG(HW_POWER_CTRL
) = HW_POWER_CTRL__POLARITY_VBUSVALID
;
80 __REG_CLR(HW_POWER_CTRL
) = HW_POWER_CTRL__VBUSVALID_IRQ
;
86 /* setup vbusvalid parameters: set threshold to 4v and power up comparators */
87 __REG_CLR(HW_POWER_5VCTRL
) = HW_POWER_5VCTRL__VBUSVALID_TRSH_BM
;
88 __REG_SET(HW_POWER_5VCTRL
) = HW_POWER_5VCTRL__VBUSVALID_TRSH_4V
|
89 HW_POWER_5VCTRL__PWRUP_VBUS_CMPS
;
90 /* enable vbusvalid detection method for the dcdc (improves efficiency) */
91 __REG_SET(HW_POWER_5VCTRL
) = HW_POWER_5VCTRL__VBUSVALID_5VDETECT
;
92 /* clear vbusvalid irq and set correct polarity */
93 __REG_CLR(HW_POWER_CTRL
) = HW_POWER_CTRL__VBUSVALID_IRQ
;
94 if(HW_POWER_STS
& HW_POWER_STS__VBUSVALID
)
95 __REG_CLR(HW_POWER_CTRL
) = HW_POWER_CTRL__POLARITY_VBUSVALID
;
97 __REG_SET(HW_POWER_CTRL
) = HW_POWER_CTRL__POLARITY_VBUSVALID
;
98 __REG_SET(HW_POWER_CTRL
) = HW_POWER_CTRL__ENIRQ_VBUS_VALID
;
99 imx233_enable_interrupt(INT_SRC_VDD5V
, true);
100 /* setup linear regulator offsets to 25 mV below to prevent contention between
101 * linear regulators and DCDC */
102 __FIELD_SET(HW_POWER_VDDDCTRL
, LINREG_OFFSET
, 2);
103 __FIELD_SET(HW_POWER_VDDACTRL
, LINREG_OFFSET
, 2);
104 __FIELD_SET(HW_POWER_VDDIOCTRL
, LINREG_OFFSET
, 2);
105 /* enable a few bits controlling the DC-DC as recommended by Freescale */
106 __REG_SET(HW_POWER_LOOPCTRL
) = HW_POWER_LOOPCTRL__TOGGLE_DIF
|
107 HW_POWER_LOOPCTRL__EN_CM_HYST
;
108 __FIELD_SET(HW_POWER_LOOPCTRL
, EN_RCSCALE
, HW_POWER_LOOPCTRL__EN_RCSCALE__2X
);
113 /* wait a bit, useful for the user to stop touching anything */
115 #ifdef SANSA_FUZEPLUS
116 /* This pin seems to be important to shutdown the hardware properly */
117 imx233_set_pin_function(0, 9, PINCTRL_FUNCTION_GPIO
);
118 imx233_enable_gpio_output(0, 9, true);
119 imx233_set_gpio_output(0, 9, true);
122 HW_POWER_RESET
= HW_POWER_RESET__UNLOCK
| HW_POWER_RESET__PWD
;
126 unsigned int power_input_status(void)
128 return (usb_detect() == USB_INSERTED
)
129 ? POWER_INPUT_MAIN_CHARGER
: POWER_INPUT_NONE
;
132 bool charging_state(void)
134 return HW_POWER_STS
& HW_POWER_STS__CHRGSTS
;
137 void imx233_power_set_charge_current(unsigned current
)
139 __REG_CLR(HW_POWER_CHARGE
) = HW_POWER_CHARGE__BATTCHRG_I_BM
;
140 /* find closest current LOWER THAN OR EQUAL TO the expected current */
141 for(unsigned i
= 0; i
< ARRAYLEN(g_charger_current_bits
); i
++)
142 if(current
>= g_charger_current_bits
[i
].current
)
144 current
-= g_charger_current_bits
[i
].current
;
145 __REG_SET(HW_POWER_CHARGE
) = g_charger_current_bits
[i
].bit
;
149 void imx233_power_set_stop_current(unsigned current
)
151 __REG_CLR(HW_POWER_CHARGE
) = HW_POWER_CHARGE__STOP_ILIMIT_BM
;
152 /* find closest current GREATHER THAN OR EQUAL TO the expected current */
154 for(unsigned i
= 0; i
< ARRAYLEN(g_charger_stop_current_bits
); i
++)
155 sum
+= g_charger_stop_current_bits
[i
].current
;
156 for(unsigned i
= 0; i
< ARRAYLEN(g_charger_stop_current_bits
); i
++)
158 sum
-= g_charger_stop_current_bits
[i
].current
;
161 current
-= g_charger_stop_current_bits
[i
].current
;
162 __REG_SET(HW_POWER_CHARGE
) = g_charger_stop_current_bits
[i
].bit
;
167 struct imx233_power_info_t
imx233_power_get_info(unsigned flags
)
169 static int dcdc_freqsel
[8] = {
170 [HW_POWER_MISC__FREQSEL__RES
] = 0,
171 [HW_POWER_MISC__FREQSEL__20MHz
] = 20000,
172 [HW_POWER_MISC__FREQSEL__24MHz
] = 24000,
173 [HW_POWER_MISC__FREQSEL__19p2MHz
] = 19200,
174 [HW_POWER_MISC__FREQSEL__14p4MHz
] = 14200,
175 [HW_POWER_MISC__FREQSEL__18MHz
] = 18000,
176 [HW_POWER_MISC__FREQSEL__21p6MHz
] = 21600,
177 [HW_POWER_MISC__FREQSEL__17p28MHz
] = 17280,
180 struct imx233_power_info_t s
;
181 memset(&s
, 0, sizeof(s
));
182 if(flags
& POWER_INFO_VDDD
)
184 s
.vddd
= HW_POWER_VDDDCTRL__TRG_MIN
+ HW_POWER_VDDDCTRL__TRG_STEP
* __XTRACT(HW_POWER_VDDDCTRL
, TRG
);
185 s
.vddd_linreg
= HW_POWER_VDDDCTRL
& HW_POWER_VDDDCTRL__ENABLE_LINREG
;
186 s
.vddd_linreg_offset
= __XTRACT(HW_POWER_VDDDCTRL
, LINREG_OFFSET
) == 0 ? 0 :
187 __XTRACT(HW_POWER_VDDDCTRL
, LINREG_OFFSET
) == 1 ? 25 : -25;
189 if(flags
& POWER_INFO_VDDA
)
191 s
.vdda
= HW_POWER_VDDACTRL__TRG_MIN
+ HW_POWER_VDDACTRL__TRG_STEP
* __XTRACT(HW_POWER_VDDACTRL
, TRG
);
192 s
.vdda_linreg
= HW_POWER_VDDACTRL
& HW_POWER_VDDACTRL__ENABLE_LINREG
;
193 s
.vdda_linreg_offset
= __XTRACT(HW_POWER_VDDACTRL
, LINREG_OFFSET
) == 0 ? 0 :
194 __XTRACT(HW_POWER_VDDACTRL
, LINREG_OFFSET
) == 1 ? 25 : -25;
196 if(flags
& POWER_INFO_VDDIO
)
198 s
.vddio
= HW_POWER_VDDIOCTRL__TRG_MIN
+ HW_POWER_VDDIOCTRL__TRG_STEP
* __XTRACT(HW_POWER_VDDIOCTRL
, TRG
);
199 s
.vddio_linreg_offset
= __XTRACT(HW_POWER_VDDIOCTRL
, LINREG_OFFSET
) == 0 ? 0 :
200 __XTRACT(HW_POWER_VDDIOCTRL
, LINREG_OFFSET
) == 1 ? 25 : -25;
202 if(flags
& POWER_INFO_VDDMEM
)
204 s
.vddmem
= HW_POWER_VDDMEMCTRL__TRG_MIN
+ HW_POWER_VDDMEMCTRL__TRG_STEP
* __XTRACT(HW_POWER_VDDMEMCTRL
, TRG
);
205 s
.vddmem_linreg
= HW_POWER_VDDMEMCTRL
& HW_POWER_VDDMEMCTRL__ENABLE_LINREG
;
207 if(flags
& POWER_INFO_DCDC
)
209 s
.dcdc_sel_pllclk
= HW_POWER_MISC
& HW_POWER_MISC__SEL_PLLCLK
;
210 s
.dcdc_freqsel
= dcdc_freqsel
[__XTRACT(HW_POWER_MISC
, FREQSEL
)];
212 if(flags
& POWER_INFO_CHARGE
)
214 for(unsigned i
= 0; i
< ARRAYLEN(g_charger_current_bits
); i
++)
215 if(HW_POWER_CHARGE
& g_charger_current_bits
[i
].bit
)
216 s
.charge_current
+= g_charger_current_bits
[i
].current
;
217 for(unsigned i
= 0; i
< ARRAYLEN(g_charger_stop_current_bits
); i
++)
218 if(HW_POWER_CHARGE
& g_charger_stop_current_bits
[i
].bit
)
219 s
.stop_current
+= g_charger_stop_current_bits
[i
].current
;
220 s
.charging
= HW_POWER_STS
& HW_POWER_STS__CHRGSTS
;
221 s
.batt_adj
= HW_POWER_BATTMONITOR
& HW_POWER_BATTMONITOR__ENBATADJ
;
223 if(flags
& POWER_INFO_4P2
)
225 s
._4p2_enable
= HW_POWER_DCDC4P2
& HW_POWER_DCDC4P2__ENABLE_4P2
;
226 s
._4p2_dcdc
= HW_POWER_DCDC4P2
& HW_POWER_DCDC4P2__ENABLE_DCDC
;
227 s
._4p2_cmptrip
= __XTRACT(HW_POWER_DCDC4P2
, CMPTRIP
);
228 s
._4p2_dropout
= __XTRACT(HW_POWER_DCDC4P2
, DROPOUT_CTRL
);
230 if(flags
& POWER_INFO_5V
)
232 s
._5v_pwd_charge_4p2
= HW_POWER_5VCTRL
& HW_POWER_5VCTRL__PWD_CHARGE_4P2
;
233 s
._5v_dcdc_xfer
= HW_POWER_5VCTRL
& HW_POWER_5VCTRL__DCDC_XFER
;
234 s
._5v_enable_dcdc
= HW_POWER_5VCTRL
& HW_POWER_5VCTRL__ENABLE_DCDC
;
235 for(unsigned i
= 0; i
< ARRAYLEN(g_4p2_charge_limit_bits
); i
++)
236 if(HW_POWER_5VCTRL
& g_4p2_charge_limit_bits
[i
].bit
)
237 s
._5v_charge_4p2_limit
+= g_4p2_charge_limit_bits
[i
].current
;
238 s
._5v_vbusvalid_detect
= HW_POWER_5VCTRL
& HW_POWER_5VCTRL__VBUSVALID_5VDETECT
;
239 s
._5v_vbus_cmps
= HW_POWER_5VCTRL
& HW_POWER_5VCTRL__PWRUP_VBUS_CMPS
;
240 s
._5v_vbusvalid_thr
=
241 __XTRACT(HW_POWER_5VCTRL
, VBUSVALID_TRSH
) == 0 ?
243 : 3900 + __XTRACT(HW_POWER_5VCTRL
, VBUSVALID_TRSH
) * 100;