simple-card.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. /*
  2. * ASoC simple sound card support
  3. *
  4. * Copyright (C) 2012 Renesas Solutions Corp.
  5. * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. */
  11. #include <linux/clk.h>
  12. #include <linux/device.h>
  13. #include <linux/module.h>
  14. #include <linux/of.h>
  15. #include <linux/platform_device.h>
  16. #include <linux/string.h>
  17. #include <sound/simple_card.h>
  18. #include <sound/soc-dai.h>
  19. #include <sound/soc.h>
  20. struct simple_card_data {
  21. struct snd_soc_card snd_card;
  22. struct simple_dai_props {
  23. struct asoc_simple_dai cpu_dai;
  24. struct asoc_simple_dai codec_dai;
  25. } *dai_props;
  26. unsigned int mclk_fs;
  27. struct snd_soc_dai_link dai_link[]; /* dynamically allocated */
  28. };
  29. static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
  30. struct snd_pcm_hw_params *params)
  31. {
  32. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  33. struct snd_soc_dai *codec_dai = rtd->codec_dai;
  34. struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
  35. unsigned int mclk;
  36. int ret = 0;
  37. if (priv->mclk_fs) {
  38. mclk = params_rate(params) * priv->mclk_fs;
  39. ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
  40. SND_SOC_CLOCK_IN);
  41. }
  42. return ret;
  43. }
  44. static struct snd_soc_ops asoc_simple_card_ops = {
  45. .hw_params = asoc_simple_card_hw_params,
  46. };
  47. static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai,
  48. struct asoc_simple_dai *set)
  49. {
  50. int ret;
  51. if (set->fmt) {
  52. ret = snd_soc_dai_set_fmt(dai, set->fmt);
  53. if (ret && ret != -ENOTSUPP) {
  54. dev_err(dai->dev, "simple-card: set_fmt error\n");
  55. goto err;
  56. }
  57. }
  58. if (set->sysclk) {
  59. ret = snd_soc_dai_set_sysclk(dai, 0, set->sysclk, 0);
  60. if (ret && ret != -ENOTSUPP) {
  61. dev_err(dai->dev, "simple-card: set_sysclk error\n");
  62. goto err;
  63. }
  64. }
  65. if (set->slots) {
  66. ret = snd_soc_dai_set_tdm_slot(dai, 0, 0,
  67. set->slots,
  68. set->slot_width);
  69. if (ret && ret != -ENOTSUPP) {
  70. dev_err(dai->dev, "simple-card: set_tdm_slot error\n");
  71. goto err;
  72. }
  73. }
  74. ret = 0;
  75. err:
  76. return ret;
  77. }
  78. static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
  79. {
  80. struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
  81. struct snd_soc_dai *codec = rtd->codec_dai;
  82. struct snd_soc_dai *cpu = rtd->cpu_dai;
  83. struct simple_dai_props *dai_props;
  84. int num, ret;
  85. num = rtd - rtd->card->rtd;
  86. dai_props = &priv->dai_props[num];
  87. ret = __asoc_simple_card_dai_init(codec, &dai_props->codec_dai);
  88. if (ret < 0)
  89. return ret;
  90. ret = __asoc_simple_card_dai_init(cpu, &dai_props->cpu_dai);
  91. if (ret < 0)
  92. return ret;
  93. return 0;
  94. }
  95. static int
  96. asoc_simple_card_sub_parse_of(struct device_node *np,
  97. struct asoc_simple_dai *dai,
  98. const struct device_node **p_node,
  99. const char **name)
  100. {
  101. struct device_node *node;
  102. struct clk *clk;
  103. int ret;
  104. /*
  105. * get node via "sound-dai = <&phandle port>"
  106. * it will be used as xxx_of_node on soc_bind_dai_link()
  107. */
  108. node = of_parse_phandle(np, "sound-dai", 0);
  109. if (!node)
  110. return -ENODEV;
  111. *p_node = node;
  112. /* get dai->name */
  113. ret = snd_soc_of_get_dai_name(np, name);
  114. if (ret < 0)
  115. return ret;
  116. /* parse TDM slot */
  117. ret = snd_soc_of_parse_tdm_slot(np, &dai->slots, &dai->slot_width);
  118. if (ret)
  119. return ret;
  120. /*
  121. * dai->sysclk come from
  122. * "clocks = <&xxx>" (if system has common clock)
  123. * or "system-clock-frequency = <xxx>"
  124. * or device's module clock.
  125. */
  126. if (of_property_read_bool(np, "clocks")) {
  127. clk = of_clk_get(np, 0);
  128. if (IS_ERR(clk)) {
  129. ret = PTR_ERR(clk);
  130. return ret;
  131. }
  132. dai->sysclk = clk_get_rate(clk);
  133. } else if (of_property_read_bool(np, "system-clock-frequency")) {
  134. of_property_read_u32(np,
  135. "system-clock-frequency",
  136. &dai->sysclk);
  137. } else {
  138. clk = of_clk_get(node, 0);
  139. if (!IS_ERR(clk))
  140. dai->sysclk = clk_get_rate(clk);
  141. }
  142. return 0;
  143. }
  144. static int simple_card_dai_link_of(struct device_node *node,
  145. struct device *dev,
  146. struct snd_soc_dai_link *dai_link,
  147. struct simple_dai_props *dai_props,
  148. bool is_top_level_node)
  149. {
  150. struct device_node *np = NULL;
  151. struct device_node *bitclkmaster = NULL;
  152. struct device_node *framemaster = NULL;
  153. unsigned int daifmt;
  154. char *name;
  155. char prop[128];
  156. char *prefix = "";
  157. int ret;
  158. if (is_top_level_node)
  159. prefix = "simple-audio-card,";
  160. daifmt = snd_soc_of_parse_daifmt(node, prefix,
  161. &bitclkmaster, &framemaster);
  162. daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
  163. snprintf(prop, sizeof(prop), "%scpu", prefix);
  164. np = of_get_child_by_name(node, prop);
  165. if (!np) {
  166. ret = -EINVAL;
  167. dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
  168. goto dai_link_of_err;
  169. }
  170. ret = asoc_simple_card_sub_parse_of(np, &dai_props->cpu_dai,
  171. &dai_link->cpu_of_node,
  172. &dai_link->cpu_dai_name);
  173. if (ret < 0)
  174. goto dai_link_of_err;
  175. dai_props->cpu_dai.fmt = daifmt;
  176. switch (((np == bitclkmaster) << 4) | (np == framemaster)) {
  177. case 0x11:
  178. dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBS_CFS;
  179. break;
  180. case 0x10:
  181. dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBS_CFM;
  182. break;
  183. case 0x01:
  184. dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBM_CFS;
  185. break;
  186. default:
  187. dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBM_CFM;
  188. break;
  189. }
  190. of_node_put(np);
  191. snprintf(prop, sizeof(prop), "%scodec", prefix);
  192. np = of_get_child_by_name(node, prop);
  193. if (!np) {
  194. ret = -EINVAL;
  195. dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
  196. goto dai_link_of_err;
  197. }
  198. ret = asoc_simple_card_sub_parse_of(np, &dai_props->codec_dai,
  199. &dai_link->codec_of_node,
  200. &dai_link->codec_dai_name);
  201. if (ret < 0)
  202. goto dai_link_of_err;
  203. if (strlen(prefix) && !bitclkmaster && !framemaster) {
  204. /* No dai-link level and master setting was not found from
  205. sound node level, revert back to legacy DT parsing and
  206. take the settings from codec node. */
  207. dev_dbg(dev, "%s: Revert to legacy daifmt parsing\n",
  208. __func__);
  209. dai_props->cpu_dai.fmt = dai_props->codec_dai.fmt =
  210. snd_soc_of_parse_daifmt(np, NULL, NULL, NULL) |
  211. (daifmt & ~SND_SOC_DAIFMT_CLOCK_MASK);
  212. } else {
  213. dai_props->codec_dai.fmt = daifmt;
  214. switch (((np == bitclkmaster) << 4) | (np == framemaster)) {
  215. case 0x11:
  216. dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBM_CFM;
  217. break;
  218. case 0x10:
  219. dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBM_CFS;
  220. break;
  221. case 0x01:
  222. dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBS_CFM;
  223. break;
  224. default:
  225. dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBS_CFS;
  226. break;
  227. }
  228. }
  229. if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) {
  230. ret = -EINVAL;
  231. goto dai_link_of_err;
  232. }
  233. /* simple-card assumes platform == cpu */
  234. dai_link->platform_of_node = dai_link->cpu_of_node;
  235. /* Link name is created from CPU/CODEC dai name */
  236. name = devm_kzalloc(dev,
  237. strlen(dai_link->cpu_dai_name) +
  238. strlen(dai_link->codec_dai_name) + 2,
  239. GFP_KERNEL);
  240. sprintf(name, "%s-%s", dai_link->cpu_dai_name,
  241. dai_link->codec_dai_name);
  242. dai_link->name = dai_link->stream_name = name;
  243. dai_link->ops = &asoc_simple_card_ops;
  244. dev_dbg(dev, "\tname : %s\n", dai_link->stream_name);
  245. dev_dbg(dev, "\tcpu : %s / %04x / %d\n",
  246. dai_link->cpu_dai_name,
  247. dai_props->cpu_dai.fmt,
  248. dai_props->cpu_dai.sysclk);
  249. dev_dbg(dev, "\tcodec : %s / %04x / %d\n",
  250. dai_link->codec_dai_name,
  251. dai_props->codec_dai.fmt,
  252. dai_props->codec_dai.sysclk);
  253. dai_link_of_err:
  254. if (np)
  255. of_node_put(np);
  256. if (bitclkmaster)
  257. of_node_put(bitclkmaster);
  258. if (framemaster)
  259. of_node_put(framemaster);
  260. return ret;
  261. }
  262. static int asoc_simple_card_parse_of(struct device_node *node,
  263. struct simple_card_data *priv,
  264. struct device *dev,
  265. int multi)
  266. {
  267. struct snd_soc_dai_link *dai_link = priv->snd_card.dai_link;
  268. struct simple_dai_props *dai_props = priv->dai_props;
  269. int ret;
  270. /* parsing the card name from DT */
  271. snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name");
  272. /* off-codec widgets */
  273. if (of_property_read_bool(node, "simple-audio-card,widgets")) {
  274. ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card,
  275. "simple-audio-card,widgets");
  276. if (ret)
  277. return ret;
  278. }
  279. /* DAPM routes */
  280. if (of_property_read_bool(node, "simple-audio-card,routing")) {
  281. ret = snd_soc_of_parse_audio_routing(&priv->snd_card,
  282. "simple-audio-card,routing");
  283. if (ret)
  284. return ret;
  285. }
  286. /* Factor to mclk, used in hw_params() */
  287. of_property_read_u32(node, "simple-audio-card,mclk-fs",
  288. &priv->mclk_fs);
  289. dev_dbg(dev, "New simple-card: %s\n", priv->snd_card.name ?
  290. priv->snd_card.name : "");
  291. if (multi) {
  292. struct device_node *np = NULL;
  293. int i;
  294. for (i = 0; (np = of_get_next_child(node, np)); i++) {
  295. dev_dbg(dev, "\tlink %d:\n", i);
  296. ret = simple_card_dai_link_of(np, dev, dai_link + i,
  297. dai_props + i, false);
  298. if (ret < 0) {
  299. of_node_put(np);
  300. return ret;
  301. }
  302. }
  303. } else {
  304. ret = simple_card_dai_link_of(node, dev, dai_link, dai_props,
  305. true);
  306. if (ret < 0)
  307. return ret;
  308. }
  309. if (!priv->snd_card.name)
  310. priv->snd_card.name = priv->snd_card.dai_link->name;
  311. return 0;
  312. }
  313. /* update the reference count of the devices nodes at end of probe */
  314. static int asoc_simple_card_unref(struct platform_device *pdev)
  315. {
  316. struct snd_soc_card *card = platform_get_drvdata(pdev);
  317. struct snd_soc_dai_link *dai_link;
  318. struct device_node *np;
  319. int num_links;
  320. for (num_links = 0, dai_link = card->dai_link;
  321. num_links < card->num_links;
  322. num_links++, dai_link++) {
  323. np = (struct device_node *) dai_link->cpu_of_node;
  324. if (np)
  325. of_node_put(np);
  326. np = (struct device_node *) dai_link->codec_of_node;
  327. if (np)
  328. of_node_put(np);
  329. }
  330. return 0;
  331. }
  332. static int asoc_simple_card_probe(struct platform_device *pdev)
  333. {
  334. struct simple_card_data *priv;
  335. struct snd_soc_dai_link *dai_link;
  336. struct device_node *np = pdev->dev.of_node;
  337. struct device *dev = &pdev->dev;
  338. int num_links, multi, ret;
  339. /* get the number of DAI links */
  340. if (np && of_get_child_by_name(np, "simple-audio-card,dai-link")) {
  341. num_links = of_get_child_count(np);
  342. multi = 1;
  343. } else {
  344. num_links = 1;
  345. multi = 0;
  346. }
  347. /* allocate the private data and the DAI link array */
  348. priv = devm_kzalloc(dev,
  349. sizeof(*priv) + sizeof(*dai_link) * num_links,
  350. GFP_KERNEL);
  351. if (!priv)
  352. return -ENOMEM;
  353. /*
  354. * init snd_soc_card
  355. */
  356. priv->snd_card.owner = THIS_MODULE;
  357. priv->snd_card.dev = dev;
  358. dai_link = priv->dai_link;
  359. priv->snd_card.dai_link = dai_link;
  360. priv->snd_card.num_links = num_links;
  361. /* get room for the other properties */
  362. priv->dai_props = devm_kzalloc(dev,
  363. sizeof(*priv->dai_props) * num_links,
  364. GFP_KERNEL);
  365. if (!priv->dai_props)
  366. return -ENOMEM;
  367. if (np && of_device_is_available(np)) {
  368. ret = asoc_simple_card_parse_of(np, priv, dev, multi);
  369. if (ret < 0) {
  370. if (ret != -EPROBE_DEFER)
  371. dev_err(dev, "parse error %d\n", ret);
  372. goto err;
  373. }
  374. /*
  375. * soc_bind_dai_link() will check cpu name
  376. * after of_node matching if dai_link has cpu_dai_name.
  377. * but, it will never match if name was created by fmt_single_name()
  378. * remove cpu_dai_name to escape name matching.
  379. * see
  380. * fmt_single_name()
  381. * fmt_multiple_name()
  382. */
  383. if (num_links == 1)
  384. dai_link->cpu_dai_name = NULL;
  385. } else {
  386. struct asoc_simple_card_info *cinfo;
  387. cinfo = dev->platform_data;
  388. if (!cinfo) {
  389. dev_err(dev, "no info for asoc-simple-card\n");
  390. return -EINVAL;
  391. }
  392. if (!cinfo->name ||
  393. !cinfo->codec_dai.name ||
  394. !cinfo->codec ||
  395. !cinfo->platform ||
  396. !cinfo->cpu_dai.name) {
  397. dev_err(dev, "insufficient asoc_simple_card_info settings\n");
  398. return -EINVAL;
  399. }
  400. priv->snd_card.name = (cinfo->card) ? cinfo->card : cinfo->name;
  401. dai_link->name = cinfo->name;
  402. dai_link->stream_name = cinfo->name;
  403. dai_link->platform_name = cinfo->platform;
  404. dai_link->codec_name = cinfo->codec;
  405. dai_link->cpu_dai_name = cinfo->cpu_dai.name;
  406. dai_link->codec_dai_name = cinfo->codec_dai.name;
  407. memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai,
  408. sizeof(priv->dai_props->cpu_dai));
  409. memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai,
  410. sizeof(priv->dai_props->codec_dai));
  411. priv->dai_props->cpu_dai.fmt |= cinfo->daifmt;
  412. priv->dai_props->codec_dai.fmt |= cinfo->daifmt;
  413. }
  414. /*
  415. * init snd_soc_dai_link
  416. */
  417. dai_link->init = asoc_simple_card_dai_init;
  418. snd_soc_card_set_drvdata(&priv->snd_card, priv);
  419. ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
  420. err:
  421. asoc_simple_card_unref(pdev);
  422. return ret;
  423. }
  424. static const struct of_device_id asoc_simple_of_match[] = {
  425. { .compatible = "simple-audio-card", },
  426. {},
  427. };
  428. MODULE_DEVICE_TABLE(of, asoc_simple_of_match);
  429. static struct platform_driver asoc_simple_card = {
  430. .driver = {
  431. .name = "asoc-simple-card",
  432. .owner = THIS_MODULE,
  433. .of_match_table = asoc_simple_of_match,
  434. },
  435. .probe = asoc_simple_card_probe,
  436. };
  437. module_platform_driver(asoc_simple_card);
  438. MODULE_ALIAS("platform:asoc-simple-card");
  439. MODULE_LICENSE("GPL");
  440. MODULE_DESCRIPTION("ASoC Simple Sound Card");
  441. MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");