mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-04 12:16:41 +00:00
ASoC: sun4i-codec: Add support for different DAC FIFOC addresses to quirks
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. Signed-off-by: Marcus Cooper <codekipper@gmail.com> Signed-off-by: Ryan Walklin <ryan@testtoast.com> Reviewed-by: Andre Przywara <andre.przywara@arm.com> Tested-by: Philippe Simons <simons.philippe@gmail.com> Link: https://patch.msgid.link/20241023075917.186835-4-ryan@testtoast.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
a77e6c12cd
commit
5836a9d2ca
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user