mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-04 04:02:26 +00:00
ASoC: add Allwinner H616 audio codec support
Merge series from Ryan Walklin <ryan@testtoast.com>: The Allwinner H616 has a playback-only audio codec, with a single stereo or differential-mono line output. This patch series adds support for the H616 (and H313/H618/H700/T507) SoC. Based on the Allwinner kernel SDK driver, and tested on the H700.
This commit is contained in:
commit
7fc18ae228
@ -22,6 +22,7 @@ properties:
|
||||
- allwinner,sun8i-a23-codec
|
||||
- allwinner,sun8i-h3-codec
|
||||
- allwinner,sun8i-v3s-codec
|
||||
- allwinner,sun50i-h616-codec
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
@ -40,14 +41,20 @@ properties:
|
||||
- const: codec
|
||||
|
||||
dmas:
|
||||
items:
|
||||
- description: RX DMA Channel
|
||||
- description: TX DMA Channel
|
||||
oneOf:
|
||||
- items:
|
||||
- description: RX DMA Channel
|
||||
- description: TX DMA Channel
|
||||
- items:
|
||||
- description: TX DMA Channel
|
||||
|
||||
dma-names:
|
||||
items:
|
||||
- const: rx
|
||||
- const: tx
|
||||
oneOf:
|
||||
- items:
|
||||
- const: rx
|
||||
- const: tx
|
||||
- items:
|
||||
- const: tx
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
@ -229,6 +236,40 @@ allOf:
|
||||
- Mic
|
||||
- Speaker
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- allwinner,sun50i-h616-codec
|
||||
|
||||
then:
|
||||
properties:
|
||||
allwinner,audio-routing:
|
||||
items:
|
||||
enum:
|
||||
- LINEOUT
|
||||
- Line Out
|
||||
|
||||
dmas:
|
||||
items:
|
||||
- description: TX DMA Channel
|
||||
|
||||
dma-names:
|
||||
items:
|
||||
- const: tx
|
||||
|
||||
else:
|
||||
properties:
|
||||
dmas:
|
||||
items:
|
||||
- description: RX DMA Channel
|
||||
- description: TX DMA Channel
|
||||
|
||||
dma-names:
|
||||
items:
|
||||
- const: rx
|
||||
- const: tx
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
|
@ -226,6 +226,43 @@
|
||||
#define SUN8I_H3_CODEC_DAC_DBG (0x48)
|
||||
#define SUN8I_H3_CODEC_ADC_DBG (0x4c)
|
||||
|
||||
/* H616 specific registers */
|
||||
#define SUN50I_H616_CODEC_DAC_FIFOC (0x10)
|
||||
|
||||
#define SUN50I_DAC_FIFO_STA (0x14)
|
||||
#define SUN50I_DAC_TXE_INT (3)
|
||||
#define SUN50I_DAC_TXU_INT (2)
|
||||
#define SUN50I_DAC_TXO_INT (1)
|
||||
|
||||
#define SUN50I_DAC_CNT (0x24)
|
||||
#define SUN50I_DAC_DG_REG (0x28)
|
||||
#define SUN50I_DAC_DAP_CTL (0xf0)
|
||||
|
||||
#define SUN50I_H616_DAC_AC_DAC_REG (0x310)
|
||||
#define SUN50I_H616_DAC_LEN (15)
|
||||
#define SUN50I_H616_DAC_REN (14)
|
||||
#define SUN50I_H616_LINEOUTL_EN (13)
|
||||
#define SUN50I_H616_LMUTE (12)
|
||||
#define SUN50I_H616_LINEOUTR_EN (11)
|
||||
#define SUN50I_H616_RMUTE (10)
|
||||
#define SUN50I_H616_RSWITCH (9)
|
||||
#define SUN50I_H616_RAMPEN (8)
|
||||
#define SUN50I_H616_LINEOUTL_SEL (6)
|
||||
#define SUN50I_H616_LINEOUTR_SEL (5)
|
||||
#define SUN50I_H616_LINEOUT_VOL (0)
|
||||
|
||||
#define SUN50I_H616_DAC_AC_MIXER_REG (0x314)
|
||||
#define SUN50I_H616_LMIX_LDAC (21)
|
||||
#define SUN50I_H616_LMIX_RDAC (20)
|
||||
#define SUN50I_H616_RMIX_RDAC (17)
|
||||
#define SUN50I_H616_RMIX_LDAC (16)
|
||||
#define SUN50I_H616_LMIXEN (11)
|
||||
#define SUN50I_H616_RMIXEN (10)
|
||||
|
||||
#define SUN50I_H616_DAC_AC_RAMP_REG (0x31c)
|
||||
#define SUN50I_H616_RAMP_STEP (4)
|
||||
#define SUN50I_H616_RDEN (0)
|
||||
|
||||
/* TODO H3 DAP (Digital Audio Processing) bits */
|
||||
|
||||
struct sun4i_codec {
|
||||
@ -238,6 +275,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 +285,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 +395,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 +410,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 +549,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 +559,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 +626,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);
|
||||
}
|
||||
@ -1518,6 +1557,150 @@ static struct snd_soc_card *sun8i_v3s_codec_create_card(struct device *dev)
|
||||
return card;
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new sun50i_h616_codec_codec_controls[] = {
|
||||
SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC,
|
||||
SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1,
|
||||
sun6i_codec_dvol_scale),
|
||||
SOC_SINGLE_TLV("Line Out Playback Volume",
|
||||
SUN50I_H616_DAC_AC_DAC_REG,
|
||||
SUN50I_H616_LINEOUT_VOL, 0x1f, 0,
|
||||
sun6i_codec_lineout_vol_scale),
|
||||
SOC_DOUBLE("Line Out Playback Switch",
|
||||
SUN50I_H616_DAC_AC_DAC_REG,
|
||||
SUN50I_H616_LINEOUTL_EN,
|
||||
SUN50I_H616_LINEOUTR_EN, 1, 0),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new sun50i_h616_codec_mixer_controls[] = {
|
||||
SOC_DAPM_DOUBLE("DAC Playback Switch",
|
||||
SUN50I_H616_DAC_AC_MIXER_REG,
|
||||
SUN50I_H616_LMIX_LDAC,
|
||||
SUN50I_H616_RMIX_RDAC, 1, 0),
|
||||
SOC_DAPM_DOUBLE("DAC Reversed Playback Switch",
|
||||
SUN50I_H616_DAC_AC_MIXER_REG,
|
||||
SUN50I_H616_LMIX_RDAC,
|
||||
SUN50I_H616_RMIX_LDAC, 1, 0),
|
||||
};
|
||||
|
||||
static SOC_ENUM_DOUBLE_DECL(sun50i_h616_codec_lineout_src_enum,
|
||||
SUN50I_H616_DAC_AC_DAC_REG,
|
||||
SUN50I_H616_LINEOUTL_SEL,
|
||||
SUN50I_H616_LINEOUTR_SEL,
|
||||
sun6i_codec_lineout_src_enum_text);
|
||||
|
||||
static const struct snd_kcontrol_new sun50i_h616_codec_lineout_src[] = {
|
||||
SOC_DAPM_ENUM("Line Out Source Playback Route",
|
||||
sun50i_h616_codec_lineout_src_enum),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget sun50i_h616_codec_codec_widgets[] = {
|
||||
/* Digital parts of the DACs */
|
||||
SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC,
|
||||
SUN4I_CODEC_DAC_DPC_EN_DA, 0,
|
||||
NULL, 0),
|
||||
|
||||
/* Analog parts of the DACs */
|
||||
SND_SOC_DAPM_DAC("Left DAC", "Codec Playback",
|
||||
SUN50I_H616_DAC_AC_DAC_REG,
|
||||
SUN50I_H616_DAC_LEN, 0),
|
||||
SND_SOC_DAPM_DAC("Right DAC", "Codec Playback",
|
||||
SUN50I_H616_DAC_AC_DAC_REG,
|
||||
SUN50I_H616_DAC_REN, 0),
|
||||
|
||||
/* Mixers */
|
||||
SOC_MIXER_ARRAY("Left Mixer", SUN50I_H616_DAC_AC_MIXER_REG,
|
||||
SUN50I_H616_LMIXEN, 0,
|
||||
sun50i_h616_codec_mixer_controls),
|
||||
SOC_MIXER_ARRAY("Right Mixer", SUN50I_H616_DAC_AC_MIXER_REG,
|
||||
SUN50I_H616_RMIXEN, 0,
|
||||
sun50i_h616_codec_mixer_controls),
|
||||
|
||||
/* Line Out path */
|
||||
SND_SOC_DAPM_MUX("Line Out Source Playback Route",
|
||||
SND_SOC_NOPM, 0, 0, sun50i_h616_codec_lineout_src),
|
||||
SND_SOC_DAPM_OUT_DRV("Line Out Ramp Controller",
|
||||
SUN50I_H616_DAC_AC_RAMP_REG,
|
||||
SUN50I_H616_RDEN, 0, NULL, 0),
|
||||
SND_SOC_DAPM_OUTPUT("LINEOUT"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver sun50i_h616_codec_codec = {
|
||||
.controls = sun50i_h616_codec_codec_controls,
|
||||
.num_controls = ARRAY_SIZE(sun50i_h616_codec_codec_controls),
|
||||
.dapm_widgets = sun50i_h616_codec_codec_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(sun50i_h616_codec_codec_widgets),
|
||||
.idle_bias_on = 1,
|
||||
.use_pmdown_time = 1,
|
||||
.endianness = 1,
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new sun50i_h616_card_controls[] = {
|
||||
SOC_DAPM_PIN_SWITCH("LINEOUT"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget sun50i_h616_codec_card_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_LINE("Line Out", NULL),
|
||||
SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event),
|
||||
};
|
||||
|
||||
/* Connect digital side enables to analog side widgets */
|
||||
static const struct snd_soc_dapm_route sun50i_h616_codec_card_routes[] = {
|
||||
/* DAC Routes */
|
||||
{ "Left DAC", NULL, "DAC Enable" },
|
||||
{ "Right DAC", NULL, "DAC Enable" },
|
||||
|
||||
/* Left Mixer Routes */
|
||||
{ "Left Mixer", "DAC Playback Switch", "Left DAC" },
|
||||
{ "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" },
|
||||
|
||||
/* Right Mixer Routes */
|
||||
{ "Right Mixer", "DAC Playback Switch", "Right DAC" },
|
||||
{ "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" },
|
||||
|
||||
/* Line Out Routes */
|
||||
{ "Line Out Source Playback Route", "Stereo", "Left Mixer" },
|
||||
{ "Line Out Source Playback Route", "Stereo", "Right Mixer" },
|
||||
{ "Line Out Source Playback Route", "Mono Differential", "Left Mixer" },
|
||||
{ "Line Out Source Playback Route", "Mono Differential", "Right Mixer" },
|
||||
{ "Line Out Ramp Controller", NULL, "Line Out Source Playback Route" },
|
||||
{ "LINEOUT", NULL, "Line Out Ramp Controller" },
|
||||
};
|
||||
|
||||
static struct snd_soc_card *sun50i_h616_codec_create_card(struct device *dev)
|
||||
{
|
||||
struct snd_soc_card *card;
|
||||
int ret;
|
||||
|
||||
card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
|
||||
if (!card)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
|
||||
if (!card->dai_link)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
card->dai_link->playback_only = true;
|
||||
card->dai_link->capture_only = false;
|
||||
|
||||
card->dev = dev;
|
||||
card->owner = THIS_MODULE;
|
||||
card->name = "H616 Audio Codec";
|
||||
card->driver_name = "sun4i-codec";
|
||||
card->controls = sun50i_h616_card_controls;
|
||||
card->num_controls = ARRAY_SIZE(sun50i_h616_card_controls);
|
||||
card->dapm_widgets = sun50i_h616_codec_card_dapm_widgets;
|
||||
card->num_dapm_widgets = ARRAY_SIZE(sun50i_h616_codec_card_dapm_widgets);
|
||||
card->dapm_routes = sun50i_h616_codec_card_routes;
|
||||
card->num_dapm_routes = ARRAY_SIZE(sun50i_h616_codec_card_routes);
|
||||
card->fully_routed = true;
|
||||
|
||||
ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
|
||||
if (ret)
|
||||
dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
|
||||
|
||||
return card;
|
||||
};
|
||||
|
||||
static const struct regmap_config sun4i_codec_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
@ -1560,14 +1743,24 @@ static const struct regmap_config sun8i_v3s_codec_regmap_config = {
|
||||
.max_register = SUN8I_H3_CODEC_ADC_DBG,
|
||||
};
|
||||
|
||||
static const struct regmap_config sun50i_h616_codec_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.max_register = SUN50I_H616_DAC_AC_RAMP_REG,
|
||||
.cache_type = REGCACHE_NONE,
|
||||
};
|
||||
|
||||
struct sun4i_codec_quirks {
|
||||
const struct regmap_config *regmap_config;
|
||||
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;
|
||||
bool playback_only;
|
||||
};
|
||||
|
||||
static const struct sun4i_codec_quirks sun4i_codec_quirks = {
|
||||
@ -1575,6 +1768,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 +1778,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 +1789,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 +1799,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 +1815,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,11 +1830,21 @@ 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,
|
||||
};
|
||||
|
||||
static const struct sun4i_codec_quirks sun50i_h616_codec_quirks = {
|
||||
.regmap_config = &sun50i_h616_codec_regmap_config,
|
||||
.codec = &sun50i_h616_codec_codec,
|
||||
.create_card = sun50i_h616_codec_create_card,
|
||||
.reg_dac_fifoc = REG_FIELD(SUN50I_H616_CODEC_DAC_FIFOC, 0, 31),
|
||||
.reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA,
|
||||
.has_reset = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id sun4i_codec_of_match[] = {
|
||||
{
|
||||
.compatible = "allwinner,sun4i-a10-codec",
|
||||
@ -1662,6 +1870,10 @@ static const struct of_device_id sun4i_codec_of_match[] = {
|
||||
.compatible = "allwinner,sun8i-v3s-codec",
|
||||
.data = &sun8i_v3s_codec_quirks,
|
||||
},
|
||||
{
|
||||
.compatible = "allwinner,sun50i-h616-codec",
|
||||
.data = &sun50i_h616_codec_quirks,
|
||||
},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sun4i_codec_of_match);
|
||||
@ -1739,6 +1951,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");
|
||||
@ -1760,10 +1982,13 @@ static int sun4i_codec_probe(struct platform_device *pdev)
|
||||
scodec->playback_dma_data.maxburst = 8;
|
||||
scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
|
||||
|
||||
/* DMA configuration for RX FIFO */
|
||||
scodec->capture_dma_data.addr = res->start + quirks->reg_adc_rxdata;
|
||||
scodec->capture_dma_data.maxburst = 8;
|
||||
scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
|
||||
if (!quirks->playback_only) {
|
||||
/* DMA configuration for RX FIFO */
|
||||
scodec->capture_dma_data.addr = res->start +
|
||||
quirks->reg_adc_rxdata;
|
||||
scodec->capture_dma_data.maxburst = 8;
|
||||
scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
|
||||
}
|
||||
|
||||
ret = devm_snd_soc_register_component(&pdev->dev, quirks->codec,
|
||||
&sun4i_codec_dai, 1);
|
||||
@ -1837,4 +2062,5 @@ MODULE_AUTHOR("Emilio López <emilio@elopez.com.ar>");
|
||||
MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
|
||||
MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
|
||||
MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
|
||||
MODULE_AUTHOR("Ryan Walklin <ryan@testtoast.com");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
Loading…
Reference in New Issue
Block a user