aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/echoaudio/layla20_dsp.c
diff options
context:
space:
mode:
authorGiuliano Pochini <pochini@shiny.it>2006-06-28 07:53:41 -0400
committerJaroslav Kysela <perex@suse.cz>2006-06-28 13:31:20 -0400
commitdd7b254d8dd3a9528f423ac3bf875e6f0c8da561 (patch)
tree923ac13451c796b730f21c7260beba9f74acff63 /sound/pci/echoaudio/layla20_dsp.c
parentcb9d24e4349013628259b5fee97e692173731b07 (diff)
[ALSA] Add echoaudio sound drivers
From: Giuliano Pochini <pochini@shiny.it>Add echoaudio sound drivers (darla20, darla24, echo3g, gina20, gina24, indigo, indigodj, indigoio, layla20, lala24, mia, mona) Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound/pci/echoaudio/layla20_dsp.c')
-rw-r--r--sound/pci/echoaudio/layla20_dsp.c290
1 files changed, 290 insertions, 0 deletions
diff --git a/sound/pci/echoaudio/layla20_dsp.c b/sound/pci/echoaudio/layla20_dsp.c
new file mode 100644
index 000000000000..990c9a60a0a8
--- /dev/null
+++ b/sound/pci/echoaudio/layla20_dsp.c
@@ -0,0 +1,290 @@
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,
35 const struct firmware *asic);
36static int check_asic_status(struct echoaudio *chip);
37static int update_flags(struct echoaudio *chip);
38
39
40static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
41{
42 int err;
43
44 DE_INIT(("init_hw() - Layla20\n"));
45 snd_assert((subdevice_id & 0xfff0) == LAYLA20, 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 = &card_fw[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 &card_fw[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 snd_assert(rate >= 8000 && rate <= 50000, return -EINVAL);
159
160 /* Only set the clock for internal mode. Do not return failure,
161 simply treat it as a non-event. */
162 if (chip->input_clock != ECHO_CLOCK_INTERNAL) {
163 DE_ACT(("set_sample_rate: Cannot set sample rate - "
164 "clock not set to CLK_CLOCKININTERNAL\n"));
165 chip->comm_page->sample_rate = cpu_to_le32(rate);
166 chip->sample_rate = rate;
167 return 0;
168 }
169
170 if (wait_handshake(chip))
171 return -EIO;
172
173 DE_ACT(("set_sample_rate(%d)\n", rate));
174 chip->sample_rate = rate;
175 chip->comm_page->sample_rate = cpu_to_le32(rate);
176 clear_handshake(chip);
177 return send_vector(chip, DSP_VC_SET_LAYLA_SAMPLE_RATE);
178}
179
180
181
182static int set_input_clock(struct echoaudio *chip, u16 clock_source)
183{
184 u16 clock;
185 u32 rate;
186
187 DE_ACT(("set_input_clock:\n"));
188 rate = 0;
189 switch (clock_source) {
190 case ECHO_CLOCK_INTERNAL:
191 DE_ACT(("Set Layla20 clock to INTERNAL\n"));
192 rate = chip->sample_rate;
193 clock = LAYLA20_CLOCK_INTERNAL;
194 break;
195 case ECHO_CLOCK_SPDIF:
196 DE_ACT(("Set Layla20 clock to SPDIF\n"));
197 clock = LAYLA20_CLOCK_SPDIF;
198 break;
199 case ECHO_CLOCK_WORD:
200 DE_ACT(("Set Layla20 clock to WORD\n"));
201 clock = LAYLA20_CLOCK_WORD;
202 break;
203 case ECHO_CLOCK_SUPER:
204 DE_ACT(("Set Layla20 clock to SUPER\n"));
205 clock = LAYLA20_CLOCK_SUPER;
206 break;
207 default:
208 DE_ACT(("Input clock 0x%x not supported for Layla24\n",
209 clock_source));
210 return -EINVAL;
211 }
212 chip->input_clock = clock_source;
213
214 chip->comm_page->input_clock = cpu_to_le16(clock);
215 clear_handshake(chip);
216 send_vector(chip, DSP_VC_UPDATE_CLOCKS);
217
218 if (rate)
219 set_sample_rate(chip, rate);
220
221 return 0;
222}
223
224
225
226static int set_output_clock(struct echoaudio *chip, u16 clock)
227{
228 DE_ACT(("set_output_clock: %d\n", clock));
229 switch (clock) {
230 case ECHO_CLOCK_SUPER:
231 clock = LAYLA20_OUTPUT_CLOCK_SUPER;
232 break;
233 case ECHO_CLOCK_WORD:
234 clock = LAYLA20_OUTPUT_CLOCK_WORD;
235 break;
236 default:
237 DE_ACT(("set_output_clock wrong clock\n"));
238 return -EINVAL;
239 }
240
241 if (wait_handshake(chip))
242 return -EIO;
243
244 chip->comm_page->output_clock = cpu_to_le16(clock);
245 chip->output_clock = clock;
246 clear_handshake(chip);
247 return send_vector(chip, DSP_VC_UPDATE_CLOCKS);
248}
249
250
251
252/* Set input bus gain (one unit is 0.5dB !) */
253static int set_input_gain(struct echoaudio *chip, u16 input, int gain)
254{
255 snd_assert(input < num_busses_in(chip), return -EINVAL);
256
257 if (wait_handshake(chip))
258 return -EIO;
259
260 chip->input_gain[input] = gain;
261 gain += GL20_INPUT_GAIN_MAGIC_NUMBER;
262 chip->comm_page->line_in_level[input] = gain;
263 return 0;
264}
265
266
267
268/* Tell the DSP to reread the flags from the comm page */
269static int update_flags(struct echoaudio *chip)
270{
271 if (wait_handshake(chip))
272 return -EIO;
273 clear_handshake(chip);
274 return send_vector(chip, DSP_VC_UPDATE_FLAGS);
275}
276
277
278
279static int set_professional_spdif(struct echoaudio *chip, char prof)
280{
281 DE_ACT(("set_professional_spdif %d\n", prof));
282 if (prof)
283 chip->comm_page->flags |=
284 __constant_cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
285 else
286 chip->comm_page->flags &=
287 ~__constant_cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
288 chip->professional_spdif = prof;
289 return update_flags(chip);
290}