diff options
author | Clément Guedez <klem.dev@gmail.com> | 2015-03-17 21:26:31 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2015-03-18 03:07:00 -0400 |
commit | 1aa9a4ea4fea5e4afe8be0229774b8f98db2e6c3 (patch) | |
tree | 18d78a7c77cd270ad70699bba7a3619f6ae28e7c /sound/pci | |
parent | ae8a9a11256a0906831a7db39b8cbcdec51ae28a (diff) |
ALSA: ice1724: ESI W192M: Add sampling rate control of the ADC/DAC
Add sampling rate control for ADC/DAC for ESI W192M.
Allow to switch between 48K/96K/192K sampling rate.
All DAC need to be mute when changing samplerate.
Signed-off-by: Clément Guedez <klem.dev@gmail.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r-- | sound/pci/ice1712/wtm.c | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/sound/pci/ice1712/wtm.c b/sound/pci/ice1712/wtm.c index 6d3412f72855..9906119e0954 100644 --- a/sound/pci/ice1712/wtm.c +++ b/sound/pci/ice1712/wtm.c | |||
@@ -30,12 +30,18 @@ | |||
30 | #include <linux/init.h> | 30 | #include <linux/init.h> |
31 | #include <sound/core.h> | 31 | #include <sound/core.h> |
32 | #include <sound/tlv.h> | 32 | #include <sound/tlv.h> |
33 | #include <linux/slab.h> | ||
33 | 34 | ||
34 | #include "ice1712.h" | 35 | #include "ice1712.h" |
35 | #include "envy24ht.h" | 36 | #include "envy24ht.h" |
36 | #include "wtm.h" | 37 | #include "wtm.h" |
37 | #include "stac946x.h" | 38 | #include "stac946x.h" |
38 | 39 | ||
40 | struct wtm_spec { | ||
41 | /* rate change needs atomic mute/unmute of all dacs*/ | ||
42 | struct mutex mute_mutex; | ||
43 | }; | ||
44 | |||
39 | 45 | ||
40 | /* | 46 | /* |
41 | * 2*ADC 6*DAC no1 ringbuffer r/w on i2c bus | 47 | * 2*ADC 6*DAC no1 ringbuffer r/w on i2c bus |
@@ -69,15 +75,65 @@ static inline unsigned char stac9460_2_get(struct snd_ice1712 *ice, int reg) | |||
69 | /* | 75 | /* |
70 | * DAC mute control | 76 | * DAC mute control |
71 | */ | 77 | */ |
78 | static void stac9460_dac_mute_all(struct snd_ice1712 *ice, unsigned char mute, | ||
79 | unsigned short int *change_mask) | ||
80 | { | ||
81 | unsigned char new, old; | ||
82 | int id, idx, change; | ||
83 | |||
84 | /*stac9460 1*/ | ||
85 | for (id = 0; id < 7; id++) { | ||
86 | if (*change_mask & (0x01 << id)) { | ||
87 | if (id == 0) | ||
88 | idx = STAC946X_MASTER_VOLUME; | ||
89 | else | ||
90 | idx = STAC946X_LF_VOLUME - 1 + id; | ||
91 | old = stac9460_get(ice, idx); | ||
92 | new = (~mute << 7 & 0x80) | (old & ~0x80); | ||
93 | change = (new != old); | ||
94 | if (change) { | ||
95 | stac9460_put(ice, idx, new); | ||
96 | *change_mask = *change_mask | (0x01 << id); | ||
97 | } else { | ||
98 | *change_mask = *change_mask & ~(0x01 << id); | ||
99 | } | ||
100 | } | ||
101 | } | ||
102 | |||
103 | /*stac9460 2*/ | ||
104 | for (id = 0; id < 3; id++) { | ||
105 | if (*change_mask & (0x01 << (id + 7))) { | ||
106 | if (id == 0) | ||
107 | idx = STAC946X_MASTER_VOLUME; | ||
108 | else | ||
109 | idx = STAC946X_LF_VOLUME - 1 + id; | ||
110 | old = stac9460_2_get(ice, idx); | ||
111 | new = (~mute << 7 & 0x80) | (old & ~0x80); | ||
112 | change = (new != old); | ||
113 | if (change) { | ||
114 | stac9460_2_put(ice, idx, new); | ||
115 | *change_mask = *change_mask | (0x01 << id); | ||
116 | } else { | ||
117 | *change_mask = *change_mask & ~(0x01 << id); | ||
118 | } | ||
119 | } | ||
120 | } | ||
121 | } | ||
122 | |||
123 | |||
124 | |||
72 | #define stac9460_dac_mute_info snd_ctl_boolean_mono_info | 125 | #define stac9460_dac_mute_info snd_ctl_boolean_mono_info |
73 | 126 | ||
74 | static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, | 127 | static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, |
75 | struct snd_ctl_elem_value *ucontrol) | 128 | struct snd_ctl_elem_value *ucontrol) |
76 | { | 129 | { |
77 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 130 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
131 | struct wtm_spec *spec = ice->spec; | ||
78 | unsigned char val; | 132 | unsigned char val; |
79 | int idx, id; | 133 | int idx, id; |
80 | 134 | ||
135 | mutex_lock(&spec->mute_mutex); | ||
136 | |||
81 | if (kcontrol->private_value) { | 137 | if (kcontrol->private_value) { |
82 | idx = STAC946X_MASTER_VOLUME; | 138 | idx = STAC946X_MASTER_VOLUME; |
83 | id = 0; | 139 | id = 0; |
@@ -90,6 +146,8 @@ static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, | |||
90 | else | 146 | else |
91 | val = stac9460_2_get(ice, idx - 6); | 147 | val = stac9460_2_get(ice, idx - 6); |
92 | ucontrol->value.integer.value[0] = (~val >> 7) & 0x1; | 148 | ucontrol->value.integer.value[0] = (~val >> 7) & 0x1; |
149 | |||
150 | mutex_unlock(&spec->mute_mutex); | ||
93 | return 0; | 151 | return 0; |
94 | } | 152 | } |
95 | 153 | ||
@@ -388,6 +446,44 @@ static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol, | |||
388 | } | 446 | } |
389 | 447 | ||
390 | 448 | ||
449 | /* | ||
450 | * Handler for setting correct codec rate - called when rate change is detected | ||
451 | */ | ||
452 | static void stac9460_set_rate_val(struct snd_ice1712 *ice, unsigned int rate) | ||
453 | { | ||
454 | unsigned char old, new; | ||
455 | unsigned short int changed; | ||
456 | struct wtm_spec *spec = ice->spec; | ||
457 | |||
458 | if (rate == 0) /* no hint - S/PDIF input is master, simply return */ | ||
459 | return; | ||
460 | else if (rate <= 48000) | ||
461 | new = 0x08; /* 256x, base rate mode */ | ||
462 | else if (rate <= 96000) | ||
463 | new = 0x11; /* 256x, mid rate mode */ | ||
464 | else | ||
465 | new = 0x12; /* 128x, high rate mode */ | ||
466 | |||
467 | old = stac9460_get(ice, STAC946X_MASTER_CLOCKING); | ||
468 | if (old == new) | ||
469 | return; | ||
470 | /* change detected, setting master clock, muting first */ | ||
471 | /* due to possible conflicts with mute controls - mutexing */ | ||
472 | mutex_lock(&spec->mute_mutex); | ||
473 | /* we have to remember current mute status for each DAC */ | ||
474 | changed = 0xFFFF; | ||
475 | stac9460_dac_mute_all(ice, 0, &changed); | ||
476 | /*printk(KERN_DEBUG "Rate change: %d, new MC: 0x%02x\n", rate, new);*/ | ||
477 | stac9460_put(ice, STAC946X_MASTER_CLOCKING, new); | ||
478 | stac9460_2_put(ice, STAC946X_MASTER_CLOCKING, new); | ||
479 | udelay(10); | ||
480 | /* unmuting - only originally unmuted dacs - | ||
481 | * i.e. those changed when muting */ | ||
482 | stac9460_dac_mute_all(ice, 1, &changed); | ||
483 | mutex_unlock(&spec->mute_mutex); | ||
484 | } | ||
485 | |||
486 | |||
391 | /*Limits value in dB for fader*/ | 487 | /*Limits value in dB for fader*/ |
392 | static const DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0); | 488 | static const DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0); |
393 | static const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0); | 489 | static const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0); |
@@ -487,21 +583,32 @@ static int wtm_init(struct snd_ice1712 *ice) | |||
487 | { | 583 | { |
488 | static unsigned short stac_inits_wtm[] = { | 584 | static unsigned short stac_inits_wtm[] = { |
489 | STAC946X_RESET, 0, | 585 | STAC946X_RESET, 0, |
586 | STAC946X_MASTER_CLOCKING, 0x11, | ||
490 | (unsigned short)-1 | 587 | (unsigned short)-1 |
491 | }; | 588 | }; |
492 | unsigned short *p; | 589 | unsigned short *p; |
590 | struct wtm_spec *spec; | ||
493 | 591 | ||
494 | /*WTM 192M*/ | 592 | /*WTM 192M*/ |
495 | ice->num_total_dacs = 8; | 593 | ice->num_total_dacs = 8; |
496 | ice->num_total_adcs = 4; | 594 | ice->num_total_adcs = 4; |
497 | ice->force_rdma1 = 1; | 595 | ice->force_rdma1 = 1; |
498 | 596 | ||
597 | /*init mutex for dac mute conflict*/ | ||
598 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
599 | if (!spec) | ||
600 | return -ENOMEM; | ||
601 | ice->spec = spec; | ||
602 | mutex_init(&spec->mute_mutex); | ||
603 | |||
604 | |||
499 | /*initialize codec*/ | 605 | /*initialize codec*/ |
500 | p = stac_inits_wtm; | 606 | p = stac_inits_wtm; |
501 | for (; *p != (unsigned short)-1; p += 2) { | 607 | for (; *p != (unsigned short)-1; p += 2) { |
502 | stac9460_put(ice, p[0], p[1]); | 608 | stac9460_put(ice, p[0], p[1]); |
503 | stac9460_2_put(ice, p[0], p[1]); | 609 | stac9460_2_put(ice, p[0], p[1]); |
504 | } | 610 | } |
611 | ice->gpio.set_pro_rate = stac9460_set_rate_val; | ||
505 | return 0; | 612 | return 0; |
506 | } | 613 | } |
507 | 614 | ||