All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 00/11] ASoC: hdac: Add hdac generic driver
@ 2016-06-27  3:47 Subhransu S. Prusty
  2016-06-27  3:47 ` [RFC 01/11] ALSA: hdac: Add codec helper library Subhransu S. Prusty
                   ` (11 more replies)
  0 siblings, 12 replies; 30+ messages in thread
From: Subhransu S. Prusty @ 2016-06-27  3:47 UTC (permalink / raw)
  To: alsa-devel; +Cc: tiwai, patches.audio, broonie, Subhransu S. Prusty, lgirdwood

HDA devices generically can be modelled with DAPM in ASoC. This
series adds a framework in ASoC to model HDA devices. HDA widgets
are enumerated and one or multiple DAPM widget(s) are created.
Connection list is queried for each widget to identify the
connection between two endpoints and modelled using DAPM graph.

Set of event handlers are defined for each widget type. Based on
DAPM events required verbs are sent to program codec.

Finally a function is exported to query for the device endpoint
configuration to create machine controls.

Hardik T Shah (1):
  ASoC: Add dai_ops to set the stream tag.

Subhransu S. Prusty (10):
  ALSA: hdac: Add codec helper library
  ALSA: hda - Add macro to test pin widget's input capability
  ASoC: hdac: Add a generic hdac driver framework
  ASoC: hdac: Create DAPM model for HDA widgets
  ASoC: dapm: Create API to add a single route element
  ASoC: hdac: Build DAPM graph by querying through widget connection
    list
  ASoC: hdac: Register widget event handlers
  ALSA: hda - macro to get default config device of pin widgets
  ASoC: dapm: Export snd_soc_dapm_new_control
  ASoC: hdac: Export API to create machine controls

 include/sound/hdaudio.h         |    1 +
 include/sound/soc-dai.h         |   12 +
 include/sound/soc-dapm.h        |    5 +
 sound/hda/ext/Makefile          |    3 +-
 sound/hda/ext/hdac_codec.c      |  188 +++++
 sound/hda/ext/hdac_codec.h      |   52 ++
 sound/hda/local.h               |   13 +
 sound/soc/codecs/Kconfig        |    5 +
 sound/soc/codecs/Makefile       |    2 +
 sound/soc/codecs/hdac_generic.c | 1561 +++++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/hdac_generic.h |   31 +
 sound/soc/soc-core.c            |   35 +
 sound/soc/soc-dapm.c            |   22 +
 13 files changed, 1929 insertions(+), 1 deletion(-)
 create mode 100644 sound/hda/ext/hdac_codec.c
 create mode 100644 sound/hda/ext/hdac_codec.h
 create mode 100644 sound/soc/codecs/hdac_generic.c
 create mode 100644 sound/soc/codecs/hdac_generic.h

-- 
1.9.1

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

* [RFC 01/11] ALSA: hdac: Add codec helper library
  2016-06-27  3:47 [RFC 00/11] ASoC: hdac: Add hdac generic driver Subhransu S. Prusty
@ 2016-06-27  3:47 ` Subhransu S. Prusty
  2016-06-27  3:47 ` [RFC 02/11] ASoC: Add dai_ops to set the stream tag Subhransu S. Prusty
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 30+ messages in thread
From: Subhransu S. Prusty @ 2016-06-27  3:47 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, lgirdwood, patches.audio, broonie, Vinod Koul,
	Subhransu S. Prusty

Add hdac helpers to enumerate the HDA widgets and fill connection
lists for each.

Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
---
 include/sound/hdaudio.h    |   1 +
 sound/hda/ext/Makefile     |   3 +-
 sound/hda/ext/hdac_codec.c | 188 +++++++++++++++++++++++++++++++++++++++++++++
 sound/hda/ext/hdac_codec.h |  52 +++++++++++++
 4 files changed, 243 insertions(+), 1 deletion(-)
 create mode 100644 sound/hda/ext/hdac_codec.c
 create mode 100644 sound/hda/ext/hdac_codec.h

diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h
index 93e63c5..79502dc 100644
--- a/include/sound/hdaudio.h
+++ b/include/sound/hdaudio.h
@@ -71,6 +71,7 @@ struct hdac_device {
 			 unsigned int flags, unsigned int *res);
 
 	/* widgets */
+	struct list_head widget_list;
 	unsigned int num_nodes;
 	hda_nid_t start_nid, end_nid;
 
diff --git a/sound/hda/ext/Makefile b/sound/hda/ext/Makefile
index 9b6f641..d3c51e0 100644
--- a/sound/hda/ext/Makefile
+++ b/sound/hda/ext/Makefile
@@ -1,3 +1,4 @@
-snd-hda-ext-core-objs := hdac_ext_bus.o hdac_ext_controller.o hdac_ext_stream.o
+snd-hda-ext-core-objs := hdac_ext_bus.o hdac_ext_controller.o hdac_ext_stream.o	\
+			hdac_codec.o
 
 obj-$(CONFIG_SND_HDA_EXT_CORE) += snd-hda-ext-core.o
diff --git a/sound/hda/ext/hdac_codec.c b/sound/hda/ext/hdac_codec.c
new file mode 100644
index 0000000..93e49a3
--- /dev/null
+++ b/sound/hda/ext/hdac_codec.c
@@ -0,0 +1,188 @@
+/*
+ *  hdac_codec.c - HDA codec library
+ *
+ *  Copyright (C) 2016-2017 Intel Corp
+ *  Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <sound/soc.h>
+#include <sound/hdaudio_ext.h>
+#include "../../hda/local.h"
+#include "hdac_codec.h"
+#include <sound/hda_verbs.h>
+
+static int hdac_generic_query_connlist(struct hdac_device *hdac,
+				struct hdac_codec_widget *wid)
+{
+	hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
+	unsigned int caps;
+	int i;
+
+	if (!(get_wcaps(hdac, wid->nid) & AC_WCAP_CONN_LIST)) {
+		dev_info(&hdac->dev,
+			"HDAC ASoC: wid %d wcaps %#x doesn't support connection list\n",
+			wid->nid, get_wcaps(hdac, wid->nid));
+
+		return 0;
+	}
+
+	wid->num_inputs = snd_hdac_get_connections(hdac, wid->nid,
+					mux_nids, HDA_MAX_CONNECTIONS);
+
+	if (wid->num_inputs == 0) {
+		dev_info(&hdac->dev, "No connections found for wid: %d\n",
+							wid->nid);
+		return 0;
+	}
+
+	for (i = 0; i < wid->num_inputs; i++) {
+		wid->conn_list[i].nid = mux_nids[i];
+		caps = get_wcaps(hdac, mux_nids[i]);
+		wid->conn_list[i].type = get_wcaps_type(caps);
+	}
+
+	dev_dbg(&hdac->dev, "num_inputs %d for wid: %d\n",
+			wid->num_inputs, wid->nid);
+
+	return wid->num_inputs;
+}
+
+static int hdac_codec_add_widget(struct hdac_device *codec, hda_nid_t nid,
+				unsigned int type, unsigned int caps)
+{
+	struct hdac_codec_widget *widget;
+	unsigned int *cfg;
+	int ret;
+
+	widget = kzalloc(sizeof(*widget), GFP_KERNEL);
+	if (!widget)
+		return -ENOMEM;
+
+	widget->nid = nid;
+	widget->type = type;
+	widget->caps = caps;
+	list_add_tail(&widget->head, &codec->widget_list);
+
+	switch (type) {
+	case AC_WID_PIN:
+		cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
+
+		*cfg = snd_hdac_codec_read(codec, nid, 0,
+					AC_VERB_GET_CONFIG_DEFAULT, 0);
+		widget->params = cfg;
+		break;
+
+	default:
+		break;
+	}
+
+	ret = hdac_generic_query_connlist(codec, widget);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+/**
+ * snd_hdac_parse_widgets - Iterates over the hda codec, enumerates the
+ *			    widgets and its connections.
+ * @hdac: pointer to HDAC devcie
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_hdac_parse_widgets(struct hdac_device *hdac)
+{
+	hda_nid_t nid;
+	int num_nodes, i;
+	struct hdac_codec_widget *wid;
+	struct hdac_codec_widget *tmp;
+	int ret = 0;
+
+	num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid);
+	if (!nid || num_nodes <= 0) {
+		dev_err(&hdac->dev, "HDAC ASoC: failed to get afg sub nodes\n");
+		return -EINVAL;
+	}
+	hdac->num_nodes = num_nodes;
+	hdac->start_nid = nid;
+
+	for (i = 0; i < hdac->num_nodes; i++, nid++) {
+		unsigned int caps;
+		unsigned int type;
+
+		caps = get_wcaps(hdac, nid);
+		type = get_wcaps_type(caps);
+
+		ret = hdac_codec_add_widget(hdac, nid, type, caps);
+		if (ret < 0)
+			goto fail_add_widget;
+
+	}
+
+	hdac->end_nid = nid;
+
+	/* Cache input connection to a widget */
+	list_for_each_entry(wid, &hdac->widget_list, head) {
+		if (!wid->num_inputs)
+			continue;
+
+		for (i = 0; i < wid->num_inputs; i++) {
+			list_for_each_entry(tmp, &hdac->widget_list, head) {
+				if (wid->conn_list[i].nid == tmp->nid) {
+					wid->conn_list[i].input_w = tmp;
+					break;
+				}
+			}
+		}
+	}
+
+fail_add_widget:
+	snd_hdac_codec_cleanup(hdac);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_parse_widgets);
+
+/**
+ * snd_hdac_codec_init - Initialize some more hdac device elements
+ * @hdac: pointer to hdac device
+ *
+ * Returns 0 if successful.
+ */
+int snd_hdac_codec_init(struct hdac_device *hdac)
+{
+	INIT_LIST_HEAD(&hdac->widget_list);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_codec_init);
+
+/**
+ * snd_hdac_codec_cleanup - Cleanup resources allocated during device
+ * initialization.
+ * @hdac: pointer to hdac device
+ */
+void snd_hdac_codec_cleanup(struct hdac_device *hdac)
+{
+	struct hdac_codec_widget *wid, *tmp;
+
+	list_for_each_entry_safe(wid, tmp, &hdac->widget_list, head) {
+		kfree(wid->params);
+		list_del(&wid->head);
+		kfree(wid);
+	}
+}
+EXPORT_SYMBOL_GPL(snd_hdac_codec_cleanup);
diff --git a/sound/hda/ext/hdac_codec.h b/sound/hda/ext/hdac_codec.h
new file mode 100644
index 0000000..cc9db65
--- /dev/null
+++ b/sound/hda/ext/hdac_codec.h
@@ -0,0 +1,52 @@
+/*
+ *  hdac_codec.h - HDA codec library
+ *
+ *  Copyright (C) 2016-2017 Intel Corp
+ *  Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#ifndef __HDAC_CODEC_H__
+#define __HDAC_CODEC_H__
+
+#define HDA_MAX_CONNECTIONS 32
+/* amp values */
+#define AMP_IN_MUTE(idx)	(0x7080 | ((idx)<<8))
+#define AMP_IN_UNMUTE(idx)	(0x7000 | ((idx)<<8))
+#define AMP_OUT_MUTE		0xb080
+#define AMP_OUT_UNMUTE		0xb000
+
+struct hdac_codec_widget;
+struct hdac_codec_connection_list {
+	hda_nid_t nid;
+	unsigned int type;
+	struct hdac_codec_widget *input_w;
+};
+
+struct hdac_codec_widget {
+	struct list_head head;
+	hda_nid_t nid;
+	unsigned int caps;
+	unsigned int type;
+	int num_inputs;
+	struct hdac_codec_connection_list conn_list[HDA_MAX_CONNECTIONS];
+	void *priv;	/* Codec specific widget data */
+	void *params;	/* Widget specific parameters */
+};
+
+int snd_hdac_parse_widgets(struct hdac_device *hdac);
+int snd_hdac_codec_init(struct hdac_device *hdac);
+void snd_hdac_codec_cleanup(struct hdac_device *hdac);
+
+#endif /* __HDAC_CODEC_H__ */
-- 
1.9.1

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

* [RFC 02/11] ASoC: Add dai_ops to set the stream tag.
  2016-06-27  3:47 [RFC 00/11] ASoC: hdac: Add hdac generic driver Subhransu S. Prusty
  2016-06-27  3:47 ` [RFC 01/11] ALSA: hdac: Add codec helper library Subhransu S. Prusty
@ 2016-06-27  3:47 ` Subhransu S. Prusty
  2016-06-27 17:30   ` Mark Brown
  2016-06-27  3:47 ` [RFC 03/11] ALSA: hda - Add macro to test pin widget's input capability Subhransu S. Prusty
                   ` (9 subsequent siblings)
  11 siblings, 1 reply; 30+ messages in thread
From: Subhransu S. Prusty @ 2016-06-27  3:47 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, Hardik T Shah, lgirdwood, patches.audio, broonie,
	Vinod Koul, Subhransu S. Prusty

From: Hardik T Shah <hardik.t.shah@intel.com>

Stream tag is unique stream identifier for each HDA stream. It's
programmed in both host and codec to identify link the stream is
transported.  The platform driver allocates the stream and calls
this ops to program the stream tag in the codec dai.

Signed-off-by: Hardik T Shah <hardik.t.shah@intel.com>
Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
---
 include/sound/soc-dai.h | 12 ++++++++++++
 sound/soc/soc-core.c    | 35 +++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+)

diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 964b7de..52e52b4 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -140,6 +140,11 @@ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute,
 
 int snd_soc_dai_is_dummy(struct snd_soc_dai *dai);
 
+
+/* Stream tag programming for codec and cpu dai */
+int snd_soc_dai_program_stream_tag(struct snd_soc_pcm_runtime *rtd,
+						int stream_tag);
+
 struct snd_soc_dai_ops {
 	/*
 	 * DAI clocking configuration, all optional.
@@ -175,6 +180,13 @@ struct snd_soc_dai_ops {
 	int (*mute_stream)(struct snd_soc_dai *dai, int mute, int stream);
 
 	/*
+	 * stream_tag - optional
+	 * Can be used by to program same stream tag for both cpu dai
+	 * and codec dai.
+	 */
+	int (*program_stream_tag)(struct snd_soc_dai *, int);
+
+	/*
 	 * ALSA PCM audio operations - all optional.
 	 * Called by soc-core during audio PCM operations.
 	 */
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index d2e62b15..b096a2f 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -2528,6 +2528,41 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
 EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
 
 /**
+ * snd_soc_dai_program_stream_tag - used to program same stream tag for both
+ *				cpu dai and codec dai.
+ * @rtd: The runtime for which the DAI link format should be changed
+ * @stream_tag: Stream tag to be programmed.
+ *
+ * Returns 0 on success, otherwise a negative error code.
+ */
+int snd_soc_dai_program_stream_tag(struct snd_soc_pcm_runtime *rtd,
+						int stream_tag)
+{
+	int i;
+	const struct snd_soc_dai_ops *codec_dai_ops;
+	struct snd_soc_dai *codec_dai;
+	int ret = 0;
+
+	for (i = 0; i < rtd->num_codecs; i++) {
+		codec_dai = rtd->codec_dais[i];
+		if (!codec_dai->driver)
+			continue;
+
+		codec_dai_ops = codec_dai->driver->ops;
+		if (codec_dai_ops->program_stream_tag) {
+			ret = codec_dai_ops->program_stream_tag(
+					codec_dai, stream_tag);
+			if (ret)
+				return ret;
+		}
+	}
+
+	return ret;
+
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_program_stream_tag);
+
+/**
  * snd_soc_dai_set_channel_map - configure DAI audio channel map
  * @dai: DAI
  * @tx_num: how many TX channels
-- 
1.9.1

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

* [RFC 03/11] ALSA: hda - Add macro to test pin widget's input capability
  2016-06-27  3:47 [RFC 00/11] ASoC: hdac: Add hdac generic driver Subhransu S. Prusty
  2016-06-27  3:47 ` [RFC 01/11] ALSA: hdac: Add codec helper library Subhransu S. Prusty
  2016-06-27  3:47 ` [RFC 02/11] ASoC: Add dai_ops to set the stream tag Subhransu S. Prusty
@ 2016-06-27  3:47 ` Subhransu S. Prusty
  2016-06-27  3:47 ` [RFC 04/11] ASoC: hdac: Add a generic hdac driver framework Subhransu S. Prusty
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 30+ messages in thread
From: Subhransu S. Prusty @ 2016-06-27  3:47 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, lgirdwood, patches.audio, broonie, Vinod Koul,
	Subhransu S. Prusty

Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
---
 sound/hda/local.h | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/sound/hda/local.h b/sound/hda/local.h
index 0d5bb15..a51f5f6 100644
--- a/sound/hda/local.h
+++ b/sound/hda/local.h
@@ -8,6 +8,16 @@
 #define get_wcaps(codec, nid) \
 	snd_hdac_read_parm(codec, nid, AC_PAR_AUDIO_WIDGET_CAP)
 
+#define get_pcaps(codec, nid) \
+	snd_hdac_read_parm(codec, nid, AC_PAR_PIN_CAP)
+
+static inline int is_input_pin(struct hdac_device *codec, hda_nid_t nid)
+{
+	unsigned int pincap = get_pcaps(codec, nid);
+
+	return (pincap & AC_PINCAP_IN) != 0;
+}
+
 /* get the widget type from widget capability bits */
 static inline int get_wcaps_type(unsigned int wcaps)
 {
-- 
1.9.1

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

* [RFC 04/11] ASoC: hdac: Add a generic hdac driver framework
  2016-06-27  3:47 [RFC 00/11] ASoC: hdac: Add hdac generic driver Subhransu S. Prusty
                   ` (2 preceding siblings ...)
  2016-06-27  3:47 ` [RFC 03/11] ALSA: hda - Add macro to test pin widget's input capability Subhransu S. Prusty
@ 2016-06-27  3:47 ` Subhransu S. Prusty
  2016-06-27  3:47 ` [RFC 05/11] ASoC: hdac: Create DAPM model for HDA widgets Subhransu S. Prusty
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 30+ messages in thread
From: Subhransu S. Prusty @ 2016-06-27  3:47 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, lgirdwood, patches.audio, broonie, Vinod Koul,
	Subhransu S. Prusty

This patch adds support to register the hdac driver with the HDA
bus and enumerate the driver if a device is found.

It uses the hdac core helper APIs to parse the HDA widgets and
identifies the number of mapping dapm widgets to be created.
Based on the ADCs and DACs queries the codec dais are allocated
and registers with asoc.

The AFG node is power managed through set_bias_level callback and
hw_params, program_stream_tag callback support are added in the
dai_ops to program the stream parameters.

Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
---
 sound/soc/codecs/Kconfig        |   5 +
 sound/soc/codecs/Makefile       |   2 +
 sound/soc/codecs/hdac_generic.c | 412 ++++++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/hdac_generic.h |  25 +++
 4 files changed, 444 insertions(+)
 create mode 100644 sound/soc/codecs/hdac_generic.c
 create mode 100644 sound/soc/codecs/hdac_generic.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 907c804..101eb3f 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -68,6 +68,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_ES8328_SPI if SPI_MASTER
 	select SND_SOC_ES8328_I2C if I2C
 	select SND_SOC_GTM601
+	select SND_SOC_HDAC_GENERIC
 	select SND_SOC_HDAC_HDMI
 	select SND_SOC_ICS43432
 	select SND_SOC_INNO_RK3036
@@ -491,6 +492,10 @@ config SND_SOC_ES8328_SPI
 config SND_SOC_GTM601
 	tristate 'GTM601 UMTS modem audio codec'
 
+config SND_SOC_HDAC_GENERIC
+	tristate
+	select SND_HDA_EXT_CORE
+
 config SND_SOC_HDAC_HDMI
 	tristate
 	select SND_HDA_EXT_CORE
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 185a712..547e8c2 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -61,6 +61,7 @@ snd-soc-es8328-objs := es8328.o
 snd-soc-es8328-i2c-objs := es8328-i2c.o
 snd-soc-es8328-spi-objs := es8328-spi.o
 snd-soc-gtm601-objs := gtm601.o
+snd-soc-hdac-generic-objs := hdac_generic.o
 snd-soc-hdac-hdmi-objs := hdac_hdmi.o
 snd-soc-ics43432-objs := ics43432.o
 snd-soc-inno-rk3036-objs := inno_rk3036.o
@@ -270,6 +271,7 @@ obj-$(CONFIG_SND_SOC_ES8328)	+= snd-soc-es8328.o
 obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o
 obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o
 obj-$(CONFIG_SND_SOC_GTM601)    += snd-soc-gtm601.o
+obj-$(CONFIG_SND_SOC_HDAC_GENERIC) += snd-soc-hdac-generic.o
 obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o
 obj-$(CONFIG_SND_SOC_ICS43432)	+= snd-soc-ics43432.o
 obj-$(CONFIG_SND_SOC_INNO_RK3036)	+= snd-soc-inno-rk3036.o
diff --git a/sound/soc/codecs/hdac_generic.c b/sound/soc/codecs/hdac_generic.c
new file mode 100644
index 0000000..79db501
--- /dev/null
+++ b/sound/soc/codecs/hdac_generic.c
@@ -0,0 +1,412 @@
+/*
+ *  hdac_generic.c - ASoc HDA generic codec driver
+ *
+ *  Copyright (C) 2016-2017 Intel Corp
+ *  Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#include <sound/hdaudio_ext.h>
+#include <sound/hda_regmap.h>
+#include "../../hda/local.h"
+#include "../../hda/ext/hdac_codec.h"
+#include "hdac_generic.h"
+
+#define HDA_MAX_CVTS	10
+
+struct hdac_generic_dai_map {
+	struct hdac_codec_widget *cvt;
+};
+
+struct hdac_generic_priv {
+	struct hdac_generic_dai_map dai_map[HDA_MAX_CVTS];
+	unsigned int num_pins;
+	unsigned int num_adcs;
+	unsigned int num_dacs;
+	unsigned int num_dapm_widgets;
+};
+
+static void hdac_generic_calc_dapm_widgets(struct hdac_ext_device *edev)
+{
+	struct hdac_generic_priv *hdac_priv = edev->private_data;
+	struct hdac_codec_widget *wid;
+
+	if (list_empty(&edev->hdac.widget_list))
+		return;
+
+	/*
+	 * PIN widget with output capable are represented with an additional
+	 * virtual mux widgets.
+	 */
+	list_for_each_entry(wid, &edev->hdac.widget_list, head) {
+		switch (wid->type) {
+		case AC_WID_AUD_IN:
+			hdac_priv->num_dapm_widgets++;
+			hdac_priv->num_adcs++;
+			break;
+
+		case AC_WID_AUD_OUT:
+			hdac_priv->num_dapm_widgets++;
+			hdac_priv->num_dacs++;
+			break;
+
+		case AC_WID_PIN:
+			hdac_priv->num_pins++;
+			/*
+			 * PIN widgets are represented with dapm_pga and
+			 * dapm_output.
+			 */
+			hdac_priv->num_dapm_widgets += 2;
+
+			if (is_input_pin(&edev->hdac, wid->nid))
+				continue;
+
+			/*
+			 * PIN widget with output capable are represented
+			 * with an additional virtual mux widgets.
+			 */
+			if (wid->num_inputs > 1)
+				hdac_priv->num_dapm_widgets++;
+
+			break;
+
+		case AC_WID_AUD_MIX:
+			hdac_priv->num_dapm_widgets++;
+			break;
+
+		case AC_WID_AUD_SEL:
+			hdac_priv->num_dapm_widgets++;
+			break;
+
+		case AC_WID_POWER:
+			hdac_priv->num_dapm_widgets++;
+			break;
+
+		case AC_WID_BEEP:
+			/*
+			 * Beep widgets are represented with a siggen and
+			 * pga dapm widgets
+			 */
+			hdac_priv->num_dapm_widgets += 2;
+			break;
+
+		default:
+			break;
+		}
+	}
+}
+
+static int hdac_generic_set_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai)
+{
+	struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai);
+	struct hdac_generic_priv *hdac_priv = edev->private_data;
+	struct hdac_generic_dai_map *dai_map = &hdac_priv->dai_map[dai->id];
+	u32 format;
+
+	format = snd_hdac_calc_stream_format(params_rate(hparams),
+			params_channels(hparams), params_format(hparams),
+			24, 0);
+
+	snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
+				AC_VERB_SET_STREAM_FORMAT, format);
+
+	return 0;
+}
+
+static int hdac_generic_program_stream_tag(struct snd_soc_dai *dai,
+						int strm_tag)
+{
+	struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai);
+	struct hdac_generic_priv *hdac_priv = edev->private_data;
+	struct hdac_generic_dai_map *dai_map = &hdac_priv->dai_map[dai->id];
+	int val;
+
+	val = snd_hdac_codec_read(&edev->hdac, dai_map->cvt->nid, 0,
+					AC_VERB_GET_CONV, 0);
+	snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
+				AC_VERB_SET_CHANNEL_STREAMID,
+				(val & 0xf0) | (strm_tag << 4));
+
+	return 0;
+}
+
+static int hdac_codec_set_bias_level(struct snd_soc_codec *codec,
+			enum snd_soc_bias_level level)
+{
+	struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
+	struct hdac_device *hdac = &edev->hdac;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		snd_hdac_codec_read(hdac, hdac->afg, 0,
+			AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_hdac_codec_read(hdac, hdac->afg, 0,
+				AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int hdac_codec_probe(struct snd_soc_codec *codec)
+{
+	struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
+	struct snd_soc_dapm_context *dapm =
+		snd_soc_component_get_dapm(&codec->component);
+
+	edev->scodec = codec;
+
+	/* TODO: create widget, route and controls */
+	/* TODO: jack sense */
+
+	/* Imp: Store the card pointer in hda_codec */
+	edev->card = dapm->card->snd_card;
+
+	/* TODO: runtime PM */
+	return 0;
+}
+
+static int hdac_codec_remove(struct snd_soc_codec *codec)
+{
+	/* TODO: disable runtime pm */
+	return 0;
+}
+
+static struct snd_soc_codec_driver hdac_generic_codec = {
+	.probe		= hdac_codec_probe,
+	.remove		= hdac_codec_remove,
+	.set_bias_level = hdac_codec_set_bias_level,
+};
+
+static struct snd_soc_dai_ops hdac_generic_ops = {
+	.hw_params = hdac_generic_set_hw_params,
+	.program_stream_tag = hdac_generic_program_stream_tag,
+};
+
+static int hdac_generic_create_dais(struct hdac_ext_device *edev,
+		struct snd_soc_dai_driver **dais, int num_dais)
+{
+	struct hdac_device *hdac = &edev->hdac;
+	struct hdac_generic_priv *hdac_priv = edev->private_data;
+	struct snd_soc_dai_driver *codec_dais;
+	char stream_name[HDAC_GENERIC_NAME_SIZE];
+	char dai_name[HDAC_GENERIC_NAME_SIZE];
+	struct hdac_codec_widget *widget;
+	int i = 0;
+	u32 rates, bps;
+	unsigned int rate_max = 192000, rate_min = 8000;
+	u64 formats;
+	int ret;
+
+	codec_dais = devm_kzalloc(&hdac->dev,
+			(sizeof(*codec_dais) * num_dais),
+			GFP_KERNEL);
+	if (!codec_dais)
+		return -ENOMEM;
+
+	/* Iterate over the input cvt list (adc) and create capture DAIs */
+	list_for_each_entry(widget, &edev->hdac.widget_list, head) {
+
+		if ((widget->type != AC_WID_AUD_IN) &&
+				(widget->type != AC_WID_AUD_OUT))
+			continue;
+
+		ret = snd_hdac_query_supported_pcm(hdac, widget->nid,
+				&rates,	&formats, &bps);
+		if (ret)
+			return ret;
+
+		sprintf(dai_name, "%x-aif%d", hdac->vendor_id, i+1);
+
+		codec_dais[i].name = devm_kstrdup(&hdac->dev, dai_name,
+							GFP_KERNEL);
+		if (!codec_dais[i].name)
+			return -ENOMEM;
+
+		codec_dais[i].ops = &hdac_generic_ops;
+		codec_dais[i].dobj.private = widget;
+		hdac_priv->dai_map[i].cvt = widget;
+
+		switch (widget->type) {
+		case AC_WID_AUD_IN:
+			snprintf(stream_name, sizeof(stream_name),
+					"Analog Capture-%d", widget->nid);
+			codec_dais[i].capture.stream_name =
+					devm_kstrdup(&hdac->dev, stream_name,
+								GFP_KERNEL);
+			if (!codec_dais[i].capture.stream_name)
+				return -ENOMEM;
+
+			 /*
+			  * Set caps based on capability queried from the
+			  * converter.
+			  */
+			codec_dais[i].capture.formats = formats;
+			codec_dais[i].capture.rates = rates;
+			codec_dais[i].capture.rate_max = rate_max;
+			codec_dais[i].capture.rate_min = rate_min;
+			codec_dais[i].capture.channels_min = 2;
+			codec_dais[i].capture.channels_max = 2;
+
+			i++;
+			break;
+
+		case AC_WID_AUD_OUT:
+			if (widget->caps & AC_WCAP_DIGITAL)
+				snprintf(stream_name, sizeof(stream_name),
+					"Digital Playback-%d", widget->nid);
+			else
+				snprintf(stream_name, sizeof(stream_name),
+					"Analog Playback-%d", widget->nid);
+
+			codec_dais[i].playback.stream_name =
+					devm_kstrdup(&hdac->dev, stream_name,
+								GFP_KERNEL);
+			if (!codec_dais[i].playback.stream_name)
+				return -ENOMEM;
+
+			/*
+			 * Set caps based on capability queried from the
+			 * converter.
+			 */
+			codec_dais[i].playback.formats = formats;
+			codec_dais[i].playback.rates = rates;
+			codec_dais[i].playback.rate_max = rate_max;
+			codec_dais[i].playback.rate_min = rate_min;
+			codec_dais[i].playback.channels_min = 2;
+			codec_dais[i].playback.channels_max = 2;
+
+			i++;
+
+			break;
+		default:
+			break;
+		}
+	}
+
+	*dais = codec_dais;
+
+	return 0;
+}
+
+static int hdac_generic_dev_probe(struct hdac_ext_device *edev)
+{
+	struct hdac_device *codec = &edev->hdac;
+	struct hdac_generic_priv *hdac_priv;
+	struct snd_soc_dai_driver *codec_dais = NULL;
+	int num_dais = 0;
+	int ret = 0;
+
+	hdac_priv = devm_kzalloc(&codec->dev, sizeof(*hdac_priv), GFP_KERNEL);
+	if (hdac_priv == NULL)
+		return -ENOMEM;
+
+	ret = snd_hdac_codec_init(codec);
+	if (ret < 0)
+		return ret;
+
+	edev->private_data = hdac_priv;
+	dev_set_drvdata(&codec->dev, edev);
+
+	ret = snd_hdac_parse_widgets(codec);
+	if (ret < 0) {
+		dev_err(&codec->dev, "Failed to parse widgets with err: %d\n",
+							ret);
+		return ret;
+	}
+
+	hdac_generic_calc_dapm_widgets(edev);
+
+	if (!hdac_priv->num_pins || ((!hdac_priv->num_adcs) &&
+					 (!hdac_priv->num_dacs))) {
+
+		dev_err(&codec->dev, "No port widgets or cvt widgets");
+		return -EIO;
+	}
+
+	num_dais = hdac_priv->num_adcs + hdac_priv->num_dacs;
+
+	ret = hdac_generic_create_dais(edev, &codec_dais, num_dais);
+	if (ret < 0) {
+		dev_err(&codec->dev, "Failed to create dais with err: %d\n",
+							ret);
+		return ret;
+	}
+
+	/* ASoC specific initialization */
+	return snd_soc_register_codec(&codec->dev, &hdac_generic_codec,
+			codec_dais, num_dais);
+}
+
+static int hdac_generic_dev_remove(struct hdac_ext_device *edev)
+{
+	snd_hdac_codec_cleanup(&edev->hdac);
+	return 0;
+}
+
+/*
+ * TODO:
+ * Driver_data will be used to perform any vendor specific init, register
+ * specific dai ops.
+ * Driver will implement it's own match function to retrieve driver data.
+ */
+static const struct hda_device_id codec_list[] = {
+	HDA_CODEC_EXT_ENTRY(0x10ec0286, 0x100002, "ALC286", 0),
+	{}
+};
+
+MODULE_DEVICE_TABLE(hdaudio, codec_list);
+
+static struct hdac_ext_driver hdac_codec_driver = {
+	. hdac = {
+		.driver = {
+			.name   = "HDA ASoC Codec",
+			/* Add PM */
+		},
+		.id_table       = codec_list,
+	},
+	.probe          = hdac_generic_dev_probe,
+	.remove         = hdac_generic_dev_remove,
+};
+
+static int __init hdac_generic_init(void)
+{
+	return snd_hda_ext_driver_register(&hdac_codec_driver);
+}
+
+static void __exit hdac_generic_exit(void)
+{
+	snd_hda_ext_driver_unregister(&hdac_codec_driver);
+}
+
+module_init(hdac_generic_init);
+module_exit(hdac_generic_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("HDA ASoC codec");
+MODULE_AUTHOR("Subhransu S. Prusty<subhransu.s.prusty@intel.com>");
diff --git a/sound/soc/codecs/hdac_generic.h b/sound/soc/codecs/hdac_generic.h
new file mode 100644
index 0000000..5a4cd36
--- /dev/null
+++ b/sound/soc/codecs/hdac_generic.h
@@ -0,0 +1,25 @@
+/*
+ *  hdac_generic.h - ASoc HDA generic codec driver
+ *
+ *  Copyright (C) 2016-2017 Intel Corp
+ *  Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#ifndef __HDAC_GENERIC_H__
+#define __HDAC_GENERIC_H__
+
+#define HDAC_GENERIC_NAME_SIZE	32
+
+#endif /* __HDAC_GENERIC_H__ */
-- 
1.9.1

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

* [RFC 05/11] ASoC: hdac: Create DAPM model for HDA widgets
  2016-06-27  3:47 [RFC 00/11] ASoC: hdac: Add hdac generic driver Subhransu S. Prusty
                   ` (3 preceding siblings ...)
  2016-06-27  3:47 ` [RFC 04/11] ASoC: hdac: Add a generic hdac driver framework Subhransu S. Prusty
@ 2016-06-27  3:47 ` Subhransu S. Prusty
  2016-06-27  3:47 ` [RFC 06/11] ASoC: dapm: Create API to add a single route element Subhransu S. Prusty
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 30+ messages in thread
From: Subhransu S. Prusty @ 2016-06-27  3:47 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, lgirdwood, patches.audio, broonie, Vinod Koul,
	Subhransu S. Prusty

HDA device widgets are mapped to dapm widgets to take advantage
of DAPM. Each HDA widget can be mapped to one or multiple dapm
widgets based on interface and how it is connected with other
widgets.

For example, a PIN widget 2 or 3 dapm widgets are created
depending on the capability. A dapm input/out widget is created
to represent the input/output capability, a pga widget is created
so that pin with retasking capability can be properly represented
in a dapm graph and a mux widget for output pin is created, if
the connection list has more than one input.

Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
---
 sound/soc/codecs/hdac_generic.c | 484 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 483 insertions(+), 1 deletion(-)

diff --git a/sound/soc/codecs/hdac_generic.c b/sound/soc/codecs/hdac_generic.c
index 79db501..d2b6bec 100644
--- a/sound/soc/codecs/hdac_generic.c
+++ b/sound/soc/codecs/hdac_generic.c
@@ -43,6 +43,483 @@ struct hdac_generic_priv {
 	unsigned int num_dapm_widgets;
 };
 
+static char *wid_names[] = {
+		"dac", "adc", "mixer", "mux", "pin", "power",
+		"volme knob", "beep", NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, "vendor",
+};
+
+static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
+{
+	struct hdac_device *hdac = dev_to_hdac_dev(dev);
+
+	return to_ehdac_device(hdac);
+}
+
+static int hdac_generic_fill_widget_info(struct device *dev,
+		struct snd_soc_dapm_widget *w, enum snd_soc_dapm_type id,
+		void *priv, const char *wname, const char *stream,
+		struct snd_kcontrol_new *wc, int numkc,
+		int (*event)(struct snd_soc_dapm_widget *, struct snd_kcontrol *, int),
+		unsigned short event_flags)
+{
+	w->id = id;
+	w->name = devm_kstrdup(dev, wname, GFP_KERNEL);
+	if (!w->name)
+		return -ENOMEM;
+
+	w->sname = stream;
+	w->reg = SND_SOC_NOPM;
+	w->shift = 0;
+	w->kcontrol_news = wc;
+	w->num_kcontrols = numkc;
+	w->priv = priv;
+	w->event = event;
+	w->event_flags = event_flags;
+
+	return 0;
+}
+
+static int hdac_generic_alloc_mux_widget(struct snd_soc_dapm_context *dapm,
+		struct snd_soc_dapm_widget *widgets, int index,
+		struct hdac_codec_widget *wid)
+
+{
+	struct snd_kcontrol_new *kc;
+	struct soc_enum *se;
+	char kc_name[HDAC_GENERIC_NAME_SIZE];
+	char mux_items[HDAC_GENERIC_NAME_SIZE];
+	char widget_name[HDAC_GENERIC_NAME_SIZE];
+	const char *name;
+	/* To hold inputs to the Pin mux */
+	char *items[HDA_MAX_CONNECTIONS];
+	int i = 0, ret;
+	int num_items = wid->num_inputs + 1;
+
+	if (wid->type == AC_WID_AUD_SEL)
+		sprintf(widget_name, "Mux %x", wid->nid);
+	else if (wid->type == AC_WID_PIN)
+		sprintf(widget_name, "Pin %x Mux", wid->nid);
+	else
+		return -EINVAL;
+
+	kc = devm_kzalloc(dapm->dev, sizeof(*kc), GFP_KERNEL);
+	if (!kc)
+		return -ENOMEM;
+
+	se = devm_kzalloc(dapm->dev, sizeof(*se), GFP_KERNEL);
+	if (!se)
+		return -ENOMEM;
+
+	sprintf(kc_name, "Mux %d Input", wid->nid);
+	kc->name = devm_kstrdup(dapm->dev, kc_name, GFP_KERNEL);
+	if (!kc->name)
+		return -ENOMEM;
+
+	kc->private_value = (long)se;
+	kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	kc->access = 0;
+	kc->info = snd_soc_info_enum_double;
+	kc->put = snd_soc_dapm_put_enum_double;
+	kc->get = snd_soc_dapm_get_enum_double;
+
+	se->reg = SND_SOC_NOPM;
+
+	se->items = num_items;
+	se->mask = roundup_pow_of_two(se->items) - 1;
+
+	sprintf(mux_items, "NONE");
+	items[i] = devm_kstrdup(dapm->dev, mux_items, GFP_KERNEL);
+	if (!items[i])
+		return -ENOMEM;
+
+	for (i = 0; i < wid->num_inputs; i++)	{
+		name = wid_names[wid->conn_list[i].type];
+		if (!name)
+			return -EINVAL;
+
+		sprintf(mux_items, "%s %x", name, wid->conn_list[i].nid);
+		items[i + 1] = devm_kstrdup(dapm->dev, mux_items, GFP_KERNEL);
+		if (!items[i])
+			return -ENOMEM;
+	}
+
+	se->texts = devm_kmemdup(dapm->dev, items,
+			(num_items  * sizeof(char *)), GFP_KERNEL);
+	if (!se->texts)
+		return -ENOMEM;
+
+	ret = hdac_generic_fill_widget_info(dapm->dev, &widgets[index],
+			snd_soc_dapm_mux, wid, widget_name, NULL, kc, 1,
+			NULL, 0);
+
+	if (ret < 0)
+		return ret;
+
+	wid->priv = &widgets[index];
+
+	return 0;
+}
+
+static const char *get_dai_stream(struct snd_soc_dai_driver *dai_drv,
+			int num_dais, struct hdac_codec_widget *wid)
+{
+	int i;
+	struct hdac_codec_widget *tmp;
+
+	for (i = 0; i < num_dais; i++) {
+		tmp = dai_drv[i].dobj.private;
+		if (tmp->nid == wid->nid) {
+			if (wid->type == AC_WID_AUD_IN)
+				return dai_drv[i].capture.stream_name;
+			else
+				return dai_drv[i].playback.stream_name;
+		}
+	}
+
+	return NULL;
+}
+
+static int hdac_codec_alloc_cvt_widget(struct snd_soc_dapm_context *dapm,
+			struct snd_soc_dapm_widget *widgets, int index,
+			struct hdac_codec_widget *wid)
+{
+	struct snd_soc_dai_driver *dai_drv = dapm->component->dai_drv;
+	char widget_name[HDAC_GENERIC_NAME_SIZE];
+	const char *dai_strm_name;
+	int ret = 0;
+
+	dai_strm_name = get_dai_stream(dai_drv,
+				dapm->component->num_dai, wid);
+	if (!dai_strm_name)
+		return -EINVAL;
+
+	if (wid->type == AC_WID_AUD_IN) {
+		sprintf(widget_name, "ADC %x", wid->nid);
+	} else {
+		sprintf(widget_name, "%s DAC %x",
+			(wid->caps & AC_WCAP_DIGITAL) ? "Digital" : "Analog",
+			wid->nid);
+	}
+
+	ret = hdac_generic_fill_widget_info(dapm->dev, &widgets[index],
+			wid->type == AC_WID_AUD_IN ?
+			snd_soc_dapm_aif_in : snd_soc_dapm_aif_out,
+			wid, widget_name, dai_strm_name, NULL, 0, NULL, 0);
+	if (ret < 0)
+		return ret;
+
+	wid->priv = &widgets[index];
+
+	return 0;
+}
+
+static int hdac_codec_alloc_mixer_widget(struct snd_soc_dapm_context *dapm,
+				struct snd_soc_dapm_widget *w, int index,
+				struct hdac_codec_widget *wid)
+{
+	struct snd_kcontrol_new *kc;
+	struct soc_mixer_control *mc;
+	char kc_name[HDAC_GENERIC_NAME_SIZE];
+	char widget_name[HDAC_GENERIC_NAME_SIZE];
+	const char *name;
+	int i, ret;
+
+	kc = devm_kzalloc(dapm->dev,
+			(sizeof(*kc) * wid->num_inputs),
+			GFP_KERNEL);
+	if (!kc)
+		return -ENOMEM;
+
+	for (i = 0; i < wid->num_inputs; i++) {
+		name = wid_names[wid->conn_list[i].type];
+		if (!name)
+			return -EINVAL;
+
+		sprintf(kc_name, "%s %x in Switch",
+				name, wid->conn_list[i].nid);
+		kc[i].name = devm_kstrdup(dapm->dev, kc_name, GFP_KERNEL);
+		if (!kc[i].name)
+			return -ENOMEM;
+
+		mc = devm_kzalloc(dapm->dev, (sizeof(*mc)), GFP_KERNEL);
+		if (!mc)
+			return -ENOMEM;
+
+		mc->reg = SND_SOC_NOPM;
+		mc->rreg = SND_SOC_NOPM;
+		mc->max = 1;
+
+		kc[i].private_value = (long)mc;
+		kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+		kc[i].info = snd_soc_info_volsw;
+		kc[i].put = snd_soc_dapm_get_volsw;
+		kc[i].get = snd_soc_dapm_put_volsw;
+	}
+
+	sprintf(widget_name, "Mixer %x", wid->nid);
+	ret = hdac_generic_fill_widget_info(dapm->dev, &w[index],
+			snd_soc_dapm_mixer, wid, widget_name, NULL,
+			kc, wid->num_inputs, NULL, 0);
+	if (ret < 0)
+		return ret;
+
+	wid->priv = &w[index];
+
+	return 0;
+}
+
+/*
+ * Each Pin widget will be represented with:
+ *	DAPM input/output - Based on out/in capability queried
+ *	DAPM PGA - To program the PIN configuration
+ *	DAPM Mux - Create a virtual Mux widget, if output capable pin can
+ *		   select from multiple inputs.
+ *
+ * Returns number of dapm widgets created on success else returns -ve error
+ * code.
+ */
+static int hdac_codec_alloc_pin_widget(struct snd_soc_dapm_context *dapm,
+			struct snd_soc_dapm_widget *widgets, int index,
+			struct hdac_codec_widget *wid)
+{
+	struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev);
+	char widget_name[HDAC_GENERIC_NAME_SIZE];
+	int i = index;
+	int ret;
+	bool input;
+	/*
+	 * Pin complex are represented with multiple dapm widgets. Cache them
+	 * for easy reference. wid_ref[0]->input/output, wid_ref[1]->pga,
+	 * wid_ref[2]->mux.
+	 */
+	struct snd_soc_dapm_widget **wid_ref;
+
+	input = is_input_pin(&edev->hdac, wid->nid);
+
+	wid_ref = devm_kzalloc(dapm->dev,
+			3 * sizeof(struct snd_soc_dapm_widget),
+			GFP_KERNEL);
+	if (!wid_ref)
+		return -ENOMEM;
+
+	/* Create output/input widget */
+	sprintf(widget_name, "Pin %x %s", wid->nid,
+				input ? "Input" : "Output");
+
+	ret = hdac_generic_fill_widget_info(dapm->dev, &widgets[i],
+			input ? snd_soc_dapm_input : snd_soc_dapm_output,
+			wid, widget_name, NULL, NULL, 0, NULL, 0);
+	if (ret < 0)
+		return ret;
+
+	wid_ref[0] = &widgets[i++];
+
+	/* Create PGA widget */
+	sprintf(widget_name, "Pin %x PGA", wid->nid);
+	ret = hdac_generic_fill_widget_info(dapm->dev, &widgets[i],
+			snd_soc_dapm_pga, wid, widget_name, NULL,
+			NULL, 0, NULL, 0);
+	if (ret < 0)
+		return ret;
+
+	wid_ref[1] = &widgets[i++];
+
+	/* Create Mux if Pin widget can select from multiple inputs */
+	if (!input && wid->num_inputs > 1) {
+		sprintf(widget_name, "Pin %x Mux", wid->nid);
+		ret = hdac_generic_alloc_mux_widget(dapm, widgets, i, wid);
+		if (ret < 0)
+			return ret;
+
+		wid_ref[2] = &widgets[i++];
+	}
+
+	/* override hda widget private with dapm widget group */
+	wid->priv = wid_ref;
+
+	/* Return number of dapm widgets created */
+	return i - index;
+}
+
+static int hdac_codec_alloc_power_widget(struct snd_soc_dapm_context *dapm,
+			struct snd_soc_dapm_widget *widgets, int index,
+			struct hdac_codec_widget *wid)
+{
+	char widget_name[HDAC_GENERIC_NAME_SIZE];
+	int ret = 0;
+
+	sprintf(widget_name, "Power %x", wid->nid);
+	ret = hdac_generic_fill_widget_info(dapm->dev, &widgets[index],
+			snd_soc_dapm_supply, wid, widget_name,
+			NULL, NULL, 0, NULL, 0);
+	if (ret < 0)
+		return ret;
+
+	wid->priv = &widgets[index];
+
+	return 0;
+}
+
+/*
+ * Each Beep hda widget will be represented with two dapm widget a siggen
+ * and a PGA. A virtual switch control will be added to turn on/off DAPM.
+ */
+static int hdac_codec_alloc_beep_widget(struct snd_soc_dapm_context *dapm,
+			struct snd_soc_dapm_widget *widgets, int index,
+			struct hdac_codec_widget *wid)
+{
+	char widget_name[HDAC_GENERIC_NAME_SIZE];
+	int i = index, ret = 0;
+	struct soc_mixer_control *mc;
+	struct snd_kcontrol_new *kc;
+	char kc_name[HDAC_GENERIC_NAME_SIZE];
+	/*
+	 * Beep widgets are represented with multiple dapm widgets. Cache them
+	 * for each reference. wid_ref[0]->siggen, wid_ref[1]->pga.
+	 */
+	struct snd_soc_dapm_widget **wid_ref;
+
+	wid_ref = devm_kzalloc(dapm->dev,
+			2 * sizeof(struct snd_soc_dapm_widget),
+			GFP_KERNEL);
+	if (!wid_ref)
+		return -ENOMEM;
+
+	sprintf(widget_name, "Beep Gen %x", wid->nid);
+	ret = hdac_generic_fill_widget_info(dapm->dev, &widgets[i++],
+			snd_soc_dapm_siggen, wid, widget_name,
+			NULL, NULL, 0, NULL, 0);
+		if (ret < 0)
+			return ret;
+
+	kc = devm_kzalloc(dapm->dev,
+			(sizeof(*kc) * wid->num_inputs),
+			GFP_KERNEL);
+	if (!kc)
+		return -ENOMEM;
+
+	sprintf(kc_name, "%s %x in Switch", wid_names[wid->type], wid->nid);
+	kc[i].name = devm_kstrdup(dapm->dev, kc_name, GFP_KERNEL);
+	if (!kc[i].name)
+		return -ENOMEM;
+	mc = devm_kzalloc(dapm->dev, (sizeof(*mc)), GFP_KERNEL);
+	if (!mc)
+		return -ENOMEM;
+
+	mc->reg = SND_SOC_NOPM;
+	mc->rreg = SND_SOC_NOPM;
+	mc->max = 1;
+
+	kc[i].private_value = (long)mc;
+	kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	kc[i].info = snd_soc_info_volsw;
+	kc[i].put = snd_soc_dapm_get_volsw;
+	kc[i].get = snd_soc_dapm_put_volsw;
+
+	sprintf(widget_name, "Beep Gen %x PGA", wid->nid);
+	ret = hdac_generic_fill_widget_info(dapm->dev, &widgets[i],
+			snd_soc_dapm_pga, wid, widget_name,
+			NULL, kc, 1, NULL, 0);
+	if (ret < 0)
+		return ret;
+
+	wid->priv = wid_ref;
+
+	return 0;
+}
+
+/* Create DAPM widgets to represent each codec widget */
+static int hdac_codec_alloc_widgets(struct snd_soc_dapm_context *dapm,
+		struct snd_soc_dapm_widget *widgets)
+{
+	struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev);
+	struct hdac_codec_widget *wid;
+	int index = 0;
+	int ret = 0;
+
+	list_for_each_entry(wid, &edev->hdac.widget_list, head) {
+		switch (wid->type) {
+		case AC_WID_AUD_IN:
+		case AC_WID_AUD_OUT:
+			ret = hdac_codec_alloc_cvt_widget(dapm, widgets,
+							index, wid);
+			if (ret < 0)
+				return ret;
+			index++;
+			break;
+
+		case AC_WID_PIN:
+			ret = hdac_codec_alloc_pin_widget(dapm, widgets,
+							index, wid);
+			if (ret < 0)
+				return ret;
+			index += ret;
+			break;
+
+		case AC_WID_AUD_MIX:
+			ret = hdac_codec_alloc_mixer_widget(dapm, widgets,
+							index, wid);
+			if (ret < 0)
+				return ret;
+			index++;
+			break;
+
+		case AC_WID_AUD_SEL:
+			ret = hdac_generic_alloc_mux_widget(dapm, widgets,
+							index, wid);
+			if (ret < 0)
+				return ret;
+			index++;
+			break;
+
+		case AC_WID_POWER:
+			ret = hdac_codec_alloc_power_widget(dapm, widgets,
+							index, wid);
+			if (ret < 0)
+				return ret;
+			index++;
+			break;
+
+		case AC_WID_BEEP:
+			ret = hdac_codec_alloc_beep_widget(dapm, widgets,
+							index, wid);
+			if (ret < 0)
+				return ret;
+			index += 2;
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int hdac_generic_create_fill_widget_route_map(
+		struct snd_soc_dapm_context *dapm)
+{
+	struct snd_soc_dapm_widget *widgets;
+	struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev);
+	struct hdac_generic_priv *hdac_priv = edev->private_data;
+
+	widgets = devm_kzalloc(dapm->dev,
+			(sizeof(*widgets) * hdac_priv->num_dapm_widgets),
+			GFP_KERNEL);
+	if (!widgets)
+		return -ENOMEM;
+
+	/* Create DAPM widgets */
+	hdac_codec_alloc_widgets(dapm, widgets);
+
+	snd_soc_dapm_new_controls(dapm, widgets, hdac_priv->num_dapm_widgets);
+
+	/* TODO:  Add each path to dapm graph when enumerated */
+
+	return 0;
+}
+
 static void hdac_generic_calc_dapm_widgets(struct hdac_ext_device *edev)
 {
 	struct hdac_generic_priv *hdac_priv = edev->private_data;
@@ -178,10 +655,15 @@ static int hdac_codec_probe(struct snd_soc_codec *codec)
 	struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
 	struct snd_soc_dapm_context *dapm =
 		snd_soc_component_get_dapm(&codec->component);
+	int ret;
 
 	edev->scodec = codec;
 
-	/* TODO: create widget, route and controls */
+	/* create widget, route and controls */
+	ret = hdac_generic_create_fill_widget_route_map(dapm);
+	if (ret < 0)
+		return ret;
+
 	/* TODO: jack sense */
 
 	/* Imp: Store the card pointer in hda_codec */
-- 
1.9.1

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

* [RFC 06/11] ASoC: dapm: Create API to add a single route element
  2016-06-27  3:47 [RFC 00/11] ASoC: hdac: Add hdac generic driver Subhransu S. Prusty
                   ` (4 preceding siblings ...)
  2016-06-27  3:47 ` [RFC 05/11] ASoC: hdac: Create DAPM model for HDA widgets Subhransu S. Prusty
@ 2016-06-27  3:47 ` Subhransu S. Prusty
  2016-06-27 18:02   ` Mark Brown
  2016-06-27  3:48 ` [RFC 07/11] ASoC: hdac: Build DAPM graph by querying through widget connection list Subhransu S. Prusty
                   ` (5 subsequent siblings)
  11 siblings, 1 reply; 30+ messages in thread
From: Subhransu S. Prusty @ 2016-06-27  3:47 UTC (permalink / raw)
  To: alsa-devel; +Cc: tiwai, patches.audio, broonie, Subhransu S. Prusty, lgirdwood

This is useful when one route element is added at a time.

Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
---
 include/sound/soc-dapm.h |  2 ++
 sound/soc/soc-dapm.c     | 21 +++++++++++++++++++++
 2 files changed, 23 insertions(+)

diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 9706946..fffd1f1 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -396,6 +396,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card);
 void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm);
 int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
 			    const struct snd_soc_dapm_route *route, int num);
+int snd_soc_dapm_add_route_single(struct snd_soc_dapm_context *dapm,
+			    const struct snd_soc_dapm_route *route);
 int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
 			    const struct snd_soc_dapm_route *route, int num);
 int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index c446485..ad67647 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -2802,6 +2802,27 @@ int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
 EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
 
 /**
+ * snd_soc_dapm_add_route_single - Add a single route
+ * @dapm: DAPM context
+ * @route: audio route element
+ *
+ * Connects 2 dapm widgets together via a named audio path.
+ * xxx_add_route is already managed through dapm lock.
+ */
+int snd_soc_dapm_add_route_single(struct snd_soc_dapm_context *dapm,
+			    const struct snd_soc_dapm_route *route)
+{
+	int ret;
+
+	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
+	ret = snd_soc_dapm_add_route(dapm, route);
+	mutex_unlock(&dapm->card->dapm_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_add_route_single);
+
+/**
  * snd_soc_dapm_del_routes - Remove routes between DAPM widgets
  * @dapm: DAPM context
  * @route: audio routes
-- 
1.9.1

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

* [RFC 07/11] ASoC: hdac: Build DAPM graph by querying through widget connection list
  2016-06-27  3:47 [RFC 00/11] ASoC: hdac: Add hdac generic driver Subhransu S. Prusty
                   ` (5 preceding siblings ...)
  2016-06-27  3:47 ` [RFC 06/11] ASoC: dapm: Create API to add a single route element Subhransu S. Prusty
@ 2016-06-27  3:48 ` Subhransu S. Prusty
  2016-06-27  3:48 ` [RFC 08/11] ASoC: hdac: Register widget event handlers Subhransu S. Prusty
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 30+ messages in thread
From: Subhransu S. Prusty @ 2016-06-27  3:48 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, lgirdwood, patches.audio, broonie, Vinod Koul,
	Subhransu S. Prusty

This patch recursively traverses the HDA codec widgets and builds
the graph by querying connection list of each.

Only output pin widget and adc widget endpoints can support
connection list. So for a playback path query happens from output
pin widget end and for a capture path query happens from adc
widget end till an input endpoint is found.

Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
---
 sound/soc/codecs/hdac_generic.c | 324 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 323 insertions(+), 1 deletion(-)

diff --git a/sound/soc/codecs/hdac_generic.c b/sound/soc/codecs/hdac_generic.c
index d2b6bec..a2084aa 100644
--- a/sound/soc/codecs/hdac_generic.c
+++ b/sound/soc/codecs/hdac_generic.c
@@ -49,6 +49,19 @@ static char *wid_names[] = {
 		NULL, NULL, NULL, "vendor",
 };
 
+struct route_map {
+	struct list_head head;
+	const char *sink;
+	char *control;
+	const char *src;
+};
+
+struct widget_node_entries {
+	struct hdac_codec_widget *wid;
+	struct snd_soc_dapm_widget *w;
+	int num_nodes;
+};
+
 static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
 {
 	struct hdac_device *hdac = dev_to_hdac_dev(dev);
@@ -56,6 +69,311 @@ static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
 	return to_ehdac_device(hdac);
 }
 
+static bool is_duplicate_route(struct list_head *route_list,
+		const char *sink, const char *control, const char *src)
+{
+	struct route_map *map;
+
+	list_for_each_entry(map, route_list, head) {
+
+		if (strcmp(src, map->src))
+			continue;
+		if (strcmp(sink, map->sink))
+			continue;
+		if (!control && !map->control)
+			return true;
+		if ((control && map->control) &&
+				!strcmp(control, map->control))
+			return true;
+	}
+
+	return false;
+}
+
+static int hdac_generic_add_route(struct snd_soc_dapm_context *dapm,
+		const char *sink, const char *control, const char *src,
+		struct list_head *route_list)
+{
+	struct snd_soc_dapm_route route;
+	struct route_map *map;
+
+	/*
+	 * During parsing a loop can happen from input pin to output pin.
+	 * An input pin is represented with pga and input dapm widgets.
+	 * There is possibility of duplicate route between these two pga and
+	 * input widgets as the input can appear for multiple output pins or
+	 * adcs during connection list query.
+	 */
+	if (is_duplicate_route(route_list, sink, control, src))
+		return 0;
+
+	route.sink = sink;
+	route.source = src;
+	route.control = control;
+	route.connected = NULL;
+
+	snd_soc_dapm_add_route_single(dapm, &route);
+
+	map = kzalloc(sizeof(*map), GFP_KERNEL);
+	if (!map)
+		return -ENOMEM;
+
+
+	map->sink = sink;
+	map->src = src;
+	if (control) {
+		map->control =
+			kzalloc(sizeof(char) * SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+								GFP_KERNEL);
+		if (!map->control)
+			return -ENOMEM;
+
+		strcpy(map->control, control);
+	}
+
+	list_add_tail(&map->head, route_list);
+
+	return 0;
+}
+
+/* Returns the only dapm widget which can be connected to other hda widgets */
+static struct snd_soc_dapm_widget *hda_widget_to_dapm_widget(
+			struct hdac_ext_device *edev,
+			struct hdac_codec_widget *wid)
+{
+	struct snd_soc_dapm_widget **wid_ref;
+
+	switch (wid->type) {
+	case AC_WID_PIN:
+		wid_ref = wid->priv;
+
+		if (is_input_pin(&edev->hdac, wid->nid))
+			return wid_ref[1];
+
+		if (wid->num_inputs == 1)
+			return wid_ref[1];
+
+		return wid_ref[2];
+
+	case AC_WID_BEEP:
+		wid_ref = wid->priv;
+
+		return wid_ref[1];
+
+	case AC_WID_AUD_OUT:
+	case AC_WID_AUD_IN:
+	case AC_WID_AUD_MIX:
+	case AC_WID_AUD_SEL:
+	case AC_WID_POWER:
+		return wid->priv;
+
+	default:
+		break;
+	}
+
+	return NULL;
+}
+
+static void fill_pinout_next_wid_entry(struct hdac_ext_device *edev,
+			struct widget_node_entries *next,
+			struct widget_node_entries *wid_entry,
+			const char **control, int index)
+{
+	struct snd_soc_dapm_widget **wid_ref = wid_entry->wid->priv;
+	const struct snd_kcontrol_new *kc;
+	struct soc_enum *se;
+
+	switch (wid_entry->w->id) {
+	case snd_soc_dapm_output:
+		next->w = wid_ref[1];
+		next->num_nodes = 1;
+		next->wid = wid_entry->wid;
+
+		break;
+	case snd_soc_dapm_pga:
+		if (wid_entry->wid->num_inputs == 1) {
+			next->wid = wid_entry->wid->conn_list[index].input_w;
+			next->w = hda_widget_to_dapm_widget(
+					edev, next->wid);
+			next->num_nodes = next->wid->num_inputs;
+		} else {
+			next->wid = wid_entry->wid;
+			next->w = wid_ref[2];
+			next->num_nodes = wid_entry->wid->num_inputs;
+		}
+
+		break;
+
+	case snd_soc_dapm_mux:
+		kc = wid_entry->w->kcontrol_news;
+		se = (struct soc_enum *)kc->private_value;
+
+		next->wid = wid_entry->wid->conn_list[index].input_w;
+		next->num_nodes = next->wid->num_inputs;
+		next->w = hda_widget_to_dapm_widget(edev, next->wid);
+
+		*control = se->texts[index + 1];
+
+		break;
+	default:
+		break;
+	}
+}
+
+static int parse_node_and_add_route(struct snd_soc_dapm_context *dapm,
+				struct widget_node_entries *wid_entry,
+				struct list_head *route_list)
+{
+	struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev);
+	int i, ret;
+	struct widget_node_entries next;
+	const char *control = NULL;
+
+
+	if (!wid_entry->num_nodes)
+		return 0;
+
+	if ((wid_entry->w->id == snd_soc_dapm_dac) ||
+			 (wid_entry->w->id == snd_soc_dapm_input) ||
+			 (wid_entry->w->id == snd_soc_dapm_siggen)) {
+
+		return 0;
+	}
+
+	for (i = 0; i < wid_entry->num_nodes; i++) {
+
+		if (wid_entry->wid->type == AC_WID_PIN) {
+			control = NULL;
+
+			if (is_input_pin(&edev->hdac, wid_entry->wid->nid)) {
+
+				struct snd_soc_dapm_widget **wid_ref =
+							wid_entry->wid->priv;
+
+				if (wid_entry->w->id == snd_soc_dapm_pga) {
+					next.w = wid_ref[0];
+					next.num_nodes = 1;
+					next.wid = wid_entry->wid;
+				}
+			} else { /* if output pin */
+				fill_pinout_next_wid_entry(edev, &next,
+						wid_entry, &control, i);
+			}
+		} else {
+			struct snd_soc_dapm_widget *w = wid_entry->wid->priv;
+			const struct snd_kcontrol_new *kc;
+			struct soc_enum *se;
+
+			next.wid = wid_entry->wid->conn_list[i].input_w;
+			next.w = hda_widget_to_dapm_widget(edev, next.wid);
+			next.num_nodes = next.wid->num_inputs;
+
+			switch (w->id) {
+			case snd_soc_dapm_mux:
+				kc = &w->kcontrol_news[0];
+				se = (struct soc_enum *)kc->private_value;
+				control = se->texts[i + 1];
+
+				break;
+
+			case snd_soc_dapm_mixer:
+				kc = &w->kcontrol_news[i];
+				control = kc->name;
+
+				break;
+			default:
+				break;
+			}
+		}
+
+		ret = hdac_generic_add_route(dapm, wid_entry->w->name,
+					control, next.w->name, route_list);
+		if (ret < 0)
+			return ret;
+
+		ret = parse_node_and_add_route(dapm, &next, route_list);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+/*
+ * Example graph connection from a output PIN to a DAC:
+ * DAC1->
+ *         Mixer 1 ------->
+ * DAC2->                   Virtual Mux -> PIN PGA -> OUTPUT PIN
+ *                       ->
+ * LOUT1 ----------------|
+ *
+ * Widget connection map can be created by querying the connection list for
+ * each widget. The parsing can happen from two endpoints:
+ * 1) PIN widget 2) ADC widget.
+ *
+ * This goes through both pin list and adc list and builds the graph.
+ */
+
+static int hdac_generic_add_route_to_list(struct snd_soc_dapm_context *dapm,
+				struct snd_soc_dapm_widget *widgets)
+{
+	struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev);
+	struct hdac_codec_widget *wid;
+	struct snd_soc_dapm_widget **wid_ref;
+	struct widget_node_entries wid_entry;
+	struct list_head route_list;
+	struct route_map *map, *tmp;
+	int ret =  0;
+
+	/*
+	 * manage the routes through a temp list to identify duplicate
+	 * routes from being added.
+	 */
+	INIT_LIST_HEAD(&route_list);
+	list_for_each_entry(wid, &edev->hdac.widget_list, head) {
+		if (wid->type != AC_WID_PIN)
+			continue;
+		/*
+		 * input capable pins don't have a connection list, so skip
+		 * them.
+		 */
+		if (is_input_pin(&edev->hdac, wid->nid))
+			continue;
+
+		wid_ref = wid->priv;
+
+		wid_entry.wid = wid;
+		wid_entry.num_nodes = 1;
+		wid_entry.w = wid_ref[0];
+
+		ret = parse_node_and_add_route(dapm, &wid_entry, &route_list);
+		if (ret < 0)
+			goto fail;
+	}
+
+	list_for_each_entry(wid, &edev->hdac.widget_list, head) {
+		if (wid->type != AC_WID_AUD_IN)
+			continue;
+
+		wid_entry.wid = wid;
+		wid_entry.num_nodes = wid->num_inputs;
+		wid_entry.w = wid->priv;
+
+		ret = parse_node_and_add_route(dapm, &wid_entry, &route_list);
+		if (ret < 0)
+			goto fail;
+	}
+
+fail:
+	list_for_each_entry_safe(map, tmp, &route_list, head) {
+		kfree(map->control);
+		list_del(&map->head);
+		kfree(map);
+	}
+
+	return ret;
+}
+
 static int hdac_generic_fill_widget_info(struct device *dev,
 		struct snd_soc_dapm_widget *w, enum snd_soc_dapm_type id,
 		void *priv, const char *wname, const char *stream,
@@ -515,7 +833,11 @@ static int hdac_generic_create_fill_widget_route_map(
 
 	snd_soc_dapm_new_controls(dapm, widgets, hdac_priv->num_dapm_widgets);
 
-	/* TODO:  Add each path to dapm graph when enumerated */
+	/* Add each path to dapm graph when enumerated */
+	hdac_generic_add_route_to_list(dapm, widgets);
+
+	snd_soc_dapm_new_widgets(dapm->card);
+
 
 	return 0;
 }
-- 
1.9.1

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

* [RFC 08/11] ASoC: hdac: Register widget event handlers
  2016-06-27  3:47 [RFC 00/11] ASoC: hdac: Add hdac generic driver Subhransu S. Prusty
                   ` (6 preceding siblings ...)
  2016-06-27  3:48 ` [RFC 07/11] ASoC: hdac: Build DAPM graph by querying through widget connection list Subhransu S. Prusty
@ 2016-06-27  3:48 ` Subhransu S. Prusty
  2016-06-27  3:48 ` [RFC 09/11] ALSA: hda - macro to get default config device of pin widgets Subhransu S. Prusty
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 30+ messages in thread
From: Subhransu S. Prusty @ 2016-06-27  3:48 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, lgirdwood, patches.audio, broonie, Vinod Koul,
	Subhransu S. Prusty

Register the event handlers and program the codec by sending
required verbs in the event handlers.

Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
---
 sound/soc/codecs/hdac_generic.c | 212 ++++++++++++++++++++++++++++++++++++++--
 sound/soc/codecs/hdac_generic.h |   3 +
 2 files changed, 209 insertions(+), 6 deletions(-)

diff --git a/sound/soc/codecs/hdac_generic.c b/sound/soc/codecs/hdac_generic.c
index a2084aa..32f8736 100644
--- a/sound/soc/codecs/hdac_generic.c
+++ b/sound/soc/codecs/hdac_generic.c
@@ -69,6 +69,188 @@ static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
 	return to_ehdac_device(hdac);
 }
 
+static void hdac_generic_set_power_state(struct hdac_ext_device *edev,
+			hda_nid_t nid, unsigned int pwr_state)
+{
+	/* TODO: check D0sup bit before setting this */
+	if (!snd_hdac_check_power_state(&edev->hdac, nid, pwr_state))
+		snd_hdac_regmap_write(&edev->hdac, nid,
+				AC_VERB_SET_POWER_STATE, pwr_state);
+}
+
+static int hdac_generic_pin_io_event(struct snd_soc_dapm_widget *w,
+			struct snd_kcontrol *kc, int event)
+{
+	struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev);
+	struct hdac_codec_widget *wid = w->priv;
+
+	snd_hdac_codec_write(&edev->hdac, wid->nid, 0,
+			AC_VERB_SET_PIN_WIDGET_CONTROL,
+			w->id == snd_soc_dapm_input ?
+			AC_PINCTL_IN_EN : AC_PINCTL_OUT_EN);
+
+	return 0;
+}
+
+static int hdac_generic_pin_mux_event(struct snd_soc_dapm_widget *w,
+			struct snd_kcontrol *kc, int event)
+{
+	struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev);
+	struct hdac_codec_widget *wid = w->priv;
+	int mux_idx;
+
+	if (!kc)
+		kc  = w->kcontrols[0];
+
+	mux_idx = dapm_kcontrol_get_value(kc);
+
+	snd_hdac_codec_write(&edev->hdac, wid->nid, 0,
+			AC_VERB_SET_CONNECT_SEL, mux_idx);
+
+	return 0;
+}
+
+static int hdac_generic_pin_pga_event(struct snd_soc_dapm_widget *w,
+			struct snd_kcontrol *kc, int event)
+{
+	struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev);
+	struct hdac_codec_widget *wid = w->priv;
+
+	hdac_generic_set_power_state(edev, wid->nid,
+		(event == SND_SOC_DAPM_PRE_PMU ? AC_PWRST_D0:AC_PWRST_D3));
+
+	snd_hdac_codec_write(&edev->hdac, wid->nid, 0,
+			AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+
+	return 0;
+}
+
+static int hdac_generic_widget_power_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kc, int event)
+{
+	struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev);
+	struct hdac_codec_widget *wid = w->priv;
+
+	hdac_generic_set_power_state(edev, wid->nid,
+		(event == SND_SOC_DAPM_PRE_PMU ? AC_PWRST_D0:AC_PWRST_D3));
+
+	return 0;
+}
+
+static int get_mixer_control_index(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kc)
+{
+	int i;
+
+	for (i = 0; i < w->num_kcontrols; i++) {
+		if (w->kcontrols[i] == kc)
+			return i;
+	}
+
+	return -1;
+}
+
+static int hdac_generic_mixer_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kc, int event)
+{
+	struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev);
+	struct hdac_codec_widget *wid = w->priv;
+	bool no_input = true;
+	int i;
+
+	if (event == SND_SOC_DAPM_POST_REG) {
+		i = get_mixer_control_index(w, kc);
+		if (i == -1) {
+			dev_err(&edev->hdac.dev, "%s: Wrong kcontrol event: %s\n",
+							__func__, kc->id.name);
+			return -EINVAL;
+		}
+		if (dapm_kcontrol_get_value(kc)) {
+			snd_hdac_regmap_write(&edev->hdac, wid->nid,
+				AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(i));
+			no_input = false;
+		} else {
+			snd_hdac_regmap_write(&edev->hdac, wid->nid,
+				AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(i));
+		}
+
+		if (no_input)
+			snd_hdac_regmap_write(&edev->hdac, wid->nid,
+				AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+		return 0;
+	}
+
+	hdac_generic_set_power_state(edev, wid->nid,
+		(event == SND_SOC_DAPM_PRE_PMU ? AC_PWRST_D0:AC_PWRST_D3));
+
+	/* TODO: Check capability and program amp */
+	snd_hdac_regmap_write(&edev->hdac, wid->nid, AC_VERB_SET_AMP_GAIN_MUTE,
+							AMP_OUT_UNMUTE);
+
+	for (i = 0; i < w->num_kcontrols; i++) {
+		if (dapm_kcontrol_get_value(w->kcontrols[i])) {
+			snd_hdac_regmap_write(&edev->hdac, wid->nid,
+				AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(i));
+		}
+	}
+
+	return 0;
+}
+
+static void update_mux_input_amp_mute(struct hdac_ext_device *edev,
+		hda_nid_t nid, struct snd_kcontrol *kc)
+{
+	bool no_input = true;
+	struct soc_enum *e = (struct soc_enum *)kc->private_value;
+	int mux_idx, i;
+
+	mux_idx = dapm_kcontrol_get_value(kc);
+
+	for (i = 0; i < (e->items - 1); i++) {
+		if (i == mux_idx) {
+			snd_hdac_regmap_write(&edev->hdac, nid,
+				AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(i));
+
+			no_input = false;
+		} else {
+			snd_hdac_regmap_write(&edev->hdac, nid,
+				AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(i));
+		}
+	}
+
+	if (no_input)
+		snd_hdac_regmap_write(&edev->hdac, nid,
+			AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+}
+
+static int hdac_generic_selector_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kc, int event)
+{
+	struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev);
+	struct hdac_codec_widget *wid = w->priv;
+
+	if (event == SND_SOC_DAPM_POST_REG) {
+		/* TODO: Check capability and program amp */
+		update_mux_input_amp_mute(edev, wid->nid, kc);
+
+		return 0;
+	}
+
+	hdac_generic_set_power_state(edev, wid->nid,
+		(event == SND_SOC_DAPM_PRE_PMU ? AC_PWRST_D0:AC_PWRST_D3));
+
+	snd_hdac_regmap_write(&edev->hdac, wid->nid, AC_VERB_SET_CONNECT_SEL,
+				dapm_kcontrol_get_value(w->kcontrols[0]));
+
+	snd_hdac_regmap_write(&edev->hdac, wid->nid, AC_VERB_SET_AMP_GAIN_MUTE,
+							AMP_OUT_UNMUTE);
+	/* TODO: Check capability and program amp */
+	update_mux_input_amp_mute(edev, wid->nid, w->kcontrols[0]);
+
+	return 0;
+}
+
 static bool is_duplicate_route(struct list_head *route_list,
 		const char *sink, const char *control, const char *src)
 {
@@ -469,7 +651,8 @@ static int hdac_generic_alloc_mux_widget(struct snd_soc_dapm_context *dapm,
 
 	ret = hdac_generic_fill_widget_info(dapm->dev, &widgets[index],
 			snd_soc_dapm_mux, wid, widget_name, NULL, kc, 1,
-			NULL, 0);
+			hdac_generic_selector_event, SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_REG);
 
 	if (ret < 0)
 		return ret;
@@ -523,7 +706,9 @@ static int hdac_codec_alloc_cvt_widget(struct snd_soc_dapm_context *dapm,
 	ret = hdac_generic_fill_widget_info(dapm->dev, &widgets[index],
 			wid->type == AC_WID_AUD_IN ?
 			snd_soc_dapm_aif_in : snd_soc_dapm_aif_out,
-			wid, widget_name, dai_strm_name, NULL, 0, NULL, 0);
+			wid, widget_name, dai_strm_name, NULL, 0,
+			hdac_generic_widget_power_event,
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD);
 	if (ret < 0)
 		return ret;
 
@@ -578,7 +763,9 @@ static int hdac_codec_alloc_mixer_widget(struct snd_soc_dapm_context *dapm,
 	sprintf(widget_name, "Mixer %x", wid->nid);
 	ret = hdac_generic_fill_widget_info(dapm->dev, &w[index],
 			snd_soc_dapm_mixer, wid, widget_name, NULL,
-			kc, wid->num_inputs, NULL, 0);
+			kc, wid->num_inputs, hdac_generic_mixer_event,
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD |
+			SND_SOC_DAPM_POST_REG);
 	if (ret < 0)
 		return ret;
 
@@ -627,7 +814,9 @@ static int hdac_codec_alloc_pin_widget(struct snd_soc_dapm_context *dapm,
 
 	ret = hdac_generic_fill_widget_info(dapm->dev, &widgets[i],
 			input ? snd_soc_dapm_input : snd_soc_dapm_output,
-			wid, widget_name, NULL, NULL, 0, NULL, 0);
+			wid, widget_name, NULL, NULL, 0,
+			hdac_generic_pin_io_event,
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD);
 	if (ret < 0)
 		return ret;
 
@@ -637,7 +826,8 @@ static int hdac_codec_alloc_pin_widget(struct snd_soc_dapm_context *dapm,
 	sprintf(widget_name, "Pin %x PGA", wid->nid);
 	ret = hdac_generic_fill_widget_info(dapm->dev, &widgets[i],
 			snd_soc_dapm_pga, wid, widget_name, NULL,
-			NULL, 0, NULL, 0);
+			NULL, 0, hdac_generic_pin_pga_event,
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD);
 	if (ret < 0)
 		return ret;
 
@@ -649,6 +839,15 @@ static int hdac_codec_alloc_pin_widget(struct snd_soc_dapm_context *dapm,
 		ret = hdac_generic_alloc_mux_widget(dapm, widgets, i, wid);
 		if (ret < 0)
 			return ret;
+		/*
+		 * Pin mux will not use generic selector handler, so
+		 * override. Also mux widget create will increment the
+		 * index, so assign the previous widget.
+		 */
+		widgets[i].event_flags = SND_SOC_DAPM_PRE_PMU |
+						SND_SOC_DAPM_POST_PMD |
+						SND_SOC_DAPM_POST_REG;
+		widgets[i].event = hdac_generic_pin_mux_event;
 
 		wid_ref[2] = &widgets[i++];
 	}
@@ -670,7 +869,8 @@ static int hdac_codec_alloc_power_widget(struct snd_soc_dapm_context *dapm,
 	sprintf(widget_name, "Power %x", wid->nid);
 	ret = hdac_generic_fill_widget_info(dapm->dev, &widgets[index],
 			snd_soc_dapm_supply, wid, widget_name,
-			NULL, NULL, 0, NULL, 0);
+			NULL, NULL, 0, hdac_generic_widget_power_event,
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD);
 	if (ret < 0)
 		return ret;
 
diff --git a/sound/soc/codecs/hdac_generic.h b/sound/soc/codecs/hdac_generic.h
index 5a4cd36..c52dc7c 100644
--- a/sound/soc/codecs/hdac_generic.h
+++ b/sound/soc/codecs/hdac_generic.h
@@ -21,5 +21,8 @@
 #define __HDAC_GENERIC_H__
 
 #define HDAC_GENERIC_NAME_SIZE	32
+#define AMP_OUT_MUTE		0xb080
+#define AMP_OUT_UNMUTE		0xb000
+#define PIN_OUT			(AC_PINCTL_OUT_EN)
 
 #endif /* __HDAC_GENERIC_H__ */
-- 
1.9.1

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

* [RFC 09/11] ALSA: hda - macro to get default config device of pin widgets
  2016-06-27  3:47 [RFC 00/11] ASoC: hdac: Add hdac generic driver Subhransu S. Prusty
                   ` (7 preceding siblings ...)
  2016-06-27  3:48 ` [RFC 08/11] ASoC: hdac: Register widget event handlers Subhransu S. Prusty
@ 2016-06-27  3:48 ` Subhransu S. Prusty
  2016-06-27  3:48 ` [RFC 10/11] ASoC: dapm: Export snd_soc_dapm_new_control Subhransu S. Prusty
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 30+ messages in thread
From: Subhransu S. Prusty @ 2016-06-27  3:48 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, lgirdwood, patches.audio, broonie, Vinod Koul,
	Subhransu S. Prusty

Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
---
 sound/hda/local.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/sound/hda/local.h b/sound/hda/local.h
index a51f5f6..cceeac2 100644
--- a/sound/hda/local.h
+++ b/sound/hda/local.h
@@ -11,6 +11,9 @@
 #define get_pcaps(codec, nid) \
 	snd_hdac_read_parm(codec, nid, AC_PAR_PIN_CAP)
 
+#define get_defcfg_device(cfg) \
+	((cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT)
+
 static inline int is_input_pin(struct hdac_device *codec, hda_nid_t nid)
 {
 	unsigned int pincap = get_pcaps(codec, nid);
-- 
1.9.1

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

* [RFC 10/11] ASoC: dapm: Export snd_soc_dapm_new_control
  2016-06-27  3:47 [RFC 00/11] ASoC: hdac: Add hdac generic driver Subhransu S. Prusty
                   ` (8 preceding siblings ...)
  2016-06-27  3:48 ` [RFC 09/11] ALSA: hda - macro to get default config device of pin widgets Subhransu S. Prusty
@ 2016-06-27  3:48 ` Subhransu S. Prusty
  2016-07-05 14:57   ` Applied "ASoC: dapm: Export snd_soc_dapm_new_control" to the asoc tree Mark Brown
  2016-06-27  3:48 ` [RFC 11/11] ASoC: hdac: Export API to create machine controls Subhransu S. Prusty
  2016-06-27  7:05 ` [RFC 00/11] ASoC: hdac: Add hdac generic driver Takashi Iwai
  11 siblings, 1 reply; 30+ messages in thread
From: Subhransu S. Prusty @ 2016-06-27  3:48 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, lgirdwood, patches.audio, broonie, Vinod Koul,
	Subhransu S. Prusty

This is useful outside the core, when one dapm element is added
at a time.

Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
---
 include/sound/soc-dapm.h | 3 +++
 sound/soc/soc-dapm.c     | 1 +
 2 files changed, 4 insertions(+)

diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index fffd1f1..6e24f00 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -381,6 +381,9 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
 int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
 	const struct snd_soc_dapm_widget *widget,
 	int num);
+struct snd_soc_dapm_widget *snd_soc_dapm_new_control(
+		struct snd_soc_dapm_context *dapm,
+		const struct snd_soc_dapm_widget *widget);
 int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
 				 struct snd_soc_dai *dai);
 int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index ad67647..963c115a 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -3303,6 +3303,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
 	mutex_unlock(&dapm->card->dapm_mutex);
 	return w;
 }
+EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
 
 struct snd_soc_dapm_widget *
 snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
-- 
1.9.1

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

* [RFC 11/11] ASoC: hdac: Export API to create machine controls
  2016-06-27  3:47 [RFC 00/11] ASoC: hdac: Add hdac generic driver Subhransu S. Prusty
                   ` (9 preceding siblings ...)
  2016-06-27  3:48 ` [RFC 10/11] ASoC: dapm: Export snd_soc_dapm_new_control Subhransu S. Prusty
@ 2016-06-27  3:48 ` Subhransu S. Prusty
  2016-06-27  7:05 ` [RFC 00/11] ASoC: hdac: Add hdac generic driver Takashi Iwai
  11 siblings, 0 replies; 30+ messages in thread
From: Subhransu S. Prusty @ 2016-06-27  3:48 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, lgirdwood, patches.audio, broonie, Vinod Koul,
	Subhransu S. Prusty

The default configuration of pin complex is queried and machine
controls are created.

Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
---
 sound/soc/codecs/hdac_generic.c | 145 ++++++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/hdac_generic.h |   3 +
 2 files changed, 148 insertions(+)

diff --git a/sound/soc/codecs/hdac_generic.c b/sound/soc/codecs/hdac_generic.c
index 32f8736..2630a83 100644
--- a/sound/soc/codecs/hdac_generic.c
+++ b/sound/soc/codecs/hdac_generic.c
@@ -580,6 +580,151 @@ static int hdac_generic_fill_widget_info(struct device *dev,
 	return 0;
 }
 
+static int hdac_generic_add_machine_control(struct snd_soc_dapm_context *dapm,
+				enum snd_soc_dapm_type id, const char *name,
+				struct hdac_codec_widget *wid)
+{
+	struct snd_soc_dapm_widget **wid_ref;
+	struct snd_soc_dapm_widget *dapm_w;
+	struct snd_soc_dapm_route route;
+	int ret;
+
+	dapm_w = devm_kzalloc(dapm->dev, sizeof(*dapm_w), GFP_KERNEL);
+	ret = hdac_generic_fill_widget_info(dapm->dev, dapm_w,
+				id, NULL, name,
+				NULL, NULL, 0, NULL, 0);
+	if (ret < 0)
+		return ret;
+
+	wid_ref = wid->priv;
+
+	snd_soc_dapm_new_control(dapm, dapm_w);
+	route.sink = dapm_w->name;
+	route.control = NULL;
+	route.source = wid_ref[0]->name;
+	route.connected = NULL;
+	snd_soc_dapm_add_route_single(dapm, &route);
+	snd_soc_dapm_new_widgets(dapm->card);
+
+	return 0;
+}
+
+/**
+ * hdac_generic_machine_control_init - Add machine widgets and graph
+ * @dapm: machine dapm context
+ * @codec: codec object
+ * @device: pcm device
+ *
+ * Reads the default configuration parameters and builds the machine
+ * controls and graph.
+ */
+int hdac_generic_machine_control_init(struct snd_soc_dapm_context *dapm,
+		struct snd_soc_codec *codec, int device)
+{
+	struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
+	struct hdac_codec_widget *wid;
+	struct snd_soc_dapm_widget **wid_ref;
+	unsigned int *cfg;
+	short dev;
+	int ret;
+
+	list_for_each_entry(wid, &edev->hdac.widget_list, head) {
+		if (wid->type == AC_WID_PIN)
+			continue;
+
+		cfg = wid->params;
+		dev = get_defcfg_device(*cfg);
+
+		if (is_input_pin(&edev->hdac, wid->nid) &&
+				((dev == AC_JACK_LINE_OUT) ||
+				(dev == AC_JACK_SPEAKER) ||
+				(dev == AC_JACK_DIG_OTHER_OUT) ||
+				(dev == AC_JACK_HP_OUT) ||
+				(dev == AC_JACK_SPDIF_OUT))) {
+
+			dev_warn(dapm->dev,
+				"Wrong pin and dev configuration, nid: %d\n",
+				wid->nid);
+
+			continue;
+		}
+
+		switch (dev) {
+		case AC_JACK_LINE_OUT:
+			ret = hdac_generic_add_machine_control(dapm,
+					snd_soc_dapm_line, "Lineout", wid);
+			if (ret < 0)
+				return ret;
+			break;
+		case AC_JACK_SPEAKER:
+			ret = hdac_generic_add_machine_control(dapm,
+					snd_soc_dapm_spk, "spk", wid);
+			if (ret < 0)
+				return ret;
+			break;
+		case AC_JACK_SPDIF_OUT:
+			ret = hdac_generic_add_machine_control(dapm,
+					snd_soc_dapm_spk, "spdif_out", wid);
+			if (ret < 0)
+				return ret;
+			break;
+		case AC_JACK_DIG_OTHER_OUT:
+			ret = hdac_generic_add_machine_control(dapm,
+					snd_soc_dapm_spk, "dig_other_out", wid);
+			if (ret < 0)
+				return ret;
+			break;
+
+		case AC_JACK_HP_OUT:
+			ret = hdac_generic_add_machine_control(dapm,
+					snd_soc_dapm_hp, "hp", wid);
+			if (ret < 0)
+				return ret;
+			break;
+
+		case AC_JACK_AUX:
+			ret = hdac_generic_add_machine_control(dapm,
+					snd_soc_dapm_line, "Aux", wid);
+			if (ret < 0)
+				return ret;
+			break;
+		case AC_JACK_LINE_IN:
+			ret = hdac_generic_add_machine_control(dapm,
+					snd_soc_dapm_line, "Linein", wid);
+			if (ret < 0)
+				return ret;
+			break;
+
+		case AC_JACK_MIC_IN:
+			ret = hdac_generic_add_machine_control(dapm,
+					snd_soc_dapm_mic, "MIC", wid);
+			if (ret < 0)
+				return ret;
+			break;
+		case AC_JACK_SPDIF_IN:
+			ret = hdac_generic_add_machine_control(dapm,
+					snd_soc_dapm_mic, "spdif_in", wid);
+			if (ret < 0)
+				return ret;
+			break;
+		case AC_JACK_DIG_OTHER_IN:
+			ret = hdac_generic_add_machine_control(dapm,
+					snd_soc_dapm_mic, "dig_other_in", wid);
+			if (ret < 0)
+				return ret;
+			break;
+
+		default:
+			wid_ref = wid->priv;
+			snd_soc_dapm_nc_pin(dapm, wid_ref[0]->name);
+			break;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(hdac_generic_machine_control_init);
+
 static int hdac_generic_alloc_mux_widget(struct snd_soc_dapm_context *dapm,
 		struct snd_soc_dapm_widget *widgets, int index,
 		struct hdac_codec_widget *wid)
diff --git a/sound/soc/codecs/hdac_generic.h b/sound/soc/codecs/hdac_generic.h
index c52dc7c..cf55d0a 100644
--- a/sound/soc/codecs/hdac_generic.h
+++ b/sound/soc/codecs/hdac_generic.h
@@ -25,4 +25,7 @@
 #define AMP_OUT_UNMUTE		0xb000
 #define PIN_OUT			(AC_PINCTL_OUT_EN)
 
+int hdac_generic_machine_control_init(struct snd_soc_dapm_context *dapm,
+			struct snd_soc_codec *codec, int device);
+
 #endif /* __HDAC_GENERIC_H__ */
-- 
1.9.1

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

* Re: [RFC 00/11] ASoC: hdac: Add hdac generic driver
  2016-06-27  3:47 [RFC 00/11] ASoC: hdac: Add hdac generic driver Subhransu S. Prusty
                   ` (10 preceding siblings ...)
  2016-06-27  3:48 ` [RFC 11/11] ASoC: hdac: Export API to create machine controls Subhransu S. Prusty
@ 2016-06-27  7:05 ` Takashi Iwai
  2016-06-28  5:13   ` Subhransu S. Prusty
  11 siblings, 1 reply; 30+ messages in thread
From: Takashi Iwai @ 2016-06-27  7:05 UTC (permalink / raw)
  To: Subhransu S. Prusty; +Cc: patches.audio, alsa-devel, broonie, lgirdwood

On Mon, 27 Jun 2016 05:47:53 +0200,
Subhransu S. Prusty wrote:
> 
> HDA devices generically can be modelled with DAPM in ASoC. This
> series adds a framework in ASoC to model HDA devices. HDA widgets
> are enumerated and one or multiple DAPM widget(s) are created.
> Connection list is queried for each widget to identify the
> connection between two endpoints and modelled using DAPM graph.
> 
> Set of event handlers are defined for each widget type. Based on
> DAPM events required verbs are sent to program codec.
> 
> Finally a function is exported to query for the device endpoint
> configuration to create machine controls.

Well...  This is really a hard way to go.  The generic codec support
is good, but only if it can cover most of stuff.  That is, you'll have
to think of the exceptions from the beginning, because the majority of
HD-audio devices are exceptional, i.e. don't follow the standard
strictly.  As a generic hint, I would recommend the following:

- Try lots of different codecs and pin configurations.
  At best, write an emulator and process on it, and check the
  robustness and the correctness of your code.
  For example, the old AD1984A is one of the beasts that gives you a
  hell of complex routes.  Also the recent Cirrus codecs gives you
  tons of I/O pins.

- Think how to remap the pins and other setups in general.
  This is one of the most important keys.  Writing the generic code is
  only to solve a tip of iceberg.  The most difficult part is to adapt
  the generic code to the real machine configurations.

- Think how to handle the vendor-specific codes.
  Majority of machines have the own code due to the headset, EAPD,
  digital mic or LED controls, as well as the non-standard jack
  detection.


Takashi

> 
> Hardik T Shah (1):
>   ASoC: Add dai_ops to set the stream tag.
> 
> Subhransu S. Prusty (10):
>   ALSA: hdac: Add codec helper library
>   ALSA: hda - Add macro to test pin widget's input capability
>   ASoC: hdac: Add a generic hdac driver framework
>   ASoC: hdac: Create DAPM model for HDA widgets
>   ASoC: dapm: Create API to add a single route element
>   ASoC: hdac: Build DAPM graph by querying through widget connection
>     list
>   ASoC: hdac: Register widget event handlers
>   ALSA: hda - macro to get default config device of pin widgets
>   ASoC: dapm: Export snd_soc_dapm_new_control
>   ASoC: hdac: Export API to create machine controls
> 
>  include/sound/hdaudio.h         |    1 +
>  include/sound/soc-dai.h         |   12 +
>  include/sound/soc-dapm.h        |    5 +
>  sound/hda/ext/Makefile          |    3 +-
>  sound/hda/ext/hdac_codec.c      |  188 +++++
>  sound/hda/ext/hdac_codec.h      |   52 ++
>  sound/hda/local.h               |   13 +
>  sound/soc/codecs/Kconfig        |    5 +
>  sound/soc/codecs/Makefile       |    2 +
>  sound/soc/codecs/hdac_generic.c | 1561 +++++++++++++++++++++++++++++++++++++++
>  sound/soc/codecs/hdac_generic.h |   31 +
>  sound/soc/soc-core.c            |   35 +
>  sound/soc/soc-dapm.c            |   22 +
>  13 files changed, 1929 insertions(+), 1 deletion(-)
>  create mode 100644 sound/hda/ext/hdac_codec.c
>  create mode 100644 sound/hda/ext/hdac_codec.h
>  create mode 100644 sound/soc/codecs/hdac_generic.c
>  create mode 100644 sound/soc/codecs/hdac_generic.h
> 
> -- 
> 1.9.1
> 

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

* Re: [RFC 02/11] ASoC: Add dai_ops to set the stream tag.
  2016-06-27  3:47 ` [RFC 02/11] ASoC: Add dai_ops to set the stream tag Subhransu S. Prusty
@ 2016-06-27 17:30   ` Mark Brown
  2016-06-28  5:21     ` Subhransu S. Prusty
  0 siblings, 1 reply; 30+ messages in thread
From: Mark Brown @ 2016-06-27 17:30 UTC (permalink / raw)
  To: Subhransu S. Prusty
  Cc: alsa-devel, tiwai, Hardik T Shah, lgirdwood, patches.audio, Vinod Koul


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

On Mon, Jun 27, 2016 at 09:17:55AM +0530, Subhransu S. Prusty wrote:

> Stream tag is unique stream identifier for each HDA stream. It's
> programmed in both host and codec to identify link the stream is
> transported.  The platform driver allocates the stream and calls
> this ops to program the stream tag in the codec dai.

This seems incredibly HDMI specific...  what are these tags, can we
represent this as TDM (which seems to be what this is really)?

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

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



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

* Re: [RFC 06/11] ASoC: dapm: Create API to add a single route element
  2016-06-27  3:47 ` [RFC 06/11] ASoC: dapm: Create API to add a single route element Subhransu S. Prusty
@ 2016-06-27 18:02   ` Mark Brown
  2016-06-28  5:22     ` Subhransu S. Prusty
  0 siblings, 1 reply; 30+ messages in thread
From: Mark Brown @ 2016-06-27 18:02 UTC (permalink / raw)
  To: Subhransu S. Prusty; +Cc: tiwai, patches.audio, alsa-devel, lgirdwood


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

On Mon, Jun 27, 2016 at 09:17:59AM +0530, Subhransu S. Prusty wrote:

>  int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
>  			    const struct snd_soc_dapm_route *route, int num);
> +int snd_soc_dapm_add_route_single(struct snd_soc_dapm_context *dapm,
> +			    const struct snd_soc_dapm_route *route);

Just snd_soc_dapm_add_route() and rename the existing internal function.

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

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



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

* Re: [RFC 00/11] ASoC: hdac: Add hdac generic driver
  2016-06-27  7:05 ` [RFC 00/11] ASoC: hdac: Add hdac generic driver Takashi Iwai
@ 2016-06-28  5:13   ` Subhransu S. Prusty
  2016-07-08  7:33     ` Subhransu S. Prusty
  0 siblings, 1 reply; 30+ messages in thread
From: Subhransu S. Prusty @ 2016-06-28  5:13 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: patches.audio, alsa-devel, broonie, lgirdwood

On Mon, Jun 27, 2016 at 09:05:47AM +0200, Takashi Iwai wrote:
> On Mon, 27 Jun 2016 05:47:53 +0200,
> Subhransu S. Prusty wrote:
> > 
> > HDA devices generically can be modelled with DAPM in ASoC. This
> > series adds a framework in ASoC to model HDA devices. HDA widgets
> > are enumerated and one or multiple DAPM widget(s) are created.
> > Connection list is queried for each widget to identify the
> > connection between two endpoints and modelled using DAPM graph.
> > 
> > Set of event handlers are defined for each widget type. Based on
> > DAPM events required verbs are sent to program codec.
> > 
> > Finally a function is exported to query for the device endpoint
> > configuration to create machine controls.
> 
> Well...  This is really a hard way to go.  The generic codec support
> is good, but only if it can cover most of stuff.  That is, you'll have
> to think of the exceptions from the beginning, because the majority of
> HD-audio devices are exceptional, i.e. don't follow the standard

Hi Takashi,

Thanks for review.

I think, more detail in the cover letter would have been helpful here. Sorry
for missing out. Let me explain more.

Intention here is to create a framework for the HDA devices in ASoC. This
will follow standard. This will be registered as generic "virtual" class
device. If there is no match found for vendor id and device id, then the
class driver will be loaded. For vendor specific devices, a match function
will be provided. With the help of this, the vendor quirks will be
registered. Additional widgets, controls and route will be created in a
vendor specific way through vendor ops. So its similar to patch files in
legacy HDA driver.

Vendor specific quirks patch series will follow after the framework is
merged.


> strictly.  As a generic hint, I would recommend the following:
> 
> - Try lots of different codecs and pin configurations.
>   At best, write an emulator and process on it, and check the
>   robustness and the correctness of your code.
>   For example, the old AD1984A is one of the beasts that gives you a
>   hell of complex routes.  Also the recent Cirrus codecs gives you
>   tons of I/O pins.
> 
> - Think how to remap the pins and other setups in general.

Only problem with remapping of the pins, I can think of is, the way it is
represented in DAPM route. In DAPM pins are modelled with multiple DAPM
widgets (input/output, PGA) to handle this remapping capability. Any pin
capable of remapping will be represented with both an input and output DAPM
widget and will have all possible route mapping registered with DAPM. The
remap capability of pin will appear as an alsa control in userspace. Based
on the configuration from userspace the pin capability will be programmed in
the driver.

>   This is one of the most important keys.  Writing the generic code is
>   only to solve a tip of iceberg.  The most difficult part is to adapt
>   the generic code to the real machine configurations.
> 
> - Think how to handle the vendor-specific codes.
>   Majority of machines have the own code due to the headset, EAPD,

These will be handled through alsa controls. There will be many though due
to many optional features and vendor specific.

>   digital mic or LED controls, as well as the non-standard jack
>   detection.

Can you please explain more on what is non-standard jack detection?

Thanks
Subhransu
> 
> 
> Takashi
> 
> > 
> > Hardik T Shah (1):
> >   ASoC: Add dai_ops to set the stream tag.
> > 
> > Subhransu S. Prusty (10):
> >   ALSA: hdac: Add codec helper library
> >   ALSA: hda - Add macro to test pin widget's input capability
> >   ASoC: hdac: Add a generic hdac driver framework
> >   ASoC: hdac: Create DAPM model for HDA widgets
> >   ASoC: dapm: Create API to add a single route element
> >   ASoC: hdac: Build DAPM graph by querying through widget connection
> >     list
> >   ASoC: hdac: Register widget event handlers
> >   ALSA: hda - macro to get default config device of pin widgets
> >   ASoC: dapm: Export snd_soc_dapm_new_control
> >   ASoC: hdac: Export API to create machine controls
> > 
> >  include/sound/hdaudio.h         |    1 +
> >  include/sound/soc-dai.h         |   12 +
> >  include/sound/soc-dapm.h        |    5 +
> >  sound/hda/ext/Makefile          |    3 +-
> >  sound/hda/ext/hdac_codec.c      |  188 +++++
> >  sound/hda/ext/hdac_codec.h      |   52 ++
> >  sound/hda/local.h               |   13 +
> >  sound/soc/codecs/Kconfig        |    5 +
> >  sound/soc/codecs/Makefile       |    2 +
> >  sound/soc/codecs/hdac_generic.c | 1561 +++++++++++++++++++++++++++++++++++++++
> >  sound/soc/codecs/hdac_generic.h |   31 +
> >  sound/soc/soc-core.c            |   35 +
> >  sound/soc/soc-dapm.c            |   22 +
> >  13 files changed, 1929 insertions(+), 1 deletion(-)
> >  create mode 100644 sound/hda/ext/hdac_codec.c
> >  create mode 100644 sound/hda/ext/hdac_codec.h
> >  create mode 100644 sound/soc/codecs/hdac_generic.c
> >  create mode 100644 sound/soc/codecs/hdac_generic.h
> > 
> > -- 
> > 1.9.1
> > 
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

-- 

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

* Re: [RFC 02/11] ASoC: Add dai_ops to set the stream tag.
  2016-06-27 17:30   ` Mark Brown
@ 2016-06-28  5:21     ` Subhransu S. Prusty
  2016-06-28 11:15       ` Mark Brown
  0 siblings, 1 reply; 30+ messages in thread
From: Subhransu S. Prusty @ 2016-06-28  5:21 UTC (permalink / raw)
  To: Mark Brown
  Cc: alsa-devel, tiwai, Hardik T Shah, lgirdwood, patches.audio, Vinod Koul

On Mon, Jun 27, 2016 at 06:30:09PM +0100, Mark Brown wrote:
> On Mon, Jun 27, 2016 at 09:17:55AM +0530, Subhransu S. Prusty wrote:
> 
> > Stream tag is unique stream identifier for each HDA stream. It's
> > programmed in both host and codec to identify link the stream is
> > transported.  The platform driver allocates the stream and calls
> > this ops to program the stream tag in the codec dai.
> 
> This seems incredibly HDMI specific...  what are these tags, can we
> represent this as TDM (which seems to be what this is really)?

Hi Mark,

This is HDA specific and the tag is to support use of same DMA channel by
both host and codec.

Regards,
Subhransu

-- 

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

* Re: [RFC 06/11] ASoC: dapm: Create API to add a single route element
  2016-06-27 18:02   ` Mark Brown
@ 2016-06-28  5:22     ` Subhransu S. Prusty
  0 siblings, 0 replies; 30+ messages in thread
From: Subhransu S. Prusty @ 2016-06-28  5:22 UTC (permalink / raw)
  To: Mark Brown; +Cc: tiwai, patches.audio, alsa-devel, lgirdwood

On Mon, Jun 27, 2016 at 07:02:06PM +0100, Mark Brown wrote:
> On Mon, Jun 27, 2016 at 09:17:59AM +0530, Subhransu S. Prusty wrote:
> 
> >  int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
> >  			    const struct snd_soc_dapm_route *route, int num);
> > +int snd_soc_dapm_add_route_single(struct snd_soc_dapm_context *dapm,
> > +			    const struct snd_soc_dapm_route *route);
> 
> Just snd_soc_dapm_add_route() and rename the existing internal function.

Sure.

Thanks
Subhransu



-- 

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

* Re: [RFC 02/11] ASoC: Add dai_ops to set the stream tag.
  2016-06-28  5:21     ` Subhransu S. Prusty
@ 2016-06-28 11:15       ` Mark Brown
  2016-06-29  4:08         ` Subhransu S. Prusty
  0 siblings, 1 reply; 30+ messages in thread
From: Mark Brown @ 2016-06-28 11:15 UTC (permalink / raw)
  To: Subhransu S. Prusty
  Cc: alsa-devel, tiwai, Hardik T Shah, lgirdwood, patches.audio, Vinod Koul


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

On Tue, Jun 28, 2016 at 10:51:38AM +0530, Subhransu S. Prusty wrote:
> On Mon, Jun 27, 2016 at 06:30:09PM +0100, Mark Brown wrote:

> > This seems incredibly HDMI specific...  what are these tags, can we
> > represent this as TDM (which seems to be what this is really)?

> This is HDA specific and the tag is to support use of same DMA channel by
> both host and codec.

What is a "DMA channel"?

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

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



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

* Re: [RFC 02/11] ASoC: Add dai_ops to set the stream tag.
  2016-06-28 11:15       ` Mark Brown
@ 2016-06-29  4:08         ` Subhransu S. Prusty
  2016-06-29 18:50           ` Mark Brown
  0 siblings, 1 reply; 30+ messages in thread
From: Subhransu S. Prusty @ 2016-06-29  4:08 UTC (permalink / raw)
  To: Mark Brown
  Cc: alsa-devel, tiwai, Hardik T Shah, lgirdwood, patches.audio, Vinod Koul

On Tue, Jun 28, 2016 at 12:15:20PM +0100, Mark Brown wrote:
> On Tue, Jun 28, 2016 at 10:51:38AM +0530, Subhransu S. Prusty wrote:
> > On Mon, Jun 27, 2016 at 06:30:09PM +0100, Mark Brown wrote:
> 
> > > This seems incredibly HDMI specific...  what are these tags, can we
> > > represent this as TDM (which seems to be what this is really)?
> 
> > This is HDA specific and the tag is to support use of same DMA channel by
> > both host and codec.
> 
> What is a "DMA channel"?

Ok. I agree this looks like TDM and we should model it like that :)

Now, the issue is how? The current TDM API doesn't seem so intutive to
invoke for this case. What do you suggest...

Regards,
Subhransu



-- 

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

* Re: [RFC 02/11] ASoC: Add dai_ops to set the stream tag.
  2016-06-29  4:08         ` Subhransu S. Prusty
@ 2016-06-29 18:50           ` Mark Brown
  2016-06-30  8:59             ` Subhransu S. Prusty
  0 siblings, 1 reply; 30+ messages in thread
From: Mark Brown @ 2016-06-29 18:50 UTC (permalink / raw)
  To: Subhransu S. Prusty
  Cc: alsa-devel, tiwai, Hardik T Shah, lgirdwood, patches.audio, Vinod Koul


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

On Wed, Jun 29, 2016 at 09:38:11AM +0530, Subhransu S. Prusty wrote:
> On Tue, Jun 28, 2016 at 12:15:20PM +0100, Mark Brown wrote:
> > On Tue, Jun 28, 2016 at 10:51:38AM +0530, Subhransu S. Prusty wrote:

> > > This is HDA specific and the tag is to support use of same DMA channel by
> > > both host and codec.

> > What is a "DMA channel"?

> Ok. I agree this looks like TDM and we should model it like that :)

> Now, the issue is how? The current TDM API doesn't seem so intutive to
> invoke for this case. What do you suggest...

Without knowing what tags and DMA channels are it's hard to make
suggestions...

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

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



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

* Re: [RFC 02/11] ASoC: Add dai_ops to set the stream tag.
  2016-06-29 18:50           ` Mark Brown
@ 2016-06-30  8:59             ` Subhransu S. Prusty
  2016-07-05 12:54               ` Mark Brown
  0 siblings, 1 reply; 30+ messages in thread
From: Subhransu S. Prusty @ 2016-06-30  8:59 UTC (permalink / raw)
  To: Mark Brown
  Cc: alsa-devel, tiwai, Hardik T Shah, lgirdwood, patches.audio, Vinod Koul

On Wed, Jun 29, 2016 at 07:50:23PM +0100, Mark Brown wrote:
> On Wed, Jun 29, 2016 at 09:38:11AM +0530, Subhransu S. Prusty wrote:
> > On Tue, Jun 28, 2016 at 12:15:20PM +0100, Mark Brown wrote:
> > > On Tue, Jun 28, 2016 at 10:51:38AM +0530, Subhransu S. Prusty wrote:
> 
> > > > This is HDA specific and the tag is to support use of same DMA channel by
> > > > both host and codec.
> 
> > > What is a "DMA channel"?
> 
> > Ok. I agree this looks like TDM and we should model it like that :)
> 
> > Now, the issue is how? The current TDM API doesn't seem so intutive to
> > invoke for this case. What do you suggest...
> 
> Without knowing what tags and DMA channels are it's hard to make
> suggestions...

Hi Mark,

Sure. Let me explain more.

Each DMA channel can be mapped to a stream in HDA. Each stream is mapped
uniquely with a stream tag. The stream is programmed in both host and
codec. In host the DMA is programmed with this stream tag and based on this
DMA picks data from host buffer and puts it onto the link. Similarly the
codec converter is programmed with the same stream tag and codec receives
packet from the link associated with the stream tag.

Regards,
Subhransu


-- 

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

* Re: [RFC 02/11] ASoC: Add dai_ops to set the stream tag.
  2016-06-30  8:59             ` Subhransu S. Prusty
@ 2016-07-05 12:54               ` Mark Brown
  2016-07-08  5:27                 ` Subhransu S. Prusty
  0 siblings, 1 reply; 30+ messages in thread
From: Mark Brown @ 2016-07-05 12:54 UTC (permalink / raw)
  To: Subhransu S. Prusty
  Cc: alsa-devel, tiwai, Hardik T Shah, lgirdwood, patches.audio, Vinod Koul


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

On Thu, Jun 30, 2016 at 02:29:07PM +0530, Subhransu S. Prusty wrote:

> Each DMA channel can be mapped to a stream in HDA. Each stream is mapped
> uniquely with a stream tag. The stream is programmed in both host and
> codec. In host the DMA is programmed with this stream tag and based on this
> DMA picks data from host buffer and puts it onto the link. Similarly the
> codec converter is programmed with the same stream tag and codec receives
> packet from the link associated with the stream tag.

Are these arbatrary tags?  If so why not just pick tags that look like
normal TDM timeslots?

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

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



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

* Applied "ASoC: dapm: Export snd_soc_dapm_new_control" to the asoc tree
  2016-06-27  3:48 ` [RFC 10/11] ASoC: dapm: Export snd_soc_dapm_new_control Subhransu S. Prusty
@ 2016-07-05 14:57   ` Mark Brown
  0 siblings, 0 replies; 30+ messages in thread
From: Mark Brown @ 2016-07-05 14:57 UTC (permalink / raw)
  Cc: alsa-devel, Vinod Koul, lgirdwood, patches.audio, tiwai, broonie,
	Subhransu S. Prusty

The patch

   ASoC: dapm: Export snd_soc_dapm_new_control

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From a5d5639f812f24f10c7affaf0d537c204fdea986 Mon Sep 17 00:00:00 2001
From: "Subhransu S. Prusty" <subhransu.s.prusty@intel.com>
Date: Mon, 27 Jun 2016 09:18:03 +0530
Subject: [PATCH] ASoC: dapm: Export snd_soc_dapm_new_control

This is useful outside the core, when one dapm element is added
at a time.

Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 include/sound/soc-dapm.h | 3 +++
 sound/soc/soc-dapm.c     | 1 +
 2 files changed, 4 insertions(+)

diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 3101d53468aa..0efeb38ae059 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -382,6 +382,9 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
 int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
 	const struct snd_soc_dapm_widget *widget,
 	int num);
+struct snd_soc_dapm_widget *snd_soc_dapm_new_control(
+		struct snd_soc_dapm_context *dapm,
+		const struct snd_soc_dapm_widget *widget);
 int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
 				 struct snd_soc_dai *dai);
 int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index c4464858bf01..cc8f480251e7 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -3282,6 +3282,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
 	mutex_unlock(&dapm->card->dapm_mutex);
 	return w;
 }
+EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
 
 struct snd_soc_dapm_widget *
 snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
-- 
2.8.1

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

* Re: [RFC 02/11] ASoC: Add dai_ops to set the stream tag.
  2016-07-05 12:54               ` Mark Brown
@ 2016-07-08  5:27                 ` Subhransu S. Prusty
  0 siblings, 0 replies; 30+ messages in thread
From: Subhransu S. Prusty @ 2016-07-08  5:27 UTC (permalink / raw)
  To: Mark Brown
  Cc: alsa-devel, tiwai, Hardik T Shah, lgirdwood, patches.audio, Vinod Koul

On Tue, Jul 05, 2016 at 02:54:03PM +0200, Mark Brown wrote:
> On Thu, Jun 30, 2016 at 02:29:07PM +0530, Subhransu S. Prusty wrote:
> 
> > Each DMA channel can be mapped to a stream in HDA. Each stream is mapped
> > uniquely with a stream tag. The stream is programmed in both host and
> > codec. In host the DMA is programmed with this stream tag and based on this
> > DMA picks data from host buffer and puts it onto the link. Similarly the
> > codec converter is programmed with the same stream tag and codec receives
> > packet from the link associated with the stream tag.
> 
> Are these arbatrary tags?  If so why not just pick tags that look like
> normal TDM timeslots?

If I understand correctly, the tag will be programmed in the tx_mask and
all other arguments will not be used.

Regards,
Subhransu


-- 

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

* Re: [RFC 00/11] ASoC: hdac: Add hdac generic driver
  2016-06-28  5:13   ` Subhransu S. Prusty
@ 2016-07-08  7:33     ` Subhransu S. Prusty
  2016-07-08  7:53       ` Takashi Iwai
  0 siblings, 1 reply; 30+ messages in thread
From: Subhransu S. Prusty @ 2016-07-08  7:33 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: patches.audio, alsa-devel, broonie, lgirdwood

On Tue, Jun 28, 2016 at 10:43:47AM +0530, Subhransu S. Prusty wrote:
> On Mon, Jun 27, 2016 at 09:05:47AM +0200, Takashi Iwai wrote:
> > On Mon, 27 Jun 2016 05:47:53 +0200,
> > Subhransu S. Prusty wrote:
> > > 
> > > HDA devices generically can be modelled with DAPM in ASoC. This
> > > series adds a framework in ASoC to model HDA devices. HDA widgets
> > > are enumerated and one or multiple DAPM widget(s) are created.
> > > Connection list is queried for each widget to identify the
> > > connection between two endpoints and modelled using DAPM graph.
> > > 
> > > Set of event handlers are defined for each widget type. Based on
> > > DAPM events required verbs are sent to program codec.
> > > 
> > > Finally a function is exported to query for the device endpoint
> > > configuration to create machine controls.
> > 
> > Well...  This is really a hard way to go.  The generic codec support
> > is good, but only if it can cover most of stuff.  That is, you'll have
> > to think of the exceptions from the beginning, because the majority of
> > HD-audio devices are exceptional, i.e. don't follow the standard
> 
> Hi Takashi,
> 
> Thanks for review.
> 
> I think, more detail in the cover letter would have been helpful here. Sorry
> for missing out. Let me explain more.
> 
> Intention here is to create a framework for the HDA devices in ASoC. This
> will follow standard. This will be registered as generic "virtual" class
> device. If there is no match found for vendor id and device id, then the
> class driver will be loaded. For vendor specific devices, a match function
> will be provided. With the help of this, the vendor quirks will be
> registered. Additional widgets, controls and route will be created in a
> vendor specific way through vendor ops. So its similar to patch files in
> legacy HDA driver.
> 
> Vendor specific quirks patch series will follow after the framework is
> merged.

Hi Takashi,

Any more feedback or looking for more details?

Regards,
Subhransu
> 
> 
> > strictly.  As a generic hint, I would recommend the following:
> > 
> > - Try lots of different codecs and pin configurations.
> >   At best, write an emulator and process on it, and check the
> >   robustness and the correctness of your code.
> >   For example, the old AD1984A is one of the beasts that gives you a
> >   hell of complex routes.  Also the recent Cirrus codecs gives you
> >   tons of I/O pins.
> > 
> > - Think how to remap the pins and other setups in general.
> 
> Only problem with remapping of the pins, I can think of is, the way it is
> represented in DAPM route. In DAPM pins are modelled with multiple DAPM
> widgets (input/output, PGA) to handle this remapping capability. Any pin
> capable of remapping will be represented with both an input and output DAPM
> widget and will have all possible route mapping registered with DAPM. The
> remap capability of pin will appear as an alsa control in userspace. Based
> on the configuration from userspace the pin capability will be programmed in
> the driver.
> 
> >   This is one of the most important keys.  Writing the generic code is
> >   only to solve a tip of iceberg.  The most difficult part is to adapt
> >   the generic code to the real machine configurations.
> > 
> > - Think how to handle the vendor-specific codes.
> >   Majority of machines have the own code due to the headset, EAPD,
> 
> These will be handled through alsa controls. There will be many though due
> to many optional features and vendor specific.
> 
> >   digital mic or LED controls, as well as the non-standard jack
> >   detection.
> 
> Can you please explain more on what is non-standard jack detection?
> 
> Thanks
> Subhransu
> > 
> > 
> > Takashi
> > 
> > > 
> > > Hardik T Shah (1):
> > >   ASoC: Add dai_ops to set the stream tag.
> > > 
> > > Subhransu S. Prusty (10):
> > >   ALSA: hdac: Add codec helper library
> > >   ALSA: hda - Add macro to test pin widget's input capability
> > >   ASoC: hdac: Add a generic hdac driver framework
> > >   ASoC: hdac: Create DAPM model for HDA widgets
> > >   ASoC: dapm: Create API to add a single route element
> > >   ASoC: hdac: Build DAPM graph by querying through widget connection
> > >     list
> > >   ASoC: hdac: Register widget event handlers
> > >   ALSA: hda - macro to get default config device of pin widgets
> > >   ASoC: dapm: Export snd_soc_dapm_new_control
> > >   ASoC: hdac: Export API to create machine controls
> > > 
> > >  include/sound/hdaudio.h         |    1 +
> > >  include/sound/soc-dai.h         |   12 +
> > >  include/sound/soc-dapm.h        |    5 +
> > >  sound/hda/ext/Makefile          |    3 +-
> > >  sound/hda/ext/hdac_codec.c      |  188 +++++
> > >  sound/hda/ext/hdac_codec.h      |   52 ++
> > >  sound/hda/local.h               |   13 +
> > >  sound/soc/codecs/Kconfig        |    5 +
> > >  sound/soc/codecs/Makefile       |    2 +
> > >  sound/soc/codecs/hdac_generic.c | 1561 +++++++++++++++++++++++++++++++++++++++
> > >  sound/soc/codecs/hdac_generic.h |   31 +
> > >  sound/soc/soc-core.c            |   35 +
> > >  sound/soc/soc-dapm.c            |   22 +
> > >  13 files changed, 1929 insertions(+), 1 deletion(-)
> > >  create mode 100644 sound/hda/ext/hdac_codec.c
> > >  create mode 100644 sound/hda/ext/hdac_codec.h
> > >  create mode 100644 sound/soc/codecs/hdac_generic.c
> > >  create mode 100644 sound/soc/codecs/hdac_generic.h
> > > 
> > > -- 
> > > 1.9.1
> > > 
> > _______________________________________________
> > Alsa-devel mailing list
> > Alsa-devel@alsa-project.org
> > http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
> 
> -- 

-- 

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

* Re: [RFC 00/11] ASoC: hdac: Add hdac generic driver
  2016-07-08  7:33     ` Subhransu S. Prusty
@ 2016-07-08  7:53       ` Takashi Iwai
  2016-07-08  8:21         ` Subhransu S. Prusty
  0 siblings, 1 reply; 30+ messages in thread
From: Takashi Iwai @ 2016-07-08  7:53 UTC (permalink / raw)
  To: Subhransu S. Prusty; +Cc: patches.audio, alsa-devel, broonie, lgirdwood

On Fri, 08 Jul 2016 09:33:48 +0200,
Subhransu S. Prusty wrote:
> 
> On Tue, Jun 28, 2016 at 10:43:47AM +0530, Subhransu S. Prusty wrote:
> > On Mon, Jun 27, 2016 at 09:05:47AM +0200, Takashi Iwai wrote:
> > > On Mon, 27 Jun 2016 05:47:53 +0200,
> > > Subhransu S. Prusty wrote:
> > > > 
> > > > HDA devices generically can be modelled with DAPM in ASoC. This
> > > > series adds a framework in ASoC to model HDA devices. HDA widgets
> > > > are enumerated and one or multiple DAPM widget(s) are created.
> > > > Connection list is queried for each widget to identify the
> > > > connection between two endpoints and modelled using DAPM graph.
> > > > 
> > > > Set of event handlers are defined for each widget type. Based on
> > > > DAPM events required verbs are sent to program codec.
> > > > 
> > > > Finally a function is exported to query for the device endpoint
> > > > configuration to create machine controls.
> > > 
> > > Well...  This is really a hard way to go.  The generic codec support
> > > is good, but only if it can cover most of stuff.  That is, you'll have
> > > to think of the exceptions from the beginning, because the majority of
> > > HD-audio devices are exceptional, i.e. don't follow the standard
> > 
> > Hi Takashi,
> > 
> > Thanks for review.
> > 
> > I think, more detail in the cover letter would have been helpful here. Sorry
> > for missing out. Let me explain more.
> > 
> > Intention here is to create a framework for the HDA devices in ASoC. This
> > will follow standard. This will be registered as generic "virtual" class
> > device. If there is no match found for vendor id and device id, then the
> > class driver will be loaded. For vendor specific devices, a match function
> > will be provided. With the help of this, the vendor quirks will be
> > registered. Additional widgets, controls and route will be created in a
> > vendor specific way through vendor ops. So its similar to patch files in
> > legacy HDA driver.
> > 
> > Vendor specific quirks patch series will follow after the framework is
> > merged.
> 
> Hi Takashi,
> 
> Any more feedback or looking for more details?

Sorry I haven't looked at the patchset much, as they are mostly for
ASoC specific.  BTW, what about EAPD and pin vref?  Are they set up
and configurable?


Takashi

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

* Re: [RFC 00/11] ASoC: hdac: Add hdac generic driver
  2016-07-08  7:53       ` Takashi Iwai
@ 2016-07-08  8:21         ` Subhransu S. Prusty
  2016-07-08  8:37           ` Takashi Iwai
  0 siblings, 1 reply; 30+ messages in thread
From: Subhransu S. Prusty @ 2016-07-08  8:21 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: patches.audio, alsa-devel, broonie, lgirdwood

On Fri, Jul 08, 2016 at 09:53:05AM +0200, Takashi Iwai wrote:
> On Fri, 08 Jul 2016 09:33:48 +0200,
> Subhransu S. Prusty wrote:
> > 
> > On Tue, Jun 28, 2016 at 10:43:47AM +0530, Subhransu S. Prusty wrote:
> > > On Mon, Jun 27, 2016 at 09:05:47AM +0200, Takashi Iwai wrote:
> > > > On Mon, 27 Jun 2016 05:47:53 +0200,
> > > > Subhransu S. Prusty wrote:
> > > > > 
> > > > > HDA devices generically can be modelled with DAPM in ASoC. This
> > > > > series adds a framework in ASoC to model HDA devices. HDA widgets
> > > > > are enumerated and one or multiple DAPM widget(s) are created.
> > > > > Connection list is queried for each widget to identify the
> > > > > connection between two endpoints and modelled using DAPM graph.
> > > > > 
> > > > > Set of event handlers are defined for each widget type. Based on
> > > > > DAPM events required verbs are sent to program codec.
> > > > > 
> > > > > Finally a function is exported to query for the device endpoint
> > > > > configuration to create machine controls.
> > > > 
> > > > Well...  This is really a hard way to go.  The generic codec support
> > > > is good, but only if it can cover most of stuff.  That is, you'll have
> > > > to think of the exceptions from the beginning, because the majority of
> > > > HD-audio devices are exceptional, i.e. don't follow the standard
> > > 
> > > Hi Takashi,
> > > 
> > > Thanks for review.
> > > 
> > > I think, more detail in the cover letter would have been helpful here. Sorry
> > > for missing out. Let me explain more.
> > > 
> > > Intention here is to create a framework for the HDA devices in ASoC. This
> > > will follow standard. This will be registered as generic "virtual" class
> > > device. If there is no match found for vendor id and device id, then the
> > > class driver will be loaded. For vendor specific devices, a match function
> > > will be provided. With the help of this, the vendor quirks will be
> > > registered. Additional widgets, controls and route will be created in a
> > > vendor specific way through vendor ops. So its similar to patch files in
> > > legacy HDA driver.
> > > 
> > > Vendor specific quirks patch series will follow after the framework is
> > > merged.
> > 
> > Hi Takashi,
> > 
> > Any more feedback or looking for more details?
> 
> Sorry I haven't looked at the patchset much, as they are mostly for
> ASoC specific.  BTW, what about EAPD and pin vref?  Are they set up
> and configurable?

EAPD can be configured as an widget if capability available.  vref can
be alsa control to the user to set the percentage value.

Regards,
Subhransu

> 
> 
> Takashi

-- 

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

* Re: [RFC 00/11] ASoC: hdac: Add hdac generic driver
  2016-07-08  8:21         ` Subhransu S. Prusty
@ 2016-07-08  8:37           ` Takashi Iwai
  2016-07-08  8:49             ` Subhransu S. Prusty
  0 siblings, 1 reply; 30+ messages in thread
From: Takashi Iwai @ 2016-07-08  8:37 UTC (permalink / raw)
  To: Subhransu S. Prusty; +Cc: patches.audio, alsa-devel, broonie, lgirdwood

On Fri, 08 Jul 2016 10:21:39 +0200,
Subhransu S. Prusty wrote:
> 
> On Fri, Jul 08, 2016 at 09:53:05AM +0200, Takashi Iwai wrote:
> > On Fri, 08 Jul 2016 09:33:48 +0200,
> > Subhransu S. Prusty wrote:
> > > 
> > > On Tue, Jun 28, 2016 at 10:43:47AM +0530, Subhransu S. Prusty wrote:
> > > > On Mon, Jun 27, 2016 at 09:05:47AM +0200, Takashi Iwai wrote:
> > > > > On Mon, 27 Jun 2016 05:47:53 +0200,
> > > > > Subhransu S. Prusty wrote:
> > > > > > 
> > > > > > HDA devices generically can be modelled with DAPM in ASoC. This
> > > > > > series adds a framework in ASoC to model HDA devices. HDA widgets
> > > > > > are enumerated and one or multiple DAPM widget(s) are created.
> > > > > > Connection list is queried for each widget to identify the
> > > > > > connection between two endpoints and modelled using DAPM graph.
> > > > > > 
> > > > > > Set of event handlers are defined for each widget type. Based on
> > > > > > DAPM events required verbs are sent to program codec.
> > > > > > 
> > > > > > Finally a function is exported to query for the device endpoint
> > > > > > configuration to create machine controls.
> > > > > 
> > > > > Well...  This is really a hard way to go.  The generic codec support
> > > > > is good, but only if it can cover most of stuff.  That is, you'll have
> > > > > to think of the exceptions from the beginning, because the majority of
> > > > > HD-audio devices are exceptional, i.e. don't follow the standard
> > > > 
> > > > Hi Takashi,
> > > > 
> > > > Thanks for review.
> > > > 
> > > > I think, more detail in the cover letter would have been helpful here. Sorry
> > > > for missing out. Let me explain more.
> > > > 
> > > > Intention here is to create a framework for the HDA devices in ASoC. This
> > > > will follow standard. This will be registered as generic "virtual" class
> > > > device. If there is no match found for vendor id and device id, then the
> > > > class driver will be loaded. For vendor specific devices, a match function
> > > > will be provided. With the help of this, the vendor quirks will be
> > > > registered. Additional widgets, controls and route will be created in a
> > > > vendor specific way through vendor ops. So its similar to patch files in
> > > > legacy HDA driver.
> > > > 
> > > > Vendor specific quirks patch series will follow after the framework is
> > > > merged.
> > > 
> > > Hi Takashi,
> > > 
> > > Any more feedback or looking for more details?
> > 
> > Sorry I haven't looked at the patchset much, as they are mostly for
> > ASoC specific.  BTW, what about EAPD and pin vref?  Are they set up
> > and configurable?
> 
> EAPD can be configured as an widget if capability available.  vref can
> be alsa control to the user to set the percentage value.

Were these implemented in your patchset, or mean as a plan?


Takashi

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

* Re: [RFC 00/11] ASoC: hdac: Add hdac generic driver
  2016-07-08  8:37           ` Takashi Iwai
@ 2016-07-08  8:49             ` Subhransu S. Prusty
  0 siblings, 0 replies; 30+ messages in thread
From: Subhransu S. Prusty @ 2016-07-08  8:49 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: patches.audio, alsa-devel, broonie, lgirdwood

On Fri, Jul 08, 2016 at 10:37:48AM +0200, Takashi Iwai wrote:
> On Fri, 08 Jul 2016 10:21:39 +0200,
> Subhransu S. Prusty wrote:
> > 
> > On Fri, Jul 08, 2016 at 09:53:05AM +0200, Takashi Iwai wrote:
> > > On Fri, 08 Jul 2016 09:33:48 +0200,
> > > Subhransu S. Prusty wrote:
> > > > 
> > > > On Tue, Jun 28, 2016 at 10:43:47AM +0530, Subhransu S. Prusty wrote:
> > > > > On Mon, Jun 27, 2016 at 09:05:47AM +0200, Takashi Iwai wrote:
> > > > > > On Mon, 27 Jun 2016 05:47:53 +0200,
> > > > > > Subhransu S. Prusty wrote:
> > > > > > > 
> > > > > > > HDA devices generically can be modelled with DAPM in ASoC. This
> > > > > > > series adds a framework in ASoC to model HDA devices. HDA widgets
> > > > > > > are enumerated and one or multiple DAPM widget(s) are created.
> > > > > > > Connection list is queried for each widget to identify the
> > > > > > > connection between two endpoints and modelled using DAPM graph.
> > > > > > > 
> > > > > > > Set of event handlers are defined for each widget type. Based on
> > > > > > > DAPM events required verbs are sent to program codec.
> > > > > > > 
> > > > > > > Finally a function is exported to query for the device endpoint
> > > > > > > configuration to create machine controls.
> > > > > > 
> > > > > > Well...  This is really a hard way to go.  The generic codec support
> > > > > > is good, but only if it can cover most of stuff.  That is, you'll have
> > > > > > to think of the exceptions from the beginning, because the majority of
> > > > > > HD-audio devices are exceptional, i.e. don't follow the standard
> > > > > 
> > > > > Hi Takashi,
> > > > > 
> > > > > Thanks for review.
> > > > > 
> > > > > I think, more detail in the cover letter would have been helpful here. Sorry
> > > > > for missing out. Let me explain more.
> > > > > 
> > > > > Intention here is to create a framework for the HDA devices in ASoC. This
> > > > > will follow standard. This will be registered as generic "virtual" class
> > > > > device. If there is no match found for vendor id and device id, then the
> > > > > class driver will be loaded. For vendor specific devices, a match function
> > > > > will be provided. With the help of this, the vendor quirks will be
> > > > > registered. Additional widgets, controls and route will be created in a
> > > > > vendor specific way through vendor ops. So its similar to patch files in
> > > > > legacy HDA driver.
> > > > > 
> > > > > Vendor specific quirks patch series will follow after the framework is
> > > > > merged.
> > > > 
> > > > Hi Takashi,
> > > > 
> > > > Any more feedback or looking for more details?
> > > 
> > > Sorry I haven't looked at the patchset much, as they are mostly for
> > > ASoC specific.  BTW, what about EAPD and pin vref?  Are they set up
> > > and configurable?
> > 
> > EAPD can be configured as an widget if capability available.  vref can
> > be alsa control to the user to set the percentage value.
> 
> Were these implemented in your patchset, or mean as a plan?

This is not implemented in this patchset. But yes it's already in our plan.
This series only programs the required verbs. We will add optional features,
jack detection, vendor specific quirks and other features after the basic
drivers is merged.

Regards,
Subhransu
> 
> 
> Takashi
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

-- 

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

end of thread, other threads:[~2016-07-08  8:53 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-27  3:47 [RFC 00/11] ASoC: hdac: Add hdac generic driver Subhransu S. Prusty
2016-06-27  3:47 ` [RFC 01/11] ALSA: hdac: Add codec helper library Subhransu S. Prusty
2016-06-27  3:47 ` [RFC 02/11] ASoC: Add dai_ops to set the stream tag Subhransu S. Prusty
2016-06-27 17:30   ` Mark Brown
2016-06-28  5:21     ` Subhransu S. Prusty
2016-06-28 11:15       ` Mark Brown
2016-06-29  4:08         ` Subhransu S. Prusty
2016-06-29 18:50           ` Mark Brown
2016-06-30  8:59             ` Subhransu S. Prusty
2016-07-05 12:54               ` Mark Brown
2016-07-08  5:27                 ` Subhransu S. Prusty
2016-06-27  3:47 ` [RFC 03/11] ALSA: hda - Add macro to test pin widget's input capability Subhransu S. Prusty
2016-06-27  3:47 ` [RFC 04/11] ASoC: hdac: Add a generic hdac driver framework Subhransu S. Prusty
2016-06-27  3:47 ` [RFC 05/11] ASoC: hdac: Create DAPM model for HDA widgets Subhransu S. Prusty
2016-06-27  3:47 ` [RFC 06/11] ASoC: dapm: Create API to add a single route element Subhransu S. Prusty
2016-06-27 18:02   ` Mark Brown
2016-06-28  5:22     ` Subhransu S. Prusty
2016-06-27  3:48 ` [RFC 07/11] ASoC: hdac: Build DAPM graph by querying through widget connection list Subhransu S. Prusty
2016-06-27  3:48 ` [RFC 08/11] ASoC: hdac: Register widget event handlers Subhransu S. Prusty
2016-06-27  3:48 ` [RFC 09/11] ALSA: hda - macro to get default config device of pin widgets Subhransu S. Prusty
2016-06-27  3:48 ` [RFC 10/11] ASoC: dapm: Export snd_soc_dapm_new_control Subhransu S. Prusty
2016-07-05 14:57   ` Applied "ASoC: dapm: Export snd_soc_dapm_new_control" to the asoc tree Mark Brown
2016-06-27  3:48 ` [RFC 11/11] ASoC: hdac: Export API to create machine controls Subhransu S. Prusty
2016-06-27  7:05 ` [RFC 00/11] ASoC: hdac: Add hdac generic driver Takashi Iwai
2016-06-28  5:13   ` Subhransu S. Prusty
2016-07-08  7:33     ` Subhransu S. Prusty
2016-07-08  7:53       ` Takashi Iwai
2016-07-08  8:21         ` Subhransu S. Prusty
2016-07-08  8:37           ` Takashi Iwai
2016-07-08  8:49             ` Subhransu S. Prusty

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