pd-s3c6410.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. #include <linux/version.h>
  2. #include <linux/kernel.h>
  3. #include <linux/errno.h>
  4. #include <linux/init.h>
  5. #include <linux/list.h>
  6. #include <asm/io.h>
  7. #include <asm/arch/regs-s3c6400-clock.h>
  8. #include <asm/arch/pd.h>
  9. #include "pd-s3c6410.h"
  10. struct pdfw_md pd_md;
  11. static unsigned long pd_get_gate_reg(struct pm_pdtype *pd)
  12. {
  13. return (unsigned long)S3C_NORMAL_CFG;
  14. }
  15. static unsigned long pd_get_blk_pwr_stat_reg(struct pm_pdtype *pd)
  16. {
  17. return (unsigned long)S3C_BLK_PWR_STAT;
  18. }
  19. int s3c_pd_enable(struct pm_pdtype *pd)
  20. {
  21. unsigned long gate_reg;
  22. unsigned long stable_reg;
  23. unsigned long flags;
  24. unsigned long reg;
  25. unsigned int tmp;
  26. gate_reg = pd_get_gate_reg(pd);
  27. stable_reg = pd_get_blk_pwr_stat_reg(pd);
  28. local_irq_save(flags);
  29. reg = __raw_readl(gate_reg);
  30. reg |= pd->ctrlbit;
  31. __raw_writel(reg, gate_reg);
  32. /* here we have to wait until power stabilizes */
  33. while (1) {
  34. tmp = __raw_readl(stable_reg);
  35. if (tmp && pd->stblregbit) break;
  36. }
  37. local_irq_restore(flags);
  38. pd->state = PDSTATE_ON;
  39. return 0;
  40. }
  41. int s3c_pd_disable(struct pm_pdtype *pd)
  42. {
  43. unsigned long gate_reg;
  44. unsigned long flags;
  45. unsigned long reg;
  46. gate_reg = pd_get_gate_reg(pd);
  47. local_irq_save(flags);
  48. reg = __raw_readl(gate_reg);
  49. reg &= ~(pd->ctrlbit);
  50. __raw_writel(reg, gate_reg);
  51. local_irq_restore(flags);
  52. pd->state = PDSTATE_OFF;
  53. return 0;
  54. }
  55. int s3c_pd_state(struct pm_pdtype *pd)
  56. {
  57. unsigned long gate_reg;
  58. unsigned long reg;
  59. gate_reg = pd_get_gate_reg(pd);
  60. reg = __raw_readl(gate_reg);
  61. if (reg & pd->ctrlbit)
  62. return PDSTATE_ON;
  63. else
  64. return PDSTATE_OFF;
  65. }
  66. struct pm_pdtype domain_etm = {
  67. name:"domain_etm",
  68. on: s3c_pd_enable,
  69. off: s3c_pd_disable,
  70. get_hwstate: s3c_pd_state,
  71. ctrlbit: S3C_PWRGATE_DOMAIN_ETM,
  72. stblregbit: S3C_BLK_ETM,
  73. };
  74. struct pm_pdtype domain_v = {
  75. name:"domain_v",
  76. on: s3c_pd_enable,
  77. off: s3c_pd_disable,
  78. get_hwstate: s3c_pd_state,
  79. ctrlbit: S3C_PWRGATE_DOMAIN_V,
  80. stblregbit: S3C_BLK_V,
  81. };
  82. struct pm_pdtype domain_f = {
  83. name:"domain_f",
  84. on: s3c_pd_enable,
  85. off: s3c_pd_disable,
  86. get_hwstate: s3c_pd_state,
  87. ctrlbit: S3C_PWRGATE_DOMAIN_F,
  88. stblregbit: S3C_BLK_F,
  89. };
  90. struct pm_pdtype domain_p = {
  91. name:"domain_p",
  92. on: s3c_pd_enable,
  93. off: s3c_pd_disable,
  94. get_hwstate: s3c_pd_state,
  95. ctrlbit: S3C_PWRGATE_DOMAIN_P,
  96. stblregbit: S3C_BLK_P,
  97. };
  98. struct pm_pdtype domain_i = {
  99. name:"domain_i",
  100. on: s3c_pd_enable,
  101. off: s3c_pd_disable,
  102. get_hwstate: s3c_pd_state,
  103. ctrlbit: S3C_PWRGATE_DOMAIN_I,
  104. stblregbit: S3C_BLK_I,
  105. };
  106. struct pm_pdtype domain_s = {
  107. name:"domain_s",
  108. on: s3c_pd_enable,
  109. off: s3c_pd_disable,
  110. get_hwstate: s3c_pd_state,
  111. ctrlbit: S3C_PWRGATE_DOMAIN_S,
  112. stblregbit: S3C_BLK_S,
  113. };
  114. void init_pd(struct pm_pdtype *pd)
  115. {
  116. /* Set initial power state to ON:
  117. power is required until driver probe() are done */
  118. pd->state = PDSTATE_ON;
  119. INIT_LIST_HEAD(&(pd->entry));
  120. INIT_LIST_HEAD(&(pd->devhead));
  121. }
  122. /*
  123. * Initialize power domain structs
  124. */
  125. void s3c6400_init_powerdomain(void)
  126. {
  127. init_pd(&domain_etm);
  128. init_pd(&domain_v);
  129. init_pd(&domain_f);
  130. init_pd(&domain_p);
  131. init_pd(&domain_i);
  132. init_pd(&domain_s);
  133. list_add_tail(&domain_etm.entry, &pd_head);
  134. list_add_tail(&domain_v.entry, &pd_head);
  135. list_add_tail(&domain_f.entry, &pd_head);
  136. list_add_tail(&domain_p.entry, &pd_head);
  137. list_add_tail(&domain_i.entry, &pd_head);
  138. list_add_tail(&domain_s.entry, &pd_head);
  139. }
  140. void s3c6400_cleanup_powerdomain(void)
  141. {
  142. }
  143. /* solve discrepancies between actual system state
  144. and what is recorded in the pdfw data structures */
  145. void s3c6400_sync_powerdomain(void)
  146. {
  147. struct list_head *t1, *t2;
  148. struct pm_pdtype *pd;
  149. struct pm_devtype *pdev;
  150. list_for_each(t1, &pd_head) {
  151. pd = list_entry(t1, struct pm_pdtype, entry);
  152. if (pd->get_hwstate && (pd->state != pd->get_hwstate(pd))) {
  153. printk(KERN_WARNING "%s:PDSTATE not in sync\n",pd->name);
  154. pd->state = pd->get_hwstate(pd);
  155. if (pd->state == PDSTATE_ON) {
  156. list_for_each(t2, &pd->devhead) {
  157. pdev = list_entry(t2, struct pm_devtype, entry);
  158. if (pdev->after_pdon)
  159. pdev->after_pdon();
  160. }
  161. }
  162. }
  163. }
  164. }
  165. #ifdef CONFIG_S3C6400_PDFW_PROC
  166. #include <linux/proc_fs.h>
  167. #include <asm/uaccess.h>
  168. static struct proc_dir_entry* s3c6400_pd_proc = NULL;
  169. int s3c6400_pd_write_proc(struct file* file, const char* buffer,
  170. unsigned long count, void* data)
  171. {
  172. char buf[100];
  173. unsigned int tmp;
  174. int size = count;
  175. if (size >= sizeof(buf))
  176. size = sizeof(buf) - 1;
  177. memset(buf, 0, sizeof(buf));
  178. copy_from_user(buf, buffer, size);
  179. buf[size] = '\0';
  180. tmp = simple_strtol(buf, NULL, 16);
  181. __raw_writel(tmp, S3C_NORMAL_CFG);
  182. s3c6400_sync_powerdomain();
  183. return count;
  184. }
  185. int s3c6400_pd_read_proc(char* page, char** start, off_t off, int count,
  186. int *eof, void *data)
  187. {
  188. char *i = page;
  189. unsigned int reg;
  190. reg = __raw_readl(S3C_NORMAL_CFG);
  191. i += sprintf(i, "0x%X\n", reg);
  192. *start = NULL;
  193. *eof = 1;
  194. return (i - page);
  195. }
  196. #endif /* CONFIG_S3C6400_PDFW_PROC */
  197. int __init s3c6400_pdfw_init(void)
  198. {
  199. #ifdef CONFIG_S3C6400_PDFW_PROC
  200. struct proc_dir_entry *tmp;
  201. s3c6400_pd_proc = proc_mkdir("pd", NULL);
  202. if (s3c6400_pd_proc != NULL) {
  203. tmp = create_proc_entry("gatereg", 0, s3c6400_pd_proc);
  204. if (tmp) {
  205. tmp->write_proc = s3c6400_pd_write_proc;
  206. tmp->read_proc = s3c6400_pd_read_proc;
  207. }
  208. }
  209. #endif
  210. pd_md.init = s3c6400_init_powerdomain;
  211. pd_md.cleanup = s3c6400_cleanup_powerdomain;
  212. pd_md.sync = s3c6400_sync_powerdomain;
  213. printk(KERN_INFO "s3c6400_pdfw_init done\n");
  214. return 0;
  215. }
  216. arch_initcall(s3c6400_pdfw_init);