~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/pci/echoaudio/gina24_dsp.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 <pochini@shiny.it>
 28 
 29 ****************************************************************************/
 30 
 31 
 32 static int write_control_reg(struct echoaudio *chip, u32 value, char force);
 33 static int set_input_clock(struct echoaudio *chip, u16 clock);
 34 static int set_professional_spdif(struct echoaudio *chip, char prof);
 35 static int set_digital_mode(struct echoaudio *chip, u8 mode);
 36 static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic);
 37 static int check_asic_status(struct echoaudio *chip);
 38 
 39 
 40 static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
 41 {
 42         int err;
 43 
 44         if (snd_BUG_ON((subdevice_id & 0xfff0) != GINA24))
 45                 return -ENODEV;
 46 
 47         err = init_dsp_comm_page(chip);
 48         if (err) {
 49                 dev_err(chip->card->dev,
 50                         "init_hw - could not initialize DSP comm page\n");
 51                 return err;
 52         }
 53 
 54         chip->device_id = device_id;
 55         chip->subdevice_id = subdevice_id;
 56         chip->bad_board = true;
 57         chip->input_clock_types =
 58                 ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF |
 59                 ECHO_CLOCK_BIT_ESYNC | ECHO_CLOCK_BIT_ESYNC96 |
 60                 ECHO_CLOCK_BIT_ADAT;
 61 
 62         /* Gina24 comes in both '301 and '361 flavors */
 63         if (chip->device_id == DEVICE_ID_56361) {
 64                 chip->dsp_code_to_load = FW_GINA24_361_DSP;
 65                 chip->digital_modes =
 66                         ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA |
 67                         ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL |
 68                         ECHOCAPS_HAS_DIGITAL_MODE_ADAT;
 69         } else {
 70                 chip->dsp_code_to_load = FW_GINA24_301_DSP;
 71                 chip->digital_modes =
 72                         ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA |
 73                         ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL |
 74                         ECHOCAPS_HAS_DIGITAL_MODE_ADAT |
 75                         ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_CDROM;
 76         }
 77 
 78         err = load_firmware(chip);
 79         if (err < 0)
 80                 return err;
 81         chip->bad_board = false;
 82 
 83         return err;
 84 }
 85 
 86 
 87 
 88 static int set_mixer_defaults(struct echoaudio *chip)
 89 {
 90         chip->digital_mode = DIGITAL_MODE_SPDIF_RCA;
 91         chip->professional_spdif = false;
 92         chip->digital_in_automute = true;
 93         return init_line_levels(chip);
 94 }
 95 
 96 
 97 
 98 static u32 detect_input_clocks(const struct echoaudio *chip)
 99 {
100         u32 clocks_from_dsp, clock_bits;
101 
102         /* Map the DSP clock detect bits to the generic driver clock
103            detect bits */
104         clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
105 
106         clock_bits = ECHO_CLOCK_BIT_INTERNAL;
107 
108         if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_SPDIF)
109                 clock_bits |= ECHO_CLOCK_BIT_SPDIF;
110 
111         if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_ADAT)
112                 clock_bits |= ECHO_CLOCK_BIT_ADAT;
113 
114         if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_ESYNC)
115                 clock_bits |= ECHO_CLOCK_BIT_ESYNC | ECHO_CLOCK_BIT_ESYNC96;
116 
117         return clock_bits;
118 }
119 
120 
121 
122 /* Gina24 has an ASIC on the PCI card which must be loaded for anything
123 interesting to happen. */
124 static int load_asic(struct echoaudio *chip)
125 {
126         u32 control_reg;
127         int err;
128         short asic;
129 
130         if (chip->asic_loaded)
131                 return 1;
132 
133         /* Give the DSP a few milliseconds to settle down */
134         mdelay(10);
135 
136         /* Pick the correct ASIC for '301 or '361 Gina24 */
137         if (chip->device_id == DEVICE_ID_56361)
138                 asic = FW_GINA24_361_ASIC;
139         else
140                 asic = FW_GINA24_301_ASIC;
141 
142         err = load_asic_generic(chip, DSP_FNC_LOAD_GINA24_ASIC, asic);
143         if (err < 0)
144                 return err;
145 
146         chip->asic_code = asic;
147 
148         /* Now give the new ASIC a little time to set up */
149         mdelay(10);
150         /* See if it worked */
151         err = check_asic_status(chip);
152 
153         /* Set up the control register if the load succeeded -
154            48 kHz, internal clock, S/PDIF RCA mode */
155         if (!err) {
156                 control_reg = GML_CONVERTER_ENABLE | GML_48KHZ;
157                 err = write_control_reg(chip, control_reg, true);
158         }
159         return err;
160 }
161 
162 
163 
164 static int set_sample_rate(struct echoaudio *chip, u32 rate)
165 {
166         u32 control_reg, clock;
167 
168         if (snd_BUG_ON(rate >= 50000 &&
169                        chip->digital_mode == DIGITAL_MODE_ADAT))
170                 return -EINVAL;
171 
172         /* Only set the clock for internal mode. */
173         if (chip->input_clock != ECHO_CLOCK_INTERNAL) {
174                 dev_warn(chip->card->dev,
175                          "Cannot set sample rate - clock not set to CLK_CLOCKININTERNAL\n");
176                 /* Save the rate anyhow */
177                 chip->comm_page->sample_rate = cpu_to_le32(rate);
178                 chip->sample_rate = rate;
179                 return 0;
180         }
181 
182         clock = 0;
183 
184         control_reg = le32_to_cpu(chip->comm_page->control_register);
185         control_reg &= GML_CLOCK_CLEAR_MASK & GML_SPDIF_RATE_CLEAR_MASK;
186 
187         switch (rate) {
188         case 96000:
189                 clock = GML_96KHZ;
190                 break;
191         case 88200:
192                 clock = GML_88KHZ;
193                 break;
194         case 48000:
195                 clock = GML_48KHZ | GML_SPDIF_SAMPLE_RATE1;
196                 break;
197         case 44100:
198                 clock = GML_44KHZ;
199                 /* Professional mode ? */
200                 if (control_reg & GML_SPDIF_PRO_MODE)
201                         clock |= GML_SPDIF_SAMPLE_RATE0;
202                 break;
203         case 32000:
204                 clock = GML_32KHZ | GML_SPDIF_SAMPLE_RATE0 |
205                         GML_SPDIF_SAMPLE_RATE1;
206                 break;
207         case 22050:
208                 clock = GML_22KHZ;
209                 break;
210         case 16000:
211                 clock = GML_16KHZ;
212                 break;
213         case 11025:
214                 clock = GML_11KHZ;
215                 break;
216         case 8000:
217                 clock = GML_8KHZ;
218                 break;
219         default:
220                 dev_err(chip->card->dev,
221                         "set_sample_rate: %d invalid!\n", rate);
222                 return -EINVAL;
223         }
224 
225         control_reg |= clock;
226 
227         chip->comm_page->sample_rate = cpu_to_le32(rate);       /* ignored by the DSP */
228         chip->sample_rate = rate;
229         dev_dbg(chip->card->dev, "set_sample_rate: %d clock %d\n", rate, clock);
230 
231         return write_control_reg(chip, control_reg, false);
232 }
233 
234 
235 
236 static int set_input_clock(struct echoaudio *chip, u16 clock)
237 {
238         u32 control_reg, clocks_from_dsp;
239 
240 
241         /* Mask off the clock select bits */
242         control_reg = le32_to_cpu(chip->comm_page->control_register) &
243                 GML_CLOCK_CLEAR_MASK;
244         clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
245 
246         switch (clock) {
247         case ECHO_CLOCK_INTERNAL:
248                 chip->input_clock = ECHO_CLOCK_INTERNAL;
249                 return set_sample_rate(chip, chip->sample_rate);
250         case ECHO_CLOCK_SPDIF:
251                 if (chip->digital_mode == DIGITAL_MODE_ADAT)
252                         return -EAGAIN;
253                 control_reg |= GML_SPDIF_CLOCK;
254                 if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_SPDIF96)
255                         control_reg |= GML_DOUBLE_SPEED_MODE;
256                 else
257                         control_reg &= ~GML_DOUBLE_SPEED_MODE;
258                 break;
259         case ECHO_CLOCK_ADAT:
260                 if (chip->digital_mode != DIGITAL_MODE_ADAT)
261                         return -EAGAIN;
262                 control_reg |= GML_ADAT_CLOCK;
263                 control_reg &= ~GML_DOUBLE_SPEED_MODE;
264                 break;
265         case ECHO_CLOCK_ESYNC:
266                 control_reg |= GML_ESYNC_CLOCK;
267                 control_reg &= ~GML_DOUBLE_SPEED_MODE;
268                 break;
269         case ECHO_CLOCK_ESYNC96:
270                 control_reg |= GML_ESYNC_CLOCK | GML_DOUBLE_SPEED_MODE;
271                 break;
272         default:
273                 dev_err(chip->card->dev,
274                         "Input clock 0x%x not supported for Gina24\n", clock);
275                 return -EINVAL;
276         }
277 
278         chip->input_clock = clock;
279         return write_control_reg(chip, control_reg, true);
280 }
281 
282 
283 
284 static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
285 {
286         u32 control_reg;
287         int err, incompatible_clock;
288 
289         /* Set clock to "internal" if it's not compatible with the new mode */
290         incompatible_clock = false;
291         switch (mode) {
292         case DIGITAL_MODE_SPDIF_OPTICAL:
293         case DIGITAL_MODE_SPDIF_CDROM:
294         case DIGITAL_MODE_SPDIF_RCA:
295                 if (chip->input_clock == ECHO_CLOCK_ADAT)
296                         incompatible_clock = true;
297                 break;
298         case DIGITAL_MODE_ADAT:
299                 if (chip->input_clock == ECHO_CLOCK_SPDIF)
300                         incompatible_clock = true;
301                 break;
302         default:
303                 dev_err(chip->card->dev,
304                         "Digital mode not supported: %d\n", mode);
305                 return -EINVAL;
306         }
307 
308         spin_lock_irq(&chip->lock);
309 
310         if (incompatible_clock) {       /* Switch to 48KHz, internal */
311                 chip->sample_rate = 48000;
312                 set_input_clock(chip, ECHO_CLOCK_INTERNAL);
313         }
314 
315         /* Clear the current digital mode */
316         control_reg = le32_to_cpu(chip->comm_page->control_register);
317         control_reg &= GML_DIGITAL_MODE_CLEAR_MASK;
318 
319         /* Tweak the control reg */
320         switch (mode) {
321         case DIGITAL_MODE_SPDIF_OPTICAL:
322                 control_reg |= GML_SPDIF_OPTICAL_MODE;
323                 break;
324         case DIGITAL_MODE_SPDIF_CDROM:
325                 /* '361 Gina24 cards do not have the S/PDIF CD-ROM mode */
326                 if (chip->device_id == DEVICE_ID_56301)
327                         control_reg |= GML_SPDIF_CDROM_MODE;
328                 break;
329         case DIGITAL_MODE_SPDIF_RCA:
330                 /* GML_SPDIF_OPTICAL_MODE bit cleared */
331                 break;
332         case DIGITAL_MODE_ADAT:
333                 control_reg |= GML_ADAT_MODE;
334                 control_reg &= ~GML_DOUBLE_SPEED_MODE;
335                 break;
336         }
337 
338         err = write_control_reg(chip, control_reg, true);
339         spin_unlock_irq(&chip->lock);
340         if (err < 0)
341                 return err;
342         chip->digital_mode = mode;
343 
344         dev_dbg(chip->card->dev,
345                 "set_digital_mode to %d\n", chip->digital_mode);
346         return incompatible_clock;
347 }
348 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php