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