xref: /openbmc/linux/sound/soc/intel/atom/sst-mfld-platform-compress.c (revision cbecf716ca618fd44feda6bd9a64a8179d031fc5)
18e8e69d6SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2b97169daSJie Yang /*
3b97169daSJie Yang  *  sst_mfld_platform.c - Intel MID Platform driver
4b97169daSJie Yang  *
5b97169daSJie Yang  *  Copyright (C) 2010-2014 Intel Corp
6b97169daSJie Yang  *  Author: Vinod Koul <vinod.koul@intel.com>
7b97169daSJie Yang  *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8b97169daSJie Yang  *
9b97169daSJie Yang  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10b97169daSJie Yang  */
11b97169daSJie Yang #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12b97169daSJie Yang 
13b97169daSJie Yang #include <linux/slab.h>
14b97169daSJie Yang #include <linux/io.h>
15b97169daSJie Yang #include <linux/module.h>
16b97169daSJie Yang #include <sound/core.h>
17b97169daSJie Yang #include <sound/pcm.h>
18b97169daSJie Yang #include <sound/pcm_params.h>
19b97169daSJie Yang #include <sound/soc.h>
20b97169daSJie Yang #include <sound/compress_driver.h>
21b97169daSJie Yang #include "sst-mfld-platform.h"
22b97169daSJie Yang 
23b97169daSJie Yang /* compress stream operations */
sst_compr_fragment_elapsed(void * arg)24b97169daSJie Yang static void sst_compr_fragment_elapsed(void *arg)
25b97169daSJie Yang {
26b97169daSJie Yang 	struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg;
27b97169daSJie Yang 
28b97169daSJie Yang 	pr_debug("fragment elapsed by driver\n");
29b97169daSJie Yang 	if (cstream)
30b97169daSJie Yang 		snd_compr_fragment_elapsed(cstream);
31b97169daSJie Yang }
32b97169daSJie Yang 
sst_drain_notify(void * arg)33b97169daSJie Yang static void sst_drain_notify(void *arg)
34b97169daSJie Yang {
35b97169daSJie Yang 	struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg;
36b97169daSJie Yang 
37b97169daSJie Yang 	pr_debug("drain notify by driver\n");
38b97169daSJie Yang 	if (cstream)
39b97169daSJie Yang 		snd_compr_drain_notify(cstream);
40b97169daSJie Yang }
41b97169daSJie Yang 
sst_platform_compr_open(struct snd_soc_component * component,struct snd_compr_stream * cstream)42c60e4459SKuninori Morimoto static int sst_platform_compr_open(struct snd_soc_component *component,
43c60e4459SKuninori Morimoto 				   struct snd_compr_stream *cstream)
44b97169daSJie Yang {
45*b0a2a93dSPierre-Louis Bossart 	int ret_val;
46b97169daSJie Yang 	struct snd_compr_runtime *runtime = cstream->runtime;
47b97169daSJie Yang 	struct sst_runtime_stream *stream;
48b97169daSJie Yang 
49b97169daSJie Yang 	stream = kzalloc(sizeof(*stream), GFP_KERNEL);
50b97169daSJie Yang 	if (!stream)
51b97169daSJie Yang 		return -ENOMEM;
52b97169daSJie Yang 
53b97169daSJie Yang 	spin_lock_init(&stream->status_lock);
54b97169daSJie Yang 
55b97169daSJie Yang 	/* get the sst ops */
56b97169daSJie Yang 	if (!sst || !try_module_get(sst->dev->driver->owner)) {
57b97169daSJie Yang 		pr_err("no device available to run\n");
58b97169daSJie Yang 		ret_val = -ENODEV;
59b97169daSJie Yang 		goto out_ops;
60b97169daSJie Yang 	}
61b97169daSJie Yang 	stream->compr_ops = sst->compr_ops;
62b97169daSJie Yang 	stream->id = 0;
63b97169daSJie Yang 
64b97169daSJie Yang 	/* Turn on LPE */
65b97169daSJie Yang 	sst->compr_ops->power(sst->dev, true);
66b97169daSJie Yang 
67b97169daSJie Yang 	sst_set_stream_status(stream, SST_PLATFORM_INIT);
68b97169daSJie Yang 	runtime->private_data = stream;
69b97169daSJie Yang 	return 0;
70b97169daSJie Yang out_ops:
71b97169daSJie Yang 	kfree(stream);
72b97169daSJie Yang 	return ret_val;
73b97169daSJie Yang }
74b97169daSJie Yang 
sst_platform_compr_free(struct snd_soc_component * component,struct snd_compr_stream * cstream)75c60e4459SKuninori Morimoto static int sst_platform_compr_free(struct snd_soc_component *component,
76c60e4459SKuninori Morimoto 				   struct snd_compr_stream *cstream)
77b97169daSJie Yang {
78b97169daSJie Yang 	struct sst_runtime_stream *stream;
79b97169daSJie Yang 	int ret_val = 0, str_id;
80b97169daSJie Yang 
81b97169daSJie Yang 	stream = cstream->runtime->private_data;
82b97169daSJie Yang 	/* Turn off LPE */
83b97169daSJie Yang 	sst->compr_ops->power(sst->dev, false);
84b97169daSJie Yang 
85b97169daSJie Yang 	/*need to check*/
86b97169daSJie Yang 	str_id = stream->id;
87b97169daSJie Yang 	if (str_id)
88b97169daSJie Yang 		ret_val = stream->compr_ops->close(sst->dev, str_id);
89b97169daSJie Yang 	module_put(sst->dev->driver->owner);
90b97169daSJie Yang 	kfree(stream);
91b97169daSJie Yang 	pr_debug("%s: %d\n", __func__, ret_val);
92b97169daSJie Yang 	return 0;
93b97169daSJie Yang }
94b97169daSJie Yang 
sst_platform_compr_set_params(struct snd_soc_component * component,struct snd_compr_stream * cstream,struct snd_compr_params * params)95c60e4459SKuninori Morimoto static int sst_platform_compr_set_params(struct snd_soc_component *component,
96c60e4459SKuninori Morimoto 					 struct snd_compr_stream *cstream,
97b97169daSJie Yang 					 struct snd_compr_params *params)
98b97169daSJie Yang {
99b97169daSJie Yang 	struct sst_runtime_stream *stream;
100b97169daSJie Yang 	int retval;
101b97169daSJie Yang 	struct snd_sst_params str_params;
102b97169daSJie Yang 	struct sst_compress_cb cb;
1036840962bSKuninori Morimoto 	struct sst_data *ctx = snd_soc_component_get_drvdata(component);
104b97169daSJie Yang 
105b97169daSJie Yang 	stream = cstream->runtime->private_data;
106b97169daSJie Yang 	/* construct fw structure for this*/
107b97169daSJie Yang 	memset(&str_params, 0, sizeof(str_params));
108b97169daSJie Yang 
109b97169daSJie Yang 	/* fill the device type and stream id to pass to SST driver */
110b97169daSJie Yang 	retval = sst_fill_stream_params(cstream, ctx, &str_params, true);
111b97169daSJie Yang 	pr_debug("compr_set_params: fill stream params ret_val = 0x%x\n", retval);
112b97169daSJie Yang 	if (retval < 0)
113b97169daSJie Yang 		return retval;
114b97169daSJie Yang 
115b97169daSJie Yang 	switch (params->codec.id) {
116b97169daSJie Yang 	case SND_AUDIOCODEC_MP3: {
117b97169daSJie Yang 		str_params.codec = SST_CODEC_TYPE_MP3;
118b97169daSJie Yang 		str_params.sparams.uc.mp3_params.num_chan = params->codec.ch_in;
119b97169daSJie Yang 		str_params.sparams.uc.mp3_params.pcm_wd_sz = 16;
120b97169daSJie Yang 		break;
121b97169daSJie Yang 	}
122b97169daSJie Yang 
123b97169daSJie Yang 	case SND_AUDIOCODEC_AAC: {
124b97169daSJie Yang 		str_params.codec = SST_CODEC_TYPE_AAC;
125b97169daSJie Yang 		str_params.sparams.uc.aac_params.num_chan = params->codec.ch_in;
126b97169daSJie Yang 		str_params.sparams.uc.aac_params.pcm_wd_sz = 16;
127b97169daSJie Yang 		if (params->codec.format == SND_AUDIOSTREAMFORMAT_MP4ADTS)
128b97169daSJie Yang 			str_params.sparams.uc.aac_params.bs_format =
129b97169daSJie Yang 							AAC_BIT_STREAM_ADTS;
130b97169daSJie Yang 		else if (params->codec.format == SND_AUDIOSTREAMFORMAT_RAW)
131b97169daSJie Yang 			str_params.sparams.uc.aac_params.bs_format =
132b97169daSJie Yang 							AAC_BIT_STREAM_RAW;
133b97169daSJie Yang 		else {
134b97169daSJie Yang 			pr_err("Undefined format%d\n", params->codec.format);
135b97169daSJie Yang 			return -EINVAL;
136b97169daSJie Yang 		}
137b97169daSJie Yang 		str_params.sparams.uc.aac_params.externalsr =
138b97169daSJie Yang 						params->codec.sample_rate;
139b97169daSJie Yang 		break;
140b97169daSJie Yang 	}
141b97169daSJie Yang 
142b97169daSJie Yang 	default:
143b97169daSJie Yang 		pr_err("codec not supported, id =%d\n", params->codec.id);
144b97169daSJie Yang 		return -EINVAL;
145b97169daSJie Yang 	}
146b97169daSJie Yang 
147b97169daSJie Yang 	str_params.aparams.ring_buf_info[0].addr  =
148b97169daSJie Yang 					virt_to_phys(cstream->runtime->buffer);
149b97169daSJie Yang 	str_params.aparams.ring_buf_info[0].size =
150b97169daSJie Yang 					cstream->runtime->buffer_size;
151b97169daSJie Yang 	str_params.aparams.sg_count = 1;
152b97169daSJie Yang 	str_params.aparams.frag_size = cstream->runtime->fragment_size;
153b97169daSJie Yang 
154b97169daSJie Yang 	cb.param = cstream;
155b97169daSJie Yang 	cb.compr_cb = sst_compr_fragment_elapsed;
156b97169daSJie Yang 	cb.drain_cb_param = cstream;
157b97169daSJie Yang 	cb.drain_notify = sst_drain_notify;
158b97169daSJie Yang 
159b97169daSJie Yang 	retval = stream->compr_ops->open(sst->dev, &str_params, &cb);
160b97169daSJie Yang 	if (retval < 0) {
161b97169daSJie Yang 		pr_err("stream allocation failed %d\n", retval);
162b97169daSJie Yang 		return retval;
163b97169daSJie Yang 	}
164b97169daSJie Yang 
165b97169daSJie Yang 	stream->id = retval;
166b97169daSJie Yang 	return 0;
167b97169daSJie Yang }
168b97169daSJie Yang 
sst_platform_compr_trigger(struct snd_soc_component * component,struct snd_compr_stream * cstream,int cmd)169c60e4459SKuninori Morimoto static int sst_platform_compr_trigger(struct snd_soc_component *component,
170c60e4459SKuninori Morimoto 				      struct snd_compr_stream *cstream, int cmd)
171b97169daSJie Yang {
172b97169daSJie Yang 	struct sst_runtime_stream *stream = cstream->runtime->private_data;
173b97169daSJie Yang 
174b97169daSJie Yang 	switch (cmd) {
175b97169daSJie Yang 	case SNDRV_PCM_TRIGGER_START:
176b97169daSJie Yang 		if (stream->compr_ops->stream_start)
177b97169daSJie Yang 			return stream->compr_ops->stream_start(sst->dev, stream->id);
17818f58399SAlan Cox 		break;
179b97169daSJie Yang 	case SNDRV_PCM_TRIGGER_STOP:
180b97169daSJie Yang 		if (stream->compr_ops->stream_drop)
181b97169daSJie Yang 			return stream->compr_ops->stream_drop(sst->dev, stream->id);
18218f58399SAlan Cox 		break;
183b97169daSJie Yang 	case SND_COMPR_TRIGGER_DRAIN:
184b97169daSJie Yang 		if (stream->compr_ops->stream_drain)
185b97169daSJie Yang 			return stream->compr_ops->stream_drain(sst->dev, stream->id);
18618f58399SAlan Cox 		break;
187b97169daSJie Yang 	case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
188b97169daSJie Yang 		if (stream->compr_ops->stream_partial_drain)
189b97169daSJie Yang 			return stream->compr_ops->stream_partial_drain(sst->dev, stream->id);
19018f58399SAlan Cox 		break;
191b97169daSJie Yang 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
192b97169daSJie Yang 		if (stream->compr_ops->stream_pause)
193b97169daSJie Yang 			return stream->compr_ops->stream_pause(sst->dev, stream->id);
19418f58399SAlan Cox 		break;
195b97169daSJie Yang 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
196b97169daSJie Yang 		if (stream->compr_ops->stream_pause_release)
197b97169daSJie Yang 			return stream->compr_ops->stream_pause_release(sst->dev, stream->id);
19818f58399SAlan Cox 		break;
199b97169daSJie Yang 	}
20018f58399SAlan Cox 	return -EINVAL;
201b97169daSJie Yang }
202b97169daSJie Yang 
sst_platform_compr_pointer(struct snd_soc_component * component,struct snd_compr_stream * cstream,struct snd_compr_tstamp * tstamp)203c60e4459SKuninori Morimoto static int sst_platform_compr_pointer(struct snd_soc_component *component,
204c60e4459SKuninori Morimoto 				      struct snd_compr_stream *cstream,
205b97169daSJie Yang 				      struct snd_compr_tstamp *tstamp)
206b97169daSJie Yang {
207b97169daSJie Yang 	struct sst_runtime_stream *stream;
208b97169daSJie Yang 
209b97169daSJie Yang 	stream  = cstream->runtime->private_data;
210b97169daSJie Yang 	stream->compr_ops->tstamp(sst->dev, stream->id, tstamp);
211b97169daSJie Yang 	tstamp->byte_offset = tstamp->copied_total %
212b97169daSJie Yang 				 (u32)cstream->runtime->buffer_size;
213b97169daSJie Yang 	pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset);
214b97169daSJie Yang 	return 0;
215b97169daSJie Yang }
216b97169daSJie Yang 
sst_platform_compr_ack(struct snd_soc_component * component,struct snd_compr_stream * cstream,size_t bytes)217c60e4459SKuninori Morimoto static int sst_platform_compr_ack(struct snd_soc_component *component,
218c60e4459SKuninori Morimoto 				  struct snd_compr_stream *cstream,
219b97169daSJie Yang 				  size_t bytes)
220b97169daSJie Yang {
221b97169daSJie Yang 	struct sst_runtime_stream *stream;
222b97169daSJie Yang 
223b97169daSJie Yang 	stream  = cstream->runtime->private_data;
224b97169daSJie Yang 	stream->compr_ops->ack(sst->dev, stream->id, (unsigned long)bytes);
225b97169daSJie Yang 	stream->bytes_written += bytes;
226b97169daSJie Yang 
227b97169daSJie Yang 	return 0;
228b97169daSJie Yang }
229b97169daSJie Yang 
sst_platform_compr_get_caps(struct snd_soc_component * component,struct snd_compr_stream * cstream,struct snd_compr_caps * caps)230c60e4459SKuninori Morimoto static int sst_platform_compr_get_caps(struct snd_soc_component *component,
231c60e4459SKuninori Morimoto 				       struct snd_compr_stream *cstream,
232b97169daSJie Yang 				       struct snd_compr_caps *caps)
233b97169daSJie Yang {
234b97169daSJie Yang 	struct sst_runtime_stream *stream =
235b97169daSJie Yang 		cstream->runtime->private_data;
236b97169daSJie Yang 
237b97169daSJie Yang 	return stream->compr_ops->get_caps(caps);
238b97169daSJie Yang }
239b97169daSJie Yang 
sst_platform_compr_get_codec_caps(struct snd_soc_component * component,struct snd_compr_stream * cstream,struct snd_compr_codec_caps * codec)240c60e4459SKuninori Morimoto static int sst_platform_compr_get_codec_caps(struct snd_soc_component *component,
241c60e4459SKuninori Morimoto 					     struct snd_compr_stream *cstream,
242b97169daSJie Yang 					     struct snd_compr_codec_caps *codec)
243b97169daSJie Yang {
244b97169daSJie Yang 	struct sst_runtime_stream *stream =
245b97169daSJie Yang 		cstream->runtime->private_data;
246b97169daSJie Yang 
247b97169daSJie Yang 	return stream->compr_ops->get_codec_caps(codec);
248b97169daSJie Yang }
249b97169daSJie Yang 
sst_platform_compr_set_metadata(struct snd_soc_component * component,struct snd_compr_stream * cstream,struct snd_compr_metadata * metadata)250c60e4459SKuninori Morimoto static int sst_platform_compr_set_metadata(struct snd_soc_component *component,
251c60e4459SKuninori Morimoto 					   struct snd_compr_stream *cstream,
252b97169daSJie Yang 					   struct snd_compr_metadata *metadata)
253b97169daSJie Yang {
254b97169daSJie Yang 	struct sst_runtime_stream *stream  =
255b97169daSJie Yang 		 cstream->runtime->private_data;
256b97169daSJie Yang 
257b97169daSJie Yang 	return stream->compr_ops->set_metadata(sst->dev, stream->id, metadata);
258b97169daSJie Yang }
259b97169daSJie Yang 
260c60e4459SKuninori Morimoto const struct snd_compress_ops sst_platform_compress_ops = {
261b97169daSJie Yang 
262b97169daSJie Yang 	.open = sst_platform_compr_open,
263b97169daSJie Yang 	.free = sst_platform_compr_free,
264b97169daSJie Yang 	.set_params = sst_platform_compr_set_params,
265b97169daSJie Yang 	.set_metadata = sst_platform_compr_set_metadata,
266b97169daSJie Yang 	.trigger = sst_platform_compr_trigger,
267b97169daSJie Yang 	.pointer = sst_platform_compr_pointer,
268b97169daSJie Yang 	.ack = sst_platform_compr_ack,
269b97169daSJie Yang 	.get_caps = sst_platform_compr_get_caps,
270b97169daSJie Yang 	.get_codec_caps = sst_platform_compr_get_codec_caps,
271b97169daSJie Yang };
272