xref: /OK3568_Linux_fs/kernel/sound/firewire/tascam/tascam-pcm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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