2006-09-27 16:20:22 +09:00
/*
* bios - less APM driver for hp680
*
* Copyright 2005 ( c ) Andriy Skulysh < askulysh @ gmail . com >
2008-03-04 23:09:25 -08:00
* Copyright 2008 ( c ) Kristoffer Ericson < kristoffer . ericson @ gmail . com >
2006-09-27 16:20:22 +09:00
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License .
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/interrupt.h>
2007-01-24 21:56:20 +09:00
# include <linux/apm-emulation.h>
# include <linux/io.h>
2006-09-27 16:20:22 +09:00
# include <asm/adc.h>
2008-10-20 13:02:48 +09:00
# include <mach/hp6xx.h>
2006-09-27 16:20:22 +09:00
2008-03-04 23:09:25 -08:00
/* percentage values */
2006-09-27 16:20:22 +09:00
# define APM_CRITICAL 10
# define APM_LOW 30
2008-03-04 23:09:25 -08:00
/* resonably sane values */
2007-09-11 12:43:33 +09:00
# define HP680_BATTERY_MAX 898
# define HP680_BATTERY_MIN 486
# define HP680_BATTERY_AC_ON 1023
2006-09-27 16:20:22 +09:00
# define MODNAME "hp6x0_apm"
2008-03-06 13:48:08 +09:00
# define PGDR 0xa400012c
2007-01-24 21:56:20 +09:00
static void hp6x0_apm_get_power_status ( struct apm_power_info * info )
2006-09-27 16:20:22 +09:00
{
2007-01-24 21:56:20 +09:00
int battery , backup , charging , percentage ;
2006-09-27 16:20:22 +09:00
u8 pgdr ;
2007-01-24 21:56:20 +09:00
battery = adc_single ( ADC_CHANNEL_BATTERY ) ;
backup = adc_single ( ADC_CHANNEL_BACKUP ) ;
charging = adc_single ( ADC_CHANNEL_CHARGE ) ;
2006-09-27 16:20:22 +09:00
percentage = 100 * ( battery - HP680_BATTERY_MIN ) /
( HP680_BATTERY_MAX - HP680_BATTERY_MIN ) ;
2008-03-04 23:09:25 -08:00
/* % of full battery */
info - > battery_life = percentage ;
/* We want our estimates in minutes */
info - > units = 0 ;
/* Extremely(!!) rough estimate, we will replace this with a datalist later on */
info - > time = ( 2 * battery ) ;
2007-01-24 21:56:20 +09:00
info - > ac_line_status = ( battery > HP680_BATTERY_AC_ON ) ?
2006-09-27 16:20:22 +09:00
APM_AC_ONLINE : APM_AC_OFFLINE ;
2010-01-26 12:58:40 +09:00
pgdr = __raw_readb ( PGDR ) ;
2006-09-27 16:20:22 +09:00
if ( pgdr & PGDR_MAIN_BATTERY_OUT ) {
2007-01-24 21:56:20 +09:00
info - > battery_status = APM_BATTERY_STATUS_NOT_PRESENT ;
info - > battery_flag = 0x80 ;
} else if ( charging < 8 ) {
info - > battery_status = APM_BATTERY_STATUS_CHARGING ;
info - > battery_flag = 0x08 ;
2008-03-04 23:09:25 -08:00
info - > ac_line_status = 0x01 ;
2006-09-27 16:20:22 +09:00
} else if ( percentage < = APM_CRITICAL ) {
2007-01-24 21:56:20 +09:00
info - > battery_status = APM_BATTERY_STATUS_CRITICAL ;
info - > battery_flag = 0x04 ;
2006-09-27 16:20:22 +09:00
} else if ( percentage < = APM_LOW ) {
2007-01-24 21:56:20 +09:00
info - > battery_status = APM_BATTERY_STATUS_LOW ;
info - > battery_flag = 0x02 ;
2006-09-27 16:20:22 +09:00
} else {
2007-01-24 21:56:20 +09:00
info - > battery_status = APM_BATTERY_STATUS_HIGH ;
info - > battery_flag = 0x01 ;
2006-09-27 16:20:22 +09:00
}
}
2006-10-06 15:31:16 +09:00
static irqreturn_t hp6x0_apm_interrupt ( int irq , void * dev )
2006-09-27 16:20:22 +09:00
{
2007-09-11 12:43:33 +09:00
if ( ! APM_DISABLED )
2006-09-27 16:20:22 +09:00
apm_queue_event ( APM_USER_SUSPEND ) ;
return IRQ_HANDLED ;
}
static int __init hp6x0_apm_init ( void )
{
int ret ;
ret = request_irq ( HP680_BTN_IRQ , hp6x0_apm_interrupt ,
2007-01-24 21:56:20 +09:00
IRQF_DISABLED , MODNAME , NULL ) ;
2006-09-27 16:20:22 +09:00
if ( unlikely ( ret < 0 ) ) {
printk ( KERN_ERR MODNAME " : IRQ %d request failed \n " ,
HP680_BTN_IRQ ) ;
return ret ;
}
2007-01-24 21:56:20 +09:00
apm_get_power_status = hp6x0_apm_get_power_status ;
2006-09-27 16:20:22 +09:00
return ret ;
}
static void __exit hp6x0_apm_exit ( void )
{
free_irq ( HP680_BTN_IRQ , 0 ) ;
}
module_init ( hp6x0_apm_init ) ;
module_exit ( hp6x0_apm_exit ) ;
MODULE_AUTHOR ( " Adriy Skulysh " ) ;
MODULE_DESCRIPTION ( " hp6xx Advanced Power Management " ) ;
MODULE_LICENSE ( " GPL " ) ;