simple-card.c 13.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
/*
 * ASoC simple sound card support
 *
 * Copyright (C) 2012 Renesas Solutions Corp.
 * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
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 22
#include <sound/soc-dai.h>
#include <sound/soc.h>
23

24 25 26 27 28 29
struct asoc_simple_jack {
	struct snd_soc_jack jack;
	struct snd_soc_jack_pin pin;
	struct snd_soc_jack_gpio gpio;
};

30 31
struct simple_card_data {
	struct snd_soc_card snd_card;
32 33 34
	struct simple_dai_props {
		struct asoc_simple_dai cpu_dai;
		struct asoc_simple_dai codec_dai;
35
		unsigned int mclk_fs;
36
	} *dai_props;
37
	unsigned int mclk_fs;
38 39
	struct asoc_simple_jack hp_jack;
	struct asoc_simple_jack mic_jack;
40
	struct snd_soc_dai_link *dai_link;
41 42
};

43
#define simple_priv_to_dev(priv) ((priv)->snd_card.dev)
44 45
#define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + (i))
#define simple_priv_to_props(priv, i) ((priv)->dai_props + (i))
46

47 48
#define DAI	"sound-dai"
#define CELL	"#sound-dai-cells"
49 50
#define PREFIX	"simple-audio-card,"

51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
#define asoc_simple_card_init_hp(card, sjack, prefix)\
	asoc_simple_card_init_jack(card, sjack, 1, prefix)
#define asoc_simple_card_init_mic(card, sjack, prefix)\
	asoc_simple_card_init_jack(card, sjack, 0, prefix)
static int asoc_simple_card_init_jack(struct snd_soc_card *card,
				      struct asoc_simple_jack *sjack,
				      int is_hp, char *prefix)
{
	struct device *dev = card->dev;
	enum of_gpio_flags flags;
	char prop[128];
	char *pin_name;
	char *gpio_name;
	int mask;
	int det;

	sjack->gpio.gpio = -ENOENT;

	if (is_hp) {
		snprintf(prop, sizeof(prop), "%shp-det-gpio", prefix);
		pin_name	= "Headphones";
		gpio_name	= "Headphone detection";
		mask		= SND_JACK_HEADPHONE;
	} else {
		snprintf(prop, sizeof(prop), "%smic-det-gpio", prefix);
		pin_name	= "Mic Jack";
		gpio_name	= "Mic detection";
		mask		= SND_JACK_MICROPHONE;
	}

	det = of_get_named_gpio_flags(dev->of_node, prop, 0, &flags);
	if (det == -EPROBE_DEFER)
		return -EPROBE_DEFER;

	if (gpio_is_valid(det)) {
		sjack->pin.pin		= pin_name;
		sjack->pin.mask		= mask;

		sjack->gpio.name	= gpio_name;
		sjack->gpio.report	= mask;
		sjack->gpio.gpio	= det;
		sjack->gpio.invert	= !!(flags & OF_GPIO_ACTIVE_LOW);
		sjack->gpio.debounce_time = 150;

		snd_soc_card_jack_new(card, pin_name, mask,
				      &sjack->jack,
				      &sjack->pin, 1);

		snd_soc_jack_add_gpios(&sjack->jack, 1,
				       &sjack->gpio);
	}

	return 0;
}

static void asoc_simple_card_remove_jack(struct asoc_simple_jack *sjack)
{
	if (gpio_is_valid(sjack->gpio.gpio))
		snd_soc_jack_free_gpios(&sjack->jack, 1, &sjack->gpio);
}

112 113 114 115 116
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 =
117
		simple_priv_to_props(priv, rtd->num);
118 119 120 121 122
	int ret;

	ret = clk_prepare_enable(dai_props->cpu_dai.clk);
	if (ret)
		return ret;
123

124 125 126 127 128 129 130 131 132 133 134 135
	ret = clk_prepare_enable(dai_props->codec_dai.clk);
	if (ret)
		clk_disable_unprepare(dai_props->cpu_dai.clk);

	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 =
136
		simple_priv_to_props(priv, rtd->num);
137 138 139 140 141 142

	clk_disable_unprepare(dai_props->cpu_dai.clk);

	clk_disable_unprepare(dai_props->codec_dai.clk);
}

143 144 145 146 147
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;
148
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
149
	struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
150 151
	struct simple_dai_props *dai_props =
		simple_priv_to_props(priv, rtd->num);
152
	unsigned int mclk, mclk_fs = 0;
153 154
	int ret = 0;

155 156 157 158 159 160 161
	if (priv->mclk_fs)
		mclk_fs = priv->mclk_fs;
	else if (dai_props->mclk_fs)
		mclk_fs = dai_props->mclk_fs;

	if (mclk_fs) {
		mclk = params_rate(params) * mclk_fs;
162 163
		ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
					     SND_SOC_CLOCK_IN);
164 165 166 167 168 169 170
		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;
171
	}
172
	return 0;
173
err:
174 175 176
	return ret;
}

177
static const struct snd_soc_ops asoc_simple_card_ops = {
178 179
	.startup = asoc_simple_card_startup,
	.shutdown = asoc_simple_card_shutdown,
180 181 182
	.hw_params = asoc_simple_card_hw_params,
};

183 184
static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
{
185
	struct simple_card_data *priv =	snd_soc_card_get_drvdata(rtd->card);
186 187
	struct snd_soc_dai *codec = rtd->codec_dai;
	struct snd_soc_dai *cpu = rtd->cpu_dai;
188 189
	struct simple_dai_props *dai_props =
		simple_priv_to_props(priv, rtd->num);
190
	int ret;
191

192
	ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai);
193 194
	if (ret < 0)
		return ret;
195

196
	ret = asoc_simple_card_init_dai(cpu, &dai_props->cpu_dai);
197 198
	if (ret < 0)
		return ret;
199

200 201 202 203 204 205 206
	ret = asoc_simple_card_init_hp(rtd->card, &priv->hp_jack, PREFIX);
	if (ret < 0)
		return ret;

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

208 209 210
	return 0;
}

211
static int asoc_simple_card_dai_link_of(struct device_node *node,
212
					struct simple_card_data *priv,
213
					int idx,
214
					bool is_top_level_node)
215
{
216
	struct device *dev = simple_priv_to_dev(priv);
217 218
	struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
	struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
219 220
	struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai;
	struct asoc_simple_dai *codec_dai = &dai_props->codec_dai;
221
	struct device_node *cpu = NULL;
222
	struct device_node *plat = NULL;
223
	struct device_node *codec = NULL;
224 225
	char prop[128];
	char *prefix = "";
226
	int ret, single_cpu;
227

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

	snprintf(prop, sizeof(prop), "%scpu", prefix);
233 234
	cpu = of_get_child_by_name(node, prop);

235 236 237
	snprintf(prop, sizeof(prop), "%splat", prefix);
	plat = of_get_child_by_name(node, prop);

238 239 240 241
	snprintf(prop, sizeof(prop), "%scodec", prefix);
	codec = of_get_child_by_name(node, prop);

	if (!cpu || !codec) {
242
		ret = -EINVAL;
243
		dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
244
		goto dai_link_of_err;
245
	}
246

247 248
	ret = asoc_simple_card_parse_daifmt(dev, node, codec,
					    prefix, &dai_link->dai_fmt);
249 250 251
	if (ret < 0)
		goto dai_link_of_err;

252
	of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs);
253

254 255 256 257 258 259 260 261 262 263 264 265 266
	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;

267 268 269 270
	ret = snd_soc_of_parse_tdm_slot(cpu,	&cpu_dai->tx_slot_mask,
						&cpu_dai->rx_slot_mask,
						&cpu_dai->slots,
						&cpu_dai->slot_width);
271 272 273
	if (ret < 0)
		goto dai_link_of_err;

274 275 276 277
	ret = snd_soc_of_parse_tdm_slot(codec,	&codec_dai->tx_slot_mask,
						&codec_dai->rx_slot_mask,
						&codec_dai->slots,
						&codec_dai->slot_width);
278 279 280
	if (ret < 0)
		goto dai_link_of_err;

281 282 283 284 285 286 287 288
	ret = asoc_simple_card_parse_clk_cpu(cpu, dai_link, cpu_dai);
	if (ret < 0)
		goto dai_link_of_err;

	ret = asoc_simple_card_parse_clk_codec(codec, dai_link, codec_dai);
	if (ret < 0)
		goto dai_link_of_err;

289 290
	ret = asoc_simple_card_canonicalize_dailink(dai_link);
	if (ret < 0)
291
		goto dai_link_of_err;
292

293 294 295 296 297
	ret = asoc_simple_card_set_dailink_name(dev, dai_link,
						"%s-%s",
						dai_link->cpu_dai_name,
						dai_link->codec_dai_name);
	if (ret < 0)
298 299
		goto dai_link_of_err;

300
	dai_link->ops = &asoc_simple_card_ops;
301
	dai_link->init = asoc_simple_card_dai_init;
302 303

	dev_dbg(dev, "\tname : %s\n", dai_link->stream_name);
304 305
	dev_dbg(dev, "\tformat : %04x\n", dai_link->dai_fmt);
	dev_dbg(dev, "\tcpu : %s / %d\n",
306 307
		dai_link->cpu_dai_name,
		dai_props->cpu_dai.sysclk);
308
	dev_dbg(dev, "\tcodec : %s / %d\n",
309 310 311
		dai_link->codec_dai_name,
		dai_props->codec_dai.sysclk);

312
	asoc_simple_card_canonicalize_cpu(dai_link, single_cpu);
313

314
dai_link_of_err:
315 316 317
	of_node_put(cpu);
	of_node_put(codec);

318 319 320
	return ret;
}

321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
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;
	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;

	priv->snd_card.aux_dev = devm_kzalloc(dev,
			n * sizeof(*priv->snd_card.aux_dev), GFP_KERNEL);
	if (!priv->snd_card.aux_dev)
		return -ENOMEM;

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

	priv->snd_card.num_aux_devs = n;
	return 0;
}

351
static int asoc_simple_card_parse_of(struct device_node *node,
352
				     struct simple_card_data *priv)
353
{
354
	struct device *dev = simple_priv_to_dev(priv);
355
	struct device_node *dai_link;
356
	int ret;
357

358 359 360
	if (!node)
		return -EINVAL;

361 362
	dai_link = of_get_child_by_name(node, PREFIX "dai-link");

363
	/* The off-codec widgets */
364
	if (of_property_read_bool(node, PREFIX "widgets")) {
365
		ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card,
366
					PREFIX "widgets");
367
		if (ret)
368
			goto card_parse_end;
369 370
	}

371
	/* DAPM routes */
372
	if (of_property_read_bool(node, PREFIX "routing")) {
373
		ret = snd_soc_of_parse_audio_routing(&priv->snd_card,
374
					PREFIX "routing");
375
		if (ret)
376
			goto card_parse_end;
377
	}
378

379
	/* Factor to mclk, used in hw_params() */
380
	of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs);
381

382
	/* Single/Muti DAI link(s) & New style of DT node */
383
	if (dai_link) {
384
		struct device_node *np = NULL;
385 386 387
		int i = 0;

		for_each_child_of_node(node, np) {
388
			dev_dbg(dev, "\tlink %d:\n", i);
389
			ret = asoc_simple_card_dai_link_of(np, priv,
390
							   i, false);
391 392
			if (ret < 0) {
				of_node_put(np);
393
				goto card_parse_end;
394
			}
395
			i++;
396
		}
397
	} else {
398
		/* For single DAI link & old style of DT node */
399
		ret = asoc_simple_card_dai_link_of(node, priv, 0, true);
400
		if (ret < 0)
401
			goto card_parse_end;
402
	}
403

404
	ret = asoc_simple_card_parse_card_name(&priv->snd_card, PREFIX);
405 406 407 408
	if (ret < 0)
		goto card_parse_end;

	ret = asoc_simple_card_parse_aux_devs(node, priv);
409

410 411 412 413
card_parse_end:
	of_node_put(dai_link);

	return ret;
414 415
}

416 417
static int asoc_simple_card_probe(struct platform_device *pdev)
{
418
	struct simple_card_data *priv;
419
	struct snd_soc_dai_link *dai_link;
420
	struct simple_dai_props *dai_props;
421
	struct device_node *np = pdev->dev.of_node;
422
	struct device *dev = &pdev->dev;
423
	int num, ret;
424

425
	/* Get the number of DAI links */
426
	if (np && of_get_child_by_name(np, PREFIX "dai-link"))
427
		num = of_get_child_count(np);
428
	else
429
		num = 1;
430

431
	/* Allocate the private data and the DAI link array */
432
	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
433
	if (!priv)
434 435
		return -ENOMEM;

436 437 438 439 440 441 442 443
	dai_props = devm_kzalloc(dev, sizeof(*dai_props) * num, GFP_KERNEL);
	dai_link  = devm_kzalloc(dev, sizeof(*dai_link)  * num, GFP_KERNEL);
	if (!dai_props || !dai_link)
		return -ENOMEM;

	priv->dai_props			= dai_props;
	priv->dai_link			= dai_link;

444
	/* Init snd_soc_card */
445 446 447
	priv->snd_card.owner		= THIS_MODULE;
	priv->snd_card.dev		= dev;
	priv->snd_card.dai_link		= priv->dai_link;
448
	priv->snd_card.num_links	= num;
449

450
	if (np && of_device_is_available(np)) {
451

452
		ret = asoc_simple_card_parse_of(np, priv);
453 454 455
		if (ret < 0) {
			if (ret != -EPROBE_DEFER)
				dev_err(dev, "parse error %d\n", ret);
456
			goto err;
457
		}
458

459
	} else {
460 461 462 463
		struct asoc_simple_card_info *cinfo;

		cinfo = dev->platform_data;
		if (!cinfo) {
464 465 466
			dev_err(dev, "no info for asoc-simple-card\n");
			return -EINVAL;
		}
467

468 469 470 471
		if (!cinfo->name ||
		    !cinfo->codec_dai.name ||
		    !cinfo->codec ||
		    !cinfo->platform ||
472 473 474 475
		    !cinfo->cpu_dai.name) {
			dev_err(dev, "insufficient asoc_simple_card_info settings\n");
			return -EINVAL;
		}
476

477
		priv->snd_card.name	= (cinfo->card) ? cinfo->card : cinfo->name;
478 479 480 481
		dai_link->name		= cinfo->name;
		dai_link->stream_name	= cinfo->name;
		dai_link->platform_name	= cinfo->platform;
		dai_link->codec_name	= cinfo->codec;
482 483
		dai_link->cpu_dai_name	= cinfo->cpu_dai.name;
		dai_link->codec_dai_name = cinfo->codec_dai.name;
484
		dai_link->dai_fmt	= cinfo->daifmt;
485
		dai_link->init		= asoc_simple_card_dai_init;
486 487 488 489
		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));
490 491
	}

492
	snd_soc_card_set_drvdata(&priv->snd_card, priv);
493

494
	ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
495 496
	if (ret >= 0)
		return ret;
497
err:
498
	asoc_simple_card_clean_reference(&priv->snd_card);
499

500
	return ret;
501 502
}

503 504
static int asoc_simple_card_remove(struct platform_device *pdev)
{
505 506 507
	struct snd_soc_card *card = platform_get_drvdata(pdev);
	struct simple_card_data *priv = snd_soc_card_get_drvdata(card);

508 509
	asoc_simple_card_remove_jack(&priv->hp_jack);
	asoc_simple_card_remove_jack(&priv->mic_jack);
510

511
	return asoc_simple_card_clean_reference(card);
512 513
}

514 515 516 517 518 519
static const struct of_device_id asoc_simple_of_match[] = {
	{ .compatible = "simple-audio-card", },
	{},
};
MODULE_DEVICE_TABLE(of, asoc_simple_of_match);

520 521
static struct platform_driver asoc_simple_card = {
	.driver = {
522
		.name = "asoc-simple-card",
523
		.pm = &snd_soc_pm_ops,
524
		.of_match_table = asoc_simple_of_match,
525
	},
526
	.probe = asoc_simple_card_probe,
527
	.remove = asoc_simple_card_remove,
528 529 530 531
};

module_platform_driver(asoc_simple_card);

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