--- linux/arch/arm/mach-sa1100/collie_battery.c	Tue Jul 22 02:24:32 2003
+++ linux/arch/arm/mach-sa1100/collie_battery.c	Tue Jul 22 03:07:56 2003
@@ -14,10 +14,11 @@
  * 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.
  *
  * ChangeLog:
+ *	Nov 2002 Dietz Proepper: improved battery status.
  *	12-Nov-2001 Lineo Japan, Inc.
  *	30-Jul-2002 Lineo Japan, Inc.  for 2.4.18
  *      29-Jan-2003 Sharp Corporation  modify for new QT I/F
  *
  */
@@ -79,10 +80,11 @@ int collie_read_BackBattery(void);
 int collie_read_Temp(void);
 int collie_check_temp(void);
 int collie_check_voltage(void);
 static void collie_charge_on(void);
 static void collie_charge_off(void);
+static void do_main_battery(void);
 int set_led_status(int which,int status);
 int GetMainLevel( int Volt );
 int GetBackLevel( int Volt );
 int collie_get_main_battery(void);
 unsigned short GetBackupBatteryAD(void);
@@ -91,40 +93,35 @@ int suspend_collie_read_Temp(void);
 /*** extern ***********************************************************************/
 extern u32 apm_wakeup_src_mask;
 extern int counter_step_contrast;
 
 
-/*** gloabal variables ************************************************************/
-int charge_status = 0;			/* charge status  1 : charge  0: not charge */
-
-typedef struct BatteryThresh {
-	int high;
-	int low;
-	int verylow;
-} BATTERY_THRESH;
+/* defines */
+#define COLLIE_BATTERY_STATUS_HIGH      APM_BATTERY_STATUS_HIGH
+#define COLLIE_BATTERY_STATUS_LOW       APM_BATTERY_STATUS_LOW
+#define COLLIE_BATTERY_STATUS_VERYLOW   APM_BATTERY_STATUS_VERY_LOW
+#define COLLIE_BATTERY_STATUS_CRITICAL  APM_BATTERY_STATUS_CRITICAL
 
+/*** gloabal variables ************************************************************/
+int charge_status = 0;	/* charge status  1 : charge  0: not charge */
 
-#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0) || \
-    defined(CONFIG_COLLIE_TR1) || defined(CONFIG_COLLIE_DEV)
-BATTERY_THRESH  collie_main_battery_thresh_fl = {
-  368, 358, 356
-};
-
-BATTERY_THRESH  collie_main_battery_thresh_nofl = {
-  378, 364, 362
-};
-#else
-BATTERY_THRESH  collie_main_battery_thresh_fl = {
-  368, 358, 356
-};
-
-BATTERY_THRESH  collie_main_battery_thresh_nofl = {
-  378, 365, 363
+typedef struct {
+    int voltage_thres[2];		/* 0: nofl 1: fl */
+    int percent;
+    int state;
+} main_battery_thres;
+    
+#define MAIN_BATTERY_THRES 4
+
+main_battery_thres main_batt_thres[MAIN_BATTERY_THRES+2] = {
+	{{5000, 5000}, 100, COLLIE_BATTERY_STATUS_HIGH }, /* do not remove! */
+	{{412,408}, 100, COLLIE_BATTERY_STATUS_HIGH},
+	{{378,368}, 40, COLLIE_BATTERY_STATUS_HIGH},
+	{{364,358}, 5, COLLIE_BATTERY_STATUS_LOW},
+	{{362,356}, 1, COLLIE_BATTERY_STATUS_CRITICAL},
+	{{0, 0}, 1, COLLIE_BATTERY_STATUS_CRITICAL }	/* do not remove, too! */
 };
-#endif
-
-
 
 typedef struct ChargeThresh {
   int bar1;
   int bar2;
   int bar3;
@@ -180,24 +177,18 @@ static struct miscdevice battery_device 
 #define GetBackADCtoPower(x)   (( 330 * x * 2 ) / 1024 )     // MAX 3.3V
 #define ConvRevise(x)          ( ( ad_revise * x ) / 652 )
 #define MAIN_DIFF          50	// 0.5V 
 #define DIFF_CNT           ( 3 - 1 )
 
-#define COLLIE_BATTERY_STATUS_HIGH	APM_BATTERY_STATUS_HIGH
-#define COLLIE_BATTERY_STATUS_LOW	APM_BATTERY_STATUS_LOW
-#define COLLIE_BATTERY_STATUS_VERYLOW	APM_BATTERY_STATUS_VERY_LOW
-#define COLLIE_BATTERY_STATUS_CRITICAL	APM_BATTERY_STATUS_CRITICAL
-
 #define COLLIE_AC_LINE_STATUS	(!( GPLR & GPIO_AC_IN )	? APM_AC_OFFLINE : APM_AC_ONLINE)
 
-
 #define COLLIE_PM_TICK         		( 1000 / 10 )                   // 1sec
 #define COLLIE_APO_TICKTIME		(  5  * COLLIE_PM_TICK )	// 5sec
 #define COLLIE_LPO_TICKTIME		COLLIE_APO_TICKTIME
 #define COLLIE_APO_DEFAULT		( ( 3 * 60 ) * COLLIE_PM_TICK )	// 3 min
 #define COLLIE_LPO_DEFAULT		(  20 * COLLIE_PM_TICK )	// 20 sec
-#define COLLIE_MAIN_GOOD_COUNT		( 10*60 / ( COLLIE_APO_TICKTIME / COLLIE_PM_TICK ) )
+#define COLLIE_MAIN_GOOD_COUNT		( 1*60 / ( COLLIE_APO_TICKTIME / COLLIE_PM_TICK ) )
 #define COLLIE_MAIN_NOGOOD_COUNT	( 1*60  / ( COLLIE_APO_TICKTIME / COLLIE_PM_TICK ) )
 
 #define COLLIE_BACKUP_BATTERY_CK_TIME	( 10*60*1*100 )		// 10min
 #define COLLIE_BACKUP_BATTERY_LOW	( 190 )	
 
@@ -212,10 +203,11 @@ unsigned int LPOCntWk = 0;
 static DECLARE_WAIT_QUEUE_HEAD(queue);
 static int	msglevel;
 
 int collie_backup_battery = COLLIE_BATTERY_STATUS_HIGH;
 int collie_main_battery   = COLLIE_BATTERY_STATUS_HIGH;
+int collie_main_battery_percent = 100;
 int collie_main_charge_battery = 100;
 int collie_ac_status = APM_AC_OFFLINE;
 int ad_revise = 0;
 
 static int MainCntWk = COLLIE_MAIN_GOOD_COUNT;
@@ -229,10 +221,11 @@ static struct pm_dev *battery_pm_dev;	 /
 
 static int battery_off_flag = 0;	/* charge : suspend while get adc */
 static int collie_charge_temp = 973;
 static int collie_charge_volt = 465;	/* charge : check charge 3.0V     */
 static int charge_off_mode = 0;		/* charge : check volt or non     */
+static int collie_main_battery_voltage = 400;
 
 static DECLARE_WAIT_QUEUE_HEAD(wq_on);
 static DECLARE_WAIT_QUEUE_HEAD(wq_off);
 #if 1 // 2003.1.29
 static DECLARE_WAIT_QUEUE_HEAD(battery_waitqueue);
@@ -276,28 +269,11 @@ int collie_apm_get_power_status(u_char *
 	}
 	collie_battery_status = *battery_status;
 #endif
 
 	// main battery status to percentage
-	switch (*battery_status)
-	  {
-	  case COLLIE_BATTERY_STATUS_HIGH:
-	    *battery_percentage = 100;
-	    break;
-	  case COLLIE_BATTERY_STATUS_LOW:
-	    *battery_percentage = 40;
-	    break;
-	  case COLLIE_BATTERY_STATUS_VERYLOW:
-	    *battery_percentage = 5;
-	    break;
-	  case COLLIE_BATTERY_STATUS_CRITICAL:
-	    *battery_percentage = 1;
-	    break;
-	  default:
-	    *battery_percentage = 100;
-	    break;
-	  }
+	*battery_percentage = collie_main_battery_percent;
 
 	if ( *ac_line_status == APM_AC_ONLINE )
 	  *battery_percentage = 100;
 
 	// good or ac in   --> GOOD_COUNT
@@ -529,12 +505,13 @@ int collie_get_main_battery(void)
 	    voltage = collie_read_MainBattery();
 	    if ( voltage > 0 ) break;
 	    if ( i++ > 5 ) { voltage = 380; break; }
 	  }
 
-	  collie_main_battery = GetMainLevel(GetMainADCtoPower(voltage));
-	  collie_main_charge_battery = GetMainChargePercent(GetMainADCtoPower(voltage));
+	  collie_main_battery_voltage = GetMainADCtoPower(voltage);
+	  do_main_battery();
+	  collie_main_charge_battery = GetMainChargePercent(collie_main_battery_voltage);
 
 	  DPRINTK2("charge percent = %d ( at %d ) \n",collie_main_charge_battery,jiffies);
 
 	  DPRINTK(" get Main battery status %d\n",collie_main_battery);
 
@@ -562,36 +539,36 @@ int GetMainChargePercent( int Volt )
   } else {
     return 5;
   }
 }
 
-int GetMainLevel( int Volt )
+static void do_main_battery()
 {
-
-  DPRINTK("  volt = %d  \n",Volt);
-
-
-  if ( counter_step_contrast ) {
-	if ( Volt > collie_main_battery_thresh_fl.high )
-		return COLLIE_BATTERY_STATUS_HIGH;
-	else if ( Volt > collie_main_battery_thresh_fl.low )
-		return COLLIE_BATTERY_STATUS_LOW;
-	else if ( Volt > collie_main_battery_thresh_fl.verylow )
-		return COLLIE_BATTERY_STATUS_VERYLOW;
-	else
-		return COLLIE_BATTERY_STATUS_CRITICAL;
-  } else {
-	if ( Volt > collie_main_battery_thresh_nofl.high )
-		return COLLIE_BATTERY_STATUS_HIGH;
-	else if ( Volt > collie_main_battery_thresh_nofl.low )
-		return COLLIE_BATTERY_STATUS_LOW;
-	else if ( Volt > collie_main_battery_thresh_nofl.verylow )
-		return COLLIE_BATTERY_STATUS_VERYLOW;
-	else
-		return COLLIE_BATTERY_STATUS_CRITICAL;
-  }
-
+	int i = MAIN_BATTERY_THRES;
+	int fl = (counter_step_contrast)? 1 : 0;
+  
+	while ( i > 0 &&
+		( collie_main_battery_voltage > main_batt_thres[i].voltage_thres[fl] ) )
+		i--;
+	/* i is now between 0 and MAIN_BATTERY_THRES. That means
+	 * we can safely access main_batt_thres[i] and
+	 * main_batt_thres[i+1] */
+	
+	collie_main_battery = main_batt_thres[i].state;
+	{ /* perhaps we should put that deltas to our table, too? */
+		long deltav = main_batt_thres[i].voltage_thres[fl] -
+			      main_batt_thres[i+1].voltage_thres[fl];
+		long deltap = main_batt_thres[i].percent -
+			      main_batt_thres[i+1].percent;
+		
+		collie_main_battery_percent = 			/* (1) */
+	   	   main_batt_thres[i+1].percent + 
+	   	   deltap * (collie_main_battery_voltage - 
+ 		   main_batt_thres[i+1].voltage_thres[fl]) /
+	   	   deltav; 
+		DPRINTK("Battery stuff: v=%i i=%i , dv=%li , dp=%li , p=%i",collie_main_battery_voltage , i, deltav, deltap, collie_main_battery_percent );
+	}
 }
 
 
 int GetBackLevel( int Volt )
 {
@@ -834,20 +811,18 @@ unsigned short chkFatalBatt(void)
     GEDR = GPIO_CO;
     //    printk("CO = %x\n",GEDR&GPIO_CO);
   }
 
 
-  if ( volt < collie_main_battery_thresh_nofl.verylow )
+  if ( volt < main_batt_thres[MAIN_BATTERY_THRES].voltage_thres[0] )
     return 0;
   else
     return 1;
 #endif
 }
 
 
-
-
 int suspend_collie_check_temp(void)
 {
   unsigned short temp , i = 0;
 
   while(1) {
@@ -1032,10 +1007,11 @@ struct proc_dir_entry *proc_batt;
 typedef struct collie_battery_entry {
 	int*		addr;
 	int		def_value;
 	char*		name;
 	char*		description;
+	char		readonly;
 	unsigned short	low_ino;
 } collie_battery_entry_t;
 
 #if 1 // 2003.1.29
 static collie_battery_entry_t collie_battery_params[] = {
@@ -1044,11 +1020,13 @@ static collie_battery_entry_t collie_bat
   { &collie_change_battery_status , 0 , "chg_status", "Change status" }
 };
 #else
 static collie_battery_entry_t collie_battery_params[] = {
 /*  { addr,	def_value,	name,	    description }*/
-  { &msglevel,	0,		"msglevel",    "debug message output level" }
+/*  { &msglevel,	0,		"msglevel",    "debug message output level" } */
+  { &msglevel,	0,		"msglevel",    "debug message output level", 0 },
+  { &collie_main_battery_voltage, -1, "main_voltage", "main battery voltage", 1 }
 };
 #endif
 #define NUM_OF_BATTERY_ENTRY	(sizeof(collie_battery_params)/sizeof(collie_battery_entry_t))
 
 static ssize_t collie_battery_read_params(struct file *file, char *buf,
@@ -1069,11 +1047,12 @@ static ssize_t collie_battery_read_param
 		}
 	}
 	if (current_param==NULL) {
 		return -EINVAL;
 	}
-	count = sprintf(outputbuf, "0x%08X\n",
+//	count = sprintf(outputbuf, "0x%08X\n",
+	count = sprintf(outputbuf, "%04i\n",
 			*((volatile Word *) current_param->addr));
 	*ppos += count;
 	if (count>nbytes)	/* Assume output can be read at one time */
 		return -EINVAL;
 	if (copy_to_user(buf, outputbuf, count))
@@ -1094,11 +1073,12 @@ static ssize_t collie_battery_write_para
 		if(collie_battery_params[i].low_ino==i_ino) {
 			current_param = &collie_battery_params[i];
 			break;
 		}
 	}
-	if (current_param==NULL) {
+//	if (current_param==NULL) {
+	if (current_param==NULL || current_param->readonly) {
 		return -EINVAL;
 	}
 
 	param = simple_strtoul(buf,&endp,0);
 	if (param == -1) {