summaryrefslogtreecommitdiff
path: root/sound/x86/intel_hdmi_audio.c
diff options
context:
space:
mode:
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>");