summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorKP, Jeeja <jeeja.kp@intel.com>2012-03-22 21:47:57 +0530
committerbuildbot <buildbot@intel.com>2012-04-12 05:23:02 -0700
commit5485b9ef3232681dd20e4a01fff608b35e7fd802 (patch)
treebbcd9a2136146b6016b860131447272f25cdda8c /sound
parent2fb8b53711b4892bd87abc3dbc6bd915094d663c (diff)
downloadkernel-mfld-blackbay-5485b9ef3232681dd20e4a01fff608b35e7fd802.tar.gz
kernel-mfld-blackbay-5485b9ef3232681dd20e4a01fff608b35e7fd802.tar.bz2
kernel-mfld-blackbay-5485b9ef3232681dd20e4a01fff608b35e7fd802.zip
audio: Exposed LPE Mixer controls for the HAL to select the Mixer required
based on the sink device BZ: 26104 Added support for device pipeline configuration by exposing LPE Mixer elements as ALSA mixer controls. To add support in SOc for add platform controls, following alsa patchs are applied 1. 0001-ASoC-core-Add-API-call-to-register-platform-kcontrol 2. 0002-ASoC-core-Make-platform-probe-more-like-codec-probe Change-Id: I01b829294f82753496f06a5df05afec4c48384b7 Signed-off-by: KP, Jeeja <jeeja.kp@intel.com> Reviewed-on: http://android.intel.com:8080/40136 Reviewed-by: Koul, Vinod <vinod.koul@intel.com> Tested-by: M, Arulselvan <arulselvan.m@intel.com> Reviewed-by: buildbot <buildbot@intel.com> Tested-by: buildbot <buildbot@intel.com>
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/sst/intel_sst.c5
-rw-r--r--sound/pci/sst/intel_sst_common.h5
-rw-r--r--sound/pci/sst/intel_sst_drv_interface.c40
-rw-r--r--sound/pci/sst/intel_sst_fw_ipc.h6
-rw-r--r--sound/pci/sst/intel_sst_ipc.c33
-rw-r--r--sound/soc/mid-x86/sst_platform.c152
-rw-r--r--sound/soc/soc-core.c85
7 files changed, 308 insertions, 18 deletions
diff --git a/sound/pci/sst/intel_sst.c b/sound/pci/sst/intel_sst.c
index 8d6a1f4ce33..8d201efc27c 100644
--- a/sound/pci/sst/intel_sst.c
+++ b/sound/pci/sst/intel_sst.c
@@ -207,6 +207,7 @@ static int __devinit intel_sst_probe(struct pci_dev *pci,
mutex_init(&sst_drv_ctx->stream_lock);
mutex_init(&sst_drv_ctx->sst_lock);
+ mutex_init(&sst_drv_ctx->mixer_ctrl_lock);
sst_drv_ctx->stream_cnt = 0;
sst_drv_ctx->encoded_cnt = 0;
@@ -276,6 +277,10 @@ static int __devinit intel_sst_probe(struct pci_dev *pci,
sst_drv_ctx->mmap_len);
}
}
+ if (sst_drv_ctx->pci_id == SST_CLV_PCI_ID) {
+ sst_drv_ctx->device_input_mixer = SST_STREAM_DEVICE_IHF
+ | SST_INPUT_STREAM_PCM;
+ }
/* Init the device */
ret = pci_enable_device(pci);
diff --git a/sound/pci/sst/intel_sst_common.h b/sound/pci/sst/intel_sst_common.h
index df4eef39ca1..a7d05c50b97 100644
--- a/sound/pci/sst/intel_sst_common.h
+++ b/sound/pci/sst/intel_sst_common.h
@@ -470,6 +470,8 @@ struct intel_sst_drv {
struct sst_dma dma;
void *fw_in_mem;
struct sst_runtime_param runtime_param;
+ unsigned int device_input_mixer;
+ struct mutex mixer_ctrl_lock;
};
extern struct intel_sst_drv *sst_drv_ctx;
@@ -558,7 +560,8 @@ void sst_clear_interrupt(void);
int sst_download_fw(void);
void free_stream_context(unsigned int str_id);
void sst_clean_stream(struct stream_info *stream);
-vibra_pwm_configure(unsigned int enable);
+int vibra_pwm_configure(unsigned int enable);
+int sst_send_algo_param(struct snd_ppp_params *algo_params);
/*
* sst_fill_header - inline to fill sst header
diff --git a/sound/pci/sst/intel_sst_drv_interface.c b/sound/pci/sst/intel_sst_drv_interface.c
index 4a6c06e915a..03a08becf79 100644
--- a/sound/pci/sst/intel_sst_drv_interface.c
+++ b/sound/pci/sst/intel_sst_drv_interface.c
@@ -162,6 +162,34 @@ void free_stream_context(unsigned int str_id)
}
}
+void sst_send_lpe_mixer_algo_params()
+{
+ struct snd_ppp_params algo_param;
+ struct snd_ppp_mixer_params mixer_param;
+ unsigned int input_mixer, stream_device_id;
+
+ mutex_lock(&sst_drv_ctx->mixer_ctrl_lock);
+ input_mixer = (sst_drv_ctx->device_input_mixer)
+ & SST_INPUT_STREAM_MIXED;
+ stream_device_id = sst_drv_ctx->device_input_mixer - input_mixer;
+ algo_param.algo_id = SST_CODEC_MIXER;
+ algo_param.str_id = stream_device_id;
+ algo_param.enable = 1;
+ algo_param.reserved = 0;
+ algo_param.size = sizeof(algo_param);
+ mixer_param.type = SST_ALGO_PARAM_MIXER_STREAM_CFG;
+ mixer_param.input_stream_bitmap = input_mixer;
+ mixer_param.size = sizeof(input_mixer);
+ algo_param.params = &mixer_param;
+ mutex_unlock(&sst_drv_ctx->mixer_ctrl_lock);
+ pr_err("setting pp param\n");
+ pr_debug("Algo ID %d Str id %d Enable %d Size %d\n",
+ algo_param.algo_id, algo_param.str_id,
+ algo_param.enable, algo_param.size);
+ sst_send_algo_param(&algo_param);
+}
+
+
/*
* sst_get_stream_allocated - this function gets a stream allocated with
* the given params
@@ -178,6 +206,10 @@ int sst_get_stream_allocated(struct snd_sst_params *str_param,
int retval, str_id;
struct stream_info *str_info;
+ if (sst_drv_ctx->pci_id == SST_CLV_PCI_ID) {
+ pr_debug("Sending LPE mixer algo Params\n");
+ sst_send_lpe_mixer_algo_params();
+ }
retval = sst_alloc_stream((char *) &str_param->sparams, str_param->ops,
str_param->codec, str_param->device_type);
if (retval < 0) {
@@ -628,6 +660,14 @@ static int sst_set_generic_params(enum sst_controls cmd, void *arg)
ret_val = sst_copy_runtime_param(dst, src);
break;
}
+ case SST_SET_ALGO_PARAMS: {
+ unsigned int device_input_mixer = *((unsigned int *)arg);
+ pr_debug("LPE mixer algo param set %x\n", device_input_mixer);
+ mutex_lock(&sst_drv_ctx->mixer_ctrl_lock);
+ sst_drv_ctx->device_input_mixer = device_input_mixer;
+ mutex_unlock(&sst_drv_ctx->mixer_ctrl_lock);
+ break;
+ }
default:
pr_err("Invalid cmd request:%d\n", cmd);
ret_val = -EINVAL;
diff --git a/sound/pci/sst/intel_sst_fw_ipc.h b/sound/pci/sst/intel_sst_fw_ipc.h
index 97d23309a2e..b91be93ede1 100644
--- a/sound/pci/sst/intel_sst_fw_ipc.h
+++ b/sound/pci/sst/intel_sst_fw_ipc.h
@@ -362,6 +362,12 @@ struct lib_slot_info {
u32 dram_offset; /* starting offset of slot in DRAM */
} __attribute__ ((packed));
+struct snd_ppp_mixer_params {
+ __u32 type; /*Type of the parameter */
+ __u32 size;
+ __u32 input_stream_bitmap; /*Input stream Bit Map*/
+} __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 */
diff --git a/sound/pci/sst/intel_sst_ipc.c b/sound/pci/sst/intel_sst_ipc.c
index 893e74b9798..4ddad218885 100644
--- a/sound/pci/sst/intel_sst_ipc.c
+++ b/sound/pci/sst/intel_sst_ipc.c
@@ -97,6 +97,39 @@ static int sst_send_runtime_param(struct snd_sst_runtime_params *params)
params->addr, params->size);
return sst_send_ipc_msg_nowait(&msg);
}
+
+/*
+ * sst_send_algo_param - send LPE Mixer param to SST
+ *
+ * this function sends the algo parameter to sst dsp engine
+ */
+int sst_send_algo_param(struct snd_ppp_params *algo_params)
+{
+ u32 header_size = 0;
+ struct ipc_post *msg = NULL;
+ u32 ipc_msg_size = sizeof(u32) + sizeof(*algo_params)
+ - sizeof(algo_params->params) + algo_params->size;
+ u32 offset = 0;
+
+ if (ipc_msg_size > SST_MAILBOX_SIZE)
+ return -ENOMEM;
+ if (sst_create_large_msg(&msg))
+ return -ENOMEM;
+ sst_fill_header(&msg->header,
+ IPC_IA_ALG_PARAMS, 1, algo_params->str_id);
+ msg->header.part.data = sizeof(u32) + sizeof(*algo_params)
+ - sizeof(algo_params->params) + algo_params->size;
+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
+ offset = sizeof(u32);
+ header_size = sizeof(*algo_params) - sizeof(algo_params->params);
+ memcpy(msg->mailbox_data + sizeof(u32), algo_params,
+ sizeof(*algo_params) - sizeof(algo_params->params));
+ offset += header_size;
+ memcpy(msg->mailbox_data + offset , algo_params->params,
+ algo_params->size);
+ return sst_send_ipc_msg_nowait(&msg);
+}
+
/**
* sst_post_message - Posts message to SST
*
diff --git a/sound/soc/mid-x86/sst_platform.c b/sound/soc/mid-x86/sst_platform.c
index 49d1e96c877..ec908d81096 100644
--- a/sound/soc/mid-x86/sst_platform.c
+++ b/sound/soc/mid-x86/sst_platform.c
@@ -66,6 +66,33 @@ static struct snd_pcm_hardware sst_platform_pcm_hw = {
.periods_max = SST_MAX_PERIODS,
.fifo_size = SST_FIFO_SIZE,
};
+#ifdef CONFIG_SND_CLV_MACHINE
+static unsigned int lpe_mixer_input_ihf;
+static unsigned int lpe_mixer_input_hs;
+
+int sst_set_mixer_param(unsigned int device_input_mixer)
+{
+ struct intel_sst_card_ops *sstdrv_ops;
+ int ret_val;
+
+ /* allocate memory for SST API set */
+ sstdrv_ops = kzalloc(sizeof(*sstdrv_ops), GFP_KERNEL);
+ if (!sstdrv_ops)
+ return -ENOMEM;
+ /* registering with SST driver to get access to SST APIs to use */
+ ret_val = register_sst_card(sstdrv_ops);
+ if (ret_val) {
+ pr_err("sst: sst card registration failed\n");
+ return -EIO;
+ }
+
+ /*allocate memory for params*/
+ ret_val = sstdrv_ops->pcm_control->set_generic_params(
+ SST_SET_ALGO_PARAMS, (void *)&device_input_mixer);
+ kfree(sstdrv_ops);
+ return ret_val;
+}
+#endif
static int sst_platform_ihf_set_tdm_slot(struct snd_soc_dai *dai,
unsigned int tx_mask, unsigned int rx_mask,
@@ -94,11 +121,99 @@ static int sst_platform_ihf_set_tdm_slot(struct snd_soc_dai *dai,
kfree(sstdrv_ops);
return ret_val;
}
-
static const struct snd_soc_dai_ops sst_ihf_ops = {
.set_tdm_slot = sst_platform_ihf_set_tdm_slot,
};
+#ifdef CONFIG_SND_CLV_MACHINE
+static int lpe_mixer_ihf_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = lpe_mixer_input_ihf;
+ return 0;
+}
+
+static int lpe_mixer_ihf_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int device_input_mixer;
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ pr_debug("input is PCM stream\n");
+ device_input_mixer = SST_STREAM_DEVICE_IHF
+ | SST_INPUT_STREAM_PCM;
+ break;
+ case 1:
+ pr_debug("input is Comptress stream\n");
+ device_input_mixer = SST_STREAM_DEVICE_IHF
+ | SST_INPUT_STREAM_COMPRESS;
+ break;
+ case 2:
+ pr_debug("input is mixed stream\n");
+ device_input_mixer = SST_STREAM_DEVICE_IHF
+ | SST_INPUT_STREAM_MIXED;
+ break;
+ default:
+ pr_err("Invalid Input%d\n", ucontrol->value.integer.value[0]);
+ return -EINVAL;
+ }
+ lpe_mixer_input_ihf = ucontrol->value.integer.value[0];
+ sst_set_mixer_param(device_input_mixer);
+ return 0;
+}
+
+static int lpe_mixer_headset_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = lpe_mixer_input_hs;
+ return 0;
+}
+
+static int lpe_mixer_headset_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int mixer_input_stream;
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ pr_debug("input is PCM stream\n");
+ mixer_input_stream = SST_STREAM_DEVICE_HS
+ | SST_INPUT_STREAM_PCM;
+ break;
+ case 1:
+ pr_debug("input is Comptress stream\n");
+ mixer_input_stream = SST_STREAM_DEVICE_HS
+ | SST_INPUT_STREAM_COMPRESS;
+ break;
+ case 2:
+ pr_debug("input is PCM stream\n");
+ mixer_input_stream = SST_STREAM_DEVICE_HS
+ | SST_INPUT_STREAM_MIXED;
+ break;
+ default:
+ pr_err("Invalid Input%d\n", ucontrol->value.integer.value[0]);
+ return -EINVAL;
+ }
+ lpe_mixer_input_hs = ucontrol->value.integer.value[0];
+ sst_set_mixer_param(mixer_input_stream);
+ return 0;
+}
+static const char *lpe_mixer_text[] = {
+ "PCM", "Compressed", "PCM and Compressed"};
+
+static const struct soc_enum lpe_mixer_enum =
+ SOC_ENUM_SINGLE_EXT(3, lpe_mixer_text);
+
+
+static const struct snd_kcontrol_new sst_controls[] = {
+ SOC_ENUM_EXT("LPE IHF mixer", lpe_mixer_enum,
+ lpe_mixer_ihf_get, lpe_mixer_ihf_set),
+ SOC_ENUM_EXT("LPE headset mixer", lpe_mixer_enum,
+ lpe_mixer_headset_get, lpe_mixer_headset_set),
+};
+#endif
+
/* MFLD - MSIC */
static struct snd_soc_dai_driver sst_platform_dai[] = {
{
@@ -598,7 +713,42 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
}
return retval;
}
+#ifdef CONFIG_SND_CLV_MACHINE
+static int sst_soc_probe(struct snd_soc_platform *platform)
+{
+ pr_debug("%s called\n", __func__);
+
+ lpe_mixer_input_ihf = 0;
+ lpe_mixer_input_hs = 0;
+ pr_debug("platform is %p\n", platform);
+ if (!platform) {
+ pr_err("platform ptr invalid");
+ return -EINVAL;
+ }
+ if (!platform->card) {
+ pr_err("platform card ptr invalid");
+ return -EINVAL;
+ }
+ if (!platform->card->snd_card) {
+ pr_err("platform card snd_card ptr invalid");
+ return -EINVAL;
+ }
+
+ return snd_soc_add_platform_controls(platform, sst_controls,
+ ARRAY_SIZE(sst_controls));
+}
+
+static int sst_soc_remove(struct snd_soc_platform *platform)
+{
+ pr_debug("%s called\n", __func__);
+ return 0;
+}
+#endif
static struct snd_soc_platform_driver sst_soc_platform_drv = {
+#ifdef CONFIG_SND_CLV_MACHINE
+ .probe = &sst_soc_probe,
+ .remove = &sst_soc_remove,
+#endif
.ops = &sst_platform_ops,
.pcm_new = sst_pcm_new,
.pcm_free = sst_pcm_free,
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 3736248d428..25fb4bdb72b 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -458,7 +458,7 @@ static int soc_ac97_dev_unregister(struct snd_soc_codec *codec)
}
/* stop no dev release warning */
-static void soc_ac97_device_release(struct device *dev){}
+static void soc_ac97_device_release(struct device *dev) {}
/* register ac97 codec to bus */
static int soc_ac97_dev_register(struct snd_soc_codec *codec)
@@ -1531,6 +1531,39 @@ err_probe:
return ret;
}
+static int soc_probe_platform(struct snd_soc_card *card,
+ struct snd_soc_platform *platform)
+{
+ int ret = 0;
+ const struct snd_soc_platform_driver *driver = platform->driver;
+
+ platform->card = card;
+
+ if (!try_module_get(platform->dev->driver->owner))
+ return -ENODEV;
+
+ if (driver->probe) {
+ ret = driver->probe(platform);
+ if (ret < 0) {
+ dev_err(platform->dev,
+ "asoc: failed to probe platform %s: %d\n",
+ platform->name, ret);
+ goto err_probe;
+ }
+ }
+
+ /* mark platform as probed and add to card platform list */
+ platform->probed = 1;
+ list_add(&platform->card_list, &card->platform_dev_list);
+
+ return 0;
+
+err_probe:
+ module_put(platform->dev->driver->owner);
+
+ return ret;
+}
+
static void rtd_release(struct device *dev) {}
static int soc_post_component_init(struct snd_soc_card *card,
@@ -1649,21 +1682,10 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num)
/* probe the platform */
if (!platform->probed) {
- if (!try_module_get(platform->dev->driver->owner))
- return -ENODEV;
+ ret = soc_probe_platform(card, platform);
+ if (ret < 0)
+ return ret;
- if (platform->driver->probe) {
- ret = platform->driver->probe(platform);
- if (ret < 0) {
- printk(KERN_ERR "asoc: failed to probe platform %s\n",
- platform->name);
- module_put(platform->dev->driver->owner);
- return ret;
- }
- }
- /* mark platform as probed and add to card platform list */
- platform->probed = 1;
- list_add(&platform->card_list, &card->platform_dev_list);
}
/* probe the CODEC DAI */
@@ -2121,7 +2143,7 @@ static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
if (codec_dai->driver->capture.channels_min)
capture = 1;
- dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num,new_name);
+ dev_dbg(rtd->card->dev, "registered pcm #%d %s\n", num, new_name);
ret = snd_pcm_new(rtd->card->snd_card, new_name,
num, playback, capture, &pcm);
if (ret < 0) {
@@ -2494,6 +2516,37 @@ int snd_soc_add_controls(struct snd_soc_codec *codec,
EXPORT_SYMBOL_GPL(snd_soc_add_controls);
/**
+ * snd_soc_add_platform_controls - add an array of controls to a platform.
+ * Convienience function to add a list of controls.
+ *
+ * @platform: platform to add controls to
+ * @controls: array of controls to add
+ * @num_controls: number of elements in the array
+ *
+ * Return 0 for success, else error.
+ */
+int snd_soc_add_platform_controls(struct snd_soc_platform *platform,
+ const struct snd_kcontrol_new *controls, int num_controls)
+{
+ struct snd_card *card = platform->card->snd_card;
+ int err, i;
+
+ for (i = 0; i < num_controls; i++) {
+ const struct snd_kcontrol_new *control = &controls[i];
+ err = snd_ctl_add(card, snd_soc_cnew(control, platform,
+ control->name, NULL));
+ if (err < 0) {
+ dev_err(platform->dev, "Failed to add %s %d\n",
+ control->name, err);
+ return err;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_add_platform_controls);
+
+/**
* snd_soc_info_enum_double - enumerated double mixer info callback
* @kcontrol: mixer control
* @uinfo: control element information