Skip to content

Commit 52ea7c0

Browse files
SFxingyuwubroonie
authored andcommitted
ASoC: dwc: i2s: Add StarFive JH7110 SoC support
Add StarFive JH7110(TX0/TX1/RX channels) SoC support in the designware I2S driver and a flag to check if it is on the JH7110 SoC. These channels need to enable clocks, resets and syscon register on the JH7110 SoC. So add init ops in platform data for the JH7110 SoC to do this. Their resets should be deassert before changing the parent of clocks so these are done in the init ops of platform data. The I2S controllers use DMA controller by platform data on the JH7110 and their settings about snd_dmaengine_dai_dma_data() should be added in the dw_configure_dai_by_pd(). And use dmaengine PCM registration if these do not have IRQ on the JH7110 SoC. Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com> Link: https://lore.kernel.org/r/20230821144151.207339-4-xingyu.wu@starfivetech.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent d6d6c51 commit 52ea7c0

File tree

3 files changed

+287
-21
lines changed

3 files changed

+287
-21
lines changed

include/sound/designware_i2s.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ struct i2s_clk_config_data {
2121
u32 sample_rate;
2222
};
2323

24+
struct dw_i2s_dev;
25+
2426
struct i2s_platform_data {
2527
#define DWC_I2S_PLAY (1 << 0)
2628
#define DWC_I2S_RECORD (1 << 1)
@@ -42,6 +44,7 @@ struct i2s_platform_data {
4244
void *capture_dma_data;
4345
bool (*filter)(struct dma_chan *chan, void *slave);
4446
int (*i2s_clk_cfg)(struct i2s_clk_config_data *config);
47+
int (*i2s_pd_init)(struct dw_i2s_dev *dev);
4548
};
4649

4750
struct i2s_dma_data {

sound/soc/dwc/dwc-i2s.c

Lines changed: 283 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
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+
230247
static 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

454471
static 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+
692916
static 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+
8241083
static 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

Comments
 (0)