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 
11288a8d0cSTakashi Sakamoto #define	CALLBACK_TIMEOUT	200
12dfabc0eeSTakashi Sakamoto #define NOTIFICATION_TIMEOUT_MS	(2 * MSEC_PER_SEC)
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 
60dfabc0eeSTakashi Sakamoto /*
61dfabc0eeSTakashi Sakamoto  * This operation has an effect to synchronize GLOBAL_STATUS/GLOBAL_SAMPLE_RATE
62dfabc0eeSTakashi Sakamoto  * to GLOBAL_STATUS. Especially, just after powering on, these are different.
63dfabc0eeSTakashi Sakamoto  */
64afa617f2STakashi Sakamoto static int ensure_phase_lock(struct snd_dice *dice, unsigned int rate)
65dfabc0eeSTakashi Sakamoto {
66fbeac84dSTakashi Sakamoto 	__be32 reg, nominal;
67afa617f2STakashi Sakamoto 	u32 data;
68afa617f2STakashi Sakamoto 	int i;
69dfabc0eeSTakashi Sakamoto 	int err;
70dfabc0eeSTakashi Sakamoto 
71dfabc0eeSTakashi Sakamoto 	err = snd_dice_transaction_read_global(dice, GLOBAL_CLOCK_SELECT,
72dfabc0eeSTakashi Sakamoto 					       &reg, sizeof(reg));
73dfabc0eeSTakashi Sakamoto 	if (err < 0)
74dfabc0eeSTakashi Sakamoto 		return err;
75dfabc0eeSTakashi Sakamoto 
76afa617f2STakashi Sakamoto 	data = be32_to_cpu(reg);
77afa617f2STakashi Sakamoto 
78afa617f2STakashi Sakamoto 	data &= ~CLOCK_RATE_MASK;
79afa617f2STakashi Sakamoto 	for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) {
80afa617f2STakashi Sakamoto 		if (snd_dice_rates[i] == rate)
81afa617f2STakashi Sakamoto 			break;
82afa617f2STakashi Sakamoto 	}
83afa617f2STakashi Sakamoto 	if (i == ARRAY_SIZE(snd_dice_rates))
84afa617f2STakashi Sakamoto 		return -EINVAL;
85afa617f2STakashi Sakamoto 	data |= i << CLOCK_RATE_SHIFT;
86afa617f2STakashi Sakamoto 
87dfabc0eeSTakashi Sakamoto 	if (completion_done(&dice->clock_accepted))
88dfabc0eeSTakashi Sakamoto 		reinit_completion(&dice->clock_accepted);
89dfabc0eeSTakashi Sakamoto 
90afa617f2STakashi Sakamoto 	reg = cpu_to_be32(data);
91dfabc0eeSTakashi Sakamoto 	err = snd_dice_transaction_write_global(dice, GLOBAL_CLOCK_SELECT,
92dfabc0eeSTakashi Sakamoto 						&reg, sizeof(reg));
93dfabc0eeSTakashi Sakamoto 	if (err < 0)
94dfabc0eeSTakashi Sakamoto 		return err;
95dfabc0eeSTakashi Sakamoto 
96dfabc0eeSTakashi Sakamoto 	if (wait_for_completion_timeout(&dice->clock_accepted,
97fbeac84dSTakashi Sakamoto 			msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0) {
98fbeac84dSTakashi Sakamoto 		/*
99fbeac84dSTakashi Sakamoto 		 * Old versions of Dice firmware transfer no notification when
100fbeac84dSTakashi Sakamoto 		 * the same clock status as current one is set. In this case,
101fbeac84dSTakashi Sakamoto 		 * just check current clock status.
102fbeac84dSTakashi Sakamoto 		 */
103fbeac84dSTakashi Sakamoto 		err = snd_dice_transaction_read_global(dice, GLOBAL_STATUS,
104fbeac84dSTakashi Sakamoto 						&nominal, sizeof(nominal));
105fbeac84dSTakashi Sakamoto 		if (err < 0)
106fbeac84dSTakashi Sakamoto 			return err;
107fbeac84dSTakashi Sakamoto 		if (!(be32_to_cpu(nominal) & STATUS_SOURCE_LOCKED))
108dfabc0eeSTakashi Sakamoto 			return -ETIMEDOUT;
109fbeac84dSTakashi Sakamoto 	}
110dfabc0eeSTakashi Sakamoto 
111dfabc0eeSTakashi Sakamoto 	return 0;
112dfabc0eeSTakashi Sakamoto }
113dfabc0eeSTakashi Sakamoto 
1148cc1a8abSTakashi Sakamoto static int get_register_params(struct snd_dice *dice,
1158cc1a8abSTakashi Sakamoto 			       struct reg_params *tx_params,
1168cc1a8abSTakashi Sakamoto 			       struct reg_params *rx_params)
1176eb6c81eSTakashi Sakamoto {
118436b5abeSTakashi Sakamoto 	__be32 reg[2];
119436b5abeSTakashi Sakamoto 	int err;
1206eb6c81eSTakashi Sakamoto 
121436b5abeSTakashi Sakamoto 	err = snd_dice_transaction_read_tx(dice, TX_NUMBER, reg, sizeof(reg));
122436b5abeSTakashi Sakamoto 	if (err < 0)
123436b5abeSTakashi Sakamoto 		return err;
1248cc1a8abSTakashi Sakamoto 	tx_params->count =
1258cc1a8abSTakashi Sakamoto 			min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS);
1268cc1a8abSTakashi Sakamoto 	tx_params->size = be32_to_cpu(reg[1]) * 4;
127288a8d0cSTakashi Sakamoto 
128436b5abeSTakashi Sakamoto 	err = snd_dice_transaction_read_rx(dice, RX_NUMBER, reg, sizeof(reg));
129436b5abeSTakashi Sakamoto 	if (err < 0)
130436b5abeSTakashi Sakamoto 		return err;
1318cc1a8abSTakashi Sakamoto 	rx_params->count =
1328cc1a8abSTakashi Sakamoto 			min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS);
1338cc1a8abSTakashi Sakamoto 	rx_params->size = be32_to_cpu(reg[1]) * 4;
134436b5abeSTakashi Sakamoto 
135436b5abeSTakashi Sakamoto 	return 0;
136436b5abeSTakashi Sakamoto }
137436b5abeSTakashi Sakamoto 
138436b5abeSTakashi Sakamoto static void release_resources(struct snd_dice *dice)
139436b5abeSTakashi Sakamoto {
140436b5abeSTakashi Sakamoto 	unsigned int i;
141436b5abeSTakashi Sakamoto 
142436b5abeSTakashi Sakamoto 	for (i = 0; i < MAX_STREAMS; i++) {
143436b5abeSTakashi Sakamoto 		if (amdtp_stream_running(&dice->tx_stream[i])) {
144436b5abeSTakashi Sakamoto 			amdtp_stream_pcm_abort(&dice->tx_stream[i]);
145436b5abeSTakashi Sakamoto 			amdtp_stream_stop(&dice->tx_stream[i]);
146436b5abeSTakashi Sakamoto 		}
147436b5abeSTakashi Sakamoto 		if (amdtp_stream_running(&dice->rx_stream[i])) {
148436b5abeSTakashi Sakamoto 			amdtp_stream_pcm_abort(&dice->rx_stream[i]);
149436b5abeSTakashi Sakamoto 			amdtp_stream_stop(&dice->rx_stream[i]);
150436b5abeSTakashi Sakamoto 		}
151436b5abeSTakashi Sakamoto 
152436b5abeSTakashi Sakamoto 		fw_iso_resources_free(&dice->tx_resources[i]);
153436b5abeSTakashi Sakamoto 		fw_iso_resources_free(&dice->rx_resources[i]);
154436b5abeSTakashi Sakamoto 	}
155436b5abeSTakashi Sakamoto }
156436b5abeSTakashi Sakamoto 
157436b5abeSTakashi Sakamoto static void stop_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
1588cc1a8abSTakashi Sakamoto 			 struct reg_params *params)
159436b5abeSTakashi Sakamoto {
160436b5abeSTakashi Sakamoto 	__be32 reg;
161436b5abeSTakashi Sakamoto 	unsigned int i;
162436b5abeSTakashi Sakamoto 
1638cc1a8abSTakashi Sakamoto 	for (i = 0; i < params->count; i++) {
164436b5abeSTakashi Sakamoto 		reg = cpu_to_be32((u32)-1);
165436b5abeSTakashi Sakamoto 		if (dir == AMDTP_IN_STREAM) {
166436b5abeSTakashi Sakamoto 			snd_dice_transaction_write_tx(dice,
1678cc1a8abSTakashi Sakamoto 					params->size * i + TX_ISOCHRONOUS,
168436b5abeSTakashi Sakamoto 					&reg, sizeof(reg));
169436b5abeSTakashi Sakamoto 		} else {
170436b5abeSTakashi Sakamoto 			snd_dice_transaction_write_rx(dice,
1718cc1a8abSTakashi Sakamoto 					params->size * i + RX_ISOCHRONOUS,
172436b5abeSTakashi Sakamoto 					&reg, sizeof(reg));
173436b5abeSTakashi Sakamoto 		}
174436b5abeSTakashi Sakamoto 	}
175288a8d0cSTakashi Sakamoto }
176288a8d0cSTakashi Sakamoto 
1779a02843cSTakashi Sakamoto static int keep_resources(struct snd_dice *dice,
178436b5abeSTakashi Sakamoto 			  enum amdtp_stream_direction dir, unsigned int index,
179436b5abeSTakashi Sakamoto 			  unsigned int rate, unsigned int pcm_chs,
180436b5abeSTakashi Sakamoto 			  unsigned int midi_ports)
181288a8d0cSTakashi Sakamoto {
182436b5abeSTakashi Sakamoto 	struct amdtp_stream *stream;
1839a02843cSTakashi Sakamoto 	struct fw_iso_resources *resources;
18427ec83b5STakashi Sakamoto 	bool double_pcm_frames;
185436b5abeSTakashi Sakamoto 	unsigned int i;
186288a8d0cSTakashi Sakamoto 	int err;
187288a8d0cSTakashi Sakamoto 
188436b5abeSTakashi Sakamoto 	if (dir == AMDTP_IN_STREAM) {
189436b5abeSTakashi Sakamoto 		stream = &dice->tx_stream[index];
190436b5abeSTakashi Sakamoto 		resources = &dice->tx_resources[index];
1919a02843cSTakashi Sakamoto 	} else {
192436b5abeSTakashi Sakamoto 		stream = &dice->rx_stream[index];
193436b5abeSTakashi Sakamoto 		resources = &dice->rx_resources[index];
1949a02843cSTakashi Sakamoto 	}
195288a8d0cSTakashi Sakamoto 
196288a8d0cSTakashi Sakamoto 	/*
197288a8d0cSTakashi Sakamoto 	 * At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in
198288a8d0cSTakashi Sakamoto 	 * one data block of AMDTP packet. Thus sampling transfer frequency is
199288a8d0cSTakashi Sakamoto 	 * a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are
200288a8d0cSTakashi Sakamoto 	 * transferred on AMDTP packets at 96 kHz. Two successive samples of a
201288a8d0cSTakashi Sakamoto 	 * channel are stored consecutively in the packet. This quirk is called
202288a8d0cSTakashi Sakamoto 	 * as 'Dual Wire'.
203288a8d0cSTakashi Sakamoto 	 * For this quirk, blocking mode is required and PCM buffer size should
204288a8d0cSTakashi Sakamoto 	 * be aligned to SYT_INTERVAL.
205288a8d0cSTakashi Sakamoto 	 */
2066f688268STakashi Sakamoto 	double_pcm_frames = rate > 96000;
20727ec83b5STakashi Sakamoto 	if (double_pcm_frames) {
208288a8d0cSTakashi Sakamoto 		rate /= 2;
209288a8d0cSTakashi Sakamoto 		pcm_chs *= 2;
210288a8d0cSTakashi Sakamoto 	}
211288a8d0cSTakashi Sakamoto 
21251c29fd2STakashi Sakamoto 	err = amdtp_am824_set_parameters(stream, rate, pcm_chs, midi_ports,
21351c29fd2STakashi Sakamoto 					 double_pcm_frames);
214547e631cSTakashi Sakamoto 	if (err < 0)
215436b5abeSTakashi Sakamoto 		return err;
216547e631cSTakashi Sakamoto 
21727ec83b5STakashi Sakamoto 	if (double_pcm_frames) {
218288a8d0cSTakashi Sakamoto 		pcm_chs /= 2;
219288a8d0cSTakashi Sakamoto 
220288a8d0cSTakashi Sakamoto 		for (i = 0; i < pcm_chs; i++) {
221f65be911STakashi Sakamoto 			amdtp_am824_set_pcm_position(stream, i, i * 2);
222f65be911STakashi Sakamoto 			amdtp_am824_set_pcm_position(stream, i + pcm_chs,
223f65be911STakashi Sakamoto 						     i * 2 + 1);
224288a8d0cSTakashi Sakamoto 		}
225288a8d0cSTakashi Sakamoto 	}
226288a8d0cSTakashi Sakamoto 
227436b5abeSTakashi Sakamoto 	return fw_iso_resources_allocate(resources,
228436b5abeSTakashi Sakamoto 				amdtp_stream_get_max_payload(stream),
229436b5abeSTakashi Sakamoto 				fw_parent_device(dice->unit)->max_speed);
230288a8d0cSTakashi Sakamoto }
231288a8d0cSTakashi Sakamoto 
232436b5abeSTakashi Sakamoto static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
2338cc1a8abSTakashi Sakamoto 			 unsigned int rate, struct reg_params *params)
234436b5abeSTakashi Sakamoto {
235436b5abeSTakashi Sakamoto 	__be32 reg[2];
236afa617f2STakashi Sakamoto 	enum snd_dice_rate_mode mode;
237436b5abeSTakashi Sakamoto 	unsigned int i, pcm_chs, midi_ports;
238436b5abeSTakashi Sakamoto 	struct amdtp_stream *streams;
239436b5abeSTakashi Sakamoto 	struct fw_iso_resources *resources;
240b0e159feSTakashi Sakamoto 	struct fw_device *fw_dev = fw_parent_device(dice->unit);
241436b5abeSTakashi Sakamoto 	int err = 0;
242436b5abeSTakashi Sakamoto 
243436b5abeSTakashi Sakamoto 	if (dir == AMDTP_IN_STREAM) {
244436b5abeSTakashi Sakamoto 		streams = dice->tx_stream;
245436b5abeSTakashi Sakamoto 		resources = dice->tx_resources;
246436b5abeSTakashi Sakamoto 	} else {
247436b5abeSTakashi Sakamoto 		streams = dice->rx_stream;
248436b5abeSTakashi Sakamoto 		resources = dice->rx_resources;
249436b5abeSTakashi Sakamoto 	}
250436b5abeSTakashi Sakamoto 
251afa617f2STakashi Sakamoto 	err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
252afa617f2STakashi Sakamoto 	if (err < 0)
253afa617f2STakashi Sakamoto 		return err;
254afa617f2STakashi Sakamoto 
2558cc1a8abSTakashi Sakamoto 	for (i = 0; i < params->count; i++) {
256afa617f2STakashi Sakamoto 		unsigned int pcm_cache;
257afa617f2STakashi Sakamoto 		unsigned int midi_cache;
258afa617f2STakashi Sakamoto 
259436b5abeSTakashi Sakamoto 		if (dir == AMDTP_IN_STREAM) {
260afa617f2STakashi Sakamoto 			pcm_cache = dice->tx_pcm_chs[i][mode];
261afa617f2STakashi Sakamoto 			midi_cache = dice->tx_midi_ports[i];
262436b5abeSTakashi Sakamoto 			err = snd_dice_transaction_read_tx(dice,
2638cc1a8abSTakashi Sakamoto 					params->size * i + TX_NUMBER_AUDIO,
264436b5abeSTakashi Sakamoto 					reg, sizeof(reg));
265436b5abeSTakashi Sakamoto 		} else {
266afa617f2STakashi Sakamoto 			pcm_cache = dice->rx_pcm_chs[i][mode];
267afa617f2STakashi Sakamoto 			midi_cache = dice->rx_midi_ports[i];
268436b5abeSTakashi Sakamoto 			err = snd_dice_transaction_read_rx(dice,
2698cc1a8abSTakashi Sakamoto 					params->size * i + RX_NUMBER_AUDIO,
270436b5abeSTakashi Sakamoto 					reg, sizeof(reg));
271436b5abeSTakashi Sakamoto 		}
272436b5abeSTakashi Sakamoto 		if (err < 0)
273436b5abeSTakashi Sakamoto 			return err;
274436b5abeSTakashi Sakamoto 		pcm_chs = be32_to_cpu(reg[0]);
275436b5abeSTakashi Sakamoto 		midi_ports = be32_to_cpu(reg[1]);
276436b5abeSTakashi Sakamoto 
277afa617f2STakashi Sakamoto 		/* These are important for developer of this driver. */
278afa617f2STakashi Sakamoto 		if (pcm_chs != pcm_cache || midi_ports != midi_cache) {
279afa617f2STakashi Sakamoto 			dev_info(&dice->unit->device,
280afa617f2STakashi Sakamoto 				 "cache mismatch: pcm: %u:%u, midi: %u:%u\n",
281afa617f2STakashi Sakamoto 				 pcm_chs, pcm_cache, midi_ports, midi_cache);
282afa617f2STakashi Sakamoto 			return -EPROTO;
283afa617f2STakashi Sakamoto 		}
284afa617f2STakashi Sakamoto 
285436b5abeSTakashi Sakamoto 		err = keep_resources(dice, dir, i, rate, pcm_chs, midi_ports);
286436b5abeSTakashi Sakamoto 		if (err < 0)
287436b5abeSTakashi Sakamoto 			return err;
288436b5abeSTakashi Sakamoto 
289436b5abeSTakashi Sakamoto 		reg[0] = cpu_to_be32(resources[i].channel);
290436b5abeSTakashi Sakamoto 		if (dir == AMDTP_IN_STREAM) {
291436b5abeSTakashi Sakamoto 			err = snd_dice_transaction_write_tx(dice,
2928cc1a8abSTakashi Sakamoto 					params->size * i + TX_ISOCHRONOUS,
293436b5abeSTakashi Sakamoto 					reg, sizeof(reg[0]));
294436b5abeSTakashi Sakamoto 		} else {
295436b5abeSTakashi Sakamoto 			err = snd_dice_transaction_write_rx(dice,
2968cc1a8abSTakashi Sakamoto 					params->size * i + RX_ISOCHRONOUS,
297436b5abeSTakashi Sakamoto 					reg, sizeof(reg[0]));
298436b5abeSTakashi Sakamoto 		}
299436b5abeSTakashi Sakamoto 		if (err < 0)
300436b5abeSTakashi Sakamoto 			return err;
301436b5abeSTakashi Sakamoto 
302b0e159feSTakashi Sakamoto 		if (dir == AMDTP_IN_STREAM) {
303b0e159feSTakashi Sakamoto 			reg[0] = cpu_to_be32(fw_dev->max_speed);
304b0e159feSTakashi Sakamoto 			err = snd_dice_transaction_write_tx(dice,
305b0e159feSTakashi Sakamoto 					params->size * i + TX_SPEED,
306b0e159feSTakashi Sakamoto 					reg, sizeof(reg[0]));
307b0e159feSTakashi Sakamoto 			if (err < 0)
308b0e159feSTakashi Sakamoto 				return err;
309b0e159feSTakashi Sakamoto 		}
310b0e159feSTakashi Sakamoto 
311436b5abeSTakashi Sakamoto 		err = amdtp_stream_start(&streams[i], resources[i].channel,
312b0e159feSTakashi Sakamoto 					 fw_dev->max_speed);
313288a8d0cSTakashi Sakamoto 		if (err < 0)
314288a8d0cSTakashi Sakamoto 			return err;
315288a8d0cSTakashi Sakamoto 	}
316288a8d0cSTakashi Sakamoto 
317436b5abeSTakashi Sakamoto 	return err;
318436b5abeSTakashi Sakamoto }
319436b5abeSTakashi Sakamoto 
32020b94544STakashi Sakamoto static int start_duplex_streams(struct snd_dice *dice, unsigned int rate)
32120b94544STakashi Sakamoto {
32220b94544STakashi Sakamoto 	struct reg_params tx_params, rx_params;
32320b94544STakashi Sakamoto 	int i;
32420b94544STakashi Sakamoto 	int err;
32520b94544STakashi Sakamoto 
32620b94544STakashi Sakamoto 	err = get_register_params(dice, &tx_params, &rx_params);
32720b94544STakashi Sakamoto 	if (err < 0)
32820b94544STakashi Sakamoto 		return err;
32920b94544STakashi Sakamoto 
33020b94544STakashi Sakamoto 	/* Stop transmission. */
33120b94544STakashi Sakamoto 	stop_streams(dice, AMDTP_IN_STREAM, &tx_params);
33220b94544STakashi Sakamoto 	stop_streams(dice, AMDTP_OUT_STREAM, &rx_params);
33320b94544STakashi Sakamoto 	snd_dice_transaction_clear_enable(dice);
33420b94544STakashi Sakamoto 	release_resources(dice);
33520b94544STakashi Sakamoto 
336afa617f2STakashi Sakamoto 	err = ensure_phase_lock(dice, rate);
33720b94544STakashi Sakamoto 	if (err < 0) {
33820b94544STakashi Sakamoto 		dev_err(&dice->unit->device, "fail to ensure phase lock\n");
33920b94544STakashi Sakamoto 		return err;
34020b94544STakashi Sakamoto 	}
34120b94544STakashi Sakamoto 
342afa617f2STakashi Sakamoto 	/* Likely to have changed stream formats. */
343afa617f2STakashi Sakamoto 	err = get_register_params(dice, &tx_params, &rx_params);
344afa617f2STakashi Sakamoto 	if (err < 0)
345afa617f2STakashi Sakamoto 		return err;
346afa617f2STakashi Sakamoto 
34720b94544STakashi Sakamoto 	/* Start both streams. */
34820b94544STakashi Sakamoto 	err = start_streams(dice, AMDTP_IN_STREAM, rate, &tx_params);
34920b94544STakashi Sakamoto 	if (err < 0)
35020b94544STakashi Sakamoto 		goto error;
35120b94544STakashi Sakamoto 	err = start_streams(dice, AMDTP_OUT_STREAM, rate, &rx_params);
35220b94544STakashi Sakamoto 	if (err < 0)
35320b94544STakashi Sakamoto 		goto error;
35420b94544STakashi Sakamoto 
35520b94544STakashi Sakamoto 	err = snd_dice_transaction_set_enable(dice);
35620b94544STakashi Sakamoto 	if (err < 0) {
35720b94544STakashi Sakamoto 		dev_err(&dice->unit->device, "fail to enable interface\n");
35820b94544STakashi Sakamoto 		goto error;
35920b94544STakashi Sakamoto 	}
36020b94544STakashi Sakamoto 
36120b94544STakashi Sakamoto 	for (i = 0; i < MAX_STREAMS; i++) {
36220b94544STakashi Sakamoto 		if ((i < tx_params.count &&
36320b94544STakashi Sakamoto 		    !amdtp_stream_wait_callback(&dice->tx_stream[i],
36420b94544STakashi Sakamoto 						CALLBACK_TIMEOUT)) ||
36520b94544STakashi Sakamoto 		    (i < rx_params.count &&
36620b94544STakashi Sakamoto 		     !amdtp_stream_wait_callback(&dice->rx_stream[i],
36720b94544STakashi Sakamoto 						 CALLBACK_TIMEOUT))) {
36820b94544STakashi Sakamoto 			err = -ETIMEDOUT;
36920b94544STakashi Sakamoto 			goto error;
37020b94544STakashi Sakamoto 		}
37120b94544STakashi Sakamoto 	}
37220b94544STakashi Sakamoto 
37320b94544STakashi Sakamoto 	return 0;
37420b94544STakashi Sakamoto error:
37520b94544STakashi Sakamoto 	stop_streams(dice, AMDTP_IN_STREAM, &tx_params);
37620b94544STakashi Sakamoto 	stop_streams(dice, AMDTP_OUT_STREAM, &rx_params);
37720b94544STakashi Sakamoto 	snd_dice_transaction_clear_enable(dice);
37820b94544STakashi Sakamoto 	release_resources(dice);
37920b94544STakashi Sakamoto 	return err;
38020b94544STakashi Sakamoto }
38120b94544STakashi Sakamoto 
382436b5abeSTakashi Sakamoto /*
383436b5abeSTakashi Sakamoto  * MEMO: After this function, there're two states of streams:
384436b5abeSTakashi Sakamoto  *  - None streams are running.
385436b5abeSTakashi Sakamoto  *  - All streams are running.
386436b5abeSTakashi Sakamoto  */
3879a02843cSTakashi Sakamoto int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate)
3889a02843cSTakashi Sakamoto {
389288a8d0cSTakashi Sakamoto 	unsigned int curr_rate;
390436b5abeSTakashi Sakamoto 	unsigned int i;
391ec592fd3STakashi Sakamoto 	enum snd_dice_rate_mode mode;
392436b5abeSTakashi Sakamoto 	int err;
3939a02843cSTakashi Sakamoto 
3949a02843cSTakashi Sakamoto 	if (dice->substreams_counter == 0)
395436b5abeSTakashi Sakamoto 		return -EIO;
3969a02843cSTakashi Sakamoto 
397ec592fd3STakashi Sakamoto 	/* Check sampling transmission frequency. */
398288a8d0cSTakashi Sakamoto 	err = snd_dice_transaction_get_rate(dice, &curr_rate);
399288a8d0cSTakashi Sakamoto 	if (err < 0) {
400288a8d0cSTakashi Sakamoto 		dev_err(&dice->unit->device,
401288a8d0cSTakashi Sakamoto 			"fail to get sampling rate\n");
402436b5abeSTakashi Sakamoto 		return err;
403288a8d0cSTakashi Sakamoto 	}
404a113ff88STakashi Sakamoto 	if (rate == 0)
405a113ff88STakashi Sakamoto 		rate = curr_rate;
406436b5abeSTakashi Sakamoto 	if (rate != curr_rate)
407afa617f2STakashi Sakamoto 		goto restart;
408288a8d0cSTakashi Sakamoto 
409ec592fd3STakashi Sakamoto 	/* Check error of packet streaming. */
410ec592fd3STakashi Sakamoto 	for (i = 0; i < MAX_STREAMS; ++i) {
411ec592fd3STakashi Sakamoto 		if (amdtp_streaming_error(&dice->tx_stream[i]))
412ec592fd3STakashi Sakamoto 			break;
413ec592fd3STakashi Sakamoto 		if (amdtp_streaming_error(&dice->rx_stream[i]))
414436b5abeSTakashi Sakamoto 			break;
415436b5abeSTakashi Sakamoto 	}
416ec592fd3STakashi Sakamoto 	if (i < MAX_STREAMS)
41720b94544STakashi Sakamoto 		goto restart;
418ec592fd3STakashi Sakamoto 
419ec592fd3STakashi Sakamoto 	/* Check required streams are running or not. */
420ec592fd3STakashi Sakamoto 	err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
421ec592fd3STakashi Sakamoto 	if (err < 0)
422ec592fd3STakashi Sakamoto 		return err;
423ec592fd3STakashi Sakamoto 	for (i = 0; i < MAX_STREAMS; ++i) {
424ec592fd3STakashi Sakamoto 		if (dice->tx_pcm_chs[i][mode] > 0 &&
425ec592fd3STakashi Sakamoto 		    !amdtp_stream_running(&dice->tx_stream[i]))
426ec592fd3STakashi Sakamoto 			break;
427ec592fd3STakashi Sakamoto 		if (dice->rx_pcm_chs[i][mode] > 0 &&
428436b5abeSTakashi Sakamoto 		    !amdtp_stream_running(&dice->rx_stream[i]))
429436b5abeSTakashi Sakamoto 			break;
430436b5abeSTakashi Sakamoto 	}
431ec592fd3STakashi Sakamoto 	if (i < MAX_STREAMS)
43220b94544STakashi Sakamoto 		goto restart;
433436b5abeSTakashi Sakamoto 
43420b94544STakashi Sakamoto 	return 0;
43520b94544STakashi Sakamoto restart:
43620b94544STakashi Sakamoto 	return start_duplex_streams(dice, rate);
4376eb6c81eSTakashi Sakamoto }
4386eb6c81eSTakashi Sakamoto 
439436b5abeSTakashi Sakamoto /*
440436b5abeSTakashi Sakamoto  * MEMO: After this function, there're two states of streams:
441436b5abeSTakashi Sakamoto  *  - None streams are running.
442436b5abeSTakashi Sakamoto  *  - All streams are running.
443436b5abeSTakashi Sakamoto  */
4449a02843cSTakashi Sakamoto void snd_dice_stream_stop_duplex(struct snd_dice *dice)
4456eb6c81eSTakashi Sakamoto {
4468cc1a8abSTakashi Sakamoto 	struct reg_params tx_params, rx_params;
447436b5abeSTakashi Sakamoto 
4489a02843cSTakashi Sakamoto 	if (dice->substreams_counter > 0)
4499a02843cSTakashi Sakamoto 		return;
4509a02843cSTakashi Sakamoto 
451288a8d0cSTakashi Sakamoto 	snd_dice_transaction_clear_enable(dice);
4529a02843cSTakashi Sakamoto 
4538cc1a8abSTakashi Sakamoto 	if (get_register_params(dice, &tx_params, &rx_params) == 0) {
4548cc1a8abSTakashi Sakamoto 		stop_streams(dice, AMDTP_IN_STREAM, &tx_params);
4558cc1a8abSTakashi Sakamoto 		stop_streams(dice, AMDTP_OUT_STREAM, &rx_params);
4566eb6c81eSTakashi Sakamoto 	}
4576eb6c81eSTakashi Sakamoto 
458436b5abeSTakashi Sakamoto 	release_resources(dice);
459436b5abeSTakashi Sakamoto }
4609a02843cSTakashi Sakamoto 
461436b5abeSTakashi Sakamoto static int init_stream(struct snd_dice *dice, enum amdtp_stream_direction dir,
462436b5abeSTakashi Sakamoto 		       unsigned int index)
463436b5abeSTakashi Sakamoto {
464436b5abeSTakashi Sakamoto 	struct amdtp_stream *stream;
465436b5abeSTakashi Sakamoto 	struct fw_iso_resources *resources;
466436b5abeSTakashi Sakamoto 	int err;
467436b5abeSTakashi Sakamoto 
468436b5abeSTakashi Sakamoto 	if (dir == AMDTP_IN_STREAM) {
469436b5abeSTakashi Sakamoto 		stream = &dice->tx_stream[index];
470436b5abeSTakashi Sakamoto 		resources = &dice->tx_resources[index];
4719a02843cSTakashi Sakamoto 	} else {
472436b5abeSTakashi Sakamoto 		stream = &dice->rx_stream[index];
473436b5abeSTakashi Sakamoto 		resources = &dice->rx_resources[index];
4749a02843cSTakashi Sakamoto 	}
4759a02843cSTakashi Sakamoto 
4769a02843cSTakashi Sakamoto 	err = fw_iso_resources_init(resources, dice->unit);
4779a02843cSTakashi Sakamoto 	if (err < 0)
4789a02843cSTakashi Sakamoto 		goto end;
4799a02843cSTakashi Sakamoto 	resources->channels_mask = 0x00000000ffffffffuLL;
4809a02843cSTakashi Sakamoto 
4815955815eSTakashi Sakamoto 	err = amdtp_am824_init(stream, dice->unit, dir, CIP_BLOCKING);
4829a02843cSTakashi Sakamoto 	if (err < 0) {
4839a02843cSTakashi Sakamoto 		amdtp_stream_destroy(stream);
4849a02843cSTakashi Sakamoto 		fw_iso_resources_destroy(resources);
4859a02843cSTakashi Sakamoto 	}
4869a02843cSTakashi Sakamoto end:
4879a02843cSTakashi Sakamoto 	return err;
4889a02843cSTakashi Sakamoto }
4899a02843cSTakashi Sakamoto 
490d23c2cc4STakashi Sakamoto /*
491d23c2cc4STakashi Sakamoto  * This function should be called before starting streams or after stopping
492d23c2cc4STakashi Sakamoto  * streams.
493d23c2cc4STakashi Sakamoto  */
494436b5abeSTakashi Sakamoto static void destroy_stream(struct snd_dice *dice,
495436b5abeSTakashi Sakamoto 			   enum amdtp_stream_direction dir,
496436b5abeSTakashi Sakamoto 			   unsigned int index)
4979a02843cSTakashi Sakamoto {
498436b5abeSTakashi Sakamoto 	struct amdtp_stream *stream;
499d23c2cc4STakashi Sakamoto 	struct fw_iso_resources *resources;
5009a02843cSTakashi Sakamoto 
501436b5abeSTakashi Sakamoto 	if (dir == AMDTP_IN_STREAM) {
502436b5abeSTakashi Sakamoto 		stream = &dice->tx_stream[index];
503436b5abeSTakashi Sakamoto 		resources = &dice->tx_resources[index];
504436b5abeSTakashi Sakamoto 	} else {
505436b5abeSTakashi Sakamoto 		stream = &dice->rx_stream[index];
506436b5abeSTakashi Sakamoto 		resources = &dice->rx_resources[index];
507436b5abeSTakashi Sakamoto 	}
508d23c2cc4STakashi Sakamoto 
509d23c2cc4STakashi Sakamoto 	amdtp_stream_destroy(stream);
510d23c2cc4STakashi Sakamoto 	fw_iso_resources_destroy(resources);
5119a02843cSTakashi Sakamoto }
5129a02843cSTakashi Sakamoto 
5139a02843cSTakashi Sakamoto int snd_dice_stream_init_duplex(struct snd_dice *dice)
5146eb6c81eSTakashi Sakamoto {
515436b5abeSTakashi Sakamoto 	int i, err;
5166eb6c81eSTakashi Sakamoto 
517436b5abeSTakashi Sakamoto 	for (i = 0; i < MAX_STREAMS; i++) {
518436b5abeSTakashi Sakamoto 		err = init_stream(dice, AMDTP_IN_STREAM, i);
519436b5abeSTakashi Sakamoto 		if (err < 0) {
520436b5abeSTakashi Sakamoto 			for (; i >= 0; i--)
5210f925660STakashi Sakamoto 				destroy_stream(dice, AMDTP_IN_STREAM, i);
5226eb6c81eSTakashi Sakamoto 			goto end;
523436b5abeSTakashi Sakamoto 		}
524436b5abeSTakashi Sakamoto 	}
5256eb6c81eSTakashi Sakamoto 
526436b5abeSTakashi Sakamoto 	for (i = 0; i < MAX_STREAMS; i++) {
527436b5abeSTakashi Sakamoto 		err = init_stream(dice, AMDTP_OUT_STREAM, i);
528436b5abeSTakashi Sakamoto 		if (err < 0) {
529436b5abeSTakashi Sakamoto 			for (; i >= 0; i--)
530436b5abeSTakashi Sakamoto 				destroy_stream(dice, AMDTP_OUT_STREAM, i);
531436b5abeSTakashi Sakamoto 			for (i = 0; i < MAX_STREAMS; i++)
532436b5abeSTakashi Sakamoto 				destroy_stream(dice, AMDTP_IN_STREAM, i);
533436b5abeSTakashi Sakamoto 			break;
534436b5abeSTakashi Sakamoto 		}
535436b5abeSTakashi Sakamoto 	}
5366eb6c81eSTakashi Sakamoto end:
5376eb6c81eSTakashi Sakamoto 	return err;
5386eb6c81eSTakashi Sakamoto }
5396eb6c81eSTakashi Sakamoto 
5409a02843cSTakashi Sakamoto void snd_dice_stream_destroy_duplex(struct snd_dice *dice)
5416eb6c81eSTakashi Sakamoto {
5426b94fb14STakashi Sakamoto 	unsigned int i;
543436b5abeSTakashi Sakamoto 
5446b94fb14STakashi Sakamoto 	for (i = 0; i < MAX_STREAMS; i++) {
5456b94fb14STakashi Sakamoto 		destroy_stream(dice, AMDTP_IN_STREAM, i);
5466b94fb14STakashi Sakamoto 		destroy_stream(dice, AMDTP_OUT_STREAM, i);
547436b5abeSTakashi Sakamoto 	}
5486eb6c81eSTakashi Sakamoto }
5496eb6c81eSTakashi Sakamoto 
5509a02843cSTakashi Sakamoto void snd_dice_stream_update_duplex(struct snd_dice *dice)
5516eb6c81eSTakashi Sakamoto {
5528cc1a8abSTakashi Sakamoto 	struct reg_params tx_params, rx_params;
553436b5abeSTakashi Sakamoto 
5546eb6c81eSTakashi Sakamoto 	/*
5556eb6c81eSTakashi Sakamoto 	 * On a bus reset, the DICE firmware disables streaming and then goes
5566eb6c81eSTakashi Sakamoto 	 * off contemplating its own navel for hundreds of milliseconds before
5576eb6c81eSTakashi Sakamoto 	 * it can react to any of our attempts to reenable streaming.  This
5586eb6c81eSTakashi Sakamoto 	 * means that we lose synchronization anyway, so we force our streams
5596eb6c81eSTakashi Sakamoto 	 * to stop so that the application can restart them in an orderly
5606eb6c81eSTakashi Sakamoto 	 * manner.
5616eb6c81eSTakashi Sakamoto 	 */
5626eb6c81eSTakashi Sakamoto 	dice->global_enabled = false;
5636eb6c81eSTakashi Sakamoto 
5648cc1a8abSTakashi Sakamoto 	if (get_register_params(dice, &tx_params, &rx_params) == 0) {
5658cc1a8abSTakashi Sakamoto 		stop_streams(dice, AMDTP_IN_STREAM, &tx_params);
5668cc1a8abSTakashi Sakamoto 		stop_streams(dice, AMDTP_OUT_STREAM, &rx_params);
567436b5abeSTakashi Sakamoto 	}
5686eb6c81eSTakashi Sakamoto }
5696eb6c81eSTakashi Sakamoto 
570b60152f7STakashi Sakamoto int snd_dice_stream_detect_current_formats(struct snd_dice *dice)
571b60152f7STakashi Sakamoto {
572b60152f7STakashi Sakamoto 	unsigned int rate;
573b60152f7STakashi Sakamoto 	enum snd_dice_rate_mode mode;
574b60152f7STakashi Sakamoto 	__be32 reg[2];
575b60152f7STakashi Sakamoto 	struct reg_params tx_params, rx_params;
576b60152f7STakashi Sakamoto 	int i;
577b60152f7STakashi Sakamoto 	int err;
578b60152f7STakashi Sakamoto 
57958579c05STakashi Sakamoto 	/* If extended protocol is available, detect detail spec. */
58058579c05STakashi Sakamoto 	err = snd_dice_detect_extension_formats(dice);
58158579c05STakashi Sakamoto 	if (err >= 0)
58258579c05STakashi Sakamoto 		return err;
58358579c05STakashi Sakamoto 
584b60152f7STakashi Sakamoto 	/*
585b60152f7STakashi Sakamoto 	 * Available stream format is restricted at current mode of sampling
586b60152f7STakashi Sakamoto 	 * clock.
587b60152f7STakashi Sakamoto 	 */
588b60152f7STakashi Sakamoto 	err = snd_dice_transaction_get_rate(dice, &rate);
589b60152f7STakashi Sakamoto 	if (err < 0)
590b60152f7STakashi Sakamoto 		return err;
591b60152f7STakashi Sakamoto 
592b60152f7STakashi Sakamoto 	err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
593b60152f7STakashi Sakamoto 	if (err < 0)
594b60152f7STakashi Sakamoto 		return err;
595b60152f7STakashi Sakamoto 
596b60152f7STakashi Sakamoto 	/*
597b60152f7STakashi Sakamoto 	 * Just after owning the unit (GLOBAL_OWNER), the unit can return
598b60152f7STakashi Sakamoto 	 * invalid stream formats. Selecting clock parameters have an effect
599b60152f7STakashi Sakamoto 	 * for the unit to refine it.
600b60152f7STakashi Sakamoto 	 */
601afa617f2STakashi Sakamoto 	err = ensure_phase_lock(dice, rate);
602b60152f7STakashi Sakamoto 	if (err < 0)
603b60152f7STakashi Sakamoto 		return err;
604b60152f7STakashi Sakamoto 
605b60152f7STakashi Sakamoto 	err = get_register_params(dice, &tx_params, &rx_params);
606b60152f7STakashi Sakamoto 	if (err < 0)
607b60152f7STakashi Sakamoto 		return err;
608b60152f7STakashi Sakamoto 
609b60152f7STakashi Sakamoto 	for (i = 0; i < tx_params.count; ++i) {
610b60152f7STakashi Sakamoto 		err = snd_dice_transaction_read_tx(dice,
611b60152f7STakashi Sakamoto 				tx_params.size * i + TX_NUMBER_AUDIO,
612b60152f7STakashi Sakamoto 				reg, sizeof(reg));
613b60152f7STakashi Sakamoto 		if (err < 0)
614b60152f7STakashi Sakamoto 			return err;
615b60152f7STakashi Sakamoto 		dice->tx_pcm_chs[i][mode] = be32_to_cpu(reg[0]);
616b60152f7STakashi Sakamoto 		dice->tx_midi_ports[i] = max_t(unsigned int,
617b60152f7STakashi Sakamoto 				be32_to_cpu(reg[1]), dice->tx_midi_ports[i]);
618b60152f7STakashi Sakamoto 	}
619b60152f7STakashi Sakamoto 	for (i = 0; i < rx_params.count; ++i) {
620b60152f7STakashi Sakamoto 		err = snd_dice_transaction_read_rx(dice,
621b60152f7STakashi Sakamoto 				rx_params.size * i + RX_NUMBER_AUDIO,
622b60152f7STakashi Sakamoto 				reg, sizeof(reg));
623b60152f7STakashi Sakamoto 		if (err < 0)
624b60152f7STakashi Sakamoto 			return err;
625b60152f7STakashi Sakamoto 		dice->rx_pcm_chs[i][mode] = be32_to_cpu(reg[0]);
626b60152f7STakashi Sakamoto 		dice->rx_midi_ports[i] = max_t(unsigned int,
627b60152f7STakashi Sakamoto 				be32_to_cpu(reg[1]), dice->rx_midi_ports[i]);
628b60152f7STakashi Sakamoto 	}
629b60152f7STakashi Sakamoto 
630b60152f7STakashi Sakamoto 	return 0;
631b60152f7STakashi Sakamoto }
632b60152f7STakashi Sakamoto 
6336eb6c81eSTakashi Sakamoto static void dice_lock_changed(struct snd_dice *dice)
6346eb6c81eSTakashi Sakamoto {
6356eb6c81eSTakashi Sakamoto 	dice->dev_lock_changed = true;
6366eb6c81eSTakashi Sakamoto 	wake_up(&dice->hwdep_wait);
6376eb6c81eSTakashi Sakamoto }
6386eb6c81eSTakashi Sakamoto 
6396eb6c81eSTakashi Sakamoto int snd_dice_stream_lock_try(struct snd_dice *dice)
6406eb6c81eSTakashi Sakamoto {
6416eb6c81eSTakashi Sakamoto 	int err;
6426eb6c81eSTakashi Sakamoto 
6436eb6c81eSTakashi Sakamoto 	spin_lock_irq(&dice->lock);
6446eb6c81eSTakashi Sakamoto 
6456eb6c81eSTakashi Sakamoto 	if (dice->dev_lock_count < 0) {
6466eb6c81eSTakashi Sakamoto 		err = -EBUSY;
6476eb6c81eSTakashi Sakamoto 		goto out;
6486eb6c81eSTakashi Sakamoto 	}
6496eb6c81eSTakashi Sakamoto 
6506eb6c81eSTakashi Sakamoto 	if (dice->dev_lock_count++ == 0)
6516eb6c81eSTakashi Sakamoto 		dice_lock_changed(dice);
6526eb6c81eSTakashi Sakamoto 	err = 0;
6536eb6c81eSTakashi Sakamoto out:
6546eb6c81eSTakashi Sakamoto 	spin_unlock_irq(&dice->lock);
6556eb6c81eSTakashi Sakamoto 	return err;
6566eb6c81eSTakashi Sakamoto }
6576eb6c81eSTakashi Sakamoto 
6586eb6c81eSTakashi Sakamoto void snd_dice_stream_lock_release(struct snd_dice *dice)
6596eb6c81eSTakashi Sakamoto {
6606eb6c81eSTakashi Sakamoto 	spin_lock_irq(&dice->lock);
6616eb6c81eSTakashi Sakamoto 
6626eb6c81eSTakashi Sakamoto 	if (WARN_ON(dice->dev_lock_count <= 0))
6636eb6c81eSTakashi Sakamoto 		goto out;
6646eb6c81eSTakashi Sakamoto 
6656eb6c81eSTakashi Sakamoto 	if (--dice->dev_lock_count == 0)
6666eb6c81eSTakashi Sakamoto 		dice_lock_changed(dice);
6676eb6c81eSTakashi Sakamoto out:
6686eb6c81eSTakashi Sakamoto 	spin_unlock_irq(&dice->lock);
6696eb6c81eSTakashi Sakamoto }
670