Alsa-devel
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
July 2009
- 135 participants
- 252 discussions
[alsa-devel] [PATCH] ASoC: Fix wm8753 register cache size and initialization
by Lars-Peter Clausen 03 Jul '09
by Lars-Peter Clausen 03 Jul '09
03 Jul '09
The register cache size is of by one. There are 63 registers in use but the
register cache size has only space for 62.
Furthermore the codec's reg_cache_size is of by another one. Since the wm8753
register cache uses one-based indexing we have to add one to its size.
Register cache initialization only copied the first sizeof(void*) elements leaving the others
uninitialized. Fix it by using the size of the reg cache template.
Signed-off-by: Lars-Peter Clausen <lars(a)metafoo.de>
---
sound/soc/codecs/wm8753.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index d28eeac..18a3ef9 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -79,7 +79,7 @@ static const u16 wm8753_reg[] = {
0x0097, 0x0097, 0x0000, 0x0004,
0x0000, 0x0083, 0x0024, 0x01ba,
0x0000, 0x0083, 0x0024, 0x01ba,
- 0x0000, 0x0000
+ 0x0000, 0x0000, 0x0000
};
/* codec private data */
@@ -1660,11 +1660,11 @@ static int wm8753_register(struct wm8753_priv *wm8753)
codec->set_bias_level = wm8753_set_bias_level;
codec->dai = wm8753_dai;
codec->num_dai = 2;
- codec->reg_cache_size = ARRAY_SIZE(wm8753->reg_cache);
+ codec->reg_cache_size = ARRAY_SIZE(wm8753->reg_cache) + 1;
codec->reg_cache = &wm8753->reg_cache;
codec->private_data = wm8753;
- memcpy(codec->reg_cache, wm8753_reg, sizeof(codec->reg_cache));
+ memcpy(codec->reg_cache, wm8753_reg, sizeof(wm8753_reg));
INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work);
ret = wm8753_reset(codec);
--
1.5.6.5
2
3
[alsa-devel] [PATCH] ASoC: TWL4030: Add tristate callbacks for HiFi and Voice
by Lopez Cruz, Misael 03 Jul '09
by Lopez Cruz, Misael 03 Jul '09
03 Jul '09
Add "set_tristate" callbacks for HiFi and Voice DAIs.
Machine drivers can enable and disable tristate for each
DAI with "snd_soc_dai_set_tristate" function.
Signed-off-by: Misael Lopez Cruz <x0052729(a)ti.com>
---
sound/soc/codecs/twl4030.c | 28 ++++++++++++++++++++++++++++
1 files changed, 28 insertions(+), 0 deletions(-)
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 6da94ca..818fb37 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -1849,6 +1849,19 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
return 0;
}
+static int twl4030_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF);
+
+ if (tristate)
+ reg |= TWL4030_AIF_TRI_EN;
+ else
+ reg &= ~TWL4030_AIF_TRI_EN;
+
+ return twl4030_write(codec, TWL4030_REG_AUDIO_IF, reg);
+}
+
/* In case of voice mode, the RX1 L(VRX) for downlink and the TX2 L/R
* (VTXL, VTXR) for uplink has to be enabled/disabled. */
static void twl4030_voice_enable(struct snd_soc_codec *codec, int direction,
@@ -2023,6 +2036,19 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
return 0;
}
+static int twl4030_voice_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_VOICE_IF);
+
+ if (tristate)
+ reg |= TWL4030_VIF_TRI_EN;
+ else
+ reg &= ~TWL4030_VIF_TRI_EN;
+
+ return twl4030_write(codec, TWL4030_REG_VOICE_IF, reg);
+}
+
#define TWL4030_RATES (SNDRV_PCM_RATE_8000_48000)
#define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE)
@@ -2032,6 +2058,7 @@ static struct snd_soc_dai_ops twl4030_dai_ops = {
.hw_params = twl4030_hw_params,
.set_sysclk = twl4030_set_dai_sysclk,
.set_fmt = twl4030_set_dai_fmt,
+ .set_tristate = twl4030_set_tristate,
};
static struct snd_soc_dai_ops twl4030_dai_voice_ops = {
@@ -2040,6 +2067,7 @@ static struct snd_soc_dai_ops twl4030_dai_voice_ops = {
.hw_params = twl4030_voice_hw_params,
.set_sysclk = twl4030_voice_set_dai_sysclk,
.set_fmt = twl4030_voice_set_dai_fmt,
+ .set_tristate = twl4030_voice_set_tristate,
};
struct snd_soc_dai twl4030_dai[] = {
--
1.5.4.3
3
2
[alsa-devel] [PATCH] ASoC: Zoom2: Update twl4030_setup_data parameters
by Candelaria Villareal, Jorge 03 Jul '09
by Candelaria Villareal, Jorge 03 Jul '09
03 Jul '09
Add support for EXTMUTE in Zoom2 machine driver. This is necessary
to further reduce pop noise problem. Signal EXTMUTE is connected to
signal GPIO 153 in Zoom2 board.
In addition, change ramp delay value to 3 (218/161/109 ms). With
previous ramp delay value, pop noise was louder. With a longer value
the beep tone can be observed.
Signed-off-by: Jorge Eduardo Candelaria <x0107209(a)ti.com>
---
sound/soc/omap/zoom2.c | 17 +++++++++++++++--
1 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c
index be2e307..ec549a4 100644
--- a/sound/soc/omap/zoom2.c
+++ b/sound/soc/omap/zoom2.c
@@ -35,7 +35,8 @@
#include "omap-pcm.h"
#include "../codecs/twl4030.h"
-#define ZOOM2_HEADSET_MUX_GPIO (OMAP_MAX_GPIO_LINES + 15)
+#define ZOOM2_HEADSET_MUX_GPIO (OMAP_MAX_GPIO_LINES + 15)
+#define ZOOM2_HEADSET_EXTMUTE_GPIO 153
static int zoom2_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
@@ -234,10 +235,18 @@ static struct snd_soc_card snd_soc_zoom2 = {
.num_links = ARRAY_SIZE(zoom2_dai),
};
+/* EXTMUTE callback function */
+void zoom2_set_hs_extmute(int mute)
+{
+ gpio_set_value(ZOOM2_HEADSET_EXTMUTE_GPIO, mute);
+}
+
/* twl4030 setup */
static struct twl4030_setup_data twl4030_setup = {
- .ramp_delay_value = 2, /* 81 ms */
+ .ramp_delay_value = 3, /* 161 ms */
.sysclk = 26000,
+ .hs_extmute = 1,
+ .set_hs_extmute = zoom2_set_hs_extmute,
};
/* Audio subsystem */
@@ -277,6 +286,9 @@ static int __init zoom2_soc_init(void)
BUG_ON(gpio_request(ZOOM2_HEADSET_MUX_GPIO, "hs_mux") < 0);
gpio_direction_output(ZOOM2_HEADSET_MUX_GPIO, 0);
+ BUG_ON(gpio_request(ZOOM2_HEADSET_EXTMUTE_GPIO, "ext_mute") < 0);
+ gpio_direction_output(ZOOM2_HEADSET_EXTMUTE_GPIO, 0);
+
return 0;
err1:
@@ -290,6 +302,7 @@ module_init(zoom2_soc_init);
static void __exit zoom2_soc_exit(void)
{
gpio_free(ZOOM2_HEADSET_MUX_GPIO);
+ gpio_free(ZOOM2_HEADSET_EXTMUTE_GPIO);
platform_device_unregister(zoom2_snd_device);
}
--
1.6.0.4
3
2
[alsa-devel] [PATCH 1/2] ASoC: Fix mpc5200-psc-ac97 to ensure the data ready bit is cleared
by Grant Likely 03 Jul '09
by Grant Likely 03 Jul '09
03 Jul '09
From: Grant Likely <grant.likely(a)secretlab.ca>
When doing register reads, it is possible for there to be a stale
data ready bit set which will cause subsequent reads to return
prematurely with incorrect data. This patch fixes the issues by
ensuring stale data is cleared before starting another transaction.
Signed-off-by: Grant Likely <grant.likely(a)secretlab.ca>
---
sound/soc/fsl/mpc5200_psc_ac97.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c
index 794a247..9b8503f 100644
--- a/sound/soc/fsl/mpc5200_psc_ac97.c
+++ b/sound/soc/fsl/mpc5200_psc_ac97.c
@@ -41,6 +41,10 @@ static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
pr_err("timeout on ac97 bus (rdy)\n");
return -ENODEV;
}
+
+ /* Force clear the data valid bit */
+ in_be32(&psc_dma->psc_regs->ac97_data);
+
/* Send the read */
out_be32(&psc_dma->psc_regs->ac97_cmd, (1<<31) | ((reg & 0x7f) << 24));
4
6
[alsa-devel] [PATCH] ASoC: TWL4030: Add tristate callbacks for HiFi and Voice
by Lopez Cruz, Misael 03 Jul '09
by Lopez Cruz, Misael 03 Jul '09
03 Jul '09
Add "set_tristate" callbacks for HiFi and Voice DAIs.
Machine drivers can enable and disable tristate for each
DAI with "snd_soc_dai_set_tristate" function provided by
SoC core.
Signed-off-by: Misael Lopez Cruz <x0052729(a)ti.com>
---
sound/soc/codecs/twl4030.c | 28 ++++++++++++++++++++++++++++
1 files changed, 28 insertions(+), 0 deletions(-)
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 6da94ca..ffeb53f 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -1849,6 +1849,19 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
return 0;
}
+static int twl4030_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_VOICE_IF);
+
+ if (tristate)
+ reg |= TWL4030_AIF_TRI_EN;
+ else
+ reg &= ~TWL4030_AIF_TRI_EN;
+
+ return twl4030_write(codec, TWL4030_REG_AUDIO_IF, reg);
+}
+
/* In case of voice mode, the RX1 L(VRX) for downlink and the TX2 L/R
* (VTXL, VTXR) for uplink has to be enabled/disabled. */
static void twl4030_voice_enable(struct snd_soc_codec *codec, int direction,
@@ -2023,6 +2036,19 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
return 0;
}
+static int twl4030_voice_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_VOICE_IF);
+
+ if (tristate)
+ reg |= TWL4030_VIF_TRI_EN;
+ else
+ reg &= ~TWL4030_VIF_TRI_EN;
+
+ return twl4030_write(codec, TWL4030_REG_VOICE_IF, reg);
+}
+
#define TWL4030_RATES (SNDRV_PCM_RATE_8000_48000)
#define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE)
@@ -2032,6 +2058,7 @@ static struct snd_soc_dai_ops twl4030_dai_ops = {
.hw_params = twl4030_hw_params,
.set_sysclk = twl4030_set_dai_sysclk,
.set_fmt = twl4030_set_dai_fmt,
+ .set_tristate = twl4030_set_tristate,
};
static struct snd_soc_dai_ops twl4030_dai_voice_ops = {
@@ -2040,6 +2067,7 @@ static struct snd_soc_dai_ops twl4030_dai_voice_ops = {
.hw_params = twl4030_voice_hw_params,
.set_sysclk = twl4030_voice_set_dai_sysclk,
.set_fmt = twl4030_voice_set_dai_fmt,
+ .set_tristate = twl4030_voice_set_tristate,
};
struct snd_soc_dai twl4030_dai[] = {
--
1.5.4.3
2
2
This adds the stream module which contains the function for
stream operations & control. For a stream the control
and data are two major parts. This module implements the
control (play/pause/resume/stop/free/alloc) for a stream.
It also implements data play/capture frames where buffers
are sent/received to Firmware.
The objective of SST driver is to achieve Low power
playback by utilizing DSP as much as possible. So SST gets
large music buffers from player/middleware and sends
them to firmware in a scatter gather list.
The firmware decodes and renders them, while IA can goto
low power states
Signed-off-by: Vinod Koul <vinod.koul(a)intel.com>
Signed-off-by: Harsha Priya <priya.harsha(a)intel.com>
Signed-off-by: R Dharageswari <dharageswari.r(a)intel.com>
new file: sound/pci/sst/intel_sst_stream.c
---
sound/pci/sst/intel_sst_stream.c | 711 ++++++++++++++++++++++++++++++++++++++
1 files changed, 711 insertions(+), 0 deletions(-)
create mode 100644 sound/pci/sst/intel_sst_stream.c
diff --git a/sound/pci/sst/intel_sst_stream.c b/sound/pci/sst/intel_sst_stream.c
new file mode 100644
index 0000000..aabf057
--- /dev/null
+++ b/sound/pci/sst/intel_sst_stream.c
@@ -0,0 +1,711 @@
+/*
+ * intel_sst_stream.c - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-09 Intel Corp
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ * Harsha Priya <priya.harsha(a)intel.com>
+ * R Dharageswari <dharageswari.r(a)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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This file contains the stream operations of SST driver
+ */
+
+#include <linux/cdev.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/syscalls.h>
+#include <linux/file.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+#include <linux/firmware.h>
+#include <sound/intel_sst_ioctl.h>
+#include "intel_sst_fw_ipc.h"
+#include <sound/intel_sst.h>
+#include "intel_sst_common.h"
+#include "intel_sst_pvt.h"
+#ifdef CONFIG_SST_OSPM_SUPPORT
+#include <linux/intel_mid.h>
+#endif
+
+/**
+* sst_alloc_stream - Send msg for a new stream ID
+* @params: stream params
+* @stream_ops: operation of stream PB/capture
+* @codec: codec for stream
+* @session_id: pvt_id passed by MMF to distinguish stream
+*
+* This function is called by any function which wants to start
+* a new stream. This also check if a stream exists which is idle
+* it initializes idle stream id to this request
+*/
+int sst_alloc_stream(char *params, int stream_ops, int codec, int session_id)
+{
+ struct ipc_post *msg = NULL;
+ struct snd_sst_alloc_params alloc_param = {{0,},};
+
+ sst_dbg("entering sst_alloc_stream \n");
+ sst_dbg("%d %d %d\n", stream_ops, codec, session_id);
+
+ BUG_ON(!params);
+
+ /*send msg to FW to allocate a stream*/
+ if (sst_create_large_msg(&msg) != 0)
+ return -ENOMEM;
+
+ sst_fill_header(&msg->header, IPC_IA_ALLOC_STREAM, 1, 0);
+ msg->header.part.data = sizeof(alloc_param) + sizeof(u32);
+ alloc_param.str_type.codec_type = codec;
+ alloc_param.str_type.str_type = 2; /*music*/
+ alloc_param.str_type.operation = stream_ops;
+ alloc_param.str_type.protected_str = 0; /*non drm*/
+ alloc_param.str_type.pvt_id = session_id;
+ memcpy(&alloc_param.stream_params, params,
+ sizeof(struct snd_sst_stream_params));
+
+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
+ memcpy(msg->mailbox_data + sizeof(u32), &alloc_param,
+ sizeof(alloc_param));
+
+ list_add_tail(&msg->node, &sst_ops->ipc_dispatch_list);
+ sst_post_message(&sst_ops->ipc_post_msg_wq);
+ sst_dbg("alloc stream done\n");
+ return 0;
+}
+
+/**
+* sst_alloc_stream_response - process alloc reply
+* @alloc_header: respose header
+*
+* This function is called by process_reply when reply from FW comes
+* based on response has to process further
+*/
+int sst_alloc_stream_response(unsigned int str_id,
+ struct snd_sst_str_type *type)
+{
+ int retval = 0, i, valid_str = 0;
+ struct ipc_post *msg = NULL;
+
+ /*allocation succesfull*/
+ sst_dbg("stream number given = %d \n", str_id);
+
+ for (i = 0; i < MAX_STREAM_FIELD; i++) {
+ if (type->pvt_id == sst_ops->alloc_block[i].sst_id) {
+ valid_str = 1;
+ break;
+ }
+ }
+ if (valid_str == 0) {
+ /*this is not valid stream*/
+ sst_err("Invalid stream allocation detetcted... freeing\n");
+ if (sst_create_short_msg(&msg) != 0)
+ return -ENOMEM;
+ sst_fill_header(&msg->header, IPC_IA_FREE_STREAM, 0, str_id);
+ list_add_tail(&msg->node, &sst_ops->ipc_dispatch_list);
+ sst_post_message(&sst_ops->ipc_post_msg_wq);
+ return 0;
+ }
+
+ sst_init_stream(&sst_ops->streams[str_id], type->codec_type,
+ type->pvt_id, type->operation);
+
+ sst_dbg("stream pvt id = %d \n", type->pvt_id);
+
+ /*Unblock with retval code*/
+ sst_wake_up_alloc_block(sst_ops, type->pvt_id, str_id, NULL);
+ return retval;
+}
+
+/**
+* sst_pause_stream - Send msg for a pausing stream
+* @id: stream ID
+*
+* This function is called by any function which wants to pause
+* an already running stream.
+*/
+int sst_pause_stream(int str_id)
+{
+ int retval = 0;
+ struct ipc_post *msg = NULL;
+ struct stream_info *str_info = NULL;
+
+ sst_dbg("sst_pause_stream for %d\n", str_id);
+ retval = sst_validate_strid(str_id);
+ if (retval != 0)
+ return retval;
+ str_info = &sst_ops->streams[str_id];
+ if (STREAM_PAUSED == str_info->status)
+ return 0;
+
+ if (STREAM_RUNNING == str_info->status ||
+ STREAM_INIT == str_info->status) {
+
+ if (str_info->prev == STREAM_UN_INIT)
+ return -EBADRQC;
+
+ mutex_lock(&str_info->lock);
+ if (sst_create_short_msg(&msg) != 0) {
+ mutex_unlock(&str_info->lock);
+ return -ENOMEM;
+ }
+ sst_fill_header(&msg->header, IPC_IA_PAUSE_STREAM, 0, str_id);
+ list_add_tail(&msg->node, &sst_ops->ipc_dispatch_list);
+ mutex_unlock(&str_info->lock);
+ sst_post_message(&sst_ops->ipc_post_msg_wq);
+ str_info->ctrl_blk.condition = false;
+ str_info->ctrl_blk.ret_code = 0;
+ str_info->ctrl_blk.on = true;
+ retval = sst_wait_interruptible_timeout(sst_ops,
+ &str_info->ctrl_blk, SST_BLOCK_TIMEOUT);
+ if (retval == 0) {
+ str_info->prev = str_info->status;
+ str_info->status = STREAM_PAUSED;
+#ifdef CONFIG_SST_OSPM_SUPPORT
+ sst_ospm_send_event(OSPM_EVENT_SUBSYS_STOP_PLAY);
+#endif
+ } else if (retval == SST_ERR_INVALID_STREAM_ID) {
+ retval = EINVAL;
+ sst_clean_stream(str_info);
+ }
+ } else {
+ retval = -EBADRQC;
+ sst_err("BADQRC for stream\n");
+ }
+
+ return retval;
+}
+
+/**
+* sst_resume_stream - Send msg for resuming stream
+* @id: stream ID
+*
+* This function is called by any function which wants to resume
+* an already paused stream.
+*/
+int sst_resume_stream(int str_id)
+{
+ int retval = 0;
+ struct ipc_post *msg = NULL;
+ struct stream_info *str_info = NULL;
+
+ sst_dbg("sst_resume_stream for %d\n", str_id);
+ retval = sst_validate_strid(str_id);
+ if (retval != 0)
+ return retval;
+ str_info = &sst_ops->streams[str_id];
+ if (STREAM_RUNNING == str_info->status)
+ return 0;
+ if (STREAM_PAUSED == str_info->status) {
+ mutex_lock(&str_info->lock);
+ if (sst_create_short_msg(&msg) != 0) {
+ mutex_unlock(&str_info->lock);
+ return -ENOMEM;
+ }
+ sst_fill_header(&msg->header, IPC_IA_RESUME_STREAM, 0, str_id);
+ list_add_tail(&msg->node, &sst_ops->ipc_dispatch_list);
+ mutex_unlock(&str_info->lock);
+ sst_post_message(&sst_ops->ipc_post_msg_wq);
+ str_info->ctrl_blk.condition = false;
+ str_info->ctrl_blk.ret_code = 0;
+ str_info->ctrl_blk.on = true;
+ retval = sst_wait_interruptible_timeout(sst_ops,
+ &str_info->ctrl_blk, SST_BLOCK_TIMEOUT);
+ if (retval == 0) {
+ if (STREAM_RUNNING == str_info->prev)
+ str_info->status = STREAM_RUNNING;
+ else
+ str_info->status = STREAM_INIT;
+ str_info->prev = STREAM_PAUSED;
+#ifdef CONFIG_SST_OSPM_SUPPORT
+ sst_ospm_send_event(OSPM_EVENT_SUBSYS_START_PLAY);
+#endif
+ } else if (retval == SST_ERR_INVALID_STREAM_ID) {
+ retval = EINVAL;
+ sst_clean_stream(str_info);
+ }
+ } else {
+ retval = -EBADRQC;
+ sst_err("BADQRC for stream\n");
+ }
+
+ return retval;
+}
+
+
+/**
+* sst_drop_stream - Send msg for stopping stream
+* @id: stream ID
+*
+* This function is called by any function which wants to stop
+* a stream.
+*/
+int sst_drop_stream(int str_id)
+{
+ int retval = 0;
+ struct ipc_post *msg = NULL;
+ struct sst_stream_bufs *bufs = NULL, *_bufs = NULL;
+ struct stream_info *str_info = NULL;
+
+ sst_dbg("sst_drop_stream for %d\n", str_id);
+ retval = sst_validate_strid(str_id);
+ if (retval != 0)
+ return retval;
+ str_info = &sst_ops->streams[str_id];
+ if (STREAM_UN_INIT != str_info->status) {
+
+ mutex_lock(&str_info->lock);
+
+ if (sst_create_short_msg(&msg) != 0) {
+ mutex_unlock(&str_info->lock);
+ return -ENOMEM;
+ }
+ sst_fill_header(&msg->header, IPC_IA_DROP_STREAM, 0, str_id);
+ list_add_tail(&msg->node, &sst_ops->ipc_dispatch_list);
+ mutex_unlock(&sst_ops->streams[str_id].lock);
+ sst_post_message(&sst_ops->ipc_post_msg_wq);
+ str_info->ctrl_blk.condition = false;
+ str_info->ctrl_blk.ret_code = 0;
+ str_info->ctrl_blk.on = true;
+ retval = sst_wait_interruptible_timeout(sst_ops,
+ &str_info->ctrl_blk, SST_BLOCK_TIMEOUT);
+ if (retval == 0) {
+ str_info->prev = str_info->status;
+ str_info->status = STREAM_INIT;
+ if (str_info->data_blk.on == true) {
+ /*moved codec specfic check to generic check*/
+ str_info->data_blk.condition = true;
+ str_info->data_blk.ret_code = 0;
+ wake_up(&sst_ops->wait_queue);
+ }
+ list_for_each_entry_safe(bufs, _bufs,
+ &str_info->bufs, node) {
+ list_del(&bufs->node);
+ kfree(bufs);
+ }
+#ifdef CONFIG_SST_OSPM_SUPPORT
+ sst_ospm_send_event(OSPM_EVENT_SUBSYS_STOP_PLAY);
+#endif
+ } else if (retval == SST_ERR_INVALID_STREAM_ID) {
+ retval = EINVAL;
+ sst_clean_stream(str_info);
+ }
+ } else {
+ retval = -EBADRQC;
+ sst_err("BADQRC for stream\n");
+ }
+
+ return retval;
+}
+
+/**
+* sst_free_stream - Frees a stream
+* @id: stream ID
+*
+* This function is called by any function which wants to free
+* a stream.
+*/
+int sst_free_stream(int str_id)
+{
+ int retval = 0;
+ struct ipc_post *msg = NULL;
+ struct stream_info *str_info = NULL;
+
+ sst_dbg("sst_free_stream for %d\n", str_id);
+
+ retval = sst_validate_strid(str_id);
+ if (0 != retval)
+ return retval;
+ str_info = &sst_ops->streams[str_id];
+
+ if (STREAM_UN_INIT != str_info->status) {
+ mutex_lock(&str_info->lock);
+ if (sst_create_short_msg(&msg) != 0) {
+ mutex_unlock(&str_info->lock);
+ return -ENOMEM;
+ }
+ sst_fill_header(&msg->header, IPC_IA_FREE_STREAM, 0, str_id);
+ list_add_tail(&msg->node, &sst_ops->ipc_dispatch_list);
+ mutex_unlock(&str_info->lock);
+ sst_post_message(&sst_ops->ipc_post_msg_wq);
+ str_info->prev = str_info->status;
+ str_info->status = STREAM_UN_INIT;
+ if (str_info->data_blk.on == true) {
+ str_info->data_blk.condition = true;
+ str_info->data_blk.ret_code = 0;
+ wake_up(&sst_ops->wait_queue);
+ }
+ sst_clean_stream(str_info);
+ sst_dbg("Stream freed\n");
+
+#ifdef CONFIG_SST_OSPM_SUPPORT
+ sst_ospm_send_event(OSPM_EVENT_SUBSYS_STOP_PLAY);
+#endif
+ } else {
+ retval = -EBADRQC;
+ sst_dbg("BADQRC for stream\n");
+ }
+
+ return retval;
+}
+
+
+/**
+* sst_set_stream_param - Send msg for setting stream
+* @id: stream id
+* @params: stream params
+*
+* This function sets stream params during runtime
+*/
+int sst_set_stream_param(int str_id, struct snd_sst_params *str_param)
+{
+ int retval = 0;
+ struct ipc_post *msg = NULL;
+ struct stream_info *str_info = NULL;
+
+ BUG_ON(!str_param);
+ retval = sst_validate_strid(str_id);
+ if (retval != 0)
+ return retval;
+ sst_dbg("set_stream for %d\n", str_id);
+ if (STREAM_INIT == sst_ops->streams[str_id].status) {
+ mutex_lock(&sst_ops->streams[str_id].lock);
+
+ if (sst_create_large_msg(&msg) != 0) {
+ mutex_unlock(&sst_ops->streams[str_id].lock);
+ return -ENOMEM;
+ }
+
+ sst_fill_header(&msg->header,
+ IPC_IA_SET_STREAM_PARAMS, 1, str_id);
+ msg->header.part.data = sizeof(u32) +
+ sizeof(str_param->sparams);
+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
+ memcpy(msg->mailbox_data + sizeof(u32), &str_param->sparams,
+ sizeof(str_param->sparams));
+ list_add_tail(&msg->node, &sst_ops->ipc_dispatch_list);
+ sst_post_message(&sst_ops->ipc_post_msg_wq);
+ mutex_unlock(&sst_ops->streams[str_id].lock);
+ str_info->ctrl_blk.condition = false;
+ str_info->ctrl_blk.ret_code = 0;
+ str_info->ctrl_blk.on = true;
+ retval = sst_wait_interruptible_timeout(sst_ops,
+ &str_info->ctrl_blk, SST_BLOCK_TIMEOUT);
+ if (retval != 0) {
+ retval = EINVAL;
+ sst_free_stream(str_id);
+ } else if (retval == SST_ERR_INVALID_STREAM_ID) {
+ retval = EINVAL;
+ sst_clean_stream(str_info);
+ }
+ } else {
+ retval = -EBADRQC;
+ sst_err("BADQRC for stream\n");
+ }
+ return retval;
+}
+
+/**
+* sst_route_control - To start or drop the routing from once device to another.
+* @id: stream id
+*
+* This function gets stream params during runtime
+*/
+/*
+int sst_route_control(int str_id)
+{
+ int retval = 0;
+ struct ipc_post *msg = NULL;
+ struct snd_sst_control_routing *route = {0,};
+ struct stream_info *str_info = NULL;
+ sst_dbg("sst_route_control for %d\n", str_id);
+ retval = sst_validate_strid(str_id);
+ route->control = 0;
+ if (0 != retval)
+ return retval;
+ str_info = &sst_ops->streams[str_id];
+ mutex_lock(&str_info->lock);
+ if (sst_create_large_msg(&msg) != 0) {
+ mutex_unlock(&str_info->lock);
+ return -ENOMEM;
+ }
+ sst_fill_header(&msg->header, IPC_IA_CONTROL_ROUTING, 1, str_id);
+ msg->header.part.data = sizeof(u32) + sizeof(*route);
+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
+ memcpy(msg->mailbox_data + sizeof(u32), route,
+ sizeof(*route));
+
+
+ list_add_tail(&msg->node, &sst_ops->ipc_dispatch_list);
+ mutex_unlock(&str_info->lock);
+ sst_post_message(&sst_ops->ipc_post_msg_wq);
+
+ str_info->ctrl_blk.condition = false;
+ str_info->ctrl_blk.ret_code = 0;
+ str_info->ctrl_blk.on = true;
+ retval = sst_wait_interruptible_timeout(sst_ops,
+ &str_info->ctrl_blk, SST_BLOCK_TIMEOUT);
+ if (retval == 0)
+ return retval;
+ else if (retval == SST_ERR_INVALID_STREAM_ID) {
+ retval = EINVAL;
+ sst_clean_stream(str_info);
+ }
+ return retval;
+
+}*/
+
+/**
+* sst_target_device_select - This fuction allows to select the target device
+* for the playback or capture
+* @id: stream id
+*
+* This function gets stream params and the target device during runtime
+*/
+
+int sst_target_device_select(struct snd_sst_target_device *target_device)
+{
+/* int retval = 0;
+ struct ipc_post *msg = NULL;
+ struct snd_sst_slot_info *slot_info = NULL;
+ struct stream_info *str_info = NULL;
+*/ sst_dbg("stream_control ");
+ return 0;
+#if 0
+ if (sst_create_large_msg(&msg) != 0) {
+ mutex_unlock(&str_info->lock);
+ return -ENOMEM;
+ }
+ sst_fill_header(&msg->header, IPC_IA_TARGET_DEV_SELECT,
+ 1, str_id);
+ msg->header.part.data = sizeof(u32) + sizeof(*target_device);
+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
+ memcpy(msg->mailbox_data + sizeof(u32), target_device,
+ sizeof(*target_device));
+ list_add_tail(&msg->node, &sst_ops->ipc_dispatch_list);
+ mutex_unlock(&str_info->lock);
+ sst_post_message(&sst_ops->ipc_post_msg_wq);
+
+ str_info->ctrl_blk.condition = false;
+ str_info->ctrl_blk.ret_code = 0;
+ str_info->ctrl_blk.on = true;
+ retval = sst_wait_interruptible_timeout(sst_ops,
+ &str_info->ctrl_blk, SST_BLOCK_TIMEOUT);
+ if (retval == SST_ERR_INVALID_STREAM_ID) {
+ retval = -EINVAL;
+ sst_clean_stream(str_info);
+ }
+ if (target_device->device_route < 0 ||
+ target_device->device_route > 2)
+ return -EINVAL;
+ slot_info = &target_device->devices[0];
+
+ if (slot_info->type == SND_SST_TARGET_PMIC)
+ retval = sst_set_pmic_config(str_id, &slot_info->pcm_params);
+ if (target_device->device_route == 2) {
+ slot_info = &target_device->devices[1];
+ if (target_device->devices[1].type == SND_SST_TARGET_PMIC)
+ retval = sst_set_pmic_config(str_id,
+ &slot_info->pcm_params);
+ }
+ if (retval >= 0)
+ retval = sst_route_control(str_id);
+ return retval;
+#endif
+}
+
+
+int sst_set_pmic_config(int str_id, struct snd_sst_pmic_config *pc)
+{
+ int retval = 0;
+ sst_dbg("stream_control for %d\n", str_id);
+ retval = sst_validate_strid(str_id);
+ if (0 != retval)
+ return retval;
+ sst_ops->scard_ops.set_pcm_params(pc->sfreq, pc->pcm_wd_sz);
+ return retval;
+}
+
+
+int sst_create_sg_list(struct stream_info *stream,
+ struct sst_frame_info *sg_list)
+{
+ struct sst_stream_bufs *kbufs = NULL;
+ int i = 0;
+
+ list_for_each_entry(kbufs, &stream->bufs, node) {
+ if (kbufs->in_use == false) {
+ sg_list->addr[i].addr =
+ virt_to_phys((void *)
+ kbufs->addr + kbufs->offset);
+ sst_dbg("phy addr[%d] 0x%x Size 0x%x\n", i,
+ sg_list->addr[i].addr, kbufs->size);
+ sg_list->addr[i].size = kbufs->size;
+ kbufs->in_use = true;
+ i++;
+ }
+ if (i >= MAX_NUM_SCATTER_BUFFERS)
+ break;
+ }
+
+ sg_list->num_entries = i;
+ sst_dbg("sg list entries = %d \n", sg_list->num_entries);
+ return i;
+}
+
+/**
+* sst_play_frame - Send msg for sending stream frames
+* @streamID: ID of stream
+*
+* This function is called when codec set is sucessfull
+* it send the initial frames to SST
+*/
+int sst_play_frame(int str_id)
+{
+ int i = 0, retval = 0;
+ struct ipc_post *msg = NULL;
+ struct sst_frame_info sg_list = {0};
+ struct sst_stream_bufs *kbufs = NULL, *_kbufs;
+ struct stream_info *stream = NULL;
+
+ sst_dbg("play frame for %d\n", str_id);
+ retval = sst_validate_strid(str_id);
+ if (retval != 0)
+ return retval;
+
+ stream = &sst_ops->streams[str_id];
+ if (stream->status == STREAM_UN_INIT ||
+ stream->status == STREAM_PAUSED) {
+ sst_err("stream in UNIT state\n");
+ return -EINVAL;
+ }
+ /*clear prev sent buffers*/
+ list_for_each_entry_safe(kbufs, _kbufs, &stream->bufs, node) {
+ if (kbufs->in_use == true) {
+ list_del(&kbufs->node);
+ kfree(kbufs);
+ sst_dbg("del node \n");
+ }
+ }
+ if (list_empty(&stream->bufs)) {
+ /*no user buffer available*/
+ sst_dbg("Null buffer!!!!stream status = %d \n", stream->status);
+ stream->prev = stream->status;
+ stream->status = STREAM_INIT;
+ sst_dbg("new stream status = %d \n", stream->status);
+ if (stream->data_blk.on == true) {
+ sst_dbg("user list is empty.. wake \n");
+ /*unblock*/
+ stream->data_blk.ret_code = 0;
+ stream->data_blk.condition = true;
+ stream->data_blk.on = false;
+ wake_up(&sst_ops->wait_queue);
+ }
+#ifdef CONFIG_SST_OSPM_SUPPORT
+ sst_ospm_send_event(OSPM_EVENT_AUDIO_BUF_EMPTY);
+#endif
+ return -EINVAL;
+ }
+
+ /*create list*/
+ i = sst_create_sg_list(stream, &sg_list);
+
+ /*post msg*/
+ if (0 != sst_create_large_msg(&msg))
+ return -ENOMEM;
+
+ sst_fill_header(&msg->header, IPC_IA_PLAY_FRAMES, 1, str_id);
+ msg->header.part.data = sizeof(u32) + sizeof(sg_list);
+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
+ memcpy(msg->mailbox_data + sizeof(u32), &sg_list, sizeof(sg_list));
+ list_add_tail(&msg->node, &sst_ops->ipc_dispatch_list);
+ sst_post_message(&sst_ops->ipc_post_msg_wq);
+ return 0;
+
+}
+
+/**
+* sst_capture_frame - switches based on ecoded/pcm capture for sending stream frames
+* @streamID: ID of stream
+*
+* This function is called when frames to SST are sent for capture
+*/
+int sst_capture_frame(int str_id)
+{
+ int i = 0, retval = 0;
+ struct ipc_post *msg = NULL;
+ struct sst_frame_info sg_list = {0};
+ struct sst_stream_bufs *kbufs = NULL, *_kbufs;
+ struct stream_info *stream = NULL;
+
+
+ sst_dbg("capture frame for %d\n", str_id);
+ retval = sst_validate_strid(str_id);
+ if (retval != 0)
+ return retval;
+
+ stream = &sst_ops->streams[str_id];
+ if (stream->status == STREAM_UN_INIT ||
+ stream->status == STREAM_PAUSED) {
+ sst_err("stream in UNIT state\n");
+ return -EINVAL;
+ }
+
+ /*clear prev sent buffers*/
+ list_for_each_entry_safe(kbufs, _kbufs, &stream->bufs, node) {
+ if (kbufs->in_use == true) {
+ list_del(&kbufs->node);
+ kfree(kbufs);
+ sst_dbg("del node \n");
+ }
+ }
+
+ if (list_empty(&stream->bufs)) {
+ /*no user buffer available*/
+ sst_dbg("Null buffer!!!!stream status = %d \n", stream->status);
+ stream->prev = stream->status;
+ stream->status = STREAM_INIT;
+ sst_dbg("new stream status = %d \n", stream->status);
+ if (stream->data_blk.on == true) {
+ sst_dbg("user list is empty.. wake \n");
+ /*unblock*/
+ stream->data_blk.ret_code = 0;
+ stream->data_blk.condition = true;
+ stream->data_blk.on = false;
+ wake_up(&sst_ops->wait_queue);
+ }
+#ifdef CONFIG_SST_OSPM_SUPPORT
+ sst_ospm_send_event(OSPM_EVENT_AUDIO_BUF_FULL);
+#endif
+ return -EINVAL;
+ }
+
+ /*create new sg list*/
+ i = sst_create_sg_list(stream, &sg_list);
+
+ /*post msg*/
+ if (0 != sst_create_large_msg(&msg))
+ return -ENOMEM;
+
+ sst_fill_header(&msg->header, IPC_IA_CAPT_FRAMES, 1, str_id);
+ msg->header.part.data = sizeof(u32) + sizeof(sg_list);
+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
+ memcpy(msg->mailbox_data + sizeof(u32), &sg_list, sizeof(sg_list));
+ list_add_tail(&msg->node, &sst_ops->ipc_dispatch_list);
+ sst_post_message(&sst_ops->ipc_post_msg_wq);
+ return 0;
+}
--
1.5.4.5
1
0
[alsa-devel] [PATCH] [RFC 6/13] Intel SST driver dsp engine interface module
by Vinod Koul 03 Jul '09
by Vinod Koul 03 Jul '09
03 Jul '09
This adds the IPC module which uses Inter process mechanism
to communicate between driver & SST engine (DSP processor).
To communicate between IA processor and DSP, IPC doorbell
registers are used. A write to these registers triggers
an interrupt to other side. The format of messages
and "mailbox" for message payload is defined in intel_lpe_fw_ipc.h
Signed-off-by: Vinod Koul <vinod.koul(a)intel.com>
Signed-off-by: Harsha Priya <priya.harsha(a)intel.com>
new file: sound/pci/sst/intel_sst_fw_ipc.h
new file: sound/pci/sst/intel_sst_ipc.c
---
sound/pci/sst/intel_sst_fw_ipc.h | 368 ++++++++++++++++++++++++++
sound/pci/sst/intel_sst_ipc.c | 536 ++++++++++++++++++++++++++++++++++++++
2 files changed, 904 insertions(+), 0 deletions(-)
create mode 100644 sound/pci/sst/intel_sst_fw_ipc.h
create mode 100644 sound/pci/sst/intel_sst_ipc.c
diff --git a/sound/pci/sst/intel_sst_fw_ipc.h b/sound/pci/sst/intel_sst_fw_ipc.h
new file mode 100644
index 0000000..6520e4e
--- /dev/null
+++ b/sound/pci/sst/intel_sst_fw_ipc.h
@@ -0,0 +1,368 @@
+#ifndef __INTEL_SST_FW_IPC_H__
+#define __INTEL_SST_FW_IPC_H__
+/*
+* intel_sst_fw_ipc.h - Intel SST Driver for audio engine
+*
+* Copyright (C) 2008-09 Intel Corporation
+* Author: Vinod Koul <vinod.koul(a)intel.com>
+* Harsha Priya <priya.harsha(a)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.
+*
+* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+*
+* This driver exposes the audio engine functionalities to the ALSA
+* and middleware.
+* This file has definitions shared between the firmware and driver
+*/
+
+#define MAX_NUM_STREAMS 4
+#define MAX_DBG_RW_BYTES 80
+#define MAX_NUM_SCATTER_BUFFERS 8
+#define MAX_LOOP_BACK_DWORDS 8
+/* IPC base address and mailbox, timestamp offsets */
+#define SST_MAILBOX_SIZE 0x0400
+#define SST_MAILBOX_SEND 0x0000
+#define SST_MAILBOX_RCV 0x0804
+#define SST_TIME_STAMP 0x1800
+#define SST_RESERVED_OFFSET 0x1840
+#define SST_CHEKPOINT_OFFSET 0x1C00
+#define REPLY_MSG 0x80
+
+/* Message ID's for IPC messages */
+/* Bits B7: SST or IA/SC ; B6-B4: Msg Category; B3-B0: Msg Type */
+
+/* I2L Firmware/Codec Download msgs */
+#define IPC_IA_PREP_LIB_DNLD 0x01
+#define IPC_IA_LIB_DNLD_CMPLT 0x02
+
+#define IPC_IA_SET_PMIC_TYPE 0x03
+#define IPC_IA_GET_FW_VERSION 0x04
+#define IPC_IA_GET_FW_BUILD_INF 0x05
+#define IPC_IA_GET_FW_INFO 0x06
+
+/* I2L Codec Config/control msgs */
+#define IPC_IA_SET_CODEC_PARAMS 0x10
+#define IPC_IA_GET_CODEC_PARAMS 0x11
+#define IPC_IA_SET_PPP_PARAMS 0x12
+#define IPC_IA_GET_PPP_PARAMS 0x13
+#define IPC_IA_PLAY_FRAMES 0x14
+#define IPC_IA_CAPT_FRAMES 0x15
+#define IPC_IA_PLAY_VOICE 0x16
+#define IPC_IA_CAPT_VOICE 0x17
+#define IPC_IA_DECODE_FRAMES 0x18
+
+/* I2L Stream config/control msgs */
+#define IPC_IA_ALLOC_STREAM 0x20 /* Allocate a stream ID */
+#define IPC_IA_FREE_STREAM 0x21 /* Free the stream ID */
+#define IPC_IA_SET_STREAM_PARAMS 0x22
+#define IPC_IA_GET_STREAM_PARAMS 0x23
+#define IPC_IA_PAUSE_STREAM 0x24
+#define IPC_IA_RESUME_STREAM 0x25
+#define IPC_IA_DROP_STREAM 0x26
+#define IPC_IA_DRAIN_STREAM 0x27 /* Short msg with str_id */
+#define IPC_IA_TARGET_DEV_SELECT 0x28
+#define IPC_IA_CONTROL_ROUTING 0x29
+
+/* Debug msgs */
+#define IPC_IA_DBG_MEM_READ 0x40
+#define IPC_IA_DBG_MEM_WRITE 0x41
+#define IPC_IA_DBG_LOOP_BACK 0x42
+
+/* L2I Firmware/Codec Download msgs */
+#define IPC_IA_FW_INIT_CMPLT 0x81
+
+/* L2I Codec Config/control msgs */
+#define IPC_SST_GET_PLAY_FRAMES 0x90 /* Request IA more data */
+#define IPC_SST_GET_CAPT_FRAMES 0x91 /* Request IA more data */
+#define IPC_SST_BUF_UNDER_RUN 0x92 /* PB Under run and stopped */
+#define IPC_SST_BUF_OVER_RUN 0x93 /* CAP Under run and stopped */
+#define IPC_SST_DRAIN_END 0x94 /* PB Drain complete and stopped */
+#define IPC_SST_CHNGE_SSP_PARAMS 0x95 /* PB SSP parameters changed */
+#define IPC_SST_STREAM_PROCESS_FATAL_ERR 0x96/*error in processing a stream*/
+#define IPC_SST_PERIOD_ELAPSED 0x97 /*period elapsed*/
+#define IPC_IA_TARGET_DEV_CHNGD 0x98 /* error in processing a stream */
+
+/* L2S messages */
+#define IPC_SC_DDR_LINK_UP 0xC0
+#define IPC_SC_DDR_LINK_DOWN 0xC1
+
+/* L2I Error reporting msgs */
+#define IPC_IA_MEM_ALLOC_FAIL 0xE0
+#define IPC_IA_PROC_ERR 0xE1 /* error in processing a
+ stream can be used by playback and
+ capture modules */
+
+/* L2I Debug msgs*/
+#define IPC_IA_PRINT_STRING 0xF0
+
+/* Command Response or Acknowledge message to any IPC message will have
+ * same message ID and stream ID information which is sent.
+ * There is no specific Ack message ID. The data field is used as response
+ * meaning.
+ */
+enum ackData {
+ IPC_ACK_SUCCESS = 0,
+ IPC_ACK_FAILURE
+};
+
+
+enum sst_error_codes {
+ /* Error code,response to msgId: Description */
+ /* Common error codes */
+ SST_SUCCESS = 0, /*Success*/
+ SST_ERR_INVALID_STREAM_ID, /*Invalid stream ID */
+ SST_ERR_INVALID_MSG_ID, /*Invalid message ID */
+ SST_ERR_INVALID_STREAM_OP, /*Invalid stream operation request */
+ SST_ERR_INVALID_PARAMS, /*Invalid params */
+ SST_ERR_INVALID_CODEC, /*Invalid codec type */
+ SST_ERR_INVALID_MEDIA_TYPE, /*Invalid media type */
+ SST_ERR_STREAM_ERR, /*ANY: Stream control or config or
+ processing error */
+
+ /* IPC specific error codes */
+ SST_IPC_ERR_CALL_BACK_NOT_REGD, /*Call back for msg not regd*/
+ SST_IPC_ERR_STREAM_NOT_ALLOCATED, /*Stream is not allocated */
+ SST_IPC_ERR_STREAM_ALLOC_FAILED, /*ALLOC:Stream alloc failed*/
+ SST_IPC_ERR_GET_STREAM_FAILED, /*ALLOC:Get stream id failed*/
+ SST_ERR_MOD_NOT_AVAIL, /* SET/GET: Mod(AEC/AGC/ALC) not available */
+ SST_ERR_MOD_DNLD_RQD, /* SET/GET: Mod(AEC/AGC/ALC) download required*/
+ SST_ERR_STREAM_STOPPED, /* ANY: Stream is in stopped state */
+ SST_ERR_STREAM_IN_USE, /* ANY: Stream is already in use */
+
+ /* Capture specific error codes*/
+ SST_CAP_ERR_INCMPLTE_CAPTURE_MSG,/*ANY:Incomplete message */
+ SST_CAP_ERR_CAPTURE_FAIL, /*ANY:Capture op failed */
+ SST_CAP_ERR_GET_DDR_NEW_SGLIST, /*AR: Meena */
+ SST_CAP_ERR_UNDER_RUN, /* lack of input data */
+ SST_CAP_ERR_OVERFLOW, /* lack of output space */
+
+ /* Playback specific error codes*/
+ SST_PB_ERR_INCMPLTE_PLAY_MSG, /* ANY: Incomplete message */
+ SST_PB_ERR_PLAY_FAIL, /* ANY: Playback operation failed */
+ SST_PB_ERR_GET_DDR_NEW_SGLIST, /* AR: Ashok */
+
+ /* Codec manager specific error codes*/
+ SST_LIB_ERR_LIB_DNLD_REQUIRED, /* ALLOC: Codec download required */
+ SST_LIB_ERR_LIB_NOT_SUPPORTED, /* Library is not supported */
+
+ /* Library manager specific error codes*/
+ SST_SCC_ERR_PREP_DNLD_FAILED, /* Failed to prepare for codec download */
+ SST_SCC_ERR_LIB_DNLD_RES_FAILED, /* Lib download resume failed */
+ /* Scheduler specific error codes*/
+ SST_SCH_ERR_FAIL, /* REPORT: */
+
+ /* DMA specific error codes */
+ SST_DMA_ERR_NO_CHNL_AVAILABLE, /* DMA Ch not available*/
+ SST_DMA_ERR_INVALID_INPUT_PARAMS, /* Invalid input params */
+ SST_DMA_ERR_CHNL_ALREADY_SUSPENDED, /* Ch is suspended */
+ SST_DMA_ERR_CHNL_ALREADY_STARTED, /* Ch already started */
+ SST_DMA_ERR_CHNL_NOT_ENABLED, /* Ch not enabled */
+ SST_DMA_ERR_TRANSFER_FAILED, /* Transfer failed */
+ SST_SSP_ERR_ALREADY_ENABLED, /* REPORT: SSP already enabled*/
+ SST_SSP_ERR_ALREADY_DISABLED, /* REPORT: SSP already disabled*/
+ SST_SSP_ERR_NOT_INITIALIZED,
+
+ /* Other error codes */
+ SST_ERR_MOD_INIT_FAIL, /* Firmware Module init failed */
+
+ /* FW init error codes */
+ SST_RDR_ERR_IO_DEV_SEL_NOT_ALLOWED,
+ SST_RDR_ERR_ROUTE_ALREADY_STARTED,
+ SST_RDR_PREP_CODEC_DNLD_FAILED,
+
+ /* Memory debug error codes */
+ SST_ERR_DBG_MEM_READ_FAIL,
+ SST_ERR_DBG_MEM_WRITE_FAIL,
+
+
+};
+
+enum dbg_mem_data_type {
+ /* Data type of debug read/write */
+ DATA_TYPE_U32,
+ DATA_TYPE_U16,
+ DATA_TYPE_U8,
+};
+
+/* CAUTION NOTE: All IPC message body must be multiple of 32 bits.*/
+
+/* IPC Header */
+union ipc_header {
+ struct {
+ u32 msg_id:8; /* Message ID - Max 256 Message Types */
+ u32 str_id:3; /* Undefined for SC communication */
+ u32 large:1; /* Large Message if large = 1 */
+ u32 reserved:4;/* Reserved for future use */
+ u32 data:14; /* Ack/Info for msg, size of msg in Mailbox */
+ u32 done:1; /* bit 30 */
+ u32 busy:1; /* bit 31 */
+ } part;
+ u32 full;
+} __attribute__ ((packed));
+
+struct ipc_header_fw_init {
+ struct snd_sst_fw_version fw_version;/* Firmware version details*/
+ u16 result; /* Fw init result */
+ u8 module_id; /* Module ID in case of error */
+ u8 debug_info; /* Debug info from Module ID in case of fail */
+} __attribute__ ((packed));
+
+/* Firmware build info */
+struct sst_fw_build_info {
+ unsigned char date[16]; /* Firmware build date */
+ unsigned char time[16]; /* Firmware build time */
+} __attribute__ ((packed));
+
+/* Address and size info of a frame buffer in DDR */
+struct sst_address_info {
+ u32 addr; /* Address at IA */
+ u32 size; /* Size of the buffer */
+} __attribute__ ((packed));
+
+/* Time stamp */
+struct snd_sst_tstamp {
+ u64 samples_processed;
+ u64 samples_rendered;
+ u32 sampling_frequency;
+};
+
+/* Frame info to play or capture */
+struct sst_frame_info {
+ u16 num_entries; /* number of entries to follow */
+ u16 rsrvd;
+ struct sst_address_info addr[MAX_NUM_SCATTER_BUFFERS];
+} __attribute__ ((packed));
+
+/* Frames info for decode */
+struct snd_sst_decode_info {
+ struct snd_sst_dbufs frames_in;
+ struct snd_sst_dbufs frames_out;
+} __attribute__ ((packed));
+/* SST to IA print debug message*/
+struct ipc_sst_ia_print_params {
+ u32 string_size; /* Max value is 160 */
+ u8 prt_string[160]; /* Null terminated Char string */
+} __attribute__ ((packed));
+/* Voice data message */
+struct snd_sst_voice_data {
+ u16 num_bytes; /* Number of valid voice data bytes */
+ u8 pcm_wd_size; /* 0=8 bit, 1=16 bit 2=32 bit*/
+ u8 reserved; /* Reserved */
+ u8 voice_data_buf[0]; /* Voice data buffer in bytes, little endian */
+} __attribute__ ((packed));
+
+/* SST to IA memory read debug message */
+struct ipc_sst_ia_dbg_mem_rw {
+ u16 num_bytes; /* Maximum of MAX_DBG_RW_BYTES */
+ u16 data_type; /* enum: dbg_mem_data_type */
+ u32 address; /* Memory address of data memory of data_type */
+ u8 rw_bytes[MAX_DBG_RW_BYTES];/* Maximum of 64 bytes can be RW */
+} __attribute__ ((packed));
+
+struct ipc_sst_ia_dbg_loop_back {
+ u16 num_dwords; /* Maximum of MAX_DBG_RW_BYTES */
+ u16 increment_val;/* Increments dwords by this value, 0- no increment */
+ u32 lpbk_dwords[MAX_LOOP_BACK_DWORDS];/* Maximum of 8 dwords loopback */
+} __attribute__ ((packed));
+
+/* Stream type params struture for Alloc stream */
+struct snd_sst_str_type {
+ u8 codec_type; /* Codec type */
+ u8 str_type; /* 1 = voice 2 = music */
+ u8 operation; /* Playback or Capture */
+ u8 protected_str; /* 0=Non DRM, 1=DRM */
+ u8 pvt_id; /* Driver Private ID */
+ u8 reserved; /* Reserved */
+ u16 result; /* Result used for acknowledgment */
+} __attribute__ ((packed));
+
+/* Library info structure */
+struct module_info {
+ u32 lib_version;
+ u32 lib_type;
+ u32 media_type;
+ u8 lib_name[12];
+ u32 lib_caps;
+ unsigned char b_date[16]; /* Lib build date */
+ unsigned char b_time[16]; /* Lib build time */
+} __attribute__ ((packed));
+
+/* Library slot info */
+struct lib_slot_info {
+ u8 slot_num; /* 1 or 2*/
+ u8 reserved1;
+ u16 reserved2;
+ u32 iram_size; /* slot size in IRAM */
+ u32 dram_size; /* slot size in DRAM */
+ u32 iram_offset; /* starting offset of slot in IRAM */
+ u32 dram_offset; /* starting offset of slot in DRAM */
+} __attribute__ ((packed));
+
+struct snd_sst_lib_download {
+ struct module_info lib_info; /* library info type, capabilities etc*/
+ struct lib_slot_info slot_info; /* slot info to be downloaded */
+ u32 mod_entry_pt;
+};
+
+struct snd_sst_lib_download_info {
+ struct snd_sst_lib_download dload_lib;
+ u16 result; /* Result used for acknowledgment */
+ u8 pvt_id; /*Private ID*/
+ u8 reserved; /*for alignment*/
+};
+
+/* Alloc stream params structure */
+struct snd_sst_alloc_params {
+ struct snd_sst_str_type str_type;
+ struct snd_sst_stream_params stream_params;
+};
+
+struct snd_sst_fw_get_stream_params {
+ struct snd_sst_str_type str_type;
+ struct snd_sst_params codec_params;
+ struct snd_sst_pmic_config pcm_params;
+};
+
+/* Alloc stream response message */
+struct snd_sst_alloc_response {
+ struct snd_sst_str_type str_type; /* Stream type for allocation*/
+ struct snd_sst_lib_download lib_dnld; /*Valid only for codec dnld*/
+};
+
+/*struct ipc_msg_body {
+ union {
+ CODEC_PARAM_STRUCTURES;
+ PPP_PARAM_STRUCTURES;
+ struct snd_sst_alloc_params alloc_params;
+ struct snd_sst_alloc_response alloc_response;
+ struct snd_sst_stream_params stream_params;
+ struct sst_frame_info frames_info;
+ struct ipc_sst_ia_print_params print_params;
+ struct ipc_sst_ia_dbg_mem_rw dbg_mem_rw;
+ struct ipc_sst_ia_dbg_loop_back loop_back;
+ struct pmic_pcm_params ssp_params;
+ } u;
+};*/
+
+
+
+struct ipc_post {
+ struct list_head node;
+ union ipc_header header; /* driver specific */
+ char *mailbox_data;
+};
+
+#endif /*__INTEL_SST_FW_IPC_H__*/
diff --git a/sound/pci/sst/intel_sst_ipc.c b/sound/pci/sst/intel_sst_ipc.c
new file mode 100644
index 0000000..98b4031
--- /dev/null
+++ b/sound/pci/sst/intel_sst_ipc.c
@@ -0,0 +1,536 @@
+/*
+ * intel_sst_ipc.c - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-09 Intel Corporation
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ * Harsha Priya <priya.harsha(a)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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This file defines all ipc functions
+ */
+
+#include <linux/cdev.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+#include <linux/file.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <linux/firmware.h>
+#include <sound/intel_sst.h>
+#include <sound/intel_sst_ioctl.h>
+#include "intel_sst_fw_ipc.h"
+#include "intel_sst_common.h"
+#include "intel_sst_pvt.h"
+
+void sst_send_loop_test(int loop_no)
+{
+ struct ipc_post *msg = NULL;
+ struct ipc_sst_ia_dbg_loop_back loop_msg;
+ static int large_num;
+
+ sst_dbg("Loop testing %d \n", loop_no);
+
+ if (large_num >= 4) {
+ sst_dbg("Loop testing complete.....\n");
+ return;
+ }
+ if (loop_no >= 4) {
+ /*large loop*/
+ large_num++;
+ sst_dbg("Large msg \n");
+ if (0 != sst_create_large_msg(&msg))
+ return;
+
+ loop_msg.increment_val = 1;
+ loop_msg.lpbk_dwords[0] = 0x11111111;
+ loop_msg.lpbk_dwords[1] = 0x22222222;
+ loop_msg.lpbk_dwords[2] = 0x33333333;
+ loop_msg.lpbk_dwords[3] = 0x44444444;
+ loop_msg.num_dwords = 4;
+ sst_fill_header(&msg->header, IPC_IA_DBG_LOOP_BACK, 1, loop_no);
+ msg->header.part.data = sizeof(u32) + sizeof(loop_msg);
+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
+ memcpy(msg->mailbox_data + sizeof(u32),
+ &loop_msg, sizeof(loop_msg));
+ } else {
+ /*short loop*/
+ sst_dbg("Loop Short msg \n");
+ if (0 != sst_create_short_msg(&msg))
+ return;
+ sst_fill_header(&msg->header, IPC_IA_DBG_LOOP_BACK, 0, loop_no);
+ }
+ list_add_tail(&msg->node, &sst_ops->ipc_dispatch_list);
+ sst_post_message(&sst_ops->ipc_post_msg_wq);
+ return;
+}
+
+void sst_send_pmic_type(void)
+{
+ struct ipc_post *msg = NULL;
+
+ sst_dbg("...called\n");
+
+ if (0 != sst_create_short_msg(&msg))
+ return;
+
+ sst_fill_header(&msg->header, IPC_IA_SET_PMIC_TYPE, 0, 0);
+ msg->header.part.data = sst_ops->pmic_vendor;
+ list_add_tail(&msg->node, &sst_ops->ipc_dispatch_list);
+ sst_post_message(&sst_ops->ipc_post_msg_wq);
+ return;
+}
+
+void sst_get_fw_version(void)
+{
+ struct ipc_post *msg = NULL;
+
+ sst_dbg("...called\n");
+
+ if (0 != sst_create_short_msg(&msg))
+ return;
+
+ sst_fill_header(&msg->header, IPC_IA_GET_FW_VERSION, 0, 0);
+ list_add_tail(&msg->node, &sst_ops->ipc_dispatch_list);
+ sst_post_message(&sst_ops->ipc_post_msg_wq);
+ if (0 != sst_create_short_msg(&msg))
+ return;
+
+ sst_fill_header(&msg->header, IPC_IA_GET_FW_BUILD_INF, 0, 0);
+ list_add_tail(&msg->node, &sst_ops->ipc_dispatch_list);
+ sst_post_message(&sst_ops->ipc_post_msg_wq);
+ return;
+}
+
+/**
+* sst_post_message - Posts message to SST
+* @work: Pointer to work structure
+*
+* This function is called by any component in driver which
+* wants to send an IPC message. This will post message only if
+* busy bit is free
+*/
+void sst_post_message(struct work_struct *work)
+{
+ struct ipc_post *msg;
+ union ipc_header header;
+ union interrupt_reg imr;
+ imr.full = 0;
+
+ sst_dbg("..called \n");
+ mutex_lock(&sst_ops->list_lock);
+ /*check list*/
+ if (0 != list_empty(&sst_ops->ipc_dispatch_list)) {
+ /*list is empty, mask imr*/
+ sst_dbg(" Empty msg queue... masking \n");
+ imr.full = readl(sst_ops->shim + SST_IMRX);
+ imr.part.done_interrupt = 1;
+ writel(imr.full, sst_ops->shim + SST_IMRX);
+ mutex_unlock(&sst_ops->list_lock);
+ return;
+ }
+
+ /*check busy bit*/
+ header.full = readl(sst_ops->shim + SST_IPCX);
+ if (1 == header.part.busy) {
+ /*busy, unmask*/
+ sst_dbg("Busy not free... unmasking\n");
+ imr.full = readl(sst_ops->shim + SST_IMRX);
+ imr.part.done_interrupt = 0;
+ writel(imr.full, sst_ops->shim + SST_IMRX);
+ mutex_unlock(&sst_ops->list_lock);
+ return;
+ }
+ /*copy msg from list*/
+ msg = list_entry(sst_ops->ipc_dispatch_list.next,
+ struct ipc_post, node);
+ list_del(&msg->node);
+ sst_dbg("Post message: header = %x\n", msg->header.full);
+ sst_dbg("size: = %x\n", msg->header.part.data);
+ if (1 == msg->header.part.large)
+ memcpy_toio(sst_ops->mailbox + SST_MAILBOX_SEND,
+ msg->mailbox_data, msg->header.part.data);
+ writel(msg->header.full, sst_ops->shim + SST_IPCX);
+ mutex_unlock(&sst_ops->list_lock);
+
+ kfree(msg->mailbox_data);
+ kfree(msg);
+ sst_dbg("...done\n");
+ return;
+}
+
+void sst_clear_interrupt(void)
+{
+ union interrupt_reg isr;
+ union interrupt_reg imr;
+ union ipc_header clear_ipc;
+
+ sst_dbg("sst clearing interrupt \n");
+ imr.full = readl(sst_ops->shim + SST_IMRX);
+ isr.full = readl(sst_ops->shim + SST_ISRX);
+ /* write 1 to clear */;
+ isr.part.busy_interrupt = 1;
+ writel(isr.full, sst_ops->shim + SST_ISRX);
+ /*Set IA done bit*/
+ clear_ipc.full = readl(sst_ops->shim + SST_IPCD);
+ clear_ipc.part.busy = 0;
+ clear_ipc.part.done = 1;
+ clear_ipc.part.data = IPC_ACK_SUCCESS;
+ writel(clear_ipc.full, sst_ops->shim + SST_IPCD);
+ /*un mask busy interrupt*/
+ imr.part.busy_interrupt = 0;
+ writel(imr.full, sst_ops->shim + SST_IMRX);
+}
+
+/**
+* sst_process_message - Processes message from SST
+* @work: Pointer to work structure
+*
+* This function is scheduled by ISR
+* It take a msg from process_queue and does action based on msg
+*/
+void sst_process_message(struct work_struct *work)
+{
+ struct sst_ipc_msg_wq *msg =
+ container_of(work, struct sst_ipc_msg_wq, wq);
+ int str_id = msg->header.part.str_id;
+
+ sst_dbg("called \n");
+
+ /*based on msg in list call respective handler*/
+ switch (msg->header.part.msg_id) {
+ case IPC_SST_BUF_UNDER_RUN:
+ case IPC_SST_BUF_OVER_RUN:
+ if (sst_validate_strid(str_id) != 0) {
+ sst_err("stream id %d invalid\n", str_id);
+ break;
+ }
+ sst_err("Buffer under/overrun for %d\n",
+ msg->header.part.str_id);
+ sst_dbg("Got Underrun & not to send data...ignore\n");
+ break;
+
+ case IPC_SST_GET_PLAY_FRAMES:
+ {
+ struct stream_info *stream ;
+
+ if (sst_validate_strid(str_id) != 0) {
+ sst_err("stream id %d invalid\n", str_id);
+ break;
+ }
+ /*call sst_play_frame*/
+ stream = &sst_ops->streams[str_id];
+ sst_dbg("sst_play_frames for %d\n", msg->header.part.str_id);
+ mutex_lock(&sst_ops->streams[str_id].lock);
+ sst_play_frame(msg->header.part.str_id);
+ mutex_unlock(&sst_ops->streams[str_id].lock);
+ break;
+ }
+
+ case IPC_SST_PERIOD_ELAPSED:
+ {
+ struct snd_sst_tstamp fw_tstamp = {0,};
+ struct stream_info *stream ;
+
+ if (sst_validate_strid(str_id) != 0) {
+ sst_err("stream id %d invalid\n", str_id);
+ break;
+ }
+ stream = &sst_ops->streams[str_id];
+
+ sst_dbg("Period elapsed \n");
+ memcpy_fromio(&fw_tstamp,
+ ((void *)(sst_ops->mailbox + SST_TIME_STAMP) +
+ (str_id * sizeof(fw_tstamp))),
+ sizeof(fw_tstamp));
+ sst_dbg("samples played = %lld\n", fw_tstamp.samples_processed);
+ sst_dbg("diff in mesg = %d\n", msg->header.part.data);
+ sst_clear_interrupt();
+ if (stream->period_elapsed)
+ stream->period_elapsed(stream->pcm_substream);
+ return;
+ }
+
+ case IPC_SST_GET_CAPT_FRAMES:
+ /*call sst_capture_frame*/
+ if (sst_validate_strid(str_id) != 0) {
+ sst_err("stream id %d invalid\n", str_id);
+ break;
+ }
+ sst_dbg("sst_capture_frames for %d\n", msg->header.part.str_id);
+ mutex_lock(&sst_ops->streams[str_id].lock);
+ if (sst_ops->streams[str_id].ops == STREAM_OPS_CAPTURE &&
+ sst_ops->streams[str_id].mmapped == false &&
+ sst_ops->streams[str_id].codec !=
+ SST_CODEC_TYPE_PCM) {
+ sst_dbg("waking up block for copy...\n");
+ sst_ops->streams[str_id].data_blk.ret_code = 0;
+ sst_ops->streams[str_id].data_blk.condition = true;
+ sst_ops->streams[str_id].data_blk.on = false;
+ wake_up(&sst_ops->wait_queue);
+ } else
+ sst_capture_frame(msg->header.part.str_id);
+ mutex_unlock(&sst_ops->streams[str_id].lock);
+ break;
+
+ case IPC_IA_PRINT_STRING:
+ sst_dbg("been asked to print something by fw\n");
+ /*TBD*/
+ break;
+
+ case IPC_IA_FW_INIT_CMPLT: {
+ /*send next data to FW*/
+ struct ipc_header_fw_init *init =
+ (struct ipc_header_fw_init *)msg->mailbox;
+
+ sst_dbg("*** FW Init msg came*** \n");
+ if (0 == init->result) {
+ sst_ops->sst_state = SST_FW_RUNNING;
+ sst_info("FW Version %x.%x \n",
+ init->fw_version.major, init->fw_version.minor);
+ sst_info("Build No %x Type %x \n",
+ init->fw_version.build, init->fw_version.type);
+#ifdef SND_LOOP_TEST
+ sst_send_loop_test(0);
+#endif
+ sst_send_pmic_type();
+ sst_get_fw_version();
+ } else {
+ sst_ops->sst_state = SST_ERROR;
+ sst_dbg("FW Init failed, Error %x\n", init->result);
+ sst_dbg("FW Init failed, Module %x, Debug Info %x \n",
+ init->module_id, init->debug_info);
+ }
+ sst_dbg("Waking up... open\n");
+ sst_wake_up_alloc_block(sst_ops, 0xFF, 0, NULL);
+ break;
+ }
+
+ case IPC_SST_STREAM_PROCESS_FATAL_ERR:
+ if (sst_validate_strid(str_id) != 0) {
+ sst_err("stream id %d invalid\n", str_id);
+ break;
+ }
+ sst_err(" codec fatal error %x for stream %d... \n",
+ msg->header.full, msg->header.part.str_id);
+ sst_err("Dropping the stream \n");
+ sst_drop_stream(msg->header.part.str_id);
+ break;
+
+ default:
+ /*Illegal case*/
+ sst_err("Unhandled case msg_id %x message %x\n",
+ msg->header.part.msg_id, msg->header.full);
+ }
+ sst_clear_interrupt();
+ return;
+}
+
+/**
+* sst_process_reply - Processes reply message from SST
+* @work: Pointer to work structure
+*
+* This function is scheduled by ISR
+* It take a reply msg from response_queue and
+* does action based on msg
+*/
+void sst_process_reply(struct work_struct *work)
+{
+ struct sst_ipc_msg_wq *msg =
+ container_of(work, struct sst_ipc_msg_wq, wq);
+ int str_id = msg->header.part.str_id;
+ struct stream_info *str_info = NULL;
+
+ sst_dbg("called for %x \n", msg->header.full);
+
+ switch (msg->header.part.msg_id) {
+ case IPC_IA_DROP_STREAM:
+ case IPC_IA_PAUSE_STREAM:
+ case IPC_IA_RESUME_STREAM:
+ case IPC_IA_SET_STREAM_PARAMS:
+ if (0 == msg->header.part.data) {
+ sst_dbg("Msg succedded %x \n", msg->header.part.msg_id);
+ } else {
+ sst_err("Msg %x reply error %x \n",
+ msg->header.part.msg_id,
+ msg->header.part.data);
+ }
+ if (sst_validate_strid(str_id) != 0) {
+ sst_err("stream id %d invalid\n", str_id);
+ break;
+ }
+
+ str_info = &sst_ops->streams[str_id];
+ str_info->ctrl_blk.ret_code = msg->header.part.data;
+ if (str_info->ctrl_blk.on == true) {
+ str_info->ctrl_blk.condition = true;
+ wake_up(&sst_ops->wait_queue);
+ }
+ break;
+
+ case IPC_IA_FREE_STREAM:
+ if (0 == msg->header.part.data) {
+ sst_dbg("Stream %d freed\n", str_id);
+ } else {
+ sst_err("Free for %d returned error %x\n",
+ str_id, msg->header.part.data);
+ }
+ break;
+ case IPC_IA_GET_STREAM_PARAMS: {
+ if (sst_validate_strid(str_id) != 0) {
+ sst_err("stream id %d invalid\n", str_id);
+ break;
+ }
+ if (0 == msg->header.part.data) {
+ struct snd_sst_stream_params *params = NULL;
+ params = kzalloc(sizeof(*params), GFP_KERNEL);
+ if (NULL == params) {
+ sst_err("mem allocation failed\n");
+ break;
+ }
+ memcpy(params, &msg->mailbox, sizeof(*params));
+ str_info = &sst_ops->streams[str_id];
+ str_info->get_parameters = params;
+ } else {
+ sst_err("Msg %x reply error %x \n",
+ msg->header.part.msg_id, msg->header.part.data);
+ }
+ break;
+ }
+
+ case IPC_IA_ALLOC_STREAM: {
+ /*map to stream, call play*/
+ struct snd_sst_alloc_response *resp =
+ (struct snd_sst_alloc_response *)msg->mailbox;
+ if (0 != resp->str_type.result) {
+ /*error case*/
+ struct snd_sst_alloc_response *lib = NULL;
+ sst_err("error alloc stream = %x \n",
+ resp->str_type.result);
+ if (resp->str_type.result ==
+ SST_LIB_ERR_LIB_DNLD_REQUIRED) {
+ lib = kzalloc(sizeof(*lib), GFP_ATOMIC);
+ if (NULL == lib) {
+ sst_err("mem allocation failed \n");
+ break;
+ }
+ memcpy(lib, msg->mailbox, sizeof(*lib));
+ /*library needs to be downloaded*/
+ sst_dbg("Codec Download required \n");
+ }
+ sst_wake_up_alloc_block(sst_ops, resp->str_type.pvt_id,
+ (-resp->str_type.result), lib);
+ break;
+ }
+ sst_alloc_stream_response(str_id, &resp->str_type);
+ break;
+ }
+
+ case IPC_IA_DBG_LOOP_BACK:
+ /*Debug loop back msg*/
+ sst_dbg("Loop back came \n");
+ if (0 != msg->header.part.data)
+ sst_dbg("Possible error if not large \n");
+ sst_dbg("Loop ID: %d\n", str_id);
+ if (msg->header.part.large) {
+ struct ipc_sst_ia_dbg_loop_back *loop_msg =
+ (struct ipc_sst_ia_dbg_loop_back *)msg->mailbox;
+ int i;
+ sst_dbg("Got large loop back: Words %d\n",
+ loop_msg->num_dwords);
+ for (i = 0; i < loop_msg->num_dwords; i++) {
+ sst_dbg("Loop Word %d = %d \n", i,
+ loop_msg->lpbk_dwords[i]);
+ }
+ }
+ sst_send_loop_test((str_id + 1));
+ break;
+
+ case IPC_IA_PLAY_FRAMES:
+ case IPC_IA_CAPT_FRAMES:
+ if (sst_validate_strid(str_id) != 0) {
+ sst_err("stream id %d invalid\n", str_id);
+ break;
+ }
+ sst_dbg("Ack for play/capt frames recived \n");
+ break;
+
+ case IPC_IA_PREP_LIB_DNLD: {
+ struct snd_sst_str_type *str_type =
+ (struct snd_sst_str_type *)msg->mailbox;
+ sst_dbg("Prep Lib download %x\n", msg->header.part.msg_id);
+ if (0 != str_type->result)
+ sst_err("Error in prep lib download 0x%x\n",
+ str_type->result);
+ else
+ sst_dbg("Need to download codec now...\n");
+ str_type->result = 0;
+ sst_wake_up_alloc_block(sst_ops, str_type->pvt_id,
+ str_type->result, NULL);
+ break;
+ }
+
+ case IPC_IA_LIB_DNLD_CMPLT: {
+ struct snd_sst_lib_download_info *resp =
+ (struct snd_sst_lib_download_info *)msg->mailbox;
+ int retval = resp->result;
+
+ sst_dbg("Lib download cmplt %x\n", msg->header.part.msg_id);
+ if (0 != retval)
+ sst_err("Error in lib dload %x\n", resp->result);
+ else {
+ sst_dbg("Codec download complete...\n");
+ sst_info("Dloaded codec Type %d Ver %d Built %s: %s\n",
+ resp->dload_lib.lib_info.lib_type,
+ resp->dload_lib.lib_info.lib_version,
+ resp->dload_lib.lib_info.b_date,
+ resp->dload_lib.lib_info.b_time);
+ }
+ sst_wake_up_alloc_block(sst_ops, resp->pvt_id, retval, NULL);
+ break;
+ }
+
+ case IPC_IA_GET_FW_VERSION: {
+ struct snd_sst_fw_version *version =
+ (struct snd_sst_fw_version *)msg->mailbox;
+ sst_info("***LOADED SST FW VERSION*** = %2d.%02d\n",
+ version->major, version->minor);
+ sst_info("Build No %x Type %x \n",
+ version->build, version->type);
+ break;
+ }
+ case IPC_IA_GET_FW_BUILD_INF: {
+ struct sst_fw_build_info *build =
+ (struct sst_fw_build_info *)msg->mailbox;
+ sst_info("Build date %s Time %s\n",
+ build->date, build->time);
+ break;
+ }
+
+ default:
+ /*Illegal case*/
+ sst_err("process reply :default case = %x\n",
+ msg->header.full);
+
+ }
+ sst_clear_interrupt();
+ return;
+}
--
1.5.4.5
1
0
This adds header files of sound card driver, it defines some utility
functions and common declarations for vendor sound cards as well
Signed-off-by: Vinod Koul <vinod.koul(a)intel.com>
Signed-off-by: Harsha Priya <priya.harsha(a)intel.com>
new file: sound/pci/sst/intelmid.h
new file: sound/pci/sst/intelmid_pvt.h
new file: sound/pci/sst/intelmid_snd_control.h
---
sound/pci/sst/intelmid.h | 274 ++++++++++++++++++++++++++++++++++
sound/pci/sst/intelmid_pvt.h | 198 ++++++++++++++++++++++++
sound/pci/sst/intelmid_snd_control.h | 153 +++++++++++++++++++
3 files changed, 625 insertions(+), 0 deletions(-)
create mode 100644 sound/pci/sst/intelmid.h
create mode 100644 sound/pci/sst/intelmid_pvt.h
create mode 100644 sound/pci/sst/intelmid_snd_control.h
diff --git a/sound/pci/sst/intelmid.h b/sound/pci/sst/intelmid.h
new file mode 100644
index 0000000..938ad52
--- /dev/null
+++ b/sound/pci/sst/intelmid.h
@@ -0,0 +1,274 @@
+/*
+ * intelmid.c - Intel Sound card driver for MID
+ *
+ * Copyright (C) 2008-09 Intel Corp
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ * Harsha Priya <priya.harsha(a)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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * ALSA driver header for Intel MAD chipset
+ */
+#ifndef __INTELMID_H
+#define __INTELMID_H
+
+#include <linux/time.h>
+#define DRIVER_NAME "pmic_audio"
+#define PMIC_SOUND_IRQ_TYPE_MASK (1 << 15)
+#define AUDINT_BASE (0xFFFFEFF8 + (6 * sizeof(u8)))
+/*#define FULL_CTRL*/
+/*#define REG_IRQ*/
+/*values #defined */
+/* will differ for different hw - to be taken from config */
+#define MAX_DEVICES 1
+#define MIN_RATE 8000
+#define MAX_RATE 48000
+#define MAX_BUFFER (320*1024)
+#define MIN_BUFFER (320*1024)
+#define MAX_PERIODS (1024*2)
+#define MIN_PERIODS 1
+#define MAX_PERIOD_BYTES MAX_BUFFER
+#define MIN_PERIOD_BYTES 32
+#define MAX_MUTE 1
+#define MIN_MUTE 0
+#define MONO_CNTL 1
+#define STEREO_CNTL 2
+#define MIN_CHANNEL 1
+#define MAX_CHANNEL 2
+#define FIFO_SIZE 0 /*fifo not being used*/
+#define INTEL_MAD "Intel MAD"
+#define MUTE_ALL_DEV 9
+/*TODO +6 db*/
+#define MAX_VOL 64
+/*TODO -57 db*/
+#define MIN_VOL 0
+#define PLAYBACK_COUNT 1
+#define CAPTURE_COUNT 1
+
+struct mad_device {
+ unsigned int mic_plugged:1;
+ unsigned int headphones_plugged:1;
+ unsigned int line_in_plugged:1;
+};
+
+struct mad_wq {
+ struct snd_pcm_substream *substream;
+ struct work_struct wq;
+ struct mutex wq_lock;
+};
+
+struct mad_capture_wq {
+ struct snd_pcm_substream *substream;
+ struct stream_buffer buffer_to_sst;
+ struct work_struct wq;
+};
+struct snd_intelmad {
+ struct snd_card *card; /*ptr to the card details*/
+ int card_index;/* card index */
+ char *card_id; /*card id*/
+ struct mad_device pin_sense; /*current pin sense */
+ struct intel_sst_card_ops *sstdrv_ops;/*ptr to sst driver ops*/
+ struct spi_device *spi;
+ int irq;
+ int pmic_status;
+ void __iomem *int_base;
+};
+
+struct snd_control_val {
+ int mic1_vol_max;
+ int mic1_vol_min;
+ int mic2_vol_max;
+ int mic2_vol_min;
+ int dmic_vol_max;
+ int dmic_vol_min;
+ int linein_vol_max;
+ int linein_vol_min;
+ int hp_vol_max;
+ int hp_vol_min;
+ int speaker_vol_max;
+ int speaker_vol_min;
+ int earpiece_vol_max;
+ int earpiece_vol_min;
+};
+
+struct mad_stream_pvt {
+ int stream_id;
+ int stream_status;
+ int stream_ops;
+ unsigned int stream_type; /*0:Audio 1:Voice Default:Audio*/
+ struct snd_pcm_substream *substream;
+ unsigned int pcm_size;
+ unsigned int pcm_jiffie;
+ unsigned int pcm_buf_pos;
+ struct snd_pcm_indirect pcm_indirect;
+ struct pcm_stream_info buf_ptr;
+ unsigned long period_elapsed_ptr;
+ struct mad_wq mad_msg_wq;
+ struct mad_capture_wq mad_capture_wq;
+};
+
+enum mad_drv_status {
+ INIT = 1,
+ STARTED,
+ RUNNING,
+ PAUSED,
+ DROPPED,
+};
+
+enum mad_pmic_status {
+ PMIC_UNINIT = 1,
+ PMIC_INIT,
+};
+#ifdef FULL_CTRL
+enum _widget_ctrl {
+ LINE_IN_VOL = 1,
+ LINE_IN_MUTE,
+ DMIC_VOL,
+ DMIC_MUTE,
+ MIC1_VOL,
+ MIC1_MUTE,
+ MIC2_VOL,
+ MIC2_MUTE,
+ INPUT_SEL,
+ HEADPHONES_VOL ,
+ HEADPHONES_MUTE,
+ INTERNAL_SPEAKERS_VOL,
+ INTERNAL_SPEAKERS_MUTE,
+ EARPIECE_VOL,
+ EARPIECE_MUTE,
+ OUTPUT_SEL,
+ MASTER_MUTE
+};
+#else
+enum _widget_ctrl {
+ HEADPHONES_VOL = 1 ,
+ HEADPHONES_MUTE,
+};
+#endif
+
+enum {
+ AUDIO_GENL_ATTR_UNSPEC = 0,
+ AUDIO_GENL_ATTR_EVENT, /* Audio event info needed by user space */
+ AUDIO_GENL_ATTR_MAX,
+};
+enum {
+ AUDIO_GENL_CMD_UNSPEC,
+ AUDIO_GENL_CMD_EVENT, /* kernel->user notifications for OSPM events */
+ AUDIO_GENL_CMD_MAX,
+};
+
+enum eaudio_events {
+ AUDIO_EVENT_HP_DETECT,
+ AUDIO_EVENT_HS_DETECT,
+ AUDIO_EVENT_SHORT_PRESS,
+ AUDIO_EVENT_LONG_PRESS,
+ AUDIO_EVENT_COUNT,
+};
+
+struct audio_genl_event {
+ u32 orig;
+ enum eaudio_events event;
+};
+
+struct snd_pmic_ops v[3] = {
+ {
+ .set_input_dev = fs_set_selected_input_dev,
+ .set_output_dev = fs_set_selected_output_dev,
+ .set_mute = fs_set_mute,
+ .get_mute = fs_get_mute,
+ .set_vol = fs_set_vol,
+ .get_vol = fs_get_vol,
+ .init_card = fs_init_card,
+ .set_pcm_params = fs_set_pcm_params,
+ .init_card_capture = fs_init_capture_card,
+ },
+ {
+ .set_input_dev = mx_set_selected_input_dev,
+ .set_output_dev = mx_set_selected_output_dev,
+ .set_mute = mx_set_mute,
+ .get_mute = mx_get_mute,
+ .set_vol = mx_set_vol,
+ .get_vol = mx_get_vol,
+ .init_card = mx_init_card,
+ .set_pcm_params = mx_set_pcm_params,
+ .init_card_capture = mx_init_capture_card,
+ },
+ {
+ .set_input_dev = nc_set_selected_input_dev,
+ .set_output_dev = nc_set_selected_output_dev,
+ .set_mute = nc_set_mute,
+ .get_mute = nc_get_mute,
+ .set_vol = nc_set_vol,
+ .get_vol = nc_get_vol,
+ .init_card = nc_init_card,
+ .set_pcm_params = nc_set_pcm_params,
+ .init_card_capture = nc_init_capture_card,
+ },
+};
+
+struct snd_control_val ctrl_val[3] = {
+ {
+ .mic1_vol_max = MAX_VOL,
+ .mic1_vol_min = MIN_VOL,
+ .mic2_vol_max = MAX_VOL,
+ .mic2_vol_min = MIN_VOL,
+ .dmic_vol_max = MAX_VOL,
+ .dmic_vol_min = MIN_VOL,
+ .linein_vol_max = MAX_VOL,
+ .linein_vol_min = MIN_VOL,
+ .hp_vol_max = MAX_VOL,
+ .hp_vol_min = MIN_VOL,
+ .speaker_vol_max = MAX_VOL,
+ .speaker_vol_min = MIN_VOL,
+ .earpiece_vol_max = MAX_VOL,
+ .earpiece_vol_min = MIN_VOL,
+ },
+ {
+ .mic1_vol_max = MAX_VOL,
+ .mic1_vol_min = MIN_VOL,
+ .mic2_vol_max = MAX_VOL,
+ .mic2_vol_min = MIN_VOL,
+ .dmic_vol_max = MAX_VOL,
+ .dmic_vol_min = MIN_VOL,
+ .linein_vol_max = MAX_VOL,
+ .linein_vol_min = MIN_VOL,
+ .hp_vol_max = MAX_VOL,
+ .hp_vol_min = MIN_VOL,
+ .speaker_vol_max = MAX_VOL,
+ .speaker_vol_min = MIN_VOL,
+ .earpiece_vol_max = MAX_VOL,
+ .earpiece_vol_min = MIN_VOL,
+ },
+ {
+ .mic1_vol_max = 30,
+ .mic1_vol_min = 10,
+ .mic2_vol_max = 30,
+ .mic2_vol_min = 10,
+ .dmic_vol_max = 0,
+ .dmic_vol_min = -63,
+ .linein_vol_max = MAX_VOL,
+ .linein_vol_min = MIN_VOL,
+ .hp_vol_max = 6,
+ .hp_vol_min = -25,
+ .speaker_vol_max = 6,
+ .speaker_vol_min = -25,
+ .earpiece_vol_max = 6,
+ .earpiece_vol_min = -25,
+ },
+};
+
+#endif /*__INTELMID_H*/
diff --git a/sound/pci/sst/intelmid_pvt.h b/sound/pci/sst/intelmid_pvt.h
new file mode 100644
index 0000000..73cb9b5
--- /dev/null
+++ b/sound/pci/sst/intelmid_pvt.h
@@ -0,0 +1,198 @@
+#ifndef __INTEL_MID_PVT_H__
+#define __INTEL_MID_PVT_H__
+/*
+ * intelmid_pvt.h - Intel Sound card driver for MID
+ *
+ * Copyright (C) 2008-09 Intel Corp
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ * Harsha Priya <priya.harsha(a)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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * ALSA driver for Intel MID sound card chipset - holding private functions
+ */
+
+static int snd_intelmad_volume_info(struct snd_ctl_elem_info *uinfo,
+ int control_type, int max, int min)
+{
+ WARN_ON(!uinfo);
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = control_type;
+ uinfo->value.integer.min = min;
+ uinfo->value.integer.max = max;
+ return 0;
+}
+
+#ifdef FULL_CTRL
+/**
+* mute_all - mutes all the DAC and ADC controls
+* @kcontrol: pointer to the control of master mute switch
+* @uval: pointer to the structure where the control's info need
+* to be filled
+* This function is internally called from snd_intelmad_mute_set for master_mute
+*/
+static int mute_all(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uval)
+{
+ int i = 0, value = 0, ret_val = 0;
+ struct snd_intelmad *intelmaddata = NULL;
+ struct snd_pmic_ops *scard_ops = NULL;
+ int cntl_list[MUTE_ALL_DEV] =
+ {PMIC_SND_LEFT_HP_MUTE,
+ PMIC_SND_RIGHT_HP_MUTE,
+ PMIC_SND_RIGHT_SPEAKER_MUTE,
+ PMIC_SND_LEFT_SPEAKER_MUTE,
+ PMIC_SND_MONO_EARPIECE_MUTE,
+ PMIC_SND_INPUT_MUTE_LINE_IN,
+ PMIC_SND_INPUT_MUTE_MIC1,
+ PMIC_SND_INPUT_MUTE_MIC2,
+ PMIC_SND_INPUT_MUTE_DMIC
+ };
+
+ sst_dbg("called\n");
+
+ WARN_ON(!uval);
+ WARN_ON(!kcontrol);
+
+ value = uval->value.integer.value[0];
+ if (value == 0)
+ value = 1;
+ else
+ value = 0;
+
+ intelmaddata = kcontrol->private_data;
+
+ WARN_ON(!intelmaddata->sstdrv_ops);
+
+ if (PMIC_UNINIT == intelmaddata->pmic_status) {
+ ret_val = intelmaddata->sstdrv_ops->scard_ops->init_card();
+ intelmaddata->pmic_status = PMIC_INIT;
+ }
+
+ if (0 != ret_val)
+ return ret_val;
+
+ scard_ops = intelmaddata->sstdrv_ops->scard_ops;
+
+ WARN_ON(!scard_ops);
+ sst_dbg("************uval::%ld\n", uval->value.integer.value[0]);
+ sst_dbg("************value::%d\n", value);
+ for (i = 0; i < MUTE_ALL_DEV; i++) {
+ ret_val = scard_ops->set_mute(cntl_list[i], value);
+ if (0 != ret_val)
+ return ret_val;
+ }
+ kcontrol->private_value = 0;
+ return ret_val;
+}
+#endif
+
+void period_elapsed(void *mad_substream)
+{
+ struct snd_pcm_substream *substream = mad_substream;
+ struct mad_stream_pvt *stream = substream->runtime->private_data;
+
+ sst_dbg("called\n");
+ if (stream->stream_status != RUNNING)
+ return;
+ sst_dbg("calling period elapsed\n");
+ snd_pcm_period_elapsed(substream);
+ return;
+}
+
+
+int snd_intelmad_alloc_stream(struct snd_pcm_substream *substream)
+{
+ struct snd_intelmad *intelmaddata = NULL;
+ struct mad_stream_pvt *stream = substream->runtime->private_data;
+ struct snd_sst_stream_params param = {{{0,},},};
+ struct snd_sst_params str_params = {0};
+ int ret_val = 0, stream_type = 0;
+ unsigned int bits_per_sec = 0;
+
+ intelmaddata = snd_pcm_substream_chip(substream);
+
+ if (SNDRV_PCM_FMTBIT_S8 == substream->runtime->format ||
+ SNDRV_PCM_FMTBIT_U8 == substream->runtime->format)
+ stream->stream_type = STREAM_TYPE_VOICE;
+ else
+ stream->stream_type = STREAM_TYPE_MUSIC;
+
+ stream_type = substream->stream;
+ sst_dbg("stream type = %d \n", stream_type);
+
+ bits_per_sec = (substream->runtime->sample_bits/8)
+ * (substream->runtime->channels)
+ * (substream->runtime->rate);
+ /*set codec params and inform SST driver the same*/
+
+ param.uc.pcm_params.codec = SST_CODEC_TYPE_PCM;
+ param.uc.pcm_params.brate = bits_per_sec;
+ param.uc.pcm_params.num_chan = substream->runtime->channels;
+ param.uc.pcm_params.sfreq = substream->runtime->rate;
+ param.uc.pcm_params.pcm_wd_sz = substream->runtime->sample_bits;
+ param.uc.pcm_params.frame_size = 0;
+ param.uc.pcm_params.samples_per_frame = 250;
+ param.uc.pcm_params.period_count = substream->runtime->period_size;
+ sst_dbg("period_count = %d\n", param.uc.pcm_params.period_count);
+ sst_dbg("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 (SNDRV_PCM_STREAM_PLAYBACK == stream_type)
+ str_params.ops = STREAM_OPS_PLAYBACK;
+ else
+ str_params.ops = STREAM_OPS_CAPTURE;
+ ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_ALLOC,
+ &str_params);
+ sst_dbg("SST_SND_PLAY/CAPTURE ret_val = %x\n",
+ ret_val);
+ if (ret_val < 0)
+ return ret_val;
+
+ stream->stream_id = ret_val;
+ stream->stream_status = INIT;
+ stream->period_elapsed_ptr = 0;
+ stream->buf_ptr.buffer_ptr = 0;
+ sst_dbg("str id : %d\n", stream->stream_id);
+
+ return ret_val;
+}
+
+int snd_intelmad_init_stream(struct snd_pcm_substream *substream)
+{
+ struct mad_stream_pvt *stream = substream->runtime->private_data;
+ struct snd_intelmad *intelmaddata = NULL;
+ int ret_val = 0;
+
+ sst_dbg("setting buffer ptr param\n");
+ intelmaddata = snd_pcm_substream_chip(substream);
+ stream->buf_ptr.str_id = stream->stream_id;
+ stream->buf_ptr.period_elapsed = period_elapsed;
+ stream->buf_ptr.mad_substream = substream;
+ stream->buf_ptr.buffer_ptr = 0;
+ ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_STREAM_INIT,
+ &stream->buf_ptr);
+ if (0 != ret_val)
+ sst_err("error code = %d \n", ret_val);
+ return ret_val;
+
+}
+
+#endif
diff --git a/sound/pci/sst/intelmid_snd_control.h b/sound/pci/sst/intelmid_snd_control.h
new file mode 100644
index 0000000..49fdf9c
--- /dev/null
+++ b/sound/pci/sst/intelmid_snd_control.h
@@ -0,0 +1,153 @@
+#ifndef __INTELMID_SND_CTRL_H__
+#define __INTELMID_SND_CTRL_H__
+/*
+ * intelmid_snd_control.h - Intel Sound card driver for MID
+ *
+ * Copyright (C) 2008-09 Intel Corporation
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ * Harsha Priya <priya.harsha(a)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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This file defines all snd control functions
+ */
+
+/*
+Mask bits
+*/
+#define MASK0 0x01 /*0000 0001*/
+#define MASK1 0x02 /*0000 0010*/
+#define MASK2 0x04 /*0000 0100*/
+#define MASK3 0x08 /*0000 1000*/
+#define MASK4 0x10 /*0001 0000*/
+#define MASK5 0x20 /*0010 0000*/
+#define MASK6 0x40 /*0100 0000*/
+#define MASK7 0x80 /*1000 0000*/
+/*
+value bits
+*/
+#define VALUE0 0x01 /*0000 0001*/
+#define VALUE1 0x02 /*0000 0010*/
+#define VALUE2 0x04 /*0000 0100*/
+#define VALUE3 0x08 /*0000 1000*/
+#define VALUE4 0x10 /*0001 0000*/
+#define VALUE5 0x20 /*0010 0000*/
+#define VALUE6 0x40 /*0100 0000*/
+#define VALUE7 0x80 /*1000 0000*/
+
+#define MUTE 0 /* ALSA Passes 0 for mute */
+#define UNMUTE 1 /* ALSA Passes 1 for unmute */
+
+#define MAX_VOL_PMIC_VENDOR0 6 /* max volume in dB for stereo & voice DAC */
+#define MIN_VOL_PMIC_VENDOR0 (-57) /* min vol in dB for stereo & voice DAC*/
+/* Head phone volume control */
+#define MAX_HP_VOL_PMIC_VENDOR1 6 /* max volume in dB for HP */
+#define MIN_HP_VOL_PMIC_VENDOR1 (-84) /* min volume in dB for HP */
+#define MAX_HP_VOL_INDX_PMIC_VENDOR1 40 /* Number of HP volume control values */
+
+/* Mono Earpiece Volume control */
+#define MAX_EP_VOL_PMIC_VENDOR1 0 /* max volume in dB for EP */
+#define MIN_EP_VOL_PMIC_VENDOR1 (-75) /* min volume in dB for EP */
+#define MAX_EP_VOL_INDX_PMIC_VENDOR1 32 /* Number of EP volume control values */
+
+int nc_set_selected_input_dev(int value);
+int nc_get_selected_input_dev(int *value);
+int nc_set_selected_output_dev(int value);
+int nc_get_selected_output_dev(int *value);
+int nc_set_mute(int dev_id, int value);
+int nc_get_mute(int dev_id, int *value);
+int nc_set_vol(int dev_id, int value);
+int nc_get_vol(int dev_id, int *value);
+int nc_init_card(void);
+void nc_set_pcm_params(int sfreq, int word_size);
+int nc_init_capture_card(void);
+
+int fs_set_selected_input_dev(int value);
+int fs_get_selected_input_dev(int *value);
+int fs_set_selected_output_dev(int value);
+int fs_get_selected_output_dev(int *value);
+int fs_set_mute(int dev_id, int value);
+int fs_get_mute(int dev_id, int *value);
+int fs_set_vol(int dev_id, int value);
+int fs_get_vol(int dev_id, int *value);
+int fs_init_card(void);
+void fs_set_pcm_params(int sfreq, int word_size);
+int fs_init_capture_card(void);
+
+int mx_get_selected_input_dev(int *value);
+int mx_set_selected_input_dev(int value);
+int mx_set_selected_output_dev(int value);
+int mx_get_selected_output_dev(int *value);
+int mx_set_mute(int dev_id, int value);
+int mx_get_mute(int dev_id, int *value);
+int mx_set_vol(int dev_id, int value);
+int mx_get_vol(int dev_id, int *value);
+int mx_init_card(void);
+void mx_set_pcm_params(int sfreq, int word_size);
+int mx_init_capture_card(void);
+
+
+/*device*/
+enum SND_INPUT_DEVICE {
+ LINE_IN = 0,
+ MIC1,
+ MIC2,
+ DMIC,
+ IN_UNDEFINED
+};
+
+enum SND_OUTPUT_DEVICE {
+ MONO_HS = 0,
+ STEREO_HEADPHONE,
+ INTERNAL_SPKR,
+ OUT_UNDEFINED
+};
+
+enum SND_CARDS {
+ SND_FS = 0,
+ SND_MX,
+ SND_NC,
+};
+
+enum pmic_controls {
+ PMIC_SND_INPUT_MUTE_LINE_IN = 0x0001,
+ PMIC_SND_INPUT_MUTE_MIC1 = 0x0002,
+ PMIC_SND_INPUT_MUTE_MIC2 = 0x0003,
+ PMIC_SND_INPUT_MUTE_DMIC = 0x0004,
+ PMIC_SND_INPUT_VOL_MIC1 = 0x0005,
+ PMIC_SND_INPUT_VOL_MIC2 = 0x0006,
+ PMIC_SND_INPUT_VOL_DMIC = 0x0007,
+ PMIC_SND_INPUT_VOL_RIGHT_LINE_IN = 0x0008,
+ PMIC_SND_INPUT_VOL_LEFT_LINE_IN = 0x0009,
+/*Output controls*/
+ PMIC_SND_LEFT_HP_VOL = 0x0010,
+ PMIC_SND_RIGHT_HP_VOL = 0x0011,
+ PMIC_SND_LEFT_HP_MUTE = 0x0012,
+ PMIC_SND_RIGHT_HP_MUTE = 0x0013,
+ PMIC_SND_LEFT_SPEAKER_VOL = 0x0014,
+ PMIC_SND_RIGHT_SPEAKER_VOL = 0x0015,
+ PMIC_SND_LEFT_SPEAKER_MUTE = 0x0016,
+ PMIC_SND_RIGHT_SPEAKER_MUTE = 0x0017,
+ PMIC_SND_MONO_EARPIECE_VOL = 0x0018,
+ PMIC_SND_MONO_EARPIECE_MUTE = 0x0019,
+/*Other controls*/
+ PMIC_MAX_CONTROLS = 0x0019,
+};
+
+#endif /*__INTELMID_SND_CTRL_H__*/
+
+
--
1.5.4.5
1
0
03 Jul '09
This adds the support for vendor PMICs for widget control
and configurations. The MID platform supports three
different vendor implementation of PMIC.
The sound card, ie all analog components like DAC,
ADC, mixer settings are different for three vendors. This
patch implements these settings for one of the vendor
Signed-off-by: Vinod Koul <vinod.koul(a)intel.com>
Signed-off-by: Harsha Priya <priya.harsha(a)intel.com>
Signed-off-by: R Dharageswari <dharageswari.r(a)intel.com>
new file: sound/pci/sst/intelmid_v2_control.c
---
sound/pci/sst/intelmid_v2_control.c | 629 +++++++++++++++++++++++++++++++++++
1 files changed, 629 insertions(+), 0 deletions(-)
create mode 100644 sound/pci/sst/intelmid_v2_control.c
diff --git a/sound/pci/sst/intelmid_v2_control.c b/sound/pci/sst/intelmid_v2_control.c
new file mode 100644
index 0000000..21e3cdb
--- /dev/null
+++ b/sound/pci/sst/intelmid_v2_control.c
@@ -0,0 +1,629 @@
+/*
+ * intelmid_v2_control.c - Intel Sound card driver for MID
+ *
+ * Copyright (C) 2008-09 Intel Corp
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ * Harsha Priya <priya.harsha(a)intel.com>
+ * R Dharageswari <dharageswari.r(a)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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This file contains the control operations of vendor 3
+ */
+
+#include <linux/cdev.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+#include <linux/file.h>
+#include <linux/fcntl.h>
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/workqueue.h>
+#include <linux/pci.h>
+#include <linux/firmware.h>
+#include <sound/intel_sst.h>
+#include <sound/intel_sst_ioctl.h>
+#include "intel_sst_fw_ipc.h"
+#include "intel_sst_common.h"
+#include "intel_sst_pvt.h"
+#include "intelmid_snd_control.h"
+
+#include <asm/ipc_defs.h>
+enum reg_v3 {
+ VAUDIOCNT = 0x51,
+ VOICEPORT1 = 0x100,
+ VOICEPORT2 = 0x101,
+ AUDIOPORT1 = 0x102,
+ AUDIOPORT2 = 0x103,
+ ADCSAMPLERATE = 0x104,
+ DMICCTRL1 = 0x105,
+ DMICCTRL2 = 0x106,
+ MICCTRL = 0x107,
+ MICSELVOL = 0x108,
+ LILSEL = 0x109,
+ LIRSEL = 0x10a,
+ VOICEVOL = 0x10b,
+ AUDIOLVOL = 0x10c,
+ AUDIORVOL = 0x10d,
+ LMUTE = 0x10e,
+ RMUTE = 0x10f,
+ POWERCTRL1 = 0x110,
+ POWERCTRL2 = 0x111,
+ DRVPOWERCTRL = 0x112,
+ VREFPLL = 0x113,
+ PCMBUFCTRL = 0x114,
+ SOFTMUTE = 0x115,
+ DTMFPATH = 0x116,
+ DTMFVOL = 0x117,
+ DTMFFREQ = 0x118,
+ DTMFHFREQ = 0x119,
+ DTMFLFREQ = 0x11a,
+ DTMFCTRL = 0x11b,
+ DTMFASON = 0x11c,
+ DTMFASOFF = 0x11d,
+ DTMFASINUM = 0x11e,
+ CLASSDVOL = 0x11f,
+ VOICEDACAVOL = 0x120,
+ AUDDACAVOL = 0x121,
+ LOMUTEVOL = 0x122,
+ HPLVOL = 0x123,
+ HPRVOL = 0x124,
+ MONOVOL = 0x125,
+ LINEOUTMIXVOL = 0x126,
+ EPMIXVOL = 0x127,
+ LINEOUTLSEL = 0x128,
+ LINEOUTRSEL = 0x129,
+ EPMIXOUTSEL = 0x12a,
+ HPLMIXSEL = 0x12b,
+ HPRMIXSEL = 0x12c,
+ LOANTIPOP = 0x12d,
+};
+
+
+int nc_init_card(void)
+{
+ struct sc_reg_access sc_access[] = {
+
+ {VAUDIOCNT, 0x27, 0},
+ {VOICEPORT1, 0xd5, 0},
+ {VOICEPORT2, 0x08, 0},
+ {AUDIOPORT1, 0x98, 0},
+ {AUDIOPORT2, 0x09, 0},
+ {AUDIOLVOL, 0x0e, 0},
+ {AUDIORVOL, 0x0e, 0},
+ {LMUTE, 0x03, 0},
+ {RMUTE, 0x03, 0},
+ {POWERCTRL1, 0xff, 0},
+ {POWERCTRL2, 0xff, 0},
+ {DRVPOWERCTRL, 0xff, 0},
+ {VREFPLL, 0xff , 0},
+ {HPLMIXSEL, 0xef, 0},
+ {HPRMIXSEL, 0xf7, 0},
+ {VAUDIOCNT, 0x27, 0},
+ {PCMBUFCTRL, 0x13, 0},
+ {DTMFPATH, 0x02, 0},
+ {DTMFCTRL, 0x00, 0},
+ {VOICEPORT1, 0xd5, 0},
+ {VOICEPORT2, 0x08, 0},
+ {VREFPLL, 0x3f, 0},
+ {POWERCTRL1, 0xff, 0},
+ {POWERCTRL2, 0xff, 0},
+ {DRVPOWERCTRL, 0xff, 0},
+ {HPLMIXSEL, 0xde, 0},
+ {HPRMIXSEL, 0xde, 0},
+ {VOICEVOL, 0x0e, 0},
+ {LMUTE, 0x01, 0},
+ {AUDIOPORT1, 0xa8, 0},
+ {AUDIOPORT2, 0x17, 0},
+ {AUDIOLVOL, 0x0e, 0},
+ {AUDIORVOL, 0x0e, 0},
+ {LMUTE, 0x03, 0},
+ {RMUTE, 0x03, 0},
+ {HPLMIXSEL, 0xef, 0},
+ {HPRMIXSEL, 0xf7, 0},
+ };
+ sst_sc_reg_access(sc_access, PMIC_WRITE, 37);
+ sst_dbg("complete!!\n");
+ return 0;
+}
+
+int nc_init_capture_card(void)
+{
+ struct sc_reg_access sc_access_capture[] = {
+ /*voice port enabling workaorund*/
+ {0x03A, 0x05, 0x00},
+ {0x051, 0x27, 0x00},
+ {0x113, 0x3A, 0x00},
+ {0x100, 0x90, 0x00},
+ {0x101, 0x07, 0x00},
+ {0x114, 0x33, 0x00},
+ {0x107, 0x10, 0x00},
+ {0x104, 0x83, 0x00},
+ {0x12B, 0xDE, 0x00},
+ {0x12C, 0xDE, 0x00},
+ {0x108, 0x53, 0x00},
+ {0x10A, 0x0C, 0x00},
+ {0x10B, 0x0E, 0x00},
+ {0x123, 0x0C, 0x00},
+ {0x124, 0x0C, 0x00},
+ {0x10E, 0x03, 0x00},
+ {0x10F, 0x03, 0x00},
+ {0x110, 0xD4, 0x00},
+ {0x111, 0x0C, 0x00},
+ {0x112, 0x06, 0x00},
+
+ /*audio port*/
+ {0x051, 0x27, 0x00},
+ {0x113, 0x35, 0x00},
+ {0x102, 0x90, 0x00},
+ {0x103, 0x00, 0x00},
+ {0x114, 0x33, 0x00},
+ {0x107, 0x11, 0x00},
+ {0x104, 0x83, 0x00},
+ {0x12B, 0xE6, 0x00},
+ {0x12C, 0xE6, 0x00},
+ {0x108, 0x53, 0x00},
+ {0x10A, 0x0C, 0x00},
+ {0x10B, 0x0E, 0x00},
+ {0x123, 0x0C, 0x00},
+ {0x124, 0x0C, 0x00},
+ {0x10E, 0x03, 0x00},
+ {0x10F, 0x03, 0x00},
+ {0x110, 0xFF, 0x00},
+ {0x111, 0x0C, 0x00},
+ {0x112, 0x06, 0x00},
+ };
+ sst_dbg("calling capture init\n");
+ sst_sc_reg_access(sc_access_capture, PMIC_WRITE, 39);
+ sst_dbg("complete!!\n");
+ return 0;
+}
+
+void nc_set_pcm_params(int sfreq, int word_size)
+{
+ int config2 = 0;
+ struct sc_reg_access sc_access;
+
+ switch (word_size) {
+ case 16:
+ switch (sfreq) {
+ case 8000:
+ config2 = 0x00;
+ break;
+ case 11025:
+ config2 = 0x01;
+ break;
+ case 12000:
+ config2 = 0x02;
+ break;
+ case 16000:
+ config2 = 0x03;
+ break;
+ case 22050:
+ config2 = 0x04;
+ break;
+ case 24000:
+ config2 = 0x05;
+ break;
+ case 32000:
+ config2 = 0x07;
+ break;
+ case 44100:
+ config2 = 0x08;
+ break;
+ case 48000:
+ config2 = 0x09;
+ break;
+ }
+ sst_dbg("word_size = %d\n", word_size);
+ sc_access.reg_addr = AUDIOPORT1;
+ sc_access.value = 0x98;
+ sst_sc_reg_access(&sc_access, PMIC_WRITE, 1);
+ sc_access.reg_addr = AUDIOPORT2;
+ sc_access.value = config2;
+ sst_sc_reg_access(&sc_access, PMIC_WRITE, 1);
+ break;
+ case 24:
+ switch (sfreq) {
+ case 8000:
+ config2 = 0x10;
+ break;
+ case 11025:
+ config2 = 0x11;
+ break;
+ case 12000:
+ config2 = 0x12;
+ break;
+ case 16000:
+ config2 = 0x13;
+ break;
+ case 22050:
+ config2 = 0x14;
+ break;
+ case 24000:
+ config2 = 0x15;
+ break;
+ case 32000:
+ config2 = 0x17;
+ break;
+ case 44100:
+ config2 = 0x18;
+ break;
+ case 48000:
+ config2 = 0x19;
+ break;
+ }
+ sst_dbg("word_size = %d\n", word_size);
+ sc_access.reg_addr = AUDIOPORT1;
+ sc_access.value = 0xAB;
+ sst_sc_reg_access(&sc_access, PMIC_WRITE, 1);
+ sc_access.reg_addr = AUDIOPORT2;
+ sc_access.value = config2;
+ sst_sc_reg_access(&sc_access, PMIC_WRITE, 1);
+ break;
+
+ }
+ sst_dbg("config2 = 0x%x\n", config2);
+ return;
+
+}
+int nc_set_selected_output_dev(int value)
+{
+ int retval = 0;
+ struct sc_reg_access sc_access_MHS[] = {
+ {RMUTE, 0X02, 0},
+ {POWERCTRL2, 0Xff, 0},
+ {DRVPOWERCTRL, 0xff, 0},
+ {VREFPLL, 0xff, 0},
+ {LMUTE, 0x02, 0},
+ {HPLMIXSEL, 0x00, 0},
+ {HPRMIXSEL, 0x00, 0},
+ {POWERCTRL1, 0xFF, 0},
+ {AUDIOLVOL, 0x00, 0},
+ {AUDIORVOL, 0x00, 0},
+ {LOMUTEVOL, 0x00, 0}
+ };
+
+ struct sc_reg_access sc_access_SH[] = {
+ {LMUTE, 0x03, 0x00},
+ {RMUTE, 0x02, 0x00}
+ };
+
+ struct sc_reg_access sc_access_IS[] = {
+ {LMUTE, 0x05, 0x00},
+ {RMUTE, 0x04, 0x00}
+ };
+
+
+ sst_dbg("nc set selected output:%d", value);
+
+ switch (value) {
+ case STEREO_HEADPHONE:
+ retval = sst_sc_reg_access(sc_access_SH, PMIC_WRITE, 2);
+ break;
+
+ case INTERNAL_SPKR:
+ retval = sst_sc_reg_access(sc_access_IS, PMIC_WRITE, 2);
+ break;
+
+ case MONO_HS:
+ retval = sst_sc_reg_access(sc_access_MHS, PMIC_WRITE, 11);
+ break;
+ default:
+ sst_err("rcvd illegal request:");
+ return -EINVAL;
+ }
+ return retval;
+}
+
+int nc_set_mute(int dev_id, int value)
+{
+ int retval = 0;
+ struct sc_reg_access sc_access;
+
+ sst_dbg("set device id::%d\n", dev_id);
+ sst_dbg("set device value::%d\n", value);
+ switch (dev_id) {
+ case PMIC_SND_INPUT_MUTE_MIC1:
+ sst_dbg("PMIC_SND_INPUT_MUTE_MIC1: value::%d", value);
+ if (value == UNMUTE) {
+ /* unmute the system, set the 6th bit to one */
+ sc_access.value = 0x00;
+ } else {
+ /* mute the system, reset the 6th bit to zero */
+ sc_access.value = 0x40;
+ }
+ sc_access.reg_addr = LILSEL;
+ sc_access.mask = MASK6;
+ break;
+ case PMIC_SND_INPUT_MUTE_MIC2:
+ sst_dbg("PMIC_SND_INPUT_MUTE_MIC2: value::%d", value);
+ if (value == UNMUTE) {
+ /* unmute the system, set the 6th bit to one */
+ sc_access.value = 0x00;
+ } else {
+ /* mute the system, reset the 6th bit to zero */
+ sc_access.value = 0x40;
+ }
+ sc_access.reg_addr = LIRSEL;
+ sc_access.mask = MASK6;
+ break;
+ case PMIC_SND_INPUT_MUTE_DMIC:
+ sst_dbg("PMIC_SND_INPUT_MUTE_DMIC: value::%d", value);
+ if (value == UNMUTE) {
+ /* unmute the system, set the 6th bit to one */
+ sc_access.value = 0x00;
+ } else {
+ /* mute the system, reset the 6th bit to zero */
+ sc_access.value = 0x40;
+ }
+ sc_access.reg_addr = DMICCTRL1;
+ sc_access.mask = MASK6;
+ break;
+ case PMIC_SND_LEFT_HP_MUTE:
+ case PMIC_SND_RIGHT_HP_MUTE:
+ if (value == UNMUTE)
+ sc_access.value = 0x0;
+ else
+ sc_access.value = 0x04;
+ if (dev_id == PMIC_SND_LEFT_HP_MUTE) {
+ sc_access.reg_addr = LMUTE;
+ sst_dbg("PMIC_SND_LEFT_HP_MUTE:: value::%d\n",
+ sc_access.value);
+ } else {
+ sc_access.reg_addr = RMUTE;
+ sst_dbg("PMIC_SND_RIGHT_HP_MUTE:: value::%d\n",
+ sc_access.value);
+ }
+ sc_access.mask = MASK2;
+ break;
+ case PMIC_SND_MONO_EARPIECE_MUTE:
+ if (value == UNMUTE)
+ sc_access.value = 0x00;
+ else
+ sc_access.value = 0x02;
+ sc_access.reg_addr = LMUTE;
+ sst_dbg("PMIC_SND_MONO_EARPIECE_MUTE::%d\n", sc_access.value);
+ sc_access.mask = MASK1;
+ break;
+ default:
+ sst_dbg("Invalid Device_id\n");
+ return -EINVAL;
+ }
+ retval = sst_sc_reg_access(&sc_access, PMIC_READ_MODIFY, 1);
+ return retval;
+
+}
+
+int nc_set_vol(int dev_id, int value)
+{
+ int retval = 0, MAX_VOL = 6;
+ struct sc_reg_access sc_access;
+
+ sst_dbg("set volume:%d", dev_id);
+ switch (dev_id) {
+ case PMIC_SND_INPUT_VOL_MIC1:
+ sst_dbg("PMIC_SND_INPUT_VOL_MIC1:: value::%d", value);
+ sc_access.value = abs(value);
+ sc_access.reg_addr = LILSEL;
+ sc_access.mask = MASK0|MASK1|MASK2|MASK3|MASK4|MASK5;
+ break;
+ case PMIC_SND_INPUT_VOL_MIC2:
+ sst_dbg("PMIC_SND_INPUT_VOL_MIC2:: value::%d", value);
+ sc_access.value = abs(value);
+ sc_access.reg_addr = LIRSEL;
+ sc_access.mask = MASK0|MASK1|MASK2|MASK3|MASK4|MASK5;
+ break;
+ case PMIC_SND_INPUT_VOL_DMIC:
+ sst_dbg("PMIC_SND_INPUT_VOL_DMIC:: value::%d", value);
+ sc_access.value = abs(value);
+ sc_access.reg_addr = DMICCTRL1;
+ sc_access.mask = MASK0|MASK1|MASK3|MASK4|MASK5|MASK6;
+ break;
+ case PMIC_SND_INPUT_VOL_RIGHT_LINE_IN:
+ break;
+ case PMIC_SND_INPUT_VOL_LEFT_LINE_IN:
+ break;
+ case PMIC_SND_LEFT_HP_VOL:
+ sc_access.value = MAX_VOL - value;
+ sst_dbg("PMIC_SND_LEFT_HP_VOL:%d", value);
+ sc_access.reg_addr = HPLVOL;
+ sc_access.mask = (MASK0|MASK1|MASK2|MASK3|MASK4);
+ break;
+
+ case PMIC_SND_RIGHT_HP_VOL:
+ sc_access.value = MAX_VOL-value;
+ sst_dbg("PMIC_SND_RIGHT_HP_VOL: value::%d\n", value);
+ sc_access.reg_addr = HPRVOL;
+ sc_access.mask = (MASK0|MASK1|MASK2|MASK3|MASK4);
+ break;
+
+ case PMIC_SND_MONO_EARPIECE_VOL:
+ sc_access.value = MAX_VOL-value;
+ sst_dbg("PMIC_MONO_EARPIECE_VOL: value::%d", value);
+ sc_access.reg_addr = MONOVOL;
+ sc_access.mask = (MASK0|MASK1|MASK2|MASK3|MASK4);
+ break;
+ default:
+ sst_dbg("Invalid Device_id\n");
+ return -EINVAL;;
+
+ }
+ /*sst_sc_read_modify(®_adrs, &difference, 1);*/
+ retval = sst_sc_reg_access(&sc_access, PMIC_READ_MODIFY, 1);
+ return retval;
+}
+
+int nc_set_selected_input_dev(int value)
+{
+ struct sc_reg_access sc_access[3];
+ int retval = 0;
+ u8 num_val;
+
+ sst_dbg("nc set selected input:%d", value);
+
+ switch (value) {
+ case MIC1:
+ sst_dbg("MIC1\n");
+ sc_access[0].reg_addr = LILSEL;
+ sc_access[0].mask = MASK7;
+ sc_access[0].value = 0x00;
+ num_val = 1;
+ break;
+
+ case MIC2:
+ sst_dbg("MIC2\n");
+ sc_access[0].reg_addr = LIRSEL;
+ sc_access[0].value = 0x06;
+ sc_access[0].mask = MASK0|MASK1|MASK2|MASK3|MASK4|
+ MASK5|MASK6|MASK7;
+
+ sc_access[1].reg_addr = MICSELVOL;
+ sc_access[1].value = 0x13;
+ sc_access[1].mask = MASK0|MASK1|MASK4 ;
+
+ sc_access[2].reg_addr = MICCTRL;
+ sc_access[2].value = 0x10;
+ sc_access[2].mask = MASK4;
+ num_val = 3;
+
+ break;
+
+ case DMIC:
+ sst_dbg("DMIC\n");
+ sc_access[0].reg_addr = DMICCTRL1;
+ sc_access[0].value = 0x40;
+ sc_access[0].mask = MASK6;
+ num_val = 1;
+
+ break;
+ default:
+ sst_err("rcvd illegal request:");
+ return -EINVAL;
+ }
+ retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, num_val);
+ return retval;
+}
+
+int nc_get_selected_output_dev(int *value)
+{
+ return 0;
+}
+
+int nc_get_mute(int dev_id, int *value)
+{
+ int retval = 0, mask = 0;
+ struct sc_reg_access sc_access = {0,};
+
+ sst_dbg("get mute::%d\n", dev_id);
+
+ switch (dev_id) {
+ case PMIC_SND_INPUT_MUTE_MIC1:
+ sst_dbg("PMIC_SND_INPUT_MUTE_MIC1\n");
+ sc_access.reg_addr = LILSEL;
+ mask = MASK6;
+ break;
+ case PMIC_SND_INPUT_MUTE_MIC2:
+ sst_dbg("PMIC_SND_INPUT_MUTE_MIC2\n");
+ sc_access.reg_addr = LIRSEL;
+ mask = MASK6;
+ break;
+ case PMIC_SND_LEFT_HP_MUTE:
+ case PMIC_SND_RIGHT_HP_MUTE:
+ mask = MASK2;
+ sst_dbg("PMIC_SN_LEFT/RIGHT_HP_MUTE\n");
+ if (dev_id == PMIC_SND_RIGHT_HP_MUTE)
+ sc_access.reg_addr = RMUTE;
+ else
+ sc_access.reg_addr = LMUTE;
+ break;
+
+ case PMIC_SND_MONO_EARPIECE_MUTE:
+ sst_dbg("PMIC_MONO_EARPIECE_MUTE\n");
+ sc_access.reg_addr = RMUTE;
+ mask = MASK1;
+ break;
+ default:
+ sst_dbg("Invalid Device_id\n");
+ return -EINVAL;
+
+ }
+ retval = sst_sc_reg_access(&sc_access, PMIC_READ_MODIFY, 1);
+ sst_dbg("reg value = %d\n", sc_access.value);
+ if (retval != 0)
+ return retval;
+ *value = (sc_access.value) & mask;
+ if (*value)
+ *value = 0;
+ else
+ *value = 1;
+ sst_dbg("value returned = 0x%x\n", *value);
+ return retval;
+}
+
+int nc_get_vol(int dev_id, int *value)
+{
+ int retval = 0, mask = 0, MAX_VOL = 6;
+ struct sc_reg_access sc_access = {0,};
+
+ switch (dev_id) {
+ case PMIC_SND_INPUT_VOL_MIC1:
+ sst_dbg("PMIC_SND_INPUT_VOL_MIC1\n");
+ sc_access.reg_addr = LILSEL;
+ mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5);
+ break;
+ case PMIC_SND_INPUT_VOL_MIC2:
+ sst_dbg("PMIC_SND_INPUT_VOL_MIC2\n");
+ sc_access.reg_addr = LIRSEL;
+ mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5);
+ break;
+ case PMIC_SND_INPUT_VOL_DMIC:
+ sst_dbg("PMIC_SND_INPUT_VOL_DMIC\n");
+ break;
+ case PMIC_SND_LEFT_HP_VOL:
+ sst_dbg("GET_VOLUME_PMIC_LEFT_HP_VOL\n");
+ sc_access.reg_addr = HPLVOL;
+ mask = (MASK0|MASK1|MASK2|MASK3|MASK4);
+ break;
+ case PMIC_SND_RIGHT_HP_VOL:
+ sst_dbg("GET_VOLUME_PMIC_RIGHT_HP_VOL\n");
+ sc_access.reg_addr = HPRVOL;
+ mask = (MASK0|MASK1|MASK2|MASK3|MASK4);
+ break;
+ case PMIC_SND_MONO_EARPIECE_VOL:
+ sst_dbg("GET_VOLUME_MONOEARPIECE_VOL\n");
+ sc_access.reg_addr = MONOVOL;
+ mask = (MASK0|MASK1|MASK2|MASK3|MASK4);
+ break;
+ default:
+ sst_dbg("Invalid Device_id = %d\n", dev_id);
+ return -EINVAL;
+
+ }
+ retval = sst_sc_reg_access(&sc_access, PMIC_READ, 1);
+ *value = (sc_access.value) & mask;
+ *value = MAX_VOL - *value;
+ sst_dbg("value returned = 0x%x\n", *value);
+ return retval;
+}
+
--
1.5.4.5
1
0
03 Jul '09
This adds the support for vendor PMICs for widget control
and configurations. The MID platform supports three
different vendor implementation of PMIC.
The sound card, ie all analog components like DAC,
ADC, mixer settings are different for three vendors. This
patch implements these settings for one of the vendor.
Signed-off-by: Vinod Koul <vinod.koul(a)intel.com>
Signed-off-by: Harsha Priya <priya.harsha(a)intel.com>
Signed-off-by: R Dharageswari <dharageswari.r(a)intel.com>
new file: sound/pci/sst/intelmid_v1_control.c
---
sound/pci/sst/intelmid_v1_control.c | 637 +++++++++++++++++++++++++++++++++++
1 files changed, 637 insertions(+), 0 deletions(-)
create mode 100644 sound/pci/sst/intelmid_v1_control.c
diff --git a/sound/pci/sst/intelmid_v1_control.c b/sound/pci/sst/intelmid_v1_control.c
new file mode 100644
index 0000000..32c2c51
--- /dev/null
+++ b/sound/pci/sst/intelmid_v1_control.c
@@ -0,0 +1,637 @@
+/*
+ * intelmid_v1_control.c - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-09 Intel Corp
+ * Authors: Vinod Koul <vinod.koul(a)intel.com>
+ * Harsha Priya <priya.harsha(a)intel.com>
+ * R Dharageswari <dharageswari.r(a)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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This file contains the control operations of vendor 3
+ */
+
+#include <linux/cdev.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+#include <linux/file.h>
+#include <linux/fcntl.h>
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/workqueue.h>
+#include <linux/pci.h>
+#include <linux/firmware.h>
+#include <sound/intel_sst.h>
+#include <sound/intel_sst_ioctl.h>
+#include "intel_sst_fw_ipc.h"
+#include "intel_sst_common.h"
+#include "intel_sst_pvt.h"
+#include "intelmid_snd_control.h"
+
+#include <asm/ipc_defs.h>
+enum _reg_v2 {
+
+ MASTER_CLOCK_PRESCALAR = 0x205,
+ SET_MASTER_AND_LR_CLK1 = 0x20b,
+ SET_MASTER_AND_LR_CLK2 = 0x20c,
+ MASTER_MODE_AND_DATA_DELAY = 0x20d,
+ DIGITAL_INTERFACE_TO_DAI2 = 0x20e,
+ CLK_AND_FS1 = 0x208,
+ CLK_AND_FS2 = 0x209,
+ DAI2_TO_DAC_HP = 0x210,
+ HP_OP_SINGLE_ENDED = 0x224,
+ ENABLE_OPDEV_CTRL = 0x226,
+ ENABLE_DEV_AND_USE_XTAL = 0x227,
+
+ /* Max audio subsystem (PQ49) MAX 8921 */
+ AS_IP_MODE_CTL = 0xF9,
+ AS_LEFT_SPKR_VOL_CTL = 0xFA, /* Mono Earpiece volume control */
+ AS_RIGHT_SPKR_VOL_CTL = 0xFB,
+ AS_LEFT_HP_VOL_CTL = 0xFC,
+ AS_RIGHT_HP_VOL_CTL = 0xFD,
+ AS_OP_MIX_CTL = 0xFE,
+ AS_CONFIG = 0xFF,
+
+ /* Headphone volume control & mute registers */
+ VOL_CTRL_LT = 0x21c,
+ VOL_CTRL_RT = 0x21d,
+
+};
+
+/* Headphone volume control values in dB */
+int mx_hp_vol[MAX_HP_VOL_INDX_PMIC_VENDOR1] =
+{
+ (+6),
+ (+6), /* +5.5, commented as this is not an integer */
+ (+5),
+ (+5), /* +4.5, commented as this is not an integer */
+ (+4),
+ (+4), /* +3.5, commented as this is not an integer */
+ (+3),
+ (+2),
+ (+1),
+ 0,
+ (-1),
+ (-2),
+ (-3),
+ (-4),
+ (-5),
+ (-6),
+ (-8),
+ (-10),
+ (-12),
+ (-14),
+ (-16),
+ (-18),
+ (-20),
+ (-22),
+ (-26),
+ (-30),
+ (-34),
+ (-38),
+ (-42),
+ (-46),
+ (-50),
+ (-54),
+ (-58),
+ (-62),
+ (-66),
+ (-70),
+ (-74),
+ (-78),
+ (-82),
+ (-84)
+}; /* mx_hp_vol[] */
+
+/* Mono Earpiece volume control values in dB */
+int mx_ep_vol[MAX_EP_VOL_INDX_PMIC_VENDOR1] =
+{
+ (-75),
+ (-71),
+ (-67),
+ (-63),
+ (-59),
+ (-55),
+ (-51),
+ (-47),
+ (-44),
+ (-41),
+ (-38),
+ (-35),
+ (-32),
+ (-29),
+ (-26),
+ (-23),
+ (-21),
+ (-19),
+ (-17),
+ (-15),
+ (-13),
+ (-11),
+ (-9),
+ (-7),
+ (-6),
+ (-5),
+ (-4),
+ (-3),
+ (-2),
+ (-1),
+ (0)
+}; /* mx_ep_vol[] */
+
+int mx_init_card(void)
+{
+
+ struct sc_reg_access sc_access[17] = {{0,},};
+ int retval = 0;
+ sst_dbg("mx initializing card...\n");
+
+ sc_access[0].reg_addr = MASTER_CLOCK_PRESCALAR;
+ sc_access[0].value = 0x10;
+ sc_access[1].reg_addr = SET_MASTER_AND_LR_CLK1;
+ sc_access[1].value = 0x60;
+ sc_access[2].reg_addr = SET_MASTER_AND_LR_CLK2;
+ sc_access[2].value = 0x00;
+ sc_access[3].reg_addr = MASTER_MODE_AND_DATA_DELAY ;
+ sc_access[3].value = 0x90;
+ sc_access[4].reg_addr = DIGITAL_INTERFACE_TO_DAI2;
+ sc_access[4].value = 0x51;
+ sc_access[5].reg_addr = CLK_AND_FS1;
+ sc_access[5].value = 0x90;
+ sc_access[6].reg_addr = CLK_AND_FS2;
+ sc_access[6].value = 0x51;/*Mx fix for 50Mhz*/
+ sc_access[7].reg_addr = DAI2_TO_DAC_HP;
+ sc_access[7].value = 0x21;
+ sc_access[8].reg_addr = VOL_CTRL_LT;
+ sc_access[8].value = 0x09;
+ sc_access[9].reg_addr = VOL_CTRL_RT;
+ sc_access[9].value = 0x00;
+ sc_access[10].reg_addr = HP_OP_SINGLE_ENDED;
+ sc_access[10].value = 0x04;
+ sc_access[11].reg_addr = ENABLE_OPDEV_CTRL;
+ sc_access[11].value = 0x0c;
+ sc_access[12].reg_addr = ENABLE_DEV_AND_USE_XTAL ;
+ sc_access[12].value = 0x88;
+ /* mono earpiece - default register configuration */
+ /* Input mode control - zero crossing detection
+ * enabled */
+ sc_access[13].reg_addr = AS_IP_MODE_CTL;
+ sc_access[13].value = 0x40;
+
+ /* Left speaker volume (Mono EP) (-6) dB */
+ sc_access[14].reg_addr = AS_LEFT_SPKR_VOL_CTL;
+ sc_access[14].value = 0x19;
+
+ /* output mixer -INA1 + INA2 enabled */
+ sc_access[15].reg_addr = AS_OP_MIX_CTL;
+ sc_access[15].value = 0x60;
+ /* configuration - Disable the audio subsytem (Max 8921) */
+ sc_access[16].reg_addr = AS_CONFIG;
+ sc_access[16].value = 0x00;
+
+ retval = sst_sc_reg_access(sc_access, PMIC_WRITE, 17);
+ if (0 != retval) {
+ sst_dbg("pmic communication failed \n");
+ return retval;
+ }
+
+ sst_dbg("mx Initilaisation complete!!\n");
+ return 0;
+}
+
+int mx_init_capture_card(void)
+{
+ return 0;
+}
+
+void mx_set_pcm_params(int sfreq, int word_size)
+{
+ int config1 = 0, config2 = 0;
+ int retval = 0;
+ struct sc_reg_access sc_access[4] = {{0,},};
+
+ switch (sfreq) {
+ case 8000:
+ config1 = 0x10;
+ config2 = 0x00;
+ break;
+ case 11025:
+ config1 = 0x16;
+ config2 = 0x0d;
+ break;
+ case 12000:
+ config1 = 0x18;
+ config2 = 0x00;
+ break;
+ case 16000:
+ config1 = 0x20;
+ config2 = 0x00;
+ break;
+ case 22050:
+ config1 = 0x2c;
+ config2 = 0x1a;
+ break;
+ case 24000:
+ config1 = 0x30;
+ config2 = 0x00;
+ break;
+ case 32000:
+ config1 = 0x40;
+ config2 = 0x00;
+ break;
+ case 44100:
+ config1 = 0x58;
+ config2 = 0x33;
+ break;
+ case 48000:
+ config1 = 0x60;
+ config2 = 0x00;
+ break;
+ }
+
+ sc_access[0].reg_addr = SET_MASTER_AND_LR_CLK1;
+ sc_access[0].value = config1;
+ sc_access[1].reg_addr = SET_MASTER_AND_LR_CLK2;
+ sc_access[1].value = config2;
+ switch (word_size) {
+ case 16:
+ config1 = 0x51;
+ config2 = 0x31;
+ break;
+ case 24:
+ config1 = 0x52;
+ config2 = 0x32;
+ break;
+ }
+
+ sst_dbg("config1 = %x\n", config1);
+ sst_dbg("config2 = %x\n", config2);
+ sc_access[2].reg_addr = DIGITAL_INTERFACE_TO_DAI2;
+ sc_access[2].value = config1;
+ sc_access[3].reg_addr = CLK_AND_FS2;
+ sc_access[3].value = config2;
+ retval = sst_sc_reg_access(sc_access, PMIC_WRITE, 4);
+ if (0 != retval)
+ sst_dbg("pmic communication failed \n");
+ return;
+} /* mx_set_pcm_params */
+
+int mx_set_selected_output_dev(int dev_id)
+{
+ struct sc_reg_access sc_access[4] = {{0,},};
+ int retval = 0;
+
+ sst_dbg("mx_set_selected_input_dev dev_id:0x%x\n", dev_id);
+ switch (dev_id) {
+ case INTERNAL_SPKR:
+ break;
+
+ case STEREO_HEADPHONE:
+ /* Enable stereo headphones - Begin */
+ /* Volume Left Un-Mute */
+ sc_access[0].reg_addr = VOL_CTRL_LT;
+ sc_access[0].value = 0x00;
+ sc_access[0].mask = MASK6;
+ /* Volume right Un-Mute */
+ sc_access[1].reg_addr = VOL_CTRL_RT;
+ sc_access[1].value = 0x00;
+ sc_access[1].mask = MASK6;
+ /* Enable stereo headphones - End */
+
+ /* Disable Mono earpiece - Begin */
+ /* configuration - AS Disable */
+ sc_access[2].reg_addr = AS_CONFIG;
+ sc_access[2].value = 0x00;
+ sc_access[2].mask = MASK7;
+
+ /* Line output (L&R) Disable */
+ sc_access[3].reg_addr = ENABLE_OPDEV_CTRL;
+ sc_access[3].value = 0x00;
+ sc_access[3].mask = MASK4|MASK5;
+ retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 4);
+ if (0 != retval)
+ return retval;
+ /* Disable Mono earpiece - End */
+ break;
+
+ case MONO_HS:
+ /* select mono earpiece - Begin */
+ /* configuration - AS enable, left speaker enable */
+ sc_access[0].reg_addr = AS_CONFIG;
+ sc_access[0].value = 0xA0;
+ sc_access[0].mask = (MASK5|MASK7);
+ /* Line output (L&R), DAC output (L&R) enable */
+ sc_access[1].reg_addr = ENABLE_OPDEV_CTRL;
+ sc_access[1].value = 0x3C;
+ sc_access[1].mask = (MASK2|MASK3|MASK4|MASK5);
+ retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2);
+ if (0 != retval)
+ return retval;
+ /* select mono earpiece -end */
+ break;
+ } /* switch (dev_id) */
+
+ return retval;
+} /* mx_set_selected_output_dev */
+
+int mx_set_selected_input_dev(int value)
+{
+ return 0;
+} /* mx_set_selected_input_dev */
+
+int mx_set_mute(int dev_id, int value)
+{
+ struct sc_reg_access sc_access[1] = {{0,},};
+ int retval = 0;
+
+ sst_dbg("mx_set_mute dev_id:0x%x , value:%d \n", dev_id, value);
+
+ /* MAD passes value:0 for mute, value:1 for unmute */
+ switch (dev_id) {
+ case PMIC_SND_INPUT_MUTE_LINE_IN:
+ break;
+
+ case PMIC_SND_INPUT_MUTE_MIC1:
+ break;
+
+ case PMIC_SND_INPUT_MUTE_MIC2:
+ break;
+
+ case PMIC_SND_INPUT_MUTE_DMIC:
+ break;
+
+ case PMIC_SND_LEFT_SPEAKER_MUTE:
+ break;
+
+ case PMIC_SND_RIGHT_SPEAKER_MUTE:
+ break;
+
+ case PMIC_SND_LEFT_HP_MUTE:
+ sc_access[0].reg_addr = VOL_CTRL_LT;
+ if (value == MUTE)
+ sc_access[0].value = 0x40;
+ else
+ sc_access[0].value = 0x00;
+ sc_access[0].mask = MASK6;
+ retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
+ break;
+
+ case PMIC_SND_RIGHT_HP_MUTE:
+ sc_access[0].reg_addr = VOL_CTRL_RT;
+ if (value == MUTE)
+ sc_access[0].value = 0x40;
+ else
+ sc_access[0].value = 0x00;
+ sc_access[0].mask = MASK6;
+ retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
+ break;
+
+ case PMIC_SND_MONO_EARPIECE_MUTE:
+ sc_access[0].reg_addr = AS_LEFT_SPKR_VOL_CTL;
+ if (value == MUTE)
+ sc_access[0].value = 0x00;
+ else
+ sc_access[0].value = 0x19;
+ sc_access[0].mask = (MASK0|MASK1|MASK2|MASK3|MASK4);
+ retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
+ break;
+ } /* switch (dev_id) */
+
+ return retval;
+} /* mx_set_mute */
+
+int mx_set_vol(int dev_id, int value)
+{
+ struct sc_reg_access sc_access[1] = {{0,},};
+ int retval = 0, i;
+
+ sst_dbg("mx_set_vol dev_id:0x%x , value:%d \n", dev_id, value);
+ switch (dev_id) {
+ case PMIC_SND_INPUT_VOL_MIC1:
+ case PMIC_SND_INPUT_VOL_MIC2:
+ break;
+ case PMIC_SND_INPUT_VOL_DMIC:
+ break;
+ case PMIC_SND_LEFT_SPEAKER_VOL:
+ break;
+ case PMIC_SND_RIGHT_SPEAKER_VOL:
+ break;
+ case PMIC_SND_LEFT_HP_VOL:
+ for (i = 0; i < MAX_HP_VOL_INDX_PMIC_VENDOR1; i++) {
+ if (value >= mx_hp_vol[i]) {
+ sc_access[0].value = i;
+ break; /* exit out of the for loop */
+ } /* if(value >= mx_hp_vol[i]) */
+
+ } /* for(i=0; i< MAX_HP_VOL_INDX_PMIC_VENDOR1; i++) */
+ sc_access[0].reg_addr = VOL_CTRL_LT;
+ sc_access[0].mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5);
+ break;
+ case PMIC_SND_RIGHT_HP_VOL:
+ for (i = 0; i < MAX_HP_VOL_INDX_PMIC_VENDOR1; i++) {
+ if (value >= mx_hp_vol[i]) {
+ sc_access[0].value = i;
+ break; /* exit out of the for loop */
+ } /* if(value >= mx_hp_vol[i]) */
+ } /* for(i=0; i< MAX_HP_VOL_INDX_PMIC_VENDOR1; i++) */
+ sc_access[0].reg_addr = VOL_CTRL_RT;
+ sc_access[0].mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5);
+ break;
+ case PMIC_SND_MONO_EARPIECE_VOL:
+ for (i = 0; i < MAX_EP_VOL_INDX_PMIC_VENDOR1; i++) {
+ if (value <= mx_ep_vol[i]) {
+ sc_access[0].value = i;
+ break; /* exit out of the for loop */
+ } /* if(value >= mx_ep_vol[i]) */
+ } /* for(i=0; i< MAX_EP_VOL_INDX_PMIC_VENDOR1; i++) */
+ sc_access[0].reg_addr = AS_LEFT_SPKR_VOL_CTL;
+ sc_access[0].mask = (MASK0|MASK1|MASK2|MASK3|MASK4);
+ break;
+ } /* switch (dev_id) */
+ retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
+ return retval;
+} /* mx_set_vol */
+
+
+int mx_get_selected_input_dev(int *value)
+{
+ return 0;
+} /* mx_get_selected_input_dev */
+
+int mx_get_selected_output_dev(int *value)
+{
+ struct sc_reg_access sc_access[1] = {{0,},};
+ int retval = 0, temp_value;
+
+ sc_access[0].reg_addr = AS_CONFIG;
+ retval = sst_sc_reg_access(sc_access, PMIC_READ, 1);
+ if (0 != retval) {
+ /*pmic communication fails*/
+ sst_err("pmic commn failed \n");
+ return retval;
+ }
+ temp_value = sc_access[0].value;
+ if (0 == temp_value)
+ /* Max 8921 is disabled hence Mono earpiece is disabled */
+ *value = STEREO_HEADPHONE;
+ else
+ *value = MONO_HS;
+ return 0;
+} /* mx_get_selected_output_dev */
+
+int mx_get_mute(int dev_id, int *value)
+{
+ struct sc_reg_access sc_access[1] = {{0,},};
+ int retval = 0, temp_value;
+
+ switch (dev_id) {
+ case PMIC_SND_INPUT_MUTE_LINE_IN:
+ break;
+
+ case PMIC_SND_INPUT_MUTE_MIC1:
+ break;
+
+ case PMIC_SND_INPUT_MUTE_MIC2:
+ break;
+
+ case PMIC_SND_INPUT_MUTE_DMIC:
+ break;
+
+ case PMIC_SND_LEFT_SPEAKER_MUTE:
+ break;
+
+ case PMIC_SND_RIGHT_SPEAKER_MUTE:
+ break;
+
+ case PMIC_SND_LEFT_HP_MUTE:
+ sc_access[0].reg_addr = VOL_CTRL_LT;
+ retval = sst_sc_reg_access(sc_access, PMIC_READ, 1);
+ if (0 != retval) {
+ /*pmic communication fails*/
+ sst_err("pmic commn failed \n");
+ return retval;
+ }
+ temp_value = sc_access[0].value & (MASK6);
+ if (0 == temp_value)
+ *value = UNMUTE;
+ else
+ *value = MUTE;
+ break;
+ case PMIC_SND_RIGHT_HP_MUTE:
+ sc_access[0].reg_addr = VOL_CTRL_RT;
+ retval = sst_sc_reg_access(sc_access, PMIC_READ, 1);
+ if (0 != retval) {
+ /*pmic communication fails*/
+ sst_err("pmic commn failed \n");
+ return retval;
+ }
+ temp_value = sc_access[0].value &
+ (MASK6);
+ if (0 == temp_value)
+ *value = UNMUTE;
+ else
+ *value = MUTE;
+ break;
+ case PMIC_SND_MONO_EARPIECE_MUTE:
+ sc_access[0].reg_addr = AS_LEFT_SPKR_VOL_CTL;
+ retval = sst_sc_reg_access(sc_access, PMIC_READ, 1);
+ if (0 != retval) {
+ /*pmic communication fails*/
+ sst_err("pmic commn failed \n");
+ return retval;
+ }
+ temp_value = sc_access[0].value &
+ (MASK0|MASK1|MASK2|MASK3|MASK4);
+
+ if (0 == temp_value)
+ *value = UNMUTE;
+ else
+ *value = MUTE;
+ break;
+ } /* switch (dev_id) */
+
+ sst_dbg("dev id:0x%2x, :0x%2x \n", dev_id, *value);
+ return retval;
+} /* mx_get_mute */
+
+int mx_get_vol(int dev_id, int *value)
+{
+ struct sc_reg_access sc_access[1] = {{0,},};
+ int retval = 0, temp_value = 0;
+
+ switch (dev_id) {
+ case PMIC_SND_INPUT_VOL_MIC1:
+ case PMIC_SND_INPUT_VOL_MIC2:
+ break;
+ case PMIC_SND_INPUT_VOL_DMIC:
+ break;
+ case PMIC_SND_LEFT_SPEAKER_VOL:
+ break;
+ case PMIC_SND_RIGHT_SPEAKER_VOL:
+ break;
+ case PMIC_SND_LEFT_HP_VOL:
+ sc_access[0].reg_addr = VOL_CTRL_LT;
+ retval = sst_sc_reg_access(sc_access, PMIC_READ, 1);
+ if (0 != retval) {
+ /*pmic communication fails*/
+ sst_err("pmic commn failed \n");
+ return retval;
+ }
+ temp_value = sc_access[0].value
+ & (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5);
+ *value = mx_hp_vol[temp_value];
+ break;
+ case PMIC_SND_RIGHT_HP_VOL:
+ sc_access[0].reg_addr = VOL_CTRL_RT;
+ retval = sst_sc_reg_access(sc_access, PMIC_READ, 1);
+ if (0 != retval) {
+ /*pmic communication fails*/
+ sst_err("pmic commn failed \n");
+ return retval;
+ }
+ temp_value = sc_access[0].value
+ & (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5);
+ *value = mx_hp_vol[temp_value];
+ break;
+ case PMIC_SND_MONO_EARPIECE_VOL:
+ sc_access[0].reg_addr = AS_LEFT_SPKR_VOL_CTL;
+ retval = sst_sc_reg_access(sc_access, PMIC_READ, 1);
+ if (0 != retval) {
+ /*pmic communication fails*/
+ sst_err("pmic commn failed \n");
+ return retval;
+ }
+ temp_value = sc_access[0].value
+ & (MASK0|MASK1|MASK2|MASK3|MASK4);
+ *value = mx_ep_vol[temp_value];
+ break;
+ } /* switch (dev_id) */
+
+ sst_dbg("value read from the register:0x%2x\n", temp_value);
+ sst_dbg("dev_id:0x%2x , volume:0x%2x in dB\n", dev_id, *value);
+
+ return retval;
+} /* mx_get_vol() */
+
+
+
--
1.5.4.5
1
0