[alsa-devel] [PATCH 1/3] ASoC: ssm4567: Add DAC high-pass-filter control
Add a switch which can be used to enable/disable the DAC high-pass-filter.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- sound/soc/codecs/ssm4567.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c index 4b5c17f..e1e33d8 100644 --- a/sound/soc/codecs/ssm4567.c +++ b/sound/soc/codecs/ssm4567.c @@ -145,6 +145,8 @@ static const struct snd_kcontrol_new ssm4567_snd_controls[] = { SOC_SINGLE_TLV("Master Playback Volume", SSM4567_REG_DAC_VOLUME, 0, 0xff, 1, ssm4567_vol_tlv), SOC_SINGLE("DAC Low Power Mode Switch", SSM4567_REG_DAC_CTRL, 4, 1, 0), + SOC_SINGLE("DAC High Pass Filter Switch", SSM4567_REG_DAC_CTRL, + 5, 1, 0), };
static const struct snd_soc_dapm_widget ssm4567_dapm_widgets[] = {
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: Lars-Peter Clausen lars@metafoo.de --- sound/soc/codecs/ssm4567.c | 119 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+)
diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c index e1e33d8..2176679 100644 --- a/sound/soc/codecs/ssm4567.c +++ b/sound/soc/codecs/ssm4567.c @@ -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 = {
This patch adds a switch to enable/disable boost stage of the output amplifier. Applications that know that they do not need the output amplifier boost stage can disable it to conserve a bit of power.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- sound/soc/codecs/ssm4567.c | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c index 2176679..a984485 100644 --- a/sound/soc/codecs/ssm4567.c +++ b/sound/soc/codecs/ssm4567.c @@ -165,13 +165,20 @@ static const struct snd_kcontrol_new ssm4567_snd_controls[] = { 5, 1, 0), };
+static const struct snd_kcontrol_new ssm4567_amplifier_boost_control = + SOC_DAPM_SINGLE("Switch", SSM4567_REG_POWER_CTRL, 1, 1, 1); + static const struct snd_soc_dapm_widget ssm4567_dapm_widgets[] = { SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM4567_REG_POWER_CTRL, 2, 1), + SND_SOC_DAPM_SWITCH("Amplifier Boost", SSM4567_REG_POWER_CTRL, 3, 1, + &ssm4567_amplifier_boost_control),
SND_SOC_DAPM_OUTPUT("OUT"), };
static const struct snd_soc_dapm_route ssm4567_routes[] = { + { "OUT", NULL, "Amplifier Boost" }, + { "Amplifier Boost", "Switch", "DAC" }, { "OUT", NULL, "DAC" }, };
participants (2)
-
Lars-Peter Clausen
-
Mark Brown