1/* 2 * bios-less APM driver for hp680 3 * 4 * Copyright 2005 (c) Andriy Skulysh <askulysh@gmail.com> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License. 8 */ 9#include <linux/module.h> 10#include <linux/kernel.h> 11#include <linux/init.h> 12#include <linux/interrupt.h> 13#include <linux/apm-emulation.h> 14#include <linux/io.h> 15#include <asm/adc.h> 16#include <asm/hp6xx.h> 17 18#define SH7709_PGDR 0xa400012c 19 20#define APM_CRITICAL 10 21#define APM_LOW 30 22 23#define HP680_BATTERY_MAX 875 24#define HP680_BATTERY_MIN 600 25#define HP680_BATTERY_AC_ON 900 26 27#define MODNAME "hp6x0_apm" 28 29static void hp6x0_apm_get_power_status(struct apm_power_info *info) 30{ 31 int battery, backup, charging, percentage; 32 u8 pgdr; 33 34 battery = adc_single(ADC_CHANNEL_BATTERY); 35 backup = adc_single(ADC_CHANNEL_BACKUP); 36 charging = adc_single(ADC_CHANNEL_CHARGE); 37 38 percentage = 100 * (battery - HP680_BATTERY_MIN) / 39 (HP680_BATTERY_MAX - HP680_BATTERY_MIN); 40 41 info->ac_line_status = (battery > HP680_BATTERY_AC_ON) ? 42 APM_AC_ONLINE : APM_AC_OFFLINE; 43 44 pgdr = ctrl_inb(SH7709_PGDR); 45 if (pgdr & PGDR_MAIN_BATTERY_OUT) { 46 info->battery_status = APM_BATTERY_STATUS_NOT_PRESENT; 47 info->battery_flag = 0x80; 48 } else if (charging < 8) { 49 info->battery_status = APM_BATTERY_STATUS_CHARGING; 50 info->battery_flag = 0x08; 51 info->ac_line_status = 0xff; 52 } else if (percentage <= APM_CRITICAL) { 53 info->battery_status = APM_BATTERY_STATUS_CRITICAL; 54 info->battery_flag = 0x04; 55 } else if (percentage <= APM_LOW) { 56 info->battery_status = APM_BATTERY_STATUS_LOW; 57 info->battery_flag = 0x02; 58 } else { 59 info->battery_status = APM_BATTERY_STATUS_HIGH; 60 info->battery_flag = 0x01; 61 } 62 63 info->units = 0; 64} 65 66static irqreturn_t hp6x0_apm_interrupt(int irq, void *dev) 67{ 68 if (!apm_suspended) 69 apm_queue_event(APM_USER_SUSPEND); 70 71 return IRQ_HANDLED; 72} 73 74static int __init hp6x0_apm_init(void) 75{ 76 int ret; 77 78 ret = request_irq(HP680_BTN_IRQ, hp6x0_apm_interrupt, 79 IRQF_DISABLED, MODNAME, NULL); 80 if (unlikely(ret < 0)) { 81 printk(KERN_ERR MODNAME ": IRQ %d request failed\n", 82 HP680_BTN_IRQ); 83 return ret; 84 } 85 86 apm_get_power_status = hp6x0_apm_get_power_status; 87 88 return ret; 89} 90 91static void __exit hp6x0_apm_exit(void) 92{ 93 free_irq(HP680_BTN_IRQ, 0); 94 apm_get_info = NULL; 95} 96 97module_init(hp6x0_apm_init); 98module_exit(hp6x0_apm_exit); 99 100MODULE_AUTHOR("Adriy Skulysh"); 101MODULE_DESCRIPTION("hp6xx Advanced Power Management"); 102MODULE_LICENSE("GPL"); 103