1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * tascam-pcm.c - a part of driver for TASCAM FireWire series
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (c) 2015 Takashi Sakamoto
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include "tascam.h"
9*4882a593Smuzhiyun
pcm_init_hw_params(struct snd_tscm * tscm,struct snd_pcm_substream * substream)10*4882a593Smuzhiyun static int pcm_init_hw_params(struct snd_tscm *tscm,
11*4882a593Smuzhiyun struct snd_pcm_substream *substream)
12*4882a593Smuzhiyun {
13*4882a593Smuzhiyun struct snd_pcm_runtime *runtime = substream->runtime;
14*4882a593Smuzhiyun struct snd_pcm_hardware *hw = &runtime->hw;
15*4882a593Smuzhiyun struct amdtp_stream *stream;
16*4882a593Smuzhiyun unsigned int pcm_channels;
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
19*4882a593Smuzhiyun runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
20*4882a593Smuzhiyun stream = &tscm->tx_stream;
21*4882a593Smuzhiyun pcm_channels = tscm->spec->pcm_capture_analog_channels;
22*4882a593Smuzhiyun } else {
23*4882a593Smuzhiyun runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
24*4882a593Smuzhiyun stream = &tscm->rx_stream;
25*4882a593Smuzhiyun pcm_channels = tscm->spec->pcm_playback_analog_channels;
26*4882a593Smuzhiyun }
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun if (tscm->spec->has_adat)
29*4882a593Smuzhiyun pcm_channels += 8;
30*4882a593Smuzhiyun if (tscm->spec->has_spdif)
31*4882a593Smuzhiyun pcm_channels += 2;
32*4882a593Smuzhiyun runtime->hw.channels_min = runtime->hw.channels_max = pcm_channels;
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun hw->rates = SNDRV_PCM_RATE_44100 |
35*4882a593Smuzhiyun SNDRV_PCM_RATE_48000 |
36*4882a593Smuzhiyun SNDRV_PCM_RATE_88200 |
37*4882a593Smuzhiyun SNDRV_PCM_RATE_96000;
38*4882a593Smuzhiyun snd_pcm_limit_hw_rates(runtime);
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun return amdtp_tscm_add_pcm_hw_constraints(stream, runtime);
41*4882a593Smuzhiyun }
42*4882a593Smuzhiyun
pcm_open(struct snd_pcm_substream * substream)43*4882a593Smuzhiyun static int pcm_open(struct snd_pcm_substream *substream)
44*4882a593Smuzhiyun {
45*4882a593Smuzhiyun struct snd_tscm *tscm = substream->private_data;
46*4882a593Smuzhiyun struct amdtp_domain *d = &tscm->domain;
47*4882a593Smuzhiyun enum snd_tscm_clock clock;
48*4882a593Smuzhiyun int err;
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun err = snd_tscm_stream_lock_try(tscm);
51*4882a593Smuzhiyun if (err < 0)
52*4882a593Smuzhiyun return err;
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun err = pcm_init_hw_params(tscm, substream);
55*4882a593Smuzhiyun if (err < 0)
56*4882a593Smuzhiyun goto err_locked;
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun err = snd_tscm_stream_get_clock(tscm, &clock);
59*4882a593Smuzhiyun if (err < 0)
60*4882a593Smuzhiyun goto err_locked;
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun mutex_lock(&tscm->mutex);
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun // When source of clock is not internal or any stream is reserved for
65*4882a593Smuzhiyun // transmission of PCM frames, the available sampling rate is limited
66*4882a593Smuzhiyun // at current one.
67*4882a593Smuzhiyun if (clock != SND_TSCM_CLOCK_INTERNAL || tscm->substreams_counter > 0) {
68*4882a593Smuzhiyun unsigned int frames_per_period = d->events_per_period;
69*4882a593Smuzhiyun unsigned int frames_per_buffer = d->events_per_buffer;
70*4882a593Smuzhiyun unsigned int rate;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun err = snd_tscm_stream_get_rate(tscm, &rate);
73*4882a593Smuzhiyun if (err < 0) {
74*4882a593Smuzhiyun mutex_unlock(&tscm->mutex);
75*4882a593Smuzhiyun goto err_locked;
76*4882a593Smuzhiyun }
77*4882a593Smuzhiyun substream->runtime->hw.rate_min = rate;
78*4882a593Smuzhiyun substream->runtime->hw.rate_max = rate;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun err = snd_pcm_hw_constraint_minmax(substream->runtime,
81*4882a593Smuzhiyun SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
82*4882a593Smuzhiyun frames_per_period, frames_per_period);
83*4882a593Smuzhiyun if (err < 0) {
84*4882a593Smuzhiyun mutex_unlock(&tscm->mutex);
85*4882a593Smuzhiyun goto err_locked;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun err = snd_pcm_hw_constraint_minmax(substream->runtime,
89*4882a593Smuzhiyun SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
90*4882a593Smuzhiyun frames_per_buffer, frames_per_buffer);
91*4882a593Smuzhiyun if (err < 0) {
92*4882a593Smuzhiyun mutex_unlock(&tscm->mutex);
93*4882a593Smuzhiyun goto err_locked;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun mutex_unlock(&tscm->mutex);
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun snd_pcm_set_sync(substream);
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun return 0;
102*4882a593Smuzhiyun err_locked:
103*4882a593Smuzhiyun snd_tscm_stream_lock_release(tscm);
104*4882a593Smuzhiyun return err;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun
pcm_close(struct snd_pcm_substream * substream)107*4882a593Smuzhiyun static int pcm_close(struct snd_pcm_substream *substream)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun struct snd_tscm *tscm = substream->private_data;
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun snd_tscm_stream_lock_release(tscm);
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun return 0;
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun
pcm_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * hw_params)116*4882a593Smuzhiyun static int pcm_hw_params(struct snd_pcm_substream *substream,
117*4882a593Smuzhiyun struct snd_pcm_hw_params *hw_params)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun struct snd_tscm *tscm = substream->private_data;
120*4882a593Smuzhiyun int err = 0;
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
123*4882a593Smuzhiyun unsigned int rate = params_rate(hw_params);
124*4882a593Smuzhiyun unsigned int frames_per_period = params_period_size(hw_params);
125*4882a593Smuzhiyun unsigned int frames_per_buffer = params_buffer_size(hw_params);
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun mutex_lock(&tscm->mutex);
128*4882a593Smuzhiyun err = snd_tscm_stream_reserve_duplex(tscm, rate,
129*4882a593Smuzhiyun frames_per_period, frames_per_buffer);
130*4882a593Smuzhiyun if (err >= 0)
131*4882a593Smuzhiyun ++tscm->substreams_counter;
132*4882a593Smuzhiyun mutex_unlock(&tscm->mutex);
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun return err;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
pcm_hw_free(struct snd_pcm_substream * substream)138*4882a593Smuzhiyun static int pcm_hw_free(struct snd_pcm_substream *substream)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun struct snd_tscm *tscm = substream->private_data;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun mutex_lock(&tscm->mutex);
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
145*4882a593Smuzhiyun --tscm->substreams_counter;
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun snd_tscm_stream_stop_duplex(tscm);
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun mutex_unlock(&tscm->mutex);
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun return 0;
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun
pcm_capture_prepare(struct snd_pcm_substream * substream)154*4882a593Smuzhiyun static int pcm_capture_prepare(struct snd_pcm_substream *substream)
155*4882a593Smuzhiyun {
156*4882a593Smuzhiyun struct snd_tscm *tscm = substream->private_data;
157*4882a593Smuzhiyun struct snd_pcm_runtime *runtime = substream->runtime;
158*4882a593Smuzhiyun int err;
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun mutex_lock(&tscm->mutex);
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun err = snd_tscm_stream_start_duplex(tscm, runtime->rate);
163*4882a593Smuzhiyun if (err >= 0)
164*4882a593Smuzhiyun amdtp_stream_pcm_prepare(&tscm->tx_stream);
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun mutex_unlock(&tscm->mutex);
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun return err;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun
pcm_playback_prepare(struct snd_pcm_substream * substream)171*4882a593Smuzhiyun static int pcm_playback_prepare(struct snd_pcm_substream *substream)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun struct snd_tscm *tscm = substream->private_data;
174*4882a593Smuzhiyun struct snd_pcm_runtime *runtime = substream->runtime;
175*4882a593Smuzhiyun int err;
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun mutex_lock(&tscm->mutex);
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun err = snd_tscm_stream_start_duplex(tscm, runtime->rate);
180*4882a593Smuzhiyun if (err >= 0)
181*4882a593Smuzhiyun amdtp_stream_pcm_prepare(&tscm->rx_stream);
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun mutex_unlock(&tscm->mutex);
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun return err;
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun
pcm_capture_trigger(struct snd_pcm_substream * substream,int cmd)188*4882a593Smuzhiyun static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun struct snd_tscm *tscm = substream->private_data;
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun switch (cmd) {
193*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_START:
194*4882a593Smuzhiyun amdtp_stream_pcm_trigger(&tscm->tx_stream, substream);
195*4882a593Smuzhiyun break;
196*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_STOP:
197*4882a593Smuzhiyun amdtp_stream_pcm_trigger(&tscm->tx_stream, NULL);
198*4882a593Smuzhiyun break;
199*4882a593Smuzhiyun default:
200*4882a593Smuzhiyun return -EINVAL;
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun return 0;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun
pcm_playback_trigger(struct snd_pcm_substream * substream,int cmd)206*4882a593Smuzhiyun static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun struct snd_tscm *tscm = substream->private_data;
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun switch (cmd) {
211*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_START:
212*4882a593Smuzhiyun amdtp_stream_pcm_trigger(&tscm->rx_stream, substream);
213*4882a593Smuzhiyun break;
214*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_STOP:
215*4882a593Smuzhiyun amdtp_stream_pcm_trigger(&tscm->rx_stream, NULL);
216*4882a593Smuzhiyun break;
217*4882a593Smuzhiyun default:
218*4882a593Smuzhiyun return -EINVAL;
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun return 0;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun
pcm_capture_pointer(struct snd_pcm_substream * sbstrm)224*4882a593Smuzhiyun static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun struct snd_tscm *tscm = sbstrm->private_data;
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun return amdtp_domain_stream_pcm_pointer(&tscm->domain, &tscm->tx_stream);
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun
pcm_playback_pointer(struct snd_pcm_substream * sbstrm)231*4882a593Smuzhiyun static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun struct snd_tscm *tscm = sbstrm->private_data;
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun return amdtp_domain_stream_pcm_pointer(&tscm->domain, &tscm->rx_stream);
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun
pcm_capture_ack(struct snd_pcm_substream * substream)238*4882a593Smuzhiyun static int pcm_capture_ack(struct snd_pcm_substream *substream)
239*4882a593Smuzhiyun {
240*4882a593Smuzhiyun struct snd_tscm *tscm = substream->private_data;
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun return amdtp_domain_stream_pcm_ack(&tscm->domain, &tscm->tx_stream);
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun
pcm_playback_ack(struct snd_pcm_substream * substream)245*4882a593Smuzhiyun static int pcm_playback_ack(struct snd_pcm_substream *substream)
246*4882a593Smuzhiyun {
247*4882a593Smuzhiyun struct snd_tscm *tscm = substream->private_data;
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun return amdtp_domain_stream_pcm_ack(&tscm->domain, &tscm->rx_stream);
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun
snd_tscm_create_pcm_devices(struct snd_tscm * tscm)252*4882a593Smuzhiyun int snd_tscm_create_pcm_devices(struct snd_tscm *tscm)
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun static const struct snd_pcm_ops capture_ops = {
255*4882a593Smuzhiyun .open = pcm_open,
256*4882a593Smuzhiyun .close = pcm_close,
257*4882a593Smuzhiyun .hw_params = pcm_hw_params,
258*4882a593Smuzhiyun .hw_free = pcm_hw_free,
259*4882a593Smuzhiyun .prepare = pcm_capture_prepare,
260*4882a593Smuzhiyun .trigger = pcm_capture_trigger,
261*4882a593Smuzhiyun .pointer = pcm_capture_pointer,
262*4882a593Smuzhiyun .ack = pcm_capture_ack,
263*4882a593Smuzhiyun };
264*4882a593Smuzhiyun static const struct snd_pcm_ops playback_ops = {
265*4882a593Smuzhiyun .open = pcm_open,
266*4882a593Smuzhiyun .close = pcm_close,
267*4882a593Smuzhiyun .hw_params = pcm_hw_params,
268*4882a593Smuzhiyun .hw_free = pcm_hw_free,
269*4882a593Smuzhiyun .prepare = pcm_playback_prepare,
270*4882a593Smuzhiyun .trigger = pcm_playback_trigger,
271*4882a593Smuzhiyun .pointer = pcm_playback_pointer,
272*4882a593Smuzhiyun .ack = pcm_playback_ack,
273*4882a593Smuzhiyun };
274*4882a593Smuzhiyun struct snd_pcm *pcm;
275*4882a593Smuzhiyun int err;
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun err = snd_pcm_new(tscm->card, tscm->card->driver, 0, 1, 1, &pcm);
278*4882a593Smuzhiyun if (err < 0)
279*4882a593Smuzhiyun return err;
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun pcm->private_data = tscm;
282*4882a593Smuzhiyun snprintf(pcm->name, sizeof(pcm->name),
283*4882a593Smuzhiyun "%s PCM", tscm->card->shortname);
284*4882a593Smuzhiyun snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
285*4882a593Smuzhiyun snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
286*4882a593Smuzhiyun snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun return 0;
289*4882a593Smuzhiyun }
290