[alsa-devel] [RFC 2/4] ASoC SST: Add mid platfrom driver
Koul, Vinod
vinod.koul at intel.com
Tue Dec 28 13:10:58 CET 2010
From: Vinod Koul <vinod.koul at intel.com>
This patch adds the platform driver for mid asoc drivers
This platfrom driver sends commands to sst dsp engine driver for the dai operations
Signed-off-by: Vinod Koul <vinod.koul at intel.com>
Signed-off-by: Harsha Priya <priya.harsha at intel.com>
---
sound/soc/mid-x86/mid_platform.c | 326 ++++++++++++++++++++++++++++++++++
sound/soc/mid-x86/mid_platform.h | 77 ++++++++
sound/soc/mid-x86/mid_platform_pvt.c | 121 +++++++++++++
3 files changed, 524 insertions(+), 0 deletions(-)
create mode 100644 sound/soc/mid-x86/mid_platform.c
create mode 100644 sound/soc/mid-x86/mid_platform.h
create mode 100644 sound/soc/mid-x86/mid_platform_pvt.c
diff --git a/sound/soc/mid-x86/mid_platform.c b/sound/soc/mid-x86/mid_platform.c
new file mode 100644
index 0000000..8c854df
--- /dev/null
+++ b/sound/soc/mid-x86/mid_platform.c
@@ -0,0 +1,326 @@
+/*
+ * mid_platform.c - Intel MID common Platform driver
+ *
+ * Copyright (C) 2010 Intel Corp
+ * Author: Harsha Priya <priya.harsha at 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/intel_sst.h>
+#include <linux/slab.h>
+#include "mid_platform.h"
+
+static struct snd_pcm_hardware snd_intelmad_pcm_hw = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_DOUBLE |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME |
+ SNDRV_PCM_INFO_MMAP|
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_SYNC_START),
+ .formats = (SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_U16 |
+ SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_U24 |
+ SNDRV_PCM_FMTBIT_S32 | SNDRV_PCM_FMTBIT_U32),
+ .rates = (SNDRV_PCM_RATE_8000|
+ SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000),
+ .rate_min = MIN_RATE,
+ .rate_max = MAX_RATE,
+ .channels_min = MIN_CHANNEL,
+ .channels_max = MAX_CHANNEL_AMIC,
+ .buffer_bytes_max = MAX_BUFFER,
+ .period_bytes_min = MIN_PERIOD_BYTES,
+ .period_bytes_max = MAX_PERIOD_BYTES,
+ .periods_min = MIN_PERIODS,
+ .periods_max = MAX_PERIODS,
+ .fifo_size = FIFO_SIZE,
+};
+
+static int mid_platform_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime;
+ struct mid_runtime_stream *stream;
+ int ret_val = 0;
+
+ WARN_ON(!substream);
+
+ pr_debug("mid_platform_open called\n");
+
+ runtime = substream->runtime;
+ runtime->hw = snd_intelmad_pcm_hw;
+
+ stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+ if (!stream)
+ return -ENOMEM;
+ stream->stream_info.str_id = 0;
+ stream->stream_status = INIT;
+ stream->stream_info.mad_substream = substream;
+ /* allocate memory for LPE API set */
+ stream->sstdrv_ops = kzalloc(sizeof(*stream->sstdrv_ops),
+ GFP_KERNEL);
+ if (!stream->sstdrv_ops) {
+ pr_err("sst: mem allocation for ops fail\n");
+ kfree(stream);
+ return -ENOMEM;
+ }
+ stream->sstdrv_ops->vendor_id = MSIC_VENDOR_ID;
+
+ /* registering with SST driver to get access to SST APIs to use */
+ ret_val = register_sst_card(stream->sstdrv_ops);
+ if (ret_val) {
+ pr_err("sst: sst card registration failed\n");
+ return ret_val;
+ }
+ runtime->private_data = stream;
+ return snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+}
+
+static int mid_platform_close(struct snd_pcm_substream *substream)
+{
+ struct mid_runtime_stream *stream;
+ int ret_val = 0, str_id;
+
+ pr_debug("mid_platform_close called\n");
+ WARN_ON(!substream);
+
+ stream = substream->runtime->private_data;
+ str_id = stream->stream_info.str_id;
+
+ if (str_id)
+ ret_val = stream->sstdrv_ops->pcm_control->close(str_id);
+ kfree(stream->sstdrv_ops);
+ kfree(stream);
+ return ret_val;
+}
+
+static int mid_platform_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ struct mid_runtime_stream *stream;
+ int ret_val = 0, str_id;
+ struct mid_sst_pcm_control *sst_ops;
+
+ pr_debug("mid_platform_pcm_prepare called\n");
+
+ WARN_ON(!substream);
+ stream = substream->runtime->private_data;
+ sst_ops = stream->sstdrv_ops->pcm_control;
+ str_id = stream->stream_info.str_id;
+ if (stream->stream_info.str_id) {
+ ret_val = sst_ops->device_control(SST_SND_DROP, &str_id);
+ return ret_val;
+ }
+
+ ret_val = snd_intelmad_alloc_stream(substream);
+ if (ret_val < 0)
+ return ret_val;
+ snprintf(substream->pcm->id, sizeof(substream->pcm->id),
+ "%d", stream->stream_info.str_id);
+
+ ret_val = snd_intelmad_init_stream(substream);
+ if (ret_val)
+ return ret_val;
+ substream->runtime->hw.info = SNDRV_PCM_INFO_BLOCK_TRANSFER;
+ return ret_val;
+}
+
+static int mid_platform_pcm_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+{
+ int ret_val = 0, str_id;
+ struct mid_runtime_stream *stream;
+ struct mid_sst_pcm_control *sst_ops;
+
+ pr_debug("mid_platform_pcm_trigger called\n");
+ WARN_ON(!substream);
+
+ stream = substream->runtime->private_data;
+
+ sst_ops = stream->sstdrv_ops->pcm_control;
+ str_id = stream->stream_info.str_id;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ pr_debug("sst: Trigger Start\n");
+ ret_val = sst_ops->device_control(SST_SND_START, &str_id);
+ if (ret_val)
+ return ret_val;
+ stream->stream_status = RUNNING;
+ stream->stream_info.mad_substream = substream;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ pr_debug("sst: in stop\n");
+ ret_val = sst_ops->device_control(SST_SND_DROP, &str_id);
+ if (ret_val)
+ return ret_val;
+ stream->stream_status = DROPPED;
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ pr_debug("sst: in pause\n");
+ ret_val = sst_ops->device_control(SST_SND_PAUSE, &str_id);
+ if (ret_val)
+ return ret_val;
+ stream->stream_status = PAUSED;
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ pr_debug("sst: in pause release\n");
+ ret_val = sst_ops->device_control(SST_SND_RESUME, &str_id);
+ if (ret_val)
+ return ret_val;
+ stream->stream_status = RUNNING;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return ret_val;
+}
+
+
+static snd_pcm_uframes_t mid_platform_pcm_pointer
+ (struct snd_pcm_substream *substream)
+{
+ /* struct snd_pcm_runtime *runtime = substream->runtime; */
+ struct mid_runtime_stream *stream;
+ int ret_val;
+ struct mid_sst_pcm_control *sst_ops;
+ struct mid_pcm_stream_info *str_info;
+
+ pr_debug("mid_platform_pcm_pointer called\n");
+ WARN_ON(!substream);
+
+ stream = substream->runtime->private_data;
+ if (stream->stream_status == INIT)
+ return 0;
+ sst_ops = stream->sstdrv_ops->pcm_control;
+ str_info = &stream->stream_info;
+ ret_val = sst_ops->device_control(SST_SND_BUFFER_POINTER, str_info);
+ if (ret_val) {
+ pr_err("sst: error code = 0x%x\n", ret_val);
+ return ret_val;
+ }
+
+ return stream->stream_info.buffer_ptr;
+}
+
+
+static struct snd_pcm_ops intel_mid_platform_ops = {
+ .open = mid_platform_open,
+ .close = mid_platform_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .prepare = mid_platform_pcm_prepare,
+ .trigger = mid_platform_pcm_trigger,
+ .pointer = mid_platform_pcm_pointer,
+};
+
+static void intel_mid_pcm_free(struct snd_pcm *pcm)
+{
+ pr_debug("intel_mid_pcm_free called\n");
+ snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+int intel_mid_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
+ struct snd_pcm *pcm)
+{
+ int retval = 0;
+
+ pr_debug("intel_mid_pcm_new called\n");
+
+ if (dai->driver->playback.channels_min ||
+ dai->driver->capture.channels_min) {
+ retval = snd_pcm_lib_preallocate_pages_for_all(pcm,
+ SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_dma_continuous_data(GFP_KERNEL),
+ MIN_BUFFER, MAX_BUFFER);
+ if (retval) {
+ pr_err("dma buffer allocationf fail\n");
+ return retval;
+ }
+ }
+
+ return retval;
+}
+struct snd_soc_platform_driver intelmid_soc_platform_drv = {
+ .ops = &intel_mid_platform_ops,
+ .pcm_new = intel_mid_pcm_new,
+ .pcm_free = intel_mid_pcm_free,
+};
+
+static int intelmid_platform_probe(struct platform_device *pdev)
+{
+ struct mid_dev_data *dev_data = platform_get_drvdata(pdev);
+ int ret;
+ pr_debug("intelmid_platform_probe called\n");
+ ret = snd_soc_register_platform(&pdev->dev, &intelmid_soc_platform_drv);
+ if (ret) {
+ pr_err("registering soc platform failed\n");
+ return ret;
+ }
+ return snd_soc_register_dais(&pdev->dev,
+ dev_data->dai, dev_data->num_dais);
+}
+
+static int intelmid_platform_remove(struct platform_device *pdev)
+{
+ struct mid_dev_data *dev_data = platform_get_drvdata(pdev);
+
+ if (dev_data)
+ snd_soc_unregister_dais(&pdev->dev, dev_data->num_dais);
+
+ snd_soc_unregister_platform(&pdev->dev);
+ pr_debug("intelmid_platform_remove sucess\n");
+
+ return 0;
+}
+
+static struct platform_driver intelmid_platform_driver = {
+ .driver = {
+ .name = "mid-audio-platform",
+ .owner = THIS_MODULE,
+ },
+ .probe = intelmid_platform_probe,
+ .remove = intelmid_platform_remove,
+ /*.suspend = intelmid_platform_suspend,
+ .resume = intelmid_platform_resume,*/
+};
+
+static int __init intel_mid_soc_platform_init(void)
+{
+ pr_debug("intel_mid_soc_platform_init called\n");
+ return platform_driver_register(&intelmid_platform_driver);
+}
+module_init(intel_mid_soc_platform_init);
+
+static void __exit intel_mid_soc_platform_exit(void)
+{
+ platform_driver_unregister(&intelmid_platform_driver);
+ pr_debug("intel_mid_soc_platform_exit sucess\n");
+}
+module_exit(intel_mid_soc_platform_exit);
+
+MODULE_DESCRIPTION("ASoC Intel(R) PLATFORM driver");
+MODULE_AUTHOR("Harsha Priya");
+MODULE_LICENSE("GPL v2");
+
diff --git a/sound/soc/mid-x86/mid_platform.h b/sound/soc/mid-x86/mid_platform.h
new file mode 100644
index 0000000..6d719c0
--- /dev/null
+++ b/sound/soc/mid-x86/mid_platform.h
@@ -0,0 +1,77 @@
+/*
+ * mid_platform.h - Intel MID Platform driver header file
+ *
+ * Copyright (C) 2010 Intel Corp
+ * Author: Harsha Priya <priya.harsha at 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *
+ */
+
+#ifndef __MID_PLATFORMDRV_H__
+#define __MID_PLATFORMDRV_H__
+
+#define MIN_RATE 8000
+#define MAX_RATE 48000
+#define MIN_CHANNEL 1
+#define MAX_CHANNEL_AMIC 2
+#define MAX_CHANNEL_DMIC 5
+#define MAX_BUFFER (800*1024)
+#define MIN_BUFFER (800*1024)
+#define MIN_PERIOD_BYTES 32
+#define MAX_PERIOD_BYTES MAX_BUFFER
+#define MIN_PERIODS 2
+#define MAX_PERIODS (1024*2)
+#define FIFO_SIZE 0
+#define MSIC_VENDOR_ID 0x3
+#define SST_CARD_NAMES "intel_mid_card"
+
+int snd_intelmad_alloc_stream(struct snd_pcm_substream *substream);
+int snd_intelmad_init_stream(struct snd_pcm_substream *substream);
+
+struct mid_runtime_stream {
+ int stream_status;
+ struct mid_pcm_stream_info stream_info;
+ struct intel_sst_card_ops *sstdrv_ops;
+ unsigned long long buffer_ptr;
+};
+
+struct mid_dev_data {
+ struct snd_soc_dai_driver *dai;
+ int num_dais;
+};
+
+enum mid_drv_status {
+ INIT = 1,
+ STARTED,
+ RUNNING,
+ PAUSED,
+ DROPPED,
+};
+
+/* device */
+enum SND_INPUT_DEVICE {
+ AMIC,
+ DMIC,
+ HS_MIC,
+ IN_UNDEFINED
+};
+
+
+#endif
+
diff --git a/sound/soc/mid-x86/mid_platform_pvt.c b/sound/soc/mid-x86/mid_platform_pvt.c
new file mode 100644
index 0000000..124191f
--- /dev/null
+++ b/sound/soc/mid-x86/mid_platform_pvt.c
@@ -0,0 +1,121 @@
+/*
+ * mid_platform_pvt.c - Intel MID Platform driver private functions
+ *
+ * Copyright (C) 2010 Intel Corp
+ * Author: Harsha Priya <priya.harsha at 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/io.h>
+#include <sound/pcm.h>
+#include <sound/intel_sst.h>
+#include <sound/intel_sst_ioctl.h>
+#include "mid_platform.h"
+
+int snd_intelmad_alloc_stream(struct snd_pcm_substream *substream)
+{
+ struct mid_runtime_stream *stream =
+ substream->runtime->private_data;
+ struct snd_sst_stream_params param = {{{0,},},};
+ struct snd_sst_params str_params = {0};
+ int ret_val;
+
+ /* set codec params and inform SST driver the same */
+
+ param.uc.pcm_params.codec = SST_CODEC_TYPE_PCM;
+ param.uc.pcm_params.num_chan = (u8) substream->runtime->channels;
+ param.uc.pcm_params.pcm_wd_sz = substream->runtime->sample_bits;
+ param.uc.pcm_params.reserved = 0;
+ param.uc.pcm_params.sfreq = substream->runtime->rate;
+ param.uc.pcm_params.ring_buffer_size =
+ snd_pcm_lib_buffer_bytes(substream);
+ param.uc.pcm_params.period_count = substream->runtime->period_size;
+ param.uc.pcm_params.ring_buffer_addr =
+ virt_to_phys(substream->dma_buffer.area);
+ substream->runtime->dma_area = substream->dma_buffer.area;
+
+ pr_debug("period_cnt = %d\n", param.uc.pcm_params.period_count);
+ pr_debug("sfreq= %d, wd_sz = %d\n",
+ param.uc.pcm_params.sfreq, param.uc.pcm_params.pcm_wd_sz);
+
+ str_params.sparams = param;
+ str_params.codec = SST_CODEC_TYPE_PCM;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ str_params.ops = STREAM_OPS_PLAYBACK;
+ str_params.device_type = substream->pcm->device + 1;
+ pr_debug("Playbck stream,Device %d\n",
+ substream->pcm->device);
+ } else {
+ str_params.ops = STREAM_OPS_CAPTURE;
+ str_params.device_type = SND_SST_DEVICE_CAPTURE;
+ pr_debug("Capture stream,Device %d\n",
+ substream->pcm->device);
+ }
+ ret_val = stream->sstdrv_ops->pcm_control->open(&str_params);
+ pr_debug("SST_SND_PLAY/CAPTURE ret_val = %x\n", ret_val);
+ if (ret_val < 0)
+ return ret_val;
+
+ stream->stream_info.str_id = ret_val;
+ pr_debug("str id : %d\n", stream->stream_info.str_id);
+
+ return ret_val;
+}
+
+
+void period_elapsed(void *mad_substream)
+{
+ struct snd_pcm_substream *substream = mad_substream;
+ struct mid_runtime_stream *stream;
+
+ if (!substream || !substream->runtime)
+ return;
+ stream = substream->runtime->private_data;
+ if (!stream)
+ return;
+
+ if (stream->stream_status != RUNNING)
+ return;
+ pr_debug("calling period elapsed\n");
+ snd_pcm_period_elapsed(substream);
+ return;
+}
+
+int snd_intelmad_init_stream(struct snd_pcm_substream *substream)
+{
+ struct mid_runtime_stream *stream =
+ substream->runtime->private_data;
+ int ret_val;
+
+ pr_debug("setting buffer ptr param\n");
+ stream->stream_status = INIT;
+ stream->stream_info.period_elapsed = period_elapsed;
+ stream->stream_info.mad_substream = substream;
+ stream->stream_info.buffer_ptr = 0;
+ stream->stream_info.sfreq = substream->runtime->rate;
+ ret_val = stream->sstdrv_ops->pcm_control->device_control(
+ SST_SND_STREAM_INIT, &stream->stream_info);
+ if (ret_val)
+ pr_err("control_set ret error %d\n", ret_val);
+ return ret_val;
+
+}
--
1.7.2.3
More information about the Alsa-devel
mailing list