| .. | .. |
|---|
| 21 | 21 | #include <sound/dmaengine_pcm.h> |
|---|
| 22 | 22 | |
|---|
| 23 | 23 | #include "rockchip_i2s.h" |
|---|
| 24 | +#include "rockchip_dlp_pcm.h" |
|---|
| 25 | +#include "rockchip_utils.h" |
|---|
| 24 | 26 | |
|---|
| 25 | 27 | #define DRV_NAME "rockchip-i2s" |
|---|
| 26 | 28 | |
|---|
| 27 | 29 | #define CLK_PPM_MIN (-1000) |
|---|
| 28 | 30 | #define CLK_PPM_MAX (1000) |
|---|
| 31 | + |
|---|
| 32 | +#define DEFAULT_MCLK_FS 256 |
|---|
| 33 | +#define DEFAULT_FS 48000 |
|---|
| 34 | + |
|---|
| 35 | +#define WAIT_TIME_MS_MAX 10000 |
|---|
| 36 | + |
|---|
| 37 | +#define QUIRK_ALWAYS_ON BIT(0) |
|---|
| 29 | 38 | |
|---|
| 30 | 39 | struct rk_i2s_pins { |
|---|
| 31 | 40 | u32 reg_offset; |
|---|
| .. | .. |
|---|
| 44 | 53 | |
|---|
| 45 | 54 | struct regmap *regmap; |
|---|
| 46 | 55 | struct regmap *grf; |
|---|
| 56 | + |
|---|
| 57 | + struct snd_pcm_substream *substreams[SNDRV_PCM_STREAM_LAST + 1]; |
|---|
| 58 | + unsigned int wait_time[SNDRV_PCM_STREAM_LAST + 1]; |
|---|
| 47 | 59 | |
|---|
| 48 | 60 | bool has_capture; |
|---|
| 49 | 61 | bool has_playback; |
|---|
| .. | .. |
|---|
| 66 | 78 | int clk_ppm; |
|---|
| 67 | 79 | bool mclk_calibrate; |
|---|
| 68 | 80 | |
|---|
| 81 | + unsigned int quirks; |
|---|
| 82 | +}; |
|---|
| 83 | + |
|---|
| 84 | +static struct i2s_of_quirks { |
|---|
| 85 | + char *quirk; |
|---|
| 86 | + int id; |
|---|
| 87 | +} of_quirks[] = { |
|---|
| 88 | + { |
|---|
| 89 | + .quirk = "rockchip,always-on", |
|---|
| 90 | + .id = QUIRK_ALWAYS_ON, |
|---|
| 91 | + }, |
|---|
| 69 | 92 | }; |
|---|
| 70 | 93 | |
|---|
| 71 | 94 | static int i2s_runtime_suspend(struct device *dev) |
|---|
| .. | .. |
|---|
| 157 | 180 | regmap_update_bits(i2s->regmap, I2S_DMACR, |
|---|
| 158 | 181 | I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE); |
|---|
| 159 | 182 | |
|---|
| 160 | | - if (!i2s->rx_start) { |
|---|
| 183 | + if (!i2s->rx_start && !(i2s->quirks & QUIRK_ALWAYS_ON)) { |
|---|
| 161 | 184 | regmap_update_bits(i2s->regmap, I2S_XFER, |
|---|
| 162 | 185 | I2S_XFER_TXS_START | |
|---|
| 163 | 186 | I2S_XFER_RXS_START, |
|---|
| .. | .. |
|---|
| 189 | 212 | regmap_update_bits(i2s->regmap, I2S_DMACR, |
|---|
| 190 | 213 | I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE); |
|---|
| 191 | 214 | |
|---|
| 192 | | - if (!i2s->tx_start) { |
|---|
| 215 | + if (!i2s->tx_start && !(i2s->quirks & QUIRK_ALWAYS_ON)) { |
|---|
| 193 | 216 | regmap_update_bits(i2s->regmap, I2S_XFER, |
|---|
| 194 | 217 | I2S_XFER_TXS_START | |
|---|
| 195 | 218 | I2S_XFER_RXS_START, |
|---|
| .. | .. |
|---|
| 312 | 335 | return ret; |
|---|
| 313 | 336 | } |
|---|
| 314 | 337 | |
|---|
| 338 | +static void rockchip_i2s_get_performance(struct snd_pcm_substream *substream, |
|---|
| 339 | + struct snd_pcm_hw_params *params, |
|---|
| 340 | + struct snd_soc_dai *dai, |
|---|
| 341 | + unsigned int csr) |
|---|
| 342 | +{ |
|---|
| 343 | + struct rk_i2s_dev *i2s = to_info(dai); |
|---|
| 344 | + unsigned int tdl; |
|---|
| 345 | + int fifo; |
|---|
| 346 | + |
|---|
| 347 | + regmap_read(i2s->regmap, I2S_DMACR, &tdl); |
|---|
| 348 | + |
|---|
| 349 | + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
|---|
| 350 | + fifo = I2S_DMACR_TDL_V(tdl) * I2S_TXCR_CSR_V(csr); |
|---|
| 351 | + else |
|---|
| 352 | + fifo = I2S_DMACR_RDL_V(tdl) * I2S_RXCR_CSR_V(csr); |
|---|
| 353 | + |
|---|
| 354 | + rockchip_utils_get_performance(substream, params, dai, fifo); |
|---|
| 355 | +} |
|---|
| 356 | + |
|---|
| 315 | 357 | static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream, |
|---|
| 316 | 358 | struct snd_pcm_hw_params *params, |
|---|
| 317 | 359 | struct snd_soc_dai *dai) |
|---|
| .. | .. |
|---|
| 353 | 395 | val |= I2S_TXCR_VDW(24); |
|---|
| 354 | 396 | break; |
|---|
| 355 | 397 | case SNDRV_PCM_FORMAT_S32_LE: |
|---|
| 398 | + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: |
|---|
| 356 | 399 | val |= I2S_TXCR_VDW(32); |
|---|
| 357 | 400 | break; |
|---|
| 358 | 401 | default: |
|---|
| .. | .. |
|---|
| 377 | 420 | params_channels(params)); |
|---|
| 378 | 421 | return -EINVAL; |
|---|
| 379 | 422 | } |
|---|
| 423 | + |
|---|
| 424 | + rockchip_i2s_get_performance(substream, params, dai, val); |
|---|
| 380 | 425 | |
|---|
| 381 | 426 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) |
|---|
| 382 | 427 | regmap_update_bits(i2s->regmap, I2S_RXCR, |
|---|
| .. | .. |
|---|
| 415 | 460 | I2S_DMACR_TDL(16)); |
|---|
| 416 | 461 | regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_RDL_MASK, |
|---|
| 417 | 462 | I2S_DMACR_RDL(16)); |
|---|
| 463 | + |
|---|
| 464 | + return 0; |
|---|
| 465 | +} |
|---|
| 466 | + |
|---|
| 467 | +static int rockchip_i2s_hw_free(struct snd_pcm_substream *substream, |
|---|
| 468 | + struct snd_soc_dai *dai) |
|---|
| 469 | +{ |
|---|
| 470 | + rockchip_utils_put_performance(substream, dai); |
|---|
| 418 | 471 | |
|---|
| 419 | 472 | return 0; |
|---|
| 420 | 473 | } |
|---|
| .. | .. |
|---|
| 549 | 602 | static int rockchip_i2s_clk_compensation_get(struct snd_kcontrol *kcontrol, |
|---|
| 550 | 603 | struct snd_ctl_elem_value *ucontrol) |
|---|
| 551 | 604 | { |
|---|
| 552 | | - struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); |
|---|
| 553 | | - struct rk_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai); |
|---|
| 605 | + struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol); |
|---|
| 606 | + struct rk_i2s_dev *i2s = snd_soc_component_get_drvdata(compnt); |
|---|
| 554 | 607 | |
|---|
| 555 | 608 | ucontrol->value.integer.value[0] = i2s->clk_ppm; |
|---|
| 556 | 609 | |
|---|
| .. | .. |
|---|
| 560 | 613 | static int rockchip_i2s_clk_compensation_put(struct snd_kcontrol *kcontrol, |
|---|
| 561 | 614 | struct snd_ctl_elem_value *ucontrol) |
|---|
| 562 | 615 | { |
|---|
| 563 | | - struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); |
|---|
| 564 | | - struct rk_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai); |
|---|
| 616 | + struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol); |
|---|
| 617 | + struct rk_i2s_dev *i2s = snd_soc_component_get_drvdata(compnt); |
|---|
| 565 | 618 | int ppm = ucontrol->value.integer.value[0]; |
|---|
| 566 | 619 | |
|---|
| 567 | 620 | if ((ucontrol->value.integer.value[0] < CLK_PPM_MIN) || |
|---|
| .. | .. |
|---|
| 588 | 641 | i2s->has_capture ? &i2s->capture_dma_data : NULL); |
|---|
| 589 | 642 | |
|---|
| 590 | 643 | if (i2s->mclk_calibrate) |
|---|
| 591 | | - snd_soc_add_dai_controls(dai, &rockchip_i2s_compensation_control, 1); |
|---|
| 644 | + snd_soc_add_component_controls(dai->component, |
|---|
| 645 | + &rockchip_i2s_compensation_control, |
|---|
| 646 | + 1); |
|---|
| 592 | 647 | |
|---|
| 593 | 648 | return 0; |
|---|
| 594 | 649 | } |
|---|
| 595 | 650 | |
|---|
| 651 | +static int rockchip_i2s_startup(struct snd_pcm_substream *substream, |
|---|
| 652 | + struct snd_soc_dai *dai) |
|---|
| 653 | +{ |
|---|
| 654 | + struct rk_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai); |
|---|
| 655 | + int stream = substream->stream; |
|---|
| 656 | + |
|---|
| 657 | + if (i2s->substreams[stream]) |
|---|
| 658 | + return -EBUSY; |
|---|
| 659 | + |
|---|
| 660 | + if (i2s->wait_time[stream]) |
|---|
| 661 | + substream->wait_time = msecs_to_jiffies(i2s->wait_time[stream]); |
|---|
| 662 | + |
|---|
| 663 | + i2s->substreams[stream] = substream; |
|---|
| 664 | + |
|---|
| 665 | + return 0; |
|---|
| 666 | +} |
|---|
| 667 | + |
|---|
| 668 | +static void rockchip_i2s_shutdown(struct snd_pcm_substream *substream, |
|---|
| 669 | + struct snd_soc_dai *dai) |
|---|
| 670 | +{ |
|---|
| 671 | + struct rk_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai); |
|---|
| 672 | + |
|---|
| 673 | + i2s->substreams[substream->stream] = NULL; |
|---|
| 674 | +} |
|---|
| 675 | + |
|---|
| 596 | 676 | static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = { |
|---|
| 677 | + .startup = rockchip_i2s_startup, |
|---|
| 678 | + .shutdown = rockchip_i2s_shutdown, |
|---|
| 597 | 679 | .hw_params = rockchip_i2s_hw_params, |
|---|
| 680 | + .hw_free = rockchip_i2s_hw_free, |
|---|
| 598 | 681 | .set_bclk_ratio = rockchip_i2s_set_bclk_ratio, |
|---|
| 599 | 682 | .set_sysclk = rockchip_i2s_set_sysclk, |
|---|
| 600 | 683 | .set_fmt = rockchip_i2s_set_fmt, |
|---|
| .. | .. |
|---|
| 606 | 689 | .ops = &rockchip_i2s_dai_ops, |
|---|
| 607 | 690 | }; |
|---|
| 608 | 691 | |
|---|
| 692 | +static int rockchip_i2s_get_bclk_ratio(struct snd_kcontrol *kcontrol, |
|---|
| 693 | + struct snd_ctl_elem_value *ucontrol) |
|---|
| 694 | +{ |
|---|
| 695 | + struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol); |
|---|
| 696 | + struct rk_i2s_dev *i2s = snd_soc_component_get_drvdata(compnt); |
|---|
| 697 | + |
|---|
| 698 | + ucontrol->value.integer.value[0] = i2s->bclk_ratio; |
|---|
| 699 | + |
|---|
| 700 | + return 0; |
|---|
| 701 | +} |
|---|
| 702 | + |
|---|
| 703 | +static int rockchip_i2s_put_bclk_ratio(struct snd_kcontrol *kcontrol, |
|---|
| 704 | + struct snd_ctl_elem_value *ucontrol) |
|---|
| 705 | +{ |
|---|
| 706 | + struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol); |
|---|
| 707 | + struct rk_i2s_dev *i2s = snd_soc_component_get_drvdata(compnt); |
|---|
| 708 | + int value = ucontrol->value.integer.value[0]; |
|---|
| 709 | + |
|---|
| 710 | + if (value == i2s->bclk_ratio) |
|---|
| 711 | + return 0; |
|---|
| 712 | + |
|---|
| 713 | + i2s->bclk_ratio = value; |
|---|
| 714 | + |
|---|
| 715 | + return 1; |
|---|
| 716 | +} |
|---|
| 717 | + |
|---|
| 718 | +static int rockchip_i2s_wait_time_info(struct snd_kcontrol *kcontrol, |
|---|
| 719 | + struct snd_ctl_elem_info *uinfo) |
|---|
| 720 | +{ |
|---|
| 721 | + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
|---|
| 722 | + uinfo->count = 1; |
|---|
| 723 | + uinfo->value.integer.min = 0; |
|---|
| 724 | + uinfo->value.integer.max = WAIT_TIME_MS_MAX; |
|---|
| 725 | + uinfo->value.integer.step = 1; |
|---|
| 726 | + |
|---|
| 727 | + return 0; |
|---|
| 728 | +} |
|---|
| 729 | + |
|---|
| 730 | +static int rockchip_i2s_rd_wait_time_get(struct snd_kcontrol *kcontrol, |
|---|
| 731 | + struct snd_ctl_elem_value *ucontrol) |
|---|
| 732 | +{ |
|---|
| 733 | + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
|---|
| 734 | + struct rk_i2s_dev *i2s = snd_soc_component_get_drvdata(component); |
|---|
| 735 | + |
|---|
| 736 | + ucontrol->value.integer.value[0] = i2s->wait_time[SNDRV_PCM_STREAM_CAPTURE]; |
|---|
| 737 | + |
|---|
| 738 | + return 0; |
|---|
| 739 | +} |
|---|
| 740 | + |
|---|
| 741 | +static int rockchip_i2s_rd_wait_time_put(struct snd_kcontrol *kcontrol, |
|---|
| 742 | + struct snd_ctl_elem_value *ucontrol) |
|---|
| 743 | +{ |
|---|
| 744 | + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
|---|
| 745 | + struct rk_i2s_dev *i2s = snd_soc_component_get_drvdata(component); |
|---|
| 746 | + |
|---|
| 747 | + if (ucontrol->value.integer.value[0] > WAIT_TIME_MS_MAX) |
|---|
| 748 | + return -EINVAL; |
|---|
| 749 | + |
|---|
| 750 | + i2s->wait_time[SNDRV_PCM_STREAM_CAPTURE] = ucontrol->value.integer.value[0]; |
|---|
| 751 | + |
|---|
| 752 | + return 1; |
|---|
| 753 | +} |
|---|
| 754 | + |
|---|
| 755 | +static int rockchip_i2s_wr_wait_time_get(struct snd_kcontrol *kcontrol, |
|---|
| 756 | + struct snd_ctl_elem_value *ucontrol) |
|---|
| 757 | +{ |
|---|
| 758 | + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
|---|
| 759 | + struct rk_i2s_dev *i2s = snd_soc_component_get_drvdata(component); |
|---|
| 760 | + |
|---|
| 761 | + ucontrol->value.integer.value[0] = i2s->wait_time[SNDRV_PCM_STREAM_PLAYBACK]; |
|---|
| 762 | + |
|---|
| 763 | + return 0; |
|---|
| 764 | +} |
|---|
| 765 | + |
|---|
| 766 | +static int rockchip_i2s_wr_wait_time_put(struct snd_kcontrol *kcontrol, |
|---|
| 767 | + struct snd_ctl_elem_value *ucontrol) |
|---|
| 768 | +{ |
|---|
| 769 | + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
|---|
| 770 | + struct rk_i2s_dev *i2s = snd_soc_component_get_drvdata(component); |
|---|
| 771 | + |
|---|
| 772 | + if (ucontrol->value.integer.value[0] > WAIT_TIME_MS_MAX) |
|---|
| 773 | + return -EINVAL; |
|---|
| 774 | + |
|---|
| 775 | + i2s->wait_time[SNDRV_PCM_STREAM_PLAYBACK] = ucontrol->value.integer.value[0]; |
|---|
| 776 | + |
|---|
| 777 | + return 1; |
|---|
| 778 | +} |
|---|
| 779 | + |
|---|
| 780 | +#define SAI_PCM_WAIT_TIME(xname, xhandler_get, xhandler_put) \ |
|---|
| 781 | +{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, \ |
|---|
| 782 | + .info = rockchip_i2s_wait_time_info, \ |
|---|
| 783 | + .get = xhandler_get, .put = xhandler_put } |
|---|
| 784 | + |
|---|
| 785 | +static const struct snd_kcontrol_new rockchip_i2s_snd_controls[] = { |
|---|
| 786 | + SOC_SINGLE_EXT("BCLK Ratio", 0, 0, INT_MAX, 0, |
|---|
| 787 | + rockchip_i2s_get_bclk_ratio, |
|---|
| 788 | + rockchip_i2s_put_bclk_ratio), |
|---|
| 789 | + |
|---|
| 790 | + SAI_PCM_WAIT_TIME("PCM Read Wait Time MS", |
|---|
| 791 | + rockchip_i2s_rd_wait_time_get, |
|---|
| 792 | + rockchip_i2s_rd_wait_time_put), |
|---|
| 793 | + SAI_PCM_WAIT_TIME("PCM Write Wait Time MS", |
|---|
| 794 | + rockchip_i2s_wr_wait_time_get, |
|---|
| 795 | + rockchip_i2s_wr_wait_time_put), |
|---|
| 796 | +}; |
|---|
| 797 | + |
|---|
| 609 | 798 | static const struct snd_soc_component_driver rockchip_i2s_component = { |
|---|
| 610 | 799 | .name = DRV_NAME, |
|---|
| 800 | + .controls = rockchip_i2s_snd_controls, |
|---|
| 801 | + .num_controls = ARRAY_SIZE(rockchip_i2s_snd_controls), |
|---|
| 611 | 802 | }; |
|---|
| 612 | 803 | |
|---|
| 613 | 804 | static bool rockchip_i2s_wr_reg(struct device *dev, unsigned int reg) |
|---|
| .. | .. |
|---|
| 639 | 830 | case I2S_CLR: |
|---|
| 640 | 831 | case I2S_TXDR: |
|---|
| 641 | 832 | case I2S_RXDR: |
|---|
| 642 | | - case I2S_FIFOLR: |
|---|
| 833 | + case I2S_TXFIFOLR: |
|---|
| 834 | + case I2S_RXFIFOLR: |
|---|
| 643 | 835 | case I2S_INTSR: |
|---|
| 644 | 836 | return true; |
|---|
| 645 | 837 | default: |
|---|
| .. | .. |
|---|
| 652 | 844 | switch (reg) { |
|---|
| 653 | 845 | case I2S_INTSR: |
|---|
| 654 | 846 | case I2S_CLR: |
|---|
| 655 | | - case I2S_FIFOLR: |
|---|
| 847 | + case I2S_TXFIFOLR: |
|---|
| 848 | + case I2S_RXFIFOLR: |
|---|
| 656 | 849 | case I2S_TXDR: |
|---|
| 657 | 850 | case I2S_RXDR: |
|---|
| 658 | 851 | return true; |
|---|
| .. | .. |
|---|
| 772 | 965 | SNDRV_PCM_FMTBIT_S16_LE | |
|---|
| 773 | 966 | SNDRV_PCM_FMTBIT_S20_3LE | |
|---|
| 774 | 967 | SNDRV_PCM_FMTBIT_S24_LE | |
|---|
| 775 | | - SNDRV_PCM_FMTBIT_S32_LE; |
|---|
| 968 | + SNDRV_PCM_FMTBIT_S32_LE | |
|---|
| 969 | + SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE; |
|---|
| 776 | 970 | |
|---|
| 777 | 971 | i2s->playback_dma_data.addr = res->start + I2S_TXDR; |
|---|
| 778 | 972 | i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; |
|---|
| 779 | 973 | i2s->playback_dma_data.maxburst = 8; |
|---|
| 780 | 974 | |
|---|
| 781 | | - if (!of_property_read_u32(node, "rockchip,playback-channels", &val)) { |
|---|
| 975 | + if (!device_property_read_u32(i2s->dev, "rockchip,playback-channels", &val)) { |
|---|
| 782 | 976 | if (val >= 2 && val <= 8) |
|---|
| 783 | 977 | dai->playback.channels_max = val; |
|---|
| 784 | 978 | } |
|---|
| .. | .. |
|---|
| 793 | 987 | SNDRV_PCM_FMTBIT_S16_LE | |
|---|
| 794 | 988 | SNDRV_PCM_FMTBIT_S20_3LE | |
|---|
| 795 | 989 | SNDRV_PCM_FMTBIT_S24_LE | |
|---|
| 796 | | - SNDRV_PCM_FMTBIT_S32_LE; |
|---|
| 990 | + SNDRV_PCM_FMTBIT_S32_LE | |
|---|
| 991 | + SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE; |
|---|
| 797 | 992 | |
|---|
| 798 | 993 | i2s->capture_dma_data.addr = res->start + I2S_RXDR; |
|---|
| 799 | 994 | i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; |
|---|
| 800 | 995 | i2s->capture_dma_data.maxburst = 8; |
|---|
| 801 | 996 | |
|---|
| 802 | | - if (!of_property_read_u32(node, "rockchip,capture-channels", &val)) { |
|---|
| 997 | + if (!device_property_read_u32(i2s->dev, "rockchip,capture-channels", &val)) { |
|---|
| 803 | 998 | if (val >= 2 && val <= 8) |
|---|
| 804 | 999 | dai->capture.channels_max = val; |
|---|
| 805 | 1000 | } |
|---|
| 806 | 1001 | } |
|---|
| 807 | 1002 | |
|---|
| 808 | 1003 | i2s->clk_trcm = I2S_CKR_TRCM_TXRX; |
|---|
| 809 | | - if (!of_property_read_u32(node, "rockchip,clk-trcm", &val)) { |
|---|
| 1004 | + if (!device_property_read_u32(i2s->dev, "rockchip,clk-trcm", &val)) { |
|---|
| 810 | 1005 | if (val >= 0 && val <= 2) { |
|---|
| 811 | 1006 | i2s->clk_trcm = val << I2S_CKR_TRCM_SHIFT; |
|---|
| 812 | 1007 | if (i2s->clk_trcm) |
|---|
| .. | .. |
|---|
| 823 | 1018 | return 0; |
|---|
| 824 | 1019 | } |
|---|
| 825 | 1020 | |
|---|
| 1021 | +static int rockchip_i2s_keep_clk_always_on(struct rk_i2s_dev *i2s) |
|---|
| 1022 | +{ |
|---|
| 1023 | + unsigned int mclk_rate = DEFAULT_FS * DEFAULT_MCLK_FS; |
|---|
| 1024 | + unsigned int bclk_rate = i2s->bclk_ratio * DEFAULT_FS; |
|---|
| 1025 | + unsigned int div_lrck = i2s->bclk_ratio; |
|---|
| 1026 | + unsigned int div_bclk; |
|---|
| 1027 | + |
|---|
| 1028 | + div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate); |
|---|
| 1029 | + |
|---|
| 1030 | + /* assign generic freq */ |
|---|
| 1031 | + clk_set_rate(i2s->mclk, mclk_rate); |
|---|
| 1032 | + |
|---|
| 1033 | + regmap_update_bits(i2s->regmap, I2S_CKR, |
|---|
| 1034 | + I2S_CKR_MDIV_MASK, |
|---|
| 1035 | + I2S_CKR_MDIV(div_bclk)); |
|---|
| 1036 | + regmap_update_bits(i2s->regmap, I2S_CKR, |
|---|
| 1037 | + I2S_CKR_TSD_MASK | |
|---|
| 1038 | + I2S_CKR_RSD_MASK, |
|---|
| 1039 | + I2S_CKR_TSD(div_lrck) | |
|---|
| 1040 | + I2S_CKR_RSD(div_lrck)); |
|---|
| 1041 | + regmap_update_bits(i2s->regmap, I2S_XFER, |
|---|
| 1042 | + I2S_XFER_TXS_START | I2S_XFER_RXS_START, |
|---|
| 1043 | + I2S_XFER_TXS_START | I2S_XFER_RXS_START); |
|---|
| 1044 | + |
|---|
| 1045 | + pm_runtime_forbid(i2s->dev); |
|---|
| 1046 | + |
|---|
| 1047 | + dev_info(i2s->dev, "CLK-ALWAYS-ON: mclk: %d, bclk: %d, fsync: %d\n", |
|---|
| 1048 | + mclk_rate, bclk_rate, DEFAULT_FS); |
|---|
| 1049 | + |
|---|
| 1050 | + return 0; |
|---|
| 1051 | +} |
|---|
| 1052 | + |
|---|
| 1053 | +static int rockchip_i2s_get_fifo_count(struct device *dev, |
|---|
| 1054 | + struct snd_pcm_substream *substream) |
|---|
| 1055 | +{ |
|---|
| 1056 | + struct rk_i2s_dev *i2s = dev_get_drvdata(dev); |
|---|
| 1057 | + unsigned int tx, rx; |
|---|
| 1058 | + int val = 0; |
|---|
| 1059 | + |
|---|
| 1060 | + regmap_read(i2s->regmap, I2S_TXFIFOLR, &tx); |
|---|
| 1061 | + regmap_read(i2s->regmap, I2S_RXFIFOLR, &rx); |
|---|
| 1062 | + |
|---|
| 1063 | + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
|---|
| 1064 | + val = I2S_FIFOLR_XFL3(tx) + |
|---|
| 1065 | + I2S_FIFOLR_XFL2(tx) + |
|---|
| 1066 | + I2S_FIFOLR_XFL1(tx) + |
|---|
| 1067 | + I2S_FIFOLR_XFL0(tx); |
|---|
| 1068 | + else |
|---|
| 1069 | + /* XFL4 is compatible for old version */ |
|---|
| 1070 | + val = I2S_FIFOLR_XFL4(tx) + |
|---|
| 1071 | + I2S_FIFOLR_XFL3(rx) + |
|---|
| 1072 | + I2S_FIFOLR_XFL2(rx) + |
|---|
| 1073 | + I2S_FIFOLR_XFL1(rx) + |
|---|
| 1074 | + I2S_FIFOLR_XFL0(rx); |
|---|
| 1075 | + |
|---|
| 1076 | + return val; |
|---|
| 1077 | +} |
|---|
| 1078 | + |
|---|
| 1079 | +static const struct snd_dlp_config dconfig = { |
|---|
| 1080 | + .get_fifo_count = rockchip_i2s_get_fifo_count, |
|---|
| 1081 | +}; |
|---|
| 1082 | + |
|---|
| 826 | 1083 | static int rockchip_i2s_probe(struct platform_device *pdev) |
|---|
| 827 | 1084 | { |
|---|
| 828 | 1085 | struct device_node *node = pdev->dev.of_node; |
|---|
| .. | .. |
|---|
| 831 | 1088 | struct snd_soc_dai_driver *dai; |
|---|
| 832 | 1089 | struct resource *res; |
|---|
| 833 | 1090 | void __iomem *regs; |
|---|
| 834 | | - int ret; |
|---|
| 1091 | + int ret, i, val; |
|---|
| 835 | 1092 | |
|---|
| 836 | 1093 | i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); |
|---|
| 837 | 1094 | if (!i2s) |
|---|
| .. | .. |
|---|
| 849 | 1106 | i2s->pins = of_id->data; |
|---|
| 850 | 1107 | } |
|---|
| 851 | 1108 | |
|---|
| 1109 | + for (i = 0; i < ARRAY_SIZE(of_quirks); i++) |
|---|
| 1110 | + if (device_property_read_bool(i2s->dev, of_quirks[i].quirk)) |
|---|
| 1111 | + i2s->quirks |= of_quirks[i].id; |
|---|
| 1112 | + |
|---|
| 852 | 1113 | regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); |
|---|
| 853 | 1114 | if (IS_ERR(regs)) |
|---|
| 854 | 1115 | return PTR_ERR(regs); |
|---|
| .. | .. |
|---|
| 862 | 1123 | } |
|---|
| 863 | 1124 | |
|---|
| 864 | 1125 | i2s->bclk_ratio = 64; |
|---|
| 1126 | + if (!device_property_read_u32(&pdev->dev, "rockchip,bclk-fs", &val)) { |
|---|
| 1127 | + if ((val >= 32) && (val % 2 == 0)) |
|---|
| 1128 | + i2s->bclk_ratio = val; |
|---|
| 1129 | + } |
|---|
| 865 | 1130 | |
|---|
| 866 | 1131 | dev_set_drvdata(&pdev->dev, i2s); |
|---|
| 867 | 1132 | |
|---|
| 868 | 1133 | i2s->mclk_calibrate = |
|---|
| 869 | | - of_property_read_bool(node, "rockchip,mclk-calibrate"); |
|---|
| 1134 | + device_property_read_bool(&pdev->dev, "rockchip,mclk-calibrate"); |
|---|
| 870 | 1135 | if (i2s->mclk_calibrate) { |
|---|
| 871 | 1136 | i2s->mclk_root = devm_clk_get(&pdev->dev, "i2s_clk_root"); |
|---|
| 872 | 1137 | if (IS_ERR(i2s->mclk_root)) |
|---|
| .. | .. |
|---|
| 894 | 1159 | return ret; |
|---|
| 895 | 1160 | } |
|---|
| 896 | 1161 | |
|---|
| 1162 | + ret = rockchip_i2s_init_dai(i2s, res, &dai); |
|---|
| 1163 | + if (ret) |
|---|
| 1164 | + goto err_clk; |
|---|
| 1165 | + |
|---|
| 1166 | + /* |
|---|
| 1167 | + * CLK_ALWAYS_ON should be placed after all registers write done, |
|---|
| 1168 | + * because this situation will enable XFER bit which will make |
|---|
| 1169 | + * some registers(depend on XFER) write failed. |
|---|
| 1170 | + */ |
|---|
| 1171 | + if (i2s->quirks & QUIRK_ALWAYS_ON) { |
|---|
| 1172 | + ret = rockchip_i2s_keep_clk_always_on(i2s); |
|---|
| 1173 | + if (ret) |
|---|
| 1174 | + goto err_clk; |
|---|
| 1175 | + } |
|---|
| 1176 | + |
|---|
| 1177 | + /* |
|---|
| 1178 | + * MUST: after pm_runtime_enable step, any register R/W |
|---|
| 1179 | + * should be wrapped with pm_runtime_get_sync/put. |
|---|
| 1180 | + * |
|---|
| 1181 | + * Another approach is to enable the regcache true to |
|---|
| 1182 | + * avoid access HW registers. |
|---|
| 1183 | + * |
|---|
| 1184 | + * Alternatively, performing the registers R/W before |
|---|
| 1185 | + * pm_runtime_enable is also a good option. |
|---|
| 1186 | + */ |
|---|
| 897 | 1187 | pm_runtime_enable(&pdev->dev); |
|---|
| 898 | 1188 | if (!pm_runtime_enabled(&pdev->dev)) { |
|---|
| 899 | 1189 | ret = i2s_runtime_resume(&pdev->dev); |
|---|
| 900 | 1190 | if (ret) |
|---|
| 901 | 1191 | goto err_pm_disable; |
|---|
| 902 | 1192 | } |
|---|
| 903 | | - |
|---|
| 904 | | - ret = rockchip_i2s_init_dai(i2s, res, &dai); |
|---|
| 905 | | - if (ret) |
|---|
| 906 | | - goto err_pm_disable; |
|---|
| 907 | 1193 | |
|---|
| 908 | 1194 | ret = devm_snd_soc_register_component(&pdev->dev, |
|---|
| 909 | 1195 | &rockchip_i2s_component, |
|---|
| .. | .. |
|---|
| 914 | 1200 | goto err_suspend; |
|---|
| 915 | 1201 | } |
|---|
| 916 | 1202 | |
|---|
| 917 | | - if (of_property_read_bool(node, "rockchip,no-dmaengine")) { |
|---|
| 1203 | + if (device_property_read_bool(&pdev->dev, "rockchip,no-dmaengine")) { |
|---|
| 918 | 1204 | dev_info(&pdev->dev, "Used for Multi-DAI\n"); |
|---|
| 919 | 1205 | return 0; |
|---|
| 920 | 1206 | } |
|---|
| 921 | 1207 | |
|---|
| 922 | | - ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); |
|---|
| 1208 | + if (device_property_read_bool(&pdev->dev, "rockchip,digital-loopback")) |
|---|
| 1209 | + ret = devm_snd_dmaengine_dlp_register(&pdev->dev, &dconfig); |
|---|
| 1210 | + else |
|---|
| 1211 | + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); |
|---|
| 1212 | + |
|---|
| 923 | 1213 | if (ret) { |
|---|
| 924 | 1214 | dev_err(&pdev->dev, "Could not register PCM\n"); |
|---|
| 925 | 1215 | goto err_suspend; |
|---|
| .. | .. |
|---|
| 932 | 1222 | i2s_runtime_suspend(&pdev->dev); |
|---|
| 933 | 1223 | err_pm_disable: |
|---|
| 934 | 1224 | pm_runtime_disable(&pdev->dev); |
|---|
| 935 | | - |
|---|
| 1225 | +err_clk: |
|---|
| 936 | 1226 | clk_disable_unprepare(i2s->hclk); |
|---|
| 937 | 1227 | |
|---|
| 938 | 1228 | return ret; |
|---|