| .. | .. |
|---|
| 132 | 132 | |
|---|
| 133 | 133 | /* Error Handling: TX */ |
|---|
| 134 | 134 | if (isr[i] & ISR_TXFO) { |
|---|
| 135 | | - dev_err(dev->dev, "TX overrun (ch_id=%d)\n", i); |
|---|
| 135 | + dev_err_ratelimited(dev->dev, "TX overrun (ch_id=%d)\n", i); |
|---|
| 136 | 136 | irq_valid = true; |
|---|
| 137 | 137 | } |
|---|
| 138 | 138 | |
|---|
| 139 | 139 | /* Error Handling: TX */ |
|---|
| 140 | 140 | if (isr[i] & ISR_RXFO) { |
|---|
| 141 | | - dev_err(dev->dev, "RX overrun (ch_id=%d)\n", i); |
|---|
| 141 | + dev_err_ratelimited(dev->dev, "RX overrun (ch_id=%d)\n", i); |
|---|
| 142 | 142 | irq_valid = true; |
|---|
| 143 | 143 | } |
|---|
| 144 | 144 | } |
|---|
| .. | .. |
|---|
| 181 | 181 | i2s_write_reg(dev->i2s_base, CER, 0); |
|---|
| 182 | 182 | i2s_write_reg(dev->i2s_base, IER, 0); |
|---|
| 183 | 183 | } |
|---|
| 184 | | -} |
|---|
| 185 | | - |
|---|
| 186 | | -static int dw_i2s_startup(struct snd_pcm_substream *substream, |
|---|
| 187 | | - struct snd_soc_dai *cpu_dai) |
|---|
| 188 | | -{ |
|---|
| 189 | | - struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); |
|---|
| 190 | | - union dw_i2s_snd_dma_data *dma_data = NULL; |
|---|
| 191 | | - |
|---|
| 192 | | - if (!(dev->capability & DWC_I2S_RECORD) && |
|---|
| 193 | | - (substream->stream == SNDRV_PCM_STREAM_CAPTURE)) |
|---|
| 194 | | - return -EINVAL; |
|---|
| 195 | | - |
|---|
| 196 | | - if (!(dev->capability & DWC_I2S_PLAY) && |
|---|
| 197 | | - (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)) |
|---|
| 198 | | - return -EINVAL; |
|---|
| 199 | | - |
|---|
| 200 | | - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
|---|
| 201 | | - dma_data = &dev->play_dma_data; |
|---|
| 202 | | - else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) |
|---|
| 203 | | - dma_data = &dev->capture_dma_data; |
|---|
| 204 | | - |
|---|
| 205 | | - snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)dma_data); |
|---|
| 206 | | - |
|---|
| 207 | | - return 0; |
|---|
| 208 | 184 | } |
|---|
| 209 | 185 | |
|---|
| 210 | 186 | static void dw_i2s_config(struct dw_i2s_dev *dev, int stream) |
|---|
| .. | .. |
|---|
| 305 | 281 | return 0; |
|---|
| 306 | 282 | } |
|---|
| 307 | 283 | |
|---|
| 308 | | -static void dw_i2s_shutdown(struct snd_pcm_substream *substream, |
|---|
| 309 | | - struct snd_soc_dai *dai) |
|---|
| 310 | | -{ |
|---|
| 311 | | - snd_soc_dai_set_dma_data(dai, substream, NULL); |
|---|
| 312 | | -} |
|---|
| 313 | | - |
|---|
| 314 | 284 | static int dw_i2s_prepare(struct snd_pcm_substream *substream, |
|---|
| 315 | 285 | struct snd_soc_dai *dai) |
|---|
| 316 | 286 | { |
|---|
| .. | .. |
|---|
| 382 | 352 | } |
|---|
| 383 | 353 | |
|---|
| 384 | 354 | static const struct snd_soc_dai_ops dw_i2s_dai_ops = { |
|---|
| 385 | | - .startup = dw_i2s_startup, |
|---|
| 386 | | - .shutdown = dw_i2s_shutdown, |
|---|
| 387 | 355 | .hw_params = dw_i2s_hw_params, |
|---|
| 388 | 356 | .prepare = dw_i2s_prepare, |
|---|
| 389 | 357 | .trigger = dw_i2s_trigger, |
|---|
| 390 | 358 | .set_fmt = dw_i2s_set_fmt, |
|---|
| 391 | | -}; |
|---|
| 392 | | - |
|---|
| 393 | | -static const struct snd_soc_component_driver dw_i2s_component = { |
|---|
| 394 | | - .name = "dw-i2s", |
|---|
| 395 | 359 | }; |
|---|
| 396 | 360 | |
|---|
| 397 | 361 | #ifdef CONFIG_PM |
|---|
| .. | .. |
|---|
| 407 | 371 | static int dw_i2s_runtime_resume(struct device *dev) |
|---|
| 408 | 372 | { |
|---|
| 409 | 373 | struct dw_i2s_dev *dw_dev = dev_get_drvdata(dev); |
|---|
| 374 | + int ret; |
|---|
| 410 | 375 | |
|---|
| 411 | | - if (dw_dev->capability & DW_I2S_MASTER) |
|---|
| 412 | | - clk_enable(dw_dev->clk); |
|---|
| 376 | + if (dw_dev->capability & DW_I2S_MASTER) { |
|---|
| 377 | + ret = clk_enable(dw_dev->clk); |
|---|
| 378 | + if (ret) |
|---|
| 379 | + return ret; |
|---|
| 380 | + } |
|---|
| 413 | 381 | return 0; |
|---|
| 414 | 382 | } |
|---|
| 415 | 383 | |
|---|
| 416 | | -static int dw_i2s_suspend(struct snd_soc_dai *dai) |
|---|
| 384 | +static int dw_i2s_suspend(struct snd_soc_component *component) |
|---|
| 417 | 385 | { |
|---|
| 418 | | - struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); |
|---|
| 386 | + struct dw_i2s_dev *dev = snd_soc_component_get_drvdata(component); |
|---|
| 419 | 387 | |
|---|
| 420 | 388 | if (dev->capability & DW_I2S_MASTER) |
|---|
| 421 | 389 | clk_disable(dev->clk); |
|---|
| 422 | 390 | return 0; |
|---|
| 423 | 391 | } |
|---|
| 424 | 392 | |
|---|
| 425 | | -static int dw_i2s_resume(struct snd_soc_dai *dai) |
|---|
| 393 | +static int dw_i2s_resume(struct snd_soc_component *component) |
|---|
| 426 | 394 | { |
|---|
| 427 | | - struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); |
|---|
| 395 | + struct dw_i2s_dev *dev = snd_soc_component_get_drvdata(component); |
|---|
| 396 | + struct snd_soc_dai *dai; |
|---|
| 397 | + int stream, ret; |
|---|
| 428 | 398 | |
|---|
| 429 | | - if (dev->capability & DW_I2S_MASTER) |
|---|
| 430 | | - clk_enable(dev->clk); |
|---|
| 399 | + if (dev->capability & DW_I2S_MASTER) { |
|---|
| 400 | + ret = clk_enable(dev->clk); |
|---|
| 401 | + if (ret) |
|---|
| 402 | + return ret; |
|---|
| 403 | + } |
|---|
| 431 | 404 | |
|---|
| 432 | | - if (dai->playback_active) |
|---|
| 433 | | - dw_i2s_config(dev, SNDRV_PCM_STREAM_PLAYBACK); |
|---|
| 434 | | - if (dai->capture_active) |
|---|
| 435 | | - dw_i2s_config(dev, SNDRV_PCM_STREAM_CAPTURE); |
|---|
| 405 | + for_each_component_dais(component, dai) { |
|---|
| 406 | + for_each_pcm_streams(stream) |
|---|
| 407 | + if (snd_soc_dai_stream_active(dai, stream)) |
|---|
| 408 | + dw_i2s_config(dev, stream); |
|---|
| 409 | + } |
|---|
| 410 | + |
|---|
| 436 | 411 | return 0; |
|---|
| 437 | 412 | } |
|---|
| 438 | 413 | |
|---|
| .. | .. |
|---|
| 440 | 415 | #define dw_i2s_suspend NULL |
|---|
| 441 | 416 | #define dw_i2s_resume NULL |
|---|
| 442 | 417 | #endif |
|---|
| 418 | + |
|---|
| 419 | +static const struct snd_soc_component_driver dw_i2s_component = { |
|---|
| 420 | + .name = "dw-i2s", |
|---|
| 421 | + .suspend = dw_i2s_suspend, |
|---|
| 422 | + .resume = dw_i2s_resume, |
|---|
| 423 | +}; |
|---|
| 443 | 424 | |
|---|
| 444 | 425 | /* |
|---|
| 445 | 426 | * The following tables allow a direct lookup of various parameters |
|---|
| .. | .. |
|---|
| 611 | 592 | |
|---|
| 612 | 593 | } |
|---|
| 613 | 594 | |
|---|
| 595 | +static int dw_i2s_dai_probe(struct snd_soc_dai *dai) |
|---|
| 596 | +{ |
|---|
| 597 | + struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); |
|---|
| 598 | + |
|---|
| 599 | + snd_soc_dai_init_dma_data(dai, &dev->play_dma_data, &dev->capture_dma_data); |
|---|
| 600 | + return 0; |
|---|
| 601 | +} |
|---|
| 602 | + |
|---|
| 614 | 603 | static int dw_i2s_probe(struct platform_device *pdev) |
|---|
| 615 | 604 | { |
|---|
| 616 | 605 | const struct i2s_platform_data *pdata = pdev->dev.platform_data; |
|---|
| .. | .. |
|---|
| 629 | 618 | return -ENOMEM; |
|---|
| 630 | 619 | |
|---|
| 631 | 620 | dw_i2s_dai->ops = &dw_i2s_dai_ops; |
|---|
| 632 | | - dw_i2s_dai->suspend = dw_i2s_suspend; |
|---|
| 633 | | - dw_i2s_dai->resume = dw_i2s_resume; |
|---|
| 621 | + dw_i2s_dai->probe = dw_i2s_dai_probe; |
|---|
| 634 | 622 | |
|---|
| 635 | 623 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 636 | 624 | dev->i2s_base = devm_ioremap_resource(&pdev->dev, res); |
|---|