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 */
 143SND_SOC_DAILINK_DEFS(dm6446,
 144        DAILINK_COMP_ARRAY(COMP_CPU("davinci-mcbsp")),
 145        DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x-codec.1-001b",
 146                                      "tlv320aic3x-hifi")),
 147        DAILINK_COMP_ARRAY(COMP_PLATFORM("davinci-mcbsp")));
 148
 149static struct snd_soc_dai_link dm6446_evm_dai = {
 150        .name = "TLV320AIC3X",
 151        .stream_name = "AIC3X",
 152        .init = evm_aic3x_init,
 153        .ops = &evm_ops,
 154        .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
 155                   SND_SOC_DAIFMT_IB_NF,
 156        SND_SOC_DAILINK_REG(dm6446),
 157};
 158
 159SND_SOC_DAILINK_DEFS(dm355,
 160        DAILINK_COMP_ARRAY(COMP_CPU("davinci-mcbsp.1")),
 161        DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x-codec.1-001b",
 162                                      "tlv320aic3x-hifi")),
 163        DAILINK_COMP_ARRAY(COMP_PLATFORM("davinci-mcbsp.1")));
 164
 165static struct snd_soc_dai_link dm355_evm_dai = {
 166        .name = "TLV320AIC3X",
 167        .stream_name = "AIC3X",
 168        .init = evm_aic3x_init,
 169        .ops = &evm_ops,
 170        .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
 171                   SND_SOC_DAIFMT_IB_NF,
 172        SND_SOC_DAILINK_REG(dm355),
 173};
 174
 175#ifdef CONFIG_SND_SOC_DM365_AIC3X_CODEC
 176SND_SOC_DAILINK_DEFS(dm365,
 177        DAILINK_COMP_ARRAY(COMP_CPU("davinci-mcbsp")),
 178        DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x-codec.1-0018",
 179                                      "tlv320aic3x-hifi")),
 180        DAILINK_COMP_ARRAY(COMP_PLATFORM("davinci-mcbsp")));
 181#elif defined(CONFIG_SND_SOC_DM365_VOICE_CODEC)
 182SND_SOC_DAILINK_DEFS(dm365,
 183        DAILINK_COMP_ARRAY(COMP_CPU("davinci-vcif")),
 184        DAILINK_COMP_ARRAY(COMP_CODEC("cq93vc-codec", "cq93vc-hifi")),
 185        DAILINK_COMP_ARRAY(COMP_PLATFORM("davinci-vcif")));
 186#endif
 187
 188static struct snd_soc_dai_link dm365_evm_dai = {
 189#ifdef CONFIG_SND_SOC_DM365_AIC3X_CODEC
 190        .name = "TLV320AIC3X",
 191        .stream_name = "AIC3X",
 192        .init = evm_aic3x_init,
 193        .ops = &evm_ops,
 194        .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
 195                   SND_SOC_DAIFMT_IB_NF,
 196        SND_SOC_DAILINK_REG(dm365),
 197#elif defined(CONFIG_SND_SOC_DM365_VOICE_CODEC)
 198        .name = "Voice Codec - CQ93VC",
 199        .stream_name = "CQ93",
 200        SND_SOC_DAILINK_REG(dm365),
 201#endif
 202};
 203
 204SND_SOC_DAILINK_DEFS(dm6467_aic3x,
 205        DAILINK_COMP_ARRAY(COMP_CPU("davinci-mcasp.0")),
 206        DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x-codec.0-001a",
 207                                      "tlv320aic3x-hifi")),
 208        DAILINK_COMP_ARRAY(COMP_PLATFORM("davinci-mcasp.0")));
 209
 210SND_SOC_DAILINK_DEFS(dm6467_spdif,
 211        DAILINK_COMP_ARRAY(COMP_CPU("davinci-mcasp.1")),
 212        DAILINK_COMP_ARRAY(COMP_CODEC("spdif_dit", "dit-hifi")),
 213        DAILINK_COMP_ARRAY(COMP_PLATFORM("davinci-mcasp.1")));
 214
 215static struct snd_soc_dai_link dm6467_evm_dai[] = {
 216        {
 217                .name = "TLV320AIC3X",
 218                .stream_name = "AIC3X",
 219                .init = evm_aic3x_init,
 220                .ops = &evm_ops,
 221                .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
 222                           SND_SOC_DAIFMT_IB_NF,
 223                SND_SOC_DAILINK_REG(dm6467_aic3x),
 224        },
 225        {
 226                .name = "McASP",
 227                .stream_name = "spdif",
 228                .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
 229                           SND_SOC_DAIFMT_IB_NF,
 230                SND_SOC_DAILINK_REG(dm6467_spdif),
 231        },
 232};
 233
 234SND_SOC_DAILINK_DEFS(da830,
 235        DAILINK_COMP_ARRAY(COMP_CPU("davinci-mcasp.1")),
 236        DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x-codec.1-0018",
 237                                      "tlv320aic3x-hifi")),
 238        DAILINK_COMP_ARRAY(COMP_PLATFORM("davinci-mcasp.1")));
 239
 240static struct snd_soc_dai_link da830_evm_dai = {
 241        .name = "TLV320AIC3X",
 242        .stream_name = "AIC3X",
 243        .init = evm_aic3x_init,
 244        .ops = &evm_ops,
 245        .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
 246                   SND_SOC_DAIFMT_IB_NF,
 247        SND_SOC_DAILINK_REG(da830),
 248};
 249
 250SND_SOC_DAILINK_DEFS(da850,
 251        DAILINK_COMP_ARRAY(COMP_CPU("davinci-mcasp.0")),
 252        DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x-codec.1-0018",
 253                                      "tlv320aic3x-hifi")),
 254        DAILINK_COMP_ARRAY(COMP_PLATFORM("davinci-mcasp.0")));
 255
 256static struct snd_soc_dai_link da850_evm_dai = {
 257        .name = "TLV320AIC3X",
 258        .stream_name = "AIC3X",
 259        .init = evm_aic3x_init,
 260        .ops = &evm_ops,
 261        .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
 262                   SND_SOC_DAIFMT_IB_NF,
 263        SND_SOC_DAILINK_REG(da850),
 264};
 265
 266/* davinci dm6446 evm audio machine driver */
 267/*
 268 * ASP0 in DM6446 EVM is clocked by U55, as configured by
 269 * board-dm644x-evm.c using GPIOs from U18.  There are six
 270 * options; here we "know" we use a 48 KHz sample rate.
 271 */
 272static struct snd_soc_card_drvdata_davinci dm6446_snd_soc_card_drvdata = {
 273        .sysclk = 12288000,
 274};
 275
 276static struct snd_soc_card dm6446_snd_soc_card_evm = {
 277        .name = "DaVinci DM6446 EVM",
 278        .owner = THIS_MODULE,
 279        .dai_link = &dm6446_evm_dai,
 280        .num_links = 1,
 281        .drvdata = &dm6446_snd_soc_card_drvdata,
 282};
 283
 284/* davinci dm355 evm audio machine driver */
 285/* ASP1 on DM355 EVM is clocked by an external oscillator */
 286static struct snd_soc_card_drvdata_davinci dm355_snd_soc_card_drvdata = {
 287        .sysclk = 27000000,
 288};
 289
 290static struct snd_soc_card dm355_snd_soc_card_evm = {
 291        .name = "DaVinci DM355 EVM",
 292        .owner = THIS_MODULE,
 293        .dai_link = &dm355_evm_dai,
 294        .num_links = 1,
 295        .drvdata = &dm355_snd_soc_card_drvdata,
 296};
 297
 298/* davinci dm365 evm audio machine driver */
 299static struct snd_soc_card_drvdata_davinci dm365_snd_soc_card_drvdata = {
 300        .sysclk = 27000000,
 301};
 302
 303static struct snd_soc_card dm365_snd_soc_card_evm = {
 304        .name = "DaVinci DM365 EVM",
 305        .owner = THIS_MODULE,
 306        .dai_link = &dm365_evm_dai,
 307        .num_links = 1,
 308        .drvdata = &dm365_snd_soc_card_drvdata,
 309};
 310
 311/* davinci dm6467 evm audio machine driver */
 312static struct snd_soc_card_drvdata_davinci dm6467_snd_soc_card_drvdata = {
 313        .sysclk = 27000000,
 314};
 315
 316static struct snd_soc_card dm6467_snd_soc_card_evm = {
 317        .name = "DaVinci DM6467 EVM",
 318        .owner = THIS_MODULE,
 319        .dai_link = dm6467_evm_dai,
 320        .num_links = ARRAY_SIZE(dm6467_evm_dai),
 321        .drvdata = &dm6467_snd_soc_card_drvdata,
 322};
 323
 324static struct snd_soc_card_drvdata_davinci da830_snd_soc_card_drvdata = {
 325        .sysclk = 24576000,
 326};
 327
 328static struct snd_soc_card da830_snd_soc_card = {
 329        .name = "DA830/OMAP-L137 EVM",
 330        .owner = THIS_MODULE,
 331        .dai_link = &da830_evm_dai,
 332        .num_links = 1,
 333        .drvdata = &da830_snd_soc_card_drvdata,
 334};
 335
 336static struct snd_soc_card_drvdata_davinci da850_snd_soc_card_drvdata = {
 337        .sysclk = 24576000,
 338};
 339
 340static struct snd_soc_card da850_snd_soc_card = {
 341        .name = "DA850/OMAP-L138 EVM",
 342        .owner = THIS_MODULE,
 343        .dai_link = &da850_evm_dai,
 344        .num_links = 1,
 345        .drvdata = &da850_snd_soc_card_drvdata,
 346};
 347
 348#if defined(CONFIG_OF)
 349
 350/*
 351 * The struct is used as place holder. It will be completely
 352 * filled with data from dt node.
 353 */
 354SND_SOC_DAILINK_DEFS(evm,
 355        DAILINK_COMP_ARRAY(COMP_EMPTY()),
 356        DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "tlv320aic3x-hifi")),
 357        DAILINK_COMP_ARRAY(COMP_EMPTY()));
 358
 359static struct snd_soc_dai_link evm_dai_tlv320aic3x = {
 360        .name           = "TLV320AIC3X",
 361        .stream_name    = "AIC3X",
 362        .ops            = &evm_ops,
 363        .init           = evm_aic3x_init,
 364        .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
 365                   SND_SOC_DAIFMT_IB_NF,
 366        SND_SOC_DAILINK_REG(evm),
 367};
 368
 369static const struct of_device_id davinci_evm_dt_ids[] = {
 370        {
 371                .compatible = "ti,da830-evm-audio",
 372                .data = (void *) &evm_dai_tlv320aic3x,
 373        },
 374        { /* sentinel */ }
 375};
 376MODULE_DEVICE_TABLE(of, davinci_evm_dt_ids);
 377
 378/* davinci evm audio machine driver */
 379static struct snd_soc_card evm_soc_card = {
 380        .owner = THIS_MODULE,
 381        .num_links = 1,
 382};
 383
 384static int davinci_evm_probe(struct platform_device *pdev)
 385{
 386        struct device_node *np = pdev->dev.of_node;
 387        const struct of_device_id *match;
 388        struct snd_soc_dai_link *dai;
 389        struct snd_soc_card_drvdata_davinci *drvdata = NULL;
 390        struct clk *mclk;
 391        int ret = 0;
 392
 393        match = of_match_device(of_match_ptr(davinci_evm_dt_ids), &pdev->dev);
 394        if (!match) {
 395                dev_err(&pdev->dev, "Error: No device match found\n");
 396                return -ENODEV;
 397        }
 398
 399        dai = (struct snd_soc_dai_link *) match->data;
 400
 401        evm_soc_card.dai_link = dai;
 402
 403        dai->codecs->of_node = of_parse_phandle(np, "ti,audio-codec", 0);
 404        if (!dai->codecs->of_node)
 405                return -EINVAL;
 406
 407        dai->cpus->of_node = of_parse_phandle(np, "ti,mcasp-controller", 0);
 408        if (!dai->cpus->of_node)
 409                return -EINVAL;
 410
 411        dai->platforms->of_node = dai->cpus->of_node;
 412
 413        evm_soc_card.dev = &pdev->dev;
 414        ret = snd_soc_of_parse_card_name(&evm_soc_card, "ti,model");
 415        if (ret)
 416                return ret;
 417
 418        mclk = devm_clk_get(&pdev->dev, "mclk");
 419        if (PTR_ERR(mclk) == -EPROBE_DEFER) {
 420                return -EPROBE_DEFER;
 421        } else if (IS_ERR(mclk)) {
 422                dev_dbg(&pdev->dev, "mclk not found.\n");
 423                mclk = NULL;
 424        }
 425
 426        drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
 427        if (!drvdata)
 428                return -ENOMEM;
 429
 430        drvdata->mclk = mclk;
 431
 432        ret = of_property_read_u32(np, "ti,codec-clock-rate", &drvdata->sysclk);
 433
 434        if (ret < 0) {
 435                if (!drvdata->mclk) {
 436                        dev_err(&pdev->dev,
 437                                "No clock or clock rate defined.\n");
 438                        return -EINVAL;
 439                }
 440                drvdata->sysclk = clk_get_rate(drvdata->mclk);
 441        } else if (drvdata->mclk) {
 442                unsigned int requestd_rate = drvdata->sysclk;
 443                clk_set_rate(drvdata->mclk, drvdata->sysclk);
 444                drvdata->sysclk = clk_get_rate(drvdata->mclk);
 445                if (drvdata->sysclk != requestd_rate)
 446                        dev_warn(&pdev->dev,
 447                                 "Could not get requested rate %u using %u.\n",
 448                                 requestd_rate, drvdata->sysclk);
 449        }
 450
 451        snd_soc_card_set_drvdata(&evm_soc_card, drvdata);
 452        ret = devm_snd_soc_register_card(&pdev->dev, &evm_soc_card);
 453
 454        if (ret)
 455                dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
 456
 457        return ret;
 458}
 459
 460static struct platform_driver davinci_evm_driver = {
 461        .probe          = davinci_evm_probe,
 462        .driver         = {
 463                .name   = "davinci_evm",
 464                .pm     = &snd_soc_pm_ops,
 465                .of_match_table = of_match_ptr(davinci_evm_dt_ids),
 466        },
 467};
 468#endif
 469
 470static struct platform_device *evm_snd_device;
 471
 472static int __init evm_init(void)
 473{
 474        struct snd_soc_card *evm_snd_dev_data;
 475        int index;
 476        int ret;
 477
 478        /*
 479         * If dtb is there, the devices will be created dynamically.
 480         * Only register platfrom driver structure.
 481         */
 482#if defined(CONFIG_OF)
 483        if (of_have_populated_dt())
 484                return platform_driver_register(&davinci_evm_driver);
 485#endif
 486
 487        if (machine_is_davinci_evm()) {
 488                evm_snd_dev_data = &dm6446_snd_soc_card_evm;
 489                index = 0;
 490        } else if (machine_is_davinci_dm355_evm()) {
 491                evm_snd_dev_data = &dm355_snd_soc_card_evm;
 492                index = 1;
 493        } else if (machine_is_davinci_dm365_evm()) {
 494                evm_snd_dev_data = &dm365_snd_soc_card_evm;
 495                index = 0;
 496        } else if (machine_is_davinci_dm6467_evm()) {
 497                evm_snd_dev_data = &dm6467_snd_soc_card_evm;
 498                index = 0;
 499        } else if (machine_is_davinci_da830_evm()) {
 500                evm_snd_dev_data = &da830_snd_soc_card;
 501                index = 1;
 502        } else if (machine_is_davinci_da850_evm()) {
 503                evm_snd_dev_data = &da850_snd_soc_card;
 504                index = 0;
 505        } else
 506                return -EINVAL;
 507
 508        evm_snd_device = platform_device_alloc("soc-audio", index);
 509        if (!evm_snd_device)
 510                return -ENOMEM;
 511
 512        platform_set_drvdata(evm_snd_device, evm_snd_dev_data);
 513        ret = platform_device_add(evm_snd_device);
 514        if (ret)
 515                platform_device_put(evm_snd_device);
 516
 517        return ret;
 518}
 519
 520static void __exit evm_exit(void)
 521{
 522#if defined(CONFIG_OF)
 523        if (of_have_populated_dt()) {
 524                platform_driver_unregister(&davinci_evm_driver);
 525                return;
 526        }
 527#endif
 528
 529        platform_device_unregister(evm_snd_device);
 530}
 531
 532module_init(evm_init);
 533module_exit(evm_exit);
 534
 535MODULE_AUTHOR("Vladimir Barinov");
 536MODULE_DESCRIPTION("TI DAVINCI EVM ASoC driver");
 537MODULE_LICENSE("GPL");
 538