simple-card.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  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/gpio.h>
  14. #include <linux/module.h>
  15. #include <linux/of.h>
  16. #include <linux/of_gpio.h>
  17. #include <linux/platform_device.h>
  18. #include <linux/string.h>
  19. #include <sound/jack.h>
  20. #include <sound/simple_card.h>
  21. #include <sound/soc-dai.h>
  22. #include <sound/soc.h>
  23. struct simple_card_data {
  24. struct snd_soc_card snd_card;
  25. struct simple_dai_props {
  26. struct asoc_simple_dai cpu_dai;
  27. struct asoc_simple_dai codec_dai;
  28. } *dai_props;
  29. unsigned int mclk_fs;
  30. int gpio_hp_det;
  31. int gpio_hp_det_invert;
  32. int gpio_mic_det;
  33. int gpio_mic_det_invert;
  34. struct snd_soc_dai_link dai_link[]; /* dynamically allocated */
  35. };
  36. #define simple_priv_to_dev(priv) ((priv)->snd_card.dev)
  37. #define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + i)
  38. #define simple_priv_to_props(priv, i) ((priv)->dai_props + i)
  39. static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
  40. {
  41. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  42. struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
  43. struct simple_dai_props *dai_props =
  44. &priv->dai_props[rtd - rtd->card->rtd];
  45. int ret;
  46. ret = clk_prepare_enable(dai_props->cpu_dai.clk);
  47. if (ret)
  48. return ret;
  49. ret = clk_prepare_enable(dai_props->codec_dai.clk);
  50. if (ret)
  51. clk_disable_unprepare(dai_props->cpu_dai.clk);
  52. return ret;
  53. }
  54. static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
  55. {
  56. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  57. struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
  58. struct simple_dai_props *dai_props =
  59. &priv->dai_props[rtd - rtd->card->rtd];
  60. clk_disable_unprepare(dai_props->cpu_dai.clk);
  61. clk_disable_unprepare(dai_props->codec_dai.clk);
  62. }
  63. static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
  64. struct snd_pcm_hw_params *params)
  65. {
  66. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  67. struct snd_soc_dai *codec_dai = rtd->codec_dai;
  68. struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
  69. unsigned int mclk;
  70. int ret = 0;
  71. if (priv->mclk_fs) {
  72. mclk = params_rate(params) * priv->mclk_fs;
  73. ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
  74. SND_SOC_CLOCK_IN);
  75. }
  76. return ret;
  77. }
  78. static struct snd_soc_ops asoc_simple_card_ops = {
  79. .startup = asoc_simple_card_startup,
  80. .shutdown = asoc_simple_card_shutdown,
  81. .hw_params = asoc_simple_card_hw_params,
  82. };
  83. static struct snd_soc_jack simple_card_hp_jack;
  84. static struct snd_soc_jack_pin simple_card_hp_jack_pins[] = {
  85. {
  86. .pin = "Headphones",
  87. .mask = SND_JACK_HEADPHONE,
  88. },
  89. };
  90. static struct snd_soc_jack_gpio simple_card_hp_jack_gpio = {
  91. .name = "Headphone detection",
  92. .report = SND_JACK_HEADPHONE,
  93. .debounce_time = 150,
  94. };
  95. static struct snd_soc_jack simple_card_mic_jack;
  96. static struct snd_soc_jack_pin simple_card_mic_jack_pins[] = {
  97. {
  98. .pin = "Mic Jack",
  99. .mask = SND_JACK_MICROPHONE,
  100. },
  101. };
  102. static struct snd_soc_jack_gpio simple_card_mic_jack_gpio = {
  103. .name = "Mic detection",
  104. .report = SND_JACK_MICROPHONE,
  105. .debounce_time = 150,
  106. };
  107. static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai,
  108. struct asoc_simple_dai *set)
  109. {
  110. int ret;
  111. if (set->sysclk) {
  112. ret = snd_soc_dai_set_sysclk(dai, 0, set->sysclk, 0);
  113. if (ret && ret != -ENOTSUPP) {
  114. dev_err(dai->dev, "simple-card: set_sysclk error\n");
  115. goto err;
  116. }
  117. }
  118. if (set->slots) {
  119. ret = snd_soc_dai_set_tdm_slot(dai, 0, 0,
  120. set->slots,
  121. set->slot_width);
  122. if (ret && ret != -ENOTSUPP) {
  123. dev_err(dai->dev, "simple-card: set_tdm_slot error\n");
  124. goto err;
  125. }
  126. }
  127. ret = 0;
  128. err:
  129. return ret;
  130. }
  131. static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
  132. {
  133. struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
  134. struct snd_soc_dai *codec = rtd->codec_dai;
  135. struct snd_soc_dai *cpu = rtd->cpu_dai;
  136. struct simple_dai_props *dai_props;
  137. int num, ret;
  138. num = rtd - rtd->card->rtd;
  139. dai_props = &priv->dai_props[num];
  140. ret = __asoc_simple_card_dai_init(codec, &dai_props->codec_dai);
  141. if (ret < 0)
  142. return ret;
  143. ret = __asoc_simple_card_dai_init(cpu, &dai_props->cpu_dai);
  144. if (ret < 0)
  145. return ret;
  146. if (gpio_is_valid(priv->gpio_hp_det)) {
  147. snd_soc_card_jack_new(rtd->card, "Headphones",
  148. SND_JACK_HEADPHONE,
  149. &simple_card_hp_jack,
  150. simple_card_hp_jack_pins,
  151. ARRAY_SIZE(simple_card_hp_jack_pins));
  152. simple_card_hp_jack_gpio.gpio = priv->gpio_hp_det;
  153. simple_card_hp_jack_gpio.invert = priv->gpio_hp_det_invert;
  154. snd_soc_jack_add_gpios(&simple_card_hp_jack, 1,
  155. &simple_card_hp_jack_gpio);
  156. }
  157. if (gpio_is_valid(priv->gpio_mic_det)) {
  158. snd_soc_card_jack_new(rtd->card, "Mic Jack",
  159. SND_JACK_MICROPHONE,
  160. &simple_card_mic_jack,
  161. simple_card_mic_jack_pins,
  162. ARRAY_SIZE(simple_card_mic_jack_pins));
  163. simple_card_mic_jack_gpio.gpio = priv->gpio_mic_det;
  164. simple_card_mic_jack_gpio.invert = priv->gpio_mic_det_invert;
  165. snd_soc_jack_add_gpios(&simple_card_mic_jack, 1,
  166. &simple_card_mic_jack_gpio);
  167. }
  168. return 0;
  169. }
  170. static int
  171. asoc_simple_card_sub_parse_of(struct device_node *np,
  172. struct asoc_simple_dai *dai,
  173. struct device_node **p_node,
  174. const char **name,
  175. int *args_count)
  176. {
  177. struct of_phandle_args args;
  178. struct clk *clk;
  179. u32 val;
  180. int ret;
  181. /*
  182. * Get node via "sound-dai = <&phandle port>"
  183. * it will be used as xxx_of_node on soc_bind_dai_link()
  184. */
  185. ret = of_parse_phandle_with_args(np, "sound-dai",
  186. "#sound-dai-cells", 0, &args);
  187. if (ret)
  188. return ret;
  189. *p_node = args.np;
  190. if (args_count)
  191. *args_count = args.args_count;
  192. /* Get dai->name */
  193. ret = snd_soc_of_get_dai_name(np, name);
  194. if (ret < 0)
  195. return ret;
  196. /* Parse TDM slot */
  197. ret = snd_soc_of_parse_tdm_slot(np, &dai->slots, &dai->slot_width);
  198. if (ret)
  199. return ret;
  200. /*
  201. * Parse dai->sysclk come from "clocks = <&xxx>"
  202. * (if system has common clock)
  203. * or "system-clock-frequency = <xxx>"
  204. * or device's module clock.
  205. */
  206. if (of_property_read_bool(np, "clocks")) {
  207. clk = of_clk_get(np, 0);
  208. if (IS_ERR(clk)) {
  209. ret = PTR_ERR(clk);
  210. return ret;
  211. }
  212. dai->sysclk = clk_get_rate(clk);
  213. dai->clk = clk;
  214. } else if (!of_property_read_u32(np, "system-clock-frequency", &val)) {
  215. dai->sysclk = val;
  216. } else {
  217. clk = of_clk_get(args.np, 0);
  218. if (!IS_ERR(clk))
  219. dai->sysclk = clk_get_rate(clk);
  220. }
  221. return 0;
  222. }
  223. static int asoc_simple_card_parse_daifmt(struct device_node *node,
  224. struct simple_card_data *priv,
  225. struct device_node *codec,
  226. char *prefix, int idx)
  227. {
  228. struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
  229. struct device *dev = simple_priv_to_dev(priv);
  230. struct device_node *bitclkmaster = NULL;
  231. struct device_node *framemaster = NULL;
  232. unsigned int daifmt;
  233. daifmt = snd_soc_of_parse_daifmt(node, prefix,
  234. &bitclkmaster, &framemaster);
  235. daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
  236. if (strlen(prefix) && !bitclkmaster && !framemaster) {
  237. /*
  238. * No dai-link level and master setting was not found from
  239. * sound node level, revert back to legacy DT parsing and
  240. * take the settings from codec node.
  241. */
  242. dev_dbg(dev, "Revert to legacy daifmt parsing\n");
  243. daifmt = snd_soc_of_parse_daifmt(codec, NULL, NULL, NULL) |
  244. (daifmt & ~SND_SOC_DAIFMT_CLOCK_MASK);
  245. } else {
  246. if (codec == bitclkmaster)
  247. daifmt |= (codec == framemaster) ?
  248. SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS;
  249. else
  250. daifmt |= (codec == framemaster) ?
  251. SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS;
  252. }
  253. dai_link->dai_fmt = daifmt;
  254. of_node_put(bitclkmaster);
  255. of_node_put(framemaster);
  256. return 0;
  257. }
  258. static int asoc_simple_card_dai_link_of(struct device_node *node,
  259. struct simple_card_data *priv,
  260. int idx,
  261. bool is_top_level_node)
  262. {
  263. struct device *dev = simple_priv_to_dev(priv);
  264. struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
  265. struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
  266. struct device_node *cpu = NULL;
  267. struct device_node *codec = NULL;
  268. char *name;
  269. char prop[128];
  270. char *prefix = "";
  271. int ret, cpu_args;
  272. /* For single DAI link & old style of DT node */
  273. if (is_top_level_node)
  274. prefix = "simple-audio-card,";
  275. snprintf(prop, sizeof(prop), "%scpu", prefix);
  276. cpu = of_get_child_by_name(node, prop);
  277. snprintf(prop, sizeof(prop), "%scodec", prefix);
  278. codec = of_get_child_by_name(node, prop);
  279. if (!cpu || !codec) {
  280. ret = -EINVAL;
  281. dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
  282. goto dai_link_of_err;
  283. }
  284. ret = asoc_simple_card_parse_daifmt(node, priv,
  285. codec, prefix, idx);
  286. if (ret < 0)
  287. goto dai_link_of_err;
  288. ret = asoc_simple_card_sub_parse_of(cpu, &dai_props->cpu_dai,
  289. &dai_link->cpu_of_node,
  290. &dai_link->cpu_dai_name,
  291. &cpu_args);
  292. if (ret < 0)
  293. goto dai_link_of_err;
  294. ret = asoc_simple_card_sub_parse_of(codec, &dai_props->codec_dai,
  295. &dai_link->codec_of_node,
  296. &dai_link->codec_dai_name, NULL);
  297. if (ret < 0)
  298. goto dai_link_of_err;
  299. if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) {
  300. ret = -EINVAL;
  301. goto dai_link_of_err;
  302. }
  303. /* Simple Card assumes platform == cpu */
  304. dai_link->platform_of_node = dai_link->cpu_of_node;
  305. /* DAI link name is created from CPU/CODEC dai name */
  306. name = devm_kzalloc(dev,
  307. strlen(dai_link->cpu_dai_name) +
  308. strlen(dai_link->codec_dai_name) + 2,
  309. GFP_KERNEL);
  310. if (!name) {
  311. ret = -ENOMEM;
  312. goto dai_link_of_err;
  313. }
  314. sprintf(name, "%s-%s", dai_link->cpu_dai_name,
  315. dai_link->codec_dai_name);
  316. dai_link->name = dai_link->stream_name = name;
  317. dai_link->ops = &asoc_simple_card_ops;
  318. dai_link->init = asoc_simple_card_dai_init;
  319. dev_dbg(dev, "\tname : %s\n", dai_link->stream_name);
  320. dev_dbg(dev, "\tformat : %04x\n", dai_link->dai_fmt);
  321. dev_dbg(dev, "\tcpu : %s / %d\n",
  322. dai_link->cpu_dai_name,
  323. dai_props->cpu_dai.sysclk);
  324. dev_dbg(dev, "\tcodec : %s / %d\n",
  325. dai_link->codec_dai_name,
  326. dai_props->codec_dai.sysclk);
  327. /*
  328. * In soc_bind_dai_link() will check cpu name after
  329. * of_node matching if dai_link has cpu_dai_name.
  330. * but, it will never match if name was created by
  331. * fmt_single_name() remove cpu_dai_name if cpu_args
  332. * was 0. See:
  333. * fmt_single_name()
  334. * fmt_multiple_name()
  335. */
  336. if (!cpu_args)
  337. dai_link->cpu_dai_name = NULL;
  338. dai_link_of_err:
  339. of_node_put(cpu);
  340. of_node_put(codec);
  341. return ret;
  342. }
  343. static int asoc_simple_card_parse_of(struct device_node *node,
  344. struct simple_card_data *priv)
  345. {
  346. struct device *dev = simple_priv_to_dev(priv);
  347. enum of_gpio_flags flags;
  348. u32 val;
  349. int ret;
  350. if (!node)
  351. return -EINVAL;
  352. /* Parse the card name from DT */
  353. snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name");
  354. /* The off-codec widgets */
  355. if (of_property_read_bool(node, "simple-audio-card,widgets")) {
  356. ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card,
  357. "simple-audio-card,widgets");
  358. if (ret)
  359. return ret;
  360. }
  361. /* DAPM routes */
  362. if (of_property_read_bool(node, "simple-audio-card,routing")) {
  363. ret = snd_soc_of_parse_audio_routing(&priv->snd_card,
  364. "simple-audio-card,routing");
  365. if (ret)
  366. return ret;
  367. }
  368. /* Factor to mclk, used in hw_params() */
  369. ret = of_property_read_u32(node, "simple-audio-card,mclk-fs", &val);
  370. if (ret == 0)
  371. priv->mclk_fs = val;
  372. dev_dbg(dev, "New simple-card: %s\n", priv->snd_card.name ?
  373. priv->snd_card.name : "");
  374. /* Single/Muti DAI link(s) & New style of DT node */
  375. if (of_get_child_by_name(node, "simple-audio-card,dai-link")) {
  376. struct device_node *np = NULL;
  377. int i = 0;
  378. for_each_child_of_node(node, np) {
  379. dev_dbg(dev, "\tlink %d:\n", i);
  380. ret = asoc_simple_card_dai_link_of(np, priv,
  381. i, false);
  382. if (ret < 0) {
  383. of_node_put(np);
  384. return ret;
  385. }
  386. i++;
  387. }
  388. } else {
  389. /* For single DAI link & old style of DT node */
  390. ret = asoc_simple_card_dai_link_of(node, priv, 0, true);
  391. if (ret < 0)
  392. return ret;
  393. }
  394. priv->gpio_hp_det = of_get_named_gpio_flags(node,
  395. "simple-audio-card,hp-det-gpio", 0, &flags);
  396. priv->gpio_hp_det_invert = !!(flags & OF_GPIO_ACTIVE_LOW);
  397. if (priv->gpio_hp_det == -EPROBE_DEFER)
  398. return -EPROBE_DEFER;
  399. priv->gpio_mic_det = of_get_named_gpio_flags(node,
  400. "simple-audio-card,mic-det-gpio", 0, &flags);
  401. priv->gpio_mic_det_invert = !!(flags & OF_GPIO_ACTIVE_LOW);
  402. if (priv->gpio_mic_det == -EPROBE_DEFER)
  403. return -EPROBE_DEFER;
  404. if (!priv->snd_card.name)
  405. priv->snd_card.name = priv->snd_card.dai_link->name;
  406. return 0;
  407. }
  408. /* Decrease the reference count of the device nodes */
  409. static int asoc_simple_card_unref(struct snd_soc_card *card)
  410. {
  411. struct snd_soc_dai_link *dai_link;
  412. int num_links;
  413. for (num_links = 0, dai_link = card->dai_link;
  414. num_links < card->num_links;
  415. num_links++, dai_link++) {
  416. of_node_put(dai_link->cpu_of_node);
  417. of_node_put(dai_link->codec_of_node);
  418. }
  419. return 0;
  420. }
  421. static int asoc_simple_card_probe(struct platform_device *pdev)
  422. {
  423. struct simple_card_data *priv;
  424. struct snd_soc_dai_link *dai_link;
  425. struct device_node *np = pdev->dev.of_node;
  426. struct device *dev = &pdev->dev;
  427. int num_links, ret;
  428. /* Get the number of DAI links */
  429. if (np && of_get_child_by_name(np, "simple-audio-card,dai-link"))
  430. num_links = of_get_child_count(np);
  431. else
  432. num_links = 1;
  433. /* Allocate the private data and the DAI link array */
  434. priv = devm_kzalloc(dev,
  435. sizeof(*priv) + sizeof(*dai_link) * num_links,
  436. GFP_KERNEL);
  437. if (!priv)
  438. return -ENOMEM;
  439. /* Init snd_soc_card */
  440. priv->snd_card.owner = THIS_MODULE;
  441. priv->snd_card.dev = dev;
  442. dai_link = priv->dai_link;
  443. priv->snd_card.dai_link = dai_link;
  444. priv->snd_card.num_links = num_links;
  445. priv->gpio_hp_det = -ENOENT;
  446. priv->gpio_mic_det = -ENOENT;
  447. /* Get room for the other properties */
  448. priv->dai_props = devm_kzalloc(dev,
  449. sizeof(*priv->dai_props) * num_links,
  450. GFP_KERNEL);
  451. if (!priv->dai_props)
  452. return -ENOMEM;
  453. if (np && of_device_is_available(np)) {
  454. ret = asoc_simple_card_parse_of(np, priv);
  455. if (ret < 0) {
  456. if (ret != -EPROBE_DEFER)
  457. dev_err(dev, "parse error %d\n", ret);
  458. goto err;
  459. }
  460. } else {
  461. struct asoc_simple_card_info *cinfo;
  462. cinfo = dev->platform_data;
  463. if (!cinfo) {
  464. dev_err(dev, "no info for asoc-simple-card\n");
  465. return -EINVAL;
  466. }
  467. if (!cinfo->name ||
  468. !cinfo->codec_dai.name ||
  469. !cinfo->codec ||
  470. !cinfo->platform ||
  471. !cinfo->cpu_dai.name) {
  472. dev_err(dev, "insufficient asoc_simple_card_info settings\n");
  473. return -EINVAL;
  474. }
  475. priv->snd_card.name = (cinfo->card) ? cinfo->card : cinfo->name;
  476. dai_link->name = cinfo->name;
  477. dai_link->stream_name = cinfo->name;
  478. dai_link->platform_name = cinfo->platform;
  479. dai_link->codec_name = cinfo->codec;
  480. dai_link->cpu_dai_name = cinfo->cpu_dai.name;
  481. dai_link->codec_dai_name = cinfo->codec_dai.name;
  482. dai_link->dai_fmt = cinfo->daifmt;
  483. dai_link->init = asoc_simple_card_dai_init;
  484. memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai,
  485. sizeof(priv->dai_props->cpu_dai));
  486. memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai,
  487. sizeof(priv->dai_props->codec_dai));
  488. }
  489. snd_soc_card_set_drvdata(&priv->snd_card, priv);
  490. ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
  491. if (ret >= 0)
  492. return ret;
  493. err:
  494. asoc_simple_card_unref(&priv->snd_card);
  495. return ret;
  496. }
  497. static int asoc_simple_card_remove(struct platform_device *pdev)
  498. {
  499. struct snd_soc_card *card = platform_get_drvdata(pdev);
  500. struct simple_card_data *priv = snd_soc_card_get_drvdata(card);
  501. if (gpio_is_valid(priv->gpio_hp_det))
  502. snd_soc_jack_free_gpios(&simple_card_hp_jack, 1,
  503. &simple_card_hp_jack_gpio);
  504. if (gpio_is_valid(priv->gpio_mic_det))
  505. snd_soc_jack_free_gpios(&simple_card_mic_jack, 1,
  506. &simple_card_mic_jack_gpio);
  507. return asoc_simple_card_unref(card);
  508. }
  509. static const struct of_device_id asoc_simple_of_match[] = {
  510. { .compatible = "simple-audio-card", },
  511. {},
  512. };
  513. MODULE_DEVICE_TABLE(of, asoc_simple_of_match);
  514. static struct platform_driver asoc_simple_card = {
  515. .driver = {
  516. .name = "asoc-simple-card",
  517. .of_match_table = asoc_simple_of_match,
  518. },
  519. .probe = asoc_simple_card_probe,
  520. .remove = asoc_simple_card_remove,
  521. };
  522. module_platform_driver(asoc_simple_card);
  523. MODULE_ALIAS("platform:asoc-simple-card");
  524. MODULE_LICENSE("GPL");
  525. MODULE_DESCRIPTION("ASoC Simple Sound Card");
  526. MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");