From b35ac43067ec35a0d281df1aa52419d4ad6589bd Mon Sep 17 00:00:00 2001 From: Ramesh Babu K V Date: Tue, 28 Feb 2012 21:06:40 +0530 Subject: [PATCH] audio:add support for mono speaker BZ: 23041 This patch adds support for mono speaker configuration using runtime sst params. If particular board has mono speaker, kernel config SND_MFLD_MONO_SPEAKER_SUPPORT needs to selected to enable the mono speaker support. Change-Id: I3084772106669c129c426981c140b60afe658d41 Signed-off-by: Ramesh Babu K V Reviewed-on: http://android.intel.com:8080/36911 Reviewed-by: Koul, Vinod Reviewed-by: Gupta, ArvindX K Reviewed-by: Hibare, PramodX Tested-by: Hibare, PramodX Reviewed-by: buildbot Tested-by: buildbot --- include/sound/intel_sst.h | 4 ++- include/sound/intel_sst_ioctl.h | 13 +++++-- sound/pci/sst/intel_sst.c | 1 + sound/pci/sst/intel_sst_common.h | 5 ++- sound/pci/sst/intel_sst_drv_interface.c | 60 +++++++++++++++++++++++++++++++++ sound/pci/sst/intel_sst_ipc.c | 44 ++++++++++++++++++++++++ sound/soc/mid-x86/Kconfig | 9 +++++ sound/soc/mid-x86/mfld_machine.c | 16 +++++++++ sound/soc/mid-x86/sst_platform.c | 33 ++++++++++++++++++ 9 files changed, 181 insertions(+), 4 deletions(-) diff --git a/include/sound/intel_sst.h b/include/sound/intel_sst.h index 82be67f8..3111289 100644 --- a/include/sound/intel_sst.h +++ b/include/sound/intel_sst.h @@ -65,7 +65,8 @@ enum sst_controls { SST_VMIC_CHANNEL_SELECT = 0x1011, SST_SND_DEVICE_RESUME = 0x1012, SST_SND_DEVICE_RESUME_SYNC = 0x1013, - SST_MAX_CONTROLS = 0x1013, + SST_SET_RUNTIME_PARAMS = 0x1014, + SST_MAX_CONTROLS = 0x1014, }; enum SND_CARDS { @@ -118,6 +119,7 @@ int intelmad_get_mic_bias(void); struct intel_sst_pcm_control { int (*open) (struct snd_sst_params *str_param); int (*device_control) (int cmd, void *arg); + int (*set_generic_params) (enum sst_controls cmd, void *arg); int (*close) (unsigned int str_id); }; struct intel_sst_card_ops { diff --git a/include/sound/intel_sst_ioctl.h b/include/sound/intel_sst_ioctl.h index f7a7c6a..eaea339 100644 --- a/include/sound/intel_sst_ioctl.h +++ b/include/sound/intel_sst_ioctl.h @@ -335,8 +335,9 @@ enum snd_sst_port_action { }; enum stream_param_type { - SET_TIME_SLOT = 0, - OTHERS = 1, /*reserved for other params that need to be set in future*/ + SST_SET_TIME_SLOT = 0, + SST_SET_CHANNEL_INFO = 1, + OTHERS = 2, /*reserved for other params that need to be set in future*/ }; /* Target selection per device structure */ @@ -412,6 +413,14 @@ struct snd_sst_tuning_params { __u8 rsvd; __u64 addr; } __attribute__ ((packed)); + +struct snd_sst_runtime_params { + __u8 type; + __u8 str_id; + __u8 size; + __u8 rsvd; + void *addr; +} __attribute__ ((packed)); /*IOCTL defined here */ /*SST MMF IOCTLS only */ #define SNDRV_SST_STREAM_SET_PARAMS _IOWR('L', 0x00, \ diff --git a/sound/pci/sst/intel_sst.c b/sound/pci/sst/intel_sst.c index de97691..ce69d07 100644 --- a/sound/pci/sst/intel_sst.c +++ b/sound/pci/sst/intel_sst.c @@ -447,6 +447,7 @@ static void __devexit intel_sst_remove(struct pci_dev *pci) kfree(sst_drv_ctx->mmap_mem); } else kfree(sst_drv_ctx->fw_cntx); + kfree(sst_drv_ctx->runtime_param.param.addr); flush_scheduled_work(); destroy_workqueue(sst_drv_ctx->process_reply_wq); destroy_workqueue(sst_drv_ctx->process_msg_wq); diff --git a/sound/pci/sst/intel_sst_common.h b/sound/pci/sst/intel_sst_common.h index 37f80c6..932961d 100644 --- a/sound/pci/sst/intel_sst_common.h +++ b/sound/pci/sst/intel_sst_common.h @@ -344,7 +344,9 @@ struct sst_dma { struct pci_dev *dmac; }; - +struct sst_runtime_param { + struct snd_sst_runtime_params param; +}; #define PCI_DMAC_MFLD_ID 0x0830 #define PCI_DMAC_CLV_ID 0x08F0 #define SST_MAX_DMA_LEN (4095*4) @@ -454,6 +456,7 @@ struct intel_sst_drv { struct list_head fw_list; struct sst_dma dma; void *fw_in_mem; + struct sst_runtime_param runtime_param; }; extern struct intel_sst_drv *sst_drv_ctx; diff --git a/sound/pci/sst/intel_sst_drv_interface.c b/sound/pci/sst/intel_sst_drv_interface.c index 58befa1..4a6c06e 100644 --- a/sound/pci/sst/intel_sst_drv_interface.c +++ b/sound/pci/sst/intel_sst_drv_interface.c @@ -575,10 +575,70 @@ static int sst_device_control(int cmd, void *arg) return retval; } +/* + * sst_copy_runtime_param - copy runtime params from src to dst + * structure. + * + *@dst: destination runtime structure + *@src: source runtime structure + * + * This helper function is called to copy the runtime parameter + * structure. +*/ +static int sst_copy_runtime_param(struct snd_sst_runtime_params *dst, + struct snd_sst_runtime_params *src) +{ + dst->type = src->type; + dst->str_id = src->str_id; + dst->size = src->size; + if (dst->addr) { + pr_err("mem allocated in prev setting, use the same memory\n"); + return -EINVAL; + } + dst->addr = kzalloc(dst->size, GFP_KERNEL); + if (!dst->addr) + return -ENOMEM; + memcpy(dst->addr, src->addr, dst->size); + return 0; +} +/* + * sst_set_generic_params - Set generic params + * + * @cmd: control cmd to be set + * @arg: command argument + * + * This function is called by MID sound card driver to configure + * SST runtime params. + */ +static int sst_set_generic_params(enum sst_controls cmd, void *arg) +{ + int ret_val = 0; + pr_debug("Enter:%s, cmd:%d\n", __func__, cmd); + + if (NULL == arg) + return -EINVAL; + + switch (cmd) { + case SST_SET_RUNTIME_PARAMS: { + struct snd_sst_runtime_params *src; + struct snd_sst_runtime_params *dst; + + src = (struct snd_sst_runtime_params *)arg; + dst = &(sst_drv_ctx->runtime_param.param); + ret_val = sst_copy_runtime_param(dst, src); + break; + } + default: + pr_err("Invalid cmd request:%d\n", cmd); + ret_val = -EINVAL; + } + return ret_val; +} static struct intel_sst_pcm_control pcm_ops = { .open = sst_open_pcm_stream, .device_control = sst_device_control, + .set_generic_params = sst_set_generic_params, .close = sst_close_pcm_stream, }; diff --git a/sound/pci/sst/intel_sst_ipc.c b/sound/pci/sst/intel_sst_ipc.c index d5c894b..893e74b 100644 --- a/sound/pci/sst/intel_sst_ipc.c +++ b/sound/pci/sst/intel_sst_ipc.c @@ -36,6 +36,23 @@ #include "intel_sst_fw_ipc.h" #include "intel_sst_common.h" +/** + * sst_send_ipc_msg_nowait - send ipc msg for algorithm parameters + * and returns immediately without waiting for reply + * + * @msg: post msg pointer + * + * This function is called to send ipc msg + */ +static int sst_send_ipc_msg_nowait(struct ipc_post **msg) +{ + spin_lock(&sst_drv_ctx->list_spin_lock); + list_add_tail(&(*msg)->node, &sst_drv_ctx->ipc_dispatch_list); + spin_unlock(&sst_drv_ctx->list_spin_lock); + sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); + return 0; +} + /* * sst_send_sound_card_type - send sound card type * @@ -56,6 +73,30 @@ static void sst_send_sound_card_type(void) sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); } +/* + * sst_send_runtime_param - send runtime param to SST + * + * this function sends the runtime parameter to sst dsp engine + */ +static int sst_send_runtime_param(struct snd_sst_runtime_params *params) +{ + struct ipc_post *msg = NULL; + int ret_val; + + pr_debug("Enter:%s\n", __func__); + ret_val = sst_create_large_msg(&msg); + if (ret_val) + return ret_val; + sst_fill_header(&msg->header, IPC_IA_SET_RUNTIME_PARAMS, 1, + params->str_id); + msg->header.part.data = sizeof(u32) + sizeof(*params) + params->size; + memcpy(msg->mailbox_data, &msg->header.full, sizeof(u32)); + memcpy(msg->mailbox_data + sizeof(u32), params, sizeof(*params)); + /* driver doesn't need to send address, so overwrite addr with data */ + memcpy(msg->mailbox_data + sizeof(u32) + sizeof(*params) - sizeof(params->addr), + params->addr, params->size); + return sst_send_ipc_msg_nowait(&msg); +} /** * sst_post_message - Posts message to SST * @@ -176,6 +217,9 @@ static int process_fw_init(struct sst_ipc_msg_wq *msg) } if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) sst_send_sound_card_type(); + /* If there any runtime parameter to set, send it */ + if (sst_drv_ctx->runtime_param.param.addr) + sst_send_runtime_param(&(sst_drv_ctx->runtime_param.param)); mutex_lock(&sst_drv_ctx->sst_lock); sst_drv_ctx->lpe_stalled = 0; mutex_unlock(&sst_drv_ctx->sst_lock); diff --git a/sound/soc/mid-x86/Kconfig b/sound/soc/mid-x86/Kconfig index 7ed9c3d..75da0c5 100644 --- a/sound/soc/mid-x86/Kconfig +++ b/sound/soc/mid-x86/Kconfig @@ -27,3 +27,12 @@ config SND_CLV_MACHINE config SND_SST_PLATFORM tristate + +config SND_MFLD_MONO_SPEAKER_SUPPORT + tristate "Mono Speaker support for Medfield based devices" + default N + help + This adds support for Mono speaker support on Intel(R) MID Medfield based devices. + Say Y if you have device with mono speaker. If you say N support for stereo speakers + will be enabled. + If unsure select "N". diff --git a/sound/soc/mid-x86/mfld_machine.c b/sound/soc/mid-x86/mfld_machine.c index 39c55d3..d939a98 100644 --- a/sound/soc/mid-x86/mfld_machine.c +++ b/sound/soc/mid-x86/mfld_machine.c @@ -345,6 +345,18 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime) return ret_val; } +#ifdef CONFIG_SND_MFLD_MONO_SPEAKER_SUPPORT +static int mfld_speaker_init(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_dai *cpu_dai = runtime->cpu_dai; + struct snd_soc_dapm_context *dapm = &runtime->codec->dapm; + + snd_soc_dapm_disable_pin(dapm, "IHFOUTR"); + snd_soc_dapm_sync(dapm); + return cpu_dai->driver->ops->set_tdm_slot(cpu_dai, 0, 0, 1, 0); +} +#endif + static struct snd_soc_dai_link mfld_msic_dailink[] = { { .name = "Medfield Headset", @@ -363,7 +375,11 @@ static struct snd_soc_dai_link mfld_msic_dailink[] = { .codec_dai_name = "SN95031 Speaker", .codec_name = "sn95031", .platform_name = "sst-platform", +#ifdef CONFIG_SND_MFLD_MONO_SPEAKER_SUPPORT + .init = mfld_speaker_init, +#else .init = NULL, +#endif .ignore_suspend = 1, }, /* diff --git a/sound/soc/mid-x86/sst_platform.c b/sound/soc/mid-x86/sst_platform.c index 6739ee5..d57d9e8 100644 --- a/sound/soc/mid-x86/sst_platform.c +++ b/sound/soc/mid-x86/sst_platform.c @@ -67,6 +67,38 @@ static struct snd_pcm_hardware sst_platform_pcm_hw = { .fifo_size = SST_FIFO_SIZE, }; +static int sst_platform_ihf_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) { + struct intel_sst_card_ops *sstdrv_ops; + struct snd_sst_runtime_params params_data; + int channels = slots; + 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; + } + params_data.type = SST_SET_CHANNEL_INFO; + params_data.str_id = SND_SST_DEVICE_IHF; + params_data.size = sizeof(channels); + params_data.addr = &channels; + ret_val = sstdrv_ops->pcm_control->set_generic_params(SST_SET_RUNTIME_PARAMS, + (void *)¶ms_data); + 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, +}; + /* MFLD - MSIC */ static struct snd_soc_dai_driver sst_platform_dai[] = { { @@ -105,6 +137,7 @@ static struct snd_soc_dai_driver sst_platform_dai[] = { #endif .formats = SNDRV_PCM_FMTBIT_S16_LE, }, + .ops = &sst_ihf_ops, }, { .name = "Vibra1-cpu-dai", -- 2.7.4