From patchwork Wed Jul 30 13:02:23 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Subhransu S. Prusty" X-Patchwork-Id: 4649191 Return-Path: X-Original-To: patchwork-alsa-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 74ABDC0338 for ; Wed, 30 Jul 2014 13:29:21 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 385F320158 for ; Wed, 30 Jul 2014 13:29:20 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.kernel.org (Postfix) with ESMTP id A09EB2012B for ; Wed, 30 Jul 2014 13:29:18 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id 97563265005; Wed, 30 Jul 2014 15:29:17 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from alsa0.perex.cz (localhost [IPv6:::1]) by alsa0.perex.cz (Postfix) with ESMTP id 1C032261A18; Wed, 30 Jul 2014 15:26:10 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 9C113261A0E; Wed, 30 Jul 2014 15:26:08 +0200 (CEST) Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by alsa0.perex.cz (Postfix) with ESMTP id 7FA2B261A18 for ; Wed, 30 Jul 2014 15:24:05 +0200 (CEST) Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga103.fm.intel.com with ESMTP; 30 Jul 2014 06:17:12 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.97,862,1389772800"; d="scan'208";a="365828787" Received: from subhransu-udesk1.iind.intel.com ([10.223.96.40]) by FMSMGA003.fm.intel.com with ESMTP; 30 Jul 2014 06:20:59 -0700 From: "Subhransu S. Prusty" To: alsa-devel@alsa-project.org Date: Wed, 30 Jul 2014 18:32:23 +0530 Message-Id: <1406725350-23275-7-git-send-email-subhransu.s.prusty@intel.com> X-Mailer: git-send-email 1.9.0 In-Reply-To: <1406725350-23275-1-git-send-email-subhransu.s.prusty@intel.com> References: <1406725350-23275-1-git-send-email-subhransu.s.prusty@intel.com> Cc: vinod.koul@intel.com, broonie@kernel.org, "Subhransu S. Prusty" , lgirdwood@gmail.com, Lars-Peter Clausen Subject: [alsa-devel] [v3 06/13] ASoC: Intel: mrfld: add bytes control for modules X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP From: Vinod Koul This patch add support for various modules like eq etc for mrfld DSP. All these modules will be exposed to usermode as bytes controls. Signed-off-by: Vinod Koul Signed-off-by: Subhransu S. Prusty --- sound/soc/intel/sst-atom-controls.c | 176 ++++++++++++++++++++++++++++++++++++ sound/soc/intel/sst-atom-controls.h | 130 ++++++++++++++++++++++++++ 2 files changed, 306 insertions(+) diff --git a/sound/soc/intel/sst-atom-controls.c b/sound/soc/intel/sst-atom-controls.c index 38731e3e5e95..9b878c17d10a 100644 --- a/sound/soc/intel/sst-atom-controls.c +++ b/sound/soc/intel/sst-atom-controls.c @@ -25,6 +25,180 @@ #include "sst-mfld-platform.h" #include "sst-atom-controls.h" +static inline void sst_fill_byte_control(char *param, + u8 ipc_msg, u8 block, + u8 task_id, u8 pipe_id, + u16 len, void *cmd_data) +{ + + struct snd_sst_bytes_v2 *byte_data = (struct snd_sst_bytes_v2 *)param; + + byte_data->type = SST_CMD_BYTES_SET; + byte_data->ipc_msg = ipc_msg; + byte_data->block = block; + byte_data->task_id = task_id; + byte_data->pipe_id = pipe_id; + + if (len > SST_MAX_BIN_BYTES - sizeof(*byte_data)) { + pr_err("%s: command length too big (%u)", __func__, len); + len = SST_MAX_BIN_BYTES - sizeof(*byte_data); + WARN_ON(1); /* this happens only if code is wrong */ + } + byte_data->len = len; + memcpy(byte_data->bytes, cmd_data, len); + print_hex_dump_bytes("writing to lpe: ", DUMP_PREFIX_OFFSET, + byte_data, len + sizeof(*byte_data)); +} + +static int sst_fill_and_send_cmd_unlocked(struct sst_data *drv, + u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id, + void *cmd_data, u16 len) +{ + sst_fill_byte_control(drv->byte_stream, ipc_msg, block, task_id, pipe_id, + len, cmd_data); + return sst->ops->send_byte_stream(drv->byte_stream); +} + +/** + * sst_fill_and_send_cmd - generate the IPC message and send it to the FW + * @ipc_msg: type of IPC (CMD, SET_PARAMS, GET_PARAMS) + * @cmd_data: the IPC payload + */ +static int sst_fill_and_send_cmd(struct sst_data *drv, + u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id, + void *cmd_data, u16 len) +{ + int ret; + + mutex_lock(&drv->lock); + ret = sst_fill_and_send_cmd_unlocked(drv, ipc_msg, block, task_id, pipe_id, + cmd_data, len); + mutex_unlock(&drv->lock); + + return ret; +} + +static void sst_send_algo_cmd(struct sst_data *drv, + struct sst_algo_control *bc) +{ + int len; + struct sst_cmd_set_params *cmd; + + if (bc->params == NULL) + return; + + /* bc->max includes sizeof algos + length field */ + len = sizeof(cmd->dst) + sizeof(cmd->command_id) + bc->max; + + cmd = kzalloc(len, GFP_KERNEL); + if (cmd == NULL) { + pr_err("Failed to send cmd, kzalloc failed\n"); + return; + } + + SST_FILL_DESTINATION(2, cmd->dst, bc->pipe_id, bc->module_id); + cmd->command_id = bc->cmd_id; + memcpy(cmd->params, bc->params, bc->max); + + sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_SET_PARAMS, + SST_FLAG_BLOCKED, bc->task_id, 0, cmd, len); + kfree(cmd); +} + +static int sst_algo_bytes_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct sst_algo_control *bc = (void *)kcontrol->private_value; + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = bc->max; + + /* allocate space to cache the algo parameters in the driver */ + if (bc->params == NULL) { + bc->params = devm_kzalloc(component->dev, bc->max, GFP_KERNEL); + if (bc->params == NULL) { + pr_err("kzalloc failed\n"); + return -ENOMEM; + } + } + return 0; +} + +static int sst_algo_control_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct sst_algo_control *bc = (void *)kcontrol->private_value; + + switch (bc->type) { + case SST_ALGO_PARAMS: + if (bc->params) + memcpy(ucontrol->value.bytes.data, bc->params, bc->max); + break; + case SST_ALGO_BYPASS: + ucontrol->value.integer.value[0] = bc->bypass ? 1 : 0; + pr_debug("%s: bypass %d\n", __func__, bc->bypass); + break; + default: + pr_err("Invalid Input- algo type:%d\n", bc->type); + return -EINVAL; + + } + return 0; +} + +static int sst_algo_control_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); + struct sst_data *drv = snd_soc_platform_get_drvdata(platform); + struct sst_algo_control *bc = (void *)kcontrol->private_value; + + pr_debug("in %s control_name=%s\n", __func__, kcontrol->id.name); + mutex_lock(&drv->lock); + switch (bc->type) { + case SST_ALGO_PARAMS: + if (bc->params) + memcpy(bc->params, ucontrol->value.bytes.data, bc->max); + break; + case SST_ALGO_BYPASS: + bc->bypass = !!ucontrol->value.integer.value[0]; + break; + default: + mutex_unlock(&drv->lock); + pr_err("Invalid Input- algo type:%ld\n", ucontrol->value.integer.value[0]); + return -EINVAL; + } + /*if pipe is enabled, need to send the algo params from here */ + if (bc->w && bc->w->power) + sst_send_algo_cmd(drv, bc); + mutex_unlock(&drv->lock); + + return 0; +} + +static const struct snd_kcontrol_new sst_algo_controls[] = { + SST_ALGO_KCONTROL_BYTES("media_loop1_out", "fir", 272, SST_MODULE_ID_FIR_24, + SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR), + SST_ALGO_KCONTROL_BYTES("media_loop1_out", "iir", 300, SST_MODULE_ID_IIR_24, + SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_IIR), + SST_ALGO_KCONTROL_BYTES("media_loop1_out", "mdrp", 286, SST_MODULE_ID_MDRP, + SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_SET_MDRP), + SST_ALGO_KCONTROL_BYTES("media_loop2_out", "fir", 272, SST_MODULE_ID_FIR_24, + SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR), + SST_ALGO_KCONTROL_BYTES("media_loop2_out", "iir", 300, SST_MODULE_ID_IIR_24, + SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_VB_SET_IIR), + SST_ALGO_KCONTROL_BYTES("media_loop2_out", "mdrp", 286, SST_MODULE_ID_MDRP, + SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_SET_MDRP), + SST_ALGO_KCONTROL_BYTES("sprot_loop_out", "lpro", 192, SST_MODULE_ID_SPROT, + SST_PATH_INDEX_SPROT_LOOP_OUT, 0, SST_TASK_SBA, SBA_VB_LPRO), + SST_ALGO_KCONTROL_BYTES("codec_in0", "dcr", 52, SST_MODULE_ID_FILT_DCR, + SST_PATH_INDEX_CODEC_IN0, 0, SST_TASK_SBA, SBA_VB_SET_IIR), + SST_ALGO_KCONTROL_BYTES("codec_in1", "dcr", 52, SST_MODULE_ID_FILT_DCR, + SST_PATH_INDEX_CODEC_IN1, 0, SST_TASK_SBA, SBA_VB_SET_IIR), + +}; + int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform) { int ret = 0; @@ -37,5 +211,7 @@ int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform) return -ENOMEM; } + snd_soc_add_platform_controls(platform, sst_algo_controls, + ARRAY_SIZE(sst_algo_controls)); return ret; } diff --git a/sound/soc/intel/sst-atom-controls.h b/sound/soc/intel/sst-atom-controls.h index 8554889c0694..a73e894b175c 100644 --- a/sound/soc/intel/sst-atom-controls.h +++ b/sound/soc/intel/sst-atom-controls.h @@ -309,4 +309,134 @@ enum sst_swm_state { SST_SWM_ON = 3, }; +#define SST_FILL_LOCATION_IDS(dst, cell_idx, pipe_id) do { \ + dst.location_id.p.cell_nbr_idx = (cell_idx); \ + dst.location_id.p.path_id = (pipe_id); \ + } while (0) +#define SST_FILL_LOCATION_ID(dst, loc_id) (\ + dst.location_id.f = (loc_id)) +#define SST_FILL_MODULE_ID(dst, mod_id) (\ + dst.module_id = (mod_id)) + +#define SST_FILL_DESTINATION1(dst, id) do { \ + SST_FILL_LOCATION_ID(dst, (id) & 0xFFFF); \ + SST_FILL_MODULE_ID(dst, ((id) & 0xFFFF0000) >> 16); \ + } while (0) +#define SST_FILL_DESTINATION2(dst, loc_id, mod_id) do { \ + SST_FILL_LOCATION_ID(dst, loc_id); \ + SST_FILL_MODULE_ID(dst, mod_id); \ + } while (0) +#define SST_FILL_DESTINATION3(dst, cell_idx, path_id, mod_id) do { \ + SST_FILL_LOCATION_IDS(dst, cell_idx, path_id); \ + SST_FILL_MODULE_ID(dst, mod_id); \ + } while (0) + +#define SST_FILL_DESTINATION(level, dst, ...) \ + SST_FILL_DESTINATION##level(dst, __VA_ARGS__) +#define SST_FILL_DEFAULT_DESTINATION(dst) \ + SST_FILL_DESTINATION(2, dst, SST_DEFAULT_LOCATION_ID, SST_DEFAULT_MODULE_ID) + +struct sst_destination_id { + union sst_location_id { + struct { + u8 cell_nbr_idx; /* module index */ + u8 path_id; /* pipe_id */ + } __packed p; /* part */ + u16 f; /* full */ + } __packed location_id; + u16 module_id; +} __packed; +struct sst_dsp_header { + struct sst_destination_id dst; + u16 command_id; + u16 length; +} __packed; + +/* + * + * Common Commands + * + */ +struct sst_cmd_generic { + struct sst_dsp_header header; +} __packed; +struct sst_cmd_set_params { + struct sst_destination_id dst; + u16 command_id; + char params[0]; +} __packed; +#define SST_CONTROL_NAME(xpname, xmname, xinstance, xtype) \ + xpname " " xmname " " #xinstance " " xtype + +#define SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, xtype, xsubmodule) \ + xpname " " xmname " " #xinstance " " xtype " " xsubmodule +enum sst_algo_kcontrol_type { + SST_ALGO_PARAMS, + SST_ALGO_BYPASS, +}; + +struct sst_algo_control { + enum sst_algo_kcontrol_type type; + int max; + u16 module_id; + u16 pipe_id; + u16 task_id; + u16 cmd_id; + bool bypass; + unsigned char *params; + struct snd_soc_dapm_widget *w; +}; + +/* size of the control = size of params + size of length field */ +#define SST_ALGO_CTL_VALUE(xcount, xtype, xpipe, xmod, xtask, xcmd) \ + (struct sst_algo_control){ \ + .max = xcount + sizeof(u16), .type = xtype, .module_id = xmod, \ + .pipe_id = xpipe, .task_id = xtask, .cmd_id = xcmd, \ + } + +#define SST_ALGO_KCONTROL(xname, xcount, xmod, xpipe, \ + xtask, xcmd, xtype, xinfo, xget, xput) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .info = xinfo, .get = xget, .put = xput, \ + .private_value = (unsigned long)& \ + SST_ALGO_CTL_VALUE(xcount, xtype, xpipe, \ + xmod, xtask, xcmd), \ +} + +#define SST_ALGO_KCONTROL_BYTES(xpname, xmname, xcount, xmod, \ + xpipe, xinstance, xtask, xcmd) \ + SST_ALGO_KCONTROL(SST_CONTROL_NAME(xpname, xmname, xinstance, "params"), \ + xcount, xmod, xpipe, xtask, xcmd, SST_ALGO_PARAMS, \ + sst_algo_bytes_ctl_info, \ + sst_algo_control_get, sst_algo_control_set) + +#define SST_ALGO_KCONTROL_BOOL(xpname, xmname, xmod, xpipe, xinstance, xtask) \ + SST_ALGO_KCONTROL(SST_CONTROL_NAME(xpname, xmname, xinstance, "bypass"), \ + 0, xmod, xpipe, xtask, 0, SST_ALGO_BYPASS, \ + snd_soc_info_bool_ext, \ + sst_algo_control_get, sst_algo_control_set) + +#define SST_ALGO_BYPASS_PARAMS(xpname, xmname, xcount, xmod, xpipe, \ + xinstance, xtask, xcmd) \ + SST_ALGO_KCONTROL_BOOL(xpname, xmname, xmod, xpipe, xinstance, xtask), \ + SST_ALGO_KCONTROL_BYTES(xpname, xmname, xcount, xmod, xpipe, xinstance, xtask, xcmd) + +#define SST_COMBO_ALGO_KCONTROL_BYTES(xpname, xmname, xsubmod, xcount, xmod, \ + xpipe, xinstance, xtask, xcmd) \ + SST_ALGO_KCONTROL(SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, "params", \ + xsubmod), \ + xcount, xmod, xpipe, xtask, xcmd, SST_ALGO_PARAMS, \ + sst_algo_bytes_ctl_info, \ + sst_algo_control_get, sst_algo_control_set) + + +struct sst_enum { + bool tx; + unsigned short reg; + unsigned int max; + const char * const *texts; + struct snd_soc_dapm_widget *w; +}; + #endif