summaryrefslogtreecommitdiff
path: root/firmware/target/arm/imx31/gigabeat-s/powermgmt-gigabeat-s.c
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2010-04-09 01:21:53 +0000
committerMichael Sevakis <jethead71@rockbox.org>2010-04-09 01:21:53 +0000
commit7abf2b53a462612808d46d6d77a7f35261a0e5a3 (patch)
tree241304f7cd2b5d1c2a9e091fe56a33d2d2f8e816 /firmware/target/arm/imx31/gigabeat-s/powermgmt-gigabeat-s.c
parent43304b87b0662d1619ac60e5297a1694aa580310 (diff)
downloadrockbox-7abf2b53a462612808d46d6d77a7f35261a0e5a3.tar.gz
rockbox-7abf2b53a462612808d46d6d77a7f35261a0e5a3.zip
Gigabeat S/i.MX31: Sort files in the /target tree into things that are SoC-generic (into /imx31) and player-specific (into /gigabeat-s, based upon current appearances). Move i2s clock init into the appropriate file. Housekeeping only-- no functional changes.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25547 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm/imx31/gigabeat-s/powermgmt-gigabeat-s.c')
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/powermgmt-gigabeat-s.c940
1 files changed, 940 insertions, 0 deletions
diff --git a/firmware/target/arm/imx31/gigabeat-s/powermgmt-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/powermgmt-gigabeat-s.c
new file mode 100644
index 0000000000..34abf04940
--- /dev/null
+++ b/firmware/target/arm/imx31/gigabeat-s/powermgmt-gigabeat-s.c
@@ -0,0 +1,940 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (c) 2008 by Michael Sevakis
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 <stdlib.h>
22#include "config.h"
23#include "system.h"
24#include "thread.h"
25#include "mc13783.h"
26#include "adc.h"
27#include "powermgmt.h"
28#include "power.h"
29#include "power-gigabeat-s.h"
30
31/* TODO: Battery tests to get the right values! */
32const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] =
33{
34 3450
35};
36
37const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] =
38{
39 3400
40};
41
42/* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */
43const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] =
44{
45 /* Toshiba Gigabeat Li Ion 830mAH figured from discharge curve */
46 { 3480, 3550, 3590, 3610, 3630, 3650, 3700, 3760, 3800, 3910, 3990 },
47};
48
49/* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */
50const unsigned short percent_to_volt_charge[11] =
51{
52 /* Toshiba Gigabeat Li Ion 830mAH */
53 3480, 3550, 3590, 3610, 3630, 3650, 3700, 3760, 3800, 3910, 3990
54};
55
56/* Returns battery voltage from ADC [millivolts] */
57unsigned int battery_adc_voltage(void)
58{
59 /* ADC reading 0-1023 = 2400mV-4700mV */
60 return ((adc_read(ADC_BATTERY) * 2303) >> 10) + 2400;
61}
62
63/* Returns the application supply voltage from ADC [millvolts] */
64unsigned int application_supply_adc_voltage(void)
65{
66 return ((adc_read(ADC_APPLICATION_SUPPLY) * 2303) >> 10) + 2400;
67}
68
69unsigned int chrgraw_adc_voltage(void)
70{
71 return (adc_read(ADC_CHARGER_VOLTAGE) * 23023) >> 10;
72}
73
74/* Returns battery charge current from ADC [milliamps] */
75int battery_adc_charge_current(void)
76{
77 /* Positive reading = charger to battery
78 * Negative reading = battery to charger terminal
79 * ADC reading -512-511 = -2875mA-2875mA */
80 unsigned int value = adc_read(ADC_CHARGER_CURRENT);
81 int I;
82
83 if (value == ADC_READ_ERROR)
84 return INT_MIN;
85
86 I = ((((int32_t)value << 22) >> 22) * 2881) >> 9;
87 return ILEVEL_ADJUST_IN(I);
88}
89
90/* Estimate power dissipation in the charge path regulator in mW. */
91unsigned int cccv_regulator_dissipation(void)
92{
93 /* BATTISNS is shorted to BATT so we don't need to use the
94 * battery current reading. */
95 int chrgraw = (adc_read(ADC_CHARGER_VOLTAGE) * 230225) >> 10;
96 int batt = ((adc_read(ADC_BATTERY) * 23023) >> 10) + 24000;
97 int ichrgsn = adc_read(ADC_CHARGER_CURRENT);
98 ichrgsn = ((((int32_t)ichrgsn << 22) >> 22) * 2881) >> 9;
99 ichrgsn = abs(ichrgsn);
100
101 return (chrgraw - ichrgsn - batt)*ILEVEL_ADJUST_IN(ichrgsn) / 10000;
102}
103
104/* Returns battery temperature from ADC [deg-C] */
105int battery_adc_temp(void)
106{
107 /* E[volts] = value * 2.3V / 1023
108 * R[ohms] = E/I = E[volts] / 0.00002[A] (Thermistor bias current source)
109 *
110 * Steinhart-Hart thermistor equation:
111 * [A + B*ln(R) + D*ln^3(R)] = 1 / T[°K]
112 *
113 * Coeffients that fit experimental data (one thermistor so far, one run):
114 * A = 0.0013002631685462800
115 * B = 0.0002000841932612330
116 * D = 0.0000000640446750919
117 */
118 static const unsigned short ntc_table[] =
119 {
120#if 0 /* These have degree deltas > 1 (except the final two) so leave them
121 * out. 70 deg C upper limit is quite sufficient. */
122 0, /* INF */ 1, /* 171 */ 2, /* 145 */ 3, /* 130 */
123 4, /* 121 */ 5, /* 114 */ 6, /* 108 */ 7, /* 104 */
124 8, /* 100 */ 9, /* 96 */ 10, /* 93 */ 11, /* 91 */
125 12, /* 88 */ 13, /* 86 */ 14, /* 84 */ 15, /* 82 */
126 16, /* 81 */ 17, /* 79 */ 18, /* 78 */ 19, /* 76 */
127 20, /* 75 */ 21, /* 74 */ 22, /* 72 */ 23, /* 71 */
128#endif
129 24, /* 70 */ 25, /* 69 */ 26, /* 68 */ 27, /* 67 */
130 28, /* 66 */ 30, /* 65 */ 31, /* 64 */ 32, /* 63 */
131 33, /* 62 */ 35, /* 61 */ 36, /* 60 */ 38, /* 59 */
132 39, /* 58 */ 41, /* 57 */ 43, /* 56 */ 45, /* 55 */
133 47, /* 54 */ 49, /* 53 */ 51, /* 52 */ 53, /* 51 */
134 56, /* 50 */ 58, /* 49 */ 61, /* 48 */ 63, /* 47 */
135 66, /* 46 */ 69, /* 45 */ 73, /* 44 */ 76, /* 43 */
136 80, /* 42 */ 83, /* 41 */ 87, /* 40 */ 92, /* 39 */
137 96, /* 38 */ 101, /* 37 */ 106, /* 36 */ 111, /* 35 */
138 116, /* 34 */ 122, /* 33 */ 128, /* 32 */ 135, /* 31 */
139 142, /* 30 */ 149, /* 29 */ 156, /* 28 */ 164, /* 27 */
140 173, /* 26 */ 182, /* 25 */ 192, /* 24 */ 202, /* 23 */
141 212, /* 22 */ 224, /* 21 */ 236, /* 20 */ 249, /* 19 */
142 262, /* 18 */ 277, /* 17 */ 292, /* 16 */ 308, /* 15 */
143 325, /* 14 */ 344, /* 13 */ 363, /* 12 */ 384, /* 11 */
144 406, /* 10 */ 429, /* 9 */ 454, /* 8 */ 480, /* 7 */
145 509, /* 6 */ 539, /* 5 */ 571, /* 4 */ 605, /* 3 */
146 641, /* 2 */ 680, /* 1 */ 722, /* 0 */ 766, /* -1 */
147 813, /* -2 */ 864, /* -3 */ 918, /* -4 */ 976, /* -5 */
148 };
149
150 unsigned int value = adc_read(ADC_BATTERY_TEMP);
151
152 if (value > 0)
153 {
154 unsigned i;
155
156 for (i = 1; i < ARRAYLEN(ntc_table); i++)
157 {
158 if (ntc_table[i] > value)
159 break;
160 }
161
162 return 71 - i;
163 }
164
165 return INT_MIN;
166}
167
168/** Charger control **/
169
170/* All code has a preference for the main charger being connected over
171 * USB. USB is considered in the algorithm only if it is the sole source. */
172static uint32_t int_sense0 = 0; /* Interrupt Sense 0 bits */
173static unsigned int last_inputs = POWER_INPUT_NONE; /* Detect input changes */
174static int charger_total_timer = 0; /* Total allowed charging time */
175static int icharger_ave = 0; /* Filtered charging current */
176static bool charger_close = false; /* Shutdown notification */
177static bool service_wdt = true; /* Service the watchdog timer, if things
178 go very wrong, cease and shut down. */
179static uint32_t charger_setting = 0; /* Current ICHRG and VCHRG regulator
180 * setting (register bits) */
181#define CHARGER_ADJUST ((uint32_t)-1)/* Force change in regulator setting */
182static int autorecharge_counter = 0 ; /* Battery < threshold debounce */
183static int chgcurr_timer = 0; /* Countdown to CHGCURR error */
184#define AUTORECHARGE_COUNTDOWN (10*2) /* 10s debounce */
185#define WATCHDOG_TIMEOUT (10*2) /* If not serviced, poweroff in 10s */
186#define CHGCURR_TIMEOUT (4*2) /* 4s debounce */
187
188/* Temperature monitoring */
189static enum
190{
191 TEMP_STATE_NORMAL = 0, /* Within range */
192 TEMP_STATE_WAIT = 1, /* Went out of range, wait to come back */
193 TEMP_LOW_LIMIT = 0, /* Min temp */
194 TEMP_HIGH_LIMIT = 1, /* Max temp */
195} temp_state = TEMP_STATE_NORMAL;
196
197/* Set power thread priority for charging mode or not */
198static inline void charging_set_thread_priority(bool charging)
199{
200#ifdef HAVE_PRIORITY_SCHEDULING
201 thread_set_priority(THREAD_ID_CURRENT,
202 charging ? PRIORITY_REALTIME : PRIORITY_SYSTEM);
203#endif
204 (void)charging;
205}
206
207/* Update filtered charger current - exponential moving average */
208static bool charger_current_filter_step(void)
209{
210 int value = battery_adc_charge_current();
211
212 if (value == ADC_READ_ERROR)
213 return false;
214
215 icharger_ave += value - (icharger_ave / ICHARGER_AVE_SAMPLES);
216 return true;
217}
218
219/* Return true if the main charger is connected. */
220static bool main_charger_connected(void)
221{
222 return (last_inputs &
223 POWER_INPUT_MAIN_CHARGER &
224 POWER_INPUT_CHARGER) != 0;
225}
226
227/* Return the voltage level which should automatically trigger
228 * another recharge cycle based upon which power source is available.
229 * Assumes at least one is. */
230static unsigned int auto_recharge_voltage(void)
231{
232 if (main_charger_connected())
233 return BATT_VAUTO_RECHARGE;
234 else
235 return BATT_USB_VAUTO_RECHARGE;
236}
237
238/* Return greater of supply (BP) or filtered battery voltage. */
239unsigned int input_millivolts(void)
240{
241 unsigned int app_millivolts = application_supply_adc_voltage();
242 unsigned int bat_millivolts = battery_voltage();
243
244 return MAX(app_millivolts, bat_millivolts);
245}
246
247/* Get smoothed readings for initializing filtered data. */
248static int stat_battery_reading(int type)
249{
250 int high = INT_MIN, low = INT_MAX;
251 int value = 0;
252 int i;
253
254 for (i = 0; i < 7; i++)
255 {
256 int reading = ADC_READ_ERROR;
257
258 sleep(2); /* Get unique readings */
259
260 switch (type)
261 {
262 case ADC_BATTERY:
263 reading = battery_adc_voltage();
264 break;
265
266 case ADC_CHARGER_CURRENT:
267 reading = battery_adc_charge_current();
268 break;
269 }
270
271 if (reading == ADC_READ_ERROR)
272 return INT_MIN;
273
274 if (reading > high)
275 high = reading;
276
277 if (reading < low)
278 low = reading;
279
280 value += reading;
281 }
282
283 /* Discard extremes */
284 return (value - high - low) / 5;
285}
286
287/* Update filtered battery voltage instead of waiting for filter
288 * decay. */
289static bool update_filtered_battery_voltage(void)
290{
291 int millivolts = stat_battery_reading(ADC_BATTERY);
292
293 if (millivolts != INT_MIN)
294 {
295 reset_battery_filter(millivolts);
296 return true;
297 }
298
299 return false;
300}
301
302/* Sets the charge current limit based upon state. charge_state should be
303 * set before calling. */
304static bool adjust_charger_current(void)
305{
306 static const uint8_t charger_bits[][2] =
307 {
308 [DISCHARGING] =
309 {
310 /* These are actually zeros but reflect this setting */
311 MC13783_ICHRG_0MA | MC13783_VCHRG_4_050V,
312 MC13783_ICHRG_0MA | MC13783_VCHRG_4_050V,
313 },
314 /* Main(+USB): Charge slowly from the adapter until voltage is
315 * sufficient for normal charging.
316 *
317 * USB: The truth is that things will probably not make it this far.
318 * Cover the case, just in case the disk isn't used and it is
319 * manageable. */
320 [TRICKLE] =
321 {
322 BATTERY_ITRICKLE | BATTERY_VCHARGING,
323 BATTERY_ITRICKLE_USB | BATTERY_VCHARGING
324 },
325 [TOPOFF] =
326 {
327 BATTERY_IFAST | BATTERY_VCHARGING,
328 BATTERY_IFAST_USB | BATTERY_VCHARGING
329 },
330 [CHARGING] =
331 {
332 BATTERY_IFAST | BATTERY_VCHARGING,
333 BATTERY_IFAST_USB | BATTERY_VCHARGING
334 },
335 /* Must maintain battery when on USB power only - utterly nasty
336 * but true and something retailos does (it will even end up charging
337 * the battery but not reporting that it is doing so).
338 * Float lower than MAX - could end up slightly discharging after
339 * a full charge but this is safer than maxing it out. */
340 [CHARGING+1] =
341 {
342 BATTERY_IFLOAT_USB | BATTERY_VFLOAT_USB,
343 BATTERY_IMAINTAIN_USB | BATTERY_VMAINTAIN_USB
344 },
345#if 0
346 /* Slower settings to so that the linear regulator doesn't dissipate
347 * an excessive amount of power when coming out of precharge state. */
348 [CHARGING+2] =
349 {
350 BATTERY_ISLOW | BATTERY_VCHARGING,
351 BATTERY_ISLOW_USB | BATTEYR_VCHARGING
352 },
353#endif
354 };
355
356 bool success = false;
357 int usb_select;
358 uint32_t i;
359
360 usb_select = ((last_inputs & POWER_INPUT) == POWER_INPUT_USB)
361 ? 1 : 0;
362
363 if (charge_state == DISCHARGING && usb_select == 1)
364 {
365 /* USB-only, DISCHARGING, = maintaining battery */
366 int select = (last_inputs & POWER_INPUT_CHARGER) ? 0 : 1;
367 charger_setting = charger_bits[CHARGING+1][select];
368 }
369 else
370 {
371 /* Take very good care not to write garbage. */
372 int state = charge_state;
373
374 if (state < DISCHARGING || state > CHARGING)
375 state = DISCHARGING;
376
377 charger_setting = charger_bits[state][usb_select];
378 }
379
380 if (charger_setting != 0)
381 {
382 if ((charger_setting & MC13783_VCHRG) > BATTERY_VCHARGING ||
383 (charger_setting & MC13783_ICHRG) > BATTERY_IFAST)
384 {
385 /* Table is corrupted somehow. We shouldn't run at all.
386 *
387 * Explanation: On two occasions, even though this driver monitors
388 * the regulator register settings on each step and
389 * ensures that only valid table indexes are used,
390 * the current and voltage seem to be misregulated,
391 * resulting in excessively high battery voltage that
392 * will trip the battery protection. After careful
393 * review it seems that two possibilities exist:
394 * This code or data got trashed at some point or
395 * there really is a hardware bug of some sort. So
396 * far the cause is unknown. Voltage is also
397 * monitored in the CHARGING case for that reason.
398 * The solution for data or code corruption is to
399 * just panic and refuse to run the device. The
400 * solution for overvoltage due to hardware bug is to
401 * disable the charging. The action taken will reveal
402 * the true cause, thus _who_ is responsible.
403 * "Burning lithium is baaaad", so sayeth The Council
404 * of Seven Ascended Masters. */
405 charge_state = CHARGE_STATE_DISABLED;
406 service_wdt = false;
407 }
408 else
409 {
410 /* Turn on 5K pulldown. */
411 i = mc13783_set(MC13783_CHARGER, MC13783_CHRGRAWPDEN);
412
413 if (i != MC13783_DATA_ERROR)
414 {
415 charging_set_thread_priority(true);
416
417 /* Turn regulator logically ON. Hardware may still override.
418 */
419 i = mc13783_write_masked(MC13783_CHARGER, charger_setting,
420 MC13783_ICHRG | MC13783_VCHRG);
421
422 if (i != MC13783_DATA_ERROR)
423 {
424 int icharger;
425
426 /* Enable charge current conversion */
427 adc_enable_channel(ADC_CHARGER_CURRENT, true);
428
429 /* Charge path regulator turn on takes ~100ms max. */
430 sleep(HZ/10);
431
432 icharger = stat_battery_reading(ADC_CHARGER_CURRENT);
433
434 if (icharger != INT_MIN)
435 {
436 icharger_ave = icharger * ICHARGER_AVE_SAMPLES;
437
438 if (update_filtered_battery_voltage())
439 return true;
440 }
441 }
442 }
443
444 /* Force regulator OFF. */
445 charge_state = CHARGE_STATE_ERROR;
446 }
447 }
448
449 /* Turn regulator OFF. */
450 icharger_ave = 0;
451 i = mc13783_write_masked(MC13783_CHARGER,
452 MC13783_ICHRG_0MA | MC13783_VCHRG_4_050V,
453 MC13783_ICHRG | MC13783_VCHRG |
454 MC13783_CHRGRAWPDEN);
455
456 if (MC13783_DATA_ERROR == i)
457 {
458 /* Failed. Force poweroff by not servicing the watchdog. */
459 service_wdt = false;
460 }
461 else if (0 == charger_setting)
462 {
463 /* Here because OFF was requested state */
464 success = true;
465 }
466
467 charger_setting = 0;
468
469 adc_enable_channel(ADC_CHARGER_CURRENT, false);
470 update_filtered_battery_voltage();
471 charging_set_thread_priority(false);
472
473 return success;
474}
475
476/* Stop the charger - if USB only then the regulator will not really be
477 * turned off. ERROR or DISABLED will turn it off however. */
478static void stop_charger(void)
479{
480 charger_total_timer = 0;
481
482 if (charge_state > DISCHARGING)
483 charge_state = DISCHARGING;
484
485 adjust_charger_current();
486}
487
488/* Return OK if it is acceptable to start the regulator. */
489static bool charging_ok(void)
490{
491 bool ok = charge_state >= DISCHARGING; /* Not an error condition? */
492
493 if (ok)
494 {
495 /* Is the battery even connected? */
496 ok = (last_inputs & POWER_INPUT_BATTERY) != 0;
497 }
498
499 if (ok)
500 {
501 /* No tolerance for any over/under temp - wait for it to
502 * come back into safe range. */
503 static const signed char temp_ranges[2][2] =
504 {
505 /* Temperature range before beginning charging */
506 { BATTERY_CHARGE_MIN,
507 BATTERY_CHARGE_MAX },
508 /* Temperature range after out-of-range detected -
509 charging will self-resume */
510 { BATTERY_CHARGE_RESTART_MIN,
511 BATTERY_CHARGE_RESTART_MAX },
512 };
513
514 int temp = battery_adc_temp();
515 const signed char *range = temp_ranges[temp_state];
516
517 ok = temp >= range[TEMP_LOW_LIMIT] &&
518 temp <= range[TEMP_HIGH_LIMIT];
519
520 switch (temp_state)
521 {
522 case TEMP_STATE_NORMAL:
523 if (!ok)
524 temp_state = TEMP_STATE_WAIT;
525 break;
526
527 case TEMP_STATE_WAIT:
528 if (ok)
529 temp_state = TEMP_STATE_NORMAL;
530 break;
531
532 default:
533 break;
534 }
535 }
536
537 if (ok)
538 {
539 /* Any events that should stop the regulator? */
540
541 /* Overvoltage at CHRGRAW? */
542 ok = (int_sense0 & MC13783_CHGOVS) == 0;
543
544 if (ok)
545 {
546 /* CHGCURR sensed? */
547 ok = (int_sense0 & MC13783_CHGCURRS) != 0;
548
549 if (!ok)
550 {
551 /* Debounce transient states */
552 if (chgcurr_timer > 0)
553 {
554 chgcurr_timer--;
555 ok = true;
556 }
557 }
558 else
559 {
560 chgcurr_timer = CHGCURR_TIMEOUT;
561 }
562 }
563
564 /* Charger may need to be reinserted */
565 if (!ok)
566 charge_state = CHARGE_STATE_ERROR;
567 }
568
569 if (charger_setting != 0)
570 {
571 if (ok)
572 {
573 /* Protect against any conceivable overcharge/voltage condition
574 * before hardware protection must intervene. Disable charger
575 * until reboot. */
576 ok = battery_voltage() < BATT_TOO_HIGH;
577 if (!ok)
578 charge_state = CHARGE_STATE_DISABLED;
579 }
580
581 if (ok)
582 {
583 /* Watch to not overheat FET (nothing should go over about 1012.7mW).
584 * Trying a higher voltage AC adapter can work (up to 6.90V) but
585 * we'll just reject that. Reducing current for adapters that bring
586 * CHRGRAW to > 4.900V is another possible action. */
587 ok = cccv_regulator_dissipation() < 1150;
588 if (!ok)
589 charge_state = CHARGE_STATE_ERROR;
590 }
591
592 if (!ok)
593 {
594 int state = charge_state;
595
596 if (state > DISCHARGING)
597 state = DISCHARGING;
598
599 /* Force off for all states including maintaining the battery level
600 * on USB. */
601 charge_state = CHARGE_STATE_ERROR;
602 stop_charger();
603 charge_state = state;
604 }
605 }
606
607 return ok;
608}
609
610void powermgmt_init_target(void)
611{
612#ifdef IMX31_ALLOW_CHARGING
613 const uint32_t regval_w =
614 MC13783_VCHRG_4_050V | MC13783_ICHRG_0MA |
615 MC13783_ICHRGTR_0MA | MC13783_OVCTRL_6_90V;
616
617 /* Use watchdog to shut system down if we lose control of the charging
618 * hardware. */
619 watchdog_init(WATCHDOG_TIMEOUT);
620
621 mc13783_write(MC13783_CHARGER, regval_w);
622
623 if (mc13783_read(MC13783_CHARGER) == regval_w)
624 {
625 /* Divide CHRGRAW input by 10 */
626 mc13783_clear(MC13783_ADC0, MC13783_CHRGRAWDIV);
627 /* Turn off BATTDETB. It's worthless on MESx0V since the battery
628 * isn't removable (nor the thermistor). */
629 mc13783_clear(MC13783_POWER_CONTROL0, MC13783_BATTDETEN);
630 }
631 else
632 {
633 /* Register has the wrong value - set error condition and disable
634 * since something is wrong. */
635 charge_state = CHARGE_STATE_DISABLED;
636 stop_charger();
637 }
638#else
639 /* Disable charger use */
640 charge_state = CHARGE_STATE_DISABLED;
641#endif
642}
643
644/* Returns true if the unit is charging the batteries. */
645bool charging_state(void)
646{
647 switch (charge_state)
648 {
649 case TRICKLE:
650 case TOPOFF:
651 case CHARGING:
652 return true;
653 default:
654 return false;
655 }
656}
657
658/* Filtered battery charge current */
659int battery_charge_current(void)
660{
661 return icharger_ave / ICHARGER_AVE_SAMPLES;
662}
663
664static void charger_plugged(void)
665{
666 adc_enable_channel(ADC_BATTERY_TEMP, true);
667 autorecharge_counter = -1;
668}
669
670static void charger_unplugged(void)
671{
672 /* Charger pulled - turn off current sources (though hardware
673 * will have done that anyway). */
674 if (charge_state > CHARGE_STATE_DISABLED)
675 {
676 /* Reset state and clear any error. If disabled, the charger
677 * will not have been started or will have been stopped already. */
678 stop_charger();
679 charge_state = DISCHARGING;
680 }
681
682 /* Might need to reevaluate these bits in charger_none. */
683 last_inputs &= ~(POWER_INPUT | POWER_INPUT_CHARGER);
684 temp_state = TEMP_STATE_NORMAL;
685 autorecharge_counter = 0;
686 chgcurr_timer = 0;
687
688 adc_enable_channel(ADC_BATTERY_TEMP, false);
689}
690
691static void charger_none(void)
692{
693 unsigned int pwr = power_thread_inputs;
694
695 if (last_inputs != pwr)
696 {
697 last_inputs = pwr;
698
699 if (charge_state == CHARGE_STATE_DISABLED)
700 return;
701
702 if ((pwr & (POWER_INPUT | POWER_INPUT_CHARGER)) == POWER_INPUT_USB)
703 {
704 /* USB connected but not configured. Maintain battery to the
705 * greatest degree possible. It probably won't be enough but the
706 * discharge won't be so severe. */
707 charger_plugged();
708 charger_setting = CHARGER_ADJUST;
709 }
710 else
711 {
712 charger_unplugged();
713 last_inputs = pwr; /* Restore status */
714 }
715 }
716 else if (charger_setting != 0)
717 {
718 /* Maintaining - keep filter going and check charge state */
719 int_sense0 = mc13783_read(MC13783_INTERRUPT_SENSE0);
720
721 if (!charger_current_filter_step())
722 {
723 /* Failed to read current */
724 charge_state = CHARGE_STATE_ERROR;
725 }
726
727 charging_ok();
728 }
729}
730
731static void charger_control(void)
732{
733 unsigned int pwr = power_thread_inputs;
734
735 if (last_inputs != pwr)
736 {
737 unsigned int changed = last_inputs ^ pwr;
738
739 last_inputs = pwr;
740
741 if (charger_setting != 0)
742 charger_setting = CHARGER_ADJUST;
743
744 if (charge_state == DISCHARGING)
745 {
746 if (main_charger_connected())
747 {
748 /* If main is connected, ignore USB plugs. */
749 if (changed & POWER_INPUT_MAIN_CHARGER)
750 {
751 /* Main charger plugged - try charge */
752 autorecharge_counter = -1;
753 }
754 }
755 else if (pwr & POWER_INPUT_USB_CHARGER
756 & POWER_INPUT_CHARGER)
757 {
758 /* USB power only */
759 if (changed & POWER_INPUT_USB_CHARGER)
760 {
761 /* USB charger plugged - try charge */
762 autorecharge_counter = -1;
763 }
764 else if (changed & POWER_INPUT_MAIN_CHARGER)
765 {
766 /* Main charger pulled - go to battery maintenence. */
767 charger_setting = CHARGER_ADJUST;
768 }
769 }
770 }
771 }
772
773 if (charger_setting != 0 && !charger_current_filter_step())
774 {
775 /* Failed to read current */
776 charge_state = CHARGE_STATE_ERROR;
777 }
778
779 int_sense0 = mc13783_read(MC13783_INTERRUPT_SENSE0);
780
781 if (!charging_ok())
782 return;
783
784 switch (charge_state)
785 {
786 case DISCHARGING:
787 {
788 /* Battery voltage may have dropped and a charge cycle should
789 * start again. Debounced. */
790 if (autorecharge_counter < 0 &&
791 battery_adc_voltage() < BATT_FULL_VOLTAGE)
792 {
793 /* Try starting a cycle now if battery isn't already topped
794 * off to allow user to ensure the battery is full. */
795 }
796 else if (battery_voltage() > auto_recharge_voltage())
797 {
798 /* Still above threshold - reset counter */
799 autorecharge_counter = AUTORECHARGE_COUNTDOWN;
800 break;
801 }
802 else if (autorecharge_counter > 0)
803 {
804 /* Coundown to restart */
805 autorecharge_counter--;
806 break;
807 }
808
809 autorecharge_counter = 0;
810
811 charging_set_thread_priority(true);
812
813 if (stat_battery_reading(ADC_BATTERY) < BATT_VTRICKLE_CHARGE)
814 {
815 /* Battery is deeply discharged - precharge at lower current. */
816 charge_state = TRICKLE;
817 }
818 else
819 {
820 /* Ok for fast charge */
821 charge_state = CHARGING;
822 }
823
824 charger_setting = CHARGER_ADJUST;
825 charger_total_timer = CHARGER_TOTAL_TIMER*60*2;
826 break;
827 } /* DISCHARGING: */
828
829 case TRICKLE: /* Very low - precharge */
830 {
831 if (battery_voltage() <= BATT_VTRICKLE_CHARGE)
832 break;
833
834 /* Switch to normal charge mode. */
835 charge_state = CHARGING;
836 charger_setting = CHARGER_ADJUST;
837 break;
838 } /* TRICKLE: */
839
840 case CHARGING: /* Constant-current stage */
841 case TOPOFF: /* Constant-voltage stage */
842 {
843 /* Reg. mode is more informative than an operational necessity. */
844 charge_state = (int_sense0 & MC13783_CCCVS) ? TOPOFF : CHARGING;
845
846 if (main_charger_connected())
847 {
848 /* Monitor and stop if current drops below threshold. */
849 if (battery_charge_current() > BATTERY_ICHARGE_COMPLETE)
850 break;
851 }
852 else
853 {
854 /* Accurate I-level can't be determined since device also
855 * powers through the I sense. This simply stops the reporting
856 * of charging but the regulator remains on. */
857 if (battery_voltage() <= BATT_USB_VSTOP)
858 break;
859 }
860
861 stop_charger();
862 break;
863 } /* CHARGING: TOPOFF: */
864
865 default:
866 break;
867 } /* switch */
868
869 /* Check if charger timer expired and stop it if so. */
870 if (charger_total_timer > 0 && --charger_total_timer == 0)
871 {
872 charge_state = CHARGE_STATE_ERROR;
873 stop_charger(); /* Time ran out - error */
874 }
875}
876
877/* Main charging algorithm - called from powermgmt.c */
878void charging_algorithm_step(void)
879{
880#ifdef IMX31_ALLOW_CHARGING
881 if (service_wdt)
882 watchdog_service();
883#endif
884
885 /* Switch by input state */
886 switch (charger_input_state)
887 {
888 case NO_CHARGER:
889 charger_none();
890 break;
891
892 case CHARGER_PLUGGED:
893 charger_plugged();
894 break;
895
896 case CHARGER:
897 charger_control();
898 break;
899
900 case CHARGER_UNPLUGGED:
901 charger_unplugged();
902 break;
903 } /* switch */
904
905 if (charger_close)
906 {
907 if (charge_state != CHARGE_STATE_DISABLED)
908 {
909 /* Disable starts while shutting down */
910 charge_state = CHARGE_STATE_DISABLED;
911 stop_charger();
912 }
913
914 charger_close = false;
915 return;
916 }
917
918 if (charger_setting != 0)
919 {
920 if ((mc13783_read(MC13783_CHARGER) & (MC13783_ICHRG | MC13783_VCHRG)) !=
921 charger_setting)
922 {
923 /* The hardware setting doesn't match. It could have turned the
924 * charger off in a race of plugging/unplugging or the setting
925 * was changed in one of the calls. */
926 adjust_charger_current();
927 }
928 }
929}
930
931/* Disable the charger and prepare for poweroff - called off-thread so we
932 * signal the charging thread to prepare to quit. */
933void charging_algorithm_close(void)
934{
935 charger_close = true;
936
937 /* Power management thread will set it false again */
938 while (charger_close)
939 sleep(HZ/10);
940}