layla20_dsp.c revision 19b50063780953563e3c3a2867c39aad7b9e64cf
1/****************************************************************************
2
3   Copyright Echo Digital Audio Corporation (c) 1998 - 2004
4   All rights reserved
5   www.echoaudio.com
6
7   This file is part of Echo Digital Audio's generic driver library.
8
9   Echo Digital Audio's generic driver library is free software;
10   you can redistribute it and/or modify it under the terms of
11   the GNU General Public License as published by the Free Software
12   Foundation.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, Inc., 59 Temple Place - Suite 330, Boston,
22   MA  02111-1307, USA.
23
24   *************************************************************************
25
26 Translation from C++ and adaptation for use in ALSA-Driver
27 were made by Giuliano Pochini <pochini@shiny.it>
28
29****************************************************************************/
30
31
32static int read_dsp(struct echoaudio *chip, u32 *data);
33static int set_professional_spdif(struct echoaudio *chip, char prof);
34static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic);
35static int check_asic_status(struct echoaudio *chip);
36static int update_flags(struct echoaudio *chip);
37
38
39static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
40{
41	int err;
42
43	DE_INIT(("init_hw() - Layla20\n"));
44	if (snd_BUG_ON((subdevice_id & 0xfff0) != LAYLA20))
45		return -ENODEV;
46
47	if ((err = init_dsp_comm_page(chip))) {
48		DE_INIT(("init_hw - could not initialize DSP comm page\n"));
49		return err;
50	}
51
52	chip->device_id = device_id;
53	chip->subdevice_id = subdevice_id;
54	chip->bad_board = TRUE;
55	chip->has_midi = TRUE;
56	chip->dsp_code_to_load = FW_LAYLA20_DSP;
57	chip->input_clock_types =
58		ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF |
59		ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_SUPER;
60	chip->output_clock_types =
61		ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_SUPER;
62
63	if ((err = load_firmware(chip)) < 0)
64		return err;
65	chip->bad_board = FALSE;
66
67	if ((err = init_line_levels(chip)) < 0)
68		return err;
69
70	err = set_professional_spdif(chip, TRUE);
71
72	DE_INIT(("init_hw done\n"));
73	return err;
74}
75
76
77
78static u32 detect_input_clocks(const struct echoaudio *chip)
79{
80	u32 clocks_from_dsp, clock_bits;
81
82	/* Map the DSP clock detect bits to the generic driver clock detect bits */
83	clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
84
85	clock_bits = ECHO_CLOCK_BIT_INTERNAL;
86
87	if (clocks_from_dsp & GLDM_CLOCK_DETECT_BIT_SPDIF)
88		clock_bits |= ECHO_CLOCK_BIT_SPDIF;
89
90	if (clocks_from_dsp & GLDM_CLOCK_DETECT_BIT_WORD) {
91		if (clocks_from_dsp & GLDM_CLOCK_DETECT_BIT_SUPER)
92			clock_bits |= ECHO_CLOCK_BIT_SUPER;
93		else
94			clock_bits |= ECHO_CLOCK_BIT_WORD;
95	}
96
97	return clock_bits;
98}
99
100
101
102/* ASIC status check - some cards have one or two ASICs that need to be
103loaded.  Once that load is complete, this function is called to see if
104the load was successful.
105If this load fails, it does not necessarily mean that the hardware is
106defective - the external box may be disconnected or turned off.
107This routine sometimes fails for Layla20; for Layla20, the loop runs
1085 times and succeeds if it wins on three of the loops. */
109static int check_asic_status(struct echoaudio *chip)
110{
111	u32 asic_status;
112	int goodcnt, i;
113
114	chip->asic_loaded = FALSE;
115	for (i = goodcnt = 0; i < 5; i++) {
116		send_vector(chip, DSP_VC_TEST_ASIC);
117
118		/* The DSP will return a value to indicate whether or not
119		   the ASIC is currently loaded */
120		if (read_dsp(chip, &asic_status) < 0) {
121			DE_ACT(("check_asic_status: failed on read_dsp\n"));
122			return -EIO;
123		}
124
125		if (asic_status == ASIC_ALREADY_LOADED) {
126			if (++goodcnt == 3) {
127				chip->asic_loaded = TRUE;
128				return 0;
129			}
130		}
131	}
132	return -EIO;
133}
134
135
136
137/* Layla20 has an ASIC in the external box */
138static int load_asic(struct echoaudio *chip)
139{
140	int err;
141
142	if (chip->asic_loaded)
143		return 0;
144
145	err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA_ASIC,
146				FW_LAYLA20_ASIC);
147	if (err < 0)
148		return err;
149
150	/* Check if ASIC is alive and well. */
151	return check_asic_status(chip);
152}
153
154
155
156static int set_sample_rate(struct echoaudio *chip, u32 rate)
157{
158	if (snd_BUG_ON(rate < 8000 || rate > 50000))
159		return -EINVAL;
160
161	/* Only set the clock for internal mode. Do not return failure,
162	   simply treat it as a non-event. */
163	if (chip->input_clock != ECHO_CLOCK_INTERNAL) {
164		DE_ACT(("set_sample_rate: Cannot set sample rate - "
165			"clock not set to CLK_CLOCKININTERNAL\n"));
166		chip->comm_page->sample_rate = cpu_to_le32(rate);
167		chip->sample_rate = rate;
168		return 0;
169	}
170
171	if (wait_handshake(chip))
172		return -EIO;
173
174	DE_ACT(("set_sample_rate(%d)\n", rate));
175	chip->sample_rate = rate;
176	chip->comm_page->sample_rate = cpu_to_le32(rate);
177	clear_handshake(chip);
178	return send_vector(chip, DSP_VC_SET_LAYLA_SAMPLE_RATE);
179}
180
181
182
183static int set_input_clock(struct echoaudio *chip, u16 clock_source)
184{
185	u16 clock;
186	u32 rate;
187
188	DE_ACT(("set_input_clock:\n"));
189	rate = 0;
190	switch (clock_source) {
191	case ECHO_CLOCK_INTERNAL:
192		DE_ACT(("Set Layla20 clock to INTERNAL\n"));
193		rate = chip->sample_rate;
194		clock = LAYLA20_CLOCK_INTERNAL;
195		break;
196	case ECHO_CLOCK_SPDIF:
197		DE_ACT(("Set Layla20 clock to SPDIF\n"));
198		clock = LAYLA20_CLOCK_SPDIF;
199		break;
200	case ECHO_CLOCK_WORD:
201		DE_ACT(("Set Layla20 clock to WORD\n"));
202		clock = LAYLA20_CLOCK_WORD;
203		break;
204	case ECHO_CLOCK_SUPER:
205		DE_ACT(("Set Layla20 clock to SUPER\n"));
206		clock = LAYLA20_CLOCK_SUPER;
207		break;
208	default:
209		DE_ACT(("Input clock 0x%x not supported for Layla24\n",
210			clock_source));
211		return -EINVAL;
212	}
213	chip->input_clock = clock_source;
214
215	chip->comm_page->input_clock = cpu_to_le16(clock);
216	clear_handshake(chip);
217	send_vector(chip, DSP_VC_UPDATE_CLOCKS);
218
219	if (rate)
220		set_sample_rate(chip, rate);
221
222	return 0;
223}
224
225
226
227static int set_output_clock(struct echoaudio *chip, u16 clock)
228{
229	DE_ACT(("set_output_clock: %d\n", clock));
230	switch (clock) {
231	case ECHO_CLOCK_SUPER:
232		clock = LAYLA20_OUTPUT_CLOCK_SUPER;
233		break;
234	case ECHO_CLOCK_WORD:
235		clock = LAYLA20_OUTPUT_CLOCK_WORD;
236		break;
237	default:
238		DE_ACT(("set_output_clock wrong clock\n"));
239		return -EINVAL;
240	}
241
242	if (wait_handshake(chip))
243		return -EIO;
244
245	chip->comm_page->output_clock = cpu_to_le16(clock);
246	chip->output_clock = clock;
247	clear_handshake(chip);
248	return send_vector(chip, DSP_VC_UPDATE_CLOCKS);
249}
250
251
252
253/* Set input bus gain (one unit is 0.5dB !) */
254static int set_input_gain(struct echoaudio *chip, u16 input, int gain)
255{
256	if (snd_BUG_ON(input >= num_busses_in(chip)))
257		return -EINVAL;
258
259	if (wait_handshake(chip))
260		return -EIO;
261
262	chip->input_gain[input] = gain;
263	gain += GL20_INPUT_GAIN_MAGIC_NUMBER;
264	chip->comm_page->line_in_level[input] = gain;
265	return 0;
266}
267
268
269
270/* Tell the DSP to reread the flags from the comm page */
271static int update_flags(struct echoaudio *chip)
272{
273	if (wait_handshake(chip))
274		return -EIO;
275	clear_handshake(chip);
276	return send_vector(chip, DSP_VC_UPDATE_FLAGS);
277}
278
279
280
281static int set_professional_spdif(struct echoaudio *chip, char prof)
282{
283	DE_ACT(("set_professional_spdif %d\n", prof));
284	if (prof)
285		chip->comm_page->flags |=
286			cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
287	else
288		chip->comm_page->flags &=
289			~cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
290	chip->professional_spdif = prof;
291	return update_flags(chip);
292}
293