alsa-devel.alsa-project.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/5] ASoC: Add support for machine specific trigger callback
@ 2014-04-28 12:17 Stefan Roese
  2014-04-28 12:17 ` [PATCH 2/5] ASoC: Add HA (HEAD acoustics) DSP codec driver template Stefan Roese
                   ` (4 more replies)
  0 siblings, 5 replies; 12+ messages in thread
From: Stefan Roese @ 2014-04-28 12:17 UTC (permalink / raw)
  To: alsa-devel, linux-omap; +Cc: broonie, Jarkko Nikula

From: Jarkko Nikula <jarkko.nikula@bitmer.com>

Machine specific trigger callback allows to do final stream start/stop
related operations in a machine driver after setting up the codec, DMA and
DAI.

One example could be clock management for linked streams case where machine
driver can start/stop synchronously the linked streams.

Signed-off-by: Jarkko Nikula <jarkko.nikula@bitmer.com>
Signed-off-by: Stefan Roese <sr@denx.de>
---
 sound/soc/soc-pcm.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 2cedf09..a3a7021 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -819,6 +819,13 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 		if (ret < 0)
 			return ret;
 	}
+
+	if (rtd->dai_link->ops && rtd->dai_link->ops->trigger) {
+		ret = rtd->dai_link->ops->trigger(substream, cmd);
+		if (ret < 0)
+			return ret;
+	}
+
 	return 0;
 }
 
-- 
1.9.1


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

* [PATCH 2/5] ASoC: Add HA (HEAD acoustics) DSP codec driver template
  2014-04-28 12:17 [PATCH 1/5] ASoC: Add support for machine specific trigger callback Stefan Roese
@ 2014-04-28 12:17 ` Stefan Roese
  2014-04-28 14:45   ` [alsa-devel] " Lars-Peter Clausen
                     ` (2 more replies)
  2014-04-28 12:17 ` [PATCH 3/5] ASoC: omap: Add HA (HEAD acoustics) DSP add-on card audio driver for TAO3530 Stefan Roese
                   ` (3 subsequent siblings)
  4 siblings, 3 replies; 12+ messages in thread
From: Stefan Roese @ 2014-04-28 12:17 UTC (permalink / raw)
  To: alsa-devel, linux-omap; +Cc: broonie, Jarkko Nikula, Thorsten Eisbein

From: Jarkko Nikula <jarkko.nikula@bitmer.com>

This codec driver template represents an I2C controlled multichannel audio
codec that has many typical ASoC codec driver features like volume controls,
mixer stages, mux selection, output power control, in-codec audio routings,
codec bias management and DAI link configuration.

Updates from Stefan Roese, 2014-04-28:
Port the HA DSP codec driver to Linux v3.15-rc. This includes
support for DT based probing. No platform-data code is needed
any more, DT nodes are sufficient.

Signed-off-by: Jarkko Nikula <jarkko.nikula@bitmer.com>
Signed-off-by: Stefan Roese <sr@denx.de>
Cc: Thorsten Eisbein <thorsten.eisbein@head-acoustics.de>
---
 sound/soc/codecs/Kconfig  |   4 +
 sound/soc/codecs/Makefile |   2 +
 sound/soc/codecs/ha-dsp.c | 419 ++++++++++++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/ha-dsp.h |  50 ++++++
 4 files changed, 475 insertions(+)
 create mode 100644 sound/soc/codecs/ha-dsp.c
 create mode 100644 sound/soc/codecs/ha-dsp.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index f0e8401..f357988 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -51,6 +51,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_DA732X if I2C
 	select SND_SOC_DA9055 if I2C
 	select SND_SOC_BT_SCO
+	select SND_SOC_HA_DSP if I2C
 	select SND_SOC_ISABELLE if I2C
 	select SND_SOC_JZ4740_CODEC
 	select SND_SOC_LM4857 if I2C
@@ -343,6 +344,9 @@ config SND_SOC_BT_SCO
 config SND_SOC_DMIC
 	tristate
 
+config SND_SOC_HA_DSP
+	tristate
+
 config SND_SOC_HDMI_CODEC
        tristate "HDMI stub CODEC"
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 3c4d275..f296bec 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -39,6 +39,7 @@ snd-soc-da732x-objs := da732x.o
 snd-soc-da9055-objs := da9055.o
 snd-soc-bt-sco-objs := bt-sco.o
 snd-soc-dmic-objs := dmic.o
+snd-soc-ha-dsp-objs := ha-dsp.o
 snd-soc-isabelle-objs := isabelle.o
 snd-soc-jz4740-codec-objs := jz4740.o
 snd-soc-l3-objs := l3.o
@@ -190,6 +191,7 @@ obj-$(CONFIG_SND_SOC_DA732X)	+= snd-soc-da732x.o
 obj-$(CONFIG_SND_SOC_DA9055)	+= snd-soc-da9055.o
 obj-$(CONFIG_SND_SOC_BT_SCO)	+= snd-soc-bt-sco.o
 obj-$(CONFIG_SND_SOC_DMIC)	+= snd-soc-dmic.o
+obj-$(CONFIG_SND_SOC_HA_DSP)	+= snd-soc-ha-dsp.o
 obj-$(CONFIG_SND_SOC_ISABELLE)	+= snd-soc-isabelle.o
 obj-$(CONFIG_SND_SOC_JZ4740_CODEC)	+= snd-soc-jz4740-codec.o
 obj-$(CONFIG_SND_SOC_L3)	+= snd-soc-l3.o
diff --git a/sound/soc/codecs/ha-dsp.c b/sound/soc/codecs/ha-dsp.c
new file mode 100644
index 0000000..7cf24dc
--- /dev/null
+++ b/sound/soc/codecs/ha-dsp.c
@@ -0,0 +1,419 @@
+/*
+ * ha-dsp.c  --  HA DSP ALSA SoC Audio driver
+ *
+ * Copyright 2011 Head acoustics GmbH
+ *
+ * Author: Jarkko Nikula <jarkko.nikula@bitmer.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.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+
+#include "ha-dsp.h"
+
+/* Reset default register values for soc-cache */
+static const struct reg_default ha_dsp_reg_defaults[] = {
+	{ 0x00, 0x00 },
+	{ 0x01, 0x55 },
+	{ 0x02, 0x55 },
+	{ 0x03, 0x00 },
+	{ 0x04, 0x00 },
+	{ 0x05, 0x00 },
+	{ 0x06, 0x00 },
+	{ 0x07, 0x00 },
+	{ 0x08, 0x02 },
+	{ 0x09, 0x02 },
+	{ 0x0a, 0x02 },
+	{ 0x0b, 0x02 },
+	{ 0x0c, 0x02 },
+	{ 0x0d, 0x02 },
+	{ 0x0e, 0x02 },
+	{ 0x0f, 0x02 },
+};
+
+/* DSP mode selection */
+static const char *ha_dsp_mode_texts[] = {"Mode 1", "Mode 2"};
+static SOC_ENUM_SINGLE_DECL(ha_dsp_mode_enum, HA_DSP_CTRL, 0,
+			    ha_dsp_mode_texts);
+
+/* Monitor output mux selection */
+static const char *ha_dsp_monitor_texts[] = {"Off", "ADC", "DAC"};
+static SOC_ENUM_SINGLE_DECL(ha_dsp_monitor_enum, HA_DSP_CTRL, 1,
+			    ha_dsp_monitor_texts);
+
+static const struct snd_kcontrol_new ha_dsp_monitor_control =
+	SOC_DAPM_ENUM("Route", ha_dsp_monitor_enum);
+
+/* Output mixers */
+static const struct snd_kcontrol_new ha_dsp_out1_mixer_controls[] = {
+	SOC_DAPM_SINGLE("DAC Switch", HA_DSP_OUT1_CTRL, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN Bypass Switch", HA_DSP_OUT1_CTRL, 2, 1, 0),
+};
+static const struct snd_kcontrol_new ha_dsp_out2_mixer_controls[] = {
+	SOC_DAPM_SINGLE("DAC Switch", HA_DSP_OUT2_CTRL, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN Bypass Switch", HA_DSP_OUT2_CTRL, 2, 1, 0),
+};
+static const struct snd_kcontrol_new ha_dsp_out3_mixer_controls[] = {
+	SOC_DAPM_SINGLE("DAC Switch", HA_DSP_OUT3_CTRL, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN Bypass Switch", HA_DSP_OUT3_CTRL, 2, 1, 0),
+};
+static const struct snd_kcontrol_new ha_dsp_out4_mixer_controls[] = {
+	SOC_DAPM_SINGLE("DAC Switch", HA_DSP_OUT4_CTRL, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN Bypass Switch", HA_DSP_OUT4_CTRL, 2, 1, 0),
+};
+static const struct snd_kcontrol_new ha_dsp_out5_mixer_controls[] = {
+	SOC_DAPM_SINGLE("DAC Switch", HA_DSP_OUT5_CTRL, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN Bypass Switch", HA_DSP_OUT5_CTRL, 2, 1, 0),
+};
+static const struct snd_kcontrol_new ha_dsp_out6_mixer_controls[] = {
+	SOC_DAPM_SINGLE("DAC Switch", HA_DSP_OUT6_CTRL, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN Bypass Switch", HA_DSP_OUT6_CTRL, 2, 1, 0),
+};
+static const struct snd_kcontrol_new ha_dsp_out7_mixer_controls[] = {
+	SOC_DAPM_SINGLE("DAC Switch", HA_DSP_OUT7_CTRL, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN Bypass Switch", HA_DSP_OUT1_CTRL, 2, 1, 0),
+};
+static const struct snd_kcontrol_new ha_dsp_out8_mixer_controls[] = {
+	SOC_DAPM_SINGLE("DAC Switch", HA_DSP_OUT8_CTRL, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN Bypass Switch", HA_DSP_OUT8_CTRL, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new ha_dsp_snd_controls[] = {
+	SOC_SINGLE("ADC Capture Volume",
+		   HA_DSP_ADC_VOL, 0, 0x7f, 0),
+	SOC_SINGLE("ADC Capture Switch",
+		   HA_DSP_ADC_VOL, 7, 0x01, 1),
+
+	SOC_SINGLE("PCM Playback Volume",
+		   HA_DSP_DAC_VOL, 0, 0x7f, 0),
+	SOC_SINGLE("PCM Playback Switch",
+		   HA_DSP_DAC_VOL, 7, 0x01, 1),
+
+	SOC_ENUM("DSP Mode", ha_dsp_mode_enum),
+};
+
+static const struct snd_soc_dapm_widget ha_dsp_widgets[] = {
+	SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_MIXER("OUT1 Mixer", SND_SOC_NOPM, 0, 0,
+			   &ha_dsp_out1_mixer_controls[0],
+			   ARRAY_SIZE(ha_dsp_out1_mixer_controls)),
+	SND_SOC_DAPM_MIXER("OUT2 Mixer", SND_SOC_NOPM, 0, 0,
+			   &ha_dsp_out2_mixer_controls[0],
+			   ARRAY_SIZE(ha_dsp_out2_mixer_controls)),
+	SND_SOC_DAPM_MIXER("OUT3 Mixer", SND_SOC_NOPM, 0, 0,
+			   &ha_dsp_out3_mixer_controls[0],
+			   ARRAY_SIZE(ha_dsp_out3_mixer_controls)),
+	SND_SOC_DAPM_MIXER("OUT4 Mixer", SND_SOC_NOPM, 0, 0,
+			   &ha_dsp_out4_mixer_controls[0],
+			   ARRAY_SIZE(ha_dsp_out4_mixer_controls)),
+	SND_SOC_DAPM_MIXER("OUT5 Mixer", SND_SOC_NOPM, 0, 0,
+			   &ha_dsp_out5_mixer_controls[0],
+			   ARRAY_SIZE(ha_dsp_out5_mixer_controls)),
+	SND_SOC_DAPM_MIXER("OUT6 Mixer", SND_SOC_NOPM, 0, 0,
+			   &ha_dsp_out6_mixer_controls[0],
+			   ARRAY_SIZE(ha_dsp_out6_mixer_controls)),
+	SND_SOC_DAPM_MIXER("OUT7 Mixer", SND_SOC_NOPM, 0, 0,
+			   &ha_dsp_out7_mixer_controls[0],
+			   ARRAY_SIZE(ha_dsp_out7_mixer_controls)),
+	SND_SOC_DAPM_MIXER("OUT8 Mixer", SND_SOC_NOPM, 0, 0,
+			   &ha_dsp_out8_mixer_controls[0],
+			   ARRAY_SIZE(ha_dsp_out8_mixer_controls)),
+
+	SND_SOC_DAPM_PGA("OUT1 PGA", HA_DSP_OUT1_CTRL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("OUT2 PGA", HA_DSP_OUT2_CTRL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("OUT3 PGA", HA_DSP_OUT3_CTRL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("OUT4 PGA", HA_DSP_OUT4_CTRL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("OUT5 PGA", HA_DSP_OUT5_CTRL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("OUT6 PGA", HA_DSP_OUT6_CTRL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("OUT7 PGA", HA_DSP_OUT7_CTRL, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("OUT8 PGA", HA_DSP_OUT8_CTRL, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("Monitor Out Mux", SND_SOC_NOPM, 0, 0,
+			 &ha_dsp_monitor_control),
+
+	/* Input pins */
+	SND_SOC_DAPM_INPUT("IN1"),
+	SND_SOC_DAPM_INPUT("IN2"),
+	SND_SOC_DAPM_INPUT("IN3"),
+	SND_SOC_DAPM_INPUT("IN4"),
+	SND_SOC_DAPM_INPUT("IN5"),
+	SND_SOC_DAPM_INPUT("IN6"),
+	SND_SOC_DAPM_INPUT("IN7"),
+	SND_SOC_DAPM_INPUT("IN8"),
+
+	/* Output pins */
+	SND_SOC_DAPM_OUTPUT("OUT1"),
+	SND_SOC_DAPM_OUTPUT("OUT2"),
+	SND_SOC_DAPM_OUTPUT("OUT3"),
+	SND_SOC_DAPM_OUTPUT("OUT4"),
+	SND_SOC_DAPM_OUTPUT("OUT5"),
+	SND_SOC_DAPM_OUTPUT("OUT6"),
+	SND_SOC_DAPM_OUTPUT("OUT7"),
+	SND_SOC_DAPM_OUTPUT("OUT8"),
+	SND_SOC_DAPM_OUTPUT("MONITOR"),
+};
+
+static const struct snd_soc_dapm_route ha_dsp_routes[] = {
+	/* Inputs to ADC */
+	{"ADC", NULL, "IN1"},
+	{"ADC", NULL, "IN2"},
+	{"ADC", NULL, "IN3"},
+	{"ADC", NULL, "IN4"},
+	{"ADC", NULL, "IN5"},
+	{"ADC", NULL, "IN6"},
+	{"ADC", NULL, "IN7"},
+	{"ADC", NULL, "IN8"},
+
+	/* DAC and input bypass paths to outputs */
+	{"OUT1 Mixer", "DAC Switch", "DAC"},
+	{"OUT1 Mixer", "IN Bypass Switch", "IN1"},
+	{"OUT1 PGA", NULL, "OUT1 Mixer"},
+	{"OUT1", NULL, "OUT1 PGA"},
+
+	{"OUT2 Mixer", "DAC Switch", "DAC"},
+	{"OUT2 Mixer", "IN Bypass Switch", "IN2"},
+	{"OUT2 PGA", NULL, "OUT2 Mixer"},
+	{"OUT2", NULL, "OUT2 PGA"},
+
+	{"OUT3 Mixer", "DAC Switch", "DAC"},
+	{"OUT3 Mixer", "IN Bypass Switch", "IN3"},
+	{"OUT3 PGA", NULL, "OUT3 Mixer"},
+	{"OUT3", NULL, "OUT3 PGA"},
+
+	{"OUT4 Mixer", "DAC Switch", "DAC"},
+	{"OUT4 Mixer", "IN Bypass Switch", "IN4"},
+	{"OUT4 PGA", NULL, "OUT4 Mixer"},
+	{"OUT4", NULL, "OUT4 PGA"},
+
+	{"OUT5 Mixer", "DAC Switch", "DAC"},
+	{"OUT5 Mixer", "IN Bypass Switch", "IN5"},
+	{"OUT5 PGA", NULL, "OUT5 Mixer"},
+	{"OUT5", NULL, "OUT5 PGA"},
+
+	{"OUT6 Mixer", "DAC Switch", "DAC"},
+	{"OUT6 Mixer", "IN Bypass Switch", "IN6"},
+	{"OUT6 PGA", NULL, "OUT6 Mixer"},
+	{"OUT6", NULL, "OUT6 PGA"},
+
+	{"OUT7 Mixer", "DAC Switch", "DAC"},
+	{"OUT7 Mixer", "IN Bypass Switch", "IN7"},
+	{"OUT7 PGA", NULL, "OUT7 Mixer"},
+	{"OUT7", NULL, "OUT7 PGA"},
+
+	{"OUT8 Mixer", "DAC Switch", "DAC"},
+	{"OUT8 Mixer", "IN Bypass Switch", "IN8"},
+	{"OUT8 PGA", NULL, "OUT8 Mixer"},
+	{"OUT8", NULL, "OUT8 PGA"},
+
+	/* Monitor output */
+	{"Monitor Out Mux", "ADC", "ADC"},
+	{"Monitor Out Mux", "DAC", "DAC"},
+	{"MONITOR", NULL, "Monitor Out Mux"},
+};
+
+static int ha_dsp_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->codec;
+
+	dev_dbg(codec->dev, "Sample format 0x%X\n", params_format(params));
+	dev_dbg(codec->dev, "Channels %d\n", params_channels(params));
+	dev_dbg(codec->dev, "Rate %d\n", params_rate(params));
+
+	return 0;
+}
+
+static int ha_dsp_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			      unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+
+	/* codec role */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		dev_dbg(codec->dev, "Codec is master\n");
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		dev_dbg(codec->dev, "Codec is slave\n");
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* DAI format */
+	dev_dbg(codec->dev, "DAI format 0x%X",
+		fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+
+	/* Bit clock and frame sync polarities */
+	dev_dbg(codec->dev, "Clock polarities 0x%X\n",
+		fmt & SND_SOC_DAIFMT_INV_MASK);
+
+	return 0;
+}
+
+static int ha_dsp_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+	dev_dbg(codec->dev, "Changing bias from %d to %d\n",
+		codec->dapm.bias_level, level);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		/* Set PLL on */
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		/* Set power on, Set PLL off */
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* Set power down */
+		break;
+	}
+	codec->dapm.bias_level = level;
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops ha_dsp_dai_ops = {
+	.hw_params	= ha_dsp_hw_params,
+	.set_fmt	= ha_dsp_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver ha_dsp_dai = {
+	.name = "ha-dsp-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 16,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		/* We use only 32 Bits for Audio */
+		.formats = SNDRV_PCM_FMTBIT_S32_LE,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 16,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		/* We use only 32 Bits for Audio */
+		.formats = SNDRV_PCM_FMTBIT_S32_LE,
+	},
+	.ops = &ha_dsp_dai_ops,
+};
+
+static int ha_dsp_probe(struct snd_soc_codec *codec)
+{
+	int ret;
+
+	codec->control_data = dev_get_regmap(codec->dev->parent, NULL);
+	ret = snd_soc_codec_set_cache_io(codec, codec->control_data);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int ha_dsp_remove(struct snd_soc_codec *codec)
+{
+	snd_soc_write(codec, HA_DSP_CTRL, HA_DSP_SW_RESET);
+
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_ha_dsp = {
+	.probe = ha_dsp_probe,
+	.remove = ha_dsp_remove,
+	.set_bias_level = ha_dsp_set_bias_level,
+
+	.controls = ha_dsp_snd_controls,
+	.num_controls = ARRAY_SIZE(ha_dsp_snd_controls),
+	.dapm_widgets = ha_dsp_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(ha_dsp_widgets),
+	.dapm_routes = ha_dsp_routes,
+	.num_dapm_routes = ARRAY_SIZE(ha_dsp_routes),
+};
+
+static const struct regmap_config ha_dsp_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = 0x0f,
+	.reg_defaults = ha_dsp_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(ha_dsp_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int ha_dsp_i2c_probe(struct i2c_client *client,
+			    const struct i2c_device_id *id)
+{
+	struct regmap *regmap;
+	int ret;
+
+	regmap = devm_regmap_init_i2c(client, &ha_dsp_regmap);
+	if (IS_ERR(regmap)) {
+		ret = PTR_ERR(regmap);
+		dev_err(&client->dev, "Failed to create regmap: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_register_codec(&client->dev, &soc_codec_dev_ha_dsp,
+				     &ha_dsp_dai, 1);
+
+	return ret;
+}
+
+static int ha_dsp_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+
+	return 0;
+}
+
+/*
+ * This name/ID is neded to match the DT node for the codec
+ */
+static const struct i2c_device_id ha_dsp_i2c_id[] = {
+	{ "ha-dsp-audio", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ha_dsp_i2c_id);
+
+static struct i2c_driver ha_dsp_i2c_driver = {
+	.driver = {
+		.name = "ha-dsp-codec",
+		.owner = THIS_MODULE,
+	},
+	.probe = ha_dsp_i2c_probe,
+	.remove = ha_dsp_i2c_remove,
+	.id_table = ha_dsp_i2c_id,
+};
+
+module_i2c_driver(ha_dsp_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC HA DSP driver");
+MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ha-dsp.h b/sound/soc/codecs/ha-dsp.h
new file mode 100644
index 0000000..cab82f8
--- /dev/null
+++ b/sound/soc/codecs/ha-dsp.h
@@ -0,0 +1,50 @@
+/*
+ * ha-dsp.h  --  HA DSP ALSA SoC Audio driver
+ *
+ * Copyright 2011 Head acoustics GmbH
+ *
+ * Author: Jarkko Nikula <jhnikula@gmail.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.
+ */
+
+#ifndef __HA_DSP_H__
+#define __HA_DSP_H__
+
+/* Registers */
+
+/*
+ * Bit 2-1: Monitor output selection: Off, ADC, DAC
+ * Bit 0: DSP Mode
+ */
+#define HA_DSP_CTRL		0x00
+
+/*
+ * Bit 7: Mute
+ * Bit 6-0: Volume
+ */
+#define HA_DSP_DAC_VOL		0x01
+#define HA_DSP_ADC_VOL		0x02
+
+/*
+ * Bit 2: INx Bypass to OUTx Switch
+ * Bit 1: DAC to OUTx switch
+ * Bit 0: Output power
+ */
+#define HA_DSP_OUT1_CTRL	0x08
+#define HA_DSP_OUT2_CTRL	0x09
+#define HA_DSP_OUT3_CTRL	0x0a
+#define HA_DSP_OUT4_CTRL	0x0b
+#define HA_DSP_OUT5_CTRL	0x0c
+#define HA_DSP_OUT6_CTRL	0x0d
+#define HA_DSP_OUT7_CTRL	0x0e
+#define HA_DSP_OUT8_CTRL	0x0f
+
+/* Register bits and values */
+
+/* HA_DSP_CTRL */
+#define HA_DSP_SW_RESET		0xff
+
+#endif
-- 
1.9.1


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

* [PATCH 3/5] ASoC: omap: Add HA (HEAD acoustics) DSP add-on card audio driver for TAO3530
  2014-04-28 12:17 [PATCH 1/5] ASoC: Add support for machine specific trigger callback Stefan Roese
  2014-04-28 12:17 ` [PATCH 2/5] ASoC: Add HA (HEAD acoustics) DSP codec driver template Stefan Roese
@ 2014-04-28 12:17 ` Stefan Roese
  2014-04-28 17:35   ` Jarkko Nikula
                     ` (2 more replies)
  2014-04-28 12:17 ` [PATCH 4/5] DT: Add vendor prefix for HEAD acoustics Stefan Roese
                   ` (2 subsequent siblings)
  4 siblings, 3 replies; 12+ messages in thread
From: Stefan Roese @ 2014-04-28 12:17 UTC (permalink / raw)
  To: alsa-devel, linux-omap; +Cc: broonie, Jarkko Nikula, Thorsten Eisbein

From: Jarkko Nikula <jarkko.nikula@bitmer.com>

HA DSP card which features a HA DSP audio codec is intended to be connected
to TAO-3530 (or BeagleBoard) using McBSP3 for digital audio and I2C bus for
codec control. A GPIO signal from CPU to codec is used to request clock
signals active.

This machine driver has a special feature to support linked streams where
playback and capture can be triggered HW simultaneously. This is implemented
for linked streams by activating/deactivating the clock request signal to
codec only after both streams are ready to start/stop. For non-linked streams
the request signal is active whenever there is a stream active.

Updates from Stefan Roese, 2014-04-28:
Port the HA DSP add-on card audio driver to Linux v3.15-rc. This
includes support for DT based probing. No platform-data code is
needed any more, DT nodes are sufficient.

The GPIO used to synchronize the clock for playback and record
is now configured via the DT as well (no #define any more). When
this GPIO is not configured in the DT, the sync clock feature is
disabled.

The slave mode #define was also moved to a DT configuration
property (ha_dsp_codec_slave). If this property is set in the DT
sound card device node, then this testing slave mode is used.
Otherwise the "normal" operation is selected.

Also the now recommended card registration via snd_soc_register_card()
is used instead of platform_device_add().

Signed-off-by: Jarkko Nikula <jarkko.nikula@bitmer.com>
Signed-off-by: Stefan Roese <sr@denx.de>
Cc: Thorsten Eisbein <thorsten.eisbein@head-acoustics.de>
---
 sound/soc/omap/Kconfig       |  11 ++
 sound/soc/omap/Makefile      |   2 +
 sound/soc/omap/ha-dsp-card.c | 307 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 320 insertions(+)
 create mode 100644 sound/soc/omap/ha-dsp-card.c

diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index e006593..86cc869 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -117,3 +117,14 @@ config SND_OMAP_SOC_OMAP3_PANDORA
 	select SND_SOC_TWL4030
 	help
 	  Say Y if you want to add support for SoC audio on the OMAP3 Pandora.
+
+config SND_OMAP_SOC_HA_DSP_CARD
+	tristate "SoC Audio support for HA DSP add-on card"
+	depends on TWL4030_CORE && SND_OMAP_SOC
+	depends on SND_OMAP_SOC_OMAP_TWL4030
+	select SND_OMAP_SOC_MCBSP
+	select SND_SOC_TWL4030
+	select SND_SOC_HA_DSP
+	help
+	  Say Y if you want to add support for Soc audio on HA DSP add-on card
+	  for TAO-3530/Thunder or BeagleBoard
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
index a725905..02c0094 100644
--- a/sound/soc/omap/Makefile
+++ b/sound/soc/omap/Makefile
@@ -21,6 +21,7 @@ snd-soc-omap-abe-twl6040-objs := omap-abe-twl6040.o
 snd-soc-omap-twl4030-objs := omap-twl4030.o
 snd-soc-omap3pandora-objs := omap3pandora.o
 snd-soc-omap-hdmi-card-objs := omap-hdmi-card.o
+snd-soc-ha-dsp-card-objs := ha-dsp-card.o
 
 obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
 obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o
@@ -31,3 +32,4 @@ obj-$(CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o
 obj-$(CONFIG_SND_OMAP_SOC_OMAP_TWL4030) += snd-soc-omap-twl4030.o
 obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o
 obj-$(CONFIG_SND_OMAP_SOC_OMAP_HDMI) += snd-soc-omap-hdmi-card.o
+obj-$(CONFIG_SND_OMAP_SOC_HA_DSP_CARD) += snd-soc-ha-dsp-card.o
diff --git a/sound/soc/omap/ha-dsp-card.c b/sound/soc/omap/ha-dsp-card.c
new file mode 100644
index 0000000..d2656ff
--- /dev/null
+++ b/sound/soc/omap/ha-dsp-card.c
@@ -0,0 +1,307 @@
+/*
+ * ha-dsp-card.c  --  SoC audio HA-DSP add-on card for TAO-3530
+ *
+ * Author: Jarkko Nikula <jarkko.nikula@bitmer.com>
+ *
+ * Additional changes by:
+ *   Thorsten Eisbein <thorsten.eisbein@head-acoustics.de>
+ *   Stefan Roese <sr@denx.de>
+ *
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
+#include "omap-mcbsp.h"
+
+struct ha_dsp_card {
+	int slave;
+	int gpio;
+	int play_act;
+	int rec_act;
+};
+
+static int ha_dsp_card_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_card *card = codec->card;
+	struct ha_dsp_card *priv = snd_soc_card_get_drvdata(card);
+	unsigned int fmt;
+	int ret;
+	int div;
+
+	switch (params_channels(params)) {
+	case 2:
+	case 4:
+	case 8:
+	case 16:
+		fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (priv->slave)
+		fmt |= SND_SOC_DAIFMT_CBS_CFS;
+	else
+		fmt |= SND_SOC_DAIFMT_CBM_CFM;
+
+	/* Set codec DAI configuration */
+	ret = snd_soc_dai_set_fmt(codec_dai, fmt);
+	if (ret < 0) {
+		pr_err("can't set codec DAI configuration\n");
+		return ret;
+	}
+
+	/* Set cpu DAI configuration */
+	ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+	if (ret < 0) {
+		pr_err("can't set cpu DAI configuration\n");
+		return ret;
+	}
+
+	if (priv->slave) {
+		ret = snd_soc_dai_set_sysclk(cpu_dai,
+					     OMAP_MCBSP_SYSCLK_CLKS_FCLK,
+					     96000000, SND_SOC_CLOCK_IN);
+		if (ret < 0) {
+			pr_err("can't set McBSP sysclk\n");
+			return ret;
+		}
+
+		/*
+		 * Calculate McBSP SRG divisor in McBSP master mode
+		 */
+		div = 96000000 / params_rate(params) / params_channels(params);
+		switch (params_format(params)) {
+		case SNDRV_PCM_FORMAT_S16_LE:
+			div /= 16;
+			break;
+		case SNDRV_PCM_FORMAT_S24_LE:
+		case SNDRV_PCM_FORMAT_S32_LE:
+			div /= 32;
+			break;
+		};
+
+		/*
+		 * Round to maximum divisor if needed. This means that extra
+		 * bit-clock cycles are transmitted when sample rate and number
+		 * of bits in frame (channels * sample bits) are low.
+		 */
+		if (div >= 256)
+			div = 256;
+
+		ret = snd_soc_dai_set_clkdiv(cpu_dai, OMAP_MCBSP_CLKGDV, div);
+		if (ret < 0) {
+			pr_err("can't set SRG clock divider\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int ha_dsp_card_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_card *card = codec->card;
+	struct ha_dsp_card *priv = snd_soc_card_get_drvdata(card);
+	int start;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		start = 1;
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		start = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (priv->gpio != -1) {
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			priv->play_act = start;
+		else
+			priv->rec_act = start;
+
+		if (snd_pcm_stream_linked(substream)) {
+			/*
+			 * Set/clear the clock request gpio only after both
+			 * streams have started/stopped in streams are linked
+			 * case
+			 */
+			if (priv->play_act == priv->rec_act)
+				gpio_set_value(priv->gpio, start);
+		} else {
+			/*
+			 * Keep clock request gpio active as long as there is
+			 * either playback or capture active in non-linked
+			 * stream case
+			 */
+			gpio_set_value(priv->gpio,
+				       (priv->play_act || priv->rec_act));
+		}
+	}
+
+	return 0;
+}
+
+static struct snd_soc_ops ha_dsp_card_ops = {
+	.hw_params = ha_dsp_card_hw_params,
+	.trigger = ha_dsp_card_trigger,
+};
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link ha_dsp_card_dai = {
+	.name = "HA-DSP",
+	.stream_name = "HA-DSP",
+	.cpu_dai_name = "omap-mcbsp-dai.2",
+	.platform_name = "omap-pcm-audio",
+	.codec_dai_name = "ha-dsp-hifi",
+	.codec_name = "ha-dsp-codec.2-0020",
+	.ops = &ha_dsp_card_ops,
+};
+
+/* Audio machine driver */
+static struct snd_soc_card snd_soc_ha_dsp_card = {
+	.name = "tao3530-ha-dsp",
+	.owner = THIS_MODULE,
+	.dai_link = &ha_dsp_card_dai,
+	.num_links = 1,
+};
+
+static int ha_dsp_card_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &snd_soc_ha_dsp_card;
+	struct device_node *node = pdev->dev.of_node;
+	struct device_node *dai_node;
+	struct ha_dsp_card *priv;
+	int ret;
+
+	card->dev = &pdev->dev;
+
+	if (!node) {
+		dev_err(&pdev->dev, "No DT node provided\n");
+		return -ENODEV;
+	}
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (priv == NULL)
+		return -ENOMEM;
+
+	ret = of_get_gpio(node, 0);
+	if (ret < 0) {
+		if (ret == -EPROBE_DEFER)
+			return ret;
+
+		/* No GPIO provided, don't enable GPIO sync */
+		priv->gpio = -1;
+		goto cont_no_gpio;
+	}
+
+	/* GPIO setup */
+	priv->gpio = ret;
+	ret = devm_gpio_request(&pdev->dev, priv->gpio,	"HA-DSP clock request");
+	if (ret) {
+		dev_err(&pdev->dev, "failed to request GPIO %u\n", priv->gpio);
+		return ret;
+	}
+
+	ret = gpio_direction_output(priv->gpio, 0);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to set pin direction\n");
+		return -EINVAL;
+	}
+	dev_info(&pdev->dev, "Using GPIO %d as sync clock\n", priv->gpio);
+
+cont_no_gpio:
+	priv->slave = of_property_read_bool(node, "ha_dsp_codec_slave");
+	if (priv->slave)
+		dev_info(&pdev->dev, "Using slave mode for testing!\n");
+
+	if (snd_soc_of_parse_card_name(card, "ti,model")) {
+		dev_err(&pdev->dev, "Card name is not provided\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	dai_node = of_parse_phandle(node, "ti,mcbsp", 0);
+	if (!dai_node) {
+		dev_err(&pdev->dev, "McBSP node is not provided\n");
+		ret = -EINVAL;
+		goto err;
+	}
+	ha_dsp_card_dai.cpu_dai_name  = NULL;
+	ha_dsp_card_dai.cpu_of_node = dai_node;
+
+	snd_soc_card_set_drvdata(card, priv);
+
+	ret = snd_soc_register_card(card);
+	if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+			ret);
+		goto err;
+	}
+
+	return 0;
+
+err:
+	return ret;
+}
+
+static int ha_dsp_card_remove(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+	snd_soc_unregister_card(card);
+
+	return 0;
+}
+
+static const struct of_device_id ha_dsp_card_of_match[] = {
+	{ .compatible = "ha,ha-dsp-card", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, ha_dsp_card_of_match);
+
+static struct platform_driver ha_dsp_card_driver = {
+	.driver = {
+		.name = "ha-dsp-card",
+		.owner = THIS_MODULE,
+		.pm = &snd_soc_pm_ops,
+		.of_match_table = ha_dsp_card_of_match,
+	},
+	.probe = ha_dsp_card_probe,
+	.remove = ha_dsp_card_remove,
+};
+
+module_platform_driver(ha_dsp_card_driver);
+
+MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
+MODULE_DESCRIPTION("ALSA SoC TAO3530-HA-DSP");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ha-dsp-card");
-- 
1.9.1


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

* [PATCH 4/5] DT: Add vendor prefix for HEAD acoustics
  2014-04-28 12:17 [PATCH 1/5] ASoC: Add support for machine specific trigger callback Stefan Roese
  2014-04-28 12:17 ` [PATCH 2/5] ASoC: Add HA (HEAD acoustics) DSP codec driver template Stefan Roese
  2014-04-28 12:17 ` [PATCH 3/5] ASoC: omap: Add HA (HEAD acoustics) DSP add-on card audio driver for TAO3530 Stefan Roese
@ 2014-04-28 12:17 ` Stefan Roese
  2014-04-28 12:17 ` [PATCH 5/5] ASoC: omap: Add DT bindings documentation for HA DSP audio driver Stefan Roese
  2014-04-29 19:05 ` [PATCH 1/5] ASoC: Add support for machine specific trigger callback Mark Brown
  4 siblings, 0 replies; 12+ messages in thread
From: Stefan Roese @ 2014-04-28 12:17 UTC (permalink / raw)
  To: alsa-devel, linux-omap; +Cc: broonie, Thorsten Eisbein

Add "ha" for "HEAD acoustics" to the list of DT vendor prefixes.

Signed-off-by: Stefan Roese <sr@denx.de>
Cc: Thorsten Eisbein <thorsten.eisbein@head-acoustics.de>
---
 Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index abc3080..0cdca38 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -53,6 +53,7 @@ globalscale	Globalscale Technologies, Inc.
 gmt	Global Mixed-mode Technology, Inc.
 google	Google, Inc.
 gumstix	Gumstix, Inc.
+ha	HEAD acoustics
 haoyu	Haoyu Microelectronic Co. Ltd.
 hisilicon	Hisilicon Limited.
 honeywell	Honeywell
-- 
1.9.1


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

* [PATCH 5/5] ASoC: omap: Add DT bindings documentation for HA DSP audio driver
  2014-04-28 12:17 [PATCH 1/5] ASoC: Add support for machine specific trigger callback Stefan Roese
                   ` (2 preceding siblings ...)
  2014-04-28 12:17 ` [PATCH 4/5] DT: Add vendor prefix for HEAD acoustics Stefan Roese
@ 2014-04-28 12:17 ` Stefan Roese
  2014-04-29 19:05 ` [PATCH 1/5] ASoC: Add support for machine specific trigger callback Mark Brown
  4 siblings, 0 replies; 12+ messages in thread
From: Stefan Roese @ 2014-04-28 12:17 UTC (permalink / raw)
  To: alsa-devel, linux-omap; +Cc: broonie, Thorsten Eisbein

Signed-off-by: Stefan Roese <sr@denx.de>
Cc: Thorsten Eisbein <thorsten.eisbein@head-acoustics.de>
---
 .../devicetree/bindings/sound/omap3-ha.txt         | 27 ++++++++++++++++++++++
 1 file changed, 27 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/omap3-ha.txt

diff --git a/Documentation/devicetree/bindings/sound/omap3-ha.txt b/Documentation/devicetree/bindings/sound/omap3-ha.txt
new file mode 100644
index 0000000..09eccda
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/omap3-ha.txt
@@ -0,0 +1,27 @@
+OMAP3 HA (HEAD acoustics) audio controller
+
+Required properties:
+- compatible: "ha,ha-dsp-card" for OMAP3-HA board (TAO3530 based)
+- ti,model: Name of the sound card (for example "omap3-ha")
+- ti,mcbsp: phandle for the McBSP node
+- ti,codec: phandle for the twl4030 audio node
+- gpios: GPIO used to sync the clock for playback and record
+
+Optional properties:
+- ha_dsp_codec_slave:
+  Add this property to test the codec in slave mode or without actual codec.
+  This makes it possible to test this driver by letting the OMAP be the DAI
+  link master.
+
+Example:
+sound2 {
+	compatible = "ha,ha-dsp-card";
+	ti,model = "omap3-ha";
+
+	/* McBSP3 is used for HA-DSP */
+	ti,mcbsp = <&mcbsp3>;
+	ti,codec = <&soc_audio>;
+
+	/* GPIO to sync the clock for playback and record */
+	gpios = <&gpio2 12 GPIO_ACTIVE_LOW>;	/* GPIO 44 */
+};
-- 
1.9.1


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

* Re: [alsa-devel] [PATCH 2/5] ASoC: Add HA (HEAD acoustics) DSP codec driver template
  2014-04-28 12:17 ` [PATCH 2/5] ASoC: Add HA (HEAD acoustics) DSP codec driver template Stefan Roese
@ 2014-04-28 14:45   ` Lars-Peter Clausen
  2014-04-28 17:32   ` Jarkko Nikula
  2014-04-29 18:47   ` Mark Brown
  2 siblings, 0 replies; 12+ messages in thread
From: Lars-Peter Clausen @ 2014-04-28 14:45 UTC (permalink / raw)
  To: Stefan Roese
  Cc: alsa-devel, linux-omap, broonie, Thorsten Eisbein, Jarkko Nikula

On 04/28/2014 02:17 PM, Stefan Roese wrote:
> From: Jarkko Nikula <jarkko.nikula@bitmer.com>
>
> This codec driver template represents an I2C controlled multichannel audio
> codec that has many typical ASoC codec driver features like volume controls,
> mixer stages, mux selection, output power control, in-codec audio routings,
> codec bias management and DAI link configuration.
>
> Updates from Stefan Roese, 2014-04-28:
> Port the HA DSP codec driver to Linux v3.15-rc. This includes
> support for DT based probing. No platform-data code is needed
> any more, DT nodes are sufficient.
>
> Signed-off-by: Jarkko Nikula <jarkko.nikula@bitmer.com>
> Signed-off-by: Stefan Roese <sr@denx.de>
> Cc: Thorsten Eisbein <thorsten.eisbein@head-acoustics.de>

Looks very good. Couple of bits inline.

[...]
> +
> +#include <linux/module.h>
> +#include <linux/moduleparam.h>
> +#include <linux/init.h>
> +#include <linux/delay.h>
> +#include <linux/pm.h>
> +#include <linux/i2c.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/slab.h>
> +#include <sound/core.h>
> +#include <sound/pcm.h>
> +#include <sound/pcm_params.h>
> +#include <sound/soc.h>
> +#include <sound/soc-dapm.h>
> +#include <sound/tlv.h>
> +#include <sound/initval.h>

There seem to be a couple of includes here that are not really needed.

> +
> +#include "ha-dsp.h"
[...]
> +static const char *ha_dsp_mode_texts[] = {"Mode 1", "Mode 2"};

const char *const

> +static SOC_ENUM_SINGLE_DECL(ha_dsp_mode_enum, HA_DSP_CTRL, 0,
> +			    ha_dsp_mode_texts);
> +
> +/* Monitor output mux selection */
> +static const char *ha_dsp_monitor_texts[] = {"Off", "ADC", "DAC"};

const char *const

> +static SOC_ENUM_SINGLE_DECL(ha_dsp_monitor_enum, HA_DSP_CTRL, 1,
> +			    ha_dsp_monitor_texts);
> +
[...]
> +static const struct snd_soc_dapm_widget ha_dsp_widgets[] = {
> +	SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
> +	SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
> +
> +	SND_SOC_DAPM_MIXER("OUT1 Mixer", SND_SOC_NOPM, 0, 0,
> +			   &ha_dsp_out1_mixer_controls[0],
> +			   ARRAY_SIZE(ha_dsp_out1_mixer_controls)),

There is the SOC_MIXER_ARRAY() helper macro that you can use here and below.

> +	SND_SOC_DAPM_MIXER("OUT2 Mixer", SND_SOC_NOPM, 0, 0,
> +			   &ha_dsp_out2_mixer_controls[0],
> +			   ARRAY_SIZE(ha_dsp_out2_mixer_controls)),
> +	SND_SOC_DAPM_MIXER("OUT3 Mixer", SND_SOC_NOPM, 0, 0,
> +			   &ha_dsp_out3_mixer_controls[0],
> +			   ARRAY_SIZE(ha_dsp_out3_mixer_controls)),
> +	SND_SOC_DAPM_MIXER("OUT4 Mixer", SND_SOC_NOPM, 0, 0,
> +			   &ha_dsp_out4_mixer_controls[0],
> +			   ARRAY_SIZE(ha_dsp_out4_mixer_controls)),
> +	SND_SOC_DAPM_MIXER("OUT5 Mixer", SND_SOC_NOPM, 0, 0,
> +			   &ha_dsp_out5_mixer_controls[0],
> +			   ARRAY_SIZE(ha_dsp_out5_mixer_controls)),
> +	SND_SOC_DAPM_MIXER("OUT6 Mixer", SND_SOC_NOPM, 0, 0,
> +			   &ha_dsp_out6_mixer_controls[0],
> +			   ARRAY_SIZE(ha_dsp_out6_mixer_controls)),
> +	SND_SOC_DAPM_MIXER("OUT7 Mixer", SND_SOC_NOPM, 0, 0,
> +			   &ha_dsp_out7_mixer_controls[0],
> +			   ARRAY_SIZE(ha_dsp_out7_mixer_controls)),
> +	SND_SOC_DAPM_MIXER("OUT8 Mixer", SND_SOC_NOPM, 0, 0,
> +			   &ha_dsp_out8_mixer_controls[0],
> +			   ARRAY_SIZE(ha_dsp_out8_mixer_controls)),
[...]
> +static int ha_dsp_hw_params(struct snd_pcm_substream *substream,
> +			    struct snd_pcm_hw_params *params,
> +			    struct snd_soc_dai *dai)
> +{
> +	struct snd_soc_pcm_runtime *rtd = substream->private_data;
> +	struct snd_soc_codec *codec = rtd->codec;

A codec should never look at the pcm_runtime. The proper way to get a 
pointer to the codec in dai callbacks is dai->codec. Or just use dai->dev below.

> +
> +	dev_dbg(codec->dev, "Sample format 0x%X\n", params_format(params));
> +	dev_dbg(codec->dev, "Channels %d\n", params_channels(params));
> +	dev_dbg(codec->dev, "Rate %d\n", params_rate(params));
> +
> +	return 0;
> +}
[...]
> +static int ha_dsp_set_bias_level(struct snd_soc_codec *codec,
> +				 enum snd_soc_bias_level level)
> +{
> +	dev_dbg(codec->dev, "Changing bias from %d to %d\n",
> +		codec->dapm.bias_level, level);
> +
> +	switch (level) {
> +	case SND_SOC_BIAS_ON:
> +		break;
> +	case SND_SOC_BIAS_PREPARE:
> +		/* Set PLL on */
> +		break;
> +	case SND_SOC_BIAS_STANDBY:
> +		/* Set power on, Set PLL off */
> +		break;
> +	case SND_SOC_BIAS_OFF:
> +		/* Set power down */
> +		break;
> +	}
> +	codec->dapm.bias_level = level;

If you don't do anything in set_bias_level, just don't implement the 
function. The default implementation if no callback is specified is to set 
the bias_level to the requested level.

> +
> +	return 0;
> +}
> +
> +static struct snd_soc_dai_ops ha_dsp_dai_ops = {

const

> +	.hw_params	= ha_dsp_hw_params,
> +	.set_fmt	= ha_dsp_set_dai_fmt,
> +};
> +
> +static struct snd_soc_dai_driver ha_dsp_dai = {
> +	.name = "ha-dsp-hifi",
> +	.playback = {
> +		.stream_name = "Playback",
> +		.channels_min = 2,
> +		.channels_max = 16,
> +		.rates = SNDRV_PCM_RATE_8000_96000,
> +		/* We use only 32 Bits for Audio */
> +		.formats = SNDRV_PCM_FMTBIT_S32_LE,
> +	},
> +	.capture = {
> +		.stream_name = "Capture",
> +		.channels_min = 2,
> +		.channels_max = 16,
> +		.rates = SNDRV_PCM_RATE_8000_96000,
> +		/* We use only 32 Bits for Audio */
> +		.formats = SNDRV_PCM_FMTBIT_S32_LE,
> +	},
> +	.ops = &ha_dsp_dai_ops,
> +};
> +
> +static int ha_dsp_probe(struct snd_soc_codec *codec)
> +{
> +	int ret;
> +
> +	codec->control_data = dev_get_regmap(codec->dev->parent, NULL);

Why do you want to use the regmap instance of the parent? That doesn't make 
sense given that you initialized a remgap instance for the device itself.

> +	ret = snd_soc_codec_set_cache_io(codec, codec->control_data);
> +	if (ret != 0) {
> +		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int ha_dsp_remove(struct snd_soc_codec *codec)
> +{
> +	snd_soc_write(codec, HA_DSP_CTRL, HA_DSP_SW_RESET);

To get the codec into a well know state it is best practice to also reset it 
when probing the device.

> +
> +	return 0;
> +}
> +
[...]
> +static int ha_dsp_i2c_probe(struct i2c_client *client,
> +			    const struct i2c_device_id *id)
> +{
> +	struct regmap *regmap;
> +	int ret;
> +
> +	regmap = devm_regmap_init_i2c(client, &ha_dsp_regmap);
> +	if (IS_ERR(regmap)) {
> +		ret = PTR_ERR(regmap);
> +		dev_err(&client->dev, "Failed to create regmap: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = snd_soc_register_codec(&client->dev, &soc_codec_dev_ha_dsp,
> +				     &ha_dsp_dai, 1);

Just return snd_soc_register_codec(...)

> +
> +	return ret;
> +}
[...]

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

* Re: [PATCH 2/5] ASoC: Add HA (HEAD acoustics) DSP codec driver template
  2014-04-28 12:17 ` [PATCH 2/5] ASoC: Add HA (HEAD acoustics) DSP codec driver template Stefan Roese
  2014-04-28 14:45   ` [alsa-devel] " Lars-Peter Clausen
@ 2014-04-28 17:32   ` Jarkko Nikula
  2014-04-29 18:47   ` Mark Brown
  2 siblings, 0 replies; 12+ messages in thread
From: Jarkko Nikula @ 2014-04-28 17:32 UTC (permalink / raw)
  To: Stefan Roese, alsa-devel, linux-omap; +Cc: broonie, Thorsten Eisbein

Hi Stefan

On 04/28/2014 03:17 PM, Stefan Roese wrote:
> From: Jarkko Nikula <jarkko.nikula@bitmer.com>
> 
> This codec driver template represents an I2C controlled multichannel audio
> codec that has many typical ASoC codec driver features like volume controls,
> mixer stages, mux selection, output power control, in-codec audio routings,
> codec bias management and DAI link configuration.
> 
I think it's fair to change authorship to you or Thorsten as this is now
more a real codec driver than implementation template I developed
originally a few years back and you have done porting to newer kernel
and API. Plus taking review commits too :-)

> Updates from Stefan Roese, 2014-04-28:
> Port the HA DSP codec driver to Linux v3.15-rc. This includes
> support for DT based probing. No platform-data code is needed
> any more, DT nodes are sufficient.
> 
> Signed-off-by: Jarkko Nikula <jarkko.nikula@bitmer.com>
> Signed-off-by: Stefan Roese <sr@denx.de>
> Cc: Thorsten Eisbein <thorsten.eisbein@head-acoustics.de>
> ---
To me it's fine if you write commit log like it was done by you and say
it's based on early implementation template from me. Or something like that.

> diff --git a/sound/soc/codecs/ha-dsp.c b/sound/soc/codecs/ha-dsp.c
> new file mode 100644
> index 0000000..7cf24dc
> --- /dev/null
> +++ b/sound/soc/codecs/ha-dsp.c
> @@ -0,0 +1,419 @@
> +/*
> + * ha-dsp.c  --  HA DSP ALSA SoC Audio driver
> + *
> + * Copyright 2011 Head acoustics GmbH
> + *
> + * Author: Jarkko Nikula <jarkko.nikula@bitmer.com>
> + *
List here also other authors in order to get kudos to you too.

-- 
Jarkko

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

* Re: [PATCH 3/5] ASoC: omap: Add HA (HEAD acoustics) DSP add-on card audio driver for TAO3530
  2014-04-28 12:17 ` [PATCH 3/5] ASoC: omap: Add HA (HEAD acoustics) DSP add-on card audio driver for TAO3530 Stefan Roese
@ 2014-04-28 17:35   ` Jarkko Nikula
  2014-04-28 17:39   ` Jarkko Nikula
  2014-04-29 18:54   ` Mark Brown
  2 siblings, 0 replies; 12+ messages in thread
From: Jarkko Nikula @ 2014-04-28 17:35 UTC (permalink / raw)
  To: Stefan Roese, alsa-devel, linux-omap; +Cc: broonie, Thorsten Eisbein

On 04/28/2014 03:17 PM, Stefan Roese wrote:
> From: Jarkko Nikula <jarkko.nikula@bitmer.com>
> 
Same authorship and commit log notes here than to 2/5. One important
comment below.

> --- /dev/null
> +++ b/sound/soc/omap/ha-dsp-card.c
> @@ -0,0 +1,307 @@
> +/*
> + * ha-dsp-card.c  --  SoC audio HA-DSP add-on card for TAO-3530
> + *
> + * Author: Jarkko Nikula <jarkko.nikula@bitmer.com>
> + *
> + * Additional changes by:
> + *   Thorsten Eisbein <thorsten.eisbein@head-acoustics.de>
> + *   Stefan Roese <sr@denx.de>

Put here Copyright 2011 Head acoustics GmbH.

-- 
Jarkko

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

* Re: [PATCH 3/5] ASoC: omap: Add HA (HEAD acoustics) DSP add-on card audio driver for TAO3530
  2014-04-28 12:17 ` [PATCH 3/5] ASoC: omap: Add HA (HEAD acoustics) DSP add-on card audio driver for TAO3530 Stefan Roese
  2014-04-28 17:35   ` Jarkko Nikula
@ 2014-04-28 17:39   ` Jarkko Nikula
  2014-04-29 18:54   ` Mark Brown
  2 siblings, 0 replies; 12+ messages in thread
From: Jarkko Nikula @ 2014-04-28 17:39 UTC (permalink / raw)
  To: Stefan Roese, alsa-devel, linux-omap; +Cc: broonie, Thorsten Eisbein

On 04/28/2014 03:17 PM, Stefan Roese wrote:
> From: Jarkko Nikula <jarkko.nikula@bitmer.com>
>
Same authorship and commit log notes here than to 2/5. One important
note below.

> --- /dev/null
> +++ b/sound/soc/omap/ha-dsp-card.c
> @@ -0,0 +1,307 @@
> +/*
> + * ha-dsp-card.c  --  SoC audio HA-DSP add-on card for TAO-3530
> + *
> + * Author: Jarkko Nikula <jarkko.nikula@bitmer.com>
> + *
> + * Additional changes by:
> + *   Thorsten Eisbein <thorsten.eisbein@head-acoustics.de>
> + *   Stefan Roese <sr@denx.de>
> + *
Put here Copyright 2011 Head acoustics GmbH.

-- 
Jarkko

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

* Re: [PATCH 2/5] ASoC: Add HA (HEAD acoustics) DSP codec driver template
  2014-04-28 12:17 ` [PATCH 2/5] ASoC: Add HA (HEAD acoustics) DSP codec driver template Stefan Roese
  2014-04-28 14:45   ` [alsa-devel] " Lars-Peter Clausen
  2014-04-28 17:32   ` Jarkko Nikula
@ 2014-04-29 18:47   ` Mark Brown
  2 siblings, 0 replies; 12+ messages in thread
From: Mark Brown @ 2014-04-29 18:47 UTC (permalink / raw)
  To: Stefan Roese; +Cc: alsa-devel, linux-omap, Thorsten Eisbein, Jarkko Nikula


[-- Attachment #1.1: Type: text/plain, Size: 1376 bytes --]

On Mon, Apr 28, 2014 at 02:17:53PM +0200, Stefan Roese wrote:

> +static int ha_dsp_hw_params(struct snd_pcm_substream *substream,
> +			    struct snd_pcm_hw_params *params,
> +			    struct snd_soc_dai *dai)
> +{
> +	struct snd_soc_pcm_runtime *rtd = substream->private_data;
> +	struct snd_soc_codec *codec = rtd->codec;
> +
> +	dev_dbg(codec->dev, "Sample format 0x%X\n", params_format(params));
> +	dev_dbg(codec->dev, "Channels %d\n", params_channels(params));
> +	dev_dbg(codec->dev, "Rate %d\n", params_rate(params));
> +
> +	return 0;
> +}

This doesn't do anything, you should either implement active code here
or remove it (I note that a range of sample rates are supported and the
CODEC can be clock master so I'd expect to see code here).

> +	/* codec role */
> +	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
> +	case SND_SOC_DAIFMT_CBM_CFM:
> +		dev_dbg(codec->dev, "Codec is master\n");
> +		break;
> +	case SND_SOC_DAIFMT_CBS_CFS:
> +		dev_dbg(codec->dev, "Codec is slave\n");
> +		break;
> +	default:
> +		return -EINVAL;
> +	}

This isn't doing anything with what it parsed, how does that work?

> +/*
> + * This name/ID is neded to match the DT node for the codec
> + */
> +static const struct i2c_device_id ha_dsp_i2c_id[] = {
> +	{ "ha-dsp-audio", 0 },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(i2c, ha_dsp_i2c_id);

This doesn't have any actual part numbers?

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



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

* Re: [PATCH 3/5] ASoC: omap: Add HA (HEAD acoustics) DSP add-on card audio driver for TAO3530
  2014-04-28 12:17 ` [PATCH 3/5] ASoC: omap: Add HA (HEAD acoustics) DSP add-on card audio driver for TAO3530 Stefan Roese
  2014-04-28 17:35   ` Jarkko Nikula
  2014-04-28 17:39   ` Jarkko Nikula
@ 2014-04-29 18:54   ` Mark Brown
  2 siblings, 0 replies; 12+ messages in thread
From: Mark Brown @ 2014-04-29 18:54 UTC (permalink / raw)
  To: Stefan Roese; +Cc: alsa-devel, linux-omap, Thorsten Eisbein, Jarkko Nikula


[-- Attachment #1.1: Type: text/plain, Size: 1893 bytes --]

On Mon, Apr 28, 2014 at 02:17:54PM +0200, Stefan Roese wrote:

> +	switch (params_channels(params)) {
> +	case 2:
> +	case 4:
> +	case 8:
> +	case 16:
> +		fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}

Why is this "conditional" on the number of channels (though the same
value is always chosen)?

> +		/*
> +		 * Calculate McBSP SRG divisor in McBSP master mode
> +		 */
> +		div = 96000000 / params_rate(params) / params_channels(params);
> +		switch (params_format(params)) {
> +		case SNDRV_PCM_FORMAT_S16_LE:
> +			div /= 16;
> +			break;
> +		case SNDRV_PCM_FORMAT_S24_LE:
> +		case SNDRV_PCM_FORMAT_S32_LE:
> +			div /= 32;
> +			break;
> +		};

params_width().

> +		ret = snd_soc_dai_set_clkdiv(cpu_dai, OMAP_MCBSP_CLKGDV, div);
> +		if (ret < 0) {
> +			pr_err("can't set SRG clock divider\n");
> +			return ret;
> +		}

Why not put this code into the DAI driver for the SoC - what's board
specific about the calcuation?  I'd expect this to be handlable by
set_sysclk().

> +	if (!node) {
> +		dev_err(&pdev->dev, "No DT node provided\n");
> +		return -ENODEV;
> +	}

You've got something with a DT binding here but no binding document,
documentation is mandatory for new DT bindings.

> +	priv->slave = of_property_read_bool(node, "ha_dsp_codec_slave");
> +	if (priv->slave)
> +		dev_info(&pdev->dev, "Using slave mode for testing!\n");

This seems like something that shouldn't be in production code, or
perhaps a build time option if the testing is valuable?

> +	if (snd_soc_of_parse_card_name(card, "ti,model")) {
> +		dev_err(&pdev->dev, "Card name is not provided\n");
> +		ret = -ENODEV;
> +		goto err;
> +	}

Why not have a default?

> +	ret = snd_soc_register_card(card);
> +	if (ret) {
> +		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
> +			ret);
> +		goto err;
> +	}

devm_snd_soc_register_card().

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



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

* Re: [PATCH 1/5] ASoC: Add support for machine specific trigger callback
  2014-04-28 12:17 [PATCH 1/5] ASoC: Add support for machine specific trigger callback Stefan Roese
                   ` (3 preceding siblings ...)
  2014-04-28 12:17 ` [PATCH 5/5] ASoC: omap: Add DT bindings documentation for HA DSP audio driver Stefan Roese
@ 2014-04-29 19:05 ` Mark Brown
  4 siblings, 0 replies; 12+ messages in thread
From: Mark Brown @ 2014-04-29 19:05 UTC (permalink / raw)
  To: Stefan Roese; +Cc: alsa-devel, linux-omap, Jarkko Nikula

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

On Mon, Apr 28, 2014 at 02:17:52PM +0200, Stefan Roese wrote:
> From: Jarkko Nikula <jarkko.nikula@bitmer.com>
> 
> Machine specific trigger callback allows to do final stream start/stop
> related operations in a machine driver after setting up the codec, DMA and
> DAI.

Applied, thanks.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

end of thread, other threads:[~2014-04-29 22:19 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-04-28 12:17 [PATCH 1/5] ASoC: Add support for machine specific trigger callback Stefan Roese
2014-04-28 12:17 ` [PATCH 2/5] ASoC: Add HA (HEAD acoustics) DSP codec driver template Stefan Roese
2014-04-28 14:45   ` [alsa-devel] " Lars-Peter Clausen
2014-04-28 17:32   ` Jarkko Nikula
2014-04-29 18:47   ` Mark Brown
2014-04-28 12:17 ` [PATCH 3/5] ASoC: omap: Add HA (HEAD acoustics) DSP add-on card audio driver for TAO3530 Stefan Roese
2014-04-28 17:35   ` Jarkko Nikula
2014-04-28 17:39   ` Jarkko Nikula
2014-04-29 18:54   ` Mark Brown
2014-04-28 12:17 ` [PATCH 4/5] DT: Add vendor prefix for HEAD acoustics Stefan Roese
2014-04-28 12:17 ` [PATCH 5/5] ASoC: omap: Add DT bindings documentation for HA DSP audio driver Stefan Roese
2014-04-29 19:05 ` [PATCH 1/5] ASoC: Add support for machine specific trigger callback Mark Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).