Merge tag 'for-6.3-rc6-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave...
[linux-block.git] / sound / firewire / motu / motu-pcm.c
CommitLineData
da607e19 1// SPDX-License-Identifier: GPL-2.0-only
dd49b2d1
TS
2/*
3 * motu-pcm.c - a part of driver for MOTU FireWire series
4 *
5 * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
dd49b2d1
TS
6 */
7
8#include <sound/pcm_params.h>
9#include "motu.h"
10
11static int motu_rate_constraint(struct snd_pcm_hw_params *params,
12 struct snd_pcm_hw_rule *rule)
13{
14 struct snd_motu_packet_format *formats = rule->private;
15
16 const struct snd_interval *c =
17 hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
18 struct snd_interval *r =
19 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
20 struct snd_interval rates = {
21 .min = UINT_MAX, .max = 0, .integer = 1
22 };
23 unsigned int i, pcm_channels, rate, mode;
24
25 for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) {
26 rate = snd_motu_clock_rates[i];
27 mode = i / 2;
28
9883b385 29 pcm_channels = formats->pcm_chunks[mode];
dd49b2d1
TS
30 if (!snd_interval_test(c, pcm_channels))
31 continue;
32
33 rates.min = min(rates.min, rate);
34 rates.max = max(rates.max, rate);
35 }
36
37 return snd_interval_refine(r, &rates);
38}
39
40static int motu_channels_constraint(struct snd_pcm_hw_params *params,
41 struct snd_pcm_hw_rule *rule)
42{
43 struct snd_motu_packet_format *formats = rule->private;
44
45 const struct snd_interval *r =
46 hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
47 struct snd_interval *c =
48 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
49 struct snd_interval channels = {
50 .min = UINT_MAX, .max = 0, .integer = 1
51 };
52 unsigned int i, pcm_channels, rate, mode;
53
54 for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) {
55 rate = snd_motu_clock_rates[i];
56 mode = i / 2;
57
58 if (!snd_interval_test(r, rate))
59 continue;
60
9883b385 61 pcm_channels = formats->pcm_chunks[mode];
dd49b2d1
TS
62 channels.min = min(channels.min, pcm_channels);
63 channels.max = max(channels.max, pcm_channels);
64 }
65
66 return snd_interval_refine(c, &channels);
67}
68
69static void limit_channels_and_rates(struct snd_motu *motu,
70 struct snd_pcm_runtime *runtime,
71 struct snd_motu_packet_format *formats)
72{
73 struct snd_pcm_hardware *hw = &runtime->hw;
74 unsigned int i, pcm_channels, rate, mode;
75
76 hw->channels_min = UINT_MAX;
77 hw->channels_max = 0;
78
79 for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) {
80 rate = snd_motu_clock_rates[i];
81 mode = i / 2;
82
9883b385 83 pcm_channels = formats->pcm_chunks[mode];
dd49b2d1
TS
84 if (pcm_channels == 0)
85 continue;
86
87 hw->rates |= snd_pcm_rate_to_rate_bit(rate);
88 hw->channels_min = min(hw->channels_min, pcm_channels);
89 hw->channels_max = max(hw->channels_max, pcm_channels);
90 }
91
92 snd_pcm_limit_hw_rates(runtime);
93}
94
dd49b2d1
TS
95static int init_hw_info(struct snd_motu *motu,
96 struct snd_pcm_substream *substream)
97{
98 struct snd_pcm_runtime *runtime = substream->runtime;
99 struct snd_pcm_hardware *hw = &runtime->hw;
100 struct amdtp_stream *stream;
101 struct snd_motu_packet_format *formats;
102 int err;
103
dd49b2d1
TS
104 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
105 hw->formats = SNDRV_PCM_FMTBIT_S32;
106 stream = &motu->tx_stream;
107 formats = &motu->tx_packet_formats;
108 } else {
109 hw->formats = SNDRV_PCM_FMTBIT_S32;
110 stream = &motu->rx_stream;
111 formats = &motu->rx_packet_formats;
112 }
113
114 limit_channels_and_rates(motu, runtime, formats);
dd49b2d1
TS
115
116 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
117 motu_rate_constraint, formats,
118 SNDRV_PCM_HW_PARAM_CHANNELS, -1);
119 if (err < 0)
120 return err;
121 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
122 motu_channels_constraint, formats,
123 SNDRV_PCM_HW_PARAM_RATE, -1);
124 if (err < 0)
125 return err;
126
127 return amdtp_motu_add_pcm_hw_constraints(stream, runtime);
128}
129
130static int pcm_open(struct snd_pcm_substream *substream)
131{
132 struct snd_motu *motu = substream->private_data;
3fd80b20 133 struct amdtp_domain *d = &motu->domain;
dd49b2d1 134 enum snd_motu_clock_source src;
dd49b2d1
TS
135 int err;
136
71c37977
TS
137 err = snd_motu_stream_lock_try(motu);
138 if (err < 0)
139 return err;
140
dd49b2d1
TS
141 mutex_lock(&motu->mutex);
142
8b460c76 143 err = snd_motu_stream_cache_packet_formats(motu);
dd49b2d1 144 if (err < 0)
71c37977 145 goto err_locked;
dd49b2d1
TS
146
147 err = init_hw_info(motu, substream);
148 if (err < 0)
71c37977 149 goto err_locked;
dd49b2d1 150
ff222b7e 151 err = snd_motu_protocol_get_clock_source(motu, &src);
dd49b2d1 152 if (err < 0)
71c37977 153 goto err_locked;
3fd80b20
TS
154
155 // When source of clock is not internal or any stream is reserved for
156 // transmission of PCM frames, the available sampling rate is limited
157 // at current one.
3f58f004
TS
158 if ((src != SND_MOTU_CLOCK_SOURCE_INTERNAL &&
159 src != SND_MOTU_CLOCK_SOURCE_SPH) ||
3fd80b20
TS
160 (motu->substreams_counter > 0 && d->events_per_period > 0)) {
161 unsigned int frames_per_period = d->events_per_period;
0f5482e7 162 unsigned int frames_per_buffer = d->events_per_buffer;
3fd80b20
TS
163 unsigned int rate;
164
ff222b7e 165 err = snd_motu_protocol_get_clock_rate(motu, &rate);
dd49b2d1 166 if (err < 0)
71c37977 167 goto err_locked;
3fd80b20 168
dd49b2d1
TS
169 substream->runtime->hw.rate_min = rate;
170 substream->runtime->hw.rate_max = rate;
3fd80b20
TS
171
172 if (frames_per_period > 0) {
173 err = snd_pcm_hw_constraint_minmax(substream->runtime,
174 SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
175 frames_per_period, frames_per_period);
9ff3483e 176 if (err < 0)
3fd80b20 177 goto err_locked;
0f5482e7
TS
178
179 err = snd_pcm_hw_constraint_minmax(substream->runtime,
180 SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
181 frames_per_buffer, frames_per_buffer);
9ff3483e 182 if (err < 0)
0f5482e7 183 goto err_locked;
3fd80b20 184 }
dd49b2d1
TS
185 }
186
187 snd_pcm_set_sync(substream);
188
189 mutex_unlock(&motu->mutex);
190
3fd80b20 191 return 0;
71c37977
TS
192err_locked:
193 mutex_unlock(&motu->mutex);
194 snd_motu_stream_lock_release(motu);
dd49b2d1
TS
195 return err;
196}
197
198static int pcm_close(struct snd_pcm_substream *substream)
199{
71c37977
TS
200 struct snd_motu *motu = substream->private_data;
201
202 snd_motu_stream_lock_release(motu);
203
dd49b2d1
TS
204 return 0;
205}
206
15d472ec
TS
207static int pcm_hw_params(struct snd_pcm_substream *substream,
208 struct snd_pcm_hw_params *hw_params)
dd49b2d1
TS
209{
210 struct snd_motu *motu = substream->private_data;
7641d549 211 int err = 0;
dd49b2d1 212
23cb0767 213 if (substream->runtime->state == SNDRV_PCM_STATE_OPEN) {
8edc56ec 214 unsigned int rate = params_rate(hw_params);
0d39cd0e 215 unsigned int frames_per_period = params_period_size(hw_params);
0f5482e7 216 unsigned int frames_per_buffer = params_buffer_size(hw_params);
8edc56ec 217
dd49b2d1 218 mutex_lock(&motu->mutex);
0d39cd0e 219 err = snd_motu_stream_reserve_duplex(motu, rate,
0f5482e7 220 frames_per_period, frames_per_buffer);
8edc56ec
TS
221 if (err >= 0)
222 ++motu->substreams_counter;
dd49b2d1
TS
223 mutex_unlock(&motu->mutex);
224 }
225
8edc56ec 226 return err;
dd49b2d1 227}
dd49b2d1 228
15d472ec 229static int pcm_hw_free(struct snd_pcm_substream *substream)
dd49b2d1
TS
230{
231 struct snd_motu *motu = substream->private_data;
232
233 mutex_lock(&motu->mutex);
234
23cb0767 235 if (substream->runtime->state != SNDRV_PCM_STATE_OPEN)
8edc56ec 236 --motu->substreams_counter;
dd49b2d1
TS
237
238 snd_motu_stream_stop_duplex(motu);
239
240 mutex_unlock(&motu->mutex);
241
7641d549 242 return 0;
dd49b2d1
TS
243}
244
245static int capture_prepare(struct snd_pcm_substream *substream)
246{
247 struct snd_motu *motu = substream->private_data;
248 int err;
249
250 mutex_lock(&motu->mutex);
8edc56ec 251 err = snd_motu_stream_start_duplex(motu);
dd49b2d1
TS
252 mutex_unlock(&motu->mutex);
253 if (err >= 0)
254 amdtp_stream_pcm_prepare(&motu->tx_stream);
255
256 return 0;
257}
258static int playback_prepare(struct snd_pcm_substream *substream)
259{
260 struct snd_motu *motu = substream->private_data;
261 int err;
262
263 mutex_lock(&motu->mutex);
8edc56ec 264 err = snd_motu_stream_start_duplex(motu);
dd49b2d1
TS
265 mutex_unlock(&motu->mutex);
266 if (err >= 0)
267 amdtp_stream_pcm_prepare(&motu->rx_stream);
268
269 return err;
270}
271
272static int capture_trigger(struct snd_pcm_substream *substream, int cmd)
273{
274 struct snd_motu *motu = substream->private_data;
275
276 switch (cmd) {
277 case SNDRV_PCM_TRIGGER_START:
278 amdtp_stream_pcm_trigger(&motu->tx_stream, substream);
279 break;
280 case SNDRV_PCM_TRIGGER_STOP:
281 amdtp_stream_pcm_trigger(&motu->tx_stream, NULL);
282 break;
283 default:
284 return -EINVAL;
285 }
286
287 return 0;
288}
289static int playback_trigger(struct snd_pcm_substream *substream, int cmd)
290{
291 struct snd_motu *motu = substream->private_data;
292
293 switch (cmd) {
294 case SNDRV_PCM_TRIGGER_START:
295 amdtp_stream_pcm_trigger(&motu->rx_stream, substream);
296 break;
297 case SNDRV_PCM_TRIGGER_STOP:
298 amdtp_stream_pcm_trigger(&motu->rx_stream, NULL);
299 break;
300 default:
301 return -EINVAL;
302 }
303
304 return 0;
305}
306
307static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream)
308{
309 struct snd_motu *motu = substream->private_data;
310
f890f9a0 311 return amdtp_domain_stream_pcm_pointer(&motu->domain, &motu->tx_stream);
dd49b2d1
TS
312}
313static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream)
314{
315 struct snd_motu *motu = substream->private_data;
316
f890f9a0 317 return amdtp_domain_stream_pcm_pointer(&motu->domain, &motu->rx_stream);
dd49b2d1
TS
318}
319
875becf8
TS
320static int capture_ack(struct snd_pcm_substream *substream)
321{
322 struct snd_motu *motu = substream->private_data;
323
e6dcc92f 324 return amdtp_domain_stream_pcm_ack(&motu->domain, &motu->tx_stream);
875becf8
TS
325}
326
327static int playback_ack(struct snd_pcm_substream *substream)
328{
329 struct snd_motu *motu = substream->private_data;
330
e6dcc92f 331 return amdtp_domain_stream_pcm_ack(&motu->domain, &motu->rx_stream);
875becf8
TS
332}
333
dd49b2d1
TS
334int snd_motu_create_pcm_devices(struct snd_motu *motu)
335{
b2165f38 336 static const struct snd_pcm_ops capture_ops = {
dd49b2d1
TS
337 .open = pcm_open,
338 .close = pcm_close,
15d472ec
TS
339 .hw_params = pcm_hw_params,
340 .hw_free = pcm_hw_free,
dd49b2d1
TS
341 .prepare = capture_prepare,
342 .trigger = capture_trigger,
343 .pointer = capture_pointer,
875becf8 344 .ack = capture_ack,
dd49b2d1 345 };
b2165f38 346 static const struct snd_pcm_ops playback_ops = {
dd49b2d1
TS
347 .open = pcm_open,
348 .close = pcm_close,
15d472ec
TS
349 .hw_params = pcm_hw_params,
350 .hw_free = pcm_hw_free,
dd49b2d1
TS
351 .prepare = playback_prepare,
352 .trigger = playback_trigger,
353 .pointer = playback_pointer,
875becf8 354 .ack = playback_ack,
dd49b2d1
TS
355 };
356 struct snd_pcm *pcm;
357 int err;
358
359 err = snd_pcm_new(motu->card, motu->card->driver, 0, 1, 1, &pcm);
360 if (err < 0)
361 return err;
362 pcm->private_data = motu;
363 strcpy(pcm->name, motu->card->shortname);
364
365 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
366 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
7641d549 367 snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);
dd49b2d1
TS
368
369 return 0;
370}