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