From 5fd48fd7d6894b33d1ef998b1e37e5a0a2604b08 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 18 Jan 2010 14:49:50 +0100 Subject: [PATCH] --- yaml --- r: 182701 b: refs/heads/master c: 3e879d7bac705be4813a0ec9560cbe31db4b269f h: refs/heads/master i: 182699: e25134daa1e36880b92920d4fa32158f126d8eee v: v3 --- [refs] | 2 +- .../sound/alsa/ALSA-Configuration.txt | 2 +- trunk/include/sound/pcm.h | 5 +- trunk/sound/core/pcm.c | 1 - trunk/sound/core/pcm_lib.c | 20 +- trunk/sound/core/pcm_native.c | 5 - trunk/sound/core/seq/seq_timer.c | 27 +- trunk/sound/pci/Kconfig | 1 - trunk/sound/pci/oxygen/Makefile | 2 +- trunk/sound/pci/oxygen/virtuoso.c | 3 - trunk/sound/pci/oxygen/wm8766.h | 73 -- trunk/sound/pci/oxygen/wm8776.h | 177 --- trunk/sound/pci/oxygen/xonar.h | 2 - trunk/sound/pci/oxygen/xonar_wm87x6.c | 1021 ----------------- 14 files changed, 29 insertions(+), 1312 deletions(-) delete mode 100644 trunk/sound/pci/oxygen/wm8766.h delete mode 100644 trunk/sound/pci/oxygen/wm8776.h delete mode 100644 trunk/sound/pci/oxygen/xonar_wm87x6.c diff --git a/[refs] b/[refs] index f0c59da87d72..c31e402c32a2 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 8b296c8f9f660b70e958e6e6b9b4293e6ae854f2 +refs/heads/master: 3e879d7bac705be4813a0ec9560cbe31db4b269f diff --git a/trunk/Documentation/sound/alsa/ALSA-Configuration.txt b/trunk/Documentation/sound/alsa/ALSA-Configuration.txt index 33df82e3a398..c83fd7b64201 100644 --- a/trunk/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/trunk/Documentation/sound/alsa/ALSA-Configuration.txt @@ -1948,7 +1948,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. ------------------- Module for sound cards based on the Asus AV100/AV200 chips, - i.e., Xonar D1, DX, D2, D2X, DS, HDAV1.3 (Deluxe), Essence ST + i.e., Xonar D1, DX, D2, D2X, HDAV1.3 (Deluxe), Essence ST (Deluxe) and Essence STX. This module supports autoprobe and multiple cards. diff --git a/trunk/include/sound/pcm.h b/trunk/include/sound/pcm.h index 768e3098656c..1d4ca2aae50d 100644 --- a/trunk/include/sound/pcm.h +++ b/trunk/include/sound/pcm.h @@ -311,9 +311,8 @@ struct snd_pcm_runtime { struct snd_pcm_mmap_control *control; /* -- locking / scheduling -- */ - unsigned int twake: 1; /* do transfer (!poll) wakeup */ - wait_queue_head_t sleep; /* poll sleep */ - wait_queue_head_t tsleep; /* transfer sleep */ + unsigned int nowake: 1; /* no wakeup (data-copy in progress) */ + wait_queue_head_t sleep; struct fasync_struct *fasync; /* -- private section -- */ diff --git a/trunk/sound/core/pcm.c b/trunk/sound/core/pcm.c index 0d428d0896db..df57a0e30bf2 100644 --- a/trunk/sound/core/pcm.c +++ b/trunk/sound/core/pcm.c @@ -894,7 +894,6 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, memset((void*)runtime->control, 0, size); init_waitqueue_head(&runtime->sleep); - init_waitqueue_head(&runtime->tsleep); runtime->status->state = SNDRV_PCM_STATE_OPEN; diff --git a/trunk/sound/core/pcm_lib.c b/trunk/sound/core/pcm_lib.c index 272f15d19017..720019560794 100644 --- a/trunk/sound/core/pcm_lib.c +++ b/trunk/sound/core/pcm_lib.c @@ -285,8 +285,8 @@ int snd_pcm_update_state(struct snd_pcm_substream *substream, return -EPIPE; } } - if (avail >= runtime->control->avail_min) - wake_up(runtime->twake ? &runtime->tsleep : &runtime->sleep); + if (!runtime->nowake && avail >= runtime->control->avail_min) + wake_up(&runtime->sleep); return 0; } @@ -1706,7 +1706,7 @@ static int wait_for_avail_min(struct snd_pcm_substream *substream, long tout; init_waitqueue_entry(&wait, current); - add_wait_queue(&runtime->tsleep, &wait); + add_wait_queue(&runtime->sleep, &wait); for (;;) { if (signal_pending(current)) { err = -ERESTARTSYS; @@ -1749,7 +1749,7 @@ static int wait_for_avail_min(struct snd_pcm_substream *substream, break; } _endloop: - remove_wait_queue(&runtime->tsleep, &wait); + remove_wait_queue(&runtime->sleep, &wait); *availp = avail; return err; } @@ -1808,7 +1808,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, goto _end_unlock; } - runtime->twake = 1; + runtime->nowake = 1; while (size > 0) { snd_pcm_uframes_t frames, appl_ptr, appl_ofs; snd_pcm_uframes_t avail; @@ -1830,7 +1830,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, if (frames > cont) frames = cont; if (snd_BUG_ON(!frames)) { - runtime->twake = 0; + runtime->nowake = 0; snd_pcm_stream_unlock_irq(substream); return -EINVAL; } @@ -1869,7 +1869,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, } } _end_unlock: - runtime->twake = 0; + runtime->nowake = 0; if (xfer > 0 && err >= 0) snd_pcm_update_state(substream, runtime); snd_pcm_stream_unlock_irq(substream); @@ -2030,7 +2030,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, goto _end_unlock; } - runtime->twake = 1; + runtime->nowake = 1; while (size > 0) { snd_pcm_uframes_t frames, appl_ptr, appl_ofs; snd_pcm_uframes_t avail; @@ -2059,7 +2059,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, if (frames > cont) frames = cont; if (snd_BUG_ON(!frames)) { - runtime->twake = 0; + runtime->nowake = 0; snd_pcm_stream_unlock_irq(substream); return -EINVAL; } @@ -2092,7 +2092,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, xfer += frames; } _end_unlock: - runtime->twake = 0; + runtime->nowake = 0; if (xfer > 0 && err >= 0) snd_pcm_update_state(substream, runtime); snd_pcm_stream_unlock_irq(substream); diff --git a/trunk/sound/core/pcm_native.c b/trunk/sound/core/pcm_native.c index 43552fd73d24..5df0d21f18b3 100644 --- a/trunk/sound/core/pcm_native.c +++ b/trunk/sound/core/pcm_native.c @@ -919,7 +919,6 @@ static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state) runtime->status->state = state; } wake_up(&runtime->sleep); - wake_up(&runtime->tsleep); } static struct action_ops snd_pcm_action_stop = { @@ -1005,7 +1004,6 @@ static void snd_pcm_post_pause(struct snd_pcm_substream *substream, int push) SNDRV_TIMER_EVENT_MPAUSE, &runtime->trigger_tstamp); wake_up(&runtime->sleep); - wake_up(&runtime->tsleep); } else { runtime->status->state = SNDRV_PCM_STATE_RUNNING; if (substream->timer) @@ -1063,7 +1061,6 @@ static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state) runtime->status->suspended_state = runtime->status->state; runtime->status->state = SNDRV_PCM_STATE_SUSPENDED; wake_up(&runtime->sleep); - wake_up(&runtime->tsleep); } static struct action_ops snd_pcm_action_suspend = { @@ -3165,9 +3162,7 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, long size; unsigned long offset; -#ifdef pgprot_noncached area->vm_page_prot = pgprot_noncached(area->vm_page_prot); -#endif area->vm_flags |= VM_IO; size = area->vm_end - area->vm_start; offset = area->vm_pgoff << PAGE_SHIFT; diff --git a/trunk/sound/core/seq/seq_timer.c b/trunk/sound/core/seq/seq_timer.c index 160b1bd0cd62..f745c317d6af 100644 --- a/trunk/sound/core/seq/seq_timer.c +++ b/trunk/sound/core/seq/seq_timer.c @@ -33,21 +33,22 @@ #define SKEW_BASE 0x10000 /* 16bit shift */ -static void snd_seq_timer_set_tick_resolution(struct snd_seq_timer *tmr) +static void snd_seq_timer_set_tick_resolution(struct snd_seq_timer_tick *tick, + int tempo, int ppq) { - if (tmr->tempo < 1000000) - tmr->tick.resolution = (tmr->tempo * 1000) / tmr->ppq; + if (tempo < 1000000) + tick->resolution = (tempo * 1000) / ppq; else { /* might overflow.. */ unsigned int s; - s = tmr->tempo % tmr->ppq; - s = (s * 1000) / tmr->ppq; - tmr->tick.resolution = (tmr->tempo / tmr->ppq) * 1000; - tmr->tick.resolution += s; + s = tempo % ppq; + s = (s * 1000) / ppq; + tick->resolution = (tempo / ppq) * 1000; + tick->resolution += s; } - if (tmr->tick.resolution <= 0) - tmr->tick.resolution = 1; - snd_seq_timer_update_tick(&tmr->tick, 0); + if (tick->resolution <= 0) + tick->resolution = 1; + snd_seq_timer_update_tick(tick, 0); } /* create new timer (constructor) */ @@ -95,7 +96,7 @@ void snd_seq_timer_defaults(struct snd_seq_timer * tmr) /* setup defaults */ tmr->ppq = 96; /* 96 PPQ */ tmr->tempo = 500000; /* 120 BPM */ - snd_seq_timer_set_tick_resolution(tmr); + snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq); tmr->running = 0; tmr->type = SNDRV_SEQ_TIMER_ALSA; @@ -179,7 +180,7 @@ int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo) spin_lock_irqsave(&tmr->lock, flags); if ((unsigned int)tempo != tmr->tempo) { tmr->tempo = tempo; - snd_seq_timer_set_tick_resolution(tmr); + snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq); } spin_unlock_irqrestore(&tmr->lock, flags); return 0; @@ -204,7 +205,7 @@ int snd_seq_timer_set_ppq(struct snd_seq_timer * tmr, int ppq) } tmr->ppq = ppq; - snd_seq_timer_set_tick_resolution(tmr); + snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq); spin_unlock_irqrestore(&tmr->lock, flags); return 0; } diff --git a/trunk/sound/pci/Kconfig b/trunk/sound/pci/Kconfig index 1298c68d6bf0..351654cf7b09 100644 --- a/trunk/sound/pci/Kconfig +++ b/trunk/sound/pci/Kconfig @@ -789,7 +789,6 @@ config SND_VIRTUOSO Say Y here to include support for sound cards based on the Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, Essence ST (Deluxe), and Essence STX. - Support for the DS is experimental. Support for the HDAV1.3 (Deluxe) is very experimental. To compile this driver as a module, choose M here: the module diff --git a/trunk/sound/pci/oxygen/Makefile b/trunk/sound/pci/oxygen/Makefile index acd8f15f7bff..389941cf6100 100644 --- a/trunk/sound/pci/oxygen/Makefile +++ b/trunk/sound/pci/oxygen/Makefile @@ -2,7 +2,7 @@ snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o snd-hifier-objs := hifier.o snd-oxygen-objs := oxygen.o snd-virtuoso-objs := virtuoso.o xonar_lib.o \ - xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o + xonar_pcm179x.o xonar_cs43xx.o xonar_hdmi.o obj-$(CONFIG_SND_OXYGEN_LIB) += snd-oxygen-lib.o obj-$(CONFIG_SND_HIFIER) += snd-hifier.o diff --git a/trunk/sound/pci/oxygen/virtuoso.c b/trunk/sound/pci/oxygen/virtuoso.c index 563b6f50821f..6accaf9580b2 100644 --- a/trunk/sound/pci/oxygen/virtuoso.c +++ b/trunk/sound/pci/oxygen/virtuoso.c @@ -49,7 +49,6 @@ static struct pci_device_id xonar_ids[] __devinitdata = { { OXYGEN_PCI_SUBID(0x1043, 0x834f) }, { OXYGEN_PCI_SUBID(0x1043, 0x835c) }, { OXYGEN_PCI_SUBID(0x1043, 0x835d) }, - { OXYGEN_PCI_SUBID(0x1043, 0x838e) }, { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, { } }; @@ -62,8 +61,6 @@ static int __devinit get_xonar_model(struct oxygen *chip, return 0; if (get_xonar_cs43xx_model(chip, id) >= 0) return 0; - if (get_xonar_wm87x6_model(chip, id) >= 0) - return 0; return -EINVAL; } diff --git a/trunk/sound/pci/oxygen/wm8766.h b/trunk/sound/pci/oxygen/wm8766.h deleted file mode 100644 index e0e849a7eaeb..000000000000 --- a/trunk/sound/pci/oxygen/wm8766.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef WM8766_H_INCLUDED -#define WM8766_H_INCLUDED - -#define WM8766_LDA1 0x00 -#define WM8766_RDA1 0x01 -#define WM8766_DAC_CTRL 0x02 -#define WM8766_INT_CTRL 0x03 -#define WM8766_LDA2 0x04 -#define WM8766_RDA2 0x05 -#define WM8766_LDA3 0x06 -#define WM8766_RDA3 0x07 -#define WM8766_MASTDA 0x08 -#define WM8766_DAC_CTRL2 0x09 -#define WM8766_DAC_CTRL3 0x0a -#define WM8766_MUTE1 0x0c -#define WM8766_MUTE2 0x0f -#define WM8766_RESET 0x1f - -/* LDAx/RDAx/MASTDA */ -#define WM8766_ATT_MASK 0x0ff -#define WM8766_UPDATE 0x100 -/* DAC_CTRL */ -#define WM8766_MUTEALL 0x001 -#define WM8766_DEEMPALL 0x002 -#define WM8766_PWDN 0x004 -#define WM8766_ATC 0x008 -#define WM8766_IZD 0x010 -#define WM8766_PL_LEFT_MASK 0x060 -#define WM8766_PL_LEFT_MUTE 0x000 -#define WM8766_PL_LEFT_LEFT 0x020 -#define WM8766_PL_LEFT_RIGHT 0x040 -#define WM8766_PL_LEFT_LRMIX 0x060 -#define WM8766_PL_RIGHT_MASK 0x180 -#define WM8766_PL_RIGHT_MUTE 0x000 -#define WM8766_PL_RIGHT_LEFT 0x080 -#define WM8766_PL_RIGHT_RIGHT 0x100 -#define WM8766_PL_RIGHT_LRMIX 0x180 -/* INT_CTRL */ -#define WM8766_FMT_MASK 0x003 -#define WM8766_FMT_RJUST 0x000 -#define WM8766_FMT_LJUST 0x001 -#define WM8766_FMT_I2S 0x002 -#define WM8766_FMT_DSP 0x003 -#define WM8766_LRP 0x004 -#define WM8766_BCP 0x008 -#define WM8766_IWL_MASK 0x030 -#define WM8766_IWL_16 0x000 -#define WM8766_IWL_20 0x010 -#define WM8766_IWL_24 0x020 -#define WM8766_IWL_32 0x030 -#define WM8766_PHASE_MASK 0x1c0 -/* DAC_CTRL2 */ -#define WM8766_ZCD 0x001 -#define WM8766_DZFM_MASK 0x006 -#define WM8766_DMUTE_MASK 0x038 -#define WM8766_DEEMP_MASK 0x1c0 -/* DAC_CTRL3 */ -#define WM8766_DACPD_MASK 0x00e -#define WM8766_PWRDNALL 0x010 -#define WM8766_MS 0x020 -#define WM8766_RATE_MASK 0x1c0 -#define WM8766_RATE_128 0x000 -#define WM8766_RATE_192 0x040 -#define WM8766_RATE_256 0x080 -#define WM8766_RATE_384 0x0c0 -#define WM8766_RATE_512 0x100 -#define WM8766_RATE_768 0x140 -/* MUTE1 */ -#define WM8766_MPD1 0x040 -/* MUTE2 */ -#define WM8766_MPD2 0x020 - -#endif diff --git a/trunk/sound/pci/oxygen/wm8776.h b/trunk/sound/pci/oxygen/wm8776.h deleted file mode 100644 index 1a96f5615727..000000000000 --- a/trunk/sound/pci/oxygen/wm8776.h +++ /dev/null @@ -1,177 +0,0 @@ -#ifndef WM8776_H_INCLUDED -#define WM8776_H_INCLUDED - -/* - * the following register names are from: - * wm8776.h -- WM8776 ASoC driver - * - * Copyright 2009 Wolfson Microelectronics plc - * - * Author: Mark Brown - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#define WM8776_HPLVOL 0x00 -#define WM8776_HPRVOL 0x01 -#define WM8776_HPMASTER 0x02 -#define WM8776_DACLVOL 0x03 -#define WM8776_DACRVOL 0x04 -#define WM8776_DACMASTER 0x05 -#define WM8776_PHASESWAP 0x06 -#define WM8776_DACCTRL1 0x07 -#define WM8776_DACMUTE 0x08 -#define WM8776_DACCTRL2 0x09 -#define WM8776_DACIFCTRL 0x0a -#define WM8776_ADCIFCTRL 0x0b -#define WM8776_MSTRCTRL 0x0c -#define WM8776_PWRDOWN 0x0d -#define WM8776_ADCLVOL 0x0e -#define WM8776_ADCRVOL 0x0f -#define WM8776_ALCCTRL1 0x10 -#define WM8776_ALCCTRL2 0x11 -#define WM8776_ALCCTRL3 0x12 -#define WM8776_NOISEGATE 0x13 -#define WM8776_LIMITER 0x14 -#define WM8776_ADCMUX 0x15 -#define WM8776_OUTMUX 0x16 -#define WM8776_RESET 0x17 - - -/* HPLVOL/HPRVOL/HPMASTER */ -#define WM8776_HPATT_MASK 0x07f -#define WM8776_HPZCEN 0x080 -#define WM8776_UPDATE 0x100 - -/* DACLVOL/DACRVOL/DACMASTER */ -#define WM8776_DATT_MASK 0x0ff -/*#define WM8776_UPDATE 0x100*/ - -/* PHASESWAP */ -#define WM8776_PH_MASK 0x003 - -/* DACCTRL1 */ -#define WM8776_DZCEN 0x001 -#define WM8776_ATC 0x002 -#define WM8776_IZD 0x004 -#define WM8776_TOD 0x008 -#define WM8776_PL_LEFT_MASK 0x030 -#define WM8776_PL_LEFT_MUTE 0x000 -#define WM8776_PL_LEFT_LEFT 0x010 -#define WM8776_PL_LEFT_RIGHT 0x020 -#define WM8776_PL_LEFT_LRMIX 0x030 -#define WM8776_PL_RIGHT_MASK 0x0c0 -#define WM8776_PL_RIGHT_MUTE 0x000 -#define WM8776_PL_RIGHT_LEFT 0x040 -#define WM8776_PL_RIGHT_RIGHT 0x080 -#define WM8776_PL_RIGHT_LRMIX 0x0c0 - -/* DACMUTE */ -#define WM8776_DMUTE 0x001 - -/* DACCTRL2 */ -#define WM8776_DEEMPH 0x001 -#define WM8776_DZFM_MASK 0x006 -#define WM8776_DZFM_NONE 0x000 -#define WM8776_DZFM_LR 0x002 -#define WM8776_DZFM_BOTH 0x004 -#define WM8776_DZFM_EITHER 0x006 - -/* DACIFCTRL */ -#define WM8776_DACFMT_MASK 0x003 -#define WM8776_DACFMT_RJUST 0x000 -#define WM8776_DACFMT_LJUST 0x001 -#define WM8776_DACFMT_I2S 0x002 -#define WM8776_DACFMT_DSP 0x003 -#define WM8776_DACLRP 0x004 -#define WM8776_DACBCP 0x008 -#define WM8776_DACWL_MASK 0x030 -#define WM8776_DACWL_16 0x000 -#define WM8776_DACWL_20 0x010 -#define WM8776_DACWL_24 0x020 -#define WM8776_DACWL_32 0x030 - -/* ADCIFCTRL */ -#define WM8776_ADCFMT_MASK 0x003 -#define WM8776_ADCFMT_RJUST 0x000 -#define WM8776_ADCFMT_LJUST 0x001 -#define WM8776_ADCFMT_I2S 0x002 -#define WM8776_ADCFMT_DSP 0x003 -#define WM8776_ADCLRP 0x004 -#define WM8776_ADCBCP 0x008 -#define WM8776_ADCWL_MASK 0x030 -#define WM8776_ADCWL_16 0x000 -#define WM8776_ADCWL_20 0x010 -#define WM8776_ADCWL_24 0x020 -#define WM8776_ADCWL_32 0x030 -#define WM8776_ADCMCLK 0x040 -#define WM8776_ADCHPD 0x100 - -/* MSTRCTRL */ -#define WM8776_ADCRATE_MASK 0x007 -#define WM8776_ADCRATE_256 0x002 -#define WM8776_ADCRATE_384 0x003 -#define WM8776_ADCRATE_512 0x004 -#define WM8776_ADCRATE_768 0x005 -#define WM8776_ADCOSR 0x008 -#define WM8776_DACRATE_MASK 0x070 -#define WM8776_DACRATE_128 0x000 -#define WM8776_DACRATE_192 0x010 -#define WM8776_DACRATE_256 0x020 -#define WM8776_DACRATE_384 0x030 -#define WM8776_DACRATE_512 0x040 -#define WM8776_DACRATE_768 0x050 -#define WM8776_DACMS 0x080 -#define WM8776_ADCMS 0x100 - -/* PWRDOWN */ -#define WM8776_PDWN 0x001 -#define WM8776_ADCPD 0x002 -#define WM8776_DACPD 0x004 -#define WM8776_HPPD 0x008 -#define WM8776_AINPD 0x040 - -/* ADCLVOL/ADCRVOL */ -#define WM8776_AGMASK 0x0ff -#define WM8776_ZCA 0x100 - -/* ALCCTRL1 */ -#define WM8776_LCT_MASK 0x00f -#define WM8776_MAXGAIN_MASK 0x070 -#define WM8776_LCSEL_MASK 0x180 -#define WM8776_LCSEL_LIMITER 0x000 -#define WM8776_LCSEL_ALC_RIGHT 0x080 -#define WM8776_LCSEL_ALC_LEFT 0x100 -#define WM8776_LCSEL_ALC_STEREO 0x180 - -/* ALCCTRL2 */ -#define WM8776_HLD_MASK 0x00f -#define WM8776_ALCZC 0x080 -#define WM8776_LCEN 0x100 - -/* ALCCTRL3 */ -#define WM8776_ATK_MASK 0x00f -#define WM8776_DCY_MASK 0x0f0 - -/* NOISEGATE */ -#define WM8776_NGAT 0x001 -#define WM8776_NGTH_MASK 0x01c - -/* LIMITER */ -#define WM8776_MAXATTEN_MASK 0x00f -#define WM8776_TRANWIN_MASK 0x070 - -/* ADCMUX */ -#define WM8776_AMX_MASK 0x01f -#define WM8776_MUTERA 0x040 -#define WM8776_MUTELA 0x080 -#define WM8776_LRBOTH 0x100 - -/* OUTMUX */ -#define WM8776_MX_DAC 0x001 -#define WM8776_MX_AUX 0x002 -#define WM8776_MX_BYPASS 0x004 - -#endif diff --git a/trunk/sound/pci/oxygen/xonar.h b/trunk/sound/pci/oxygen/xonar.h index b35343b0a9a5..89b3ed814d64 100644 --- a/trunk/sound/pci/oxygen/xonar.h +++ b/trunk/sound/pci/oxygen/xonar.h @@ -35,8 +35,6 @@ int get_xonar_pcm179x_model(struct oxygen *chip, const struct pci_device_id *id); int get_xonar_cs43xx_model(struct oxygen *chip, const struct pci_device_id *id); -int get_xonar_wm87x6_model(struct oxygen *chip, - const struct pci_device_id *id); /* HDMI helper functions */ diff --git a/trunk/sound/pci/oxygen/xonar_wm87x6.c b/trunk/sound/pci/oxygen/xonar_wm87x6.c deleted file mode 100644 index 7754db166d9e..000000000000 --- a/trunk/sound/pci/oxygen/xonar_wm87x6.c +++ /dev/null @@ -1,1021 +0,0 @@ -/* - * card driver for models with WM8776/WM8766 DACs (Xonar DS) - * - * Copyright (c) Clemens Ladisch - * - * - * This driver is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2. - * - * This driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this driver; if not, see . - */ - -/* - * Xonar DS - * -------- - * - * CMI8788: - * - * SPI 0 -> WM8766 (surround, center/LFE, back) - * SPI 1 -> WM8776 (front, input) - * - * GPIO 4 <- headphone detect - * GPIO 6 -> route input jack to input 1/2 (1/0) - * GPIO 7 -> enable output to speakers - * GPIO 8 -> enable output to speakers - */ - -#include -#include -#include -#include -#include -#include -#include -#include "xonar.h" -#include "wm8776.h" -#include "wm8766.h" - -#define GPIO_DS_HP_DETECT 0x0010 -#define GPIO_DS_INPUT_ROUTE 0x0040 -#define GPIO_DS_OUTPUT_ENABLE 0x0180 - -#define LC_CONTROL_LIMITER 0x40000000 -#define LC_CONTROL_ALC 0x20000000 - -struct xonar_wm87x6 { - struct xonar_generic generic; - u16 wm8776_regs[0x17]; - u16 wm8766_regs[0x10]; - struct snd_kcontrol *lc_controls[13]; -}; - -static void wm8776_write(struct oxygen *chip, - unsigned int reg, unsigned int value) -{ - struct xonar_wm87x6 *data = chip->model_data; - - oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | - OXYGEN_SPI_DATA_LENGTH_2 | - OXYGEN_SPI_CLOCK_160 | - (1 << OXYGEN_SPI_CODEC_SHIFT) | - OXYGEN_SPI_CEN_LATCH_CLOCK_LO, - (reg << 9) | value); - if (reg < ARRAY_SIZE(data->wm8776_regs)) { - if (reg >= WM8776_HPLVOL || reg <= WM8776_DACMASTER) - value &= ~WM8776_UPDATE; - data->wm8776_regs[reg] = value; - } -} - -static void wm8776_write_cached(struct oxygen *chip, - unsigned int reg, unsigned int value) -{ - struct xonar_wm87x6 *data = chip->model_data; - - if (reg >= ARRAY_SIZE(data->wm8776_regs) || - value != data->wm8776_regs[reg]) - wm8776_write(chip, reg, value); -} - -static void wm8766_write(struct oxygen *chip, - unsigned int reg, unsigned int value) -{ - struct xonar_wm87x6 *data = chip->model_data; - - oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | - OXYGEN_SPI_DATA_LENGTH_2 | - OXYGEN_SPI_CLOCK_160 | - (0 << OXYGEN_SPI_CODEC_SHIFT) | - OXYGEN_SPI_CEN_LATCH_CLOCK_LO, - (reg << 9) | value); - if (reg < ARRAY_SIZE(data->wm8766_regs)) - data->wm8766_regs[reg] = value; -} - -static void wm8766_write_cached(struct oxygen *chip, - unsigned int reg, unsigned int value) -{ - struct xonar_wm87x6 *data = chip->model_data; - - if (reg >= ARRAY_SIZE(data->wm8766_regs) || - value != data->wm8766_regs[reg]) { - if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) || - (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA)) - value &= ~WM8766_UPDATE; - wm8766_write(chip, reg, value); - } -} - -static void wm8776_registers_init(struct oxygen *chip) -{ - struct xonar_wm87x6 *data = chip->model_data; - - wm8776_write(chip, WM8776_RESET, 0); - wm8776_write(chip, WM8776_DACCTRL1, WM8776_DZCEN | - WM8776_PL_LEFT_LEFT | WM8776_PL_RIGHT_RIGHT); - wm8776_write(chip, WM8776_DACMUTE, chip->dac_mute ? WM8776_DMUTE : 0); - wm8776_write(chip, WM8776_DACIFCTRL, - WM8776_DACFMT_LJUST | WM8776_DACWL_24); - wm8776_write(chip, WM8776_ADCIFCTRL, - data->wm8776_regs[WM8776_ADCIFCTRL]); - wm8776_write(chip, WM8776_MSTRCTRL, data->wm8776_regs[WM8776_MSTRCTRL]); - wm8776_write(chip, WM8776_PWRDOWN, data->wm8776_regs[WM8776_PWRDOWN]); - wm8776_write(chip, WM8776_HPLVOL, data->wm8776_regs[WM8776_HPLVOL]); - wm8776_write(chip, WM8776_HPRVOL, data->wm8776_regs[WM8776_HPRVOL] | - WM8776_UPDATE); - wm8776_write(chip, WM8776_ADCLVOL, data->wm8776_regs[WM8776_ADCLVOL]); - wm8776_write(chip, WM8776_ADCRVOL, data->wm8776_regs[WM8776_ADCRVOL]); - wm8776_write(chip, WM8776_ADCMUX, data->wm8776_regs[WM8776_ADCMUX]); - wm8776_write(chip, WM8776_DACLVOL, chip->dac_volume[0]); - wm8776_write(chip, WM8776_DACRVOL, chip->dac_volume[1] | WM8776_UPDATE); -} - -static void wm8766_registers_init(struct oxygen *chip) -{ - wm8766_write(chip, WM8766_RESET, 0); - wm8766_write(chip, WM8766_INT_CTRL, WM8766_FMT_LJUST | WM8766_IWL_24); - wm8766_write(chip, WM8766_DAC_CTRL2, - WM8766_ZCD | (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); - wm8766_write(chip, WM8766_LDA1, chip->dac_volume[2]); - wm8766_write(chip, WM8766_RDA1, chip->dac_volume[3]); - wm8766_write(chip, WM8766_LDA2, chip->dac_volume[4]); - wm8766_write(chip, WM8766_RDA2, chip->dac_volume[5]); - wm8766_write(chip, WM8766_LDA3, chip->dac_volume[6]); - wm8766_write(chip, WM8766_RDA3, chip->dac_volume[7] | WM8766_UPDATE); -} - -static void wm8776_init(struct oxygen *chip) -{ - struct xonar_wm87x6 *data = chip->model_data; - - data->wm8776_regs[WM8776_HPLVOL] = (0x79 - 60) | WM8776_HPZCEN; - data->wm8776_regs[WM8776_HPRVOL] = (0x79 - 60) | WM8776_HPZCEN; - data->wm8776_regs[WM8776_ADCIFCTRL] = - WM8776_ADCFMT_LJUST | WM8776_ADCWL_24 | WM8776_ADCMCLK; - data->wm8776_regs[WM8776_MSTRCTRL] = - WM8776_ADCRATE_256 | WM8776_DACRATE_256; - data->wm8776_regs[WM8776_PWRDOWN] = WM8776_HPPD; - data->wm8776_regs[WM8776_ADCLVOL] = 0xa5 | WM8776_ZCA; - data->wm8776_regs[WM8776_ADCRVOL] = 0xa5 | WM8776_ZCA; - data->wm8776_regs[WM8776_ADCMUX] = 0x001; - wm8776_registers_init(chip); -} - -static void xonar_ds_init(struct oxygen *chip) -{ - struct xonar_wm87x6 *data = chip->model_data; - - data->generic.anti_pop_delay = 300; - data->generic.output_enable_bit = GPIO_DS_OUTPUT_ENABLE; - - wm8776_init(chip); - wm8766_registers_init(chip); - - oxygen_write16_masked(chip, OXYGEN_GPIO_CONTROL, GPIO_DS_INPUT_ROUTE, - GPIO_DS_HP_DETECT | GPIO_DS_INPUT_ROUTE); - oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DS_INPUT_ROUTE); - oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, GPIO_DS_HP_DETECT); - chip->interrupt_mask |= OXYGEN_INT_GPIO; - - xonar_enable_output(chip); - - snd_component_add(chip->card, "WM8776"); - snd_component_add(chip->card, "WM8766"); -} - -static void xonar_ds_cleanup(struct oxygen *chip) -{ - xonar_disable_output(chip); -} - -static void xonar_ds_suspend(struct oxygen *chip) -{ - xonar_ds_cleanup(chip); -} - -static void xonar_ds_resume(struct oxygen *chip) -{ - wm8776_registers_init(chip); - wm8766_registers_init(chip); - xonar_enable_output(chip); -} - -static void wm8776_adc_hardware_filter(unsigned int channel, - struct snd_pcm_hardware *hardware) -{ - if (channel == PCM_A) { - hardware->rates = SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_64000 | - SNDRV_PCM_RATE_88200 | - SNDRV_PCM_RATE_96000; - hardware->rate_max = 96000; - } -} - -static void set_wm87x6_dac_params(struct oxygen *chip, - struct snd_pcm_hw_params *params) -{ -} - -static void set_wm8776_adc_params(struct oxygen *chip, - struct snd_pcm_hw_params *params) -{ - u16 reg; - - reg = WM8776_ADCRATE_256 | WM8776_DACRATE_256; - if (params_rate(params) > 48000) - reg |= WM8776_ADCOSR; - wm8776_write_cached(chip, WM8776_MSTRCTRL, reg); -} - -static void update_wm8776_volume(struct oxygen *chip) -{ - struct xonar_wm87x6 *data = chip->model_data; - u8 to_change; - - if (chip->dac_volume[0] == chip->dac_volume[1]) { - if (chip->dac_volume[0] != data->wm8776_regs[WM8776_DACLVOL] || - chip->dac_volume[1] != data->wm8776_regs[WM8776_DACRVOL]) { - wm8776_write(chip, WM8776_DACMASTER, - chip->dac_volume[0] | WM8776_UPDATE); - data->wm8776_regs[WM8776_DACLVOL] = chip->dac_volume[0]; - data->wm8776_regs[WM8776_DACRVOL] = chip->dac_volume[0]; - } - } else { - to_change = (chip->dac_volume[0] != - data->wm8776_regs[WM8776_DACLVOL]) << 0; - to_change |= (chip->dac_volume[1] != - data->wm8776_regs[WM8776_DACLVOL]) << 1; - if (to_change & 1) - wm8776_write(chip, WM8776_DACLVOL, chip->dac_volume[0] | - ((to_change & 2) ? 0 : WM8776_UPDATE)); - if (to_change & 2) - wm8776_write(chip, WM8776_DACRVOL, - chip->dac_volume[1] | WM8776_UPDATE); - } -} - -static void update_wm87x6_volume(struct oxygen *chip) -{ - static const u8 wm8766_regs[6] = { - WM8766_LDA1, WM8766_RDA1, - WM8766_LDA2, WM8766_RDA2, - WM8766_LDA3, WM8766_RDA3, - }; - struct xonar_wm87x6 *data = chip->model_data; - unsigned int i; - u8 to_change; - - update_wm8776_volume(chip); - if (chip->dac_volume[2] == chip->dac_volume[3] && - chip->dac_volume[2] == chip->dac_volume[4] && - chip->dac_volume[2] == chip->dac_volume[5] && - chip->dac_volume[2] == chip->dac_volume[6] && - chip->dac_volume[2] == chip->dac_volume[7]) { - to_change = 0; - for (i = 0; i < 6; ++i) - if (chip->dac_volume[2] != - data->wm8766_regs[wm8766_regs[i]]) - to_change = 1; - if (to_change) { - wm8766_write(chip, WM8766_MASTDA, - chip->dac_volume[2] | WM8766_UPDATE); - for (i = 0; i < 6; ++i) - data->wm8766_regs[wm8766_regs[i]] = - chip->dac_volume[2]; - } - } else { - to_change = 0; - for (i = 0; i < 6; ++i) - to_change |= (chip->dac_volume[2 + i] != - data->wm8766_regs[wm8766_regs[i]]) << i; - for (i = 0; i < 6; ++i) - if (to_change & (1 << i)) - wm8766_write(chip, wm8766_regs[i], - chip->dac_volume[2 + i] | - ((to_change & (0x3e << i)) - ? 0 : WM8766_UPDATE)); - } -} - -static void update_wm8776_mute(struct oxygen *chip) -{ - wm8776_write_cached(chip, WM8776_DACMUTE, - chip->dac_mute ? WM8776_DMUTE : 0); -} - -static void update_wm87x6_mute(struct oxygen *chip) -{ - update_wm8776_mute(chip); - wm8766_write_cached(chip, WM8766_DAC_CTRL2, WM8766_ZCD | - (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); -} - -static void xonar_ds_gpio_changed(struct oxygen *chip) -{ - u16 bits; - - bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); - snd_printk(KERN_INFO "HP detect: %d\n", !!(bits & GPIO_DS_HP_DETECT)); -} - -static int wm8776_bit_switch_get(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - struct oxygen *chip = ctl->private_data; - struct xonar_wm87x6 *data = chip->model_data; - u16 bit = ctl->private_value & 0xffff; - unsigned int reg_index = (ctl->private_value >> 16) & 0xff; - bool invert = (ctl->private_value >> 24) & 1; - - value->value.integer.value[0] = - ((data->wm8776_regs[reg_index] & bit) != 0) ^ invert; - return 0; -} - -static int wm8776_bit_switch_put(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - struct oxygen *chip = ctl->private_data; - struct xonar_wm87x6 *data = chip->model_data; - u16 bit = ctl->private_value & 0xffff; - u16 reg_value; - unsigned int reg_index = (ctl->private_value >> 16) & 0xff; - bool invert = (ctl->private_value >> 24) & 1; - int changed; - - mutex_lock(&chip->mutex); - reg_value = data->wm8776_regs[reg_index] & ~bit; - if (value->value.integer.value[0] ^ invert) - reg_value |= bit; - changed = reg_value != data->wm8776_regs[reg_index]; - if (changed) - wm8776_write(chip, reg_index, reg_value); - mutex_unlock(&chip->mutex); - return changed; -} - -static int wm8776_field_enum_info(struct snd_kcontrol *ctl, - struct snd_ctl_elem_info *info) -{ - static const char *const hld[16] = { - "0 ms", "2.67 ms", "5.33 ms", "10.6 ms", - "21.3 ms", "42.7 ms", "85.3 ms", "171 ms", - "341 ms", "683 ms", "1.37 s", "2.73 s", - "5.46 s", "10.9 s", "21.8 s", "43.7 s", - }; - static const char *const atk_lim[11] = { - "0.25 ms", "0.5 ms", "1 ms", "2 ms", - "4 ms", "8 ms", "16 ms", "32 ms", - "64 ms", "128 ms", "256 ms", - }; - static const char *const atk_alc[11] = { - "8.40 ms", "16.8 ms", "33.6 ms", "67.2 ms", - "134 ms", "269 ms", "538 ms", "1.08 s", - "2.15 s", "4.3 s", "8.6 s", - }; - static const char *const dcy_lim[11] = { - "1.2 ms", "2.4 ms", "4.8 ms", "9.6 ms", - "19.2 ms", "38.4 ms", "76.8 ms", "154 ms", - "307 ms", "614 ms", "1.23 s", - }; - static const char *const dcy_alc[11] = { - "33.5 ms", "67.0 ms", "134 ms", "268 ms", - "536 ms", "1.07 s", "2.14 s", "4.29 s", - "8.58 s", "17.2 s", "34.3 s", - }; - static const char *const tranwin[8] = { - "0 us", "62.5 us", "125 us", "250 us", - "500 us", "1 ms", "2 ms", "4 ms", - }; - u8 max; - const char *const *names; - - max = (ctl->private_value >> 12) & 0xf; - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = max + 1; - if (info->value.enumerated.item > max) - info->value.enumerated.item = max; - switch ((ctl->private_value >> 24) & 0x1f) { - case WM8776_ALCCTRL2: - names = hld; - break; - case WM8776_ALCCTRL3: - if (((ctl->private_value >> 20) & 0xf) == 0) { - if (ctl->private_value & LC_CONTROL_LIMITER) - names = atk_lim; - else - names = atk_alc; - } else { - if (ctl->private_value & LC_CONTROL_LIMITER) - names = dcy_lim; - else - names = dcy_alc; - } - break; - case WM8776_LIMITER: - names = tranwin; - break; - default: - return -ENXIO; - } - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; -} - -static int wm8776_field_volume_info(struct snd_kcontrol *ctl, - struct snd_ctl_elem_info *info) -{ - info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - info->count = 1; - info->value.integer.min = (ctl->private_value >> 8) & 0xf; - info->value.integer.max = (ctl->private_value >> 12) & 0xf; - return 0; -} - -static void wm8776_field_set_from_ctl(struct snd_kcontrol *ctl) -{ - struct oxygen *chip = ctl->private_data; - struct xonar_wm87x6 *data = chip->model_data; - unsigned int value, reg_index, mode; - u8 min, max, shift; - u16 mask, reg_value; - bool invert; - - if ((data->wm8776_regs[WM8776_ALCCTRL1] & WM8776_LCSEL_MASK) == - WM8776_LCSEL_LIMITER) - mode = LC_CONTROL_LIMITER; - else - mode = LC_CONTROL_ALC; - if (!(ctl->private_value & mode)) - return; - - value = ctl->private_value & 0xf; - min = (ctl->private_value >> 8) & 0xf; - max = (ctl->private_value >> 12) & 0xf; - mask = (ctl->private_value >> 16) & 0xf; - shift = (ctl->private_value >> 20) & 0xf; - reg_index = (ctl->private_value >> 24) & 0x1f; - invert = (ctl->private_value >> 29) & 0x1; - - if (invert) - value = max - (value - min); - reg_value = data->wm8776_regs[reg_index]; - reg_value &= ~(mask << shift); - reg_value |= value << shift; - wm8776_write_cached(chip, reg_index, reg_value); -} - -static int wm8776_field_set(struct snd_kcontrol *ctl, unsigned int value) -{ - struct oxygen *chip = ctl->private_data; - u8 min, max; - int changed; - - min = (ctl->private_value >> 8) & 0xf; - max = (ctl->private_value >> 12) & 0xf; - if (value < min || value > max) - return -EINVAL; - mutex_lock(&chip->mutex); - changed = value != (ctl->private_value & 0xf); - if (changed) { - ctl->private_value = (ctl->private_value & ~0xf) | value; - wm8776_field_set_from_ctl(ctl); - } - mutex_unlock(&chip->mutex); - return changed; -} - -static int wm8776_field_enum_get(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - value->value.enumerated.item[0] = ctl->private_value & 0xf; - return 0; -} - -static int wm8776_field_volume_get(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - value->value.integer.value[0] = ctl->private_value & 0xf; - return 0; -} - -static int wm8776_field_enum_put(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - return wm8776_field_set(ctl, value->value.enumerated.item[0]); -} - -static int wm8776_field_volume_put(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - return wm8776_field_set(ctl, value->value.integer.value[0]); -} - -static int wm8776_hp_vol_info(struct snd_kcontrol *ctl, - struct snd_ctl_elem_info *info) -{ - info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - info->count = 2; - info->value.integer.min = 0x79 - 60; - info->value.integer.max = 0x7f; - return 0; -} - -static int wm8776_hp_vol_get(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - struct oxygen *chip = ctl->private_data; - struct xonar_wm87x6 *data = chip->model_data; - - mutex_lock(&chip->mutex); - value->value.integer.value[0] = - data->wm8776_regs[WM8776_HPLVOL] & WM8776_HPATT_MASK; - value->value.integer.value[1] = - data->wm8776_regs[WM8776_HPRVOL] & WM8776_HPATT_MASK; - mutex_unlock(&chip->mutex); - return 0; -} - -static int wm8776_hp_vol_put(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - struct oxygen *chip = ctl->private_data; - struct xonar_wm87x6 *data = chip->model_data; - u8 to_update; - - mutex_lock(&chip->mutex); - to_update = (value->value.integer.value[0] != - (data->wm8776_regs[WM8776_HPLVOL] & WM8776_HPATT_MASK)) - << 0; - to_update |= (value->value.integer.value[1] != - (data->wm8776_regs[WM8776_HPRVOL] & WM8776_HPATT_MASK)) - << 1; - if (value->value.integer.value[0] == value->value.integer.value[1]) { - if (to_update) { - wm8776_write(chip, WM8776_HPMASTER, - value->value.integer.value[0] | - WM8776_HPZCEN | WM8776_UPDATE); - data->wm8776_regs[WM8776_HPLVOL] = - value->value.integer.value[0] | WM8776_HPZCEN; - data->wm8776_regs[WM8776_HPRVOL] = - value->value.integer.value[0] | WM8776_HPZCEN; - } - } else { - if (to_update & 1) - wm8776_write(chip, WM8776_HPLVOL, - value->value.integer.value[0] | - WM8776_HPZCEN | - ((to_update & 2) ? 0 : WM8776_UPDATE)); - if (to_update & 2) - wm8776_write(chip, WM8776_HPRVOL, - value->value.integer.value[1] | - WM8776_HPZCEN | WM8776_UPDATE); - } - mutex_unlock(&chip->mutex); - return to_update != 0; -} - -static int wm8776_input_mux_get(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - struct oxygen *chip = ctl->private_data; - struct xonar_wm87x6 *data = chip->model_data; - unsigned int mux_bit = ctl->private_value; - - value->value.integer.value[0] = - !!(data->wm8776_regs[WM8776_ADCMUX] & mux_bit); - return 0; -} - -static int wm8776_input_mux_put(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - struct oxygen *chip = ctl->private_data; - struct xonar_wm87x6 *data = chip->model_data; - unsigned int mux_bit = ctl->private_value; - u16 reg; - int changed; - - mutex_lock(&chip->mutex); - reg = data->wm8776_regs[WM8776_ADCMUX]; - if (value->value.integer.value[0]) { - reg &= ~0x003; - reg |= mux_bit; - } else - reg &= ~mux_bit; - changed = reg != data->wm8776_regs[WM8776_ADCMUX]; - if (changed) { - oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, - reg & 1 ? GPIO_DS_INPUT_ROUTE : 0, - GPIO_DS_INPUT_ROUTE); - wm8776_write(chip, WM8776_ADCMUX, reg); - } - mutex_unlock(&chip->mutex); - return changed; -} - -static int wm8776_input_vol_info(struct snd_kcontrol *ctl, - struct snd_ctl_elem_info *info) -{ - info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - info->count = 2; - info->value.integer.min = 0xa5; - info->value.integer.max = 0xff; - return 0; -} - -static int wm8776_input_vol_get(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - struct oxygen *chip = ctl->private_data; - struct xonar_wm87x6 *data = chip->model_data; - - mutex_lock(&chip->mutex); - value->value.integer.value[0] = - data->wm8776_regs[WM8776_ADCLVOL] & WM8776_AGMASK; - value->value.integer.value[1] = - data->wm8776_regs[WM8776_ADCRVOL] & WM8776_AGMASK; - mutex_unlock(&chip->mutex); - return 0; -} - -static int wm8776_input_vol_put(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - struct oxygen *chip = ctl->private_data; - struct xonar_wm87x6 *data = chip->model_data; - int changed = 0; - - mutex_lock(&chip->mutex); - changed = (value->value.integer.value[0] != - (data->wm8776_regs[WM8776_ADCLVOL] & WM8776_AGMASK)) || - (value->value.integer.value[1] != - (data->wm8776_regs[WM8776_ADCRVOL] & WM8776_AGMASK)); - wm8776_write_cached(chip, WM8776_ADCLVOL, - value->value.integer.value[0] | WM8776_ZCA); - wm8776_write_cached(chip, WM8776_ADCRVOL, - value->value.integer.value[1] | WM8776_ZCA); - mutex_unlock(&chip->mutex); - return changed; -} - -static int wm8776_level_control_info(struct snd_kcontrol *ctl, - struct snd_ctl_elem_info *info) -{ - static const char *const names[3] = { - "None", "Peak Limiter", "Automatic Level Control" - }; - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = 3; - if (info->value.enumerated.item >= 3) - info->value.enumerated.item = 2; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; -} - -static int wm8776_level_control_get(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - struct oxygen *chip = ctl->private_data; - struct xonar_wm87x6 *data = chip->model_data; - - if (!(data->wm8776_regs[WM8776_ALCCTRL2] & WM8776_LCEN)) - value->value.enumerated.item[0] = 0; - else if ((data->wm8776_regs[WM8776_ALCCTRL1] & WM8776_LCSEL_MASK) == - WM8776_LCSEL_LIMITER) - value->value.enumerated.item[0] = 1; - else - value->value.enumerated.item[0] = 2; - return 0; -} - -static void activate_control(struct oxygen *chip, - struct snd_kcontrol *ctl, unsigned int mode) -{ - unsigned int access; - - if (ctl->private_value & mode) - access = 0; - else - access = SNDRV_CTL_ELEM_ACCESS_INACTIVE; - if ((ctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_INACTIVE) != access) { - ctl->vd[0].access ^= SNDRV_CTL_ELEM_ACCESS_INACTIVE; - snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); - } -} - -static int wm8776_level_control_put(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - struct oxygen *chip = ctl->private_data; - struct xonar_wm87x6 *data = chip->model_data; - unsigned int mode = 0, i; - u16 ctrl1, ctrl2; - int changed; - - if (value->value.enumerated.item[0] >= 3) - return -EINVAL; - mutex_lock(&chip->mutex); - changed = value->value.enumerated.item[0] != ctl->private_value; - if (changed) { - ctl->private_value = value->value.enumerated.item[0]; - ctrl1 = data->wm8776_regs[WM8776_ALCCTRL1]; - ctrl2 = data->wm8776_regs[WM8776_ALCCTRL2]; - switch (value->value.enumerated.item[0]) { - default: - wm8776_write_cached(chip, WM8776_ALCCTRL2, - ctrl2 & ~WM8776_LCEN); - break; - case 1: - wm8776_write_cached(chip, WM8776_ALCCTRL1, - (ctrl1 & ~WM8776_LCSEL_MASK) | - WM8776_LCSEL_LIMITER); - wm8776_write_cached(chip, WM8776_ALCCTRL2, - ctrl2 | WM8776_LCEN); - mode = LC_CONTROL_LIMITER; - break; - case 2: - wm8776_write_cached(chip, WM8776_ALCCTRL1, - (ctrl1 & ~WM8776_LCSEL_MASK) | - WM8776_LCSEL_ALC_STEREO); - wm8776_write_cached(chip, WM8776_ALCCTRL2, - ctrl2 | WM8776_LCEN); - mode = LC_CONTROL_ALC; - break; - } - for (i = 0; i < ARRAY_SIZE(data->lc_controls); ++i) - activate_control(chip, data->lc_controls[i], mode); - } - mutex_unlock(&chip->mutex); - return changed; -} - -static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) -{ - static const char *const names[2] = { - "None", "High-pass Filter" - }; - - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = 2; - if (info->value.enumerated.item >= 2) - info->value.enumerated.item = 1; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; -} - -static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) -{ - struct oxygen *chip = ctl->private_data; - struct xonar_wm87x6 *data = chip->model_data; - - value->value.enumerated.item[0] = - !(data->wm8776_regs[WM8776_ADCIFCTRL] & WM8776_ADCHPD); - return 0; -} - -static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) -{ - struct oxygen *chip = ctl->private_data; - struct xonar_wm87x6 *data = chip->model_data; - unsigned int reg; - int changed; - - mutex_lock(&chip->mutex); - reg = data->wm8776_regs[WM8776_ADCIFCTRL] & ~WM8776_ADCHPD; - if (!value->value.enumerated.item[0]) - reg |= WM8776_ADCHPD; - changed = reg != data->wm8776_regs[WM8776_ADCIFCTRL]; - if (changed) - wm8776_write(chip, WM8776_ADCIFCTRL, reg); - mutex_unlock(&chip->mutex); - return changed; -} - -#define WM8776_BIT_SWITCH(xname, reg, bit, invert, flags) { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .info = snd_ctl_boolean_mono_info, \ - .get = wm8776_bit_switch_get, \ - .put = wm8776_bit_switch_put, \ - .private_value = ((reg) << 16) | (bit) | ((invert) << 24) | (flags), \ -} -#define _WM8776_FIELD_CTL(xname, reg, shift, initval, min, max, mask, flags) \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .private_value = (initval) | ((min) << 8) | ((max) << 12) | \ - ((mask) << 16) | ((shift) << 20) | ((reg) << 24) | (flags) -#define WM8776_FIELD_CTL_ENUM(xname, reg, shift, init, min, max, mask, flags) {\ - _WM8776_FIELD_CTL(xname " Capture Enum", \ - reg, shift, init, min, max, mask, flags), \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ - SNDRV_CTL_ELEM_ACCESS_INACTIVE, \ - .info = wm8776_field_enum_info, \ - .get = wm8776_field_enum_get, \ - .put = wm8776_field_enum_put, \ -} -#define WM8776_FIELD_CTL_VOLUME(a, b, c, d, e, f, g, h, tlv_p) { \ - _WM8776_FIELD_CTL(a " Capture Volume", b, c, d, e, f, g, h), \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ - SNDRV_CTL_ELEM_ACCESS_INACTIVE | \ - SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ - .info = wm8776_field_volume_info, \ - .get = wm8776_field_volume_get, \ - .put = wm8776_field_volume_put, \ - .tlv = { .p = tlv_p }, \ -} - -static const DECLARE_TLV_DB_SCALE(wm87x6_dac_db_scale, -6000, 50, 0); -static const DECLARE_TLV_DB_SCALE(wm8776_adc_db_scale, -2100, 50, 0); -static const DECLARE_TLV_DB_SCALE(wm8776_hp_db_scale, -6000, 100, 0); -static const DECLARE_TLV_DB_SCALE(wm8776_lct_db_scale, -1600, 100, 0); -static const DECLARE_TLV_DB_SCALE(wm8776_maxgain_db_scale, 0, 400, 0); -static const DECLARE_TLV_DB_SCALE(wm8776_ngth_db_scale, -7800, 600, 0); -static const DECLARE_TLV_DB_SCALE(wm8776_maxatten_lim_db_scale, -1200, 100, 0); -static const DECLARE_TLV_DB_SCALE(wm8776_maxatten_alc_db_scale, -2100, 400, 0); - -static const struct snd_kcontrol_new ds_controls[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Headphone Playback Volume", - .info = wm8776_hp_vol_info, - .get = wm8776_hp_vol_get, - .put = wm8776_hp_vol_put, - .tlv = { .p = wm8776_hp_db_scale }, - }, - WM8776_BIT_SWITCH("Headphone Playback Switch", - WM8776_PWRDOWN, WM8776_HPPD, 1, 0), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Capture Volume", - .info = wm8776_input_vol_info, - .get = wm8776_input_vol_get, - .put = wm8776_input_vol_put, - .tlv = { .p = wm8776_adc_db_scale }, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Line Capture Switch", - .info = snd_ctl_boolean_mono_info, - .get = wm8776_input_mux_get, - .put = wm8776_input_mux_put, - .private_value = 1 << 0, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Mic Capture Switch", - .info = snd_ctl_boolean_mono_info, - .get = wm8776_input_mux_get, - .put = wm8776_input_mux_put, - .private_value = 1 << 1, - }, - WM8776_BIT_SWITCH("Aux", WM8776_ADCMUX, 1 << 2, 0, 0), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "ADC Filter Capture Enum", - .info = hpf_info, - .get = hpf_get, - .put = hpf_put, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Level Control Capture Enum", - .info = wm8776_level_control_info, - .get = wm8776_level_control_get, - .put = wm8776_level_control_put, - .private_value = 0, - }, -}; -static const struct snd_kcontrol_new lc_controls[] = { - WM8776_FIELD_CTL_VOLUME("Limiter Threshold", - WM8776_ALCCTRL1, 0, 11, 0, 15, 0xf, - LC_CONTROL_LIMITER, wm8776_lct_db_scale), - WM8776_FIELD_CTL_ENUM("Limiter Attack Time", - WM8776_ALCCTRL3, 0, 2, 0, 10, 0xf, - LC_CONTROL_LIMITER), - WM8776_FIELD_CTL_ENUM("Limiter Decay Time", - WM8776_ALCCTRL3, 4, 3, 0, 10, 0xf, - LC_CONTROL_LIMITER), - WM8776_FIELD_CTL_ENUM("Limiter Transient Window", - WM8776_LIMITER, 4, 2, 0, 7, 0x7, - LC_CONTROL_LIMITER), - WM8776_FIELD_CTL_VOLUME("Limiter Maximum Attenuation", - WM8776_LIMITER, 0, 6, 3, 12, 0xf, - LC_CONTROL_LIMITER, - wm8776_maxatten_lim_db_scale), - WM8776_FIELD_CTL_VOLUME("ALC Target Level", - WM8776_ALCCTRL1, 0, 11, 0, 15, 0xf, - LC_CONTROL_ALC, wm8776_lct_db_scale), - WM8776_FIELD_CTL_ENUM("ALC Attack Time", - WM8776_ALCCTRL3, 0, 2, 0, 10, 0xf, - LC_CONTROL_ALC), - WM8776_FIELD_CTL_ENUM("ALC Decay Time", - WM8776_ALCCTRL3, 4, 3, 0, 10, 0xf, - LC_CONTROL_ALC), - WM8776_FIELD_CTL_VOLUME("ALC Maximum Gain", - WM8776_ALCCTRL1, 4, 7, 1, 7, 0x7, - LC_CONTROL_ALC, wm8776_maxgain_db_scale), - WM8776_FIELD_CTL_VOLUME("ALC Maximum Attenuation", - WM8776_LIMITER, 0, 10, 10, 15, 0xf, - LC_CONTROL_ALC, wm8776_maxatten_alc_db_scale), - WM8776_FIELD_CTL_ENUM("ALC Hold Time", - WM8776_ALCCTRL2, 0, 0, 0, 15, 0xf, - LC_CONTROL_ALC), - WM8776_BIT_SWITCH("Noise Gate Capture Switch", - WM8776_NOISEGATE, WM8776_NGAT, 0, - LC_CONTROL_ALC), - WM8776_FIELD_CTL_VOLUME("Noise Gate Threshold", - WM8776_NOISEGATE, 2, 0, 0, 7, 0x7, - LC_CONTROL_ALC, wm8776_ngth_db_scale), -}; - -static int xonar_ds_control_filter(struct snd_kcontrol_new *template) -{ - if (!strncmp(template->name, "CD Capture ", 11)) - return 1; /* no CD input */ - return 0; -} - -static int xonar_ds_mixer_init(struct oxygen *chip) -{ - struct xonar_wm87x6 *data = chip->model_data; - unsigned int i; - struct snd_kcontrol *ctl; - int err; - - for (i = 0; i < ARRAY_SIZE(ds_controls); ++i) { - ctl = snd_ctl_new1(&ds_controls[i], chip); - if (!ctl) - return -ENOMEM; - err = snd_ctl_add(chip->card, ctl); - if (err < 0) - return err; - } - BUILD_BUG_ON(ARRAY_SIZE(lc_controls) != ARRAY_SIZE(data->lc_controls)); - for (i = 0; i < ARRAY_SIZE(lc_controls); ++i) { - ctl = snd_ctl_new1(&lc_controls[i], chip); - if (!ctl) - return -ENOMEM; - err = snd_ctl_add(chip->card, ctl); - if (err < 0) - return err; - data->lc_controls[i] = ctl; - } - return 0; -} - -static const struct oxygen_model model_xonar_ds = { - .shortname = "Xonar DS", - .longname = "Asus Virtuoso 200", - .chip = "AV200", - .init = xonar_ds_init, - .control_filter = xonar_ds_control_filter, - .mixer_init = xonar_ds_mixer_init, - .cleanup = xonar_ds_cleanup, - .suspend = xonar_ds_suspend, - .resume = xonar_ds_resume, - .pcm_hardware_filter = wm8776_adc_hardware_filter, - .get_i2s_mclk = oxygen_default_i2s_mclk, - .set_dac_params = set_wm87x6_dac_params, - .set_adc_params = set_wm8776_adc_params, - .update_dac_volume = update_wm87x6_volume, - .update_dac_mute = update_wm87x6_mute, - .gpio_changed = xonar_ds_gpio_changed, - .dac_tlv = wm87x6_dac_db_scale, - .model_data_size = sizeof(struct xonar_wm87x6), - .device_config = PLAYBACK_0_TO_I2S | - PLAYBACK_1_TO_SPDIF | - CAPTURE_0_FROM_I2S_1, - .dac_channels = 8, - .dac_volume_min = 255 - 2*60, - .dac_volume_max = 255, - .function_flags = OXYGEN_FUNCTION_SPI, - .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, - .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, -}; - -int __devinit get_xonar_wm87x6_model(struct oxygen *chip, - const struct pci_device_id *id) -{ - switch (id->subdevice) { - case 0x838e: - chip->model = model_xonar_ds; - break; - default: - return -EINVAL; - } - return 0; -}