diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2007-12-11 09:25:59 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-12-19 07:02:35 -0500 |
commit | f91266edba3c6ef001819c5abe4c3a0643f66fc9 (patch) | |
tree | 9ca84ad4550288c3b467dea7197b935c345755d7 /drivers/macintosh/via-pmu.c | |
parent | 887ef35ae4eb269839e0f296b132edc15477db1c (diff) |
[POWERPC] powermac: Use generic suspend code
This adds platform_suspend_ops for PMU based machines, directly in
the PMU driver. This allows suspending via /sys/power/state
on powerbooks.
The patch also replaces the PMU ioctl with a simple call to
pm_suspend(PM_SUSPEND_MEM).
Additionally, it cleans up some debug code.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'drivers/macintosh/via-pmu.c')
-rw-r--r-- | drivers/macintosh/via-pmu.c | 405 |
1 files changed, 173 insertions, 232 deletions
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 0e233185ad14..8f98257e6a15 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c | |||
@@ -10,13 +10,11 @@ | |||
10 | * | 10 | * |
11 | * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi. | 11 | * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi. |
12 | * Copyright (C) 2001-2002 Benjamin Herrenschmidt | 12 | * Copyright (C) 2001-2002 Benjamin Herrenschmidt |
13 | * Copyright (C) 2006-2007 Johannes Berg | ||
13 | * | 14 | * |
14 | * THIS DRIVER IS BECOMING A TOTAL MESS ! | 15 | * THIS DRIVER IS BECOMING A TOTAL MESS ! |
15 | * - Cleanup atomically disabling reply to PMU events after | 16 | * - Cleanup atomically disabling reply to PMU events after |
16 | * a sleep or a freq. switch | 17 | * a sleep or a freq. switch |
17 | * - Move sleep code out of here to pmac_pm, merge into new | ||
18 | * common PM infrastructure | ||
19 | * - Save/Restore PCI space properly | ||
20 | * | 18 | * |
21 | */ | 19 | */ |
22 | #include <stdarg.h> | 20 | #include <stdarg.h> |
@@ -64,7 +62,7 @@ | |||
64 | #include "via-pmu-event.h" | 62 | #include "via-pmu-event.h" |
65 | 63 | ||
66 | /* Some compile options */ | 64 | /* Some compile options */ |
67 | #define DEBUG_SLEEP | 65 | #undef DEBUG_SLEEP |
68 | 66 | ||
69 | /* Misc minor number allocated for /dev/pmu */ | 67 | /* Misc minor number allocated for /dev/pmu */ |
70 | #define PMU_MINOR 154 | 68 | #define PMU_MINOR 154 |
@@ -149,12 +147,9 @@ static spinlock_t pmu_lock; | |||
149 | static u8 pmu_intr_mask; | 147 | static u8 pmu_intr_mask; |
150 | static int pmu_version; | 148 | static int pmu_version; |
151 | static int drop_interrupts; | 149 | static int drop_interrupts; |
152 | #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32) | 150 | #if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32) |
153 | static int option_lid_wakeup = 1; | 151 | static int option_lid_wakeup = 1; |
154 | #endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */ | 152 | #endif /* CONFIG_SUSPEND && CONFIG_PPC32 */ |
155 | #if (defined(CONFIG_PM_SLEEP)&&defined(CONFIG_PPC32))||defined(CONFIG_PMAC_BACKLIGHT_LEGACY) | ||
156 | static int sleep_in_progress; | ||
157 | #endif | ||
158 | static unsigned long async_req_locks; | 153 | static unsigned long async_req_locks; |
159 | static unsigned int pmu_irq_stats[11]; | 154 | static unsigned int pmu_irq_stats[11]; |
160 | 155 | ||
@@ -226,7 +221,7 @@ extern void enable_kernel_fp(void); | |||
226 | 221 | ||
227 | #ifdef DEBUG_SLEEP | 222 | #ifdef DEBUG_SLEEP |
228 | int pmu_polled_request(struct adb_request *req); | 223 | int pmu_polled_request(struct adb_request *req); |
229 | int pmu_wink(struct adb_request *req); | 224 | void pmu_blink(int n); |
230 | #endif | 225 | #endif |
231 | 226 | ||
232 | /* | 227 | /* |
@@ -881,7 +876,7 @@ proc_read_options(char *page, char **start, off_t off, | |||
881 | { | 876 | { |
882 | char *p = page; | 877 | char *p = page; |
883 | 878 | ||
884 | #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32) | 879 | #if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32) |
885 | if (pmu_kind == PMU_KEYLARGO_BASED && | 880 | if (pmu_kind == PMU_KEYLARGO_BASED && |
886 | pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0) | 881 | pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0) |
887 | p += sprintf(p, "lid_wakeup=%d\n", option_lid_wakeup); | 882 | p += sprintf(p, "lid_wakeup=%d\n", option_lid_wakeup); |
@@ -922,7 +917,7 @@ proc_write_options(struct file *file, const char __user *buffer, | |||
922 | *(val++) = 0; | 917 | *(val++) = 0; |
923 | while(*val == ' ') | 918 | while(*val == ' ') |
924 | val++; | 919 | val++; |
925 | #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32) | 920 | #if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32) |
926 | if (pmu_kind == PMU_KEYLARGO_BASED && | 921 | if (pmu_kind == PMU_KEYLARGO_BASED && |
927 | pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0) | 922 | pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0) |
928 | if (!strcmp(label, "lid_wakeup")) | 923 | if (!strcmp(label, "lid_wakeup")) |
@@ -1728,44 +1723,7 @@ pmu_present(void) | |||
1728 | return via != 0; | 1723 | return via != 0; |
1729 | } | 1724 | } |
1730 | 1725 | ||
1731 | #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32) | 1726 | #if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32) |
1732 | #ifdef DEBUG_SLEEP | ||
1733 | /* N.B. This doesn't work on the 3400 */ | ||
1734 | void | ||
1735 | pmu_blink(int n) | ||
1736 | { | ||
1737 | struct adb_request req; | ||
1738 | |||
1739 | memset(&req, 0, sizeof(req)); | ||
1740 | |||
1741 | for (; n > 0; --n) { | ||
1742 | req.nbytes = 4; | ||
1743 | req.done = NULL; | ||
1744 | req.data[0] = 0xee; | ||
1745 | req.data[1] = 4; | ||
1746 | req.data[2] = 0; | ||
1747 | req.data[3] = 1; | ||
1748 | req.reply[0] = ADB_RET_OK; | ||
1749 | req.reply_len = 1; | ||
1750 | req.reply_expected = 0; | ||
1751 | pmu_polled_request(&req); | ||
1752 | mdelay(50); | ||
1753 | req.nbytes = 4; | ||
1754 | req.done = NULL; | ||
1755 | req.data[0] = 0xee; | ||
1756 | req.data[1] = 4; | ||
1757 | req.data[2] = 0; | ||
1758 | req.data[3] = 0; | ||
1759 | req.reply[0] = ADB_RET_OK; | ||
1760 | req.reply_len = 1; | ||
1761 | req.reply_expected = 0; | ||
1762 | pmu_polled_request(&req); | ||
1763 | mdelay(50); | ||
1764 | } | ||
1765 | mdelay(50); | ||
1766 | } | ||
1767 | #endif | ||
1768 | |||
1769 | /* | 1727 | /* |
1770 | * Put the powerbook to sleep. | 1728 | * Put the powerbook to sleep. |
1771 | */ | 1729 | */ |
@@ -1802,122 +1760,6 @@ restore_via_state(void) | |||
1802 | 1760 | ||
1803 | extern void pmu_backlight_set_sleep(int sleep); | 1761 | extern void pmu_backlight_set_sleep(int sleep); |
1804 | 1762 | ||
1805 | static int | ||
1806 | pmac_suspend_devices(void) | ||
1807 | { | ||
1808 | int ret; | ||
1809 | |||
1810 | pm_prepare_console(); | ||
1811 | |||
1812 | /* Sync the disks. */ | ||
1813 | /* XXX It would be nice to have some way to ensure that | ||
1814 | * nobody is dirtying any new buffers while we wait. That | ||
1815 | * could be achieved using the refrigerator for processes | ||
1816 | * that swsusp uses | ||
1817 | */ | ||
1818 | sys_sync(); | ||
1819 | |||
1820 | /* Send suspend call to devices, hold the device core's dpm_sem */ | ||
1821 | ret = device_suspend(PMSG_SUSPEND); | ||
1822 | if (ret) { | ||
1823 | printk(KERN_ERR "Driver sleep failed\n"); | ||
1824 | return -EBUSY; | ||
1825 | } | ||
1826 | |||
1827 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
1828 | /* Tell backlight code not to muck around with the chip anymore */ | ||
1829 | pmu_backlight_set_sleep(1); | ||
1830 | #endif | ||
1831 | |||
1832 | /* Call platform functions marked "on sleep" */ | ||
1833 | pmac_pfunc_i2c_suspend(); | ||
1834 | pmac_pfunc_base_suspend(); | ||
1835 | |||
1836 | /* Stop preemption */ | ||
1837 | preempt_disable(); | ||
1838 | |||
1839 | /* Make sure the decrementer won't interrupt us */ | ||
1840 | asm volatile("mtdec %0" : : "r" (0x7fffffff)); | ||
1841 | /* Make sure any pending DEC interrupt occurring while we did | ||
1842 | * the above didn't re-enable the DEC */ | ||
1843 | mb(); | ||
1844 | asm volatile("mtdec %0" : : "r" (0x7fffffff)); | ||
1845 | |||
1846 | /* We can now disable MSR_EE. This code of course works properly only | ||
1847 | * on UP machines... For SMP, if we ever implement sleep, we'll have to | ||
1848 | * stop the "other" CPUs way before we do all that stuff. | ||
1849 | */ | ||
1850 | local_irq_disable(); | ||
1851 | |||
1852 | /* Broadcast power down irq | ||
1853 | * This isn't that useful in most cases (only directly wired devices can | ||
1854 | * use this but still... This will take care of sysdev's as well, so | ||
1855 | * we exit from here with local irqs disabled and PIC off. | ||
1856 | */ | ||
1857 | ret = device_power_down(PMSG_SUSPEND); | ||
1858 | if (ret) { | ||
1859 | wakeup_decrementer(); | ||
1860 | local_irq_enable(); | ||
1861 | preempt_enable(); | ||
1862 | device_resume(); | ||
1863 | printk(KERN_ERR "Driver powerdown failed\n"); | ||
1864 | return -EBUSY; | ||
1865 | } | ||
1866 | |||
1867 | /* Wait for completion of async requests */ | ||
1868 | while (!batt_req.complete) | ||
1869 | pmu_poll(); | ||
1870 | |||
1871 | /* Giveup the lazy FPU & vec so we don't have to back them | ||
1872 | * up from the low level code | ||
1873 | */ | ||
1874 | enable_kernel_fp(); | ||
1875 | |||
1876 | #ifdef CONFIG_ALTIVEC | ||
1877 | if (cpu_has_feature(CPU_FTR_ALTIVEC)) | ||
1878 | enable_kernel_altivec(); | ||
1879 | #endif /* CONFIG_ALTIVEC */ | ||
1880 | |||
1881 | return 0; | ||
1882 | } | ||
1883 | |||
1884 | static int | ||
1885 | pmac_wakeup_devices(void) | ||
1886 | { | ||
1887 | mdelay(100); | ||
1888 | |||
1889 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
1890 | /* Tell backlight code it can use the chip again */ | ||
1891 | pmu_backlight_set_sleep(0); | ||
1892 | #endif | ||
1893 | |||
1894 | /* Power back up system devices (including the PIC) */ | ||
1895 | device_power_up(); | ||
1896 | |||
1897 | /* Force a poll of ADB interrupts */ | ||
1898 | adb_int_pending = 1; | ||
1899 | via_pmu_interrupt(0, NULL); | ||
1900 | |||
1901 | /* Restart jiffies & scheduling */ | ||
1902 | wakeup_decrementer(); | ||
1903 | |||
1904 | /* Re-enable local CPU interrupts */ | ||
1905 | local_irq_enable(); | ||
1906 | mdelay(10); | ||
1907 | preempt_enable(); | ||
1908 | |||
1909 | /* Call platform functions marked "on wake" */ | ||
1910 | pmac_pfunc_base_resume(); | ||
1911 | pmac_pfunc_i2c_resume(); | ||
1912 | |||
1913 | /* Resume devices */ | ||
1914 | device_resume(); | ||
1915 | |||
1916 | pm_restore_console(); | ||
1917 | |||
1918 | return 0; | ||
1919 | } | ||
1920 | |||
1921 | #define GRACKLE_PM (1<<7) | 1763 | #define GRACKLE_PM (1<<7) |
1922 | #define GRACKLE_DOZE (1<<5) | 1764 | #define GRACKLE_DOZE (1<<5) |
1923 | #define GRACKLE_NAP (1<<4) | 1765 | #define GRACKLE_NAP (1<<4) |
@@ -1928,19 +1770,12 @@ static int powerbook_sleep_grackle(void) | |||
1928 | unsigned long save_l2cr; | 1770 | unsigned long save_l2cr; |
1929 | unsigned short pmcr1; | 1771 | unsigned short pmcr1; |
1930 | struct adb_request req; | 1772 | struct adb_request req; |
1931 | int ret; | ||
1932 | struct pci_dev *grackle; | 1773 | struct pci_dev *grackle; |
1933 | 1774 | ||
1934 | grackle = pci_get_bus_and_slot(0, 0); | 1775 | grackle = pci_get_bus_and_slot(0, 0); |
1935 | if (!grackle) | 1776 | if (!grackle) |
1936 | return -ENODEV; | 1777 | return -ENODEV; |
1937 | 1778 | ||
1938 | ret = pmac_suspend_devices(); | ||
1939 | if (ret) { | ||
1940 | printk(KERN_ERR "Sleep rejected by devices\n"); | ||
1941 | return ret; | ||
1942 | } | ||
1943 | |||
1944 | /* Turn off various things. Darwin does some retry tests here... */ | 1779 | /* Turn off various things. Darwin does some retry tests here... */ |
1945 | pmu_request(&req, NULL, 2, PMU_POWER_CTRL0, PMU_POW0_OFF|PMU_POW0_HARD_DRIVE); | 1780 | pmu_request(&req, NULL, 2, PMU_POWER_CTRL0, PMU_POW0_OFF|PMU_POW0_HARD_DRIVE); |
1946 | pmu_wait_complete(&req); | 1781 | pmu_wait_complete(&req); |
@@ -2003,8 +1838,6 @@ static int powerbook_sleep_grackle(void) | |||
2003 | PMU_POW_ON|PMU_POW_BACKLIGHT|PMU_POW_CHARGER|PMU_POW_IRLED|PMU_POW_MEDIABAY); | 1838 | PMU_POW_ON|PMU_POW_BACKLIGHT|PMU_POW_CHARGER|PMU_POW_IRLED|PMU_POW_MEDIABAY); |
2004 | pmu_wait_complete(&req); | 1839 | pmu_wait_complete(&req); |
2005 | 1840 | ||
2006 | pmac_wakeup_devices(); | ||
2007 | |||
2008 | return 0; | 1841 | return 0; |
2009 | } | 1842 | } |
2010 | 1843 | ||
@@ -2014,7 +1847,6 @@ powerbook_sleep_Core99(void) | |||
2014 | unsigned long save_l2cr; | 1847 | unsigned long save_l2cr; |
2015 | unsigned long save_l3cr; | 1848 | unsigned long save_l3cr; |
2016 | struct adb_request req; | 1849 | struct adb_request req; |
2017 | int ret; | ||
2018 | 1850 | ||
2019 | if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) < 0) { | 1851 | if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) < 0) { |
2020 | printk(KERN_ERR "Sleep mode not supported on this machine\n"); | 1852 | printk(KERN_ERR "Sleep mode not supported on this machine\n"); |
@@ -2024,12 +1856,6 @@ powerbook_sleep_Core99(void) | |||
2024 | if (num_online_cpus() > 1 || cpu_is_offline(0)) | 1856 | if (num_online_cpus() > 1 || cpu_is_offline(0)) |
2025 | return -EAGAIN; | 1857 | return -EAGAIN; |
2026 | 1858 | ||
2027 | ret = pmac_suspend_devices(); | ||
2028 | if (ret) { | ||
2029 | printk(KERN_ERR "Sleep rejected by devices\n"); | ||
2030 | return ret; | ||
2031 | } | ||
2032 | |||
2033 | /* Stop environment and ADB interrupts */ | 1859 | /* Stop environment and ADB interrupts */ |
2034 | pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0); | 1860 | pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0); |
2035 | pmu_wait_complete(&req); | 1861 | pmu_wait_complete(&req); |
@@ -2100,8 +1926,6 @@ powerbook_sleep_Core99(void) | |||
2100 | /* Restore LPJ, cpufreq will adjust the cpu frequency */ | 1926 | /* Restore LPJ, cpufreq will adjust the cpu frequency */ |
2101 | loops_per_jiffy /= 2; | 1927 | loops_per_jiffy /= 2; |
2102 | 1928 | ||
2103 | pmac_wakeup_devices(); | ||
2104 | |||
2105 | return 0; | 1929 | return 0; |
2106 | } | 1930 | } |
2107 | 1931 | ||
@@ -2120,7 +1944,7 @@ static void powerbook_sleep_init_3400(void) | |||
2120 | 1944 | ||
2121 | static int powerbook_sleep_3400(void) | 1945 | static int powerbook_sleep_3400(void) |
2122 | { | 1946 | { |
2123 | int ret, i, x; | 1947 | int i, x; |
2124 | unsigned int hid0; | 1948 | unsigned int hid0; |
2125 | unsigned long msr; | 1949 | unsigned long msr; |
2126 | struct adb_request sleep_req; | 1950 | struct adb_request sleep_req; |
@@ -2130,12 +1954,6 @@ static int powerbook_sleep_3400(void) | |||
2130 | return -ENOMEM; | 1954 | return -ENOMEM; |
2131 | mem_ctrl_sleep = pb3400_mem_ctrl + PB3400_MEM_CTRL_SLEEP; | 1955 | mem_ctrl_sleep = pb3400_mem_ctrl + PB3400_MEM_CTRL_SLEEP; |
2132 | 1956 | ||
2133 | ret = pmac_suspend_devices(); | ||
2134 | if (ret) { | ||
2135 | printk(KERN_ERR "Sleep rejected by devices\n"); | ||
2136 | return ret; | ||
2137 | } | ||
2138 | |||
2139 | /* Set the memory controller to keep the memory refreshed | 1957 | /* Set the memory controller to keep the memory refreshed |
2140 | while we're asleep */ | 1958 | while we're asleep */ |
2141 | for (i = 0x403f; i >= 0x4000; --i) { | 1959 | for (i = 0x403f; i >= 0x4000; --i) { |
@@ -2173,12 +1991,10 @@ static int powerbook_sleep_3400(void) | |||
2173 | out_be32(mem_ctrl_sleep, 0x3f); | 1991 | out_be32(mem_ctrl_sleep, 0x3f); |
2174 | pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, 0); | 1992 | pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, 0); |
2175 | 1993 | ||
2176 | pmac_wakeup_devices(); | ||
2177 | |||
2178 | return 0; | 1994 | return 0; |
2179 | } | 1995 | } |
2180 | 1996 | ||
2181 | #endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */ | 1997 | #endif /* CONFIG_SUSPEND && CONFIG_PPC32 */ |
2182 | 1998 | ||
2183 | /* | 1999 | /* |
2184 | * Support for /dev/pmu device | 2000 | * Support for /dev/pmu device |
@@ -2351,6 +2167,129 @@ pmu_release(struct inode *inode, struct file *file) | |||
2351 | return 0; | 2167 | return 0; |
2352 | } | 2168 | } |
2353 | 2169 | ||
2170 | #if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32) | ||
2171 | /* | ||
2172 | * overrides the weak arch_suspend_disable_irqs in kernel/power/main.c | ||
2173 | * | ||
2174 | * XXX: Once Scott Wood's patch is merged, this needs to use the ppc_md | ||
2175 | * hooks that patch adds! | ||
2176 | */ | ||
2177 | void arch_suspend_disable_irqs(void) | ||
2178 | { | ||
2179 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
2180 | /* Tell backlight code not to muck around with the chip anymore */ | ||
2181 | pmu_backlight_set_sleep(1); | ||
2182 | #endif | ||
2183 | |||
2184 | /* Call platform functions marked "on sleep" */ | ||
2185 | pmac_pfunc_i2c_suspend(); | ||
2186 | pmac_pfunc_base_suspend(); | ||
2187 | |||
2188 | /* Stop preemption */ | ||
2189 | preempt_disable(); | ||
2190 | |||
2191 | /* Make sure the decrementer won't interrupt us */ | ||
2192 | asm volatile("mtdec %0" : : "r" (0x7fffffff)); | ||
2193 | /* Make sure any pending DEC interrupt occurring while we did | ||
2194 | * the above didn't re-enable the DEC */ | ||
2195 | mb(); | ||
2196 | asm volatile("mtdec %0" : : "r" (0x7fffffff)); | ||
2197 | |||
2198 | local_irq_disable(); | ||
2199 | } | ||
2200 | |||
2201 | static int powerbook_sleep(suspend_state_t state) | ||
2202 | { | ||
2203 | int error = 0; | ||
2204 | |||
2205 | /* Wait for completion of async requests */ | ||
2206 | while (!batt_req.complete) | ||
2207 | pmu_poll(); | ||
2208 | |||
2209 | /* Giveup the lazy FPU & vec so we don't have to back them | ||
2210 | * up from the low level code | ||
2211 | */ | ||
2212 | enable_kernel_fp(); | ||
2213 | |||
2214 | #ifdef CONFIG_ALTIVEC | ||
2215 | if (cpu_has_feature(CPU_FTR_ALTIVEC)) | ||
2216 | enable_kernel_altivec(); | ||
2217 | #endif /* CONFIG_ALTIVEC */ | ||
2218 | |||
2219 | switch (pmu_kind) { | ||
2220 | case PMU_OHARE_BASED: | ||
2221 | error = powerbook_sleep_3400(); | ||
2222 | break; | ||
2223 | case PMU_HEATHROW_BASED: | ||
2224 | case PMU_PADDINGTON_BASED: | ||
2225 | error = powerbook_sleep_grackle(); | ||
2226 | break; | ||
2227 | case PMU_KEYLARGO_BASED: | ||
2228 | error = powerbook_sleep_Core99(); | ||
2229 | break; | ||
2230 | default: | ||
2231 | return -ENOSYS; | ||
2232 | } | ||
2233 | |||
2234 | if (error) | ||
2235 | return error; | ||
2236 | |||
2237 | mdelay(100); | ||
2238 | |||
2239 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
2240 | /* Tell backlight code it can use the chip again */ | ||
2241 | pmu_backlight_set_sleep(0); | ||
2242 | #endif | ||
2243 | |||
2244 | return 0; | ||
2245 | } | ||
2246 | |||
2247 | /* | ||
2248 | * overrides the weak arch_suspend_enable_irqs in kernel/power/main.c | ||
2249 | * | ||
2250 | * XXX: Once Scott Wood's patch is merged, this needs to use the ppc_md | ||
2251 | * hooks that patch adds! | ||
2252 | */ | ||
2253 | void arch_suspend_enable_irqs(void) | ||
2254 | { | ||
2255 | /* Force a poll of ADB interrupts */ | ||
2256 | adb_int_pending = 1; | ||
2257 | via_pmu_interrupt(0, NULL); | ||
2258 | |||
2259 | /* Restart jiffies & scheduling */ | ||
2260 | wakeup_decrementer(); | ||
2261 | |||
2262 | /* Re-enable local CPU interrupts */ | ||
2263 | local_irq_enable(); | ||
2264 | mdelay(10); | ||
2265 | preempt_enable(); | ||
2266 | |||
2267 | /* Call platform functions marked "on wake" */ | ||
2268 | pmac_pfunc_base_resume(); | ||
2269 | pmac_pfunc_i2c_resume(); | ||
2270 | } | ||
2271 | |||
2272 | static int pmu_sleep_valid(suspend_state_t state) | ||
2273 | { | ||
2274 | return state == PM_SUSPEND_MEM | ||
2275 | && (pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, -1) >= 0); | ||
2276 | } | ||
2277 | |||
2278 | static struct platform_suspend_ops pmu_pm_ops = { | ||
2279 | .enter = powerbook_sleep, | ||
2280 | .valid = pmu_sleep_valid, | ||
2281 | }; | ||
2282 | |||
2283 | static int register_pmu_pm_ops(void) | ||
2284 | { | ||
2285 | suspend_set_ops(&pmu_pm_ops); | ||
2286 | |||
2287 | return 0; | ||
2288 | } | ||
2289 | |||
2290 | device_initcall(register_pmu_pm_ops); | ||
2291 | #endif | ||
2292 | |||
2354 | static int | 2293 | static int |
2355 | pmu_ioctl(struct inode * inode, struct file *filp, | 2294 | pmu_ioctl(struct inode * inode, struct file *filp, |
2356 | u_int cmd, u_long arg) | 2295 | u_int cmd, u_long arg) |
@@ -2359,35 +2298,15 @@ pmu_ioctl(struct inode * inode, struct file *filp, | |||
2359 | int error = -EINVAL; | 2298 | int error = -EINVAL; |
2360 | 2299 | ||
2361 | switch (cmd) { | 2300 | switch (cmd) { |
2362 | #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32) | ||
2363 | case PMU_IOC_SLEEP: | 2301 | case PMU_IOC_SLEEP: |
2364 | if (!capable(CAP_SYS_ADMIN)) | 2302 | if (!capable(CAP_SYS_ADMIN)) |
2365 | return -EACCES; | 2303 | return -EACCES; |
2366 | if (sleep_in_progress) | 2304 | return pm_suspend(PM_SUSPEND_MEM); |
2367 | return -EBUSY; | ||
2368 | sleep_in_progress = 1; | ||
2369 | switch (pmu_kind) { | ||
2370 | case PMU_OHARE_BASED: | ||
2371 | error = powerbook_sleep_3400(); | ||
2372 | break; | ||
2373 | case PMU_HEATHROW_BASED: | ||
2374 | case PMU_PADDINGTON_BASED: | ||
2375 | error = powerbook_sleep_grackle(); | ||
2376 | break; | ||
2377 | case PMU_KEYLARGO_BASED: | ||
2378 | error = powerbook_sleep_Core99(); | ||
2379 | break; | ||
2380 | default: | ||
2381 | error = -ENOSYS; | ||
2382 | } | ||
2383 | sleep_in_progress = 0; | ||
2384 | break; | ||
2385 | case PMU_IOC_CAN_SLEEP: | 2305 | case PMU_IOC_CAN_SLEEP: |
2386 | if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) < 0) | 2306 | if (pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, -1) < 0) |
2387 | return put_user(0, argp); | 2307 | return put_user(0, argp); |
2388 | else | 2308 | else |
2389 | return put_user(1, argp); | 2309 | return put_user(1, argp); |
2390 | #endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */ | ||
2391 | 2310 | ||
2392 | #ifdef CONFIG_PMAC_BACKLIGHT_LEGACY | 2311 | #ifdef CONFIG_PMAC_BACKLIGHT_LEGACY |
2393 | /* Compatibility ioctl's for backlight */ | 2312 | /* Compatibility ioctl's for backlight */ |
@@ -2395,9 +2314,6 @@ pmu_ioctl(struct inode * inode, struct file *filp, | |||
2395 | { | 2314 | { |
2396 | int brightness; | 2315 | int brightness; |
2397 | 2316 | ||
2398 | if (sleep_in_progress) | ||
2399 | return -EBUSY; | ||
2400 | |||
2401 | brightness = pmac_backlight_get_legacy_brightness(); | 2317 | brightness = pmac_backlight_get_legacy_brightness(); |
2402 | if (brightness < 0) | 2318 | if (brightness < 0) |
2403 | return brightness; | 2319 | return brightness; |
@@ -2409,9 +2325,6 @@ pmu_ioctl(struct inode * inode, struct file *filp, | |||
2409 | { | 2325 | { |
2410 | int brightness; | 2326 | int brightness; |
2411 | 2327 | ||
2412 | if (sleep_in_progress) | ||
2413 | return -EBUSY; | ||
2414 | |||
2415 | error = get_user(brightness, argp); | 2328 | error = get_user(brightness, argp); |
2416 | if (error) | 2329 | if (error) |
2417 | return error; | 2330 | return error; |
@@ -2536,15 +2449,43 @@ pmu_polled_request(struct adb_request *req) | |||
2536 | local_irq_restore(flags); | 2449 | local_irq_restore(flags); |
2537 | return 0; | 2450 | return 0; |
2538 | } | 2451 | } |
2539 | #endif /* DEBUG_SLEEP */ | ||
2540 | 2452 | ||
2453 | /* N.B. This doesn't work on the 3400 */ | ||
2454 | void pmu_blink(int n) | ||
2455 | { | ||
2456 | struct adb_request req; | ||
2541 | 2457 | ||
2542 | /* FIXME: This is a temporary set of callbacks to enable us | 2458 | memset(&req, 0, sizeof(req)); |
2543 | * to do suspend-to-disk. | ||
2544 | */ | ||
2545 | 2459 | ||
2546 | #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32) | 2460 | for (; n > 0; --n) { |
2461 | req.nbytes = 4; | ||
2462 | req.done = NULL; | ||
2463 | req.data[0] = 0xee; | ||
2464 | req.data[1] = 4; | ||
2465 | req.data[2] = 0; | ||
2466 | req.data[3] = 1; | ||
2467 | req.reply[0] = ADB_RET_OK; | ||
2468 | req.reply_len = 1; | ||
2469 | req.reply_expected = 0; | ||
2470 | pmu_polled_request(&req); | ||
2471 | mdelay(50); | ||
2472 | req.nbytes = 4; | ||
2473 | req.done = NULL; | ||
2474 | req.data[0] = 0xee; | ||
2475 | req.data[1] = 4; | ||
2476 | req.data[2] = 0; | ||
2477 | req.data[3] = 0; | ||
2478 | req.reply[0] = ADB_RET_OK; | ||
2479 | req.reply_len = 1; | ||
2480 | req.reply_expected = 0; | ||
2481 | pmu_polled_request(&req); | ||
2482 | mdelay(50); | ||
2483 | } | ||
2484 | mdelay(50); | ||
2485 | } | ||
2486 | #endif /* DEBUG_SLEEP */ | ||
2547 | 2487 | ||
2488 | #if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32) | ||
2548 | int pmu_sys_suspended; | 2489 | int pmu_sys_suspended; |
2549 | 2490 | ||
2550 | static int pmu_sys_suspend(struct sys_device *sysdev, pm_message_t state) | 2491 | static int pmu_sys_suspend(struct sys_device *sysdev, pm_message_t state) |
@@ -2578,7 +2519,7 @@ static int pmu_sys_resume(struct sys_device *sysdev) | |||
2578 | return 0; | 2519 | return 0; |
2579 | } | 2520 | } |
2580 | 2521 | ||
2581 | #endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */ | 2522 | #endif /* CONFIG_SUSPEND && CONFIG_PPC32 */ |
2582 | 2523 | ||
2583 | static struct sysdev_class pmu_sysclass = { | 2524 | static struct sysdev_class pmu_sysclass = { |
2584 | set_kset_name("pmu"), | 2525 | set_kset_name("pmu"), |
@@ -2589,10 +2530,10 @@ static struct sys_device device_pmu = { | |||
2589 | }; | 2530 | }; |
2590 | 2531 | ||
2591 | static struct sysdev_driver driver_pmu = { | 2532 | static struct sysdev_driver driver_pmu = { |
2592 | #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32) | 2533 | #if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32) |
2593 | .suspend = &pmu_sys_suspend, | 2534 | .suspend = &pmu_sys_suspend, |
2594 | .resume = &pmu_sys_resume, | 2535 | .resume = &pmu_sys_resume, |
2595 | #endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */ | 2536 | #endif /* CONFIG_SUSPEND && CONFIG_PPC32 */ |
2596 | }; | 2537 | }; |
2597 | 2538 | ||
2598 | static int __init init_pmu_sysfs(void) | 2539 | static int __init init_pmu_sysfs(void) |
@@ -2627,10 +2568,10 @@ EXPORT_SYMBOL(pmu_wait_complete); | |||
2627 | EXPORT_SYMBOL(pmu_suspend); | 2568 | EXPORT_SYMBOL(pmu_suspend); |
2628 | EXPORT_SYMBOL(pmu_resume); | 2569 | EXPORT_SYMBOL(pmu_resume); |
2629 | EXPORT_SYMBOL(pmu_unlock); | 2570 | EXPORT_SYMBOL(pmu_unlock); |
2630 | #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32) | 2571 | #if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32) |
2631 | EXPORT_SYMBOL(pmu_enable_irled); | 2572 | EXPORT_SYMBOL(pmu_enable_irled); |
2632 | EXPORT_SYMBOL(pmu_battery_count); | 2573 | EXPORT_SYMBOL(pmu_battery_count); |
2633 | EXPORT_SYMBOL(pmu_batteries); | 2574 | EXPORT_SYMBOL(pmu_batteries); |
2634 | EXPORT_SYMBOL(pmu_power_flags); | 2575 | EXPORT_SYMBOL(pmu_power_flags); |
2635 | #endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */ | 2576 | #endif /* CONFIG_SUSPEND && CONFIG_PPC32 */ |
2636 | 2577 | ||