cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

simple-card.c (18723B)


      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
      8#include <linux/clk.h>
      9#include <linux/device.h>
     10#include <linux/module.h>
     11#include <linux/of.h>
     12#include <linux/of_device.h>
     13#include <linux/platform_device.h>
     14#include <linux/string.h>
     15#include <sound/simple_card.h>
     16#include <sound/soc-dai.h>
     17#include <sound/soc.h>
     18
     19#define DPCM_SELECTABLE 1
     20
     21#define DAI	"sound-dai"
     22#define CELL	"#sound-dai-cells"
     23#define PREFIX	"simple-audio-card,"
     24
     25static const struct snd_soc_ops simple_ops = {
     26	.startup	= asoc_simple_startup,
     27	.shutdown	= asoc_simple_shutdown,
     28	.hw_params	= asoc_simple_hw_params,
     29};
     30
     31static int asoc_simple_parse_platform(struct device_node *node,
     32				      struct snd_soc_dai_link_component *dlc)
     33{
     34	struct of_phandle_args args;
     35	int ret;
     36
     37	if (!node)
     38		return 0;
     39
     40	/*
     41	 * Get node via "sound-dai = <&phandle port>"
     42	 * it will be used as xxx_of_node on soc_bind_dai_link()
     43	 */
     44	ret = of_parse_phandle_with_args(node, DAI, CELL, 0, &args);
     45	if (ret)
     46		return ret;
     47
     48	/* dai_name is not required and may not exist for plat component */
     49
     50	dlc->of_node = args.np;
     51
     52	return 0;
     53}
     54
     55static int asoc_simple_parse_dai(struct device_node *node,
     56				 struct snd_soc_dai_link_component *dlc,
     57				 int *is_single_link)
     58{
     59	struct of_phandle_args args;
     60	int ret;
     61
     62	if (!node)
     63		return 0;
     64
     65	/*
     66	 * Get node via "sound-dai = <&phandle port>"
     67	 * it will be used as xxx_of_node on soc_bind_dai_link()
     68	 */
     69	ret = of_parse_phandle_with_args(node, DAI, CELL, 0, &args);
     70	if (ret)
     71		return ret;
     72
     73	/*
     74	 * FIXME
     75	 *
     76	 * Here, dlc->dai_name is pointer to CPU/Codec DAI name.
     77	 * If user unbinded CPU or Codec driver, but not for Sound Card,
     78	 * dlc->dai_name is keeping unbinded CPU or Codec
     79	 * driver's pointer.
     80	 *
     81	 * If user re-bind CPU or Codec driver again, ALSA SoC will try
     82	 * to rebind Card via snd_soc_try_rebind_card(), but because of
     83	 * above reason, it might can't bind Sound Card.
     84	 * Because Sound Card is pointing to released dai_name pointer.
     85	 *
     86	 * To avoid this rebind Card issue,
     87	 * 1) It needs to alloc memory to keep dai_name eventhough
     88	 *    CPU or Codec driver was unbinded, or
     89	 * 2) user need to rebind Sound Card everytime
     90	 *    if he unbinded CPU or Codec.
     91	 */
     92	ret = snd_soc_of_get_dai_name(node, &dlc->dai_name);
     93	if (ret < 0)
     94		return ret;
     95
     96	dlc->of_node = args.np;
     97
     98	if (is_single_link)
     99		*is_single_link = !args.args_count;
    100
    101	return 0;
    102}
    103
    104static void simple_parse_convert(struct device *dev,
    105				 struct device_node *np,
    106				 struct asoc_simple_data *adata)
    107{
    108	struct device_node *top = dev->of_node;
    109	struct device_node *node = of_get_parent(np);
    110
    111	asoc_simple_parse_convert(top,  PREFIX, adata);
    112	asoc_simple_parse_convert(node, PREFIX, adata);
    113	asoc_simple_parse_convert(node, NULL,   adata);
    114	asoc_simple_parse_convert(np,   NULL,   adata);
    115
    116	of_node_put(node);
    117}
    118
    119static void simple_parse_mclk_fs(struct device_node *top,
    120				 struct device_node *np,
    121				 struct simple_dai_props *props,
    122				 char *prefix)
    123{
    124	struct device_node *node = of_get_parent(np);
    125	char prop[128];
    126
    127	snprintf(prop, sizeof(prop), "%smclk-fs", PREFIX);
    128	of_property_read_u32(top,	prop, &props->mclk_fs);
    129
    130	snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
    131	of_property_read_u32(node,	prop, &props->mclk_fs);
    132	of_property_read_u32(np,	prop, &props->mclk_fs);
    133
    134	of_node_put(node);
    135}
    136
    137static int simple_parse_node(struct asoc_simple_priv *priv,
    138			     struct device_node *np,
    139			     struct link_info *li,
    140			     char *prefix,
    141			     int *cpu)
    142{
    143	struct device *dev = simple_priv_to_dev(priv);
    144	struct device_node *top = dev->of_node;
    145	struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
    146	struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
    147	struct snd_soc_dai_link_component *dlc;
    148	struct asoc_simple_dai *dai;
    149	int ret;
    150
    151	if (cpu) {
    152		dlc = asoc_link_to_cpu(dai_link, 0);
    153		dai = simple_props_to_dai_cpu(dai_props, 0);
    154	} else {
    155		dlc = asoc_link_to_codec(dai_link, 0);
    156		dai = simple_props_to_dai_codec(dai_props, 0);
    157	}
    158
    159	simple_parse_mclk_fs(top, np, dai_props, prefix);
    160
    161	ret = asoc_simple_parse_dai(np, dlc, cpu);
    162	if (ret)
    163		return ret;
    164
    165	ret = asoc_simple_parse_clk(dev, np, dai, dlc);
    166	if (ret)
    167		return ret;
    168
    169	ret = asoc_simple_parse_tdm(np, dai);
    170	if (ret)
    171		return ret;
    172
    173	return 0;
    174}
    175
    176static int simple_link_init(struct asoc_simple_priv *priv,
    177			    struct device_node *node,
    178			    struct device_node *codec,
    179			    struct link_info *li,
    180			    char *prefix, char *name)
    181{
    182	struct device *dev = simple_priv_to_dev(priv);
    183	struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
    184	int ret;
    185
    186	ret = asoc_simple_parse_daifmt(dev, node, codec,
    187				       prefix, &dai_link->dai_fmt);
    188	if (ret < 0)
    189		return 0;
    190
    191	dai_link->init			= asoc_simple_dai_init;
    192	dai_link->ops			= &simple_ops;
    193
    194	return asoc_simple_set_dailink_name(dev, dai_link, name);
    195}
    196
    197static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
    198				   struct device_node *np,
    199				   struct device_node *codec,
    200				   struct link_info *li,
    201				   bool is_top)
    202{
    203	struct device *dev = simple_priv_to_dev(priv);
    204	struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
    205	struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
    206	struct device_node *top = dev->of_node;
    207	struct device_node *node = of_get_parent(np);
    208	char *prefix = "";
    209	char dai_name[64];
    210	int ret;
    211
    212	dev_dbg(dev, "link_of DPCM (%pOF)\n", np);
    213
    214	/* For single DAI link & old style of DT node */
    215	if (is_top)
    216		prefix = PREFIX;
    217
    218	if (li->cpu) {
    219		struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0);
    220		struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0);
    221		int is_single_links = 0;
    222
    223		/* Codec is dummy */
    224
    225		/* FE settings */
    226		dai_link->dynamic		= 1;
    227		dai_link->dpcm_merged_format	= 1;
    228
    229		ret = simple_parse_node(priv, np, li, prefix, &is_single_links);
    230		if (ret < 0)
    231			goto out_put_node;
    232
    233		snprintf(dai_name, sizeof(dai_name), "fe.%s", cpus->dai_name);
    234
    235		asoc_simple_canonicalize_cpu(cpus, is_single_links);
    236		asoc_simple_canonicalize_platform(platforms, cpus);
    237	} else {
    238		struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0);
    239		struct snd_soc_codec_conf *cconf;
    240
    241		/* CPU is dummy */
    242
    243		/* BE settings */
    244		dai_link->no_pcm		= 1;
    245		dai_link->be_hw_params_fixup	= asoc_simple_be_hw_params_fixup;
    246
    247		cconf	= simple_props_to_codec_conf(dai_props, 0);
    248
    249		ret = simple_parse_node(priv, np, li, prefix, NULL);
    250		if (ret < 0)
    251			goto out_put_node;
    252
    253		snprintf(dai_name, sizeof(dai_name), "be.%s", codecs->dai_name);
    254
    255		/* check "prefix" from top node */
    256		snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node,
    257					      PREFIX "prefix");
    258		snd_soc_of_parse_node_prefix(node, cconf, codecs->of_node,
    259					     "prefix");
    260		snd_soc_of_parse_node_prefix(np, cconf, codecs->of_node,
    261					     "prefix");
    262	}
    263
    264	simple_parse_convert(dev, np, &dai_props->adata);
    265
    266	snd_soc_dai_link_set_capabilities(dai_link);
    267
    268	ret = simple_link_init(priv, node, codec, li, prefix, dai_name);
    269
    270out_put_node:
    271	li->link++;
    272
    273	of_node_put(node);
    274	return ret;
    275}
    276
    277static int simple_dai_link_of(struct asoc_simple_priv *priv,
    278			      struct device_node *np,
    279			      struct device_node *codec,
    280			      struct link_info *li,
    281			      bool is_top)
    282{
    283	struct device *dev = simple_priv_to_dev(priv);
    284	struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
    285	struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0);
    286	struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0);
    287	struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0);
    288	struct device_node *cpu = NULL;
    289	struct device_node *node = NULL;
    290	struct device_node *plat = NULL;
    291	char dai_name[64];
    292	char prop[128];
    293	char *prefix = "";
    294	int ret, single_cpu = 0;
    295
    296	cpu  = np;
    297	node = of_get_parent(np);
    298
    299	dev_dbg(dev, "link_of (%pOF)\n", node);
    300
    301	/* For single DAI link & old style of DT node */
    302	if (is_top)
    303		prefix = PREFIX;
    304
    305	snprintf(prop, sizeof(prop), "%splat", prefix);
    306	plat = of_get_child_by_name(node, prop);
    307
    308	ret = simple_parse_node(priv, cpu, li, prefix, &single_cpu);
    309	if (ret < 0)
    310		goto dai_link_of_err;
    311
    312	ret = simple_parse_node(priv, codec, li, prefix, NULL);
    313	if (ret < 0)
    314		goto dai_link_of_err;
    315
    316	ret = asoc_simple_parse_platform(plat, platforms);
    317	if (ret < 0)
    318		goto dai_link_of_err;
    319
    320	snprintf(dai_name, sizeof(dai_name),
    321		 "%s-%s", cpus->dai_name, codecs->dai_name);
    322
    323	asoc_simple_canonicalize_cpu(cpus, single_cpu);
    324	asoc_simple_canonicalize_platform(platforms, cpus);
    325
    326	ret = simple_link_init(priv, node, codec, li, prefix, dai_name);
    327
    328dai_link_of_err:
    329	of_node_put(plat);
    330	of_node_put(node);
    331
    332	li->link++;
    333
    334	return ret;
    335}
    336
    337static int __simple_for_each_link(struct asoc_simple_priv *priv,
    338			struct link_info *li,
    339			int (*func_noml)(struct asoc_simple_priv *priv,
    340					 struct device_node *np,
    341					 struct device_node *codec,
    342					 struct link_info *li, bool is_top),
    343			int (*func_dpcm)(struct asoc_simple_priv *priv,
    344					 struct device_node *np,
    345					 struct device_node *codec,
    346					 struct link_info *li, bool is_top))
    347{
    348	struct device *dev = simple_priv_to_dev(priv);
    349	struct device_node *top = dev->of_node;
    350	struct device_node *node;
    351	uintptr_t dpcm_selectable = (uintptr_t)of_device_get_match_data(dev);
    352	bool is_top = 0;
    353	int ret = 0;
    354
    355	/* Check if it has dai-link */
    356	node = of_get_child_by_name(top, PREFIX "dai-link");
    357	if (!node) {
    358		node = of_node_get(top);
    359		is_top = 1;
    360	}
    361
    362	/* loop for all dai-link */
    363	do {
    364		struct asoc_simple_data adata;
    365		struct device_node *codec;
    366		struct device_node *plat;
    367		struct device_node *np;
    368		int num = of_get_child_count(node);
    369
    370		/* get codec */
    371		codec = of_get_child_by_name(node, is_top ?
    372					     PREFIX "codec" : "codec");
    373		if (!codec) {
    374			ret = -ENODEV;
    375			goto error;
    376		}
    377		/* get platform */
    378		plat = of_get_child_by_name(node, is_top ?
    379					    PREFIX "plat" : "plat");
    380
    381		/* get convert-xxx property */
    382		memset(&adata, 0, sizeof(adata));
    383		for_each_child_of_node(node, np)
    384			simple_parse_convert(dev, np, &adata);
    385
    386		/* loop for all CPU/Codec node */
    387		for_each_child_of_node(node, np) {
    388			if (plat == np)
    389				continue;
    390			/*
    391			 * It is DPCM
    392			 * if it has many CPUs,
    393			 * or has convert-xxx property
    394			 */
    395			if (dpcm_selectable &&
    396			    (num > 2 ||
    397			     adata.convert_rate || adata.convert_channels)) {
    398				/*
    399				 * np
    400				 *	 |1(CPU)|0(Codec)  li->cpu
    401				 * CPU	 |Pass  |return
    402				 * Codec |return|Pass
    403				 */
    404				if (li->cpu != (np == codec))
    405					ret = func_dpcm(priv, np, codec, li, is_top);
    406			/* else normal sound */
    407			} else {
    408				/*
    409				 * np
    410				 *	 |1(CPU)|0(Codec)  li->cpu
    411				 * CPU	 |Pass  |return
    412				 * Codec |return|return
    413				 */
    414				if (li->cpu && (np != codec))
    415					ret = func_noml(priv, np, codec, li, is_top);
    416			}
    417
    418			if (ret < 0) {
    419				of_node_put(codec);
    420				of_node_put(np);
    421				goto error;
    422			}
    423		}
    424
    425		of_node_put(codec);
    426		node = of_get_next_child(top, node);
    427	} while (!is_top && node);
    428
    429 error:
    430	of_node_put(node);
    431	return ret;
    432}
    433
    434static int simple_for_each_link(struct asoc_simple_priv *priv,
    435				struct link_info *li,
    436				int (*func_noml)(struct asoc_simple_priv *priv,
    437						 struct device_node *np,
    438						 struct device_node *codec,
    439						 struct link_info *li, bool is_top),
    440				int (*func_dpcm)(struct asoc_simple_priv *priv,
    441						 struct device_node *np,
    442						 struct device_node *codec,
    443						 struct link_info *li, bool is_top))
    444{
    445	int ret;
    446	/*
    447	 * Detect all CPU first, and Detect all Codec 2nd.
    448	 *
    449	 * In Normal sound case, all DAIs are detected
    450	 * as "CPU-Codec".
    451	 *
    452	 * In DPCM sound case,
    453	 * all CPUs   are detected as "CPU-dummy", and
    454	 * all Codecs are detected as "dummy-Codec".
    455	 * To avoid random sub-device numbering,
    456	 * detect "dummy-Codec" in last;
    457	 */
    458	for (li->cpu = 1; li->cpu >= 0; li->cpu--) {
    459		ret = __simple_for_each_link(priv, li, func_noml, func_dpcm);
    460		if (ret < 0)
    461			break;
    462	}
    463
    464	return ret;
    465}
    466
    467static int simple_parse_of(struct asoc_simple_priv *priv, struct link_info *li)
    468{
    469	struct snd_soc_card *card = simple_priv_to_card(priv);
    470	int ret;
    471
    472	ret = asoc_simple_parse_widgets(card, PREFIX);
    473	if (ret < 0)
    474		return ret;
    475
    476	ret = asoc_simple_parse_routing(card, PREFIX);
    477	if (ret < 0)
    478		return ret;
    479
    480	ret = asoc_simple_parse_pin_switches(card, PREFIX);
    481	if (ret < 0)
    482		return ret;
    483
    484	/* Single/Muti DAI link(s) & New style of DT node */
    485	memset(li, 0, sizeof(*li));
    486	ret = simple_for_each_link(priv, li,
    487				   simple_dai_link_of,
    488				   simple_dai_link_of_dpcm);
    489	if (ret < 0)
    490		return ret;
    491
    492	ret = asoc_simple_parse_card_name(card, PREFIX);
    493	if (ret < 0)
    494		return ret;
    495
    496	ret = snd_soc_of_parse_aux_devs(card, PREFIX "aux-devs");
    497
    498	return ret;
    499}
    500
    501static int simple_count_noml(struct asoc_simple_priv *priv,
    502			     struct device_node *np,
    503			     struct device_node *codec,
    504			     struct link_info *li, bool is_top)
    505{
    506	if (li->link >= SNDRV_MAX_LINKS) {
    507		struct device *dev = simple_priv_to_dev(priv);
    508
    509		dev_err(dev, "too many links\n");
    510		return -EINVAL;
    511	}
    512
    513	li->num[li->link].cpus		= 1;
    514	li->num[li->link].codecs	= 1;
    515	li->num[li->link].platforms	= 1;
    516
    517	li->link += 1;
    518
    519	return 0;
    520}
    521
    522static int simple_count_dpcm(struct asoc_simple_priv *priv,
    523			     struct device_node *np,
    524			     struct device_node *codec,
    525			     struct link_info *li, bool is_top)
    526{
    527	if (li->link >= SNDRV_MAX_LINKS) {
    528		struct device *dev = simple_priv_to_dev(priv);
    529
    530		dev_err(dev, "too many links\n");
    531		return -EINVAL;
    532	}
    533
    534	if (li->cpu) {
    535		li->num[li->link].cpus		= 1;
    536		li->num[li->link].platforms	= 1;
    537
    538		li->link++; /* CPU-dummy */
    539	} else {
    540		li->num[li->link].codecs	= 1;
    541
    542		li->link++; /* dummy-Codec */
    543	}
    544
    545	return 0;
    546}
    547
    548static int simple_get_dais_count(struct asoc_simple_priv *priv,
    549				 struct link_info *li)
    550{
    551	struct device *dev = simple_priv_to_dev(priv);
    552	struct device_node *top = dev->of_node;
    553
    554	/*
    555	 * link_num :	number of links.
    556	 *		CPU-Codec / CPU-dummy / dummy-Codec
    557	 * dais_num :	number of DAIs
    558	 * ccnf_num :	number of codec_conf
    559	 *		same number for "dummy-Codec"
    560	 *
    561	 * ex1)
    562	 * CPU0 --- Codec0	link : 5
    563	 * CPU1 --- Codec1	dais : 7
    564	 * CPU2 -/		ccnf : 1
    565	 * CPU3 --- Codec2
    566	 *
    567	 *	=> 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
    568	 *	=> 7 DAIs  = 4xCPU + 3xCodec
    569	 *	=> 1 ccnf  = 1xdummy-Codec
    570	 *
    571	 * ex2)
    572	 * CPU0 --- Codec0	link : 5
    573	 * CPU1 --- Codec1	dais : 6
    574	 * CPU2 -/		ccnf : 1
    575	 * CPU3 -/
    576	 *
    577	 *	=> 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
    578	 *	=> 6 DAIs  = 4xCPU + 2xCodec
    579	 *	=> 1 ccnf  = 1xdummy-Codec
    580	 *
    581	 * ex3)
    582	 * CPU0 --- Codec0	link : 6
    583	 * CPU1 -/		dais : 6
    584	 * CPU2 --- Codec1	ccnf : 2
    585	 * CPU3 -/
    586	 *
    587	 *	=> 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
    588	 *	=> 6 DAIs  = 4xCPU + 2xCodec
    589	 *	=> 2 ccnf  = 2xdummy-Codec
    590	 *
    591	 * ex4)
    592	 * CPU0 --- Codec0 (convert-rate)	link : 3
    593	 * CPU1 --- Codec1			dais : 4
    594	 *					ccnf : 1
    595	 *
    596	 *	=> 3 links = 1xCPU-Codec + 1xCPU-dummy + 1xdummy-Codec
    597	 *	=> 4 DAIs  = 2xCPU + 2xCodec
    598	 *	=> 1 ccnf  = 1xdummy-Codec
    599	 */
    600	if (!top) {
    601		li->num[0].cpus		= 1;
    602		li->num[0].codecs	= 1;
    603		li->num[0].platforms	= 1;
    604
    605		li->link = 1;
    606		return 0;
    607	}
    608
    609	return simple_for_each_link(priv, li,
    610				    simple_count_noml,
    611				    simple_count_dpcm);
    612}
    613
    614static int simple_soc_probe(struct snd_soc_card *card)
    615{
    616	struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
    617	int ret;
    618
    619	ret = asoc_simple_init_hp(card, &priv->hp_jack, PREFIX);
    620	if (ret < 0)
    621		return ret;
    622
    623	ret = asoc_simple_init_mic(card, &priv->mic_jack, PREFIX);
    624	if (ret < 0)
    625		return ret;
    626
    627	return 0;
    628}
    629
    630static int asoc_simple_probe(struct platform_device *pdev)
    631{
    632	struct asoc_simple_priv *priv;
    633	struct device *dev = &pdev->dev;
    634	struct device_node *np = dev->of_node;
    635	struct snd_soc_card *card;
    636	struct link_info *li;
    637	int ret;
    638
    639	/* Allocate the private data and the DAI link array */
    640	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
    641	if (!priv)
    642		return -ENOMEM;
    643
    644	card = simple_priv_to_card(priv);
    645	card->owner		= THIS_MODULE;
    646	card->dev		= dev;
    647	card->probe		= simple_soc_probe;
    648	card->driver_name       = "simple-card";
    649
    650	li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL);
    651	if (!li)
    652		return -ENOMEM;
    653
    654	ret = simple_get_dais_count(priv, li);
    655	if (ret < 0)
    656		return ret;
    657
    658	if (!li->link)
    659		return -EINVAL;
    660
    661	ret = asoc_simple_init_priv(priv, li);
    662	if (ret < 0)
    663		return ret;
    664
    665	if (np && of_device_is_available(np)) {
    666
    667		ret = simple_parse_of(priv, li);
    668		if (ret < 0) {
    669			dev_err_probe(dev, ret, "parse error\n");
    670			goto err;
    671		}
    672
    673	} else {
    674		struct asoc_simple_card_info *cinfo;
    675		struct snd_soc_dai_link_component *cpus;
    676		struct snd_soc_dai_link_component *codecs;
    677		struct snd_soc_dai_link_component *platform;
    678		struct snd_soc_dai_link *dai_link = priv->dai_link;
    679		struct simple_dai_props *dai_props = priv->dai_props;
    680
    681		cinfo = dev->platform_data;
    682		if (!cinfo) {
    683			dev_err(dev, "no info for asoc-simple-card\n");
    684			return -EINVAL;
    685		}
    686
    687		if (!cinfo->name ||
    688		    !cinfo->codec_dai.name ||
    689		    !cinfo->codec ||
    690		    !cinfo->platform ||
    691		    !cinfo->cpu_dai.name) {
    692			dev_err(dev, "insufficient asoc_simple_card_info settings\n");
    693			return -EINVAL;
    694		}
    695
    696		cpus			= dai_link->cpus;
    697		cpus->dai_name		= cinfo->cpu_dai.name;
    698
    699		codecs			= dai_link->codecs;
    700		codecs->name		= cinfo->codec;
    701		codecs->dai_name	= cinfo->codec_dai.name;
    702
    703		platform		= dai_link->platforms;
    704		platform->name		= cinfo->platform;
    705
    706		card->name		= (cinfo->card) ? cinfo->card : cinfo->name;
    707		dai_link->name		= cinfo->name;
    708		dai_link->stream_name	= cinfo->name;
    709		dai_link->dai_fmt	= cinfo->daifmt;
    710		dai_link->init		= asoc_simple_dai_init;
    711		memcpy(dai_props->cpu_dai, &cinfo->cpu_dai,
    712					sizeof(*dai_props->cpu_dai));
    713		memcpy(dai_props->codec_dai, &cinfo->codec_dai,
    714					sizeof(*dai_props->codec_dai));
    715	}
    716
    717	snd_soc_card_set_drvdata(card, priv);
    718
    719	asoc_simple_debug_info(priv);
    720
    721	ret = devm_snd_soc_register_card(dev, card);
    722	if (ret < 0)
    723		goto err;
    724
    725	devm_kfree(dev, li);
    726	return 0;
    727err:
    728	asoc_simple_clean_reference(card);
    729
    730	return ret;
    731}
    732
    733static const struct of_device_id simple_of_match[] = {
    734	{ .compatible = "simple-audio-card", },
    735	{ .compatible = "simple-scu-audio-card",
    736	  .data = (void *)DPCM_SELECTABLE },
    737	{},
    738};
    739MODULE_DEVICE_TABLE(of, simple_of_match);
    740
    741static struct platform_driver asoc_simple_card = {
    742	.driver = {
    743		.name = "asoc-simple-card",
    744		.pm = &snd_soc_pm_ops,
    745		.of_match_table = simple_of_match,
    746	},
    747	.probe = asoc_simple_probe,
    748	.remove = asoc_simple_remove,
    749};
    750
    751module_platform_driver(asoc_simple_card);
    752
    753MODULE_ALIAS("platform:asoc-simple-card");
    754MODULE_LICENSE("GPL v2");
    755MODULE_DESCRIPTION("ASoC Simple Sound Card");
    756MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");