1616#include <linux/init.h>
1717#include <linux/io.h>
1818#include <linux/interrupt.h>
19+ #include <linux/mfd/syscon.h>
1920#include <linux/module.h>
2021#include <linux/reset.h>
2122#include <linux/slab.h>
@@ -198,7 +199,8 @@ static void i2s_start(struct dw_i2s_dev *dev,
198199 else
199200 i2s_write_reg (dev -> i2s_base , IRER , 1 );
200201
201- if (dev -> use_pio )
202+ /* I2S needs to enable IRQ to make a handshake with DMAC on the JH7110 SoC */
203+ if (dev -> use_pio || dev -> is_jh7110 )
202204 i2s_enable_irqs (dev , substream -> stream , config -> chan_nr );
203205 else
204206 i2s_enable_dma (dev , substream -> stream );
@@ -216,7 +218,7 @@ static void i2s_stop(struct dw_i2s_dev *dev,
216218 else
217219 i2s_write_reg (dev -> i2s_base , IRER , 0 );
218220
219- if (dev -> use_pio )
221+ if (dev -> use_pio || dev -> is_jh7110 )
220222 i2s_disable_irqs (dev , substream -> stream , 8 );
221223 else
222224 i2s_disable_dma (dev , substream -> stream );
@@ -227,6 +229,21 @@ static void i2s_stop(struct dw_i2s_dev *dev,
227229 }
228230}
229231
232+ static int dw_i2s_startup (struct snd_pcm_substream * substream ,
233+ struct snd_soc_dai * cpu_dai )
234+ {
235+ struct dw_i2s_dev * dev = snd_soc_dai_get_drvdata (cpu_dai );
236+
237+ if (dev -> is_jh7110 ) {
238+ struct snd_soc_pcm_runtime * rtd = asoc_substream_to_rtd (substream );
239+ struct snd_soc_dai_link * dai_link = rtd -> dai_link ;
240+
241+ dai_link -> trigger_stop = SND_SOC_TRIGGER_ORDER_LDC ;
242+ }
243+
244+ return 0 ;
245+ }
246+
230247static void dw_i2s_config (struct dw_i2s_dev * dev , int stream )
231248{
232249 u32 ch_reg ;
@@ -453,6 +470,7 @@ static int dw_i2s_dai_probe(struct snd_soc_dai *dai)
453470
454471static const struct snd_soc_dai_ops dw_i2s_dai_ops = {
455472 .probe = dw_i2s_dai_probe ,
473+ .startup = dw_i2s_startup ,
456474 .hw_params = dw_i2s_hw_params ,
457475 .prepare = dw_i2s_prepare ,
458476 .trigger = dw_i2s_trigger ,
@@ -637,17 +655,39 @@ static int dw_configure_dai_by_pd(struct dw_i2s_dev *dev,
637655
638656 if (dev -> quirks & DW_I2S_QUIRK_16BIT_IDX_OVERRIDE )
639657 idx = 1 ;
640- /* Set DMA slaves info */
641- dev -> play_dma_data .pd .data = pdata -> play_dma_data ;
642- dev -> capture_dma_data .pd .data = pdata -> capture_dma_data ;
643- dev -> play_dma_data .pd .addr = res -> start + I2S_TXDMA ;
644- dev -> capture_dma_data .pd .addr = res -> start + I2S_RXDMA ;
645- dev -> play_dma_data .pd .max_burst = 16 ;
646- dev -> capture_dma_data .pd .max_burst = 16 ;
647- dev -> play_dma_data .pd .addr_width = bus_widths [idx ];
648- dev -> capture_dma_data .pd .addr_width = bus_widths [idx ];
649- dev -> play_dma_data .pd .filter = pdata -> filter ;
650- dev -> capture_dma_data .pd .filter = pdata -> filter ;
658+
659+ if (dev -> is_jh7110 ) {
660+ /* Use platform data and snd_dmaengine_dai_dma_data struct at the same time */
661+ u32 comp2 = i2s_read_reg (dev -> i2s_base , I2S_COMP_PARAM_2 );
662+ u32 idx2 ;
663+
664+ if (COMP1_TX_ENABLED (comp1 )) {
665+ idx2 = COMP1_TX_WORDSIZE_0 (comp1 );
666+ dev -> play_dma_data .dt .addr = res -> start + I2S_TXDMA ;
667+ dev -> play_dma_data .dt .fifo_size = dev -> fifo_th * 2 *
668+ (fifo_width [idx2 ]) >> 8 ;
669+ dev -> play_dma_data .dt .maxburst = 16 ;
670+ }
671+ if (COMP1_RX_ENABLED (comp1 )) {
672+ idx2 = COMP2_RX_WORDSIZE_0 (comp2 );
673+ dev -> capture_dma_data .dt .addr = res -> start + I2S_RXDMA ;
674+ dev -> capture_dma_data .dt .fifo_size = dev -> fifo_th * 2 *
675+ (fifo_width [idx2 ] >> 8 );
676+ dev -> capture_dma_data .dt .maxburst = 16 ;
677+ }
678+ } else {
679+ /* Set DMA slaves info */
680+ dev -> play_dma_data .pd .data = pdata -> play_dma_data ;
681+ dev -> capture_dma_data .pd .data = pdata -> capture_dma_data ;
682+ dev -> play_dma_data .pd .addr = res -> start + I2S_TXDMA ;
683+ dev -> capture_dma_data .pd .addr = res -> start + I2S_RXDMA ;
684+ dev -> play_dma_data .pd .max_burst = 16 ;
685+ dev -> capture_dma_data .pd .max_burst = 16 ;
686+ dev -> play_dma_data .pd .addr_width = bus_widths [idx ];
687+ dev -> capture_dma_data .pd .addr_width = bus_widths [idx ];
688+ dev -> play_dma_data .pd .filter = pdata -> filter ;
689+ dev -> capture_dma_data .pd .filter = pdata -> filter ;
690+ }
651691
652692 return 0 ;
653693}
@@ -689,6 +729,190 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev,
689729
690730}
691731
732+ /* clocks initialization with master mode on JH7110 SoC */
733+ static int jh7110_i2s_crg_master_init (struct dw_i2s_dev * dev )
734+ {
735+ static struct clk_bulk_data clks [] = {
736+ { .id = "mclk" },
737+ { .id = "mclk_ext" },
738+ { .id = "mclk_inner" },
739+ { .id = "apb" },
740+ { .id = "i2sclk" },
741+ };
742+ struct reset_control * resets = devm_reset_control_array_get_exclusive (dev -> dev );
743+ int ret ;
744+ struct clk * pclk ;
745+ struct clk * bclk_mst ;
746+ struct clk * mclk ;
747+ struct clk * mclk_ext ;
748+ struct clk * mclk_inner ;
749+
750+ if (IS_ERR (resets ))
751+ return dev_err_probe (dev -> dev , PTR_ERR (resets ), "failed to get i2s resets\n" );
752+
753+ ret = clk_bulk_get (dev -> dev , ARRAY_SIZE (clks ), clks );
754+ if (ret )
755+ return dev_err_probe (dev -> dev , ret , "failed to get i2s clocks\n" );
756+
757+ mclk = clks [0 ].clk ;
758+ mclk_ext = clks [1 ].clk ;
759+ mclk_inner = clks [2 ].clk ;
760+ pclk = clks [3 ].clk ;
761+ bclk_mst = clks [4 ].clk ;
762+
763+ ret = clk_prepare_enable (pclk );
764+ if (ret )
765+ goto exit ;
766+
767+ /* Use inner mclk first and avoid uninitialized gpio for external mclk */
768+ ret = clk_set_parent (mclk , mclk_inner );
769+ if (ret )
770+ goto err_dis_pclk ;
771+
772+ ret = clk_prepare_enable (bclk_mst );
773+ if (ret )
774+ goto err_dis_pclk ;
775+
776+ /* deassert resets before set clock parent */
777+ ret = reset_control_deassert (resets );
778+ if (ret )
779+ goto err_dis_all ;
780+
781+ /* external clock (12.288MHz) for Audio */
782+ ret = clk_set_parent (mclk , mclk_ext );
783+ if (ret )
784+ goto err_dis_all ;
785+
786+ /* i2sclk will be got and enabled repeatedly later and should be disabled now. */
787+ clk_disable_unprepare (bclk_mst );
788+ clk_bulk_put (ARRAY_SIZE (clks ), clks );
789+ dev -> is_jh7110 = true;
790+
791+ return 0 ;
792+
793+ err_dis_all :
794+ clk_disable_unprepare (bclk_mst );
795+ err_dis_pclk :
796+ clk_disable_unprepare (pclk );
797+ exit :
798+ clk_bulk_put (ARRAY_SIZE (clks ), clks );
799+ return ret ;
800+ }
801+
802+ /* clocks initialization with slave mode on JH7110 SoC */
803+ static int jh7110_i2s_crg_slave_init (struct dw_i2s_dev * dev )
804+ {
805+ static struct clk_bulk_data clks [] = {
806+ { .id = "mclk" },
807+ { .id = "mclk_ext" },
808+ { .id = "apb" },
809+ { .id = "bclk_ext" },
810+ { .id = "lrck_ext" },
811+ { .id = "bclk" },
812+ { .id = "lrck" },
813+ { .id = "mclk_inner" },
814+ { .id = "i2sclk" },
815+ };
816+ struct reset_control * resets = devm_reset_control_array_get_exclusive (dev -> dev );
817+ int ret ;
818+ struct clk * pclk ;
819+ struct clk * bclk_mst ;
820+ struct clk * bclk_ext ;
821+ struct clk * lrck_ext ;
822+ struct clk * bclk ;
823+ struct clk * lrck ;
824+ struct clk * mclk ;
825+ struct clk * mclk_ext ;
826+ struct clk * mclk_inner ;
827+
828+ if (IS_ERR (resets ))
829+ return dev_err_probe (dev -> dev , PTR_ERR (resets ), "failed to get i2s resets\n" );
830+
831+ ret = clk_bulk_get (dev -> dev , ARRAY_SIZE (clks ), clks );
832+ if (ret )
833+ return dev_err_probe (dev -> dev , ret , "failed to get i2s clocks\n" );
834+
835+ mclk = clks [0 ].clk ;
836+ mclk_ext = clks [1 ].clk ;
837+ pclk = clks [2 ].clk ;
838+ bclk_ext = clks [3 ].clk ;
839+ lrck_ext = clks [4 ].clk ;
840+ bclk = clks [5 ].clk ;
841+ lrck = clks [6 ].clk ;
842+ mclk_inner = clks [7 ].clk ;
843+ bclk_mst = clks [8 ].clk ;
844+
845+ ret = clk_prepare_enable (pclk );
846+ if (ret )
847+ goto exit ;
848+
849+ ret = clk_set_parent (mclk , mclk_inner );
850+ if (ret )
851+ goto err_dis_pclk ;
852+
853+ ret = clk_prepare_enable (bclk_mst );
854+ if (ret )
855+ goto err_dis_pclk ;
856+
857+ ret = reset_control_deassert (resets );
858+ if (ret )
859+ goto err_dis_all ;
860+
861+ /* The sources of BCLK and LRCK are the external codec. */
862+ ret = clk_set_parent (bclk , bclk_ext );
863+ if (ret )
864+ goto err_dis_all ;
865+
866+ ret = clk_set_parent (lrck , lrck_ext );
867+ if (ret )
868+ goto err_dis_all ;
869+
870+ ret = clk_set_parent (mclk , mclk_ext );
871+ if (ret )
872+ goto err_dis_all ;
873+
874+ /* The i2sclk will be got and enabled repeatedly later and should be disabled now. */
875+ clk_disable_unprepare (bclk_mst );
876+ clk_bulk_put (ARRAY_SIZE (clks ), clks );
877+ dev -> is_jh7110 = true;
878+
879+ return 0 ;
880+
881+ err_dis_all :
882+ clk_disable_unprepare (bclk_mst );
883+ err_dis_pclk :
884+ clk_disable_unprepare (pclk );
885+ exit :
886+ clk_bulk_put (ARRAY_SIZE (clks ), clks );
887+ return ret ;
888+ }
889+
890+ /* Special syscon initialization about RX channel with slave mode on JH7110 SoC */
891+ static int jh7110_i2srx_crg_init (struct dw_i2s_dev * dev )
892+ {
893+ struct regmap * regmap ;
894+ unsigned int args [2 ];
895+
896+ regmap = syscon_regmap_lookup_by_phandle_args (dev -> dev -> of_node ,
897+ "starfive,syscon" ,
898+ 2 , args );
899+ if (IS_ERR (regmap ))
900+ return dev_err_probe (dev -> dev , PTR_ERR (regmap ), "getting the regmap failed\n" );
901+
902+ /* Enable I2Srx with syscon register, args[0]: offset, args[1]: mask */
903+ regmap_update_bits (regmap , args [0 ], args [1 ], args [1 ]);
904+
905+ return jh7110_i2s_crg_slave_init (dev );
906+ }
907+
908+ static int jh7110_i2stx0_clk_cfg (struct i2s_clk_config_data * config )
909+ {
910+ struct dw_i2s_dev * dev = container_of (config , struct dw_i2s_dev , config );
911+ u32 bclk_rate = config -> sample_rate * 64 ;
912+
913+ return clk_set_rate (dev -> clk , bclk_rate );
914+ }
915+
692916static int dw_i2s_probe (struct platform_device * pdev )
693917{
694918 const struct i2s_platform_data * pdata = of_device_get_match_data (& pdev -> dev );
@@ -712,15 +936,25 @@ static int dw_i2s_probe(struct platform_device *pdev)
712936 if (IS_ERR (dev -> i2s_base ))
713937 return PTR_ERR (dev -> i2s_base );
714938
715- dev -> reset = devm_reset_control_array_get_optional_shared (& pdev -> dev );
716- if (IS_ERR (dev -> reset ))
717- return PTR_ERR (dev -> reset );
939+ dev -> dev = & pdev -> dev ;
940+ dev -> is_jh7110 = false;
941+ if (pdata ) {
942+ if (pdata -> i2s_pd_init ) {
943+ ret = pdata -> i2s_pd_init (dev );
944+ if (ret )
945+ return ret ;
946+ }
947+ }
718948
719- ret = reset_control_deassert (dev -> reset );
720- if (ret )
721- return ret ;
949+ if (!dev -> is_jh7110 ) {
950+ dev -> reset = devm_reset_control_array_get_optional_shared (& pdev -> dev );
951+ if (IS_ERR (dev -> reset ))
952+ return PTR_ERR (dev -> reset );
722953
723- dev -> dev = & pdev -> dev ;
954+ ret = reset_control_deassert (dev -> reset );
955+ if (ret )
956+ return ret ;
957+ }
724958
725959 irq = platform_get_irq_optional (pdev , 0 );
726960 if (irq >= 0 ) {
@@ -779,7 +1013,7 @@ static int dw_i2s_probe(struct platform_device *pdev)
7791013 goto err_clk_disable ;
7801014 }
7811015
782- if (!pdata ) {
1016+ if (!pdata || dev -> is_jh7110 ) {
7831017 if (irq >= 0 ) {
7841018 ret = dw_pcm_register (pdev );
7851019 dev -> use_pio = true;
@@ -821,8 +1055,36 @@ static void dw_i2s_remove(struct platform_device *pdev)
8211055}
8221056
8231057#ifdef CONFIG_OF
1058+ static const struct i2s_platform_data jh7110_i2stx0_data = {
1059+ .cap = DWC_I2S_PLAY | DW_I2S_MASTER ,
1060+ .channel = TWO_CHANNEL_SUPPORT ,
1061+ .snd_fmts = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE ,
1062+ .snd_rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 ,
1063+ .i2s_clk_cfg = jh7110_i2stx0_clk_cfg ,
1064+ .i2s_pd_init = jh7110_i2s_crg_master_init ,
1065+ };
1066+
1067+ static const struct i2s_platform_data jh7110_i2stx1_data = {
1068+ .cap = DWC_I2S_PLAY | DW_I2S_SLAVE ,
1069+ .channel = TWO_CHANNEL_SUPPORT ,
1070+ .snd_fmts = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE ,
1071+ .snd_rates = SNDRV_PCM_RATE_8000_192000 ,
1072+ .i2s_pd_init = jh7110_i2s_crg_slave_init ,
1073+ };
1074+
1075+ static const struct i2s_platform_data jh7110_i2srx_data = {
1076+ .cap = DWC_I2S_RECORD | DW_I2S_SLAVE ,
1077+ .channel = TWO_CHANNEL_SUPPORT ,
1078+ .snd_fmts = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE ,
1079+ .snd_rates = SNDRV_PCM_RATE_8000_192000 ,
1080+ .i2s_pd_init = jh7110_i2srx_crg_init ,
1081+ };
1082+
8241083static const struct of_device_id dw_i2s_of_match [] = {
8251084 { .compatible = "snps,designware-i2s" , },
1085+ { .compatible = "starfive,jh7110-i2stx0" , .data = & jh7110_i2stx0_data , },
1086+ { .compatible = "starfive,jh7110-i2stx1" , .data = & jh7110_i2stx1_data ,},
1087+ { .compatible = "starfive,jh7110-i2srx" , .data = & jh7110_i2srx_data ,},
8261088 {},
8271089};
8281090
0 commit comments