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 ®, 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 ®, 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 { 1403cd2c2d7STakashi Sakamoto int i; 141436b5abeSTakashi Sakamoto 1423cd2c2d7STakashi Sakamoto for (i = 0; i < MAX_STREAMS; ++i) { 143436b5abeSTakashi Sakamoto fw_iso_resources_free(&dice->tx_resources[i]); 144436b5abeSTakashi Sakamoto fw_iso_resources_free(&dice->rx_resources[i]); 145436b5abeSTakashi Sakamoto } 146436b5abeSTakashi Sakamoto } 147436b5abeSTakashi Sakamoto 148436b5abeSTakashi Sakamoto static void stop_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, 1498cc1a8abSTakashi Sakamoto struct reg_params *params) 150436b5abeSTakashi Sakamoto { 151436b5abeSTakashi Sakamoto __be32 reg; 152436b5abeSTakashi Sakamoto unsigned int i; 153436b5abeSTakashi Sakamoto 1548cc1a8abSTakashi Sakamoto for (i = 0; i < params->count; i++) { 155436b5abeSTakashi Sakamoto reg = cpu_to_be32((u32)-1); 156436b5abeSTakashi Sakamoto if (dir == AMDTP_IN_STREAM) { 157436b5abeSTakashi Sakamoto snd_dice_transaction_write_tx(dice, 1588cc1a8abSTakashi Sakamoto params->size * i + TX_ISOCHRONOUS, 159436b5abeSTakashi Sakamoto ®, sizeof(reg)); 160436b5abeSTakashi Sakamoto } else { 161436b5abeSTakashi Sakamoto snd_dice_transaction_write_rx(dice, 1628cc1a8abSTakashi Sakamoto params->size * i + RX_ISOCHRONOUS, 163436b5abeSTakashi Sakamoto ®, sizeof(reg)); 164436b5abeSTakashi Sakamoto } 165436b5abeSTakashi Sakamoto } 166288a8d0cSTakashi Sakamoto } 167288a8d0cSTakashi Sakamoto 168c738aed1STakashi Sakamoto static int keep_resources(struct snd_dice *dice, struct amdtp_stream *stream, 169c738aed1STakashi Sakamoto struct fw_iso_resources *resources, unsigned int rate, 170c738aed1STakashi Sakamoto unsigned int pcm_chs, unsigned int midi_ports) 171288a8d0cSTakashi Sakamoto { 17227ec83b5STakashi Sakamoto bool double_pcm_frames; 173436b5abeSTakashi Sakamoto unsigned int i; 174288a8d0cSTakashi Sakamoto int err; 175288a8d0cSTakashi Sakamoto 176c738aed1STakashi Sakamoto // At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in 177c738aed1STakashi Sakamoto // one data block of AMDTP packet. Thus sampling transfer frequency is 178c738aed1STakashi Sakamoto // a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are 179c738aed1STakashi Sakamoto // transferred on AMDTP packets at 96 kHz. Two successive samples of a 180c738aed1STakashi Sakamoto // channel are stored consecutively in the packet. This quirk is called 181c738aed1STakashi Sakamoto // as 'Dual Wire'. 182c738aed1STakashi Sakamoto // For this quirk, blocking mode is required and PCM buffer size should 183c738aed1STakashi Sakamoto // be aligned to SYT_INTERVAL. 1846f688268STakashi Sakamoto double_pcm_frames = rate > 96000; 18527ec83b5STakashi Sakamoto if (double_pcm_frames) { 186288a8d0cSTakashi Sakamoto rate /= 2; 187288a8d0cSTakashi Sakamoto pcm_chs *= 2; 188288a8d0cSTakashi Sakamoto } 189288a8d0cSTakashi Sakamoto 19051c29fd2STakashi Sakamoto err = amdtp_am824_set_parameters(stream, rate, pcm_chs, midi_ports, 19151c29fd2STakashi Sakamoto double_pcm_frames); 192547e631cSTakashi Sakamoto if (err < 0) 193436b5abeSTakashi Sakamoto return err; 194547e631cSTakashi Sakamoto 19527ec83b5STakashi Sakamoto if (double_pcm_frames) { 196288a8d0cSTakashi Sakamoto pcm_chs /= 2; 197288a8d0cSTakashi Sakamoto 198288a8d0cSTakashi Sakamoto for (i = 0; i < pcm_chs; i++) { 199f65be911STakashi Sakamoto amdtp_am824_set_pcm_position(stream, i, i * 2); 200f65be911STakashi Sakamoto amdtp_am824_set_pcm_position(stream, i + pcm_chs, 201f65be911STakashi Sakamoto i * 2 + 1); 202288a8d0cSTakashi Sakamoto } 203288a8d0cSTakashi Sakamoto } 204288a8d0cSTakashi Sakamoto 205436b5abeSTakashi Sakamoto return fw_iso_resources_allocate(resources, 206436b5abeSTakashi Sakamoto amdtp_stream_get_max_payload(stream), 207436b5abeSTakashi Sakamoto fw_parent_device(dice->unit)->max_speed); 208288a8d0cSTakashi Sakamoto } 209288a8d0cSTakashi Sakamoto 210c738aed1STakashi Sakamoto static int keep_dual_resources(struct snd_dice *dice, unsigned int rate, 211c738aed1STakashi Sakamoto enum amdtp_stream_direction dir, 212c738aed1STakashi Sakamoto struct reg_params *params) 213c738aed1STakashi Sakamoto { 214c738aed1STakashi Sakamoto enum snd_dice_rate_mode mode; 215c738aed1STakashi Sakamoto int i; 216c738aed1STakashi Sakamoto int err; 217c738aed1STakashi Sakamoto 218c738aed1STakashi Sakamoto err = snd_dice_stream_get_rate_mode(dice, rate, &mode); 219c738aed1STakashi Sakamoto if (err < 0) 220c738aed1STakashi Sakamoto return err; 221c738aed1STakashi Sakamoto 222c738aed1STakashi Sakamoto for (i = 0; i < params->count; ++i) { 223c738aed1STakashi Sakamoto __be32 reg[2]; 224c738aed1STakashi Sakamoto struct amdtp_stream *stream; 225c738aed1STakashi Sakamoto struct fw_iso_resources *resources; 226c738aed1STakashi Sakamoto unsigned int pcm_cache; 227c738aed1STakashi Sakamoto unsigned int midi_cache; 228c738aed1STakashi Sakamoto unsigned int pcm_chs; 229c738aed1STakashi Sakamoto unsigned int midi_ports; 230c738aed1STakashi Sakamoto 231c738aed1STakashi Sakamoto if (dir == AMDTP_IN_STREAM) { 232c738aed1STakashi Sakamoto stream = &dice->tx_stream[i]; 233c738aed1STakashi Sakamoto resources = &dice->tx_resources[i]; 234c738aed1STakashi Sakamoto 235c738aed1STakashi Sakamoto pcm_cache = dice->tx_pcm_chs[i][mode]; 236c738aed1STakashi Sakamoto midi_cache = dice->tx_midi_ports[i]; 237c738aed1STakashi Sakamoto err = snd_dice_transaction_read_tx(dice, 238c738aed1STakashi Sakamoto params->size * i + TX_NUMBER_AUDIO, 239c738aed1STakashi Sakamoto reg, sizeof(reg)); 240c738aed1STakashi Sakamoto } else { 241c738aed1STakashi Sakamoto stream = &dice->rx_stream[i]; 242c738aed1STakashi Sakamoto resources = &dice->rx_resources[i]; 243c738aed1STakashi Sakamoto 244c738aed1STakashi Sakamoto pcm_cache = dice->rx_pcm_chs[i][mode]; 245c738aed1STakashi Sakamoto midi_cache = dice->rx_midi_ports[i]; 246c738aed1STakashi Sakamoto err = snd_dice_transaction_read_rx(dice, 247c738aed1STakashi Sakamoto params->size * i + RX_NUMBER_AUDIO, 248c738aed1STakashi Sakamoto reg, sizeof(reg)); 249c738aed1STakashi Sakamoto } 250c738aed1STakashi Sakamoto if (err < 0) 251c738aed1STakashi Sakamoto return err; 252c738aed1STakashi Sakamoto pcm_chs = be32_to_cpu(reg[0]); 253c738aed1STakashi Sakamoto midi_ports = be32_to_cpu(reg[1]); 254c738aed1STakashi Sakamoto 255c738aed1STakashi Sakamoto // These are important for developer of this driver. 256c738aed1STakashi Sakamoto if (pcm_chs != pcm_cache || midi_ports != midi_cache) { 257c738aed1STakashi Sakamoto dev_info(&dice->unit->device, 258c738aed1STakashi Sakamoto "cache mismatch: pcm: %u:%u, midi: %u:%u\n", 259c738aed1STakashi Sakamoto pcm_chs, pcm_cache, midi_ports, midi_cache); 260c738aed1STakashi Sakamoto return -EPROTO; 261c738aed1STakashi Sakamoto } 262c738aed1STakashi Sakamoto 263c738aed1STakashi Sakamoto err = keep_resources(dice, stream, resources, rate, pcm_chs, 264c738aed1STakashi Sakamoto midi_ports); 265c738aed1STakashi Sakamoto if (err < 0) 266c738aed1STakashi Sakamoto return err; 267c738aed1STakashi Sakamoto } 268c738aed1STakashi Sakamoto 269c738aed1STakashi Sakamoto return 0; 270c738aed1STakashi Sakamoto } 271c738aed1STakashi Sakamoto 272b3480638STakashi Sakamoto static void finish_session(struct snd_dice *dice, struct reg_params *tx_params, 273b3480638STakashi Sakamoto struct reg_params *rx_params) 274b3480638STakashi Sakamoto { 275b3480638STakashi Sakamoto stop_streams(dice, AMDTP_IN_STREAM, tx_params); 276b3480638STakashi Sakamoto stop_streams(dice, AMDTP_OUT_STREAM, rx_params); 277b3480638STakashi Sakamoto 278b3480638STakashi Sakamoto snd_dice_transaction_clear_enable(dice); 279b3480638STakashi Sakamoto } 280b3480638STakashi Sakamoto 2813cd2c2d7STakashi Sakamoto int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate) 2823cd2c2d7STakashi Sakamoto { 2833cd2c2d7STakashi Sakamoto unsigned int curr_rate; 2843cd2c2d7STakashi Sakamoto int err; 2853cd2c2d7STakashi Sakamoto 2863cd2c2d7STakashi Sakamoto // Check sampling transmission frequency. 2873cd2c2d7STakashi Sakamoto err = snd_dice_transaction_get_rate(dice, &curr_rate); 2883cd2c2d7STakashi Sakamoto if (err < 0) 2893cd2c2d7STakashi Sakamoto return err; 2903cd2c2d7STakashi Sakamoto if (rate == 0) 2913cd2c2d7STakashi Sakamoto rate = curr_rate; 2923cd2c2d7STakashi Sakamoto 2933cd2c2d7STakashi Sakamoto if (dice->substreams_counter == 0 || curr_rate != rate) { 2943cd2c2d7STakashi Sakamoto struct reg_params tx_params, rx_params; 2953cd2c2d7STakashi Sakamoto 296e9f21129STakashi Sakamoto amdtp_domain_stop(&dice->domain); 297e9f21129STakashi Sakamoto 2983cd2c2d7STakashi Sakamoto err = get_register_params(dice, &tx_params, &rx_params); 2993cd2c2d7STakashi Sakamoto if (err < 0) 3003cd2c2d7STakashi Sakamoto return err; 3013cd2c2d7STakashi Sakamoto finish_session(dice, &tx_params, &rx_params); 3023cd2c2d7STakashi Sakamoto 3033cd2c2d7STakashi Sakamoto release_resources(dice); 3043cd2c2d7STakashi Sakamoto 3053cd2c2d7STakashi Sakamoto // Just after owning the unit (GLOBAL_OWNER), the unit can 3063cd2c2d7STakashi Sakamoto // return invalid stream formats. Selecting clock parameters 3073cd2c2d7STakashi Sakamoto // have an effect for the unit to refine it. 3083cd2c2d7STakashi Sakamoto err = ensure_phase_lock(dice, rate); 3093cd2c2d7STakashi Sakamoto if (err < 0) 3103cd2c2d7STakashi Sakamoto return err; 3113cd2c2d7STakashi Sakamoto 3123cd2c2d7STakashi Sakamoto // After changing sampling transfer frequency, the value of 3133cd2c2d7STakashi Sakamoto // register can be changed. 3143cd2c2d7STakashi Sakamoto err = get_register_params(dice, &tx_params, &rx_params); 3153cd2c2d7STakashi Sakamoto if (err < 0) 3163cd2c2d7STakashi Sakamoto return err; 3173cd2c2d7STakashi Sakamoto 3183cd2c2d7STakashi Sakamoto err = keep_dual_resources(dice, rate, AMDTP_IN_STREAM, 3193cd2c2d7STakashi Sakamoto &tx_params); 3203cd2c2d7STakashi Sakamoto if (err < 0) 3213cd2c2d7STakashi Sakamoto goto error; 3223cd2c2d7STakashi Sakamoto 3233cd2c2d7STakashi Sakamoto err = keep_dual_resources(dice, rate, AMDTP_OUT_STREAM, 3243cd2c2d7STakashi Sakamoto &rx_params); 3253cd2c2d7STakashi Sakamoto if (err < 0) 3263cd2c2d7STakashi Sakamoto goto error; 3273cd2c2d7STakashi Sakamoto } 3283cd2c2d7STakashi Sakamoto 3293cd2c2d7STakashi Sakamoto return 0; 3303cd2c2d7STakashi Sakamoto error: 3313cd2c2d7STakashi Sakamoto release_resources(dice); 3323cd2c2d7STakashi Sakamoto return err; 3333cd2c2d7STakashi Sakamoto } 3343cd2c2d7STakashi Sakamoto 335436b5abeSTakashi Sakamoto static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, 3368cc1a8abSTakashi Sakamoto unsigned int rate, struct reg_params *params) 337436b5abeSTakashi Sakamoto { 338c738aed1STakashi Sakamoto unsigned int max_speed = fw_parent_device(dice->unit)->max_speed; 339c738aed1STakashi Sakamoto int i; 340c738aed1STakashi Sakamoto int err; 341436b5abeSTakashi Sakamoto 3428cc1a8abSTakashi Sakamoto for (i = 0; i < params->count; i++) { 343c738aed1STakashi Sakamoto struct amdtp_stream *stream; 344c738aed1STakashi Sakamoto struct fw_iso_resources *resources; 345c738aed1STakashi Sakamoto __be32 reg; 346afa617f2STakashi Sakamoto 347436b5abeSTakashi Sakamoto if (dir == AMDTP_IN_STREAM) { 348c738aed1STakashi Sakamoto stream = dice->tx_stream + i; 349c738aed1STakashi Sakamoto resources = dice->tx_resources + i; 350436b5abeSTakashi Sakamoto } else { 351c738aed1STakashi Sakamoto stream = dice->rx_stream + i; 352c738aed1STakashi Sakamoto resources = dice->rx_resources + i; 353afa617f2STakashi Sakamoto } 354afa617f2STakashi Sakamoto 355c738aed1STakashi Sakamoto reg = cpu_to_be32(resources->channel); 356436b5abeSTakashi Sakamoto if (dir == AMDTP_IN_STREAM) { 357436b5abeSTakashi Sakamoto err = snd_dice_transaction_write_tx(dice, 3588cc1a8abSTakashi Sakamoto params->size * i + TX_ISOCHRONOUS, 359c738aed1STakashi Sakamoto ®, sizeof(reg)); 360436b5abeSTakashi Sakamoto } else { 361436b5abeSTakashi Sakamoto err = snd_dice_transaction_write_rx(dice, 3628cc1a8abSTakashi Sakamoto params->size * i + RX_ISOCHRONOUS, 363c738aed1STakashi Sakamoto ®, sizeof(reg)); 364436b5abeSTakashi Sakamoto } 365436b5abeSTakashi Sakamoto if (err < 0) 366436b5abeSTakashi Sakamoto return err; 367436b5abeSTakashi Sakamoto 368b0e159feSTakashi Sakamoto if (dir == AMDTP_IN_STREAM) { 369c738aed1STakashi Sakamoto reg = cpu_to_be32(max_speed); 370b0e159feSTakashi Sakamoto err = snd_dice_transaction_write_tx(dice, 371b0e159feSTakashi Sakamoto params->size * i + TX_SPEED, 372c738aed1STakashi Sakamoto ®, sizeof(reg)); 373b0e159feSTakashi Sakamoto if (err < 0) 374b0e159feSTakashi Sakamoto return err; 375b0e159feSTakashi Sakamoto } 376b0e159feSTakashi Sakamoto 377e9f21129STakashi Sakamoto err = amdtp_domain_add_stream(&dice->domain, stream, 378e9f21129STakashi Sakamoto resources->channel, max_speed); 379288a8d0cSTakashi Sakamoto if (err < 0) 380288a8d0cSTakashi Sakamoto return err; 381288a8d0cSTakashi Sakamoto } 382288a8d0cSTakashi Sakamoto 383c72d3a0aSTakashi Sakamoto return 0; 384436b5abeSTakashi Sakamoto } 385436b5abeSTakashi Sakamoto 3863cd2c2d7STakashi Sakamoto /* 3873cd2c2d7STakashi Sakamoto * MEMO: After this function, there're two states of streams: 3883cd2c2d7STakashi Sakamoto * - None streams are running. 3893cd2c2d7STakashi Sakamoto * - All streams are running. 3903cd2c2d7STakashi Sakamoto */ 3913cd2c2d7STakashi Sakamoto int snd_dice_stream_start_duplex(struct snd_dice *dice) 39220b94544STakashi Sakamoto { 393d5553026STakashi Sakamoto unsigned int generation = dice->rx_resources[0].generation; 39420b94544STakashi Sakamoto struct reg_params tx_params, rx_params; 3953cd2c2d7STakashi Sakamoto unsigned int i; 3963cd2c2d7STakashi Sakamoto unsigned int rate; 3973cd2c2d7STakashi Sakamoto enum snd_dice_rate_mode mode; 39820b94544STakashi Sakamoto int err; 39920b94544STakashi Sakamoto 4003cd2c2d7STakashi Sakamoto if (dice->substreams_counter == 0) 4013cd2c2d7STakashi Sakamoto return -EIO; 4023cd2c2d7STakashi Sakamoto 40320b94544STakashi Sakamoto err = get_register_params(dice, &tx_params, &rx_params); 40420b94544STakashi Sakamoto if (err < 0) 40520b94544STakashi Sakamoto return err; 40620b94544STakashi Sakamoto 4073cd2c2d7STakashi Sakamoto // Check error of packet streaming. 4083cd2c2d7STakashi Sakamoto for (i = 0; i < MAX_STREAMS; ++i) { 4093cd2c2d7STakashi Sakamoto if (amdtp_streaming_error(&dice->tx_stream[i]) || 4103cd2c2d7STakashi Sakamoto amdtp_streaming_error(&dice->rx_stream[i])) { 411e9f21129STakashi Sakamoto amdtp_domain_stop(&dice->domain); 412b3480638STakashi Sakamoto finish_session(dice, &tx_params, &rx_params); 4133cd2c2d7STakashi Sakamoto break; 4143cd2c2d7STakashi Sakamoto } 41520b94544STakashi Sakamoto } 41620b94544STakashi Sakamoto 417d5553026STakashi Sakamoto if (generation != fw_parent_device(dice->unit)->card->generation) { 418d5553026STakashi Sakamoto for (i = 0; i < MAX_STREAMS; ++i) { 419d5553026STakashi Sakamoto if (i < tx_params.count) 420d5553026STakashi Sakamoto fw_iso_resources_update(dice->tx_resources + i); 421d5553026STakashi Sakamoto if (i < rx_params.count) 422d5553026STakashi Sakamoto fw_iso_resources_update(dice->rx_resources + i); 423d5553026STakashi Sakamoto } 424d5553026STakashi Sakamoto } 425d5553026STakashi Sakamoto 4263cd2c2d7STakashi Sakamoto // Check required streams are running or not. 4273cd2c2d7STakashi Sakamoto err = snd_dice_transaction_get_rate(dice, &rate); 428afa617f2STakashi Sakamoto if (err < 0) 429afa617f2STakashi Sakamoto return err; 4303cd2c2d7STakashi Sakamoto err = snd_dice_stream_get_rate_mode(dice, rate, &mode); 4313cd2c2d7STakashi Sakamoto if (err < 0) 4323cd2c2d7STakashi Sakamoto return err; 4333cd2c2d7STakashi Sakamoto for (i = 0; i < MAX_STREAMS; ++i) { 4343cd2c2d7STakashi Sakamoto if (dice->tx_pcm_chs[i][mode] > 0 && 4353cd2c2d7STakashi Sakamoto !amdtp_stream_running(&dice->tx_stream[i])) 4363cd2c2d7STakashi Sakamoto break; 4373cd2c2d7STakashi Sakamoto if (dice->rx_pcm_chs[i][mode] > 0 && 4383cd2c2d7STakashi Sakamoto !amdtp_stream_running(&dice->rx_stream[i])) 4393cd2c2d7STakashi Sakamoto break; 4403cd2c2d7STakashi Sakamoto } 4413cd2c2d7STakashi Sakamoto if (i < MAX_STREAMS) { 4423cd2c2d7STakashi Sakamoto // Start both streams. 44320b94544STakashi Sakamoto err = start_streams(dice, AMDTP_IN_STREAM, rate, &tx_params); 44420b94544STakashi Sakamoto if (err < 0) 44520b94544STakashi Sakamoto goto error; 4463cd2c2d7STakashi Sakamoto 44720b94544STakashi Sakamoto err = start_streams(dice, AMDTP_OUT_STREAM, rate, &rx_params); 44820b94544STakashi Sakamoto if (err < 0) 44920b94544STakashi Sakamoto goto error; 45020b94544STakashi Sakamoto 45120b94544STakashi Sakamoto err = snd_dice_transaction_set_enable(dice); 45220b94544STakashi Sakamoto if (err < 0) { 4533cd2c2d7STakashi Sakamoto dev_err(&dice->unit->device, 4543cd2c2d7STakashi Sakamoto "fail to enable interface\n"); 45520b94544STakashi Sakamoto goto error; 45620b94544STakashi Sakamoto } 45720b94544STakashi Sakamoto 458e9f21129STakashi Sakamoto err = amdtp_domain_start(&dice->domain); 459e9f21129STakashi Sakamoto if (err < 0) 460e9f21129STakashi Sakamoto goto error; 461e9f21129STakashi Sakamoto 46220b94544STakashi Sakamoto for (i = 0; i < MAX_STREAMS; i++) { 46320b94544STakashi Sakamoto if ((i < tx_params.count && 46420b94544STakashi Sakamoto !amdtp_stream_wait_callback(&dice->tx_stream[i], 46520b94544STakashi Sakamoto CALLBACK_TIMEOUT)) || 46620b94544STakashi Sakamoto (i < rx_params.count && 46720b94544STakashi Sakamoto !amdtp_stream_wait_callback(&dice->rx_stream[i], 46820b94544STakashi Sakamoto CALLBACK_TIMEOUT))) { 46920b94544STakashi Sakamoto err = -ETIMEDOUT; 47020b94544STakashi Sakamoto goto error; 47120b94544STakashi Sakamoto } 47220b94544STakashi Sakamoto } 4733cd2c2d7STakashi Sakamoto } 47420b94544STakashi Sakamoto 47520b94544STakashi Sakamoto return 0; 47620b94544STakashi Sakamoto error: 477e9f21129STakashi Sakamoto amdtp_domain_stop(&dice->domain); 478b3480638STakashi Sakamoto finish_session(dice, &tx_params, &rx_params); 47920b94544STakashi Sakamoto return err; 48020b94544STakashi Sakamoto } 48120b94544STakashi Sakamoto 482436b5abeSTakashi Sakamoto /* 483436b5abeSTakashi Sakamoto * MEMO: After this function, there're two states of streams: 484436b5abeSTakashi Sakamoto * - None streams are running. 485436b5abeSTakashi Sakamoto * - All streams are running. 486436b5abeSTakashi Sakamoto */ 4879a02843cSTakashi Sakamoto void snd_dice_stream_stop_duplex(struct snd_dice *dice) 4886eb6c81eSTakashi Sakamoto { 4898cc1a8abSTakashi Sakamoto struct reg_params tx_params, rx_params; 490436b5abeSTakashi Sakamoto 4913cd2c2d7STakashi Sakamoto if (dice->substreams_counter == 0) { 492e9f21129STakashi Sakamoto if (get_register_params(dice, &tx_params, &rx_params) >= 0) { 493e9f21129STakashi Sakamoto amdtp_domain_stop(&dice->domain); 494b3480638STakashi Sakamoto finish_session(dice, &tx_params, &rx_params); 495e9f21129STakashi Sakamoto } 496740680f2STakashi Sakamoto 497740680f2STakashi Sakamoto release_resources(dice); 4983cd2c2d7STakashi Sakamoto } 499436b5abeSTakashi Sakamoto } 5009a02843cSTakashi Sakamoto 501436b5abeSTakashi Sakamoto static int init_stream(struct snd_dice *dice, enum amdtp_stream_direction dir, 502436b5abeSTakashi Sakamoto unsigned int index) 503436b5abeSTakashi Sakamoto { 504436b5abeSTakashi Sakamoto struct amdtp_stream *stream; 505436b5abeSTakashi Sakamoto struct fw_iso_resources *resources; 506436b5abeSTakashi Sakamoto int err; 507436b5abeSTakashi Sakamoto 508436b5abeSTakashi Sakamoto if (dir == AMDTP_IN_STREAM) { 509436b5abeSTakashi Sakamoto stream = &dice->tx_stream[index]; 510436b5abeSTakashi Sakamoto resources = &dice->tx_resources[index]; 5119a02843cSTakashi Sakamoto } else { 512436b5abeSTakashi Sakamoto stream = &dice->rx_stream[index]; 513436b5abeSTakashi Sakamoto resources = &dice->rx_resources[index]; 5149a02843cSTakashi Sakamoto } 5159a02843cSTakashi Sakamoto 5169a02843cSTakashi Sakamoto err = fw_iso_resources_init(resources, dice->unit); 5179a02843cSTakashi Sakamoto if (err < 0) 5189a02843cSTakashi Sakamoto goto end; 5199a02843cSTakashi Sakamoto resources->channels_mask = 0x00000000ffffffffuLL; 5209a02843cSTakashi Sakamoto 5215955815eSTakashi Sakamoto err = amdtp_am824_init(stream, dice->unit, dir, CIP_BLOCKING); 5229a02843cSTakashi Sakamoto if (err < 0) { 5239a02843cSTakashi Sakamoto amdtp_stream_destroy(stream); 5249a02843cSTakashi Sakamoto fw_iso_resources_destroy(resources); 5259a02843cSTakashi Sakamoto } 5269a02843cSTakashi Sakamoto end: 5279a02843cSTakashi Sakamoto return err; 5289a02843cSTakashi Sakamoto } 5299a02843cSTakashi Sakamoto 530d23c2cc4STakashi Sakamoto /* 531d23c2cc4STakashi Sakamoto * This function should be called before starting streams or after stopping 532d23c2cc4STakashi Sakamoto * streams. 533d23c2cc4STakashi Sakamoto */ 534436b5abeSTakashi Sakamoto static void destroy_stream(struct snd_dice *dice, 535436b5abeSTakashi Sakamoto enum amdtp_stream_direction dir, 536436b5abeSTakashi Sakamoto unsigned int index) 5379a02843cSTakashi Sakamoto { 538436b5abeSTakashi Sakamoto struct amdtp_stream *stream; 539d23c2cc4STakashi Sakamoto struct fw_iso_resources *resources; 5409a02843cSTakashi Sakamoto 541436b5abeSTakashi Sakamoto if (dir == AMDTP_IN_STREAM) { 542436b5abeSTakashi Sakamoto stream = &dice->tx_stream[index]; 543436b5abeSTakashi Sakamoto resources = &dice->tx_resources[index]; 544436b5abeSTakashi Sakamoto } else { 545436b5abeSTakashi Sakamoto stream = &dice->rx_stream[index]; 546436b5abeSTakashi Sakamoto resources = &dice->rx_resources[index]; 547436b5abeSTakashi Sakamoto } 548d23c2cc4STakashi Sakamoto 549d23c2cc4STakashi Sakamoto amdtp_stream_destroy(stream); 550d23c2cc4STakashi Sakamoto fw_iso_resources_destroy(resources); 5519a02843cSTakashi Sakamoto } 5529a02843cSTakashi Sakamoto 5539a02843cSTakashi Sakamoto int snd_dice_stream_init_duplex(struct snd_dice *dice) 5546eb6c81eSTakashi Sakamoto { 555436b5abeSTakashi Sakamoto int i, err; 5566eb6c81eSTakashi Sakamoto 557436b5abeSTakashi Sakamoto for (i = 0; i < MAX_STREAMS; i++) { 558436b5abeSTakashi Sakamoto err = init_stream(dice, AMDTP_IN_STREAM, i); 559436b5abeSTakashi Sakamoto if (err < 0) { 560436b5abeSTakashi Sakamoto for (; i >= 0; i--) 5610f925660STakashi Sakamoto destroy_stream(dice, AMDTP_IN_STREAM, i); 5626eb6c81eSTakashi Sakamoto goto end; 563436b5abeSTakashi Sakamoto } 564436b5abeSTakashi Sakamoto } 5656eb6c81eSTakashi Sakamoto 566436b5abeSTakashi Sakamoto for (i = 0; i < MAX_STREAMS; i++) { 567436b5abeSTakashi Sakamoto err = init_stream(dice, AMDTP_OUT_STREAM, i); 568436b5abeSTakashi Sakamoto if (err < 0) { 569436b5abeSTakashi Sakamoto for (; i >= 0; i--) 570436b5abeSTakashi Sakamoto destroy_stream(dice, AMDTP_OUT_STREAM, i); 571436b5abeSTakashi Sakamoto for (i = 0; i < MAX_STREAMS; i++) 572436b5abeSTakashi Sakamoto destroy_stream(dice, AMDTP_IN_STREAM, i); 573436b5abeSTakashi Sakamoto break; 574436b5abeSTakashi Sakamoto } 575436b5abeSTakashi Sakamoto } 576e9f21129STakashi Sakamoto 577e9f21129STakashi Sakamoto err = amdtp_domain_init(&dice->domain); 578e9f21129STakashi Sakamoto if (err < 0) { 579e9f21129STakashi Sakamoto for (i = 0; i < MAX_STREAMS; ++i) { 580e9f21129STakashi Sakamoto destroy_stream(dice, AMDTP_OUT_STREAM, i); 581e9f21129STakashi Sakamoto destroy_stream(dice, AMDTP_IN_STREAM, i); 582e9f21129STakashi Sakamoto } 583e9f21129STakashi Sakamoto } 5846eb6c81eSTakashi Sakamoto end: 5856eb6c81eSTakashi Sakamoto return err; 5866eb6c81eSTakashi Sakamoto } 5876eb6c81eSTakashi Sakamoto 5889a02843cSTakashi Sakamoto void snd_dice_stream_destroy_duplex(struct snd_dice *dice) 5896eb6c81eSTakashi Sakamoto { 5906b94fb14STakashi Sakamoto unsigned int i; 591436b5abeSTakashi Sakamoto 5926b94fb14STakashi Sakamoto for (i = 0; i < MAX_STREAMS; i++) { 5936b94fb14STakashi Sakamoto destroy_stream(dice, AMDTP_IN_STREAM, i); 5946b94fb14STakashi Sakamoto destroy_stream(dice, AMDTP_OUT_STREAM, i); 595436b5abeSTakashi Sakamoto } 596e9f21129STakashi Sakamoto 597e9f21129STakashi Sakamoto amdtp_domain_destroy(&dice->domain); 5986eb6c81eSTakashi Sakamoto } 5996eb6c81eSTakashi Sakamoto 6009a02843cSTakashi Sakamoto void snd_dice_stream_update_duplex(struct snd_dice *dice) 6016eb6c81eSTakashi Sakamoto { 6028cc1a8abSTakashi Sakamoto struct reg_params tx_params, rx_params; 603436b5abeSTakashi Sakamoto 6046eb6c81eSTakashi Sakamoto /* 6056eb6c81eSTakashi Sakamoto * On a bus reset, the DICE firmware disables streaming and then goes 6066eb6c81eSTakashi Sakamoto * off contemplating its own navel for hundreds of milliseconds before 6076eb6c81eSTakashi Sakamoto * it can react to any of our attempts to reenable streaming. This 6086eb6c81eSTakashi Sakamoto * means that we lose synchronization anyway, so we force our streams 6096eb6c81eSTakashi Sakamoto * to stop so that the application can restart them in an orderly 6106eb6c81eSTakashi Sakamoto * manner. 6116eb6c81eSTakashi Sakamoto */ 6126eb6c81eSTakashi Sakamoto dice->global_enabled = false; 6136eb6c81eSTakashi Sakamoto 6148cc1a8abSTakashi Sakamoto if (get_register_params(dice, &tx_params, &rx_params) == 0) { 615e9f21129STakashi Sakamoto amdtp_domain_stop(&dice->domain); 616e9f21129STakashi Sakamoto 6178cc1a8abSTakashi Sakamoto stop_streams(dice, AMDTP_IN_STREAM, &tx_params); 6188cc1a8abSTakashi Sakamoto stop_streams(dice, AMDTP_OUT_STREAM, &rx_params); 619436b5abeSTakashi Sakamoto } 6206eb6c81eSTakashi Sakamoto } 6216eb6c81eSTakashi Sakamoto 622b60152f7STakashi Sakamoto int snd_dice_stream_detect_current_formats(struct snd_dice *dice) 623b60152f7STakashi Sakamoto { 624b60152f7STakashi Sakamoto unsigned int rate; 625b60152f7STakashi Sakamoto enum snd_dice_rate_mode mode; 626b60152f7STakashi Sakamoto __be32 reg[2]; 627b60152f7STakashi Sakamoto struct reg_params tx_params, rx_params; 628b60152f7STakashi Sakamoto int i; 629b60152f7STakashi Sakamoto int err; 630b60152f7STakashi Sakamoto 63158579c05STakashi Sakamoto /* If extended protocol is available, detect detail spec. */ 63258579c05STakashi Sakamoto err = snd_dice_detect_extension_formats(dice); 63358579c05STakashi Sakamoto if (err >= 0) 63458579c05STakashi Sakamoto return err; 63558579c05STakashi Sakamoto 636b60152f7STakashi Sakamoto /* 637b60152f7STakashi Sakamoto * Available stream format is restricted at current mode of sampling 638b60152f7STakashi Sakamoto * clock. 639b60152f7STakashi Sakamoto */ 640b60152f7STakashi Sakamoto err = snd_dice_transaction_get_rate(dice, &rate); 641b60152f7STakashi Sakamoto if (err < 0) 642b60152f7STakashi Sakamoto return err; 643b60152f7STakashi Sakamoto 644b60152f7STakashi Sakamoto err = snd_dice_stream_get_rate_mode(dice, rate, &mode); 645b60152f7STakashi Sakamoto if (err < 0) 646b60152f7STakashi Sakamoto return err; 647b60152f7STakashi Sakamoto 648b60152f7STakashi Sakamoto /* 649b60152f7STakashi Sakamoto * Just after owning the unit (GLOBAL_OWNER), the unit can return 650b60152f7STakashi Sakamoto * invalid stream formats. Selecting clock parameters have an effect 651b60152f7STakashi Sakamoto * for the unit to refine it. 652b60152f7STakashi Sakamoto */ 653afa617f2STakashi Sakamoto err = ensure_phase_lock(dice, rate); 654b60152f7STakashi Sakamoto if (err < 0) 655b60152f7STakashi Sakamoto return err; 656b60152f7STakashi Sakamoto 657b60152f7STakashi Sakamoto err = get_register_params(dice, &tx_params, &rx_params); 658b60152f7STakashi Sakamoto if (err < 0) 659b60152f7STakashi Sakamoto return err; 660b60152f7STakashi Sakamoto 661b60152f7STakashi Sakamoto for (i = 0; i < tx_params.count; ++i) { 662b60152f7STakashi Sakamoto err = snd_dice_transaction_read_tx(dice, 663b60152f7STakashi Sakamoto tx_params.size * i + TX_NUMBER_AUDIO, 664b60152f7STakashi Sakamoto reg, sizeof(reg)); 665b60152f7STakashi Sakamoto if (err < 0) 666b60152f7STakashi Sakamoto return err; 667b60152f7STakashi Sakamoto dice->tx_pcm_chs[i][mode] = be32_to_cpu(reg[0]); 668b60152f7STakashi Sakamoto dice->tx_midi_ports[i] = max_t(unsigned int, 669b60152f7STakashi Sakamoto be32_to_cpu(reg[1]), dice->tx_midi_ports[i]); 670b60152f7STakashi Sakamoto } 671b60152f7STakashi Sakamoto for (i = 0; i < rx_params.count; ++i) { 672b60152f7STakashi Sakamoto err = snd_dice_transaction_read_rx(dice, 673b60152f7STakashi Sakamoto rx_params.size * i + RX_NUMBER_AUDIO, 674b60152f7STakashi Sakamoto reg, sizeof(reg)); 675b60152f7STakashi Sakamoto if (err < 0) 676b60152f7STakashi Sakamoto return err; 677b60152f7STakashi Sakamoto dice->rx_pcm_chs[i][mode] = be32_to_cpu(reg[0]); 678b60152f7STakashi Sakamoto dice->rx_midi_ports[i] = max_t(unsigned int, 679b60152f7STakashi Sakamoto be32_to_cpu(reg[1]), dice->rx_midi_ports[i]); 680b60152f7STakashi Sakamoto } 681b60152f7STakashi Sakamoto 682b60152f7STakashi Sakamoto return 0; 683b60152f7STakashi Sakamoto } 684b60152f7STakashi Sakamoto 6856eb6c81eSTakashi Sakamoto static void dice_lock_changed(struct snd_dice *dice) 6866eb6c81eSTakashi Sakamoto { 6876eb6c81eSTakashi Sakamoto dice->dev_lock_changed = true; 6886eb6c81eSTakashi Sakamoto wake_up(&dice->hwdep_wait); 6896eb6c81eSTakashi Sakamoto } 6906eb6c81eSTakashi Sakamoto 6916eb6c81eSTakashi Sakamoto int snd_dice_stream_lock_try(struct snd_dice *dice) 6926eb6c81eSTakashi Sakamoto { 6936eb6c81eSTakashi Sakamoto int err; 6946eb6c81eSTakashi Sakamoto 6956eb6c81eSTakashi Sakamoto spin_lock_irq(&dice->lock); 6966eb6c81eSTakashi Sakamoto 6976eb6c81eSTakashi Sakamoto if (dice->dev_lock_count < 0) { 6986eb6c81eSTakashi Sakamoto err = -EBUSY; 6996eb6c81eSTakashi Sakamoto goto out; 7006eb6c81eSTakashi Sakamoto } 7016eb6c81eSTakashi Sakamoto 7026eb6c81eSTakashi Sakamoto if (dice->dev_lock_count++ == 0) 7036eb6c81eSTakashi Sakamoto dice_lock_changed(dice); 7046eb6c81eSTakashi Sakamoto err = 0; 7056eb6c81eSTakashi Sakamoto out: 7066eb6c81eSTakashi Sakamoto spin_unlock_irq(&dice->lock); 7076eb6c81eSTakashi Sakamoto return err; 7086eb6c81eSTakashi Sakamoto } 7096eb6c81eSTakashi Sakamoto 7106eb6c81eSTakashi Sakamoto void snd_dice_stream_lock_release(struct snd_dice *dice) 7116eb6c81eSTakashi Sakamoto { 7126eb6c81eSTakashi Sakamoto spin_lock_irq(&dice->lock); 7136eb6c81eSTakashi Sakamoto 7146eb6c81eSTakashi Sakamoto if (WARN_ON(dice->dev_lock_count <= 0)) 7156eb6c81eSTakashi Sakamoto goto out; 7166eb6c81eSTakashi Sakamoto 7176eb6c81eSTakashi Sakamoto if (--dice->dev_lock_count == 0) 7186eb6c81eSTakashi Sakamoto dice_lock_changed(dice); 7196eb6c81eSTakashi Sakamoto out: 7206eb6c81eSTakashi Sakamoto spin_unlock_irq(&dice->lock); 7216eb6c81eSTakashi Sakamoto } 722