meson-card-utils.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. // SPDX-License-Identifier: GPL-2.0
  2. //
  3. // Copyright (c) 2020 BayLibre, SAS.
  4. // Author: Jerome Brunet <jbrunet@baylibre.com>
  5. #include <linux/module.h>
  6. #include <linux/of_platform.h>
  7. #include <sound/soc.h>
  8. #include "meson-card.h"
  9. int meson_card_i2s_set_sysclk(struct snd_pcm_substream *substream,
  10. struct snd_pcm_hw_params *params,
  11. unsigned int mclk_fs)
  12. {
  13. struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
  14. struct snd_soc_dai *codec_dai;
  15. unsigned int mclk;
  16. int ret, i;
  17. if (!mclk_fs)
  18. return 0;
  19. mclk = params_rate(params) * mclk_fs;
  20. for_each_rtd_codec_dais(rtd, i, codec_dai) {
  21. ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
  22. SND_SOC_CLOCK_IN);
  23. if (ret && ret != -ENOTSUPP)
  24. return ret;
  25. }
  26. ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_cpu(rtd, 0), 0, mclk,
  27. SND_SOC_CLOCK_OUT);
  28. if (ret && ret != -ENOTSUPP)
  29. return ret;
  30. return 0;
  31. }
  32. EXPORT_SYMBOL_GPL(meson_card_i2s_set_sysclk);
  33. int meson_card_reallocate_links(struct snd_soc_card *card,
  34. unsigned int num_links)
  35. {
  36. struct meson_card *priv = snd_soc_card_get_drvdata(card);
  37. struct snd_soc_dai_link *links;
  38. void **ldata;
  39. links = krealloc(priv->card.dai_link,
  40. num_links * sizeof(*priv->card.dai_link),
  41. GFP_KERNEL | __GFP_ZERO);
  42. if (!links)
  43. goto err_links;
  44. ldata = krealloc(priv->link_data,
  45. num_links * sizeof(*priv->link_data),
  46. GFP_KERNEL | __GFP_ZERO);
  47. if (!ldata)
  48. goto err_ldata;
  49. priv->card.dai_link = links;
  50. priv->link_data = ldata;
  51. priv->card.num_links = num_links;
  52. return 0;
  53. err_ldata:
  54. kfree(links);
  55. err_links:
  56. dev_err(priv->card.dev, "failed to allocate links\n");
  57. return -ENOMEM;
  58. }
  59. EXPORT_SYMBOL_GPL(meson_card_reallocate_links);
  60. int meson_card_parse_dai(struct snd_soc_card *card,
  61. struct device_node *node,
  62. struct snd_soc_dai_link_component *dlc)
  63. {
  64. int ret;
  65. if (!dlc || !node)
  66. return -EINVAL;
  67. ret = snd_soc_of_get_dlc(node, NULL, dlc, 0);
  68. if (ret)
  69. return dev_err_probe(card->dev, ret, "can't parse dai\n");
  70. return ret;
  71. }
  72. EXPORT_SYMBOL_GPL(meson_card_parse_dai);
  73. static int meson_card_set_link_name(struct snd_soc_card *card,
  74. struct snd_soc_dai_link *link,
  75. struct device_node *node,
  76. const char *prefix)
  77. {
  78. char *name = devm_kasprintf(card->dev, GFP_KERNEL, "%s.%s",
  79. prefix, node->full_name);
  80. if (!name)
  81. return -ENOMEM;
  82. link->name = name;
  83. link->stream_name = name;
  84. return 0;
  85. }
  86. unsigned int meson_card_parse_daifmt(struct device_node *node,
  87. struct device_node *cpu_node)
  88. {
  89. struct device_node *bitclkmaster = NULL;
  90. struct device_node *framemaster = NULL;
  91. unsigned int daifmt;
  92. daifmt = snd_soc_daifmt_parse_format(node, NULL);
  93. snd_soc_daifmt_parse_clock_provider_as_phandle(node, NULL, &bitclkmaster, &framemaster);
  94. /* If no master is provided, default to cpu master */
  95. if (!bitclkmaster || bitclkmaster == cpu_node) {
  96. daifmt |= (!framemaster || framemaster == cpu_node) ?
  97. SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBS_CFM;
  98. } else {
  99. daifmt |= (!framemaster || framemaster == cpu_node) ?
  100. SND_SOC_DAIFMT_CBM_CFS : SND_SOC_DAIFMT_CBM_CFM;
  101. }
  102. of_node_put(bitclkmaster);
  103. of_node_put(framemaster);
  104. return daifmt;
  105. }
  106. EXPORT_SYMBOL_GPL(meson_card_parse_daifmt);
  107. int meson_card_set_be_link(struct snd_soc_card *card,
  108. struct snd_soc_dai_link *link,
  109. struct device_node *node)
  110. {
  111. struct snd_soc_dai_link_component *codec;
  112. struct device_node *np;
  113. int ret, num_codecs;
  114. num_codecs = of_get_child_count(node);
  115. if (!num_codecs) {
  116. dev_err(card->dev, "be link %s has no codec\n",
  117. node->full_name);
  118. return -EINVAL;
  119. }
  120. codec = devm_kcalloc(card->dev, num_codecs, sizeof(*codec), GFP_KERNEL);
  121. if (!codec)
  122. return -ENOMEM;
  123. link->codecs = codec;
  124. link->num_codecs = num_codecs;
  125. for_each_child_of_node(node, np) {
  126. ret = meson_card_parse_dai(card, np, codec);
  127. if (ret) {
  128. of_node_put(np);
  129. return ret;
  130. }
  131. codec++;
  132. }
  133. ret = meson_card_set_link_name(card, link, node, "be");
  134. if (ret)
  135. dev_err(card->dev, "error setting %pOFn link name\n", np);
  136. return ret;
  137. }
  138. EXPORT_SYMBOL_GPL(meson_card_set_be_link);
  139. int meson_card_set_fe_link(struct snd_soc_card *card,
  140. struct snd_soc_dai_link *link,
  141. struct device_node *node,
  142. bool is_playback)
  143. {
  144. link->codecs = &snd_soc_dummy_dlc;
  145. link->num_codecs = 1;
  146. link->dynamic = 1;
  147. link->dpcm_merged_format = 1;
  148. link->dpcm_merged_chan = 1;
  149. link->dpcm_merged_rate = 1;
  150. if (is_playback)
  151. link->playback_only = 1;
  152. else
  153. link->capture_only = 1;
  154. return meson_card_set_link_name(card, link, node, "fe");
  155. }
  156. EXPORT_SYMBOL_GPL(meson_card_set_fe_link);
  157. static int meson_card_add_links(struct snd_soc_card *card)
  158. {
  159. struct meson_card *priv = snd_soc_card_get_drvdata(card);
  160. struct device_node *node = card->dev->of_node;
  161. struct device_node *np;
  162. int num, i, ret;
  163. num = of_get_child_count(node);
  164. if (!num) {
  165. dev_err(card->dev, "card has no links\n");
  166. return -EINVAL;
  167. }
  168. ret = meson_card_reallocate_links(card, num);
  169. if (ret)
  170. return ret;
  171. i = 0;
  172. for_each_child_of_node(node, np) {
  173. ret = priv->match_data->add_link(card, np, &i);
  174. if (ret) {
  175. of_node_put(np);
  176. return ret;
  177. }
  178. i++;
  179. }
  180. return 0;
  181. }
  182. static int meson_card_parse_of_optional(struct snd_soc_card *card,
  183. const char *propname,
  184. int (*func)(struct snd_soc_card *c,
  185. const char *p))
  186. {
  187. /* If property is not provided, don't fail ... */
  188. if (!of_property_read_bool(card->dev->of_node, propname))
  189. return 0;
  190. /* ... but do fail if it is provided and the parsing fails */
  191. return func(card, propname);
  192. }
  193. static void meson_card_clean_references(struct meson_card *priv)
  194. {
  195. struct snd_soc_card *card = &priv->card;
  196. struct snd_soc_dai_link *link;
  197. struct snd_soc_dai_link_component *codec;
  198. struct snd_soc_aux_dev *aux;
  199. int i, j;
  200. if (card->dai_link) {
  201. for_each_card_prelinks(card, i, link) {
  202. if (link->cpus)
  203. of_node_put(link->cpus->of_node);
  204. for_each_link_codecs(link, j, codec)
  205. of_node_put(codec->of_node);
  206. }
  207. }
  208. if (card->aux_dev) {
  209. for_each_card_pre_auxs(card, i, aux)
  210. of_node_put(aux->dlc.of_node);
  211. }
  212. kfree(card->dai_link);
  213. kfree(priv->link_data);
  214. }
  215. int meson_card_probe(struct platform_device *pdev)
  216. {
  217. const struct meson_card_match_data *data;
  218. struct device *dev = &pdev->dev;
  219. struct meson_card *priv;
  220. int ret;
  221. data = of_device_get_match_data(dev);
  222. if (!data) {
  223. dev_err(dev, "failed to match device\n");
  224. return -ENODEV;
  225. }
  226. priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  227. if (!priv)
  228. return -ENOMEM;
  229. platform_set_drvdata(pdev, priv);
  230. snd_soc_card_set_drvdata(&priv->card, priv);
  231. priv->card.owner = THIS_MODULE;
  232. priv->card.dev = dev;
  233. priv->card.driver_name = dev->driver->name;
  234. priv->match_data = data;
  235. ret = snd_soc_of_parse_card_name(&priv->card, "model");
  236. if (ret < 0)
  237. return ret;
  238. ret = meson_card_parse_of_optional(&priv->card, "audio-routing",
  239. snd_soc_of_parse_audio_routing);
  240. if (ret) {
  241. dev_err(dev, "error while parsing routing\n");
  242. return ret;
  243. }
  244. ret = meson_card_parse_of_optional(&priv->card, "audio-widgets",
  245. snd_soc_of_parse_audio_simple_widgets);
  246. if (ret) {
  247. dev_err(dev, "error while parsing widgets\n");
  248. return ret;
  249. }
  250. ret = meson_card_add_links(&priv->card);
  251. if (ret)
  252. goto out_err;
  253. ret = snd_soc_of_parse_aux_devs(&priv->card, "audio-aux-devs");
  254. if (ret)
  255. goto out_err;
  256. ret = devm_snd_soc_register_card(dev, &priv->card);
  257. if (ret)
  258. goto out_err;
  259. return 0;
  260. out_err:
  261. meson_card_clean_references(priv);
  262. return ret;
  263. }
  264. EXPORT_SYMBOL_GPL(meson_card_probe);
  265. void meson_card_remove(struct platform_device *pdev)
  266. {
  267. struct meson_card *priv = platform_get_drvdata(pdev);
  268. meson_card_clean_references(priv);
  269. }
  270. EXPORT_SYMBOL_GPL(meson_card_remove);
  271. MODULE_DESCRIPTION("Amlogic Sound Card Utils");
  272. MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
  273. MODULE_LICENSE("GPL v2");