Path: blob/master/sound/pci/echoaudio/layla20_dsp.c
10817 views
/****************************************************************************12Copyright Echo Digital Audio Corporation (c) 1998 - 20043All rights reserved4www.echoaudio.com56This file is part of Echo Digital Audio's generic driver library.78Echo Digital Audio's generic driver library is free software;9you can redistribute it and/or modify it under the terms of10the GNU General Public License as published by the Free Software11Foundation.1213This program is distributed in the hope that it will be useful,14but WITHOUT ANY WARRANTY; without even the implied warranty of15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the16GNU General Public License for more details.1718You should have received a copy of the GNU General Public License19along with this program; if not, write to the Free Software20Foundation, Inc., 59 Temple Place - Suite 330, Boston,21MA 02111-1307, USA.2223*************************************************************************2425Translation from C++ and adaptation for use in ALSA-Driver26were made by Giuliano Pochini <[email protected]>2728****************************************************************************/293031static int read_dsp(struct echoaudio *chip, u32 *data);32static int set_professional_spdif(struct echoaudio *chip, char prof);33static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic);34static int check_asic_status(struct echoaudio *chip);35static int update_flags(struct echoaudio *chip);363738static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)39{40int err;4142DE_INIT(("init_hw() - Layla20\n"));43if (snd_BUG_ON((subdevice_id & 0xfff0) != LAYLA20))44return -ENODEV;4546if ((err = init_dsp_comm_page(chip))) {47DE_INIT(("init_hw - could not initialize DSP comm page\n"));48return err;49}5051chip->device_id = device_id;52chip->subdevice_id = subdevice_id;53chip->bad_board = TRUE;54chip->has_midi = TRUE;55chip->dsp_code_to_load = FW_LAYLA20_DSP;56chip->input_clock_types =57ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF |58ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_SUPER;59chip->output_clock_types =60ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_SUPER;6162if ((err = load_firmware(chip)) < 0)63return err;64chip->bad_board = FALSE;6566DE_INIT(("init_hw done\n"));67return err;68}69707172static int set_mixer_defaults(struct echoaudio *chip)73{74chip->professional_spdif = FALSE;75return init_line_levels(chip);76}77787980static u32 detect_input_clocks(const struct echoaudio *chip)81{82u32 clocks_from_dsp, clock_bits;8384/* Map the DSP clock detect bits to the generic driver clock detect bits */85clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);8687clock_bits = ECHO_CLOCK_BIT_INTERNAL;8889if (clocks_from_dsp & GLDM_CLOCK_DETECT_BIT_SPDIF)90clock_bits |= ECHO_CLOCK_BIT_SPDIF;9192if (clocks_from_dsp & GLDM_CLOCK_DETECT_BIT_WORD) {93if (clocks_from_dsp & GLDM_CLOCK_DETECT_BIT_SUPER)94clock_bits |= ECHO_CLOCK_BIT_SUPER;95else96clock_bits |= ECHO_CLOCK_BIT_WORD;97}9899return clock_bits;100}101102103104/* ASIC status check - some cards have one or two ASICs that need to be105loaded. Once that load is complete, this function is called to see if106the load was successful.107If this load fails, it does not necessarily mean that the hardware is108defective - the external box may be disconnected or turned off.109This routine sometimes fails for Layla20; for Layla20, the loop runs1105 times and succeeds if it wins on three of the loops. */111static int check_asic_status(struct echoaudio *chip)112{113u32 asic_status;114int goodcnt, i;115116chip->asic_loaded = FALSE;117for (i = goodcnt = 0; i < 5; i++) {118send_vector(chip, DSP_VC_TEST_ASIC);119120/* The DSP will return a value to indicate whether or not121the ASIC is currently loaded */122if (read_dsp(chip, &asic_status) < 0) {123DE_ACT(("check_asic_status: failed on read_dsp\n"));124return -EIO;125}126127if (asic_status == ASIC_ALREADY_LOADED) {128if (++goodcnt == 3) {129chip->asic_loaded = TRUE;130return 0;131}132}133}134return -EIO;135}136137138139/* Layla20 has an ASIC in the external box */140static int load_asic(struct echoaudio *chip)141{142int err;143144if (chip->asic_loaded)145return 0;146147err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA_ASIC,148FW_LAYLA20_ASIC);149if (err < 0)150return err;151152/* Check if ASIC is alive and well. */153return check_asic_status(chip);154}155156157158static int set_sample_rate(struct echoaudio *chip, u32 rate)159{160if (snd_BUG_ON(rate < 8000 || rate > 50000))161return -EINVAL;162163/* Only set the clock for internal mode. Do not return failure,164simply treat it as a non-event. */165if (chip->input_clock != ECHO_CLOCK_INTERNAL) {166DE_ACT(("set_sample_rate: Cannot set sample rate - "167"clock not set to CLK_CLOCKININTERNAL\n"));168chip->comm_page->sample_rate = cpu_to_le32(rate);169chip->sample_rate = rate;170return 0;171}172173if (wait_handshake(chip))174return -EIO;175176DE_ACT(("set_sample_rate(%d)\n", rate));177chip->sample_rate = rate;178chip->comm_page->sample_rate = cpu_to_le32(rate);179clear_handshake(chip);180return send_vector(chip, DSP_VC_SET_LAYLA_SAMPLE_RATE);181}182183184185static int set_input_clock(struct echoaudio *chip, u16 clock_source)186{187u16 clock;188u32 rate;189190DE_ACT(("set_input_clock:\n"));191rate = 0;192switch (clock_source) {193case ECHO_CLOCK_INTERNAL:194DE_ACT(("Set Layla20 clock to INTERNAL\n"));195rate = chip->sample_rate;196clock = LAYLA20_CLOCK_INTERNAL;197break;198case ECHO_CLOCK_SPDIF:199DE_ACT(("Set Layla20 clock to SPDIF\n"));200clock = LAYLA20_CLOCK_SPDIF;201break;202case ECHO_CLOCK_WORD:203DE_ACT(("Set Layla20 clock to WORD\n"));204clock = LAYLA20_CLOCK_WORD;205break;206case ECHO_CLOCK_SUPER:207DE_ACT(("Set Layla20 clock to SUPER\n"));208clock = LAYLA20_CLOCK_SUPER;209break;210default:211DE_ACT(("Input clock 0x%x not supported for Layla24\n",212clock_source));213return -EINVAL;214}215chip->input_clock = clock_source;216217chip->comm_page->input_clock = cpu_to_le16(clock);218clear_handshake(chip);219send_vector(chip, DSP_VC_UPDATE_CLOCKS);220221if (rate)222set_sample_rate(chip, rate);223224return 0;225}226227228229static int set_output_clock(struct echoaudio *chip, u16 clock)230{231DE_ACT(("set_output_clock: %d\n", clock));232switch (clock) {233case ECHO_CLOCK_SUPER:234clock = LAYLA20_OUTPUT_CLOCK_SUPER;235break;236case ECHO_CLOCK_WORD:237clock = LAYLA20_OUTPUT_CLOCK_WORD;238break;239default:240DE_ACT(("set_output_clock wrong clock\n"));241return -EINVAL;242}243244if (wait_handshake(chip))245return -EIO;246247chip->comm_page->output_clock = cpu_to_le16(clock);248chip->output_clock = clock;249clear_handshake(chip);250return send_vector(chip, DSP_VC_UPDATE_CLOCKS);251}252253254255/* Set input bus gain (one unit is 0.5dB !) */256static int set_input_gain(struct echoaudio *chip, u16 input, int gain)257{258if (snd_BUG_ON(input >= num_busses_in(chip)))259return -EINVAL;260261if (wait_handshake(chip))262return -EIO;263264chip->input_gain[input] = gain;265gain += GL20_INPUT_GAIN_MAGIC_NUMBER;266chip->comm_page->line_in_level[input] = gain;267return 0;268}269270271272/* Tell the DSP to reread the flags from the comm page */273static int update_flags(struct echoaudio *chip)274{275if (wait_handshake(chip))276return -EIO;277clear_handshake(chip);278return send_vector(chip, DSP_VC_UPDATE_FLAGS);279}280281282283static int set_professional_spdif(struct echoaudio *chip, char prof)284{285DE_ACT(("set_professional_spdif %d\n", prof));286if (prof)287chip->comm_page->flags |=288cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);289else290chip->comm_page->flags &=291~cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);292chip->professional_spdif = prof;293return update_flags(chip);294}295296297