summaryrefslogtreecommitdiffstats
path: root/sound/x86/intel_hdmi_lpe_audio.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/x86/intel_hdmi_lpe_audio.c')
-rw-r--r--sound/x86/intel_hdmi_lpe_audio.c462
1 files changed, 0 insertions, 462 deletions
diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c
deleted file mode 100644
index 8789f55..0000000
--- a/sound/x86/intel_hdmi_lpe_audio.c
+++ /dev/null
@@ -1,462 +0,0 @@
-/*
- * intel_hdmi_lpe_audio.c - Intel HDMI LPE audio driver for Atom platforms
- *
- * Copyright (C) 2016 Intel Corp
- * Authors:
- * Jerome Anand <jerome.anand@intel.com>
- * Aravind Siddappaji <aravindx.siddappaji@intel.com>
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-#include <linux/platform_device.h>
-#include <linux/irqreturn.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/control.h>
-#include <sound/initval.h>
-#include <drm/intel_lpe_audio.h>
-#include "intel_hdmi_lpe_audio.h"
-#include "intel_hdmi_audio.h"
-
-struct hdmi_lpe_audio_ctx {
- struct platform_device *pdev;
- int irq;
- void __iomem *mmio_start;
- struct snd_intelhad *had;
- int tmds_clock_speed;
- bool dp_output;
- int link_rate;
- unsigned int had_config_offset;
- int hdmi_audio_interrupt_mask;
- struct work_struct hdmi_audio_wq;
- int state; /* connection state */
- union otm_hdmi_eld_t eld; /* ELD copy */
-};
-
-static void mid_hdmi_audio_signal_event(struct platform_device *pdev,
- enum had_event_type event)
-{
- struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev);
-
- dev_dbg(&pdev->dev, "%s: Enter\n", __func__);
-
- /* The handler is protected in the respective
- * event handlers to avoid races
- */
- had_event_handler(event, ctx->had);
-}
-
-/*
- * used to write into display controller HDMI audio registers.
- */
-int mid_hdmi_audio_write(struct platform_device *pdev, u32 reg, u32 val)
-{
- struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev);
-
- dev_dbg(&pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, val);
-
- if (ctx->dp_output) {
- if (reg == AUD_CONFIG && (val & AUD_CONFIG_VALID_BIT))
- val |= AUD_CONFIG_DP_MODE | AUD_CONFIG_BLOCK_BIT;
- }
- iowrite32(val, ctx->mmio_start + ctx->had_config_offset + reg);
-
- return 0;
-}
-
-/*
- * used to get the register value read from
- * display controller HDMI audio registers.
- */
-int mid_hdmi_audio_read(struct platform_device *pdev, u32 reg, u32 *val)
-{
- struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev);
-
- *val = ioread32(ctx->mmio_start + ctx->had_config_offset + reg);
- dev_dbg(&pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, *val);
- return 0;
-}
-
-/*
- * used to update the masked bits in display controller HDMI
- * audio registers.
- */
-int mid_hdmi_audio_rmw(struct platform_device *pdev,
- u32 reg, u32 val, u32 mask)
-{
- struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev);
- u32 val_tmp = 0;
-
- val_tmp = ioread32(ctx->mmio_start + ctx->had_config_offset + reg);
- val_tmp &= ~mask;
- val_tmp |= (val & mask);
-
- if (ctx->dp_output) {
- if (reg == AUD_CONFIG && (val_tmp & AUD_CONFIG_VALID_BIT))
- val_tmp |= AUD_CONFIG_DP_MODE | AUD_CONFIG_BLOCK_BIT;
- }
-
- iowrite32(val_tmp, ctx->mmio_start + ctx->had_config_offset + reg);
- dev_dbg(&pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__,
- reg, val_tmp);
-
- return 0;
-}
-
-/*
- * used to return the HDMI audio capabilities.
- * e.g. resolution, frame rate.
- */
-int mid_hdmi_audio_get_caps(struct platform_device *pdev,
- enum had_caps_list get_element,
- void *capabilities)
-{
- struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev);
- int ret = 0;
-
- dev_dbg(&pdev->dev, "%s: Enter\n", __func__);
-
- switch (get_element) {
- case HAD_GET_ELD:
- memcpy(capabilities, &ctx->eld, sizeof(ctx->eld));
- print_hex_dump_bytes("eld: ", DUMP_PREFIX_NONE,
- (u8 *)&ctx->eld, sizeof(ctx->eld));
- break;
- case HAD_GET_DISPLAY_RATE:
- /* ToDo: Verify if sampling freq logic is correct */
- *(u32 *)capabilities = ctx->tmds_clock_speed;
- dev_dbg(&pdev->dev, "%s: tmds_clock_speed = 0x%x\n",
- __func__, ctx->tmds_clock_speed);
- break;
- case HAD_GET_LINK_RATE:
- /* ToDo: Verify if sampling freq logic is correct */
- *(u32 *)capabilities = ctx->link_rate;
- dev_dbg(&pdev->dev, "%s: link rate = 0x%x\n",
- __func__, ctx->link_rate);
- break;
- case HAD_GET_DP_OUTPUT:
- *(u32 *)capabilities = ctx->dp_output;
- dev_dbg(&pdev->dev, "%s: dp_output = %d\n",
- __func__, ctx->dp_output);
- break;
- default:
- break;
- }
-
- return ret;
-}
-
-/*
- * used to set the HDMI audio capabilities.
- * e.g. Audio INT.
- */
-int mid_hdmi_audio_set_caps(struct platform_device *pdev,
- enum had_caps_list set_element,
- void *capabilties)
-{
- dev_dbg(&pdev->dev, "%s: cap_id = 0x%x\n", __func__, set_element);
-
- switch (set_element) {
- case HAD_SET_ENABLE_AUDIO_INT:
- {
- u32 status_reg;
-
- mid_hdmi_audio_read(pdev, AUD_HDMI_STATUS_v2,
- &status_reg);
- status_reg |=
- HDMI_AUDIO_BUFFER_DONE | HDMI_AUDIO_UNDERRUN;
- mid_hdmi_audio_write(pdev, AUD_HDMI_STATUS_v2,
- status_reg);
- mid_hdmi_audio_read(pdev, AUD_HDMI_STATUS_v2,
- &status_reg);
- }
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-static void _had_wq(struct work_struct *work)
-{
- struct hdmi_lpe_audio_ctx *ctx =
- container_of(work, struct hdmi_lpe_audio_ctx, hdmi_audio_wq);
-
- mid_hdmi_audio_signal_event(ctx->pdev, HAD_EVENT_HOT_PLUG);
-}
-
-static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id)
-{
- struct platform_device *pdev = dev_id;
- u32 audio_stat, audio_reg;
- struct hdmi_lpe_audio_ctx *ctx;
-
- dev_dbg(&pdev->dev, "%s: Enter\n", __func__);
-
- ctx = platform_get_drvdata(pdev);
-
- audio_reg = AUD_HDMI_STATUS_v2;
- mid_hdmi_audio_read(pdev, audio_reg, &audio_stat);
-
- if (audio_stat & HDMI_AUDIO_UNDERRUN) {
- mid_hdmi_audio_write(pdev, audio_reg, HDMI_AUDIO_UNDERRUN);
- mid_hdmi_audio_signal_event(pdev,
- HAD_EVENT_AUDIO_BUFFER_UNDERRUN);
- }
-
- if (audio_stat & HDMI_AUDIO_BUFFER_DONE) {
- mid_hdmi_audio_write(pdev, audio_reg, HDMI_AUDIO_BUFFER_DONE);
- mid_hdmi_audio_signal_event(pdev,
- HAD_EVENT_AUDIO_BUFFER_DONE);
- }
-
- return IRQ_HANDLED;
-}
-
-static void notify_audio_lpe(struct platform_device *pdev)
-{
- struct hdmi_lpe_audio_ctx *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;
-
- mid_hdmi_audio_signal_event(pdev,
- HAD_EVENT_HOT_UNPLUG);
- } 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));
-
- mid_hdmi_audio_signal_event(pdev, HAD_EVENT_HOT_PLUG);
-
- 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;
- mid_hdmi_audio_signal_event(pdev,
- HAD_EVENT_MODE_CHANGING);
- }
- }
-}
-
-/**
- * hdmi_lpe_audio_probe - start bridge with i915
- *
- * 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
- */
-static int hdmi_lpe_audio_probe(struct platform_device *pdev)
-{
- struct hdmi_lpe_audio_ctx *ctx;
- struct intel_hdmi_lpe_audio_pdata *pdata;
- int irq;
- struct resource *res_mmio;
- void __iomem *mmio_start;
- int ret = 0;
- unsigned long flag_irq;
-
- 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;
- }
-
- /* 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;
- }
-
- 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);
-
- mmio_start = ioremap_nocache(res_mmio->start,
- (size_t)(resource_size(res_mmio)));
- if (!mmio_start) {
- dev_err(&pdev->dev, "Could not get ioremap\n");
- return -EACCES;
- }
-
- /* alloc and save context */
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
- if (ctx == NULL) {
- ret = -ENOMEM;
- goto error_ctx;
- }
-
- ctx->pdev = pdev;
- ctx->irq = irq;
- dev_dbg(&pdev->dev, "hdmi lpe audio: irq num = %d\n", irq);
- ctx->mmio_start = mmio_start;
- ctx->tmds_clock_speed = DIS_SAMPLE_RATE_148_5;
- INIT_WORK(&ctx->hdmi_audio_wq, _had_wq);
- ctx->state = hdmi_connector_status_disconnected;
-
- /* assume pipe A as default */
- ctx->had_config_offset = AUDIO_HDMI_CONFIG_A;
-
- platform_set_drvdata(pdev, ctx);
-
- /* setup interrupt handler */
- ret = request_irq(irq, display_pipe_interrupt_handler, 0,
- pdev->name, pdev);
-
- if (ret < 0) {
- dev_err(&pdev->dev, "request_irq failed\n");
- goto error_irq;
- }
-
- ret = hdmi_audio_probe(pdev, &ctx->had);
- if (ret < 0)
- goto error_probe;
-
- dev_dbg(&pdev->dev, "hdmi lpe audio: setting pin eld notify callback\n");
-
- /* The Audio driver is loading now and we need to notify
- * it if there is an HDMI device attached
- */
- dev_dbg(&pdev->dev, "%s: Scheduling HDMI audio work queue\n",
- __func__);
- schedule_work(&ctx->hdmi_audio_wq);
-
- spin_lock_irqsave(&pdata->lpe_audio_slock, flag_irq);
- pdata->notify_audio_lpe = notify_audio_lpe;
- if (pdata->notify_pending) {
-
- 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, flag_irq);
-
- return ret;
-
- error_probe:
- free_irq(irq, pdev);
- error_irq:
- kfree(ctx);
- error_ctx:
- iounmap(mmio_start);
- return ret;
-}
-
-/**
- * hdmi_lpe_audio_remove - stop bridge with i915
- *
- * This function is called when the platform device is destroyed. The sound
- * card should have been removed on hot plug event.
- */
-static int hdmi_lpe_audio_remove(struct platform_device *pdev)
-{
- struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev);
-
- dev_dbg(&pdev->dev, "Enter %s\n", __func__);
-
- hdmi_audio_remove(ctx->had);
-
- /* release resources */
- iounmap(ctx->mmio_start);
- free_irq(ctx->irq, pdev);
- kfree(ctx);
- return 0;
-}
-
-static int hdmi_lpe_audio_suspend(struct platform_device *pdev,
- pm_message_t state)
-{
- struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev);
-
- dev_dbg(&pdev->dev, "%s: state %d", __func__, ctx->state);
- /* HDMI is not connected, assuming audio device is suspended already */
- if (ctx->state != hdmi_connector_status_disconnected)
- hdmi_audio_suspend(ctx->had);
- return 0;
-}
-
-static int hdmi_lpe_audio_resume(struct platform_device *pdev)
-{
- struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev);
-
- dev_dbg(&pdev->dev, "%s: state %d", __func__, ctx->state);
- /* HDMI is not connected, there is no need to resume audio device */
- if (ctx->state != hdmi_connector_status_disconnected)
- hdmi_audio_resume(ctx->had);
- 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_LICENSE("GPL v2");
-MODULE_ALIAS("platform:hdmi_lpe_audio");
OpenPOWER on IntegriCloud