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