blob: 2a355ae5956241982680f1f1958c974645c84054 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Device driver for the via-pmu on Apple Powermacs.
3 *
4 * The VIA (versatile interface adapter) interfaces to the PMU,
5 * a 6805 microprocessor core whose primary function is to control
6 * battery charging and system power on the PowerBook 3400 and 2400.
7 * The PMU also controls the ADB (Apple Desktop Bus) which connects
8 * to the keyboard and mouse, as well as the non-volatile RAM
9 * and the RTC (real time clock) chip.
10 *
11 * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi.
12 * Copyright (C) 2001-2002 Benjamin Herrenschmidt
13 *
14 * THIS DRIVER IS BECOMING A TOTAL MESS !
15 * - Cleanup atomically disabling reply to PMU events after
16 * a sleep or a freq. switch
17 * - Move sleep code out of here to pmac_pm, merge into new
18 * common PM infrastructure
19 * - Move backlight code out as well
20 * - Save/Restore PCI space properly
21 *
22 */
23#include <stdarg.h>
24#include <linux/config.h>
25#include <linux/types.h>
26#include <linux/errno.h>
27#include <linux/kernel.h>
28#include <linux/delay.h>
29#include <linux/sched.h>
30#include <linux/miscdevice.h>
31#include <linux/blkdev.h>
32#include <linux/pci.h>
33#include <linux/slab.h>
34#include <linux/poll.h>
35#include <linux/adb.h>
36#include <linux/pmu.h>
37#include <linux/cuda.h>
38#include <linux/smp_lock.h>
39#include <linux/module.h>
40#include <linux/spinlock.h>
41#include <linux/pm.h>
42#include <linux/proc_fs.h>
43#include <linux/init.h>
44#include <linux/interrupt.h>
45#include <linux/device.h>
46#include <linux/sysdev.h>
47#include <linux/suspend.h>
48#include <linux/syscalls.h>
49#include <linux/cpu.h>
50#include <asm/prom.h>
51#include <asm/machdep.h>
52#include <asm/io.h>
53#include <asm/pgtable.h>
54#include <asm/system.h>
55#include <asm/sections.h>
56#include <asm/irq.h>
57#include <asm/pmac_feature.h>
Benjamin Herrenschmidt5b9ca522006-01-07 11:41:02 +110058#include <asm/pmac_pfunc.h>
59#include <asm/pmac_low_i2c.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#include <asm/uaccess.h>
61#include <asm/mmu_context.h>
62#include <asm/cputable.h>
63#include <asm/time.h>
64#ifdef CONFIG_PMAC_BACKLIGHT
65#include <asm/backlight.h>
66#endif
67
Benjamin Herrenschmidte4ee69c2005-06-27 14:36:32 -070068#ifdef CONFIG_PPC32
69#include <asm/open_pic.h>
70#endif
71
Linus Torvalds1da177e2005-04-16 15:20:36 -070072/* Some compile options */
73#undef SUSPEND_USES_PMU
74#define DEBUG_SLEEP
75#undef HACKED_PCI_SAVE
76
77/* Misc minor number allocated for /dev/pmu */
78#define PMU_MINOR 154
79
80/* How many iterations between battery polls */
81#define BATTERY_POLLING_COUNT 2
82
83static volatile unsigned char __iomem *via;
84
85/* VIA registers - spaced 0x200 bytes apart */
86#define RS 0x200 /* skip between registers */
87#define B 0 /* B-side data */
88#define A RS /* A-side data */
89#define DIRB (2*RS) /* B-side direction (1=output) */
90#define DIRA (3*RS) /* A-side direction (1=output) */
91#define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */
92#define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */
93#define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */
94#define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */
95#define T2CL (8*RS) /* Timer 2 ctr/latch (low 8 bits) */
96#define T2CH (9*RS) /* Timer 2 counter (high 8 bits) */
97#define SR (10*RS) /* Shift register */
98#define ACR (11*RS) /* Auxiliary control register */
99#define PCR (12*RS) /* Peripheral control register */
100#define IFR (13*RS) /* Interrupt flag register */
101#define IER (14*RS) /* Interrupt enable register */
102#define ANH (15*RS) /* A-side data, no handshake */
103
104/* Bits in B data register: both active low */
105#define TACK 0x08 /* Transfer acknowledge (input) */
106#define TREQ 0x10 /* Transfer request (output) */
107
108/* Bits in ACR */
109#define SR_CTRL 0x1c /* Shift register control bits */
110#define SR_EXT 0x0c /* Shift on external clock */
111#define SR_OUT 0x10 /* Shift out if 1 */
112
113/* Bits in IFR and IER */
114#define IER_SET 0x80 /* set bits in IER */
115#define IER_CLR 0 /* clear bits in IER */
116#define SR_INT 0x04 /* Shift register full/empty */
117#define CB2_INT 0x08
118#define CB1_INT 0x10 /* transition on CB1 input */
119
120static volatile enum pmu_state {
121 idle,
122 sending,
123 intack,
124 reading,
125 reading_intr,
126 locked,
127} pmu_state;
128
129static volatile enum int_data_state {
130 int_data_empty,
131 int_data_fill,
132 int_data_ready,
133 int_data_flush
134} int_data_state[2] = { int_data_empty, int_data_empty };
135
136static struct adb_request *current_req;
137static struct adb_request *last_req;
138static struct adb_request *req_awaiting_reply;
139static unsigned char interrupt_data[2][32];
140static int interrupt_data_len[2];
141static int int_data_last;
142static unsigned char *reply_ptr;
143static int data_index;
144static int data_len;
145static volatile int adb_int_pending;
146static volatile int disable_poll;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147static struct device_node *vias;
148static int pmu_kind = PMU_UNKNOWN;
149static int pmu_fully_inited = 0;
150static int pmu_has_adb;
Benjamin Herrenschmidt51d30822005-11-23 17:57:25 +1100151static struct device_node *gpio_node;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152static unsigned char __iomem *gpio_reg = NULL;
153static int gpio_irq = -1;
154static int gpio_irq_enabled = -1;
155static volatile int pmu_suspended = 0;
156static spinlock_t pmu_lock;
157static u8 pmu_intr_mask;
158static int pmu_version;
159static int drop_interrupts;
Paul Mackerrasa0005032005-11-02 15:08:17 +1100160#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161static int option_lid_wakeup = 1;
Paul Mackerrasa0005032005-11-02 15:08:17 +1100162#endif /* CONFIG_PM && CONFIG_PPC32 */
Michael Hanselmann5474c122006-06-25 05:47:08 -0700163#if (defined(CONFIG_PM)&&defined(CONFIG_PPC32))||defined(CONFIG_PMAC_BACKLIGHT_LEGACY)
Kristian Muellera04c8782005-12-15 12:31:55 +0800164static int sleep_in_progress;
Andrew Morton57ae5952006-03-21 23:20:27 -0800165#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166static unsigned long async_req_locks;
167static unsigned int pmu_irq_stats[11];
168
169static struct proc_dir_entry *proc_pmu_root;
170static struct proc_dir_entry *proc_pmu_info;
171static struct proc_dir_entry *proc_pmu_irqstats;
172static struct proc_dir_entry *proc_pmu_options;
173static int option_server_mode;
174
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175int pmu_battery_count;
176int pmu_cur_battery;
177unsigned int pmu_power_flags;
178struct pmu_battery_info pmu_batteries[PMU_MAX_BATTERIES];
179static int query_batt_timer = BATTERY_POLLING_COUNT;
180static struct adb_request batt_req;
181static struct proc_dir_entry *proc_pmu_batt[PMU_MAX_BATTERIES];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
183#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
184extern int disable_kernel_backlight;
185#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */
186
187int __fake_sleep;
188int asleep;
Alan Sterne041c682006-03-27 01:16:30 -0800189BLOCKING_NOTIFIER_HEAD(sleep_notifier_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190
191#ifdef CONFIG_ADB
192static int adb_dev_map = 0;
193static int pmu_adb_flags;
194
195static int pmu_probe(void);
196static int pmu_init(void);
197static int pmu_send_request(struct adb_request *req, int sync);
198static int pmu_adb_autopoll(int devs);
199static int pmu_adb_reset_bus(void);
200#endif /* CONFIG_ADB */
201
202static int init_pmu(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203static void pmu_start(void);
204static irqreturn_t via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs);
205static irqreturn_t gpio1_interrupt(int irq, void *arg, struct pt_regs *regs);
206static int proc_get_info(char *page, char **start, off_t off,
207 int count, int *eof, void *data);
208static int proc_get_irqstats(char *page, char **start, off_t off,
209 int count, int *eof, void *data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210static void pmu_pass_intr(unsigned char *data, int len);
211static int proc_get_batt(char *page, char **start, off_t off,
212 int count, int *eof, void *data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213static int proc_read_options(char *page, char **start, off_t off,
214 int count, int *eof, void *data);
215static int proc_write_options(struct file *file, const char __user *buffer,
216 unsigned long count, void *data);
217
218#ifdef CONFIG_ADB
219struct adb_driver via_pmu_driver = {
220 "PMU",
221 pmu_probe,
222 pmu_init,
223 pmu_send_request,
224 pmu_adb_autopoll,
225 pmu_poll_adb,
226 pmu_adb_reset_bus
227};
228#endif /* CONFIG_ADB */
229
230extern void low_sleep_handler(void);
231extern void enable_kernel_altivec(void);
232extern void enable_kernel_fp(void);
233
234#ifdef DEBUG_SLEEP
235int pmu_polled_request(struct adb_request *req);
236int pmu_wink(struct adb_request *req);
237#endif
238
239/*
240 * This table indicates for each PMU opcode:
241 * - the number of data bytes to be sent with the command, or -1
242 * if a length byte should be sent,
243 * - the number of response bytes which the PMU will return, or
244 * -1 if it will send a length byte.
245 */
Jon Loeligeraacaf9b2005-09-17 10:36:54 -0500246static const s8 pmu_data_len[256][2] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247/* 0 1 2 3 4 5 6 7 */
248/*00*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
249/*08*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
250/*10*/ { 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
251/*18*/ { 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0, 0},
252/*20*/ {-1, 0},{ 0, 0},{ 2, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},
253/*28*/ { 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0,-1},
254/*30*/ { 4, 0},{20, 0},{-1, 0},{ 3, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
255/*38*/ { 0, 4},{ 0,20},{ 2,-1},{ 2, 1},{ 3,-1},{-1,-1},{-1,-1},{ 4, 0},
256/*40*/ { 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
257/*48*/ { 0, 1},{ 0, 1},{-1,-1},{ 1, 0},{ 1, 0},{-1,-1},{-1,-1},{-1,-1},
258/*50*/ { 1, 0},{ 0, 0},{ 2, 0},{ 2, 0},{-1, 0},{ 1, 0},{ 3, 0},{ 1, 0},
259/*58*/ { 0, 1},{ 1, 0},{ 0, 2},{ 0, 2},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},
260/*60*/ { 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
261/*68*/ { 0, 3},{ 0, 3},{ 0, 2},{ 0, 8},{ 0,-1},{ 0,-1},{-1,-1},{-1,-1},
262/*70*/ { 1, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
263/*78*/ { 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{ 5, 1},{ 4, 1},{ 4, 1},
264/*80*/ { 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
265/*88*/ { 0, 5},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
266/*90*/ { 1, 0},{ 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
267/*98*/ { 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
268/*a0*/ { 2, 0},{ 2, 0},{ 2, 0},{ 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0},
269/*a8*/ { 1, 1},{ 1, 0},{ 3, 0},{ 2, 0},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
270/*b0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
271/*b8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
272/*c0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
273/*c8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
274/*d0*/ { 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
275/*d8*/ { 1, 1},{ 1, 1},{-1,-1},{-1,-1},{ 0, 1},{ 0,-1},{-1,-1},{-1,-1},
276/*e0*/ {-1, 0},{ 4, 0},{ 0, 1},{-1, 0},{-1, 0},{ 4, 0},{-1, 0},{-1, 0},
277/*e8*/ { 3,-1},{-1,-1},{ 0, 1},{-1,-1},{ 0,-1},{-1,-1},{-1,-1},{ 0, 0},
278/*f0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
279/*f8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
280};
281
282static char *pbook_type[] = {
283 "Unknown PowerBook",
284 "PowerBook 2400/3400/3500(G3)",
285 "PowerBook G3 Series",
286 "1999 PowerBook G3",
287 "Core99"
288};
289
Benjamin Herrenschmidt51d30822005-11-23 17:57:25 +1100290int __init find_via_pmu(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291{
Benjamin Herrenschmidtcc5d0182005-12-13 18:01:21 +1100292 u64 taddr;
Benjamin Herrenschmidt51d30822005-11-23 17:57:25 +1100293 u32 *reg;
294
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 if (via != 0)
296 return 1;
Benjamin Herrenschmidt51d30822005-11-23 17:57:25 +1100297 vias = of_find_node_by_name(NULL, "via-pmu");
298 if (vias == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
Benjamin Herrenschmidt51d30822005-11-23 17:57:25 +1100301 reg = (u32 *)get_property(vias, "reg", NULL);
302 if (reg == NULL) {
303 printk(KERN_ERR "via-pmu: No \"reg\" property !\n");
304 goto fail;
305 }
306 taddr = of_translate_address(vias, reg);
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100307 if (taddr == OF_BAD_ADDR) {
Benjamin Herrenschmidt51d30822005-11-23 17:57:25 +1100308 printk(KERN_ERR "via-pmu: Can't translate address !\n");
309 goto fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 }
311
312 spin_lock_init(&pmu_lock);
313
314 pmu_has_adb = 1;
315
316 pmu_intr_mask = PMU_INT_PCEJECT |
317 PMU_INT_SNDBRT |
318 PMU_INT_ADB |
319 PMU_INT_TICK;
320
321 if (vias->parent->name && ((strcmp(vias->parent->name, "ohare") == 0)
322 || device_is_compatible(vias->parent, "ohare")))
323 pmu_kind = PMU_OHARE_BASED;
324 else if (device_is_compatible(vias->parent, "paddington"))
325 pmu_kind = PMU_PADDINGTON_BASED;
326 else if (device_is_compatible(vias->parent, "heathrow"))
327 pmu_kind = PMU_HEATHROW_BASED;
328 else if (device_is_compatible(vias->parent, "Keylargo")
329 || device_is_compatible(vias->parent, "K2-Keylargo")) {
Benjamin Herrenschmidt51d30822005-11-23 17:57:25 +1100330 struct device_node *gpiop;
Benjamin Herrenschmidtcc5d0182005-12-13 18:01:21 +1100331 u64 gaddr = OF_BAD_ADDR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
333 pmu_kind = PMU_KEYLARGO_BASED;
334 pmu_has_adb = (find_type_devices("adb") != NULL);
335 pmu_intr_mask = PMU_INT_PCEJECT |
336 PMU_INT_SNDBRT |
337 PMU_INT_ADB |
338 PMU_INT_TICK |
339 PMU_INT_ENVIRONMENT;
340
Benjamin Herrenschmidt51d30822005-11-23 17:57:25 +1100341 gpiop = of_find_node_by_name(NULL, "gpio");
342 if (gpiop) {
343 reg = (u32 *)get_property(gpiop, "reg", NULL);
344 if (reg)
345 gaddr = of_translate_address(gpiop, reg);
Benjamin Herrenschmidtcc5d0182005-12-13 18:01:21 +1100346 if (gaddr != OF_BAD_ADDR)
Benjamin Herrenschmidt51d30822005-11-23 17:57:25 +1100347 gpio_reg = ioremap(gaddr, 0x10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 }
Benjamin Herrenschmidt51d30822005-11-23 17:57:25 +1100349 if (gpio_reg == NULL)
350 printk(KERN_ERR "via-pmu: Can't find GPIO reg !\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 } else
352 pmu_kind = PMU_UNKNOWN;
353
Benjamin Herrenschmidt51d30822005-11-23 17:57:25 +1100354 via = ioremap(taddr, 0x2000);
355 if (via == NULL) {
356 printk(KERN_ERR "via-pmu: Can't map address !\n");
357 goto fail;
358 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
360 out_8(&via[IER], IER_CLR | 0x7f); /* disable all intrs */
361 out_8(&via[IFR], 0x7f); /* clear IFR */
362
363 pmu_state = idle;
364
365 if (!init_pmu()) {
366 via = NULL;
367 return 0;
368 }
369
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100370 printk(KERN_INFO "PMU driver v%d initialized for %s, firmware: %02x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 PMU_DRIVER_VERSION, pbook_type[pmu_kind], pmu_version);
372
373 sys_ctrler = SYS_CTRLER_PMU;
374
375 return 1;
Benjamin Herrenschmidt51d30822005-11-23 17:57:25 +1100376 fail:
377 of_node_put(vias);
378 vias = NULL;
379 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380}
381
382#ifdef CONFIG_ADB
Benjamin Herrenschmidt51d30822005-11-23 17:57:25 +1100383static int pmu_probe(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384{
385 return vias == NULL? -ENODEV: 0;
386}
387
Benjamin Herrenschmidt51d30822005-11-23 17:57:25 +1100388static int __init pmu_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389{
390 if (vias == NULL)
391 return -ENODEV;
392 return 0;
393}
394#endif /* CONFIG_ADB */
395
396/*
397 * We can't wait until pmu_init gets called, that happens too late.
398 * It happens after IDE and SCSI initialization, which can take a few
399 * seconds, and by that time the PMU could have given up on us and
400 * turned us off.
401 * Thus this is called with arch_initcall rather than device_initcall.
402 */
403static int __init via_pmu_start(void)
404{
405 if (vias == NULL)
406 return -ENODEV;
407
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 batt_req.complete = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409
Benjamin Herrenschmidt51d30822005-11-23 17:57:25 +1100410#ifndef CONFIG_PPC_MERGE
Benjamin Herrenschmidte4ee69c2005-06-27 14:36:32 -0700411 if (pmu_kind == PMU_KEYLARGO_BASED)
412 openpic_set_irq_priority(vias->intrs[0].line,
413 OPENPIC_PRIORITY_DEFAULT + 1);
414#endif
415
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 if (request_irq(vias->intrs[0].line, via_pmu_interrupt, 0, "VIA-PMU",
417 (void *)0)) {
418 printk(KERN_ERR "VIA-PMU: can't get irq %d\n",
419 vias->intrs[0].line);
420 return -EAGAIN;
421 }
422
Benjamin Herrenschmidt51d30822005-11-23 17:57:25 +1100423 if (pmu_kind == PMU_KEYLARGO_BASED) {
424 gpio_node = of_find_node_by_name(NULL, "extint-gpio1");
425 if (gpio_node == NULL)
426 gpio_node = of_find_node_by_name(NULL,
427 "pmu-interrupt");
428 if (gpio_node && gpio_node->n_intrs > 0)
429 gpio_irq = gpio_node->intrs[0].line;
430
431 if (gpio_irq != -1) {
432 if (request_irq(gpio_irq, gpio1_interrupt, 0,
433 "GPIO1 ADB", (void *)0))
434 printk(KERN_ERR "pmu: can't get irq %d"
435 " (GPIO1)\n", gpio_irq);
436 else
437 gpio_irq_enabled = 1;
438 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 }
440
441 /* Enable interrupts */
442 out_8(&via[IER], IER_SET | SR_INT | CB1_INT);
443
444 pmu_fully_inited = 1;
445
446 /* Make sure PMU settle down before continuing. This is _very_ important
447 * since the IDE probe may shut interrupts down for quite a bit of time. If
448 * a PMU communication is pending while this happens, the PMU may timeout
449 * Not that on Core99 machines, the PMU keeps sending us environement
450 * messages, we should find a way to either fix IDE or make it call
451 * pmu_suspend() before masking interrupts. This can also happens while
452 * scolling with some fbdevs.
453 */
454 do {
455 pmu_poll();
456 } while (pmu_state != idle);
457
458 return 0;
459}
460
461arch_initcall(via_pmu_start);
462
463/*
464 * This has to be done after pci_init, which is a subsys_initcall.
465 */
466static int __init via_pmu_dev_init(void)
467{
468 if (vias == NULL)
469 return -ENODEV;
470
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471#ifdef CONFIG_PMAC_BACKLIGHT
Michael Hanselmann5474c122006-06-25 05:47:08 -0700472 /* Initialize backlight */
473 pmu_backlight_init(vias);
474#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475
Benjamin Herrenschmidt8c870932005-06-27 14:36:34 -0700476#ifdef CONFIG_PPC32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 if (machine_is_compatible("AAPL,3400/2400") ||
478 machine_is_compatible("AAPL,3500")) {
479 int mb = pmac_call_feature(PMAC_FTR_GET_MB_INFO,
480 NULL, PMAC_MB_INFO_MODEL, 0);
481 pmu_battery_count = 1;
482 if (mb == PMAC_TYPE_COMET)
483 pmu_batteries[0].flags |= PMU_BATT_TYPE_COMET;
484 else
485 pmu_batteries[0].flags |= PMU_BATT_TYPE_HOOPER;
486 } else if (machine_is_compatible("AAPL,PowerBook1998") ||
487 machine_is_compatible("PowerBook1,1")) {
488 pmu_battery_count = 2;
489 pmu_batteries[0].flags |= PMU_BATT_TYPE_SMART;
490 pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART;
491 } else {
492 struct device_node* prim = find_devices("power-mgt");
493 u32 *prim_info = NULL;
494 if (prim)
495 prim_info = (u32 *)get_property(prim, "prim-info", NULL);
496 if (prim_info) {
497 /* Other stuffs here yet unknown */
498 pmu_battery_count = (prim_info[6] >> 16) & 0xff;
499 pmu_batteries[0].flags |= PMU_BATT_TYPE_SMART;
500 if (pmu_battery_count > 1)
501 pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART;
502 }
503 }
Benjamin Herrenschmidt8c870932005-06-27 14:36:34 -0700504#endif /* CONFIG_PPC32 */
505
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 /* Create /proc/pmu */
507 proc_pmu_root = proc_mkdir("pmu", NULL);
508 if (proc_pmu_root) {
Benjamin Herrenschmidt8c870932005-06-27 14:36:34 -0700509 long i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510
511 for (i=0; i<pmu_battery_count; i++) {
512 char title[16];
Benjamin Herrenschmidt8c870932005-06-27 14:36:34 -0700513 sprintf(title, "battery_%ld", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 proc_pmu_batt[i] = create_proc_read_entry(title, 0, proc_pmu_root,
515 proc_get_batt, (void *)i);
516 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517
518 proc_pmu_info = create_proc_read_entry("info", 0, proc_pmu_root,
519 proc_get_info, NULL);
520 proc_pmu_irqstats = create_proc_read_entry("interrupts", 0, proc_pmu_root,
521 proc_get_irqstats, NULL);
522 proc_pmu_options = create_proc_entry("options", 0600, proc_pmu_root);
523 if (proc_pmu_options) {
524 proc_pmu_options->nlink = 1;
525 proc_pmu_options->read_proc = proc_read_options;
526 proc_pmu_options->write_proc = proc_write_options;
527 }
528 }
529 return 0;
530}
531
532device_initcall(via_pmu_dev_init);
533
Jon Loeligeraacaf9b2005-09-17 10:36:54 -0500534static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535init_pmu(void)
536{
537 int timeout;
538 struct adb_request req;
539
540 out_8(&via[B], via[B] | TREQ); /* negate TREQ */
541 out_8(&via[DIRB], (via[DIRB] | TREQ) & ~TACK); /* TACK in, TREQ out */
542
543 pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask);
544 timeout = 100000;
545 while (!req.complete) {
546 if (--timeout < 0) {
547 printk(KERN_ERR "init_pmu: no response from PMU\n");
548 return 0;
549 }
550 udelay(10);
551 pmu_poll();
552 }
553
554 /* ack all pending interrupts */
555 timeout = 100000;
556 interrupt_data[0][0] = 1;
557 while (interrupt_data[0][0] || pmu_state != idle) {
558 if (--timeout < 0) {
559 printk(KERN_ERR "init_pmu: timed out acking intrs\n");
560 return 0;
561 }
562 if (pmu_state == idle)
563 adb_int_pending = 1;
564 via_pmu_interrupt(0, NULL, NULL);
565 udelay(10);
566 }
567
568 /* Tell PMU we are ready. */
569 if (pmu_kind == PMU_KEYLARGO_BASED) {
570 pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2);
571 while (!req.complete)
572 pmu_poll();
573 }
574
575 /* Read PMU version */
576 pmu_request(&req, NULL, 1, PMU_GET_VERSION);
577 pmu_wait_complete(&req);
578 if (req.reply_len > 0)
579 pmu_version = req.reply[0];
580
581 /* Read server mode setting */
582 if (pmu_kind == PMU_KEYLARGO_BASED) {
583 pmu_request(&req, NULL, 2, PMU_POWER_EVENTS,
584 PMU_PWR_GET_POWERUP_EVENTS);
585 pmu_wait_complete(&req);
586 if (req.reply_len == 2) {
587 if (req.reply[1] & PMU_PWR_WAKEUP_AC_INSERT)
588 option_server_mode = 1;
589 printk(KERN_INFO "via-pmu: Server Mode is %s\n",
590 option_server_mode ? "enabled" : "disabled");
591 }
592 }
593 return 1;
594}
595
596int
597pmu_get_model(void)
598{
599 return pmu_kind;
600}
601
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602static void pmu_set_server_mode(int server_mode)
603{
604 struct adb_request req;
605
606 if (pmu_kind != PMU_KEYLARGO_BASED)
607 return;
608
609 option_server_mode = server_mode;
610 pmu_request(&req, NULL, 2, PMU_POWER_EVENTS, PMU_PWR_GET_POWERUP_EVENTS);
611 pmu_wait_complete(&req);
612 if (req.reply_len < 2)
613 return;
614 if (server_mode)
615 pmu_request(&req, NULL, 4, PMU_POWER_EVENTS,
616 PMU_PWR_SET_POWERUP_EVENTS,
617 req.reply[0], PMU_PWR_WAKEUP_AC_INSERT);
618 else
619 pmu_request(&req, NULL, 4, PMU_POWER_EVENTS,
620 PMU_PWR_CLR_POWERUP_EVENTS,
621 req.reply[0], PMU_PWR_WAKEUP_AC_INSERT);
622 pmu_wait_complete(&req);
623}
624
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625/* This new version of the code for 2400/3400/3500 powerbooks
626 * is inspired from the implementation in gkrellm-pmu
627 */
Jon Loeligeraacaf9b2005-09-17 10:36:54 -0500628static void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629done_battery_state_ohare(struct adb_request* req)
630{
631 /* format:
632 * [0] : flags
633 * 0x01 : AC indicator
634 * 0x02 : charging
635 * 0x04 : battery exist
636 * 0x08 :
637 * 0x10 :
638 * 0x20 : full charged
639 * 0x40 : pcharge reset
640 * 0x80 : battery exist
641 *
642 * [1][2] : battery voltage
643 * [3] : CPU temperature
644 * [4] : battery temperature
645 * [5] : current
646 * [6][7] : pcharge
647 * --tkoba
648 */
649 unsigned int bat_flags = PMU_BATT_TYPE_HOOPER;
650 long pcharge, charge, vb, vmax, lmax;
651 long vmax_charging, vmax_charged;
652 long amperage, voltage, time, max;
653 int mb = pmac_call_feature(PMAC_FTR_GET_MB_INFO,
654 NULL, PMAC_MB_INFO_MODEL, 0);
655
656 if (req->reply[0] & 0x01)
657 pmu_power_flags |= PMU_PWR_AC_PRESENT;
658 else
659 pmu_power_flags &= ~PMU_PWR_AC_PRESENT;
660
661 if (mb == PMAC_TYPE_COMET) {
662 vmax_charged = 189;
663 vmax_charging = 213;
664 lmax = 6500;
665 } else {
666 vmax_charged = 330;
667 vmax_charging = 330;
668 lmax = 6500;
669 }
670 vmax = vmax_charged;
671
672 /* If battery installed */
673 if (req->reply[0] & 0x04) {
674 bat_flags |= PMU_BATT_PRESENT;
675 if (req->reply[0] & 0x02)
676 bat_flags |= PMU_BATT_CHARGING;
677 vb = (req->reply[1] << 8) | req->reply[2];
678 voltage = (vb * 265 + 72665) / 10;
679 amperage = req->reply[5];
680 if ((req->reply[0] & 0x01) == 0) {
681 if (amperage > 200)
682 vb += ((amperage - 200) * 15)/100;
683 } else if (req->reply[0] & 0x02) {
684 vb = (vb * 97) / 100;
685 vmax = vmax_charging;
686 }
687 charge = (100 * vb) / vmax;
688 if (req->reply[0] & 0x40) {
689 pcharge = (req->reply[6] << 8) + req->reply[7];
690 if (pcharge > lmax)
691 pcharge = lmax;
692 pcharge *= 100;
693 pcharge = 100 - pcharge / lmax;
694 if (pcharge < charge)
695 charge = pcharge;
696 }
697 if (amperage > 0)
698 time = (charge * 16440) / amperage;
699 else
700 time = 0;
701 max = 100;
702 amperage = -amperage;
703 } else
704 charge = max = amperage = voltage = time = 0;
705
706 pmu_batteries[pmu_cur_battery].flags = bat_flags;
707 pmu_batteries[pmu_cur_battery].charge = charge;
708 pmu_batteries[pmu_cur_battery].max_charge = max;
709 pmu_batteries[pmu_cur_battery].amperage = amperage;
710 pmu_batteries[pmu_cur_battery].voltage = voltage;
711 pmu_batteries[pmu_cur_battery].time_remaining = time;
712
713 clear_bit(0, &async_req_locks);
714}
715
Jon Loeligeraacaf9b2005-09-17 10:36:54 -0500716static void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717done_battery_state_smart(struct adb_request* req)
718{
719 /* format:
720 * [0] : format of this structure (known: 3,4,5)
721 * [1] : flags
722 *
723 * format 3 & 4:
724 *
725 * [2] : charge
726 * [3] : max charge
727 * [4] : current
728 * [5] : voltage
729 *
730 * format 5:
731 *
732 * [2][3] : charge
733 * [4][5] : max charge
734 * [6][7] : current
735 * [8][9] : voltage
736 */
737
738 unsigned int bat_flags = PMU_BATT_TYPE_SMART;
739 int amperage;
740 unsigned int capa, max, voltage;
741
742 if (req->reply[1] & 0x01)
743 pmu_power_flags |= PMU_PWR_AC_PRESENT;
744 else
745 pmu_power_flags &= ~PMU_PWR_AC_PRESENT;
746
747
748 capa = max = amperage = voltage = 0;
749
750 if (req->reply[1] & 0x04) {
751 bat_flags |= PMU_BATT_PRESENT;
752 switch(req->reply[0]) {
753 case 3:
754 case 4: capa = req->reply[2];
755 max = req->reply[3];
756 amperage = *((signed char *)&req->reply[4]);
757 voltage = req->reply[5];
758 break;
759 case 5: capa = (req->reply[2] << 8) | req->reply[3];
760 max = (req->reply[4] << 8) | req->reply[5];
761 amperage = *((signed short *)&req->reply[6]);
762 voltage = (req->reply[8] << 8) | req->reply[9];
763 break;
764 default:
765 printk(KERN_WARNING "pmu.c : unrecognized battery info, len: %d, %02x %02x %02x %02x\n",
766 req->reply_len, req->reply[0], req->reply[1], req->reply[2], req->reply[3]);
767 break;
768 }
769 }
770
771 if ((req->reply[1] & 0x01) && (amperage > 0))
772 bat_flags |= PMU_BATT_CHARGING;
773
774 pmu_batteries[pmu_cur_battery].flags = bat_flags;
775 pmu_batteries[pmu_cur_battery].charge = capa;
776 pmu_batteries[pmu_cur_battery].max_charge = max;
777 pmu_batteries[pmu_cur_battery].amperage = amperage;
778 pmu_batteries[pmu_cur_battery].voltage = voltage;
779 if (amperage) {
780 if ((req->reply[1] & 0x01) && (amperage > 0))
781 pmu_batteries[pmu_cur_battery].time_remaining
782 = ((max-capa) * 3600) / amperage;
783 else
784 pmu_batteries[pmu_cur_battery].time_remaining
785 = (capa * 3600) / (-amperage);
786 } else
787 pmu_batteries[pmu_cur_battery].time_remaining = 0;
788
789 pmu_cur_battery = (pmu_cur_battery + 1) % pmu_battery_count;
790
791 clear_bit(0, &async_req_locks);
792}
793
Jon Loeligeraacaf9b2005-09-17 10:36:54 -0500794static void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795query_battery_state(void)
796{
797 if (test_and_set_bit(0, &async_req_locks))
798 return;
799 if (pmu_kind == PMU_OHARE_BASED)
800 pmu_request(&batt_req, done_battery_state_ohare,
801 1, PMU_BATTERY_STATE);
802 else
803 pmu_request(&batt_req, done_battery_state_smart,
804 2, PMU_SMART_BATTERY_STATE, pmu_cur_battery+1);
805}
806
Jon Loeligeraacaf9b2005-09-17 10:36:54 -0500807static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808proc_get_info(char *page, char **start, off_t off,
809 int count, int *eof, void *data)
810{
811 char* p = page;
812
813 p += sprintf(p, "PMU driver version : %d\n", PMU_DRIVER_VERSION);
814 p += sprintf(p, "PMU firmware version : %02x\n", pmu_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 p += sprintf(p, "AC Power : %d\n",
Benjamin Herrenschmidt63e1fd42006-03-13 21:20:42 -0800816 ((pmu_power_flags & PMU_PWR_AC_PRESENT) != 0) || pmu_battery_count == 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 p += sprintf(p, "Battery count : %d\n", pmu_battery_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818
819 return p - page;
820}
821
Jon Loeligeraacaf9b2005-09-17 10:36:54 -0500822static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823proc_get_irqstats(char *page, char **start, off_t off,
824 int count, int *eof, void *data)
825{
826 int i;
827 char* p = page;
828 static const char *irq_names[] = {
829 "Total CB1 triggered events",
830 "Total GPIO1 triggered events",
831 "PC-Card eject button",
832 "Sound/Brightness button",
833 "ADB message",
834 "Battery state change",
835 "Environment interrupt",
836 "Tick timer",
837 "Ghost interrupt (zero len)",
838 "Empty interrupt (empty mask)",
839 "Max irqs in a row"
840 };
841
842 for (i=0; i<11; i++) {
843 p += sprintf(p, " %2u: %10u (%s)\n",
844 i, pmu_irq_stats[i], irq_names[i]);
845 }
846 return p - page;
847}
848
Jon Loeligeraacaf9b2005-09-17 10:36:54 -0500849static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850proc_get_batt(char *page, char **start, off_t off,
851 int count, int *eof, void *data)
852{
Benjamin Herrenschmidt8c870932005-06-27 14:36:34 -0700853 long batnum = (long)data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 char *p = page;
855
856 p += sprintf(p, "\n");
857 p += sprintf(p, "flags : %08x\n",
858 pmu_batteries[batnum].flags);
859 p += sprintf(p, "charge : %d\n",
860 pmu_batteries[batnum].charge);
861 p += sprintf(p, "max_charge : %d\n",
862 pmu_batteries[batnum].max_charge);
863 p += sprintf(p, "current : %d\n",
864 pmu_batteries[batnum].amperage);
865 p += sprintf(p, "voltage : %d\n",
866 pmu_batteries[batnum].voltage);
867 p += sprintf(p, "time rem. : %d\n",
868 pmu_batteries[batnum].time_remaining);
869
870 return p - page;
871}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872
Jon Loeligeraacaf9b2005-09-17 10:36:54 -0500873static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874proc_read_options(char *page, char **start, off_t off,
875 int count, int *eof, void *data)
876{
877 char *p = page;
878
Paul Mackerrasa0005032005-11-02 15:08:17 +1100879#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 if (pmu_kind == PMU_KEYLARGO_BASED &&
881 pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
882 p += sprintf(p, "lid_wakeup=%d\n", option_lid_wakeup);
Benjamin Herrenschmidt8c870932005-06-27 14:36:34 -0700883#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 if (pmu_kind == PMU_KEYLARGO_BASED)
885 p += sprintf(p, "server_mode=%d\n", option_server_mode);
886
887 return p - page;
888}
889
Jon Loeligeraacaf9b2005-09-17 10:36:54 -0500890static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891proc_write_options(struct file *file, const char __user *buffer,
892 unsigned long count, void *data)
893{
894 char tmp[33];
895 char *label, *val;
896 unsigned long fcount = count;
897
898 if (!count)
899 return -EINVAL;
900 if (count > 32)
901 count = 32;
902 if (copy_from_user(tmp, buffer, count))
903 return -EFAULT;
904 tmp[count] = 0;
905
906 label = tmp;
907 while(*label == ' ')
908 label++;
909 val = label;
910 while(*val && (*val != '=')) {
911 if (*val == ' ')
912 *val = 0;
913 val++;
914 }
915 if ((*val) == 0)
916 return -EINVAL;
917 *(val++) = 0;
918 while(*val == ' ')
919 val++;
Paul Mackerrasa0005032005-11-02 15:08:17 +1100920#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 if (pmu_kind == PMU_KEYLARGO_BASED &&
922 pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
923 if (!strcmp(label, "lid_wakeup"))
924 option_lid_wakeup = ((*val) == '1');
Benjamin Herrenschmidt8c870932005-06-27 14:36:34 -0700925#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 if (pmu_kind == PMU_KEYLARGO_BASED && !strcmp(label, "server_mode")) {
927 int new_value;
928 new_value = ((*val) == '1');
929 if (new_value != option_server_mode)
930 pmu_set_server_mode(new_value);
931 }
932 return fcount;
933}
934
935#ifdef CONFIG_ADB
936/* Send an ADB command */
Jon Loeligeraacaf9b2005-09-17 10:36:54 -0500937static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938pmu_send_request(struct adb_request *req, int sync)
939{
940 int i, ret;
941
942 if ((vias == NULL) || (!pmu_fully_inited)) {
943 req->complete = 1;
944 return -ENXIO;
945 }
946
947 ret = -EINVAL;
948
949 switch (req->data[0]) {
950 case PMU_PACKET:
951 for (i = 0; i < req->nbytes - 1; ++i)
952 req->data[i] = req->data[i+1];
953 --req->nbytes;
954 if (pmu_data_len[req->data[0]][1] != 0) {
955 req->reply[0] = ADB_RET_OK;
956 req->reply_len = 1;
957 } else
958 req->reply_len = 0;
959 ret = pmu_queue_request(req);
960 break;
961 case CUDA_PACKET:
962 switch (req->data[1]) {
963 case CUDA_GET_TIME:
964 if (req->nbytes != 2)
965 break;
966 req->data[0] = PMU_READ_RTC;
967 req->nbytes = 1;
968 req->reply_len = 3;
969 req->reply[0] = CUDA_PACKET;
970 req->reply[1] = 0;
971 req->reply[2] = CUDA_GET_TIME;
972 ret = pmu_queue_request(req);
973 break;
974 case CUDA_SET_TIME:
975 if (req->nbytes != 6)
976 break;
977 req->data[0] = PMU_SET_RTC;
978 req->nbytes = 5;
979 for (i = 1; i <= 4; ++i)
980 req->data[i] = req->data[i+1];
981 req->reply_len = 3;
982 req->reply[0] = CUDA_PACKET;
983 req->reply[1] = 0;
984 req->reply[2] = CUDA_SET_TIME;
985 ret = pmu_queue_request(req);
986 break;
987 }
988 break;
989 case ADB_PACKET:
990 if (!pmu_has_adb)
991 return -ENXIO;
992 for (i = req->nbytes - 1; i > 1; --i)
993 req->data[i+2] = req->data[i];
994 req->data[3] = req->nbytes - 2;
995 req->data[2] = pmu_adb_flags;
996 /*req->data[1] = req->data[1];*/
997 req->data[0] = PMU_ADB_CMD;
998 req->nbytes += 2;
999 req->reply_expected = 1;
1000 req->reply_len = 0;
1001 ret = pmu_queue_request(req);
1002 break;
1003 }
1004 if (ret) {
1005 req->complete = 1;
1006 return ret;
1007 }
1008
1009 if (sync)
1010 while (!req->complete)
1011 pmu_poll();
1012
1013 return 0;
1014}
1015
1016/* Enable/disable autopolling */
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05001017static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018pmu_adb_autopoll(int devs)
1019{
1020 struct adb_request req;
1021
1022 if ((vias == NULL) || (!pmu_fully_inited) || !pmu_has_adb)
1023 return -ENXIO;
1024
1025 if (devs) {
1026 adb_dev_map = devs;
1027 pmu_request(&req, NULL, 5, PMU_ADB_CMD, 0, 0x86,
1028 adb_dev_map >> 8, adb_dev_map);
1029 pmu_adb_flags = 2;
1030 } else {
1031 pmu_request(&req, NULL, 1, PMU_ADB_POLL_OFF);
1032 pmu_adb_flags = 0;
1033 }
1034 while (!req.complete)
1035 pmu_poll();
1036 return 0;
1037}
1038
1039/* Reset the ADB bus */
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05001040static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041pmu_adb_reset_bus(void)
1042{
1043 struct adb_request req;
1044 int save_autopoll = adb_dev_map;
1045
1046 if ((vias == NULL) || (!pmu_fully_inited) || !pmu_has_adb)
1047 return -ENXIO;
1048
1049 /* anyone got a better idea?? */
1050 pmu_adb_autopoll(0);
1051
1052 req.nbytes = 5;
1053 req.done = NULL;
1054 req.data[0] = PMU_ADB_CMD;
1055 req.data[1] = 0;
1056 req.data[2] = ADB_BUSRESET;
1057 req.data[3] = 0;
1058 req.data[4] = 0;
1059 req.reply_len = 0;
1060 req.reply_expected = 1;
1061 if (pmu_queue_request(&req) != 0) {
1062 printk(KERN_ERR "pmu_adb_reset_bus: pmu_queue_request failed\n");
1063 return -EIO;
1064 }
1065 pmu_wait_complete(&req);
1066
1067 if (save_autopoll != 0)
1068 pmu_adb_autopoll(save_autopoll);
1069
1070 return 0;
1071}
1072#endif /* CONFIG_ADB */
1073
1074/* Construct and send a pmu request */
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05001075int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076pmu_request(struct adb_request *req, void (*done)(struct adb_request *),
1077 int nbytes, ...)
1078{
1079 va_list list;
1080 int i;
1081
1082 if (vias == NULL)
1083 return -ENXIO;
1084
1085 if (nbytes < 0 || nbytes > 32) {
1086 printk(KERN_ERR "pmu_request: bad nbytes (%d)\n", nbytes);
1087 req->complete = 1;
1088 return -EINVAL;
1089 }
1090 req->nbytes = nbytes;
1091 req->done = done;
1092 va_start(list, nbytes);
1093 for (i = 0; i < nbytes; ++i)
1094 req->data[i] = va_arg(list, int);
1095 va_end(list);
1096 req->reply_len = 0;
1097 req->reply_expected = 0;
1098 return pmu_queue_request(req);
1099}
1100
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05001101int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102pmu_queue_request(struct adb_request *req)
1103{
1104 unsigned long flags;
1105 int nsend;
1106
1107 if (via == NULL) {
1108 req->complete = 1;
1109 return -ENXIO;
1110 }
1111 if (req->nbytes <= 0) {
1112 req->complete = 1;
1113 return 0;
1114 }
1115 nsend = pmu_data_len[req->data[0]][0];
1116 if (nsend >= 0 && req->nbytes != nsend + 1) {
1117 req->complete = 1;
1118 return -EINVAL;
1119 }
1120
1121 req->next = NULL;
1122 req->sent = 0;
1123 req->complete = 0;
1124
1125 spin_lock_irqsave(&pmu_lock, flags);
1126 if (current_req != 0) {
1127 last_req->next = req;
1128 last_req = req;
1129 } else {
1130 current_req = req;
1131 last_req = req;
1132 if (pmu_state == idle)
1133 pmu_start();
1134 }
1135 spin_unlock_irqrestore(&pmu_lock, flags);
1136
1137 return 0;
1138}
1139
1140static inline void
1141wait_for_ack(void)
1142{
1143 /* Sightly increased the delay, I had one occurrence of the message
1144 * reported
1145 */
1146 int timeout = 4000;
1147 while ((in_8(&via[B]) & TACK) == 0) {
1148 if (--timeout < 0) {
1149 printk(KERN_ERR "PMU not responding (!ack)\n");
1150 return;
1151 }
1152 udelay(10);
1153 }
1154}
1155
1156/* New PMU seems to be very sensitive to those timings, so we make sure
1157 * PCI is flushed immediately */
1158static inline void
1159send_byte(int x)
1160{
1161 volatile unsigned char __iomem *v = via;
1162
1163 out_8(&v[ACR], in_8(&v[ACR]) | SR_OUT | SR_EXT);
1164 out_8(&v[SR], x);
1165 out_8(&v[B], in_8(&v[B]) & ~TREQ); /* assert TREQ */
1166 (void)in_8(&v[B]);
1167}
1168
1169static inline void
1170recv_byte(void)
1171{
1172 volatile unsigned char __iomem *v = via;
1173
1174 out_8(&v[ACR], (in_8(&v[ACR]) & ~SR_OUT) | SR_EXT);
1175 in_8(&v[SR]); /* resets SR */
1176 out_8(&v[B], in_8(&v[B]) & ~TREQ);
1177 (void)in_8(&v[B]);
1178}
1179
1180static inline void
1181pmu_done(struct adb_request *req)
1182{
1183 void (*done)(struct adb_request *) = req->done;
1184 mb();
1185 req->complete = 1;
1186 /* Here, we assume that if the request has a done member, the
1187 * struct request will survive to setting req->complete to 1
1188 */
1189 if (done)
1190 (*done)(req);
1191}
1192
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05001193static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194pmu_start(void)
1195{
1196 struct adb_request *req;
1197
1198 /* assert pmu_state == idle */
1199 /* get the packet to send */
1200 req = current_req;
1201 if (req == 0 || pmu_state != idle
1202 || (/*req->reply_expected && */req_awaiting_reply))
1203 return;
1204
1205 pmu_state = sending;
1206 data_index = 1;
1207 data_len = pmu_data_len[req->data[0]][0];
1208
1209 /* Sounds safer to make sure ACK is high before writing. This helped
1210 * kill a problem with ADB and some iBooks
1211 */
1212 wait_for_ack();
1213 /* set the shift register to shift out and send a byte */
1214 send_byte(req->data[0]);
1215}
1216
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05001217void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218pmu_poll(void)
1219{
1220 if (!via)
1221 return;
1222 if (disable_poll)
1223 return;
1224 via_pmu_interrupt(0, NULL, NULL);
1225}
1226
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05001227void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228pmu_poll_adb(void)
1229{
1230 if (!via)
1231 return;
1232 if (disable_poll)
1233 return;
1234 /* Kicks ADB read when PMU is suspended */
1235 adb_int_pending = 1;
1236 do {
1237 via_pmu_interrupt(0, NULL, NULL);
1238 } while (pmu_suspended && (adb_int_pending || pmu_state != idle
1239 || req_awaiting_reply));
1240}
1241
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05001242void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243pmu_wait_complete(struct adb_request *req)
1244{
1245 if (!via)
1246 return;
1247 while((pmu_state != idle && pmu_state != locked) || !req->complete)
1248 via_pmu_interrupt(0, NULL, NULL);
1249}
1250
1251/* This function loops until the PMU is idle and prevents it from
1252 * anwsering to ADB interrupts. pmu_request can still be called.
1253 * This is done to avoid spurrious shutdowns when we know we'll have
1254 * interrupts switched off for a long time
1255 */
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05001256void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257pmu_suspend(void)
1258{
1259 unsigned long flags;
1260#ifdef SUSPEND_USES_PMU
1261 struct adb_request *req;
1262#endif
1263 if (!via)
1264 return;
1265
1266 spin_lock_irqsave(&pmu_lock, flags);
1267 pmu_suspended++;
1268 if (pmu_suspended > 1) {
1269 spin_unlock_irqrestore(&pmu_lock, flags);
1270 return;
1271 }
1272
1273 do {
1274 spin_unlock_irqrestore(&pmu_lock, flags);
1275 if (req_awaiting_reply)
1276 adb_int_pending = 1;
1277 via_pmu_interrupt(0, NULL, NULL);
1278 spin_lock_irqsave(&pmu_lock, flags);
1279 if (!adb_int_pending && pmu_state == idle && !req_awaiting_reply) {
1280#ifdef SUSPEND_USES_PMU
1281 pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0);
1282 spin_unlock_irqrestore(&pmu_lock, flags);
1283 while(!req.complete)
1284 pmu_poll();
1285#else /* SUSPEND_USES_PMU */
1286 if (gpio_irq >= 0)
1287 disable_irq_nosync(gpio_irq);
1288 out_8(&via[IER], CB1_INT | IER_CLR);
1289 spin_unlock_irqrestore(&pmu_lock, flags);
1290#endif /* SUSPEND_USES_PMU */
1291 break;
1292 }
1293 } while (1);
1294}
1295
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05001296void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297pmu_resume(void)
1298{
1299 unsigned long flags;
1300
1301 if (!via || (pmu_suspended < 1))
1302 return;
1303
1304 spin_lock_irqsave(&pmu_lock, flags);
1305 pmu_suspended--;
1306 if (pmu_suspended > 0) {
1307 spin_unlock_irqrestore(&pmu_lock, flags);
1308 return;
1309 }
1310 adb_int_pending = 1;
1311#ifdef SUSPEND_USES_PMU
1312 pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask);
1313 spin_unlock_irqrestore(&pmu_lock, flags);
1314 while(!req.complete)
1315 pmu_poll();
1316#else /* SUSPEND_USES_PMU */
1317 if (gpio_irq >= 0)
1318 enable_irq(gpio_irq);
1319 out_8(&via[IER], CB1_INT | IER_SET);
1320 spin_unlock_irqrestore(&pmu_lock, flags);
1321 pmu_poll();
1322#endif /* SUSPEND_USES_PMU */
1323}
1324
1325/* Interrupt data could be the result data from an ADB cmd */
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05001326static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
1328{
1329 unsigned char ints, pirq;
1330 int i = 0;
1331
1332 asleep = 0;
1333 if (drop_interrupts || len < 1) {
1334 adb_int_pending = 0;
1335 pmu_irq_stats[8]++;
1336 return;
1337 }
1338
1339 /* Get PMU interrupt mask */
1340 ints = data[0];
1341
1342 /* Record zero interrupts for stats */
1343 if (ints == 0)
1344 pmu_irq_stats[9]++;
1345
1346 /* Hack to deal with ADB autopoll flag */
1347 if (ints & PMU_INT_ADB)
1348 ints &= ~(PMU_INT_ADB_AUTO | PMU_INT_AUTO_SRQ_POLL);
1349
1350next:
1351
1352 if (ints == 0) {
1353 if (i > pmu_irq_stats[10])
1354 pmu_irq_stats[10] = i;
1355 return;
1356 }
1357
1358 for (pirq = 0; pirq < 8; pirq++)
1359 if (ints & (1 << pirq))
1360 break;
1361 pmu_irq_stats[pirq]++;
1362 i++;
1363 ints &= ~(1 << pirq);
1364
1365 /* Note: for some reason, we get an interrupt with len=1,
1366 * data[0]==0 after each normal ADB interrupt, at least
1367 * on the Pismo. Still investigating... --BenH
1368 */
1369 if ((1 << pirq) & PMU_INT_ADB) {
1370 if ((data[0] & PMU_INT_ADB_AUTO) == 0) {
1371 struct adb_request *req = req_awaiting_reply;
1372 if (req == 0) {
1373 printk(KERN_ERR "PMU: extra ADB reply\n");
1374 return;
1375 }
1376 req_awaiting_reply = NULL;
1377 if (len <= 2)
1378 req->reply_len = 0;
1379 else {
1380 memcpy(req->reply, data + 1, len - 1);
1381 req->reply_len = len - 1;
1382 }
1383 pmu_done(req);
1384 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 if (len == 4 && data[1] == 0x2c) {
1386 extern int xmon_wants_key, xmon_adb_keycode;
1387 if (xmon_wants_key) {
1388 xmon_adb_keycode = data[2];
1389 return;
1390 }
1391 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392#ifdef CONFIG_ADB
1393 /*
1394 * XXX On the [23]400 the PMU gives us an up
1395 * event for keycodes 0x74 or 0x75 when the PC
1396 * card eject buttons are released, so we
1397 * ignore those events.
1398 */
1399 if (!(pmu_kind == PMU_OHARE_BASED && len == 4
1400 && data[1] == 0x2c && data[3] == 0xff
1401 && (data[2] & ~1) == 0xf4))
1402 adb_input(data+1, len-1, regs, 1);
1403#endif /* CONFIG_ADB */
1404 }
1405 }
1406 /* Sound/brightness button pressed */
1407 else if ((1 << pirq) & PMU_INT_SNDBRT) {
1408#ifdef CONFIG_PMAC_BACKLIGHT
1409 if (len == 3)
1410#ifdef CONFIG_INPUT_ADBHID
1411 if (!disable_kernel_backlight)
1412#endif /* CONFIG_INPUT_ADBHID */
Michael Hanselmann5474c122006-06-25 05:47:08 -07001413 pmac_backlight_set_legacy_brightness(data[1] >> 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414#endif /* CONFIG_PMAC_BACKLIGHT */
1415 }
1416 /* Tick interrupt */
1417 else if ((1 << pirq) & PMU_INT_TICK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 /* Environement or tick interrupt, query batteries */
1419 if (pmu_battery_count) {
1420 if ((--query_batt_timer) == 0) {
1421 query_battery_state();
1422 query_batt_timer = BATTERY_POLLING_COUNT;
1423 }
1424 }
1425 }
1426 else if ((1 << pirq) & PMU_INT_ENVIRONMENT) {
1427 if (pmu_battery_count)
1428 query_battery_state();
1429 pmu_pass_intr(data, len);
1430 } else {
1431 pmu_pass_intr(data, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 }
1433 goto next;
1434}
1435
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05001436static struct adb_request*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437pmu_sr_intr(struct pt_regs *regs)
1438{
1439 struct adb_request *req;
1440 int bite = 0;
1441
1442 if (via[B] & TREQ) {
1443 printk(KERN_ERR "PMU: spurious SR intr (%x)\n", via[B]);
1444 out_8(&via[IFR], SR_INT);
1445 return NULL;
1446 }
1447 /* The ack may not yet be low when we get the interrupt */
1448 while ((in_8(&via[B]) & TACK) != 0)
1449 ;
1450
1451 /* if reading grab the byte, and reset the interrupt */
1452 if (pmu_state == reading || pmu_state == reading_intr)
1453 bite = in_8(&via[SR]);
1454
1455 /* reset TREQ and wait for TACK to go high */
1456 out_8(&via[B], in_8(&via[B]) | TREQ);
1457 wait_for_ack();
1458
1459 switch (pmu_state) {
1460 case sending:
1461 req = current_req;
1462 if (data_len < 0) {
1463 data_len = req->nbytes - 1;
1464 send_byte(data_len);
1465 break;
1466 }
1467 if (data_index <= data_len) {
1468 send_byte(req->data[data_index++]);
1469 break;
1470 }
1471 req->sent = 1;
1472 data_len = pmu_data_len[req->data[0]][1];
1473 if (data_len == 0) {
1474 pmu_state = idle;
1475 current_req = req->next;
1476 if (req->reply_expected)
1477 req_awaiting_reply = req;
1478 else
1479 return req;
1480 } else {
1481 pmu_state = reading;
1482 data_index = 0;
1483 reply_ptr = req->reply + req->reply_len;
1484 recv_byte();
1485 }
1486 break;
1487
1488 case intack:
1489 data_index = 0;
1490 data_len = -1;
1491 pmu_state = reading_intr;
1492 reply_ptr = interrupt_data[int_data_last];
1493 recv_byte();
1494 if (gpio_irq >= 0 && !gpio_irq_enabled) {
1495 enable_irq(gpio_irq);
1496 gpio_irq_enabled = 1;
1497 }
1498 break;
1499
1500 case reading:
1501 case reading_intr:
1502 if (data_len == -1) {
1503 data_len = bite;
1504 if (bite > 32)
1505 printk(KERN_ERR "PMU: bad reply len %d\n", bite);
1506 } else if (data_index < 32) {
1507 reply_ptr[data_index++] = bite;
1508 }
1509 if (data_index < data_len) {
1510 recv_byte();
1511 break;
1512 }
1513
1514 if (pmu_state == reading_intr) {
1515 pmu_state = idle;
1516 int_data_state[int_data_last] = int_data_ready;
1517 interrupt_data_len[int_data_last] = data_len;
1518 } else {
1519 req = current_req;
1520 /*
1521 * For PMU sleep and freq change requests, we lock the
1522 * PMU until it's explicitely unlocked. This avoids any
1523 * spurrious event polling getting in
1524 */
1525 current_req = req->next;
1526 req->reply_len += data_index;
1527 if (req->data[0] == PMU_SLEEP || req->data[0] == PMU_CPU_SPEED)
1528 pmu_state = locked;
1529 else
1530 pmu_state = idle;
1531 return req;
1532 }
1533 break;
1534
1535 default:
1536 printk(KERN_ERR "via_pmu_interrupt: unknown state %d?\n",
1537 pmu_state);
1538 }
1539 return NULL;
1540}
1541
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05001542static irqreturn_t
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
1544{
1545 unsigned long flags;
1546 int intr;
1547 int nloop = 0;
1548 int int_data = -1;
1549 struct adb_request *req = NULL;
1550 int handled = 0;
1551
1552 /* This is a bit brutal, we can probably do better */
1553 spin_lock_irqsave(&pmu_lock, flags);
1554 ++disable_poll;
1555
1556 for (;;) {
1557 intr = in_8(&via[IFR]) & (SR_INT | CB1_INT);
1558 if (intr == 0)
1559 break;
1560 handled = 1;
1561 if (++nloop > 1000) {
1562 printk(KERN_DEBUG "PMU: stuck in intr loop, "
1563 "intr=%x, ier=%x pmu_state=%d\n",
1564 intr, in_8(&via[IER]), pmu_state);
1565 break;
1566 }
1567 out_8(&via[IFR], intr);
1568 if (intr & CB1_INT) {
1569 adb_int_pending = 1;
1570 pmu_irq_stats[0]++;
1571 }
1572 if (intr & SR_INT) {
1573 req = pmu_sr_intr(regs);
1574 if (req)
1575 break;
1576 }
1577 }
1578
1579recheck:
1580 if (pmu_state == idle) {
1581 if (adb_int_pending) {
1582 if (int_data_state[0] == int_data_empty)
1583 int_data_last = 0;
1584 else if (int_data_state[1] == int_data_empty)
1585 int_data_last = 1;
1586 else
1587 goto no_free_slot;
1588 pmu_state = intack;
1589 int_data_state[int_data_last] = int_data_fill;
1590 /* Sounds safer to make sure ACK is high before writing.
1591 * This helped kill a problem with ADB and some iBooks
1592 */
1593 wait_for_ack();
1594 send_byte(PMU_INT_ACK);
1595 adb_int_pending = 0;
1596 } else if (current_req)
1597 pmu_start();
1598 }
1599no_free_slot:
1600 /* Mark the oldest buffer for flushing */
1601 if (int_data_state[!int_data_last] == int_data_ready) {
1602 int_data_state[!int_data_last] = int_data_flush;
1603 int_data = !int_data_last;
1604 } else if (int_data_state[int_data_last] == int_data_ready) {
1605 int_data_state[int_data_last] = int_data_flush;
1606 int_data = int_data_last;
1607 }
1608 --disable_poll;
1609 spin_unlock_irqrestore(&pmu_lock, flags);
1610
1611 /* Deal with completed PMU requests outside of the lock */
1612 if (req) {
1613 pmu_done(req);
1614 req = NULL;
1615 }
1616
1617 /* Deal with interrupt datas outside of the lock */
1618 if (int_data >= 0) {
1619 pmu_handle_data(interrupt_data[int_data], interrupt_data_len[int_data], regs);
1620 spin_lock_irqsave(&pmu_lock, flags);
1621 ++disable_poll;
1622 int_data_state[int_data] = int_data_empty;
1623 int_data = -1;
1624 goto recheck;
1625 }
1626
1627 return IRQ_RETVAL(handled);
1628}
1629
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05001630void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631pmu_unlock(void)
1632{
1633 unsigned long flags;
1634
1635 spin_lock_irqsave(&pmu_lock, flags);
1636 if (pmu_state == locked)
1637 pmu_state = idle;
1638 adb_int_pending = 1;
1639 spin_unlock_irqrestore(&pmu_lock, flags);
1640}
1641
1642
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05001643static irqreturn_t
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644gpio1_interrupt(int irq, void *arg, struct pt_regs *regs)
1645{
1646 unsigned long flags;
1647
1648 if ((in_8(gpio_reg + 0x9) & 0x02) == 0) {
1649 spin_lock_irqsave(&pmu_lock, flags);
1650 if (gpio_irq_enabled > 0) {
1651 disable_irq_nosync(gpio_irq);
1652 gpio_irq_enabled = 0;
1653 }
1654 pmu_irq_stats[1]++;
1655 adb_int_pending = 1;
1656 spin_unlock_irqrestore(&pmu_lock, flags);
1657 via_pmu_interrupt(0, NULL, NULL);
1658 return IRQ_HANDLED;
1659 }
1660 return IRQ_NONE;
1661}
1662
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05001663void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664pmu_enable_irled(int on)
1665{
1666 struct adb_request req;
1667
1668 if (vias == NULL)
1669 return ;
1670 if (pmu_kind == PMU_KEYLARGO_BASED)
1671 return ;
1672
1673 pmu_request(&req, NULL, 2, PMU_POWER_CTRL, PMU_POW_IRLED |
1674 (on ? PMU_POW_ON : PMU_POW_OFF));
1675 pmu_wait_complete(&req);
1676}
1677
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05001678void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679pmu_restart(void)
1680{
1681 struct adb_request req;
1682
1683 if (via == NULL)
1684 return;
1685
1686 local_irq_disable();
1687
1688 drop_interrupts = 1;
1689
1690 if (pmu_kind != PMU_KEYLARGO_BASED) {
1691 pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB |
1692 PMU_INT_TICK );
1693 while(!req.complete)
1694 pmu_poll();
1695 }
1696
1697 pmu_request(&req, NULL, 1, PMU_RESET);
1698 pmu_wait_complete(&req);
1699 for (;;)
1700 ;
1701}
1702
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05001703void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704pmu_shutdown(void)
1705{
1706 struct adb_request req;
1707
1708 if (via == NULL)
1709 return;
1710
1711 local_irq_disable();
1712
1713 drop_interrupts = 1;
1714
1715 if (pmu_kind != PMU_KEYLARGO_BASED) {
1716 pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB |
1717 PMU_INT_TICK );
1718 pmu_wait_complete(&req);
1719 } else {
1720 /* Disable server mode on shutdown or we'll just
1721 * wake up again
1722 */
1723 pmu_set_server_mode(0);
1724 }
1725
1726 pmu_request(&req, NULL, 5, PMU_SHUTDOWN,
1727 'M', 'A', 'T', 'T');
1728 pmu_wait_complete(&req);
1729 for (;;)
1730 ;
1731}
1732
1733int
1734pmu_present(void)
1735{
1736 return via != 0;
1737}
1738
Benjamin Herrenschmidt8c870932005-06-27 14:36:34 -07001739#ifdef CONFIG_PM
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740
1741static LIST_HEAD(sleep_notifiers);
1742
1743int
1744pmu_register_sleep_notifier(struct pmu_sleep_notifier *n)
1745{
1746 struct list_head *list;
1747 struct pmu_sleep_notifier *notifier;
1748
1749 for (list = sleep_notifiers.next; list != &sleep_notifiers;
1750 list = list->next) {
1751 notifier = list_entry(list, struct pmu_sleep_notifier, list);
1752 if (n->priority > notifier->priority)
1753 break;
1754 }
1755 __list_add(&n->list, list->prev, list);
1756 return 0;
1757}
Paul Mackerras3fb62b52005-11-08 12:14:50 +11001758EXPORT_SYMBOL(pmu_register_sleep_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759
1760int
1761pmu_unregister_sleep_notifier(struct pmu_sleep_notifier* n)
1762{
1763 if (n->list.next == 0)
1764 return -ENOENT;
1765 list_del(&n->list);
1766 n->list.next = NULL;
1767 return 0;
1768}
Paul Mackerras3fb62b52005-11-08 12:14:50 +11001769EXPORT_SYMBOL(pmu_unregister_sleep_notifier);
Paul Mackerrasa0005032005-11-02 15:08:17 +11001770#endif /* CONFIG_PM */
1771
1772#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773
1774/* Sleep is broadcast last-to-first */
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05001775static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776broadcast_sleep(int when, int fallback)
1777{
1778 int ret = PBOOK_SLEEP_OK;
1779 struct list_head *list;
1780 struct pmu_sleep_notifier *notifier;
1781
1782 for (list = sleep_notifiers.prev; list != &sleep_notifiers;
1783 list = list->prev) {
1784 notifier = list_entry(list, struct pmu_sleep_notifier, list);
1785 ret = notifier->notifier_call(notifier, when);
1786 if (ret != PBOOK_SLEEP_OK) {
1787 printk(KERN_DEBUG "sleep %d rejected by %p (%p)\n",
1788 when, notifier, notifier->notifier_call);
1789 for (; list != &sleep_notifiers; list = list->next) {
1790 notifier = list_entry(list, struct pmu_sleep_notifier, list);
1791 notifier->notifier_call(notifier, fallback);
1792 }
1793 return ret;
1794 }
1795 }
1796 return ret;
1797}
1798
1799/* Wake is broadcast first-to-last */
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05001800static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801broadcast_wake(void)
1802{
1803 int ret = PBOOK_SLEEP_OK;
1804 struct list_head *list;
1805 struct pmu_sleep_notifier *notifier;
1806
1807 for (list = sleep_notifiers.next; list != &sleep_notifiers;
1808 list = list->next) {
1809 notifier = list_entry(list, struct pmu_sleep_notifier, list);
1810 notifier->notifier_call(notifier, PBOOK_WAKE);
1811 }
1812 return ret;
1813}
1814
1815/*
1816 * This struct is used to store config register values for
1817 * PCI devices which may get powered off when we sleep.
1818 */
1819static struct pci_save {
1820#ifndef HACKED_PCI_SAVE
1821 u16 command;
1822 u16 cache_lat;
1823 u16 intr;
1824 u32 rom_address;
1825#else
1826 u32 config[16];
1827#endif
1828} *pbook_pci_saves;
1829static int pbook_npci_saves;
1830
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05001831static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832pbook_alloc_pci_save(void)
1833{
1834 int npci;
1835 struct pci_dev *pd = NULL;
1836
1837 npci = 0;
1838 while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
1839 ++npci;
1840 }
1841 if (npci == 0)
1842 return;
1843 pbook_pci_saves = (struct pci_save *)
1844 kmalloc(npci * sizeof(struct pci_save), GFP_KERNEL);
1845 pbook_npci_saves = npci;
1846}
1847
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05001848static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849pbook_free_pci_save(void)
1850{
1851 if (pbook_pci_saves == NULL)
1852 return;
1853 kfree(pbook_pci_saves);
1854 pbook_pci_saves = NULL;
1855 pbook_npci_saves = 0;
1856}
1857
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05001858static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859pbook_pci_save(void)
1860{
1861 struct pci_save *ps = pbook_pci_saves;
1862 struct pci_dev *pd = NULL;
1863 int npci = pbook_npci_saves;
1864
1865 if (ps == NULL)
1866 return;
1867
1868 while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
1869 if (npci-- == 0)
1870 return;
1871#ifndef HACKED_PCI_SAVE
1872 pci_read_config_word(pd, PCI_COMMAND, &ps->command);
1873 pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat);
1874 pci_read_config_word(pd, PCI_INTERRUPT_LINE, &ps->intr);
1875 pci_read_config_dword(pd, PCI_ROM_ADDRESS, &ps->rom_address);
1876#else
1877 int i;
1878 for (i=1;i<16;i++)
1879 pci_read_config_dword(pd, i<<4, &ps->config[i]);
1880#endif
1881 ++ps;
1882 }
1883}
1884
1885/* For this to work, we must take care of a few things: If gmac was enabled
1886 * during boot, it will be in the pci dev list. If it's disabled at this point
1887 * (and it will probably be), then you can't access it's config space.
1888 */
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05001889static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890pbook_pci_restore(void)
1891{
1892 u16 cmd;
1893 struct pci_save *ps = pbook_pci_saves - 1;
1894 struct pci_dev *pd = NULL;
1895 int npci = pbook_npci_saves;
1896 int j;
1897
1898 while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
1899#ifdef HACKED_PCI_SAVE
1900 int i;
1901 if (npci-- == 0)
1902 return;
1903 ps++;
1904 for (i=2;i<16;i++)
1905 pci_write_config_dword(pd, i<<4, ps->config[i]);
1906 pci_write_config_dword(pd, 4, ps->config[1]);
1907#else
1908 if (npci-- == 0)
1909 return;
1910 ps++;
1911 if (ps->command == 0)
1912 continue;
1913 pci_read_config_word(pd, PCI_COMMAND, &cmd);
1914 if ((ps->command & ~cmd) == 0)
1915 continue;
1916 switch (pd->hdr_type) {
1917 case PCI_HEADER_TYPE_NORMAL:
1918 for (j = 0; j < 6; ++j)
1919 pci_write_config_dword(pd,
1920 PCI_BASE_ADDRESS_0 + j*4,
1921 pd->resource[j].start);
1922 pci_write_config_dword(pd, PCI_ROM_ADDRESS,
1923 ps->rom_address);
1924 pci_write_config_word(pd, PCI_CACHE_LINE_SIZE,
1925 ps->cache_lat);
1926 pci_write_config_word(pd, PCI_INTERRUPT_LINE,
1927 ps->intr);
1928 pci_write_config_word(pd, PCI_COMMAND, ps->command);
1929 break;
1930 }
1931#endif
1932 }
1933}
1934
1935#ifdef DEBUG_SLEEP
1936/* N.B. This doesn't work on the 3400 */
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05001937void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938pmu_blink(int n)
1939{
1940 struct adb_request req;
1941
1942 memset(&req, 0, sizeof(req));
1943
1944 for (; n > 0; --n) {
1945 req.nbytes = 4;
1946 req.done = NULL;
1947 req.data[0] = 0xee;
1948 req.data[1] = 4;
1949 req.data[2] = 0;
1950 req.data[3] = 1;
1951 req.reply[0] = ADB_RET_OK;
1952 req.reply_len = 1;
1953 req.reply_expected = 0;
1954 pmu_polled_request(&req);
1955 mdelay(50);
1956 req.nbytes = 4;
1957 req.done = NULL;
1958 req.data[0] = 0xee;
1959 req.data[1] = 4;
1960 req.data[2] = 0;
1961 req.data[3] = 0;
1962 req.reply[0] = ADB_RET_OK;
1963 req.reply_len = 1;
1964 req.reply_expected = 0;
1965 pmu_polled_request(&req);
1966 mdelay(50);
1967 }
1968 mdelay(50);
1969}
1970#endif
1971
1972/*
1973 * Put the powerbook to sleep.
1974 */
1975
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05001976static u32 save_via[8];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05001978static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979save_via_state(void)
1980{
1981 save_via[0] = in_8(&via[ANH]);
1982 save_via[1] = in_8(&via[DIRA]);
1983 save_via[2] = in_8(&via[B]);
1984 save_via[3] = in_8(&via[DIRB]);
1985 save_via[4] = in_8(&via[PCR]);
1986 save_via[5] = in_8(&via[ACR]);
1987 save_via[6] = in_8(&via[T1CL]);
1988 save_via[7] = in_8(&via[T1CH]);
1989}
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05001990static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991restore_via_state(void)
1992{
1993 out_8(&via[ANH], save_via[0]);
1994 out_8(&via[DIRA], save_via[1]);
1995 out_8(&via[B], save_via[2]);
1996 out_8(&via[DIRB], save_via[3]);
1997 out_8(&via[PCR], save_via[4]);
1998 out_8(&via[ACR], save_via[5]);
1999 out_8(&via[T1CL], save_via[6]);
2000 out_8(&via[T1CH], save_via[7]);
2001 out_8(&via[IER], IER_CLR | 0x7f); /* disable all intrs */
2002 out_8(&via[IFR], 0x7f); /* clear IFR */
2003 out_8(&via[IER], IER_SET | SR_INT | CB1_INT);
2004}
2005
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05002006static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007pmac_suspend_devices(void)
2008{
2009 int ret;
2010
2011 pm_prepare_console();
2012
2013 /* Notify old-style device drivers & userland */
2014 ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT);
2015 if (ret != PBOOK_SLEEP_OK) {
2016 printk(KERN_ERR "Sleep rejected by drivers\n");
2017 return -EBUSY;
2018 }
2019
2020 /* Sync the disks. */
2021 /* XXX It would be nice to have some way to ensure that
2022 * nobody is dirtying any new buffers while we wait. That
2023 * could be achieved using the refrigerator for processes
2024 * that swsusp uses
2025 */
2026 sys_sync();
2027
2028 /* Sleep can fail now. May not be very robust but useful for debugging */
2029 ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE);
2030 if (ret != PBOOK_SLEEP_OK) {
2031 printk(KERN_ERR "Driver sleep failed\n");
2032 return -EBUSY;
2033 }
2034
2035 /* Send suspend call to devices, hold the device core's dpm_sem */
2036 ret = device_suspend(PMSG_SUSPEND);
2037 if (ret) {
2038 broadcast_wake();
2039 printk(KERN_ERR "Driver sleep failed\n");
2040 return -EBUSY;
2041 }
2042
Benjamin Herrenschmidt5b9ca522006-01-07 11:41:02 +11002043 /* Call platform functions marked "on sleep" */
2044 pmac_pfunc_i2c_suspend();
2045 pmac_pfunc_base_suspend();
2046
Benjamin Herrenschmidte521dca2005-05-02 16:12:00 +10002047 /* Stop preemption */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 preempt_disable();
2049
2050 /* Make sure the decrementer won't interrupt us */
2051 asm volatile("mtdec %0" : : "r" (0x7fffffff));
2052 /* Make sure any pending DEC interrupt occurring while we did
2053 * the above didn't re-enable the DEC */
2054 mb();
2055 asm volatile("mtdec %0" : : "r" (0x7fffffff));
2056
2057 /* We can now disable MSR_EE. This code of course works properly only
2058 * on UP machines... For SMP, if we ever implement sleep, we'll have to
2059 * stop the "other" CPUs way before we do all that stuff.
2060 */
2061 local_irq_disable();
2062
2063 /* Broadcast power down irq
2064 * This isn't that useful in most cases (only directly wired devices can
2065 * use this but still... This will take care of sysdev's as well, so
2066 * we exit from here with local irqs disabled and PIC off.
2067 */
Pavel Machekbf2049f2005-04-16 15:25:38 -07002068 ret = device_power_down(PMSG_SUSPEND);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 if (ret) {
2070 wakeup_decrementer();
2071 local_irq_enable();
2072 preempt_enable();
2073 device_resume();
2074 broadcast_wake();
2075 printk(KERN_ERR "Driver powerdown failed\n");
2076 return -EBUSY;
2077 }
2078
Michael Hanselmann5474c122006-06-25 05:47:08 -07002079 /* Wait for completion of async requests */
2080 while (!batt_req.complete)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081 pmu_poll();
2082
2083 /* Giveup the lazy FPU & vec so we don't have to back them
2084 * up from the low level code
2085 */
2086 enable_kernel_fp();
2087
2088#ifdef CONFIG_ALTIVEC
2089 if (cpu_has_feature(CPU_FTR_ALTIVEC))
2090 enable_kernel_altivec();
2091#endif /* CONFIG_ALTIVEC */
2092
2093 return 0;
2094}
2095
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05002096static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097pmac_wakeup_devices(void)
2098{
2099 mdelay(100);
2100
2101 /* Power back up system devices (including the PIC) */
2102 device_power_up();
2103
2104 /* Force a poll of ADB interrupts */
2105 adb_int_pending = 1;
2106 via_pmu_interrupt(0, NULL, NULL);
2107
2108 /* Restart jiffies & scheduling */
2109 wakeup_decrementer();
2110
2111 /* Re-enable local CPU interrupts */
2112 local_irq_enable();
Benjamin Herrenschmidtb16eeb42005-05-27 12:53:02 -07002113 mdelay(10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 preempt_enable();
2115
Benjamin Herrenschmidt5b9ca522006-01-07 11:41:02 +11002116 /* Call platform functions marked "on wake" */
2117 pmac_pfunc_base_resume();
2118 pmac_pfunc_i2c_resume();
2119
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 /* Resume devices */
2121 device_resume();
2122
2123 /* Notify old style drivers */
2124 broadcast_wake();
2125
2126 pm_restore_console();
2127
2128 return 0;
2129}
2130
2131#define GRACKLE_PM (1<<7)
2132#define GRACKLE_DOZE (1<<5)
2133#define GRACKLE_NAP (1<<4)
2134#define GRACKLE_SLEEP (1<<3)
2135
Olaf Hering3bea6312006-03-21 23:00:05 -08002136static int powerbook_sleep_grackle(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137{
2138 unsigned long save_l2cr;
2139 unsigned short pmcr1;
2140 struct adb_request req;
2141 int ret;
2142 struct pci_dev *grackle;
2143
2144 grackle = pci_find_slot(0, 0);
2145 if (!grackle)
2146 return -ENODEV;
2147
2148 ret = pmac_suspend_devices();
2149 if (ret) {
2150 printk(KERN_ERR "Sleep rejected by devices\n");
2151 return ret;
2152 }
2153
2154 /* Turn off various things. Darwin does some retry tests here... */
2155 pmu_request(&req, NULL, 2, PMU_POWER_CTRL0, PMU_POW0_OFF|PMU_POW0_HARD_DRIVE);
2156 pmu_wait_complete(&req);
2157 pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
2158 PMU_POW_OFF|PMU_POW_BACKLIGHT|PMU_POW_IRLED|PMU_POW_MEDIABAY);
2159 pmu_wait_complete(&req);
2160
2161 /* For 750, save backside cache setting and disable it */
2162 save_l2cr = _get_L2CR(); /* (returns -1 if not available) */
2163
2164 if (!__fake_sleep) {
2165 /* Ask the PMU to put us to sleep */
2166 pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
2167 pmu_wait_complete(&req);
2168 }
2169
2170 /* The VIA is supposed not to be restored correctly*/
2171 save_via_state();
2172 /* We shut down some HW */
2173 pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,1);
2174
2175 pci_read_config_word(grackle, 0x70, &pmcr1);
2176 /* Apparently, MacOS uses NAP mode for Grackle ??? */
2177 pmcr1 &= ~(GRACKLE_DOZE|GRACKLE_SLEEP);
2178 pmcr1 |= GRACKLE_PM|GRACKLE_NAP;
2179 pci_write_config_word(grackle, 0x70, pmcr1);
2180
2181 /* Call low-level ASM sleep handler */
2182 if (__fake_sleep)
2183 mdelay(5000);
2184 else
2185 low_sleep_handler();
2186
2187 /* We're awake again, stop grackle PM */
2188 pci_read_config_word(grackle, 0x70, &pmcr1);
2189 pmcr1 &= ~(GRACKLE_PM|GRACKLE_DOZE|GRACKLE_SLEEP|GRACKLE_NAP);
2190 pci_write_config_word(grackle, 0x70, pmcr1);
2191
2192 /* Make sure the PMU is idle */
2193 pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0);
2194 restore_via_state();
2195
2196 /* Restore L2 cache */
2197 if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0)
2198 _set_L2CR(save_l2cr);
2199
2200 /* Restore userland MMU context */
Paul Mackerras6218a762006-06-11 14:15:17 +10002201 set_context(current->active_mm->context.id, current->active_mm->pgd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202
2203 /* Power things up */
2204 pmu_unlock();
2205 pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask);
2206 pmu_wait_complete(&req);
2207 pmu_request(&req, NULL, 2, PMU_POWER_CTRL0,
2208 PMU_POW0_ON|PMU_POW0_HARD_DRIVE);
2209 pmu_wait_complete(&req);
2210 pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
2211 PMU_POW_ON|PMU_POW_BACKLIGHT|PMU_POW_CHARGER|PMU_POW_IRLED|PMU_POW_MEDIABAY);
2212 pmu_wait_complete(&req);
2213
2214 pmac_wakeup_devices();
2215
2216 return 0;
2217}
2218
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05002219static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220powerbook_sleep_Core99(void)
2221{
2222 unsigned long save_l2cr;
2223 unsigned long save_l3cr;
2224 struct adb_request req;
2225 int ret;
2226
2227 if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) < 0) {
2228 printk(KERN_ERR "Sleep mode not supported on this machine\n");
2229 return -ENOSYS;
2230 }
2231
2232 if (num_online_cpus() > 1 || cpu_is_offline(0))
2233 return -EAGAIN;
2234
2235 ret = pmac_suspend_devices();
2236 if (ret) {
2237 printk(KERN_ERR "Sleep rejected by devices\n");
2238 return ret;
2239 }
2240
Benjamin Herrenschmidtb16eeb42005-05-27 12:53:02 -07002241 /* Stop environment and ADB interrupts */
2242 pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0);
2243 pmu_wait_complete(&req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244
2245 /* Tell PMU what events will wake us up */
2246 pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_CLR_WAKEUP_EVENTS,
2247 0xff, 0xff);
2248 pmu_wait_complete(&req);
2249 pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_SET_WAKEUP_EVENTS,
2250 0, PMU_PWR_WAKEUP_KEY |
2251 (option_lid_wakeup ? PMU_PWR_WAKEUP_LID_OPEN : 0));
2252 pmu_wait_complete(&req);
2253
2254 /* Save the state of the L2 and L3 caches */
2255 save_l3cr = _get_L3CR(); /* (returns -1 if not available) */
2256 save_l2cr = _get_L2CR(); /* (returns -1 if not available) */
2257
2258 if (!__fake_sleep) {
2259 /* Ask the PMU to put us to sleep */
2260 pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
2261 pmu_wait_complete(&req);
2262 }
2263
2264 /* The VIA is supposed not to be restored correctly*/
2265 save_via_state();
2266
2267 /* Shut down various ASICs. There's a chance that we can no longer
2268 * talk to the PMU after this, so I moved it to _after_ sending the
2269 * sleep command to it. Still need to be checked.
2270 */
2271 pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, 1);
2272
2273 /* Call low-level ASM sleep handler */
2274 if (__fake_sleep)
2275 mdelay(5000);
2276 else
2277 low_sleep_handler();
2278
2279 /* Restore Apple core ASICs state */
2280 pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, 0);
2281
2282 /* Restore VIA */
2283 restore_via_state();
2284
Benjamin Herrenschmidt0086b5e2005-06-10 14:19:02 +10002285 /* tweak LPJ before cpufreq is there */
2286 loops_per_jiffy *= 2;
2287
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 /* Restore video */
2289 pmac_call_early_video_resume();
2290
2291 /* Restore L2 cache */
2292 if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0)
2293 _set_L2CR(save_l2cr);
2294 /* Restore L3 cache */
2295 if (save_l3cr != 0xffffffff && (save_l3cr & L3CR_L3E) != 0)
2296 _set_L3CR(save_l3cr);
2297
2298 /* Restore userland MMU context */
Paul Mackerras6218a762006-06-11 14:15:17 +10002299 set_context(current->active_mm->context.id, current->active_mm->pgd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300
2301 /* Tell PMU we are ready */
2302 pmu_unlock();
2303 pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2);
2304 pmu_wait_complete(&req);
2305 pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask);
2306 pmu_wait_complete(&req);
2307
Benjamin Herrenschmidt0086b5e2005-06-10 14:19:02 +10002308 /* Restore LPJ, cpufreq will adjust the cpu frequency */
2309 loops_per_jiffy /= 2;
2310
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311 pmac_wakeup_devices();
2312
2313 return 0;
2314}
2315
2316#define PB3400_MEM_CTRL 0xf8000000
2317#define PB3400_MEM_CTRL_SLEEP 0x70
2318
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05002319static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320powerbook_sleep_3400(void)
2321{
2322 int ret, i, x;
2323 unsigned int hid0;
2324 unsigned long p;
2325 struct adb_request sleep_req;
2326 void __iomem *mem_ctrl;
2327 unsigned int __iomem *mem_ctrl_sleep;
2328
2329 /* first map in the memory controller registers */
2330 mem_ctrl = ioremap(PB3400_MEM_CTRL, 0x100);
2331 if (mem_ctrl == NULL) {
2332 printk("powerbook_sleep_3400: ioremap failed\n");
2333 return -ENOMEM;
2334 }
2335 mem_ctrl_sleep = mem_ctrl + PB3400_MEM_CTRL_SLEEP;
2336
2337 /* Allocate room for PCI save */
2338 pbook_alloc_pci_save();
2339
2340 ret = pmac_suspend_devices();
2341 if (ret) {
2342 pbook_free_pci_save();
2343 printk(KERN_ERR "Sleep rejected by devices\n");
2344 return ret;
2345 }
2346
2347 /* Save the state of PCI config space for some slots */
2348 pbook_pci_save();
2349
2350 /* Set the memory controller to keep the memory refreshed
2351 while we're asleep */
2352 for (i = 0x403f; i >= 0x4000; --i) {
2353 out_be32(mem_ctrl_sleep, i);
2354 do {
2355 x = (in_be32(mem_ctrl_sleep) >> 16) & 0x3ff;
2356 } while (x == 0);
2357 if (x >= 0x100)
2358 break;
2359 }
2360
2361 /* Ask the PMU to put us to sleep */
2362 pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
2363 while (!sleep_req.complete)
2364 mb();
2365
2366 pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,1);
2367
2368 /* displacement-flush the L2 cache - necessary? */
2369 for (p = KERNELBASE; p < KERNELBASE + 0x100000; p += 0x1000)
2370 i = *(volatile int *)p;
2371 asleep = 1;
2372
2373 /* Put the CPU into sleep mode */
Benjamin Herrenschmidt21fe3302005-11-07 16:41:59 +11002374 hid0 = mfspr(SPRN_HID0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375 hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP;
Benjamin Herrenschmidt21fe3302005-11-07 16:41:59 +11002376 mtspr(SPRN_HID0, hid0);
2377 mtmsr(mfmsr() | MSR_POW | MSR_EE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378 udelay(10);
2379
2380 /* OK, we're awake again, start restoring things */
2381 out_be32(mem_ctrl_sleep, 0x3f);
2382 pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0);
2383 pbook_pci_restore();
2384 pmu_unlock();
2385
2386 /* wait for the PMU interrupt sequence to complete */
2387 while (asleep)
2388 mb();
2389
2390 pmac_wakeup_devices();
2391 pbook_free_pci_save();
2392 iounmap(mem_ctrl);
2393
2394 return 0;
2395}
2396
Paul Mackerrasa0005032005-11-02 15:08:17 +11002397#endif /* CONFIG_PM && CONFIG_PPC32 */
Benjamin Herrenschmidt8c870932005-06-27 14:36:34 -07002398
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399/*
2400 * Support for /dev/pmu device
2401 */
2402#define RB_SIZE 0x10
2403struct pmu_private {
2404 struct list_head list;
2405 int rb_get;
2406 int rb_put;
2407 struct rb_entry {
2408 unsigned short len;
2409 unsigned char data[16];
2410 } rb_buf[RB_SIZE];
2411 wait_queue_head_t wait;
2412 spinlock_t lock;
2413#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
2414 int backlight_locker;
2415#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */
2416};
2417
2418static LIST_HEAD(all_pmu_pvt);
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05002419static DEFINE_SPINLOCK(all_pvt_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05002421static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422pmu_pass_intr(unsigned char *data, int len)
2423{
2424 struct pmu_private *pp;
2425 struct list_head *list;
2426 int i;
2427 unsigned long flags;
2428
2429 if (len > sizeof(pp->rb_buf[0].data))
2430 len = sizeof(pp->rb_buf[0].data);
2431 spin_lock_irqsave(&all_pvt_lock, flags);
2432 for (list = &all_pmu_pvt; (list = list->next) != &all_pmu_pvt; ) {
2433 pp = list_entry(list, struct pmu_private, list);
2434 spin_lock(&pp->lock);
2435 i = pp->rb_put + 1;
2436 if (i >= RB_SIZE)
2437 i = 0;
2438 if (i != pp->rb_get) {
2439 struct rb_entry *rp = &pp->rb_buf[pp->rb_put];
2440 rp->len = len;
2441 memcpy(rp->data, data, len);
2442 pp->rb_put = i;
2443 wake_up_interruptible(&pp->wait);
2444 }
2445 spin_unlock(&pp->lock);
2446 }
2447 spin_unlock_irqrestore(&all_pvt_lock, flags);
2448}
2449
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05002450static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451pmu_open(struct inode *inode, struct file *file)
2452{
2453 struct pmu_private *pp;
2454 unsigned long flags;
2455
2456 pp = kmalloc(sizeof(struct pmu_private), GFP_KERNEL);
2457 if (pp == 0)
2458 return -ENOMEM;
2459 pp->rb_get = pp->rb_put = 0;
2460 spin_lock_init(&pp->lock);
2461 init_waitqueue_head(&pp->wait);
2462 spin_lock_irqsave(&all_pvt_lock, flags);
2463#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
2464 pp->backlight_locker = 0;
2465#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */
2466 list_add(&pp->list, &all_pmu_pvt);
2467 spin_unlock_irqrestore(&all_pvt_lock, flags);
2468 file->private_data = pp;
2469 return 0;
2470}
2471
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05002472static ssize_t
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473pmu_read(struct file *file, char __user *buf,
2474 size_t count, loff_t *ppos)
2475{
2476 struct pmu_private *pp = file->private_data;
2477 DECLARE_WAITQUEUE(wait, current);
2478 unsigned long flags;
2479 int ret = 0;
2480
2481 if (count < 1 || pp == 0)
2482 return -EINVAL;
2483 if (!access_ok(VERIFY_WRITE, buf, count))
2484 return -EFAULT;
2485
2486 spin_lock_irqsave(&pp->lock, flags);
2487 add_wait_queue(&pp->wait, &wait);
2488 current->state = TASK_INTERRUPTIBLE;
2489
2490 for (;;) {
2491 ret = -EAGAIN;
2492 if (pp->rb_get != pp->rb_put) {
2493 int i = pp->rb_get;
2494 struct rb_entry *rp = &pp->rb_buf[i];
2495 ret = rp->len;
2496 spin_unlock_irqrestore(&pp->lock, flags);
2497 if (ret > count)
2498 ret = count;
2499 if (ret > 0 && copy_to_user(buf, rp->data, ret))
2500 ret = -EFAULT;
2501 if (++i >= RB_SIZE)
2502 i = 0;
2503 spin_lock_irqsave(&pp->lock, flags);
2504 pp->rb_get = i;
2505 }
2506 if (ret >= 0)
2507 break;
2508 if (file->f_flags & O_NONBLOCK)
2509 break;
2510 ret = -ERESTARTSYS;
2511 if (signal_pending(current))
2512 break;
2513 spin_unlock_irqrestore(&pp->lock, flags);
2514 schedule();
2515 spin_lock_irqsave(&pp->lock, flags);
2516 }
2517 current->state = TASK_RUNNING;
2518 remove_wait_queue(&pp->wait, &wait);
2519 spin_unlock_irqrestore(&pp->lock, flags);
2520
2521 return ret;
2522}
2523
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05002524static ssize_t
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525pmu_write(struct file *file, const char __user *buf,
2526 size_t count, loff_t *ppos)
2527{
2528 return 0;
2529}
2530
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05002531static unsigned int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532pmu_fpoll(struct file *filp, poll_table *wait)
2533{
2534 struct pmu_private *pp = filp->private_data;
2535 unsigned int mask = 0;
2536 unsigned long flags;
2537
2538 if (pp == 0)
2539 return 0;
2540 poll_wait(filp, &pp->wait, wait);
2541 spin_lock_irqsave(&pp->lock, flags);
2542 if (pp->rb_get != pp->rb_put)
2543 mask |= POLLIN;
2544 spin_unlock_irqrestore(&pp->lock, flags);
2545 return mask;
2546}
2547
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05002548static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549pmu_release(struct inode *inode, struct file *file)
2550{
2551 struct pmu_private *pp = file->private_data;
2552 unsigned long flags;
2553
2554 lock_kernel();
2555 if (pp != 0) {
2556 file->private_data = NULL;
2557 spin_lock_irqsave(&all_pvt_lock, flags);
2558 list_del(&pp->list);
2559 spin_unlock_irqrestore(&all_pvt_lock, flags);
2560#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
2561 if (pp->backlight_locker) {
2562 spin_lock_irqsave(&pmu_lock, flags);
2563 disable_kernel_backlight--;
2564 spin_unlock_irqrestore(&pmu_lock, flags);
2565 }
2566#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */
2567 kfree(pp);
2568 }
2569 unlock_kernel();
2570 return 0;
2571}
2572
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05002573static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574pmu_ioctl(struct inode * inode, struct file *filp,
2575 u_int cmd, u_long arg)
2576{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 __u32 __user *argp = (__u32 __user *)arg;
Benjamin Herrenschmidt8c870932005-06-27 14:36:34 -07002578 int error = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579
2580 switch (cmd) {
Paul Mackerrasa0005032005-11-02 15:08:17 +11002581#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 case PMU_IOC_SLEEP:
2583 if (!capable(CAP_SYS_ADMIN))
2584 return -EACCES;
2585 if (sleep_in_progress)
2586 return -EBUSY;
2587 sleep_in_progress = 1;
2588 switch (pmu_kind) {
2589 case PMU_OHARE_BASED:
2590 error = powerbook_sleep_3400();
2591 break;
2592 case PMU_HEATHROW_BASED:
2593 case PMU_PADDINGTON_BASED:
2594 error = powerbook_sleep_grackle();
2595 break;
2596 case PMU_KEYLARGO_BASED:
2597 error = powerbook_sleep_Core99();
2598 break;
2599 default:
2600 error = -ENOSYS;
2601 }
2602 sleep_in_progress = 0;
Benjamin Herrenschmidt8c870932005-06-27 14:36:34 -07002603 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 case PMU_IOC_CAN_SLEEP:
2605 if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) < 0)
2606 return put_user(0, argp);
2607 else
2608 return put_user(1, argp);
Paul Mackerrasa0005032005-11-02 15:08:17 +11002609#endif /* CONFIG_PM && CONFIG_PPC32 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610
Michael Hanselmann5474c122006-06-25 05:47:08 -07002611#ifdef CONFIG_PMAC_BACKLIGHT_LEGACY
2612 /* Compatibility ioctl's for backlight */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 case PMU_IOC_GET_BACKLIGHT:
Michael Hanselmann5474c122006-06-25 05:47:08 -07002614 {
2615 int brightness;
2616
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 if (sleep_in_progress)
2618 return -EBUSY;
Michael Hanselmann5474c122006-06-25 05:47:08 -07002619
2620 brightness = pmac_backlight_get_legacy_brightness();
2621 if (brightness < 0)
2622 return brightness;
2623 else
2624 return put_user(brightness, argp);
2625
2626 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 case PMU_IOC_SET_BACKLIGHT:
2628 {
Michael Hanselmann5474c122006-06-25 05:47:08 -07002629 int brightness;
2630
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 if (sleep_in_progress)
2632 return -EBUSY;
Michael Hanselmann5474c122006-06-25 05:47:08 -07002633
2634 error = get_user(brightness, argp);
2635 if (error)
2636 return error;
2637
2638 return pmac_backlight_set_legacy_brightness(brightness);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 }
2640#ifdef CONFIG_INPUT_ADBHID
2641 case PMU_IOC_GRAB_BACKLIGHT: {
Benjamin Herrenschmidt8c870932005-06-27 14:36:34 -07002642 struct pmu_private *pp = filp->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 unsigned long flags;
Benjamin Herrenschmidt8c870932005-06-27 14:36:34 -07002644
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 if (pp->backlight_locker)
2646 return 0;
2647 pp->backlight_locker = 1;
2648 spin_lock_irqsave(&pmu_lock, flags);
2649 disable_kernel_backlight++;
2650 spin_unlock_irqrestore(&pmu_lock, flags);
2651 return 0;
2652 }
2653#endif /* CONFIG_INPUT_ADBHID */
Michael Hanselmann5474c122006-06-25 05:47:08 -07002654#endif /* CONFIG_PMAC_BACKLIGHT_LEGACY */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 case PMU_IOC_GET_MODEL:
2656 return put_user(pmu_kind, argp);
2657 case PMU_IOC_HAS_ADB:
2658 return put_user(pmu_has_adb, argp);
2659 }
Benjamin Herrenschmidt8c870932005-06-27 14:36:34 -07002660 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661}
2662
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05002663static struct file_operations pmu_device_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 .read = pmu_read,
2665 .write = pmu_write,
2666 .poll = pmu_fpoll,
2667 .ioctl = pmu_ioctl,
2668 .open = pmu_open,
2669 .release = pmu_release,
2670};
2671
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05002672static struct miscdevice pmu_device = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 PMU_MINOR, "pmu", &pmu_device_fops
2674};
2675
Benjamin Herrenschmidt8c870932005-06-27 14:36:34 -07002676static int pmu_device_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677{
2678 if (!via)
Benjamin Herrenschmidt8c870932005-06-27 14:36:34 -07002679 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 if (misc_register(&pmu_device) < 0)
2681 printk(KERN_ERR "via-pmu: cannot register misc device.\n");
Benjamin Herrenschmidt8c870932005-06-27 14:36:34 -07002682 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683}
Benjamin Herrenschmidt8c870932005-06-27 14:36:34 -07002684device_initcall(pmu_device_init);
2685
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686
2687#ifdef DEBUG_SLEEP
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05002688static inline void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689polled_handshake(volatile unsigned char __iomem *via)
2690{
2691 via[B] &= ~TREQ; eieio();
2692 while ((via[B] & TACK) != 0)
2693 ;
2694 via[B] |= TREQ; eieio();
2695 while ((via[B] & TACK) == 0)
2696 ;
2697}
2698
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05002699static inline void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700polled_send_byte(volatile unsigned char __iomem *via, int x)
2701{
2702 via[ACR] |= SR_OUT | SR_EXT; eieio();
2703 via[SR] = x; eieio();
2704 polled_handshake(via);
2705}
2706
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05002707static inline int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708polled_recv_byte(volatile unsigned char __iomem *via)
2709{
2710 int x;
2711
2712 via[ACR] = (via[ACR] & ~SR_OUT) | SR_EXT; eieio();
2713 x = via[SR]; eieio();
2714 polled_handshake(via);
2715 x = via[SR]; eieio();
2716 return x;
2717}
2718
Jon Loeligeraacaf9b2005-09-17 10:36:54 -05002719int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720pmu_polled_request(struct adb_request *req)
2721{
2722 unsigned long flags;
2723 int i, l, c;
2724 volatile unsigned char __iomem *v = via;
2725
2726 req->complete = 1;
2727 c = req->data[0];
2728 l = pmu_data_len[c][0];
2729 if (l >= 0 && req->nbytes != l + 1)
2730 return -EINVAL;
2731
2732 local_irq_save(flags);
2733 while (pmu_state != idle)
2734 pmu_poll();
2735
2736 while ((via[B] & TACK) == 0)
2737 ;
2738 polled_send_byte(v, c);
2739 if (l < 0) {
2740 l = req->nbytes - 1;
2741 polled_send_byte(v, l);
2742 }
2743 for (i = 1; i <= l; ++i)
2744 polled_send_byte(v, req->data[i]);
2745
2746 l = pmu_data_len[c][1];
2747 if (l < 0)
2748 l = polled_recv_byte(v);
2749 for (i = 0; i < l; ++i)
2750 req->reply[i + req->reply_len] = polled_recv_byte(v);
2751
2752 if (req->done)
2753 (*req->done)(req);
2754
2755 local_irq_restore(flags);
2756 return 0;
2757}
2758#endif /* DEBUG_SLEEP */
2759
2760
2761/* FIXME: This is a temporary set of callbacks to enable us
2762 * to do suspend-to-disk.
2763 */
2764
Paul Mackerrasa0005032005-11-02 15:08:17 +11002765#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766
2767static int pmu_sys_suspended = 0;
2768
Pavel Machek3bfffd92005-04-16 15:25:37 -07002769static int pmu_sys_suspend(struct sys_device *sysdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770{
Pavel Machekca078ba2005-09-03 15:56:57 -07002771 if (state.event != PM_EVENT_SUSPEND || pmu_sys_suspended)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 return 0;
2773
2774 /* Suspend PMU event interrupts */
2775 pmu_suspend();
2776
2777 pmu_sys_suspended = 1;
2778 return 0;
2779}
2780
2781static int pmu_sys_resume(struct sys_device *sysdev)
2782{
2783 struct adb_request req;
2784
2785 if (!pmu_sys_suspended)
2786 return 0;
2787
2788 /* Tell PMU we are ready */
2789 pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2);
2790 pmu_wait_complete(&req);
2791
2792 /* Resume PMU event interrupts */
2793 pmu_resume();
2794
2795 pmu_sys_suspended = 0;
2796
2797 return 0;
2798}
2799
Paul Mackerrasa0005032005-11-02 15:08:17 +11002800#endif /* CONFIG_PM && CONFIG_PPC32 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801
2802static struct sysdev_class pmu_sysclass = {
2803 set_kset_name("pmu"),
2804};
2805
2806static struct sys_device device_pmu = {
2807 .id = 0,
2808 .cls = &pmu_sysclass,
2809};
2810
2811static struct sysdev_driver driver_pmu = {
Paul Mackerrasa0005032005-11-02 15:08:17 +11002812#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 .suspend = &pmu_sys_suspend,
2814 .resume = &pmu_sys_resume,
Paul Mackerrasa0005032005-11-02 15:08:17 +11002815#endif /* CONFIG_PM && CONFIG_PPC32 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816};
2817
2818static int __init init_pmu_sysfs(void)
2819{
2820 int rc;
2821
2822 rc = sysdev_class_register(&pmu_sysclass);
2823 if (rc) {
2824 printk(KERN_ERR "Failed registering PMU sys class\n");
2825 return -ENODEV;
2826 }
2827 rc = sysdev_register(&device_pmu);
2828 if (rc) {
2829 printk(KERN_ERR "Failed registering PMU sys device\n");
2830 return -ENODEV;
2831 }
2832 rc = sysdev_driver_register(&pmu_sysclass, &driver_pmu);
2833 if (rc) {
2834 printk(KERN_ERR "Failed registering PMU sys driver\n");
2835 return -ENODEV;
2836 }
2837 return 0;
2838}
2839
2840subsys_initcall(init_pmu_sysfs);
2841
2842EXPORT_SYMBOL(pmu_request);
Benjamin Herrenschmidt730745a2006-01-07 11:30:44 +11002843EXPORT_SYMBOL(pmu_queue_request);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844EXPORT_SYMBOL(pmu_poll);
2845EXPORT_SYMBOL(pmu_poll_adb);
2846EXPORT_SYMBOL(pmu_wait_complete);
2847EXPORT_SYMBOL(pmu_suspend);
2848EXPORT_SYMBOL(pmu_resume);
2849EXPORT_SYMBOL(pmu_unlock);
Paul Mackerrasa0005032005-11-02 15:08:17 +11002850#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851EXPORT_SYMBOL(pmu_enable_irled);
2852EXPORT_SYMBOL(pmu_battery_count);
2853EXPORT_SYMBOL(pmu_batteries);
2854EXPORT_SYMBOL(pmu_power_flags);
Paul Mackerrasa0005032005-11-02 15:08:17 +11002855#endif /* CONFIG_PM && CONFIG_PPC32 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856