Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add I2S support for the StarFive JH7110 SoC

Merge series from Xingyu Wu <xingyu.wu@starfivetech.com>:

This patch series adds I2S support for the StarFive JH7110 RISC-V
SoC based on Designware I2S controller. There has three I2S channels
(RX/TX0/TX1) on the JH7110 SoC, one of which is for record(RX) and
two for playback(TX).

The first patch adds support for the StarFive JH7110 SoC in the
Designware I2S bindings.
The second patch adds the ops to get data from platform bus in the
I2S driver.
The third patch adds support for the StarFive JH7110 SoC in
the Designware I2S driver.
The fourth patch fixes the name of I2STX1 pinmux.
The last patch adds device node of I2S RX/TX0/TX1 in JH7110 dts.

This patch series is based on Linux-next(20230818) which is merge
clock, syscon and dma nodes for the StarFive JH7110 SoC.

The series has been tested and works normally on the VisionFive 2
board by plugging an audio expansion board.

+394 -26
+105 -3
Documentation/devicetree/bindings/sound/snps,designware-i2s.yaml
··· 17 17 - const: snps,designware-i2s 18 18 - enum: 19 19 - snps,designware-i2s 20 + - starfive,jh7110-i2stx0 21 + - starfive,jh7110-i2stx1 22 + - starfive,jh7110-i2srx 20 23 21 24 reg: 22 25 maxItems: 1 ··· 32 29 maxItems: 1 33 30 34 31 clocks: 35 - description: Sampling rate reference clock 36 - maxItems: 1 32 + items: 33 + - description: Sampling rate reference clock 34 + - description: APB clock 35 + - description: Audio master clock 36 + - description: Inner audio master clock source 37 + - description: External audio master clock source 38 + - description: Bit clock 39 + - description: Left/right channel clock 40 + - description: External bit clock 41 + - description: External left/right channel clock 42 + minItems: 1 37 43 38 44 clock-names: 39 - const: i2sclk 45 + items: 46 + - const: i2sclk 47 + - const: apb 48 + - const: mclk 49 + - const: mclk_inner 50 + - const: mclk_ext 51 + - const: bclk 52 + - const: lrck 53 + - const: bclk_ext 54 + - const: lrck_ext 55 + minItems: 1 40 56 41 57 resets: 42 58 items: 43 59 - description: Optional controller resets 60 + - description: controller reset of Sampling rate 61 + minItems: 1 44 62 45 63 dmas: 46 64 items: ··· 74 50 - const: tx 75 51 - const: rx 76 52 minItems: 1 53 + 54 + starfive,syscon: 55 + $ref: /schemas/types.yaml#/definitions/phandle-array 56 + items: 57 + - items: 58 + - description: phandle to System Register Controller sys_syscon node. 59 + - description: I2S-rx enabled control offset of SYS_SYSCONSAIF__SYSCFG register. 60 + - description: I2S-rx enabled control mask 61 + description: 62 + The phandle to System Register Controller syscon node and the I2S-rx(ADC) 63 + enabled control offset and mask of SYS_SYSCONSAIF__SYSCFG register. 77 64 78 65 allOf: 79 66 - $ref: dai-common.yaml# ··· 101 66 properties: 102 67 "#sound-dai-cells": 103 68 const: 0 69 + - if: 70 + properties: 71 + compatible: 72 + contains: 73 + const: snps,designware-i2s 74 + then: 75 + properties: 76 + clocks: 77 + maxItems: 1 78 + clock-names: 79 + maxItems: 1 80 + resets: 81 + maxItems: 1 82 + else: 83 + properties: 84 + resets: 85 + minItems: 2 86 + maxItems: 2 87 + - if: 88 + properties: 89 + compatible: 90 + contains: 91 + const: starfive,jh7110-i2stx0 92 + then: 93 + properties: 94 + clocks: 95 + minItems: 5 96 + maxItems: 5 97 + clock-names: 98 + minItems: 5 99 + maxItems: 5 100 + required: 101 + - resets 102 + - if: 103 + properties: 104 + compatible: 105 + contains: 106 + const: starfive,jh7110-i2stx1 107 + then: 108 + properties: 109 + clocks: 110 + minItems: 9 111 + maxItems: 9 112 + clock-names: 113 + minItems: 9 114 + maxItems: 9 115 + required: 116 + - resets 117 + - if: 118 + properties: 119 + compatible: 120 + contains: 121 + const: starfive,jh7110-i2srx 122 + then: 123 + properties: 124 + clocks: 125 + minItems: 9 126 + maxItems: 9 127 + clock-names: 128 + minItems: 9 129 + maxItems: 9 130 + required: 131 + - resets 132 + - starfive,syscon 133 + else: 134 + properties: 135 + starfive,syscon: false 104 136 105 137 required: 106 138 - compatible
+3
include/sound/designware_i2s.h
··· 21 21 u32 sample_rate; 22 22 }; 23 23 24 + struct dw_i2s_dev; 25 + 24 26 struct i2s_platform_data { 25 27 #define DWC_I2S_PLAY (1 << 0) 26 28 #define DWC_I2S_RECORD (1 << 1) ··· 44 42 void *capture_dma_data; 45 43 bool (*filter)(struct dma_chan *chan, void *slave); 46 44 int (*i2s_clk_cfg)(struct i2s_clk_config_data *config); 45 + int (*i2s_pd_init)(struct dw_i2s_dev *dev); 47 46 }; 48 47 49 48 struct i2s_dma_data {
+285 -23
sound/soc/dwc/dwc-i2s.c
··· 16 16 #include <linux/init.h> 17 17 #include <linux/io.h> 18 18 #include <linux/interrupt.h> 19 + #include <linux/mfd/syscon.h> 19 20 #include <linux/module.h> 20 21 #include <linux/reset.h> 21 22 #include <linux/slab.h> ··· 199 198 else 200 199 i2s_write_reg(dev->i2s_base, IRER, 1); 201 200 202 - if (dev->use_pio) 201 + /* I2S needs to enable IRQ to make a handshake with DMAC on the JH7110 SoC */ 202 + if (dev->use_pio || dev->is_jh7110) 203 203 i2s_enable_irqs(dev, substream->stream, config->chan_nr); 204 204 else 205 205 i2s_enable_dma(dev, substream->stream); ··· 218 216 else 219 217 i2s_write_reg(dev->i2s_base, IRER, 0); 220 218 221 - if (dev->use_pio) 219 + if (dev->use_pio || dev->is_jh7110) 222 220 i2s_disable_irqs(dev, substream->stream, 8); 223 221 else 224 222 i2s_disable_dma(dev, substream->stream); ··· 227 225 i2s_write_reg(dev->i2s_base, CER, 0); 228 226 i2s_write_reg(dev->i2s_base, IER, 0); 229 227 } 228 + } 229 + 230 + static int dw_i2s_startup(struct snd_pcm_substream *substream, 231 + struct snd_soc_dai *cpu_dai) 232 + { 233 + struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); 234 + 235 + if (dev->is_jh7110) { 236 + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 237 + struct snd_soc_dai_link *dai_link = rtd->dai_link; 238 + 239 + dai_link->trigger_stop = SND_SOC_TRIGGER_ORDER_LDC; 240 + } 241 + 242 + return 0; 230 243 } 231 244 232 245 static void dw_i2s_config(struct dw_i2s_dev *dev, int stream) ··· 470 453 471 454 static const struct snd_soc_dai_ops dw_i2s_dai_ops = { 472 455 .probe = dw_i2s_dai_probe, 456 + .startup = dw_i2s_startup, 473 457 .hw_params = dw_i2s_hw_params, 474 458 .prepare = dw_i2s_prepare, 475 459 .trigger = dw_i2s_trigger, ··· 655 637 656 638 if (dev->quirks & DW_I2S_QUIRK_16BIT_IDX_OVERRIDE) 657 639 idx = 1; 658 - /* Set DMA slaves info */ 659 - dev->play_dma_data.pd.data = pdata->play_dma_data; 660 - dev->capture_dma_data.pd.data = pdata->capture_dma_data; 661 - dev->play_dma_data.pd.addr = res->start + I2S_TXDMA; 662 - dev->capture_dma_data.pd.addr = res->start + I2S_RXDMA; 663 - dev->play_dma_data.pd.max_burst = 16; 664 - dev->capture_dma_data.pd.max_burst = 16; 665 - dev->play_dma_data.pd.addr_width = bus_widths[idx]; 666 - dev->capture_dma_data.pd.addr_width = bus_widths[idx]; 667 - dev->play_dma_data.pd.filter = pdata->filter; 668 - dev->capture_dma_data.pd.filter = pdata->filter; 640 + 641 + if (dev->is_jh7110) { 642 + /* Use platform data and snd_dmaengine_dai_dma_data struct at the same time */ 643 + u32 comp2 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_2); 644 + u32 idx2; 645 + 646 + if (COMP1_TX_ENABLED(comp1)) { 647 + idx2 = COMP1_TX_WORDSIZE_0(comp1); 648 + dev->play_dma_data.dt.addr = res->start + I2S_TXDMA; 649 + dev->play_dma_data.dt.fifo_size = dev->fifo_th * 2 * 650 + (fifo_width[idx2]) >> 8; 651 + dev->play_dma_data.dt.maxburst = 16; 652 + } 653 + if (COMP1_RX_ENABLED(comp1)) { 654 + idx2 = COMP2_RX_WORDSIZE_0(comp2); 655 + dev->capture_dma_data.dt.addr = res->start + I2S_RXDMA; 656 + dev->capture_dma_data.dt.fifo_size = dev->fifo_th * 2 * 657 + (fifo_width[idx2] >> 8); 658 + dev->capture_dma_data.dt.maxburst = 16; 659 + } 660 + } else { 661 + /* Set DMA slaves info */ 662 + dev->play_dma_data.pd.data = pdata->play_dma_data; 663 + dev->capture_dma_data.pd.data = pdata->capture_dma_data; 664 + dev->play_dma_data.pd.addr = res->start + I2S_TXDMA; 665 + dev->capture_dma_data.pd.addr = res->start + I2S_RXDMA; 666 + dev->play_dma_data.pd.max_burst = 16; 667 + dev->capture_dma_data.pd.max_burst = 16; 668 + dev->play_dma_data.pd.addr_width = bus_widths[idx]; 669 + dev->capture_dma_data.pd.addr_width = bus_widths[idx]; 670 + dev->play_dma_data.pd.filter = pdata->filter; 671 + dev->capture_dma_data.pd.filter = pdata->filter; 672 + } 669 673 670 674 return 0; 671 675 } ··· 729 689 730 690 } 731 691 692 + /* clocks initialization with master mode on JH7110 SoC */ 693 + static int jh7110_i2s_crg_master_init(struct dw_i2s_dev *dev) 694 + { 695 + static struct clk_bulk_data clks[] = { 696 + { .id = "mclk" }, 697 + { .id = "mclk_ext" }, 698 + { .id = "mclk_inner" }, 699 + { .id = "apb" }, 700 + { .id = "i2sclk" }, 701 + }; 702 + struct reset_control *resets = devm_reset_control_array_get_exclusive(dev->dev); 703 + int ret; 704 + struct clk *pclk; 705 + struct clk *bclk_mst; 706 + struct clk *mclk; 707 + struct clk *mclk_ext; 708 + struct clk *mclk_inner; 709 + 710 + if (IS_ERR(resets)) 711 + return dev_err_probe(dev->dev, PTR_ERR(resets), "failed to get i2s resets\n"); 712 + 713 + ret = clk_bulk_get(dev->dev, ARRAY_SIZE(clks), clks); 714 + if (ret) 715 + return dev_err_probe(dev->dev, ret, "failed to get i2s clocks\n"); 716 + 717 + mclk = clks[0].clk; 718 + mclk_ext = clks[1].clk; 719 + mclk_inner = clks[2].clk; 720 + pclk = clks[3].clk; 721 + bclk_mst = clks[4].clk; 722 + 723 + ret = clk_prepare_enable(pclk); 724 + if (ret) 725 + goto exit; 726 + 727 + /* Use inner mclk first and avoid uninitialized gpio for external mclk */ 728 + ret = clk_set_parent(mclk, mclk_inner); 729 + if (ret) 730 + goto err_dis_pclk; 731 + 732 + ret = clk_prepare_enable(bclk_mst); 733 + if (ret) 734 + goto err_dis_pclk; 735 + 736 + /* deassert resets before set clock parent */ 737 + ret = reset_control_deassert(resets); 738 + if (ret) 739 + goto err_dis_all; 740 + 741 + /* external clock (12.288MHz) for Audio */ 742 + ret = clk_set_parent(mclk, mclk_ext); 743 + if (ret) 744 + goto err_dis_all; 745 + 746 + /* i2sclk will be got and enabled repeatedly later and should be disabled now. */ 747 + clk_disable_unprepare(bclk_mst); 748 + clk_bulk_put(ARRAY_SIZE(clks), clks); 749 + dev->is_jh7110 = true; 750 + 751 + return 0; 752 + 753 + err_dis_all: 754 + clk_disable_unprepare(bclk_mst); 755 + err_dis_pclk: 756 + clk_disable_unprepare(pclk); 757 + exit: 758 + clk_bulk_put(ARRAY_SIZE(clks), clks); 759 + return ret; 760 + } 761 + 762 + /* clocks initialization with slave mode on JH7110 SoC */ 763 + static int jh7110_i2s_crg_slave_init(struct dw_i2s_dev *dev) 764 + { 765 + static struct clk_bulk_data clks[] = { 766 + { .id = "mclk" }, 767 + { .id = "mclk_ext" }, 768 + { .id = "apb" }, 769 + { .id = "bclk_ext" }, 770 + { .id = "lrck_ext" }, 771 + { .id = "bclk" }, 772 + { .id = "lrck" }, 773 + { .id = "mclk_inner" }, 774 + { .id = "i2sclk" }, 775 + }; 776 + struct reset_control *resets = devm_reset_control_array_get_exclusive(dev->dev); 777 + int ret; 778 + struct clk *pclk; 779 + struct clk *bclk_mst; 780 + struct clk *bclk_ext; 781 + struct clk *lrck_ext; 782 + struct clk *bclk; 783 + struct clk *lrck; 784 + struct clk *mclk; 785 + struct clk *mclk_ext; 786 + struct clk *mclk_inner; 787 + 788 + if (IS_ERR(resets)) 789 + return dev_err_probe(dev->dev, PTR_ERR(resets), "failed to get i2s resets\n"); 790 + 791 + ret = clk_bulk_get(dev->dev, ARRAY_SIZE(clks), clks); 792 + if (ret) 793 + return dev_err_probe(dev->dev, ret, "failed to get i2s clocks\n"); 794 + 795 + mclk = clks[0].clk; 796 + mclk_ext = clks[1].clk; 797 + pclk = clks[2].clk; 798 + bclk_ext = clks[3].clk; 799 + lrck_ext = clks[4].clk; 800 + bclk = clks[5].clk; 801 + lrck = clks[6].clk; 802 + mclk_inner = clks[7].clk; 803 + bclk_mst = clks[8].clk; 804 + 805 + ret = clk_prepare_enable(pclk); 806 + if (ret) 807 + goto exit; 808 + 809 + ret = clk_set_parent(mclk, mclk_inner); 810 + if (ret) 811 + goto err_dis_pclk; 812 + 813 + ret = clk_prepare_enable(bclk_mst); 814 + if (ret) 815 + goto err_dis_pclk; 816 + 817 + ret = reset_control_deassert(resets); 818 + if (ret) 819 + goto err_dis_all; 820 + 821 + /* The sources of BCLK and LRCK are the external codec. */ 822 + ret = clk_set_parent(bclk, bclk_ext); 823 + if (ret) 824 + goto err_dis_all; 825 + 826 + ret = clk_set_parent(lrck, lrck_ext); 827 + if (ret) 828 + goto err_dis_all; 829 + 830 + ret = clk_set_parent(mclk, mclk_ext); 831 + if (ret) 832 + goto err_dis_all; 833 + 834 + /* The i2sclk will be got and enabled repeatedly later and should be disabled now. */ 835 + clk_disable_unprepare(bclk_mst); 836 + clk_bulk_put(ARRAY_SIZE(clks), clks); 837 + dev->is_jh7110 = true; 838 + 839 + return 0; 840 + 841 + err_dis_all: 842 + clk_disable_unprepare(bclk_mst); 843 + err_dis_pclk: 844 + clk_disable_unprepare(pclk); 845 + exit: 846 + clk_bulk_put(ARRAY_SIZE(clks), clks); 847 + return ret; 848 + } 849 + 850 + /* Special syscon initialization about RX channel with slave mode on JH7110 SoC */ 851 + static int jh7110_i2srx_crg_init(struct dw_i2s_dev *dev) 852 + { 853 + struct regmap *regmap; 854 + unsigned int args[2]; 855 + 856 + regmap = syscon_regmap_lookup_by_phandle_args(dev->dev->of_node, 857 + "starfive,syscon", 858 + 2, args); 859 + if (IS_ERR(regmap)) 860 + return dev_err_probe(dev->dev, PTR_ERR(regmap), "getting the regmap failed\n"); 861 + 862 + /* Enable I2Srx with syscon register, args[0]: offset, args[1]: mask */ 863 + regmap_update_bits(regmap, args[0], args[1], args[1]); 864 + 865 + return jh7110_i2s_crg_slave_init(dev); 866 + } 867 + 868 + static int jh7110_i2stx0_clk_cfg(struct i2s_clk_config_data *config) 869 + { 870 + struct dw_i2s_dev *dev = container_of(config, struct dw_i2s_dev, config); 871 + u32 bclk_rate = config->sample_rate * 64; 872 + 873 + return clk_set_rate(dev->clk, bclk_rate); 874 + } 875 + 732 876 static int dw_i2s_probe(struct platform_device *pdev) 733 877 { 734 - const struct i2s_platform_data *pdata = pdev->dev.platform_data; 878 + const struct i2s_platform_data *pdata = of_device_get_match_data(&pdev->dev); 735 879 struct dw_i2s_dev *dev; 736 880 struct resource *res; 737 881 int ret, irq; ··· 936 712 if (IS_ERR(dev->i2s_base)) 937 713 return PTR_ERR(dev->i2s_base); 938 714 939 - dev->reset = devm_reset_control_array_get_optional_shared(&pdev->dev); 940 - if (IS_ERR(dev->reset)) 941 - return PTR_ERR(dev->reset); 942 - 943 - ret = reset_control_deassert(dev->reset); 944 - if (ret) 945 - return ret; 946 - 947 715 dev->dev = &pdev->dev; 716 + dev->is_jh7110 = false; 717 + if (pdata) { 718 + if (pdata->i2s_pd_init) { 719 + ret = pdata->i2s_pd_init(dev); 720 + if (ret) 721 + return ret; 722 + } 723 + } 724 + 725 + if (!dev->is_jh7110) { 726 + dev->reset = devm_reset_control_array_get_optional_shared(&pdev->dev); 727 + if (IS_ERR(dev->reset)) 728 + return PTR_ERR(dev->reset); 729 + 730 + ret = reset_control_deassert(dev->reset); 731 + if (ret) 732 + return ret; 733 + } 948 734 949 735 irq = platform_get_irq_optional(pdev, 0); 950 736 if (irq >= 0) { ··· 1013 779 goto err_clk_disable; 1014 780 } 1015 781 1016 - if (!pdata) { 782 + if (!pdata || dev->is_jh7110) { 1017 783 if (irq >= 0) { 1018 784 ret = dw_pcm_register(pdev); 1019 785 dev->use_pio = true; ··· 1055 821 } 1056 822 1057 823 #ifdef CONFIG_OF 824 + static const struct i2s_platform_data jh7110_i2stx0_data = { 825 + .cap = DWC_I2S_PLAY | DW_I2S_MASTER, 826 + .channel = TWO_CHANNEL_SUPPORT, 827 + .snd_fmts = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, 828 + .snd_rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000, 829 + .i2s_clk_cfg = jh7110_i2stx0_clk_cfg, 830 + .i2s_pd_init = jh7110_i2s_crg_master_init, 831 + }; 832 + 833 + static const struct i2s_platform_data jh7110_i2stx1_data = { 834 + .cap = DWC_I2S_PLAY | DW_I2S_SLAVE, 835 + .channel = TWO_CHANNEL_SUPPORT, 836 + .snd_fmts = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, 837 + .snd_rates = SNDRV_PCM_RATE_8000_192000, 838 + .i2s_pd_init = jh7110_i2s_crg_slave_init, 839 + }; 840 + 841 + static const struct i2s_platform_data jh7110_i2srx_data = { 842 + .cap = DWC_I2S_RECORD | DW_I2S_SLAVE, 843 + .channel = TWO_CHANNEL_SUPPORT, 844 + .snd_fmts = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, 845 + .snd_rates = SNDRV_PCM_RATE_8000_192000, 846 + .i2s_pd_init = jh7110_i2srx_crg_init, 847 + }; 848 + 1058 849 static const struct of_device_id dw_i2s_of_match[] = { 1059 850 { .compatible = "snps,designware-i2s", }, 851 + { .compatible = "starfive,jh7110-i2stx0", .data = &jh7110_i2stx0_data, }, 852 + { .compatible = "starfive,jh7110-i2stx1", .data = &jh7110_i2stx1_data,}, 853 + { .compatible = "starfive,jh7110-i2srx", .data = &jh7110_i2srx_data,}, 1060 854 {}, 1061 855 }; 1062 856
+1
sound/soc/dwc/local.h
··· 123 123 u32 fifo_th; 124 124 u32 l_reg; 125 125 u32 r_reg; 126 + bool is_jh7110; /* Flag for StarFive JH7110 SoC */ 126 127 127 128 /* data related to DMA transfers b/w i2s and DMAC */ 128 129 union dw_i2s_snd_dma_data play_dma_data;