1da607e19SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
26eb6c81eSTakashi Sakamoto /*
36eb6c81eSTakashi Sakamoto  * dice_stream.c - a part of driver for DICE based devices
46eb6c81eSTakashi Sakamoto  *
56eb6c81eSTakashi Sakamoto  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
66eb6c81eSTakashi Sakamoto  * Copyright (c) 2014 Takashi Sakamoto <o-takashi@sakamocchi.jp>
76eb6c81eSTakashi Sakamoto  */
86eb6c81eSTakashi Sakamoto 
96eb6c81eSTakashi Sakamoto #include "dice.h"
106eb6c81eSTakashi Sakamoto 
11bdaedca7STakashi Sakamoto #define	READY_TIMEOUT_MS	200
12*41319eb5STakashi Sakamoto #define NOTIFICATION_TIMEOUT_MS	100
13288a8d0cSTakashi Sakamoto 
148cc1a8abSTakashi Sakamoto struct reg_params {
158cc1a8abSTakashi Sakamoto 	unsigned int count;
168cc1a8abSTakashi Sakamoto 	unsigned int size;
178cc1a8abSTakashi Sakamoto };
188cc1a8abSTakashi Sakamoto 
196eb6c81eSTakashi Sakamoto const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT] = {
206eb6c81eSTakashi Sakamoto 	/* mode 0 */
216eb6c81eSTakashi Sakamoto 	[0] =  32000,
226eb6c81eSTakashi Sakamoto 	[1] =  44100,
236eb6c81eSTakashi Sakamoto 	[2] =  48000,
246eb6c81eSTakashi Sakamoto 	/* mode 1 */
256eb6c81eSTakashi Sakamoto 	[3] =  88200,
266eb6c81eSTakashi Sakamoto 	[4] =  96000,
276eb6c81eSTakashi Sakamoto 	/* mode 2 */
286eb6c81eSTakashi Sakamoto 	[5] = 176400,
296eb6c81eSTakashi Sakamoto 	[6] = 192000,
306eb6c81eSTakashi Sakamoto };
316eb6c81eSTakashi Sakamoto 
32b60152f7STakashi Sakamoto int snd_dice_stream_get_rate_mode(struct snd_dice *dice, unsigned int rate,
33b60152f7STakashi Sakamoto 				  enum snd_dice_rate_mode *mode)
34b60152f7STakashi Sakamoto {
35b60152f7STakashi Sakamoto 	/* Corresponding to each entry in snd_dice_rates. */
36b60152f7STakashi Sakamoto 	static const enum snd_dice_rate_mode modes[] = {
37b60152f7STakashi Sakamoto 		[0] = SND_DICE_RATE_MODE_LOW,
38b60152f7STakashi Sakamoto 		[1] = SND_DICE_RATE_MODE_LOW,
39b60152f7STakashi Sakamoto 		[2] = SND_DICE_RATE_MODE_LOW,
40b60152f7STakashi Sakamoto 		[3] = SND_DICE_RATE_MODE_MIDDLE,
41b60152f7STakashi Sakamoto 		[4] = SND_DICE_RATE_MODE_MIDDLE,
42b60152f7STakashi Sakamoto 		[5] = SND_DICE_RATE_MODE_HIGH,
43b60152f7STakashi Sakamoto 		[6] = SND_DICE_RATE_MODE_HIGH,
44b60152f7STakashi Sakamoto 	};
45b60152f7STakashi Sakamoto 	int i;
46b60152f7STakashi Sakamoto 
47b60152f7STakashi Sakamoto 	for (i = 0; i < ARRAY_SIZE(snd_dice_rates); i++) {
48b60152f7STakashi Sakamoto 		if (!(dice->clock_caps & BIT(i)))
49b60152f7STakashi Sakamoto 			continue;
50b60152f7STakashi Sakamoto 		if (snd_dice_rates[i] != rate)
51b60152f7STakashi Sakamoto 			continue;
52b60152f7STakashi Sakamoto 
53b60152f7STakashi Sakamoto 		*mode = modes[i];
54b60152f7STakashi Sakamoto 		return 0;
55b60152f7STakashi Sakamoto 	}
56b60152f7STakashi Sakamoto 
57b60152f7STakashi Sakamoto 	return -EINVAL;
58b60152f7STakashi Sakamoto }
59b60152f7STakashi Sakamoto 
60*41319eb5STakashi Sakamoto static int select_clock(struct snd_dice *dice, unsigned int rate)
61dfabc0eeSTakashi Sakamoto {
62*41319eb5STakashi Sakamoto 	__be32 reg;
63afa617f2STakashi Sakamoto 	u32 data;
64afa617f2STakashi Sakamoto 	int i;
65dfabc0eeSTakashi Sakamoto 	int err;
66dfabc0eeSTakashi Sakamoto 
67dfabc0eeSTakashi Sakamoto 	err = snd_dice_transaction_read_global(dice, GLOBAL_CLOCK_SELECT,
68dfabc0eeSTakashi Sakamoto 					       &reg, sizeof(reg));
69dfabc0eeSTakashi Sakamoto 	if (err < 0)
70dfabc0eeSTakashi Sakamoto 		return err;
71dfabc0eeSTakashi Sakamoto 
72afa617f2STakashi Sakamoto 	data = be32_to_cpu(reg);
73afa617f2STakashi Sakamoto 
74afa617f2STakashi Sakamoto 	data &= ~CLOCK_RATE_MASK;
75afa617f2STakashi Sakamoto 	for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) {
76afa617f2STakashi Sakamoto 		if (snd_dice_rates[i] == rate)
77afa617f2STakashi Sakamoto 			break;
78afa617f2STakashi Sakamoto 	}
79afa617f2STakashi Sakamoto 	if (i == ARRAY_SIZE(snd_dice_rates))
80afa617f2STakashi Sakamoto 		return -EINVAL;
81afa617f2STakashi Sakamoto 	data |= i << CLOCK_RATE_SHIFT;
82afa617f2STakashi Sakamoto 
83dfabc0eeSTakashi Sakamoto 	if (completion_done(&dice->clock_accepted))
84dfabc0eeSTakashi Sakamoto 		reinit_completion(&dice->clock_accepted);
85dfabc0eeSTakashi Sakamoto 
86afa617f2STakashi Sakamoto 	reg = cpu_to_be32(data);
87dfabc0eeSTakashi Sakamoto 	err = snd_dice_transaction_write_global(dice, GLOBAL_CLOCK_SELECT,
88dfabc0eeSTakashi Sakamoto 						&reg, sizeof(reg));
89dfabc0eeSTakashi Sakamoto 	if (err < 0)
90dfabc0eeSTakashi Sakamoto 		return err;
91dfabc0eeSTakashi Sakamoto 
92dfabc0eeSTakashi Sakamoto 	if (wait_for_completion_timeout(&dice->clock_accepted,
93*41319eb5STakashi Sakamoto 			msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0)
94dfabc0eeSTakashi Sakamoto 		return -ETIMEDOUT;
95dfabc0eeSTakashi Sakamoto 
96dfabc0eeSTakashi Sakamoto 	return 0;
97dfabc0eeSTakashi Sakamoto }
98dfabc0eeSTakashi Sakamoto 
998cc1a8abSTakashi Sakamoto static int get_register_params(struct snd_dice *dice,
1008cc1a8abSTakashi Sakamoto 			       struct reg_params *tx_params,
1018cc1a8abSTakashi Sakamoto 			       struct reg_params *rx_params)
1026eb6c81eSTakashi Sakamoto {
103436b5abeSTakashi Sakamoto 	__be32 reg[2];
104436b5abeSTakashi Sakamoto 	int err;
1056eb6c81eSTakashi Sakamoto 
106436b5abeSTakashi Sakamoto 	err = snd_dice_transaction_read_tx(dice, TX_NUMBER, reg, sizeof(reg));
107436b5abeSTakashi Sakamoto 	if (err < 0)
108436b5abeSTakashi Sakamoto 		return err;
1098cc1a8abSTakashi Sakamoto 	tx_params->count =
1108cc1a8abSTakashi Sakamoto 			min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS);
1118cc1a8abSTakashi Sakamoto 	tx_params->size = be32_to_cpu(reg[1]) * 4;
112288a8d0cSTakashi Sakamoto 
113436b5abeSTakashi Sakamoto 	err = snd_dice_transaction_read_rx(dice, RX_NUMBER, reg, sizeof(reg));
114436b5abeSTakashi Sakamoto 	if (err < 0)
115436b5abeSTakashi Sakamoto 		return err;
1168cc1a8abSTakashi Sakamoto 	rx_params->count =
1178cc1a8abSTakashi Sakamoto 			min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS);
1188cc1a8abSTakashi Sakamoto 	rx_params->size = be32_to_cpu(reg[1]) * 4;
119436b5abeSTakashi Sakamoto 
120436b5abeSTakashi Sakamoto 	return 0;
121436b5abeSTakashi Sakamoto }
122436b5abeSTakashi Sakamoto 
123436b5abeSTakashi Sakamoto static void release_resources(struct snd_dice *dice)
124436b5abeSTakashi Sakamoto {
1253cd2c2d7STakashi Sakamoto 	int i;
126436b5abeSTakashi Sakamoto 
1273cd2c2d7STakashi Sakamoto 	for (i = 0; i < MAX_STREAMS; ++i) {
128436b5abeSTakashi Sakamoto 		fw_iso_resources_free(&dice->tx_resources[i]);
129436b5abeSTakashi Sakamoto 		fw_iso_resources_free(&dice->rx_resources[i]);
130436b5abeSTakashi Sakamoto 	}
131436b5abeSTakashi Sakamoto }
132436b5abeSTakashi Sakamoto 
133436b5abeSTakashi Sakamoto static void stop_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
1348cc1a8abSTakashi Sakamoto 			 struct reg_params *params)
135436b5abeSTakashi Sakamoto {
136436b5abeSTakashi Sakamoto 	__be32 reg;
137436b5abeSTakashi Sakamoto 	unsigned int i;
138436b5abeSTakashi Sakamoto 
1398cc1a8abSTakashi Sakamoto 	for (i = 0; i < params->count; i++) {
140436b5abeSTakashi Sakamoto 		reg = cpu_to_be32((u32)-1);
141436b5abeSTakashi Sakamoto 		if (dir == AMDTP_IN_STREAM) {
142436b5abeSTakashi Sakamoto 			snd_dice_transaction_write_tx(dice,
1438cc1a8abSTakashi Sakamoto 					params->size * i + TX_ISOCHRONOUS,
144436b5abeSTakashi Sakamoto 					&reg, sizeof(reg));
145436b5abeSTakashi Sakamoto 		} else {
146436b5abeSTakashi Sakamoto 			snd_dice_transaction_write_rx(dice,
1478cc1a8abSTakashi Sakamoto 					params->size * i + RX_ISOCHRONOUS,
148436b5abeSTakashi Sakamoto 					&reg, sizeof(reg));
149436b5abeSTakashi Sakamoto 		}
150436b5abeSTakashi Sakamoto 	}
151288a8d0cSTakashi Sakamoto }
152288a8d0cSTakashi Sakamoto 
153c738aed1STakashi Sakamoto static int keep_resources(struct snd_dice *dice, struct amdtp_stream *stream,
154c738aed1STakashi Sakamoto 			  struct fw_iso_resources *resources, unsigned int rate,
155c738aed1STakashi Sakamoto 			  unsigned int pcm_chs, unsigned int midi_ports)
156288a8d0cSTakashi Sakamoto {
15727ec83b5STakashi Sakamoto 	bool double_pcm_frames;
158436b5abeSTakashi Sakamoto 	unsigned int i;
159288a8d0cSTakashi Sakamoto 	int err;
160288a8d0cSTakashi Sakamoto 
161c738aed1STakashi Sakamoto 	// At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in
162c738aed1STakashi Sakamoto 	// one data block of AMDTP packet. Thus sampling transfer frequency is
163c738aed1STakashi Sakamoto 	// a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are
164c738aed1STakashi Sakamoto 	// transferred on AMDTP packets at 96 kHz. Two successive samples of a
165c738aed1STakashi Sakamoto 	// channel are stored consecutively in the packet. This quirk is called
166c738aed1STakashi Sakamoto 	// as 'Dual Wire'.
167c738aed1STakashi Sakamoto 	// For this quirk, blocking mode is required and PCM buffer size should
168c738aed1STakashi Sakamoto 	// be aligned to SYT_INTERVAL.
1699f079c1bSTakashi Sakamoto 	double_pcm_frames = (rate > 96000 && !dice->disable_double_pcm_frames);
17027ec83b5STakashi Sakamoto 	if (double_pcm_frames) {
171288a8d0cSTakashi Sakamoto 		rate /= 2;
172288a8d0cSTakashi Sakamoto 		pcm_chs *= 2;
173288a8d0cSTakashi Sakamoto 	}
174288a8d0cSTakashi Sakamoto 
17551c29fd2STakashi Sakamoto 	err = amdtp_am824_set_parameters(stream, rate, pcm_chs, midi_ports,
17651c29fd2STakashi Sakamoto 					 double_pcm_frames);
177547e631cSTakashi Sakamoto 	if (err < 0)
178436b5abeSTakashi Sakamoto 		return err;
179547e631cSTakashi Sakamoto 
18027ec83b5STakashi Sakamoto 	if (double_pcm_frames) {
181288a8d0cSTakashi Sakamoto 		pcm_chs /= 2;
182288a8d0cSTakashi Sakamoto 
183288a8d0cSTakashi Sakamoto 		for (i = 0; i < pcm_chs; i++) {
184f65be911STakashi Sakamoto 			amdtp_am824_set_pcm_position(stream, i, i * 2);
185f65be911STakashi Sakamoto 			amdtp_am824_set_pcm_position(stream, i + pcm_chs,
186f65be911STakashi Sakamoto 						     i * 2 + 1);
187288a8d0cSTakashi Sakamoto 		}
188288a8d0cSTakashi Sakamoto 	}
189288a8d0cSTakashi Sakamoto 
190436b5abeSTakashi Sakamoto 	return fw_iso_resources_allocate(resources,
191436b5abeSTakashi Sakamoto 				amdtp_stream_get_max_payload(stream),
192436b5abeSTakashi Sakamoto 				fw_parent_device(dice->unit)->max_speed);
193288a8d0cSTakashi Sakamoto }
194288a8d0cSTakashi Sakamoto 
195c738aed1STakashi Sakamoto static int keep_dual_resources(struct snd_dice *dice, unsigned int rate,
196c738aed1STakashi Sakamoto 			       enum amdtp_stream_direction dir,
197c738aed1STakashi Sakamoto 			       struct reg_params *params)
198c738aed1STakashi Sakamoto {
199c738aed1STakashi Sakamoto 	enum snd_dice_rate_mode mode;
200c738aed1STakashi Sakamoto 	int i;
201c738aed1STakashi Sakamoto 	int err;
202c738aed1STakashi Sakamoto 
203c738aed1STakashi Sakamoto 	err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
204c738aed1STakashi Sakamoto 	if (err < 0)
205c738aed1STakashi Sakamoto 		return err;
206c738aed1STakashi Sakamoto 
207c738aed1STakashi Sakamoto 	for (i = 0; i < params->count; ++i) {
208c738aed1STakashi Sakamoto 		__be32 reg[2];
209c738aed1STakashi Sakamoto 		struct amdtp_stream *stream;
210c738aed1STakashi Sakamoto 		struct fw_iso_resources *resources;
211c738aed1STakashi Sakamoto 		unsigned int pcm_cache;
212c738aed1STakashi Sakamoto 		unsigned int pcm_chs;
213c738aed1STakashi Sakamoto 		unsigned int midi_ports;
214c738aed1STakashi Sakamoto 
215c738aed1STakashi Sakamoto 		if (dir == AMDTP_IN_STREAM) {
216c738aed1STakashi Sakamoto 			stream = &dice->tx_stream[i];
217c738aed1STakashi Sakamoto 			resources = &dice->tx_resources[i];
218c738aed1STakashi Sakamoto 
219c738aed1STakashi Sakamoto 			pcm_cache = dice->tx_pcm_chs[i][mode];
220c738aed1STakashi Sakamoto 			err = snd_dice_transaction_read_tx(dice,
221c738aed1STakashi Sakamoto 					params->size * i + TX_NUMBER_AUDIO,
222c738aed1STakashi Sakamoto 					reg, sizeof(reg));
223c738aed1STakashi Sakamoto 		} else {
224c738aed1STakashi Sakamoto 			stream = &dice->rx_stream[i];
225c738aed1STakashi Sakamoto 			resources = &dice->rx_resources[i];
226c738aed1STakashi Sakamoto 
227c738aed1STakashi Sakamoto 			pcm_cache = dice->rx_pcm_chs[i][mode];
228c738aed1STakashi Sakamoto 			err = snd_dice_transaction_read_rx(dice,
229c738aed1STakashi Sakamoto 					params->size * i + RX_NUMBER_AUDIO,
230c738aed1STakashi Sakamoto 					reg, sizeof(reg));
231c738aed1STakashi Sakamoto 		}
232c738aed1STakashi Sakamoto 		if (err < 0)
233c738aed1STakashi Sakamoto 			return err;
234c738aed1STakashi Sakamoto 		pcm_chs = be32_to_cpu(reg[0]);
235c738aed1STakashi Sakamoto 		midi_ports = be32_to_cpu(reg[1]);
236c738aed1STakashi Sakamoto 
237c738aed1STakashi Sakamoto 		// These are important for developer of this driver.
238a9f47fcbSTakashi Sakamoto 		if (pcm_chs != pcm_cache) {
239c738aed1STakashi Sakamoto 			dev_info(&dice->unit->device,
240a9f47fcbSTakashi Sakamoto 				 "cache mismatch: pcm: %u:%u, midi: %u\n",
241a9f47fcbSTakashi Sakamoto 				 pcm_chs, pcm_cache, midi_ports);
242c738aed1STakashi Sakamoto 			return -EPROTO;
243c738aed1STakashi Sakamoto 		}
244c738aed1STakashi Sakamoto 
245c738aed1STakashi Sakamoto 		err = keep_resources(dice, stream, resources, rate, pcm_chs,
246c738aed1STakashi Sakamoto 				     midi_ports);
247c738aed1STakashi Sakamoto 		if (err < 0)
248c738aed1STakashi Sakamoto 			return err;
249c738aed1STakashi Sakamoto 	}
250c738aed1STakashi Sakamoto 
251c738aed1STakashi Sakamoto 	return 0;
252c738aed1STakashi Sakamoto }
253c738aed1STakashi Sakamoto 
254b3480638STakashi Sakamoto static void finish_session(struct snd_dice *dice, struct reg_params *tx_params,
255b3480638STakashi Sakamoto 			   struct reg_params *rx_params)
256b3480638STakashi Sakamoto {
257b3480638STakashi Sakamoto 	stop_streams(dice, AMDTP_IN_STREAM, tx_params);
258b3480638STakashi Sakamoto 	stop_streams(dice, AMDTP_OUT_STREAM, rx_params);
259b3480638STakashi Sakamoto 
260b3480638STakashi Sakamoto 	snd_dice_transaction_clear_enable(dice);
261b3480638STakashi Sakamoto }
262b3480638STakashi Sakamoto 
26394c8101aSTakashi Sakamoto int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate,
264ecb40fd2STakashi Sakamoto 				   unsigned int events_per_period,
265ecb40fd2STakashi Sakamoto 				   unsigned int events_per_buffer)
2663cd2c2d7STakashi Sakamoto {
2673cd2c2d7STakashi Sakamoto 	unsigned int curr_rate;
2683cd2c2d7STakashi Sakamoto 	int err;
2693cd2c2d7STakashi Sakamoto 
2703cd2c2d7STakashi Sakamoto 	// Check sampling transmission frequency.
2713cd2c2d7STakashi Sakamoto 	err = snd_dice_transaction_get_rate(dice, &curr_rate);
2723cd2c2d7STakashi Sakamoto 	if (err < 0)
2733cd2c2d7STakashi Sakamoto 		return err;
2743cd2c2d7STakashi Sakamoto 	if (rate == 0)
2753cd2c2d7STakashi Sakamoto 		rate = curr_rate;
2763cd2c2d7STakashi Sakamoto 
2773cd2c2d7STakashi Sakamoto 	if (dice->substreams_counter == 0 || curr_rate != rate) {
2783cd2c2d7STakashi Sakamoto 		struct reg_params tx_params, rx_params;
2793cd2c2d7STakashi Sakamoto 
280e9f21129STakashi Sakamoto 		amdtp_domain_stop(&dice->domain);
281e9f21129STakashi Sakamoto 
2823cd2c2d7STakashi Sakamoto 		err = get_register_params(dice, &tx_params, &rx_params);
2833cd2c2d7STakashi Sakamoto 		if (err < 0)
2843cd2c2d7STakashi Sakamoto 			return err;
2853cd2c2d7STakashi Sakamoto 		finish_session(dice, &tx_params, &rx_params);
2863cd2c2d7STakashi Sakamoto 
2873cd2c2d7STakashi Sakamoto 		release_resources(dice);
2883cd2c2d7STakashi Sakamoto 
2893cd2c2d7STakashi Sakamoto 		// Just after owning the unit (GLOBAL_OWNER), the unit can
2903cd2c2d7STakashi Sakamoto 		// return invalid stream formats. Selecting clock parameters
2913cd2c2d7STakashi Sakamoto 		// have an effect for the unit to refine it.
292*41319eb5STakashi Sakamoto 		err = select_clock(dice, rate);
2933cd2c2d7STakashi Sakamoto 		if (err < 0)
2943cd2c2d7STakashi Sakamoto 			return err;
2953cd2c2d7STakashi Sakamoto 
2963cd2c2d7STakashi Sakamoto 		// After changing sampling transfer frequency, the value of
2973cd2c2d7STakashi Sakamoto 		// register can be changed.
2983cd2c2d7STakashi Sakamoto 		err = get_register_params(dice, &tx_params, &rx_params);
2993cd2c2d7STakashi Sakamoto 		if (err < 0)
3003cd2c2d7STakashi Sakamoto 			return err;
3013cd2c2d7STakashi Sakamoto 
3023cd2c2d7STakashi Sakamoto 		err = keep_dual_resources(dice, rate, AMDTP_IN_STREAM,
3033cd2c2d7STakashi Sakamoto 					  &tx_params);
3043cd2c2d7STakashi Sakamoto 		if (err < 0)
3053cd2c2d7STakashi Sakamoto 			goto error;
3063cd2c2d7STakashi Sakamoto 
3073cd2c2d7STakashi Sakamoto 		err = keep_dual_resources(dice, rate, AMDTP_OUT_STREAM,
3083cd2c2d7STakashi Sakamoto 					  &rx_params);
3093cd2c2d7STakashi Sakamoto 		if (err < 0)
3103cd2c2d7STakashi Sakamoto 			goto error;
31194c8101aSTakashi Sakamoto 
31294c8101aSTakashi Sakamoto 		err = amdtp_domain_set_events_per_period(&dice->domain,
313ecb40fd2STakashi Sakamoto 					events_per_period, events_per_buffer);
31494c8101aSTakashi Sakamoto 		if (err < 0)
31594c8101aSTakashi Sakamoto 			goto error;
3163cd2c2d7STakashi Sakamoto 	}
3173cd2c2d7STakashi Sakamoto 
3183cd2c2d7STakashi Sakamoto 	return 0;
3193cd2c2d7STakashi Sakamoto error:
3203cd2c2d7STakashi Sakamoto 	release_resources(dice);
3213cd2c2d7STakashi Sakamoto 	return err;
3223cd2c2d7STakashi Sakamoto }
3233cd2c2d7STakashi Sakamoto 
324436b5abeSTakashi Sakamoto static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
3258cc1a8abSTakashi Sakamoto 			 unsigned int rate, struct reg_params *params)
326436b5abeSTakashi Sakamoto {
327c738aed1STakashi Sakamoto 	unsigned int max_speed = fw_parent_device(dice->unit)->max_speed;
328c738aed1STakashi Sakamoto 	int i;
329c738aed1STakashi Sakamoto 	int err;
330436b5abeSTakashi Sakamoto 
3318cc1a8abSTakashi Sakamoto 	for (i = 0; i < params->count; i++) {
332c738aed1STakashi Sakamoto 		struct amdtp_stream *stream;
333c738aed1STakashi Sakamoto 		struct fw_iso_resources *resources;
334c738aed1STakashi Sakamoto 		__be32 reg;
335afa617f2STakashi Sakamoto 
336436b5abeSTakashi Sakamoto 		if (dir == AMDTP_IN_STREAM) {
337c738aed1STakashi Sakamoto 			stream = dice->tx_stream + i;
338c738aed1STakashi Sakamoto 			resources = dice->tx_resources + i;
339436b5abeSTakashi Sakamoto 		} else {
340c738aed1STakashi Sakamoto 			stream = dice->rx_stream + i;
341c738aed1STakashi Sakamoto 			resources = dice->rx_resources + i;
342afa617f2STakashi Sakamoto 		}
343afa617f2STakashi Sakamoto 
344c738aed1STakashi Sakamoto 		reg = cpu_to_be32(resources->channel);
345436b5abeSTakashi Sakamoto 		if (dir == AMDTP_IN_STREAM) {
346436b5abeSTakashi Sakamoto 			err = snd_dice_transaction_write_tx(dice,
3478cc1a8abSTakashi Sakamoto 					params->size * i + TX_ISOCHRONOUS,
348c738aed1STakashi Sakamoto 					&reg, sizeof(reg));
349436b5abeSTakashi Sakamoto 		} else {
350436b5abeSTakashi Sakamoto 			err = snd_dice_transaction_write_rx(dice,
3518cc1a8abSTakashi Sakamoto 					params->size * i + RX_ISOCHRONOUS,
352c738aed1STakashi Sakamoto 					&reg, sizeof(reg));
353436b5abeSTakashi Sakamoto 		}
354436b5abeSTakashi Sakamoto 		if (err < 0)
355436b5abeSTakashi Sakamoto 			return err;
356436b5abeSTakashi Sakamoto 
357b0e159feSTakashi Sakamoto 		if (dir == AMDTP_IN_STREAM) {
358c738aed1STakashi Sakamoto 			reg = cpu_to_be32(max_speed);
359b0e159feSTakashi Sakamoto 			err = snd_dice_transaction_write_tx(dice,
360b0e159feSTakashi Sakamoto 					params->size * i + TX_SPEED,
361c738aed1STakashi Sakamoto 					&reg, sizeof(reg));
362b0e159feSTakashi Sakamoto 			if (err < 0)
363b0e159feSTakashi Sakamoto 				return err;
364b0e159feSTakashi Sakamoto 		}
365b0e159feSTakashi Sakamoto 
366e9f21129STakashi Sakamoto 		err = amdtp_domain_add_stream(&dice->domain, stream,
367e9f21129STakashi Sakamoto 					      resources->channel, max_speed);
368288a8d0cSTakashi Sakamoto 		if (err < 0)
369288a8d0cSTakashi Sakamoto 			return err;
370288a8d0cSTakashi Sakamoto 	}
371288a8d0cSTakashi Sakamoto 
372c72d3a0aSTakashi Sakamoto 	return 0;
373436b5abeSTakashi Sakamoto }
374436b5abeSTakashi Sakamoto 
3753cd2c2d7STakashi Sakamoto /*
3763cd2c2d7STakashi Sakamoto  * MEMO: After this function, there're two states of streams:
3773cd2c2d7STakashi Sakamoto  *  - None streams are running.
3783cd2c2d7STakashi Sakamoto  *  - All streams are running.
3793cd2c2d7STakashi Sakamoto  */
3803cd2c2d7STakashi Sakamoto int snd_dice_stream_start_duplex(struct snd_dice *dice)
38120b94544STakashi Sakamoto {
382d5553026STakashi Sakamoto 	unsigned int generation = dice->rx_resources[0].generation;
38320b94544STakashi Sakamoto 	struct reg_params tx_params, rx_params;
3843cd2c2d7STakashi Sakamoto 	unsigned int i;
3853cd2c2d7STakashi Sakamoto 	unsigned int rate;
3863cd2c2d7STakashi Sakamoto 	enum snd_dice_rate_mode mode;
38720b94544STakashi Sakamoto 	int err;
38820b94544STakashi Sakamoto 
3893cd2c2d7STakashi Sakamoto 	if (dice->substreams_counter == 0)
3903cd2c2d7STakashi Sakamoto 		return -EIO;
3913cd2c2d7STakashi Sakamoto 
39220b94544STakashi Sakamoto 	err = get_register_params(dice, &tx_params, &rx_params);
39320b94544STakashi Sakamoto 	if (err < 0)
39420b94544STakashi Sakamoto 		return err;
39520b94544STakashi Sakamoto 
3963cd2c2d7STakashi Sakamoto 	// Check error of packet streaming.
3973cd2c2d7STakashi Sakamoto 	for (i = 0; i < MAX_STREAMS; ++i) {
3983cd2c2d7STakashi Sakamoto 		if (amdtp_streaming_error(&dice->tx_stream[i]) ||
3993cd2c2d7STakashi Sakamoto 		    amdtp_streaming_error(&dice->rx_stream[i])) {
400e9f21129STakashi Sakamoto 			amdtp_domain_stop(&dice->domain);
401b3480638STakashi Sakamoto 			finish_session(dice, &tx_params, &rx_params);
4023cd2c2d7STakashi Sakamoto 			break;
4033cd2c2d7STakashi Sakamoto 		}
40420b94544STakashi Sakamoto 	}
40520b94544STakashi Sakamoto 
406d5553026STakashi Sakamoto 	if (generation != fw_parent_device(dice->unit)->card->generation) {
407d5553026STakashi Sakamoto 		for (i = 0; i < MAX_STREAMS; ++i) {
408d5553026STakashi Sakamoto 			if (i < tx_params.count)
409d5553026STakashi Sakamoto 				fw_iso_resources_update(dice->tx_resources + i);
410d5553026STakashi Sakamoto 			if (i < rx_params.count)
411d5553026STakashi Sakamoto 				fw_iso_resources_update(dice->rx_resources + i);
412d5553026STakashi Sakamoto 		}
413d5553026STakashi Sakamoto 	}
414d5553026STakashi Sakamoto 
4153cd2c2d7STakashi Sakamoto 	// Check required streams are running or not.
4163cd2c2d7STakashi Sakamoto 	err = snd_dice_transaction_get_rate(dice, &rate);
417afa617f2STakashi Sakamoto 	if (err < 0)
418afa617f2STakashi Sakamoto 		return err;
4193cd2c2d7STakashi Sakamoto 	err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
4203cd2c2d7STakashi Sakamoto 	if (err < 0)
4213cd2c2d7STakashi Sakamoto 		return err;
4223cd2c2d7STakashi Sakamoto 	for (i = 0; i < MAX_STREAMS; ++i) {
4233cd2c2d7STakashi Sakamoto 		if (dice->tx_pcm_chs[i][mode] > 0 &&
4243cd2c2d7STakashi Sakamoto 		    !amdtp_stream_running(&dice->tx_stream[i]))
4253cd2c2d7STakashi Sakamoto 			break;
4263cd2c2d7STakashi Sakamoto 		if (dice->rx_pcm_chs[i][mode] > 0 &&
4273cd2c2d7STakashi Sakamoto 		    !amdtp_stream_running(&dice->rx_stream[i]))
4283cd2c2d7STakashi Sakamoto 			break;
4293cd2c2d7STakashi Sakamoto 	}
4303cd2c2d7STakashi Sakamoto 	if (i < MAX_STREAMS) {
4313cd2c2d7STakashi Sakamoto 		// Start both streams.
43220b94544STakashi Sakamoto 		err = start_streams(dice, AMDTP_IN_STREAM, rate, &tx_params);
43320b94544STakashi Sakamoto 		if (err < 0)
43420b94544STakashi Sakamoto 			goto error;
4353cd2c2d7STakashi Sakamoto 
43620b94544STakashi Sakamoto 		err = start_streams(dice, AMDTP_OUT_STREAM, rate, &rx_params);
43720b94544STakashi Sakamoto 		if (err < 0)
43820b94544STakashi Sakamoto 			goto error;
43920b94544STakashi Sakamoto 
44020b94544STakashi Sakamoto 		err = snd_dice_transaction_set_enable(dice);
44120b94544STakashi Sakamoto 		if (err < 0) {
4423cd2c2d7STakashi Sakamoto 			dev_err(&dice->unit->device,
4433cd2c2d7STakashi Sakamoto 				"fail to enable interface\n");
44420b94544STakashi Sakamoto 			goto error;
44520b94544STakashi Sakamoto 		}
44620b94544STakashi Sakamoto 
4472f21a177STakashi Sakamoto 		err = amdtp_domain_start(&dice->domain, 0, false, false);
448e9f21129STakashi Sakamoto 		if (err < 0)
449e9f21129STakashi Sakamoto 			goto error;
450e9f21129STakashi Sakamoto 
451bdaedca7STakashi Sakamoto 		if (!amdtp_domain_wait_ready(&dice->domain, READY_TIMEOUT_MS)) {
45220b94544STakashi Sakamoto 			err = -ETIMEDOUT;
45320b94544STakashi Sakamoto 			goto error;
45420b94544STakashi Sakamoto 		}
45520b94544STakashi Sakamoto 	}
45620b94544STakashi Sakamoto 
45720b94544STakashi Sakamoto 	return 0;
45820b94544STakashi Sakamoto error:
459e9f21129STakashi Sakamoto 	amdtp_domain_stop(&dice->domain);
460b3480638STakashi Sakamoto 	finish_session(dice, &tx_params, &rx_params);
46120b94544STakashi Sakamoto 	return err;
46220b94544STakashi Sakamoto }
46320b94544STakashi Sakamoto 
464436b5abeSTakashi Sakamoto /*
465436b5abeSTakashi Sakamoto  * MEMO: After this function, there're two states of streams:
466436b5abeSTakashi Sakamoto  *  - None streams are running.
467436b5abeSTakashi Sakamoto  *  - All streams are running.
468436b5abeSTakashi Sakamoto  */
4699a02843cSTakashi Sakamoto void snd_dice_stream_stop_duplex(struct snd_dice *dice)
4706eb6c81eSTakashi Sakamoto {
4718cc1a8abSTakashi Sakamoto 	struct reg_params tx_params, rx_params;
472436b5abeSTakashi Sakamoto 
4733cd2c2d7STakashi Sakamoto 	if (dice->substreams_counter == 0) {
474dd7b836dSTakashi Sakamoto 		if (get_register_params(dice, &tx_params, &rx_params) >= 0)
475b3480638STakashi Sakamoto 			finish_session(dice, &tx_params, &rx_params);
476740680f2STakashi Sakamoto 
477dd7b836dSTakashi Sakamoto 		amdtp_domain_stop(&dice->domain);
478740680f2STakashi Sakamoto 		release_resources(dice);
4793cd2c2d7STakashi Sakamoto 	}
480436b5abeSTakashi Sakamoto }
4819a02843cSTakashi Sakamoto 
482436b5abeSTakashi Sakamoto static int init_stream(struct snd_dice *dice, enum amdtp_stream_direction dir,
483436b5abeSTakashi Sakamoto 		       unsigned int index)
484436b5abeSTakashi Sakamoto {
485436b5abeSTakashi Sakamoto 	struct amdtp_stream *stream;
486436b5abeSTakashi Sakamoto 	struct fw_iso_resources *resources;
487436b5abeSTakashi Sakamoto 	int err;
488436b5abeSTakashi Sakamoto 
489436b5abeSTakashi Sakamoto 	if (dir == AMDTP_IN_STREAM) {
490436b5abeSTakashi Sakamoto 		stream = &dice->tx_stream[index];
491436b5abeSTakashi Sakamoto 		resources = &dice->tx_resources[index];
4929a02843cSTakashi Sakamoto 	} else {
493436b5abeSTakashi Sakamoto 		stream = &dice->rx_stream[index];
494436b5abeSTakashi Sakamoto 		resources = &dice->rx_resources[index];
4959a02843cSTakashi Sakamoto 	}
4969a02843cSTakashi Sakamoto 
4979a02843cSTakashi Sakamoto 	err = fw_iso_resources_init(resources, dice->unit);
4989a02843cSTakashi Sakamoto 	if (err < 0)
4999a02843cSTakashi Sakamoto 		goto end;
5009a02843cSTakashi Sakamoto 	resources->channels_mask = 0x00000000ffffffffuLL;
5019a02843cSTakashi Sakamoto 
5025955815eSTakashi Sakamoto 	err = amdtp_am824_init(stream, dice->unit, dir, CIP_BLOCKING);
5039a02843cSTakashi Sakamoto 	if (err < 0) {
5049a02843cSTakashi Sakamoto 		amdtp_stream_destroy(stream);
5059a02843cSTakashi Sakamoto 		fw_iso_resources_destroy(resources);
5069a02843cSTakashi Sakamoto 	}
5079a02843cSTakashi Sakamoto end:
5089a02843cSTakashi Sakamoto 	return err;
5099a02843cSTakashi Sakamoto }
5109a02843cSTakashi Sakamoto 
511d23c2cc4STakashi Sakamoto /*
512d23c2cc4STakashi Sakamoto  * This function should be called before starting streams or after stopping
513d23c2cc4STakashi Sakamoto  * streams.
514d23c2cc4STakashi Sakamoto  */
515436b5abeSTakashi Sakamoto static void destroy_stream(struct snd_dice *dice,
516436b5abeSTakashi Sakamoto 			   enum amdtp_stream_direction dir,
517436b5abeSTakashi Sakamoto 			   unsigned int index)
5189a02843cSTakashi Sakamoto {
519436b5abeSTakashi Sakamoto 	struct amdtp_stream *stream;
520d23c2cc4STakashi Sakamoto 	struct fw_iso_resources *resources;
5219a02843cSTakashi Sakamoto 
522436b5abeSTakashi Sakamoto 	if (dir == AMDTP_IN_STREAM) {
523436b5abeSTakashi Sakamoto 		stream = &dice->tx_stream[index];
524436b5abeSTakashi Sakamoto 		resources = &dice->tx_resources[index];
525436b5abeSTakashi Sakamoto 	} else {
526436b5abeSTakashi Sakamoto 		stream = &dice->rx_stream[index];
527436b5abeSTakashi Sakamoto 		resources = &dice->rx_resources[index];
528436b5abeSTakashi Sakamoto 	}
529d23c2cc4STakashi Sakamoto 
530d23c2cc4STakashi Sakamoto 	amdtp_stream_destroy(stream);
531d23c2cc4STakashi Sakamoto 	fw_iso_resources_destroy(resources);
5329a02843cSTakashi Sakamoto }
5339a02843cSTakashi Sakamoto 
5349a02843cSTakashi Sakamoto int snd_dice_stream_init_duplex(struct snd_dice *dice)
5356eb6c81eSTakashi Sakamoto {
536436b5abeSTakashi Sakamoto 	int i, err;
5376eb6c81eSTakashi Sakamoto 
538436b5abeSTakashi Sakamoto 	for (i = 0; i < MAX_STREAMS; i++) {
539436b5abeSTakashi Sakamoto 		err = init_stream(dice, AMDTP_IN_STREAM, i);
540436b5abeSTakashi Sakamoto 		if (err < 0) {
541436b5abeSTakashi Sakamoto 			for (; i >= 0; i--)
5420f925660STakashi Sakamoto 				destroy_stream(dice, AMDTP_IN_STREAM, i);
5436eb6c81eSTakashi Sakamoto 			goto end;
544436b5abeSTakashi Sakamoto 		}
545436b5abeSTakashi Sakamoto 	}
5466eb6c81eSTakashi Sakamoto 
547436b5abeSTakashi Sakamoto 	for (i = 0; i < MAX_STREAMS; i++) {
548436b5abeSTakashi Sakamoto 		err = init_stream(dice, AMDTP_OUT_STREAM, i);
549436b5abeSTakashi Sakamoto 		if (err < 0) {
550436b5abeSTakashi Sakamoto 			for (; i >= 0; i--)
551436b5abeSTakashi Sakamoto 				destroy_stream(dice, AMDTP_OUT_STREAM, i);
552436b5abeSTakashi Sakamoto 			for (i = 0; i < MAX_STREAMS; i++)
553436b5abeSTakashi Sakamoto 				destroy_stream(dice, AMDTP_IN_STREAM, i);
5546e26d193STakashi Sakamoto 			goto end;
555436b5abeSTakashi Sakamoto 		}
556436b5abeSTakashi Sakamoto 	}
557e9f21129STakashi Sakamoto 
558e9f21129STakashi Sakamoto 	err = amdtp_domain_init(&dice->domain);
559e9f21129STakashi Sakamoto 	if (err < 0) {
560e9f21129STakashi Sakamoto 		for (i = 0; i < MAX_STREAMS; ++i) {
561e9f21129STakashi Sakamoto 			destroy_stream(dice, AMDTP_OUT_STREAM, i);
562e9f21129STakashi Sakamoto 			destroy_stream(dice, AMDTP_IN_STREAM, i);
563e9f21129STakashi Sakamoto 		}
564e9f21129STakashi Sakamoto 	}
5656eb6c81eSTakashi Sakamoto end:
5666eb6c81eSTakashi Sakamoto 	return err;
5676eb6c81eSTakashi Sakamoto }
5686eb6c81eSTakashi Sakamoto 
5699a02843cSTakashi Sakamoto void snd_dice_stream_destroy_duplex(struct snd_dice *dice)
5706eb6c81eSTakashi Sakamoto {
5716b94fb14STakashi Sakamoto 	unsigned int i;
572436b5abeSTakashi Sakamoto 
5736b94fb14STakashi Sakamoto 	for (i = 0; i < MAX_STREAMS; i++) {
5746b94fb14STakashi Sakamoto 		destroy_stream(dice, AMDTP_IN_STREAM, i);
5756b94fb14STakashi Sakamoto 		destroy_stream(dice, AMDTP_OUT_STREAM, i);
576436b5abeSTakashi Sakamoto 	}
577e9f21129STakashi Sakamoto 
578e9f21129STakashi Sakamoto 	amdtp_domain_destroy(&dice->domain);
5796eb6c81eSTakashi Sakamoto }
5806eb6c81eSTakashi Sakamoto 
5819a02843cSTakashi Sakamoto void snd_dice_stream_update_duplex(struct snd_dice *dice)
5826eb6c81eSTakashi Sakamoto {
5838cc1a8abSTakashi Sakamoto 	struct reg_params tx_params, rx_params;
584436b5abeSTakashi Sakamoto 
5856eb6c81eSTakashi Sakamoto 	/*
5866eb6c81eSTakashi Sakamoto 	 * On a bus reset, the DICE firmware disables streaming and then goes
5876eb6c81eSTakashi Sakamoto 	 * off contemplating its own navel for hundreds of milliseconds before
5886eb6c81eSTakashi Sakamoto 	 * it can react to any of our attempts to reenable streaming.  This
5896eb6c81eSTakashi Sakamoto 	 * means that we lose synchronization anyway, so we force our streams
5906eb6c81eSTakashi Sakamoto 	 * to stop so that the application can restart them in an orderly
5916eb6c81eSTakashi Sakamoto 	 * manner.
5926eb6c81eSTakashi Sakamoto 	 */
5936eb6c81eSTakashi Sakamoto 	dice->global_enabled = false;
5946eb6c81eSTakashi Sakamoto 
5958cc1a8abSTakashi Sakamoto 	if (get_register_params(dice, &tx_params, &rx_params) == 0) {
596e9f21129STakashi Sakamoto 		amdtp_domain_stop(&dice->domain);
597e9f21129STakashi Sakamoto 
5988cc1a8abSTakashi Sakamoto 		stop_streams(dice, AMDTP_IN_STREAM, &tx_params);
5998cc1a8abSTakashi Sakamoto 		stop_streams(dice, AMDTP_OUT_STREAM, &rx_params);
600436b5abeSTakashi Sakamoto 	}
6016eb6c81eSTakashi Sakamoto }
6026eb6c81eSTakashi Sakamoto 
603b60152f7STakashi Sakamoto int snd_dice_stream_detect_current_formats(struct snd_dice *dice)
604b60152f7STakashi Sakamoto {
605b60152f7STakashi Sakamoto 	unsigned int rate;
606b60152f7STakashi Sakamoto 	enum snd_dice_rate_mode mode;
607b60152f7STakashi Sakamoto 	__be32 reg[2];
608b60152f7STakashi Sakamoto 	struct reg_params tx_params, rx_params;
609b60152f7STakashi Sakamoto 	int i;
610b60152f7STakashi Sakamoto 	int err;
611b60152f7STakashi Sakamoto 
61258579c05STakashi Sakamoto 	/* If extended protocol is available, detect detail spec. */
61358579c05STakashi Sakamoto 	err = snd_dice_detect_extension_formats(dice);
61458579c05STakashi Sakamoto 	if (err >= 0)
61558579c05STakashi Sakamoto 		return err;
61658579c05STakashi Sakamoto 
617b60152f7STakashi Sakamoto 	/*
618b60152f7STakashi Sakamoto 	 * Available stream format is restricted at current mode of sampling
619b60152f7STakashi Sakamoto 	 * clock.
620b60152f7STakashi Sakamoto 	 */
621b60152f7STakashi Sakamoto 	err = snd_dice_transaction_get_rate(dice, &rate);
622b60152f7STakashi Sakamoto 	if (err < 0)
623b60152f7STakashi Sakamoto 		return err;
624b60152f7STakashi Sakamoto 
625b60152f7STakashi Sakamoto 	err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
626b60152f7STakashi Sakamoto 	if (err < 0)
627b60152f7STakashi Sakamoto 		return err;
628b60152f7STakashi Sakamoto 
629b60152f7STakashi Sakamoto 	/*
630b60152f7STakashi Sakamoto 	 * Just after owning the unit (GLOBAL_OWNER), the unit can return
631b60152f7STakashi Sakamoto 	 * invalid stream formats. Selecting clock parameters have an effect
632b60152f7STakashi Sakamoto 	 * for the unit to refine it.
633b60152f7STakashi Sakamoto 	 */
634*41319eb5STakashi Sakamoto 	err = select_clock(dice, rate);
635b60152f7STakashi Sakamoto 	if (err < 0)
636b60152f7STakashi Sakamoto 		return err;
637b60152f7STakashi Sakamoto 
638b60152f7STakashi Sakamoto 	err = get_register_params(dice, &tx_params, &rx_params);
639b60152f7STakashi Sakamoto 	if (err < 0)
640b60152f7STakashi Sakamoto 		return err;
641b60152f7STakashi Sakamoto 
642b60152f7STakashi Sakamoto 	for (i = 0; i < tx_params.count; ++i) {
643b60152f7STakashi Sakamoto 		err = snd_dice_transaction_read_tx(dice,
644b60152f7STakashi Sakamoto 				tx_params.size * i + TX_NUMBER_AUDIO,
645b60152f7STakashi Sakamoto 				reg, sizeof(reg));
646b60152f7STakashi Sakamoto 		if (err < 0)
647b60152f7STakashi Sakamoto 			return err;
648b60152f7STakashi Sakamoto 		dice->tx_pcm_chs[i][mode] = be32_to_cpu(reg[0]);
649b60152f7STakashi Sakamoto 		dice->tx_midi_ports[i] = max_t(unsigned int,
650b60152f7STakashi Sakamoto 				be32_to_cpu(reg[1]), dice->tx_midi_ports[i]);
651b60152f7STakashi Sakamoto 	}
652b60152f7STakashi Sakamoto 	for (i = 0; i < rx_params.count; ++i) {
653b60152f7STakashi Sakamoto 		err = snd_dice_transaction_read_rx(dice,
654b60152f7STakashi Sakamoto 				rx_params.size * i + RX_NUMBER_AUDIO,
655b60152f7STakashi Sakamoto 				reg, sizeof(reg));
656b60152f7STakashi Sakamoto 		if (err < 0)
657b60152f7STakashi Sakamoto 			return err;
658b60152f7STakashi Sakamoto 		dice->rx_pcm_chs[i][mode] = be32_to_cpu(reg[0]);
659b60152f7STakashi Sakamoto 		dice->rx_midi_ports[i] = max_t(unsigned int,
660b60152f7STakashi Sakamoto 				be32_to_cpu(reg[1]), dice->rx_midi_ports[i]);
661b60152f7STakashi Sakamoto 	}
662b60152f7STakashi Sakamoto 
663b60152f7STakashi Sakamoto 	return 0;
664b60152f7STakashi Sakamoto }
665b60152f7STakashi Sakamoto 
6666eb6c81eSTakashi Sakamoto static void dice_lock_changed(struct snd_dice *dice)
6676eb6c81eSTakashi Sakamoto {
6686eb6c81eSTakashi Sakamoto 	dice->dev_lock_changed = true;
6696eb6c81eSTakashi Sakamoto 	wake_up(&dice->hwdep_wait);
6706eb6c81eSTakashi Sakamoto }
6716eb6c81eSTakashi Sakamoto 
6726eb6c81eSTakashi Sakamoto int snd_dice_stream_lock_try(struct snd_dice *dice)
6736eb6c81eSTakashi Sakamoto {
6746eb6c81eSTakashi Sakamoto 	int err;
6756eb6c81eSTakashi Sakamoto 
6766eb6c81eSTakashi Sakamoto 	spin_lock_irq(&dice->lock);
6776eb6c81eSTakashi Sakamoto 
6786eb6c81eSTakashi Sakamoto 	if (dice->dev_lock_count < 0) {
6796eb6c81eSTakashi Sakamoto 		err = -EBUSY;
6806eb6c81eSTakashi Sakamoto 		goto out;
6816eb6c81eSTakashi Sakamoto 	}
6826eb6c81eSTakashi Sakamoto 
6836eb6c81eSTakashi Sakamoto 	if (dice->dev_lock_count++ == 0)
6846eb6c81eSTakashi Sakamoto 		dice_lock_changed(dice);
6856eb6c81eSTakashi Sakamoto 	err = 0;
6866eb6c81eSTakashi Sakamoto out:
6876eb6c81eSTakashi Sakamoto 	spin_unlock_irq(&dice->lock);
6886eb6c81eSTakashi Sakamoto 	return err;
6896eb6c81eSTakashi Sakamoto }
6906eb6c81eSTakashi Sakamoto 
6916eb6c81eSTakashi Sakamoto void snd_dice_stream_lock_release(struct snd_dice *dice)
6926eb6c81eSTakashi Sakamoto {
6936eb6c81eSTakashi Sakamoto 	spin_lock_irq(&dice->lock);
6946eb6c81eSTakashi Sakamoto 
6956eb6c81eSTakashi Sakamoto 	if (WARN_ON(dice->dev_lock_count <= 0))
6966eb6c81eSTakashi Sakamoto 		goto out;
6976eb6c81eSTakashi Sakamoto 
6986eb6c81eSTakashi Sakamoto 	if (--dice->dev_lock_count == 0)
6996eb6c81eSTakashi Sakamoto 		dice_lock_changed(dice);
7006eb6c81eSTakashi Sakamoto out:
7016eb6c81eSTakashi Sakamoto 	spin_unlock_irq(&dice->lock);
7026eb6c81eSTakashi Sakamoto }
703