xlnx_formatter_pcm.c (19183B)
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 int 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 return ret; 707} 708 709static const struct of_device_id xlnx_formatter_pcm_of_match[] = { 710 { .compatible = "xlnx,audio-formatter-1.0"}, 711 {}, 712}; 713MODULE_DEVICE_TABLE(of, xlnx_formatter_pcm_of_match); 714 715static struct platform_driver xlnx_formatter_pcm_driver = { 716 .probe = xlnx_formatter_pcm_probe, 717 .remove = xlnx_formatter_pcm_remove, 718 .driver = { 719 .name = DRV_NAME, 720 .of_match_table = xlnx_formatter_pcm_of_match, 721 }, 722}; 723 724module_platform_driver(xlnx_formatter_pcm_driver); 725MODULE_AUTHOR("Maruthi Srinivas Bayyavarapu <maruthis@xilinx.com>"); 726MODULE_LICENSE("GPL v2");