audio_slimslave.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. /* Copyright (c) 2013-2014, 2017 The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. */
  12. #include <linux/init.h>
  13. #include <linux/module.h>
  14. #include <linux/fs.h>
  15. #include <linux/device.h>
  16. #include <linux/mutex.h>
  17. #include <linux/miscdevice.h>
  18. #include <sound/audio_slimslave.h>
  19. #include <linux/slimbus/slimbus.h>
  20. #include <linux/pm_runtime.h>
  21. static struct slim_device *slim;
  22. static int vote_count;
  23. struct mutex suspend_lock;
  24. bool suspend;
  25. static int audio_slim_open(struct inode *inode, struct file *file)
  26. {
  27. pr_debug("%s:\n", __func__);
  28. if (vote_count) {
  29. pr_debug("%s: unvote: vote_count=%d\n", __func__, vote_count);
  30. pm_runtime_mark_last_busy(slim->dev.parent);
  31. pm_runtime_put(slim->dev.parent);
  32. vote_count--;
  33. }
  34. return 0;
  35. };
  36. static int audio_slim_release(struct inode *inode, struct file *file)
  37. {
  38. pr_debug("%s:\n", __func__);
  39. if (vote_count) {
  40. pr_debug("%s: unvote: vote_count=%d\n", __func__, vote_count);
  41. pm_runtime_mark_last_busy(slim->dev.parent);
  42. pm_runtime_put(slim->dev.parent);
  43. vote_count--;
  44. } else {
  45. pr_debug("%s: vote: vote_count=%d\n", __func__, vote_count);
  46. pm_runtime_get_sync(slim->dev.parent);
  47. vote_count++;
  48. }
  49. return 0;
  50. };
  51. static long audio_slim_ioctl(struct file *file, unsigned int cmd,
  52. unsigned long u_arg)
  53. {
  54. switch (cmd) {
  55. case AUDIO_SLIMSLAVE_VOTE:
  56. mutex_lock(&suspend_lock);
  57. if (!vote_count && !suspend) {
  58. pr_debug("%s:AUDIO_SLIMSLAVE_VOTE\n", __func__);
  59. pm_runtime_get_sync(slim->dev.parent);
  60. vote_count++;
  61. } else {
  62. pr_err("%s:Invalid vote: vote_count=%d suspend=%d\n",
  63. __func__, vote_count, suspend);
  64. }
  65. mutex_unlock(&suspend_lock);
  66. break;
  67. case AUDIO_SLIMSLAVE_UNVOTE:
  68. mutex_lock(&suspend_lock);
  69. if (vote_count && !suspend) {
  70. pr_debug("%s:AUDIO_SLIMSLAVE_UNVOTE\n", __func__);
  71. pm_runtime_mark_last_busy(slim->dev.parent);
  72. pm_runtime_put(slim->dev.parent);
  73. vote_count--;
  74. } else {
  75. pr_err("%s:Invalid unvote: vote_count=%d suspend=%d\n",
  76. __func__, vote_count, suspend);
  77. }
  78. mutex_unlock(&suspend_lock);
  79. break;
  80. default:
  81. pr_debug("%s: Invalid ioctl cmd: %d\n", __func__, cmd);
  82. break;
  83. }
  84. return 0;
  85. }
  86. static const struct file_operations audio_slimslave_fops = {
  87. .open = audio_slim_open,
  88. .unlocked_ioctl = audio_slim_ioctl,
  89. .release = audio_slim_release,
  90. };
  91. struct miscdevice audio_slimslave_misc = {
  92. .minor = MISC_DYNAMIC_MINOR,
  93. .name = AUDIO_SLIMSLAVE_IOCTL_NAME,
  94. .fops = &audio_slimslave_fops,
  95. };
  96. static int audio_slimslave_probe(struct slim_device *audio_slim)
  97. {
  98. pr_debug("%s:\n", __func__);
  99. mutex_init(&suspend_lock);
  100. suspend = false;
  101. slim = audio_slim;
  102. misc_register(&audio_slimslave_misc);
  103. return 0;
  104. }
  105. static int audio_slimslave_remove(struct slim_device *audio_slim)
  106. {
  107. pr_debug("%s:\n", __func__);
  108. misc_deregister(&audio_slimslave_misc);
  109. return 0;
  110. }
  111. static int audio_slimslave_resume(struct slim_device *audio_slim)
  112. {
  113. pr_debug("%s:\n", __func__);
  114. mutex_lock(&suspend_lock);
  115. suspend = false;
  116. mutex_unlock(&suspend_lock);
  117. return 0;
  118. }
  119. static int audio_slimslave_suspend(struct slim_device *audio_slim,
  120. pm_message_t pmesg)
  121. {
  122. pr_debug("%s:\n", __func__);
  123. mutex_lock(&suspend_lock);
  124. suspend = true;
  125. mutex_unlock(&suspend_lock);
  126. return 0;
  127. }
  128. static const struct slim_device_id audio_slimslave_dt_match[] = {
  129. {"audio-slimslave", 0},
  130. {}
  131. };
  132. static struct slim_driver audio_slimslave_driver = {
  133. .driver = {
  134. .name = "audio-slimslave",
  135. .owner = THIS_MODULE,
  136. },
  137. .probe = audio_slimslave_probe,
  138. .remove = audio_slimslave_remove,
  139. .id_table = audio_slimslave_dt_match,
  140. .resume = audio_slimslave_resume,
  141. .suspend = audio_slimslave_suspend,
  142. };
  143. int __init audio_slimslave_init(void)
  144. {
  145. return slim_driver_register(&audio_slimslave_driver);
  146. }
  147. void audio_slimslave_exit(void)
  148. {
  149. }
  150. /* Module information */
  151. MODULE_DESCRIPTION("Audio side Slimbus slave driver");
  152. MODULE_LICENSE("GPL v2");