diff options
Diffstat (limited to 'arch/mips/au1000/common/power.c')
-rw-r--r-- | arch/mips/au1000/common/power.c | 493 |
1 files changed, 493 insertions, 0 deletions
diff --git a/arch/mips/au1000/common/power.c b/arch/mips/au1000/common/power.c new file mode 100644 index 000000000000..c40daccbb5b1 --- /dev/null +++ b/arch/mips/au1000/common/power.c | |||
@@ -0,0 +1,493 @@ | |||
1 | /* | ||
2 | * BRIEF MODULE DESCRIPTION | ||
3 | * Au1000 Power Management routines. | ||
4 | * | ||
5 | * Copyright 2001 MontaVista Software Inc. | ||
6 | * Author: MontaVista Software, Inc. | ||
7 | * ppopov@mvista.com or source@mvista.com | ||
8 | * | ||
9 | * Some of the routines are right out of init/main.c, whose | ||
10 | * copyrights apply here. | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | * | ||
17 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
19 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
20 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
23 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
24 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
27 | * | ||
28 | * You should have received a copy of the GNU General Public License along | ||
29 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
30 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
31 | */ | ||
32 | #include <linux/config.h> | ||
33 | #include <linux/init.h> | ||
34 | #include <linux/pm.h> | ||
35 | #include <linux/slab.h> | ||
36 | #include <linux/sysctl.h> | ||
37 | |||
38 | #include <asm/string.h> | ||
39 | #include <asm/uaccess.h> | ||
40 | #include <asm/io.h> | ||
41 | #include <asm/system.h> | ||
42 | #include <asm/mach-au1x00/au1000.h> | ||
43 | |||
44 | #ifdef CONFIG_PM | ||
45 | |||
46 | #define DEBUG 1 | ||
47 | #ifdef DEBUG | ||
48 | # define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) | ||
49 | #else | ||
50 | # define DPRINTK(fmt, args...) | ||
51 | #endif | ||
52 | |||
53 | static void calibrate_delay(void); | ||
54 | |||
55 | extern void set_au1x00_speed(unsigned int new_freq); | ||
56 | extern unsigned int get_au1x00_speed(void); | ||
57 | extern unsigned long get_au1x00_uart_baud_base(void); | ||
58 | extern void set_au1x00_uart_baud_base(unsigned long new_baud_base); | ||
59 | extern unsigned long save_local_and_disable(int controller); | ||
60 | extern void restore_local_and_enable(int controller, unsigned long mask); | ||
61 | extern void local_enable_irq(unsigned int irq_nr); | ||
62 | |||
63 | /* Quick acpi hack. This will have to change! */ | ||
64 | #define CTL_ACPI 9999 | ||
65 | #define ACPI_S1_SLP_TYP 19 | ||
66 | #define ACPI_SLEEP 21 | ||
67 | |||
68 | |||
69 | static DEFINE_SPINLOCK(pm_lock); | ||
70 | |||
71 | /* We need to save/restore a bunch of core registers that are | ||
72 | * either volatile or reset to some state across a processor sleep. | ||
73 | * If reading a register doesn't provide a proper result for a | ||
74 | * later restore, we have to provide a function for loading that | ||
75 | * register and save a copy. | ||
76 | * | ||
77 | * We only have to save/restore registers that aren't otherwise | ||
78 | * done as part of a driver pm_* function. | ||
79 | */ | ||
80 | static uint sleep_aux_pll_cntrl; | ||
81 | static uint sleep_cpu_pll_cntrl; | ||
82 | static uint sleep_pin_function; | ||
83 | static uint sleep_uart0_inten; | ||
84 | static uint sleep_uart0_fifoctl; | ||
85 | static uint sleep_uart0_linectl; | ||
86 | static uint sleep_uart0_clkdiv; | ||
87 | static uint sleep_uart0_enable; | ||
88 | static uint sleep_usbhost_enable; | ||
89 | static uint sleep_usbdev_enable; | ||
90 | static uint sleep_static_memctlr[4][3]; | ||
91 | |||
92 | /* Define this to cause the value you write to /proc/sys/pm/sleep to | ||
93 | * set the TOY timer for the amount of time you want to sleep. | ||
94 | * This is done mainly for testing, but may be useful in other cases. | ||
95 | * The value is number of 32KHz ticks to sleep. | ||
96 | */ | ||
97 | #define SLEEP_TEST_TIMEOUT 1 | ||
98 | #ifdef SLEEP_TEST_TIMEOUT | ||
99 | static int sleep_ticks; | ||
100 | void wakeup_counter0_set(int ticks); | ||
101 | #endif | ||
102 | |||
103 | static void | ||
104 | save_core_regs(void) | ||
105 | { | ||
106 | extern void save_au1xxx_intctl(void); | ||
107 | extern void pm_eth0_shutdown(void); | ||
108 | |||
109 | /* Do the serial ports.....these really should be a pm_* | ||
110 | * registered function by the driver......but of course the | ||
111 | * standard serial driver doesn't understand our Au1xxx | ||
112 | * unique registers. | ||
113 | */ | ||
114 | sleep_uart0_inten = au_readl(UART0_ADDR + UART_IER); | ||
115 | sleep_uart0_fifoctl = au_readl(UART0_ADDR + UART_FCR); | ||
116 | sleep_uart0_linectl = au_readl(UART0_ADDR + UART_LCR); | ||
117 | sleep_uart0_clkdiv = au_readl(UART0_ADDR + UART_CLK); | ||
118 | sleep_uart0_enable = au_readl(UART0_ADDR + UART_MOD_CNTRL); | ||
119 | |||
120 | /* Shutdown USB host/device. | ||
121 | */ | ||
122 | sleep_usbhost_enable = au_readl(USB_HOST_CONFIG); | ||
123 | |||
124 | /* There appears to be some undocumented reset register.... | ||
125 | */ | ||
126 | au_writel(0, 0xb0100004); au_sync(); | ||
127 | au_writel(0, USB_HOST_CONFIG); au_sync(); | ||
128 | |||
129 | sleep_usbdev_enable = au_readl(USBD_ENABLE); | ||
130 | au_writel(0, USBD_ENABLE); au_sync(); | ||
131 | |||
132 | /* Save interrupt controller state. | ||
133 | */ | ||
134 | save_au1xxx_intctl(); | ||
135 | |||
136 | /* Clocks and PLLs. | ||
137 | */ | ||
138 | sleep_aux_pll_cntrl = au_readl(SYS_AUXPLL); | ||
139 | |||
140 | /* We don't really need to do this one, but unless we | ||
141 | * write it again it won't have a valid value if we | ||
142 | * happen to read it. | ||
143 | */ | ||
144 | sleep_cpu_pll_cntrl = au_readl(SYS_CPUPLL); | ||
145 | |||
146 | sleep_pin_function = au_readl(SYS_PINFUNC); | ||
147 | |||
148 | /* Save the static memory controller configuration. | ||
149 | */ | ||
150 | sleep_static_memctlr[0][0] = au_readl(MEM_STCFG0); | ||
151 | sleep_static_memctlr[0][1] = au_readl(MEM_STTIME0); | ||
152 | sleep_static_memctlr[0][2] = au_readl(MEM_STADDR0); | ||
153 | sleep_static_memctlr[1][0] = au_readl(MEM_STCFG1); | ||
154 | sleep_static_memctlr[1][1] = au_readl(MEM_STTIME1); | ||
155 | sleep_static_memctlr[1][2] = au_readl(MEM_STADDR1); | ||
156 | sleep_static_memctlr[2][0] = au_readl(MEM_STCFG2); | ||
157 | sleep_static_memctlr[2][1] = au_readl(MEM_STTIME2); | ||
158 | sleep_static_memctlr[2][2] = au_readl(MEM_STADDR2); | ||
159 | sleep_static_memctlr[3][0] = au_readl(MEM_STCFG3); | ||
160 | sleep_static_memctlr[3][1] = au_readl(MEM_STTIME3); | ||
161 | sleep_static_memctlr[3][2] = au_readl(MEM_STADDR3); | ||
162 | } | ||
163 | |||
164 | static void | ||
165 | restore_core_regs(void) | ||
166 | { | ||
167 | extern void restore_au1xxx_intctl(void); | ||
168 | extern void wakeup_counter0_adjust(void); | ||
169 | |||
170 | au_writel(sleep_aux_pll_cntrl, SYS_AUXPLL); au_sync(); | ||
171 | au_writel(sleep_cpu_pll_cntrl, SYS_CPUPLL); au_sync(); | ||
172 | au_writel(sleep_pin_function, SYS_PINFUNC); au_sync(); | ||
173 | |||
174 | /* Restore the static memory controller configuration. | ||
175 | */ | ||
176 | au_writel(sleep_static_memctlr[0][0], MEM_STCFG0); | ||
177 | au_writel(sleep_static_memctlr[0][1], MEM_STTIME0); | ||
178 | au_writel(sleep_static_memctlr[0][2], MEM_STADDR0); | ||
179 | au_writel(sleep_static_memctlr[1][0], MEM_STCFG1); | ||
180 | au_writel(sleep_static_memctlr[1][1], MEM_STTIME1); | ||
181 | au_writel(sleep_static_memctlr[1][2], MEM_STADDR1); | ||
182 | au_writel(sleep_static_memctlr[2][0], MEM_STCFG2); | ||
183 | au_writel(sleep_static_memctlr[2][1], MEM_STTIME2); | ||
184 | au_writel(sleep_static_memctlr[2][2], MEM_STADDR2); | ||
185 | au_writel(sleep_static_memctlr[3][0], MEM_STCFG3); | ||
186 | au_writel(sleep_static_memctlr[3][1], MEM_STTIME3); | ||
187 | au_writel(sleep_static_memctlr[3][2], MEM_STADDR3); | ||
188 | |||
189 | /* Enable the UART if it was enabled before sleep. | ||
190 | * I guess I should define module control bits........ | ||
191 | */ | ||
192 | if (sleep_uart0_enable & 0x02) { | ||
193 | au_writel(0, UART0_ADDR + UART_MOD_CNTRL); au_sync(); | ||
194 | au_writel(1, UART0_ADDR + UART_MOD_CNTRL); au_sync(); | ||
195 | au_writel(3, UART0_ADDR + UART_MOD_CNTRL); au_sync(); | ||
196 | au_writel(sleep_uart0_inten, UART0_ADDR + UART_IER); au_sync(); | ||
197 | au_writel(sleep_uart0_fifoctl, UART0_ADDR + UART_FCR); au_sync(); | ||
198 | au_writel(sleep_uart0_linectl, UART0_ADDR + UART_LCR); au_sync(); | ||
199 | au_writel(sleep_uart0_clkdiv, UART0_ADDR + UART_CLK); au_sync(); | ||
200 | } | ||
201 | |||
202 | restore_au1xxx_intctl(); | ||
203 | wakeup_counter0_adjust(); | ||
204 | } | ||
205 | |||
206 | unsigned long suspend_mode; | ||
207 | |||
208 | void wakeup_from_suspend(void) | ||
209 | { | ||
210 | suspend_mode = 0; | ||
211 | } | ||
212 | |||
213 | int au_sleep(void) | ||
214 | { | ||
215 | unsigned long wakeup, flags; | ||
216 | extern void save_and_sleep(void); | ||
217 | |||
218 | spin_lock_irqsave(&pm_lock,flags); | ||
219 | |||
220 | save_core_regs(); | ||
221 | |||
222 | flush_cache_all(); | ||
223 | |||
224 | /** The code below is all system dependent and we should probably | ||
225 | ** have a function call out of here to set this up. You need | ||
226 | ** to configure the GPIO or timer interrupts that will bring | ||
227 | ** you out of sleep. | ||
228 | ** For testing, the TOY counter wakeup is useful. | ||
229 | **/ | ||
230 | |||
231 | #if 0 | ||
232 | au_writel(au_readl(SYS_PINSTATERD) & ~(1 << 11), SYS_PINSTATERD); | ||
233 | |||
234 | /* gpio 6 can cause a wake up event */ | ||
235 | wakeup = au_readl(SYS_WAKEMSK); | ||
236 | wakeup &= ~(1 << 8); /* turn off match20 wakeup */ | ||
237 | wakeup |= 1 << 6; /* turn on gpio 6 wakeup */ | ||
238 | #else | ||
239 | /* For testing, allow match20 to wake us up. | ||
240 | */ | ||
241 | #ifdef SLEEP_TEST_TIMEOUT | ||
242 | wakeup_counter0_set(sleep_ticks); | ||
243 | #endif | ||
244 | wakeup = 1 << 8; /* turn on match20 wakeup */ | ||
245 | wakeup = 0; | ||
246 | #endif | ||
247 | au_writel(1, SYS_WAKESRC); /* clear cause */ | ||
248 | au_sync(); | ||
249 | au_writel(wakeup, SYS_WAKEMSK); | ||
250 | au_sync(); | ||
251 | |||
252 | save_and_sleep(); | ||
253 | |||
254 | /* after a wakeup, the cpu vectors back to 0x1fc00000 so | ||
255 | * it's up to the boot code to get us back here. | ||
256 | */ | ||
257 | restore_core_regs(); | ||
258 | spin_unlock_irqrestore(&pm_lock, flags); | ||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | static int pm_do_sleep(ctl_table * ctl, int write, struct file *file, | ||
263 | void *buffer, size_t * len) | ||
264 | { | ||
265 | int retval = 0; | ||
266 | #ifdef SLEEP_TEST_TIMEOUT | ||
267 | #define TMPBUFLEN2 16 | ||
268 | char buf[TMPBUFLEN2], *p; | ||
269 | #endif | ||
270 | |||
271 | if (!write) { | ||
272 | *len = 0; | ||
273 | } else { | ||
274 | #ifdef SLEEP_TEST_TIMEOUT | ||
275 | if (*len > TMPBUFLEN2 - 1) { | ||
276 | return -EFAULT; | ||
277 | } | ||
278 | if (copy_from_user(buf, buffer, *len)) { | ||
279 | return -EFAULT; | ||
280 | } | ||
281 | buf[*len] = 0; | ||
282 | p = buf; | ||
283 | sleep_ticks = simple_strtoul(p, &p, 0); | ||
284 | #endif | ||
285 | retval = pm_send_all(PM_SUSPEND, (void *) 2); | ||
286 | |||
287 | if (retval) | ||
288 | return retval; | ||
289 | |||
290 | au_sleep(); | ||
291 | retval = pm_send_all(PM_RESUME, (void *) 0); | ||
292 | } | ||
293 | return retval; | ||
294 | } | ||
295 | |||
296 | static int pm_do_suspend(ctl_table * ctl, int write, struct file *file, | ||
297 | void *buffer, size_t * len) | ||
298 | { | ||
299 | int retval = 0; | ||
300 | void au1k_wait(void); | ||
301 | |||
302 | if (!write) { | ||
303 | *len = 0; | ||
304 | } else { | ||
305 | retval = pm_send_all(PM_SUSPEND, (void *) 2); | ||
306 | if (retval) | ||
307 | return retval; | ||
308 | suspend_mode = 1; | ||
309 | au1k_wait(); | ||
310 | retval = pm_send_all(PM_RESUME, (void *) 0); | ||
311 | } | ||
312 | return retval; | ||
313 | } | ||
314 | |||
315 | |||
316 | static int pm_do_freq(ctl_table * ctl, int write, struct file *file, | ||
317 | void *buffer, size_t * len) | ||
318 | { | ||
319 | int retval = 0, i; | ||
320 | unsigned long val, pll; | ||
321 | #define TMPBUFLEN 64 | ||
322 | #define MAX_CPU_FREQ 396 | ||
323 | char buf[TMPBUFLEN], *p; | ||
324 | unsigned long flags, intc0_mask, intc1_mask; | ||
325 | unsigned long old_baud_base, old_cpu_freq, baud_rate, old_clk, | ||
326 | old_refresh; | ||
327 | unsigned long new_baud_base, new_cpu_freq, new_clk, new_refresh; | ||
328 | |||
329 | spin_lock_irqsave(&pm_lock, flags); | ||
330 | if (!write) { | ||
331 | *len = 0; | ||
332 | } else { | ||
333 | /* Parse the new frequency */ | ||
334 | if (*len > TMPBUFLEN - 1) { | ||
335 | spin_unlock_irqrestore(&pm_lock, flags); | ||
336 | return -EFAULT; | ||
337 | } | ||
338 | if (copy_from_user(buf, buffer, *len)) { | ||
339 | spin_unlock_irqrestore(&pm_lock, flags); | ||
340 | return -EFAULT; | ||
341 | } | ||
342 | buf[*len] = 0; | ||
343 | p = buf; | ||
344 | val = simple_strtoul(p, &p, 0); | ||
345 | if (val > MAX_CPU_FREQ) { | ||
346 | spin_unlock_irqrestore(&pm_lock, flags); | ||
347 | return -EFAULT; | ||
348 | } | ||
349 | |||
350 | pll = val / 12; | ||
351 | if ((pll > 33) || (pll < 7)) { /* 396 MHz max, 84 MHz min */ | ||
352 | /* revisit this for higher speed cpus */ | ||
353 | spin_unlock_irqrestore(&pm_lock, flags); | ||
354 | return -EFAULT; | ||
355 | } | ||
356 | |||
357 | old_baud_base = get_au1x00_uart_baud_base(); | ||
358 | old_cpu_freq = get_au1x00_speed(); | ||
359 | |||
360 | new_cpu_freq = pll * 12 * 1000000; | ||
361 | new_baud_base = (new_cpu_freq / (2 * ((int)(au_readl(SYS_POWERCTRL)&0x03) + 2) * 16)); | ||
362 | set_au1x00_speed(new_cpu_freq); | ||
363 | set_au1x00_uart_baud_base(new_baud_base); | ||
364 | |||
365 | old_refresh = au_readl(MEM_SDREFCFG) & 0x1ffffff; | ||
366 | new_refresh = | ||
367 | ((old_refresh * new_cpu_freq) / | ||
368 | old_cpu_freq) | (au_readl(MEM_SDREFCFG) & ~0x1ffffff); | ||
369 | |||
370 | au_writel(pll, SYS_CPUPLL); | ||
371 | au_sync_delay(1); | ||
372 | au_writel(new_refresh, MEM_SDREFCFG); | ||
373 | au_sync_delay(1); | ||
374 | |||
375 | for (i = 0; i < 4; i++) { | ||
376 | if (au_readl | ||
377 | (UART_BASE + UART_MOD_CNTRL + | ||
378 | i * 0x00100000) == 3) { | ||
379 | old_clk = | ||
380 | au_readl(UART_BASE + UART_CLK + | ||
381 | i * 0x00100000); | ||
382 | // baud_rate = baud_base/clk | ||
383 | baud_rate = old_baud_base / old_clk; | ||
384 | /* we won't get an exact baud rate and the error | ||
385 | * could be significant enough that our new | ||
386 | * calculation will result in a clock that will | ||
387 | * give us a baud rate that's too far off from | ||
388 | * what we really want. | ||
389 | */ | ||
390 | if (baud_rate > 100000) | ||
391 | baud_rate = 115200; | ||
392 | else if (baud_rate > 50000) | ||
393 | baud_rate = 57600; | ||
394 | else if (baud_rate > 30000) | ||
395 | baud_rate = 38400; | ||
396 | else if (baud_rate > 17000) | ||
397 | baud_rate = 19200; | ||
398 | else | ||
399 | (baud_rate = 9600); | ||
400 | // new_clk = new_baud_base/baud_rate | ||
401 | new_clk = new_baud_base / baud_rate; | ||
402 | au_writel(new_clk, | ||
403 | UART_BASE + UART_CLK + | ||
404 | i * 0x00100000); | ||
405 | au_sync_delay(10); | ||
406 | } | ||
407 | } | ||
408 | } | ||
409 | |||
410 | |||
411 | /* We don't want _any_ interrupts other than | ||
412 | * match20. Otherwise our calibrate_delay() | ||
413 | * calculation will be off, potentially a lot. | ||
414 | */ | ||
415 | intc0_mask = save_local_and_disable(0); | ||
416 | intc1_mask = save_local_and_disable(1); | ||
417 | local_enable_irq(AU1000_TOY_MATCH2_INT); | ||
418 | spin_unlock_irqrestore(&pm_lock, flags); | ||
419 | calibrate_delay(); | ||
420 | restore_local_and_enable(0, intc0_mask); | ||
421 | restore_local_and_enable(1, intc1_mask); | ||
422 | return retval; | ||
423 | } | ||
424 | |||
425 | |||
426 | static struct ctl_table pm_table[] = { | ||
427 | {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, &pm_do_suspend}, | ||
428 | {ACPI_SLEEP, "sleep", NULL, 0, 0600, NULL, &pm_do_sleep}, | ||
429 | {CTL_ACPI, "freq", NULL, 0, 0600, NULL, &pm_do_freq}, | ||
430 | {0} | ||
431 | }; | ||
432 | |||
433 | static struct ctl_table pm_dir_table[] = { | ||
434 | {CTL_ACPI, "pm", NULL, 0, 0555, pm_table}, | ||
435 | {0} | ||
436 | }; | ||
437 | |||
438 | /* | ||
439 | * Initialize power interface | ||
440 | */ | ||
441 | static int __init pm_init(void) | ||
442 | { | ||
443 | register_sysctl_table(pm_dir_table, 1); | ||
444 | return 0; | ||
445 | } | ||
446 | |||
447 | __initcall(pm_init); | ||
448 | |||
449 | |||
450 | /* | ||
451 | * This is right out of init/main.c | ||
452 | */ | ||
453 | |||
454 | /* This is the number of bits of precision for the loops_per_jiffy. Each | ||
455 | bit takes on average 1.5/HZ seconds. This (like the original) is a little | ||
456 | better than 1% */ | ||
457 | #define LPS_PREC 8 | ||
458 | |||
459 | static void calibrate_delay(void) | ||
460 | { | ||
461 | unsigned long ticks, loopbit; | ||
462 | int lps_precision = LPS_PREC; | ||
463 | |||
464 | loops_per_jiffy = (1 << 12); | ||
465 | |||
466 | while (loops_per_jiffy <<= 1) { | ||
467 | /* wait for "start of" clock tick */ | ||
468 | ticks = jiffies; | ||
469 | while (ticks == jiffies) | ||
470 | /* nothing */ ; | ||
471 | /* Go .. */ | ||
472 | ticks = jiffies; | ||
473 | __delay(loops_per_jiffy); | ||
474 | ticks = jiffies - ticks; | ||
475 | if (ticks) | ||
476 | break; | ||
477 | } | ||
478 | |||
479 | /* Do a binary approximation to get loops_per_jiffy set to equal one clock | ||
480 | (up to lps_precision bits) */ | ||
481 | loops_per_jiffy >>= 1; | ||
482 | loopbit = loops_per_jiffy; | ||
483 | while (lps_precision-- && (loopbit >>= 1)) { | ||
484 | loops_per_jiffy |= loopbit; | ||
485 | ticks = jiffies; | ||
486 | while (ticks == jiffies); | ||
487 | ticks = jiffies; | ||
488 | __delay(loops_per_jiffy); | ||
489 | if (jiffies != ticks) /* longer than 1 tick */ | ||
490 | loops_per_jiffy &= ~loopbit; | ||
491 | } | ||
492 | } | ||
493 | #endif /* CONFIG_PM */ | ||