Messages in this thread | | | Date | Mon, 25 Jul 2005 07:46:42 +0200 | From | Pavel Machek <> | Subject | [warning: ugly, FYI] battery charging support for sharp sl-5500 |
| |
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@suse.cz> * * 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@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |