18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci#include "../codecs/wm8994.h" 48c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 58c2ecf20Sopenharmony_ci#include <sound/soc.h> 68c2ecf20Sopenharmony_ci#include <linux/module.h> 78c2ecf20Sopenharmony_ci#include <linux/of.h> 88c2ecf20Sopenharmony_ci#include <linux/of_device.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci /* 118c2ecf20Sopenharmony_ci * Default CFG switch settings to use this driver: 128c2ecf20Sopenharmony_ci * SMDKV310: CFG5-1000, CFG7-111111 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci /* 168c2ecf20Sopenharmony_ci * Configure audio route as :- 178c2ecf20Sopenharmony_ci * $ amixer sset 'DAC1' on,on 188c2ecf20Sopenharmony_ci * $ amixer sset 'Right Headphone Mux' 'DAC' 198c2ecf20Sopenharmony_ci * $ amixer sset 'Left Headphone Mux' 'DAC' 208c2ecf20Sopenharmony_ci * $ amixer sset 'DAC1R Mixer AIF1.1' on 218c2ecf20Sopenharmony_ci * $ amixer sset 'DAC1L Mixer AIF1.1' on 228c2ecf20Sopenharmony_ci * $ amixer sset 'IN2L' on 238c2ecf20Sopenharmony_ci * $ amixer sset 'IN2L PGA IN2LN' on 248c2ecf20Sopenharmony_ci * $ amixer sset 'MIXINL IN2L' on 258c2ecf20Sopenharmony_ci * $ amixer sset 'AIF1ADC1L Mixer ADC/DMIC' on 268c2ecf20Sopenharmony_ci * $ amixer sset 'IN2R' on 278c2ecf20Sopenharmony_ci * $ amixer sset 'IN2R PGA IN2RN' on 288c2ecf20Sopenharmony_ci * $ amixer sset 'MIXINR IN2R' on 298c2ecf20Sopenharmony_ci * $ amixer sset 'AIF1ADC1R Mixer ADC/DMIC' on 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* SMDK has a 16.934MHZ crystal attached to WM8994 */ 338c2ecf20Sopenharmony_ci#define SMDK_WM8994_FREQ 16934000 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistruct smdk_wm8994_data { 368c2ecf20Sopenharmony_ci int mclk1_rate; 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* Default SMDKs */ 408c2ecf20Sopenharmony_cistatic struct smdk_wm8994_data smdk_board_data = { 418c2ecf20Sopenharmony_ci .mclk1_rate = SMDK_WM8994_FREQ, 428c2ecf20Sopenharmony_ci}; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic int smdk_hw_params(struct snd_pcm_substream *substream, 458c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 488c2ecf20Sopenharmony_ci struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 498c2ecf20Sopenharmony_ci unsigned int pll_out; 508c2ecf20Sopenharmony_ci int ret; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci /* AIF1CLK should be >=3MHz for optimal performance */ 538c2ecf20Sopenharmony_ci if (params_width(params) == 24) 548c2ecf20Sopenharmony_ci pll_out = params_rate(params) * 384; 558c2ecf20Sopenharmony_ci else if (params_rate(params) == 8000 || params_rate(params) == 11025) 568c2ecf20Sopenharmony_ci pll_out = params_rate(params) * 512; 578c2ecf20Sopenharmony_ci else 588c2ecf20Sopenharmony_ci pll_out = params_rate(params) * 256; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, WM8994_FLL_SRC_MCLK1, 618c2ecf20Sopenharmony_ci SMDK_WM8994_FREQ, pll_out); 628c2ecf20Sopenharmony_ci if (ret < 0) 638c2ecf20Sopenharmony_ci return ret; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1, 668c2ecf20Sopenharmony_ci pll_out, SND_SOC_CLOCK_IN); 678c2ecf20Sopenharmony_ci if (ret < 0) 688c2ecf20Sopenharmony_ci return ret; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci return 0; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* 748c2ecf20Sopenharmony_ci * SMDK WM8994 DAI operations. 758c2ecf20Sopenharmony_ci */ 768c2ecf20Sopenharmony_cistatic struct snd_soc_ops smdk_ops = { 778c2ecf20Sopenharmony_ci .hw_params = smdk_hw_params, 788c2ecf20Sopenharmony_ci}; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic int smdk_wm8994_init_paiftx(struct snd_soc_pcm_runtime *rtd) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = &rtd->card->dapm; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci /* Other pins NC */ 858c2ecf20Sopenharmony_ci snd_soc_dapm_nc_pin(dapm, "HPOUT2P"); 868c2ecf20Sopenharmony_ci snd_soc_dapm_nc_pin(dapm, "HPOUT2N"); 878c2ecf20Sopenharmony_ci snd_soc_dapm_nc_pin(dapm, "SPKOUTLN"); 888c2ecf20Sopenharmony_ci snd_soc_dapm_nc_pin(dapm, "SPKOUTLP"); 898c2ecf20Sopenharmony_ci snd_soc_dapm_nc_pin(dapm, "SPKOUTRP"); 908c2ecf20Sopenharmony_ci snd_soc_dapm_nc_pin(dapm, "SPKOUTRN"); 918c2ecf20Sopenharmony_ci snd_soc_dapm_nc_pin(dapm, "LINEOUT1N"); 928c2ecf20Sopenharmony_ci snd_soc_dapm_nc_pin(dapm, "LINEOUT1P"); 938c2ecf20Sopenharmony_ci snd_soc_dapm_nc_pin(dapm, "LINEOUT2N"); 948c2ecf20Sopenharmony_ci snd_soc_dapm_nc_pin(dapm, "LINEOUT2P"); 958c2ecf20Sopenharmony_ci snd_soc_dapm_nc_pin(dapm, "IN1LP"); 968c2ecf20Sopenharmony_ci snd_soc_dapm_nc_pin(dapm, "IN2LP:VXRN"); 978c2ecf20Sopenharmony_ci snd_soc_dapm_nc_pin(dapm, "IN1RP"); 988c2ecf20Sopenharmony_ci snd_soc_dapm_nc_pin(dapm, "IN2RP:VXRP"); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci return 0; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(aif1, 1048c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CPU("samsung-i2s.0")), 1058c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC("wm8994-codec", "wm8994-aif1")), 1068c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_PLATFORM("samsung-i2s.0"))); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(fifo_tx, 1098c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CPU("samsung-i2s-sec")), 1108c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC("wm8994-codec", "wm8994-aif1")), 1118c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_PLATFORM("samsung-i2s-sec"))); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic struct snd_soc_dai_link smdk_dai[] = { 1148c2ecf20Sopenharmony_ci { /* Primary DAI i/f */ 1158c2ecf20Sopenharmony_ci .name = "WM8994 AIF1", 1168c2ecf20Sopenharmony_ci .stream_name = "Pri_Dai", 1178c2ecf20Sopenharmony_ci .init = smdk_wm8994_init_paiftx, 1188c2ecf20Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 1198c2ecf20Sopenharmony_ci SND_SOC_DAIFMT_CBM_CFM, 1208c2ecf20Sopenharmony_ci .ops = &smdk_ops, 1218c2ecf20Sopenharmony_ci SND_SOC_DAILINK_REG(aif1), 1228c2ecf20Sopenharmony_ci }, { /* Sec_Fifo Playback i/f */ 1238c2ecf20Sopenharmony_ci .name = "Sec_FIFO TX", 1248c2ecf20Sopenharmony_ci .stream_name = "Sec_Dai", 1258c2ecf20Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 1268c2ecf20Sopenharmony_ci SND_SOC_DAIFMT_CBM_CFM, 1278c2ecf20Sopenharmony_ci .ops = &smdk_ops, 1288c2ecf20Sopenharmony_ci SND_SOC_DAILINK_REG(fifo_tx), 1298c2ecf20Sopenharmony_ci }, 1308c2ecf20Sopenharmony_ci}; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic struct snd_soc_card smdk = { 1338c2ecf20Sopenharmony_ci .name = "SMDK-I2S", 1348c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1358c2ecf20Sopenharmony_ci .dai_link = smdk_dai, 1368c2ecf20Sopenharmony_ci .num_links = ARRAY_SIZE(smdk_dai), 1378c2ecf20Sopenharmony_ci}; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic const struct of_device_id samsung_wm8994_of_match[] = { 1408c2ecf20Sopenharmony_ci { .compatible = "samsung,smdk-wm8994", .data = &smdk_board_data }, 1418c2ecf20Sopenharmony_ci {}, 1428c2ecf20Sopenharmony_ci}; 1438c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, samsung_wm8994_of_match); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic int smdk_audio_probe(struct platform_device *pdev) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci int ret; 1488c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 1498c2ecf20Sopenharmony_ci struct snd_soc_card *card = &smdk; 1508c2ecf20Sopenharmony_ci struct smdk_wm8994_data *board; 1518c2ecf20Sopenharmony_ci const struct of_device_id *id; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci card->dev = &pdev->dev; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci board = devm_kzalloc(&pdev->dev, sizeof(*board), GFP_KERNEL); 1568c2ecf20Sopenharmony_ci if (!board) 1578c2ecf20Sopenharmony_ci return -ENOMEM; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci if (np) { 1608c2ecf20Sopenharmony_ci smdk_dai[0].cpus->dai_name = NULL; 1618c2ecf20Sopenharmony_ci smdk_dai[0].cpus->of_node = of_parse_phandle(np, 1628c2ecf20Sopenharmony_ci "samsung,i2s-controller", 0); 1638c2ecf20Sopenharmony_ci if (!smdk_dai[0].cpus->of_node) { 1648c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 1658c2ecf20Sopenharmony_ci "Property 'samsung,i2s-controller' missing or invalid\n"); 1668c2ecf20Sopenharmony_ci ret = -EINVAL; 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci smdk_dai[0].platforms->name = NULL; 1708c2ecf20Sopenharmony_ci smdk_dai[0].platforms->of_node = smdk_dai[0].cpus->of_node; 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci id = of_match_device(of_match_ptr(samsung_wm8994_of_match), &pdev->dev); 1748c2ecf20Sopenharmony_ci if (id) 1758c2ecf20Sopenharmony_ci *board = *((struct smdk_wm8994_data *)id->data); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, board); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_card(&pdev->dev, card); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (ret) 1828c2ecf20Sopenharmony_ci dev_err_probe(&pdev->dev, ret, "snd_soc_register_card() failed\n"); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci return ret; 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic struct platform_driver smdk_audio_driver = { 1888c2ecf20Sopenharmony_ci .driver = { 1898c2ecf20Sopenharmony_ci .name = "smdk-audio-wm8994", 1908c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(samsung_wm8994_of_match), 1918c2ecf20Sopenharmony_ci .pm = &snd_soc_pm_ops, 1928c2ecf20Sopenharmony_ci }, 1938c2ecf20Sopenharmony_ci .probe = smdk_audio_probe, 1948c2ecf20Sopenharmony_ci}; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cimodule_platform_driver(smdk_audio_driver); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ALSA SoC SMDK WM8994"); 1998c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 2008c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:smdk-audio-wm8994"); 201