Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * ASoC driver for TI DAVINCI EVM platform
0004  *
0005  * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
0006  * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
0007  */
0008 
0009 #include <linux/module.h>
0010 #include <linux/moduleparam.h>
0011 #include <linux/timer.h>
0012 #include <linux/interrupt.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/i2c.h>
0015 #include <linux/of_platform.h>
0016 #include <linux/clk.h>
0017 #include <sound/core.h>
0018 #include <sound/pcm.h>
0019 #include <sound/soc.h>
0020 
0021 #include <asm/dma.h>
0022 #include <asm/mach-types.h>
0023 
0024 struct snd_soc_card_drvdata_davinci {
0025     struct clk *mclk;
0026     unsigned sysclk;
0027 };
0028 
0029 static int evm_startup(struct snd_pcm_substream *substream)
0030 {
0031     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0032     struct snd_soc_card *soc_card = rtd->card;
0033     struct snd_soc_card_drvdata_davinci *drvdata =
0034         snd_soc_card_get_drvdata(soc_card);
0035 
0036     if (drvdata->mclk)
0037         return clk_prepare_enable(drvdata->mclk);
0038 
0039     return 0;
0040 }
0041 
0042 static void evm_shutdown(struct snd_pcm_substream *substream)
0043 {
0044     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0045     struct snd_soc_card *soc_card = rtd->card;
0046     struct snd_soc_card_drvdata_davinci *drvdata =
0047         snd_soc_card_get_drvdata(soc_card);
0048 
0049     clk_disable_unprepare(drvdata->mclk);
0050 }
0051 
0052 static int evm_hw_params(struct snd_pcm_substream *substream,
0053              struct snd_pcm_hw_params *params)
0054 {
0055     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0056     struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
0057     struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
0058     struct snd_soc_card *soc_card = rtd->card;
0059     int ret = 0;
0060     unsigned sysclk = ((struct snd_soc_card_drvdata_davinci *)
0061                snd_soc_card_get_drvdata(soc_card))->sysclk;
0062 
0063     /* set the codec system clock */
0064     ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk, SND_SOC_CLOCK_OUT);
0065     if (ret < 0)
0066         return ret;
0067 
0068     /* set the CPU system clock */
0069     ret = snd_soc_dai_set_sysclk(cpu_dai, 0, sysclk, SND_SOC_CLOCK_OUT);
0070     if (ret < 0 && ret != -ENOTSUPP)
0071         return ret;
0072 
0073     return 0;
0074 }
0075 
0076 static const struct snd_soc_ops evm_ops = {
0077     .startup = evm_startup,
0078     .shutdown = evm_shutdown,
0079     .hw_params = evm_hw_params,
0080 };
0081 
0082 /* davinci-evm machine dapm widgets */
0083 static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
0084     SND_SOC_DAPM_HP("Headphone Jack", NULL),
0085     SND_SOC_DAPM_LINE("Line Out", NULL),
0086     SND_SOC_DAPM_MIC("Mic Jack", NULL),
0087     SND_SOC_DAPM_LINE("Line In", NULL),
0088 };
0089 
0090 /* davinci-evm machine audio_mapnections to the codec pins */
0091 static const struct snd_soc_dapm_route audio_map[] = {
0092     /* Headphone connected to HPLOUT, HPROUT */
0093     {"Headphone Jack", NULL, "HPLOUT"},
0094     {"Headphone Jack", NULL, "HPROUT"},
0095 
0096     /* Line Out connected to LLOUT, RLOUT */
0097     {"Line Out", NULL, "LLOUT"},
0098     {"Line Out", NULL, "RLOUT"},
0099 
0100     /* Mic connected to (MIC3L | MIC3R) */
0101     {"MIC3L", NULL, "Mic Bias"},
0102     {"MIC3R", NULL, "Mic Bias"},
0103     {"Mic Bias", NULL, "Mic Jack"},
0104 
0105     /* Line In connected to (LINE1L | LINE2L), (LINE1R | LINE2R) */
0106     {"LINE1L", NULL, "Line In"},
0107     {"LINE2L", NULL, "Line In"},
0108     {"LINE1R", NULL, "Line In"},
0109     {"LINE2R", NULL, "Line In"},
0110 };
0111 
0112 /* Logic for a aic3x as connected on a davinci-evm */
0113 static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd)
0114 {
0115     struct snd_soc_card *card = rtd->card;
0116     struct device_node *np = card->dev->of_node;
0117     int ret;
0118 
0119     /* Add davinci-evm specific widgets */
0120     snd_soc_dapm_new_controls(&card->dapm, aic3x_dapm_widgets,
0121                   ARRAY_SIZE(aic3x_dapm_widgets));
0122 
0123     if (np) {
0124         ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing");
0125         if (ret)
0126             return ret;
0127     } else {
0128         /* Set up davinci-evm specific audio path audio_map */
0129         snd_soc_dapm_add_routes(&card->dapm, audio_map,
0130                     ARRAY_SIZE(audio_map));
0131     }
0132 
0133     /* not connected */
0134     snd_soc_dapm_nc_pin(&card->dapm, "MONO_LOUT");
0135     snd_soc_dapm_nc_pin(&card->dapm, "HPLCOM");
0136     snd_soc_dapm_nc_pin(&card->dapm, "HPRCOM");
0137 
0138     return 0;
0139 }
0140 
0141 /* davinci-evm digital audio interface glue - connects codec <--> CPU */
0142 SND_SOC_DAILINK_DEFS(dm6446,
0143     DAILINK_COMP_ARRAY(COMP_CPU("davinci-mcbsp")),
0144     DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x-codec.1-001b",
0145                       "tlv320aic3x-hifi")),
0146     DAILINK_COMP_ARRAY(COMP_PLATFORM("davinci-mcbsp")));
0147 
0148 static struct snd_soc_dai_link dm6446_evm_dai = {
0149     .name = "TLV320AIC3X",
0150     .stream_name = "AIC3X",
0151     .init = evm_aic3x_init,
0152     .ops = &evm_ops,
0153     .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
0154            SND_SOC_DAIFMT_IB_NF,
0155     SND_SOC_DAILINK_REG(dm6446),
0156 };
0157 
0158 SND_SOC_DAILINK_DEFS(dm355,
0159     DAILINK_COMP_ARRAY(COMP_CPU("davinci-mcbsp.1")),
0160     DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x-codec.1-001b",
0161                       "tlv320aic3x-hifi")),
0162     DAILINK_COMP_ARRAY(COMP_PLATFORM("davinci-mcbsp.1")));
0163 
0164 static struct snd_soc_dai_link dm355_evm_dai = {
0165     .name = "TLV320AIC3X",
0166     .stream_name = "AIC3X",
0167     .init = evm_aic3x_init,
0168     .ops = &evm_ops,
0169     .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
0170            SND_SOC_DAIFMT_IB_NF,
0171     SND_SOC_DAILINK_REG(dm355),
0172 };
0173 
0174 #ifdef CONFIG_SND_SOC_DM365_AIC3X_CODEC
0175 SND_SOC_DAILINK_DEFS(dm365,
0176     DAILINK_COMP_ARRAY(COMP_CPU("davinci-mcbsp")),
0177     DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x-codec.1-0018",
0178                       "tlv320aic3x-hifi")),
0179     DAILINK_COMP_ARRAY(COMP_PLATFORM("davinci-mcbsp")));
0180 #elif defined(CONFIG_SND_SOC_DM365_VOICE_CODEC)
0181 SND_SOC_DAILINK_DEFS(dm365,
0182     DAILINK_COMP_ARRAY(COMP_CPU("davinci-vcif")),
0183     DAILINK_COMP_ARRAY(COMP_CODEC("cq93vc-codec", "cq93vc-hifi")),
0184     DAILINK_COMP_ARRAY(COMP_PLATFORM("davinci-vcif")));
0185 #endif
0186 
0187 static struct snd_soc_dai_link dm365_evm_dai = {
0188 #ifdef CONFIG_SND_SOC_DM365_AIC3X_CODEC
0189     .name = "TLV320AIC3X",
0190     .stream_name = "AIC3X",
0191     .init = evm_aic3x_init,
0192     .ops = &evm_ops,
0193     .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
0194            SND_SOC_DAIFMT_IB_NF,
0195     SND_SOC_DAILINK_REG(dm365),
0196 #elif defined(CONFIG_SND_SOC_DM365_VOICE_CODEC)
0197     .name = "Voice Codec - CQ93VC",
0198     .stream_name = "CQ93",
0199     SND_SOC_DAILINK_REG(dm365),
0200 #endif
0201 };
0202 
0203 SND_SOC_DAILINK_DEFS(dm6467_aic3x,
0204     DAILINK_COMP_ARRAY(COMP_CPU("davinci-mcasp.0")),
0205     DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x-codec.0-001a",
0206                       "tlv320aic3x-hifi")),
0207     DAILINK_COMP_ARRAY(COMP_PLATFORM("davinci-mcasp.0")));
0208 
0209 SND_SOC_DAILINK_DEFS(dm6467_spdif,
0210     DAILINK_COMP_ARRAY(COMP_CPU("davinci-mcasp.1")),
0211     DAILINK_COMP_ARRAY(COMP_CODEC("spdif_dit", "dit-hifi")),
0212     DAILINK_COMP_ARRAY(COMP_PLATFORM("davinci-mcasp.1")));
0213 
0214 static struct snd_soc_dai_link dm6467_evm_dai[] = {
0215     {
0216         .name = "TLV320AIC3X",
0217         .stream_name = "AIC3X",
0218         .init = evm_aic3x_init,
0219         .ops = &evm_ops,
0220         .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
0221                SND_SOC_DAIFMT_IB_NF,
0222         SND_SOC_DAILINK_REG(dm6467_aic3x),
0223     },
0224     {
0225         .name = "McASP",
0226         .stream_name = "spdif",
0227         .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
0228                SND_SOC_DAIFMT_IB_NF,
0229         SND_SOC_DAILINK_REG(dm6467_spdif),
0230     },
0231 };
0232 
0233 SND_SOC_DAILINK_DEFS(da830,
0234     DAILINK_COMP_ARRAY(COMP_CPU("davinci-mcasp.1")),
0235     DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x-codec.1-0018",
0236                       "tlv320aic3x-hifi")),
0237     DAILINK_COMP_ARRAY(COMP_PLATFORM("davinci-mcasp.1")));
0238 
0239 static struct snd_soc_dai_link da830_evm_dai = {
0240     .name = "TLV320AIC3X",
0241     .stream_name = "AIC3X",
0242     .init = evm_aic3x_init,
0243     .ops = &evm_ops,
0244     .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
0245            SND_SOC_DAIFMT_IB_NF,
0246     SND_SOC_DAILINK_REG(da830),
0247 };
0248 
0249 SND_SOC_DAILINK_DEFS(da850,
0250     DAILINK_COMP_ARRAY(COMP_CPU("davinci-mcasp.0")),
0251     DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x-codec.1-0018",
0252                       "tlv320aic3x-hifi")),
0253     DAILINK_COMP_ARRAY(COMP_PLATFORM("davinci-mcasp.0")));
0254 
0255 static struct snd_soc_dai_link da850_evm_dai = {
0256     .name = "TLV320AIC3X",
0257     .stream_name = "AIC3X",
0258     .init = evm_aic3x_init,
0259     .ops = &evm_ops,
0260     .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
0261            SND_SOC_DAIFMT_IB_NF,
0262     SND_SOC_DAILINK_REG(da850),
0263 };
0264 
0265 /* davinci dm6446 evm audio machine driver */
0266 /*
0267  * ASP0 in DM6446 EVM is clocked by U55, as configured by
0268  * board-dm644x-evm.c using GPIOs from U18.  There are six
0269  * options; here we "know" we use a 48 KHz sample rate.
0270  */
0271 static struct snd_soc_card_drvdata_davinci dm6446_snd_soc_card_drvdata = {
0272     .sysclk = 12288000,
0273 };
0274 
0275 static struct snd_soc_card dm6446_snd_soc_card_evm = {
0276     .name = "DaVinci DM6446 EVM",
0277     .owner = THIS_MODULE,
0278     .dai_link = &dm6446_evm_dai,
0279     .num_links = 1,
0280     .drvdata = &dm6446_snd_soc_card_drvdata,
0281 };
0282 
0283 /* davinci dm355 evm audio machine driver */
0284 /* ASP1 on DM355 EVM is clocked by an external oscillator */
0285 static struct snd_soc_card_drvdata_davinci dm355_snd_soc_card_drvdata = {
0286     .sysclk = 27000000,
0287 };
0288 
0289 static struct snd_soc_card dm355_snd_soc_card_evm = {
0290     .name = "DaVinci DM355 EVM",
0291     .owner = THIS_MODULE,
0292     .dai_link = &dm355_evm_dai,
0293     .num_links = 1,
0294     .drvdata = &dm355_snd_soc_card_drvdata,
0295 };
0296 
0297 /* davinci dm365 evm audio machine driver */
0298 static struct snd_soc_card_drvdata_davinci dm365_snd_soc_card_drvdata = {
0299     .sysclk = 27000000,
0300 };
0301 
0302 static struct snd_soc_card dm365_snd_soc_card_evm = {
0303     .name = "DaVinci DM365 EVM",
0304     .owner = THIS_MODULE,
0305     .dai_link = &dm365_evm_dai,
0306     .num_links = 1,
0307     .drvdata = &dm365_snd_soc_card_drvdata,
0308 };
0309 
0310 /* davinci dm6467 evm audio machine driver */
0311 static struct snd_soc_card_drvdata_davinci dm6467_snd_soc_card_drvdata = {
0312     .sysclk = 27000000,
0313 };
0314 
0315 static struct snd_soc_card dm6467_snd_soc_card_evm = {
0316     .name = "DaVinci DM6467 EVM",
0317     .owner = THIS_MODULE,
0318     .dai_link = dm6467_evm_dai,
0319     .num_links = ARRAY_SIZE(dm6467_evm_dai),
0320     .drvdata = &dm6467_snd_soc_card_drvdata,
0321 };
0322 
0323 static struct snd_soc_card_drvdata_davinci da830_snd_soc_card_drvdata = {
0324     .sysclk = 24576000,
0325 };
0326 
0327 static struct snd_soc_card da830_snd_soc_card = {
0328     .name = "DA830/OMAP-L137 EVM",
0329     .owner = THIS_MODULE,
0330     .dai_link = &da830_evm_dai,
0331     .num_links = 1,
0332     .drvdata = &da830_snd_soc_card_drvdata,
0333 };
0334 
0335 static struct snd_soc_card_drvdata_davinci da850_snd_soc_card_drvdata = {
0336     .sysclk = 24576000,
0337 };
0338 
0339 static struct snd_soc_card da850_snd_soc_card = {
0340     .name = "DA850/OMAP-L138 EVM",
0341     .owner = THIS_MODULE,
0342     .dai_link = &da850_evm_dai,
0343     .num_links = 1,
0344     .drvdata = &da850_snd_soc_card_drvdata,
0345 };
0346 
0347 #if defined(CONFIG_OF)
0348 
0349 /*
0350  * The struct is used as place holder. It will be completely
0351  * filled with data from dt node.
0352  */
0353 SND_SOC_DAILINK_DEFS(evm,
0354     DAILINK_COMP_ARRAY(COMP_EMPTY()),
0355     DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "tlv320aic3x-hifi")),
0356     DAILINK_COMP_ARRAY(COMP_EMPTY()));
0357 
0358 static struct snd_soc_dai_link evm_dai_tlv320aic3x = {
0359     .name       = "TLV320AIC3X",
0360     .stream_name    = "AIC3X",
0361     .ops            = &evm_ops,
0362     .init           = evm_aic3x_init,
0363     .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
0364            SND_SOC_DAIFMT_IB_NF,
0365     SND_SOC_DAILINK_REG(evm),
0366 };
0367 
0368 static const struct of_device_id davinci_evm_dt_ids[] = {
0369     {
0370         .compatible = "ti,da830-evm-audio",
0371         .data = (void *) &evm_dai_tlv320aic3x,
0372     },
0373     { /* sentinel */ }
0374 };
0375 MODULE_DEVICE_TABLE(of, davinci_evm_dt_ids);
0376 
0377 /* davinci evm audio machine driver */
0378 static struct snd_soc_card evm_soc_card = {
0379     .owner = THIS_MODULE,
0380     .num_links = 1,
0381 };
0382 
0383 static int davinci_evm_probe(struct platform_device *pdev)
0384 {
0385     struct device_node *np = pdev->dev.of_node;
0386     const struct of_device_id *match;
0387     struct snd_soc_dai_link *dai;
0388     struct snd_soc_card_drvdata_davinci *drvdata = NULL;
0389     struct clk *mclk;
0390     int ret = 0;
0391 
0392     match = of_match_device(of_match_ptr(davinci_evm_dt_ids), &pdev->dev);
0393     if (!match) {
0394         dev_err(&pdev->dev, "Error: No device match found\n");
0395         return -ENODEV;
0396     }
0397 
0398     dai = (struct snd_soc_dai_link *) match->data;
0399 
0400     evm_soc_card.dai_link = dai;
0401 
0402     dai->codecs->of_node = of_parse_phandle(np, "ti,audio-codec", 0);
0403     if (!dai->codecs->of_node)
0404         return -EINVAL;
0405 
0406     dai->cpus->of_node = of_parse_phandle(np, "ti,mcasp-controller", 0);
0407     if (!dai->cpus->of_node)
0408         return -EINVAL;
0409 
0410     dai->platforms->of_node = dai->cpus->of_node;
0411 
0412     evm_soc_card.dev = &pdev->dev;
0413     ret = snd_soc_of_parse_card_name(&evm_soc_card, "ti,model");
0414     if (ret)
0415         return ret;
0416 
0417     mclk = devm_clk_get(&pdev->dev, "mclk");
0418     if (PTR_ERR(mclk) == -EPROBE_DEFER) {
0419         return -EPROBE_DEFER;
0420     } else if (IS_ERR(mclk)) {
0421         dev_dbg(&pdev->dev, "mclk not found.\n");
0422         mclk = NULL;
0423     }
0424 
0425     drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
0426     if (!drvdata)
0427         return -ENOMEM;
0428 
0429     drvdata->mclk = mclk;
0430 
0431     ret = of_property_read_u32(np, "ti,codec-clock-rate", &drvdata->sysclk);
0432 
0433     if (ret < 0) {
0434         if (!drvdata->mclk) {
0435             dev_err(&pdev->dev,
0436                 "No clock or clock rate defined.\n");
0437             return -EINVAL;
0438         }
0439         drvdata->sysclk = clk_get_rate(drvdata->mclk);
0440     } else if (drvdata->mclk) {
0441         unsigned int requestd_rate = drvdata->sysclk;
0442         clk_set_rate(drvdata->mclk, drvdata->sysclk);
0443         drvdata->sysclk = clk_get_rate(drvdata->mclk);
0444         if (drvdata->sysclk != requestd_rate)
0445             dev_warn(&pdev->dev,
0446                  "Could not get requested rate %u using %u.\n",
0447                  requestd_rate, drvdata->sysclk);
0448     }
0449 
0450     snd_soc_card_set_drvdata(&evm_soc_card, drvdata);
0451     ret = devm_snd_soc_register_card(&pdev->dev, &evm_soc_card);
0452 
0453     if (ret)
0454         dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
0455 
0456     return ret;
0457 }
0458 
0459 static struct platform_driver davinci_evm_driver = {
0460     .probe      = davinci_evm_probe,
0461     .driver     = {
0462         .name   = "davinci_evm",
0463         .pm = &snd_soc_pm_ops,
0464         .of_match_table = of_match_ptr(davinci_evm_dt_ids),
0465     },
0466 };
0467 #endif
0468 
0469 static struct platform_device *evm_snd_device;
0470 
0471 static int __init evm_init(void)
0472 {
0473     struct snd_soc_card *evm_snd_dev_data;
0474     int index;
0475     int ret;
0476 
0477     /*
0478      * If dtb is there, the devices will be created dynamically.
0479      * Only register platfrom driver structure.
0480      */
0481 #if defined(CONFIG_OF)
0482     if (of_have_populated_dt())
0483         return platform_driver_register(&davinci_evm_driver);
0484 #endif
0485 
0486     if (machine_is_davinci_evm()) {
0487         evm_snd_dev_data = &dm6446_snd_soc_card_evm;
0488         index = 0;
0489     } else if (machine_is_davinci_dm355_evm()) {
0490         evm_snd_dev_data = &dm355_snd_soc_card_evm;
0491         index = 1;
0492     } else if (machine_is_davinci_dm365_evm()) {
0493         evm_snd_dev_data = &dm365_snd_soc_card_evm;
0494         index = 0;
0495     } else if (machine_is_davinci_dm6467_evm()) {
0496         evm_snd_dev_data = &dm6467_snd_soc_card_evm;
0497         index = 0;
0498     } else if (machine_is_davinci_da830_evm()) {
0499         evm_snd_dev_data = &da830_snd_soc_card;
0500         index = 1;
0501     } else if (machine_is_davinci_da850_evm()) {
0502         evm_snd_dev_data = &da850_snd_soc_card;
0503         index = 0;
0504     } else
0505         return -EINVAL;
0506 
0507     evm_snd_device = platform_device_alloc("soc-audio", index);
0508     if (!evm_snd_device)
0509         return -ENOMEM;
0510 
0511     platform_set_drvdata(evm_snd_device, evm_snd_dev_data);
0512     ret = platform_device_add(evm_snd_device);
0513     if (ret)
0514         platform_device_put(evm_snd_device);
0515 
0516     return ret;
0517 }
0518 
0519 static void __exit evm_exit(void)
0520 {
0521 #if defined(CONFIG_OF)
0522     if (of_have_populated_dt()) {
0523         platform_driver_unregister(&davinci_evm_driver);
0524         return;
0525     }
0526 #endif
0527 
0528     platform_device_unregister(evm_snd_device);
0529 }
0530 
0531 module_init(evm_init);
0532 module_exit(evm_exit);
0533 
0534 MODULE_AUTHOR("Vladimir Barinov");
0535 MODULE_DESCRIPTION("TI DAVINCI EVM ASoC driver");
0536 MODULE_LICENSE("GPL");