Commit | Line | Data |
---|---|---|
4b68b4e1 VK |
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 | ||
21 | #include <linux/slab.h> | |
22 | #include <linux/io.h> | |
23 | #include <linux/module.h> | |
24 | #include <sound/core.h> | |
25 | #include <sound/pcm.h> | |
26 | #include <sound/pcm_params.h> | |
27 | #include <sound/soc.h> | |
28 | #include <sound/compress_driver.h> | |
29 | #include "sst-mfld-platform.h" | |
30 | ||
31 | /* compress stream operations */ | |
32 | static void sst_compr_fragment_elapsed(void *arg) | |
33 | { | |
34 | struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg; | |
35 | ||
36 | pr_debug("fragment elapsed by driver\n"); | |
37 | if (cstream) | |
38 | snd_compr_fragment_elapsed(cstream); | |
39 | } | |
40 | ||
bd17aa45 VK |
41 | static void sst_drain_notify(void *arg) |
42 | { | |
43 | struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg; | |
44 | ||
45 | pr_debug("drain notify by driver\n"); | |
46 | if (cstream) | |
47 | snd_compr_drain_notify(cstream); | |
48 | } | |
49 | ||
4b68b4e1 VK |
50 | static int sst_platform_compr_open(struct snd_compr_stream *cstream) |
51 | { | |
52 | ||
53 | int ret_val = 0; | |
54 | struct snd_compr_runtime *runtime = cstream->runtime; | |
55 | struct sst_runtime_stream *stream; | |
56 | ||
57 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); | |
58 | if (!stream) | |
59 | return -ENOMEM; | |
60 | ||
61 | spin_lock_init(&stream->status_lock); | |
62 | ||
63 | /* get the sst ops */ | |
64 | if (!sst || !try_module_get(sst->dev->driver->owner)) { | |
65 | pr_err("no device available to run\n"); | |
66 | ret_val = -ENODEV; | |
67 | goto out_ops; | |
68 | } | |
69 | stream->compr_ops = sst->compr_ops; | |
70 | ||
71 | stream->id = 0; | |
72 | sst_set_stream_status(stream, SST_PLATFORM_INIT); | |
73 | runtime->private_data = stream; | |
74 | return 0; | |
75 | out_ops: | |
76 | kfree(stream); | |
77 | return ret_val; | |
78 | } | |
79 | ||
80 | static int sst_platform_compr_free(struct snd_compr_stream *cstream) | |
81 | { | |
82 | struct sst_runtime_stream *stream; | |
83 | int ret_val = 0, str_id; | |
84 | ||
85 | stream = cstream->runtime->private_data; | |
86 | /*need to check*/ | |
87 | str_id = stream->id; | |
88 | if (str_id) | |
89 | ret_val = stream->compr_ops->close(str_id); | |
90 | module_put(sst->dev->driver->owner); | |
91 | kfree(stream); | |
92 | pr_debug("%s: %d\n", __func__, ret_val); | |
93 | return 0; | |
94 | } | |
95 | ||
96 | static int sst_platform_compr_set_params(struct snd_compr_stream *cstream, | |
97 | struct snd_compr_params *params) | |
98 | { | |
99 | struct sst_runtime_stream *stream; | |
100 | int retval; | |
101 | struct snd_sst_params str_params; | |
102 | struct sst_compress_cb cb; | |
0ec66fed VK |
103 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; |
104 | struct snd_soc_platform *platform = rtd->platform; | |
105 | struct sst_data *ctx = snd_soc_platform_get_drvdata(platform); | |
4b68b4e1 VK |
106 | |
107 | stream = cstream->runtime->private_data; | |
108 | /* construct fw structure for this*/ | |
109 | memset(&str_params, 0, sizeof(str_params)); | |
110 | ||
0ec66fed VK |
111 | /* fill the device type and stream id to pass to SST driver */ |
112 | retval = sst_fill_stream_params(cstream, ctx, &str_params, true); | |
113 | pr_debug("compr_set_params: fill stream params ret_val = 0x%x\n", retval); | |
114 | if (retval < 0) | |
115 | return retval; | |
4b68b4e1 VK |
116 | |
117 | switch (params->codec.id) { | |
118 | case SND_AUDIOCODEC_MP3: { | |
119 | str_params.codec = SST_CODEC_TYPE_MP3; | |
4b68b4e1 VK |
120 | str_params.sparams.uc.mp3_params.num_chan = params->codec.ch_in; |
121 | str_params.sparams.uc.mp3_params.pcm_wd_sz = 16; | |
122 | break; | |
123 | } | |
124 | ||
125 | case SND_AUDIOCODEC_AAC: { | |
126 | str_params.codec = SST_CODEC_TYPE_AAC; | |
4b68b4e1 VK |
127 | str_params.sparams.uc.aac_params.num_chan = params->codec.ch_in; |
128 | str_params.sparams.uc.aac_params.pcm_wd_sz = 16; | |
129 | if (params->codec.format == SND_AUDIOSTREAMFORMAT_MP4ADTS) | |
130 | str_params.sparams.uc.aac_params.bs_format = | |
131 | AAC_BIT_STREAM_ADTS; | |
132 | else if (params->codec.format == SND_AUDIOSTREAMFORMAT_RAW) | |
133 | str_params.sparams.uc.aac_params.bs_format = | |
134 | AAC_BIT_STREAM_RAW; | |
135 | else { | |
136 | pr_err("Undefined format%d\n", params->codec.format); | |
137 | return -EINVAL; | |
138 | } | |
139 | str_params.sparams.uc.aac_params.externalsr = | |
140 | params->codec.sample_rate; | |
141 | break; | |
142 | } | |
143 | ||
144 | default: | |
145 | pr_err("codec not supported, id =%d\n", params->codec.id); | |
146 | return -EINVAL; | |
147 | } | |
148 | ||
149 | str_params.aparams.ring_buf_info[0].addr = | |
150 | virt_to_phys(cstream->runtime->buffer); | |
151 | str_params.aparams.ring_buf_info[0].size = | |
152 | cstream->runtime->buffer_size; | |
153 | str_params.aparams.sg_count = 1; | |
154 | str_params.aparams.frag_size = cstream->runtime->fragment_size; | |
155 | ||
156 | cb.param = cstream; | |
157 | cb.compr_cb = sst_compr_fragment_elapsed; | |
bd17aa45 VK |
158 | cb.drain_cb_param = cstream; |
159 | cb.drain_notify = sst_drain_notify; | |
4b68b4e1 VK |
160 | |
161 | retval = stream->compr_ops->open(&str_params, &cb); | |
162 | if (retval < 0) { | |
163 | pr_err("stream allocation failed %d\n", retval); | |
164 | return retval; | |
165 | } | |
166 | ||
167 | stream->id = retval; | |
168 | return 0; | |
169 | } | |
170 | ||
171 | static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd) | |
172 | { | |
173 | struct sst_runtime_stream *stream = | |
174 | cstream->runtime->private_data; | |
175 | ||
176 | return stream->compr_ops->control(cmd, stream->id); | |
177 | } | |
178 | ||
179 | static int sst_platform_compr_pointer(struct snd_compr_stream *cstream, | |
180 | struct snd_compr_tstamp *tstamp) | |
181 | { | |
182 | struct sst_runtime_stream *stream; | |
183 | ||
184 | stream = cstream->runtime->private_data; | |
185 | stream->compr_ops->tstamp(stream->id, tstamp); | |
186 | tstamp->byte_offset = tstamp->copied_total % | |
187 | (u32)cstream->runtime->buffer_size; | |
188 | pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset); | |
189 | return 0; | |
190 | } | |
191 | ||
192 | static int sst_platform_compr_ack(struct snd_compr_stream *cstream, | |
193 | size_t bytes) | |
194 | { | |
195 | struct sst_runtime_stream *stream; | |
196 | ||
197 | stream = cstream->runtime->private_data; | |
198 | stream->compr_ops->ack(stream->id, (unsigned long)bytes); | |
199 | stream->bytes_written += bytes; | |
200 | ||
201 | return 0; | |
202 | } | |
203 | ||
204 | static int sst_platform_compr_get_caps(struct snd_compr_stream *cstream, | |
205 | struct snd_compr_caps *caps) | |
206 | { | |
207 | struct sst_runtime_stream *stream = | |
208 | cstream->runtime->private_data; | |
209 | ||
210 | return stream->compr_ops->get_caps(caps); | |
211 | } | |
212 | ||
213 | static int sst_platform_compr_get_codec_caps(struct snd_compr_stream *cstream, | |
214 | struct snd_compr_codec_caps *codec) | |
215 | { | |
216 | struct sst_runtime_stream *stream = | |
217 | cstream->runtime->private_data; | |
218 | ||
219 | return stream->compr_ops->get_codec_caps(codec); | |
220 | } | |
221 | ||
222 | static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream, | |
223 | struct snd_compr_metadata *metadata) | |
224 | { | |
225 | struct sst_runtime_stream *stream = | |
226 | cstream->runtime->private_data; | |
227 | ||
228 | return stream->compr_ops->set_metadata(stream->id, metadata); | |
229 | } | |
230 | ||
231 | struct snd_compr_ops sst_platform_compr_ops = { | |
232 | ||
233 | .open = sst_platform_compr_open, | |
234 | .free = sst_platform_compr_free, | |
235 | .set_params = sst_platform_compr_set_params, | |
236 | .set_metadata = sst_platform_compr_set_metadata, | |
237 | .trigger = sst_platform_compr_trigger, | |
238 | .pointer = sst_platform_compr_pointer, | |
239 | .ack = sst_platform_compr_ack, | |
240 | .get_caps = sst_platform_compr_get_caps, | |
241 | .get_codec_caps = sst_platform_compr_get_codec_caps, | |
242 | }; |