Linux-libre 5.4.47-gnu
[librecmc/linux-libre.git] / sound / pci / oxygen / xonar_dg.c
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 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
57 int 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
74 int 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
100 int 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
116 static 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
148 void 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
164 void dg_cleanup(struct oxygen *chip)
165 {
166         oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
167 }
168
169 void dg_suspend(struct oxygen *chip)
170 {
171         dg_cleanup(chip);
172 }
173
174 void 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
181 void 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
206 void 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
231 static 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
242 unsigned 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
274 void 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 }