Skip to contentSkip to conversation

ALSA SOC driver for uda134x codec

PATCH RESEND Superseded Christian Pellegrin 2 participants 3 messages Nov 13, 2008 – Nov 14, 2008

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

cover ALSA SOC driver for uda134x codec

This patch adds support for the UDA1341 codec. It is *heavily* based on the one made by Zoltan Devai but:

since the UDA is the only use of the L3 protocol I can find I just embedded a stripped-down L3 bit-banging algorithm from the original RMK work. It is really small.

Generated on 20081113 against f7e1798a78a30bae1cf3ebc3e1b6f7c1bac57756

---
 include/sound/l3.h         |   18 ++
 include/sound/uda134x.h    |   58 ++++
 sound/soc/codecs/Kconfig   |    8 +
 sound/soc/codecs/Makefile  |    4 +
 sound/soc/codecs/l3.c      |   91 +++++++
 sound/soc/codecs/uda134x.c |  636 ++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 815 insertions(+), 0 deletions(-)
include/sound/l3.h new file +18 -0
new file mode 100644
index 0000000..423a08f
@@ -0,0 +1,18 @@
+#ifndef _L3_H_
+#define _L3_H_ 1
+
+struct l3_pins {
+	void (*setdat)(int);
+	void (*setclk)(int);
+	void (*setmode)(int);
+	int data_hold;
+	int data_setup;
+	int clock_high;
+	int mode_hold;
+	int mode;
+	int mode_setup;
+};
+
+int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len);
+
+#endif
include/sound/uda134x.h new file +58 -0

58 lines not on this page · raw message

sound/soc/codecs/Kconfig +8 -0
index b73c36a..7756e5b 100644
@@ -10,6 +10,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_TLV320AIC26 if SPI_MASTER
 	select SND_SOC_TLV320AIC3X if I2C
 	select SND_SOC_TWL4030 if TWL4030_CORE
+	select SND_SOC_UDA134X
 	select SND_SOC_UDA1380 if I2C
 	select SND_SOC_WM8510 if (I2C || SPI_MASTER)
 	select SND_SOC_WM8580 if I2C
@@ -84,6 +85,13 @@ config SND_SOC_TWL4030
 	tristate
 	depends on TWL4030_CORE
 
+config SND_SOC_L3
+       tristate
+
+config SND_SOC_UDA134X
+       tristate
+       select SND_SOC_L3
+
 config SND_SOC_UDA1380
         tristate
 
sound/soc/codecs/Makefile +4 -0
index 3b9b58a..9af993e 100644
@@ -8,6 +8,8 @@ snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic26-objs := tlv320aic26.o
 snd-soc-tlv320aic3x-objs := tlv320aic3x.o
 snd-soc-twl4030-objs := twl4030.o
+snd-soc-l3-objs := l3.o
+snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
 snd-soc-wm8510-objs := wm8510.o
 snd-soc-wm8580-objs := wm8580.o
@@ -31,6 +33,8 @@ obj-$(CONFIG_SND_SOC_TLV320AIC23)	+= snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC26)	+= snd-soc-tlv320aic26.o
 obj-$(CONFIG_SND_SOC_TLV320AIC3X)	+= snd-soc-tlv320aic3x.o
 obj-$(CONFIG_SND_SOC_TWL4030)	+= snd-soc-twl4030.o
+obj-$(CONFIG_SND_SOC_L3)	+= snd-soc-l3.o
+obj-$(CONFIG_SND_SOC_UDA134X)	+= snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA1380)	+= snd-soc-uda1380.o
 obj-$(CONFIG_SND_SOC_WM8510)	+= snd-soc-wm8510.o
 obj-$(CONFIG_SND_SOC_WM8580)	+= snd-soc-wm8580.o
sound/soc/codecs/l3.c new file +91 -0

91 lines not on this page · raw message

sound/soc/codecs/uda134x.c new file +636 -0

636 lines not on this page · raw message

--
1.4.4.4

#1 lore raw
Quoted 8 lines · Christian Pellegrin

This patch adds support for the UDA1341 codec. It is *heavily* based on the one made by Zoltan Devai but:

since the UDA is the only use of the L3 protocol I can find I just embedded a stripped-down L3 bit-banging algorithm from the original RMK work. It is really small.

Generated on 20081113 against f7e1798a78a30bae1cf3ebc3e1b6f7c1bac57756

A couple of minor procedural points:
- Normally the patches in a series are numbered starting from 1 with mail 0 being a cover letter ("This series does..." or similar).
- Information like the "Generated on" should go after the --- with the diffstat so that it doesn't go in the commit message.

include/sound/uda134x.h line 47

Quoted 4 lines

+++ b/include/sound/uda134x.h

include/sound/uda134x.h new file +2 -0
+extern struct snd_soc_dai uda134x_dai;
+extern struct snd_soc_codec_device soc_codec_dev_uda134x;

At least this should be in a header sound/soc/codecs - as I said previously that is the idiom used by codec drivers. However...

include/sound/uda134x.h line 56

Quoted 8 lines
include/sound/uda134x.h new file +8 -0
+struct uda134x_platform_data {
+	struct l3_pins l3;
+	void (*power) (int);
+	int model;
+#define UDA134X_UDA1340 0
+#define UDA134X_UDA1341 1
+#define UDA134X_UDA1344 2
+};

...putting this in a separate file in include/sound is a good idea.

Is having UDA1340 as zero a good idea - that'll mean that if someone forgets to initialise the model it'll come out as UDA1340? It might be better to start the model numbers from 1 so that it'll be obvious if that happens. Might also be an idea to use an enum rather than the series of #defines?

sound/soc/codecs/Kconfig config SND_SOC_TWL4030 · line 94

Quoted 4 lines
sound/soc/codecs/Kconfig +4 -0
+config SND_SOC_UDA134X
+       tristate
+       select SND_SOC_L3
+

Note that the select here won't actually do any good but it's useful for documentation.

sound/soc/codecs/Makefile snd-soc-tlv320aic23-objs := tlv320aic23.o · line 12

Quoted 10 lines
sound/soc/codecs/Makefile +2 -0
index 3b9b58a..9af993e 100644
@@ -8,6 +8,8 @@ snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic26-objs := tlv320aic26.o
 snd-soc-tlv320aic3x-objs := tlv320aic3x.o
 snd-soc-twl4030-objs := twl4030.o
+snd-soc-l3-objs := l3.o
+snd-soc-uda134x-objs := uda134x.o

Please keep this and the other build stuff sorted (it helps merges).

sound/soc/codecs/Makefile snd-soc-tlv320aic23-objs := tlv320aic23.o · line 15

Quoted 3 lines
sound/soc/codecs/Makefile +3 -0
+	if (reg >= UDA134X_REGS_NUM) {
+		printk(KERN_ERR "%s unkown register: reg: %d",
+		       __func__, reg);

Could use pr_error() here and elsewhere but doesn't make much difference either way - up to you.

sound/soc/codecs/Makefile snd-soc-tlv320aic23-objs := tlv320aic23.o

Quoted 12 lines
sound/soc/codecs/Makefile +12 -0
+static int uda134x_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->codec;
+	struct uda134x_priv *uda134x = codec->private_data;
+	struct snd_pcm_runtime *master_runtime;
+
+	if (uda134x->master_substream) {
+		master_runtime = uda134x->master_substream->runtime;
+
+		pr_debug("%s costrining to %d bits at %d\n", __func__,

constraining.

Quoted 12 lines
sound/soc/codecs/Makefile +12 -0
+static int uda134x_set_bias_level(struct snd_soc_codec *codec,
+				  enum snd_soc_bias_level level)
+{
+	u8 reg;
+	struct uda134x_platform_data *pd = codec->control_data;
+	int i;
+	u8 *cache = codec->reg_cache;
+
+	pr_debug("%s bias level %d\n", __func__, level);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:

sound/soc/codecs/Makefile

Quoted 10 lines
sound/soc/codecs/Makefile +10 -0
+		/* power on */
+		if (pd->power)
+			pd->power(1);
+		/* Sync reg_cache with the hardware */
+		for (i = 0; i < ARRAY_SIZE(uda134x_reg); i++)
+			codec->write(codec, i, *cache++);
+		/* ADC, DAC on */
+		reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1);
+		uda134x_write(codec, UDA134X_STATUS1, reg | 0x03);
+		break;

This should probably be done when going into SND_SOC_BIAS_STANDBY or at least _PREPARE. The codec will be brought up to _ON whenever a playback or record is active, spending most of the rest of the time at _STANDBY. The result will be that you're syncing the register cache to the codec every time playback starts, even if the codec is already on. _ON is expected to be very quick.

It might be worth implementing DAPM for the ADC and DAC power - the savings are probably very small but it should be very straightforward to implement. Not essential, though - doing it in bias_level() is also OK.

Quoted 1 line

+EXPORT_SYMBOL(uda134x_dai);

Note that since ASoC core is all EXPORT_SYMBOL_GPL() it'll be difficult for anyone to actually use this from non-GPLed code.

sound/soc/codecs/Makefile

Quoted 10 lines
sound/soc/codecs/Makefile +10 -0
+	pd = codec_setup_data;
+	switch (pd->model) {
+	case UDA134X_UDA1340:
+	case UDA134X_UDA1341:
+	case UDA134X_UDA1344:
+		break;
+	default:
+		printk(KERN_ERR "UDA134X SoC codec: "
+		       "unsupported model\n");
+		return -EINVAL;

Probably worth printing out what the model was set to if it's not recognised.

sound/soc/codecs/Makefile

Quoted 10 lines
sound/soc/codecs/Makefile +10 -0
+struct snd_soc_codec_device soc_codec_dev_uda134x = {
+	.probe =        uda134x_soc_probe,
+	.remove =       uda134x_soc_remove,
+#if defined(CONFIG_PM)
+	.suspend =      uda134x_soc_suspend,
+	.resume =       uda134x_soc_resume,
+#else
+	.suspend =      NULL,
+	.resume =       NULL,
+#endif /* CONFIG_PM */

The #else should be with the definition of the functions so there's no need for a conditional here.

#2 lore raw
Quoted 8 lines · Mark Brown

On Thu, Nov 13, 2008 at 04:41:30PM +0100, Christian Pellegrin wrote:

A couple of minor procedural points:
- Normally the patches in a series are numbered starting from 1 with mail 0 being a cover letter ("This series does..." or similar).
- Information like the "Generated on" should go after the --- with the diffstat so that it doesn't go in the commit message.

ack

Quoted 8 lines

include/sound/uda134x.h line 47

Quoted 4 lines

+++ b/include/sound/uda134x.h

include/sound/uda134x.h new file +2 -0
+extern struct snd_soc_dai uda134x_dai;
+extern struct snd_soc_codec_device soc_codec_dev_uda134x;

At least this should be in a header sound/soc/codecs - as I said previously that is the idiom used by codec drivers. However...

ack

Quoted 9 lines

...putting this in a separate file in include/sound is a good idea.

Is having UDA1340 as zero a good idea - that'll mean that if someone forgets to initialise the model it'll come out as UDA1340? It might be better to start the model numbers from 1 so that it'll be obvious if that happens. Might also be an idea to use an enum rather than the series of #defines?

good point, ack

Quoted 11 lines

sound/soc/codecs/Makefile snd-soc-tlv320aic23-objs := tlv320aic23.o · line 12

Quoted 8 lines
sound/soc/codecs/Makefile +2 -0
@@ -8,6 +8,8 @@ snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic26-objs := tlv320aic26.o
 snd-soc-tlv320aic3x-objs := tlv320aic3x.o
 snd-soc-twl4030-objs := twl4030.o
+snd-soc-l3-objs := l3.o
+snd-soc-uda134x-objs := uda134x.o

Please keep this and the other build stuff sorted (it helps merges).

I'll sort alphabetically

Quoted 7 lines

sound/soc/codecs/Makefile snd-soc-tlv320aic23-objs := tlv320aic23.o · line 15

Quoted 3 lines
sound/soc/codecs/Makefile +3 -0
+     if (reg >= UDA134X_REGS_NUM) {
+             printk(KERN_ERR "%s unkown register: reg: %d",
+                    __func__, reg);

Could use pr_error() here and elsewhere but doesn't make much difference either way - up to you.

didn't know about it. The next driver will use it because it's shorter.

Quoted 4 lines
Quoted 1 line

+ pr_debug("%s costrining to %d bits at %d\n", __func__,

constraining.

ack

Quoted 6 lines

sound/soc/codecs/Makefile

Quoted 5 lines
sound/soc/codecs/Makefile +5 -0
+                     codec->write(codec, i, *cache++);
+             /* ADC, DAC on */
+             reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1);
+             uda134x_write(codec, UDA134X_STATUS1, reg | 0x03);
+             break;
Quoted 6 lines

This should probably be done when going into SND_SOC_BIAS_STANDBY or at least _PREPARE. The codec will be brought up to _ON whenever a playback or record is active, spending most of the rest of the time at _STANDBY. The result will be that you're syncing the register cache to the codec every time playback starts, even if the codec is already on. _ON is expected to be very quick.

ack, I was thinking to put it in prepare but I wasn't sure.

Quoted 6 lines
Quoted 2 lines

+EXPORT_SYMBOL(uda134x_dai);

Note that since ASoC core is all EXPORT_SYMBOL_GPL() it'll be difficult for anyone to actually use this from non-GPLed code.

ack

Quoted 7 lines

sound/soc/codecs/Makefile

Quoted 3 lines
sound/soc/codecs/Makefile +3 -0
+             printk(KERN_ERR "UDA134X SoC codec: "
+                    "unsupported model\n");
+             return -EINVAL;

Probably worth printing out what the model was set to if it's not recognised.

ack

Quoted 4 lines

The #else should be with the definition of the functions so there's no need for a conditional here.

ack

Signature · 5 lines
Christian Pellegrin, see http://www.evolware.org/chri/
"Real Programmers don't play tennis, or any other sport which requires
you to change clothes. Mountain climbing is OK, and Real Programmers
wear their climbing boots to work in case a mountain should suddenly
spring up in the middle of the computer room."