xref: /linux/sound/pci/echoaudio/mia_dsp.c (revision bc1d4e705f48f001f3a5480f04067c48bd00bcf0)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /****************************************************************************
3 
4    Copyright Echo Digital Audio Corporation (c) 1998 - 2004
5    All rights reserved
6    www.echoaudio.com
7 
8    This file is part of Echo Digital Audio's generic driver library.
9    *************************************************************************
10 
11  Translation from C++ and adaptation for use in ALSA-Driver
12  were made by Giuliano Pochini <pochini@shiny.it>
13 
14 ****************************************************************************/
15 
16 
17 static int set_input_clock(struct echoaudio *chip, u16 clock);
18 static int set_professional_spdif(struct echoaudio *chip, char prof);
19 static int update_flags(struct echoaudio *chip);
20 static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
21 			   int gain);
22 static int update_vmixer_level(struct echoaudio *chip);
23 
24 
init_hw(struct echoaudio * chip,u16 device_id,u16 subdevice_id)25 static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
26 {
27 	int err;
28 
29 	if (snd_BUG_ON((subdevice_id & 0xfff0) != MIA))
30 		return -ENODEV;
31 
32 	err = init_dsp_comm_page(chip);
33 	if (err) {
34 		dev_err(chip->card->dev,
35 			"init_hw - could not initialize DSP comm page\n");
36 		return err;
37 	}
38 
39 	chip->device_id = device_id;
40 	chip->subdevice_id = subdevice_id;
41 	chip->bad_board = true;
42 	chip->dsp_code_to_load = FW_MIA_DSP;
43 	/* Since this card has no ASIC, mark it as loaded so everything
44 	   works OK */
45 	chip->asic_loaded = true;
46 	if ((subdevice_id & 0x0000f) == MIA_MIDI_REV)
47 		chip->has_midi = true;
48 	chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL |
49 		ECHO_CLOCK_BIT_SPDIF;
50 
51 	err = load_firmware(chip);
52 	if (err < 0)
53 		return err;
54 	chip->bad_board = false;
55 
56 	return err;
57 }
58 
59 
60 
set_mixer_defaults(struct echoaudio * chip)61 static int set_mixer_defaults(struct echoaudio *chip)
62 {
63 	return init_line_levels(chip);
64 }
65 
66 
67 
detect_input_clocks(const struct echoaudio * chip)68 static u32 detect_input_clocks(const struct echoaudio *chip)
69 {
70 	u32 clocks_from_dsp, clock_bits;
71 
72 	/* Map the DSP clock detect bits to the generic driver clock
73 	   detect bits */
74 	clocks_from_dsp = le32_to_cpu(chip->comm_page->status_clocks);
75 
76 	clock_bits = ECHO_CLOCK_BIT_INTERNAL;
77 
78 	if (clocks_from_dsp & GLDM_CLOCK_DETECT_BIT_SPDIF)
79 		clock_bits |= ECHO_CLOCK_BIT_SPDIF;
80 
81 	return clock_bits;
82 }
83 
84 
85 
86 /* The Mia has no ASIC. Just do nothing */
load_asic(struct echoaudio * chip)87 static int load_asic(struct echoaudio *chip)
88 {
89 	return 0;
90 }
91 
92 
93 
set_sample_rate(struct echoaudio * chip,u32 rate)94 static int set_sample_rate(struct echoaudio *chip, u32 rate)
95 {
96 	u32 control_reg;
97 
98 	switch (rate) {
99 	case 96000:
100 		control_reg = MIA_96000;
101 		break;
102 	case 88200:
103 		control_reg = MIA_88200;
104 		break;
105 	case 48000:
106 		control_reg = MIA_48000;
107 		break;
108 	case 44100:
109 		control_reg = MIA_44100;
110 		break;
111 	case 32000:
112 		control_reg = MIA_32000;
113 		break;
114 	default:
115 		dev_err(chip->card->dev,
116 			"set_sample_rate: %d invalid!\n", rate);
117 		return -EINVAL;
118 	}
119 
120 	/* Override the clock setting if this Mia is set to S/PDIF clock */
121 	if (chip->input_clock == ECHO_CLOCK_SPDIF)
122 		control_reg |= MIA_SPDIF;
123 
124 	/* Set the control register if it has changed */
125 	if (control_reg != le32_to_cpu(chip->comm_page->control_register)) {
126 		if (wait_handshake(chip))
127 			return -EIO;
128 
129 		chip->comm_page->sample_rate = cpu_to_le32(rate);	/* ignored by the DSP */
130 		chip->comm_page->control_register = cpu_to_le32(control_reg);
131 		chip->sample_rate = rate;
132 
133 		clear_handshake(chip);
134 		return send_vector(chip, DSP_VC_UPDATE_CLOCKS);
135 	}
136 	return 0;
137 }
138 
139 
140 
set_input_clock(struct echoaudio * chip,u16 clock)141 static int set_input_clock(struct echoaudio *chip, u16 clock)
142 {
143 	dev_dbg(chip->card->dev, "set_input_clock(%d)\n", clock);
144 	if (snd_BUG_ON(clock != ECHO_CLOCK_INTERNAL &&
145 		       clock != ECHO_CLOCK_SPDIF))
146 		return -EINVAL;
147 
148 	chip->input_clock = clock;
149 	return set_sample_rate(chip, chip->sample_rate);
150 }
151 
152 
153 
154 /* This function routes the sound from a virtual channel to a real output */
set_vmixer_gain(struct echoaudio * chip,u16 output,u16 pipe,int gain)155 static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
156 			   int gain)
157 {
158 	int index;
159 
160 	if (snd_BUG_ON(pipe >= num_pipes_out(chip) ||
161 		       output >= num_busses_out(chip)))
162 		return -EINVAL;
163 
164 	if (wait_handshake(chip))
165 		return -EIO;
166 
167 	chip->vmixer_gain[output][pipe] = gain;
168 	index = output * num_pipes_out(chip) + pipe;
169 	chip->comm_page->vmixer[index] = gain;
170 
171 	dev_dbg(chip->card->dev,
172 		"set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain);
173 	return 0;
174 }
175 
176 
177 
178 /* Tell the DSP to read and update virtual mixer levels in comm page. */
update_vmixer_level(struct echoaudio * chip)179 static int update_vmixer_level(struct echoaudio *chip)
180 {
181 	if (wait_handshake(chip))
182 		return -EIO;
183 	clear_handshake(chip);
184 	return send_vector(chip, DSP_VC_SET_VMIXER_GAIN);
185 }
186 
187 
188 
189 /* Tell the DSP to reread the flags from the comm page */
update_flags(struct echoaudio * chip)190 static int update_flags(struct echoaudio *chip)
191 {
192 	if (wait_handshake(chip))
193 		return -EIO;
194 	clear_handshake(chip);
195 	return send_vector(chip, DSP_VC_UPDATE_FLAGS);
196 }
197 
198 
199 
set_professional_spdif(struct echoaudio * chip,char prof)200 static int set_professional_spdif(struct echoaudio *chip, char prof)
201 {
202 	dev_dbg(chip->card->dev, "set_professional_spdif %d\n", prof);
203 	if (prof)
204 		chip->comm_page->flags |=
205 			cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
206 	else
207 		chip->comm_page->flags &=
208 			~cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
209 	chip->professional_spdif = prof;
210 	return update_flags(chip);
211 }
212 
213