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