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
67int 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
84int 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
110int 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
126static 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
158void 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
174void dg_cleanup(struct oxygen *chip)
175{
176	oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
177}
178
179void dg_suspend(struct oxygen *chip)
180{
181	dg_cleanup(chip);
182}
183
184void 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
191void 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
216void 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
241static 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
252unsigned 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
284void 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