diff options
Diffstat (limited to 'arch/sparc/kernel/pmc.c')
-rw-r--r-- | arch/sparc/kernel/pmc.c | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/arch/sparc/kernel/pmc.c b/arch/sparc/kernel/pmc.c new file mode 100644 index 000000000000..7eca8871ff47 --- /dev/null +++ b/arch/sparc/kernel/pmc.c | |||
@@ -0,0 +1,99 @@ | |||
1 | /* pmc - Driver implementation for power management functions | ||
2 | * of Power Management Controller (PMC) on SPARCstation-Voyager. | ||
3 | * | ||
4 | * Copyright (c) 2002 Eric Brower (ebrower@usa.net) | ||
5 | */ | ||
6 | |||
7 | #include <linux/kernel.h> | ||
8 | #include <linux/fs.h> | ||
9 | #include <linux/errno.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/miscdevice.h> | ||
12 | #include <linux/pm.h> | ||
13 | |||
14 | #include <asm/io.h> | ||
15 | #include <asm/sbus.h> | ||
16 | #include <asm/oplib.h> | ||
17 | #include <asm/uaccess.h> | ||
18 | #include <asm/auxio.h> | ||
19 | |||
20 | /* Debug | ||
21 | * | ||
22 | * #define PMC_DEBUG_LED | ||
23 | * #define PMC_NO_IDLE | ||
24 | */ | ||
25 | |||
26 | #define PMC_MINOR MISC_DYNAMIC_MINOR | ||
27 | #define PMC_OBPNAME "SUNW,pmc" | ||
28 | #define PMC_DEVNAME "pmc" | ||
29 | |||
30 | #define PMC_IDLE_REG 0x00 | ||
31 | #define PMC_IDLE_ON 0x01 | ||
32 | |||
33 | volatile static u8 __iomem *regs; | ||
34 | static int pmc_regsize; | ||
35 | |||
36 | #define pmc_readb(offs) (sbus_readb(regs+offs)) | ||
37 | #define pmc_writeb(val, offs) (sbus_writeb(val, regs+offs)) | ||
38 | |||
39 | /* | ||
40 | * CPU idle callback function | ||
41 | * See .../arch/sparc/kernel/process.c | ||
42 | */ | ||
43 | void pmc_swift_idle(void) | ||
44 | { | ||
45 | #ifdef PMC_DEBUG_LED | ||
46 | set_auxio(0x00, AUXIO_LED); | ||
47 | #endif | ||
48 | |||
49 | pmc_writeb(pmc_readb(PMC_IDLE_REG) | PMC_IDLE_ON, PMC_IDLE_REG); | ||
50 | |||
51 | #ifdef PMC_DEBUG_LED | ||
52 | set_auxio(AUXIO_LED, 0x00); | ||
53 | #endif | ||
54 | } | ||
55 | |||
56 | static inline void pmc_free(void) | ||
57 | { | ||
58 | sbus_iounmap(regs, pmc_regsize); | ||
59 | } | ||
60 | |||
61 | static int __init pmc_probe(void) | ||
62 | { | ||
63 | struct sbus_bus *sbus = NULL; | ||
64 | struct sbus_dev *sdev = NULL; | ||
65 | for_each_sbus(sbus) { | ||
66 | for_each_sbusdev(sdev, sbus) { | ||
67 | if (!strcmp(sdev->prom_name, PMC_OBPNAME)) { | ||
68 | goto sbus_done; | ||
69 | } | ||
70 | } | ||
71 | } | ||
72 | |||
73 | sbus_done: | ||
74 | if (!sdev) { | ||
75 | return -ENODEV; | ||
76 | } | ||
77 | |||
78 | pmc_regsize = sdev->reg_addrs[0].reg_size; | ||
79 | regs = sbus_ioremap(&sdev->resource[0], 0, | ||
80 | pmc_regsize, PMC_OBPNAME); | ||
81 | if (!regs) { | ||
82 | printk(KERN_ERR "%s: unable to map registers\n", PMC_DEVNAME); | ||
83 | return -ENODEV; | ||
84 | } | ||
85 | |||
86 | #ifndef PMC_NO_IDLE | ||
87 | /* Assign power management IDLE handler */ | ||
88 | pm_idle = pmc_swift_idle; | ||
89 | #endif | ||
90 | |||
91 | printk(KERN_INFO "%s: power management initialized\n", PMC_DEVNAME); | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | /* This driver is not critical to the boot process | ||
96 | * and is easiest to ioremap when SBus is already | ||
97 | * initialized, so we install ourselves thusly: | ||
98 | */ | ||
99 | __initcall(pmc_probe); | ||