728 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// Xilinx ASoC audio formatter support4//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 023#define XLNX_MM2S_OFFSET 0x10024 25#define XLNX_AUD_CORE_CONFIG 0x426#define XLNX_AUD_CTRL 0x1027#define XLNX_AUD_STS 0x1428 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 0x1834#define XLNX_AUD_PERIOD_CONFIG 0x1C35#define XLNX_AUD_BUFF_ADDR_LSB 0x2036#define XLNX_AUD_BUFF_ADDR_MSB 0x2437#define XLNX_AUD_XFER_COUNT 0x2838#define XLNX_AUD_CH_STS_START 0x2C39#define XLNX_BYTES_PER_CH 0x4440#define XLNX_AUD_ALIGN_BYTES 6441 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 850#define CFG_MM2S_XFER_MASK GENMASK(14, 13)51#define CFG_MM2S_XFER_SHIFT 1352#define CFG_MM2S_PKG_MASK BIT(12)53 54#define CFG_S2MM_CH_MASK GENMASK(27, 24)55#define CFG_S2MM_CH_SHIFT 2456#define CFG_S2MM_XFER_MASK GENMASK(30, 29)57#define CFG_S2MM_XFER_SHIFT 2958#define CFG_S2MM_PKG_MASK BIT(28)59 60#define AUD_CTRL_DATA_WIDTH_SHIFT 1661#define AUD_CTRL_ACTIVE_CH_SHIFT 1962#define PERIOD_CFG_PERIODS_SHIFT 1663 64#define PERIODS_MIN 265#define PERIODS_MAX 666#define PERIOD_BYTES_MIN 19267#define PERIOD_BYTES_MAX (50 * 1024)68#define XLNX_PARAM_UNKNOWN 069 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 configuration92 * @mmio: base address offset93 * @interleaved: audio channels arrangement in buffer94 * @xfer_mode: data formatting mode during transfer95 * @ch_limit: Maximum channels supported96 * @buffer_size: stream ring buffer size97 */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_AES129};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 else210 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 else239 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 else244 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_t439xlnx_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