xref: /openbmc/linux/sound/pci/oxygen/xonar_dg.c (revision e8f6f3b4)
1 /*
2  * card driver for the Xonar DG/DGX
3  *
4  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
5  * Copyright (c) Roman Volkov <v1ron@mail.ru>
6  *
7  *  This driver is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License, version 2.
9  *
10  *  This driver is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this driver; if not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 /*
20  * Xonar DG/DGX
21  * ------------
22  *
23  * CS4245 and CS4361 both will mute all outputs if any clock ratio
24  * is invalid.
25  *
26  * CMI8788:
27  *
28  *   SPI 0 -> CS4245
29  *
30  *   Playback:
31  *   I²S 1 -> CS4245
32  *   I²S 2 -> CS4361 (center/LFE)
33  *   I²S 3 -> CS4361 (surround)
34  *   I²S 4 -> CS4361 (front)
35  *   Capture:
36  *   I²S ADC 1 <- CS4245
37  *
38  *   GPIO 3 <- ?
39  *   GPIO 4 <- headphone detect
40  *   GPIO 5 -> enable ADC analog circuit for the left channel
41  *   GPIO 6 -> enable ADC analog circuit for the right channel
42  *   GPIO 7 -> switch green rear output jack between CS4245 and and the first
43  *             channel of CS4361 (mechanical relay)
44  *   GPIO 8 -> enable output to speakers
45  *
46  * CS4245:
47  *
48  *   input 0 <- mic
49  *   input 1 <- aux
50  *   input 2 <- front mic
51  *   input 4 <- line
52  *   DAC out -> headphones
53  *   aux out -> front panel headphones
54  */
55 
56 #include <linux/pci.h>
57 #include <linux/delay.h>
58 #include <sound/control.h>
59 #include <sound/core.h>
60 #include <sound/info.h>
61 #include <sound/pcm.h>
62 #include <sound/tlv.h>
63 #include "oxygen.h"
64 #include "xonar_dg.h"
65 #include "cs4245.h"
66 
67 int cs4245_write_spi(struct oxygen *chip, u8 reg)
68 {
69 	struct dg *data = chip->model_data;
70 	unsigned int packet;
71 
72 	packet = reg << 8;
73 	packet |= (CS4245_SPI_ADDRESS | CS4245_SPI_WRITE) << 16;
74 	packet |= data->cs4245_shadow[reg];
75 
76 	return oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
77 				OXYGEN_SPI_DATA_LENGTH_3 |
78 				OXYGEN_SPI_CLOCK_1280 |
79 				(0 << OXYGEN_SPI_CODEC_SHIFT) |
80 				OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
81 				packet);
82 }
83 
84 int cs4245_read_spi(struct oxygen *chip, u8 addr)
85 {
86 	struct dg *data = chip->model_data;
87 	int ret;
88 
89 	ret = oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
90 		OXYGEN_SPI_DATA_LENGTH_2 |
91 		OXYGEN_SPI_CEN_LATCH_CLOCK_HI |
92 		OXYGEN_SPI_CLOCK_1280 | (0 << OXYGEN_SPI_CODEC_SHIFT),
93 		((CS4245_SPI_ADDRESS | CS4245_SPI_WRITE) << 8) | addr);
94 	if (ret < 0)
95 		return ret;
96 
97 	ret = oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
98 		OXYGEN_SPI_DATA_LENGTH_2 |
99 		OXYGEN_SPI_CEN_LATCH_CLOCK_HI |
100 		OXYGEN_SPI_CLOCK_1280 | (0 << OXYGEN_SPI_CODEC_SHIFT),
101 		(CS4245_SPI_ADDRESS | CS4245_SPI_READ) << 8);
102 	if (ret < 0)
103 		return ret;
104 
105 	data->cs4245_shadow[addr] = oxygen_read8(chip, OXYGEN_SPI_DATA1);
106 
107 	return 0;
108 }
109 
110 int cs4245_shadow_control(struct oxygen *chip, enum cs4245_shadow_operation op)
111 {
112 	struct dg *data = chip->model_data;
113 	unsigned char addr;
114 	int ret;
115 
116 	for (addr = 1; addr < ARRAY_SIZE(data->cs4245_shadow); addr++) {
117 		ret = (op == CS4245_SAVE_TO_SHADOW ?
118 			cs4245_read_spi(chip, addr) :
119 			cs4245_write_spi(chip, addr));
120 		if (ret < 0)
121 			return ret;
122 	}
123 	return 0;
124 }
125 
126 static void cs4245_init(struct oxygen *chip)
127 {
128 	struct dg *data = chip->model_data;
129 
130 	/* save the initial state: codec version, registers */
131 	cs4245_shadow_control(chip, CS4245_SAVE_TO_SHADOW);
132 
133 	/*
134 	 * Power up the CODEC internals, enable soft ramp & zero cross, work in
135 	 * async. mode, enable aux output from DAC. Invert DAC output as in the
136 	 * Windows driver.
137 	 */
138 	data->cs4245_shadow[CS4245_POWER_CTRL] = 0;
139 	data->cs4245_shadow[CS4245_SIGNAL_SEL] =
140 		CS4245_A_OUT_SEL_DAC | CS4245_ASYNCH;
141 	data->cs4245_shadow[CS4245_DAC_CTRL_1] =
142 		CS4245_DAC_FM_SINGLE | CS4245_DAC_DIF_LJUST;
143 	data->cs4245_shadow[CS4245_DAC_CTRL_2] =
144 		CS4245_DAC_SOFT | CS4245_DAC_ZERO | CS4245_INVERT_DAC;
145 	data->cs4245_shadow[CS4245_ADC_CTRL] =
146 		CS4245_ADC_FM_SINGLE | CS4245_ADC_DIF_LJUST;
147 	data->cs4245_shadow[CS4245_ANALOG_IN] =
148 		CS4245_PGA_SOFT | CS4245_PGA_ZERO;
149 	data->cs4245_shadow[CS4245_PGA_B_CTRL] = 0;
150 	data->cs4245_shadow[CS4245_PGA_A_CTRL] = 0;
151 	data->cs4245_shadow[CS4245_DAC_A_CTRL] = 8;
152 	data->cs4245_shadow[CS4245_DAC_B_CTRL] = 8;
153 
154 	cs4245_shadow_control(chip, CS4245_LOAD_FROM_SHADOW);
155 	snd_component_add(chip->card, "CS4245");
156 }
157 
158 void dg_init(struct oxygen *chip)
159 {
160 	struct dg *data = chip->model_data;
161 
162 	data->output_sel = PLAYBACK_DST_HP_FP;
163 	data->input_sel = CAPTURE_SRC_MIC;
164 
165 	cs4245_init(chip);
166 	oxygen_write16(chip, OXYGEN_GPIO_CONTROL,
167 		       GPIO_OUTPUT_ENABLE | GPIO_HP_REAR | GPIO_INPUT_ROUTE);
168 	/* anti-pop delay, wait some time before enabling the output */
169 	msleep(2500);
170 	oxygen_write16(chip, OXYGEN_GPIO_DATA,
171 		       GPIO_OUTPUT_ENABLE | GPIO_INPUT_ROUTE);
172 }
173 
174 void dg_cleanup(struct oxygen *chip)
175 {
176 	oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
177 }
178 
179 void dg_suspend(struct oxygen *chip)
180 {
181 	dg_cleanup(chip);
182 }
183 
184 void dg_resume(struct oxygen *chip)
185 {
186 	cs4245_shadow_control(chip, CS4245_LOAD_FROM_SHADOW);
187 	msleep(2500);
188 	oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
189 }
190 
191 void set_cs4245_dac_params(struct oxygen *chip,
192 				  struct snd_pcm_hw_params *params)
193 {
194 	struct dg *data = chip->model_data;
195 	unsigned char dac_ctrl;
196 	unsigned char mclk_freq;
197 
198 	dac_ctrl = data->cs4245_shadow[CS4245_DAC_CTRL_1] & ~CS4245_DAC_FM_MASK;
199 	mclk_freq = data->cs4245_shadow[CS4245_MCLK_FREQ] & ~CS4245_MCLK1_MASK;
200 	if (params_rate(params) <= 50000) {
201 		dac_ctrl |= CS4245_DAC_FM_SINGLE;
202 		mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK1_SHIFT;
203 	} else if (params_rate(params) <= 100000) {
204 		dac_ctrl |= CS4245_DAC_FM_DOUBLE;
205 		mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK1_SHIFT;
206 	} else {
207 		dac_ctrl |= CS4245_DAC_FM_QUAD;
208 		mclk_freq |= CS4245_MCLK_2 << CS4245_MCLK1_SHIFT;
209 	}
210 	data->cs4245_shadow[CS4245_DAC_CTRL_1] = dac_ctrl;
211 	data->cs4245_shadow[CS4245_MCLK_FREQ] = mclk_freq;
212 	cs4245_write_spi(chip, CS4245_DAC_CTRL_1);
213 	cs4245_write_spi(chip, CS4245_MCLK_FREQ);
214 }
215 
216 void set_cs4245_adc_params(struct oxygen *chip,
217 				  struct snd_pcm_hw_params *params)
218 {
219 	struct dg *data = chip->model_data;
220 	unsigned char adc_ctrl;
221 	unsigned char mclk_freq;
222 
223 	adc_ctrl = data->cs4245_shadow[CS4245_ADC_CTRL] & ~CS4245_ADC_FM_MASK;
224 	mclk_freq = data->cs4245_shadow[CS4245_MCLK_FREQ] & ~CS4245_MCLK2_MASK;
225 	if (params_rate(params) <= 50000) {
226 		adc_ctrl |= CS4245_ADC_FM_SINGLE;
227 		mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK2_SHIFT;
228 	} else if (params_rate(params) <= 100000) {
229 		adc_ctrl |= CS4245_ADC_FM_DOUBLE;
230 		mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK2_SHIFT;
231 	} else {
232 		adc_ctrl |= CS4245_ADC_FM_QUAD;
233 		mclk_freq |= CS4245_MCLK_2 << CS4245_MCLK2_SHIFT;
234 	}
235 	data->cs4245_shadow[CS4245_ADC_CTRL] = adc_ctrl;
236 	data->cs4245_shadow[CS4245_MCLK_FREQ] = mclk_freq;
237 	cs4245_write_spi(chip, CS4245_ADC_CTRL);
238 	cs4245_write_spi(chip, CS4245_MCLK_FREQ);
239 }
240 
241 static inline unsigned int shift_bits(unsigned int value,
242 				      unsigned int shift_from,
243 				      unsigned int shift_to,
244 				      unsigned int mask)
245 {
246 	if (shift_from < shift_to)
247 		return (value << (shift_to - shift_from)) & mask;
248 	else
249 		return (value >> (shift_from - shift_to)) & mask;
250 }
251 
252 unsigned int adjust_dg_dac_routing(struct oxygen *chip,
253 					  unsigned int play_routing)
254 {
255 	struct dg *data = chip->model_data;
256 
257 	switch (data->output_sel) {
258 	case PLAYBACK_DST_HP:
259 	case PLAYBACK_DST_HP_FP:
260 		oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING,
261 			OXYGEN_PLAY_MUTE23 | OXYGEN_PLAY_MUTE45 |
262 			OXYGEN_PLAY_MUTE67, OXYGEN_PLAY_MUTE_MASK);
263 		break;
264 	case PLAYBACK_DST_MULTICH:
265 		oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING,
266 			OXYGEN_PLAY_MUTE01, OXYGEN_PLAY_MUTE_MASK);
267 		break;
268 	}
269 	return (play_routing & OXYGEN_PLAY_DAC0_SOURCE_MASK) |
270 	       shift_bits(play_routing,
271 			  OXYGEN_PLAY_DAC2_SOURCE_SHIFT,
272 			  OXYGEN_PLAY_DAC1_SOURCE_SHIFT,
273 			  OXYGEN_PLAY_DAC1_SOURCE_MASK) |
274 	       shift_bits(play_routing,
275 			  OXYGEN_PLAY_DAC1_SOURCE_SHIFT,
276 			  OXYGEN_PLAY_DAC2_SOURCE_SHIFT,
277 			  OXYGEN_PLAY_DAC2_SOURCE_MASK) |
278 	       shift_bits(play_routing,
279 			  OXYGEN_PLAY_DAC0_SOURCE_SHIFT,
280 			  OXYGEN_PLAY_DAC3_SOURCE_SHIFT,
281 			  OXYGEN_PLAY_DAC3_SOURCE_MASK);
282 }
283 
284 void dump_cs4245_registers(struct oxygen *chip,
285 				  struct snd_info_buffer *buffer)
286 {
287 	struct dg *data = chip->model_data;
288 	unsigned int addr;
289 
290 	snd_iprintf(buffer, "\nCS4245:");
291 	cs4245_read_spi(chip, CS4245_INT_STATUS);
292 	for (addr = 1; addr < ARRAY_SIZE(data->cs4245_shadow); addr++)
293 		snd_iprintf(buffer, " %02x", data->cs4245_shadow[addr]);
294 	snd_iprintf(buffer, "\n");
295 }
296