hm60x/hm801: Buttons rework.
[maemo-rb.git] / firmware / target / arm / imx233 / power-imx233.c
blob2ae7ff653c4edbb3582ccab54fbcccbd43a17bca
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
22 #include "config.h"
23 #include "system.h"
24 #include "power.h"
25 #include "string.h"
26 #include "usb.h"
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
34 unsigned current;
35 uint32_t bit;
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 }
69 void INT_VDD5V(void)
71 if(HW_POWER_CTRL & HW_POWER_CTRL__VBUSVALID_IRQ)
73 if(HW_POWER_STS & HW_POWER_STS__VBUSVALID)
74 usb_insert_int();
75 else
76 usb_remove_int();
77 /* reverse polarity */
78 __REG_TOG(HW_POWER_CTRL) = HW_POWER_CTRL__POLARITY_VBUSVALID;
79 /* enable int */
80 __REG_CLR(HW_POWER_CTRL) = HW_POWER_CTRL__VBUSVALID_IRQ;
84 void power_init(void)
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;
96 else
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);
111 void power_off(void)
113 /* wait a bit, useful for the user to stop touching anything */
114 sleep(HZ / 2);
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);
120 #endif
121 /* power down */
122 HW_POWER_RESET = HW_POWER_RESET__UNLOCK | HW_POWER_RESET__PWD;
123 while(1);
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 */
153 unsigned sum = 0;
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;
159 if(current > sum)
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 ?
242 2900
243 : 3900 + __XTRACT(HW_POWER_5VCTRL, VBUSVALID_TRSH) * 100;
245 return s;