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