xref: /openbmc/linux/sound/pci/ca0106/ca0106_proc.c (revision bbb774d9)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *  Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk>
4  *  Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit
5  *  Version: 0.0.18
6  *
7  *  FEATURES currently supported:
8  *    See ca0106_main.c for features.
9  *
10  *  Changelog:
11  *    Support interrupts per period.
12  *    Removed noise from Center/LFE channel when in Analog mode.
13  *    Rename and remove mixer controls.
14  *  0.0.6
15  *    Use separate card based DMA buffer for periods table list.
16  *  0.0.7
17  *    Change remove and rename ctrls into lists.
18  *  0.0.8
19  *    Try to fix capture sources.
20  *  0.0.9
21  *    Fix AC3 output.
22  *    Enable S32_LE format support.
23  *  0.0.10
24  *    Enable playback 48000 and 96000 rates. (Rates other that these do not work, even with "plug:front".)
25  *  0.0.11
26  *    Add Model name recognition.
27  *  0.0.12
28  *    Correct interrupt timing. interrupt at end of period, instead of in the middle of a playback period.
29  *    Remove redundent "voice" handling.
30  *  0.0.13
31  *    Single trigger call for multi channels.
32  *  0.0.14
33  *    Set limits based on what the sound card hardware can do.
34  *    playback periods_min=2, periods_max=8
35  *    capture hw constraints require period_size = n * 64 bytes.
36  *    playback hw constraints require period_size = n * 64 bytes.
37  *  0.0.15
38  *    Separate ca0106.c into separate functional .c files.
39  *  0.0.16
40  *    Modified Copyright message.
41  *  0.0.17
42  *    Add iec958 file in proc file system to show status of SPDIF in.
43  *  0.0.18
44  *    Implement support for Line-in capture on SB Live 24bit.
45  *
46  *  This code was initially based on code from ALSA's emu10k1x.c which is:
47  *  Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com>
48  */
49 #include <linux/delay.h>
50 #include <linux/init.h>
51 #include <linux/interrupt.h>
52 #include <linux/moduleparam.h>
53 #include <linux/io.h>
54 #include <sound/core.h>
55 #include <sound/initval.h>
56 #include <sound/pcm.h>
57 #include <sound/ac97_codec.h>
58 #include <sound/info.h>
59 #include <sound/asoundef.h>
60 
61 #include "ca0106.h"
62 
63 
64 struct snd_ca0106_category_str {
65 	int val;
66 	const char *name;
67 };
68 
69 static const struct snd_ca0106_category_str snd_ca0106_con_category[] = {
70 	{ IEC958_AES1_CON_DAT, "DAT" },
71 	{ IEC958_AES1_CON_VCR, "VCR" },
72 	{ IEC958_AES1_CON_MICROPHONE, "microphone" },
73 	{ IEC958_AES1_CON_SYNTHESIZER, "synthesizer" },
74 	{ IEC958_AES1_CON_RATE_CONVERTER, "rate converter" },
75 	{ IEC958_AES1_CON_MIXER, "mixer" },
76 	{ IEC958_AES1_CON_SAMPLER, "sampler" },
77 	{ IEC958_AES1_CON_PCM_CODER, "PCM coder" },
78 	{ IEC958_AES1_CON_IEC908_CD, "CD" },
79 	{ IEC958_AES1_CON_NON_IEC908_CD, "non-IEC908 CD" },
80 	{ IEC958_AES1_CON_GENERAL, "general" },
81 };
82 
83 
84 static void snd_ca0106_proc_dump_iec958( struct snd_info_buffer *buffer, u32 value)
85 {
86 	int i;
87 	u32 status[4];
88 	status[0] = value & 0xff;
89 	status[1] = (value >> 8) & 0xff;
90 	status[2] = (value >> 16)  & 0xff;
91 	status[3] = (value >> 24)  & 0xff;
92 
93 	if (! (status[0] & IEC958_AES0_PROFESSIONAL)) {
94 		/* consumer */
95 		snd_iprintf(buffer, "Mode: consumer\n");
96 		snd_iprintf(buffer, "Data: ");
97 		if (!(status[0] & IEC958_AES0_NONAUDIO)) {
98 			snd_iprintf(buffer, "audio\n");
99 		} else {
100 			snd_iprintf(buffer, "non-audio\n");
101 		}
102 		snd_iprintf(buffer, "Rate: ");
103 		switch (status[3] & IEC958_AES3_CON_FS) {
104 		case IEC958_AES3_CON_FS_44100:
105 			snd_iprintf(buffer, "44100 Hz\n");
106 			break;
107 		case IEC958_AES3_CON_FS_48000:
108 			snd_iprintf(buffer, "48000 Hz\n");
109 			break;
110 		case IEC958_AES3_CON_FS_32000:
111 			snd_iprintf(buffer, "32000 Hz\n");
112 			break;
113 		default:
114 			snd_iprintf(buffer, "unknown\n");
115 			break;
116 		}
117 		snd_iprintf(buffer, "Copyright: ");
118 		if (status[0] & IEC958_AES0_CON_NOT_COPYRIGHT) {
119 			snd_iprintf(buffer, "permitted\n");
120 		} else {
121 			snd_iprintf(buffer, "protected\n");
122 		}
123 		snd_iprintf(buffer, "Emphasis: ");
124 		if ((status[0] & IEC958_AES0_CON_EMPHASIS) != IEC958_AES0_CON_EMPHASIS_5015) {
125 			snd_iprintf(buffer, "none\n");
126 		} else {
127 			snd_iprintf(buffer, "50/15us\n");
128 		}
129 		snd_iprintf(buffer, "Category: ");
130 		for (i = 0; i < ARRAY_SIZE(snd_ca0106_con_category); i++) {
131 			if ((status[1] & IEC958_AES1_CON_CATEGORY) == snd_ca0106_con_category[i].val) {
132 				snd_iprintf(buffer, "%s\n", snd_ca0106_con_category[i].name);
133 				break;
134 			}
135 		}
136 		if (i >= ARRAY_SIZE(snd_ca0106_con_category)) {
137 			snd_iprintf(buffer, "unknown 0x%x\n", status[1] & IEC958_AES1_CON_CATEGORY);
138 		}
139 		snd_iprintf(buffer, "Original: ");
140 		if (status[1] & IEC958_AES1_CON_ORIGINAL) {
141 			snd_iprintf(buffer, "original\n");
142 		} else {
143 			snd_iprintf(buffer, "1st generation\n");
144 		}
145 		snd_iprintf(buffer, "Clock: ");
146 		switch (status[3] & IEC958_AES3_CON_CLOCK) {
147 		case IEC958_AES3_CON_CLOCK_1000PPM:
148 			snd_iprintf(buffer, "1000 ppm\n");
149 			break;
150 		case IEC958_AES3_CON_CLOCK_50PPM:
151 			snd_iprintf(buffer, "50 ppm\n");
152 			break;
153 		case IEC958_AES3_CON_CLOCK_VARIABLE:
154 			snd_iprintf(buffer, "variable pitch\n");
155 			break;
156 		default:
157 			snd_iprintf(buffer, "unknown\n");
158 			break;
159 		}
160 	} else {
161 		snd_iprintf(buffer, "Mode: professional\n");
162 		snd_iprintf(buffer, "Data: ");
163 		if (!(status[0] & IEC958_AES0_NONAUDIO)) {
164 			snd_iprintf(buffer, "audio\n");
165 		} else {
166 			snd_iprintf(buffer, "non-audio\n");
167 		}
168 		snd_iprintf(buffer, "Rate: ");
169 		switch (status[0] & IEC958_AES0_PRO_FS) {
170 		case IEC958_AES0_PRO_FS_44100:
171 			snd_iprintf(buffer, "44100 Hz\n");
172 			break;
173 		case IEC958_AES0_PRO_FS_48000:
174 			snd_iprintf(buffer, "48000 Hz\n");
175 			break;
176 		case IEC958_AES0_PRO_FS_32000:
177 			snd_iprintf(buffer, "32000 Hz\n");
178 			break;
179 		default:
180 			snd_iprintf(buffer, "unknown\n");
181 			break;
182 		}
183 		snd_iprintf(buffer, "Rate Locked: ");
184 		if (status[0] & IEC958_AES0_PRO_FREQ_UNLOCKED)
185 			snd_iprintf(buffer, "no\n");
186 		else
187 			snd_iprintf(buffer, "yes\n");
188 		snd_iprintf(buffer, "Emphasis: ");
189 		switch (status[0] & IEC958_AES0_PRO_EMPHASIS) {
190 		case IEC958_AES0_PRO_EMPHASIS_CCITT:
191 			snd_iprintf(buffer, "CCITT J.17\n");
192 			break;
193 		case IEC958_AES0_PRO_EMPHASIS_NONE:
194 			snd_iprintf(buffer, "none\n");
195 			break;
196 		case IEC958_AES0_PRO_EMPHASIS_5015:
197 			snd_iprintf(buffer, "50/15us\n");
198 			break;
199 		case IEC958_AES0_PRO_EMPHASIS_NOTID:
200 		default:
201 			snd_iprintf(buffer, "unknown\n");
202 			break;
203 		}
204 		snd_iprintf(buffer, "Stereophonic: ");
205 		if ((status[1] & IEC958_AES1_PRO_MODE) == IEC958_AES1_PRO_MODE_STEREOPHONIC) {
206 			snd_iprintf(buffer, "stereo\n");
207 		} else {
208 			snd_iprintf(buffer, "not indicated\n");
209 		}
210 		snd_iprintf(buffer, "Userbits: ");
211 		switch (status[1] & IEC958_AES1_PRO_USERBITS) {
212 		case IEC958_AES1_PRO_USERBITS_192:
213 			snd_iprintf(buffer, "192bit\n");
214 			break;
215 		case IEC958_AES1_PRO_USERBITS_UDEF:
216 			snd_iprintf(buffer, "user-defined\n");
217 			break;
218 		default:
219 			snd_iprintf(buffer, "unknown\n");
220 			break;
221 		}
222 		snd_iprintf(buffer, "Sample Bits: ");
223 		switch (status[2] & IEC958_AES2_PRO_SBITS) {
224 		case IEC958_AES2_PRO_SBITS_20:
225 			snd_iprintf(buffer, "20 bit\n");
226 			break;
227 		case IEC958_AES2_PRO_SBITS_24:
228 			snd_iprintf(buffer, "24 bit\n");
229 			break;
230 		case IEC958_AES2_PRO_SBITS_UDEF:
231 			snd_iprintf(buffer, "user defined\n");
232 			break;
233 		default:
234 			snd_iprintf(buffer, "unknown\n");
235 			break;
236 		}
237 		snd_iprintf(buffer, "Word Length: ");
238 		switch (status[2] & IEC958_AES2_PRO_WORDLEN) {
239 		case IEC958_AES2_PRO_WORDLEN_22_18:
240 			snd_iprintf(buffer, "22 bit or 18 bit\n");
241 			break;
242 		case IEC958_AES2_PRO_WORDLEN_23_19:
243 			snd_iprintf(buffer, "23 bit or 19 bit\n");
244 			break;
245 		case IEC958_AES2_PRO_WORDLEN_24_20:
246 			snd_iprintf(buffer, "24 bit or 20 bit\n");
247 			break;
248 		case IEC958_AES2_PRO_WORDLEN_20_16:
249 			snd_iprintf(buffer, "20 bit or 16 bit\n");
250 			break;
251 		default:
252 			snd_iprintf(buffer, "unknown\n");
253 			break;
254 		}
255 	}
256 }
257 
258 static void snd_ca0106_proc_iec958(struct snd_info_entry *entry,
259 				       struct snd_info_buffer *buffer)
260 {
261 	struct snd_ca0106 *emu = entry->private_data;
262 	u32 value;
263 
264         value = snd_ca0106_ptr_read(emu, SAMPLE_RATE_TRACKER_STATUS, 0);
265 	snd_iprintf(buffer, "Status: %s, %s, %s\n",
266 		  (value & 0x100000) ? "Rate Locked" : "Not Rate Locked",
267 		  (value & 0x200000) ? "SPDIF Locked" : "No SPDIF Lock",
268 		  (value & 0x400000) ? "Audio Valid" : "No valid audio" );
269 	snd_iprintf(buffer, "Estimated sample rate: %u\n",
270 		  ((value & 0xfffff) * 48000) / 0x8000 );
271 	if (value & 0x200000) {
272 		snd_iprintf(buffer, "IEC958/SPDIF input status:\n");
273         	value = snd_ca0106_ptr_read(emu, SPDIF_INPUT_STATUS, 0);
274 		snd_ca0106_proc_dump_iec958(buffer, value);
275 	}
276 
277 	snd_iprintf(buffer, "\n");
278 }
279 
280 static void snd_ca0106_proc_reg_write32(struct snd_info_entry *entry,
281 				       struct snd_info_buffer *buffer)
282 {
283 	struct snd_ca0106 *emu = entry->private_data;
284 	unsigned long flags;
285         char line[64];
286         u32 reg, val;
287         while (!snd_info_get_line(buffer, line, sizeof(line))) {
288                 if (sscanf(line, "%x %x", &reg, &val) != 2)
289                         continue;
290 		if (reg < 0x40 && val <= 0xffffffff) {
291 			spin_lock_irqsave(&emu->emu_lock, flags);
292 			outl(val, emu->port + (reg & 0xfffffffc));
293 			spin_unlock_irqrestore(&emu->emu_lock, flags);
294 		}
295         }
296 }
297 
298 static void snd_ca0106_proc_reg_read32(struct snd_info_entry *entry,
299 				       struct snd_info_buffer *buffer)
300 {
301 	struct snd_ca0106 *emu = entry->private_data;
302 	unsigned long value;
303 	unsigned long flags;
304 	int i;
305 	snd_iprintf(buffer, "Registers:\n\n");
306 	for(i = 0; i < 0x20; i+=4) {
307 		spin_lock_irqsave(&emu->emu_lock, flags);
308 		value = inl(emu->port + i);
309 		spin_unlock_irqrestore(&emu->emu_lock, flags);
310 		snd_iprintf(buffer, "Register %02X: %08lX\n", i, value);
311 	}
312 }
313 
314 static void snd_ca0106_proc_reg_read16(struct snd_info_entry *entry,
315 				       struct snd_info_buffer *buffer)
316 {
317 	struct snd_ca0106 *emu = entry->private_data;
318         unsigned int value;
319 	unsigned long flags;
320 	int i;
321 	snd_iprintf(buffer, "Registers:\n\n");
322 	for(i = 0; i < 0x20; i+=2) {
323 		spin_lock_irqsave(&emu->emu_lock, flags);
324 		value = inw(emu->port + i);
325 		spin_unlock_irqrestore(&emu->emu_lock, flags);
326 		snd_iprintf(buffer, "Register %02X: %04X\n", i, value);
327 	}
328 }
329 
330 static void snd_ca0106_proc_reg_read8(struct snd_info_entry *entry,
331 				       struct snd_info_buffer *buffer)
332 {
333 	struct snd_ca0106 *emu = entry->private_data;
334 	unsigned int value;
335 	unsigned long flags;
336 	int i;
337 	snd_iprintf(buffer, "Registers:\n\n");
338 	for(i = 0; i < 0x20; i+=1) {
339 		spin_lock_irqsave(&emu->emu_lock, flags);
340 		value = inb(emu->port + i);
341 		spin_unlock_irqrestore(&emu->emu_lock, flags);
342 		snd_iprintf(buffer, "Register %02X: %02X\n", i, value);
343 	}
344 }
345 
346 static void snd_ca0106_proc_reg_read1(struct snd_info_entry *entry,
347 				       struct snd_info_buffer *buffer)
348 {
349 	struct snd_ca0106 *emu = entry->private_data;
350 	unsigned long value;
351 	int i,j;
352 
353 	snd_iprintf(buffer, "Registers\n");
354 	for(i = 0; i < 0x40; i++) {
355 		snd_iprintf(buffer, "%02X: ",i);
356 		for (j = 0; j < 4; j++) {
357                   value = snd_ca0106_ptr_read(emu, i, j);
358 		  snd_iprintf(buffer, "%08lX ", value);
359                 }
360 	        snd_iprintf(buffer, "\n");
361 	}
362 }
363 
364 static void snd_ca0106_proc_reg_read2(struct snd_info_entry *entry,
365 				       struct snd_info_buffer *buffer)
366 {
367 	struct snd_ca0106 *emu = entry->private_data;
368 	unsigned long value;
369 	int i,j;
370 
371 	snd_iprintf(buffer, "Registers\n");
372 	for(i = 0x40; i < 0x80; i++) {
373 		snd_iprintf(buffer, "%02X: ",i);
374 		for (j = 0; j < 4; j++) {
375                   value = snd_ca0106_ptr_read(emu, i, j);
376 		  snd_iprintf(buffer, "%08lX ", value);
377                 }
378 	        snd_iprintf(buffer, "\n");
379 	}
380 }
381 
382 static void snd_ca0106_proc_reg_write(struct snd_info_entry *entry,
383 				       struct snd_info_buffer *buffer)
384 {
385 	struct snd_ca0106 *emu = entry->private_data;
386         char line[64];
387         unsigned int reg, channel_id , val;
388         while (!snd_info_get_line(buffer, line, sizeof(line))) {
389                 if (sscanf(line, "%x %x %x", &reg, &channel_id, &val) != 3)
390                         continue;
391 		if (reg < 0x80 && val <= 0xffffffff && channel_id <= 3)
392                         snd_ca0106_ptr_write(emu, reg, channel_id, val);
393         }
394 }
395 
396 static void snd_ca0106_proc_i2c_write(struct snd_info_entry *entry,
397 				       struct snd_info_buffer *buffer)
398 {
399 	struct snd_ca0106 *emu = entry->private_data;
400         char line[64];
401         unsigned int reg, val;
402         while (!snd_info_get_line(buffer, line, sizeof(line))) {
403                 if (sscanf(line, "%x %x", &reg, &val) != 2)
404                         continue;
405                 if ((reg <= 0x7f) || (val <= 0x1ff)) {
406                         snd_ca0106_i2c_write(emu, reg, val);
407 		}
408         }
409 }
410 
411 int snd_ca0106_proc_init(struct snd_ca0106 *emu)
412 {
413 	snd_card_ro_proc_new(emu->card, "iec958", emu, snd_ca0106_proc_iec958);
414 	snd_card_rw_proc_new(emu->card, "ca0106_reg32", emu,
415 			     snd_ca0106_proc_reg_read32,
416 			     snd_ca0106_proc_reg_write32);
417 	snd_card_ro_proc_new(emu->card, "ca0106_reg16", emu,
418 			     snd_ca0106_proc_reg_read16);
419 	snd_card_ro_proc_new(emu->card, "ca0106_reg8", emu,
420 			     snd_ca0106_proc_reg_read8);
421 	snd_card_rw_proc_new(emu->card, "ca0106_regs1", emu,
422 			     snd_ca0106_proc_reg_read1,
423 			     snd_ca0106_proc_reg_write);
424 	snd_card_rw_proc_new(emu->card, "ca0106_i2c", emu, NULL,
425 			     snd_ca0106_proc_i2c_write);
426 	snd_card_ro_proc_new(emu->card, "ca0106_regs2", emu,
427 			     snd_ca0106_proc_reg_read2);
428 	return 0;
429 }
430