Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/pci/echoaudio/layla20_dsp.c
26451 views
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 <[email protected]>
28
29
****************************************************************************/
30
31
32
static int read_dsp(struct echoaudio *chip, u32 *data);
33
static int set_professional_spdif(struct echoaudio *chip, char prof);
34
static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic);
35
static int check_asic_status(struct echoaudio *chip);
36
static int update_flags(struct echoaudio *chip);
37
38
39
static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
40
{
41
int err;
42
43
if (snd_BUG_ON((subdevice_id & 0xfff0) != LAYLA20))
44
return -ENODEV;
45
46
err = init_dsp_comm_page(chip);
47
if (err) {
48
dev_err(chip->card->dev,
49
"init_hw - could not initialize DSP comm page\n");
50
return err;
51
}
52
53
chip->device_id = device_id;
54
chip->subdevice_id = subdevice_id;
55
chip->bad_board = true;
56
chip->has_midi = true;
57
chip->dsp_code_to_load = FW_LAYLA20_DSP;
58
chip->input_clock_types =
59
ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF |
60
ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_SUPER;
61
chip->output_clock_types =
62
ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_SUPER;
63
64
err = load_firmware(chip);
65
if (err < 0)
66
return err;
67
chip->bad_board = false;
68
69
return err;
70
}
71
72
73
74
static int set_mixer_defaults(struct echoaudio *chip)
75
{
76
chip->professional_spdif = false;
77
return init_line_levels(chip);
78
}
79
80
81
82
static u32 detect_input_clocks(const struct echoaudio *chip)
83
{
84
u32 clocks_from_dsp, clock_bits;
85
86
/* Map the DSP clock detect bits to the generic driver clock detect bits */
87
clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
88
89
clock_bits = ECHO_CLOCK_BIT_INTERNAL;
90
91
if (clocks_from_dsp & GLDM_CLOCK_DETECT_BIT_SPDIF)
92
clock_bits |= ECHO_CLOCK_BIT_SPDIF;
93
94
if (clocks_from_dsp & GLDM_CLOCK_DETECT_BIT_WORD) {
95
if (clocks_from_dsp & GLDM_CLOCK_DETECT_BIT_SUPER)
96
clock_bits |= ECHO_CLOCK_BIT_SUPER;
97
else
98
clock_bits |= ECHO_CLOCK_BIT_WORD;
99
}
100
101
return clock_bits;
102
}
103
104
105
106
/* ASIC status check - some cards have one or two ASICs that need to be
107
loaded. Once that load is complete, this function is called to see if
108
the load was successful.
109
If this load fails, it does not necessarily mean that the hardware is
110
defective - the external box may be disconnected or turned off.
111
This routine sometimes fails for Layla20; for Layla20, the loop runs
112
5 times and succeeds if it wins on three of the loops. */
113
static int check_asic_status(struct echoaudio *chip)
114
{
115
u32 asic_status;
116
int goodcnt, i;
117
118
chip->asic_loaded = false;
119
for (i = goodcnt = 0; i < 5; i++) {
120
send_vector(chip, DSP_VC_TEST_ASIC);
121
122
/* The DSP will return a value to indicate whether or not
123
the ASIC is currently loaded */
124
if (read_dsp(chip, &asic_status) < 0) {
125
dev_err(chip->card->dev,
126
"check_asic_status: failed on read_dsp\n");
127
return -EIO;
128
}
129
130
if (asic_status == ASIC_ALREADY_LOADED) {
131
if (++goodcnt == 3) {
132
chip->asic_loaded = true;
133
return 0;
134
}
135
}
136
}
137
return -EIO;
138
}
139
140
141
142
/* Layla20 has an ASIC in the external box */
143
static int load_asic(struct echoaudio *chip)
144
{
145
int err;
146
147
if (chip->asic_loaded)
148
return 0;
149
150
err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA_ASIC,
151
FW_LAYLA20_ASIC);
152
if (err < 0)
153
return err;
154
155
/* Check if ASIC is alive and well. */
156
return check_asic_status(chip);
157
}
158
159
160
161
static int set_sample_rate(struct echoaudio *chip, u32 rate)
162
{
163
if (snd_BUG_ON(rate < 8000 || rate > 50000))
164
return -EINVAL;
165
166
/* Only set the clock for internal mode. Do not return failure,
167
simply treat it as a non-event. */
168
if (chip->input_clock != ECHO_CLOCK_INTERNAL) {
169
dev_warn(chip->card->dev,
170
"Cannot set sample rate - clock not set to CLK_CLOCKININTERNAL\n");
171
chip->comm_page->sample_rate = cpu_to_le32(rate);
172
chip->sample_rate = rate;
173
return 0;
174
}
175
176
if (wait_handshake(chip))
177
return -EIO;
178
179
dev_dbg(chip->card->dev, "set_sample_rate(%d)\n", rate);
180
chip->sample_rate = rate;
181
chip->comm_page->sample_rate = cpu_to_le32(rate);
182
clear_handshake(chip);
183
return send_vector(chip, DSP_VC_SET_LAYLA_SAMPLE_RATE);
184
}
185
186
187
188
static int set_input_clock(struct echoaudio *chip, u16 clock_source)
189
{
190
u16 clock;
191
u32 rate;
192
193
rate = 0;
194
switch (clock_source) {
195
case ECHO_CLOCK_INTERNAL:
196
rate = chip->sample_rate;
197
clock = LAYLA20_CLOCK_INTERNAL;
198
break;
199
case ECHO_CLOCK_SPDIF:
200
clock = LAYLA20_CLOCK_SPDIF;
201
break;
202
case ECHO_CLOCK_WORD:
203
clock = LAYLA20_CLOCK_WORD;
204
break;
205
case ECHO_CLOCK_SUPER:
206
clock = LAYLA20_CLOCK_SUPER;
207
break;
208
default:
209
dev_err(chip->card->dev,
210
"Input clock 0x%x not supported for Layla24\n",
211
clock_source);
212
return -EINVAL;
213
}
214
chip->input_clock = clock_source;
215
216
chip->comm_page->input_clock = cpu_to_le16(clock);
217
clear_handshake(chip);
218
send_vector(chip, DSP_VC_UPDATE_CLOCKS);
219
220
if (rate)
221
set_sample_rate(chip, rate);
222
223
return 0;
224
}
225
226
227
228
static int set_output_clock(struct echoaudio *chip, u16 clock)
229
{
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
dev_err(chip->card->dev, "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 !) */
254
static 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 */
271
static 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
281
static int set_professional_spdif(struct echoaudio *chip, char prof)
282
{
283
if (prof)
284
chip->comm_page->flags |=
285
cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
286
else
287
chip->comm_page->flags &=
288
~cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
289
chip->professional_spdif = prof;
290
return update_flags(chip);
291
}
292
293