1*4882a593Smuzhiyun /****************************************************************************
2*4882a593Smuzhiyun
3*4882a593Smuzhiyun Copyright Echo Digital Audio Corporation (c) 1998 - 2004
4*4882a593Smuzhiyun All rights reserved
5*4882a593Smuzhiyun www.echoaudio.com
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun This file is part of Echo Digital Audio's generic driver library.
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun Echo Digital Audio's generic driver library is free software;
10*4882a593Smuzhiyun you can redistribute it and/or modify it under the terms of
11*4882a593Smuzhiyun the GNU General Public License as published by the Free Software
12*4882a593Smuzhiyun Foundation.
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun This program is distributed in the hope that it will be useful,
15*4882a593Smuzhiyun but WITHOUT ANY WARRANTY; without even the implied warranty of
16*4882a593Smuzhiyun MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17*4882a593Smuzhiyun GNU General Public License for more details.
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun You should have received a copy of the GNU General Public License
20*4882a593Smuzhiyun along with this program; if not, write to the Free Software
21*4882a593Smuzhiyun Foundation, Inc., 59 Temple Place - Suite 330, Boston,
22*4882a593Smuzhiyun MA 02111-1307, USA.
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun *************************************************************************
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun Translation from C++ and adaptation for use in ALSA-Driver
27*4882a593Smuzhiyun were made by Giuliano Pochini <pochini@shiny.it>
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun ****************************************************************************/
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun /* These functions are common for Gina24, Layla24 and Mona cards */
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun /* ASIC status check - some cards have one or two ASICs that need to be
36*4882a593Smuzhiyun loaded. Once that load is complete, this function is called to see if
37*4882a593Smuzhiyun the load was successful.
38*4882a593Smuzhiyun If this load fails, it does not necessarily mean that the hardware is
39*4882a593Smuzhiyun defective - the external box may be disconnected or turned off. */
check_asic_status(struct echoaudio * chip)40*4882a593Smuzhiyun static int check_asic_status(struct echoaudio *chip)
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun u32 asic_status;
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun send_vector(chip, DSP_VC_TEST_ASIC);
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun /* The DSP will return a value to indicate whether or not the
47*4882a593Smuzhiyun ASIC is currently loaded */
48*4882a593Smuzhiyun if (read_dsp(chip, &asic_status) < 0) {
49*4882a593Smuzhiyun dev_err(chip->card->dev,
50*4882a593Smuzhiyun "check_asic_status: failed on read_dsp\n");
51*4882a593Smuzhiyun chip->asic_loaded = false;
52*4882a593Smuzhiyun return -EIO;
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun chip->asic_loaded = (asic_status == ASIC_ALREADY_LOADED);
56*4882a593Smuzhiyun return chip->asic_loaded ? 0 : -EIO;
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun /* Most configuration of Gina24, Layla24, or Mona is accomplished by writing
62*4882a593Smuzhiyun the control register. write_control_reg sends the new control register
63*4882a593Smuzhiyun value to the DSP. */
write_control_reg(struct echoaudio * chip,u32 value,char force)64*4882a593Smuzhiyun static int write_control_reg(struct echoaudio *chip, u32 value, char force)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun __le32 reg_value;
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun /* Handle the digital input auto-mute */
69*4882a593Smuzhiyun if (chip->digital_in_automute)
70*4882a593Smuzhiyun value |= GML_DIGITAL_IN_AUTO_MUTE;
71*4882a593Smuzhiyun else
72*4882a593Smuzhiyun value &= ~GML_DIGITAL_IN_AUTO_MUTE;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun dev_dbg(chip->card->dev, "write_control_reg: 0x%x\n", value);
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun /* Write the control register */
77*4882a593Smuzhiyun reg_value = cpu_to_le32(value);
78*4882a593Smuzhiyun if (reg_value != chip->comm_page->control_register || force) {
79*4882a593Smuzhiyun if (wait_handshake(chip))
80*4882a593Smuzhiyun return -EIO;
81*4882a593Smuzhiyun chip->comm_page->control_register = reg_value;
82*4882a593Smuzhiyun clear_handshake(chip);
83*4882a593Smuzhiyun return send_vector(chip, DSP_VC_WRITE_CONTROL_REG);
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun return 0;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun /* Gina24, Layla24, and Mona support digital input auto-mute. If the digital
91*4882a593Smuzhiyun input auto-mute is enabled, the DSP will only enable the digital inputs if
92*4882a593Smuzhiyun the card is syncing to a valid clock on the ADAT or S/PDIF inputs.
93*4882a593Smuzhiyun If the auto-mute is disabled, the digital inputs are enabled regardless of
94*4882a593Smuzhiyun what the input clock is set or what is connected. */
set_input_auto_mute(struct echoaudio * chip,int automute)95*4882a593Smuzhiyun static int set_input_auto_mute(struct echoaudio *chip, int automute)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun dev_dbg(chip->card->dev, "set_input_auto_mute %d\n", automute);
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun chip->digital_in_automute = automute;
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun /* Re-set the input clock to the current value - indirectly causes
102*4882a593Smuzhiyun the auto-mute flag to be sent to the DSP */
103*4882a593Smuzhiyun return set_input_clock(chip, chip->input_clock);
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun /* S/PDIF coax / S/PDIF optical / ADAT - switch */
set_digital_mode(struct echoaudio * chip,u8 mode)109*4882a593Smuzhiyun static int set_digital_mode(struct echoaudio *chip, u8 mode)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun u8 previous_mode;
112*4882a593Smuzhiyun int err, i, o;
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun if (chip->bad_board)
115*4882a593Smuzhiyun return -EIO;
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun /* All audio channels must be closed before changing the digital mode */
118*4882a593Smuzhiyun if (snd_BUG_ON(chip->pipe_alloc_mask))
119*4882a593Smuzhiyun return -EAGAIN;
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun if (snd_BUG_ON(!(chip->digital_modes & (1 << mode))))
122*4882a593Smuzhiyun return -EINVAL;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun previous_mode = chip->digital_mode;
125*4882a593Smuzhiyun err = dsp_set_digital_mode(chip, mode);
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun /* If we successfully changed the digital mode from or to ADAT,
128*4882a593Smuzhiyun then make sure all output, input and monitor levels are
129*4882a593Smuzhiyun updated by the DSP comm object. */
130*4882a593Smuzhiyun if (err >= 0 && previous_mode != mode &&
131*4882a593Smuzhiyun (previous_mode == DIGITAL_MODE_ADAT || mode == DIGITAL_MODE_ADAT)) {
132*4882a593Smuzhiyun spin_lock_irq(&chip->lock);
133*4882a593Smuzhiyun for (o = 0; o < num_busses_out(chip); o++)
134*4882a593Smuzhiyun for (i = 0; i < num_busses_in(chip); i++)
135*4882a593Smuzhiyun set_monitor_gain(chip, o, i,
136*4882a593Smuzhiyun chip->monitor_gain[o][i]);
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun #ifdef ECHOCARD_HAS_INPUT_GAIN
139*4882a593Smuzhiyun for (i = 0; i < num_busses_in(chip); i++)
140*4882a593Smuzhiyun set_input_gain(chip, i, chip->input_gain[i]);
141*4882a593Smuzhiyun update_input_line_level(chip);
142*4882a593Smuzhiyun #endif
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun for (o = 0; o < num_busses_out(chip); o++)
145*4882a593Smuzhiyun set_output_gain(chip, o, chip->output_gain[o]);
146*4882a593Smuzhiyun update_output_line_level(chip);
147*4882a593Smuzhiyun spin_unlock_irq(&chip->lock);
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun return err;
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun /* Set the S/PDIF output format */
set_professional_spdif(struct echoaudio * chip,char prof)156*4882a593Smuzhiyun static int set_professional_spdif(struct echoaudio *chip, char prof)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun u32 control_reg;
159*4882a593Smuzhiyun int err;
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun /* Clear the current S/PDIF flags */
162*4882a593Smuzhiyun control_reg = le32_to_cpu(chip->comm_page->control_register);
163*4882a593Smuzhiyun control_reg &= GML_SPDIF_FORMAT_CLEAR_MASK;
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun /* Set the new S/PDIF flags depending on the mode */
166*4882a593Smuzhiyun control_reg |= GML_SPDIF_TWO_CHANNEL | GML_SPDIF_24_BIT |
167*4882a593Smuzhiyun GML_SPDIF_COPY_PERMIT;
168*4882a593Smuzhiyun if (prof) {
169*4882a593Smuzhiyun /* Professional mode */
170*4882a593Smuzhiyun control_reg |= GML_SPDIF_PRO_MODE;
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun switch (chip->sample_rate) {
173*4882a593Smuzhiyun case 32000:
174*4882a593Smuzhiyun control_reg |= GML_SPDIF_SAMPLE_RATE0 |
175*4882a593Smuzhiyun GML_SPDIF_SAMPLE_RATE1;
176*4882a593Smuzhiyun break;
177*4882a593Smuzhiyun case 44100:
178*4882a593Smuzhiyun control_reg |= GML_SPDIF_SAMPLE_RATE0;
179*4882a593Smuzhiyun break;
180*4882a593Smuzhiyun case 48000:
181*4882a593Smuzhiyun control_reg |= GML_SPDIF_SAMPLE_RATE1;
182*4882a593Smuzhiyun break;
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun } else {
185*4882a593Smuzhiyun /* Consumer mode */
186*4882a593Smuzhiyun switch (chip->sample_rate) {
187*4882a593Smuzhiyun case 32000:
188*4882a593Smuzhiyun control_reg |= GML_SPDIF_SAMPLE_RATE0 |
189*4882a593Smuzhiyun GML_SPDIF_SAMPLE_RATE1;
190*4882a593Smuzhiyun break;
191*4882a593Smuzhiyun case 48000:
192*4882a593Smuzhiyun control_reg |= GML_SPDIF_SAMPLE_RATE1;
193*4882a593Smuzhiyun break;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun if ((err = write_control_reg(chip, control_reg, false)))
198*4882a593Smuzhiyun return err;
199*4882a593Smuzhiyun chip->professional_spdif = prof;
200*4882a593Smuzhiyun dev_dbg(chip->card->dev, "set_professional_spdif to %s\n",
201*4882a593Smuzhiyun prof ? "Professional" : "Consumer");
202*4882a593Smuzhiyun return 0;
203*4882a593Smuzhiyun }
204