.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* Atmel ALSA SoC Audio Class D Amplifier (CLASSD) driver |
---|
2 | 3 | * |
---|
3 | 4 | * Copyright (C) 2015 Atmel |
---|
4 | 5 | * |
---|
5 | 6 | * Author: Songjun Wu <songjun.wu@atmel.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 or later |
---|
9 | | - * as published by the Free Software Foundation. |
---|
10 | 7 | */ |
---|
11 | 8 | |
---|
12 | 9 | #include <linux/of.h> |
---|
.. | .. |
---|
121 | 118 | static int atmel_classd_cpu_dai_startup(struct snd_pcm_substream *substream, |
---|
122 | 119 | struct snd_soc_dai *cpu_dai) |
---|
123 | 120 | { |
---|
124 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
| 121 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
125 | 122 | struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card); |
---|
| 123 | + int err; |
---|
126 | 124 | |
---|
127 | 125 | regmap_write(dd->regmap, CLASSD_THR, 0x0); |
---|
128 | 126 | |
---|
129 | | - return clk_prepare_enable(dd->pclk); |
---|
| 127 | + err = clk_prepare_enable(dd->pclk); |
---|
| 128 | + if (err) |
---|
| 129 | + return err; |
---|
| 130 | + err = clk_prepare_enable(dd->gclk); |
---|
| 131 | + if (err) { |
---|
| 132 | + clk_disable_unprepare(dd->pclk); |
---|
| 133 | + return err; |
---|
| 134 | + } |
---|
| 135 | + return 0; |
---|
130 | 136 | } |
---|
131 | | - |
---|
132 | | -static void atmel_classd_cpu_dai_shutdown(struct snd_pcm_substream *substream, |
---|
133 | | - struct snd_soc_dai *cpu_dai) |
---|
134 | | -{ |
---|
135 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
136 | | - struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card); |
---|
137 | | - |
---|
138 | | - clk_disable_unprepare(dd->pclk); |
---|
139 | | -} |
---|
140 | | - |
---|
141 | | -static const struct snd_soc_dai_ops atmel_classd_cpu_dai_ops = { |
---|
142 | | - .startup = atmel_classd_cpu_dai_startup, |
---|
143 | | - .shutdown = atmel_classd_cpu_dai_shutdown, |
---|
144 | | -}; |
---|
145 | | - |
---|
146 | | -static struct snd_soc_dai_driver atmel_classd_cpu_dai = { |
---|
147 | | - .playback = { |
---|
148 | | - .channels_min = 1, |
---|
149 | | - .channels_max = 2, |
---|
150 | | - .rates = ATMEL_CLASSD_RATES, |
---|
151 | | - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
---|
152 | | - .ops = &atmel_classd_cpu_dai_ops, |
---|
153 | | -}; |
---|
154 | | - |
---|
155 | | -static const struct snd_soc_component_driver atmel_classd_cpu_dai_component = { |
---|
156 | | - .name = "atmel-classd", |
---|
157 | | -}; |
---|
158 | 137 | |
---|
159 | 138 | /* platform */ |
---|
160 | 139 | static int |
---|
.. | .. |
---|
162 | 141 | struct snd_pcm_hw_params *params, |
---|
163 | 142 | struct dma_slave_config *slave_config) |
---|
164 | 143 | { |
---|
165 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
| 144 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
166 | 145 | struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card); |
---|
167 | 146 | |
---|
168 | 147 | if (params_physical_width(params) != 16) { |
---|
.. | .. |
---|
309 | 288 | return regcache_sync(dd->regmap); |
---|
310 | 289 | } |
---|
311 | 290 | |
---|
312 | | -static struct snd_soc_component_driver soc_component_dev_classd = { |
---|
313 | | - .probe = atmel_classd_component_probe, |
---|
314 | | - .resume = atmel_classd_component_resume, |
---|
315 | | - .controls = atmel_classd_snd_controls, |
---|
316 | | - .num_controls = ARRAY_SIZE(atmel_classd_snd_controls), |
---|
317 | | - .idle_bias_on = 1, |
---|
318 | | - .use_pmdown_time = 1, |
---|
319 | | - .endianness = 1, |
---|
320 | | - .non_legacy_dai_naming = 1, |
---|
321 | | -}; |
---|
322 | | - |
---|
323 | | -/* codec dai component */ |
---|
324 | | -static int atmel_classd_codec_dai_startup(struct snd_pcm_substream *substream, |
---|
325 | | - struct snd_soc_dai *codec_dai) |
---|
| 291 | +static int atmel_classd_cpu_dai_mute_stream(struct snd_soc_dai *cpu_dai, |
---|
| 292 | + int mute, int direction) |
---|
326 | 293 | { |
---|
327 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
328 | | - struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card); |
---|
329 | | - |
---|
330 | | - return clk_prepare_enable(dd->gclk); |
---|
331 | | -} |
---|
332 | | - |
---|
333 | | -static int atmel_classd_codec_dai_digital_mute(struct snd_soc_dai *codec_dai, |
---|
334 | | - int mute) |
---|
335 | | -{ |
---|
336 | | - struct snd_soc_component *component = codec_dai->component; |
---|
| 294 | + struct snd_soc_component *component = cpu_dai->component; |
---|
337 | 295 | u32 mask, val; |
---|
338 | 296 | |
---|
339 | 297 | mask = CLASSD_MR_LMUTE_MASK | CLASSD_MR_RMUTE_MASK; |
---|
.. | .. |
---|
376 | 334 | }; |
---|
377 | 335 | |
---|
378 | 336 | static int |
---|
379 | | -atmel_classd_codec_dai_hw_params(struct snd_pcm_substream *substream, |
---|
380 | | - struct snd_pcm_hw_params *params, |
---|
381 | | - struct snd_soc_dai *codec_dai) |
---|
| 337 | +atmel_classd_cpu_dai_hw_params(struct snd_pcm_substream *substream, |
---|
| 338 | + struct snd_pcm_hw_params *params, |
---|
| 339 | + struct snd_soc_dai *cpu_dai) |
---|
382 | 340 | { |
---|
383 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
| 341 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
384 | 342 | struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card); |
---|
385 | | - struct snd_soc_component *component = codec_dai->component; |
---|
| 343 | + struct snd_soc_component *component = cpu_dai->component; |
---|
386 | 344 | int fs; |
---|
387 | 345 | int i, best, best_val, cur_val, ret; |
---|
388 | 346 | u32 mask, val; |
---|
.. | .. |
---|
420 | 378 | } |
---|
421 | 379 | |
---|
422 | 380 | static void |
---|
423 | | -atmel_classd_codec_dai_shutdown(struct snd_pcm_substream *substream, |
---|
424 | | - struct snd_soc_dai *codec_dai) |
---|
| 381 | +atmel_classd_cpu_dai_shutdown(struct snd_pcm_substream *substream, |
---|
| 382 | + struct snd_soc_dai *cpu_dai) |
---|
425 | 383 | { |
---|
426 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
| 384 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
427 | 385 | struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card); |
---|
428 | 386 | |
---|
429 | 387 | clk_disable_unprepare(dd->gclk); |
---|
430 | 388 | } |
---|
431 | 389 | |
---|
432 | | -static int atmel_classd_codec_dai_prepare(struct snd_pcm_substream *substream, |
---|
433 | | - struct snd_soc_dai *codec_dai) |
---|
| 390 | +static int atmel_classd_cpu_dai_prepare(struct snd_pcm_substream *substream, |
---|
| 391 | + struct snd_soc_dai *cpu_dai) |
---|
434 | 392 | { |
---|
435 | | - struct snd_soc_component *component = codec_dai->component; |
---|
| 393 | + struct snd_soc_component *component = cpu_dai->component; |
---|
436 | 394 | |
---|
437 | 395 | snd_soc_component_update_bits(component, CLASSD_MR, |
---|
438 | 396 | CLASSD_MR_LEN_MASK | CLASSD_MR_REN_MASK, |
---|
.. | .. |
---|
442 | 400 | return 0; |
---|
443 | 401 | } |
---|
444 | 402 | |
---|
445 | | -static int atmel_classd_codec_dai_trigger(struct snd_pcm_substream *substream, |
---|
446 | | - int cmd, struct snd_soc_dai *codec_dai) |
---|
| 403 | +static int atmel_classd_cpu_dai_trigger(struct snd_pcm_substream *substream, |
---|
| 404 | + int cmd, struct snd_soc_dai *cpu_dai) |
---|
447 | 405 | { |
---|
448 | | - struct snd_soc_component *component = codec_dai->component; |
---|
| 406 | + struct snd_soc_component *component = cpu_dai->component; |
---|
449 | 407 | u32 mask, val; |
---|
450 | 408 | |
---|
451 | 409 | mask = CLASSD_MR_LEN_MASK | CLASSD_MR_REN_MASK; |
---|
.. | .. |
---|
471 | 429 | return 0; |
---|
472 | 430 | } |
---|
473 | 431 | |
---|
474 | | -static const struct snd_soc_dai_ops atmel_classd_codec_dai_ops = { |
---|
475 | | - .digital_mute = atmel_classd_codec_dai_digital_mute, |
---|
476 | | - .startup = atmel_classd_codec_dai_startup, |
---|
477 | | - .shutdown = atmel_classd_codec_dai_shutdown, |
---|
478 | | - .hw_params = atmel_classd_codec_dai_hw_params, |
---|
479 | | - .prepare = atmel_classd_codec_dai_prepare, |
---|
480 | | - .trigger = atmel_classd_codec_dai_trigger, |
---|
| 432 | +static const struct snd_soc_dai_ops atmel_classd_cpu_dai_ops = { |
---|
| 433 | + .startup = atmel_classd_cpu_dai_startup, |
---|
| 434 | + .shutdown = atmel_classd_cpu_dai_shutdown, |
---|
| 435 | + .mute_stream = atmel_classd_cpu_dai_mute_stream, |
---|
| 436 | + .hw_params = atmel_classd_cpu_dai_hw_params, |
---|
| 437 | + .prepare = atmel_classd_cpu_dai_prepare, |
---|
| 438 | + .trigger = atmel_classd_cpu_dai_trigger, |
---|
| 439 | + .no_capture_mute = 1, |
---|
481 | 440 | }; |
---|
482 | 441 | |
---|
483 | | -#define ATMEL_CLASSD_CODEC_DAI_NAME "atmel-classd-hifi" |
---|
484 | | - |
---|
485 | | -static struct snd_soc_dai_driver atmel_classd_codec_dai = { |
---|
486 | | - .name = ATMEL_CLASSD_CODEC_DAI_NAME, |
---|
| 442 | +static struct snd_soc_dai_driver atmel_classd_cpu_dai = { |
---|
487 | 443 | .playback = { |
---|
488 | 444 | .stream_name = "Playback", |
---|
489 | 445 | .channels_min = 1, |
---|
.. | .. |
---|
491 | 447 | .rates = ATMEL_CLASSD_RATES, |
---|
492 | 448 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
---|
493 | 449 | }, |
---|
494 | | - .ops = &atmel_classd_codec_dai_ops, |
---|
| 450 | + .ops = &atmel_classd_cpu_dai_ops, |
---|
| 451 | +}; |
---|
| 452 | + |
---|
| 453 | +static const struct snd_soc_component_driver atmel_classd_cpu_dai_component = { |
---|
| 454 | + .name = "atmel-classd", |
---|
| 455 | + .probe = atmel_classd_component_probe, |
---|
| 456 | + .resume = atmel_classd_component_resume, |
---|
| 457 | + .controls = atmel_classd_snd_controls, |
---|
| 458 | + .num_controls = ARRAY_SIZE(atmel_classd_snd_controls), |
---|
| 459 | + .idle_bias_on = 1, |
---|
| 460 | + .use_pmdown_time = 1, |
---|
495 | 461 | }; |
---|
496 | 462 | |
---|
497 | 463 | /* ASoC sound card */ |
---|
.. | .. |
---|
500 | 466 | { |
---|
501 | 467 | struct snd_soc_dai_link *dai_link; |
---|
502 | 468 | struct atmel_classd *dd = snd_soc_card_get_drvdata(card); |
---|
| 469 | + struct snd_soc_dai_link_component *comp; |
---|
503 | 470 | |
---|
504 | 471 | dai_link = devm_kzalloc(dev, sizeof(*dai_link), GFP_KERNEL); |
---|
505 | 472 | if (!dai_link) |
---|
506 | 473 | return -ENOMEM; |
---|
507 | 474 | |
---|
| 475 | + comp = devm_kzalloc(dev, 3 * sizeof(*comp), GFP_KERNEL); |
---|
| 476 | + if (!comp) |
---|
| 477 | + return -ENOMEM; |
---|
| 478 | + |
---|
| 479 | + dai_link->cpus = &comp[0]; |
---|
| 480 | + dai_link->codecs = &comp[1]; |
---|
| 481 | + dai_link->platforms = &comp[2]; |
---|
| 482 | + |
---|
| 483 | + dai_link->num_cpus = 1; |
---|
| 484 | + dai_link->num_codecs = 1; |
---|
| 485 | + dai_link->num_platforms = 1; |
---|
| 486 | + |
---|
508 | 487 | dai_link->name = "CLASSD"; |
---|
509 | 488 | dai_link->stream_name = "CLASSD PCM"; |
---|
510 | | - dai_link->codec_dai_name = ATMEL_CLASSD_CODEC_DAI_NAME; |
---|
511 | | - dai_link->cpu_dai_name = dev_name(dev); |
---|
512 | | - dai_link->codec_name = dev_name(dev); |
---|
513 | | - dai_link->platform_name = dev_name(dev); |
---|
| 489 | + dai_link->codecs->dai_name = "snd-soc-dummy-dai"; |
---|
| 490 | + dai_link->cpus->dai_name = dev_name(dev); |
---|
| 491 | + dai_link->codecs->name = "snd-soc-dummy"; |
---|
| 492 | + dai_link->platforms->name = dev_name(dev); |
---|
514 | 493 | |
---|
515 | 494 | card->dai_link = dai_link; |
---|
516 | 495 | card->num_links = 1; |
---|
.. | .. |
---|
561 | 540 | dd->pdata = pdata; |
---|
562 | 541 | |
---|
563 | 542 | dd->irq = platform_get_irq(pdev, 0); |
---|
564 | | - if (dd->irq < 0) { |
---|
565 | | - ret = dd->irq; |
---|
566 | | - dev_err(dev, "failed to could not get irq: %d\n", ret); |
---|
567 | | - return ret; |
---|
568 | | - } |
---|
| 543 | + if (dd->irq < 0) |
---|
| 544 | + return dd->irq; |
---|
569 | 545 | |
---|
570 | 546 | dd->pclk = devm_clk_get(dev, "pclk"); |
---|
571 | 547 | if (IS_ERR(dd->pclk)) { |
---|
.. | .. |
---|
610 | 586 | 0); |
---|
611 | 587 | if (ret) { |
---|
612 | 588 | dev_err(dev, "could not register platform: %d\n", ret); |
---|
613 | | - return ret; |
---|
614 | | - } |
---|
615 | | - |
---|
616 | | - ret = devm_snd_soc_register_component(dev, &soc_component_dev_classd, |
---|
617 | | - &atmel_classd_codec_dai, 1); |
---|
618 | | - if (ret) { |
---|
619 | | - dev_err(dev, "could not register component: %d\n", ret); |
---|
620 | 589 | return ret; |
---|
621 | 590 | } |
---|
622 | 591 | |
---|