summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/debug_menu.c32
-rw-r--r--firmware/SOURCES26
-rw-r--r--firmware/export/as3514.h33
-rw-r--r--firmware/export/config-c200.h5
-rw-r--r--firmware/export/config-e200.h5
-rw-r--r--firmware/export/powermgmt.h7
-rw-r--r--firmware/powermgmt.c2
-rw-r--r--firmware/target/arm/powermgmt-ascodec.c231
-rw-r--r--firmware/target/arm/sandisk/powermgmt-target.h59
-rw-r--r--firmware/target/arm/sandisk/sansa-c200/powermgmt-c200.c13
-rw-r--r--firmware/target/arm/sandisk/sansa-e200/powermgmt-e200.c11
11 files changed, 375 insertions, 49 deletions
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index 10d69b0..7477bb0 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -106,7 +106,7 @@
#include "debug-target.h"
#endif
-#if defined(SANSA_E200) || defined(PHILIPS_SA9200)
+#if defined(SANSA_E200) || defined(SANSA_C200) || defined(PHILIPS_SA9200)
#include "ascodec.h"
#include "as3514.h"
#endif
@@ -1251,10 +1251,6 @@ extern unsigned char serbuf[];
lcd_puts(0, line++, buf);
snprintf(buf, sizeof(buf), "ADC_VBAT: %4d", adc_read(ADC_VBAT));
lcd_puts(0, line++, buf);
- snprintf(buf, sizeof(buf), "CHARGER: %02X/%02X",
- ascodec_read(AS3514_CHARGER),
- ascodec_read(AS3514_IRQ_ENRD0));
- lcd_puts(0, line++, buf);
#endif
#endif
lcd_update();
@@ -1757,6 +1753,32 @@ static bool view_battery(void)
}
lcd_puts(0, line++, buf);
+#elif defined(SANSA_E200) || defined(SANSA_C200)
+ const int first = CHARGE_STATE_DISABLED;
+ static const char * const chrgstate_strings[] =
+ {
+ [CHARGE_STATE_DISABLED-first] = "Disabled",
+ [CHARGE_STATE_ERROR-first] = "Error",
+ [DISCHARGING-first] = "Discharging",
+ [CHARGING-first] = "Charging",
+ };
+ const char *str = NULL;
+
+ snprintf(buf, 30, "Charger: %s",
+ charger_inserted() ? "present" : "absent");
+ lcd_puts(0, 3, buf);
+
+ y = charge_state - first;
+ if ((unsigned)y < ARRAYLEN(chrgstate_strings))
+ str = chrgstate_strings[y];
+
+ snprintf(buf, sizeof(buf), "State: %s",
+ str ? str : "<unknown>");
+ lcd_puts(0, 4, buf);
+
+ snprintf(buf, sizeof(buf), "CHARGER: %02X",
+ ascodec_read(AS3514_CHARGER));
+ lcd_puts(0, 5, buf);
#else
snprintf(buf, 30, "Charger: %s",
charger_inserted() ? "present" : "absent");
diff --git a/firmware/SOURCES b/firmware/SOURCES
index f4d86bc..3f55856 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -485,17 +485,18 @@ target/sh/archos/ondio/fmradio_i2c-ondio.c
#ifdef SANSA_E200
#ifndef SIMULATOR
-target/arm/lcd-as-memframe.S
-target/arm/ata-sd-pp.c
-target/arm/sandisk/sansa-e200/lcd-e200.c
target/arm/adc-as3514.c
target/arm/ascodec-pp.c
-target/arm/sandisk/backlight-c200_e200.c
+target/arm/ata-sd-pp.c
+target/arm/lcd-as-memframe.S
+target/arm/powermgmt-ascodec.c
+target/arm/i2s-pp.c
target/arm/usb-fw-pp502x.c
-target/arm/sandisk/sansa-e200/button-e200.c
+target/arm/sandisk/backlight-c200_e200.c
target/arm/sandisk/power-c200_e200.c
+target/arm/sandisk/sansa-e200/lcd-e200.c
+target/arm/sandisk/sansa-e200/button-e200.c
target/arm/sandisk/sansa-e200/powermgmt-e200.c
-target/arm/i2s-pp.c
#ifndef BOOTLOADER
target/arm/sandisk/audio-c200_e200.c
#endif /* BOOTLOADER */
@@ -504,17 +505,18 @@ target/arm/sandisk/audio-c200_e200.c
#ifdef SANSA_C200
#ifndef SIMULATOR
-target/arm/ata-sd-pp.c
-target/arm/sandisk/sansa-c200/lcd-c200.c
-target/arm/sandisk/sansa-c200/lcd-as-c200.S
target/arm/adc-as3514.c
target/arm/ascodec-pp.c
-target/arm/sandisk/backlight-c200_e200.c
+target/arm/ata-sd-pp.c
+target/arm/i2s-pp.c
+target/arm/powermgmt-ascodec.c
target/arm/usb-fw-pp502x.c
-target/arm/sandisk/sansa-c200/button-c200.c
+target/arm/sandisk/backlight-c200_e200.c
target/arm/sandisk/power-c200_e200.c
+target/arm/sandisk/sansa-c200/lcd-c200.c
+target/arm/sandisk/sansa-c200/lcd-as-c200.S
+target/arm/sandisk/sansa-c200/button-c200.c
target/arm/sandisk/sansa-c200/powermgmt-c200.c
-target/arm/i2s-pp.c
#ifndef BOOTLOADER
target/arm/sandisk/audio-c200_e200.c
#endif /* BOOTLOADER */
diff --git a/firmware/export/as3514.h b/firmware/export/as3514.h
index 07aa0eb..9489d1a 100644
--- a/firmware/export/as3514.h
+++ b/firmware/export/as3514.h
@@ -249,8 +249,37 @@ extern void audiohw_set_frequency(int fsel);
#define ADC_I_MICSUP2 11 /* Current of MicSup2 for remote control detection */
#define ADC_VBAT 12 /* Single cell battery voltage */
-#define ADC_UNREG_POWER ADC_BVDD /* For compatibility */
-
+/* AS3514_CHARGER */
+#define TMPSUP_OFF (0x1 << 7)
+#define CHG_I (0x7 << 4)
+#define CHG_I_400MA (0x7 << 4)
+#define CHG_I_350MA (0x6 << 4)
+#define CHG_I_300MA (0x5 << 4)
+#define CHG_I_250MA (0x4 << 4)
+#define CHG_I_200MA (0x3 << 4)
+#define CHG_I_150MA (0x2 << 4)
+#define CHG_I_100MA (0x1 << 4)
+#define CHG_I_50MA (0x0 << 4)
+#define CHG_V (0x7 << 1)
+#define CHG_V_4_25V (0x7 << 1)
+#define CHG_V_4_20V (0x6 << 1)
+#define CHG_V_4_15V (0x5 << 1)
+#define CHG_V_4_10V (0x4 << 1)
+#define CHG_V_4_05V (0x3 << 1)
+#define CHG_V_4_00V (0x2 << 1)
+#define CHG_V_3_95V (0x1 << 1)
+#define CHG_V_3_90V (0x0 << 1)
+#define CHG_OFF (0x1 << 0)
+
+/* AS3514_IRQ_ENRD0 */
+#define CHG_TMPHIGH (0x1 << 7)
+#define CHG_ENDOFCH (0x1 << 6)
+#define CHG_STATUS (0x1 << 5)
+#define CHG_CHANGED (0x1 << 4)
+#define USB_STATUS (0x1 << 3)
+#define USB_CHANGED (0x1 << 2)
+#define RVDD_WASLOW (0x1 << 1)
+#define BVDD_ISLOW (0x1 << 0)
#define AS3514_I2C_ADDR 0x46
diff --git a/firmware/export/config-c200.h b/firmware/export/config-c200.h
index f4ab33f..d68d214 100644
--- a/firmware/export/config-c200.h
+++ b/firmware/export/config-c200.h
@@ -123,8 +123,9 @@
#define BATTERY_CAPACITY_INC 0 /* capacity increment */
#define BATTERY_TYPES_COUNT 1 /* only one type */
-/* Hardware controlled charging? FIXME */
-#define CONFIG_CHARGING CHARGING_SIMPLE
+/* Charging implemented in a target-specific algorithm */
+#define CONFIG_CHARGING CHARGING_TARGET
+#define HAVE_POWEROFF_WHILE_CHARGING
/* define this if the unit can be powered or charged via USB */
#define HAVE_USB_POWER
diff --git a/firmware/export/config-e200.h b/firmware/export/config-e200.h
index 602a847..2be64d9 100644
--- a/firmware/export/config-e200.h
+++ b/firmware/export/config-e200.h
@@ -120,8 +120,9 @@
#define BATTERY_CAPACITY_INC 0 /* capacity increment */
#define BATTERY_TYPES_COUNT 1 /* only one type */
-/* Hardware controlled charging? FIXME */
-#define CONFIG_CHARGING CHARGING_SIMPLE
+/* Charging implemented in a target-specific algorithm */
+#define CONFIG_CHARGING CHARGING_TARGET
+#define HAVE_POWEROFF_WHILE_CHARGING
/* define current usage levels */
#define CURRENT_NORMAL 30 /* Toni's measurements in Nov 2008 */
diff --git a/firmware/export/powermgmt.h b/firmware/export/powermgmt.h
index 5be3a39..39e2e6e 100644
--- a/firmware/export/powermgmt.h
+++ b/firmware/export/powermgmt.h
@@ -27,7 +27,7 @@
enum charge_state_type
{
- /* sorted by increasing charging current */
+ /* sorted by increasing charging current (do not change!) */
#if CONFIG_CHARGING >= CHARGING_MONITOR
CHARGE_STATE_DISABLED = -2, /* Disable charger use (safety measure) */
CHARGE_STATE_ERROR = -1, /* Some error occurred that should not allow
@@ -143,13 +143,16 @@ unsigned int battery_voltage(void); /* filtered batt. voltage in millivolts */
#ifdef HAVE_BATTERY_SWITCH
unsigned int input_millivolts(void); /* voltage that device is running from */
+#endif /* HAVE_BATTERY_SWITCH */
+#if defined(HAVE_BATTERY_SWITCH) || defined(HAVE_RESET_BATTERY_FILTER)
/* Set the filtered battery voltage (to adjust it before beginning a charge
* cycle for instance where old, loaded readings will likely be invalid).
* Also readjust when battery switch is opened or closed.
*/
void reset_battery_filter(int millivolts);
-#endif /* HAVE_BATTERY_SWITCH */
+#endif /* HAVE_BATTERY_SWITCH || HAVE_RESET_BATTERY_FILTER */
+
/* read unfiltered battery info */
void battery_read_info(int *voltage, int *level);
diff --git a/firmware/powermgmt.c b/firmware/powermgmt.c
index f71eb45..3fc2160 100644
--- a/firmware/powermgmt.c
+++ b/firmware/powermgmt.c
@@ -435,7 +435,7 @@ bool query_force_shutdown(void)
#endif
}
-#ifdef HAVE_BATTERY_SWITCH
+#if defined(HAVE_BATTERY_SWITCH) || defined(HAVE_RESET_BATTERY_FILTER)
/*
* Reset the battery voltage filter to a new value and update the
* status.
diff --git a/firmware/target/arm/powermgmt-ascodec.c b/firmware/target/arm/powermgmt-ascodec.c
new file mode 100644
index 0000000..ab9fd7b
--- /dev/null
+++ b/firmware/target/arm/powermgmt-ascodec.c
@@ -0,0 +1,231 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2009 by Michael Sevakis
+ * Copyright (C) 2008 by Bertrik Sikken
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "config.h"
+#include "system.h"
+#include "thread.h"
+#include "as3514.h"
+#include "ascodec.h"
+#include "adc.h"
+#include "powermgmt.h"
+#include "power.h"
+
+/*===========================================================================
+ * These parameters may be defined per target:
+ *
+ * BATT_FULL_VOLTAGE - Upon connect a charge cycle begins if the reading is
+ * lower than this value (millivolts).
+ *
+ * BATT_VAUTO_RECHARGE - While left plugged after cycle completion, the
+ * charger restarts automatically if the reading drops
+ * below this value (millivolts). Must be less than
+ * BATT_FULL_VOLTAGE.
+ *
+ * ADC_BATTERY - ADC channel from which to read the battery voltage
+ *
+ * BATT_CHG_V - Charger voltage regulation setting (as3514 regval)
+ *
+ * BATT_CHG_I - Charger current regulation setting (as3514 regval)
+ *
+ * CHARGER_TOTAL_TIMER - Maximum allowed charging time (1/2-second steps)
+ *===========================================================================
+ */
+
+/* This code assumes USB power input is not distinguishable from main
+ * power and charger connect cannot wait for USB configuration before
+ * considering USB charging available. Where they are distinguishable,
+ * things get more complicated. */
+static bool charger_close = false; /* Shutting down? */
+static int charger_total_timer = 0; /* Timeout in algorithm steps */
+
+/* Current battery threshold for (re)charge:
+ * First plugged = BATT_FULL_VOLTAGE
+ * After charge cycle or non-start = BATT_VAUTO_RECHARGE
+ */
+static unsigned int batt_threshold = 0;
+
+/* ADC should read 0x3ff=5.12V */
+/* full-scale ADC readout (2^10) in millivolt */
+
+/* Returns battery voltage from ADC [millivolts] */
+unsigned int battery_adc_voltage(void)
+{
+ return (adc_read(ADC_BATTERY) * 5125 + 512) >> 10;
+}
+
+/* Returns true if the unit is charging the batteries. */
+bool charging_state(void)
+{
+ return charge_state == CHARGING;
+}
+
+/* Reset the battery filter to a new voltage */
+static void battery_voltage_sync(void)
+{
+ int i;
+ unsigned int mv;
+
+ for (i = 0, mv = 0; i < 5; i++)
+ mv += battery_adc_voltage();
+
+ reset_battery_filter(mv / 5);
+}
+
+/* Disable charger and minimize all settings. Reset timers, etc. */
+static void disable_charger(void)
+{
+ ascodec_write(AS3514_IRQ_ENRD0, 0);
+ ascodec_write(AS3514_CHARGER,
+ TMPSUP_OFF | CHG_I_50MA | CHG_V_3_90V | CHG_OFF);
+
+ if (charge_state > DISCHARGING)
+ charge_state = DISCHARGING; /* Not an error state already */
+
+ charger_total_timer = 0;
+ battery_voltage_sync();
+}
+
+/* Enable charger with specified settings. Start timers, etc. */
+static void enable_charger(void)
+{
+ ascodec_write(AS3514_CHARGER, BATT_CHG_I | BATT_CHG_V);
+ /* Watch for end of charge. Temperature supervision is handled in
+ * hardware. Charger status can be read and has no interrupt enable. */
+ ascodec_write(AS3514_IRQ_ENRD0, CHG_ENDOFCH);
+
+ sleep(HZ/10); /* Allow charger turn-on time (it could be gradual). */
+
+ ascodec_read(AS3514_IRQ_ENRD0); /* Clear out interrupts (important!) */
+
+ charge_state = CHARGING;
+ charger_total_timer = CHARGER_TOTAL_TIMER;
+ battery_voltage_sync();
+}
+
+void powermgmt_init_target(void)
+{
+ /* Everything CHARGER, OFF! */
+ ascodec_write(AS3514_IRQ_ENRD0, 0);
+ ascodec_write(AS3514_CHARGER,
+ TMPSUP_OFF | CHG_I_50MA | CHG_V_3_90V | CHG_OFF);
+}
+
+static inline void charger_plugged(void)
+{
+ batt_threshold = BATT_FULL_VOLTAGE; /* Start with topped value. */
+ battery_voltage_sync();
+}
+
+static inline void charger_control(void)
+{
+ switch (charge_state)
+ {
+ case DISCHARGING:
+ {
+ unsigned int millivolts;
+ unsigned int thresh = batt_threshold;
+
+ if (BATT_FULL_VOLTAGE == thresh)
+ {
+ /* Wait for CHG_status to be indicated. */
+ if ((ascodec_read(AS3514_IRQ_ENRD0) & CHG_STATUS) == 0)
+ break;
+
+ batt_threshold = BATT_VAUTO_RECHARGE;
+ }
+
+ millivolts = battery_voltage();
+
+ if (millivolts <= thresh)
+ enable_charger();
+ break;
+ } /* DISCHARGING: */
+
+ case CHARGING:
+ {
+ if ((ascodec_read(AS3514_IRQ_ENRD0) & CHG_ENDOFCH) == 0)
+ {
+ if (--charger_total_timer > 0)
+ break;
+
+ /* Timer ran out - require replug. */
+ charge_state = CHARGE_STATE_ERROR;
+ }
+ /* else end of charge */
+
+ disable_charger();
+ break;
+ } /* CHARGING: */
+
+ default:
+ /* DISABLED, ERROR */
+ break;
+ }
+}
+
+static inline void charger_unplugged(void)
+{
+ disable_charger();
+ if (charge_state >= CHARGE_STATE_ERROR)
+ charge_state = DISCHARGING; /* Reset error */
+}
+
+/* Main charging algorithm - called from powermgmt.c */
+void charging_algorithm_step(void)
+{
+ switch (charger_input_state)
+ {
+ case NO_CHARGER:
+ /* Nothing to do */
+ break;
+
+ case CHARGER_PLUGGED:
+ charger_plugged();
+ break;
+
+ case CHARGER:
+ charger_control();
+ break;
+
+ case CHARGER_UNPLUGGED:
+ charger_unplugged();
+ break;
+ }
+
+ if (charger_close)
+ {
+ /* Disable further charging and ack. */
+ charge_state = CHARGE_STATE_DISABLED;
+ disable_charger();
+ charger_close = false;
+ }
+}
+
+/* Disable the charger and prepare for poweroff - called off-thread so we
+ * signal the charging thread to prepare to quit. */
+void charging_algorithm_close(void)
+{
+ charger_close = true;
+
+ /* Power management thread will set it false again. */
+ while (charger_close)
+ sleep(HZ/10);
+}
diff --git a/firmware/target/arm/sandisk/powermgmt-target.h b/firmware/target/arm/sandisk/powermgmt-target.h
new file mode 100644
index 0000000..aa6a0e0
--- /dev/null
+++ b/firmware/target/arm/sandisk/powermgmt-target.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2009 by Michael Sevakis
+ * Copyright (C) 2008 by Bertrik Sikken
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef POWERMGMT_TARGET_H
+#define POWERMGMT_TARGET_H
+
+#if defined(SANSA_C200)
+/* This configuration triggers a single charge cycle upon plugging and stops.
+ * The true voltage cannot be read accurately and so monitoring isn't really
+ * possible. The battery filter is still synced to have a proper reading
+ * when disconnecting. */
+#define BATT_FULL_VOLTAGE 5121 /* Won't read this high - force start */
+#define BATT_VAUTO_RECHARGE 0 /* Won't read this low - force one cycle */
+#define BATT_CHG_V CHG_V_4_20V
+#define BATT_CHG_I CHG_I_300MA
+#define CHARGER_TOTAL_TIMER (4*3600*2) /* 4 hours enough? */
+#define ADC_BATTERY ADC_BVDD
+#elif defined(SANSA_E200)
+/* PREFERRED - Check if topped-off and monitor voltage while plugged. */
+#define BATT_FULL_VOLTAGE 4160
+#define BATT_VAUTO_RECHARGE 4100
+#define BATT_CHG_V CHG_V_4_20V
+#define BATT_CHG_I CHG_I_300MA
+#define CHARGER_TOTAL_TIMER (4*3600*2) /* 4 hours enough? */
+/* On e200 ADC_RTCSUP seems to represent battery voltage better than
+ * ADC_BVDD during charging (ADC_BVDD is way too high) and appears the
+ * same in normal use.
+ */
+#define ADC_BATTERY ADC_RTCSUP
+#endif
+
+void powermgmt_init_target(void);
+void charging_algorithm_step(void);
+void charging_algorithm_close(void);
+
+/* We want to be able to reset the averaging filter */
+#define HAVE_RESET_BATTERY_FILTER
+
+#define BATT_AVE_SAMPLES 32
+
+#endif /* POWERMGMT_TARGET_H */
diff --git a/firmware/target/arm/sandisk/sansa-c200/powermgmt-c200.c b/firmware/target/arm/sandisk/sansa-c200/powermgmt-c200.c
index 963e721..9d7a0e2 100644
--- a/firmware/target/arm/sandisk/sansa-c200/powermgmt-c200.c
+++ b/firmware/target/arm/sandisk/sansa-c200/powermgmt-c200.c
@@ -38,8 +38,8 @@ const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] =
const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] =
{
+ /* NOTE: why is the top voltage 4237? That's just too high. */
{ 3286, 3679, 3734, 3764, 3788, 3824, 3886, 3950, 4014, 4098, 4237 },
-
};
/* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */
@@ -48,14 +48,3 @@ const unsigned short percent_to_volt_charge[11] =
/* Sansa c200 has a 530 mAh LiPo battery */
3300, 3390, 3480, 3570, 3660, 3750, 3840, 3930, 4020, 4110, 4200
};
-
-/* ADC should read 0x3ff=5.12V */
-#define BATTERY_SCALE_FACTOR 5125
-/* full-scale ADC readout (2^10) in millivolt */
-
-/* Returns battery voltage from ADC [millivolts] */
-unsigned int battery_adc_voltage(void)
-{
- return (adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR) >> 10;
-}
-
diff --git a/firmware/target/arm/sandisk/sansa-e200/powermgmt-e200.c b/firmware/target/arm/sandisk/sansa-e200/powermgmt-e200.c
index 43f3746..144ca37 100644
--- a/firmware/target/arm/sandisk/sansa-e200/powermgmt-e200.c
+++ b/firmware/target/arm/sandisk/sansa-e200/powermgmt-e200.c
@@ -47,14 +47,3 @@ const unsigned short percent_to_volt_charge[11] =
/* Sansa Li Ion 750mAH FIXME */
3300, 3680, 3740, 3760, 3780, 3810, 3870, 3930, 3970, 4070, 4160
};
-
-/* ADC should read 0x3ff=5.12V */
-#define BATTERY_SCALE_FACTOR 5125
-/* full-scale ADC readout (2^10) in millivolt */
-
-/* Returns battery voltage from ADC [millivolts] */
-unsigned int battery_adc_voltage(void)
-{
- return (adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR) >> 10;
-}
-