diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-15 15:41:41 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-15 15:41:41 -0700 |
commit | d0a3997c0c3f9351e24029349dee65dd1d9e8d84 (patch) | |
tree | 7a04fe282b0c7b329cd87cdb891f0f3879dc71a6 /sound/pci/ice1712/wtm.c | |
parent | 6d50ff91d9780263160262daeb6adfdda8ddbc6c (diff) | |
parent | d6eb9e3ec78c98324097bab8eea266c3bb0d0ac7 (diff) |
Merge tag 'sound-4.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai:
"There have been major modernization with the standard bus: in ALSA
sequencer core and HD-audio. Also, HD-audio receives the regmap
support replacing the in-house cache register cache code. These
changes shouldn't impact the existing behavior, but rather
refactoring.
In addition, HD-audio got the code split to a core library part and
the "legacy" driver parts. This is a preliminary work for adapting
the upcoming ASoC HD-audio driver, and the whole transition is still
work in progress, likely finished in 4.1.
Along with them, there are many updates in ASoC area as usual, too:
lots of cleanups, Intel code shuffling, etc.
Here are some highlights:
ALSA core:
- PCM: the audio timestamp / wallclock enhancement
- PCM: fixes in DPCM management
- Fixes / cleanups of user-space control element management
- Sequencer: modernization using the standard bus
HD-audio:
- Modernization using the standard bus
- Regmap support
- Use standard runtime PM for codec power saving
- Widget-path based power-saving for IDT, VIA and Realtek codecs
- Reorganized sysfs entries for each codec object
- More Dell headset support
ASoC:
- Move of jack registration to the card level
- Lots of ASoC cleanups, mainly moving things from the CODEC level to
the card level
- Support for DAPM routes specified by both the machine driver and DT
- Continuing improvements to rcar
- pcm512x enhacements
- Intel platforms updates
- rt5670 updates / fixes
- New platforms / devices: some non-DSP Qualcomm platforms, Google's
Storm platform, Maxmim MAX98925 CODECs and the Ingenic JZ4780 SoC
Misc:
- ice1724: Improved ESI W192M support
- emu10k1: Emu 1010 fixes/enhancement"
* tag 'sound-4.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (411 commits)
ALSA: hda - set GET bit when adding a vendor verb to the codec regmap
ALSA: hda/realtek - Enable the ALC292 dock fixup on the Thinkpad T450
ALSA: hda - Fix another race in runtime PM refcounting
ALSA: hda - Expose codec type sysfs
ALSA: ctl: fix to handle several elements added by one operation for userspace element
ASoC: Intel: fix array_size.cocci warnings
ASoC: n810: Automatically disconnect non-connected pins
ASoC: n810: Consistently pass the card DAPM context to n810_ext_control()
ASoC: davinci-evm: Use card DAPM context to access widgets
ASoC: mop500_ab8500: Use card DAPM context to access widgets
ASoC: wm1133-ev1: Use card DAPM context to access widgets
ASoC: atmel: Improve machine driver compile test coverage
ASoC: atmel: Add dependency to SND_SOC_I2C_AND_SPI where necessary
ALSA: control: Fix a typo of SNDRV_CTL_ELEM_ACCESS_TLV_* with SNDRV_CTL_TLV_OP_*
ALSA: usb-audio: Don't attempt to get Microsoft Lifecam Cinema sample rate
ASoC: rnsd: fix build regression without CONFIG_OF
ALSA: emu10k1: add toggles for E-mu 1010 optical ports
ALSA: ctl: fill identical information to return value when adding userspace elements
ALSA: ctl: fix a bug to return no identical information in info operation for userspace controls
ALSA: ctl: confirm to return all identical information in 'activate' event
...
Diffstat (limited to 'sound/pci/ice1712/wtm.c')
-rw-r--r-- | sound/pci/ice1712/wtm.c | 172 |
1 files changed, 151 insertions, 21 deletions
diff --git a/sound/pci/ice1712/wtm.c b/sound/pci/ice1712/wtm.c index bcf30a387b87..9906119e0954 100644 --- a/sound/pci/ice1712/wtm.c +++ b/sound/pci/ice1712/wtm.c @@ -29,12 +29,19 @@ #include <linux/interrupt.h> #include <linux/init.h> #include <sound/core.h> +#include <sound/tlv.h> +#include <linux/slab.h> #include "ice1712.h" #include "envy24ht.h" #include "wtm.h" #include "stac946x.h" +struct wtm_spec { + /* rate change needs atomic mute/unmute of all dacs*/ + struct mutex mute_mutex; +}; + /* * 2*ADC 6*DAC no1 ringbuffer r/w on i2c bus @@ -68,15 +75,65 @@ static inline unsigned char stac9460_2_get(struct snd_ice1712 *ice, int reg) /* * DAC mute control */ +static void stac9460_dac_mute_all(struct snd_ice1712 *ice, unsigned char mute, + unsigned short int *change_mask) +{ + unsigned char new, old; + int id, idx, change; + + /*stac9460 1*/ + for (id = 0; id < 7; id++) { + if (*change_mask & (0x01 << id)) { + if (id == 0) + idx = STAC946X_MASTER_VOLUME; + else + idx = STAC946X_LF_VOLUME - 1 + id; + old = stac9460_get(ice, idx); + new = (~mute << 7 & 0x80) | (old & ~0x80); + change = (new != old); + if (change) { + stac9460_put(ice, idx, new); + *change_mask = *change_mask | (0x01 << id); + } else { + *change_mask = *change_mask & ~(0x01 << id); + } + } + } + + /*stac9460 2*/ + for (id = 0; id < 3; id++) { + if (*change_mask & (0x01 << (id + 7))) { + if (id == 0) + idx = STAC946X_MASTER_VOLUME; + else + idx = STAC946X_LF_VOLUME - 1 + id; + old = stac9460_2_get(ice, idx); + new = (~mute << 7 & 0x80) | (old & ~0x80); + change = (new != old); + if (change) { + stac9460_2_put(ice, idx, new); + *change_mask = *change_mask | (0x01 << id); + } else { + *change_mask = *change_mask & ~(0x01 << id); + } + } + } +} + + + #define stac9460_dac_mute_info snd_ctl_boolean_mono_info static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); + struct wtm_spec *spec = ice->spec; unsigned char val; int idx, id; + mutex_lock(&spec->mute_mutex); + if (kcontrol->private_value) { idx = STAC946X_MASTER_VOLUME; id = 0; @@ -89,6 +146,8 @@ static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, else val = stac9460_2_get(ice, idx - 6); ucontrol->value.integer.value[0] = (~val >> 7) & 0x1; + + mutex_unlock(&spec->mute_mutex); return 0; } @@ -338,8 +397,14 @@ static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol, /* * MIC / LINE switch fonction */ +static int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static const char * const texts[2] = { "Line In", "Mic" }; + + return snd_ctl_enum_info(uinfo, 1, 2, texts); +} -#define stac9460_mic_sw_info snd_ctl_boolean_mono_info static int stac9460_mic_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -353,7 +418,7 @@ static int stac9460_mic_sw_get(struct snd_kcontrol *kcontrol, val = stac9460_get(ice, STAC946X_GENERAL_PURPOSE); else val = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE); - ucontrol->value.integer.value[0] = ~val>>7 & 0x1; + ucontrol->value.enumerated.item[0] = (val >> 7) & 0x1; return 0; } @@ -369,7 +434,7 @@ static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol, old = stac9460_get(ice, STAC946X_GENERAL_PURPOSE); else old = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE); - new = (~ucontrol->value.integer.value[0] << 7 & 0x80) | (old & ~0x80); + new = (ucontrol->value.enumerated.item[0] << 7 & 0x80) | (old & ~0x80); change = (new != old); if (change) { if (id == 0) @@ -380,17 +445,63 @@ static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol, return change; } + +/* + * Handler for setting correct codec rate - called when rate change is detected + */ +static void stac9460_set_rate_val(struct snd_ice1712 *ice, unsigned int rate) +{ + unsigned char old, new; + unsigned short int changed; + struct wtm_spec *spec = ice->spec; + + if (rate == 0) /* no hint - S/PDIF input is master, simply return */ + return; + else if (rate <= 48000) + new = 0x08; /* 256x, base rate mode */ + else if (rate <= 96000) + new = 0x11; /* 256x, mid rate mode */ + else + new = 0x12; /* 128x, high rate mode */ + + old = stac9460_get(ice, STAC946X_MASTER_CLOCKING); + if (old == new) + return; + /* change detected, setting master clock, muting first */ + /* due to possible conflicts with mute controls - mutexing */ + mutex_lock(&spec->mute_mutex); + /* we have to remember current mute status for each DAC */ + changed = 0xFFFF; + stac9460_dac_mute_all(ice, 0, &changed); + /*printk(KERN_DEBUG "Rate change: %d, new MC: 0x%02x\n", rate, new);*/ + stac9460_put(ice, STAC946X_MASTER_CLOCKING, new); + stac9460_2_put(ice, STAC946X_MASTER_CLOCKING, new); + udelay(10); + /* unmuting - only originally unmuted dacs - + * i.e. those changed when muting */ + stac9460_dac_mute_all(ice, 1, &changed); + mutex_unlock(&spec->mute_mutex); +} + + +/*Limits value in dB for fader*/ +static const DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0); + /* * Control tabs */ static struct snd_kcontrol_new stac9640_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ), .name = "Master Playback Switch", .info = stac9460_dac_mute_info, .get = stac9460_dac_mute_get, .put = stac9460_dac_mute_put, - .private_value = 1 + .private_value = 1, + .tlv = { .p = db_scale_dac } }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -402,7 +513,7 @@ static struct snd_kcontrol_new stac9640_controls[] = { }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "MIC/Line switch", + .name = "MIC/Line Input Enum", .count = 2, .info = stac9460_mic_sw_info, .get = stac9460_mic_sw_get, @@ -419,11 +530,15 @@ static struct snd_kcontrol_new stac9640_controls[] = { }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ), + .name = "DAC Volume", .count = 8, .info = stac9460_dac_vol_info, .get = stac9460_dac_vol_get, .put = stac9460_dac_vol_put, + .tlv = { .p = db_scale_dac } }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -435,12 +550,15 @@ static struct snd_kcontrol_new stac9640_controls[] = { }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ), + .name = "ADC Volume", .count = 2, .info = stac9460_adc_vol_info, .get = stac9460_adc_vol_get, .put = stac9460_adc_vol_put, - + .tlv = { .p = db_scale_adc } } }; @@ -463,41 +581,53 @@ static int wtm_add_controls(struct snd_ice1712 *ice) static int wtm_init(struct snd_ice1712 *ice) { - static unsigned short stac_inits_prodigy[] = { + static unsigned short stac_inits_wtm[] = { STAC946X_RESET, 0, + STAC946X_MASTER_CLOCKING, 0x11, (unsigned short)-1 }; unsigned short *p; + struct wtm_spec *spec; /*WTM 192M*/ ice->num_total_dacs = 8; ice->num_total_adcs = 4; ice->force_rdma1 = 1; + /*init mutex for dac mute conflict*/ + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) + return -ENOMEM; + ice->spec = spec; + mutex_init(&spec->mute_mutex); + + /*initialize codec*/ - p = stac_inits_prodigy; + p = stac_inits_wtm; for (; *p != (unsigned short)-1; p += 2) { stac9460_put(ice, p[0], p[1]); stac9460_2_put(ice, p[0], p[1]); } + ice->gpio.set_pro_rate = stac9460_set_rate_val; return 0; } static unsigned char wtm_eeprom[] = { - 0x47, /*SYSCONF: clock 192KHz, 4ADC, 8DAC */ - 0x80, /* ACLINK : I2S */ - 0xf8, /* I2S: vol; 96k, 24bit, 192k */ - 0xc1 /*SPDIF: out-en, spidf ext out*/, - 0x9f, /* GPIO_DIR */ - 0xff, /* GPIO_DIR1 */ - 0x7f, /* GPIO_DIR2 */ - 0x9f, /* GPIO_MASK */ - 0xff, /* GPIO_MASK1 */ - 0x7f, /* GPIO_MASK2 */ - 0x16, /* GPIO_STATE */ - 0x80, /* GPIO_STATE1 */ - 0x00, /* GPIO_STATE2 */ + [ICE_EEP2_SYSCONF] = 0x67, /*SYSCONF: clock 192KHz, mpu401, + 4ADC, 8DAC */ + [ICE_EEP2_ACLINK] = 0x80, /* ACLINK : I2S */ + [ICE_EEP2_I2S] = 0xf8, /* I2S: vol; 96k, 24bit, 192k */ + [ICE_EEP2_SPDIF] = 0xc1, /*SPDIF: out-en, spidf ext out*/ + [ICE_EEP2_GPIO_DIR] = 0x9f, + [ICE_EEP2_GPIO_DIR1] = 0xff, + [ICE_EEP2_GPIO_DIR2] = 0x7f, + [ICE_EEP2_GPIO_MASK] = 0x9f, + [ICE_EEP2_GPIO_MASK1] = 0xff, + [ICE_EEP2_GPIO_MASK2] = 0x7f, + [ICE_EEP2_GPIO_STATE] = 0x16, + [ICE_EEP2_GPIO_STATE1] = 0x80, + [ICE_EEP2_GPIO_STATE2] = 0x00, }; |