[alsa-devel] [PATCH 00/30] ASoC: hdac_hdmi: Add support to enable MST audio
From: Jeeja KP jeeja.kp@intel.com
Display port 1.2 introduces new capability Multi-stream transport (MST) which will allow multiple stream to route to single display port where multiple monitors are connected. Multiple monitors will be connected by a MST Hub or a monitor capable of daisy-chaining.
With MST support, a pin can support multiple ports and on each port a monitor can be connected.
This patch series enables DP MST Audio by extending the current design from pin to port. o With MST, pin mux for CVT selection will be used to select CVT for pin-port instead of pin. So create the pin mux accordingly.
o Pin is marked as MST capable when connect event reports pipe as valid. if pipe is -1, then pin is not MST capable and default to port 0. if pipe is valid, then pin is MST capable and port = pipe.
o For MST capable pin, select the device entry before configuring the pin widget verbs controlling the sink device operations.
o Add support to handle multiple Port mapped to same converter by creating as port list in pcm and report jack event based on the no of ports connected/disconnected .
o i915 acomp APIs are now used to read the ELD info and support is extended for MST port as well.
o Configure port/pin/audio infoframe in widget event handlers for dynamic routing when monitor is connected/disconnected instead of DAI ops.
o Use set_tdm slot to set the stream tag instead of dai params and store it in pcm context and use this in configuring the converter in widget event handler.
o Use pin widget to represent the output to enable/disable path when a device is connected/disconnected. Added API to create the pin widget and this will be called by the machine driver after jack creation.
o Add channel map support for bxt machine.
o Move from snd_jack to ASOC jack framework, create the jack in machine driver.
o Create port pin widget to enable and disable the path dynamically when a jack is connected/disconnected.
Note: This patch series has dependency on the series "ASoC: Intel: Skylake: Driver updates"
Jeeja KP (29): ASoC: hdac_hdmi: Register widget event handlers ASoC: Intel: Skylake: Use set_tdm_slot to set the dma channel ASoC: hdac_hdmi: Move channel info from pin to PCM structure ASoC: Intel: bxt: add channel map support in rt298 machine ASoC: Intel: bxt: add channel map support in bxt_da7219_max98357a machine ASoC: hdac_hdmi: Begin to add support for DP Multi-stream audio ASoC: Intel: Skylake: Add route change to rt286 machine ASoC: Intel: Skylake: Add route change to nau88l25_max98357a machine ASoC: Intel: Skylake: Add route change to nau88l25_ssm4567 machine ASoC: Intel: bxt: Add route change to rt298 machine ASoC: Intel: bxt: Add route change to da7219_max98357a machine ASoC: hdac_hdmi: Add support to handle MST capable pin ASoC: hdac_hdmi: Add MST verb support ASoC: hdac_hdmi: Handle MST pin jack detection at boot/resume ASoc: hdac_hdmi: Configure pin verbs for MST ASoC: hdac_hdmi: Add support for multiple ports to a PCM ASoC: hdac_hdmi: Use ASoC jack instead of snd_jack ASoC: Intel: Skylake: Create ASoC jack for hdmi in rt286 machine ASoC: Intel: Skylake: Create ASoC jack for hdmi in skl_nau88l25_max98357a machine ASoC: Intel: Skylake: Create ASoC jack for hdmi in skl_nau88l25_ssm4567 machine ASoC: Intel: bxt: Create ASoC jack for hdmi in bxt_rt298 machine ASoC: Intel: bxt: Create ASoC jack for hdmi in bxt_da7219_max98357 machine ASoC: hdac_hdmi: Add machine pin widget for each port ASoC: Intel: Skylake: Add jack port initialize in rt286 machine ASoC: Intel: Skylake: Add jack port initialize in skl_nau88l25_max98357a machine ASoC: Intel: Skylake: Add jack port initialize in skl_nau88l25_ssm4567 machine ASoC: Intel: Skylake: Add jack port initialize in bxt_rt298 machine ASoC: Intel: Skylake: Add jack port initialize in bxt_da7219_max98357a machine ASoC: Intel: Skylake: Fix to delete DSP pipe after stopping pipe
Sandeep Tayal (1): ASoC: hdac_hdmi: use audio component framework to read ELD
sound/soc/codecs/hdac_hdmi.c | 1331 ++++++++++++++--------- sound/soc/codecs/hdac_hdmi.h | 5 +- sound/soc/intel/boards/bxt_da7219_max98357a.c | 75 +- sound/soc/intel/boards/bxt_rt298.c | 78 +- sound/soc/intel/boards/skl_nau88l25_max98357a.c | 34 +- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 33 +- sound/soc/intel/boards/skl_rt286.c | 30 +- sound/soc/intel/skylake/skl-messages.c | 2 +- sound/soc/intel/skylake/skl-pcm.c | 10 +- 9 files changed, 1045 insertions(+), 553 deletions(-)
From: Sandeep Tayal sandeepx.tayal@intel.com
With codec read sometimes the pin_sense shows invalid monitor present and eld_valid. Currently driver polls for few times to get the valid eld data.
To avoid the latency, Instead of reading ELD from codec, read it directly from the display driver using audio component framework. and removed the unused direct codec helper functions.
Signed-off-by: Sandeep Tayal sandeepx.tayal@intel.com Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/codecs/hdac_hdmi.c | 201 ++++++++++++------------------------------- 1 file changed, 56 insertions(+), 145 deletions(-)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 1c2a978..548474d 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -46,6 +46,10 @@ #define ELD_MAX_SIZE 256 #define ELD_FIXED_BYTES 20
+#define ELD_VER_CEA_861D 2 +#define ELD_VER_PARTIAL 31 +#define ELD_MAX_MNL 16 + struct hdac_hdmi_cvt_params { unsigned int channels_min; unsigned int channels_max; @@ -81,8 +85,6 @@ struct hdac_hdmi_pin { hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; struct hdac_hdmi_eld eld; struct hdac_ext_device *edev; - int repoll_count; - struct delayed_work work; struct mutex lock; bool chmap_set; unsigned char chmap[8]; /* ALSA API channel-map */ @@ -179,80 +181,6 @@ static int hdac_hdmi_eld_limit_formats(struct snd_pcm_runtime *runtime,
}
- /* HDMI ELD routines */ -static unsigned int hdac_hdmi_get_eld_data(struct hdac_device *codec, - hda_nid_t nid, int byte_index) -{ - unsigned int val; - - val = snd_hdac_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_ELDD, - byte_index); - - dev_dbg(&codec->dev, "HDMI: ELD data byte %d: 0x%x\n", - byte_index, val); - - return val; -} - -static int hdac_hdmi_get_eld_size(struct hdac_device *codec, hda_nid_t nid) -{ - return snd_hdac_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, - AC_DIPSIZE_ELD_BUF); -} - -/* - * This function queries the ELD size and ELD data and fills in the buffer - * passed by user - */ -static int hdac_hdmi_get_eld(struct hdac_device *codec, hda_nid_t nid, - unsigned char *buf, int *eld_size) -{ - int i, size, ret = 0; - - /* - * ELD size is initialized to zero in caller function. If no errors and - * ELD is valid, actual eld_size is assigned. - */ - - size = hdac_hdmi_get_eld_size(codec, nid); - if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) { - dev_err(&codec->dev, "HDMI: invalid ELD buf size %d\n", size); - return -ERANGE; - } - - /* set ELD buffer */ - for (i = 0; i < size; i++) { - unsigned int val = hdac_hdmi_get_eld_data(codec, nid, i); - /* - * Graphics driver might be writing to ELD buffer right now. - * Just abort. The caller will repoll after a while. - */ - if (!(val & AC_ELDD_ELD_VALID)) { - dev_err(&codec->dev, - "HDMI: invalid ELD data byte %d\n", i); - ret = -EINVAL; - goto error; - } - val &= AC_ELDD_ELD_DATA; - /* - * The first byte cannot be zero. This can happen on some DVI - * connections. Some Intel chips may also need some 250ms delay - * to return non-zero ELD data, even when the graphics driver - * correctly writes ELD content before setting ELD_valid bit. - */ - if (!val && !i) { - dev_err(&codec->dev, "HDMI: 0 ELD data\n"); - ret = -EINVAL; - goto error; - } - buf[i] = val; - } - - *eld_size = size; -error: - return ret; -} - static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac, hda_nid_t cvt_nid, hda_nid_t pin_nid, u32 stream_tag, int format) @@ -1065,32 +993,59 @@ static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid) return hdac_hdmi_query_cvt_params(&edev->hdac, cvt); }
-static void hdac_hdmi_parse_eld(struct hdac_ext_device *edev, +static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev, struct hdac_hdmi_pin *pin) { + unsigned int ver, mnl; + + ver = (pin->eld.eld_buffer[DRM_ELD_VER] & DRM_ELD_VER_MASK) + >> DRM_ELD_VER_SHIFT; + + if (ver != ELD_VER_CEA_861D && ver != ELD_VER_PARTIAL) { + dev_err(&edev->hdac.dev, "HDMI: Unknown ELD version %d\n", ver); + return -EINVAL; + } + + mnl = (pin->eld.eld_buffer[DRM_ELD_CEA_EDID_VER_MNL] & + DRM_ELD_MNL_MASK) >> DRM_ELD_MNL_SHIFT; + + if (mnl > ELD_MAX_MNL) { + dev_err(&edev->hdac.dev, "HDMI: MNL Invalid %d\n", mnl); + return -EINVAL; + } + pin->eld.info.spk_alloc = pin->eld.eld_buffer[DRM_ELD_SPEAKER]; + + return 0; }
-static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll) +static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin) { struct hdac_ext_device *edev = pin->edev; struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm; - int val; - - pin->repoll_count = repoll; + int size;
- pm_runtime_get_sync(&edev->hdac.dev); - val = snd_hdac_codec_read(&edev->hdac, pin->nid, 0, - AC_VERB_GET_PIN_SENSE, 0); + mutex_lock(&hdmi->pin_mutex); + pin->eld.monitor_present = false;
- dev_dbg(&edev->hdac.dev, "Pin sense val %x for pin: %d\n", - val, pin->nid); + size = snd_hdac_acomp_get_eld(&edev->hdac, pin->nid, -1, + &pin->eld.monitor_present, pin->eld.eld_buffer, + ELD_MAX_SIZE);
+ if (size > 0) { + size = min(size, ELD_MAX_SIZE); + if (hdac_hdmi_parse_eld(edev, pin) < 0) + size = -EINVAL; + }
- mutex_lock(&hdmi->pin_mutex); - pin->eld.monitor_present = !!(val & AC_PINSENSE_PRESENCE); - pin->eld.eld_valid = !!(val & AC_PINSENSE_ELDV); + if (size > 0) { + pin->eld.eld_valid = true; + pin->eld.eld_size = size; + } else { + pin->eld.eld_valid = false; + pin->eld.eld_size = 0; + }
pcm = hdac_hdmi_get_pcm(edev, pin);
@@ -1112,66 +1067,23 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll) }
mutex_unlock(&hdmi->pin_mutex); - goto put_hdac_device; + return; }
if (pin->eld.monitor_present && pin->eld.eld_valid) { - /* TODO: use i915 component for reading ELD later */ - if (hdac_hdmi_get_eld(&edev->hdac, pin->nid, - pin->eld.eld_buffer, - &pin->eld.eld_size) == 0) { - - if (pcm) { - dev_dbg(&edev->hdac.dev, - "jack report for pcm=%d\n", - pcm->pcm_id); - - snd_jack_report(pcm->jack, SND_JACK_AVOUT); - } - hdac_hdmi_parse_eld(edev, pin); - - print_hex_dump_debug("ELD: ", - DUMP_PREFIX_OFFSET, 16, 1, - pin->eld.eld_buffer, pin->eld.eld_size, - true); - } else { - pin->eld.monitor_present = false; - pin->eld.eld_valid = false; - - if (pcm) { - dev_dbg(&edev->hdac.dev, - "jack report for pcm=%d\n", - pcm->pcm_id); + if (pcm) { + dev_dbg(&edev->hdac.dev, + "jack report for pcm=%d\n", + pcm->pcm_id);
- snd_jack_report(pcm->jack, 0); - } + snd_jack_report(pcm->jack, SND_JACK_AVOUT); } + + print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1, + pin->eld.eld_buffer, pin->eld.eld_size, false); }
mutex_unlock(&hdmi->pin_mutex); - - /* - * Sometimes the pin_sense may present invalid monitor - * present and eld_valid. If ELD data is not valid, loop few - * more times to get correct pin sense and valid ELD. - */ - if ((!pin->eld.monitor_present || !pin->eld.eld_valid) && repoll) - schedule_delayed_work(&pin->work, msecs_to_jiffies(300)); - -put_hdac_device: - pm_runtime_put_sync(&edev->hdac.dev); -} - -static void hdac_hdmi_repoll_eld(struct work_struct *work) -{ - struct hdac_hdmi_pin *pin = - container_of(to_delayed_work(work), struct hdac_hdmi_pin, work); - - /* picked from legacy HDA driver */ - if (pin->repoll_count++ > 6) - pin->repoll_count = 0; - - hdac_hdmi_present_sense(pin, pin->repoll_count); }
static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) @@ -1190,7 +1102,6 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
pin->edev = edev; mutex_init(&pin->lock); - INIT_DELAYED_WORK(&pin->work, hdac_hdmi_repoll_eld);
return 0; } @@ -1401,7 +1312,7 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
list_for_each_entry(pin, &hdmi->pin_list, head) { if (pin->nid == pin_nid) - hdac_hdmi_present_sense(pin, 1); + hdac_hdmi_present_sense(pin); } }
@@ -1502,7 +1413,7 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec) }
list_for_each_entry(pin, &hdmi->pin_list, head) - hdac_hdmi_present_sense(pin, 1); + hdac_hdmi_present_sense(pin);
/* Imp: Store the card pointer in hda_codec */ edev->card = dapm->card->snd_card; @@ -1567,7 +1478,7 @@ static void hdmi_codec_complete(struct device *dev) * all pins here. */ list_for_each_entry(pin, &hdmi->pin_list, head) - hdac_hdmi_present_sense(pin, 1); + hdac_hdmi_present_sense(pin);
pm_runtime_put_sync(&edev->hdac.dev); }
The patch
ASoC: hdac_hdmi: use audio component framework to read ELD
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 f6fa11a35c548a516a41ce1669d0dbcdaabb267f Mon Sep 17 00:00:00 2001
From: Sandeep Tayal sandeepx.tayal@intel.com Date: Wed, 18 Jan 2017 21:34:41 +0530 Subject: [PATCH] ASoC: hdac_hdmi: use audio component framework to read ELD
With codec read sometimes the pin_sense shows invalid monitor present and eld_valid. Currently driver polls for few times to get the valid eld data.
To avoid the latency, Instead of reading ELD from codec, read it directly from the display driver using audio component framework. and removed the unused direct codec helper functions.
Signed-off-by: Sandeep Tayal sandeepx.tayal@intel.com Signed-off-by: Jeeja KP jeeja.kp@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/codecs/hdac_hdmi.c | 201 ++++++++++++------------------------------- 1 file changed, 56 insertions(+), 145 deletions(-)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 1da4405ee435..261c31890827 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -46,6 +46,10 @@ #define ELD_MAX_SIZE 256 #define ELD_FIXED_BYTES 20
+#define ELD_VER_CEA_861D 2 +#define ELD_VER_PARTIAL 31 +#define ELD_MAX_MNL 16 + struct hdac_hdmi_cvt_params { unsigned int channels_min; unsigned int channels_max; @@ -81,8 +85,6 @@ struct hdac_hdmi_pin { hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; struct hdac_hdmi_eld eld; struct hdac_ext_device *edev; - int repoll_count; - struct delayed_work work; struct mutex lock; bool chmap_set; unsigned char chmap[8]; /* ALSA API channel-map */ @@ -179,80 +181,6 @@ static int hdac_hdmi_eld_limit_formats(struct snd_pcm_runtime *runtime,
}
- /* HDMI ELD routines */ -static unsigned int hdac_hdmi_get_eld_data(struct hdac_device *codec, - hda_nid_t nid, int byte_index) -{ - unsigned int val; - - val = snd_hdac_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_ELDD, - byte_index); - - dev_dbg(&codec->dev, "HDMI: ELD data byte %d: 0x%x\n", - byte_index, val); - - return val; -} - -static int hdac_hdmi_get_eld_size(struct hdac_device *codec, hda_nid_t nid) -{ - return snd_hdac_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, - AC_DIPSIZE_ELD_BUF); -} - -/* - * This function queries the ELD size and ELD data and fills in the buffer - * passed by user - */ -static int hdac_hdmi_get_eld(struct hdac_device *codec, hda_nid_t nid, - unsigned char *buf, int *eld_size) -{ - int i, size, ret = 0; - - /* - * ELD size is initialized to zero in caller function. If no errors and - * ELD is valid, actual eld_size is assigned. - */ - - size = hdac_hdmi_get_eld_size(codec, nid); - if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) { - dev_err(&codec->dev, "HDMI: invalid ELD buf size %d\n", size); - return -ERANGE; - } - - /* set ELD buffer */ - for (i = 0; i < size; i++) { - unsigned int val = hdac_hdmi_get_eld_data(codec, nid, i); - /* - * Graphics driver might be writing to ELD buffer right now. - * Just abort. The caller will repoll after a while. - */ - if (!(val & AC_ELDD_ELD_VALID)) { - dev_err(&codec->dev, - "HDMI: invalid ELD data byte %d\n", i); - ret = -EINVAL; - goto error; - } - val &= AC_ELDD_ELD_DATA; - /* - * The first byte cannot be zero. This can happen on some DVI - * connections. Some Intel chips may also need some 250ms delay - * to return non-zero ELD data, even when the graphics driver - * correctly writes ELD content before setting ELD_valid bit. - */ - if (!val && !i) { - dev_err(&codec->dev, "HDMI: 0 ELD data\n"); - ret = -EINVAL; - goto error; - } - buf[i] = val; - } - - *eld_size = size; -error: - return ret; -} - static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac, hda_nid_t cvt_nid, hda_nid_t pin_nid, u32 stream_tag, int format) @@ -1056,32 +984,59 @@ static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid) return hdac_hdmi_query_cvt_params(&edev->hdac, cvt); }
-static void hdac_hdmi_parse_eld(struct hdac_ext_device *edev, +static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev, struct hdac_hdmi_pin *pin) { + unsigned int ver, mnl; + + ver = (pin->eld.eld_buffer[DRM_ELD_VER] & DRM_ELD_VER_MASK) + >> DRM_ELD_VER_SHIFT; + + if (ver != ELD_VER_CEA_861D && ver != ELD_VER_PARTIAL) { + dev_err(&edev->hdac.dev, "HDMI: Unknown ELD version %d\n", ver); + return -EINVAL; + } + + mnl = (pin->eld.eld_buffer[DRM_ELD_CEA_EDID_VER_MNL] & + DRM_ELD_MNL_MASK) >> DRM_ELD_MNL_SHIFT; + + if (mnl > ELD_MAX_MNL) { + dev_err(&edev->hdac.dev, "HDMI: MNL Invalid %d\n", mnl); + return -EINVAL; + } + pin->eld.info.spk_alloc = pin->eld.eld_buffer[DRM_ELD_SPEAKER]; + + return 0; }
-static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll) +static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin) { struct hdac_ext_device *edev = pin->edev; struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm; - int val; - - pin->repoll_count = repoll; + int size;
- pm_runtime_get_sync(&edev->hdac.dev); - val = snd_hdac_codec_read(&edev->hdac, pin->nid, 0, - AC_VERB_GET_PIN_SENSE, 0); + mutex_lock(&hdmi->pin_mutex); + pin->eld.monitor_present = false;
- dev_dbg(&edev->hdac.dev, "Pin sense val %x for pin: %d\n", - val, pin->nid); + size = snd_hdac_acomp_get_eld(&edev->hdac, pin->nid, -1, + &pin->eld.monitor_present, pin->eld.eld_buffer, + ELD_MAX_SIZE);
+ if (size > 0) { + size = min(size, ELD_MAX_SIZE); + if (hdac_hdmi_parse_eld(edev, pin) < 0) + size = -EINVAL; + }
- mutex_lock(&hdmi->pin_mutex); - pin->eld.monitor_present = !!(val & AC_PINSENSE_PRESENCE); - pin->eld.eld_valid = !!(val & AC_PINSENSE_ELDV); + if (size > 0) { + pin->eld.eld_valid = true; + pin->eld.eld_size = size; + } else { + pin->eld.eld_valid = false; + pin->eld.eld_size = 0; + }
pcm = hdac_hdmi_get_pcm(edev, pin);
@@ -1103,66 +1058,23 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll) }
mutex_unlock(&hdmi->pin_mutex); - goto put_hdac_device; + return; }
if (pin->eld.monitor_present && pin->eld.eld_valid) { - /* TODO: use i915 component for reading ELD later */ - if (hdac_hdmi_get_eld(&edev->hdac, pin->nid, - pin->eld.eld_buffer, - &pin->eld.eld_size) == 0) { - - if (pcm) { - dev_dbg(&edev->hdac.dev, - "jack report for pcm=%d\n", - pcm->pcm_id); - - snd_jack_report(pcm->jack, SND_JACK_AVOUT); - } - hdac_hdmi_parse_eld(edev, pin); - - print_hex_dump_debug("ELD: ", - DUMP_PREFIX_OFFSET, 16, 1, - pin->eld.eld_buffer, pin->eld.eld_size, - true); - } else { - pin->eld.monitor_present = false; - pin->eld.eld_valid = false; - - if (pcm) { - dev_dbg(&edev->hdac.dev, - "jack report for pcm=%d\n", - pcm->pcm_id); + if (pcm) { + dev_dbg(&edev->hdac.dev, + "jack report for pcm=%d\n", + pcm->pcm_id);
- snd_jack_report(pcm->jack, 0); - } + snd_jack_report(pcm->jack, SND_JACK_AVOUT); } + + print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1, + pin->eld.eld_buffer, pin->eld.eld_size, false); }
mutex_unlock(&hdmi->pin_mutex); - - /* - * Sometimes the pin_sense may present invalid monitor - * present and eld_valid. If ELD data is not valid, loop few - * more times to get correct pin sense and valid ELD. - */ - if ((!pin->eld.monitor_present || !pin->eld.eld_valid) && repoll) - schedule_delayed_work(&pin->work, msecs_to_jiffies(300)); - -put_hdac_device: - pm_runtime_put_sync(&edev->hdac.dev); -} - -static void hdac_hdmi_repoll_eld(struct work_struct *work) -{ - struct hdac_hdmi_pin *pin = - container_of(to_delayed_work(work), struct hdac_hdmi_pin, work); - - /* picked from legacy HDA driver */ - if (pin->repoll_count++ > 6) - pin->repoll_count = 0; - - hdac_hdmi_present_sense(pin, pin->repoll_count); }
static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) @@ -1181,7 +1093,6 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
pin->edev = edev; mutex_init(&pin->lock); - INIT_DELAYED_WORK(&pin->work, hdac_hdmi_repoll_eld);
return 0; } @@ -1392,7 +1303,7 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port)
list_for_each_entry(pin, &hdmi->pin_list, head) { if (pin->nid == pin_nid) - hdac_hdmi_present_sense(pin, 1); + hdac_hdmi_present_sense(pin); } }
@@ -1493,7 +1404,7 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec) }
list_for_each_entry(pin, &hdmi->pin_list, head) - hdac_hdmi_present_sense(pin, 1); + hdac_hdmi_present_sense(pin);
/* Imp: Store the card pointer in hda_codec */ edev->card = dapm->card->snd_card; @@ -1558,7 +1469,7 @@ static void hdmi_codec_complete(struct device *dev) * all pins here. */ list_for_each_entry(pin, &hdmi->pin_list, head) - hdac_hdmi_present_sense(pin, 1); + hdac_hdmi_present_sense(pin);
pm_runtime_put_sync(&edev->hdac.dev); }
From: Jeeja KP jeeja.kp@intel.com
In case of hdmi connect/disconnect or when stream need to be route to multiple monitors, corresponding port and audio infoframe needs to be reconfigured. Currently all the configuration are done in DAI ops which results in silence playback.
So use dapm widget event handlers to program audio infoframe and enable /disable port configuration when widget is power on/off.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/codecs/hdac_hdmi.c | 359 ++++++++++++++++++++++--------------------- 1 file changed, 183 insertions(+), 176 deletions(-)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 548474d..c0b49f4 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -97,6 +97,9 @@ struct hdac_hdmi_pcm { struct hdac_hdmi_pin *pin; struct hdac_hdmi_cvt *cvt; struct snd_jack *jack; + int stream_tag; + int channels; + int format; };
struct hdac_hdmi_dai_pin_map { @@ -116,11 +119,19 @@ struct hdac_hdmi_priv { struct hdac_chmap chmap; };
-static void hdac_hdmi_enable_cvt(struct hdac_ext_device *edev, - struct hdac_hdmi_dai_pin_map *dai_map); +static struct hdac_hdmi_pcm * +hdac_hdmi_get_pcm_from_cvt(struct hdac_hdmi_priv *hdmi, + struct hdac_hdmi_cvt *cvt) +{ + struct hdac_hdmi_pcm *pcm = NULL;
-static int hdac_hdmi_enable_pin(struct hdac_ext_device *hdac, - struct hdac_hdmi_dai_pin_map *dai_map); + list_for_each_entry(pcm, &hdmi->pcm_list, head) { + if (pcm->cvt == cvt) + break; + } + + return pcm; +}
static struct hdac_hdmi_pcm *get_hdmi_pcm_from_id(struct hdac_hdmi_priv *hdmi, int pcm_idx) @@ -181,25 +192,6 @@ static int hdac_hdmi_eld_limit_formats(struct snd_pcm_runtime *runtime,
}
-static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac, - hda_nid_t cvt_nid, hda_nid_t pin_nid, - u32 stream_tag, int format) -{ - unsigned int val; - - dev_dbg(&hdac->hdac.dev, "cvt nid %d pnid %d stream %d format 0x%x\n", - cvt_nid, pin_nid, stream_tag, format); - - val = (stream_tag << 4); - - snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0, - AC_VERB_SET_CHANNEL_STREAMID, val); - snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0, - AC_VERB_SET_STREAM_FORMAT, format); - - return 0; -} - static void hdac_hdmi_set_dip_index(struct hdac_ext_device *hdac, hda_nid_t pin_nid, int packet_index, int byte_index) @@ -312,54 +304,25 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, return 0; }
-static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev, - struct hdac_hdmi_dai_pin_map *dai_map, unsigned int pwr_state) -{ - /* Power up pin widget */ - if (!snd_hdac_check_power_state(&edev->hdac, dai_map->pin->nid, - pwr_state)) - snd_hdac_codec_write(&edev->hdac, dai_map->pin->nid, 0, - AC_VERB_SET_POWER_STATE, pwr_state); - - /* Power up converter */ - if (!snd_hdac_check_power_state(&edev->hdac, dai_map->cvt->nid, - pwr_state)) - snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0, - AC_VERB_SET_POWER_STATE, pwr_state); -} - -static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int hdac_hdmi_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) { - struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); - struct hdac_hdmi_priv *hdmi = hdac->private_data; + struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai); + struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_dai_pin_map *dai_map; - struct hdac_hdmi_pin *pin; - struct hdac_ext_dma_params *dd; - int ret; + struct hdac_hdmi_pcm *pcm;
- dai_map = &hdmi->dai_map[dai->id]; - pin = dai_map->pin; + dev_dbg(&edev->hdac.dev, "%s: strm_tag: %d\n", __func__, tx_mask);
- dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream); - dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n", - dd->stream_tag, dd->format); + dai_map = &hdmi->dai_map[dai->id];
- hdac_hdmi_enable_cvt(hdac, dai_map); - ret = hdac_hdmi_enable_pin(hdac, dai_map); - if (ret < 0) - return ret; - mutex_lock(&pin->lock); - pin->channels = substream->runtime->channels; + pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt);
- ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid, - dai_map->pin->nid); - mutex_unlock(&pin->lock); - if (ret < 0) - return ret; + if (pcm) + pcm->stream_tag = (tx_mask << 4);
- return hdac_hdmi_setup_stream(hdac, dai_map->cvt->nid, - dai_map->pin->nid, dd->stream_tag, dd->format); + return 0; }
static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, @@ -369,7 +332,8 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, struct hdac_hdmi_priv *hdmi = hdac->private_data; struct hdac_hdmi_dai_pin_map *dai_map; struct hdac_hdmi_pin *pin; - struct hdac_ext_dma_params *dd; + struct hdac_hdmi_pcm *pcm; + int format;
dai_map = &hdmi->dai_map[dai->id]; pin = dai_map->pin; @@ -383,79 +347,16 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, return -ENODEV; }
- dd = snd_soc_dai_get_dma_data(dai, substream); - if (!dd) { - dd = kzalloc(sizeof(*dd), GFP_KERNEL); - if (!dd) - return -ENOMEM; - } - - dd->format = snd_hdac_calc_stream_format(params_rate(hparams), + format = snd_hdac_calc_stream_format(params_rate(hparams), params_channels(hparams), params_format(hparams), 24, 0);
- snd_soc_dai_set_dma_data(dai, substream, (void *)dd); - - return 0; -} - -static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai); - struct hdac_ext_dma_params *dd; - struct hdac_hdmi_priv *hdmi = edev->private_data; - struct hdac_hdmi_dai_pin_map *dai_map; - - dai_map = &hdmi->dai_map[dai->id]; - - dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream); - - if (dd) { - snd_soc_dai_set_dma_data(dai, substream, NULL); - kfree(dd); - } - - return 0; -} - -static void hdac_hdmi_enable_cvt(struct hdac_ext_device *edev, - struct hdac_hdmi_dai_pin_map *dai_map) -{ - /* Enable transmission */ - snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0, - AC_VERB_SET_DIGI_CONVERT_1, 1); - - /* Category Code (CC) to zero */ - snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0, - AC_VERB_SET_DIGI_CONVERT_2, 0); -} - -static int hdac_hdmi_enable_pin(struct hdac_ext_device *hdac, - struct hdac_hdmi_dai_pin_map *dai_map) -{ - int mux_idx; - struct hdac_hdmi_pin *pin = dai_map->pin; - - for (mux_idx = 0; mux_idx < pin->num_mux_nids; mux_idx++) { - if (pin->mux_nids[mux_idx] == dai_map->cvt->nid) { - snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, - AC_VERB_SET_CONNECT_SEL, mux_idx); - break; - } - } - - if (mux_idx == pin->num_mux_nids) + pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt); + if (!pcm) return -EIO;
- /* Enable out path for this pin widget */ - snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - - hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0); - - snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); + pcm->format = format; + pcm->channels = params_channels(hparams);
return 0; } @@ -569,27 +470,6 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, pin->eld.eld_buffer); }
-static int hdac_hdmi_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -{ - struct hdac_hdmi_dai_pin_map *dai_map; - struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); - struct hdac_hdmi_priv *hdmi = hdac->private_data; - - dai_map = &hdmi->dai_map[dai->id]; - switch (cmd) { - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - return hdac_hdmi_playback_prepare(substream, dai); - - default: - return 0; - } - - return 0; -} - static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -600,16 +480,6 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, dai_map = &hdmi->dai_map[dai->id];
if (dai_map->pin) { - snd_hdac_codec_write(&hdac->hdac, dai_map->cvt->nid, 0, - AC_VERB_SET_CHANNEL_STREAMID, 0); - snd_hdac_codec_write(&hdac->hdac, dai_map->cvt->nid, 0, - AC_VERB_SET_STREAM_FORMAT, 0); - - hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3); - - snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - mutex_lock(&dai_map->pin->lock); dai_map->pin->chmap_set = false; memset(dai_map->pin->chmap, 0, sizeof(dai_map->pin->chmap)); @@ -650,10 +520,11 @@ hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt) }
static int hdac_hdmi_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) + 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); @@ -666,6 +537,8 @@ static int hdac_hdmi_fill_widget_info(struct device *dev, w->kcontrol_news = wc; w->num_kcontrols = numkc; w->priv = priv; + w->event = event; + w->event_flags = event_flags;
return 0; } @@ -695,6 +568,136 @@ static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev, return NULL; }
+static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev, + hda_nid_t nid, unsigned int pwr_state) +{ + if (get_wcaps(&edev->hdac, nid) & AC_WCAP_POWER) { + if (!snd_hdac_check_power_state(&edev->hdac, nid, pwr_state)) + snd_hdac_codec_write(&edev->hdac, nid, 0, + AC_VERB_SET_POWER_STATE, pwr_state); + } +} + +static void hdac_hdmi_set_amp(struct hdac_ext_device *edev, + hda_nid_t nid, int val) +{ + if (get_wcaps(&edev->hdac, nid) & AC_WCAP_OUT_AMP) + snd_hdac_codec_write(&edev->hdac, nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, val); +} + + +static int hdac_hdmi_pin_output_widget_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct hdac_hdmi_pin *pin = w->priv; + struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev); + struct hdac_hdmi_pcm *pcm; + + dev_dbg(&edev->hdac.dev, "%s: widget: %s event: %x\n", + __func__, w->name, event); + + pcm = hdac_hdmi_get_pcm(edev, pin); + if (!pcm) + return -EIO; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + hdac_hdmi_set_power_state(edev, pin->nid, AC_PWRST_D0); + + /* Enable out path for this pin widget */ + snd_hdac_codec_write(&edev->hdac, pin->nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + + hdac_hdmi_set_amp(edev, pin->nid, AMP_OUT_UNMUTE); + + return hdac_hdmi_setup_audio_infoframe(edev, pcm->cvt->nid, + pin->nid); + + case SND_SOC_DAPM_POST_PMD: + hdac_hdmi_set_amp(edev, pin->nid, AMP_OUT_MUTE); + + /* Disable out path for this pin widget */ + snd_hdac_codec_write(&edev->hdac, pin->nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0); + + hdac_hdmi_set_power_state(edev, pin->nid, AC_PWRST_D3); + break; + + } + + return 0; +} + +static int hdac_hdmi_cvt_output_widget_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct hdac_hdmi_cvt *cvt = w->priv; + struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev); + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_pcm *pcm; + + dev_dbg(&edev->hdac.dev, "%s: widget: %s event: %x\n", + __func__, w->name, event); + + pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, cvt); + if (!pcm) + return -EIO; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + hdac_hdmi_set_power_state(edev, cvt->nid, AC_PWRST_D0); + + /* Enable transmission */ + snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, + AC_VERB_SET_DIGI_CONVERT_1, 1); + + /* Category Code (CC) to zero */ + snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, + AC_VERB_SET_DIGI_CONVERT_2, 0); + + snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, + AC_VERB_SET_CHANNEL_STREAMID, pcm->stream_tag); + snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, + AC_VERB_SET_STREAM_FORMAT, pcm->format); + break; + + case SND_SOC_DAPM_POST_PMD: + snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, + AC_VERB_SET_CHANNEL_STREAMID, 0); + snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, + AC_VERB_SET_STREAM_FORMAT, 0); + + hdac_hdmi_set_power_state(edev, cvt->nid, AC_PWRST_D3); + break; + + } + + return 0; +} + +static int hdac_hdmi_pin_mux_widget_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct hdac_hdmi_pin *pin = w->priv; + struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev); + int mux_idx; + + dev_dbg(&edev->hdac.dev, "%s: widget: %s event: %x\n", + __func__, w->name, event); + + if (!kc) + kc = w->kcontrols[0]; + + mux_idx = dapm_kcontrol_get_value(kc); + if (mux_idx > 0) { + snd_hdac_codec_write(&edev->hdac, pin->nid, 0, + AC_VERB_SET_CONNECT_SEL, (mux_idx - 1)); + } + + return 0; +} + /* * Based on user selection, map the PINs with the PCMs. */ @@ -812,7 +815,9 @@ static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev, return -ENOMEM;
return hdac_hdmi_fill_widget_info(&edev->hdac.dev, widget, - snd_soc_dapm_mux, pin, widget_name, NULL, kc, 1); + snd_soc_dapm_mux, pin, widget_name, NULL, kc, 1, + hdac_hdmi_pin_mux_widget_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_REG); }
/* Add cvt <- input <- mux route map */ @@ -883,8 +888,10 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) list_for_each_entry(cvt, &hdmi->cvt_list, head) { sprintf(widget_name, "Converter %d", cvt->nid); ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i], - snd_soc_dapm_aif_in, &cvt->nid, - widget_name, dai_drv[i].playback.stream_name, NULL, 0); + snd_soc_dapm_aif_in, cvt, + widget_name, dai_drv[i].playback.stream_name, NULL, 0, + hdac_hdmi_cvt_output_widget_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD); if (ret < 0) return ret; i++; @@ -893,8 +900,10 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) list_for_each_entry(pin, &hdmi->pin_list, head) { sprintf(widget_name, "hif%d Output", pin->nid); ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i], - snd_soc_dapm_output, &pin->nid, - widget_name, NULL, NULL, 0); + snd_soc_dapm_output, pin, + widget_name, NULL, NULL, 0, + hdac_hdmi_pin_output_widget_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD); if (ret < 0) return ret; i++; @@ -1150,9 +1159,7 @@ static struct snd_soc_dai_ops hdmi_dai_ops = { .startup = hdac_hdmi_pcm_open, .shutdown = hdac_hdmi_pcm_close, .hw_params = hdac_hdmi_set_hw_params, - .prepare = hdac_hdmi_playback_prepare, - .trigger = hdac_hdmi_trigger, - .hw_free = hdac_hdmi_playback_cleanup, + .set_tdm_slot = hdac_hdmi_set_tdm_slot, };
/*
From: Jeeja KP jeeja.kp@intel.com
DMA channel(stream tag) used by the HDA link need to programmed in codec so that codec receives packet from the link associated with the same channel.
DMA channel is allocated in link BE dai hw_params, the same needs to be set for the BE codec dai. Instead of using get/set dma_data(), use dai_ops snd_soc_dai_set_tdm_slot() to set the stream tag.
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/intel/skylake/skl-pcm.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 508144b..b0817a12 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -542,10 +542,10 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); struct hdac_ext_stream *link_dev; struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - struct hdac_ext_dma_params *dma_params; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct skl_pipe_params p_params = {0}; struct hdac_ext_link *link; + int stream_tag;
link_dev = snd_hdac_ext_stream_assign(ebus, substream, HDAC_EXT_STREAM_TYPE_LINK); @@ -558,16 +558,16 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, if (!link) return -EINVAL;
+ stream_tag = hdac_stream(link_dev)->stream_tag; + /* set the stream tag in the codec dai dma params */ - dma_params = snd_soc_dai_get_dma_data(codec_dai, substream); - if (dma_params) - dma_params->stream_tag = hdac_stream(link_dev)->stream_tag; + snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0);
p_params.s_fmt = snd_pcm_format_width(params_format(params)); p_params.ch = params_channels(params); p_params.s_freq = params_rate(params); p_params.stream = substream->stream; - p_params.link_dma_id = hdac_stream(link_dev)->stream_tag - 1; + p_params.link_dma_id = stream_tag - 1; p_params.link_index = link->index; p_params.format = params_format(params);
The patch
ASoC: Intel: Skylake: Use set_tdm_slot to set the dma channel
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 1011509dfd25f90db333f82fa85c39b0861d2b09 Mon Sep 17 00:00:00 2001
From: Jeeja KP jeeja.kp@intel.com Date: Tue, 24 Jan 2017 21:49:04 +0530 Subject: [PATCH] ASoC: Intel: Skylake: Use set_tdm_slot to set the dma channel
DMA channel(stream tag) used by the HDA link need to programmed in codec so that codec receives packet from the link associated with the same channel.
DMA channel is allocated in link BE dai hw_params, the same needs to be set for the BE codec dai. Instead of using get/set dma_data(), use dai_ops snd_soc_dai_set_tdm_slot() to set the stream tag.
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Jeeja KP jeeja.kp@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/skylake/skl-pcm.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index ae7997ab19b1..55dc9f27d4b2 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -532,10 +532,10 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); struct hdac_ext_stream *link_dev; struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - struct hdac_ext_dma_params *dma_params; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct skl_pipe_params p_params = {0}; struct hdac_ext_link *link; + int stream_tag;
link_dev = snd_hdac_ext_stream_assign(ebus, substream, HDAC_EXT_STREAM_TYPE_LINK); @@ -548,16 +548,16 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, if (!link) return -EINVAL;
+ stream_tag = hdac_stream(link_dev)->stream_tag; + /* set the stream tag in the codec dai dma params */ - dma_params = snd_soc_dai_get_dma_data(codec_dai, substream); - if (dma_params) - dma_params->stream_tag = hdac_stream(link_dev)->stream_tag; + snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0);
p_params.s_fmt = snd_pcm_format_width(params_format(params)); p_params.ch = params_channels(params); p_params.s_freq = params_rate(params); p_params.stream = substream->stream; - p_params.link_dma_id = hdac_stream(link_dev)->stream_tag - 1; + p_params.link_dma_id = stream_tag - 1; p_params.link_index = link->index; p_params.format = params_format(params);
From: Jeeja KP jeeja.kp@intel.com
Channel info is part of the pcm parameter and channel map control is created for each pcm. So move channel info to pcm instead of pin structure and the mutex lock to pcm.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/codecs/hdac_hdmi.c | 76 ++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 42 deletions(-)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index c0b49f4..2a370d6 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -85,10 +85,6 @@ struct hdac_hdmi_pin { hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; struct hdac_hdmi_eld eld; struct hdac_ext_device *edev; - struct mutex lock; - bool chmap_set; - unsigned char chmap[8]; /* ALSA API channel-map */ - int channels; /* current number of channels */ };
struct hdac_hdmi_pcm { @@ -100,6 +96,9 @@ struct hdac_hdmi_pcm { int stream_tag; int channels; int format; + bool chmap_set; + unsigned char chmap[8]; /* ALSA API channel-map */ + struct mutex lock; };
struct hdac_hdmi_dai_pin_map { @@ -217,13 +216,13 @@ struct dp_audio_infoframe { };
static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, - hda_nid_t cvt_nid, hda_nid_t pin_nid) + struct hdac_hdmi_pcm *pcm, struct hdac_hdmi_pin *pin) { uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE]; struct hdmi_audio_infoframe frame; struct dp_audio_infoframe dp_ai; struct hdac_hdmi_priv *hdmi = hdac->private_data; - struct hdac_hdmi_pin *pin; + struct hdac_hdmi_cvt *cvt = pcm->cvt; u8 *dip; int ret; int i; @@ -231,19 +230,14 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, u8 conn_type; int channels, ca;
- list_for_each_entry(pin, &hdmi->pin_list, head) { - if (pin->nid == pin_nid) - break; - } - ca = snd_hdac_channel_allocation(&hdac->hdac, pin->eld.info.spk_alloc, - pin->channels, pin->chmap_set, true, pin->chmap); + pcm->channels, pcm->chmap_set, true, pcm->chmap);
channels = snd_hdac_get_active_channels(ca); - hdmi->chmap.ops.set_channel_count(&hdac->hdac, cvt_nid, channels); + hdmi->chmap.ops.set_channel_count(&hdac->hdac, cvt->nid, channels);
snd_hdac_setup_channel_mapping(&hdmi->chmap, pin->nid, false, ca, - pin->channels, pin->chmap, pin->chmap_set); + pcm->channels, pcm->chmap, pcm->chmap_set);
eld_buf = pin->eld.eld_buffer; conn_type = drm_eld_get_conn_type(eld_buf); @@ -279,26 +273,26 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, }
/* stop infoframe transmission */ - hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); - snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, + hdac_hdmi_set_dip_index(hdac, pin->nid, 0x0, 0x0); + snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE);
/* Fill infoframe. Index auto-incremented */ - hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); + hdac_hdmi_set_dip_index(hdac, pin->nid, 0x0, 0x0); if (conn_type == DRM_ELD_CONN_TYPE_HDMI) { for (i = 0; i < sizeof(buffer); i++) - snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, + snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, AC_VERB_SET_HDMI_DIP_DATA, buffer[i]); } else { for (i = 0; i < sizeof(dp_ai); i++) - snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, + snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, AC_VERB_SET_HDMI_DIP_DATA, dip[i]); }
/* Start infoframe */ - hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); - snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, + hdac_hdmi_set_dip_index(hdac, pin->nid, 0x0, 0x0); + snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST);
return 0; @@ -476,18 +470,22 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); struct hdac_hdmi_priv *hdmi = hdac->private_data; struct hdac_hdmi_dai_pin_map *dai_map; + struct hdac_hdmi_pcm *pcm;
dai_map = &hdmi->dai_map[dai->id];
- if (dai_map->pin) { - mutex_lock(&dai_map->pin->lock); - dai_map->pin->chmap_set = false; - memset(dai_map->pin->chmap, 0, sizeof(dai_map->pin->chmap)); - dai_map->pin->channels = 0; - mutex_unlock(&dai_map->pin->lock); + pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt);
- dai_map->pin = NULL; + if (pcm) { + mutex_lock(&pcm->lock); + pcm->chmap_set = false; + memset(pcm->chmap, 0, sizeof(pcm->chmap)); + pcm->channels = 0; + mutex_unlock(&pcm->lock); } + + if (dai_map->pin) + dai_map->pin = NULL; }
static int @@ -611,8 +609,7 @@ static int hdac_hdmi_pin_output_widget_event(struct snd_soc_dapm_widget *w,
hdac_hdmi_set_amp(edev, pin->nid, AMP_OUT_UNMUTE);
- return hdac_hdmi_setup_audio_infoframe(edev, pcm->cvt->nid, - pin->nid); + return hdac_hdmi_setup_audio_infoframe(edev, pcm, pin);
case SND_SOC_DAPM_POST_PMD: hdac_hdmi_set_amp(edev, pin->nid, AMP_OUT_MUTE); @@ -1110,7 +1107,6 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) hdmi->num_pin++;
pin->edev = edev; - mutex_init(&pin->lock);
return 0; } @@ -1361,6 +1357,7 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) return -ENOMEM; pcm->pcm_id = device; pcm->cvt = hdmi->dai_map[dai->id].cvt; + mutex_init(&pcm->lock);
snd_pcm = hdac_hdmi_get_pcm_from_id(dai->component->card, device); if (snd_pcm) { @@ -1506,13 +1503,8 @@ static void hdac_hdmi_get_chmap(struct hdac_device *hdac, int pcm_idx, struct hdac_ext_device *edev = to_ehdac_device(hdac); struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); - struct hdac_hdmi_pin *pin = pcm->pin; - - /* chmap is already set to 0 in caller */ - if (!pin) - return;
- memcpy(chmap, pin->chmap, ARRAY_SIZE(pin->chmap)); + memcpy(chmap, pcm->chmap, ARRAY_SIZE(pcm->chmap)); }
static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx, @@ -1523,12 +1515,12 @@ static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx, struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); struct hdac_hdmi_pin *pin = pcm->pin;
- mutex_lock(&pin->lock); - pin->chmap_set = true; - memcpy(pin->chmap, chmap, ARRAY_SIZE(pin->chmap)); + mutex_lock(&pcm->lock); + pcm->chmap_set = true; + memcpy(pcm->chmap, chmap, ARRAY_SIZE(pcm->chmap)); if (prepared) - hdac_hdmi_setup_audio_infoframe(edev, pcm->cvt->nid, pin->nid); - mutex_unlock(&pin->lock); + hdac_hdmi_setup_audio_infoframe(edev, pcm, pin); + mutex_unlock(&pcm->lock); }
static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx)
The patch
ASoC: hdac_hdmi: Move channel info from pin to PCM structure
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 ab1eea19d0223481fab7345072825d00ce98c339 Mon Sep 17 00:00:00 2001
From: Jeeja KP jeeja.kp@intel.com Date: Tue, 24 Jan 2017 21:49:05 +0530 Subject: [PATCH] ASoC: hdac_hdmi: Move channel info from pin to PCM structure
Channel info is part of the pcm parameter and channel map control is created for each pcm. So move channel info to pcm instead of pin structure and the mutex lock to pcm.
Signed-off-by: Jeeja KP jeeja.kp@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/codecs/hdac_hdmi.c | 76 ++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 42 deletions(-)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index c0b49f4b7074..2a370d694f6d 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -85,10 +85,6 @@ struct hdac_hdmi_pin { hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; struct hdac_hdmi_eld eld; struct hdac_ext_device *edev; - struct mutex lock; - bool chmap_set; - unsigned char chmap[8]; /* ALSA API channel-map */ - int channels; /* current number of channels */ };
struct hdac_hdmi_pcm { @@ -100,6 +96,9 @@ struct hdac_hdmi_pcm { int stream_tag; int channels; int format; + bool chmap_set; + unsigned char chmap[8]; /* ALSA API channel-map */ + struct mutex lock; };
struct hdac_hdmi_dai_pin_map { @@ -217,13 +216,13 @@ struct dp_audio_infoframe { };
static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, - hda_nid_t cvt_nid, hda_nid_t pin_nid) + struct hdac_hdmi_pcm *pcm, struct hdac_hdmi_pin *pin) { uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE]; struct hdmi_audio_infoframe frame; struct dp_audio_infoframe dp_ai; struct hdac_hdmi_priv *hdmi = hdac->private_data; - struct hdac_hdmi_pin *pin; + struct hdac_hdmi_cvt *cvt = pcm->cvt; u8 *dip; int ret; int i; @@ -231,19 +230,14 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, u8 conn_type; int channels, ca;
- list_for_each_entry(pin, &hdmi->pin_list, head) { - if (pin->nid == pin_nid) - break; - } - ca = snd_hdac_channel_allocation(&hdac->hdac, pin->eld.info.spk_alloc, - pin->channels, pin->chmap_set, true, pin->chmap); + pcm->channels, pcm->chmap_set, true, pcm->chmap);
channels = snd_hdac_get_active_channels(ca); - hdmi->chmap.ops.set_channel_count(&hdac->hdac, cvt_nid, channels); + hdmi->chmap.ops.set_channel_count(&hdac->hdac, cvt->nid, channels);
snd_hdac_setup_channel_mapping(&hdmi->chmap, pin->nid, false, ca, - pin->channels, pin->chmap, pin->chmap_set); + pcm->channels, pcm->chmap, pcm->chmap_set);
eld_buf = pin->eld.eld_buffer; conn_type = drm_eld_get_conn_type(eld_buf); @@ -279,26 +273,26 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, }
/* stop infoframe transmission */ - hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); - snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, + hdac_hdmi_set_dip_index(hdac, pin->nid, 0x0, 0x0); + snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE);
/* Fill infoframe. Index auto-incremented */ - hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); + hdac_hdmi_set_dip_index(hdac, pin->nid, 0x0, 0x0); if (conn_type == DRM_ELD_CONN_TYPE_HDMI) { for (i = 0; i < sizeof(buffer); i++) - snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, + snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, AC_VERB_SET_HDMI_DIP_DATA, buffer[i]); } else { for (i = 0; i < sizeof(dp_ai); i++) - snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, + snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, AC_VERB_SET_HDMI_DIP_DATA, dip[i]); }
/* Start infoframe */ - hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); - snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, + hdac_hdmi_set_dip_index(hdac, pin->nid, 0x0, 0x0); + snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST);
return 0; @@ -476,18 +470,22 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); struct hdac_hdmi_priv *hdmi = hdac->private_data; struct hdac_hdmi_dai_pin_map *dai_map; + struct hdac_hdmi_pcm *pcm;
dai_map = &hdmi->dai_map[dai->id];
- if (dai_map->pin) { - mutex_lock(&dai_map->pin->lock); - dai_map->pin->chmap_set = false; - memset(dai_map->pin->chmap, 0, sizeof(dai_map->pin->chmap)); - dai_map->pin->channels = 0; - mutex_unlock(&dai_map->pin->lock); + pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt);
- dai_map->pin = NULL; + if (pcm) { + mutex_lock(&pcm->lock); + pcm->chmap_set = false; + memset(pcm->chmap, 0, sizeof(pcm->chmap)); + pcm->channels = 0; + mutex_unlock(&pcm->lock); } + + if (dai_map->pin) + dai_map->pin = NULL; }
static int @@ -611,8 +609,7 @@ static int hdac_hdmi_pin_output_widget_event(struct snd_soc_dapm_widget *w,
hdac_hdmi_set_amp(edev, pin->nid, AMP_OUT_UNMUTE);
- return hdac_hdmi_setup_audio_infoframe(edev, pcm->cvt->nid, - pin->nid); + return hdac_hdmi_setup_audio_infoframe(edev, pcm, pin);
case SND_SOC_DAPM_POST_PMD: hdac_hdmi_set_amp(edev, pin->nid, AMP_OUT_MUTE); @@ -1110,7 +1107,6 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) hdmi->num_pin++;
pin->edev = edev; - mutex_init(&pin->lock);
return 0; } @@ -1361,6 +1357,7 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) return -ENOMEM; pcm->pcm_id = device; pcm->cvt = hdmi->dai_map[dai->id].cvt; + mutex_init(&pcm->lock);
snd_pcm = hdac_hdmi_get_pcm_from_id(dai->component->card, device); if (snd_pcm) { @@ -1506,13 +1503,8 @@ static void hdac_hdmi_get_chmap(struct hdac_device *hdac, int pcm_idx, struct hdac_ext_device *edev = to_ehdac_device(hdac); struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); - struct hdac_hdmi_pin *pin = pcm->pin; - - /* chmap is already set to 0 in caller */ - if (!pin) - return;
- memcpy(chmap, pin->chmap, ARRAY_SIZE(pin->chmap)); + memcpy(chmap, pcm->chmap, ARRAY_SIZE(pcm->chmap)); }
static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx, @@ -1523,12 +1515,12 @@ static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx, struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); struct hdac_hdmi_pin *pin = pcm->pin;
- mutex_lock(&pin->lock); - pin->chmap_set = true; - memcpy(pin->chmap, chmap, ARRAY_SIZE(pin->chmap)); + mutex_lock(&pcm->lock); + pcm->chmap_set = true; + memcpy(pcm->chmap, chmap, ARRAY_SIZE(pcm->chmap)); if (prepared) - hdac_hdmi_setup_audio_infoframe(edev, pcm->cvt->nid, pin->nid); - mutex_unlock(&pin->lock); + hdac_hdmi_setup_audio_infoframe(edev, pcm, pin); + mutex_unlock(&pcm->lock); }
static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx)
From: Jeeja KP jeeja.kp@intel.com
HDMI registers channel map controls per pcm. As PCMs are not registered during dai_link init callback, store the pcm ids and codec DAIs during this init callback.
Register for late probe and call the jack_init API which registers channel map in the late probe callback handler.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/intel/boards/bxt_rt298.c | 52 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-)
diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index 1309405..bc9ee09 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -26,8 +26,18 @@ #include "../../codecs/hdac_hdmi.h" #include "../../codecs/rt298.h"
-static struct snd_soc_jack broxton_headset; /* Headset jack detection DAPM pins */ +static struct snd_soc_jack broxton_headset; + +struct bxt_hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +struct bxt_rt286_private { + struct list_head hdmi_pcm_list; +};
enum { BXT_DPCM_AUDIO_PB = 0, @@ -139,9 +149,20 @@ static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd)
static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd) { + struct bxt_rt286_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *dai = rtd->codec_dai; + struct bxt_hdmi_pcm *pcm;
- return hdac_hdmi_jack_init(dai, BXT_DPCM_AUDIO_HDMI1_PB + dai->id); + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pcm->device = BXT_DPCM_AUDIO_HDMI1_PB + dai->id; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; }
static int broxton_ssp5_fixup(struct snd_soc_pcm_runtime *rtd, @@ -432,6 +453,22 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = { }, };
+static int bxt_card_late_probe(struct snd_soc_card *card) +{ + struct bxt_rt286_private *ctx = snd_soc_card_get_drvdata(card); + struct bxt_hdmi_pcm *pcm; + int err; + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device); + if (err < 0) + return err; + } + + return 0; +} + + /* broxton audio machine driver for SPT + RT298S */ static struct snd_soc_card broxton_rt298 = { .name = "broxton-rt298", @@ -445,11 +482,22 @@ static struct snd_soc_card broxton_rt298 = { .dapm_routes = broxton_rt298_map, .num_dapm_routes = ARRAY_SIZE(broxton_rt298_map), .fully_routed = true, + .late_probe = bxt_card_late_probe, + };
static int broxton_audio_probe(struct platform_device *pdev) { + struct bxt_rt286_private *ctx; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + if (!ctx) + return -ENOMEM; + + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + broxton_rt298.dev = &pdev->dev; + snd_soc_card_set_drvdata(&broxton_rt298, ctx);
return devm_snd_soc_register_card(&pdev->dev, &broxton_rt298); }
The patch
ASoC: Intel: bxt: add channel map support in rt298 machine
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 51e0f3c825f0f800479aa6fd2066587b425d1010 Mon Sep 17 00:00:00 2001
From: Jeeja KP jeeja.kp@intel.com Date: Tue, 24 Jan 2017 21:49:06 +0530 Subject: [PATCH] ASoC: Intel: bxt: add channel map support in rt298 machine
HDMI registers channel map controls per pcm. As PCMs are not registered during dai_link init callback, store the pcm ids and codec DAIs during this init callback.
Register for late probe and call the jack_init API which registers channel map in the late probe callback handler.
Signed-off-by: Jeeja KP jeeja.kp@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/boards/bxt_rt298.c | 52 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-)
diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index 1309405b3808..bc9ee0975073 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -26,8 +26,18 @@ #include "../../codecs/hdac_hdmi.h" #include "../../codecs/rt298.h"
-static struct snd_soc_jack broxton_headset; /* Headset jack detection DAPM pins */ +static struct snd_soc_jack broxton_headset; + +struct bxt_hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +struct bxt_rt286_private { + struct list_head hdmi_pcm_list; +};
enum { BXT_DPCM_AUDIO_PB = 0, @@ -139,9 +149,20 @@ static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd)
static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd) { + struct bxt_rt286_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *dai = rtd->codec_dai; + struct bxt_hdmi_pcm *pcm;
- return hdac_hdmi_jack_init(dai, BXT_DPCM_AUDIO_HDMI1_PB + dai->id); + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pcm->device = BXT_DPCM_AUDIO_HDMI1_PB + dai->id; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; }
static int broxton_ssp5_fixup(struct snd_soc_pcm_runtime *rtd, @@ -432,6 +453,22 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = { }, };
+static int bxt_card_late_probe(struct snd_soc_card *card) +{ + struct bxt_rt286_private *ctx = snd_soc_card_get_drvdata(card); + struct bxt_hdmi_pcm *pcm; + int err; + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device); + if (err < 0) + return err; + } + + return 0; +} + + /* broxton audio machine driver for SPT + RT298S */ static struct snd_soc_card broxton_rt298 = { .name = "broxton-rt298", @@ -445,11 +482,22 @@ static struct snd_soc_card broxton_rt298 = { .dapm_routes = broxton_rt298_map, .num_dapm_routes = ARRAY_SIZE(broxton_rt298_map), .fully_routed = true, + .late_probe = bxt_card_late_probe, + };
static int broxton_audio_probe(struct platform_device *pdev) { + struct bxt_rt286_private *ctx; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + if (!ctx) + return -ENOMEM; + + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + broxton_rt298.dev = &pdev->dev; + snd_soc_card_set_drvdata(&broxton_rt298, ctx);
return devm_snd_soc_register_card(&pdev->dev, &broxton_rt298); }
From: Jeeja KP jeeja.kp@intel.com
HDMI registers channel map controls per PCM. As PCMs are not registered during dai_link init callback, store the pcm ids and codec DAIs during this init callback.
Register for late probe and call the jack_init API which also registers channel map in the late probe callback handler.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 49 ++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-)
diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index f46da61..8dfe5e8 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -34,6 +34,16 @@
static struct snd_soc_jack broxton_headset;
+struct bxt_hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +struct bxt_card_private { + struct list_head hdmi_pcm_list; +}; + enum { BXT_DPCM_AUDIO_PB = 0, BXT_DPCM_AUDIO_CP, @@ -181,9 +191,20 @@ static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd) { + struct bxt_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *dai = rtd->codec_dai; + struct bxt_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM;
- return hdac_hdmi_jack_init(dai, BXT_DPCM_AUDIO_HDMI1_PB + dai->id); + pcm->device = BXT_DPCM_AUDIO_HDMI1_PB + dai->id; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; }
static int broxton_da7219_fe_init(struct snd_soc_pcm_runtime *rtd) @@ -531,6 +552,21 @@ static struct snd_soc_dai_link broxton_dais[] = { }, };
+static int bxt_card_late_probe(struct snd_soc_card *card) +{ + struct bxt_card_private *ctx = snd_soc_card_get_drvdata(card); + struct bxt_hdmi_pcm *pcm; + int err; + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device); + if (err < 0) + return err; + } + + return 0; +} + /* broxton audio machine driver for SPT + da7219 */ static struct snd_soc_card broxton_audio_card = { .name = "bxtda7219max", @@ -544,11 +580,22 @@ static struct snd_soc_card broxton_audio_card = { .dapm_routes = broxton_map, .num_dapm_routes = ARRAY_SIZE(broxton_map), .fully_routed = true, + .late_probe = bxt_card_late_probe, };
static int broxton_audio_probe(struct platform_device *pdev) { + struct bxt_card_private *ctx; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + if (!ctx) + return -ENOMEM; + + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + broxton_audio_card.dev = &pdev->dev; + snd_soc_card_set_drvdata(&broxton_audio_card, ctx); + return devm_snd_soc_register_card(&pdev->dev, &broxton_audio_card); }
The patch
ASoC: Intel: bxt: add channel map support in bxt_da7219_max98357a machine
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 ba2103467794645e43d8115bef6f4fd18a40b47b Mon Sep 17 00:00:00 2001
From: Jeeja KP jeeja.kp@intel.com Date: Tue, 24 Jan 2017 21:49:07 +0530 Subject: [PATCH] ASoC: Intel: bxt: add channel map support in bxt_da7219_max98357a machine
HDMI registers channel map controls per PCM. As PCMs are not registered during dai_link init callback, store the pcm ids and codec DAIs during this init callback.
Register for late probe and call the jack_init API which also registers channel map in the late probe callback handler.
Signed-off-by: Jeeja KP jeeja.kp@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 49 ++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-)
diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 876d82d4a39e..a9647a27ebc2 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -34,6 +34,16 @@
static struct snd_soc_jack broxton_headset;
+struct bxt_hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +struct bxt_card_private { + struct list_head hdmi_pcm_list; +}; + enum { BXT_DPCM_AUDIO_PB = 0, BXT_DPCM_AUDIO_CP, @@ -147,9 +157,20 @@ static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd) { + struct bxt_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *dai = rtd->codec_dai; + struct bxt_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM;
- return hdac_hdmi_jack_init(dai, BXT_DPCM_AUDIO_HDMI1_PB + dai->id); + pcm->device = BXT_DPCM_AUDIO_HDMI1_PB + dai->id; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; }
static int broxton_da7219_fe_init(struct snd_soc_pcm_runtime *rtd) @@ -496,6 +517,21 @@ static struct snd_soc_dai_link broxton_dais[] = { }, };
+static int bxt_card_late_probe(struct snd_soc_card *card) +{ + struct bxt_card_private *ctx = snd_soc_card_get_drvdata(card); + struct bxt_hdmi_pcm *pcm; + int err; + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device); + if (err < 0) + return err; + } + + return 0; +} + /* broxton audio machine driver for SPT + da7219 */ static struct snd_soc_card broxton_audio_card = { .name = "bxtda7219max", @@ -509,11 +545,22 @@ static struct snd_soc_card broxton_audio_card = { .dapm_routes = broxton_map, .num_dapm_routes = ARRAY_SIZE(broxton_map), .fully_routed = true, + .late_probe = bxt_card_late_probe, };
static int broxton_audio_probe(struct platform_device *pdev) { + struct bxt_card_private *ctx; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + if (!ctx) + return -ENOMEM; + + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + broxton_audio_card.dev = &pdev->dev; + snd_soc_card_set_drvdata(&broxton_audio_card, ctx); + return devm_snd_soc_register_card(&pdev->dev, &broxton_audio_card); }
From: Jeeja KP jeeja.kp@intel.com
With MST each pin contains several ports to which device can be connected.
As a preparatory work to support DP MST this patch adds below changes: 1. Defines the port structure and moves all stream related information like ELD, converter list, chmap to port. 2. Creates ports for each pin based on the max_ports support. 3. Based on Pin-Port combination creates DAPM Mux widget instead of Pin to allow user to select a converter. 4. Port zero is the default port when pin does not support MST.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/codecs/hdac_hdmi.c | 396 ++++++++++++++++++++++++++----------------- 1 file changed, 241 insertions(+), 155 deletions(-)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 2a370d6..f0e2857 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -42,6 +42,7 @@ #define HDA_MAX_CONNECTIONS 32
#define HDA_MAX_CVTS 3 +#define HDA_MAX_PORTS 3
#define ELD_MAX_SIZE 256 #define ELD_FIXED_BYTES 20 @@ -81,16 +82,23 @@ struct hdac_hdmi_eld { struct hdac_hdmi_pin { struct list_head head; hda_nid_t nid; + struct hdac_hdmi_port *ports; + int num_ports; + struct hdac_ext_device *edev; +}; + +struct hdac_hdmi_port { + int id; + struct hdac_hdmi_pin *pin; int num_mux_nids; hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; struct hdac_hdmi_eld eld; - struct hdac_ext_device *edev; };
struct hdac_hdmi_pcm { struct list_head head; int pcm_id; - struct hdac_hdmi_pin *pin; + struct hdac_hdmi_port *port; struct hdac_hdmi_cvt *cvt; struct snd_jack *jack; int stream_tag; @@ -101,19 +109,20 @@ struct hdac_hdmi_pcm { struct mutex lock; };
-struct hdac_hdmi_dai_pin_map { +struct hdac_hdmi_dai_port_map { int dai_id; - struct hdac_hdmi_pin *pin; + struct hdac_hdmi_port *port; struct hdac_hdmi_cvt *cvt; };
struct hdac_hdmi_priv { - struct hdac_hdmi_dai_pin_map dai_map[HDA_MAX_CVTS]; + struct hdac_hdmi_dai_port_map dai_map[HDA_MAX_CVTS]; struct list_head pin_list; struct list_head cvt_list; struct list_head pcm_list; int num_pin; int num_cvt; + int num_ports; struct mutex pin_mutex; struct hdac_chmap chmap; }; @@ -216,10 +225,11 @@ struct dp_audio_infoframe { };
static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, - struct hdac_hdmi_pcm *pcm, struct hdac_hdmi_pin *pin) + struct hdac_hdmi_pcm *pcm, struct hdac_hdmi_port *port) { uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE]; struct hdmi_audio_infoframe frame; + struct hdac_hdmi_pin *pin = port->pin; struct dp_audio_infoframe dp_ai; struct hdac_hdmi_priv *hdmi = hdac->private_data; struct hdac_hdmi_cvt *cvt = pcm->cvt; @@ -230,7 +240,7 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, u8 conn_type; int channels, ca;
- ca = snd_hdac_channel_allocation(&hdac->hdac, pin->eld.info.spk_alloc, + ca = snd_hdac_channel_allocation(&hdac->hdac, port->eld.info.spk_alloc, pcm->channels, pcm->chmap_set, true, pcm->chmap);
channels = snd_hdac_get_active_channels(ca); @@ -239,7 +249,7 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, snd_hdac_setup_channel_mapping(&hdmi->chmap, pin->nid, false, ca, pcm->channels, pcm->chmap, pcm->chmap_set);
- eld_buf = pin->eld.eld_buffer; + eld_buf = port->eld.eld_buffer; conn_type = drm_eld_get_conn_type(eld_buf);
switch (conn_type) { @@ -304,7 +314,7 @@ static int hdac_hdmi_set_tdm_slot(struct snd_soc_dai *dai, { struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai); struct hdac_hdmi_priv *hdmi = edev->private_data; - struct hdac_hdmi_dai_pin_map *dai_map; + struct hdac_hdmi_dai_port_map *dai_map; struct hdac_hdmi_pcm *pcm;
dev_dbg(&edev->hdac.dev, "%s: strm_tag: %d\n", __func__, tx_mask); @@ -324,20 +334,21 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, { struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); struct hdac_hdmi_priv *hdmi = hdac->private_data; - struct hdac_hdmi_dai_pin_map *dai_map; - struct hdac_hdmi_pin *pin; + struct hdac_hdmi_dai_port_map *dai_map; + struct hdac_hdmi_port *port; struct hdac_hdmi_pcm *pcm; int format;
dai_map = &hdmi->dai_map[dai->id]; - pin = dai_map->pin; + port = dai_map->port;
- if (!pin) + if (!port) return -ENODEV;
- if ((!pin->eld.monitor_present) || (!pin->eld.eld_valid)) { - dev_err(&hdac->hdac.dev, "device is not configured for this pin: %d\n", - pin->nid); + if ((!port->eld.monitor_present) || (!port->eld.eld_valid)) { + dev_err(&hdac->hdac.dev, + "device is not configured for this pin:port%d:%d\n", + port->pin->nid, port->id); return -ENODEV; }
@@ -355,8 +366,9 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, return 0; }
-static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac, - struct hdac_hdmi_pin *pin) +static int hdac_hdmi_query_port_connlist(struct hdac_ext_device *hdac, + struct hdac_hdmi_pin *pin, + struct hdac_hdmi_port *port) { if (!(get_wcaps(&hdac->hdac, pin->nid) & AC_WCAP_CONN_LIST)) { dev_warn(&hdac->hdac.dev, @@ -365,51 +377,52 @@ static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac, return -EINVAL; }
- pin->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid, - pin->mux_nids, HDA_MAX_CONNECTIONS); - if (pin->num_mux_nids == 0) - dev_warn(&hdac->hdac.dev, "No connections found for pin: %d\n", - pin->nid); + port->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid, + port->mux_nids, HDA_MAX_CONNECTIONS); + if (port->num_mux_nids == 0) + dev_warn(&hdac->hdac.dev, + "No connections found for pin:port %d:%d\n", + pin->nid, port->id);
- dev_dbg(&hdac->hdac.dev, "num_mux_nids %d for pin: %d\n", - pin->num_mux_nids, pin->nid); + dev_dbg(&hdac->hdac.dev, "num_mux_nids %d for pin:port %d:%d\n", + port->num_mux_nids, pin->nid, port->id);
- return pin->num_mux_nids; + return port->num_mux_nids; }
/* - * Query pcm list and return pin widget to which stream is routed. + * Query pcm list and return port to which stream is routed. * - * Also query connection list of the pin, to validate the cvt to pin map. + * Also query connection list of the pin, to validate the cvt to port map. * - * Same stream rendering to multiple pins simultaneously can be done - * possibly, but not supported for now in driver. So return the first pin + * Same stream rendering to multiple ports simultaneously can be done + * possibly, but not supported for now in driver. So return the first port * connected. */ -static struct hdac_hdmi_pin *hdac_hdmi_get_pin_from_cvt( +static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt( struct hdac_ext_device *edev, struct hdac_hdmi_priv *hdmi, struct hdac_hdmi_cvt *cvt) { struct hdac_hdmi_pcm *pcm; - struct hdac_hdmi_pin *pin = NULL; + struct hdac_hdmi_port *port = NULL; int ret, i;
list_for_each_entry(pcm, &hdmi->pcm_list, head) { if (pcm->cvt == cvt) { - pin = pcm->pin; + port = pcm->port; break; } }
- if (pin) { - ret = hdac_hdmi_query_pin_connlist(edev, pin); + if (port) { + ret = hdac_hdmi_query_port_connlist(edev, port->pin, port); if (ret < 0) return NULL;
- for (i = 0; i < pin->num_mux_nids; i++) { - if (pin->mux_nids[i] == cvt->nid) - return pin; + for (i = 0; i < port->num_mux_nids; i++) { + if (port->mux_nids[i] == cvt->nid) + return port; } }
@@ -426,42 +439,43 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, { struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); struct hdac_hdmi_priv *hdmi = hdac->private_data; - struct hdac_hdmi_dai_pin_map *dai_map; + struct hdac_hdmi_dai_port_map *dai_map; struct hdac_hdmi_cvt *cvt; - struct hdac_hdmi_pin *pin; + struct hdac_hdmi_port *port; int ret;
dai_map = &hdmi->dai_map[dai->id];
cvt = dai_map->cvt; - pin = hdac_hdmi_get_pin_from_cvt(hdac, hdmi, cvt); + port = hdac_hdmi_get_port_from_cvt(hdac, hdmi, cvt);
/* * To make PA and other userland happy. * userland scans devices so returning error does not help. */ - if (!pin) + if (!port) return 0;
- if ((!pin->eld.monitor_present) || - (!pin->eld.eld_valid)) { + if ((!port->eld.monitor_present) || + (!port->eld.eld_valid)) {
dev_warn(&hdac->hdac.dev, - "Failed: monitor present? %d ELD valid?: %d for pin: %d\n", - pin->eld.monitor_present, pin->eld.eld_valid, pin->nid); + "Failed: present?:%d ELD valid?:%d pin:port: %d:%d\n", + port->eld.monitor_present, port->eld.eld_valid, + port->pin->nid, port->id);
return 0; }
- dai_map->pin = pin; + dai_map->port = port;
ret = hdac_hdmi_eld_limit_formats(substream->runtime, - pin->eld.eld_buffer); + port->eld.eld_buffer); if (ret < 0) return ret;
return snd_pcm_hw_constraint_eld(substream->runtime, - pin->eld.eld_buffer); + port->eld.eld_buffer); }
static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, @@ -469,7 +483,7 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, { struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); struct hdac_hdmi_priv *hdmi = hdac->private_data; - struct hdac_hdmi_dai_pin_map *dai_map; + struct hdac_hdmi_dai_port_map *dai_map; struct hdac_hdmi_pcm *pcm;
dai_map = &hdmi->dai_map[dai->id]; @@ -484,8 +498,8 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, mutex_unlock(&pcm->lock); }
- if (dai_map->pin) - dai_map->pin = NULL; + if (dai_map->port) + dai_map->port = NULL; }
static int @@ -553,13 +567,16 @@ static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route, }
static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev, - struct hdac_hdmi_pin *pin) + struct hdac_hdmi_port *port) { struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm = NULL;
list_for_each_entry(pcm, &hdmi->pcm_list, head) { - if (pcm->pin == pin) + if (!pcm->port) + continue; + + if (pcm->port == port) return pcm; }
@@ -588,37 +605,37 @@ static void hdac_hdmi_set_amp(struct hdac_ext_device *edev, static int hdac_hdmi_pin_output_widget_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kc, int event) { - struct hdac_hdmi_pin *pin = w->priv; + struct hdac_hdmi_port *port = w->priv; struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev); struct hdac_hdmi_pcm *pcm;
dev_dbg(&edev->hdac.dev, "%s: widget: %s event: %x\n", __func__, w->name, event);
- pcm = hdac_hdmi_get_pcm(edev, pin); + pcm = hdac_hdmi_get_pcm(edev, port); if (!pcm) return -EIO;
switch (event) { case SND_SOC_DAPM_PRE_PMU: - hdac_hdmi_set_power_state(edev, pin->nid, AC_PWRST_D0); + hdac_hdmi_set_power_state(edev, port->pin->nid, AC_PWRST_D0);
/* Enable out path for this pin widget */ - snd_hdac_codec_write(&edev->hdac, pin->nid, 0, + snd_hdac_codec_write(&edev->hdac, port->pin->nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
- hdac_hdmi_set_amp(edev, pin->nid, AMP_OUT_UNMUTE); + hdac_hdmi_set_amp(edev, port->pin->nid, AMP_OUT_UNMUTE);
- return hdac_hdmi_setup_audio_infoframe(edev, pcm, pin); + return hdac_hdmi_setup_audio_infoframe(edev, pcm, port);
case SND_SOC_DAPM_POST_PMD: - hdac_hdmi_set_amp(edev, pin->nid, AMP_OUT_MUTE); + hdac_hdmi_set_amp(edev, port->pin->nid, AMP_OUT_MUTE);
/* Disable out path for this pin widget */ - snd_hdac_codec_write(&edev->hdac, pin->nid, 0, + snd_hdac_codec_write(&edev->hdac, port->pin->nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
- hdac_hdmi_set_power_state(edev, pin->nid, AC_PWRST_D3); + hdac_hdmi_set_power_state(edev, port->pin->nid, AC_PWRST_D3); break;
} @@ -676,7 +693,7 @@ static int hdac_hdmi_cvt_output_widget_event(struct snd_soc_dapm_widget *w, static int hdac_hdmi_pin_mux_widget_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kc, int event) { - struct hdac_hdmi_pin *pin = w->priv; + struct hdac_hdmi_port *port = w->priv; struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev); int mux_idx;
@@ -688,7 +705,7 @@ static int hdac_hdmi_pin_mux_widget_event(struct snd_soc_dapm_widget *w,
mux_idx = dapm_kcontrol_get_value(kc); if (mux_idx > 0) { - snd_hdac_codec_write(&edev->hdac, pin->nid, 0, + snd_hdac_codec_write(&edev->hdac, port->pin->nid, 0, AC_VERB_SET_CONNECT_SEL, (mux_idx - 1)); }
@@ -698,14 +715,14 @@ static int hdac_hdmi_pin_mux_widget_event(struct snd_soc_dapm_widget *w, /* * Based on user selection, map the PINs with the PCMs. */ -static int hdac_hdmi_set_pin_mux(struct snd_kcontrol *kcontrol, +static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int ret; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); struct snd_soc_dapm_context *dapm = w->dapm; - struct hdac_hdmi_pin *pin = w->priv; + struct hdac_hdmi_port *port = w->priv; struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev); struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm = NULL; @@ -715,18 +732,22 @@ static int hdac_hdmi_set_pin_mux(struct snd_kcontrol *kcontrol, if (ret < 0) return ret;
+ if (port == NULL) + return -EINVAL; + mutex_lock(&hdmi->pin_mutex); list_for_each_entry(pcm, &hdmi->pcm_list, head) { - if (pcm->pin == pin) - pcm->pin = NULL; + if (!pcm->port && pcm->port == port && + pcm->port->id == port->id) + pcm->port = NULL;
/* * Jack status is not reported during device probe as the * PCMs are not registered by then. So report it here. */ - if (!strcmp(cvt_name, pcm->cvt->name) && !pcm->pin) { - pcm->pin = pin; - if (pin->eld.monitor_present && pin->eld.eld_valid) { + if (!strcmp(cvt_name, pcm->cvt->name) && !pcm->port) { + pcm->port = port; + if (port->eld.monitor_present && port->eld.eld_valid) { dev_dbg(&edev->hdac.dev, "jack report for pcm=%d\n", pcm->pcm_id); @@ -751,12 +772,13 @@ static int hdac_hdmi_set_pin_mux(struct snd_kcontrol *kcontrol, * care of selecting the right one and leaving all other inputs selected to * "NONE" */ -static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev, - struct hdac_hdmi_pin *pin, +static int hdac_hdmi_create_pin_port_muxs(struct hdac_ext_device *edev, + struct hdac_hdmi_port *port, struct snd_soc_dapm_widget *widget, const char *widget_name) { struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_pin *pin = port->pin; struct snd_kcontrol_new *kc; struct hdac_hdmi_cvt *cvt; struct soc_enum *se; @@ -775,7 +797,7 @@ static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev, if (!se) return -ENOMEM;
- sprintf(kc_name, "Pin %d Input", pin->nid); + sprintf(kc_name, "Pin %d port %d Input", pin->nid, port->id); kc->name = devm_kstrdup(&edev->hdac.dev, kc_name, GFP_KERNEL); if (!kc->name) return -ENOMEM; @@ -784,7 +806,7 @@ static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev, kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER; kc->access = 0; kc->info = snd_soc_info_enum_double; - kc->put = hdac_hdmi_set_pin_mux; + kc->put = hdac_hdmi_set_pin_port_mux; kc->get = snd_soc_dapm_get_enum_double;
se->reg = SND_SOC_NOPM; @@ -812,7 +834,7 @@ static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev, return -ENOMEM;
return hdac_hdmi_fill_widget_info(&edev->hdac.dev, widget, - snd_soc_dapm_mux, pin, widget_name, NULL, kc, 1, + snd_soc_dapm_mux, port, widget_name, NULL, kc, 1, hdac_hdmi_pin_mux_widget_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_REG); } @@ -825,10 +847,10 @@ static void hdac_hdmi_add_pinmux_cvt_route(struct hdac_ext_device *edev, struct hdac_hdmi_priv *hdmi = edev->private_data; const struct snd_kcontrol_new *kc; struct soc_enum *se; - int mux_index = hdmi->num_cvt + hdmi->num_pin; + int mux_index = hdmi->num_cvt + hdmi->num_ports; int i, j;
- for (i = 0; i < hdmi->num_pin; i++) { + for (i = 0; i < hdmi->num_ports; i++) { kc = widgets[mux_index].kcontrol_news; se = (struct soc_enum *)kc->private_value; for (j = 0; j < hdmi->num_cvt; j++) { @@ -847,17 +869,18 @@ static void hdac_hdmi_add_pinmux_cvt_route(struct hdac_ext_device *edev, /* * Widgets are added in the below sequence * Converter widgets for num converters enumerated - * Pin widgets for num pins enumerated - * Pin mux widgets to represent connenction list of pin widget + * Pin-port widgets for num ports for Pins enumerated + * Pin-port mux widgets to represent connenction list of pin widget * - * Total widgets elements = num_cvt + num_pin + num_pin; + * For each port, one Mux and One output widget is added + * Total widgets elements = num_cvt + (num_ports * 2); * * Routes are added as below: - * pin mux -> pin (based on num_pins) - * cvt -> "Input sel control" -> pin_mux + * pin-port mux -> pin (based on num_ports) + * cvt -> "Input sel control" -> pin-port_mux * * Total route elements: - * num_pins + (pin_muxes * num_cvt) + * num_ports + (pin_muxes * num_cvt) */ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) { @@ -869,14 +892,14 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) char widget_name[NAME_SIZE]; struct hdac_hdmi_cvt *cvt; struct hdac_hdmi_pin *pin; - int ret, i = 0, num_routes = 0; + int ret, i = 0, num_routes = 0, j;
if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list)) return -EINVAL;
- widgets = devm_kzalloc(dapm->dev, - (sizeof(*widgets) * ((2 * hdmi->num_pin) + hdmi->num_cvt)), - GFP_KERNEL); + widgets = devm_kzalloc(dapm->dev, (sizeof(*widgets) * + ((2 * hdmi->num_ports) + hdmi->num_cvt)), + GFP_KERNEL);
if (!widgets) return -ENOMEM; @@ -895,31 +918,39 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) }
list_for_each_entry(pin, &hdmi->pin_list, head) { - sprintf(widget_name, "hif%d Output", pin->nid); - ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i], - snd_soc_dapm_output, pin, - widget_name, NULL, NULL, 0, - hdac_hdmi_pin_output_widget_event, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD); - if (ret < 0) - return ret; - i++; + for (j = 0; j < pin->num_ports; j++) { + sprintf(widget_name, "hif%d-%d Output", + pin->nid, pin->ports[j].id); + ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i], + snd_soc_dapm_output, &pin->ports[j], + widget_name, NULL, NULL, 0, + hdac_hdmi_pin_output_widget_event, + SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD); + if (ret < 0) + return ret; + i++; + } }
/* DAPM widgets to represent the connection list to pin widget */ list_for_each_entry(pin, &hdmi->pin_list, head) { - sprintf(widget_name, "Pin %d Mux", pin->nid); - ret = hdac_hdmi_create_pin_muxs(edev, pin, &widgets[i], - widget_name); - if (ret < 0) - return ret; - i++; + for (j = 0; j < pin->num_ports; j++) { + sprintf(widget_name, "Pin%d-Port%d Mux", + pin->nid, pin->ports[j].id); + ret = hdac_hdmi_create_pin_port_muxs(edev, + &pin->ports[j], &widgets[i], + widget_name); + if (ret < 0) + return ret; + i++;
- /* For cvt to pin_mux mapping */ - num_routes += hdmi->num_cvt; + /* For cvt to pin_mux mapping */ + num_routes += hdmi->num_cvt;
- /* For pin_mux to pin mapping */ - num_routes++; + /* For pin_mux to pin mapping */ + num_routes++; + } }
route = devm_kzalloc(dapm->dev, (sizeof(*route) * num_routes), @@ -930,20 +961,22 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) i = 0; /* Add pin <- NULL <- mux route map */ list_for_each_entry(pin, &hdmi->pin_list, head) { - int sink_index = i + hdmi->num_cvt; - int src_index = sink_index + hdmi->num_pin; + for (j = 0; j < pin->num_ports; j++) { + int sink_index = i + hdmi->num_cvt; + int src_index = sink_index + pin->num_ports * + hdmi->num_pin;
- hdac_hdmi_fill_route(&route[i], + hdac_hdmi_fill_route(&route[i], widgets[sink_index].name, NULL, widgets[src_index].name, NULL); - i++; - + i++; + } }
hdac_hdmi_add_pinmux_cvt_route(edev, widgets, route, i);
snd_soc_dapm_new_controls(dapm, widgets, - ((2 * hdmi->num_pin) + hdmi->num_cvt)); + ((2 * hdmi->num_ports) + hdmi->num_cvt));
snd_soc_dapm_add_routes(dapm, route, num_routes); snd_soc_dapm_new_widgets(dapm->card); @@ -955,7 +988,7 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev) { struct hdac_hdmi_priv *hdmi = edev->private_data; - struct hdac_hdmi_dai_pin_map *dai_map; + struct hdac_hdmi_dai_port_map *dai_map; struct hdac_hdmi_cvt *cvt; int dai_id = 0;
@@ -999,12 +1032,12 @@ static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid) return hdac_hdmi_query_cvt_params(&edev->hdac, cvt); }
-static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev, - struct hdac_hdmi_pin *pin) +static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev, + struct hdac_hdmi_port *port) { unsigned int ver, mnl;
- ver = (pin->eld.eld_buffer[DRM_ELD_VER] & DRM_ELD_VER_MASK) + ver = (port->eld.eld_buffer[DRM_ELD_VER] & DRM_ELD_VER_MASK) >> DRM_ELD_VER_SHIFT;
if (ver != ELD_VER_CEA_861D && ver != ELD_VER_PARTIAL) { @@ -1012,7 +1045,7 @@ static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev, return -EINVAL; }
- mnl = (pin->eld.eld_buffer[DRM_ELD_CEA_EDID_VER_MNL] & + mnl = (port->eld.eld_buffer[DRM_ELD_CEA_EDID_VER_MNL] & DRM_ELD_MNL_MASK) >> DRM_ELD_MNL_SHIFT;
if (mnl > ELD_MAX_MNL) { @@ -1020,45 +1053,50 @@ static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev, return -EINVAL; }
- pin->eld.info.spk_alloc = pin->eld.eld_buffer[DRM_ELD_SPEAKER]; + port->eld.info.spk_alloc = port->eld.eld_buffer[DRM_ELD_SPEAKER];
return 0; }
-static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin) +static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, + struct hdac_hdmi_port *port) { struct hdac_ext_device *edev = pin->edev; struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm; - int size; + int size = 0; + + if (!hdmi) + return;
mutex_lock(&hdmi->pin_mutex); - pin->eld.monitor_present = false; + port->eld.monitor_present = false;
size = snd_hdac_acomp_get_eld(&edev->hdac, pin->nid, -1, - &pin->eld.monitor_present, pin->eld.eld_buffer, + &port->eld.monitor_present, + port->eld.eld_buffer, ELD_MAX_SIZE);
if (size > 0) { size = min(size, ELD_MAX_SIZE); - if (hdac_hdmi_parse_eld(edev, pin) < 0) + if (hdac_hdmi_parse_eld(edev, port) < 0) size = -EINVAL; }
if (size > 0) { - pin->eld.eld_valid = true; - pin->eld.eld_size = size; + port->eld.eld_valid = true; + port->eld.eld_size = size; } else { - pin->eld.eld_valid = false; - pin->eld.eld_size = 0; + port->eld.eld_valid = false; + port->eld.eld_size = 0; }
- pcm = hdac_hdmi_get_pcm(edev, pin); + pcm = hdac_hdmi_get_pcm(edev, port);
- if (!pin->eld.monitor_present || !pin->eld.eld_valid) { + if (!port->eld.monitor_present || !port->eld.eld_valid) {
- dev_dbg(&edev->hdac.dev, "%s: disconnect for pin %d\n", - __func__, pin->nid); + dev_dbg(&edev->hdac.dev, "%s: disconnect for pin:port %d:%d\n", + __func__, pin->nid, port->id);
/* * PCMs are not registered during device probe, so don't @@ -1076,7 +1114,7 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin) return; }
- if (pin->eld.monitor_present && pin->eld.eld_valid) { + if (port->eld.monitor_present && port->eld.eld_valid) { if (pcm) { dev_dbg(&edev->hdac.dev, "jack report for pcm=%d\n", @@ -1086,27 +1124,57 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin) }
print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1, - pin->eld.eld_buffer, pin->eld.eld_size, false); - } + port->eld.eld_buffer, port->eld.eld_size, false);
+ } mutex_unlock(&hdmi->pin_mutex); }
+static int hdac_hdmi_add_ports(struct hdac_hdmi_priv *hdmi, + struct hdac_hdmi_pin *pin) +{ + struct hdac_hdmi_port *ports; + int max_ports = HDA_MAX_PORTS; + int i; + + /* + * FIXME: max_port may vary for each platform, so pass this as + * as driver data or query from i915 interface when this API is + * implemented. + */ + + ports = kcalloc(max_ports, sizeof(*ports), GFP_KERNEL); + if (!ports) + return -ENOMEM; + + for (i = 0; i < max_ports; i++) { + ports[i].id = i; + ports[i].pin = pin; + } + pin->ports = ports; + pin->num_ports = max_ports; + return 0; +} + static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) { struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pin *pin; + int ret;
pin = kzalloc(sizeof(*pin), GFP_KERNEL); if (!pin) return -ENOMEM;
pin->nid = nid; + pin->edev = edev; + ret = hdac_hdmi_add_ports(hdmi, pin); + if (ret < 0) + return ret;
list_add_tail(&pin->head, &hdmi->pin_list); hdmi->num_pin++; - - pin->edev = edev; + hdmi->num_ports += pin->num_ports;
return 0; } @@ -1288,17 +1356,19 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev, return hdac_hdmi_init_dai_map(edev); }
-static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) +static void hdac_hdmi_eld_notify_cb(void *aptr, int dport, int pipe) { struct hdac_ext_device *edev = aptr; struct hdac_hdmi_priv *hdmi = edev->private_data; - struct hdac_hdmi_pin *pin; + struct hdac_hdmi_pin *pin = NULL; + struct hdac_hdmi_port *port = NULL; struct snd_soc_codec *codec = edev->scodec;
/* Don't know how this mapping is derived */ - hda_nid_t pin_nid = port + 0x04; + hda_nid_t pin_nid = dport + 0x04;
- dev_dbg(&edev->hdac.dev, "%s: for pin: %d\n", __func__, pin_nid); + dev_dbg(&edev->hdac.dev, "%s: for pin:%d port=%d\n", __func__, + pin_nid, pipe);
/* * skip notification during system suspend (but not in runtime PM); @@ -1314,9 +1384,18 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) return;
list_for_each_entry(pin, &hdmi->pin_list, head) { - if (pin->nid == pin_nid) - hdac_hdmi_present_sense(pin); + if (pin->nid != pin_nid) + continue; + + if (pipe == -1) { + /* if not MST, default is port[0] */ + port = &pin->ports[0]; + break; + } } + + if (port) + hdac_hdmi_present_sense(pin, port); }
static struct i915_audio_component_audio_ops aops = { @@ -1388,7 +1467,7 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec) snd_soc_component_get_dapm(&codec->component); struct hdac_hdmi_pin *pin; struct hdac_ext_link *hlink = NULL; - int ret; + int ret, i;
edev->scodec = codec;
@@ -1417,7 +1496,8 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec) }
list_for_each_entry(pin, &hdmi->pin_list, head) - hdac_hdmi_present_sense(pin); + for (i = 0; i < pin->num_ports; i++) + hdac_hdmi_present_sense(pin, &pin->ports[i]);
/* Imp: Store the card pointer in hda_codec */ edev->card = dapm->card->snd_card; @@ -1468,6 +1548,7 @@ static void hdmi_codec_complete(struct device *dev) struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pin *pin; struct hdac_device *hdac = &edev->hdac; + int i;
/* Power up afg */ snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE, @@ -1482,7 +1563,8 @@ static void hdmi_codec_complete(struct device *dev) * all pins here. */ list_for_each_entry(pin, &hdmi->pin_list, head) - hdac_hdmi_present_sense(pin); + for (i = 0; i < pin->num_ports; i++) + hdac_hdmi_present_sense(pin, &pin->ports[i]);
pm_runtime_put_sync(&edev->hdac.dev); } @@ -1513,13 +1595,13 @@ static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx, struct hdac_ext_device *edev = to_ehdac_device(hdac); struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); - struct hdac_hdmi_pin *pin = pcm->pin; + struct hdac_hdmi_port *port = pcm->port;
mutex_lock(&pcm->lock); pcm->chmap_set = true; memcpy(pcm->chmap, chmap, ARRAY_SIZE(pcm->chmap)); if (prepared) - hdac_hdmi_setup_audio_infoframe(edev, pcm, pin); + hdac_hdmi_setup_audio_infoframe(edev, pcm, port); mutex_unlock(&pcm->lock); }
@@ -1528,9 +1610,9 @@ static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx) struct hdac_ext_device *edev = to_ehdac_device(hdac); struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); - struct hdac_hdmi_pin *pin = pcm->pin; + struct hdac_hdmi_port *port = pcm->port;
- return pin ? true:false; + return port ? true:false; }
static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx) @@ -1538,12 +1620,12 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx) struct hdac_ext_device *edev = to_ehdac_device(hdac); struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); - struct hdac_hdmi_pin *pin = pcm->pin; + struct hdac_hdmi_port *port = pcm->port;
- if (!pin || !pin->eld.eld_valid) + if (!port || !port->eld.eld_valid) return 0;
- return pin->eld.info.spk_alloc; + return port->eld.info.spk_alloc; }
static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) @@ -1616,12 +1698,13 @@ static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) struct hdac_hdmi_pin *pin, *pin_next; struct hdac_hdmi_cvt *cvt, *cvt_next; struct hdac_hdmi_pcm *pcm, *pcm_next; + int i;
snd_soc_unregister_codec(&edev->hdac.dev);
list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) { pcm->cvt = NULL; - pcm->pin = NULL; + pcm->port = NULL; list_del(&pcm->head); kfree(pcm); } @@ -1633,6 +1716,9 @@ static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) }
list_for_each_entry_safe(pin, pin_next, &hdmi->pin_list, head) { + for (i = 0; i < pin->num_ports; i++) + pin->ports[i].pin = NULL; + kfree(pin->ports); list_del(&pin->head); kfree(pin); }
From: Jeeja KP jeeja.kp@intel.com
To support MST moved pin to port, this changes the routes based on port. So change the route in skl_rt286 machine.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/intel/boards/skl_rt286.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index dc5c361..5e56af3 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -94,9 +94,9 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = { {"DMIC1 Pin", NULL, "DMIC2"}, {"DMic", NULL, "SoC DMIC"},
- {"HDMI1", NULL, "hif5 Output"}, - {"HDMI2", NULL, "hif6 Output"}, - {"HDMI3", NULL, "hif7 Output"}, + {"HDMI1", NULL, "hif5-0 Output"}, + {"HDMI2", NULL, "hif6-0 Output"}, + {"HDMI3", NULL, "hif7-0 Output"},
/* CODEC BE connections */ { "AIF1 Playback", NULL, "ssp0 Tx"},
From: Jeeja KP jeeja.kp@intel.com
To support MST moved pin to port, this changes the routes based on port. So change the route in nau88l25_max98357a machine.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/intel/boards/skl_nau88l25_max98357a.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index 436afb9..57acc58 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -141,8 +141,8 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = { SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_SPK("Spk", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("DP", NULL), - SND_SOC_DAPM_SPK("HDMI", NULL), + SND_SOC_DAPM_SPK("DP1", NULL), + SND_SOC_DAPM_SPK("DP2", NULL), SND_SOC_DAPM_SUPPLY("ssp0 mclk", SND_SOC_NOPM, 0, 0, ssp_set_clk, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), @@ -163,8 +163,8 @@ static const struct snd_soc_dapm_route skylake_map[] = { { "MIC", NULL, "Headset Mic" }, { "DMic", NULL, "SoC DMIC" },
- {"HDMI", NULL, "hif5 Output"}, - {"DP", NULL, "hif6 Output"}, + {"DP1", NULL, "hif5-0 Output"}, + {"DP2", NULL, "hif6-0 Output"},
/* CODEC BE connections */ { "HiFi Playback", NULL, "ssp0 Tx" },
From: Jeeja KP jeeja.kp@intel.com
To support MST moved pin to port, this changes the routes based on port. So change the route in nau88l25_ssm4567 machine.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 8ab865e..41117bc 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -115,8 +115,8 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = { SND_SOC_DAPM_SPK("Left Speaker", NULL), SND_SOC_DAPM_SPK("Right Speaker", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("DP", NULL), - SND_SOC_DAPM_SPK("HDMI", NULL), + SND_SOC_DAPM_SPK("DP1", NULL), + SND_SOC_DAPM_SPK("DP2", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), @@ -135,8 +135,9 @@ static const struct snd_soc_dapm_route skylake_map[] = { {"MIC", NULL, "Headset Mic"}, {"DMic", NULL, "SoC DMIC"},
- {"HDMI", NULL, "hif5 Output"}, - {"DP", NULL, "hif6 Output"}, + {"DP1", NULL, "hif5-0 Output"}, + {"DP2", NULL, "hif6-0 Output"}, + /* CODEC BE connections */ { "Left Playback", NULL, "ssp0 Tx"}, { "Right Playback", NULL, "ssp0 Tx"},
From: Jeeja KP jeeja.kp@intel.com
To support MST moved pin to port, this changes the routes based on port. So change the route in bxt_rt298 machine.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/intel/boards/bxt_rt298.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index bc9ee09..09be868 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -92,9 +92,9 @@ static const struct snd_soc_dapm_route broxton_rt298_map[] = { {"DMIC1 Pin", NULL, "DMIC2"}, {"DMic", NULL, "SoC DMIC"},
- {"HDMI1", NULL, "hif5 Output"}, - {"HDMI2", NULL, "hif6 Output"}, - {"HDMI3", NULL, "hif7 Output"}, + {"HDMI1", NULL, "hif5-0 Output"}, + {"HDMI2", NULL, "hif6-0 Output"}, + {"HDMI2", NULL, "hif7-0 Output"},
/* CODEC BE connections */ { "AIF1 Playback", NULL, "ssp5 Tx"},
From: Jeeja KP jeeja.kp@intel.com
To support MST moved pin to port, this changes the routes based on port. So change the route in bxt_da7219_max98357a machine.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 8dfe5e8..36c3589 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -128,9 +128,9 @@ static const struct snd_soc_dapm_route broxton_map[] = { {"codec0_in", NULL, "ssp1 Rx"}, {"ssp1 Rx", NULL, "Capture"},
- {"HDMI1", NULL, "hif5 Output"}, - {"HDMI2", NULL, "hif6 Output"}, - {"HDMI3", NULL, "hif7 Output"}, + {"HDMI1", NULL, "hif5-0 Output"}, + {"HDMI2", NULL, "hif6-0 Output"}, + {"HDMI2", NULL, "hif7-0 Output"},
{"hifi3", NULL, "iDisp3 Tx"}, {"iDisp3 Tx", NULL, "iDisp3_out"},
From: Jeeja KP jeeja.kp@intel.com
To handle jack event and configuration of the pin widget for MST capable pin, this patch adds: o Flag to identify the pin is MST capable. o In notify callback(), based on the pipe and port information marks if the port is mst_capable. In case of non MST, port is defaulted to zero.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/codecs/hdac_hdmi.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index f0e2857..3152b61 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -82,6 +82,7 @@ struct hdac_hdmi_eld { struct hdac_hdmi_pin { struct list_head head; hda_nid_t nid; + bool mst_capable; struct hdac_hdmi_port *ports; int num_ports; struct hdac_ext_device *edev; @@ -1065,14 +1066,22 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm; int size = 0; + int port_id = -1;
if (!hdmi) return;
+ /* + * In case of non MST pin, get_eld info API expectes port + * to be -1. + */ mutex_lock(&hdmi->pin_mutex); port->eld.monitor_present = false;
- size = snd_hdac_acomp_get_eld(&edev->hdac, pin->nid, -1, + if (pin->mst_capable) + port_id = port->id; + + size = snd_hdac_acomp_get_eld(&edev->hdac, pin->nid, port_id, &port->eld.monitor_present, port->eld.eld_buffer, ELD_MAX_SIZE); @@ -1167,6 +1176,7 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) return -ENOMEM;
pin->nid = nid; + pin->mst_capable = false; pin->edev = edev; ret = hdac_hdmi_add_ports(hdmi, pin); if (ret < 0) @@ -1363,6 +1373,7 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int dport, int pipe) struct hdac_hdmi_pin *pin = NULL; struct hdac_hdmi_port *port = NULL; struct snd_soc_codec *codec = edev->scodec; + int i;
/* Don't know how this mapping is derived */ hda_nid_t pin_nid = dport + 0x04; @@ -1388,13 +1399,23 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int dport, int pipe) continue;
if (pipe == -1) { + pin->mst_capable = false; /* if not MST, default is port[0] */ port = &pin->ports[0]; - break; + goto out; + } else { + for (i = 0; i < pin->num_ports; i++) { + pin->mst_capable = true; + if (pin->ports[i].id == pipe) { + port = &pin->ports[i]; + goto out; + } + } } }
- if (port) +out: + if (pin && port) hdac_hdmi_present_sense(pin, port); }
From: Jeeja KP jeeja.kp@intel.com
To support DP MST audio, new pin verbs/params are added. This patch adds helper functions to do following: o To set a specific port o To get the currently selected port o To get the length of port.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/codecs/hdac_hdmi.c | 70 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 3152b61..7397c4c 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -142,6 +142,76 @@ hdac_hdmi_get_pcm_from_cvt(struct hdac_hdmi_priv *hdmi, return pcm; }
+/* MST supported verbs */ +/* + * Get the no devices that can be connected to a port on the Pin widget. + */ +static int hdac_hdmi_get_port_len(struct hdac_ext_device *hdac, hda_nid_t nid) +{ + unsigned int caps; + unsigned int type, param; + + caps = get_wcaps(&hdac->hdac, nid); + type = get_wcaps_type(caps); + + if (!(caps & AC_WCAP_DIGITAL) || (type != AC_WID_PIN)) + return 0; + + param = snd_hdac_read_parm_uncached(&hdac->hdac, nid, + AC_PAR_DEVLIST_LEN); + if (param == -1) + return param; + + return param & AC_DEV_LIST_LEN_MASK; +} + +/* + * Get the port entry select on the pin. Return the port entry + * id selected on the pin. Return 0 means the first port entry + * is selected or MST is not supported. + */ +static int hdac_hdmi_port_select_get(struct hdac_ext_device *hdac, + struct hdac_hdmi_port *port) +{ + return snd_hdac_codec_read(&hdac->hdac, port->pin->nid, + 0, AC_VERB_GET_DEVICE_SEL, 0); +} + +/* + * Sets the selected port entry for the configuring Pin widget verb. + * returns error if port set is not equal to port get otherwise success + */ +static int hdac_hdmi_port_select_set(struct hdac_ext_device *hdac, + struct hdac_hdmi_port *port) +{ + int num_ports; + + if (!port->pin->mst_capable) + return 0; + + /* AC_PAR_DEVLIST_LEN is 0 based. */ + num_ports = hdac_hdmi_get_port_len(hdac, port->pin->nid); + + if (num_ports < 0) + return -EIO; + /* + * Device List Length is a 0 based integer value indicating the + * number of sink device that a MST Pin Widget can support. + */ + if (num_ports + 1 < port->id) + return 0; + + snd_hdac_codec_write(&hdac->hdac, port->pin->nid, 0, + AC_VERB_SET_DEVICE_SEL, port->id); + + if (port->id != hdac_hdmi_port_select_get(hdac, port)) + return -EIO; + + dev_dbg(&hdac->hdac.dev, "Selected the port=%d\n", port->id); + + return 0; +} + static struct hdac_hdmi_pcm *get_hdmi_pcm_from_id(struct hdac_hdmi_priv *hdmi, int pcm_idx) {
The patch
ASoC: hdac_hdmi: Add MST verb support
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 fc181b04f2d44805624d4bc5a0615bc084199a81 Mon Sep 17 00:00:00 2001
From: Jeeja KP jeeja.kp@intel.com Date: Tue, 7 Feb 2017 19:09:45 +0530 Subject: [PATCH] ASoC: hdac_hdmi: Add MST verb support
To support DP MST audio, new pin verbs/params are added. This patch adds helper functions to do following: o To set a specific port o To get the currently selected port o To get the length of port.
Signed-off-by: Jeeja KP jeeja.kp@intel.com Acked-by: Vinod Koul vinod.koul@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/codecs/hdac_hdmi.c | 70 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 17a1ad3ead21..84b7d6cd7c37 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -142,6 +142,76 @@ hdac_hdmi_get_pcm_from_cvt(struct hdac_hdmi_priv *hdmi, return pcm; }
+/* MST supported verbs */ +/* + * Get the no devices that can be connected to a port on the Pin widget. + */ +static int hdac_hdmi_get_port_len(struct hdac_ext_device *hdac, hda_nid_t nid) +{ + unsigned int caps; + unsigned int type, param; + + caps = get_wcaps(&hdac->hdac, nid); + type = get_wcaps_type(caps); + + if (!(caps & AC_WCAP_DIGITAL) || (type != AC_WID_PIN)) + return 0; + + param = snd_hdac_read_parm_uncached(&hdac->hdac, nid, + AC_PAR_DEVLIST_LEN); + if (param == -1) + return param; + + return param & AC_DEV_LIST_LEN_MASK; +} + +/* + * Get the port entry select on the pin. Return the port entry + * id selected on the pin. Return 0 means the first port entry + * is selected or MST is not supported. + */ +static int hdac_hdmi_port_select_get(struct hdac_ext_device *hdac, + struct hdac_hdmi_port *port) +{ + return snd_hdac_codec_read(&hdac->hdac, port->pin->nid, + 0, AC_VERB_GET_DEVICE_SEL, 0); +} + +/* + * Sets the selected port entry for the configuring Pin widget verb. + * returns error if port set is not equal to port get otherwise success + */ +static int hdac_hdmi_port_select_set(struct hdac_ext_device *hdac, + struct hdac_hdmi_port *port) +{ + int num_ports; + + if (!port->pin->mst_capable) + return 0; + + /* AC_PAR_DEVLIST_LEN is 0 based. */ + num_ports = hdac_hdmi_get_port_len(hdac, port->pin->nid); + + if (num_ports < 0) + return -EIO; + /* + * Device List Length is a 0 based integer value indicating the + * number of sink device that a MST Pin Widget can support. + */ + if (num_ports + 1 < port->id) + return 0; + + snd_hdac_codec_write(&hdac->hdac, port->pin->nid, 0, + AC_VERB_SET_DEVICE_SEL, port->id); + + if (port->id != hdac_hdmi_port_select_get(hdac, port)) + return -EIO; + + dev_dbg(&hdac->hdac.dev, "Selected the port=%d\n", port->id); + + return 0; +} + static struct hdac_hdmi_pcm *get_hdmi_pcm_from_id(struct hdac_hdmi_priv *hdmi, int pcm_idx) {
From: Jeeja KP jeeja.kp@intel.com
The ELD notification can be received asynchronously from the graphics side and this may happen just at the moment the sound driver is initializing and notification will be missed. Similarly at system resume, the notification is ignored as the ELD and connection states are updated in anyway at the end of the resume. So check the jack status in boot/resume by querying the port presence based on pin caps and report the jack status.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/codecs/hdac_hdmi.c | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 7397c4c..fda2c6c 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1550,15 +1550,38 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) } EXPORT_SYMBOL_GPL(hdac_hdmi_jack_init);
+static void hdac_hdmi_present_sense_all_pins(struct hdac_ext_device *edev, + struct hdac_hdmi_priv *hdmi, bool detect_pin_caps) +{ + int i; + struct hdac_hdmi_pin *pin; + + list_for_each_entry(pin, &hdmi->pin_list, head) { + if (detect_pin_caps) { + + if (hdac_hdmi_get_port_len(edev, pin->nid) == 0) + pin->mst_capable = false; + else + pin->mst_capable = true; + } + + for (i = 0; i < pin->num_ports; i++) { + if (!pin->mst_capable && i > 0) + continue; + + hdac_hdmi_present_sense(pin, &pin->ports[i]); + } + } +} + static int hdmi_codec_probe(struct snd_soc_codec *codec) { struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); struct hdac_hdmi_priv *hdmi = edev->private_data; struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(&codec->component); - struct hdac_hdmi_pin *pin; struct hdac_ext_link *hlink = NULL; - int ret, i; + int ret;
edev->scodec = codec;
@@ -1586,10 +1609,7 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec) return ret; }
- list_for_each_entry(pin, &hdmi->pin_list, head) - for (i = 0; i < pin->num_ports; i++) - hdac_hdmi_present_sense(pin, &pin->ports[i]); - + hdac_hdmi_present_sense_all_pins(edev, hdmi, true); /* Imp: Store the card pointer in hda_codec */ edev->card = dapm->card->snd_card;
@@ -1637,9 +1657,7 @@ static void hdmi_codec_complete(struct device *dev) { struct hdac_ext_device *edev = to_hda_ext_device(dev); struct hdac_hdmi_priv *hdmi = edev->private_data; - struct hdac_hdmi_pin *pin; struct hdac_device *hdac = &edev->hdac; - int i;
/* Power up afg */ snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE, @@ -1651,11 +1669,10 @@ static void hdmi_codec_complete(struct device *dev) /* * As the ELD notify callback request is not entertained while the * device is in suspend state. Need to manually check detection of - * all pins here. + * all pins here. pin capablity change is not support, so use the + * already set pin caps. */ - list_for_each_entry(pin, &hdmi->pin_list, head) - for (i = 0; i < pin->num_ports; i++) - hdac_hdmi_present_sense(pin, &pin->ports[i]); + hdac_hdmi_present_sense_all_pins(edev, hdmi, false);
pm_runtime_put_sync(&edev->hdac.dev); }
The patch
ASoC: hdac_hdmi: Handle MST pin jack detection at boot/resume
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 a9ce96bcd9c4d0c1ffd3d37c000bcee470b2535b Mon Sep 17 00:00:00 2001
From: Jeeja KP jeeja.kp@intel.com Date: Tue, 7 Feb 2017 19:09:46 +0530 Subject: [PATCH] ASoC: hdac_hdmi: Handle MST pin jack detection at boot/resume
The ELD notification can be received asynchronously from the graphics side and this may happen just at the moment the sound driver is initializing and notification will be missed. Similarly at system resume, the notification is ignored as the ELD and connection states are updated in anyway at the end of the resume. So check the jack status in boot/resume by querying the port presence based on pin caps and report the jack status.
Signed-off-by: Jeeja KP jeeja.kp@intel.com Acked-by: Vinod Koul vinod.koul@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/codecs/hdac_hdmi.c | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 84b7d6cd7c37..c5527e81a490 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1551,15 +1551,38 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) } EXPORT_SYMBOL_GPL(hdac_hdmi_jack_init);
+static void hdac_hdmi_present_sense_all_pins(struct hdac_ext_device *edev, + struct hdac_hdmi_priv *hdmi, bool detect_pin_caps) +{ + int i; + struct hdac_hdmi_pin *pin; + + list_for_each_entry(pin, &hdmi->pin_list, head) { + if (detect_pin_caps) { + + if (hdac_hdmi_get_port_len(edev, pin->nid) == 0) + pin->mst_capable = false; + else + pin->mst_capable = true; + } + + for (i = 0; i < pin->num_ports; i++) { + if (!pin->mst_capable && i > 0) + continue; + + hdac_hdmi_present_sense(pin, &pin->ports[i]); + } + } +} + static int hdmi_codec_probe(struct snd_soc_codec *codec) { struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); struct hdac_hdmi_priv *hdmi = edev->private_data; struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(&codec->component); - struct hdac_hdmi_pin *pin; struct hdac_ext_link *hlink = NULL; - int ret, i; + int ret;
edev->scodec = codec;
@@ -1587,10 +1610,7 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec) return ret; }
- list_for_each_entry(pin, &hdmi->pin_list, head) - for (i = 0; i < pin->num_ports; i++) - hdac_hdmi_present_sense(pin, &pin->ports[i]); - + hdac_hdmi_present_sense_all_pins(edev, hdmi, true); /* Imp: Store the card pointer in hda_codec */ edev->card = dapm->card->snd_card;
@@ -1638,9 +1658,7 @@ static void hdmi_codec_complete(struct device *dev) { struct hdac_ext_device *edev = to_hda_ext_device(dev); struct hdac_hdmi_priv *hdmi = edev->private_data; - struct hdac_hdmi_pin *pin; struct hdac_device *hdac = &edev->hdac; - int i;
/* Power up afg */ snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE, @@ -1652,11 +1670,10 @@ static void hdmi_codec_complete(struct device *dev) /* * As the ELD notify callback request is not entertained while the * device is in suspend state. Need to manually check detection of - * all pins here. + * all pins here. pin capablity change is not support, so use the + * already set pin caps. */ - list_for_each_entry(pin, &hdmi->pin_list, head) - for (i = 0; i < pin->num_ports; i++) - hdac_hdmi_present_sense(pin, &pin->ports[i]); + hdac_hdmi_present_sense_all_pins(edev, hdmi, false);
pm_runtime_put_sync(&edev->hdac.dev); }
From: Jeeja KP jeeja.kp@intel.com
To enable stream on a specific port of a MST capable pin, the port needs to be selected before we configure the pin widget verb.
When port is selected, all the pin widget verb controlling the sink device operation will be directed to selected port. So add port selection before configuring the pin widget verb.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/codecs/hdac_hdmi.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index fda2c6c..e9bf4ac 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -448,6 +448,9 @@ static int hdac_hdmi_query_port_connlist(struct hdac_ext_device *hdac, return -EINVAL; }
+ if (hdac_hdmi_port_select_set(hdac, port) < 0) + return -EIO; + port->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid, port->mux_nids, HDA_MAX_CONNECTIONS); if (port->num_mux_nids == 0) @@ -687,6 +690,10 @@ static int hdac_hdmi_pin_output_widget_event(struct snd_soc_dapm_widget *w, if (!pcm) return -EIO;
+ /* set the device if pin is mst_capable */ + if (hdac_hdmi_port_select_set(edev, port) < 0) + return -EIO; + switch (event) { case SND_SOC_DAPM_PRE_PMU: hdac_hdmi_set_power_state(edev, port->pin->nid, AC_PWRST_D0); @@ -775,6 +782,11 @@ static int hdac_hdmi_pin_mux_widget_event(struct snd_soc_dapm_widget *w, kc = w->kcontrols[0];
mux_idx = dapm_kcontrol_get_value(kc); + + /* set the device if pin is mst_capable */ + if (hdac_hdmi_port_select_set(edev, port) < 0) + return -EIO; + if (mux_idx > 0) { snd_hdac_codec_write(&edev->hdac, port->pin->nid, 0, AC_VERB_SET_CONNECT_SEL, (mux_idx - 1));
The patch
ASoc: hdac_hdmi: Configure pin verbs for MST
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 1b46ebd136b3ad334762d6e66b0b96b432680e50 Mon Sep 17 00:00:00 2001
From: Jeeja KP jeeja.kp@intel.com Date: Tue, 7 Feb 2017 19:09:47 +0530 Subject: [PATCH] ASoc: hdac_hdmi: Configure pin verbs for MST
To enable stream on a specific port of a MST capable pin, the port needs to be selected before we configure the pin widget verb.
When port is selected, all the pin widget verb controlling the sink device operation will be directed to selected port. So add port selection before configuring the pin widget verb.
Signed-off-by: Jeeja KP jeeja.kp@intel.com Acked-by: Vinod Koul vinod.koul@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/codecs/hdac_hdmi.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index c5527e81a490..6cf86a0a118c 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -448,6 +448,9 @@ static int hdac_hdmi_query_port_connlist(struct hdac_ext_device *hdac, return -EINVAL; }
+ if (hdac_hdmi_port_select_set(hdac, port) < 0) + return -EIO; + port->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid, port->mux_nids, HDA_MAX_CONNECTIONS); if (port->num_mux_nids == 0) @@ -687,6 +690,10 @@ static int hdac_hdmi_pin_output_widget_event(struct snd_soc_dapm_widget *w, if (!pcm) return -EIO;
+ /* set the device if pin is mst_capable */ + if (hdac_hdmi_port_select_set(edev, port) < 0) + return -EIO; + switch (event) { case SND_SOC_DAPM_PRE_PMU: hdac_hdmi_set_power_state(edev, port->pin->nid, AC_PWRST_D0); @@ -775,6 +782,11 @@ static int hdac_hdmi_pin_mux_widget_event(struct snd_soc_dapm_widget *w, kc = w->kcontrols[0];
mux_idx = dapm_kcontrol_get_value(kc); + + /* set the device if pin is mst_capable */ + if (hdac_hdmi_port_select_set(edev, port) < 0) + return -EIO; + if (mux_idx > 0) { snd_hdac_codec_write(&edev->hdac, port->pin->nid, 0, AC_VERB_SET_CONNECT_SEL, (mux_idx - 1));
From: Jeeja KP jeeja.kp@intel.com
Since we have the MST feature enabled and Pin-Port mux for user to select the converter routing, multiple port mapping to same converter needs to be supported.
To support multiple port mapped to same converter following changes are done for this:. o Add port list to pcm, so that multiple ports can be mapped to a PCM. o Jack reporting in case where multiple port are attached to same PCM. o Change hdac_hdmi_get_port_from_cvt(), channel_map, remove functions to parse through all ports mapped to same the PCM.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/codecs/hdac_hdmi.c | 168 +++++++++++++++++++++++++++++-------------- 1 file changed, 113 insertions(+), 55 deletions(-)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index e9bf4ac..0c4531b 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -89,6 +89,7 @@ struct hdac_hdmi_pin { };
struct hdac_hdmi_port { + struct list_head head; int id; struct hdac_hdmi_pin *pin; int num_mux_nids; @@ -99,7 +100,7 @@ struct hdac_hdmi_port { struct hdac_hdmi_pcm { struct list_head head; int pcm_id; - struct hdac_hdmi_port *port; + struct list_head port_list; struct hdac_hdmi_cvt *cvt; struct snd_jack *jack; int stream_tag; @@ -108,6 +109,7 @@ struct hdac_hdmi_pcm { bool chmap_set; unsigned char chmap[8]; /* ALSA API channel-map */ struct mutex lock; + int jack_event; };
struct hdac_hdmi_dai_port_map { @@ -142,6 +144,37 @@ hdac_hdmi_get_pcm_from_cvt(struct hdac_hdmi_priv *hdmi, return pcm; }
+static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm, + struct hdac_hdmi_port *port, bool is_connect) +{ + struct hdac_ext_device *edev = port->pin->edev; + + if (is_connect) { + /* + * Report Jack connect event when a device is connected + * for the first time where same PCM is attached to multiple + * ports. + */ + if (pcm->jack_event == 0) { + dev_dbg(&edev->hdac.dev, + "jack report for pcm=%d\n", + pcm->pcm_id); + snd_jack_report(pcm->jack, SND_JACK_AVOUT); + } + pcm->jack_event++; + } else { + /* + * Report Jack disconnect event when a device is disconnected + * is the only last connected device when same PCM is attached + * to multiple ports. + */ + if (pcm->jack_event == 1) + snd_jack_report(pcm->jack, 0); + if (pcm->jack_event > 0) + pcm->jack_event--; + } +} + /* MST supported verbs */ /* * Get the no devices that can be connected to a port on the Pin widget. @@ -484,19 +517,24 @@ static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt(
list_for_each_entry(pcm, &hdmi->pcm_list, head) { if (pcm->cvt == cvt) { - port = pcm->port; - break; - } - } - - if (port) { - ret = hdac_hdmi_query_port_connlist(edev, port->pin, port); - if (ret < 0) - return NULL; + if (list_empty(&pcm->port_list)) + continue;
- for (i = 0; i < port->num_mux_nids; i++) { - if (port->mux_nids[i] == cvt->nid) - return port; + list_for_each_entry(port, &pcm->port_list, head) { + mutex_lock(&pcm->lock); + ret = hdac_hdmi_query_port_connlist(edev, + port->pin, port); + mutex_unlock(&pcm->lock); + if (ret < 0) + continue; + + for (i = 0; i < port->num_mux_nids; i++) { + if (port->mux_nids[i] == cvt->nid && + port->eld.monitor_present && + port->eld.eld_valid) + return port; + } + } } }
@@ -529,7 +567,6 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, */ if (!port) return 0; - if ((!port->eld.monitor_present) || (!port->eld.eld_valid)) {
@@ -645,13 +682,16 @@ static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev, { struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm = NULL; + struct hdac_hdmi_port *p;
list_for_each_entry(pcm, &hdmi->pcm_list, head) { - if (!pcm->port) + if (list_empty(&pcm->port_list)) continue;
- if (pcm->port == port) - return pcm; + list_for_each_entry(p, &pcm->port_list, head) { + if (p->id == port->id && port->pin == p->pin) + return pcm; + } }
return NULL; @@ -802,6 +842,7 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int ret; + struct hdac_hdmi_port *p, *p_next; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); struct snd_soc_dapm_context *dapm = w->dapm; @@ -820,25 +861,30 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol,
mutex_lock(&hdmi->pin_mutex); list_for_each_entry(pcm, &hdmi->pcm_list, head) { - if (!pcm->port && pcm->port == port && - pcm->port->id == port->id) - pcm->port = NULL; + if (list_empty(&pcm->port_list)) + continue;
- /* - * Jack status is not reported during device probe as the - * PCMs are not registered by then. So report it here. - */ - if (!strcmp(cvt_name, pcm->cvt->name) && !pcm->port) { - pcm->port = port; - if (port->eld.monitor_present && port->eld.eld_valid) { - dev_dbg(&edev->hdac.dev, - "jack report for pcm=%d\n", - pcm->pcm_id); + list_for_each_entry_safe(p, p_next, &pcm->port_list, head) { + if (p == port && p->id == port->id && + p->pin == port->pin) { + hdac_hdmi_jack_report(pcm, port, false); + list_del(&p->head); + } + } + }
- snd_jack_report(pcm->jack, SND_JACK_AVOUT); + /* + * Jack status is not reported during device probe as the + * PCMs are not registered by then. So report it here. + */ + list_for_each_entry(pcm, &hdmi->pcm_list, head) { + if (!strcmp(cvt_name, pcm->cvt->name)) { + list_add_tail(&port->head, &pcm->port_list); + if (port->eld.monitor_present && port->eld.eld_valid) { + hdac_hdmi_jack_report(pcm, port, true); + mutex_unlock(&hdmi->pin_mutex); + return ret; } - mutex_unlock(&hdmi->pin_mutex); - return ret; } } mutex_unlock(&hdmi->pin_mutex); @@ -1186,7 +1232,7 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin,
if (!port->eld.monitor_present || !port->eld.eld_valid) {
- dev_dbg(&edev->hdac.dev, "%s: disconnect for pin:port %d:%d\n", + dev_err(&edev->hdac.dev, "%s: disconnect for pin:port %d:%d\n", __func__, pin->nid, port->id);
/* @@ -1194,25 +1240,16 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, * report jack here. It will be done in usermode mux * control select. */ - if (pcm) { - dev_dbg(&edev->hdac.dev, - "jack report for pcm=%d\n", pcm->pcm_id); - - snd_jack_report(pcm->jack, 0); - } + if (pcm) + hdac_hdmi_jack_report(pcm, port, false);
mutex_unlock(&hdmi->pin_mutex); return; }
if (port->eld.monitor_present && port->eld.eld_valid) { - if (pcm) { - dev_dbg(&edev->hdac.dev, - "jack report for pcm=%d\n", - pcm->pcm_id); - - snd_jack_report(pcm->jack, SND_JACK_AVOUT); - } + if (pcm) + hdac_hdmi_jack_report(pcm, port, true);
print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1, port->eld.eld_buffer, port->eld.eld_size, false); @@ -1539,8 +1576,9 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) return -ENOMEM; pcm->pcm_id = device; pcm->cvt = hdmi->dai_map[dai->id].cvt; + pcm->jack_event = 0; mutex_init(&pcm->lock); - + INIT_LIST_HEAD(&pcm->port_list); snd_pcm = hdac_hdmi_get_pcm_from_id(dai->component->card, device); if (snd_pcm) { err = snd_hdac_add_chmap_ctls(snd_pcm, device, &hdmi->chmap); @@ -1715,13 +1753,17 @@ static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx, struct hdac_ext_device *edev = to_ehdac_device(hdac); struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); - struct hdac_hdmi_port *port = pcm->port; + struct hdac_hdmi_port *port; + + if (list_empty(&pcm->port_list)) + return;
mutex_lock(&pcm->lock); pcm->chmap_set = true; memcpy(pcm->chmap, chmap, ARRAY_SIZE(pcm->chmap)); - if (prepared) - hdac_hdmi_setup_audio_infoframe(edev, pcm, port); + list_for_each_entry(port, &pcm->port_list, head) + if (prepared) + hdac_hdmi_setup_audio_infoframe(edev, pcm, port); mutex_unlock(&pcm->lock); }
@@ -1730,9 +1772,11 @@ static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx) struct hdac_ext_device *edev = to_ehdac_device(hdac); struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); - struct hdac_hdmi_port *port = pcm->port;
- return port ? true:false; + if (list_empty(&pcm->port_list)) + return false; + + return true; }
static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx) @@ -1740,7 +1784,15 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx) struct hdac_ext_device *edev = to_ehdac_device(hdac); struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); - struct hdac_hdmi_port *port = pcm->port; + struct hdac_hdmi_port *port; + + if (list_empty(&pcm->port_list)) + return 0; + + port = list_first_entry(&pcm->port_list, struct hdac_hdmi_port, head); + + if (!port) + return 0;
if (!port || !port->eld.eld_valid) return 0; @@ -1818,13 +1870,19 @@ static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) struct hdac_hdmi_pin *pin, *pin_next; struct hdac_hdmi_cvt *cvt, *cvt_next; struct hdac_hdmi_pcm *pcm, *pcm_next; + struct hdac_hdmi_port *port; int i;
snd_soc_unregister_codec(&edev->hdac.dev);
list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) { pcm->cvt = NULL; - pcm->port = NULL; + if (list_empty(&pcm->port_list)) + continue; + + list_for_each_entry(port, &pcm->port_list, head) + port = NULL; + list_del(&pcm->head); kfree(pcm); }
The patch
ASoC: hdac_hdmi: Add support for multiple ports to a PCM
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 e0e5d3e5a53b3bc354c18030b78b7ebcb33e004b Mon Sep 17 00:00:00 2001
From: Jeeja KP jeeja.kp@intel.com Date: Tue, 7 Feb 2017 19:09:48 +0530 Subject: [PATCH] ASoC: hdac_hdmi: Add support for multiple ports to a PCM
Since we have the MST feature enabled and Pin-Port mux for user to select the converter routing, multiple port mapping to same converter needs to be supported.
To support multiple port mapped to same converter following changes are done for this:. o Add port list to pcm, so that multiple ports can be mapped to a PCM. o Jack reporting in case where multiple port are attached to same PCM. o Change hdac_hdmi_get_port_from_cvt(), channel_map, remove functions to parse through all ports mapped to same the PCM.
Signed-off-by: Jeeja KP jeeja.kp@intel.com Acked-by: Vinod Koul vinod.koul@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/codecs/hdac_hdmi.c | 168 +++++++++++++++++++++++++++++-------------- 1 file changed, 113 insertions(+), 55 deletions(-)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 6cf86a0a118c..f8b6e9f1c6f6 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -89,6 +89,7 @@ struct hdac_hdmi_pin { };
struct hdac_hdmi_port { + struct list_head head; int id; struct hdac_hdmi_pin *pin; int num_mux_nids; @@ -99,7 +100,7 @@ struct hdac_hdmi_port { struct hdac_hdmi_pcm { struct list_head head; int pcm_id; - struct hdac_hdmi_port *port; + struct list_head port_list; struct hdac_hdmi_cvt *cvt; struct snd_jack *jack; int stream_tag; @@ -108,6 +109,7 @@ struct hdac_hdmi_pcm { bool chmap_set; unsigned char chmap[8]; /* ALSA API channel-map */ struct mutex lock; + int jack_event; };
struct hdac_hdmi_dai_port_map { @@ -142,6 +144,37 @@ hdac_hdmi_get_pcm_from_cvt(struct hdac_hdmi_priv *hdmi, return pcm; }
+static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm, + struct hdac_hdmi_port *port, bool is_connect) +{ + struct hdac_ext_device *edev = port->pin->edev; + + if (is_connect) { + /* + * Report Jack connect event when a device is connected + * for the first time where same PCM is attached to multiple + * ports. + */ + if (pcm->jack_event == 0) { + dev_dbg(&edev->hdac.dev, + "jack report for pcm=%d\n", + pcm->pcm_id); + snd_jack_report(pcm->jack, SND_JACK_AVOUT); + } + pcm->jack_event++; + } else { + /* + * Report Jack disconnect event when a device is disconnected + * is the only last connected device when same PCM is attached + * to multiple ports. + */ + if (pcm->jack_event == 1) + snd_jack_report(pcm->jack, 0); + if (pcm->jack_event > 0) + pcm->jack_event--; + } +} + /* MST supported verbs */ /* * Get the no devices that can be connected to a port on the Pin widget. @@ -484,19 +517,24 @@ static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt(
list_for_each_entry(pcm, &hdmi->pcm_list, head) { if (pcm->cvt == cvt) { - port = pcm->port; - break; - } - } - - if (port) { - ret = hdac_hdmi_query_port_connlist(edev, port->pin, port); - if (ret < 0) - return NULL; + if (list_empty(&pcm->port_list)) + continue;
- for (i = 0; i < port->num_mux_nids; i++) { - if (port->mux_nids[i] == cvt->nid) - return port; + list_for_each_entry(port, &pcm->port_list, head) { + mutex_lock(&pcm->lock); + ret = hdac_hdmi_query_port_connlist(edev, + port->pin, port); + mutex_unlock(&pcm->lock); + if (ret < 0) + continue; + + for (i = 0; i < port->num_mux_nids; i++) { + if (port->mux_nids[i] == cvt->nid && + port->eld.monitor_present && + port->eld.eld_valid) + return port; + } + } } }
@@ -529,7 +567,6 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, */ if (!port) return 0; - if ((!port->eld.monitor_present) || (!port->eld.eld_valid)) {
@@ -645,13 +682,16 @@ static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev, { struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm = NULL; + struct hdac_hdmi_port *p;
list_for_each_entry(pcm, &hdmi->pcm_list, head) { - if (!pcm->port) + if (list_empty(&pcm->port_list)) continue;
- if (pcm->port == port) - return pcm; + list_for_each_entry(p, &pcm->port_list, head) { + if (p->id == port->id && port->pin == p->pin) + return pcm; + } }
return NULL; @@ -802,6 +842,7 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int ret; + struct hdac_hdmi_port *p, *p_next; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); struct snd_soc_dapm_context *dapm = w->dapm; @@ -820,25 +861,30 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol,
mutex_lock(&hdmi->pin_mutex); list_for_each_entry(pcm, &hdmi->pcm_list, head) { - if (!pcm->port && pcm->port == port && - pcm->port->id == port->id) - pcm->port = NULL; + if (list_empty(&pcm->port_list)) + continue;
- /* - * Jack status is not reported during device probe as the - * PCMs are not registered by then. So report it here. - */ - if (!strcmp(cvt_name, pcm->cvt->name) && !pcm->port) { - pcm->port = port; - if (port->eld.monitor_present && port->eld.eld_valid) { - dev_dbg(&edev->hdac.dev, - "jack report for pcm=%d\n", - pcm->pcm_id); + list_for_each_entry_safe(p, p_next, &pcm->port_list, head) { + if (p == port && p->id == port->id && + p->pin == port->pin) { + hdac_hdmi_jack_report(pcm, port, false); + list_del(&p->head); + } + } + }
- snd_jack_report(pcm->jack, SND_JACK_AVOUT); + /* + * Jack status is not reported during device probe as the + * PCMs are not registered by then. So report it here. + */ + list_for_each_entry(pcm, &hdmi->pcm_list, head) { + if (!strcmp(cvt_name, pcm->cvt->name)) { + list_add_tail(&port->head, &pcm->port_list); + if (port->eld.monitor_present && port->eld.eld_valid) { + hdac_hdmi_jack_report(pcm, port, true); + mutex_unlock(&hdmi->pin_mutex); + return ret; } - mutex_unlock(&hdmi->pin_mutex); - return ret; } } mutex_unlock(&hdmi->pin_mutex); @@ -1186,7 +1232,7 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin,
if (!port->eld.monitor_present || !port->eld.eld_valid) {
- dev_dbg(&edev->hdac.dev, "%s: disconnect for pin:port %d:%d\n", + dev_err(&edev->hdac.dev, "%s: disconnect for pin:port %d:%d\n", __func__, pin->nid, port->id);
/* @@ -1194,25 +1240,16 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, * report jack here. It will be done in usermode mux * control select. */ - if (pcm) { - dev_dbg(&edev->hdac.dev, - "jack report for pcm=%d\n", pcm->pcm_id); - - snd_jack_report(pcm->jack, 0); - } + if (pcm) + hdac_hdmi_jack_report(pcm, port, false);
mutex_unlock(&hdmi->pin_mutex); return; }
if (port->eld.monitor_present && port->eld.eld_valid) { - if (pcm) { - dev_dbg(&edev->hdac.dev, - "jack report for pcm=%d\n", - pcm->pcm_id); - - snd_jack_report(pcm->jack, SND_JACK_AVOUT); - } + if (pcm) + hdac_hdmi_jack_report(pcm, port, true);
print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1, port->eld.eld_buffer, port->eld.eld_size, false); @@ -1540,8 +1577,9 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) return -ENOMEM; pcm->pcm_id = device; pcm->cvt = hdmi->dai_map[dai->id].cvt; + pcm->jack_event = 0; mutex_init(&pcm->lock); - + INIT_LIST_HEAD(&pcm->port_list); snd_pcm = hdac_hdmi_get_pcm_from_id(dai->component->card, device); if (snd_pcm) { err = snd_hdac_add_chmap_ctls(snd_pcm, device, &hdmi->chmap); @@ -1716,13 +1754,17 @@ static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx, struct hdac_ext_device *edev = to_ehdac_device(hdac); struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); - struct hdac_hdmi_port *port = pcm->port; + struct hdac_hdmi_port *port; + + if (list_empty(&pcm->port_list)) + return;
mutex_lock(&pcm->lock); pcm->chmap_set = true; memcpy(pcm->chmap, chmap, ARRAY_SIZE(pcm->chmap)); - if (prepared) - hdac_hdmi_setup_audio_infoframe(edev, pcm, port); + list_for_each_entry(port, &pcm->port_list, head) + if (prepared) + hdac_hdmi_setup_audio_infoframe(edev, pcm, port); mutex_unlock(&pcm->lock); }
@@ -1731,9 +1773,11 @@ static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx) struct hdac_ext_device *edev = to_ehdac_device(hdac); struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); - struct hdac_hdmi_port *port = pcm->port;
- return port ? true:false; + if (list_empty(&pcm->port_list)) + return false; + + return true; }
static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx) @@ -1741,7 +1785,15 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx) struct hdac_ext_device *edev = to_ehdac_device(hdac); struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); - struct hdac_hdmi_port *port = pcm->port; + struct hdac_hdmi_port *port; + + if (list_empty(&pcm->port_list)) + return 0; + + port = list_first_entry(&pcm->port_list, struct hdac_hdmi_port, head); + + if (!port) + return 0;
if (!port || !port->eld.eld_valid) return 0; @@ -1819,13 +1871,19 @@ static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) struct hdac_hdmi_pin *pin, *pin_next; struct hdac_hdmi_cvt *cvt, *cvt_next; struct hdac_hdmi_pcm *pcm, *pcm_next; + struct hdac_hdmi_port *port; int i;
snd_soc_unregister_codec(&edev->hdac.dev);
list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) { pcm->cvt = NULL; - pcm->port = NULL; + if (list_empty(&pcm->port_list)) + continue; + + list_for_each_entry(port, &pcm->port_list, head) + port = NULL; + list_del(&pcm->head); kfree(pcm); }
From: Jeeja KP jeeja.kp@intel.com
Use snd_soc_jack instead of snd_jack and create the jack in machine driver and pass the jack pointer to hdac_hdmi driver for jack reporting.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/codecs/hdac_hdmi.c | 19 ++++++++----------- sound/soc/codecs/hdac_hdmi.h | 3 ++- 2 files changed, 10 insertions(+), 12 deletions(-)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 0c4531b..8c950f4 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -102,7 +102,7 @@ struct hdac_hdmi_pcm { int pcm_id; struct list_head port_list; struct hdac_hdmi_cvt *cvt; - struct snd_jack *jack; + struct snd_soc_jack *jack; int stream_tag; int channels; int format; @@ -159,7 +159,8 @@ static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm, dev_dbg(&edev->hdac.dev, "jack report for pcm=%d\n", pcm->pcm_id); - snd_jack_report(pcm->jack, SND_JACK_AVOUT); + snd_soc_jack_report(pcm->jack, SND_JACK_AVOUT, + SND_JACK_AVOUT); } pcm->jack_event++; } else { @@ -169,7 +170,7 @@ static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm, * to multiple ports. */ if (pcm->jack_event == 1) - snd_jack_report(pcm->jack, 0); + snd_soc_jack_report(pcm->jack, 0, SND_JACK_AVOUT); if (pcm->jack_event > 0) pcm->jack_event--; } @@ -1555,13 +1556,11 @@ static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card, return NULL; }
-int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) +int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device, + struct snd_soc_jack *jack) { - char jack_name[NAME_SIZE]; struct snd_soc_codec *codec = dai->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); struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm; struct snd_pcm *snd_pcm; @@ -1577,6 +1576,7 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) pcm->pcm_id = device; pcm->cvt = hdmi->dai_map[dai->id].cvt; pcm->jack_event = 0; + pcm->jack = jack; mutex_init(&pcm->lock); INIT_LIST_HEAD(&pcm->port_list); snd_pcm = hdac_hdmi_get_pcm_from_id(dai->component->card, device); @@ -1593,10 +1593,7 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device)
list_add_tail(&pcm->head, &hdmi->pcm_list);
- sprintf(jack_name, "HDMI/DP, pcm=%d Jack", device); - - return snd_jack_new(dapm->card->snd_card, jack_name, - SND_JACK_AVOUT, &pcm->jack, true, false); + return 0; } EXPORT_SYMBOL_GPL(hdac_hdmi_jack_init);
diff --git a/sound/soc/codecs/hdac_hdmi.h b/sound/soc/codecs/hdac_hdmi.h index 8dfd1e0..bf7edb3 100644 --- a/sound/soc/codecs/hdac_hdmi.h +++ b/sound/soc/codecs/hdac_hdmi.h @@ -1,6 +1,7 @@ #ifndef __HDAC_HDMI_H__ #define __HDAC_HDMI_H__
-int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int pcm); +int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int pcm, + struct snd_soc_jack *jack);
#endif /* __HDAC_HDMI_H__ */
The patch
ASoC: hdac_hdmi: Use ASoC jack instead of snd_jack
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 624900163d060f15d71ff383104a909737de770c Mon Sep 17 00:00:00 2001
From: Jeeja KP jeeja.kp@intel.com Date: Tue, 7 Feb 2017 19:09:49 +0530 Subject: [PATCH] ASoC: hdac_hdmi: Use ASoC jack instead of snd_jack
Use snd_soc_jack instead of snd_jack and create the jack in machine driver and pass the jack pointer to hdac_hdmi driver for jack reporting.
Signed-off-by: Jeeja KP jeeja.kp@intel.com Acked-by: Vinod Koul vinod.koul@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/codecs/hdac_hdmi.c | 19 ++++++++----------- sound/soc/codecs/hdac_hdmi.h | 3 ++- 2 files changed, 10 insertions(+), 12 deletions(-)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index f8b6e9f1c6f6..0f2c1e823281 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -102,7 +102,7 @@ struct hdac_hdmi_pcm { int pcm_id; struct list_head port_list; struct hdac_hdmi_cvt *cvt; - struct snd_jack *jack; + struct snd_soc_jack *jack; int stream_tag; int channels; int format; @@ -159,7 +159,8 @@ static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm, dev_dbg(&edev->hdac.dev, "jack report for pcm=%d\n", pcm->pcm_id); - snd_jack_report(pcm->jack, SND_JACK_AVOUT); + snd_soc_jack_report(pcm->jack, SND_JACK_AVOUT, + SND_JACK_AVOUT); } pcm->jack_event++; } else { @@ -169,7 +170,7 @@ static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm, * to multiple ports. */ if (pcm->jack_event == 1) - snd_jack_report(pcm->jack, 0); + snd_soc_jack_report(pcm->jack, 0, SND_JACK_AVOUT); if (pcm->jack_event > 0) pcm->jack_event--; } @@ -1556,13 +1557,11 @@ static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card, return NULL; }
-int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) +int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device, + struct snd_soc_jack *jack) { - char jack_name[NAME_SIZE]; struct snd_soc_codec *codec = dai->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); struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_pcm *pcm; struct snd_pcm *snd_pcm; @@ -1578,6 +1577,7 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) pcm->pcm_id = device; pcm->cvt = hdmi->dai_map[dai->id].cvt; pcm->jack_event = 0; + pcm->jack = jack; mutex_init(&pcm->lock); INIT_LIST_HEAD(&pcm->port_list); snd_pcm = hdac_hdmi_get_pcm_from_id(dai->component->card, device); @@ -1594,10 +1594,7 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device)
list_add_tail(&pcm->head, &hdmi->pcm_list);
- sprintf(jack_name, "HDMI/DP, pcm=%d Jack", device); - - return snd_jack_new(dapm->card->snd_card, jack_name, - SND_JACK_AVOUT, &pcm->jack, true, false); + return 0; } EXPORT_SYMBOL_GPL(hdac_hdmi_jack_init);
diff --git a/sound/soc/codecs/hdac_hdmi.h b/sound/soc/codecs/hdac_hdmi.h index 8dfd1e0b57b3..bf7edb3227d2 100644 --- a/sound/soc/codecs/hdac_hdmi.h +++ b/sound/soc/codecs/hdac_hdmi.h @@ -1,6 +1,7 @@ #ifndef __HDAC_HDMI_H__ #define __HDAC_HDMI_H__
-int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int pcm); +int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int pcm, + struct snd_soc_jack *jack);
#endif /* __HDAC_HDMI_H__ */
From: Jeeja KP jeeja.kp@intel.com
Creates ASoC jack for HDMI pcm and calls hdmi codec API to initialize jack in skl_rt268 machine
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/intel/boards/skl_rt286.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index 5e56af3..11647b0 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -29,6 +29,7 @@ #include "../../codecs/hdac_hdmi.h"
static struct snd_soc_jack skylake_headset; +static struct snd_soc_jack skylake_hdmi[3];
struct skl_hdmi_pcm { struct list_head head; @@ -458,16 +459,30 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { }, };
+#define NAME_SIZE 32 static int skylake_card_late_probe(struct snd_soc_card *card) { struct skl_rt286_private *ctx = snd_soc_card_get_drvdata(card); struct skl_hdmi_pcm *pcm; - int err; + int err, i = 0; + char jack_name[NAME_SIZE];
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device); + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &skylake_hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &skylake_hdmi[i]); if (err < 0) return err; + + i++; }
return 0;
The patch
ASoC: Intel: Skylake: Create ASoC jack for hdmi in rt286 machine
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 f3af359242f58b9c5f6f78ff4d13e8f108514bc0 Mon Sep 17 00:00:00 2001
From: Jeeja KP jeeja.kp@intel.com Date: Tue, 7 Feb 2017 19:09:50 +0530 Subject: [PATCH] ASoC: Intel: Skylake: Create ASoC jack for hdmi in rt286 machine
Creates ASoC jack for HDMI pcm and calls hdmi codec API to initialize jack in skl_rt268 machine
Signed-off-by: Jeeja KP jeeja.kp@intel.com Acked-by: Vinod Koul vinod.koul@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/boards/skl_rt286.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index 5e56af3a6ee3..11647b0ea147 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -29,6 +29,7 @@ #include "../../codecs/hdac_hdmi.h"
static struct snd_soc_jack skylake_headset; +static struct snd_soc_jack skylake_hdmi[3];
struct skl_hdmi_pcm { struct list_head head; @@ -458,16 +459,30 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { }, };
+#define NAME_SIZE 32 static int skylake_card_late_probe(struct snd_soc_card *card) { struct skl_rt286_private *ctx = snd_soc_card_get_drvdata(card); struct skl_hdmi_pcm *pcm; - int err; + int err, i = 0; + char jack_name[NAME_SIZE];
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device); + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &skylake_hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &skylake_hdmi[i]); if (err < 0) return err; + + i++; }
return 0;
From: Jeeja KP jeeja.kp@intel.com
Creates ASoC jack for HDMI PCM and calls hdmi codec API to initialize jack in skl_nau88l25_max98357a machine
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/intel/boards/skl_nau88l25_max98357a.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index 57acc58..5a5173f 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -32,6 +32,7 @@ static struct snd_soc_jack skylake_headset; static struct snd_soc_card skylake_audio_card; static const struct snd_pcm_hw_constraint_list *dmic_constraints; +static struct snd_soc_jack skylake_hdmi[3];
struct skl_hdmi_pcm { struct list_head head; @@ -637,16 +638,31 @@ static struct snd_soc_dai_link skylake_dais[] = { }, };
+#define NAME_SIZE 32 static int skylake_card_late_probe(struct snd_soc_card *card) { struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(card); struct skl_hdmi_pcm *pcm; - int err; + int err, i = 0; + char jack_name[NAME_SIZE];
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device); + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, + &skylake_hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &skylake_hdmi[i]); if (err < 0) return err; + + i++; }
return 0;
The patch
ASoC: Intel: Skylake: Create ASoC jack for hdmi in skl_nau88l25_max98357a machine
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 c541b2dd45042c1e031778e0229d032dff90f045 Mon Sep 17 00:00:00 2001
From: Jeeja KP jeeja.kp@intel.com Date: Tue, 7 Feb 2017 19:09:51 +0530 Subject: [PATCH] ASoC: Intel: Skylake: Create ASoC jack for hdmi in skl_nau88l25_max98357a machine
Creates ASoC jack for HDMI PCM and calls hdmi codec API to initialize jack in skl_nau88l25_max98357a machine
Signed-off-by: Jeeja KP jeeja.kp@intel.com Acked-by: Vinod Koul vinod.koul@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/boards/skl_nau88l25_max98357a.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index bb4196867752..48f7c96b3f3d 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -32,6 +32,7 @@ static struct snd_soc_jack skylake_headset; static struct snd_soc_card skylake_audio_card; static const struct snd_pcm_hw_constraint_list *dmic_constraints; +static struct snd_soc_jack skylake_hdmi[3];
struct skl_hdmi_pcm { struct list_head head; @@ -603,16 +604,31 @@ static struct snd_soc_dai_link skylake_dais[] = { }, };
+#define NAME_SIZE 32 static int skylake_card_late_probe(struct snd_soc_card *card) { struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(card); struct skl_hdmi_pcm *pcm; - int err; + int err, i = 0; + char jack_name[NAME_SIZE];
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device); + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, + &skylake_hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &skylake_hdmi[i]); if (err < 0) return err; + + i++; }
return 0;
From: Jeeja KP jeeja.kp@intel.com
Creates ASoC jack for HDMI PCM and calls hdmi codec API to initialize jack in skl_nau88l25_ssm4567 machine
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 41117bc..5deb68f 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -36,6 +36,7 @@ static struct snd_soc_jack skylake_headset; static struct snd_soc_card skylake_audio_card; static const struct snd_pcm_hw_constraint_list *dmic_constraints; +static struct snd_soc_jack skylake_hdmi[3];
struct skl_hdmi_pcm { struct list_head head; @@ -654,16 +655,31 @@ static struct snd_soc_dai_link skylake_dais[] = { }, };
+#define NAME_SIZE 32 static int skylake_card_late_probe(struct snd_soc_card *card) { struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(card); struct skl_hdmi_pcm *pcm; - int err; + int err, i = 0; + char jack_name[NAME_SIZE];
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device); + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, + &skylake_hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &skylake_hdmi[i]); if (err < 0) return err; + + i++; }
return 0;
The patch
ASoC: Intel: Skylake: Create ASoC jack for hdmi in nau88l25_ssm4567 machine
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 9e4278cd9b8e6e6464a4eb5e65c2b232076aa6c6 Mon Sep 17 00:00:00 2001
From: Jeeja KP jeeja.kp@intel.com Date: Tue, 7 Feb 2017 19:09:52 +0530 Subject: [PATCH] ASoC: Intel: Skylake: Create ASoC jack for hdmi in nau88l25_ssm4567 machine
Creates ASoC jack for HDMI PCM and calls hdmi codec API to initialize jack in skl_nau88l25_ssm4567 machine
Signed-off-by: Jeeja KP jeeja.kp@intel.com Acked-by: Vinod Koul vinod.koul@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 41117bc51450..5deb68f0c1f0 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -36,6 +36,7 @@ static struct snd_soc_jack skylake_headset; static struct snd_soc_card skylake_audio_card; static const struct snd_pcm_hw_constraint_list *dmic_constraints; +static struct snd_soc_jack skylake_hdmi[3];
struct skl_hdmi_pcm { struct list_head head; @@ -654,16 +655,31 @@ static struct snd_soc_dai_link skylake_dais[] = { }, };
+#define NAME_SIZE 32 static int skylake_card_late_probe(struct snd_soc_card *card) { struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(card); struct skl_hdmi_pcm *pcm; - int err; + int err, i = 0; + char jack_name[NAME_SIZE];
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device); + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, + &skylake_hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &skylake_hdmi[i]); if (err < 0) return err; + + i++; }
return 0;
From: Jeeja KP jeeja.kp@intel.com
Creates ASoC jack for HDMI PCM and calls hdmi codec API to initialize jack in bxt_rt298.c machine
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/intel/boards/bxt_rt298.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index 09be868..d5f53a6 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -28,6 +28,7 @@
/* Headset jack detection DAPM pins */ static struct snd_soc_jack broxton_headset; +static struct snd_soc_jack broxton_hdmi[3];
struct bxt_hdmi_pcm { struct list_head head; @@ -453,16 +454,30 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = { }, };
+#define NAME_SIZE 32 static int bxt_card_late_probe(struct snd_soc_card *card) { struct bxt_rt286_private *ctx = snd_soc_card_get_drvdata(card); struct bxt_hdmi_pcm *pcm; - int err; + int err, i = 0; + char jack_name[NAME_SIZE];
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device); + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &broxton_hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &broxton_hdmi[i]); if (err < 0) return err; + + i++; }
return 0;
The patch
ASoC: Intel: bxt: Create ASoC jack for hdmi in bxt_rt298 machine
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 7932b8ace390c4474d1dc62d7843e843bc3ae9b5 Mon Sep 17 00:00:00 2001
From: Jeeja KP jeeja.kp@intel.com Date: Tue, 7 Feb 2017 19:09:53 +0530 Subject: [PATCH] ASoC: Intel: bxt: Create ASoC jack for hdmi in bxt_rt298 machine
Creates ASoC jack for HDMI PCM and calls hdmi codec API to initialize jack in bxt_rt298.c machine
Signed-off-by: Jeeja KP jeeja.kp@intel.com Acked-by: Vinod Koul vinod.koul@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/boards/bxt_rt298.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index 09be868833d1..d5f53a6de041 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -28,6 +28,7 @@
/* Headset jack detection DAPM pins */ static struct snd_soc_jack broxton_headset; +static struct snd_soc_jack broxton_hdmi[3];
struct bxt_hdmi_pcm { struct list_head head; @@ -453,16 +454,30 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = { }, };
+#define NAME_SIZE 32 static int bxt_card_late_probe(struct snd_soc_card *card) { struct bxt_rt286_private *ctx = snd_soc_card_get_drvdata(card); struct bxt_hdmi_pcm *pcm; - int err; + int err, i = 0; + char jack_name[NAME_SIZE];
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device); + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &broxton_hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &broxton_hdmi[i]); if (err < 0) return err; + + i++; }
return 0;
From: Jeeja KP jeeja.kp@intel.com
Creates ASoC jack for HDMI PCM and calls hdmi codec API to initialize jack in bxt_da7219_max98357 machine
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 36c3589..35d95b4 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -33,6 +33,7 @@ #define QUAD_CHANNEL 4
static struct snd_soc_jack broxton_headset; +static struct snd_soc_jack broxton_hdmi[3];
struct bxt_hdmi_pcm { struct list_head head; @@ -552,16 +553,30 @@ static struct snd_soc_dai_link broxton_dais[] = { }, };
+#define NAME_SIZE 32 static int bxt_card_late_probe(struct snd_soc_card *card) { struct bxt_card_private *ctx = snd_soc_card_get_drvdata(card); struct bxt_hdmi_pcm *pcm; - int err; + int err, i = 0; + char jack_name[NAME_SIZE];
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device); + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &broxton_hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &broxton_hdmi[i]); if (err < 0) return err; + + i++; }
return 0;
The patch
ASoC: Intel: bxt: Create ASoC jack for hdmi in bxt_da7219_max98357 machine
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 625de2bf2ed1632cb74a4a38f8f09a2063fb74af Mon Sep 17 00:00:00 2001
From: Jeeja KP jeeja.kp@intel.com Date: Tue, 7 Feb 2017 19:09:54 +0530 Subject: [PATCH] ASoC: Intel: bxt: Create ASoC jack for hdmi in bxt_da7219_max98357 machine
Creates ASoC jack for HDMI PCM and calls hdmi codec API to initialize jack in bxt_da7219_max98357 machine
Signed-off-by: Jeeja KP jeeja.kp@intel.com Acked-by: Vinod Koul vinod.koul@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index a9647a27ebc2..18f3d0e1a6b2 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -33,6 +33,7 @@ #define QUAD_CHANNEL 4
static struct snd_soc_jack broxton_headset; +static struct snd_soc_jack broxton_hdmi[3];
struct bxt_hdmi_pcm { struct list_head head; @@ -517,16 +518,30 @@ static struct snd_soc_dai_link broxton_dais[] = { }, };
+#define NAME_SIZE 32 static int bxt_card_late_probe(struct snd_soc_card *card) { struct bxt_card_private *ctx = snd_soc_card_get_drvdata(card); struct bxt_hdmi_pcm *pcm; - int err; + int err, i = 0; + char jack_name[NAME_SIZE];
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device); + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &broxton_hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &broxton_hdmi[i]); if (err < 0) return err; + + i++; }
return 0;
From: Jeeja KP jeeja.kp@intel.com
Represent each port as machine DAPM pin widget. This helps in enable/disable pin when monitor is connected/disconnected in case pcm is rendered to multiple ports.
Create machine pin widgets and pin switch kcontrol for each port and report based on the pin status
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/codecs/hdac_hdmi.c | 130 +++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/hdac_hdmi.h | 2 + 2 files changed, 132 insertions(+)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 8c950f4..a6d28c6 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -95,6 +95,9 @@ struct hdac_hdmi_port { int num_mux_nids; hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; struct hdac_hdmi_eld eld; + const char *jack_pin; + struct snd_soc_dapm_context *dapm; + const char *output_pin; };
struct hdac_hdmi_pcm { @@ -149,6 +152,11 @@ static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm, { struct hdac_ext_device *edev = port->pin->edev;
+ if (is_connect) + snd_soc_dapm_enable_pin(port->dapm, port->jack_pin); + else + snd_soc_dapm_disable_pin(port->dapm, port->jack_pin); + if (is_connect) { /* * Report Jack connect event when a device is connected @@ -174,6 +182,8 @@ static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm, if (pcm->jack_event > 0) pcm->jack_event--; } + + snd_soc_dapm_sync(port->dapm); }
/* MST supported verbs */ @@ -1059,6 +1069,7 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) SND_SOC_DAPM_POST_PMD); if (ret < 0) return ret; + pin->ports[j].output_pin = widgets[i].name; i++; } } @@ -1556,6 +1567,125 @@ static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card, return NULL; }
+/* create jack pin kcontrols */ +static int create_fill_jack_kcontrols(struct snd_soc_card *card, + struct hdac_ext_device *edev) +{ + struct hdac_hdmi_pin *pin; + struct snd_kcontrol_new *kc; + char kc_name[NAME_SIZE], xname[NAME_SIZE]; + char *name; + int i = 0, j; + struct snd_soc_codec *codec = edev->scodec; + struct hdac_hdmi_priv *hdmi = edev->private_data; + + kc = devm_kcalloc(codec->dev, hdmi->num_ports, + sizeof(*kc), GFP_KERNEL); + + if (!kc) + return -ENOMEM; + + list_for_each_entry(pin, &hdmi->pin_list, head) { + for (j = 0; j < pin->num_ports; j++) { + snprintf(xname, sizeof(xname), "hif%d-%d Jack", + pin->nid, pin->ports[j].id); + name = devm_kstrdup(codec->dev, xname, GFP_KERNEL); + if (!name) + return -ENOMEM; + snprintf(kc_name, sizeof(kc_name), "%s Switch", xname); + kc[i].name = devm_kstrdup(codec->dev, kc_name, + GFP_KERNEL); + if (!kc[i].name) + return -ENOMEM; + + kc[i].private_value = (unsigned long)name; + kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + kc[i].access = 0; + kc[i].info = snd_soc_dapm_info_pin_switch; + kc[i].put = snd_soc_dapm_put_pin_switch; + kc[i].get = snd_soc_dapm_get_pin_switch; + i++; + } + } + + return snd_soc_add_card_controls(card, kc, i); +} + +int hdac_hdmi_jack_port_init(struct snd_soc_codec *codec, + struct snd_soc_dapm_context *dapm) +{ + struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_pin *pin; + struct snd_soc_dapm_widget *widgets; + struct snd_soc_dapm_route *route; + char w_name[NAME_SIZE]; + int i = 0, j, ret; + + widgets = devm_kcalloc(dapm->dev, hdmi->num_ports, + sizeof(*widgets), GFP_KERNEL); + + if (!widgets) + return -ENOMEM; + + route = devm_kcalloc(dapm->dev, hdmi->num_ports, + sizeof(*route), GFP_KERNEL); + if (!route) + return -ENOMEM; + + /* create Jack DAPM widget */ + list_for_each_entry(pin, &hdmi->pin_list, head) { + for (j = 0; j < pin->num_ports; j++) { + snprintf(w_name, sizeof(w_name), "hif%d-%d Jack", + pin->nid, pin->ports[j].id); + + ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i], + snd_soc_dapm_spk, NULL, + w_name, NULL, NULL, 0, NULL, 0); + if (ret < 0) + return ret; + + pin->ports[j].jack_pin = widgets[i].name; + pin->ports[j].dapm = dapm; + + /* add to route from Jack widget to output */ + hdac_hdmi_fill_route(&route[i], pin->ports[j].jack_pin, + NULL, pin->ports[j].output_pin, NULL); + + i++; + } + } + + /* Add Route from Jack widget to the output widget */ + ret = snd_soc_dapm_new_controls(dapm, widgets, hdmi->num_ports); + if (ret < 0) + return ret; + + ret = snd_soc_dapm_add_routes(dapm, route, hdmi->num_ports); + if (ret < 0) + return ret; + + ret = snd_soc_dapm_new_widgets(dapm->card); + if (ret < 0) + return ret; + + /* Add Jack Pin switch Kcontrol */ + ret = create_fill_jack_kcontrols(dapm->card, edev); + + if (ret < 0) + return ret; + + /* default set the Jack Pin switch to OFF */ + list_for_each_entry(pin, &hdmi->pin_list, head) { + for (j = 0; j < pin->num_ports; j++) + snd_soc_dapm_disable_pin(pin->ports[j].dapm, + pin->ports[j].jack_pin); + } + + return 0; +} +EXPORT_SYMBOL_GPL(hdac_hdmi_jack_port_init); + int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device, struct snd_soc_jack *jack) { diff --git a/sound/soc/codecs/hdac_hdmi.h b/sound/soc/codecs/hdac_hdmi.h index bf7edb3..dfc3a9c 100644 --- a/sound/soc/codecs/hdac_hdmi.h +++ b/sound/soc/codecs/hdac_hdmi.h @@ -4,4 +4,6 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int pcm, struct snd_soc_jack *jack);
+int hdac_hdmi_jack_port_init(struct snd_soc_codec *codec, + struct snd_soc_dapm_context *dapm); #endif /* __HDAC_HDMI_H__ */
The patch
ASoC: hdac_hdmi: Add machine pin widget for each port
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 0324e51b5ba405cd2d66e9e95430f6b9562d0ac0 Mon Sep 17 00:00:00 2001
From: Jeeja KP jeeja.kp@intel.com Date: Tue, 7 Feb 2017 19:09:55 +0530 Subject: [PATCH] ASoC: hdac_hdmi: Add machine pin widget for each port
Represent each port as machine DAPM pin widget. This helps in enable/disable pin when monitor is connected/disconnected in case pcm is rendered to multiple ports.
Create machine pin widgets and pin switch kcontrol for each port and report based on the pin status
Signed-off-by: Jeeja KP jeeja.kp@intel.com Acked-by: Vinod Koul vinod.koul@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/codecs/hdac_hdmi.c | 130 +++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/hdac_hdmi.h | 2 + 2 files changed, 132 insertions(+)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 0f2c1e823281..0a5510a3a8e1 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -95,6 +95,9 @@ struct hdac_hdmi_port { int num_mux_nids; hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; struct hdac_hdmi_eld eld; + const char *jack_pin; + struct snd_soc_dapm_context *dapm; + const char *output_pin; };
struct hdac_hdmi_pcm { @@ -149,6 +152,11 @@ static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm, { struct hdac_ext_device *edev = port->pin->edev;
+ if (is_connect) + snd_soc_dapm_enable_pin(port->dapm, port->jack_pin); + else + snd_soc_dapm_disable_pin(port->dapm, port->jack_pin); + if (is_connect) { /* * Report Jack connect event when a device is connected @@ -174,6 +182,8 @@ static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm, if (pcm->jack_event > 0) pcm->jack_event--; } + + snd_soc_dapm_sync(port->dapm); }
/* MST supported verbs */ @@ -1059,6 +1069,7 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) SND_SOC_DAPM_POST_PMD); if (ret < 0) return ret; + pin->ports[j].output_pin = widgets[i].name; i++; } } @@ -1557,6 +1568,125 @@ static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card, return NULL; }
+/* create jack pin kcontrols */ +static int create_fill_jack_kcontrols(struct snd_soc_card *card, + struct hdac_ext_device *edev) +{ + struct hdac_hdmi_pin *pin; + struct snd_kcontrol_new *kc; + char kc_name[NAME_SIZE], xname[NAME_SIZE]; + char *name; + int i = 0, j; + struct snd_soc_codec *codec = edev->scodec; + struct hdac_hdmi_priv *hdmi = edev->private_data; + + kc = devm_kcalloc(codec->dev, hdmi->num_ports, + sizeof(*kc), GFP_KERNEL); + + if (!kc) + return -ENOMEM; + + list_for_each_entry(pin, &hdmi->pin_list, head) { + for (j = 0; j < pin->num_ports; j++) { + snprintf(xname, sizeof(xname), "hif%d-%d Jack", + pin->nid, pin->ports[j].id); + name = devm_kstrdup(codec->dev, xname, GFP_KERNEL); + if (!name) + return -ENOMEM; + snprintf(kc_name, sizeof(kc_name), "%s Switch", xname); + kc[i].name = devm_kstrdup(codec->dev, kc_name, + GFP_KERNEL); + if (!kc[i].name) + return -ENOMEM; + + kc[i].private_value = (unsigned long)name; + kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + kc[i].access = 0; + kc[i].info = snd_soc_dapm_info_pin_switch; + kc[i].put = snd_soc_dapm_put_pin_switch; + kc[i].get = snd_soc_dapm_get_pin_switch; + i++; + } + } + + return snd_soc_add_card_controls(card, kc, i); +} + +int hdac_hdmi_jack_port_init(struct snd_soc_codec *codec, + struct snd_soc_dapm_context *dapm) +{ + struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_pin *pin; + struct snd_soc_dapm_widget *widgets; + struct snd_soc_dapm_route *route; + char w_name[NAME_SIZE]; + int i = 0, j, ret; + + widgets = devm_kcalloc(dapm->dev, hdmi->num_ports, + sizeof(*widgets), GFP_KERNEL); + + if (!widgets) + return -ENOMEM; + + route = devm_kcalloc(dapm->dev, hdmi->num_ports, + sizeof(*route), GFP_KERNEL); + if (!route) + return -ENOMEM; + + /* create Jack DAPM widget */ + list_for_each_entry(pin, &hdmi->pin_list, head) { + for (j = 0; j < pin->num_ports; j++) { + snprintf(w_name, sizeof(w_name), "hif%d-%d Jack", + pin->nid, pin->ports[j].id); + + ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i], + snd_soc_dapm_spk, NULL, + w_name, NULL, NULL, 0, NULL, 0); + if (ret < 0) + return ret; + + pin->ports[j].jack_pin = widgets[i].name; + pin->ports[j].dapm = dapm; + + /* add to route from Jack widget to output */ + hdac_hdmi_fill_route(&route[i], pin->ports[j].jack_pin, + NULL, pin->ports[j].output_pin, NULL); + + i++; + } + } + + /* Add Route from Jack widget to the output widget */ + ret = snd_soc_dapm_new_controls(dapm, widgets, hdmi->num_ports); + if (ret < 0) + return ret; + + ret = snd_soc_dapm_add_routes(dapm, route, hdmi->num_ports); + if (ret < 0) + return ret; + + ret = snd_soc_dapm_new_widgets(dapm->card); + if (ret < 0) + return ret; + + /* Add Jack Pin switch Kcontrol */ + ret = create_fill_jack_kcontrols(dapm->card, edev); + + if (ret < 0) + return ret; + + /* default set the Jack Pin switch to OFF */ + list_for_each_entry(pin, &hdmi->pin_list, head) { + for (j = 0; j < pin->num_ports; j++) + snd_soc_dapm_disable_pin(pin->ports[j].dapm, + pin->ports[j].jack_pin); + } + + return 0; +} +EXPORT_SYMBOL_GPL(hdac_hdmi_jack_port_init); + int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device, struct snd_soc_jack *jack) { diff --git a/sound/soc/codecs/hdac_hdmi.h b/sound/soc/codecs/hdac_hdmi.h index bf7edb3227d2..dfc3a9cf7199 100644 --- a/sound/soc/codecs/hdac_hdmi.h +++ b/sound/soc/codecs/hdac_hdmi.h @@ -4,4 +4,6 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int pcm, struct snd_soc_jack *jack);
+int hdac_hdmi_jack_port_init(struct snd_soc_codec *codec, + struct snd_soc_dapm_context *dapm); #endif /* __HDAC_HDMI_H__ */
From: Jeeja KP jeeja.kp@intel.com
After the pcm jack is created, create and initialize the pin switch widget for each port. Pin switch is to enable/disable the pin when monitor is connected/disconnected.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/intel/boards/skl_rt286.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index 11647b0..f5ab7b8 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -95,10 +95,6 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = { {"DMIC1 Pin", NULL, "DMIC2"}, {"DMic", NULL, "SoC DMIC"},
- {"HDMI1", NULL, "hif5-0 Output"}, - {"HDMI2", NULL, "hif6-0 Output"}, - {"HDMI3", NULL, "hif7-0 Output"}, - /* CODEC BE connections */ { "AIF1 Playback", NULL, "ssp0 Tx"}, { "ssp0 Tx", NULL, "codec0_out"}, @@ -464,10 +460,12 @@ static int skylake_card_late_probe(struct snd_soc_card *card) { struct skl_rt286_private *ctx = snd_soc_card_get_drvdata(card); struct skl_hdmi_pcm *pcm; + struct snd_soc_codec *codec = NULL; int err, i = 0; char jack_name[NAME_SIZE];
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + codec = pcm->codec_dai->codec; snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, @@ -485,7 +483,10 @@ static int skylake_card_late_probe(struct snd_soc_card *card) i++; }
- return 0; + if (!codec) + return -EINVAL; + + return hdac_hdmi_jack_port_init(codec, &card->dapm); }
/* skylake audio machine driver for SPT + RT286S */
The patch
ASoC: Intel: Skylake: Add jack port initialize in rt286 machine
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 64f8620d482d38ed093eca78d8ca9b1bb64a6172 Mon Sep 17 00:00:00 2001
From: Jeeja KP jeeja.kp@intel.com Date: Tue, 7 Feb 2017 19:09:56 +0530 Subject: [PATCH] ASoC: Intel: Skylake: Add jack port initialize in rt286 machine
After the pcm jack is created, create and initialize the pin switch widget for each port. Pin switch is to enable/disable the pin when monitor is connected/disconnected.
Signed-off-by: Jeeja KP jeeja.kp@intel.com Acked-by: Vinod Koul vinod.koul@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/boards/skl_rt286.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index 11647b0ea147..f5ab7b8d51d1 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -95,10 +95,6 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = { {"DMIC1 Pin", NULL, "DMIC2"}, {"DMic", NULL, "SoC DMIC"},
- {"HDMI1", NULL, "hif5-0 Output"}, - {"HDMI2", NULL, "hif6-0 Output"}, - {"HDMI3", NULL, "hif7-0 Output"}, - /* CODEC BE connections */ { "AIF1 Playback", NULL, "ssp0 Tx"}, { "ssp0 Tx", NULL, "codec0_out"}, @@ -464,10 +460,12 @@ static int skylake_card_late_probe(struct snd_soc_card *card) { struct skl_rt286_private *ctx = snd_soc_card_get_drvdata(card); struct skl_hdmi_pcm *pcm; + struct snd_soc_codec *codec = NULL; int err, i = 0; char jack_name[NAME_SIZE];
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + codec = pcm->codec_dai->codec; snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, @@ -485,7 +483,10 @@ static int skylake_card_late_probe(struct snd_soc_card *card) i++; }
- return 0; + if (!codec) + return -EINVAL; + + return hdac_hdmi_jack_port_init(codec, &card->dapm); }
/* skylake audio machine driver for SPT + RT286S */
From: Jeeja KP jeeja.kp@intel.com
After the pcm jack is created, create and initialize the pin switch widget for each port. Pin switch is to enable/disable the pin when monitor is connected/disconnected.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/intel/boards/skl_nau88l25_max98357a.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index 5a5173f..e66aba9 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -164,9 +164,6 @@ static const struct snd_soc_dapm_route skylake_map[] = { { "MIC", NULL, "Headset Mic" }, { "DMic", NULL, "SoC DMIC" },
- {"DP1", NULL, "hif5-0 Output"}, - {"DP2", NULL, "hif6-0 Output"}, - /* CODEC BE connections */ { "HiFi Playback", NULL, "ssp0 Tx" }, { "ssp0 Tx", NULL, "codec0_out" }, @@ -643,10 +640,12 @@ static int skylake_card_late_probe(struct snd_soc_card *card) { struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(card); struct skl_hdmi_pcm *pcm; + struct snd_soc_codec *codec = NULL; int err, i = 0; char jack_name[NAME_SIZE];
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + codec = pcm->codec_dai->codec; snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, @@ -665,7 +664,10 @@ static int skylake_card_late_probe(struct snd_soc_card *card) i++; }
- return 0; + if (!codec) + return -EINVAL; + + return hdac_hdmi_jack_port_init(codec, &card->dapm); }
/* skylake audio machine driver for SPT + NAU88L25 */
The patch
ASoC: Intel: Skylake: Add jack port initialize in nau88l25_max98357a machine
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 565f13a95ec3d541324e80657bd512a19df8e576 Mon Sep 17 00:00:00 2001
From: Jeeja KP jeeja.kp@intel.com Date: Tue, 7 Feb 2017 19:09:57 +0530 Subject: [PATCH] ASoC: Intel: Skylake: Add jack port initialize in nau88l25_max98357a machine
After the pcm jack is created, create and initialize the pin switch widget for each port. Pin switch is to enable/disable the pin when monitor is connected/disconnected.
Signed-off-by: Jeeja KP jeeja.kp@intel.com Acked-by: Vinod Koul vinod.koul@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/boards/skl_nau88l25_max98357a.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index 48f7c96b3f3d..3b12bc1fa518 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -131,9 +131,6 @@ static const struct snd_soc_dapm_route skylake_map[] = { { "MIC", NULL, "Headset Mic" }, { "DMic", NULL, "SoC DMIC" },
- {"DP1", NULL, "hif5-0 Output"}, - {"DP2", NULL, "hif6-0 Output"}, - /* CODEC BE connections */ { "HiFi Playback", NULL, "ssp0 Tx" }, { "ssp0 Tx", NULL, "codec0_out" }, @@ -609,10 +606,12 @@ static int skylake_card_late_probe(struct snd_soc_card *card) { struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(card); struct skl_hdmi_pcm *pcm; + struct snd_soc_codec *codec = NULL; int err, i = 0; char jack_name[NAME_SIZE];
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + codec = pcm->codec_dai->codec; snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, @@ -631,7 +630,10 @@ static int skylake_card_late_probe(struct snd_soc_card *card) i++; }
- return 0; + if (!codec) + return -EINVAL; + + return hdac_hdmi_jack_port_init(codec, &card->dapm); }
/* skylake audio machine driver for SPT + NAU88L25 */
From: Jeeja KP jeeja.kp@intel.com
After the pcm jack is created, create and initialize the pin switch widget for each port. Pin switch is to enable/disable the pin when monitor is connected/disconnected.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 5deb68f..eb7751b 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -136,9 +136,6 @@ static const struct snd_soc_dapm_route skylake_map[] = { {"MIC", NULL, "Headset Mic"}, {"DMic", NULL, "SoC DMIC"},
- {"DP1", NULL, "hif5-0 Output"}, - {"DP2", NULL, "hif6-0 Output"}, - /* CODEC BE connections */ { "Left Playback", NULL, "ssp0 Tx"}, { "Right Playback", NULL, "ssp0 Tx"}, @@ -660,10 +657,12 @@ static int skylake_card_late_probe(struct snd_soc_card *card) { struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(card); struct skl_hdmi_pcm *pcm; + struct snd_soc_codec *codec = NULL; int err, i = 0; char jack_name[NAME_SIZE];
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + codec = pcm->codec_dai->codec; snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, @@ -682,7 +681,10 @@ static int skylake_card_late_probe(struct snd_soc_card *card) i++; }
- return 0; + if (!codec) + return -EINVAL; + + return hdac_hdmi_jack_port_init(codec, &card->dapm); }
/* skylake audio machine driver for SPT + NAU88L25 */
The patch
ASoC: Intel: Skylake: Add jack port initialize in nau88l25_ssm4567 machine
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 86b5703158ff39e5efe9480784a7cad1b4baef59 Mon Sep 17 00:00:00 2001
From: Jeeja KP jeeja.kp@intel.com Date: Tue, 7 Feb 2017 19:09:58 +0530 Subject: [PATCH] ASoC: Intel: Skylake: Add jack port initialize in nau88l25_ssm4567 machine
After the pcm jack is created, create and initialize the pin switch widget for each port. Pin switch is to enable/disable the pin when monitor is connected/disconnected.
Signed-off-by: Jeeja KP jeeja.kp@intel.com Acked-by: Vinod Koul vinod.koul@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 5deb68f0c1f0..eb7751b0599b 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -136,9 +136,6 @@ static const struct snd_soc_dapm_route skylake_map[] = { {"MIC", NULL, "Headset Mic"}, {"DMic", NULL, "SoC DMIC"},
- {"DP1", NULL, "hif5-0 Output"}, - {"DP2", NULL, "hif6-0 Output"}, - /* CODEC BE connections */ { "Left Playback", NULL, "ssp0 Tx"}, { "Right Playback", NULL, "ssp0 Tx"}, @@ -660,10 +657,12 @@ static int skylake_card_late_probe(struct snd_soc_card *card) { struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(card); struct skl_hdmi_pcm *pcm; + struct snd_soc_codec *codec = NULL; int err, i = 0; char jack_name[NAME_SIZE];
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + codec = pcm->codec_dai->codec; snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, @@ -682,7 +681,10 @@ static int skylake_card_late_probe(struct snd_soc_card *card) i++; }
- return 0; + if (!codec) + return -EINVAL; + + return hdac_hdmi_jack_port_init(codec, &card->dapm); }
/* skylake audio machine driver for SPT + NAU88L25 */
From: Jeeja KP jeeja.kp@intel.com
After the pcm jack is created, create and initialize the pin switch widget for each port. Pin switch is to enable/disable the pin when monitor is connected/disconnected. --- sound/soc/intel/boards/bxt_rt298.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index d5f53a6..176c080 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -459,10 +459,12 @@ static int bxt_card_late_probe(struct snd_soc_card *card) { struct bxt_rt286_private *ctx = snd_soc_card_get_drvdata(card); struct bxt_hdmi_pcm *pcm; + struct snd_soc_codec *codec = NULL; int err, i = 0; char jack_name[NAME_SIZE];
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + codec = pcm->codec_dai->codec; snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, @@ -480,7 +482,10 @@ static int bxt_card_late_probe(struct snd_soc_card *card) i++; }
- return 0; + if (!codec) + return -EINVAL; + + return hdac_hdmi_jack_port_init(codec, &card->dapm); }
The patch
ASoC: Intel: bxt: Add jack port initialize in bxt_rt298 machine
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 7ba8ba3f4f9604ce776475e3b501e41c762af797 Mon Sep 17 00:00:00 2001
From: Jeeja KP jeeja.kp@intel.com Date: Fri, 17 Feb 2017 15:04:46 +0530 Subject: [PATCH] ASoC: Intel: bxt: Add jack port initialize in bxt_rt298 machine
After the pcm jack is created, create and initialize the pin switch widget for each port. Pin switch is to enable/disable the pin when monitor is connected/disconnected.
Signed-off-by: Jeeja KP jeeja.kp@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/boards/bxt_rt298.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index d5f53a6de041..176c080a9818 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -459,10 +459,12 @@ static int bxt_card_late_probe(struct snd_soc_card *card) { struct bxt_rt286_private *ctx = snd_soc_card_get_drvdata(card); struct bxt_hdmi_pcm *pcm; + struct snd_soc_codec *codec = NULL; int err, i = 0; char jack_name[NAME_SIZE];
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + codec = pcm->codec_dai->codec; snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, @@ -480,7 +482,10 @@ static int bxt_card_late_probe(struct snd_soc_card *card) i++; }
- return 0; + if (!codec) + return -EINVAL; + + return hdac_hdmi_jack_port_init(codec, &card->dapm); }
From: Jeeja KP jeeja.kp@intel.com
After the pcm jack is created, create and initialize the pin switch widget for each port. Pin switch is to enable/disable the pin when monitor is connected/disconnected.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 35d95b4..10fc2ed 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -558,10 +558,12 @@ static int bxt_card_late_probe(struct snd_soc_card *card) { struct bxt_card_private *ctx = snd_soc_card_get_drvdata(card); struct bxt_hdmi_pcm *pcm; + struct snd_soc_codec *codec = NULL; int err, i = 0; char jack_name[NAME_SIZE];
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + codec = pcm->codec_dai->codec; snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, @@ -579,7 +581,10 @@ static int bxt_card_late_probe(struct snd_soc_card *card) i++; }
- return 0; + if (!codec) + return -EINVAL; + + return hdac_hdmi_jack_port_init(codec, &card->dapm); }
/* broxton audio machine driver for SPT + da7219 */
The patch
ASoC: Intel: bxt: Add jack port initialize in da7219_max98357a machine
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 c5cf9f37a0fb6e50d68f6dcf58b93b2c47c780a1 Mon Sep 17 00:00:00 2001
From: Jeeja KP jeeja.kp@intel.com Date: Tue, 7 Feb 2017 19:10:00 +0530 Subject: [PATCH] ASoC: Intel: bxt: Add jack port initialize in da7219_max98357a machine
After the pcm jack is created, create and initialize the pin switch widget for each port. Pin switch is to enable/disable the pin when monitor is connected/disconnected.
Signed-off-by: Jeeja KP jeeja.kp@intel.com Acked-by: Vinod Koul vinod.koul@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 18f3d0e1a6b2..2cda06cde4d1 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -523,10 +523,12 @@ static int bxt_card_late_probe(struct snd_soc_card *card) { struct bxt_card_private *ctx = snd_soc_card_get_drvdata(card); struct bxt_hdmi_pcm *pcm; + struct snd_soc_codec *codec = NULL; int err, i = 0; char jack_name[NAME_SIZE];
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + codec = pcm->codec_dai->codec; snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, @@ -544,7 +546,10 @@ static int bxt_card_late_probe(struct snd_soc_card *card) i++; }
- return 0; + if (!codec) + return -EINVAL; + + return hdac_hdmi_jack_port_init(codec, &card->dapm); }
/* broxton audio machine driver for SPT + da7219 */
From: Jeeja KP jeeja.kp@intel.com
DSP pipe needs to stopped before deleting the pipe. Currently check is is for pipe state > STARTED, which is incorrect. So changed to include pipe state STARTED to stop the pipe if it started.
Signed-off-by: Jeeja KP jeeja.kp@intel.com --- sound/soc/intel/skylake/skl-messages.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index e79cbcf..7190df5 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -1091,7 +1091,7 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) dev_dbg(ctx->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id);
/* If pipe is started, do stop the pipe in FW. */ - if (pipe->state > SKL_PIPE_STARTED) { + if (pipe->state >= SKL_PIPE_STARTED) { ret = skl_set_pipe_state(ctx, pipe, PPL_PAUSED); if (ret < 0) { dev_err(ctx->dev, "Failed to stop pipeline\n");
The patch
ASoC: Intel: Skylake: Fix to delete DSP pipe after stopping pipe
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 6914968b8203aef72edf936319c4d46c6d46401b Mon Sep 17 00:00:00 2001
From: Jeeja KP jeeja.kp@intel.com Date: Mon, 13 Mar 2017 22:11:23 +0530 Subject: [PATCH] ASoC: Intel: Skylake: Fix to delete DSP pipe after stopping pipe
DSP pipe needs to stopped before deleting the pipe. Currently check is for pipe state > STARTED, which is incorrect. So changed to include pipe state STARTED to stop the pipe if it started.
Signed-off-by: Jeeja KP jeeja.kp@intel.com Acked-by: Vinod Koul vinod.koul@intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/intel/skylake/skl-messages.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index e66870474f10..ed576965cacc 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -1098,7 +1098,7 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) dev_dbg(ctx->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id);
/* If pipe is started, do stop the pipe in FW. */ - if (pipe->state > SKL_PIPE_STARTED) { + if (pipe->state >= SKL_PIPE_STARTED) { ret = skl_set_pipe_state(ctx, pipe, PPL_PAUSED); if (ret < 0) { dev_err(ctx->dev, "Failed to stop pipeline\n");
On Mon, Jan 16, 2017 at 11:27:27PM +0530, jeeja.kp@intel.com wrote:
From: Jeeja KP jeeja.kp@intel.com
Display port 1.2 introduces new capability Multi-stream transport (MST) which will allow multiple stream to route to single display port where multiple monitors are connected. Multiple monitors will be connected by a MST Hub or a monitor capable of daisy-chaining.
This is a *really* big patch series. As I've said before please try to keep patch serieses down to a manageable size, 20 patches is getting quite large and this is quite a bit bigger. It's a lot easier for people to digest things in smaller chunks and it's a lot easier to push something enormous that's going to take time to get through to the back of the queue when you're short on time.
On Tue, Jan 17, 2017 at 05:54:42PM +0000, Mark Brown wrote:
On Mon, Jan 16, 2017 at 11:27:27PM +0530, jeeja.kp@intel.com wrote:
From: Jeeja KP jeeja.kp@intel.com
Display port 1.2 introduces new capability Multi-stream transport (MST) which will allow multiple stream to route to single display port where multiple monitors are connected. Multiple monitors will be connected by a MST Hub or a monitor capable of daisy-chaining.
This is a *really* big patch series. As I've said before please try to keep patch serieses down to a manageable size, 20 patches is getting quite large and this is quite a bit bigger. It's a lot easier for people to digest things in smaller chunks and it's a lot easier to push something enormous that's going to take time to get through to the back of the queue when you're short on time.
i will split the patch series and post it again. --
participants (3)
-
Jeeja KP
-
jeeja.kp@intel.com
-
Mark Brown