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