[warning: ugly, FYI] battery charging support for sharp sl-5500

From: Pavel Machek
Date: Mon Jul 25 2005 - 09:50:12 EST


Hi!

I took battery charging code from sharp and placed it in
arch/arm/mach-sa1100/battery-collie.c (hope that's good place...). It
still does not link, and will need complete rewrite, but... If you
have done this already please let me know.

/*
* Battery routines for collie (Sharp Zaurus sl-5500)
*
* Copyright (C) 2001 SHARP
* Copyright 2005 Pavel Machek <pavel@xxxxxxx>
*
* 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.
*
* ChangeLog:
* 12-Nov-2001 Lineo Japan, Inc.
* 30-Jul-2002 Lineo Japan, Inc. for 2.4.18
*/

/* this driver supports the following functions:
* - apm_get_power_status
* - charge proc
*/


#include <linux/config.h>
#include <linux/module.h>

#include <linux/poll.h>
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/timer.h>
#include <linux/fcntl.h>
#include <linux/stat.h>
#include <linux/proc_fs.h>
#include <linux/miscdevice.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/kernel.h>
#include <linux/smp_lock.h>
#include <linux/apm_bios.h>
#include <linux/delay.h>

#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/mach/irq.h>

#include <asm/hardware/scoop.h>
#include <asm/arch/ucb1x00.h>
#include <asm/arch/collie.h>

/* Various strange defines, coming from sharp */

#define COLLIE_TC35143_IODAT_LOW 0 /* set up fs 8k LPF on data */
#define COLLIE_TC35143_IODAT_HIGH 1 /* set up fs 8k LPF off data */

#define COLLIE_TC35143_IODIR_OUTPUT 1 /* set up output mode */
#define COLLIE_TC35143_IODIR_INPUT 0 /* set up input mode */

/*
* UCB1200 register 10: ADC control register
*/
#define ADC_SYNC_ENA (1 << 0)
#define ADC_INPUT_MASK (7 << 2)
#define ADC_INPUT_TSPX (0 << 2)
#define ADC_INPUT_TSMX (1 << 2)
#define ADC_INPUT_TSPY (2 << 2)
#define ADC_INPUT_TSMY (3 << 2)
#define ADC_INPUT_AD0 (4 << 2)
#define ADC_INPUT_AD1 (5 << 2)
#define ADC_INPUT_AD2 (6 << 2)
#define ADC_INPUT_AD3 (7 << 2)
#define ADC_START (1 << 7)
#define ADC_ENA (1 << 15)

#define COLLIE_TC35143_ADC_BAT_TMP ADC_INPUT_AD0 /* BAT TMP */
#define COLLIE_TC35143_ADC_BAT_VOL ADC_INPUT_AD1 /* MAIN/BACKUP BAT VOL */
#define COLLIE_TC35143_ADC_TC_PRESSURE ADC_INPUT_AD2 /* TC PRESSURE */
#define COLLIE_TC35143_ADC_REMOCON_KEY ADC_INPUT_AD3 /* REMOCON KEY */


#define CF_BUF_CTRL_BASE 0xF0800000
#define SCP_REG(adr) (*(volatile unsigned short*)(CF_BUF_CTRL_BASE+(adr)))

#define SCP_MCR 0x00
#define SCP_CDR 0x04
#define SCP_CSR 0x08
#define SCP_CPR 0x0C
#define SCP_CCR 0x10
#define SCP_IRR 0x14
#define SCP_IRM 0x14
#define SCP_IMR 0x18
#define SCP_ISR 0x1C
#define SCP_GPCR 0x20
#define SCP_GPWR 0x24
#define SCP_GPRR 0x28
#define SCP_REG_MCR SCP_REG(SCP_MCR)
#define SCP_REG_CDR SCP_REG(SCP_CDR)
#define SCP_REG_CSR SCP_REG(SCP_CSR)
#define SCP_REG_CPR SCP_REG(SCP_CPR)
#define SCP_REG_CCR SCP_REG(SCP_CCR)
#define SCP_REG_IRR SCP_REG(SCP_IRR)
#define SCP_REG_IRM SCP_REG(SCP_IRM)
#define SCP_REG_IMR SCP_REG(SCP_IMR)
#define SCP_REG_ISR SCP_REG(SCP_ISR)
#define SCP_REG_GPCR SCP_REG(SCP_GPCR)
#define SCP_REG_GPWR SCP_REG(SCP_GPWR)
#define SCP_REG_GPRR SCP_REG(SCP_GPRR)

#define FLASH_MEM_BASE 0xe8ffc000
#define FLASH_DATA(adr) (*(volatile unsigned int*)(FLASH_MEM_BASE+(adr)))
#define FLASH_DATA_F(adr) (*(volatile float32 *)(FLASH_MEM_BASE+(adr)))
#define FLASH_MAGIC_CHG(a,b,c,d) ( ( d << 24 ) | ( c << 16 ) | ( b << 8 ) | a )

// AD
#define FLASH_AD_MAJIC FLASH_MAGIC_CHG('B','V','A','D')
#define FLASH_AD_MAGIC_ADR 0x30
#define FLASH_AD_DATA_ADR 0x34

#define IRQ_GPIO_CO IRQ_GPIO20
#define IRQ_GPIO_AC_IN IRQ_GPIO1

//#define DEBUG 1
#ifdef DEBUG
#define DPRINTK(x, args...) printk(__FUNCTION__ ": " x,##args)
#define DPRINTK2(x, args...) printk(__FUNCTION__ ": " x,##args)
#else
#define DPRINTK(x, args...) if ( msglevel > 1 ) printk(x,##args);
#define DPRINTK2(x, args...) if ( msglevel > 0 ) printk(x,##args);
#endif




/*** prototype *********************************************************************/
int collie_read_MainBattery(void);
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);
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);
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;


#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
};
#endif



typedef struct ChargeThresh {
int bar1;
int bar2;
int bar3;
int bar4;
} CHARGE_THRESH;

CHARGE_THRESH collie_main_battery_thresh_charge = {
391 , 403, 411 , 417
};

/*** local variables *************************************************************/
#if 1
static struct file_operations collie_battery_fops = {
};
#else
static struct file_operations collie_battery_fops = {
owner: THIS_MODULE,
read: do_read,
poll: do_poll,
ioctl: do_ioctl,
open: do_open,
release: do_release,
};
#endif

/*
* The battery device is one of the misc char devices.
* This is its minor number.
*/
#define BATTERY_MINOR_DEV 215

static struct miscdevice battery_device = {
BATTERY_MINOR_DEV,
"battery",
&collie_battery_fops
};

#define ADC_REQ_ID (u32)(&battery_device)

#ifdef CONFIG_COLLIE_TR0
#define CHARGE_ON() ucb1200_set_io(COLLIE_TC35143_GPIO_CHRG_ON, COLLIE_TC35143_IODAT_HIGH)
#define CHARGE_OFF() ucb1200_set_io(COLLIE_TC35143_GPIO_CHRG_ON, COLLIE_TC35143_IODAT_LOW)
#else
#define CHARGE_ON() SCP_REG_GPWR |= COLLIE_SCP_CHARGE_ON
#define CHARGE_OFF() SCP_REG_GPWR &= ~COLLIE_SCP_CHARGE_ON
#endif

#define CHARGE_LED_ON() printk("charger on\n");
#define CHARGE_LED_OFF() printk("charger off\n");
#define CHARGE_LED_ERR() printk("charger error\n");

#define GetMainADCtoPower(x) (( 330 * x * 2 ) / 1024 ) // MAX 4.2V
#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 100
#define COLLIE_BATTERY_STATUS_LOW 40
#define COLLIE_BATTERY_STATUS_VERYLOW 5
#define COLLIE_BATTERY_STATUS_CRITICAL 1


#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_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 )


extern int autoPowerCancel;
extern int autoLightCancel;
extern int ppp_connect_count;
unsigned int APOCnt = COLLIE_APO_DEFAULT;
unsigned int APOCntWk = 0;
unsigned int LPOCnt = COLLIE_LPO_DEFAULT;
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_charge_battery = 100;

#define APM_AC_OFFLINE 0
#define APM_AC_ONLINE 1

int collie_ac_status = APM_AC_OFFLINE;
int ad_revise = 0;

static int MainCntWk = COLLIE_MAIN_GOOD_COUNT;
static int MainCnt = COLLIE_MAIN_NOGOOD_COUNT;
static int FattCnt = 0;
static int back_ac_status = 3;

#ifdef CONFIG_PM
static struct pm_dev *battery_pm_dev; /* registered PM device */
#endif

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 DECLARE_WAIT_QUEUE_HEAD(wq_on);
static DECLARE_WAIT_QUEUE_HEAD(wq_off);

static int collie_backup_battery_flag = 0; // 0 : init 1: passed 10min
static int collie_fatal_off = 1;


/*** main ***********************************************************************/
// call by apm.c only
int collie_apm_get_power_status(u_char *ac_line_status,
u_char *battery_status,
u_char *battery_flag,
u_char *battery_percentage,
u_short *battery_life)
{

// set ac status
*ac_line_status = collie_ac_status;

// set battery_status main
*battery_status = collie_main_battery;

// 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;
}

if ( *ac_line_status == APM_AC_ONLINE )
*battery_percentage = 100;

// good or ac in --> GOOD_COUNT
// low or very low --> NOGOOD_COUNT
if ( ( *battery_status == COLLIE_BATTERY_STATUS_HIGH ) || ( *ac_line_status == APM_AC_ONLINE ) )
MainCnt = COLLIE_MAIN_GOOD_COUNT;
else
MainCnt = COLLIE_MAIN_NOGOOD_COUNT;

// set battery_flag
if ( *battery_flag == COLLIE_BATTERY_STATUS_VERYLOW )
*battery_flag = (1 << 5);
else
*battery_flag = (1 << *battery_status);

// chk charge status
if ( charge_status ) {
*battery_status = 101;
*battery_flag = (1 << 3);
*battery_percentage = collie_main_charge_battery;
MainCnt = COLLIE_MAIN_NOGOOD_COUNT;
}

// set battery life
*battery_life = -1;



DPRINTK("jiffies = %d / COLLIE_BACKUP_BATTERY_CK_TIME = %d / collie_backup_battery_flag = %d\n",
jiffies , COLLIE_BACKUP_BATTERY_CK_TIME , collie_backup_battery_flag);
DPRINTK("MainCnt = %d\n",MainCnt);


return APM_SUCCESS;
}


/*** misc ***********************************************************************/
static void collie_charge_on(void)
{
while(1) {

sleep_on(&wq_on);

DPRINTK("call charge on \n");

if ( collie_check_temp() ) {
/* error led on */
CHARGE_LED_ERR();
/* charge status flag reset */
charge_status = 0;
} else {
/* led on */
CHARGE_LED_ON();
/* Charge ON */
CHARGE_ON();
/* charge status flag set */
charge_status = 1;
}

}
}

static void collie_charge_off(void)
{

while(1) {

sleep_on(&wq_off);

DPRINTK("%d\n",charge_off_mode);

/* Charge OFF */
CHARGE_OFF();

/* led off */
CHARGE_LED_OFF();

if ( charge_off_mode && collie_check_voltage() ) {
/* error led on */
CHARGE_LED_ERR();
}

/* charge status flag reset */
charge_status = 0;

}

}



static void collie_pm(void)
{

while(1) {
interruptible_sleep_on_timeout((wait_queue_head_t*)&queue, COLLIE_APO_TICKTIME );

// get ac status. if change ac status , chk main battery.
collie_ac_status = (!( GPLR & COLLIE_GPIO_AC_IN ) ? APM_AC_OFFLINE : APM_AC_ONLINE);
if ( back_ac_status != collie_ac_status ) {
MainCntWk = COLLIE_MAIN_GOOD_COUNT; // chk battery
}
back_ac_status = collie_ac_status;

// get main battery
collie_get_main_battery();

// get backup battery status.
if ( ( jiffies > COLLIE_BACKUP_BATTERY_CK_TIME ) && !collie_backup_battery_flag ) {
collie_backup_battery_flag = 1;
printk("check backup battery ! \n");
}

// chk critical
if ( ( collie_main_battery == COLLIE_BATTERY_STATUS_CRITICAL ) && collie_fatal_off ) {
if ( FattCnt++ >= COLLIE_MAIN_NOGOOD_COUNT ) {
collie_fatal_off = 0;
printk("Fatal Off\n");
}
} else {
FattCnt = 0;
}

// auto power off chk
if ( !autoPowerCancel || ppp_connect_count > 0 ) {
APOCntWk = 0;
autoPowerCancel = 1;
} else {
APOCntWk += COLLIE_APO_TICKTIME;
}

if ( APOCntWk >= APOCnt ) {
APOCntWk = 0;
}


// auto frontlight off
if ( !autoLightCancel ) {
LPOCntWk = 0;
autoLightCancel = 1;
} else {
LPOCntWk += COLLIE_LPO_TICKTIME;
}

if ( LPOCntWk >= LPOCnt ) {
// printk("Auto Light Off\n");
// colliefl_blank(1);
LPOCntWk = 0;
}
// printk("Auto Light Off %d\n",LPOCntWk);


}

}


/*** Int ***********************************************************************/
static void Collie_ac_interrupt(int irq, void *dummy, struct pt_regs *fp)
{
if ((GPLR & COLLIE_GPIO_AC_IN)==0) {
/* High->Low : desert */
charge_off_mode = 0;
wake_up(&wq_off);
} else {
/* Low->High : assert */
wake_up(&wq_on);
}

}

static void Collie_co_interrupt(int irq, void *dummy, struct pt_regs *fp)
{
if ((GPLR & COLLIE_GPIO_AC_IN)==0) {
/* High->Low : desert */
charge_off_mode = 0;
wake_up(&wq_off);
} else {
charge_off_mode = 1;
wake_up(&wq_off);
}
}


int GetMainChargePercent( int Volt )
{
DPRINTK(" volt = %d \n",Volt);

if ( Volt >= collie_main_battery_thresh_charge.bar4 ) {
return 95;
} else if ( Volt >= collie_main_battery_thresh_charge.bar3 ) {
return 75;
} else if ( Volt >= collie_main_battery_thresh_charge.bar2 ) {
return 50;
} else if ( Volt >= collie_main_battery_thresh_charge.bar1 ) {
return 25;
} else {
return 5;
}
}

/*** get adc *********************************************************************/
int collie_get_main_battery(void)
{
#ifdef CONFIG_COLLIE_TR0
return COLLIE_BATTERY_STATUS_HIGH;
#else
int i = 0;

MainCntWk++;

if ( MainCntWk > MainCnt ) {
int voltage;

MainCntWk = 0;

while(1) {
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));

DPRINTK2("charge percent = %d ( at %d ) \n",collie_main_charge_battery,jiffies);

DPRINTK(" get Main battery status %d\n",collie_main_battery);

} else {
DPRINTK(" not get Main battery \n");
DPRINTK("MainCntWk = %d\n",MainCntWk);
}
return collie_main_battery;

#endif
}


int GetMainLevel( int Volt )
{

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 GetBackLevel( int Volt )
{
if ( Volt > COLLIE_BACKUP_BATTERY_LOW )
return COLLIE_BATTERY_STATUS_HIGH;
else
return COLLIE_BATTERY_STATUS_VERYLOW;
}


int collie_read_MainBattery(void)
{
int voltage;


ucb1200_set_io(COLLIE_TC35143_GPIO_BBAT_ON, COLLIE_TC35143_IODAT_LOW);
ucb1200_set_io(COLLIE_TC35143_GPIO_MBAT_ON, COLLIE_TC35143_IODAT_HIGH);
voltage = ucb1200_get_adc_value(ADC_REQ_ID, COLLIE_TC35143_ADC_BAT_VOL);
if ( battery_off_flag )
voltage = -1;
ucb1200_set_io(COLLIE_TC35143_GPIO_MBAT_ON, COLLIE_TC35143_IODAT_LOW);

battery_off_flag = 0;

DPRINTK("adc = %d\n",voltage);

if ( voltage != -1 ) {
DPRINTK2("main adc = %d(%d)\n",(voltage+ConvRevise(voltage)),voltage);
return (voltage+ConvRevise(voltage));
} else {
return voltage;
}
}

int collie_read_BackBattery(void)
{
int voltage;

ucb1200_set_io(COLLIE_TC35143_GPIO_MBAT_ON, COLLIE_TC35143_IODAT_LOW);
ucb1200_set_io(COLLIE_TC35143_GPIO_BBAT_ON, COLLIE_TC35143_IODAT_HIGH);
mdelay(3);
voltage = ucb1200_get_adc_value(ADC_REQ_ID, COLLIE_TC35143_ADC_BAT_VOL);
if ( battery_off_flag )
voltage = -1;
ucb1200_set_io(COLLIE_TC35143_GPIO_BBAT_ON, COLLIE_TC35143_IODAT_LOW);

battery_off_flag = 0;
return voltage;
}

int collie_read_Temp(void)
{
int voltage;


ucb1200_set_io(COLLIE_TC35143_GPIO_TMP_ON, COLLIE_TC35143_IODAT_HIGH);
voltage = ucb1200_get_adc_value(ADC_REQ_ID, COLLIE_TC35143_ADC_BAT_TMP);
if ( battery_off_flag )
voltage = -1;
ucb1200_set_io(COLLIE_TC35143_GPIO_TMP_ON, COLLIE_TC35143_IODAT_LOW);

battery_off_flag = 0;
return voltage;
}


int collie_check_temp(void)
{
int temp , i = 0;

if ( in_interrupt() ) {
DPRINTK("charge(temp) : in_interrupt !\n");
return 1;
}

while(1) {
temp = collie_read_Temp();
if ( temp > 0 ) break;
if ( i > 5 ) { DPRINTK("charge : can not temp ad.\n"); break; }
i++;
}

DPRINTK("collie_check_temp = %d\n",temp);

if ( temp > collie_charge_temp ) return 1;


return 0;
}

int collie_check_voltage(void)
{
int temp , i = 0;


if ( in_interrupt() ) {
DPRINTK("charge(vol) : in_interrupt !\n");
return 1;
}

while(1) {
temp = collie_read_MainBattery();
if ( temp > 0 ) break;
if ( i > 5 ) { DPRINTK("charge : can not main ad.\n"); break; }
i++;
}

DPRINTK("collie_check_volt = %d\n",temp);

if ( temp < collie_charge_volt ) return 1;

return 0;
}

/*** PM *************************************************************************/
void Collie_battery_power_off(void)
{
// ucb1200_set_io(COLLIE_TC35143_GPIO_MBAT_ON, COLLIE_TC35143_IODAT_LOW);
// ucb1200_set_io(COLLIE_TC35143_GPIO_BBAT_ON, COLLIE_TC35143_IODAT_LOW);
// ucb1200_set_io(COLLIE_TC35143_GPIO_TMP_ON, COLLIE_TC35143_IODAT_LOW);
}

void Collie_battery_power_on(void)
{
/* 35143F io port initialize */
#ifdef CONFIG_COLLIE_TR0
ucb1200_set_io_direction(COLLIE_TC35143_GPIO_CHRG_ON, COLLIE_TC35143_IODIR_OUTPUT);
#endif
ucb1200_set_io_direction(COLLIE_TC35143_GPIO_MBAT_ON, COLLIE_TC35143_IODIR_OUTPUT);
ucb1200_set_io_direction(COLLIE_TC35143_GPIO_TMP_ON, COLLIE_TC35143_IODIR_OUTPUT);
ucb1200_set_io_direction(COLLIE_TC35143_GPIO_BBAT_ON, COLLIE_TC35143_IODIR_OUTPUT);

if ( collie_backup_battery_flag )
collie_backup_battery = GetBackLevel(GetBackADCtoPower(GetBackupBatteryAD()));

}


#ifdef CONFIG_PM
static int Collie_battery_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
{
switch (req) {
case PM_SUSPEND:
battery_off_flag = 1;
Collie_battery_power_off();
ucb1200_cancel_get_adc_value(ADC_REQ_ID);
apm_wakeup_src_mask |= ( COLLIE_GPIO_AC_IN | COLLIE_GPIO_CO );
break;
case PM_RESUME:
collie_fatal_off = 1;
FattCnt = 0;
APOCntWk = 0;
LPOCntWk = 0;
ucb1200_cancel_get_adc_value(ADC_REQ_ID);
Collie_battery_power_on();
MainCntWk = COLLIE_MAIN_GOOD_COUNT + 1;
break;
}
return 0;
}
#endif

/*** for suspend hook ***********************************************************/
int suspend_collie_read_Temp(void)
{
int temp;

ucb1200_set_io(COLLIE_TC35143_GPIO_TMP_ON, COLLIE_TC35143_IODAT_HIGH);
udelay(700);
temp = suspend_read_adc((int)&temp, COLLIE_TC35143_ADC_BAT_TMP);
ucb1200_set_io(COLLIE_TC35143_GPIO_TMP_ON, COLLIE_TC35143_IODAT_LOW);

printk("suspend temp = %d\n",temp);


return temp;
}


unsigned short suspend_collie_read_MainBattery(void)
{
int temp;

ucb1200_set_io(COLLIE_TC35143_GPIO_MBAT_ON, COLLIE_TC35143_IODAT_HIGH);
udelay(700);
temp = suspend_read_adc((int)&temp, COLLIE_TC35143_ADC_BAT_VOL);
ucb1200_set_io(COLLIE_TC35143_GPIO_MBAT_ON, COLLIE_TC35143_IODAT_LOW);

printk("suspend main adc = %d(%d)\n",(temp+ConvRevise(temp)),temp);

return (temp+ConvRevise(temp));
}


unsigned short GetBackupBatteryAD(void)
{
int temp;

ucb1200_set_io(COLLIE_TC35143_GPIO_BBAT_ON, COLLIE_TC35143_IODAT_HIGH);
// mdelay(3);
mdelay(5);
temp = suspend_read_adc((int)&temp, COLLIE_TC35143_ADC_BAT_VOL);
ucb1200_set_io(COLLIE_TC35143_GPIO_BBAT_ON, COLLIE_TC35143_IODAT_LOW);

printk("suspend backup adc = %d(%d)\n",(temp+ConvRevise(temp)),temp);

return temp;
}

void collie_get_ad(void)
{
if ( FLASH_DATA(FLASH_AD_MAGIC_ADR) == FLASH_AD_MAJIC ) {
ad_revise = 652-FLASH_DATA(FLASH_AD_DATA_ADR);
} else {
ad_revise = 0;
}
DPRINTK2("ad revise = %d(%d)\n",ad_revise,FLASH_DATA(FLASH_AD_DATA_ADR));
}

unsigned short chkFatalBatt(void)
{
#ifdef CONFIG_COLLIE_TR0
return 1;
#else
int volt;

// fail safe
collie_get_ad();

if ( charge_status == 1 ) {
CHARGE_OFF();
udelay(100);
}

volt = GetMainADCtoPower(suspend_collie_read_MainBattery());
printk("fatal chk = %d\n",volt);


if ( charge_status == 1 ) {
udelay(100);
CHARGE_ON();
GEDR = COLLIE_GPIO_CO;
}


if ( volt < collie_main_battery_thresh_nofl.verylow )
return 0;
else
return 1;
#endif
}




int suspend_collie_check_temp(void)
{
unsigned short temp , i = 0;

while(1) {
temp = suspend_collie_read_Temp();
if ( temp > 0 ) break;
if ( i > 5 ) { DPRINTK("suspend charge : can not read temp ad.\n"); break; }
i++;
}

DPRINTK("%d\n",temp);

if ( temp > collie_charge_temp ) return 1;

return 0;
}



int suspend_collie_check_voltage(void)
{
int temp , i = 0;

while(1) {
temp = suspend_collie_read_MainBattery();
if ( temp > 0 ) break;
if ( i > 5 ) { DPRINTK("can not read main ad.\n"); break; }
i++;
}

DPRINTK("%d\n",temp);

if ( temp < collie_charge_volt ) return 1;

return 0;
}



void suspend_collie_charge_on(void)
{

DPRINTK("call suspend charge on \n");

if ( suspend_collie_check_temp() ) {
/* error led on */
CHARGE_LED_ERR();
/* charge status flag reset */
charge_status = 0;
} else {
/* led on */
CHARGE_LED_ON();
/* Charge ON */
CHARGE_ON();
/* charge status flag set */
charge_status = 1;
}
}


void suspend_collie_charge_off(int charge_off_mode)
{

DPRINTK("call suspend charge off \n");


/* Charge OFF */
CHARGE_OFF();

/* led off FIX ME !*/
CHARGE_LED_OFF();

if ( charge_off_mode && suspend_collie_check_voltage()) {
/* error led on */
CHARGE_LED_ERR();
}

/* charge status flag reset */
charge_status = 0;
}


void collie_battery_charge_hook(int mode)
{
switch (mode){
case 0:
if ( charge_status )
suspend_collie_charge_off(1);
break;

case 1:
if ( charge_status )
suspend_collie_charge_off(0);
break;

case 2:
if ( !charge_status )
suspend_collie_charge_on();
break;

default:
break;
}
}



/*** Config & Setup **********************************************************/


void battery_init(void)
{
int err;

/* get ad revise */
collie_get_ad();

/* 35143F io port initialize */
#ifdef CONFIG_COLLIE_TR0
ucb1200_set_io_direction(COLLIE_TC35143_GPIO_CHRG_ON, COLLIE_TC35143_IODIR_OUTPUT);
#endif
ucb1200_set_io_direction(COLLIE_TC35143_GPIO_MBAT_ON, COLLIE_TC35143_IODIR_OUTPUT);
ucb1200_set_io_direction(COLLIE_TC35143_GPIO_TMP_ON, COLLIE_TC35143_IODIR_OUTPUT);
ucb1200_set_io_direction(COLLIE_TC35143_GPIO_BBAT_ON, COLLIE_TC35143_IODIR_OUTPUT);

/* Set transition detect */
usb1x00_enable_irq(NULL, COLLIE_GPIO_AC_IN, UCB_RISING);
usb1x00_enable_irq(NULL, COLLIE_GPIO_CO, UCB_RISING);

/* Register interrupt handler. */
if ((err = request_irq(IRQ_GPIO_AC_IN, Collie_ac_interrupt, SA_INTERRUPT,
"ACIN", Collie_ac_interrupt))) {
printk("Could not get irq %d.\n", IRQ_GPIO_AC_IN);
return;
}

/* Register interrupt handler. */
if ((err = request_irq(IRQ_GPIO_CO, Collie_co_interrupt, SA_INTERRUPT,
"CO", Collie_co_interrupt))) {
free_irq(IRQ_GPIO_AC_IN, Collie_ac_interrupt);
printk("Could not get irq %d.\n", IRQ_GPIO_CO);
return;
}

/* regist to Misc driver */
misc_register(&battery_device);

/* Make threads */
kernel_thread(collie_charge_on, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
kernel_thread(collie_charge_off, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
kernel_thread(collie_pm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);

/* set backup work */
collie_backup_battery = COLLIE_BATTERY_STATUS_HIGH;

}




#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_batt;

typedef struct collie_battery_entry {
int* addr;
int def_value;
char* name;
char* description;
unsigned short low_ino;
} collie_battery_entry_t;

static collie_battery_entry_t collie_battery_params[] = {
/* { addr, def_value, name, description }*/
{ &msglevel, 0, "msglevel", "debug message output level" }
};
#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,
size_t nbytes, loff_t *ppos)
{
int i_ino = (file->f_dentry->d_inode)->i_ino;
char outputbuf[15];
int count;
int i;
collie_battery_entry_t *current_param = NULL;

if (*ppos>0) /* Assume reading completed in previous read*/
return 0;
for (i=0; i<NUM_OF_BATTERY_ENTRY; i++) {
if (collie_battery_params[i].low_ino==i_ino) {
current_param = &collie_battery_params[i];
break;
}
}
if (current_param==NULL) {
return -EINVAL;
}
count = sprintf(outputbuf, "0x%08X\n",
*((volatile u16 *) 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))
return -EFAULT;
return count;
}

static ssize_t collie_battery_write_params(struct file *file, const char *buf,
size_t nbytes, loff_t *ppos)
{
int i_ino = (file->f_dentry->d_inode)->i_ino;
collie_battery_entry_t *current_param = NULL;
int i;
unsigned long param;
char *endp;

for (i=0; i<NUM_OF_BATTERY_ENTRY; i++) {
if(collie_battery_params[i].low_ino==i_ino) {
current_param = &collie_battery_params[i];
break;
}
}
if (current_param==NULL) {
return -EINVAL;
}

param = simple_strtoul(buf,&endp,0);
if (param == -1) {
*current_param->addr = current_param->def_value;
} else {
*current_param->addr = param;
}
return nbytes+endp-buf;
}

static struct file_operations proc_params_operations = {
read: collie_battery_read_params,
write: collie_battery_write_params,
};
#endif




int __init Collie_battery_init(void)
{
#ifdef CONFIG_PM
battery_pm_dev = pm_register(PM_SYS_DEV, 0, Collie_battery_pm_callback);
#endif

battery_init();

#ifdef CONFIG_PROC_FS
{
int i;
struct proc_dir_entry *entry;

proc_batt = proc_mkdir("driver/battery", NULL);
if (proc_batt == NULL) {
ucb1200_cancel_get_adc_value(ADC_REQ_ID);
free_irq(IRQ_GPIO_AC_IN, Collie_ac_interrupt);
free_irq(IRQ_GPIO_CO, Collie_co_interrupt);

misc_deregister(&battery_device);
printk(KERN_ERR "can't create /proc/driver/battery\n");
return -ENOMEM;
}
for (i=0; i<NUM_OF_BATTERY_ENTRY; i++) {
entry = create_proc_entry(collie_battery_params[i].name,
S_IWUSR |S_IRUSR | S_IRGRP | S_IROTH,
proc_batt);
if (entry) {
collie_battery_params[i].low_ino = entry->low_ino;
entry->proc_fops = &proc_params_operations;
} else {
int j;
for (j=0; j<i; j++) {
remove_proc_entry(collie_battery_params[i].name,
proc_batt);
}
remove_proc_entry("driver/battery", &proc_root);
proc_batt = 0;
ucb1200_cancel_get_adc_value(ADC_REQ_ID);
free_irq(IRQ_GPIO_AC_IN, Collie_ac_interrupt);
free_irq(IRQ_GPIO_CO, Collie_co_interrupt);
misc_deregister(&battery_device);
printk(KERN_ERR "ts: can't create /proc/driver/ts/threshold\n");
return -ENOMEM;
}
}
}
#endif


return 0;
}

module_init(Collie_battery_init);



#ifdef MODULE
int init_module(void)
{
Collie_battery_init();
return 0;
}

void cleanup_module(void)
{
ucb1200_cancel_get_adc_value(ADC_REQ_ID);
free_irq(IRQ_GPIO_AC_IN, Collie_ac_interrupt);
free_irq(IRQ_GPIO_CO, Collie_co_interrupt);

#ifdef CONFIG_PROC_FS
{
int i;
for (i=0; i<NUM_OF_COLLIE_BATTERY_ENTRY; i++) {
remove_proc_entry(collie_battery_params[i].name, proc_batt);
}
remove_proc_entry("driver/battery", NULL);
proc_batt = 0;
}
#endif

misc_deregister(&battery_device);
}
#endif /* MODULE */


--
teflon -- maybe it is a trademark, but it should not be.
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/