xref: /openbmc/linux/sound/firewire/oxfw/oxfw-pcm.c (revision 3713d93a6a12f8629c2660bb4a30d48b98105fca)
1*3713d93aSTakashi Sakamoto /*
2*3713d93aSTakashi Sakamoto  * oxfw_pcm.c - a part of driver for OXFW970/971 based devices
3*3713d93aSTakashi Sakamoto  *
4*3713d93aSTakashi Sakamoto  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
5*3713d93aSTakashi Sakamoto  * Licensed under the terms of the GNU General Public License, version 2.
6*3713d93aSTakashi Sakamoto  */
7*3713d93aSTakashi Sakamoto 
8*3713d93aSTakashi Sakamoto #include "oxfw.h"
9*3713d93aSTakashi Sakamoto 
10*3713d93aSTakashi Sakamoto static int firewave_rate_constraint(struct snd_pcm_hw_params *params,
11*3713d93aSTakashi Sakamoto 				    struct snd_pcm_hw_rule *rule)
12*3713d93aSTakashi Sakamoto {
13*3713d93aSTakashi Sakamoto 	static unsigned int stereo_rates[] = { 48000, 96000 };
14*3713d93aSTakashi Sakamoto 	struct snd_interval *channels =
15*3713d93aSTakashi Sakamoto 			hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
16*3713d93aSTakashi Sakamoto 	struct snd_interval *rate =
17*3713d93aSTakashi Sakamoto 			hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
18*3713d93aSTakashi Sakamoto 
19*3713d93aSTakashi Sakamoto 	/* two channels work only at 48/96 kHz */
20*3713d93aSTakashi Sakamoto 	if (snd_interval_max(channels) < 6)
21*3713d93aSTakashi Sakamoto 		return snd_interval_list(rate, 2, stereo_rates, 0);
22*3713d93aSTakashi Sakamoto 	return 0;
23*3713d93aSTakashi Sakamoto }
24*3713d93aSTakashi Sakamoto 
25*3713d93aSTakashi Sakamoto static int firewave_channels_constraint(struct snd_pcm_hw_params *params,
26*3713d93aSTakashi Sakamoto 					struct snd_pcm_hw_rule *rule)
27*3713d93aSTakashi Sakamoto {
28*3713d93aSTakashi Sakamoto 	static const struct snd_interval all_channels = { .min = 6, .max = 6 };
29*3713d93aSTakashi Sakamoto 	struct snd_interval *rate =
30*3713d93aSTakashi Sakamoto 			hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
31*3713d93aSTakashi Sakamoto 	struct snd_interval *channels =
32*3713d93aSTakashi Sakamoto 			hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
33*3713d93aSTakashi Sakamoto 
34*3713d93aSTakashi Sakamoto 	/* 32/44.1 kHz work only with all six channels */
35*3713d93aSTakashi Sakamoto 	if (snd_interval_max(rate) < 48000)
36*3713d93aSTakashi Sakamoto 		return snd_interval_refine(channels, &all_channels);
37*3713d93aSTakashi Sakamoto 	return 0;
38*3713d93aSTakashi Sakamoto }
39*3713d93aSTakashi Sakamoto 
40*3713d93aSTakashi Sakamoto int firewave_constraints(struct snd_pcm_runtime *runtime)
41*3713d93aSTakashi Sakamoto {
42*3713d93aSTakashi Sakamoto 	static unsigned int channels_list[] = { 2, 6 };
43*3713d93aSTakashi Sakamoto 	static struct snd_pcm_hw_constraint_list channels_list_constraint = {
44*3713d93aSTakashi Sakamoto 		.count = 2,
45*3713d93aSTakashi Sakamoto 		.list = channels_list,
46*3713d93aSTakashi Sakamoto 	};
47*3713d93aSTakashi Sakamoto 	int err;
48*3713d93aSTakashi Sakamoto 
49*3713d93aSTakashi Sakamoto 	runtime->hw.rates = SNDRV_PCM_RATE_32000 |
50*3713d93aSTakashi Sakamoto 			    SNDRV_PCM_RATE_44100 |
51*3713d93aSTakashi Sakamoto 			    SNDRV_PCM_RATE_48000 |
52*3713d93aSTakashi Sakamoto 			    SNDRV_PCM_RATE_96000;
53*3713d93aSTakashi Sakamoto 	runtime->hw.channels_max = 6;
54*3713d93aSTakashi Sakamoto 
55*3713d93aSTakashi Sakamoto 	err = snd_pcm_hw_constraint_list(runtime, 0,
56*3713d93aSTakashi Sakamoto 					 SNDRV_PCM_HW_PARAM_CHANNELS,
57*3713d93aSTakashi Sakamoto 					 &channels_list_constraint);
58*3713d93aSTakashi Sakamoto 	if (err < 0)
59*3713d93aSTakashi Sakamoto 		return err;
60*3713d93aSTakashi Sakamoto 	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
61*3713d93aSTakashi Sakamoto 				  firewave_rate_constraint, NULL,
62*3713d93aSTakashi Sakamoto 				  SNDRV_PCM_HW_PARAM_CHANNELS, -1);
63*3713d93aSTakashi Sakamoto 	if (err < 0)
64*3713d93aSTakashi Sakamoto 		return err;
65*3713d93aSTakashi Sakamoto 	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
66*3713d93aSTakashi Sakamoto 				  firewave_channels_constraint, NULL,
67*3713d93aSTakashi Sakamoto 				  SNDRV_PCM_HW_PARAM_RATE, -1);
68*3713d93aSTakashi Sakamoto 	if (err < 0)
69*3713d93aSTakashi Sakamoto 		return err;
70*3713d93aSTakashi Sakamoto 
71*3713d93aSTakashi Sakamoto 	return 0;
72*3713d93aSTakashi Sakamoto }
73*3713d93aSTakashi Sakamoto 
74*3713d93aSTakashi Sakamoto int lacie_speakers_constraints(struct snd_pcm_runtime *runtime)
75*3713d93aSTakashi Sakamoto {
76*3713d93aSTakashi Sakamoto 	runtime->hw.rates = SNDRV_PCM_RATE_32000 |
77*3713d93aSTakashi Sakamoto 			    SNDRV_PCM_RATE_44100 |
78*3713d93aSTakashi Sakamoto 			    SNDRV_PCM_RATE_48000 |
79*3713d93aSTakashi Sakamoto 			    SNDRV_PCM_RATE_88200 |
80*3713d93aSTakashi Sakamoto 			    SNDRV_PCM_RATE_96000;
81*3713d93aSTakashi Sakamoto 
82*3713d93aSTakashi Sakamoto 	return 0;
83*3713d93aSTakashi Sakamoto }
84*3713d93aSTakashi Sakamoto 
85*3713d93aSTakashi Sakamoto static int pcm_open(struct snd_pcm_substream *substream)
86*3713d93aSTakashi Sakamoto {
87*3713d93aSTakashi Sakamoto 	static const struct snd_pcm_hardware hardware = {
88*3713d93aSTakashi Sakamoto 		.info = SNDRV_PCM_INFO_MMAP |
89*3713d93aSTakashi Sakamoto 			SNDRV_PCM_INFO_MMAP_VALID |
90*3713d93aSTakashi Sakamoto 			SNDRV_PCM_INFO_BATCH |
91*3713d93aSTakashi Sakamoto 			SNDRV_PCM_INFO_INTERLEAVED |
92*3713d93aSTakashi Sakamoto 			SNDRV_PCM_INFO_BLOCK_TRANSFER,
93*3713d93aSTakashi Sakamoto 		.formats = AMDTP_OUT_PCM_FORMAT_BITS,
94*3713d93aSTakashi Sakamoto 		.channels_min = 2,
95*3713d93aSTakashi Sakamoto 		.channels_max = 2,
96*3713d93aSTakashi Sakamoto 		.buffer_bytes_max = 4 * 1024 * 1024,
97*3713d93aSTakashi Sakamoto 		.period_bytes_min = 1,
98*3713d93aSTakashi Sakamoto 		.period_bytes_max = UINT_MAX,
99*3713d93aSTakashi Sakamoto 		.periods_min = 1,
100*3713d93aSTakashi Sakamoto 		.periods_max = UINT_MAX,
101*3713d93aSTakashi Sakamoto 	};
102*3713d93aSTakashi Sakamoto 	struct snd_oxfw *oxfw = substream->private_data;
103*3713d93aSTakashi Sakamoto 	struct snd_pcm_runtime *runtime = substream->runtime;
104*3713d93aSTakashi Sakamoto 	bool used;
105*3713d93aSTakashi Sakamoto 	int err;
106*3713d93aSTakashi Sakamoto 
107*3713d93aSTakashi Sakamoto 	err = cmp_connection_check_used(&oxfw->in_conn, &used);
108*3713d93aSTakashi Sakamoto 	if ((err < 0) || used)
109*3713d93aSTakashi Sakamoto 		goto end;
110*3713d93aSTakashi Sakamoto 
111*3713d93aSTakashi Sakamoto 	runtime->hw = hardware;
112*3713d93aSTakashi Sakamoto 
113*3713d93aSTakashi Sakamoto 	err = oxfw->device_info->pcm_constraints(runtime);
114*3713d93aSTakashi Sakamoto 	if (err < 0)
115*3713d93aSTakashi Sakamoto 		goto end;
116*3713d93aSTakashi Sakamoto 	err = snd_pcm_limit_hw_rates(runtime);
117*3713d93aSTakashi Sakamoto 	if (err < 0)
118*3713d93aSTakashi Sakamoto 		goto end;
119*3713d93aSTakashi Sakamoto 
120*3713d93aSTakashi Sakamoto 	err = amdtp_stream_add_pcm_hw_constraints(&oxfw->rx_stream, runtime);
121*3713d93aSTakashi Sakamoto end:
122*3713d93aSTakashi Sakamoto 	return err;
123*3713d93aSTakashi Sakamoto }
124*3713d93aSTakashi Sakamoto 
125*3713d93aSTakashi Sakamoto static int pcm_close(struct snd_pcm_substream *substream)
126*3713d93aSTakashi Sakamoto {
127*3713d93aSTakashi Sakamoto 	return 0;
128*3713d93aSTakashi Sakamoto }
129*3713d93aSTakashi Sakamoto 
130*3713d93aSTakashi Sakamoto static int pcm_hw_params(struct snd_pcm_substream *substream,
131*3713d93aSTakashi Sakamoto 			 struct snd_pcm_hw_params *hw_params)
132*3713d93aSTakashi Sakamoto {
133*3713d93aSTakashi Sakamoto 	struct snd_oxfw *oxfw = substream->private_data;
134*3713d93aSTakashi Sakamoto 	int err;
135*3713d93aSTakashi Sakamoto 
136*3713d93aSTakashi Sakamoto 	mutex_lock(&oxfw->mutex);
137*3713d93aSTakashi Sakamoto 
138*3713d93aSTakashi Sakamoto 	snd_oxfw_stream_stop_simplex(oxfw);
139*3713d93aSTakashi Sakamoto 
140*3713d93aSTakashi Sakamoto 	err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
141*3713d93aSTakashi Sakamoto 					       params_buffer_bytes(hw_params));
142*3713d93aSTakashi Sakamoto 	if (err < 0)
143*3713d93aSTakashi Sakamoto 		goto error;
144*3713d93aSTakashi Sakamoto 
145*3713d93aSTakashi Sakamoto 	amdtp_stream_set_parameters(&oxfw->rx_stream,
146*3713d93aSTakashi Sakamoto 				    params_rate(hw_params),
147*3713d93aSTakashi Sakamoto 				    params_channels(hw_params),
148*3713d93aSTakashi Sakamoto 				    0);
149*3713d93aSTakashi Sakamoto 
150*3713d93aSTakashi Sakamoto 	amdtp_stream_set_pcm_format(&oxfw->rx_stream,
151*3713d93aSTakashi Sakamoto 				    params_format(hw_params));
152*3713d93aSTakashi Sakamoto 
153*3713d93aSTakashi Sakamoto 	err = avc_general_set_sig_fmt(oxfw->unit, params_rate(hw_params),
154*3713d93aSTakashi Sakamoto 				      AVC_GENERAL_PLUG_DIR_IN, 0);
155*3713d93aSTakashi Sakamoto 	if (err < 0) {
156*3713d93aSTakashi Sakamoto 		dev_err(&oxfw->unit->device, "failed to set sample rate\n");
157*3713d93aSTakashi Sakamoto 		goto err_buffer;
158*3713d93aSTakashi Sakamoto 	}
159*3713d93aSTakashi Sakamoto 
160*3713d93aSTakashi Sakamoto 	return 0;
161*3713d93aSTakashi Sakamoto 
162*3713d93aSTakashi Sakamoto err_buffer:
163*3713d93aSTakashi Sakamoto 	snd_pcm_lib_free_vmalloc_buffer(substream);
164*3713d93aSTakashi Sakamoto error:
165*3713d93aSTakashi Sakamoto 	mutex_unlock(&oxfw->mutex);
166*3713d93aSTakashi Sakamoto 	return err;
167*3713d93aSTakashi Sakamoto }
168*3713d93aSTakashi Sakamoto 
169*3713d93aSTakashi Sakamoto static int pcm_hw_free(struct snd_pcm_substream *substream)
170*3713d93aSTakashi Sakamoto {
171*3713d93aSTakashi Sakamoto 	struct snd_oxfw *oxfw = substream->private_data;
172*3713d93aSTakashi Sakamoto 
173*3713d93aSTakashi Sakamoto 	mutex_lock(&oxfw->mutex);
174*3713d93aSTakashi Sakamoto 	snd_oxfw_stream_stop_simplex(oxfw);
175*3713d93aSTakashi Sakamoto 	mutex_unlock(&oxfw->mutex);
176*3713d93aSTakashi Sakamoto 
177*3713d93aSTakashi Sakamoto 	return snd_pcm_lib_free_vmalloc_buffer(substream);
178*3713d93aSTakashi Sakamoto }
179*3713d93aSTakashi Sakamoto 
180*3713d93aSTakashi Sakamoto static int pcm_prepare(struct snd_pcm_substream *substream)
181*3713d93aSTakashi Sakamoto {
182*3713d93aSTakashi Sakamoto 	struct snd_oxfw *oxfw = substream->private_data;
183*3713d93aSTakashi Sakamoto 	int err;
184*3713d93aSTakashi Sakamoto 
185*3713d93aSTakashi Sakamoto 	mutex_lock(&oxfw->mutex);
186*3713d93aSTakashi Sakamoto 
187*3713d93aSTakashi Sakamoto 	snd_oxfw_stream_stop_simplex(oxfw);
188*3713d93aSTakashi Sakamoto 
189*3713d93aSTakashi Sakamoto 	err = snd_oxfw_stream_start_simplex(oxfw);
190*3713d93aSTakashi Sakamoto 	if (err < 0)
191*3713d93aSTakashi Sakamoto 		goto end;
192*3713d93aSTakashi Sakamoto 
193*3713d93aSTakashi Sakamoto 	amdtp_stream_pcm_prepare(&oxfw->rx_stream);
194*3713d93aSTakashi Sakamoto end:
195*3713d93aSTakashi Sakamoto 	mutex_unlock(&oxfw->mutex);
196*3713d93aSTakashi Sakamoto 	return err;
197*3713d93aSTakashi Sakamoto }
198*3713d93aSTakashi Sakamoto 
199*3713d93aSTakashi Sakamoto static int pcm_trigger(struct snd_pcm_substream *substream, int cmd)
200*3713d93aSTakashi Sakamoto {
201*3713d93aSTakashi Sakamoto 	struct snd_oxfw *oxfw = substream->private_data;
202*3713d93aSTakashi Sakamoto 	struct snd_pcm_substream *pcm;
203*3713d93aSTakashi Sakamoto 
204*3713d93aSTakashi Sakamoto 	switch (cmd) {
205*3713d93aSTakashi Sakamoto 	case SNDRV_PCM_TRIGGER_START:
206*3713d93aSTakashi Sakamoto 		pcm = substream;
207*3713d93aSTakashi Sakamoto 		break;
208*3713d93aSTakashi Sakamoto 	case SNDRV_PCM_TRIGGER_STOP:
209*3713d93aSTakashi Sakamoto 		pcm = NULL;
210*3713d93aSTakashi Sakamoto 		break;
211*3713d93aSTakashi Sakamoto 	default:
212*3713d93aSTakashi Sakamoto 		return -EINVAL;
213*3713d93aSTakashi Sakamoto 	}
214*3713d93aSTakashi Sakamoto 	amdtp_stream_pcm_trigger(&oxfw->rx_stream, pcm);
215*3713d93aSTakashi Sakamoto 	return 0;
216*3713d93aSTakashi Sakamoto }
217*3713d93aSTakashi Sakamoto 
218*3713d93aSTakashi Sakamoto static snd_pcm_uframes_t pcm_pointer(struct snd_pcm_substream *substream)
219*3713d93aSTakashi Sakamoto {
220*3713d93aSTakashi Sakamoto 	struct snd_oxfw *oxfw = substream->private_data;
221*3713d93aSTakashi Sakamoto 
222*3713d93aSTakashi Sakamoto 	return amdtp_stream_pcm_pointer(&oxfw->rx_stream);
223*3713d93aSTakashi Sakamoto }
224*3713d93aSTakashi Sakamoto 
225*3713d93aSTakashi Sakamoto int snd_oxfw_create_pcm(struct snd_oxfw *oxfw)
226*3713d93aSTakashi Sakamoto {
227*3713d93aSTakashi Sakamoto 	static struct snd_pcm_ops ops = {
228*3713d93aSTakashi Sakamoto 		.open      = pcm_open,
229*3713d93aSTakashi Sakamoto 		.close     = pcm_close,
230*3713d93aSTakashi Sakamoto 		.ioctl     = snd_pcm_lib_ioctl,
231*3713d93aSTakashi Sakamoto 		.hw_params = pcm_hw_params,
232*3713d93aSTakashi Sakamoto 		.hw_free   = pcm_hw_free,
233*3713d93aSTakashi Sakamoto 		.prepare   = pcm_prepare,
234*3713d93aSTakashi Sakamoto 		.trigger   = pcm_trigger,
235*3713d93aSTakashi Sakamoto 		.pointer   = pcm_pointer,
236*3713d93aSTakashi Sakamoto 		.page      = snd_pcm_lib_get_vmalloc_page,
237*3713d93aSTakashi Sakamoto 		.mmap      = snd_pcm_lib_mmap_vmalloc,
238*3713d93aSTakashi Sakamoto 	};
239*3713d93aSTakashi Sakamoto 	struct snd_pcm *pcm;
240*3713d93aSTakashi Sakamoto 	int err;
241*3713d93aSTakashi Sakamoto 
242*3713d93aSTakashi Sakamoto 	err = snd_pcm_new(oxfw->card, oxfw->card->driver, 0, 1, 0, &pcm);
243*3713d93aSTakashi Sakamoto 	if (err < 0)
244*3713d93aSTakashi Sakamoto 		return err;
245*3713d93aSTakashi Sakamoto 	pcm->private_data = oxfw;
246*3713d93aSTakashi Sakamoto 	strcpy(pcm->name, oxfw->card->shortname);
247*3713d93aSTakashi Sakamoto 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ops);
248*3713d93aSTakashi Sakamoto 	return 0;
249*3713d93aSTakashi Sakamoto }
250