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