X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fmacintosh%2Fvia-pmu.c;fp=drivers%2Fmacintosh%2Fvia-pmu.c;h=b941ee220997adbc96b50b48862d0e47c687afda;hb=f7f1b0f1e2fbadeab12d24236000e778aa9b1ead;hp=019f4c4e3a9410f16d94832af0181024c2c89451;hpb=e3f6fb6212a7102bdb56ba38fa1e98fe72950475;p=linux-2.6.git diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 019f4c4e3..b941ee220 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -367,9 +368,7 @@ find_via_pmu(void) printk(KERN_INFO "PMU driver %d initialized for %s, firmware: %02x\n", PMU_DRIVER_VERSION, pbook_type[pmu_kind], pmu_version); -#ifndef CONFIG_PPC64 sys_ctrler = SYS_CTRLER_PMU; -#endif return 1; } @@ -1745,6 +1744,9 @@ pmu_restart(void) { struct adb_request req; + if (via == NULL) + return; + local_irq_disable(); drop_interrupts = 1; @@ -1767,6 +1769,9 @@ pmu_shutdown(void) { struct adb_request req; + if (via == NULL) + return; + local_irq_disable(); drop_interrupts = 1; @@ -2326,7 +2331,7 @@ pmac_suspend_devices(void) /* Sync the disks. */ /* XXX It would be nice to have some way to ensure that * nobody is dirtying any new buffers while we wait. That - * could be acheived using the refrigerator for processes + * could be achieved using the refrigerator for processes * that swsusp uses */ sys_sync(); @@ -2339,13 +2344,17 @@ pmac_suspend_devices(void) } /* Send suspend call to devices, hold the device core's dpm_sem */ - ret = device_suspend(PM_SUSPEND_MEM); + ret = device_suspend(PMSG_SUSPEND); if (ret) { broadcast_wake(); printk(KERN_ERR "Driver sleep failed\n"); return -EBUSY; } + /* Disable clock spreading on some machines */ + pmac_tweak_clock_spreading(0); + + /* Stop preemption */ preempt_disable(); /* Make sure the decrementer won't interrupt us */ @@ -2366,7 +2375,7 @@ pmac_suspend_devices(void) * use this but still... This will take care of sysdev's as well, so * we exit from here with local irqs disabled and PIC off. */ - ret = device_power_down(PM_SUSPEND_MEM); + ret = device_power_down(PMSG_SUSPEND); if (ret) { wakeup_decrementer(); local_irq_enable(); @@ -2379,7 +2388,6 @@ pmac_suspend_devices(void) /* Wait for completion of async backlight requests */ while (!bright_req_1.complete || !bright_req_2.complete || - !batt_req.complete) pmu_poll(); @@ -2389,7 +2397,7 @@ pmac_suspend_devices(void) enable_kernel_fp(); #ifdef CONFIG_ALTIVEC - if (cur_cpu_spec[0]->cpu_features & CPU_FTR_ALTIVEC) + if (cpu_has_feature(CPU_FTR_ALTIVEC)) enable_kernel_altivec(); #endif /* CONFIG_ALTIVEC */ @@ -2413,11 +2421,12 @@ pmac_wakeup_devices(void) /* Re-enable local CPU interrupts */ local_irq_enable(); - - mdelay(100); - + mdelay(10); preempt_enable(); + /* Re-enable clock spreading on some machines */ + pmac_tweak_clock_spreading(1); + /* Resume devices */ device_resume(); @@ -2540,7 +2549,9 @@ powerbook_sleep_Core99(void) return ret; } - printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1)); + /* Stop environment and ADB interrupts */ + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0); + pmu_wait_complete(&req); /* Tell PMU what events will wake us up */ pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_CLR_WAKEUP_EVENTS, @@ -2582,6 +2593,9 @@ powerbook_sleep_Core99(void) /* Restore VIA */ restore_via_state(); + /* tweak LPJ before cpufreq is there */ + loops_per_jiffy *= 2; + /* Restore video */ pmac_call_early_video_resume(); @@ -2602,7 +2616,8 @@ powerbook_sleep_Core99(void) pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask); pmu_wait_complete(&req); - printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1)); + /* Restore LPJ, cpufreq will adjust the cpu frequency */ + loops_per_jiffy /= 2; pmac_wakeup_devices(); @@ -2770,13 +2785,12 @@ pmu_read(struct file *file, char __user *buf, struct pmu_private *pp = file->private_data; DECLARE_WAITQUEUE(wait, current); unsigned long flags; - int ret; + int ret = 0; if (count < 1 || pp == 0) return -EINVAL; - ret = verify_area(VERIFY_WRITE, buf, count); - if (ret) - return ret; + if (!access_ok(VERIFY_WRITE, buf, count)) + return -EFAULT; spin_lock_irqsave(&pp->lock, flags); add_wait_queue(&pp->wait, &wait); @@ -3040,6 +3054,88 @@ pmu_polled_request(struct adb_request *req) } #endif /* DEBUG_SLEEP */ + +/* FIXME: This is a temporary set of callbacks to enable us + * to do suspend-to-disk. + */ + +#ifdef CONFIG_PM + +static int pmu_sys_suspended = 0; + +static int pmu_sys_suspend(struct sys_device *sysdev, pm_message_t state) +{ + if (state != PM_SUSPEND_DISK || pmu_sys_suspended) + return 0; + + /* Suspend PMU event interrupts */ + pmu_suspend(); + + pmu_sys_suspended = 1; + return 0; +} + +static int pmu_sys_resume(struct sys_device *sysdev) +{ + struct adb_request req; + + if (!pmu_sys_suspended) + return 0; + + /* Tell PMU we are ready */ + pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2); + pmu_wait_complete(&req); + + /* Resume PMU event interrupts */ + pmu_resume(); + + pmu_sys_suspended = 0; + + return 0; +} + +#endif /* CONFIG_PM */ + +static struct sysdev_class pmu_sysclass = { + set_kset_name("pmu"), +}; + +static struct sys_device device_pmu = { + .id = 0, + .cls = &pmu_sysclass, +}; + +static struct sysdev_driver driver_pmu = { +#ifdef CONFIG_PM + .suspend = &pmu_sys_suspend, + .resume = &pmu_sys_resume, +#endif /* CONFIG_PM */ +}; + +static int __init init_pmu_sysfs(void) +{ + int rc; + + rc = sysdev_class_register(&pmu_sysclass); + if (rc) { + printk(KERN_ERR "Failed registering PMU sys class\n"); + return -ENODEV; + } + rc = sysdev_register(&device_pmu); + if (rc) { + printk(KERN_ERR "Failed registering PMU sys device\n"); + return -ENODEV; + } + rc = sysdev_driver_register(&pmu_sysclass, &driver_pmu); + if (rc) { + printk(KERN_ERR "Failed registering PMU sys driver\n"); + return -ENODEV; + } + return 0; +} + +subsys_initcall(init_pmu_sysfs); + EXPORT_SYMBOL(pmu_request); EXPORT_SYMBOL(pmu_poll); EXPORT_SYMBOL(pmu_poll_adb);