Message ID | 20201102091656.25379-1-shumingf@realtek.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | ASoC: rt1015: support TDM slot configuration | expand |
> +static int rt1015_set_tdm_slot(struct snd_soc_dai *dai, > + unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) > +{ > + struct snd_soc_component *component = dai->component; > + unsigned int val = 0, rx_slotnum, tx_slotnum; > + int ret = 0, first_bit; > + > + switch (slots) { > + case 4: > + val |= RT1015_I2S_TX_4CH; > + break; > + case 6: > + val |= RT1015_I2S_TX_6CH; > + break; > + case 8: > + val |= RT1015_I2S_TX_8CH; > + break; > + case 2: > + break; nit-pick: I would put the case 2 first to keep the order. I thought for a second this was an error case due to the discontinuity. > + default: > + ret = -EINVAL; > + goto _set_tdm_err_; > + } > + > + switch (slot_width) { > + case 20: > + val |= RT1015_I2S_CH_TX_LEN_20B; > + break; > + case 24: > + val |= RT1015_I2S_CH_TX_LEN_24B; > + break; > + case 32: > + val |= RT1015_I2S_CH_TX_LEN_32B; > + break; > + case 16: > + break; nit-pick: same here, I would put 16 first. > + default: > + ret = -EINVAL; > + goto _set_tdm_err_; > + } > + > + /* Rx slot configuration */ > + rx_slotnum = hweight_long(rx_mask); > + if (rx_slotnum > 1 || !rx_slotnum) { I am confused here, is this saying you can only have a single channel on RX? If yes should this be simplified as if (rx_slotnum != 1) ? > + ret = -EINVAL; > + dev_err(component->dev, "too many rx slots or zero slot\n"); > + goto _set_tdm_err_; > + } > + > + first_bit = __ffs(rx_mask); > + switch (first_bit) { > + case 0: > + case 2: > + case 4: > + case 6: > + snd_soc_component_update_bits(component, > + RT1015_PAD_DRV2, RT1015_MONO_LR_SEL_MASK, > + RT1015_MONO_L_CHANNEL); > + snd_soc_component_update_bits(component, > + RT1015_TDM1_4, > + RT1015_TDM_I2S_TX_L_DAC1_1_MASK | > + RT1015_TDM_I2S_TX_R_DAC1_1_MASK, > + (first_bit << RT1015_TDM_I2S_TX_L_DAC1_1_SFT) | > + ((first_bit+1) << RT1015_TDM_I2S_TX_R_DAC1_1_SFT)); looks like there's an assumption that the rx mask has contiguous bits set? Maybe add a comment to explain how the RX path works? > + break; > + case 1: > + case 3: > + case 5: > + case 7: > + snd_soc_component_update_bits(component, > + RT1015_PAD_DRV2, RT1015_MONO_LR_SEL_MASK, > + RT1015_MONO_R_CHANNEL); > + snd_soc_component_update_bits(component, > + RT1015_TDM1_4, > + RT1015_TDM_I2S_TX_L_DAC1_1_MASK | > + RT1015_TDM_I2S_TX_R_DAC1_1_MASK, > + ((first_bit-1) << RT1015_TDM_I2S_TX_L_DAC1_1_SFT) | > + (first_bit << RT1015_TDM_I2S_TX_R_DAC1_1_SFT)); > + break; > + default: > + ret = -EINVAL; > + goto _set_tdm_err_; > + } > + > + /* Tx slot configuration */ > + tx_slotnum = hweight_long(tx_mask); > + if (tx_slotnum) { > + ret = -EINVAL; > + dev_err(component->dev, "doesn't need to support tx slots\n"); > + goto _set_tdm_err_; > + } > + > + snd_soc_component_update_bits(component, RT1015_TDM1_1, > + RT1015_I2S_CH_TX_MASK | RT1015_I2S_CH_RX_MASK | > + RT1015_I2S_CH_TX_LEN_MASK | RT1015_I2S_CH_RX_LEN_MASK, val); > + > +_set_tdm_err_: > + return ret; > +} > +
> > +static int rt1015_set_tdm_slot(struct snd_soc_dai *dai, > > + unsigned int tx_mask, unsigned int rx_mask, int slots, int > > +slot_width) { > > + struct snd_soc_component *component = dai->component; > > + unsigned int val = 0, rx_slotnum, tx_slotnum; > > + int ret = 0, first_bit; > > + > > + switch (slots) { > > + case 4: > > + val |= RT1015_I2S_TX_4CH; > > + break; > > + case 6: > > + val |= RT1015_I2S_TX_6CH; > > + break; > > + case 8: > > + val |= RT1015_I2S_TX_8CH; > > + break; > > + case 2: > > + break; > > nit-pick: I would put the case 2 first to keep the order. I thought for a second > this was an error case due to the discontinuity. OK, will fix that. > > + default: > > + ret = -EINVAL; > > + goto _set_tdm_err_; > > + } > > + > > + switch (slot_width) { > > + case 20: > > + val |= RT1015_I2S_CH_TX_LEN_20B; > > + break; > > + case 24: > > + val |= RT1015_I2S_CH_TX_LEN_24B; > > + break; > > + case 32: > > + val |= RT1015_I2S_CH_TX_LEN_32B; > > + break; > > + case 16: > > + break; > > nit-pick: same here, I would put 16 first. > > > + default: > > + ret = -EINVAL; > > + goto _set_tdm_err_; > > + } > > + > > + /* Rx slot configuration */ > > + rx_slotnum = hweight_long(rx_mask); > > + if (rx_slotnum > 1 || !rx_slotnum) { > > I am confused here, is this saying you can only have a single channel on RX? > > If yes should this be simplified as if (rx_slotnum != 1) ? Yes, RT1015 is a mono amplifier, so only a single channel will be configured. I will fix the check condition as your suggestion. Thanks. > > + ret = -EINVAL; > > + dev_err(component->dev, "too many rx slots or zero slot\n"); > > + goto _set_tdm_err_; > > + } > > + > > + first_bit = __ffs(rx_mask); > > + switch (first_bit) { > > + case 0: > > + case 2: > > + case 4: > > + case 6: > > + snd_soc_component_update_bits(component, > > + RT1015_PAD_DRV2, RT1015_MONO_LR_SEL_MASK, > > + RT1015_MONO_L_CHANNEL); > > + snd_soc_component_update_bits(component, > > + RT1015_TDM1_4, > > + RT1015_TDM_I2S_TX_L_DAC1_1_MASK | > > + RT1015_TDM_I2S_TX_R_DAC1_1_MASK, > > + (first_bit << RT1015_TDM_I2S_TX_L_DAC1_1_SFT) | > > + ((first_bit+1) << RT1015_TDM_I2S_TX_R_DAC1_1_SFT)); > > looks like there's an assumption that the rx mask has contiguous bits set? > Maybe add a comment to explain how the RX path works? Yes. In the normal case, the system will send the stereo audio to the codec. I assume that the stereo audio is placed in slot 0/2/4/6. I will add a comment above this switch case. > > + break; > > + case 1: > > + case 3: > > + case 5: > > + case 7: > > + snd_soc_component_update_bits(component, > > + RT1015_PAD_DRV2, RT1015_MONO_LR_SEL_MASK, > > + RT1015_MONO_R_CHANNEL); > > + snd_soc_component_update_bits(component, > > + RT1015_TDM1_4, > > + RT1015_TDM_I2S_TX_L_DAC1_1_MASK | > > + RT1015_TDM_I2S_TX_R_DAC1_1_MASK, > > + ((first_bit-1) << RT1015_TDM_I2S_TX_L_DAC1_1_SFT) | > > + (first_bit << RT1015_TDM_I2S_TX_R_DAC1_1_SFT)); > > + break;
diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c index 25fe2ddedd54..5d3e269d17f5 100644 --- a/sound/soc/codecs/rt1015.c +++ b/sound/soc/codecs/rt1015.c @@ -944,6 +944,106 @@ static int rt1015_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) return 0; } +static int rt1015_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) +{ + struct snd_soc_component *component = dai->component; + unsigned int val = 0, rx_slotnum, tx_slotnum; + int ret = 0, first_bit; + + switch (slots) { + case 4: + val |= RT1015_I2S_TX_4CH; + break; + case 6: + val |= RT1015_I2S_TX_6CH; + break; + case 8: + val |= RT1015_I2S_TX_8CH; + break; + case 2: + break; + default: + ret = -EINVAL; + goto _set_tdm_err_; + } + + switch (slot_width) { + case 20: + val |= RT1015_I2S_CH_TX_LEN_20B; + break; + case 24: + val |= RT1015_I2S_CH_TX_LEN_24B; + break; + case 32: + val |= RT1015_I2S_CH_TX_LEN_32B; + break; + case 16: + break; + default: + ret = -EINVAL; + goto _set_tdm_err_; + } + + /* Rx slot configuration */ + rx_slotnum = hweight_long(rx_mask); + if (rx_slotnum > 1 || !rx_slotnum) { + ret = -EINVAL; + dev_err(component->dev, "too many rx slots or zero slot\n"); + goto _set_tdm_err_; + } + + first_bit = __ffs(rx_mask); + switch (first_bit) { + case 0: + case 2: + case 4: + case 6: + snd_soc_component_update_bits(component, + RT1015_PAD_DRV2, RT1015_MONO_LR_SEL_MASK, + RT1015_MONO_L_CHANNEL); + snd_soc_component_update_bits(component, + RT1015_TDM1_4, + RT1015_TDM_I2S_TX_L_DAC1_1_MASK | + RT1015_TDM_I2S_TX_R_DAC1_1_MASK, + (first_bit << RT1015_TDM_I2S_TX_L_DAC1_1_SFT) | + ((first_bit+1) << RT1015_TDM_I2S_TX_R_DAC1_1_SFT)); + break; + case 1: + case 3: + case 5: + case 7: + snd_soc_component_update_bits(component, + RT1015_PAD_DRV2, RT1015_MONO_LR_SEL_MASK, + RT1015_MONO_R_CHANNEL); + snd_soc_component_update_bits(component, + RT1015_TDM1_4, + RT1015_TDM_I2S_TX_L_DAC1_1_MASK | + RT1015_TDM_I2S_TX_R_DAC1_1_MASK, + ((first_bit-1) << RT1015_TDM_I2S_TX_L_DAC1_1_SFT) | + (first_bit << RT1015_TDM_I2S_TX_R_DAC1_1_SFT)); + break; + default: + ret = -EINVAL; + goto _set_tdm_err_; + } + + /* Tx slot configuration */ + tx_slotnum = hweight_long(tx_mask); + if (tx_slotnum) { + ret = -EINVAL; + dev_err(component->dev, "doesn't need to support tx slots\n"); + goto _set_tdm_err_; + } + + snd_soc_component_update_bits(component, RT1015_TDM1_1, + RT1015_I2S_CH_TX_MASK | RT1015_I2S_CH_RX_MASK | + RT1015_I2S_CH_TX_LEN_MASK | RT1015_I2S_CH_RX_LEN_MASK, val); + +_set_tdm_err_: + return ret; +} + static int rt1015_probe(struct snd_soc_component *component) { struct rt1015_priv *rt1015 = @@ -975,6 +1075,7 @@ static struct snd_soc_dai_ops rt1015_aif_dai_ops = { .hw_params = rt1015_hw_params, .set_fmt = rt1015_set_dai_fmt, .set_bclk_ratio = rt1015_set_bclk_ratio, + .set_tdm_slot = rt1015_set_tdm_slot, }; static struct snd_soc_dai_driver rt1015_dai[] = { diff --git a/sound/soc/codecs/rt1015.h b/sound/soc/codecs/rt1015.h index d3fdd30aca6d..ad8274c80990 100644 --- a/sound/soc/codecs/rt1015.h +++ b/sound/soc/codecs/rt1015.h @@ -213,6 +213,12 @@ #define RT1015_ID_VERA 0x0 #define RT1015_ID_VERB 0x1 +/* 0x00f2 */ +#define RT1015_MONO_LR_SEL_MASK (0x3 << 4) +#define RT1015_MONO_L_CHANNEL (0x0 << 4) +#define RT1015_MONO_R_CHANNEL (0x1 << 4) +#define RT1015_MONO_LR_MIX_CHANNEL (0x2 << 4) + /* 0x0102 */ #define RT1015_DAC_VOL_MASK (0x7f << 9) #define RT1015_DAC_VOL_SFT 9 @@ -275,6 +281,42 @@ #define RT1015_TDM_INV_BCLK_MASK (0x1 << 15) #define RT1015_TDM_INV_BCLK_SFT 15 #define RT1015_TDM_INV_BCLK (0x1 << 15) +#define RT1015_I2S_CH_TX_MASK (0x3 << 10) +#define RT1015_I2S_CH_TX_SFT 10 +#define RT1015_I2S_TX_2CH (0x0 << 10) +#define RT1015_I2S_TX_4CH (0x1 << 10) +#define RT1015_I2S_TX_6CH (0x2 << 10) +#define RT1015_I2S_TX_8CH (0x3 << 10) +#define RT1015_I2S_CH_RX_MASK (0x3 << 8) +#define RT1015_I2S_CH_RX_SFT 8 +#define RT1015_I2S_RX_2CH (0x0 << 8) +#define RT1015_I2S_RX_4CH (0x1 << 8) +#define RT1015_I2S_RX_6CH (0x2 << 8) +#define RT1015_I2S_RX_8CH (0x3 << 8) +#define RT1015_I2S_LR_CH_SEL_MASK (0x1 << 7) +#define RT1015_I2S_LR_CH_SEL_SFT 7 +#define RT1015_I2S_LEFT_CH_SEL (0x0 << 7) +#define RT1015_I2S_RIGHT_CH_SEL (0x1 << 7) +#define RT1015_I2S_CH_TX_LEN_MASK (0x7 << 4) +#define RT1015_I2S_CH_TX_LEN_SFT 4 +#define RT1015_I2S_CH_TX_LEN_16B (0x0 << 4) +#define RT1015_I2S_CH_TX_LEN_20B (0x1 << 4) +#define RT1015_I2S_CH_TX_LEN_24B (0x2 << 4) +#define RT1015_I2S_CH_TX_LEN_32B (0x3 << 4) +#define RT1015_I2S_CH_TX_LEN_8B (0x4 << 4) +#define RT1015_I2S_CH_RX_LEN_MASK (0x7 << 0) +#define RT1015_I2S_CH_RX_LEN_SFT 0 +#define RT1015_I2S_CH_RX_LEN_16B (0x0 << 0) +#define RT1015_I2S_CH_RX_LEN_20B (0x1 << 0) +#define RT1015_I2S_CH_RX_LEN_24B (0x2 << 0) +#define RT1015_I2S_CH_RX_LEN_32B (0x3 << 0) +#define RT1015_I2S_CH_RX_LEN_8B (0x4 << 0) + +/* TDM1 Setting-4 (0x011a) */ +#define RT1015_TDM_I2S_TX_L_DAC1_1_MASK (0x7 << 12) +#define RT1015_TDM_I2S_TX_R_DAC1_1_MASK (0x7 << 8) +#define RT1015_TDM_I2S_TX_L_DAC1_1_SFT 12 +#define RT1015_TDM_I2S_TX_R_DAC1_1_SFT 8 /* 0x0330 */ #define RT1015_ABST_AUTO_EN_MASK (0x1 << 13)