Commit | Line | Data |
---|---|---|
1da177e4 LT |
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 | */ | |
1da177e4 LT |
32 | #include <linux/init.h> |
33 | #include <linux/pm.h> | |
bca73e4b | 34 | #include <linux/pm_legacy.h> |
1da177e4 LT |
35 | #include <linux/slab.h> |
36 | #include <linux/sysctl.h> | |
3ce86ee1 | 37 | #include <linux/jiffies.h> |
1da177e4 LT |
38 | |
39 | #include <asm/string.h> | |
40 | #include <asm/uaccess.h> | |
41 | #include <asm/io.h> | |
42 | #include <asm/system.h> | |
3ce86ee1 | 43 | #include <asm/cacheflush.h> |
1da177e4 LT |
44 | #include <asm/mach-au1x00/au1000.h> |
45 | ||
46 | #ifdef CONFIG_PM | |
47 | ||
48 | #define DEBUG 1 | |
49 | #ifdef DEBUG | |
50 | # define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) | |
51 | #else | |
52 | # define DPRINTK(fmt, args...) | |
53 | #endif | |
54 | ||
3ce86ee1 | 55 | static void au1000_calibrate_delay(void); |
1da177e4 LT |
56 | |
57 | extern void set_au1x00_speed(unsigned int new_freq); | |
58 | extern unsigned int get_au1x00_speed(void); | |
59 | extern unsigned long get_au1x00_uart_baud_base(void); | |
60 | extern void set_au1x00_uart_baud_base(unsigned long new_baud_base); | |
61 | extern unsigned long save_local_and_disable(int controller); | |
62 | extern void restore_local_and_enable(int controller, unsigned long mask); | |
63 | extern void local_enable_irq(unsigned int irq_nr); | |
64 | ||
1da177e4 LT |
65 | static DEFINE_SPINLOCK(pm_lock); |
66 | ||
67 | /* We need to save/restore a bunch of core registers that are | |
68 | * either volatile or reset to some state across a processor sleep. | |
69 | * If reading a register doesn't provide a proper result for a | |
70 | * later restore, we have to provide a function for loading that | |
71 | * register and save a copy. | |
72 | * | |
73 | * We only have to save/restore registers that aren't otherwise | |
74 | * done as part of a driver pm_* function. | |
75 | */ | |
fc103349 RB |
76 | static unsigned int sleep_aux_pll_cntrl; |
77 | static unsigned int sleep_cpu_pll_cntrl; | |
78 | static unsigned int sleep_pin_function; | |
79 | static unsigned int sleep_uart0_inten; | |
80 | static unsigned int sleep_uart0_fifoctl; | |
81 | static unsigned int sleep_uart0_linectl; | |
82 | static unsigned int sleep_uart0_clkdiv; | |
83 | static unsigned int sleep_uart0_enable; | |
84 | static unsigned int sleep_usbhost_enable; | |
85 | static unsigned int sleep_usbdev_enable; | |
86 | static unsigned int sleep_static_memctlr[4][3]; | |
1da177e4 LT |
87 | |
88 | /* Define this to cause the value you write to /proc/sys/pm/sleep to | |
89 | * set the TOY timer for the amount of time you want to sleep. | |
90 | * This is done mainly for testing, but may be useful in other cases. | |
91 | * The value is number of 32KHz ticks to sleep. | |
92 | */ | |
93 | #define SLEEP_TEST_TIMEOUT 1 | |
94 | #ifdef SLEEP_TEST_TIMEOUT | |
95 | static int sleep_ticks; | |
96 | void wakeup_counter0_set(int ticks); | |
97 | #endif | |
98 | ||
99 | static void | |
100 | save_core_regs(void) | |
101 | { | |
102 | extern void save_au1xxx_intctl(void); | |
103 | extern void pm_eth0_shutdown(void); | |
104 | ||
105 | /* Do the serial ports.....these really should be a pm_* | |
106 | * registered function by the driver......but of course the | |
107 | * standard serial driver doesn't understand our Au1xxx | |
108 | * unique registers. | |
109 | */ | |
110 | sleep_uart0_inten = au_readl(UART0_ADDR + UART_IER); | |
111 | sleep_uart0_fifoctl = au_readl(UART0_ADDR + UART_FCR); | |
112 | sleep_uart0_linectl = au_readl(UART0_ADDR + UART_LCR); | |
113 | sleep_uart0_clkdiv = au_readl(UART0_ADDR + UART_CLK); | |
114 | sleep_uart0_enable = au_readl(UART0_ADDR + UART_MOD_CNTRL); | |
115 | ||
116 | /* Shutdown USB host/device. | |
117 | */ | |
118 | sleep_usbhost_enable = au_readl(USB_HOST_CONFIG); | |
119 | ||
120 | /* There appears to be some undocumented reset register.... | |
121 | */ | |
122 | au_writel(0, 0xb0100004); au_sync(); | |
123 | au_writel(0, USB_HOST_CONFIG); au_sync(); | |
124 | ||
125 | sleep_usbdev_enable = au_readl(USBD_ENABLE); | |
126 | au_writel(0, USBD_ENABLE); au_sync(); | |
127 | ||
128 | /* Save interrupt controller state. | |
129 | */ | |
130 | save_au1xxx_intctl(); | |
131 | ||
132 | /* Clocks and PLLs. | |
133 | */ | |
134 | sleep_aux_pll_cntrl = au_readl(SYS_AUXPLL); | |
135 | ||
136 | /* We don't really need to do this one, but unless we | |
137 | * write it again it won't have a valid value if we | |
138 | * happen to read it. | |
139 | */ | |
140 | sleep_cpu_pll_cntrl = au_readl(SYS_CPUPLL); | |
141 | ||
142 | sleep_pin_function = au_readl(SYS_PINFUNC); | |
143 | ||
144 | /* Save the static memory controller configuration. | |
145 | */ | |
146 | sleep_static_memctlr[0][0] = au_readl(MEM_STCFG0); | |
147 | sleep_static_memctlr[0][1] = au_readl(MEM_STTIME0); | |
148 | sleep_static_memctlr[0][2] = au_readl(MEM_STADDR0); | |
149 | sleep_static_memctlr[1][0] = au_readl(MEM_STCFG1); | |
150 | sleep_static_memctlr[1][1] = au_readl(MEM_STTIME1); | |
151 | sleep_static_memctlr[1][2] = au_readl(MEM_STADDR1); | |
152 | sleep_static_memctlr[2][0] = au_readl(MEM_STCFG2); | |
153 | sleep_static_memctlr[2][1] = au_readl(MEM_STTIME2); | |
154 | sleep_static_memctlr[2][2] = au_readl(MEM_STADDR2); | |
155 | sleep_static_memctlr[3][0] = au_readl(MEM_STCFG3); | |
156 | sleep_static_memctlr[3][1] = au_readl(MEM_STTIME3); | |
157 | sleep_static_memctlr[3][2] = au_readl(MEM_STADDR3); | |
158 | } | |
159 | ||
160 | static void | |
161 | restore_core_regs(void) | |
162 | { | |
163 | extern void restore_au1xxx_intctl(void); | |
164 | extern void wakeup_counter0_adjust(void); | |
165 | ||
166 | au_writel(sleep_aux_pll_cntrl, SYS_AUXPLL); au_sync(); | |
167 | au_writel(sleep_cpu_pll_cntrl, SYS_CPUPLL); au_sync(); | |
168 | au_writel(sleep_pin_function, SYS_PINFUNC); au_sync(); | |
169 | ||
170 | /* Restore the static memory controller configuration. | |
171 | */ | |
172 | au_writel(sleep_static_memctlr[0][0], MEM_STCFG0); | |
173 | au_writel(sleep_static_memctlr[0][1], MEM_STTIME0); | |
174 | au_writel(sleep_static_memctlr[0][2], MEM_STADDR0); | |
175 | au_writel(sleep_static_memctlr[1][0], MEM_STCFG1); | |
176 | au_writel(sleep_static_memctlr[1][1], MEM_STTIME1); | |
177 | au_writel(sleep_static_memctlr[1][2], MEM_STADDR1); | |
178 | au_writel(sleep_static_memctlr[2][0], MEM_STCFG2); | |
179 | au_writel(sleep_static_memctlr[2][1], MEM_STTIME2); | |
180 | au_writel(sleep_static_memctlr[2][2], MEM_STADDR2); | |
181 | au_writel(sleep_static_memctlr[3][0], MEM_STCFG3); | |
182 | au_writel(sleep_static_memctlr[3][1], MEM_STTIME3); | |
183 | au_writel(sleep_static_memctlr[3][2], MEM_STADDR3); | |
184 | ||
185 | /* Enable the UART if it was enabled before sleep. | |
186 | * I guess I should define module control bits........ | |
187 | */ | |
188 | if (sleep_uart0_enable & 0x02) { | |
189 | au_writel(0, UART0_ADDR + UART_MOD_CNTRL); au_sync(); | |
190 | au_writel(1, UART0_ADDR + UART_MOD_CNTRL); au_sync(); | |
191 | au_writel(3, UART0_ADDR + UART_MOD_CNTRL); au_sync(); | |
192 | au_writel(sleep_uart0_inten, UART0_ADDR + UART_IER); au_sync(); | |
193 | au_writel(sleep_uart0_fifoctl, UART0_ADDR + UART_FCR); au_sync(); | |
194 | au_writel(sleep_uart0_linectl, UART0_ADDR + UART_LCR); au_sync(); | |
195 | au_writel(sleep_uart0_clkdiv, UART0_ADDR + UART_CLK); au_sync(); | |
196 | } | |
197 | ||
198 | restore_au1xxx_intctl(); | |
199 | wakeup_counter0_adjust(); | |
200 | } | |
201 | ||
202 | unsigned long suspend_mode; | |
203 | ||
204 | void wakeup_from_suspend(void) | |
205 | { | |
206 | suspend_mode = 0; | |
207 | } | |
208 | ||
209 | int au_sleep(void) | |
210 | { | |
211 | unsigned long wakeup, flags; | |
212 | extern void save_and_sleep(void); | |
213 | ||
21a151d8 | 214 | spin_lock_irqsave(&pm_lock, flags); |
1da177e4 LT |
215 | |
216 | save_core_regs(); | |
217 | ||
218 | flush_cache_all(); | |
219 | ||
220 | /** The code below is all system dependent and we should probably | |
221 | ** have a function call out of here to set this up. You need | |
222 | ** to configure the GPIO or timer interrupts that will bring | |
223 | ** you out of sleep. | |
224 | ** For testing, the TOY counter wakeup is useful. | |
225 | **/ | |
226 | ||
227 | #if 0 | |
228 | au_writel(au_readl(SYS_PINSTATERD) & ~(1 << 11), SYS_PINSTATERD); | |
229 | ||
230 | /* gpio 6 can cause a wake up event */ | |
231 | wakeup = au_readl(SYS_WAKEMSK); | |
232 | wakeup &= ~(1 << 8); /* turn off match20 wakeup */ | |
233 | wakeup |= 1 << 6; /* turn on gpio 6 wakeup */ | |
234 | #else | |
235 | /* For testing, allow match20 to wake us up. | |
236 | */ | |
237 | #ifdef SLEEP_TEST_TIMEOUT | |
238 | wakeup_counter0_set(sleep_ticks); | |
239 | #endif | |
240 | wakeup = 1 << 8; /* turn on match20 wakeup */ | |
241 | wakeup = 0; | |
242 | #endif | |
243 | au_writel(1, SYS_WAKESRC); /* clear cause */ | |
244 | au_sync(); | |
245 | au_writel(wakeup, SYS_WAKEMSK); | |
246 | au_sync(); | |
247 | ||
248 | save_and_sleep(); | |
249 | ||
250 | /* after a wakeup, the cpu vectors back to 0x1fc00000 so | |
251 | * it's up to the boot code to get us back here. | |
252 | */ | |
253 | restore_core_regs(); | |
254 | spin_unlock_irqrestore(&pm_lock, flags); | |
255 | return 0; | |
256 | } | |
257 | ||
258 | static int pm_do_sleep(ctl_table * ctl, int write, struct file *file, | |
3ce86ee1 | 259 | void __user *buffer, size_t * len, loff_t *ppos) |
1da177e4 LT |
260 | { |
261 | int retval = 0; | |
262 | #ifdef SLEEP_TEST_TIMEOUT | |
263 | #define TMPBUFLEN2 16 | |
264 | char buf[TMPBUFLEN2], *p; | |
265 | #endif | |
266 | ||
267 | if (!write) { | |
268 | *len = 0; | |
269 | } else { | |
270 | #ifdef SLEEP_TEST_TIMEOUT | |
271 | if (*len > TMPBUFLEN2 - 1) { | |
272 | return -EFAULT; | |
273 | } | |
274 | if (copy_from_user(buf, buffer, *len)) { | |
275 | return -EFAULT; | |
276 | } | |
277 | buf[*len] = 0; | |
278 | p = buf; | |
279 | sleep_ticks = simple_strtoul(p, &p, 0); | |
280 | #endif | |
281 | retval = pm_send_all(PM_SUSPEND, (void *) 2); | |
282 | ||
283 | if (retval) | |
284 | return retval; | |
285 | ||
286 | au_sleep(); | |
287 | retval = pm_send_all(PM_RESUME, (void *) 0); | |
288 | } | |
289 | return retval; | |
290 | } | |
291 | ||
292 | static int pm_do_suspend(ctl_table * ctl, int write, struct file *file, | |
3ce86ee1 | 293 | void __user *buffer, size_t * len, loff_t *ppos) |
1da177e4 LT |
294 | { |
295 | int retval = 0; | |
1da177e4 LT |
296 | |
297 | if (!write) { | |
298 | *len = 0; | |
299 | } else { | |
300 | retval = pm_send_all(PM_SUSPEND, (void *) 2); | |
301 | if (retval) | |
302 | return retval; | |
303 | suspend_mode = 1; | |
494900af | 304 | |
1da177e4 LT |
305 | retval = pm_send_all(PM_RESUME, (void *) 0); |
306 | } | |
307 | return retval; | |
308 | } | |
309 | ||
310 | ||
311 | static int pm_do_freq(ctl_table * ctl, int write, struct file *file, | |
3ce86ee1 | 312 | void __user *buffer, size_t * len, loff_t *ppos) |
1da177e4 LT |
313 | { |
314 | int retval = 0, i; | |
315 | unsigned long val, pll; | |
316 | #define TMPBUFLEN 64 | |
317 | #define MAX_CPU_FREQ 396 | |
318 | char buf[TMPBUFLEN], *p; | |
319 | unsigned long flags, intc0_mask, intc1_mask; | |
320 | unsigned long old_baud_base, old_cpu_freq, baud_rate, old_clk, | |
321 | old_refresh; | |
322 | unsigned long new_baud_base, new_cpu_freq, new_clk, new_refresh; | |
323 | ||
324 | spin_lock_irqsave(&pm_lock, flags); | |
325 | if (!write) { | |
326 | *len = 0; | |
327 | } else { | |
328 | /* Parse the new frequency */ | |
329 | if (*len > TMPBUFLEN - 1) { | |
330 | spin_unlock_irqrestore(&pm_lock, flags); | |
331 | return -EFAULT; | |
332 | } | |
333 | if (copy_from_user(buf, buffer, *len)) { | |
334 | spin_unlock_irqrestore(&pm_lock, flags); | |
335 | return -EFAULT; | |
336 | } | |
337 | buf[*len] = 0; | |
338 | p = buf; | |
339 | val = simple_strtoul(p, &p, 0); | |
340 | if (val > MAX_CPU_FREQ) { | |
341 | spin_unlock_irqrestore(&pm_lock, flags); | |
342 | return -EFAULT; | |
343 | } | |
344 | ||
345 | pll = val / 12; | |
346 | if ((pll > 33) || (pll < 7)) { /* 396 MHz max, 84 MHz min */ | |
347 | /* revisit this for higher speed cpus */ | |
348 | spin_unlock_irqrestore(&pm_lock, flags); | |
349 | return -EFAULT; | |
350 | } | |
351 | ||
352 | old_baud_base = get_au1x00_uart_baud_base(); | |
353 | old_cpu_freq = get_au1x00_speed(); | |
354 | ||
355 | new_cpu_freq = pll * 12 * 1000000; | |
356 | new_baud_base = (new_cpu_freq / (2 * ((int)(au_readl(SYS_POWERCTRL)&0x03) + 2) * 16)); | |
357 | set_au1x00_speed(new_cpu_freq); | |
358 | set_au1x00_uart_baud_base(new_baud_base); | |
359 | ||
360 | old_refresh = au_readl(MEM_SDREFCFG) & 0x1ffffff; | |
361 | new_refresh = | |
362 | ((old_refresh * new_cpu_freq) / | |
363 | old_cpu_freq) | (au_readl(MEM_SDREFCFG) & ~0x1ffffff); | |
364 | ||
365 | au_writel(pll, SYS_CPUPLL); | |
366 | au_sync_delay(1); | |
367 | au_writel(new_refresh, MEM_SDREFCFG); | |
368 | au_sync_delay(1); | |
369 | ||
370 | for (i = 0; i < 4; i++) { | |
371 | if (au_readl | |
372 | (UART_BASE + UART_MOD_CNTRL + | |
373 | i * 0x00100000) == 3) { | |
374 | old_clk = | |
375 | au_readl(UART_BASE + UART_CLK + | |
376 | i * 0x00100000); | |
377 | // baud_rate = baud_base/clk | |
378 | baud_rate = old_baud_base / old_clk; | |
379 | /* we won't get an exact baud rate and the error | |
380 | * could be significant enough that our new | |
381 | * calculation will result in a clock that will | |
382 | * give us a baud rate that's too far off from | |
383 | * what we really want. | |
384 | */ | |
385 | if (baud_rate > 100000) | |
386 | baud_rate = 115200; | |
387 | else if (baud_rate > 50000) | |
388 | baud_rate = 57600; | |
389 | else if (baud_rate > 30000) | |
390 | baud_rate = 38400; | |
391 | else if (baud_rate > 17000) | |
392 | baud_rate = 19200; | |
393 | else | |
394 | (baud_rate = 9600); | |
395 | // new_clk = new_baud_base/baud_rate | |
396 | new_clk = new_baud_base / baud_rate; | |
397 | au_writel(new_clk, | |
398 | UART_BASE + UART_CLK + | |
399 | i * 0x00100000); | |
400 | au_sync_delay(10); | |
401 | } | |
402 | } | |
403 | } | |
404 | ||
405 | ||
406 | /* We don't want _any_ interrupts other than | |
3ce86ee1 | 407 | * match20. Otherwise our au1000_calibrate_delay() |
1da177e4 LT |
408 | * calculation will be off, potentially a lot. |
409 | */ | |
410 | intc0_mask = save_local_and_disable(0); | |
411 | intc1_mask = save_local_and_disable(1); | |
412 | local_enable_irq(AU1000_TOY_MATCH2_INT); | |
413 | spin_unlock_irqrestore(&pm_lock, flags); | |
3ce86ee1 | 414 | au1000_calibrate_delay(); |
1da177e4 LT |
415 | restore_local_and_enable(0, intc0_mask); |
416 | restore_local_and_enable(1, intc1_mask); | |
417 | return retval; | |
418 | } | |
419 | ||
420 | ||
421 | static struct ctl_table pm_table[] = { | |
7ed744d1 EB |
422 | { |
423 | .ctl_name = CTL_UNNUMBERED, | |
424 | .procname = "suspend", | |
425 | .data = NULL, | |
426 | .maxlen = 0, | |
427 | .mode = 0600, | |
428 | .proc_handler = &pm_do_suspend | |
429 | }, | |
430 | { | |
431 | .ctl_name = CTL_UNNUMBERED, | |
432 | .procname = "sleep", | |
433 | .data = NULL, | |
434 | .maxlen = 0, | |
435 | .mode = 0600, | |
436 | .proc_handler = &pm_do_sleep | |
437 | }, | |
438 | { | |
439 | .ctl_name = CTL_UNNUMBERED, | |
440 | .procname = "freq", | |
441 | .data = NULL, | |
442 | .maxlen = 0, | |
443 | .mode = 0600, | |
444 | .proc_handler = &pm_do_freq | |
445 | }, | |
446 | {} | |
1da177e4 LT |
447 | }; |
448 | ||
449 | static struct ctl_table pm_dir_table[] = { | |
7ed744d1 EB |
450 | { |
451 | .ctl_name = CTL_UNNUMBERED, | |
452 | .procname = "pm", | |
453 | .mode = 0555, | |
454 | .child = pm_table | |
455 | }, | |
456 | {} | |
1da177e4 LT |
457 | }; |
458 | ||
459 | /* | |
460 | * Initialize power interface | |
461 | */ | |
462 | static int __init pm_init(void) | |
463 | { | |
0b4d4147 | 464 | register_sysctl_table(pm_dir_table); |
1da177e4 LT |
465 | return 0; |
466 | } | |
467 | ||
468 | __initcall(pm_init); | |
469 | ||
470 | ||
471 | /* | |
472 | * This is right out of init/main.c | |
473 | */ | |
474 | ||
475 | /* This is the number of bits of precision for the loops_per_jiffy. Each | |
476 | bit takes on average 1.5/HZ seconds. This (like the original) is a little | |
477 | better than 1% */ | |
478 | #define LPS_PREC 8 | |
479 | ||
3ce86ee1 | 480 | static void au1000_calibrate_delay(void) |
1da177e4 LT |
481 | { |
482 | unsigned long ticks, loopbit; | |
483 | int lps_precision = LPS_PREC; | |
484 | ||
485 | loops_per_jiffy = (1 << 12); | |
486 | ||
487 | while (loops_per_jiffy <<= 1) { | |
488 | /* wait for "start of" clock tick */ | |
489 | ticks = jiffies; | |
490 | while (ticks == jiffies) | |
491 | /* nothing */ ; | |
492 | /* Go .. */ | |
493 | ticks = jiffies; | |
494 | __delay(loops_per_jiffy); | |
495 | ticks = jiffies - ticks; | |
496 | if (ticks) | |
497 | break; | |
498 | } | |
499 | ||
500 | /* Do a binary approximation to get loops_per_jiffy set to equal one clock | |
501 | (up to lps_precision bits) */ | |
502 | loops_per_jiffy >>= 1; | |
503 | loopbit = loops_per_jiffy; | |
504 | while (lps_precision-- && (loopbit >>= 1)) { | |
505 | loops_per_jiffy |= loopbit; | |
506 | ticks = jiffies; | |
507 | while (ticks == jiffies); | |
508 | ticks = jiffies; | |
509 | __delay(loops_per_jiffy); | |
510 | if (jiffies != ticks) /* longer than 1 tick */ | |
511 | loops_per_jiffy &= ~loopbit; | |
512 | } | |
513 | } | |
514 | #endif /* CONFIG_PM */ |