simple-card.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. // SPDX-License-Identifier: GPL-2.0
  2. //
  3. // ASoC simple sound card support
  4. //
  5. // Copyright (C) 2012 Renesas Solutions Corp.
  6. // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
  7. #include <linux/clk.h>
  8. #include <linux/device.h>
  9. #include <linux/module.h>
  10. #include <linux/of.h>
  11. #include <linux/platform_device.h>
  12. #include <linux/string.h>
  13. #include <sound/simple_card.h>
  14. #include <sound/soc-dai.h>
  15. #include <sound/soc.h>
  16. struct simple_card_data {
  17. struct snd_soc_card snd_card;
  18. struct simple_dai_props {
  19. struct asoc_simple_dai cpu_dai;
  20. struct asoc_simple_dai codec_dai;
  21. unsigned int mclk_fs;
  22. } *dai_props;
  23. unsigned int mclk_fs;
  24. struct asoc_simple_jack hp_jack;
  25. struct asoc_simple_jack mic_jack;
  26. struct snd_soc_dai_link *dai_link;
  27. };
  28. #define simple_priv_to_card(priv) (&(priv)->snd_card)
  29. #define simple_priv_to_props(priv, i) ((priv)->dai_props + (i))
  30. #define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev)
  31. #define simple_priv_to_link(priv, i) (simple_priv_to_card(priv)->dai_link + (i))
  32. #define DAI "sound-dai"
  33. #define CELL "#sound-dai-cells"
  34. #define PREFIX "simple-audio-card,"
  35. static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
  36. {
  37. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  38. struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
  39. struct simple_dai_props *dai_props =
  40. simple_priv_to_props(priv, rtd->num);
  41. int ret;
  42. ret = asoc_simple_card_clk_enable(&dai_props->cpu_dai);
  43. if (ret)
  44. return ret;
  45. ret = asoc_simple_card_clk_enable(&dai_props->codec_dai);
  46. if (ret)
  47. asoc_simple_card_clk_disable(&dai_props->cpu_dai);
  48. return ret;
  49. }
  50. static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
  51. {
  52. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  53. struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
  54. struct simple_dai_props *dai_props =
  55. simple_priv_to_props(priv, rtd->num);
  56. asoc_simple_card_clk_disable(&dai_props->cpu_dai);
  57. asoc_simple_card_clk_disable(&dai_props->codec_dai);
  58. }
  59. static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai,
  60. unsigned long rate)
  61. {
  62. if (!simple_dai->clk)
  63. return 0;
  64. if (clk_get_rate(simple_dai->clk) == rate)
  65. return 0;
  66. return clk_set_rate(simple_dai->clk, rate);
  67. }
  68. static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
  69. struct snd_pcm_hw_params *params)
  70. {
  71. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  72. struct snd_soc_dai *codec_dai = rtd->codec_dai;
  73. struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
  74. struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
  75. struct simple_dai_props *dai_props =
  76. simple_priv_to_props(priv, rtd->num);
  77. unsigned int mclk, mclk_fs = 0;
  78. int ret = 0;
  79. if (priv->mclk_fs)
  80. mclk_fs = priv->mclk_fs;
  81. else if (dai_props->mclk_fs)
  82. mclk_fs = dai_props->mclk_fs;
  83. if (mclk_fs) {
  84. mclk = params_rate(params) * mclk_fs;
  85. ret = asoc_simple_set_clk_rate(&dai_props->codec_dai, mclk);
  86. if (ret < 0)
  87. return ret;
  88. ret = asoc_simple_set_clk_rate(&dai_props->cpu_dai, mclk);
  89. if (ret < 0)
  90. return ret;
  91. ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
  92. SND_SOC_CLOCK_IN);
  93. if (ret && ret != -ENOTSUPP)
  94. goto err;
  95. ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
  96. SND_SOC_CLOCK_OUT);
  97. if (ret && ret != -ENOTSUPP)
  98. goto err;
  99. }
  100. return 0;
  101. err:
  102. return ret;
  103. }
  104. static const struct snd_soc_ops asoc_simple_card_ops = {
  105. .startup = asoc_simple_card_startup,
  106. .shutdown = asoc_simple_card_shutdown,
  107. .hw_params = asoc_simple_card_hw_params,
  108. };
  109. static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
  110. {
  111. struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
  112. struct snd_soc_dai *codec = rtd->codec_dai;
  113. struct snd_soc_dai *cpu = rtd->cpu_dai;
  114. struct simple_dai_props *dai_props =
  115. simple_priv_to_props(priv, rtd->num);
  116. int ret;
  117. ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai);
  118. if (ret < 0)
  119. return ret;
  120. ret = asoc_simple_card_init_dai(cpu, &dai_props->cpu_dai);
  121. if (ret < 0)
  122. return ret;
  123. return 0;
  124. }
  125. static int asoc_simple_card_dai_link_of(struct device_node *node,
  126. struct simple_card_data *priv,
  127. int idx,
  128. bool is_top_level_node)
  129. {
  130. struct device *dev = simple_priv_to_dev(priv);
  131. struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
  132. struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
  133. struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai;
  134. struct asoc_simple_dai *codec_dai = &dai_props->codec_dai;
  135. struct device_node *cpu = NULL;
  136. struct device_node *plat = NULL;
  137. struct device_node *codec = NULL;
  138. char prop[128];
  139. char *prefix = "";
  140. int ret, single_cpu;
  141. /* For single DAI link & old style of DT node */
  142. if (is_top_level_node)
  143. prefix = PREFIX;
  144. snprintf(prop, sizeof(prop), "%scpu", prefix);
  145. cpu = of_get_child_by_name(node, prop);
  146. if (!cpu) {
  147. ret = -EINVAL;
  148. dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
  149. goto dai_link_of_err;
  150. }
  151. snprintf(prop, sizeof(prop), "%splat", prefix);
  152. plat = of_get_child_by_name(node, prop);
  153. snprintf(prop, sizeof(prop), "%scodec", prefix);
  154. codec = of_get_child_by_name(node, prop);
  155. if (!codec) {
  156. ret = -EINVAL;
  157. dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
  158. goto dai_link_of_err;
  159. }
  160. ret = asoc_simple_card_parse_daifmt(dev, node, codec,
  161. prefix, &dai_link->dai_fmt);
  162. if (ret < 0)
  163. goto dai_link_of_err;
  164. of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs);
  165. ret = asoc_simple_card_parse_cpu(cpu, dai_link,
  166. DAI, CELL, &single_cpu);
  167. if (ret < 0)
  168. goto dai_link_of_err;
  169. ret = asoc_simple_card_parse_codec(codec, dai_link, DAI, CELL);
  170. if (ret < 0)
  171. goto dai_link_of_err;
  172. ret = asoc_simple_card_parse_platform(plat, dai_link, DAI, CELL);
  173. if (ret < 0)
  174. goto dai_link_of_err;
  175. ret = asoc_simple_card_of_parse_tdm(cpu, cpu_dai);
  176. if (ret < 0)
  177. goto dai_link_of_err;
  178. ret = asoc_simple_card_of_parse_tdm(codec, codec_dai);
  179. if (ret < 0)
  180. goto dai_link_of_err;
  181. ret = asoc_simple_card_parse_clk_cpu(dev, cpu, dai_link, cpu_dai);
  182. if (ret < 0)
  183. goto dai_link_of_err;
  184. ret = asoc_simple_card_parse_clk_codec(dev, codec, dai_link, codec_dai);
  185. if (ret < 0)
  186. goto dai_link_of_err;
  187. ret = asoc_simple_card_canonicalize_dailink(dai_link);
  188. if (ret < 0)
  189. goto dai_link_of_err;
  190. ret = asoc_simple_card_set_dailink_name(dev, dai_link,
  191. "%s-%s",
  192. dai_link->cpu_dai_name,
  193. dai_link->codec_dai_name);
  194. if (ret < 0)
  195. goto dai_link_of_err;
  196. dai_link->ops = &asoc_simple_card_ops;
  197. dai_link->init = asoc_simple_card_dai_init;
  198. asoc_simple_card_canonicalize_cpu(dai_link, single_cpu);
  199. dai_link_of_err:
  200. of_node_put(cpu);
  201. of_node_put(codec);
  202. return ret;
  203. }
  204. static int asoc_simple_card_parse_aux_devs(struct device_node *node,
  205. struct simple_card_data *priv)
  206. {
  207. struct device *dev = simple_priv_to_dev(priv);
  208. struct device_node *aux_node;
  209. struct snd_soc_card *card = simple_priv_to_card(priv);
  210. int i, n, len;
  211. if (!of_find_property(node, PREFIX "aux-devs", &len))
  212. return 0; /* Ok to have no aux-devs */
  213. n = len / sizeof(__be32);
  214. if (n <= 0)
  215. return -EINVAL;
  216. card->aux_dev = devm_kcalloc(dev,
  217. n, sizeof(*card->aux_dev), GFP_KERNEL);
  218. if (!card->aux_dev)
  219. return -ENOMEM;
  220. for (i = 0; i < n; i++) {
  221. aux_node = of_parse_phandle(node, PREFIX "aux-devs", i);
  222. if (!aux_node)
  223. return -EINVAL;
  224. card->aux_dev[i].codec_of_node = aux_node;
  225. }
  226. card->num_aux_devs = n;
  227. return 0;
  228. }
  229. static int asoc_simple_card_parse_of(struct simple_card_data *priv)
  230. {
  231. struct device *dev = simple_priv_to_dev(priv);
  232. struct snd_soc_card *card = simple_priv_to_card(priv);
  233. struct device_node *dai_link;
  234. struct device_node *node = dev->of_node;
  235. int ret;
  236. if (!node)
  237. return -EINVAL;
  238. dai_link = of_get_child_by_name(node, PREFIX "dai-link");
  239. ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
  240. if (ret < 0)
  241. goto card_parse_end;
  242. ret = asoc_simple_card_of_parse_routing(card, PREFIX, 1);
  243. if (ret < 0)
  244. goto card_parse_end;
  245. /* Factor to mclk, used in hw_params() */
  246. of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs);
  247. /* Single/Muti DAI link(s) & New style of DT node */
  248. if (dai_link) {
  249. struct device_node *np = NULL;
  250. int i = 0;
  251. for_each_child_of_node(node, np) {
  252. dev_dbg(dev, "\tlink %d:\n", i);
  253. ret = asoc_simple_card_dai_link_of(np, priv,
  254. i, false);
  255. if (ret < 0) {
  256. of_node_put(np);
  257. goto card_parse_end;
  258. }
  259. i++;
  260. }
  261. } else {
  262. /* For single DAI link & old style of DT node */
  263. ret = asoc_simple_card_dai_link_of(node, priv, 0, true);
  264. if (ret < 0)
  265. goto card_parse_end;
  266. }
  267. ret = asoc_simple_card_parse_card_name(card, PREFIX);
  268. if (ret < 0)
  269. goto card_parse_end;
  270. ret = asoc_simple_card_parse_aux_devs(node, priv);
  271. card_parse_end:
  272. of_node_put(dai_link);
  273. return ret;
  274. }
  275. static int asoc_simple_soc_card_probe(struct snd_soc_card *card)
  276. {
  277. struct simple_card_data *priv = snd_soc_card_get_drvdata(card);
  278. int ret;
  279. ret = asoc_simple_card_init_hp(card, &priv->hp_jack, PREFIX);
  280. if (ret < 0)
  281. return ret;
  282. ret = asoc_simple_card_init_mic(card, &priv->mic_jack, PREFIX);
  283. if (ret < 0)
  284. return ret;
  285. return 0;
  286. }
  287. static int asoc_simple_card_probe(struct platform_device *pdev)
  288. {
  289. struct simple_card_data *priv;
  290. struct snd_soc_dai_link *dai_link;
  291. struct simple_dai_props *dai_props;
  292. struct device *dev = &pdev->dev;
  293. struct device_node *np = dev->of_node;
  294. struct snd_soc_card *card;
  295. int num, ret;
  296. /* Get the number of DAI links */
  297. if (np && of_get_child_by_name(np, PREFIX "dai-link"))
  298. num = of_get_child_count(np);
  299. else
  300. num = 1;
  301. /* Allocate the private data and the DAI link array */
  302. priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  303. if (!priv)
  304. return -ENOMEM;
  305. dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL);
  306. dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL);
  307. if (!dai_props || !dai_link)
  308. return -ENOMEM;
  309. priv->dai_props = dai_props;
  310. priv->dai_link = dai_link;
  311. /* Init snd_soc_card */
  312. card = simple_priv_to_card(priv);
  313. card->owner = THIS_MODULE;
  314. card->dev = dev;
  315. card->dai_link = priv->dai_link;
  316. card->num_links = num;
  317. card->probe = asoc_simple_soc_card_probe;
  318. if (np && of_device_is_available(np)) {
  319. ret = asoc_simple_card_parse_of(priv);
  320. if (ret < 0) {
  321. if (ret != -EPROBE_DEFER)
  322. dev_err(dev, "parse error %d\n", ret);
  323. goto err;
  324. }
  325. } else {
  326. struct asoc_simple_card_info *cinfo;
  327. cinfo = dev->platform_data;
  328. if (!cinfo) {
  329. dev_err(dev, "no info for asoc-simple-card\n");
  330. return -EINVAL;
  331. }
  332. if (!cinfo->name ||
  333. !cinfo->codec_dai.name ||
  334. !cinfo->codec ||
  335. !cinfo->platform ||
  336. !cinfo->cpu_dai.name) {
  337. dev_err(dev, "insufficient asoc_simple_card_info settings\n");
  338. return -EINVAL;
  339. }
  340. card->name = (cinfo->card) ? cinfo->card : cinfo->name;
  341. dai_link->name = cinfo->name;
  342. dai_link->stream_name = cinfo->name;
  343. dai_link->platform_name = cinfo->platform;
  344. dai_link->codec_name = cinfo->codec;
  345. dai_link->cpu_dai_name = cinfo->cpu_dai.name;
  346. dai_link->codec_dai_name = cinfo->codec_dai.name;
  347. dai_link->dai_fmt = cinfo->daifmt;
  348. dai_link->init = asoc_simple_card_dai_init;
  349. memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai,
  350. sizeof(priv->dai_props->cpu_dai));
  351. memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai,
  352. sizeof(priv->dai_props->codec_dai));
  353. }
  354. snd_soc_card_set_drvdata(card, priv);
  355. ret = devm_snd_soc_register_card(dev, card);
  356. if (ret < 0)
  357. goto err;
  358. return 0;
  359. err:
  360. asoc_simple_card_clean_reference(card);
  361. return ret;
  362. }
  363. static int asoc_simple_card_remove(struct platform_device *pdev)
  364. {
  365. struct snd_soc_card *card = platform_get_drvdata(pdev);
  366. return asoc_simple_card_clean_reference(card);
  367. }
  368. static const struct of_device_id asoc_simple_of_match[] = {
  369. { .compatible = "simple-audio-card", },
  370. {},
  371. };
  372. MODULE_DEVICE_TABLE(of, asoc_simple_of_match);
  373. static struct platform_driver asoc_simple_card = {
  374. .driver = {
  375. .name = "asoc-simple-card",
  376. .pm = &snd_soc_pm_ops,
  377. .of_match_table = asoc_simple_of_match,
  378. },
  379. .probe = asoc_simple_card_probe,
  380. .remove = asoc_simple_card_remove,
  381. };
  382. module_platform_driver(asoc_simple_card);
  383. MODULE_ALIAS("platform:asoc-simple-card");
  384. MODULE_LICENSE("GPL v2");
  385. MODULE_DESCRIPTION("ASoC Simple Sound Card");
  386. MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");