Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ead99f89 authored by Lars-Peter Clausen's avatar Lars-Peter Clausen Committed by Mark Brown
Browse files

ASoC: ssm4567: Add support for setting the DAI format and TDM configuration



The SSM4567 has support for a couple of different DAI formats. In TDM mode
it is also possible to select the TDM slot. This patch adds support for this
by implementing the set_fmt and set_tdm_slot callbacks.

Signed-off-by: default avatarLars-Peter Clausen <lars@metafoo.de>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent feec843d
Loading
Loading
Loading
Loading
+119 −0
Original line number Diff line number Diff line
@@ -69,6 +69,22 @@
#define SSM4567_DAC_FS_64000_96000	0x3
#define SSM4567_DAC_FS_128000_192000	0x4

/* SAI_CTRL_1 */
#define SSM4567_SAI_CTRL_1_BCLK			BIT(6)
#define SSM4567_SAI_CTRL_1_TDM_BLCKS_MASK	(0x3 << 4)
#define SSM4567_SAI_CTRL_1_TDM_BLCKS_32		(0x0 << 4)
#define SSM4567_SAI_CTRL_1_TDM_BLCKS_48		(0x1 << 4)
#define SSM4567_SAI_CTRL_1_TDM_BLCKS_64		(0x2 << 4)
#define SSM4567_SAI_CTRL_1_FSYNC		BIT(3)
#define SSM4567_SAI_CTRL_1_LJ			BIT(2)
#define SSM4567_SAI_CTRL_1_TDM			BIT(1)
#define SSM4567_SAI_CTRL_1_PDM			BIT(0)

/* SAI_CTRL_2 */
#define SSM4567_SAI_CTRL_2_AUTO_SLOT		BIT(3)
#define SSM4567_SAI_CTRL_2_TDM_SLOT_MASK	0x7
#define SSM4567_SAI_CTRL_2_TDM_SLOT(x)		(x)

struct ssm4567 {
	struct regmap *regmap;
};
@@ -194,6 +210,107 @@ static int ssm4567_mute(struct snd_soc_dai *dai, int mute)
			SSM4567_DAC_MUTE, val);
}

static int ssm4567_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
	unsigned int rx_mask, int slots, int width)
{
	struct ssm4567 *ssm4567 = snd_soc_dai_get_drvdata(dai);
	unsigned int blcks;
	int slot;
	int ret;

	if (tx_mask == 0)
		return -EINVAL;

	if (rx_mask && rx_mask != tx_mask)
		return -EINVAL;

	slot = __ffs(tx_mask);
	if (tx_mask != BIT(slot))
		return -EINVAL;

	switch (width) {
	case 32:
		blcks = SSM4567_SAI_CTRL_1_TDM_BLCKS_32;
		break;
	case 48:
		blcks = SSM4567_SAI_CTRL_1_TDM_BLCKS_48;
		break;
	case 64:
		blcks = SSM4567_SAI_CTRL_1_TDM_BLCKS_64;
		break;
	default:
		return -EINVAL;
	}

	ret = regmap_update_bits(ssm4567->regmap, SSM4567_REG_SAI_CTRL_2,
		SSM4567_SAI_CTRL_2_AUTO_SLOT | SSM4567_SAI_CTRL_2_TDM_SLOT_MASK,
		SSM4567_SAI_CTRL_2_TDM_SLOT(slot));
	if (ret)
		return ret;

	return regmap_update_bits(ssm4567->regmap, SSM4567_REG_SAI_CTRL_1,
		SSM4567_SAI_CTRL_1_TDM_BLCKS_MASK, blcks);
}

static int ssm4567_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
	struct ssm4567 *ssm4567 = snd_soc_dai_get_drvdata(dai);
	unsigned int ctrl1 = 0;
	bool invert_fclk;

	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
	case SND_SOC_DAIFMT_CBS_CFS:
		break;
	default:
		return -EINVAL;
	}

	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
	case SND_SOC_DAIFMT_NB_NF:
		invert_fclk = false;
		break;
	case SND_SOC_DAIFMT_IB_NF:
		ctrl1 |= SSM4567_SAI_CTRL_1_BCLK;
		invert_fclk = false;
		break;
	case SND_SOC_DAIFMT_NB_IF:
		ctrl1 |= SSM4567_SAI_CTRL_1_FSYNC;
		invert_fclk = true;
		break;
	case SND_SOC_DAIFMT_IB_IF:
		ctrl1 |= SSM4567_SAI_CTRL_1_BCLK;
		invert_fclk = true;
		break;
	default:
		return -EINVAL;
	}

	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
	case SND_SOC_DAIFMT_I2S:
		break;
	case SND_SOC_DAIFMT_LEFT_J:
		ctrl1 |= SSM4567_SAI_CTRL_1_LJ;
		invert_fclk = !invert_fclk;
		break;
	case SND_SOC_DAIFMT_DSP_A:
		ctrl1 |= SSM4567_SAI_CTRL_1_TDM;
		break;
	case SND_SOC_DAIFMT_DSP_B:
		ctrl1 |= SSM4567_SAI_CTRL_1_TDM | SSM4567_SAI_CTRL_1_LJ;
		break;
	case SND_SOC_DAIFMT_PDM:
		ctrl1 |= SSM4567_SAI_CTRL_1_PDM;
		break;
	default:
		return -EINVAL;
	}

	if (invert_fclk)
		ctrl1 |= SSM4567_SAI_CTRL_1_FSYNC;

	return regmap_write(ssm4567->regmap, SSM4567_REG_SAI_CTRL_1, ctrl1);
}

static int ssm4567_set_power(struct ssm4567 *ssm4567, bool enable)
{
	int ret = 0;
@@ -248,6 +365,8 @@ static int ssm4567_set_bias_level(struct snd_soc_codec *codec,
static const struct snd_soc_dai_ops ssm4567_dai_ops = {
	.hw_params	= ssm4567_hw_params,
	.digital_mute	= ssm4567_mute,
	.set_fmt	= ssm4567_set_dai_fmt,
	.set_tdm_slot	= ssm4567_set_tdm_slot,
};

static struct snd_soc_dai_driver ssm4567_dai = {