1 // SPDX-License-Identifier: GPL-2.0-or-later 1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 2 /* 3 * Driver for Digigram VX soundcards 3 * Driver for Digigram VX soundcards 4 * 4 * 5 * IEC958 stuff 5 * IEC958 stuff 6 * 6 * 7 * Copyright (c) 2002 by Takashi Iwai <tiwai@s 7 * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> 8 */ 8 */ 9 9 10 #include <linux/delay.h> 10 #include <linux/delay.h> 11 #include <sound/core.h> 11 #include <sound/core.h> 12 #include <sound/vx_core.h> 12 #include <sound/vx_core.h> 13 #include "vx_cmd.h" 13 #include "vx_cmd.h" 14 14 15 15 16 /* 16 /* 17 * vx_modify_board_clock - tell the board that 17 * vx_modify_board_clock - tell the board that its clock has been modified 18 * @sync: DSP needs to resynchronize its FIFO 18 * @sync: DSP needs to resynchronize its FIFO 19 */ 19 */ 20 static int vx_modify_board_clock(struct vx_cor 20 static int vx_modify_board_clock(struct vx_core *chip, int sync) 21 { 21 { 22 struct vx_rmh rmh; 22 struct vx_rmh rmh; 23 23 24 vx_init_rmh(&rmh, CMD_MODIFY_CLOCK); 24 vx_init_rmh(&rmh, CMD_MODIFY_CLOCK); 25 /* Ask the DSP to resynchronize its FI 25 /* Ask the DSP to resynchronize its FIFO. */ 26 if (sync) 26 if (sync) 27 rmh.Cmd[0] |= CMD_MODIFY_CLOCK 27 rmh.Cmd[0] |= CMD_MODIFY_CLOCK_S_BIT; 28 return vx_send_msg(chip, &rmh); 28 return vx_send_msg(chip, &rmh); 29 } 29 } 30 30 31 /* 31 /* 32 * vx_modify_board_inputs - resync audio input 32 * vx_modify_board_inputs - resync audio inputs 33 */ 33 */ 34 static int vx_modify_board_inputs(struct vx_co 34 static int vx_modify_board_inputs(struct vx_core *chip) 35 { 35 { 36 struct vx_rmh rmh; 36 struct vx_rmh rmh; 37 37 38 vx_init_rmh(&rmh, CMD_RESYNC_AUDIO_INP 38 vx_init_rmh(&rmh, CMD_RESYNC_AUDIO_INPUTS); 39 rmh.Cmd[0] |= 1 << 0; /* reference: AU 39 rmh.Cmd[0] |= 1 << 0; /* reference: AUDIO 0 */ 40 return vx_send_msg(chip, &rmh); 40 return vx_send_msg(chip, &rmh); 41 } 41 } 42 42 43 /* 43 /* 44 * vx_read_one_cbit - read one bit from UER co 44 * vx_read_one_cbit - read one bit from UER config 45 * @index: the bit index 45 * @index: the bit index 46 * returns 0 or 1. 46 * returns 0 or 1. 47 */ 47 */ 48 static int vx_read_one_cbit(struct vx_core *ch 48 static int vx_read_one_cbit(struct vx_core *chip, int index) 49 { 49 { 50 int val; 50 int val; 51 51 52 mutex_lock(&chip->lock); 52 mutex_lock(&chip->lock); 53 if (chip->type >= VX_TYPE_VXPOCKET) { 53 if (chip->type >= VX_TYPE_VXPOCKET) { 54 vx_outb(chip, CSUER, 1); /* re 54 vx_outb(chip, CSUER, 1); /* read */ 55 vx_outb(chip, RUER, index & XX 55 vx_outb(chip, RUER, index & XX_UER_CBITS_OFFSET_MASK); 56 val = (vx_inb(chip, RUER) >> 7 56 val = (vx_inb(chip, RUER) >> 7) & 0x01; 57 } else { 57 } else { 58 vx_outl(chip, CSUER, 1); /* re 58 vx_outl(chip, CSUER, 1); /* read */ 59 vx_outl(chip, RUER, index & XX 59 vx_outl(chip, RUER, index & XX_UER_CBITS_OFFSET_MASK); 60 val = (vx_inl(chip, RUER) >> 7 60 val = (vx_inl(chip, RUER) >> 7) & 0x01; 61 } 61 } 62 mutex_unlock(&chip->lock); 62 mutex_unlock(&chip->lock); 63 return val; 63 return val; 64 } 64 } 65 65 66 /* 66 /* 67 * vx_write_one_cbit - write one bit to UER co 67 * vx_write_one_cbit - write one bit to UER config 68 * @index: the bit index 68 * @index: the bit index 69 * @val: bit value, 0 or 1 69 * @val: bit value, 0 or 1 70 */ 70 */ 71 static void vx_write_one_cbit(struct vx_core * 71 static void vx_write_one_cbit(struct vx_core *chip, int index, int val) 72 { 72 { 73 val = !!val; /* 0 or 1 */ 73 val = !!val; /* 0 or 1 */ 74 mutex_lock(&chip->lock); 74 mutex_lock(&chip->lock); 75 if (vx_is_pcmcia(chip)) { 75 if (vx_is_pcmcia(chip)) { 76 vx_outb(chip, CSUER, 0); /* wr 76 vx_outb(chip, CSUER, 0); /* write */ 77 vx_outb(chip, RUER, (val << 7) 77 vx_outb(chip, RUER, (val << 7) | (index & XX_UER_CBITS_OFFSET_MASK)); 78 } else { 78 } else { 79 vx_outl(chip, CSUER, 0); /* wr 79 vx_outl(chip, CSUER, 0); /* write */ 80 vx_outl(chip, RUER, (val << 7) 80 vx_outl(chip, RUER, (val << 7) | (index & XX_UER_CBITS_OFFSET_MASK)); 81 } 81 } 82 mutex_unlock(&chip->lock); 82 mutex_unlock(&chip->lock); 83 } 83 } 84 84 85 /* 85 /* 86 * vx_read_uer_status - read the current UER s 86 * vx_read_uer_status - read the current UER status 87 * @mode: pointer to store the UER mode, VX_UE 87 * @mode: pointer to store the UER mode, VX_UER_MODE_XXX 88 * 88 * 89 * returns the frequency of UER, or 0 if not s 89 * returns the frequency of UER, or 0 if not sync, 90 * or a negative error code. 90 * or a negative error code. 91 */ 91 */ 92 static int vx_read_uer_status(struct vx_core * 92 static int vx_read_uer_status(struct vx_core *chip, unsigned int *mode) 93 { 93 { 94 int val, freq; 94 int val, freq; 95 95 96 /* Default values */ 96 /* Default values */ 97 freq = 0; 97 freq = 0; 98 98 99 /* Read UER status */ 99 /* Read UER status */ 100 if (vx_is_pcmcia(chip)) 100 if (vx_is_pcmcia(chip)) 101 val = vx_inb(chip, CSUER); 101 val = vx_inb(chip, CSUER); 102 else 102 else 103 val = vx_inl(chip, CSUER); 103 val = vx_inl(chip, CSUER); 104 if (val < 0) 104 if (val < 0) 105 return val; 105 return val; 106 /* If clock is present, read frequency 106 /* If clock is present, read frequency */ 107 if (val & VX_SUER_CLOCK_PRESENT_MASK) 107 if (val & VX_SUER_CLOCK_PRESENT_MASK) { 108 switch (val & VX_SUER_FREQ_MAS 108 switch (val & VX_SUER_FREQ_MASK) { 109 case VX_SUER_FREQ_32KHz_MASK: 109 case VX_SUER_FREQ_32KHz_MASK: 110 freq = 32000; 110 freq = 32000; 111 break; 111 break; 112 case VX_SUER_FREQ_44KHz_MASK: 112 case VX_SUER_FREQ_44KHz_MASK: 113 freq = 44100; 113 freq = 44100; 114 break; 114 break; 115 case VX_SUER_FREQ_48KHz_MASK: 115 case VX_SUER_FREQ_48KHz_MASK: 116 freq = 48000; 116 freq = 48000; 117 break; 117 break; 118 } 118 } 119 } 119 } 120 if (val & VX_SUER_DATA_PRESENT_MASK) 120 if (val & VX_SUER_DATA_PRESENT_MASK) 121 /* bit 0 corresponds to consum 121 /* bit 0 corresponds to consumer/professional bit */ 122 *mode = vx_read_one_cbit(chip, 122 *mode = vx_read_one_cbit(chip, 0) ? 123 VX_UER_MODE_PROFESSION 123 VX_UER_MODE_PROFESSIONAL : VX_UER_MODE_CONSUMER; 124 else 124 else 125 *mode = VX_UER_MODE_NOT_PRESEN 125 *mode = VX_UER_MODE_NOT_PRESENT; 126 126 127 return freq; 127 return freq; 128 } 128 } 129 129 130 130 131 /* 131 /* 132 * compute the sample clock value from frequen 132 * compute the sample clock value from frequency 133 * 133 * 134 * The formula is as follows: 134 * The formula is as follows: 135 * 135 * 136 * HexFreq = (dword) ((double) ((double) 28 136 * HexFreq = (dword) ((double) ((double) 28224000 / (double) Frequency)) 137 * switch ( HexFreq & 0x00000F00 ) 137 * switch ( HexFreq & 0x00000F00 ) 138 * case 0x00000100: ; 138 * case 0x00000100: ; 139 * case 0x00000200: 139 * case 0x00000200: 140 * case 0x00000300: HexFreq -= 0x00000201 ; 140 * case 0x00000300: HexFreq -= 0x00000201 ; 141 * case 0x00000400: 141 * case 0x00000400: 142 * case 0x00000500: 142 * case 0x00000500: 143 * case 0x00000600: 143 * case 0x00000600: 144 * case 0x00000700: HexFreq = (dword) (((do 144 * case 0x00000700: HexFreq = (dword) (((double) 28224000 / (double) (Frequency*2)) - 1) 145 * default : HexFreq = (dword) ((dou 145 * default : HexFreq = (dword) ((double) 28224000 / (double) (Frequency*4)) - 0x000001FF 146 */ 146 */ 147 147 148 static int vx_calc_clock_from_freq(struct vx_c 148 static int vx_calc_clock_from_freq(struct vx_core *chip, int freq) 149 { 149 { 150 int hexfreq; 150 int hexfreq; 151 151 152 if (snd_BUG_ON(freq <= 0)) 152 if (snd_BUG_ON(freq <= 0)) 153 return 0; 153 return 0; 154 154 155 hexfreq = (28224000 * 10) / freq; 155 hexfreq = (28224000 * 10) / freq; 156 hexfreq = (hexfreq + 5) / 10; 156 hexfreq = (hexfreq + 5) / 10; 157 157 158 /* max freq = 55125 Hz */ 158 /* max freq = 55125 Hz */ 159 if (snd_BUG_ON(hexfreq <= 0x00000200)) 159 if (snd_BUG_ON(hexfreq <= 0x00000200)) 160 return 0; 160 return 0; 161 161 162 if (hexfreq <= 0x03ff) 162 if (hexfreq <= 0x03ff) 163 return hexfreq - 0x00000201; 163 return hexfreq - 0x00000201; 164 if (hexfreq <= 0x07ff) 164 if (hexfreq <= 0x07ff) 165 return (hexfreq / 2) - 1; 165 return (hexfreq / 2) - 1; 166 if (hexfreq <= 0x0fff) 166 if (hexfreq <= 0x0fff) 167 return (hexfreq / 4) + 0x00000 167 return (hexfreq / 4) + 0x000001ff; 168 168 169 return 0x5fe; /* min freq = 6893 Hz 169 return 0x5fe; /* min freq = 6893 Hz */ 170 } 170 } 171 171 172 172 173 /* 173 /* 174 * vx_change_clock_source - change the clock s 174 * vx_change_clock_source - change the clock source 175 * @source: the new source 175 * @source: the new source 176 */ 176 */ 177 static void vx_change_clock_source(struct vx_c 177 static void vx_change_clock_source(struct vx_core *chip, int source) 178 { 178 { 179 /* we mute DAC to prevent clicks */ 179 /* we mute DAC to prevent clicks */ 180 vx_toggle_dac_mute(chip, 1); 180 vx_toggle_dac_mute(chip, 1); 181 mutex_lock(&chip->lock); 181 mutex_lock(&chip->lock); 182 chip->ops->set_clock_source(chip, sour 182 chip->ops->set_clock_source(chip, source); 183 chip->clock_source = source; 183 chip->clock_source = source; 184 mutex_unlock(&chip->lock); 184 mutex_unlock(&chip->lock); 185 /* unmute */ 185 /* unmute */ 186 vx_toggle_dac_mute(chip, 0); 186 vx_toggle_dac_mute(chip, 0); 187 } 187 } 188 188 189 189 190 /* 190 /* 191 * set the internal clock 191 * set the internal clock 192 */ 192 */ 193 void vx_set_internal_clock(struct vx_core *chi 193 void vx_set_internal_clock(struct vx_core *chip, unsigned int freq) 194 { 194 { 195 int clock; 195 int clock; 196 196 197 /* Get real clock value */ 197 /* Get real clock value */ 198 clock = vx_calc_clock_from_freq(chip, 198 clock = vx_calc_clock_from_freq(chip, freq); 199 dev_dbg(chip->card->dev, 199 dev_dbg(chip->card->dev, 200 "set internal clock to 0x%x fr 200 "set internal clock to 0x%x from freq %d\n", clock, freq); 201 mutex_lock(&chip->lock); 201 mutex_lock(&chip->lock); 202 if (vx_is_pcmcia(chip)) { 202 if (vx_is_pcmcia(chip)) { 203 vx_outb(chip, HIFREQ, (clock > 203 vx_outb(chip, HIFREQ, (clock >> 8) & 0x0f); 204 vx_outb(chip, LOFREQ, clock & 204 vx_outb(chip, LOFREQ, clock & 0xff); 205 } else { 205 } else { 206 vx_outl(chip, HIFREQ, (clock > 206 vx_outl(chip, HIFREQ, (clock >> 8) & 0x0f); 207 vx_outl(chip, LOFREQ, clock & 207 vx_outl(chip, LOFREQ, clock & 0xff); 208 } 208 } 209 mutex_unlock(&chip->lock); 209 mutex_unlock(&chip->lock); 210 } 210 } 211 211 212 212 213 /* 213 /* 214 * set the iec958 status bits 214 * set the iec958 status bits 215 * @bits: 32-bit status bits 215 * @bits: 32-bit status bits 216 */ 216 */ 217 void vx_set_iec958_status(struct vx_core *chip 217 void vx_set_iec958_status(struct vx_core *chip, unsigned int bits) 218 { 218 { 219 int i; 219 int i; 220 220 221 if (chip->chip_status & VX_STAT_IS_STA 221 if (chip->chip_status & VX_STAT_IS_STALE) 222 return; 222 return; 223 223 224 for (i = 0; i < 32; i++) 224 for (i = 0; i < 32; i++) 225 vx_write_one_cbit(chip, i, bit 225 vx_write_one_cbit(chip, i, bits & (1 << i)); 226 } 226 } 227 227 228 228 229 /* 229 /* 230 * vx_set_clock - change the clock and audio s 230 * vx_set_clock - change the clock and audio source if necessary 231 */ 231 */ 232 int vx_set_clock(struct vx_core *chip, unsigne 232 int vx_set_clock(struct vx_core *chip, unsigned int freq) 233 { 233 { 234 int src_changed = 0; 234 int src_changed = 0; 235 235 236 if (chip->chip_status & VX_STAT_IS_STA 236 if (chip->chip_status & VX_STAT_IS_STALE) 237 return 0; 237 return 0; 238 238 239 /* change the audio source if possible 239 /* change the audio source if possible */ 240 vx_sync_audio_source(chip); 240 vx_sync_audio_source(chip); 241 241 242 if (chip->clock_mode == VX_CLOCK_MODE_ 242 if (chip->clock_mode == VX_CLOCK_MODE_EXTERNAL || 243 (chip->clock_mode == VX_CLOCK_MODE 243 (chip->clock_mode == VX_CLOCK_MODE_AUTO && 244 chip->audio_source == VX_AUDIO_SR 244 chip->audio_source == VX_AUDIO_SRC_DIGITAL)) { 245 if (chip->clock_source != UER_ 245 if (chip->clock_source != UER_SYNC) { 246 vx_change_clock_source 246 vx_change_clock_source(chip, UER_SYNC); 247 mdelay(6); 247 mdelay(6); 248 src_changed = 1; 248 src_changed = 1; 249 } 249 } 250 } else if (chip->clock_mode == VX_CLOC 250 } else if (chip->clock_mode == VX_CLOCK_MODE_INTERNAL || 251 (chip->clock_mode == VX_CLO 251 (chip->clock_mode == VX_CLOCK_MODE_AUTO && 252 chip->audio_source != VX_A 252 chip->audio_source != VX_AUDIO_SRC_DIGITAL)) { 253 if (chip->clock_source != INTE 253 if (chip->clock_source != INTERNAL_QUARTZ) { 254 vx_change_clock_source 254 vx_change_clock_source(chip, INTERNAL_QUARTZ); 255 src_changed = 1; 255 src_changed = 1; 256 } 256 } 257 if (chip->freq == freq) 257 if (chip->freq == freq) 258 return 0; 258 return 0; 259 vx_set_internal_clock(chip, fr 259 vx_set_internal_clock(chip, freq); 260 if (src_changed) 260 if (src_changed) 261 vx_modify_board_inputs 261 vx_modify_board_inputs(chip); 262 } 262 } 263 if (chip->freq == freq) 263 if (chip->freq == freq) 264 return 0; 264 return 0; 265 chip->freq = freq; 265 chip->freq = freq; 266 vx_modify_board_clock(chip, 1); 266 vx_modify_board_clock(chip, 1); 267 return 0; 267 return 0; 268 } 268 } 269 269 270 270 271 /* 271 /* 272 * vx_change_frequency - called from interrupt 272 * vx_change_frequency - called from interrupt handler 273 */ 273 */ 274 int vx_change_frequency(struct vx_core *chip) 274 int vx_change_frequency(struct vx_core *chip) 275 { 275 { 276 int freq; 276 int freq; 277 277 278 if (chip->chip_status & VX_STAT_IS_STA 278 if (chip->chip_status & VX_STAT_IS_STALE) 279 return 0; 279 return 0; 280 280 281 if (chip->clock_source == INTERNAL_QUA 281 if (chip->clock_source == INTERNAL_QUARTZ) 282 return 0; 282 return 0; 283 /* 283 /* 284 * Read the real UER board frequency 284 * Read the real UER board frequency 285 */ 285 */ 286 freq = vx_read_uer_status(chip, &chip- 286 freq = vx_read_uer_status(chip, &chip->uer_detected); 287 if (freq < 0) 287 if (freq < 0) 288 return freq; 288 return freq; 289 /* 289 /* 290 * The frequency computed by the DSP i 290 * The frequency computed by the DSP is good and 291 * is different from the previous comp 291 * is different from the previous computed. 292 */ 292 */ 293 if (freq == 48000 || freq == 44100 || 293 if (freq == 48000 || freq == 44100 || freq == 32000) 294 chip->freq_detected = freq; 294 chip->freq_detected = freq; 295 295 296 return 0; 296 return 0; 297 } 297 } 298 298
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.