ASoC: compress - fix code alignment
[firefly-linux-kernel-4.4.55.git] / sound / soc / soc-compress.c
1 /*
2  * soc-compress.c  --  ALSA SoC Compress
3  *
4  * Copyright (C) 2012 Intel Corp.
5  *
6  * Authors: Namarta Kohli <namartax.kohli@intel.com>
7  *          Ramesh Babu K V <ramesh.babu@linux.intel.com>
8  *          Vinod Koul <vinod.koul@linux.intel.com>
9  *
10  *  This program is free software; you can redistribute  it and/or modify it
11  *  under  the terms of  the GNU General  Public License as published by the
12  *  Free Software Foundation;  either version 2 of the  License, or (at your
13  *  option) any later version.
14  *
15  */
16
17 #include <linux/kernel.h>
18 #include <linux/init.h>
19 #include <linux/delay.h>
20 #include <linux/slab.h>
21 #include <linux/workqueue.h>
22 #include <sound/core.h>
23 #include <sound/compress_params.h>
24 #include <sound/compress_driver.h>
25 #include <sound/soc.h>
26 #include <sound/initval.h>
27
28 static int soc_compr_open(struct snd_compr_stream *cstream)
29 {
30         struct snd_soc_pcm_runtime *rtd = cstream->private_data;
31         struct snd_soc_platform *platform = rtd->platform;
32         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
33         struct snd_soc_dai *codec_dai = rtd->codec_dai;
34         int ret = 0;
35
36         if (platform->driver->compr_ops && platform->driver->compr_ops->open) {
37                 ret = platform->driver->compr_ops->open(cstream);
38                 if (ret < 0) {
39                         pr_err("compress asoc: can't open platform %s\n", platform->name);
40                         goto out;
41                 }
42         }
43
44         if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->startup) {
45                 ret = rtd->dai_link->compr_ops->startup(cstream);
46                 if (ret < 0) {
47                         pr_err("compress asoc: %s startup failed\n", rtd->dai_link->name);
48                         goto machine_err;
49                 }
50         }
51
52         if (cstream->direction == SND_COMPRESS_PLAYBACK) {
53                 cpu_dai->playback_active++;
54                 codec_dai->playback_active++;
55         } else {
56                 cpu_dai->capture_active++;
57                 codec_dai->capture_active++;
58         }
59
60         cpu_dai->active++;
61         codec_dai->active++;
62         rtd->codec->active++;
63
64         return 0;
65
66 machine_err:
67         if (platform->driver->compr_ops && platform->driver->compr_ops->free)
68                 platform->driver->compr_ops->free(cstream);
69 out:
70         return ret;
71 }
72
73 static int soc_compr_free(struct snd_compr_stream *cstream)
74 {
75         struct snd_soc_pcm_runtime *rtd = cstream->private_data;
76         struct snd_soc_platform *platform = rtd->platform;
77         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
78         struct snd_soc_dai *codec_dai = rtd->codec_dai;
79         struct snd_soc_codec *codec = rtd->codec;
80
81         if (cstream->direction == SND_COMPRESS_PLAYBACK) {
82                 cpu_dai->playback_active--;
83                 codec_dai->playback_active--;
84         } else {
85                 cpu_dai->capture_active--;
86                 codec_dai->capture_active--;
87         }
88
89         snd_soc_dai_digital_mute(codec_dai, 1);
90
91         cpu_dai->active--;
92         codec_dai->active--;
93         codec->active--;
94
95         if (!cpu_dai->active)
96                 cpu_dai->rate = 0;
97
98         if (!codec_dai->active)
99                 codec_dai->rate = 0;
100
101
102         if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->shutdown)
103                 rtd->dai_link->compr_ops->shutdown(cstream);
104
105         if (platform->driver->compr_ops && platform->driver->compr_ops->free)
106                 platform->driver->compr_ops->free(cstream);
107         cpu_dai->runtime = NULL;
108
109         if (cstream->direction == SND_COMPRESS_PLAYBACK) {
110                 if (!rtd->pmdown_time || codec->ignore_pmdown_time ||
111                     rtd->dai_link->ignore_pmdown_time) {
112                         snd_soc_dapm_stream_event(rtd,
113                                         SNDRV_PCM_STREAM_PLAYBACK,
114                                         SND_SOC_DAPM_STREAM_STOP);
115                 } else
116                         codec_dai->pop_wait = 1;
117                         schedule_delayed_work(&rtd->delayed_work,
118                                 msecs_to_jiffies(rtd->pmdown_time));
119         } else {
120                 /* capture streams can be powered down now */
121                 snd_soc_dapm_stream_event(rtd,
122                         SNDRV_PCM_STREAM_CAPTURE,
123                         SND_SOC_DAPM_STREAM_STOP);
124         }
125
126         return 0;
127 }
128
129 static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
130 {
131
132         struct snd_soc_pcm_runtime *rtd = cstream->private_data;
133         struct snd_soc_platform *platform = rtd->platform;
134         struct snd_soc_dai *codec_dai = rtd->codec_dai;
135         int ret = 0;
136
137         if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
138                 ret = platform->driver->compr_ops->trigger(cstream, cmd);
139                 if (ret < 0)
140                         return ret;
141         }
142
143         if (cmd == SNDRV_PCM_TRIGGER_START)
144                 snd_soc_dai_digital_mute(codec_dai, 0);
145         else if (cmd == SNDRV_PCM_TRIGGER_STOP)
146                 snd_soc_dai_digital_mute(codec_dai, 1);
147
148         return ret;
149 }
150
151 static int soc_compr_set_params(struct snd_compr_stream *cstream,
152                                         struct snd_compr_params *params)
153 {
154         struct snd_soc_pcm_runtime *rtd = cstream->private_data;
155         struct snd_soc_platform *platform = rtd->platform;
156         struct snd_soc_dai *codec_dai = rtd->codec_dai;
157         int ret = 0;
158
159         /* first we call set_params for the platform driver
160          * this should configure the soc side
161          * if the machine has compressed ops then we call that as well
162          * expectation is that platform and machine will configure everything
163          * for this compress path, like configuring pcm port for codec
164          */
165         if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
166                 ret = platform->driver->compr_ops->set_params(cstream, params);
167                 if (ret < 0)
168                         return ret;
169         }
170
171         if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) {
172                 ret = rtd->dai_link->compr_ops->set_params(cstream);
173                 if (ret < 0)
174                         return ret;
175         }
176
177         snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
178                                 SND_SOC_DAPM_STREAM_START);
179
180         return ret;
181 }
182
183 static int soc_compr_get_params(struct snd_compr_stream *cstream,
184                                         struct snd_codec *params)
185 {
186         struct snd_soc_pcm_runtime *rtd = cstream->private_data;
187         struct snd_soc_platform *platform = rtd->platform;
188         int ret = 0;
189
190         if (platform->driver->compr_ops && platform->driver->compr_ops->get_params)
191                 ret = platform->driver->compr_ops->get_params(cstream, params);
192
193         return ret;
194 }
195
196 static int soc_compr_get_caps(struct snd_compr_stream *cstream,
197                                 struct snd_compr_caps *caps)
198 {
199         struct snd_soc_pcm_runtime *rtd = cstream->private_data;
200         struct snd_soc_platform *platform = rtd->platform;
201         int ret = 0;
202
203         if (platform->driver->compr_ops && platform->driver->compr_ops->get_caps)
204                 ret = platform->driver->compr_ops->get_caps(cstream, caps);
205
206         return ret;
207 }
208
209 static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream,
210                                 struct snd_compr_codec_caps *codec)
211 {
212         struct snd_soc_pcm_runtime *rtd = cstream->private_data;
213         struct snd_soc_platform *platform = rtd->platform;
214         int ret = 0;
215
216         if (platform->driver->compr_ops && platform->driver->compr_ops->get_codec_caps)
217                 ret = platform->driver->compr_ops->get_codec_caps(cstream, codec);
218
219         return ret;
220 }
221
222 static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
223 {
224         struct snd_soc_pcm_runtime *rtd = cstream->private_data;
225         struct snd_soc_platform *platform = rtd->platform;
226         int ret = 0;
227
228         if (platform->driver->compr_ops && platform->driver->compr_ops->ack)
229                 ret = platform->driver->compr_ops->ack(cstream, bytes);
230
231         return ret;
232 }
233
234 static int soc_compr_pointer(struct snd_compr_stream *cstream,
235                         struct snd_compr_tstamp *tstamp)
236 {
237         struct snd_soc_pcm_runtime *rtd = cstream->private_data;
238         struct snd_soc_platform *platform = rtd->platform;
239
240         if (platform->driver->compr_ops && platform->driver->compr_ops->pointer)
241                  platform->driver->compr_ops->pointer(cstream, tstamp);
242
243         return 0;
244 }
245
246 /* ASoC Compress operations */
247 static struct snd_compr_ops soc_compr_ops = {
248         .open           = soc_compr_open,
249         .free           = soc_compr_free,
250         .set_params     = soc_compr_set_params,
251         .get_params     = soc_compr_get_params,
252         .trigger        = soc_compr_trigger,
253         .pointer        = soc_compr_pointer,
254         .ack            = soc_compr_ack,
255         .get_caps       = soc_compr_get_caps,
256         .get_codec_caps = soc_compr_get_codec_caps
257 };
258
259 /* create a new compress */
260 int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
261 {
262         struct snd_soc_codec *codec = rtd->codec;
263         struct snd_soc_dai *codec_dai = rtd->codec_dai;
264         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
265         struct snd_compr *compr;
266         char new_name[64];
267         int ret = 0, direction = 0;
268
269         /* check client and interface hw capabilities */
270         snprintf(new_name, sizeof(new_name), "%s %s-%d",
271                         rtd->dai_link->stream_name, codec_dai->name, num);
272         direction = SND_COMPRESS_PLAYBACK;
273         compr = kzalloc(sizeof(*compr), GFP_KERNEL);
274         if (compr == NULL) {
275                 snd_printk(KERN_ERR "Cannot allocate compr\n");
276                 return -ENOMEM;
277         }
278
279         compr->ops = &soc_compr_ops;
280         mutex_init(&compr->lock);
281         ret = snd_compress_new(rtd->card->snd_card, num, direction, compr);
282         if (ret < 0) {
283                 pr_err("compress asoc: can't create compress for codec %s\n",
284                         codec->name);
285                 kfree(compr);
286                 return ret;
287         }
288
289         rtd->compr = compr;
290         compr->private_data = rtd;
291
292         printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n", codec_dai->name,
293                 cpu_dai->name);
294         return ret;
295 }