File Index
Files and directories
Sign in
FILE

vx_uer.c

File preview with syntax highlighting.

linux-6.19.14/sound/drivers/vx/vx_uer.c C
  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	guard(mutex)(&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	return val;
 63}
 64
 65/*
 66 * vx_write_one_cbit - write one bit to UER config
 67 * @index: the bit index
 68 * @val: bit value, 0 or 1
 69 */
 70static void vx_write_one_cbit(struct vx_core *chip, int index, int val)
 71{
 72	val = !!val;	/* 0 or 1 */
 73	guard(mutex)(&chip->lock);
 74	if (vx_is_pcmcia(chip)) {
 75		vx_outb(chip, CSUER, 0); /* write */
 76		vx_outb(chip, RUER, (val << 7) | (index & XX_UER_CBITS_OFFSET_MASK));
 77	} else {
 78		vx_outl(chip, CSUER, 0); /* write */
 79		vx_outl(chip, RUER, (val << 7) | (index & XX_UER_CBITS_OFFSET_MASK));
 80	}
 81}
 82
 83/*
 84 * vx_read_uer_status - read the current UER status
 85 * @mode: pointer to store the UER mode, VX_UER_MODE_XXX
 86 *
 87 * returns the frequency of UER, or 0 if not sync,
 88 * or a negative error code.
 89 */
 90static int vx_read_uer_status(struct vx_core *chip, unsigned int *mode)
 91{
 92	int val, freq;
 93
 94	/* Default values */
 95	freq = 0;
 96
 97	/* Read UER status */
 98	if (vx_is_pcmcia(chip))
 99	    val = vx_inb(chip, CSUER);
100	else
101	    val = vx_inl(chip, CSUER);
102	if (val < 0)
103		return val;
104	/* If clock is present, read frequency */
105	if (val & VX_SUER_CLOCK_PRESENT_MASK) {
106		switch (val & VX_SUER_FREQ_MASK) {
107		case VX_SUER_FREQ_32KHz_MASK:
108			freq = 32000;
109			break;
110		case VX_SUER_FREQ_44KHz_MASK:
111			freq = 44100;
112			break;
113		case VX_SUER_FREQ_48KHz_MASK:
114			freq = 48000;
115			break;
116		}
117        }
118	if (val & VX_SUER_DATA_PRESENT_MASK)
119		/* bit 0 corresponds to consumer/professional bit */
120		*mode = vx_read_one_cbit(chip, 0) ?
121			VX_UER_MODE_PROFESSIONAL : VX_UER_MODE_CONSUMER;
122	else
123		*mode = VX_UER_MODE_NOT_PRESENT;
124
125	return freq;
126}
127
128
129/*
130 * compute the sample clock value from frequency
131 *
132 * The formula is as follows:
133 *
134 *    HexFreq = (dword) ((double) ((double) 28224000 / (double) Frequency))
135 *    switch ( HexFreq & 0x00000F00 )
136 *    case 0x00000100: ;
137 *    case 0x00000200:
138 *    case 0x00000300: HexFreq -= 0x00000201 ;
139 *    case 0x00000400:
140 *    case 0x00000500:
141 *    case 0x00000600:
142 *    case 0x00000700: HexFreq = (dword) (((double) 28224000 / (double) (Frequency*2)) - 1)
143 *    default        : HexFreq = (dword) ((double) 28224000 / (double) (Frequency*4)) - 0x000001FF
144 */
145
146static int vx_calc_clock_from_freq(struct vx_core *chip, int freq)
147{
148	int hexfreq;
149
150	if (snd_BUG_ON(freq <= 0))
151		return 0;
152
153	hexfreq = (28224000 * 10) / freq;
154	hexfreq = (hexfreq + 5) / 10;
155
156	/* max freq = 55125 Hz */
157	if (snd_BUG_ON(hexfreq <= 0x00000200))
158		return 0;
159
160	if (hexfreq <= 0x03ff)
161		return hexfreq - 0x00000201;
162	if (hexfreq <= 0x07ff) 
163		return (hexfreq / 2) - 1;
164	if (hexfreq <= 0x0fff)
165		return (hexfreq / 4) + 0x000001ff;
166
167	return 0x5fe; 	/* min freq = 6893 Hz */
168}
169
170
171/*
172 * vx_change_clock_source - change the clock source
173 * @source: the new source
174 */
175static void vx_change_clock_source(struct vx_core *chip, int source)
176{
177	/* we mute DAC to prevent clicks */
178	vx_toggle_dac_mute(chip, 1);
179	scoped_guard(mutex, &chip->lock) {
180		chip->ops->set_clock_source(chip, source);
181		chip->clock_source = source;
182	}
183	/* unmute */
184	vx_toggle_dac_mute(chip, 0);
185}
186
187
188/*
189 * set the internal clock
190 */
191void vx_set_internal_clock(struct vx_core *chip, unsigned int freq)
192{
193	int clock;
194
195	/* Get real clock value */
196	clock = vx_calc_clock_from_freq(chip, freq);
197	dev_dbg(chip->card->dev,
198		"set internal clock to 0x%x from freq %d\n", clock, freq);
199	guard(mutex)(&chip->lock);
200	if (vx_is_pcmcia(chip)) {
201		vx_outb(chip, HIFREQ, (clock >> 8) & 0x0f);
202		vx_outb(chip, LOFREQ, clock & 0xff);
203	} else {
204		vx_outl(chip, HIFREQ, (clock >> 8) & 0x0f);
205		vx_outl(chip, LOFREQ, clock & 0xff);
206	}
207}
208
209
210/*
211 * set the iec958 status bits
212 * @bits: 32-bit status bits
213 */
214void vx_set_iec958_status(struct vx_core *chip, unsigned int bits)
215{
216	int i;
217
218	if (chip->chip_status & VX_STAT_IS_STALE)
219		return;
220
221	for (i = 0; i < 32; i++)
222		vx_write_one_cbit(chip, i, bits & (1 << i));
223}
224
225
226/*
227 * vx_set_clock - change the clock and audio source if necessary
228 */
229int vx_set_clock(struct vx_core *chip, unsigned int freq)
230{
231	int src_changed = 0;
232
233	if (chip->chip_status & VX_STAT_IS_STALE)
234		return 0;
235
236	/* change the audio source if possible */
237	vx_sync_audio_source(chip);
238
239	if (chip->clock_mode == VX_CLOCK_MODE_EXTERNAL ||
240	    (chip->clock_mode == VX_CLOCK_MODE_AUTO &&
241	     chip->audio_source == VX_AUDIO_SRC_DIGITAL)) {
242		if (chip->clock_source != UER_SYNC) {
243			vx_change_clock_source(chip, UER_SYNC);
244			mdelay(6);
245			src_changed = 1;
246		}
247	} else if (chip->clock_mode == VX_CLOCK_MODE_INTERNAL ||
248		   (chip->clock_mode == VX_CLOCK_MODE_AUTO &&
249		    chip->audio_source != VX_AUDIO_SRC_DIGITAL)) {
250		if (chip->clock_source != INTERNAL_QUARTZ) {
251			vx_change_clock_source(chip, INTERNAL_QUARTZ);
252			src_changed = 1;
253		}
254		if (chip->freq == freq)
255			return 0;
256		vx_set_internal_clock(chip, freq);
257		if (src_changed)
258			vx_modify_board_inputs(chip);
259	}
260	if (chip->freq == freq)
261		return 0;
262	chip->freq = freq;
263	vx_modify_board_clock(chip, 1);
264	return 0;
265}
266
267
268/*
269 * vx_change_frequency - called from interrupt handler
270 */
271int vx_change_frequency(struct vx_core *chip)
272{
273	int freq;
274
275	if (chip->chip_status & VX_STAT_IS_STALE)
276		return 0;
277
278	if (chip->clock_source == INTERNAL_QUARTZ)
279		return 0;
280	/*
281	 * Read the real UER board frequency
282	 */
283	freq = vx_read_uer_status(chip, &chip->uer_detected);
284	if (freq < 0)
285		return freq;
286	/*
287	 * The frequency computed by the DSP is good and
288	 * is different from the previous computed.
289	 */
290	if (freq == 48000 || freq == 44100 || freq == 32000)
291		chip->freq_detected = freq;
292
293	return 0;
294}
~/ Read-only file preview.