summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorguoyin.chen <guoyin.chen@freescale.com>2013-02-27 13:32:17 +0800
committerguoyin.chen <guoyin.chen@freescale.com>2013-02-27 13:32:17 +0800
commit66c3a24a57bd9e721f5d0d45924c3c250bb37770 (patch)
tree5c467232e149c887a847cedb1cf762a6a6940924 /sound
parent57ee456c6db3bb07b4725b234ac0a4aefd1c80e1 (diff)
parent85b80e70a92ad66b86dc0a1636c59145b9fbf39c (diff)
Merge remote-tracking branch 'fsl-linux-sdk/imx_3.0.35' into imx_3.0.35_android
Conflicts: arch/arm/mach-mx6/Makefile arch/arm/mach-mx6/board-mx6dl_hdmidongle.h arch/arm/mach-mx6/board-mx6q_hdmidongle.c arch/arm/mach-mx6/board-mx6q_hdmidongle.h arch/arm/mach-mx6/board-mx6q_sabreauto.c arch/arm/mach-mx6/board-mx6q_sabrelite.c drivers/media/video/mxc/capture/csi_v4l2_capture.c drivers/media/video/mxc/capture/ipu_csi_enc.c drivers/mxc/gpu-viv/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.c drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel.c drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel.h drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal.h drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_compiler.h drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_enum.h drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_options.h drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.c drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_driver.c drivers/mxc/vpu/mxc_vpu.c drivers/usb/gadget/arcotg_udc.c drivers/video/mxc/mxc_ipuv3_fb.c drivers/video/mxc_hdmi.c include/linux/mxcfb.h sound/soc/imx/imx-wm8962.c
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/imx/Kconfig6
-rw-r--r--sound/soc/imx/imx-ssi.c96
-rw-r--r--sound/soc/imx/imx-wm8962.c272
3 files changed, 266 insertions, 108 deletions
diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig
index 7fb135ab70f1..9b01af01a45d 100644
--- a/sound/soc/imx/Kconfig
+++ b/sound/soc/imx/Kconfig
@@ -124,4 +124,10 @@ config SND_SOC_IMX_HDMI
help
Say Y if you want to add support for SoC audio through IMX HDMI.
+config SND_MXC_SOC_IRAM
+ bool "Locate SSI Audio DMA playback buffers in IRAM"
+ depends on MACH_MX6SL_EVK && MACH_MX6SL_ARM2
+ help
+ Say Y if you don't want Audio playback buffers in external ram
+
endif # SND_IMX_SOC
diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c
index 060d093a0aa9..d398307873bf 100644
--- a/sound/soc/imx/imx-ssi.c
+++ b/sound/soc/imx/imx-ssi.c
@@ -1,7 +1,7 @@
/*
* imx-ssi.c -- ALSA Soc Audio Layer
*
- * Copyright 2010-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2010-2013 Freescale Semiconductor, Inc. All Rights Reserved.
*
* Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
*
@@ -53,6 +53,7 @@
#include <sound/soc.h>
#include <mach/ssi.h>
+#include <mach/iram.h>
#include <mach/hardware.h>
#include "imx-ssi.h"
@@ -62,6 +63,9 @@
#define IMX_SSI_FORMATS \
(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
SNDRV_PCM_FMTBIT_S24_LE)
+#ifdef CONFIG_SND_MXC_SOC_IRAM
+static int UseIRAM;
+#endif
/*
* SSI Network Mode or TDM slots configuration.
@@ -419,15 +423,61 @@ static struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
.shutdown = imx_ssi_shutdown,
};
+#ifdef CONFIG_SND_MXC_SOC_IRAM
+
+static struct vm_operations_struct snd_mxc_audio_playback_vm_ops = {
+ .open = snd_pcm_mmap_data_open,
+ .close = snd_pcm_mmap_data_close,
+};
+
+/*
+ enable user space access to iram buffer
+*/
+static int imx_iram_audio_playback_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *area)
+{
+ struct snd_dma_buffer *buf = &substream->dma_buffer;
+ unsigned long off;
+ unsigned long phys;
+ unsigned long size;
+ int ret = 0;
+
+ area->vm_ops = &snd_mxc_audio_playback_vm_ops;
+ area->vm_private_data = substream;
+
+ off = area->vm_pgoff << PAGE_SHIFT;
+ phys = buf->addr + off;
+ size = area->vm_end - area->vm_start;
+
+ area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
+ area->vm_flags |= VM_IO;
+ ret =
+ remap_pfn_range(area, area->vm_start, phys >> PAGE_SHIFT,
+ size, area->vm_page_prot);
+
+ return ret;
+}
+#endif
+
int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
{
struct snd_pcm_runtime *runtime = substream->runtime;
int ret;
+#ifdef CONFIG_SND_MXC_SOC_IRAM
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+ if ((!strncmp(rtd->cpu_dai->name, "imx-ssi", strlen("imx-ssi")))
+ && (UseIRAM & (1<<substream->stream)))
+ ret = imx_iram_audio_playback_mmap(substream, vma);
+ else
+ ret = dma_mmap_coherent(NULL, vma, runtime->dma_area,
+ runtime->dma_addr, runtime->dma_bytes);
+#else
ret = dma_mmap_coherent(NULL, vma, runtime->dma_area,
runtime->dma_addr, runtime->dma_bytes);
-
+#endif
pr_debug("%s: ret: %d %p 0x%08x 0x%08x\n", __func__, ret,
runtime->dma_area,
runtime->dma_addr,
@@ -442,6 +492,9 @@ static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
struct snd_soc_pcm_runtime *rtd = pcm->private_data;
struct snd_dma_buffer *buf = &substream->dma_buffer;
size_t size;
+#ifdef CONFIG_SND_MXC_SOC_IRAM
+ unsigned long buf_paddr;
+#endif
if (!strncmp(rtd->cpu_dai->name, "imx-ssi", strlen("imx-ssi")))
size = IMX_SSI_DMABUF_SIZE;
@@ -455,11 +508,34 @@ static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
buf->dev.type = SNDRV_DMA_TYPE_DEV;
buf->dev.dev = pcm->card->dev;
buf->private_data = NULL;
+ buf->bytes = size;
+
+#ifdef CONFIG_SND_MXC_SOC_IRAM
+ if (!strncmp(rtd->cpu_dai->name, "imx-ssi", strlen("imx-ssi"))) {
+ buf->area = iram_alloc(size, &buf_paddr);
+ if (!buf->area) {
+ buf->area =
+ dma_alloc_writecombine(pcm->card->dev, size,
+ &buf->addr, GFP_KERNEL);
+ if (!buf->area)
+ return -ENOMEM;
+ } else {
+ buf->addr = buf_paddr;
+ UseIRAM |= 1<<substream->stream;
+ }
+ } else {
+ buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+ &buf->addr, GFP_KERNEL);
+ if (!buf->area)
+ return -ENOMEM;
+
+ }
+#else
buf->area = dma_alloc_writecombine(pcm->card->dev, size,
&buf->addr, GFP_KERNEL);
if (!buf->area)
return -ENOMEM;
- buf->bytes = size;
+#endif
return 0;
}
@@ -500,6 +576,9 @@ void imx_pcm_free(struct snd_pcm *pcm)
struct snd_pcm_substream *substream;
struct snd_dma_buffer *buf;
int stream;
+#ifdef CONFIG_SND_MXC_SOC_IRAM
+ struct snd_soc_pcm_runtime *rtd = pcm->private_data;
+#endif
for (stream = 0; stream < 2; stream++) {
substream = pcm->streams[stream].substream;
@@ -510,8 +589,19 @@ void imx_pcm_free(struct snd_pcm *pcm)
if (!buf->area)
continue;
+#ifdef CONFIG_SND_MXC_SOC_IRAM
+ if ((!strncmp(rtd->cpu_dai->name, "imx-ssi", strlen("imx-ssi")))
+ && (UseIRAM & (1<<substream->stream))) {
+ iram_free(buf->addr, IMX_SSI_DMABUF_SIZE);
+ UseIRAM &= ~(1<<substream->stream);
+ } else {
+ dma_free_writecombine(pcm->card->dev, buf->bytes,
+ buf->area, buf->addr);
+ }
+#else
dma_free_writecombine(pcm->card->dev, buf->bytes,
buf->area, buf->addr);
+#endif
buf->area = NULL;
}
}
diff --git a/sound/soc/imx/imx-wm8962.c b/sound/soc/imx/imx-wm8962.c
index ad8e5fd94e02..d57ff16585aa 100644
--- a/sound/soc/imx/imx-wm8962.c
+++ b/sound/soc/imx/imx-wm8962.c
@@ -1,7 +1,7 @@
/*
* imx-wm8962.c
*
- * Copyright (C) 2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -65,6 +65,34 @@ static int suspend_mic_flag;
static int hp_irq;
static int mic_irq;
+static struct snd_soc_jack imx_hp_jack;
+static struct snd_soc_jack_pin imx_hp_jack_pins[] = {
+ {
+ .pin = "Ext Spk",
+ .mask = SND_JACK_HEADPHONE,
+ },
+};
+static struct snd_soc_jack_gpio imx_hp_jack_gpio = {
+ .name = "headphone detect",
+ .report = SND_JACK_HEADPHONE,
+ .debounce_time = 150,
+ .invert = 0,
+};
+
+static struct snd_soc_jack imx_mic_jack;
+static struct snd_soc_jack_pin imx_mic_jack_pins[] = {
+ {
+ .pin = "DMIC",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+static struct snd_soc_jack_gpio imx_mic_jack_gpio = {
+ .name = "micphone detect",
+ .report = SND_JACK_MICROPHONE,
+ .debounce_time = 150,
+ .invert = 0,
+};
+
static int imx_hifi_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -152,6 +180,115 @@ static int imx_hifi_hw_params(struct snd_pcm_substream *substream,
return 0;
}
+static void imx_resume_event(struct work_struct *wor)
+{
+ struct imx_priv *priv = &card_priv;
+ struct platform_device *pdev = priv->pdev;
+ struct mxc_audio_platform_data *plat = pdev->dev.platform_data;
+ struct snd_soc_jack *jack;
+ int enable;
+ int report;
+
+ if (plat->hp_gpio != -1) {
+ jack = imx_hp_jack_gpio.jack;
+
+ enable = gpio_get_value_cansleep(imx_hp_jack_gpio.gpio);
+ if (imx_hp_jack_gpio.invert)
+ enable = !enable;
+
+ if (enable)
+ report = imx_hp_jack_gpio.report;
+ else
+ report = 0;
+
+ snd_soc_jack_report(jack, report, imx_hp_jack_gpio.report);
+ }
+
+ if (plat->mic_gpio != -1) {
+ jack = imx_mic_jack_gpio.jack;
+
+ enable = gpio_get_value_cansleep(imx_mic_jack_gpio.gpio);
+ if (imx_mic_jack_gpio.invert)
+ enable = !enable;
+
+ if (enable)
+ report = imx_mic_jack_gpio.report;
+ else
+ report = 0;
+
+ snd_soc_jack_report(jack, report, imx_mic_jack_gpio.report);
+ }
+
+ return;
+}
+
+static int imx_event_hp(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct imx_priv *priv = &card_priv;
+ struct platform_device *pdev = priv->pdev;
+ struct mxc_audio_platform_data *plat = pdev->dev.platform_data;
+ char *envp[3];
+ char *buf;
+
+ if (plat->hp_gpio != -1) {
+ priv->hp_status = gpio_get_value(plat->hp_gpio);
+
+ buf = kmalloc(32, GFP_ATOMIC);
+ if (!buf) {
+ pr_err("%s kmalloc failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ if (priv->hp_status != plat->hp_active_low)
+ snprintf(buf, 32, "STATE=%d", 2);
+ else
+ snprintf(buf, 32, "STATE=%d", 0);
+
+ envp[0] = "NAME=headphone";
+ envp[1] = buf;
+ envp[2] = NULL;
+ kobject_uevent_env(&pdev->dev.kobj, KOBJ_CHANGE, envp);
+ kfree(buf);
+ }
+
+ return 0;
+}
+
+static int imx_event_mic(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct imx_priv *priv = &card_priv;
+ struct platform_device *pdev = priv->pdev;
+ struct mxc_audio_platform_data *plat = pdev->dev.platform_data;
+ char *envp[3];
+ char *buf;
+
+ if (plat->mic_gpio != -1) {
+ priv->amic_status = gpio_get_value(plat->mic_gpio);
+
+ buf = kmalloc(32, GFP_ATOMIC);
+ if (!buf) {
+ pr_err("%s kmalloc failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ if (priv->amic_status == 0)
+ snprintf(buf, 32, "STATE=%d", 2);
+ else
+ snprintf(buf, 32, "STATE=%d", 0);
+
+ envp[0] = "NAME=amic";
+ envp[1] = buf;
+ envp[2] = NULL;
+ kobject_uevent_env(&pdev->dev.kobj, KOBJ_CHANGE, envp);
+ kfree(buf);
+ }
+
+ return 0;
+}
+
+
static const struct snd_kcontrol_new controls[] = {
SOC_DAPM_PIN_SWITCH("Ext Spk"),
};
@@ -159,9 +296,9 @@ static const struct snd_kcontrol_new controls[] = {
/* imx card dapm widgets */
static const struct snd_soc_dapm_widget imx_dapm_widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_SPK("Ext Spk", NULL),
+ SND_SOC_DAPM_SPK("Ext Spk", imx_event_hp),
SND_SOC_DAPM_MIC("AMIC", NULL),
- SND_SOC_DAPM_MIC("DMIC", NULL),
+ SND_SOC_DAPM_MIC("DMIC", imx_event_mic),
};
/* imx machine connections to the codec pins */
@@ -264,64 +401,6 @@ static ssize_t show_headphone(struct device_driver *dev, char *buf)
static DRIVER_ATTR(headphone, S_IRUGO | S_IWUSR, show_headphone, NULL);
-static void amic_detect_handler(struct work_struct *work)
-{
- struct imx_priv *priv = &card_priv;
- struct platform_device *pdev = priv->pdev;
- struct mxc_audio_platform_data *plat = pdev->dev.platform_data;
- char *envp[3];
- char *buf;
-
- /* sysfs_notify(&pdev->dev.kobj, NULL, "amic"); */
- priv->amic_status = gpio_get_value(plat->mic_gpio);
-
- /* if amic is inserted, disable dmic */
- if (priv->amic_status != plat->mic_active_low)
- snd_soc_dapm_nc_pin(&gcodec->dapm, "DMIC");
- else
- snd_soc_dapm_enable_pin(&gcodec->dapm, "DMIC");
-
- snd_soc_dapm_sync(&gcodec->dapm);
-
- /* setup a message for userspace headphone in */
- buf = kmalloc(32, GFP_ATOMIC);
- if (!buf) {
- pr_err("%s kmalloc failed\n", __func__);
- return;
- }
-
- if (priv->amic_status == 0)
- snprintf(buf, 32, "STATE=%d", 2);
- else
- snprintf(buf, 32, "STATE=%d", 0);
-
- envp[0] = "NAME=amic";
- envp[1] = buf;
- envp[2] = NULL;
- kobject_uevent_env(&pdev->dev.kobj, KOBJ_CHANGE, envp);
- kfree(buf);
-
- if ((suspend_mic_flag == 1) && (mic_irq == 0)) {
- suspend_mic_flag = 0;
- return;
- }
- mic_irq = 0;
- enable_irq(priv->amic_irq);
-}
-
-static DECLARE_DELAYED_WORK(amic_event, amic_detect_handler);
-
-static irqreturn_t imx_amic_detect_handler(int irq, void *data)
-{
- if (suspend_mic_flag == 1)
- return IRQ_HANDLED;
-
- mic_irq = 1;
- disable_irq_nosync(irq);
- schedule_delayed_work(&amic_event, msecs_to_jiffies(200));
- return IRQ_HANDLED;
-}
-
static ssize_t show_amic(struct device_driver *dev, char *buf)
{
struct imx_priv *priv = &card_priv;
@@ -329,7 +408,7 @@ static ssize_t show_amic(struct device_driver *dev, char *buf)
struct mxc_audio_platform_data *plat = pdev->dev.platform_data;
/* determine whether amic is plugged in */
- priv->amic_status = gpio_get_value(plat->mic_gpio);
+ priv->amic_status = gpio_get_value(plat->hp_gpio);
if (priv->amic_status != plat->mic_active_low)
strcpy(buf, "amic\n");
@@ -341,9 +420,7 @@ static ssize_t show_amic(struct device_driver *dev, char *buf)
static DRIVER_ATTR(amic, S_IRUGO | S_IWUSR, show_amic, NULL);
-static DECLARE_DELAYED_WORK(resume_hp_event, headphone_detect_handler);
-static DECLARE_DELAYED_WORK(resume_mic_event, amic_detect_handler);
-
+static DECLARE_DELAYED_WORK(resume_hp_event, imx_resume_event);
int imx_hifi_trigger(struct snd_pcm_substream *substream, int cmd)
{
@@ -351,17 +428,10 @@ int imx_hifi_trigger(struct snd_pcm_substream *substream, int cmd)
struct platform_device *pdev = priv->pdev;
struct mxc_audio_platform_data *plat = pdev->dev.platform_data;
- if (SNDRV_PCM_TRIGGER_SUSPEND == cmd) {
- suspend_hp_flag = 1;
- suspend_mic_flag = 1;
- }
if (SNDRV_PCM_TRIGGER_RESUME == cmd) {
- if (plat->hp_gpio != -1)
+ if ((plat->hp_gpio != -1) || (plat->mic_gpio != -1))
schedule_delayed_work(&resume_hp_event,
- msecs_to_jiffies(200));
- if (plat->mic_gpio != -1)
- schedule_delayed_work(&resume_mic_event,
- msecs_to_jiffies(200));
+ msecs_to_jiffies(200));
}
return 0;
@@ -388,19 +458,17 @@ static int imx_wm8962_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_enable_pin(&codec->dapm, "AMIC");
if (plat->hp_gpio != -1) {
- priv->hp_irq = gpio_to_irq(plat->hp_gpio);
-
- ret = request_irq(priv->hp_irq,
- imx_headphone_detect_handler,
- IRQ_TYPE_EDGE_BOTH, pdev->name, priv);
-
- if (ret < 0) {
- ret = -EINVAL;
- return ret;
- }
+ imx_hp_jack_gpio.gpio = plat->hp_gpio;
+ snd_soc_jack_new(codec, "Ext Spk", SND_JACK_LINEOUT,
+ &imx_hp_jack);
+ snd_soc_jack_add_pins(&imx_hp_jack,
+ ARRAY_SIZE(imx_hp_jack_pins),
+ imx_hp_jack_pins);
+ snd_soc_jack_add_gpios(&imx_hp_jack,
+ 1, &imx_hp_jack_gpio);
ret = driver_create_file(pdev->dev.driver,
- &driver_attr_headphone);
+ &driver_attr_headphone);
if (ret < 0) {
ret = -EINVAL;
return ret;
@@ -416,32 +484,26 @@ static int imx_wm8962_init(struct snd_soc_pcm_runtime *rtd)
}
if (plat->mic_gpio != -1) {
- priv->amic_irq = gpio_to_irq(plat->mic_gpio);
-
- ret = request_irq(priv->amic_irq,
- imx_amic_detect_handler,
- IRQ_TYPE_EDGE_BOTH, pdev->name, priv);
+ imx_mic_jack_gpio.gpio = plat->mic_gpio;
+ snd_soc_jack_new(codec, "DMIC", SND_JACK_MICROPHONE,
+ &imx_mic_jack);
+ snd_soc_jack_add_pins(&imx_mic_jack,
+ ARRAY_SIZE(imx_mic_jack_pins),
+ imx_mic_jack_pins);
+ snd_soc_jack_add_gpios(&imx_mic_jack,
+ 1, &imx_mic_jack_gpio);
+ ret = driver_create_file(pdev->dev.driver,
+ &driver_attr_amic);
if (ret < 0) {
ret = -EINVAL;
return ret;
}
-
- ret = driver_create_file(pdev->dev.driver, &driver_attr_amic);
- if (ret < 0) {
- ret = -EINVAL;
- return ret;
- }
-
- priv->amic_status = gpio_get_value(plat->mic_gpio);
-
- /* if amic is inserted, disable DMIC */
- if (priv->amic_status != plat->mic_active_low)
- snd_soc_dapm_nc_pin(&codec->dapm, "DMIC");
- else
- snd_soc_dapm_enable_pin(&codec->dapm, "DMIC");
- } else if (!snd_soc_dapm_get_pin_status(&codec->dapm, "DMICDAT"))
+ } else {
snd_soc_dapm_nc_pin(&codec->dapm, "DMIC");
+ }
+
+ snd_soc_dapm_sync(&codec->dapm);
snd_soc_dapm_sync(&codec->dapm);