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