1 // SPDX-License-Identifier: GPL-2.0-only 2 // 3 // Copyright (C) 2020 Intel Corporation. 4 // 5 // Intel KeemBay Platform driver. 6 // 7 8 #include <linux/clk.h> 9 #include <linux/io.h> 10 #include <linux/module.h> 11 #include <sound/pcm.h> 12 #include <sound/pcm_params.h> 13 #include <sound/soc.h> 14 #include "kmb_platform.h" 15 16 #define PERIODS_MIN 2 17 #define PERIODS_MAX 48 18 #define PERIOD_BYTES_MIN 4096 19 #define BUFFER_BYTES_MAX (PERIODS_MAX * PERIOD_BYTES_MIN) 20 #define TDM_OPERATION 1 21 #define I2S_OPERATION 0 22 #define DATA_WIDTH_CONFIG_BIT 6 23 #define TDM_CHANNEL_CONFIG_BIT 3 24 25 static const struct snd_pcm_hardware kmb_pcm_hardware = { 26 .info = SNDRV_PCM_INFO_INTERLEAVED | 27 SNDRV_PCM_INFO_MMAP | 28 SNDRV_PCM_INFO_MMAP_VALID | 29 SNDRV_PCM_INFO_BATCH | 30 SNDRV_PCM_INFO_BLOCK_TRANSFER, 31 .rates = SNDRV_PCM_RATE_8000 | 32 SNDRV_PCM_RATE_16000 | 33 SNDRV_PCM_RATE_48000, 34 .rate_min = 8000, 35 .rate_max = 48000, 36 .formats = SNDRV_PCM_FMTBIT_S16_LE | 37 SNDRV_PCM_FMTBIT_S24_LE | 38 SNDRV_PCM_FMTBIT_S32_LE, 39 .channels_min = 2, 40 .channels_max = 2, 41 .buffer_bytes_max = BUFFER_BYTES_MAX, 42 .period_bytes_min = PERIOD_BYTES_MIN, 43 .period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN, 44 .periods_min = PERIODS_MIN, 45 .periods_max = PERIODS_MAX, 46 .fifo_size = 16, 47 }; 48 49 static unsigned int kmb_pcm_tx_fn(struct kmb_i2s_info *kmb_i2s, 50 struct snd_pcm_runtime *runtime, 51 unsigned int tx_ptr, bool *period_elapsed) 52 { 53 unsigned int period_pos = tx_ptr % runtime->period_size; 54 void __iomem *i2s_base = kmb_i2s->i2s_base; 55 void *buf = runtime->dma_area; 56 int i; 57 58 /* KMB i2s uses two separate L/R FIFO */ 59 for (i = 0; i < kmb_i2s->fifo_th; i++) { 60 if (kmb_i2s->config.data_width == 16) { 61 writel(((u16(*)[2])buf)[tx_ptr][0], i2s_base + LRBR_LTHR(0)); 62 writel(((u16(*)[2])buf)[tx_ptr][1], i2s_base + RRBR_RTHR(0)); 63 } else { 64 writel(((u32(*)[2])buf)[tx_ptr][0], i2s_base + LRBR_LTHR(0)); 65 writel(((u32(*)[2])buf)[tx_ptr][1], i2s_base + RRBR_RTHR(0)); 66 } 67 68 period_pos++; 69 70 if (++tx_ptr >= runtime->buffer_size) 71 tx_ptr = 0; 72 } 73 74 *period_elapsed = period_pos >= runtime->period_size; 75 76 return tx_ptr; 77 } 78 79 static unsigned int kmb_pcm_rx_fn(struct kmb_i2s_info *kmb_i2s, 80 struct snd_pcm_runtime *runtime, 81 unsigned int rx_ptr, bool *period_elapsed) 82 { 83 unsigned int period_pos = rx_ptr % runtime->period_size; 84 void __iomem *i2s_base = kmb_i2s->i2s_base; 85 void *buf = runtime->dma_area; 86 int i; 87 88 /* KMB i2s uses two separate L/R FIFO */ 89 for (i = 0; i < kmb_i2s->fifo_th; i++) { 90 if (kmb_i2s->config.data_width == 16) { 91 ((u16(*)[2])buf)[rx_ptr][0] = readl(i2s_base + LRBR_LTHR(0)); 92 ((u16(*)[2])buf)[rx_ptr][1] = readl(i2s_base + RRBR_RTHR(0)); 93 } else { 94 ((u32(*)[2])buf)[rx_ptr][0] = readl(i2s_base + LRBR_LTHR(0)); 95 ((u32(*)[2])buf)[rx_ptr][1] = readl(i2s_base + RRBR_RTHR(0)); 96 } 97 98 period_pos++; 99 100 if (++rx_ptr >= runtime->buffer_size) 101 rx_ptr = 0; 102 } 103 104 *period_elapsed = period_pos >= runtime->period_size; 105 106 return rx_ptr; 107 } 108 109 static inline void kmb_i2s_disable_channels(struct kmb_i2s_info *kmb_i2s, 110 u32 stream) 111 { 112 u32 i; 113 114 /* Disable all channels regardless of configuration*/ 115 if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 116 for (i = 0; i < MAX_ISR; i++) 117 writel(0, kmb_i2s->i2s_base + TER(i)); 118 } else { 119 for (i = 0; i < MAX_ISR; i++) 120 writel(0, kmb_i2s->i2s_base + RER(i)); 121 } 122 } 123 124 static inline void kmb_i2s_clear_irqs(struct kmb_i2s_info *kmb_i2s, u32 stream) 125 { 126 struct i2s_clk_config_data *config = &kmb_i2s->config; 127 u32 i; 128 129 if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 130 for (i = 0; i < config->chan_nr / 2; i++) 131 readl(kmb_i2s->i2s_base + TOR(i)); 132 } else { 133 for (i = 0; i < config->chan_nr / 2; i++) 134 readl(kmb_i2s->i2s_base + ROR(i)); 135 } 136 } 137 138 static inline void kmb_i2s_irq_trigger(struct kmb_i2s_info *kmb_i2s, 139 u32 stream, int chan_nr, bool trigger) 140 { 141 u32 i, irq; 142 u32 flag; 143 144 if (stream == SNDRV_PCM_STREAM_PLAYBACK) 145 flag = TX_INT_FLAG; 146 else 147 flag = RX_INT_FLAG; 148 149 for (i = 0; i < chan_nr / 2; i++) { 150 irq = readl(kmb_i2s->i2s_base + IMR(i)); 151 152 if (trigger) 153 irq = irq & ~flag; 154 else 155 irq = irq | flag; 156 157 writel(irq, kmb_i2s->i2s_base + IMR(i)); 158 } 159 } 160 161 static void kmb_pcm_operation(struct kmb_i2s_info *kmb_i2s, bool playback) 162 { 163 struct snd_pcm_substream *substream; 164 bool period_elapsed; 165 unsigned int new_ptr; 166 unsigned int ptr; 167 168 if (playback) 169 substream = kmb_i2s->tx_substream; 170 else 171 substream = kmb_i2s->rx_substream; 172 173 if (!substream || !snd_pcm_running(substream)) 174 return; 175 176 if (playback) { 177 ptr = kmb_i2s->tx_ptr; 178 new_ptr = kmb_pcm_tx_fn(kmb_i2s, substream->runtime, 179 ptr, &period_elapsed); 180 cmpxchg(&kmb_i2s->tx_ptr, ptr, new_ptr); 181 } else { 182 ptr = kmb_i2s->rx_ptr; 183 new_ptr = kmb_pcm_rx_fn(kmb_i2s, substream->runtime, 184 ptr, &period_elapsed); 185 cmpxchg(&kmb_i2s->rx_ptr, ptr, new_ptr); 186 } 187 188 if (period_elapsed) 189 snd_pcm_period_elapsed(substream); 190 } 191 192 static int kmb_pcm_open(struct snd_soc_component *component, 193 struct snd_pcm_substream *substream) 194 { 195 struct snd_pcm_runtime *runtime = substream->runtime; 196 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 197 struct kmb_i2s_info *kmb_i2s; 198 199 kmb_i2s = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); 200 snd_soc_set_runtime_hwparams(substream, &kmb_pcm_hardware); 201 snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); 202 runtime->private_data = kmb_i2s; 203 204 return 0; 205 } 206 207 static int kmb_pcm_trigger(struct snd_soc_component *component, 208 struct snd_pcm_substream *substream, int cmd) 209 { 210 struct snd_pcm_runtime *runtime = substream->runtime; 211 struct kmb_i2s_info *kmb_i2s = runtime->private_data; 212 213 switch (cmd) { 214 case SNDRV_PCM_TRIGGER_START: 215 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 216 kmb_i2s->tx_ptr = 0; 217 kmb_i2s->tx_substream = substream; 218 } else { 219 kmb_i2s->rx_ptr = 0; 220 kmb_i2s->rx_substream = substream; 221 } 222 break; 223 case SNDRV_PCM_TRIGGER_STOP: 224 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 225 kmb_i2s->tx_substream = NULL; 226 else 227 kmb_i2s->rx_substream = NULL; 228 break; 229 default: 230 return -EINVAL; 231 } 232 233 return 0; 234 } 235 236 static irqreturn_t kmb_i2s_irq_handler(int irq, void *dev_id) 237 { 238 struct kmb_i2s_info *kmb_i2s = dev_id; 239 struct i2s_clk_config_data *config = &kmb_i2s->config; 240 irqreturn_t ret = IRQ_NONE; 241 u32 isr[4]; 242 int i; 243 244 for (i = 0; i < config->chan_nr / 2; i++) 245 isr[i] = readl(kmb_i2s->i2s_base + ISR(i)); 246 247 kmb_i2s_clear_irqs(kmb_i2s, SNDRV_PCM_STREAM_PLAYBACK); 248 kmb_i2s_clear_irqs(kmb_i2s, SNDRV_PCM_STREAM_CAPTURE); 249 250 for (i = 0; i < config->chan_nr / 2; i++) { 251 /* 252 * Check if TX fifo is empty. If empty fill FIFO with samples 253 */ 254 if ((isr[i] & ISR_TXFE)) { 255 kmb_pcm_operation(kmb_i2s, true); 256 ret = IRQ_HANDLED; 257 } 258 /* 259 * Data available. Retrieve samples from FIFO 260 */ 261 if ((isr[i] & ISR_RXDA)) { 262 kmb_pcm_operation(kmb_i2s, false); 263 ret = IRQ_HANDLED; 264 } 265 /* Error Handling: TX */ 266 if (isr[i] & ISR_TXFO) { 267 dev_dbg(kmb_i2s->dev, "TX overrun (ch_id=%d)\n", i); 268 ret = IRQ_HANDLED; 269 } 270 /* Error Handling: RX */ 271 if (isr[i] & ISR_RXFO) { 272 dev_dbg(kmb_i2s->dev, "RX overrun (ch_id=%d)\n", i); 273 ret = IRQ_HANDLED; 274 } 275 } 276 277 return ret; 278 } 279 280 static int kmb_platform_pcm_new(struct snd_soc_component *component, 281 struct snd_soc_pcm_runtime *soc_runtime) 282 { 283 size_t size = kmb_pcm_hardware.buffer_bytes_max; 284 /* Use SNDRV_DMA_TYPE_CONTINUOUS as KMB doesn't use PCI sg buffer */ 285 snd_pcm_set_managed_buffer_all(soc_runtime->pcm, 286 SNDRV_DMA_TYPE_CONTINUOUS, 287 NULL, size, size); 288 return 0; 289 } 290 291 static snd_pcm_uframes_t kmb_pcm_pointer(struct snd_soc_component *component, 292 struct snd_pcm_substream *substream) 293 { 294 struct snd_pcm_runtime *runtime = substream->runtime; 295 struct kmb_i2s_info *kmb_i2s = runtime->private_data; 296 snd_pcm_uframes_t pos; 297 298 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 299 pos = kmb_i2s->tx_ptr; 300 else 301 pos = kmb_i2s->rx_ptr; 302 303 return pos < runtime->buffer_size ? pos : 0; 304 } 305 306 static const struct snd_soc_component_driver kmb_component = { 307 .name = "kmb", 308 .pcm_construct = kmb_platform_pcm_new, 309 .open = kmb_pcm_open, 310 .trigger = kmb_pcm_trigger, 311 .pointer = kmb_pcm_pointer, 312 }; 313 314 static void kmb_i2s_start(struct kmb_i2s_info *kmb_i2s, 315 struct snd_pcm_substream *substream) 316 { 317 struct i2s_clk_config_data *config = &kmb_i2s->config; 318 319 /* I2S Programming sequence in Keem_Bay_VPU_DB_v1.1 */ 320 writel(1, kmb_i2s->i2s_base + IER); 321 322 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 323 writel(1, kmb_i2s->i2s_base + ITER); 324 else 325 writel(1, kmb_i2s->i2s_base + IRER); 326 327 kmb_i2s_irq_trigger(kmb_i2s, substream->stream, config->chan_nr, true); 328 329 if (kmb_i2s->master) 330 writel(1, kmb_i2s->i2s_base + CER); 331 else 332 writel(0, kmb_i2s->i2s_base + CER); 333 } 334 335 static void kmb_i2s_stop(struct kmb_i2s_info *kmb_i2s, 336 struct snd_pcm_substream *substream) 337 { 338 /* I2S Programming sequence in Keem_Bay_VPU_DB_v1.1 */ 339 kmb_i2s_clear_irqs(kmb_i2s, substream->stream); 340 341 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 342 writel(0, kmb_i2s->i2s_base + ITER); 343 else 344 writel(0, kmb_i2s->i2s_base + IRER); 345 346 kmb_i2s_irq_trigger(kmb_i2s, substream->stream, 8, false); 347 348 if (!kmb_i2s->active) { 349 writel(0, kmb_i2s->i2s_base + CER); 350 writel(0, kmb_i2s->i2s_base + IER); 351 } 352 } 353 354 static void kmb_disable_clk(void *clk) 355 { 356 clk_disable_unprepare(clk); 357 } 358 359 static int kmb_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) 360 { 361 struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai); 362 int ret; 363 364 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 365 case SND_SOC_DAIFMT_CBM_CFM: 366 kmb_i2s->master = false; 367 ret = 0; 368 break; 369 case SND_SOC_DAIFMT_CBS_CFS: 370 writel(MASTER_MODE, kmb_i2s->pss_base + I2S_GEN_CFG_0); 371 372 ret = clk_prepare_enable(kmb_i2s->clk_i2s); 373 if (ret < 0) 374 return ret; 375 376 ret = devm_add_action_or_reset(kmb_i2s->dev, kmb_disable_clk, 377 kmb_i2s->clk_i2s); 378 if (ret) 379 return ret; 380 381 kmb_i2s->master = true; 382 break; 383 default: 384 return -EINVAL; 385 } 386 387 return ret; 388 } 389 390 static int kmb_dai_trigger(struct snd_pcm_substream *substream, 391 int cmd, struct snd_soc_dai *cpu_dai) 392 { 393 struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai); 394 395 switch (cmd) { 396 case SNDRV_PCM_TRIGGER_START: 397 /* Keep track of i2s activity before turn off 398 * the i2s interface 399 */ 400 kmb_i2s->active++; 401 kmb_i2s_start(kmb_i2s, substream); 402 break; 403 case SNDRV_PCM_TRIGGER_STOP: 404 kmb_i2s->active--; 405 kmb_i2s_stop(kmb_i2s, substream); 406 break; 407 default: 408 return -EINVAL; 409 } 410 411 return 0; 412 } 413 414 static void kmb_i2s_config(struct kmb_i2s_info *kmb_i2s, int stream) 415 { 416 struct i2s_clk_config_data *config = &kmb_i2s->config; 417 u32 ch_reg; 418 419 kmb_i2s_disable_channels(kmb_i2s, stream); 420 421 for (ch_reg = 0; ch_reg < config->chan_nr / 2; ch_reg++) { 422 if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 423 writel(kmb_i2s->xfer_resolution, 424 kmb_i2s->i2s_base + TCR(ch_reg)); 425 426 writel(kmb_i2s->fifo_th - 1, 427 kmb_i2s->i2s_base + TFCR(ch_reg)); 428 429 writel(1, kmb_i2s->i2s_base + TER(ch_reg)); 430 } else { 431 writel(kmb_i2s->xfer_resolution, 432 kmb_i2s->i2s_base + RCR(ch_reg)); 433 434 writel(kmb_i2s->fifo_th - 1, 435 kmb_i2s->i2s_base + RFCR(ch_reg)); 436 437 writel(1, kmb_i2s->i2s_base + RER(ch_reg)); 438 } 439 } 440 } 441 442 static int kmb_dai_hw_params(struct snd_pcm_substream *substream, 443 struct snd_pcm_hw_params *hw_params, 444 struct snd_soc_dai *cpu_dai) 445 { 446 struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai); 447 struct i2s_clk_config_data *config = &kmb_i2s->config; 448 u32 register_val, write_val; 449 int ret; 450 451 switch (params_format(hw_params)) { 452 case SNDRV_PCM_FORMAT_S16_LE: 453 config->data_width = 16; 454 kmb_i2s->ccr = 0x00; 455 kmb_i2s->xfer_resolution = 0x02; 456 break; 457 case SNDRV_PCM_FORMAT_S24_LE: 458 config->data_width = 24; 459 kmb_i2s->ccr = 0x08; 460 kmb_i2s->xfer_resolution = 0x04; 461 break; 462 case SNDRV_PCM_FORMAT_S32_LE: 463 config->data_width = 32; 464 kmb_i2s->ccr = 0x10; 465 kmb_i2s->xfer_resolution = 0x05; 466 break; 467 default: 468 dev_err(kmb_i2s->dev, "kmb: unsupported PCM fmt"); 469 return -EINVAL; 470 } 471 472 config->chan_nr = params_channels(hw_params); 473 474 switch (config->chan_nr) { 475 /* TODO: This switch case will handle up to TDM8 in the near future */ 476 case TWO_CHANNEL_SUPPORT: 477 write_val = ((config->chan_nr / 2) << TDM_CHANNEL_CONFIG_BIT) | 478 (config->data_width << DATA_WIDTH_CONFIG_BIT) | 479 MASTER_MODE | I2S_OPERATION; 480 481 writel(write_val, kmb_i2s->pss_base + I2S_GEN_CFG_0); 482 483 register_val = readl(kmb_i2s->pss_base + I2S_GEN_CFG_0); 484 dev_dbg(kmb_i2s->dev, "pss register = 0x%X", register_val); 485 break; 486 default: 487 dev_dbg(kmb_i2s->dev, "channel not supported\n"); 488 return -EINVAL; 489 } 490 491 kmb_i2s_config(kmb_i2s, substream->stream); 492 493 writel(kmb_i2s->ccr, kmb_i2s->i2s_base + CCR); 494 495 config->sample_rate = params_rate(hw_params); 496 497 if (kmb_i2s->master) { 498 /* Only 2 ch supported in Master mode */ 499 u32 bitclk = config->sample_rate * config->data_width * 2; 500 501 ret = clk_set_rate(kmb_i2s->clk_i2s, bitclk); 502 if (ret) { 503 dev_err(kmb_i2s->dev, 504 "Can't set I2S clock rate: %d\n", ret); 505 return ret; 506 } 507 } 508 509 return 0; 510 } 511 512 static int kmb_dai_prepare(struct snd_pcm_substream *substream, 513 struct snd_soc_dai *cpu_dai) 514 { 515 struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai); 516 517 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 518 writel(1, kmb_i2s->i2s_base + TXFFR); 519 else 520 writel(1, kmb_i2s->i2s_base + RXFFR); 521 522 return 0; 523 } 524 525 static struct snd_soc_dai_ops kmb_dai_ops = { 526 .trigger = kmb_dai_trigger, 527 .hw_params = kmb_dai_hw_params, 528 .prepare = kmb_dai_prepare, 529 .set_fmt = kmb_set_dai_fmt, 530 }; 531 532 static struct snd_soc_dai_driver intel_kmb_platform_dai[] = { 533 { 534 .name = "kmb-plat-dai", 535 .playback = { 536 .channels_min = 2, 537 .channels_max = 2, 538 .rates = SNDRV_PCM_RATE_8000 | 539 SNDRV_PCM_RATE_16000 | 540 SNDRV_PCM_RATE_48000, 541 .rate_min = 8000, 542 .rate_max = 48000, 543 .formats = (SNDRV_PCM_FMTBIT_S32_LE | 544 SNDRV_PCM_FMTBIT_S24_LE | 545 SNDRV_PCM_FMTBIT_S16_LE), 546 }, 547 .capture = { 548 .channels_min = 2, 549 .channels_max = 2, 550 /* 551 * .channels_max will be overwritten 552 * if provided by Device Tree 553 */ 554 .rates = SNDRV_PCM_RATE_8000 | 555 SNDRV_PCM_RATE_16000 | 556 SNDRV_PCM_RATE_48000, 557 .rate_min = 8000, 558 .rate_max = 48000, 559 .formats = (SNDRV_PCM_FMTBIT_S32_LE | 560 SNDRV_PCM_FMTBIT_S24_LE | 561 SNDRV_PCM_FMTBIT_S16_LE), 562 }, 563 .ops = &kmb_dai_ops, 564 }, 565 }; 566 567 static int kmb_plat_dai_probe(struct platform_device *pdev) 568 { 569 struct snd_soc_dai_driver *kmb_i2s_dai; 570 struct device *dev = &pdev->dev; 571 struct kmb_i2s_info *kmb_i2s; 572 int ret, irq; 573 u32 comp1_reg; 574 575 kmb_i2s = devm_kzalloc(dev, sizeof(*kmb_i2s), GFP_KERNEL); 576 if (!kmb_i2s) 577 return -ENOMEM; 578 579 kmb_i2s_dai = devm_kzalloc(dev, sizeof(*kmb_i2s_dai), GFP_KERNEL); 580 if (!kmb_i2s_dai) 581 return -ENOMEM; 582 583 kmb_i2s_dai->ops = &kmb_dai_ops; 584 585 /* Prepare the related clocks */ 586 kmb_i2s->clk_apb = devm_clk_get(dev, "apb_clk"); 587 if (IS_ERR(kmb_i2s->clk_apb)) { 588 dev_err(dev, "Failed to get apb clock\n"); 589 return PTR_ERR(kmb_i2s->clk_apb); 590 } 591 592 ret = clk_prepare_enable(kmb_i2s->clk_apb); 593 if (ret < 0) 594 return ret; 595 596 ret = devm_add_action_or_reset(dev, kmb_disable_clk, kmb_i2s->clk_apb); 597 if (ret) { 598 dev_err(dev, "Failed to add clk_apb reset action\n"); 599 return ret; 600 } 601 602 kmb_i2s->clk_i2s = devm_clk_get(dev, "osc"); 603 if (IS_ERR(kmb_i2s->clk_i2s)) { 604 dev_err(dev, "Failed to get osc clock\n"); 605 return PTR_ERR(kmb_i2s->clk_i2s); 606 } 607 608 kmb_i2s->i2s_base = devm_platform_ioremap_resource(pdev, 0); 609 if (IS_ERR(kmb_i2s->i2s_base)) 610 return PTR_ERR(kmb_i2s->i2s_base); 611 612 kmb_i2s->pss_base = devm_platform_ioremap_resource(pdev, 1); 613 if (IS_ERR(kmb_i2s->pss_base)) 614 return PTR_ERR(kmb_i2s->pss_base); 615 616 kmb_i2s->dev = &pdev->dev; 617 618 irq = platform_get_irq_optional(pdev, 0); 619 if (irq > 0) { 620 ret = devm_request_irq(dev, irq, kmb_i2s_irq_handler, 0, 621 pdev->name, kmb_i2s); 622 if (ret < 0) { 623 dev_err(dev, "failed to request irq\n"); 624 return ret; 625 } 626 } 627 628 comp1_reg = readl(kmb_i2s->i2s_base + I2S_COMP_PARAM_1); 629 630 kmb_i2s->fifo_th = (1 << COMP1_FIFO_DEPTH(comp1_reg)) / 2; 631 632 ret = devm_snd_soc_register_component(dev, &kmb_component, 633 intel_kmb_platform_dai, 634 ARRAY_SIZE(intel_kmb_platform_dai)); 635 if (ret) { 636 dev_err(dev, "not able to register dai\n"); 637 return ret; 638 } 639 640 /* To ensure none of the channels are enabled at boot up */ 641 kmb_i2s_disable_channels(kmb_i2s, SNDRV_PCM_STREAM_PLAYBACK); 642 kmb_i2s_disable_channels(kmb_i2s, SNDRV_PCM_STREAM_CAPTURE); 643 644 dev_set_drvdata(dev, kmb_i2s); 645 646 return ret; 647 } 648 649 static const struct of_device_id kmb_plat_of_match[] = { 650 { .compatible = "intel,keembay-i2s", }, 651 {} 652 }; 653 654 static struct platform_driver kmb_plat_dai_driver = { 655 .driver = { 656 .name = "kmb-plat-dai", 657 .of_match_table = kmb_plat_of_match, 658 }, 659 .probe = kmb_plat_dai_probe, 660 }; 661 662 module_platform_driver(kmb_plat_dai_driver); 663 664 MODULE_DESCRIPTION("ASoC Intel KeemBay Platform driver"); 665 MODULE_AUTHOR("Sia Jee Heng <jee.heng.sia@intel.com>"); 666 MODULE_AUTHOR("Sit, Michael Wei Hong <michael.wei.hong.sit@intel.com>"); 667 MODULE_LICENSE("GPL v2"); 668 MODULE_ALIAS("platform:kmb_platform"); 669