Merge tag 'asoc-v5.3' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie...
[linux.git] / sound / firewire / digi00x / digi00x-pcm.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * digi00x-pcm.c - a part of driver for Digidesign Digi 002/003 family
4  *
5  * Copyright (c) 2014-2015 Takashi Sakamoto
6  */
7
8 #include "digi00x.h"
9
10 static int hw_rule_rate(struct snd_pcm_hw_params *params,
11                         struct snd_pcm_hw_rule *rule)
12 {
13         struct snd_interval *r =
14                 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
15         const struct snd_interval *c =
16                 hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
17         struct snd_interval t = {
18                 .min = UINT_MAX, .max = 0, .integer = 1,
19         };
20         unsigned int i;
21
22         for (i = 0; i < SND_DG00X_RATE_COUNT; i++) {
23                 if (!snd_interval_test(c,
24                                        snd_dg00x_stream_pcm_channels[i]))
25                         continue;
26
27                 t.min = min(t.min, snd_dg00x_stream_rates[i]);
28                 t.max = max(t.max, snd_dg00x_stream_rates[i]);
29         }
30
31         return snd_interval_refine(r, &t);
32 }
33
34 static int hw_rule_channels(struct snd_pcm_hw_params *params,
35                             struct snd_pcm_hw_rule *rule)
36 {
37         struct snd_interval *c =
38                 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
39         const struct snd_interval *r =
40                 hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
41         struct snd_interval t = {
42                 .min = UINT_MAX, .max = 0, .integer = 1,
43         };
44         unsigned int i;
45
46         for (i = 0; i < SND_DG00X_RATE_COUNT; i++) {
47                 if (!snd_interval_test(r, snd_dg00x_stream_rates[i]))
48                         continue;
49
50                 t.min = min(t.min, snd_dg00x_stream_pcm_channels[i]);
51                 t.max = max(t.max, snd_dg00x_stream_pcm_channels[i]);
52         }
53
54         return snd_interval_refine(c, &t);
55 }
56
57 static int pcm_init_hw_params(struct snd_dg00x *dg00x,
58                               struct snd_pcm_substream *substream)
59 {
60         struct snd_pcm_runtime *runtime = substream->runtime;
61         struct snd_pcm_hardware *hw = &runtime->hw;
62         struct amdtp_stream *s;
63         int err;
64
65
66         if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
67                 substream->runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
68                 s = &dg00x->tx_stream;
69         } else {
70                 substream->runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
71                 s = &dg00x->rx_stream;
72         }
73
74         hw->channels_min = 10;
75         hw->channels_max = 18;
76
77         hw->rates = SNDRV_PCM_RATE_44100 |
78                     SNDRV_PCM_RATE_48000 |
79                     SNDRV_PCM_RATE_88200 |
80                     SNDRV_PCM_RATE_96000;
81         snd_pcm_limit_hw_rates(runtime);
82
83         err = snd_pcm_hw_rule_add(substream->runtime, 0,
84                                   SNDRV_PCM_HW_PARAM_CHANNELS,
85                                   hw_rule_channels, NULL,
86                                   SNDRV_PCM_HW_PARAM_RATE, -1);
87         if (err < 0)
88                 return err;
89
90         err = snd_pcm_hw_rule_add(substream->runtime, 0,
91                                   SNDRV_PCM_HW_PARAM_RATE,
92                                   hw_rule_rate, NULL,
93                                   SNDRV_PCM_HW_PARAM_CHANNELS, -1);
94         if (err < 0)
95                 return err;
96
97         return amdtp_dot_add_pcm_hw_constraints(s, substream->runtime);
98 }
99
100 static int pcm_open(struct snd_pcm_substream *substream)
101 {
102         struct snd_dg00x *dg00x = substream->private_data;
103         enum snd_dg00x_clock clock;
104         bool detect;
105         unsigned int rate;
106         int err;
107
108         err = snd_dg00x_stream_lock_try(dg00x);
109         if (err < 0)
110                 goto end;
111
112         err = pcm_init_hw_params(dg00x, substream);
113         if (err < 0)
114                 goto err_locked;
115
116         /* Check current clock source. */
117         err = snd_dg00x_stream_get_clock(dg00x, &clock);
118         if (err < 0)
119                 goto err_locked;
120         if (clock != SND_DG00X_CLOCK_INTERNAL) {
121                 err = snd_dg00x_stream_check_external_clock(dg00x, &detect);
122                 if (err < 0)
123                         goto err_locked;
124                 if (!detect) {
125                         err = -EBUSY;
126                         goto err_locked;
127                 }
128         }
129
130         if ((clock != SND_DG00X_CLOCK_INTERNAL) ||
131             amdtp_stream_pcm_running(&dg00x->rx_stream) ||
132             amdtp_stream_pcm_running(&dg00x->tx_stream)) {
133                 err = snd_dg00x_stream_get_external_rate(dg00x, &rate);
134                 if (err < 0)
135                         goto err_locked;
136                 substream->runtime->hw.rate_min = rate;
137                 substream->runtime->hw.rate_max = rate;
138         }
139
140         snd_pcm_set_sync(substream);
141 end:
142         return err;
143 err_locked:
144         snd_dg00x_stream_lock_release(dg00x);
145         return err;
146 }
147
148 static int pcm_close(struct snd_pcm_substream *substream)
149 {
150         struct snd_dg00x *dg00x = substream->private_data;
151
152         snd_dg00x_stream_lock_release(dg00x);
153
154         return 0;
155 }
156
157 static int pcm_hw_params(struct snd_pcm_substream *substream,
158                          struct snd_pcm_hw_params *hw_params)
159 {
160         struct snd_dg00x *dg00x = substream->private_data;
161         int err;
162
163         err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
164                                                params_buffer_bytes(hw_params));
165         if (err < 0)
166                 return err;
167
168         if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
169                 unsigned int rate = params_rate(hw_params);
170
171                 mutex_lock(&dg00x->mutex);
172                 err = snd_dg00x_stream_reserve_duplex(dg00x, rate);
173                 if (err >= 0)
174                         ++dg00x->substreams_counter;
175                 mutex_unlock(&dg00x->mutex);
176         }
177
178         return err;
179 }
180
181 static int pcm_hw_free(struct snd_pcm_substream *substream)
182 {
183         struct snd_dg00x *dg00x = substream->private_data;
184
185         mutex_lock(&dg00x->mutex);
186
187         if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
188                 --dg00x->substreams_counter;
189
190         snd_dg00x_stream_stop_duplex(dg00x);
191
192         mutex_unlock(&dg00x->mutex);
193
194         return snd_pcm_lib_free_vmalloc_buffer(substream);
195 }
196
197 static int pcm_capture_prepare(struct snd_pcm_substream *substream)
198 {
199         struct snd_dg00x *dg00x = substream->private_data;
200         int err;
201
202         mutex_lock(&dg00x->mutex);
203
204         err = snd_dg00x_stream_start_duplex(dg00x);
205         if (err >= 0)
206                 amdtp_stream_pcm_prepare(&dg00x->tx_stream);
207
208         mutex_unlock(&dg00x->mutex);
209
210         return err;
211 }
212
213 static int pcm_playback_prepare(struct snd_pcm_substream *substream)
214 {
215         struct snd_dg00x *dg00x = substream->private_data;
216         int err;
217
218         mutex_lock(&dg00x->mutex);
219
220         err = snd_dg00x_stream_start_duplex(dg00x);
221         if (err >= 0) {
222                 amdtp_stream_pcm_prepare(&dg00x->rx_stream);
223                 amdtp_dot_reset(&dg00x->rx_stream);
224         }
225
226         mutex_unlock(&dg00x->mutex);
227
228         return err;
229 }
230
231 static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
232 {
233         struct snd_dg00x *dg00x = substream->private_data;
234
235         switch (cmd) {
236         case SNDRV_PCM_TRIGGER_START:
237                 amdtp_stream_pcm_trigger(&dg00x->tx_stream, substream);
238                 break;
239         case SNDRV_PCM_TRIGGER_STOP:
240                 amdtp_stream_pcm_trigger(&dg00x->tx_stream, NULL);
241                 break;
242         default:
243                 return -EINVAL;
244         }
245
246         return 0;
247 }
248
249 static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
250 {
251         struct snd_dg00x *dg00x = substream->private_data;
252
253         switch (cmd) {
254         case SNDRV_PCM_TRIGGER_START:
255                 amdtp_stream_pcm_trigger(&dg00x->rx_stream, substream);
256                 break;
257         case SNDRV_PCM_TRIGGER_STOP:
258                 amdtp_stream_pcm_trigger(&dg00x->rx_stream, NULL);
259                 break;
260         default:
261                 return -EINVAL;
262         }
263
264         return 0;
265 }
266
267 static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
268 {
269         struct snd_dg00x *dg00x = sbstrm->private_data;
270
271         return amdtp_stream_pcm_pointer(&dg00x->tx_stream);
272 }
273
274 static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
275 {
276         struct snd_dg00x *dg00x = sbstrm->private_data;
277
278         return amdtp_stream_pcm_pointer(&dg00x->rx_stream);
279 }
280
281 static int pcm_capture_ack(struct snd_pcm_substream *substream)
282 {
283         struct snd_dg00x *dg00x = substream->private_data;
284
285         return amdtp_stream_pcm_ack(&dg00x->tx_stream);
286 }
287
288 static int pcm_playback_ack(struct snd_pcm_substream *substream)
289 {
290         struct snd_dg00x *dg00x = substream->private_data;
291
292         return amdtp_stream_pcm_ack(&dg00x->rx_stream);
293 }
294
295 int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
296 {
297         static const struct snd_pcm_ops capture_ops = {
298                 .open           = pcm_open,
299                 .close          = pcm_close,
300                 .ioctl          = snd_pcm_lib_ioctl,
301                 .hw_params      = pcm_hw_params,
302                 .hw_free        = pcm_hw_free,
303                 .prepare        = pcm_capture_prepare,
304                 .trigger        = pcm_capture_trigger,
305                 .pointer        = pcm_capture_pointer,
306                 .ack            = pcm_capture_ack,
307                 .page           = snd_pcm_lib_get_vmalloc_page,
308         };
309         static const struct snd_pcm_ops playback_ops = {
310                 .open           = pcm_open,
311                 .close          = pcm_close,
312                 .ioctl          = snd_pcm_lib_ioctl,
313                 .hw_params      = pcm_hw_params,
314                 .hw_free        = pcm_hw_free,
315                 .prepare        = pcm_playback_prepare,
316                 .trigger        = pcm_playback_trigger,
317                 .pointer        = pcm_playback_pointer,
318                 .ack            = pcm_playback_ack,
319                 .page           = snd_pcm_lib_get_vmalloc_page,
320         };
321         struct snd_pcm *pcm;
322         int err;
323
324         err = snd_pcm_new(dg00x->card, dg00x->card->driver, 0, 1, 1, &pcm);
325         if (err < 0)
326                 return err;
327
328         pcm->private_data = dg00x;
329         snprintf(pcm->name, sizeof(pcm->name),
330                  "%s PCM", dg00x->card->shortname);
331         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
332         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
333
334         return 0;
335 }