18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ASoC driver for TI DAVINCI EVM platform 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: Vladimir Barinov, <vbarinov@embeddedalley.com> 68c2ecf20Sopenharmony_ci * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 118c2ecf20Sopenharmony_ci#include <linux/timer.h> 128c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 138c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 148c2ecf20Sopenharmony_ci#include <linux/i2c.h> 158c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 168c2ecf20Sopenharmony_ci#include <linux/clk.h> 178c2ecf20Sopenharmony_ci#include <sound/core.h> 188c2ecf20Sopenharmony_ci#include <sound/pcm.h> 198c2ecf20Sopenharmony_ci#include <sound/soc.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <asm/dma.h> 228c2ecf20Sopenharmony_ci#include <asm/mach-types.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistruct snd_soc_card_drvdata_davinci { 258c2ecf20Sopenharmony_ci struct clk *mclk; 268c2ecf20Sopenharmony_ci unsigned sysclk; 278c2ecf20Sopenharmony_ci}; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic int evm_startup(struct snd_pcm_substream *substream) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 328c2ecf20Sopenharmony_ci struct snd_soc_card *soc_card = rtd->card; 338c2ecf20Sopenharmony_ci struct snd_soc_card_drvdata_davinci *drvdata = 348c2ecf20Sopenharmony_ci snd_soc_card_get_drvdata(soc_card); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci if (drvdata->mclk) 378c2ecf20Sopenharmony_ci return clk_prepare_enable(drvdata->mclk); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci return 0; 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic void evm_shutdown(struct snd_pcm_substream *substream) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 458c2ecf20Sopenharmony_ci struct snd_soc_card *soc_card = rtd->card; 468c2ecf20Sopenharmony_ci struct snd_soc_card_drvdata_davinci *drvdata = 478c2ecf20Sopenharmony_ci snd_soc_card_get_drvdata(soc_card); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci if (drvdata->mclk) 508c2ecf20Sopenharmony_ci clk_disable_unprepare(drvdata->mclk); 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic int evm_hw_params(struct snd_pcm_substream *substream, 548c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 578c2ecf20Sopenharmony_ci struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 588c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 598c2ecf20Sopenharmony_ci struct snd_soc_card *soc_card = rtd->card; 608c2ecf20Sopenharmony_ci int ret = 0; 618c2ecf20Sopenharmony_ci unsigned sysclk = ((struct snd_soc_card_drvdata_davinci *) 628c2ecf20Sopenharmony_ci snd_soc_card_get_drvdata(soc_card))->sysclk; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci /* set the codec system clock */ 658c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk, SND_SOC_CLOCK_OUT); 668c2ecf20Sopenharmony_ci if (ret < 0) 678c2ecf20Sopenharmony_ci return ret; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci /* set the CPU system clock */ 708c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_sysclk(cpu_dai, 0, sysclk, SND_SOC_CLOCK_OUT); 718c2ecf20Sopenharmony_ci if (ret < 0 && ret != -ENOTSUPP) 728c2ecf20Sopenharmony_ci return ret; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci return 0; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic struct snd_soc_ops evm_ops = { 788c2ecf20Sopenharmony_ci .startup = evm_startup, 798c2ecf20Sopenharmony_ci .shutdown = evm_shutdown, 808c2ecf20Sopenharmony_ci .hw_params = evm_hw_params, 818c2ecf20Sopenharmony_ci}; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/* davinci-evm machine dapm widgets */ 848c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { 858c2ecf20Sopenharmony_ci SND_SOC_DAPM_HP("Headphone Jack", NULL), 868c2ecf20Sopenharmony_ci SND_SOC_DAPM_LINE("Line Out", NULL), 878c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIC("Mic Jack", NULL), 888c2ecf20Sopenharmony_ci SND_SOC_DAPM_LINE("Line In", NULL), 898c2ecf20Sopenharmony_ci}; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci/* davinci-evm machine audio_mapnections to the codec pins */ 928c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route audio_map[] = { 938c2ecf20Sopenharmony_ci /* Headphone connected to HPLOUT, HPROUT */ 948c2ecf20Sopenharmony_ci {"Headphone Jack", NULL, "HPLOUT"}, 958c2ecf20Sopenharmony_ci {"Headphone Jack", NULL, "HPROUT"}, 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci /* Line Out connected to LLOUT, RLOUT */ 988c2ecf20Sopenharmony_ci {"Line Out", NULL, "LLOUT"}, 998c2ecf20Sopenharmony_ci {"Line Out", NULL, "RLOUT"}, 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* Mic connected to (MIC3L | MIC3R) */ 1028c2ecf20Sopenharmony_ci {"MIC3L", NULL, "Mic Bias"}, 1038c2ecf20Sopenharmony_ci {"MIC3R", NULL, "Mic Bias"}, 1048c2ecf20Sopenharmony_ci {"Mic Bias", NULL, "Mic Jack"}, 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* Line In connected to (LINE1L | LINE2L), (LINE1R | LINE2R) */ 1078c2ecf20Sopenharmony_ci {"LINE1L", NULL, "Line In"}, 1088c2ecf20Sopenharmony_ci {"LINE2L", NULL, "Line In"}, 1098c2ecf20Sopenharmony_ci {"LINE1R", NULL, "Line In"}, 1108c2ecf20Sopenharmony_ci {"LINE2R", NULL, "Line In"}, 1118c2ecf20Sopenharmony_ci}; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/* Logic for a aic3x as connected on a davinci-evm */ 1148c2ecf20Sopenharmony_cistatic int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci struct snd_soc_card *card = rtd->card; 1178c2ecf20Sopenharmony_ci struct device_node *np = card->dev->of_node; 1188c2ecf20Sopenharmony_ci int ret; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci /* Add davinci-evm specific widgets */ 1218c2ecf20Sopenharmony_ci snd_soc_dapm_new_controls(&card->dapm, aic3x_dapm_widgets, 1228c2ecf20Sopenharmony_ci ARRAY_SIZE(aic3x_dapm_widgets)); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (np) { 1258c2ecf20Sopenharmony_ci ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing"); 1268c2ecf20Sopenharmony_ci if (ret) 1278c2ecf20Sopenharmony_ci return ret; 1288c2ecf20Sopenharmony_ci } else { 1298c2ecf20Sopenharmony_ci /* Set up davinci-evm specific audio path audio_map */ 1308c2ecf20Sopenharmony_ci snd_soc_dapm_add_routes(&card->dapm, audio_map, 1318c2ecf20Sopenharmony_ci ARRAY_SIZE(audio_map)); 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* not connected */ 1358c2ecf20Sopenharmony_ci snd_soc_dapm_nc_pin(&card->dapm, "MONO_LOUT"); 1368c2ecf20Sopenharmony_ci snd_soc_dapm_nc_pin(&card->dapm, "HPLCOM"); 1378c2ecf20Sopenharmony_ci snd_soc_dapm_nc_pin(&card->dapm, "HPRCOM"); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci return 0; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci/* davinci-evm digital audio interface glue - connects codec <--> CPU */ 1438c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(dm6446, 1448c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CPU("davinci-mcbsp")), 1458c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x-codec.1-001b", 1468c2ecf20Sopenharmony_ci "tlv320aic3x-hifi")), 1478c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_PLATFORM("davinci-mcbsp"))); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic struct snd_soc_dai_link dm6446_evm_dai = { 1508c2ecf20Sopenharmony_ci .name = "TLV320AIC3X", 1518c2ecf20Sopenharmony_ci .stream_name = "AIC3X", 1528c2ecf20Sopenharmony_ci .init = evm_aic3x_init, 1538c2ecf20Sopenharmony_ci .ops = &evm_ops, 1548c2ecf20Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM | 1558c2ecf20Sopenharmony_ci SND_SOC_DAIFMT_IB_NF, 1568c2ecf20Sopenharmony_ci SND_SOC_DAILINK_REG(dm6446), 1578c2ecf20Sopenharmony_ci}; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(dm355, 1608c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CPU("davinci-mcbsp.1")), 1618c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x-codec.1-001b", 1628c2ecf20Sopenharmony_ci "tlv320aic3x-hifi")), 1638c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_PLATFORM("davinci-mcbsp.1"))); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic struct snd_soc_dai_link dm355_evm_dai = { 1668c2ecf20Sopenharmony_ci .name = "TLV320AIC3X", 1678c2ecf20Sopenharmony_ci .stream_name = "AIC3X", 1688c2ecf20Sopenharmony_ci .init = evm_aic3x_init, 1698c2ecf20Sopenharmony_ci .ops = &evm_ops, 1708c2ecf20Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM | 1718c2ecf20Sopenharmony_ci SND_SOC_DAIFMT_IB_NF, 1728c2ecf20Sopenharmony_ci SND_SOC_DAILINK_REG(dm355), 1738c2ecf20Sopenharmony_ci}; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_SOC_DM365_AIC3X_CODEC 1768c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(dm365, 1778c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CPU("davinci-mcbsp")), 1788c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x-codec.1-0018", 1798c2ecf20Sopenharmony_ci "tlv320aic3x-hifi")), 1808c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_PLATFORM("davinci-mcbsp"))); 1818c2ecf20Sopenharmony_ci#elif defined(CONFIG_SND_SOC_DM365_VOICE_CODEC) 1828c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(dm365, 1838c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CPU("davinci-vcif")), 1848c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC("cq93vc-codec", "cq93vc-hifi")), 1858c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_PLATFORM("davinci-vcif"))); 1868c2ecf20Sopenharmony_ci#endif 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic struct snd_soc_dai_link dm365_evm_dai = { 1898c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_SOC_DM365_AIC3X_CODEC 1908c2ecf20Sopenharmony_ci .name = "TLV320AIC3X", 1918c2ecf20Sopenharmony_ci .stream_name = "AIC3X", 1928c2ecf20Sopenharmony_ci .init = evm_aic3x_init, 1938c2ecf20Sopenharmony_ci .ops = &evm_ops, 1948c2ecf20Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM | 1958c2ecf20Sopenharmony_ci SND_SOC_DAIFMT_IB_NF, 1968c2ecf20Sopenharmony_ci SND_SOC_DAILINK_REG(dm365), 1978c2ecf20Sopenharmony_ci#elif defined(CONFIG_SND_SOC_DM365_VOICE_CODEC) 1988c2ecf20Sopenharmony_ci .name = "Voice Codec - CQ93VC", 1998c2ecf20Sopenharmony_ci .stream_name = "CQ93", 2008c2ecf20Sopenharmony_ci SND_SOC_DAILINK_REG(dm365), 2018c2ecf20Sopenharmony_ci#endif 2028c2ecf20Sopenharmony_ci}; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(dm6467_aic3x, 2058c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CPU("davinci-mcasp.0")), 2068c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x-codec.0-001a", 2078c2ecf20Sopenharmony_ci "tlv320aic3x-hifi")), 2088c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_PLATFORM("davinci-mcasp.0"))); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(dm6467_spdif, 2118c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CPU("davinci-mcasp.1")), 2128c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC("spdif_dit", "dit-hifi")), 2138c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_PLATFORM("davinci-mcasp.1"))); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic struct snd_soc_dai_link dm6467_evm_dai[] = { 2168c2ecf20Sopenharmony_ci { 2178c2ecf20Sopenharmony_ci .name = "TLV320AIC3X", 2188c2ecf20Sopenharmony_ci .stream_name = "AIC3X", 2198c2ecf20Sopenharmony_ci .init = evm_aic3x_init, 2208c2ecf20Sopenharmony_ci .ops = &evm_ops, 2218c2ecf20Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM | 2228c2ecf20Sopenharmony_ci SND_SOC_DAIFMT_IB_NF, 2238c2ecf20Sopenharmony_ci SND_SOC_DAILINK_REG(dm6467_aic3x), 2248c2ecf20Sopenharmony_ci }, 2258c2ecf20Sopenharmony_ci { 2268c2ecf20Sopenharmony_ci .name = "McASP", 2278c2ecf20Sopenharmony_ci .stream_name = "spdif", 2288c2ecf20Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM | 2298c2ecf20Sopenharmony_ci SND_SOC_DAIFMT_IB_NF, 2308c2ecf20Sopenharmony_ci SND_SOC_DAILINK_REG(dm6467_spdif), 2318c2ecf20Sopenharmony_ci }, 2328c2ecf20Sopenharmony_ci}; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(da830, 2358c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CPU("davinci-mcasp.1")), 2368c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x-codec.1-0018", 2378c2ecf20Sopenharmony_ci "tlv320aic3x-hifi")), 2388c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_PLATFORM("davinci-mcasp.1"))); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic struct snd_soc_dai_link da830_evm_dai = { 2418c2ecf20Sopenharmony_ci .name = "TLV320AIC3X", 2428c2ecf20Sopenharmony_ci .stream_name = "AIC3X", 2438c2ecf20Sopenharmony_ci .init = evm_aic3x_init, 2448c2ecf20Sopenharmony_ci .ops = &evm_ops, 2458c2ecf20Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM | 2468c2ecf20Sopenharmony_ci SND_SOC_DAIFMT_IB_NF, 2478c2ecf20Sopenharmony_ci SND_SOC_DAILINK_REG(da830), 2488c2ecf20Sopenharmony_ci}; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(da850, 2518c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CPU("davinci-mcasp.0")), 2528c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x-codec.1-0018", 2538c2ecf20Sopenharmony_ci "tlv320aic3x-hifi")), 2548c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_PLATFORM("davinci-mcasp.0"))); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic struct snd_soc_dai_link da850_evm_dai = { 2578c2ecf20Sopenharmony_ci .name = "TLV320AIC3X", 2588c2ecf20Sopenharmony_ci .stream_name = "AIC3X", 2598c2ecf20Sopenharmony_ci .init = evm_aic3x_init, 2608c2ecf20Sopenharmony_ci .ops = &evm_ops, 2618c2ecf20Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM | 2628c2ecf20Sopenharmony_ci SND_SOC_DAIFMT_IB_NF, 2638c2ecf20Sopenharmony_ci SND_SOC_DAILINK_REG(da850), 2648c2ecf20Sopenharmony_ci}; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci/* davinci dm6446 evm audio machine driver */ 2678c2ecf20Sopenharmony_ci/* 2688c2ecf20Sopenharmony_ci * ASP0 in DM6446 EVM is clocked by U55, as configured by 2698c2ecf20Sopenharmony_ci * board-dm644x-evm.c using GPIOs from U18. There are six 2708c2ecf20Sopenharmony_ci * options; here we "know" we use a 48 KHz sample rate. 2718c2ecf20Sopenharmony_ci */ 2728c2ecf20Sopenharmony_cistatic struct snd_soc_card_drvdata_davinci dm6446_snd_soc_card_drvdata = { 2738c2ecf20Sopenharmony_ci .sysclk = 12288000, 2748c2ecf20Sopenharmony_ci}; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic struct snd_soc_card dm6446_snd_soc_card_evm = { 2778c2ecf20Sopenharmony_ci .name = "DaVinci DM6446 EVM", 2788c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 2798c2ecf20Sopenharmony_ci .dai_link = &dm6446_evm_dai, 2808c2ecf20Sopenharmony_ci .num_links = 1, 2818c2ecf20Sopenharmony_ci .drvdata = &dm6446_snd_soc_card_drvdata, 2828c2ecf20Sopenharmony_ci}; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci/* davinci dm355 evm audio machine driver */ 2858c2ecf20Sopenharmony_ci/* ASP1 on DM355 EVM is clocked by an external oscillator */ 2868c2ecf20Sopenharmony_cistatic struct snd_soc_card_drvdata_davinci dm355_snd_soc_card_drvdata = { 2878c2ecf20Sopenharmony_ci .sysclk = 27000000, 2888c2ecf20Sopenharmony_ci}; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic struct snd_soc_card dm355_snd_soc_card_evm = { 2918c2ecf20Sopenharmony_ci .name = "DaVinci DM355 EVM", 2928c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 2938c2ecf20Sopenharmony_ci .dai_link = &dm355_evm_dai, 2948c2ecf20Sopenharmony_ci .num_links = 1, 2958c2ecf20Sopenharmony_ci .drvdata = &dm355_snd_soc_card_drvdata, 2968c2ecf20Sopenharmony_ci}; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci/* davinci dm365 evm audio machine driver */ 2998c2ecf20Sopenharmony_cistatic struct snd_soc_card_drvdata_davinci dm365_snd_soc_card_drvdata = { 3008c2ecf20Sopenharmony_ci .sysclk = 27000000, 3018c2ecf20Sopenharmony_ci}; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic struct snd_soc_card dm365_snd_soc_card_evm = { 3048c2ecf20Sopenharmony_ci .name = "DaVinci DM365 EVM", 3058c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 3068c2ecf20Sopenharmony_ci .dai_link = &dm365_evm_dai, 3078c2ecf20Sopenharmony_ci .num_links = 1, 3088c2ecf20Sopenharmony_ci .drvdata = &dm365_snd_soc_card_drvdata, 3098c2ecf20Sopenharmony_ci}; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci/* davinci dm6467 evm audio machine driver */ 3128c2ecf20Sopenharmony_cistatic struct snd_soc_card_drvdata_davinci dm6467_snd_soc_card_drvdata = { 3138c2ecf20Sopenharmony_ci .sysclk = 27000000, 3148c2ecf20Sopenharmony_ci}; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic struct snd_soc_card dm6467_snd_soc_card_evm = { 3178c2ecf20Sopenharmony_ci .name = "DaVinci DM6467 EVM", 3188c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 3198c2ecf20Sopenharmony_ci .dai_link = dm6467_evm_dai, 3208c2ecf20Sopenharmony_ci .num_links = ARRAY_SIZE(dm6467_evm_dai), 3218c2ecf20Sopenharmony_ci .drvdata = &dm6467_snd_soc_card_drvdata, 3228c2ecf20Sopenharmony_ci}; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic struct snd_soc_card_drvdata_davinci da830_snd_soc_card_drvdata = { 3258c2ecf20Sopenharmony_ci .sysclk = 24576000, 3268c2ecf20Sopenharmony_ci}; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic struct snd_soc_card da830_snd_soc_card = { 3298c2ecf20Sopenharmony_ci .name = "DA830/OMAP-L137 EVM", 3308c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 3318c2ecf20Sopenharmony_ci .dai_link = &da830_evm_dai, 3328c2ecf20Sopenharmony_ci .num_links = 1, 3338c2ecf20Sopenharmony_ci .drvdata = &da830_snd_soc_card_drvdata, 3348c2ecf20Sopenharmony_ci}; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cistatic struct snd_soc_card_drvdata_davinci da850_snd_soc_card_drvdata = { 3378c2ecf20Sopenharmony_ci .sysclk = 24576000, 3388c2ecf20Sopenharmony_ci}; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic struct snd_soc_card da850_snd_soc_card = { 3418c2ecf20Sopenharmony_ci .name = "DA850/OMAP-L138 EVM", 3428c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 3438c2ecf20Sopenharmony_ci .dai_link = &da850_evm_dai, 3448c2ecf20Sopenharmony_ci .num_links = 1, 3458c2ecf20Sopenharmony_ci .drvdata = &da850_snd_soc_card_drvdata, 3468c2ecf20Sopenharmony_ci}; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci#if defined(CONFIG_OF) 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci/* 3518c2ecf20Sopenharmony_ci * The struct is used as place holder. It will be completely 3528c2ecf20Sopenharmony_ci * filled with data from dt node. 3538c2ecf20Sopenharmony_ci */ 3548c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(evm, 3558c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_EMPTY()), 3568c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "tlv320aic3x-hifi")), 3578c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_EMPTY())); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic struct snd_soc_dai_link evm_dai_tlv320aic3x = { 3608c2ecf20Sopenharmony_ci .name = "TLV320AIC3X", 3618c2ecf20Sopenharmony_ci .stream_name = "AIC3X", 3628c2ecf20Sopenharmony_ci .ops = &evm_ops, 3638c2ecf20Sopenharmony_ci .init = evm_aic3x_init, 3648c2ecf20Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM | 3658c2ecf20Sopenharmony_ci SND_SOC_DAIFMT_IB_NF, 3668c2ecf20Sopenharmony_ci SND_SOC_DAILINK_REG(evm), 3678c2ecf20Sopenharmony_ci}; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cistatic const struct of_device_id davinci_evm_dt_ids[] = { 3708c2ecf20Sopenharmony_ci { 3718c2ecf20Sopenharmony_ci .compatible = "ti,da830-evm-audio", 3728c2ecf20Sopenharmony_ci .data = (void *) &evm_dai_tlv320aic3x, 3738c2ecf20Sopenharmony_ci }, 3748c2ecf20Sopenharmony_ci { /* sentinel */ } 3758c2ecf20Sopenharmony_ci}; 3768c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, davinci_evm_dt_ids); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci/* davinci evm audio machine driver */ 3798c2ecf20Sopenharmony_cistatic struct snd_soc_card evm_soc_card = { 3808c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 3818c2ecf20Sopenharmony_ci .num_links = 1, 3828c2ecf20Sopenharmony_ci}; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cistatic int davinci_evm_probe(struct platform_device *pdev) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 3878c2ecf20Sopenharmony_ci const struct of_device_id *match; 3888c2ecf20Sopenharmony_ci struct snd_soc_dai_link *dai; 3898c2ecf20Sopenharmony_ci struct snd_soc_card_drvdata_davinci *drvdata = NULL; 3908c2ecf20Sopenharmony_ci struct clk *mclk; 3918c2ecf20Sopenharmony_ci int ret = 0; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci match = of_match_device(of_match_ptr(davinci_evm_dt_ids), &pdev->dev); 3948c2ecf20Sopenharmony_ci if (!match) { 3958c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Error: No device match found\n"); 3968c2ecf20Sopenharmony_ci return -ENODEV; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci dai = (struct snd_soc_dai_link *) match->data; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci evm_soc_card.dai_link = dai; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci dai->codecs->of_node = of_parse_phandle(np, "ti,audio-codec", 0); 4048c2ecf20Sopenharmony_ci if (!dai->codecs->of_node) 4058c2ecf20Sopenharmony_ci return -EINVAL; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci dai->cpus->of_node = of_parse_phandle(np, "ti,mcasp-controller", 0); 4088c2ecf20Sopenharmony_ci if (!dai->cpus->of_node) 4098c2ecf20Sopenharmony_ci return -EINVAL; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci dai->platforms->of_node = dai->cpus->of_node; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci evm_soc_card.dev = &pdev->dev; 4148c2ecf20Sopenharmony_ci ret = snd_soc_of_parse_card_name(&evm_soc_card, "ti,model"); 4158c2ecf20Sopenharmony_ci if (ret) 4168c2ecf20Sopenharmony_ci return ret; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci mclk = devm_clk_get(&pdev->dev, "mclk"); 4198c2ecf20Sopenharmony_ci if (PTR_ERR(mclk) == -EPROBE_DEFER) { 4208c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 4218c2ecf20Sopenharmony_ci } else if (IS_ERR(mclk)) { 4228c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "mclk not found.\n"); 4238c2ecf20Sopenharmony_ci mclk = NULL; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); 4278c2ecf20Sopenharmony_ci if (!drvdata) 4288c2ecf20Sopenharmony_ci return -ENOMEM; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci drvdata->mclk = mclk; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, "ti,codec-clock-rate", &drvdata->sysclk); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci if (ret < 0) { 4358c2ecf20Sopenharmony_ci if (!drvdata->mclk) { 4368c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 4378c2ecf20Sopenharmony_ci "No clock or clock rate defined.\n"); 4388c2ecf20Sopenharmony_ci return -EINVAL; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci drvdata->sysclk = clk_get_rate(drvdata->mclk); 4418c2ecf20Sopenharmony_ci } else if (drvdata->mclk) { 4428c2ecf20Sopenharmony_ci unsigned int requestd_rate = drvdata->sysclk; 4438c2ecf20Sopenharmony_ci clk_set_rate(drvdata->mclk, drvdata->sysclk); 4448c2ecf20Sopenharmony_ci drvdata->sysclk = clk_get_rate(drvdata->mclk); 4458c2ecf20Sopenharmony_ci if (drvdata->sysclk != requestd_rate) 4468c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, 4478c2ecf20Sopenharmony_ci "Could not get requested rate %u using %u.\n", 4488c2ecf20Sopenharmony_ci requestd_rate, drvdata->sysclk); 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci snd_soc_card_set_drvdata(&evm_soc_card, drvdata); 4528c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_card(&pdev->dev, &evm_soc_card); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if (ret) 4558c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci return ret; 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cistatic struct platform_driver davinci_evm_driver = { 4618c2ecf20Sopenharmony_ci .probe = davinci_evm_probe, 4628c2ecf20Sopenharmony_ci .driver = { 4638c2ecf20Sopenharmony_ci .name = "davinci_evm", 4648c2ecf20Sopenharmony_ci .pm = &snd_soc_pm_ops, 4658c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(davinci_evm_dt_ids), 4668c2ecf20Sopenharmony_ci }, 4678c2ecf20Sopenharmony_ci}; 4688c2ecf20Sopenharmony_ci#endif 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_cistatic struct platform_device *evm_snd_device; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic int __init evm_init(void) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci struct snd_soc_card *evm_snd_dev_data; 4758c2ecf20Sopenharmony_ci int index; 4768c2ecf20Sopenharmony_ci int ret; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci /* 4798c2ecf20Sopenharmony_ci * If dtb is there, the devices will be created dynamically. 4808c2ecf20Sopenharmony_ci * Only register platfrom driver structure. 4818c2ecf20Sopenharmony_ci */ 4828c2ecf20Sopenharmony_ci#if defined(CONFIG_OF) 4838c2ecf20Sopenharmony_ci if (of_have_populated_dt()) 4848c2ecf20Sopenharmony_ci return platform_driver_register(&davinci_evm_driver); 4858c2ecf20Sopenharmony_ci#endif 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci if (machine_is_davinci_evm()) { 4888c2ecf20Sopenharmony_ci evm_snd_dev_data = &dm6446_snd_soc_card_evm; 4898c2ecf20Sopenharmony_ci index = 0; 4908c2ecf20Sopenharmony_ci } else if (machine_is_davinci_dm355_evm()) { 4918c2ecf20Sopenharmony_ci evm_snd_dev_data = &dm355_snd_soc_card_evm; 4928c2ecf20Sopenharmony_ci index = 1; 4938c2ecf20Sopenharmony_ci } else if (machine_is_davinci_dm365_evm()) { 4948c2ecf20Sopenharmony_ci evm_snd_dev_data = &dm365_snd_soc_card_evm; 4958c2ecf20Sopenharmony_ci index = 0; 4968c2ecf20Sopenharmony_ci } else if (machine_is_davinci_dm6467_evm()) { 4978c2ecf20Sopenharmony_ci evm_snd_dev_data = &dm6467_snd_soc_card_evm; 4988c2ecf20Sopenharmony_ci index = 0; 4998c2ecf20Sopenharmony_ci } else if (machine_is_davinci_da830_evm()) { 5008c2ecf20Sopenharmony_ci evm_snd_dev_data = &da830_snd_soc_card; 5018c2ecf20Sopenharmony_ci index = 1; 5028c2ecf20Sopenharmony_ci } else if (machine_is_davinci_da850_evm()) { 5038c2ecf20Sopenharmony_ci evm_snd_dev_data = &da850_snd_soc_card; 5048c2ecf20Sopenharmony_ci index = 0; 5058c2ecf20Sopenharmony_ci } else 5068c2ecf20Sopenharmony_ci return -EINVAL; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci evm_snd_device = platform_device_alloc("soc-audio", index); 5098c2ecf20Sopenharmony_ci if (!evm_snd_device) 5108c2ecf20Sopenharmony_ci return -ENOMEM; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci platform_set_drvdata(evm_snd_device, evm_snd_dev_data); 5138c2ecf20Sopenharmony_ci ret = platform_device_add(evm_snd_device); 5148c2ecf20Sopenharmony_ci if (ret) 5158c2ecf20Sopenharmony_ci platform_device_put(evm_snd_device); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci return ret; 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic void __exit evm_exit(void) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci#if defined(CONFIG_OF) 5238c2ecf20Sopenharmony_ci if (of_have_populated_dt()) { 5248c2ecf20Sopenharmony_ci platform_driver_unregister(&davinci_evm_driver); 5258c2ecf20Sopenharmony_ci return; 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci#endif 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci platform_device_unregister(evm_snd_device); 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cimodule_init(evm_init); 5338c2ecf20Sopenharmony_cimodule_exit(evm_exit); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ciMODULE_AUTHOR("Vladimir Barinov"); 5368c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TI DAVINCI EVM ASoC driver"); 5378c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 538