On Sun, 29 Sep 2024 23:06:02 +1300 Ryan Walklin <ryan@xxxxxxxxxxxxx> wrote: Hi, > From: Marcus Cooper <codekipper@xxxxxxxxx> > > The Allwinner H616 SoC uses a different register address to control the > output FIFO. > > Allow this to be specified separately from the ADC FIFO control > register. That looks good to me, it follows the existing regmap_field pattern for the input FIFO, and I can confirm it changes every user of the DAC register. > Signed-off-by: Marcus Cooper <codekipper@xxxxxxxxx> > Signed-off-by: Ryan Walklin <ryan@xxxxxxxxxxxxx> Reviewed-by: Andre Przywara <andre.przywara@xxxxxxx> Cheers, Andre > --- > sound/soc/sunxi/sun4i-codec.c | 83 +++++++++++++++++++++-------------- > 1 file changed, 51 insertions(+), 32 deletions(-) > > diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c > index 330bc0c09f56b..37f5678b55291 100644 > --- a/sound/soc/sunxi/sun4i-codec.c > +++ b/sound/soc/sunxi/sun4i-codec.c > @@ -238,6 +238,8 @@ struct sun4i_codec { > > /* ADC_FIFOC register is at different offset on different SoCs */ > struct regmap_field *reg_adc_fifoc; > + /* DAC_FIFOC register is at different offset on different SoCs */ > + struct regmap_field *reg_dac_fifoc; > > struct snd_dmaengine_dai_dma_data capture_dma_data; > struct snd_dmaengine_dai_dma_data playback_dma_data; > @@ -246,19 +248,19 @@ struct sun4i_codec { > static void sun4i_codec_start_playback(struct sun4i_codec *scodec) > { > /* Flush TX FIFO */ > - regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, > - BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH)); > + regmap_field_set_bits(scodec->reg_dac_fifoc, > + BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH)); > > /* Enable DAC DRQ */ > - regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, > - BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN)); > + regmap_field_set_bits(scodec->reg_dac_fifoc, > + BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN)); > } > > static void sun4i_codec_stop_playback(struct sun4i_codec *scodec) > { > /* Disable DAC DRQ */ > - regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, > - BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN)); > + regmap_field_clear_bits(scodec->reg_dac_fifoc, > + BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN)); > } > > static void sun4i_codec_start_capture(struct sun4i_codec *scodec) > @@ -356,13 +358,13 @@ static int sun4i_codec_prepare_playback(struct snd_pcm_substream *substream, > u32 val; > > /* Flush the TX FIFO */ > - regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, > - BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH)); > + regmap_field_set_bits(scodec->reg_dac_fifoc, > + BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH)); > > /* Set TX FIFO Empty Trigger Level */ > - regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, > - 0x3f << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL, > - 0xf << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL); > + regmap_field_update_bits(scodec->reg_dac_fifoc, > + 0x3f << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL, > + 0xf << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL); > > if (substream->runtime->rate > 32000) > /* Use 64 bits FIR filter */ > @@ -371,13 +373,13 @@ static int sun4i_codec_prepare_playback(struct snd_pcm_substream *substream, > /* Use 32 bits FIR filter */ > val = BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION); > > - regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, > - BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION), > - val); > + regmap_field_update_bits(scodec->reg_dac_fifoc, > + BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION), > + val); > > /* Send zeros when we have an underrun */ > - regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, > - BIT(SUN4I_CODEC_DAC_FIFOC_SEND_LASAT)); > + regmap_field_clear_bits(scodec->reg_dac_fifoc, > + BIT(SUN4I_CODEC_DAC_FIFOC_SEND_LASAT)); > > return 0; > }; > @@ -510,9 +512,9 @@ static int sun4i_codec_hw_params_playback(struct sun4i_codec *scodec, > u32 val; > > /* Set DAC sample rate */ > - regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, > - 7 << SUN4I_CODEC_DAC_FIFOC_DAC_FS, > - hwrate << SUN4I_CODEC_DAC_FIFOC_DAC_FS); > + regmap_field_update_bits(scodec->reg_dac_fifoc, > + 7 << SUN4I_CODEC_DAC_FIFOC_DAC_FS, > + hwrate << SUN4I_CODEC_DAC_FIFOC_DAC_FS); > > /* Set the number of channels we want to use */ > if (params_channels(params) == 1) > @@ -520,27 +522,27 @@ static int sun4i_codec_hw_params_playback(struct sun4i_codec *scodec, > else > val = 0; > > - regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, > - BIT(SUN4I_CODEC_DAC_FIFOC_MONO_EN), > - val); > + regmap_field_update_bits(scodec->reg_dac_fifoc, > + BIT(SUN4I_CODEC_DAC_FIFOC_MONO_EN), > + val); > > /* Set the number of sample bits to either 16 or 24 bits */ > if (hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min == 32) { > - regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, > - BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS)); > + regmap_field_set_bits(scodec->reg_dac_fifoc, > + BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS)); > > /* Set TX FIFO mode to padding the LSBs with 0 */ > - regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, > - BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE)); > + regmap_field_clear_bits(scodec->reg_dac_fifoc, > + BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE)); > > scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; > } else { > - regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, > - BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS)); > + regmap_field_clear_bits(scodec->reg_dac_fifoc, > + BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS)); > > /* Set TX FIFO mode to repeat the MSB */ > - regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, > - BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE)); > + regmap_field_set_bits(scodec->reg_dac_fifoc, > + BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE)); > > scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; > } > @@ -587,8 +589,8 @@ static int sun4i_codec_startup(struct snd_pcm_substream *substream, > * Stop issuing DRQ when we have room for less than 16 samples > * in our TX FIFO > */ > - regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, > - 3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT); > + regmap_field_set_bits(scodec->reg_dac_fifoc, > + 3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT); > > return clk_prepare_enable(scodec->clk_module); > } > @@ -1565,6 +1567,7 @@ struct sun4i_codec_quirks { > const struct snd_soc_component_driver *codec; > struct snd_soc_card * (*create_card)(struct device *dev); > struct reg_field reg_adc_fifoc; /* used for regmap_field */ > + struct reg_field reg_dac_fifoc; /* used for regmap_field */ > unsigned int reg_dac_txdata; /* TX FIFO offset for DMA config */ > unsigned int reg_adc_rxdata; /* RX FIFO offset for DMA config */ > bool has_reset; > @@ -1575,6 +1578,7 @@ static const struct sun4i_codec_quirks sun4i_codec_quirks = { > .codec = &sun4i_codec_codec, > .create_card = sun4i_codec_create_card, > .reg_adc_fifoc = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31), > + .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31), > .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, > .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA, > }; > @@ -1584,6 +1588,7 @@ static const struct sun4i_codec_quirks sun6i_a31_codec_quirks = { > .codec = &sun6i_codec_codec, > .create_card = sun6i_codec_create_card, > .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), > + .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31), > .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, > .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, > .has_reset = true, > @@ -1594,6 +1599,7 @@ static const struct sun4i_codec_quirks sun7i_codec_quirks = { > .codec = &sun7i_codec_codec, > .create_card = sun4i_codec_create_card, > .reg_adc_fifoc = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31), > + .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31), > .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, > .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA, > }; > @@ -1603,6 +1609,7 @@ static const struct sun4i_codec_quirks sun8i_a23_codec_quirks = { > .codec = &sun8i_a23_codec_codec, > .create_card = sun8i_a23_codec_create_card, > .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), > + .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31), > .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, > .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, > .has_reset = true, > @@ -1618,6 +1625,7 @@ static const struct sun4i_codec_quirks sun8i_h3_codec_quirks = { > .codec = &sun8i_a23_codec_codec, > .create_card = sun8i_h3_codec_create_card, > .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), > + .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31), > .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA, > .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, > .has_reset = true, > @@ -1632,6 +1640,7 @@ static const struct sun4i_codec_quirks sun8i_v3s_codec_quirks = { > .codec = &sun8i_a23_codec_codec, > .create_card = sun8i_v3s_codec_create_card, > .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), > + .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31), > .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA, > .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, > .has_reset = true, > @@ -1739,6 +1748,16 @@ static int sun4i_codec_probe(struct platform_device *pdev) > return ret; > } > > + scodec->reg_dac_fifoc = devm_regmap_field_alloc(&pdev->dev, > + scodec->regmap, > + quirks->reg_dac_fifoc); > + if (IS_ERR(scodec->reg_dac_fifoc)) { > + ret = PTR_ERR(scodec->reg_dac_fifoc); > + dev_err(&pdev->dev, "Failed to create regmap fields: %d\n", > + ret); > + return ret; > + } > + > /* Enable the bus clock */ > if (clk_prepare_enable(scodec->clk_apb)) { > dev_err(&pdev->dev, "Failed to enable the APB clock\n");