Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
drivers
parisc
power.c
Go to the documentation of this file.
1
/*
2
* linux/drivers/parisc/power.c
3
* HP PARISC soft power switch support driver
4
*
5
* Copyright (c) 2001-2007 Helge Deller <
[email protected]
>
6
* All rights reserved.
7
*
8
*
9
* Redistribution and use in source and binary forms, with or without
10
* modification, are permitted provided that the following conditions
11
* are met:
12
* 1. Redistributions of source code must retain the above copyright
13
* notice, this list of conditions, and the following disclaimer,
14
* without modification.
15
* 2. The name of the author may not be used to endorse or promote products
16
* derived from this software without specific prior written permission.
17
*
18
* Alternatively, this software may be distributed under the terms of the
19
* GNU General Public License ("GPL").
20
*
21
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
25
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30
*
31
*
32
* HINT:
33
* Support of the soft power switch button may be enabled or disabled at
34
* runtime through the "/proc/sys/kernel/power" procfs entry.
35
*/
36
37
#include <linux/module.h>
38
#include <
linux/init.h
>
39
#include <linux/kernel.h>
40
#include <
linux/notifier.h
>
41
#include <linux/reboot.h>
42
#include <linux/sched.h>
43
#include <
linux/kthread.h
>
44
#include <
linux/pm.h
>
45
46
#include <asm/pdc.h>
47
#include <asm/io.h>
48
#include <
asm/led.h
>
49
50
#define DRIVER_NAME "powersw"
51
#define KTHREAD_NAME "kpowerswd"
52
53
/* how often should the power button be polled ? */
54
#define POWERSWITCH_POLL_PER_SEC 2
55
56
/* how long does the power button needs to be down until we react ? */
57
#define POWERSWITCH_DOWN_SEC 2
58
59
/* assembly code to access special registers */
60
/* taken from PCXL ERS page 82 */
61
#define DIAG_CODE(code) (0x14000000 + ((code)<<5))
62
63
#define MFCPU_X(rDiagReg, t_ch, t_th, code) \
64
(DIAG_CODE(code) + ((rDiagReg)<<21) + ((t_ch)<<16) + ((t_th)<<0) )
65
66
#define MTCPU(dr, gr) MFCPU_X(dr, gr, 0, 0x12)
/* move value of gr to dr[dr] */
67
#define MFCPU_C(dr, gr) MFCPU_X(dr, gr, 0, 0x30)
/* for dr0 and dr8 only ! */
68
#define MFCPU_T(dr, gr) MFCPU_X(dr, 0, gr, 0xa0)
/* all dr except dr0 and dr8 */
69
70
#define __getDIAG(dr) ( { \
71
register unsigned long __res asm("r28");\
72
__asm__ __volatile__ ( \
73
".word %1" : "=&r" (__res) : "i" (MFCPU_T(dr,28) ) \
74
); \
75
__res; \
76
} )
77
78
/* local shutdown counter */
79
static
int
shutdown_timer
__read_mostly
;
80
81
/* check, give feedback and start shutdown after one second */
82
static
void
process_shutdown(
void
)
83
{
84
if
(shutdown_timer == 0)
85
printk
(
KERN_ALERT
KTHREAD_NAME
": Shutdown requested...\n"
);
86
87
shutdown_timer++;
88
89
/* wait until the button was pressed for 1 second */
90
if
(shutdown_timer == (
POWERSWITCH_DOWN_SEC
*
POWERSWITCH_POLL_PER_SEC
)) {
91
static
const
char
msg
[] =
"Shutting down..."
;
92
printk
(
KERN_INFO
KTHREAD_NAME
": %s\n"
, msg);
93
lcd_print
(msg);
94
95
/* send kill signal */
96
if
(kill_cad_pid(
SIGINT
, 1)) {
97
/* just in case killing init process failed */
98
if
(
pm_power_off
)
99
pm_power_off
();
100
}
101
}
102
}
103
104
105
/* main power switch task struct */
106
static
struct
task_struct
*power_task;
107
108
/* filename in /proc which can be used to enable/disable the power switch */
109
#define SYSCTL_FILENAME "sys/kernel/power"
110
111
/* soft power switch enabled/disabled */
112
int
pwrsw_enabled
__read_mostly
= 1;
113
114
/* main kernel thread worker. It polls the button state */
115
static
int
kpowerswd(
void
*
param
)
116
{
117
__set_current_state
(
TASK_RUNNING
);
118
119
do
{
120
int
button_not_pressed;
121
unsigned
long
soft_power_reg = (
unsigned
long
) param;
122
123
schedule_timeout_interruptible
(pwrsw_enabled ?
HZ
:
HZ
/
POWERSWITCH_POLL_PER_SEC
);
124
__set_current_state
(
TASK_RUNNING
);
125
126
if
(
unlikely
(!pwrsw_enabled))
127
continue
;
128
129
if
(soft_power_reg) {
130
/*
131
* Non-Gecko-style machines:
132
* Check the power switch status which is read from the
133
* real I/O location at soft_power_reg.
134
* Bit 31 ("the lowest bit) is the status of the power switch.
135
* This bit is "1" if the button is NOT pressed.
136
*/
137
button_not_pressed = (gsc_readl(soft_power_reg) & 0x1);
138
}
else
{
139
/*
140
* On gecko style machines (e.g. 712/xx and 715/xx)
141
* the power switch status is stored in Bit 0 ("the highest bit")
142
* of CPU diagnose register 25.
143
* Warning: Some machines never reset the DIAG flag, even if
144
* the button has been released again.
145
*/
146
button_not_pressed = (
__getDIAG
(25) & 0x80000000);
147
}
148
149
if
(
likely
(button_not_pressed)) {
150
if
(
unlikely
(shutdown_timer &&
/* avoid writing if not necessary */
151
shutdown_timer < (
POWERSWITCH_DOWN_SEC
*
POWERSWITCH_POLL_PER_SEC
))) {
152
shutdown_timer = 0;
153
printk
(
KERN_INFO
KTHREAD_NAME
": Shutdown request aborted.\n"
);
154
}
155
}
else
156
process_shutdown();
157
158
159
}
while
(!
kthread_should_stop
());
160
161
return
0;
162
}
163
164
165
/*
166
* powerfail interruption handler (irq IRQ_FROM_REGION(CPU_IRQ_REGION)+2)
167
*/
168
#if 0
169
static
void
powerfail_interrupt(
int
code
,
void
*
x
)
170
{
171
printk
(
KERN_CRIT
"POWERFAIL INTERRUPTION !\n"
);
172
poweroff();
173
}
174
#endif
175
176
177
178
179
/* parisc_panic_event() is called by the panic handler.
180
* As soon as a panic occurs, our tasklets above will not be
181
* executed any longer. This function then re-enables the
182
* soft-power switch and allows the user to switch off the system
183
*/
184
static
int
parisc_panic_event(
struct
notifier_block
*
this
,
185
unsigned
long
event
,
void
*
ptr
)
186
{
187
/* re-enable the soft-power switch */
188
pdc_soft_power_button
(0);
189
return
NOTIFY_DONE;
190
}
191
192
static
struct
notifier_block
parisc_panic_block = {
193
.notifier_call = parisc_panic_event,
194
.priority =
INT_MAX
,
195
};
196
197
198
static
int
__init
power_init(
void
)
199
{
200
unsigned
long
ret
;
201
unsigned
long
soft_power_reg;
202
203
#if 0
204
request_irq
( IRQ_FROM_REGION(CPU_IRQ_REGION)+2, &powerfail_interrupt,
205
0,
"powerfail"
,
NULL
);
206
#endif
207
208
/* enable the soft power switch if possible */
209
ret =
pdc_soft_power_info
(&soft_power_reg);
210
if
(ret ==
PDC_OK
)
211
ret =
pdc_soft_power_button
(1);
212
if
(ret !=
PDC_OK
)
213
soft_power_reg = -1
UL
;
214
215
switch
(soft_power_reg) {
216
case
0:
printk
(
KERN_INFO
DRIVER_NAME
": Gecko-style soft power switch enabled.\n"
);
217
break
;
218
219
case
-1
UL
:
printk
(
KERN_INFO
DRIVER_NAME
": Soft power switch support not available.\n"
);
220
return
-
ENODEV
;
221
222
default
:
printk
(
KERN_INFO
DRIVER_NAME
": Soft power switch at 0x%08lx enabled.\n"
,
223
soft_power_reg);
224
}
225
226
power_task =
kthread_run
(kpowerswd, (
void
*)soft_power_reg,
KTHREAD_NAME
);
227
if
(IS_ERR(power_task)) {
228
printk
(
KERN_ERR
DRIVER_NAME
": thread creation failed. Driver not loaded.\n"
);
229
pdc_soft_power_button
(0);
230
return
-
EIO
;
231
}
232
233
/* Register a call for panic conditions. */
234
atomic_notifier_chain_register
(&panic_notifier_list,
235
&parisc_panic_block);
236
237
return
0;
238
}
239
240
static
void
__exit
power_exit(
void
)
241
{
242
kthread_stop
(power_task);
243
244
atomic_notifier_chain_unregister
(&panic_notifier_list,
245
&parisc_panic_block);
246
247
pdc_soft_power_button
(0);
248
}
249
250
arch_initcall
(power_init);
251
module_exit
(power_exit);
252
253
254
MODULE_AUTHOR
(
"Helge Deller <
[email protected]
>"
);
255
MODULE_DESCRIPTION
(
"Soft power switch driver"
);
256
MODULE_LICENSE
(
"Dual BSD/GPL"
);
Generated on Thu Jan 10 2013 13:08:50 for Linux Kernel by
1.8.2