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