Commit | Line | Data |
---|---|---|
3aa770e7 AS |
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 | */ | |
3aa770e7 | 9 | #include <linux/module.h> |
3aa770e7 AS |
10 | #include <linux/kernel.h> |
11 | #include <linux/init.h> | |
12 | #include <linux/interrupt.h> | |
0a9b0db1 PM |
13 | #include <linux/apm-emulation.h> |
14 | #include <linux/io.h> | |
3aa770e7 | 15 | #include <asm/adc.h> |
082c44d2 | 16 | #include <asm/hp6xx.h> |
3aa770e7 AS |
17 | |
18 | #define SH7709_PGDR 0xa400012c | |
19 | ||
20 | #define APM_CRITICAL 10 | |
21 | #define APM_LOW 30 | |
22 | ||
8c8ee825 KE |
23 | #define HP680_BATTERY_MAX 898 |
24 | #define HP680_BATTERY_MIN 486 | |
25 | #define HP680_BATTERY_AC_ON 1023 | |
3aa770e7 AS |
26 | |
27 | #define MODNAME "hp6x0_apm" | |
28 | ||
0a9b0db1 | 29 | static void hp6x0_apm_get_power_status(struct apm_power_info *info) |
3aa770e7 | 30 | { |
0a9b0db1 | 31 | int battery, backup, charging, percentage; |
3aa770e7 | 32 | u8 pgdr; |
3aa770e7 | 33 | |
0a9b0db1 PM |
34 | battery = adc_single(ADC_CHANNEL_BATTERY); |
35 | backup = adc_single(ADC_CHANNEL_BACKUP); | |
36 | charging = adc_single(ADC_CHANNEL_CHARGE); | |
3aa770e7 AS |
37 | |
38 | percentage = 100 * (battery - HP680_BATTERY_MIN) / | |
39 | (HP680_BATTERY_MAX - HP680_BATTERY_MIN); | |
40 | ||
0a9b0db1 | 41 | info->ac_line_status = (battery > HP680_BATTERY_AC_ON) ? |
3aa770e7 AS |
42 | APM_AC_ONLINE : APM_AC_OFFLINE; |
43 | ||
3aa770e7 AS |
44 | pgdr = ctrl_inb(SH7709_PGDR); |
45 | if (pgdr & PGDR_MAIN_BATTERY_OUT) { | |
0a9b0db1 PM |
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; | |
3aa770e7 | 52 | } else if (percentage <= APM_CRITICAL) { |
0a9b0db1 PM |
53 | info->battery_status = APM_BATTERY_STATUS_CRITICAL; |
54 | info->battery_flag = 0x04; | |
3aa770e7 | 55 | } else if (percentage <= APM_LOW) { |
0a9b0db1 PM |
56 | info->battery_status = APM_BATTERY_STATUS_LOW; |
57 | info->battery_flag = 0x02; | |
3aa770e7 | 58 | } else { |
0a9b0db1 PM |
59 | info->battery_status = APM_BATTERY_STATUS_HIGH; |
60 | info->battery_flag = 0x01; | |
3aa770e7 AS |
61 | } |
62 | ||
0a9b0db1 | 63 | info->units = 0; |
3aa770e7 AS |
64 | } |
65 | ||
35f3c518 | 66 | static irqreturn_t hp6x0_apm_interrupt(int irq, void *dev) |
3aa770e7 | 67 | { |
8c8ee825 | 68 | if (!APM_DISABLED) |
3aa770e7 AS |
69 | apm_queue_event(APM_USER_SUSPEND); |
70 | ||
71 | return IRQ_HANDLED; | |
72 | } | |
73 | ||
74 | static int __init hp6x0_apm_init(void) | |
75 | { | |
76 | int ret; | |
77 | ||
78 | ret = request_irq(HP680_BTN_IRQ, hp6x0_apm_interrupt, | |
0a9b0db1 | 79 | IRQF_DISABLED, MODNAME, NULL); |
3aa770e7 AS |
80 | if (unlikely(ret < 0)) { |
81 | printk(KERN_ERR MODNAME ": IRQ %d request failed\n", | |
82 | HP680_BTN_IRQ); | |
83 | return ret; | |
84 | } | |
85 | ||
0a9b0db1 | 86 | apm_get_power_status = hp6x0_apm_get_power_status; |
3aa770e7 AS |
87 | |
88 | return ret; | |
89 | } | |
90 | ||
91 | static void __exit hp6x0_apm_exit(void) | |
92 | { | |
93 | free_irq(HP680_BTN_IRQ, 0); | |
3aa770e7 AS |
94 | } |
95 | ||
96 | module_init(hp6x0_apm_init); | |
97 | module_exit(hp6x0_apm_exit); | |
98 | ||
99 | MODULE_AUTHOR("Adriy Skulysh"); | |
100 | MODULE_DESCRIPTION("hp6xx Advanced Power Management"); | |
101 | MODULE_LICENSE("GPL"); |