diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 01:02:30 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 01:02:30 +0000 |
commit | 76cb841cb886eef6b3bee341a2266c76578724ad (patch) | |
tree | f5892e5ba6cc11949952a6ce4ecbe6d516d6ce58 /sound/pci/echoaudio/echoaudio_gml.c | |
parent | Initial commit. (diff) | |
download | linux-upstream.tar.xz linux-upstream.zip |
Adding upstream version 4.19.249.upstream/4.19.249upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sound/pci/echoaudio/echoaudio_gml.c')
-rw-r--r-- | sound/pci/echoaudio/echoaudio_gml.c | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/sound/pci/echoaudio/echoaudio_gml.c b/sound/pci/echoaudio/echoaudio_gml.c new file mode 100644 index 000000000..eea6fe530 --- /dev/null +++ b/sound/pci/echoaudio/echoaudio_gml.c @@ -0,0 +1,203 @@ +/**************************************************************************** + + Copyright Echo Digital Audio Corporation (c) 1998 - 2004 + All rights reserved + www.echoaudio.com + + This file is part of Echo Digital Audio's generic driver library. + + Echo Digital Audio's generic driver library is free software; + you can redistribute it and/or modify it under the terms of + the GNU General Public License as published by the Free Software + Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + ************************************************************************* + + Translation from C++ and adaptation for use in ALSA-Driver + were made by Giuliano Pochini <pochini@shiny.it> + +****************************************************************************/ + + +/* These functions are common for Gina24, Layla24 and Mona cards */ + + +/* ASIC status check - some cards have one or two ASICs that need to be +loaded. Once that load is complete, this function is called to see if +the load was successful. +If this load fails, it does not necessarily mean that the hardware is +defective - the external box may be disconnected or turned off. */ +static int check_asic_status(struct echoaudio *chip) +{ + u32 asic_status; + + send_vector(chip, DSP_VC_TEST_ASIC); + + /* The DSP will return a value to indicate whether or not the + ASIC is currently loaded */ + if (read_dsp(chip, &asic_status) < 0) { + dev_err(chip->card->dev, + "check_asic_status: failed on read_dsp\n"); + chip->asic_loaded = false; + return -EIO; + } + + chip->asic_loaded = (asic_status == ASIC_ALREADY_LOADED); + return chip->asic_loaded ? 0 : -EIO; +} + + + +/* Most configuration of Gina24, Layla24, or Mona is accomplished by writing +the control register. write_control_reg sends the new control register +value to the DSP. */ +static int write_control_reg(struct echoaudio *chip, u32 value, char force) +{ + __le32 reg_value; + + /* Handle the digital input auto-mute */ + if (chip->digital_in_automute) + value |= GML_DIGITAL_IN_AUTO_MUTE; + else + value &= ~GML_DIGITAL_IN_AUTO_MUTE; + + dev_dbg(chip->card->dev, "write_control_reg: 0x%x\n", value); + + /* Write the control register */ + reg_value = cpu_to_le32(value); + if (reg_value != chip->comm_page->control_register || force) { + if (wait_handshake(chip)) + return -EIO; + chip->comm_page->control_register = reg_value; + clear_handshake(chip); + return send_vector(chip, DSP_VC_WRITE_CONTROL_REG); + } + return 0; +} + + + +/* Gina24, Layla24, and Mona support digital input auto-mute. If the digital +input auto-mute is enabled, the DSP will only enable the digital inputs if +the card is syncing to a valid clock on the ADAT or S/PDIF inputs. +If the auto-mute is disabled, the digital inputs are enabled regardless of +what the input clock is set or what is connected. */ +static int set_input_auto_mute(struct echoaudio *chip, int automute) +{ + dev_dbg(chip->card->dev, "set_input_auto_mute %d\n", automute); + + chip->digital_in_automute = automute; + + /* Re-set the input clock to the current value - indirectly causes + the auto-mute flag to be sent to the DSP */ + return set_input_clock(chip, chip->input_clock); +} + + + +/* S/PDIF coax / S/PDIF optical / ADAT - switch */ +static int set_digital_mode(struct echoaudio *chip, u8 mode) +{ + u8 previous_mode; + int err, i, o; + + if (chip->bad_board) + return -EIO; + + /* All audio channels must be closed before changing the digital mode */ + if (snd_BUG_ON(chip->pipe_alloc_mask)) + return -EAGAIN; + + if (snd_BUG_ON(!(chip->digital_modes & (1 << mode)))) + return -EINVAL; + + previous_mode = chip->digital_mode; + err = dsp_set_digital_mode(chip, mode); + + /* If we successfully changed the digital mode from or to ADAT, + then make sure all output, input and monitor levels are + updated by the DSP comm object. */ + if (err >= 0 && previous_mode != mode && + (previous_mode == DIGITAL_MODE_ADAT || mode == DIGITAL_MODE_ADAT)) { + spin_lock_irq(&chip->lock); + for (o = 0; o < num_busses_out(chip); o++) + for (i = 0; i < num_busses_in(chip); i++) + set_monitor_gain(chip, o, i, + chip->monitor_gain[o][i]); + +#ifdef ECHOCARD_HAS_INPUT_GAIN + for (i = 0; i < num_busses_in(chip); i++) + set_input_gain(chip, i, chip->input_gain[i]); + update_input_line_level(chip); +#endif + + for (o = 0; o < num_busses_out(chip); o++) + set_output_gain(chip, o, chip->output_gain[o]); + update_output_line_level(chip); + spin_unlock_irq(&chip->lock); + } + + return err; +} + + + +/* Set the S/PDIF output format */ +static int set_professional_spdif(struct echoaudio *chip, char prof) +{ + u32 control_reg; + int err; + + /* Clear the current S/PDIF flags */ + control_reg = le32_to_cpu(chip->comm_page->control_register); + control_reg &= GML_SPDIF_FORMAT_CLEAR_MASK; + + /* Set the new S/PDIF flags depending on the mode */ + control_reg |= GML_SPDIF_TWO_CHANNEL | GML_SPDIF_24_BIT | + GML_SPDIF_COPY_PERMIT; + if (prof) { + /* Professional mode */ + control_reg |= GML_SPDIF_PRO_MODE; + + switch (chip->sample_rate) { + case 32000: + control_reg |= GML_SPDIF_SAMPLE_RATE0 | + GML_SPDIF_SAMPLE_RATE1; + break; + case 44100: + control_reg |= GML_SPDIF_SAMPLE_RATE0; + break; + case 48000: + control_reg |= GML_SPDIF_SAMPLE_RATE1; + break; + } + } else { + /* Consumer mode */ + switch (chip->sample_rate) { + case 32000: + control_reg |= GML_SPDIF_SAMPLE_RATE0 | + GML_SPDIF_SAMPLE_RATE1; + break; + case 48000: + control_reg |= GML_SPDIF_SAMPLE_RATE1; + break; + } + } + + if ((err = write_control_reg(chip, control_reg, false))) + return err; + chip->professional_spdif = prof; + dev_dbg(chip->card->dev, "set_professional_spdif to %s\n", + prof ? "Professional" : "Consumer"); + return 0; +} |