power.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:8k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  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. #include <linux/acpi.h>
  38. #include <asm/string.h>
  39. #include <asm/uaccess.h>
  40. #include <asm/io.h>
  41. #include <asm/system.h>
  42. #include <asm/au1000.h>
  43. #define DEBUG 1
  44. #ifdef DEBUG
  45. #  define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args)
  46. #else
  47. #  define DPRINTK(fmt, args...)
  48. #endif
  49. extern void au1k_wait(void);
  50. static void calibrate_delay(void);
  51. extern void set_au1000_speed(unsigned int new_freq);
  52. extern unsigned int get_au1000_speed(void);
  53. extern unsigned long get_au1000_uart_baud_base(void);
  54. extern void set_au1000_uart_baud_base(unsigned long new_baud_base);
  55. extern unsigned long save_local_and_disable(int controller);
  56. extern void restore_local_and_enable(int controller, unsigned long mask);
  57. extern void local_enable_irq(unsigned int irq_nr);
  58. /* Quick acpi hack. This will have to change! */
  59. #define CTL_ACPI 9999
  60. #define ACPI_S1_SLP_TYP 19
  61. #define ACPI_SLEEP 21
  62. #ifdef CONFIG_PM
  63. unsigned long suspend_mode;
  64. void wakeup_from_suspend(void)
  65. {
  66. suspend_mode = 0;
  67. }
  68. int au_sleep(void)
  69. {
  70. unsigned long wakeup, flags;
  71. save_and_cli(flags);
  72. flush_cache_all();
  73. /* pin 6 is gpio */
  74. au_writel(au_readl(SYS_PINSTATERD) & ~(1 << 11), SYS_PINSTATERD);
  75. /* gpio 6 can cause a wake up event */
  76. wakeup = au_readl(SYS_WAKEMSK);
  77. wakeup &= ~(1 << 8); /* turn off match20 wakeup */
  78. wakeup |= 1 << 6; /* turn on gpio 6 wakeup   */
  79. au_writel(wakeup, SYS_WAKEMSK);
  80. au_writel(1, SYS_WAKESRC); /* clear cause */
  81. au_writel(1, SYS_SLPPWR); /* prepare to sleep */
  82. __asm__("la $4, 1fnt"
  83. "lui $5, 0xb190nt"
  84. "ori $5, 0x18nt"
  85. "sw $4, 0($5)nt"
  86. "li $4, 1nt"
  87. "lui $5, 0xb190nt"
  88. "ori $5, 0x7cnt"
  89. "sw $4, 0($5)nt" "syncnt" "1:tnt" "nopnt");
  90. /* after a wakeup, the cpu vectors back to 0x1fc00000 so
  91.  * it's up to the boot code to get us back here.
  92.  */
  93. restore_flags(flags);
  94. return 0;
  95. }
  96. static int pm_do_sleep(ctl_table * ctl, int write, struct file *file,
  97.        void *buffer, size_t * len)
  98. {
  99. int retval = 0;
  100. if (!write) {
  101. *len = 0;
  102. } else {
  103. retval = pm_send_all(PM_SUSPEND, (void *) 2);
  104. if (retval)
  105. return retval;
  106. au_sleep();
  107. retval = pm_send_all(PM_RESUME, (void *) 0);
  108. }
  109. return retval;
  110. }
  111. static int pm_do_suspend(ctl_table * ctl, int write, struct file *file,
  112.  void *buffer, size_t * len)
  113. {
  114. int retval = 0;
  115. if (!write) {
  116. *len = 0;
  117. } else {
  118. retval = pm_send_all(PM_SUSPEND, (void *) 2);
  119. if (retval)
  120. return retval;
  121. suspend_mode = 1;
  122. au1k_wait();
  123. retval = pm_send_all(PM_RESUME, (void *) 0);
  124. }
  125. return retval;
  126. }
  127. static int pm_do_freq(ctl_table * ctl, int write, struct file *file,
  128.       void *buffer, size_t * len)
  129. {
  130. int retval = 0, i;
  131. unsigned long val, pll;
  132. #define TMPBUFLEN 64
  133. #define MAX_CPU_FREQ 396
  134. char buf[8], *p;
  135. unsigned long flags, intc0_mask, intc1_mask;
  136. unsigned long old_baud_base, old_cpu_freq, baud_rate, old_clk,
  137.     old_refresh;
  138. unsigned long new_baud_base, new_cpu_freq, new_clk, new_refresh;
  139. save_and_cli(flags);
  140. if (!write) {
  141. *len = 0;
  142. } else {
  143. /* Parse the new frequency */
  144. if (*len > TMPBUFLEN - 1) {
  145. restore_flags(flags);
  146. return -EFAULT;
  147. }
  148. if (copy_from_user(buf, buffer, *len)) {
  149. restore_flags(flags);
  150. return -EFAULT;
  151. }
  152. buf[*len] = 0;
  153. p = buf;
  154. val = simple_strtoul(p, &p, 0);
  155. if (val > MAX_CPU_FREQ) {
  156. restore_flags(flags);
  157. return -EFAULT;
  158. }
  159. pll = val / 12;
  160. if ((pll > 33) || (pll < 7)) { /* 396 MHz max, 84 MHz min */
  161. /* revisit this for higher speed cpus */
  162. restore_flags(flags);
  163. return -EFAULT;
  164. }
  165. old_baud_base = get_au1000_uart_baud_base();
  166. old_cpu_freq = get_au1000_speed();
  167. new_cpu_freq = pll * 12 * 1000000;
  168. new_baud_base = (new_cpu_freq / 4) / 16;
  169. set_au1000_speed(new_cpu_freq);
  170. set_au1000_uart_baud_base(new_baud_base);
  171. old_refresh = au_readl(MEM_SDREFCFG) & 0x1ffffff;
  172. new_refresh =
  173.     ((old_refresh * new_cpu_freq) /
  174.      old_cpu_freq) | (au_readl(MEM_SDREFCFG) & ~0x1ffffff);
  175. au_writel(pll, SYS_CPUPLL);
  176. au_sync_delay(1);
  177. au_writel(new_refresh, MEM_SDREFCFG);
  178. au_sync_delay(1);
  179. for (i = 0; i < 4; i++) {
  180. if (au_readl
  181.     (UART_BASE + UART_MOD_CNTRL +
  182.      i * 0x00100000) == 3) {
  183. old_clk =
  184.     au_readl(UART_BASE + UART_CLK +
  185.   i * 0x00100000);
  186. // baud_rate = baud_base/clk
  187. baud_rate = old_baud_base / old_clk;
  188. /* we won't get an exact baud rate and the error
  189.  * could be significant enough that our new
  190.  * calculation will result in a clock that will
  191.  * give us a baud rate that's too far off from
  192.  * what we really want.
  193.  */
  194. if (baud_rate > 100000)
  195. baud_rate = 115200;
  196. else if (baud_rate > 50000)
  197. baud_rate = 57600;
  198. else if (baud_rate > 30000)
  199. baud_rate = 38400;
  200. else if (baud_rate > 17000)
  201. baud_rate = 19200;
  202. else
  203. (baud_rate = 9600);
  204. // new_clk = new_baud_base/baud_rate
  205. new_clk = new_baud_base / baud_rate;
  206. au_writel(new_clk,
  207.        UART_BASE + UART_CLK +
  208.        i * 0x00100000);
  209. au_sync_delay(10);
  210. }
  211. }
  212. }
  213. /* We don't want _any_ interrupts other than
  214.  * match20. Otherwise our calibrate_delay()
  215.  * calculation will be off, potentially a lot.
  216.  */
  217. intc0_mask = save_local_and_disable(0);
  218. intc1_mask = save_local_and_disable(1);
  219. local_enable_irq(AU1000_TOY_MATCH2_INT);
  220. restore_flags(flags);
  221. calibrate_delay();
  222. restore_local_and_enable(0, intc0_mask);
  223. restore_local_and_enable(1, intc1_mask);
  224. return retval;
  225. }
  226. static struct ctl_table pm_table[] = {
  227. {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, &pm_do_suspend},
  228. {ACPI_SLEEP, "sleep", NULL, 0, 0600, NULL, &pm_do_sleep},
  229. {CTL_ACPI, "freq", NULL, 0, 0600, NULL, &pm_do_freq},
  230. {0}
  231. };
  232. static struct ctl_table pm_dir_table[] = {
  233. {CTL_ACPI, "pm", NULL, 0, 0555, pm_table},
  234. {0}
  235. };
  236. /*
  237.  * Initialize power interface
  238.  */
  239. static int __init pm_init(void)
  240. {
  241. register_sysctl_table(pm_dir_table, 1);
  242. return 0;
  243. }
  244. __initcall(pm_init);
  245. /*
  246.  * This is right out of init/main.c
  247.  */
  248. /* This is the number of bits of precision for the loops_per_jiffy.  Each
  249.    bit takes on average 1.5/HZ seconds.  This (like the original) is a little
  250.    better than 1% */
  251. #define LPS_PREC 8
  252. static void calibrate_delay(void)
  253. {
  254. unsigned long ticks, loopbit;
  255. int lps_precision = LPS_PREC;
  256. loops_per_jiffy = (1 << 12);
  257. while (loops_per_jiffy <<= 1) {
  258. /* wait for "start of" clock tick */
  259. ticks = jiffies;
  260. while (ticks == jiffies)
  261. /* nothing */ ;
  262. /* Go .. */
  263. ticks = jiffies;
  264. __delay(loops_per_jiffy);
  265. ticks = jiffies - ticks;
  266. if (ticks)
  267. break;
  268. }
  269. /* Do a binary approximation to get loops_per_jiffy set to equal one clock
  270.    (up to lps_precision bits) */
  271. loops_per_jiffy >>= 1;
  272. loopbit = loops_per_jiffy;
  273. while (lps_precision-- && (loopbit >>= 1)) {
  274. loops_per_jiffy |= loopbit;
  275. ticks = jiffies;
  276. while (ticks == jiffies);
  277. ticks = jiffies;
  278. __delay(loops_per_jiffy);
  279. if (jiffies != ticks) /* longer than 1 tick */
  280. loops_per_jiffy &= ~loopbit;
  281. }
  282. }
  283. #endif /* CONFIG_PM */