linux/sound/soc/xilinx/xlnx_formatter_pcm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2//
   3// Xilinx ASoC audio formatter support
   4//
   5// Copyright (C) 2018 Xilinx, Inc.
   6//
   7// Author: Maruthi Srinivas Bayyavarapu <maruthis@xilinx.com>
   8
   9#include <linux/clk.h>
  10#include <linux/io.h>
  11#include <linux/module.h>
  12#include <linux/of_address.h>
  13#include <linux/of_irq.h>
  14#include <linux/sizes.h>
  15
  16#include <sound/asoundef.h>
  17#include <sound/soc.h>
  18#include <sound/pcm_params.h>
  19
  20#define DRV_NAME "xlnx_formatter_pcm"
  21
  22#define XLNX_S2MM_OFFSET        0
  23#define XLNX_MM2S_OFFSET        0x100
  24
  25#define XLNX_AUD_CORE_CONFIG    0x4
  26#define XLNX_AUD_CTRL           0x10
  27#define XLNX_AUD_STS            0x14
  28
  29#define AUD_CTRL_RESET_MASK     BIT(1)
  30#define AUD_CFG_MM2S_MASK       BIT(15)
  31#define AUD_CFG_S2MM_MASK       BIT(31)
  32
  33#define XLNX_AUD_FS_MULTIPLIER  0x18
  34#define XLNX_AUD_PERIOD_CONFIG  0x1C
  35#define XLNX_AUD_BUFF_ADDR_LSB  0x20
  36#define XLNX_AUD_BUFF_ADDR_MSB  0x24
  37#define XLNX_AUD_XFER_COUNT     0x28
  38#define XLNX_AUD_CH_STS_START   0x2C
  39#define XLNX_BYTES_PER_CH       0x44
  40
  41#define AUD_STS_IOC_IRQ_MASK    BIT(31)
  42#define AUD_STS_CH_STS_MASK     BIT(29)
  43#define AUD_CTRL_IOC_IRQ_MASK   BIT(13)
  44#define AUD_CTRL_TOUT_IRQ_MASK  BIT(14)
  45#define AUD_CTRL_DMA_EN_MASK    BIT(0)
  46
  47#define CFG_MM2S_CH_MASK        GENMASK(11, 8)
  48#define CFG_MM2S_CH_SHIFT       8
  49#define CFG_MM2S_XFER_MASK      GENMASK(14, 13)
  50#define CFG_MM2S_XFER_SHIFT     13
  51#define CFG_MM2S_PKG_MASK       BIT(12)
  52
  53#define CFG_S2MM_CH_MASK        GENMASK(27, 24)
  54#define CFG_S2MM_CH_SHIFT       24
  55#define CFG_S2MM_XFER_MASK      GENMASK(30, 29)
  56#define CFG_S2MM_XFER_SHIFT     29
  57#define CFG_S2MM_PKG_MASK       BIT(28)
  58
  59#define AUD_CTRL_DATA_WIDTH_SHIFT       16
  60#define AUD_CTRL_ACTIVE_CH_SHIFT        19
  61#define PERIOD_CFG_PERIODS_SHIFT        16
  62
  63#define PERIODS_MIN             2
  64#define PERIODS_MAX             6
  65#define PERIOD_BYTES_MIN        192
  66#define PERIOD_BYTES_MAX        (50 * 1024)
  67#define XLNX_PARAM_UNKNOWN      0
  68
  69enum bit_depth {
  70        BIT_DEPTH_8,
  71        BIT_DEPTH_16,
  72        BIT_DEPTH_20,
  73        BIT_DEPTH_24,
  74        BIT_DEPTH_32,
  75};
  76
  77struct xlnx_pcm_drv_data {
  78        void __iomem *mmio;
  79        bool s2mm_presence;
  80        bool mm2s_presence;
  81        int s2mm_irq;
  82        int mm2s_irq;
  83        struct snd_pcm_substream *play_stream;
  84        struct snd_pcm_substream *capture_stream;
  85        struct clk *axi_clk;
  86};
  87
  88/*
  89 * struct xlnx_pcm_stream_param - stream configuration
  90 * @mmio: base address offset
  91 * @interleaved: audio channels arrangement in buffer
  92 * @xfer_mode: data formatting mode during transfer
  93 * @ch_limit: Maximum channels supported
  94 * @buffer_size: stream ring buffer size
  95 */
  96struct xlnx_pcm_stream_param {
  97        void __iomem *mmio;
  98        bool interleaved;
  99        u32 xfer_mode;
 100        u32 ch_limit;
 101        u64 buffer_size;
 102};
 103
 104static const struct snd_pcm_hardware xlnx_pcm_hardware = {
 105        .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
 106                SNDRV_PCM_INFO_BATCH | SNDRV_PCM_INFO_PAUSE |
 107                SNDRV_PCM_INFO_RESUME,
 108        .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |
 109                   SNDRV_PCM_FMTBIT_S24_LE,
 110        .channels_min = 2,
 111        .channels_max = 2,
 112        .rates = SNDRV_PCM_RATE_8000_192000,
 113        .rate_min = 8000,
 114        .rate_max = 192000,
 115        .buffer_bytes_max = PERIODS_MAX * PERIOD_BYTES_MAX,
 116        .period_bytes_min = PERIOD_BYTES_MIN,
 117        .period_bytes_max = PERIOD_BYTES_MAX,
 118        .periods_min = PERIODS_MIN,
 119        .periods_max = PERIODS_MAX,
 120};
 121
 122enum {
 123        AES_TO_AES,
 124        AES_TO_PCM,
 125        PCM_TO_PCM,
 126        PCM_TO_AES
 127};
 128
 129static void xlnx_parse_aes_params(u32 chsts_reg1_val, u32 chsts_reg2_val,
 130                                  struct device *dev)
 131{
 132        u32 padded, srate, bit_depth, status[2];
 133
 134        if (chsts_reg1_val & IEC958_AES0_PROFESSIONAL) {
 135                status[0] = chsts_reg1_val & 0xff;
 136                status[1] = (chsts_reg1_val >> 16) & 0xff;
 137
 138                switch (status[0] & IEC958_AES0_PRO_FS) {
 139                case IEC958_AES0_PRO_FS_44100:
 140                        srate = 44100;
 141                        break;
 142                case IEC958_AES0_PRO_FS_48000:
 143                        srate = 48000;
 144                        break;
 145                case IEC958_AES0_PRO_FS_32000:
 146                        srate = 32000;
 147                        break;
 148                case IEC958_AES0_PRO_FS_NOTID:
 149                default:
 150                        srate = XLNX_PARAM_UNKNOWN;
 151                        break;
 152                }
 153
 154                switch (status[1] & IEC958_AES2_PRO_SBITS) {
 155                case IEC958_AES2_PRO_WORDLEN_NOTID:
 156                case IEC958_AES2_PRO_SBITS_20:
 157                        padded = 0;
 158                        break;
 159                case IEC958_AES2_PRO_SBITS_24:
 160                        padded = 4;
 161                        break;
 162                default:
 163                        bit_depth = XLNX_PARAM_UNKNOWN;
 164                        goto log_params;
 165                }
 166
 167                switch (status[1] & IEC958_AES2_PRO_WORDLEN) {
 168                case IEC958_AES2_PRO_WORDLEN_20_16:
 169                        bit_depth = 16 + padded;
 170                        break;
 171                case IEC958_AES2_PRO_WORDLEN_22_18:
 172                        bit_depth = 18 + padded;
 173                        break;
 174                case IEC958_AES2_PRO_WORDLEN_23_19:
 175                        bit_depth = 19 + padded;
 176                        break;
 177                case IEC958_AES2_PRO_WORDLEN_24_20:
 178                        bit_depth = 20 + padded;
 179                        break;
 180                case IEC958_AES2_PRO_WORDLEN_NOTID:
 181                default:
 182                        bit_depth = XLNX_PARAM_UNKNOWN;
 183                        break;
 184                }
 185
 186        } else {
 187                status[0] = (chsts_reg1_val >> 24) & 0xff;
 188                status[1] = chsts_reg2_val & 0xff;
 189
 190                switch (status[0] & IEC958_AES3_CON_FS) {
 191                case IEC958_AES3_CON_FS_44100:
 192                        srate = 44100;
 193                        break;
 194                case IEC958_AES3_CON_FS_48000:
 195                        srate = 48000;
 196                        break;
 197                case IEC958_AES3_CON_FS_32000:
 198                        srate = 32000;
 199                        break;
 200                default:
 201                        srate = XLNX_PARAM_UNKNOWN;
 202                        break;
 203                }
 204
 205                if (status[1] & IEC958_AES4_CON_MAX_WORDLEN_24)
 206                        padded = 4;
 207                else
 208                        padded = 0;
 209
 210                switch (status[1] & IEC958_AES4_CON_WORDLEN) {
 211                case IEC958_AES4_CON_WORDLEN_20_16:
 212                        bit_depth = 16 + padded;
 213                        break;
 214                case IEC958_AES4_CON_WORDLEN_22_18:
 215                        bit_depth = 18 + padded;
 216                        break;
 217                case IEC958_AES4_CON_WORDLEN_23_19:
 218                        bit_depth = 19 + padded;
 219                        break;
 220                case IEC958_AES4_CON_WORDLEN_24_20:
 221                        bit_depth = 20 + padded;
 222                        break;
 223                case IEC958_AES4_CON_WORDLEN_21_17:
 224                        bit_depth = 17 + padded;
 225                        break;
 226                case IEC958_AES4_CON_WORDLEN_NOTID:
 227                default:
 228                        bit_depth = XLNX_PARAM_UNKNOWN;
 229                        break;
 230                }
 231        }
 232
 233log_params:
 234        if (srate != XLNX_PARAM_UNKNOWN)
 235                dev_info(dev, "sample rate = %d\n", srate);
 236        else
 237                dev_info(dev, "sample rate = unknown\n");
 238
 239        if (bit_depth != XLNX_PARAM_UNKNOWN)
 240                dev_info(dev, "bit_depth = %d\n", bit_depth);
 241        else
 242                dev_info(dev, "bit_depth = unknown\n");
 243}
 244
 245static int xlnx_formatter_pcm_reset(void __iomem *mmio_base)
 246{
 247        u32 val, retries = 0;
 248
 249        val = readl(mmio_base + XLNX_AUD_CTRL);
 250        val |= AUD_CTRL_RESET_MASK;
 251        writel(val, mmio_base + XLNX_AUD_CTRL);
 252
 253        val = readl(mmio_base + XLNX_AUD_CTRL);
 254        /* Poll for maximum timeout of approximately 100ms (1 * 100)*/
 255        while ((val & AUD_CTRL_RESET_MASK) && (retries < 100)) {
 256                mdelay(1);
 257                retries++;
 258                val = readl(mmio_base + XLNX_AUD_CTRL);
 259        }
 260        if (val & AUD_CTRL_RESET_MASK)
 261                return -ENODEV;
 262
 263        return 0;
 264}
 265
 266static void xlnx_formatter_disable_irqs(void __iomem *mmio_base, int stream)
 267{
 268        u32 val;
 269
 270        val = readl(mmio_base + XLNX_AUD_CTRL);
 271        val &= ~AUD_CTRL_IOC_IRQ_MASK;
 272        if (stream == SNDRV_PCM_STREAM_CAPTURE)
 273                val &= ~AUD_CTRL_TOUT_IRQ_MASK;
 274
 275        writel(val, mmio_base + XLNX_AUD_CTRL);
 276}
 277
 278static irqreturn_t xlnx_mm2s_irq_handler(int irq, void *arg)
 279{
 280        u32 val;
 281        void __iomem *reg;
 282        struct device *dev = arg;
 283        struct xlnx_pcm_drv_data *adata = dev_get_drvdata(dev);
 284
 285        reg = adata->mmio + XLNX_MM2S_OFFSET + XLNX_AUD_STS;
 286        val = readl(reg);
 287        if (val & AUD_STS_IOC_IRQ_MASK) {
 288                writel(val & AUD_STS_IOC_IRQ_MASK, reg);
 289                if (adata->play_stream)
 290                        snd_pcm_period_elapsed(adata->play_stream);
 291                return IRQ_HANDLED;
 292        }
 293
 294        return IRQ_NONE;
 295}
 296
 297static irqreturn_t xlnx_s2mm_irq_handler(int irq, void *arg)
 298{
 299        u32 val;
 300        void __iomem *reg;
 301        struct device *dev = arg;
 302        struct xlnx_pcm_drv_data *adata = dev_get_drvdata(dev);
 303
 304        reg = adata->mmio + XLNX_S2MM_OFFSET + XLNX_AUD_STS;
 305        val = readl(reg);
 306        if (val & AUD_STS_IOC_IRQ_MASK) {
 307                writel(val & AUD_STS_IOC_IRQ_MASK, reg);
 308                if (adata->capture_stream)
 309                        snd_pcm_period_elapsed(adata->capture_stream);
 310                return IRQ_HANDLED;
 311        }
 312
 313        return IRQ_NONE;
 314}
 315
 316static int xlnx_formatter_pcm_open(struct snd_soc_component *component,
 317                                   struct snd_pcm_substream *substream)
 318{
 319        int err;
 320        u32 val, data_format_mode;
 321        u32 ch_count_mask, ch_count_shift, data_xfer_mode, data_xfer_shift;
 322        struct xlnx_pcm_stream_param *stream_data;
 323        struct snd_pcm_runtime *runtime = substream->runtime;
 324        struct xlnx_pcm_drv_data *adata = dev_get_drvdata(component->dev);
 325
 326        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
 327            !adata->mm2s_presence)
 328                return -ENODEV;
 329        else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
 330                 !adata->s2mm_presence)
 331                return -ENODEV;
 332
 333        stream_data = kzalloc(sizeof(*stream_data), GFP_KERNEL);
 334        if (!stream_data)
 335                return -ENOMEM;
 336
 337        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 338                ch_count_mask = CFG_MM2S_CH_MASK;
 339                ch_count_shift = CFG_MM2S_CH_SHIFT;
 340                data_xfer_mode = CFG_MM2S_XFER_MASK;
 341                data_xfer_shift = CFG_MM2S_XFER_SHIFT;
 342                data_format_mode = CFG_MM2S_PKG_MASK;
 343                stream_data->mmio = adata->mmio + XLNX_MM2S_OFFSET;
 344                adata->play_stream = substream;
 345
 346        } else {
 347                ch_count_mask = CFG_S2MM_CH_MASK;
 348                ch_count_shift = CFG_S2MM_CH_SHIFT;
 349                data_xfer_mode = CFG_S2MM_XFER_MASK;
 350                data_xfer_shift = CFG_S2MM_XFER_SHIFT;
 351                data_format_mode = CFG_S2MM_PKG_MASK;
 352                stream_data->mmio = adata->mmio + XLNX_S2MM_OFFSET;
 353                adata->capture_stream = substream;
 354        }
 355
 356        val = readl(adata->mmio + XLNX_AUD_CORE_CONFIG);
 357
 358        if (!(val & data_format_mode))
 359                stream_data->interleaved = true;
 360
 361        stream_data->xfer_mode = (val & data_xfer_mode) >> data_xfer_shift;
 362        stream_data->ch_limit = (val & ch_count_mask) >> ch_count_shift;
 363        dev_info(component->dev,
 364                 "stream %d : format = %d mode = %d ch_limit = %d\n",
 365                 substream->stream, stream_data->interleaved,
 366                 stream_data->xfer_mode, stream_data->ch_limit);
 367
 368        snd_soc_set_runtime_hwparams(substream, &xlnx_pcm_hardware);
 369        runtime->private_data = stream_data;
 370
 371        /* Resize the period size divisible by 64 */
 372        err = snd_pcm_hw_constraint_step(runtime, 0,
 373                                         SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64);
 374        if (err) {
 375                dev_err(component->dev,
 376                        "unable to set constraint on period bytes\n");
 377                return err;
 378        }
 379
 380        /* enable DMA IOC irq */
 381        val = readl(stream_data->mmio + XLNX_AUD_CTRL);
 382        val |= AUD_CTRL_IOC_IRQ_MASK;
 383        writel(val, stream_data->mmio + XLNX_AUD_CTRL);
 384
 385        return 0;
 386}
 387
 388static int xlnx_formatter_pcm_close(struct snd_soc_component *component,
 389                                    struct snd_pcm_substream *substream)
 390{
 391        int ret;
 392        struct xlnx_pcm_stream_param *stream_data =
 393                        substream->runtime->private_data;
 394
 395        ret = xlnx_formatter_pcm_reset(stream_data->mmio);
 396        if (ret) {
 397                dev_err(component->dev, "audio formatter reset failed\n");
 398                goto err_reset;
 399        }
 400        xlnx_formatter_disable_irqs(stream_data->mmio, substream->stream);
 401
 402err_reset:
 403        kfree(stream_data);
 404        return 0;
 405}
 406
 407static snd_pcm_uframes_t
 408xlnx_formatter_pcm_pointer(struct snd_soc_component *component,
 409                           struct snd_pcm_substream *substream)
 410{
 411        u32 pos;
 412        struct snd_pcm_runtime *runtime = substream->runtime;
 413        struct xlnx_pcm_stream_param *stream_data = runtime->private_data;
 414
 415        pos = readl(stream_data->mmio + XLNX_AUD_XFER_COUNT);
 416
 417        if (pos >= stream_data->buffer_size)
 418                pos = 0;
 419
 420        return bytes_to_frames(runtime, pos);
 421}
 422
 423static int xlnx_formatter_pcm_hw_params(struct snd_soc_component *component,
 424                                        struct snd_pcm_substream *substream,
 425                                        struct snd_pcm_hw_params *params)
 426{
 427        u32 low, high, active_ch, val, bytes_per_ch, bits_per_sample;
 428        u32 aes_reg1_val, aes_reg2_val;
 429        u64 size;
 430        struct snd_pcm_runtime *runtime = substream->runtime;
 431        struct xlnx_pcm_stream_param *stream_data = runtime->private_data;
 432
 433        active_ch = params_channels(params);
 434        if (active_ch > stream_data->ch_limit)
 435                return -EINVAL;
 436
 437        if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
 438            stream_data->xfer_mode == AES_TO_PCM) {
 439                val = readl(stream_data->mmio + XLNX_AUD_STS);
 440                if (val & AUD_STS_CH_STS_MASK) {
 441                        aes_reg1_val = readl(stream_data->mmio +
 442                                             XLNX_AUD_CH_STS_START);
 443                        aes_reg2_val = readl(stream_data->mmio +
 444                                             XLNX_AUD_CH_STS_START + 0x4);
 445
 446                        xlnx_parse_aes_params(aes_reg1_val, aes_reg2_val,
 447                                              component->dev);
 448                }
 449        }
 450
 451        size = params_buffer_bytes(params);
 452
 453        stream_data->buffer_size = size;
 454
 455        low = lower_32_bits(substream->dma_buffer.addr);
 456        high = upper_32_bits(substream->dma_buffer.addr);
 457        writel(low, stream_data->mmio + XLNX_AUD_BUFF_ADDR_LSB);
 458        writel(high, stream_data->mmio + XLNX_AUD_BUFF_ADDR_MSB);
 459
 460        val = readl(stream_data->mmio + XLNX_AUD_CTRL);
 461        bits_per_sample = params_width(params);
 462        switch (bits_per_sample) {
 463        case 8:
 464                val |= (BIT_DEPTH_8 << AUD_CTRL_DATA_WIDTH_SHIFT);
 465                break;
 466        case 16:
 467                val |= (BIT_DEPTH_16 << AUD_CTRL_DATA_WIDTH_SHIFT);
 468                break;
 469        case 20:
 470                val |= (BIT_DEPTH_20 << AUD_CTRL_DATA_WIDTH_SHIFT);
 471                break;
 472        case 24:
 473                val |= (BIT_DEPTH_24 << AUD_CTRL_DATA_WIDTH_SHIFT);
 474                break;
 475        case 32:
 476                val |= (BIT_DEPTH_32 << AUD_CTRL_DATA_WIDTH_SHIFT);
 477                break;
 478        default:
 479                return -EINVAL;
 480        }
 481
 482        val |= active_ch << AUD_CTRL_ACTIVE_CH_SHIFT;
 483        writel(val, stream_data->mmio + XLNX_AUD_CTRL);
 484
 485        val = (params_periods(params) << PERIOD_CFG_PERIODS_SHIFT)
 486                | params_period_bytes(params);
 487        writel(val, stream_data->mmio + XLNX_AUD_PERIOD_CONFIG);
 488        bytes_per_ch = DIV_ROUND_UP(params_period_bytes(params), active_ch);
 489        writel(bytes_per_ch, stream_data->mmio + XLNX_BYTES_PER_CH);
 490
 491        return 0;
 492}
 493
 494static int xlnx_formatter_pcm_trigger(struct snd_soc_component *component,
 495                                      struct snd_pcm_substream *substream,
 496                                      int cmd)
 497{
 498        u32 val;
 499        struct xlnx_pcm_stream_param *stream_data =
 500                        substream->runtime->private_data;
 501
 502        switch (cmd) {
 503        case SNDRV_PCM_TRIGGER_START:
 504        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 505        case SNDRV_PCM_TRIGGER_RESUME:
 506                val = readl(stream_data->mmio + XLNX_AUD_CTRL);
 507                val |= AUD_CTRL_DMA_EN_MASK;
 508                writel(val, stream_data->mmio + XLNX_AUD_CTRL);
 509                break;
 510        case SNDRV_PCM_TRIGGER_STOP:
 511        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 512        case SNDRV_PCM_TRIGGER_SUSPEND:
 513                val = readl(stream_data->mmio + XLNX_AUD_CTRL);
 514                val &= ~AUD_CTRL_DMA_EN_MASK;
 515                writel(val, stream_data->mmio + XLNX_AUD_CTRL);
 516                break;
 517        }
 518
 519        return 0;
 520}
 521
 522static int xlnx_formatter_pcm_new(struct snd_soc_component *component,
 523                                  struct snd_soc_pcm_runtime *rtd)
 524{
 525        snd_pcm_set_managed_buffer_all(rtd->pcm,
 526                        SNDRV_DMA_TYPE_DEV, component->dev,
 527                        xlnx_pcm_hardware.buffer_bytes_max,
 528                        xlnx_pcm_hardware.buffer_bytes_max);
 529        return 0;
 530}
 531
 532static const struct snd_soc_component_driver xlnx_asoc_component = {
 533        .name           = DRV_NAME,
 534        .open           = xlnx_formatter_pcm_open,
 535        .close          = xlnx_formatter_pcm_close,
 536        .hw_params      = xlnx_formatter_pcm_hw_params,
 537        .trigger        = xlnx_formatter_pcm_trigger,
 538        .pointer        = xlnx_formatter_pcm_pointer,
 539        .pcm_construct  = xlnx_formatter_pcm_new,
 540};
 541
 542static int xlnx_formatter_pcm_probe(struct platform_device *pdev)
 543{
 544        int ret;
 545        u32 val;
 546        struct xlnx_pcm_drv_data *aud_drv_data;
 547        struct device *dev = &pdev->dev;
 548
 549        aud_drv_data = devm_kzalloc(dev, sizeof(*aud_drv_data), GFP_KERNEL);
 550        if (!aud_drv_data)
 551                return -ENOMEM;
 552
 553        aud_drv_data->axi_clk = devm_clk_get(dev, "s_axi_lite_aclk");
 554        if (IS_ERR(aud_drv_data->axi_clk)) {
 555                ret = PTR_ERR(aud_drv_data->axi_clk);
 556                dev_err(dev, "failed to get s_axi_lite_aclk(%d)\n", ret);
 557                return ret;
 558        }
 559        ret = clk_prepare_enable(aud_drv_data->axi_clk);
 560        if (ret) {
 561                dev_err(dev,
 562                        "failed to enable s_axi_lite_aclk(%d)\n", ret);
 563                return ret;
 564        }
 565
 566        aud_drv_data->mmio = devm_platform_ioremap_resource(pdev, 0);
 567        if (IS_ERR(aud_drv_data->mmio)) {
 568                dev_err(dev, "audio formatter ioremap failed\n");
 569                ret = PTR_ERR(aud_drv_data->mmio);
 570                goto clk_err;
 571        }
 572
 573        val = readl(aud_drv_data->mmio + XLNX_AUD_CORE_CONFIG);
 574        if (val & AUD_CFG_MM2S_MASK) {
 575                aud_drv_data->mm2s_presence = true;
 576                ret = xlnx_formatter_pcm_reset(aud_drv_data->mmio +
 577                                               XLNX_MM2S_OFFSET);
 578                if (ret) {
 579                        dev_err(dev, "audio formatter reset failed\n");
 580                        goto clk_err;
 581                }
 582                xlnx_formatter_disable_irqs(aud_drv_data->mmio +
 583                                            XLNX_MM2S_OFFSET,
 584                                            SNDRV_PCM_STREAM_PLAYBACK);
 585
 586                aud_drv_data->mm2s_irq = platform_get_irq_byname(pdev,
 587                                                                 "irq_mm2s");
 588                if (aud_drv_data->mm2s_irq < 0) {
 589                        ret = aud_drv_data->mm2s_irq;
 590                        goto clk_err;
 591                }
 592                ret = devm_request_irq(dev, aud_drv_data->mm2s_irq,
 593                                       xlnx_mm2s_irq_handler, 0,
 594                                       "xlnx_formatter_pcm_mm2s_irq", dev);
 595                if (ret) {
 596                        dev_err(dev, "xlnx audio mm2s irq request failed\n");
 597                        goto clk_err;
 598                }
 599        }
 600        if (val & AUD_CFG_S2MM_MASK) {
 601                aud_drv_data->s2mm_presence = true;
 602                ret = xlnx_formatter_pcm_reset(aud_drv_data->mmio +
 603                                               XLNX_S2MM_OFFSET);
 604                if (ret) {
 605                        dev_err(dev, "audio formatter reset failed\n");
 606                        goto clk_err;
 607                }
 608                xlnx_formatter_disable_irqs(aud_drv_data->mmio +
 609                                            XLNX_S2MM_OFFSET,
 610                                            SNDRV_PCM_STREAM_CAPTURE);
 611
 612                aud_drv_data->s2mm_irq = platform_get_irq_byname(pdev,
 613                                                                 "irq_s2mm");
 614                if (aud_drv_data->s2mm_irq < 0) {
 615                        ret = aud_drv_data->s2mm_irq;
 616                        goto clk_err;
 617                }
 618                ret = devm_request_irq(dev, aud_drv_data->s2mm_irq,
 619                                       xlnx_s2mm_irq_handler, 0,
 620                                       "xlnx_formatter_pcm_s2mm_irq",
 621                                       dev);
 622                if (ret) {
 623                        dev_err(dev, "xlnx audio s2mm irq request failed\n");
 624                        goto clk_err;
 625                }
 626        }
 627
 628        dev_set_drvdata(dev, aud_drv_data);
 629
 630        ret = devm_snd_soc_register_component(dev, &xlnx_asoc_component,
 631                                              NULL, 0);
 632        if (ret) {
 633                dev_err(dev, "pcm platform device register failed\n");
 634                goto clk_err;
 635        }
 636
 637        return 0;
 638
 639clk_err:
 640        clk_disable_unprepare(aud_drv_data->axi_clk);
 641        return ret;
 642}
 643
 644static int xlnx_formatter_pcm_remove(struct platform_device *pdev)
 645{
 646        int ret = 0;
 647        struct xlnx_pcm_drv_data *adata = dev_get_drvdata(&pdev->dev);
 648
 649        if (adata->s2mm_presence)
 650                ret = xlnx_formatter_pcm_reset(adata->mmio + XLNX_S2MM_OFFSET);
 651
 652        /* Try MM2S reset, even if S2MM  reset fails */
 653        if (adata->mm2s_presence)
 654                ret = xlnx_formatter_pcm_reset(adata->mmio + XLNX_MM2S_OFFSET);
 655
 656        if (ret)
 657                dev_err(&pdev->dev, "audio formatter reset failed\n");
 658
 659        clk_disable_unprepare(adata->axi_clk);
 660        return ret;
 661}
 662
 663static const struct of_device_id xlnx_formatter_pcm_of_match[] = {
 664        { .compatible = "xlnx,audio-formatter-1.0"},
 665        {},
 666};
 667MODULE_DEVICE_TABLE(of, xlnx_formatter_pcm_of_match);
 668
 669static struct platform_driver xlnx_formatter_pcm_driver = {
 670        .probe  = xlnx_formatter_pcm_probe,
 671        .remove = xlnx_formatter_pcm_remove,
 672        .driver = {
 673                .name   = DRV_NAME,
 674                .of_match_table = xlnx_formatter_pcm_of_match,
 675        },
 676};
 677
 678module_platform_driver(xlnx_formatter_pcm_driver);
 679MODULE_AUTHOR("Maruthi Srinivas Bayyavarapu <maruthis@xilinx.com>");
 680MODULE_LICENSE("GPL v2");
 681