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