linux/sound/soc/ti/davinci-evm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * ASoC driver for TI DAVINCI EVM platform
   4 *
   5 * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
   6 * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
   7 */
   8
   9#include <linux/module.h>
  10#include <linux/moduleparam.h>
  11#include <linux/timer.h>
  12#include <linux/interrupt.h>
  13#include <linux/platform_device.h>
  14#include <linux/i2c.h>
  15#include <linux/of_platform.h>
  16#include <linux/clk.h>
  17#include <sound/core.h>
  18#include <sound/pcm.h>
  19#include <sound/soc.h>
  20
  21#include <asm/dma.h>
  22#include <asm/mach-types.h>
  23
  24struct snd_soc_card_drvdata_davinci {
  25        struct clk *mclk;
  26        unsigned sysclk;
  27};
  28
  29static int evm_startup(struct snd_pcm_substream *substream)
  30{
  31        struct snd_soc_pcm_runtime *rtd = substream->private_data;
  32        struct snd_soc_card *soc_card = rtd->card;
  33        struct snd_soc_card_drvdata_davinci *drvdata =
  34                snd_soc_card_get_drvdata(soc_card);
  35
  36        if (drvdata->mclk)
  37                return clk_prepare_enable(drvdata->mclk);
  38
  39        return 0;
  40}
  41
  42static void evm_shutdown(struct snd_pcm_substream *substream)
  43{
  44        struct snd_soc_pcm_runtime *rtd = substream->private_data;
  45        struct snd_soc_card *soc_card = rtd->card;
  46        struct snd_soc_card_drvdata_davinci *drvdata =
  47                snd_soc_card_get_drvdata(soc_card);
  48
  49        if (drvdata->mclk)
  50                clk_disable_unprepare(drvdata->mclk);
  51}
  52
  53static int evm_hw_params(struct snd_pcm_substream *substream,
  54                         struct snd_pcm_hw_params *params)
  55{
  56        struct snd_soc_pcm_runtime *rtd = substream->private_data;
  57        struct snd_soc_dai *codec_dai = rtd->codec_dai;
  58        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
  59        struct snd_soc_card *soc_card = rtd->card;
  60        int ret = 0;
  61        unsigned sysclk = ((struct snd_soc_card_drvdata_davinci *)
  62                           snd_soc_card_get_drvdata(soc_card))->sysclk;
  63
  64        /* set the codec system clock */
  65        ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk, SND_SOC_CLOCK_OUT);
  66        if (ret < 0)
  67                return ret;
  68
  69        /* set the CPU system clock */
  70        ret = snd_soc_dai_set_sysclk(cpu_dai, 0, sysclk, SND_SOC_CLOCK_OUT);
  71        if (ret < 0)
  72                return ret;
  73
  74        return 0;
  75}
  76
  77static struct snd_soc_ops evm_ops = {
  78        .startup = evm_startup,
  79        .shutdown = evm_shutdown,
  80        .hw_params = evm_hw_params,
  81};
  82
  83/* davinci-evm machine dapm widgets */
  84static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
  85        SND_SOC_DAPM_HP("Headphone Jack", NULL),
  86        SND_SOC_DAPM_LINE("Line Out", NULL),
  87        SND_SOC_DAPM_MIC("Mic Jack", NULL),
  88        SND_SOC_DAPM_LINE("Line In", NULL),
  89};
  90
  91/* davinci-evm machine audio_mapnections to the codec pins */
  92static const struct snd_soc_dapm_route audio_map[] = {
  93        /* Headphone connected to HPLOUT, HPROUT */
  94        {"Headphone Jack", NULL, "HPLOUT"},
  95        {"Headphone Jack", NULL, "HPROUT"},
  96
  97        /* Line Out connected to LLOUT, RLOUT */
  98        {"Line Out", NULL, "LLOUT"},
  99        {"Line Out", NULL, "RLOUT"},
 100
 101        /* Mic connected to (MIC3L | MIC3R) */
 102        {"MIC3L", NULL, "Mic Bias"},
 103        {"MIC3R", NULL, "Mic Bias"},
 104        {"Mic Bias", NULL, "Mic Jack"},
 105
 106        /* Line In connected to (LINE1L | LINE2L), (LINE1R | LINE2R) */
 107        {"LINE1L", NULL, "Line In"},
 108        {"LINE2L", NULL, "Line In"},
 109        {"LINE1R", NULL, "Line In"},
 110        {"LINE2R", NULL, "Line In"},
 111};
 112
 113/* Logic for a aic3x as connected on a davinci-evm */
 114static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd)
 115{
 116        struct snd_soc_card *card = rtd->card;
 117        struct device_node *np = card->dev->of_node;
 118        int ret;
 119
 120        /* Add davinci-evm specific widgets */
 121        snd_soc_dapm_new_controls(&card->dapm, aic3x_dapm_widgets,
 122                                  ARRAY_SIZE(aic3x_dapm_widgets));
 123
 124        if (np) {
 125                ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing");
 126                if (ret)
 127                        return ret;
 128        } else {
 129                /* Set up davinci-evm specific audio path audio_map */
 130                snd_soc_dapm_add_routes(&card->dapm, audio_map,
 131                                        ARRAY_SIZE(audio_map));
 132        }
 133
 134        /* not connected */
 135        snd_soc_dapm_nc_pin(&card->dapm, "MONO_LOUT");
 136        snd_soc_dapm_nc_pin(&card->dapm, "HPLCOM");
 137        snd_soc_dapm_nc_pin(&card->dapm, "HPRCOM");
 138
 139        return 0;
 140}
 141
 142/* davinci-evm digital audio interface glue - connects codec <--> CPU */
 143static struct snd_soc_dai_link dm6446_evm_dai = {
 144        .name = "TLV320AIC3X",
 145        .stream_name = "AIC3X",
 146        .cpu_dai_name = "davinci-mcbsp",
 147        .codec_dai_name = "tlv320aic3x-hifi",
 148        .codec_name = "tlv320aic3x-codec.1-001b",
 149        .platform_name = "davinci-mcbsp",
 150        .init = evm_aic3x_init,
 151        .ops = &evm_ops,
 152        .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
 153                   SND_SOC_DAIFMT_IB_NF,
 154};
 155
 156static struct snd_soc_dai_link dm355_evm_dai = {
 157        .name = "TLV320AIC3X",
 158        .stream_name = "AIC3X",
 159        .cpu_dai_name = "davinci-mcbsp.1",
 160        .codec_dai_name = "tlv320aic3x-hifi",
 161        .codec_name = "tlv320aic3x-codec.1-001b",
 162        .platform_name = "davinci-mcbsp.1",
 163        .init = evm_aic3x_init,
 164        .ops = &evm_ops,
 165        .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
 166                   SND_SOC_DAIFMT_IB_NF,
 167};
 168
 169static struct snd_soc_dai_link dm365_evm_dai = {
 170#ifdef CONFIG_SND_SOC_DM365_AIC3X_CODEC
 171        .name = "TLV320AIC3X",
 172        .stream_name = "AIC3X",
 173        .cpu_dai_name = "davinci-mcbsp",
 174        .codec_dai_name = "tlv320aic3x-hifi",
 175        .codec_name = "tlv320aic3x-codec.1-0018",
 176        .platform_name = "davinci-mcbsp",
 177        .init = evm_aic3x_init,
 178        .ops = &evm_ops,
 179        .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
 180                   SND_SOC_DAIFMT_IB_NF,
 181#elif defined(CONFIG_SND_SOC_DM365_VOICE_CODEC)
 182        .name = "Voice Codec - CQ93VC",
 183        .stream_name = "CQ93",
 184        .cpu_dai_name = "davinci-vcif",
 185        .codec_dai_name = "cq93vc-hifi",
 186        .codec_name = "cq93vc-codec",
 187        .platform_name = "davinci-vcif",
 188#endif
 189};
 190
 191static struct snd_soc_dai_link dm6467_evm_dai[] = {
 192        {
 193                .name = "TLV320AIC3X",
 194                .stream_name = "AIC3X",
 195                .cpu_dai_name= "davinci-mcasp.0",
 196                .codec_dai_name = "tlv320aic3x-hifi",
 197                .platform_name = "davinci-mcasp.0",
 198                .codec_name = "tlv320aic3x-codec.0-001a",
 199                .init = evm_aic3x_init,
 200                .ops = &evm_ops,
 201                .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
 202                           SND_SOC_DAIFMT_IB_NF,
 203        },
 204        {
 205                .name = "McASP",
 206                .stream_name = "spdif",
 207                .cpu_dai_name= "davinci-mcasp.1",
 208                .codec_dai_name = "dit-hifi",
 209                .codec_name = "spdif_dit",
 210                .platform_name = "davinci-mcasp.1",
 211                .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
 212                           SND_SOC_DAIFMT_IB_NF,
 213        },
 214};
 215
 216static struct snd_soc_dai_link da830_evm_dai = {
 217        .name = "TLV320AIC3X",
 218        .stream_name = "AIC3X",
 219        .cpu_dai_name = "davinci-mcasp.1",
 220        .codec_dai_name = "tlv320aic3x-hifi",
 221        .codec_name = "tlv320aic3x-codec.1-0018",
 222        .platform_name = "davinci-mcasp.1",
 223        .init = evm_aic3x_init,
 224        .ops = &evm_ops,
 225        .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
 226                   SND_SOC_DAIFMT_IB_NF,
 227};
 228
 229static struct snd_soc_dai_link da850_evm_dai = {
 230        .name = "TLV320AIC3X",
 231        .stream_name = "AIC3X",
 232        .cpu_dai_name= "davinci-mcasp.0",
 233        .codec_dai_name = "tlv320aic3x-hifi",
 234        .codec_name = "tlv320aic3x-codec.1-0018",
 235        .platform_name = "davinci-mcasp.0",
 236        .init = evm_aic3x_init,
 237        .ops = &evm_ops,
 238        .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
 239                   SND_SOC_DAIFMT_IB_NF,
 240};
 241
 242/* davinci dm6446 evm audio machine driver */
 243/*
 244 * ASP0 in DM6446 EVM is clocked by U55, as configured by
 245 * board-dm644x-evm.c using GPIOs from U18.  There are six
 246 * options; here we "know" we use a 48 KHz sample rate.
 247 */
 248static struct snd_soc_card_drvdata_davinci dm6446_snd_soc_card_drvdata = {
 249        .sysclk = 12288000,
 250};
 251
 252static struct snd_soc_card dm6446_snd_soc_card_evm = {
 253        .name = "DaVinci DM6446 EVM",
 254        .owner = THIS_MODULE,
 255        .dai_link = &dm6446_evm_dai,
 256        .num_links = 1,
 257        .drvdata = &dm6446_snd_soc_card_drvdata,
 258};
 259
 260/* davinci dm355 evm audio machine driver */
 261/* ASP1 on DM355 EVM is clocked by an external oscillator */
 262static struct snd_soc_card_drvdata_davinci dm355_snd_soc_card_drvdata = {
 263        .sysclk = 27000000,
 264};
 265
 266static struct snd_soc_card dm355_snd_soc_card_evm = {
 267        .name = "DaVinci DM355 EVM",
 268        .owner = THIS_MODULE,
 269        .dai_link = &dm355_evm_dai,
 270        .num_links = 1,
 271        .drvdata = &dm355_snd_soc_card_drvdata,
 272};
 273
 274/* davinci dm365 evm audio machine driver */
 275static struct snd_soc_card_drvdata_davinci dm365_snd_soc_card_drvdata = {
 276        .sysclk = 27000000,
 277};
 278
 279static struct snd_soc_card dm365_snd_soc_card_evm = {
 280        .name = "DaVinci DM365 EVM",
 281        .owner = THIS_MODULE,
 282        .dai_link = &dm365_evm_dai,
 283        .num_links = 1,
 284        .drvdata = &dm365_snd_soc_card_drvdata,
 285};
 286
 287/* davinci dm6467 evm audio machine driver */
 288static struct snd_soc_card_drvdata_davinci dm6467_snd_soc_card_drvdata = {
 289        .sysclk = 27000000,
 290};
 291
 292static struct snd_soc_card dm6467_snd_soc_card_evm = {
 293        .name = "DaVinci DM6467 EVM",
 294        .owner = THIS_MODULE,
 295        .dai_link = dm6467_evm_dai,
 296        .num_links = ARRAY_SIZE(dm6467_evm_dai),
 297        .drvdata = &dm6467_snd_soc_card_drvdata,
 298};
 299
 300static struct snd_soc_card_drvdata_davinci da830_snd_soc_card_drvdata = {
 301        .sysclk = 24576000,
 302};
 303
 304static struct snd_soc_card da830_snd_soc_card = {
 305        .name = "DA830/OMAP-L137 EVM",
 306        .owner = THIS_MODULE,
 307        .dai_link = &da830_evm_dai,
 308        .num_links = 1,
 309        .drvdata = &da830_snd_soc_card_drvdata,
 310};
 311
 312static struct snd_soc_card_drvdata_davinci da850_snd_soc_card_drvdata = {
 313        .sysclk = 24576000,
 314};
 315
 316static struct snd_soc_card da850_snd_soc_card = {
 317        .name = "DA850/OMAP-L138 EVM",
 318        .owner = THIS_MODULE,
 319        .dai_link = &da850_evm_dai,
 320        .num_links = 1,
 321        .drvdata = &da850_snd_soc_card_drvdata,
 322};
 323
 324#if defined(CONFIG_OF)
 325
 326/*
 327 * The struct is used as place holder. It will be completely
 328 * filled with data from dt node.
 329 */
 330static struct snd_soc_dai_link evm_dai_tlv320aic3x = {
 331        .name           = "TLV320AIC3X",
 332        .stream_name    = "AIC3X",
 333        .codec_dai_name = "tlv320aic3x-hifi",
 334        .ops            = &evm_ops,
 335        .init           = evm_aic3x_init,
 336        .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
 337                   SND_SOC_DAIFMT_IB_NF,
 338};
 339
 340static const struct of_device_id davinci_evm_dt_ids[] = {
 341        {
 342                .compatible = "ti,da830-evm-audio",
 343                .data = (void *) &evm_dai_tlv320aic3x,
 344        },
 345        { /* sentinel */ }
 346};
 347MODULE_DEVICE_TABLE(of, davinci_evm_dt_ids);
 348
 349/* davinci evm audio machine driver */
 350static struct snd_soc_card evm_soc_card = {
 351        .owner = THIS_MODULE,
 352        .num_links = 1,
 353};
 354
 355static int davinci_evm_probe(struct platform_device *pdev)
 356{
 357        struct device_node *np = pdev->dev.of_node;
 358        const struct of_device_id *match;
 359        struct snd_soc_dai_link *dai;
 360        struct snd_soc_card_drvdata_davinci *drvdata = NULL;
 361        struct clk *mclk;
 362        int ret = 0;
 363
 364        match = of_match_device(of_match_ptr(davinci_evm_dt_ids), &pdev->dev);
 365        if (!match) {
 366                dev_err(&pdev->dev, "Error: No device match found\n");
 367                return -ENODEV;
 368        }
 369
 370        dai = (struct snd_soc_dai_link *) match->data;
 371
 372        evm_soc_card.dai_link = dai;
 373
 374        dai->codec_of_node = of_parse_phandle(np, "ti,audio-codec", 0);
 375        if (!dai->codec_of_node)
 376                return -EINVAL;
 377
 378        dai->cpu_of_node = of_parse_phandle(np, "ti,mcasp-controller", 0);
 379        if (!dai->cpu_of_node)
 380                return -EINVAL;
 381
 382        dai->platform_of_node = dai->cpu_of_node;
 383
 384        evm_soc_card.dev = &pdev->dev;
 385        ret = snd_soc_of_parse_card_name(&evm_soc_card, "ti,model");
 386        if (ret)
 387                return ret;
 388
 389        mclk = devm_clk_get(&pdev->dev, "mclk");
 390        if (PTR_ERR(mclk) == -EPROBE_DEFER) {
 391                return -EPROBE_DEFER;
 392        } else if (IS_ERR(mclk)) {
 393                dev_dbg(&pdev->dev, "mclk not found.\n");
 394                mclk = NULL;
 395        }
 396
 397        drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
 398        if (!drvdata)
 399                return -ENOMEM;
 400
 401        drvdata->mclk = mclk;
 402
 403        ret = of_property_read_u32(np, "ti,codec-clock-rate", &drvdata->sysclk);
 404
 405        if (ret < 0) {
 406                if (!drvdata->mclk) {
 407                        dev_err(&pdev->dev,
 408                                "No clock or clock rate defined.\n");
 409                        return -EINVAL;
 410                }
 411                drvdata->sysclk = clk_get_rate(drvdata->mclk);
 412        } else if (drvdata->mclk) {
 413                unsigned int requestd_rate = drvdata->sysclk;
 414                clk_set_rate(drvdata->mclk, drvdata->sysclk);
 415                drvdata->sysclk = clk_get_rate(drvdata->mclk);
 416                if (drvdata->sysclk != requestd_rate)
 417                        dev_warn(&pdev->dev,
 418                                 "Could not get requested rate %u using %u.\n",
 419                                 requestd_rate, drvdata->sysclk);
 420        }
 421
 422        snd_soc_card_set_drvdata(&evm_soc_card, drvdata);
 423        ret = devm_snd_soc_register_card(&pdev->dev, &evm_soc_card);
 424
 425        if (ret)
 426                dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
 427
 428        return ret;
 429}
 430
 431static struct platform_driver davinci_evm_driver = {
 432        .probe          = davinci_evm_probe,
 433        .driver         = {
 434                .name   = "davinci_evm",
 435                .pm     = &snd_soc_pm_ops,
 436                .of_match_table = of_match_ptr(davinci_evm_dt_ids),
 437        },
 438};
 439#endif
 440
 441static struct platform_device *evm_snd_device;
 442
 443static int __init evm_init(void)
 444{
 445        struct snd_soc_card *evm_snd_dev_data;
 446        int index;
 447        int ret;
 448
 449        /*
 450         * If dtb is there, the devices will be created dynamically.
 451         * Only register platfrom driver structure.
 452         */
 453#if defined(CONFIG_OF)
 454        if (of_have_populated_dt())
 455                return platform_driver_register(&davinci_evm_driver);
 456#endif
 457
 458        if (machine_is_davinci_evm()) {
 459                evm_snd_dev_data = &dm6446_snd_soc_card_evm;
 460                index = 0;
 461        } else if (machine_is_davinci_dm355_evm()) {
 462                evm_snd_dev_data = &dm355_snd_soc_card_evm;
 463                index = 1;
 464        } else if (machine_is_davinci_dm365_evm()) {
 465                evm_snd_dev_data = &dm365_snd_soc_card_evm;
 466                index = 0;
 467        } else if (machine_is_davinci_dm6467_evm()) {
 468                evm_snd_dev_data = &dm6467_snd_soc_card_evm;
 469                index = 0;
 470        } else if (machine_is_davinci_da830_evm()) {
 471                evm_snd_dev_data = &da830_snd_soc_card;
 472                index = 1;
 473        } else if (machine_is_davinci_da850_evm()) {
 474                evm_snd_dev_data = &da850_snd_soc_card;
 475                index = 0;
 476        } else
 477                return -EINVAL;
 478
 479        evm_snd_device = platform_device_alloc("soc-audio", index);
 480        if (!evm_snd_device)
 481                return -ENOMEM;
 482
 483        platform_set_drvdata(evm_snd_device, evm_snd_dev_data);
 484        ret = platform_device_add(evm_snd_device);
 485        if (ret)
 486                platform_device_put(evm_snd_device);
 487
 488        return ret;
 489}
 490
 491static void __exit evm_exit(void)
 492{
 493#if defined(CONFIG_OF)
 494        if (of_have_populated_dt()) {
 495                platform_driver_unregister(&davinci_evm_driver);
 496                return;
 497        }
 498#endif
 499
 500        platform_device_unregister(evm_snd_device);
 501}
 502
 503module_init(evm_init);
 504module_exit(evm_exit);
 505
 506MODULE_AUTHOR("Vladimir Barinov");
 507MODULE_DESCRIPTION("TI DAVINCI EVM ASoC driver");
 508MODULE_LICENSE("GPL");
 509