diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-09-17 17:43:33 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-09-17 17:43:33 -0700 |
commit | 6ab8ad31601f29470eb895fd95e5c963e125aa1b (patch) | |
tree | 73327fe9fc2ee62e7815fa0a666fdf46aaab7322 /sound/soc/mediatek/mt8183/mt8183-dai-tdm.c | |
parent | ea982ba7f79141d86eb7a440fcba6796ed718b9b (diff) | |
parent | 9bf9bf5440b99edfba496388c90b52ebcd9df715 (diff) | |
download | linux-6ab8ad31601f29470eb895fd95e5c963e125aa1b.tar.bz2 |
Merge tag 'sound-5.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai:
"As shown in diffstat and logs, it was again a busy development cycle
at this time, too. The most significant changes are still on-going
refactoring / modernization works for ASoC core and drivers, but there
are lots of other changes as well. Here we go, some highlights below:
ASoC:
- Quite a lot of cleanup / refactoring of ASoC core and APIs; most of
them are systematic, but also including cleanups and modernization
- A bulk of updates for some ASoC platforms, Freescale, sunxi and
Intel SST/SOF
- Initial support for Sound Open Firmware on i.MX8
- Removal of deprecated w90x900 and nuc900 drivers
- New support for Cirrus Logic CS47L15 and CS47L92, Freescale i.MX
7ULP and 8MQ, Meson G12A and NXP UDA1334
USB-audio:
- More validations of descriptor units for hardening against bugs
reported by fuzzers
- PCM device assignment workaround for a past call-order change
- Scarlett Gen2 mixer interface, a few more more quirks
HD-audio:
- Support for audio component with AMD/ATI and Nvidia HDMI codecs
- Clean up HD-audio core and remove indirect access ops for Intel SOF
- DMIC detection at probe; it would make systems automatically
falling back to SST/SOF driver on devices that need DMIC handling.
Needs a new Kconfig to set, and beware that it's still new and a
bit experimental
FireWire:
- Lots of code refactoring and cleanups"
* tag 'sound-5.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (521 commits)
ASoC: sdm845: remove unneeded semicolon
ASoC: fsl_sai: Implement set_bclk_ratio
ASoC: dmaengine: Replace strncpy() with strscpy_pad() for pcm->name
ASoC: wcd9335: remove redundant use of ret variable
ALSA: firewire-tascam: check intermediate state of clock status and retry
ALSA: firewire-tascam: handle error code when getting current source of clock
ASoC: hdmi-codec: Add an op to set callback function for plug event
ASoC: rt5677: keep analog power register at SND_SOC_BIAS_OFF
ASoC: rt5677: Remove magic number register writes
ASoC: soc-core: self contained soc_unbind_aux_dev()
ASoC: soc-core: add soc_unbind_aux_dev()
ASoC: soc-core: self contained soc_bind_aux_dev()
ASoC: soc-core: move soc_probe_link_dais() next to soc_remove_link_dais()
ASoC: soc-core: self contained soc_probe_link_dais()
ASoC: soc-core: add new soc_link_init()
ASoC: soc-core: move soc_probe_dai() next to soc_remove_dai()
ASoC: soc-core: self contained soc_remove_link_dais()
ASoC: soc-core: self contained soc_remove_link_components()
ASoC: soc-core: self contained soc_probe_link_components()
ASoC: rt1308: make array pd static const, makes object smaller
...
Diffstat (limited to 'sound/soc/mediatek/mt8183/mt8183-dai-tdm.c')
-rw-r--r-- | sound/soc/mediatek/mt8183/mt8183-dai-tdm.c | 177 |
1 files changed, 143 insertions, 34 deletions
diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-tdm.c b/sound/soc/mediatek/mt8183/mt8183-dai-tdm.c index 8983d54a9b67..0d69cf440407 100644 --- a/sound/soc/mediatek/mt8183/mt8183-dai-tdm.c +++ b/sound/soc/mediatek/mt8183/mt8183-dai-tdm.c @@ -15,7 +15,9 @@ struct mtk_afe_tdm_priv { int bck_id; int bck_rate; - + int tdm_out_mode; + int bck_invert; + int lck_invert; int mclk_id; int mclk_multiple; /* according to sample rate */ int mclk_rate; @@ -23,6 +25,21 @@ struct mtk_afe_tdm_priv { }; enum { + TDM_OUT_I2S = 0, + TDM_OUT_TDM = 1, +}; + +enum { + TDM_BCK_NON_INV = 0, + TDM_BCK_INV = 1, +}; + +enum { + TDM_LCK_NON_INV = 0, + TDM_LCK_INV = 1, +}; + +enum { TDM_WLEN_16_BIT = 1, TDM_WLEN_32_BIT = 2, }; @@ -93,6 +110,25 @@ static unsigned int get_tdm_ch(unsigned int ch) } } +static unsigned int get_tdm_ch_fixup(unsigned int channels) +{ + if (channels > 4) + return 8; + else if (channels > 2) + return 4; + else + return 2; +} + +static unsigned int get_tdm_ch_per_sdata(unsigned int mode, + unsigned int channels) +{ + if (mode == TDM_OUT_TDM) + return get_tdm_ch_fixup(channels); + else + return 2; +} + /* interconnection */ enum { HDMI_CONN_CH0 = 0, @@ -433,8 +469,11 @@ static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream, struct mt8183_afe_private *afe_priv = afe->platform_priv; int tdm_id = dai->id; struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[tdm_id]; + unsigned int tdm_out_mode = tdm_priv->tdm_out_mode; unsigned int rate = params_rate(params); unsigned int channels = params_channels(params); + unsigned int out_channels_per_sdata = + get_tdm_ch_per_sdata(tdm_out_mode, channels); snd_pcm_format_t format = params_format(params); unsigned int tdm_con = 0; @@ -448,7 +487,7 @@ static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream, /* calculate bck */ tdm_priv->bck_rate = rate * - channels * + out_channels_per_sdata * snd_pcm_format_physical_width(format); if (tdm_priv->bck_rate > tdm_priv->mclk_rate) @@ -461,50 +500,72 @@ static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream, __func__, tdm_id, rate, channels, format, tdm_priv->mclk_rate, tdm_priv->bck_rate); + dev_info(afe->dev, "%s(), out_channels_per_sdata = %d\n", + __func__, out_channels_per_sdata); /* set tdm */ - tdm_con = 1 << BCK_INVERSE_SFT; - tdm_con |= 1 << LRCK_INVERSE_SFT; - tdm_con |= 1 << DELAY_DATA_SFT; + if (tdm_priv->bck_invert) + regmap_update_bits(afe->regmap, AUDIO_TOP_CON3, + BCK_INVERSE_MASK_SFT, + 0x1 << BCK_INVERSE_SFT); + + if (tdm_priv->lck_invert) + tdm_con |= 1 << LRCK_INVERSE_SFT; + + if (tdm_priv->tdm_out_mode == TDM_OUT_I2S) { + tdm_con |= 1 << DELAY_DATA_SFT; + tdm_con |= get_tdm_lrck_width(format) << LRCK_TDM_WIDTH_SFT; + } else if (tdm_priv->tdm_out_mode == TDM_OUT_TDM) { + tdm_con |= 0 << DELAY_DATA_SFT; + tdm_con |= 0 << LRCK_TDM_WIDTH_SFT; + } + tdm_con |= 1 << LEFT_ALIGN_SFT; tdm_con |= get_tdm_wlen(format) << WLEN_SFT; - tdm_con |= get_tdm_ch(channels) << CHANNEL_NUM_SFT; + tdm_con |= get_tdm_ch(out_channels_per_sdata) << CHANNEL_NUM_SFT; tdm_con |= get_tdm_channel_bck(format) << CHANNEL_BCK_CYCLES_SFT; - tdm_con |= get_tdm_lrck_width(format) << LRCK_TDM_WIDTH_SFT; regmap_write(afe->regmap, AFE_TDM_CON1, tdm_con); - switch (channels) { - case 1: - case 2: + if (out_channels_per_sdata == 2) { + switch (channels) { + case 1: + case 2: + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; + break; + case 3: + case 4: + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; + break; + case 5: + case 6: + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; + break; + case 7: + case 8: + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_START_O36_O37 << ST_CH_PAIR_SOUT3_SFT; + break; + default: + tdm_con = 0; + } + } else { tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT1_SFT; tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT; tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; - break; - case 3: - case 4: - tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; - tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; - tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT; - tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; - break; - case 5: - case 6: - tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; - tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; - tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT; - tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; - break; - case 7: - case 8: - tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; - tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; - tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT; - tdm_con |= TDM_CH_START_O36_O37 << ST_CH_PAIR_SOUT3_SFT; - break; - default: - tdm_con = 0; } + regmap_write(afe->regmap, AFE_TDM_CON2, tdm_con); regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, @@ -573,10 +634,58 @@ static int mtk_dai_tdm_set_sysclk(struct snd_soc_dai *dai, return mtk_dai_tdm_cal_mclk(afe, tdm_priv, freq); } +static int mtk_dai_tdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dai->dev); + struct mt8183_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id]; + + if (!tdm_priv) { + dev_warn(afe->dev, "%s(), tdm_priv == NULL", __func__); + return -EINVAL; + } + + /* DAI mode*/ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + tdm_priv->tdm_out_mode = TDM_OUT_I2S; + break; + case SND_SOC_DAIFMT_DSP_A: + tdm_priv->tdm_out_mode = TDM_OUT_TDM; + break; + default: + tdm_priv->tdm_out_mode = TDM_OUT_I2S; + } + + /* DAI clock inversion*/ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + tdm_priv->bck_invert = TDM_BCK_NON_INV; + tdm_priv->lck_invert = TDM_LCK_NON_INV; + break; + case SND_SOC_DAIFMT_NB_IF: + tdm_priv->bck_invert = TDM_BCK_NON_INV; + tdm_priv->lck_invert = TDM_LCK_INV; + break; + case SND_SOC_DAIFMT_IB_NF: + tdm_priv->bck_invert = TDM_BCK_INV; + tdm_priv->lck_invert = TDM_LCK_NON_INV; + break; + case SND_SOC_DAIFMT_IB_IF: + default: + tdm_priv->bck_invert = TDM_BCK_INV; + tdm_priv->lck_invert = TDM_LCK_INV; + break; + } + + return 0; +} + static const struct snd_soc_dai_ops mtk_dai_tdm_ops = { .hw_params = mtk_dai_tdm_hw_params, .trigger = mtk_dai_tdm_trigger, .set_sysclk = mtk_dai_tdm_set_sysclk, + .set_fmt = mtk_dai_tdm_set_fmt, }; /* dai driver */ |