+++ /dev/null
-From: Takashi Iwai <tiwai@suse.de>
-Subject: ALSA: hda - Slave SPDIF support
-Patch-mainline: 2.6.28-rc1
-References:
-
-Add the support of slave SPDIF outputs for multiple SPDIF devices.
-
-Signed-off-by: Takashi Iwai <tiwai@suse.de>
-
----
----
- sound/pci/hda/hda_codec.c | 72 ++++++++++++++++++++++++++-----------
- sound/pci/hda/hda_codec.h | 89 +++++++++++++++++++++++++++++++++++++++++++---
- sound/pci/hda/hda_local.h | 15 ++++---
- 3 files changed, 146 insertions(+), 30 deletions(-)
-
---- a/sound/pci/hda/hda_codec.c
-+++ b/sound/pci/hda/hda_codec.c
-@@ -1430,6 +1430,29 @@ static unsigned int convert_to_spdif_sta
- return sbits;
- }
-
-+/* set digital convert verbs both for the given NID and its slaves */
-+static void set_dig_out(struct hda_codec *codec, hda_nid_t nid,
-+ int verb, int val)
-+{
-+ hda_nid_t *d;
-+
-+ snd_hda_codec_write(codec, nid, 0, verb, val);
-+ d = codec->slave_dig_outs;
-+ if (!d)
-+ return;
-+ for (; *d; d++)
-+ snd_hda_codec_write(codec, *d, 0, verb, val);
-+}
-+
-+static inline void set_dig_out_convert(struct hda_codec *codec, hda_nid_t nid,
-+ int dig1, int dig2)
-+{
-+ if (dig1 != -1)
-+ set_dig_out(codec, nid, AC_VERB_SET_DIGI_CONVERT_1, dig1);
-+ if (dig2 != -1)
-+ set_dig_out(codec, nid, AC_VERB_SET_DIGI_CONVERT_2, dig2);
-+}
-+
- static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
- {
-@@ -1448,14 +1471,8 @@ static int snd_hda_spdif_default_put(str
- change = codec->spdif_ctls != val;
- codec->spdif_ctls = val;
-
-- if (change) {
-- snd_hda_codec_write_cache(codec, nid, 0,
-- AC_VERB_SET_DIGI_CONVERT_1,
-- val & 0xff);
-- snd_hda_codec_write_cache(codec, nid, 0,
-- AC_VERB_SET_DIGI_CONVERT_2,
-- val >> 8);
-- }
-+ if (change)
-+ set_dig_out_convert(codec, nid, val & 0xff, (val >> 8) & 0xff);
-
- mutex_unlock(&codec->spdif_mutex);
- return change;
-@@ -1487,9 +1504,7 @@ static int snd_hda_spdif_out_switch_put(
- change = codec->spdif_ctls != val;
- if (change) {
- codec->spdif_ctls = val;
-- snd_hda_codec_write_cache(codec, nid, 0,
-- AC_VERB_SET_DIGI_CONVERT_1,
-- val & 0xff);
-+ set_dig_out_convert(codec, nid, val & 0xff, -1);
- /* unmute amp switch (if any) */
- if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) &&
- (val & AC_DIG1_ENABLE))
-@@ -2583,14 +2598,31 @@ static void setup_dig_out_stream(struct
- unsigned int stream_tag, unsigned int format)
- {
- /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
-- if (codec->spdif_ctls & AC_DIG1_ENABLE)
-- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
-- codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
-+ if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
-+ set_dig_out_convert(codec, nid,
-+ codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff,
-+ -1);
- snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
-+ if (codec->slave_dig_outs) {
-+ hda_nid_t *d;
-+ for (d = codec->slave_dig_outs; *d; d++)
-+ snd_hda_codec_setup_stream(codec, *d, stream_tag, 0,
-+ format);
-+ }
- /* turn on again (if needed) */
-- if (codec->spdif_ctls & AC_DIG1_ENABLE)
-- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
-- codec->spdif_ctls & 0xff);
-+ if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
-+ set_dig_out_convert(codec, nid,
-+ codec->spdif_ctls & 0xff, -1);
-+}
-+
-+static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid)
-+{
-+ snd_hda_codec_cleanup_stream(codec, nid);
-+ if (codec->slave_dig_outs) {
-+ hda_nid_t *d;
-+ for (d = codec->slave_dig_outs; *d; d++)
-+ snd_hda_codec_cleanup_stream(codec, *d);
-+ }
- }
-
- /*
-@@ -2602,7 +2634,7 @@ int snd_hda_multi_out_dig_open(struct hd
- mutex_lock(&codec->spdif_mutex);
- if (mout->dig_out_used == HDA_DIG_ANALOG_DUP)
- /* already opened as analog dup; reset it once */
-- snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid);
-+ cleanup_dig_out_stream(codec, mout->dig_out_nid);
- mout->dig_out_used = HDA_DIG_EXCLUSIVE;
- mutex_unlock(&codec->spdif_mutex);
- return 0;
-@@ -2697,7 +2729,7 @@ int snd_hda_multi_out_analog_prepare(str
- stream_tag, format);
- } else {
- mout->dig_out_used = 0;
-- snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid);
-+ cleanup_dig_out_stream(codec, mout->dig_out_nid);
- }
- }
- mutex_unlock(&codec->spdif_mutex);
-@@ -2748,7 +2780,7 @@ int snd_hda_multi_out_analog_cleanup(str
- mout->extra_out_nid[i]);
- mutex_lock(&codec->spdif_mutex);
- if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
-- snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid);
-+ cleanup_dig_out_stream(codec, mout->dig_out_nid);
- mout->dig_out_used = 0;
- }
- mutex_unlock(&codec->spdif_mutex);
---- a/sound/pci/hda/hda_codec.h
-+++ b/sound/pci/hda/hda_codec.h
-@@ -90,6 +90,14 @@ enum {
- #define AC_VERB_GET_CONFIG_DEFAULT 0x0f1c
- /* f20: AFG/MFG */
- #define AC_VERB_GET_SUBSYSTEM_ID 0x0f20
-+#define AC_VERB_GET_CVT_CHAN_COUNT 0x0f2d
-+#define AC_VERB_GET_HDMI_DIP_SIZE 0x0f2e
-+#define AC_VERB_GET_HDMI_ELDD 0x0f2f
-+#define AC_VERB_GET_HDMI_DIP_INDEX 0x0f30
-+#define AC_VERB_GET_HDMI_DIP_DATA 0x0f31
-+#define AC_VERB_GET_HDMI_DIP_XMIT 0x0f32
-+#define AC_VERB_GET_HDMI_CP_CTRL 0x0f33
-+#define AC_VERB_GET_HDMI_CHAN_SLOT 0x0f34
-
- /*
- * SET verbs
-@@ -121,7 +129,14 @@ enum {
- #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1 0x71d
- #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2 0x71e
- #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_3 0x71f
-+#define AC_VERB_SET_EAPD 0x788
- #define AC_VERB_SET_CODEC_RESET 0x7ff
-+#define AC_VERB_SET_CVT_CHAN_COUNT 0x72d
-+#define AC_VERB_SET_HDMI_DIP_INDEX 0x730
-+#define AC_VERB_SET_HDMI_DIP_DATA 0x731
-+#define AC_VERB_SET_HDMI_DIP_XMIT 0x732
-+#define AC_VERB_SET_HDMI_CP_CTRL 0x733
-+#define AC_VERB_SET_HDMI_CHAN_SLOT 0x734
-
- /*
- * Parameter IDs
-@@ -143,6 +158,7 @@ enum {
- #define AC_PAR_GPIO_CAP 0x11
- #define AC_PAR_AMP_OUT_CAP 0x12
- #define AC_PAR_VOL_KNB_CAP 0x13
-+#define AC_PAR_HDMI_LPCM_CAP 0x20
-
- /*
- * AC_VERB_PARAMETERS results (32bit)
-@@ -171,6 +187,8 @@ enum {
- #define AC_WCAP_DIGITAL (1<<9) /* digital I/O */
- #define AC_WCAP_POWER (1<<10) /* power control */
- #define AC_WCAP_LR_SWAP (1<<11) /* L/R swap */
-+#define AC_WCAP_CP_CAPS (1<<12) /* content protection */
-+#define AC_WCAP_CHAN_CNT_EXT (7<<13) /* channel count ext */
- #define AC_WCAP_DELAY (0xf<<16)
- #define AC_WCAP_DELAY_SHIFT 16
- #define AC_WCAP_TYPE (0xf<<20)
-@@ -206,9 +224,20 @@ enum {
- /* Input converter SDI select */
- #define AC_SDI_SELECT (0xf<<0)
-
--/* Unsolicited response */
-+/* Unsolicited response control */
- #define AC_UNSOL_TAG (0x3f<<0)
- #define AC_UNSOL_ENABLED (1<<7)
-+#define AC_USRSP_EN AC_UNSOL_ENABLED
-+
-+/* Unsolicited responses */
-+#define AC_UNSOL_RES_TAG (0x3f<<26)
-+#define AC_UNSOL_RES_TAG_SHIFT 26
-+#define AC_UNSOL_RES_SUBTAG (0x1f<<21)
-+#define AC_UNSOL_RES_SUBTAG_SHIFT 21
-+#define AC_UNSOL_RES_ELDV (1<<1) /* ELD Data valid (for HDMI) */
-+#define AC_UNSOL_RES_PD (1<<0) /* pinsense detect */
-+#define AC_UNSOL_RES_CP_STATE (1<<1) /* content protection */
-+#define AC_UNSOL_RES_CP_READY (1<<0) /* content protection */
-
- /* Pin widget capabilies */
- #define AC_PINCAP_IMP_SENSE (1<<0) /* impedance sense capable */
-@@ -222,6 +251,10 @@ enum {
- * but is marked reserved in the Intel HDA specification.
- */
- #define AC_PINCAP_LR_SWAP (1<<7) /* L/R swap */
-+/* Note: The same bit as LR_SWAP is newly defined as HDMI capability
-+ * in HD-audio specification
-+ */
-+#define AC_PINCAP_HDMI (1<<7) /* HDMI pin */
- #define AC_PINCAP_VREF (0x37<<8)
- #define AC_PINCAP_VREF_SHIFT 8
- #define AC_PINCAP_EAPD (1<<16) /* EAPD capable */
-@@ -272,6 +305,22 @@ enum {
- #define AC_KNBCAP_NUM_STEPS (0x7f<<0)
- #define AC_KNBCAP_DELTA (1<<7)
-
-+/* HDMI LPCM capabilities */
-+#define AC_LPCMCAP_48K_CP_CHNS (0x0f<<0) /* max channels w/ CP-on */
-+#define AC_LPCMCAP_48K_NO_CHNS (0x0f<<4) /* max channels w/o CP-on */
-+#define AC_LPCMCAP_48K_20BIT (1<<8) /* 20b bitrate supported */
-+#define AC_LPCMCAP_48K_24BIT (1<<9) /* 24b bitrate supported */
-+#define AC_LPCMCAP_96K_CP_CHNS (0x0f<<10) /* max channels w/ CP-on */
-+#define AC_LPCMCAP_96K_NO_CHNS (0x0f<<14) /* max channels w/o CP-on */
-+#define AC_LPCMCAP_96K_20BIT (1<<18) /* 20b bitrate supported */
-+#define AC_LPCMCAP_96K_24BIT (1<<19) /* 24b bitrate supported */
-+#define AC_LPCMCAP_192K_CP_CHNS (0x0f<<20) /* max channels w/ CP-on */
-+#define AC_LPCMCAP_192K_NO_CHNS (0x0f<<24) /* max channels w/o CP-on */
-+#define AC_LPCMCAP_192K_20BIT (1<<28) /* 20b bitrate supported */
-+#define AC_LPCMCAP_192K_24BIT (1<<29) /* 24b bitrate supported */
-+#define AC_LPCMCAP_44K (1<<30) /* 44.1kHz support */
-+#define AC_LPCMCAP_44K_MS (1<<31) /* 44.1kHz-multiplies support */
-+
- /*
- * Control Parameters
- */
-@@ -317,18 +366,44 @@ enum {
- #define AC_PINCTL_OUT_EN (1<<6)
- #define AC_PINCTL_HP_EN (1<<7)
-
--/* Unsolicited response - 8bit */
--#define AC_USRSP_EN (1<<7)
--
- /* Pin sense - 32bit */
- #define AC_PINSENSE_IMPEDANCE_MASK (0x7fffffff)
- #define AC_PINSENSE_PRESENCE (1<<31)
-+#define AC_PINSENSE_ELDV (1<<30) /* ELD valid (HDMI) */
-
- /* EAPD/BTL enable - 32bit */
- #define AC_EAPDBTL_BALANCED (1<<0)
- #define AC_EAPDBTL_EAPD (1<<1)
- #define AC_EAPDBTL_LR_SWAP (1<<2)
-
-+/* HDMI ELD data */
-+#define AC_ELDD_ELD_VALID (1<<31)
-+#define AC_ELDD_ELD_DATA 0xff
-+
-+/* HDMI DIP size */
-+#define AC_DIPSIZE_ELD_BUF (1<<3) /* ELD buf size of packet size */
-+#define AC_DIPSIZE_PACK_IDX (0x07<<0) /* packet index */
-+
-+/* HDMI DIP index */
-+#define AC_DIPIDX_PACK_IDX (0x07<<5) /* packet idnex */
-+#define AC_DIPIDX_BYTE_IDX (0x1f<<0) /* byte index */
-+
-+/* HDMI DIP xmit (transmit) control */
-+#define AC_DIPXMIT_MASK (0x3<<6)
-+#define AC_DIPXMIT_DISABLE (0x0<<6) /* disable xmit */
-+#define AC_DIPXMIT_ONCE (0x2<<6) /* xmit once then disable */
-+#define AC_DIPXMIT_BEST (0x3<<6) /* best effort */
-+
-+/* HDMI content protection (CP) control */
-+#define AC_CPCTRL_CES (1<<9) /* current encryption state */
-+#define AC_CPCTRL_READY (1<<8) /* ready bit */
-+#define AC_CPCTRL_SUBTAG (0x1f<<3) /* subtag for unsol-resp */
-+#define AC_CPCTRL_STATE (3<<0) /* current CP request state */
-+
-+/* Converter channel <-> HDMI slot mapping */
-+#define AC_CVTMAP_HDMI_SLOT (0xf<<0) /* HDMI slot number */
-+#define AC_CVTMAP_CHAN (0xf<<4) /* converter channel number */
-+
- /* configuration default - 32bit */
- #define AC_DEFCFG_SEQUENCE (0xf<<0)
- #define AC_DEFCFG_DEF_ASSOC (0xf<<4)
-@@ -650,9 +725,15 @@ struct hda_codec {
- unsigned int spdif_status; /* IEC958 status bits */
- unsigned short spdif_ctls; /* SPDIF control bits */
- unsigned int spdif_in_enable; /* SPDIF input enable? */
-+ hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
-
- struct snd_hwdep *hwdep; /* assigned hwdep device */
-
-+ /* misc flags */
-+ unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each
-+ * status change
-+ * (e.g. Realtek codecs)
-+ */
- #ifdef CONFIG_SND_HDA_POWER_SAVE
- unsigned int power_on :1; /* current (global) power-state */
- unsigned int power_transition :1; /* power-state in transition */
---- a/sound/pci/hda/hda_local.h
-+++ b/sound/pci/hda/hda_local.h
-@@ -368,12 +368,15 @@ int snd_hda_parse_pin_def_config(struct
- #define AMP_OUT_UNMUTE 0xb000
- #define AMP_OUT_ZERO 0xb000
- /* pinctl values */
--#define PIN_IN 0x20
--#define PIN_VREF80 0x24
--#define PIN_VREF50 0x21
--#define PIN_OUT 0x40
--#define PIN_HP 0xc0
--#define PIN_HP_AMP 0x80
-+#define PIN_IN (AC_PINCTL_IN_EN)
-+#define PIN_VREFHIZ (AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ)
-+#define PIN_VREF50 (AC_PINCTL_IN_EN | AC_PINCTL_VREF_50)
-+#define PIN_VREFGRD (AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD)
-+#define PIN_VREF80 (AC_PINCTL_IN_EN | AC_PINCTL_VREF_80)
-+#define PIN_VREF100 (AC_PINCTL_IN_EN | AC_PINCTL_VREF_100)
-+#define PIN_OUT (AC_PINCTL_OUT_EN)
-+#define PIN_HP (AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN)
-+#define PIN_HP_AMP (AC_PINCTL_HP_EN)
-
- /*
- * get widget capabilities