pd.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. #include <linux/version.h>
  2. #include <linux/module.h>
  3. #if defined(MODVERSIONS)
  4. #include <linux/modversions.h>
  5. #endif
  6. #include <linux/kernel.h>
  7. #include <linux/init.h>
  8. #include <linux/list.h>
  9. #include <linux/string.h>
  10. #include <linux/errno.h>
  11. #include <asm/arch/pd.h>
  12. LIST_HEAD(pd_head);
  13. /* This is a device-to-powerdomain mapper table for fast searching */
  14. struct pm_pdtype *pd_hashtbl[MAX_PMDEVS];
  15. void init_pd_hashtbl(void)
  16. {
  17. int i;
  18. for(i=0; i<MAX_PMDEVS; i++) {
  19. pd_hashtbl[i] = NULL;
  20. }
  21. }
  22. int get_free_devid(void)
  23. {
  24. int i;
  25. for(i=1; i<MAX_PMDEVS; i++) {
  26. if (pd_hashtbl[i] == NULL)
  27. return i;
  28. }
  29. return -EINVAL;
  30. }
  31. /*
  32. * Register a device with the power domain subsystem
  33. * struct pm_devtype * dev: device to register
  34. * const char * pd_name: name of the power domain to register
  35. */
  36. int pd_register_dev(struct pm_devtype *dev, const char *pd_name)
  37. {
  38. struct list_head *temp;
  39. struct pm_pdtype *pd;
  40. /* search for the power domain that this device belongs to */
  41. list_for_each(temp, &pd_head) {
  42. pd = list_entry(temp, struct pm_pdtype, entry);
  43. if (!strcmp(pd_name, pd->name)) {
  44. dev->devid = get_free_devid();
  45. if (dev->devid < 0) {
  46. printk(KERN_WARNING "Too many devices\n");
  47. return -EINVAL;
  48. }
  49. dev->pd = pd;
  50. pd_hashtbl[dev->devid] = pd;
  51. list_add_tail(&dev->entry, &pd->devhead);
  52. return dev->devid;
  53. }
  54. }
  55. /* We only get here when we can't find this device's power domain */
  56. printk(KERN_WARNING "can't find this device's pd\n");
  57. return -EINVAL;
  58. }
  59. int pd_unregister_dev(struct pm_devtype *dev)
  60. {
  61. pd_hashtbl[dev->devid] = NULL; // free devid
  62. dev->devid = 0;
  63. list_del_init(&dev->entry);
  64. return 0;
  65. }
  66. int pd_on(struct pm_pdtype *pd)
  67. {
  68. struct list_head *temp;
  69. struct pm_devtype *pdev;
  70. int ret = 0;
  71. /* supply power */
  72. if (pd->on) {
  73. ret = pd->on(pd); // redirect to machine dependent code
  74. /* resume all devices in this power domain */
  75. list_for_each(temp, &pd->devhead) {
  76. pdev = list_entry(temp, struct pm_devtype, entry);
  77. /* do initialization if needed */
  78. if (pdev->after_pdon)
  79. pdev->after_pdon();
  80. }
  81. }
  82. /* we assume pd is always on if no pd->on is defined */
  83. return ret;
  84. }
  85. int pd_off(struct pm_pdtype *pd)
  86. {
  87. struct list_head *temp;
  88. struct pm_devtype *pdev;
  89. if (pd->off) {
  90. /* suspend all devices in this power domain */
  91. list_for_each(temp, &pd->devhead) {
  92. pdev = list_entry(temp, struct pm_devtype, entry);
  93. /* saving device context */
  94. if (pdev->before_pdoff)
  95. pdev->before_pdoff();
  96. }
  97. return pd->off(pd);
  98. }
  99. /* cannot turn off since no pd->off is defined */
  100. return -EINVAL;
  101. }
  102. int pd_sync(struct pm_pdtype *pd)
  103. {
  104. pd_md_sync();
  105. printk(KERN_INFO "pdfw synchronized\n");
  106. return 0;
  107. }
  108. int __init pd_init(void)
  109. {
  110. /* initialize machine dependent data structure */
  111. init_pd_hashtbl();
  112. pd_md_init();
  113. pd_md_sync();
  114. printk(KERN_INFO "Power Domain Framework initialized\n");
  115. return 0;
  116. }
  117. void __exit pd_exit(void)
  118. {
  119. pd_md_cleanup();
  120. return;
  121. }
  122. #ifdef MODULE
  123. module_init(pd_init);
  124. module_exit(pd_exit);
  125. #else
  126. __initcall(pd_init);
  127. #endif
  128. EXPORT_SYMBOL(pd_register_dev);
  129. EXPORT_SYMBOL(pd_unregister_dev);
  130. EXPORT_SYMBOL(pd_on);
  131. EXPORT_SYMBOL(pd_off);
  132. EXPORT_SYMBOL(pd_sync);
  133. EXPORT_SYMBOL(pd_head);
  134. EXPORT_SYMBOL(pd_hashtbl);
  135. MODULE_AUTHOR("Ikhwan Lee");
  136. MODULE_LICENSE("Dual BSD/GPL");