Commit 3aa770e7972723f479122cf66b529017d2175289
Committed by
Paul Mundt
1 parent
ef48e8e349
Exists in
master
and in
4 other branches
sh: APM/PM support.
This adds some simple PM stubs and the basic APM interfaces, primarily for use by hp6xx, where the existing userland expects it. Signed-off-by: Andriy Skulysh <askulysh@gmail.com> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Showing 21 changed files with 1124 additions and 22 deletions Side-by-side Diff
- arch/sh/Kconfig
- arch/sh/boards/hp6xx/Makefile
- arch/sh/boards/hp6xx/hp6xx_apm.c
- arch/sh/boards/hp6xx/pm.c
- arch/sh/boards/hp6xx/pm_wakeup.S
- arch/sh/boards/hp6xx/setup.c
- arch/sh/kernel/Makefile
- arch/sh/kernel/apm.c
- arch/sh/kernel/entry.S
- arch/sh/kernel/pm.c
- arch/sh/kernel/sh_ksyms.c
- arch/sh/kernel/time.c
- arch/sh/kernel/timers/timer-tmu.c
- drivers/input/touchscreen/hp680_ts_input.c
- include/asm-sh/apm.h
- include/asm-sh/cpu-sh3/freq.h
- include/asm-sh/hd64461.h
- include/asm-sh/hp6xx/hp6xx.h
- include/asm-sh/pm.h
- include/asm-sh/system.h
- include/asm-sh/timer.h
arch/sh/Kconfig
... | ... | @@ -638,6 +638,16 @@ |
638 | 638 | |
639 | 639 | endmenu |
640 | 640 | |
641 | +menu "Power management options (EXPERIMENTAL)" | |
642 | +depends on EXPERIMENTAL | |
643 | + | |
644 | +source kernel/power/Kconfig | |
645 | + | |
646 | +config APM | |
647 | + bool "Advanced Power Management Emulation" | |
648 | + depends on PM | |
649 | +endmenu | |
650 | + | |
641 | 651 | source "net/Kconfig" |
642 | 652 | |
643 | 653 | source "drivers/Kconfig" |
arch/sh/boards/hp6xx/Makefile
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"); |
arch/sh/boards/hp6xx/pm.c
1 | +/* | |
2 | + * hp6x0 Power Management Routines | |
3 | + * | |
4 | + * Copyright (c) 2006 Andriy Skulysh <askulsyh@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/init.h> | |
11 | +#include <linux/suspend.h> | |
12 | +#include <linux/errno.h> | |
13 | +#include <linux/time.h> | |
14 | +#include <asm/io.h> | |
15 | +#include <asm/hd64461.h> | |
16 | +#include <asm/hp6xx/hp6xx.h> | |
17 | +#include <asm/cpu/dac.h> | |
18 | +#include <asm/pm.h> | |
19 | + | |
20 | +#define STBCR 0xffffff82 | |
21 | +#define STBCR2 0xffffff88 | |
22 | + | |
23 | +static int hp6x0_pm_enter(suspend_state_t state) | |
24 | +{ | |
25 | + u8 stbcr, stbcr2; | |
26 | +#ifdef CONFIG_HD64461_ENABLER | |
27 | + u8 scr; | |
28 | + u16 hd64461_stbcr; | |
29 | +#endif | |
30 | + | |
31 | + if (state != PM_SUSPEND_MEM) | |
32 | + return -EINVAL; | |
33 | + | |
34 | +#ifdef CONFIG_HD64461_ENABLER | |
35 | + outb(0, HD64461_PCC1CSCIER); | |
36 | + | |
37 | + scr = inb(HD64461_PCC1SCR); | |
38 | + scr |= HD64461_PCCSCR_VCC1; | |
39 | + outb(scr, HD64461_PCC1SCR); | |
40 | + | |
41 | + hd64461_stbcr = inw(HD64461_STBCR); | |
42 | + hd64461_stbcr |= HD64461_STBCR_SPC1ST; | |
43 | + outw(hd64461_stbcr, HD64461_STBCR); | |
44 | +#endif | |
45 | + | |
46 | + ctrl_outb(0x1f, DACR); | |
47 | + | |
48 | + stbcr = ctrl_inb(STBCR); | |
49 | + ctrl_outb(0x01, STBCR); | |
50 | + | |
51 | + stbcr2 = ctrl_inb(STBCR2); | |
52 | + ctrl_outb(0x7f , STBCR2); | |
53 | + | |
54 | + outw(0xf07f, HD64461_SCPUCR); | |
55 | + | |
56 | + pm_enter(); | |
57 | + | |
58 | + outw(0, HD64461_SCPUCR); | |
59 | + ctrl_outb(stbcr, STBCR); | |
60 | + ctrl_outb(stbcr2, STBCR2); | |
61 | + | |
62 | +#ifdef CONFIG_HD64461_ENABLER | |
63 | + hd64461_stbcr = inw(HD64461_STBCR); | |
64 | + hd64461_stbcr &= ~HD64461_STBCR_SPC1ST; | |
65 | + outw(hd64461_stbcr, HD64461_STBCR); | |
66 | + | |
67 | + outb(0x4c, HD64461_PCC1CSCIER); | |
68 | + outb(0x00, HD64461_PCC1CSCR); | |
69 | +#endif | |
70 | + | |
71 | + return 0; | |
72 | +} | |
73 | + | |
74 | +/* | |
75 | + * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk. | |
76 | + */ | |
77 | +static struct pm_ops hp6x0_pm_ops = { | |
78 | + .pm_disk_mode = PM_DISK_FIRMWARE, | |
79 | + .enter = hp6x0_pm_enter, | |
80 | +}; | |
81 | + | |
82 | +static int __init hp6x0_pm_init(void) | |
83 | +{ | |
84 | + pm_set_ops(&hp6x0_pm_ops); | |
85 | + return 0; | |
86 | +} | |
87 | + | |
88 | +late_initcall(hp6x0_pm_init); |
arch/sh/boards/hp6xx/pm_wakeup.S
1 | +/* | |
2 | + * Copyright (c) 2006 Andriy Skulysh <askulsyh@gmail.com> | |
3 | + * | |
4 | + * This file is subject to the terms and conditions of the GNU General Public | |
5 | + * License. See the file "COPYING" in the main directory of this archive | |
6 | + * for more details. | |
7 | + * | |
8 | + */ | |
9 | + | |
10 | +#include <linux/linkage.h> | |
11 | +#include <asm/cpu/mmu_context.h> | |
12 | + | |
13 | +#define k0 r0 | |
14 | +#define k1 r1 | |
15 | +#define k2 r2 | |
16 | +#define k3 r3 | |
17 | +#define k4 r4 | |
18 | + | |
19 | +/* | |
20 | + * Kernel mode register usage: | |
21 | + * k0 scratch | |
22 | + * k1 scratch | |
23 | + * k2 scratch (Exception code) | |
24 | + * k3 scratch (Return address) | |
25 | + * k4 scratch | |
26 | + * k5 reserved | |
27 | + * k6 Global Interrupt Mask (0--15 << 4) | |
28 | + * k7 CURRENT_THREAD_INFO (pointer to current thread info) | |
29 | + */ | |
30 | + | |
31 | +ENTRY(wakeup_start) | |
32 | +! clear STBY bit | |
33 | + mov #-126, k2 | |
34 | + and #127, k0 | |
35 | + mov.b k0, @k2 | |
36 | +! enable refresh | |
37 | + mov.l 5f, k1 | |
38 | + mov.w 6f, k0 | |
39 | + mov.w k0, @k1 | |
40 | +! jump to handler | |
41 | + mov.l 2f, k2 | |
42 | + mov.l 3f, k3 | |
43 | + mov.l @k2, k2 | |
44 | + | |
45 | + mov.l 4f, k1 | |
46 | + jmp @k1 | |
47 | + nop | |
48 | + | |
49 | + .align 2 | |
50 | +1: .long EXPEVT | |
51 | +2: .long INTEVT | |
52 | +3: .long ret_from_irq | |
53 | +4: .long handle_exception | |
54 | +5: .long 0xffffff68 | |
55 | +6: .word 0x0524 | |
56 | + | |
57 | +ENTRY(wakeup_end) | |
58 | + nop |
arch/sh/boards/hp6xx/setup.c
... | ... | @@ -15,6 +15,9 @@ |
15 | 15 | #include <asm/hp6xx/hp6xx.h> |
16 | 16 | #include <asm/cpu/dac.h> |
17 | 17 | |
18 | +#define SCPCR 0xa4000116 | |
19 | +#define SCPDR 0xa4000136 | |
20 | + | |
18 | 21 | const char *get_system_type(void) |
19 | 22 | { |
20 | 23 | return "HP6xx"; |
... | ... | @@ -24,6 +27,7 @@ |
24 | 27 | { |
25 | 28 | u8 v8; |
26 | 29 | u16 v; |
30 | + | |
27 | 31 | v = inw(HD64461_STBCR); |
28 | 32 | v |= HD64461_STBCR_SURTST | HD64461_STBCR_SIRST | |
29 | 33 | HD64461_STBCR_STM1ST | HD64461_STBCR_STM0ST | |
... | ... | @@ -49,6 +53,16 @@ |
49 | 53 | v8 = ctrl_inb(DACR); |
50 | 54 | v8 &= ~DACR_DAE; |
51 | 55 | ctrl_outb(v8,DACR); |
56 | + | |
57 | + v8 = ctrl_inb(SCPDR); | |
58 | + v8 |= SCPDR_TS_SCAN_X | SCPDR_TS_SCAN_Y; | |
59 | + v8 &= ~SCPDR_TS_SCAN_ENABLE; | |
60 | + ctrl_outb(v8, SCPDR); | |
61 | + | |
62 | + v = ctrl_inw(SCPCR); | |
63 | + v &= ~SCPCR_TS_MASK; | |
64 | + v |= SCPCR_TS_ENABLE; | |
65 | + ctrl_outw(v, SCPCR); | |
52 | 66 | |
53 | 67 | return 0; |
54 | 68 | } |
arch/sh/kernel/Makefile
arch/sh/kernel/apm.c
1 | +/* | |
2 | + * bios-less APM driver for hp680 | |
3 | + * | |
4 | + * Copyright 2005 (c) Andriy Skulysh <askulysh@gmail.com> | |
5 | + * | |
6 | + * based on ARM APM driver by | |
7 | + * Jamey Hicks <jamey@crl.dec.com> | |
8 | + * | |
9 | + * adapted from the APM BIOS driver for Linux by | |
10 | + * Stephen Rothwell (sfr@linuxcare.com) | |
11 | + * | |
12 | + * APM 1.2 Reference: | |
13 | + * Intel Corporation, Microsoft Corporation. Advanced Power Management | |
14 | + * (APM) BIOS Interface Specification, Revision 1.2, February 1996. | |
15 | + * | |
16 | + * [This document is available from Microsoft at: | |
17 | + * http://www.microsoft.com/hwdev/busbios/amp_12.htm] | |
18 | + */ | |
19 | +#include <linux/config.h> | |
20 | +#include <linux/module.h> | |
21 | +#include <linux/poll.h> | |
22 | +#include <linux/timer.h> | |
23 | +#include <linux/slab.h> | |
24 | +#include <linux/proc_fs.h> | |
25 | +#include <linux/miscdevice.h> | |
26 | +#include <linux/apm_bios.h> | |
27 | +#include <linux/pm.h> | |
28 | +#include <linux/pm_legacy.h> | |
29 | +#include <asm/apm.h> | |
30 | + | |
31 | +#define MODNAME "apm" | |
32 | + | |
33 | +/* | |
34 | + * The apm_bios device is one of the misc char devices. | |
35 | + * This is its minor number. | |
36 | + */ | |
37 | +#define APM_MINOR_DEV 134 | |
38 | + | |
39 | +/* | |
40 | + * Maximum number of events stored | |
41 | + */ | |
42 | +#define APM_MAX_EVENTS 16 | |
43 | + | |
44 | +struct apm_queue { | |
45 | + unsigned int event_head; | |
46 | + unsigned int event_tail; | |
47 | + apm_event_t events[APM_MAX_EVENTS]; | |
48 | +}; | |
49 | + | |
50 | +/* | |
51 | + * The per-file APM data | |
52 | + */ | |
53 | +struct apm_user { | |
54 | + struct list_head list; | |
55 | + | |
56 | + unsigned int suser: 1; | |
57 | + unsigned int writer: 1; | |
58 | + unsigned int reader: 1; | |
59 | + | |
60 | + int suspend_result; | |
61 | + unsigned int suspend_state; | |
62 | +#define SUSPEND_NONE 0 /* no suspend pending */ | |
63 | +#define SUSPEND_PENDING 1 /* suspend pending read */ | |
64 | +#define SUSPEND_READ 2 /* suspend read, pending ack */ | |
65 | +#define SUSPEND_ACKED 3 /* suspend acked */ | |
66 | +#define SUSPEND_DONE 4 /* suspend completed */ | |
67 | + | |
68 | + struct apm_queue queue; | |
69 | +}; | |
70 | + | |
71 | +/* | |
72 | + * Local variables | |
73 | + */ | |
74 | +static int suspends_pending; | |
75 | + | |
76 | +static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); | |
77 | +static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); | |
78 | + | |
79 | +/* | |
80 | + * This is a list of everyone who has opened /dev/apm_bios | |
81 | + */ | |
82 | +static DECLARE_RWSEM(user_list_lock); | |
83 | +static LIST_HEAD(apm_user_list); | |
84 | + | |
85 | +/* | |
86 | + * kapmd info. kapmd provides us a process context to handle | |
87 | + * "APM" events within - specifically necessary if we're going | |
88 | + * to be suspending the system. | |
89 | + */ | |
90 | +static DECLARE_WAIT_QUEUE_HEAD(kapmd_wait); | |
91 | +static DECLARE_COMPLETION(kapmd_exit); | |
92 | +static DEFINE_SPINLOCK(kapmd_queue_lock); | |
93 | +static struct apm_queue kapmd_queue; | |
94 | + | |
95 | +int apm_suspended; | |
96 | +EXPORT_SYMBOL(apm_suspended); | |
97 | + | |
98 | +/* Platform-specific apm_read_proc(). */ | |
99 | +int (*apm_get_info)(char *buf, char **start, off_t fpos, int length); | |
100 | +EXPORT_SYMBOL(apm_get_info); | |
101 | + | |
102 | +/* | |
103 | + * APM event queue management. | |
104 | + */ | |
105 | +static inline int queue_empty(struct apm_queue *q) | |
106 | +{ | |
107 | + return q->event_head == q->event_tail; | |
108 | +} | |
109 | + | |
110 | +static inline apm_event_t queue_get_event(struct apm_queue *q) | |
111 | +{ | |
112 | + q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS; | |
113 | + return q->events[q->event_tail]; | |
114 | +} | |
115 | + | |
116 | +static void queue_add_event(struct apm_queue *q, apm_event_t event) | |
117 | +{ | |
118 | + q->event_head = (q->event_head + 1) % APM_MAX_EVENTS; | |
119 | + if (q->event_head == q->event_tail) { | |
120 | + static int notified; | |
121 | + | |
122 | + if (notified++ == 0) | |
123 | + printk(KERN_ERR "apm: an event queue overflowed\n"); | |
124 | + | |
125 | + q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS; | |
126 | + } | |
127 | + q->events[q->event_head] = event; | |
128 | +} | |
129 | + | |
130 | +static void queue_event_one_user(struct apm_user *as, apm_event_t event) | |
131 | +{ | |
132 | + if (as->suser && as->writer) { | |
133 | + switch (event) { | |
134 | + case APM_SYS_SUSPEND: | |
135 | + case APM_USER_SUSPEND: | |
136 | + /* | |
137 | + * If this user already has a suspend pending, | |
138 | + * don't queue another one. | |
139 | + */ | |
140 | + if (as->suspend_state != SUSPEND_NONE) | |
141 | + return; | |
142 | + | |
143 | + as->suspend_state = SUSPEND_PENDING; | |
144 | + suspends_pending++; | |
145 | + break; | |
146 | + } | |
147 | + } | |
148 | + queue_add_event(&as->queue, event); | |
149 | +} | |
150 | + | |
151 | +static void queue_event(apm_event_t event, struct apm_user *sender) | |
152 | +{ | |
153 | + struct apm_user *as; | |
154 | + | |
155 | + down_read(&user_list_lock); | |
156 | + | |
157 | + list_for_each_entry(as, &apm_user_list, list) | |
158 | + if (as != sender && as->reader) | |
159 | + queue_event_one_user(as, event); | |
160 | + | |
161 | + up_read(&user_list_lock); | |
162 | + wake_up_interruptible(&apm_waitqueue); | |
163 | +} | |
164 | + | |
165 | +/** | |
166 | + * apm_queue_event - queue an APM event for kapmd | |
167 | + * @event: APM event | |
168 | + * | |
169 | + * Queue an APM event for kapmd to process and ultimately take the | |
170 | + * appropriate action. Only a subset of events are handled: | |
171 | + * %APM_LOW_BATTERY | |
172 | + * %APM_POWER_STATUS_CHANGE | |
173 | + * %APM_USER_SUSPEND | |
174 | + * %APM_SYS_SUSPEND | |
175 | + * %APM_CRITICAL_SUSPEND | |
176 | + */ | |
177 | +void apm_queue_event(apm_event_t event) | |
178 | +{ | |
179 | + spin_lock_irq(&kapmd_queue_lock); | |
180 | + queue_add_event(&kapmd_queue, event); | |
181 | + spin_unlock_irq(&kapmd_queue_lock); | |
182 | + | |
183 | + wake_up_interruptible(&kapmd_wait); | |
184 | +} | |
185 | +EXPORT_SYMBOL(apm_queue_event); | |
186 | + | |
187 | +static void apm_suspend(void) | |
188 | +{ | |
189 | + struct apm_user *as; | |
190 | + int err; | |
191 | + | |
192 | + apm_suspended = 1; | |
193 | + err = pm_suspend(PM_SUSPEND_MEM); | |
194 | + | |
195 | + /* | |
196 | + * Anyone on the APM queues will think we're still suspended. | |
197 | + * Send a message so everyone knows we're now awake again. | |
198 | + */ | |
199 | + queue_event(APM_NORMAL_RESUME, NULL); | |
200 | + | |
201 | + /* | |
202 | + * Finally, wake up anyone who is sleeping on the suspend. | |
203 | + */ | |
204 | + down_read(&user_list_lock); | |
205 | + list_for_each_entry(as, &apm_user_list, list) { | |
206 | + as->suspend_result = err; | |
207 | + as->suspend_state = SUSPEND_DONE; | |
208 | + } | |
209 | + up_read(&user_list_lock); | |
210 | + | |
211 | + wake_up(&apm_suspend_waitqueue); | |
212 | + apm_suspended = 0; | |
213 | +} | |
214 | + | |
215 | +static ssize_t apm_read(struct file *fp, char __user *buf, | |
216 | + size_t count, loff_t *ppos) | |
217 | +{ | |
218 | + struct apm_user *as = fp->private_data; | |
219 | + apm_event_t event; | |
220 | + int i = count, ret = 0; | |
221 | + | |
222 | + if (count < sizeof(apm_event_t)) | |
223 | + return -EINVAL; | |
224 | + | |
225 | + if (queue_empty(&as->queue) && fp->f_flags & O_NONBLOCK) | |
226 | + return -EAGAIN; | |
227 | + | |
228 | + wait_event_interruptible(apm_waitqueue, !queue_empty(&as->queue)); | |
229 | + | |
230 | + while ((i >= sizeof(event)) && !queue_empty(&as->queue)) { | |
231 | + event = queue_get_event(&as->queue); | |
232 | + | |
233 | + ret = -EFAULT; | |
234 | + if (copy_to_user(buf, &event, sizeof(event))) | |
235 | + break; | |
236 | + | |
237 | + if (event == APM_SYS_SUSPEND || event == APM_USER_SUSPEND) | |
238 | + as->suspend_state = SUSPEND_READ; | |
239 | + | |
240 | + buf += sizeof(event); | |
241 | + i -= sizeof(event); | |
242 | + } | |
243 | + | |
244 | + if (i < count) | |
245 | + ret = count - i; | |
246 | + | |
247 | + return ret; | |
248 | +} | |
249 | + | |
250 | +static unsigned int apm_poll(struct file *fp, poll_table * wait) | |
251 | +{ | |
252 | + struct apm_user *as = fp->private_data; | |
253 | + | |
254 | + poll_wait(fp, &apm_waitqueue, wait); | |
255 | + return queue_empty(&as->queue) ? 0 : POLLIN | POLLRDNORM; | |
256 | +} | |
257 | + | |
258 | +/* | |
259 | + * apm_ioctl - handle APM ioctl | |
260 | + * | |
261 | + * APM_IOC_SUSPEND | |
262 | + * This IOCTL is overloaded, and performs two functions. It is used to: | |
263 | + * - initiate a suspend | |
264 | + * - acknowledge a suspend read from /dev/apm_bios. | |
265 | + * Only when everyone who has opened /dev/apm_bios with write permission | |
266 | + * has acknowledge does the actual suspend happen. | |
267 | + */ | |
268 | +static int | |
269 | +apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg) | |
270 | +{ | |
271 | + struct apm_user *as = filp->private_data; | |
272 | + unsigned long flags; | |
273 | + int err = -EINVAL; | |
274 | + | |
275 | + if (!as->suser || !as->writer) | |
276 | + return -EPERM; | |
277 | + | |
278 | + switch (cmd) { | |
279 | + case APM_IOC_SUSPEND: | |
280 | + as->suspend_result = -EINTR; | |
281 | + | |
282 | + if (as->suspend_state == SUSPEND_READ) { | |
283 | + /* | |
284 | + * If we read a suspend command from /dev/apm_bios, | |
285 | + * then the corresponding APM_IOC_SUSPEND ioctl is | |
286 | + * interpreted as an acknowledge. | |
287 | + */ | |
288 | + as->suspend_state = SUSPEND_ACKED; | |
289 | + suspends_pending--; | |
290 | + } else { | |
291 | + /* | |
292 | + * Otherwise it is a request to suspend the system. | |
293 | + * Queue an event for all readers, and expect an | |
294 | + * acknowledge from all writers who haven't already | |
295 | + * acknowledged. | |
296 | + */ | |
297 | + queue_event(APM_USER_SUSPEND, as); | |
298 | + } | |
299 | + | |
300 | + /* | |
301 | + * If there are no further acknowledges required, suspend | |
302 | + * the system. | |
303 | + */ | |
304 | + if (suspends_pending == 0) | |
305 | + apm_suspend(); | |
306 | + | |
307 | + /* | |
308 | + * Wait for the suspend/resume to complete. If there are | |
309 | + * pending acknowledges, we wait here for them. | |
310 | + * | |
311 | + * Note that we need to ensure that the PM subsystem does | |
312 | + * not kick us out of the wait when it suspends the threads. | |
313 | + */ | |
314 | + flags = current->flags; | |
315 | + current->flags |= PF_NOFREEZE; | |
316 | + | |
317 | + /* | |
318 | + * Note: do not allow a thread which is acking the suspend | |
319 | + * to escape until the resume is complete. | |
320 | + */ | |
321 | + if (as->suspend_state == SUSPEND_ACKED) | |
322 | + wait_event(apm_suspend_waitqueue, | |
323 | + as->suspend_state == SUSPEND_DONE); | |
324 | + else | |
325 | + wait_event_interruptible(apm_suspend_waitqueue, | |
326 | + as->suspend_state == SUSPEND_DONE); | |
327 | + | |
328 | + current->flags = flags; | |
329 | + err = as->suspend_result; | |
330 | + as->suspend_state = SUSPEND_NONE; | |
331 | + break; | |
332 | + } | |
333 | + | |
334 | + return err; | |
335 | +} | |
336 | + | |
337 | +static int apm_release(struct inode * inode, struct file * filp) | |
338 | +{ | |
339 | + struct apm_user *as = filp->private_data; | |
340 | + filp->private_data = NULL; | |
341 | + | |
342 | + down_write(&user_list_lock); | |
343 | + list_del(&as->list); | |
344 | + up_write(&user_list_lock); | |
345 | + | |
346 | + /* | |
347 | + * We are now unhooked from the chain. As far as new | |
348 | + * events are concerned, we no longer exist. However, we | |
349 | + * need to balance suspends_pending, which means the | |
350 | + * possibility of sleeping. | |
351 | + */ | |
352 | + if (as->suspend_state != SUSPEND_NONE) { | |
353 | + suspends_pending -= 1; | |
354 | + if (suspends_pending == 0) | |
355 | + apm_suspend(); | |
356 | + } | |
357 | + | |
358 | + kfree(as); | |
359 | + return 0; | |
360 | +} | |
361 | + | |
362 | +static int apm_open(struct inode * inode, struct file * filp) | |
363 | +{ | |
364 | + struct apm_user *as; | |
365 | + | |
366 | + as = kzalloc(sizeof(*as), GFP_KERNEL); | |
367 | + if (as) { | |
368 | + /* | |
369 | + * XXX - this is a tiny bit broken, when we consider BSD | |
370 | + * process accounting. If the device is opened by root, we | |
371 | + * instantly flag that we used superuser privs. Who knows, | |
372 | + * we might close the device immediately without doing a | |
373 | + * privileged operation -- cevans | |
374 | + */ | |
375 | + as->suser = capable(CAP_SYS_ADMIN); | |
376 | + as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE; | |
377 | + as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ; | |
378 | + | |
379 | + down_write(&user_list_lock); | |
380 | + list_add(&as->list, &apm_user_list); | |
381 | + up_write(&user_list_lock); | |
382 | + | |
383 | + filp->private_data = as; | |
384 | + } | |
385 | + | |
386 | + return as ? 0 : -ENOMEM; | |
387 | +} | |
388 | + | |
389 | +static struct file_operations apm_bios_fops = { | |
390 | + .owner = THIS_MODULE, | |
391 | + .read = apm_read, | |
392 | + .poll = apm_poll, | |
393 | + .ioctl = apm_ioctl, | |
394 | + .open = apm_open, | |
395 | + .release = apm_release, | |
396 | +}; | |
397 | + | |
398 | +static struct miscdevice apm_device = { | |
399 | + .minor = APM_MINOR_DEV, | |
400 | + .name = "apm_bios", | |
401 | + .fops = &apm_bios_fops | |
402 | +}; | |
403 | + | |
404 | + | |
405 | +#ifdef CONFIG_PROC_FS | |
406 | +/* | |
407 | + * Arguments, with symbols from linux/apm_bios.h. | |
408 | + * | |
409 | + * 0) Linux driver version (this will change if format changes) | |
410 | + * 1) APM BIOS Version. Usually 1.0, 1.1 or 1.2. | |
411 | + * 2) APM flags from APM Installation Check (0x00): | |
412 | + * bit 0: APM_16_BIT_SUPPORT | |
413 | + * bit 1: APM_32_BIT_SUPPORT | |
414 | + * bit 2: APM_IDLE_SLOWS_CLOCK | |
415 | + * bit 3: APM_BIOS_DISABLED | |
416 | + * bit 4: APM_BIOS_DISENGAGED | |
417 | + * 3) AC line status | |
418 | + * 0x00: Off-line | |
419 | + * 0x01: On-line | |
420 | + * 0x02: On backup power (BIOS >= 1.1 only) | |
421 | + * 0xff: Unknown | |
422 | + * 4) Battery status | |
423 | + * 0x00: High | |
424 | + * 0x01: Low | |
425 | + * 0x02: Critical | |
426 | + * 0x03: Charging | |
427 | + * 0x04: Selected battery not present (BIOS >= 1.2 only) | |
428 | + * 0xff: Unknown | |
429 | + * 5) Battery flag | |
430 | + * bit 0: High | |
431 | + * bit 1: Low | |
432 | + * bit 2: Critical | |
433 | + * bit 3: Charging | |
434 | + * bit 7: No system battery | |
435 | + * 0xff: Unknown | |
436 | + * 6) Remaining battery life (percentage of charge): | |
437 | + * 0-100: valid | |
438 | + * -1: Unknown | |
439 | + * 7) Remaining battery life (time units): | |
440 | + * Number of remaining minutes or seconds | |
441 | + * -1: Unknown | |
442 | + * 8) min = minutes; sec = seconds | |
443 | + */ | |
444 | +static int apm_read_proc(char *buf, char **start, off_t fpos, int length) | |
445 | +{ | |
446 | + if (likely(apm_get_info)) | |
447 | + return apm_get_info(buf, start, fpos, length); | |
448 | + | |
449 | + return -EINVAL; | |
450 | +} | |
451 | +#endif | |
452 | + | |
453 | +static int kapmd(void *arg) | |
454 | +{ | |
455 | + daemonize("kapmd"); | |
456 | + current->flags |= PF_NOFREEZE; | |
457 | + | |
458 | + do { | |
459 | + apm_event_t event; | |
460 | + | |
461 | + wait_event_interruptible(kapmd_wait, | |
462 | + !queue_empty(&kapmd_queue) || !pm_active); | |
463 | + | |
464 | + if (!pm_active) | |
465 | + break; | |
466 | + | |
467 | + spin_lock_irq(&kapmd_queue_lock); | |
468 | + event = 0; | |
469 | + if (!queue_empty(&kapmd_queue)) | |
470 | + event = queue_get_event(&kapmd_queue); | |
471 | + spin_unlock_irq(&kapmd_queue_lock); | |
472 | + | |
473 | + switch (event) { | |
474 | + case 0: | |
475 | + break; | |
476 | + | |
477 | + case APM_LOW_BATTERY: | |
478 | + case APM_POWER_STATUS_CHANGE: | |
479 | + queue_event(event, NULL); | |
480 | + break; | |
481 | + | |
482 | + case APM_USER_SUSPEND: | |
483 | + case APM_SYS_SUSPEND: | |
484 | + queue_event(event, NULL); | |
485 | + if (suspends_pending == 0) | |
486 | + apm_suspend(); | |
487 | + break; | |
488 | + | |
489 | + case APM_CRITICAL_SUSPEND: | |
490 | + apm_suspend(); | |
491 | + break; | |
492 | + } | |
493 | + } while (1); | |
494 | + | |
495 | + complete_and_exit(&kapmd_exit, 0); | |
496 | +} | |
497 | + | |
498 | +static int __init apm_init(void) | |
499 | +{ | |
500 | + int ret; | |
501 | + | |
502 | + pm_active = 1; | |
503 | + | |
504 | + ret = kernel_thread(kapmd, NULL, CLONE_KERNEL); | |
505 | + if (unlikely(ret < 0)) { | |
506 | + pm_active = 0; | |
507 | + return ret; | |
508 | + } | |
509 | + | |
510 | + create_proc_info_entry("apm", 0, NULL, apm_read_proc); | |
511 | + | |
512 | + ret = misc_register(&apm_device); | |
513 | + if (unlikely(ret != 0)) { | |
514 | + remove_proc_entry("apm", NULL); | |
515 | + | |
516 | + pm_active = 0; | |
517 | + wake_up(&kapmd_wait); | |
518 | + wait_for_completion(&kapmd_exit); | |
519 | + } | |
520 | + | |
521 | + return ret; | |
522 | +} | |
523 | + | |
524 | +static void __exit apm_exit(void) | |
525 | +{ | |
526 | + misc_deregister(&apm_device); | |
527 | + remove_proc_entry("apm", NULL); | |
528 | + | |
529 | + pm_active = 0; | |
530 | + wake_up(&kapmd_wait); | |
531 | + wait_for_completion(&kapmd_exit); | |
532 | +} | |
533 | + | |
534 | +module_init(apm_init); | |
535 | +module_exit(apm_exit); | |
536 | + | |
537 | +MODULE_AUTHOR("Stephen Rothwell, Andriy Skulysh"); | |
538 | +MODULE_DESCRIPTION("Advanced Power Management"); | |
539 | +MODULE_LICENSE("GPL"); |
arch/sh/kernel/entry.S
... | ... | @@ -308,7 +308,7 @@ |
308 | 308 | .align 2 |
309 | 309 | ret_from_exception: |
310 | 310 | preempt_stop() |
311 | -ret_from_irq: | |
311 | +ENTRY(ret_from_irq) | |
312 | 312 | ! |
313 | 313 | mov #OFF_SR, r0 |
314 | 314 | mov.l @(r0,r15), r0 ! get status register |
... | ... | @@ -704,7 +704,7 @@ |
704 | 704 | ! |
705 | 705 | ! |
706 | 706 | .align 2 |
707 | -handle_exception: | |
707 | +ENTRY(handle_exception) | |
708 | 708 | ! Using k0, k1 for scratch registers (r0_bank1, r1_bank), |
709 | 709 | ! save all registers onto stack. |
710 | 710 | ! |
arch/sh/kernel/pm.c
1 | +/* | |
2 | + * Generic Power Management Routine | |
3 | + * | |
4 | + * Copyright (c) 2006 Andriy Skulysh <askulsyh@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/suspend.h> | |
10 | +#include <linux/delay.h> | |
11 | +#include <linux/gfp.h> | |
12 | +#include <asm/freq.h> | |
13 | +#include <asm/io.h> | |
14 | +#include <asm/watchdog.h> | |
15 | +#include <asm/pm.h> | |
16 | + | |
17 | +#define INTR_OFFSET 0x600 | |
18 | + | |
19 | +#define STBCR 0xffffff82 | |
20 | +#define STBCR2 0xffffff88 | |
21 | + | |
22 | +#define STBCR_STBY 0x80 | |
23 | +#define STBCR_MSTP2 0x04 | |
24 | + | |
25 | +#define MCR 0xffffff68 | |
26 | +#define RTCNT 0xffffff70 | |
27 | + | |
28 | +#define MCR_RMODE 2 | |
29 | +#define MCR_RFSH 4 | |
30 | + | |
31 | +void pm_enter(void) | |
32 | +{ | |
33 | + u8 stbcr, csr; | |
34 | + u16 frqcr, mcr; | |
35 | + u32 vbr_new, vbr_old; | |
36 | + | |
37 | + set_bl_bit(); | |
38 | + | |
39 | + /* set wdt */ | |
40 | + csr = sh_wdt_read_csr(); | |
41 | + csr &= ~WTCSR_TME; | |
42 | + csr |= WTCSR_CKS_4096; | |
43 | + sh_wdt_write_csr(csr); | |
44 | + csr = sh_wdt_read_csr(); | |
45 | + sh_wdt_write_cnt(0); | |
46 | + | |
47 | + /* disable PLL1 */ | |
48 | + frqcr = ctrl_inw(FRQCR); | |
49 | + frqcr &= ~(FRQCR_PLLEN | FRQCR_PSTBY); | |
50 | + ctrl_outw(frqcr, FRQCR); | |
51 | + | |
52 | + /* enable standby */ | |
53 | + stbcr = ctrl_inb(STBCR); | |
54 | + ctrl_outb(stbcr | STBCR_STBY | STBCR_MSTP2, STBCR); | |
55 | + | |
56 | + /* set self-refresh */ | |
57 | + mcr = ctrl_inw(MCR); | |
58 | + ctrl_outw(mcr & ~MCR_RFSH, MCR); | |
59 | + | |
60 | + /* set interrupt handler */ | |
61 | + asm volatile("stc vbr, %0" : "=r" (vbr_old)); | |
62 | + vbr_new = get_zeroed_page(GFP_ATOMIC); | |
63 | + udelay(50); | |
64 | + memcpy((void*)(vbr_new + INTR_OFFSET), | |
65 | + &wakeup_start, &wakeup_end - &wakeup_start); | |
66 | + asm volatile("ldc %0, vbr" : : "r" (vbr_new)); | |
67 | + | |
68 | + ctrl_outw(0, RTCNT); | |
69 | + ctrl_outw(mcr | MCR_RFSH | MCR_RMODE, MCR); | |
70 | + | |
71 | + cpu_sleep(); | |
72 | + | |
73 | + asm volatile("ldc %0, vbr" : : "r" (vbr_old)); | |
74 | + | |
75 | + free_page(vbr_new); | |
76 | + | |
77 | + /* enable PLL1 */ | |
78 | + frqcr = ctrl_inw(FRQCR); | |
79 | + frqcr |= FRQCR_PSTBY; | |
80 | + ctrl_outw(frqcr, FRQCR); | |
81 | + udelay(50); | |
82 | + frqcr |= FRQCR_PLLEN; | |
83 | + ctrl_outw(frqcr, FRQCR); | |
84 | + | |
85 | + ctrl_outb(stbcr, STBCR); | |
86 | + | |
87 | + clear_bl_bit(); | |
88 | +} |
arch/sh/kernel/sh_ksyms.c
arch/sh/kernel/time.c
... | ... | @@ -143,8 +143,33 @@ |
143 | 143 | } |
144 | 144 | } |
145 | 145 | |
146 | +#ifdef CONFIG_PM | |
147 | +int timer_suspend(struct sys_device *dev, pm_message_t state) | |
148 | +{ | |
149 | + struct sys_timer *sys_timer = container_of(dev, struct sys_timer, dev); | |
150 | + | |
151 | + sys_timer->ops->stop(); | |
152 | + | |
153 | + return 0; | |
154 | +} | |
155 | + | |
156 | +int timer_resume(struct sys_device *dev) | |
157 | +{ | |
158 | + struct sys_timer *sys_timer = container_of(dev, struct sys_timer, dev); | |
159 | + | |
160 | + sys_timer->ops->start(); | |
161 | + | |
162 | + return 0; | |
163 | +} | |
164 | +#else | |
165 | +#define timer_suspend NULL | |
166 | +#define timer_resume NULL | |
167 | +#endif | |
168 | + | |
146 | 169 | static struct sysdev_class timer_sysclass = { |
147 | 170 | set_kset_name("timer"), |
171 | + .suspend = timer_suspend, | |
172 | + .resume = timer_resume, | |
148 | 173 | }; |
149 | 174 | |
150 | 175 | static int __init timer_init_sysfs(void) |
arch/sh/kernel/timers/timer-tmu.c
... | ... | @@ -188,6 +188,18 @@ |
188 | 188 | .ops = &tmu_clk_ops, |
189 | 189 | }; |
190 | 190 | |
191 | +static int tmu_timer_start(void) | |
192 | +{ | |
193 | + ctrl_outb(TMU_TSTR_INIT, TMU_TSTR); | |
194 | + return 0; | |
195 | +} | |
196 | + | |
197 | +static int tmu_timer_stop(void) | |
198 | +{ | |
199 | + ctrl_outb(0, TMU_TSTR); | |
200 | + return 0; | |
201 | +} | |
202 | + | |
191 | 203 | static int tmu_timer_init(void) |
192 | 204 | { |
193 | 205 | unsigned long interval; |
... | ... | @@ -197,7 +209,7 @@ |
197 | 209 | tmu0_clk.parent = clk_get("module_clk"); |
198 | 210 | |
199 | 211 | /* Start TMU0 */ |
200 | - ctrl_outb(0, TMU_TSTR); | |
212 | + tmu_timer_stop(); | |
201 | 213 | #if !defined(CONFIG_CPU_SUBTYPE_SH7300) && !defined(CONFIG_CPU_SUBTYPE_SH7760) |
202 | 214 | ctrl_outb(TMU_TOCR_INIT, TMU_TOCR); |
203 | 215 | #endif |
204 | 216 | |
... | ... | @@ -211,13 +223,15 @@ |
211 | 223 | ctrl_outl(interval, TMU0_TCOR); |
212 | 224 | ctrl_outl(interval, TMU0_TCNT); |
213 | 225 | |
214 | - ctrl_outb(TMU_TSTR_INIT, TMU_TSTR); | |
226 | + tmu_timer_start(); | |
215 | 227 | |
216 | 228 | return 0; |
217 | 229 | } |
218 | 230 | |
219 | 231 | struct sys_timer_ops tmu_timer_ops = { |
220 | 232 | .init = tmu_timer_init, |
233 | + .start = tmu_timer_start, | |
234 | + .stop = tmu_timer_stop, | |
221 | 235 | .get_frequency = tmu_timer_get_frequency, |
222 | 236 | .get_offset = tmu_timer_get_offset, |
223 | 237 | }; |
drivers/input/touchscreen/hp680_ts_input.c
... | ... | @@ -15,7 +15,6 @@ |
15 | 15 | #define HP680_TS_ABS_Y_MIN 80 |
16 | 16 | #define HP680_TS_ABS_Y_MAX 910 |
17 | 17 | |
18 | -#define SCPCR 0xa4000116 | |
19 | 18 | #define PHDR 0xa400012e |
20 | 19 | #define SCPDR 0xa4000136 |
21 | 20 | |
... | ... | @@ -77,19 +76,6 @@ |
77 | 76 | |
78 | 77 | static int __init hp680_ts_init(void) |
79 | 78 | { |
80 | - u8 scpdr; | |
81 | - u16 scpcr; | |
82 | - | |
83 | - scpdr = ctrl_inb(SCPDR); | |
84 | - scpdr |= SCPDR_TS_SCAN_X | SCPDR_TS_SCAN_Y; | |
85 | - scpdr &= ~SCPDR_TS_SCAN_ENABLE; | |
86 | - ctrl_outb(scpdr, SCPDR); | |
87 | - | |
88 | - scpcr = ctrl_inw(SCPCR); | |
89 | - scpcr &= ~SCPCR_TS_MASK; | |
90 | - scpcr |= SCPCR_TS_ENABLE; | |
91 | - ctrl_outw(scpcr, SCPCR); | |
92 | - | |
93 | 79 | hp680_ts_dev = input_allocate_device(); |
94 | 80 | if (!hp680_ts_dev) |
95 | 81 | return -ENOMEM; |
include/asm-sh/apm.h
1 | +/* | |
2 | + * Copyright 2006 (c) Andriy Skulysh <askulysh@gmail.com> | |
3 | + * | |
4 | + * This file is subject to the terms and conditions of the GNU General Public | |
5 | + * License. See the file "COPYING" in the main directory of this archive | |
6 | + * for more details. | |
7 | + * | |
8 | + */ | |
9 | + | |
10 | +#ifndef __ASM_SH_APM_H | |
11 | +#define __ASM_SH_APM_H | |
12 | + | |
13 | +#define APM_AC_OFFLINE 0 | |
14 | +#define APM_AC_ONLINE 1 | |
15 | +#define APM_AC_BACKUP 2 | |
16 | +#define APM_AC_UNKNOWN 0xff | |
17 | + | |
18 | +#define APM_BATTERY_STATUS_HIGH 0 | |
19 | +#define APM_BATTERY_STATUS_LOW 1 | |
20 | +#define APM_BATTERY_STATUS_CRITICAL 2 | |
21 | +#define APM_BATTERY_STATUS_CHARGING 3 | |
22 | +#define APM_BATTERY_STATUS_NOT_PRESENT 4 | |
23 | +#define APM_BATTERY_STATUS_UNKNOWN 0xff | |
24 | + | |
25 | +#define APM_BATTERY_LIFE_UNKNOWN 0xFFFF | |
26 | +#define APM_BATTERY_LIFE_MINUTES 0x8000 | |
27 | +#define APM_BATTERY_LIFE_VALUE_MASK 0x7FFF | |
28 | + | |
29 | +#define APM_BATTERY_FLAG_HIGH (1 << 0) | |
30 | +#define APM_BATTERY_FLAG_LOW (1 << 1) | |
31 | +#define APM_BATTERY_FLAG_CRITICAL (1 << 2) | |
32 | +#define APM_BATTERY_FLAG_CHARGING (1 << 3) | |
33 | +#define APM_BATTERY_FLAG_NOT_PRESENT (1 << 7) | |
34 | +#define APM_BATTERY_FLAG_UNKNOWN 0xff | |
35 | + | |
36 | +#define APM_UNITS_MINS 0 | |
37 | +#define APM_UNITS_SECS 1 | |
38 | +#define APM_UNITS_UNKNOWN -1 | |
39 | + | |
40 | + | |
41 | +extern int (*apm_get_info)(char *buf, char **start, off_t fpos, int length); | |
42 | +extern int apm_suspended; | |
43 | + | |
44 | +void apm_queue_event(apm_event_t event); | |
45 | + | |
46 | +#endif |
include/asm-sh/cpu-sh3/freq.h
include/asm-sh/hd64461.h
... | ... | @@ -40,7 +40,12 @@ |
40 | 40 | #define HD64461_LCDCBAR 0x11000 |
41 | 41 | #define HD64461_LCDCLOR 0x11002 |
42 | 42 | #define HD64461_LCDCCR 0x11004 |
43 | -#define HD64461_LCDCCR_MOFF 0x80 | |
43 | +#define HD64461_LCDCCR_STBACK 0x0400 | |
44 | +#define HD64461_LCDCCR_STREQ 0x0100 | |
45 | +#define HD64461_LCDCCR_MOFF 0x0080 | |
46 | +#define HD64461_LCDCCR_REFSEL 0x0040 | |
47 | +#define HD64461_LCDCCR_EPON 0x0020 | |
48 | +#define HD64461_LCDCCR_SPON 0x0010 | |
44 | 49 | |
45 | 50 | #define HD64461_LDR1 0x11010 |
46 | 51 | #define HD64461_LDR1_DON 0x01 |
include/asm-sh/hp6xx/hp6xx.h
... | ... | @@ -2,16 +2,33 @@ |
2 | 2 | #define __ASM_SH_HP6XX_H |
3 | 3 | |
4 | 4 | /* |
5 | - * Copyright (C) 2003 Andriy Skulysh | |
5 | + * Copyright (C) 2003, 2004, 2005 Andriy Skulysh | |
6 | + * | |
7 | + * This file is subject to the terms and conditions of the GNU General Public | |
8 | + * License. See the file "COPYING" in the main directory of this archive | |
9 | + * for more details. | |
10 | + * | |
6 | 11 | */ |
7 | 12 | |
8 | -#define HP680_TS_IRQ IRQ3_IRQ | |
13 | +#define HP680_BTN_IRQ IRQ0_IRQ | |
14 | +#define HP680_TS_IRQ IRQ3_IRQ | |
15 | +#define HP680_HD64461_IRQ IRQ4_IRQ | |
9 | 16 | |
10 | 17 | #define DAC_LCD_BRIGHTNESS 0 |
11 | 18 | #define DAC_SPEAKER_VOLUME 1 |
12 | 19 | |
20 | +#define PGDR_OPENED 0x01 | |
21 | +#define PGDR_MAIN_BATTERY_OUT 0x04 | |
22 | +#define PGDR_PLAY_BUTTON 0x08 | |
23 | +#define PGDR_REWIND_BUTTON 0x10 | |
24 | +#define PGDR_RECORD_BUTTON 0x20 | |
25 | + | |
13 | 26 | #define PHDR_TS_PEN_DOWN 0x08 |
14 | 27 | |
28 | +#define PJDR_LED_BLINK 0x02 | |
29 | + | |
30 | +#define PKDR_LED_GREEN 0x10 | |
31 | + | |
15 | 32 | #define SCPDR_TS_SCAN_ENABLE 0x20 |
16 | 33 | #define SCPDR_TS_SCAN_Y 0x02 |
17 | 34 | #define SCPDR_TS_SCAN_X 0x01 |
18 | 35 | |
19 | 36 | |
20 | 37 | |
... | ... | @@ -21,11 +38,43 @@ |
21 | 38 | |
22 | 39 | #define ADC_CHANNEL_TS_Y 1 |
23 | 40 | #define ADC_CHANNEL_TS_X 2 |
41 | +#define ADC_CHANNEL_BATTERY 3 | |
42 | +#define ADC_CHANNEL_BACKUP 4 | |
43 | +#define ADC_CHANNEL_CHARGE 5 | |
24 | 44 | |
25 | 45 | #define HD64461_GPADR_SPEAKER 0x01 |
26 | 46 | #define HD64461_GPADR_PCMCIA0 (0x02|0x08) |
47 | + | |
27 | 48 | #define HD64461_GPBDR_LCDOFF 0x01 |
49 | +#define HD64461_GPBDR_LCD_CONTRAST_MASK 0x78 | |
28 | 50 | #define HD64461_GPBDR_LED_RED 0x80 |
51 | + | |
52 | +#include <asm/hd64461.h> | |
53 | +#include <asm/io.h> | |
54 | + | |
55 | +#define PJDR 0xa4000130 | |
56 | +#define PKDR 0xa4000132 | |
57 | + | |
58 | +static inline void hp6xx_led_red(int on) | |
59 | +{ | |
60 | + u16 v16; | |
61 | + v16 = ctrl_inw(CONFIG_HD64461_IOBASE + HD64461_GPBDR - 0x10000); | |
62 | + if (on) | |
63 | + ctrl_outw(v16 & (~HD64461_GPBDR_LED_RED), CONFIG_HD64461_IOBASE + HD64461_GPBDR - 0x10000); | |
64 | + else | |
65 | + ctrl_outw(v16 | HD64461_GPBDR_LED_RED, CONFIG_HD64461_IOBASE + HD64461_GPBDR - 0x10000); | |
66 | +} | |
67 | + | |
68 | +static inline void hp6xx_led_green(int on) | |
69 | +{ | |
70 | + u8 v8; | |
71 | + | |
72 | + v8 = ctrl_inb(PKDR); | |
73 | + if (on) | |
74 | + ctrl_outb(v8 & (~PKDR_LED_GREEN), PKDR); | |
75 | + else | |
76 | + ctrl_outb(v8 | PKDR_LED_GREEN, PKDR); | |
77 | +} | |
29 | 78 | |
30 | 79 | |
31 | 80 | #endif /* __ASM_SH_HP6XX_H */ |
include/asm-sh/pm.h
1 | +/* | |
2 | + * This file is subject to the terms and conditions of the GNU General Public | |
3 | + * License. See the file "COPYING" in the main directory of this archive | |
4 | + * for more details. | |
5 | + * | |
6 | + * Copyright 2006 (c) Andriy Skulysh <askulysh@gmail.com> | |
7 | + * | |
8 | + */ | |
9 | +#ifndef __ASM_SH_PM_H | |
10 | +#define __ASM_SH_PM_H | |
11 | + | |
12 | +extern u8 wakeup_start; | |
13 | +extern u8 wakeup_end; | |
14 | + | |
15 | +void pm_enter(void); | |
16 | + | |
17 | +#endif |
include/asm-sh/system.h
... | ... | @@ -172,6 +172,31 @@ |
172 | 172 | : "memory"); |
173 | 173 | } |
174 | 174 | |
175 | +static __inline__ void set_bl_bit(void) | |
176 | +{ | |
177 | + unsigned long __dummy0, __dummy1; | |
178 | + | |
179 | + __asm__ __volatile__ ("stc sr, %0\n\t" | |
180 | + "or %2, %0\n\t" | |
181 | + "and %3, %0\n\t" | |
182 | + "ldc %0, sr" | |
183 | + : "=&r" (__dummy0), "=r" (__dummy1) | |
184 | + : "r" (0x10000000), "r" (0xffffff0f) | |
185 | + : "memory"); | |
186 | +} | |
187 | + | |
188 | +static __inline__ void clear_bl_bit(void) | |
189 | +{ | |
190 | + unsigned long __dummy0, __dummy1; | |
191 | + | |
192 | + __asm__ __volatile__ ("stc sr, %0\n\t" | |
193 | + "and %2, %0\n\t" | |
194 | + "ldc %0, sr" | |
195 | + : "=&r" (__dummy0), "=r" (__dummy1) | |
196 | + : "1" (~0x10000000) | |
197 | + : "memory"); | |
198 | +} | |
199 | + | |
175 | 200 | #define local_save_flags(x) \ |
176 | 201 | __asm__("stc sr, %0; and #0xf0, %0" : "=&z" (x) :/**/: "memory" ) |
177 | 202 |