All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] sound/soc: adds TAS5754M digital input amplifier component driver
       [not found] <20211029095414.29131-1-joerg@hifiberry.com>
@ 2021-10-29  9:57   ` Joerg Schambacher
  2022-01-10  8:45   ` Joerg Schambacher
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 21+ messages in thread
From: Joerg Schambacher @ 2021-10-29  9:57 UTC (permalink / raw)
  To: alsa-devel; +Cc: joerg, broonie, kbuild-all

Adds a minimum component driver to run the amplifier in I2S master
mode only from standard audio clocks. Therefore, it only allows
44.1, 88.2, 176.4, 48, 96 and 192ksps with 16, 20, 24 and 32 bits
sample size. Digital volume control and the -6dB switch are supported.

Signed-off-by: Joerg Schambacher <joerg@hifiberry.com>
---
Added of_match_ptr() macro to fix the error when compiling on non CONFIG_OF
systems.

Joerg
 sound/soc/codecs/Kconfig    |   8 +
 sound/soc/codecs/Makefile   |   2 +
 sound/soc/codecs/tas5754m.c | 547 ++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/tas5754m.h | 259 +++++++++++++++++
 4 files changed, 816 insertions(+)
 create mode 100644 sound/soc/codecs/tas5754m.c
 create mode 100644 sound/soc/codecs/tas5754m.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 82ee233a269d..cf0584948fcf 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -210,6 +210,7 @@ config SND_SOC_ALL_CODECS
 	imply SND_SOC_TAS5086
 	imply SND_SOC_TAS571X
 	imply SND_SOC_TAS5720
+	imply SND_SOC_TAS5754M
 	imply SND_SOC_TAS6424
 	imply SND_SOC_TDA7419
 	imply SND_SOC_TFA9879
@@ -1419,6 +1420,13 @@ config SND_SOC_TAS5720
 	  Enable support for Texas Instruments TAS5720L/M high-efficiency mono
 	  Class-D audio power amplifiers.
 
+config SND_SOC_TAS5754M
+	tristate "Texas Instruments TAS5754M Digital Input Audio amplifier"
+	depends on I2C
+	help
+	  Enable support for Texas Instruments TAS5754M digital input
+	  Class-D audio power amplifiers.
+
 config SND_SOC_TAS6424
 	tristate "Texas Instruments TAS6424 Quad-Channel Audio amplifier"
 	depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 8dcea2c4604a..39984900258a 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -227,6 +227,7 @@ snd-soc-sti-sas-objs := sti-sas.o
 snd-soc-tas5086-objs := tas5086.o
 snd-soc-tas571x-objs := tas571x.o
 snd-soc-tas5720-objs := tas5720.o
+snd-soc-tas5754m-objs := tas5754m.o
 snd-soc-tas6424-objs := tas6424.o
 snd-soc-tda7419-objs := tda7419.o
 snd-soc-tas2770-objs := tas2770.o
@@ -555,6 +556,7 @@ obj-$(CONFIG_SND_SOC_TAS2764)	+= snd-soc-tas2764.o
 obj-$(CONFIG_SND_SOC_TAS5086)	+= snd-soc-tas5086.o
 obj-$(CONFIG_SND_SOC_TAS571X)	+= snd-soc-tas571x.o
 obj-$(CONFIG_SND_SOC_TAS5720)	+= snd-soc-tas5720.o
+obj-$(CONFIG_SND_SOC_TAS5754M)	+= snd-soc-tas5754m.o
 obj-$(CONFIG_SND_SOC_TAS6424)	+= snd-soc-tas6424.o
 obj-$(CONFIG_SND_SOC_TDA7419)	+= snd-soc-tda7419.o
 obj-$(CONFIG_SND_SOC_TAS2770) += snd-soc-tas2770.o
diff --git a/sound/soc/codecs/tas5754m.c b/sound/soc/codecs/tas5754m.c
new file mode 100644
index 000000000000..aef2c65acc26
--- /dev/null
+++ b/sound/soc/codecs/tas5754m.c
@@ -0,0 +1,547 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for the TAS5754M Audio Amplifier in Master mode (only)
+ * supports only standard audio frequencies 44.1 to 192 ksps
+ *
+ * Author: Joerg Schambacher <joerg@hifiberry.com>
+ * with fragments from Andy Liu <andy-liu@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+
+#include "tas5754m.h"
+
+#define TAS5754M_RATES		(SNDRV_PCM_RATE_48000  |	\
+				 SNDRV_PCM_RATE_96000  |	\
+				 SNDRV_PCM_RATE_192000 |	\
+				 SNDRV_PCM_RATE_44100  |	\
+				 SNDRV_PCM_RATE_88200  |	\
+				 SNDRV_PCM_RATE_176400)
+#define TAS5754M_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE  | \
+				 SNDRV_PCM_FMTBIT_S20_LE  | \
+				 SNDRV_PCM_FMTBIT_S24_LE  | \
+				 SNDRV_PCM_FMTBIT_S32_LE)
+
+
+static const struct reg_sequence tas5754m_init_sequence[] = {
+	{ TAS5754M_RESET,		0x00 },
+	{ TAS5754M_MUTE,		0x11 },
+	{ TAS5754M_POWER,		0x00 },
+	{ TAS5754M_PLL_EN,		0x00 },
+	{ TAS5754M_RESET,		0x00 },
+	{ TAS5754M_GPIO_OUTPUT_3,	0x02 },
+	{ TAS5754M_GPIO_OUTPUT_4,	0x02 },
+	{ TAS5754M_GPIO_OUTPUT_6,	0x02 },
+	{ TAS5754M_GPIO_EN,		0x2c },
+	{ TAS5754M_GPIO_CONTROL_1,	0x04 },
+	{ TAS5754M_BCLK_LRCLK_CFG,	0x11 },
+	{ TAS5754M_MASTER_MODE,		0x7c },
+	{ TAS5754M_ERROR_DETECT,	0x77 },
+	{ TAS5754M_PLL_EN,		0x01 },
+	{ TAS5754M_PLL_REF,		0x00 },
+	{ TAS5754M_PLL_COEFF_0,		0x03 },
+	{ TAS5754M_PLL_COEFF_1,		0x0c },
+	{ TAS5754M_PLL_COEFF_2,		0x00 },
+	{ TAS5754M_PLL_COEFF_3,		0x00 },
+	{ TAS5754M_PLL_COEFF_4,		0x00 },
+	{ TAS5754M_DAC_REF,		0x30 },
+	{ TAS5754M_DSP_CLKDIV,		0x01 },
+	{ TAS5754M_DAC_CLKDIV,		0x0f },
+	{ TAS5754M_NCP_CLKDIV,		0x03 },
+	{ TAS5754M_OSR_CLKDIV,		0x00 },
+	{ TAS5754M_FS_SPEED_MODE,	0x00 },
+	{ TAS5754M_MASTER_CLKDIV_1,	0x0f },
+	{ TAS5754M_MASTER_CLKDIV_2,	0x1f },
+	{ TAS5754M_I2S_1,		0x00 },
+	{ TAS5754M_I2S_2,		0x01 },
+	{ TAS5754M_PLL_EN,		0x01 },
+	{ TAS5754M_MASTER_MODE,		0x7f },
+	{ TAS5754M_MUTE,		0x11 },
+};
+
+static const struct reg_default tas5754m_reg_defaults[] = {
+	{ TAS5754M_RESET,             0x00 },
+	{ TAS5754M_POWER,             0x00 },
+	{ TAS5754M_MUTE,              0x00 },
+	{ TAS5754M_DSP,               0x00 },
+	{ TAS5754M_PLL_REF,           0x00 },
+	{ TAS5754M_DAC_REF,           0x00 },
+	{ TAS5754M_DAC_ROUTING,       0x11 },
+	{ TAS5754M_DSP_PROGRAM,       0x01 },
+	{ TAS5754M_CLKDET,            0x00 },
+	{ TAS5754M_AUTO_MUTE,         0x00 },
+	{ TAS5754M_ERROR_DETECT,      0x00 },
+	{ TAS5754M_DIGITAL_VOLUME_1,  0x00 },
+	{ TAS5754M_DIGITAL_VOLUME_2,  0x30 },
+	{ TAS5754M_DIGITAL_VOLUME_3,  0x30 },
+	{ TAS5754M_DIGITAL_MUTE_1,    0x22 },
+	{ TAS5754M_DIGITAL_MUTE_2,    0x00 },
+	{ TAS5754M_DIGITAL_MUTE_3,    0x07 },
+	{ TAS5754M_OUTPUT_AMPLITUDE,  0x00 },
+	{ TAS5754M_ANALOG_GAIN_CTRL,  0x00 },
+	{ TAS5754M_UNDERVOLTAGE_PROT, 0x00 },
+	{ TAS5754M_ANALOG_MUTE_CTRL,  0x00 },
+	{ TAS5754M_ANALOG_GAIN_BOOST, 0x00 },
+	{ TAS5754M_VCOM_CTRL_1,       0x00 },
+	{ TAS5754M_VCOM_CTRL_2,       0x01 },
+	{ TAS5754M_BCLK_LRCLK_CFG,    0x00 },
+	{ TAS5754M_MASTER_MODE,       0x7c },
+	{ TAS5754M_GPIO_DACIN,        0x00 },
+	{ TAS5754M_GPIO_PLLIN,        0x00 },
+	{ TAS5754M_SYNCHRONIZE,       0x10 },
+	{ TAS5754M_PLL_COEFF_0,       0x00 },
+	{ TAS5754M_PLL_COEFF_1,       0x00 },
+	{ TAS5754M_PLL_COEFF_2,       0x00 },
+	{ TAS5754M_PLL_COEFF_3,       0x00 },
+	{ TAS5754M_PLL_COEFF_4,       0x00 },
+	{ TAS5754M_DSP_CLKDIV,        0x00 },
+	{ TAS5754M_DAC_CLKDIV,        0x00 },
+	{ TAS5754M_NCP_CLKDIV,        0x00 },
+	{ TAS5754M_OSR_CLKDIV,        0x00 },
+	{ TAS5754M_MASTER_CLKDIV_1,   0x00 },
+	{ TAS5754M_MASTER_CLKDIV_2,   0x00 },
+	{ TAS5754M_FS_SPEED_MODE,     0x00 },
+	{ TAS5754M_IDAC_1,            0x01 },
+	{ TAS5754M_IDAC_2,            0x00 },
+};
+
+static bool tas5754m_readable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TAS5754M_RESET:
+	case TAS5754M_POWER:
+	case TAS5754M_MUTE:
+	case TAS5754M_PLL_EN:
+	case TAS5754M_SPI_MISO_FUNCTION:
+	case TAS5754M_DSP:
+	case TAS5754M_GPIO_EN:
+	case TAS5754M_BCLK_LRCLK_CFG:
+	case TAS5754M_DSP_GPIO_INPUT:
+	case TAS5754M_MASTER_MODE:
+	case TAS5754M_PLL_REF:
+	case TAS5754M_DAC_REF:
+	case TAS5754M_GPIO_DACIN:
+	case TAS5754M_GPIO_PLLIN:
+	case TAS5754M_SYNCHRONIZE:
+	case TAS5754M_PLL_COEFF_0:
+	case TAS5754M_PLL_COEFF_1:
+	case TAS5754M_PLL_COEFF_2:
+	case TAS5754M_PLL_COEFF_3:
+	case TAS5754M_PLL_COEFF_4:
+	case TAS5754M_DSP_CLKDIV:
+	case TAS5754M_DAC_CLKDIV:
+	case TAS5754M_NCP_CLKDIV:
+	case TAS5754M_OSR_CLKDIV:
+	case TAS5754M_MASTER_CLKDIV_1:
+	case TAS5754M_MASTER_CLKDIV_2:
+	case TAS5754M_FS_SPEED_MODE:
+	case TAS5754M_IDAC_1:
+	case TAS5754M_IDAC_2:
+	case TAS5754M_ERROR_DETECT:
+	case TAS5754M_I2S_1:
+	case TAS5754M_I2S_2:
+	case TAS5754M_DAC_ROUTING:
+	case TAS5754M_DSP_PROGRAM:
+	case TAS5754M_CLKDET:
+	case TAS5754M_AUTO_MUTE:
+	case TAS5754M_DIGITAL_VOLUME_1:
+	case TAS5754M_DIGITAL_VOLUME_2:
+	case TAS5754M_DIGITAL_VOLUME_3:
+	case TAS5754M_DIGITAL_MUTE_1:
+	case TAS5754M_DIGITAL_MUTE_2:
+	case TAS5754M_DIGITAL_MUTE_3:
+	case TAS5754M_GPIO_OUTPUT_1:
+	case TAS5754M_GPIO_OUTPUT_2:
+	case TAS5754M_GPIO_OUTPUT_3:
+	case TAS5754M_GPIO_OUTPUT_4:
+	case TAS5754M_GPIO_OUTPUT_5:
+	case TAS5754M_GPIO_OUTPUT_6:
+	case TAS5754M_GPIO_CONTROL_1:
+	case TAS5754M_GPIO_CONTROL_2:
+	case TAS5754M_OVERFLOW:
+	case TAS5754M_RATE_DET_1:
+	case TAS5754M_RATE_DET_2:
+	case TAS5754M_RATE_DET_3:
+	case TAS5754M_RATE_DET_4:
+	case TAS5754M_CLOCK_STATUS:
+	case TAS5754M_ANALOG_MUTE_DET:
+	case TAS5754M_GPIN:
+	case TAS5754M_DIGITAL_MUTE_DET:
+	case TAS5754M_OUTPUT_AMPLITUDE:
+	case TAS5754M_ANALOG_GAIN_CTRL:
+	case TAS5754M_UNDERVOLTAGE_PROT:
+	case TAS5754M_ANALOG_MUTE_CTRL:
+	case TAS5754M_ANALOG_GAIN_BOOST:
+	case TAS5754M_VCOM_CTRL_1:
+	case TAS5754M_VCOM_CTRL_2:
+	case TAS5754M_CRAM_CTRL:
+	case TAS5754M_FLEX_A:
+	case TAS5754M_FLEX_B:
+		return true;
+	default:
+		return reg < 0x7f;
+	}
+}
+
+static bool tas5754m_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TAS5754M_PLL_EN:
+	case TAS5754M_OVERFLOW:
+	case TAS5754M_RATE_DET_1:
+	case TAS5754M_RATE_DET_2:
+	case TAS5754M_RATE_DET_3:
+	case TAS5754M_RATE_DET_4:
+	case TAS5754M_CLOCK_STATUS:
+	case TAS5754M_ANALOG_MUTE_DET:
+	case TAS5754M_GPIN:
+	case TAS5754M_DIGITAL_MUTE_DET:
+	case TAS5754M_CRAM_CTRL:
+		return true;
+	default:
+		return reg < 0x7f;
+	}
+}
+
+struct tas5754m_priv {
+	struct regmap *regmap;
+	struct clk *sclk;
+};
+
+static const struct regmap_range_cfg tas5754m_range = {
+	.name = "Pages",
+	.range_min = TAS5754M_VIRT_BASE,
+	.range_max = TAS5754M_MAX_REGISTER,
+	.selector_reg = TAS5754M_PAGE,
+	.selector_mask = 0x7f,
+	.window_start = 0,
+	.window_len = 128,
+};
+
+const struct regmap_config tas5754m_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.ranges = &tas5754m_range,
+	.num_ranges = 1,
+	.max_register = TAS5754M_MAX_REGISTER,
+
+	.reg_defaults = tas5754m_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(tas5754m_reg_defaults),
+	.readable_reg = tas5754m_readable,
+	.volatile_reg = tas5754m_volatile,
+
+	.cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_GPL(tas5754m_regmap);
+
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1);
+static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0);
+
+static const struct snd_kcontrol_new tas5754m_controls[] = {
+SOC_DOUBLE_R_TLV("Digital Playback Volume", TAS5754M_DIGITAL_VOLUME_2,
+		 TAS5754M_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv),
+SOC_DOUBLE_TLV("Analog Playback Volume", TAS5754M_ANALOG_GAIN_CTRL,
+	     TAS5754M_LAGN_SHIFT, TAS5754M_RAGN_SHIFT, 1, 1, analog_tlv),
+};
+
+static int tas5754m_set_bias_level(struct snd_soc_component *component,
+					enum snd_soc_bias_level level)
+{
+	struct tas5754m_priv *tas5754m =
+				snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		ret = regmap_update_bits(tas5754m->regmap,
+				TAS5754M_POWER, TAS5754M_RQST, 0);
+		if (ret != 0) {
+			dev_err(component->dev,
+				"Failed to remove standby: %d\n", ret);
+			return ret;
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		ret = regmap_update_bits(tas5754m->regmap,
+				TAS5754M_POWER, TAS5754M_RQST, TAS5754M_RQST);
+		if (ret != 0) {
+			dev_err(component->dev,
+				"Failed to request standby: %d\n", ret);
+			return ret;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static int tas5754m_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+	unsigned long bclk;
+	unsigned long mclk;
+	int sample_len;
+	int bclk_div;
+	int lrclk_div;
+	int alen;
+	int ret;
+
+	switch (params_width(params)) {
+	case 16:
+		sample_len = 16;
+		alen = TAS5754M_ALEN_16;
+		break;
+	case 20:
+		sample_len = 32;
+		alen = TAS5754M_ALEN_20;
+		break;
+	case 24:
+		sample_len = 32;
+		alen = TAS5754M_ALEN_24;
+		break;
+	case 32:
+		sample_len = 32;
+		alen = TAS5754M_ALEN_32;
+		break;
+	default:
+		dev_err(component->dev, "Unsupported sample size: %d\n",
+			params_width(params));
+		return -EINVAL;
+	}
+	ret = regmap_update_bits(tas5754m->regmap, TAS5754M_I2S_1, alen, alen);
+	if (ret != 0) {
+		dev_err(component->dev,
+			"Cannot set sample size: %d\n", ret);
+		return ret;
+	}
+
+	switch (params_rate(params)) {
+	case 44100:
+	case 48000:
+		ret = regmap_write(tas5754m->regmap,
+			TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_48KHZ);
+		break;
+	case 88200:
+	case 96000:
+		ret = regmap_write(tas5754m->regmap,
+			TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_96KHZ);
+		break;
+	case 176400:
+	case 192000:
+		ret = regmap_write(tas5754m->regmap,
+			TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_192KHZ);
+		break;
+	default:
+		dev_err(component->dev, "Sample rate not supported: %d\n",
+			params_rate(params));
+		return -EINVAL;
+	}
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to config PLL\n");
+		return ret;
+	}
+
+
+	mclk = clk_get_rate(tas5754m->sclk);
+	bclk = sample_len * 2 * params_rate(params);
+	bclk_div = mclk / bclk;
+	lrclk_div = sample_len * 2;
+
+	// stop LR / SCLK clocks
+	ret = regmap_write(tas5754m->regmap, TAS5754M_MASTER_MODE, 0x7c);
+
+	// set SCLK divider
+	ret |= regmap_write(tas5754m->regmap, TAS5754M_MASTER_CLKDIV_1,
+								bclk_div - 1);
+
+	// set LRCLK divider
+	ret |= regmap_write(tas5754m->regmap, TAS5754M_MASTER_CLKDIV_2,
+								lrclk_div - 1);
+
+	// restart LR / SCLK clocks
+	ret |= regmap_write(tas5754m->regmap, TAS5754M_MASTER_MODE, 0x7f);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to config PLL\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver tas5754m_soc_component = {
+	.set_bias_level = tas5754m_set_bias_level,
+	.idle_bias_on = true,
+	.controls = tas5754m_controls,
+	.num_controls = ARRAY_SIZE(tas5754m_controls),
+};
+
+static int tas5754m_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+	struct snd_soc_component *component = dai->component;
+
+	if (mute) {
+		snd_soc_component_write(component, TAS5754M_MUTE, 0x11);
+	} else {
+		usleep_range(1000, 2000);
+		snd_soc_component_write(component, TAS5754M_MUTE, 0x00);
+	}
+	return 0;
+}
+
+static const struct snd_soc_dai_ops tas5754m_dai_ops = {
+	.mute_stream = tas5754m_mute,
+	.hw_params = tas5754m_hw_params,
+};
+
+static struct snd_soc_dai_driver tas5754m_dai = {
+	.name		= "tas5754m-amplifier",
+	.playback	= {
+		.stream_name	= "Playback",
+		.channels_min	= 2,
+		.channels_max	= 2,
+		.rates		= TAS5754M_RATES,
+		.formats	= TAS5754M_FORMATS,
+	},
+	.ops = &tas5754m_dai_ops,
+};
+
+static int tas5754m_probe(struct device *dev, struct regmap *regmap)
+{
+	struct tas5754m_priv *tas5754m;
+	int ret;
+
+	tas5754m = devm_kzalloc(dev, sizeof(struct tas5754m_priv), GFP_KERNEL);
+	if (!tas5754m)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, tas5754m);
+	tas5754m->regmap = regmap;
+
+	ret = regmap_multi_reg_write(regmap, tas5754m_init_sequence,
+					ARRAY_SIZE(tas5754m_init_sequence));
+
+	if (ret != 0) {
+		dev_err(dev, "Failed to initialize TAS5754M: %d\n", ret);
+		goto err;
+	}
+
+	tas5754m->sclk = devm_clk_get(dev, NULL);
+	if (PTR_ERR(tas5754m->sclk) == -EPROBE_DEFER) {
+		ret = -EPROBE_DEFER;
+		goto err;
+	}
+	if (!IS_ERR(tas5754m->sclk)) {
+		ret = clk_prepare_enable(tas5754m->sclk);
+		if (ret != 0) {
+			dev_err(dev, "Failed to enable SCLK: %d\n", ret);
+			goto err;
+		}
+	}
+
+	ret = snd_soc_register_component(dev,
+			&tas5754m_soc_component, &tas5754m_dai, 1);
+	if (ret != 0) {
+		dev_err(dev, "Failed to register CODEC: %d\n", ret);
+		goto err;
+	}
+
+	return 0;
+
+err:
+	return ret;
+
+}
+
+static int tas5754m_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+{
+	struct regmap *regmap;
+	struct regmap_config config = tas5754m_regmap;
+
+	/* enable auto-increment mode */
+	config.read_flag_mask = 0x80;
+	config.write_flag_mask = 0x80;
+
+	regmap = devm_regmap_init_i2c(i2c, &config);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return tas5754m_probe(&i2c->dev, regmap);
+}
+
+static int tas5754m_remove(struct device *dev)
+{
+	snd_soc_unregister_component(dev);
+
+	return 0;
+}
+
+static int tas5754m_i2c_remove(struct i2c_client *i2c)
+{
+	tas5754m_remove(&i2c->dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id tas5754m_i2c_id[] = {
+	{ "tas5754m", },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tas5754m_i2c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id tas5754m_of_match[] = {
+	{ .compatible = "ti,tas5754m", },
+	{ .compatible = "ti,tas5756m", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, tas5754m_of_match);
+#endif
+
+static struct i2c_driver tas5754m_i2c_driver = {
+	.probe		= tas5754m_i2c_probe,
+	.remove		= tas5754m_i2c_remove,
+	.id_table	= tas5754m_i2c_id,
+	.driver		= {
+		.name	= "tas5754m",
+		.of_match_table = of_match_ptr(tas5754m_of_match),
+	},
+};
+
+module_i2c_driver(tas5754m_i2c_driver);
+
+MODULE_AUTHOR("Joerg Schambacher <joerg@hifiberry.com>");
+MODULE_DESCRIPTION("TAS5754M Audio Amplifier Driver - Master mode only");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas5754m.h b/sound/soc/codecs/tas5754m.h
new file mode 100644
index 000000000000..492b8abede6c
--- /dev/null
+++ b/sound/soc/codecs/tas5754m.h
@@ -0,0 +1,259 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Driver for the TAS5754M DAC+amplifier combo devices
+ *
+ * Author:	(copied from pcm512x.h)
+ *		Mark Brown <broonie@kernel.org>
+ *		Copyright 2014 Linaro Ltd
+ */
+
+#ifndef _SND_SOC_TAS5754M
+#define _SND_SOC_TAS5754M
+
+#include <linux/pm.h>
+#include <linux/regmap.h>
+
+#define TAS5754M_VIRT_BASE 0x000
+#define TAS5754M_PAGE_LEN  0x80
+#define TAS5754M_PAGE_BASE(n)  (TAS5754M_VIRT_BASE + (TAS5754M_PAGE_LEN * n))
+
+#define TAS5754M_PAGE              0
+
+#define TAS5754M_RESET             (TAS5754M_PAGE_BASE(0) +   1)
+#define TAS5754M_POWER             (TAS5754M_PAGE_BASE(0) +   2)
+#define TAS5754M_MUTE              (TAS5754M_PAGE_BASE(0) +   3)
+#define TAS5754M_PLL_EN            (TAS5754M_PAGE_BASE(0) +   4)
+#define TAS5754M_SPI_MISO_FUNCTION (TAS5754M_PAGE_BASE(0) +   6)
+#define TAS5754M_DSP               (TAS5754M_PAGE_BASE(0) +   7)
+#define TAS5754M_GPIO_EN           (TAS5754M_PAGE_BASE(0) +   8)
+#define TAS5754M_BCLK_LRCLK_CFG    (TAS5754M_PAGE_BASE(0) +   9)
+#define TAS5754M_DSP_GPIO_INPUT    (TAS5754M_PAGE_BASE(0) +  10)
+#define TAS5754M_MASTER_MODE       (TAS5754M_PAGE_BASE(0) +  12)
+#define TAS5754M_PLL_REF           (TAS5754M_PAGE_BASE(0) +  13)
+#define TAS5754M_DAC_REF           (TAS5754M_PAGE_BASE(0) +  14)
+#define TAS5754M_GPIO_DACIN        (TAS5754M_PAGE_BASE(0) +  16)
+#define TAS5754M_GPIO_PLLIN        (TAS5754M_PAGE_BASE(0) +  18)
+#define TAS5754M_SYNCHRONIZE       (TAS5754M_PAGE_BASE(0) +  19)
+#define TAS5754M_PLL_COEFF_0       (TAS5754M_PAGE_BASE(0) +  20)
+#define TAS5754M_PLL_COEFF_1       (TAS5754M_PAGE_BASE(0) +  21)
+#define TAS5754M_PLL_COEFF_2       (TAS5754M_PAGE_BASE(0) +  22)
+#define TAS5754M_PLL_COEFF_3       (TAS5754M_PAGE_BASE(0) +  23)
+#define TAS5754M_PLL_COEFF_4       (TAS5754M_PAGE_BASE(0) +  24)
+#define TAS5754M_DSP_CLKDIV        (TAS5754M_PAGE_BASE(0) +  27)
+#define TAS5754M_DAC_CLKDIV        (TAS5754M_PAGE_BASE(0) +  28)
+#define TAS5754M_NCP_CLKDIV        (TAS5754M_PAGE_BASE(0) +  29)
+#define TAS5754M_OSR_CLKDIV        (TAS5754M_PAGE_BASE(0) +  30)
+#define TAS5754M_MASTER_CLKDIV_1   (TAS5754M_PAGE_BASE(0) +  32)
+#define TAS5754M_MASTER_CLKDIV_2   (TAS5754M_PAGE_BASE(0) +  33)
+#define TAS5754M_FS_SPEED_MODE     (TAS5754M_PAGE_BASE(0) +  34)
+#define TAS5754M_IDAC_1            (TAS5754M_PAGE_BASE(0) +  35)
+#define TAS5754M_IDAC_2            (TAS5754M_PAGE_BASE(0) +  36)
+#define TAS5754M_ERROR_DETECT      (TAS5754M_PAGE_BASE(0) +  37)
+#define TAS5754M_I2S_1             (TAS5754M_PAGE_BASE(0) +  40)
+#define TAS5754M_I2S_2             (TAS5754M_PAGE_BASE(0) +  41)
+#define TAS5754M_DAC_ROUTING       (TAS5754M_PAGE_BASE(0) +  42)
+#define TAS5754M_DSP_PROGRAM       (TAS5754M_PAGE_BASE(0) +  43)
+#define TAS5754M_CLKDET            (TAS5754M_PAGE_BASE(0) +  44)
+#define TAS5754M_AUTO_MUTE         (TAS5754M_PAGE_BASE(0) +  59)
+#define TAS5754M_DIGITAL_VOLUME_1  (TAS5754M_PAGE_BASE(0) +  60)
+#define TAS5754M_DIGITAL_VOLUME_2  (TAS5754M_PAGE_BASE(0) +  61)
+#define TAS5754M_DIGITAL_VOLUME_3  (TAS5754M_PAGE_BASE(0) +  62)
+#define TAS5754M_DIGITAL_MUTE_1    (TAS5754M_PAGE_BASE(0) +  63)
+#define TAS5754M_DIGITAL_MUTE_2    (TAS5754M_PAGE_BASE(0) +  64)
+#define TAS5754M_DIGITAL_MUTE_3    (TAS5754M_PAGE_BASE(0) +  65)
+#define TAS5754M_GPIO_OUTPUT_1     (TAS5754M_PAGE_BASE(0) +  80)
+#define TAS5754M_GPIO_OUTPUT_2     (TAS5754M_PAGE_BASE(0) +  81)
+#define TAS5754M_GPIO_OUTPUT_3     (TAS5754M_PAGE_BASE(0) +  82)
+#define TAS5754M_GPIO_OUTPUT_4     (TAS5754M_PAGE_BASE(0) +  83)
+#define TAS5754M_GPIO_OUTPUT_5     (TAS5754M_PAGE_BASE(0) +  84)
+#define TAS5754M_GPIO_OUTPUT_6     (TAS5754M_PAGE_BASE(0) +  85)
+#define TAS5754M_GPIO_CONTROL_1    (TAS5754M_PAGE_BASE(0) +  86)
+#define TAS5754M_GPIO_CONTROL_2    (TAS5754M_PAGE_BASE(0) +  87)
+#define TAS5754M_OVERFLOW          (TAS5754M_PAGE_BASE(0) +  90)
+#define TAS5754M_RATE_DET_1        (TAS5754M_PAGE_BASE(0) +  91)
+#define TAS5754M_RATE_DET_2        (TAS5754M_PAGE_BASE(0) +  92)
+#define TAS5754M_RATE_DET_3        (TAS5754M_PAGE_BASE(0) +  93)
+#define TAS5754M_RATE_DET_4        (TAS5754M_PAGE_BASE(0) +  94)
+#define TAS5754M_CLOCK_STATUS      (TAS5754M_PAGE_BASE(0) +  95)
+#define TAS5754M_ANALOG_MUTE_DET   (TAS5754M_PAGE_BASE(0) + 108)
+#define TAS5754M_GPIN              (TAS5754M_PAGE_BASE(0) + 119)
+#define TAS5754M_DIGITAL_MUTE_DET  (TAS5754M_PAGE_BASE(0) + 120)
+
+#define TAS5754M_OUTPUT_AMPLITUDE  (TAS5754M_PAGE_BASE(1) +   1)
+#define TAS5754M_ANALOG_GAIN_CTRL  (TAS5754M_PAGE_BASE(1) +   2)
+#define TAS5754M_UNDERVOLTAGE_PROT (TAS5754M_PAGE_BASE(1) +   5)
+#define TAS5754M_ANALOG_MUTE_CTRL  (TAS5754M_PAGE_BASE(1) +   6)
+#define TAS5754M_ANALOG_GAIN_BOOST (TAS5754M_PAGE_BASE(1) +   7)
+#define TAS5754M_VCOM_CTRL_1       (TAS5754M_PAGE_BASE(1) +   8)
+#define TAS5754M_VCOM_CTRL_2       (TAS5754M_PAGE_BASE(1) +   9)
+
+#define TAS5754M_CRAM_CTRL         (TAS5754M_PAGE_BASE(44) +  1)
+
+#define TAS5754M_FLEX_A            (TAS5754M_PAGE_BASE(253) + 63)
+#define TAS5754M_FLEX_B            (TAS5754M_PAGE_BASE(253) + 64)
+
+#define TAS5754M_MAX_REGISTER      (TAS5754M_PAGE_BASE(253) + 64)
+
+/* Page 0, Register 1 - reset */
+#define TAS5754M_RSTR (1 << 0)
+#define TAS5754M_RSTM (1 << 4)
+
+/* Page 0, Register 2 - power */
+#define TAS5754M_RQPD       (1 << 0)
+#define TAS5754M_RQPD_SHIFT 0
+#define TAS5754M_RQST       (1 << 4)
+#define TAS5754M_RQST_SHIFT 4
+
+/* Page 0, Register 3 - mute */
+#define TAS5754M_RQMR (1 << 0)
+#define TAS5754M_RQMR_SHIFT 0
+#define TAS5754M_RQML (1 << 4)
+#define TAS5754M_RQML_SHIFT 4
+
+/* Page 0, Register 4 - PLL */
+#define TAS5754M_PLLE       (1 << 0)
+#define TAS5754M_PLLE_SHIFT 0
+#define TAS5754M_PLCK       (1 << 4)
+#define TAS5754M_PLCK_SHIFT 4
+
+/* Page 0, Register 7 - DSP */
+#define TAS5754M_SDSL       (1 << 0)
+#define TAS5754M_SDSL_SHIFT 0
+#define TAS5754M_DEMP       (1 << 4)
+#define TAS5754M_DEMP_SHIFT 4
+
+/* Page 0, Register 8 - GPIO output enable */
+#define TAS5754M_G1OE       (1 << 0)
+#define TAS5754M_G2OE       (1 << 1)
+#define TAS5754M_G3OE       (1 << 2)
+#define TAS5754M_G4OE       (1 << 3)
+#define TAS5754M_G5OE       (1 << 4)
+#define TAS5754M_G6OE       (1 << 5)
+
+/* Page 0, Register 9 - BCK, LRCLK configuration */
+#define TAS5754M_LRKO       (1 << 0)
+#define TAS5754M_LRKO_SHIFT 0
+#define TAS5754M_BCKO       (1 << 4)
+#define TAS5754M_BCKO_SHIFT 4
+#define TAS5754M_BCKP       (1 << 5)
+#define TAS5754M_BCKP_SHIFT 5
+
+/* Page 0, Register 12 - Master mode BCK, LRCLK reset */
+#define TAS5754M_RLRK       (1 << 0)
+#define TAS5754M_RLRK_SHIFT 0
+#define TAS5754M_RBCK       (1 << 1)
+#define TAS5754M_RBCK_SHIFT 1
+
+/* Page 0, Register 13 - PLL reference */
+#define TAS5754M_SREF        (7 << 4)
+#define TAS5754M_SREF_SHIFT  4
+#define TAS5754M_SREF_SCK    (0 << 4)
+#define TAS5754M_SREF_BCK    (1 << 4)
+#define TAS5754M_SREF_GPIO   (3 << 4)
+
+/* Page 0, Register 14 - DAC reference */
+#define TAS5754M_SDAC        (7 << 4)
+#define TAS5754M_SDAC_SHIFT  4
+#define TAS5754M_SDAC_MCK    (0 << 4)
+#define TAS5754M_SDAC_PLL    (1 << 4)
+#define TAS5754M_SDAC_SCK    (3 << 4)
+#define TAS5754M_SDAC_BCK    (4 << 4)
+#define TAS5754M_SDAC_GPIO   (5 << 4)
+
+/* Page 0, Register 16, 18 - GPIO source for DAC, PLL */
+#define TAS5754M_GREF        (7 << 0)
+#define TAS5754M_GREF_SHIFT  0
+#define TAS5754M_GREF_GPIO1  (0 << 0)
+#define TAS5754M_GREF_GPIO2  (1 << 0)
+#define TAS5754M_GREF_GPIO3  (2 << 0)
+#define TAS5754M_GREF_GPIO4  (3 << 0)
+#define TAS5754M_GREF_GPIO5  (4 << 0)
+#define TAS5754M_GREF_GPIO6  (5 << 0)
+
+/* Page 0, Register 19 - synchronize */
+#define TAS5754M_RQSY        (1 << 0)
+#define TAS5754M_RQSY_RESUME (0 << 0)
+#define TAS5754M_RQSY_HALT   (1 << 0)
+
+/* Page 0, Register 34 - fs speed mode */
+#define TAS5754M_FSSP        (3 << 0)
+#define TAS5754M_FSSP_SHIFT  0
+#define TAS5754M_FSSP_48KHZ  (0 << 0)
+#define TAS5754M_FSSP_96KHZ  (1 << 0)
+#define TAS5754M_FSSP_192KHZ (2 << 0)
+#define TAS5754M_FSSP_384KHZ (3 << 0)
+
+/* Page 0, Register 37 - Error detection */
+#define TAS5754M_IPLK (1 << 0)
+#define TAS5754M_DCAS (1 << 1)
+#define TAS5754M_IDCM (1 << 2)
+#define TAS5754M_IDCH (1 << 3)
+#define TAS5754M_IDSK (1 << 4)
+#define TAS5754M_IDBK (1 << 5)
+#define TAS5754M_IDFS (1 << 6)
+
+/* Page 0, Register 40 - I2S configuration */
+#define TAS5754M_ALEN       (3 << 0)
+#define TAS5754M_ALEN_SHIFT 0
+#define TAS5754M_ALEN_16    (0 << 0)
+#define TAS5754M_ALEN_20    (1 << 0)
+#define TAS5754M_ALEN_24    (2 << 0)
+#define TAS5754M_ALEN_32    (3 << 0)
+#define TAS5754M_AFMT       (3 << 4)
+#define TAS5754M_AFMT_SHIFT 4
+#define TAS5754M_AFMT_I2S   (0 << 4)
+#define TAS5754M_AFMT_DSP   (1 << 4)
+#define TAS5754M_AFMT_RTJ   (2 << 4)
+#define TAS5754M_AFMT_LTJ   (3 << 4)
+
+/* Page 0, Register 42 - DAC routing */
+#define TAS5754M_AUPR_SHIFT 0
+#define TAS5754M_AUPL_SHIFT 4
+
+/* Page 0, Register 59 - auto mute */
+#define TAS5754M_ATMR_SHIFT 0
+#define TAS5754M_ATML_SHIFT 4
+
+/* Page 0, Register 63 - ramp rates */
+#define TAS5754M_VNDF_SHIFT 6
+#define TAS5754M_VNDS_SHIFT 4
+#define TAS5754M_VNUF_SHIFT 2
+#define TAS5754M_VNUS_SHIFT 0
+
+/* Page 0, Register 64 - emergency ramp rates */
+#define TAS5754M_VEDF_SHIFT 6
+#define TAS5754M_VEDS_SHIFT 4
+
+/* Page 0, Register 65 - Digital mute enables */
+#define TAS5754M_ACTL_SHIFT 2
+#define TAS5754M_AMLE_SHIFT 1
+#define TAS5754M_AMRE_SHIFT 0
+
+/* Page 0, Register 80-85, GPIO output selection */
+#define TAS5754M_GxSL       (31 << 0)
+#define TAS5754M_GxSL_SHIFT 0
+#define TAS5754M_GxSL_OFF   (0 << 0)
+#define TAS5754M_GxSL_DSP   (1 << 0)
+#define TAS5754M_GxSL_REG   (2 << 0)
+#define TAS5754M_GxSL_AMUTB (3 << 0)
+#define TAS5754M_GxSL_AMUTL (4 << 0)
+#define TAS5754M_GxSL_AMUTR (5 << 0)
+#define TAS5754M_GxSL_CLKI  (6 << 0)
+#define TAS5754M_GxSL_SDOUT (7 << 0)
+#define TAS5754M_GxSL_ANMUL (8 << 0)
+#define TAS5754M_GxSL_ANMUR (9 << 0)
+#define TAS5754M_GxSL_PLLLK (10 << 0)
+#define TAS5754M_GxSL_CPCLK (11 << 0)
+#define TAS5754M_GxSL_UV0_7 (14 << 0)
+#define TAS5754M_GxSL_UV0_3 (15 << 0)
+#define TAS5754M_GxSL_PLLCK (16 << 0)
+
+/* Page 1, Register 2 - analog volume control */
+#define TAS5754M_RAGN_SHIFT 0
+#define TAS5754M_LAGN_SHIFT 4
+
+/* Page 1, Register 7 - analog boost control */
+#define TAS5754M_AGBR_SHIFT 0
+#define TAS5754M_AGBL_SHIFT 4
+
+#endif

base-commit: f6274b06e326d8471cdfb52595f989a90f5e888f
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2] sound/soc: adds TAS5754M digital input amplifier component driver
@ 2021-10-29  9:57   ` Joerg Schambacher
  0 siblings, 0 replies; 21+ messages in thread
From: Joerg Schambacher @ 2021-10-29  9:57 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 29024 bytes --]

Adds a minimum component driver to run the amplifier in I2S master
mode only from standard audio clocks. Therefore, it only allows
44.1, 88.2, 176.4, 48, 96 and 192ksps with 16, 20, 24 and 32 bits
sample size. Digital volume control and the -6dB switch are supported.

Signed-off-by: Joerg Schambacher <joerg@hifiberry.com>
---
Added of_match_ptr() macro to fix the error when compiling on non CONFIG_OF
systems.

Joerg
 sound/soc/codecs/Kconfig    |   8 +
 sound/soc/codecs/Makefile   |   2 +
 sound/soc/codecs/tas5754m.c | 547 ++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/tas5754m.h | 259 +++++++++++++++++
 4 files changed, 816 insertions(+)
 create mode 100644 sound/soc/codecs/tas5754m.c
 create mode 100644 sound/soc/codecs/tas5754m.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 82ee233a269d..cf0584948fcf 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -210,6 +210,7 @@ config SND_SOC_ALL_CODECS
 	imply SND_SOC_TAS5086
 	imply SND_SOC_TAS571X
 	imply SND_SOC_TAS5720
+	imply SND_SOC_TAS5754M
 	imply SND_SOC_TAS6424
 	imply SND_SOC_TDA7419
 	imply SND_SOC_TFA9879
@@ -1419,6 +1420,13 @@ config SND_SOC_TAS5720
 	  Enable support for Texas Instruments TAS5720L/M high-efficiency mono
 	  Class-D audio power amplifiers.
 
+config SND_SOC_TAS5754M
+	tristate "Texas Instruments TAS5754M Digital Input Audio amplifier"
+	depends on I2C
+	help
+	  Enable support for Texas Instruments TAS5754M digital input
+	  Class-D audio power amplifiers.
+
 config SND_SOC_TAS6424
 	tristate "Texas Instruments TAS6424 Quad-Channel Audio amplifier"
 	depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 8dcea2c4604a..39984900258a 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -227,6 +227,7 @@ snd-soc-sti-sas-objs := sti-sas.o
 snd-soc-tas5086-objs := tas5086.o
 snd-soc-tas571x-objs := tas571x.o
 snd-soc-tas5720-objs := tas5720.o
+snd-soc-tas5754m-objs := tas5754m.o
 snd-soc-tas6424-objs := tas6424.o
 snd-soc-tda7419-objs := tda7419.o
 snd-soc-tas2770-objs := tas2770.o
@@ -555,6 +556,7 @@ obj-$(CONFIG_SND_SOC_TAS2764)	+= snd-soc-tas2764.o
 obj-$(CONFIG_SND_SOC_TAS5086)	+= snd-soc-tas5086.o
 obj-$(CONFIG_SND_SOC_TAS571X)	+= snd-soc-tas571x.o
 obj-$(CONFIG_SND_SOC_TAS5720)	+= snd-soc-tas5720.o
+obj-$(CONFIG_SND_SOC_TAS5754M)	+= snd-soc-tas5754m.o
 obj-$(CONFIG_SND_SOC_TAS6424)	+= snd-soc-tas6424.o
 obj-$(CONFIG_SND_SOC_TDA7419)	+= snd-soc-tda7419.o
 obj-$(CONFIG_SND_SOC_TAS2770) += snd-soc-tas2770.o
diff --git a/sound/soc/codecs/tas5754m.c b/sound/soc/codecs/tas5754m.c
new file mode 100644
index 000000000000..aef2c65acc26
--- /dev/null
+++ b/sound/soc/codecs/tas5754m.c
@@ -0,0 +1,547 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for the TAS5754M Audio Amplifier in Master mode (only)
+ * supports only standard audio frequencies 44.1 to 192 ksps
+ *
+ * Author: Joerg Schambacher <joerg@hifiberry.com>
+ * with fragments from Andy Liu <andy-liu@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+
+#include "tas5754m.h"
+
+#define TAS5754M_RATES		(SNDRV_PCM_RATE_48000  |	\
+				 SNDRV_PCM_RATE_96000  |	\
+				 SNDRV_PCM_RATE_192000 |	\
+				 SNDRV_PCM_RATE_44100  |	\
+				 SNDRV_PCM_RATE_88200  |	\
+				 SNDRV_PCM_RATE_176400)
+#define TAS5754M_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE  | \
+				 SNDRV_PCM_FMTBIT_S20_LE  | \
+				 SNDRV_PCM_FMTBIT_S24_LE  | \
+				 SNDRV_PCM_FMTBIT_S32_LE)
+
+
+static const struct reg_sequence tas5754m_init_sequence[] = {
+	{ TAS5754M_RESET,		0x00 },
+	{ TAS5754M_MUTE,		0x11 },
+	{ TAS5754M_POWER,		0x00 },
+	{ TAS5754M_PLL_EN,		0x00 },
+	{ TAS5754M_RESET,		0x00 },
+	{ TAS5754M_GPIO_OUTPUT_3,	0x02 },
+	{ TAS5754M_GPIO_OUTPUT_4,	0x02 },
+	{ TAS5754M_GPIO_OUTPUT_6,	0x02 },
+	{ TAS5754M_GPIO_EN,		0x2c },
+	{ TAS5754M_GPIO_CONTROL_1,	0x04 },
+	{ TAS5754M_BCLK_LRCLK_CFG,	0x11 },
+	{ TAS5754M_MASTER_MODE,		0x7c },
+	{ TAS5754M_ERROR_DETECT,	0x77 },
+	{ TAS5754M_PLL_EN,		0x01 },
+	{ TAS5754M_PLL_REF,		0x00 },
+	{ TAS5754M_PLL_COEFF_0,		0x03 },
+	{ TAS5754M_PLL_COEFF_1,		0x0c },
+	{ TAS5754M_PLL_COEFF_2,		0x00 },
+	{ TAS5754M_PLL_COEFF_3,		0x00 },
+	{ TAS5754M_PLL_COEFF_4,		0x00 },
+	{ TAS5754M_DAC_REF,		0x30 },
+	{ TAS5754M_DSP_CLKDIV,		0x01 },
+	{ TAS5754M_DAC_CLKDIV,		0x0f },
+	{ TAS5754M_NCP_CLKDIV,		0x03 },
+	{ TAS5754M_OSR_CLKDIV,		0x00 },
+	{ TAS5754M_FS_SPEED_MODE,	0x00 },
+	{ TAS5754M_MASTER_CLKDIV_1,	0x0f },
+	{ TAS5754M_MASTER_CLKDIV_2,	0x1f },
+	{ TAS5754M_I2S_1,		0x00 },
+	{ TAS5754M_I2S_2,		0x01 },
+	{ TAS5754M_PLL_EN,		0x01 },
+	{ TAS5754M_MASTER_MODE,		0x7f },
+	{ TAS5754M_MUTE,		0x11 },
+};
+
+static const struct reg_default tas5754m_reg_defaults[] = {
+	{ TAS5754M_RESET,             0x00 },
+	{ TAS5754M_POWER,             0x00 },
+	{ TAS5754M_MUTE,              0x00 },
+	{ TAS5754M_DSP,               0x00 },
+	{ TAS5754M_PLL_REF,           0x00 },
+	{ TAS5754M_DAC_REF,           0x00 },
+	{ TAS5754M_DAC_ROUTING,       0x11 },
+	{ TAS5754M_DSP_PROGRAM,       0x01 },
+	{ TAS5754M_CLKDET,            0x00 },
+	{ TAS5754M_AUTO_MUTE,         0x00 },
+	{ TAS5754M_ERROR_DETECT,      0x00 },
+	{ TAS5754M_DIGITAL_VOLUME_1,  0x00 },
+	{ TAS5754M_DIGITAL_VOLUME_2,  0x30 },
+	{ TAS5754M_DIGITAL_VOLUME_3,  0x30 },
+	{ TAS5754M_DIGITAL_MUTE_1,    0x22 },
+	{ TAS5754M_DIGITAL_MUTE_2,    0x00 },
+	{ TAS5754M_DIGITAL_MUTE_3,    0x07 },
+	{ TAS5754M_OUTPUT_AMPLITUDE,  0x00 },
+	{ TAS5754M_ANALOG_GAIN_CTRL,  0x00 },
+	{ TAS5754M_UNDERVOLTAGE_PROT, 0x00 },
+	{ TAS5754M_ANALOG_MUTE_CTRL,  0x00 },
+	{ TAS5754M_ANALOG_GAIN_BOOST, 0x00 },
+	{ TAS5754M_VCOM_CTRL_1,       0x00 },
+	{ TAS5754M_VCOM_CTRL_2,       0x01 },
+	{ TAS5754M_BCLK_LRCLK_CFG,    0x00 },
+	{ TAS5754M_MASTER_MODE,       0x7c },
+	{ TAS5754M_GPIO_DACIN,        0x00 },
+	{ TAS5754M_GPIO_PLLIN,        0x00 },
+	{ TAS5754M_SYNCHRONIZE,       0x10 },
+	{ TAS5754M_PLL_COEFF_0,       0x00 },
+	{ TAS5754M_PLL_COEFF_1,       0x00 },
+	{ TAS5754M_PLL_COEFF_2,       0x00 },
+	{ TAS5754M_PLL_COEFF_3,       0x00 },
+	{ TAS5754M_PLL_COEFF_4,       0x00 },
+	{ TAS5754M_DSP_CLKDIV,        0x00 },
+	{ TAS5754M_DAC_CLKDIV,        0x00 },
+	{ TAS5754M_NCP_CLKDIV,        0x00 },
+	{ TAS5754M_OSR_CLKDIV,        0x00 },
+	{ TAS5754M_MASTER_CLKDIV_1,   0x00 },
+	{ TAS5754M_MASTER_CLKDIV_2,   0x00 },
+	{ TAS5754M_FS_SPEED_MODE,     0x00 },
+	{ TAS5754M_IDAC_1,            0x01 },
+	{ TAS5754M_IDAC_2,            0x00 },
+};
+
+static bool tas5754m_readable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TAS5754M_RESET:
+	case TAS5754M_POWER:
+	case TAS5754M_MUTE:
+	case TAS5754M_PLL_EN:
+	case TAS5754M_SPI_MISO_FUNCTION:
+	case TAS5754M_DSP:
+	case TAS5754M_GPIO_EN:
+	case TAS5754M_BCLK_LRCLK_CFG:
+	case TAS5754M_DSP_GPIO_INPUT:
+	case TAS5754M_MASTER_MODE:
+	case TAS5754M_PLL_REF:
+	case TAS5754M_DAC_REF:
+	case TAS5754M_GPIO_DACIN:
+	case TAS5754M_GPIO_PLLIN:
+	case TAS5754M_SYNCHRONIZE:
+	case TAS5754M_PLL_COEFF_0:
+	case TAS5754M_PLL_COEFF_1:
+	case TAS5754M_PLL_COEFF_2:
+	case TAS5754M_PLL_COEFF_3:
+	case TAS5754M_PLL_COEFF_4:
+	case TAS5754M_DSP_CLKDIV:
+	case TAS5754M_DAC_CLKDIV:
+	case TAS5754M_NCP_CLKDIV:
+	case TAS5754M_OSR_CLKDIV:
+	case TAS5754M_MASTER_CLKDIV_1:
+	case TAS5754M_MASTER_CLKDIV_2:
+	case TAS5754M_FS_SPEED_MODE:
+	case TAS5754M_IDAC_1:
+	case TAS5754M_IDAC_2:
+	case TAS5754M_ERROR_DETECT:
+	case TAS5754M_I2S_1:
+	case TAS5754M_I2S_2:
+	case TAS5754M_DAC_ROUTING:
+	case TAS5754M_DSP_PROGRAM:
+	case TAS5754M_CLKDET:
+	case TAS5754M_AUTO_MUTE:
+	case TAS5754M_DIGITAL_VOLUME_1:
+	case TAS5754M_DIGITAL_VOLUME_2:
+	case TAS5754M_DIGITAL_VOLUME_3:
+	case TAS5754M_DIGITAL_MUTE_1:
+	case TAS5754M_DIGITAL_MUTE_2:
+	case TAS5754M_DIGITAL_MUTE_3:
+	case TAS5754M_GPIO_OUTPUT_1:
+	case TAS5754M_GPIO_OUTPUT_2:
+	case TAS5754M_GPIO_OUTPUT_3:
+	case TAS5754M_GPIO_OUTPUT_4:
+	case TAS5754M_GPIO_OUTPUT_5:
+	case TAS5754M_GPIO_OUTPUT_6:
+	case TAS5754M_GPIO_CONTROL_1:
+	case TAS5754M_GPIO_CONTROL_2:
+	case TAS5754M_OVERFLOW:
+	case TAS5754M_RATE_DET_1:
+	case TAS5754M_RATE_DET_2:
+	case TAS5754M_RATE_DET_3:
+	case TAS5754M_RATE_DET_4:
+	case TAS5754M_CLOCK_STATUS:
+	case TAS5754M_ANALOG_MUTE_DET:
+	case TAS5754M_GPIN:
+	case TAS5754M_DIGITAL_MUTE_DET:
+	case TAS5754M_OUTPUT_AMPLITUDE:
+	case TAS5754M_ANALOG_GAIN_CTRL:
+	case TAS5754M_UNDERVOLTAGE_PROT:
+	case TAS5754M_ANALOG_MUTE_CTRL:
+	case TAS5754M_ANALOG_GAIN_BOOST:
+	case TAS5754M_VCOM_CTRL_1:
+	case TAS5754M_VCOM_CTRL_2:
+	case TAS5754M_CRAM_CTRL:
+	case TAS5754M_FLEX_A:
+	case TAS5754M_FLEX_B:
+		return true;
+	default:
+		return reg < 0x7f;
+	}
+}
+
+static bool tas5754m_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TAS5754M_PLL_EN:
+	case TAS5754M_OVERFLOW:
+	case TAS5754M_RATE_DET_1:
+	case TAS5754M_RATE_DET_2:
+	case TAS5754M_RATE_DET_3:
+	case TAS5754M_RATE_DET_4:
+	case TAS5754M_CLOCK_STATUS:
+	case TAS5754M_ANALOG_MUTE_DET:
+	case TAS5754M_GPIN:
+	case TAS5754M_DIGITAL_MUTE_DET:
+	case TAS5754M_CRAM_CTRL:
+		return true;
+	default:
+		return reg < 0x7f;
+	}
+}
+
+struct tas5754m_priv {
+	struct regmap *regmap;
+	struct clk *sclk;
+};
+
+static const struct regmap_range_cfg tas5754m_range = {
+	.name = "Pages",
+	.range_min = TAS5754M_VIRT_BASE,
+	.range_max = TAS5754M_MAX_REGISTER,
+	.selector_reg = TAS5754M_PAGE,
+	.selector_mask = 0x7f,
+	.window_start = 0,
+	.window_len = 128,
+};
+
+const struct regmap_config tas5754m_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.ranges = &tas5754m_range,
+	.num_ranges = 1,
+	.max_register = TAS5754M_MAX_REGISTER,
+
+	.reg_defaults = tas5754m_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(tas5754m_reg_defaults),
+	.readable_reg = tas5754m_readable,
+	.volatile_reg = tas5754m_volatile,
+
+	.cache_type = REGCACHE_RBTREE,
+};
+EXPORT_SYMBOL_GPL(tas5754m_regmap);
+
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1);
+static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0);
+
+static const struct snd_kcontrol_new tas5754m_controls[] = {
+SOC_DOUBLE_R_TLV("Digital Playback Volume", TAS5754M_DIGITAL_VOLUME_2,
+		 TAS5754M_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv),
+SOC_DOUBLE_TLV("Analog Playback Volume", TAS5754M_ANALOG_GAIN_CTRL,
+	     TAS5754M_LAGN_SHIFT, TAS5754M_RAGN_SHIFT, 1, 1, analog_tlv),
+};
+
+static int tas5754m_set_bias_level(struct snd_soc_component *component,
+					enum snd_soc_bias_level level)
+{
+	struct tas5754m_priv *tas5754m =
+				snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		ret = regmap_update_bits(tas5754m->regmap,
+				TAS5754M_POWER, TAS5754M_RQST, 0);
+		if (ret != 0) {
+			dev_err(component->dev,
+				"Failed to remove standby: %d\n", ret);
+			return ret;
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		ret = regmap_update_bits(tas5754m->regmap,
+				TAS5754M_POWER, TAS5754M_RQST, TAS5754M_RQST);
+		if (ret != 0) {
+			dev_err(component->dev,
+				"Failed to request standby: %d\n", ret);
+			return ret;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static int tas5754m_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+	unsigned long bclk;
+	unsigned long mclk;
+	int sample_len;
+	int bclk_div;
+	int lrclk_div;
+	int alen;
+	int ret;
+
+	switch (params_width(params)) {
+	case 16:
+		sample_len = 16;
+		alen = TAS5754M_ALEN_16;
+		break;
+	case 20:
+		sample_len = 32;
+		alen = TAS5754M_ALEN_20;
+		break;
+	case 24:
+		sample_len = 32;
+		alen = TAS5754M_ALEN_24;
+		break;
+	case 32:
+		sample_len = 32;
+		alen = TAS5754M_ALEN_32;
+		break;
+	default:
+		dev_err(component->dev, "Unsupported sample size: %d\n",
+			params_width(params));
+		return -EINVAL;
+	}
+	ret = regmap_update_bits(tas5754m->regmap, TAS5754M_I2S_1, alen, alen);
+	if (ret != 0) {
+		dev_err(component->dev,
+			"Cannot set sample size: %d\n", ret);
+		return ret;
+	}
+
+	switch (params_rate(params)) {
+	case 44100:
+	case 48000:
+		ret = regmap_write(tas5754m->regmap,
+			TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_48KHZ);
+		break;
+	case 88200:
+	case 96000:
+		ret = regmap_write(tas5754m->regmap,
+			TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_96KHZ);
+		break;
+	case 176400:
+	case 192000:
+		ret = regmap_write(tas5754m->regmap,
+			TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_192KHZ);
+		break;
+	default:
+		dev_err(component->dev, "Sample rate not supported: %d\n",
+			params_rate(params));
+		return -EINVAL;
+	}
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to config PLL\n");
+		return ret;
+	}
+
+
+	mclk = clk_get_rate(tas5754m->sclk);
+	bclk = sample_len * 2 * params_rate(params);
+	bclk_div = mclk / bclk;
+	lrclk_div = sample_len * 2;
+
+	// stop LR / SCLK clocks
+	ret = regmap_write(tas5754m->regmap, TAS5754M_MASTER_MODE, 0x7c);
+
+	// set SCLK divider
+	ret |= regmap_write(tas5754m->regmap, TAS5754M_MASTER_CLKDIV_1,
+								bclk_div - 1);
+
+	// set LRCLK divider
+	ret |= regmap_write(tas5754m->regmap, TAS5754M_MASTER_CLKDIV_2,
+								lrclk_div - 1);
+
+	// restart LR / SCLK clocks
+	ret |= regmap_write(tas5754m->regmap, TAS5754M_MASTER_MODE, 0x7f);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to config PLL\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_component_driver tas5754m_soc_component = {
+	.set_bias_level = tas5754m_set_bias_level,
+	.idle_bias_on = true,
+	.controls = tas5754m_controls,
+	.num_controls = ARRAY_SIZE(tas5754m_controls),
+};
+
+static int tas5754m_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+	struct snd_soc_component *component = dai->component;
+
+	if (mute) {
+		snd_soc_component_write(component, TAS5754M_MUTE, 0x11);
+	} else {
+		usleep_range(1000, 2000);
+		snd_soc_component_write(component, TAS5754M_MUTE, 0x00);
+	}
+	return 0;
+}
+
+static const struct snd_soc_dai_ops tas5754m_dai_ops = {
+	.mute_stream = tas5754m_mute,
+	.hw_params = tas5754m_hw_params,
+};
+
+static struct snd_soc_dai_driver tas5754m_dai = {
+	.name		= "tas5754m-amplifier",
+	.playback	= {
+		.stream_name	= "Playback",
+		.channels_min	= 2,
+		.channels_max	= 2,
+		.rates		= TAS5754M_RATES,
+		.formats	= TAS5754M_FORMATS,
+	},
+	.ops = &tas5754m_dai_ops,
+};
+
+static int tas5754m_probe(struct device *dev, struct regmap *regmap)
+{
+	struct tas5754m_priv *tas5754m;
+	int ret;
+
+	tas5754m = devm_kzalloc(dev, sizeof(struct tas5754m_priv), GFP_KERNEL);
+	if (!tas5754m)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, tas5754m);
+	tas5754m->regmap = regmap;
+
+	ret = regmap_multi_reg_write(regmap, tas5754m_init_sequence,
+					ARRAY_SIZE(tas5754m_init_sequence));
+
+	if (ret != 0) {
+		dev_err(dev, "Failed to initialize TAS5754M: %d\n", ret);
+		goto err;
+	}
+
+	tas5754m->sclk = devm_clk_get(dev, NULL);
+	if (PTR_ERR(tas5754m->sclk) == -EPROBE_DEFER) {
+		ret = -EPROBE_DEFER;
+		goto err;
+	}
+	if (!IS_ERR(tas5754m->sclk)) {
+		ret = clk_prepare_enable(tas5754m->sclk);
+		if (ret != 0) {
+			dev_err(dev, "Failed to enable SCLK: %d\n", ret);
+			goto err;
+		}
+	}
+
+	ret = snd_soc_register_component(dev,
+			&tas5754m_soc_component, &tas5754m_dai, 1);
+	if (ret != 0) {
+		dev_err(dev, "Failed to register CODEC: %d\n", ret);
+		goto err;
+	}
+
+	return 0;
+
+err:
+	return ret;
+
+}
+
+static int tas5754m_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+{
+	struct regmap *regmap;
+	struct regmap_config config = tas5754m_regmap;
+
+	/* enable auto-increment mode */
+	config.read_flag_mask = 0x80;
+	config.write_flag_mask = 0x80;
+
+	regmap = devm_regmap_init_i2c(i2c, &config);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return tas5754m_probe(&i2c->dev, regmap);
+}
+
+static int tas5754m_remove(struct device *dev)
+{
+	snd_soc_unregister_component(dev);
+
+	return 0;
+}
+
+static int tas5754m_i2c_remove(struct i2c_client *i2c)
+{
+	tas5754m_remove(&i2c->dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id tas5754m_i2c_id[] = {
+	{ "tas5754m", },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tas5754m_i2c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id tas5754m_of_match[] = {
+	{ .compatible = "ti,tas5754m", },
+	{ .compatible = "ti,tas5756m", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, tas5754m_of_match);
+#endif
+
+static struct i2c_driver tas5754m_i2c_driver = {
+	.probe		= tas5754m_i2c_probe,
+	.remove		= tas5754m_i2c_remove,
+	.id_table	= tas5754m_i2c_id,
+	.driver		= {
+		.name	= "tas5754m",
+		.of_match_table = of_match_ptr(tas5754m_of_match),
+	},
+};
+
+module_i2c_driver(tas5754m_i2c_driver);
+
+MODULE_AUTHOR("Joerg Schambacher <joerg@hifiberry.com>");
+MODULE_DESCRIPTION("TAS5754M Audio Amplifier Driver - Master mode only");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas5754m.h b/sound/soc/codecs/tas5754m.h
new file mode 100644
index 000000000000..492b8abede6c
--- /dev/null
+++ b/sound/soc/codecs/tas5754m.h
@@ -0,0 +1,259 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Driver for the TAS5754M DAC+amplifier combo devices
+ *
+ * Author:	(copied from pcm512x.h)
+ *		Mark Brown <broonie@kernel.org>
+ *		Copyright 2014 Linaro Ltd
+ */
+
+#ifndef _SND_SOC_TAS5754M
+#define _SND_SOC_TAS5754M
+
+#include <linux/pm.h>
+#include <linux/regmap.h>
+
+#define TAS5754M_VIRT_BASE 0x000
+#define TAS5754M_PAGE_LEN  0x80
+#define TAS5754M_PAGE_BASE(n)  (TAS5754M_VIRT_BASE + (TAS5754M_PAGE_LEN * n))
+
+#define TAS5754M_PAGE              0
+
+#define TAS5754M_RESET             (TAS5754M_PAGE_BASE(0) +   1)
+#define TAS5754M_POWER             (TAS5754M_PAGE_BASE(0) +   2)
+#define TAS5754M_MUTE              (TAS5754M_PAGE_BASE(0) +   3)
+#define TAS5754M_PLL_EN            (TAS5754M_PAGE_BASE(0) +   4)
+#define TAS5754M_SPI_MISO_FUNCTION (TAS5754M_PAGE_BASE(0) +   6)
+#define TAS5754M_DSP               (TAS5754M_PAGE_BASE(0) +   7)
+#define TAS5754M_GPIO_EN           (TAS5754M_PAGE_BASE(0) +   8)
+#define TAS5754M_BCLK_LRCLK_CFG    (TAS5754M_PAGE_BASE(0) +   9)
+#define TAS5754M_DSP_GPIO_INPUT    (TAS5754M_PAGE_BASE(0) +  10)
+#define TAS5754M_MASTER_MODE       (TAS5754M_PAGE_BASE(0) +  12)
+#define TAS5754M_PLL_REF           (TAS5754M_PAGE_BASE(0) +  13)
+#define TAS5754M_DAC_REF           (TAS5754M_PAGE_BASE(0) +  14)
+#define TAS5754M_GPIO_DACIN        (TAS5754M_PAGE_BASE(0) +  16)
+#define TAS5754M_GPIO_PLLIN        (TAS5754M_PAGE_BASE(0) +  18)
+#define TAS5754M_SYNCHRONIZE       (TAS5754M_PAGE_BASE(0) +  19)
+#define TAS5754M_PLL_COEFF_0       (TAS5754M_PAGE_BASE(0) +  20)
+#define TAS5754M_PLL_COEFF_1       (TAS5754M_PAGE_BASE(0) +  21)
+#define TAS5754M_PLL_COEFF_2       (TAS5754M_PAGE_BASE(0) +  22)
+#define TAS5754M_PLL_COEFF_3       (TAS5754M_PAGE_BASE(0) +  23)
+#define TAS5754M_PLL_COEFF_4       (TAS5754M_PAGE_BASE(0) +  24)
+#define TAS5754M_DSP_CLKDIV        (TAS5754M_PAGE_BASE(0) +  27)
+#define TAS5754M_DAC_CLKDIV        (TAS5754M_PAGE_BASE(0) +  28)
+#define TAS5754M_NCP_CLKDIV        (TAS5754M_PAGE_BASE(0) +  29)
+#define TAS5754M_OSR_CLKDIV        (TAS5754M_PAGE_BASE(0) +  30)
+#define TAS5754M_MASTER_CLKDIV_1   (TAS5754M_PAGE_BASE(0) +  32)
+#define TAS5754M_MASTER_CLKDIV_2   (TAS5754M_PAGE_BASE(0) +  33)
+#define TAS5754M_FS_SPEED_MODE     (TAS5754M_PAGE_BASE(0) +  34)
+#define TAS5754M_IDAC_1            (TAS5754M_PAGE_BASE(0) +  35)
+#define TAS5754M_IDAC_2            (TAS5754M_PAGE_BASE(0) +  36)
+#define TAS5754M_ERROR_DETECT      (TAS5754M_PAGE_BASE(0) +  37)
+#define TAS5754M_I2S_1             (TAS5754M_PAGE_BASE(0) +  40)
+#define TAS5754M_I2S_2             (TAS5754M_PAGE_BASE(0) +  41)
+#define TAS5754M_DAC_ROUTING       (TAS5754M_PAGE_BASE(0) +  42)
+#define TAS5754M_DSP_PROGRAM       (TAS5754M_PAGE_BASE(0) +  43)
+#define TAS5754M_CLKDET            (TAS5754M_PAGE_BASE(0) +  44)
+#define TAS5754M_AUTO_MUTE         (TAS5754M_PAGE_BASE(0) +  59)
+#define TAS5754M_DIGITAL_VOLUME_1  (TAS5754M_PAGE_BASE(0) +  60)
+#define TAS5754M_DIGITAL_VOLUME_2  (TAS5754M_PAGE_BASE(0) +  61)
+#define TAS5754M_DIGITAL_VOLUME_3  (TAS5754M_PAGE_BASE(0) +  62)
+#define TAS5754M_DIGITAL_MUTE_1    (TAS5754M_PAGE_BASE(0) +  63)
+#define TAS5754M_DIGITAL_MUTE_2    (TAS5754M_PAGE_BASE(0) +  64)
+#define TAS5754M_DIGITAL_MUTE_3    (TAS5754M_PAGE_BASE(0) +  65)
+#define TAS5754M_GPIO_OUTPUT_1     (TAS5754M_PAGE_BASE(0) +  80)
+#define TAS5754M_GPIO_OUTPUT_2     (TAS5754M_PAGE_BASE(0) +  81)
+#define TAS5754M_GPIO_OUTPUT_3     (TAS5754M_PAGE_BASE(0) +  82)
+#define TAS5754M_GPIO_OUTPUT_4     (TAS5754M_PAGE_BASE(0) +  83)
+#define TAS5754M_GPIO_OUTPUT_5     (TAS5754M_PAGE_BASE(0) +  84)
+#define TAS5754M_GPIO_OUTPUT_6     (TAS5754M_PAGE_BASE(0) +  85)
+#define TAS5754M_GPIO_CONTROL_1    (TAS5754M_PAGE_BASE(0) +  86)
+#define TAS5754M_GPIO_CONTROL_2    (TAS5754M_PAGE_BASE(0) +  87)
+#define TAS5754M_OVERFLOW          (TAS5754M_PAGE_BASE(0) +  90)
+#define TAS5754M_RATE_DET_1        (TAS5754M_PAGE_BASE(0) +  91)
+#define TAS5754M_RATE_DET_2        (TAS5754M_PAGE_BASE(0) +  92)
+#define TAS5754M_RATE_DET_3        (TAS5754M_PAGE_BASE(0) +  93)
+#define TAS5754M_RATE_DET_4        (TAS5754M_PAGE_BASE(0) +  94)
+#define TAS5754M_CLOCK_STATUS      (TAS5754M_PAGE_BASE(0) +  95)
+#define TAS5754M_ANALOG_MUTE_DET   (TAS5754M_PAGE_BASE(0) + 108)
+#define TAS5754M_GPIN              (TAS5754M_PAGE_BASE(0) + 119)
+#define TAS5754M_DIGITAL_MUTE_DET  (TAS5754M_PAGE_BASE(0) + 120)
+
+#define TAS5754M_OUTPUT_AMPLITUDE  (TAS5754M_PAGE_BASE(1) +   1)
+#define TAS5754M_ANALOG_GAIN_CTRL  (TAS5754M_PAGE_BASE(1) +   2)
+#define TAS5754M_UNDERVOLTAGE_PROT (TAS5754M_PAGE_BASE(1) +   5)
+#define TAS5754M_ANALOG_MUTE_CTRL  (TAS5754M_PAGE_BASE(1) +   6)
+#define TAS5754M_ANALOG_GAIN_BOOST (TAS5754M_PAGE_BASE(1) +   7)
+#define TAS5754M_VCOM_CTRL_1       (TAS5754M_PAGE_BASE(1) +   8)
+#define TAS5754M_VCOM_CTRL_2       (TAS5754M_PAGE_BASE(1) +   9)
+
+#define TAS5754M_CRAM_CTRL         (TAS5754M_PAGE_BASE(44) +  1)
+
+#define TAS5754M_FLEX_A            (TAS5754M_PAGE_BASE(253) + 63)
+#define TAS5754M_FLEX_B            (TAS5754M_PAGE_BASE(253) + 64)
+
+#define TAS5754M_MAX_REGISTER      (TAS5754M_PAGE_BASE(253) + 64)
+
+/* Page 0, Register 1 - reset */
+#define TAS5754M_RSTR (1 << 0)
+#define TAS5754M_RSTM (1 << 4)
+
+/* Page 0, Register 2 - power */
+#define TAS5754M_RQPD       (1 << 0)
+#define TAS5754M_RQPD_SHIFT 0
+#define TAS5754M_RQST       (1 << 4)
+#define TAS5754M_RQST_SHIFT 4
+
+/* Page 0, Register 3 - mute */
+#define TAS5754M_RQMR (1 << 0)
+#define TAS5754M_RQMR_SHIFT 0
+#define TAS5754M_RQML (1 << 4)
+#define TAS5754M_RQML_SHIFT 4
+
+/* Page 0, Register 4 - PLL */
+#define TAS5754M_PLLE       (1 << 0)
+#define TAS5754M_PLLE_SHIFT 0
+#define TAS5754M_PLCK       (1 << 4)
+#define TAS5754M_PLCK_SHIFT 4
+
+/* Page 0, Register 7 - DSP */
+#define TAS5754M_SDSL       (1 << 0)
+#define TAS5754M_SDSL_SHIFT 0
+#define TAS5754M_DEMP       (1 << 4)
+#define TAS5754M_DEMP_SHIFT 4
+
+/* Page 0, Register 8 - GPIO output enable */
+#define TAS5754M_G1OE       (1 << 0)
+#define TAS5754M_G2OE       (1 << 1)
+#define TAS5754M_G3OE       (1 << 2)
+#define TAS5754M_G4OE       (1 << 3)
+#define TAS5754M_G5OE       (1 << 4)
+#define TAS5754M_G6OE       (1 << 5)
+
+/* Page 0, Register 9 - BCK, LRCLK configuration */
+#define TAS5754M_LRKO       (1 << 0)
+#define TAS5754M_LRKO_SHIFT 0
+#define TAS5754M_BCKO       (1 << 4)
+#define TAS5754M_BCKO_SHIFT 4
+#define TAS5754M_BCKP       (1 << 5)
+#define TAS5754M_BCKP_SHIFT 5
+
+/* Page 0, Register 12 - Master mode BCK, LRCLK reset */
+#define TAS5754M_RLRK       (1 << 0)
+#define TAS5754M_RLRK_SHIFT 0
+#define TAS5754M_RBCK       (1 << 1)
+#define TAS5754M_RBCK_SHIFT 1
+
+/* Page 0, Register 13 - PLL reference */
+#define TAS5754M_SREF        (7 << 4)
+#define TAS5754M_SREF_SHIFT  4
+#define TAS5754M_SREF_SCK    (0 << 4)
+#define TAS5754M_SREF_BCK    (1 << 4)
+#define TAS5754M_SREF_GPIO   (3 << 4)
+
+/* Page 0, Register 14 - DAC reference */
+#define TAS5754M_SDAC        (7 << 4)
+#define TAS5754M_SDAC_SHIFT  4
+#define TAS5754M_SDAC_MCK    (0 << 4)
+#define TAS5754M_SDAC_PLL    (1 << 4)
+#define TAS5754M_SDAC_SCK    (3 << 4)
+#define TAS5754M_SDAC_BCK    (4 << 4)
+#define TAS5754M_SDAC_GPIO   (5 << 4)
+
+/* Page 0, Register 16, 18 - GPIO source for DAC, PLL */
+#define TAS5754M_GREF        (7 << 0)
+#define TAS5754M_GREF_SHIFT  0
+#define TAS5754M_GREF_GPIO1  (0 << 0)
+#define TAS5754M_GREF_GPIO2  (1 << 0)
+#define TAS5754M_GREF_GPIO3  (2 << 0)
+#define TAS5754M_GREF_GPIO4  (3 << 0)
+#define TAS5754M_GREF_GPIO5  (4 << 0)
+#define TAS5754M_GREF_GPIO6  (5 << 0)
+
+/* Page 0, Register 19 - synchronize */
+#define TAS5754M_RQSY        (1 << 0)
+#define TAS5754M_RQSY_RESUME (0 << 0)
+#define TAS5754M_RQSY_HALT   (1 << 0)
+
+/* Page 0, Register 34 - fs speed mode */
+#define TAS5754M_FSSP        (3 << 0)
+#define TAS5754M_FSSP_SHIFT  0
+#define TAS5754M_FSSP_48KHZ  (0 << 0)
+#define TAS5754M_FSSP_96KHZ  (1 << 0)
+#define TAS5754M_FSSP_192KHZ (2 << 0)
+#define TAS5754M_FSSP_384KHZ (3 << 0)
+
+/* Page 0, Register 37 - Error detection */
+#define TAS5754M_IPLK (1 << 0)
+#define TAS5754M_DCAS (1 << 1)
+#define TAS5754M_IDCM (1 << 2)
+#define TAS5754M_IDCH (1 << 3)
+#define TAS5754M_IDSK (1 << 4)
+#define TAS5754M_IDBK (1 << 5)
+#define TAS5754M_IDFS (1 << 6)
+
+/* Page 0, Register 40 - I2S configuration */
+#define TAS5754M_ALEN       (3 << 0)
+#define TAS5754M_ALEN_SHIFT 0
+#define TAS5754M_ALEN_16    (0 << 0)
+#define TAS5754M_ALEN_20    (1 << 0)
+#define TAS5754M_ALEN_24    (2 << 0)
+#define TAS5754M_ALEN_32    (3 << 0)
+#define TAS5754M_AFMT       (3 << 4)
+#define TAS5754M_AFMT_SHIFT 4
+#define TAS5754M_AFMT_I2S   (0 << 4)
+#define TAS5754M_AFMT_DSP   (1 << 4)
+#define TAS5754M_AFMT_RTJ   (2 << 4)
+#define TAS5754M_AFMT_LTJ   (3 << 4)
+
+/* Page 0, Register 42 - DAC routing */
+#define TAS5754M_AUPR_SHIFT 0
+#define TAS5754M_AUPL_SHIFT 4
+
+/* Page 0, Register 59 - auto mute */
+#define TAS5754M_ATMR_SHIFT 0
+#define TAS5754M_ATML_SHIFT 4
+
+/* Page 0, Register 63 - ramp rates */
+#define TAS5754M_VNDF_SHIFT 6
+#define TAS5754M_VNDS_SHIFT 4
+#define TAS5754M_VNUF_SHIFT 2
+#define TAS5754M_VNUS_SHIFT 0
+
+/* Page 0, Register 64 - emergency ramp rates */
+#define TAS5754M_VEDF_SHIFT 6
+#define TAS5754M_VEDS_SHIFT 4
+
+/* Page 0, Register 65 - Digital mute enables */
+#define TAS5754M_ACTL_SHIFT 2
+#define TAS5754M_AMLE_SHIFT 1
+#define TAS5754M_AMRE_SHIFT 0
+
+/* Page 0, Register 80-85, GPIO output selection */
+#define TAS5754M_GxSL       (31 << 0)
+#define TAS5754M_GxSL_SHIFT 0
+#define TAS5754M_GxSL_OFF   (0 << 0)
+#define TAS5754M_GxSL_DSP   (1 << 0)
+#define TAS5754M_GxSL_REG   (2 << 0)
+#define TAS5754M_GxSL_AMUTB (3 << 0)
+#define TAS5754M_GxSL_AMUTL (4 << 0)
+#define TAS5754M_GxSL_AMUTR (5 << 0)
+#define TAS5754M_GxSL_CLKI  (6 << 0)
+#define TAS5754M_GxSL_SDOUT (7 << 0)
+#define TAS5754M_GxSL_ANMUL (8 << 0)
+#define TAS5754M_GxSL_ANMUR (9 << 0)
+#define TAS5754M_GxSL_PLLLK (10 << 0)
+#define TAS5754M_GxSL_CPCLK (11 << 0)
+#define TAS5754M_GxSL_UV0_7 (14 << 0)
+#define TAS5754M_GxSL_UV0_3 (15 << 0)
+#define TAS5754M_GxSL_PLLCK (16 << 0)
+
+/* Page 1, Register 2 - analog volume control */
+#define TAS5754M_RAGN_SHIFT 0
+#define TAS5754M_LAGN_SHIFT 4
+
+/* Page 1, Register 7 - analog boost control */
+#define TAS5754M_AGBR_SHIFT 0
+#define TAS5754M_AGBL_SHIFT 4
+
+#endif

base-commit: f6274b06e326d8471cdfb52595f989a90f5e888f
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH v2] sound/soc: adds TAS5754M digital input amplifier component driver
  2021-10-29  9:57   ` Joerg Schambacher
@ 2021-11-17 15:13     ` Mark Brown
  -1 siblings, 0 replies; 21+ messages in thread
From: Mark Brown @ 2021-11-17 15:13 UTC (permalink / raw)
  To: Joerg Schambacher; +Cc: alsa-devel, kbuild-all

[-- Attachment #1: Type: text/plain, Size: 14590 bytes --]

On Fri, Oct 29, 2021 at 11:57:30AM +0200, Joerg Schambacher wrote:

> Adds a minimum component driver to run the amplifier in I2S master
> mode only from standard audio clocks. Therefore, it only allows
> 44.1, 88.2, 176.4, 48, 96 and 192ksps with 16, 20, 24 and 32 bits
> sample size. Digital volume control and the -6dB switch are supported.

This looks pretty clean, there's a bunch of minor stylistic bits below
but other than one major thing this looks good.  The major thing is the
use of a had coded init sequence to configure the device rather than
implemenenting the relevant APIs to do so, that's going to make the
driver unsuitable for use on boards other than the specific one you
happen to be looking at at the minute.

Please submit patches using subject lines reflecting the style for the
subsystem, this makes it easier for people to identify relevant patches.
Look at what existing commits in the area you're changing are doing and
make sure your subject lines visually resemble what they're doing.

> @@ -0,0 +1,547 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Driver for the TAS5754M Audio Amplifier in Master mode (only)
> + * supports only standard audio frequencies 44.1 to 192 ksps

Please make the entire comment a C++ one so things look more
intentional.

> +EXPORT_SYMBOL_GPL(tas5754m_regmap);

There's only one file in the driver, why is this exported?

> +	mclk = clk_get_rate(tas5754m->sclk);
> +	bclk = sample_len * 2 * params_rate(params);

snd_soc_params_to_bclk().

> +	// set SCLK divider
> +	ret |= regmap_write(tas5754m->regmap, TAS5754M_MASTER_CLKDIV_1,
> +								bclk_div - 1);
> +
> +	// set LRCLK divider
> +	ret |= regmap_write(tas5754m->regmap, TAS5754M_MASTER_CLKDIV_2,
> +								lrclk_div - 1);

Check the return statuses individually or just don't bother, if you or
them together then you could end up with a nonsensical error code which
could cause confusion down the line.

> +	if (mute) {
> +		snd_soc_component_write(component, TAS5754M_MUTE, 0x11);
> +	} else {
> +		usleep_range(1000, 2000);
> +		snd_soc_component_write(component, TAS5754M_MUTE, 0x00);

Why the sleep here?

> +	ret = regmap_multi_reg_write(regmap, tas5754m_init_sequence,
> +					ARRAY_SIZE(tas5754m_init_sequence));

This init sequence looks an awful lot like it's doing board specific
configuration - it's enabling the PLL, configuring GPIOs and clock
dividers among other things.  These should all be done through board
specific configuration or based on the currently configured audio path,
what's suitable for one board may not be suitable for another board.
Doing a reset of the chip is good but the rest of it really looks like
it doesn't belong.

> +	ret = snd_soc_register_component(dev,
> +			&tas5754m_soc_component, &tas5754m_dai, 1);

devm_snd_soc_register_component()

> +static const struct i2c_device_id tas5754m_i2c_id[] = {
> +	{ "tas5754m", },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(i2c, tas5754m_i2c_id);
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id tas5754m_of_match[] = {
> +	{ .compatible = "ti,tas5754m", },
> +	{ .compatible = "ti,tas5756m", },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, tas5754m_of_match);
> +#endif

Why not list both I2C IDs as well?

> @@ -0,0 +1,259 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Driver for the TAS5754M DAC+amplifier combo devices
> + *
> + * Author:	(copied from pcm512x.h)
> + *		Mark Brown <broonie@kernel.org>
> + *		Copyright 2014 Linaro Ltd
> + */

If the register map can be copied can't the two drivers be combined?

> +#define TAS5754M_VIRT_BASE 0x000
> +#define TAS5754M_PAGE_LEN  0x80
> +#define TAS5754M_PAGE_BASE(n)  (TAS5754M_VIRT_BASE + (TAS5754M_PAGE_LEN * n))
> +
> +#define TAS5754M_PAGE              0

There's no mention of paging in the regmap description for the driver
which feels like it's asking for problems.

> +
> +#define TAS5754M_RESET             (TAS5754M_PAGE_BASE(0) +   1)
> +#define TAS5754M_POWER             (TAS5754M_PAGE_BASE(0) +   2)
> +#define TAS5754M_MUTE              (TAS5754M_PAGE_BASE(0) +   3)
> +#define TAS5754M_PLL_EN            (TAS5754M_PAGE_BASE(0) +   4)
> +#define TAS5754M_SPI_MISO_FUNCTION (TAS5754M_PAGE_BASE(0) +   6)
> +#define TAS5754M_DSP               (TAS5754M_PAGE_BASE(0) +   7)
> +#define TAS5754M_GPIO_EN           (TAS5754M_PAGE_BASE(0) +   8)
> +#define TAS5754M_BCLK_LRCLK_CFG    (TAS5754M_PAGE_BASE(0) +   9)
> +#define TAS5754M_DSP_GPIO_INPUT    (TAS5754M_PAGE_BASE(0) +  10)
> +#define TAS5754M_MASTER_MODE       (TAS5754M_PAGE_BASE(0) +  12)
> +#define TAS5754M_PLL_REF           (TAS5754M_PAGE_BASE(0) +  13)
> +#define TAS5754M_DAC_REF           (TAS5754M_PAGE_BASE(0) +  14)
> +#define TAS5754M_GPIO_DACIN        (TAS5754M_PAGE_BASE(0) +  16)
> +#define TAS5754M_GPIO_PLLIN        (TAS5754M_PAGE_BASE(0) +  18)
> +#define TAS5754M_SYNCHRONIZE       (TAS5754M_PAGE_BASE(0) +  19)
> +#define TAS5754M_PLL_COEFF_0       (TAS5754M_PAGE_BASE(0) +  20)
> +#define TAS5754M_PLL_COEFF_1       (TAS5754M_PAGE_BASE(0) +  21)
> +#define TAS5754M_PLL_COEFF_2       (TAS5754M_PAGE_BASE(0) +  22)
> +#define TAS5754M_PLL_COEFF_3       (TAS5754M_PAGE_BASE(0) +  23)
> +#define TAS5754M_PLL_COEFF_4       (TAS5754M_PAGE_BASE(0) +  24)
> +#define TAS5754M_DSP_CLKDIV        (TAS5754M_PAGE_BASE(0) +  27)
> +#define TAS5754M_DAC_CLKDIV        (TAS5754M_PAGE_BASE(0) +  28)
> +#define TAS5754M_NCP_CLKDIV        (TAS5754M_PAGE_BASE(0) +  29)
> +#define TAS5754M_OSR_CLKDIV        (TAS5754M_PAGE_BASE(0) +  30)
> +#define TAS5754M_MASTER_CLKDIV_1   (TAS5754M_PAGE_BASE(0) +  32)
> +#define TAS5754M_MASTER_CLKDIV_2   (TAS5754M_PAGE_BASE(0) +  33)
> +#define TAS5754M_FS_SPEED_MODE     (TAS5754M_PAGE_BASE(0) +  34)
> +#define TAS5754M_IDAC_1            (TAS5754M_PAGE_BASE(0) +  35)
> +#define TAS5754M_IDAC_2            (TAS5754M_PAGE_BASE(0) +  36)
> +#define TAS5754M_ERROR_DETECT      (TAS5754M_PAGE_BASE(0) +  37)
> +#define TAS5754M_I2S_1             (TAS5754M_PAGE_BASE(0) +  40)
> +#define TAS5754M_I2S_2             (TAS5754M_PAGE_BASE(0) +  41)
> +#define TAS5754M_DAC_ROUTING       (TAS5754M_PAGE_BASE(0) +  42)
> +#define TAS5754M_DSP_PROGRAM       (TAS5754M_PAGE_BASE(0) +  43)
> +#define TAS5754M_CLKDET            (TAS5754M_PAGE_BASE(0) +  44)
> +#define TAS5754M_AUTO_MUTE         (TAS5754M_PAGE_BASE(0) +  59)
> +#define TAS5754M_DIGITAL_VOLUME_1  (TAS5754M_PAGE_BASE(0) +  60)
> +#define TAS5754M_DIGITAL_VOLUME_2  (TAS5754M_PAGE_BASE(0) +  61)
> +#define TAS5754M_DIGITAL_VOLUME_3  (TAS5754M_PAGE_BASE(0) +  62)
> +#define TAS5754M_DIGITAL_MUTE_1    (TAS5754M_PAGE_BASE(0) +  63)
> +#define TAS5754M_DIGITAL_MUTE_2    (TAS5754M_PAGE_BASE(0) +  64)
> +#define TAS5754M_DIGITAL_MUTE_3    (TAS5754M_PAGE_BASE(0) +  65)
> +#define TAS5754M_GPIO_OUTPUT_1     (TAS5754M_PAGE_BASE(0) +  80)
> +#define TAS5754M_GPIO_OUTPUT_2     (TAS5754M_PAGE_BASE(0) +  81)
> +#define TAS5754M_GPIO_OUTPUT_3     (TAS5754M_PAGE_BASE(0) +  82)
> +#define TAS5754M_GPIO_OUTPUT_4     (TAS5754M_PAGE_BASE(0) +  83)
> +#define TAS5754M_GPIO_OUTPUT_5     (TAS5754M_PAGE_BASE(0) +  84)
> +#define TAS5754M_GPIO_OUTPUT_6     (TAS5754M_PAGE_BASE(0) +  85)
> +#define TAS5754M_GPIO_CONTROL_1    (TAS5754M_PAGE_BASE(0) +  86)
> +#define TAS5754M_GPIO_CONTROL_2    (TAS5754M_PAGE_BASE(0) +  87)
> +#define TAS5754M_OVERFLOW          (TAS5754M_PAGE_BASE(0) +  90)
> +#define TAS5754M_RATE_DET_1        (TAS5754M_PAGE_BASE(0) +  91)
> +#define TAS5754M_RATE_DET_2        (TAS5754M_PAGE_BASE(0) +  92)
> +#define TAS5754M_RATE_DET_3        (TAS5754M_PAGE_BASE(0) +  93)
> +#define TAS5754M_RATE_DET_4        (TAS5754M_PAGE_BASE(0) +  94)
> +#define TAS5754M_CLOCK_STATUS      (TAS5754M_PAGE_BASE(0) +  95)
> +#define TAS5754M_ANALOG_MUTE_DET   (TAS5754M_PAGE_BASE(0) + 108)
> +#define TAS5754M_GPIN              (TAS5754M_PAGE_BASE(0) + 119)
> +#define TAS5754M_DIGITAL_MUTE_DET  (TAS5754M_PAGE_BASE(0) + 120)
> +
> +#define TAS5754M_OUTPUT_AMPLITUDE  (TAS5754M_PAGE_BASE(1) +   1)
> +#define TAS5754M_ANALOG_GAIN_CTRL  (TAS5754M_PAGE_BASE(1) +   2)
> +#define TAS5754M_UNDERVOLTAGE_PROT (TAS5754M_PAGE_BASE(1) +   5)
> +#define TAS5754M_ANALOG_MUTE_CTRL  (TAS5754M_PAGE_BASE(1) +   6)
> +#define TAS5754M_ANALOG_GAIN_BOOST (TAS5754M_PAGE_BASE(1) +   7)
> +#define TAS5754M_VCOM_CTRL_1       (TAS5754M_PAGE_BASE(1) +   8)
> +#define TAS5754M_VCOM_CTRL_2       (TAS5754M_PAGE_BASE(1) +   9)
> +
> +#define TAS5754M_CRAM_CTRL         (TAS5754M_PAGE_BASE(44) +  1)
> +
> +#define TAS5754M_FLEX_A            (TAS5754M_PAGE_BASE(253) + 63)
> +#define TAS5754M_FLEX_B            (TAS5754M_PAGE_BASE(253) + 64)
> +
> +#define TAS5754M_MAX_REGISTER      (TAS5754M_PAGE_BASE(253) + 64)
> +
> +/* Page 0, Register 1 - reset */
> +#define TAS5754M_RSTR (1 << 0)
> +#define TAS5754M_RSTM (1 << 4)
> +
> +/* Page 0, Register 2 - power */
> +#define TAS5754M_RQPD       (1 << 0)
> +#define TAS5754M_RQPD_SHIFT 0
> +#define TAS5754M_RQST       (1 << 4)
> +#define TAS5754M_RQST_SHIFT 4
> +
> +/* Page 0, Register 3 - mute */
> +#define TAS5754M_RQMR (1 << 0)
> +#define TAS5754M_RQMR_SHIFT 0
> +#define TAS5754M_RQML (1 << 4)
> +#define TAS5754M_RQML_SHIFT 4
> +
> +/* Page 0, Register 4 - PLL */
> +#define TAS5754M_PLLE       (1 << 0)
> +#define TAS5754M_PLLE_SHIFT 0
> +#define TAS5754M_PLCK       (1 << 4)
> +#define TAS5754M_PLCK_SHIFT 4
> +
> +/* Page 0, Register 7 - DSP */
> +#define TAS5754M_SDSL       (1 << 0)
> +#define TAS5754M_SDSL_SHIFT 0
> +#define TAS5754M_DEMP       (1 << 4)
> +#define TAS5754M_DEMP_SHIFT 4
> +
> +/* Page 0, Register 8 - GPIO output enable */
> +#define TAS5754M_G1OE       (1 << 0)
> +#define TAS5754M_G2OE       (1 << 1)
> +#define TAS5754M_G3OE       (1 << 2)
> +#define TAS5754M_G4OE       (1 << 3)
> +#define TAS5754M_G5OE       (1 << 4)
> +#define TAS5754M_G6OE       (1 << 5)
> +
> +/* Page 0, Register 9 - BCK, LRCLK configuration */
> +#define TAS5754M_LRKO       (1 << 0)
> +#define TAS5754M_LRKO_SHIFT 0
> +#define TAS5754M_BCKO       (1 << 4)
> +#define TAS5754M_BCKO_SHIFT 4
> +#define TAS5754M_BCKP       (1 << 5)
> +#define TAS5754M_BCKP_SHIFT 5
> +
> +/* Page 0, Register 12 - Master mode BCK, LRCLK reset */
> +#define TAS5754M_RLRK       (1 << 0)
> +#define TAS5754M_RLRK_SHIFT 0
> +#define TAS5754M_RBCK       (1 << 1)
> +#define TAS5754M_RBCK_SHIFT 1
> +
> +/* Page 0, Register 13 - PLL reference */
> +#define TAS5754M_SREF        (7 << 4)
> +#define TAS5754M_SREF_SHIFT  4
> +#define TAS5754M_SREF_SCK    (0 << 4)
> +#define TAS5754M_SREF_BCK    (1 << 4)
> +#define TAS5754M_SREF_GPIO   (3 << 4)
> +
> +/* Page 0, Register 14 - DAC reference */
> +#define TAS5754M_SDAC        (7 << 4)
> +#define TAS5754M_SDAC_SHIFT  4
> +#define TAS5754M_SDAC_MCK    (0 << 4)
> +#define TAS5754M_SDAC_PLL    (1 << 4)
> +#define TAS5754M_SDAC_SCK    (3 << 4)
> +#define TAS5754M_SDAC_BCK    (4 << 4)
> +#define TAS5754M_SDAC_GPIO   (5 << 4)
> +
> +/* Page 0, Register 16, 18 - GPIO source for DAC, PLL */
> +#define TAS5754M_GREF        (7 << 0)
> +#define TAS5754M_GREF_SHIFT  0
> +#define TAS5754M_GREF_GPIO1  (0 << 0)
> +#define TAS5754M_GREF_GPIO2  (1 << 0)
> +#define TAS5754M_GREF_GPIO3  (2 << 0)
> +#define TAS5754M_GREF_GPIO4  (3 << 0)
> +#define TAS5754M_GREF_GPIO5  (4 << 0)
> +#define TAS5754M_GREF_GPIO6  (5 << 0)
> +
> +/* Page 0, Register 19 - synchronize */
> +#define TAS5754M_RQSY        (1 << 0)
> +#define TAS5754M_RQSY_RESUME (0 << 0)
> +#define TAS5754M_RQSY_HALT   (1 << 0)
> +
> +/* Page 0, Register 34 - fs speed mode */
> +#define TAS5754M_FSSP        (3 << 0)
> +#define TAS5754M_FSSP_SHIFT  0
> +#define TAS5754M_FSSP_48KHZ  (0 << 0)
> +#define TAS5754M_FSSP_96KHZ  (1 << 0)
> +#define TAS5754M_FSSP_192KHZ (2 << 0)
> +#define TAS5754M_FSSP_384KHZ (3 << 0)
> +
> +/* Page 0, Register 37 - Error detection */
> +#define TAS5754M_IPLK (1 << 0)
> +#define TAS5754M_DCAS (1 << 1)
> +#define TAS5754M_IDCM (1 << 2)
> +#define TAS5754M_IDCH (1 << 3)
> +#define TAS5754M_IDSK (1 << 4)
> +#define TAS5754M_IDBK (1 << 5)
> +#define TAS5754M_IDFS (1 << 6)
> +
> +/* Page 0, Register 40 - I2S configuration */
> +#define TAS5754M_ALEN       (3 << 0)
> +#define TAS5754M_ALEN_SHIFT 0
> +#define TAS5754M_ALEN_16    (0 << 0)
> +#define TAS5754M_ALEN_20    (1 << 0)
> +#define TAS5754M_ALEN_24    (2 << 0)
> +#define TAS5754M_ALEN_32    (3 << 0)
> +#define TAS5754M_AFMT       (3 << 4)
> +#define TAS5754M_AFMT_SHIFT 4
> +#define TAS5754M_AFMT_I2S   (0 << 4)
> +#define TAS5754M_AFMT_DSP   (1 << 4)
> +#define TAS5754M_AFMT_RTJ   (2 << 4)
> +#define TAS5754M_AFMT_LTJ   (3 << 4)
> +
> +/* Page 0, Register 42 - DAC routing */
> +#define TAS5754M_AUPR_SHIFT 0
> +#define TAS5754M_AUPL_SHIFT 4
> +
> +/* Page 0, Register 59 - auto mute */
> +#define TAS5754M_ATMR_SHIFT 0
> +#define TAS5754M_ATML_SHIFT 4
> +
> +/* Page 0, Register 63 - ramp rates */
> +#define TAS5754M_VNDF_SHIFT 6
> +#define TAS5754M_VNDS_SHIFT 4
> +#define TAS5754M_VNUF_SHIFT 2
> +#define TAS5754M_VNUS_SHIFT 0
> +
> +/* Page 0, Register 64 - emergency ramp rates */
> +#define TAS5754M_VEDF_SHIFT 6
> +#define TAS5754M_VEDS_SHIFT 4
> +
> +/* Page 0, Register 65 - Digital mute enables */
> +#define TAS5754M_ACTL_SHIFT 2
> +#define TAS5754M_AMLE_SHIFT 1
> +#define TAS5754M_AMRE_SHIFT 0
> +
> +/* Page 0, Register 80-85, GPIO output selection */
> +#define TAS5754M_GxSL       (31 << 0)
> +#define TAS5754M_GxSL_SHIFT 0
> +#define TAS5754M_GxSL_OFF   (0 << 0)
> +#define TAS5754M_GxSL_DSP   (1 << 0)
> +#define TAS5754M_GxSL_REG   (2 << 0)
> +#define TAS5754M_GxSL_AMUTB (3 << 0)
> +#define TAS5754M_GxSL_AMUTL (4 << 0)
> +#define TAS5754M_GxSL_AMUTR (5 << 0)
> +#define TAS5754M_GxSL_CLKI  (6 << 0)
> +#define TAS5754M_GxSL_SDOUT (7 << 0)
> +#define TAS5754M_GxSL_ANMUL (8 << 0)
> +#define TAS5754M_GxSL_ANMUR (9 << 0)
> +#define TAS5754M_GxSL_PLLLK (10 << 0)
> +#define TAS5754M_GxSL_CPCLK (11 << 0)
> +#define TAS5754M_GxSL_UV0_7 (14 << 0)
> +#define TAS5754M_GxSL_UV0_3 (15 << 0)
> +#define TAS5754M_GxSL_PLLCK (16 << 0)
> +
> +/* Page 1, Register 2 - analog volume control */
> +#define TAS5754M_RAGN_SHIFT 0
> +#define TAS5754M_LAGN_SHIFT 4
> +
> +/* Page 1, Register 7 - analog boost control */
> +#define TAS5754M_AGBR_SHIFT 0
> +#define TAS5754M_AGBL_SHIFT 4
> +
> +#endif
> 
> base-commit: f6274b06e326d8471cdfb52595f989a90f5e888f
> -- 
> 2.17.1
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2] sound/soc: adds TAS5754M digital input amplifier component driver
@ 2021-11-17 15:13     ` Mark Brown
  0 siblings, 0 replies; 21+ messages in thread
From: Mark Brown @ 2021-11-17 15:13 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 14590 bytes --]

On Fri, Oct 29, 2021 at 11:57:30AM +0200, Joerg Schambacher wrote:

> Adds a minimum component driver to run the amplifier in I2S master
> mode only from standard audio clocks. Therefore, it only allows
> 44.1, 88.2, 176.4, 48, 96 and 192ksps with 16, 20, 24 and 32 bits
> sample size. Digital volume control and the -6dB switch are supported.

This looks pretty clean, there's a bunch of minor stylistic bits below
but other than one major thing this looks good.  The major thing is the
use of a had coded init sequence to configure the device rather than
implemenenting the relevant APIs to do so, that's going to make the
driver unsuitable for use on boards other than the specific one you
happen to be looking at at the minute.

Please submit patches using subject lines reflecting the style for the
subsystem, this makes it easier for people to identify relevant patches.
Look at what existing commits in the area you're changing are doing and
make sure your subject lines visually resemble what they're doing.

> @@ -0,0 +1,547 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Driver for the TAS5754M Audio Amplifier in Master mode (only)
> + * supports only standard audio frequencies 44.1 to 192 ksps

Please make the entire comment a C++ one so things look more
intentional.

> +EXPORT_SYMBOL_GPL(tas5754m_regmap);

There's only one file in the driver, why is this exported?

> +	mclk = clk_get_rate(tas5754m->sclk);
> +	bclk = sample_len * 2 * params_rate(params);

snd_soc_params_to_bclk().

> +	// set SCLK divider
> +	ret |= regmap_write(tas5754m->regmap, TAS5754M_MASTER_CLKDIV_1,
> +								bclk_div - 1);
> +
> +	// set LRCLK divider
> +	ret |= regmap_write(tas5754m->regmap, TAS5754M_MASTER_CLKDIV_2,
> +								lrclk_div - 1);

Check the return statuses individually or just don't bother, if you or
them together then you could end up with a nonsensical error code which
could cause confusion down the line.

> +	if (mute) {
> +		snd_soc_component_write(component, TAS5754M_MUTE, 0x11);
> +	} else {
> +		usleep_range(1000, 2000);
> +		snd_soc_component_write(component, TAS5754M_MUTE, 0x00);

Why the sleep here?

> +	ret = regmap_multi_reg_write(regmap, tas5754m_init_sequence,
> +					ARRAY_SIZE(tas5754m_init_sequence));

This init sequence looks an awful lot like it's doing board specific
configuration - it's enabling the PLL, configuring GPIOs and clock
dividers among other things.  These should all be done through board
specific configuration or based on the currently configured audio path,
what's suitable for one board may not be suitable for another board.
Doing a reset of the chip is good but the rest of it really looks like
it doesn't belong.

> +	ret = snd_soc_register_component(dev,
> +			&tas5754m_soc_component, &tas5754m_dai, 1);

devm_snd_soc_register_component()

> +static const struct i2c_device_id tas5754m_i2c_id[] = {
> +	{ "tas5754m", },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(i2c, tas5754m_i2c_id);
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id tas5754m_of_match[] = {
> +	{ .compatible = "ti,tas5754m", },
> +	{ .compatible = "ti,tas5756m", },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, tas5754m_of_match);
> +#endif

Why not list both I2C IDs as well?

> @@ -0,0 +1,259 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Driver for the TAS5754M DAC+amplifier combo devices
> + *
> + * Author:	(copied from pcm512x.h)
> + *		Mark Brown <broonie@kernel.org>
> + *		Copyright 2014 Linaro Ltd
> + */

If the register map can be copied can't the two drivers be combined?

> +#define TAS5754M_VIRT_BASE 0x000
> +#define TAS5754M_PAGE_LEN  0x80
> +#define TAS5754M_PAGE_BASE(n)  (TAS5754M_VIRT_BASE + (TAS5754M_PAGE_LEN * n))
> +
> +#define TAS5754M_PAGE              0

There's no mention of paging in the regmap description for the driver
which feels like it's asking for problems.

> +
> +#define TAS5754M_RESET             (TAS5754M_PAGE_BASE(0) +   1)
> +#define TAS5754M_POWER             (TAS5754M_PAGE_BASE(0) +   2)
> +#define TAS5754M_MUTE              (TAS5754M_PAGE_BASE(0) +   3)
> +#define TAS5754M_PLL_EN            (TAS5754M_PAGE_BASE(0) +   4)
> +#define TAS5754M_SPI_MISO_FUNCTION (TAS5754M_PAGE_BASE(0) +   6)
> +#define TAS5754M_DSP               (TAS5754M_PAGE_BASE(0) +   7)
> +#define TAS5754M_GPIO_EN           (TAS5754M_PAGE_BASE(0) +   8)
> +#define TAS5754M_BCLK_LRCLK_CFG    (TAS5754M_PAGE_BASE(0) +   9)
> +#define TAS5754M_DSP_GPIO_INPUT    (TAS5754M_PAGE_BASE(0) +  10)
> +#define TAS5754M_MASTER_MODE       (TAS5754M_PAGE_BASE(0) +  12)
> +#define TAS5754M_PLL_REF           (TAS5754M_PAGE_BASE(0) +  13)
> +#define TAS5754M_DAC_REF           (TAS5754M_PAGE_BASE(0) +  14)
> +#define TAS5754M_GPIO_DACIN        (TAS5754M_PAGE_BASE(0) +  16)
> +#define TAS5754M_GPIO_PLLIN        (TAS5754M_PAGE_BASE(0) +  18)
> +#define TAS5754M_SYNCHRONIZE       (TAS5754M_PAGE_BASE(0) +  19)
> +#define TAS5754M_PLL_COEFF_0       (TAS5754M_PAGE_BASE(0) +  20)
> +#define TAS5754M_PLL_COEFF_1       (TAS5754M_PAGE_BASE(0) +  21)
> +#define TAS5754M_PLL_COEFF_2       (TAS5754M_PAGE_BASE(0) +  22)
> +#define TAS5754M_PLL_COEFF_3       (TAS5754M_PAGE_BASE(0) +  23)
> +#define TAS5754M_PLL_COEFF_4       (TAS5754M_PAGE_BASE(0) +  24)
> +#define TAS5754M_DSP_CLKDIV        (TAS5754M_PAGE_BASE(0) +  27)
> +#define TAS5754M_DAC_CLKDIV        (TAS5754M_PAGE_BASE(0) +  28)
> +#define TAS5754M_NCP_CLKDIV        (TAS5754M_PAGE_BASE(0) +  29)
> +#define TAS5754M_OSR_CLKDIV        (TAS5754M_PAGE_BASE(0) +  30)
> +#define TAS5754M_MASTER_CLKDIV_1   (TAS5754M_PAGE_BASE(0) +  32)
> +#define TAS5754M_MASTER_CLKDIV_2   (TAS5754M_PAGE_BASE(0) +  33)
> +#define TAS5754M_FS_SPEED_MODE     (TAS5754M_PAGE_BASE(0) +  34)
> +#define TAS5754M_IDAC_1            (TAS5754M_PAGE_BASE(0) +  35)
> +#define TAS5754M_IDAC_2            (TAS5754M_PAGE_BASE(0) +  36)
> +#define TAS5754M_ERROR_DETECT      (TAS5754M_PAGE_BASE(0) +  37)
> +#define TAS5754M_I2S_1             (TAS5754M_PAGE_BASE(0) +  40)
> +#define TAS5754M_I2S_2             (TAS5754M_PAGE_BASE(0) +  41)
> +#define TAS5754M_DAC_ROUTING       (TAS5754M_PAGE_BASE(0) +  42)
> +#define TAS5754M_DSP_PROGRAM       (TAS5754M_PAGE_BASE(0) +  43)
> +#define TAS5754M_CLKDET            (TAS5754M_PAGE_BASE(0) +  44)
> +#define TAS5754M_AUTO_MUTE         (TAS5754M_PAGE_BASE(0) +  59)
> +#define TAS5754M_DIGITAL_VOLUME_1  (TAS5754M_PAGE_BASE(0) +  60)
> +#define TAS5754M_DIGITAL_VOLUME_2  (TAS5754M_PAGE_BASE(0) +  61)
> +#define TAS5754M_DIGITAL_VOLUME_3  (TAS5754M_PAGE_BASE(0) +  62)
> +#define TAS5754M_DIGITAL_MUTE_1    (TAS5754M_PAGE_BASE(0) +  63)
> +#define TAS5754M_DIGITAL_MUTE_2    (TAS5754M_PAGE_BASE(0) +  64)
> +#define TAS5754M_DIGITAL_MUTE_3    (TAS5754M_PAGE_BASE(0) +  65)
> +#define TAS5754M_GPIO_OUTPUT_1     (TAS5754M_PAGE_BASE(0) +  80)
> +#define TAS5754M_GPIO_OUTPUT_2     (TAS5754M_PAGE_BASE(0) +  81)
> +#define TAS5754M_GPIO_OUTPUT_3     (TAS5754M_PAGE_BASE(0) +  82)
> +#define TAS5754M_GPIO_OUTPUT_4     (TAS5754M_PAGE_BASE(0) +  83)
> +#define TAS5754M_GPIO_OUTPUT_5     (TAS5754M_PAGE_BASE(0) +  84)
> +#define TAS5754M_GPIO_OUTPUT_6     (TAS5754M_PAGE_BASE(0) +  85)
> +#define TAS5754M_GPIO_CONTROL_1    (TAS5754M_PAGE_BASE(0) +  86)
> +#define TAS5754M_GPIO_CONTROL_2    (TAS5754M_PAGE_BASE(0) +  87)
> +#define TAS5754M_OVERFLOW          (TAS5754M_PAGE_BASE(0) +  90)
> +#define TAS5754M_RATE_DET_1        (TAS5754M_PAGE_BASE(0) +  91)
> +#define TAS5754M_RATE_DET_2        (TAS5754M_PAGE_BASE(0) +  92)
> +#define TAS5754M_RATE_DET_3        (TAS5754M_PAGE_BASE(0) +  93)
> +#define TAS5754M_RATE_DET_4        (TAS5754M_PAGE_BASE(0) +  94)
> +#define TAS5754M_CLOCK_STATUS      (TAS5754M_PAGE_BASE(0) +  95)
> +#define TAS5754M_ANALOG_MUTE_DET   (TAS5754M_PAGE_BASE(0) + 108)
> +#define TAS5754M_GPIN              (TAS5754M_PAGE_BASE(0) + 119)
> +#define TAS5754M_DIGITAL_MUTE_DET  (TAS5754M_PAGE_BASE(0) + 120)
> +
> +#define TAS5754M_OUTPUT_AMPLITUDE  (TAS5754M_PAGE_BASE(1) +   1)
> +#define TAS5754M_ANALOG_GAIN_CTRL  (TAS5754M_PAGE_BASE(1) +   2)
> +#define TAS5754M_UNDERVOLTAGE_PROT (TAS5754M_PAGE_BASE(1) +   5)
> +#define TAS5754M_ANALOG_MUTE_CTRL  (TAS5754M_PAGE_BASE(1) +   6)
> +#define TAS5754M_ANALOG_GAIN_BOOST (TAS5754M_PAGE_BASE(1) +   7)
> +#define TAS5754M_VCOM_CTRL_1       (TAS5754M_PAGE_BASE(1) +   8)
> +#define TAS5754M_VCOM_CTRL_2       (TAS5754M_PAGE_BASE(1) +   9)
> +
> +#define TAS5754M_CRAM_CTRL         (TAS5754M_PAGE_BASE(44) +  1)
> +
> +#define TAS5754M_FLEX_A            (TAS5754M_PAGE_BASE(253) + 63)
> +#define TAS5754M_FLEX_B            (TAS5754M_PAGE_BASE(253) + 64)
> +
> +#define TAS5754M_MAX_REGISTER      (TAS5754M_PAGE_BASE(253) + 64)
> +
> +/* Page 0, Register 1 - reset */
> +#define TAS5754M_RSTR (1 << 0)
> +#define TAS5754M_RSTM (1 << 4)
> +
> +/* Page 0, Register 2 - power */
> +#define TAS5754M_RQPD       (1 << 0)
> +#define TAS5754M_RQPD_SHIFT 0
> +#define TAS5754M_RQST       (1 << 4)
> +#define TAS5754M_RQST_SHIFT 4
> +
> +/* Page 0, Register 3 - mute */
> +#define TAS5754M_RQMR (1 << 0)
> +#define TAS5754M_RQMR_SHIFT 0
> +#define TAS5754M_RQML (1 << 4)
> +#define TAS5754M_RQML_SHIFT 4
> +
> +/* Page 0, Register 4 - PLL */
> +#define TAS5754M_PLLE       (1 << 0)
> +#define TAS5754M_PLLE_SHIFT 0
> +#define TAS5754M_PLCK       (1 << 4)
> +#define TAS5754M_PLCK_SHIFT 4
> +
> +/* Page 0, Register 7 - DSP */
> +#define TAS5754M_SDSL       (1 << 0)
> +#define TAS5754M_SDSL_SHIFT 0
> +#define TAS5754M_DEMP       (1 << 4)
> +#define TAS5754M_DEMP_SHIFT 4
> +
> +/* Page 0, Register 8 - GPIO output enable */
> +#define TAS5754M_G1OE       (1 << 0)
> +#define TAS5754M_G2OE       (1 << 1)
> +#define TAS5754M_G3OE       (1 << 2)
> +#define TAS5754M_G4OE       (1 << 3)
> +#define TAS5754M_G5OE       (1 << 4)
> +#define TAS5754M_G6OE       (1 << 5)
> +
> +/* Page 0, Register 9 - BCK, LRCLK configuration */
> +#define TAS5754M_LRKO       (1 << 0)
> +#define TAS5754M_LRKO_SHIFT 0
> +#define TAS5754M_BCKO       (1 << 4)
> +#define TAS5754M_BCKO_SHIFT 4
> +#define TAS5754M_BCKP       (1 << 5)
> +#define TAS5754M_BCKP_SHIFT 5
> +
> +/* Page 0, Register 12 - Master mode BCK, LRCLK reset */
> +#define TAS5754M_RLRK       (1 << 0)
> +#define TAS5754M_RLRK_SHIFT 0
> +#define TAS5754M_RBCK       (1 << 1)
> +#define TAS5754M_RBCK_SHIFT 1
> +
> +/* Page 0, Register 13 - PLL reference */
> +#define TAS5754M_SREF        (7 << 4)
> +#define TAS5754M_SREF_SHIFT  4
> +#define TAS5754M_SREF_SCK    (0 << 4)
> +#define TAS5754M_SREF_BCK    (1 << 4)
> +#define TAS5754M_SREF_GPIO   (3 << 4)
> +
> +/* Page 0, Register 14 - DAC reference */
> +#define TAS5754M_SDAC        (7 << 4)
> +#define TAS5754M_SDAC_SHIFT  4
> +#define TAS5754M_SDAC_MCK    (0 << 4)
> +#define TAS5754M_SDAC_PLL    (1 << 4)
> +#define TAS5754M_SDAC_SCK    (3 << 4)
> +#define TAS5754M_SDAC_BCK    (4 << 4)
> +#define TAS5754M_SDAC_GPIO   (5 << 4)
> +
> +/* Page 0, Register 16, 18 - GPIO source for DAC, PLL */
> +#define TAS5754M_GREF        (7 << 0)
> +#define TAS5754M_GREF_SHIFT  0
> +#define TAS5754M_GREF_GPIO1  (0 << 0)
> +#define TAS5754M_GREF_GPIO2  (1 << 0)
> +#define TAS5754M_GREF_GPIO3  (2 << 0)
> +#define TAS5754M_GREF_GPIO4  (3 << 0)
> +#define TAS5754M_GREF_GPIO5  (4 << 0)
> +#define TAS5754M_GREF_GPIO6  (5 << 0)
> +
> +/* Page 0, Register 19 - synchronize */
> +#define TAS5754M_RQSY        (1 << 0)
> +#define TAS5754M_RQSY_RESUME (0 << 0)
> +#define TAS5754M_RQSY_HALT   (1 << 0)
> +
> +/* Page 0, Register 34 - fs speed mode */
> +#define TAS5754M_FSSP        (3 << 0)
> +#define TAS5754M_FSSP_SHIFT  0
> +#define TAS5754M_FSSP_48KHZ  (0 << 0)
> +#define TAS5754M_FSSP_96KHZ  (1 << 0)
> +#define TAS5754M_FSSP_192KHZ (2 << 0)
> +#define TAS5754M_FSSP_384KHZ (3 << 0)
> +
> +/* Page 0, Register 37 - Error detection */
> +#define TAS5754M_IPLK (1 << 0)
> +#define TAS5754M_DCAS (1 << 1)
> +#define TAS5754M_IDCM (1 << 2)
> +#define TAS5754M_IDCH (1 << 3)
> +#define TAS5754M_IDSK (1 << 4)
> +#define TAS5754M_IDBK (1 << 5)
> +#define TAS5754M_IDFS (1 << 6)
> +
> +/* Page 0, Register 40 - I2S configuration */
> +#define TAS5754M_ALEN       (3 << 0)
> +#define TAS5754M_ALEN_SHIFT 0
> +#define TAS5754M_ALEN_16    (0 << 0)
> +#define TAS5754M_ALEN_20    (1 << 0)
> +#define TAS5754M_ALEN_24    (2 << 0)
> +#define TAS5754M_ALEN_32    (3 << 0)
> +#define TAS5754M_AFMT       (3 << 4)
> +#define TAS5754M_AFMT_SHIFT 4
> +#define TAS5754M_AFMT_I2S   (0 << 4)
> +#define TAS5754M_AFMT_DSP   (1 << 4)
> +#define TAS5754M_AFMT_RTJ   (2 << 4)
> +#define TAS5754M_AFMT_LTJ   (3 << 4)
> +
> +/* Page 0, Register 42 - DAC routing */
> +#define TAS5754M_AUPR_SHIFT 0
> +#define TAS5754M_AUPL_SHIFT 4
> +
> +/* Page 0, Register 59 - auto mute */
> +#define TAS5754M_ATMR_SHIFT 0
> +#define TAS5754M_ATML_SHIFT 4
> +
> +/* Page 0, Register 63 - ramp rates */
> +#define TAS5754M_VNDF_SHIFT 6
> +#define TAS5754M_VNDS_SHIFT 4
> +#define TAS5754M_VNUF_SHIFT 2
> +#define TAS5754M_VNUS_SHIFT 0
> +
> +/* Page 0, Register 64 - emergency ramp rates */
> +#define TAS5754M_VEDF_SHIFT 6
> +#define TAS5754M_VEDS_SHIFT 4
> +
> +/* Page 0, Register 65 - Digital mute enables */
> +#define TAS5754M_ACTL_SHIFT 2
> +#define TAS5754M_AMLE_SHIFT 1
> +#define TAS5754M_AMRE_SHIFT 0
> +
> +/* Page 0, Register 80-85, GPIO output selection */
> +#define TAS5754M_GxSL       (31 << 0)
> +#define TAS5754M_GxSL_SHIFT 0
> +#define TAS5754M_GxSL_OFF   (0 << 0)
> +#define TAS5754M_GxSL_DSP   (1 << 0)
> +#define TAS5754M_GxSL_REG   (2 << 0)
> +#define TAS5754M_GxSL_AMUTB (3 << 0)
> +#define TAS5754M_GxSL_AMUTL (4 << 0)
> +#define TAS5754M_GxSL_AMUTR (5 << 0)
> +#define TAS5754M_GxSL_CLKI  (6 << 0)
> +#define TAS5754M_GxSL_SDOUT (7 << 0)
> +#define TAS5754M_GxSL_ANMUL (8 << 0)
> +#define TAS5754M_GxSL_ANMUR (9 << 0)
> +#define TAS5754M_GxSL_PLLLK (10 << 0)
> +#define TAS5754M_GxSL_CPCLK (11 << 0)
> +#define TAS5754M_GxSL_UV0_7 (14 << 0)
> +#define TAS5754M_GxSL_UV0_3 (15 << 0)
> +#define TAS5754M_GxSL_PLLCK (16 << 0)
> +
> +/* Page 1, Register 2 - analog volume control */
> +#define TAS5754M_RAGN_SHIFT 0
> +#define TAS5754M_LAGN_SHIFT 4
> +
> +/* Page 1, Register 7 - analog boost control */
> +#define TAS5754M_AGBR_SHIFT 0
> +#define TAS5754M_AGBL_SHIFT 4
> +
> +#endif
> 
> base-commit: f6274b06e326d8471cdfb52595f989a90f5e888f
> -- 
> 2.17.1
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v3] ASoC: adds component driver for TAS575xM digital amplifiers
       [not found] <20211029095414.29131-1-joerg@hifiberry.com>
@ 2022-01-10  8:45   ` Joerg Schambacher
  2022-01-10  8:45   ` Joerg Schambacher
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 21+ messages in thread
From: Joerg Schambacher @ 2022-01-10  8:45 UTC (permalink / raw)
  To: alsa-devel; +Cc: joerg, broonie, kbuild-all

Adds a minimum component driver to run the amplifier in I2S master
mode only from standard audio clocks. Therefore, it only allows
44.1, 88.2, 176.4, 48, 96 and 192ksps with 16, 20, 24 and 32 bits
sample size. Digital volume control and the -6dB and +0.8dB switches
are supported.

Signed-off-by: Joerg Schambacher <joerg@hifiberry.com>
---
 sound/soc/codecs/Kconfig    |   8 +
 sound/soc/codecs/Makefile   |   2 +
 sound/soc/codecs/tas5754m.c | 700 ++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/tas5754m.h | 260 ++++++++++++++
 4 files changed, 970 insertions(+)
 create mode 100644 sound/soc/codecs/tas5754m.c
 create mode 100644 sound/soc/codecs/tas5754m.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 82ee233a269d..cf0584948fcf 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -210,6 +210,7 @@ config SND_SOC_ALL_CODECS
 	imply SND_SOC_TAS5086
 	imply SND_SOC_TAS571X
 	imply SND_SOC_TAS5720
+	imply SND_SOC_TAS5754M
 	imply SND_SOC_TAS6424
 	imply SND_SOC_TDA7419
 	imply SND_SOC_TFA9879
@@ -1419,6 +1420,13 @@ config SND_SOC_TAS5720
 	  Enable support for Texas Instruments TAS5720L/M high-efficiency mono
 	  Class-D audio power amplifiers.
 
+config SND_SOC_TAS5754M
+	tristate "Texas Instruments TAS5754M Digital Input Audio amplifier"
+	depends on I2C
+	help
+	  Enable support for Texas Instruments TAS5754M digital input
+	  Class-D audio power amplifiers.
+
 config SND_SOC_TAS6424
 	tristate "Texas Instruments TAS6424 Quad-Channel Audio amplifier"
 	depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 8dcea2c4604a..39984900258a 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -227,6 +227,7 @@ snd-soc-sti-sas-objs := sti-sas.o
 snd-soc-tas5086-objs := tas5086.o
 snd-soc-tas571x-objs := tas571x.o
 snd-soc-tas5720-objs := tas5720.o
+snd-soc-tas5754m-objs := tas5754m.o
 snd-soc-tas6424-objs := tas6424.o
 snd-soc-tda7419-objs := tda7419.o
 snd-soc-tas2770-objs := tas2770.o
@@ -555,6 +556,7 @@ obj-$(CONFIG_SND_SOC_TAS2764)	+= snd-soc-tas2764.o
 obj-$(CONFIG_SND_SOC_TAS5086)	+= snd-soc-tas5086.o
 obj-$(CONFIG_SND_SOC_TAS571X)	+= snd-soc-tas571x.o
 obj-$(CONFIG_SND_SOC_TAS5720)	+= snd-soc-tas5720.o
+obj-$(CONFIG_SND_SOC_TAS5754M)	+= snd-soc-tas5754m.o
 obj-$(CONFIG_SND_SOC_TAS6424)	+= snd-soc-tas6424.o
 obj-$(CONFIG_SND_SOC_TDA7419)	+= snd-soc-tda7419.o
 obj-$(CONFIG_SND_SOC_TAS2770) += snd-soc-tas2770.o
diff --git a/sound/soc/codecs/tas5754m.c b/sound/soc/codecs/tas5754m.c
new file mode 100644
index 000000000000..7aab9d29c46d
--- /dev/null
+++ b/sound/soc/codecs/tas5754m.c
@@ -0,0 +1,700 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for the TAS5754M Audio Amplifier
+ *
+ * Author: Joerg Schambacher <joerg@hifiberry.com>
+ *         with fragments from Andy Liu <andy-liu@ti.com>
+ *
+ * The driver supports I2S master mode only with standard audio
+ * frequencies 44.1 to 192 ksps from a 24.576/22.2592MHz master
+ * clock input
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+
+#include "tas5754m.h"
+
+#define TAS5754M_RATES		(SNDRV_PCM_RATE_48000  | \
+				 SNDRV_PCM_RATE_96000  | \
+				 SNDRV_PCM_RATE_192000 | \
+				 SNDRV_PCM_RATE_44100  | \
+				 SNDRV_PCM_RATE_88200  | \
+				 SNDRV_PCM_RATE_176400)
+#define TAS5754M_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE  | \
+				 SNDRV_PCM_FMTBIT_S20_LE  | \
+				 SNDRV_PCM_FMTBIT_S24_LE  | \
+				 SNDRV_PCM_FMTBIT_S32_LE)
+
+
+static const struct reg_default tas5754m_reg_defaults[] = {
+	{ TAS5754M_RESET,             0x00 },
+	{ TAS5754M_POWER,             0x00 },
+	{ TAS5754M_MUTE,              0x00 },
+	{ TAS5754M_DSP,               0x00 },
+	{ TAS5754M_PLL_REF,           0x00 },
+	{ TAS5754M_DAC_REF,           0x00 },
+	{ TAS5754M_DAC_ROUTING,       0x11 },
+	{ TAS5754M_DSP_PROGRAM,       0x01 },
+	{ TAS5754M_CLKDET,            0x00 },
+	{ TAS5754M_AUTO_MUTE,         0x00 },
+	{ TAS5754M_ERROR_DETECT,      0x00 },
+	{ TAS5754M_DIGITAL_VOLUME_1,  0x00 },
+	{ TAS5754M_DIGITAL_VOLUME_2,  0x30 },
+	{ TAS5754M_DIGITAL_VOLUME_3,  0x30 },
+	{ TAS5754M_DIGITAL_MUTE_1,    0x22 },
+	{ TAS5754M_DIGITAL_MUTE_2,    0x00 },
+	{ TAS5754M_DIGITAL_MUTE_3,    0x07 },
+	{ TAS5754M_OUTPUT_AMPLITUDE,  0x00 },
+	{ TAS5754M_ANALOG_GAIN_CTRL,  0x00 },
+	{ TAS5754M_UNDERVOLTAGE_PROT, 0x00 },
+	{ TAS5754M_ANALOG_MUTE_CTRL,  0x00 },
+	{ TAS5754M_ANALOG_GAIN_BOOST, 0x00 },
+	{ TAS5754M_VCOM_CTRL_1,       0x00 },
+	{ TAS5754M_VCOM_CTRL_2,       0x01 },
+	{ TAS5754M_BCLK_LRCLK_CFG,    0x00 },
+	{ TAS5754M_MASTER_MODE,       0x7c },
+	{ TAS5754M_GPIO_PLLIN,        0x00 },
+	{ TAS5754M_SYNCHRONIZE,       0x10 },
+	{ TAS5754M_PLL_COEFF_P,       0x00 },
+	{ TAS5754M_PLL_COEFF_J,       0x00 },
+	{ TAS5754M_PLL_COEFF_DH,      0x00 },
+	{ TAS5754M_PLL_COEFF_DL,      0x00 },
+	{ TAS5754M_PLL_COEFF_R,       0x00 },
+	{ TAS5754M_DSP_CLKDIV,        0x00 },
+	{ TAS5754M_DAC_CLKDIV,        0x00 },
+	{ TAS5754M_NCP_CLKDIV,        0x00 },
+	{ TAS5754M_OSR_CLKDIV,        0x00 },
+	{ TAS5754M_MASTER_SCLKDIV,    0x00 },
+	{ TAS5754M_MASTER_LRCLKDIV,   0x00 },
+	{ TAS5754M_FS_SPEED_MODE,     0x00 },
+	{ TAS5754M_IDAC_1,            0x01 },
+	{ TAS5754M_IDAC_2,            0x00 },
+};
+
+static bool tas5754m_readable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TAS5754M_RESET:
+	case TAS5754M_POWER:
+	case TAS5754M_MUTE:
+	case TAS5754M_PLL_EN:
+	case TAS5754M_DSP:
+	case TAS5754M_GPIO_EN:
+	case TAS5754M_BCLK_LRCLK_CFG:
+	case TAS5754M_DSP_GPIO_INPUT:
+	case TAS5754M_MASTER_MODE:
+	case TAS5754M_PLL_REF:
+	case TAS5754M_DAC_REF:
+	case TAS5754M_GPIO_PLLIN:
+	case TAS5754M_SYNCHRONIZE:
+	case TAS5754M_PLL_COEFF_P:
+	case TAS5754M_PLL_COEFF_J:
+	case TAS5754M_PLL_COEFF_DH:
+	case TAS5754M_PLL_COEFF_DL:
+	case TAS5754M_PLL_COEFF_R:
+	case TAS5754M_DSP_CLKDIV:
+	case TAS5754M_DAC_CLKDIV:
+	case TAS5754M_NCP_CLKDIV:
+	case TAS5754M_OSR_CLKDIV:
+	case TAS5754M_MASTER_SCLKDIV:
+	case TAS5754M_MASTER_LRCLKDIV:
+	case TAS5754M_FS_SPEED_MODE:
+	case TAS5754M_IDAC_1:
+	case TAS5754M_IDAC_2:
+	case TAS5754M_ERROR_DETECT:
+	case TAS5754M_I2S_1:
+	case TAS5754M_I2S_2:
+	case TAS5754M_DAC_ROUTING:
+	case TAS5754M_DSP_PROGRAM:
+	case TAS5754M_CLKDET:
+	case TAS5754M_AUTO_MUTE:
+	case TAS5754M_DIGITAL_VOLUME_1:
+	case TAS5754M_DIGITAL_VOLUME_2:
+	case TAS5754M_DIGITAL_VOLUME_3:
+	case TAS5754M_DIGITAL_MUTE_1:
+	case TAS5754M_DIGITAL_MUTE_2:
+	case TAS5754M_DIGITAL_MUTE_3:
+	case TAS5754M_GPIO_OUTPUT_0:
+	case TAS5754M_GPIO_OUTPUT_1:
+	case TAS5754M_GPIO_OUTPUT_2:
+	case TAS5754M_GPIO_CONTROL_1:
+	case TAS5754M_GPIO_CONTROL_2:
+	case TAS5754M_OVERFLOW:
+	case TAS5754M_RATE_DET_1:
+	case TAS5754M_RATE_DET_2:
+	case TAS5754M_RATE_DET_3:
+	case TAS5754M_RATE_DET_4:
+	case TAS5754M_CLOCK_STATUS:
+	case TAS5754M_ANALOG_MUTE_DET:
+	case TAS5754M_GPIN:
+	case TAS5754M_DIGITAL_MUTE_DET:
+	case TAS5754M_OUTPUT_AMPLITUDE:
+	case TAS5754M_ANALOG_GAIN_CTRL:
+	case TAS5754M_UNDERVOLTAGE_PROT:
+	case TAS5754M_ANALOG_MUTE_CTRL:
+	case TAS5754M_ANALOG_GAIN_BOOST:
+	case TAS5754M_VCOM_CTRL_1:
+	case TAS5754M_VCOM_CTRL_2:
+	case TAS5754M_CRAM_CTRL:
+	case TAS5754M_FLEX_A:
+	case TAS5754M_FLEX_B:
+		return true;
+	default:
+		return reg < 0x7f;
+	}
+}
+
+static bool tas5754m_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TAS5754M_PLL_EN:
+	case TAS5754M_OVERFLOW:
+	case TAS5754M_RATE_DET_1:
+	case TAS5754M_RATE_DET_2:
+	case TAS5754M_RATE_DET_3:
+	case TAS5754M_RATE_DET_4:
+	case TAS5754M_CLOCK_STATUS:
+	case TAS5754M_ANALOG_MUTE_DET:
+	case TAS5754M_GPIN:
+	case TAS5754M_DIGITAL_MUTE_DET:
+	case TAS5754M_CRAM_CTRL:
+		return true;
+	default:
+		return reg < 0x7f;
+	}
+}
+
+struct tas5754m_priv {
+	struct regmap *regmap;
+	struct clk *sclk;
+	int sample_len;
+	int fmt;
+	int mode;
+};
+
+static const struct regmap_range_cfg tas5754m_range = {
+	.name = "Pages",
+	.range_min = TAS5754M_VIRT_BASE,
+	.range_max = TAS5754M_MAX_REGISTER,
+	.selector_reg = TAS5754M_PAGE,
+	.selector_mask = 0x7f,
+	.window_start = 0,
+	.window_len = 128,
+};
+
+const struct regmap_config tas5754m_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.ranges = &tas5754m_range,
+	.num_ranges = 1,
+	.max_register = TAS5754M_MAX_REGISTER,
+
+	.reg_defaults = tas5754m_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(tas5754m_reg_defaults),
+	.readable_reg = tas5754m_readable,
+	.volatile_reg = tas5754m_volatile,
+
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1);
+static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0);
+
+static const struct snd_kcontrol_new tas5754m_controls[] = {
+SOC_DOUBLE_R_TLV("Digital Playback Volume", TAS5754M_DIGITAL_VOLUME_2,
+		 TAS5754M_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv),
+SOC_DOUBLE_TLV("Analog Playback Volume", TAS5754M_ANALOG_GAIN_CTRL,
+	     TAS5754M_LAGN_SHIFT, TAS5754M_RAGN_SHIFT, 1, 1, analog_tlv),
+SOC_DOUBLE_TLV("Analogue Playback Boost Volume", TAS5754M_ANALOG_GAIN_BOOST,
+	       TAS5754M_AGBL_SHIFT, TAS5754M_AGBR_SHIFT, 1, 0, boost_tlv),
+};
+
+static int tas5754m_set_bias_level(struct snd_soc_component *component,
+					enum snd_soc_bias_level level)
+{
+	struct tas5754m_priv *tas5754m =
+				snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		ret = regmap_update_bits(tas5754m->regmap,
+				TAS5754M_POWER, TAS5754M_RQST, 0);
+		if (ret != 0) {
+			dev_err(component->dev,
+				"Failed to remove standby: %d\n", ret);
+			return ret;
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		ret = regmap_update_bits(tas5754m->regmap,
+				TAS5754M_POWER, TAS5754M_RQST, TAS5754M_RQST);
+		if (ret != 0) {
+			dev_err(component->dev,
+				"Failed to request standby: %d\n", ret);
+			return ret;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+int tas5754m_set_clock_tree_master(struct snd_soc_dai *dai,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+	static const struct reg_sequence pll_settings[] = {
+		{ TAS5754M_PLL_COEFF_P,		0x01 },	// P=2
+		{ TAS5754M_PLL_COEFF_J,		0x08 },	// J=8
+		{ TAS5754M_PLL_COEFF_DL,	0x00 },	// D12-8 = 0
+		{ TAS5754M_PLL_COEFF_DH,	0x00 },	// D7-0 = 0
+		{ TAS5754M_PLL_COEFF_R,		0x00 },	// R=1
+	};
+	int ret;
+
+	/* disable PLL before any clock tree change */
+	ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
+				 TAS5754M_PLLE, 0);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to disable PLL: %d\n", ret);
+		return ret;
+	}
+
+	/* set DAC clock source to MCLK */
+	ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_REF, 0x30);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to set DAC ref\n");
+		return ret;
+	}
+
+	/* run PLL at fixed ratio to MCLK */
+	ret = regmap_multi_reg_write(tas5754m->regmap, pll_settings,
+					ARRAY_SIZE(pll_settings));
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to set PLL ratio\n");
+		return ret;
+	}
+
+	/* set DSP divider to 2 => reg 0x01 */
+	ret = regmap_write(tas5754m->regmap, TAS5754M_DSP_CLKDIV, 1);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to set DSP divider\n");
+		return ret;
+	}
+	/* set DAC divider to 4 => reg 0x03*/
+	ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_CLKDIV, 3);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to set OSDACR divider\n");
+		return ret;
+	}
+	/* set OSR divider to 1 */
+	ret = regmap_write(tas5754m->regmap, TAS5754M_OSR_CLKDIV, 0);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to set OSR divider\n");
+		return ret;
+	}
+	/* set CP divider to 4 => reg 0x03*/
+	ret = regmap_write(tas5754m->regmap, TAS5754M_NCP_CLKDIV, 3);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to set CP divider\n");
+		return ret;
+	}
+	/* finally enable PLL */
+	ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
+				 TAS5754M_PLLE, 1);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to enable PLL: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+int tas5754m_set_dai_mode(struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+	int fmt = tas5754m->fmt;
+
+	/* only I2S MASTER mode implemented */
+	if (((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S)) {
+		dev_err(component->dev,
+			"DAI format not supported (I2S master only)\n");
+		return -EINVAL;
+	}
+	/* TAS5754/6m do not support inverted clocks in MASTER mode */
+	if (((fmt & SND_SOC_DAIFMT_CLOCK_MASK) != SND_SOC_DAIFMT_NB_NF)) {
+		dev_err(component->dev,	"Inverted clocks not supported\n");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		regmap_update_bits(tas5754m->regmap,
+				TAS5754M_BCLK_LRCLK_CFG,
+				TAS5754M_LRKO | TAS5754M_BCKO,
+				TAS5754M_LRKO | TAS5754M_BCKO);
+		/* reset CLK dividers */
+		regmap_update_bits(tas5754m->regmap,
+				TAS5754M_MASTER_MODE,
+				0x00,
+				TAS5754M_RLRK | TAS5754M_RBCK);
+		/* ignore all clock error detection but MCLK */
+		regmap_update_bits(tas5754m->regmap,
+				TAS5754M_ERROR_DETECT,
+				TAS5754M_IPLK | TAS5754M_DCAS |
+				TAS5754M_IDCM | TAS5754M_IDSK |
+				TAS5754M_IDBK | TAS5754M_IDFS,
+				TAS5754M_IPLK | TAS5754M_DCAS |
+				TAS5754M_IDCM | TAS5754M_IDSK |
+				TAS5754M_IDBK | TAS5754M_IDFS);
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+	case SND_SOC_DAIFMT_CBM_CFS:
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int tas5754m_set_dividers_master(struct snd_soc_dai *dai,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+	unsigned long bclk;
+	unsigned long mclk;
+	int bclk_div;
+	int lrclk_div;
+	int osr;
+	int ret;
+
+	mclk = clk_get_rate(tas5754m->sclk);
+	bclk = tas5754m->sample_len * 2 * params_rate(params);
+	bclk_div = mclk / bclk;
+	lrclk_div = tas5754m->sample_len * 2;
+	osr = mclk / 4 / params_rate(params) / 16;
+
+	// stop LR / SCLK clocks
+	ret = regmap_update_bits(tas5754m->regmap,
+				TAS5754M_MASTER_MODE,
+				!TAS5754M_RLRK | !TAS5754M_RBCK,
+				TAS5754M_RLRK | TAS5754M_RBCK);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to stop PLL\n");
+		return ret;
+	}
+
+	// set SCLK divider
+	ret = regmap_write(tas5754m->regmap, TAS5754M_MASTER_SCLKDIV,
+								bclk_div - 1);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to set SCLK divider\n");
+		return ret;
+	}
+
+	// set LRCLK divider
+	ret = regmap_write(tas5754m->regmap, TAS5754M_MASTER_LRCLKDIV,
+								lrclk_div - 1);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to set LRCLK divider\n");
+		return ret;
+	}
+
+	ret = regmap_write(tas5754m->regmap,
+		TAS5754M_OSR_CLKDIV, osr - 1);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to set OSR divider\n");
+		return ret;
+	}
+
+	// restart LR / SCLK clocks
+	ret = regmap_update_bits(tas5754m->regmap,
+				TAS5754M_MASTER_MODE,
+				TAS5754M_RLRK | TAS5754M_RBCK,
+				TAS5754M_RLRK | TAS5754M_RBCK);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to restart PLL\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tas5754m_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+	int alen;
+	int ret;
+
+	switch (params_width(params)) {
+	case 16:
+		tas5754m->sample_len = 16;
+		alen = TAS5754M_ALEN_16;
+		break;
+	case 20:
+		tas5754m->sample_len = 32;
+		alen = TAS5754M_ALEN_20;
+		break;
+	case 24:
+		tas5754m->sample_len = 32;
+		alen = TAS5754M_ALEN_24;
+		break;
+	case 32:
+		tas5754m->sample_len = 32;
+		alen = TAS5754M_ALEN_32;
+		break;
+	default:
+		dev_err(component->dev, "Unsupported sample size: %d\n",
+			params_width(params));
+		return -EINVAL;
+	}
+	ret = regmap_update_bits(tas5754m->regmap, TAS5754M_I2S_1, alen, alen);
+	if (ret != 0) {
+		dev_err(component->dev,
+			"Cannot set sample size: %d\n", ret);
+		return ret;
+	}
+
+	ret = tas5754m_set_dai_mode(dai);
+	if (ret != 0) {
+		dev_err(component->dev,
+			"DAI mode not supported: %d\n", ret);
+		return ret;
+	}
+
+	ret = tas5754m_set_clock_tree_master(dai, params);
+	if (ret != 0)
+		return ret;
+
+	switch (params_rate(params)) {
+	case 44100:
+	case 48000:
+		ret = regmap_write(tas5754m->regmap,
+			TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_48KHZ);
+		break;
+	case 88200:
+	case 96000:
+		ret = regmap_write(tas5754m->regmap,
+			TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_96KHZ);
+		break;
+	case 176400:
+	case 192000:
+		ret = regmap_write(tas5754m->regmap,
+			TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_192KHZ);
+		break;
+	default:
+		dev_err(component->dev, "Sample rate not supported: %d\n",
+			params_rate(params));
+		return -EINVAL;
+	}
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to config PLL\n");
+		return ret;
+	}
+
+	ret = tas5754m_set_dividers_master(dai, params);
+	if (ret != 0)
+		return ret;
+
+	return 0;
+}
+
+static int tas5754m_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+
+	tas5754m->fmt = fmt;
+
+	return 0;
+}
+
+
+static const struct snd_soc_component_driver tas5754m_soc_component = {
+	.set_bias_level = tas5754m_set_bias_level,
+	.idle_bias_on = true,
+	.controls = tas5754m_controls,
+	.num_controls = ARRAY_SIZE(tas5754m_controls),
+};
+
+static int tas5754m_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+	struct snd_soc_component *component = dai->component;
+
+	if (mute) {
+		snd_soc_component_write(component, TAS5754M_MUTE, 0x11);
+	} else {
+		/* wait for stable operation before unmute */
+		usleep_range(1000, 2000);
+		snd_soc_component_write(component, TAS5754M_MUTE, 0x00);
+	}
+	return 0;
+}
+
+static const struct snd_soc_dai_ops tas5754m_dai_ops = {
+	.mute_stream = tas5754m_mute,
+	.hw_params = tas5754m_hw_params,
+	.set_fmt = tas5754m_set_fmt,
+};
+
+static struct snd_soc_dai_driver tas5754m_dai = {
+	.name		= "tas5754m-amplifier",
+	.playback	= {
+		.stream_name	= "Playback",
+		.channels_min	= 2,
+		.channels_max	= 2,
+		.rates		= TAS5754M_RATES,
+		.formats	= TAS5754M_FORMATS,
+	},
+	.ops = &tas5754m_dai_ops,
+};
+
+static int tas5754m_probe(struct device *dev, struct regmap *regmap)
+{
+	struct tas5754m_priv *tas5754m;
+	int ret;
+
+	tas5754m = devm_kzalloc(dev, sizeof(struct tas5754m_priv), GFP_KERNEL);
+	if (!tas5754m)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, tas5754m);
+	tas5754m->regmap = regmap;
+
+	regmap_write(regmap, TAS5754M_RESET, TAS5754M_RSTR | TAS5754M_RSTM);
+
+	if (ret != 0) {
+		dev_err(dev, "Failed to initialize TAS5754M: %d\n", ret);
+		goto err;
+	}
+
+	tas5754m->sclk = devm_clk_get(dev, NULL);
+	if (PTR_ERR(tas5754m->sclk) == -EPROBE_DEFER) {
+		ret = -EPROBE_DEFER;
+		goto err;
+	}
+	if (!IS_ERR(tas5754m->sclk)) {
+		ret = clk_prepare_enable(tas5754m->sclk);
+		if (ret != 0) {
+			dev_err(dev, "Failed to enable SCLK: %d\n", ret);
+			goto err;
+		}
+	}
+
+	ret = devm_snd_soc_register_component(dev,
+			&tas5754m_soc_component, &tas5754m_dai, 1);
+	if (ret != 0) {
+		dev_err(dev, "Failed to register CODEC: %d\n", ret);
+		goto err;
+	}
+
+	return 0;
+
+err:
+	return ret;
+
+}
+
+static int tas5754m_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+{
+	struct regmap *regmap;
+	struct regmap_config config = tas5754m_regmap;
+
+	/* enable auto-increment mode */
+	config.read_flag_mask = 0x80;
+	config.write_flag_mask = 0x80;
+
+	regmap = devm_regmap_init_i2c(i2c, &config);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return tas5754m_probe(&i2c->dev, regmap);
+}
+
+static int tas5754m_remove(struct device *dev)
+{
+	snd_soc_unregister_component(dev);
+
+	return 0;
+}
+
+static int tas5754m_i2c_remove(struct i2c_client *i2c)
+{
+	tas5754m_remove(&i2c->dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id tas5754m_i2c_id[] = {
+	{ "tas5754m", },
+	{ "tas5756m", },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tas5754m_i2c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id tas5754m_of_match[] = {
+	{ .compatible = "ti,tas5754m", },
+	{ .compatible = "ti,tas5756m", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, tas5754m_of_match);
+#endif
+
+static struct i2c_driver tas5754m_i2c_driver = {
+	.probe		= tas5754m_i2c_probe,
+	.remove		= tas5754m_i2c_remove,
+	.id_table	= tas5754m_i2c_id,
+	.driver		= {
+		.name	= "tas5754m",
+		.of_match_table = of_match_ptr(tas5754m_of_match),
+	},
+};
+
+module_i2c_driver(tas5754m_i2c_driver);
+
+MODULE_AUTHOR("Joerg Schambacher <joerg@hifiberry.com>");
+MODULE_DESCRIPTION("TAS5754M Audio Amplifier Driver - Master mode only");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas5754m.h b/sound/soc/codecs/tas5754m.h
new file mode 100644
index 000000000000..c6e26dba169f
--- /dev/null
+++ b/sound/soc/codecs/tas5754m.h
@@ -0,0 +1,260 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Driver for the TAS575xM DAC+amplifier combo devices
+ *
+ * Author:	(copied from pcm512x.h)
+ *		Mark Brown <broonie@kernel.org>
+ *		Copyright 2014 Linaro Ltd
+ *
+ *		Register names adapted and non available
+ *		register definitions removed according
+ +		to TAS5754M specification
+ *		Joerg Schambacher <joerg@hifiberry.com>
+ */
+
+#ifndef _SND_SOC_TAS5754M
+#define _SND_SOC_TAS5754M
+
+#include <linux/pm.h>
+#include <linux/regmap.h>
+
+#define TAS5754M_VIRT_BASE 0x000
+#define TAS5754M_PAGE_LEN  0x80
+#define TAS5754M_PAGE_BASE(n)  (TAS5754M_VIRT_BASE + (TAS5754M_PAGE_LEN * n))
+
+#define TAS5754M_PAGE              0
+
+#define TAS5754M_RESET             (TAS5754M_PAGE_BASE(0) +   1)
+#define TAS5754M_POWER             (TAS5754M_PAGE_BASE(0) +   2)
+#define TAS5754M_MUTE              (TAS5754M_PAGE_BASE(0) +   3)
+#define TAS5754M_PLL_EN            (TAS5754M_PAGE_BASE(0) +   4)
+#define TAS5754M_DSP               (TAS5754M_PAGE_BASE(0) +   7)
+#define TAS5754M_GPIO_EN           (TAS5754M_PAGE_BASE(0) +   8)
+#define TAS5754M_BCLK_LRCLK_CFG    (TAS5754M_PAGE_BASE(0) +   9)
+#define TAS5754M_DSP_GPIO_INPUT    (TAS5754M_PAGE_BASE(0) +  10)
+#define TAS5754M_MASTER_MODE       (TAS5754M_PAGE_BASE(0) +  12)
+#define TAS5754M_PLL_REF           (TAS5754M_PAGE_BASE(0) +  13)
+#define TAS5754M_DAC_REF           (TAS5754M_PAGE_BASE(0) +  14)
+#define TAS5754M_GPIO_PLLIN        (TAS5754M_PAGE_BASE(0) +  18)
+#define TAS5754M_SYNCHRONIZE       (TAS5754M_PAGE_BASE(0) +  19)
+#define TAS5754M_PLL_COEFF_P       (TAS5754M_PAGE_BASE(0) +  20)
+#define TAS5754M_PLL_COEFF_J       (TAS5754M_PAGE_BASE(0) +  21)
+#define TAS5754M_PLL_COEFF_DH      (TAS5754M_PAGE_BASE(0) +  22)
+#define TAS5754M_PLL_COEFF_DL      (TAS5754M_PAGE_BASE(0) +  23)
+#define TAS5754M_PLL_COEFF_R       (TAS5754M_PAGE_BASE(0) +  24)
+#define TAS5754M_DSP_CLKDIV        (TAS5754M_PAGE_BASE(0) +  27)
+#define TAS5754M_DAC_CLKDIV        (TAS5754M_PAGE_BASE(0) +  28)
+#define TAS5754M_NCP_CLKDIV        (TAS5754M_PAGE_BASE(0) +  29)
+#define TAS5754M_OSR_CLKDIV        (TAS5754M_PAGE_BASE(0) +  30)
+#define TAS5754M_MASTER_SCLKDIV    (TAS5754M_PAGE_BASE(0) +  32)
+#define TAS5754M_MASTER_LRCLKDIV   (TAS5754M_PAGE_BASE(0) +  33)
+#define TAS5754M_FS_SPEED_MODE     (TAS5754M_PAGE_BASE(0) +  34)
+#define TAS5754M_IDAC_1            (TAS5754M_PAGE_BASE(0) +  35)
+#define TAS5754M_IDAC_2            (TAS5754M_PAGE_BASE(0) +  36)
+#define TAS5754M_ERROR_DETECT      (TAS5754M_PAGE_BASE(0) +  37)
+#define TAS5754M_I2S_1             (TAS5754M_PAGE_BASE(0) +  40)
+#define TAS5754M_I2S_2             (TAS5754M_PAGE_BASE(0) +  41)
+#define TAS5754M_DAC_ROUTING       (TAS5754M_PAGE_BASE(0) +  42)
+#define TAS5754M_DSP_PROGRAM       (TAS5754M_PAGE_BASE(0) +  43)
+#define TAS5754M_CLKDET            (TAS5754M_PAGE_BASE(0) +  44)
+#define TAS5754M_AUTO_MUTE         (TAS5754M_PAGE_BASE(0) +  59)
+#define TAS5754M_DIGITAL_VOLUME_1  (TAS5754M_PAGE_BASE(0) +  60)
+#define TAS5754M_DIGITAL_VOLUME_2  (TAS5754M_PAGE_BASE(0) +  61)
+#define TAS5754M_DIGITAL_VOLUME_3  (TAS5754M_PAGE_BASE(0) +  62)
+#define TAS5754M_DIGITAL_MUTE_1    (TAS5754M_PAGE_BASE(0) +  63)
+#define TAS5754M_DIGITAL_MUTE_2    (TAS5754M_PAGE_BASE(0) +  64)
+#define TAS5754M_DIGITAL_MUTE_3    (TAS5754M_PAGE_BASE(0) +  65)
+#define TAS5754M_GPIO_OUTPUT_1     (TAS5754M_PAGE_BASE(0) +  82)
+#define TAS5754M_GPIO_OUTPUT_0     (TAS5754M_PAGE_BASE(0) +  83)
+#define TAS5754M_GPIO_OUTPUT_2     (TAS5754M_PAGE_BASE(0) +  85)
+#define TAS5754M_GPIO_CONTROL_1    (TAS5754M_PAGE_BASE(0) +  86)
+#define TAS5754M_GPIO_CONTROL_2    (TAS5754M_PAGE_BASE(0) +  87)
+#define TAS5754M_OVERFLOW          (TAS5754M_PAGE_BASE(0) +  90)
+#define TAS5754M_RATE_DET_1        (TAS5754M_PAGE_BASE(0) +  91)
+#define TAS5754M_RATE_DET_2        (TAS5754M_PAGE_BASE(0) +  92)
+#define TAS5754M_RATE_DET_3        (TAS5754M_PAGE_BASE(0) +  93)
+#define TAS5754M_RATE_DET_4        (TAS5754M_PAGE_BASE(0) +  94)
+#define TAS5754M_CLOCK_STATUS      (TAS5754M_PAGE_BASE(0) +  95)
+#define TAS5754M_ANALOG_MUTE_DET   (TAS5754M_PAGE_BASE(0) + 108)
+#define TAS5754M_FS_MODE_MON       (TAS5754M_PAGE_BASE(0) + 115)
+#define TAS5754M_GPIN              (TAS5754M_PAGE_BASE(0) + 119)
+#define TAS5754M_DIGITAL_MUTE_DET  (TAS5754M_PAGE_BASE(0) + 120)
+
+#define TAS5754M_OUTPUT_AMPLITUDE  (TAS5754M_PAGE_BASE(1) +   1)
+#define TAS5754M_ANALOG_GAIN_CTRL  (TAS5754M_PAGE_BASE(1) +   2)
+#define TAS5754M_UNDERVOLTAGE_PROT (TAS5754M_PAGE_BASE(1) +   5)
+#define TAS5754M_ANALOG_MUTE_CTRL  (TAS5754M_PAGE_BASE(1) +   6)
+#define TAS5754M_ANALOG_GAIN_BOOST (TAS5754M_PAGE_BASE(1) +   7)
+#define TAS5754M_VCOM_CTRL_1       (TAS5754M_PAGE_BASE(1) +   8)
+#define TAS5754M_VCOM_CTRL_2       (TAS5754M_PAGE_BASE(1) +   9)
+
+#define TAS5754M_CRAM_CTRL         (TAS5754M_PAGE_BASE(44) +  1)
+
+#define TAS5754M_FLEX_A            (TAS5754M_PAGE_BASE(253) + 63)
+#define TAS5754M_FLEX_B            (TAS5754M_PAGE_BASE(253) + 64)
+
+#define TAS5754M_MAX_REGISTER      (TAS5754M_PAGE_BASE(253) + 64)
+
+/* Page 0, Register 1 - reset */
+#define TAS5754M_RSTR (1 << 0)
+#define TAS5754M_RSTM (1 << 4)
+
+/* Page 0, Register 2 - power */
+#define TAS5754M_RQPD       (1 << 0)
+#define TAS5754M_RQPD_SHIFT 0
+#define TAS5754M_RQST       (1 << 4)
+#define TAS5754M_RQST_SHIFT 4
+
+/* Page 0, Register 3 - mute */
+#define TAS5754M_RQMR (1 << 0)
+#define TAS5754M_RQMR_SHIFT 0
+#define TAS5754M_RQML (1 << 4)
+#define TAS5754M_RQML_SHIFT 4
+
+/* Page 0, Register 4 - PLL */
+#define TAS5754M_PLLE       (1 << 0)
+#define TAS5754M_PLLE_SHIFT 0
+#define TAS5754M_PLCK       (1 << 4)
+#define TAS5754M_PLCK_SHIFT 4
+
+/* Page 0, Register 7 - DSP */
+#define TAS5754M_SDSL       (1 << 0)
+#define TAS5754M_SDSL_SHIFT 0
+#define TAS5754M_DEMP       (1 << 4)
+#define TAS5754M_DEMP_SHIFT 4
+
+/* Page 0, Register 8 - GPIO output enable */
+#define TAS5754M_G1OE       (1 << 0)
+#define TAS5754M_G2OE       (1 << 1)
+#define TAS5754M_G3OE       (1 << 2)
+#define TAS5754M_G4OE       (1 << 3)
+#define TAS5754M_G5OE       (1 << 4)
+#define TAS5754M_G6OE       (1 << 5)
+
+/* Page 0, Register 9 - BCK, LRCLK configuration */
+#define TAS5754M_LRKO       (1 << 0)
+#define TAS5754M_LRKO_SHIFT 0
+#define TAS5754M_BCKO       (1 << 4)
+#define TAS5754M_BCKO_SHIFT 4
+#define TAS5754M_BCKP       (1 << 5)
+#define TAS5754M_BCKP_SHIFT 5
+
+/* Page 0, Register 12 - Master mode BCK, LRCLK reset */
+#define TAS5754M_RLRK       (1 << 0)
+#define TAS5754M_RLRK_SHIFT 0
+#define TAS5754M_RBCK       (1 << 1)
+#define TAS5754M_RBCK_SHIFT 1
+
+/* Page 0, Register 13 - PLL reference */
+#define TAS5754M_SREF        (7 << 4)
+#define TAS5754M_SREF_SHIFT  4
+#define TAS5754M_SREF_SCK    (0 << 4)
+#define TAS5754M_SREF_BCK    (1 << 4)
+#define TAS5754M_SREF_GPIO   (3 << 4)
+
+/* Page 0, Register 14 - DAC reference */
+#define TAS5754M_SDAC        (7 << 4)
+#define TAS5754M_SDAC_SHIFT  4
+#define TAS5754M_SDAC_MCK    (0 << 4)
+#define TAS5754M_SDAC_PLL    (1 << 4)
+#define TAS5754M_SDAC_SCK    (3 << 4)
+#define TAS5754M_SDAC_BCK    (4 << 4)
+#define TAS5754M_SDAC_GPIO   (5 << 4)
+
+/* Page 0, Register 16, 18 - GPIO source for DAC, PLL */
+#define TAS5754M_GREF        (7 << 0)
+#define TAS5754M_GREF_SHIFT  0
+#define TAS5754M_GREF_GPIO1  (0 << 0)
+#define TAS5754M_GREF_GPIO2  (1 << 0)
+#define TAS5754M_GREF_GPIO3  (2 << 0)
+#define TAS5754M_GREF_GPIO4  (3 << 0)
+#define TAS5754M_GREF_GPIO5  (4 << 0)
+#define TAS5754M_GREF_GPIO6  (5 << 0)
+
+/* Page 0, Register 19 - synchronize */
+#define TAS5754M_RQSY        (1 << 0)
+#define TAS5754M_RQSY_RESUME (0 << 0)
+#define TAS5754M_RQSY_HALT   (1 << 0)
+
+/* Page 0, Register 34 - fs speed mode */
+#define TAS5754M_FSSP        (3 << 0)
+#define TAS5754M_FSSP_SHIFT  0
+#define TAS5754M_FSSP_48KHZ  (0 << 0)
+#define TAS5754M_FSSP_96KHZ  (1 << 0)
+#define TAS5754M_FSSP_192KHZ (2 << 0)
+#define TAS5754M_FSSP_384KHZ (3 << 0)
+
+/* Page 0, Register 37 - Error detection */
+#define TAS5754M_IPLK (1 << 0)
+#define TAS5754M_DCAS (1 << 1)
+#define TAS5754M_IDCM (1 << 2)
+#define TAS5754M_IDCH (1 << 3)
+#define TAS5754M_IDSK (1 << 4)
+#define TAS5754M_IDBK (1 << 5)
+#define TAS5754M_IDFS (1 << 6)
+
+/* Page 0, Register 40 - I2S configuration */
+#define TAS5754M_ALEN       (3 << 0)
+#define TAS5754M_ALEN_SHIFT 0
+#define TAS5754M_ALEN_16    (0 << 0)
+#define TAS5754M_ALEN_20    (1 << 0)
+#define TAS5754M_ALEN_24    (2 << 0)
+#define TAS5754M_ALEN_32    (3 << 0)
+#define TAS5754M_AFMT       (3 << 4)
+#define TAS5754M_AFMT_SHIFT 4
+#define TAS5754M_AFMT_I2S   (0 << 4)
+#define TAS5754M_AFMT_DSP   (1 << 4)
+#define TAS5754M_AFMT_RTJ   (2 << 4)
+#define TAS5754M_AFMT_LTJ   (3 << 4)
+
+/* Page 0, Register 42 - DAC routing */
+#define TAS5754M_AUPR_SHIFT 0
+#define TAS5754M_AUPL_SHIFT 4
+
+/* Page 0, Register 59 - auto mute */
+#define TAS5754M_ATMR_SHIFT 0
+#define TAS5754M_ATML_SHIFT 4
+
+/* Page 0, Register 63 - ramp rates */
+#define TAS5754M_VNDF_SHIFT 6
+#define TAS5754M_VNDS_SHIFT 4
+#define TAS5754M_VNUF_SHIFT 2
+#define TAS5754M_VNUS_SHIFT 0
+
+/* Page 0, Register 64 - emergency ramp rates */
+#define TAS5754M_VEDF_SHIFT 6
+#define TAS5754M_VEDS_SHIFT 4
+
+/* Page 0, Register 65 - Digital mute enables */
+#define TAS5754M_ACTL_SHIFT 2
+#define TAS5754M_AMLE_SHIFT 1
+#define TAS5754M_AMRE_SHIFT 0
+
+/* Page 0, Register 80-85, GPIO output selection */
+#define TAS5754M_GxSL       (31 << 0)
+#define TAS5754M_GxSL_SHIFT 0
+#define TAS5754M_GxSL_OFF   (0 << 0)
+#define TAS5754M_GxSL_DSP   (1 << 0)
+#define TAS5754M_GxSL_REG   (2 << 0)
+#define TAS5754M_GxSL_AMUTB (3 << 0)
+#define TAS5754M_GxSL_AMUTL (4 << 0)
+#define TAS5754M_GxSL_AMUTR (5 << 0)
+#define TAS5754M_GxSL_CLKI  (6 << 0)
+#define TAS5754M_GxSL_SDOUT (7 << 0)
+#define TAS5754M_GxSL_ANMUL (8 << 0)
+#define TAS5754M_GxSL_ANMUR (9 << 0)
+#define TAS5754M_GxSL_PLLLK (10 << 0)
+#define TAS5754M_GxSL_CPCLK (11 << 0)
+#define TAS5754M_GxSL_UV0_7 (14 << 0)
+#define TAS5754M_GxSL_UV0_3 (15 << 0)
+#define TAS5754M_GxSL_PLLCK (16 << 0)
+
+/* Page 1, Register 2 - analog volume control */
+#define TAS5754M_RAGN_SHIFT 0
+#define TAS5754M_LAGN_SHIFT 4
+
+/* Page 1, Register 7 - analog boost control */
+#define TAS5754M_AGBR_SHIFT 0
+#define TAS5754M_AGBL_SHIFT 4
+
+#endif
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v3] ASoC: adds component driver for TAS575xM digital amplifiers
@ 2022-01-10  8:45   ` Joerg Schambacher
  0 siblings, 0 replies; 21+ messages in thread
From: Joerg Schambacher @ 2022-01-10  8:45 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 33190 bytes --]

Adds a minimum component driver to run the amplifier in I2S master
mode only from standard audio clocks. Therefore, it only allows
44.1, 88.2, 176.4, 48, 96 and 192ksps with 16, 20, 24 and 32 bits
sample size. Digital volume control and the -6dB and +0.8dB switches
are supported.

Signed-off-by: Joerg Schambacher <joerg@hifiberry.com>
---
 sound/soc/codecs/Kconfig    |   8 +
 sound/soc/codecs/Makefile   |   2 +
 sound/soc/codecs/tas5754m.c | 700 ++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/tas5754m.h | 260 ++++++++++++++
 4 files changed, 970 insertions(+)
 create mode 100644 sound/soc/codecs/tas5754m.c
 create mode 100644 sound/soc/codecs/tas5754m.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 82ee233a269d..cf0584948fcf 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -210,6 +210,7 @@ config SND_SOC_ALL_CODECS
 	imply SND_SOC_TAS5086
 	imply SND_SOC_TAS571X
 	imply SND_SOC_TAS5720
+	imply SND_SOC_TAS5754M
 	imply SND_SOC_TAS6424
 	imply SND_SOC_TDA7419
 	imply SND_SOC_TFA9879
@@ -1419,6 +1420,13 @@ config SND_SOC_TAS5720
 	  Enable support for Texas Instruments TAS5720L/M high-efficiency mono
 	  Class-D audio power amplifiers.
 
+config SND_SOC_TAS5754M
+	tristate "Texas Instruments TAS5754M Digital Input Audio amplifier"
+	depends on I2C
+	help
+	  Enable support for Texas Instruments TAS5754M digital input
+	  Class-D audio power amplifiers.
+
 config SND_SOC_TAS6424
 	tristate "Texas Instruments TAS6424 Quad-Channel Audio amplifier"
 	depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 8dcea2c4604a..39984900258a 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -227,6 +227,7 @@ snd-soc-sti-sas-objs := sti-sas.o
 snd-soc-tas5086-objs := tas5086.o
 snd-soc-tas571x-objs := tas571x.o
 snd-soc-tas5720-objs := tas5720.o
+snd-soc-tas5754m-objs := tas5754m.o
 snd-soc-tas6424-objs := tas6424.o
 snd-soc-tda7419-objs := tda7419.o
 snd-soc-tas2770-objs := tas2770.o
@@ -555,6 +556,7 @@ obj-$(CONFIG_SND_SOC_TAS2764)	+= snd-soc-tas2764.o
 obj-$(CONFIG_SND_SOC_TAS5086)	+= snd-soc-tas5086.o
 obj-$(CONFIG_SND_SOC_TAS571X)	+= snd-soc-tas571x.o
 obj-$(CONFIG_SND_SOC_TAS5720)	+= snd-soc-tas5720.o
+obj-$(CONFIG_SND_SOC_TAS5754M)	+= snd-soc-tas5754m.o
 obj-$(CONFIG_SND_SOC_TAS6424)	+= snd-soc-tas6424.o
 obj-$(CONFIG_SND_SOC_TDA7419)	+= snd-soc-tda7419.o
 obj-$(CONFIG_SND_SOC_TAS2770) += snd-soc-tas2770.o
diff --git a/sound/soc/codecs/tas5754m.c b/sound/soc/codecs/tas5754m.c
new file mode 100644
index 000000000000..7aab9d29c46d
--- /dev/null
+++ b/sound/soc/codecs/tas5754m.c
@@ -0,0 +1,700 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for the TAS5754M Audio Amplifier
+ *
+ * Author: Joerg Schambacher <joerg@hifiberry.com>
+ *         with fragments from Andy Liu <andy-liu@ti.com>
+ *
+ * The driver supports I2S master mode only with standard audio
+ * frequencies 44.1 to 192 ksps from a 24.576/22.2592MHz master
+ * clock input
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+
+#include "tas5754m.h"
+
+#define TAS5754M_RATES		(SNDRV_PCM_RATE_48000  | \
+				 SNDRV_PCM_RATE_96000  | \
+				 SNDRV_PCM_RATE_192000 | \
+				 SNDRV_PCM_RATE_44100  | \
+				 SNDRV_PCM_RATE_88200  | \
+				 SNDRV_PCM_RATE_176400)
+#define TAS5754M_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE  | \
+				 SNDRV_PCM_FMTBIT_S20_LE  | \
+				 SNDRV_PCM_FMTBIT_S24_LE  | \
+				 SNDRV_PCM_FMTBIT_S32_LE)
+
+
+static const struct reg_default tas5754m_reg_defaults[] = {
+	{ TAS5754M_RESET,             0x00 },
+	{ TAS5754M_POWER,             0x00 },
+	{ TAS5754M_MUTE,              0x00 },
+	{ TAS5754M_DSP,               0x00 },
+	{ TAS5754M_PLL_REF,           0x00 },
+	{ TAS5754M_DAC_REF,           0x00 },
+	{ TAS5754M_DAC_ROUTING,       0x11 },
+	{ TAS5754M_DSP_PROGRAM,       0x01 },
+	{ TAS5754M_CLKDET,            0x00 },
+	{ TAS5754M_AUTO_MUTE,         0x00 },
+	{ TAS5754M_ERROR_DETECT,      0x00 },
+	{ TAS5754M_DIGITAL_VOLUME_1,  0x00 },
+	{ TAS5754M_DIGITAL_VOLUME_2,  0x30 },
+	{ TAS5754M_DIGITAL_VOLUME_3,  0x30 },
+	{ TAS5754M_DIGITAL_MUTE_1,    0x22 },
+	{ TAS5754M_DIGITAL_MUTE_2,    0x00 },
+	{ TAS5754M_DIGITAL_MUTE_3,    0x07 },
+	{ TAS5754M_OUTPUT_AMPLITUDE,  0x00 },
+	{ TAS5754M_ANALOG_GAIN_CTRL,  0x00 },
+	{ TAS5754M_UNDERVOLTAGE_PROT, 0x00 },
+	{ TAS5754M_ANALOG_MUTE_CTRL,  0x00 },
+	{ TAS5754M_ANALOG_GAIN_BOOST, 0x00 },
+	{ TAS5754M_VCOM_CTRL_1,       0x00 },
+	{ TAS5754M_VCOM_CTRL_2,       0x01 },
+	{ TAS5754M_BCLK_LRCLK_CFG,    0x00 },
+	{ TAS5754M_MASTER_MODE,       0x7c },
+	{ TAS5754M_GPIO_PLLIN,        0x00 },
+	{ TAS5754M_SYNCHRONIZE,       0x10 },
+	{ TAS5754M_PLL_COEFF_P,       0x00 },
+	{ TAS5754M_PLL_COEFF_J,       0x00 },
+	{ TAS5754M_PLL_COEFF_DH,      0x00 },
+	{ TAS5754M_PLL_COEFF_DL,      0x00 },
+	{ TAS5754M_PLL_COEFF_R,       0x00 },
+	{ TAS5754M_DSP_CLKDIV,        0x00 },
+	{ TAS5754M_DAC_CLKDIV,        0x00 },
+	{ TAS5754M_NCP_CLKDIV,        0x00 },
+	{ TAS5754M_OSR_CLKDIV,        0x00 },
+	{ TAS5754M_MASTER_SCLKDIV,    0x00 },
+	{ TAS5754M_MASTER_LRCLKDIV,   0x00 },
+	{ TAS5754M_FS_SPEED_MODE,     0x00 },
+	{ TAS5754M_IDAC_1,            0x01 },
+	{ TAS5754M_IDAC_2,            0x00 },
+};
+
+static bool tas5754m_readable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TAS5754M_RESET:
+	case TAS5754M_POWER:
+	case TAS5754M_MUTE:
+	case TAS5754M_PLL_EN:
+	case TAS5754M_DSP:
+	case TAS5754M_GPIO_EN:
+	case TAS5754M_BCLK_LRCLK_CFG:
+	case TAS5754M_DSP_GPIO_INPUT:
+	case TAS5754M_MASTER_MODE:
+	case TAS5754M_PLL_REF:
+	case TAS5754M_DAC_REF:
+	case TAS5754M_GPIO_PLLIN:
+	case TAS5754M_SYNCHRONIZE:
+	case TAS5754M_PLL_COEFF_P:
+	case TAS5754M_PLL_COEFF_J:
+	case TAS5754M_PLL_COEFF_DH:
+	case TAS5754M_PLL_COEFF_DL:
+	case TAS5754M_PLL_COEFF_R:
+	case TAS5754M_DSP_CLKDIV:
+	case TAS5754M_DAC_CLKDIV:
+	case TAS5754M_NCP_CLKDIV:
+	case TAS5754M_OSR_CLKDIV:
+	case TAS5754M_MASTER_SCLKDIV:
+	case TAS5754M_MASTER_LRCLKDIV:
+	case TAS5754M_FS_SPEED_MODE:
+	case TAS5754M_IDAC_1:
+	case TAS5754M_IDAC_2:
+	case TAS5754M_ERROR_DETECT:
+	case TAS5754M_I2S_1:
+	case TAS5754M_I2S_2:
+	case TAS5754M_DAC_ROUTING:
+	case TAS5754M_DSP_PROGRAM:
+	case TAS5754M_CLKDET:
+	case TAS5754M_AUTO_MUTE:
+	case TAS5754M_DIGITAL_VOLUME_1:
+	case TAS5754M_DIGITAL_VOLUME_2:
+	case TAS5754M_DIGITAL_VOLUME_3:
+	case TAS5754M_DIGITAL_MUTE_1:
+	case TAS5754M_DIGITAL_MUTE_2:
+	case TAS5754M_DIGITAL_MUTE_3:
+	case TAS5754M_GPIO_OUTPUT_0:
+	case TAS5754M_GPIO_OUTPUT_1:
+	case TAS5754M_GPIO_OUTPUT_2:
+	case TAS5754M_GPIO_CONTROL_1:
+	case TAS5754M_GPIO_CONTROL_2:
+	case TAS5754M_OVERFLOW:
+	case TAS5754M_RATE_DET_1:
+	case TAS5754M_RATE_DET_2:
+	case TAS5754M_RATE_DET_3:
+	case TAS5754M_RATE_DET_4:
+	case TAS5754M_CLOCK_STATUS:
+	case TAS5754M_ANALOG_MUTE_DET:
+	case TAS5754M_GPIN:
+	case TAS5754M_DIGITAL_MUTE_DET:
+	case TAS5754M_OUTPUT_AMPLITUDE:
+	case TAS5754M_ANALOG_GAIN_CTRL:
+	case TAS5754M_UNDERVOLTAGE_PROT:
+	case TAS5754M_ANALOG_MUTE_CTRL:
+	case TAS5754M_ANALOG_GAIN_BOOST:
+	case TAS5754M_VCOM_CTRL_1:
+	case TAS5754M_VCOM_CTRL_2:
+	case TAS5754M_CRAM_CTRL:
+	case TAS5754M_FLEX_A:
+	case TAS5754M_FLEX_B:
+		return true;
+	default:
+		return reg < 0x7f;
+	}
+}
+
+static bool tas5754m_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TAS5754M_PLL_EN:
+	case TAS5754M_OVERFLOW:
+	case TAS5754M_RATE_DET_1:
+	case TAS5754M_RATE_DET_2:
+	case TAS5754M_RATE_DET_3:
+	case TAS5754M_RATE_DET_4:
+	case TAS5754M_CLOCK_STATUS:
+	case TAS5754M_ANALOG_MUTE_DET:
+	case TAS5754M_GPIN:
+	case TAS5754M_DIGITAL_MUTE_DET:
+	case TAS5754M_CRAM_CTRL:
+		return true;
+	default:
+		return reg < 0x7f;
+	}
+}
+
+struct tas5754m_priv {
+	struct regmap *regmap;
+	struct clk *sclk;
+	int sample_len;
+	int fmt;
+	int mode;
+};
+
+static const struct regmap_range_cfg tas5754m_range = {
+	.name = "Pages",
+	.range_min = TAS5754M_VIRT_BASE,
+	.range_max = TAS5754M_MAX_REGISTER,
+	.selector_reg = TAS5754M_PAGE,
+	.selector_mask = 0x7f,
+	.window_start = 0,
+	.window_len = 128,
+};
+
+const struct regmap_config tas5754m_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.ranges = &tas5754m_range,
+	.num_ranges = 1,
+	.max_register = TAS5754M_MAX_REGISTER,
+
+	.reg_defaults = tas5754m_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(tas5754m_reg_defaults),
+	.readable_reg = tas5754m_readable,
+	.volatile_reg = tas5754m_volatile,
+
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1);
+static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0);
+
+static const struct snd_kcontrol_new tas5754m_controls[] = {
+SOC_DOUBLE_R_TLV("Digital Playback Volume", TAS5754M_DIGITAL_VOLUME_2,
+		 TAS5754M_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv),
+SOC_DOUBLE_TLV("Analog Playback Volume", TAS5754M_ANALOG_GAIN_CTRL,
+	     TAS5754M_LAGN_SHIFT, TAS5754M_RAGN_SHIFT, 1, 1, analog_tlv),
+SOC_DOUBLE_TLV("Analogue Playback Boost Volume", TAS5754M_ANALOG_GAIN_BOOST,
+	       TAS5754M_AGBL_SHIFT, TAS5754M_AGBR_SHIFT, 1, 0, boost_tlv),
+};
+
+static int tas5754m_set_bias_level(struct snd_soc_component *component,
+					enum snd_soc_bias_level level)
+{
+	struct tas5754m_priv *tas5754m =
+				snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		ret = regmap_update_bits(tas5754m->regmap,
+				TAS5754M_POWER, TAS5754M_RQST, 0);
+		if (ret != 0) {
+			dev_err(component->dev,
+				"Failed to remove standby: %d\n", ret);
+			return ret;
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		ret = regmap_update_bits(tas5754m->regmap,
+				TAS5754M_POWER, TAS5754M_RQST, TAS5754M_RQST);
+		if (ret != 0) {
+			dev_err(component->dev,
+				"Failed to request standby: %d\n", ret);
+			return ret;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+int tas5754m_set_clock_tree_master(struct snd_soc_dai *dai,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+	static const struct reg_sequence pll_settings[] = {
+		{ TAS5754M_PLL_COEFF_P,		0x01 },	// P=2
+		{ TAS5754M_PLL_COEFF_J,		0x08 },	// J=8
+		{ TAS5754M_PLL_COEFF_DL,	0x00 },	// D12-8 = 0
+		{ TAS5754M_PLL_COEFF_DH,	0x00 },	// D7-0 = 0
+		{ TAS5754M_PLL_COEFF_R,		0x00 },	// R=1
+	};
+	int ret;
+
+	/* disable PLL before any clock tree change */
+	ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
+				 TAS5754M_PLLE, 0);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to disable PLL: %d\n", ret);
+		return ret;
+	}
+
+	/* set DAC clock source to MCLK */
+	ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_REF, 0x30);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to set DAC ref\n");
+		return ret;
+	}
+
+	/* run PLL at fixed ratio to MCLK */
+	ret = regmap_multi_reg_write(tas5754m->regmap, pll_settings,
+					ARRAY_SIZE(pll_settings));
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to set PLL ratio\n");
+		return ret;
+	}
+
+	/* set DSP divider to 2 => reg 0x01 */
+	ret = regmap_write(tas5754m->regmap, TAS5754M_DSP_CLKDIV, 1);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to set DSP divider\n");
+		return ret;
+	}
+	/* set DAC divider to 4 => reg 0x03*/
+	ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_CLKDIV, 3);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to set OSDACR divider\n");
+		return ret;
+	}
+	/* set OSR divider to 1 */
+	ret = regmap_write(tas5754m->regmap, TAS5754M_OSR_CLKDIV, 0);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to set OSR divider\n");
+		return ret;
+	}
+	/* set CP divider to 4 => reg 0x03*/
+	ret = regmap_write(tas5754m->regmap, TAS5754M_NCP_CLKDIV, 3);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to set CP divider\n");
+		return ret;
+	}
+	/* finally enable PLL */
+	ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
+				 TAS5754M_PLLE, 1);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to enable PLL: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+int tas5754m_set_dai_mode(struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+	int fmt = tas5754m->fmt;
+
+	/* only I2S MASTER mode implemented */
+	if (((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S)) {
+		dev_err(component->dev,
+			"DAI format not supported (I2S master only)\n");
+		return -EINVAL;
+	}
+	/* TAS5754/6m do not support inverted clocks in MASTER mode */
+	if (((fmt & SND_SOC_DAIFMT_CLOCK_MASK) != SND_SOC_DAIFMT_NB_NF)) {
+		dev_err(component->dev,	"Inverted clocks not supported\n");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		regmap_update_bits(tas5754m->regmap,
+				TAS5754M_BCLK_LRCLK_CFG,
+				TAS5754M_LRKO | TAS5754M_BCKO,
+				TAS5754M_LRKO | TAS5754M_BCKO);
+		/* reset CLK dividers */
+		regmap_update_bits(tas5754m->regmap,
+				TAS5754M_MASTER_MODE,
+				0x00,
+				TAS5754M_RLRK | TAS5754M_RBCK);
+		/* ignore all clock error detection but MCLK */
+		regmap_update_bits(tas5754m->regmap,
+				TAS5754M_ERROR_DETECT,
+				TAS5754M_IPLK | TAS5754M_DCAS |
+				TAS5754M_IDCM | TAS5754M_IDSK |
+				TAS5754M_IDBK | TAS5754M_IDFS,
+				TAS5754M_IPLK | TAS5754M_DCAS |
+				TAS5754M_IDCM | TAS5754M_IDSK |
+				TAS5754M_IDBK | TAS5754M_IDFS);
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+	case SND_SOC_DAIFMT_CBM_CFS:
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int tas5754m_set_dividers_master(struct snd_soc_dai *dai,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+	unsigned long bclk;
+	unsigned long mclk;
+	int bclk_div;
+	int lrclk_div;
+	int osr;
+	int ret;
+
+	mclk = clk_get_rate(tas5754m->sclk);
+	bclk = tas5754m->sample_len * 2 * params_rate(params);
+	bclk_div = mclk / bclk;
+	lrclk_div = tas5754m->sample_len * 2;
+	osr = mclk / 4 / params_rate(params) / 16;
+
+	// stop LR / SCLK clocks
+	ret = regmap_update_bits(tas5754m->regmap,
+				TAS5754M_MASTER_MODE,
+				!TAS5754M_RLRK | !TAS5754M_RBCK,
+				TAS5754M_RLRK | TAS5754M_RBCK);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to stop PLL\n");
+		return ret;
+	}
+
+	// set SCLK divider
+	ret = regmap_write(tas5754m->regmap, TAS5754M_MASTER_SCLKDIV,
+								bclk_div - 1);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to set SCLK divider\n");
+		return ret;
+	}
+
+	// set LRCLK divider
+	ret = regmap_write(tas5754m->regmap, TAS5754M_MASTER_LRCLKDIV,
+								lrclk_div - 1);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to set LRCLK divider\n");
+		return ret;
+	}
+
+	ret = regmap_write(tas5754m->regmap,
+		TAS5754M_OSR_CLKDIV, osr - 1);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to set OSR divider\n");
+		return ret;
+	}
+
+	// restart LR / SCLK clocks
+	ret = regmap_update_bits(tas5754m->regmap,
+				TAS5754M_MASTER_MODE,
+				TAS5754M_RLRK | TAS5754M_RBCK,
+				TAS5754M_RLRK | TAS5754M_RBCK);
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to restart PLL\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tas5754m_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+	int alen;
+	int ret;
+
+	switch (params_width(params)) {
+	case 16:
+		tas5754m->sample_len = 16;
+		alen = TAS5754M_ALEN_16;
+		break;
+	case 20:
+		tas5754m->sample_len = 32;
+		alen = TAS5754M_ALEN_20;
+		break;
+	case 24:
+		tas5754m->sample_len = 32;
+		alen = TAS5754M_ALEN_24;
+		break;
+	case 32:
+		tas5754m->sample_len = 32;
+		alen = TAS5754M_ALEN_32;
+		break;
+	default:
+		dev_err(component->dev, "Unsupported sample size: %d\n",
+			params_width(params));
+		return -EINVAL;
+	}
+	ret = regmap_update_bits(tas5754m->regmap, TAS5754M_I2S_1, alen, alen);
+	if (ret != 0) {
+		dev_err(component->dev,
+			"Cannot set sample size: %d\n", ret);
+		return ret;
+	}
+
+	ret = tas5754m_set_dai_mode(dai);
+	if (ret != 0) {
+		dev_err(component->dev,
+			"DAI mode not supported: %d\n", ret);
+		return ret;
+	}
+
+	ret = tas5754m_set_clock_tree_master(dai, params);
+	if (ret != 0)
+		return ret;
+
+	switch (params_rate(params)) {
+	case 44100:
+	case 48000:
+		ret = regmap_write(tas5754m->regmap,
+			TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_48KHZ);
+		break;
+	case 88200:
+	case 96000:
+		ret = regmap_write(tas5754m->regmap,
+			TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_96KHZ);
+		break;
+	case 176400:
+	case 192000:
+		ret = regmap_write(tas5754m->regmap,
+			TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_192KHZ);
+		break;
+	default:
+		dev_err(component->dev, "Sample rate not supported: %d\n",
+			params_rate(params));
+		return -EINVAL;
+	}
+	if (ret != 0) {
+		dev_err(component->dev, "Failed to config PLL\n");
+		return ret;
+	}
+
+	ret = tas5754m_set_dividers_master(dai, params);
+	if (ret != 0)
+		return ret;
+
+	return 0;
+}
+
+static int tas5754m_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+
+	tas5754m->fmt = fmt;
+
+	return 0;
+}
+
+
+static const struct snd_soc_component_driver tas5754m_soc_component = {
+	.set_bias_level = tas5754m_set_bias_level,
+	.idle_bias_on = true,
+	.controls = tas5754m_controls,
+	.num_controls = ARRAY_SIZE(tas5754m_controls),
+};
+
+static int tas5754m_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+	struct snd_soc_component *component = dai->component;
+
+	if (mute) {
+		snd_soc_component_write(component, TAS5754M_MUTE, 0x11);
+	} else {
+		/* wait for stable operation before unmute */
+		usleep_range(1000, 2000);
+		snd_soc_component_write(component, TAS5754M_MUTE, 0x00);
+	}
+	return 0;
+}
+
+static const struct snd_soc_dai_ops tas5754m_dai_ops = {
+	.mute_stream = tas5754m_mute,
+	.hw_params = tas5754m_hw_params,
+	.set_fmt = tas5754m_set_fmt,
+};
+
+static struct snd_soc_dai_driver tas5754m_dai = {
+	.name		= "tas5754m-amplifier",
+	.playback	= {
+		.stream_name	= "Playback",
+		.channels_min	= 2,
+		.channels_max	= 2,
+		.rates		= TAS5754M_RATES,
+		.formats	= TAS5754M_FORMATS,
+	},
+	.ops = &tas5754m_dai_ops,
+};
+
+static int tas5754m_probe(struct device *dev, struct regmap *regmap)
+{
+	struct tas5754m_priv *tas5754m;
+	int ret;
+
+	tas5754m = devm_kzalloc(dev, sizeof(struct tas5754m_priv), GFP_KERNEL);
+	if (!tas5754m)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, tas5754m);
+	tas5754m->regmap = regmap;
+
+	regmap_write(regmap, TAS5754M_RESET, TAS5754M_RSTR | TAS5754M_RSTM);
+
+	if (ret != 0) {
+		dev_err(dev, "Failed to initialize TAS5754M: %d\n", ret);
+		goto err;
+	}
+
+	tas5754m->sclk = devm_clk_get(dev, NULL);
+	if (PTR_ERR(tas5754m->sclk) == -EPROBE_DEFER) {
+		ret = -EPROBE_DEFER;
+		goto err;
+	}
+	if (!IS_ERR(tas5754m->sclk)) {
+		ret = clk_prepare_enable(tas5754m->sclk);
+		if (ret != 0) {
+			dev_err(dev, "Failed to enable SCLK: %d\n", ret);
+			goto err;
+		}
+	}
+
+	ret = devm_snd_soc_register_component(dev,
+			&tas5754m_soc_component, &tas5754m_dai, 1);
+	if (ret != 0) {
+		dev_err(dev, "Failed to register CODEC: %d\n", ret);
+		goto err;
+	}
+
+	return 0;
+
+err:
+	return ret;
+
+}
+
+static int tas5754m_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+{
+	struct regmap *regmap;
+	struct regmap_config config = tas5754m_regmap;
+
+	/* enable auto-increment mode */
+	config.read_flag_mask = 0x80;
+	config.write_flag_mask = 0x80;
+
+	regmap = devm_regmap_init_i2c(i2c, &config);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return tas5754m_probe(&i2c->dev, regmap);
+}
+
+static int tas5754m_remove(struct device *dev)
+{
+	snd_soc_unregister_component(dev);
+
+	return 0;
+}
+
+static int tas5754m_i2c_remove(struct i2c_client *i2c)
+{
+	tas5754m_remove(&i2c->dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id tas5754m_i2c_id[] = {
+	{ "tas5754m", },
+	{ "tas5756m", },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tas5754m_i2c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id tas5754m_of_match[] = {
+	{ .compatible = "ti,tas5754m", },
+	{ .compatible = "ti,tas5756m", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, tas5754m_of_match);
+#endif
+
+static struct i2c_driver tas5754m_i2c_driver = {
+	.probe		= tas5754m_i2c_probe,
+	.remove		= tas5754m_i2c_remove,
+	.id_table	= tas5754m_i2c_id,
+	.driver		= {
+		.name	= "tas5754m",
+		.of_match_table = of_match_ptr(tas5754m_of_match),
+	},
+};
+
+module_i2c_driver(tas5754m_i2c_driver);
+
+MODULE_AUTHOR("Joerg Schambacher <joerg@hifiberry.com>");
+MODULE_DESCRIPTION("TAS5754M Audio Amplifier Driver - Master mode only");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas5754m.h b/sound/soc/codecs/tas5754m.h
new file mode 100644
index 000000000000..c6e26dba169f
--- /dev/null
+++ b/sound/soc/codecs/tas5754m.h
@@ -0,0 +1,260 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Driver for the TAS575xM DAC+amplifier combo devices
+ *
+ * Author:	(copied from pcm512x.h)
+ *		Mark Brown <broonie@kernel.org>
+ *		Copyright 2014 Linaro Ltd
+ *
+ *		Register names adapted and non available
+ *		register definitions removed according
+ +		to TAS5754M specification
+ *		Joerg Schambacher <joerg@hifiberry.com>
+ */
+
+#ifndef _SND_SOC_TAS5754M
+#define _SND_SOC_TAS5754M
+
+#include <linux/pm.h>
+#include <linux/regmap.h>
+
+#define TAS5754M_VIRT_BASE 0x000
+#define TAS5754M_PAGE_LEN  0x80
+#define TAS5754M_PAGE_BASE(n)  (TAS5754M_VIRT_BASE + (TAS5754M_PAGE_LEN * n))
+
+#define TAS5754M_PAGE              0
+
+#define TAS5754M_RESET             (TAS5754M_PAGE_BASE(0) +   1)
+#define TAS5754M_POWER             (TAS5754M_PAGE_BASE(0) +   2)
+#define TAS5754M_MUTE              (TAS5754M_PAGE_BASE(0) +   3)
+#define TAS5754M_PLL_EN            (TAS5754M_PAGE_BASE(0) +   4)
+#define TAS5754M_DSP               (TAS5754M_PAGE_BASE(0) +   7)
+#define TAS5754M_GPIO_EN           (TAS5754M_PAGE_BASE(0) +   8)
+#define TAS5754M_BCLK_LRCLK_CFG    (TAS5754M_PAGE_BASE(0) +   9)
+#define TAS5754M_DSP_GPIO_INPUT    (TAS5754M_PAGE_BASE(0) +  10)
+#define TAS5754M_MASTER_MODE       (TAS5754M_PAGE_BASE(0) +  12)
+#define TAS5754M_PLL_REF           (TAS5754M_PAGE_BASE(0) +  13)
+#define TAS5754M_DAC_REF           (TAS5754M_PAGE_BASE(0) +  14)
+#define TAS5754M_GPIO_PLLIN        (TAS5754M_PAGE_BASE(0) +  18)
+#define TAS5754M_SYNCHRONIZE       (TAS5754M_PAGE_BASE(0) +  19)
+#define TAS5754M_PLL_COEFF_P       (TAS5754M_PAGE_BASE(0) +  20)
+#define TAS5754M_PLL_COEFF_J       (TAS5754M_PAGE_BASE(0) +  21)
+#define TAS5754M_PLL_COEFF_DH      (TAS5754M_PAGE_BASE(0) +  22)
+#define TAS5754M_PLL_COEFF_DL      (TAS5754M_PAGE_BASE(0) +  23)
+#define TAS5754M_PLL_COEFF_R       (TAS5754M_PAGE_BASE(0) +  24)
+#define TAS5754M_DSP_CLKDIV        (TAS5754M_PAGE_BASE(0) +  27)
+#define TAS5754M_DAC_CLKDIV        (TAS5754M_PAGE_BASE(0) +  28)
+#define TAS5754M_NCP_CLKDIV        (TAS5754M_PAGE_BASE(0) +  29)
+#define TAS5754M_OSR_CLKDIV        (TAS5754M_PAGE_BASE(0) +  30)
+#define TAS5754M_MASTER_SCLKDIV    (TAS5754M_PAGE_BASE(0) +  32)
+#define TAS5754M_MASTER_LRCLKDIV   (TAS5754M_PAGE_BASE(0) +  33)
+#define TAS5754M_FS_SPEED_MODE     (TAS5754M_PAGE_BASE(0) +  34)
+#define TAS5754M_IDAC_1            (TAS5754M_PAGE_BASE(0) +  35)
+#define TAS5754M_IDAC_2            (TAS5754M_PAGE_BASE(0) +  36)
+#define TAS5754M_ERROR_DETECT      (TAS5754M_PAGE_BASE(0) +  37)
+#define TAS5754M_I2S_1             (TAS5754M_PAGE_BASE(0) +  40)
+#define TAS5754M_I2S_2             (TAS5754M_PAGE_BASE(0) +  41)
+#define TAS5754M_DAC_ROUTING       (TAS5754M_PAGE_BASE(0) +  42)
+#define TAS5754M_DSP_PROGRAM       (TAS5754M_PAGE_BASE(0) +  43)
+#define TAS5754M_CLKDET            (TAS5754M_PAGE_BASE(0) +  44)
+#define TAS5754M_AUTO_MUTE         (TAS5754M_PAGE_BASE(0) +  59)
+#define TAS5754M_DIGITAL_VOLUME_1  (TAS5754M_PAGE_BASE(0) +  60)
+#define TAS5754M_DIGITAL_VOLUME_2  (TAS5754M_PAGE_BASE(0) +  61)
+#define TAS5754M_DIGITAL_VOLUME_3  (TAS5754M_PAGE_BASE(0) +  62)
+#define TAS5754M_DIGITAL_MUTE_1    (TAS5754M_PAGE_BASE(0) +  63)
+#define TAS5754M_DIGITAL_MUTE_2    (TAS5754M_PAGE_BASE(0) +  64)
+#define TAS5754M_DIGITAL_MUTE_3    (TAS5754M_PAGE_BASE(0) +  65)
+#define TAS5754M_GPIO_OUTPUT_1     (TAS5754M_PAGE_BASE(0) +  82)
+#define TAS5754M_GPIO_OUTPUT_0     (TAS5754M_PAGE_BASE(0) +  83)
+#define TAS5754M_GPIO_OUTPUT_2     (TAS5754M_PAGE_BASE(0) +  85)
+#define TAS5754M_GPIO_CONTROL_1    (TAS5754M_PAGE_BASE(0) +  86)
+#define TAS5754M_GPIO_CONTROL_2    (TAS5754M_PAGE_BASE(0) +  87)
+#define TAS5754M_OVERFLOW          (TAS5754M_PAGE_BASE(0) +  90)
+#define TAS5754M_RATE_DET_1        (TAS5754M_PAGE_BASE(0) +  91)
+#define TAS5754M_RATE_DET_2        (TAS5754M_PAGE_BASE(0) +  92)
+#define TAS5754M_RATE_DET_3        (TAS5754M_PAGE_BASE(0) +  93)
+#define TAS5754M_RATE_DET_4        (TAS5754M_PAGE_BASE(0) +  94)
+#define TAS5754M_CLOCK_STATUS      (TAS5754M_PAGE_BASE(0) +  95)
+#define TAS5754M_ANALOG_MUTE_DET   (TAS5754M_PAGE_BASE(0) + 108)
+#define TAS5754M_FS_MODE_MON       (TAS5754M_PAGE_BASE(0) + 115)
+#define TAS5754M_GPIN              (TAS5754M_PAGE_BASE(0) + 119)
+#define TAS5754M_DIGITAL_MUTE_DET  (TAS5754M_PAGE_BASE(0) + 120)
+
+#define TAS5754M_OUTPUT_AMPLITUDE  (TAS5754M_PAGE_BASE(1) +   1)
+#define TAS5754M_ANALOG_GAIN_CTRL  (TAS5754M_PAGE_BASE(1) +   2)
+#define TAS5754M_UNDERVOLTAGE_PROT (TAS5754M_PAGE_BASE(1) +   5)
+#define TAS5754M_ANALOG_MUTE_CTRL  (TAS5754M_PAGE_BASE(1) +   6)
+#define TAS5754M_ANALOG_GAIN_BOOST (TAS5754M_PAGE_BASE(1) +   7)
+#define TAS5754M_VCOM_CTRL_1       (TAS5754M_PAGE_BASE(1) +   8)
+#define TAS5754M_VCOM_CTRL_2       (TAS5754M_PAGE_BASE(1) +   9)
+
+#define TAS5754M_CRAM_CTRL         (TAS5754M_PAGE_BASE(44) +  1)
+
+#define TAS5754M_FLEX_A            (TAS5754M_PAGE_BASE(253) + 63)
+#define TAS5754M_FLEX_B            (TAS5754M_PAGE_BASE(253) + 64)
+
+#define TAS5754M_MAX_REGISTER      (TAS5754M_PAGE_BASE(253) + 64)
+
+/* Page 0, Register 1 - reset */
+#define TAS5754M_RSTR (1 << 0)
+#define TAS5754M_RSTM (1 << 4)
+
+/* Page 0, Register 2 - power */
+#define TAS5754M_RQPD       (1 << 0)
+#define TAS5754M_RQPD_SHIFT 0
+#define TAS5754M_RQST       (1 << 4)
+#define TAS5754M_RQST_SHIFT 4
+
+/* Page 0, Register 3 - mute */
+#define TAS5754M_RQMR (1 << 0)
+#define TAS5754M_RQMR_SHIFT 0
+#define TAS5754M_RQML (1 << 4)
+#define TAS5754M_RQML_SHIFT 4
+
+/* Page 0, Register 4 - PLL */
+#define TAS5754M_PLLE       (1 << 0)
+#define TAS5754M_PLLE_SHIFT 0
+#define TAS5754M_PLCK       (1 << 4)
+#define TAS5754M_PLCK_SHIFT 4
+
+/* Page 0, Register 7 - DSP */
+#define TAS5754M_SDSL       (1 << 0)
+#define TAS5754M_SDSL_SHIFT 0
+#define TAS5754M_DEMP       (1 << 4)
+#define TAS5754M_DEMP_SHIFT 4
+
+/* Page 0, Register 8 - GPIO output enable */
+#define TAS5754M_G1OE       (1 << 0)
+#define TAS5754M_G2OE       (1 << 1)
+#define TAS5754M_G3OE       (1 << 2)
+#define TAS5754M_G4OE       (1 << 3)
+#define TAS5754M_G5OE       (1 << 4)
+#define TAS5754M_G6OE       (1 << 5)
+
+/* Page 0, Register 9 - BCK, LRCLK configuration */
+#define TAS5754M_LRKO       (1 << 0)
+#define TAS5754M_LRKO_SHIFT 0
+#define TAS5754M_BCKO       (1 << 4)
+#define TAS5754M_BCKO_SHIFT 4
+#define TAS5754M_BCKP       (1 << 5)
+#define TAS5754M_BCKP_SHIFT 5
+
+/* Page 0, Register 12 - Master mode BCK, LRCLK reset */
+#define TAS5754M_RLRK       (1 << 0)
+#define TAS5754M_RLRK_SHIFT 0
+#define TAS5754M_RBCK       (1 << 1)
+#define TAS5754M_RBCK_SHIFT 1
+
+/* Page 0, Register 13 - PLL reference */
+#define TAS5754M_SREF        (7 << 4)
+#define TAS5754M_SREF_SHIFT  4
+#define TAS5754M_SREF_SCK    (0 << 4)
+#define TAS5754M_SREF_BCK    (1 << 4)
+#define TAS5754M_SREF_GPIO   (3 << 4)
+
+/* Page 0, Register 14 - DAC reference */
+#define TAS5754M_SDAC        (7 << 4)
+#define TAS5754M_SDAC_SHIFT  4
+#define TAS5754M_SDAC_MCK    (0 << 4)
+#define TAS5754M_SDAC_PLL    (1 << 4)
+#define TAS5754M_SDAC_SCK    (3 << 4)
+#define TAS5754M_SDAC_BCK    (4 << 4)
+#define TAS5754M_SDAC_GPIO   (5 << 4)
+
+/* Page 0, Register 16, 18 - GPIO source for DAC, PLL */
+#define TAS5754M_GREF        (7 << 0)
+#define TAS5754M_GREF_SHIFT  0
+#define TAS5754M_GREF_GPIO1  (0 << 0)
+#define TAS5754M_GREF_GPIO2  (1 << 0)
+#define TAS5754M_GREF_GPIO3  (2 << 0)
+#define TAS5754M_GREF_GPIO4  (3 << 0)
+#define TAS5754M_GREF_GPIO5  (4 << 0)
+#define TAS5754M_GREF_GPIO6  (5 << 0)
+
+/* Page 0, Register 19 - synchronize */
+#define TAS5754M_RQSY        (1 << 0)
+#define TAS5754M_RQSY_RESUME (0 << 0)
+#define TAS5754M_RQSY_HALT   (1 << 0)
+
+/* Page 0, Register 34 - fs speed mode */
+#define TAS5754M_FSSP        (3 << 0)
+#define TAS5754M_FSSP_SHIFT  0
+#define TAS5754M_FSSP_48KHZ  (0 << 0)
+#define TAS5754M_FSSP_96KHZ  (1 << 0)
+#define TAS5754M_FSSP_192KHZ (2 << 0)
+#define TAS5754M_FSSP_384KHZ (3 << 0)
+
+/* Page 0, Register 37 - Error detection */
+#define TAS5754M_IPLK (1 << 0)
+#define TAS5754M_DCAS (1 << 1)
+#define TAS5754M_IDCM (1 << 2)
+#define TAS5754M_IDCH (1 << 3)
+#define TAS5754M_IDSK (1 << 4)
+#define TAS5754M_IDBK (1 << 5)
+#define TAS5754M_IDFS (1 << 6)
+
+/* Page 0, Register 40 - I2S configuration */
+#define TAS5754M_ALEN       (3 << 0)
+#define TAS5754M_ALEN_SHIFT 0
+#define TAS5754M_ALEN_16    (0 << 0)
+#define TAS5754M_ALEN_20    (1 << 0)
+#define TAS5754M_ALEN_24    (2 << 0)
+#define TAS5754M_ALEN_32    (3 << 0)
+#define TAS5754M_AFMT       (3 << 4)
+#define TAS5754M_AFMT_SHIFT 4
+#define TAS5754M_AFMT_I2S   (0 << 4)
+#define TAS5754M_AFMT_DSP   (1 << 4)
+#define TAS5754M_AFMT_RTJ   (2 << 4)
+#define TAS5754M_AFMT_LTJ   (3 << 4)
+
+/* Page 0, Register 42 - DAC routing */
+#define TAS5754M_AUPR_SHIFT 0
+#define TAS5754M_AUPL_SHIFT 4
+
+/* Page 0, Register 59 - auto mute */
+#define TAS5754M_ATMR_SHIFT 0
+#define TAS5754M_ATML_SHIFT 4
+
+/* Page 0, Register 63 - ramp rates */
+#define TAS5754M_VNDF_SHIFT 6
+#define TAS5754M_VNDS_SHIFT 4
+#define TAS5754M_VNUF_SHIFT 2
+#define TAS5754M_VNUS_SHIFT 0
+
+/* Page 0, Register 64 - emergency ramp rates */
+#define TAS5754M_VEDF_SHIFT 6
+#define TAS5754M_VEDS_SHIFT 4
+
+/* Page 0, Register 65 - Digital mute enables */
+#define TAS5754M_ACTL_SHIFT 2
+#define TAS5754M_AMLE_SHIFT 1
+#define TAS5754M_AMRE_SHIFT 0
+
+/* Page 0, Register 80-85, GPIO output selection */
+#define TAS5754M_GxSL       (31 << 0)
+#define TAS5754M_GxSL_SHIFT 0
+#define TAS5754M_GxSL_OFF   (0 << 0)
+#define TAS5754M_GxSL_DSP   (1 << 0)
+#define TAS5754M_GxSL_REG   (2 << 0)
+#define TAS5754M_GxSL_AMUTB (3 << 0)
+#define TAS5754M_GxSL_AMUTL (4 << 0)
+#define TAS5754M_GxSL_AMUTR (5 << 0)
+#define TAS5754M_GxSL_CLKI  (6 << 0)
+#define TAS5754M_GxSL_SDOUT (7 << 0)
+#define TAS5754M_GxSL_ANMUL (8 << 0)
+#define TAS5754M_GxSL_ANMUR (9 << 0)
+#define TAS5754M_GxSL_PLLLK (10 << 0)
+#define TAS5754M_GxSL_CPCLK (11 << 0)
+#define TAS5754M_GxSL_UV0_7 (14 << 0)
+#define TAS5754M_GxSL_UV0_3 (15 << 0)
+#define TAS5754M_GxSL_PLLCK (16 << 0)
+
+/* Page 1, Register 2 - analog volume control */
+#define TAS5754M_RAGN_SHIFT 0
+#define TAS5754M_LAGN_SHIFT 4
+
+/* Page 1, Register 7 - analog boost control */
+#define TAS5754M_AGBR_SHIFT 0
+#define TAS5754M_AGBL_SHIFT 4
+
+#endif
-- 
2.25.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH v3] ASoC: adds component driver for TAS575xM digital amplifiers
  2022-01-10  8:45   ` Joerg Schambacher
@ 2022-01-10 11:20     ` kernel test robot
  -1 siblings, 0 replies; 21+ messages in thread
From: kernel test robot @ 2022-01-10 11:20 UTC (permalink / raw)
  To: Joerg Schambacher, alsa-devel; +Cc: broonie, joerg, kbuild-all

Hi Joerg,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on broonie-sound/for-next]
[also build test WARNING on v5.16 next-20220110]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Joerg-Schambacher/ASoC-adds-component-driver-for-TAS575xM-digital-amplifiers/20220110-164852
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
config: powerpc-allyesconfig (https://download.01.org/0day-ci/archive/20220110/202201101949.6FmvBdvY-lkp@intel.com/config)
compiler: powerpc-linux-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/194435492a87ace959d74aae1cecb27f16ad8966
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Joerg-Schambacher/ASoC-adds-component-driver-for-TAS575xM-digital-amplifiers/20220110-164852
        git checkout 194435492a87ace959d74aae1cecb27f16ad8966
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=powerpc SHELL=/bin/bash sound/soc/codecs/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> sound/soc/codecs/tas5754m.c:273:5: warning: no previous prototype for 'tas5754m_set_clock_tree_master' [-Wmissing-prototypes]
     273 | int tas5754m_set_clock_tree_master(struct snd_soc_dai *dai,
         |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> sound/soc/codecs/tas5754m.c:346:5: warning: no previous prototype for 'tas5754m_set_dai_mode' [-Wmissing-prototypes]
     346 | int tas5754m_set_dai_mode(struct snd_soc_dai *dai)
         |     ^~~~~~~~~~~~~~~~~~~~~
>> sound/soc/codecs/tas5754m.c:395:5: warning: no previous prototype for 'tas5754m_set_dividers_master' [-Wmissing-prototypes]
     395 | int tas5754m_set_dividers_master(struct snd_soc_dai *dai,
         |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~


vim +/tas5754m_set_clock_tree_master +273 sound/soc/codecs/tas5754m.c

   272	
 > 273	int tas5754m_set_clock_tree_master(struct snd_soc_dai *dai,
   274						struct snd_pcm_hw_params *params)
   275	{
   276		struct snd_soc_component *component = dai->component;
   277		struct tas5754m_priv *tas5754m =
   278				snd_soc_component_get_drvdata(component);
   279		static const struct reg_sequence pll_settings[] = {
   280			{ TAS5754M_PLL_COEFF_P,		0x01 },	// P=2
   281			{ TAS5754M_PLL_COEFF_J,		0x08 },	// J=8
   282			{ TAS5754M_PLL_COEFF_DL,	0x00 },	// D12-8 = 0
   283			{ TAS5754M_PLL_COEFF_DH,	0x00 },	// D7-0 = 0
   284			{ TAS5754M_PLL_COEFF_R,		0x00 },	// R=1
   285		};
   286		int ret;
   287	
   288		/* disable PLL before any clock tree change */
   289		ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
   290					 TAS5754M_PLLE, 0);
   291		if (ret != 0) {
   292			dev_err(component->dev, "Failed to disable PLL: %d\n", ret);
   293			return ret;
   294		}
   295	
   296		/* set DAC clock source to MCLK */
   297		ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_REF, 0x30);
   298		if (ret != 0) {
   299			dev_err(component->dev, "Failed to set DAC ref\n");
   300			return ret;
   301		}
   302	
   303		/* run PLL at fixed ratio to MCLK */
   304		ret = regmap_multi_reg_write(tas5754m->regmap, pll_settings,
   305						ARRAY_SIZE(pll_settings));
   306		if (ret != 0) {
   307			dev_err(component->dev, "Failed to set PLL ratio\n");
   308			return ret;
   309		}
   310	
   311		/* set DSP divider to 2 => reg 0x01 */
   312		ret = regmap_write(tas5754m->regmap, TAS5754M_DSP_CLKDIV, 1);
   313		if (ret != 0) {
   314			dev_err(component->dev, "Failed to set DSP divider\n");
   315			return ret;
   316		}
   317		/* set DAC divider to 4 => reg 0x03*/
   318		ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_CLKDIV, 3);
   319		if (ret != 0) {
   320			dev_err(component->dev, "Failed to set OSDACR divider\n");
   321			return ret;
   322		}
   323		/* set OSR divider to 1 */
   324		ret = regmap_write(tas5754m->regmap, TAS5754M_OSR_CLKDIV, 0);
   325		if (ret != 0) {
   326			dev_err(component->dev, "Failed to set OSR divider\n");
   327			return ret;
   328		}
   329		/* set CP divider to 4 => reg 0x03*/
   330		ret = regmap_write(tas5754m->regmap, TAS5754M_NCP_CLKDIV, 3);
   331		if (ret != 0) {
   332			dev_err(component->dev, "Failed to set CP divider\n");
   333			return ret;
   334		}
   335		/* finally enable PLL */
   336		ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
   337					 TAS5754M_PLLE, 1);
   338		if (ret != 0) {
   339			dev_err(component->dev, "Failed to enable PLL: %d\n", ret);
   340			return ret;
   341		}
   342	
   343		return 0;
   344	}
   345	
 > 346	int tas5754m_set_dai_mode(struct snd_soc_dai *dai)
   347	{
   348		struct snd_soc_component *component = dai->component;
   349		struct tas5754m_priv *tas5754m =
   350				snd_soc_component_get_drvdata(component);
   351		int fmt = tas5754m->fmt;
   352	
   353		/* only I2S MASTER mode implemented */
   354		if (((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S)) {
   355			dev_err(component->dev,
   356				"DAI format not supported (I2S master only)\n");
   357			return -EINVAL;
   358		}
   359		/* TAS5754/6m do not support inverted clocks in MASTER mode */
   360		if (((fmt & SND_SOC_DAIFMT_CLOCK_MASK) != SND_SOC_DAIFMT_NB_NF)) {
   361			dev_err(component->dev,	"Inverted clocks not supported\n");
   362			return -EINVAL;
   363		}
   364	
   365		switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
   366		case SND_SOC_DAIFMT_CBM_CFM:
   367			regmap_update_bits(tas5754m->regmap,
   368					TAS5754M_BCLK_LRCLK_CFG,
   369					TAS5754M_LRKO | TAS5754M_BCKO,
   370					TAS5754M_LRKO | TAS5754M_BCKO);
   371			/* reset CLK dividers */
   372			regmap_update_bits(tas5754m->regmap,
   373					TAS5754M_MASTER_MODE,
   374					0x00,
   375					TAS5754M_RLRK | TAS5754M_RBCK);
   376			/* ignore all clock error detection but MCLK */
   377			regmap_update_bits(tas5754m->regmap,
   378					TAS5754M_ERROR_DETECT,
   379					TAS5754M_IPLK | TAS5754M_DCAS |
   380					TAS5754M_IDCM | TAS5754M_IDSK |
   381					TAS5754M_IDBK | TAS5754M_IDFS,
   382					TAS5754M_IPLK | TAS5754M_DCAS |
   383					TAS5754M_IDCM | TAS5754M_IDSK |
   384					TAS5754M_IDBK | TAS5754M_IDFS);
   385			break;
   386		case SND_SOC_DAIFMT_CBS_CFS:
   387		case SND_SOC_DAIFMT_CBM_CFS:
   388		default:
   389			return -EINVAL;
   390		}
   391	
   392		return 0;
   393	}
   394	
 > 395	int tas5754m_set_dividers_master(struct snd_soc_dai *dai,
   396					struct snd_pcm_hw_params *params)
   397	{
   398		struct snd_soc_component *component = dai->component;
   399		struct tas5754m_priv *tas5754m =
   400				snd_soc_component_get_drvdata(component);
   401		unsigned long bclk;
   402		unsigned long mclk;
   403		int bclk_div;
   404		int lrclk_div;
   405		int osr;
   406		int ret;
   407	
   408		mclk = clk_get_rate(tas5754m->sclk);
   409		bclk = tas5754m->sample_len * 2 * params_rate(params);
   410		bclk_div = mclk / bclk;
   411		lrclk_div = tas5754m->sample_len * 2;
   412		osr = mclk / 4 / params_rate(params) / 16;
   413	
   414		// stop LR / SCLK clocks
   415		ret = regmap_update_bits(tas5754m->regmap,
   416					TAS5754M_MASTER_MODE,
   417					!TAS5754M_RLRK | !TAS5754M_RBCK,
   418					TAS5754M_RLRK | TAS5754M_RBCK);
   419		if (ret != 0) {
   420			dev_err(component->dev, "Failed to stop PLL\n");
   421			return ret;
   422		}
   423	
   424		// set SCLK divider
   425		ret = regmap_write(tas5754m->regmap, TAS5754M_MASTER_SCLKDIV,
   426									bclk_div - 1);
   427		if (ret != 0) {
   428			dev_err(component->dev, "Failed to set SCLK divider\n");
   429			return ret;
   430		}
   431	
   432		// set LRCLK divider
   433		ret = regmap_write(tas5754m->regmap, TAS5754M_MASTER_LRCLKDIV,
   434									lrclk_div - 1);
   435		if (ret != 0) {
   436			dev_err(component->dev, "Failed to set LRCLK divider\n");
   437			return ret;
   438		}
   439	
   440		ret = regmap_write(tas5754m->regmap,
   441			TAS5754M_OSR_CLKDIV, osr - 1);
   442		if (ret != 0) {
   443			dev_err(component->dev, "Failed to set OSR divider\n");
   444			return ret;
   445		}
   446	
   447		// restart LR / SCLK clocks
   448		ret = regmap_update_bits(tas5754m->regmap,
   449					TAS5754M_MASTER_MODE,
   450					TAS5754M_RLRK | TAS5754M_RBCK,
   451					TAS5754M_RLRK | TAS5754M_RBCK);
   452		if (ret != 0) {
   453			dev_err(component->dev, "Failed to restart PLL\n");
   454			return ret;
   455		}
   456	
   457		return 0;
   458	}
   459	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3] ASoC: adds component driver for TAS575xM digital amplifiers
@ 2022-01-10 11:20     ` kernel test robot
  0 siblings, 0 replies; 21+ messages in thread
From: kernel test robot @ 2022-01-10 11:20 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 9293 bytes --]

Hi Joerg,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on broonie-sound/for-next]
[also build test WARNING on v5.16 next-20220110]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Joerg-Schambacher/ASoC-adds-component-driver-for-TAS575xM-digital-amplifiers/20220110-164852
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
config: powerpc-allyesconfig (https://download.01.org/0day-ci/archive/20220110/202201101949.6FmvBdvY-lkp(a)intel.com/config)
compiler: powerpc-linux-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/194435492a87ace959d74aae1cecb27f16ad8966
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Joerg-Schambacher/ASoC-adds-component-driver-for-TAS575xM-digital-amplifiers/20220110-164852
        git checkout 194435492a87ace959d74aae1cecb27f16ad8966
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=powerpc SHELL=/bin/bash sound/soc/codecs/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> sound/soc/codecs/tas5754m.c:273:5: warning: no previous prototype for 'tas5754m_set_clock_tree_master' [-Wmissing-prototypes]
     273 | int tas5754m_set_clock_tree_master(struct snd_soc_dai *dai,
         |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> sound/soc/codecs/tas5754m.c:346:5: warning: no previous prototype for 'tas5754m_set_dai_mode' [-Wmissing-prototypes]
     346 | int tas5754m_set_dai_mode(struct snd_soc_dai *dai)
         |     ^~~~~~~~~~~~~~~~~~~~~
>> sound/soc/codecs/tas5754m.c:395:5: warning: no previous prototype for 'tas5754m_set_dividers_master' [-Wmissing-prototypes]
     395 | int tas5754m_set_dividers_master(struct snd_soc_dai *dai,
         |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~


vim +/tas5754m_set_clock_tree_master +273 sound/soc/codecs/tas5754m.c

   272	
 > 273	int tas5754m_set_clock_tree_master(struct snd_soc_dai *dai,
   274						struct snd_pcm_hw_params *params)
   275	{
   276		struct snd_soc_component *component = dai->component;
   277		struct tas5754m_priv *tas5754m =
   278				snd_soc_component_get_drvdata(component);
   279		static const struct reg_sequence pll_settings[] = {
   280			{ TAS5754M_PLL_COEFF_P,		0x01 },	// P=2
   281			{ TAS5754M_PLL_COEFF_J,		0x08 },	// J=8
   282			{ TAS5754M_PLL_COEFF_DL,	0x00 },	// D12-8 = 0
   283			{ TAS5754M_PLL_COEFF_DH,	0x00 },	// D7-0 = 0
   284			{ TAS5754M_PLL_COEFF_R,		0x00 },	// R=1
   285		};
   286		int ret;
   287	
   288		/* disable PLL before any clock tree change */
   289		ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
   290					 TAS5754M_PLLE, 0);
   291		if (ret != 0) {
   292			dev_err(component->dev, "Failed to disable PLL: %d\n", ret);
   293			return ret;
   294		}
   295	
   296		/* set DAC clock source to MCLK */
   297		ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_REF, 0x30);
   298		if (ret != 0) {
   299			dev_err(component->dev, "Failed to set DAC ref\n");
   300			return ret;
   301		}
   302	
   303		/* run PLL at fixed ratio to MCLK */
   304		ret = regmap_multi_reg_write(tas5754m->regmap, pll_settings,
   305						ARRAY_SIZE(pll_settings));
   306		if (ret != 0) {
   307			dev_err(component->dev, "Failed to set PLL ratio\n");
   308			return ret;
   309		}
   310	
   311		/* set DSP divider to 2 => reg 0x01 */
   312		ret = regmap_write(tas5754m->regmap, TAS5754M_DSP_CLKDIV, 1);
   313		if (ret != 0) {
   314			dev_err(component->dev, "Failed to set DSP divider\n");
   315			return ret;
   316		}
   317		/* set DAC divider to 4 => reg 0x03*/
   318		ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_CLKDIV, 3);
   319		if (ret != 0) {
   320			dev_err(component->dev, "Failed to set OSDACR divider\n");
   321			return ret;
   322		}
   323		/* set OSR divider to 1 */
   324		ret = regmap_write(tas5754m->regmap, TAS5754M_OSR_CLKDIV, 0);
   325		if (ret != 0) {
   326			dev_err(component->dev, "Failed to set OSR divider\n");
   327			return ret;
   328		}
   329		/* set CP divider to 4 => reg 0x03*/
   330		ret = regmap_write(tas5754m->regmap, TAS5754M_NCP_CLKDIV, 3);
   331		if (ret != 0) {
   332			dev_err(component->dev, "Failed to set CP divider\n");
   333			return ret;
   334		}
   335		/* finally enable PLL */
   336		ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
   337					 TAS5754M_PLLE, 1);
   338		if (ret != 0) {
   339			dev_err(component->dev, "Failed to enable PLL: %d\n", ret);
   340			return ret;
   341		}
   342	
   343		return 0;
   344	}
   345	
 > 346	int tas5754m_set_dai_mode(struct snd_soc_dai *dai)
   347	{
   348		struct snd_soc_component *component = dai->component;
   349		struct tas5754m_priv *tas5754m =
   350				snd_soc_component_get_drvdata(component);
   351		int fmt = tas5754m->fmt;
   352	
   353		/* only I2S MASTER mode implemented */
   354		if (((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S)) {
   355			dev_err(component->dev,
   356				"DAI format not supported (I2S master only)\n");
   357			return -EINVAL;
   358		}
   359		/* TAS5754/6m do not support inverted clocks in MASTER mode */
   360		if (((fmt & SND_SOC_DAIFMT_CLOCK_MASK) != SND_SOC_DAIFMT_NB_NF)) {
   361			dev_err(component->dev,	"Inverted clocks not supported\n");
   362			return -EINVAL;
   363		}
   364	
   365		switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
   366		case SND_SOC_DAIFMT_CBM_CFM:
   367			regmap_update_bits(tas5754m->regmap,
   368					TAS5754M_BCLK_LRCLK_CFG,
   369					TAS5754M_LRKO | TAS5754M_BCKO,
   370					TAS5754M_LRKO | TAS5754M_BCKO);
   371			/* reset CLK dividers */
   372			regmap_update_bits(tas5754m->regmap,
   373					TAS5754M_MASTER_MODE,
   374					0x00,
   375					TAS5754M_RLRK | TAS5754M_RBCK);
   376			/* ignore all clock error detection but MCLK */
   377			regmap_update_bits(tas5754m->regmap,
   378					TAS5754M_ERROR_DETECT,
   379					TAS5754M_IPLK | TAS5754M_DCAS |
   380					TAS5754M_IDCM | TAS5754M_IDSK |
   381					TAS5754M_IDBK | TAS5754M_IDFS,
   382					TAS5754M_IPLK | TAS5754M_DCAS |
   383					TAS5754M_IDCM | TAS5754M_IDSK |
   384					TAS5754M_IDBK | TAS5754M_IDFS);
   385			break;
   386		case SND_SOC_DAIFMT_CBS_CFS:
   387		case SND_SOC_DAIFMT_CBM_CFS:
   388		default:
   389			return -EINVAL;
   390		}
   391	
   392		return 0;
   393	}
   394	
 > 395	int tas5754m_set_dividers_master(struct snd_soc_dai *dai,
   396					struct snd_pcm_hw_params *params)
   397	{
   398		struct snd_soc_component *component = dai->component;
   399		struct tas5754m_priv *tas5754m =
   400				snd_soc_component_get_drvdata(component);
   401		unsigned long bclk;
   402		unsigned long mclk;
   403		int bclk_div;
   404		int lrclk_div;
   405		int osr;
   406		int ret;
   407	
   408		mclk = clk_get_rate(tas5754m->sclk);
   409		bclk = tas5754m->sample_len * 2 * params_rate(params);
   410		bclk_div = mclk / bclk;
   411		lrclk_div = tas5754m->sample_len * 2;
   412		osr = mclk / 4 / params_rate(params) / 16;
   413	
   414		// stop LR / SCLK clocks
   415		ret = regmap_update_bits(tas5754m->regmap,
   416					TAS5754M_MASTER_MODE,
   417					!TAS5754M_RLRK | !TAS5754M_RBCK,
   418					TAS5754M_RLRK | TAS5754M_RBCK);
   419		if (ret != 0) {
   420			dev_err(component->dev, "Failed to stop PLL\n");
   421			return ret;
   422		}
   423	
   424		// set SCLK divider
   425		ret = regmap_write(tas5754m->regmap, TAS5754M_MASTER_SCLKDIV,
   426									bclk_div - 1);
   427		if (ret != 0) {
   428			dev_err(component->dev, "Failed to set SCLK divider\n");
   429			return ret;
   430		}
   431	
   432		// set LRCLK divider
   433		ret = regmap_write(tas5754m->regmap, TAS5754M_MASTER_LRCLKDIV,
   434									lrclk_div - 1);
   435		if (ret != 0) {
   436			dev_err(component->dev, "Failed to set LRCLK divider\n");
   437			return ret;
   438		}
   439	
   440		ret = regmap_write(tas5754m->regmap,
   441			TAS5754M_OSR_CLKDIV, osr - 1);
   442		if (ret != 0) {
   443			dev_err(component->dev, "Failed to set OSR divider\n");
   444			return ret;
   445		}
   446	
   447		// restart LR / SCLK clocks
   448		ret = regmap_update_bits(tas5754m->regmap,
   449					TAS5754M_MASTER_MODE,
   450					TAS5754M_RLRK | TAS5754M_RBCK,
   451					TAS5754M_RLRK | TAS5754M_RBCK);
   452		if (ret != 0) {
   453			dev_err(component->dev, "Failed to restart PLL\n");
   454			return ret;
   455		}
   456	
   457		return 0;
   458	}
   459	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3] ASoC: adds component driver for TAS575xM digital amplifiers
  2022-01-10  8:45   ` Joerg Schambacher
@ 2022-01-10 16:25     ` Cezary Rojewski
  -1 siblings, 0 replies; 21+ messages in thread
From: Cezary Rojewski @ 2022-01-10 16:25 UTC (permalink / raw)
  To: Joerg Schambacher, alsa-devel; +Cc: broonie, kbuild-all

On 2022-01-10 9:45 AM, Joerg Schambacher wrote:
> Adds a minimum component driver to run the amplifier in I2S master
> mode only from standard audio clocks. Therefore, it only allows
> 44.1, 88.2, 176.4, 48, 96 and 192ksps with 16, 20, 24 and 32 bits
> sample size. Digital volume control and the -6dB and +0.8dB switches
> are supported.

Couple nitpicks and suggestions below.

(...)

> +static int tas5754m_set_bias_level(struct snd_soc_component *component,
> +					enum snd_soc_bias_level level)
> +{
> +	struct tas5754m_priv *tas5754m =
> +				snd_soc_component_get_drvdata(component);
> +	int ret;
> +
> +	switch (level) {
> +	case SND_SOC_BIAS_ON:
> +	case SND_SOC_BIAS_PREPARE:
> +		break;
> +
> +	case SND_SOC_BIAS_STANDBY:
> +		ret = regmap_update_bits(tas5754m->regmap,
> +				TAS5754M_POWER, TAS5754M_RQST, 0);
> +		if (ret != 0) {

I believe we are dealing here with standard API function i.e. 0 on 
success and negative value on error. And thus, 'if (ret)' suffices.

> +			dev_err(component->dev,
> +				"Failed to remove standby: %d\n", ret);
> +			return ret;
> +		}
> +		break;
> +
> +	case SND_SOC_BIAS_OFF:
> +		ret = regmap_update_bits(tas5754m->regmap,
> +				TAS5754M_POWER, TAS5754M_RQST, TAS5754M_RQST);
> +		if (ret != 0) {

Ditto. This also goes for every single usage of regmap_xxx() in this file.

> +			dev_err(component->dev,
> +				"Failed to request standby: %d\n", ret);
> +			return ret;
> +		}
> +		break;
> +	}
> +
> +	return 0;

You could also drop the 'return ret' from the if-statements above - 
granting you also ability to drop the brackets - and instead return 
'ret' instead of '0' here. Of course that means 'ret' needs to be 
initialized appropriately at the top of the function.

> +}
> +
> +int tas5754m_set_clock_tree_master(struct snd_soc_dai *dai,
> +					struct snd_pcm_hw_params *params)

Indentation seems off.

> +{
> +	struct snd_soc_component *component = dai->component;
> +	struct tas5754m_priv *tas5754m =
> +			snd_soc_component_get_drvdata(component);
> +	static const struct reg_sequence pll_settings[] = {
> +		{ TAS5754M_PLL_COEFF_P,		0x01 },	// P=2
> +		{ TAS5754M_PLL_COEFF_J,		0x08 },	// J=8
> +		{ TAS5754M_PLL_COEFF_DL,	0x00 },	// D12-8 = 0
> +		{ TAS5754M_PLL_COEFF_DH,	0x00 },	// D7-0 = 0
> +		{ TAS5754M_PLL_COEFF_R,		0x00 },	// R=1
> +	};
> +	int ret;
> +
> +	/* disable PLL before any clock tree change */
> +	ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
> +				 TAS5754M_PLLE, 0);
> +	if (ret != 0) {
> +		dev_err(component->dev, "Failed to disable PLL: %d\n", ret);
> +		return ret;
> +	}
> +
> +	/* set DAC clock source to MCLK */
> +	ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_REF, 0x30);
> +	if (ret != 0) {
> +		dev_err(component->dev, "Failed to set DAC ref\n");
> +		return ret;
> +	}
> +
> +	/* run PLL at fixed ratio to MCLK */
> +	ret = regmap_multi_reg_write(tas5754m->regmap, pll_settings,
> +					ARRAY_SIZE(pll_settings));
> +	if (ret != 0) {
> +		dev_err(component->dev, "Failed to set PLL ratio\n");
> +		return ret;
> +	}
> +
> +	/* set DSP divider to 2 => reg 0x01 */
> +	ret = regmap_write(tas5754m->regmap, TAS5754M_DSP_CLKDIV, 1);
> +	if (ret != 0) {
> +		dev_err(component->dev, "Failed to set DSP divider\n");
> +		return ret;
> +	}
> +	/* set DAC divider to 4 => reg 0x03*/
> +	ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_CLKDIV, 3);
> +	if (ret != 0) {
> +		dev_err(component->dev, "Failed to set OSDACR divider\n");
> +		return ret;
> +	}
> +	/* set OSR divider to 1 */
> +	ret = regmap_write(tas5754m->regmap, TAS5754M_OSR_CLKDIV, 0);
> +	if (ret != 0) {
> +		dev_err(component->dev, "Failed to set OSR divider\n");
> +		return ret;
> +	}
> +	/* set CP divider to 4 => reg 0x03*/
> +	ret = regmap_write(tas5754m->regmap, TAS5754M_NCP_CLKDIV, 3);
> +	if (ret != 0) {
> +		dev_err(component->dev, "Failed to set CP divider\n");
> +		return ret;
> +	}
> +	/* finally enable PLL */
> +	ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
> +				 TAS5754M_PLLE, 1);
> +	if (ret != 0) {
> +		dev_err(component->dev, "Failed to enable PLL: %d\n", ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}

I'd suggest to keep the logical block organization cohesive. Especially 
if there are several of them all located within a single function. Some 
of the do/check/error-out blocks above are separated by a newline from 
the following ones, and some are not.

Another point is the cohesiveness of the error-message format. Some of 
the above print value of 'ret' i.e. carry additional value whereas other 
skip that part. Is this intentional?

> +
> +int tas5754m_set_dai_mode(struct snd_soc_dai *dai)
> +{
> +	struct snd_soc_component *component = dai->component;
> +	struct tas5754m_priv *tas5754m =
> +			snd_soc_component_get_drvdata(component);
> +	int fmt = tas5754m->fmt;
> +
> +	/* only I2S MASTER mode implemented */
> +	if (((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S)) {

Maybe I'm missing something but the most outter pair of brackets is 
redundant.

> +		dev_err(component->dev,
> +			"DAI format not supported (I2S master only)\n");
> +		return -EINVAL;
> +	}
> +	/* TAS5754/6m do not support inverted clocks in MASTER mode */

A newline before the comment would make this more readabile - that's a 
new logical block afterall.

> +	if (((fmt & SND_SOC_DAIFMT_CLOCK_MASK) != SND_SOC_DAIFMT_NB_NF)) {

Again, I may be missing something, but this looks like outter brackets 
are redundant.

> +		dev_err(component->dev,	"Inverted clocks not supported\n");
> +		return -EINVAL;
> +	}
> +
> +	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
> +	case SND_SOC_DAIFMT_CBM_CFM:
> +		regmap_update_bits(tas5754m->regmap,
> +				TAS5754M_BCLK_LRCLK_CFG,
> +				TAS5754M_LRKO | TAS5754M_BCKO,
> +				TAS5754M_LRKO | TAS5754M_BCKO);
> +		/* reset CLK dividers */
> +		regmap_update_bits(tas5754m->regmap,
> +				TAS5754M_MASTER_MODE,
> +				0x00,
> +				TAS5754M_RLRK | TAS5754M_RBCK);
> +		/* ignore all clock error detection but MCLK */
> +		regmap_update_bits(tas5754m->regmap,
> +				TAS5754M_ERROR_DETECT,
> +				TAS5754M_IPLK | TAS5754M_DCAS |
> +				TAS5754M_IDCM | TAS5754M_IDSK |
> +				TAS5754M_IDBK | TAS5754M_IDFS,
> +				TAS5754M_IPLK | TAS5754M_DCAS |
> +				TAS5754M_IDCM | TAS5754M_IDSK |
> +				TAS5754M_IDBK | TAS5754M_IDFS);
> +		break;
> +	case SND_SOC_DAIFMT_CBS_CFS:
> +	case SND_SOC_DAIFMT_CBM_CFS:
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +int tas5754m_set_dividers_master(struct snd_soc_dai *dai,
> +				struct snd_pcm_hw_params *params)
> +{
> +	struct snd_soc_component *component = dai->component;
> +	struct tas5754m_priv *tas5754m =
> +			snd_soc_component_get_drvdata(component);
> +	unsigned long bclk;
> +	unsigned long mclk;
> +	int bclk_div;
> +	int lrclk_div;
> +	int osr;
> +	int ret;
> +
> +	mclk = clk_get_rate(tas5754m->sclk);
> +	bclk = tas5754m->sample_len * 2 * params_rate(params);
> +	bclk_div = mclk / bclk;
> +	lrclk_div = tas5754m->sample_len * 2;
> +	osr = mclk / 4 / params_rate(params) / 16;

Is there a specific reason as to why these magic numbers aren't 
defines/constants?

> +
> +	// stop LR / SCLK clocks

Formatting of this comment looks odd. Please align with the recommended one.


(...)


Regards,
Czarek

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3] ASoC: adds component driver for TAS575xM digital amplifiers
@ 2022-01-10 16:25     ` Cezary Rojewski
  0 siblings, 0 replies; 21+ messages in thread
From: Cezary Rojewski @ 2022-01-10 16:25 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 7475 bytes --]

On 2022-01-10 9:45 AM, Joerg Schambacher wrote:
> Adds a minimum component driver to run the amplifier in I2S master
> mode only from standard audio clocks. Therefore, it only allows
> 44.1, 88.2, 176.4, 48, 96 and 192ksps with 16, 20, 24 and 32 bits
> sample size. Digital volume control and the -6dB and +0.8dB switches
> are supported.

Couple nitpicks and suggestions below.

(...)

> +static int tas5754m_set_bias_level(struct snd_soc_component *component,
> +					enum snd_soc_bias_level level)
> +{
> +	struct tas5754m_priv *tas5754m =
> +				snd_soc_component_get_drvdata(component);
> +	int ret;
> +
> +	switch (level) {
> +	case SND_SOC_BIAS_ON:
> +	case SND_SOC_BIAS_PREPARE:
> +		break;
> +
> +	case SND_SOC_BIAS_STANDBY:
> +		ret = regmap_update_bits(tas5754m->regmap,
> +				TAS5754M_POWER, TAS5754M_RQST, 0);
> +		if (ret != 0) {

I believe we are dealing here with standard API function i.e. 0 on 
success and negative value on error. And thus, 'if (ret)' suffices.

> +			dev_err(component->dev,
> +				"Failed to remove standby: %d\n", ret);
> +			return ret;
> +		}
> +		break;
> +
> +	case SND_SOC_BIAS_OFF:
> +		ret = regmap_update_bits(tas5754m->regmap,
> +				TAS5754M_POWER, TAS5754M_RQST, TAS5754M_RQST);
> +		if (ret != 0) {

Ditto. This also goes for every single usage of regmap_xxx() in this file.

> +			dev_err(component->dev,
> +				"Failed to request standby: %d\n", ret);
> +			return ret;
> +		}
> +		break;
> +	}
> +
> +	return 0;

You could also drop the 'return ret' from the if-statements above - 
granting you also ability to drop the brackets - and instead return 
'ret' instead of '0' here. Of course that means 'ret' needs to be 
initialized appropriately at the top of the function.

> +}
> +
> +int tas5754m_set_clock_tree_master(struct snd_soc_dai *dai,
> +					struct snd_pcm_hw_params *params)

Indentation seems off.

> +{
> +	struct snd_soc_component *component = dai->component;
> +	struct tas5754m_priv *tas5754m =
> +			snd_soc_component_get_drvdata(component);
> +	static const struct reg_sequence pll_settings[] = {
> +		{ TAS5754M_PLL_COEFF_P,		0x01 },	// P=2
> +		{ TAS5754M_PLL_COEFF_J,		0x08 },	// J=8
> +		{ TAS5754M_PLL_COEFF_DL,	0x00 },	// D12-8 = 0
> +		{ TAS5754M_PLL_COEFF_DH,	0x00 },	// D7-0 = 0
> +		{ TAS5754M_PLL_COEFF_R,		0x00 },	// R=1
> +	};
> +	int ret;
> +
> +	/* disable PLL before any clock tree change */
> +	ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
> +				 TAS5754M_PLLE, 0);
> +	if (ret != 0) {
> +		dev_err(component->dev, "Failed to disable PLL: %d\n", ret);
> +		return ret;
> +	}
> +
> +	/* set DAC clock source to MCLK */
> +	ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_REF, 0x30);
> +	if (ret != 0) {
> +		dev_err(component->dev, "Failed to set DAC ref\n");
> +		return ret;
> +	}
> +
> +	/* run PLL at fixed ratio to MCLK */
> +	ret = regmap_multi_reg_write(tas5754m->regmap, pll_settings,
> +					ARRAY_SIZE(pll_settings));
> +	if (ret != 0) {
> +		dev_err(component->dev, "Failed to set PLL ratio\n");
> +		return ret;
> +	}
> +
> +	/* set DSP divider to 2 => reg 0x01 */
> +	ret = regmap_write(tas5754m->regmap, TAS5754M_DSP_CLKDIV, 1);
> +	if (ret != 0) {
> +		dev_err(component->dev, "Failed to set DSP divider\n");
> +		return ret;
> +	}
> +	/* set DAC divider to 4 => reg 0x03*/
> +	ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_CLKDIV, 3);
> +	if (ret != 0) {
> +		dev_err(component->dev, "Failed to set OSDACR divider\n");
> +		return ret;
> +	}
> +	/* set OSR divider to 1 */
> +	ret = regmap_write(tas5754m->regmap, TAS5754M_OSR_CLKDIV, 0);
> +	if (ret != 0) {
> +		dev_err(component->dev, "Failed to set OSR divider\n");
> +		return ret;
> +	}
> +	/* set CP divider to 4 => reg 0x03*/
> +	ret = regmap_write(tas5754m->regmap, TAS5754M_NCP_CLKDIV, 3);
> +	if (ret != 0) {
> +		dev_err(component->dev, "Failed to set CP divider\n");
> +		return ret;
> +	}
> +	/* finally enable PLL */
> +	ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
> +				 TAS5754M_PLLE, 1);
> +	if (ret != 0) {
> +		dev_err(component->dev, "Failed to enable PLL: %d\n", ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}

I'd suggest to keep the logical block organization cohesive. Especially 
if there are several of them all located within a single function. Some 
of the do/check/error-out blocks above are separated by a newline from 
the following ones, and some are not.

Another point is the cohesiveness of the error-message format. Some of 
the above print value of 'ret' i.e. carry additional value whereas other 
skip that part. Is this intentional?

> +
> +int tas5754m_set_dai_mode(struct snd_soc_dai *dai)
> +{
> +	struct snd_soc_component *component = dai->component;
> +	struct tas5754m_priv *tas5754m =
> +			snd_soc_component_get_drvdata(component);
> +	int fmt = tas5754m->fmt;
> +
> +	/* only I2S MASTER mode implemented */
> +	if (((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S)) {

Maybe I'm missing something but the most outter pair of brackets is 
redundant.

> +		dev_err(component->dev,
> +			"DAI format not supported (I2S master only)\n");
> +		return -EINVAL;
> +	}
> +	/* TAS5754/6m do not support inverted clocks in MASTER mode */

A newline before the comment would make this more readabile - that's a 
new logical block afterall.

> +	if (((fmt & SND_SOC_DAIFMT_CLOCK_MASK) != SND_SOC_DAIFMT_NB_NF)) {

Again, I may be missing something, but this looks like outter brackets 
are redundant.

> +		dev_err(component->dev,	"Inverted clocks not supported\n");
> +		return -EINVAL;
> +	}
> +
> +	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
> +	case SND_SOC_DAIFMT_CBM_CFM:
> +		regmap_update_bits(tas5754m->regmap,
> +				TAS5754M_BCLK_LRCLK_CFG,
> +				TAS5754M_LRKO | TAS5754M_BCKO,
> +				TAS5754M_LRKO | TAS5754M_BCKO);
> +		/* reset CLK dividers */
> +		regmap_update_bits(tas5754m->regmap,
> +				TAS5754M_MASTER_MODE,
> +				0x00,
> +				TAS5754M_RLRK | TAS5754M_RBCK);
> +		/* ignore all clock error detection but MCLK */
> +		regmap_update_bits(tas5754m->regmap,
> +				TAS5754M_ERROR_DETECT,
> +				TAS5754M_IPLK | TAS5754M_DCAS |
> +				TAS5754M_IDCM | TAS5754M_IDSK |
> +				TAS5754M_IDBK | TAS5754M_IDFS,
> +				TAS5754M_IPLK | TAS5754M_DCAS |
> +				TAS5754M_IDCM | TAS5754M_IDSK |
> +				TAS5754M_IDBK | TAS5754M_IDFS);
> +		break;
> +	case SND_SOC_DAIFMT_CBS_CFS:
> +	case SND_SOC_DAIFMT_CBM_CFS:
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +int tas5754m_set_dividers_master(struct snd_soc_dai *dai,
> +				struct snd_pcm_hw_params *params)
> +{
> +	struct snd_soc_component *component = dai->component;
> +	struct tas5754m_priv *tas5754m =
> +			snd_soc_component_get_drvdata(component);
> +	unsigned long bclk;
> +	unsigned long mclk;
> +	int bclk_div;
> +	int lrclk_div;
> +	int osr;
> +	int ret;
> +
> +	mclk = clk_get_rate(tas5754m->sclk);
> +	bclk = tas5754m->sample_len * 2 * params_rate(params);
> +	bclk_div = mclk / bclk;
> +	lrclk_div = tas5754m->sample_len * 2;
> +	osr = mclk / 4 / params_rate(params) / 16;

Is there a specific reason as to why these magic numbers aren't 
defines/constants?

> +
> +	// stop LR / SCLK clocks

Formatting of this comment looks odd. Please align with the recommended one.


(...)


Regards,
Czarek

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3] ASoC: adds component driver for TAS575xM digital amplifiers
  2022-01-10  8:45   ` Joerg Schambacher
  (?)
@ 2022-01-12 18:42     ` kernel test robot
  -1 siblings, 0 replies; 21+ messages in thread
From: kernel test robot @ 2022-01-12 18:42 UTC (permalink / raw)
  To: Joerg Schambacher, alsa-devel; +Cc: llvm, kbuild-all, joerg, broonie

Hi Joerg,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on broonie-sound/for-next]
[also build test WARNING on v5.16 next-20220112]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Joerg-Schambacher/ASoC-adds-component-driver-for-TAS575xM-digital-amplifiers/20220110-164852
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
config: arm-randconfig-r034-20220112 (https://download.01.org/0day-ci/archive/20220113/202201130224.PtfT1pHZ-lkp@intel.com/config)
compiler: clang version 14.0.0 (https://github.com/llvm/llvm-project 244dd2913a43a200f5a6544d424cdc37b771028b)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install arm cross compiling tool for clang build
        # apt-get install binutils-arm-linux-gnueabi
        # https://github.com/0day-ci/linux/commit/194435492a87ace959d74aae1cecb27f16ad8966
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Joerg-Schambacher/ASoC-adds-component-driver-for-TAS575xM-digital-amplifiers/20220110-164852
        git checkout 194435492a87ace959d74aae1cecb27f16ad8966
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm SHELL=/bin/bash sound/soc/codecs/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> sound/soc/codecs/tas5754m.c:273:5: warning: no previous prototype for function 'tas5754m_set_clock_tree_master' [-Wmissing-prototypes]
   int tas5754m_set_clock_tree_master(struct snd_soc_dai *dai,
       ^
   sound/soc/codecs/tas5754m.c:273:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int tas5754m_set_clock_tree_master(struct snd_soc_dai *dai,
   ^
   static 
>> sound/soc/codecs/tas5754m.c:346:5: warning: no previous prototype for function 'tas5754m_set_dai_mode' [-Wmissing-prototypes]
   int tas5754m_set_dai_mode(struct snd_soc_dai *dai)
       ^
   sound/soc/codecs/tas5754m.c:346:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int tas5754m_set_dai_mode(struct snd_soc_dai *dai)
   ^
   static 
>> sound/soc/codecs/tas5754m.c:417:23: warning: converting the result of '<<' to a boolean always evaluates to true [-Wtautological-constant-compare]
                                   !TAS5754M_RLRK | !TAS5754M_RBCK,
                                                     ^
   sound/soc/codecs/tas5754m.h:145:32: note: expanded from macro 'TAS5754M_RBCK'
   #define TAS5754M_RBCK       (1 << 1)
                                  ^
   sound/soc/codecs/tas5754m.c:417:6: warning: converting the result of '<<' to a boolean always evaluates to true [-Wtautological-constant-compare]
                                   !TAS5754M_RLRK | !TAS5754M_RBCK,
                                    ^
   sound/soc/codecs/tas5754m.h:143:32: note: expanded from macro 'TAS5754M_RLRK'
   #define TAS5754M_RLRK       (1 << 0)
                                  ^
>> sound/soc/codecs/tas5754m.c:395:5: warning: no previous prototype for function 'tas5754m_set_dividers_master' [-Wmissing-prototypes]
   int tas5754m_set_dividers_master(struct snd_soc_dai *dai,
       ^
   sound/soc/codecs/tas5754m.c:395:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int tas5754m_set_dividers_master(struct snd_soc_dai *dai,
   ^
   static 
>> sound/soc/codecs/tas5754m.c:608:6: warning: variable 'ret' is uninitialized when used here [-Wuninitialized]
           if (ret != 0) {
               ^~~
   sound/soc/codecs/tas5754m.c:597:9: note: initialize the variable 'ret' to silence this warning
           int ret;
                  ^
                   = 0
   6 warnings generated.


vim +/tas5754m_set_clock_tree_master +273 sound/soc/codecs/tas5754m.c

   272	
 > 273	int tas5754m_set_clock_tree_master(struct snd_soc_dai *dai,
   274						struct snd_pcm_hw_params *params)
   275	{
   276		struct snd_soc_component *component = dai->component;
   277		struct tas5754m_priv *tas5754m =
   278				snd_soc_component_get_drvdata(component);
   279		static const struct reg_sequence pll_settings[] = {
   280			{ TAS5754M_PLL_COEFF_P,		0x01 },	// P=2
   281			{ TAS5754M_PLL_COEFF_J,		0x08 },	// J=8
   282			{ TAS5754M_PLL_COEFF_DL,	0x00 },	// D12-8 = 0
   283			{ TAS5754M_PLL_COEFF_DH,	0x00 },	// D7-0 = 0
   284			{ TAS5754M_PLL_COEFF_R,		0x00 },	// R=1
   285		};
   286		int ret;
   287	
   288		/* disable PLL before any clock tree change */
   289		ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
   290					 TAS5754M_PLLE, 0);
   291		if (ret != 0) {
   292			dev_err(component->dev, "Failed to disable PLL: %d\n", ret);
   293			return ret;
   294		}
   295	
   296		/* set DAC clock source to MCLK */
   297		ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_REF, 0x30);
   298		if (ret != 0) {
   299			dev_err(component->dev, "Failed to set DAC ref\n");
   300			return ret;
   301		}
   302	
   303		/* run PLL at fixed ratio to MCLK */
   304		ret = regmap_multi_reg_write(tas5754m->regmap, pll_settings,
   305						ARRAY_SIZE(pll_settings));
   306		if (ret != 0) {
   307			dev_err(component->dev, "Failed to set PLL ratio\n");
   308			return ret;
   309		}
   310	
   311		/* set DSP divider to 2 => reg 0x01 */
   312		ret = regmap_write(tas5754m->regmap, TAS5754M_DSP_CLKDIV, 1);
   313		if (ret != 0) {
   314			dev_err(component->dev, "Failed to set DSP divider\n");
   315			return ret;
   316		}
   317		/* set DAC divider to 4 => reg 0x03*/
   318		ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_CLKDIV, 3);
   319		if (ret != 0) {
   320			dev_err(component->dev, "Failed to set OSDACR divider\n");
   321			return ret;
   322		}
   323		/* set OSR divider to 1 */
   324		ret = regmap_write(tas5754m->regmap, TAS5754M_OSR_CLKDIV, 0);
   325		if (ret != 0) {
   326			dev_err(component->dev, "Failed to set OSR divider\n");
   327			return ret;
   328		}
   329		/* set CP divider to 4 => reg 0x03*/
   330		ret = regmap_write(tas5754m->regmap, TAS5754M_NCP_CLKDIV, 3);
   331		if (ret != 0) {
   332			dev_err(component->dev, "Failed to set CP divider\n");
   333			return ret;
   334		}
   335		/* finally enable PLL */
   336		ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
   337					 TAS5754M_PLLE, 1);
   338		if (ret != 0) {
   339			dev_err(component->dev, "Failed to enable PLL: %d\n", ret);
   340			return ret;
   341		}
   342	
   343		return 0;
   344	}
   345	
 > 346	int tas5754m_set_dai_mode(struct snd_soc_dai *dai)
   347	{
   348		struct snd_soc_component *component = dai->component;
   349		struct tas5754m_priv *tas5754m =
   350				snd_soc_component_get_drvdata(component);
   351		int fmt = tas5754m->fmt;
   352	
   353		/* only I2S MASTER mode implemented */
   354		if (((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S)) {
   355			dev_err(component->dev,
   356				"DAI format not supported (I2S master only)\n");
   357			return -EINVAL;
   358		}
   359		/* TAS5754/6m do not support inverted clocks in MASTER mode */
   360		if (((fmt & SND_SOC_DAIFMT_CLOCK_MASK) != SND_SOC_DAIFMT_NB_NF)) {
   361			dev_err(component->dev,	"Inverted clocks not supported\n");
   362			return -EINVAL;
   363		}
   364	
   365		switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
   366		case SND_SOC_DAIFMT_CBM_CFM:
   367			regmap_update_bits(tas5754m->regmap,
   368					TAS5754M_BCLK_LRCLK_CFG,
   369					TAS5754M_LRKO | TAS5754M_BCKO,
   370					TAS5754M_LRKO | TAS5754M_BCKO);
   371			/* reset CLK dividers */
   372			regmap_update_bits(tas5754m->regmap,
   373					TAS5754M_MASTER_MODE,
   374					0x00,
   375					TAS5754M_RLRK | TAS5754M_RBCK);
   376			/* ignore all clock error detection but MCLK */
   377			regmap_update_bits(tas5754m->regmap,
   378					TAS5754M_ERROR_DETECT,
   379					TAS5754M_IPLK | TAS5754M_DCAS |
   380					TAS5754M_IDCM | TAS5754M_IDSK |
   381					TAS5754M_IDBK | TAS5754M_IDFS,
   382					TAS5754M_IPLK | TAS5754M_DCAS |
   383					TAS5754M_IDCM | TAS5754M_IDSK |
   384					TAS5754M_IDBK | TAS5754M_IDFS);
   385			break;
   386		case SND_SOC_DAIFMT_CBS_CFS:
   387		case SND_SOC_DAIFMT_CBM_CFS:
   388		default:
   389			return -EINVAL;
   390		}
   391	
   392		return 0;
   393	}
   394	
 > 395	int tas5754m_set_dividers_master(struct snd_soc_dai *dai,
   396					struct snd_pcm_hw_params *params)
   397	{
   398		struct snd_soc_component *component = dai->component;
   399		struct tas5754m_priv *tas5754m =
   400				snd_soc_component_get_drvdata(component);
   401		unsigned long bclk;
   402		unsigned long mclk;
   403		int bclk_div;
   404		int lrclk_div;
   405		int osr;
   406		int ret;
   407	
   408		mclk = clk_get_rate(tas5754m->sclk);
   409		bclk = tas5754m->sample_len * 2 * params_rate(params);
   410		bclk_div = mclk / bclk;
   411		lrclk_div = tas5754m->sample_len * 2;
   412		osr = mclk / 4 / params_rate(params) / 16;
   413	
   414		// stop LR / SCLK clocks
   415		ret = regmap_update_bits(tas5754m->regmap,
   416					TAS5754M_MASTER_MODE,
 > 417					!TAS5754M_RLRK | !TAS5754M_RBCK,
   418					TAS5754M_RLRK | TAS5754M_RBCK);
   419		if (ret != 0) {
   420			dev_err(component->dev, "Failed to stop PLL\n");
   421			return ret;
   422		}
   423	
   424		// set SCLK divider
   425		ret = regmap_write(tas5754m->regmap, TAS5754M_MASTER_SCLKDIV,
   426									bclk_div - 1);
   427		if (ret != 0) {
   428			dev_err(component->dev, "Failed to set SCLK divider\n");
   429			return ret;
   430		}
   431	
   432		// set LRCLK divider
   433		ret = regmap_write(tas5754m->regmap, TAS5754M_MASTER_LRCLKDIV,
   434									lrclk_div - 1);
   435		if (ret != 0) {
   436			dev_err(component->dev, "Failed to set LRCLK divider\n");
   437			return ret;
   438		}
   439	
   440		ret = regmap_write(tas5754m->regmap,
   441			TAS5754M_OSR_CLKDIV, osr - 1);
   442		if (ret != 0) {
   443			dev_err(component->dev, "Failed to set OSR divider\n");
   444			return ret;
   445		}
   446	
   447		// restart LR / SCLK clocks
   448		ret = regmap_update_bits(tas5754m->regmap,
   449					TAS5754M_MASTER_MODE,
   450					TAS5754M_RLRK | TAS5754M_RBCK,
   451					TAS5754M_RLRK | TAS5754M_RBCK);
   452		if (ret != 0) {
   453			dev_err(component->dev, "Failed to restart PLL\n");
   454			return ret;
   455		}
   456	
   457		return 0;
   458	}
   459	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3] ASoC: adds component driver for TAS575xM digital amplifiers
@ 2022-01-12 18:42     ` kernel test robot
  0 siblings, 0 replies; 21+ messages in thread
From: kernel test robot @ 2022-01-12 18:42 UTC (permalink / raw)
  To: Joerg Schambacher, alsa-devel; +Cc: joerg, llvm, kbuild-all, broonie

Hi Joerg,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on broonie-sound/for-next]
[also build test WARNING on v5.16 next-20220112]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Joerg-Schambacher/ASoC-adds-component-driver-for-TAS575xM-digital-amplifiers/20220110-164852
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
config: arm-randconfig-r034-20220112 (https://download.01.org/0day-ci/archive/20220113/202201130224.PtfT1pHZ-lkp@intel.com/config)
compiler: clang version 14.0.0 (https://github.com/llvm/llvm-project 244dd2913a43a200f5a6544d424cdc37b771028b)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install arm cross compiling tool for clang build
        # apt-get install binutils-arm-linux-gnueabi
        # https://github.com/0day-ci/linux/commit/194435492a87ace959d74aae1cecb27f16ad8966
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Joerg-Schambacher/ASoC-adds-component-driver-for-TAS575xM-digital-amplifiers/20220110-164852
        git checkout 194435492a87ace959d74aae1cecb27f16ad8966
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm SHELL=/bin/bash sound/soc/codecs/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> sound/soc/codecs/tas5754m.c:273:5: warning: no previous prototype for function 'tas5754m_set_clock_tree_master' [-Wmissing-prototypes]
   int tas5754m_set_clock_tree_master(struct snd_soc_dai *dai,
       ^
   sound/soc/codecs/tas5754m.c:273:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int tas5754m_set_clock_tree_master(struct snd_soc_dai *dai,
   ^
   static 
>> sound/soc/codecs/tas5754m.c:346:5: warning: no previous prototype for function 'tas5754m_set_dai_mode' [-Wmissing-prototypes]
   int tas5754m_set_dai_mode(struct snd_soc_dai *dai)
       ^
   sound/soc/codecs/tas5754m.c:346:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int tas5754m_set_dai_mode(struct snd_soc_dai *dai)
   ^
   static 
>> sound/soc/codecs/tas5754m.c:417:23: warning: converting the result of '<<' to a boolean always evaluates to true [-Wtautological-constant-compare]
                                   !TAS5754M_RLRK | !TAS5754M_RBCK,
                                                     ^
   sound/soc/codecs/tas5754m.h:145:32: note: expanded from macro 'TAS5754M_RBCK'
   #define TAS5754M_RBCK       (1 << 1)
                                  ^
   sound/soc/codecs/tas5754m.c:417:6: warning: converting the result of '<<' to a boolean always evaluates to true [-Wtautological-constant-compare]
                                   !TAS5754M_RLRK | !TAS5754M_RBCK,
                                    ^
   sound/soc/codecs/tas5754m.h:143:32: note: expanded from macro 'TAS5754M_RLRK'
   #define TAS5754M_RLRK       (1 << 0)
                                  ^
>> sound/soc/codecs/tas5754m.c:395:5: warning: no previous prototype for function 'tas5754m_set_dividers_master' [-Wmissing-prototypes]
   int tas5754m_set_dividers_master(struct snd_soc_dai *dai,
       ^
   sound/soc/codecs/tas5754m.c:395:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int tas5754m_set_dividers_master(struct snd_soc_dai *dai,
   ^
   static 
>> sound/soc/codecs/tas5754m.c:608:6: warning: variable 'ret' is uninitialized when used here [-Wuninitialized]
           if (ret != 0) {
               ^~~
   sound/soc/codecs/tas5754m.c:597:9: note: initialize the variable 'ret' to silence this warning
           int ret;
                  ^
                   = 0
   6 warnings generated.


vim +/tas5754m_set_clock_tree_master +273 sound/soc/codecs/tas5754m.c

   272	
 > 273	int tas5754m_set_clock_tree_master(struct snd_soc_dai *dai,
   274						struct snd_pcm_hw_params *params)
   275	{
   276		struct snd_soc_component *component = dai->component;
   277		struct tas5754m_priv *tas5754m =
   278				snd_soc_component_get_drvdata(component);
   279		static const struct reg_sequence pll_settings[] = {
   280			{ TAS5754M_PLL_COEFF_P,		0x01 },	// P=2
   281			{ TAS5754M_PLL_COEFF_J,		0x08 },	// J=8
   282			{ TAS5754M_PLL_COEFF_DL,	0x00 },	// D12-8 = 0
   283			{ TAS5754M_PLL_COEFF_DH,	0x00 },	// D7-0 = 0
   284			{ TAS5754M_PLL_COEFF_R,		0x00 },	// R=1
   285		};
   286		int ret;
   287	
   288		/* disable PLL before any clock tree change */
   289		ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
   290					 TAS5754M_PLLE, 0);
   291		if (ret != 0) {
   292			dev_err(component->dev, "Failed to disable PLL: %d\n", ret);
   293			return ret;
   294		}
   295	
   296		/* set DAC clock source to MCLK */
   297		ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_REF, 0x30);
   298		if (ret != 0) {
   299			dev_err(component->dev, "Failed to set DAC ref\n");
   300			return ret;
   301		}
   302	
   303		/* run PLL at fixed ratio to MCLK */
   304		ret = regmap_multi_reg_write(tas5754m->regmap, pll_settings,
   305						ARRAY_SIZE(pll_settings));
   306		if (ret != 0) {
   307			dev_err(component->dev, "Failed to set PLL ratio\n");
   308			return ret;
   309		}
   310	
   311		/* set DSP divider to 2 => reg 0x01 */
   312		ret = regmap_write(tas5754m->regmap, TAS5754M_DSP_CLKDIV, 1);
   313		if (ret != 0) {
   314			dev_err(component->dev, "Failed to set DSP divider\n");
   315			return ret;
   316		}
   317		/* set DAC divider to 4 => reg 0x03*/
   318		ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_CLKDIV, 3);
   319		if (ret != 0) {
   320			dev_err(component->dev, "Failed to set OSDACR divider\n");
   321			return ret;
   322		}
   323		/* set OSR divider to 1 */
   324		ret = regmap_write(tas5754m->regmap, TAS5754M_OSR_CLKDIV, 0);
   325		if (ret != 0) {
   326			dev_err(component->dev, "Failed to set OSR divider\n");
   327			return ret;
   328		}
   329		/* set CP divider to 4 => reg 0x03*/
   330		ret = regmap_write(tas5754m->regmap, TAS5754M_NCP_CLKDIV, 3);
   331		if (ret != 0) {
   332			dev_err(component->dev, "Failed to set CP divider\n");
   333			return ret;
   334		}
   335		/* finally enable PLL */
   336		ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
   337					 TAS5754M_PLLE, 1);
   338		if (ret != 0) {
   339			dev_err(component->dev, "Failed to enable PLL: %d\n", ret);
   340			return ret;
   341		}
   342	
   343		return 0;
   344	}
   345	
 > 346	int tas5754m_set_dai_mode(struct snd_soc_dai *dai)
   347	{
   348		struct snd_soc_component *component = dai->component;
   349		struct tas5754m_priv *tas5754m =
   350				snd_soc_component_get_drvdata(component);
   351		int fmt = tas5754m->fmt;
   352	
   353		/* only I2S MASTER mode implemented */
   354		if (((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S)) {
   355			dev_err(component->dev,
   356				"DAI format not supported (I2S master only)\n");
   357			return -EINVAL;
   358		}
   359		/* TAS5754/6m do not support inverted clocks in MASTER mode */
   360		if (((fmt & SND_SOC_DAIFMT_CLOCK_MASK) != SND_SOC_DAIFMT_NB_NF)) {
   361			dev_err(component->dev,	"Inverted clocks not supported\n");
   362			return -EINVAL;
   363		}
   364	
   365		switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
   366		case SND_SOC_DAIFMT_CBM_CFM:
   367			regmap_update_bits(tas5754m->regmap,
   368					TAS5754M_BCLK_LRCLK_CFG,
   369					TAS5754M_LRKO | TAS5754M_BCKO,
   370					TAS5754M_LRKO | TAS5754M_BCKO);
   371			/* reset CLK dividers */
   372			regmap_update_bits(tas5754m->regmap,
   373					TAS5754M_MASTER_MODE,
   374					0x00,
   375					TAS5754M_RLRK | TAS5754M_RBCK);
   376			/* ignore all clock error detection but MCLK */
   377			regmap_update_bits(tas5754m->regmap,
   378					TAS5754M_ERROR_DETECT,
   379					TAS5754M_IPLK | TAS5754M_DCAS |
   380					TAS5754M_IDCM | TAS5754M_IDSK |
   381					TAS5754M_IDBK | TAS5754M_IDFS,
   382					TAS5754M_IPLK | TAS5754M_DCAS |
   383					TAS5754M_IDCM | TAS5754M_IDSK |
   384					TAS5754M_IDBK | TAS5754M_IDFS);
   385			break;
   386		case SND_SOC_DAIFMT_CBS_CFS:
   387		case SND_SOC_DAIFMT_CBM_CFS:
   388		default:
   389			return -EINVAL;
   390		}
   391	
   392		return 0;
   393	}
   394	
 > 395	int tas5754m_set_dividers_master(struct snd_soc_dai *dai,
   396					struct snd_pcm_hw_params *params)
   397	{
   398		struct snd_soc_component *component = dai->component;
   399		struct tas5754m_priv *tas5754m =
   400				snd_soc_component_get_drvdata(component);
   401		unsigned long bclk;
   402		unsigned long mclk;
   403		int bclk_div;
   404		int lrclk_div;
   405		int osr;
   406		int ret;
   407	
   408		mclk = clk_get_rate(tas5754m->sclk);
   409		bclk = tas5754m->sample_len * 2 * params_rate(params);
   410		bclk_div = mclk / bclk;
   411		lrclk_div = tas5754m->sample_len * 2;
   412		osr = mclk / 4 / params_rate(params) / 16;
   413	
   414		// stop LR / SCLK clocks
   415		ret = regmap_update_bits(tas5754m->regmap,
   416					TAS5754M_MASTER_MODE,
 > 417					!TAS5754M_RLRK | !TAS5754M_RBCK,
   418					TAS5754M_RLRK | TAS5754M_RBCK);
   419		if (ret != 0) {
   420			dev_err(component->dev, "Failed to stop PLL\n");
   421			return ret;
   422		}
   423	
   424		// set SCLK divider
   425		ret = regmap_write(tas5754m->regmap, TAS5754M_MASTER_SCLKDIV,
   426									bclk_div - 1);
   427		if (ret != 0) {
   428			dev_err(component->dev, "Failed to set SCLK divider\n");
   429			return ret;
   430		}
   431	
   432		// set LRCLK divider
   433		ret = regmap_write(tas5754m->regmap, TAS5754M_MASTER_LRCLKDIV,
   434									lrclk_div - 1);
   435		if (ret != 0) {
   436			dev_err(component->dev, "Failed to set LRCLK divider\n");
   437			return ret;
   438		}
   439	
   440		ret = regmap_write(tas5754m->regmap,
   441			TAS5754M_OSR_CLKDIV, osr - 1);
   442		if (ret != 0) {
   443			dev_err(component->dev, "Failed to set OSR divider\n");
   444			return ret;
   445		}
   446	
   447		// restart LR / SCLK clocks
   448		ret = regmap_update_bits(tas5754m->regmap,
   449					TAS5754M_MASTER_MODE,
   450					TAS5754M_RLRK | TAS5754M_RBCK,
   451					TAS5754M_RLRK | TAS5754M_RBCK);
   452		if (ret != 0) {
   453			dev_err(component->dev, "Failed to restart PLL\n");
   454			return ret;
   455		}
   456	
   457		return 0;
   458	}
   459	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3] ASoC: adds component driver for TAS575xM digital amplifiers
@ 2022-01-12 18:42     ` kernel test robot
  0 siblings, 0 replies; 21+ messages in thread
From: kernel test robot @ 2022-01-12 18:42 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 11238 bytes --]

Hi Joerg,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on broonie-sound/for-next]
[also build test WARNING on v5.16 next-20220112]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Joerg-Schambacher/ASoC-adds-component-driver-for-TAS575xM-digital-amplifiers/20220110-164852
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
config: arm-randconfig-r034-20220112 (https://download.01.org/0day-ci/archive/20220113/202201130224.PtfT1pHZ-lkp(a)intel.com/config)
compiler: clang version 14.0.0 (https://github.com/llvm/llvm-project 244dd2913a43a200f5a6544d424cdc37b771028b)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install arm cross compiling tool for clang build
        # apt-get install binutils-arm-linux-gnueabi
        # https://github.com/0day-ci/linux/commit/194435492a87ace959d74aae1cecb27f16ad8966
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Joerg-Schambacher/ASoC-adds-component-driver-for-TAS575xM-digital-amplifiers/20220110-164852
        git checkout 194435492a87ace959d74aae1cecb27f16ad8966
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm SHELL=/bin/bash sound/soc/codecs/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> sound/soc/codecs/tas5754m.c:273:5: warning: no previous prototype for function 'tas5754m_set_clock_tree_master' [-Wmissing-prototypes]
   int tas5754m_set_clock_tree_master(struct snd_soc_dai *dai,
       ^
   sound/soc/codecs/tas5754m.c:273:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int tas5754m_set_clock_tree_master(struct snd_soc_dai *dai,
   ^
   static 
>> sound/soc/codecs/tas5754m.c:346:5: warning: no previous prototype for function 'tas5754m_set_dai_mode' [-Wmissing-prototypes]
   int tas5754m_set_dai_mode(struct snd_soc_dai *dai)
       ^
   sound/soc/codecs/tas5754m.c:346:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int tas5754m_set_dai_mode(struct snd_soc_dai *dai)
   ^
   static 
>> sound/soc/codecs/tas5754m.c:417:23: warning: converting the result of '<<' to a boolean always evaluates to true [-Wtautological-constant-compare]
                                   !TAS5754M_RLRK | !TAS5754M_RBCK,
                                                     ^
   sound/soc/codecs/tas5754m.h:145:32: note: expanded from macro 'TAS5754M_RBCK'
   #define TAS5754M_RBCK       (1 << 1)
                                  ^
   sound/soc/codecs/tas5754m.c:417:6: warning: converting the result of '<<' to a boolean always evaluates to true [-Wtautological-constant-compare]
                                   !TAS5754M_RLRK | !TAS5754M_RBCK,
                                    ^
   sound/soc/codecs/tas5754m.h:143:32: note: expanded from macro 'TAS5754M_RLRK'
   #define TAS5754M_RLRK       (1 << 0)
                                  ^
>> sound/soc/codecs/tas5754m.c:395:5: warning: no previous prototype for function 'tas5754m_set_dividers_master' [-Wmissing-prototypes]
   int tas5754m_set_dividers_master(struct snd_soc_dai *dai,
       ^
   sound/soc/codecs/tas5754m.c:395:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int tas5754m_set_dividers_master(struct snd_soc_dai *dai,
   ^
   static 
>> sound/soc/codecs/tas5754m.c:608:6: warning: variable 'ret' is uninitialized when used here [-Wuninitialized]
           if (ret != 0) {
               ^~~
   sound/soc/codecs/tas5754m.c:597:9: note: initialize the variable 'ret' to silence this warning
           int ret;
                  ^
                   = 0
   6 warnings generated.


vim +/tas5754m_set_clock_tree_master +273 sound/soc/codecs/tas5754m.c

   272	
 > 273	int tas5754m_set_clock_tree_master(struct snd_soc_dai *dai,
   274						struct snd_pcm_hw_params *params)
   275	{
   276		struct snd_soc_component *component = dai->component;
   277		struct tas5754m_priv *tas5754m =
   278				snd_soc_component_get_drvdata(component);
   279		static const struct reg_sequence pll_settings[] = {
   280			{ TAS5754M_PLL_COEFF_P,		0x01 },	// P=2
   281			{ TAS5754M_PLL_COEFF_J,		0x08 },	// J=8
   282			{ TAS5754M_PLL_COEFF_DL,	0x00 },	// D12-8 = 0
   283			{ TAS5754M_PLL_COEFF_DH,	0x00 },	// D7-0 = 0
   284			{ TAS5754M_PLL_COEFF_R,		0x00 },	// R=1
   285		};
   286		int ret;
   287	
   288		/* disable PLL before any clock tree change */
   289		ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
   290					 TAS5754M_PLLE, 0);
   291		if (ret != 0) {
   292			dev_err(component->dev, "Failed to disable PLL: %d\n", ret);
   293			return ret;
   294		}
   295	
   296		/* set DAC clock source to MCLK */
   297		ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_REF, 0x30);
   298		if (ret != 0) {
   299			dev_err(component->dev, "Failed to set DAC ref\n");
   300			return ret;
   301		}
   302	
   303		/* run PLL at fixed ratio to MCLK */
   304		ret = regmap_multi_reg_write(tas5754m->regmap, pll_settings,
   305						ARRAY_SIZE(pll_settings));
   306		if (ret != 0) {
   307			dev_err(component->dev, "Failed to set PLL ratio\n");
   308			return ret;
   309		}
   310	
   311		/* set DSP divider to 2 => reg 0x01 */
   312		ret = regmap_write(tas5754m->regmap, TAS5754M_DSP_CLKDIV, 1);
   313		if (ret != 0) {
   314			dev_err(component->dev, "Failed to set DSP divider\n");
   315			return ret;
   316		}
   317		/* set DAC divider to 4 => reg 0x03*/
   318		ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_CLKDIV, 3);
   319		if (ret != 0) {
   320			dev_err(component->dev, "Failed to set OSDACR divider\n");
   321			return ret;
   322		}
   323		/* set OSR divider to 1 */
   324		ret = regmap_write(tas5754m->regmap, TAS5754M_OSR_CLKDIV, 0);
   325		if (ret != 0) {
   326			dev_err(component->dev, "Failed to set OSR divider\n");
   327			return ret;
   328		}
   329		/* set CP divider to 4 => reg 0x03*/
   330		ret = regmap_write(tas5754m->regmap, TAS5754M_NCP_CLKDIV, 3);
   331		if (ret != 0) {
   332			dev_err(component->dev, "Failed to set CP divider\n");
   333			return ret;
   334		}
   335		/* finally enable PLL */
   336		ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
   337					 TAS5754M_PLLE, 1);
   338		if (ret != 0) {
   339			dev_err(component->dev, "Failed to enable PLL: %d\n", ret);
   340			return ret;
   341		}
   342	
   343		return 0;
   344	}
   345	
 > 346	int tas5754m_set_dai_mode(struct snd_soc_dai *dai)
   347	{
   348		struct snd_soc_component *component = dai->component;
   349		struct tas5754m_priv *tas5754m =
   350				snd_soc_component_get_drvdata(component);
   351		int fmt = tas5754m->fmt;
   352	
   353		/* only I2S MASTER mode implemented */
   354		if (((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S)) {
   355			dev_err(component->dev,
   356				"DAI format not supported (I2S master only)\n");
   357			return -EINVAL;
   358		}
   359		/* TAS5754/6m do not support inverted clocks in MASTER mode */
   360		if (((fmt & SND_SOC_DAIFMT_CLOCK_MASK) != SND_SOC_DAIFMT_NB_NF)) {
   361			dev_err(component->dev,	"Inverted clocks not supported\n");
   362			return -EINVAL;
   363		}
   364	
   365		switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
   366		case SND_SOC_DAIFMT_CBM_CFM:
   367			regmap_update_bits(tas5754m->regmap,
   368					TAS5754M_BCLK_LRCLK_CFG,
   369					TAS5754M_LRKO | TAS5754M_BCKO,
   370					TAS5754M_LRKO | TAS5754M_BCKO);
   371			/* reset CLK dividers */
   372			regmap_update_bits(tas5754m->regmap,
   373					TAS5754M_MASTER_MODE,
   374					0x00,
   375					TAS5754M_RLRK | TAS5754M_RBCK);
   376			/* ignore all clock error detection but MCLK */
   377			regmap_update_bits(tas5754m->regmap,
   378					TAS5754M_ERROR_DETECT,
   379					TAS5754M_IPLK | TAS5754M_DCAS |
   380					TAS5754M_IDCM | TAS5754M_IDSK |
   381					TAS5754M_IDBK | TAS5754M_IDFS,
   382					TAS5754M_IPLK | TAS5754M_DCAS |
   383					TAS5754M_IDCM | TAS5754M_IDSK |
   384					TAS5754M_IDBK | TAS5754M_IDFS);
   385			break;
   386		case SND_SOC_DAIFMT_CBS_CFS:
   387		case SND_SOC_DAIFMT_CBM_CFS:
   388		default:
   389			return -EINVAL;
   390		}
   391	
   392		return 0;
   393	}
   394	
 > 395	int tas5754m_set_dividers_master(struct snd_soc_dai *dai,
   396					struct snd_pcm_hw_params *params)
   397	{
   398		struct snd_soc_component *component = dai->component;
   399		struct tas5754m_priv *tas5754m =
   400				snd_soc_component_get_drvdata(component);
   401		unsigned long bclk;
   402		unsigned long mclk;
   403		int bclk_div;
   404		int lrclk_div;
   405		int osr;
   406		int ret;
   407	
   408		mclk = clk_get_rate(tas5754m->sclk);
   409		bclk = tas5754m->sample_len * 2 * params_rate(params);
   410		bclk_div = mclk / bclk;
   411		lrclk_div = tas5754m->sample_len * 2;
   412		osr = mclk / 4 / params_rate(params) / 16;
   413	
   414		// stop LR / SCLK clocks
   415		ret = regmap_update_bits(tas5754m->regmap,
   416					TAS5754M_MASTER_MODE,
 > 417					!TAS5754M_RLRK | !TAS5754M_RBCK,
   418					TAS5754M_RLRK | TAS5754M_RBCK);
   419		if (ret != 0) {
   420			dev_err(component->dev, "Failed to stop PLL\n");
   421			return ret;
   422		}
   423	
   424		// set SCLK divider
   425		ret = regmap_write(tas5754m->regmap, TAS5754M_MASTER_SCLKDIV,
   426									bclk_div - 1);
   427		if (ret != 0) {
   428			dev_err(component->dev, "Failed to set SCLK divider\n");
   429			return ret;
   430		}
   431	
   432		// set LRCLK divider
   433		ret = regmap_write(tas5754m->regmap, TAS5754M_MASTER_LRCLKDIV,
   434									lrclk_div - 1);
   435		if (ret != 0) {
   436			dev_err(component->dev, "Failed to set LRCLK divider\n");
   437			return ret;
   438		}
   439	
   440		ret = regmap_write(tas5754m->regmap,
   441			TAS5754M_OSR_CLKDIV, osr - 1);
   442		if (ret != 0) {
   443			dev_err(component->dev, "Failed to set OSR divider\n");
   444			return ret;
   445		}
   446	
   447		// restart LR / SCLK clocks
   448		ret = regmap_update_bits(tas5754m->regmap,
   449					TAS5754M_MASTER_MODE,
   450					TAS5754M_RLRK | TAS5754M_RBCK,
   451					TAS5754M_RLRK | TAS5754M_RBCK);
   452		if (ret != 0) {
   453			dev_err(component->dev, "Failed to restart PLL\n");
   454			return ret;
   455		}
   456	
   457		return 0;
   458	}
   459	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2] sound/soc: adds TAS5754M digital input amplifier component driver
       [not found] <20211029095414.29131-1-joerg@hifiberry.com>
@ 2022-01-19 12:50   ` Joerg Schambacher
  2022-01-10  8:45   ` Joerg Schambacher
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 21+ messages in thread
From: Joerg Schambacher @ 2022-01-19 12:50 UTC (permalink / raw)
  To: Mark Brown, alsa-devel; +Cc: joerg, kbuild-all

Mark,

Thanks for your useful feedback. I guess my comments on my first reply got lost somewhere on the way ....

I've updated and fixed some other issues meanwhile, too.

Joerg

On Wed, Nov 17, 2021 at 03:13:47PM +0000, Mark Brown wrote:
> On Fri, Oct 29, 2021 at 11:57:30AM +0200, Joerg Schambacher wrote:
> 
> > Adds a minimum component driver to run the amplifier in I2S master
> > mode only from standard audio clocks. Therefore, it only allows
> > 44.1, 88.2, 176.4, 48, 96 and 192ksps with 16, 20, 24 and 32 bits
> > sample size. Digital volume control and the -6dB switch are supported.
> 
> This looks pretty clean, there's a bunch of minor stylistic bits below
> but other than one major thing this looks good.  The major thing is the
> use of a had coded init sequence to configure the device rather than
> implemenenting the relevant APIs to do so, that's going to make the
> driver unsuitable for use on boards other than the specific one you
> happen to be looking at at the minute.
> 
> Please submit patches using subject lines reflecting the style for the
> subsystem, this makes it easier for people to identify relevant patches.
> Look at what existing commits in the area you're changing are doing and
> make sure your subject lines visually resemble what they're doing.
> 
> > @@ -0,0 +1,547 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Driver for the TAS5754M Audio Amplifier in Master mode (only)
> > + * supports only standard audio frequencies 44.1 to 192 ksps
> 
> Please make the entire comment a C++ one so things look more
> intentional.
> 
> > +EXPORT_SYMBOL_GPL(tas5754m_regmap);
> 
yes, remainder from some experiments - fixed

> There's only one file in the driver, why is this exported?
> 
> > +	mclk = clk_get_rate(tas5754m->sclk);
> > +	bclk = sample_len * 2 * params_rate(params);
> 
> snd_soc_params_to_bclk().
snd_soc_params_to_bclk() does not always gives the necessary value

> 
> > +	// set SCLK divider
> > +	ret |= regmap_write(tas5754m->regmap, TAS5754M_MASTER_CLKDIV_1,
> > +								bclk_div - 1);
> > +
> > +	// set LRCLK divider
> > +	ret |= regmap_write(tas5754m->regmap, TAS5754M_MASTER_CLKDIV_2,
> > +								lrclk_div - 1);
> 
Fixed

> Check the return statuses individually or just don't bother, if you or
> them together then you could end up with a nonsensical error code which
> could cause confusion down the line.
> 
> > +	if (mute) {
> > +		snd_soc_component_write(component, TAS5754M_MUTE, 0x11);
> > +	} else {
> > +		usleep_range(1000, 2000);
> > +		snd_soc_component_write(component, TAS5754M_MUTE, 0x00);
> 
> Why the sleep here?
Wait for settling of the clocks before unmute

> 
> > +	ret = regmap_multi_reg_write(regmap, tas5754m_init_sequence,
> > +					ARRAY_SIZE(tas5754m_init_sequence));
> 
> This init sequence looks an awful lot like it's doing board specific
> configuration - it's enabling the PLL, configuring GPIOs and clock
> dividers among other things.  These should all be done through board
> specific configuration or based on the currently configured audio path,
> what's suitable for one board may not be suitable for another board.
> Doing a reset of the chip is good but the rest of it really looks like
> it doesn't belong.
Ok, completely re-organized in the next trial

> 
> > +	ret = snd_soc_register_component(dev,
> > +			&tas5754m_soc_component, &tas5754m_dai, 1);
> 
> devm_snd_soc_register_component()
> 
fixed

> > +static const struct i2c_device_id tas5754m_i2c_id[] = {
> > +	{ "tas5754m", },
> > +	{ }
> > +};
> > +MODULE_DEVICE_TABLE(i2c, tas5754m_i2c_id);
> > +
> > +#ifdef CONFIG_OF
> > +static const struct of_device_id tas5754m_of_match[] = {
> > +	{ .compatible = "ti,tas5754m", },
> > +	{ .compatible = "ti,tas5756m", },
> > +	{ }
> > +};
> > +MODULE_DEVICE_TABLE(of, tas5754m_of_match);
> > +#endif
> 
> Why not list both I2C IDs as well?
Fixed

> 
> > @@ -0,0 +1,259 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +/*
> > + * Driver for the TAS5754M DAC+amplifier combo devices
> > + *
> > + * Author:	(copied from pcm512x.h)
> > + *		Mark Brown <broonie@kernel.org>
> > + *		Copyright 2014 Linaro Ltd
> > + */
> 
> If the register map can be copied can't the two drivers be combined?
The TI apps team recommended to write a separate driver as there are some differences. I have also aligned some names to the TAS575xM spec in the next patch

> 
> > +#define TAS5754M_VIRT_BASE 0x000
> > +#define TAS5754M_PAGE_LEN  0x80
> > +#define TAS5754M_PAGE_BASE(n)  (TAS5754M_VIRT_BASE + (TAS5754M_PAGE_LEN * n))
> > +
> > +#define TAS5754M_PAGE              0
> 
> There's no mention of paging in the regmap description for the driver
> which feels like it's asking for problems.
I think, it's defined in the correct way. Where/when exactly do you see a problem?

> 
> > +
> > +#define TAS5754M_RESET             (TAS5754M_PAGE_BASE(0) +   1)
> > +#define TAS5754M_POWER             (TAS5754M_PAGE_BASE(0) +   2)
> > +#define TAS5754M_MUTE              (TAS5754M_PAGE_BASE(0) +   3)
> > +#define TAS5754M_PLL_EN            (TAS5754M_PAGE_BASE(0) +   4)
> > +#define TAS5754M_SPI_MISO_FUNCTION (TAS5754M_PAGE_BASE(0) +   6)
> > +#define TAS5754M_DSP               (TAS5754M_PAGE_BASE(0) +   7)
> > +#define TAS5754M_GPIO_EN           (TAS5754M_PAGE_BASE(0) +   8)
> > +#define TAS5754M_BCLK_LRCLK_CFG    (TAS5754M_PAGE_BASE(0) +   9)
> > +#define TAS5754M_DSP_GPIO_INPUT    (TAS5754M_PAGE_BASE(0) +  10)
> > +#define TAS5754M_MASTER_MODE       (TAS5754M_PAGE_BASE(0) +  12)
> > +#define TAS5754M_PLL_REF           (TAS5754M_PAGE_BASE(0) +  13)
> > +#define TAS5754M_DAC_REF           (TAS5754M_PAGE_BASE(0) +  14)
> > +#define TAS5754M_GPIO_DACIN        (TAS5754M_PAGE_BASE(0) +  16)
> > +#define TAS5754M_GPIO_PLLIN        (TAS5754M_PAGE_BASE(0) +  18)
> > +#define TAS5754M_SYNCHRONIZE       (TAS5754M_PAGE_BASE(0) +  19)
> > +#define TAS5754M_PLL_COEFF_0       (TAS5754M_PAGE_BASE(0) +  20)
> > +#define TAS5754M_PLL_COEFF_1       (TAS5754M_PAGE_BASE(0) +  21)
> > +#define TAS5754M_PLL_COEFF_2       (TAS5754M_PAGE_BASE(0) +  22)
> > +#define TAS5754M_PLL_COEFF_3       (TAS5754M_PAGE_BASE(0) +  23)
> > +#define TAS5754M_PLL_COEFF_4       (TAS5754M_PAGE_BASE(0) +  24)
> > +#define TAS5754M_DSP_CLKDIV        (TAS5754M_PAGE_BASE(0) +  27)
> > +#define TAS5754M_DAC_CLKDIV        (TAS5754M_PAGE_BASE(0) +  28)
> > +#define TAS5754M_NCP_CLKDIV        (TAS5754M_PAGE_BASE(0) +  29)
> > +#define TAS5754M_OSR_CLKDIV        (TAS5754M_PAGE_BASE(0) +  30)
> > +#define TAS5754M_MASTER_CLKDIV_1   (TAS5754M_PAGE_BASE(0) +  32)
> > +#define TAS5754M_MASTER_CLKDIV_2   (TAS5754M_PAGE_BASE(0) +  33)
> > +#define TAS5754M_FS_SPEED_MODE     (TAS5754M_PAGE_BASE(0) +  34)
> > +#define TAS5754M_IDAC_1            (TAS5754M_PAGE_BASE(0) +  35)
> > +#define TAS5754M_IDAC_2            (TAS5754M_PAGE_BASE(0) +  36)
> > +#define TAS5754M_ERROR_DETECT      (TAS5754M_PAGE_BASE(0) +  37)
> > +#define TAS5754M_I2S_1             (TAS5754M_PAGE_BASE(0) +  40)
> > +#define TAS5754M_I2S_2             (TAS5754M_PAGE_BASE(0) +  41)
> > +#define TAS5754M_DAC_ROUTING       (TAS5754M_PAGE_BASE(0) +  42)
> > +#define TAS5754M_DSP_PROGRAM       (TAS5754M_PAGE_BASE(0) +  43)
> > +#define TAS5754M_CLKDET            (TAS5754M_PAGE_BASE(0) +  44)
> > +#define TAS5754M_AUTO_MUTE         (TAS5754M_PAGE_BASE(0) +  59)
> > +#define TAS5754M_DIGITAL_VOLUME_1  (TAS5754M_PAGE_BASE(0) +  60)
> > +#define TAS5754M_DIGITAL_VOLUME_2  (TAS5754M_PAGE_BASE(0) +  61)
> > +#define TAS5754M_DIGITAL_VOLUME_3  (TAS5754M_PAGE_BASE(0) +  62)
> > +#define TAS5754M_DIGITAL_MUTE_1    (TAS5754M_PAGE_BASE(0) +  63)
> > +#define TAS5754M_DIGITAL_MUTE_2    (TAS5754M_PAGE_BASE(0) +  64)
> > +#define TAS5754M_DIGITAL_MUTE_3    (TAS5754M_PAGE_BASE(0) +  65)
> > +#define TAS5754M_GPIO_OUTPUT_1     (TAS5754M_PAGE_BASE(0) +  80)
> > +#define TAS5754M_GPIO_OUTPUT_2     (TAS5754M_PAGE_BASE(0) +  81)
> > +#define TAS5754M_GPIO_OUTPUT_3     (TAS5754M_PAGE_BASE(0) +  82)
> > +#define TAS5754M_GPIO_OUTPUT_4     (TAS5754M_PAGE_BASE(0) +  83)
> > +#define TAS5754M_GPIO_OUTPUT_5     (TAS5754M_PAGE_BASE(0) +  84)
> > +#define TAS5754M_GPIO_OUTPUT_6     (TAS5754M_PAGE_BASE(0) +  85)
> > +#define TAS5754M_GPIO_CONTROL_1    (TAS5754M_PAGE_BASE(0) +  86)
> > +#define TAS5754M_GPIO_CONTROL_2    (TAS5754M_PAGE_BASE(0) +  87)
> > +#define TAS5754M_OVERFLOW          (TAS5754M_PAGE_BASE(0) +  90)
> > +#define TAS5754M_RATE_DET_1        (TAS5754M_PAGE_BASE(0) +  91)
> > +#define TAS5754M_RATE_DET_2        (TAS5754M_PAGE_BASE(0) +  92)
> > +#define TAS5754M_RATE_DET_3        (TAS5754M_PAGE_BASE(0) +  93)
> > +#define TAS5754M_RATE_DET_4        (TAS5754M_PAGE_BASE(0) +  94)
> > +#define TAS5754M_CLOCK_STATUS      (TAS5754M_PAGE_BASE(0) +  95)
> > +#define TAS5754M_ANALOG_MUTE_DET   (TAS5754M_PAGE_BASE(0) + 108)
> > +#define TAS5754M_GPIN              (TAS5754M_PAGE_BASE(0) + 119)
> > +#define TAS5754M_DIGITAL_MUTE_DET  (TAS5754M_PAGE_BASE(0) + 120)
> > +
> > +#define TAS5754M_OUTPUT_AMPLITUDE  (TAS5754M_PAGE_BASE(1) +   1)
> > +#define TAS5754M_ANALOG_GAIN_CTRL  (TAS5754M_PAGE_BASE(1) +   2)
> > +#define TAS5754M_UNDERVOLTAGE_PROT (TAS5754M_PAGE_BASE(1) +   5)
> > +#define TAS5754M_ANALOG_MUTE_CTRL  (TAS5754M_PAGE_BASE(1) +   6)
> > +#define TAS5754M_ANALOG_GAIN_BOOST (TAS5754M_PAGE_BASE(1) +   7)
> > +#define TAS5754M_VCOM_CTRL_1       (TAS5754M_PAGE_BASE(1) +   8)
> > +#define TAS5754M_VCOM_CTRL_2       (TAS5754M_PAGE_BASE(1) +   9)
> > +
> > +#define TAS5754M_CRAM_CTRL         (TAS5754M_PAGE_BASE(44) +  1)
> > +
> > +#define TAS5754M_FLEX_A            (TAS5754M_PAGE_BASE(253) + 63)
> > +#define TAS5754M_FLEX_B            (TAS5754M_PAGE_BASE(253) + 64)
> > +
> > +#define TAS5754M_MAX_REGISTER      (TAS5754M_PAGE_BASE(253) + 64)
> > +
> > +/* Page 0, Register 1 - reset */
> > +#define TAS5754M_RSTR (1 << 0)
> > +#define TAS5754M_RSTM (1 << 4)
> > +
> > +/* Page 0, Register 2 - power */
> > +#define TAS5754M_RQPD       (1 << 0)
> > +#define TAS5754M_RQPD_SHIFT 0
> > +#define TAS5754M_RQST       (1 << 4)
> > +#define TAS5754M_RQST_SHIFT 4
> > +
> > +/* Page 0, Register 3 - mute */
> > +#define TAS5754M_RQMR (1 << 0)
> > +#define TAS5754M_RQMR_SHIFT 0
> > +#define TAS5754M_RQML (1 << 4)
> > +#define TAS5754M_RQML_SHIFT 4
> > +
> > +/* Page 0, Register 4 - PLL */
> > +#define TAS5754M_PLLE       (1 << 0)
> > +#define TAS5754M_PLLE_SHIFT 0
> > +#define TAS5754M_PLCK       (1 << 4)
> > +#define TAS5754M_PLCK_SHIFT 4
> > +
> > +/* Page 0, Register 7 - DSP */
> > +#define TAS5754M_SDSL       (1 << 0)
> > +#define TAS5754M_SDSL_SHIFT 0
> > +#define TAS5754M_DEMP       (1 << 4)
> > +#define TAS5754M_DEMP_SHIFT 4
> > +
> > +/* Page 0, Register 8 - GPIO output enable */
> > +#define TAS5754M_G1OE       (1 << 0)
> > +#define TAS5754M_G2OE       (1 << 1)
> > +#define TAS5754M_G3OE       (1 << 2)
> > +#define TAS5754M_G4OE       (1 << 3)
> > +#define TAS5754M_G5OE       (1 << 4)
> > +#define TAS5754M_G6OE       (1 << 5)
> > +
> > +/* Page 0, Register 9 - BCK, LRCLK configuration */
> > +#define TAS5754M_LRKO       (1 << 0)
> > +#define TAS5754M_LRKO_SHIFT 0
> > +#define TAS5754M_BCKO       (1 << 4)
> > +#define TAS5754M_BCKO_SHIFT 4
> > +#define TAS5754M_BCKP       (1 << 5)
> > +#define TAS5754M_BCKP_SHIFT 5
> > +
> > +/* Page 0, Register 12 - Master mode BCK, LRCLK reset */
> > +#define TAS5754M_RLRK       (1 << 0)
> > +#define TAS5754M_RLRK_SHIFT 0
> > +#define TAS5754M_RBCK       (1 << 1)
> > +#define TAS5754M_RBCK_SHIFT 1
> > +
> > +/* Page 0, Register 13 - PLL reference */
> > +#define TAS5754M_SREF        (7 << 4)
> > +#define TAS5754M_SREF_SHIFT  4
> > +#define TAS5754M_SREF_SCK    (0 << 4)
> > +#define TAS5754M_SREF_BCK    (1 << 4)
> > +#define TAS5754M_SREF_GPIO   (3 << 4)
> > +
> > +/* Page 0, Register 14 - DAC reference */
> > +#define TAS5754M_SDAC        (7 << 4)
> > +#define TAS5754M_SDAC_SHIFT  4
> > +#define TAS5754M_SDAC_MCK    (0 << 4)
> > +#define TAS5754M_SDAC_PLL    (1 << 4)
> > +#define TAS5754M_SDAC_SCK    (3 << 4)
> > +#define TAS5754M_SDAC_BCK    (4 << 4)
> > +#define TAS5754M_SDAC_GPIO   (5 << 4)
> > +
> > +/* Page 0, Register 16, 18 - GPIO source for DAC, PLL */
> > +#define TAS5754M_GREF        (7 << 0)
> > +#define TAS5754M_GREF_SHIFT  0
> > +#define TAS5754M_GREF_GPIO1  (0 << 0)
> > +#define TAS5754M_GREF_GPIO2  (1 << 0)
> > +#define TAS5754M_GREF_GPIO3  (2 << 0)
> > +#define TAS5754M_GREF_GPIO4  (3 << 0)
> > +#define TAS5754M_GREF_GPIO5  (4 << 0)
> > +#define TAS5754M_GREF_GPIO6  (5 << 0)
> > +
> > +/* Page 0, Register 19 - synchronize */
> > +#define TAS5754M_RQSY        (1 << 0)
> > +#define TAS5754M_RQSY_RESUME (0 << 0)
> > +#define TAS5754M_RQSY_HALT   (1 << 0)
> > +
> > +/* Page 0, Register 34 - fs speed mode */
> > +#define TAS5754M_FSSP        (3 << 0)
> > +#define TAS5754M_FSSP_SHIFT  0
> > +#define TAS5754M_FSSP_48KHZ  (0 << 0)
> > +#define TAS5754M_FSSP_96KHZ  (1 << 0)
> > +#define TAS5754M_FSSP_192KHZ (2 << 0)
> > +#define TAS5754M_FSSP_384KHZ (3 << 0)
> > +
> > +/* Page 0, Register 37 - Error detection */
> > +#define TAS5754M_IPLK (1 << 0)
> > +#define TAS5754M_DCAS (1 << 1)
> > +#define TAS5754M_IDCM (1 << 2)
> > +#define TAS5754M_IDCH (1 << 3)
> > +#define TAS5754M_IDSK (1 << 4)
> > +#define TAS5754M_IDBK (1 << 5)
> > +#define TAS5754M_IDFS (1 << 6)
> > +
> > +/* Page 0, Register 40 - I2S configuration */
> > +#define TAS5754M_ALEN       (3 << 0)
> > +#define TAS5754M_ALEN_SHIFT 0
> > +#define TAS5754M_ALEN_16    (0 << 0)
> > +#define TAS5754M_ALEN_20    (1 << 0)
> > +#define TAS5754M_ALEN_24    (2 << 0)
> > +#define TAS5754M_ALEN_32    (3 << 0)
> > +#define TAS5754M_AFMT       (3 << 4)
> > +#define TAS5754M_AFMT_SHIFT 4
> > +#define TAS5754M_AFMT_I2S   (0 << 4)
> > +#define TAS5754M_AFMT_DSP   (1 << 4)
> > +#define TAS5754M_AFMT_RTJ   (2 << 4)
> > +#define TAS5754M_AFMT_LTJ   (3 << 4)
> > +
> > +/* Page 0, Register 42 - DAC routing */
> > +#define TAS5754M_AUPR_SHIFT 0
> > +#define TAS5754M_AUPL_SHIFT 4
> > +
> > +/* Page 0, Register 59 - auto mute */
> > +#define TAS5754M_ATMR_SHIFT 0
> > +#define TAS5754M_ATML_SHIFT 4
> > +
> > +/* Page 0, Register 63 - ramp rates */
> > +#define TAS5754M_VNDF_SHIFT 6
> > +#define TAS5754M_VNDS_SHIFT 4
> > +#define TAS5754M_VNUF_SHIFT 2
> > +#define TAS5754M_VNUS_SHIFT 0
> > +
> > +/* Page 0, Register 64 - emergency ramp rates */
> > +#define TAS5754M_VEDF_SHIFT 6
> > +#define TAS5754M_VEDS_SHIFT 4
> > +
> > +/* Page 0, Register 65 - Digital mute enables */
> > +#define TAS5754M_ACTL_SHIFT 2
> > +#define TAS5754M_AMLE_SHIFT 1
> > +#define TAS5754M_AMRE_SHIFT 0
> > +
> > +/* Page 0, Register 80-85, GPIO output selection */
> > +#define TAS5754M_GxSL       (31 << 0)
> > +#define TAS5754M_GxSL_SHIFT 0
> > +#define TAS5754M_GxSL_OFF   (0 << 0)
> > +#define TAS5754M_GxSL_DSP   (1 << 0)
> > +#define TAS5754M_GxSL_REG   (2 << 0)
> > +#define TAS5754M_GxSL_AMUTB (3 << 0)
> > +#define TAS5754M_GxSL_AMUTL (4 << 0)
> > +#define TAS5754M_GxSL_AMUTR (5 << 0)
> > +#define TAS5754M_GxSL_CLKI  (6 << 0)
> > +#define TAS5754M_GxSL_SDOUT (7 << 0)
> > +#define TAS5754M_GxSL_ANMUL (8 << 0)
> > +#define TAS5754M_GxSL_ANMUR (9 << 0)
> > +#define TAS5754M_GxSL_PLLLK (10 << 0)
> > +#define TAS5754M_GxSL_CPCLK (11 << 0)
> > +#define TAS5754M_GxSL_UV0_7 (14 << 0)
> > +#define TAS5754M_GxSL_UV0_3 (15 << 0)
> > +#define TAS5754M_GxSL_PLLCK (16 << 0)
> > +
> > +/* Page 1, Register 2 - analog volume control */
> > +#define TAS5754M_RAGN_SHIFT 0
> > +#define TAS5754M_LAGN_SHIFT 4
> > +
> > +/* Page 1, Register 7 - analog boost control */
> > +#define TAS5754M_AGBR_SHIFT 0
> > +#define TAS5754M_AGBL_SHIFT 4
> > +
> > +#endif
> > 
> > base-commit: f6274b06e326d8471cdfb52595f989a90f5e888f
> > -- 
> > 2.17.1
> > 



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2] sound/soc: adds TAS5754M digital input amplifier component driver
@ 2022-01-19 12:50   ` Joerg Schambacher
  0 siblings, 0 replies; 21+ messages in thread
From: Joerg Schambacher @ 2022-01-19 12:50 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 16039 bytes --]

Mark,

Thanks for your useful feedback. I guess my comments on my first reply got lost somewhere on the way ....

I've updated and fixed some other issues meanwhile, too.

Joerg

On Wed, Nov 17, 2021 at 03:13:47PM +0000, Mark Brown wrote:
> On Fri, Oct 29, 2021 at 11:57:30AM +0200, Joerg Schambacher wrote:
> 
> > Adds a minimum component driver to run the amplifier in I2S master
> > mode only from standard audio clocks. Therefore, it only allows
> > 44.1, 88.2, 176.4, 48, 96 and 192ksps with 16, 20, 24 and 32 bits
> > sample size. Digital volume control and the -6dB switch are supported.
> 
> This looks pretty clean, there's a bunch of minor stylistic bits below
> but other than one major thing this looks good.  The major thing is the
> use of a had coded init sequence to configure the device rather than
> implemenenting the relevant APIs to do so, that's going to make the
> driver unsuitable for use on boards other than the specific one you
> happen to be looking at at the minute.
> 
> Please submit patches using subject lines reflecting the style for the
> subsystem, this makes it easier for people to identify relevant patches.
> Look at what existing commits in the area you're changing are doing and
> make sure your subject lines visually resemble what they're doing.
> 
> > @@ -0,0 +1,547 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Driver for the TAS5754M Audio Amplifier in Master mode (only)
> > + * supports only standard audio frequencies 44.1 to 192 ksps
> 
> Please make the entire comment a C++ one so things look more
> intentional.
> 
> > +EXPORT_SYMBOL_GPL(tas5754m_regmap);
> 
yes, remainder from some experiments - fixed

> There's only one file in the driver, why is this exported?
> 
> > +	mclk = clk_get_rate(tas5754m->sclk);
> > +	bclk = sample_len * 2 * params_rate(params);
> 
> snd_soc_params_to_bclk().
snd_soc_params_to_bclk() does not always gives the necessary value

> 
> > +	// set SCLK divider
> > +	ret |= regmap_write(tas5754m->regmap, TAS5754M_MASTER_CLKDIV_1,
> > +								bclk_div - 1);
> > +
> > +	// set LRCLK divider
> > +	ret |= regmap_write(tas5754m->regmap, TAS5754M_MASTER_CLKDIV_2,
> > +								lrclk_div - 1);
> 
Fixed

> Check the return statuses individually or just don't bother, if you or
> them together then you could end up with a nonsensical error code which
> could cause confusion down the line.
> 
> > +	if (mute) {
> > +		snd_soc_component_write(component, TAS5754M_MUTE, 0x11);
> > +	} else {
> > +		usleep_range(1000, 2000);
> > +		snd_soc_component_write(component, TAS5754M_MUTE, 0x00);
> 
> Why the sleep here?
Wait for settling of the clocks before unmute

> 
> > +	ret = regmap_multi_reg_write(regmap, tas5754m_init_sequence,
> > +					ARRAY_SIZE(tas5754m_init_sequence));
> 
> This init sequence looks an awful lot like it's doing board specific
> configuration - it's enabling the PLL, configuring GPIOs and clock
> dividers among other things.  These should all be done through board
> specific configuration or based on the currently configured audio path,
> what's suitable for one board may not be suitable for another board.
> Doing a reset of the chip is good but the rest of it really looks like
> it doesn't belong.
Ok, completely re-organized in the next trial

> 
> > +	ret = snd_soc_register_component(dev,
> > +			&tas5754m_soc_component, &tas5754m_dai, 1);
> 
> devm_snd_soc_register_component()
> 
fixed

> > +static const struct i2c_device_id tas5754m_i2c_id[] = {
> > +	{ "tas5754m", },
> > +	{ }
> > +};
> > +MODULE_DEVICE_TABLE(i2c, tas5754m_i2c_id);
> > +
> > +#ifdef CONFIG_OF
> > +static const struct of_device_id tas5754m_of_match[] = {
> > +	{ .compatible = "ti,tas5754m", },
> > +	{ .compatible = "ti,tas5756m", },
> > +	{ }
> > +};
> > +MODULE_DEVICE_TABLE(of, tas5754m_of_match);
> > +#endif
> 
> Why not list both I2C IDs as well?
Fixed

> 
> > @@ -0,0 +1,259 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +/*
> > + * Driver for the TAS5754M DAC+amplifier combo devices
> > + *
> > + * Author:	(copied from pcm512x.h)
> > + *		Mark Brown <broonie@kernel.org>
> > + *		Copyright 2014 Linaro Ltd
> > + */
> 
> If the register map can be copied can't the two drivers be combined?
The TI apps team recommended to write a separate driver as there are some differences. I have also aligned some names to the TAS575xM spec in the next patch

> 
> > +#define TAS5754M_VIRT_BASE 0x000
> > +#define TAS5754M_PAGE_LEN  0x80
> > +#define TAS5754M_PAGE_BASE(n)  (TAS5754M_VIRT_BASE + (TAS5754M_PAGE_LEN * n))
> > +
> > +#define TAS5754M_PAGE              0
> 
> There's no mention of paging in the regmap description for the driver
> which feels like it's asking for problems.
I think, it's defined in the correct way. Where/when exactly do you see a problem?

> 
> > +
> > +#define TAS5754M_RESET             (TAS5754M_PAGE_BASE(0) +   1)
> > +#define TAS5754M_POWER             (TAS5754M_PAGE_BASE(0) +   2)
> > +#define TAS5754M_MUTE              (TAS5754M_PAGE_BASE(0) +   3)
> > +#define TAS5754M_PLL_EN            (TAS5754M_PAGE_BASE(0) +   4)
> > +#define TAS5754M_SPI_MISO_FUNCTION (TAS5754M_PAGE_BASE(0) +   6)
> > +#define TAS5754M_DSP               (TAS5754M_PAGE_BASE(0) +   7)
> > +#define TAS5754M_GPIO_EN           (TAS5754M_PAGE_BASE(0) +   8)
> > +#define TAS5754M_BCLK_LRCLK_CFG    (TAS5754M_PAGE_BASE(0) +   9)
> > +#define TAS5754M_DSP_GPIO_INPUT    (TAS5754M_PAGE_BASE(0) +  10)
> > +#define TAS5754M_MASTER_MODE       (TAS5754M_PAGE_BASE(0) +  12)
> > +#define TAS5754M_PLL_REF           (TAS5754M_PAGE_BASE(0) +  13)
> > +#define TAS5754M_DAC_REF           (TAS5754M_PAGE_BASE(0) +  14)
> > +#define TAS5754M_GPIO_DACIN        (TAS5754M_PAGE_BASE(0) +  16)
> > +#define TAS5754M_GPIO_PLLIN        (TAS5754M_PAGE_BASE(0) +  18)
> > +#define TAS5754M_SYNCHRONIZE       (TAS5754M_PAGE_BASE(0) +  19)
> > +#define TAS5754M_PLL_COEFF_0       (TAS5754M_PAGE_BASE(0) +  20)
> > +#define TAS5754M_PLL_COEFF_1       (TAS5754M_PAGE_BASE(0) +  21)
> > +#define TAS5754M_PLL_COEFF_2       (TAS5754M_PAGE_BASE(0) +  22)
> > +#define TAS5754M_PLL_COEFF_3       (TAS5754M_PAGE_BASE(0) +  23)
> > +#define TAS5754M_PLL_COEFF_4       (TAS5754M_PAGE_BASE(0) +  24)
> > +#define TAS5754M_DSP_CLKDIV        (TAS5754M_PAGE_BASE(0) +  27)
> > +#define TAS5754M_DAC_CLKDIV        (TAS5754M_PAGE_BASE(0) +  28)
> > +#define TAS5754M_NCP_CLKDIV        (TAS5754M_PAGE_BASE(0) +  29)
> > +#define TAS5754M_OSR_CLKDIV        (TAS5754M_PAGE_BASE(0) +  30)
> > +#define TAS5754M_MASTER_CLKDIV_1   (TAS5754M_PAGE_BASE(0) +  32)
> > +#define TAS5754M_MASTER_CLKDIV_2   (TAS5754M_PAGE_BASE(0) +  33)
> > +#define TAS5754M_FS_SPEED_MODE     (TAS5754M_PAGE_BASE(0) +  34)
> > +#define TAS5754M_IDAC_1            (TAS5754M_PAGE_BASE(0) +  35)
> > +#define TAS5754M_IDAC_2            (TAS5754M_PAGE_BASE(0) +  36)
> > +#define TAS5754M_ERROR_DETECT      (TAS5754M_PAGE_BASE(0) +  37)
> > +#define TAS5754M_I2S_1             (TAS5754M_PAGE_BASE(0) +  40)
> > +#define TAS5754M_I2S_2             (TAS5754M_PAGE_BASE(0) +  41)
> > +#define TAS5754M_DAC_ROUTING       (TAS5754M_PAGE_BASE(0) +  42)
> > +#define TAS5754M_DSP_PROGRAM       (TAS5754M_PAGE_BASE(0) +  43)
> > +#define TAS5754M_CLKDET            (TAS5754M_PAGE_BASE(0) +  44)
> > +#define TAS5754M_AUTO_MUTE         (TAS5754M_PAGE_BASE(0) +  59)
> > +#define TAS5754M_DIGITAL_VOLUME_1  (TAS5754M_PAGE_BASE(0) +  60)
> > +#define TAS5754M_DIGITAL_VOLUME_2  (TAS5754M_PAGE_BASE(0) +  61)
> > +#define TAS5754M_DIGITAL_VOLUME_3  (TAS5754M_PAGE_BASE(0) +  62)
> > +#define TAS5754M_DIGITAL_MUTE_1    (TAS5754M_PAGE_BASE(0) +  63)
> > +#define TAS5754M_DIGITAL_MUTE_2    (TAS5754M_PAGE_BASE(0) +  64)
> > +#define TAS5754M_DIGITAL_MUTE_3    (TAS5754M_PAGE_BASE(0) +  65)
> > +#define TAS5754M_GPIO_OUTPUT_1     (TAS5754M_PAGE_BASE(0) +  80)
> > +#define TAS5754M_GPIO_OUTPUT_2     (TAS5754M_PAGE_BASE(0) +  81)
> > +#define TAS5754M_GPIO_OUTPUT_3     (TAS5754M_PAGE_BASE(0) +  82)
> > +#define TAS5754M_GPIO_OUTPUT_4     (TAS5754M_PAGE_BASE(0) +  83)
> > +#define TAS5754M_GPIO_OUTPUT_5     (TAS5754M_PAGE_BASE(0) +  84)
> > +#define TAS5754M_GPIO_OUTPUT_6     (TAS5754M_PAGE_BASE(0) +  85)
> > +#define TAS5754M_GPIO_CONTROL_1    (TAS5754M_PAGE_BASE(0) +  86)
> > +#define TAS5754M_GPIO_CONTROL_2    (TAS5754M_PAGE_BASE(0) +  87)
> > +#define TAS5754M_OVERFLOW          (TAS5754M_PAGE_BASE(0) +  90)
> > +#define TAS5754M_RATE_DET_1        (TAS5754M_PAGE_BASE(0) +  91)
> > +#define TAS5754M_RATE_DET_2        (TAS5754M_PAGE_BASE(0) +  92)
> > +#define TAS5754M_RATE_DET_3        (TAS5754M_PAGE_BASE(0) +  93)
> > +#define TAS5754M_RATE_DET_4        (TAS5754M_PAGE_BASE(0) +  94)
> > +#define TAS5754M_CLOCK_STATUS      (TAS5754M_PAGE_BASE(0) +  95)
> > +#define TAS5754M_ANALOG_MUTE_DET   (TAS5754M_PAGE_BASE(0) + 108)
> > +#define TAS5754M_GPIN              (TAS5754M_PAGE_BASE(0) + 119)
> > +#define TAS5754M_DIGITAL_MUTE_DET  (TAS5754M_PAGE_BASE(0) + 120)
> > +
> > +#define TAS5754M_OUTPUT_AMPLITUDE  (TAS5754M_PAGE_BASE(1) +   1)
> > +#define TAS5754M_ANALOG_GAIN_CTRL  (TAS5754M_PAGE_BASE(1) +   2)
> > +#define TAS5754M_UNDERVOLTAGE_PROT (TAS5754M_PAGE_BASE(1) +   5)
> > +#define TAS5754M_ANALOG_MUTE_CTRL  (TAS5754M_PAGE_BASE(1) +   6)
> > +#define TAS5754M_ANALOG_GAIN_BOOST (TAS5754M_PAGE_BASE(1) +   7)
> > +#define TAS5754M_VCOM_CTRL_1       (TAS5754M_PAGE_BASE(1) +   8)
> > +#define TAS5754M_VCOM_CTRL_2       (TAS5754M_PAGE_BASE(1) +   9)
> > +
> > +#define TAS5754M_CRAM_CTRL         (TAS5754M_PAGE_BASE(44) +  1)
> > +
> > +#define TAS5754M_FLEX_A            (TAS5754M_PAGE_BASE(253) + 63)
> > +#define TAS5754M_FLEX_B            (TAS5754M_PAGE_BASE(253) + 64)
> > +
> > +#define TAS5754M_MAX_REGISTER      (TAS5754M_PAGE_BASE(253) + 64)
> > +
> > +/* Page 0, Register 1 - reset */
> > +#define TAS5754M_RSTR (1 << 0)
> > +#define TAS5754M_RSTM (1 << 4)
> > +
> > +/* Page 0, Register 2 - power */
> > +#define TAS5754M_RQPD       (1 << 0)
> > +#define TAS5754M_RQPD_SHIFT 0
> > +#define TAS5754M_RQST       (1 << 4)
> > +#define TAS5754M_RQST_SHIFT 4
> > +
> > +/* Page 0, Register 3 - mute */
> > +#define TAS5754M_RQMR (1 << 0)
> > +#define TAS5754M_RQMR_SHIFT 0
> > +#define TAS5754M_RQML (1 << 4)
> > +#define TAS5754M_RQML_SHIFT 4
> > +
> > +/* Page 0, Register 4 - PLL */
> > +#define TAS5754M_PLLE       (1 << 0)
> > +#define TAS5754M_PLLE_SHIFT 0
> > +#define TAS5754M_PLCK       (1 << 4)
> > +#define TAS5754M_PLCK_SHIFT 4
> > +
> > +/* Page 0, Register 7 - DSP */
> > +#define TAS5754M_SDSL       (1 << 0)
> > +#define TAS5754M_SDSL_SHIFT 0
> > +#define TAS5754M_DEMP       (1 << 4)
> > +#define TAS5754M_DEMP_SHIFT 4
> > +
> > +/* Page 0, Register 8 - GPIO output enable */
> > +#define TAS5754M_G1OE       (1 << 0)
> > +#define TAS5754M_G2OE       (1 << 1)
> > +#define TAS5754M_G3OE       (1 << 2)
> > +#define TAS5754M_G4OE       (1 << 3)
> > +#define TAS5754M_G5OE       (1 << 4)
> > +#define TAS5754M_G6OE       (1 << 5)
> > +
> > +/* Page 0, Register 9 - BCK, LRCLK configuration */
> > +#define TAS5754M_LRKO       (1 << 0)
> > +#define TAS5754M_LRKO_SHIFT 0
> > +#define TAS5754M_BCKO       (1 << 4)
> > +#define TAS5754M_BCKO_SHIFT 4
> > +#define TAS5754M_BCKP       (1 << 5)
> > +#define TAS5754M_BCKP_SHIFT 5
> > +
> > +/* Page 0, Register 12 - Master mode BCK, LRCLK reset */
> > +#define TAS5754M_RLRK       (1 << 0)
> > +#define TAS5754M_RLRK_SHIFT 0
> > +#define TAS5754M_RBCK       (1 << 1)
> > +#define TAS5754M_RBCK_SHIFT 1
> > +
> > +/* Page 0, Register 13 - PLL reference */
> > +#define TAS5754M_SREF        (7 << 4)
> > +#define TAS5754M_SREF_SHIFT  4
> > +#define TAS5754M_SREF_SCK    (0 << 4)
> > +#define TAS5754M_SREF_BCK    (1 << 4)
> > +#define TAS5754M_SREF_GPIO   (3 << 4)
> > +
> > +/* Page 0, Register 14 - DAC reference */
> > +#define TAS5754M_SDAC        (7 << 4)
> > +#define TAS5754M_SDAC_SHIFT  4
> > +#define TAS5754M_SDAC_MCK    (0 << 4)
> > +#define TAS5754M_SDAC_PLL    (1 << 4)
> > +#define TAS5754M_SDAC_SCK    (3 << 4)
> > +#define TAS5754M_SDAC_BCK    (4 << 4)
> > +#define TAS5754M_SDAC_GPIO   (5 << 4)
> > +
> > +/* Page 0, Register 16, 18 - GPIO source for DAC, PLL */
> > +#define TAS5754M_GREF        (7 << 0)
> > +#define TAS5754M_GREF_SHIFT  0
> > +#define TAS5754M_GREF_GPIO1  (0 << 0)
> > +#define TAS5754M_GREF_GPIO2  (1 << 0)
> > +#define TAS5754M_GREF_GPIO3  (2 << 0)
> > +#define TAS5754M_GREF_GPIO4  (3 << 0)
> > +#define TAS5754M_GREF_GPIO5  (4 << 0)
> > +#define TAS5754M_GREF_GPIO6  (5 << 0)
> > +
> > +/* Page 0, Register 19 - synchronize */
> > +#define TAS5754M_RQSY        (1 << 0)
> > +#define TAS5754M_RQSY_RESUME (0 << 0)
> > +#define TAS5754M_RQSY_HALT   (1 << 0)
> > +
> > +/* Page 0, Register 34 - fs speed mode */
> > +#define TAS5754M_FSSP        (3 << 0)
> > +#define TAS5754M_FSSP_SHIFT  0
> > +#define TAS5754M_FSSP_48KHZ  (0 << 0)
> > +#define TAS5754M_FSSP_96KHZ  (1 << 0)
> > +#define TAS5754M_FSSP_192KHZ (2 << 0)
> > +#define TAS5754M_FSSP_384KHZ (3 << 0)
> > +
> > +/* Page 0, Register 37 - Error detection */
> > +#define TAS5754M_IPLK (1 << 0)
> > +#define TAS5754M_DCAS (1 << 1)
> > +#define TAS5754M_IDCM (1 << 2)
> > +#define TAS5754M_IDCH (1 << 3)
> > +#define TAS5754M_IDSK (1 << 4)
> > +#define TAS5754M_IDBK (1 << 5)
> > +#define TAS5754M_IDFS (1 << 6)
> > +
> > +/* Page 0, Register 40 - I2S configuration */
> > +#define TAS5754M_ALEN       (3 << 0)
> > +#define TAS5754M_ALEN_SHIFT 0
> > +#define TAS5754M_ALEN_16    (0 << 0)
> > +#define TAS5754M_ALEN_20    (1 << 0)
> > +#define TAS5754M_ALEN_24    (2 << 0)
> > +#define TAS5754M_ALEN_32    (3 << 0)
> > +#define TAS5754M_AFMT       (3 << 4)
> > +#define TAS5754M_AFMT_SHIFT 4
> > +#define TAS5754M_AFMT_I2S   (0 << 4)
> > +#define TAS5754M_AFMT_DSP   (1 << 4)
> > +#define TAS5754M_AFMT_RTJ   (2 << 4)
> > +#define TAS5754M_AFMT_LTJ   (3 << 4)
> > +
> > +/* Page 0, Register 42 - DAC routing */
> > +#define TAS5754M_AUPR_SHIFT 0
> > +#define TAS5754M_AUPL_SHIFT 4
> > +
> > +/* Page 0, Register 59 - auto mute */
> > +#define TAS5754M_ATMR_SHIFT 0
> > +#define TAS5754M_ATML_SHIFT 4
> > +
> > +/* Page 0, Register 63 - ramp rates */
> > +#define TAS5754M_VNDF_SHIFT 6
> > +#define TAS5754M_VNDS_SHIFT 4
> > +#define TAS5754M_VNUF_SHIFT 2
> > +#define TAS5754M_VNUS_SHIFT 0
> > +
> > +/* Page 0, Register 64 - emergency ramp rates */
> > +#define TAS5754M_VEDF_SHIFT 6
> > +#define TAS5754M_VEDS_SHIFT 4
> > +
> > +/* Page 0, Register 65 - Digital mute enables */
> > +#define TAS5754M_ACTL_SHIFT 2
> > +#define TAS5754M_AMLE_SHIFT 1
> > +#define TAS5754M_AMRE_SHIFT 0
> > +
> > +/* Page 0, Register 80-85, GPIO output selection */
> > +#define TAS5754M_GxSL       (31 << 0)
> > +#define TAS5754M_GxSL_SHIFT 0
> > +#define TAS5754M_GxSL_OFF   (0 << 0)
> > +#define TAS5754M_GxSL_DSP   (1 << 0)
> > +#define TAS5754M_GxSL_REG   (2 << 0)
> > +#define TAS5754M_GxSL_AMUTB (3 << 0)
> > +#define TAS5754M_GxSL_AMUTL (4 << 0)
> > +#define TAS5754M_GxSL_AMUTR (5 << 0)
> > +#define TAS5754M_GxSL_CLKI  (6 << 0)
> > +#define TAS5754M_GxSL_SDOUT (7 << 0)
> > +#define TAS5754M_GxSL_ANMUL (8 << 0)
> > +#define TAS5754M_GxSL_ANMUR (9 << 0)
> > +#define TAS5754M_GxSL_PLLLK (10 << 0)
> > +#define TAS5754M_GxSL_CPCLK (11 << 0)
> > +#define TAS5754M_GxSL_UV0_7 (14 << 0)
> > +#define TAS5754M_GxSL_UV0_3 (15 << 0)
> > +#define TAS5754M_GxSL_PLLCK (16 << 0)
> > +
> > +/* Page 1, Register 2 - analog volume control */
> > +#define TAS5754M_RAGN_SHIFT 0
> > +#define TAS5754M_LAGN_SHIFT 4
> > +
> > +/* Page 1, Register 7 - analog boost control */
> > +#define TAS5754M_AGBR_SHIFT 0
> > +#define TAS5754M_AGBL_SHIFT 4
> > +
> > +#endif
> > 
> > base-commit: f6274b06e326d8471cdfb52595f989a90f5e888f
> > -- 
> > 2.17.1
> > 


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v4] ASoC: adds component driver for TAS575xM digital amplifiers
  2022-01-10 16:25     ` Cezary Rojewski
@ 2022-01-19 13:05       ` Joerg Schambacher
  -1 siblings, 0 replies; 21+ messages in thread
From: Joerg Schambacher @ 2022-01-19 13:05 UTC (permalink / raw)
  To: Cezary Rojewski, alsa-devel, Mark Brown; +Cc: joerg, kbuild-all

Cezary,

Thanks for your review and the feedback. I hope I've fixed all issues.

Joerg

On Mon, Jan 10, 2022 at 05:25:14PM +0100, Cezary Rojewski wrote:
> On 2022-01-10 9:45 AM, Joerg Schambacher wrote:
> > Adds a minimum component driver to run the amplifier in I2S master
> > mode only from standard audio clocks. Therefore, it only allows
> > 44.1, 88.2, 176.4, 48, 96 and 192ksps with 16, 20, 24 and 32 bits
> > sample size. Digital volume control and the -6dB and +0.8dB switches
> > are supported.
> 
> Couple nitpicks and suggestions below.
> 
> (...)
> 
> > +static int tas5754m_set_bias_level(struct snd_soc_component *component,
> > +					enum snd_soc_bias_level level)
> > +{
> > +	struct tas5754m_priv *tas5754m =
> > +				snd_soc_component_get_drvdata(component);
> > +	int ret;
> > +
> > +	switch (level) {
> > +	case SND_SOC_BIAS_ON:
> > +	case SND_SOC_BIAS_PREPARE:
> > +		break;
> > +
> > +	case SND_SOC_BIAS_STANDBY:
> > +		ret = regmap_update_bits(tas5754m->regmap,
> > +				TAS5754M_POWER, TAS5754M_RQST, 0);
> > +		if (ret != 0) {
> 
> I believe we are dealing here with standard API function i.e. 0 on success
> and negative value on error. And thus, 'if (ret)' suffices.
> 
yes, fixed

> > +			dev_err(component->dev,
> > +				"Failed to remove standby: %d\n", ret);
> > +			return ret;
> > +		}
> > +		break;
> > +
> > +	case SND_SOC_BIAS_OFF:
> > +		ret = regmap_update_bits(tas5754m->regmap,
> > +				TAS5754M_POWER, TAS5754M_RQST, TAS5754M_RQST);
> > +		if (ret != 0) {
> 
> Ditto. This also goes for every single usage of regmap_xxx() in this file.
> 
> > +			dev_err(component->dev,
> > +				"Failed to request standby: %d\n", ret);
> > +			return ret;
> > +		}
> > +		break;
> > +	}
> > +
> > +	return 0;
> 
> You could also drop the 'return ret' from the if-statements above - granting
> you also ability to drop the brackets - and instead return 'ret' instead of
> '0' here. Of course that means 'ret' needs to be initialized appropriately
> at the top of the function.
yes, fixed as recommended
> 
> > +}
> > +
> > +int tas5754m_set_clock_tree_master(struct snd_soc_dai *dai,
> > +					struct snd_pcm_hw_params *params)
> 
> Indentation seems off.
aligned all functions/parameters

> 
> > +{
> > +	struct snd_soc_component *component = dai->component;
> > +	struct tas5754m_priv *tas5754m =
> > +			snd_soc_component_get_drvdata(component);
> > +	static const struct reg_sequence pll_settings[] = {
> > +		{ TAS5754M_PLL_COEFF_P,		0x01 },	// P=2
> > +		{ TAS5754M_PLL_COEFF_J,		0x08 },	// J=8
> > +		{ TAS5754M_PLL_COEFF_DL,	0x00 },	// D12-8 = 0
> > +		{ TAS5754M_PLL_COEFF_DH,	0x00 },	// D7-0 = 0
> > +		{ TAS5754M_PLL_COEFF_R,		0x00 },	// R=1
> > +	};
> > +	int ret;
> > +
> > +	/* disable PLL before any clock tree change */
> > +	ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
> > +				 TAS5754M_PLLE, 0);
> > +	if (ret != 0) {
> > +		dev_err(component->dev, "Failed to disable PLL: %d\n", ret);
> > +		return ret;
> > +	}
> > +
> > +	/* set DAC clock source to MCLK */
> > +	ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_REF, 0x30);
> > +	if (ret != 0) {
> > +		dev_err(component->dev, "Failed to set DAC ref\n");
> > +		return ret;
> > +	}
> > +
> > +	/* run PLL at fixed ratio to MCLK */
> > +	ret = regmap_multi_reg_write(tas5754m->regmap, pll_settings,
> > +					ARRAY_SIZE(pll_settings));
> > +	if (ret != 0) {
> > +		dev_err(component->dev, "Failed to set PLL ratio\n");
> > +		return ret;
> > +	}
> > +
> > +	/* set DSP divider to 2 => reg 0x01 */
> > +	ret = regmap_write(tas5754m->regmap, TAS5754M_DSP_CLKDIV, 1);
> > +	if (ret != 0) {
> > +		dev_err(component->dev, "Failed to set DSP divider\n");
> > +		return ret;
> > +	}
> > +	/* set DAC divider to 4 => reg 0x03*/
> > +	ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_CLKDIV, 3);
> > +	if (ret != 0) {
> > +		dev_err(component->dev, "Failed to set OSDACR divider\n");
> > +		return ret;
> > +	}
> > +	/* set OSR divider to 1 */
> > +	ret = regmap_write(tas5754m->regmap, TAS5754M_OSR_CLKDIV, 0);
> > +	if (ret != 0) {
> > +		dev_err(component->dev, "Failed to set OSR divider\n");
> > +		return ret;
> > +	}
> > +	/* set CP divider to 4 => reg 0x03*/
> > +	ret = regmap_write(tas5754m->regmap, TAS5754M_NCP_CLKDIV, 3);
> > +	if (ret != 0) {
> > +		dev_err(component->dev, "Failed to set CP divider\n");
> > +		return ret;
> > +	}
> > +	/* finally enable PLL */
> > +	ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
> > +				 TAS5754M_PLLE, 1);
> > +	if (ret != 0) {
> > +		dev_err(component->dev, "Failed to enable PLL: %d\n", ret);
> > +		return ret;
> > +	}
> > +
> > +	return 0;
> > +}
> 
> I'd suggest to keep the logical block organization cohesive. Especially if
> there are several of them all located within a single function. Some of the
> do/check/error-out blocks above are separated by a newline from the
> following ones, and some are not.
> 
> Another point is the cohesiveness of the error-message format. Some of the
> above print value of 'ret' i.e. carry additional value whereas other skip
> that part. Is this intentional?

done following your suggestions
> 
> > +
> > +int tas5754m_set_dai_mode(struct snd_soc_dai *dai)
> > +{
> > +	struct snd_soc_component *component = dai->component;
> > +	struct tas5754m_priv *tas5754m =
> > +			snd_soc_component_get_drvdata(component);
> > +	int fmt = tas5754m->fmt;
> > +
> > +	/* only I2S MASTER mode implemented */
> > +	if (((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S)) {
> 
> Maybe I'm missing something but the most outter pair of brackets is
> redundant.
Removed the brackets - I once had a warning like 'brackets around boolean expression' - but it works correct now.

> 
> > +		dev_err(component->dev,
> > +			"DAI format not supported (I2S master only)\n");
> > +		return -EINVAL;
> > +	}
> > +	/* TAS5754/6m do not support inverted clocks in MASTER mode */
> 
> A newline before the comment would make this more readabile - that's a new
> logical block afterall.
fixed
> 
> > +	if (((fmt & SND_SOC_DAIFMT_CLOCK_MASK) != SND_SOC_DAIFMT_NB_NF)) {
> 
> Again, I may be missing something, but this looks like outter brackets are
> redundant.
> 
> > +		dev_err(component->dev,	"Inverted clocks not supported\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
> > +	case SND_SOC_DAIFMT_CBM_CFM:
> > +		regmap_update_bits(tas5754m->regmap,
> > +				TAS5754M_BCLK_LRCLK_CFG,
> > +				TAS5754M_LRKO | TAS5754M_BCKO,
> > +				TAS5754M_LRKO | TAS5754M_BCKO);
> > +		/* reset CLK dividers */
> > +		regmap_update_bits(tas5754m->regmap,
> > +				TAS5754M_MASTER_MODE,
> > +				0x00,
> > +				TAS5754M_RLRK | TAS5754M_RBCK);
> > +		/* ignore all clock error detection but MCLK */
> > +		regmap_update_bits(tas5754m->regmap,
> > +				TAS5754M_ERROR_DETECT,
> > +				TAS5754M_IPLK | TAS5754M_DCAS |
> > +				TAS5754M_IDCM | TAS5754M_IDSK |
> > +				TAS5754M_IDBK | TAS5754M_IDFS,
> > +				TAS5754M_IPLK | TAS5754M_DCAS |
> > +				TAS5754M_IDCM | TAS5754M_IDSK |
> > +				TAS5754M_IDBK | TAS5754M_IDFS);
> > +		break;
> > +	case SND_SOC_DAIFMT_CBS_CFS:
> > +	case SND_SOC_DAIFMT_CBM_CFS:
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +int tas5754m_set_dividers_master(struct snd_soc_dai *dai,
> > +				struct snd_pcm_hw_params *params)
> > +{
> > +	struct snd_soc_component *component = dai->component;
> > +	struct tas5754m_priv *tas5754m =
> > +			snd_soc_component_get_drvdata(component);
> > +	unsigned long bclk;
> > +	unsigned long mclk;
> > +	int bclk_div;
> > +	int lrclk_div;
> > +	int osr;
> > +	int ret;
> > +
> > +	mclk = clk_get_rate(tas5754m->sclk);
> > +	bclk = tas5754m->sample_len * 2 * params_rate(params);
> > +	bclk_div = mclk / bclk;
> > +	lrclk_div = tas5754m->sample_len * 2;
> > +	osr = mclk / 4 / params_rate(params) / 16;
> 
> Is there a specific reason as to why these magic numbers aren't
> defines/constants?
mclk and sample_len vary: can be 22.5792/24.576MHz and 16/32 bits

> 
> > +
> > +	// stop LR / SCLK clocks
> 
> Formatting of this comment looks odd. Please align with the recommended one.
> 
> 
> (...)
> 
> 
> Regards,
> Czarek
From 06172ee3aff67edb09c934d96740ced85a70e8f6 Mon Sep 17 00:00:00 2001
From: Joerg Schambacher <joerg@hifiberry.com>
Date: Tue, 5 Oct 2021 14:38:21 +0200
Subject: [PATCH] ASoC: adds component driver for TAS575xM digital amplifiers

Adds a minimum component driver to run the amplifier in I2S master
mode only from standard audio clocks. Therefore, it only allows
44.1, 88.2, 176.4, 48, 96 and 192ksps with 16, 20, 24 and 32 bits
sample size. Digital volume control and the -6dB and +0.8dB switches
are supported.

Signed-off-by: Joerg Schambacher <joerg@hifiberry.com>
---
 sound/soc/codecs/Kconfig    |   8 +
 sound/soc/codecs/Makefile   |   2 +
 sound/soc/codecs/tas5754m.c | 691 ++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/tas5754m.h | 260 ++++++++++++++
 4 files changed, 961 insertions(+)
 create mode 100644 sound/soc/codecs/tas5754m.c
 create mode 100644 sound/soc/codecs/tas5754m.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 82ee233a269d..cf0584948fcf 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -210,6 +210,7 @@ config SND_SOC_ALL_CODECS
 	imply SND_SOC_TAS5086
 	imply SND_SOC_TAS571X
 	imply SND_SOC_TAS5720
+	imply SND_SOC_TAS5754M
 	imply SND_SOC_TAS6424
 	imply SND_SOC_TDA7419
 	imply SND_SOC_TFA9879
@@ -1419,6 +1420,13 @@ config SND_SOC_TAS5720
 	  Enable support for Texas Instruments TAS5720L/M high-efficiency mono
 	  Class-D audio power amplifiers.
 
+config SND_SOC_TAS5754M
+	tristate "Texas Instruments TAS5754M Digital Input Audio amplifier"
+	depends on I2C
+	help
+	  Enable support for Texas Instruments TAS5754M digital input
+	  Class-D audio power amplifiers.
+
 config SND_SOC_TAS6424
 	tristate "Texas Instruments TAS6424 Quad-Channel Audio amplifier"
 	depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 8dcea2c4604a..39984900258a 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -227,6 +227,7 @@ snd-soc-sti-sas-objs := sti-sas.o
 snd-soc-tas5086-objs := tas5086.o
 snd-soc-tas571x-objs := tas571x.o
 snd-soc-tas5720-objs := tas5720.o
+snd-soc-tas5754m-objs := tas5754m.o
 snd-soc-tas6424-objs := tas6424.o
 snd-soc-tda7419-objs := tda7419.o
 snd-soc-tas2770-objs := tas2770.o
@@ -555,6 +556,7 @@ obj-$(CONFIG_SND_SOC_TAS2764)	+= snd-soc-tas2764.o
 obj-$(CONFIG_SND_SOC_TAS5086)	+= snd-soc-tas5086.o
 obj-$(CONFIG_SND_SOC_TAS571X)	+= snd-soc-tas571x.o
 obj-$(CONFIG_SND_SOC_TAS5720)	+= snd-soc-tas5720.o
+obj-$(CONFIG_SND_SOC_TAS5754M)	+= snd-soc-tas5754m.o
 obj-$(CONFIG_SND_SOC_TAS6424)	+= snd-soc-tas6424.o
 obj-$(CONFIG_SND_SOC_TDA7419)	+= snd-soc-tda7419.o
 obj-$(CONFIG_SND_SOC_TAS2770) += snd-soc-tas2770.o
diff --git a/sound/soc/codecs/tas5754m.c b/sound/soc/codecs/tas5754m.c
new file mode 100644
index 000000000000..5aec0c1c6aeb
--- /dev/null
+++ b/sound/soc/codecs/tas5754m.c
@@ -0,0 +1,691 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for the TAS5754M Audio Amplifier
+ *
+ * Author: Joerg Schambacher <joerg@hifiberry.com>
+ *         with fragments from Andy Liu <andy-liu@ti.com>
+ *
+ * The driver supports I2S master mode only with standard audio
+ * frequencies 44.1 to 192 ksps from a 24.576/22.2592MHz master
+ * clock input
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+
+#include "tas5754m.h"
+
+#define TAS5754M_RATES		(SNDRV_PCM_RATE_48000  | \
+				 SNDRV_PCM_RATE_96000  | \
+				 SNDRV_PCM_RATE_192000 | \
+				 SNDRV_PCM_RATE_44100  | \
+				 SNDRV_PCM_RATE_88200  | \
+				 SNDRV_PCM_RATE_176400)
+#define TAS5754M_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE  | \
+				 SNDRV_PCM_FMTBIT_S20_LE  | \
+				 SNDRV_PCM_FMTBIT_S24_LE  | \
+				 SNDRV_PCM_FMTBIT_S32_LE)
+
+
+static const struct reg_default tas5754m_reg_defaults[] = {
+	{ TAS5754M_RESET,             0x00 },
+	{ TAS5754M_POWER,             0x00 },
+	{ TAS5754M_MUTE,              0x00 },
+	{ TAS5754M_DSP,               0x00 },
+	{ TAS5754M_PLL_REF,           0x00 },
+	{ TAS5754M_DAC_REF,           0x00 },
+	{ TAS5754M_DAC_ROUTING,       0x11 },
+	{ TAS5754M_DSP_PROGRAM,       0x01 },
+	{ TAS5754M_CLKDET,            0x00 },
+	{ TAS5754M_AUTO_MUTE,         0x00 },
+	{ TAS5754M_ERROR_DETECT,      0x00 },
+	{ TAS5754M_DIGITAL_VOLUME_1,  0x00 },
+	{ TAS5754M_DIGITAL_VOLUME_2,  0x30 },
+	{ TAS5754M_DIGITAL_VOLUME_3,  0x30 },
+	{ TAS5754M_DIGITAL_MUTE_1,    0x22 },
+	{ TAS5754M_DIGITAL_MUTE_2,    0x00 },
+	{ TAS5754M_DIGITAL_MUTE_3,    0x07 },
+	{ TAS5754M_OUTPUT_AMPLITUDE,  0x00 },
+	{ TAS5754M_ANALOG_GAIN_CTRL,  0x00 },
+	{ TAS5754M_UNDERVOLTAGE_PROT, 0x00 },
+	{ TAS5754M_ANALOG_MUTE_CTRL,  0x00 },
+	{ TAS5754M_ANALOG_GAIN_BOOST, 0x00 },
+	{ TAS5754M_VCOM_CTRL_1,       0x00 },
+	{ TAS5754M_VCOM_CTRL_2,       0x01 },
+	{ TAS5754M_BCLK_LRCLK_CFG,    0x00 },
+	{ TAS5754M_MASTER_MODE,       0x7c },
+	{ TAS5754M_GPIO_PLLIN,        0x00 },
+	{ TAS5754M_SYNCHRONIZE,       0x10 },
+	{ TAS5754M_PLL_COEFF_P,       0x00 },
+	{ TAS5754M_PLL_COEFF_J,       0x00 },
+	{ TAS5754M_PLL_COEFF_DH,      0x00 },
+	{ TAS5754M_PLL_COEFF_DL,      0x00 },
+	{ TAS5754M_PLL_COEFF_R,       0x00 },
+	{ TAS5754M_DSP_CLKDIV,        0x00 },
+	{ TAS5754M_DAC_CLKDIV,        0x00 },
+	{ TAS5754M_NCP_CLKDIV,        0x00 },
+	{ TAS5754M_OSR_CLKDIV,        0x00 },
+	{ TAS5754M_MASTER_SCLKDIV,    0x00 },
+	{ TAS5754M_MASTER_LRCLKDIV,   0x00 },
+	{ TAS5754M_FS_SPEED_MODE,     0x00 },
+	{ TAS5754M_IDAC_1,            0x01 },
+	{ TAS5754M_IDAC_2,            0x00 },
+};
+
+static bool tas5754m_readable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TAS5754M_RESET:
+	case TAS5754M_POWER:
+	case TAS5754M_MUTE:
+	case TAS5754M_PLL_EN:
+	case TAS5754M_DSP:
+	case TAS5754M_GPIO_EN:
+	case TAS5754M_BCLK_LRCLK_CFG:
+	case TAS5754M_DSP_GPIO_INPUT:
+	case TAS5754M_MASTER_MODE:
+	case TAS5754M_PLL_REF:
+	case TAS5754M_DAC_REF:
+	case TAS5754M_GPIO_PLLIN:
+	case TAS5754M_SYNCHRONIZE:
+	case TAS5754M_PLL_COEFF_P:
+	case TAS5754M_PLL_COEFF_J:
+	case TAS5754M_PLL_COEFF_DH:
+	case TAS5754M_PLL_COEFF_DL:
+	case TAS5754M_PLL_COEFF_R:
+	case TAS5754M_DSP_CLKDIV:
+	case TAS5754M_DAC_CLKDIV:
+	case TAS5754M_NCP_CLKDIV:
+	case TAS5754M_OSR_CLKDIV:
+	case TAS5754M_MASTER_SCLKDIV:
+	case TAS5754M_MASTER_LRCLKDIV:
+	case TAS5754M_FS_SPEED_MODE:
+	case TAS5754M_IDAC_1:
+	case TAS5754M_IDAC_2:
+	case TAS5754M_ERROR_DETECT:
+	case TAS5754M_I2S_1:
+	case TAS5754M_I2S_2:
+	case TAS5754M_DAC_ROUTING:
+	case TAS5754M_DSP_PROGRAM:
+	case TAS5754M_CLKDET:
+	case TAS5754M_AUTO_MUTE:
+	case TAS5754M_DIGITAL_VOLUME_1:
+	case TAS5754M_DIGITAL_VOLUME_2:
+	case TAS5754M_DIGITAL_VOLUME_3:
+	case TAS5754M_DIGITAL_MUTE_1:
+	case TAS5754M_DIGITAL_MUTE_2:
+	case TAS5754M_DIGITAL_MUTE_3:
+	case TAS5754M_GPIO_OUTPUT_0:
+	case TAS5754M_GPIO_OUTPUT_1:
+	case TAS5754M_GPIO_OUTPUT_2:
+	case TAS5754M_GPIO_CONTROL_1:
+	case TAS5754M_GPIO_CONTROL_2:
+	case TAS5754M_OVERFLOW:
+	case TAS5754M_RATE_DET_1:
+	case TAS5754M_RATE_DET_2:
+	case TAS5754M_RATE_DET_3:
+	case TAS5754M_RATE_DET_4:
+	case TAS5754M_CLOCK_STATUS:
+	case TAS5754M_ANALOG_MUTE_DET:
+	case TAS5754M_GPIN:
+	case TAS5754M_DIGITAL_MUTE_DET:
+	case TAS5754M_OUTPUT_AMPLITUDE:
+	case TAS5754M_ANALOG_GAIN_CTRL:
+	case TAS5754M_UNDERVOLTAGE_PROT:
+	case TAS5754M_ANALOG_MUTE_CTRL:
+	case TAS5754M_ANALOG_GAIN_BOOST:
+	case TAS5754M_VCOM_CTRL_1:
+	case TAS5754M_VCOM_CTRL_2:
+	case TAS5754M_CRAM_CTRL:
+	case TAS5754M_FLEX_A:
+	case TAS5754M_FLEX_B:
+		return true;
+	default:
+		return reg < 0x7f;
+	}
+}
+
+static bool tas5754m_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TAS5754M_PLL_EN:
+	case TAS5754M_OVERFLOW:
+	case TAS5754M_RATE_DET_1:
+	case TAS5754M_RATE_DET_2:
+	case TAS5754M_RATE_DET_3:
+	case TAS5754M_RATE_DET_4:
+	case TAS5754M_CLOCK_STATUS:
+	case TAS5754M_ANALOG_MUTE_DET:
+	case TAS5754M_GPIN:
+	case TAS5754M_DIGITAL_MUTE_DET:
+	case TAS5754M_CRAM_CTRL:
+		return true;
+	default:
+		return reg < 0x7f;
+	}
+}
+
+struct tas5754m_priv {
+	struct regmap *regmap;
+	struct clk *sclk;
+	int sample_len;
+	int fmt;
+	int mode;
+};
+
+static const struct regmap_range_cfg tas5754m_range = {
+	.name = "Pages",
+	.range_min = TAS5754M_VIRT_BASE,
+	.range_max = TAS5754M_MAX_REGISTER,
+	.selector_reg = TAS5754M_PAGE,
+	.selector_mask = 0x7f,
+	.window_start = 0,
+	.window_len = 128,
+};
+
+const struct regmap_config tas5754m_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.ranges = &tas5754m_range,
+	.num_ranges = 1,
+	.max_register = TAS5754M_MAX_REGISTER,
+
+	.reg_defaults = tas5754m_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(tas5754m_reg_defaults),
+	.readable_reg = tas5754m_readable,
+	.volatile_reg = tas5754m_volatile,
+
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1);
+static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0);
+
+static const struct snd_kcontrol_new tas5754m_controls[] = {
+SOC_DOUBLE_R_TLV("Digital Playback Volume", TAS5754M_DIGITAL_VOLUME_2,
+		 TAS5754M_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv),
+SOC_DOUBLE_TLV("Analog Playback Volume", TAS5754M_ANALOG_GAIN_CTRL,
+	     TAS5754M_LAGN_SHIFT, TAS5754M_RAGN_SHIFT, 1, 1, analog_tlv),
+SOC_DOUBLE_TLV("Analogue Playback Boost Volume", TAS5754M_ANALOG_GAIN_BOOST,
+	       TAS5754M_AGBL_SHIFT, TAS5754M_AGBR_SHIFT, 1, 0, boost_tlv),
+};
+
+static int tas5754m_set_bias_level(struct snd_soc_component *component,
+				   enum snd_soc_bias_level level)
+{
+	struct tas5754m_priv *tas5754m =
+				snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	default:
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		ret = regmap_update_bits(tas5754m->regmap,
+				TAS5754M_POWER, TAS5754M_RQST, 0);
+		if (ret)
+			dev_err(component->dev,
+				"Failed to remove standby: %d\n", ret);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		ret = regmap_update_bits(tas5754m->regmap,
+				TAS5754M_POWER, TAS5754M_RQST, TAS5754M_RQST);
+		if (ret)
+			dev_err(component->dev,
+				"Failed to request standby: %d\n", ret);
+		break;
+	}
+
+	return ret;
+}
+
+static int tas5754m_set_clock_tree_master(struct snd_soc_dai *dai,
+					  struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+	static const struct reg_sequence pll_settings[] = {
+		{ TAS5754M_PLL_COEFF_P,		0x01 },	// P=2
+		{ TAS5754M_PLL_COEFF_J,		0x08 },	// J=8
+		{ TAS5754M_PLL_COEFF_DL,	0x00 },	// D12-8 = 0
+		{ TAS5754M_PLL_COEFF_DH,	0x00 },	// D7-0 = 0
+		{ TAS5754M_PLL_COEFF_R,		0x00 },	// R=1
+	};
+	int ret;
+
+	/* disable PLL before any clock tree change */
+	ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
+				 TAS5754M_PLLE, 0);
+	if (ret) {
+		dev_err(component->dev, "Failed to disable PLL\n");
+		return ret;
+	}
+	/* set DAC clock source to MCLK */
+	ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_REF, 0x30);
+	if (ret) {
+		dev_err(component->dev, "Failed to set DAC ref\n");
+		return ret;
+	}
+	/* run PLL at fixed ratio to MCLK */
+	ret = regmap_multi_reg_write(tas5754m->regmap, pll_settings,
+					ARRAY_SIZE(pll_settings));
+	if (ret) {
+		dev_err(component->dev, "Failed to set PLL ratio\n");
+		return ret;
+	}
+	/* set DSP divider to 2 => reg 0x01 */
+	ret = regmap_write(tas5754m->regmap, TAS5754M_DSP_CLKDIV, 1);
+	if (ret) {
+		dev_err(component->dev, "Failed to set DSP divider\n");
+		return ret;
+	}
+	/* set DAC divider to 4 => reg 0x03*/
+	ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_CLKDIV, 3);
+	if (ret) {
+		dev_err(component->dev, "Failed to set OSDACR divider\n");
+		return ret;
+	}
+	/* set OSR divider to 1 */
+	ret = regmap_write(tas5754m->regmap, TAS5754M_OSR_CLKDIV, 0);
+	if (ret) {
+		dev_err(component->dev, "Failed to set OSR divider\n");
+		return ret;
+	}
+	/* set CP divider to 4 => reg 0x03*/
+	ret = regmap_write(tas5754m->regmap, TAS5754M_NCP_CLKDIV, 3);
+	if (ret) {
+		dev_err(component->dev, "Failed to set CP divider\n");
+		return ret;
+	}
+	/* finally enable PLL */
+	ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
+				 TAS5754M_PLLE, 1);
+	if (ret) {
+		dev_err(component->dev, "Failed to enable PLL\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tas5754m_set_dai_mode(struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+	int fmt = tas5754m->fmt;
+
+	/* only I2S MASTER mode implemented */
+	if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S) {
+		dev_err(component->dev,
+			"DAI format not supported (I2S master only)\n");
+		return -EINVAL;
+	}
+
+	/* TAS5754/6m do not support inverted clocks in MASTER mode */
+	if ((fmt & SND_SOC_DAIFMT_CLOCK_MASK) != SND_SOC_DAIFMT_NB_NF) {
+		dev_err(component->dev,	"Inverted clocks not supported\n");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		regmap_update_bits(tas5754m->regmap,
+				TAS5754M_BCLK_LRCLK_CFG,
+				TAS5754M_LRKO | TAS5754M_BCKO,
+				TAS5754M_LRKO | TAS5754M_BCKO);
+		/* reset CLK dividers */
+		regmap_update_bits(tas5754m->regmap,
+				TAS5754M_MASTER_MODE,
+				0x00,
+				TAS5754M_RLRK | TAS5754M_RBCK);
+		/* ignore all clock error detection but MCLK */
+		regmap_update_bits(tas5754m->regmap,
+				TAS5754M_ERROR_DETECT,
+				TAS5754M_IPLK | TAS5754M_DCAS |
+				TAS5754M_IDCM | TAS5754M_IDSK |
+				TAS5754M_IDBK | TAS5754M_IDFS,
+				TAS5754M_IPLK | TAS5754M_DCAS |
+				TAS5754M_IDCM | TAS5754M_IDSK |
+				TAS5754M_IDBK | TAS5754M_IDFS);
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+	case SND_SOC_DAIFMT_CBM_CFS:
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int tas5754m_set_dividers_master(struct snd_soc_dai *dai,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+	unsigned long bclk;
+	unsigned long mclk;
+	int bclk_div;
+	int lrclk_div;
+	int osr;
+	int ret;
+
+	/* calculate divider settings based on mclk and sample_len */
+	mclk = clk_get_rate(tas5754m->sclk);
+	bclk = tas5754m->sample_len * 2 * params_rate(params);
+	bclk_div = mclk / bclk;
+	lrclk_div = tas5754m->sample_len * 2;
+	osr = mclk / 4 / params_rate(params) / 16;
+
+	/* stop LR / SCLK clocks */
+	ret = regmap_update_bits(tas5754m->regmap,
+				TAS5754M_MASTER_MODE, 0,
+				TAS5754M_RLRK | TAS5754M_RBCK);
+	if (ret) {
+		dev_err(component->dev, "Failed to stop PLL\n");
+		return ret;
+	}
+	/* set SCLK divider */
+	ret = regmap_write(tas5754m->regmap, TAS5754M_MASTER_SCLKDIV,
+								bclk_div - 1);
+	if (ret) {
+		dev_err(component->dev, "Failed to set SCLK divider\n");
+		return ret;
+	}
+	/* set LRCLK divider */
+	ret = regmap_write(tas5754m->regmap, TAS5754M_MASTER_LRCLKDIV,
+								lrclk_div - 1);
+	if (ret) {
+		dev_err(component->dev, "Failed to set LRCLK divider\n");
+		return ret;
+	}
+	ret = regmap_write(tas5754m->regmap,
+		TAS5754M_OSR_CLKDIV, osr - 1);
+	if (ret) {
+		dev_err(component->dev, "Failed to set OSR divider\n");
+		return ret;
+	}
+	/* restart LR / SCLK clocks */
+	ret = regmap_update_bits(tas5754m->regmap,
+				TAS5754M_MASTER_MODE,
+				TAS5754M_RLRK | TAS5754M_RBCK,
+				TAS5754M_RLRK | TAS5754M_RBCK);
+	if (ret) {
+		dev_err(component->dev, "Failed to restart PLL\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tas5754m_hw_params(struct snd_pcm_substream *substream,
+			      struct snd_pcm_hw_params *params,
+			      struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+	int alen;
+	int ret;
+
+	switch (params_width(params)) {
+	case 16:
+		tas5754m->sample_len = 16;
+		alen = TAS5754M_ALEN_16;
+		break;
+	case 20:
+		tas5754m->sample_len = 32;
+		alen = TAS5754M_ALEN_20;
+		break;
+	case 24:
+		tas5754m->sample_len = 32;
+		alen = TAS5754M_ALEN_24;
+		break;
+	case 32:
+		tas5754m->sample_len = 32;
+		alen = TAS5754M_ALEN_32;
+		break;
+	default:
+		dev_err(component->dev, "Unsupported sample size: %d\n",
+			params_width(params));
+		return -EINVAL;
+	}
+	ret = regmap_update_bits(tas5754m->regmap, TAS5754M_I2S_1, alen, alen);
+	if (ret) {
+		dev_err(component->dev,
+			"Cannot set sample size: %d\n", ret);
+		return ret;
+	}
+
+	ret = tas5754m_set_dai_mode(dai);
+	if (ret) {
+		dev_err(component->dev,
+			"DAI mode not supported: %d\n", ret);
+		return ret;
+	}
+
+	ret = tas5754m_set_clock_tree_master(dai, params);
+	if (ret)
+		return ret;
+
+	switch (params_rate(params)) {
+	case 44100:
+	case 48000:
+		ret = regmap_write(tas5754m->regmap,
+			TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_48KHZ);
+		break;
+	case 88200:
+	case 96000:
+		ret = regmap_write(tas5754m->regmap,
+			TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_96KHZ);
+		break;
+	case 176400:
+	case 192000:
+		ret = regmap_write(tas5754m->regmap,
+			TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_192KHZ);
+		break;
+	default:
+		dev_err(component->dev, "Sample rate not supported: %d\n",
+			params_rate(params));
+		return -EINVAL;
+	}
+	if (ret) {
+		dev_err(component->dev, "Failed to config PLL\n");
+		return ret;
+	}
+
+	ret = tas5754m_set_dividers_master(dai, params);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int tas5754m_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+
+	tas5754m->fmt = fmt;
+
+	return 0;
+}
+
+
+static const struct snd_soc_component_driver tas5754m_soc_component = {
+	.set_bias_level = tas5754m_set_bias_level,
+	.idle_bias_on = true,
+	.controls = tas5754m_controls,
+	.num_controls = ARRAY_SIZE(tas5754m_controls),
+};
+
+static int tas5754m_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+	struct snd_soc_component *component = dai->component;
+
+	if (mute) {
+		snd_soc_component_write(component, TAS5754M_MUTE, 0x11);
+	} else {
+		/* wait for stable operation before unmute */
+		usleep_range(1000, 2000);
+		snd_soc_component_write(component, TAS5754M_MUTE, 0x00);
+	}
+	return 0;
+}
+
+static const struct snd_soc_dai_ops tas5754m_dai_ops = {
+	.mute_stream = tas5754m_mute,
+	.hw_params = tas5754m_hw_params,
+	.set_fmt = tas5754m_set_fmt,
+};
+
+static struct snd_soc_dai_driver tas5754m_dai = {
+	.name		= "tas5754m-amplifier",
+	.playback	= {
+		.stream_name	= "Playback",
+		.channels_min	= 2,
+		.channels_max	= 2,
+		.rates		= TAS5754M_RATES,
+		.formats	= TAS5754M_FORMATS,
+	},
+	.ops = &tas5754m_dai_ops,
+};
+
+static int tas5754m_probe(struct device *dev, struct regmap *regmap)
+{
+	struct tas5754m_priv *tas5754m;
+	int ret;
+
+	tas5754m = devm_kzalloc(dev, sizeof(struct tas5754m_priv), GFP_KERNEL);
+	if (!tas5754m)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, tas5754m);
+	tas5754m->regmap = regmap;
+
+	ret = regmap_write(regmap, TAS5754M_RESET,
+			TAS5754M_RSTR | TAS5754M_RSTM);
+	if (ret) {
+		dev_err(dev, "Failed to initialize TAS5754M: %d\n", ret);
+		goto err;
+	}
+
+	tas5754m->sclk = devm_clk_get(dev, NULL);
+	if (PTR_ERR(tas5754m->sclk) == -EPROBE_DEFER) {
+		ret = -EPROBE_DEFER;
+		goto err;
+	}
+	if (!IS_ERR(tas5754m->sclk)) {
+		ret = clk_prepare_enable(tas5754m->sclk);
+		if (ret) {
+			dev_err(dev, "Failed to enable SCLK: %d\n", ret);
+			goto err;
+		}
+	}
+
+	ret = devm_snd_soc_register_component(dev,
+			&tas5754m_soc_component, &tas5754m_dai, 1);
+	if (ret) {
+		dev_err(dev, "Failed to register CODEC: %d\n", ret);
+		goto err;
+	}
+
+	return 0;
+
+err:
+	return ret;
+
+}
+
+static int tas5754m_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+{
+	struct regmap *regmap;
+	struct regmap_config config = tas5754m_regmap;
+
+	/* enable auto-increment mode */
+	config.read_flag_mask = 0x80;
+	config.write_flag_mask = 0x80;
+
+	regmap = devm_regmap_init_i2c(i2c, &config);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return tas5754m_probe(&i2c->dev, regmap);
+}
+
+static int tas5754m_remove(struct device *dev)
+{
+	snd_soc_unregister_component(dev);
+
+	return 0;
+}
+
+static int tas5754m_i2c_remove(struct i2c_client *i2c)
+{
+	tas5754m_remove(&i2c->dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id tas5754m_i2c_id[] = {
+	{ "tas5754m", },
+	{ "tas5756m", },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tas5754m_i2c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id tas5754m_of_match[] = {
+	{ .compatible = "ti,tas5754m", },
+	{ .compatible = "ti,tas5756m", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, tas5754m_of_match);
+#endif
+
+static struct i2c_driver tas5754m_i2c_driver = {
+	.probe		= tas5754m_i2c_probe,
+	.remove		= tas5754m_i2c_remove,
+	.id_table	= tas5754m_i2c_id,
+	.driver		= {
+		.name	= "tas5754m",
+		.of_match_table = of_match_ptr(tas5754m_of_match),
+	},
+};
+
+module_i2c_driver(tas5754m_i2c_driver);
+
+MODULE_AUTHOR("Joerg Schambacher <joerg@hifiberry.com>");
+MODULE_DESCRIPTION("TAS5754M Audio Amplifier Driver - Master mode only");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas5754m.h b/sound/soc/codecs/tas5754m.h
new file mode 100644
index 000000000000..c6e26dba169f
--- /dev/null
+++ b/sound/soc/codecs/tas5754m.h
@@ -0,0 +1,260 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Driver for the TAS575xM DAC+amplifier combo devices
+ *
+ * Author:	(copied from pcm512x.h)
+ *		Mark Brown <broonie@kernel.org>
+ *		Copyright 2014 Linaro Ltd
+ *
+ *		Register names adapted and non available
+ *		register definitions removed according
+ +		to TAS5754M specification
+ *		Joerg Schambacher <joerg@hifiberry.com>
+ */
+
+#ifndef _SND_SOC_TAS5754M
+#define _SND_SOC_TAS5754M
+
+#include <linux/pm.h>
+#include <linux/regmap.h>
+
+#define TAS5754M_VIRT_BASE 0x000
+#define TAS5754M_PAGE_LEN  0x80
+#define TAS5754M_PAGE_BASE(n)  (TAS5754M_VIRT_BASE + (TAS5754M_PAGE_LEN * n))
+
+#define TAS5754M_PAGE              0
+
+#define TAS5754M_RESET             (TAS5754M_PAGE_BASE(0) +   1)
+#define TAS5754M_POWER             (TAS5754M_PAGE_BASE(0) +   2)
+#define TAS5754M_MUTE              (TAS5754M_PAGE_BASE(0) +   3)
+#define TAS5754M_PLL_EN            (TAS5754M_PAGE_BASE(0) +   4)
+#define TAS5754M_DSP               (TAS5754M_PAGE_BASE(0) +   7)
+#define TAS5754M_GPIO_EN           (TAS5754M_PAGE_BASE(0) +   8)
+#define TAS5754M_BCLK_LRCLK_CFG    (TAS5754M_PAGE_BASE(0) +   9)
+#define TAS5754M_DSP_GPIO_INPUT    (TAS5754M_PAGE_BASE(0) +  10)
+#define TAS5754M_MASTER_MODE       (TAS5754M_PAGE_BASE(0) +  12)
+#define TAS5754M_PLL_REF           (TAS5754M_PAGE_BASE(0) +  13)
+#define TAS5754M_DAC_REF           (TAS5754M_PAGE_BASE(0) +  14)
+#define TAS5754M_GPIO_PLLIN        (TAS5754M_PAGE_BASE(0) +  18)
+#define TAS5754M_SYNCHRONIZE       (TAS5754M_PAGE_BASE(0) +  19)
+#define TAS5754M_PLL_COEFF_P       (TAS5754M_PAGE_BASE(0) +  20)
+#define TAS5754M_PLL_COEFF_J       (TAS5754M_PAGE_BASE(0) +  21)
+#define TAS5754M_PLL_COEFF_DH      (TAS5754M_PAGE_BASE(0) +  22)
+#define TAS5754M_PLL_COEFF_DL      (TAS5754M_PAGE_BASE(0) +  23)
+#define TAS5754M_PLL_COEFF_R       (TAS5754M_PAGE_BASE(0) +  24)
+#define TAS5754M_DSP_CLKDIV        (TAS5754M_PAGE_BASE(0) +  27)
+#define TAS5754M_DAC_CLKDIV        (TAS5754M_PAGE_BASE(0) +  28)
+#define TAS5754M_NCP_CLKDIV        (TAS5754M_PAGE_BASE(0) +  29)
+#define TAS5754M_OSR_CLKDIV        (TAS5754M_PAGE_BASE(0) +  30)
+#define TAS5754M_MASTER_SCLKDIV    (TAS5754M_PAGE_BASE(0) +  32)
+#define TAS5754M_MASTER_LRCLKDIV   (TAS5754M_PAGE_BASE(0) +  33)
+#define TAS5754M_FS_SPEED_MODE     (TAS5754M_PAGE_BASE(0) +  34)
+#define TAS5754M_IDAC_1            (TAS5754M_PAGE_BASE(0) +  35)
+#define TAS5754M_IDAC_2            (TAS5754M_PAGE_BASE(0) +  36)
+#define TAS5754M_ERROR_DETECT      (TAS5754M_PAGE_BASE(0) +  37)
+#define TAS5754M_I2S_1             (TAS5754M_PAGE_BASE(0) +  40)
+#define TAS5754M_I2S_2             (TAS5754M_PAGE_BASE(0) +  41)
+#define TAS5754M_DAC_ROUTING       (TAS5754M_PAGE_BASE(0) +  42)
+#define TAS5754M_DSP_PROGRAM       (TAS5754M_PAGE_BASE(0) +  43)
+#define TAS5754M_CLKDET            (TAS5754M_PAGE_BASE(0) +  44)
+#define TAS5754M_AUTO_MUTE         (TAS5754M_PAGE_BASE(0) +  59)
+#define TAS5754M_DIGITAL_VOLUME_1  (TAS5754M_PAGE_BASE(0) +  60)
+#define TAS5754M_DIGITAL_VOLUME_2  (TAS5754M_PAGE_BASE(0) +  61)
+#define TAS5754M_DIGITAL_VOLUME_3  (TAS5754M_PAGE_BASE(0) +  62)
+#define TAS5754M_DIGITAL_MUTE_1    (TAS5754M_PAGE_BASE(0) +  63)
+#define TAS5754M_DIGITAL_MUTE_2    (TAS5754M_PAGE_BASE(0) +  64)
+#define TAS5754M_DIGITAL_MUTE_3    (TAS5754M_PAGE_BASE(0) +  65)
+#define TAS5754M_GPIO_OUTPUT_1     (TAS5754M_PAGE_BASE(0) +  82)
+#define TAS5754M_GPIO_OUTPUT_0     (TAS5754M_PAGE_BASE(0) +  83)
+#define TAS5754M_GPIO_OUTPUT_2     (TAS5754M_PAGE_BASE(0) +  85)
+#define TAS5754M_GPIO_CONTROL_1    (TAS5754M_PAGE_BASE(0) +  86)
+#define TAS5754M_GPIO_CONTROL_2    (TAS5754M_PAGE_BASE(0) +  87)
+#define TAS5754M_OVERFLOW          (TAS5754M_PAGE_BASE(0) +  90)
+#define TAS5754M_RATE_DET_1        (TAS5754M_PAGE_BASE(0) +  91)
+#define TAS5754M_RATE_DET_2        (TAS5754M_PAGE_BASE(0) +  92)
+#define TAS5754M_RATE_DET_3        (TAS5754M_PAGE_BASE(0) +  93)
+#define TAS5754M_RATE_DET_4        (TAS5754M_PAGE_BASE(0) +  94)
+#define TAS5754M_CLOCK_STATUS      (TAS5754M_PAGE_BASE(0) +  95)
+#define TAS5754M_ANALOG_MUTE_DET   (TAS5754M_PAGE_BASE(0) + 108)
+#define TAS5754M_FS_MODE_MON       (TAS5754M_PAGE_BASE(0) + 115)
+#define TAS5754M_GPIN              (TAS5754M_PAGE_BASE(0) + 119)
+#define TAS5754M_DIGITAL_MUTE_DET  (TAS5754M_PAGE_BASE(0) + 120)
+
+#define TAS5754M_OUTPUT_AMPLITUDE  (TAS5754M_PAGE_BASE(1) +   1)
+#define TAS5754M_ANALOG_GAIN_CTRL  (TAS5754M_PAGE_BASE(1) +   2)
+#define TAS5754M_UNDERVOLTAGE_PROT (TAS5754M_PAGE_BASE(1) +   5)
+#define TAS5754M_ANALOG_MUTE_CTRL  (TAS5754M_PAGE_BASE(1) +   6)
+#define TAS5754M_ANALOG_GAIN_BOOST (TAS5754M_PAGE_BASE(1) +   7)
+#define TAS5754M_VCOM_CTRL_1       (TAS5754M_PAGE_BASE(1) +   8)
+#define TAS5754M_VCOM_CTRL_2       (TAS5754M_PAGE_BASE(1) +   9)
+
+#define TAS5754M_CRAM_CTRL         (TAS5754M_PAGE_BASE(44) +  1)
+
+#define TAS5754M_FLEX_A            (TAS5754M_PAGE_BASE(253) + 63)
+#define TAS5754M_FLEX_B            (TAS5754M_PAGE_BASE(253) + 64)
+
+#define TAS5754M_MAX_REGISTER      (TAS5754M_PAGE_BASE(253) + 64)
+
+/* Page 0, Register 1 - reset */
+#define TAS5754M_RSTR (1 << 0)
+#define TAS5754M_RSTM (1 << 4)
+
+/* Page 0, Register 2 - power */
+#define TAS5754M_RQPD       (1 << 0)
+#define TAS5754M_RQPD_SHIFT 0
+#define TAS5754M_RQST       (1 << 4)
+#define TAS5754M_RQST_SHIFT 4
+
+/* Page 0, Register 3 - mute */
+#define TAS5754M_RQMR (1 << 0)
+#define TAS5754M_RQMR_SHIFT 0
+#define TAS5754M_RQML (1 << 4)
+#define TAS5754M_RQML_SHIFT 4
+
+/* Page 0, Register 4 - PLL */
+#define TAS5754M_PLLE       (1 << 0)
+#define TAS5754M_PLLE_SHIFT 0
+#define TAS5754M_PLCK       (1 << 4)
+#define TAS5754M_PLCK_SHIFT 4
+
+/* Page 0, Register 7 - DSP */
+#define TAS5754M_SDSL       (1 << 0)
+#define TAS5754M_SDSL_SHIFT 0
+#define TAS5754M_DEMP       (1 << 4)
+#define TAS5754M_DEMP_SHIFT 4
+
+/* Page 0, Register 8 - GPIO output enable */
+#define TAS5754M_G1OE       (1 << 0)
+#define TAS5754M_G2OE       (1 << 1)
+#define TAS5754M_G3OE       (1 << 2)
+#define TAS5754M_G4OE       (1 << 3)
+#define TAS5754M_G5OE       (1 << 4)
+#define TAS5754M_G6OE       (1 << 5)
+
+/* Page 0, Register 9 - BCK, LRCLK configuration */
+#define TAS5754M_LRKO       (1 << 0)
+#define TAS5754M_LRKO_SHIFT 0
+#define TAS5754M_BCKO       (1 << 4)
+#define TAS5754M_BCKO_SHIFT 4
+#define TAS5754M_BCKP       (1 << 5)
+#define TAS5754M_BCKP_SHIFT 5
+
+/* Page 0, Register 12 - Master mode BCK, LRCLK reset */
+#define TAS5754M_RLRK       (1 << 0)
+#define TAS5754M_RLRK_SHIFT 0
+#define TAS5754M_RBCK       (1 << 1)
+#define TAS5754M_RBCK_SHIFT 1
+
+/* Page 0, Register 13 - PLL reference */
+#define TAS5754M_SREF        (7 << 4)
+#define TAS5754M_SREF_SHIFT  4
+#define TAS5754M_SREF_SCK    (0 << 4)
+#define TAS5754M_SREF_BCK    (1 << 4)
+#define TAS5754M_SREF_GPIO   (3 << 4)
+
+/* Page 0, Register 14 - DAC reference */
+#define TAS5754M_SDAC        (7 << 4)
+#define TAS5754M_SDAC_SHIFT  4
+#define TAS5754M_SDAC_MCK    (0 << 4)
+#define TAS5754M_SDAC_PLL    (1 << 4)
+#define TAS5754M_SDAC_SCK    (3 << 4)
+#define TAS5754M_SDAC_BCK    (4 << 4)
+#define TAS5754M_SDAC_GPIO   (5 << 4)
+
+/* Page 0, Register 16, 18 - GPIO source for DAC, PLL */
+#define TAS5754M_GREF        (7 << 0)
+#define TAS5754M_GREF_SHIFT  0
+#define TAS5754M_GREF_GPIO1  (0 << 0)
+#define TAS5754M_GREF_GPIO2  (1 << 0)
+#define TAS5754M_GREF_GPIO3  (2 << 0)
+#define TAS5754M_GREF_GPIO4  (3 << 0)
+#define TAS5754M_GREF_GPIO5  (4 << 0)
+#define TAS5754M_GREF_GPIO6  (5 << 0)
+
+/* Page 0, Register 19 - synchronize */
+#define TAS5754M_RQSY        (1 << 0)
+#define TAS5754M_RQSY_RESUME (0 << 0)
+#define TAS5754M_RQSY_HALT   (1 << 0)
+
+/* Page 0, Register 34 - fs speed mode */
+#define TAS5754M_FSSP        (3 << 0)
+#define TAS5754M_FSSP_SHIFT  0
+#define TAS5754M_FSSP_48KHZ  (0 << 0)
+#define TAS5754M_FSSP_96KHZ  (1 << 0)
+#define TAS5754M_FSSP_192KHZ (2 << 0)
+#define TAS5754M_FSSP_384KHZ (3 << 0)
+
+/* Page 0, Register 37 - Error detection */
+#define TAS5754M_IPLK (1 << 0)
+#define TAS5754M_DCAS (1 << 1)
+#define TAS5754M_IDCM (1 << 2)
+#define TAS5754M_IDCH (1 << 3)
+#define TAS5754M_IDSK (1 << 4)
+#define TAS5754M_IDBK (1 << 5)
+#define TAS5754M_IDFS (1 << 6)
+
+/* Page 0, Register 40 - I2S configuration */
+#define TAS5754M_ALEN       (3 << 0)
+#define TAS5754M_ALEN_SHIFT 0
+#define TAS5754M_ALEN_16    (0 << 0)
+#define TAS5754M_ALEN_20    (1 << 0)
+#define TAS5754M_ALEN_24    (2 << 0)
+#define TAS5754M_ALEN_32    (3 << 0)
+#define TAS5754M_AFMT       (3 << 4)
+#define TAS5754M_AFMT_SHIFT 4
+#define TAS5754M_AFMT_I2S   (0 << 4)
+#define TAS5754M_AFMT_DSP   (1 << 4)
+#define TAS5754M_AFMT_RTJ   (2 << 4)
+#define TAS5754M_AFMT_LTJ   (3 << 4)
+
+/* Page 0, Register 42 - DAC routing */
+#define TAS5754M_AUPR_SHIFT 0
+#define TAS5754M_AUPL_SHIFT 4
+
+/* Page 0, Register 59 - auto mute */
+#define TAS5754M_ATMR_SHIFT 0
+#define TAS5754M_ATML_SHIFT 4
+
+/* Page 0, Register 63 - ramp rates */
+#define TAS5754M_VNDF_SHIFT 6
+#define TAS5754M_VNDS_SHIFT 4
+#define TAS5754M_VNUF_SHIFT 2
+#define TAS5754M_VNUS_SHIFT 0
+
+/* Page 0, Register 64 - emergency ramp rates */
+#define TAS5754M_VEDF_SHIFT 6
+#define TAS5754M_VEDS_SHIFT 4
+
+/* Page 0, Register 65 - Digital mute enables */
+#define TAS5754M_ACTL_SHIFT 2
+#define TAS5754M_AMLE_SHIFT 1
+#define TAS5754M_AMRE_SHIFT 0
+
+/* Page 0, Register 80-85, GPIO output selection */
+#define TAS5754M_GxSL       (31 << 0)
+#define TAS5754M_GxSL_SHIFT 0
+#define TAS5754M_GxSL_OFF   (0 << 0)
+#define TAS5754M_GxSL_DSP   (1 << 0)
+#define TAS5754M_GxSL_REG   (2 << 0)
+#define TAS5754M_GxSL_AMUTB (3 << 0)
+#define TAS5754M_GxSL_AMUTL (4 << 0)
+#define TAS5754M_GxSL_AMUTR (5 << 0)
+#define TAS5754M_GxSL_CLKI  (6 << 0)
+#define TAS5754M_GxSL_SDOUT (7 << 0)
+#define TAS5754M_GxSL_ANMUL (8 << 0)
+#define TAS5754M_GxSL_ANMUR (9 << 0)
+#define TAS5754M_GxSL_PLLLK (10 << 0)
+#define TAS5754M_GxSL_CPCLK (11 << 0)
+#define TAS5754M_GxSL_UV0_7 (14 << 0)
+#define TAS5754M_GxSL_UV0_3 (15 << 0)
+#define TAS5754M_GxSL_PLLCK (16 << 0)
+
+/* Page 1, Register 2 - analog volume control */
+#define TAS5754M_RAGN_SHIFT 0
+#define TAS5754M_LAGN_SHIFT 4
+
+/* Page 1, Register 7 - analog boost control */
+#define TAS5754M_AGBR_SHIFT 0
+#define TAS5754M_AGBL_SHIFT 4
+
+#endif
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH v4] ASoC: adds component driver for TAS575xM digital amplifiers
@ 2022-01-19 13:05       ` Joerg Schambacher
  0 siblings, 0 replies; 21+ messages in thread
From: Joerg Schambacher @ 2022-01-19 13:05 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 41725 bytes --]

Cezary,

Thanks for your review and the feedback. I hope I've fixed all issues.

Joerg

On Mon, Jan 10, 2022 at 05:25:14PM +0100, Cezary Rojewski wrote:
> On 2022-01-10 9:45 AM, Joerg Schambacher wrote:
> > Adds a minimum component driver to run the amplifier in I2S master
> > mode only from standard audio clocks. Therefore, it only allows
> > 44.1, 88.2, 176.4, 48, 96 and 192ksps with 16, 20, 24 and 32 bits
> > sample size. Digital volume control and the -6dB and +0.8dB switches
> > are supported.
> 
> Couple nitpicks and suggestions below.
> 
> (...)
> 
> > +static int tas5754m_set_bias_level(struct snd_soc_component *component,
> > +					enum snd_soc_bias_level level)
> > +{
> > +	struct tas5754m_priv *tas5754m =
> > +				snd_soc_component_get_drvdata(component);
> > +	int ret;
> > +
> > +	switch (level) {
> > +	case SND_SOC_BIAS_ON:
> > +	case SND_SOC_BIAS_PREPARE:
> > +		break;
> > +
> > +	case SND_SOC_BIAS_STANDBY:
> > +		ret = regmap_update_bits(tas5754m->regmap,
> > +				TAS5754M_POWER, TAS5754M_RQST, 0);
> > +		if (ret != 0) {
> 
> I believe we are dealing here with standard API function i.e. 0 on success
> and negative value on error. And thus, 'if (ret)' suffices.
> 
yes, fixed

> > +			dev_err(component->dev,
> > +				"Failed to remove standby: %d\n", ret);
> > +			return ret;
> > +		}
> > +		break;
> > +
> > +	case SND_SOC_BIAS_OFF:
> > +		ret = regmap_update_bits(tas5754m->regmap,
> > +				TAS5754M_POWER, TAS5754M_RQST, TAS5754M_RQST);
> > +		if (ret != 0) {
> 
> Ditto. This also goes for every single usage of regmap_xxx() in this file.
> 
> > +			dev_err(component->dev,
> > +				"Failed to request standby: %d\n", ret);
> > +			return ret;
> > +		}
> > +		break;
> > +	}
> > +
> > +	return 0;
> 
> You could also drop the 'return ret' from the if-statements above - granting
> you also ability to drop the brackets - and instead return 'ret' instead of
> '0' here. Of course that means 'ret' needs to be initialized appropriately
> at the top of the function.
yes, fixed as recommended
> 
> > +}
> > +
> > +int tas5754m_set_clock_tree_master(struct snd_soc_dai *dai,
> > +					struct snd_pcm_hw_params *params)
> 
> Indentation seems off.
aligned all functions/parameters

> 
> > +{
> > +	struct snd_soc_component *component = dai->component;
> > +	struct tas5754m_priv *tas5754m =
> > +			snd_soc_component_get_drvdata(component);
> > +	static const struct reg_sequence pll_settings[] = {
> > +		{ TAS5754M_PLL_COEFF_P,		0x01 },	// P=2
> > +		{ TAS5754M_PLL_COEFF_J,		0x08 },	// J=8
> > +		{ TAS5754M_PLL_COEFF_DL,	0x00 },	// D12-8 = 0
> > +		{ TAS5754M_PLL_COEFF_DH,	0x00 },	// D7-0 = 0
> > +		{ TAS5754M_PLL_COEFF_R,		0x00 },	// R=1
> > +	};
> > +	int ret;
> > +
> > +	/* disable PLL before any clock tree change */
> > +	ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
> > +				 TAS5754M_PLLE, 0);
> > +	if (ret != 0) {
> > +		dev_err(component->dev, "Failed to disable PLL: %d\n", ret);
> > +		return ret;
> > +	}
> > +
> > +	/* set DAC clock source to MCLK */
> > +	ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_REF, 0x30);
> > +	if (ret != 0) {
> > +		dev_err(component->dev, "Failed to set DAC ref\n");
> > +		return ret;
> > +	}
> > +
> > +	/* run PLL at fixed ratio to MCLK */
> > +	ret = regmap_multi_reg_write(tas5754m->regmap, pll_settings,
> > +					ARRAY_SIZE(pll_settings));
> > +	if (ret != 0) {
> > +		dev_err(component->dev, "Failed to set PLL ratio\n");
> > +		return ret;
> > +	}
> > +
> > +	/* set DSP divider to 2 => reg 0x01 */
> > +	ret = regmap_write(tas5754m->regmap, TAS5754M_DSP_CLKDIV, 1);
> > +	if (ret != 0) {
> > +		dev_err(component->dev, "Failed to set DSP divider\n");
> > +		return ret;
> > +	}
> > +	/* set DAC divider to 4 => reg 0x03*/
> > +	ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_CLKDIV, 3);
> > +	if (ret != 0) {
> > +		dev_err(component->dev, "Failed to set OSDACR divider\n");
> > +		return ret;
> > +	}
> > +	/* set OSR divider to 1 */
> > +	ret = regmap_write(tas5754m->regmap, TAS5754M_OSR_CLKDIV, 0);
> > +	if (ret != 0) {
> > +		dev_err(component->dev, "Failed to set OSR divider\n");
> > +		return ret;
> > +	}
> > +	/* set CP divider to 4 => reg 0x03*/
> > +	ret = regmap_write(tas5754m->regmap, TAS5754M_NCP_CLKDIV, 3);
> > +	if (ret != 0) {
> > +		dev_err(component->dev, "Failed to set CP divider\n");
> > +		return ret;
> > +	}
> > +	/* finally enable PLL */
> > +	ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
> > +				 TAS5754M_PLLE, 1);
> > +	if (ret != 0) {
> > +		dev_err(component->dev, "Failed to enable PLL: %d\n", ret);
> > +		return ret;
> > +	}
> > +
> > +	return 0;
> > +}
> 
> I'd suggest to keep the logical block organization cohesive. Especially if
> there are several of them all located within a single function. Some of the
> do/check/error-out blocks above are separated by a newline from the
> following ones, and some are not.
> 
> Another point is the cohesiveness of the error-message format. Some of the
> above print value of 'ret' i.e. carry additional value whereas other skip
> that part. Is this intentional?

done following your suggestions
> 
> > +
> > +int tas5754m_set_dai_mode(struct snd_soc_dai *dai)
> > +{
> > +	struct snd_soc_component *component = dai->component;
> > +	struct tas5754m_priv *tas5754m =
> > +			snd_soc_component_get_drvdata(component);
> > +	int fmt = tas5754m->fmt;
> > +
> > +	/* only I2S MASTER mode implemented */
> > +	if (((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S)) {
> 
> Maybe I'm missing something but the most outter pair of brackets is
> redundant.
Removed the brackets - I once had a warning like 'brackets around boolean expression' - but it works correct now.

> 
> > +		dev_err(component->dev,
> > +			"DAI format not supported (I2S master only)\n");
> > +		return -EINVAL;
> > +	}
> > +	/* TAS5754/6m do not support inverted clocks in MASTER mode */
> 
> A newline before the comment would make this more readabile - that's a new
> logical block afterall.
fixed
> 
> > +	if (((fmt & SND_SOC_DAIFMT_CLOCK_MASK) != SND_SOC_DAIFMT_NB_NF)) {
> 
> Again, I may be missing something, but this looks like outter brackets are
> redundant.
> 
> > +		dev_err(component->dev,	"Inverted clocks not supported\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
> > +	case SND_SOC_DAIFMT_CBM_CFM:
> > +		regmap_update_bits(tas5754m->regmap,
> > +				TAS5754M_BCLK_LRCLK_CFG,
> > +				TAS5754M_LRKO | TAS5754M_BCKO,
> > +				TAS5754M_LRKO | TAS5754M_BCKO);
> > +		/* reset CLK dividers */
> > +		regmap_update_bits(tas5754m->regmap,
> > +				TAS5754M_MASTER_MODE,
> > +				0x00,
> > +				TAS5754M_RLRK | TAS5754M_RBCK);
> > +		/* ignore all clock error detection but MCLK */
> > +		regmap_update_bits(tas5754m->regmap,
> > +				TAS5754M_ERROR_DETECT,
> > +				TAS5754M_IPLK | TAS5754M_DCAS |
> > +				TAS5754M_IDCM | TAS5754M_IDSK |
> > +				TAS5754M_IDBK | TAS5754M_IDFS,
> > +				TAS5754M_IPLK | TAS5754M_DCAS |
> > +				TAS5754M_IDCM | TAS5754M_IDSK |
> > +				TAS5754M_IDBK | TAS5754M_IDFS);
> > +		break;
> > +	case SND_SOC_DAIFMT_CBS_CFS:
> > +	case SND_SOC_DAIFMT_CBM_CFS:
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +int tas5754m_set_dividers_master(struct snd_soc_dai *dai,
> > +				struct snd_pcm_hw_params *params)
> > +{
> > +	struct snd_soc_component *component = dai->component;
> > +	struct tas5754m_priv *tas5754m =
> > +			snd_soc_component_get_drvdata(component);
> > +	unsigned long bclk;
> > +	unsigned long mclk;
> > +	int bclk_div;
> > +	int lrclk_div;
> > +	int osr;
> > +	int ret;
> > +
> > +	mclk = clk_get_rate(tas5754m->sclk);
> > +	bclk = tas5754m->sample_len * 2 * params_rate(params);
> > +	bclk_div = mclk / bclk;
> > +	lrclk_div = tas5754m->sample_len * 2;
> > +	osr = mclk / 4 / params_rate(params) / 16;
> 
> Is there a specific reason as to why these magic numbers aren't
> defines/constants?
mclk and sample_len vary: can be 22.5792/24.576MHz and 16/32 bits

> 
> > +
> > +	// stop LR / SCLK clocks
> 
> Formatting of this comment looks odd. Please align with the recommended one.
> 
> 
> (...)
> 
> 
> Regards,
> Czarek
>From 06172ee3aff67edb09c934d96740ced85a70e8f6 Mon Sep 17 00:00:00 2001
From: Joerg Schambacher <joerg@hifiberry.com>
Date: Tue, 5 Oct 2021 14:38:21 +0200
Subject: [PATCH] ASoC: adds component driver for TAS575xM digital amplifiers

Adds a minimum component driver to run the amplifier in I2S master
mode only from standard audio clocks. Therefore, it only allows
44.1, 88.2, 176.4, 48, 96 and 192ksps with 16, 20, 24 and 32 bits
sample size. Digital volume control and the -6dB and +0.8dB switches
are supported.

Signed-off-by: Joerg Schambacher <joerg@hifiberry.com>
---
 sound/soc/codecs/Kconfig    |   8 +
 sound/soc/codecs/Makefile   |   2 +
 sound/soc/codecs/tas5754m.c | 691 ++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/tas5754m.h | 260 ++++++++++++++
 4 files changed, 961 insertions(+)
 create mode 100644 sound/soc/codecs/tas5754m.c
 create mode 100644 sound/soc/codecs/tas5754m.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 82ee233a269d..cf0584948fcf 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -210,6 +210,7 @@ config SND_SOC_ALL_CODECS
 	imply SND_SOC_TAS5086
 	imply SND_SOC_TAS571X
 	imply SND_SOC_TAS5720
+	imply SND_SOC_TAS5754M
 	imply SND_SOC_TAS6424
 	imply SND_SOC_TDA7419
 	imply SND_SOC_TFA9879
@@ -1419,6 +1420,13 @@ config SND_SOC_TAS5720
 	  Enable support for Texas Instruments TAS5720L/M high-efficiency mono
 	  Class-D audio power amplifiers.
 
+config SND_SOC_TAS5754M
+	tristate "Texas Instruments TAS5754M Digital Input Audio amplifier"
+	depends on I2C
+	help
+	  Enable support for Texas Instruments TAS5754M digital input
+	  Class-D audio power amplifiers.
+
 config SND_SOC_TAS6424
 	tristate "Texas Instruments TAS6424 Quad-Channel Audio amplifier"
 	depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 8dcea2c4604a..39984900258a 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -227,6 +227,7 @@ snd-soc-sti-sas-objs := sti-sas.o
 snd-soc-tas5086-objs := tas5086.o
 snd-soc-tas571x-objs := tas571x.o
 snd-soc-tas5720-objs := tas5720.o
+snd-soc-tas5754m-objs := tas5754m.o
 snd-soc-tas6424-objs := tas6424.o
 snd-soc-tda7419-objs := tda7419.o
 snd-soc-tas2770-objs := tas2770.o
@@ -555,6 +556,7 @@ obj-$(CONFIG_SND_SOC_TAS2764)	+= snd-soc-tas2764.o
 obj-$(CONFIG_SND_SOC_TAS5086)	+= snd-soc-tas5086.o
 obj-$(CONFIG_SND_SOC_TAS571X)	+= snd-soc-tas571x.o
 obj-$(CONFIG_SND_SOC_TAS5720)	+= snd-soc-tas5720.o
+obj-$(CONFIG_SND_SOC_TAS5754M)	+= snd-soc-tas5754m.o
 obj-$(CONFIG_SND_SOC_TAS6424)	+= snd-soc-tas6424.o
 obj-$(CONFIG_SND_SOC_TDA7419)	+= snd-soc-tda7419.o
 obj-$(CONFIG_SND_SOC_TAS2770) += snd-soc-tas2770.o
diff --git a/sound/soc/codecs/tas5754m.c b/sound/soc/codecs/tas5754m.c
new file mode 100644
index 000000000000..5aec0c1c6aeb
--- /dev/null
+++ b/sound/soc/codecs/tas5754m.c
@@ -0,0 +1,691 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for the TAS5754M Audio Amplifier
+ *
+ * Author: Joerg Schambacher <joerg@hifiberry.com>
+ *         with fragments from Andy Liu <andy-liu@ti.com>
+ *
+ * The driver supports I2S master mode only with standard audio
+ * frequencies 44.1 to 192 ksps from a 24.576/22.2592MHz master
+ * clock input
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+
+#include "tas5754m.h"
+
+#define TAS5754M_RATES		(SNDRV_PCM_RATE_48000  | \
+				 SNDRV_PCM_RATE_96000  | \
+				 SNDRV_PCM_RATE_192000 | \
+				 SNDRV_PCM_RATE_44100  | \
+				 SNDRV_PCM_RATE_88200  | \
+				 SNDRV_PCM_RATE_176400)
+#define TAS5754M_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE  | \
+				 SNDRV_PCM_FMTBIT_S20_LE  | \
+				 SNDRV_PCM_FMTBIT_S24_LE  | \
+				 SNDRV_PCM_FMTBIT_S32_LE)
+
+
+static const struct reg_default tas5754m_reg_defaults[] = {
+	{ TAS5754M_RESET,             0x00 },
+	{ TAS5754M_POWER,             0x00 },
+	{ TAS5754M_MUTE,              0x00 },
+	{ TAS5754M_DSP,               0x00 },
+	{ TAS5754M_PLL_REF,           0x00 },
+	{ TAS5754M_DAC_REF,           0x00 },
+	{ TAS5754M_DAC_ROUTING,       0x11 },
+	{ TAS5754M_DSP_PROGRAM,       0x01 },
+	{ TAS5754M_CLKDET,            0x00 },
+	{ TAS5754M_AUTO_MUTE,         0x00 },
+	{ TAS5754M_ERROR_DETECT,      0x00 },
+	{ TAS5754M_DIGITAL_VOLUME_1,  0x00 },
+	{ TAS5754M_DIGITAL_VOLUME_2,  0x30 },
+	{ TAS5754M_DIGITAL_VOLUME_3,  0x30 },
+	{ TAS5754M_DIGITAL_MUTE_1,    0x22 },
+	{ TAS5754M_DIGITAL_MUTE_2,    0x00 },
+	{ TAS5754M_DIGITAL_MUTE_3,    0x07 },
+	{ TAS5754M_OUTPUT_AMPLITUDE,  0x00 },
+	{ TAS5754M_ANALOG_GAIN_CTRL,  0x00 },
+	{ TAS5754M_UNDERVOLTAGE_PROT, 0x00 },
+	{ TAS5754M_ANALOG_MUTE_CTRL,  0x00 },
+	{ TAS5754M_ANALOG_GAIN_BOOST, 0x00 },
+	{ TAS5754M_VCOM_CTRL_1,       0x00 },
+	{ TAS5754M_VCOM_CTRL_2,       0x01 },
+	{ TAS5754M_BCLK_LRCLK_CFG,    0x00 },
+	{ TAS5754M_MASTER_MODE,       0x7c },
+	{ TAS5754M_GPIO_PLLIN,        0x00 },
+	{ TAS5754M_SYNCHRONIZE,       0x10 },
+	{ TAS5754M_PLL_COEFF_P,       0x00 },
+	{ TAS5754M_PLL_COEFF_J,       0x00 },
+	{ TAS5754M_PLL_COEFF_DH,      0x00 },
+	{ TAS5754M_PLL_COEFF_DL,      0x00 },
+	{ TAS5754M_PLL_COEFF_R,       0x00 },
+	{ TAS5754M_DSP_CLKDIV,        0x00 },
+	{ TAS5754M_DAC_CLKDIV,        0x00 },
+	{ TAS5754M_NCP_CLKDIV,        0x00 },
+	{ TAS5754M_OSR_CLKDIV,        0x00 },
+	{ TAS5754M_MASTER_SCLKDIV,    0x00 },
+	{ TAS5754M_MASTER_LRCLKDIV,   0x00 },
+	{ TAS5754M_FS_SPEED_MODE,     0x00 },
+	{ TAS5754M_IDAC_1,            0x01 },
+	{ TAS5754M_IDAC_2,            0x00 },
+};
+
+static bool tas5754m_readable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TAS5754M_RESET:
+	case TAS5754M_POWER:
+	case TAS5754M_MUTE:
+	case TAS5754M_PLL_EN:
+	case TAS5754M_DSP:
+	case TAS5754M_GPIO_EN:
+	case TAS5754M_BCLK_LRCLK_CFG:
+	case TAS5754M_DSP_GPIO_INPUT:
+	case TAS5754M_MASTER_MODE:
+	case TAS5754M_PLL_REF:
+	case TAS5754M_DAC_REF:
+	case TAS5754M_GPIO_PLLIN:
+	case TAS5754M_SYNCHRONIZE:
+	case TAS5754M_PLL_COEFF_P:
+	case TAS5754M_PLL_COEFF_J:
+	case TAS5754M_PLL_COEFF_DH:
+	case TAS5754M_PLL_COEFF_DL:
+	case TAS5754M_PLL_COEFF_R:
+	case TAS5754M_DSP_CLKDIV:
+	case TAS5754M_DAC_CLKDIV:
+	case TAS5754M_NCP_CLKDIV:
+	case TAS5754M_OSR_CLKDIV:
+	case TAS5754M_MASTER_SCLKDIV:
+	case TAS5754M_MASTER_LRCLKDIV:
+	case TAS5754M_FS_SPEED_MODE:
+	case TAS5754M_IDAC_1:
+	case TAS5754M_IDAC_2:
+	case TAS5754M_ERROR_DETECT:
+	case TAS5754M_I2S_1:
+	case TAS5754M_I2S_2:
+	case TAS5754M_DAC_ROUTING:
+	case TAS5754M_DSP_PROGRAM:
+	case TAS5754M_CLKDET:
+	case TAS5754M_AUTO_MUTE:
+	case TAS5754M_DIGITAL_VOLUME_1:
+	case TAS5754M_DIGITAL_VOLUME_2:
+	case TAS5754M_DIGITAL_VOLUME_3:
+	case TAS5754M_DIGITAL_MUTE_1:
+	case TAS5754M_DIGITAL_MUTE_2:
+	case TAS5754M_DIGITAL_MUTE_3:
+	case TAS5754M_GPIO_OUTPUT_0:
+	case TAS5754M_GPIO_OUTPUT_1:
+	case TAS5754M_GPIO_OUTPUT_2:
+	case TAS5754M_GPIO_CONTROL_1:
+	case TAS5754M_GPIO_CONTROL_2:
+	case TAS5754M_OVERFLOW:
+	case TAS5754M_RATE_DET_1:
+	case TAS5754M_RATE_DET_2:
+	case TAS5754M_RATE_DET_3:
+	case TAS5754M_RATE_DET_4:
+	case TAS5754M_CLOCK_STATUS:
+	case TAS5754M_ANALOG_MUTE_DET:
+	case TAS5754M_GPIN:
+	case TAS5754M_DIGITAL_MUTE_DET:
+	case TAS5754M_OUTPUT_AMPLITUDE:
+	case TAS5754M_ANALOG_GAIN_CTRL:
+	case TAS5754M_UNDERVOLTAGE_PROT:
+	case TAS5754M_ANALOG_MUTE_CTRL:
+	case TAS5754M_ANALOG_GAIN_BOOST:
+	case TAS5754M_VCOM_CTRL_1:
+	case TAS5754M_VCOM_CTRL_2:
+	case TAS5754M_CRAM_CTRL:
+	case TAS5754M_FLEX_A:
+	case TAS5754M_FLEX_B:
+		return true;
+	default:
+		return reg < 0x7f;
+	}
+}
+
+static bool tas5754m_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TAS5754M_PLL_EN:
+	case TAS5754M_OVERFLOW:
+	case TAS5754M_RATE_DET_1:
+	case TAS5754M_RATE_DET_2:
+	case TAS5754M_RATE_DET_3:
+	case TAS5754M_RATE_DET_4:
+	case TAS5754M_CLOCK_STATUS:
+	case TAS5754M_ANALOG_MUTE_DET:
+	case TAS5754M_GPIN:
+	case TAS5754M_DIGITAL_MUTE_DET:
+	case TAS5754M_CRAM_CTRL:
+		return true;
+	default:
+		return reg < 0x7f;
+	}
+}
+
+struct tas5754m_priv {
+	struct regmap *regmap;
+	struct clk *sclk;
+	int sample_len;
+	int fmt;
+	int mode;
+};
+
+static const struct regmap_range_cfg tas5754m_range = {
+	.name = "Pages",
+	.range_min = TAS5754M_VIRT_BASE,
+	.range_max = TAS5754M_MAX_REGISTER,
+	.selector_reg = TAS5754M_PAGE,
+	.selector_mask = 0x7f,
+	.window_start = 0,
+	.window_len = 128,
+};
+
+const struct regmap_config tas5754m_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.ranges = &tas5754m_range,
+	.num_ranges = 1,
+	.max_register = TAS5754M_MAX_REGISTER,
+
+	.reg_defaults = tas5754m_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(tas5754m_reg_defaults),
+	.readable_reg = tas5754m_readable,
+	.volatile_reg = tas5754m_volatile,
+
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1);
+static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0);
+
+static const struct snd_kcontrol_new tas5754m_controls[] = {
+SOC_DOUBLE_R_TLV("Digital Playback Volume", TAS5754M_DIGITAL_VOLUME_2,
+		 TAS5754M_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv),
+SOC_DOUBLE_TLV("Analog Playback Volume", TAS5754M_ANALOG_GAIN_CTRL,
+	     TAS5754M_LAGN_SHIFT, TAS5754M_RAGN_SHIFT, 1, 1, analog_tlv),
+SOC_DOUBLE_TLV("Analogue Playback Boost Volume", TAS5754M_ANALOG_GAIN_BOOST,
+	       TAS5754M_AGBL_SHIFT, TAS5754M_AGBR_SHIFT, 1, 0, boost_tlv),
+};
+
+static int tas5754m_set_bias_level(struct snd_soc_component *component,
+				   enum snd_soc_bias_level level)
+{
+	struct tas5754m_priv *tas5754m =
+				snd_soc_component_get_drvdata(component);
+	int ret;
+
+	switch (level) {
+	default:
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		ret = regmap_update_bits(tas5754m->regmap,
+				TAS5754M_POWER, TAS5754M_RQST, 0);
+		if (ret)
+			dev_err(component->dev,
+				"Failed to remove standby: %d\n", ret);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		ret = regmap_update_bits(tas5754m->regmap,
+				TAS5754M_POWER, TAS5754M_RQST, TAS5754M_RQST);
+		if (ret)
+			dev_err(component->dev,
+				"Failed to request standby: %d\n", ret);
+		break;
+	}
+
+	return ret;
+}
+
+static int tas5754m_set_clock_tree_master(struct snd_soc_dai *dai,
+					  struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+	static const struct reg_sequence pll_settings[] = {
+		{ TAS5754M_PLL_COEFF_P,		0x01 },	// P=2
+		{ TAS5754M_PLL_COEFF_J,		0x08 },	// J=8
+		{ TAS5754M_PLL_COEFF_DL,	0x00 },	// D12-8 = 0
+		{ TAS5754M_PLL_COEFF_DH,	0x00 },	// D7-0 = 0
+		{ TAS5754M_PLL_COEFF_R,		0x00 },	// R=1
+	};
+	int ret;
+
+	/* disable PLL before any clock tree change */
+	ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
+				 TAS5754M_PLLE, 0);
+	if (ret) {
+		dev_err(component->dev, "Failed to disable PLL\n");
+		return ret;
+	}
+	/* set DAC clock source to MCLK */
+	ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_REF, 0x30);
+	if (ret) {
+		dev_err(component->dev, "Failed to set DAC ref\n");
+		return ret;
+	}
+	/* run PLL at fixed ratio to MCLK */
+	ret = regmap_multi_reg_write(tas5754m->regmap, pll_settings,
+					ARRAY_SIZE(pll_settings));
+	if (ret) {
+		dev_err(component->dev, "Failed to set PLL ratio\n");
+		return ret;
+	}
+	/* set DSP divider to 2 => reg 0x01 */
+	ret = regmap_write(tas5754m->regmap, TAS5754M_DSP_CLKDIV, 1);
+	if (ret) {
+		dev_err(component->dev, "Failed to set DSP divider\n");
+		return ret;
+	}
+	/* set DAC divider to 4 => reg 0x03*/
+	ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_CLKDIV, 3);
+	if (ret) {
+		dev_err(component->dev, "Failed to set OSDACR divider\n");
+		return ret;
+	}
+	/* set OSR divider to 1 */
+	ret = regmap_write(tas5754m->regmap, TAS5754M_OSR_CLKDIV, 0);
+	if (ret) {
+		dev_err(component->dev, "Failed to set OSR divider\n");
+		return ret;
+	}
+	/* set CP divider to 4 => reg 0x03*/
+	ret = regmap_write(tas5754m->regmap, TAS5754M_NCP_CLKDIV, 3);
+	if (ret) {
+		dev_err(component->dev, "Failed to set CP divider\n");
+		return ret;
+	}
+	/* finally enable PLL */
+	ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
+				 TAS5754M_PLLE, 1);
+	if (ret) {
+		dev_err(component->dev, "Failed to enable PLL\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tas5754m_set_dai_mode(struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+	int fmt = tas5754m->fmt;
+
+	/* only I2S MASTER mode implemented */
+	if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S) {
+		dev_err(component->dev,
+			"DAI format not supported (I2S master only)\n");
+		return -EINVAL;
+	}
+
+	/* TAS5754/6m do not support inverted clocks in MASTER mode */
+	if ((fmt & SND_SOC_DAIFMT_CLOCK_MASK) != SND_SOC_DAIFMT_NB_NF) {
+		dev_err(component->dev,	"Inverted clocks not supported\n");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		regmap_update_bits(tas5754m->regmap,
+				TAS5754M_BCLK_LRCLK_CFG,
+				TAS5754M_LRKO | TAS5754M_BCKO,
+				TAS5754M_LRKO | TAS5754M_BCKO);
+		/* reset CLK dividers */
+		regmap_update_bits(tas5754m->regmap,
+				TAS5754M_MASTER_MODE,
+				0x00,
+				TAS5754M_RLRK | TAS5754M_RBCK);
+		/* ignore all clock error detection but MCLK */
+		regmap_update_bits(tas5754m->regmap,
+				TAS5754M_ERROR_DETECT,
+				TAS5754M_IPLK | TAS5754M_DCAS |
+				TAS5754M_IDCM | TAS5754M_IDSK |
+				TAS5754M_IDBK | TAS5754M_IDFS,
+				TAS5754M_IPLK | TAS5754M_DCAS |
+				TAS5754M_IDCM | TAS5754M_IDSK |
+				TAS5754M_IDBK | TAS5754M_IDFS);
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+	case SND_SOC_DAIFMT_CBM_CFS:
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int tas5754m_set_dividers_master(struct snd_soc_dai *dai,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+	unsigned long bclk;
+	unsigned long mclk;
+	int bclk_div;
+	int lrclk_div;
+	int osr;
+	int ret;
+
+	/* calculate divider settings based on mclk and sample_len */
+	mclk = clk_get_rate(tas5754m->sclk);
+	bclk = tas5754m->sample_len * 2 * params_rate(params);
+	bclk_div = mclk / bclk;
+	lrclk_div = tas5754m->sample_len * 2;
+	osr = mclk / 4 / params_rate(params) / 16;
+
+	/* stop LR / SCLK clocks */
+	ret = regmap_update_bits(tas5754m->regmap,
+				TAS5754M_MASTER_MODE, 0,
+				TAS5754M_RLRK | TAS5754M_RBCK);
+	if (ret) {
+		dev_err(component->dev, "Failed to stop PLL\n");
+		return ret;
+	}
+	/* set SCLK divider */
+	ret = regmap_write(tas5754m->regmap, TAS5754M_MASTER_SCLKDIV,
+								bclk_div - 1);
+	if (ret) {
+		dev_err(component->dev, "Failed to set SCLK divider\n");
+		return ret;
+	}
+	/* set LRCLK divider */
+	ret = regmap_write(tas5754m->regmap, TAS5754M_MASTER_LRCLKDIV,
+								lrclk_div - 1);
+	if (ret) {
+		dev_err(component->dev, "Failed to set LRCLK divider\n");
+		return ret;
+	}
+	ret = regmap_write(tas5754m->regmap,
+		TAS5754M_OSR_CLKDIV, osr - 1);
+	if (ret) {
+		dev_err(component->dev, "Failed to set OSR divider\n");
+		return ret;
+	}
+	/* restart LR / SCLK clocks */
+	ret = regmap_update_bits(tas5754m->regmap,
+				TAS5754M_MASTER_MODE,
+				TAS5754M_RLRK | TAS5754M_RBCK,
+				TAS5754M_RLRK | TAS5754M_RBCK);
+	if (ret) {
+		dev_err(component->dev, "Failed to restart PLL\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tas5754m_hw_params(struct snd_pcm_substream *substream,
+			      struct snd_pcm_hw_params *params,
+			      struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+	int alen;
+	int ret;
+
+	switch (params_width(params)) {
+	case 16:
+		tas5754m->sample_len = 16;
+		alen = TAS5754M_ALEN_16;
+		break;
+	case 20:
+		tas5754m->sample_len = 32;
+		alen = TAS5754M_ALEN_20;
+		break;
+	case 24:
+		tas5754m->sample_len = 32;
+		alen = TAS5754M_ALEN_24;
+		break;
+	case 32:
+		tas5754m->sample_len = 32;
+		alen = TAS5754M_ALEN_32;
+		break;
+	default:
+		dev_err(component->dev, "Unsupported sample size: %d\n",
+			params_width(params));
+		return -EINVAL;
+	}
+	ret = regmap_update_bits(tas5754m->regmap, TAS5754M_I2S_1, alen, alen);
+	if (ret) {
+		dev_err(component->dev,
+			"Cannot set sample size: %d\n", ret);
+		return ret;
+	}
+
+	ret = tas5754m_set_dai_mode(dai);
+	if (ret) {
+		dev_err(component->dev,
+			"DAI mode not supported: %d\n", ret);
+		return ret;
+	}
+
+	ret = tas5754m_set_clock_tree_master(dai, params);
+	if (ret)
+		return ret;
+
+	switch (params_rate(params)) {
+	case 44100:
+	case 48000:
+		ret = regmap_write(tas5754m->regmap,
+			TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_48KHZ);
+		break;
+	case 88200:
+	case 96000:
+		ret = regmap_write(tas5754m->regmap,
+			TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_96KHZ);
+		break;
+	case 176400:
+	case 192000:
+		ret = regmap_write(tas5754m->regmap,
+			TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_192KHZ);
+		break;
+	default:
+		dev_err(component->dev, "Sample rate not supported: %d\n",
+			params_rate(params));
+		return -EINVAL;
+	}
+	if (ret) {
+		dev_err(component->dev, "Failed to config PLL\n");
+		return ret;
+	}
+
+	ret = tas5754m_set_dividers_master(dai, params);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int tas5754m_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+
+	tas5754m->fmt = fmt;
+
+	return 0;
+}
+
+
+static const struct snd_soc_component_driver tas5754m_soc_component = {
+	.set_bias_level = tas5754m_set_bias_level,
+	.idle_bias_on = true,
+	.controls = tas5754m_controls,
+	.num_controls = ARRAY_SIZE(tas5754m_controls),
+};
+
+static int tas5754m_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+	struct snd_soc_component *component = dai->component;
+
+	if (mute) {
+		snd_soc_component_write(component, TAS5754M_MUTE, 0x11);
+	} else {
+		/* wait for stable operation before unmute */
+		usleep_range(1000, 2000);
+		snd_soc_component_write(component, TAS5754M_MUTE, 0x00);
+	}
+	return 0;
+}
+
+static const struct snd_soc_dai_ops tas5754m_dai_ops = {
+	.mute_stream = tas5754m_mute,
+	.hw_params = tas5754m_hw_params,
+	.set_fmt = tas5754m_set_fmt,
+};
+
+static struct snd_soc_dai_driver tas5754m_dai = {
+	.name		= "tas5754m-amplifier",
+	.playback	= {
+		.stream_name	= "Playback",
+		.channels_min	= 2,
+		.channels_max	= 2,
+		.rates		= TAS5754M_RATES,
+		.formats	= TAS5754M_FORMATS,
+	},
+	.ops = &tas5754m_dai_ops,
+};
+
+static int tas5754m_probe(struct device *dev, struct regmap *regmap)
+{
+	struct tas5754m_priv *tas5754m;
+	int ret;
+
+	tas5754m = devm_kzalloc(dev, sizeof(struct tas5754m_priv), GFP_KERNEL);
+	if (!tas5754m)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, tas5754m);
+	tas5754m->regmap = regmap;
+
+	ret = regmap_write(regmap, TAS5754M_RESET,
+			TAS5754M_RSTR | TAS5754M_RSTM);
+	if (ret) {
+		dev_err(dev, "Failed to initialize TAS5754M: %d\n", ret);
+		goto err;
+	}
+
+	tas5754m->sclk = devm_clk_get(dev, NULL);
+	if (PTR_ERR(tas5754m->sclk) == -EPROBE_DEFER) {
+		ret = -EPROBE_DEFER;
+		goto err;
+	}
+	if (!IS_ERR(tas5754m->sclk)) {
+		ret = clk_prepare_enable(tas5754m->sclk);
+		if (ret) {
+			dev_err(dev, "Failed to enable SCLK: %d\n", ret);
+			goto err;
+		}
+	}
+
+	ret = devm_snd_soc_register_component(dev,
+			&tas5754m_soc_component, &tas5754m_dai, 1);
+	if (ret) {
+		dev_err(dev, "Failed to register CODEC: %d\n", ret);
+		goto err;
+	}
+
+	return 0;
+
+err:
+	return ret;
+
+}
+
+static int tas5754m_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+{
+	struct regmap *regmap;
+	struct regmap_config config = tas5754m_regmap;
+
+	/* enable auto-increment mode */
+	config.read_flag_mask = 0x80;
+	config.write_flag_mask = 0x80;
+
+	regmap = devm_regmap_init_i2c(i2c, &config);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return tas5754m_probe(&i2c->dev, regmap);
+}
+
+static int tas5754m_remove(struct device *dev)
+{
+	snd_soc_unregister_component(dev);
+
+	return 0;
+}
+
+static int tas5754m_i2c_remove(struct i2c_client *i2c)
+{
+	tas5754m_remove(&i2c->dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id tas5754m_i2c_id[] = {
+	{ "tas5754m", },
+	{ "tas5756m", },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tas5754m_i2c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id tas5754m_of_match[] = {
+	{ .compatible = "ti,tas5754m", },
+	{ .compatible = "ti,tas5756m", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, tas5754m_of_match);
+#endif
+
+static struct i2c_driver tas5754m_i2c_driver = {
+	.probe		= tas5754m_i2c_probe,
+	.remove		= tas5754m_i2c_remove,
+	.id_table	= tas5754m_i2c_id,
+	.driver		= {
+		.name	= "tas5754m",
+		.of_match_table = of_match_ptr(tas5754m_of_match),
+	},
+};
+
+module_i2c_driver(tas5754m_i2c_driver);
+
+MODULE_AUTHOR("Joerg Schambacher <joerg@hifiberry.com>");
+MODULE_DESCRIPTION("TAS5754M Audio Amplifier Driver - Master mode only");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas5754m.h b/sound/soc/codecs/tas5754m.h
new file mode 100644
index 000000000000..c6e26dba169f
--- /dev/null
+++ b/sound/soc/codecs/tas5754m.h
@@ -0,0 +1,260 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Driver for the TAS575xM DAC+amplifier combo devices
+ *
+ * Author:	(copied from pcm512x.h)
+ *		Mark Brown <broonie@kernel.org>
+ *		Copyright 2014 Linaro Ltd
+ *
+ *		Register names adapted and non available
+ *		register definitions removed according
+ +		to TAS5754M specification
+ *		Joerg Schambacher <joerg@hifiberry.com>
+ */
+
+#ifndef _SND_SOC_TAS5754M
+#define _SND_SOC_TAS5754M
+
+#include <linux/pm.h>
+#include <linux/regmap.h>
+
+#define TAS5754M_VIRT_BASE 0x000
+#define TAS5754M_PAGE_LEN  0x80
+#define TAS5754M_PAGE_BASE(n)  (TAS5754M_VIRT_BASE + (TAS5754M_PAGE_LEN * n))
+
+#define TAS5754M_PAGE              0
+
+#define TAS5754M_RESET             (TAS5754M_PAGE_BASE(0) +   1)
+#define TAS5754M_POWER             (TAS5754M_PAGE_BASE(0) +   2)
+#define TAS5754M_MUTE              (TAS5754M_PAGE_BASE(0) +   3)
+#define TAS5754M_PLL_EN            (TAS5754M_PAGE_BASE(0) +   4)
+#define TAS5754M_DSP               (TAS5754M_PAGE_BASE(0) +   7)
+#define TAS5754M_GPIO_EN           (TAS5754M_PAGE_BASE(0) +   8)
+#define TAS5754M_BCLK_LRCLK_CFG    (TAS5754M_PAGE_BASE(0) +   9)
+#define TAS5754M_DSP_GPIO_INPUT    (TAS5754M_PAGE_BASE(0) +  10)
+#define TAS5754M_MASTER_MODE       (TAS5754M_PAGE_BASE(0) +  12)
+#define TAS5754M_PLL_REF           (TAS5754M_PAGE_BASE(0) +  13)
+#define TAS5754M_DAC_REF           (TAS5754M_PAGE_BASE(0) +  14)
+#define TAS5754M_GPIO_PLLIN        (TAS5754M_PAGE_BASE(0) +  18)
+#define TAS5754M_SYNCHRONIZE       (TAS5754M_PAGE_BASE(0) +  19)
+#define TAS5754M_PLL_COEFF_P       (TAS5754M_PAGE_BASE(0) +  20)
+#define TAS5754M_PLL_COEFF_J       (TAS5754M_PAGE_BASE(0) +  21)
+#define TAS5754M_PLL_COEFF_DH      (TAS5754M_PAGE_BASE(0) +  22)
+#define TAS5754M_PLL_COEFF_DL      (TAS5754M_PAGE_BASE(0) +  23)
+#define TAS5754M_PLL_COEFF_R       (TAS5754M_PAGE_BASE(0) +  24)
+#define TAS5754M_DSP_CLKDIV        (TAS5754M_PAGE_BASE(0) +  27)
+#define TAS5754M_DAC_CLKDIV        (TAS5754M_PAGE_BASE(0) +  28)
+#define TAS5754M_NCP_CLKDIV        (TAS5754M_PAGE_BASE(0) +  29)
+#define TAS5754M_OSR_CLKDIV        (TAS5754M_PAGE_BASE(0) +  30)
+#define TAS5754M_MASTER_SCLKDIV    (TAS5754M_PAGE_BASE(0) +  32)
+#define TAS5754M_MASTER_LRCLKDIV   (TAS5754M_PAGE_BASE(0) +  33)
+#define TAS5754M_FS_SPEED_MODE     (TAS5754M_PAGE_BASE(0) +  34)
+#define TAS5754M_IDAC_1            (TAS5754M_PAGE_BASE(0) +  35)
+#define TAS5754M_IDAC_2            (TAS5754M_PAGE_BASE(0) +  36)
+#define TAS5754M_ERROR_DETECT      (TAS5754M_PAGE_BASE(0) +  37)
+#define TAS5754M_I2S_1             (TAS5754M_PAGE_BASE(0) +  40)
+#define TAS5754M_I2S_2             (TAS5754M_PAGE_BASE(0) +  41)
+#define TAS5754M_DAC_ROUTING       (TAS5754M_PAGE_BASE(0) +  42)
+#define TAS5754M_DSP_PROGRAM       (TAS5754M_PAGE_BASE(0) +  43)
+#define TAS5754M_CLKDET            (TAS5754M_PAGE_BASE(0) +  44)
+#define TAS5754M_AUTO_MUTE         (TAS5754M_PAGE_BASE(0) +  59)
+#define TAS5754M_DIGITAL_VOLUME_1  (TAS5754M_PAGE_BASE(0) +  60)
+#define TAS5754M_DIGITAL_VOLUME_2  (TAS5754M_PAGE_BASE(0) +  61)
+#define TAS5754M_DIGITAL_VOLUME_3  (TAS5754M_PAGE_BASE(0) +  62)
+#define TAS5754M_DIGITAL_MUTE_1    (TAS5754M_PAGE_BASE(0) +  63)
+#define TAS5754M_DIGITAL_MUTE_2    (TAS5754M_PAGE_BASE(0) +  64)
+#define TAS5754M_DIGITAL_MUTE_3    (TAS5754M_PAGE_BASE(0) +  65)
+#define TAS5754M_GPIO_OUTPUT_1     (TAS5754M_PAGE_BASE(0) +  82)
+#define TAS5754M_GPIO_OUTPUT_0     (TAS5754M_PAGE_BASE(0) +  83)
+#define TAS5754M_GPIO_OUTPUT_2     (TAS5754M_PAGE_BASE(0) +  85)
+#define TAS5754M_GPIO_CONTROL_1    (TAS5754M_PAGE_BASE(0) +  86)
+#define TAS5754M_GPIO_CONTROL_2    (TAS5754M_PAGE_BASE(0) +  87)
+#define TAS5754M_OVERFLOW          (TAS5754M_PAGE_BASE(0) +  90)
+#define TAS5754M_RATE_DET_1        (TAS5754M_PAGE_BASE(0) +  91)
+#define TAS5754M_RATE_DET_2        (TAS5754M_PAGE_BASE(0) +  92)
+#define TAS5754M_RATE_DET_3        (TAS5754M_PAGE_BASE(0) +  93)
+#define TAS5754M_RATE_DET_4        (TAS5754M_PAGE_BASE(0) +  94)
+#define TAS5754M_CLOCK_STATUS      (TAS5754M_PAGE_BASE(0) +  95)
+#define TAS5754M_ANALOG_MUTE_DET   (TAS5754M_PAGE_BASE(0) + 108)
+#define TAS5754M_FS_MODE_MON       (TAS5754M_PAGE_BASE(0) + 115)
+#define TAS5754M_GPIN              (TAS5754M_PAGE_BASE(0) + 119)
+#define TAS5754M_DIGITAL_MUTE_DET  (TAS5754M_PAGE_BASE(0) + 120)
+
+#define TAS5754M_OUTPUT_AMPLITUDE  (TAS5754M_PAGE_BASE(1) +   1)
+#define TAS5754M_ANALOG_GAIN_CTRL  (TAS5754M_PAGE_BASE(1) +   2)
+#define TAS5754M_UNDERVOLTAGE_PROT (TAS5754M_PAGE_BASE(1) +   5)
+#define TAS5754M_ANALOG_MUTE_CTRL  (TAS5754M_PAGE_BASE(1) +   6)
+#define TAS5754M_ANALOG_GAIN_BOOST (TAS5754M_PAGE_BASE(1) +   7)
+#define TAS5754M_VCOM_CTRL_1       (TAS5754M_PAGE_BASE(1) +   8)
+#define TAS5754M_VCOM_CTRL_2       (TAS5754M_PAGE_BASE(1) +   9)
+
+#define TAS5754M_CRAM_CTRL         (TAS5754M_PAGE_BASE(44) +  1)
+
+#define TAS5754M_FLEX_A            (TAS5754M_PAGE_BASE(253) + 63)
+#define TAS5754M_FLEX_B            (TAS5754M_PAGE_BASE(253) + 64)
+
+#define TAS5754M_MAX_REGISTER      (TAS5754M_PAGE_BASE(253) + 64)
+
+/* Page 0, Register 1 - reset */
+#define TAS5754M_RSTR (1 << 0)
+#define TAS5754M_RSTM (1 << 4)
+
+/* Page 0, Register 2 - power */
+#define TAS5754M_RQPD       (1 << 0)
+#define TAS5754M_RQPD_SHIFT 0
+#define TAS5754M_RQST       (1 << 4)
+#define TAS5754M_RQST_SHIFT 4
+
+/* Page 0, Register 3 - mute */
+#define TAS5754M_RQMR (1 << 0)
+#define TAS5754M_RQMR_SHIFT 0
+#define TAS5754M_RQML (1 << 4)
+#define TAS5754M_RQML_SHIFT 4
+
+/* Page 0, Register 4 - PLL */
+#define TAS5754M_PLLE       (1 << 0)
+#define TAS5754M_PLLE_SHIFT 0
+#define TAS5754M_PLCK       (1 << 4)
+#define TAS5754M_PLCK_SHIFT 4
+
+/* Page 0, Register 7 - DSP */
+#define TAS5754M_SDSL       (1 << 0)
+#define TAS5754M_SDSL_SHIFT 0
+#define TAS5754M_DEMP       (1 << 4)
+#define TAS5754M_DEMP_SHIFT 4
+
+/* Page 0, Register 8 - GPIO output enable */
+#define TAS5754M_G1OE       (1 << 0)
+#define TAS5754M_G2OE       (1 << 1)
+#define TAS5754M_G3OE       (1 << 2)
+#define TAS5754M_G4OE       (1 << 3)
+#define TAS5754M_G5OE       (1 << 4)
+#define TAS5754M_G6OE       (1 << 5)
+
+/* Page 0, Register 9 - BCK, LRCLK configuration */
+#define TAS5754M_LRKO       (1 << 0)
+#define TAS5754M_LRKO_SHIFT 0
+#define TAS5754M_BCKO       (1 << 4)
+#define TAS5754M_BCKO_SHIFT 4
+#define TAS5754M_BCKP       (1 << 5)
+#define TAS5754M_BCKP_SHIFT 5
+
+/* Page 0, Register 12 - Master mode BCK, LRCLK reset */
+#define TAS5754M_RLRK       (1 << 0)
+#define TAS5754M_RLRK_SHIFT 0
+#define TAS5754M_RBCK       (1 << 1)
+#define TAS5754M_RBCK_SHIFT 1
+
+/* Page 0, Register 13 - PLL reference */
+#define TAS5754M_SREF        (7 << 4)
+#define TAS5754M_SREF_SHIFT  4
+#define TAS5754M_SREF_SCK    (0 << 4)
+#define TAS5754M_SREF_BCK    (1 << 4)
+#define TAS5754M_SREF_GPIO   (3 << 4)
+
+/* Page 0, Register 14 - DAC reference */
+#define TAS5754M_SDAC        (7 << 4)
+#define TAS5754M_SDAC_SHIFT  4
+#define TAS5754M_SDAC_MCK    (0 << 4)
+#define TAS5754M_SDAC_PLL    (1 << 4)
+#define TAS5754M_SDAC_SCK    (3 << 4)
+#define TAS5754M_SDAC_BCK    (4 << 4)
+#define TAS5754M_SDAC_GPIO   (5 << 4)
+
+/* Page 0, Register 16, 18 - GPIO source for DAC, PLL */
+#define TAS5754M_GREF        (7 << 0)
+#define TAS5754M_GREF_SHIFT  0
+#define TAS5754M_GREF_GPIO1  (0 << 0)
+#define TAS5754M_GREF_GPIO2  (1 << 0)
+#define TAS5754M_GREF_GPIO3  (2 << 0)
+#define TAS5754M_GREF_GPIO4  (3 << 0)
+#define TAS5754M_GREF_GPIO5  (4 << 0)
+#define TAS5754M_GREF_GPIO6  (5 << 0)
+
+/* Page 0, Register 19 - synchronize */
+#define TAS5754M_RQSY        (1 << 0)
+#define TAS5754M_RQSY_RESUME (0 << 0)
+#define TAS5754M_RQSY_HALT   (1 << 0)
+
+/* Page 0, Register 34 - fs speed mode */
+#define TAS5754M_FSSP        (3 << 0)
+#define TAS5754M_FSSP_SHIFT  0
+#define TAS5754M_FSSP_48KHZ  (0 << 0)
+#define TAS5754M_FSSP_96KHZ  (1 << 0)
+#define TAS5754M_FSSP_192KHZ (2 << 0)
+#define TAS5754M_FSSP_384KHZ (3 << 0)
+
+/* Page 0, Register 37 - Error detection */
+#define TAS5754M_IPLK (1 << 0)
+#define TAS5754M_DCAS (1 << 1)
+#define TAS5754M_IDCM (1 << 2)
+#define TAS5754M_IDCH (1 << 3)
+#define TAS5754M_IDSK (1 << 4)
+#define TAS5754M_IDBK (1 << 5)
+#define TAS5754M_IDFS (1 << 6)
+
+/* Page 0, Register 40 - I2S configuration */
+#define TAS5754M_ALEN       (3 << 0)
+#define TAS5754M_ALEN_SHIFT 0
+#define TAS5754M_ALEN_16    (0 << 0)
+#define TAS5754M_ALEN_20    (1 << 0)
+#define TAS5754M_ALEN_24    (2 << 0)
+#define TAS5754M_ALEN_32    (3 << 0)
+#define TAS5754M_AFMT       (3 << 4)
+#define TAS5754M_AFMT_SHIFT 4
+#define TAS5754M_AFMT_I2S   (0 << 4)
+#define TAS5754M_AFMT_DSP   (1 << 4)
+#define TAS5754M_AFMT_RTJ   (2 << 4)
+#define TAS5754M_AFMT_LTJ   (3 << 4)
+
+/* Page 0, Register 42 - DAC routing */
+#define TAS5754M_AUPR_SHIFT 0
+#define TAS5754M_AUPL_SHIFT 4
+
+/* Page 0, Register 59 - auto mute */
+#define TAS5754M_ATMR_SHIFT 0
+#define TAS5754M_ATML_SHIFT 4
+
+/* Page 0, Register 63 - ramp rates */
+#define TAS5754M_VNDF_SHIFT 6
+#define TAS5754M_VNDS_SHIFT 4
+#define TAS5754M_VNUF_SHIFT 2
+#define TAS5754M_VNUS_SHIFT 0
+
+/* Page 0, Register 64 - emergency ramp rates */
+#define TAS5754M_VEDF_SHIFT 6
+#define TAS5754M_VEDS_SHIFT 4
+
+/* Page 0, Register 65 - Digital mute enables */
+#define TAS5754M_ACTL_SHIFT 2
+#define TAS5754M_AMLE_SHIFT 1
+#define TAS5754M_AMRE_SHIFT 0
+
+/* Page 0, Register 80-85, GPIO output selection */
+#define TAS5754M_GxSL       (31 << 0)
+#define TAS5754M_GxSL_SHIFT 0
+#define TAS5754M_GxSL_OFF   (0 << 0)
+#define TAS5754M_GxSL_DSP   (1 << 0)
+#define TAS5754M_GxSL_REG   (2 << 0)
+#define TAS5754M_GxSL_AMUTB (3 << 0)
+#define TAS5754M_GxSL_AMUTL (4 << 0)
+#define TAS5754M_GxSL_AMUTR (5 << 0)
+#define TAS5754M_GxSL_CLKI  (6 << 0)
+#define TAS5754M_GxSL_SDOUT (7 << 0)
+#define TAS5754M_GxSL_ANMUL (8 << 0)
+#define TAS5754M_GxSL_ANMUR (9 << 0)
+#define TAS5754M_GxSL_PLLLK (10 << 0)
+#define TAS5754M_GxSL_CPCLK (11 << 0)
+#define TAS5754M_GxSL_UV0_7 (14 << 0)
+#define TAS5754M_GxSL_UV0_3 (15 << 0)
+#define TAS5754M_GxSL_PLLCK (16 << 0)
+
+/* Page 1, Register 2 - analog volume control */
+#define TAS5754M_RAGN_SHIFT 0
+#define TAS5754M_LAGN_SHIFT 4
+
+/* Page 1, Register 7 - analog boost control */
+#define TAS5754M_AGBR_SHIFT 0
+#define TAS5754M_AGBL_SHIFT 4
+
+#endif
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH v5] ASoC: adds component driver for TAS575xM digital amplifiers
       [not found] <20211029095414.29131-1-joerg@hifiberry.com>
@ 2022-01-20 14:12   ` Joerg Schambacher
  2022-01-10  8:45   ` Joerg Schambacher
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 21+ messages in thread
From: Joerg Schambacher @ 2022-01-20 14:12 UTC (permalink / raw)
  To: Cezary Rojewski, alsa-devel, Mark Brown; +Cc: joerg, kbuild-all

On Thu, Jan 20, 2022 at 02:18:26AM +0800, kernel test robot wrote:
> tree:   https://github.com/0day-ci/linux/commits/UPDATE-20220119-210919/Joerg-Schambacher/ASoC-adds-component-driver-for-TAS575xM-digital-amplifiers/20220110-164852
> head:   05b8bf5544bc621031f5a0a6bdf1ac6468a7367b
> commit: 05b8bf5544bc621031f5a0a6bdf1ac6468a7367b ASoC: adds component driver for TAS575xM digital amplifiers
> date:   5 hours ago
> config: riscv-randconfig-c006-20220118 (https://download.01.org/0day-ci/archive/20220120/202201200259.nNgbKOJd-lkp@intel.com/config)
> compiler: clang version 14.0.0 (https://github.com/llvm/llvm-project f7b7138a62648f4019c55e4671682af1f851f295)
> reproduce (this is a W=1 build):
>         wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
>         chmod +x ~/bin/make.cross
>         # install riscv cross compiling tool for clang build
>         # apt-get install binutils-riscv64-linux-gnu
>         # https://github.com/0day-ci/linux/commit/05b8bf5544bc621031f5a0a6bdf1ac6468a7367b
>         git remote add linux-review https://github.com/0day-ci/linux
>         git fetch --no-tags linux-review UPDATE-20220119-210919/Joerg-Schambacher/ASoC-adds-component-driver-for-TAS575xM-digital-amplifiers/20220110-164852
>         git checkout 05b8bf5544bc621031f5a0a6bdf1ac6468a7367b
>         # save the config file to linux build tree
>         mkdir build_dir
>         COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=riscv SHELL=/bin/bash sound/soc/codecs/
> 
> If you fix the issue, kindly add following tag as appropriate
> Reported-by: kernel test robot <lkp@intel.com>
> 
> All warnings (new ones prefixed by >>):
> 
> >> sound/soc/codecs/tas5754m.c:246:7: warning: variable 'ret' is used uninitialized whenever switch case is taken [-Wsometimes-uninitialized]
>            case SND_SOC_BIAS_ON:
>                 ^~~~~~~~~~~~~~~
>    sound/soc/codecs/tas5754m.c:267:9: note: uninitialized use occurs here
>            return ret;
>                   ^~~
>    sound/soc/codecs/tas5754m.c:247:7: warning: variable 'ret' is used uninitialized whenever switch case is taken [-Wsometimes-uninitialized]
>            case SND_SOC_BIAS_PREPARE:
>                 ^~~~~~~~~~~~~~~~~~~~
>    sound/soc/codecs/tas5754m.c:267:9: note: uninitialized use occurs here
>            return ret;
>                   ^~~
>    sound/soc/codecs/tas5754m.c:242:9: note: initialize the variable 'ret' to silence this warning
>            int ret;
>                   ^
>                    = 0
>    2 warnings generated.
> 
> 
> vim +/ret +246 sound/soc/codecs/tas5754m.c
> 
>    236	
>    237	static int tas5754m_set_bias_level(struct snd_soc_component *component,
>    238					   enum snd_soc_bias_level level)
>    239	{
>    240		struct tas5754m_priv *tas5754m =
>    241					snd_soc_component_get_drvdata(component);
>    242		int ret;
>    243	
>    244		switch (level) {
>    245		default:
>  > 246		case SND_SOC_BIAS_ON:
>    247		case SND_SOC_BIAS_PREPARE:
>    248			break;
>    249	
>    250		case SND_SOC_BIAS_STANDBY:
>    251			ret = regmap_update_bits(tas5754m->regmap,
>    252					TAS5754M_POWER, TAS5754M_RQST, 0);
>    253			if (ret)
>    254				dev_err(component->dev,
>    255					"Failed to remove standby: %d\n", ret);
>    256			break;
>    257	
>    258		case SND_SOC_BIAS_OFF:
>    259			ret = regmap_update_bits(tas5754m->regmap,
>    260					TAS5754M_POWER, TAS5754M_RQST, TAS5754M_RQST);
>    261			if (ret)
>    262				dev_err(component->dev,
>    263					"Failed to request standby: %d\n", ret);
>    264			break;
>    265		}
>    266	
>    267		return ret;
>    268	}
>    269	
> 
> ---
> 0-DAY CI Kernel Test Service, Intel Corporation
> https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
all, fixed.
Joerg

From 331a880edff308e8f0608f72f244c25e56162e24 Mon Sep 17 00:00:00 2001
From: Joerg Schambacher <joerg@hifiberry.com>
Date: Tue, 5 Oct 2021 14:38:21 +0200
Subject: [PATCH] ASoC: adds component driver for TAS575xM digital amplifiers

Adds a minimum component driver to run the amplifier in I2S master
mode only from standard audio clocks. Therefore, it only allows
44.1, 88.2, 176.4, 48, 96 and 192ksps with 16, 20, 24 and 32 bits
sample size. Digital volume control and the -6dB and +0.8dB switches
are supported.

Signed-off-by: Joerg Schambacher <joerg@hifiberry.com>
---
 sound/soc/codecs/Kconfig    |   8 +
 sound/soc/codecs/Makefile   |   2 +
 sound/soc/codecs/tas5754m.c | 691 ++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/tas5754m.h | 260 ++++++++++++++
 4 files changed, 961 insertions(+)
 create mode 100644 sound/soc/codecs/tas5754m.c
 create mode 100644 sound/soc/codecs/tas5754m.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 82ee233a269d..cf0584948fcf 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -210,6 +210,7 @@ config SND_SOC_ALL_CODECS
 	imply SND_SOC_TAS5086
 	imply SND_SOC_TAS571X
 	imply SND_SOC_TAS5720
+	imply SND_SOC_TAS5754M
 	imply SND_SOC_TAS6424
 	imply SND_SOC_TDA7419
 	imply SND_SOC_TFA9879
@@ -1419,6 +1420,13 @@ config SND_SOC_TAS5720
 	  Enable support for Texas Instruments TAS5720L/M high-efficiency mono
 	  Class-D audio power amplifiers.
 
+config SND_SOC_TAS5754M
+	tristate "Texas Instruments TAS5754M Digital Input Audio amplifier"
+	depends on I2C
+	help
+	  Enable support for Texas Instruments TAS5754M digital input
+	  Class-D audio power amplifiers.
+
 config SND_SOC_TAS6424
 	tristate "Texas Instruments TAS6424 Quad-Channel Audio amplifier"
 	depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 8dcea2c4604a..39984900258a 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -227,6 +227,7 @@ snd-soc-sti-sas-objs := sti-sas.o
 snd-soc-tas5086-objs := tas5086.o
 snd-soc-tas571x-objs := tas571x.o
 snd-soc-tas5720-objs := tas5720.o
+snd-soc-tas5754m-objs := tas5754m.o
 snd-soc-tas6424-objs := tas6424.o
 snd-soc-tda7419-objs := tda7419.o
 snd-soc-tas2770-objs := tas2770.o
@@ -555,6 +556,7 @@ obj-$(CONFIG_SND_SOC_TAS2764)	+= snd-soc-tas2764.o
 obj-$(CONFIG_SND_SOC_TAS5086)	+= snd-soc-tas5086.o
 obj-$(CONFIG_SND_SOC_TAS571X)	+= snd-soc-tas571x.o
 obj-$(CONFIG_SND_SOC_TAS5720)	+= snd-soc-tas5720.o
+obj-$(CONFIG_SND_SOC_TAS5754M)	+= snd-soc-tas5754m.o
 obj-$(CONFIG_SND_SOC_TAS6424)	+= snd-soc-tas6424.o
 obj-$(CONFIG_SND_SOC_TDA7419)	+= snd-soc-tda7419.o
 obj-$(CONFIG_SND_SOC_TAS2770) += snd-soc-tas2770.o
diff --git a/sound/soc/codecs/tas5754m.c b/sound/soc/codecs/tas5754m.c
new file mode 100644
index 000000000000..06c10002f32e
--- /dev/null
+++ b/sound/soc/codecs/tas5754m.c
@@ -0,0 +1,691 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for the TAS5754M Audio Amplifier
+ *
+ * Author: Joerg Schambacher <joerg@hifiberry.com>
+ *         with fragments from Andy Liu <andy-liu@ti.com>
+ *
+ * The driver supports I2S master mode only with standard audio
+ * frequencies 44.1 to 192 ksps from a 24.576/22.2592MHz master
+ * clock input
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+
+#include "tas5754m.h"
+
+#define TAS5754M_RATES		(SNDRV_PCM_RATE_48000  | \
+				 SNDRV_PCM_RATE_96000  | \
+				 SNDRV_PCM_RATE_192000 | \
+				 SNDRV_PCM_RATE_44100  | \
+				 SNDRV_PCM_RATE_88200  | \
+				 SNDRV_PCM_RATE_176400)
+#define TAS5754M_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE  | \
+				 SNDRV_PCM_FMTBIT_S20_LE  | \
+				 SNDRV_PCM_FMTBIT_S24_LE  | \
+				 SNDRV_PCM_FMTBIT_S32_LE)
+
+
+static const struct reg_default tas5754m_reg_defaults[] = {
+	{ TAS5754M_RESET,             0x00 },
+	{ TAS5754M_POWER,             0x00 },
+	{ TAS5754M_MUTE,              0x00 },
+	{ TAS5754M_DSP,               0x00 },
+	{ TAS5754M_PLL_REF,           0x00 },
+	{ TAS5754M_DAC_REF,           0x00 },
+	{ TAS5754M_DAC_ROUTING,       0x11 },
+	{ TAS5754M_DSP_PROGRAM,       0x01 },
+	{ TAS5754M_CLKDET,            0x00 },
+	{ TAS5754M_AUTO_MUTE,         0x00 },
+	{ TAS5754M_ERROR_DETECT,      0x00 },
+	{ TAS5754M_DIGITAL_VOLUME_1,  0x00 },
+	{ TAS5754M_DIGITAL_VOLUME_2,  0x30 },
+	{ TAS5754M_DIGITAL_VOLUME_3,  0x30 },
+	{ TAS5754M_DIGITAL_MUTE_1,    0x22 },
+	{ TAS5754M_DIGITAL_MUTE_2,    0x00 },
+	{ TAS5754M_DIGITAL_MUTE_3,    0x07 },
+	{ TAS5754M_OUTPUT_AMPLITUDE,  0x00 },
+	{ TAS5754M_ANALOG_GAIN_CTRL,  0x00 },
+	{ TAS5754M_UNDERVOLTAGE_PROT, 0x00 },
+	{ TAS5754M_ANALOG_MUTE_CTRL,  0x00 },
+	{ TAS5754M_ANALOG_GAIN_BOOST, 0x00 },
+	{ TAS5754M_VCOM_CTRL_1,       0x00 },
+	{ TAS5754M_VCOM_CTRL_2,       0x01 },
+	{ TAS5754M_BCLK_LRCLK_CFG,    0x00 },
+	{ TAS5754M_MASTER_MODE,       0x7c },
+	{ TAS5754M_GPIO_PLLIN,        0x00 },
+	{ TAS5754M_SYNCHRONIZE,       0x10 },
+	{ TAS5754M_PLL_COEFF_P,       0x00 },
+	{ TAS5754M_PLL_COEFF_J,       0x00 },
+	{ TAS5754M_PLL_COEFF_DH,      0x00 },
+	{ TAS5754M_PLL_COEFF_DL,      0x00 },
+	{ TAS5754M_PLL_COEFF_R,       0x00 },
+	{ TAS5754M_DSP_CLKDIV,        0x00 },
+	{ TAS5754M_DAC_CLKDIV,        0x00 },
+	{ TAS5754M_NCP_CLKDIV,        0x00 },
+	{ TAS5754M_OSR_CLKDIV,        0x00 },
+	{ TAS5754M_MASTER_SCLKDIV,    0x00 },
+	{ TAS5754M_MASTER_LRCLKDIV,   0x00 },
+	{ TAS5754M_FS_SPEED_MODE,     0x00 },
+	{ TAS5754M_IDAC_1,            0x01 },
+	{ TAS5754M_IDAC_2,            0x00 },
+};
+
+static bool tas5754m_readable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TAS5754M_RESET:
+	case TAS5754M_POWER:
+	case TAS5754M_MUTE:
+	case TAS5754M_PLL_EN:
+	case TAS5754M_DSP:
+	case TAS5754M_GPIO_EN:
+	case TAS5754M_BCLK_LRCLK_CFG:
+	case TAS5754M_DSP_GPIO_INPUT:
+	case TAS5754M_MASTER_MODE:
+	case TAS5754M_PLL_REF:
+	case TAS5754M_DAC_REF:
+	case TAS5754M_GPIO_PLLIN:
+	case TAS5754M_SYNCHRONIZE:
+	case TAS5754M_PLL_COEFF_P:
+	case TAS5754M_PLL_COEFF_J:
+	case TAS5754M_PLL_COEFF_DH:
+	case TAS5754M_PLL_COEFF_DL:
+	case TAS5754M_PLL_COEFF_R:
+	case TAS5754M_DSP_CLKDIV:
+	case TAS5754M_DAC_CLKDIV:
+	case TAS5754M_NCP_CLKDIV:
+	case TAS5754M_OSR_CLKDIV:
+	case TAS5754M_MASTER_SCLKDIV:
+	case TAS5754M_MASTER_LRCLKDIV:
+	case TAS5754M_FS_SPEED_MODE:
+	case TAS5754M_IDAC_1:
+	case TAS5754M_IDAC_2:
+	case TAS5754M_ERROR_DETECT:
+	case TAS5754M_I2S_1:
+	case TAS5754M_I2S_2:
+	case TAS5754M_DAC_ROUTING:
+	case TAS5754M_DSP_PROGRAM:
+	case TAS5754M_CLKDET:
+	case TAS5754M_AUTO_MUTE:
+	case TAS5754M_DIGITAL_VOLUME_1:
+	case TAS5754M_DIGITAL_VOLUME_2:
+	case TAS5754M_DIGITAL_VOLUME_3:
+	case TAS5754M_DIGITAL_MUTE_1:
+	case TAS5754M_DIGITAL_MUTE_2:
+	case TAS5754M_DIGITAL_MUTE_3:
+	case TAS5754M_GPIO_OUTPUT_0:
+	case TAS5754M_GPIO_OUTPUT_1:
+	case TAS5754M_GPIO_OUTPUT_2:
+	case TAS5754M_GPIO_CONTROL_1:
+	case TAS5754M_GPIO_CONTROL_2:
+	case TAS5754M_OVERFLOW:
+	case TAS5754M_RATE_DET_1:
+	case TAS5754M_RATE_DET_2:
+	case TAS5754M_RATE_DET_3:
+	case TAS5754M_RATE_DET_4:
+	case TAS5754M_CLOCK_STATUS:
+	case TAS5754M_ANALOG_MUTE_DET:
+	case TAS5754M_GPIN:
+	case TAS5754M_DIGITAL_MUTE_DET:
+	case TAS5754M_OUTPUT_AMPLITUDE:
+	case TAS5754M_ANALOG_GAIN_CTRL:
+	case TAS5754M_UNDERVOLTAGE_PROT:
+	case TAS5754M_ANALOG_MUTE_CTRL:
+	case TAS5754M_ANALOG_GAIN_BOOST:
+	case TAS5754M_VCOM_CTRL_1:
+	case TAS5754M_VCOM_CTRL_2:
+	case TAS5754M_CRAM_CTRL:
+	case TAS5754M_FLEX_A:
+	case TAS5754M_FLEX_B:
+		return true;
+	default:
+		return reg < 0x7f;
+	}
+}
+
+static bool tas5754m_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TAS5754M_PLL_EN:
+	case TAS5754M_OVERFLOW:
+	case TAS5754M_RATE_DET_1:
+	case TAS5754M_RATE_DET_2:
+	case TAS5754M_RATE_DET_3:
+	case TAS5754M_RATE_DET_4:
+	case TAS5754M_CLOCK_STATUS:
+	case TAS5754M_ANALOG_MUTE_DET:
+	case TAS5754M_GPIN:
+	case TAS5754M_DIGITAL_MUTE_DET:
+	case TAS5754M_CRAM_CTRL:
+		return true;
+	default:
+		return reg < 0x7f;
+	}
+}
+
+struct tas5754m_priv {
+	struct regmap *regmap;
+	struct clk *sclk;
+	int sample_len;
+	int fmt;
+	int mode;
+};
+
+static const struct regmap_range_cfg tas5754m_range = {
+	.name = "Pages",
+	.range_min = TAS5754M_VIRT_BASE,
+	.range_max = TAS5754M_MAX_REGISTER,
+	.selector_reg = TAS5754M_PAGE,
+	.selector_mask = 0x7f,
+	.window_start = 0,
+	.window_len = 128,
+};
+
+const struct regmap_config tas5754m_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.ranges = &tas5754m_range,
+	.num_ranges = 1,
+	.max_register = TAS5754M_MAX_REGISTER,
+
+	.reg_defaults = tas5754m_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(tas5754m_reg_defaults),
+	.readable_reg = tas5754m_readable,
+	.volatile_reg = tas5754m_volatile,
+
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1);
+static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0);
+
+static const struct snd_kcontrol_new tas5754m_controls[] = {
+SOC_DOUBLE_R_TLV("Digital Playback Volume", TAS5754M_DIGITAL_VOLUME_2,
+		 TAS5754M_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv),
+SOC_DOUBLE_TLV("Analog Playback Volume", TAS5754M_ANALOG_GAIN_CTRL,
+	     TAS5754M_LAGN_SHIFT, TAS5754M_RAGN_SHIFT, 1, 1, analog_tlv),
+SOC_DOUBLE_TLV("Analogue Playback Boost Volume", TAS5754M_ANALOG_GAIN_BOOST,
+	       TAS5754M_AGBL_SHIFT, TAS5754M_AGBR_SHIFT, 1, 0, boost_tlv),
+};
+
+static int tas5754m_set_bias_level(struct snd_soc_component *component,
+				   enum snd_soc_bias_level level)
+{
+	struct tas5754m_priv *tas5754m =
+				snd_soc_component_get_drvdata(component);
+	int ret = 0;
+
+	switch (level) {
+	default:
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		ret = regmap_update_bits(tas5754m->regmap,
+				TAS5754M_POWER, TAS5754M_RQST, 0);
+		if (ret)
+			dev_err(component->dev,
+				"Failed to remove standby: %d\n", ret);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		ret = regmap_update_bits(tas5754m->regmap,
+				TAS5754M_POWER, TAS5754M_RQST, TAS5754M_RQST);
+		if (ret)
+			dev_err(component->dev,
+				"Failed to request standby: %d\n", ret);
+		break;
+	}
+
+	return ret;
+}
+
+static int tas5754m_set_clock_tree_master(struct snd_soc_dai *dai,
+					  struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+	static const struct reg_sequence pll_settings[] = {
+		{ TAS5754M_PLL_COEFF_P,		0x01 },	// P=2
+		{ TAS5754M_PLL_COEFF_J,		0x08 },	// J=8
+		{ TAS5754M_PLL_COEFF_DL,	0x00 },	// D12-8 = 0
+		{ TAS5754M_PLL_COEFF_DH,	0x00 },	// D7-0 = 0
+		{ TAS5754M_PLL_COEFF_R,		0x00 },	// R=1
+	};
+	int ret;
+
+	/* disable PLL before any clock tree change */
+	ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
+				 TAS5754M_PLLE, 0);
+	if (ret) {
+		dev_err(component->dev, "Failed to disable PLL\n");
+		return ret;
+	}
+	/* set DAC clock source to MCLK */
+	ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_REF, 0x30);
+	if (ret) {
+		dev_err(component->dev, "Failed to set DAC ref\n");
+		return ret;
+	}
+	/* run PLL at fixed ratio to MCLK */
+	ret = regmap_multi_reg_write(tas5754m->regmap, pll_settings,
+					ARRAY_SIZE(pll_settings));
+	if (ret) {
+		dev_err(component->dev, "Failed to set PLL ratio\n");
+		return ret;
+	}
+	/* set DSP divider to 2 => reg 0x01 */
+	ret = regmap_write(tas5754m->regmap, TAS5754M_DSP_CLKDIV, 1);
+	if (ret) {
+		dev_err(component->dev, "Failed to set DSP divider\n");
+		return ret;
+	}
+	/* set DAC divider to 4 => reg 0x03*/
+	ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_CLKDIV, 3);
+	if (ret) {
+		dev_err(component->dev, "Failed to set OSDACR divider\n");
+		return ret;
+	}
+	/* set OSR divider to 1 */
+	ret = regmap_write(tas5754m->regmap, TAS5754M_OSR_CLKDIV, 0);
+	if (ret) {
+		dev_err(component->dev, "Failed to set OSR divider\n");
+		return ret;
+	}
+	/* set CP divider to 4 => reg 0x03*/
+	ret = regmap_write(tas5754m->regmap, TAS5754M_NCP_CLKDIV, 3);
+	if (ret) {
+		dev_err(component->dev, "Failed to set CP divider\n");
+		return ret;
+	}
+	/* finally enable PLL */
+	ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
+				 TAS5754M_PLLE, 1);
+	if (ret) {
+		dev_err(component->dev, "Failed to enable PLL\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tas5754m_set_dai_mode(struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+	int fmt = tas5754m->fmt;
+
+	/* only I2S MASTER mode implemented */
+	if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S) {
+		dev_err(component->dev,
+			"DAI format not supported (I2S master only)\n");
+		return -EINVAL;
+	}
+
+	/* TAS5754/6m do not support inverted clocks in MASTER mode */
+	if ((fmt & SND_SOC_DAIFMT_CLOCK_MASK) != SND_SOC_DAIFMT_NB_NF) {
+		dev_err(component->dev,	"Inverted clocks not supported\n");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		regmap_update_bits(tas5754m->regmap,
+				TAS5754M_BCLK_LRCLK_CFG,
+				TAS5754M_LRKO | TAS5754M_BCKO,
+				TAS5754M_LRKO | TAS5754M_BCKO);
+		/* reset CLK dividers */
+		regmap_update_bits(tas5754m->regmap,
+				TAS5754M_MASTER_MODE,
+				0x00,
+				TAS5754M_RLRK | TAS5754M_RBCK);
+		/* ignore all clock error detection but MCLK */
+		regmap_update_bits(tas5754m->regmap,
+				TAS5754M_ERROR_DETECT,
+				TAS5754M_IPLK | TAS5754M_DCAS |
+				TAS5754M_IDCM | TAS5754M_IDSK |
+				TAS5754M_IDBK | TAS5754M_IDFS,
+				TAS5754M_IPLK | TAS5754M_DCAS |
+				TAS5754M_IDCM | TAS5754M_IDSK |
+				TAS5754M_IDBK | TAS5754M_IDFS);
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+	case SND_SOC_DAIFMT_CBM_CFS:
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int tas5754m_set_dividers_master(struct snd_soc_dai *dai,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+	unsigned long bclk;
+	unsigned long mclk;
+	int bclk_div;
+	int lrclk_div;
+	int osr;
+	int ret;
+
+	/* calculate divider settings based on mclk and sample_len */
+	mclk = clk_get_rate(tas5754m->sclk);
+	bclk = tas5754m->sample_len * 2 * params_rate(params);
+	bclk_div = mclk / bclk;
+	lrclk_div = tas5754m->sample_len * 2;
+	osr = mclk / 4 / params_rate(params) / 16;
+
+	/* stop LR / SCLK clocks */
+	ret = regmap_update_bits(tas5754m->regmap,
+				TAS5754M_MASTER_MODE, 0,
+				TAS5754M_RLRK | TAS5754M_RBCK);
+	if (ret) {
+		dev_err(component->dev, "Failed to stop PLL\n");
+		return ret;
+	}
+	/* set SCLK divider */
+	ret = regmap_write(tas5754m->regmap, TAS5754M_MASTER_SCLKDIV,
+								bclk_div - 1);
+	if (ret) {
+		dev_err(component->dev, "Failed to set SCLK divider\n");
+		return ret;
+	}
+	/* set LRCLK divider */
+	ret = regmap_write(tas5754m->regmap, TAS5754M_MASTER_LRCLKDIV,
+								lrclk_div - 1);
+	if (ret) {
+		dev_err(component->dev, "Failed to set LRCLK divider\n");
+		return ret;
+	}
+	ret = regmap_write(tas5754m->regmap,
+		TAS5754M_OSR_CLKDIV, osr - 1);
+	if (ret) {
+		dev_err(component->dev, "Failed to set OSR divider\n");
+		return ret;
+	}
+	/* restart LR / SCLK clocks */
+	ret = regmap_update_bits(tas5754m->regmap,
+				TAS5754M_MASTER_MODE,
+				TAS5754M_RLRK | TAS5754M_RBCK,
+				TAS5754M_RLRK | TAS5754M_RBCK);
+	if (ret) {
+		dev_err(component->dev, "Failed to restart PLL\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tas5754m_hw_params(struct snd_pcm_substream *substream,
+			      struct snd_pcm_hw_params *params,
+			      struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+	int alen;
+	int ret;
+
+	switch (params_width(params)) {
+	case 16:
+		tas5754m->sample_len = 16;
+		alen = TAS5754M_ALEN_16;
+		break;
+	case 20:
+		tas5754m->sample_len = 32;
+		alen = TAS5754M_ALEN_20;
+		break;
+	case 24:
+		tas5754m->sample_len = 32;
+		alen = TAS5754M_ALEN_24;
+		break;
+	case 32:
+		tas5754m->sample_len = 32;
+		alen = TAS5754M_ALEN_32;
+		break;
+	default:
+		dev_err(component->dev, "Unsupported sample size: %d\n",
+			params_width(params));
+		return -EINVAL;
+	}
+	ret = regmap_update_bits(tas5754m->regmap, TAS5754M_I2S_1, alen, alen);
+	if (ret) {
+		dev_err(component->dev,
+			"Cannot set sample size: %d\n", ret);
+		return ret;
+	}
+
+	ret = tas5754m_set_dai_mode(dai);
+	if (ret) {
+		dev_err(component->dev,
+			"DAI mode not supported: %d\n", ret);
+		return ret;
+	}
+
+	ret = tas5754m_set_clock_tree_master(dai, params);
+	if (ret)
+		return ret;
+
+	switch (params_rate(params)) {
+	case 44100:
+	case 48000:
+		ret = regmap_write(tas5754m->regmap,
+			TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_48KHZ);
+		break;
+	case 88200:
+	case 96000:
+		ret = regmap_write(tas5754m->regmap,
+			TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_96KHZ);
+		break;
+	case 176400:
+	case 192000:
+		ret = regmap_write(tas5754m->regmap,
+			TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_192KHZ);
+		break;
+	default:
+		dev_err(component->dev, "Sample rate not supported: %d\n",
+			params_rate(params));
+		return -EINVAL;
+	}
+	if (ret) {
+		dev_err(component->dev, "Failed to config PLL\n");
+		return ret;
+	}
+
+	ret = tas5754m_set_dividers_master(dai, params);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int tas5754m_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+
+	tas5754m->fmt = fmt;
+
+	return 0;
+}
+
+
+static const struct snd_soc_component_driver tas5754m_soc_component = {
+	.set_bias_level = tas5754m_set_bias_level,
+	.idle_bias_on = true,
+	.controls = tas5754m_controls,
+	.num_controls = ARRAY_SIZE(tas5754m_controls),
+};
+
+static int tas5754m_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+	struct snd_soc_component *component = dai->component;
+
+	if (mute) {
+		snd_soc_component_write(component, TAS5754M_MUTE, 0x11);
+	} else {
+		/* wait for stable operation before unmute */
+		usleep_range(1000, 2000);
+		snd_soc_component_write(component, TAS5754M_MUTE, 0x00);
+	}
+	return 0;
+}
+
+static const struct snd_soc_dai_ops tas5754m_dai_ops = {
+	.mute_stream = tas5754m_mute,
+	.hw_params = tas5754m_hw_params,
+	.set_fmt = tas5754m_set_fmt,
+};
+
+static struct snd_soc_dai_driver tas5754m_dai = {
+	.name		= "tas5754m-amplifier",
+	.playback	= {
+		.stream_name	= "Playback",
+		.channels_min	= 2,
+		.channels_max	= 2,
+		.rates		= TAS5754M_RATES,
+		.formats	= TAS5754M_FORMATS,
+	},
+	.ops = &tas5754m_dai_ops,
+};
+
+static int tas5754m_probe(struct device *dev, struct regmap *regmap)
+{
+	struct tas5754m_priv *tas5754m;
+	int ret;
+
+	tas5754m = devm_kzalloc(dev, sizeof(struct tas5754m_priv), GFP_KERNEL);
+	if (!tas5754m)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, tas5754m);
+	tas5754m->regmap = regmap;
+
+	ret = regmap_write(regmap, TAS5754M_RESET,
+			TAS5754M_RSTR | TAS5754M_RSTM);
+	if (ret) {
+		dev_err(dev, "Failed to initialize TAS5754M: %d\n", ret);
+		goto err;
+	}
+
+	tas5754m->sclk = devm_clk_get(dev, NULL);
+	if (PTR_ERR(tas5754m->sclk) == -EPROBE_DEFER) {
+		ret = -EPROBE_DEFER;
+		goto err;
+	}
+	if (!IS_ERR(tas5754m->sclk)) {
+		ret = clk_prepare_enable(tas5754m->sclk);
+		if (ret) {
+			dev_err(dev, "Failed to enable SCLK: %d\n", ret);
+			goto err;
+		}
+	}
+
+	ret = devm_snd_soc_register_component(dev,
+			&tas5754m_soc_component, &tas5754m_dai, 1);
+	if (ret) {
+		dev_err(dev, "Failed to register CODEC: %d\n", ret);
+		goto err;
+	}
+
+	return 0;
+
+err:
+	return ret;
+
+}
+
+static int tas5754m_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+{
+	struct regmap *regmap;
+	struct regmap_config config = tas5754m_regmap;
+
+	/* enable auto-increment mode */
+	config.read_flag_mask = 0x80;
+	config.write_flag_mask = 0x80;
+
+	regmap = devm_regmap_init_i2c(i2c, &config);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return tas5754m_probe(&i2c->dev, regmap);
+}
+
+static int tas5754m_remove(struct device *dev)
+{
+	snd_soc_unregister_component(dev);
+
+	return 0;
+}
+
+static int tas5754m_i2c_remove(struct i2c_client *i2c)
+{
+	tas5754m_remove(&i2c->dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id tas5754m_i2c_id[] = {
+	{ "tas5754m", },
+	{ "tas5756m", },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tas5754m_i2c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id tas5754m_of_match[] = {
+	{ .compatible = "ti,tas5754m", },
+	{ .compatible = "ti,tas5756m", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, tas5754m_of_match);
+#endif
+
+static struct i2c_driver tas5754m_i2c_driver = {
+	.probe		= tas5754m_i2c_probe,
+	.remove		= tas5754m_i2c_remove,
+	.id_table	= tas5754m_i2c_id,
+	.driver		= {
+		.name	= "tas5754m",
+		.of_match_table = of_match_ptr(tas5754m_of_match),
+	},
+};
+
+module_i2c_driver(tas5754m_i2c_driver);
+
+MODULE_AUTHOR("Joerg Schambacher <joerg@hifiberry.com>");
+MODULE_DESCRIPTION("TAS5754M Audio Amplifier Driver - Master mode only");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas5754m.h b/sound/soc/codecs/tas5754m.h
new file mode 100644
index 000000000000..c6e26dba169f
--- /dev/null
+++ b/sound/soc/codecs/tas5754m.h
@@ -0,0 +1,260 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Driver for the TAS575xM DAC+amplifier combo devices
+ *
+ * Author:	(copied from pcm512x.h)
+ *		Mark Brown <broonie@kernel.org>
+ *		Copyright 2014 Linaro Ltd
+ *
+ *		Register names adapted and non available
+ *		register definitions removed according
+ +		to TAS5754M specification
+ *		Joerg Schambacher <joerg@hifiberry.com>
+ */
+
+#ifndef _SND_SOC_TAS5754M
+#define _SND_SOC_TAS5754M
+
+#include <linux/pm.h>
+#include <linux/regmap.h>
+
+#define TAS5754M_VIRT_BASE 0x000
+#define TAS5754M_PAGE_LEN  0x80
+#define TAS5754M_PAGE_BASE(n)  (TAS5754M_VIRT_BASE + (TAS5754M_PAGE_LEN * n))
+
+#define TAS5754M_PAGE              0
+
+#define TAS5754M_RESET             (TAS5754M_PAGE_BASE(0) +   1)
+#define TAS5754M_POWER             (TAS5754M_PAGE_BASE(0) +   2)
+#define TAS5754M_MUTE              (TAS5754M_PAGE_BASE(0) +   3)
+#define TAS5754M_PLL_EN            (TAS5754M_PAGE_BASE(0) +   4)
+#define TAS5754M_DSP               (TAS5754M_PAGE_BASE(0) +   7)
+#define TAS5754M_GPIO_EN           (TAS5754M_PAGE_BASE(0) +   8)
+#define TAS5754M_BCLK_LRCLK_CFG    (TAS5754M_PAGE_BASE(0) +   9)
+#define TAS5754M_DSP_GPIO_INPUT    (TAS5754M_PAGE_BASE(0) +  10)
+#define TAS5754M_MASTER_MODE       (TAS5754M_PAGE_BASE(0) +  12)
+#define TAS5754M_PLL_REF           (TAS5754M_PAGE_BASE(0) +  13)
+#define TAS5754M_DAC_REF           (TAS5754M_PAGE_BASE(0) +  14)
+#define TAS5754M_GPIO_PLLIN        (TAS5754M_PAGE_BASE(0) +  18)
+#define TAS5754M_SYNCHRONIZE       (TAS5754M_PAGE_BASE(0) +  19)
+#define TAS5754M_PLL_COEFF_P       (TAS5754M_PAGE_BASE(0) +  20)
+#define TAS5754M_PLL_COEFF_J       (TAS5754M_PAGE_BASE(0) +  21)
+#define TAS5754M_PLL_COEFF_DH      (TAS5754M_PAGE_BASE(0) +  22)
+#define TAS5754M_PLL_COEFF_DL      (TAS5754M_PAGE_BASE(0) +  23)
+#define TAS5754M_PLL_COEFF_R       (TAS5754M_PAGE_BASE(0) +  24)
+#define TAS5754M_DSP_CLKDIV        (TAS5754M_PAGE_BASE(0) +  27)
+#define TAS5754M_DAC_CLKDIV        (TAS5754M_PAGE_BASE(0) +  28)
+#define TAS5754M_NCP_CLKDIV        (TAS5754M_PAGE_BASE(0) +  29)
+#define TAS5754M_OSR_CLKDIV        (TAS5754M_PAGE_BASE(0) +  30)
+#define TAS5754M_MASTER_SCLKDIV    (TAS5754M_PAGE_BASE(0) +  32)
+#define TAS5754M_MASTER_LRCLKDIV   (TAS5754M_PAGE_BASE(0) +  33)
+#define TAS5754M_FS_SPEED_MODE     (TAS5754M_PAGE_BASE(0) +  34)
+#define TAS5754M_IDAC_1            (TAS5754M_PAGE_BASE(0) +  35)
+#define TAS5754M_IDAC_2            (TAS5754M_PAGE_BASE(0) +  36)
+#define TAS5754M_ERROR_DETECT      (TAS5754M_PAGE_BASE(0) +  37)
+#define TAS5754M_I2S_1             (TAS5754M_PAGE_BASE(0) +  40)
+#define TAS5754M_I2S_2             (TAS5754M_PAGE_BASE(0) +  41)
+#define TAS5754M_DAC_ROUTING       (TAS5754M_PAGE_BASE(0) +  42)
+#define TAS5754M_DSP_PROGRAM       (TAS5754M_PAGE_BASE(0) +  43)
+#define TAS5754M_CLKDET            (TAS5754M_PAGE_BASE(0) +  44)
+#define TAS5754M_AUTO_MUTE         (TAS5754M_PAGE_BASE(0) +  59)
+#define TAS5754M_DIGITAL_VOLUME_1  (TAS5754M_PAGE_BASE(0) +  60)
+#define TAS5754M_DIGITAL_VOLUME_2  (TAS5754M_PAGE_BASE(0) +  61)
+#define TAS5754M_DIGITAL_VOLUME_3  (TAS5754M_PAGE_BASE(0) +  62)
+#define TAS5754M_DIGITAL_MUTE_1    (TAS5754M_PAGE_BASE(0) +  63)
+#define TAS5754M_DIGITAL_MUTE_2    (TAS5754M_PAGE_BASE(0) +  64)
+#define TAS5754M_DIGITAL_MUTE_3    (TAS5754M_PAGE_BASE(0) +  65)
+#define TAS5754M_GPIO_OUTPUT_1     (TAS5754M_PAGE_BASE(0) +  82)
+#define TAS5754M_GPIO_OUTPUT_0     (TAS5754M_PAGE_BASE(0) +  83)
+#define TAS5754M_GPIO_OUTPUT_2     (TAS5754M_PAGE_BASE(0) +  85)
+#define TAS5754M_GPIO_CONTROL_1    (TAS5754M_PAGE_BASE(0) +  86)
+#define TAS5754M_GPIO_CONTROL_2    (TAS5754M_PAGE_BASE(0) +  87)
+#define TAS5754M_OVERFLOW          (TAS5754M_PAGE_BASE(0) +  90)
+#define TAS5754M_RATE_DET_1        (TAS5754M_PAGE_BASE(0) +  91)
+#define TAS5754M_RATE_DET_2        (TAS5754M_PAGE_BASE(0) +  92)
+#define TAS5754M_RATE_DET_3        (TAS5754M_PAGE_BASE(0) +  93)
+#define TAS5754M_RATE_DET_4        (TAS5754M_PAGE_BASE(0) +  94)
+#define TAS5754M_CLOCK_STATUS      (TAS5754M_PAGE_BASE(0) +  95)
+#define TAS5754M_ANALOG_MUTE_DET   (TAS5754M_PAGE_BASE(0) + 108)
+#define TAS5754M_FS_MODE_MON       (TAS5754M_PAGE_BASE(0) + 115)
+#define TAS5754M_GPIN              (TAS5754M_PAGE_BASE(0) + 119)
+#define TAS5754M_DIGITAL_MUTE_DET  (TAS5754M_PAGE_BASE(0) + 120)
+
+#define TAS5754M_OUTPUT_AMPLITUDE  (TAS5754M_PAGE_BASE(1) +   1)
+#define TAS5754M_ANALOG_GAIN_CTRL  (TAS5754M_PAGE_BASE(1) +   2)
+#define TAS5754M_UNDERVOLTAGE_PROT (TAS5754M_PAGE_BASE(1) +   5)
+#define TAS5754M_ANALOG_MUTE_CTRL  (TAS5754M_PAGE_BASE(1) +   6)
+#define TAS5754M_ANALOG_GAIN_BOOST (TAS5754M_PAGE_BASE(1) +   7)
+#define TAS5754M_VCOM_CTRL_1       (TAS5754M_PAGE_BASE(1) +   8)
+#define TAS5754M_VCOM_CTRL_2       (TAS5754M_PAGE_BASE(1) +   9)
+
+#define TAS5754M_CRAM_CTRL         (TAS5754M_PAGE_BASE(44) +  1)
+
+#define TAS5754M_FLEX_A            (TAS5754M_PAGE_BASE(253) + 63)
+#define TAS5754M_FLEX_B            (TAS5754M_PAGE_BASE(253) + 64)
+
+#define TAS5754M_MAX_REGISTER      (TAS5754M_PAGE_BASE(253) + 64)
+
+/* Page 0, Register 1 - reset */
+#define TAS5754M_RSTR (1 << 0)
+#define TAS5754M_RSTM (1 << 4)
+
+/* Page 0, Register 2 - power */
+#define TAS5754M_RQPD       (1 << 0)
+#define TAS5754M_RQPD_SHIFT 0
+#define TAS5754M_RQST       (1 << 4)
+#define TAS5754M_RQST_SHIFT 4
+
+/* Page 0, Register 3 - mute */
+#define TAS5754M_RQMR (1 << 0)
+#define TAS5754M_RQMR_SHIFT 0
+#define TAS5754M_RQML (1 << 4)
+#define TAS5754M_RQML_SHIFT 4
+
+/* Page 0, Register 4 - PLL */
+#define TAS5754M_PLLE       (1 << 0)
+#define TAS5754M_PLLE_SHIFT 0
+#define TAS5754M_PLCK       (1 << 4)
+#define TAS5754M_PLCK_SHIFT 4
+
+/* Page 0, Register 7 - DSP */
+#define TAS5754M_SDSL       (1 << 0)
+#define TAS5754M_SDSL_SHIFT 0
+#define TAS5754M_DEMP       (1 << 4)
+#define TAS5754M_DEMP_SHIFT 4
+
+/* Page 0, Register 8 - GPIO output enable */
+#define TAS5754M_G1OE       (1 << 0)
+#define TAS5754M_G2OE       (1 << 1)
+#define TAS5754M_G3OE       (1 << 2)
+#define TAS5754M_G4OE       (1 << 3)
+#define TAS5754M_G5OE       (1 << 4)
+#define TAS5754M_G6OE       (1 << 5)
+
+/* Page 0, Register 9 - BCK, LRCLK configuration */
+#define TAS5754M_LRKO       (1 << 0)
+#define TAS5754M_LRKO_SHIFT 0
+#define TAS5754M_BCKO       (1 << 4)
+#define TAS5754M_BCKO_SHIFT 4
+#define TAS5754M_BCKP       (1 << 5)
+#define TAS5754M_BCKP_SHIFT 5
+
+/* Page 0, Register 12 - Master mode BCK, LRCLK reset */
+#define TAS5754M_RLRK       (1 << 0)
+#define TAS5754M_RLRK_SHIFT 0
+#define TAS5754M_RBCK       (1 << 1)
+#define TAS5754M_RBCK_SHIFT 1
+
+/* Page 0, Register 13 - PLL reference */
+#define TAS5754M_SREF        (7 << 4)
+#define TAS5754M_SREF_SHIFT  4
+#define TAS5754M_SREF_SCK    (0 << 4)
+#define TAS5754M_SREF_BCK    (1 << 4)
+#define TAS5754M_SREF_GPIO   (3 << 4)
+
+/* Page 0, Register 14 - DAC reference */
+#define TAS5754M_SDAC        (7 << 4)
+#define TAS5754M_SDAC_SHIFT  4
+#define TAS5754M_SDAC_MCK    (0 << 4)
+#define TAS5754M_SDAC_PLL    (1 << 4)
+#define TAS5754M_SDAC_SCK    (3 << 4)
+#define TAS5754M_SDAC_BCK    (4 << 4)
+#define TAS5754M_SDAC_GPIO   (5 << 4)
+
+/* Page 0, Register 16, 18 - GPIO source for DAC, PLL */
+#define TAS5754M_GREF        (7 << 0)
+#define TAS5754M_GREF_SHIFT  0
+#define TAS5754M_GREF_GPIO1  (0 << 0)
+#define TAS5754M_GREF_GPIO2  (1 << 0)
+#define TAS5754M_GREF_GPIO3  (2 << 0)
+#define TAS5754M_GREF_GPIO4  (3 << 0)
+#define TAS5754M_GREF_GPIO5  (4 << 0)
+#define TAS5754M_GREF_GPIO6  (5 << 0)
+
+/* Page 0, Register 19 - synchronize */
+#define TAS5754M_RQSY        (1 << 0)
+#define TAS5754M_RQSY_RESUME (0 << 0)
+#define TAS5754M_RQSY_HALT   (1 << 0)
+
+/* Page 0, Register 34 - fs speed mode */
+#define TAS5754M_FSSP        (3 << 0)
+#define TAS5754M_FSSP_SHIFT  0
+#define TAS5754M_FSSP_48KHZ  (0 << 0)
+#define TAS5754M_FSSP_96KHZ  (1 << 0)
+#define TAS5754M_FSSP_192KHZ (2 << 0)
+#define TAS5754M_FSSP_384KHZ (3 << 0)
+
+/* Page 0, Register 37 - Error detection */
+#define TAS5754M_IPLK (1 << 0)
+#define TAS5754M_DCAS (1 << 1)
+#define TAS5754M_IDCM (1 << 2)
+#define TAS5754M_IDCH (1 << 3)
+#define TAS5754M_IDSK (1 << 4)
+#define TAS5754M_IDBK (1 << 5)
+#define TAS5754M_IDFS (1 << 6)
+
+/* Page 0, Register 40 - I2S configuration */
+#define TAS5754M_ALEN       (3 << 0)
+#define TAS5754M_ALEN_SHIFT 0
+#define TAS5754M_ALEN_16    (0 << 0)
+#define TAS5754M_ALEN_20    (1 << 0)
+#define TAS5754M_ALEN_24    (2 << 0)
+#define TAS5754M_ALEN_32    (3 << 0)
+#define TAS5754M_AFMT       (3 << 4)
+#define TAS5754M_AFMT_SHIFT 4
+#define TAS5754M_AFMT_I2S   (0 << 4)
+#define TAS5754M_AFMT_DSP   (1 << 4)
+#define TAS5754M_AFMT_RTJ   (2 << 4)
+#define TAS5754M_AFMT_LTJ   (3 << 4)
+
+/* Page 0, Register 42 - DAC routing */
+#define TAS5754M_AUPR_SHIFT 0
+#define TAS5754M_AUPL_SHIFT 4
+
+/* Page 0, Register 59 - auto mute */
+#define TAS5754M_ATMR_SHIFT 0
+#define TAS5754M_ATML_SHIFT 4
+
+/* Page 0, Register 63 - ramp rates */
+#define TAS5754M_VNDF_SHIFT 6
+#define TAS5754M_VNDS_SHIFT 4
+#define TAS5754M_VNUF_SHIFT 2
+#define TAS5754M_VNUS_SHIFT 0
+
+/* Page 0, Register 64 - emergency ramp rates */
+#define TAS5754M_VEDF_SHIFT 6
+#define TAS5754M_VEDS_SHIFT 4
+
+/* Page 0, Register 65 - Digital mute enables */
+#define TAS5754M_ACTL_SHIFT 2
+#define TAS5754M_AMLE_SHIFT 1
+#define TAS5754M_AMRE_SHIFT 0
+
+/* Page 0, Register 80-85, GPIO output selection */
+#define TAS5754M_GxSL       (31 << 0)
+#define TAS5754M_GxSL_SHIFT 0
+#define TAS5754M_GxSL_OFF   (0 << 0)
+#define TAS5754M_GxSL_DSP   (1 << 0)
+#define TAS5754M_GxSL_REG   (2 << 0)
+#define TAS5754M_GxSL_AMUTB (3 << 0)
+#define TAS5754M_GxSL_AMUTL (4 << 0)
+#define TAS5754M_GxSL_AMUTR (5 << 0)
+#define TAS5754M_GxSL_CLKI  (6 << 0)
+#define TAS5754M_GxSL_SDOUT (7 << 0)
+#define TAS5754M_GxSL_ANMUL (8 << 0)
+#define TAS5754M_GxSL_ANMUR (9 << 0)
+#define TAS5754M_GxSL_PLLLK (10 << 0)
+#define TAS5754M_GxSL_CPCLK (11 << 0)
+#define TAS5754M_GxSL_UV0_7 (14 << 0)
+#define TAS5754M_GxSL_UV0_3 (15 << 0)
+#define TAS5754M_GxSL_PLLCK (16 << 0)
+
+/* Page 1, Register 2 - analog volume control */
+#define TAS5754M_RAGN_SHIFT 0
+#define TAS5754M_LAGN_SHIFT 4
+
+/* Page 1, Register 7 - analog boost control */
+#define TAS5754M_AGBR_SHIFT 0
+#define TAS5754M_AGBL_SHIFT 4
+
+#endif
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH v5] ASoC: adds component driver for TAS575xM digital amplifiers
@ 2022-01-20 14:12   ` Joerg Schambacher
  0 siblings, 0 replies; 21+ messages in thread
From: Joerg Schambacher @ 2022-01-20 14:12 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 37244 bytes --]

On Thu, Jan 20, 2022 at 02:18:26AM +0800, kernel test robot wrote:
> tree:   https://github.com/0day-ci/linux/commits/UPDATE-20220119-210919/Joerg-Schambacher/ASoC-adds-component-driver-for-TAS575xM-digital-amplifiers/20220110-164852
> head:   05b8bf5544bc621031f5a0a6bdf1ac6468a7367b
> commit: 05b8bf5544bc621031f5a0a6bdf1ac6468a7367b ASoC: adds component driver for TAS575xM digital amplifiers
> date:   5 hours ago
> config: riscv-randconfig-c006-20220118 (https://download.01.org/0day-ci/archive/20220120/202201200259.nNgbKOJd-lkp(a)intel.com/config)
> compiler: clang version 14.0.0 (https://github.com/llvm/llvm-project f7b7138a62648f4019c55e4671682af1f851f295)
> reproduce (this is a W=1 build):
>         wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
>         chmod +x ~/bin/make.cross
>         # install riscv cross compiling tool for clang build
>         # apt-get install binutils-riscv64-linux-gnu
>         # https://github.com/0day-ci/linux/commit/05b8bf5544bc621031f5a0a6bdf1ac6468a7367b
>         git remote add linux-review https://github.com/0day-ci/linux
>         git fetch --no-tags linux-review UPDATE-20220119-210919/Joerg-Schambacher/ASoC-adds-component-driver-for-TAS575xM-digital-amplifiers/20220110-164852
>         git checkout 05b8bf5544bc621031f5a0a6bdf1ac6468a7367b
>         # save the config file to linux build tree
>         mkdir build_dir
>         COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=riscv SHELL=/bin/bash sound/soc/codecs/
> 
> If you fix the issue, kindly add following tag as appropriate
> Reported-by: kernel test robot <lkp@intel.com>
> 
> All warnings (new ones prefixed by >>):
> 
> >> sound/soc/codecs/tas5754m.c:246:7: warning: variable 'ret' is used uninitialized whenever switch case is taken [-Wsometimes-uninitialized]
>            case SND_SOC_BIAS_ON:
>                 ^~~~~~~~~~~~~~~
>    sound/soc/codecs/tas5754m.c:267:9: note: uninitialized use occurs here
>            return ret;
>                   ^~~
>    sound/soc/codecs/tas5754m.c:247:7: warning: variable 'ret' is used uninitialized whenever switch case is taken [-Wsometimes-uninitialized]
>            case SND_SOC_BIAS_PREPARE:
>                 ^~~~~~~~~~~~~~~~~~~~
>    sound/soc/codecs/tas5754m.c:267:9: note: uninitialized use occurs here
>            return ret;
>                   ^~~
>    sound/soc/codecs/tas5754m.c:242:9: note: initialize the variable 'ret' to silence this warning
>            int ret;
>                   ^
>                    = 0
>    2 warnings generated.
> 
> 
> vim +/ret +246 sound/soc/codecs/tas5754m.c
> 
>    236	
>    237	static int tas5754m_set_bias_level(struct snd_soc_component *component,
>    238					   enum snd_soc_bias_level level)
>    239	{
>    240		struct tas5754m_priv *tas5754m =
>    241					snd_soc_component_get_drvdata(component);
>    242		int ret;
>    243	
>    244		switch (level) {
>    245		default:
>  > 246		case SND_SOC_BIAS_ON:
>    247		case SND_SOC_BIAS_PREPARE:
>    248			break;
>    249	
>    250		case SND_SOC_BIAS_STANDBY:
>    251			ret = regmap_update_bits(tas5754m->regmap,
>    252					TAS5754M_POWER, TAS5754M_RQST, 0);
>    253			if (ret)
>    254				dev_err(component->dev,
>    255					"Failed to remove standby: %d\n", ret);
>    256			break;
>    257	
>    258		case SND_SOC_BIAS_OFF:
>    259			ret = regmap_update_bits(tas5754m->regmap,
>    260					TAS5754M_POWER, TAS5754M_RQST, TAS5754M_RQST);
>    261			if (ret)
>    262				dev_err(component->dev,
>    263					"Failed to request standby: %d\n", ret);
>    264			break;
>    265		}
>    266	
>    267		return ret;
>    268	}
>    269	
> 
> ---
> 0-DAY CI Kernel Test Service, Intel Corporation
> https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
all, fixed.
Joerg

>From 331a880edff308e8f0608f72f244c25e56162e24 Mon Sep 17 00:00:00 2001
From: Joerg Schambacher <joerg@hifiberry.com>
Date: Tue, 5 Oct 2021 14:38:21 +0200
Subject: [PATCH] ASoC: adds component driver for TAS575xM digital amplifiers

Adds a minimum component driver to run the amplifier in I2S master
mode only from standard audio clocks. Therefore, it only allows
44.1, 88.2, 176.4, 48, 96 and 192ksps with 16, 20, 24 and 32 bits
sample size. Digital volume control and the -6dB and +0.8dB switches
are supported.

Signed-off-by: Joerg Schambacher <joerg@hifiberry.com>
---
 sound/soc/codecs/Kconfig    |   8 +
 sound/soc/codecs/Makefile   |   2 +
 sound/soc/codecs/tas5754m.c | 691 ++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/tas5754m.h | 260 ++++++++++++++
 4 files changed, 961 insertions(+)
 create mode 100644 sound/soc/codecs/tas5754m.c
 create mode 100644 sound/soc/codecs/tas5754m.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 82ee233a269d..cf0584948fcf 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -210,6 +210,7 @@ config SND_SOC_ALL_CODECS
 	imply SND_SOC_TAS5086
 	imply SND_SOC_TAS571X
 	imply SND_SOC_TAS5720
+	imply SND_SOC_TAS5754M
 	imply SND_SOC_TAS6424
 	imply SND_SOC_TDA7419
 	imply SND_SOC_TFA9879
@@ -1419,6 +1420,13 @@ config SND_SOC_TAS5720
 	  Enable support for Texas Instruments TAS5720L/M high-efficiency mono
 	  Class-D audio power amplifiers.
 
+config SND_SOC_TAS5754M
+	tristate "Texas Instruments TAS5754M Digital Input Audio amplifier"
+	depends on I2C
+	help
+	  Enable support for Texas Instruments TAS5754M digital input
+	  Class-D audio power amplifiers.
+
 config SND_SOC_TAS6424
 	tristate "Texas Instruments TAS6424 Quad-Channel Audio amplifier"
 	depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 8dcea2c4604a..39984900258a 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -227,6 +227,7 @@ snd-soc-sti-sas-objs := sti-sas.o
 snd-soc-tas5086-objs := tas5086.o
 snd-soc-tas571x-objs := tas571x.o
 snd-soc-tas5720-objs := tas5720.o
+snd-soc-tas5754m-objs := tas5754m.o
 snd-soc-tas6424-objs := tas6424.o
 snd-soc-tda7419-objs := tda7419.o
 snd-soc-tas2770-objs := tas2770.o
@@ -555,6 +556,7 @@ obj-$(CONFIG_SND_SOC_TAS2764)	+= snd-soc-tas2764.o
 obj-$(CONFIG_SND_SOC_TAS5086)	+= snd-soc-tas5086.o
 obj-$(CONFIG_SND_SOC_TAS571X)	+= snd-soc-tas571x.o
 obj-$(CONFIG_SND_SOC_TAS5720)	+= snd-soc-tas5720.o
+obj-$(CONFIG_SND_SOC_TAS5754M)	+= snd-soc-tas5754m.o
 obj-$(CONFIG_SND_SOC_TAS6424)	+= snd-soc-tas6424.o
 obj-$(CONFIG_SND_SOC_TDA7419)	+= snd-soc-tda7419.o
 obj-$(CONFIG_SND_SOC_TAS2770) += snd-soc-tas2770.o
diff --git a/sound/soc/codecs/tas5754m.c b/sound/soc/codecs/tas5754m.c
new file mode 100644
index 000000000000..06c10002f32e
--- /dev/null
+++ b/sound/soc/codecs/tas5754m.c
@@ -0,0 +1,691 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for the TAS5754M Audio Amplifier
+ *
+ * Author: Joerg Schambacher <joerg@hifiberry.com>
+ *         with fragments from Andy Liu <andy-liu@ti.com>
+ *
+ * The driver supports I2S master mode only with standard audio
+ * frequencies 44.1 to 192 ksps from a 24.576/22.2592MHz master
+ * clock input
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+
+#include "tas5754m.h"
+
+#define TAS5754M_RATES		(SNDRV_PCM_RATE_48000  | \
+				 SNDRV_PCM_RATE_96000  | \
+				 SNDRV_PCM_RATE_192000 | \
+				 SNDRV_PCM_RATE_44100  | \
+				 SNDRV_PCM_RATE_88200  | \
+				 SNDRV_PCM_RATE_176400)
+#define TAS5754M_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE  | \
+				 SNDRV_PCM_FMTBIT_S20_LE  | \
+				 SNDRV_PCM_FMTBIT_S24_LE  | \
+				 SNDRV_PCM_FMTBIT_S32_LE)
+
+
+static const struct reg_default tas5754m_reg_defaults[] = {
+	{ TAS5754M_RESET,             0x00 },
+	{ TAS5754M_POWER,             0x00 },
+	{ TAS5754M_MUTE,              0x00 },
+	{ TAS5754M_DSP,               0x00 },
+	{ TAS5754M_PLL_REF,           0x00 },
+	{ TAS5754M_DAC_REF,           0x00 },
+	{ TAS5754M_DAC_ROUTING,       0x11 },
+	{ TAS5754M_DSP_PROGRAM,       0x01 },
+	{ TAS5754M_CLKDET,            0x00 },
+	{ TAS5754M_AUTO_MUTE,         0x00 },
+	{ TAS5754M_ERROR_DETECT,      0x00 },
+	{ TAS5754M_DIGITAL_VOLUME_1,  0x00 },
+	{ TAS5754M_DIGITAL_VOLUME_2,  0x30 },
+	{ TAS5754M_DIGITAL_VOLUME_3,  0x30 },
+	{ TAS5754M_DIGITAL_MUTE_1,    0x22 },
+	{ TAS5754M_DIGITAL_MUTE_2,    0x00 },
+	{ TAS5754M_DIGITAL_MUTE_3,    0x07 },
+	{ TAS5754M_OUTPUT_AMPLITUDE,  0x00 },
+	{ TAS5754M_ANALOG_GAIN_CTRL,  0x00 },
+	{ TAS5754M_UNDERVOLTAGE_PROT, 0x00 },
+	{ TAS5754M_ANALOG_MUTE_CTRL,  0x00 },
+	{ TAS5754M_ANALOG_GAIN_BOOST, 0x00 },
+	{ TAS5754M_VCOM_CTRL_1,       0x00 },
+	{ TAS5754M_VCOM_CTRL_2,       0x01 },
+	{ TAS5754M_BCLK_LRCLK_CFG,    0x00 },
+	{ TAS5754M_MASTER_MODE,       0x7c },
+	{ TAS5754M_GPIO_PLLIN,        0x00 },
+	{ TAS5754M_SYNCHRONIZE,       0x10 },
+	{ TAS5754M_PLL_COEFF_P,       0x00 },
+	{ TAS5754M_PLL_COEFF_J,       0x00 },
+	{ TAS5754M_PLL_COEFF_DH,      0x00 },
+	{ TAS5754M_PLL_COEFF_DL,      0x00 },
+	{ TAS5754M_PLL_COEFF_R,       0x00 },
+	{ TAS5754M_DSP_CLKDIV,        0x00 },
+	{ TAS5754M_DAC_CLKDIV,        0x00 },
+	{ TAS5754M_NCP_CLKDIV,        0x00 },
+	{ TAS5754M_OSR_CLKDIV,        0x00 },
+	{ TAS5754M_MASTER_SCLKDIV,    0x00 },
+	{ TAS5754M_MASTER_LRCLKDIV,   0x00 },
+	{ TAS5754M_FS_SPEED_MODE,     0x00 },
+	{ TAS5754M_IDAC_1,            0x01 },
+	{ TAS5754M_IDAC_2,            0x00 },
+};
+
+static bool tas5754m_readable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TAS5754M_RESET:
+	case TAS5754M_POWER:
+	case TAS5754M_MUTE:
+	case TAS5754M_PLL_EN:
+	case TAS5754M_DSP:
+	case TAS5754M_GPIO_EN:
+	case TAS5754M_BCLK_LRCLK_CFG:
+	case TAS5754M_DSP_GPIO_INPUT:
+	case TAS5754M_MASTER_MODE:
+	case TAS5754M_PLL_REF:
+	case TAS5754M_DAC_REF:
+	case TAS5754M_GPIO_PLLIN:
+	case TAS5754M_SYNCHRONIZE:
+	case TAS5754M_PLL_COEFF_P:
+	case TAS5754M_PLL_COEFF_J:
+	case TAS5754M_PLL_COEFF_DH:
+	case TAS5754M_PLL_COEFF_DL:
+	case TAS5754M_PLL_COEFF_R:
+	case TAS5754M_DSP_CLKDIV:
+	case TAS5754M_DAC_CLKDIV:
+	case TAS5754M_NCP_CLKDIV:
+	case TAS5754M_OSR_CLKDIV:
+	case TAS5754M_MASTER_SCLKDIV:
+	case TAS5754M_MASTER_LRCLKDIV:
+	case TAS5754M_FS_SPEED_MODE:
+	case TAS5754M_IDAC_1:
+	case TAS5754M_IDAC_2:
+	case TAS5754M_ERROR_DETECT:
+	case TAS5754M_I2S_1:
+	case TAS5754M_I2S_2:
+	case TAS5754M_DAC_ROUTING:
+	case TAS5754M_DSP_PROGRAM:
+	case TAS5754M_CLKDET:
+	case TAS5754M_AUTO_MUTE:
+	case TAS5754M_DIGITAL_VOLUME_1:
+	case TAS5754M_DIGITAL_VOLUME_2:
+	case TAS5754M_DIGITAL_VOLUME_3:
+	case TAS5754M_DIGITAL_MUTE_1:
+	case TAS5754M_DIGITAL_MUTE_2:
+	case TAS5754M_DIGITAL_MUTE_3:
+	case TAS5754M_GPIO_OUTPUT_0:
+	case TAS5754M_GPIO_OUTPUT_1:
+	case TAS5754M_GPIO_OUTPUT_2:
+	case TAS5754M_GPIO_CONTROL_1:
+	case TAS5754M_GPIO_CONTROL_2:
+	case TAS5754M_OVERFLOW:
+	case TAS5754M_RATE_DET_1:
+	case TAS5754M_RATE_DET_2:
+	case TAS5754M_RATE_DET_3:
+	case TAS5754M_RATE_DET_4:
+	case TAS5754M_CLOCK_STATUS:
+	case TAS5754M_ANALOG_MUTE_DET:
+	case TAS5754M_GPIN:
+	case TAS5754M_DIGITAL_MUTE_DET:
+	case TAS5754M_OUTPUT_AMPLITUDE:
+	case TAS5754M_ANALOG_GAIN_CTRL:
+	case TAS5754M_UNDERVOLTAGE_PROT:
+	case TAS5754M_ANALOG_MUTE_CTRL:
+	case TAS5754M_ANALOG_GAIN_BOOST:
+	case TAS5754M_VCOM_CTRL_1:
+	case TAS5754M_VCOM_CTRL_2:
+	case TAS5754M_CRAM_CTRL:
+	case TAS5754M_FLEX_A:
+	case TAS5754M_FLEX_B:
+		return true;
+	default:
+		return reg < 0x7f;
+	}
+}
+
+static bool tas5754m_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TAS5754M_PLL_EN:
+	case TAS5754M_OVERFLOW:
+	case TAS5754M_RATE_DET_1:
+	case TAS5754M_RATE_DET_2:
+	case TAS5754M_RATE_DET_3:
+	case TAS5754M_RATE_DET_4:
+	case TAS5754M_CLOCK_STATUS:
+	case TAS5754M_ANALOG_MUTE_DET:
+	case TAS5754M_GPIN:
+	case TAS5754M_DIGITAL_MUTE_DET:
+	case TAS5754M_CRAM_CTRL:
+		return true;
+	default:
+		return reg < 0x7f;
+	}
+}
+
+struct tas5754m_priv {
+	struct regmap *regmap;
+	struct clk *sclk;
+	int sample_len;
+	int fmt;
+	int mode;
+};
+
+static const struct regmap_range_cfg tas5754m_range = {
+	.name = "Pages",
+	.range_min = TAS5754M_VIRT_BASE,
+	.range_max = TAS5754M_MAX_REGISTER,
+	.selector_reg = TAS5754M_PAGE,
+	.selector_mask = 0x7f,
+	.window_start = 0,
+	.window_len = 128,
+};
+
+const struct regmap_config tas5754m_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.ranges = &tas5754m_range,
+	.num_ranges = 1,
+	.max_register = TAS5754M_MAX_REGISTER,
+
+	.reg_defaults = tas5754m_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(tas5754m_reg_defaults),
+	.readable_reg = tas5754m_readable,
+	.volatile_reg = tas5754m_volatile,
+
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1);
+static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0);
+
+static const struct snd_kcontrol_new tas5754m_controls[] = {
+SOC_DOUBLE_R_TLV("Digital Playback Volume", TAS5754M_DIGITAL_VOLUME_2,
+		 TAS5754M_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv),
+SOC_DOUBLE_TLV("Analog Playback Volume", TAS5754M_ANALOG_GAIN_CTRL,
+	     TAS5754M_LAGN_SHIFT, TAS5754M_RAGN_SHIFT, 1, 1, analog_tlv),
+SOC_DOUBLE_TLV("Analogue Playback Boost Volume", TAS5754M_ANALOG_GAIN_BOOST,
+	       TAS5754M_AGBL_SHIFT, TAS5754M_AGBR_SHIFT, 1, 0, boost_tlv),
+};
+
+static int tas5754m_set_bias_level(struct snd_soc_component *component,
+				   enum snd_soc_bias_level level)
+{
+	struct tas5754m_priv *tas5754m =
+				snd_soc_component_get_drvdata(component);
+	int ret = 0;
+
+	switch (level) {
+	default:
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		ret = regmap_update_bits(tas5754m->regmap,
+				TAS5754M_POWER, TAS5754M_RQST, 0);
+		if (ret)
+			dev_err(component->dev,
+				"Failed to remove standby: %d\n", ret);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		ret = regmap_update_bits(tas5754m->regmap,
+				TAS5754M_POWER, TAS5754M_RQST, TAS5754M_RQST);
+		if (ret)
+			dev_err(component->dev,
+				"Failed to request standby: %d\n", ret);
+		break;
+	}
+
+	return ret;
+}
+
+static int tas5754m_set_clock_tree_master(struct snd_soc_dai *dai,
+					  struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+	static const struct reg_sequence pll_settings[] = {
+		{ TAS5754M_PLL_COEFF_P,		0x01 },	// P=2
+		{ TAS5754M_PLL_COEFF_J,		0x08 },	// J=8
+		{ TAS5754M_PLL_COEFF_DL,	0x00 },	// D12-8 = 0
+		{ TAS5754M_PLL_COEFF_DH,	0x00 },	// D7-0 = 0
+		{ TAS5754M_PLL_COEFF_R,		0x00 },	// R=1
+	};
+	int ret;
+
+	/* disable PLL before any clock tree change */
+	ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
+				 TAS5754M_PLLE, 0);
+	if (ret) {
+		dev_err(component->dev, "Failed to disable PLL\n");
+		return ret;
+	}
+	/* set DAC clock source to MCLK */
+	ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_REF, 0x30);
+	if (ret) {
+		dev_err(component->dev, "Failed to set DAC ref\n");
+		return ret;
+	}
+	/* run PLL at fixed ratio to MCLK */
+	ret = regmap_multi_reg_write(tas5754m->regmap, pll_settings,
+					ARRAY_SIZE(pll_settings));
+	if (ret) {
+		dev_err(component->dev, "Failed to set PLL ratio\n");
+		return ret;
+	}
+	/* set DSP divider to 2 => reg 0x01 */
+	ret = regmap_write(tas5754m->regmap, TAS5754M_DSP_CLKDIV, 1);
+	if (ret) {
+		dev_err(component->dev, "Failed to set DSP divider\n");
+		return ret;
+	}
+	/* set DAC divider to 4 => reg 0x03*/
+	ret = regmap_write(tas5754m->regmap, TAS5754M_DAC_CLKDIV, 3);
+	if (ret) {
+		dev_err(component->dev, "Failed to set OSDACR divider\n");
+		return ret;
+	}
+	/* set OSR divider to 1 */
+	ret = regmap_write(tas5754m->regmap, TAS5754M_OSR_CLKDIV, 0);
+	if (ret) {
+		dev_err(component->dev, "Failed to set OSR divider\n");
+		return ret;
+	}
+	/* set CP divider to 4 => reg 0x03*/
+	ret = regmap_write(tas5754m->regmap, TAS5754M_NCP_CLKDIV, 3);
+	if (ret) {
+		dev_err(component->dev, "Failed to set CP divider\n");
+		return ret;
+	}
+	/* finally enable PLL */
+	ret = regmap_update_bits(tas5754m->regmap, TAS5754M_PLL_EN,
+				 TAS5754M_PLLE, 1);
+	if (ret) {
+		dev_err(component->dev, "Failed to enable PLL\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tas5754m_set_dai_mode(struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+	int fmt = tas5754m->fmt;
+
+	/* only I2S MASTER mode implemented */
+	if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S) {
+		dev_err(component->dev,
+			"DAI format not supported (I2S master only)\n");
+		return -EINVAL;
+	}
+
+	/* TAS5754/6m do not support inverted clocks in MASTER mode */
+	if ((fmt & SND_SOC_DAIFMT_CLOCK_MASK) != SND_SOC_DAIFMT_NB_NF) {
+		dev_err(component->dev,	"Inverted clocks not supported\n");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		regmap_update_bits(tas5754m->regmap,
+				TAS5754M_BCLK_LRCLK_CFG,
+				TAS5754M_LRKO | TAS5754M_BCKO,
+				TAS5754M_LRKO | TAS5754M_BCKO);
+		/* reset CLK dividers */
+		regmap_update_bits(tas5754m->regmap,
+				TAS5754M_MASTER_MODE,
+				0x00,
+				TAS5754M_RLRK | TAS5754M_RBCK);
+		/* ignore all clock error detection but MCLK */
+		regmap_update_bits(tas5754m->regmap,
+				TAS5754M_ERROR_DETECT,
+				TAS5754M_IPLK | TAS5754M_DCAS |
+				TAS5754M_IDCM | TAS5754M_IDSK |
+				TAS5754M_IDBK | TAS5754M_IDFS,
+				TAS5754M_IPLK | TAS5754M_DCAS |
+				TAS5754M_IDCM | TAS5754M_IDSK |
+				TAS5754M_IDBK | TAS5754M_IDFS);
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+	case SND_SOC_DAIFMT_CBM_CFS:
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int tas5754m_set_dividers_master(struct snd_soc_dai *dai,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+	unsigned long bclk;
+	unsigned long mclk;
+	int bclk_div;
+	int lrclk_div;
+	int osr;
+	int ret;
+
+	/* calculate divider settings based on mclk and sample_len */
+	mclk = clk_get_rate(tas5754m->sclk);
+	bclk = tas5754m->sample_len * 2 * params_rate(params);
+	bclk_div = mclk / bclk;
+	lrclk_div = tas5754m->sample_len * 2;
+	osr = mclk / 4 / params_rate(params) / 16;
+
+	/* stop LR / SCLK clocks */
+	ret = regmap_update_bits(tas5754m->regmap,
+				TAS5754M_MASTER_MODE, 0,
+				TAS5754M_RLRK | TAS5754M_RBCK);
+	if (ret) {
+		dev_err(component->dev, "Failed to stop PLL\n");
+		return ret;
+	}
+	/* set SCLK divider */
+	ret = regmap_write(tas5754m->regmap, TAS5754M_MASTER_SCLKDIV,
+								bclk_div - 1);
+	if (ret) {
+		dev_err(component->dev, "Failed to set SCLK divider\n");
+		return ret;
+	}
+	/* set LRCLK divider */
+	ret = regmap_write(tas5754m->regmap, TAS5754M_MASTER_LRCLKDIV,
+								lrclk_div - 1);
+	if (ret) {
+		dev_err(component->dev, "Failed to set LRCLK divider\n");
+		return ret;
+	}
+	ret = regmap_write(tas5754m->regmap,
+		TAS5754M_OSR_CLKDIV, osr - 1);
+	if (ret) {
+		dev_err(component->dev, "Failed to set OSR divider\n");
+		return ret;
+	}
+	/* restart LR / SCLK clocks */
+	ret = regmap_update_bits(tas5754m->regmap,
+				TAS5754M_MASTER_MODE,
+				TAS5754M_RLRK | TAS5754M_RBCK,
+				TAS5754M_RLRK | TAS5754M_RBCK);
+	if (ret) {
+		dev_err(component->dev, "Failed to restart PLL\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int tas5754m_hw_params(struct snd_pcm_substream *substream,
+			      struct snd_pcm_hw_params *params,
+			      struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+	int alen;
+	int ret;
+
+	switch (params_width(params)) {
+	case 16:
+		tas5754m->sample_len = 16;
+		alen = TAS5754M_ALEN_16;
+		break;
+	case 20:
+		tas5754m->sample_len = 32;
+		alen = TAS5754M_ALEN_20;
+		break;
+	case 24:
+		tas5754m->sample_len = 32;
+		alen = TAS5754M_ALEN_24;
+		break;
+	case 32:
+		tas5754m->sample_len = 32;
+		alen = TAS5754M_ALEN_32;
+		break;
+	default:
+		dev_err(component->dev, "Unsupported sample size: %d\n",
+			params_width(params));
+		return -EINVAL;
+	}
+	ret = regmap_update_bits(tas5754m->regmap, TAS5754M_I2S_1, alen, alen);
+	if (ret) {
+		dev_err(component->dev,
+			"Cannot set sample size: %d\n", ret);
+		return ret;
+	}
+
+	ret = tas5754m_set_dai_mode(dai);
+	if (ret) {
+		dev_err(component->dev,
+			"DAI mode not supported: %d\n", ret);
+		return ret;
+	}
+
+	ret = tas5754m_set_clock_tree_master(dai, params);
+	if (ret)
+		return ret;
+
+	switch (params_rate(params)) {
+	case 44100:
+	case 48000:
+		ret = regmap_write(tas5754m->regmap,
+			TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_48KHZ);
+		break;
+	case 88200:
+	case 96000:
+		ret = regmap_write(tas5754m->regmap,
+			TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_96KHZ);
+		break;
+	case 176400:
+	case 192000:
+		ret = regmap_write(tas5754m->regmap,
+			TAS5754M_FS_SPEED_MODE, TAS5754M_FSSP_192KHZ);
+		break;
+	default:
+		dev_err(component->dev, "Sample rate not supported: %d\n",
+			params_rate(params));
+		return -EINVAL;
+	}
+	if (ret) {
+		dev_err(component->dev, "Failed to config PLL\n");
+		return ret;
+	}
+
+	ret = tas5754m_set_dividers_master(dai, params);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int tas5754m_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_component *component = dai->component;
+	struct tas5754m_priv *tas5754m =
+			snd_soc_component_get_drvdata(component);
+
+	tas5754m->fmt = fmt;
+
+	return 0;
+}
+
+
+static const struct snd_soc_component_driver tas5754m_soc_component = {
+	.set_bias_level = tas5754m_set_bias_level,
+	.idle_bias_on = true,
+	.controls = tas5754m_controls,
+	.num_controls = ARRAY_SIZE(tas5754m_controls),
+};
+
+static int tas5754m_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+	struct snd_soc_component *component = dai->component;
+
+	if (mute) {
+		snd_soc_component_write(component, TAS5754M_MUTE, 0x11);
+	} else {
+		/* wait for stable operation before unmute */
+		usleep_range(1000, 2000);
+		snd_soc_component_write(component, TAS5754M_MUTE, 0x00);
+	}
+	return 0;
+}
+
+static const struct snd_soc_dai_ops tas5754m_dai_ops = {
+	.mute_stream = tas5754m_mute,
+	.hw_params = tas5754m_hw_params,
+	.set_fmt = tas5754m_set_fmt,
+};
+
+static struct snd_soc_dai_driver tas5754m_dai = {
+	.name		= "tas5754m-amplifier",
+	.playback	= {
+		.stream_name	= "Playback",
+		.channels_min	= 2,
+		.channels_max	= 2,
+		.rates		= TAS5754M_RATES,
+		.formats	= TAS5754M_FORMATS,
+	},
+	.ops = &tas5754m_dai_ops,
+};
+
+static int tas5754m_probe(struct device *dev, struct regmap *regmap)
+{
+	struct tas5754m_priv *tas5754m;
+	int ret;
+
+	tas5754m = devm_kzalloc(dev, sizeof(struct tas5754m_priv), GFP_KERNEL);
+	if (!tas5754m)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, tas5754m);
+	tas5754m->regmap = regmap;
+
+	ret = regmap_write(regmap, TAS5754M_RESET,
+			TAS5754M_RSTR | TAS5754M_RSTM);
+	if (ret) {
+		dev_err(dev, "Failed to initialize TAS5754M: %d\n", ret);
+		goto err;
+	}
+
+	tas5754m->sclk = devm_clk_get(dev, NULL);
+	if (PTR_ERR(tas5754m->sclk) == -EPROBE_DEFER) {
+		ret = -EPROBE_DEFER;
+		goto err;
+	}
+	if (!IS_ERR(tas5754m->sclk)) {
+		ret = clk_prepare_enable(tas5754m->sclk);
+		if (ret) {
+			dev_err(dev, "Failed to enable SCLK: %d\n", ret);
+			goto err;
+		}
+	}
+
+	ret = devm_snd_soc_register_component(dev,
+			&tas5754m_soc_component, &tas5754m_dai, 1);
+	if (ret) {
+		dev_err(dev, "Failed to register CODEC: %d\n", ret);
+		goto err;
+	}
+
+	return 0;
+
+err:
+	return ret;
+
+}
+
+static int tas5754m_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+{
+	struct regmap *regmap;
+	struct regmap_config config = tas5754m_regmap;
+
+	/* enable auto-increment mode */
+	config.read_flag_mask = 0x80;
+	config.write_flag_mask = 0x80;
+
+	regmap = devm_regmap_init_i2c(i2c, &config);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return tas5754m_probe(&i2c->dev, regmap);
+}
+
+static int tas5754m_remove(struct device *dev)
+{
+	snd_soc_unregister_component(dev);
+
+	return 0;
+}
+
+static int tas5754m_i2c_remove(struct i2c_client *i2c)
+{
+	tas5754m_remove(&i2c->dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id tas5754m_i2c_id[] = {
+	{ "tas5754m", },
+	{ "tas5756m", },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tas5754m_i2c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id tas5754m_of_match[] = {
+	{ .compatible = "ti,tas5754m", },
+	{ .compatible = "ti,tas5756m", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, tas5754m_of_match);
+#endif
+
+static struct i2c_driver tas5754m_i2c_driver = {
+	.probe		= tas5754m_i2c_probe,
+	.remove		= tas5754m_i2c_remove,
+	.id_table	= tas5754m_i2c_id,
+	.driver		= {
+		.name	= "tas5754m",
+		.of_match_table = of_match_ptr(tas5754m_of_match),
+	},
+};
+
+module_i2c_driver(tas5754m_i2c_driver);
+
+MODULE_AUTHOR("Joerg Schambacher <joerg@hifiberry.com>");
+MODULE_DESCRIPTION("TAS5754M Audio Amplifier Driver - Master mode only");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas5754m.h b/sound/soc/codecs/tas5754m.h
new file mode 100644
index 000000000000..c6e26dba169f
--- /dev/null
+++ b/sound/soc/codecs/tas5754m.h
@@ -0,0 +1,260 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Driver for the TAS575xM DAC+amplifier combo devices
+ *
+ * Author:	(copied from pcm512x.h)
+ *		Mark Brown <broonie@kernel.org>
+ *		Copyright 2014 Linaro Ltd
+ *
+ *		Register names adapted and non available
+ *		register definitions removed according
+ +		to TAS5754M specification
+ *		Joerg Schambacher <joerg@hifiberry.com>
+ */
+
+#ifndef _SND_SOC_TAS5754M
+#define _SND_SOC_TAS5754M
+
+#include <linux/pm.h>
+#include <linux/regmap.h>
+
+#define TAS5754M_VIRT_BASE 0x000
+#define TAS5754M_PAGE_LEN  0x80
+#define TAS5754M_PAGE_BASE(n)  (TAS5754M_VIRT_BASE + (TAS5754M_PAGE_LEN * n))
+
+#define TAS5754M_PAGE              0
+
+#define TAS5754M_RESET             (TAS5754M_PAGE_BASE(0) +   1)
+#define TAS5754M_POWER             (TAS5754M_PAGE_BASE(0) +   2)
+#define TAS5754M_MUTE              (TAS5754M_PAGE_BASE(0) +   3)
+#define TAS5754M_PLL_EN            (TAS5754M_PAGE_BASE(0) +   4)
+#define TAS5754M_DSP               (TAS5754M_PAGE_BASE(0) +   7)
+#define TAS5754M_GPIO_EN           (TAS5754M_PAGE_BASE(0) +   8)
+#define TAS5754M_BCLK_LRCLK_CFG    (TAS5754M_PAGE_BASE(0) +   9)
+#define TAS5754M_DSP_GPIO_INPUT    (TAS5754M_PAGE_BASE(0) +  10)
+#define TAS5754M_MASTER_MODE       (TAS5754M_PAGE_BASE(0) +  12)
+#define TAS5754M_PLL_REF           (TAS5754M_PAGE_BASE(0) +  13)
+#define TAS5754M_DAC_REF           (TAS5754M_PAGE_BASE(0) +  14)
+#define TAS5754M_GPIO_PLLIN        (TAS5754M_PAGE_BASE(0) +  18)
+#define TAS5754M_SYNCHRONIZE       (TAS5754M_PAGE_BASE(0) +  19)
+#define TAS5754M_PLL_COEFF_P       (TAS5754M_PAGE_BASE(0) +  20)
+#define TAS5754M_PLL_COEFF_J       (TAS5754M_PAGE_BASE(0) +  21)
+#define TAS5754M_PLL_COEFF_DH      (TAS5754M_PAGE_BASE(0) +  22)
+#define TAS5754M_PLL_COEFF_DL      (TAS5754M_PAGE_BASE(0) +  23)
+#define TAS5754M_PLL_COEFF_R       (TAS5754M_PAGE_BASE(0) +  24)
+#define TAS5754M_DSP_CLKDIV        (TAS5754M_PAGE_BASE(0) +  27)
+#define TAS5754M_DAC_CLKDIV        (TAS5754M_PAGE_BASE(0) +  28)
+#define TAS5754M_NCP_CLKDIV        (TAS5754M_PAGE_BASE(0) +  29)
+#define TAS5754M_OSR_CLKDIV        (TAS5754M_PAGE_BASE(0) +  30)
+#define TAS5754M_MASTER_SCLKDIV    (TAS5754M_PAGE_BASE(0) +  32)
+#define TAS5754M_MASTER_LRCLKDIV   (TAS5754M_PAGE_BASE(0) +  33)
+#define TAS5754M_FS_SPEED_MODE     (TAS5754M_PAGE_BASE(0) +  34)
+#define TAS5754M_IDAC_1            (TAS5754M_PAGE_BASE(0) +  35)
+#define TAS5754M_IDAC_2            (TAS5754M_PAGE_BASE(0) +  36)
+#define TAS5754M_ERROR_DETECT      (TAS5754M_PAGE_BASE(0) +  37)
+#define TAS5754M_I2S_1             (TAS5754M_PAGE_BASE(0) +  40)
+#define TAS5754M_I2S_2             (TAS5754M_PAGE_BASE(0) +  41)
+#define TAS5754M_DAC_ROUTING       (TAS5754M_PAGE_BASE(0) +  42)
+#define TAS5754M_DSP_PROGRAM       (TAS5754M_PAGE_BASE(0) +  43)
+#define TAS5754M_CLKDET            (TAS5754M_PAGE_BASE(0) +  44)
+#define TAS5754M_AUTO_MUTE         (TAS5754M_PAGE_BASE(0) +  59)
+#define TAS5754M_DIGITAL_VOLUME_1  (TAS5754M_PAGE_BASE(0) +  60)
+#define TAS5754M_DIGITAL_VOLUME_2  (TAS5754M_PAGE_BASE(0) +  61)
+#define TAS5754M_DIGITAL_VOLUME_3  (TAS5754M_PAGE_BASE(0) +  62)
+#define TAS5754M_DIGITAL_MUTE_1    (TAS5754M_PAGE_BASE(0) +  63)
+#define TAS5754M_DIGITAL_MUTE_2    (TAS5754M_PAGE_BASE(0) +  64)
+#define TAS5754M_DIGITAL_MUTE_3    (TAS5754M_PAGE_BASE(0) +  65)
+#define TAS5754M_GPIO_OUTPUT_1     (TAS5754M_PAGE_BASE(0) +  82)
+#define TAS5754M_GPIO_OUTPUT_0     (TAS5754M_PAGE_BASE(0) +  83)
+#define TAS5754M_GPIO_OUTPUT_2     (TAS5754M_PAGE_BASE(0) +  85)
+#define TAS5754M_GPIO_CONTROL_1    (TAS5754M_PAGE_BASE(0) +  86)
+#define TAS5754M_GPIO_CONTROL_2    (TAS5754M_PAGE_BASE(0) +  87)
+#define TAS5754M_OVERFLOW          (TAS5754M_PAGE_BASE(0) +  90)
+#define TAS5754M_RATE_DET_1        (TAS5754M_PAGE_BASE(0) +  91)
+#define TAS5754M_RATE_DET_2        (TAS5754M_PAGE_BASE(0) +  92)
+#define TAS5754M_RATE_DET_3        (TAS5754M_PAGE_BASE(0) +  93)
+#define TAS5754M_RATE_DET_4        (TAS5754M_PAGE_BASE(0) +  94)
+#define TAS5754M_CLOCK_STATUS      (TAS5754M_PAGE_BASE(0) +  95)
+#define TAS5754M_ANALOG_MUTE_DET   (TAS5754M_PAGE_BASE(0) + 108)
+#define TAS5754M_FS_MODE_MON       (TAS5754M_PAGE_BASE(0) + 115)
+#define TAS5754M_GPIN              (TAS5754M_PAGE_BASE(0) + 119)
+#define TAS5754M_DIGITAL_MUTE_DET  (TAS5754M_PAGE_BASE(0) + 120)
+
+#define TAS5754M_OUTPUT_AMPLITUDE  (TAS5754M_PAGE_BASE(1) +   1)
+#define TAS5754M_ANALOG_GAIN_CTRL  (TAS5754M_PAGE_BASE(1) +   2)
+#define TAS5754M_UNDERVOLTAGE_PROT (TAS5754M_PAGE_BASE(1) +   5)
+#define TAS5754M_ANALOG_MUTE_CTRL  (TAS5754M_PAGE_BASE(1) +   6)
+#define TAS5754M_ANALOG_GAIN_BOOST (TAS5754M_PAGE_BASE(1) +   7)
+#define TAS5754M_VCOM_CTRL_1       (TAS5754M_PAGE_BASE(1) +   8)
+#define TAS5754M_VCOM_CTRL_2       (TAS5754M_PAGE_BASE(1) +   9)
+
+#define TAS5754M_CRAM_CTRL         (TAS5754M_PAGE_BASE(44) +  1)
+
+#define TAS5754M_FLEX_A            (TAS5754M_PAGE_BASE(253) + 63)
+#define TAS5754M_FLEX_B            (TAS5754M_PAGE_BASE(253) + 64)
+
+#define TAS5754M_MAX_REGISTER      (TAS5754M_PAGE_BASE(253) + 64)
+
+/* Page 0, Register 1 - reset */
+#define TAS5754M_RSTR (1 << 0)
+#define TAS5754M_RSTM (1 << 4)
+
+/* Page 0, Register 2 - power */
+#define TAS5754M_RQPD       (1 << 0)
+#define TAS5754M_RQPD_SHIFT 0
+#define TAS5754M_RQST       (1 << 4)
+#define TAS5754M_RQST_SHIFT 4
+
+/* Page 0, Register 3 - mute */
+#define TAS5754M_RQMR (1 << 0)
+#define TAS5754M_RQMR_SHIFT 0
+#define TAS5754M_RQML (1 << 4)
+#define TAS5754M_RQML_SHIFT 4
+
+/* Page 0, Register 4 - PLL */
+#define TAS5754M_PLLE       (1 << 0)
+#define TAS5754M_PLLE_SHIFT 0
+#define TAS5754M_PLCK       (1 << 4)
+#define TAS5754M_PLCK_SHIFT 4
+
+/* Page 0, Register 7 - DSP */
+#define TAS5754M_SDSL       (1 << 0)
+#define TAS5754M_SDSL_SHIFT 0
+#define TAS5754M_DEMP       (1 << 4)
+#define TAS5754M_DEMP_SHIFT 4
+
+/* Page 0, Register 8 - GPIO output enable */
+#define TAS5754M_G1OE       (1 << 0)
+#define TAS5754M_G2OE       (1 << 1)
+#define TAS5754M_G3OE       (1 << 2)
+#define TAS5754M_G4OE       (1 << 3)
+#define TAS5754M_G5OE       (1 << 4)
+#define TAS5754M_G6OE       (1 << 5)
+
+/* Page 0, Register 9 - BCK, LRCLK configuration */
+#define TAS5754M_LRKO       (1 << 0)
+#define TAS5754M_LRKO_SHIFT 0
+#define TAS5754M_BCKO       (1 << 4)
+#define TAS5754M_BCKO_SHIFT 4
+#define TAS5754M_BCKP       (1 << 5)
+#define TAS5754M_BCKP_SHIFT 5
+
+/* Page 0, Register 12 - Master mode BCK, LRCLK reset */
+#define TAS5754M_RLRK       (1 << 0)
+#define TAS5754M_RLRK_SHIFT 0
+#define TAS5754M_RBCK       (1 << 1)
+#define TAS5754M_RBCK_SHIFT 1
+
+/* Page 0, Register 13 - PLL reference */
+#define TAS5754M_SREF        (7 << 4)
+#define TAS5754M_SREF_SHIFT  4
+#define TAS5754M_SREF_SCK    (0 << 4)
+#define TAS5754M_SREF_BCK    (1 << 4)
+#define TAS5754M_SREF_GPIO   (3 << 4)
+
+/* Page 0, Register 14 - DAC reference */
+#define TAS5754M_SDAC        (7 << 4)
+#define TAS5754M_SDAC_SHIFT  4
+#define TAS5754M_SDAC_MCK    (0 << 4)
+#define TAS5754M_SDAC_PLL    (1 << 4)
+#define TAS5754M_SDAC_SCK    (3 << 4)
+#define TAS5754M_SDAC_BCK    (4 << 4)
+#define TAS5754M_SDAC_GPIO   (5 << 4)
+
+/* Page 0, Register 16, 18 - GPIO source for DAC, PLL */
+#define TAS5754M_GREF        (7 << 0)
+#define TAS5754M_GREF_SHIFT  0
+#define TAS5754M_GREF_GPIO1  (0 << 0)
+#define TAS5754M_GREF_GPIO2  (1 << 0)
+#define TAS5754M_GREF_GPIO3  (2 << 0)
+#define TAS5754M_GREF_GPIO4  (3 << 0)
+#define TAS5754M_GREF_GPIO5  (4 << 0)
+#define TAS5754M_GREF_GPIO6  (5 << 0)
+
+/* Page 0, Register 19 - synchronize */
+#define TAS5754M_RQSY        (1 << 0)
+#define TAS5754M_RQSY_RESUME (0 << 0)
+#define TAS5754M_RQSY_HALT   (1 << 0)
+
+/* Page 0, Register 34 - fs speed mode */
+#define TAS5754M_FSSP        (3 << 0)
+#define TAS5754M_FSSP_SHIFT  0
+#define TAS5754M_FSSP_48KHZ  (0 << 0)
+#define TAS5754M_FSSP_96KHZ  (1 << 0)
+#define TAS5754M_FSSP_192KHZ (2 << 0)
+#define TAS5754M_FSSP_384KHZ (3 << 0)
+
+/* Page 0, Register 37 - Error detection */
+#define TAS5754M_IPLK (1 << 0)
+#define TAS5754M_DCAS (1 << 1)
+#define TAS5754M_IDCM (1 << 2)
+#define TAS5754M_IDCH (1 << 3)
+#define TAS5754M_IDSK (1 << 4)
+#define TAS5754M_IDBK (1 << 5)
+#define TAS5754M_IDFS (1 << 6)
+
+/* Page 0, Register 40 - I2S configuration */
+#define TAS5754M_ALEN       (3 << 0)
+#define TAS5754M_ALEN_SHIFT 0
+#define TAS5754M_ALEN_16    (0 << 0)
+#define TAS5754M_ALEN_20    (1 << 0)
+#define TAS5754M_ALEN_24    (2 << 0)
+#define TAS5754M_ALEN_32    (3 << 0)
+#define TAS5754M_AFMT       (3 << 4)
+#define TAS5754M_AFMT_SHIFT 4
+#define TAS5754M_AFMT_I2S   (0 << 4)
+#define TAS5754M_AFMT_DSP   (1 << 4)
+#define TAS5754M_AFMT_RTJ   (2 << 4)
+#define TAS5754M_AFMT_LTJ   (3 << 4)
+
+/* Page 0, Register 42 - DAC routing */
+#define TAS5754M_AUPR_SHIFT 0
+#define TAS5754M_AUPL_SHIFT 4
+
+/* Page 0, Register 59 - auto mute */
+#define TAS5754M_ATMR_SHIFT 0
+#define TAS5754M_ATML_SHIFT 4
+
+/* Page 0, Register 63 - ramp rates */
+#define TAS5754M_VNDF_SHIFT 6
+#define TAS5754M_VNDS_SHIFT 4
+#define TAS5754M_VNUF_SHIFT 2
+#define TAS5754M_VNUS_SHIFT 0
+
+/* Page 0, Register 64 - emergency ramp rates */
+#define TAS5754M_VEDF_SHIFT 6
+#define TAS5754M_VEDS_SHIFT 4
+
+/* Page 0, Register 65 - Digital mute enables */
+#define TAS5754M_ACTL_SHIFT 2
+#define TAS5754M_AMLE_SHIFT 1
+#define TAS5754M_AMRE_SHIFT 0
+
+/* Page 0, Register 80-85, GPIO output selection */
+#define TAS5754M_GxSL       (31 << 0)
+#define TAS5754M_GxSL_SHIFT 0
+#define TAS5754M_GxSL_OFF   (0 << 0)
+#define TAS5754M_GxSL_DSP   (1 << 0)
+#define TAS5754M_GxSL_REG   (2 << 0)
+#define TAS5754M_GxSL_AMUTB (3 << 0)
+#define TAS5754M_GxSL_AMUTL (4 << 0)
+#define TAS5754M_GxSL_AMUTR (5 << 0)
+#define TAS5754M_GxSL_CLKI  (6 << 0)
+#define TAS5754M_GxSL_SDOUT (7 << 0)
+#define TAS5754M_GxSL_ANMUL (8 << 0)
+#define TAS5754M_GxSL_ANMUR (9 << 0)
+#define TAS5754M_GxSL_PLLLK (10 << 0)
+#define TAS5754M_GxSL_CPCLK (11 << 0)
+#define TAS5754M_GxSL_UV0_7 (14 << 0)
+#define TAS5754M_GxSL_UV0_3 (15 << 0)
+#define TAS5754M_GxSL_PLLCK (16 << 0)
+
+/* Page 1, Register 2 - analog volume control */
+#define TAS5754M_RAGN_SHIFT 0
+#define TAS5754M_LAGN_SHIFT 4
+
+/* Page 1, Register 7 - analog boost control */
+#define TAS5754M_AGBR_SHIFT 0
+#define TAS5754M_AGBL_SHIFT 4
+
+#endif
-- 
2.25.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH v2] sound/soc: adds TAS5754M digital input amplifier component driver
  2022-01-19 12:50   ` Joerg Schambacher
@ 2022-01-26 16:44     ` Mark Brown
  -1 siblings, 0 replies; 21+ messages in thread
From: Mark Brown @ 2022-01-26 16:44 UTC (permalink / raw)
  To: Joerg Schambacher; +Cc: alsa-devel, kbuild-all

[-- Attachment #1: Type: text/plain, Size: 2570 bytes --]

On Wed, Jan 19, 2022 at 01:50:33PM +0100, Joerg Schambacher wrote:

> Thanks for your useful feedback. I guess my comments on my first reply got lost somewhere on the way ....

Please don't top post, reply in line with needed context.  This allows
readers to readily follow the flow of conversation and understand what
you are talking about and also helps ensure that everything in the
discussion is being addressed.

Please fix your mail client to word wrap within paragraphs at something
substantially less than 80 columns.  Doing this makes your messages much
easier to read and reply to.

> On Wed, Nov 17, 2021 at 03:13:47PM +0000, Mark Brown wrote:
> > On Fri, Oct 29, 2021 at 11:57:30AM +0200, Joerg Schambacher wrote:

> > > +	mclk = clk_get_rate(tas5754m->sclk);
> > > +	bclk = sample_len * 2 * params_rate(params);

> > snd_soc_params_to_bclk().

> snd_soc_params_to_bclk() does not always gives the necessary value

In what way does it not give the needed value, and is that perhaps a
symptom of the constraints not being accurate?

> > > +	if (mute) {
> > > +		snd_soc_component_write(component, TAS5754M_MUTE, 0x11);
> > > +	} else {
> > > +		usleep_range(1000, 2000);
> > > +		snd_soc_component_write(component, TAS5754M_MUTE, 0x00);

> > Why the sleep here?

> Wait for settling of the clocks before unmute

Why would you need to wait for the clocks (which clocks?) to settle
before the unmute, this sounds like something that needs to be addressed
in whatever is providing the clocks.

> > If the register map can be copied can't the two drivers be combined?

> The TI apps team recommended to write a separate driver as there are some differences. I have also aligned some names to the TAS575xM spec in the next patch

What concrete differences are there here?  "The TI apps team said so"
isn't really upstream discussion or review...

> > > +#define TAS5754M_VIRT_BASE 0x000
> > > +#define TAS5754M_PAGE_LEN  0x80
> > > +#define TAS5754M_PAGE_BASE(n)  (TAS5754M_VIRT_BASE + (TAS5754M_PAGE_LEN * n))

> > > +#define TAS5754M_PAGE              0

> > There's no mention of paging in the regmap description for the driver
> > which feels like it's asking for problems.

> I think, it's defined in the correct way. Where/when exactly do you see a problem?

If there is paging going on and the regmap code doesn't know about it
then that makes it seem likely that the regmap code is going to get
confused about what's going on with the device.  What makes you say that
"it's defined in the correct way" if there's no mention of paging in the
regmap config?

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2] sound/soc: adds TAS5754M digital input amplifier component driver
@ 2022-01-26 16:44     ` Mark Brown
  0 siblings, 0 replies; 21+ messages in thread
From: Mark Brown @ 2022-01-26 16:44 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 2633 bytes --]

On Wed, Jan 19, 2022 at 01:50:33PM +0100, Joerg Schambacher wrote:

> Thanks for your useful feedback. I guess my comments on my first reply got lost somewhere on the way ....

Please don't top post, reply in line with needed context.  This allows
readers to readily follow the flow of conversation and understand what
you are talking about and also helps ensure that everything in the
discussion is being addressed.

Please fix your mail client to word wrap within paragraphs at something
substantially less than 80 columns.  Doing this makes your messages much
easier to read and reply to.

> On Wed, Nov 17, 2021 at 03:13:47PM +0000, Mark Brown wrote:
> > On Fri, Oct 29, 2021 at 11:57:30AM +0200, Joerg Schambacher wrote:

> > > +	mclk = clk_get_rate(tas5754m->sclk);
> > > +	bclk = sample_len * 2 * params_rate(params);

> > snd_soc_params_to_bclk().

> snd_soc_params_to_bclk() does not always gives the necessary value

In what way does it not give the needed value, and is that perhaps a
symptom of the constraints not being accurate?

> > > +	if (mute) {
> > > +		snd_soc_component_write(component, TAS5754M_MUTE, 0x11);
> > > +	} else {
> > > +		usleep_range(1000, 2000);
> > > +		snd_soc_component_write(component, TAS5754M_MUTE, 0x00);

> > Why the sleep here?

> Wait for settling of the clocks before unmute

Why would you need to wait for the clocks (which clocks?) to settle
before the unmute, this sounds like something that needs to be addressed
in whatever is providing the clocks.

> > If the register map can be copied can't the two drivers be combined?

> The TI apps team recommended to write a separate driver as there are some differences. I have also aligned some names to the TAS575xM spec in the next patch

What concrete differences are there here?  "The TI apps team said so"
isn't really upstream discussion or review...

> > > +#define TAS5754M_VIRT_BASE 0x000
> > > +#define TAS5754M_PAGE_LEN  0x80
> > > +#define TAS5754M_PAGE_BASE(n)  (TAS5754M_VIRT_BASE + (TAS5754M_PAGE_LEN * n))

> > > +#define TAS5754M_PAGE              0

> > There's no mention of paging in the regmap description for the driver
> > which feels like it's asking for problems.

> I think, it's defined in the correct way. Where/when exactly do you see a problem?

If there is paging going on and the regmap code doesn't know about it
then that makes it seem likely that the regmap code is going to get
confused about what's going on with the device.  What makes you say that
"it's defined in the correct way" if there's no mention of paging in the
regmap config?

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2022-01-26 16:45 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20211029095414.29131-1-joerg@hifiberry.com>
2021-10-29  9:57 ` [PATCH v2] sound/soc: adds TAS5754M digital input amplifier component driver Joerg Schambacher
2021-10-29  9:57   ` Joerg Schambacher
2021-11-17 15:13   ` Mark Brown
2021-11-17 15:13     ` Mark Brown
2022-01-10  8:45 ` [PATCH v3] ASoC: adds component driver for TAS575xM digital amplifiers Joerg Schambacher
2022-01-10  8:45   ` Joerg Schambacher
2022-01-10 11:20   ` kernel test robot
2022-01-10 11:20     ` kernel test robot
2022-01-10 16:25   ` Cezary Rojewski
2022-01-10 16:25     ` Cezary Rojewski
2022-01-19 13:05     ` [PATCH v4] " Joerg Schambacher
2022-01-19 13:05       ` Joerg Schambacher
2022-01-12 18:42   ` [PATCH v3] " kernel test robot
2022-01-12 18:42     ` kernel test robot
2022-01-12 18:42     ` kernel test robot
2022-01-19 12:50 ` [PATCH v2] sound/soc: adds TAS5754M digital input amplifier component driver Joerg Schambacher
2022-01-19 12:50   ` Joerg Schambacher
2022-01-26 16:44   ` Mark Brown
2022-01-26 16:44     ` Mark Brown
2022-01-20 14:12 ` [PATCH v5] ASoC: adds component driver for TAS575xM digital amplifiers Joerg Schambacher
2022-01-20 14:12   ` Joerg Schambacher

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.