16eb6c81eSTakashi Sakamoto /* 26eb6c81eSTakashi Sakamoto * dice_stream.c - a part of driver for DICE based devices 36eb6c81eSTakashi Sakamoto * 46eb6c81eSTakashi Sakamoto * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 56eb6c81eSTakashi Sakamoto * Copyright (c) 2014 Takashi Sakamoto <o-takashi@sakamocchi.jp> 66eb6c81eSTakashi Sakamoto * 76eb6c81eSTakashi Sakamoto * Licensed under the terms of the GNU General Public License, version 2. 86eb6c81eSTakashi Sakamoto */ 96eb6c81eSTakashi Sakamoto 106eb6c81eSTakashi Sakamoto #include "dice.h" 116eb6c81eSTakashi Sakamoto 12288a8d0cSTakashi Sakamoto #define CALLBACK_TIMEOUT 200 13dfabc0eeSTakashi Sakamoto #define NOTIFICATION_TIMEOUT_MS (2 * MSEC_PER_SEC) 14288a8d0cSTakashi Sakamoto 158cc1a8abSTakashi Sakamoto struct reg_params { 168cc1a8abSTakashi Sakamoto unsigned int count; 178cc1a8abSTakashi Sakamoto unsigned int size; 188cc1a8abSTakashi Sakamoto }; 198cc1a8abSTakashi Sakamoto 206eb6c81eSTakashi Sakamoto const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT] = { 216eb6c81eSTakashi Sakamoto /* mode 0 */ 226eb6c81eSTakashi Sakamoto [0] = 32000, 236eb6c81eSTakashi Sakamoto [1] = 44100, 246eb6c81eSTakashi Sakamoto [2] = 48000, 256eb6c81eSTakashi Sakamoto /* mode 1 */ 266eb6c81eSTakashi Sakamoto [3] = 88200, 276eb6c81eSTakashi Sakamoto [4] = 96000, 286eb6c81eSTakashi Sakamoto /* mode 2 */ 296eb6c81eSTakashi Sakamoto [5] = 176400, 306eb6c81eSTakashi Sakamoto [6] = 192000, 316eb6c81eSTakashi Sakamoto }; 326eb6c81eSTakashi Sakamoto 33b60152f7STakashi Sakamoto int snd_dice_stream_get_rate_mode(struct snd_dice *dice, unsigned int rate, 34b60152f7STakashi Sakamoto enum snd_dice_rate_mode *mode) 35b60152f7STakashi Sakamoto { 36b60152f7STakashi Sakamoto /* Corresponding to each entry in snd_dice_rates. */ 37b60152f7STakashi Sakamoto static const enum snd_dice_rate_mode modes[] = { 38b60152f7STakashi Sakamoto [0] = SND_DICE_RATE_MODE_LOW, 39b60152f7STakashi Sakamoto [1] = SND_DICE_RATE_MODE_LOW, 40b60152f7STakashi Sakamoto [2] = SND_DICE_RATE_MODE_LOW, 41b60152f7STakashi Sakamoto [3] = SND_DICE_RATE_MODE_MIDDLE, 42b60152f7STakashi Sakamoto [4] = SND_DICE_RATE_MODE_MIDDLE, 43b60152f7STakashi Sakamoto [5] = SND_DICE_RATE_MODE_HIGH, 44b60152f7STakashi Sakamoto [6] = SND_DICE_RATE_MODE_HIGH, 45b60152f7STakashi Sakamoto }; 46b60152f7STakashi Sakamoto int i; 47b60152f7STakashi Sakamoto 48b60152f7STakashi Sakamoto for (i = 0; i < ARRAY_SIZE(snd_dice_rates); i++) { 49b60152f7STakashi Sakamoto if (!(dice->clock_caps & BIT(i))) 50b60152f7STakashi Sakamoto continue; 51b60152f7STakashi Sakamoto if (snd_dice_rates[i] != rate) 52b60152f7STakashi Sakamoto continue; 53b60152f7STakashi Sakamoto 54b60152f7STakashi Sakamoto *mode = modes[i]; 55b60152f7STakashi Sakamoto return 0; 56b60152f7STakashi Sakamoto } 57b60152f7STakashi Sakamoto 58b60152f7STakashi Sakamoto return -EINVAL; 59b60152f7STakashi Sakamoto } 60b60152f7STakashi Sakamoto 61dfabc0eeSTakashi Sakamoto /* 62dfabc0eeSTakashi Sakamoto * This operation has an effect to synchronize GLOBAL_STATUS/GLOBAL_SAMPLE_RATE 63dfabc0eeSTakashi Sakamoto * to GLOBAL_STATUS. Especially, just after powering on, these are different. 64dfabc0eeSTakashi Sakamoto */ 65afa617f2STakashi Sakamoto static int ensure_phase_lock(struct snd_dice *dice, unsigned int rate) 66dfabc0eeSTakashi Sakamoto { 67fbeac84dSTakashi Sakamoto __be32 reg, nominal; 68afa617f2STakashi Sakamoto u32 data; 69afa617f2STakashi Sakamoto int i; 70dfabc0eeSTakashi Sakamoto int err; 71dfabc0eeSTakashi Sakamoto 72dfabc0eeSTakashi Sakamoto err = snd_dice_transaction_read_global(dice, GLOBAL_CLOCK_SELECT, 73dfabc0eeSTakashi Sakamoto ®, sizeof(reg)); 74dfabc0eeSTakashi Sakamoto if (err < 0) 75dfabc0eeSTakashi Sakamoto return err; 76dfabc0eeSTakashi Sakamoto 77afa617f2STakashi Sakamoto data = be32_to_cpu(reg); 78afa617f2STakashi Sakamoto 79afa617f2STakashi Sakamoto data &= ~CLOCK_RATE_MASK; 80afa617f2STakashi Sakamoto for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) { 81afa617f2STakashi Sakamoto if (snd_dice_rates[i] == rate) 82afa617f2STakashi Sakamoto break; 83afa617f2STakashi Sakamoto } 84afa617f2STakashi Sakamoto if (i == ARRAY_SIZE(snd_dice_rates)) 85afa617f2STakashi Sakamoto return -EINVAL; 86afa617f2STakashi Sakamoto data |= i << CLOCK_RATE_SHIFT; 87afa617f2STakashi Sakamoto 88dfabc0eeSTakashi Sakamoto if (completion_done(&dice->clock_accepted)) 89dfabc0eeSTakashi Sakamoto reinit_completion(&dice->clock_accepted); 90dfabc0eeSTakashi Sakamoto 91afa617f2STakashi Sakamoto reg = cpu_to_be32(data); 92dfabc0eeSTakashi Sakamoto err = snd_dice_transaction_write_global(dice, GLOBAL_CLOCK_SELECT, 93dfabc0eeSTakashi Sakamoto ®, sizeof(reg)); 94dfabc0eeSTakashi Sakamoto if (err < 0) 95dfabc0eeSTakashi Sakamoto return err; 96dfabc0eeSTakashi Sakamoto 97dfabc0eeSTakashi Sakamoto if (wait_for_completion_timeout(&dice->clock_accepted, 98fbeac84dSTakashi Sakamoto msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0) { 99fbeac84dSTakashi Sakamoto /* 100fbeac84dSTakashi Sakamoto * Old versions of Dice firmware transfer no notification when 101fbeac84dSTakashi Sakamoto * the same clock status as current one is set. In this case, 102fbeac84dSTakashi Sakamoto * just check current clock status. 103fbeac84dSTakashi Sakamoto */ 104fbeac84dSTakashi Sakamoto err = snd_dice_transaction_read_global(dice, GLOBAL_STATUS, 105fbeac84dSTakashi Sakamoto &nominal, sizeof(nominal)); 106fbeac84dSTakashi Sakamoto if (err < 0) 107fbeac84dSTakashi Sakamoto return err; 108fbeac84dSTakashi Sakamoto if (!(be32_to_cpu(nominal) & STATUS_SOURCE_LOCKED)) 109dfabc0eeSTakashi Sakamoto return -ETIMEDOUT; 110fbeac84dSTakashi Sakamoto } 111dfabc0eeSTakashi Sakamoto 112dfabc0eeSTakashi Sakamoto return 0; 113dfabc0eeSTakashi Sakamoto } 114dfabc0eeSTakashi Sakamoto 1158cc1a8abSTakashi Sakamoto static int get_register_params(struct snd_dice *dice, 1168cc1a8abSTakashi Sakamoto struct reg_params *tx_params, 1178cc1a8abSTakashi Sakamoto struct reg_params *rx_params) 1186eb6c81eSTakashi Sakamoto { 119436b5abeSTakashi Sakamoto __be32 reg[2]; 120436b5abeSTakashi Sakamoto int err; 1216eb6c81eSTakashi Sakamoto 122436b5abeSTakashi Sakamoto err = snd_dice_transaction_read_tx(dice, TX_NUMBER, reg, sizeof(reg)); 123436b5abeSTakashi Sakamoto if (err < 0) 124436b5abeSTakashi Sakamoto return err; 1258cc1a8abSTakashi Sakamoto tx_params->count = 1268cc1a8abSTakashi Sakamoto min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS); 1278cc1a8abSTakashi Sakamoto tx_params->size = be32_to_cpu(reg[1]) * 4; 128288a8d0cSTakashi Sakamoto 129436b5abeSTakashi Sakamoto err = snd_dice_transaction_read_rx(dice, RX_NUMBER, reg, sizeof(reg)); 130436b5abeSTakashi Sakamoto if (err < 0) 131436b5abeSTakashi Sakamoto return err; 1328cc1a8abSTakashi Sakamoto rx_params->count = 1338cc1a8abSTakashi Sakamoto min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS); 1348cc1a8abSTakashi Sakamoto rx_params->size = be32_to_cpu(reg[1]) * 4; 135436b5abeSTakashi Sakamoto 136436b5abeSTakashi Sakamoto return 0; 137436b5abeSTakashi Sakamoto } 138436b5abeSTakashi Sakamoto 139436b5abeSTakashi Sakamoto static void release_resources(struct snd_dice *dice) 140436b5abeSTakashi Sakamoto { 1413cd2c2d7STakashi Sakamoto int i; 142436b5abeSTakashi Sakamoto 1433cd2c2d7STakashi Sakamoto for (i = 0; i < MAX_STREAMS; ++i) { 144436b5abeSTakashi Sakamoto fw_iso_resources_free(&dice->tx_resources[i]); 145436b5abeSTakashi Sakamoto fw_iso_resources_free(&dice->rx_resources[i]); 146436b5abeSTakashi Sakamoto } 147436b5abeSTakashi Sakamoto } 148436b5abeSTakashi Sakamoto 149436b5abeSTakashi Sakamoto static void stop_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, 1508cc1a8abSTakashi Sakamoto struct reg_params *params) 151436b5abeSTakashi Sakamoto { 152436b5abeSTakashi Sakamoto __be32 reg; 153436b5abeSTakashi Sakamoto unsigned int i; 154436b5abeSTakashi Sakamoto 1558cc1a8abSTakashi Sakamoto for (i = 0; i < params->count; i++) { 156436b5abeSTakashi Sakamoto reg = cpu_to_be32((u32)-1); 157436b5abeSTakashi Sakamoto if (dir == AMDTP_IN_STREAM) { 1583cd2c2d7STakashi Sakamoto amdtp_stream_stop(&dice->tx_stream[i]); 1593cd2c2d7STakashi Sakamoto 160436b5abeSTakashi Sakamoto snd_dice_transaction_write_tx(dice, 1618cc1a8abSTakashi Sakamoto params->size * i + TX_ISOCHRONOUS, 162436b5abeSTakashi Sakamoto ®, sizeof(reg)); 163436b5abeSTakashi Sakamoto } else { 1643cd2c2d7STakashi Sakamoto amdtp_stream_stop(&dice->rx_stream[i]); 1653cd2c2d7STakashi Sakamoto 166436b5abeSTakashi Sakamoto snd_dice_transaction_write_rx(dice, 1678cc1a8abSTakashi Sakamoto params->size * i + RX_ISOCHRONOUS, 168436b5abeSTakashi Sakamoto ®, sizeof(reg)); 169436b5abeSTakashi Sakamoto } 170436b5abeSTakashi Sakamoto } 171288a8d0cSTakashi Sakamoto } 172288a8d0cSTakashi Sakamoto 173c738aed1STakashi Sakamoto static int keep_resources(struct snd_dice *dice, struct amdtp_stream *stream, 174c738aed1STakashi Sakamoto struct fw_iso_resources *resources, unsigned int rate, 175c738aed1STakashi Sakamoto unsigned int pcm_chs, unsigned int midi_ports) 176288a8d0cSTakashi Sakamoto { 17727ec83b5STakashi Sakamoto bool double_pcm_frames; 178436b5abeSTakashi Sakamoto unsigned int i; 179288a8d0cSTakashi Sakamoto int err; 180288a8d0cSTakashi Sakamoto 181c738aed1STakashi Sakamoto // At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in 182c738aed1STakashi Sakamoto // one data block of AMDTP packet. Thus sampling transfer frequency is 183c738aed1STakashi Sakamoto // a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are 184c738aed1STakashi Sakamoto // transferred on AMDTP packets at 96 kHz. Two successive samples of a 185c738aed1STakashi Sakamoto // channel are stored consecutively in the packet. This quirk is called 186c738aed1STakashi Sakamoto // as 'Dual Wire'. 187c738aed1STakashi Sakamoto // For this quirk, blocking mode is required and PCM buffer size should 188c738aed1STakashi Sakamoto // be aligned to SYT_INTERVAL. 1896f688268STakashi Sakamoto double_pcm_frames = rate > 96000; 19027ec83b5STakashi Sakamoto if (double_pcm_frames) { 191288a8d0cSTakashi Sakamoto rate /= 2; 192288a8d0cSTakashi Sakamoto pcm_chs *= 2; 193288a8d0cSTakashi Sakamoto } 194288a8d0cSTakashi Sakamoto 19551c29fd2STakashi Sakamoto err = amdtp_am824_set_parameters(stream, rate, pcm_chs, midi_ports, 19651c29fd2STakashi Sakamoto double_pcm_frames); 197547e631cSTakashi Sakamoto if (err < 0) 198436b5abeSTakashi Sakamoto return err; 199547e631cSTakashi Sakamoto 20027ec83b5STakashi Sakamoto if (double_pcm_frames) { 201288a8d0cSTakashi Sakamoto pcm_chs /= 2; 202288a8d0cSTakashi Sakamoto 203288a8d0cSTakashi Sakamoto for (i = 0; i < pcm_chs; i++) { 204f65be911STakashi Sakamoto amdtp_am824_set_pcm_position(stream, i, i * 2); 205f65be911STakashi Sakamoto amdtp_am824_set_pcm_position(stream, i + pcm_chs, 206f65be911STakashi Sakamoto i * 2 + 1); 207288a8d0cSTakashi Sakamoto } 208288a8d0cSTakashi Sakamoto } 209288a8d0cSTakashi Sakamoto 210436b5abeSTakashi Sakamoto return fw_iso_resources_allocate(resources, 211436b5abeSTakashi Sakamoto amdtp_stream_get_max_payload(stream), 212436b5abeSTakashi Sakamoto fw_parent_device(dice->unit)->max_speed); 213288a8d0cSTakashi Sakamoto } 214288a8d0cSTakashi Sakamoto 215c738aed1STakashi Sakamoto static int keep_dual_resources(struct snd_dice *dice, unsigned int rate, 216c738aed1STakashi Sakamoto enum amdtp_stream_direction dir, 217c738aed1STakashi Sakamoto struct reg_params *params) 218c738aed1STakashi Sakamoto { 219c738aed1STakashi Sakamoto enum snd_dice_rate_mode mode; 220c738aed1STakashi Sakamoto int i; 221c738aed1STakashi Sakamoto int err; 222c738aed1STakashi Sakamoto 223c738aed1STakashi Sakamoto err = snd_dice_stream_get_rate_mode(dice, rate, &mode); 224c738aed1STakashi Sakamoto if (err < 0) 225c738aed1STakashi Sakamoto return err; 226c738aed1STakashi Sakamoto 227c738aed1STakashi Sakamoto for (i = 0; i < params->count; ++i) { 228c738aed1STakashi Sakamoto __be32 reg[2]; 229c738aed1STakashi Sakamoto struct amdtp_stream *stream; 230c738aed1STakashi Sakamoto struct fw_iso_resources *resources; 231c738aed1STakashi Sakamoto unsigned int pcm_cache; 232c738aed1STakashi Sakamoto unsigned int midi_cache; 233c738aed1STakashi Sakamoto unsigned int pcm_chs; 234c738aed1STakashi Sakamoto unsigned int midi_ports; 235c738aed1STakashi Sakamoto 236c738aed1STakashi Sakamoto if (dir == AMDTP_IN_STREAM) { 237c738aed1STakashi Sakamoto stream = &dice->tx_stream[i]; 238c738aed1STakashi Sakamoto resources = &dice->tx_resources[i]; 239c738aed1STakashi Sakamoto 240c738aed1STakashi Sakamoto pcm_cache = dice->tx_pcm_chs[i][mode]; 241c738aed1STakashi Sakamoto midi_cache = dice->tx_midi_ports[i]; 242c738aed1STakashi Sakamoto err = snd_dice_transaction_read_tx(dice, 243c738aed1STakashi Sakamoto params->size * i + TX_NUMBER_AUDIO, 244c738aed1STakashi Sakamoto reg, sizeof(reg)); 245c738aed1STakashi Sakamoto } else { 246c738aed1STakashi Sakamoto stream = &dice->rx_stream[i]; 247c738aed1STakashi Sakamoto resources = &dice->rx_resources[i]; 248c738aed1STakashi Sakamoto 249c738aed1STakashi Sakamoto pcm_cache = dice->rx_pcm_chs[i][mode]; 250c738aed1STakashi Sakamoto midi_cache = dice->rx_midi_ports[i]; 251c738aed1STakashi Sakamoto err = snd_dice_transaction_read_rx(dice, 252c738aed1STakashi Sakamoto params->size * i + RX_NUMBER_AUDIO, 253c738aed1STakashi Sakamoto reg, sizeof(reg)); 254c738aed1STakashi Sakamoto } 255c738aed1STakashi Sakamoto if (err < 0) 256c738aed1STakashi Sakamoto return err; 257c738aed1STakashi Sakamoto pcm_chs = be32_to_cpu(reg[0]); 258c738aed1STakashi Sakamoto midi_ports = be32_to_cpu(reg[1]); 259c738aed1STakashi Sakamoto 260c738aed1STakashi Sakamoto // These are important for developer of this driver. 261c738aed1STakashi Sakamoto if (pcm_chs != pcm_cache || midi_ports != midi_cache) { 262c738aed1STakashi Sakamoto dev_info(&dice->unit->device, 263c738aed1STakashi Sakamoto "cache mismatch: pcm: %u:%u, midi: %u:%u\n", 264c738aed1STakashi Sakamoto pcm_chs, pcm_cache, midi_ports, midi_cache); 265c738aed1STakashi Sakamoto return -EPROTO; 266c738aed1STakashi Sakamoto } 267c738aed1STakashi Sakamoto 268c738aed1STakashi Sakamoto err = keep_resources(dice, stream, resources, rate, pcm_chs, 269c738aed1STakashi Sakamoto midi_ports); 270c738aed1STakashi Sakamoto if (err < 0) 271c738aed1STakashi Sakamoto return err; 272c738aed1STakashi Sakamoto } 273c738aed1STakashi Sakamoto 274c738aed1STakashi Sakamoto return 0; 275c738aed1STakashi Sakamoto } 276c738aed1STakashi Sakamoto 277b3480638STakashi Sakamoto static void finish_session(struct snd_dice *dice, struct reg_params *tx_params, 278b3480638STakashi Sakamoto struct reg_params *rx_params) 279b3480638STakashi Sakamoto { 280b3480638STakashi Sakamoto stop_streams(dice, AMDTP_IN_STREAM, tx_params); 281b3480638STakashi Sakamoto stop_streams(dice, AMDTP_OUT_STREAM, rx_params); 282b3480638STakashi Sakamoto 283b3480638STakashi Sakamoto snd_dice_transaction_clear_enable(dice); 284b3480638STakashi Sakamoto } 285b3480638STakashi Sakamoto 2863cd2c2d7STakashi Sakamoto int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate) 2873cd2c2d7STakashi Sakamoto { 2883cd2c2d7STakashi Sakamoto unsigned int curr_rate; 2893cd2c2d7STakashi Sakamoto int err; 2903cd2c2d7STakashi Sakamoto 2913cd2c2d7STakashi Sakamoto // Check sampling transmission frequency. 2923cd2c2d7STakashi Sakamoto err = snd_dice_transaction_get_rate(dice, &curr_rate); 2933cd2c2d7STakashi Sakamoto if (err < 0) 2943cd2c2d7STakashi Sakamoto return err; 2953cd2c2d7STakashi Sakamoto if (rate == 0) 2963cd2c2d7STakashi Sakamoto rate = curr_rate; 2973cd2c2d7STakashi Sakamoto 2983cd2c2d7STakashi Sakamoto if (dice->substreams_counter == 0 || curr_rate != rate) { 2993cd2c2d7STakashi Sakamoto struct reg_params tx_params, rx_params; 3003cd2c2d7STakashi Sakamoto 3013cd2c2d7STakashi Sakamoto err = get_register_params(dice, &tx_params, &rx_params); 3023cd2c2d7STakashi Sakamoto if (err < 0) 3033cd2c2d7STakashi Sakamoto return err; 3043cd2c2d7STakashi Sakamoto 3053cd2c2d7STakashi Sakamoto finish_session(dice, &tx_params, &rx_params); 3063cd2c2d7STakashi Sakamoto 3073cd2c2d7STakashi Sakamoto release_resources(dice); 3083cd2c2d7STakashi Sakamoto 3093cd2c2d7STakashi Sakamoto // Just after owning the unit (GLOBAL_OWNER), the unit can 3103cd2c2d7STakashi Sakamoto // return invalid stream formats. Selecting clock parameters 3113cd2c2d7STakashi Sakamoto // have an effect for the unit to refine it. 3123cd2c2d7STakashi Sakamoto err = ensure_phase_lock(dice, rate); 3133cd2c2d7STakashi Sakamoto if (err < 0) 3143cd2c2d7STakashi Sakamoto return err; 3153cd2c2d7STakashi Sakamoto 3163cd2c2d7STakashi Sakamoto // After changing sampling transfer frequency, the value of 3173cd2c2d7STakashi Sakamoto // register can be changed. 3183cd2c2d7STakashi Sakamoto err = get_register_params(dice, &tx_params, &rx_params); 3193cd2c2d7STakashi Sakamoto if (err < 0) 3203cd2c2d7STakashi Sakamoto return err; 3213cd2c2d7STakashi Sakamoto 3223cd2c2d7STakashi Sakamoto err = keep_dual_resources(dice, rate, AMDTP_IN_STREAM, 3233cd2c2d7STakashi Sakamoto &tx_params); 3243cd2c2d7STakashi Sakamoto if (err < 0) 3253cd2c2d7STakashi Sakamoto goto error; 3263cd2c2d7STakashi Sakamoto 3273cd2c2d7STakashi Sakamoto err = keep_dual_resources(dice, rate, AMDTP_OUT_STREAM, 3283cd2c2d7STakashi Sakamoto &rx_params); 3293cd2c2d7STakashi Sakamoto if (err < 0) 3303cd2c2d7STakashi Sakamoto goto error; 3313cd2c2d7STakashi Sakamoto } 3323cd2c2d7STakashi Sakamoto 3333cd2c2d7STakashi Sakamoto return 0; 3343cd2c2d7STakashi Sakamoto error: 3353cd2c2d7STakashi Sakamoto release_resources(dice); 3363cd2c2d7STakashi Sakamoto return err; 3373cd2c2d7STakashi Sakamoto } 3383cd2c2d7STakashi Sakamoto 339436b5abeSTakashi Sakamoto static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, 3408cc1a8abSTakashi Sakamoto unsigned int rate, struct reg_params *params) 341436b5abeSTakashi Sakamoto { 342c738aed1STakashi Sakamoto unsigned int max_speed = fw_parent_device(dice->unit)->max_speed; 343c738aed1STakashi Sakamoto int i; 344c738aed1STakashi Sakamoto int err; 345436b5abeSTakashi Sakamoto 3468cc1a8abSTakashi Sakamoto for (i = 0; i < params->count; i++) { 347c738aed1STakashi Sakamoto struct amdtp_stream *stream; 348c738aed1STakashi Sakamoto struct fw_iso_resources *resources; 349c738aed1STakashi Sakamoto __be32 reg; 350afa617f2STakashi Sakamoto 351436b5abeSTakashi Sakamoto if (dir == AMDTP_IN_STREAM) { 352c738aed1STakashi Sakamoto stream = dice->tx_stream + i; 353c738aed1STakashi Sakamoto resources = dice->tx_resources + i; 354436b5abeSTakashi Sakamoto } else { 355c738aed1STakashi Sakamoto stream = dice->rx_stream + i; 356c738aed1STakashi Sakamoto resources = dice->rx_resources + i; 357afa617f2STakashi Sakamoto } 358afa617f2STakashi Sakamoto 359c738aed1STakashi Sakamoto reg = cpu_to_be32(resources->channel); 360436b5abeSTakashi Sakamoto if (dir == AMDTP_IN_STREAM) { 361436b5abeSTakashi Sakamoto err = snd_dice_transaction_write_tx(dice, 3628cc1a8abSTakashi Sakamoto params->size * i + TX_ISOCHRONOUS, 363c738aed1STakashi Sakamoto ®, sizeof(reg)); 364436b5abeSTakashi Sakamoto } else { 365436b5abeSTakashi Sakamoto err = snd_dice_transaction_write_rx(dice, 3668cc1a8abSTakashi Sakamoto params->size * i + RX_ISOCHRONOUS, 367c738aed1STakashi Sakamoto ®, sizeof(reg)); 368436b5abeSTakashi Sakamoto } 369436b5abeSTakashi Sakamoto if (err < 0) 370436b5abeSTakashi Sakamoto return err; 371436b5abeSTakashi Sakamoto 372b0e159feSTakashi Sakamoto if (dir == AMDTP_IN_STREAM) { 373c738aed1STakashi Sakamoto reg = cpu_to_be32(max_speed); 374b0e159feSTakashi Sakamoto err = snd_dice_transaction_write_tx(dice, 375b0e159feSTakashi Sakamoto params->size * i + TX_SPEED, 376c738aed1STakashi Sakamoto ®, sizeof(reg)); 377b0e159feSTakashi Sakamoto if (err < 0) 378b0e159feSTakashi Sakamoto return err; 379b0e159feSTakashi Sakamoto } 380b0e159feSTakashi Sakamoto 381c738aed1STakashi Sakamoto err = amdtp_stream_start(stream, resources->channel, max_speed); 382288a8d0cSTakashi Sakamoto if (err < 0) 383288a8d0cSTakashi Sakamoto return err; 384288a8d0cSTakashi Sakamoto } 385288a8d0cSTakashi Sakamoto 386c72d3a0aSTakashi Sakamoto return 0; 387436b5abeSTakashi Sakamoto } 388436b5abeSTakashi Sakamoto 3893cd2c2d7STakashi Sakamoto /* 3903cd2c2d7STakashi Sakamoto * MEMO: After this function, there're two states of streams: 3913cd2c2d7STakashi Sakamoto * - None streams are running. 3923cd2c2d7STakashi Sakamoto * - All streams are running. 3933cd2c2d7STakashi Sakamoto */ 3943cd2c2d7STakashi Sakamoto int snd_dice_stream_start_duplex(struct snd_dice *dice) 39520b94544STakashi Sakamoto { 396d5553026STakashi Sakamoto unsigned int generation = dice->rx_resources[0].generation; 39720b94544STakashi Sakamoto struct reg_params tx_params, rx_params; 3983cd2c2d7STakashi Sakamoto unsigned int i; 3993cd2c2d7STakashi Sakamoto unsigned int rate; 4003cd2c2d7STakashi Sakamoto enum snd_dice_rate_mode mode; 40120b94544STakashi Sakamoto int err; 40220b94544STakashi Sakamoto 4033cd2c2d7STakashi Sakamoto if (dice->substreams_counter == 0) 4043cd2c2d7STakashi Sakamoto return -EIO; 4053cd2c2d7STakashi Sakamoto 40620b94544STakashi Sakamoto err = get_register_params(dice, &tx_params, &rx_params); 40720b94544STakashi Sakamoto if (err < 0) 40820b94544STakashi Sakamoto return err; 40920b94544STakashi Sakamoto 4103cd2c2d7STakashi Sakamoto // Check error of packet streaming. 4113cd2c2d7STakashi Sakamoto for (i = 0; i < MAX_STREAMS; ++i) { 4123cd2c2d7STakashi Sakamoto if (amdtp_streaming_error(&dice->tx_stream[i]) || 4133cd2c2d7STakashi Sakamoto amdtp_streaming_error(&dice->rx_stream[i])) { 414b3480638STakashi Sakamoto finish_session(dice, &tx_params, &rx_params); 4153cd2c2d7STakashi Sakamoto break; 4163cd2c2d7STakashi Sakamoto } 41720b94544STakashi Sakamoto } 41820b94544STakashi Sakamoto 419d5553026STakashi Sakamoto if (generation != fw_parent_device(dice->unit)->card->generation) { 420d5553026STakashi Sakamoto for (i = 0; i < MAX_STREAMS; ++i) { 421d5553026STakashi Sakamoto if (i < tx_params.count) 422d5553026STakashi Sakamoto fw_iso_resources_update(dice->tx_resources + i); 423d5553026STakashi Sakamoto if (i < rx_params.count) 424d5553026STakashi Sakamoto fw_iso_resources_update(dice->rx_resources + i); 425d5553026STakashi Sakamoto } 426d5553026STakashi Sakamoto } 427d5553026STakashi Sakamoto 4283cd2c2d7STakashi Sakamoto // Check required streams are running or not. 4293cd2c2d7STakashi Sakamoto err = snd_dice_transaction_get_rate(dice, &rate); 430afa617f2STakashi Sakamoto if (err < 0) 431afa617f2STakashi Sakamoto return err; 4323cd2c2d7STakashi Sakamoto err = snd_dice_stream_get_rate_mode(dice, rate, &mode); 4333cd2c2d7STakashi Sakamoto if (err < 0) 4343cd2c2d7STakashi Sakamoto return err; 4353cd2c2d7STakashi Sakamoto for (i = 0; i < MAX_STREAMS; ++i) { 4363cd2c2d7STakashi Sakamoto if (dice->tx_pcm_chs[i][mode] > 0 && 4373cd2c2d7STakashi Sakamoto !amdtp_stream_running(&dice->tx_stream[i])) 4383cd2c2d7STakashi Sakamoto break; 4393cd2c2d7STakashi Sakamoto if (dice->rx_pcm_chs[i][mode] > 0 && 4403cd2c2d7STakashi Sakamoto !amdtp_stream_running(&dice->rx_stream[i])) 4413cd2c2d7STakashi Sakamoto break; 4423cd2c2d7STakashi Sakamoto } 4433cd2c2d7STakashi Sakamoto if (i < MAX_STREAMS) { 4443cd2c2d7STakashi Sakamoto // Start both streams. 44520b94544STakashi Sakamoto err = start_streams(dice, AMDTP_IN_STREAM, rate, &tx_params); 44620b94544STakashi Sakamoto if (err < 0) 44720b94544STakashi Sakamoto goto error; 4483cd2c2d7STakashi Sakamoto 44920b94544STakashi Sakamoto err = start_streams(dice, AMDTP_OUT_STREAM, rate, &rx_params); 45020b94544STakashi Sakamoto if (err < 0) 45120b94544STakashi Sakamoto goto error; 45220b94544STakashi Sakamoto 45320b94544STakashi Sakamoto err = snd_dice_transaction_set_enable(dice); 45420b94544STakashi Sakamoto if (err < 0) { 4553cd2c2d7STakashi Sakamoto dev_err(&dice->unit->device, 4563cd2c2d7STakashi Sakamoto "fail to enable interface\n"); 45720b94544STakashi Sakamoto goto error; 45820b94544STakashi Sakamoto } 45920b94544STakashi Sakamoto 46020b94544STakashi Sakamoto for (i = 0; i < MAX_STREAMS; i++) { 46120b94544STakashi Sakamoto if ((i < tx_params.count && 46220b94544STakashi Sakamoto !amdtp_stream_wait_callback(&dice->tx_stream[i], 46320b94544STakashi Sakamoto CALLBACK_TIMEOUT)) || 46420b94544STakashi Sakamoto (i < rx_params.count && 46520b94544STakashi Sakamoto !amdtp_stream_wait_callback(&dice->rx_stream[i], 46620b94544STakashi Sakamoto CALLBACK_TIMEOUT))) { 46720b94544STakashi Sakamoto err = -ETIMEDOUT; 46820b94544STakashi Sakamoto goto error; 46920b94544STakashi Sakamoto } 47020b94544STakashi Sakamoto } 4713cd2c2d7STakashi Sakamoto } 47220b94544STakashi Sakamoto 47320b94544STakashi Sakamoto return 0; 47420b94544STakashi Sakamoto error: 475b3480638STakashi Sakamoto finish_session(dice, &tx_params, &rx_params); 47620b94544STakashi Sakamoto return err; 47720b94544STakashi Sakamoto } 47820b94544STakashi Sakamoto 479436b5abeSTakashi Sakamoto /* 480436b5abeSTakashi Sakamoto * MEMO: After this function, there're two states of streams: 481436b5abeSTakashi Sakamoto * - None streams are running. 482436b5abeSTakashi Sakamoto * - All streams are running. 483436b5abeSTakashi Sakamoto */ 4849a02843cSTakashi Sakamoto void snd_dice_stream_stop_duplex(struct snd_dice *dice) 4856eb6c81eSTakashi Sakamoto { 4868cc1a8abSTakashi Sakamoto struct reg_params tx_params, rx_params; 487436b5abeSTakashi Sakamoto 4883cd2c2d7STakashi Sakamoto if (dice->substreams_counter == 0) { 489b3480638STakashi Sakamoto if (get_register_params(dice, &tx_params, &rx_params) >= 0) 490b3480638STakashi Sakamoto finish_session(dice, &tx_params, &rx_params); 491740680f2STakashi Sakamoto 492740680f2STakashi Sakamoto release_resources(dice); 4933cd2c2d7STakashi Sakamoto } 494436b5abeSTakashi Sakamoto } 4959a02843cSTakashi Sakamoto 496436b5abeSTakashi Sakamoto static int init_stream(struct snd_dice *dice, enum amdtp_stream_direction dir, 497436b5abeSTakashi Sakamoto unsigned int index) 498436b5abeSTakashi Sakamoto { 499436b5abeSTakashi Sakamoto struct amdtp_stream *stream; 500436b5abeSTakashi Sakamoto struct fw_iso_resources *resources; 501436b5abeSTakashi Sakamoto int err; 502436b5abeSTakashi Sakamoto 503436b5abeSTakashi Sakamoto if (dir == AMDTP_IN_STREAM) { 504436b5abeSTakashi Sakamoto stream = &dice->tx_stream[index]; 505436b5abeSTakashi Sakamoto resources = &dice->tx_resources[index]; 5069a02843cSTakashi Sakamoto } else { 507436b5abeSTakashi Sakamoto stream = &dice->rx_stream[index]; 508436b5abeSTakashi Sakamoto resources = &dice->rx_resources[index]; 5099a02843cSTakashi Sakamoto } 5109a02843cSTakashi Sakamoto 5119a02843cSTakashi Sakamoto err = fw_iso_resources_init(resources, dice->unit); 5129a02843cSTakashi Sakamoto if (err < 0) 5139a02843cSTakashi Sakamoto goto end; 5149a02843cSTakashi Sakamoto resources->channels_mask = 0x00000000ffffffffuLL; 5159a02843cSTakashi Sakamoto 5165955815eSTakashi Sakamoto err = amdtp_am824_init(stream, dice->unit, dir, CIP_BLOCKING); 5179a02843cSTakashi Sakamoto if (err < 0) { 5189a02843cSTakashi Sakamoto amdtp_stream_destroy(stream); 5199a02843cSTakashi Sakamoto fw_iso_resources_destroy(resources); 5209a02843cSTakashi Sakamoto } 5219a02843cSTakashi Sakamoto end: 5229a02843cSTakashi Sakamoto return err; 5239a02843cSTakashi Sakamoto } 5249a02843cSTakashi Sakamoto 525d23c2cc4STakashi Sakamoto /* 526d23c2cc4STakashi Sakamoto * This function should be called before starting streams or after stopping 527d23c2cc4STakashi Sakamoto * streams. 528d23c2cc4STakashi Sakamoto */ 529436b5abeSTakashi Sakamoto static void destroy_stream(struct snd_dice *dice, 530436b5abeSTakashi Sakamoto enum amdtp_stream_direction dir, 531436b5abeSTakashi Sakamoto unsigned int index) 5329a02843cSTakashi Sakamoto { 533436b5abeSTakashi Sakamoto struct amdtp_stream *stream; 534d23c2cc4STakashi Sakamoto struct fw_iso_resources *resources; 5359a02843cSTakashi Sakamoto 536436b5abeSTakashi Sakamoto if (dir == AMDTP_IN_STREAM) { 537436b5abeSTakashi Sakamoto stream = &dice->tx_stream[index]; 538436b5abeSTakashi Sakamoto resources = &dice->tx_resources[index]; 539436b5abeSTakashi Sakamoto } else { 540436b5abeSTakashi Sakamoto stream = &dice->rx_stream[index]; 541436b5abeSTakashi Sakamoto resources = &dice->rx_resources[index]; 542436b5abeSTakashi Sakamoto } 543d23c2cc4STakashi Sakamoto 544d23c2cc4STakashi Sakamoto amdtp_stream_destroy(stream); 545d23c2cc4STakashi Sakamoto fw_iso_resources_destroy(resources); 5469a02843cSTakashi Sakamoto } 5479a02843cSTakashi Sakamoto 5489a02843cSTakashi Sakamoto int snd_dice_stream_init_duplex(struct snd_dice *dice) 5496eb6c81eSTakashi Sakamoto { 550436b5abeSTakashi Sakamoto int i, err; 5516eb6c81eSTakashi Sakamoto 552436b5abeSTakashi Sakamoto for (i = 0; i < MAX_STREAMS; i++) { 553436b5abeSTakashi Sakamoto err = init_stream(dice, AMDTP_IN_STREAM, i); 554436b5abeSTakashi Sakamoto if (err < 0) { 555436b5abeSTakashi Sakamoto for (; i >= 0; i--) 5560f925660STakashi Sakamoto destroy_stream(dice, AMDTP_IN_STREAM, i); 5576eb6c81eSTakashi Sakamoto goto end; 558436b5abeSTakashi Sakamoto } 559436b5abeSTakashi Sakamoto } 5606eb6c81eSTakashi Sakamoto 561436b5abeSTakashi Sakamoto for (i = 0; i < MAX_STREAMS; i++) { 562436b5abeSTakashi Sakamoto err = init_stream(dice, AMDTP_OUT_STREAM, i); 563436b5abeSTakashi Sakamoto if (err < 0) { 564436b5abeSTakashi Sakamoto for (; i >= 0; i--) 565436b5abeSTakashi Sakamoto destroy_stream(dice, AMDTP_OUT_STREAM, i); 566436b5abeSTakashi Sakamoto for (i = 0; i < MAX_STREAMS; i++) 567436b5abeSTakashi Sakamoto destroy_stream(dice, AMDTP_IN_STREAM, i); 568436b5abeSTakashi Sakamoto break; 569436b5abeSTakashi Sakamoto } 570436b5abeSTakashi Sakamoto } 5716eb6c81eSTakashi Sakamoto end: 5726eb6c81eSTakashi Sakamoto return err; 5736eb6c81eSTakashi Sakamoto } 5746eb6c81eSTakashi Sakamoto 5759a02843cSTakashi Sakamoto void snd_dice_stream_destroy_duplex(struct snd_dice *dice) 5766eb6c81eSTakashi Sakamoto { 5776b94fb14STakashi Sakamoto unsigned int i; 578436b5abeSTakashi Sakamoto 5796b94fb14STakashi Sakamoto for (i = 0; i < MAX_STREAMS; i++) { 5806b94fb14STakashi Sakamoto destroy_stream(dice, AMDTP_IN_STREAM, i); 5816b94fb14STakashi Sakamoto destroy_stream(dice, AMDTP_OUT_STREAM, i); 582436b5abeSTakashi Sakamoto } 5836eb6c81eSTakashi Sakamoto } 5846eb6c81eSTakashi Sakamoto 5859a02843cSTakashi Sakamoto void snd_dice_stream_update_duplex(struct snd_dice *dice) 5866eb6c81eSTakashi Sakamoto { 5878cc1a8abSTakashi Sakamoto struct reg_params tx_params, rx_params; 588436b5abeSTakashi Sakamoto 5896eb6c81eSTakashi Sakamoto /* 5906eb6c81eSTakashi Sakamoto * On a bus reset, the DICE firmware disables streaming and then goes 5916eb6c81eSTakashi Sakamoto * off contemplating its own navel for hundreds of milliseconds before 5926eb6c81eSTakashi Sakamoto * it can react to any of our attempts to reenable streaming. This 5936eb6c81eSTakashi Sakamoto * means that we lose synchronization anyway, so we force our streams 5946eb6c81eSTakashi Sakamoto * to stop so that the application can restart them in an orderly 5956eb6c81eSTakashi Sakamoto * manner. 5966eb6c81eSTakashi Sakamoto */ 5976eb6c81eSTakashi Sakamoto dice->global_enabled = false; 5986eb6c81eSTakashi Sakamoto 5998cc1a8abSTakashi Sakamoto if (get_register_params(dice, &tx_params, &rx_params) == 0) { 6008cc1a8abSTakashi Sakamoto stop_streams(dice, AMDTP_IN_STREAM, &tx_params); 6018cc1a8abSTakashi Sakamoto stop_streams(dice, AMDTP_OUT_STREAM, &rx_params); 602436b5abeSTakashi Sakamoto } 6036eb6c81eSTakashi Sakamoto } 6046eb6c81eSTakashi Sakamoto 605b60152f7STakashi Sakamoto int snd_dice_stream_detect_current_formats(struct snd_dice *dice) 606b60152f7STakashi Sakamoto { 607b60152f7STakashi Sakamoto unsigned int rate; 608b60152f7STakashi Sakamoto enum snd_dice_rate_mode mode; 609b60152f7STakashi Sakamoto __be32 reg[2]; 610b60152f7STakashi Sakamoto struct reg_params tx_params, rx_params; 611b60152f7STakashi Sakamoto int i; 612b60152f7STakashi Sakamoto int err; 613b60152f7STakashi Sakamoto 61458579c05STakashi Sakamoto /* If extended protocol is available, detect detail spec. */ 61558579c05STakashi Sakamoto err = snd_dice_detect_extension_formats(dice); 61658579c05STakashi Sakamoto if (err >= 0) 61758579c05STakashi Sakamoto return err; 61858579c05STakashi Sakamoto 619b60152f7STakashi Sakamoto /* 620b60152f7STakashi Sakamoto * Available stream format is restricted at current mode of sampling 621b60152f7STakashi Sakamoto * clock. 622b60152f7STakashi Sakamoto */ 623b60152f7STakashi Sakamoto err = snd_dice_transaction_get_rate(dice, &rate); 624b60152f7STakashi Sakamoto if (err < 0) 625b60152f7STakashi Sakamoto return err; 626b60152f7STakashi Sakamoto 627b60152f7STakashi Sakamoto err = snd_dice_stream_get_rate_mode(dice, rate, &mode); 628b60152f7STakashi Sakamoto if (err < 0) 629b60152f7STakashi Sakamoto return err; 630b60152f7STakashi Sakamoto 631b60152f7STakashi Sakamoto /* 632b60152f7STakashi Sakamoto * Just after owning the unit (GLOBAL_OWNER), the unit can return 633b60152f7STakashi Sakamoto * invalid stream formats. Selecting clock parameters have an effect 634b60152f7STakashi Sakamoto * for the unit to refine it. 635b60152f7STakashi Sakamoto */ 636afa617f2STakashi Sakamoto err = ensure_phase_lock(dice, rate); 637b60152f7STakashi Sakamoto if (err < 0) 638b60152f7STakashi Sakamoto return err; 639b60152f7STakashi Sakamoto 640b60152f7STakashi Sakamoto err = get_register_params(dice, &tx_params, &rx_params); 641b60152f7STakashi Sakamoto if (err < 0) 642b60152f7STakashi Sakamoto return err; 643b60152f7STakashi Sakamoto 644b60152f7STakashi Sakamoto for (i = 0; i < tx_params.count; ++i) { 645b60152f7STakashi Sakamoto err = snd_dice_transaction_read_tx(dice, 646b60152f7STakashi Sakamoto tx_params.size * i + TX_NUMBER_AUDIO, 647b60152f7STakashi Sakamoto reg, sizeof(reg)); 648b60152f7STakashi Sakamoto if (err < 0) 649b60152f7STakashi Sakamoto return err; 650b60152f7STakashi Sakamoto dice->tx_pcm_chs[i][mode] = be32_to_cpu(reg[0]); 651b60152f7STakashi Sakamoto dice->tx_midi_ports[i] = max_t(unsigned int, 652b60152f7STakashi Sakamoto be32_to_cpu(reg[1]), dice->tx_midi_ports[i]); 653b60152f7STakashi Sakamoto } 654b60152f7STakashi Sakamoto for (i = 0; i < rx_params.count; ++i) { 655b60152f7STakashi Sakamoto err = snd_dice_transaction_read_rx(dice, 656b60152f7STakashi Sakamoto rx_params.size * i + RX_NUMBER_AUDIO, 657b60152f7STakashi Sakamoto reg, sizeof(reg)); 658b60152f7STakashi Sakamoto if (err < 0) 659b60152f7STakashi Sakamoto return err; 660b60152f7STakashi Sakamoto dice->rx_pcm_chs[i][mode] = be32_to_cpu(reg[0]); 661b60152f7STakashi Sakamoto dice->rx_midi_ports[i] = max_t(unsigned int, 662b60152f7STakashi Sakamoto be32_to_cpu(reg[1]), dice->rx_midi_ports[i]); 663b60152f7STakashi Sakamoto } 664b60152f7STakashi Sakamoto 665b60152f7STakashi Sakamoto return 0; 666b60152f7STakashi Sakamoto } 667b60152f7STakashi Sakamoto 6686eb6c81eSTakashi Sakamoto static void dice_lock_changed(struct snd_dice *dice) 6696eb6c81eSTakashi Sakamoto { 6706eb6c81eSTakashi Sakamoto dice->dev_lock_changed = true; 6716eb6c81eSTakashi Sakamoto wake_up(&dice->hwdep_wait); 6726eb6c81eSTakashi Sakamoto } 6736eb6c81eSTakashi Sakamoto 6746eb6c81eSTakashi Sakamoto int snd_dice_stream_lock_try(struct snd_dice *dice) 6756eb6c81eSTakashi Sakamoto { 6766eb6c81eSTakashi Sakamoto int err; 6776eb6c81eSTakashi Sakamoto 6786eb6c81eSTakashi Sakamoto spin_lock_irq(&dice->lock); 6796eb6c81eSTakashi Sakamoto 6806eb6c81eSTakashi Sakamoto if (dice->dev_lock_count < 0) { 6816eb6c81eSTakashi Sakamoto err = -EBUSY; 6826eb6c81eSTakashi Sakamoto goto out; 6836eb6c81eSTakashi Sakamoto } 6846eb6c81eSTakashi Sakamoto 6856eb6c81eSTakashi Sakamoto if (dice->dev_lock_count++ == 0) 6866eb6c81eSTakashi Sakamoto dice_lock_changed(dice); 6876eb6c81eSTakashi Sakamoto err = 0; 6886eb6c81eSTakashi Sakamoto out: 6896eb6c81eSTakashi Sakamoto spin_unlock_irq(&dice->lock); 6906eb6c81eSTakashi Sakamoto return err; 6916eb6c81eSTakashi Sakamoto } 6926eb6c81eSTakashi Sakamoto 6936eb6c81eSTakashi Sakamoto void snd_dice_stream_lock_release(struct snd_dice *dice) 6946eb6c81eSTakashi Sakamoto { 6956eb6c81eSTakashi Sakamoto spin_lock_irq(&dice->lock); 6966eb6c81eSTakashi Sakamoto 6976eb6c81eSTakashi Sakamoto if (WARN_ON(dice->dev_lock_count <= 0)) 6986eb6c81eSTakashi Sakamoto goto out; 6996eb6c81eSTakashi Sakamoto 7006eb6c81eSTakashi Sakamoto if (--dice->dev_lock_count == 0) 7016eb6c81eSTakashi Sakamoto dice_lock_changed(dice); 7026eb6c81eSTakashi Sakamoto out: 7036eb6c81eSTakashi Sakamoto spin_unlock_irq(&dice->lock); 7046eb6c81eSTakashi Sakamoto } 705