linux/sound/soc/fsl/fsl-asoc-card.c
<<
>>
Prefs
   1/*
   2 * Freescale Generic ASoC Sound Card driver with ASRC
   3 *
   4 * Copyright (C) 2014 Freescale Semiconductor, Inc.
   5 *
   6 * Author: Nicolin Chen <nicoleotsuka@gmail.com>
   7 *
   8 * This file is licensed under the terms of the GNU General Public License
   9 * version 2. This program is licensed "as is" without any warranty of any
  10 * kind, whether express or implied.
  11 */
  12
  13#include <linux/clk.h>
  14#include <linux/i2c.h>
  15#include <linux/module.h>
  16#include <linux/of_platform.h>
  17#if IS_ENABLED(CONFIG_SND_AC97_CODEC)
  18#include <sound/ac97_codec.h>
  19#endif
  20#include <sound/pcm_params.h>
  21#include <sound/soc.h>
  22
  23#include "fsl_esai.h"
  24#include "fsl_sai.h"
  25#include "imx-audmux.h"
  26
  27#include "../codecs/sgtl5000.h"
  28#include "../codecs/wm8962.h"
  29#include "../codecs/wm8960.h"
  30
  31#define RX 0
  32#define TX 1
  33
  34/* Default DAI format without Master and Slave flag */
  35#define DAI_FMT_BASE (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF)
  36
  37/**
  38 * CODEC private data
  39 *
  40 * @mclk_freq: Clock rate of MCLK
  41 * @mclk_id: MCLK (or main clock) id for set_sysclk()
  42 * @fll_id: FLL (or secordary clock) id for set_sysclk()
  43 * @pll_id: PLL id for set_pll()
  44 */
  45struct codec_priv {
  46        unsigned long mclk_freq;
  47        u32 mclk_id;
  48        u32 fll_id;
  49        u32 pll_id;
  50};
  51
  52/**
  53 * CPU private data
  54 *
  55 * @sysclk_freq[2]: SYSCLK rates for set_sysclk()
  56 * @sysclk_dir[2]: SYSCLK directions for set_sysclk()
  57 * @sysclk_id[2]: SYSCLK ids for set_sysclk()
  58 * @slot_width: Slot width of each frame
  59 *
  60 * Note: [1] for tx and [0] for rx
  61 */
  62struct cpu_priv {
  63        unsigned long sysclk_freq[2];
  64        u32 sysclk_dir[2];
  65        u32 sysclk_id[2];
  66        u32 slot_width;
  67};
  68
  69/**
  70 * Freescale Generic ASOC card private data
  71 *
  72 * @dai_link[3]: DAI link structure including normal one and DPCM link
  73 * @pdev: platform device pointer
  74 * @codec_priv: CODEC private data
  75 * @cpu_priv: CPU private data
  76 * @card: ASoC card structure
  77 * @sample_rate: Current sample rate
  78 * @sample_format: Current sample format
  79 * @asrc_rate: ASRC sample rate used by Back-Ends
  80 * @asrc_format: ASRC sample format used by Back-Ends
  81 * @dai_fmt: DAI format between CPU and CODEC
  82 * @name: Card name
  83 */
  84
  85struct fsl_asoc_card_priv {
  86        struct snd_soc_dai_link dai_link[3];
  87        struct platform_device *pdev;
  88        struct codec_priv codec_priv;
  89        struct cpu_priv cpu_priv;
  90        struct snd_soc_card card;
  91        u32 sample_rate;
  92        u32 sample_format;
  93        u32 asrc_rate;
  94        u32 asrc_format;
  95        u32 dai_fmt;
  96        char name[32];
  97};
  98
  99/**
 100 * This dapm route map exsits for DPCM link only.
 101 * The other routes shall go through Device Tree.
 102 */
 103static const struct snd_soc_dapm_route audio_map[] = {
 104        {"CPU-Playback",  NULL, "ASRC-Playback"},
 105        {"Playback",  NULL, "CPU-Playback"},
 106        {"ASRC-Capture",  NULL, "CPU-Capture"},
 107        {"CPU-Capture",  NULL, "Capture"},
 108};
 109
 110/* Add all possible widgets into here without being redundant */
 111static const struct snd_soc_dapm_widget fsl_asoc_card_dapm_widgets[] = {
 112        SND_SOC_DAPM_LINE("Line Out Jack", NULL),
 113        SND_SOC_DAPM_LINE("Line In Jack", NULL),
 114        SND_SOC_DAPM_HP("Headphone Jack", NULL),
 115        SND_SOC_DAPM_SPK("Ext Spk", NULL),
 116        SND_SOC_DAPM_MIC("Mic Jack", NULL),
 117        SND_SOC_DAPM_MIC("AMIC", NULL),
 118        SND_SOC_DAPM_MIC("DMIC", NULL),
 119};
 120
 121static bool fsl_asoc_card_is_ac97(struct fsl_asoc_card_priv *priv)
 122{
 123        return priv->dai_fmt == SND_SOC_DAIFMT_AC97;
 124}
 125
 126static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
 127                                   struct snd_pcm_hw_params *params)
 128{
 129        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 130        struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
 131        bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
 132        struct cpu_priv *cpu_priv = &priv->cpu_priv;
 133        struct device *dev = rtd->card->dev;
 134        int ret;
 135
 136        priv->sample_rate = params_rate(params);
 137        priv->sample_format = params_format(params);
 138
 139        /*
 140         * If codec-dai is DAI Master and all configurations are already in the
 141         * set_bias_level(), bypass the remaining settings in hw_params().
 142         * Note: (dai_fmt & CBM_CFM) includes CBM_CFM and CBM_CFS.
 143         */
 144        if ((priv->card.set_bias_level &&
 145             priv->dai_fmt & SND_SOC_DAIFMT_CBM_CFM) ||
 146            fsl_asoc_card_is_ac97(priv))
 147                return 0;
 148
 149        /* Specific configurations of DAIs starts from here */
 150        ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, cpu_priv->sysclk_id[tx],
 151                                     cpu_priv->sysclk_freq[tx],
 152                                     cpu_priv->sysclk_dir[tx]);
 153        if (ret) {
 154                dev_err(dev, "failed to set sysclk for cpu dai\n");
 155                return ret;
 156        }
 157
 158        if (cpu_priv->slot_width) {
 159                ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2,
 160                                               cpu_priv->slot_width);
 161                if (ret) {
 162                        dev_err(dev, "failed to set TDM slot for cpu dai\n");
 163                        return ret;
 164                }
 165        }
 166
 167        return 0;
 168}
 169
 170static struct snd_soc_ops fsl_asoc_card_ops = {
 171        .hw_params = fsl_asoc_card_hw_params,
 172};
 173
 174static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 175                              struct snd_pcm_hw_params *params)
 176{
 177        struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
 178        struct snd_interval *rate;
 179        struct snd_mask *mask;
 180
 181        rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
 182        rate->max = rate->min = priv->asrc_rate;
 183
 184        mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
 185        snd_mask_none(mask);
 186        snd_mask_set(mask, priv->asrc_format);
 187
 188        return 0;
 189}
 190
 191static struct snd_soc_dai_link fsl_asoc_card_dai[] = {
 192        /* Default ASoC DAI Link*/
 193        {
 194                .name = "HiFi",
 195                .stream_name = "HiFi",
 196                .ops = &fsl_asoc_card_ops,
 197        },
 198        /* DPCM Link between Front-End and Back-End (Optional) */
 199        {
 200                .name = "HiFi-ASRC-FE",
 201                .stream_name = "HiFi-ASRC-FE",
 202                .codec_name = "snd-soc-dummy",
 203                .codec_dai_name = "snd-soc-dummy-dai",
 204                .dpcm_playback = 1,
 205                .dpcm_capture = 1,
 206                .dynamic = 1,
 207        },
 208        {
 209                .name = "HiFi-ASRC-BE",
 210                .stream_name = "HiFi-ASRC-BE",
 211                .platform_name = "snd-soc-dummy",
 212                .be_hw_params_fixup = be_hw_params_fixup,
 213                .ops = &fsl_asoc_card_ops,
 214                .dpcm_playback = 1,
 215                .dpcm_capture = 1,
 216                .no_pcm = 1,
 217        },
 218};
 219
 220static int fsl_asoc_card_set_bias_level(struct snd_soc_card *card,
 221                                        struct snd_soc_dapm_context *dapm,
 222                                        enum snd_soc_bias_level level)
 223{
 224        struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card);
 225        struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
 226        struct codec_priv *codec_priv = &priv->codec_priv;
 227        struct device *dev = card->dev;
 228        unsigned int pll_out;
 229        int ret;
 230
 231        if (dapm->dev != codec_dai->dev)
 232                return 0;
 233
 234        switch (level) {
 235        case SND_SOC_BIAS_PREPARE:
 236                if (dapm->bias_level != SND_SOC_BIAS_STANDBY)
 237                        break;
 238
 239                if (priv->sample_format == SNDRV_PCM_FORMAT_S24_LE)
 240                        pll_out = priv->sample_rate * 384;
 241                else
 242                        pll_out = priv->sample_rate * 256;
 243
 244                ret = snd_soc_dai_set_pll(codec_dai, codec_priv->pll_id,
 245                                          codec_priv->mclk_id,
 246                                          codec_priv->mclk_freq, pll_out);
 247                if (ret) {
 248                        dev_err(dev, "failed to start FLL: %d\n", ret);
 249                        return ret;
 250                }
 251
 252                ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->fll_id,
 253                                             pll_out, SND_SOC_CLOCK_IN);
 254                if (ret) {
 255                        dev_err(dev, "failed to set SYSCLK: %d\n", ret);
 256                        return ret;
 257                }
 258                break;
 259
 260        case SND_SOC_BIAS_STANDBY:
 261                if (dapm->bias_level != SND_SOC_BIAS_PREPARE)
 262                        break;
 263
 264                ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id,
 265                                             codec_priv->mclk_freq,
 266                                             SND_SOC_CLOCK_IN);
 267                if (ret) {
 268                        dev_err(dev, "failed to switch away from FLL: %d\n", ret);
 269                        return ret;
 270                }
 271
 272                ret = snd_soc_dai_set_pll(codec_dai, codec_priv->pll_id, 0, 0, 0);
 273                if (ret) {
 274                        dev_err(dev, "failed to stop FLL: %d\n", ret);
 275                        return ret;
 276                }
 277                break;
 278
 279        default:
 280                break;
 281        }
 282
 283        return 0;
 284}
 285
 286static int fsl_asoc_card_audmux_init(struct device_node *np,
 287                                     struct fsl_asoc_card_priv *priv)
 288{
 289        struct device *dev = &priv->pdev->dev;
 290        u32 int_ptcr = 0, ext_ptcr = 0;
 291        int int_port, ext_port;
 292        int ret;
 293
 294        ret = of_property_read_u32(np, "mux-int-port", &int_port);
 295        if (ret) {
 296                dev_err(dev, "mux-int-port missing or invalid\n");
 297                return ret;
 298        }
 299        ret = of_property_read_u32(np, "mux-ext-port", &ext_port);
 300        if (ret) {
 301                dev_err(dev, "mux-ext-port missing or invalid\n");
 302                return ret;
 303        }
 304
 305        /*
 306         * The port numbering in the hardware manual starts at 1, while
 307         * the AUDMUX API expects it starts at 0.
 308         */
 309        int_port--;
 310        ext_port--;
 311
 312        /*
 313         * Use asynchronous mode (6 wires) for all cases except AC97.
 314         * If only 4 wires are needed, just set SSI into
 315         * synchronous mode and enable 4 PADs in IOMUX.
 316         */
 317        switch (priv->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 318        case SND_SOC_DAIFMT_CBM_CFM:
 319                int_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | ext_port) |
 320                           IMX_AUDMUX_V2_PTCR_RCSEL(8 | ext_port) |
 321                           IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
 322                           IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
 323                           IMX_AUDMUX_V2_PTCR_RFSDIR |
 324                           IMX_AUDMUX_V2_PTCR_RCLKDIR |
 325                           IMX_AUDMUX_V2_PTCR_TFSDIR |
 326                           IMX_AUDMUX_V2_PTCR_TCLKDIR;
 327                break;
 328        case SND_SOC_DAIFMT_CBM_CFS:
 329                int_ptcr = IMX_AUDMUX_V2_PTCR_RCSEL(8 | ext_port) |
 330                           IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
 331                           IMX_AUDMUX_V2_PTCR_RCLKDIR |
 332                           IMX_AUDMUX_V2_PTCR_TCLKDIR;
 333                ext_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | int_port) |
 334                           IMX_AUDMUX_V2_PTCR_TFSEL(int_port) |
 335                           IMX_AUDMUX_V2_PTCR_RFSDIR |
 336                           IMX_AUDMUX_V2_PTCR_TFSDIR;
 337                break;
 338        case SND_SOC_DAIFMT_CBS_CFM:
 339                int_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | ext_port) |
 340                           IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
 341                           IMX_AUDMUX_V2_PTCR_RFSDIR |
 342                           IMX_AUDMUX_V2_PTCR_TFSDIR;
 343                ext_ptcr = IMX_AUDMUX_V2_PTCR_RCSEL(8 | int_port) |
 344                           IMX_AUDMUX_V2_PTCR_TCSEL(int_port) |
 345                           IMX_AUDMUX_V2_PTCR_RCLKDIR |
 346                           IMX_AUDMUX_V2_PTCR_TCLKDIR;
 347                break;
 348        case SND_SOC_DAIFMT_CBS_CFS:
 349                ext_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | int_port) |
 350                           IMX_AUDMUX_V2_PTCR_RCSEL(8 | int_port) |
 351                           IMX_AUDMUX_V2_PTCR_TFSEL(int_port) |
 352                           IMX_AUDMUX_V2_PTCR_TCSEL(int_port) |
 353                           IMX_AUDMUX_V2_PTCR_RFSDIR |
 354                           IMX_AUDMUX_V2_PTCR_RCLKDIR |
 355                           IMX_AUDMUX_V2_PTCR_TFSDIR |
 356                           IMX_AUDMUX_V2_PTCR_TCLKDIR;
 357                break;
 358        default:
 359                if (!fsl_asoc_card_is_ac97(priv))
 360                        return -EINVAL;
 361        }
 362
 363        if (fsl_asoc_card_is_ac97(priv)) {
 364                int_ptcr = IMX_AUDMUX_V2_PTCR_SYN |
 365                           IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
 366                           IMX_AUDMUX_V2_PTCR_TCLKDIR;
 367                ext_ptcr = IMX_AUDMUX_V2_PTCR_SYN |
 368                           IMX_AUDMUX_V2_PTCR_TFSEL(int_port) |
 369                           IMX_AUDMUX_V2_PTCR_TFSDIR;
 370        }
 371
 372        /* Asynchronous mode can not be set along with RCLKDIR */
 373        if (!fsl_asoc_card_is_ac97(priv)) {
 374                unsigned int pdcr =
 375                                IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port);
 376
 377                ret = imx_audmux_v2_configure_port(int_port, 0,
 378                                                   pdcr);
 379                if (ret) {
 380                        dev_err(dev, "audmux internal port setup failed\n");
 381                        return ret;
 382                }
 383        }
 384
 385        ret = imx_audmux_v2_configure_port(int_port, int_ptcr,
 386                                           IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port));
 387        if (ret) {
 388                dev_err(dev, "audmux internal port setup failed\n");
 389                return ret;
 390        }
 391
 392        if (!fsl_asoc_card_is_ac97(priv)) {
 393                unsigned int pdcr =
 394                                IMX_AUDMUX_V2_PDCR_RXDSEL(int_port);
 395
 396                ret = imx_audmux_v2_configure_port(ext_port, 0,
 397                                                   pdcr);
 398                if (ret) {
 399                        dev_err(dev, "audmux external port setup failed\n");
 400                        return ret;
 401                }
 402        }
 403
 404        ret = imx_audmux_v2_configure_port(ext_port, ext_ptcr,
 405                                           IMX_AUDMUX_V2_PDCR_RXDSEL(int_port));
 406        if (ret) {
 407                dev_err(dev, "audmux external port setup failed\n");
 408                return ret;
 409        }
 410
 411        return 0;
 412}
 413
 414static int fsl_asoc_card_late_probe(struct snd_soc_card *card)
 415{
 416        struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card);
 417        struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
 418        struct codec_priv *codec_priv = &priv->codec_priv;
 419        struct device *dev = card->dev;
 420        int ret;
 421
 422        if (fsl_asoc_card_is_ac97(priv)) {
 423#if IS_ENABLED(CONFIG_SND_AC97_CODEC)
 424                struct snd_soc_codec *codec = card->rtd[0].codec;
 425                struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
 426
 427                /*
 428                 * Use slots 3/4 for S/PDIF so SSI won't try to enable
 429                 * other slots and send some samples there
 430                 * due to SLOTREQ bits for S/PDIF received from codec
 431                 */
 432                snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS,
 433                                     AC97_EA_SPSA_SLOT_MASK, AC97_EA_SPSA_3_4);
 434#endif
 435
 436                return 0;
 437        }
 438
 439        ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id,
 440                                     codec_priv->mclk_freq, SND_SOC_CLOCK_IN);
 441        if (ret) {
 442                dev_err(dev, "failed to set sysclk in %s\n", __func__);
 443                return ret;
 444        }
 445
 446        return 0;
 447}
 448
 449static int fsl_asoc_card_probe(struct platform_device *pdev)
 450{
 451        struct device_node *cpu_np, *codec_np, *asrc_np;
 452        struct device_node *np = pdev->dev.of_node;
 453        struct platform_device *asrc_pdev = NULL;
 454        struct platform_device *cpu_pdev;
 455        struct fsl_asoc_card_priv *priv;
 456        struct i2c_client *codec_dev;
 457        const char *codec_dai_name;
 458        u32 width;
 459        int ret;
 460
 461        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 462        if (!priv)
 463                return -ENOMEM;
 464
 465        cpu_np = of_parse_phandle(np, "audio-cpu", 0);
 466        /* Give a chance to old DT binding */
 467        if (!cpu_np)
 468                cpu_np = of_parse_phandle(np, "ssi-controller", 0);
 469        if (!cpu_np) {
 470                dev_err(&pdev->dev, "CPU phandle missing or invalid\n");
 471                ret = -EINVAL;
 472                goto fail;
 473        }
 474
 475        cpu_pdev = of_find_device_by_node(cpu_np);
 476        if (!cpu_pdev) {
 477                dev_err(&pdev->dev, "failed to find CPU DAI device\n");
 478                ret = -EINVAL;
 479                goto fail;
 480        }
 481
 482        codec_np = of_parse_phandle(np, "audio-codec", 0);
 483        if (codec_np)
 484                codec_dev = of_find_i2c_device_by_node(codec_np);
 485        else
 486                codec_dev = NULL;
 487
 488        asrc_np = of_parse_phandle(np, "audio-asrc", 0);
 489        if (asrc_np)
 490                asrc_pdev = of_find_device_by_node(asrc_np);
 491
 492        /* Get the MCLK rate only, and leave it controlled by CODEC drivers */
 493        if (codec_dev) {
 494                struct clk *codec_clk = clk_get(&codec_dev->dev, NULL);
 495
 496                if (!IS_ERR(codec_clk)) {
 497                        priv->codec_priv.mclk_freq = clk_get_rate(codec_clk);
 498                        clk_put(codec_clk);
 499                }
 500        }
 501
 502        /* Default sample rate and format, will be updated in hw_params() */
 503        priv->sample_rate = 44100;
 504        priv->sample_format = SNDRV_PCM_FORMAT_S16_LE;
 505
 506        /* Assign a default DAI format, and allow each card to overwrite it */
 507        priv->dai_fmt = DAI_FMT_BASE;
 508
 509        /* Diversify the card configurations */
 510        if (of_device_is_compatible(np, "fsl,imx-audio-cs42888")) {
 511                codec_dai_name = "cs42888";
 512                priv->card.set_bias_level = NULL;
 513                priv->cpu_priv.sysclk_freq[TX] = priv->codec_priv.mclk_freq;
 514                priv->cpu_priv.sysclk_freq[RX] = priv->codec_priv.mclk_freq;
 515                priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT;
 516                priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT;
 517                priv->cpu_priv.slot_width = 32;
 518                priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
 519        } else if (of_device_is_compatible(np, "fsl,imx-audio-sgtl5000")) {
 520                codec_dai_name = "sgtl5000";
 521                priv->codec_priv.mclk_id = SGTL5000_SYSCLK;
 522                priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
 523        } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8962")) {
 524                codec_dai_name = "wm8962";
 525                priv->card.set_bias_level = fsl_asoc_card_set_bias_level;
 526                priv->codec_priv.mclk_id = WM8962_SYSCLK_MCLK;
 527                priv->codec_priv.fll_id = WM8962_SYSCLK_FLL;
 528                priv->codec_priv.pll_id = WM8962_FLL;
 529                priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
 530        } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8960")) {
 531                codec_dai_name = "wm8960-hifi";
 532                priv->card.set_bias_level = fsl_asoc_card_set_bias_level;
 533                priv->codec_priv.fll_id = WM8960_SYSCLK_AUTO;
 534                priv->codec_priv.pll_id = WM8960_SYSCLK_AUTO;
 535                priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
 536        } else if (of_device_is_compatible(np, "fsl,imx-audio-ac97")) {
 537                codec_dai_name = "ac97-hifi";
 538                priv->card.set_bias_level = NULL;
 539                priv->dai_fmt = SND_SOC_DAIFMT_AC97;
 540        } else {
 541                dev_err(&pdev->dev, "unknown Device Tree compatible\n");
 542                ret = -EINVAL;
 543                goto asrc_fail;
 544        }
 545
 546        if (!fsl_asoc_card_is_ac97(priv) && !codec_dev) {
 547                dev_err(&pdev->dev, "failed to find codec device\n");
 548                ret = -EINVAL;
 549                goto asrc_fail;
 550        }
 551
 552        /* Common settings for corresponding Freescale CPU DAI driver */
 553        if (strstr(cpu_np->name, "ssi")) {
 554                /* Only SSI needs to configure AUDMUX */
 555                ret = fsl_asoc_card_audmux_init(np, priv);
 556                if (ret) {
 557                        dev_err(&pdev->dev, "failed to init audmux\n");
 558                        goto asrc_fail;
 559                }
 560        } else if (strstr(cpu_np->name, "esai")) {
 561                priv->cpu_priv.sysclk_id[1] = ESAI_HCKT_EXTAL;
 562                priv->cpu_priv.sysclk_id[0] = ESAI_HCKR_EXTAL;
 563        } else if (strstr(cpu_np->name, "sai")) {
 564                priv->cpu_priv.sysclk_id[1] = FSL_SAI_CLK_MAST1;
 565                priv->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1;
 566        }
 567
 568        snprintf(priv->name, sizeof(priv->name), "%s-audio",
 569                 fsl_asoc_card_is_ac97(priv) ? "ac97" :
 570                 codec_dev->name);
 571
 572        /* Initialize sound card */
 573        priv->pdev = pdev;
 574        priv->card.dev = &pdev->dev;
 575        priv->card.name = priv->name;
 576        priv->card.dai_link = priv->dai_link;
 577        priv->card.dapm_routes = audio_map;
 578        priv->card.late_probe = fsl_asoc_card_late_probe;
 579        priv->card.num_dapm_routes = ARRAY_SIZE(audio_map);
 580        priv->card.dapm_widgets = fsl_asoc_card_dapm_widgets;
 581        priv->card.num_dapm_widgets = ARRAY_SIZE(fsl_asoc_card_dapm_widgets);
 582
 583        memcpy(priv->dai_link, fsl_asoc_card_dai,
 584               sizeof(struct snd_soc_dai_link) * ARRAY_SIZE(priv->dai_link));
 585
 586        ret = snd_soc_of_parse_audio_routing(&priv->card, "audio-routing");
 587        if (ret) {
 588                dev_err(&pdev->dev, "failed to parse audio-routing: %d\n", ret);
 589                goto asrc_fail;
 590        }
 591
 592        /* Normal DAI Link */
 593        priv->dai_link[0].cpu_of_node = cpu_np;
 594        priv->dai_link[0].codec_dai_name = codec_dai_name;
 595
 596        if (!fsl_asoc_card_is_ac97(priv))
 597                priv->dai_link[0].codec_of_node = codec_np;
 598        else {
 599                u32 idx;
 600
 601                ret = of_property_read_u32(cpu_np, "cell-index", &idx);
 602                if (ret) {
 603                        dev_err(&pdev->dev,
 604                                "cannot get CPU index property\n");
 605                        goto asrc_fail;
 606                }
 607
 608                priv->dai_link[0].codec_name =
 609                                devm_kasprintf(&pdev->dev, GFP_KERNEL,
 610                                               "ac97-codec.%u",
 611                                               (unsigned int)idx);
 612        }
 613
 614        priv->dai_link[0].platform_of_node = cpu_np;
 615        priv->dai_link[0].dai_fmt = priv->dai_fmt;
 616        priv->card.num_links = 1;
 617
 618        if (asrc_pdev) {
 619                /* DPCM DAI Links only if ASRC exsits */
 620                priv->dai_link[1].cpu_of_node = asrc_np;
 621                priv->dai_link[1].platform_of_node = asrc_np;
 622                priv->dai_link[2].codec_dai_name = codec_dai_name;
 623                priv->dai_link[2].codec_of_node = codec_np;
 624                priv->dai_link[2].codec_name =
 625                                priv->dai_link[0].codec_name;
 626                priv->dai_link[2].cpu_of_node = cpu_np;
 627                priv->dai_link[2].dai_fmt = priv->dai_fmt;
 628                priv->card.num_links = 3;
 629
 630                ret = of_property_read_u32(asrc_np, "fsl,asrc-rate",
 631                                           &priv->asrc_rate);
 632                if (ret) {
 633                        dev_err(&pdev->dev, "failed to get output rate\n");
 634                        ret = -EINVAL;
 635                        goto asrc_fail;
 636                }
 637
 638                ret = of_property_read_u32(asrc_np, "fsl,asrc-width", &width);
 639                if (ret) {
 640                        dev_err(&pdev->dev, "failed to get output rate\n");
 641                        ret = -EINVAL;
 642                        goto asrc_fail;
 643                }
 644
 645                if (width == 24)
 646                        priv->asrc_format = SNDRV_PCM_FORMAT_S24_LE;
 647                else
 648                        priv->asrc_format = SNDRV_PCM_FORMAT_S16_LE;
 649        }
 650
 651        /* Finish card registering */
 652        platform_set_drvdata(pdev, priv);
 653        snd_soc_card_set_drvdata(&priv->card, priv);
 654
 655        ret = devm_snd_soc_register_card(&pdev->dev, &priv->card);
 656        if (ret)
 657                dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
 658
 659asrc_fail:
 660        of_node_put(asrc_np);
 661        of_node_put(codec_np);
 662fail:
 663        of_node_put(cpu_np);
 664
 665        return ret;
 666}
 667
 668static const struct of_device_id fsl_asoc_card_dt_ids[] = {
 669        { .compatible = "fsl,imx-audio-ac97", },
 670        { .compatible = "fsl,imx-audio-cs42888", },
 671        { .compatible = "fsl,imx-audio-sgtl5000", },
 672        { .compatible = "fsl,imx-audio-wm8962", },
 673        { .compatible = "fsl,imx-audio-wm8960", },
 674        {}
 675};
 676MODULE_DEVICE_TABLE(of, fsl_asoc_card_dt_ids);
 677
 678static struct platform_driver fsl_asoc_card_driver = {
 679        .probe = fsl_asoc_card_probe,
 680        .driver = {
 681                .name = "fsl-asoc-card",
 682                .pm = &snd_soc_pm_ops,
 683                .of_match_table = fsl_asoc_card_dt_ids,
 684        },
 685};
 686module_platform_driver(fsl_asoc_card_driver);
 687
 688MODULE_DESCRIPTION("Freescale Generic ASoC Sound Card driver with ASRC");
 689MODULE_AUTHOR("Nicolin Chen <nicoleotsuka@gmail.com>");
 690MODULE_ALIAS("platform:fsl-asoc-card");
 691MODULE_LICENSE("GPL");
 692