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

📄 sharpsl_pm.c

📁 LINUX 2.6.17.4的源码
💻 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 <linux/leds.h>#include <asm/hardware.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 <asm/hardware/sharpsl_pm.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 *//* * Prototypes */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);DEFINE_LED_TRIGGER(sharpsl_charge_led_trigger);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 = (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN) ? 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_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT);		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);}void sharpsl_pm_led(int val){	if (val == SHARPSL_LED_ERROR) {		dev_err(sharpsl_pm.dev, "Charging Error!\n");	} else if (val == SHARPSL_LED_ON) {		dev_dbg(sharpsl_pm.dev, "Charge LED On\n");		led_trigger_event(sharpsl_charge_led_trigger, LED_FULL);	} else {		dev_dbg(sharpsl_pm.dev, "Charge LED Off\n");		led_trigger_event(sharpsl_charge_led_trigger, LED_OFF);	}}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");	sharpsl_pm.machinfo->charge(0);	sharpsl_pm_led(SHARPSL_LED_OFF);	sharpsl_pm.charge_mode = CHRG_OFF;	schedule_work(&sharpsl_bat);}static void sharpsl_charge_error(void){	sharpsl_pm_led(SHARPSL_LED_ERROR);	sharpsl_pm.machinfo->charge(0);	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 (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN)) {		sharpsl_charge_off();		return;	} else if ((sharpsl_check_battery_temp() < 0) || (sharpsl_ac_check() < 0)) {		sharpsl_charge_error();		return;	}	sharpsl_pm_led(SHARPSL_LED_ON);	sharpsl_pm.machinfo->charge(0);	mdelay(SHARPSL_CHARGE_WAIT_TIME);	sharpsl_pm.machinfo->charge(1);	sharpsl_pm.charge_start_time = jiffies;}static void sharpsl_ac_timer(unsigned long data){	int acin = sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN);	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);}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 (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN)) {		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 */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;}irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id, struct pt_regs *fp){	int is_fatal = 0;	if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_LOCK)) {		dev_err(sharpsl_pm.dev, "Battery now Unlocked! Suspending.\n");		is_fatal = 1;	}	if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_FATAL)) {		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);}/* * 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;	for (i=1; i<5; i++) {		if (temp < val[i]) {			temp = val[i];			j = i;		}	}	/* Find MIN val */	temp = val[4];	k=4;	for (i=3; i>=0; i--) {		if (temp > val[i]) {			temp = val[i];			k = i;		}	}	for (i=0; i<5; i++)		if (i != j && i != k )			sum += val[i];	dev_dbg(sharpsl_pm.dev, "Average: %d from values: %d, %d, %d, %d, %d\n", sum/3, val[0], val[1], val[2], val[3], val[4]);	return (sum/3);}static int sharpsl_check_battery_temp(void){	int val, i, buff[5];	/* Check battery temperature */	for (i=0; i<5; i++) {		mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP);		sharpsl_pm.machinfo->measure_temp(1);		mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP);		buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_TEMP);		sharpsl_pm.machinfo->measure_temp(0);	}	val = get_select_val(buff);	dev_dbg(sharpsl_pm.dev, "Temperature: %d\n", val);	if (val > SHARPSL_CHARGE_ON_TEMP)		return -1;

⌨️ 快捷键说明

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