audio-graph-card.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  1. // SPDX-License-Identifier: GPL-2.0
  2. //
  3. // ASoC audio graph sound card support
  4. //
  5. // Copyright (C) 2016 Renesas Solutions Corp.
  6. // Kuninori Morimoto <[email protected]>
  7. //
  8. // based on ${LINUX}/sound/soc/generic/simple-card.c
  9. #include <linux/clk.h>
  10. #include <linux/device.h>
  11. #include <linux/gpio.h>
  12. #include <linux/gpio/consumer.h>
  13. #include <linux/module.h>
  14. #include <linux/of.h>
  15. #include <linux/of_device.h>
  16. #include <linux/of_gpio.h>
  17. #include <linux/of_graph.h>
  18. #include <linux/platform_device.h>
  19. #include <linux/string.h>
  20. #include <sound/graph_card.h>
  21. #define DPCM_SELECTABLE 1
  22. static int graph_outdrv_event(struct snd_soc_dapm_widget *w,
  23. struct snd_kcontrol *kcontrol,
  24. int event)
  25. {
  26. struct snd_soc_dapm_context *dapm = w->dapm;
  27. struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(dapm->card);
  28. switch (event) {
  29. case SND_SOC_DAPM_POST_PMU:
  30. gpiod_set_value_cansleep(priv->pa_gpio, 1);
  31. break;
  32. case SND_SOC_DAPM_PRE_PMD:
  33. gpiod_set_value_cansleep(priv->pa_gpio, 0);
  34. break;
  35. default:
  36. return -EINVAL;
  37. }
  38. return 0;
  39. }
  40. static const struct snd_soc_dapm_widget graph_dapm_widgets[] = {
  41. SND_SOC_DAPM_OUT_DRV_E("Amplifier", SND_SOC_NOPM,
  42. 0, 0, NULL, 0, graph_outdrv_event,
  43. SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
  44. };
  45. static const struct snd_soc_ops graph_ops = {
  46. .startup = asoc_simple_startup,
  47. .shutdown = asoc_simple_shutdown,
  48. .hw_params = asoc_simple_hw_params,
  49. };
  50. static int graph_get_dai_id(struct device_node *ep)
  51. {
  52. struct device_node *node;
  53. struct device_node *endpoint;
  54. struct of_endpoint info;
  55. int i, id;
  56. const u32 *reg;
  57. int ret;
  58. /* use driver specified DAI ID if exist */
  59. ret = snd_soc_get_dai_id(ep);
  60. if (ret != -ENOTSUPP)
  61. return ret;
  62. /* use endpoint/port reg if exist */
  63. ret = of_graph_parse_endpoint(ep, &info);
  64. if (ret == 0) {
  65. /*
  66. * Because it will count port/endpoint if it doesn't have "reg".
  67. * But, we can't judge whether it has "no reg", or "reg = <0>"
  68. * only of_graph_parse_endpoint().
  69. * We need to check "reg" property
  70. */
  71. if (of_get_property(ep, "reg", NULL))
  72. return info.id;
  73. node = of_get_parent(ep);
  74. reg = of_get_property(node, "reg", NULL);
  75. of_node_put(node);
  76. if (reg)
  77. return info.port;
  78. }
  79. node = of_graph_get_port_parent(ep);
  80. /*
  81. * Non HDMI sound case, counting port/endpoint on its DT
  82. * is enough. Let's count it.
  83. */
  84. i = 0;
  85. id = -1;
  86. for_each_endpoint_of_node(node, endpoint) {
  87. if (endpoint == ep)
  88. id = i;
  89. i++;
  90. }
  91. of_node_put(node);
  92. if (id < 0)
  93. return -ENODEV;
  94. return id;
  95. }
  96. static bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc)
  97. {
  98. struct snd_soc_dai *dai = snd_soc_find_dai_with_mutex(dlc);
  99. if (dai && (dai->component->driver->pcm_construct ||
  100. dai->driver->pcm_new))
  101. return true;
  102. return false;
  103. }
  104. static int asoc_simple_parse_dai(struct device_node *ep,
  105. struct snd_soc_dai_link_component *dlc,
  106. int *is_single_link)
  107. {
  108. struct device_node *node;
  109. struct of_phandle_args args;
  110. int ret;
  111. if (!ep)
  112. return 0;
  113. node = of_graph_get_port_parent(ep);
  114. /* Get dai->name */
  115. args.np = node;
  116. args.args[0] = graph_get_dai_id(ep);
  117. args.args_count = (of_graph_get_endpoint_count(node) > 1);
  118. /*
  119. * FIXME
  120. *
  121. * Here, dlc->dai_name is pointer to CPU/Codec DAI name.
  122. * If user unbinded CPU or Codec driver, but not for Sound Card,
  123. * dlc->dai_name is keeping unbinded CPU or Codec
  124. * driver's pointer.
  125. *
  126. * If user re-bind CPU or Codec driver again, ALSA SoC will try
  127. * to rebind Card via snd_soc_try_rebind_card(), but because of
  128. * above reason, it might can't bind Sound Card.
  129. * Because Sound Card is pointing to released dai_name pointer.
  130. *
  131. * To avoid this rebind Card issue,
  132. * 1) It needs to alloc memory to keep dai_name eventhough
  133. * CPU or Codec driver was unbinded, or
  134. * 2) user need to rebind Sound Card everytime
  135. * if he unbinded CPU or Codec.
  136. */
  137. ret = snd_soc_get_dai_name(&args, &dlc->dai_name);
  138. if (ret < 0) {
  139. of_node_put(node);
  140. return ret;
  141. }
  142. dlc->of_node = node;
  143. if (is_single_link)
  144. *is_single_link = of_graph_get_endpoint_count(node) == 1;
  145. return 0;
  146. }
  147. static void graph_parse_convert(struct device *dev,
  148. struct device_node *ep,
  149. struct asoc_simple_data *adata)
  150. {
  151. struct device_node *top = dev->of_node;
  152. struct device_node *port = of_get_parent(ep);
  153. struct device_node *ports = of_get_parent(port);
  154. struct device_node *node = of_graph_get_port_parent(ep);
  155. asoc_simple_parse_convert(top, NULL, adata);
  156. if (of_node_name_eq(ports, "ports"))
  157. asoc_simple_parse_convert(ports, NULL, adata);
  158. asoc_simple_parse_convert(port, NULL, adata);
  159. asoc_simple_parse_convert(ep, NULL, adata);
  160. of_node_put(port);
  161. of_node_put(ports);
  162. of_node_put(node);
  163. }
  164. static void graph_parse_mclk_fs(struct device_node *top,
  165. struct device_node *ep,
  166. struct simple_dai_props *props)
  167. {
  168. struct device_node *port = of_get_parent(ep);
  169. struct device_node *ports = of_get_parent(port);
  170. of_property_read_u32(top, "mclk-fs", &props->mclk_fs);
  171. if (of_node_name_eq(ports, "ports"))
  172. of_property_read_u32(ports, "mclk-fs", &props->mclk_fs);
  173. of_property_read_u32(port, "mclk-fs", &props->mclk_fs);
  174. of_property_read_u32(ep, "mclk-fs", &props->mclk_fs);
  175. of_node_put(port);
  176. of_node_put(ports);
  177. }
  178. static int graph_parse_node(struct asoc_simple_priv *priv,
  179. struct device_node *ep,
  180. struct link_info *li,
  181. int *cpu)
  182. {
  183. struct device *dev = simple_priv_to_dev(priv);
  184. struct device_node *top = dev->of_node;
  185. struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
  186. struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
  187. struct snd_soc_dai_link_component *dlc;
  188. struct asoc_simple_dai *dai;
  189. int ret;
  190. if (cpu) {
  191. dlc = asoc_link_to_cpu(dai_link, 0);
  192. dai = simple_props_to_dai_cpu(dai_props, 0);
  193. } else {
  194. dlc = asoc_link_to_codec(dai_link, 0);
  195. dai = simple_props_to_dai_codec(dai_props, 0);
  196. }
  197. graph_parse_mclk_fs(top, ep, dai_props);
  198. ret = asoc_simple_parse_dai(ep, dlc, cpu);
  199. if (ret < 0)
  200. return ret;
  201. ret = asoc_simple_parse_tdm(ep, dai);
  202. if (ret < 0)
  203. return ret;
  204. ret = asoc_simple_parse_clk(dev, ep, dai, dlc);
  205. if (ret < 0)
  206. return ret;
  207. return 0;
  208. }
  209. static int graph_link_init(struct asoc_simple_priv *priv,
  210. struct device_node *cpu_ep,
  211. struct device_node *codec_ep,
  212. struct link_info *li,
  213. char *name)
  214. {
  215. struct device *dev = simple_priv_to_dev(priv);
  216. struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
  217. int ret;
  218. ret = asoc_simple_parse_daifmt(dev, cpu_ep, codec_ep,
  219. NULL, &dai_link->dai_fmt);
  220. if (ret < 0)
  221. return ret;
  222. dai_link->init = asoc_simple_dai_init;
  223. dai_link->ops = &graph_ops;
  224. if (priv->ops)
  225. dai_link->ops = priv->ops;
  226. return asoc_simple_set_dailink_name(dev, dai_link, name);
  227. }
  228. static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
  229. struct device_node *cpu_ep,
  230. struct device_node *codec_ep,
  231. struct link_info *li)
  232. {
  233. struct device *dev = simple_priv_to_dev(priv);
  234. struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
  235. struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
  236. struct device_node *top = dev->of_node;
  237. struct device_node *ep = li->cpu ? cpu_ep : codec_ep;
  238. char dai_name[64];
  239. int ret;
  240. dev_dbg(dev, "link_of DPCM (%pOF)\n", ep);
  241. if (li->cpu) {
  242. struct snd_soc_card *card = simple_priv_to_card(priv);
  243. struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0);
  244. struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0);
  245. int is_single_links = 0;
  246. /* Codec is dummy */
  247. /* FE settings */
  248. dai_link->dynamic = 1;
  249. dai_link->dpcm_merged_format = 1;
  250. ret = graph_parse_node(priv, cpu_ep, li, &is_single_links);
  251. if (ret)
  252. return ret;
  253. snprintf(dai_name, sizeof(dai_name),
  254. "fe.%pOFP.%s", cpus->of_node, cpus->dai_name);
  255. /*
  256. * In BE<->BE connections it is not required to create
  257. * PCM devices at CPU end of the dai link and thus 'no_pcm'
  258. * flag needs to be set. It is useful when there are many
  259. * BE components and some of these have to be connected to
  260. * form a valid audio path.
  261. *
  262. * For example: FE <-> BE1 <-> BE2 <-> ... <-> BEn where
  263. * there are 'n' BE components in the path.
  264. */
  265. if (card->component_chaining && !soc_component_is_pcm(cpus)) {
  266. dai_link->no_pcm = 1;
  267. dai_link->be_hw_params_fixup = asoc_simple_be_hw_params_fixup;
  268. }
  269. asoc_simple_canonicalize_cpu(cpus, is_single_links);
  270. asoc_simple_canonicalize_platform(platforms, cpus);
  271. } else {
  272. struct snd_soc_codec_conf *cconf = simple_props_to_codec_conf(dai_props, 0);
  273. struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0);
  274. struct device_node *port;
  275. struct device_node *ports;
  276. /* CPU is dummy */
  277. /* BE settings */
  278. dai_link->no_pcm = 1;
  279. dai_link->be_hw_params_fixup = asoc_simple_be_hw_params_fixup;
  280. ret = graph_parse_node(priv, codec_ep, li, NULL);
  281. if (ret < 0)
  282. return ret;
  283. snprintf(dai_name, sizeof(dai_name),
  284. "be.%pOFP.%s", codecs->of_node, codecs->dai_name);
  285. /* check "prefix" from top node */
  286. port = of_get_parent(ep);
  287. ports = of_get_parent(port);
  288. snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node,
  289. "prefix");
  290. if (of_node_name_eq(ports, "ports"))
  291. snd_soc_of_parse_node_prefix(ports, cconf, codecs->of_node, "prefix");
  292. snd_soc_of_parse_node_prefix(port, cconf, codecs->of_node,
  293. "prefix");
  294. of_node_put(ports);
  295. of_node_put(port);
  296. }
  297. graph_parse_convert(dev, ep, &dai_props->adata);
  298. snd_soc_dai_link_set_capabilities(dai_link);
  299. ret = graph_link_init(priv, cpu_ep, codec_ep, li, dai_name);
  300. li->link++;
  301. return ret;
  302. }
  303. static int graph_dai_link_of(struct asoc_simple_priv *priv,
  304. struct device_node *cpu_ep,
  305. struct device_node *codec_ep,
  306. struct link_info *li)
  307. {
  308. struct device *dev = simple_priv_to_dev(priv);
  309. struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
  310. struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0);
  311. struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0);
  312. struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0);
  313. char dai_name[64];
  314. int ret, is_single_links = 0;
  315. dev_dbg(dev, "link_of (%pOF)\n", cpu_ep);
  316. ret = graph_parse_node(priv, cpu_ep, li, &is_single_links);
  317. if (ret < 0)
  318. return ret;
  319. ret = graph_parse_node(priv, codec_ep, li, NULL);
  320. if (ret < 0)
  321. return ret;
  322. snprintf(dai_name, sizeof(dai_name),
  323. "%s-%s", cpus->dai_name, codecs->dai_name);
  324. asoc_simple_canonicalize_cpu(cpus, is_single_links);
  325. asoc_simple_canonicalize_platform(platforms, cpus);
  326. ret = graph_link_init(priv, cpu_ep, codec_ep, li, dai_name);
  327. if (ret < 0)
  328. return ret;
  329. li->link++;
  330. return 0;
  331. }
  332. static inline bool parse_as_dpcm_link(struct asoc_simple_priv *priv,
  333. struct device_node *codec_port,
  334. struct asoc_simple_data *adata)
  335. {
  336. if (priv->force_dpcm)
  337. return true;
  338. if (!priv->dpcm_selectable)
  339. return false;
  340. /*
  341. * It is DPCM
  342. * if Codec port has many endpoints,
  343. * or has convert-xxx property
  344. */
  345. if ((of_get_child_count(codec_port) > 1) ||
  346. asoc_simple_is_convert_required(adata))
  347. return true;
  348. return false;
  349. }
  350. static int __graph_for_each_link(struct asoc_simple_priv *priv,
  351. struct link_info *li,
  352. int (*func_noml)(struct asoc_simple_priv *priv,
  353. struct device_node *cpu_ep,
  354. struct device_node *codec_ep,
  355. struct link_info *li),
  356. int (*func_dpcm)(struct asoc_simple_priv *priv,
  357. struct device_node *cpu_ep,
  358. struct device_node *codec_ep,
  359. struct link_info *li))
  360. {
  361. struct of_phandle_iterator it;
  362. struct device *dev = simple_priv_to_dev(priv);
  363. struct device_node *node = dev->of_node;
  364. struct device_node *cpu_port;
  365. struct device_node *cpu_ep;
  366. struct device_node *codec_ep;
  367. struct device_node *codec_port;
  368. struct device_node *codec_port_old = NULL;
  369. struct asoc_simple_data adata;
  370. int rc, ret = 0;
  371. /* loop for all listed CPU port */
  372. of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
  373. cpu_port = it.node;
  374. cpu_ep = NULL;
  375. /* loop for all CPU endpoint */
  376. while (1) {
  377. cpu_ep = of_get_next_child(cpu_port, cpu_ep);
  378. if (!cpu_ep)
  379. break;
  380. /* get codec */
  381. codec_ep = of_graph_get_remote_endpoint(cpu_ep);
  382. codec_port = of_get_parent(codec_ep);
  383. /* get convert-xxx property */
  384. memset(&adata, 0, sizeof(adata));
  385. graph_parse_convert(dev, codec_ep, &adata);
  386. graph_parse_convert(dev, cpu_ep, &adata);
  387. /* check if link requires DPCM parsing */
  388. if (parse_as_dpcm_link(priv, codec_port, &adata)) {
  389. /*
  390. * Codec endpoint can be NULL for pluggable audio HW.
  391. * Platform DT can populate the Codec endpoint depending on the
  392. * plugged HW.
  393. */
  394. /* Do it all CPU endpoint, and 1st Codec endpoint */
  395. if (li->cpu ||
  396. ((codec_port_old != codec_port) && codec_ep))
  397. ret = func_dpcm(priv, cpu_ep, codec_ep, li);
  398. /* else normal sound */
  399. } else {
  400. if (li->cpu)
  401. ret = func_noml(priv, cpu_ep, codec_ep, li);
  402. }
  403. of_node_put(codec_ep);
  404. of_node_put(codec_port);
  405. if (ret < 0) {
  406. of_node_put(cpu_ep);
  407. return ret;
  408. }
  409. codec_port_old = codec_port;
  410. }
  411. }
  412. return 0;
  413. }
  414. static int graph_for_each_link(struct asoc_simple_priv *priv,
  415. struct link_info *li,
  416. int (*func_noml)(struct asoc_simple_priv *priv,
  417. struct device_node *cpu_ep,
  418. struct device_node *codec_ep,
  419. struct link_info *li),
  420. int (*func_dpcm)(struct asoc_simple_priv *priv,
  421. struct device_node *cpu_ep,
  422. struct device_node *codec_ep,
  423. struct link_info *li))
  424. {
  425. int ret;
  426. /*
  427. * Detect all CPU first, and Detect all Codec 2nd.
  428. *
  429. * In Normal sound case, all DAIs are detected
  430. * as "CPU-Codec".
  431. *
  432. * In DPCM sound case,
  433. * all CPUs are detected as "CPU-dummy", and
  434. * all Codecs are detected as "dummy-Codec".
  435. * To avoid random sub-device numbering,
  436. * detect "dummy-Codec" in last;
  437. */
  438. for (li->cpu = 1; li->cpu >= 0; li->cpu--) {
  439. ret = __graph_for_each_link(priv, li, func_noml, func_dpcm);
  440. if (ret < 0)
  441. break;
  442. }
  443. return ret;
  444. }
  445. static int graph_get_dais_count(struct asoc_simple_priv *priv,
  446. struct link_info *li);
  447. int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev)
  448. {
  449. struct snd_soc_card *card = simple_priv_to_card(priv);
  450. struct link_info *li;
  451. int ret;
  452. li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL);
  453. if (!li)
  454. return -ENOMEM;
  455. card->owner = THIS_MODULE;
  456. card->dev = dev;
  457. ret = graph_get_dais_count(priv, li);
  458. if (ret < 0)
  459. return ret;
  460. if (!li->link)
  461. return -EINVAL;
  462. ret = asoc_simple_init_priv(priv, li);
  463. if (ret < 0)
  464. return ret;
  465. priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW);
  466. if (IS_ERR(priv->pa_gpio)) {
  467. ret = PTR_ERR(priv->pa_gpio);
  468. dev_err(dev, "failed to get amplifier gpio: %d\n", ret);
  469. return ret;
  470. }
  471. ret = asoc_simple_parse_widgets(card, NULL);
  472. if (ret < 0)
  473. return ret;
  474. ret = asoc_simple_parse_routing(card, NULL);
  475. if (ret < 0)
  476. return ret;
  477. memset(li, 0, sizeof(*li));
  478. ret = graph_for_each_link(priv, li,
  479. graph_dai_link_of,
  480. graph_dai_link_of_dpcm);
  481. if (ret < 0)
  482. goto err;
  483. ret = asoc_simple_parse_card_name(card, NULL);
  484. if (ret < 0)
  485. goto err;
  486. snd_soc_card_set_drvdata(card, priv);
  487. asoc_simple_debug_info(priv);
  488. ret = devm_snd_soc_register_card(dev, card);
  489. if (ret < 0)
  490. goto err;
  491. devm_kfree(dev, li);
  492. return 0;
  493. err:
  494. asoc_simple_clean_reference(card);
  495. return dev_err_probe(dev, ret, "parse error\n");
  496. }
  497. EXPORT_SYMBOL_GPL(audio_graph_parse_of);
  498. static int graph_count_noml(struct asoc_simple_priv *priv,
  499. struct device_node *cpu_ep,
  500. struct device_node *codec_ep,
  501. struct link_info *li)
  502. {
  503. struct device *dev = simple_priv_to_dev(priv);
  504. if (li->link >= SNDRV_MAX_LINKS) {
  505. dev_err(dev, "too many links\n");
  506. return -EINVAL;
  507. }
  508. li->num[li->link].cpus = 1;
  509. li->num[li->link].codecs = 1;
  510. li->num[li->link].platforms = 1;
  511. li->link += 1; /* 1xCPU-Codec */
  512. dev_dbg(dev, "Count As Normal\n");
  513. return 0;
  514. }
  515. static int graph_count_dpcm(struct asoc_simple_priv *priv,
  516. struct device_node *cpu_ep,
  517. struct device_node *codec_ep,
  518. struct link_info *li)
  519. {
  520. struct device *dev = simple_priv_to_dev(priv);
  521. if (li->link >= SNDRV_MAX_LINKS) {
  522. dev_err(dev, "too many links\n");
  523. return -EINVAL;
  524. }
  525. if (li->cpu) {
  526. li->num[li->link].cpus = 1;
  527. li->num[li->link].platforms = 1;
  528. li->link++; /* 1xCPU-dummy */
  529. } else {
  530. li->num[li->link].codecs = 1;
  531. li->link++; /* 1xdummy-Codec */
  532. }
  533. dev_dbg(dev, "Count As DPCM\n");
  534. return 0;
  535. }
  536. static int graph_get_dais_count(struct asoc_simple_priv *priv,
  537. struct link_info *li)
  538. {
  539. /*
  540. * link_num : number of links.
  541. * CPU-Codec / CPU-dummy / dummy-Codec
  542. * dais_num : number of DAIs
  543. * ccnf_num : number of codec_conf
  544. * same number for "dummy-Codec"
  545. *
  546. * ex1)
  547. * CPU0 --- Codec0 link : 5
  548. * CPU1 --- Codec1 dais : 7
  549. * CPU2 -/ ccnf : 1
  550. * CPU3 --- Codec2
  551. *
  552. * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
  553. * => 7 DAIs = 4xCPU + 3xCodec
  554. * => 1 ccnf = 1xdummy-Codec
  555. *
  556. * ex2)
  557. * CPU0 --- Codec0 link : 5
  558. * CPU1 --- Codec1 dais : 6
  559. * CPU2 -/ ccnf : 1
  560. * CPU3 -/
  561. *
  562. * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
  563. * => 6 DAIs = 4xCPU + 2xCodec
  564. * => 1 ccnf = 1xdummy-Codec
  565. *
  566. * ex3)
  567. * CPU0 --- Codec0 link : 6
  568. * CPU1 -/ dais : 6
  569. * CPU2 --- Codec1 ccnf : 2
  570. * CPU3 -/
  571. *
  572. * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
  573. * => 6 DAIs = 4xCPU + 2xCodec
  574. * => 2 ccnf = 2xdummy-Codec
  575. *
  576. * ex4)
  577. * CPU0 --- Codec0 (convert-rate) link : 3
  578. * CPU1 --- Codec1 dais : 4
  579. * ccnf : 1
  580. *
  581. * => 3 links = 1xCPU-Codec + 1xCPU-dummy + 1xdummy-Codec
  582. * => 4 DAIs = 2xCPU + 2xCodec
  583. * => 1 ccnf = 1xdummy-Codec
  584. */
  585. return graph_for_each_link(priv, li,
  586. graph_count_noml,
  587. graph_count_dpcm);
  588. }
  589. static int graph_probe(struct platform_device *pdev)
  590. {
  591. struct asoc_simple_priv *priv;
  592. struct device *dev = &pdev->dev;
  593. struct snd_soc_card *card;
  594. /* Allocate the private data and the DAI link array */
  595. priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  596. if (!priv)
  597. return -ENOMEM;
  598. card = simple_priv_to_card(priv);
  599. card->dapm_widgets = graph_dapm_widgets;
  600. card->num_dapm_widgets = ARRAY_SIZE(graph_dapm_widgets);
  601. card->probe = asoc_graph_card_probe;
  602. if (of_device_get_match_data(dev))
  603. priv->dpcm_selectable = 1;
  604. return audio_graph_parse_of(priv, dev);
  605. }
  606. static const struct of_device_id graph_of_match[] = {
  607. { .compatible = "audio-graph-card", },
  608. { .compatible = "audio-graph-scu-card",
  609. .data = (void *)DPCM_SELECTABLE },
  610. {},
  611. };
  612. MODULE_DEVICE_TABLE(of, graph_of_match);
  613. static struct platform_driver graph_card = {
  614. .driver = {
  615. .name = "asoc-audio-graph-card",
  616. .pm = &snd_soc_pm_ops,
  617. .of_match_table = graph_of_match,
  618. },
  619. .probe = graph_probe,
  620. .remove = asoc_simple_remove,
  621. };
  622. module_platform_driver(graph_card);
  623. MODULE_ALIAS("platform:asoc-audio-graph-card");
  624. MODULE_LICENSE("GPL v2");
  625. MODULE_DESCRIPTION("ASoC Audio Graph Sound Card");
  626. MODULE_AUTHOR("Kuninori Morimoto <[email protected]>");