diff options
Diffstat (limited to 'firmware/target/arm')
-rw-r--r-- | firmware/target/arm/powermgmt-ascodec.c | 231 | ||||
-rw-r--r-- | firmware/target/arm/sandisk/powermgmt-target.h | 59 | ||||
-rw-r--r-- | firmware/target/arm/sandisk/sansa-c200/powermgmt-c200.c | 13 | ||||
-rw-r--r-- | firmware/target/arm/sandisk/sansa-e200/powermgmt-e200.c | 11 |
4 files changed, 291 insertions, 23 deletions
diff --git a/firmware/target/arm/powermgmt-ascodec.c b/firmware/target/arm/powermgmt-ascodec.c new file mode 100644 index 0000000000..ab9fd7b490 --- /dev/null +++ b/firmware/target/arm/powermgmt-ascodec.c | |||
@@ -0,0 +1,231 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2009 by Michael Sevakis | ||
11 | * Copyright (C) 2008 by Bertrik Sikken | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation; either version 2 | ||
16 | * of the License, or (at your option) any later version. | ||
17 | * | ||
18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
19 | * KIND, either express or implied. | ||
20 | * | ||
21 | ****************************************************************************/ | ||
22 | #include "config.h" | ||
23 | #include "system.h" | ||
24 | #include "thread.h" | ||
25 | #include "as3514.h" | ||
26 | #include "ascodec.h" | ||
27 | #include "adc.h" | ||
28 | #include "powermgmt.h" | ||
29 | #include "power.h" | ||
30 | |||
31 | /*=========================================================================== | ||
32 | * These parameters may be defined per target: | ||
33 | * | ||
34 | * BATT_FULL_VOLTAGE - Upon connect a charge cycle begins if the reading is | ||
35 | * lower than this value (millivolts). | ||
36 | * | ||
37 | * BATT_VAUTO_RECHARGE - While left plugged after cycle completion, the | ||
38 | * charger restarts automatically if the reading drops | ||
39 | * below this value (millivolts). Must be less than | ||
40 | * BATT_FULL_VOLTAGE. | ||
41 | * | ||
42 | * ADC_BATTERY - ADC channel from which to read the battery voltage | ||
43 | * | ||
44 | * BATT_CHG_V - Charger voltage regulation setting (as3514 regval) | ||
45 | * | ||
46 | * BATT_CHG_I - Charger current regulation setting (as3514 regval) | ||
47 | * | ||
48 | * CHARGER_TOTAL_TIMER - Maximum allowed charging time (1/2-second steps) | ||
49 | *=========================================================================== | ||
50 | */ | ||
51 | |||
52 | /* This code assumes USB power input is not distinguishable from main | ||
53 | * power and charger connect cannot wait for USB configuration before | ||
54 | * considering USB charging available. Where they are distinguishable, | ||
55 | * things get more complicated. */ | ||
56 | static bool charger_close = false; /* Shutting down? */ | ||
57 | static int charger_total_timer = 0; /* Timeout in algorithm steps */ | ||
58 | |||
59 | /* Current battery threshold for (re)charge: | ||
60 | * First plugged = BATT_FULL_VOLTAGE | ||
61 | * After charge cycle or non-start = BATT_VAUTO_RECHARGE | ||
62 | */ | ||
63 | static unsigned int batt_threshold = 0; | ||
64 | |||
65 | /* ADC should read 0x3ff=5.12V */ | ||
66 | /* full-scale ADC readout (2^10) in millivolt */ | ||
67 | |||
68 | /* Returns battery voltage from ADC [millivolts] */ | ||
69 | unsigned int battery_adc_voltage(void) | ||
70 | { | ||
71 | return (adc_read(ADC_BATTERY) * 5125 + 512) >> 10; | ||
72 | } | ||
73 | |||
74 | /* Returns true if the unit is charging the batteries. */ | ||
75 | bool charging_state(void) | ||
76 | { | ||
77 | return charge_state == CHARGING; | ||
78 | } | ||
79 | |||
80 | /* Reset the battery filter to a new voltage */ | ||
81 | static void battery_voltage_sync(void) | ||
82 | { | ||
83 | int i; | ||
84 | unsigned int mv; | ||
85 | |||
86 | for (i = 0, mv = 0; i < 5; i++) | ||
87 | mv += battery_adc_voltage(); | ||
88 | |||
89 | reset_battery_filter(mv / 5); | ||
90 | } | ||
91 | |||
92 | /* Disable charger and minimize all settings. Reset timers, etc. */ | ||
93 | static void disable_charger(void) | ||
94 | { | ||
95 | ascodec_write(AS3514_IRQ_ENRD0, 0); | ||
96 | ascodec_write(AS3514_CHARGER, | ||
97 | TMPSUP_OFF | CHG_I_50MA | CHG_V_3_90V | CHG_OFF); | ||
98 | |||
99 | if (charge_state > DISCHARGING) | ||
100 | charge_state = DISCHARGING; /* Not an error state already */ | ||
101 | |||
102 | charger_total_timer = 0; | ||
103 | battery_voltage_sync(); | ||
104 | } | ||
105 | |||
106 | /* Enable charger with specified settings. Start timers, etc. */ | ||
107 | static void enable_charger(void) | ||
108 | { | ||
109 | ascodec_write(AS3514_CHARGER, BATT_CHG_I | BATT_CHG_V); | ||
110 | /* Watch for end of charge. Temperature supervision is handled in | ||
111 | * hardware. Charger status can be read and has no interrupt enable. */ | ||
112 | ascodec_write(AS3514_IRQ_ENRD0, CHG_ENDOFCH); | ||
113 | |||
114 | sleep(HZ/10); /* Allow charger turn-on time (it could be gradual). */ | ||
115 | |||
116 | ascodec_read(AS3514_IRQ_ENRD0); /* Clear out interrupts (important!) */ | ||
117 | |||
118 | charge_state = CHARGING; | ||
119 | charger_total_timer = CHARGER_TOTAL_TIMER; | ||
120 | battery_voltage_sync(); | ||
121 | } | ||
122 | |||
123 | void powermgmt_init_target(void) | ||
124 | { | ||
125 | /* Everything CHARGER, OFF! */ | ||
126 | ascodec_write(AS3514_IRQ_ENRD0, 0); | ||
127 | ascodec_write(AS3514_CHARGER, | ||
128 | TMPSUP_OFF | CHG_I_50MA | CHG_V_3_90V | CHG_OFF); | ||
129 | } | ||
130 | |||
131 | static inline void charger_plugged(void) | ||
132 | { | ||
133 | batt_threshold = BATT_FULL_VOLTAGE; /* Start with topped value. */ | ||
134 | battery_voltage_sync(); | ||
135 | } | ||
136 | |||
137 | static inline void charger_control(void) | ||
138 | { | ||
139 | switch (charge_state) | ||
140 | { | ||
141 | case DISCHARGING: | ||
142 | { | ||
143 | unsigned int millivolts; | ||
144 | unsigned int thresh = batt_threshold; | ||
145 | |||
146 | if (BATT_FULL_VOLTAGE == thresh) | ||
147 | { | ||
148 | /* Wait for CHG_status to be indicated. */ | ||
149 | if ((ascodec_read(AS3514_IRQ_ENRD0) & CHG_STATUS) == 0) | ||
150 | break; | ||
151 | |||
152 | batt_threshold = BATT_VAUTO_RECHARGE; | ||
153 | } | ||
154 | |||
155 | millivolts = battery_voltage(); | ||
156 | |||
157 | if (millivolts <= thresh) | ||
158 | enable_charger(); | ||
159 | break; | ||
160 | } /* DISCHARGING: */ | ||
161 | |||
162 | case CHARGING: | ||
163 | { | ||
164 | if ((ascodec_read(AS3514_IRQ_ENRD0) & CHG_ENDOFCH) == 0) | ||
165 | { | ||
166 | if (--charger_total_timer > 0) | ||
167 | break; | ||
168 | |||
169 | /* Timer ran out - require replug. */ | ||
170 | charge_state = CHARGE_STATE_ERROR; | ||
171 | } | ||
172 | /* else end of charge */ | ||
173 | |||
174 | disable_charger(); | ||
175 | break; | ||
176 | } /* CHARGING: */ | ||
177 | |||
178 | default: | ||
179 | /* DISABLED, ERROR */ | ||
180 | break; | ||
181 | } | ||
182 | } | ||
183 | |||
184 | static inline void charger_unplugged(void) | ||
185 | { | ||
186 | disable_charger(); | ||
187 | if (charge_state >= CHARGE_STATE_ERROR) | ||
188 | charge_state = DISCHARGING; /* Reset error */ | ||
189 | } | ||
190 | |||
191 | /* Main charging algorithm - called from powermgmt.c */ | ||
192 | void charging_algorithm_step(void) | ||
193 | { | ||
194 | switch (charger_input_state) | ||
195 | { | ||
196 | case NO_CHARGER: | ||
197 | /* Nothing to do */ | ||
198 | break; | ||
199 | |||
200 | case CHARGER_PLUGGED: | ||
201 | charger_plugged(); | ||
202 | break; | ||
203 | |||
204 | case CHARGER: | ||
205 | charger_control(); | ||
206 | break; | ||
207 | |||
208 | case CHARGER_UNPLUGGED: | ||
209 | charger_unplugged(); | ||
210 | break; | ||
211 | } | ||
212 | |||
213 | if (charger_close) | ||
214 | { | ||
215 | /* Disable further charging and ack. */ | ||
216 | charge_state = CHARGE_STATE_DISABLED; | ||
217 | disable_charger(); | ||
218 | charger_close = false; | ||
219 | } | ||
220 | } | ||
221 | |||
222 | /* Disable the charger and prepare for poweroff - called off-thread so we | ||
223 | * signal the charging thread to prepare to quit. */ | ||
224 | void charging_algorithm_close(void) | ||
225 | { | ||
226 | charger_close = true; | ||
227 | |||
228 | /* Power management thread will set it false again. */ | ||
229 | while (charger_close) | ||
230 | sleep(HZ/10); | ||
231 | } | ||
diff --git a/firmware/target/arm/sandisk/powermgmt-target.h b/firmware/target/arm/sandisk/powermgmt-target.h new file mode 100644 index 0000000000..aa6a0e0e3d --- /dev/null +++ b/firmware/target/arm/sandisk/powermgmt-target.h | |||
@@ -0,0 +1,59 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2009 by Michael Sevakis | ||
11 | * Copyright (C) 2008 by Bertrik Sikken | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation; either version 2 | ||
16 | * of the License, or (at your option) any later version. | ||
17 | * | ||
18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
19 | * KIND, either express or implied. | ||
20 | * | ||
21 | ****************************************************************************/ | ||
22 | #ifndef POWERMGMT_TARGET_H | ||
23 | #define POWERMGMT_TARGET_H | ||
24 | |||
25 | #if defined(SANSA_C200) | ||
26 | /* This configuration triggers a single charge cycle upon plugging and stops. | ||
27 | * The true voltage cannot be read accurately and so monitoring isn't really | ||
28 | * possible. The battery filter is still synced to have a proper reading | ||
29 | * when disconnecting. */ | ||
30 | #define BATT_FULL_VOLTAGE 5121 /* Won't read this high - force start */ | ||
31 | #define BATT_VAUTO_RECHARGE 0 /* Won't read this low - force one cycle */ | ||
32 | #define BATT_CHG_V CHG_V_4_20V | ||
33 | #define BATT_CHG_I CHG_I_300MA | ||
34 | #define CHARGER_TOTAL_TIMER (4*3600*2) /* 4 hours enough? */ | ||
35 | #define ADC_BATTERY ADC_BVDD | ||
36 | #elif defined(SANSA_E200) | ||
37 | /* PREFERRED - Check if topped-off and monitor voltage while plugged. */ | ||
38 | #define BATT_FULL_VOLTAGE 4160 | ||
39 | #define BATT_VAUTO_RECHARGE 4100 | ||
40 | #define BATT_CHG_V CHG_V_4_20V | ||
41 | #define BATT_CHG_I CHG_I_300MA | ||
42 | #define CHARGER_TOTAL_TIMER (4*3600*2) /* 4 hours enough? */ | ||
43 | /* On e200 ADC_RTCSUP seems to represent battery voltage better than | ||
44 | * ADC_BVDD during charging (ADC_BVDD is way too high) and appears the | ||
45 | * same in normal use. | ||
46 | */ | ||
47 | #define ADC_BATTERY ADC_RTCSUP | ||
48 | #endif | ||
49 | |||
50 | void powermgmt_init_target(void); | ||
51 | void charging_algorithm_step(void); | ||
52 | void charging_algorithm_close(void); | ||
53 | |||
54 | /* We want to be able to reset the averaging filter */ | ||
55 | #define HAVE_RESET_BATTERY_FILTER | ||
56 | |||
57 | #define BATT_AVE_SAMPLES 32 | ||
58 | |||
59 | #endif /* POWERMGMT_TARGET_H */ | ||
diff --git a/firmware/target/arm/sandisk/sansa-c200/powermgmt-c200.c b/firmware/target/arm/sandisk/sansa-c200/powermgmt-c200.c index 963e7218de..9d7a0e2965 100644 --- a/firmware/target/arm/sandisk/sansa-c200/powermgmt-c200.c +++ b/firmware/target/arm/sandisk/sansa-c200/powermgmt-c200.c | |||
@@ -38,8 +38,8 @@ const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] = | |||
38 | const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] = | 38 | const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] = |
39 | { | 39 | { |
40 | 40 | ||
41 | /* NOTE: why is the top voltage 4237? That's just too high. */ | ||
41 | { 3286, 3679, 3734, 3764, 3788, 3824, 3886, 3950, 4014, 4098, 4237 }, | 42 | { 3286, 3679, 3734, 3764, 3788, 3824, 3886, 3950, 4014, 4098, 4237 }, |
42 | |||
43 | }; | 43 | }; |
44 | 44 | ||
45 | /* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */ | 45 | /* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */ |
@@ -48,14 +48,3 @@ const unsigned short percent_to_volt_charge[11] = | |||
48 | /* Sansa c200 has a 530 mAh LiPo battery */ | 48 | /* Sansa c200 has a 530 mAh LiPo battery */ |
49 | 3300, 3390, 3480, 3570, 3660, 3750, 3840, 3930, 4020, 4110, 4200 | 49 | 3300, 3390, 3480, 3570, 3660, 3750, 3840, 3930, 4020, 4110, 4200 |
50 | }; | 50 | }; |
51 | |||
52 | /* ADC should read 0x3ff=5.12V */ | ||
53 | #define BATTERY_SCALE_FACTOR 5125 | ||
54 | /* full-scale ADC readout (2^10) in millivolt */ | ||
55 | |||
56 | /* Returns battery voltage from ADC [millivolts] */ | ||
57 | unsigned int battery_adc_voltage(void) | ||
58 | { | ||
59 | return (adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR) >> 10; | ||
60 | } | ||
61 | |||
diff --git a/firmware/target/arm/sandisk/sansa-e200/powermgmt-e200.c b/firmware/target/arm/sandisk/sansa-e200/powermgmt-e200.c index 43f37463f8..144ca37ebf 100644 --- a/firmware/target/arm/sandisk/sansa-e200/powermgmt-e200.c +++ b/firmware/target/arm/sandisk/sansa-e200/powermgmt-e200.c | |||
@@ -47,14 +47,3 @@ const unsigned short percent_to_volt_charge[11] = | |||
47 | /* Sansa Li Ion 750mAH FIXME */ | 47 | /* Sansa Li Ion 750mAH FIXME */ |
48 | 3300, 3680, 3740, 3760, 3780, 3810, 3870, 3930, 3970, 4070, 4160 | 48 | 3300, 3680, 3740, 3760, 3780, 3810, 3870, 3930, 3970, 4070, 4160 |
49 | }; | 49 | }; |
50 | |||
51 | /* ADC should read 0x3ff=5.12V */ | ||
52 | #define BATTERY_SCALE_FACTOR 5125 | ||
53 | /* full-scale ADC readout (2^10) in millivolt */ | ||
54 | |||
55 | /* Returns battery voltage from ADC [millivolts] */ | ||
56 | unsigned int battery_adc_voltage(void) | ||
57 | { | ||
58 | return (adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR) >> 10; | ||
59 | } | ||
60 | |||