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