⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sharpsl_pm.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Battery and Power Management code for the Sharp SL-C7xx and SL-Cxx00 * series of PDAs * * Copyright (c) 2004-2005 Richard Purdie * * Based on code written by Sharp for 2.4 kernels * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * */#undef DEBUG#include <linux/module.h>#include <linux/timer.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/apm_bios.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/platform_device.h>#include <asm/hardware.h>#include <asm/hardware/scoop.h>#include <asm/mach-types.h>#include <asm/irq.h>#include <asm/apm.h>#include <asm/arch/pm.h>#include <asm/arch/pxa-regs.h>#include <asm/arch/sharpsl.h>#include "sharpsl.h"/* * Constants */#define SHARPSL_CHARGE_ON_TIME_INTERVAL        (msecs_to_jiffies(1*60*1000))  /* 1 min */#define SHARPSL_CHARGE_FINISH_TIME             (msecs_to_jiffies(10*60*1000)) /* 10 min */#define SHARPSL_BATCHK_TIME                    (msecs_to_jiffies(15*1000))    /* 15 sec */#define SHARPSL_BATCHK_TIME_SUSPEND            (60*10)                        /* 10 min */#define SHARPSL_WAIT_CO_TIME                   15  /* 15 sec */#define SHARPSL_WAIT_DISCHARGE_ON              100 /* 100 msec */#define SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP   10  /* 10 msec */#define SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT   10  /* 10 msec */#define SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN   10  /* 10 msec */#define SHARPSL_CHARGE_WAIT_TIME               15  /* 15 msec */#define SHARPSL_CHARGE_CO_CHECK_TIME           5   /* 5 msec */#define SHARPSL_CHARGE_RETRY_CNT               1   /* eqv. 10 min */#define SHARPSL_CHARGE_ON_VOLT         0x99  /* 2.9V */#define SHARPSL_CHARGE_ON_TEMP         0xe0  /* 2.9V */#define SHARPSL_CHARGE_ON_ACIN_HIGH    0x9b  /* 6V */#define SHARPSL_CHARGE_ON_ACIN_LOW     0x34  /* 2V */#define SHARPSL_FATAL_ACIN_VOLT        182   /* 3.45V */#define SHARPSL_FATAL_NOACIN_VOLT      170   /* 3.40V */struct battery_thresh spitz_battery_levels_acin[] = {	{ 213, 100},	{ 212,  98},	{ 211,  95},	{ 210,  93},	{ 209,  90},	{ 208,  88},	{ 207,  85},	{ 206,  83},	{ 205,  80},	{ 204,  78},	{ 203,  75},	{ 202,  73},	{ 201,  70},	{ 200,  68},	{ 199,  65},	{ 198,  63},	{ 197,  60},	{ 196,  58},	{ 195,  55},	{ 194,  53},	{ 193,  50},	{ 192,  48},	{ 192,  45},	{ 191,  43},	{ 191,  40},	{ 190,  38},	{ 190,  35},	{ 189,  33},	{ 188,  30},	{ 187,  28},	{ 186,  25},	{ 185,  23},	{ 184,  20},	{ 183,  18},	{ 182,  15},	{ 181,  13},	{ 180,  10},	{ 179,   8},	{ 178,   5},	{   0,   0},};struct battery_thresh  spitz_battery_levels_noac[] = {	{ 213, 100},	{ 212,  98},	{ 211,  95},	{ 210,  93},	{ 209,  90},	{ 208,  88},	{ 207,  85},	{ 206,  83},	{ 205,  80},	{ 204,  78},	{ 203,  75},	{ 202,  73},	{ 201,  70},	{ 200,  68},	{ 199,  65},	{ 198,  63},	{ 197,  60},	{ 196,  58},	{ 195,  55},	{ 194,  53},	{ 193,  50},	{ 192,  48},	{ 191,  45},	{ 190,  43},	{ 189,  40},	{ 188,  38},	{ 187,  35},	{ 186,  33},	{ 185,  30},	{ 184,  28},	{ 183,  25},	{ 182,  23},	{ 181,  20},	{ 180,  18},	{ 179,  15},	{ 178,  13},	{ 177,  10},	{ 176,   8},	{ 175,   5},	{   0,   0},};/* MAX1111 Commands */#define MAXCTRL_PD0      1u << 0#define MAXCTRL_PD1      1u << 1#define MAXCTRL_SGL      1u << 2#define MAXCTRL_UNI      1u << 3#define MAXCTRL_SEL_SH   4#define MAXCTRL_STR      1u << 7/* MAX1111 Channel Definitions */#define BATT_AD    4u#define BATT_THM   2u#define JK_VAD     6u/* * Prototypes */static int sharpsl_read_main_battery(void);static int sharpsl_off_charge_battery(void);static int sharpsl_check_battery_temp(void);static int sharpsl_check_battery_voltage(void);static int sharpsl_ac_check(void);static int sharpsl_fatal_check(void);static int sharpsl_average_value(int ad);static void sharpsl_average_clear(void);static void sharpsl_charge_toggle(void *private_);static void sharpsl_battery_thread(void *private_);/* * Variables */struct sharpsl_pm_status sharpsl_pm;DECLARE_WORK(toggle_charger, sharpsl_charge_toggle, NULL);DECLARE_WORK(sharpsl_bat, sharpsl_battery_thread, NULL);static int get_percentage(int voltage){	int i = sharpsl_pm.machinfo->bat_levels - 1;	struct battery_thresh *thresh;	if (sharpsl_pm.charge_mode == CHRG_ON)		thresh=sharpsl_pm.machinfo->bat_levels_acin;	else		thresh=sharpsl_pm.machinfo->bat_levels_noac;	while (i > 0 && (voltage > thresh[i].voltage))		i--;	return thresh[i].percentage;}static int get_apm_status(int voltage){	int low_thresh, high_thresh;	if (sharpsl_pm.charge_mode == CHRG_ON) {		high_thresh = sharpsl_pm.machinfo->status_high_acin;		low_thresh = sharpsl_pm.machinfo->status_low_acin;	} else {		high_thresh = sharpsl_pm.machinfo->status_high_noac;		low_thresh = sharpsl_pm.machinfo->status_low_noac;	}	if (voltage >= high_thresh)		return APM_BATTERY_STATUS_HIGH;	if (voltage >= low_thresh)		return APM_BATTERY_STATUS_LOW;	return APM_BATTERY_STATUS_CRITICAL;}void sharpsl_battery_kick(void){	schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(125));}EXPORT_SYMBOL(sharpsl_battery_kick);static void sharpsl_battery_thread(void *private_){	int voltage, percent, apm_status, i = 0;	if (!sharpsl_pm.machinfo)		return;	sharpsl_pm.battstat.ac_status = (STATUS_AC_IN() ? APM_AC_ONLINE : APM_AC_OFFLINE);	/* Corgi cannot confirm when battery fully charged so periodically kick! */	if (machine_is_corgi() && (sharpsl_pm.charge_mode == CHRG_ON)			&& time_after(jiffies, sharpsl_pm.charge_start_time +  SHARPSL_CHARGE_ON_TIME_INTERVAL))		schedule_work(&toggle_charger);	while(1) {		voltage = sharpsl_read_main_battery();		if (voltage > 0) break;		if (i++ > 5) {			voltage = sharpsl_pm.machinfo->bat_levels_noac[0].voltage;			dev_warn(sharpsl_pm.dev, "Warning: Cannot read main battery!\n");			break;		}	}	voltage = sharpsl_average_value(voltage);	apm_status = get_apm_status(voltage);	percent = get_percentage(voltage);	/* At low battery voltages, the voltage has a tendency to start           creeping back up so we try to avoid this here */	if ((sharpsl_pm.battstat.ac_status == APM_AC_ONLINE) || (apm_status == APM_BATTERY_STATUS_HIGH) ||  percent <= sharpsl_pm.battstat.mainbat_percent) {		sharpsl_pm.battstat.mainbat_voltage = voltage;		sharpsl_pm.battstat.mainbat_status = apm_status;		sharpsl_pm.battstat.mainbat_percent = percent;	}	dev_dbg(sharpsl_pm.dev, "Battery: voltage: %d, status: %d, percentage: %d, time: %d\n", voltage,			sharpsl_pm.battstat.mainbat_status, sharpsl_pm.battstat.mainbat_percent, jiffies);	/* If battery is low. limit backlight intensity to save power. */	if ((sharpsl_pm.battstat.ac_status != APM_AC_ONLINE)			&& ((sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_LOW) ||			(sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_CRITICAL))) {		if (!(sharpsl_pm.flags & SHARPSL_BL_LIMIT)) {			corgibl_limit_intensity(1);			sharpsl_pm.flags |= SHARPSL_BL_LIMIT;		}	} else if (sharpsl_pm.flags & SHARPSL_BL_LIMIT) {		corgibl_limit_intensity(0);		sharpsl_pm.flags &= ~SHARPSL_BL_LIMIT;	}	/* Suspend if critical battery level */	if ((sharpsl_pm.battstat.ac_status != APM_AC_ONLINE)			&& (sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_CRITICAL)			&& !(sharpsl_pm.flags & SHARPSL_APM_QUEUED)) {		sharpsl_pm.flags |= SHARPSL_APM_QUEUED;		dev_err(sharpsl_pm.dev, "Fatal Off\n");		apm_queue_event(APM_CRITICAL_SUSPEND);	}	schedule_delayed_work(&sharpsl_bat, SHARPSL_BATCHK_TIME);}static void sharpsl_charge_on(void){	dev_dbg(sharpsl_pm.dev, "Turning Charger On\n");	sharpsl_pm.full_count = 0;	sharpsl_pm.charge_mode = CHRG_ON;	schedule_delayed_work(&toggle_charger, msecs_to_jiffies(250));	schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(500));}static void sharpsl_charge_off(void){	dev_dbg(sharpsl_pm.dev, "Turning Charger Off\n");	CHARGE_OFF();	CHARGE_LED_OFF();	sharpsl_pm.charge_mode = CHRG_OFF;	schedule_work(&sharpsl_bat);}static void sharpsl_charge_error(void){	CHARGE_LED_ERR();	CHARGE_OFF();	sharpsl_pm.charge_mode = CHRG_ERROR;}static void sharpsl_charge_toggle(void *private_){	dev_dbg(sharpsl_pm.dev, "Toogling Charger at time: %lx\n", jiffies);	if (STATUS_AC_IN() == 0) {		sharpsl_charge_off();		return;	} else if ((sharpsl_check_battery_temp() < 0) || (sharpsl_ac_check() < 0)) {		sharpsl_charge_error();		return;	}	CHARGE_LED_ON();	CHARGE_OFF();	mdelay(SHARPSL_CHARGE_WAIT_TIME);	CHARGE_ON();	sharpsl_pm.charge_start_time = jiffies;}static void sharpsl_ac_timer(unsigned long data){	int acin = STATUS_AC_IN();	dev_dbg(sharpsl_pm.dev, "AC Status: %d\n",acin);	sharpsl_average_clear();	if (acin && (sharpsl_pm.charge_mode != CHRG_ON))		sharpsl_charge_on();	else if (sharpsl_pm.charge_mode == CHRG_ON)		sharpsl_charge_off();	schedule_work(&sharpsl_bat);}static irqreturn_t sharpsl_ac_isr(int irq, void *dev_id, struct pt_regs *fp){	/* Delay the event slightly to debounce */	/* Must be a smaller delay than the chrg_full_isr below */	mod_timer(&sharpsl_pm.ac_timer, jiffies + msecs_to_jiffies(250));	return IRQ_HANDLED;}static void sharpsl_chrg_full_timer(unsigned long data){	dev_dbg(sharpsl_pm.dev, "Charge Full at time: %lx\n", jiffies);	sharpsl_pm.full_count++;	if (STATUS_AC_IN() == 0) {		dev_dbg(sharpsl_pm.dev, "Charge Full: AC removed - stop charging!\n");		if (sharpsl_pm.charge_mode == CHRG_ON)			sharpsl_charge_off();	} else if (sharpsl_pm.full_count < 2) {		dev_dbg(sharpsl_pm.dev, "Charge Full: Count too low\n");		schedule_work(&toggle_charger);	} else if (time_after(jiffies, sharpsl_pm.charge_start_time + SHARPSL_CHARGE_FINISH_TIME)) {		dev_dbg(sharpsl_pm.dev, "Charge Full: Interrupt generated too slowly - retry.\n");		schedule_work(&toggle_charger);	} else {		sharpsl_charge_off();		sharpsl_pm.charge_mode = CHRG_DONE;		dev_dbg(sharpsl_pm.dev, "Charge Full: Charging Finished\n");	}}/* Charging Finished Interrupt (Not present on Corgi) *//* Can trigger at the same time as an AC staus change so   delay until after that has been processed */static irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id, struct pt_regs *fp){	if (sharpsl_pm.flags & SHARPSL_SUSPENDED)		return IRQ_HANDLED;	/* delay until after any ac interrupt */	mod_timer(&sharpsl_pm.chrg_full_timer, jiffies + msecs_to_jiffies(500));	return IRQ_HANDLED;}static irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id, struct pt_regs *fp){	int is_fatal = 0;	if (STATUS_BATT_LOCKED() == 0) {		dev_err(sharpsl_pm.dev, "Battery now Unlocked! Suspending.\n");		is_fatal = 1;	}	if (sharpsl_pm.machinfo->gpio_fatal && (STATUS_FATAL() == 0)) {		dev_err(sharpsl_pm.dev, "Fatal Batt Error! Suspending.\n");		is_fatal = 1;	}	if (!(sharpsl_pm.flags & SHARPSL_APM_QUEUED) && is_fatal) {		sharpsl_pm.flags |= SHARPSL_APM_QUEUED;		apm_queue_event(APM_CRITICAL_SUSPEND);	}	return IRQ_HANDLED;}/* * Maintain an average of the last 10 readings */#define SHARPSL_CNV_VALUE_NUM    10static int sharpsl_ad_index;static void sharpsl_average_clear(void){	sharpsl_ad_index = 0;}static int sharpsl_average_value(int ad){	int i, ad_val = 0;	static int sharpsl_ad[SHARPSL_CNV_VALUE_NUM+1];	if (sharpsl_pm.battstat.mainbat_status != APM_BATTERY_STATUS_HIGH) {		sharpsl_ad_index = 0;		return ad;	}	sharpsl_ad[sharpsl_ad_index] = ad;	sharpsl_ad_index++;	if (sharpsl_ad_index >= SHARPSL_CNV_VALUE_NUM) {		for (i=0; i < (SHARPSL_CNV_VALUE_NUM-1); i++)			sharpsl_ad[i] = sharpsl_ad[i+1];		sharpsl_ad_index = SHARPSL_CNV_VALUE_NUM - 1;	}	for (i=0; i < sharpsl_ad_index; i++)		ad_val += sharpsl_ad[i];	return (ad_val / sharpsl_ad_index);}/* * Read MAX1111 ADC */static int read_max1111(int channel){	return corgi_ssp_max1111_get((channel << MAXCTRL_SEL_SH) | MAXCTRL_PD0 | MAXCTRL_PD1			| MAXCTRL_SGL | MAXCTRL_UNI | MAXCTRL_STR);}static int sharpsl_read_main_battery(void){	return read_max1111(BATT_AD);}static int sharpsl_read_temp(void){	int temp;	sharpsl_pm.machinfo->measure_temp(1);	mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP);	temp = read_max1111(BATT_THM);	sharpsl_pm.machinfo->measure_temp(0);	return temp;}static int sharpsl_read_acin(void){	return read_max1111(JK_VAD);}/* * Take an array of 5 integers, remove the maximum and minimum values * and return the average. */static int get_select_val(int *val){	int i, j, k, temp, sum = 0;	/* Find MAX val */	temp = val[0];	j=0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -