simple-card.c 19.0 KB
Newer Older
1 2 3 4 5 6 7
// SPDX-License-Identifier: GPL-2.0
//
// ASoC simple sound card support
//
// Copyright (C) 2012 Renesas Solutions Corp.
// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>

8
#include <linux/clk.h>
9
#include <linux/device.h>
10
#include <linux/module.h>
11
#include <linux/of.h>
12
#include <linux/platform_device.h>
13
#include <linux/string.h>
14
#include <sound/simple_card.h>
15 16
#include <sound/soc-dai.h>
#include <sound/soc.h>
17

18 19
struct simple_card_data {
	struct snd_soc_card snd_card;
20
	struct simple_dai_props {
21 22
		struct asoc_simple_dai *cpu_dai;
		struct asoc_simple_dai *codec_dai;
23
		struct snd_soc_dai_link_component codecs; /* single codec */
24
		struct snd_soc_dai_link_component platform;
25 26
		struct asoc_simple_card_data adata;
		struct snd_soc_codec_conf *codec_conf;
27
		unsigned int mclk_fs;
28
	} *dai_props;
29 30
	struct asoc_simple_jack hp_jack;
	struct asoc_simple_jack mic_jack;
31
	struct snd_soc_dai_link *dai_link;
32
	struct asoc_simple_dai *dais;
33
	struct snd_soc_codec_conf *codec_conf;
34 35
};

36
#define simple_priv_to_card(priv) (&(priv)->snd_card)
37
#define simple_priv_to_props(priv, i) ((priv)->dai_props + (i))
38 39
#define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev)
#define simple_priv_to_link(priv, i) (simple_priv_to_card(priv)->dai_link + (i))
40

41 42
#define DAI	"sound-dai"
#define CELL	"#sound-dai-cells"
43 44
#define PREFIX	"simple-audio-card,"

45 46 47 48 49
static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct simple_card_data *priv =	snd_soc_card_get_drvdata(rtd->card);
	struct simple_dai_props *dai_props =
50
		simple_priv_to_props(priv, rtd->num);
51 52
	int ret;

53
	ret = asoc_simple_card_clk_enable(dai_props->cpu_dai);
54 55
	if (ret)
		return ret;
56

57
	ret = asoc_simple_card_clk_enable(dai_props->codec_dai);
58
	if (ret)
59
		asoc_simple_card_clk_disable(dai_props->cpu_dai);
60 61 62 63 64 65 66 67 68

	return ret;
}

static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct simple_card_data *priv =	snd_soc_card_get_drvdata(rtd->card);
	struct simple_dai_props *dai_props =
69
		simple_priv_to_props(priv, rtd->num);
70

71
	asoc_simple_card_clk_disable(dai_props->cpu_dai);
72

73
	asoc_simple_card_clk_disable(dai_props->codec_dai);
74 75
}

76 77 78
static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai,
				    unsigned long rate)
{
79 80 81
	if (!simple_dai)
		return 0;

82 83 84 85 86 87 88 89 90
	if (!simple_dai->clk)
		return 0;

	if (clk_get_rate(simple_dai->clk) == rate)
		return 0;

	return clk_set_rate(simple_dai->clk, rate);
}

91 92 93 94 95
static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
				      struct snd_pcm_hw_params *params)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_dai *codec_dai = rtd->codec_dai;
96
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
97
	struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
98 99
	struct simple_dai_props *dai_props =
		simple_priv_to_props(priv, rtd->num);
100
	unsigned int mclk, mclk_fs = 0;
101 102
	int ret = 0;

103
	if (dai_props->mclk_fs)
104 105 106 107
		mclk_fs = dai_props->mclk_fs;

	if (mclk_fs) {
		mclk = params_rate(params) * mclk_fs;
108

109
		ret = asoc_simple_set_clk_rate(dai_props->codec_dai, mclk);
110 111 112
		if (ret < 0)
			return ret;

113
		ret = asoc_simple_set_clk_rate(dai_props->cpu_dai, mclk);
114 115 116
		if (ret < 0)
			return ret;

117 118
		ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
					     SND_SOC_CLOCK_IN);
119 120 121 122 123 124 125
		if (ret && ret != -ENOTSUPP)
			goto err;

		ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
					     SND_SOC_CLOCK_OUT);
		if (ret && ret != -ENOTSUPP)
			goto err;
126
	}
127
	return 0;
128
err:
129 130 131
	return ret;
}

132
static const struct snd_soc_ops asoc_simple_card_ops = {
133 134
	.startup = asoc_simple_card_startup,
	.shutdown = asoc_simple_card_shutdown,
135 136 137
	.hw_params = asoc_simple_card_hw_params,
};

138 139
static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
{
140
	struct simple_card_data *priv =	snd_soc_card_get_drvdata(rtd->card);
141
	struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
142
	int ret;
143

144 145
	ret = asoc_simple_card_init_dai(rtd->codec_dai,
					dai_props->codec_dai);
146 147
	if (ret < 0)
		return ret;
148

149 150
	ret = asoc_simple_card_init_dai(rtd->cpu_dai,
					dai_props->cpu_dai);
151 152
	if (ret < 0)
		return ret;
153 154 155 156

	return 0;
}

157 158 159 160 161 162 163 164 165 166 167
static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
					       struct snd_pcm_hw_params *params)
{
	struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
	struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);

	asoc_simple_card_convert_fixup(&dai_props->adata, params);

	return 0;
}

168 169
static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top,
					     struct device_node *node,
170 171 172 173 174 175 176 177 178 179 180 181
					     struct device_node *np,
					     struct device_node *codec,
					     struct simple_card_data *priv,
					     int *dai_idx, int link_idx,
					     int *conf_idx, int is_fe,
					     bool is_top_level_node)
{
	struct device *dev = simple_priv_to_dev(priv);
	struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx);
	struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx);
	struct snd_soc_card *card = simple_priv_to_card(priv);
	struct asoc_simple_dai *dai;
182
	char prop[128];
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
	char *prefix = "";
	int ret;

	/* For single DAI link & old style of DT node */
	if (is_top_level_node)
		prefix = PREFIX;

	if (is_fe) {
		int is_single_links = 0;
		struct snd_soc_dai_link_component *codecs;

		/* BE is dummy */
		codecs			= dai_link->codecs;
		codecs->of_node		= NULL;
		codecs->dai_name	= "snd-soc-dummy-dai";
		codecs->name		= "snd-soc-dummy";

		/* FE settings */
		dai_link->dynamic		= 1;
		dai_link->dpcm_merged_format	= 1;

		dai =
		dai_props->cpu_dai	= &priv->dais[(*dai_idx)++];

		ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL,
						 &is_single_links);
		if (ret)
			return ret;

		ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai);
		if (ret < 0)
			return ret;

		ret = asoc_simple_card_set_dailink_name(dev, dai_link,
							"fe.%s",
							dai_link->cpu_dai_name);
		if (ret < 0)
			return ret;

		asoc_simple_card_canonicalize_cpu(dai_link, is_single_links);
	} else {
		struct snd_soc_codec_conf *cconf;

		/* FE is dummy */
		dai_link->cpu_of_node		= NULL;
		dai_link->cpu_dai_name		= "snd-soc-dummy-dai";
		dai_link->cpu_name		= "snd-soc-dummy";

		/* BE settings */
		dai_link->no_pcm		= 1;
		dai_link->be_hw_params_fixup	= asoc_simple_card_be_hw_params_fixup;

		dai =
		dai_props->codec_dai	= &priv->dais[(*dai_idx)++];

		cconf =
		dai_props->codec_conf	= &priv->codec_conf[(*conf_idx)++];

		ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL);
		if (ret < 0)
			return ret;

		ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai);
		if (ret < 0)
			return ret;

		ret = asoc_simple_card_set_dailink_name(dev, dai_link,
							"be.%s",
							dai_link->codecs->dai_name);
		if (ret < 0)
			return ret;

		/* check "prefix" from top node */
		snd_soc_of_parse_audio_prefix(card, cconf,
					      dai_link->codecs->of_node,
					      PREFIX "prefix");
		/* check "prefix" from each node if top doesn't have */
		if (!cconf->of_node)
			snd_soc_of_parse_node_prefix(np, cconf,
						     dai_link->codecs->of_node,
						     "prefix");
	}

266
	asoc_simple_card_parse_convert(dev, top,  PREFIX, &dai_props->adata);
267
	asoc_simple_card_parse_convert(dev, node, prefix, &dai_props->adata);
268
	asoc_simple_card_parse_convert(dev, np,   NULL,   &dai_props->adata);
269 270 271 272 273 274 275 276 277

	ret = asoc_simple_card_of_parse_tdm(np, dai);
	if (ret)
		return ret;

	ret = asoc_simple_card_canonicalize_dailink(dai_link);
	if (ret < 0)
		return ret;

278 279 280 281
	snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
	of_property_read_u32(top,  PREFIX "mclk-fs", &dai_props->mclk_fs);
	of_property_read_u32(node, prop, &dai_props->mclk_fs);
	of_property_read_u32(np,   prop, &dai_props->mclk_fs);
282 283 284 285 286 287 288 289 290 291 292 293 294 295

	ret = asoc_simple_card_parse_daifmt(dev, node, codec,
					    prefix, &dai_link->dai_fmt);
	if (ret < 0)
		return ret;

	dai_link->dpcm_playback		= 1;
	dai_link->dpcm_capture		= 1;
	dai_link->ops			= &asoc_simple_card_ops;
	dai_link->init			= asoc_simple_card_dai_init;

	return 0;
}

296 297
static int asoc_simple_card_dai_link_of(struct device_node *top,
					struct device_node *node,
298
					struct simple_card_data *priv,
299
					int *dai_idx, int link_idx,
300
					bool is_top_level_node)
301
{
302
	struct device *dev = simple_priv_to_dev(priv);
303 304 305 306
	struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx);
	struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx);
	struct asoc_simple_dai *cpu_dai;
	struct asoc_simple_dai *codec_dai;
307
	struct device_node *cpu = NULL;
308
	struct device_node *plat = NULL;
309
	struct device_node *codec = NULL;
310 311
	char prop[128];
	char *prefix = "";
312
	int ret, single_cpu;
313

314
	/* For single DAI link & old style of DT node */
315
	if (is_top_level_node)
316
		prefix = PREFIX;
317 318

	snprintf(prop, sizeof(prop), "%scpu", prefix);
319 320
	cpu = of_get_child_by_name(node, prop);

321 322 323 324 325 326
	if (!cpu) {
		ret = -EINVAL;
		dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
		goto dai_link_of_err;
	}

327 328 329
	snprintf(prop, sizeof(prop), "%splat", prefix);
	plat = of_get_child_by_name(node, prop);

330 331 332
	snprintf(prop, sizeof(prop), "%scodec", prefix);
	codec = of_get_child_by_name(node, prop);

333
	if (!codec) {
334
		ret = -EINVAL;
335
		dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
336
		goto dai_link_of_err;
337
	}
338

339 340 341 342 343
	cpu_dai			=
	dai_props->cpu_dai	= &priv->dais[(*dai_idx)++];
	codec_dai		=
	dai_props->codec_dai	= &priv->dais[(*dai_idx)++];

344 345
	ret = asoc_simple_card_parse_daifmt(dev, node, codec,
					    prefix, &dai_link->dai_fmt);
346 347 348
	if (ret < 0)
		goto dai_link_of_err;

349 350 351 352 353
	snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
	of_property_read_u32(top,  PREFIX "mclk-fs", &dai_props->mclk_fs);
	of_property_read_u32(node,  prop, &dai_props->mclk_fs);
	of_property_read_u32(cpu,   prop, &dai_props->mclk_fs);
	of_property_read_u32(codec, prop, &dai_props->mclk_fs);
354

355 356 357 358 359 360 361 362 363 364 365 366 367
	ret = asoc_simple_card_parse_cpu(cpu, dai_link,
					 DAI, CELL, &single_cpu);
	if (ret < 0)
		goto dai_link_of_err;

	ret = asoc_simple_card_parse_codec(codec, dai_link, DAI, CELL);
	if (ret < 0)
		goto dai_link_of_err;

	ret = asoc_simple_card_parse_platform(plat, dai_link, DAI, CELL);
	if (ret < 0)
		goto dai_link_of_err;

368
	ret = asoc_simple_card_of_parse_tdm(cpu, cpu_dai);
369 370 371
	if (ret < 0)
		goto dai_link_of_err;

372
	ret = asoc_simple_card_of_parse_tdm(codec, codec_dai);
373 374 375
	if (ret < 0)
		goto dai_link_of_err;

376
	ret = asoc_simple_card_parse_clk_cpu(dev, cpu, dai_link, cpu_dai);
377 378 379
	if (ret < 0)
		goto dai_link_of_err;

380
	ret = asoc_simple_card_parse_clk_codec(dev, codec, dai_link, codec_dai);
381 382 383
	if (ret < 0)
		goto dai_link_of_err;

384 385
	ret = asoc_simple_card_canonicalize_dailink(dai_link);
	if (ret < 0)
386
		goto dai_link_of_err;
387

388 389 390
	ret = asoc_simple_card_set_dailink_name(dev, dai_link,
						"%s-%s",
						dai_link->cpu_dai_name,
391
						dai_link->codecs->dai_name);
392
	if (ret < 0)
393 394
		goto dai_link_of_err;

395
	dai_link->ops = &asoc_simple_card_ops;
396
	dai_link->init = asoc_simple_card_dai_init;
397

398
	asoc_simple_card_canonicalize_cpu(dai_link, single_cpu);
399

400
dai_link_of_err:
401 402 403
	of_node_put(cpu);
	of_node_put(codec);

404 405 406
	return ret;
}

407 408 409 410 411
static int asoc_simple_card_parse_aux_devs(struct device_node *node,
					   struct simple_card_data *priv)
{
	struct device *dev = simple_priv_to_dev(priv);
	struct device_node *aux_node;
412
	struct snd_soc_card *card = simple_priv_to_card(priv);
413 414 415 416 417 418 419 420 421
	int i, n, len;

	if (!of_find_property(node, PREFIX "aux-devs", &len))
		return 0;		/* Ok to have no aux-devs */

	n = len / sizeof(__be32);
	if (n <= 0)
		return -EINVAL;

422 423
	card->aux_dev = devm_kcalloc(dev,
			n, sizeof(*card->aux_dev), GFP_KERNEL);
424
	if (!card->aux_dev)
425 426 427 428 429 430
		return -ENOMEM;

	for (i = 0; i < n; i++) {
		aux_node = of_parse_phandle(node, PREFIX "aux-devs", i);
		if (!aux_node)
			return -EINVAL;
431
		card->aux_dev[i].codec_of_node = aux_node;
432 433
	}

434
	card->num_aux_devs = n;
435 436 437
	return 0;
}

438
static int asoc_simple_card_parse_of(struct simple_card_data *priv)
439
{
440
	struct device *dev = simple_priv_to_dev(priv);
441
	struct device_node *top = dev->of_node;
442
	struct snd_soc_card *card = simple_priv_to_card(priv);
443 444 445 446 447 448 449 450
	struct device_node *node;
	struct device_node *np;
	struct device_node *codec;
	bool is_fe;
	int ret, loop;
	int dai_idx, link_idx, conf_idx;

	if (!top)
451 452
		return -EINVAL;

453 454
	ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
	if (ret < 0)
455
		return ret;
456

457
	ret = asoc_simple_card_of_parse_routing(card, PREFIX);
458
	if (ret < 0)
459
		return ret;
460

461
	/* Single/Muti DAI link(s) & New style of DT node */
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
	loop		= 1;
	link_idx	= 0;
	dai_idx		= 0;
	conf_idx	= 0;
	node = of_get_child_by_name(top, PREFIX "dai-link");
	if (!node) {
		node = dev->of_node;
		loop = 0;
	}

	do  {
		/* DPCM */
		if (of_get_child_count(node) > 2) {
			for_each_child_of_node(node, np) {
				codec = of_get_child_by_name(node,
							loop ?	"codec" :
								PREFIX "codec");
				if (!codec)
					return -ENODEV;

				is_fe = (np != codec);

				ret = asoc_simple_card_dai_link_of_dpcm(
485
						top, node, np, codec, priv,
486 487
						&dai_idx, link_idx++, &conf_idx,
						is_fe, !loop);
488
			}
489 490
		} else {
			ret = asoc_simple_card_dai_link_of(
491
						top, node, priv,
492
						&dai_idx, link_idx++, !loop);
493 494
		}
		if (ret < 0)
495 496 497 498
			return ret;

		node = of_get_next_child(top, node);
	} while (loop && node);
499

500
	ret = asoc_simple_card_parse_card_name(card, PREFIX);
501
	if (ret < 0)
502
		return ret;
503

504
	ret = asoc_simple_card_parse_aux_devs(top, priv);
505 506

	return ret;
507 508
}

509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582
static void asoc_simple_card_get_dais_count(struct device *dev,
					    int *link_num,
					    int *dais_num,
					    int *ccnf_num)
{
	struct device_node *top = dev->of_node;
	struct device_node *node;
	int loop;
	int num;

	/*
	 * link_num :	number of links.
	 *		CPU-Codec / CPU-dummy / dummy-Codec
	 * dais_num :	number of DAIs
	 * ccnf_num :	number of codec_conf
	 *		same number for "dummy-Codec"
	 *
	 * ex1)
	 * CPU0 --- Codec0	link : 5
	 * CPU1 --- Codec1	dais : 7
	 * CPU2 -/		ccnf : 1
	 * CPU3 --- Codec2
	 *
	 *	=> 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
	 *	=> 7 DAIs  = 4xCPU + 3xCodec
	 *	=> 1 ccnf  = 1xdummy-Codec
	 *
	 * ex2)
	 * CPU0 --- Codec0	link : 5
	 * CPU1 --- Codec1	dais : 6
	 * CPU2 -/		ccnf : 1
	 * CPU3 -/
	 *
	 *	=> 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
	 *	=> 6 DAIs  = 4xCPU + 2xCodec
	 *	=> 1 ccnf  = 1xdummy-Codec
	 *
	 * ex3)
	 * CPU0 --- Codec0	link : 6
	 * CPU1 -/		dais : 6
	 * CPU2 --- Codec1	ccnf : 2
	 * CPU3 -/
	 *
	 *	=> 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
	 *	=> 6 DAIs  = 4xCPU + 2xCodec
	 *	=> 2 ccnf  = 2xdummy-Codec
	 */
	if (!top) {
		(*link_num) = 1;
		(*dais_num) = 2;
		(*ccnf_num) = 0;
		return;
	}

	loop = 1;
	node = of_get_child_by_name(top, PREFIX "dai-link");
	if (!node) {
		node = top;
		loop = 0;
	}

	do {
		num = of_get_child_count(node);
		(*dais_num) += num;
		if (num > 2) {
			(*link_num) += num;
			(*ccnf_num)++;
		} else {
			(*link_num)++;
		}
		node = of_get_next_child(top, node);
	} while (loop && node);
}

583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
static int asoc_simple_soc_card_probe(struct snd_soc_card *card)
{
	struct simple_card_data *priv = snd_soc_card_get_drvdata(card);
	int ret;

	ret = asoc_simple_card_init_hp(card, &priv->hp_jack, PREFIX);
	if (ret < 0)
		return ret;

	ret = asoc_simple_card_init_mic(card, &priv->mic_jack, PREFIX);
	if (ret < 0)
		return ret;

	return 0;
}

599 600
static int asoc_simple_card_probe(struct platform_device *pdev)
{
601
	struct simple_card_data *priv;
602
	struct snd_soc_dai_link *dai_link;
603
	struct simple_dai_props *dai_props;
604
	struct asoc_simple_dai *dais;
605
	struct device *dev = &pdev->dev;
606
	struct device_node *np = dev->of_node;
607
	struct snd_soc_card *card;
608 609 610
	struct snd_soc_codec_conf *cconf;
	int lnum = 0, dnum = 0, cnum = 0;
	int ret, i;
611

612
	/* Allocate the private data and the DAI link array */
613
	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
614
	if (!priv)
615 616
		return -ENOMEM;

617 618 619 620 621 622 623 624
	asoc_simple_card_get_dais_count(dev, &lnum, &dnum, &cnum);
	if (!lnum || !dnum)
		return -EINVAL;

	dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL);
	dai_link  = devm_kcalloc(dev, lnum, sizeof(*dai_link),  GFP_KERNEL);
	dais      = devm_kcalloc(dev, dnum, sizeof(*dais),      GFP_KERNEL);
	cconf     = devm_kcalloc(dev, cnum, sizeof(*cconf),     GFP_KERNEL);
625
	if (!dai_props || !dai_link || !dais)
626 627
		return -ENOMEM;

628 629 630 631 632 633
	/*
	 * Use snd_soc_dai_link_component instead of legacy style
	 * It is codec only. but cpu/platform will be supported in the future.
	 * see
	 *	soc-core.c :: snd_soc_init_multicodec()
	 */
634
	for (i = 0; i < lnum; i++) {
635 636
		dai_link[i].codecs	= &dai_props[i].codecs;
		dai_link[i].num_codecs	= 1;
637
		dai_link[i].platform	= &dai_props[i].platform;
638 639
	}

640 641
	priv->dai_props			= dai_props;
	priv->dai_link			= dai_link;
642
	priv->dais			= dais;
643
	priv->codec_conf		= cconf;
644

645
	/* Init snd_soc_card */
646 647 648 649
	card = simple_priv_to_card(priv);
	card->owner		= THIS_MODULE;
	card->dev		= dev;
	card->dai_link		= priv->dai_link;
650 651 652
	card->num_links		= lnum;
	card->codec_conf	= cconf;
	card->num_configs	= cnum;
653
	card->probe		= asoc_simple_soc_card_probe;
654

655
	if (np && of_device_is_available(np)) {
656

657
		ret = asoc_simple_card_parse_of(priv);
658 659 660
		if (ret < 0) {
			if (ret != -EPROBE_DEFER)
				dev_err(dev, "parse error %d\n", ret);
661
			goto err;
662
		}
663

664
	} else {
665
		struct asoc_simple_card_info *cinfo;
666
		struct snd_soc_dai_link_component *codecs;
667
		struct snd_soc_dai_link_component *platform;
668
		int dai_idx = 0;
669 670 671

		cinfo = dev->platform_data;
		if (!cinfo) {
672 673 674
			dev_err(dev, "no info for asoc-simple-card\n");
			return -EINVAL;
		}
675

676 677 678 679
		if (!cinfo->name ||
		    !cinfo->codec_dai.name ||
		    !cinfo->codec ||
		    !cinfo->platform ||
680 681 682 683
		    !cinfo->cpu_dai.name) {
			dev_err(dev, "insufficient asoc_simple_card_info settings\n");
			return -EINVAL;
		}
684

685 686 687
		dai_props->cpu_dai	= &priv->dais[dai_idx++];
		dai_props->codec_dai	= &priv->dais[dai_idx++];

688 689 690 691
		codecs			= dai_link->codecs;
		codecs->name		= cinfo->codec;
		codecs->dai_name	= cinfo->codec_dai.name;

692 693 694
		platform		= dai_link->platform;
		platform->name		= cinfo->platform;

695
		card->name		= (cinfo->card) ? cinfo->card : cinfo->name;
696 697
		dai_link->name		= cinfo->name;
		dai_link->stream_name	= cinfo->name;
698
		dai_link->cpu_dai_name	= cinfo->cpu_dai.name;
699
		dai_link->dai_fmt	= cinfo->daifmt;
700
		dai_link->init		= asoc_simple_card_dai_init;
701 702 703 704
		memcpy(priv->dai_props->cpu_dai, &cinfo->cpu_dai,
					sizeof(*priv->dai_props->cpu_dai));
		memcpy(priv->dai_props->codec_dai, &cinfo->codec_dai,
					sizeof(*priv->dai_props->codec_dai));
705 706
	}

707
	snd_soc_card_set_drvdata(card, priv);
708

709
	ret = devm_snd_soc_register_card(dev, card);
710 711 712 713
	if (ret < 0)
		goto err;

	return 0;
714
err:
715
	asoc_simple_card_clean_reference(card);
716

717
	return ret;
718 719
}

720 721
static int asoc_simple_card_remove(struct platform_device *pdev)
{
722 723
	struct snd_soc_card *card = platform_get_drvdata(pdev);

724
	return asoc_simple_card_clean_reference(card);
725 726
}

727 728
static const struct of_device_id asoc_simple_of_match[] = {
	{ .compatible = "simple-audio-card", },
729
	{ .compatible = "simple-scu-audio-card", },
730 731 732 733
	{},
};
MODULE_DEVICE_TABLE(of, asoc_simple_of_match);

734 735
static struct platform_driver asoc_simple_card = {
	.driver = {
736
		.name = "asoc-simple-card",
737
		.pm = &snd_soc_pm_ops,
738
		.of_match_table = asoc_simple_of_match,
739
	},
740
	.probe = asoc_simple_card_probe,
741
	.remove = asoc_simple_card_remove,
742 743 744 745
};

module_platform_driver(asoc_simple_card);

746
MODULE_ALIAS("platform:asoc-simple-card");
K
Kuninori Morimoto 已提交
747
MODULE_LICENSE("GPL v2");
748 749
MODULE_DESCRIPTION("ASoC Simple Sound Card");
MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");