Skip to contentSkip to conversation

ASoC: sta350: Add codec driver

PATCH Superseded Daniel Mack 3 participants 3 messages Mar 27, 2014 – Mar 28, 2014

Subsystems (3)

v2 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

PATCH v2 1/1 ASoC: sta350: Add codec driver

From: Sven Brandau <[email protected]>

The TI STA350 is an integrated 2.1-channel power amplifier that is controllable over I2C. This patch adds an ASoC driver for it.

At a glance, this chip is very similar to the STA320 for which a driver already exists. In details, however, the register maps contain subtle differences which made a whole new driver easier to write and maintain.

[[email protected]: cleanups, DT property rework, rebased on asoc-next]

---
v1 -> v2:

* Added my S-o-b
* Made the Kconfig symbol visible
* Documented regulator notes in DT bindings doc
* Fixed spelling and other style nits
* Converted to SOC_ENUM_SINGLE_DECL
* Added a lock around the logic in sta350_coefficient_get()
* Added a DAPM route from "DAC" to "Playback"
* Use dev_dbg() rather than pr_debug()
* Changed the code to make use of regmap_update_bits rather than open-coding the same functionality
* Cleaned up the reset sequence logic
* If a gpio was requested, the claiming has to succeed (handles EPROBE_DEFER cases)
* Kick codec->control_data initialization
* Skip initialization of default values in regcache
* Apply power before running init sequences
* Parse the DT without consulting of_match_device()

 .../devicetree/bindings/sound/st,sta350.txt        |  107 ++
 include/sound/sta350.h                             |   52 +
 sound/soc/codecs/Kconfig                           |    5 +
 sound/soc/codecs/Makefile                          |    2 +
 sound/soc/codecs/sta350.c                          | 1266 ++++++++++++++++++++
 sound/soc/codecs/sta350.h                          |  228 ++++
 6 files changed, 1660 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/st,sta350.txt
 create mode 100644 include/sound/sta350.h
 create mode 100644 sound/soc/codecs/sta350.c
 create mode 100644 sound/soc/codecs/sta350.h
Documentation/devicetree/bindings/sound/st,sta350.txt new file +107 -0
new file mode 100644
index 0000000..07f9c80
@@ -0,0 +1,107 @@
+STA350 audio CODEC
+
+The driver for this device only supports I2C.
+
+Required properties:
+
+  - compatible: "st,sta350"
+  - reg: the I2C address of the device for I2C
+  - reset-gpio: a GPIO spec for the reset pin. If specified, it will be
+		deasserted before communication to the codec starts.
+
+  - power-down-gpio: a GPIO spec for the power down pin. If specified,
+		     it will be deasserted before communication to the codec
+		     starts.
+
+  - vdd-dig-supply: regulator spec, providing 3.3V
+  - vdd-pll-supply: regulator spec, providing 3.3V
+  - vcc-supply: regulator spec, providing 5V - 26V
+
+Optional properties:
+
+  -  st,output-conf: number, Selects the output configuration:
+	0: 2-channel (full-bridge) power, 2-channel data-out
+	1: 2 (half-bridge). 1 (full-bridge) on-board power
+	2: 2 Channel (Full-Bridge) Power, 1 Channel FFX
+	3: 1 Channel Mono-Parallel
+	If parameter is missing, mode 0 will be enabled.
+
+  -  st,ch1-output-mapping: Channel 1 output mapping
+  -  st,ch2-output-mapping: Channel 2 output mapping
+  -  st,ch3-output-mapping: Channel 3 output mapping
+	0: Channel 1
+	1: Channel 2
+	2: Channel 3
+	If parameter is missing, channel 1 is choosen.
+
+  -  st,thermal-warning-recover:
+	If present, thermal warning recovery is enabled.
+
+  -  st,thermal-warning-adjustment:
+	If present, thermal warning adjustment is enabled.
+
+  -  st,fault-detect-recovery:
+	If present, then fault recovery will be enabled.
+
+  -  st,ffx-power-output-mode: string
+	The FFX power output mode selects how the FFX output timing is
+	configured. Must be one of these values:
+	  -  "drop-compensation"
+	  -  "tapered-compensation"
+	  -  "full-power-mode"
+	  -  "variable-drop-compensation" (default)
+
+  -  st,drop-compensation-ns: number
+	Only required for "st,ffx-power-output-mode" ==
+	"variable-drop-compensation".
+	Specifies the drop compensation in nanoseconds.
+	The value must be in the range of 0..300, and only
+	multiples of 20 are allowed. Default is 140ns.
+
+  -  st,overcurrent-warning-adjustment:
+	If present, overcurrent warning adjustment is enabled.
+
+  -  st,max-power-use-mpcc:
+	If present, then MPCC bits are used for MPC coefficients,
+	otherwise standard MPC coefficients are used.
+
+  -  st,max-power-corr:
+	If present, power bridge correction for THD reduction near maximum
+	power output is enabled.
+
+  -  st,am-reduction-mode:
+	If present, FFX mode runs in AM reduction mode, otherwise normal
+	FFX mode is used.
+
+  -  st,odd-pwm-speed-mode:
+	If present, PWM speed mode run on odd speed mode (341.3 kHz) on all
+	channels. If not present, normal PWM spped mode (384 kHz) will be used.
+
+  -  st,distortion-compensation:
+	If present, distortion compensation variable uses DCC coefficient.
+	If not present, preset DC coefficient is used.
+
+  -  st,invalid-input-detect-mute:
+	If not present, automatic invalid input detect mute is enabled.
+
+
+
+Example:
+
+codec: sta350@38 {
+	compatible = "st,sta350";
+	reg = <0x1c>;
+	reset-gpio = <&gpio1 19 0>;
+	power-down-gpio = <&gpio1 16 0>;
+	st,output-conf = <0x3>;			// set output to 2-channel
+						// (full-bridge) power,
+						// 2-channel data-out
+	st,ch1-output-mapping = <0>;		// set channel 1 output ch 1
+	st,ch2-output-mapping = <0>;		// set channel 2 output ch 1
+	st,ch3-output-mapping = <0>;		// set channel 3 output ch 1
+	st,max-power-correction;		// enables power bridge
+						// correction for THD reduction
+						// near maximum power output
+	st,invalid-input-detect-mute;		// mute if no valid digital
+						// audio signal is provided.
+};
include/sound/sta350.h new file +52 -0

52 lines not on this page · raw message

sound/soc/codecs/Kconfig +5 -0
index f0e8401..c7b853f 100644
@@ -80,6 +80,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_SSM2602_SPI if SPI_MASTER
 	select SND_SOC_SSM2602_I2C if I2C
 	select SND_SOC_STA32X if I2C
+	select SND_SOC_STA350 if I2C
 	select SND_SOC_STA529 if I2C
 	select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
 	select SND_SOC_TAS5086 if I2C
@@ -435,6 +436,10 @@ config SND_SOC_SSM2602_I2C
 config SND_SOC_STA32X
 	tristate
 
+config SND_SOC_STA350
+	tristate "STA350 speaker amplifier"
+	depends on I2C
+
 config SND_SOC_STA529
 	tristate
 
sound/soc/codecs/Makefile +2 -0
index 3c4d275..efdb4d0 100644
@@ -74,6 +74,7 @@ snd-soc-ssm2602-objs := ssm2602.o
 snd-soc-ssm2602-spi-objs := ssm2602-spi.o
 snd-soc-ssm2602-i2c-objs := ssm2602-i2c.o
 snd-soc-sta32x-objs := sta32x.o
+snd-soc-sta350-objs := sta350.o
 snd-soc-sta529-objs := sta529.o
 snd-soc-stac9766-objs := stac9766.o
 snd-soc-tas5086-objs := tas5086.o
@@ -221,6 +222,7 @@ obj-$(CONFIG_SND_SOC_SSM2602)	+= snd-soc-ssm2602.o
 obj-$(CONFIG_SND_SOC_SSM2602_SPI)	+= snd-soc-ssm2602-spi.o
 obj-$(CONFIG_SND_SOC_SSM2602_I2C)	+= snd-soc-ssm2602-i2c.o
 obj-$(CONFIG_SND_SOC_STA32X)   += snd-soc-sta32x.o
+obj-$(CONFIG_SND_SOC_STA350)   += snd-soc-sta350.o
 obj-$(CONFIG_SND_SOC_STA529)   += snd-soc-sta529.o
 obj-$(CONFIG_SND_SOC_STAC9766)	+= snd-soc-stac9766.o
 obj-$(CONFIG_SND_SOC_TAS5086)	+= snd-soc-tas5086.o
sound/soc/codecs/sta350.c new file +1266 -0

1,266 lines not on this page · raw message

sound/soc/codecs/sta350.h new file +228 -0

228 lines not on this page · raw message

Signature · 1 line
1.8.5.3
#1 lore raw

[...]

Documentation/devicetree/bindings/sound/st,sta350.txt line 14

Quoted 6 lines
Documentation/devicetree/bindings/sound/st,sta350.txt new file +6 -0
+  - reset-gpio: a GPIO spec for the reset pin. If specified, it will be
+		deasserted before communication to the codec starts.
+
+  - power-down-gpio: a GPIO spec for the power down pin. If specified,
+		     it will be deasserted before communication to the codec
+		     starts.

I think the property name should always be '...-gpios', even if it is just one. There is some code in the kernel that assumes this.

[...]

Quoted 21 lines
sound/soc/codecs/sta350.c new file +21 -0
+
+static const unsigned int sta350_limiter_ac_attack_tlv[] = {
+	TLV_DB_RANGE_HEAD(2),
+	0, 7, TLV_DB_SCALE_ITEM(-1200, 200, 0),
+	8, 16, TLV_DB_SCALE_ITEM(300, 100, 0),
+};
+
+static const unsigned int sta350_limiter_ac_release_tlv[] = {
+	TLV_DB_RANGE_HEAD(5),
+	0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(-2900, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(-2000, 0, 0),
+	3, 8, TLV_DB_SCALE_ITEM(-1400, 200, 0),
+	8, 16, TLV_DB_SCALE_ITEM(-700, 100, 0),
+};
+
+static const unsigned int sta350_limiter_drc_attack_tlv[] = {
+	TLV_DB_RANGE_HEAD(3),
+	0, 7, TLV_DB_SCALE_ITEM(-3100, 200, 0),
+	8, 13, TLV_DB_SCALE_ITEM(-1600, 100, 0),
+	14, 16, TLV_DB_SCALE_ITEM(-1000, 300, 0),

sound/soc/codecs/sta350.c line 249

Quoted 10 lines
sound/soc/codecs/sta350.c new file +10 -0
+};
+
+static const unsigned int sta350_limiter_drc_release_tlv[] = {
+	TLV_DB_RANGE_HEAD(5),
+	0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
+	1, 2, TLV_DB_SCALE_ITEM(-3800, 200, 0),
+	3, 4, TLV_DB_SCALE_ITEM(-3300, 200, 0),
+	5, 12, TLV_DB_SCALE_ITEM(-3000, 200, 0),
+	13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0),
+};

Those TLVs above should use DECLARE_TLV_DB_RANGE(). The macro automatically sets the number specified in the TLV_DB_RANGE_HEAD is equal to the number of items, hence leaves less room for errors.

E.g.

static DECLARE_TLV_DB_RANGE(sta350_limiter_ac_attack_tlv,

	0, 7, TLV_DB_SCALE_ITEM(-1200, 200, 0),
	8, 16, TLV_DB_SCALE_ITEM(300, 100, 0),

);
[...]

Quoted 10 lines
sound/soc/codecs/sta350.c new file +10 -0
+
+static int sta350_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct sta350_priv *sta350;
+	int ret, i;
+
+	sta350 = devm_kzalloc(&i2c->dev, sizeof(struct sta350_priv),
+			      GFP_KERNEL);
+	if (!sta350)

sound/soc/codecs/sta350.c line 1190

Quoted 10 lines
sound/soc/codecs/sta350.c new file +10 -0
+		return -ENOMEM;
+
+	sta350->pdata = dev_get_platdata(&i2c->dev);
+	sta350->gpio_nreset = -EINVAL;
+	sta350->gpio_power_down = -EINVAL;
+
+	mutex_init(&sta350->coeff_lock);
+
+#ifdef CONFIG_OF
+	ret = sta350_probe_dt(&i2c->dev, sta350);

You still need to check if i2c->dev.of_node is actually set.

sound/soc/codecs/sta350.c line 1199

Quoted 9 lines
sound/soc/codecs/sta350.c new file +9 -0
+	if (ret < 0)
+		return ret;
+#endif
+
+	/* GPIOs */
+	if (gpio_is_valid(sta350->gpio_nreset)) {
+		ret = devm_gpio_request_one(&i2c->dev, sta350->gpio_nreset,
+					    GPIOF_OUT_INIT_HIGH,
+					    "ST350 Reset");

New code should use the GPIO descriptor API. See http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/linux/gpio/consumer.h

Quoted 3 lines
sound/soc/codecs/sta350.c new file +3 -0
+		if (ret < 0)
+			return ret;
+	}
#2 lore raw

Hi Lars,

Quoted 4 lines · Lars-Peter Clausen
Quoted 4 lines
sound/soc/codecs/sta350.c new file +4 -0
+	if (ret < 0)
+		return ret;
+#endif
+
Quoted 8 lines

sound/soc/codecs/sta350.c line 1199

Quoted 5 lines
sound/soc/codecs/sta350.c new file +5 -0
+	/* GPIOs */
+	if (gpio_is_valid(sta350->gpio_nreset)) {
+		ret = devm_gpio_request_one(&i2c->dev, sta350->gpio_nreset,
+					    GPIOF_OUT_INIT_HIGH,
+					    "ST350 Reset");

New code should use the GPIO descriptor API. See
http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/linux/gpio/consumer.h

Interesting new interface, missed that. Thanks for the pointer!

I changed all your remarks locally, but I'd like to give it a quick test. Will send v3 once I have confidence :)

Daniel