xref: /linux/sound/pci/echoaudio/gina20_dsp.c (revision ad3499f4668f684ef6e5d0222ae14d5e4ade1fdd)
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 set_professional_spdif(struct echoaudio *chip, char prof);
33dd7b254dSGiuliano Pochini static int update_flags(struct echoaudio *chip);
34dd7b254dSGiuliano Pochini 
35dd7b254dSGiuliano Pochini 
36dd7b254dSGiuliano Pochini static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
37dd7b254dSGiuliano Pochini {
38dd7b254dSGiuliano Pochini 	int err;
39dd7b254dSGiuliano Pochini 
40dd7b254dSGiuliano Pochini 	DE_INIT(("init_hw() - Gina20\n"));
41da3cec35STakashi Iwai 	if (snd_BUG_ON((subdevice_id & 0xfff0) != GINA20))
42da3cec35STakashi Iwai 		return -ENODEV;
43dd7b254dSGiuliano Pochini 
44dd7b254dSGiuliano Pochini 	if ((err = init_dsp_comm_page(chip))) {
45dd7b254dSGiuliano Pochini 		DE_INIT(("init_hw - could not initialize DSP comm page\n"));
46dd7b254dSGiuliano Pochini 		return err;
47dd7b254dSGiuliano Pochini 	}
48dd7b254dSGiuliano Pochini 
49dd7b254dSGiuliano Pochini 	chip->device_id = device_id;
50dd7b254dSGiuliano Pochini 	chip->subdevice_id = subdevice_id;
51dd7b254dSGiuliano Pochini 	chip->bad_board = TRUE;
5219b50063SGiuliano Pochini 	chip->dsp_code_to_load = FW_GINA20_DSP;
53dd7b254dSGiuliano Pochini 	chip->spdif_status = GD_SPDIF_STATUS_UNDEF;
54dd7b254dSGiuliano Pochini 	chip->clock_state = GD_CLOCK_UNDEF;
55dd7b254dSGiuliano Pochini 	/* Since this card has no ASIC, mark it as loaded so everything
56dd7b254dSGiuliano Pochini 	   works OK */
57dd7b254dSGiuliano Pochini 	chip->asic_loaded = TRUE;
58dd7b254dSGiuliano Pochini 	chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL |
59dd7b254dSGiuliano Pochini 		ECHO_CLOCK_BIT_SPDIF;
60dd7b254dSGiuliano Pochini 
61dd7b254dSGiuliano Pochini 	if ((err = load_firmware(chip)) < 0)
62dd7b254dSGiuliano Pochini 		return err;
63dd7b254dSGiuliano Pochini 	chip->bad_board = FALSE;
64dd7b254dSGiuliano Pochini 
65dd7b254dSGiuliano Pochini 	DE_INIT(("init_hw done\n"));
66dd7b254dSGiuliano Pochini 	return err;
67dd7b254dSGiuliano Pochini }
68dd7b254dSGiuliano Pochini 
69dd7b254dSGiuliano Pochini 
70dd7b254dSGiuliano Pochini 
71*ad3499f4SGiuliano Pochini static int set_mixer_defaults(struct echoaudio *chip)
72*ad3499f4SGiuliano Pochini {
73*ad3499f4SGiuliano Pochini 	chip->professional_spdif = FALSE;
74*ad3499f4SGiuliano Pochini 	return init_line_levels(chip);
75*ad3499f4SGiuliano Pochini }
76*ad3499f4SGiuliano Pochini 
77*ad3499f4SGiuliano Pochini 
78*ad3499f4SGiuliano Pochini 
79dd7b254dSGiuliano Pochini static u32 detect_input_clocks(const struct echoaudio *chip)
80dd7b254dSGiuliano Pochini {
81dd7b254dSGiuliano Pochini 	u32 clocks_from_dsp, clock_bits;
82dd7b254dSGiuliano Pochini 
83dd7b254dSGiuliano Pochini 	/* Map the DSP clock detect bits to the generic driver clock
84dd7b254dSGiuliano Pochini 	   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 	return clock_bits;
93dd7b254dSGiuliano Pochini }
94dd7b254dSGiuliano Pochini 
95dd7b254dSGiuliano Pochini 
96dd7b254dSGiuliano Pochini 
97dd7b254dSGiuliano Pochini /* The Gina20 has no ASIC. Just do nothing */
98dd7b254dSGiuliano Pochini static int load_asic(struct echoaudio *chip)
99dd7b254dSGiuliano Pochini {
100dd7b254dSGiuliano Pochini 	return 0;
101dd7b254dSGiuliano Pochini }
102dd7b254dSGiuliano Pochini 
103dd7b254dSGiuliano Pochini 
104dd7b254dSGiuliano Pochini 
105dd7b254dSGiuliano Pochini static int set_sample_rate(struct echoaudio *chip, u32 rate)
106dd7b254dSGiuliano Pochini {
107dd7b254dSGiuliano Pochini 	u8 clock_state, spdif_status;
108dd7b254dSGiuliano Pochini 
109dd7b254dSGiuliano Pochini 	if (wait_handshake(chip))
110dd7b254dSGiuliano Pochini 		return -EIO;
111dd7b254dSGiuliano Pochini 
112dd7b254dSGiuliano Pochini 	switch (rate) {
113dd7b254dSGiuliano Pochini 	case 44100:
114dd7b254dSGiuliano Pochini 		clock_state = GD_CLOCK_44;
115dd7b254dSGiuliano Pochini 		spdif_status = GD_SPDIF_STATUS_44;
116dd7b254dSGiuliano Pochini 		break;
117dd7b254dSGiuliano Pochini 	case 48000:
118dd7b254dSGiuliano Pochini 		clock_state = GD_CLOCK_48;
119dd7b254dSGiuliano Pochini 		spdif_status = GD_SPDIF_STATUS_48;
120dd7b254dSGiuliano Pochini 		break;
121dd7b254dSGiuliano Pochini 	default:
122dd7b254dSGiuliano Pochini 		clock_state = GD_CLOCK_NOCHANGE;
123dd7b254dSGiuliano Pochini 		spdif_status = GD_SPDIF_STATUS_NOCHANGE;
124dd7b254dSGiuliano Pochini 		break;
125dd7b254dSGiuliano Pochini 	}
126dd7b254dSGiuliano Pochini 
127dd7b254dSGiuliano Pochini 	if (chip->clock_state == clock_state)
128dd7b254dSGiuliano Pochini 		clock_state = GD_CLOCK_NOCHANGE;
129dd7b254dSGiuliano Pochini 	if (spdif_status == chip->spdif_status)
130dd7b254dSGiuliano Pochini 		spdif_status = GD_SPDIF_STATUS_NOCHANGE;
131dd7b254dSGiuliano Pochini 
132dd7b254dSGiuliano Pochini 	chip->comm_page->sample_rate = cpu_to_le32(rate);
133dd7b254dSGiuliano Pochini 	chip->comm_page->gd_clock_state = clock_state;
134dd7b254dSGiuliano Pochini 	chip->comm_page->gd_spdif_status = spdif_status;
135dd7b254dSGiuliano Pochini 	chip->comm_page->gd_resampler_state = 3;	/* magic number - should always be 3 */
136dd7b254dSGiuliano Pochini 
137dd7b254dSGiuliano Pochini 	/* Save the new audio state if it changed */
138dd7b254dSGiuliano Pochini 	if (clock_state != GD_CLOCK_NOCHANGE)
139dd7b254dSGiuliano Pochini 		chip->clock_state = clock_state;
140dd7b254dSGiuliano Pochini 	if (spdif_status != GD_SPDIF_STATUS_NOCHANGE)
141dd7b254dSGiuliano Pochini 		chip->spdif_status = spdif_status;
142dd7b254dSGiuliano Pochini 	chip->sample_rate = rate;
143dd7b254dSGiuliano Pochini 
144dd7b254dSGiuliano Pochini 	clear_handshake(chip);
145dd7b254dSGiuliano Pochini 	return send_vector(chip, DSP_VC_SET_GD_AUDIO_STATE);
146dd7b254dSGiuliano Pochini }
147dd7b254dSGiuliano Pochini 
148dd7b254dSGiuliano Pochini 
149dd7b254dSGiuliano Pochini 
150dd7b254dSGiuliano Pochini static int set_input_clock(struct echoaudio *chip, u16 clock)
151dd7b254dSGiuliano Pochini {
152dd7b254dSGiuliano Pochini 	DE_ACT(("set_input_clock:\n"));
153dd7b254dSGiuliano Pochini 
154dd7b254dSGiuliano Pochini 	switch (clock) {
155dd7b254dSGiuliano Pochini 	case ECHO_CLOCK_INTERNAL:
156dd7b254dSGiuliano Pochini 		/* Reset the audio state to unknown (just in case) */
157dd7b254dSGiuliano Pochini 		chip->clock_state = GD_CLOCK_UNDEF;
158dd7b254dSGiuliano Pochini 		chip->spdif_status = GD_SPDIF_STATUS_UNDEF;
159dd7b254dSGiuliano Pochini 		set_sample_rate(chip, chip->sample_rate);
160dd7b254dSGiuliano Pochini 		chip->input_clock = clock;
161dd7b254dSGiuliano Pochini 		DE_ACT(("Set Gina clock to INTERNAL\n"));
162dd7b254dSGiuliano Pochini 		break;
163dd7b254dSGiuliano Pochini 	case ECHO_CLOCK_SPDIF:
164dd7b254dSGiuliano Pochini 		chip->comm_page->gd_clock_state = GD_CLOCK_SPDIFIN;
165dd7b254dSGiuliano Pochini 		chip->comm_page->gd_spdif_status = GD_SPDIF_STATUS_NOCHANGE;
166dd7b254dSGiuliano Pochini 		clear_handshake(chip);
167dd7b254dSGiuliano Pochini 		send_vector(chip, DSP_VC_SET_GD_AUDIO_STATE);
168dd7b254dSGiuliano Pochini 		chip->clock_state = GD_CLOCK_SPDIFIN;
169dd7b254dSGiuliano Pochini 		DE_ACT(("Set Gina20 clock to SPDIF\n"));
170dd7b254dSGiuliano Pochini 		chip->input_clock = clock;
171dd7b254dSGiuliano Pochini 		break;
172dd7b254dSGiuliano Pochini 	default:
173dd7b254dSGiuliano Pochini 		return -EINVAL;
174dd7b254dSGiuliano Pochini 	}
175dd7b254dSGiuliano Pochini 
176dd7b254dSGiuliano Pochini 	return 0;
177dd7b254dSGiuliano Pochini }
178dd7b254dSGiuliano Pochini 
179dd7b254dSGiuliano Pochini 
180dd7b254dSGiuliano Pochini 
181dd7b254dSGiuliano Pochini /* Set input bus gain (one unit is 0.5dB !) */
182dd7b254dSGiuliano Pochini static int set_input_gain(struct echoaudio *chip, u16 input, int gain)
183dd7b254dSGiuliano Pochini {
184da3cec35STakashi Iwai 	if (snd_BUG_ON(input >= num_busses_in(chip)))
185da3cec35STakashi Iwai 		return -EINVAL;
186dd7b254dSGiuliano Pochini 
187dd7b254dSGiuliano Pochini 	if (wait_handshake(chip))
188dd7b254dSGiuliano Pochini 		return -EIO;
189dd7b254dSGiuliano Pochini 
190dd7b254dSGiuliano Pochini 	chip->input_gain[input] = gain;
191dd7b254dSGiuliano Pochini 	gain += GL20_INPUT_GAIN_MAGIC_NUMBER;
192dd7b254dSGiuliano Pochini 	chip->comm_page->line_in_level[input] = gain;
193dd7b254dSGiuliano Pochini 	return 0;
194dd7b254dSGiuliano Pochini }
195dd7b254dSGiuliano Pochini 
196dd7b254dSGiuliano Pochini 
197dd7b254dSGiuliano Pochini 
198dd7b254dSGiuliano Pochini /* Tell the DSP to reread the flags from the comm page */
199dd7b254dSGiuliano Pochini static int update_flags(struct echoaudio *chip)
200dd7b254dSGiuliano Pochini {
201dd7b254dSGiuliano Pochini 	if (wait_handshake(chip))
202dd7b254dSGiuliano Pochini 		return -EIO;
203dd7b254dSGiuliano Pochini 	clear_handshake(chip);
204dd7b254dSGiuliano Pochini 	return send_vector(chip, DSP_VC_UPDATE_FLAGS);
205dd7b254dSGiuliano Pochini }
206dd7b254dSGiuliano Pochini 
207dd7b254dSGiuliano Pochini 
208dd7b254dSGiuliano Pochini 
209dd7b254dSGiuliano Pochini static int set_professional_spdif(struct echoaudio *chip, char prof)
210dd7b254dSGiuliano Pochini {
211dd7b254dSGiuliano Pochini 	DE_ACT(("set_professional_spdif %d\n", prof));
212dd7b254dSGiuliano Pochini 	if (prof)
213dd7b254dSGiuliano Pochini 		chip->comm_page->flags |=
214e930e995SHarvey Harrison 			cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
215dd7b254dSGiuliano Pochini 	else
216dd7b254dSGiuliano Pochini 		chip->comm_page->flags &=
217e930e995SHarvey Harrison 			~cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
218dd7b254dSGiuliano Pochini 	chip->professional_spdif = prof;
219dd7b254dSGiuliano Pochini 	return update_flags(chip);
220dd7b254dSGiuliano Pochini }
221