soc-of-simple.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /*
  2. * OF helpers for ALSA SoC Layer
  3. *
  4. * Copyright (C) 2008, Secret Lab Technologies Ltd.
  5. */
  6. #include <linux/module.h>
  7. #include <linux/moduleparam.h>
  8. #include <linux/init.h>
  9. #include <linux/delay.h>
  10. #include <linux/pm.h>
  11. #include <linux/bitops.h>
  12. #include <linux/platform_device.h>
  13. #include <linux/of.h>
  14. #include <sound/core.h>
  15. #include <sound/pcm.h>
  16. #include <sound/pcm_params.h>
  17. #include <sound/soc.h>
  18. #include <sound/soc-of-simple.h>
  19. #include <sound/initval.h>
  20. MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
  21. MODULE_LICENSE("GPL");
  22. MODULE_DESCRIPTION("ALSA SoC OpenFirmware bindings");
  23. static DEFINE_MUTEX(of_snd_soc_mutex);
  24. static LIST_HEAD(of_snd_soc_device_list);
  25. static int of_snd_soc_next_index;
  26. struct of_snd_soc_device {
  27. int id;
  28. struct list_head list;
  29. struct snd_soc_device device;
  30. struct snd_soc_card card;
  31. struct snd_soc_dai_link dai_link;
  32. struct platform_device *pdev;
  33. struct device_node *platform_node;
  34. struct device_node *codec_node;
  35. };
  36. static struct snd_soc_ops of_snd_soc_ops = {
  37. };
  38. static struct of_snd_soc_device *
  39. of_snd_soc_get_device(struct device_node *codec_node)
  40. {
  41. struct of_snd_soc_device *of_soc;
  42. list_for_each_entry(of_soc, &of_snd_soc_device_list, list) {
  43. if (of_soc->codec_node == codec_node)
  44. return of_soc;
  45. }
  46. of_soc = kzalloc(sizeof(struct of_snd_soc_device), GFP_KERNEL);
  47. if (!of_soc)
  48. return NULL;
  49. /* Initialize the structure and add it to the global list */
  50. of_soc->codec_node = codec_node;
  51. of_soc->id = of_snd_soc_next_index++;
  52. of_soc->card.dai_link = &of_soc->dai_link;
  53. of_soc->card.num_links = 1;
  54. of_soc->device.card = &of_soc->card;
  55. of_soc->dai_link.ops = &of_snd_soc_ops;
  56. list_add(&of_soc->list, &of_snd_soc_device_list);
  57. return of_soc;
  58. }
  59. static void of_snd_soc_register_device(struct of_snd_soc_device *of_soc)
  60. {
  61. struct platform_device *pdev;
  62. int rc;
  63. /* Only register the device if both the codec and platform have
  64. * been registered */
  65. if ((!of_soc->device.codec_data) || (!of_soc->platform_node))
  66. return;
  67. pr_info("platform<-->codec match achieved; registering machine\n");
  68. pdev = platform_device_alloc("soc-audio", of_soc->id);
  69. if (!pdev) {
  70. pr_err("of_soc: platform_device_alloc() failed\n");
  71. return;
  72. }
  73. pdev->dev.platform_data = of_soc;
  74. platform_set_drvdata(pdev, &of_soc->device);
  75. of_soc->device.dev = &pdev->dev;
  76. /* The ASoC device is complete; register it */
  77. rc = platform_device_add(pdev);
  78. if (rc) {
  79. pr_err("of_soc: platform_device_add() failed\n");
  80. return;
  81. }
  82. }
  83. int of_snd_soc_register_codec(struct snd_soc_codec_device *codec_dev,
  84. void *codec_data, struct snd_soc_dai *dai,
  85. struct device_node *node)
  86. {
  87. struct of_snd_soc_device *of_soc;
  88. int rc = 0;
  89. pr_info("registering ASoC codec driver: %s\n", node->full_name);
  90. mutex_lock(&of_snd_soc_mutex);
  91. of_soc = of_snd_soc_get_device(node);
  92. if (!of_soc) {
  93. rc = -ENOMEM;
  94. goto out;
  95. }
  96. /* Store the codec data */
  97. of_soc->device.codec_data = codec_data;
  98. of_soc->device.codec_dev = codec_dev;
  99. of_soc->dai_link.name = (char *)node->name;
  100. of_soc->dai_link.stream_name = (char *)node->name;
  101. of_soc->dai_link.codec_dai = dai;
  102. /* Now try to register the SoC device */
  103. of_snd_soc_register_device(of_soc);
  104. out:
  105. mutex_unlock(&of_snd_soc_mutex);
  106. return rc;
  107. }
  108. EXPORT_SYMBOL_GPL(of_snd_soc_register_codec);
  109. int of_snd_soc_register_platform(struct snd_soc_platform *platform,
  110. struct device_node *node,
  111. struct snd_soc_dai *cpu_dai)
  112. {
  113. struct of_snd_soc_device *of_soc;
  114. struct device_node *codec_node;
  115. const phandle *handle;
  116. int len, rc = 0;
  117. pr_info("registering ASoC platform driver: %s\n", node->full_name);
  118. handle = of_get_property(node, "codec-handle", &len);
  119. if (!handle || len < sizeof(handle))
  120. return -ENODEV;
  121. codec_node = of_find_node_by_phandle(*handle);
  122. if (!codec_node)
  123. return -ENODEV;
  124. pr_info("looking for codec: %s\n", codec_node->full_name);
  125. mutex_lock(&of_snd_soc_mutex);
  126. of_soc = of_snd_soc_get_device(codec_node);
  127. if (!of_soc) {
  128. rc = -ENOMEM;
  129. goto out;
  130. }
  131. of_soc->platform_node = node;
  132. of_soc->dai_link.cpu_dai = cpu_dai;
  133. of_soc->card.platform = platform;
  134. of_soc->card.name = of_soc->dai_link.cpu_dai->name;
  135. /* Now try to register the SoC device */
  136. of_snd_soc_register_device(of_soc);
  137. out:
  138. mutex_unlock(&of_snd_soc_mutex);
  139. return rc;
  140. }
  141. EXPORT_SYMBOL_GPL(of_snd_soc_register_platform);