diff options
-rw-r--r-- | apps/debug_menu.c | 84 | ||||
-rw-r--r-- | firmware/export/config-gigabeat-s.h | 12 | ||||
-rw-r--r-- | firmware/export/config.h | 2 | ||||
-rw-r--r-- | firmware/export/powermgmt.h | 48 | ||||
-rw-r--r-- | firmware/export/usb.h | 3 | ||||
-rw-r--r-- | firmware/powermgmt.c | 130 | ||||
-rw-r--r-- | firmware/target/arm/imx31/debug-imx31.c | 2 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/adc-imx31.c | 30 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/adc-target.h | 9 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/mc13783-gigabeat-s.c | 25 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/mc13783-target.h | 4 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/power-imx31.c | 51 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/power-imx31.h | 3 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/powermgmt-imx31.c | 883 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/powermgmt-target.h | 114 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/system-imx31.c | 25 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/system-target.h | 5 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/usb-imx31.c | 10 |
18 files changed, 1300 insertions, 140 deletions
diff --git a/apps/debug_menu.c b/apps/debug_menu.c index 0db0e5a471..beee39a09b 100644 --- a/apps/debug_menu.c +++ b/apps/debug_menu.c | |||
@@ -1649,15 +1649,87 @@ static bool view_battery(void) | |||
1649 | charger_inserted() ? "present" : "absent"); | 1649 | charger_inserted() ? "present" : "absent"); |
1650 | lcd_puts(0, 3, buf); | 1650 | lcd_puts(0, 3, buf); |
1651 | #if defined TOSHIBA_GIGABEAT_S | 1651 | #if defined TOSHIBA_GIGABEAT_S |
1652 | int line = 4; | ||
1653 | unsigned int st; | ||
1654 | |||
1655 | static const unsigned char * const chrgstate_strings[] = | ||
1656 | { | ||
1657 | "Disabled", | ||
1658 | "Error", | ||
1659 | "Discharging", | ||
1660 | "Precharge", | ||
1661 | "Constant Voltage", | ||
1662 | "Constant Current", | ||
1663 | "<unknown>", | ||
1664 | }; | ||
1665 | |||
1666 | st = power_input_status() & | ||
1667 | (POWER_INPUT_CHARGER | POWER_INPUT_BATTERY); | ||
1668 | snprintf(buf, 30, "%s%s", | ||
1669 | (st & POWER_INPUT_MAIN_CHARGER) ? " Main" : "", | ||
1670 | (st & POWER_INPUT_USB_CHARGER) ? " USB" : ""); | ||
1671 | lcd_puts(0, line++, buf); | ||
1672 | |||
1673 | snprintf(buf, 30, "IUSB Max: %d", usb_allowed_current()); | ||
1674 | lcd_puts(0, line++, buf); | ||
1675 | |||
1676 | y = ARRAYLEN(chrgstate_strings) - 1; | ||
1677 | |||
1678 | switch (charge_state) | ||
1679 | { | ||
1680 | case CHARGE_STATE_DISABLED: y--; | ||
1681 | case CHARGE_STATE_ERROR: y--; | ||
1682 | case DISCHARGING: y--; | ||
1683 | case TRICKLE: y--; | ||
1684 | case TOPOFF: y--; | ||
1685 | case CHARGING: y--; | ||
1686 | default:; | ||
1687 | } | ||
1688 | |||
1689 | snprintf(buf, 30, "State: %s", chrgstate_strings[y]); | ||
1690 | lcd_puts(0, line++, buf); | ||
1691 | |||
1692 | snprintf(buf, 30, "Battery Switch: %s", | ||
1693 | (st & POWER_INPUT_BATTERY) ? "On" : "Off"); | ||
1694 | lcd_puts(0, line++, buf); | ||
1695 | |||
1696 | y = chrgraw_adc_voltage(); | ||
1697 | snprintf(buf, 30, "CHRGRAW: %d.%03d V", | ||
1698 | y / 1000, y % 1000); | ||
1699 | lcd_puts(0, line++, buf); | ||
1700 | |||
1701 | y = application_supply_adc_voltage(); | ||
1702 | snprintf(buf, 30, "BP : %d.%03d V", | ||
1703 | y / 1000, y % 1000); | ||
1704 | lcd_puts(0, line++, buf); | ||
1705 | |||
1652 | y = battery_adc_charge_current(); | 1706 | y = battery_adc_charge_current(); |
1653 | x = y < 0 ? '-' : ' '; | 1707 | if (y < 0) x = '-', y = -y; |
1654 | y = abs(y); | 1708 | else x = ' '; |
1655 | snprintf(buf, 30, "I Charge:%c%d.%03d A", (char)x, y / 1000, y % 1000); | 1709 | snprintf(buf, 30, "CHRGISN:%c%d mA", x, y); |
1656 | lcd_puts(0, 4, buf); | 1710 | lcd_puts(0, line++, buf); |
1711 | |||
1712 | y = cccv_regulator_dissipation(); | ||
1713 | snprintf(buf, 30, "P CCCV : %d mW", y); | ||
1714 | lcd_puts(0, line++, buf); | ||
1715 | |||
1716 | y = battery_charge_current(); | ||
1717 | if (y < 0) x = '-', y = -y; | ||
1718 | else x = ' '; | ||
1719 | snprintf(buf, 30, "I Charge:%c%d mA", x, y); | ||
1720 | lcd_puts(0, line++, buf); | ||
1657 | 1721 | ||
1658 | y = battery_adc_temp(); | 1722 | y = battery_adc_temp(); |
1659 | snprintf(buf, 30, "T Battery: %dC (%dF)", y, (9*y + 160) / 5); | 1723 | |
1660 | lcd_puts(0, 5, buf); | 1724 | if (y != INT_MIN) { |
1725 | snprintf(buf, 30, "T Battery: %dC (%dF)", y, | ||
1726 | (9*y + 160) / 5); | ||
1727 | } else { | ||
1728 | /* Conversion disabled */ | ||
1729 | snprintf(buf, 30, "T Battery: ?"); | ||
1730 | } | ||
1731 | |||
1732 | lcd_puts(0, line++, buf); | ||
1661 | #endif /* defined TOSHIBA_GIGABEAT_S */ | 1733 | #endif /* defined TOSHIBA_GIGABEAT_S */ |
1662 | #endif /* defined IPOD_NANO || defined IPOD_VIDEO */ | 1734 | #endif /* defined IPOD_NANO || defined IPOD_VIDEO */ |
1663 | #endif /* CONFIG_CHARGING != CHARGING_CONTROL */ | 1735 | #endif /* CONFIG_CHARGING != CHARGING_CONTROL */ |
diff --git a/firmware/export/config-gigabeat-s.h b/firmware/export/config-gigabeat-s.h index 54a3de2d19..b4c30268ba 100644 --- a/firmware/export/config-gigabeat-s.h +++ b/firmware/export/config-gigabeat-s.h | |||
@@ -2,7 +2,6 @@ | |||
2 | * This config file is for toshiba Gigabeat S | 2 | * This config file is for toshiba Gigabeat S |
3 | */ | 3 | */ |
4 | 4 | ||
5 | #define NO_LOW_BATTERY_SHUTDOWN | ||
6 | #define TARGET_TREE /* this target is using the target tree system */ | 5 | #define TARGET_TREE /* this target is using the target tree system */ |
7 | 6 | ||
8 | #define TOSHIBA_GIGABEAT_S 1 | 7 | #define TOSHIBA_GIGABEAT_S 1 |
@@ -132,8 +131,10 @@ | |||
132 | #define BATTERY_CAPACITY_INC 25 /* capacity increment */ | 131 | #define BATTERY_CAPACITY_INC 25 /* capacity increment */ |
133 | #define BATTERY_TYPES_COUNT 1 /* only one type */ | 132 | #define BATTERY_TYPES_COUNT 1 /* only one type */ |
134 | 133 | ||
135 | /* Hardware controlled charging with monitoring */ | 134 | /* TODO: have a proper status displayed in the bootloader and have it |
136 | #define CONFIG_CHARGING CHARGING_MONITOR | 135 | * work! */ |
136 | /* Charing implemented in a target-specific algorithm */ | ||
137 | #define CONFIG_CHARGING CHARGING_TARGET | ||
137 | 138 | ||
138 | /* define this if the hardware can be powered off while charging */ | 139 | /* define this if the hardware can be powered off while charging */ |
139 | #define HAVE_POWEROFF_WHILE_CHARGING | 140 | #define HAVE_POWEROFF_WHILE_CHARGING |
@@ -146,8 +147,9 @@ | |||
146 | #define CPU_FREQ 264000000 /* Set by retailOS loader */ | 147 | #define CPU_FREQ 264000000 /* Set by retailOS loader */ |
147 | 148 | ||
148 | /* define this if the unit can be powered or charged via USB */ | 149 | /* define this if the unit can be powered or charged via USB */ |
149 | //#define HAVE_USB_POWER /* Disable for now */ | 150 | #define HAVE_USB_POWER |
150 | //#define HAVE_USB_CHARGING_ENABLE | 151 | #define USBPOWER_BUTTON BUTTON_MENU |
152 | #define USBPOWER_BTN_IGNORE BUTTON_POWER | ||
151 | 153 | ||
152 | /* define this if the unit has a battery switch or battery can be removed | 154 | /* define this if the unit has a battery switch or battery can be removed |
153 | * when running */ | 155 | * when running */ |
diff --git a/firmware/export/config.h b/firmware/export/config.h index 75aa76a898..d484805532 100644 --- a/firmware/export/config.h +++ b/firmware/export/config.h | |||
@@ -117,6 +117,8 @@ | |||
117 | #define CHARGING_SIMPLE 1 /* Simple, hardware controlled charging */ | 117 | #define CHARGING_SIMPLE 1 /* Simple, hardware controlled charging */ |
118 | #define CHARGING_MONITOR 2 /* Hardware controlled charging with monitoring */ | 118 | #define CHARGING_MONITOR 2 /* Hardware controlled charging with monitoring */ |
119 | #define CHARGING_CONTROL 3 /* Software controlled charging */ | 119 | #define CHARGING_CONTROL 3 /* Software controlled charging */ |
120 | #define CHARGING_TARGET 4 /* Anything the target implements that is not | ||
121 | a generic implementation */ | ||
120 | 122 | ||
121 | /* CONFIG_LCD */ | 123 | /* CONFIG_LCD */ |
122 | #define LCD_SSD1815 1 /* as used by Archos Recorders and Ondios */ | 124 | #define LCD_SSD1815 1 /* as used by Archos Recorders and Ondios */ |
diff --git a/firmware/export/powermgmt.h b/firmware/export/powermgmt.h index 70c4b70d7a..c333795ad7 100644 --- a/firmware/export/powermgmt.h +++ b/firmware/export/powermgmt.h | |||
@@ -30,17 +30,26 @@ | |||
30 | #define CHARGE_END_LONGD 50 /* stop when N minutes have passed with | 30 | #define CHARGE_END_LONGD 50 /* stop when N minutes have passed with |
31 | * avg delta being < -0.02 V */ | 31 | * avg delta being < -0.02 V */ |
32 | 32 | ||
33 | #if CONFIG_CHARGING >= CHARGING_MONITOR | ||
34 | typedef enum { /* sorted by increasing charging current */ | 33 | typedef enum { /* sorted by increasing charging current */ |
34 | #if CONFIG_CHARGING >= CHARGING_MONITOR | ||
35 | CHARGE_STATE_DISABLED = -2, /* Disable charger use */ | ||
36 | CHARGE_STATE_ERROR = -1, /* Some error occurred that should not allow | ||
37 | further attempts without user intervention */ | ||
38 | #endif | ||
35 | DISCHARGING = 0, | 39 | DISCHARGING = 0, |
40 | #if CONFIG_CHARGING >= CHARGING_MONITOR | ||
36 | TRICKLE, /* Can occur for CONFIG_CHARGING >= CHARGING_MONITOR */ | 41 | TRICKLE, /* Can occur for CONFIG_CHARGING >= CHARGING_MONITOR */ |
42 | /* For LiIon, the low-current precharge mode if battery | ||
43 | was very low */ | ||
37 | TOPOFF, /* Can occur for CONFIG_CHARGING == CHARGING_CONTROL */ | 44 | TOPOFF, /* Can occur for CONFIG_CHARGING == CHARGING_CONTROL */ |
38 | CHARGING /* Can occur for all CONFIG_CHARGING options */ | 45 | /* For LiIon, constant voltage phase */ |
46 | CHARGING, /* Can occur for all CONFIG_CHARGING options */ | ||
47 | /* For LiIon, the constant current phase */ | ||
48 | #endif | ||
39 | } charge_state_type; | 49 | } charge_state_type; |
40 | 50 | ||
41 | /* tells what the charger is doing */ | 51 | /* tells what the charger is doing */ |
42 | extern charge_state_type charge_state; | 52 | extern charge_state_type charge_state; |
43 | #endif /* CONFIG_CHARGING >= CHARGING_MONITOR */ | ||
44 | 53 | ||
45 | #ifdef CONFIG_CHARGING | 54 | #ifdef CONFIG_CHARGING |
46 | /* | 55 | /* |
@@ -48,10 +57,10 @@ extern charge_state_type charge_state; | |||
48 | * one time through the power loop when the charger has been plugged in. | 57 | * one time through the power loop when the charger has been plugged in. |
49 | */ | 58 | */ |
50 | typedef enum { | 59 | typedef enum { |
51 | NO_CHARGER, | 60 | NO_CHARGER = 0, /* No charger is present */ |
52 | CHARGER_UNPLUGGED, /* transient state */ | 61 | CHARGER_UNPLUGGED, /* Transitional state during CHARGER=>NO_CHARGER */ |
53 | CHARGER_PLUGGED, /* transient state */ | 62 | CHARGER_PLUGGED, /* Transitional state during NO_CHARGER=>CHARGER */ |
54 | CHARGER | 63 | CHARGER /* Charger is present */ |
55 | } charger_input_state_type; | 64 | } charger_input_state_type; |
56 | 65 | ||
57 | /* tells the state of the charge input */ | 66 | /* tells the state of the charge input */ |
@@ -154,6 +163,11 @@ extern int trickle_sec; /* trickle charge: How many seconds per minute | |||
154 | # define MAX_CHG_V 10250 /* anything over 10.25v gives CURRENT_MAX_CHG */ | 163 | # define MAX_CHG_V 10250 /* anything over 10.25v gives CURRENT_MAX_CHG */ |
155 | #endif /* not ONDIO */ | 164 | #endif /* not ONDIO */ |
156 | 165 | ||
166 | #if CONFIG_CHARGING == CHARGING_TARGET | ||
167 | /* Include target-specific definitions */ | ||
168 | #include "powermgmt-target.h" | ||
169 | #endif | ||
170 | |||
157 | extern unsigned short power_history[POWER_HISTORY_LEN]; | 171 | extern unsigned short power_history[POWER_HISTORY_LEN]; |
158 | extern const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT]; | 172 | extern const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT]; |
159 | extern const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT]; | 173 | extern const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT]; |
@@ -165,6 +179,12 @@ extern const unsigned short percent_to_volt_charge[11]; | |||
165 | /* Start up power management thread */ | 179 | /* Start up power management thread */ |
166 | void powermgmt_init(void); | 180 | void powermgmt_init(void); |
167 | 181 | ||
182 | /* Do target portion of init (for CHARGING_TARGET) - called on power thread */ | ||
183 | void powermgmt_init_target(void); | ||
184 | |||
185 | /* Handle frequent tasks and call charging_algorithm_small_step */ | ||
186 | void power_thread_sleep(int ticks); | ||
187 | |||
168 | #endif /* SIMULATOR */ | 188 | #endif /* SIMULATOR */ |
169 | 189 | ||
170 | /* Returns battery statust */ | 190 | /* Returns battery statust */ |
@@ -173,12 +193,20 @@ int battery_time(void); /* minutes */ | |||
173 | unsigned int battery_adc_voltage(void); /* voltage from ADC in millivolts */ | 193 | unsigned int battery_adc_voltage(void); /* voltage from ADC in millivolts */ |
174 | unsigned int battery_voltage(void); /* filtered batt. voltage in millivolts */ | 194 | unsigned int battery_voltage(void); /* filtered batt. voltage in millivolts */ |
175 | 195 | ||
196 | /* Set the filtered battery voltage (to adjust it before beginning a charge | ||
197 | cycle for instance where old, loaded readings will likely be invalid). */ | ||
198 | void set_filtered_battery_voltage(int millivolts); | ||
199 | |||
176 | /* read unfiltered battery info */ | 200 | /* read unfiltered battery info */ |
177 | void battery_read_info(int *voltage, int *level); | 201 | void battery_read_info(int *voltage, int *level); |
178 | 202 | ||
179 | /* Tells if the battery level is safe for disk writes */ | 203 | /* Tells if the battery level is safe for disk writes */ |
180 | bool battery_level_safe(void); | 204 | bool battery_level_safe(void); |
181 | 205 | ||
206 | #ifdef TARGET_POWERMGMT_FILTER_CHARGE_STATE | ||
207 | int powermgmt_filter_charge_state(void); | ||
208 | #endif | ||
209 | |||
182 | void set_poweroff_timeout(int timeout); | 210 | void set_poweroff_timeout(int timeout); |
183 | void set_battery_capacity(int capacity); /* set local battery capacity value */ | 211 | void set_battery_capacity(int capacity); /* set local battery capacity value */ |
184 | void set_battery_type(int type); /* set local battery type */ | 212 | void set_battery_type(int type); /* set local battery type */ |
@@ -190,7 +218,11 @@ void reset_poweroff_timer(void); | |||
190 | void cancel_shutdown(void); | 218 | void cancel_shutdown(void); |
191 | void shutdown_hw(void); | 219 | void shutdown_hw(void); |
192 | void sys_poweroff(void); | 220 | void sys_poweroff(void); |
221 | /* Returns true if the system should force shutdown for some reason - | ||
222 | * eg. low battery */ | ||
223 | bool query_force_shutdown(void); | ||
193 | #ifdef HAVE_ACCESSORY_SUPPLY | 224 | #ifdef HAVE_ACCESSORY_SUPPLY |
194 | void accessory_supply_set(bool); | 225 | void accessory_supply_set(bool); |
195 | #endif | 226 | #endif |
196 | #endif | 227 | |
228 | #endif /* _POWERMGMT_H_ */ | ||
diff --git a/firmware/export/usb.h b/firmware/export/usb.h index 00517b2475..c8bbf28267 100644 --- a/firmware/export/usb.h +++ b/firmware/export/usb.h | |||
@@ -54,9 +54,6 @@ enum { | |||
54 | #elif CONFIG_KEYPAD == GIGABEAT_PAD | 54 | #elif CONFIG_KEYPAD == GIGABEAT_PAD |
55 | #define USBPOWER_BUTTON BUTTON_MENU | 55 | #define USBPOWER_BUTTON BUTTON_MENU |
56 | #define USBPOWER_BTN_IGNORE BUTTON_POWER | 56 | #define USBPOWER_BTN_IGNORE BUTTON_POWER |
57 | #elif CONFIG_KEYPAD == GIGABEAT_S_PAD | ||
58 | #define USBPOWER_BUTTON BUTTON_MENU | ||
59 | #define USBPOWER_BTN_IGNORE BUTTON_BACK | ||
60 | #elif (CONFIG_KEYPAD == IRIVER_H10_PAD) || \ | 57 | #elif (CONFIG_KEYPAD == IRIVER_H10_PAD) || \ |
61 | (CONFIG_KEYPAD == MROBE100_PAD) | 58 | (CONFIG_KEYPAD == MROBE100_PAD) |
62 | #define USBPOWER_BUTTON BUTTON_RIGHT | 59 | #define USBPOWER_BUTTON BUTTON_RIGHT |
diff --git a/firmware/powermgmt.c b/firmware/powermgmt.c index a1f7ed9836..00b7b2fd4f 100644 --- a/firmware/powermgmt.c +++ b/firmware/powermgmt.c | |||
@@ -76,7 +76,7 @@ static int wrcount = 0; | |||
76 | 76 | ||
77 | static int shutdown_timeout = 0; | 77 | static int shutdown_timeout = 0; |
78 | #if CONFIG_CHARGING >= CHARGING_MONITOR | 78 | #if CONFIG_CHARGING >= CHARGING_MONITOR |
79 | charge_state_type charge_state; /* charging mode */ | 79 | charge_state_type charge_state = DISCHARGING; /* charging mode */ |
80 | #endif | 80 | #endif |
81 | 81 | ||
82 | static void send_battery_level_event(void); | 82 | static void send_battery_level_event(void); |
@@ -204,8 +204,6 @@ void accessory_supply_set(bool enable) | |||
204 | 204 | ||
205 | #else /* not SIMULATOR ******************************************************/ | 205 | #else /* not SIMULATOR ******************************************************/ |
206 | 206 | ||
207 | static void power_thread_sleep(int ticks); | ||
208 | |||
209 | /* | 207 | /* |
210 | * Average battery voltage and charger voltage, filtered via a digital | 208 | * Average battery voltage and charger voltage, filtered via a digital |
211 | * exponential filter (aka. exponential moving average, scaled): | 209 | * exponential filter (aka. exponential moving average, scaled): |
@@ -241,6 +239,19 @@ static int voltage_to_battery_level(int battery_millivolts); | |||
241 | static void battery_status_update(void); | 239 | static void battery_status_update(void); |
242 | static int runcurrent(void); | 240 | static int runcurrent(void); |
243 | 241 | ||
242 | #ifndef TARGET_POWERMGMT_FILTER_CHARGE_STATE | ||
243 | static inline int powermgmt_filter_charge_state(void) | ||
244 | { | ||
245 | #if CONFIG_CHARGING >= CHARGING_MONITOR | ||
246 | /* No adjustment of state */ | ||
247 | return charge_state; | ||
248 | #else | ||
249 | /* Always discharging */ | ||
250 | return DISCHARGING; | ||
251 | #endif | ||
252 | } | ||
253 | #endif /* TARGET_POWERMGMT_FILTER_CHARGE_STATE */ | ||
254 | |||
244 | void battery_read_info(int *voltage, int *level) | 255 | void battery_read_info(int *voltage, int *level) |
245 | { | 256 | { |
246 | int millivolts = battery_adc_voltage(); | 257 | int millivolts = battery_adc_voltage(); |
@@ -285,6 +296,10 @@ int battery_time(void) | |||
285 | /* Returns battery level in percent */ | 296 | /* Returns battery level in percent */ |
286 | int battery_level(void) | 297 | int battery_level(void) |
287 | { | 298 | { |
299 | #ifdef HAVE_BATTERY_SWITCH | ||
300 | if ((power_input_status() & POWER_INPUT_BATTERY) == 0) | ||
301 | return -1; | ||
302 | #endif | ||
288 | return battery_percent; | 303 | return battery_percent; |
289 | } | 304 | } |
290 | 305 | ||
@@ -294,11 +309,13 @@ unsigned int battery_voltage(void) | |||
294 | return battery_millivolts; | 309 | return battery_millivolts; |
295 | } | 310 | } |
296 | 311 | ||
312 | #ifndef TARGET_BATTERY_LEVEL_SAFE | ||
297 | /* Tells if the battery level is safe for disk writes */ | 313 | /* Tells if the battery level is safe for disk writes */ |
298 | bool battery_level_safe(void) | 314 | bool battery_level_safe(void) |
299 | { | 315 | { |
300 | return battery_millivolts > battery_level_dangerous[battery_type]; | 316 | return battery_millivolts > battery_level_dangerous[battery_type]; |
301 | } | 317 | } |
318 | #endif | ||
302 | 319 | ||
303 | void set_poweroff_timeout(int timeout) | 320 | void set_poweroff_timeout(int timeout) |
304 | { | 321 | { |
@@ -349,26 +366,24 @@ static int voltage_to_percent(int voltage, const short* table) | |||
349 | * when battery capacity / type settings are changed */ | 366 | * when battery capacity / type settings are changed */ |
350 | static int voltage_to_battery_level(int battery_millivolts) | 367 | static int voltage_to_battery_level(int battery_millivolts) |
351 | { | 368 | { |
369 | const int state = powermgmt_filter_charge_state(); | ||
352 | int level; | 370 | int level; |
353 | 371 | ||
354 | #if CONFIG_CHARGING >= CHARGING_MONITOR | 372 | if (state == DISCHARGING) { |
355 | if (charge_state == DISCHARGING) { | ||
356 | level = voltage_to_percent(battery_millivolts, | 373 | level = voltage_to_percent(battery_millivolts, |
357 | percent_to_volt_discharge[battery_type]); | 374 | percent_to_volt_discharge[battery_type]); |
358 | } | 375 | } |
359 | else if (charge_state == CHARGING) { | 376 | #if CONFIG_CHARGING >= CHARGING_MONITOR |
377 | else if (state == CHARGING) { | ||
360 | /* battery level is defined to be < 100% until charging is finished */ | 378 | /* battery level is defined to be < 100% until charging is finished */ |
361 | level = MIN(voltage_to_percent(battery_millivolts, | 379 | level = MIN(voltage_to_percent(battery_millivolts, |
362 | percent_to_volt_charge), 99); | 380 | percent_to_volt_charge), 99); |
363 | } | 381 | } |
364 | else { /* in topoff/trickle charge, battery is by definition 100% full */ | 382 | else { |
383 | /* in topoff/trickle charge, battery is by definition 100% full */ | ||
365 | level = 100; | 384 | level = 100; |
366 | } | 385 | } |
367 | #else | 386 | #endif |
368 | /* always use the discharge table */ | ||
369 | level = voltage_to_percent(battery_millivolts, | ||
370 | percent_to_volt_discharge[battery_type]); | ||
371 | #endif /* CONFIG_CHARGING ... */ | ||
372 | 387 | ||
373 | return level; | 388 | return level; |
374 | } | 389 | } |
@@ -381,7 +396,7 @@ static void battery_status_update(void) | |||
381 | /* discharging: remaining running time */ | 396 | /* discharging: remaining running time */ |
382 | /* charging: remaining charging time */ | 397 | /* charging: remaining charging time */ |
383 | #if CONFIG_CHARGING >= CHARGING_MONITOR | 398 | #if CONFIG_CHARGING >= CHARGING_MONITOR |
384 | if (charge_state == CHARGING) { | 399 | if (powermgmt_filter_charge_state() == CHARGING) { |
385 | powermgmt_est_runningtime_min = (100 - level) * battery_capacity * 60 | 400 | powermgmt_est_runningtime_min = (100 - level) * battery_capacity * 60 |
386 | / 100 / (CURRENT_MAX_CHG - runcurrent()); | 401 | / 100 / (CURRENT_MAX_CHG - runcurrent()); |
387 | } | 402 | } |
@@ -431,15 +446,10 @@ static void handle_auto_poweroff(void) | |||
431 | } | 446 | } |
432 | #endif | 447 | #endif |
433 | 448 | ||
434 | #ifndef NO_LOW_BATTERY_SHUTDOWN | 449 | if( !shutdown_timeout && query_force_shutdown()) { |
435 | /* switch off unit if battery level is too low for reliable operation */ | 450 | backlight_on(); |
436 | if(battery_millivolts < battery_level_shutoff[battery_type]) { | 451 | sys_poweroff(); |
437 | if(!shutdown_timeout) { | ||
438 | backlight_on(); | ||
439 | sys_poweroff(); | ||
440 | } | ||
441 | } | 452 | } |
442 | #endif | ||
443 | 453 | ||
444 | if(timeout && | 454 | if(timeout && |
445 | #if CONFIG_TUNER && !defined(BOOTLOADER) | 455 | #if CONFIG_TUNER && !defined(BOOTLOADER) |
@@ -546,6 +556,18 @@ static void power_thread_rtc_process(void) | |||
546 | } | 556 | } |
547 | #endif | 557 | #endif |
548 | 558 | ||
559 | #ifndef TARGET_QUERY_FORCE_SHUTDOWN | ||
560 | bool query_force_shutdown(void) | ||
561 | { | ||
562 | #ifndef NO_LOW_BATTERY_SHUTDOWN | ||
563 | /* switch off unit if battery level is too low for reliable operation */ | ||
564 | return battery_millivolts < battery_level_shutoff[battery_type]; | ||
565 | #else | ||
566 | return false; | ||
567 | #endif | ||
568 | } | ||
569 | #endif /* TARGET_QUERY_FORCE_SHUTDOWN */ | ||
570 | |||
549 | /* | 571 | /* |
550 | * This power thread maintains a history of battery voltage | 572 | * This power thread maintains a history of battery voltage |
551 | * and implements a charging algorithm. | 573 | * and implements a charging algorithm. |
@@ -896,6 +918,18 @@ static inline void charging_algorithm_close(void) | |||
896 | } | 918 | } |
897 | #endif | 919 | #endif |
898 | } | 920 | } |
921 | #elif CONFIG_CHARGING == CHARGING_TARGET | ||
922 | extern void charging_algorithm_big_step(void); | ||
923 | extern void charging_algorithm_small_step(void); | ||
924 | extern void charging_algorithm_close(void); | ||
925 | |||
926 | void set_filtered_battery_voltage(int millivolts) | ||
927 | { | ||
928 | avgbat = millivolts * BATT_AVE_SAMPLES; | ||
929 | battery_millivolts = millivolts; | ||
930 | battery_status_update(); | ||
931 | } | ||
932 | |||
899 | #else | 933 | #else |
900 | #define BATT_AVE_SAMPLES 128 /* slw filter constant for all others */ | 934 | #define BATT_AVE_SAMPLES 128 /* slw filter constant for all others */ |
901 | 935 | ||
@@ -961,12 +995,12 @@ bool power_input_present(void) | |||
961 | * While we are waiting for the time to expire, we average the battery | 995 | * While we are waiting for the time to expire, we average the battery |
962 | * voltages. | 996 | * voltages. |
963 | */ | 997 | */ |
964 | static void power_thread_sleep(int ticks) | 998 | void power_thread_sleep(int ticks) |
965 | { | 999 | { |
966 | int small_ticks; | 1000 | long tick_return = current_tick + ticks; |
967 | |||
968 | while (ticks > 0) { | ||
969 | 1001 | ||
1002 | do | ||
1003 | { | ||
970 | #if CONFIG_CHARGING | 1004 | #if CONFIG_CHARGING |
971 | /* | 1005 | /* |
972 | * Detect charger plugged/unplugged transitions. On a plugged or | 1006 | * Detect charger plugged/unplugged transitions. On a plugged or |
@@ -979,7 +1013,8 @@ static void power_thread_sleep(int ticks) | |||
979 | case NO_CHARGER: | 1013 | case NO_CHARGER: |
980 | case CHARGER_UNPLUGGED: | 1014 | case CHARGER_UNPLUGGED: |
981 | charger_input_state = CHARGER_PLUGGED; | 1015 | charger_input_state = CHARGER_PLUGGED; |
982 | return; | 1016 | tick_return = current_tick; |
1017 | goto do_small_step; /* Algorithm should see transition */ | ||
983 | case CHARGER_PLUGGED: | 1018 | case CHARGER_PLUGGED: |
984 | queue_broadcast(SYS_CHARGER_CONNECTED, 0); | 1019 | queue_broadcast(SYS_CHARGER_CONNECTED, 0); |
985 | last_sent_battery_level = 0; | 1020 | last_sent_battery_level = 0; |
@@ -1000,19 +1035,23 @@ static void power_thread_sleep(int ticks) | |||
1000 | case CHARGER_PLUGGED: | 1035 | case CHARGER_PLUGGED: |
1001 | case CHARGER: | 1036 | case CHARGER: |
1002 | charger_input_state = CHARGER_UNPLUGGED; | 1037 | charger_input_state = CHARGER_UNPLUGGED; |
1003 | return; | 1038 | tick_return = current_tick; |
1039 | goto do_small_step; /* Algorithm should see transition */ | ||
1004 | } | 1040 | } |
1005 | } | 1041 | } |
1006 | #endif /* CONFIG_CHARGING */ | 1042 | #endif /* CONFIG_CHARGING */ |
1007 | 1043 | ||
1008 | small_ticks = MIN(HZ/2, ticks); | 1044 | ticks = tick_return - current_tick; |
1009 | sleep(small_ticks); | 1045 | |
1010 | ticks -= small_ticks; | 1046 | if (ticks > 0) { |
1047 | ticks = MIN(HZ/2, ticks); | ||
1048 | sleep(ticks); | ||
1049 | } | ||
1011 | 1050 | ||
1012 | /* If the power off timeout expires, the main thread has failed | 1051 | /* If the power off timeout expires, the main thread has failed |
1013 | to shut down the system, and we need to force a power off */ | 1052 | to shut down the system, and we need to force a power off */ |
1014 | if(shutdown_timeout) { | 1053 | if(shutdown_timeout) { |
1015 | shutdown_timeout -= small_ticks; | 1054 | shutdown_timeout -= MAX(ticks, 1); |
1016 | if(shutdown_timeout <= 0) | 1055 | if(shutdown_timeout <= 0) |
1017 | power_off(); | 1056 | power_off(); |
1018 | } | 1057 | } |
@@ -1024,9 +1063,13 @@ static void power_thread_sleep(int ticks) | |||
1024 | /* | 1063 | /* |
1025 | * Do a digital exponential filter. We don't sample the battery if | 1064 | * Do a digital exponential filter. We don't sample the battery if |
1026 | * the disk is spinning unless we are in USB mode (the disk will most | 1065 | * the disk is spinning unless we are in USB mode (the disk will most |
1027 | * likely always be spinning in USB mode). | 1066 | * likely always be spinning in USB mode) or charging. |
1028 | */ | 1067 | */ |
1029 | if (!storage_disk_is_active() || usb_inserted()) { | 1068 | if (!storage_disk_is_active() || usb_inserted() |
1069 | #if CONFIG_CHARGING >= CHARGING_MONITOR | ||
1070 | || charger_input_state == CHARGER | ||
1071 | #endif | ||
1072 | ) { | ||
1030 | avgbat += battery_adc_voltage() - (avgbat / BATT_AVE_SAMPLES); | 1073 | avgbat += battery_adc_voltage() - (avgbat / BATT_AVE_SAMPLES); |
1031 | /* | 1074 | /* |
1032 | * battery_millivolts is the millivolt-scaled filtered battery value. | 1075 | * battery_millivolts is the millivolt-scaled filtered battery value. |
@@ -1047,17 +1090,20 @@ static void power_thread_sleep(int ticks) | |||
1047 | /* update battery status every time an update is available */ | 1090 | /* update battery status every time an update is available */ |
1048 | battery_status_update(); | 1091 | battery_status_update(); |
1049 | 1092 | ||
1050 | #ifndef NO_LOW_BATTERY_SHUTDOWN | 1093 | if (!shutdown_timeout && query_force_shutdown()) { |
1051 | if (!shutdown_timeout && | ||
1052 | (battery_millivolts < battery_level_shutoff[battery_type])) | ||
1053 | sys_poweroff(); | 1094 | sys_poweroff(); |
1054 | else | 1095 | } |
1055 | #endif | 1096 | else { |
1056 | avgbat += battery_millivolts - (avgbat / BATT_AVE_SAMPLES); | 1097 | avgbat += battery_millivolts - (avgbat / BATT_AVE_SAMPLES); |
1098 | } | ||
1057 | } | 1099 | } |
1058 | 1100 | ||
1101 | #if CONFIG_CHARGING | ||
1102 | do_small_step: | ||
1103 | #endif | ||
1059 | charging_algorithm_small_step(); | 1104 | charging_algorithm_small_step(); |
1060 | } | 1105 | } |
1106 | while (TIME_BEFORE(current_tick, tick_return)); | ||
1061 | } | 1107 | } |
1062 | 1108 | ||
1063 | static void power_thread(void) | 1109 | static void power_thread(void) |
@@ -1074,7 +1120,7 @@ static void power_thread(void) | |||
1074 | #ifdef HAVE_DISK_STORAGE /* this adjustment is only needed for HD based */ | 1120 | #ifdef HAVE_DISK_STORAGE /* this adjustment is only needed for HD based */ |
1075 | /* The battery voltage is usually a little lower directly after | 1121 | /* The battery voltage is usually a little lower directly after |
1076 | turning on, because the disk was used heavily. Raise it by 5% */ | 1122 | turning on, because the disk was used heavily. Raise it by 5% */ |
1077 | #ifdef HAVE_CHARGING | 1123 | #if CONFIG_CHARGING |
1078 | if(!charger_inserted()) /* only if charger not connected */ | 1124 | if(!charger_inserted()) /* only if charger not connected */ |
1079 | #endif | 1125 | #endif |
1080 | avgbat += (percent_to_volt_discharge[battery_type][6] - | 1126 | avgbat += (percent_to_volt_discharge[battery_type][6] - |
@@ -1095,6 +1141,10 @@ static void power_thread(void) | |||
1095 | battery_percent += (battery_percent < 100); | 1141 | battery_percent += (battery_percent < 100); |
1096 | } | 1142 | } |
1097 | 1143 | ||
1144 | #if CONFIG_CHARGING == CHARGING_TARGET | ||
1145 | powermgmt_init_target(); | ||
1146 | #endif | ||
1147 | |||
1098 | while (1) | 1148 | while (1) |
1099 | { | 1149 | { |
1100 | /* rotate the power history */ | 1150 | /* rotate the power history */ |
@@ -1121,6 +1171,7 @@ void powermgmt_init(void) | |||
1121 | 1171 | ||
1122 | #endif /* SIMULATOR */ | 1172 | #endif /* SIMULATOR */ |
1123 | 1173 | ||
1174 | #ifndef BOOTLOADER | ||
1124 | void sys_poweroff(void) | 1175 | void sys_poweroff(void) |
1125 | { | 1176 | { |
1126 | #ifndef BOOTLOADER | 1177 | #ifndef BOOTLOADER |
@@ -1142,6 +1193,7 @@ void sys_poweroff(void) | |||
1142 | queue_broadcast(SYS_POWEROFF, 0); | 1193 | queue_broadcast(SYS_POWEROFF, 0); |
1143 | #endif /* BOOTLOADER */ | 1194 | #endif /* BOOTLOADER */ |
1144 | } | 1195 | } |
1196 | #endif | ||
1145 | 1197 | ||
1146 | void cancel_shutdown(void) | 1198 | void cancel_shutdown(void) |
1147 | { | 1199 | { |
diff --git a/firmware/target/arm/imx31/debug-imx31.c b/firmware/target/arm/imx31/debug-imx31.c index df2489eafb..b72390cb63 100644 --- a/firmware/target/arm/imx31/debug-imx31.c +++ b/firmware/target/arm/imx31/debug-imx31.c | |||
@@ -139,6 +139,7 @@ bool __dbg_ports(void) | |||
139 | MC13783_INTERRUPT_SENSE0, | 139 | MC13783_INTERRUPT_SENSE0, |
140 | MC13783_INTERRUPT_STATUS1, | 140 | MC13783_INTERRUPT_STATUS1, |
141 | MC13783_INTERRUPT_SENSE1, | 141 | MC13783_INTERRUPT_SENSE1, |
142 | MC13783_CHARGER, | ||
142 | MC13783_RTC_TIME, | 143 | MC13783_RTC_TIME, |
143 | MC13783_RTC_ALARM, | 144 | MC13783_RTC_ALARM, |
144 | MC13783_RTC_DAY, | 145 | MC13783_RTC_DAY, |
@@ -151,6 +152,7 @@ bool __dbg_ports(void) | |||
151 | "Int Sense0", | 152 | "Int Sense0", |
152 | "Int Stat1 ", | 153 | "Int Stat1 ", |
153 | "Int Sense1", | 154 | "Int Sense1", |
155 | "Charger ", | ||
154 | "RTC Time ", | 156 | "RTC Time ", |
155 | "RTC Alarm ", | 157 | "RTC Alarm ", |
156 | "RTC Day ", | 158 | "RTC Day ", |
diff --git a/firmware/target/arm/imx31/gigabeat-s/adc-imx31.c b/firmware/target/arm/imx31/gigabeat-s/adc-imx31.c index 85ef15b9b4..3c66c42adc 100644 --- a/firmware/target/arm/imx31/gigabeat-s/adc-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/adc-imx31.c | |||
@@ -84,6 +84,30 @@ unsigned short adc_read(int channel) | |||
84 | return (channel & 4) ? MC13783_ADD2r(data) : MC13783_ADD1r(data); | 84 | return (channel & 4) ? MC13783_ADD2r(data) : MC13783_ADD1r(data); |
85 | } | 85 | } |
86 | 86 | ||
87 | bool adc_enable_channel(int channel, bool enable) | ||
88 | { | ||
89 | uint32_t bit, mask; | ||
90 | |||
91 | switch (channel) | ||
92 | { | ||
93 | case ADC_CHARGER_CURRENT: | ||
94 | mask = MC13783_CHRGICON; | ||
95 | break; | ||
96 | |||
97 | case ADC_BATTERY_TEMP: | ||
98 | mask = MC13783_RTHEN; | ||
99 | break; | ||
100 | |||
101 | default: | ||
102 | return false; | ||
103 | } | ||
104 | |||
105 | bit = enable ? mask : 0; | ||
106 | |||
107 | return mc13783_write_masked(MC13783_ADC0, bit, mask) | ||
108 | != MC13783_DATA_ERROR; | ||
109 | } | ||
110 | |||
87 | /* Called by mc13783 interrupt thread when conversion is complete */ | 111 | /* Called by mc13783 interrupt thread when conversion is complete */ |
88 | void adc_done(void) | 112 | void adc_done(void) |
89 | { | 113 | { |
@@ -98,9 +122,9 @@ void adc_init(void) | |||
98 | /* Init so first reads get data */ | 122 | /* Init so first reads get data */ |
99 | last_adc_read[0] = last_adc_read[1] = current_tick-1; | 123 | last_adc_read[0] = last_adc_read[1] = current_tick-1; |
100 | 124 | ||
101 | /* Enable increment-by-read, thermistor, charge current */ | 125 | /* Enable increment-by-read, turn off extra conversions. */ |
102 | mc13783_write(MC13783_ADC0, MC13783_ADINC2 | MC13783_ADINC1 | | 126 | mc13783_write(MC13783_ADC0, MC13783_ADINC2 | MC13783_ADINC1); |
103 | MC13783_RTHEN | MC13783_CHRGICON); | 127 | |
104 | /* Enable ADC, set multi-channel mode */ | 128 | /* Enable ADC, set multi-channel mode */ |
105 | mc13783_write(MC13783_ADC1, MC13783_ADEN); | 129 | mc13783_write(MC13783_ADC1, MC13783_ADEN); |
106 | 130 | ||
diff --git a/firmware/target/arm/imx31/gigabeat-s/adc-target.h b/firmware/target/arm/imx31/gigabeat-s/adc-target.h index efa665dd98..00027e05df 100644 --- a/firmware/target/arm/imx31/gigabeat-s/adc-target.h +++ b/firmware/target/arm/imx31/gigabeat-s/adc-target.h | |||
@@ -47,7 +47,14 @@ | |||
47 | #define ADC_READ_ERROR 0xFFFF | 47 | #define ADC_READ_ERROR 0xFFFF |
48 | 48 | ||
49 | void adc_done(void); | 49 | void adc_done(void); |
50 | /* Enable conversion of specified channel (if switchoff is possible) */ | ||
51 | bool adc_enable_channel(int channel, bool enable); | ||
52 | |||
53 | /* Implemented in powermgmt-imx31.c */ | ||
50 | int battery_adc_charge_current(void); | 54 | int battery_adc_charge_current(void); |
51 | unsigned int battery_adc_temp(void); | 55 | int battery_adc_temp(void); |
56 | unsigned int application_supply_adc_voltage(void); | ||
57 | unsigned int chrgraw_adc_voltage(void); | ||
58 | unsigned int cccv_regulator_dissipation(void); | ||
52 | 59 | ||
53 | #endif | 60 | #endif |
diff --git a/firmware/target/arm/imx31/gigabeat-s/mc13783-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/mc13783-gigabeat-s.c index e6238112d1..fc9ad719a6 100644 --- a/firmware/target/arm/imx31/gigabeat-s/mc13783-gigabeat-s.c +++ b/firmware/target/arm/imx31/gigabeat-s/mc13783-gigabeat-s.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "button-target.h" | 28 | #include "button-target.h" |
29 | #include "usb-target.h" | 29 | #include "usb-target.h" |
30 | #include "power-imx31.h" | 30 | #include "power-imx31.h" |
31 | #include "powermgmt-target.h" | ||
31 | 32 | ||
32 | /* Gigabeat S definitions for static MC13783 event registration */ | 33 | /* Gigabeat S definitions for static MC13783 event registration */ |
33 | 34 | ||
@@ -45,26 +46,26 @@ static const struct mc13783_event mc13783_events[] = | |||
45 | .mask = MC13783_ONOFD1M, | 46 | .mask = MC13783_ONOFD1M, |
46 | .callback = button_power_event, | 47 | .callback = button_power_event, |
47 | }, | 48 | }, |
48 | #ifdef HAVE_HEADPHONE_DETECTION | 49 | [MC13783_SE1_EVENT] = /* Main charger detection */ |
49 | [MC13783_ONOFD2_EVENT] = /* Headphone jack */ | ||
50 | { | ||
51 | .set = MC13783_EVENT_SET1, | ||
52 | .mask = MC13783_ONOFD2M, | ||
53 | .callback = headphone_detect_event, | ||
54 | }, | ||
55 | #endif | ||
56 | [MC13783_CHGDET_EVENT] = /* Charger detection */ | ||
57 | { | 50 | { |
58 | .set = MC13783_EVENT_SET0, | 51 | .set = MC13783_EVENT_SET0, |
59 | .mask = MC13783_CHGDETM, | 52 | .mask = MC13783_SE1M, |
60 | .callback = charger_detect_event, | 53 | .callback = charger_main_detect_event, |
61 | }, | 54 | }, |
62 | [MC13783_USB4V4_EVENT] = /* USB insertion */ | 55 | [MC13783_USB_EVENT] = /* USB insertion/USB charger detection */ |
63 | { | 56 | { |
64 | .set = MC13783_EVENT_SET0, | 57 | .set = MC13783_EVENT_SET0, |
65 | .mask = MC13783_USBM, | 58 | .mask = MC13783_USBM, |
66 | .callback = usb_connect_event, | 59 | .callback = usb_connect_event, |
67 | }, | 60 | }, |
61 | #ifdef HAVE_HEADPHONE_DETECTION | ||
62 | [MC13783_ONOFD2_EVENT] = /* Headphone jack */ | ||
63 | { | ||
64 | .set = MC13783_EVENT_SET1, | ||
65 | .mask = MC13783_ONOFD2M, | ||
66 | .callback = headphone_detect_event, | ||
67 | }, | ||
68 | #endif | ||
68 | }; | 69 | }; |
69 | 70 | ||
70 | const struct mc13783_event_list mc13783_event_list = | 71 | const struct mc13783_event_list mc13783_event_list = |
diff --git a/firmware/target/arm/imx31/gigabeat-s/mc13783-target.h b/firmware/target/arm/imx31/gigabeat-s/mc13783-target.h index 26ab3c6e21..2ae3be1819 100644 --- a/firmware/target/arm/imx31/gigabeat-s/mc13783-target.h +++ b/firmware/target/arm/imx31/gigabeat-s/mc13783-target.h | |||
@@ -31,8 +31,8 @@ enum mc13783_event_ids | |||
31 | #ifdef HAVE_HEADPHONE_DETECTION | 31 | #ifdef HAVE_HEADPHONE_DETECTION |
32 | MC13783_ONOFD2_EVENT, /* Headphone jack */ | 32 | MC13783_ONOFD2_EVENT, /* Headphone jack */ |
33 | #endif | 33 | #endif |
34 | MC13783_CHGDET_EVENT, /* Charger detection */ | 34 | MC13783_SE1_EVENT, /* Main charger detection */ |
35 | MC13783_USB4V4_EVENT, /* USB insertion */ | 35 | MC13783_USB_EVENT, /* USB insertion */ |
36 | }; | 36 | }; |
37 | 37 | ||
38 | #endif /* MC13783_TARGET_H */ | 38 | #endif /* MC13783_TARGET_H */ |
diff --git a/firmware/target/arm/imx31/gigabeat-s/power-imx31.c b/firmware/target/arm/imx31/gigabeat-s/power-imx31.c index 17008cec4b..39724c7b75 100644 --- a/firmware/target/arm/imx31/gigabeat-s/power-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/power-imx31.c | |||
@@ -20,6 +20,8 @@ | |||
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | #include "config.h" | 21 | #include "config.h" |
22 | #include "system.h" | 22 | #include "system.h" |
23 | #include "usb.h" | ||
24 | #include "usb_core.h" | ||
23 | #include "power.h" | 25 | #include "power.h" |
24 | #include "power-imx31.h" | 26 | #include "power-imx31.h" |
25 | #include "backlight.h" | 27 | #include "backlight.h" |
@@ -29,35 +31,47 @@ | |||
29 | #include "i2c-imx31.h" | 31 | #include "i2c-imx31.h" |
30 | 32 | ||
31 | extern struct i2c_node si4700_i2c_node; | 33 | extern struct i2c_node si4700_i2c_node; |
34 | static unsigned int power_status = POWER_INPUT_NONE; | ||
32 | 35 | ||
33 | static bool charger_detect = false; | 36 | /* Detect which power sources are present. */ |
34 | |||
35 | /* This is called from the mc13783 interrupt thread */ | ||
36 | void charger_detect_event(void) | ||
37 | { | ||
38 | charger_detect = | ||
39 | mc13783_read(MC13783_INTERRUPT_SENSE0) & MC13783_CHGDETS; | ||
40 | } | ||
41 | |||
42 | unsigned int power_input_status(void) | 37 | unsigned int power_input_status(void) |
43 | { | 38 | { |
44 | unsigned int status = POWER_INPUT_NONE; | 39 | unsigned int status = power_status; |
45 | 40 | ||
46 | if ((GPIO3_DR & (1 << 20)) != 0) | 41 | if (GPIO3_DR & (1 << 20)) |
47 | status |= POWER_INPUT_BATTERY; | 42 | status |= POWER_INPUT_BATTERY; |
48 | 43 | ||
49 | if (charger_detect) | 44 | if (usb_allowed_current() < 500) |
50 | status |= POWER_INPUT_MAIN_CHARGER; | 45 | { |
46 | /* ACK that USB is connected but NOT chargeable */ | ||
47 | status &= ~(POWER_INPUT_USB_CHARGER & POWER_INPUT_CHARGER); | ||
48 | } | ||
51 | 49 | ||
52 | return status; | 50 | return status; |
53 | } | 51 | } |
54 | 52 | ||
55 | /* Returns true if the unit is charging the batteries. */ | 53 | /* Detect changes in presence of the AC adaptor. */ |
56 | bool charging_state(void) | 54 | void charger_main_detect_event(void) |
57 | { | 55 | { |
58 | return false; | 56 | if (mc13783_read(MC13783_INTERRUPT_SENSE0) & MC13783_SE1S) |
57 | power_status |= POWER_INPUT_MAIN_CHARGER; | ||
58 | else | ||
59 | power_status &= ~POWER_INPUT_MAIN_CHARGER; | ||
59 | } | 60 | } |
60 | 61 | ||
62 | /* Detect changes in USB bus power. Called from usb connect event handler. */ | ||
63 | void charger_usb_detect_event(int status) | ||
64 | { | ||
65 | /* USB plugged does not imply charging is possible or even | ||
66 | * powering the device to maintain the battery. */ | ||
67 | if (status == USB_INSERTED) | ||
68 | power_status |= POWER_INPUT_USB_CHARGER; | ||
69 | else | ||
70 | power_status &= ~POWER_INPUT_USB_CHARGER; | ||
71 | } | ||
72 | |||
73 | /* charging_state is implemented in powermgmt-imx31.c */ | ||
74 | |||
61 | void ide_power_enable(bool on) | 75 | void ide_power_enable(bool on) |
62 | { | 76 | { |
63 | if (!on) | 77 | if (!on) |
@@ -129,9 +143,8 @@ void power_off(void) | |||
129 | void power_init(void) | 143 | void power_init(void) |
130 | { | 144 | { |
131 | /* Poll initial state */ | 145 | /* Poll initial state */ |
132 | charger_detect_event(); | 146 | charger_main_detect_event(); |
133 | 147 | ||
134 | /* Enable detect event */ | 148 | /* Enable detect event */ |
135 | mc13783_enable_event(MC13783_CHGDET_EVENT); | 149 | mc13783_enable_event(MC13783_SE1_EVENT); |
136 | } | 150 | } |
137 | |||
diff --git a/firmware/target/arm/imx31/gigabeat-s/power-imx31.h b/firmware/target/arm/imx31/gigabeat-s/power-imx31.h index 86ba4ac815..9294de102c 100644 --- a/firmware/target/arm/imx31/gigabeat-s/power-imx31.h +++ b/firmware/target/arm/imx31/gigabeat-s/power-imx31.h | |||
@@ -21,6 +21,7 @@ | |||
21 | #ifndef POWER_IMX31_H | 21 | #ifndef POWER_IMX31_H |
22 | #define POWER_IMX31_H | 22 | #define POWER_IMX31_H |
23 | 23 | ||
24 | void charger_detect_event(void); | 24 | void charger_main_detect_event(void); |
25 | void charger_usb_detect_event(int status); | ||
25 | 26 | ||
26 | #endif /* POWER_IMX31_H */ | 27 | #endif /* POWER_IMX31_H */ |
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! */ | ||
32 | const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] = | ||
33 | { | ||
34 | 3450 | ||
35 | }; | ||
36 | |||
37 | const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] = | ||
38 | { | ||
39 | 3400 | ||
40 | }; | ||
41 | |||
42 | /* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */ | ||
43 | const 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 */ | ||
50 | const 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 | |||
60 | const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] = | ||
61 | { | ||
62 | 3450 | ||
63 | }; | ||
64 | |||
65 | const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] = | ||
66 | { | ||
67 | 3400 | ||
68 | }; | ||
69 | |||
70 | /* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */ | ||
71 | const 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 */ | ||
78 | const 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] */ |
85 | unsigned int battery_adc_voltage(void) | 87 | unsigned 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] */ | ||
94 | unsigned int application_supply_adc_voltage(void) | ||
95 | { | ||
96 | return ((adc_read(ADC_APPLICATION_SUPPLY) * 2303) >> 10) + 2400; | ||
97 | } | ||
98 | |||
99 | unsigned 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] */ |
92 | int battery_adc_charge_current(void) | 105 | int 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. */ | ||
121 | unsigned 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] */ |
102 | unsigned int battery_adc_temp(void) | 135 | int 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. */ | ||
170 | static uint32_t int_sense0 = 0; /* Interrupt Sense 0 bits */ | ||
171 | static unsigned int power_status = POWER_INPUT_NONE; /* Detect input changes */ | ||
172 | static int charger_total_timer = 0; /* Total allowed charging time */ | ||
173 | static int icharger_ave = 0; /* Filtered charging current */ | ||
174 | static bool charger_close = false; /* Shutdown notification */ | ||
175 | static bool service_wdt = true; /* Service the watchdog timer, if things | ||
176 | go very wrong, cease and shut down. */ | ||
177 | static 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 */ | ||
180 | static int autorecharge_counter = 0 ; /* Battery < threshold debounce */ | ||
181 | static 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 */ | ||
187 | static 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 */ | ||
196 | static 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 */ | ||
206 | static 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. */ | ||
218 | static 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. */ | ||
228 | static 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. */ | ||
238 | static 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. */ | ||
248 | static 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. */ | ||
289 | static 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. */ | ||
304 | static 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. */ | ||
443 | static 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. */ | ||
454 | static 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 | |||
560 | void 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. */ | ||
595 | int 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. */ | ||
609 | bool 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 */ | ||
623 | int battery_charge_current(void) | ||
624 | { | ||
625 | return icharger_ave / ICHARGER_AVE_SAMPLES; | ||
626 | } | ||
627 | |||
628 | bool 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 | |||
637 | bool 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 | |||
646 | static void charger_plugged(void) | ||
647 | { | ||
648 | adc_enable_channel(ADC_BATTERY_TEMP, true); | ||
649 | autorecharge_counter = -1; | ||
650 | } | ||
651 | |||
652 | static 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 | |||
673 | static 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 | |||
717 | static 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 */ | ||
861 | void 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 | |||
912 | void 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. */ | ||
920 | void 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 | ||
930 | void sys_poweroff(void) | ||
931 | { | ||
126 | } | 932 | } |
933 | #endif /* BOOTLOADER */ | ||
diff --git a/firmware/target/arm/imx31/gigabeat-s/powermgmt-target.h b/firmware/target/arm/imx31/gigabeat-s/powermgmt-target.h new file mode 100644 index 0000000000..8ad4af8d18 --- /dev/null +++ b/firmware/target/arm/imx31/gigabeat-s/powermgmt-target.h | |||
@@ -0,0 +1,114 @@ | |||
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 | #ifndef POWERMGMT_TARGET_H | ||
22 | #define POWERMGMT_TARGET_H | ||
23 | |||
24 | /* Can't just run this code willy-nilly. Do not allow charger engagement | ||
25 | * without carefully verifying compatibility. | ||
26 | * | ||
27 | * Things to check: | ||
28 | * 1) Charge path configuration for the PMIC. | ||
29 | * 2) Correct thermistor reading | ||
30 | * 3) Accurate voltage readings | ||
31 | * 4) Accurate current sense for the charge path as the sense resistor may | ||
32 | * deviate from the 0.1 ohms assumed by the charge path regulator. | ||
33 | */ | ||
34 | #ifdef TOSHIBA_GIGABEAT_S | ||
35 | /* | ||
36 | * Gigabeat S qualifications: | ||
37 | * 1) Setup for dual-supply mode with separate inputs and providing USB | ||
38 | * charging capability through external components. | ||
39 | * 2) Curve obtained experimentally - extreme deviation from "optimized" | ||
40 | * characteristics. | ||
41 | * 3) Verified at battery terminals - no deviation from datasheet formula. | ||
42 | * 4) 0.316 ohms <=?? - verified by comparitive current readings on device | ||
43 | * with ammeter readings and measurement of on-board components. | ||
44 | */ | ||
45 | #ifndef BOOTLOADER | ||
46 | #define IMX31_ALLOW_CHARGING | ||
47 | #endif | ||
48 | |||
49 | #else | ||
50 | #warning This iMX31 target requires validation of charging algorithm - charging disabled | ||
51 | #endif | ||
52 | |||
53 | #define BATT_VTRICKLE_CHARGE 2900 /* Must charge slowly */ | ||
54 | #define BATT_VSLOW_CHARGE 3500 /* Lower-current charge mode below | ||
55 | * this level */ | ||
56 | #define BATT_VAUTO_RECHARGE 4100 /* When to begin another cycle */ | ||
57 | #define BATT_USB_VAUTO_RECHARGE 4000 /* When to cycle with USB only */ | ||
58 | #define BATT_USB_VSTOP 4140 /* When to "stop" when USB only */ | ||
59 | #define BATT_TOO_LOW 2400 /* No battery? Short? Can't | ||
60 | read below 2400mV. */ | ||
61 | #define CHARGER_TOTAL_TIMER 300 /* minutes */ | ||
62 | |||
63 | /* .316 ohms is closest standard value as measured in 1% tolerance - adjust | ||
64 | * relative to .100 ohm which is what the PMIC is "tuned" for. */ | ||
65 | #define ILEVEL_ADJUST_IN(I) (100*(I) / 316) | ||
66 | #define ILEVEL_ADJUST_OUT(I) (316*(I) / 100) | ||
67 | |||
68 | /* Relative draw to battery capacity - adjusted for sense resistor */ | ||
69 | #define BATTERY_ICHARGE_COMPLETE (505*9/100) /* 9% of nominal max output */ | ||
70 | /* All charging modes use 4.200V for regulator */ | ||
71 | #define BATTERY_VCHARGING MC13783_VCHRG_4_200V | ||
72 | /* Slow charging - MAIN - Still below 3.5V (avoid excessive reg. dissipation) */ | ||
73 | /* #define BATTERY_ISLOW */ | ||
74 | /* Fast charging - MAIN */ | ||
75 | #define BATTERY_IFAST MC13783_ICHRG_1596MA /* 505mA */ | ||
76 | /* Trickle charging low battery - MAIN (~10% Imax) */ | ||
77 | #define BATTERY_ITRICKLE MC13783_ICHRG_177MA /* 56mA */ | ||
78 | /* Slow charging - USB - Still below 3.5V (avoid excessive reg. dissipation) */ | ||
79 | /* #define BATTERY_ISLOW_USB */ | ||
80 | /* Fast charging - USB */ | ||
81 | #define BATTERY_IFAST_USB MC13783_ICHRG_1152MA /* 365mA */ | ||
82 | /* Trickle charging low battery - USB (Ibat = Icccv - Idevice) */ | ||
83 | #define BATTERY_ITRICKLE_USB MC13783_ICHRG_532MA /* 168mA */ | ||
84 | /* Maintain charge - USB 500mA */ | ||
85 | #define BATTERY_IFLOAT_USB MC13783_ICHRG_1152MA /* 365mA */ | ||
86 | #define BATTERY_VFLOAT_USB MC13783_VCHRG_4_150V | ||
87 | /* Maintain charge - USB 100mA */ | ||
88 | #define BATTERY_IMAINTAIN_USB MC13783_ICHRG_266MA /* 84mA */ | ||
89 | #define BATTERY_VMAINTAIN_USB MC13783_VCHRG_4_150V | ||
90 | |||
91 | /* Battery filter lengths in samples */ | ||
92 | #define BATT_AVE_SAMPLES 32 | ||
93 | #define ICHARGER_AVE_SAMPLES 32 | ||
94 | |||
95 | /* Provide filtered charge current */ | ||
96 | int battery_charge_current(void); | ||
97 | |||
98 | #ifndef SIMULATOR | ||
99 | /* Indicate various functions that require implementation at the target level. | ||
100 | * This is because the battery could be low or the battery switch is off but | ||
101 | * with the main charger attached which implies safe power for anything. The | ||
102 | * true battery reading is always reported for voltage readings and not the | ||
103 | * value at the application supply. */ | ||
104 | #define TARGET_QUERY_FORCE_SHUTDOWN | ||
105 | |||
106 | /* For this the application supply is read out if the charger is attached or | ||
107 | * the battery read if not (completely hardware selected at BP). */ | ||
108 | #define TARGET_BATTERY_LEVEL_SAFE | ||
109 | |||
110 | /* The state should be adjusted to CHARGING or DISCHARGING */ | ||
111 | #define TARGET_POWERMGMT_FILTER_CHARGE_STATE | ||
112 | #endif /* SIMULATOR */ | ||
113 | |||
114 | #endif /* POWERMGMT_TARGET_H */ | ||
diff --git a/firmware/target/arm/imx31/gigabeat-s/system-imx31.c b/firmware/target/arm/imx31/gigabeat-s/system-imx31.c index 6d4797e9df..7d778fb8fd 100644 --- a/firmware/target/arm/imx31/gigabeat-s/system-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/system-imx31.c | |||
@@ -32,6 +32,31 @@ | |||
32 | #include "clkctl-imx31.h" | 32 | #include "clkctl-imx31.h" |
33 | #include "mc13783.h" | 33 | #include "mc13783.h" |
34 | 34 | ||
35 | /* Initialize the watchdog timer */ | ||
36 | void watchdog_init(unsigned int half_seconds) | ||
37 | { | ||
38 | uint16_t wcr = WDOG_WCR_WTw(half_seconds) | /* Timeout */ | ||
39 | WDOG_WCR_WOE | /* WDOG output enabled */ | ||
40 | WDOG_WCR_WDA | /* WDOG assertion - no effect */ | ||
41 | WDOG_WCR_SRS | /* System reset - no effect */ | ||
42 | WDOG_WCR_WRE; /* Generate a WDOG signal */ | ||
43 | |||
44 | imx31_clkctl_module_clock_gating(CG_WDOG, CGM_ON_RUN_WAIT); | ||
45 | |||
46 | WDOG_WCR = wcr; | ||
47 | WDOG_WSR = 0x5555; | ||
48 | WDOG_WCR = wcr | WDOG_WCR_WDE; /* Enable timer - hardware does | ||
49 | not allow a disable now */ | ||
50 | WDOG_WSR = 0xaaaa; | ||
51 | } | ||
52 | |||
53 | /* Service the watchdog timer */ | ||
54 | void watchdog_service(void) | ||
55 | { | ||
56 | WDOG_WSR = 0x5555; | ||
57 | WDOG_WSR = 0xaaaa; | ||
58 | } | ||
59 | |||
35 | int system_memory_guard(int newmode) | 60 | int system_memory_guard(int newmode) |
36 | { | 61 | { |
37 | (void)newmode; | 62 | (void)newmode; |
diff --git a/firmware/target/arm/imx31/gigabeat-s/system-target.h b/firmware/target/arm/imx31/gigabeat-s/system-target.h index 31f1342c9e..fbf7b23f3b 100644 --- a/firmware/target/arm/imx31/gigabeat-s/system-target.h +++ b/firmware/target/arm/imx31/gigabeat-s/system-target.h | |||
@@ -39,6 +39,11 @@ static inline void udelay(unsigned int usecs) | |||
39 | } | 39 | } |
40 | #endif | 40 | #endif |
41 | 41 | ||
42 | /* Service the watchdog timer - serviced from the power thread every minute */ | ||
43 | void watchdog_init(unsigned int half_seconds); | ||
44 | void watchdog_service(void); | ||
45 | |||
46 | /* Prepare for transition to firmware */ | ||
42 | void system_prepare_fw_start(void); | 47 | void system_prepare_fw_start(void); |
43 | void tick_stop(void); | 48 | void tick_stop(void); |
44 | void kernel_device_init(void); | 49 | void kernel_device_init(void); |
diff --git a/firmware/target/arm/imx31/gigabeat-s/usb-imx31.c b/firmware/target/arm/imx31/gigabeat-s/usb-imx31.c index 382bc326b7..a7314861c3 100644 --- a/firmware/target/arm/imx31/gigabeat-s/usb-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/usb-imx31.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "usb_drv.h" | 28 | #include "usb_drv.h" |
29 | #include "usb-target.h" | 29 | #include "usb-target.h" |
30 | #include "clkctl-imx31.h" | 30 | #include "clkctl-imx31.h" |
31 | #include "power-imx31.h" | ||
31 | #include "mc13783.h" | 32 | #include "mc13783.h" |
32 | 33 | ||
33 | static int usb_status = USB_EXTRACTED; | 34 | static int usb_status = USB_EXTRACTED; |
@@ -53,8 +54,11 @@ static void enable_transceiver(bool enable) | |||
53 | 54 | ||
54 | void usb_connect_event(void) | 55 | void usb_connect_event(void) |
55 | { | 56 | { |
56 | uint32_t status = mc13783_read(MC13783_INTERRUPT_SENSE0); | 57 | uint32_t status = mc13783_read(MC13783_INTERRUPT_SENSE0); |
57 | usb_status = (status & MC13783_USB4V4S) ? USB_INSERTED : USB_EXTRACTED; | 58 | usb_status = (status & MC13783_USB4V4S) ? |
59 | USB_INSERTED : USB_EXTRACTED; | ||
60 | /* Notify power that USB charging is potentially available */ | ||
61 | charger_usb_detect_event(usb_status); | ||
58 | } | 62 | } |
59 | 63 | ||
60 | int usb_detect(void) | 64 | int usb_detect(void) |
@@ -81,7 +85,7 @@ void usb_init_device(void) | |||
81 | usb_connect_event(); | 85 | usb_connect_event(); |
82 | 86 | ||
83 | /* Enable PMIC event */ | 87 | /* Enable PMIC event */ |
84 | mc13783_enable_event(MC13783_USB4V4_EVENT); | 88 | mc13783_enable_event(MC13783_USB_EVENT); |
85 | } | 89 | } |
86 | 90 | ||
87 | void usb_enable(bool on) | 91 | void usb_enable(bool on) |