18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2014 Marvell 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 108c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 118c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <sound/soc.h> 148c2ecf20Sopenharmony_ci#include <linux/of.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_data/asoc-kirkwood.h> 168c2ecf20Sopenharmony_ci#include "../codecs/cs42l51.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic int a370db_hw_params(struct snd_pcm_substream *substream, 198c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 228c2ecf20Sopenharmony_ci struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 238c2ecf20Sopenharmony_ci unsigned int freq; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci switch (params_rate(params)) { 268c2ecf20Sopenharmony_ci default: 278c2ecf20Sopenharmony_ci case 44100: 288c2ecf20Sopenharmony_ci freq = 11289600; 298c2ecf20Sopenharmony_ci break; 308c2ecf20Sopenharmony_ci case 48000: 318c2ecf20Sopenharmony_ci freq = 12288000; 328c2ecf20Sopenharmony_ci break; 338c2ecf20Sopenharmony_ci case 96000: 348c2ecf20Sopenharmony_ci freq = 24576000; 358c2ecf20Sopenharmony_ci break; 368c2ecf20Sopenharmony_ci } 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci return snd_soc_dai_set_sysclk(codec_dai, 0, freq, SND_SOC_CLOCK_IN); 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic const struct snd_soc_ops a370db_ops = { 428c2ecf20Sopenharmony_ci .hw_params = a370db_hw_params, 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget a370db_dapm_widgets[] = { 468c2ecf20Sopenharmony_ci SND_SOC_DAPM_HP("Out Jack", NULL), 478c2ecf20Sopenharmony_ci SND_SOC_DAPM_LINE("In Jack", NULL), 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route a370db_route[] = { 518c2ecf20Sopenharmony_ci { "Out Jack", NULL, "HPL" }, 528c2ecf20Sopenharmony_ci { "Out Jack", NULL, "HPR" }, 538c2ecf20Sopenharmony_ci { "AIN1L", NULL, "In Jack" }, 548c2ecf20Sopenharmony_ci { "AIN1L", NULL, "In Jack" }, 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(analog, 588c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CPU("i2s")), 598c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "cs42l51-hifi")), 608c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_EMPTY())); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(spdif_out, 638c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CPU("spdif")), 648c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "dit-hifi")), 658c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_EMPTY())); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(spdif_in, 688c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CPU("spdif")), 698c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "dir-hifi")), 708c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_EMPTY())); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic struct snd_soc_dai_link a370db_dai[] = { 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci .name = "CS42L51", 758c2ecf20Sopenharmony_ci .stream_name = "analog", 768c2ecf20Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS, 778c2ecf20Sopenharmony_ci .ops = &a370db_ops, 788c2ecf20Sopenharmony_ci SND_SOC_DAILINK_REG(analog), 798c2ecf20Sopenharmony_ci}, 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci .name = "S/PDIF out", 828c2ecf20Sopenharmony_ci .stream_name = "spdif-out", 838c2ecf20Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS, 848c2ecf20Sopenharmony_ci SND_SOC_DAILINK_REG(spdif_out), 858c2ecf20Sopenharmony_ci}, 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci .name = "S/PDIF in", 888c2ecf20Sopenharmony_ci .stream_name = "spdif-in", 898c2ecf20Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS, 908c2ecf20Sopenharmony_ci SND_SOC_DAILINK_REG(spdif_in), 918c2ecf20Sopenharmony_ci}, 928c2ecf20Sopenharmony_ci}; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic struct snd_soc_card a370db = { 958c2ecf20Sopenharmony_ci .name = "a370db", 968c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 978c2ecf20Sopenharmony_ci .dai_link = a370db_dai, 988c2ecf20Sopenharmony_ci .num_links = ARRAY_SIZE(a370db_dai), 998c2ecf20Sopenharmony_ci .dapm_widgets = a370db_dapm_widgets, 1008c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(a370db_dapm_widgets), 1018c2ecf20Sopenharmony_ci .dapm_routes = a370db_route, 1028c2ecf20Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(a370db_route), 1038c2ecf20Sopenharmony_ci}; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic int a370db_probe(struct platform_device *pdev) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci struct snd_soc_card *card = &a370db; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci card->dev = &pdev->dev; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci a370db_dai[0].cpus->of_node = 1128c2ecf20Sopenharmony_ci of_parse_phandle(pdev->dev.of_node, 1138c2ecf20Sopenharmony_ci "marvell,audio-controller", 0); 1148c2ecf20Sopenharmony_ci a370db_dai[0].platforms->of_node = a370db_dai[0].cpus->of_node; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci a370db_dai[0].codecs->of_node = 1178c2ecf20Sopenharmony_ci of_parse_phandle(pdev->dev.of_node, 1188c2ecf20Sopenharmony_ci "marvell,audio-codec", 0); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci a370db_dai[1].cpus->of_node = a370db_dai[0].cpus->of_node; 1218c2ecf20Sopenharmony_ci a370db_dai[1].platforms->of_node = a370db_dai[0].cpus->of_node; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci a370db_dai[1].codecs->of_node = 1248c2ecf20Sopenharmony_ci of_parse_phandle(pdev->dev.of_node, 1258c2ecf20Sopenharmony_ci "marvell,audio-codec", 1); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci a370db_dai[2].cpus->of_node = a370db_dai[0].cpus->of_node; 1288c2ecf20Sopenharmony_ci a370db_dai[2].platforms->of_node = a370db_dai[0].cpus->of_node; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci a370db_dai[2].codecs->of_node = 1318c2ecf20Sopenharmony_ci of_parse_phandle(pdev->dev.of_node, 1328c2ecf20Sopenharmony_ci "marvell,audio-codec", 2); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci return devm_snd_soc_register_card(card->dev, card); 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic const struct of_device_id a370db_dt_ids[] = { 1388c2ecf20Sopenharmony_ci { .compatible = "marvell,a370db-audio" }, 1398c2ecf20Sopenharmony_ci { }, 1408c2ecf20Sopenharmony_ci}; 1418c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, a370db_dt_ids); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic struct platform_driver a370db_driver = { 1448c2ecf20Sopenharmony_ci .driver = { 1458c2ecf20Sopenharmony_ci .name = "a370db-audio", 1468c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(a370db_dt_ids), 1478c2ecf20Sopenharmony_ci }, 1488c2ecf20Sopenharmony_ci .probe = a370db_probe, 1498c2ecf20Sopenharmony_ci}; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cimodule_platform_driver(a370db_driver); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ciMODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>"); 1548c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ALSA SoC a370db audio client"); 1558c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1568c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:a370db-audio"); 157