Loading sound/soc/codecs/nau8825.c +97 −0 Original line number Diff line number Diff line Loading @@ -1425,10 +1425,107 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return 0; } /** * nau8825_set_tdm_slot - configure DAI TDM. * @dai: DAI * @tx_mask: bitmask representing active TX slots. * @rx_mask: bitmask representing active RX slots. * @slots: Number of slots in use. * @slot_width: Width in bits for each slot. * * Configures a DAI for TDM operation. Support TDM 4/8 slots. * The limitation is DAC and ADC need shift 4 slots at 8 slots mode. */ static int nau8825_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; struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component); unsigned int ctrl_val = 0, ctrl_offset = 0, value = 0, dac_s, adc_s; if (slots != 4 && slots != 8) { dev_err(nau8825->dev, "Only support 4 or 8 slots!\n"); return -EINVAL; } /* The driver is limited to 1-channel for ADC, and 2-channel for DAC on TDM mode */ if (hweight_long((unsigned long) tx_mask) != 1 || hweight_long((unsigned long) rx_mask) != 2) { dev_err(nau8825->dev, "The limitation is 1-channel for ADC, and 2-channel for DAC on TDM mode.\n"); return -EINVAL; } if (((tx_mask & 0xf) && (tx_mask & 0xf0)) || ((rx_mask & 0xf) && (rx_mask & 0xf0)) || ((tx_mask & 0xf) && (rx_mask & 0xf0)) || ((rx_mask & 0xf) && (tx_mask & 0xf0))) { dev_err(nau8825->dev, "Slot assignment of DAC and ADC need to set same interval.\n"); return -EINVAL; } /* The offset of fixed 4 slots for 8 slots support */ if (rx_mask & 0xf0) { regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2, NAU8825_I2S_PCM_TS_EN_MASK, NAU8825_I2S_PCM_TS_EN); regmap_read(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL1, &value); ctrl_val |= NAU8825_TDM_OFFSET_EN; ctrl_offset = 4 * slot_width; if (!(value & NAU8825_I2S_PCMB_MASK)) ctrl_offset += 1; dac_s = (rx_mask & 0xf0) >> 4; adc_s = fls((tx_mask & 0xf0) >> 4); } else { dac_s = rx_mask & 0xf; adc_s = fls(tx_mask & 0xf); } ctrl_val |= NAU8825_TDM_MODE; switch (dac_s) { case 0x3: ctrl_val |= 1 << NAU8825_TDM_DACR_RX_SFT; break; case 0x5: ctrl_val |= 2 << NAU8825_TDM_DACR_RX_SFT; break; case 0x6: ctrl_val |= 1 << NAU8825_TDM_DACL_RX_SFT; ctrl_val |= 2 << NAU8825_TDM_DACR_RX_SFT; break; case 0x9: ctrl_val |= 3 << NAU8825_TDM_DACR_RX_SFT; break; case 0xa: ctrl_val |= 1 << NAU8825_TDM_DACL_RX_SFT; ctrl_val |= 3 << NAU8825_TDM_DACR_RX_SFT; break; case 0xc: ctrl_val |= 2 << NAU8825_TDM_DACL_RX_SFT; ctrl_val |= 3 << NAU8825_TDM_DACR_RX_SFT; break; default: return -EINVAL; } ctrl_val |= adc_s - 1; regmap_update_bits(nau8825->regmap, NAU8825_REG_TDM_CTRL, NAU8825_TDM_MODE | NAU8825_TDM_OFFSET_EN | NAU8825_TDM_DACL_RX_MASK | NAU8825_TDM_DACR_RX_MASK | NAU8825_TDM_TX_MASK, ctrl_val); regmap_update_bits(nau8825->regmap, NAU8825_REG_LEFT_TIME_SLOT, NAU8825_TSLOT_L0_MASK, ctrl_offset); return 0; } static const struct snd_soc_dai_ops nau8825_dai_ops = { .startup = nau8825_dai_startup, .hw_params = nau8825_hw_params, .set_fmt = nau8825_set_dai_fmt, .set_tdm_slot = nau8825_set_tdm_slot, }; #define NAU8825_RATES SNDRV_PCM_RATE_8000_192000 Loading sound/soc/codecs/nau8825.h +14 −0 Original line number Diff line number Diff line Loading @@ -225,6 +225,15 @@ #define NAU8825_JKDET_PULL_EN (1 << 9) /* 0 - enable pull, 1 - disable */ #define NAU8825_JKDET_OUTPUT_EN (1 << 8) /* 0 - enable input, 1 - enable output */ /* TDM_CTRL (0x1b) */ #define NAU8825_TDM_MODE (0x1 << 15) #define NAU8825_TDM_OFFSET_EN (0x1 << 14) #define NAU8825_TDM_DACL_RX_SFT 6 #define NAU8825_TDM_DACL_RX_MASK (0x3 << NAU8825_TDM_DACL_RX_SFT) #define NAU8825_TDM_DACR_RX_SFT 4 #define NAU8825_TDM_DACR_RX_MASK (0x3 << NAU8825_TDM_DACR_RX_SFT) #define NAU8825_TDM_TX_MASK 0x3 /* I2S_PCM_CTRL1 (0x1c) */ #define NAU8825_I2S_BP_SFT 7 #define NAU8825_I2S_BP_MASK (1 << NAU8825_I2S_BP_SFT) Loading @@ -249,6 +258,9 @@ #define NAU8825_I2S_TRISTATE (1 << 15) /* 0 - normal mode, 1 - Hi-Z output */ #define NAU8825_I2S_LRC_DIV_SFT 12 #define NAU8825_I2S_LRC_DIV_MASK (0x3 << NAU8825_I2S_LRC_DIV_SFT) #define NAU8825_I2S_PCM_TS_EN_SFT 10 #define NAU8825_I2S_PCM_TS_EN_MASK (1 << NAU8825_I2S_PCM_TS_EN_SFT) #define NAU8825_I2S_PCM_TS_EN (1 << NAU8825_I2S_PCM_TS_EN_SFT) #define NAU8825_I2S_MS_SFT 3 #define NAU8825_I2S_MS_MASK (1 << NAU8825_I2S_MS_SFT) #define NAU8825_I2S_MS_MASTER (1 << NAU8825_I2S_MS_SFT) Loading @@ -259,6 +271,8 @@ #define NAU8825_FS_ERR_CMP_SEL_SFT 14 #define NAU8825_FS_ERR_CMP_SEL_MASK (0x3 << NAU8825_FS_ERR_CMP_SEL_SFT) #define NAU8825_DIS_FS_SHORT_DET (1 << 13) #define NAU8825_TSLOT_L0_MASK 0x3ff #define NAU8825_TSLOT_R0_MASK 0x3ff /* BIQ_CTRL (0x20) */ #define NAU8825_BIQ_WRT_SFT 4 Loading Loading
sound/soc/codecs/nau8825.c +97 −0 Original line number Diff line number Diff line Loading @@ -1425,10 +1425,107 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return 0; } /** * nau8825_set_tdm_slot - configure DAI TDM. * @dai: DAI * @tx_mask: bitmask representing active TX slots. * @rx_mask: bitmask representing active RX slots. * @slots: Number of slots in use. * @slot_width: Width in bits for each slot. * * Configures a DAI for TDM operation. Support TDM 4/8 slots. * The limitation is DAC and ADC need shift 4 slots at 8 slots mode. */ static int nau8825_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; struct nau8825 *nau8825 = snd_soc_component_get_drvdata(component); unsigned int ctrl_val = 0, ctrl_offset = 0, value = 0, dac_s, adc_s; if (slots != 4 && slots != 8) { dev_err(nau8825->dev, "Only support 4 or 8 slots!\n"); return -EINVAL; } /* The driver is limited to 1-channel for ADC, and 2-channel for DAC on TDM mode */ if (hweight_long((unsigned long) tx_mask) != 1 || hweight_long((unsigned long) rx_mask) != 2) { dev_err(nau8825->dev, "The limitation is 1-channel for ADC, and 2-channel for DAC on TDM mode.\n"); return -EINVAL; } if (((tx_mask & 0xf) && (tx_mask & 0xf0)) || ((rx_mask & 0xf) && (rx_mask & 0xf0)) || ((tx_mask & 0xf) && (rx_mask & 0xf0)) || ((rx_mask & 0xf) && (tx_mask & 0xf0))) { dev_err(nau8825->dev, "Slot assignment of DAC and ADC need to set same interval.\n"); return -EINVAL; } /* The offset of fixed 4 slots for 8 slots support */ if (rx_mask & 0xf0) { regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2, NAU8825_I2S_PCM_TS_EN_MASK, NAU8825_I2S_PCM_TS_EN); regmap_read(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL1, &value); ctrl_val |= NAU8825_TDM_OFFSET_EN; ctrl_offset = 4 * slot_width; if (!(value & NAU8825_I2S_PCMB_MASK)) ctrl_offset += 1; dac_s = (rx_mask & 0xf0) >> 4; adc_s = fls((tx_mask & 0xf0) >> 4); } else { dac_s = rx_mask & 0xf; adc_s = fls(tx_mask & 0xf); } ctrl_val |= NAU8825_TDM_MODE; switch (dac_s) { case 0x3: ctrl_val |= 1 << NAU8825_TDM_DACR_RX_SFT; break; case 0x5: ctrl_val |= 2 << NAU8825_TDM_DACR_RX_SFT; break; case 0x6: ctrl_val |= 1 << NAU8825_TDM_DACL_RX_SFT; ctrl_val |= 2 << NAU8825_TDM_DACR_RX_SFT; break; case 0x9: ctrl_val |= 3 << NAU8825_TDM_DACR_RX_SFT; break; case 0xa: ctrl_val |= 1 << NAU8825_TDM_DACL_RX_SFT; ctrl_val |= 3 << NAU8825_TDM_DACR_RX_SFT; break; case 0xc: ctrl_val |= 2 << NAU8825_TDM_DACL_RX_SFT; ctrl_val |= 3 << NAU8825_TDM_DACR_RX_SFT; break; default: return -EINVAL; } ctrl_val |= adc_s - 1; regmap_update_bits(nau8825->regmap, NAU8825_REG_TDM_CTRL, NAU8825_TDM_MODE | NAU8825_TDM_OFFSET_EN | NAU8825_TDM_DACL_RX_MASK | NAU8825_TDM_DACR_RX_MASK | NAU8825_TDM_TX_MASK, ctrl_val); regmap_update_bits(nau8825->regmap, NAU8825_REG_LEFT_TIME_SLOT, NAU8825_TSLOT_L0_MASK, ctrl_offset); return 0; } static const struct snd_soc_dai_ops nau8825_dai_ops = { .startup = nau8825_dai_startup, .hw_params = nau8825_hw_params, .set_fmt = nau8825_set_dai_fmt, .set_tdm_slot = nau8825_set_tdm_slot, }; #define NAU8825_RATES SNDRV_PCM_RATE_8000_192000 Loading
sound/soc/codecs/nau8825.h +14 −0 Original line number Diff line number Diff line Loading @@ -225,6 +225,15 @@ #define NAU8825_JKDET_PULL_EN (1 << 9) /* 0 - enable pull, 1 - disable */ #define NAU8825_JKDET_OUTPUT_EN (1 << 8) /* 0 - enable input, 1 - enable output */ /* TDM_CTRL (0x1b) */ #define NAU8825_TDM_MODE (0x1 << 15) #define NAU8825_TDM_OFFSET_EN (0x1 << 14) #define NAU8825_TDM_DACL_RX_SFT 6 #define NAU8825_TDM_DACL_RX_MASK (0x3 << NAU8825_TDM_DACL_RX_SFT) #define NAU8825_TDM_DACR_RX_SFT 4 #define NAU8825_TDM_DACR_RX_MASK (0x3 << NAU8825_TDM_DACR_RX_SFT) #define NAU8825_TDM_TX_MASK 0x3 /* I2S_PCM_CTRL1 (0x1c) */ #define NAU8825_I2S_BP_SFT 7 #define NAU8825_I2S_BP_MASK (1 << NAU8825_I2S_BP_SFT) Loading @@ -249,6 +258,9 @@ #define NAU8825_I2S_TRISTATE (1 << 15) /* 0 - normal mode, 1 - Hi-Z output */ #define NAU8825_I2S_LRC_DIV_SFT 12 #define NAU8825_I2S_LRC_DIV_MASK (0x3 << NAU8825_I2S_LRC_DIV_SFT) #define NAU8825_I2S_PCM_TS_EN_SFT 10 #define NAU8825_I2S_PCM_TS_EN_MASK (1 << NAU8825_I2S_PCM_TS_EN_SFT) #define NAU8825_I2S_PCM_TS_EN (1 << NAU8825_I2S_PCM_TS_EN_SFT) #define NAU8825_I2S_MS_SFT 3 #define NAU8825_I2S_MS_MASK (1 << NAU8825_I2S_MS_SFT) #define NAU8825_I2S_MS_MASTER (1 << NAU8825_I2S_MS_SFT) Loading @@ -259,6 +271,8 @@ #define NAU8825_FS_ERR_CMP_SEL_SFT 14 #define NAU8825_FS_ERR_CMP_SEL_MASK (0x3 << NAU8825_FS_ERR_CMP_SEL_SFT) #define NAU8825_DIS_FS_SHORT_DET (1 << 13) #define NAU8825_TSLOT_L0_MASK 0x3ff #define NAU8825_TSLOT_R0_MASK 0x3ff /* BIQ_CTRL (0x20) */ #define NAU8825_BIQ_WRT_SFT 4 Loading