Merge master.kernel.org:/pub/scm/linux/kernel/git/lethal/sh64-2.6
[pandora-kernel.git] / arch / sh / boards / hp6xx / hp6xx_apm.c
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/config.h>
10 #include <linux/module.h>
11 #include <linux/apm_bios.h>
12 #include <linux/kernel.h>
13 #include <linux/init.h>
14 #include <linux/interrupt.h>
15 #include <asm/io.h>
16 #include <asm/apm.h>
17 #include <asm/adc.h>
18 #include <asm/hp6xx/hp6xx.h>
19
20 #define SH7709_PGDR                     0xa400012c
21
22 #define APM_CRITICAL                    10
23 #define APM_LOW                         30
24
25 #define HP680_BATTERY_MAX               875
26 #define HP680_BATTERY_MIN               600
27 #define HP680_BATTERY_AC_ON             900
28
29 #define MODNAME "hp6x0_apm"
30
31 static int hp6x0_apm_get_info(char *buf, char **start, off_t fpos, int length)
32 {
33         u8 pgdr;
34         char *p;
35         int battery_status;
36         int battery_flag;
37         int ac_line_status;
38         int time_units = APM_BATTERY_LIFE_UNKNOWN;
39
40         int battery = adc_single(ADC_CHANNEL_BATTERY);
41         int backup = adc_single(ADC_CHANNEL_BACKUP);
42         int charging = adc_single(ADC_CHANNEL_CHARGE);
43         int percentage;
44
45         percentage = 100 * (battery - HP680_BATTERY_MIN) /
46                            (HP680_BATTERY_MAX - HP680_BATTERY_MIN);
47
48         ac_line_status = (battery > HP680_BATTERY_AC_ON) ?
49                          APM_AC_ONLINE : APM_AC_OFFLINE;
50
51         p = buf;
52
53         pgdr = ctrl_inb(SH7709_PGDR);
54         if (pgdr & PGDR_MAIN_BATTERY_OUT) {
55                 battery_status = APM_BATTERY_STATUS_NOT_PRESENT;
56                 battery_flag = 0x80;
57                 percentage = -1;
58         } else if (charging < 8 ) {
59                 battery_status = APM_BATTERY_STATUS_CHARGING;
60                 battery_flag = 0x08;
61                 ac_line_status = 0xff;
62         } else if (percentage <= APM_CRITICAL) {
63                 battery_status = APM_BATTERY_STATUS_CRITICAL;
64                 battery_flag = 0x04;
65         } else if (percentage <= APM_LOW) {
66                 battery_status = APM_BATTERY_STATUS_LOW;
67                 battery_flag = 0x02;
68         } else {
69                 battery_status = APM_BATTERY_STATUS_HIGH;
70                 battery_flag = 0x01;
71         }
72
73         p += sprintf(p, "1.0 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
74                      APM_32_BIT_SUPPORT,
75                      ac_line_status,
76                      battery_status,
77                      battery_flag,
78                      percentage,
79                      time_units,
80                      "min");
81         p += sprintf(p, "bat=%d backup=%d charge=%d\n",
82                      battery, backup, charging);
83
84         return p - buf;
85 }
86
87 static irqreturn_t hp6x0_apm_interrupt(int irq, void *dev, struct pt_regs *regs)
88 {
89         if (!apm_suspended)
90                 apm_queue_event(APM_USER_SUSPEND);
91
92         return IRQ_HANDLED;
93 }
94
95 static int __init hp6x0_apm_init(void)
96 {
97         int ret;
98
99         ret = request_irq(HP680_BTN_IRQ, hp6x0_apm_interrupt,
100                           SA_INTERRUPT, MODNAME, 0);
101         if (unlikely(ret < 0)) {
102                 printk(KERN_ERR MODNAME ": IRQ %d request failed\n",
103                        HP680_BTN_IRQ);
104                 return ret;
105         }
106
107         apm_get_info = hp6x0_apm_get_info;
108
109         return ret;
110 }
111
112 static void __exit hp6x0_apm_exit(void)
113 {
114         free_irq(HP680_BTN_IRQ, 0);
115         apm_get_info = 0;
116 }
117
118 module_init(hp6x0_apm_init);
119 module_exit(hp6x0_apm_exit);
120
121 MODULE_AUTHOR("Adriy Skulysh");
122 MODULE_DESCRIPTION("hp6xx Advanced Power Management");
123 MODULE_LICENSE("GPL");