sst-atom-controls.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /*
  2. * sst-atom-controls.c - Intel MID Platform driver DPCM ALSA controls for Mrfld
  3. *
  4. * Copyright (C) 2013-14 Intel Corp
  5. * Author: Omair Mohammed Abdullah <omair.m.abdullah@intel.com>
  6. * Vinod Koul <vinod.koul@intel.com>
  7. * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; version 2 of the License.
  12. *
  13. * This program is distributed in the hope that it will be useful, but
  14. * WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * General Public License for more details.
  17. *
  18. * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  19. */
  20. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  21. #include <linux/slab.h>
  22. #include <sound/soc.h>
  23. #include <sound/tlv.h>
  24. #include "sst-mfld-platform.h"
  25. #include "sst-atom-controls.h"
  26. static int sst_fill_byte_control(struct sst_data *drv,
  27. u8 ipc_msg, u8 block,
  28. u8 task_id, u8 pipe_id,
  29. u16 len, void *cmd_data)
  30. {
  31. struct snd_sst_bytes_v2 *byte_data = drv->byte_stream;
  32. byte_data->type = SST_CMD_BYTES_SET;
  33. byte_data->ipc_msg = ipc_msg;
  34. byte_data->block = block;
  35. byte_data->task_id = task_id;
  36. byte_data->pipe_id = pipe_id;
  37. if (len > SST_MAX_BIN_BYTES - sizeof(*byte_data)) {
  38. dev_err(&drv->pdev->dev, "command length too big (%u)", len);
  39. return -EINVAL;
  40. }
  41. byte_data->len = len;
  42. memcpy(byte_data->bytes, cmd_data, len);
  43. print_hex_dump_bytes("writing to lpe: ", DUMP_PREFIX_OFFSET,
  44. byte_data, len + sizeof(*byte_data));
  45. return 0;
  46. }
  47. static int sst_fill_and_send_cmd_unlocked(struct sst_data *drv,
  48. u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id,
  49. void *cmd_data, u16 len)
  50. {
  51. int ret = 0;
  52. ret = sst_fill_byte_control(drv, ipc_msg,
  53. block, task_id, pipe_id, len, cmd_data);
  54. if (ret < 0)
  55. return ret;
  56. return sst->ops->send_byte_stream(sst->dev, drv->byte_stream);
  57. }
  58. /**
  59. * sst_fill_and_send_cmd - generate the IPC message and send it to the FW
  60. * @ipc_msg: type of IPC (CMD, SET_PARAMS, GET_PARAMS)
  61. * @cmd_data: the IPC payload
  62. */
  63. static int sst_fill_and_send_cmd(struct sst_data *drv,
  64. u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id,
  65. void *cmd_data, u16 len)
  66. {
  67. int ret;
  68. mutex_lock(&drv->lock);
  69. ret = sst_fill_and_send_cmd_unlocked(drv, ipc_msg, block,
  70. task_id, pipe_id, cmd_data, len);
  71. mutex_unlock(&drv->lock);
  72. return ret;
  73. }
  74. static int sst_send_algo_cmd(struct sst_data *drv,
  75. struct sst_algo_control *bc)
  76. {
  77. int len, ret = 0;
  78. struct sst_cmd_set_params *cmd;
  79. /*bc->max includes sizeof algos + length field*/
  80. len = sizeof(cmd->dst) + sizeof(cmd->command_id) + bc->max;
  81. cmd = kzalloc(len, GFP_KERNEL);
  82. if (cmd == NULL)
  83. return -ENOMEM;
  84. SST_FILL_DESTINATION(2, cmd->dst, bc->pipe_id, bc->module_id);
  85. cmd->command_id = bc->cmd_id;
  86. memcpy(cmd->params, bc->params, bc->max);
  87. ret = sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_SET_PARAMS,
  88. SST_FLAG_BLOCKED, bc->task_id, 0, cmd, len);
  89. kfree(cmd);
  90. return ret;
  91. }
  92. static int sst_algo_bytes_ctl_info(struct snd_kcontrol *kcontrol,
  93. struct snd_ctl_elem_info *uinfo)
  94. {
  95. struct sst_algo_control *bc = (void *)kcontrol->private_value;
  96. uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
  97. uinfo->count = bc->max;
  98. return 0;
  99. }
  100. static int sst_algo_control_get(struct snd_kcontrol *kcontrol,
  101. struct snd_ctl_elem_value *ucontrol)
  102. {
  103. struct sst_algo_control *bc = (void *)kcontrol->private_value;
  104. struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
  105. switch (bc->type) {
  106. case SST_ALGO_PARAMS:
  107. memcpy(ucontrol->value.bytes.data, bc->params, bc->max);
  108. break;
  109. default:
  110. dev_err(component->dev, "Invalid Input- algo type:%d\n",
  111. bc->type);
  112. return -EINVAL;
  113. }
  114. return 0;
  115. }
  116. static int sst_algo_control_set(struct snd_kcontrol *kcontrol,
  117. struct snd_ctl_elem_value *ucontrol)
  118. {
  119. int ret = 0;
  120. struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
  121. struct sst_data *drv = snd_soc_component_get_drvdata(cmpnt);
  122. struct sst_algo_control *bc = (void *)kcontrol->private_value;
  123. dev_dbg(cmpnt->dev, "control_name=%s\n", kcontrol->id.name);
  124. mutex_lock(&drv->lock);
  125. switch (bc->type) {
  126. case SST_ALGO_PARAMS:
  127. memcpy(bc->params, ucontrol->value.bytes.data, bc->max);
  128. break;
  129. default:
  130. mutex_unlock(&drv->lock);
  131. dev_err(cmpnt->dev, "Invalid Input- algo type:%d\n",
  132. bc->type);
  133. return -EINVAL;
  134. }
  135. /*if pipe is enabled, need to send the algo params from here*/
  136. if (bc->w && bc->w->power)
  137. ret = sst_send_algo_cmd(drv, bc);
  138. mutex_unlock(&drv->lock);
  139. return ret;
  140. }
  141. static const struct snd_kcontrol_new sst_algo_controls[] = {
  142. SST_ALGO_KCONTROL_BYTES("media_loop1_out", "fir", 272, SST_MODULE_ID_FIR_24,
  143. SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR),
  144. SST_ALGO_KCONTROL_BYTES("media_loop1_out", "iir", 300, SST_MODULE_ID_IIR_24,
  145. SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
  146. SST_ALGO_KCONTROL_BYTES("media_loop1_out", "mdrp", 286, SST_MODULE_ID_MDRP,
  147. SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_SET_MDRP),
  148. SST_ALGO_KCONTROL_BYTES("media_loop2_out", "fir", 272, SST_MODULE_ID_FIR_24,
  149. SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR),
  150. SST_ALGO_KCONTROL_BYTES("media_loop2_out", "iir", 300, SST_MODULE_ID_IIR_24,
  151. SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
  152. SST_ALGO_KCONTROL_BYTES("media_loop2_out", "mdrp", 286, SST_MODULE_ID_MDRP,
  153. SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_SET_MDRP),
  154. SST_ALGO_KCONTROL_BYTES("sprot_loop_out", "lpro", 192, SST_MODULE_ID_SPROT,
  155. SST_PATH_INDEX_SPROT_LOOP_OUT, 0, SST_TASK_SBA, SBA_VB_LPRO),
  156. SST_ALGO_KCONTROL_BYTES("codec_in0", "dcr", 52, SST_MODULE_ID_FILT_DCR,
  157. SST_PATH_INDEX_CODEC_IN0, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
  158. SST_ALGO_KCONTROL_BYTES("codec_in1", "dcr", 52, SST_MODULE_ID_FILT_DCR,
  159. SST_PATH_INDEX_CODEC_IN1, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
  160. };
  161. static int sst_algo_control_init(struct device *dev)
  162. {
  163. int i = 0;
  164. struct sst_algo_control *bc;
  165. /*allocate space to cache the algo parameters in the driver*/
  166. for (i = 0; i < ARRAY_SIZE(sst_algo_controls); i++) {
  167. bc = (struct sst_algo_control *)sst_algo_controls[i].private_value;
  168. bc->params = devm_kzalloc(dev, bc->max, GFP_KERNEL);
  169. if (bc->params == NULL)
  170. return -ENOMEM;
  171. }
  172. return 0;
  173. }
  174. int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform)
  175. {
  176. int ret = 0;
  177. struct sst_data *drv = snd_soc_platform_get_drvdata(platform);
  178. drv->byte_stream = devm_kzalloc(platform->dev,
  179. SST_MAX_BIN_BYTES, GFP_KERNEL);
  180. if (!drv->byte_stream)
  181. return -ENOMEM;
  182. /*Initialize algo control params*/
  183. ret = sst_algo_control_init(platform->dev);
  184. if (ret)
  185. return ret;
  186. ret = snd_soc_add_platform_controls(platform, sst_algo_controls,
  187. ARRAY_SIZE(sst_algo_controls));
  188. return ret;
  189. }