1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include <linux/delay.h>
24#include <linux/io.h>
25#include <sound/core.h>
26#include <sound/control.h>
27#include <sound/tlv.h>
28#include <sound/asoundef.h>
29#include "pcxhr.h"
30#include "pcxhr_core.h"
31#include "pcxhr_mix22.h"
32
33
34
35#define PCXHR_DSP_RESET 0x20
36#define PCXHR_XLX_CFG 0x24
37#define PCXHR_XLX_RUER 0x28
38#define PCXHR_XLX_DATA 0x2C
39#define PCXHR_XLX_STATUS 0x30
40#define PCXHR_XLX_LOFREQ 0x34
41#define PCXHR_XLX_HIFREQ 0x38
42#define PCXHR_XLX_CSUER 0x3C
43#define PCXHR_XLX_SELMIC 0x40
44
45#define PCXHR_DSP 2
46
47
48#define PCXHR_INPB(mgr, x) inb((mgr)->port[PCXHR_DSP] + (x))
49#define PCXHR_OUTPB(mgr, x, data) outb((data), (mgr)->port[PCXHR_DSP] + (x))
50
51
52
53#define PCXHR_DSP_RESET_DSP 0x01
54#define PCXHR_DSP_RESET_MUTE 0x02
55#define PCXHR_DSP_RESET_CODEC 0x08
56#define PCXHR_DSP_RESET_SMPTE 0x10
57#define PCXHR_DSP_RESET_GPO_OFFSET 5
58#define PCXHR_DSP_RESET_GPO_MASK 0x60
59
60
61#define PCXHR_CFG_SYNCDSP_MASK 0x80
62#define PCXHR_CFG_DEPENDENCY_MASK 0x60
63#define PCXHR_CFG_INDEPENDANT_SEL 0x00
64#define PCXHR_CFG_MASTER_SEL 0x40
65#define PCXHR_CFG_SLAVE_SEL 0x20
66#define PCXHR_CFG_DATA_UER1_SEL_MASK 0x10
67#define PCXHR_CFG_DATAIN_SEL_MASK 0x08
68#define PCXHR_CFG_SRC_MASK 0x04
69#define PCXHR_CFG_CLOCK_UER1_SEL_MASK 0x02
70#define PCXHR_CFG_CLOCKIN_SEL_MASK 0x01
71
72
73#define PCXHR_DATA_CODEC 0x80
74#define AKM_POWER_CONTROL_CMD 0xA007
75#define AKM_RESET_ON_CMD 0xA100
76#define AKM_RESET_OFF_CMD 0xA103
77#define AKM_CLOCK_INF_55K_CMD 0xA240
78#define AKM_CLOCK_SUP_55K_CMD 0xA24D
79#define AKM_MUTE_CMD 0xA38D
80#define AKM_UNMUTE_CMD 0xA30D
81#define AKM_LEFT_LEVEL_CMD 0xA600
82#define AKM_RIGHT_LEVEL_CMD 0xA700
83
84
85#define PCXHR_STAT_SRC_LOCK 0x01
86#define PCXHR_STAT_LEVEL_IN 0x02
87#define PCXHR_STAT_GPI_OFFSET 2
88#define PCXHR_STAT_GPI_MASK 0x0C
89#define PCXHR_STAT_MIC_CAPS 0x10
90
91#define PCXHR_STAT_FREQ_SYNC_MASK 0x01
92#define PCXHR_STAT_FREQ_UER1_MASK 0x02
93#define PCXHR_STAT_FREQ_SAVE_MASK 0x80
94
95
96#define PCXHR_SUER1_BIT_U_READ_MASK 0x80
97#define PCXHR_SUER1_BIT_C_READ_MASK 0x40
98#define PCXHR_SUER1_DATA_PRESENT_MASK 0x20
99#define PCXHR_SUER1_CLOCK_PRESENT_MASK 0x10
100#define PCXHR_SUER_BIT_U_READ_MASK 0x08
101#define PCXHR_SUER_BIT_C_READ_MASK 0x04
102#define PCXHR_SUER_DATA_PRESENT_MASK 0x02
103#define PCXHR_SUER_CLOCK_PRESENT_MASK 0x01
104
105#define PCXHR_SUER_BIT_U_WRITE_MASK 0x02
106#define PCXHR_SUER_BIT_C_WRITE_MASK 0x01
107
108
109#define PCXHR_SELMIC_PREAMPLI_OFFSET 2
110#define PCXHR_SELMIC_PREAMPLI_MASK 0x0C
111#define PCXHR_SELMIC_PHANTOM_ALIM 0x80
112
113
114static const unsigned char g_hr222_p_level[] = {
115 0x00,
116 0x01,
117 0x01,
118 0x01,
119 0x01,
120 0x01,
121 0x01,
122 0x01,
123 0x01,
124 0x02,
125 0x02,
126 0x02,
127 0x02,
128 0x02,
129 0x02,
130 0x02,
131 0x02,
132 0x02,
133 0x02,
134 0x03,
135 0x03,
136 0x03,
137 0x03,
138 0x03,
139 0x03,
140 0x04,
141 0x04,
142 0x04,
143 0x04,
144 0x05,
145 0x05,
146 0x05,
147 0x05,
148 0x06,
149 0x06,
150 0x06,
151 0x07,
152 0x07,
153 0x08,
154 0x08,
155 0x09,
156 0x09,
157 0x0a,
158 0x0a,
159 0x0b,
160 0x0b,
161 0x0c,
162 0x0d,
163 0x0e,
164 0x0e,
165 0x0f,
166 0x10,
167 0x11,
168 0x12,
169 0x13,
170 0x14,
171 0x15,
172 0x17,
173 0x18,
174 0x1a,
175 0x1b,
176 0x1d,
177 0x1e,
178 0x20,
179 0x22,
180 0x24,
181 0x26,
182 0x28,
183 0x2b,
184 0x2d,
185 0x30,
186 0x33,
187 0x36,
188 0x39,
189 0x3c,
190 0x40,
191 0x44,
192 0x48,
193 0x4c,
194 0x51,
195 0x55,
196 0x5a,
197 0x60,
198 0x66,
199 0x6c,
200 0x72,
201 0x79,
202 0x80,
203 0x87,
204 0x8f,
205 0x98,
206 0xa1,
207 0xaa,
208 0xb5,
209 0xbf,
210 0xcb,
211 0xd7,
212 0xe3,
213 0xf1,
214 0xff,
215};
216
217
218static void hr222_config_akm(struct pcxhr_mgr *mgr, unsigned short data)
219{
220 unsigned short mask = 0x8000;
221
222 PCXHR_INPB(mgr, PCXHR_XLX_HIFREQ);
223
224 while (mask) {
225 PCXHR_OUTPB(mgr, PCXHR_XLX_DATA,
226 data & mask ? PCXHR_DATA_CODEC : 0);
227 mask >>= 1;
228 }
229
230 PCXHR_INPB(mgr, PCXHR_XLX_RUER);
231}
232
233
234static int hr222_set_hw_playback_level(struct pcxhr_mgr *mgr,
235 int idx, int level)
236{
237 unsigned short cmd;
238 if (idx > 1 ||
239 level < 0 ||
240 level >= ARRAY_SIZE(g_hr222_p_level))
241 return -EINVAL;
242
243 if (idx == 0)
244 cmd = AKM_LEFT_LEVEL_CMD;
245 else
246 cmd = AKM_RIGHT_LEVEL_CMD;
247
248
249 cmd += g_hr222_p_level[level];
250
251 hr222_config_akm(mgr, cmd);
252 return 0;
253}
254
255
256static int hr222_set_hw_capture_level(struct pcxhr_mgr *mgr,
257 int level_l, int level_r, int level_mic)
258{
259
260 unsigned int data;
261 int i;
262
263 if (!mgr->capture_chips)
264 return -EINVAL;
265
266 data = ((level_mic & 0xff) << 24);
267 data |= ((level_mic & 0xff) << 16);
268 data |= ((level_r & 0xff) << 8);
269 data |= (level_l & 0xff);
270
271 PCXHR_INPB(mgr, PCXHR_XLX_DATA);
272
273 for (i = 0; i < 32; i++, data <<= 1) {
274 PCXHR_OUTPB(mgr, PCXHR_XLX_DATA,
275 (data & 0x80000000) ? PCXHR_DATA_CODEC : 0);
276 }
277 PCXHR_INPB(mgr, PCXHR_XLX_RUER);
278 return 0;
279}
280
281static void hr222_micro_boost(struct pcxhr_mgr *mgr, int level);
282
283int hr222_sub_init(struct pcxhr_mgr *mgr)
284{
285 unsigned char reg;
286
287 mgr->board_has_analog = 1;
288 mgr->xlx_cfg = PCXHR_CFG_SYNCDSP_MASK;
289
290 reg = PCXHR_INPB(mgr, PCXHR_XLX_STATUS);
291 if (reg & PCXHR_STAT_MIC_CAPS)
292 mgr->board_has_mic = 1;
293 snd_printdd("MIC input available = %d\n", mgr->board_has_mic);
294
295
296 PCXHR_OUTPB(mgr, PCXHR_DSP_RESET,
297 PCXHR_DSP_RESET_DSP);
298 msleep(5);
299 mgr->dsp_reset = PCXHR_DSP_RESET_DSP |
300 PCXHR_DSP_RESET_MUTE |
301 PCXHR_DSP_RESET_CODEC;
302 PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, mgr->dsp_reset);
303
304 msleep(5);
305
306
307 hr222_config_akm(mgr, AKM_POWER_CONTROL_CMD);
308 hr222_config_akm(mgr, AKM_CLOCK_INF_55K_CMD);
309 hr222_config_akm(mgr, AKM_UNMUTE_CMD);
310 hr222_config_akm(mgr, AKM_RESET_OFF_CMD);
311
312
313 hr222_micro_boost(mgr, 0);
314
315 return 0;
316}
317
318
319
320
321static int hr222_pll_freq_register(unsigned int freq,
322 unsigned int *pllreg,
323 unsigned int *realfreq)
324{
325 unsigned int reg;
326
327 if (freq < 6900 || freq > 219000)
328 return -EINVAL;
329 reg = (28224000 * 2) / freq;
330 reg = (reg - 1) / 2;
331 if (reg < 0x100)
332 *pllreg = reg + 0xC00;
333 else if (reg < 0x200)
334 *pllreg = reg + 0x800;
335 else if (reg < 0x400)
336 *pllreg = reg & 0x1ff;
337 else if (reg < 0x800) {
338 *pllreg = ((reg >> 1) & 0x1ff) + 0x200;
339 reg &= ~1;
340 } else {
341 *pllreg = ((reg >> 2) & 0x1ff) + 0x400;
342 reg &= ~3;
343 }
344 if (realfreq)
345 *realfreq = (28224000 / (reg + 1));
346 return 0;
347}
348
349int hr222_sub_set_clock(struct pcxhr_mgr *mgr,
350 unsigned int rate,
351 int *changed)
352{
353 unsigned int speed, pllreg = 0;
354 int err;
355 unsigned realfreq = rate;
356
357 switch (mgr->use_clock_type) {
358 case HR22_CLOCK_TYPE_INTERNAL:
359 err = hr222_pll_freq_register(rate, &pllreg, &realfreq);
360 if (err)
361 return err;
362
363 mgr->xlx_cfg &= ~(PCXHR_CFG_CLOCKIN_SEL_MASK |
364 PCXHR_CFG_CLOCK_UER1_SEL_MASK);
365 break;
366 case HR22_CLOCK_TYPE_AES_SYNC:
367 mgr->xlx_cfg |= PCXHR_CFG_CLOCKIN_SEL_MASK;
368 mgr->xlx_cfg &= ~PCXHR_CFG_CLOCK_UER1_SEL_MASK;
369 break;
370 case HR22_CLOCK_TYPE_AES_1:
371 if (!mgr->board_has_aes1)
372 return -EINVAL;
373
374 mgr->xlx_cfg |= (PCXHR_CFG_CLOCKIN_SEL_MASK |
375 PCXHR_CFG_CLOCK_UER1_SEL_MASK);
376 break;
377 default:
378 return -EINVAL;
379 }
380 hr222_config_akm(mgr, AKM_MUTE_CMD);
381
382 if (mgr->use_clock_type == HR22_CLOCK_TYPE_INTERNAL) {
383 PCXHR_OUTPB(mgr, PCXHR_XLX_HIFREQ, pllreg >> 8);
384 PCXHR_OUTPB(mgr, PCXHR_XLX_LOFREQ, pllreg & 0xff);
385 }
386
387
388 PCXHR_OUTPB(mgr, PCXHR_XLX_CFG, mgr->xlx_cfg);
389
390
391 speed = rate < 55000 ? 0 : 1;
392 if (mgr->codec_speed != speed) {
393 mgr->codec_speed = speed;
394 if (speed == 0)
395 hr222_config_akm(mgr, AKM_CLOCK_INF_55K_CMD);
396 else
397 hr222_config_akm(mgr, AKM_CLOCK_SUP_55K_CMD);
398 }
399
400 mgr->sample_rate_real = realfreq;
401 mgr->cur_clock_type = mgr->use_clock_type;
402
403 if (changed)
404 *changed = 1;
405
406 hr222_config_akm(mgr, AKM_UNMUTE_CMD);
407
408 snd_printdd("set_clock to %dHz (realfreq=%d pllreg=%x)\n",
409 rate, realfreq, pllreg);
410 return 0;
411}
412
413int hr222_get_external_clock(struct pcxhr_mgr *mgr,
414 enum pcxhr_clock_type clock_type,
415 int *sample_rate)
416{
417 int rate, calc_rate = 0;
418 unsigned int ticks;
419 unsigned char mask, reg;
420
421 if (clock_type == HR22_CLOCK_TYPE_AES_SYNC) {
422
423 mask = (PCXHR_SUER_CLOCK_PRESENT_MASK |
424 PCXHR_SUER_DATA_PRESENT_MASK);
425 reg = PCXHR_STAT_FREQ_SYNC_MASK;
426
427 } else if (clock_type == HR22_CLOCK_TYPE_AES_1 && mgr->board_has_aes1) {
428
429 mask = (PCXHR_SUER1_CLOCK_PRESENT_MASK |
430 PCXHR_SUER1_DATA_PRESENT_MASK);
431 reg = PCXHR_STAT_FREQ_UER1_MASK;
432
433 } else {
434 snd_printdd("get_external_clock : type %d not supported\n",
435 clock_type);
436 return -EINVAL;
437 }
438
439 if ((PCXHR_INPB(mgr, PCXHR_XLX_CSUER) & mask) != mask) {
440 snd_printdd("get_external_clock(%d) = 0 Hz\n", clock_type);
441 *sample_rate = 0;
442 return 0;
443 }
444
445 PCXHR_OUTPB(mgr, PCXHR_XLX_STATUS, reg);
446
447
448 reg |= PCXHR_STAT_FREQ_SAVE_MASK;
449
450 if (mgr->last_reg_stat != reg) {
451 udelay(500);
452 mgr->last_reg_stat = reg;
453 }
454
455 PCXHR_OUTPB(mgr, PCXHR_XLX_STATUS, reg);
456
457
458 ticks = (unsigned int)PCXHR_INPB(mgr, PCXHR_XLX_CFG);
459 ticks = (ticks & 0x03) << 8;
460 ticks |= (unsigned int)PCXHR_INPB(mgr, PCXHR_DSP_RESET);
461
462 if (ticks != 0)
463 calc_rate = 28224000 / ticks;
464
465 if (calc_rate > 184200)
466 rate = 192000;
467 else if (calc_rate > 152200)
468 rate = 176400;
469 else if (calc_rate > 112000)
470 rate = 128000;
471 else if (calc_rate > 92100)
472 rate = 96000;
473 else if (calc_rate > 76100)
474 rate = 88200;
475 else if (calc_rate > 56000)
476 rate = 64000;
477 else if (calc_rate > 46050)
478 rate = 48000;
479 else if (calc_rate > 38050)
480 rate = 44100;
481 else if (calc_rate > 28000)
482 rate = 32000;
483 else if (calc_rate > 23025)
484 rate = 24000;
485 else if (calc_rate > 19025)
486 rate = 22050;
487 else if (calc_rate > 14000)
488 rate = 16000;
489 else if (calc_rate > 11512)
490 rate = 12000;
491 else if (calc_rate > 9512)
492 rate = 11025;
493 else if (calc_rate > 7000)
494 rate = 8000;
495 else
496 rate = 0;
497
498 snd_printdd("External clock is at %d Hz (measured %d Hz)\n",
499 rate, calc_rate);
500 *sample_rate = rate;
501 return 0;
502}
503
504
505int hr222_read_gpio(struct pcxhr_mgr *mgr, int is_gpi, int *value)
506{
507 if (is_gpi) {
508 unsigned char reg = PCXHR_INPB(mgr, PCXHR_XLX_STATUS);
509 *value = (int)(reg & PCXHR_STAT_GPI_MASK) >>
510 PCXHR_STAT_GPI_OFFSET;
511 } else {
512 *value = (int)(mgr->dsp_reset & PCXHR_DSP_RESET_GPO_MASK) >>
513 PCXHR_DSP_RESET_GPO_OFFSET;
514 }
515 return 0;
516}
517
518
519int hr222_write_gpo(struct pcxhr_mgr *mgr, int value)
520{
521 unsigned char reg = mgr->dsp_reset & ~PCXHR_DSP_RESET_GPO_MASK;
522
523 reg |= (unsigned char)(value << PCXHR_DSP_RESET_GPO_OFFSET) &
524 PCXHR_DSP_RESET_GPO_MASK;
525
526 PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, reg);
527 mgr->dsp_reset = reg;
528 return 0;
529}
530
531int hr222_manage_timecode(struct pcxhr_mgr *mgr, int enable)
532{
533 if (enable)
534 mgr->dsp_reset |= PCXHR_DSP_RESET_SMPTE;
535 else
536 mgr->dsp_reset &= ~PCXHR_DSP_RESET_SMPTE;
537
538 PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, mgr->dsp_reset);
539 return 0;
540}
541
542int hr222_update_analog_audio_level(struct snd_pcxhr *chip,
543 int is_capture, int channel)
544{
545 snd_printdd("hr222_update_analog_audio_level(%s chan=%d)\n",
546 is_capture ? "capture" : "playback", channel);
547 if (is_capture) {
548 int level_l, level_r, level_mic;
549
550 if (chip->analog_capture_active) {
551 level_l = chip->analog_capture_volume[0];
552 level_r = chip->analog_capture_volume[1];
553 } else {
554 level_l = HR222_LINE_CAPTURE_LEVEL_MIN;
555 level_r = HR222_LINE_CAPTURE_LEVEL_MIN;
556 }
557 if (chip->mic_active)
558 level_mic = chip->mic_volume;
559 else
560 level_mic = HR222_MICRO_CAPTURE_LEVEL_MIN;
561 return hr222_set_hw_capture_level(chip->mgr,
562 level_l, level_r, level_mic);
563 } else {
564 int vol;
565 if (chip->analog_playback_active[channel])
566 vol = chip->analog_playback_volume[channel];
567 else
568 vol = HR222_LINE_PLAYBACK_LEVEL_MIN;
569 return hr222_set_hw_playback_level(chip->mgr, channel, vol);
570 }
571}
572
573
574
575#define SOURCE_LINE 0
576#define SOURCE_DIGITAL 1
577#define SOURCE_DIGISRC 2
578#define SOURCE_MIC 3
579#define SOURCE_LINEMIC 4
580
581int hr222_set_audio_source(struct snd_pcxhr *chip)
582{
583 int digital = 0;
584
585 chip->mgr->xlx_cfg &= ~(PCXHR_CFG_SRC_MASK |
586 PCXHR_CFG_DATAIN_SEL_MASK |
587 PCXHR_CFG_DATA_UER1_SEL_MASK);
588
589 if (chip->audio_capture_source == SOURCE_DIGISRC) {
590 chip->mgr->xlx_cfg |= PCXHR_CFG_SRC_MASK;
591 digital = 1;
592 } else {
593 if (chip->audio_capture_source == SOURCE_DIGITAL)
594 digital = 1;
595 }
596 if (digital) {
597 chip->mgr->xlx_cfg |= PCXHR_CFG_DATAIN_SEL_MASK;
598 if (chip->mgr->board_has_aes1) {
599
600 chip->mgr->xlx_cfg |= PCXHR_CFG_DATA_UER1_SEL_MASK;
601 }
602
603
604 } else {
605 int update_lvl = 0;
606 chip->analog_capture_active = 0;
607 chip->mic_active = 0;
608 if (chip->audio_capture_source == SOURCE_LINE ||
609 chip->audio_capture_source == SOURCE_LINEMIC) {
610 if (chip->analog_capture_active == 0)
611 update_lvl = 1;
612 chip->analog_capture_active = 1;
613 }
614 if (chip->audio_capture_source == SOURCE_MIC ||
615 chip->audio_capture_source == SOURCE_LINEMIC) {
616 if (chip->mic_active == 0)
617 update_lvl = 1;
618 chip->mic_active = 1;
619 }
620 if (update_lvl) {
621
622 hr222_update_analog_audio_level(chip, 1, 0);
623 }
624 }
625
626 PCXHR_OUTPB(chip->mgr, PCXHR_XLX_CFG, chip->mgr->xlx_cfg);
627 return 0;
628}
629
630
631int hr222_iec958_capture_byte(struct snd_pcxhr *chip,
632 int aes_idx, unsigned char *aes_bits)
633{
634 unsigned char idx = (unsigned char)(aes_idx * 8);
635 unsigned char temp = 0;
636 unsigned char mask = chip->mgr->board_has_aes1 ?
637 PCXHR_SUER1_BIT_C_READ_MASK : PCXHR_SUER_BIT_C_READ_MASK;
638 int i;
639 for (i = 0; i < 8; i++) {
640 PCXHR_OUTPB(chip->mgr, PCXHR_XLX_RUER, idx++);
641 temp <<= 1;
642 if (PCXHR_INPB(chip->mgr, PCXHR_XLX_CSUER) & mask)
643 temp |= 1;
644 }
645 snd_printdd("read iec958 AES %d byte %d = 0x%x\n",
646 chip->chip_idx, aes_idx, temp);
647 *aes_bits = temp;
648 return 0;
649}
650
651
652int hr222_iec958_update_byte(struct snd_pcxhr *chip,
653 int aes_idx, unsigned char aes_bits)
654{
655 int i;
656 unsigned char new_bits = aes_bits;
657 unsigned char old_bits = chip->aes_bits[aes_idx];
658 unsigned char idx = (unsigned char)(aes_idx * 8);
659 for (i = 0; i < 8; i++) {
660 if ((old_bits & 0x01) != (new_bits & 0x01)) {
661
662 PCXHR_OUTPB(chip->mgr, PCXHR_XLX_RUER, idx);
663
664 PCXHR_OUTPB(chip->mgr, PCXHR_XLX_CSUER, new_bits&0x01 ?
665 PCXHR_SUER_BIT_C_WRITE_MASK : 0);
666 }
667 idx++;
668 old_bits >>= 1;
669 new_bits >>= 1;
670 }
671 chip->aes_bits[aes_idx] = aes_bits;
672 return 0;
673}
674
675static void hr222_micro_boost(struct pcxhr_mgr *mgr, int level)
676{
677 unsigned char boost_mask;
678 boost_mask = (unsigned char) (level << PCXHR_SELMIC_PREAMPLI_OFFSET);
679 if (boost_mask & (~PCXHR_SELMIC_PREAMPLI_MASK))
680 return;
681
682 mgr->xlx_selmic &= ~PCXHR_SELMIC_PREAMPLI_MASK;
683 mgr->xlx_selmic |= boost_mask;
684
685 PCXHR_OUTPB(mgr, PCXHR_XLX_SELMIC, mgr->xlx_selmic);
686
687 snd_printdd("hr222_micro_boost : set %x\n", boost_mask);
688}
689
690static void hr222_phantom_power(struct pcxhr_mgr *mgr, int power)
691{
692 if (power)
693 mgr->xlx_selmic |= PCXHR_SELMIC_PHANTOM_ALIM;
694 else
695 mgr->xlx_selmic &= ~PCXHR_SELMIC_PHANTOM_ALIM;
696
697 PCXHR_OUTPB(mgr, PCXHR_XLX_SELMIC, mgr->xlx_selmic);
698
699 snd_printdd("hr222_phantom_power : set %d\n", power);
700}
701
702
703
704static const DECLARE_TLV_DB_SCALE(db_scale_mic_hr222, -9850, 50, 650);
705
706static int hr222_mic_vol_info(struct snd_kcontrol *kcontrol,
707 struct snd_ctl_elem_info *uinfo)
708{
709 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
710 uinfo->count = 1;
711 uinfo->value.integer.min = HR222_MICRO_CAPTURE_LEVEL_MIN;
712
713 uinfo->value.integer.max = HR222_MICRO_CAPTURE_LEVEL_MAX;
714 return 0;
715}
716
717static int hr222_mic_vol_get(struct snd_kcontrol *kcontrol,
718 struct snd_ctl_elem_value *ucontrol)
719{
720 struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
721 mutex_lock(&chip->mgr->mixer_mutex);
722 ucontrol->value.integer.value[0] = chip->mic_volume;
723 mutex_unlock(&chip->mgr->mixer_mutex);
724 return 0;
725}
726
727static int hr222_mic_vol_put(struct snd_kcontrol *kcontrol,
728 struct snd_ctl_elem_value *ucontrol)
729{
730 struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
731 int changed = 0;
732 mutex_lock(&chip->mgr->mixer_mutex);
733 if (chip->mic_volume != ucontrol->value.integer.value[0]) {
734 changed = 1;
735 chip->mic_volume = ucontrol->value.integer.value[0];
736 hr222_update_analog_audio_level(chip, 1, 0);
737 }
738 mutex_unlock(&chip->mgr->mixer_mutex);
739 return changed;
740}
741
742static struct snd_kcontrol_new hr222_control_mic_level = {
743 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
744 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
745 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
746 .name = "Mic Capture Volume",
747 .info = hr222_mic_vol_info,
748 .get = hr222_mic_vol_get,
749 .put = hr222_mic_vol_put,
750 .tlv = { .p = db_scale_mic_hr222 },
751};
752
753
754
755static const DECLARE_TLV_DB_SCALE(db_scale_micboost_hr222, 0, 1800, 5400);
756
757static int hr222_mic_boost_info(struct snd_kcontrol *kcontrol,
758 struct snd_ctl_elem_info *uinfo)
759{
760 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
761 uinfo->count = 1;
762 uinfo->value.integer.min = 0;
763 uinfo->value.integer.max = 3;
764 return 0;
765}
766
767static int hr222_mic_boost_get(struct snd_kcontrol *kcontrol,
768 struct snd_ctl_elem_value *ucontrol)
769{
770 struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
771 mutex_lock(&chip->mgr->mixer_mutex);
772 ucontrol->value.integer.value[0] = chip->mic_boost;
773 mutex_unlock(&chip->mgr->mixer_mutex);
774 return 0;
775}
776
777static int hr222_mic_boost_put(struct snd_kcontrol *kcontrol,
778 struct snd_ctl_elem_value *ucontrol)
779{
780 struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
781 int changed = 0;
782 mutex_lock(&chip->mgr->mixer_mutex);
783 if (chip->mic_boost != ucontrol->value.integer.value[0]) {
784 changed = 1;
785 chip->mic_boost = ucontrol->value.integer.value[0];
786 hr222_micro_boost(chip->mgr, chip->mic_boost);
787 }
788 mutex_unlock(&chip->mgr->mixer_mutex);
789 return changed;
790}
791
792static struct snd_kcontrol_new hr222_control_mic_boost = {
793 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
794 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
795 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
796 .name = "MicBoost Capture Volume",
797 .info = hr222_mic_boost_info,
798 .get = hr222_mic_boost_get,
799 .put = hr222_mic_boost_put,
800 .tlv = { .p = db_scale_micboost_hr222 },
801};
802
803
804
805#define hr222_phantom_power_info snd_ctl_boolean_mono_info
806
807static int hr222_phantom_power_get(struct snd_kcontrol *kcontrol,
808 struct snd_ctl_elem_value *ucontrol)
809{
810 struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
811 mutex_lock(&chip->mgr->mixer_mutex);
812 ucontrol->value.integer.value[0] = chip->phantom_power;
813 mutex_unlock(&chip->mgr->mixer_mutex);
814 return 0;
815}
816
817static int hr222_phantom_power_put(struct snd_kcontrol *kcontrol,
818 struct snd_ctl_elem_value *ucontrol)
819{
820 struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
821 int power, changed = 0;
822
823 mutex_lock(&chip->mgr->mixer_mutex);
824 power = !!ucontrol->value.integer.value[0];
825 if (chip->phantom_power != power) {
826 hr222_phantom_power(chip->mgr, power);
827 chip->phantom_power = power;
828 changed = 1;
829 }
830 mutex_unlock(&chip->mgr->mixer_mutex);
831 return changed;
832}
833
834static struct snd_kcontrol_new hr222_phantom_power_switch = {
835 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
836 .name = "Phantom Power Switch",
837 .info = hr222_phantom_power_info,
838 .get = hr222_phantom_power_get,
839 .put = hr222_phantom_power_put,
840};
841
842
843int hr222_add_mic_controls(struct snd_pcxhr *chip)
844{
845 int err;
846 if (!chip->mgr->board_has_mic)
847 return 0;
848
849
850 err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_control_mic_level,
851 chip));
852 if (err < 0)
853 return err;
854
855 err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_control_mic_boost,
856 chip));
857 if (err < 0)
858 return err;
859
860 err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_phantom_power_switch,
861 chip));
862 return err;
863}
864