PageRenderTime 25ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/sound/soc/intel/atom/sst-mfld-platform-compress.c

https://github.com/mturquette/linux
C | 268 lines | 203 code | 40 blank | 25 comment | 22 complexity | 85d6a8cc3781b7c3d5bb8cbb38a5918b MD5 | raw file
  1. /*
  2. * sst_mfld_platform.c - Intel MID Platform driver
  3. *
  4. * Copyright (C) 2010-2014 Intel Corp
  5. * Author: Vinod Koul <vinod.koul@intel.com>
  6. * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; version 2 of the License.
  11. *
  12. * This program is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * General Public License for more details.
  16. *
  17. * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  18. */
  19. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  20. #include <linux/slab.h>
  21. #include <linux/io.h>
  22. #include <linux/module.h>
  23. #include <sound/core.h>
  24. #include <sound/pcm.h>
  25. #include <sound/pcm_params.h>
  26. #include <sound/soc.h>
  27. #include <sound/compress_driver.h>
  28. #include "sst-mfld-platform.h"
  29. /* compress stream operations */
  30. static void sst_compr_fragment_elapsed(void *arg)
  31. {
  32. struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg;
  33. pr_debug("fragment elapsed by driver\n");
  34. if (cstream)
  35. snd_compr_fragment_elapsed(cstream);
  36. }
  37. static void sst_drain_notify(void *arg)
  38. {
  39. struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg;
  40. pr_debug("drain notify by driver\n");
  41. if (cstream)
  42. snd_compr_drain_notify(cstream);
  43. }
  44. static int sst_platform_compr_open(struct snd_compr_stream *cstream)
  45. {
  46. int ret_val = 0;
  47. struct snd_compr_runtime *runtime = cstream->runtime;
  48. struct sst_runtime_stream *stream;
  49. stream = kzalloc(sizeof(*stream), GFP_KERNEL);
  50. if (!stream)
  51. return -ENOMEM;
  52. spin_lock_init(&stream->status_lock);
  53. /* get the sst ops */
  54. if (!sst || !try_module_get(sst->dev->driver->owner)) {
  55. pr_err("no device available to run\n");
  56. ret_val = -ENODEV;
  57. goto out_ops;
  58. }
  59. stream->compr_ops = sst->compr_ops;
  60. stream->id = 0;
  61. /* Turn on LPE */
  62. sst->compr_ops->power(sst->dev, true);
  63. sst_set_stream_status(stream, SST_PLATFORM_INIT);
  64. runtime->private_data = stream;
  65. return 0;
  66. out_ops:
  67. kfree(stream);
  68. return ret_val;
  69. }
  70. static int sst_platform_compr_free(struct snd_compr_stream *cstream)
  71. {
  72. struct sst_runtime_stream *stream;
  73. int ret_val = 0, str_id;
  74. stream = cstream->runtime->private_data;
  75. /* Turn off LPE */
  76. sst->compr_ops->power(sst->dev, false);
  77. /*need to check*/
  78. str_id = stream->id;
  79. if (str_id)
  80. ret_val = stream->compr_ops->close(sst->dev, str_id);
  81. module_put(sst->dev->driver->owner);
  82. kfree(stream);
  83. pr_debug("%s: %d\n", __func__, ret_val);
  84. return 0;
  85. }
  86. static int sst_platform_compr_set_params(struct snd_compr_stream *cstream,
  87. struct snd_compr_params *params)
  88. {
  89. struct sst_runtime_stream *stream;
  90. int retval;
  91. struct snd_sst_params str_params;
  92. struct sst_compress_cb cb;
  93. struct snd_soc_pcm_runtime *rtd = cstream->private_data;
  94. struct snd_soc_platform *platform = rtd->platform;
  95. struct sst_data *ctx = snd_soc_platform_get_drvdata(platform);
  96. stream = cstream->runtime->private_data;
  97. /* construct fw structure for this*/
  98. memset(&str_params, 0, sizeof(str_params));
  99. /* fill the device type and stream id to pass to SST driver */
  100. retval = sst_fill_stream_params(cstream, ctx, &str_params, true);
  101. pr_debug("compr_set_params: fill stream params ret_val = 0x%x\n", retval);
  102. if (retval < 0)
  103. return retval;
  104. switch (params->codec.id) {
  105. case SND_AUDIOCODEC_MP3: {
  106. str_params.codec = SST_CODEC_TYPE_MP3;
  107. str_params.sparams.uc.mp3_params.num_chan = params->codec.ch_in;
  108. str_params.sparams.uc.mp3_params.pcm_wd_sz = 16;
  109. break;
  110. }
  111. case SND_AUDIOCODEC_AAC: {
  112. str_params.codec = SST_CODEC_TYPE_AAC;
  113. str_params.sparams.uc.aac_params.num_chan = params->codec.ch_in;
  114. str_params.sparams.uc.aac_params.pcm_wd_sz = 16;
  115. if (params->codec.format == SND_AUDIOSTREAMFORMAT_MP4ADTS)
  116. str_params.sparams.uc.aac_params.bs_format =
  117. AAC_BIT_STREAM_ADTS;
  118. else if (params->codec.format == SND_AUDIOSTREAMFORMAT_RAW)
  119. str_params.sparams.uc.aac_params.bs_format =
  120. AAC_BIT_STREAM_RAW;
  121. else {
  122. pr_err("Undefined format%d\n", params->codec.format);
  123. return -EINVAL;
  124. }
  125. str_params.sparams.uc.aac_params.externalsr =
  126. params->codec.sample_rate;
  127. break;
  128. }
  129. default:
  130. pr_err("codec not supported, id =%d\n", params->codec.id);
  131. return -EINVAL;
  132. }
  133. str_params.aparams.ring_buf_info[0].addr =
  134. virt_to_phys(cstream->runtime->buffer);
  135. str_params.aparams.ring_buf_info[0].size =
  136. cstream->runtime->buffer_size;
  137. str_params.aparams.sg_count = 1;
  138. str_params.aparams.frag_size = cstream->runtime->fragment_size;
  139. cb.param = cstream;
  140. cb.compr_cb = sst_compr_fragment_elapsed;
  141. cb.drain_cb_param = cstream;
  142. cb.drain_notify = sst_drain_notify;
  143. retval = stream->compr_ops->open(sst->dev, &str_params, &cb);
  144. if (retval < 0) {
  145. pr_err("stream allocation failed %d\n", retval);
  146. return retval;
  147. }
  148. stream->id = retval;
  149. return 0;
  150. }
  151. static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd)
  152. {
  153. struct sst_runtime_stream *stream = cstream->runtime->private_data;
  154. switch (cmd) {
  155. case SNDRV_PCM_TRIGGER_START:
  156. if (stream->compr_ops->stream_start)
  157. return stream->compr_ops->stream_start(sst->dev, stream->id);
  158. case SNDRV_PCM_TRIGGER_STOP:
  159. if (stream->compr_ops->stream_drop)
  160. return stream->compr_ops->stream_drop(sst->dev, stream->id);
  161. case SND_COMPR_TRIGGER_DRAIN:
  162. if (stream->compr_ops->stream_drain)
  163. return stream->compr_ops->stream_drain(sst->dev, stream->id);
  164. case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
  165. if (stream->compr_ops->stream_partial_drain)
  166. return stream->compr_ops->stream_partial_drain(sst->dev, stream->id);
  167. case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  168. if (stream->compr_ops->stream_pause)
  169. return stream->compr_ops->stream_pause(sst->dev, stream->id);
  170. case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  171. if (stream->compr_ops->stream_pause_release)
  172. return stream->compr_ops->stream_pause_release(sst->dev, stream->id);
  173. default:
  174. return -EINVAL;
  175. }
  176. }
  177. static int sst_platform_compr_pointer(struct snd_compr_stream *cstream,
  178. struct snd_compr_tstamp *tstamp)
  179. {
  180. struct sst_runtime_stream *stream;
  181. stream = cstream->runtime->private_data;
  182. stream->compr_ops->tstamp(sst->dev, stream->id, tstamp);
  183. tstamp->byte_offset = tstamp->copied_total %
  184. (u32)cstream->runtime->buffer_size;
  185. pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset);
  186. return 0;
  187. }
  188. static int sst_platform_compr_ack(struct snd_compr_stream *cstream,
  189. size_t bytes)
  190. {
  191. struct sst_runtime_stream *stream;
  192. stream = cstream->runtime->private_data;
  193. stream->compr_ops->ack(sst->dev, stream->id, (unsigned long)bytes);
  194. stream->bytes_written += bytes;
  195. return 0;
  196. }
  197. static int sst_platform_compr_get_caps(struct snd_compr_stream *cstream,
  198. struct snd_compr_caps *caps)
  199. {
  200. struct sst_runtime_stream *stream =
  201. cstream->runtime->private_data;
  202. return stream->compr_ops->get_caps(caps);
  203. }
  204. static int sst_platform_compr_get_codec_caps(struct snd_compr_stream *cstream,
  205. struct snd_compr_codec_caps *codec)
  206. {
  207. struct sst_runtime_stream *stream =
  208. cstream->runtime->private_data;
  209. return stream->compr_ops->get_codec_caps(codec);
  210. }
  211. static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream,
  212. struct snd_compr_metadata *metadata)
  213. {
  214. struct sst_runtime_stream *stream =
  215. cstream->runtime->private_data;
  216. return stream->compr_ops->set_metadata(sst->dev, stream->id, metadata);
  217. }
  218. struct snd_compr_ops sst_platform_compr_ops = {
  219. .open = sst_platform_compr_open,
  220. .free = sst_platform_compr_free,
  221. .set_params = sst_platform_compr_set_params,
  222. .set_metadata = sst_platform_compr_set_metadata,
  223. .trigger = sst_platform_compr_trigger,
  224. .pointer = sst_platform_compr_pointer,
  225. .ack = sst_platform_compr_ack,
  226. .get_caps = sst_platform_compr_get_caps,
  227. .get_codec_caps = sst_platform_compr_get_codec_caps,
  228. };