aboutsummaryrefslogtreecommitdiffstats
path: root/sound/x86/intel_hdmi_audio.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2017-01-31 13:52:22 +0100
committerTakashi Iwai <tiwai@suse.de>2017-02-03 17:31:35 +0100
commitda8648097497505d05d8cff6892351f99c029791 (patch)
tree4e107ece33e302157501cb7636f66556ee0babe5 /sound/x86/intel_hdmi_audio.c
parentALSA: x86: Drop unused hdmi_audio_query() (diff)
downloadlinux-dev-da8648097497505d05d8cff6892351f99c029791.tar.xz
linux-dev-da8648097497505d05d8cff6892351f99c029791.zip
ALSA: x86: Flatten two abstraction layers
This is the final stage for a big clean-up series. Here we flatten the two layers into one. Formerly, the implementation was split to HDMI "shell" that talks with the platform device, and HDMI audio part that communicates via caps and other event handlers. All these would be good if there were multiple instantiations or if there were data protection. But neither are true in our case. That said, it'll be easier to have a flat driver structure in the end. In this patch, the former struct hdmi_lpe_audio_ctx is forged into the existing struct snd_intelhad. The latter has already a few members that are basically the copy from the former. Only a few new members for the lowlevel I/O are added by this change. Then, the had_get_caps() and had_set_caps() are simply replaced with the direct calls to copy the data in the struct fields. Also, the had_event_handler() calls are replaced with the direct call for each event as well. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/x86/intel_hdmi_audio.c')
-rw-r--r--sound/x86/intel_hdmi_audio.c476
1 files changed, 315 insertions, 161 deletions
diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c
index 82f42a6c363c..1594f826cf31 100644
--- a/sound/x86/intel_hdmi_audio.c
+++ b/sound/x86/intel_hdmi_audio.c
@@ -27,6 +27,7 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/interrupt.h>
#include <linux/acpi.h>
#include <asm/cacheflush.h>
#include <sound/pcm.h>
@@ -35,6 +36,7 @@
#include <sound/initval.h>
#include <sound/control.h>
#include <sound/initval.h>
+#include <drm/intel_lpe_audio.h>
#include "intel_hdmi_audio.h"
/*standard module options for ALSA. This module supports only one card*/
@@ -168,72 +170,75 @@ int had_get_hwstate(struct snd_intelhad *intelhaddata)
return 0;
}
-int had_get_caps(struct snd_intelhad *intelhaddata,
- enum had_caps_list query, void *caps)
+static inline void
+mid_hdmi_audio_read(struct snd_intelhad *ctx, u32 reg, u32 *val)
{
- struct platform_device *pdev = to_platform_device(intelhaddata->dev);
- int retval;
-
- retval = had_get_hwstate(intelhaddata);
- if (!retval)
- retval = mid_hdmi_audio_get_caps(pdev, query, caps);
-
- return retval;
+ *val = ioread32(ctx->mmio_start + ctx->had_config_offset + reg);
}
-int had_set_caps(struct snd_intelhad *intelhaddata,
- enum had_caps_list set_element, void *caps)
+static inline void
+mid_hdmi_audio_write(struct snd_intelhad *ctx, u32 reg, u32 val)
{
- struct platform_device *pdev = to_platform_device(intelhaddata->dev);
- int retval;
-
- retval = had_get_hwstate(intelhaddata);
- if (!retval)
- retval = mid_hdmi_audio_set_caps(pdev, set_element, caps);
-
- return retval;
+ iowrite32(val, ctx->mmio_start + ctx->had_config_offset + reg);
}
int had_read_register(struct snd_intelhad *intelhaddata, u32 offset, u32 *data)
{
- struct platform_device *pdev = to_platform_device(intelhaddata->dev);
int retval;
retval = had_get_hwstate(intelhaddata);
- if (!retval)
- retval = mid_hdmi_audio_read(pdev, offset, data);
+ if (retval)
+ return retval;
- return retval;
+ mid_hdmi_audio_read(intelhaddata, offset, data);
+ return 0;
+}
+
+static void fixup_dp_config(struct snd_intelhad *intelhaddata,
+ u32 offset, u32 *data)
+{
+ if (intelhaddata->dp_output) {
+ if (offset == AUD_CONFIG && (*data & AUD_CONFIG_VALID_BIT))
+ *data |= AUD_CONFIG_DP_MODE | AUD_CONFIG_BLOCK_BIT;
+ }
}
int had_write_register(struct snd_intelhad *intelhaddata, u32 offset, u32 data)
{
- struct platform_device *pdev = to_platform_device(intelhaddata->dev);
int retval;
retval = had_get_hwstate(intelhaddata);
- if (!retval)
- retval = mid_hdmi_audio_write(pdev, offset, data);
+ if (retval)
+ return retval;
- return retval;
+ fixup_dp_config(intelhaddata, offset, &data);
+ mid_hdmi_audio_write(intelhaddata, offset, data);
+ return 0;
}
int had_read_modify(struct snd_intelhad *intelhaddata, u32 offset,
u32 data, u32 mask)
{
- struct platform_device *pdev = to_platform_device(intelhaddata->dev);
+ u32 val_tmp;
int retval;
retval = had_get_hwstate(intelhaddata);
- if (!retval)
- retval = mid_hdmi_audio_rmw(pdev, offset, data, mask);
+ if (retval)
+ return retval;
- return retval;
+ mid_hdmi_audio_read(intelhaddata, offset, &val_tmp);
+ val_tmp &= ~mask;
+ val_tmp |= (data & mask);
+
+ fixup_dp_config(intelhaddata, offset, &val_tmp);
+ mid_hdmi_audio_write(intelhaddata, offset, val_tmp);
+ return 0;
}
-/**
- * function to read-modify
- * AUD_CONFIG register on VLV2.The had_read_modify() function should not
- * directly be used on VLV2 for updating AUD_CONFIG register.
+
+/*
+ * function to read-modify AUD_CONFIG register on VLV2.
+ * The had_read_modify() function should not directly be used on VLV2 for
+ * updating AUD_CONFIG register.
* This is because:
* Bit6 of AUD_CONFIG register is writeonly due to a silicon bug on VLV2
* HDMI IP. As a result a read-modify of AUD_CONFIG regiter will always
@@ -249,10 +254,10 @@ int had_read_modify(struct snd_intelhad *intelhaddata, u32 offset,
* @mask : mask
*
*/
-static int had_read_modify_aud_config_v2(struct snd_pcm_substream *substream,
+static int had_read_modify_aud_config_v2(struct snd_intelhad *intelhaddata,
u32 data, u32 mask)
{
- struct snd_intelhad *intelhaddata = snd_pcm_substream_chip(substream);
+ struct snd_pcm_substream *substream;
union aud_cfg cfg_val = {.cfg_regval = 0};
u8 channels;
@@ -260,7 +265,8 @@ static int had_read_modify_aud_config_v2(struct snd_pcm_substream *substream,
* If substream is NULL, there is no active stream.
* In this case just set channels to 2
*/
- if (substream)
+ substream = intelhaddata->stream_info.had_substream;
+ if (substream && substream->runtime)
channels = substream->runtime->channels;
else
channels = 2;
@@ -274,9 +280,23 @@ static int had_read_modify_aud_config_v2(struct snd_pcm_substream *substream,
return had_read_modify(intelhaddata, AUD_CONFIG, data, mask);
}
-void snd_intelhad_enable_audio(struct snd_pcm_substream *substream, u8 enable)
+void snd_intelhad_enable_audio_int(struct snd_intelhad *ctx, bool enable)
+{
+ u32 status_reg;
+
+ if (enable) {
+ mid_hdmi_audio_read(ctx, AUD_HDMI_STATUS_v2, &status_reg);
+ status_reg |= HDMI_AUDIO_BUFFER_DONE | HDMI_AUDIO_UNDERRUN;
+ mid_hdmi_audio_write(ctx, AUD_HDMI_STATUS_v2, status_reg);
+ mid_hdmi_audio_read(ctx, AUD_HDMI_STATUS_v2, &status_reg);
+ }
+}
+
+void snd_intelhad_enable_audio(struct snd_intelhad *intelhaddata,
+ bool enable)
{
- had_read_modify_aud_config_v2(substream, enable, BIT(0));
+ had_read_modify_aud_config_v2(intelhaddata, enable ? BIT(0) : 0,
+ BIT(0));
}
static void snd_intelhad_reset_audio(struct snd_intelhad *intelhaddata,
@@ -437,7 +457,7 @@ static int snd_intelhad_channel_allocation(struct snd_intelhad *intelhaddata,
*/
for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) {
- if (intelhaddata->eeld.speaker_allocation_block & (1 << i))
+ if (intelhaddata->eld.speaker_allocation_block & (1 << i))
spk_mask |= eld_speaker_allocation_bits[i];
}
@@ -482,11 +502,8 @@ void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata)
return;
}
- had_get_caps(intelhaddata, HAD_GET_ELD, &intelhaddata->eeld);
- had_get_caps(intelhaddata, HAD_GET_DP_OUTPUT, &intelhaddata->dp_output);
-
- pr_debug("eeld.speaker_allocation_block = %x\n",
- intelhaddata->eeld.speaker_allocation_block);
+ pr_debug("eld.speaker_allocation_block = %x\n",
+ intelhaddata->eld.speaker_allocation_block);
/* WA: Fix the max channel supported to 8 */
@@ -497,14 +514,14 @@ void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata)
*/
/* if 0x2F < eld < 0x4F fall back to 0x2f, else fall back to 0x4F */
- eld_high = intelhaddata->eeld.speaker_allocation_block & eld_high_mask;
+ eld_high = intelhaddata->eld.speaker_allocation_block & eld_high_mask;
if ((eld_high & (eld_high-1)) && (eld_high > 0x1F)) {
/* eld_high & (eld_high-1): if more than 1 bit set */
/* 0x1F: 7 channels */
for (i = 1; i < 4; i++) {
high_msb = eld_high & (0x80 >> i);
if (high_msb) {
- intelhaddata->eeld.speaker_allocation_block &=
+ intelhaddata->eld.speaker_allocation_block &=
high_msb | 0xF;
break;
}
@@ -512,7 +529,7 @@ void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata)
}
for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) {
- if (intelhaddata->eeld.speaker_allocation_block & (1 << i))
+ if (intelhaddata->eld.speaker_allocation_block & (1 << i))
spk_mask |= eld_speaker_allocation_bits[i];
}
@@ -1176,7 +1193,7 @@ static int snd_intelhad_hw_free(struct snd_pcm_substream *substream)
static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream,
int cmd)
{
- int caps, retval = 0;
+ int retval = 0;
unsigned long flag_irq;
struct snd_intelhad *intelhaddata;
struct had_stream_pvt *stream;
@@ -1203,15 +1220,8 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream,
had_stream->stream_type = HAD_RUNNING_STREAM;
/* Enable Audio */
- /*
- * ToDo: Need to enable UNDERRUN interrupts as well
- * caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE;
- */
- caps = HDMI_AUDIO_BUFFER_DONE;
- retval = had_set_caps(intelhaddata, HAD_SET_ENABLE_AUDIO_INT,
- &caps);
- retval = had_set_caps(intelhaddata, HAD_SET_ENABLE_AUDIO, NULL);
- snd_intelhad_enable_audio(substream, 1);
+ snd_intelhad_enable_audio_int(intelhaddata, true);
+ snd_intelhad_enable_audio(intelhaddata, true);
pr_debug("Processed _Start\n");
@@ -1228,18 +1238,13 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream,
had_stream->stream_type = HAD_INIT;
spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irq);
/* Disable Audio */
- /*
- * ToDo: Need to disable UNDERRUN interrupts as well
- * caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE;
- */
- caps = HDMI_AUDIO_BUFFER_DONE;
- had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO_INT, &caps);
- snd_intelhad_enable_audio(substream, 0);
+ snd_intelhad_enable_audio_int(intelhaddata, false);
+ snd_intelhad_enable_audio(intelhaddata, false);
/* Reset buffer pointers */
snd_intelhad_reset_audio(intelhaddata, 1);
snd_intelhad_reset_audio(intelhaddata, 0);
stream->stream_status = STREAM_DROPPED;
- had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO, NULL);
+ snd_intelhad_enable_audio_int(intelhaddata, false);
break;
default:
@@ -1297,15 +1302,7 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream)
/* Get N value in KHz */
- retval = had_get_caps(intelhaddata, HAD_GET_DISPLAY_RATE,
- &disp_samp_freq);
- if (retval) {
- pr_err("querying display sampling freq failed %#x\n", retval);
- goto prep_end;
- }
-
- had_get_caps(intelhaddata, HAD_GET_ELD, &intelhaddata->eeld);
- had_get_caps(intelhaddata, HAD_GET_DP_OUTPUT, &intelhaddata->dp_output);
+ disp_samp_freq = intelhaddata->tmds_clock_speed;
retval = snd_intelhad_prog_n(substream->runtime->rate, &n_param,
intelhaddata);
@@ -1315,8 +1312,7 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream)
}
if (intelhaddata->dp_output)
- had_get_caps(intelhaddata, HAD_GET_LINK_RATE, &link_rate);
-
+ link_rate = intelhaddata->link_rate;
snd_intelhad_prog_cts(substream->runtime->rate,
disp_samp_freq, link_rate,
@@ -1425,25 +1421,22 @@ static int snd_intelhad_pcm_mmap(struct snd_pcm_substream *substream,
vma->vm_end - vma->vm_start, vma->vm_page_prot);
}
-int hdmi_audio_mode_change(struct snd_pcm_substream *substream)
+static int hdmi_audio_mode_change(struct snd_intelhad *intelhaddata)
{
+ struct snd_pcm_substream *substream;
int retval = 0;
u32 disp_samp_freq, n_param;
u32 link_rate = 0;
- struct snd_intelhad *intelhaddata;
- intelhaddata = snd_pcm_substream_chip(substream);
+ substream = intelhaddata->stream_info.had_substream;
+ if (!substream || !substream->runtime)
+ return 0;
/* Disable Audio */
- snd_intelhad_enable_audio(substream, 0);
+ snd_intelhad_enable_audio(intelhaddata, false);
/* Update CTS value */
- retval = had_get_caps(intelhaddata, HAD_GET_DISPLAY_RATE,
- &disp_samp_freq);
- if (retval) {
- pr_err("querying display sampling freq failed %#x\n", retval);
- goto out;
- }
+ disp_samp_freq = intelhaddata->tmds_clock_speed;
retval = snd_intelhad_prog_n(substream->runtime->rate, &n_param,
intelhaddata);
@@ -1453,14 +1446,14 @@ int hdmi_audio_mode_change(struct snd_pcm_substream *substream)
}
if (intelhaddata->dp_output)
- had_get_caps(intelhaddata, HAD_GET_LINK_RATE, &link_rate);
+ link_rate = intelhaddata->link_rate;
snd_intelhad_prog_cts(substream->runtime->rate,
disp_samp_freq, link_rate,
n_param, intelhaddata);
/* Enable Audio */
- snd_intelhad_enable_audio(substream, 1);
+ snd_intelhad_enable_audio(intelhaddata, true);
out:
return retval;
@@ -1555,129 +1548,290 @@ static struct snd_kcontrol_new had_control_iec958 = {
.put = had_iec958_put
};
+static void _had_wq(struct work_struct *work)
+{
+ struct snd_intelhad *ctx =
+ container_of(work, struct snd_intelhad, hdmi_audio_wq);
+
+ had_process_hot_plug(ctx);
+}
+
+static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id)
+{
+ struct snd_intelhad *ctx = dev_id;
+ u32 audio_stat, audio_reg;
+
+ audio_reg = AUD_HDMI_STATUS_v2;
+ mid_hdmi_audio_read(ctx, audio_reg, &audio_stat);
+
+ if (audio_stat & HDMI_AUDIO_UNDERRUN) {
+ mid_hdmi_audio_write(ctx, audio_reg, HDMI_AUDIO_UNDERRUN);
+ had_process_buffer_underrun(ctx);
+ }
+
+ if (audio_stat & HDMI_AUDIO_BUFFER_DONE) {
+ mid_hdmi_audio_write(ctx, audio_reg, HDMI_AUDIO_BUFFER_DONE);
+ had_process_buffer_done(ctx);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void notify_audio_lpe(struct platform_device *pdev)
+{
+ struct snd_intelhad *ctx = platform_get_drvdata(pdev);
+ struct intel_hdmi_lpe_audio_pdata *pdata = pdev->dev.platform_data;
+
+ if (pdata->hdmi_connected != true) {
+
+ dev_dbg(&pdev->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n",
+ __func__);
+
+ if (ctx->state == hdmi_connector_status_connected) {
+
+ ctx->state = hdmi_connector_status_disconnected;
+
+ had_process_hot_unplug(ctx);
+ } else
+ dev_dbg(&pdev->dev, "%s: Already Unplugged!\n",
+ __func__);
+
+ } else {
+ struct intel_hdmi_lpe_audio_eld *eld = &pdata->eld;
+
+ switch (eld->pipe_id) {
+ case 0:
+ ctx->had_config_offset = AUDIO_HDMI_CONFIG_A;
+ break;
+ case 1:
+ ctx->had_config_offset = AUDIO_HDMI_CONFIG_B;
+ break;
+ case 2:
+ ctx->had_config_offset = AUDIO_HDMI_CONFIG_C;
+ break;
+ default:
+ dev_dbg(&pdev->dev, "Invalid pipe %d\n",
+ eld->pipe_id);
+ break;
+ }
+
+ memcpy(&ctx->eld, eld->eld_data, sizeof(ctx->eld));
+
+ had_process_hot_plug(ctx);
+
+ ctx->state = hdmi_connector_status_connected;
+
+ dev_dbg(&pdev->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n",
+ __func__, eld->port_id, pdata->tmds_clock_speed);
+
+ if (pdata->tmds_clock_speed) {
+ ctx->tmds_clock_speed = pdata->tmds_clock_speed;
+ ctx->dp_output = pdata->dp_output;
+ ctx->link_rate = pdata->link_rate;
+
+ /* Process mode change if stream is active */
+ if (ctx->stream_data.stream_type == HAD_RUNNING_STREAM)
+ hdmi_audio_mode_change(ctx);
+ }
+ }
+}
+
+/* release resources */
+static void hdmi_lpe_audio_free(struct snd_card *card)
+{
+ struct snd_intelhad *ctx = card->private_data;
+
+ if (ctx->mmio_start)
+ iounmap(ctx->mmio_start);
+ if (ctx->irq >= 0)
+ free_irq(ctx->irq, ctx);
+}
+
/*
- * hdmi_audio_probe - to create sound card instance for HDMI audio playabck
- *
- * @devptr: platform device
- * @had_ret: pointer to store the created snd_intelhad object
+ * hdmi_lpe_audio_probe - start bridge with i915
*
- * This function is called when the platform device is probed. This function
- * creates and registers the sound card with ALSA
+ * This function is called when the i915 driver creates the
+ * hdmi-lpe-audio platform device. Card creation is deferred until a
+ * hot plug event is received
*/
-int hdmi_audio_probe(struct platform_device *devptr,
- struct snd_intelhad **had_ret)
+static int hdmi_lpe_audio_probe(struct platform_device *pdev)
{
- int retval;
- struct snd_pcm *pcm;
struct snd_card *card;
- struct snd_intelhad *intelhaddata;
+ struct snd_intelhad *ctx;
+ struct snd_pcm *pcm;
+ struct intel_hdmi_lpe_audio_pdata *pdata;
+ int irq;
+ struct resource *res_mmio;
+ int ret;
+ unsigned long flags;
+
+ dev_dbg(&pdev->dev, "Enter %s\n", __func__);
+ dev_dbg(&pdev->dev, "dma_mask: %p\n", pdev->dev.dma_mask);
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "%s: quit: pdata not allocated by i915!!\n", __func__);
+ return -EINVAL;
+ }
- pr_debug("Enter %s\n", __func__);
+ /* get resources */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "Could not get irq resource\n");
+ return -ENODEV;
+ }
+
+ res_mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res_mmio) {
+ dev_err(&pdev->dev, "Could not get IO_MEM resources\n");
+ return -ENXIO;
+ }
/* create a card instance with ALSA framework */
- retval = snd_card_new(&devptr->dev, hdmi_card_index, hdmi_card_id,
- THIS_MODULE, sizeof(*intelhaddata), &card);
- if (retval)
- return retval;
+ ret = snd_card_new(&pdev->dev, hdmi_card_index, hdmi_card_id,
+ THIS_MODULE, sizeof(*ctx), &card);
+ if (ret)
+ return ret;
+
+ ctx = card->private_data;
+ spin_lock_init(&ctx->had_spinlock);
+ ctx->drv_status = HAD_DRV_DISCONNECTED;
+ ctx->dev = &pdev->dev;
+ ctx->card = card;
+ ctx->card_id = hdmi_card_id;
+ ctx->card_index = card->number;
+ ctx->flag_underrun = 0;
+ ctx->aes_bits = SNDRV_PCM_DEFAULT_CON_SPDIF;
+ strcpy(card->driver, INTEL_HAD);
+ strcpy(card->shortname, INTEL_HAD);
+
+ ctx->irq = -1;
+ ctx->tmds_clock_speed = DIS_SAMPLE_RATE_148_5;
+ INIT_WORK(&ctx->hdmi_audio_wq, _had_wq);
+ ctx->state = hdmi_connector_status_disconnected;
+
+ card->private_free = hdmi_lpe_audio_free;
+
+ /* assume pipe A as default */
+ ctx->had_config_offset = AUDIO_HDMI_CONFIG_A;
+
+ platform_set_drvdata(pdev, ctx);
+
+ dev_dbg(&pdev->dev, "%s: mmio_start = 0x%x, mmio_end = 0x%x\n",
+ __func__, (unsigned int)res_mmio->start,
+ (unsigned int)res_mmio->end);
+
+ ctx->mmio_start = ioremap_nocache(res_mmio->start,
+ (size_t)(resource_size(res_mmio)));
+ if (!ctx->mmio_start) {
+ dev_err(&pdev->dev, "Could not get ioremap\n");
+ ret = -EACCES;
+ goto err;
+ }
- intelhaddata = card->private_data;
- spin_lock_init(&intelhaddata->had_spinlock);
- intelhaddata->drv_status = HAD_DRV_DISCONNECTED;
- pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n",
- __func__, __LINE__);
+ /* setup interrupt handler */
+ ret = request_irq(irq, display_pipe_interrupt_handler, 0,
+ pdev->name, ctx);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "request_irq failed\n");
+ goto err;
+ }
- intelhaddata->dev = &devptr->dev;
- intelhaddata->card = card;
- intelhaddata->card_id = hdmi_card_id;
- intelhaddata->card_index = card->number;
- intelhaddata->flag_underrun = 0;
- intelhaddata->aes_bits = SNDRV_PCM_DEFAULT_CON_SPDIF;
- strncpy(card->driver, INTEL_HAD, strlen(INTEL_HAD));
- strncpy(card->shortname, INTEL_HAD, strlen(INTEL_HAD));
-
- retval = snd_pcm_new(card, INTEL_HAD, PCM_INDEX, MAX_PB_STREAMS,
- MAX_CAP_STREAMS, &pcm);
- if (retval)
+ ctx->irq = irq;
+
+ ret = snd_pcm_new(card, INTEL_HAD, PCM_INDEX, MAX_PB_STREAMS,
+ MAX_CAP_STREAMS, &pcm);
+ if (ret)
goto err;
/* setup private data which can be retrieved when required */
- pcm->private_data = intelhaddata;
+ pcm->private_data = ctx;
pcm->private_free = snd_intelhad_pcm_free;
pcm->info_flags = 0;
strncpy(pcm->name, card->shortname, strlen(card->shortname));
- /* setup the ops for palyabck */
+ /* setup the ops for playabck */
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
&snd_intelhad_playback_ops);
/* allocate dma pages for ALSA stream operations
* memory allocated is based on size, not max value
* thus using same argument for max & size
*/
- retval = snd_pcm_lib_preallocate_pages_for_all(pcm,
+ snd_pcm_lib_preallocate_pages_for_all(pcm,
SNDRV_DMA_TYPE_DEV, NULL,
HAD_MAX_BUFFER, HAD_MAX_BUFFER);
- if (retval)
- goto err;
/* IEC958 controls */
- retval = snd_ctl_add(card, snd_ctl_new1(&had_control_iec958_mask,
- intelhaddata));
- if (retval < 0)
+ ret = snd_ctl_add(card, snd_ctl_new1(&had_control_iec958_mask, ctx));
+ if (ret < 0)
goto err;
- retval = snd_ctl_add(card, snd_ctl_new1(&had_control_iec958,
- intelhaddata));
- if (retval < 0)
+ ret = snd_ctl_add(card, snd_ctl_new1(&had_control_iec958, ctx));
+ if (ret < 0)
goto err;
init_channel_allocations();
/* Register channel map controls */
- retval = had_register_chmap_ctls(intelhaddata, pcm);
- if (retval < 0)
+ ret = had_register_chmap_ctls(ctx, pcm);
+ if (ret < 0)
goto err;
- retval = snd_card_register(card);
- if (retval)
+ ret = snd_card_register(card);
+ if (ret)
goto err;
- pm_runtime_set_active(intelhaddata->dev);
- pm_runtime_enable(intelhaddata->dev);
+ spin_lock_irqsave(&pdata->lpe_audio_slock, flags);
+ pdata->notify_audio_lpe = notify_audio_lpe;
+ if (pdata->notify_pending) {
- *had_ret = intelhaddata;
+ dev_dbg(&pdev->dev, "%s: handle pending notification\n", __func__);
+ notify_audio_lpe(pdev);
+ pdata->notify_pending = false;
+ }
+ spin_unlock_irqrestore(&pdata->lpe_audio_slock, flags);
+
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
+ schedule_work(&ctx->hdmi_audio_wq);
return 0;
err:
snd_card_free(card);
- pr_err("Error returned from %s api %#x\n", __func__, retval);
- return retval;
+ return ret;
}
/*
- * hdmi_audio_remove - removes the alsa card
+ * hdmi_lpe_audio_remove - stop bridge with i915
*
- *@haddata: pointer to HAD private data
- *
- * This function is called when the hdmi cable is un-plugged. This function
- * free the sound card.
+ * This function is called when the platform device is destroyed. The sound
+ * card should have been removed on hot plug event.
*/
-int hdmi_audio_remove(struct snd_intelhad *intelhaddata)
+static int hdmi_lpe_audio_remove(struct platform_device *pdev)
{
- int caps;
-
- pr_debug("Enter %s\n", __func__);
+ struct snd_intelhad *ctx = platform_get_drvdata(pdev);
- if (!intelhaddata)
- return 0;
+ dev_dbg(&pdev->dev, "Enter %s\n", __func__);
- if (intelhaddata->drv_status != HAD_DRV_DISCONNECTED) {
- caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE;
- had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO_INT, &caps);
- had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO, NULL);
- }
- snd_card_free(intelhaddata->card);
+ if (ctx->drv_status != HAD_DRV_DISCONNECTED)
+ snd_intelhad_enable_audio_int(ctx, false);
+ snd_card_free(ctx->card);
return 0;
}
+static struct platform_driver hdmi_lpe_audio_driver = {
+ .driver = {
+ .name = "hdmi-lpe-audio",
+ },
+ .probe = hdmi_lpe_audio_probe,
+ .remove = hdmi_lpe_audio_remove,
+ .suspend = hdmi_lpe_audio_suspend,
+ .resume = hdmi_lpe_audio_resume
+};
+
+module_platform_driver(hdmi_lpe_audio_driver);
+MODULE_ALIAS("platform:hdmi_lpe_audio");
+
MODULE_AUTHOR("Sailaja Bandarupalli <sailaja.bandarupalli@intel.com>");
MODULE_AUTHOR("Ramesh Babu K V <ramesh.babu@intel.com>");
MODULE_AUTHOR("Vaibhav Agarwal <vaibhav.agarwal@intel.com>");