diff -u -urN osmocom-bb.120404/src/target/firmware/Makefile osmocom-bb.120501/src/target/firmware/Makefile
--- osmocom-bb.120404/src/target/firmware/Makefile	2013-02-15 10:31:40.000000000 +0100
+++ osmocom-bb.120501/src/target/firmware/Makefile	2013-02-04 13:45:45.000000000 +0100
@@ -9,7 +9,8 @@
 # Framebuffer support, board specific drivers
 # 	
 
-FB_OBJS=fb/framebuffer.o fb/font.o fb/helvR08.o fb/helvB14.o fb/c64.o
+FB_OBJS=fb/framebuffer.o fb/font.o fb/helvR08.o fb/helvB14.o fb/c64.o \
+	fb/symbols.o
 
 FB_e88_OBJS=$(FB_OBJS) fb/fb_bw8.o fb/fb_st7558.o
 FB_e99_OBJS=$(FB_OBJS) fb/fb_rgb332.o fb/fb_ssd1783.o
@@ -24,12 +25,14 @@
 
 # OpenMoko GTA0x
 
-gta0x_OBJS=$(calypso_COMMON_OBJS) board/gta0x/rffe_gta0x_triband.o board/gta0x/init.o board/gta0x/rf_power.o $(FB_dummy_OBJS)
+gta0x_OBJS=$(calypso_COMMON_OBJS) board/gta0x/rffe_gta0x_triband.o board/gta0x/init.o \
+	board/gta0x/rf_power.o battery/dummy.o $(FB_dummy_OBJS)
 gta0x_ENVIRONMENTS=highram
 
 # Pirelli DP-L10
 
-pirelli_dpl10_OBJS=$(calypso_COMMON_OBJS) board/pirelli_dpl10/rffe_dpl10_triband.o board/pirelli_dpl10/init.o board/pirelli_dpl10/rf_power.o $(FB_dpl10_OBJS)
+pirelli_dpl10_OBJS=$(calypso_COMMON_OBJS) board/pirelli_dpl10/rffe_dpl10_triband.o board/pirelli_dpl10/init.o \
+		board/pirelli_dpl10/rf_power.o battery/dummy.o $(FB_dpl10_OBJS)
 pirelli_dpl10_ENVIRONMENTS=highram
 
 # Compal Generic
@@ -45,7 +48,7 @@
 
 # Compal E88
 
-compal_e88_OBJS=$(compal_COMMON_OBJS) board/compal_e88/init.o $(FB_e88_OBJS)
+compal_e88_OBJS=$(compal_COMMON_OBJS) board/compal_e88/init.o battery/compal_e88.o $(FB_e88_OBJS)
 compal_e88_ENVIRONMENTS=$(compal_COMMON_ENVIRONMENTS) e88loader e88flash
 
 e88loader_LDS=board/compal_e88/loader.lds
@@ -56,12 +59,13 @@
 
 # Compal E86 (has a different RFFE configuration)
 
-compal_e86_OBJS=$(calypso_COMMON_OBJS) board/compal_e86/rffe_dualband_e86.o board/compal/rf_power.o board/compal_e86/init.o $(FB_e86_OBJS)
+compal_e86_OBJS=$(calypso_COMMON_OBJS) board/compal_e86/rffe_dualband_e86.o board/compal/rf_power.o \
+			board/compal_e86/init.o battery/dummy.o $(FB_e86_OBJS)
 compal_e86_ENVIRONMENTS=$(compal_COMMON_ENVIRONMENTS)
 
 # Compal E99
 
-compal_e99_OBJS=$(compal_COMMON_OBJS) board/compal_e99/init.o $(FB_e99_OBJS)
+compal_e99_OBJS=$(compal_COMMON_OBJS) board/compal_e99/init.o battery/dummy.o $(FB_e99_OBJS)
 compal_e99_ENVIRONMENTS=$(compal_COMMON_ENVIRONMENTS)
 
 e99loader_LDS=board/compal_e99/loader.lds
@@ -70,7 +74,7 @@
 
 # Sony Ericsson J100 (made by Compal)
 
-se_j100_OBJS=$(compal_COMMON_OBJS) board/se_j100/init.o $(FB_j100_OBJS)
+se_j100_OBJS=$(compal_COMMON_OBJS) board/se_j100/init.o battery/dummy.o $(FB_j100_OBJS)
 se_j100_ENVIRONMENTS=$(compal_COMMON_ENVIRONMENTS)
 
 # Global include path
diff -u -urN osmocom-bb.120404/src/target/firmware/apps/hello_world/main.c osmocom-bb.120501/src/target/firmware/apps/hello_world/main.c
--- osmocom-bb.120404/src/target/firmware/apps/hello_world/main.c	2013-02-15 10:31:40.000000000 +0100
+++ osmocom-bb.120501/src/target/firmware/apps/hello_world/main.c	2013-02-04 13:45:45.000000000 +0100
@@ -41,6 +41,7 @@
 #include <comm/sercomm.h>
 #include <comm/timer.h>
 #include <fb/framebuffer.h>
+#include <battery/battery.h>
 
 /* Main Program */
 const char *hr = "======================================================================\n";
@@ -67,6 +68,36 @@
 	puts("\n");
 }
 
+void
+write_battery_info(void *p){
+	char buf[128];
+
+	fb_setfg(FB_COLOR_WHITE);
+	fb_setfont(FB_FONT_C64);
+
+	snprintf(buf,sizeof(buf),"B: %04d mV",battery_info.bat_volt_mV);
+	fb_gotoxy(8,41);
+	fb_putstr(buf,framebuffer->width-8);
+
+	snprintf(buf,sizeof(buf),"C: %04d mV",battery_info.charger_volt_mV);
+	fb_gotoxy(8,49);
+	fb_putstr(buf,framebuffer->width-8);
+
+	snprintf(buf,sizeof(buf),"F: %08x",battery_info.flags);
+	fb_gotoxy(8,57);
+	fb_putstr(buf,framebuffer->width-8);
+
+	fb_flush();
+	osmo_timer_schedule((struct osmo_timer_list*)p,100);
+
+}
+
+/* timer that fires the charging loop regularly */
+static struct osmo_timer_list write_battery_info_timer = {
+	.cb = &write_battery_info,
+	.data = &write_battery_info_timer
+};
+
 int main(void)
 {
 	board_init();
@@ -123,6 +154,8 @@
 	sercomm_register_rx_cb(SC_DLCI_CONSOLE, console_rx_cb);
 	sercomm_register_rx_cb(SC_DLCI_L1A_L23, l1a_l23_rx_cb);
 
+	osmo_timer_schedule(&write_battery_info_timer,100);
+
 	/* beyond this point we only react to interrupts */
 	puts("entering interrupt loop\n");
 	while (1) {
diff -u -urN osmocom-bb.120404/src/target/firmware/apps/rssi/main.c osmocom-bb.120501/src/target/firmware/apps/rssi/main.c
--- osmocom-bb.120404/src/target/firmware/apps/rssi/main.c	2013-02-15 10:31:40.000000000 +0100
+++ osmocom-bb.120501/src/target/firmware/apps/rssi/main.c	2013-02-04 13:45:45.000000000 +0100
@@ -50,6 +50,7 @@
 #include <osmocom/gsm/rsl.h>
 #include <osmocom/gsm/protocol/gsm_04_08.h>
 #include <osmocom/gsm/gsm48_ie.h>
+#include <battery/battery.h>
 
 enum key_codes key_code = KEY_INV;
 int key_pressed = 0;
@@ -170,6 +171,7 @@
 static void refresh_display(void)
 {
 	char text[16];
+	int bat = battery_info.battery_percent;
 
 	fb_clear();
 
@@ -179,9 +181,25 @@
 		fb_setfg(FB_COLOR_BLUE);
 		fb_setfont(FB_FONT_HELVR08);
 		fb_gotoxy(0, 7);
-		fb_putstr("Osmocom Monitor Tool", -1);
-		fb_gotoxy(0, 10);
+		fb_putstr("Osmocom RSSI", -1);
+		fb_setfg(FB_COLOR_RGB(0xc0, 0xc0, 0x00));
+		fb_setfont(FB_FONT_SYMBOLS);
+		fb_gotoxy(framebuffer->width - 15, 8);
+		if (bat >= 100 && (battery_info.flags & BATTERY_CHG_ENABLED)
+		 && !(battery_info.flags & BATTERY_CHARGING))
+			fb_putstr("@HHBC", framebuffer->width);
+		else {
+			sprintf(text, "@%c%c%cC", (bat >= 30) ? 'B':'A',
+				(bat >= 60) ? 'B':'A', (bat >= 90) ? 'B':'A');
+			fb_putstr(text, framebuffer->width);
+		}
+		fb_gotoxy(0, 8);
+		sprintf(text, "%c%cE%c%c", (power >= 40) ? 'D':'G',
+			(power >= 10) ? 'D':'G', (power >= 10) ? 'F':'G',
+			(power >= 40) ? 'F':'G');
+		fb_putstr(text, framebuffer->width);
 		fb_setfg(FB_COLOR_GREEN);
+		fb_gotoxy(0, 10);
 		fb_boxto(framebuffer->width - 1, 10);
 	}
 	fb_setfg(FB_COLOR_BLACK);
diff -u -urN osmocom-bb.120404/src/target/firmware/battery/compal_e88.c osmocom-bb.120501/src/target/firmware/battery/compal_e88.c
--- osmocom-bb.120404/src/target/firmware/battery/compal_e88.c	1970-01-01 01:00:00.000000000 +0100
+++ osmocom-bb.120501/src/target/firmware/battery/compal_e88.c	2013-02-04 13:42:14.000000000 +0100
@@ -0,0 +1,384 @@
+/* Battery management for compal_e88 */
+
+/* (C) 2010 by Christian Vogel <vogelchr@vogel.cx>
+ *
+ * All Rights Reserved
+ *
+ * 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+/*
+ * ___C123 (compal e88) very simplified diagram of charging circuitry___
+ *
+ *                           ICTL
+ *                            |
+ *                            v
+ *  Charger -> OVP -------> P-Mosfet --->[0.15 Ohm]---> Battery
+ *             (NCP345,  |             |            |
+ *              6.85V)   v             v            v
+ *                      VCHG          VCCS        VBAT &
+ *                                                VBATS
+ *
+ * Inputs to IOTA:
+ *  VCHG:        senses voltage on the charger input
+ *  VCSS/VBATS:  to difference amplifier, to measure charge current
+ *  VBAT:        senses voltage on the battery terminal
+ * Outputs from IOTA:
+ *  ICTL:        Control signal for the switching mosfet
+ *
+ */
+
+#include <battery/battery.h>
+#include <battery/compal_e88.h>
+
+#include <stdint.h>
+#include <abb/twl3025.h>
+#include <comm/timer.h>
+#include <stdio.h>
+
+/* ADC calibration, scale is LSB/uV or LSB/uA, physical unit is mV or mA */
+#define ADC_TO_PHYSICAL(adc,scale) (((adc)*(scale)+500)/1000)
+#define PHYSICAL_TO_ADC(phy,scale) (((phy)*1000+(scale)/2)/(scale))
+
+/* conversion factors for internal IOTA battery charging/sensing circuitry */
+#define VREF_LSB_uV 1709  /* VREF = 1.75V    --> 1.709 mV/LSB */
+#define VBAT_LSB_uV 6836  /* VBAT = 7.0 V FS --> 6.836 mV/LSB */
+#define VCHG_LSB_uV 8545  /* VCHG = 8.75V FS --> 8.545 mV/LSB */
+#define ICHG_LSB_uA 854   /* ICHG = 875mA FS --> 0.854 mA/LSB */
+
+/* battery is considered full/empty at these thresholds... */
+#define VBAT_full   PHYSICAL_TO_ADC(4000,VBAT_LSB_uV)
+#define VBAT_empty  PHYSICAL_TO_ADC(3200,VBAT_LSB_uV)
+
+/* we declare overvoltage at this point... */
+#define VBAT_fail   PHYSICAL_TO_ADC(4250,VBAT_LSB_uV)
+
+/* DAC to ADC offsets in CC mode with my C123 
+   IMEI 358317015976471, P329431014
+
+   I/mA DAC     ADC
+   ----------------
+   100	117	108
+   150	176	168
+   200	234	227
+   250	293	291
+   300	351	349
+   350	410	410
+*/
+
+#define CHGDAC_GAIN   967  /* times 0.001 */
+#define CHGDAC_OFFS    13
+
+/* convert ADC reading to DAC value, according to calibration values
+   given above */
+#define CHGDAC_ADJ(x)   (CHGDAC_GAIN*(x)/1000+CHGDAC_OFFS)
+
+/* charging current in DAC LSBs, same ref. and # of bits, but keep
+   the correction specified above in mind!  */
+
+#define ICHG_set    CHGDAC_ADJ(PHYSICAL_TO_ADC(200,ICHG_LSB_uA))
+#define VCHG_set    CHGDAC_ADJ(VBAT_full)
+
+struct battery_info battery_info;	/* global battery info */
+uint16_t bat_compal_e88_madc[MADC_NUM_CHANNELS];	/* MADC measurements */
+
+static const int BATTERY_TIMER_DELAY=5000; /* 5000ms for control loop */
+static const int ADC_TIMER_DELAY=100;      /*  100ms for ADC conversion */
+
+/* thermistor sense current, turn it up to eleven! */
+#define  TH_SENS               (THSENS0|THSENS1|THSENS2|THEN)
+#define  BATTERY_ALL_SENSE     (TH_SENS|MESBAT|TYPEN)
+
+/*
+ * charger modes state machine
+ *
+ *    +------------------+-------------------+
+ *    |                  |                   | lost AC power
+ *    |                  ^                   ^
+ *    V  on AC power     |    @VBAT_full     |
+ * +-----+        +------------+ -----> +------------+
+ * | OFF | -----> | CONST_CURR |        | CONST_VOLT |
+ * +-----+        +------------+        +------------+
+ *    ^          ^        |                   |
+ *    |         /failure  v                   v failure
+ * +---------+ /  gone    |                   | condition
+ * | FAILURE | <----------+-------------------+
+ * +---------+
+ *
+ *  Failure modes currently detected:
+ *          + high battery voltage
+ *  Failure modes TODO:
+ *          + high battery temperature
+ */
+enum bat_compal_e88_chg_state {
+	CHARG_OFF,
+	CHARG_CONST_CURR,
+	CHARG_CONST_VOLT,
+	CHARG_FAIL
+};
+static enum bat_compal_e88_chg_state bat_compal_e88_chg_state;
+
+static const char *bat_compal_e88_chg_state_names[]={
+	"Off",
+	"Constant Current",
+	"Constant Voltage",
+	"Battery Failure"
+};
+
+static void
+bat_compal_e88_goto_state(enum bat_compal_e88_chg_state newstate){
+
+	if(bat_compal_e88_chg_state == newstate) /* already there? */
+		return;
+
+	printf("\033[34;1mCHARGER: %s --> %s.\033[0m\n",
+			bat_compal_e88_chg_state_names[bat_compal_e88_chg_state],
+			bat_compal_e88_chg_state_names[newstate]);
+
+	/* update user visible flags, set registers */
+	switch(newstate){
+	case CHARG_CONST_CURR:
+		battery_info.flags &= ~BATTERY_FAILURE;
+		battery_info.flags |= (BATTERY_CHG_ENABLED|
+						BATTERY_CHARGING);
+		twl3025_reg_write(BCICTL2,0);
+		twl3025_reg_write(CHGREG,0);
+		twl3025_reg_write(BCICTL2,CHEN|LEDC|CHIV);
+		twl3025_reg_write(CHGREG,ICHG_set);
+
+		break;
+
+	case CHARG_CONST_VOLT:
+		battery_info.flags &= ~( BATTERY_CHARGING |
+						BATTERY_FAILURE );
+		battery_info.flags |= BATTERY_CHG_ENABLED;
+		twl3025_reg_write(BCICTL2,0);
+		twl3025_reg_write(CHGREG,0);
+		twl3025_reg_write(BCICTL2,CHEN|LEDC);
+		twl3025_reg_write(CHGREG,VCHG_set);
+		break;
+
+	case CHARG_FAIL:
+	case CHARG_OFF:
+	default:
+		battery_info.flags &= ~( BATTERY_CHG_ENABLED |
+			BATTERY_CHARGING | BATTERY_FAILURE );
+		twl3025_reg_write(BCICTL2,0); /* turn off charger */
+		twl3025_reg_write(CHGREG,0);
+		break;
+	}
+
+	printf("BCICTL2 is 0x%03x, CHGREG=%d\n",
+			twl3025_reg_read(BCICTL2),
+			twl3025_reg_read(CHGREG));
+
+	bat_compal_e88_chg_state = newstate;
+}
+
+static void
+bat_compal_e88_chg_control(){
+	/* with AC power disconnected, always go to off state */
+	if(!(battery_info.flags & BATTERY_CHG_CONNECTED)){
+		bat_compal_e88_goto_state(CHARG_OFF);
+		return;
+	}
+
+	/* if failure condition is detected, always goto failure state */
+	if(bat_compal_e88_madc[MADC_VBAT] > VBAT_fail){
+		bat_compal_e88_goto_state(CHARG_FAIL);
+		return;
+	}
+
+	/* now AC power is present and battery is not over failure
+	   thresholds */
+	switch(bat_compal_e88_chg_state){
+	case CHARG_OFF:
+		if(bat_compal_e88_madc[MADC_VBAT] >= VBAT_full)
+			bat_compal_e88_goto_state(CHARG_CONST_VOLT);
+		else
+			bat_compal_e88_goto_state(CHARG_CONST_CURR);
+		break;
+	case CHARG_CONST_CURR:
+		if(bat_compal_e88_madc[MADC_VBAT] >= VBAT_full)
+			bat_compal_e88_goto_state(CHARG_CONST_VOLT);
+		break;
+	case CHARG_CONST_VOLT:
+		break;
+	default:
+	case CHARG_FAIL:
+		if(bat_compal_e88_madc[MADC_VBAT] < VBAT_full)
+			bat_compal_e88_goto_state(CHARG_CONST_CURR);
+		break;
+	}
+}
+
+/*
+ * Charging voltage connection - state machine, remembers
+ * state in battery_info.flags.
+ *
+ *                     VCHG > VCHG_thr_on
+ * +-----------------+ ------------------> +---------------+
+ * | ! CHG_CONNECTED |                     | CHG_CONNECTED |
+ * +-----------------+ <------------------ +---------------+
+ *                     VCHG < VCHG_thr_off
+ */
+static void
+bat_compal_e88_chk_ac_presence(){
+	int vrpcsts = twl3025_reg_read(VRPCSTS);
+
+	/* check for presence of charging voltage */
+	if(!(battery_info.flags & BATTERY_CHG_CONNECTED)){
+		if(vrpcsts & CHGPRES){
+			puts("\033[34;1mCHARGER: external voltage connected!\033[0m\n");
+			battery_info.flags |= BATTERY_CHG_CONNECTED;
+
+			/* always keep ADC, voltage dividers and bias voltages on */
+			twl3025_unit_enable(TWL3025_UNIT_MAD,1);
+			twl3025_reg_write(BCICTL1,BATTERY_ALL_SENSE);
+		}
+	} else {
+		if(!(vrpcsts & CHGPRES)){
+			/* we'll only run ADC on demand */
+			twl3025_unit_enable(TWL3025_UNIT_MAD,0);
+			twl3025_reg_write(BCICTL1,0);
+
+			battery_info.flags &= ~ BATTERY_CHG_CONNECTED;
+			puts("\033[34;1mCHARGER: external voltage disconnected!\033[0m\n");
+		}
+	}
+}
+
+/* ---- update voltages visible to the user ---- */
+static void
+bat_compal_e88_upd_measurements(){
+	int adc,i;
+
+	battery_info.charger_volt_mV=
+		ADC_TO_PHYSICAL(bat_compal_e88_madc[MADC_VCHG],VCHG_LSB_uV);
+	battery_info.bat_volt_mV=
+		ADC_TO_PHYSICAL(bat_compal_e88_madc[MADC_VBAT],VBAT_LSB_uV);
+	battery_info.bat_chg_curr_mA=
+		ADC_TO_PHYSICAL(bat_compal_e88_madc[MADC_ICHG],ICHG_LSB_uA);
+
+	adc = bat_compal_e88_madc[MADC_VBAT];
+	if(adc <= VBAT_empty){			/* battery 0..100% */
+		battery_info.battery_percent = 0;
+	} else if (adc >= VBAT_full){
+		battery_info.battery_percent = 100;
+	} else {
+		battery_info.battery_percent =
+			(50+100*(adc-VBAT_empty))/(VBAT_full-VBAT_empty);
+	}
+
+        /* DEBUG */
+        printf("BAT-ADC: ");
+        for(i=0;i<MADC_NUM_CHANNELS;i++)
+                printf("%3d ",bat_compal_e88_madc[i]);
+        printf("%c\n",32);
+        printf("\tCharger at %u mV.\n",battery_info.charger_volt_mV);
+        printf("\tBattery at %u mV.\n",battery_info.bat_volt_mV);
+        printf("\tCharging at %u mA.\n",battery_info.bat_chg_curr_mA);
+        printf("\tBattery capacity is %u%%.\n",battery_info.battery_percent);
+	printf("\tBattery range is %d..%d mV.\n",
+		ADC_TO_PHYSICAL(VBAT_empty,VBAT_LSB_uV),
+		ADC_TO_PHYSICAL(VBAT_full,VBAT_LSB_uV));
+        printf("\tBattery full at %d LSB .. full at %d LSB\n",VBAT_empty,VBAT_full);
+        printf("\tCharging at %d LSB (%d mA).\n",ICHG_set,
+                ADC_TO_PHYSICAL(ICHG_set,ICHG_LSB_uA));
+        i = twl3025_reg_read(BCICTL2);
+        printf("\tBCICTL2=0x%03x\n",i);      
+	printf("\tbattery-info.flags=0x%08x\n",battery_info.flags);
+	printf("\tbat_compal_e88_chg_state=%d\n",bat_compal_e88_chg_state);
+}
+
+/* bat_compal_e88_adc_read() :
+ *
+ * Schedule a ADC conversion or read values from ADC. If we are
+ * running on battery, bias currents/voltage dividers are turned
+ * on on demand.
+ *
+ * Return 0 if new ADC values have been acquired, 1 if ADC
+ * has been scheduled for a new conversion or is not yet finished.
+ * 
+ */
+
+enum bat_compal_e88_madc_stat {
+	ADC_CONVERSION = 1 << 0
+};
+static uint32_t bat_compal_e88_madc_stat=0;
+
+static int
+bat_compal_e88_adc_read(){
+	int i;
+
+	if(bat_compal_e88_madc_stat & ADC_CONVERSION){
+		i = twl3025_reg_read(MADCSTAT);
+		if(i & ADCBUSY)
+			return 1;
+		for(i=0;i<MADC_NUM_CHANNELS;i++)
+			bat_compal_e88_madc[i]=twl3025_reg_read(VBATREG+i);
+		/* if charger is connected, we keep the ADC and BIAS on
+		   continuously, if running on battery, we try to save power */
+		if(!(battery_info.flags & BATTERY_CHG_CONNECTED)){
+			twl3025_reg_write(BCICTL1,0x00); /* turn off bias */
+			twl3025_unit_enable(TWL3025_UNIT_MAD,0); /* & ADC */
+		}
+		bat_compal_e88_madc_stat &= ~ ADC_CONVERSION;
+		return 0;
+	} else {
+		/* if running on battery, turn on ADC & BIAS on demand */
+		if(!(battery_info.flags & BATTERY_CHG_CONNECTED)){
+			twl3025_unit_enable(TWL3025_UNIT_MAD,1);
+			twl3025_reg_write(BCICTL1,BATTERY_ALL_SENSE);
+		}
+
+		twl3025_reg_write(MADCTRL,0xff); /* convert all channels */
+		twl3025_reg_write(VBATREG,0);    /* trigger conversion */
+
+		bat_compal_e88_madc_stat |= ADC_CONVERSION;
+		return 1;
+	}
+}
+
+static void
+battery_compal_e88_timer_cb(void *p){
+	struct osmo_timer_list *tmr = (struct osmo_timer_list*)p;
+	int i;
+
+	if(bat_compal_e88_adc_read()){ /* read back ADCs after a brief delay */
+		osmo_timer_schedule(tmr,ADC_TIMER_DELAY);
+		return;
+	}
+
+	bat_compal_e88_upd_measurements();	/* convert user-accessible information */
+	bat_compal_e88_chk_ac_presence();	/* detect AC charger presence */
+	bat_compal_e88_chg_control();	/* battery charger state machine */
+
+	osmo_timer_schedule(tmr,BATTERY_TIMER_DELAY);
+}
+
+/* timer that fires the charging loop regularly */
+static struct osmo_timer_list battery_compal88_timer = {
+	.cb = &battery_compal_e88_timer_cb,
+	.data = &battery_compal88_timer
+};
+
+void
+battery_compal_e88_init(){
+	printf("%s: starting up\n",__FUNCTION__);
+	osmo_timer_schedule(&battery_compal88_timer,BATTERY_TIMER_DELAY);
+}
+
diff -u -urN osmocom-bb.120404/src/target/firmware/battery/dummy.c osmocom-bb.120501/src/target/firmware/battery/dummy.c
--- osmocom-bb.120404/src/target/firmware/battery/dummy.c	1970-01-01 01:00:00.000000000 +0100
+++ osmocom-bb.120501/src/target/firmware/battery/dummy.c	2013-02-04 13:42:14.000000000 +0100
@@ -0,0 +1,9 @@
+#include <battery/battery.h>
+
+/* Battery Management: Dummy file when no charging logic exists. */
+struct battery_info battery_info;
+
+void battery_dummy_init(){
+	battery_info.flags = BATTERY_FAILURE; /* not implemented */
+}
+
diff -u -urN osmocom-bb.120404/src/target/firmware/board/compal_e88/init.c osmocom-bb.120501/src/target/firmware/board/compal_e88/init.c
--- osmocom-bb.120404/src/target/firmware/board/compal_e88/init.c	2013-02-15 10:31:40.000000000 +0100
+++ osmocom-bb.120501/src/target/firmware/board/compal_e88/init.c	2013-02-04 13:45:45.000000000 +0100
@@ -45,6 +45,7 @@
 #include <abb/twl3025.h>
 #include <rf/trf6151.h>
 #include <fb/framebuffer.h>
+#include <battery/compal_e88.h>
 
 #define ARMIO_LATCH_OUT 0xfffe4802
 #define IO_CNTL_REG	0xfffe4804
@@ -133,4 +134,7 @@
 
 	/* Initialize ABB driver (uses SPI) */
 	twl3025_init();
+
+	/* Initialize the charging controller */
+	battery_compal_e88_init();
 }
diff -u -urN osmocom-bb.120404/src/target/firmware/fb/font.c osmocom-bb.120501/src/target/firmware/fb/font.c
--- osmocom-bb.120404/src/target/firmware/fb/font.c	2013-02-15 10:31:40.000000000 +0100
+++ osmocom-bb.120501/src/target/firmware/fb/font.c	2013-02-04 13:42:14.000000000 +0100
@@ -32,6 +32,7 @@
 extern const struct fb_font font_helvB14;
 // extern const struct fb_font font_helvB24;
 extern const struct fb_font font_c64;
+extern const struct fb_font font_symbols;
 
 const struct fb_font *fb_fonts[]={
 //	&font_4x6,
@@ -43,6 +44,7 @@
 	&font_helvB14,
 //	&font_helvB24,
 	&font_c64,
+	&font_symbols,
 };
 
 const struct fb_char *
diff -u -urN osmocom-bb.120404/src/target/firmware/fb/symbols.c osmocom-bb.120501/src/target/firmware/fb/symbols.c
--- osmocom-bb.120404/src/target/firmware/fb/symbols.c	1970-01-01 01:00:00.000000000 +0100
+++ osmocom-bb.120501/src/target/firmware/fb/symbols.c	2013-02-04 13:42:14.000000000 +0100
@@ -0,0 +1,113 @@
+#include <fb/font.h>
+static const uint8_t font_symbols_data[] = {
+/* @ battery - */
+	/*0000:*/	3, 3, 8, 0, 0, /* width and bbox (w,h,x,y) */
+	/*0005:*/	0x60,	/* .##..... */
+	/*0006:*/	0x40,	/* .#...... */
+	/*0007:*/	0x40,	/* .#...... */
+	/*0008:*/	0x40,	/* .#...... */
+	/*0009:*/	0x40,	/* .#...... */
+	/*000a:*/	0x40,	/* .#...... */
+	/*000b:*/	0x40,	/* .#...... */
+	/*000c:*/	0x60,	/* .##..... */
+/* A battery empty */
+	/*000d:*/	3, 3, 8, 0, 0, /* width and bbox (w,h,x,y) */
+	/*0012:*/	0xe0,	/* ###..... */
+	/*0013:*/	0x00,	/* ........ */
+	/*0014:*/	0x00,	/* ........ */
+	/*0015:*/	0x00,	/* ........ */
+	/*0016:*/	0x00,	/* ........ */
+	/*0017:*/	0x00,	/* ........ */
+	/*0018:*/	0x00,	/* ........ */
+	/*0019:*/	0xe0,	/* ###..... */
+/* B battery full */
+	/*001a:*/	3, 3, 8, 0, 0, /* width and bbox (w,h,x,y) */
+	/*001f:*/	0xe0,	/* ###..... */
+	/*0020:*/	0x00,	/* ........ */
+	/*0021:*/	0xc0,	/* ##...... */
+	/*0022:*/	0xc0,	/* ##...... */
+	/*0023:*/	0xc0,	/* ##...... */
+	/*0024:*/	0xc0,	/* ##...... */
+	/*0025:*/	0x00,	/* ........ */
+	/*0026:*/	0xe0,	/* ###..... */
+/* C battery + */
+	/*0027:*/	3, 3, 8, 0, 0, /* width and bbox (w,h,x,y) */
+	/*002c:*/	0x80,	/* #....... */
+	/*002d:*/	0x80,	/* #....... */
+	/*002e:*/	0xc0,	/* ##...... */
+	/*002f:*/	0xc0,	/* ##...... */
+	/*0030:*/	0xc0,	/* ##...... */
+	/*0031:*/	0xc0,	/* ##...... */
+	/*0032:*/	0x80,	/* #....... */
+	/*0033:*/	0x80,	/* #....... */
+/* D radiation left */
+	/*0034:*/	3, 3, 8, 0, 0, /* width and bbox (w,h,x,y) */
+	/*0039:*/	0x20,	/* ..#..... */
+	/*003a:*/	0x40,	/* .#...... */
+	/*003b:*/	0x20,	/* ..#..... */
+	/*003c:*/	0x00,	/* ........ */
+	/*003d:*/	0x00,	/* ........ */
+	/*003e:*/	0x00,	/* ........ */
+	/*003f:*/	0x00,	/* ........ */
+	/*0040:*/	0x00,	/* ........ */
+/* E tower */
+	/*0041:*/	5, 5, 8, 0, 0, /* width and bbox (w,h,x,y) */
+	/*0046:*/	0x20,	/* ..#..... */
+	/*0047:*/	0x50,	/* .#.#.... */
+	/*0048:*/	0x20,	/* ..#..... */
+	/*0049:*/	0x20,	/* ..#..... */
+	/*004a:*/	0x50,	/* .#.#.... */
+	/*004b:*/	0x50,	/* .#.#.... */
+	/*004c:*/	0x88,	/* #...#... */
+	/*004d:*/	0xf8,	/* #####... */
+/* F radiation right */
+	/*004e:*/	3, 3, 8, 0, 0, /* width and bbox (w,h,x,y) */
+	/*0053:*/	0x80,	/* #....... */
+	/*0054:*/	0x40,	/* .#...... */
+	/*0055:*/	0x80,	/* #....... */
+	/*0056:*/	0x00,	/* ........ */
+	/*0057:*/	0x00,	/* ........ */
+	/*0058:*/	0x00,	/* ........ */
+	/*0059:*/	0x00,	/* ........ */
+	/*005a:*/	0x00,	/* ........ */
+/* G no radiation */
+	/*005b:*/	3, 3, 8, 0, 0, /* width and bbox (w,h,x,y) */
+	/*0060:*/	0x00,	/* ........ */
+	/*0061:*/	0x00,	/* ........ */
+	/*0062:*/	0x00,	/* ........ */
+	/*0063:*/	0x00,	/* ........ */
+	/*0064:*/	0x00,	/* ........ */
+	/*0065:*/	0x00,	/* ........ */
+	/*0066:*/	0x00,	/* ........ */
+	/*0067:*/	0x00,	/* ........ */
+/* H battery loaded */
+	/*0068:*/	3, 3, 8, 0, 0, /* width and bbox (w,h,x,y) */
+	/*006d:*/	0xe0,	/* ###..... */
+	/*006e:*/	0x00,	/* ........ */
+	/*006f:*/	0xe0,	/* ###..... */
+	/*0070:*/	0xe0,	/* ###..... */
+	/*0071:*/	0xe0,	/* ###..... */
+	/*0072:*/	0xe0,	/* ###..... */
+	/*0073:*/	0x00,	/* ........ */
+	/*0074:*/	0xe0,	/* ###..... */
+};
+static const uint16_t font_symbols_offsets[] = {
+	0x0000 /* '@' */,
+	0x000d /* 'A' */,
+	0x001a /* 'B' */,
+	0x0027 /* 'C' */,
+	0x0034 /* 'D' */,
+	0x0041 /* 'E' */,
+	0x004e /* 'F' */,
+	0x005b /* 'G' */,
+	0x0068 /* 'H' */,
+};
+const struct fb_font font_symbols = {
+	.height = 8,
+	.ascent = 8,
+	.firstchar = 64, /* '@' */
+	.lastchar = 72,
+	.chardata = font_symbols_data,
+	.charoffs = font_symbols_offsets,
+};
+
diff -u -urN osmocom-bb.120404/src/target/firmware/include/abb/twl3025.h osmocom-bb.120501/src/target/firmware/include/abb/twl3025.h
--- osmocom-bb.120404/src/target/firmware/include/abb/twl3025.h	2013-02-15 10:31:40.000000000 +0100
+++ osmocom-bb.120501/src/target/firmware/include/abb/twl3025.h	2013-02-04 13:42:14.000000000 +0100
@@ -69,6 +69,56 @@
 };
 #define BULDATA2	BULDATA1
 
+/* available ADC inputs on IOTA */
+enum twl3025_dac_inputs {/* === Signal ============================= */
+	MADC_VBAT=0,	/* battery voltage / 4                      */
+	MADC_VCHG=1,	/* charger voltage / 5                      */
+	MADC_ICHG=2,	/* I-sense amp or CHGREG DAC output         */
+	MADC_VBKP=3,	/* backup battery voltage / 4               */
+	MADC_ADIN1=4,	/* VADCID, sense battery type, not used     */
+	MADC_ADIN2=5,	/* Temperature sensor in Battery            */
+	MADC_ADIN3=6,	/* Mode_detect: sense 2.5mm jack insertion  */
+	MADC_ADIN4=7,	/* RITA: TEMP_SEN                           */
+	MADC_NUM_CHANNELS=8
+};
+
+enum madcstat_reg_bits { /* monitoring ADC status register */
+	ADCBUSY = 0x01  /* if set, a conversion is currently going on */
+};
+
+/* BCICTL1 register bits */
+enum bcictl1_reg_bits {
+	MESBAT	= 1<<0,	/* connect resistive divider for bat voltage */
+	DACNBUF	= 1<<1,	/* bypass DAC buffer */
+	THSENS0	= 1<<3,	/* thermal sensor bias current (ADIN2), bit 0 */
+	THSENS1	= 1<<4,	/* "" bit 1 */
+	THSENS2	= 1<<5,	/* "" bit 2 */
+	THEN	= 1<<6,	/* enable thermal sensor bias current (ADIN1) */ 
+	TYPEN	= 1<<7	/* enable bias current for battery type reading */
+};
+
+/* BCICTL1 register bits */
+enum bcictl2_reg_bits {
+	CHEN	= 1<<0,	/* enable charger */
+	CHIV	= 1<<1,	/* 1=constant current, 0=constant voltage */
+	CHBPASSPA=1<<2,	/* full charging of the battery during pulse radio */
+	CLIB	= 1<<3,	/* calibrate I-to-V amp (short input pins) */
+	CHDISPA	= 1<<4,	/* disabel charging during pulse radio (???) */
+	LEDC	= 1<<5,	/* enable LED during charge */
+	CGAIN4	= 1<<6,	/* if set, I-to-V amp gain is reduced from 10 to 4 */
+	PREOFF	= 1<<7	/* disable battery precharge */
+};
+
+enum vrpcsts_reg_bits {
+	ONBSTS = 1<<0,	/* button push switched on the mobile */
+	ONRSTS = 1<<1,	/* RPWON terminal switched on the mobile */
+	ITWSTS = 1<<2,	/* ITWAKEUP terminal switched on the mobile */
+	CHGSTS = 1<<3,	/* plugging in charger has switched on the mobile */
+	ONREFLT= 1<<4,	/* state of PWON terminal after debouncing */
+	ONMRFLT= 1<<5,	/* state of RPWON terminal after debouncing */
+	CHGPRES= 1<<6	/* charger is connected */
+};
+
 enum togbr2_bits {
 	TOGBR2_KEEPR	= (1 << 0),	/* Clear KEEPON bit */
 	TOGBR2_KEEPS	= (1 << 1),	/* Set KEEPON bit */
diff -u -urN osmocom-bb.120404/src/target/firmware/include/battery/battery.h osmocom-bb.120501/src/target/firmware/include/battery/battery.h
--- osmocom-bb.120404/src/target/firmware/include/battery/battery.h	1970-01-01 01:00:00.000000000 +0100
+++ osmocom-bb.120501/src/target/firmware/include/battery/battery.h	2013-02-04 13:42:14.000000000 +0100
@@ -0,0 +1,37 @@
+#ifndef _BATTERY_BATTERY_H
+#define _BATTERY_BATTERY_H
+
+/* User-visible state of the battery charger.
+ *
+ * If CHG_CONNECTED, power is externally supplied to the mobile.
+ *
+ * If CHG_ENABLED, the charger will try to provide charge
+ * to the battery if needed, but this state might be switchable?
+ *
+ * BATTERY_CHARGING: Battery is not full, so a significant charging
+ * current (not trickle charge) is supplied.
+ *
+ * BATTERY_FAILURE: Overtemperature, overvoltage, ... if this bit
+ * is set, charging should be inhibited.
+ */
+
+
+enum battery_flags {
+	BATTERY_CHG_CONNECTED = 1 << 0,  /* AC adapter is connected */
+	BATTERY_CHG_ENABLED   = 1 << 1,  /* if needed charger could charge */
+	BATTERY_CHARGING      = 1 << 2,  /* charger is actively charging */
+	BATTERY_FAILURE       = 1 << 3,  /* problem exists preventing charge */
+};
+
+struct battery_info {
+	enum battery_flags flags;
+	int charger_volt_mV; /* charger connection voltage */
+	int bat_volt_mV;     /* battery terminal voltage */
+	int bat_chg_curr_mA; /* battery charging current */
+	int battery_percent; /* 0(empty) .. 100(full) */
+};
+
+extern struct battery_info
+battery_info;
+
+#endif
diff -u -urN osmocom-bb.120404/src/target/firmware/include/battery/compal_e88.h osmocom-bb.120501/src/target/firmware/include/battery/compal_e88.h
--- osmocom-bb.120404/src/target/firmware/include/battery/compal_e88.h	1970-01-01 01:00:00.000000000 +0100
+++ osmocom-bb.120501/src/target/firmware/include/battery/compal_e88.h	2013-02-04 13:42:14.000000000 +0100
@@ -0,0 +1,15 @@
+#ifndef _BATTERY_COMPAL_E88_H
+#define _BATTERY_COMPAL_E88_H
+
+#include <stdint.h>
+#include <abb/twl3025.h>
+
+/* initialize the charger control loop on C123 */
+
+extern void
+battery_compal_e88_init();
+
+extern uint16_t
+compal_e88_madc[MADC_NUM_CHANNELS];
+
+#endif
diff -u -urN osmocom-bb.120404/src/target/firmware/include/fb/font.h osmocom-bb.120501/src/target/firmware/include/fb/font.h
--- osmocom-bb.120404/src/target/firmware/include/fb/font.h	2013-02-15 10:31:40.000000000 +0100
+++ osmocom-bb.120501/src/target/firmware/include/fb/font.h	2013-02-04 13:42:14.000000000 +0100
@@ -70,6 +70,7 @@
 	FB_FONT_HELVB14,
 //	FB_FONT_HELVB24,
 	FB_FONT_C64,
+	FB_FONT_SYMBOLS,
 };
 
 extern const struct fb_font *fb_fonts[]; // note: has to match fb_font_id enum!
