summaryrefslogtreecommitdiff
path: root/firmware/target/arm/imx31/gigabeat-s/powermgmt-imx31.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/imx31/gigabeat-s/powermgmt-imx31.c')
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/powermgmt-imx31.c883
1 files changed, 845 insertions, 38 deletions
diff --git a/firmware/target/arm/imx31/gigabeat-s/powermgmt-imx31.c b/firmware/target/arm/imx31/gigabeat-s/powermgmt-imx31.c
index 796c781f73..c44e7ccdda 100644
--- a/firmware/target/arm/imx31/gigabeat-s/powermgmt-imx31.c
+++ b/firmware/target/arm/imx31/gigabeat-s/powermgmt-imx31.c
@@ -7,8 +7,7 @@
7 * \/ \/ \/ \/ \/ 7 * \/ \/ \/ \/ \/
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Copyright (C) 2002 by Heikki Hannikainen, Uwe Freese 10 * Copyright (c) 2008 by Michael Sevakis
11 * Revisions copyright (C) 2005 by Gerald Van Baren
12 * 11 *
13 * This program is free software; you can redistribute it and/or 12 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License 13 * modify it under the terms of the GNU General Public License
@@ -19,12 +18,40 @@
19 * KIND, either express or implied. 18 * KIND, either express or implied.
20 * 19 *
21 ****************************************************************************/ 20 ****************************************************************************/
22 21#include <stdlib.h>
23/* FIXME: This is just the Gigabeat F/X file with a different name... */
24
25#include "config.h" 22#include "config.h"
23#include "system.h"
24#include "thread.h"
25#include "mc13783.h"
26#include "adc.h" 26#include "adc.h"
27#include "powermgmt.h" 27#include "powermgmt.h"
28#include "power.h"
29#include "power-imx31.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};
28 55
29/** 56/**
30 * Fixed-point natural log 57 * Fixed-point natural log
@@ -56,31 +83,6 @@ static long flog(int x)
56 return y; 83 return y;
57} 84}
58 85
59
60const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] =
61{
62 3450
63};
64
65const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] =
66{
67 3400
68};
69
70/* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */
71const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] =
72{
73 /* Toshiba Gigabeat Li Ion 830mAH figured from discharge curve */
74 { 3480, 3550, 3590, 3610, 3630, 3650, 3700, 3760, 3800, 3910, 3990 },
75};
76
77/* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */
78const unsigned short percent_to_volt_charge[11] =
79{
80 /* Toshiba Gigabeat Li Ion 830mAH */
81 3480, 3550, 3590, 3610, 3630, 3650, 3700, 3760, 3800, 3910, 3990
82};
83
84/* Returns battery voltage from ADC [millivolts] */ 86/* Returns battery voltage from ADC [millivolts] */
85unsigned int battery_adc_voltage(void) 87unsigned int battery_adc_voltage(void)
86{ 88{
@@ -88,6 +90,17 @@ unsigned int battery_adc_voltage(void)
88 return ((adc_read(ADC_BATTERY) * 2303) >> 10) + 2400; 90 return ((adc_read(ADC_BATTERY) * 2303) >> 10) + 2400;
89} 91}
90 92
93/* Returns the application supply voltage from ADC [millvolts] */
94unsigned int application_supply_adc_voltage(void)
95{
96 return ((adc_read(ADC_APPLICATION_SUPPLY) * 2303) >> 10) + 2400;
97}
98
99unsigned int chrgraw_adc_voltage(void)
100{
101 return (adc_read(ADC_CHARGER_VOLTAGE) * 23023) >> 10;
102}
103
91/* Returns battery charge current from ADC [milliamps] */ 104/* Returns battery charge current from ADC [milliamps] */
92int battery_adc_charge_current(void) 105int battery_adc_charge_current(void)
93{ 106{
@@ -95,11 +108,31 @@ int battery_adc_charge_current(void)
95 * Negative reading = battery to charger terminal 108 * Negative reading = battery to charger terminal
96 * ADC reading -512-511 = -2875mA-2875mA */ 109 * ADC reading -512-511 = -2875mA-2875mA */
97 unsigned int value = adc_read(ADC_CHARGER_CURRENT); 110 unsigned int value = adc_read(ADC_CHARGER_CURRENT);
98 return (((int)value << 22) >> 22) * 2881 >> 9; 111 int I;
112
113 if (value == ADC_READ_ERROR)
114 return INT_MIN;
115
116 I = ((((int32_t)value << 22) >> 22) * 2881) >> 9;
117 return ILEVEL_ADJUST_IN(I);
118}
119
120/* Estimate power dissipation in the charge path regulator in mW. */
121unsigned int cccv_regulator_dissipation(void)
122{
123 /* BATTISNS is shorted to BATT so we don't need to use the
124 * battery current reading. */
125 int chrgraw = (adc_read(ADC_CHARGER_VOLTAGE) * 230225) >> 10;
126 int batt = ((adc_read(ADC_BATTERY) * 23023) >> 10) + 24000;
127 int ichrgsn = adc_read(ADC_CHARGER_CURRENT);
128 ichrgsn = ((((int32_t)ichrgsn << 22) >> 22) * 2881) >> 9;
129 ichrgsn = abs(ichrgsn);
130
131 return (chrgraw - ichrgsn - batt)*ILEVEL_ADJUST_IN(ichrgsn) / 10000;
99} 132}
100 133
101/* Returns battery temperature from ADC [deg-C] */ 134/* Returns battery temperature from ADC [deg-C] */
102unsigned int battery_adc_temp(void) 135int battery_adc_temp(void)
103{ 136{
104 unsigned int value = adc_read(ADC_BATTERY_TEMP); 137 unsigned int value = adc_read(ADC_BATTERY_TEMP);
105 /* E[volts] = value * 2.3V / 1023 138 /* E[volts] = value * 2.3V / 1023
@@ -117,10 +150,784 @@ unsigned int battery_adc_temp(void)
117 * Fixed-point output matches the floating-point version for each ADC 150 * Fixed-point output matches the floating-point version for each ADC
118 * value. 151 * value.
119 */ 152 */
120 int R = 2070000 * value; 153 if (value > 0)
121 long long ln = flog(R) + 83196; 154 {
122 long long t0 = 425890304133ll; 155 int R = 2070000 * value;
123 long long t1 = 1000000*ln; 156 long long ln = flog(R) + 83196;
124 long long t3 = ln*ln*ln / 13418057; 157 long long t0 = 425890304133ll;
125 return ((32754211579494400ll / (t0 + t1 + t3)) - 27315) / 100; 158 long long t1 = 1000000*ln;
159 long long t3 = ln*ln*ln / 13418057;
160 return ((32754211579494400ll / (t0 + t1 + t3)) - 27315) / 100;
161 }
162
163 return INT_MIN;
164}
165
166/** Charger control **/
167
168/* All code has a preference for the main charger being connected over
169 * USB. USB is considered in the algorithm only if it is the sole source. */
170static uint32_t int_sense0 = 0; /* Interrupt Sense 0 bits */
171static unsigned int power_status = POWER_INPUT_NONE; /* Detect input changes */
172static int charger_total_timer = 0; /* Total allowed charging time */
173static int icharger_ave = 0; /* Filtered charging current */
174static bool charger_close = false; /* Shutdown notification */
175static bool service_wdt = true; /* Service the watchdog timer, if things
176 go very wrong, cease and shut down. */
177static uint32_t charger_setting = 0; /* Current ICHRG and VCHRG regulator
178 * setting (register bits) */
179#define CHARGER_ADJUST ((uint32_t)-1)/* Force change in regulator setting */
180static int autorecharge_counter = 0 ; /* Battery < threshold debounce */
181static int chgcurr_timer = 0; /* Countdown to CHGCURR error */
182#define AUTORECHARGE_COUNTDOWN (10*2) /* 10s debounce */
183#define WATCHDOG_TIMEOUT (10*2) /* If not serviced, poweroff in 10s */
184#define CHGCURR_TIMEOUT (2*2) /* 2s debounce */
185
186/* Temperature monitoring */
187static enum
188{
189 TEMP_STATE_NORMAL = 0, /* Within range */
190 TEMP_STATE_WAIT = 1, /* Went out of range, wait to come back */
191 TEMP_LOW_LIMIT = 0, /* Min temp */
192 TEMP_HIGH_LIMIT = 1, /* Max temp */
193} temp_state = TEMP_STATE_NORMAL;
194
195/* Set power thread priority for charging mode or not */
196static inline void charging_set_thread_priority(bool charging)
197{
198#ifdef HAVE_PRIORITY_SCHEDULING
199 thread_set_priority(THREAD_ID_CURRENT,
200 charging ? PRIORITY_REALTIME : PRIORITY_SYSTEM);
201#endif
202 (void)charging;
203}
204
205/* Update filtered charger current - exponential moving average */
206static bool charger_current_filter_step(void)
207{
208 int value = battery_adc_charge_current();
209
210 if (value == ADC_READ_ERROR)
211 return false;
212
213 icharger_ave += value - (icharger_ave / ICHARGER_AVE_SAMPLES);
214 return true;
215}
216
217/* Return true if the main charger is connected. */
218static bool main_charger_connected(void)
219{
220 return (power_status &
221 POWER_INPUT_MAIN_CHARGER &
222 POWER_INPUT_CHARGER) != 0;
223}
224
225/* Return the voltage level which should automatically trigger
226 * another recharge cycle based upon which power source is available.
227 * Assumes at least one is. */
228static unsigned int auto_recharge_voltage(void)
229{
230 if (main_charger_connected())
231 return BATT_VAUTO_RECHARGE;
232 else
233 return BATT_USB_VAUTO_RECHARGE;
234}
235
236#ifndef NO_LOW_BATTERY_SHUTDOWN
237/* Return greater of supply (BP) or filtered battery voltage. */
238static unsigned int input_millivolts(void)
239{
240 unsigned int app_millivolts = application_supply_adc_voltage();
241 unsigned int bat_millivolts = battery_voltage();
242
243 return MAX(app_millivolts, bat_millivolts);
244}
245#endif
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 set_filtered_battery_voltage(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 = ((power_status & 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 = (power_status & 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 charging_set_thread_priority(true);
383
384 /* Turn regulator logically ON. Hardware may still override. */
385 i = mc13783_write_masked(MC13783_CHARGER,
386 charger_setting | MC13783_CHRGRAWPDEN,
387 MC13783_ICHRG | MC13783_VCHRG |
388 MC13783_CHRGRAWPDEN);
389
390 if (i != MC13783_DATA_ERROR)
391 {
392 int icharger;
393
394 /* Enable charge current conversion */
395 adc_enable_channel(ADC_CHARGER_CURRENT, true);
396
397 /* Charge path regulator turn on takes ~100ms max. */
398 sleep(HZ/10);
399
400 icharger = stat_battery_reading(ADC_CHARGER_CURRENT);
401
402 if (icharger != INT_MIN)
403 {
404 icharger_ave = icharger * ICHARGER_AVE_SAMPLES;
405
406 if (update_filtered_battery_voltage())
407 return true;
408 }
409 }
410
411 /* Force regulator OFF. */
412 charge_state = CHARGE_STATE_ERROR;
413 }
414
415 /* Turn regulator OFF. */
416 icharger_ave = 0;
417 i = mc13783_write_masked(MC13783_CHARGER, charger_bits[0][0],
418 MC13783_ICHRG | MC13783_VCHRG |
419 MC13783_CHRGRAWPDEN);
420
421 if (MC13783_DATA_ERROR == i)
422 {
423 /* Failed. Force poweroff by not servicing the watchdog. */
424 service_wdt = false;
425 }
426 else if (0 == charger_setting)
427 {
428 /* Here because OFF was requested state */
429 success = true;
430 }
431
432 charger_setting = 0;
433
434 adc_enable_channel(ADC_CHARGER_CURRENT, false);
435 update_filtered_battery_voltage();
436 charging_set_thread_priority(false);
437
438 return success;
439}
440
441/* Stop the charger - if USB only then the regulator will not really be
442 * turned off. ERROR or DISABLED will turn it off however. */
443static void stop_charger(void)
444{
445 charger_total_timer = 0;
446
447 if (charge_state > DISCHARGING)
448 charge_state = DISCHARGING;
449
450 adjust_charger_current();
451}
452
453/* Return OK if it is acceptable to start the regulator. */
454static bool charging_ok(void)
455{
456 bool ok = charge_state >= DISCHARGING; /* Not an error condition? */
457
458 if (ok)
459 {
460 /* Is the battery even connected? */
461 ok = (power_status & POWER_INPUT_BATTERY) != 0;
462 }
463
464 if (ok)
465 {
466 /* No tolerance for any over/under temp - wait for it to
467 * come back into safe range. */
468 static const signed char temp_ranges[2][2] =
469 {
470 { 0, 45 }, /* Temperature range before beginning charging */
471 { 5, 40 }, /* Temperature range after out-of-range detected */
472 };
473
474 int temp = battery_adc_temp();
475 const signed char *range = temp_ranges[temp_state];
476
477 ok = temp >= range[TEMP_LOW_LIMIT] &&
478 temp <= range[TEMP_HIGH_LIMIT];
479
480 switch (temp_state)
481 {
482 case TEMP_STATE_NORMAL:
483 if (!ok)
484 temp_state = TEMP_STATE_WAIT;
485 break;
486
487 case TEMP_STATE_WAIT:
488 if (ok)
489 temp_state = TEMP_STATE_NORMAL;
490 break;
491
492 default:
493 break;
494 }
495 }
496
497 if (ok)
498 {
499 /* Any events that should stop the regulator? */
500
501 /* Overvoltage at CHRGRAW? */
502 ok = (int_sense0 & MC13783_CHGOVS) == 0;
503
504 if (ok)
505 {
506 /* CHGCURR sensed? */
507 ok = (int_sense0 & MC13783_CHGCURRS) != 0;
508
509 if (!ok)
510 {
511 /* Debounce transient states */
512 if (chgcurr_timer > 0)
513 {
514 chgcurr_timer--;
515 ok = true;
516 }
517 }
518 else
519 {
520 chgcurr_timer = CHGCURR_TIMEOUT;
521 }
522 }
523
524 /* Charger may need to be reinserted */
525 if (!ok)
526 charge_state = CHARGE_STATE_ERROR;
527 }
528
529 if (charger_setting != 0)
530 {
531 if (ok)
532 {
533 /* Watch to not overheat FET (nothing should go over about 1012.7mW).
534 * Trying a higher voltage AC adapter can work (up to 6.90V) but
535 * we'll just reject that. Reducing current for adapters that bring
536 * CHRGRAW to > 4.900V is another possible action. */
537 ok = cccv_regulator_dissipation() < 1150;
538 if (!ok)
539 charge_state = CHARGE_STATE_ERROR;
540 }
541
542 if (!ok)
543 {
544 int state = charge_state;
545
546 if (state > DISCHARGING)
547 state = DISCHARGING;
548
549 /* Force off for all states including maintaining the battery level
550 * on USB. */
551 charge_state = CHARGE_STATE_ERROR;
552 stop_charger();
553 charge_state = state;
554 }
555 }
556
557 return ok;
558}
559
560void powermgmt_init_target(void)
561{
562#ifdef IMX31_ALLOW_CHARGING
563 const uint32_t regval_w =
564 MC13783_VCHRG_4_050V | MC13783_ICHRG_0MA |
565 MC13783_ICHRGTR_0MA | MC13783_OVCTRL_6_90V;
566
567 /* Use watchdog to shut system down if we lose control of the charging
568 * hardware. */
569 watchdog_init(WATCHDOG_TIMEOUT);
570
571 mc13783_write(MC13783_CHARGER, regval_w);
572
573 if (mc13783_read(MC13783_CHARGER) == regval_w)
574 {
575 /* Divide CHRGRAW input by 10 */
576 mc13783_clear(MC13783_ADC0, MC13783_CHRGRAWDIV);
577 /* Turn off BATTDETB. It's worthless on MESx0V since the battery
578 * isn't removable (nor the thermistor). */
579 mc13783_clear(MC13783_POWER_CONTROL0, MC13783_BATTDETEN);
580 }
581 else
582 {
583 /* Register has the wrong value - set error condition and disable
584 * since something is wrong. */
585 charge_state = CHARGE_STATE_DISABLED;
586 stop_charger();
587 }
588#else
589 /* Disable charger use */
590 charge_state = CHARGE_STATE_DISABLED;
591#endif
592}
593
594/* Returns CHARGING or DISCHARGING since that's all we really do. */
595int powermgmt_filter_charge_state(void)
596{
597 switch(charge_state)
598 {
599 case TRICKLE:
600 case TOPOFF:
601 case CHARGING:
602 return CHARGING;
603 default:
604 return DISCHARGING;
605 }
606}
607
608/* Returns true if the unit is charging the batteries. */
609bool charging_state(void)
610{
611 switch (charge_state)
612 {
613 case TRICKLE:
614 case TOPOFF:
615 case CHARGING:
616 return true;
617 default:
618 return false;
619 }
620}
621
622/* Filtered battery charge current */
623int battery_charge_current(void)
624{
625 return icharger_ave / ICHARGER_AVE_SAMPLES;
626}
627
628bool query_force_shutdown(void)
629{
630#ifndef NO_LOW_BATTERY_SHUTDOWN
631 return input_millivolts() < battery_level_shutoff[0];
632#else
633 return false;
634#endif
635}
636
637bool battery_level_safe(void)
638{
639#ifndef NO_LOW_BATTERY_SHUTDOWN
640 return input_millivolts() > battery_level_dangerous[0];
641#else
642 return true;
643#endif
644}
645
646static void charger_plugged(void)
647{
648 adc_enable_channel(ADC_BATTERY_TEMP, true);
649 autorecharge_counter = -1;
650}
651
652static void charger_unplugged(void)
653{
654 /* Charger pulled - turn off current sources (though hardware
655 * will have done that anyway). */
656 if (charge_state > CHARGE_STATE_DISABLED)
657 {
658 /* Reset state and clear any error. If disabled, the charger
659 * will not have been started or will have been stopped already. */
660 stop_charger();
661 charge_state = DISCHARGING;
662 }
663
664 /* Might need to reevaluate these bits in charger_none. */
665 power_status &= ~(POWER_INPUT | POWER_INPUT_CHARGER);
666 temp_state = TEMP_STATE_NORMAL;
667 autorecharge_counter = 0;
668 chgcurr_timer = 0;
669
670 adc_enable_channel(ADC_BATTERY_TEMP, false);
671}
672
673static void charger_none(void)
674{
675 unsigned int pwr = power_input_status();
676
677 if (power_status != pwr)
678 {
679 /* If battery switch state changed, reset filter. */
680 if ((power_status ^ pwr) & POWER_INPUT_BATTERY)
681 update_filtered_battery_voltage();
682
683 power_status = pwr;
684
685 if (charge_state == CHARGE_STATE_DISABLED)
686 return;
687
688 if ((pwr & (POWER_INPUT | POWER_INPUT_CHARGER)) == POWER_INPUT_USB)
689 {
690 /* USB connected but not configured. Maintain battery to the
691 * greatest degree possible. It probably won't be enough but the
692 * discharge won't be so severe. */
693 charger_plugged();
694 charger_setting = CHARGER_ADJUST;
695 }
696 else
697 {
698 charger_unplugged();
699 power_status = pwr; /* Restore status */
700 }
701 }
702 else if (charger_setting != 0)
703 {
704 /* Maintaining - keep filter going and check charge state */
705 int_sense0 = mc13783_read(MC13783_INTERRUPT_SENSE0);
706
707 if (!charger_current_filter_step())
708 {
709 /* Failed to read current */
710 charge_state = CHARGE_STATE_ERROR;
711 }
712
713 charging_ok();
714 }
715}
716
717static void charger_control(void)
718{
719 unsigned int pwr = power_input_status();
720
721 if (power_status != pwr)
722 {
723 unsigned int changed = power_status ^ pwr;
724
725 power_status = pwr;
726
727 /* If battery switch state changed, reset filter. */
728 if (changed & POWER_INPUT_BATTERY)
729 update_filtered_battery_voltage();
730
731 if (charger_setting != 0)
732 charger_setting = CHARGER_ADJUST;
733
734 if (charge_state == DISCHARGING)
735 {
736 if (main_charger_connected())
737 {
738 /* If main is connected, ignore USB plugs. */
739 if (changed & POWER_INPUT_MAIN_CHARGER)
740 {
741 /* Main charger plugged - try charge */
742 autorecharge_counter = -1;
743 }
744 }
745 else if (pwr & POWER_INPUT_USB_CHARGER
746 & POWER_INPUT_CHARGER)
747 {
748 if (changed & POWER_INPUT_USB_CHARGER)
749 {
750 /* USB charger plugged - try charge */
751 autorecharge_counter = -1;
752 }
753 }
754 }
755 }
756
757 if (charger_setting != 0 && !charger_current_filter_step())
758 {
759 /* Failed to read current */
760 charge_state = CHARGE_STATE_ERROR;
761 }
762
763 int_sense0 = mc13783_read(MC13783_INTERRUPT_SENSE0);
764
765 if (!charging_ok())
766 return;
767
768 switch (charge_state)
769 {
770 case DISCHARGING:
771 {
772 /* Battery voltage may have dropped and a charge cycle should
773 * start again. Debounced. */
774 if (autorecharge_counter < 0)
775 {
776 /* Try starting a cycle now regardless of battery level to
777 * allow user to ensure the battery is topped off. It
778 * will soon turn off if already full. */
779 autorecharge_counter = 0;
780 }
781 else if (battery_voltage() > auto_recharge_voltage())
782 {
783 /* Still above threshold - reset counter */
784 autorecharge_counter = AUTORECHARGE_COUNTDOWN;
785 break;
786 }
787 else if (autorecharge_counter > 0)
788 {
789 /* Coundown to restart */
790 autorecharge_counter--;
791 break;
792 }
793
794 charging_set_thread_priority(true);
795
796 if (stat_battery_reading(ADC_BATTERY) < BATT_VTRICKLE_CHARGE)
797 {
798 /* Battery is deeply discharged - precharge at lower current. */
799 charge_state = TRICKLE;
800 }
801 else
802 {
803 /* Ok for fast charge */
804 charge_state = CHARGING;
805 }
806
807 charger_setting = CHARGER_ADJUST;
808 charger_total_timer = CHARGER_TOTAL_TIMER*60*2;
809 break;
810 } /* DISCHARGING: */
811
812 case TRICKLE: /* Very low - precharge */
813 {
814 if (battery_voltage() <= BATT_VTRICKLE_CHARGE)
815 break;
816
817 /* Switch to normal charge mode. */
818 charge_state = CHARGING;
819 charger_setting = CHARGER_ADJUST;
820 break;
821 } /* TRICKLE: */
822
823 case CHARGING: /* Constant-current stage */
824 case TOPOFF: /* Constant-voltage stage */
825 {
826 /* Reg. mode is more informative than an operational necessity. */
827 charge_state = (int_sense0 & MC13783_CCCVS) ? TOPOFF : CHARGING;
828
829 if (main_charger_connected())
830 {
831 /* Monitor and stop if current drops below threshold. */
832 if (battery_charge_current() > BATTERY_ICHARGE_COMPLETE)
833 break;
834 }
835 else
836 {
837 /* Accurate I-level can't be determined since device also
838 * powers through the I sense. This simply stops the reporting
839 * of charging but the regulator remains on. */
840 if (battery_voltage() <= BATT_USB_VSTOP)
841 break;
842 }
843
844 stop_charger();
845 break;
846 } /* CHARGING: TOPOFF: */
847
848 default:
849 break;
850 } /* switch */
851
852 /* Check if charger timer expired and stop it if so. */
853 if (charger_total_timer > 0 && --charger_total_timer == 0)
854 {
855 charge_state = CHARGE_STATE_ERROR;
856 stop_charger(); /* Time ran out - error */
857 }
858}
859
860/* Main charging algorithm - called from powermgmt.c */
861void charging_algorithm_small_step(void)
862{
863 if (service_wdt)
864 watchdog_service();
865
866 /* Switch by input state */
867 switch (charger_input_state)
868 {
869 case NO_CHARGER:
870 charger_none();
871 break;
872
873 case CHARGER_PLUGGED:
874 charger_plugged();
875 break;
876
877 case CHARGER:
878 charger_control();
879 break;
880
881 case CHARGER_UNPLUGGED:
882 charger_unplugged();
883 break;
884 } /* switch */
885
886 if (charger_close)
887 {
888 if (charge_state != CHARGE_STATE_DISABLED)
889 {
890 /* Disable starts while shutting down */
891 charge_state = CHARGE_STATE_DISABLED;
892 stop_charger();
893 }
894
895 charger_close = false;
896 return;
897 }
898
899 if (charger_setting != 0)
900 {
901 if ((mc13783_read(MC13783_CHARGER) & (MC13783_ICHRG | MC13783_VCHRG)) !=
902 charger_setting)
903 {
904 /* The hardware setting doesn't match. It could have turned the
905 * charger off in a race of plugging/unplugging or the setting
906 * was changed in one of the calls. */
907 adjust_charger_current();
908 }
909 }
910}
911
912void charging_algorithm_big_step(void)
913{
914 /* Sleep for one minute */
915 power_thread_sleep(HZ*60);
916}
917
918/* Disable the charger and prepare for poweroff - called off-thread so we
919 * signal the charging thread to prepare to quit. */
920void charging_algorithm_close(void)
921{
922 charger_close = true;
923
924 /* Power management thread will set it false again */
925 while (charger_close)
926 sleep(HZ/10);
927}
928
929#ifdef BOOTLOADER
930void sys_poweroff(void)
931{
126} 932}
933#endif /* BOOTLOADER */