soc-of-simple.c 4.3 KB

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