Skip to contentSkip to conversation

ASoC: codecs: tas5086: fix documentation

PATCH In review Daniel Mack 2 participants 8 messages Jun 24, 2013 – Jun 25, 2013

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/5 ASoC: codecs: tas5086: fix documentation

The property 'ti,charge-period' must be given in nanoseconds, not microseconds.

---
 Documentation/devicetree/bindings/sound/ti,tas5086.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
Documentation/devicetree/bindings/sound/ti,tas5086.txt +1 -1
index 8ea4f5b..e8310f1 100644
@@ -11,7 +11,7 @@ Optional properties:
 			chip's !RESET pin. If specified, the driver will
 			assert a hardware reset at probe time.
 
- - ti,charge-period:	This property should contain the time in microseconds
+ - ti,charge-period:	This property should contain the time in nanoseconds
 			that closely matches the external single-ended
 			split-capacitor charge period. The hardware chip
 			waits for this period of time before starting the
Signature · 1 line
1.8.1.4
#1 lore raw

PATCH 2/5 ASoC: codecs: tas5086: open-code I2C transfer routines

In order to support registers of unequal sizes, the I2C I/O has to be open-coded.

---
 sound/soc/codecs/tas5086.c | 85 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 84 insertions(+), 1 deletion(-)
sound/soc/codecs/tas5086.c +84 -1
index 6c5470c..833bccd 100644
@@ -119,6 +119,17 @@ static const struct reg_default tas5086_reg_defaults[] = {
 	{ 0x1c,	0x05 },
 };
 
+static int tas5086_register_size(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TAS5086_DEV_ID ... TAS5086_BKNDERR:
+		return 1;
+	}
+
+	dev_err(dev, "Unsupported register address: %d\n", reg);
+	return 0;
+}
+
 static bool tas5086_accessible_reg(struct device *dev, unsigned int reg)
 {
 	return !((reg == 0x0f) || (reg >= 0x11 && reg <= 0x17));
@@ -140,6 +151,76 @@ static bool tas5086_writeable_reg(struct device *dev, unsigned int reg)
 	return tas5086_accessible_reg(dev, reg) && (reg != TAS5086_DEV_ID);
 }
 
+static int tas5086_reg_write(void *context, unsigned int reg,
+			      unsigned int value)
+{
+	struct i2c_client *client = context;
+	unsigned int i, size;
+	uint8_t buf[5];
+	int ret;
+
+	size = tas5086_register_size(&client->dev, reg);
+	if (size == 0)
+		return -EINVAL;
+
+	buf[0] = reg;
+
+	for (i = size; i >= 1; --i) {
+		buf[i] = value;
+		value >>= 8;
+	}
+
+	ret = i2c_master_send(client, buf, size + 1);
+	if (ret == size + 1)
+		return 0;
+	else if (ret < 0)
+		return ret;
+	else
+		return -EIO;
+}
+
+static int tas5086_reg_read(void *context, unsigned int reg,
+			     unsigned int *value)
+{
+	struct i2c_client *client = context;
+	uint8_t send_buf, recv_buf[4];
+	struct i2c_msg msgs[2];
+	unsigned int size;
+	unsigned int i;
+	int ret;
+
+	size = tas5086_register_size(&client->dev, reg);
+	if (size == 0)
+		return -EINVAL;
+
+	send_buf = reg;
+
+	msgs[0].addr = client->addr;
+	msgs[0].len = sizeof(send_buf);
+	msgs[0].buf = &send_buf;
+	msgs[0].flags = 0;
+
+	msgs[1].addr = client->addr;
+	msgs[1].len = size;
+	msgs[1].buf = recv_buf;
+	msgs[1].flags = I2C_M_RD;
+
+	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (ret < 0)
+		return ret;
+	else if (ret != ARRAY_SIZE(msgs))
+		return -EIO;
+
+	*value = 0;
+
+	for (i = 0; i < size; i++) {
+		*value <<= 8;
+		*value |= recv_buf[i];
+	}
+
+	return 0;
+}
+
 struct tas5086_private {
 	struct regmap	*regmap;
 	unsigned int	mclk, sclk;
@@ -508,6 +589,8 @@ static const struct regmap_config tas5086_regmap = {
 	.volatile_reg		= tas5086_volatile_reg,
 	.writeable_reg		= tas5086_writeable_reg,
 	.readable_reg		= tas5086_accessible_reg,
+	.reg_read		= tas5086_reg_read,
+	.reg_write		= tas5086_reg_write,
 };
 
 static int tas5086_i2c_probe(struct i2c_client *i2c,
@@ -522,7 +605,7 @@ static int tas5086_i2c_probe(struct i2c_client *i2c,
 	if (!priv)
 		return -ENOMEM;
 
-	priv->regmap = devm_regmap_init_i2c(i2c, &tas5086_regmap);
+	priv->regmap = devm_regmap_init(dev, NULL, i2c, &tas5086_regmap);
 	if (IS_ERR(priv->regmap)) {
 		ret = PTR_ERR(priv->regmap);
 		dev_err(&i2c->dev, "Failed to create regmap: %d\n", ret);
Signature · 1 line
1.8.1.4
#2 lore raw

PATCH 3/5 ASoC: codecs: tas5086: add more register defines

In reply to Daniel Mack

Add register definitions for input and output mux registers, and rewrite the tas5086_accessible_reg() function.

---
 sound/soc/codecs/tas5086.c | 20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)
sound/soc/codecs/tas5086.c +17 -3
index 833bccd..b2aea5d 100644
@@ -83,6 +83,10 @@
 #define TAS5086_SPLIT_CAP_CHARGE	0x1a	/* Split cap charge period register */
 #define TAS5086_OSC_TRIM		0x1b	/* Oscillator trim register */
 #define TAS5086_BKNDERR 		0x1c
+#define TAS5086_INPUT_MUX		0x20
+#define TAS5086_PWM_OUTPUT_MUX		0x25
+
+#define TAS5086_MAX_REGISTER		TAS5086_PWM_OUTPUT_MUX
 
 /*
  * Default TAS5086 power-up configuration
@@ -124,6 +128,9 @@ static int tas5086_register_size(struct device *dev, unsigned int reg)
 	switch (reg) {
 	case TAS5086_DEV_ID ... TAS5086_BKNDERR:
 		return 1;
+	case TAS5086_INPUT_MUX:
+	case TAS5086_PWM_OUTPUT_MUX:
+		return 4;
 	}
 
 	dev_err(dev, "Unsupported register address: %d\n", reg);
@@ -132,7 +139,14 @@ static int tas5086_register_size(struct device *dev, unsigned int reg)
 
 static bool tas5086_accessible_reg(struct device *dev, unsigned int reg)
 {
-	return !((reg == 0x0f) || (reg >= 0x11 && reg <= 0x17));
+	switch (reg) {
+	case 0x0f:
+	case 0x11 ... 0x17:
+	case 0x1d ... 0x1f:
+		return false;
+	default:
+		return true;
+	}
 }
 
 static bool tas5086_volatile_reg(struct device *dev, unsigned int reg)
@@ -581,8 +595,8 @@ MODULE_DEVICE_TABLE(i2c, tas5086_i2c_id);
 
 static const struct regmap_config tas5086_regmap = {
 	.reg_bits		= 8,
-	.val_bits		= 8,
-	.max_register		= ARRAY_SIZE(tas5086_reg_defaults),
+	.val_bits		= 32,
+	.max_register		= TAS5086_MAX_REGISTER,
 	.reg_defaults		= tas5086_reg_defaults,
 	.num_reg_defaults	= ARRAY_SIZE(tas5086_reg_defaults),
 	.cache_type		= REGCACHE_RBTREE,
Signature · 1 line
1.8.1.4
#3 lore raw

PATCH 4/5 ASoC: codecs: tas5086: add DAPM mux controls

In reply to Daniel Mack

The TAS5086 has two muxes, one for connecting I2S inputs to internal channels, and another one for selecting which internal channel should be routed to which PWM output pin.

This patch adds DAPM widgets and routes for this driver.

---
 sound/soc/codecs/tas5086.c | 200 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 200 insertions(+)
sound/soc/codecs/tas5086.c +200 -0
index b2aea5d..99e190d 100644
@@ -471,6 +471,202 @@ static const struct snd_kcontrol_new tas5086_controls[] = {
 			    tas5086_get_deemph, tas5086_put_deemph),
 };
 
+/* Input mux controls */
+static const char *tas5086_dapm_sdin_texts[] =
+{
+	"SDIN1-L", "SDIN1-R", "SDIN2-L", "SDIN2-R",
+	"SDIN3-L", "SDIN3-R", "Ground (0)", "nc"
+};
+
+static const struct soc_enum tas5086_dapm_input_mux_enum[] = {
+	SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 20, 8, tas5086_dapm_sdin_texts),
+	SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 16, 8, tas5086_dapm_sdin_texts),
+	SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 12, 8, tas5086_dapm_sdin_texts),
+	SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 8,  8, tas5086_dapm_sdin_texts),
+	SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 4,  8, tas5086_dapm_sdin_texts),
+	SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 0,  8, tas5086_dapm_sdin_texts),
+};
+
+static const struct snd_kcontrol_new tas5086_dapm_input_mux_controls[] = {
+	SOC_DAPM_ENUM("Channel 1 input", tas5086_dapm_input_mux_enum[0]),
+	SOC_DAPM_ENUM("Channel 2 input", tas5086_dapm_input_mux_enum[1]),
+	SOC_DAPM_ENUM("Channel 3 input", tas5086_dapm_input_mux_enum[2]),
+	SOC_DAPM_ENUM("Channel 4 input", tas5086_dapm_input_mux_enum[3]),
+	SOC_DAPM_ENUM("Channel 5 input", tas5086_dapm_input_mux_enum[4]),
+	SOC_DAPM_ENUM("Channel 6 input", tas5086_dapm_input_mux_enum[5]),
+};
+
+/* Output mux controls */
+static const char *tas5086_dapm_channel_texts[] =
+	{ "Channel 1 Mux", "Channel 2 Mux", "Channel 3 Mux",
+	  "Channel 4 Mux", "Channel 5 Mux", "Channel 6 Mux" };
+
+static const struct soc_enum tas5086_dapm_output_mux_enum[] = {
+	SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 20, 6, tas5086_dapm_channel_texts),
+	SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 16, 6, tas5086_dapm_channel_texts),
+	SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 12, 6, tas5086_dapm_channel_texts),
+	SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 8,  6, tas5086_dapm_channel_texts),
+	SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 4,  6, tas5086_dapm_channel_texts),
+	SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 0,  6, tas5086_dapm_channel_texts),
+};
+
+static const struct snd_kcontrol_new tas5086_dapm_output_mux_controls[] = {
+	SOC_DAPM_ENUM("PWM1 Output", tas5086_dapm_output_mux_enum[0]),
+	SOC_DAPM_ENUM("PWM2 Output", tas5086_dapm_output_mux_enum[1]),
+	SOC_DAPM_ENUM("PWM3 Output", tas5086_dapm_output_mux_enum[2]),
+	SOC_DAPM_ENUM("PWM4 Output", tas5086_dapm_output_mux_enum[3]),
+	SOC_DAPM_ENUM("PWM5 Output", tas5086_dapm_output_mux_enum[4]),
+	SOC_DAPM_ENUM("PWM6 Output", tas5086_dapm_output_mux_enum[5]),
+};
+
+static const struct snd_soc_dapm_widget tas5086_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("SDIN1-L"),
+	SND_SOC_DAPM_INPUT("SDIN1-R"),
+	SND_SOC_DAPM_INPUT("SDIN2-L"),
+	SND_SOC_DAPM_INPUT("SDIN2-R"),
+	SND_SOC_DAPM_INPUT("SDIN3-L"),
+	SND_SOC_DAPM_INPUT("SDIN3-R"),
+	SND_SOC_DAPM_INPUT("SDIN4-L"),
+	SND_SOC_DAPM_INPUT("SDIN4-R"),
+
+	SND_SOC_DAPM_OUTPUT("PWM1"),
+	SND_SOC_DAPM_OUTPUT("PWM2"),
+	SND_SOC_DAPM_OUTPUT("PWM3"),
+	SND_SOC_DAPM_OUTPUT("PWM4"),
+	SND_SOC_DAPM_OUTPUT("PWM5"),
+	SND_SOC_DAPM_OUTPUT("PWM6"),
+
+	SND_SOC_DAPM_MUX("Channel 1 Mux", SND_SOC_NOPM, 0, 0,
+			 &tas5086_dapm_input_mux_controls[0]),
+	SND_SOC_DAPM_MUX("Channel 2 Mux", SND_SOC_NOPM, 0, 0,
+			 &tas5086_dapm_input_mux_controls[1]),
+	SND_SOC_DAPM_MUX("Channel 3 Mux", SND_SOC_NOPM, 0, 0,
+			 &tas5086_dapm_input_mux_controls[2]),
+	SND_SOC_DAPM_MUX("Channel 4 Mux", SND_SOC_NOPM, 0, 0,
+			 &tas5086_dapm_input_mux_controls[3]),
+	SND_SOC_DAPM_MUX("Channel 5 Mux", SND_SOC_NOPM, 0, 0,
+			 &tas5086_dapm_input_mux_controls[4]),
+	SND_SOC_DAPM_MUX("Channel 6 Mux", SND_SOC_NOPM, 0, 0,
+			 &tas5086_dapm_input_mux_controls[5]),
+
+	SND_SOC_DAPM_MUX("PWM1 Mux", SND_SOC_NOPM, 0, 0,
+			 &tas5086_dapm_output_mux_controls[0]),
+	SND_SOC_DAPM_MUX("PWM2 Mux", SND_SOC_NOPM, 0, 0,
+			 &tas5086_dapm_output_mux_controls[1]),
+	SND_SOC_DAPM_MUX("PWM3 Mux", SND_SOC_NOPM, 0, 0,
+			 &tas5086_dapm_output_mux_controls[2]),
+	SND_SOC_DAPM_MUX("PWM4 Mux", SND_SOC_NOPM, 0, 0,
+			 &tas5086_dapm_output_mux_controls[3]),
+	SND_SOC_DAPM_MUX("PWM5 Mux", SND_SOC_NOPM, 0, 0,
+			 &tas5086_dapm_output_mux_controls[4]),
+	SND_SOC_DAPM_MUX("PWM6 Mux", SND_SOC_NOPM, 0, 0,
+			 &tas5086_dapm_output_mux_controls[5]),
+};
+
+static const struct snd_soc_dapm_route tas5086_dapm_routes[] = {
+	/* SDIN inputs -> channel muxes */
+	{ "Channel 1 Mux", "SDIN1-L", "SDIN1-L" },
+	{ "Channel 1 Mux", "SDIN1-R", "SDIN1-R" },
+	{ "Channel 1 Mux", "SDIN2-L", "SDIN2-L" },
+	{ "Channel 1 Mux", "SDIN2-R", "SDIN2-R" },
+	{ "Channel 1 Mux", "SDIN3-L", "SDIN3-L" },
+	{ "Channel 1 Mux", "SDIN3-R", "SDIN3-R" },
+
+	{ "Channel 2 Mux", "SDIN1-L", "SDIN1-L" },
+	{ "Channel 2 Mux", "SDIN1-R", "SDIN1-R" },
+	{ "Channel 2 Mux", "SDIN2-L", "SDIN2-L" },
+	{ "Channel 2 Mux", "SDIN2-R", "SDIN2-R" },
+	{ "Channel 2 Mux", "SDIN3-L", "SDIN3-L" },
+	{ "Channel 2 Mux", "SDIN3-R", "SDIN3-R" },
+
+	{ "Channel 2 Mux", "SDIN1-L", "SDIN1-L" },
+	{ "Channel 2 Mux", "SDIN1-R", "SDIN1-R" },
+	{ "Channel 2 Mux", "SDIN2-L", "SDIN2-L" },
+	{ "Channel 2 Mux", "SDIN2-R", "SDIN2-R" },
+	{ "Channel 2 Mux", "SDIN3-L", "SDIN3-L" },
+	{ "Channel 2 Mux", "SDIN3-R", "SDIN3-R" },
+
+	{ "Channel 3 Mux", "SDIN1-L", "SDIN1-L" },
+	{ "Channel 3 Mux", "SDIN1-R", "SDIN1-R" },
+	{ "Channel 3 Mux", "SDIN2-L", "SDIN2-L" },
+	{ "Channel 3 Mux", "SDIN2-R", "SDIN2-R" },
+	{ "Channel 3 Mux", "SDIN3-L", "SDIN3-L" },
+	{ "Channel 3 Mux", "SDIN3-R", "SDIN3-R" },
+
+	{ "Channel 4 Mux", "SDIN1-L", "SDIN1-L" },
+	{ "Channel 4 Mux", "SDIN1-R", "SDIN1-R" },
+	{ "Channel 4 Mux", "SDIN2-L", "SDIN2-L" },
+	{ "Channel 4 Mux", "SDIN2-R", "SDIN2-R" },
+	{ "Channel 4 Mux", "SDIN3-L", "SDIN3-L" },
+	{ "Channel 4 Mux", "SDIN3-R", "SDIN3-R" },
+
+	{ "Channel 5 Mux", "SDIN1-L", "SDIN1-L" },
+	{ "Channel 5 Mux", "SDIN1-R", "SDIN1-R" },
+	{ "Channel 5 Mux", "SDIN2-L", "SDIN2-L" },
+	{ "Channel 5 Mux", "SDIN2-R", "SDIN2-R" },
+	{ "Channel 5 Mux", "SDIN3-L", "SDIN3-L" },
+	{ "Channel 5 Mux", "SDIN3-R", "SDIN3-R" },
+
+	{ "Channel 6 Mux", "SDIN1-L", "SDIN1-L" },
+	{ "Channel 6 Mux", "SDIN1-R", "SDIN1-R" },
+	{ "Channel 6 Mux", "SDIN2-L", "SDIN2-L" },
+	{ "Channel 6 Mux", "SDIN2-R", "SDIN2-R" },
+	{ "Channel 6 Mux", "SDIN3-L", "SDIN3-L" },
+	{ "Channel 6 Mux", "SDIN3-R", "SDIN3-R" },
+
+	/* Channel muxes -> PWM muxes */
+	{ "PWM1 Mux", "Channel 1 Mux", "Channel 1 Mux" },
+	{ "PWM2 Mux", "Channel 1 Mux", "Channel 1 Mux" },
+	{ "PWM3 Mux", "Channel 1 Mux", "Channel 1 Mux" },
+	{ "PWM4 Mux", "Channel 1 Mux", "Channel 1 Mux" },
+	{ "PWM5 Mux", "Channel 1 Mux", "Channel 1 Mux" },
+	{ "PWM6 Mux", "Channel 1 Mux", "Channel 1 Mux" },
+
+	{ "PWM1 Mux", "Channel 2 Mux", "Channel 2 Mux" },
+	{ "PWM2 Mux", "Channel 2 Mux", "Channel 2 Mux" },
+	{ "PWM3 Mux", "Channel 2 Mux", "Channel 2 Mux" },
+	{ "PWM4 Mux", "Channel 2 Mux", "Channel 2 Mux" },
+	{ "PWM5 Mux", "Channel 2 Mux", "Channel 2 Mux" },
+	{ "PWM6 Mux", "Channel 2 Mux", "Channel 2 Mux" },
+
+	{ "PWM1 Mux", "Channel 3 Mux", "Channel 3 Mux" },
+	{ "PWM2 Mux", "Channel 3 Mux", "Channel 3 Mux" },
+	{ "PWM3 Mux", "Channel 3 Mux", "Channel 3 Mux" },
+	{ "PWM4 Mux", "Channel 3 Mux", "Channel 3 Mux" },
+	{ "PWM5 Mux", "Channel 3 Mux", "Channel 3 Mux" },
+	{ "PWM6 Mux", "Channel 3 Mux", "Channel 3 Mux" },
+
+	{ "PWM1 Mux", "Channel 4 Mux", "Channel 4 Mux" },
+	{ "PWM2 Mux", "Channel 4 Mux", "Channel 4 Mux" },
+	{ "PWM3 Mux", "Channel 4 Mux", "Channel 4 Mux" },
+	{ "PWM4 Mux", "Channel 4 Mux", "Channel 4 Mux" },
+	{ "PWM5 Mux", "Channel 4 Mux", "Channel 4 Mux" },
+	{ "PWM6 Mux", "Channel 4 Mux", "Channel 4 Mux" },
+
+	{ "PWM1 Mux", "Channel 5 Mux", "Channel 5 Mux" },
+	{ "PWM2 Mux", "Channel 5 Mux", "Channel 5 Mux" },
+	{ "PWM3 Mux", "Channel 5 Mux", "Channel 5 Mux" },
+	{ "PWM4 Mux", "Channel 5 Mux", "Channel 5 Mux" },
+	{ "PWM5 Mux", "Channel 5 Mux", "Channel 5 Mux" },
+	{ "PWM6 Mux", "Channel 5 Mux", "Channel 5 Mux" },
+
+	{ "PWM1 Mux", "Channel 6 Mux", "Channel 6 Mux" },
+	{ "PWM2 Mux", "Channel 6 Mux", "Channel 6 Mux" },
+	{ "PWM3 Mux", "Channel 6 Mux", "Channel 6 Mux" },
+	{ "PWM4 Mux", "Channel 6 Mux", "Channel 6 Mux" },
+	{ "PWM5 Mux", "Channel 6 Mux", "Channel 6 Mux" },
+	{ "PWM6 Mux", "Channel 6 Mux", "Channel 6 Mux" },
+
+	/* The PWM muxes are directly connected to the PWM outputs */
+	{ "PWM1", NULL, "PWM1 Mux" },
+	{ "PWM2", NULL, "PWM2 Mux" },
+	{ "PWM3", NULL, "PWM3 Mux" },
+	{ "PWM4", NULL, "PWM4 Mux" },
+	{ "PWM5", NULL, "PWM5 Mux" },
+	{ "PWM6", NULL, "PWM6 Mux" },
+
+};
+
 static const struct snd_soc_dai_ops tas5086_dai_ops = {
 	.hw_params	= tas5086_hw_params,
 	.set_sysclk	= tas5086_set_dai_sysclk,
@@ -585,6 +781,10 @@ static struct snd_soc_codec_driver soc_codec_dev_tas5086 = {
 	.resume			= tas5086_soc_resume,
 	.controls		= tas5086_controls,
 	.num_controls		= ARRAY_SIZE(tas5086_controls),
+	.dapm_widgets		= tas5086_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(tas5086_dapm_widgets),
+	.dapm_routes		= tas5086_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(tas5086_dapm_routes),
 };
 
 static const struct i2c_device_id tas5086_i2c_id[] = {
Signature · 1 line
1.8.1.4
#4 lore raw

PATCH 5/5 ASoC: codecs: tas5086: add support for pwm start mode config

In reply to Daniel Mack

The TAS5086 has two alternative modes to start its PWM channels, Mid-Z and Low-Z. Which one to use depends on how the PWM power stages are connected to the TAS5086.

This patch adds 6 optional boolean properties to the DT bindings of the driver which allow the user to configure each individual channel to the Mid-Z scheme, and leaves all the others to the default (Low-Z).

---
 .../devicetree/bindings/sound/ti,tas5086.txt       | 11 +++++++++++
 sound/soc/codecs/tas5086.c                         | 22 ++++++++++++++++++++++
 2 files changed, 33 insertions(+)
Documentation/devicetree/bindings/sound/ti,tas5086.txt +11 -0
index e8310f1..f199f7d 100644
@@ -20,6 +20,17 @@ Optional properties:
 			When not specified, the hardware default of 1300ms
 			is retained.
 
+ - ti,mid-z-channel-X:	Boolean properties, X being a number from 1 to 6.
+			If given, channel X will start with the Mid-Z start
+			sequence, otherwise the default Low-Z scheme is used.
+
+			The correct configuration depends on how the power
+			stages connected to the PWM output pins work. Not all
+			power stages are compatible to Mid-Z - please refer
+			to the datasheets for more details.
+
+			Most systems should not set any of these properties.
+
 Examples:
 
 	i2c_bus {
sound/soc/codecs/tas5086.c +22 -0
index 99e190d..fec9a28 100644
@@ -88,6 +88,10 @@
 
 #define TAS5086_MAX_REGISTER		TAS5086_PWM_OUTPUT_MUX
 
+#define TAS5086_PWM_START_MIDZ_FOR_START_1	(1 << 7)
+#define TAS5086_PWM_START_MIDZ_FOR_START_2	(1 << 6)
+#define TAS5086_PWM_START_CHANNEL_MASK		(0x3f)
+
 /*
  * Default TAS5086 power-up configuration
  */
@@ -717,13 +721,31 @@ static int tas5086_probe(struct snd_soc_codec *codec)
 {
 	struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
 	int charge_period = 1300000; /* hardware default is 1300 ms */
+	u8 pwm_start = TAS5086_PWM_START_CHANNEL_MASK;
 	int i, ret;
 
 	if (of_match_device(of_match_ptr(tas5086_dt_ids), codec->dev)) {
 		struct device_node *of_node = codec->dev->of_node;
 		of_property_read_u32(of_node, "ti,charge-period", &charge_period);
+
+		for (i = 0; i < 6; i++) {
+			char name[25];
+
+			snprintf(name, sizeof(name),
+				 "ti,mid-z-channel-%d", i + 1);
+
+			if (of_get_property(of_node, name, NULL) != NULL)
+				pwm_start &= ~(1 << i);
+		}
 	}
 
+	/*
+	 * Configure 'part 2' of the PWM starts to always use MID-Z, and tell
+	 * all configured mid-z channels to start start under 'part 2'.
+	 */
+	regmap_write(priv->regmap, TAS5086_PWM_START,
+		     TAS5086_PWM_START_MIDZ_FOR_START_2 | pwm_start);
+
 	/* lookup and set split-capacitor charge period */
 	if (charge_period == 0) {
 		regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, 0);
Signature · 1 line
1.8.1.4
maintainer
#5 lore raw
In reply to Daniel Mack
Quoted 2 lines · Daniel Mack

The property 'ti,charge-period' must be given in nanoseconds, not microseconds.

Applied al, thanks. Though specifying this in nanoseconds does seem absurdly high resolution...

Not sure where the "codecs: " in the subject line came from either.

#6 lore raw
Quoted 6 lines · Mark Brown
Quoted 2 lines · Daniel Mack

The property 'ti,charge-period' must be given in nanoseconds, not microseconds.

Applied al, thanks. Though specifying this in nanoseconds does seem absurdly high resolution...

Meh, I was confused, sorry. That first patch need to be revered (or dropped), the documentation was correct as it stood. The time values are given in fractions of milliseconds, not microseconds. My bad.

Quoted 1 line

Not sure where the "codecs: " in the subject line came from either.

No problem, I can drop that in my future submissions.

Thanks,
Daniel

maintainer
#7 lore raw
Quoted 8 lines · Daniel Mack
Quoted 2 lines · Mark Brown

Applied al, thanks. Though specifying this in nanoseconds does seem absurdly high resolution...

Meh, I was confused, sorry. That first patch need to be revered (or dropped), the documentation was correct as it stood. The time values are given in fractions of milliseconds, not microseconds. My bad.

Dropped.