diff --git a/[refs] b/[refs] index 4325fb2c1b89..9a0b2c0dd32e 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 12bc738596ffe4e7f566e13856a0d37ba229b539 +refs/heads/master: 6423f9ea8035138d70bae1a278d3b57b743f8b3e diff --git a/trunk/Documentation/sound/alsa/ALSA-Configuration.txt b/trunk/Documentation/sound/alsa/ALSA-Configuration.txt index 5c08d96f407c..012858d2b119 100644 --- a/trunk/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/trunk/Documentation/sound/alsa/ALSA-Configuration.txt @@ -460,25 +460,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. The power-management is supported. - Module snd-ctxfi - ---------------- - - Module for Creative Sound Blaster X-Fi boards (20k1 / 20k2 chips) - * Creative Sound Blaster X-Fi Titanium Fatal1ty Champion Series - * Creative Sound Blaster X-Fi Titanium Fatal1ty Professional Series - * Creative Sound Blaster X-Fi Titanium Professional Audio - * Creative Sound Blaster X-Fi Titanium - * Creative Sound Blaster X-Fi Elite Pro - * Creative Sound Blaster X-Fi Platinum - * Creative Sound Blaster X-Fi Fatal1ty - * Creative Sound Blaster X-Fi XtremeGamer - * Creative Sound Blaster X-Fi XtremeMusic - - reference_rate - reference sample rate, 44100 or 48000 (default) - multiple - multiple to ref. sample rate, 1 or 2 (default) - - This module supports multiple cards. - Module snd-darla20 ------------------ @@ -944,7 +925,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. * Onkyo SE-90PCI * Onkyo SE-200PCI * ESI Juli@ - * ESI Maya44 * Hercules Fortissimo IV * EGO-SYS WaveTerminal 192M @@ -953,7 +933,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. prodigy71xt, prodigy71hifi, prodigyhd2, prodigy192, juli, aureon51, aureon71, universe, ap192, k8x800, phase22, phase28, ms300, av710, se200pci, se90pci, - fortissimo4, sn25p, WT192M, maya44 + fortissimo4, sn25p, WT192M This module supports multiple cards and autoprobe. @@ -1113,13 +1093,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. This module supports multiple cards. The driver requires the firmware loader support on kernel. - Module snd-lx6464es - ------------------- - - Module for Digigram LX6464ES boards - - This module supports multiple cards. - Module snd-maestro3 ------------------- @@ -1570,15 +1543,13 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. Module snd-sc6000 ----------------- - Module for Gallant SC-6000 soundcard and later models: SC-6600 - and SC-7000. + Module for Gallant SC-6000 soundcard. port - Port # (0x220 or 0x240) mss_port - MSS Port # (0x530 or 0xe80) irq - IRQ # (5,7,9,10,11) mpu_irq - MPU-401 IRQ # (5,7,9,10) ,0 - no MPU-401 irq dma - DMA # (1,3,0) - joystick - Enable gameport - 0 = disable (default), 1 = enable This module supports multiple cards. @@ -1888,8 +1859,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, HDAV1.3 (Deluxe), Essence ST - (Deluxe) and Essence STX. + i.e., Xonar D1, DX, D2, D2X, HDAV1.3 (Deluxe), and Essence STX. This module supports autoprobe and multiple cards. diff --git a/trunk/Documentation/sound/alsa/HD-Audio-Models.txt b/trunk/Documentation/sound/alsa/HD-Audio-Models.txt index 0d8d23581c44..322869fc8a9e 100644 --- a/trunk/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/trunk/Documentation/sound/alsa/HD-Audio-Models.txt @@ -36,7 +36,6 @@ ALC260 acer Acer TravelMate will Will laptops (PB V7900) replacer Replacer 672V - favorit100 Maxdata Favorit 100XS basic fixed pin assignment (old default model) test for testing/debugging purpose, almost all controls can adjusted. Appearing only when compiled with @@ -86,11 +85,10 @@ ALC269 eeepc-p703 ASUS Eeepc P703 P900A eeepc-p901 ASUS Eeepc P901 S101 fujitsu FSC Amilo - lifebook Fujitsu Lifebook S6420 auto auto-config reading BIOS (default) -ALC662/663/272 -============== +ALC662/663 +========== 3stack-dig 3-stack (2-channel) with SPDIF 3stack-6ch 3-stack (6-channel) 3stack-6ch-dig 3-stack (6-channel) with SPDIF @@ -109,9 +107,6 @@ ALC662/663/272 asus-mode4 ASUS asus-mode5 ASUS asus-mode6 ASUS - dell Dell with ALC272 - dell-zm1 Dell ZM1 with ALC272 - samsung-nc10 Samsung NC10 mini notebook auto auto-config reading BIOS (default) ALC882/885 @@ -123,7 +118,6 @@ ALC882/885 asus-a7j ASUS A7J asus-a7m ASUS A7M macpro MacPro support - mb5 Macbook 5,1 mbp3 Macbook Pro rev3 imac24 iMac 24'' with jack detection w2jc ASUS W2JC @@ -139,13 +133,10 @@ ALC883/888 acer Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc) acer-aspire Acer Aspire 9810 acer-aspire-4930g Acer Aspire 4930G - acer-aspire-6530g Acer Aspire 6530G - acer-aspire-8930g Acer Aspire 8930G medion Medion Laptops medion-md2 Medion MD2 targa-dig Targa/MSI - targa-2ch-dig Targa/MSI with 2-channel - targa-8ch-dig Targa/MSI with 8-channel (MSI GX620) + targa-2ch-dig Targs/MSI with 2-channel laptop-eapd 3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE) lenovo-101e Lenovo 101E lenovo-nb0763 Lenovo NB0763 @@ -159,9 +150,6 @@ ALC883/888 fujitsu-pi2515 Fujitsu AMILO Pi2515 fujitsu-xa3530 Fujitsu AMILO XA3530 3stack-6ch-intel Intel DG33* boards - asus-p5q ASUS P5Q-EM boards - mb31 MacBook 3,1 - sony-vaio-tt Sony VAIO TT auto auto-config reading BIOS (default) ALC861/660 @@ -360,7 +348,6 @@ STAC92HD71B* hp-m4 HP mini 1000 hp-dv5 HP dv series hp-hdx HP HDX series - hp-dv4-1222nr HP dv4-1222nr (with LED support) auto BIOS setup (default) STAC92HD73* diff --git a/trunk/Documentation/sound/alsa/Procfile.txt b/trunk/Documentation/sound/alsa/Procfile.txt index 381908d8ca42..cfac20cf9e33 100644 --- a/trunk/Documentation/sound/alsa/Procfile.txt +++ b/trunk/Documentation/sound/alsa/Procfile.txt @@ -88,34 +88,26 @@ card*/pcm*/info substreams, etc. card*/pcm*/xrun_debug - This file appears when CONFIG_SND_DEBUG=y and - CONFIG_PCM_XRUN_DEBUG=y. - This shows the status of xrun (= buffer overrun/xrun) and - invalid PCM position debug/check of ALSA PCM middle layer. - It takes an integer value, can be changed by writing to this - file, such as - - # cat 5 > /proc/asound/card0/pcm0p/xrun_debug - - The value consists of the following bit flags: - bit 0 = Enable XRUN/jiffies debug messages - bit 1 = Show stack trace at XRUN / jiffies check - bit 2 = Enable additional jiffies check - - When the bit 0 is set, the driver will show the messages to - kernel log when an xrun is detected. The debug message is - shown also when the invalid H/W pointer is detected at the - update of periods (usually called from the interrupt + This file appears when CONFIG_SND_DEBUG=y. + This shows the status of xrun (= buffer overrun/xrun) debug of + ALSA PCM middle layer, as an integer from 0 to 2. The value + can be changed by writing to this file, such as + + # cat 2 > /proc/asound/card0/pcm0p/xrun_debug + + When this value is greater than 0, the driver will show the + messages to kernel log when an xrun is detected. The debug + message is shown also when the invalid H/W pointer is detected + at the update of periods (usually called from the interrupt handler). - When the bit 1 is set, the driver will show the stack trace - additionally. This may help the debugging. + When this value is greater than 1, the driver will show the + stack trace additionally. This may help the debugging. - Since 2.6.30, this option can enable the hwptr check using + Since 2.6.30, this option also enables the hwptr check using jiffies. This detects spontaneous invalid pointer callback values, but can be lead to too much corrections for a (mostly buggy) hardware that doesn't give smooth pointer updates. - This feature is enabled via the bit 2. card*/pcm*/sub*/info The general information of this PCM sub-stream. diff --git a/trunk/Documentation/sound/alsa/README.maya44 b/trunk/Documentation/sound/alsa/README.maya44 deleted file mode 100644 index 0e41576fa13e..000000000000 --- a/trunk/Documentation/sound/alsa/README.maya44 +++ /dev/null @@ -1,163 +0,0 @@ -NOTE: The following is the original document of Rainer's patch that the -current maya44 code based on. Some contents might be obsoleted, but I -keep here as reference -- tiwai - ----------------------------------------------------------------- - -STATE OF DEVELOPMENT: - -This driver is being developed on the initiative of Piotr Makowski (oponek@gmail.com) and financed by Lars Bergmann. -Development is carried out by Rainer Zimmermann (mail@lightshed.de). - -ESI provided a sample Maya44 card for the development work. - -However, unfortunately it has turned out difficult to get detailed programming information, so I (Rainer Zimmermann) had to find out some card-specific information by experiment and conjecture. Some information (in particular, several GPIO bits) is still missing. - -This is the first testing version of the Maya44 driver released to the alsa-devel mailing list (Feb 5, 2008). - - -The following functions work, as tested by Rainer Zimmermann and Piotr Makowski: - -- playback and capture at all sampling rates -- input/output level -- crossmixing -- line/mic switch -- phantom power switch -- analogue monitor a.k.a bypass - - -The following functions *should* work, but are not fully tested: - -- Channel 3+4 analogue - S/PDIF input switching -- S/PDIF output -- all inputs/outputs on the M/IO/DIO extension card -- internal/external clock selection - - -*In particular, we would appreciate testing of these functions by anyone who has access to an M/IO/DIO extension card.* - - -Things that do not seem to work: - -- The level meters ("multi track") in 'alsamixer' do not seem to react to signals in (if this is a bug, it would probably be in the existing ICE1724 code). - -- Ardour 2.1 seems to work only via JACK, not using ALSA directly or via OSS. This still needs to be tracked down. - - -DRIVER DETAILS: - -the following files were added: - -pci/ice1724/maya44.c - Maya44 specific code -pci/ice1724/maya44.h -pci/ice1724/ice1724.patch -pci/ice1724/ice1724.h.patch - PROPOSED patch to ice1724.h (see SAMPLING RATES) -i2c/other/wm8776.c - low-level access routines for Wolfson WM8776 codecs -include/wm8776.h - - -Note that the wm8776.c code is meant to be card-independent and does not actually register the codec with the ALSA infrastructure. -This is done in maya44.c, mainly because some of the WM8776 controls are used in Maya44-specific ways, and should be named appropriately. - - -the following files were created in pci/ice1724, simply #including the corresponding file from the alsa-kernel tree: - -wtm.h -vt1720_mobo.h -revo.h -prodigy192.h -pontis.h -phase.h -maya44.h -juli.h -aureon.h -amp.h -envy24ht.h -se.h -prodigy_hifi.h - - -*I hope this is the correct way to do things.* - - -SAMPLING RATES: - -The Maya44 card (or more exactly, the Wolfson WM8776 codecs) allow a maximum sampling rate of 192 kHz for playback and 92 kHz for capture. - -As the ICE1724 chip only allows one global sampling rate, this is handled as follows: - -* setting the sampling rate on any open PCM device on the maya44 card will always set the *global* sampling rate for all playback and capture channels. - -* In the current state of the driver, setting rates of up to 192 kHz is permitted even for capture devices. - -*AVOID CAPTURING AT RATES ABOVE 96kHz*, even though it may appear to work. The codec cannot actually capture at such rates, meaning poor quality. - - -I propose some additional code for limiting the sampling rate when setting on a capture pcm device. However because of the global sampling rate, this logic would be somewhat problematic. - -The proposed code (currently deactivated) is in ice1712.h.patch, ice1724.c and maya44.c (in pci/ice1712). - - -SOUND DEVICES: - -PCM devices correspond to inputs/outputs as follows (assuming Maya44 is card #0): - -hw:0,0 input - stereo, analog input 1+2 -hw:0,0 output - stereo, analog output 1+2 -hw:0,1 input - stereo, analog input 3+4 OR S/PDIF input -hw:0,1 output - stereo, analog output 3+4 (and SPDIF out) - - -NAMING OF MIXER CONTROLS: - -(for more information about the signal flow, please refer to the block diagram on p.24 of the ESI Maya44 manual, or in the ESI windows software). - - -PCM: (digital) output level for channel 1+2 -PCM 1: same for channel 3+4 - -Mic Phantom+48V: switch for +48V phantom power for electrostatic microphones on input 1/2. - Make sure this is not turned on while any other source is connected to input 1/2. - It might damage the source and/or the maya44 card. - -Mic/Line input: if switch is is on, input jack 1/2 is microphone input (mono), otherwise line input (stereo). - -Bypass: analogue bypass from ADC input to output for channel 1+2. Same as "Monitor" in the windows driver. -Bypass 1: same for channel 3+4. - -Crossmix: cross-mixer from channels 1+2 to channels 3+4 -Crossmix 1: cross-mixer from channels 3+4 to channels 1+2 - -IEC958 Output: switch for S/PDIF output. - This is not supported by the ESI windows driver. - S/PDIF should output the same signal as channel 3+4. [untested!] - - -Digitial output selectors: - - These switches allow a direct digital routing from the ADCs to the DACs. - Each switch determines where the digital input data to one of the DACs comes from. - They are not supported by the ESI windows driver. - For normal operation, they should all be set to "PCM out". - -H/W: Output source channel 1 -H/W 1: Output source channel 2 -H/W 2: Output source channel 3 -H/W 3: Output source channel 4 - -H/W 4 ... H/W 9: unknown function, left in to enable testing. - Possibly some of these control S/PDIF output(s). - If these turn out to be unused, they will go away in later driver versions. - -Selectable values for each of the digital output selectors are: - "PCM out" -> DAC output of the corresponding channel (default setting) - "Input 1"... - "Input 4" -> direct routing from ADC output of the selected input channel - - --------- - -Feb 14, 2008 -Rainer Zimmermann -mail@lightshed.de - diff --git a/trunk/Documentation/sound/alsa/soc/dapm.txt b/trunk/Documentation/sound/alsa/soc/dapm.txt index 9ac842be9b4f..9e6763264a2e 100644 --- a/trunk/Documentation/sound/alsa/soc/dapm.txt +++ b/trunk/Documentation/sound/alsa/soc/dapm.txt @@ -62,7 +62,6 @@ Audio DAPM widgets fall into a number of types:- o Mic - Mic (and optional Jack) o Line - Line Input/Output (and optional Jack) o Speaker - Speaker - o Supply - Power or clock supply widget used by other widgets. o Pre - Special PRE widget (exec before all others) o Post - Special POST widget (exec after all others) diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index e8cb115e33b8..cf4abddfc8a4 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -4574,8 +4574,7 @@ F: drivers/pcmcia/pxa2xx* F: drivers/spi/pxa2xx* F: drivers/usb/gadget/pxa2* F: include/sound/pxa2xx-lib.h -F: sound/arm/pxa* -F: sound/soc/pxa +F: sound/soc/pxa/pxa2xx* PXA168 SUPPORT P: Eric Miao @@ -5303,12 +5302,11 @@ P: Liam Girdwood M: lrg@slimlogic.co.uk P: Mark Brown M: broonie@opensource.wolfsonmicro.com -T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git +T: git git://opensource.wolfsonmicro.com/linux-2.6-asoc L: alsa-devel@alsa-project.org (subscribers-only) W: http://alsa-project.org/main/index.php/ASoC S: Supported F: sound/soc/ -F: include/sound/soc* SPARC + UltraSPARC (sparc/sparc64) P: David S. Miller diff --git a/trunk/arch/powerpc/include/asm/mpc52xx_psc.h b/trunk/arch/powerpc/include/asm/mpc52xx_psc.h index fb8412057450..a218da6bec7c 100644 --- a/trunk/arch/powerpc/include/asm/mpc52xx_psc.h +++ b/trunk/arch/powerpc/include/asm/mpc52xx_psc.h @@ -28,10 +28,6 @@ #define MPC52xx_PSC_MAXNUM 6 /* Programmable Serial Controller (PSC) status register bits */ -#define MPC52xx_PSC_SR_UNEX_RX 0x0001 -#define MPC52xx_PSC_SR_DATA_VAL 0x0002 -#define MPC52xx_PSC_SR_DATA_OVR 0x0004 -#define MPC52xx_PSC_SR_CMDSEND 0x0008 #define MPC52xx_PSC_SR_CDE 0x0080 #define MPC52xx_PSC_SR_RXRDY 0x0100 #define MPC52xx_PSC_SR_RXFULL 0x0200 @@ -65,12 +61,6 @@ #define MPC52xx_PSC_RXTX_FIFO_EMPTY 0x0001 /* PSC interrupt status/mask bits */ -#define MPC52xx_PSC_IMR_UNEX_RX_SLOT 0x0001 -#define MPC52xx_PSC_IMR_DATA_VALID 0x0002 -#define MPC52xx_PSC_IMR_DATA_OVR 0x0004 -#define MPC52xx_PSC_IMR_CMD_SEND 0x0008 -#define MPC52xx_PSC_IMR_ERROR 0x0040 -#define MPC52xx_PSC_IMR_DEOF 0x0080 #define MPC52xx_PSC_IMR_TXRDY 0x0100 #define MPC52xx_PSC_IMR_RXRDY 0x0200 #define MPC52xx_PSC_IMR_DB 0x0400 @@ -127,7 +117,6 @@ #define MPC52xx_PSC_SICR_SIM_FIR (0x6 << 24) #define MPC52xx_PSC_SICR_SIM_CODEC_24 (0x7 << 24) #define MPC52xx_PSC_SICR_SIM_CODEC_32 (0xf << 24) -#define MPC52xx_PSC_SICR_AWR (1 << 30) #define MPC52xx_PSC_SICR_GENCLK (1 << 23) #define MPC52xx_PSC_SICR_I2S (1 << 22) #define MPC52xx_PSC_SICR_CLKPOL (1 << 21) diff --git a/trunk/include/linux/pci_ids.h b/trunk/include/linux/pci_ids.h index 28fe766393a3..0f71812d67d3 100644 --- a/trunk/include/linux/pci_ids.h +++ b/trunk/include/linux/pci_ids.h @@ -1005,7 +1005,6 @@ #define PCI_DEVICE_ID_PLX_PCI200SYN 0x3196 #define PCI_DEVICE_ID_PLX_9030 0x9030 #define PCI_DEVICE_ID_PLX_9050 0x9050 -#define PCI_DEVICE_ID_PLX_9056 0x9056 #define PCI_DEVICE_ID_PLX_9080 0x9080 #define PCI_DEVICE_ID_PLX_GTEK_SERIAL2 0xa001 @@ -1315,13 +1314,6 @@ #define PCI_VENDOR_ID_CREATIVE 0x1102 /* duplicate: ECTIVA */ #define PCI_DEVICE_ID_CREATIVE_EMU10K1 0x0002 -#define PCI_DEVICE_ID_CREATIVE_20K1 0x0005 -#define PCI_DEVICE_ID_CREATIVE_20K2 0x000b -#define PCI_SUBDEVICE_ID_CREATIVE_SB0760 0x0024 -#define PCI_SUBDEVICE_ID_CREATIVE_SB08801 0x0041 -#define PCI_SUBDEVICE_ID_CREATIVE_SB08802 0x0042 -#define PCI_SUBDEVICE_ID_CREATIVE_SB08803 0x0043 -#define PCI_SUBDEVICE_ID_CREATIVE_HENDRIX 0x6000 #define PCI_VENDOR_ID_ECTIVA 0x1102 /* duplicate: CREATIVE */ #define PCI_DEVICE_ID_ECTIVA_EV1938 0x8938 @@ -1855,10 +1847,6 @@ #define PCI_SUBDEVICE_ID_HYPERCOPE_METRO 0x0107 #define PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2 0x0108 -#define PCI_VENDOR_ID_DIGIGRAM 0x1369 -#define PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_SERIAL_SUBSYSTEM 0xc001 -#define PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_CAE_SERIAL_SUBSYSTEM 0xc002 - #define PCI_VENDOR_ID_KAWASAKI 0x136b #define PCI_DEVICE_ID_MCHIP_KL5A72002 0xff01 diff --git a/trunk/include/sound/asound.h b/trunk/include/sound/asound.h index 82aed3f47534..6add80fc2512 100644 --- a/trunk/include/sound/asound.h +++ b/trunk/include/sound/asound.h @@ -255,7 +255,6 @@ typedef int __bitwise snd_pcm_subformat_t; #define SNDRV_PCM_INFO_HALF_DUPLEX 0x00100000 /* only half duplex */ #define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000 /* playback and capture stream are somewhat correlated */ #define SNDRV_PCM_INFO_SYNC_START 0x00400000 /* pcm support some kind of sync go */ -#define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 /* internal kernel flag - FIFO size is in frames */ typedef int __bitwise snd_pcm_state_t; #define SNDRV_PCM_STATE_OPEN ((__force snd_pcm_state_t) 0) /* stream is open */ diff --git a/trunk/include/sound/core.h b/trunk/include/sound/core.h index 309cb9659a05..3dea79829acc 100644 --- a/trunk/include/sound/core.h +++ b/trunk/include/sound/core.h @@ -300,10 +300,19 @@ int snd_card_create(int idx, const char *id, struct module *module, int extra_size, struct snd_card **card_ret); +static inline __deprecated +struct snd_card *snd_card_new(int idx, const char *id, + struct module *module, int extra_size) +{ + struct snd_card *card; + if (snd_card_create(idx, id, module, extra_size, &card) < 0) + return NULL; + return card; +} + int snd_card_disconnect(struct snd_card *card); int snd_card_free(struct snd_card *card); int snd_card_free_when_closed(struct snd_card *card); -void snd_card_set_id(struct snd_card *card, const char *id); int snd_card_register(struct snd_card *card); int snd_card_info_init(void); int snd_card_info_done(void); diff --git a/trunk/include/sound/driver.h b/trunk/include/sound/driver.h new file mode 100644 index 000000000000..f0359437d01a --- /dev/null +++ b/trunk/include/sound/driver.h @@ -0,0 +1 @@ +#warning "This file is deprecated" diff --git a/trunk/include/sound/pcm.h b/trunk/include/sound/pcm.h index 23893523dc8c..c17296891617 100644 --- a/trunk/include/sound/pcm.h +++ b/trunk/include/sound/pcm.h @@ -98,7 +98,6 @@ struct snd_pcm_ops { #define SNDRV_PCM_IOCTL1_INFO 1 #define SNDRV_PCM_IOCTL1_CHANNEL_INFO 2 #define SNDRV_PCM_IOCTL1_GSTATE 3 -#define SNDRV_PCM_IOCTL1_FIFO_SIZE 4 #define SNDRV_PCM_TRIGGER_STOP 0 #define SNDRV_PCM_TRIGGER_START 1 @@ -271,7 +270,6 @@ struct snd_pcm_runtime { snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */ snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */ unsigned long hw_ptr_jiffies; /* Time when hw_ptr is updated */ - snd_pcm_sframes_t delay; /* extra delay; typically FIFO size */ /* -- HW params -- */ snd_pcm_access_t access; /* access mode */ @@ -488,6 +486,80 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream); void snd_pcm_vma_notify_data(void *client, void *data); int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area); +#if BITS_PER_LONG >= 64 + +static inline void div64_32(u_int64_t *n, u_int32_t div, u_int32_t *rem) +{ + *rem = *n % div; + *n /= div; +} + +#elif defined(i386) + +static inline void div64_32(u_int64_t *n, u_int32_t div, u_int32_t *rem) +{ + u_int32_t low, high; + low = *n & 0xffffffff; + high = *n >> 32; + if (high) { + u_int32_t high1 = high % div; + high /= div; + asm("divl %2":"=a" (low), "=d" (*rem):"rm" (div), "a" (low), "d" (high1)); + *n = (u_int64_t)high << 32 | low; + } else { + *n = low / div; + *rem = low % div; + } +} +#else + +static inline void divl(u_int32_t high, u_int32_t low, + u_int32_t div, + u_int32_t *q, u_int32_t *r) +{ + u_int64_t n = (u_int64_t)high << 32 | low; + u_int64_t d = (u_int64_t)div << 31; + u_int32_t q1 = 0; + int c = 32; + while (n > 0xffffffffU) { + q1 <<= 1; + if (n >= d) { + n -= d; + q1 |= 1; + } + d >>= 1; + c--; + } + q1 <<= c; + if (n) { + low = n; + *q = q1 | (low / div); + *r = low % div; + } else { + *r = 0; + *q = q1; + } + return; +} + +static inline void div64_32(u_int64_t *n, u_int32_t div, u_int32_t *rem) +{ + u_int32_t low, high; + low = *n & 0xffffffff; + high = *n >> 32; + if (high) { + u_int32_t high1 = high % div; + u_int32_t low1 = low; + high /= div; + divl(high1, low1, div, &low, rem); + *n = (u_int64_t)high << 32 | low; + } else { + *n = low / div; + *rem = low % div; + } +} +#endif + /* * PCM library */ diff --git a/trunk/include/sound/soc-dai.h b/trunk/include/sound/soc-dai.h index 352d7eee9b6d..13676472ddfc 100644 --- a/trunk/include/sound/soc-dai.h +++ b/trunk/include/sound/soc-dai.h @@ -44,6 +44,24 @@ struct snd_pcm_substream; #define SND_SOC_DAIFMT_CONT (0 << 4) /* continuous clock */ #define SND_SOC_DAIFMT_GATED (1 << 4) /* clock is gated */ +/* + * DAI Left/Right Clocks. + * + * Specifies whether the DAI can support different samples for similtanious + * playback and capture. This usually requires a seperate physical frame + * clock for playback and capture. + */ +#define SND_SOC_DAIFMT_SYNC (0 << 5) /* Tx FRM = Rx FRM */ +#define SND_SOC_DAIFMT_ASYNC (1 << 5) /* Tx FRM ~ Rx FRM */ + +/* + * TDM + * + * Time Division Multiplexing. Allows PCM data to be multplexed with other + * data on the DAI. + */ +#define SND_SOC_DAIFMT_TDM (1 << 6) + /* * DAI hardware signal inversions. * @@ -78,10 +96,6 @@ struct snd_pcm_substream; #define SND_SOC_CLOCK_IN 0 #define SND_SOC_CLOCK_OUT 1 -#define SND_SOC_STD_AC97_FMTS (SNDRV_PCM_FMTBIT_S16_LE |\ - SNDRV_PCM_FMTBIT_S32_LE |\ - SNDRV_PCM_FMTBIT_S32_BE) - struct snd_soc_dai_ops; struct snd_soc_dai; struct snd_ac97_bus_ops; @@ -194,7 +208,6 @@ struct snd_soc_dai { /* DAI capabilities */ struct snd_soc_pcm_stream capture; struct snd_soc_pcm_stream playback; - unsigned int symmetric_rates:1; /* DAI runtime info */ struct snd_pcm_runtime *runtime; @@ -206,8 +219,11 @@ struct snd_soc_dai { /* DAI private data */ void *private_data; - /* parent platform */ - struct snd_soc_platform *platform; + /* parent codec/platform */ + union { + struct snd_soc_codec *codec; + struct snd_soc_platform *platform; + }; struct list_head list; }; diff --git a/trunk/include/sound/soc-dapm.h b/trunk/include/sound/soc-dapm.h index ec8a45f9a069..a7def6a9a030 100644 --- a/trunk/include/sound/soc-dapm.h +++ b/trunk/include/sound/soc-dapm.h @@ -140,30 +140,16 @@ #define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \ { .id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \ .shift = wshift, .invert = winvert} -#define SND_SOC_DAPM_DAC_E(wname, stname, wreg, wshift, winvert, \ - wevent, wflags) \ -{ .id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \ - .shift = wshift, .invert = winvert, \ - .event = wevent, .event_flags = wflags} #define SND_SOC_DAPM_ADC(wname, stname, wreg, wshift, winvert) \ { .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \ .shift = wshift, .invert = winvert} -#define SND_SOC_DAPM_ADC_E(wname, stname, wreg, wshift, winvert, \ - wevent, wflags) \ -{ .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \ - .shift = wshift, .invert = winvert, \ - .event = wevent, .event_flags = wflags} -/* generic widgets */ +/* generic register modifier widget */ #define SND_SOC_DAPM_REG(wid, wname, wreg, wshift, wmask, won_val, woff_val) \ { .id = wid, .name = wname, .kcontrols = NULL, .num_kcontrols = 0, \ .reg = -((wreg) + 1), .shift = wshift, .mask = wmask, \ .on_val = won_val, .off_val = woff_val, .event = dapm_reg_event, \ .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD} -#define SND_SOC_DAPM_SUPPLY(wname, wreg, wshift, winvert, wevent, wflags) \ -{ .id = snd_soc_dapm_supply, .name = wname, .reg = wreg, \ - .shift = wshift, .invert = winvert, .event = wevent, \ - .event_flags = wflags} /* dapm kcontrol types */ #define SOC_DAPM_SINGLE(xname, reg, shift, max, invert) \ @@ -279,6 +265,8 @@ int snd_soc_dapm_add_routes(struct snd_soc_codec *codec, /* dapm events */ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream, int event); +int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev, + enum snd_soc_bias_level level); /* dapm sys fs - used by the core */ int snd_soc_dapm_sys_add(struct device *dev); @@ -310,7 +298,6 @@ enum snd_soc_dapm_type { snd_soc_dapm_vmid, /* codec bias/vmid - to minimise pops */ snd_soc_dapm_pre, /* machine specific pre widget - exec first */ snd_soc_dapm_post, /* machine specific post widget - exec last */ - snd_soc_dapm_supply, /* power/clock supply */ }; /* @@ -370,8 +357,6 @@ struct snd_soc_dapm_widget { unsigned char suspend:1; /* was active before suspend */ unsigned char pmdown:1; /* waiting for timeout */ - int (*power_check)(struct snd_soc_dapm_widget *w); - /* external events */ unsigned short event_flags; /* flags to specify event types */ int (*event)(struct snd_soc_dapm_widget*, struct snd_kcontrol *, int); @@ -383,9 +368,6 @@ struct snd_soc_dapm_widget { /* widget input and outputs */ struct list_head sources; struct list_head sinks; - - /* used during DAPM updates */ - struct list_head power_list; }; #endif diff --git a/trunk/include/sound/soc.h b/trunk/include/sound/soc.h index cf6111d72b17..a40bc6f316fc 100644 --- a/trunk/include/sound/soc.h +++ b/trunk/include/sound/soc.h @@ -118,14 +118,6 @@ .info = snd_soc_info_volsw, \ .get = xhandler_get, .put = xhandler_put, \ .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) } -#define SOC_DOUBLE_EXT(xname, xreg, shift_left, shift_right, xmax, xinvert,\ - xhandler_get, xhandler_put) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ - .info = snd_soc_info_volsw, \ - .get = xhandler_get, .put = xhandler_put, \ - .private_value = (unsigned long)&(struct soc_mixer_control) \ - {.reg = xreg, .shift = shift_left, .rshift = shift_right, \ - .max = xmax, .invert = xinvert} } #define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert,\ xhandler_get, xhandler_put, tlv_array) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ @@ -214,6 +206,10 @@ void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count, struct snd_soc_jack_gpio *gpios); #endif +/* codec IO */ +#define snd_soc_read(codec, reg) codec->read(codec, reg) +#define snd_soc_write(codec, reg, value) codec->write(codec, reg, value) + /* codec register bit access */ int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, unsigned short mask, unsigned short value); @@ -335,7 +331,6 @@ struct snd_soc_codec { struct module *owner; struct mutex mutex; struct device *dev; - struct snd_soc_device *socdev; struct list_head list; @@ -369,8 +364,6 @@ struct snd_soc_codec { enum snd_soc_bias_level bias_level; enum snd_soc_bias_level suspend_bias_level; struct delayed_work delayed_work; - struct list_head up_list; - struct list_head down_list; /* codec DAI's */ struct snd_soc_dai *dai; @@ -424,12 +417,6 @@ struct snd_soc_dai_link { /* codec/machine specific init - e.g. add machine controls */ int (*init)(struct snd_soc_codec *codec); - /* Symmetry requirements */ - unsigned int symmetric_rates:1; - - /* Symmetry data - only valid if symmetry is being enforced */ - unsigned int rate; - /* DAI pcm */ struct snd_pcm *pcm; }; @@ -503,19 +490,6 @@ struct soc_enum { void *dapm; }; -/* codec IO */ -static inline unsigned int snd_soc_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - return codec->read(codec, reg); -} - -static inline unsigned int snd_soc_write(struct snd_soc_codec *codec, - unsigned int reg, unsigned int val) -{ - return codec->write(codec, reg, val); -} - #include #endif diff --git a/trunk/include/sound/wm9081.h b/trunk/include/sound/wm9081.h deleted file mode 100644 index e173ddbf6bd4..000000000000 --- a/trunk/include/sound/wm9081.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * linux/sound/wm9081.h -- Platform data for WM9081 - * - * Copyright 2009 Wolfson Microelectronics. PLC. - * - * 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. - */ - -#ifndef __LINUX_SND_WM_9081_H -#define __LINUX_SND_WM_9081_H - -struct wm9081_retune_mobile_setting { - const char *name; - unsigned int rate; - u16 config[20]; -}; - -struct wm9081_retune_mobile_config { - struct wm9081_retune_mobile_setting *configs; - int num_configs; -}; - -#endif diff --git a/trunk/sound/aoa/fabrics/layout.c b/trunk/sound/aoa/fabrics/layout.c index 586965f9605f..fbf5c933baa4 100644 --- a/trunk/sound/aoa/fabrics/layout.c +++ b/trunk/sound/aoa/fabrics/layout.c @@ -1037,7 +1037,7 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev) } ldev->selfptr_headphone.ptr = ldev; ldev->selfptr_lineout.ptr = ldev; - dev_set_drvdata(&sdev->ofdev.dev, ldev); + sdev->ofdev.dev.driver_data = ldev; list_add(&ldev->list, &layouts_list); layouts_list_items++; @@ -1081,7 +1081,7 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev) static int aoa_fabric_layout_remove(struct soundbus_dev *sdev) { - struct layout_dev *ldev = dev_get_drvdata(&sdev->ofdev.dev); + struct layout_dev *ldev = sdev->ofdev.dev.driver_data; int i; for (i=0; iofdev.dev); + struct layout_dev *ldev = sdev->ofdev.dev.driver_data; if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off) ldev->gpio.methods->all_amps_off(&ldev->gpio); @@ -1124,7 +1124,7 @@ static int aoa_fabric_layout_suspend(struct soundbus_dev *sdev, pm_message_t sta static int aoa_fabric_layout_resume(struct soundbus_dev *sdev) { - struct layout_dev *ldev = dev_get_drvdata(&sdev->ofdev.dev); + struct layout_dev *ldev = sdev->ofdev.dev.driver_data; if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off) ldev->gpio.methods->all_amps_restore(&ldev->gpio); diff --git a/trunk/sound/aoa/soundbus/i2sbus/core.c b/trunk/sound/aoa/soundbus/i2sbus/core.c index 4e3b819d4993..418c84c99d69 100644 --- a/trunk/sound/aoa/soundbus/i2sbus/core.c +++ b/trunk/sound/aoa/soundbus/i2sbus/core.c @@ -358,14 +358,14 @@ static int i2sbus_probe(struct macio_dev* dev, const struct of_device_id *match) return -ENODEV; } - dev_set_drvdata(&dev->ofdev.dev, control); + dev->ofdev.dev.driver_data = control; return 0; } static int i2sbus_remove(struct macio_dev* dev) { - struct i2sbus_control *control = dev_get_drvdata(&dev->ofdev.dev); + struct i2sbus_control *control = dev->ofdev.dev.driver_data; struct i2sbus_dev *i2sdev, *tmp; list_for_each_entry_safe(i2sdev, tmp, &control->list, item) @@ -377,7 +377,7 @@ static int i2sbus_remove(struct macio_dev* dev) #ifdef CONFIG_PM static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state) { - struct i2sbus_control *control = dev_get_drvdata(&dev->ofdev.dev); + struct i2sbus_control *control = dev->ofdev.dev.driver_data; struct codec_info_item *cii; struct i2sbus_dev* i2sdev; int err, ret = 0; @@ -407,7 +407,7 @@ static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state) static int i2sbus_resume(struct macio_dev* dev) { - struct i2sbus_control *control = dev_get_drvdata(&dev->ofdev.dev); + struct i2sbus_control *control = dev->ofdev.dev.driver_data; struct codec_info_item *cii; struct i2sbus_dev* i2sdev; int err, ret = 0; diff --git a/trunk/sound/core/Kconfig b/trunk/sound/core/Kconfig index 6061fb5f4e1c..7bbdda041a99 100644 --- a/trunk/sound/core/Kconfig +++ b/trunk/sound/core/Kconfig @@ -205,5 +205,3 @@ config SND_PCM_XRUN_DEBUG config SND_VMASTER bool - -source "sound/core/seq/Kconfig" diff --git a/trunk/sound/core/init.c b/trunk/sound/core/init.c index d5d40d78c409..fd56afe846ed 100644 --- a/trunk/sound/core/init.c +++ b/trunk/sound/core/init.c @@ -152,8 +152,15 @@ int snd_card_create(int idx, const char *xid, card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL); if (!card) return -ENOMEM; - if (xid) + if (xid) { + if (!snd_info_check_reserved_words(xid)) { + snd_printk(KERN_ERR + "given id string '%s' is reserved.\n", xid); + err = -EBUSY; + goto __error; + } strlcpy(card->id, xid, sizeof(card->id)); + } err = 0; mutex_lock(&snd_card_mutex); if (idx < 0) { @@ -476,28 +483,22 @@ int snd_card_free(struct snd_card *card) EXPORT_SYMBOL(snd_card_free); -static void snd_card_set_id_no_lock(struct snd_card *card, const char *nid) +static void choose_default_id(struct snd_card *card) { int i, len, idx_flag = 0, loops = SNDRV_CARDS; - const char *spos, *src; - char *id; + char *id, *spos; - if (nid == NULL) { - id = card->shortname; - spos = src = id; - while (*id != '\0') { - if (*id == ' ') - spos = id + 1; - id++; - } - } else { - spos = src = nid; + id = spos = card->shortname; + while (*id != '\0') { + if (*id == ' ') + spos = id + 1; + id++; } id = card->id; while (*spos != '\0' && !isalnum(*spos)) spos++; if (isdigit(*spos)) - *id++ = isalpha(src[0]) ? src[0] : 'D'; + *id++ = isalpha(card->shortname[0]) ? card->shortname[0] : 'D'; while (*spos != '\0' && (size_t)(id - card->id) < sizeof(card->id) - 1) { if (isalnum(*spos)) *id++ = *spos; @@ -512,7 +513,7 @@ static void snd_card_set_id_no_lock(struct snd_card *card, const char *nid) while (1) { if (loops-- == 0) { - snd_printk(KERN_ERR "unable to set card id (%s)\n", id); + snd_printk(KERN_ERR "unable to choose default card id (%s)\n", id); strcpy(card->id, card->proc_root->name); return; } @@ -538,33 +539,14 @@ static void snd_card_set_id_no_lock(struct snd_card *card, const char *nid) spos = id + len - 2; if ((size_t)len <= sizeof(card->id) - 2) spos++; - *(char *)spos++ = '_'; - *(char *)spos++ = '1'; - *(char *)spos++ = '\0'; + *spos++ = '_'; + *spos++ = '1'; + *spos++ = '\0'; idx_flag++; } } } -/** - * snd_card_set_id - set card identification name - * @card: soundcard structure - * @nid: new identification string - * - * This function sets the card identification and checks for name - * collisions. - */ -void snd_card_set_id(struct snd_card *card, const char *nid) -{ - /* check if user specified own card->id */ - if (card->id[0] != '\0') - return; - mutex_lock(&snd_card_mutex); - snd_card_set_id_no_lock(card, nid); - mutex_unlock(&snd_card_mutex); -} -EXPORT_SYMBOL(snd_card_set_id); - #ifndef CONFIG_SYSFS_DEPRECATED static ssize_t card_id_show_attr(struct device *dev, @@ -658,7 +640,8 @@ int snd_card_register(struct snd_card *card) mutex_unlock(&snd_card_mutex); return 0; } - snd_card_set_id_no_lock(card, card->id[0] == '\0' ? NULL : card->id); + if (card->id[0] == '\0') + choose_default_id(card); snd_cards[card->number] = card; mutex_unlock(&snd_card_mutex); init_info_for_card(card); diff --git a/trunk/sound/core/jack.c b/trunk/sound/core/jack.c index f705eec7372a..d54d1a05fe65 100644 --- a/trunk/sound/core/jack.c +++ b/trunk/sound/core/jack.c @@ -63,7 +63,7 @@ static int snd_jack_dev_register(struct snd_device *device) /* Default to the sound card device. */ if (!jack->input_dev->dev.parent) - jack->input_dev->dev.parent = snd_card_get_device_link(card); + jack->input_dev->dev.parent = card->dev; err = input_register_device(jack->input_dev); if (err == 0) diff --git a/trunk/sound/core/oss/pcm_oss.c b/trunk/sound/core/oss/pcm_oss.c index dbe406b82591..dda000b9684c 100644 --- a/trunk/sound/core/oss/pcm_oss.c +++ b/trunk/sound/core/oss/pcm_oss.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -618,7 +617,9 @@ static long snd_pcm_oss_bytes(struct snd_pcm_substream *substream, long frames) #else { u64 bsize = (u64)runtime->oss.buffer_bytes * (u64)bytes; - return div_u64(bsize, buffer_size); + u32 rem; + div64_32(&bsize, buffer_size, &rem); + return (long)bsize; } #endif } diff --git a/trunk/sound/core/pcm_lib.c b/trunk/sound/core/pcm_lib.c index 333e4dd29450..d659995ac3ac 100644 --- a/trunk/sound/core/pcm_lib.c +++ b/trunk/sound/core/pcm_lib.c @@ -22,7 +22,6 @@ #include #include -#include #include #include #include @@ -127,37 +126,24 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram } #ifdef CONFIG_SND_PCM_XRUN_DEBUG -#define xrun_debug(substream, mask) ((substream)->pstr->xrun_debug & (mask)) +#define xrun_debug(substream) ((substream)->pstr->xrun_debug) #else -#define xrun_debug(substream, mask) 0 +#define xrun_debug(substream) 0 #endif -#define dump_stack_on_xrun(substream) do { \ - if (xrun_debug(substream, 2)) \ - dump_stack(); \ +#define dump_stack_on_xrun(substream) do { \ + if (xrun_debug(substream) > 1) \ + dump_stack(); \ } while (0) -static void pcm_debug_name(struct snd_pcm_substream *substream, - char *name, size_t len) -{ - snprintf(name, len, "pcmC%dD%d%c:%d", - substream->pcm->card->number, - substream->pcm->device, - substream->stream ? 'c' : 'p', - substream->number); -} - static void xrun(struct snd_pcm_substream *substream) { - struct snd_pcm_runtime *runtime = substream->runtime; - - if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) - snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); - if (xrun_debug(substream, 1)) { - char name[16]; - pcm_debug_name(substream, name, sizeof(name)); - snd_printd(KERN_DEBUG "XRUN: %s\n", name); + if (xrun_debug(substream)) { + snd_printd(KERN_DEBUG "XRUN: pcmC%dD%d%c\n", + substream->pcm->card->number, + substream->pcm->device, + substream->stream ? 'c' : 'p'); dump_stack_on_xrun(substream); } } @@ -168,16 +154,16 @@ snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream, { snd_pcm_uframes_t pos; + if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) + snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); pos = substream->ops->pointer(substream); if (pos == SNDRV_PCM_POS_XRUN) return pos; /* XRUN */ if (pos >= runtime->buffer_size) { if (printk_ratelimit()) { - char name[16]; - pcm_debug_name(substream, name, sizeof(name)); - snd_printd(KERN_ERR "BUG: %s, pos = 0x%lx, " + snd_printd(KERN_ERR "BUG: stream = %i, pos = 0x%lx, " "buffer size = 0x%lx, period size = 0x%lx\n", - name, pos, runtime->buffer_size, + substream->stream, pos, runtime->buffer_size, runtime->period_size); } pos = 0; @@ -211,7 +197,7 @@ static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream, #define hw_ptr_error(substream, fmt, args...) \ do { \ - if (xrun_debug(substream, 1)) { \ + if (xrun_debug(substream)) { \ if (printk_ratelimit()) { \ snd_printd("PCM: " fmt, ##args); \ } \ @@ -265,7 +251,7 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) } /* Do jiffies check only in xrun_debug mode */ - if (!xrun_debug(substream, 4)) + if (!xrun_debug(substream)) goto no_jiffies_check; /* Skip the jiffies check for hardwares with BATCH flag. @@ -275,9 +261,6 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) if (runtime->hw.info & SNDRV_PCM_INFO_BATCH) goto no_jiffies_check; hdelta = new_hw_ptr - old_hw_ptr; - if (hdelta < runtime->delay) - goto no_jiffies_check; - hdelta -= runtime->delay; jdelta = jiffies - runtime->hw_ptr_jiffies; if (((hdelta * HZ) / runtime->rate) > jdelta + HZ/100) { delta = jdelta / @@ -311,20 +294,14 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) hw_ptr_interrupt = new_hw_ptr - new_hw_ptr % runtime->period_size; } - runtime->hw_ptr_interrupt = hw_ptr_interrupt; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) snd_pcm_playback_silence(substream, new_hw_ptr); - if (runtime->status->hw_ptr == new_hw_ptr) - return 0; - runtime->hw_ptr_base = hw_base; runtime->status->hw_ptr = new_hw_ptr; runtime->hw_ptr_jiffies = jiffies; - if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) - snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); + runtime->hw_ptr_interrupt = hw_ptr_interrupt; return snd_pcm_update_hw_ptr_post(substream, runtime); } @@ -365,12 +342,8 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream) new_hw_ptr = hw_base + pos; } /* Do jiffies check only in xrun_debug mode */ - if (!xrun_debug(substream, 4)) - goto no_jiffies_check; - if (delta < runtime->delay) - goto no_jiffies_check; - delta -= runtime->delay; - if (((delta * HZ) / runtime->rate) > jdelta + HZ/100) { + if (xrun_debug(substream) && + ((delta * HZ) / runtime->rate) > jdelta + HZ/100) { hw_ptr_error(substream, "hw_ptr skipping! " "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu)\n", @@ -379,19 +352,13 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream) ((delta * HZ) / runtime->rate)); return 0; } - no_jiffies_check: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) snd_pcm_playback_silence(substream, new_hw_ptr); - if (runtime->status->hw_ptr == new_hw_ptr) - return 0; - runtime->hw_ptr_base = hw_base; runtime->status->hw_ptr = new_hw_ptr; runtime->hw_ptr_jiffies = jiffies; - if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) - snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); return snd_pcm_update_hw_ptr_post(substream, runtime); } @@ -485,7 +452,7 @@ static inline unsigned int muldiv32(unsigned int a, unsigned int b, *r = 0; return UINT_MAX; } - n = div_u64_rem(n, c, r); + div64_32(&n, c, r); if (n >= UINT_MAX) { *r = 0; return UINT_MAX; @@ -1557,23 +1524,6 @@ static int snd_pcm_lib_ioctl_channel_info(struct snd_pcm_substream *substream, return 0; } -static int snd_pcm_lib_ioctl_fifo_size(struct snd_pcm_substream *substream, - void *arg) -{ - struct snd_pcm_hw_params *params = arg; - snd_pcm_format_t format; - int channels, width; - - params->fifo_size = substream->runtime->hw.fifo_size; - if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_FIFO_IN_FRAMES)) { - format = params_format(params); - channels = params_channels(params); - width = snd_pcm_format_physical_width(format); - params->fifo_size /= width * channels; - } - return 0; -} - /** * snd_pcm_lib_ioctl - a generic PCM ioctl callback * @substream: the pcm substream instance @@ -1595,8 +1545,6 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, return snd_pcm_lib_ioctl_reset(substream, arg); case SNDRV_PCM_IOCTL1_CHANNEL_INFO: return snd_pcm_lib_ioctl_channel_info(substream, arg); - case SNDRV_PCM_IOCTL1_FIFO_SIZE: - return snd_pcm_lib_ioctl_fifo_size(substream, arg); } return -ENXIO; } diff --git a/trunk/sound/core/pcm_native.c b/trunk/sound/core/pcm_native.c index ac2150e0670d..b5da656d1ece 100644 --- a/trunk/sound/core/pcm_native.c +++ b/trunk/sound/core/pcm_native.c @@ -312,18 +312,9 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, hw = &substream->runtime->hw; if (!params->info) - params->info = hw->info & ~SNDRV_PCM_INFO_FIFO_IN_FRAMES; - if (!params->fifo_size) { - if (snd_mask_min(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT]) == - snd_mask_max(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT]) && - snd_mask_min(¶ms->masks[SNDRV_PCM_HW_PARAM_CHANNELS]) == - snd_mask_max(¶ms->masks[SNDRV_PCM_HW_PARAM_CHANNELS])) { - changed = substream->ops->ioctl(substream, - SNDRV_PCM_IOCTL1_FIFO_SIZE, params); - if (changed < 0) - return changed; - } - } + params->info = hw->info; + if (!params->fifo_size) + params->fifo_size = hw->fifo_size; params->rmask = 0; return 0; } @@ -596,15 +587,14 @@ int snd_pcm_status(struct snd_pcm_substream *substream, if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { status->avail = snd_pcm_playback_avail(runtime); if (runtime->status->state == SNDRV_PCM_STATE_RUNNING || - runtime->status->state == SNDRV_PCM_STATE_DRAINING) { + runtime->status->state == SNDRV_PCM_STATE_DRAINING) status->delay = runtime->buffer_size - status->avail; - status->delay += runtime->delay; - } else + else status->delay = 0; } else { status->avail = snd_pcm_capture_avail(runtime); if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) - status->delay = status->avail + runtime->delay; + status->delay = status->avail; else status->delay = 0; } @@ -2420,7 +2410,6 @@ static int snd_pcm_delay(struct snd_pcm_substream *substream, n = snd_pcm_playback_hw_avail(runtime); else n = snd_pcm_capture_avail(runtime); - n += runtime->delay; break; case SNDRV_PCM_STATE_XRUN: err = -EPIPE; diff --git a/trunk/sound/core/seq/Kconfig b/trunk/sound/core/seq/Kconfig deleted file mode 100644 index b851fd890a89..000000000000 --- a/trunk/sound/core/seq/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -# define SND_XXX_SEQ to min(SND_SEQUENCER,SND_XXX) - -config SND_RAWMIDI_SEQ - def_tristate SND_SEQUENCER && SND_RAWMIDI - -config SND_OPL3_LIB_SEQ - def_tristate SND_SEQUENCER && SND_OPL3_LIB - -config SND_OPL4_LIB_SEQ - def_tristate SND_SEQUENCER && SND_OPL4_LIB - -config SND_SBAWE_SEQ - def_tristate SND_SEQUENCER && SND_SBAWE - -config SND_EMU10K1_SEQ - def_tristate SND_SEQUENCER && SND_EMU10K1 diff --git a/trunk/sound/core/seq/Makefile b/trunk/sound/core/seq/Makefile index 1bcb360330e5..069593717fba 100644 --- a/trunk/sound/core/seq/Makefile +++ b/trunk/sound/core/seq/Makefile @@ -17,6 +17,14 @@ snd-seq-midi-event-objs := seq_midi_event.o snd-seq-dummy-objs := seq_dummy.o snd-seq-virmidi-objs := seq_virmidi.o +# +# this function returns: +# "m" - CONFIG_SND_SEQUENCER is m +# - CONFIG_SND_SEQUENCER is undefined +# otherwise parameter #1 value +# +sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) + obj-$(CONFIG_SND_SEQUENCER) += snd-seq.o snd-seq-device.o ifeq ($(CONFIG_SND_SEQUENCER_OSS),y) obj-$(CONFIG_SND_SEQUENCER) += snd-seq-midi-event.o @@ -25,8 +33,8 @@ obj-$(CONFIG_SND_SEQ_DUMMY) += snd-seq-dummy.o # Toplevel Module Dependency obj-$(CONFIG_SND_VIRMIDI) += snd-seq-virmidi.o snd-seq-midi-event.o -obj-$(CONFIG_SND_RAWMIDI_SEQ) += snd-seq-midi.o snd-seq-midi-event.o -obj-$(CONFIG_SND_OPL3_LIB_SEQ) += snd-seq-midi-event.o snd-seq-midi-emul.o -obj-$(CONFIG_SND_OPL4_LIB_SEQ) += snd-seq-midi-event.o snd-seq-midi-emul.o -obj-$(CONFIG_SND_SBAWE_SEQ) += snd-seq-midi-emul.o snd-seq-virmidi.o -obj-$(CONFIG_SND_EMU10K1_SEQ) += snd-seq-midi-emul.o snd-seq-virmidi.o +obj-$(call sequencer,$(CONFIG_SND_RAWMIDI)) += snd-seq-midi.o snd-seq-midi-event.o +obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o +obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o +obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-seq-midi-emul.o snd-seq-virmidi.o +obj-$(call sequencer,$(CONFIG_SND_EMU10K1)) += snd-seq-midi-emul.o snd-seq-virmidi.o diff --git a/trunk/sound/core/seq/seq_midi_event.c b/trunk/sound/core/seq/seq_midi_event.c index 8284f176a342..b5d6ea4904c0 100644 --- a/trunk/sound/core/seq/seq_midi_event.c +++ b/trunk/sound/core/seq/seq_midi_event.c @@ -504,10 +504,10 @@ static int extra_decode_xrpn(struct snd_midi_event *dev, unsigned char *buf, if (dev->nostat && count < 12) return -ENOMEM; cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f); - bytes[0] = ev->data.control.param & 0x007f; - bytes[1] = (ev->data.control.param & 0x3f80) >> 7; - bytes[2] = ev->data.control.value & 0x007f; - bytes[3] = (ev->data.control.value & 0x3f80) >> 7; + bytes[0] = (ev->data.control.param & 0x3f80) >> 7; + bytes[1] = ev->data.control.param & 0x007f; + bytes[2] = (ev->data.control.value & 0x3f80) >> 7; + bytes[3] = ev->data.control.value & 0x007f; if (cmd != dev->lastcmd && !dev->nostat) { if (count < 9) return -ENOMEM; diff --git a/trunk/sound/drivers/opl3/Makefile b/trunk/sound/drivers/opl3/Makefile index 7f2c2a10c4e5..19767a6a5c54 100644 --- a/trunk/sound/drivers/opl3/Makefile +++ b/trunk/sound/drivers/opl3/Makefile @@ -7,6 +7,14 @@ snd-opl3-lib-objs := opl3_lib.o opl3_synth.o snd-opl3-synth-y := opl3_seq.o opl3_midi.o opl3_drums.o snd-opl3-synth-$(CONFIG_SND_SEQUENCER_OSS) += opl3_oss.o +# +# this function returns: +# "m" - CONFIG_SND_SEQUENCER is m +# - CONFIG_SND_SEQUENCER is undefined +# otherwise parameter #1 value +# +sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) + obj-$(CONFIG_SND_OPL3_LIB) += snd-opl3-lib.o obj-$(CONFIG_SND_OPL4_LIB) += snd-opl3-lib.o -obj-$(CONFIG_SND_OPL3_LIB_SEQ) += snd-opl3-synth.o +obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-opl3-synth.o diff --git a/trunk/sound/drivers/opl4/Makefile b/trunk/sound/drivers/opl4/Makefile index b94009b0b19f..d178b39ffa60 100644 --- a/trunk/sound/drivers/opl4/Makefile +++ b/trunk/sound/drivers/opl4/Makefile @@ -6,5 +6,13 @@ snd-opl4-lib-objs := opl4_lib.o opl4_mixer.o opl4_proc.o snd-opl4-synth-objs := opl4_seq.o opl4_synth.o yrw801.o +# +# this function returns: +# "m" - CONFIG_SND_SEQUENCER is m +# - CONFIG_SND_SEQUENCER is undefined +# otherwise parameter #1 value +# +sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) + obj-$(CONFIG_SND_OPL4_LIB) += snd-opl4-lib.o -obj-$(CONFIG_SND_OPL4_LIB_SEQ) += snd-opl4-synth.o +obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-opl4-synth.o diff --git a/trunk/sound/isa/Kconfig b/trunk/sound/isa/Kconfig index 51a7e3777e17..c6942a4de99b 100644 --- a/trunk/sound/isa/Kconfig +++ b/trunk/sound/isa/Kconfig @@ -177,18 +177,15 @@ config SND_ES18XX will be called snd-es18xx. config SND_SC6000 - tristate "Gallant SC-6000/6600/7000 and Audio Excel DSP 16" + tristate "Gallant SC-6000, Audio Excel DSP 16" depends on HAS_IOPORT select SND_WSS_LIB select SND_OPL3_LIB select SND_MPU401_UART help - Say Y here to include support for Gallant SC-6000, SC-6600, SC-7000 - cards and clones: + Say Y here to include support for Gallant SC-6000 card and clones: Audio Excel DSP 16 and Zoltrix AV302. - These cards are based on CompuMedia ASC-9308 or ASC-9408 chips. - To compile this driver as a module, choose M here: the module will be called snd-sc6000. diff --git a/trunk/sound/isa/es1688/es1688.c b/trunk/sound/isa/es1688/es1688.c index 07df201ed8fa..442b081cafb7 100644 --- a/trunk/sound/isa/es1688/es1688.c +++ b/trunk/sound/isa/es1688/es1688.c @@ -193,7 +193,7 @@ static int __devexit snd_es1688_remove(struct device *dev, unsigned int n) static struct isa_driver snd_es1688_driver = { .match = snd_es1688_match, .probe = snd_es1688_probe, - .remove = __devexit_p(snd_es1688_remove), + .remove = snd_es1688_remove, #if 0 /* FIXME */ .suspend = snd_es1688_suspend, .resume = snd_es1688_resume, diff --git a/trunk/sound/isa/gus/gusextreme.c b/trunk/sound/isa/gus/gusextreme.c index 65e4b18581a6..180a8dea6bd9 100644 --- a/trunk/sound/isa/gus/gusextreme.c +++ b/trunk/sound/isa/gus/gusextreme.c @@ -348,7 +348,7 @@ static int __devexit snd_gusextreme_remove(struct device *dev, unsigned int n) static struct isa_driver snd_gusextreme_driver = { .match = snd_gusextreme_match, .probe = snd_gusextreme_probe, - .remove = __devexit_p(snd_gusextreme_remove), + .remove = snd_gusextreme_remove, #if 0 /* FIXME */ .suspend = snd_gusextreme_suspend, .resume = snd_gusextreme_resume, diff --git a/trunk/sound/isa/sb/Makefile b/trunk/sound/isa/sb/Makefile index faeffceb01b7..1098a56b2f4b 100644 --- a/trunk/sound/isa/sb/Makefile +++ b/trunk/sound/isa/sb/Makefile @@ -13,6 +13,14 @@ snd-sbawe-objs := sbawe.o emu8000.o snd-emu8000-synth-objs := emu8000_synth.o emu8000_callback.o emu8000_patch.o emu8000_pcm.o snd-es968-objs := es968.o +# +# this function returns: +# "m" - CONFIG_SND_SEQUENCER is m +# - CONFIG_SND_SEQUENCER is undefined +# otherwise parameter #1 value +# +sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) + # Toplevel Module Dependency obj-$(CONFIG_SND_SB_COMMON) += snd-sb-common.o obj-$(CONFIG_SND_SB16_DSP) += snd-sb16-dsp.o @@ -25,4 +33,4 @@ ifeq ($(CONFIG_SND_SB16_CSP),y) obj-$(CONFIG_SND_SB16) += snd-sb16-csp.o obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o endif -obj-$(CONFIG_SND_SBAWE_SEQ) += snd-emu8000-synth.o +obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-emu8000-synth.o diff --git a/trunk/sound/isa/sc6000.c b/trunk/sound/isa/sc6000.c index 9a8bbf6dd62a..782010608ef4 100644 --- a/trunk/sound/isa/sc6000.c +++ b/trunk/sound/isa/sc6000.c @@ -2,8 +2,6 @@ * Driver for Gallant SC-6000 soundcard. This card is also known as * Audio Excel DSP 16 or Zoltrix AV302. * These cards use CompuMedia ASC-9308 chip + AD1848 codec. - * SC-6600 and SC-7000 cards are also supported. They are based on - * CompuMedia ASC-9408 chip and CS4231 codec. * * Copyright (C) 2007 Krzysztof Helt * @@ -56,7 +54,6 @@ static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x300, 0x310, 0x320, 0x330 */ static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5, 7, 9, 10, 0 */ static int dma[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0, 1, 3 */ -static bool joystick[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = false }; module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for sc-6000 based soundcard."); @@ -76,8 +73,6 @@ module_param_array(mpu_irq, int, NULL, 0444); MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for sc-6000 driver."); module_param_array(dma, int, NULL, 0444); MODULE_PARM_DESC(dma, "DMA # for sc-6000 driver."); -module_param_array(joystick, bool, NULL, 0444); -MODULE_PARM_DESC(joystick, "Enable gameport."); /* * Commands of SC6000's DSP (SBPRO+special). @@ -196,7 +191,7 @@ static __devinit unsigned char sc6000_mpu_irq_to_softcfg(int mpu_irq) return val; } -static int sc6000_wait_data(char __iomem *vport) +static __devinit int sc6000_wait_data(char __iomem *vport) { int loop = 1000; unsigned char val = 0; @@ -211,7 +206,7 @@ static int sc6000_wait_data(char __iomem *vport) return -EAGAIN; } -static int sc6000_read(char __iomem *vport) +static __devinit int sc6000_read(char __iomem *vport) { if (sc6000_wait_data(vport)) return -EBUSY; @@ -220,7 +215,7 @@ static int sc6000_read(char __iomem *vport) } -static int sc6000_write(char __iomem *vport, int cmd) +static __devinit int sc6000_write(char __iomem *vport, int cmd) { unsigned char val; int loop = 500000; @@ -281,33 +276,8 @@ static int __devinit sc6000_dsp_reset(char __iomem *vport) } /* detection and initialization */ -static int __devinit sc6000_hw_cfg_write(char __iomem *vport, const int *cfg) -{ - if (sc6000_write(vport, COMMAND_6C) < 0) { - snd_printk(KERN_WARNING "CMD 0x%x: failed!\n", COMMAND_6C); - return -EIO; - } - if (sc6000_write(vport, COMMAND_5C) < 0) { - snd_printk(KERN_ERR "CMD 0x%x: failed!\n", COMMAND_5C); - return -EIO; - } - if (sc6000_write(vport, cfg[0]) < 0) { - snd_printk(KERN_ERR "DATA 0x%x: failed!\n", cfg[0]); - return -EIO; - } - if (sc6000_write(vport, cfg[1]) < 0) { - snd_printk(KERN_ERR "DATA 0x%x: failed!\n", cfg[1]); - return -EIO; - } - if (sc6000_write(vport, COMMAND_C5) < 0) { - snd_printk(KERN_ERR "CMD 0x%x: failed!\n", COMMAND_C5); - return -EIO; - } - - return 0; -} - -static int sc6000_cfg_write(char __iomem *vport, unsigned char softcfg) +static int __devinit sc6000_cfg_write(char __iomem *vport, + unsigned char softcfg) { if (sc6000_write(vport, WRITE_MDIRQ_CFG)) { @@ -321,7 +291,7 @@ static int sc6000_cfg_write(char __iomem *vport, unsigned char softcfg) return 0; } -static int sc6000_setup_board(char __iomem *vport, int config) +static int __devinit sc6000_setup_board(char __iomem *vport, int config) { int loop = 10; @@ -364,39 +334,16 @@ static int __devinit sc6000_init_mss(char __iomem *vport, int config, return 0; } -static void __devinit sc6000_hw_cfg_encode(char __iomem *vport, int *cfg, - long xport, long xmpu, - long xmss_port, int joystick) -{ - cfg[0] = 0; - cfg[1] = 0; - if (xport == 0x240) - cfg[0] |= 1; - if (xmpu != SNDRV_AUTO_PORT) { - cfg[0] |= (xmpu & 0x30) >> 2; - cfg[1] |= 0x20; - } - if (xmss_port == 0xe80) - cfg[0] |= 0x10; - cfg[0] |= 0x40; /* always set */ - if (!joystick) - cfg[0] |= 0x02; - cfg[1] |= 0x80; /* enable WSS system */ - cfg[1] &= ~0x40; /* disable IDE */ - snd_printd("hw cfg %x, %x\n", cfg[0], cfg[1]); -} - -static int __devinit sc6000_init_board(char __iomem *vport, - char __iomem *vmss_port, int dev) +static int __devinit sc6000_init_board(char __iomem *vport, int irq, int dma, + char __iomem *vmss_port, int mpu_irq) { char answer[15]; char version[2]; - int mss_config = sc6000_irq_to_softcfg(irq[dev]) | - sc6000_dma_to_softcfg(dma[dev]); + int mss_config = sc6000_irq_to_softcfg(irq) | + sc6000_dma_to_softcfg(dma); int config = mss_config | - sc6000_mpu_irq_to_softcfg(mpu_irq[dev]); + sc6000_mpu_irq_to_softcfg(mpu_irq); int err; - int old = 0; err = sc6000_dsp_reset(vport); if (err < 0) { @@ -413,6 +360,7 @@ static int __devinit sc6000_init_board(char __iomem *vport, /* * My SC-6000 card return "SC-6000" in DSPCopyright, so * if we have something different, we have to be warned. + * Mine returns "SC-6000A " - KH */ if (strncmp("SC-6000", answer, 7)) snd_printk(KERN_WARNING "Warning: non SC-6000 audio card!\n"); @@ -424,32 +372,13 @@ static int __devinit sc6000_init_board(char __iomem *vport, printk(KERN_INFO PFX "Detected model: %s, DSP version %d.%d\n", answer, version[0], version[1]); - /* set configuration */ - sc6000_write(vport, COMMAND_5C); - if (sc6000_read(vport) < 0) - old = 1; - - if (!old) { - int cfg[2]; - sc6000_hw_cfg_encode(vport, &cfg[0], port[dev], mpu_port[dev], - mss_port[dev], joystick[dev]); - if (sc6000_hw_cfg_write(vport, cfg) < 0) { - snd_printk(KERN_ERR "sc6000_hw_cfg_write: failed!\n"); - return -EIO; - } - } - err = sc6000_setup_board(vport, config); + /* + * 0x0A == (IRQ 7, DMA 1, MIRQ 0) + */ + err = sc6000_cfg_write(vport, 0x0a); if (err < 0) { - snd_printk(KERN_ERR "sc6000_setup_board: failed!\n"); - return -ENODEV; - } - - sc6000_dsp_reset(vport); - - if (!old) { - sc6000_write(vport, COMMAND_60); - sc6000_write(vport, 0x02); - sc6000_dsp_reset(vport); + snd_printk(KERN_ERR "sc6000_cfg_write: failed!\n"); + return -EFAULT; } err = sc6000_setup_board(vport, config); @@ -457,9 +386,10 @@ static int __devinit sc6000_init_board(char __iomem *vport, snd_printk(KERN_ERR "sc6000_setup_board: failed!\n"); return -ENODEV; } + err = sc6000_init_mss(vport, config, vmss_port, mss_config); if (err < 0) { - snd_printk(KERN_ERR "Cannot initialize " + snd_printk(KERN_ERR "Can not initialize " "Microsoft Sound System mode.\n"); return -ENODEV; } @@ -555,16 +485,14 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev) struct snd_card *card; struct snd_wss *chip; struct snd_opl3 *opl3; - char __iomem **vport; + char __iomem *vport; char __iomem *vmss_port; - err = snd_card_create(index[dev], id[dev], THIS_MODULE, sizeof(vport), - &card); + err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); if (err < 0) return err; - vport = card->private_data; if (xirq == SNDRV_AUTO_IRQ) { xirq = snd_legacy_find_free_irq(possible_irqs); if (xirq < 0) { @@ -589,8 +517,8 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev) err = -EBUSY; goto err_exit; } - *vport = devm_ioport_map(devptr, port[dev], 0x10); - if (*vport == NULL) { + vport = devm_ioport_map(devptr, port[dev], 0x10); + if (!vport) { snd_printk(KERN_ERR PFX "I/O port cannot be iomaped.\n"); err = -EBUSY; @@ -605,7 +533,7 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev) goto err_unmap1; } vmss_port = devm_ioport_map(devptr, mss_port[dev], 4); - if (!vmss_port) { + if (!vport) { snd_printk(KERN_ERR PFX "MSS port I/O cannot be iomaped.\n"); err = -EBUSY; @@ -616,7 +544,7 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev) port[dev], xirq, xdma, mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]); - err = sc6000_init_board(*vport, vmss_port, dev); + err = sc6000_init_board(vport, xirq, xdma, vmss_port, mpu_irq[dev]); if (err < 0) goto err_unmap2; @@ -624,6 +552,7 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev) WSS_HW_DETECT, 0, &chip); if (err < 0) goto err_unmap2; + card->private_data = chip; err = snd_wss_pcm(chip, 0, NULL); if (err < 0) { @@ -679,7 +608,6 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev) return 0; err_unmap2: - sc6000_setup_board(*vport, 0); release_region(mss_port[dev], 4); err_unmap1: release_region(port[dev], 0x10); @@ -690,17 +618,11 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev) static int __devexit snd_sc6000_remove(struct device *devptr, unsigned int dev) { - struct snd_card *card = dev_get_drvdata(devptr); - char __iomem **vport = card->private_data; - - if (sc6000_setup_board(*vport, 0) < 0) - snd_printk(KERN_WARNING "sc6000_setup_board failed on exit!\n"); - release_region(port[dev], 0x10); release_region(mss_port[dev], 4); + snd_card_free(dev_get_drvdata(devptr)); dev_set_drvdata(devptr, NULL); - snd_card_free(card); return 0; } diff --git a/trunk/sound/mips/sgio2audio.c b/trunk/sound/mips/sgio2audio.c index e497525bc11b..66f3b48ceafc 100644 --- a/trunk/sound/mips/sgio2audio.c +++ b/trunk/sound/mips/sgio2audio.c @@ -619,7 +619,8 @@ static int snd_sgio2audio_pcm_hw_params(struct snd_pcm_substream *substream, /* hw_free callback */ static int snd_sgio2audio_pcm_hw_free(struct snd_pcm_substream *substream) { - vfree(substream->runtime->dma_area); + if (substream->runtime->dma_area) + vfree(substream->runtime->dma_area); substream->runtime->dma_area = NULL; return 0; } diff --git a/trunk/sound/parisc/harmony.c b/trunk/sound/parisc/harmony.c index e924492df21d..6055fd6d3b38 100644 --- a/trunk/sound/parisc/harmony.c +++ b/trunk/sound/parisc/harmony.c @@ -935,7 +935,7 @@ snd_harmony_create(struct snd_card *card, h->iobase = ioremap_nocache(padev->hpa.start, HARMONY_SIZE); if (h->iobase == NULL) { printk(KERN_ERR PFX "unable to remap hpa 0x%lx\n", - (unsigned long)padev->hpa.start); + padev->hpa.start); err = -EBUSY; goto free_and_ret; } @@ -1020,7 +1020,7 @@ static struct parisc_driver snd_harmony_driver = { .name = "harmony", .id_table = snd_harmony_devtable, .probe = snd_harmony_probe, - .remove = __devexit_p(snd_harmony_remove), + .remove = snd_harmony_remove, }; static int __init diff --git a/trunk/sound/pci/Kconfig b/trunk/sound/pci/Kconfig index 748f6b7d90b7..93422e3a3f0c 100644 --- a/trunk/sound/pci/Kconfig +++ b/trunk/sound/pci/Kconfig @@ -275,16 +275,6 @@ config SND_CS5535AUDIO To compile this driver as a module, choose M here: the module will be called snd-cs5535audio. -config SND_CTXFI - tristate "Creative Sound Blaster X-Fi" - select SND_PCM - help - If you want to use soundcards based on Creative Sound Blastr X-Fi - boards with 20k1 or 20k2 chips, say Y here. - - To compile this driver as a module, choose M here: the module - will be called snd-ctxfi. - config SND_DARLA20 tristate "(Echoaudio) Darla20" select FW_LOADER @@ -542,9 +532,6 @@ config SND_HDSP To compile this driver as a module, choose M here: the module will be called snd-hdsp. -comment "Don't forget to add built-in firmwares for HDSP driver" - depends on SND_HDSP=y - config SND_HDSPM tristate "RME Hammerfall DSP MADI" select SND_HWDEP @@ -635,16 +622,6 @@ config SND_KORG1212 To compile this driver as a module, choose M here: the module will be called snd-korg1212. -config SND_LX6464ES - tristate "Digigram LX6464ES" - select SND_PCM - help - Say Y here to include support for Digigram LX6464ES boards. - - To compile this driver as a module, choose M here: the module - will be called snd-lx6464es. - - config SND_MAESTRO3 tristate "ESS Allegro/Maestro3" select SND_AC97_CODEC @@ -787,8 +764,8 @@ config SND_VIRTUOSO select SND_OXYGEN_LIB help 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. + Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, and + Essence STX. 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/Makefile b/trunk/sound/pci/Makefile index ecfc609d2b9f..65b25d221cd2 100644 --- a/trunk/sound/pci/Makefile +++ b/trunk/sound/pci/Makefile @@ -59,11 +59,9 @@ obj-$(CONFIG_SND) += \ ali5451/ \ au88x0/ \ aw2/ \ - ctxfi/ \ ca0106/ \ cs46xx/ \ cs5535audio/ \ - lx6464es/ \ echoaudio/ \ emu10k1/ \ hda/ \ diff --git a/trunk/sound/pci/au88x0/au88x0_core.c b/trunk/sound/pci/au88x0/au88x0_core.c index 23f49f356e0f..3906f5afe27a 100644 --- a/trunk/sound/pci/au88x0/au88x0_core.c +++ b/trunk/sound/pci/au88x0/au88x0_core.c @@ -1255,8 +1255,8 @@ static int inline vortex_adbdma_getlinearpos(vortex_t * vortex, int adbdma) int temp; temp = hwread(vortex->mmio, VORTEX_ADBDMA_STAT + (adbdma << 2)); - temp = (dma->period_virt * dma->period_bytes) + (temp & (dma->period_bytes - 1)); - return temp; + temp = (dma->period_virt * dma->period_bytes) + (temp & POS_MASK); + return (temp); } static void vortex_adbdma_startfifo(vortex_t * vortex, int adbdma) @@ -1504,7 +1504,8 @@ static int inline vortex_wtdma_getlinearpos(vortex_t * vortex, int wtdma) int temp; temp = hwread(vortex->mmio, VORTEX_WTDMA_STAT + (wtdma << 2)); - temp = (dma->period_virt * dma->period_bytes) + (temp & (dma->period_bytes - 1)); + //temp = (temp & POS_MASK) + (((temp>>WT_SUBBUF_SHIFT) & WT_SUBBUF_MASK)*(dma->cfg0&POS_MASK)); + temp = (temp & POS_MASK) + ((dma->period_virt) * (dma->period_bytes)); return temp; } @@ -2440,8 +2441,7 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id) spin_lock(&vortex->lock); for (i = 0; i < NR_ADB; i++) { if (vortex->dma_adb[i].fifo_status == FIFO_START) { - if (!vortex_adbdma_bufshift(vortex, i)) - continue; + if (vortex_adbdma_bufshift(vortex, i)) ; spin_unlock(&vortex->lock); snd_pcm_period_elapsed(vortex->dma_adb[i]. substream); diff --git a/trunk/sound/pci/bt87x.c b/trunk/sound/pci/bt87x.c index 24585c6c6d01..ce3f2e90f4d7 100644 --- a/trunk/sound/pci/bt87x.c +++ b/trunk/sound/pci/bt87x.c @@ -810,8 +810,6 @@ static struct pci_device_id snd_bt87x_ids[] = { BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x107d, 0x6606, GENERIC), /* Voodoo TV 200 */ BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x121a, 0x3000, GENERIC), - /* Askey Computer Corp. MagicTView'99 */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x144f, 0x3000, GENERIC), /* AVerMedia Studio No. 103, 203, ...? */ BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1461, 0x0003, AVPHONE98), /* Prolink PixelView PV-M4900 */ diff --git a/trunk/sound/pci/ca0106/ca0106_main.c b/trunk/sound/pci/ca0106/ca0106_main.c index 57b992a5c057..bfac30f7929f 100644 --- a/trunk/sound/pci/ca0106/ca0106_main.c +++ b/trunk/sound/pci/ca0106/ca0106_main.c @@ -1319,6 +1319,7 @@ static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device) } pcm->info_flags = 0; + pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; strcpy(pcm->name, "CA0106"); for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; diff --git a/trunk/sound/pci/ca0106/ca0106_mixer.c b/trunk/sound/pci/ca0106/ca0106_mixer.c index c8c6f437f5b3..c111efe61c3c 100644 --- a/trunk/sound/pci/ca0106/ca0106_mixer.c +++ b/trunk/sound/pci/ca0106/ca0106_mixer.c @@ -739,7 +739,7 @@ static int __devinit rename_ctl(struct snd_card *card, const char *src, const ch } while (0) static __devinitdata -DECLARE_TLV_DB_SCALE(snd_ca0106_master_db_scale, -6375, 25, 1); +DECLARE_TLV_DB_SCALE(snd_ca0106_master_db_scale, -6375, 50, 1); static char *slave_vols[] __devinitdata = { "Analog Front Playback Volume", @@ -841,9 +841,6 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) snd_ca0106_master_db_scale); if (!vmaster) return -ENOMEM; - err = snd_ctl_add(card, vmaster); - if (err < 0) - return err; add_slaves(card, vmaster, slave_vols); if (emu->details->spi_dac == 1) { @@ -851,13 +848,8 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) NULL); if (!vmaster) return -ENOMEM; - err = snd_ctl_add(card, vmaster); - if (err < 0) - return err; add_slaves(card, vmaster, slave_sws); } - - strcpy(card->mixername, "CA0106"); return 0; } diff --git a/trunk/sound/pci/ctxfi/Makefile b/trunk/sound/pci/ctxfi/Makefile deleted file mode 100644 index 15075f89e98a..000000000000 --- a/trunk/sound/pci/ctxfi/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -snd-ctxfi-objs := xfi.o ctatc.o ctvmem.o ctpcm.o ctmixer.o ctresource.o \ - ctsrc.o ctamixer.o ctdaio.o ctimap.o cthardware.o cttimer.o \ - cthw20k2.o cthw20k1.o - -obj-$(CONFIG_SND_CTXFI) += snd-ctxfi.o diff --git a/trunk/sound/pci/ctxfi/ct20k1reg.h b/trunk/sound/pci/ctxfi/ct20k1reg.h deleted file mode 100644 index f2e34e3f27ee..000000000000 --- a/trunk/sound/pci/ctxfi/ct20k1reg.h +++ /dev/null @@ -1,636 +0,0 @@ -/** - * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. - * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - */ - -#ifndef CT20K1REG_H -#define CT20k1REG_H - -/* 20k1 registers */ -#define DSPXRAM_START 0x000000 -#define DSPXRAM_END 0x013FFC -#define DSPAXRAM_START 0x020000 -#define DSPAXRAM_END 0x023FFC -#define DSPYRAM_START 0x040000 -#define DSPYRAM_END 0x04FFFC -#define DSPAYRAM_START 0x020000 -#define DSPAYRAM_END 0x063FFC -#define DSPMICRO_START 0x080000 -#define DSPMICRO_END 0x0B3FFC -#define DSP0IO_START 0x100000 -#define DSP0IO_END 0x101FFC -#define AUDIORINGIPDSP0_START 0x100000 -#define AUDIORINGIPDSP0_END 0x1003FC -#define AUDIORINGOPDSP0_START 0x100400 -#define AUDIORINGOPDSP0_END 0x1007FC -#define AUDPARARINGIODSP0_START 0x100800 -#define AUDPARARINGIODSP0_END 0x100BFC -#define DSP0LOCALHWREG_START 0x100C00 -#define DSP0LOCALHWREG_END 0x100C3C -#define DSP0XYRAMAGINDEX_START 0x100C40 -#define DSP0XYRAMAGINDEX_END 0x100C5C -#define DSP0XYRAMAGMDFR_START 0x100C60 -#define DSP0XYRAMAGMDFR_END 0x100C7C -#define DSP0INTCONTLVEC_START 0x100C80 -#define DSP0INTCONTLVEC_END 0x100CD8 -#define INTCONTLGLOBALREG_START 0x100D1C -#define INTCONTLGLOBALREG_END 0x100D3C -#define HOSTINTFPORTADDRCONTDSP0 0x100D40 -#define HOSTINTFPORTDATADSP0 0x100D44 -#define TIME0PERENBDSP0 0x100D60 -#define TIME0COUNTERDSP0 0x100D64 -#define TIME1PERENBDSP0 0x100D68 -#define TIME1COUNTERDSP0 0x100D6C -#define TIME2PERENBDSP0 0x100D70 -#define TIME2COUNTERDSP0 0x100D74 -#define TIME3PERENBDSP0 0x100D78 -#define TIME3COUNTERDSP0 0x100D7C -#define XRAMINDOPERREFNOUP_STARTDSP0 0x100D80 -#define XRAMINDOPERREFNOUP_ENDDSP0 0x100D9C -#define XRAMINDOPERREFUP_STARTDSP0 0x100DA0 -#define XRAMINDOPERREFUP_ENDDSP0 0x100DBC -#define YRAMINDOPERREFNOUP_STARTDSP0 0x100DC0 -#define YRAMINDOPERREFNOUP_ENDDSP0 0x100DDC -#define YRAMINDOPERREFUP_STARTDSP0 0x100DE0 -#define YRAMINDOPERREFUP_ENDDSP0 0x100DFC -#define DSP0CONDCODE 0x100E00 -#define DSP0STACKFLAG 0x100E04 -#define DSP0PROGCOUNTSTACKPTREG 0x100E08 -#define DSP0PROGCOUNTSTACKDATAREG 0x100E0C -#define DSP0CURLOOPADDRREG 0x100E10 -#define DSP0CURLOOPCOUNT 0x100E14 -#define DSP0TOPLOOPCOUNTSTACK 0x100E18 -#define DSP0TOPLOOPADDRSTACK 0x100E1C -#define DSP0LOOPSTACKPTR 0x100E20 -#define DSP0STASSTACKDATAREG 0x100E24 -#define DSP0STASSTACKPTR 0x100E28 -#define DSP0PROGCOUNT 0x100E2C -#define GLOBDSPDEBGREG 0x100E30 -#define GLOBDSPBREPTRREG 0x100E30 -#define DSP0XYRAMBASE_START 0x100EA0 -#define DSP0XYRAMBASE_END 0x100EBC -#define DSP0XYRAMLENG_START 0x100EC0 -#define DSP0XYRAMLENG_END 0x100EDC -#define SEMAPHOREREGDSP0 0x100EE0 -#define DSP0INTCONTMASKREG 0x100EE4 -#define DSP0INTCONTPENDREG 0x100EE8 -#define DSP0INTCONTSERVINT 0x100EEC -#define DSPINTCONTEXTINTMODREG 0x100EEC -#define GPIODSP0 0x100EFC -#define DMADSPBASEADDRREG_STARTDSP0 0x100F00 -#define DMADSPBASEADDRREG_ENDDSP0 0x100F1C -#define DMAHOSTBASEADDRREG_STARTDSP0 0x100F20 -#define DMAHOSTBASEADDRREG_ENDDSP0 0x100F3C -#define DMADSPCURADDRREG_STARTDSP0 0x100F40 -#define DMADSPCURADDRREG_ENDDSP0 0x100F5C -#define DMAHOSTCURADDRREG_STARTDSP0 0x100F60 -#define DMAHOSTCURADDRREG_ENDDSP0 0x100F7C -#define DMATANXCOUNTREG_STARTDSP0 0x100F80 -#define DMATANXCOUNTREG_ENDDSP0 0x100F9C -#define DMATIMEBUGREG_STARTDSP0 0x100FA0 -#define DMATIMEBUGREG_ENDDSP0 0x100FAC -#define DMACNTLMODFREG_STARTDSP0 0x100FA0 -#define DMACNTLMODFREG_ENDDSP0 0x100FAC - -#define DMAGLOBSTATSREGDSP0 0x100FEC -#define DSP0XGPRAM_START 0x101000 -#define DSP0XGPRAM_END 0x1017FC -#define DSP0YGPRAM_START 0x101800 -#define DSP0YGPRAM_END 0x101FFC - - - - -#define AUDIORINGIPDSP1_START 0x102000 -#define AUDIORINGIPDSP1_END 0x1023FC -#define AUDIORINGOPDSP1_START 0x102400 -#define AUDIORINGOPDSP1_END 0x1027FC -#define AUDPARARINGIODSP1_START 0x102800 -#define AUDPARARINGIODSP1_END 0x102BFC -#define DSP1LOCALHWREG_START 0x102C00 -#define DSP1LOCALHWREG_END 0x102C3C -#define DSP1XYRAMAGINDEX_START 0x102C40 -#define DSP1XYRAMAGINDEX_END 0x102C5C -#define DSP1XYRAMAGMDFR_START 0x102C60 -#define DSP1XYRAMAGMDFR_END 0x102C7C -#define DSP1INTCONTLVEC_START 0x102C80 -#define DSP1INTCONTLVEC_END 0x102CD8 -#define HOSTINTFPORTADDRCONTDSP1 0x102D40 -#define HOSTINTFPORTDATADSP1 0x102D44 -#define TIME0PERENBDSP1 0x102D60 -#define TIME0COUNTERDSP1 0x102D64 -#define TIME1PERENBDSP1 0x102D68 -#define TIME1COUNTERDSP1 0x102D6C -#define TIME2PERENBDSP1 0x102D70 -#define TIME2COUNTERDSP1 0x102D74 -#define TIME3PERENBDSP1 0x102D78 -#define TIME3COUNTERDSP1 0x102D7C -#define XRAMINDOPERREFNOUP_STARTDSP1 0x102D80 -#define XRAMINDOPERREFNOUP_ENDDSP1 0x102D9C -#define XRAMINDOPERREFUP_STARTDSP1 0x102DA0 -#define XRAMINDOPERREFUP_ENDDSP1 0x102DBC -#define YRAMINDOPERREFNOUP_STARTDSP1 0x102DC0 -#define YRAMINDOPERREFNOUP_ENDDSP1 0x102DDC -#define YRAMINDOPERREFUP_STARTDSP1 0x102DE0 -#define YRAMINDOPERREFUP_ENDDSP1 0x102DFC - -#define DSP1CONDCODE 0x102E00 -#define DSP1STACKFLAG 0x102E04 -#define DSP1PROGCOUNTSTACKPTREG 0x102E08 -#define DSP1PROGCOUNTSTACKDATAREG 0x102E0C -#define DSP1CURLOOPADDRREG 0x102E10 -#define DSP1CURLOOPCOUNT 0x102E14 -#define DSP1TOPLOOPCOUNTSTACK 0x102E18 -#define DSP1TOPLOOPADDRSTACK 0x102E1C -#define DSP1LOOPSTACKPTR 0x102E20 -#define DSP1STASSTACKDATAREG 0x102E24 -#define DSP1STASSTACKPTR 0x102E28 -#define DSP1PROGCOUNT 0x102E2C -#define DSP1XYRAMBASE_START 0x102EA0 -#define DSP1XYRAMBASE_END 0x102EBC -#define DSP1XYRAMLENG_START 0x102EC0 -#define DSP1XYRAMLENG_END 0x102EDC -#define SEMAPHOREREGDSP1 0x102EE0 -#define DSP1INTCONTMASKREG 0x102EE4 -#define DSP1INTCONTPENDREG 0x102EE8 -#define DSP1INTCONTSERVINT 0x102EEC -#define GPIODSP1 0x102EFC -#define DMADSPBASEADDRREG_STARTDSP1 0x102F00 -#define DMADSPBASEADDRREG_ENDDSP1 0x102F1C -#define DMAHOSTBASEADDRREG_STARTDSP1 0x102F20 -#define DMAHOSTBASEADDRREG_ENDDSP1 0x102F3C -#define DMADSPCURADDRREG_STARTDSP1 0x102F40 -#define DMADSPCURADDRREG_ENDDSP1 0x102F5C -#define DMAHOSTCURADDRREG_STARTDSP1 0x102F60 -#define DMAHOSTCURADDRREG_ENDDSP1 0x102F7C -#define DMATANXCOUNTREG_STARTDSP1 0x102F80 -#define DMATANXCOUNTREG_ENDDSP1 0x102F9C -#define DMATIMEBUGREG_STARTDSP1 0x102FA0 -#define DMATIMEBUGREG_ENDDSP1 0x102FAC -#define DMACNTLMODFREG_STARTDSP1 0x102FA0 -#define DMACNTLMODFREG_ENDDSP1 0x102FAC - -#define DMAGLOBSTATSREGDSP1 0x102FEC -#define DSP1XGPRAM_START 0x103000 -#define DSP1XGPRAM_END 0x1033FC -#define DSP1YGPRAM_START 0x103400 -#define DSP1YGPRAM_END 0x1037FC - - - -#define AUDIORINGIPDSP2_START 0x104000 -#define AUDIORINGIPDSP2_END 0x1043FC -#define AUDIORINGOPDSP2_START 0x104400 -#define AUDIORINGOPDSP2_END 0x1047FC -#define AUDPARARINGIODSP2_START 0x104800 -#define AUDPARARINGIODSP2_END 0x104BFC -#define DSP2LOCALHWREG_START 0x104C00 -#define DSP2LOCALHWREG_END 0x104C3C -#define DSP2XYRAMAGINDEX_START 0x104C40 -#define DSP2XYRAMAGINDEX_END 0x104C5C -#define DSP2XYRAMAGMDFR_START 0x104C60 -#define DSP2XYRAMAGMDFR_END 0x104C7C -#define DSP2INTCONTLVEC_START 0x104C80 -#define DSP2INTCONTLVEC_END 0x104CD8 -#define HOSTINTFPORTADDRCONTDSP2 0x104D40 -#define HOSTINTFPORTDATADSP2 0x104D44 -#define TIME0PERENBDSP2 0x104D60 -#define TIME0COUNTERDSP2 0x104D64 -#define TIME1PERENBDSP2 0x104D68 -#define TIME1COUNTERDSP2 0x104D6C -#define TIME2PERENBDSP2 0x104D70 -#define TIME2COUNTERDSP2 0x104D74 -#define TIME3PERENBDSP2 0x104D78 -#define TIME3COUNTERDSP2 0x104D7C -#define XRAMINDOPERREFNOUP_STARTDSP2 0x104D80 -#define XRAMINDOPERREFNOUP_ENDDSP2 0x104D9C -#define XRAMINDOPERREFUP_STARTDSP2 0x104DA0 -#define XRAMINDOPERREFUP_ENDDSP2 0x104DBC -#define YRAMINDOPERREFNOUP_STARTDSP2 0x104DC0 -#define YRAMINDOPERREFNOUP_ENDDSP2 0x104DDC -#define YRAMINDOPERREFUP_STARTDSP2 0x104DE0 -#define YRAMINDOPERREFUP_ENDDSP2 0x104DFC -#define DSP2CONDCODE 0x104E00 -#define DSP2STACKFLAG 0x104E04 -#define DSP2PROGCOUNTSTACKPTREG 0x104E08 -#define DSP2PROGCOUNTSTACKDATAREG 0x104E0C -#define DSP2CURLOOPADDRREG 0x104E10 -#define DSP2CURLOOPCOUNT 0x104E14 -#define DSP2TOPLOOPCOUNTSTACK 0x104E18 -#define DSP2TOPLOOPADDRSTACK 0x104E1C -#define DSP2LOOPSTACKPTR 0x104E20 -#define DSP2STASSTACKDATAREG 0x104E24 -#define DSP2STASSTACKPTR 0x104E28 -#define DSP2PROGCOUNT 0x104E2C -#define DSP2XYRAMBASE_START 0x104EA0 -#define DSP2XYRAMBASE_END 0x104EBC -#define DSP2XYRAMLENG_START 0x104EC0 -#define DSP2XYRAMLENG_END 0x104EDC -#define SEMAPHOREREGDSP2 0x104EE0 -#define DSP2INTCONTMASKREG 0x104EE4 -#define DSP2INTCONTPENDREG 0x104EE8 -#define DSP2INTCONTSERVINT 0x104EEC -#define GPIODSP2 0x104EFC -#define DMADSPBASEADDRREG_STARTDSP2 0x104F00 -#define DMADSPBASEADDRREG_ENDDSP2 0x104F1C -#define DMAHOSTBASEADDRREG_STARTDSP2 0x104F20 -#define DMAHOSTBASEADDRREG_ENDDSP2 0x104F3C -#define DMADSPCURADDRREG_STARTDSP2 0x104F40 -#define DMADSPCURADDRREG_ENDDSP2 0x104F5C -#define DMAHOSTCURADDRREG_STARTDSP2 0x104F60 -#define DMAHOSTCURADDRREG_ENDDSP2 0x104F7C -#define DMATANXCOUNTREG_STARTDSP2 0x104F80 -#define DMATANXCOUNTREG_ENDDSP2 0x104F9C -#define DMATIMEBUGREG_STARTDSP2 0x104FA0 -#define DMATIMEBUGREG_ENDDSP2 0x104FAC -#define DMACNTLMODFREG_STARTDSP2 0x104FA0 -#define DMACNTLMODFREG_ENDDSP2 0x104FAC - -#define DMAGLOBSTATSREGDSP2 0x104FEC -#define DSP2XGPRAM_START 0x105000 -#define DSP2XGPRAM_END 0x1051FC -#define DSP2YGPRAM_START 0x105800 -#define DSP2YGPRAM_END 0x1059FC - - - -#define AUDIORINGIPDSP3_START 0x106000 -#define AUDIORINGIPDSP3_END 0x1063FC -#define AUDIORINGOPDSP3_START 0x106400 -#define AUDIORINGOPDSP3_END 0x1067FC -#define AUDPARARINGIODSP3_START 0x106800 -#define AUDPARARINGIODSP3_END 0x106BFC -#define DSP3LOCALHWREG_START 0x106C00 -#define DSP3LOCALHWREG_END 0x106C3C -#define DSP3XYRAMAGINDEX_START 0x106C40 -#define DSP3XYRAMAGINDEX_END 0x106C5C -#define DSP3XYRAMAGMDFR_START 0x106C60 -#define DSP3XYRAMAGMDFR_END 0x106C7C -#define DSP3INTCONTLVEC_START 0x106C80 -#define DSP3INTCONTLVEC_END 0x106CD8 -#define HOSTINTFPORTADDRCONTDSP3 0x106D40 -#define HOSTINTFPORTDATADSP3 0x106D44 -#define TIME0PERENBDSP3 0x106D60 -#define TIME0COUNTERDSP3 0x106D64 -#define TIME1PERENBDSP3 0x106D68 -#define TIME1COUNTERDSP3 0x106D6C -#define TIME2PERENBDSP3 0x106D70 -#define TIME2COUNTERDSP3 0x106D74 -#define TIME3PERENBDSP3 0x106D78 -#define TIME3COUNTERDSP3 0x106D7C -#define XRAMINDOPERREFNOUP_STARTDSP3 0x106D80 -#define XRAMINDOPERREFNOUP_ENDDSP3 0x106D9C -#define XRAMINDOPERREFUP_STARTDSP3 0x106DA0 -#define XRAMINDOPERREFUP_ENDDSP3 0x106DBC -#define YRAMINDOPERREFNOUP_STARTDSP3 0x106DC0 -#define YRAMINDOPERREFNOUP_ENDDSP3 0x106DDC -#define YRAMINDOPERREFUP_STARTDSP3 0x106DE0 -#define YRAMINDOPERREFUP_ENDDSP3 0x100DFC - -#define DSP3CONDCODE 0x106E00 -#define DSP3STACKFLAG 0x106E04 -#define DSP3PROGCOUNTSTACKPTREG 0x106E08 -#define DSP3PROGCOUNTSTACKDATAREG 0x106E0C -#define DSP3CURLOOPADDRREG 0x106E10 -#define DSP3CURLOOPCOUNT 0x106E14 -#define DSP3TOPLOOPCOUNTSTACK 0x106E18 -#define DSP3TOPLOOPADDRSTACK 0x106E1C -#define DSP3LOOPSTACKPTR 0x106E20 -#define DSP3STASSTACKDATAREG 0x106E24 -#define DSP3STASSTACKPTR 0x106E28 -#define DSP3PROGCOUNT 0x106E2C -#define DSP3XYRAMBASE_START 0x106EA0 -#define DSP3XYRAMBASE_END 0x106EBC -#define DSP3XYRAMLENG_START 0x106EC0 -#define DSP3XYRAMLENG_END 0x106EDC -#define SEMAPHOREREGDSP3 0x106EE0 -#define DSP3INTCONTMASKREG 0x106EE4 -#define DSP3INTCONTPENDREG 0x106EE8 -#define DSP3INTCONTSERVINT 0x106EEC -#define GPIODSP3 0x106EFC -#define DMADSPBASEADDRREG_STARTDSP3 0x106F00 -#define DMADSPBASEADDRREG_ENDDSP3 0x106F1C -#define DMAHOSTBASEADDRREG_STARTDSP3 0x106F20 -#define DMAHOSTBASEADDRREG_ENDDSP3 0x106F3C -#define DMADSPCURADDRREG_STARTDSP3 0x106F40 -#define DMADSPCURADDRREG_ENDDSP3 0x106F5C -#define DMAHOSTCURADDRREG_STARTDSP3 0x106F60 -#define DMAHOSTCURADDRREG_ENDDSP3 0x106F7C -#define DMATANXCOUNTREG_STARTDSP3 0x106F80 -#define DMATANXCOUNTREG_ENDDSP3 0x106F9C -#define DMATIMEBUGREG_STARTDSP3 0x106FA0 -#define DMATIMEBUGREG_ENDDSP3 0x106FAC -#define DMACNTLMODFREG_STARTDSP3 0x106FA0 -#define DMACNTLMODFREG_ENDDSP3 0x106FAC - -#define DMAGLOBSTATSREGDSP3 0x106FEC -#define DSP3XGPRAM_START 0x107000 -#define DSP3XGPRAM_END 0x1071FC -#define DSP3YGPRAM_START 0x107800 -#define DSP3YGPRAM_END 0x1079FC - -/* end of DSP reg definitions */ - -#define DSPAIMAP_START 0x108000 -#define DSPAIMAP_END 0x1083FC -#define DSPPIMAP_START 0x108400 -#define DSPPIMAP_END 0x1087FC -#define DSPPOMAP_START 0x108800 -#define DSPPOMAP_END 0x108BFC -#define DSPPOCTL 0x108C00 -#define TKCTL_START 0x110000 -#define TKCTL_END 0x110FFC -#define TKCC_START 0x111000 -#define TKCC_END 0x111FFC -#define TKIMAP_START 0x112000 -#define TKIMAP_END 0x112FFC -#define TKDCTR16 0x113000 -#define TKPB16 0x113004 -#define TKBS16 0x113008 -#define TKDCTR32 0x11300C -#define TKPB32 0x113010 -#define TKBS32 0x113014 -#define ICDCTR16 0x113018 -#define ITBS16 0x11301C -#define ICDCTR32 0x113020 -#define ITBS32 0x113024 -#define ITSTART 0x113028 -#define TKSQ 0x11302C - -#define TKSCCTL_START 0x114000 -#define TKSCCTL_END 0x11403C -#define TKSCADR_START 0x114100 -#define TKSCADR_END 0x11413C -#define TKSCDATAX_START 0x114800 -#define TKSCDATAX_END 0x1149FC -#define TKPCDATAX_START 0x120000 -#define TKPCDATAX_END 0x12FFFC - -#define MALSA 0x130000 -#define MAPPHA 0x130004 -#define MAPPLA 0x130008 -#define MALSB 0x130010 -#define MAPPHB 0x130014 -#define MAPPLB 0x130018 - -#define TANSPORTMAPABREGS_START 0x130020 -#define TANSPORTMAPABREGS_END 0x13A2FC - -#define PTPAHX 0x13B000 -#define PTPALX 0x13B004 - -#define TANSPPAGETABLEPHYADDR015_START 0x13B008 -#define TANSPPAGETABLEPHYADDR015_END 0x13B07C -#define TRNQADRX_START 0x13B100 -#define TRNQADRX_END 0x13B13C -#define TRNQTIMX_START 0x13B200 -#define TRNQTIMX_END 0x13B23C -#define TRNQAPARMX_START 0x13B300 -#define TRNQAPARMX_END 0x13B33C - -#define TRNQCNT 0x13B400 -#define TRNCTL 0x13B404 -#define TRNIS 0x13B408 -#define TRNCURTS 0x13B40C - -#define AMOP_START 0x140000 -#define AMOPLO 0x140000 -#define AMOPHI 0x140004 -#define AMOP_END 0x147FFC -#define PMOP_START 0x148000 -#define PMOPLO 0x148000 -#define PMOPHI 0x148004 -#define PMOP_END 0x14FFFC -#define PCURR_START 0x150000 -#define PCURR_END 0x153FFC -#define PTRAG_START 0x154000 -#define PTRAG_END 0x157FFC -#define PSR_START 0x158000 -#define PSR_END 0x15BFFC - -#define PFSTAT4SEG_START 0x160000 -#define PFSTAT4SEG_END 0x160BFC -#define PFSTAT2SEG_START 0x160C00 -#define PFSTAT2SEG_END 0x1617FC -#define PFTARG4SEG_START 0x164000 -#define PFTARG4SEG_END 0x164BFC -#define PFTARG2SEG_START 0x164C00 -#define PFTARG2SEG_END 0x1657FC -#define PFSR4SEG_START 0x168000 -#define PFSR4SEG_END 0x168BFC -#define PFSR2SEG_START 0x168C00 -#define PFSR2SEG_END 0x1697FC -#define PCURRMS4SEG_START 0x16C000 -#define PCURRMS4SEG_END 0x16CCFC -#define PCURRMS2SEG_START 0x16CC00 -#define PCURRMS2SEG_END 0x16D7FC -#define PTARGMS4SEG_START 0x170000 -#define PTARGMS4SEG_END 0x172FFC -#define PTARGMS2SEG_START 0x173000 -#define PTARGMS2SEG_END 0x1747FC -#define PSRMS4SEG_START 0x170000 -#define PSRMS4SEG_END 0x172FFC -#define PSRMS2SEG_START 0x173000 -#define PSRMS2SEG_END 0x1747FC - -#define PRING_LO_START 0x190000 -#define PRING_LO_END 0x193FFC -#define PRING_HI_START 0x194000 -#define PRING_HI_END 0x197FFC -#define PRING_LO_HI_START 0x198000 -#define PRING_LO_HI 0x198000 -#define PRING_LO_HI_END 0x19BFFC - -#define PINTFIFO 0x1A0000 -#define SRCCTL 0x1B0000 -#define SRCCCR 0x1B0004 -#define SRCIMAP 0x1B0008 -#define SRCODDC 0x1B000C -#define SRCCA 0x1B0010 -#define SRCCF 0x1B0014 -#define SRCSA 0x1B0018 -#define SRCLA 0x1B001C -#define SRCCTLSWR 0x1B0020 - -/* SRC HERE */ -#define SRCALBA 0x1B002C -#define SRCMCTL 0x1B012C -#define SRCCERR 0x1B022C -#define SRCITB 0x1B032C -#define SRCIPM 0x1B082C -#define SRCIP 0x1B102C -#define SRCENBSTAT 0x1B202C -#define SRCENBLO 0x1B212C -#define SRCENBHI 0x1B222C -#define SRCENBS 0x1B232C -#define SRCENB 0x1B282C -#define SRCENB07 0x1B282C -#define SRCENBS07 0x1B302C - -#define SRCDN0Z 0x1B0030 -#define SRCDN0Z0 0x1B0030 -#define SRCDN0Z1 0x1B0034 -#define SRCDN0Z2 0x1B0038 -#define SRCDN0Z3 0x1B003C -#define SRCDN1Z 0x1B0040 -#define SRCDN1Z0 0x1B0040 -#define SRCDN1Z1 0x1B0044 -#define SRCDN1Z2 0x1B0048 -#define SRCDN1Z3 0x1B004C -#define SRCDN1Z4 0x1B0050 -#define SRCDN1Z5 0x1B0054 -#define SRCDN1Z6 0x1B0058 -#define SRCDN1Z7 0x1B005C -#define SRCUPZ 0x1B0060 -#define SRCUPZ0 0x1B0060 -#define SRCUPZ1 0x1B0064 -#define SRCUPZ2 0x1B0068 -#define SRCUPZ3 0x1B006C -#define SRCUPZ4 0x1B0070 -#define SRCUPZ5 0x1B0074 -#define SRCUPZ6 0x1B0078 -#define SRCUPZ7 0x1B007C -#define SRCCD0 0x1B0080 -#define SRCCD1 0x1B0084 -#define SRCCD2 0x1B0088 -#define SRCCD3 0x1B008C -#define SRCCD4 0x1B0090 -#define SRCCD5 0x1B0094 -#define SRCCD6 0x1B0098 -#define SRCCD7 0x1B009C -#define SRCCD8 0x1B00A0 -#define SRCCD9 0x1B00A4 -#define SRCCDA 0x1B00A8 -#define SRCCDB 0x1B00AC -#define SRCCDC 0x1B00B0 -#define SRCCDD 0x1B00B4 -#define SRCCDE 0x1B00B8 -#define SRCCDF 0x1B00BC -#define SRCCD10 0x1B00C0 -#define SRCCD11 0x1B00C4 -#define SRCCD12 0x1B00C8 -#define SRCCD13 0x1B00CC -#define SRCCD14 0x1B00D0 -#define SRCCD15 0x1B00D4 -#define SRCCD16 0x1B00D8 -#define SRCCD17 0x1B00DC -#define SRCCD18 0x1B00E0 -#define SRCCD19 0x1B00E4 -#define SRCCD1A 0x1B00E8 -#define SRCCD1B 0x1B00EC -#define SRCCD1C 0x1B00F0 -#define SRCCD1D 0x1B00F4 -#define SRCCD1E 0x1B00F8 -#define SRCCD1F 0x1B00FC - -#define SRCCONTRBLOCK_START 0x1B0100 -#define SRCCONTRBLOCK_END 0x1BFFFC -#define FILTOP_START 0x1C0000 -#define FILTOP_END 0x1C05FC -#define FILTIMAP_START 0x1C0800 -#define FILTIMAP_END 0x1C0DFC -#define FILTZ1_START 0x1C1000 -#define FILTZ1_END 0x1C15FC -#define FILTZ2_START 0x1C1800 -#define FILTZ2_END 0x1C1DFC -#define DAOIMAP_START 0x1C5000 -#define DAOIMAP 0x1C5000 -#define DAOIMAP_END 0x1C5124 - -#define AC97D 0x1C5400 -#define AC97A 0x1C5404 -#define AC97CTL 0x1C5408 -#define I2SCTL 0x1C5420 - -#define SPOS 0x1C5440 -#define SPOSA 0x1C5440 -#define SPOSB 0x1C5444 -#define SPOSC 0x1C5448 -#define SPOSD 0x1C544C - -#define SPISA 0x1C5450 -#define SPISB 0x1C5454 -#define SPISC 0x1C5458 -#define SPISD 0x1C545C - -#define SPFSCTL 0x1C5460 - -#define SPFS0 0x1C5468 -#define SPFS1 0x1C546C -#define SPFS2 0x1C5470 -#define SPFS3 0x1C5474 -#define SPFS4 0x1C5478 -#define SPFS5 0x1C547C - -#define SPOCTL 0x1C5480 -#define SPICTL 0x1C5484 -#define SPISTS 0x1C5488 -#define SPINTP 0x1C548C -#define SPINTE 0x1C5490 -#define SPUTCTLAB 0x1C5494 -#define SPUTCTLCD 0x1C5498 - -#define SRTSPA 0x1C54C0 -#define SRTSPB 0x1C54C4 -#define SRTSPC 0x1C54C8 -#define SRTSPD 0x1C54CC - -#define SRTSCTL 0x1C54D0 -#define SRTSCTLA 0x1C54D0 -#define SRTSCTLB 0x1C54D4 -#define SRTSCTLC 0x1C54D8 -#define SRTSCTLD 0x1C54DC - -#define SRTI2S 0x1C54E0 -#define SRTICTL 0x1C54F0 - -#define WC 0x1C6000 -#define TIMR 0x1C6004 -# define TIMR_IE (1<<15) -# define TIMR_IP (1<<14) - -#define GIP 0x1C6010 -#define GIE 0x1C6014 -#define DIE 0x1C6018 -#define DIC 0x1C601C -#define GPIO 0x1C6020 -#define GPIOCTL 0x1C6024 -#define GPIP 0x1C6028 -#define GPIE 0x1C602C -#define DSPINT0 0x1C6030 -#define DSPEIOC 0x1C6034 -#define MUADAT 0x1C6040 -#define MUACMD 0x1C6044 -#define MUASTAT 0x1C6044 -#define MUBDAT 0x1C6048 -#define MUBCMD 0x1C604C -#define MUBSTAT 0x1C604C -#define UARTCMA 0x1C6050 -#define UARTCMB 0x1C6054 -#define UARTIP 0x1C6058 -#define UARTIE 0x1C605C -#define PLLCTL 0x1C6060 -#define PLLDCD 0x1C6064 -#define GCTL 0x1C6070 -#define ID0 0x1C6080 -#define ID1 0x1C6084 -#define ID2 0x1C6088 -#define ID3 0x1C608C -#define SDRCTL 0x1C7000 - - -#define I2SA_L 0x0L -#define I2SA_R 0x1L -#define I2SB_L 0x8L -#define I2SB_R 0x9L -#define I2SC_L 0x10L -#define I2SC_R 0x11L -#define I2SD_L 0x18L -#define I2SD_R 0x19L - -#endif /* CT20K1REG_H */ - - diff --git a/trunk/sound/pci/ctxfi/ct20k2reg.h b/trunk/sound/pci/ctxfi/ct20k2reg.h deleted file mode 100644 index 2d07986f57cc..000000000000 --- a/trunk/sound/pci/ctxfi/ct20k2reg.h +++ /dev/null @@ -1,85 +0,0 @@ -/** - * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. - * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - */ - -#ifndef _20K2REGISTERS_H_ -#define _20K2REGISTERS_H_ - - -/* Timer Registers */ -#define TIMER_TIMR 0x1B7004 -#define INTERRUPT_GIP 0x1B7010 -#define INTERRUPT_GIE 0x1B7014 - -/* I2C Registers */ -#define I2C_IF_ADDRESS 0x1B9000 -#define I2C_IF_WDATA 0x1B9004 -#define I2C_IF_RDATA 0x1B9008 -#define I2C_IF_STATUS 0x1B900C -#define I2C_IF_WLOCK 0x1B9010 - -/* Global Control Registers */ -#define GLOBAL_CNTL_GCTL 0x1B7090 - -/* PLL Registers */ -#define PLL_CTL 0x1B7080 -#define PLL_STAT 0x1B7084 -#define PLL_ENB 0x1B7088 - -/* SRC Registers */ -#define SRC_CTL 0x1A0000 /* 0x1A0000 + (256 * Chn) */ -#define SRC_CCR 0x1A0004 /* 0x1A0004 + (256 * Chn) */ -#define SRC_IMAP 0x1A0008 /* 0x1A0008 + (256 * Chn) */ -#define SRC_CA 0x1A0010 /* 0x1A0010 + (256 * Chn) */ -#define SRC_CF 0x1A0014 /* 0x1A0014 + (256 * Chn) */ -#define SRC_SA 0x1A0018 /* 0x1A0018 + (256 * Chn) */ -#define SRC_LA 0x1A001C /* 0x1A001C + (256 * Chn) */ -#define SRC_CTLSWR 0x1A0020 /* 0x1A0020 + (256 * Chn) */ -#define SRC_CD 0x1A0080 /* 0x1A0080 + (256 * Chn) + (4 * Regn) */ -#define SRC_MCTL 0x1A012C -#define SRC_IP 0x1A102C /* 0x1A102C + (256 * Regn) */ -#define SRC_ENB 0x1A282C /* 0x1A282C + (256 * Regn) */ -#define SRC_ENBSTAT 0x1A202C -#define SRC_ENBSA 0x1A232C -#define SRC_DN0Z 0x1A0030 -#define SRC_DN1Z 0x1A0040 -#define SRC_UPZ 0x1A0060 - -/* GPIO Registers */ -#define GPIO_DATA 0x1B7020 -#define GPIO_CTRL 0x1B7024 - -/* Virtual memory registers */ -#define VMEM_PTPAL 0x1C6300 /* 0x1C6300 + (16 * Chn) */ -#define VMEM_PTPAH 0x1C6304 /* 0x1C6304 + (16 * Chn) */ -#define VMEM_CTL 0x1C7000 - -/* Transport Registers */ -#define TRANSPORT_ENB 0x1B6000 -#define TRANSPORT_CTL 0x1B6004 -#define TRANSPORT_INT 0x1B6008 - -/* Audio IO */ -#define AUDIO_IO_AIM 0x1B5000 /* 0x1B5000 + (0x04 * Chn) */ -#define AUDIO_IO_TX_CTL 0x1B5400 /* 0x1B5400 + (0x40 * Chn) */ -#define AUDIO_IO_TX_CSTAT_L 0x1B5408 /* 0x1B5408 + (0x40 * Chn) */ -#define AUDIO_IO_TX_CSTAT_H 0x1B540C /* 0x1B540C + (0x40 * Chn) */ -#define AUDIO_IO_RX_CTL 0x1B5410 /* 0x1B5410 + (0x40 * Chn) */ -#define AUDIO_IO_RX_SRT_CTL 0x1B5420 /* 0x1B5420 + (0x40 * Chn) */ -#define AUDIO_IO_MCLK 0x1B5600 -#define AUDIO_IO_TX_BLRCLK 0x1B5604 -#define AUDIO_IO_RX_BLRCLK 0x1B5608 - -/* Mixer */ -#define MIXER_AMOPLO 0x130000 /* 0x130000 + (8 * Chn) [4095 : 0] */ -#define MIXER_AMOPHI 0x130004 /* 0x130004 + (8 * Chn) [4095 : 0] */ -#define MIXER_PRING_LO_HI 0x188000 /* 0x188000 + (4 * Chn) [4095 : 0] */ -#define MIXER_PMOPLO 0x138000 /* 0x138000 + (8 * Chn) [4095 : 0] */ -#define MIXER_PMOPHI 0x138004 /* 0x138004 + (8 * Chn) [4095 : 0] */ -#define MIXER_AR_ENABLE 0x19000C - -#endif diff --git a/trunk/sound/pci/ctxfi/ctamixer.c b/trunk/sound/pci/ctxfi/ctamixer.c deleted file mode 100644 index a1db51b3ead8..000000000000 --- a/trunk/sound/pci/ctxfi/ctamixer.c +++ /dev/null @@ -1,488 +0,0 @@ -/** - * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. - * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - * - * @File ctamixer.c - * - * @Brief - * This file contains the implementation of the Audio Mixer - * resource management object. - * - * @Author Liu Chun - * @Date May 21 2008 - * - */ - -#include "ctamixer.h" -#include "cthardware.h" -#include - -#define AMIXER_RESOURCE_NUM 256 -#define SUM_RESOURCE_NUM 256 - -#define AMIXER_Y_IMMEDIATE 1 - -#define BLANK_SLOT 4094 - -static int amixer_master(struct rsc *rsc) -{ - rsc->conj = 0; - return rsc->idx = container_of(rsc, struct amixer, rsc)->idx[0]; -} - -static int amixer_next_conj(struct rsc *rsc) -{ - rsc->conj++; - return container_of(rsc, struct amixer, rsc)->idx[rsc->conj]; -} - -static int amixer_index(const struct rsc *rsc) -{ - return container_of(rsc, struct amixer, rsc)->idx[rsc->conj]; -} - -static int amixer_output_slot(const struct rsc *rsc) -{ - return (amixer_index(rsc) << 4) + 0x4; -} - -static struct rsc_ops amixer_basic_rsc_ops = { - .master = amixer_master, - .next_conj = amixer_next_conj, - .index = amixer_index, - .output_slot = amixer_output_slot, -}; - -static int amixer_set_input(struct amixer *amixer, struct rsc *rsc) -{ - struct hw *hw; - - hw = amixer->rsc.hw; - hw->amixer_set_mode(amixer->rsc.ctrl_blk, AMIXER_Y_IMMEDIATE); - amixer->input = rsc; - if (NULL == rsc) - hw->amixer_set_x(amixer->rsc.ctrl_blk, BLANK_SLOT); - else - hw->amixer_set_x(amixer->rsc.ctrl_blk, - rsc->ops->output_slot(rsc)); - - return 0; -} - -/* y is a 14-bit immediate constant */ -static int amixer_set_y(struct amixer *amixer, unsigned int y) -{ - struct hw *hw; - - hw = amixer->rsc.hw; - hw->amixer_set_y(amixer->rsc.ctrl_blk, y); - - return 0; -} - -static int amixer_set_invalid_squash(struct amixer *amixer, unsigned int iv) -{ - struct hw *hw; - - hw = amixer->rsc.hw; - hw->amixer_set_iv(amixer->rsc.ctrl_blk, iv); - - return 0; -} - -static int amixer_set_sum(struct amixer *amixer, struct sum *sum) -{ - struct hw *hw; - - hw = amixer->rsc.hw; - amixer->sum = sum; - if (NULL == sum) { - hw->amixer_set_se(amixer->rsc.ctrl_blk, 0); - } else { - hw->amixer_set_se(amixer->rsc.ctrl_blk, 1); - hw->amixer_set_sadr(amixer->rsc.ctrl_blk, - sum->rsc.ops->index(&sum->rsc)); - } - - return 0; -} - -static int amixer_commit_write(struct amixer *amixer) -{ - struct hw *hw; - unsigned int index; - int i; - struct rsc *input; - struct sum *sum; - - hw = amixer->rsc.hw; - input = amixer->input; - sum = amixer->sum; - - /* Program master and conjugate resources */ - amixer->rsc.ops->master(&amixer->rsc); - if (NULL != input) - input->ops->master(input); - - if (NULL != sum) - sum->rsc.ops->master(&sum->rsc); - - for (i = 0; i < amixer->rsc.msr; i++) { - hw->amixer_set_dirty_all(amixer->rsc.ctrl_blk); - if (NULL != input) { - hw->amixer_set_x(amixer->rsc.ctrl_blk, - input->ops->output_slot(input)); - input->ops->next_conj(input); - } - if (NULL != sum) { - hw->amixer_set_sadr(amixer->rsc.ctrl_blk, - sum->rsc.ops->index(&sum->rsc)); - sum->rsc.ops->next_conj(&sum->rsc); - } - index = amixer->rsc.ops->output_slot(&amixer->rsc); - hw->amixer_commit_write(hw, index, amixer->rsc.ctrl_blk); - amixer->rsc.ops->next_conj(&amixer->rsc); - } - amixer->rsc.ops->master(&amixer->rsc); - if (NULL != input) - input->ops->master(input); - - if (NULL != sum) - sum->rsc.ops->master(&sum->rsc); - - return 0; -} - -static int amixer_commit_raw_write(struct amixer *amixer) -{ - struct hw *hw; - unsigned int index; - - hw = amixer->rsc.hw; - index = amixer->rsc.ops->output_slot(&amixer->rsc); - hw->amixer_commit_write(hw, index, amixer->rsc.ctrl_blk); - - return 0; -} - -static int amixer_get_y(struct amixer *amixer) -{ - struct hw *hw; - - hw = amixer->rsc.hw; - return hw->amixer_get_y(amixer->rsc.ctrl_blk); -} - -static int amixer_setup(struct amixer *amixer, struct rsc *input, - unsigned int scale, struct sum *sum) -{ - amixer_set_input(amixer, input); - amixer_set_y(amixer, scale); - amixer_set_sum(amixer, sum); - amixer_commit_write(amixer); - return 0; -} - -static struct amixer_rsc_ops amixer_ops = { - .set_input = amixer_set_input, - .set_invalid_squash = amixer_set_invalid_squash, - .set_scale = amixer_set_y, - .set_sum = amixer_set_sum, - .commit_write = amixer_commit_write, - .commit_raw_write = amixer_commit_raw_write, - .setup = amixer_setup, - .get_scale = amixer_get_y, -}; - -static int amixer_rsc_init(struct amixer *amixer, - const struct amixer_desc *desc, - struct amixer_mgr *mgr) -{ - int err; - - err = rsc_init(&amixer->rsc, amixer->idx[0], - AMIXER, desc->msr, mgr->mgr.hw); - if (err) - return err; - - /* Set amixer specific operations */ - amixer->rsc.ops = &amixer_basic_rsc_ops; - amixer->ops = &amixer_ops; - amixer->input = NULL; - amixer->sum = NULL; - - amixer_setup(amixer, NULL, 0, NULL); - - return 0; -} - -static int amixer_rsc_uninit(struct amixer *amixer) -{ - amixer_setup(amixer, NULL, 0, NULL); - rsc_uninit(&amixer->rsc); - amixer->ops = NULL; - amixer->input = NULL; - amixer->sum = NULL; - return 0; -} - -static int get_amixer_rsc(struct amixer_mgr *mgr, - const struct amixer_desc *desc, - struct amixer **ramixer) -{ - int err, i; - unsigned int idx; - struct amixer *amixer; - unsigned long flags; - - *ramixer = NULL; - - /* Allocate mem for amixer resource */ - amixer = kzalloc(sizeof(*amixer), GFP_KERNEL); - if (NULL == amixer) { - err = -ENOMEM; - return err; - } - - /* Check whether there are sufficient - * amixer resources to meet request. */ - spin_lock_irqsave(&mgr->mgr_lock, flags); - for (i = 0; i < desc->msr; i++) { - err = mgr_get_resource(&mgr->mgr, 1, &idx); - if (err) - break; - - amixer->idx[i] = idx; - } - spin_unlock_irqrestore(&mgr->mgr_lock, flags); - if (err) { - printk(KERN_ERR "ctxfi: Can't meet AMIXER resource request!\n"); - goto error; - } - - err = amixer_rsc_init(amixer, desc, mgr); - if (err) - goto error; - - *ramixer = amixer; - - return 0; - -error: - spin_lock_irqsave(&mgr->mgr_lock, flags); - for (i--; i >= 0; i--) - mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]); - - spin_unlock_irqrestore(&mgr->mgr_lock, flags); - kfree(amixer); - return err; -} - -static int put_amixer_rsc(struct amixer_mgr *mgr, struct amixer *amixer) -{ - unsigned long flags; - int i; - - spin_lock_irqsave(&mgr->mgr_lock, flags); - for (i = 0; i < amixer->rsc.msr; i++) - mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]); - - spin_unlock_irqrestore(&mgr->mgr_lock, flags); - amixer_rsc_uninit(amixer); - kfree(amixer); - - return 0; -} - -int amixer_mgr_create(void *hw, struct amixer_mgr **ramixer_mgr) -{ - int err; - struct amixer_mgr *amixer_mgr; - - *ramixer_mgr = NULL; - amixer_mgr = kzalloc(sizeof(*amixer_mgr), GFP_KERNEL); - if (NULL == amixer_mgr) - return -ENOMEM; - - err = rsc_mgr_init(&amixer_mgr->mgr, AMIXER, AMIXER_RESOURCE_NUM, hw); - if (err) - goto error; - - spin_lock_init(&amixer_mgr->mgr_lock); - - amixer_mgr->get_amixer = get_amixer_rsc; - amixer_mgr->put_amixer = put_amixer_rsc; - - *ramixer_mgr = amixer_mgr; - - return 0; - -error: - kfree(amixer_mgr); - return err; -} - -int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr) -{ - rsc_mgr_uninit(&amixer_mgr->mgr); - kfree(amixer_mgr); - return 0; -} - -/* SUM resource management */ - -static int sum_master(struct rsc *rsc) -{ - rsc->conj = 0; - return rsc->idx = container_of(rsc, struct sum, rsc)->idx[0]; -} - -static int sum_next_conj(struct rsc *rsc) -{ - rsc->conj++; - return container_of(rsc, struct sum, rsc)->idx[rsc->conj]; -} - -static int sum_index(const struct rsc *rsc) -{ - return container_of(rsc, struct sum, rsc)->idx[rsc->conj]; -} - -static int sum_output_slot(const struct rsc *rsc) -{ - return (sum_index(rsc) << 4) + 0xc; -} - -static struct rsc_ops sum_basic_rsc_ops = { - .master = sum_master, - .next_conj = sum_next_conj, - .index = sum_index, - .output_slot = sum_output_slot, -}; - -static int sum_rsc_init(struct sum *sum, - const struct sum_desc *desc, - struct sum_mgr *mgr) -{ - int err; - - err = rsc_init(&sum->rsc, sum->idx[0], SUM, desc->msr, mgr->mgr.hw); - if (err) - return err; - - sum->rsc.ops = &sum_basic_rsc_ops; - - return 0; -} - -static int sum_rsc_uninit(struct sum *sum) -{ - rsc_uninit(&sum->rsc); - return 0; -} - -static int get_sum_rsc(struct sum_mgr *mgr, - const struct sum_desc *desc, - struct sum **rsum) -{ - int err, i; - unsigned int idx; - struct sum *sum; - unsigned long flags; - - *rsum = NULL; - - /* Allocate mem for sum resource */ - sum = kzalloc(sizeof(*sum), GFP_KERNEL); - if (NULL == sum) { - err = -ENOMEM; - return err; - } - - /* Check whether there are sufficient sum resources to meet request. */ - spin_lock_irqsave(&mgr->mgr_lock, flags); - for (i = 0; i < desc->msr; i++) { - err = mgr_get_resource(&mgr->mgr, 1, &idx); - if (err) - break; - - sum->idx[i] = idx; - } - spin_unlock_irqrestore(&mgr->mgr_lock, flags); - if (err) { - printk(KERN_ERR "ctxfi: Can't meet SUM resource request!\n"); - goto error; - } - - err = sum_rsc_init(sum, desc, mgr); - if (err) - goto error; - - *rsum = sum; - - return 0; - -error: - spin_lock_irqsave(&mgr->mgr_lock, flags); - for (i--; i >= 0; i--) - mgr_put_resource(&mgr->mgr, 1, sum->idx[i]); - - spin_unlock_irqrestore(&mgr->mgr_lock, flags); - kfree(sum); - return err; -} - -static int put_sum_rsc(struct sum_mgr *mgr, struct sum *sum) -{ - unsigned long flags; - int i; - - spin_lock_irqsave(&mgr->mgr_lock, flags); - for (i = 0; i < sum->rsc.msr; i++) - mgr_put_resource(&mgr->mgr, 1, sum->idx[i]); - - spin_unlock_irqrestore(&mgr->mgr_lock, flags); - sum_rsc_uninit(sum); - kfree(sum); - - return 0; -} - -int sum_mgr_create(void *hw, struct sum_mgr **rsum_mgr) -{ - int err; - struct sum_mgr *sum_mgr; - - *rsum_mgr = NULL; - sum_mgr = kzalloc(sizeof(*sum_mgr), GFP_KERNEL); - if (NULL == sum_mgr) - return -ENOMEM; - - err = rsc_mgr_init(&sum_mgr->mgr, SUM, SUM_RESOURCE_NUM, hw); - if (err) - goto error; - - spin_lock_init(&sum_mgr->mgr_lock); - - sum_mgr->get_sum = get_sum_rsc; - sum_mgr->put_sum = put_sum_rsc; - - *rsum_mgr = sum_mgr; - - return 0; - -error: - kfree(sum_mgr); - return err; -} - -int sum_mgr_destroy(struct sum_mgr *sum_mgr) -{ - rsc_mgr_uninit(&sum_mgr->mgr); - kfree(sum_mgr); - return 0; -} - diff --git a/trunk/sound/pci/ctxfi/ctamixer.h b/trunk/sound/pci/ctxfi/ctamixer.h deleted file mode 100644 index cc49e5ab4750..000000000000 --- a/trunk/sound/pci/ctxfi/ctamixer.h +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. - * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - * - * @File ctamixer.h - * - * @Brief - * This file contains the definition of the Audio Mixer - * resource management object. - * - * @Author Liu Chun - * @Date May 21 2008 - * - */ - -#ifndef CTAMIXER_H -#define CTAMIXER_H - -#include "ctresource.h" -#include - -/* Define the descriptor of a summation node resource */ -struct sum { - struct rsc rsc; /* Basic resource info */ - unsigned char idx[8]; -}; - -/* Define sum resource request description info */ -struct sum_desc { - unsigned int msr; -}; - -struct sum_mgr { - struct rsc_mgr mgr; /* Basic resource manager info */ - spinlock_t mgr_lock; - - /* request one sum resource */ - int (*get_sum)(struct sum_mgr *mgr, - const struct sum_desc *desc, struct sum **rsum); - /* return one sum resource */ - int (*put_sum)(struct sum_mgr *mgr, struct sum *sum); -}; - -/* Constructor and destructor of daio resource manager */ -int sum_mgr_create(void *hw, struct sum_mgr **rsum_mgr); -int sum_mgr_destroy(struct sum_mgr *sum_mgr); - -/* Define the descriptor of a amixer resource */ -struct amixer_rsc_ops; - -struct amixer { - struct rsc rsc; /* Basic resource info */ - unsigned char idx[8]; - struct rsc *input; /* pointer to a resource acting as source */ - struct sum *sum; /* Put amixer output to this summation node */ - struct amixer_rsc_ops *ops; /* AMixer specific operations */ -}; - -struct amixer_rsc_ops { - int (*set_input)(struct amixer *amixer, struct rsc *rsc); - int (*set_scale)(struct amixer *amixer, unsigned int scale); - int (*set_invalid_squash)(struct amixer *amixer, unsigned int iv); - int (*set_sum)(struct amixer *amixer, struct sum *sum); - int (*commit_write)(struct amixer *amixer); - /* Only for interleaved recording */ - int (*commit_raw_write)(struct amixer *amixer); - int (*setup)(struct amixer *amixer, struct rsc *input, - unsigned int scale, struct sum *sum); - int (*get_scale)(struct amixer *amixer); -}; - -/* Define amixer resource request description info */ -struct amixer_desc { - unsigned int msr; -}; - -struct amixer_mgr { - struct rsc_mgr mgr; /* Basic resource manager info */ - spinlock_t mgr_lock; - - /* request one amixer resource */ - int (*get_amixer)(struct amixer_mgr *mgr, - const struct amixer_desc *desc, - struct amixer **ramixer); - /* return one amixer resource */ - int (*put_amixer)(struct amixer_mgr *mgr, struct amixer *amixer); -}; - -/* Constructor and destructor of amixer resource manager */ -int amixer_mgr_create(void *hw, struct amixer_mgr **ramixer_mgr); -int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr); - -#endif /* CTAMIXER_H */ diff --git a/trunk/sound/pci/ctxfi/ctatc.c b/trunk/sound/pci/ctxfi/ctatc.c deleted file mode 100644 index a49c76647307..000000000000 --- a/trunk/sound/pci/ctxfi/ctatc.c +++ /dev/null @@ -1,1713 +0,0 @@ -/** - * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. - * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - * - * @File ctatc.c - * - * @Brief - * This file contains the implementation of the device resource management - * object. - * - * @Author Liu Chun - * @Date Mar 28 2008 - */ - -#include "ctatc.h" -#include "ctpcm.h" -#include "ctmixer.h" -#include "cthardware.h" -#include "ctsrc.h" -#include "ctamixer.h" -#include "ctdaio.h" -#include "cttimer.h" -#include -#include -#include -#include - -#define MONO_SUM_SCALE 0x19a8 /* 2^(-0.5) in 14-bit floating format */ -#define DAIONUM 7 -#define MAX_MULTI_CHN 8 - -#define IEC958_DEFAULT_CON ((IEC958_AES0_NONAUDIO \ - | IEC958_AES0_CON_NOT_COPYRIGHT) \ - | ((IEC958_AES1_CON_MIXER \ - | IEC958_AES1_CON_ORIGINAL) << 8) \ - | (0x10 << 16) \ - | ((IEC958_AES3_CON_FS_48000) << 24)) - -static struct snd_pci_quirk __devinitdata subsys_20k1_list[] = { - SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0022, "SB055x", CTSB055X), - SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x002f, "SB055x", CTSB055X), - SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0029, "SB073x", CTSB073X), - SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0031, "SB073x", CTSB073X), - SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000, 0x6000, - "UAA", CTUAA), - { } /* terminator */ -}; - -static struct snd_pci_quirk __devinitdata subsys_20k2_list[] = { - SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB0760, - "SB0760", CTSB0760), - SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08801, - "SB0880", CTSB0880), - SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08802, - "SB0880", CTSB0880), - SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08803, - "SB0880", CTSB0880), - SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000, - PCI_SUBDEVICE_ID_CREATIVE_HENDRIX, "HENDRIX", - CTHENDRIX), - { } /* terminator */ -}; - -static const char *ct_subsys_name[NUM_CTCARDS] = { - /* 20k1 models */ - [CTSB055X] = "SB055x", - [CTSB073X] = "SB073x", - [CTUAA] = "UAA", - [CT20K1_UNKNOWN] = "Unknown", - /* 20k2 models */ - [CTSB0760] = "SB076x", - [CTHENDRIX] = "Hendrix", - [CTSB0880] = "SB0880", - [CT20K2_UNKNOWN] = "Unknown", -}; - -static struct { - int (*create)(struct ct_atc *atc, - enum CTALSADEVS device, const char *device_name); - int (*destroy)(void *alsa_dev); - const char *public_name; -} alsa_dev_funcs[NUM_CTALSADEVS] = { - [FRONT] = { .create = ct_alsa_pcm_create, - .destroy = NULL, - .public_name = "Front/WaveIn"}, - [SURROUND] = { .create = ct_alsa_pcm_create, - .destroy = NULL, - .public_name = "Surround"}, - [CLFE] = { .create = ct_alsa_pcm_create, - .destroy = NULL, - .public_name = "Center/LFE"}, - [SIDE] = { .create = ct_alsa_pcm_create, - .destroy = NULL, - .public_name = "Side"}, - [IEC958] = { .create = ct_alsa_pcm_create, - .destroy = NULL, - .public_name = "IEC958 Non-audio"}, - - [MIXER] = { .create = ct_alsa_mix_create, - .destroy = NULL, - .public_name = "Mixer"} -}; - -typedef int (*create_t)(void *, void **); -typedef int (*destroy_t)(void *); - -static struct { - int (*create)(void *hw, void **rmgr); - int (*destroy)(void *mgr); -} rsc_mgr_funcs[NUM_RSCTYP] = { - [SRC] = { .create = (create_t)src_mgr_create, - .destroy = (destroy_t)src_mgr_destroy }, - [SRCIMP] = { .create = (create_t)srcimp_mgr_create, - .destroy = (destroy_t)srcimp_mgr_destroy }, - [AMIXER] = { .create = (create_t)amixer_mgr_create, - .destroy = (destroy_t)amixer_mgr_destroy }, - [SUM] = { .create = (create_t)sum_mgr_create, - .destroy = (destroy_t)sum_mgr_destroy }, - [DAIO] = { .create = (create_t)daio_mgr_create, - .destroy = (destroy_t)daio_mgr_destroy } -}; - -static int -atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm); - -/* * - * Only mono and interleaved modes are supported now. - * Always allocates a contiguous channel block. - * */ - -static int ct_map_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm) -{ - struct snd_pcm_runtime *runtime; - struct ct_vm *vm; - - if (NULL == apcm->substream) - return 0; - - runtime = apcm->substream->runtime; - vm = atc->vm; - - apcm->vm_block = vm->map(vm, apcm->substream, runtime->dma_bytes); - - if (NULL == apcm->vm_block) - return -ENOENT; - - return 0; -} - -static void ct_unmap_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm) -{ - struct ct_vm *vm; - - if (NULL == apcm->vm_block) - return; - - vm = atc->vm; - - vm->unmap(vm, apcm->vm_block); - - apcm->vm_block = NULL; -} - -static unsigned long atc_get_ptp_phys(struct ct_atc *atc, int index) -{ - struct ct_vm *vm; - void *kvirt_addr; - unsigned long phys_addr; - - vm = atc->vm; - kvirt_addr = vm->get_ptp_virt(vm, index); - if (kvirt_addr == NULL) - phys_addr = (~0UL); - else - phys_addr = virt_to_phys(kvirt_addr); - - return phys_addr; -} - -static unsigned int convert_format(snd_pcm_format_t snd_format) -{ - switch (snd_format) { - case SNDRV_PCM_FORMAT_U8: - return SRC_SF_U8; - case SNDRV_PCM_FORMAT_S16_LE: - return SRC_SF_S16; - case SNDRV_PCM_FORMAT_S24_3LE: - return SRC_SF_S24; - case SNDRV_PCM_FORMAT_S32_LE: - return SRC_SF_S32; - case SNDRV_PCM_FORMAT_FLOAT_LE: - return SRC_SF_F32; - default: - printk(KERN_ERR "ctxfi: not recognized snd format is %d \n", - snd_format); - return SRC_SF_S16; - } -} - -static unsigned int -atc_get_pitch(unsigned int input_rate, unsigned int output_rate) -{ - unsigned int pitch; - int b; - - /* get pitch and convert to fixed-point 8.24 format. */ - pitch = (input_rate / output_rate) << 24; - input_rate %= output_rate; - input_rate /= 100; - output_rate /= 100; - for (b = 31; ((b >= 0) && !(input_rate >> b)); ) - b--; - - if (b >= 0) { - input_rate <<= (31 - b); - input_rate /= output_rate; - b = 24 - (31 - b); - if (b >= 0) - input_rate <<= b; - else - input_rate >>= -b; - - pitch |= input_rate; - } - - return pitch; -} - -static int select_rom(unsigned int pitch) -{ - if ((pitch > 0x00428f5c) && (pitch < 0x01b851ec)) { - /* 0.26 <= pitch <= 1.72 */ - return 1; - } else if ((0x01d66666 == pitch) || (0x01d66667 == pitch)) { - /* pitch == 1.8375 */ - return 2; - } else if (0x02000000 == pitch) { - /* pitch == 2 */ - return 3; - } else if ((pitch >= 0x0) && (pitch <= 0x08000000)) { - /* 0 <= pitch <= 8 */ - return 0; - } else { - return -ENOENT; - } -} - -static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) -{ - struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; - struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER]; - struct src_desc desc = {0}; - struct amixer_desc mix_dsc = {0}; - struct src *src; - struct amixer *amixer; - int err; - int n_amixer = apcm->substream->runtime->channels, i = 0; - int device = apcm->substream->pcm->device; - unsigned int pitch; - - /* first release old resources */ - atc_pcm_release_resources(atc, apcm); - - /* Get SRC resource */ - desc.multi = apcm->substream->runtime->channels; - desc.msr = atc->msr; - desc.mode = MEMRD; - err = src_mgr->get_src(src_mgr, &desc, (struct src **)&apcm->src); - if (err) - goto error1; - - pitch = atc_get_pitch(apcm->substream->runtime->rate, - (atc->rsr * atc->msr)); - src = apcm->src; - src->ops->set_pitch(src, pitch); - src->ops->set_rom(src, select_rom(pitch)); - src->ops->set_sf(src, convert_format(apcm->substream->runtime->format)); - src->ops->set_pm(src, (src->ops->next_interleave(src) != NULL)); - - /* Get AMIXER resource */ - n_amixer = (n_amixer < 2) ? 2 : n_amixer; - apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL); - if (NULL == apcm->amixers) { - err = -ENOMEM; - goto error1; - } - mix_dsc.msr = atc->msr; - for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) { - err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc, - (struct amixer **)&apcm->amixers[i]); - if (err) - goto error1; - - apcm->n_amixer++; - } - - /* Set up device virtual mem map */ - err = ct_map_audio_buffer(atc, apcm); - if (err < 0) - goto error1; - - /* Connect resources */ - src = apcm->src; - for (i = 0; i < n_amixer; i++) { - amixer = apcm->amixers[i]; - mutex_lock(&atc->atc_mutex); - amixer->ops->setup(amixer, &src->rsc, - INIT_VOL, atc->pcm[i+device*2]); - mutex_unlock(&atc->atc_mutex); - src = src->ops->next_interleave(src); - if (NULL == src) - src = apcm->src; - } - - ct_timer_prepare(apcm->timer); - - return 0; - -error1: - atc_pcm_release_resources(atc, apcm); - return err; -} - -static int -atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm) -{ - struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; - struct srcimp_mgr *srcimp_mgr = atc->rsc_mgrs[SRCIMP]; - struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER]; - struct sum_mgr *sum_mgr = atc->rsc_mgrs[SUM]; - struct srcimp *srcimp; - int i; - - if (NULL != apcm->srcimps) { - for (i = 0; i < apcm->n_srcimp; i++) { - srcimp = apcm->srcimps[i]; - srcimp->ops->unmap(srcimp); - srcimp_mgr->put_srcimp(srcimp_mgr, srcimp); - apcm->srcimps[i] = NULL; - } - kfree(apcm->srcimps); - apcm->srcimps = NULL; - } - - if (NULL != apcm->srccs) { - for (i = 0; i < apcm->n_srcc; i++) { - src_mgr->put_src(src_mgr, apcm->srccs[i]); - apcm->srccs[i] = NULL; - } - kfree(apcm->srccs); - apcm->srccs = NULL; - } - - if (NULL != apcm->amixers) { - for (i = 0; i < apcm->n_amixer; i++) { - amixer_mgr->put_amixer(amixer_mgr, apcm->amixers[i]); - apcm->amixers[i] = NULL; - } - kfree(apcm->amixers); - apcm->amixers = NULL; - } - - if (NULL != apcm->mono) { - sum_mgr->put_sum(sum_mgr, apcm->mono); - apcm->mono = NULL; - } - - if (NULL != apcm->src) { - src_mgr->put_src(src_mgr, apcm->src); - apcm->src = NULL; - } - - if (NULL != apcm->vm_block) { - /* Undo device virtual mem map */ - ct_unmap_audio_buffer(atc, apcm); - apcm->vm_block = NULL; - } - - return 0; -} - -static int atc_pcm_playback_start(struct ct_atc *atc, struct ct_atc_pcm *apcm) -{ - unsigned int max_cisz; - struct src *src = apcm->src; - - if (apcm->started) - return 0; - apcm->started = 1; - - max_cisz = src->multi * src->rsc.msr; - max_cisz = 0x80 * (max_cisz < 8 ? max_cisz : 8); - - src->ops->set_sa(src, apcm->vm_block->addr); - src->ops->set_la(src, apcm->vm_block->addr + apcm->vm_block->size); - src->ops->set_ca(src, apcm->vm_block->addr + max_cisz); - src->ops->set_cisz(src, max_cisz); - - src->ops->set_bm(src, 1); - src->ops->set_state(src, SRC_STATE_INIT); - src->ops->commit_write(src); - - ct_timer_start(apcm->timer); - return 0; -} - -static int atc_pcm_stop(struct ct_atc *atc, struct ct_atc_pcm *apcm) -{ - struct src *src; - int i; - - ct_timer_stop(apcm->timer); - - src = apcm->src; - src->ops->set_bm(src, 0); - src->ops->set_state(src, SRC_STATE_OFF); - src->ops->commit_write(src); - - if (NULL != apcm->srccs) { - for (i = 0; i < apcm->n_srcc; i++) { - src = apcm->srccs[i]; - src->ops->set_bm(src, 0); - src->ops->set_state(src, SRC_STATE_OFF); - src->ops->commit_write(src); - } - } - - apcm->started = 0; - - return 0; -} - -static int -atc_pcm_playback_position(struct ct_atc *atc, struct ct_atc_pcm *apcm) -{ - struct src *src = apcm->src; - u32 size, max_cisz; - int position; - - if (!src) - return 0; - position = src->ops->get_ca(src); - - size = apcm->vm_block->size; - max_cisz = src->multi * src->rsc.msr; - max_cisz = 128 * (max_cisz < 8 ? max_cisz : 8); - - return (position + size - max_cisz - apcm->vm_block->addr) % size; -} - -struct src_node_conf_t { - unsigned int pitch; - unsigned int msr:8; - unsigned int mix_msr:8; - unsigned int imp_msr:8; - unsigned int vo:1; -}; - -static void setup_src_node_conf(struct ct_atc *atc, struct ct_atc_pcm *apcm, - struct src_node_conf_t *conf, int *n_srcc) -{ - unsigned int pitch; - - /* get pitch and convert to fixed-point 8.24 format. */ - pitch = atc_get_pitch((atc->rsr * atc->msr), - apcm->substream->runtime->rate); - *n_srcc = 0; - - if (1 == atc->msr) { - *n_srcc = apcm->substream->runtime->channels; - conf[0].pitch = pitch; - conf[0].mix_msr = conf[0].imp_msr = conf[0].msr = 1; - conf[0].vo = 1; - } else if (2 == atc->msr) { - if (0x8000000 < pitch) { - /* Need two-stage SRCs, SRCIMPs and - * AMIXERs for converting format */ - conf[0].pitch = (atc->msr << 24); - conf[0].msr = conf[0].mix_msr = 1; - conf[0].imp_msr = atc->msr; - conf[0].vo = 0; - conf[1].pitch = atc_get_pitch(atc->rsr, - apcm->substream->runtime->rate); - conf[1].msr = conf[1].mix_msr = conf[1].imp_msr = 1; - conf[1].vo = 1; - *n_srcc = apcm->substream->runtime->channels * 2; - } else if (0x1000000 < pitch) { - /* Need one-stage SRCs, SRCIMPs and - * AMIXERs for converting format */ - conf[0].pitch = pitch; - conf[0].msr = conf[0].mix_msr - = conf[0].imp_msr = atc->msr; - conf[0].vo = 1; - *n_srcc = apcm->substream->runtime->channels; - } - } -} - -static int -atc_pcm_capture_get_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm) -{ - struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; - struct srcimp_mgr *srcimp_mgr = atc->rsc_mgrs[SRCIMP]; - struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER]; - struct sum_mgr *sum_mgr = atc->rsc_mgrs[SUM]; - struct src_desc src_dsc = {0}; - struct src *src; - struct srcimp_desc srcimp_dsc = {0}; - struct srcimp *srcimp; - struct amixer_desc mix_dsc = {0}; - struct sum_desc sum_dsc = {0}; - unsigned int pitch; - int multi, err, i; - int n_srcimp, n_amixer, n_srcc, n_sum; - struct src_node_conf_t src_node_conf[2] = {{0} }; - - /* first release old resources */ - atc_pcm_release_resources(atc, apcm); - - /* The numbers of converting SRCs and SRCIMPs should be determined - * by pitch value. */ - - multi = apcm->substream->runtime->channels; - - /* get pitch and convert to fixed-point 8.24 format. */ - pitch = atc_get_pitch((atc->rsr * atc->msr), - apcm->substream->runtime->rate); - - setup_src_node_conf(atc, apcm, src_node_conf, &n_srcc); - n_sum = (1 == multi) ? 1 : 0; - n_amixer = n_sum * 2 + n_srcc; - n_srcimp = n_srcc; - if ((multi > 1) && (0x8000000 >= pitch)) { - /* Need extra AMIXERs and SRCIMPs for special treatment - * of interleaved recording of conjugate channels */ - n_amixer += multi * atc->msr; - n_srcimp += multi * atc->msr; - } else { - n_srcimp += multi; - } - - if (n_srcc) { - apcm->srccs = kzalloc(sizeof(void *)*n_srcc, GFP_KERNEL); - if (NULL == apcm->srccs) - return -ENOMEM; - } - if (n_amixer) { - apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL); - if (NULL == apcm->amixers) { - err = -ENOMEM; - goto error1; - } - } - apcm->srcimps = kzalloc(sizeof(void *)*n_srcimp, GFP_KERNEL); - if (NULL == apcm->srcimps) { - err = -ENOMEM; - goto error1; - } - - /* Allocate SRCs for sample rate conversion if needed */ - src_dsc.multi = 1; - src_dsc.mode = ARCRW; - for (i = 0, apcm->n_srcc = 0; i < n_srcc; i++) { - src_dsc.msr = src_node_conf[i/multi].msr; - err = src_mgr->get_src(src_mgr, &src_dsc, - (struct src **)&apcm->srccs[i]); - if (err) - goto error1; - - src = apcm->srccs[i]; - pitch = src_node_conf[i/multi].pitch; - src->ops->set_pitch(src, pitch); - src->ops->set_rom(src, select_rom(pitch)); - src->ops->set_vo(src, src_node_conf[i/multi].vo); - - apcm->n_srcc++; - } - - /* Allocate AMIXERs for routing SRCs of conversion if needed */ - for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) { - if (i < (n_sum*2)) - mix_dsc.msr = atc->msr; - else if (i < (n_sum*2+n_srcc)) - mix_dsc.msr = src_node_conf[(i-n_sum*2)/multi].mix_msr; - else - mix_dsc.msr = 1; - - err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc, - (struct amixer **)&apcm->amixers[i]); - if (err) - goto error1; - - apcm->n_amixer++; - } - - /* Allocate a SUM resource to mix all input channels together */ - sum_dsc.msr = atc->msr; - err = sum_mgr->get_sum(sum_mgr, &sum_dsc, (struct sum **)&apcm->mono); - if (err) - goto error1; - - pitch = atc_get_pitch((atc->rsr * atc->msr), - apcm->substream->runtime->rate); - /* Allocate SRCIMP resources */ - for (i = 0, apcm->n_srcimp = 0; i < n_srcimp; i++) { - if (i < (n_srcc)) - srcimp_dsc.msr = src_node_conf[i/multi].imp_msr; - else if (1 == multi) - srcimp_dsc.msr = (pitch <= 0x8000000) ? atc->msr : 1; - else - srcimp_dsc.msr = 1; - - err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc, &srcimp); - if (err) - goto error1; - - apcm->srcimps[i] = srcimp; - apcm->n_srcimp++; - } - - /* Allocate a SRC for writing data to host memory */ - src_dsc.multi = apcm->substream->runtime->channels; - src_dsc.msr = 1; - src_dsc.mode = MEMWR; - err = src_mgr->get_src(src_mgr, &src_dsc, (struct src **)&apcm->src); - if (err) - goto error1; - - src = apcm->src; - src->ops->set_pitch(src, pitch); - - /* Set up device virtual mem map */ - err = ct_map_audio_buffer(atc, apcm); - if (err < 0) - goto error1; - - return 0; - -error1: - atc_pcm_release_resources(atc, apcm); - return err; -} - -static int atc_pcm_capture_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) -{ - struct src *src; - struct amixer *amixer; - struct srcimp *srcimp; - struct ct_mixer *mixer = atc->mixer; - struct sum *mono; - struct rsc *out_ports[8] = {NULL}; - int err, i, j, n_sum, multi; - unsigned int pitch; - int mix_base = 0, imp_base = 0; - - atc_pcm_release_resources(atc, apcm); - - /* Get needed resources. */ - err = atc_pcm_capture_get_resources(atc, apcm); - if (err) - return err; - - /* Connect resources */ - mixer->get_output_ports(mixer, MIX_PCMO_FRONT, - &out_ports[0], &out_ports[1]); - - multi = apcm->substream->runtime->channels; - if (1 == multi) { - mono = apcm->mono; - for (i = 0; i < 2; i++) { - amixer = apcm->amixers[i]; - amixer->ops->setup(amixer, out_ports[i], - MONO_SUM_SCALE, mono); - } - out_ports[0] = &mono->rsc; - n_sum = 1; - mix_base = n_sum * 2; - } - - for (i = 0; i < apcm->n_srcc; i++) { - src = apcm->srccs[i]; - srcimp = apcm->srcimps[imp_base+i]; - amixer = apcm->amixers[mix_base+i]; - srcimp->ops->map(srcimp, src, out_ports[i%multi]); - amixer->ops->setup(amixer, &src->rsc, INIT_VOL, NULL); - out_ports[i%multi] = &amixer->rsc; - } - - pitch = atc_get_pitch((atc->rsr * atc->msr), - apcm->substream->runtime->rate); - - if ((multi > 1) && (pitch <= 0x8000000)) { - /* Special connection for interleaved - * recording with conjugate channels */ - for (i = 0; i < multi; i++) { - out_ports[i]->ops->master(out_ports[i]); - for (j = 0; j < atc->msr; j++) { - amixer = apcm->amixers[apcm->n_srcc+j*multi+i]; - amixer->ops->set_input(amixer, out_ports[i]); - amixer->ops->set_scale(amixer, INIT_VOL); - amixer->ops->set_sum(amixer, NULL); - amixer->ops->commit_raw_write(amixer); - out_ports[i]->ops->next_conj(out_ports[i]); - - srcimp = apcm->srcimps[apcm->n_srcc+j*multi+i]; - srcimp->ops->map(srcimp, apcm->src, - &amixer->rsc); - } - } - } else { - for (i = 0; i < multi; i++) { - srcimp = apcm->srcimps[apcm->n_srcc+i]; - srcimp->ops->map(srcimp, apcm->src, out_ports[i]); - } - } - - ct_timer_prepare(apcm->timer); - - return 0; -} - -static int atc_pcm_capture_start(struct ct_atc *atc, struct ct_atc_pcm *apcm) -{ - struct src *src; - struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; - int i, multi; - - if (apcm->started) - return 0; - - apcm->started = 1; - multi = apcm->substream->runtime->channels; - /* Set up converting SRCs */ - for (i = 0; i < apcm->n_srcc; i++) { - src = apcm->srccs[i]; - src->ops->set_pm(src, ((i%multi) != (multi-1))); - src_mgr->src_disable(src_mgr, src); - } - - /* Set up recording SRC */ - src = apcm->src; - src->ops->set_sf(src, convert_format(apcm->substream->runtime->format)); - src->ops->set_sa(src, apcm->vm_block->addr); - src->ops->set_la(src, apcm->vm_block->addr + apcm->vm_block->size); - src->ops->set_ca(src, apcm->vm_block->addr); - src_mgr->src_disable(src_mgr, src); - - /* Disable relevant SRCs firstly */ - src_mgr->commit_write(src_mgr); - - /* Enable SRCs respectively */ - for (i = 0; i < apcm->n_srcc; i++) { - src = apcm->srccs[i]; - src->ops->set_state(src, SRC_STATE_RUN); - src->ops->commit_write(src); - src_mgr->src_enable_s(src_mgr, src); - } - src = apcm->src; - src->ops->set_bm(src, 1); - src->ops->set_state(src, SRC_STATE_RUN); - src->ops->commit_write(src); - src_mgr->src_enable_s(src_mgr, src); - - /* Enable relevant SRCs synchronously */ - src_mgr->commit_write(src_mgr); - - ct_timer_start(apcm->timer); - return 0; -} - -static int -atc_pcm_capture_position(struct ct_atc *atc, struct ct_atc_pcm *apcm) -{ - struct src *src = apcm->src; - - if (!src) - return 0; - return src->ops->get_ca(src) - apcm->vm_block->addr; -} - -static int spdif_passthru_playback_get_resources(struct ct_atc *atc, - struct ct_atc_pcm *apcm) -{ - struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; - struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER]; - struct src_desc desc = {0}; - struct amixer_desc mix_dsc = {0}; - struct src *src; - int err; - int n_amixer = apcm->substream->runtime->channels, i; - unsigned int pitch, rsr = atc->pll_rate; - - /* first release old resources */ - atc_pcm_release_resources(atc, apcm); - - /* Get SRC resource */ - desc.multi = apcm->substream->runtime->channels; - desc.msr = 1; - while (apcm->substream->runtime->rate > (rsr * desc.msr)) - desc.msr <<= 1; - - desc.mode = MEMRD; - err = src_mgr->get_src(src_mgr, &desc, (struct src **)&apcm->src); - if (err) - goto error1; - - pitch = atc_get_pitch(apcm->substream->runtime->rate, (rsr * desc.msr)); - src = apcm->src; - src->ops->set_pitch(src, pitch); - src->ops->set_rom(src, select_rom(pitch)); - src->ops->set_sf(src, convert_format(apcm->substream->runtime->format)); - src->ops->set_pm(src, (src->ops->next_interleave(src) != NULL)); - src->ops->set_bp(src, 1); - - /* Get AMIXER resource */ - n_amixer = (n_amixer < 2) ? 2 : n_amixer; - apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL); - if (NULL == apcm->amixers) { - err = -ENOMEM; - goto error1; - } - mix_dsc.msr = desc.msr; - for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) { - err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc, - (struct amixer **)&apcm->amixers[i]); - if (err) - goto error1; - - apcm->n_amixer++; - } - - /* Set up device virtual mem map */ - err = ct_map_audio_buffer(atc, apcm); - if (err < 0) - goto error1; - - return 0; - -error1: - atc_pcm_release_resources(atc, apcm); - return err; -} - -static int atc_pll_init(struct ct_atc *atc, int rate) -{ - struct hw *hw = atc->hw; - int err; - err = hw->pll_init(hw, rate); - atc->pll_rate = err ? 0 : rate; - return err; -} - -static int -spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm) -{ - struct dao *dao = container_of(atc->daios[SPDIFOO], struct dao, daio); - unsigned int rate = apcm->substream->runtime->rate; - unsigned int status; - int err = 0; - unsigned char iec958_con_fs; - - switch (rate) { - case 48000: - iec958_con_fs = IEC958_AES3_CON_FS_48000; - break; - case 44100: - iec958_con_fs = IEC958_AES3_CON_FS_44100; - break; - case 32000: - iec958_con_fs = IEC958_AES3_CON_FS_32000; - break; - default: - return -ENOENT; - } - - mutex_lock(&atc->atc_mutex); - dao->ops->get_spos(dao, &status); - if (((status >> 24) & IEC958_AES3_CON_FS) != iec958_con_fs) { - status &= ((~IEC958_AES3_CON_FS) << 24); - status |= (iec958_con_fs << 24); - dao->ops->set_spos(dao, status); - dao->ops->commit_write(dao); - } - if ((rate != atc->pll_rate) && (32000 != rate)) - err = atc_pll_init(atc, rate); - mutex_unlock(&atc->atc_mutex); - - return err; -} - -static int -spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) -{ - struct src *src; - struct amixer *amixer; - struct dao *dao; - int err; - int i; - - atc_pcm_release_resources(atc, apcm); - - /* Configure SPDIFOO and PLL to passthrough mode; - * determine pll_rate. */ - err = spdif_passthru_playback_setup(atc, apcm); - if (err) - return err; - - /* Get needed resources. */ - err = spdif_passthru_playback_get_resources(atc, apcm); - if (err) - return err; - - /* Connect resources */ - src = apcm->src; - for (i = 0; i < apcm->n_amixer; i++) { - amixer = apcm->amixers[i]; - amixer->ops->setup(amixer, &src->rsc, INIT_VOL, NULL); - src = src->ops->next_interleave(src); - if (NULL == src) - src = apcm->src; - } - /* Connect to SPDIFOO */ - mutex_lock(&atc->atc_mutex); - dao = container_of(atc->daios[SPDIFOO], struct dao, daio); - amixer = apcm->amixers[0]; - dao->ops->set_left_input(dao, &amixer->rsc); - amixer = apcm->amixers[1]; - dao->ops->set_right_input(dao, &amixer->rsc); - mutex_unlock(&atc->atc_mutex); - - ct_timer_prepare(apcm->timer); - - return 0; -} - -static int atc_select_line_in(struct ct_atc *atc) -{ - struct hw *hw = atc->hw; - struct ct_mixer *mixer = atc->mixer; - struct src *src; - - if (hw->is_adc_source_selected(hw, ADC_LINEIN)) - return 0; - - mixer->set_input_left(mixer, MIX_MIC_IN, NULL); - mixer->set_input_right(mixer, MIX_MIC_IN, NULL); - - hw->select_adc_source(hw, ADC_LINEIN); - - src = atc->srcs[2]; - mixer->set_input_left(mixer, MIX_LINE_IN, &src->rsc); - src = atc->srcs[3]; - mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc); - - return 0; -} - -static int atc_select_mic_in(struct ct_atc *atc) -{ - struct hw *hw = atc->hw; - struct ct_mixer *mixer = atc->mixer; - struct src *src; - - if (hw->is_adc_source_selected(hw, ADC_MICIN)) - return 0; - - mixer->set_input_left(mixer, MIX_LINE_IN, NULL); - mixer->set_input_right(mixer, MIX_LINE_IN, NULL); - - hw->select_adc_source(hw, ADC_MICIN); - - src = atc->srcs[2]; - mixer->set_input_left(mixer, MIX_MIC_IN, &src->rsc); - src = atc->srcs[3]; - mixer->set_input_right(mixer, MIX_MIC_IN, &src->rsc); - - return 0; -} - -static int atc_have_digit_io_switch(struct ct_atc *atc) -{ - struct hw *hw = atc->hw; - - return hw->have_digit_io_switch(hw); -} - -static int atc_select_digit_io(struct ct_atc *atc) -{ - struct hw *hw = atc->hw; - - if (hw->is_adc_source_selected(hw, ADC_NONE)) - return 0; - - hw->select_adc_source(hw, ADC_NONE); - - return 0; -} - -static int atc_daio_unmute(struct ct_atc *atc, unsigned char state, int type) -{ - struct daio_mgr *daio_mgr = atc->rsc_mgrs[DAIO]; - - if (state) - daio_mgr->daio_enable(daio_mgr, atc->daios[type]); - else - daio_mgr->daio_disable(daio_mgr, atc->daios[type]); - - daio_mgr->commit_write(daio_mgr); - - return 0; -} - -static int -atc_dao_get_status(struct ct_atc *atc, unsigned int *status, int type) -{ - struct dao *dao = container_of(atc->daios[type], struct dao, daio); - return dao->ops->get_spos(dao, status); -} - -static int -atc_dao_set_status(struct ct_atc *atc, unsigned int status, int type) -{ - struct dao *dao = container_of(atc->daios[type], struct dao, daio); - - dao->ops->set_spos(dao, status); - dao->ops->commit_write(dao); - return 0; -} - -static int atc_line_front_unmute(struct ct_atc *atc, unsigned char state) -{ - return atc_daio_unmute(atc, state, LINEO1); -} - -static int atc_line_surround_unmute(struct ct_atc *atc, unsigned char state) -{ - return atc_daio_unmute(atc, state, LINEO4); -} - -static int atc_line_clfe_unmute(struct ct_atc *atc, unsigned char state) -{ - return atc_daio_unmute(atc, state, LINEO3); -} - -static int atc_line_rear_unmute(struct ct_atc *atc, unsigned char state) -{ - return atc_daio_unmute(atc, state, LINEO2); -} - -static int atc_line_in_unmute(struct ct_atc *atc, unsigned char state) -{ - return atc_daio_unmute(atc, state, LINEIM); -} - -static int atc_spdif_out_unmute(struct ct_atc *atc, unsigned char state) -{ - return atc_daio_unmute(atc, state, SPDIFOO); -} - -static int atc_spdif_in_unmute(struct ct_atc *atc, unsigned char state) -{ - return atc_daio_unmute(atc, state, SPDIFIO); -} - -static int atc_spdif_out_get_status(struct ct_atc *atc, unsigned int *status) -{ - return atc_dao_get_status(atc, status, SPDIFOO); -} - -static int atc_spdif_out_set_status(struct ct_atc *atc, unsigned int status) -{ - return atc_dao_set_status(atc, status, SPDIFOO); -} - -static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state) -{ - struct dao_desc da_dsc = {0}; - struct dao *dao; - int err; - struct ct_mixer *mixer = atc->mixer; - struct rsc *rscs[2] = {NULL}; - unsigned int spos = 0; - - mutex_lock(&atc->atc_mutex); - dao = container_of(atc->daios[SPDIFOO], struct dao, daio); - da_dsc.msr = state ? 1 : atc->msr; - da_dsc.passthru = state ? 1 : 0; - err = dao->ops->reinit(dao, &da_dsc); - if (state) { - spos = IEC958_DEFAULT_CON; - } else { - mixer->get_output_ports(mixer, MIX_SPDIF_OUT, - &rscs[0], &rscs[1]); - dao->ops->set_left_input(dao, rscs[0]); - dao->ops->set_right_input(dao, rscs[1]); - /* Restore PLL to atc->rsr if needed. */ - if (atc->pll_rate != atc->rsr) - err = atc_pll_init(atc, atc->rsr); - } - dao->ops->set_spos(dao, spos); - dao->ops->commit_write(dao); - mutex_unlock(&atc->atc_mutex); - - return err; -} - -static int atc_release_resources(struct ct_atc *atc) -{ - int i; - struct daio_mgr *daio_mgr = NULL; - struct dao *dao = NULL; - struct dai *dai = NULL; - struct daio *daio = NULL; - struct sum_mgr *sum_mgr = NULL; - struct src_mgr *src_mgr = NULL; - struct srcimp_mgr *srcimp_mgr = NULL; - struct srcimp *srcimp = NULL; - struct ct_mixer *mixer = NULL; - - /* disconnect internal mixer objects */ - if (NULL != atc->mixer) { - mixer = atc->mixer; - mixer->set_input_left(mixer, MIX_LINE_IN, NULL); - mixer->set_input_right(mixer, MIX_LINE_IN, NULL); - mixer->set_input_left(mixer, MIX_MIC_IN, NULL); - mixer->set_input_right(mixer, MIX_MIC_IN, NULL); - mixer->set_input_left(mixer, MIX_SPDIF_IN, NULL); - mixer->set_input_right(mixer, MIX_SPDIF_IN, NULL); - } - - if (NULL != atc->daios) { - daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO]; - for (i = 0; i < atc->n_daio; i++) { - daio = atc->daios[i]; - if (daio->type < LINEIM) { - dao = container_of(daio, struct dao, daio); - dao->ops->clear_left_input(dao); - dao->ops->clear_right_input(dao); - } else { - dai = container_of(daio, struct dai, daio); - /* some thing to do for dai ... */ - } - daio_mgr->put_daio(daio_mgr, daio); - } - kfree(atc->daios); - atc->daios = NULL; - } - - if (NULL != atc->pcm) { - sum_mgr = atc->rsc_mgrs[SUM]; - for (i = 0; i < atc->n_pcm; i++) - sum_mgr->put_sum(sum_mgr, atc->pcm[i]); - - kfree(atc->pcm); - atc->pcm = NULL; - } - - if (NULL != atc->srcs) { - src_mgr = atc->rsc_mgrs[SRC]; - for (i = 0; i < atc->n_src; i++) - src_mgr->put_src(src_mgr, atc->srcs[i]); - - kfree(atc->srcs); - atc->srcs = NULL; - } - - if (NULL != atc->srcimps) { - srcimp_mgr = atc->rsc_mgrs[SRCIMP]; - for (i = 0; i < atc->n_srcimp; i++) { - srcimp = atc->srcimps[i]; - srcimp->ops->unmap(srcimp); - srcimp_mgr->put_srcimp(srcimp_mgr, atc->srcimps[i]); - } - kfree(atc->srcimps); - atc->srcimps = NULL; - } - - return 0; -} - -static int ct_atc_destroy(struct ct_atc *atc) -{ - int i = 0; - - if (NULL == atc) - return 0; - - if (atc->timer) { - ct_timer_free(atc->timer); - atc->timer = NULL; - } - - atc_release_resources(atc); - - /* Destroy internal mixer objects */ - if (NULL != atc->mixer) - ct_mixer_destroy(atc->mixer); - - for (i = 0; i < NUM_RSCTYP; i++) { - if ((NULL != rsc_mgr_funcs[i].destroy) && - (NULL != atc->rsc_mgrs[i])) - rsc_mgr_funcs[i].destroy(atc->rsc_mgrs[i]); - - } - - if (NULL != atc->hw) - destroy_hw_obj((struct hw *)atc->hw); - - /* Destroy device virtual memory manager object */ - if (NULL != atc->vm) { - ct_vm_destroy(atc->vm); - atc->vm = NULL; - } - - kfree(atc); - - return 0; -} - -static int atc_dev_free(struct snd_device *dev) -{ - struct ct_atc *atc = dev->device_data; - return ct_atc_destroy(atc); -} - -static int __devinit atc_identify_card(struct ct_atc *atc) -{ - const struct snd_pci_quirk *p; - const struct snd_pci_quirk *list; - - switch (atc->chip_type) { - case ATC20K1: - atc->chip_name = "20K1"; - list = subsys_20k1_list; - break; - case ATC20K2: - atc->chip_name = "20K2"; - list = subsys_20k2_list; - break; - default: - return -ENOENT; - } - p = snd_pci_quirk_lookup(atc->pci, list); - if (p) { - if (p->value < 0) { - printk(KERN_ERR "ctxfi: " - "Device %04x:%04x is black-listed\n", - atc->pci->subsystem_vendor, - atc->pci->subsystem_device); - return -ENOENT; - } - atc->model = p->value; - } else { - if (atc->chip_type == ATC20K1) - atc->model = CT20K1_UNKNOWN; - else - atc->model = CT20K2_UNKNOWN; - } - atc->model_name = ct_subsys_name[atc->model]; - snd_printd("ctxfi: chip %s model %s (%04x:%04x) is found\n", - atc->chip_name, atc->model_name, - atc->pci->subsystem_vendor, - atc->pci->subsystem_device); - return 0; -} - -int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc) -{ - enum CTALSADEVS i; - int err; - - alsa_dev_funcs[MIXER].public_name = atc->chip_name; - - for (i = 0; i < NUM_CTALSADEVS; i++) { - if (NULL == alsa_dev_funcs[i].create) - continue; - - err = alsa_dev_funcs[i].create(atc, i, - alsa_dev_funcs[i].public_name); - if (err) { - printk(KERN_ERR "ctxfi: " - "Creating alsa device %d failed!\n", i); - return err; - } - } - - return 0; -} - -static int __devinit atc_create_hw_devs(struct ct_atc *atc) -{ - struct hw *hw; - struct card_conf info = {0}; - int i, err; - - err = create_hw_obj(atc->pci, atc->chip_type, atc->model, &hw); - if (err) { - printk(KERN_ERR "Failed to create hw obj!!!\n"); - return err; - } - atc->hw = hw; - - /* Initialize card hardware. */ - info.rsr = atc->rsr; - info.msr = atc->msr; - info.vm_pgt_phys = atc_get_ptp_phys(atc, 0); - err = hw->card_init(hw, &info); - if (err < 0) - return err; - - for (i = 0; i < NUM_RSCTYP; i++) { - if (NULL == rsc_mgr_funcs[i].create) - continue; - - err = rsc_mgr_funcs[i].create(atc->hw, &atc->rsc_mgrs[i]); - if (err) { - printk(KERN_ERR "ctxfi: " - "Failed to create rsc_mgr %d!!!\n", i); - return err; - } - } - - return 0; -} - -static int atc_get_resources(struct ct_atc *atc) -{ - struct daio_desc da_desc = {0}; - struct daio_mgr *daio_mgr; - struct src_desc src_dsc = {0}; - struct src_mgr *src_mgr; - struct srcimp_desc srcimp_dsc = {0}; - struct srcimp_mgr *srcimp_mgr; - struct sum_desc sum_dsc = {0}; - struct sum_mgr *sum_mgr; - int err, i; - - atc->daios = kzalloc(sizeof(void *)*(DAIONUM), GFP_KERNEL); - if (NULL == atc->daios) - return -ENOMEM; - - atc->srcs = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL); - if (NULL == atc->srcs) - return -ENOMEM; - - atc->srcimps = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL); - if (NULL == atc->srcimps) - return -ENOMEM; - - atc->pcm = kzalloc(sizeof(void *)*(2*4), GFP_KERNEL); - if (NULL == atc->pcm) - return -ENOMEM; - - daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO]; - da_desc.msr = atc->msr; - for (i = 0, atc->n_daio = 0; i < DAIONUM-1; i++) { - da_desc.type = i; - err = daio_mgr->get_daio(daio_mgr, &da_desc, - (struct daio **)&atc->daios[i]); - if (err) { - printk(KERN_ERR "ctxfi: Failed to get DAIO " - "resource %d!!!\n", i); - return err; - } - atc->n_daio++; - } - if (atc->model == CTSB073X) - da_desc.type = SPDIFI1; - else - da_desc.type = SPDIFIO; - err = daio_mgr->get_daio(daio_mgr, &da_desc, - (struct daio **)&atc->daios[i]); - if (err) { - printk(KERN_ERR "ctxfi: Failed to get S/PDIF-in resource!!!\n"); - return err; - } - atc->n_daio++; - - src_mgr = atc->rsc_mgrs[SRC]; - src_dsc.multi = 1; - src_dsc.msr = atc->msr; - src_dsc.mode = ARCRW; - for (i = 0, atc->n_src = 0; i < (2*2); i++) { - err = src_mgr->get_src(src_mgr, &src_dsc, - (struct src **)&atc->srcs[i]); - if (err) - return err; - - atc->n_src++; - } - - srcimp_mgr = atc->rsc_mgrs[SRCIMP]; - srcimp_dsc.msr = 8; /* SRCIMPs for S/PDIFIn SRT */ - for (i = 0, atc->n_srcimp = 0; i < (2*1); i++) { - err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc, - (struct srcimp **)&atc->srcimps[i]); - if (err) - return err; - - atc->n_srcimp++; - } - srcimp_dsc.msr = 8; /* SRCIMPs for LINE/MICIn SRT */ - for (i = 0; i < (2*1); i++) { - err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc, - (struct srcimp **)&atc->srcimps[2*1+i]); - if (err) - return err; - - atc->n_srcimp++; - } - - sum_mgr = atc->rsc_mgrs[SUM]; - sum_dsc.msr = atc->msr; - for (i = 0, atc->n_pcm = 0; i < (2*4); i++) { - err = sum_mgr->get_sum(sum_mgr, &sum_dsc, - (struct sum **)&atc->pcm[i]); - if (err) - return err; - - atc->n_pcm++; - } - - return 0; -} - -static void -atc_connect_dai(struct src_mgr *src_mgr, struct dai *dai, - struct src **srcs, struct srcimp **srcimps) -{ - struct rsc *rscs[2] = {NULL}; - struct src *src; - struct srcimp *srcimp; - int i = 0; - - rscs[0] = &dai->daio.rscl; - rscs[1] = &dai->daio.rscr; - for (i = 0; i < 2; i++) { - src = srcs[i]; - srcimp = srcimps[i]; - srcimp->ops->map(srcimp, src, rscs[i]); - src_mgr->src_disable(src_mgr, src); - } - - src_mgr->commit_write(src_mgr); /* Actually disable SRCs */ - - src = srcs[0]; - src->ops->set_pm(src, 1); - for (i = 0; i < 2; i++) { - src = srcs[i]; - src->ops->set_state(src, SRC_STATE_RUN); - src->ops->commit_write(src); - src_mgr->src_enable_s(src_mgr, src); - } - - dai->ops->set_srt_srcl(dai, &(srcs[0]->rsc)); - dai->ops->set_srt_srcr(dai, &(srcs[1]->rsc)); - - dai->ops->set_enb_src(dai, 1); - dai->ops->set_enb_srt(dai, 1); - dai->ops->commit_write(dai); - - src_mgr->commit_write(src_mgr); /* Synchronously enable SRCs */ -} - -static void atc_connect_resources(struct ct_atc *atc) -{ - struct dai *dai; - struct dao *dao; - struct src *src; - struct sum *sum; - struct ct_mixer *mixer; - struct rsc *rscs[2] = {NULL}; - int i, j; - - mixer = atc->mixer; - - for (i = MIX_WAVE_FRONT, j = LINEO1; i <= MIX_SPDIF_OUT; i++, j++) { - mixer->get_output_ports(mixer, i, &rscs[0], &rscs[1]); - dao = container_of(atc->daios[j], struct dao, daio); - dao->ops->set_left_input(dao, rscs[0]); - dao->ops->set_right_input(dao, rscs[1]); - } - - dai = container_of(atc->daios[LINEIM], struct dai, daio); - atc_connect_dai(atc->rsc_mgrs[SRC], dai, - (struct src **)&atc->srcs[2], - (struct srcimp **)&atc->srcimps[2]); - src = atc->srcs[2]; - mixer->set_input_left(mixer, MIX_LINE_IN, &src->rsc); - src = atc->srcs[3]; - mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc); - - dai = container_of(atc->daios[SPDIFIO], struct dai, daio); - atc_connect_dai(atc->rsc_mgrs[SRC], dai, - (struct src **)&atc->srcs[0], - (struct srcimp **)&atc->srcimps[0]); - - src = atc->srcs[0]; - mixer->set_input_left(mixer, MIX_SPDIF_IN, &src->rsc); - src = atc->srcs[1]; - mixer->set_input_right(mixer, MIX_SPDIF_IN, &src->rsc); - - for (i = MIX_PCMI_FRONT, j = 0; i <= MIX_PCMI_SURROUND; i++, j += 2) { - sum = atc->pcm[j]; - mixer->set_input_left(mixer, i, &sum->rsc); - sum = atc->pcm[j+1]; - mixer->set_input_right(mixer, i, &sum->rsc); - } -} - -#ifdef CONFIG_PM -static int atc_suspend(struct ct_atc *atc, pm_message_t state) -{ - int i; - struct hw *hw = atc->hw; - - snd_power_change_state(atc->card, SNDRV_CTL_POWER_D3hot); - - for (i = FRONT; i < NUM_PCMS; i++) { - if (!atc->pcms[i]) - continue; - - snd_pcm_suspend_all(atc->pcms[i]); - } - - atc_release_resources(atc); - - hw->suspend(hw, state); - - return 0; -} - -static int atc_hw_resume(struct ct_atc *atc) -{ - struct hw *hw = atc->hw; - struct card_conf info = {0}; - - /* Re-initialize card hardware. */ - info.rsr = atc->rsr; - info.msr = atc->msr; - info.vm_pgt_phys = atc_get_ptp_phys(atc, 0); - return hw->resume(hw, &info); -} - -static int atc_resources_resume(struct ct_atc *atc) -{ - struct ct_mixer *mixer; - int err = 0; - - /* Get resources */ - err = atc_get_resources(atc); - if (err < 0) { - atc_release_resources(atc); - return err; - } - - /* Build topology */ - atc_connect_resources(atc); - - mixer = atc->mixer; - mixer->resume(mixer); - - return 0; -} - -static int atc_resume(struct ct_atc *atc) -{ - int err = 0; - - /* Do hardware resume. */ - err = atc_hw_resume(atc); - if (err < 0) { - printk(KERN_ERR "ctxfi: pci_enable_device failed, " - "disabling device\n"); - snd_card_disconnect(atc->card); - return err; - } - - err = atc_resources_resume(atc); - if (err < 0) - return err; - - snd_power_change_state(atc->card, SNDRV_CTL_POWER_D0); - - return 0; -} -#endif - -static struct ct_atc atc_preset __devinitdata = { - .map_audio_buffer = ct_map_audio_buffer, - .unmap_audio_buffer = ct_unmap_audio_buffer, - .pcm_playback_prepare = atc_pcm_playback_prepare, - .pcm_release_resources = atc_pcm_release_resources, - .pcm_playback_start = atc_pcm_playback_start, - .pcm_playback_stop = atc_pcm_stop, - .pcm_playback_position = atc_pcm_playback_position, - .pcm_capture_prepare = atc_pcm_capture_prepare, - .pcm_capture_start = atc_pcm_capture_start, - .pcm_capture_stop = atc_pcm_stop, - .pcm_capture_position = atc_pcm_capture_position, - .spdif_passthru_playback_prepare = spdif_passthru_playback_prepare, - .get_ptp_phys = atc_get_ptp_phys, - .select_line_in = atc_select_line_in, - .select_mic_in = atc_select_mic_in, - .select_digit_io = atc_select_digit_io, - .line_front_unmute = atc_line_front_unmute, - .line_surround_unmute = atc_line_surround_unmute, - .line_clfe_unmute = atc_line_clfe_unmute, - .line_rear_unmute = atc_line_rear_unmute, - .line_in_unmute = atc_line_in_unmute, - .spdif_out_unmute = atc_spdif_out_unmute, - .spdif_in_unmute = atc_spdif_in_unmute, - .spdif_out_get_status = atc_spdif_out_get_status, - .spdif_out_set_status = atc_spdif_out_set_status, - .spdif_out_passthru = atc_spdif_out_passthru, - .have_digit_io_switch = atc_have_digit_io_switch, -#ifdef CONFIG_PM - .suspend = atc_suspend, - .resume = atc_resume, -#endif -}; - -/** - * ct_atc_create - create and initialize a hardware manager - * @card: corresponding alsa card object - * @pci: corresponding kernel pci device object - * @ratc: return created object address in it - * - * Creates and initializes a hardware manager. - * - * Creates kmallocated ct_atc structure. Initializes hardware. - * Returns 0 if suceeds, or negative error code if fails. - */ - -int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, - unsigned int rsr, unsigned int msr, - int chip_type, struct ct_atc **ratc) -{ - struct ct_atc *atc; - static struct snd_device_ops ops = { - .dev_free = atc_dev_free, - }; - int err; - - *ratc = NULL; - - atc = kzalloc(sizeof(*atc), GFP_KERNEL); - if (NULL == atc) - return -ENOMEM; - - /* Set operations */ - *atc = atc_preset; - - atc->card = card; - atc->pci = pci; - atc->rsr = rsr; - atc->msr = msr; - atc->chip_type = chip_type; - - mutex_init(&atc->atc_mutex); - - /* Find card model */ - err = atc_identify_card(atc); - if (err < 0) { - printk(KERN_ERR "ctatc: Card not recognised\n"); - goto error1; - } - - /* Set up device virtual memory management object */ - err = ct_vm_create(&atc->vm); - if (err < 0) - goto error1; - - /* Create all atc hw devices */ - err = atc_create_hw_devs(atc); - if (err < 0) - goto error1; - - err = ct_mixer_create(atc, (struct ct_mixer **)&atc->mixer); - if (err) { - printk(KERN_ERR "ctxfi: Failed to create mixer obj!!!\n"); - goto error1; - } - - /* Get resources */ - err = atc_get_resources(atc); - if (err < 0) - goto error1; - - /* Build topology */ - atc_connect_resources(atc); - - atc->timer = ct_timer_new(atc); - if (!atc->timer) - goto error1; - - err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, atc, &ops); - if (err < 0) - goto error1; - - snd_card_set_dev(card, &pci->dev); - - *ratc = atc; - return 0; - -error1: - ct_atc_destroy(atc); - printk(KERN_ERR "ctxfi: Something wrong!!!\n"); - return err; -} diff --git a/trunk/sound/pci/ctxfi/ctatc.h b/trunk/sound/pci/ctxfi/ctatc.h deleted file mode 100644 index 9fd8a5708943..000000000000 --- a/trunk/sound/pci/ctxfi/ctatc.h +++ /dev/null @@ -1,154 +0,0 @@ -/** - * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. - * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - * - * @File ctatc.h - * - * @Brief - * This file contains the definition of the device resource management object. - * - * @Author Liu Chun - * @Date Mar 28 2008 - * - */ - -#ifndef CTATC_H -#define CTATC_H - -#include -#include -#include -#include -#include - -#include "ctvmem.h" -#include "ctresource.h" - -enum CTALSADEVS { /* Types of alsa devices */ - FRONT, - SURROUND, - CLFE, - SIDE, - IEC958, - MIXER, - NUM_CTALSADEVS /* This should always be the last */ -}; - -struct ct_atc_chip_sub_details { - u16 subsys; - const char *nm_model; -}; - -struct ct_atc_chip_details { - u16 vendor; - u16 device; - const struct ct_atc_chip_sub_details *sub_details; - const char *nm_card; -}; - -struct ct_atc; -struct ct_timer; -struct ct_timer_instance; - -/* alsa pcm stream descriptor */ -struct ct_atc_pcm { - struct snd_pcm_substream *substream; - void (*interrupt)(struct ct_atc_pcm *apcm); - struct ct_timer_instance *timer; - unsigned int started:1; - - /* Only mono and interleaved modes are supported now. */ - struct ct_vm_block *vm_block; - void *src; /* SRC for interacting with host memory */ - void **srccs; /* SRCs for sample rate conversion */ - void **srcimps; /* SRC Input Mappers */ - void **amixers; /* AMIXERs for routing converted data */ - void *mono; /* A SUM resource for mixing chs to one */ - unsigned char n_srcc; /* Number of converting SRCs */ - unsigned char n_srcimp; /* Number of SRC Input Mappers */ - unsigned char n_amixer; /* Number of AMIXERs */ -}; - -/* Chip resource management object */ -struct ct_atc { - struct pci_dev *pci; - struct snd_card *card; - unsigned int rsr; /* reference sample rate in Hz */ - unsigned int msr; /* master sample rate in rsr */ - unsigned int pll_rate; /* current rate of Phase Lock Loop */ - - int chip_type; - int model; - const char *chip_name; - const char *model_name; - - struct ct_vm *vm; /* device virtual memory manager for this card */ - int (*map_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm); - void (*unmap_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm); - unsigned long (*get_ptp_phys)(struct ct_atc *atc, int index); - - struct mutex atc_mutex; - - int (*pcm_playback_prepare)(struct ct_atc *atc, - struct ct_atc_pcm *apcm); - int (*pcm_playback_start)(struct ct_atc *atc, struct ct_atc_pcm *apcm); - int (*pcm_playback_stop)(struct ct_atc *atc, struct ct_atc_pcm *apcm); - int (*pcm_playback_position)(struct ct_atc *atc, - struct ct_atc_pcm *apcm); - int (*spdif_passthru_playback_prepare)(struct ct_atc *atc, - struct ct_atc_pcm *apcm); - int (*pcm_capture_prepare)(struct ct_atc *atc, struct ct_atc_pcm *apcm); - int (*pcm_capture_start)(struct ct_atc *atc, struct ct_atc_pcm *apcm); - int (*pcm_capture_stop)(struct ct_atc *atc, struct ct_atc_pcm *apcm); - int (*pcm_capture_position)(struct ct_atc *atc, - struct ct_atc_pcm *apcm); - int (*pcm_release_resources)(struct ct_atc *atc, - struct ct_atc_pcm *apcm); - int (*select_line_in)(struct ct_atc *atc); - int (*select_mic_in)(struct ct_atc *atc); - int (*select_digit_io)(struct ct_atc *atc); - int (*line_front_unmute)(struct ct_atc *atc, unsigned char state); - int (*line_surround_unmute)(struct ct_atc *atc, unsigned char state); - int (*line_clfe_unmute)(struct ct_atc *atc, unsigned char state); - int (*line_rear_unmute)(struct ct_atc *atc, unsigned char state); - int (*line_in_unmute)(struct ct_atc *atc, unsigned char state); - int (*spdif_out_unmute)(struct ct_atc *atc, unsigned char state); - int (*spdif_in_unmute)(struct ct_atc *atc, unsigned char state); - int (*spdif_out_get_status)(struct ct_atc *atc, unsigned int *status); - int (*spdif_out_set_status)(struct ct_atc *atc, unsigned int status); - int (*spdif_out_passthru)(struct ct_atc *atc, unsigned char state); - int (*have_digit_io_switch)(struct ct_atc *atc); - - /* Don't touch! Used for internal object. */ - void *rsc_mgrs[NUM_RSCTYP]; /* chip resource managers */ - void *mixer; /* internal mixer object */ - void *hw; /* chip specific hardware access object */ - void **daios; /* digital audio io resources */ - void **pcm; /* SUMs for collecting all pcm stream */ - void **srcs; /* Sample Rate Converters for input signal */ - void **srcimps; /* input mappers for SRCs */ - unsigned char n_daio; - unsigned char n_src; - unsigned char n_srcimp; - unsigned char n_pcm; - - struct ct_timer *timer; - -#ifdef CONFIG_PM - int (*suspend)(struct ct_atc *atc, pm_message_t state); - int (*resume)(struct ct_atc *atc); -#define NUM_PCMS (NUM_CTALSADEVS - 1) - struct snd_pcm *pcms[NUM_PCMS]; -#endif -}; - - -int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, - unsigned int rsr, unsigned int msr, int chip_type, - struct ct_atc **ratc); -int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc); - -#endif /* CTATC_H */ diff --git a/trunk/sound/pci/ctxfi/ctdaio.c b/trunk/sound/pci/ctxfi/ctdaio.c deleted file mode 100644 index 082e35c08c02..000000000000 --- a/trunk/sound/pci/ctxfi/ctdaio.c +++ /dev/null @@ -1,769 +0,0 @@ -/** - * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. - * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - * - * @File ctdaio.c - * - * @Brief - * This file contains the implementation of Digital Audio Input Output - * resource management object. - * - * @Author Liu Chun - * @Date May 23 2008 - * - */ - -#include "ctdaio.h" -#include "cthardware.h" -#include "ctimap.h" -#include -#include - -#define DAIO_RESOURCE_NUM NUM_DAIOTYP -#define DAIO_OUT_MAX SPDIFOO - -union daio_usage { - struct { - unsigned short lineo1:1; - unsigned short lineo2:1; - unsigned short lineo3:1; - unsigned short lineo4:1; - unsigned short spdifoo:1; - unsigned short lineim:1; - unsigned short spdifio:1; - unsigned short spdifi1:1; - } bf; - unsigned short data; -}; - -struct daio_rsc_idx { - unsigned short left; - unsigned short right; -}; - -struct daio_rsc_idx idx_20k1[NUM_DAIOTYP] = { - [LINEO1] = {.left = 0x00, .right = 0x01}, - [LINEO2] = {.left = 0x18, .right = 0x19}, - [LINEO3] = {.left = 0x08, .right = 0x09}, - [LINEO4] = {.left = 0x10, .right = 0x11}, - [LINEIM] = {.left = 0x1b5, .right = 0x1bd}, - [SPDIFOO] = {.left = 0x20, .right = 0x21}, - [SPDIFIO] = {.left = 0x15, .right = 0x1d}, - [SPDIFI1] = {.left = 0x95, .right = 0x9d}, -}; - -struct daio_rsc_idx idx_20k2[NUM_DAIOTYP] = { - [LINEO1] = {.left = 0x40, .right = 0x41}, - [LINEO2] = {.left = 0x70, .right = 0x71}, - [LINEO3] = {.left = 0x50, .right = 0x51}, - [LINEO4] = {.left = 0x60, .right = 0x61}, - [LINEIM] = {.left = 0x45, .right = 0xc5}, - [SPDIFOO] = {.left = 0x00, .right = 0x01}, - [SPDIFIO] = {.left = 0x05, .right = 0x85}, -}; - -static int daio_master(struct rsc *rsc) -{ - /* Actually, this is not the resource index of DAIO. - * For DAO, it is the input mapper index. And, for DAI, - * it is the output time-slot index. */ - return rsc->conj = rsc->idx; -} - -static int daio_index(const struct rsc *rsc) -{ - return rsc->conj; -} - -static int daio_out_next_conj(struct rsc *rsc) -{ - return rsc->conj += 2; -} - -static int daio_in_next_conj_20k1(struct rsc *rsc) -{ - return rsc->conj += 0x200; -} - -static int daio_in_next_conj_20k2(struct rsc *rsc) -{ - return rsc->conj += 0x100; -} - -static struct rsc_ops daio_out_rsc_ops = { - .master = daio_master, - .next_conj = daio_out_next_conj, - .index = daio_index, - .output_slot = NULL, -}; - -static struct rsc_ops daio_in_rsc_ops_20k1 = { - .master = daio_master, - .next_conj = daio_in_next_conj_20k1, - .index = NULL, - .output_slot = daio_index, -}; - -static struct rsc_ops daio_in_rsc_ops_20k2 = { - .master = daio_master, - .next_conj = daio_in_next_conj_20k2, - .index = NULL, - .output_slot = daio_index, -}; - -static unsigned int daio_device_index(enum DAIOTYP type, struct hw *hw) -{ - switch (hw->chip_type) { - case ATC20K1: - switch (type) { - case SPDIFOO: return 0; - case SPDIFIO: return 0; - case SPDIFI1: return 1; - case LINEO1: return 4; - case LINEO2: return 7; - case LINEO3: return 5; - case LINEO4: return 6; - case LINEIM: return 7; - default: return -EINVAL; - } - case ATC20K2: - switch (type) { - case SPDIFOO: return 0; - case SPDIFIO: return 0; - case LINEO1: return 4; - case LINEO2: return 7; - case LINEO3: return 5; - case LINEO4: return 6; - case LINEIM: return 4; - default: return -EINVAL; - } - default: - return -EINVAL; - } -} - -static int dao_rsc_reinit(struct dao *dao, const struct dao_desc *desc); - -static int dao_spdif_get_spos(struct dao *dao, unsigned int *spos) -{ - ((struct hw *)dao->hw)->dao_get_spos(dao->ctrl_blk, spos); - return 0; -} - -static int dao_spdif_set_spos(struct dao *dao, unsigned int spos) -{ - ((struct hw *)dao->hw)->dao_set_spos(dao->ctrl_blk, spos); - return 0; -} - -static int dao_commit_write(struct dao *dao) -{ - ((struct hw *)dao->hw)->dao_commit_write(dao->hw, - daio_device_index(dao->daio.type, dao->hw), dao->ctrl_blk); - return 0; -} - -static int dao_set_left_input(struct dao *dao, struct rsc *input) -{ - struct imapper *entry; - struct daio *daio = &dao->daio; - int i; - - entry = kzalloc((sizeof(*entry) * daio->rscl.msr), GFP_KERNEL); - if (NULL == entry) - return -ENOMEM; - - /* Program master and conjugate resources */ - input->ops->master(input); - daio->rscl.ops->master(&daio->rscl); - for (i = 0; i < daio->rscl.msr; i++, entry++) { - entry->slot = input->ops->output_slot(input); - entry->user = entry->addr = daio->rscl.ops->index(&daio->rscl); - dao->mgr->imap_add(dao->mgr, entry); - dao->imappers[i] = entry; - - input->ops->next_conj(input); - daio->rscl.ops->next_conj(&daio->rscl); - } - input->ops->master(input); - daio->rscl.ops->master(&daio->rscl); - - return 0; -} - -static int dao_set_right_input(struct dao *dao, struct rsc *input) -{ - struct imapper *entry; - struct daio *daio = &dao->daio; - int i; - - entry = kzalloc((sizeof(*entry) * daio->rscr.msr), GFP_KERNEL); - if (NULL == entry) - return -ENOMEM; - - /* Program master and conjugate resources */ - input->ops->master(input); - daio->rscr.ops->master(&daio->rscr); - for (i = 0; i < daio->rscr.msr; i++, entry++) { - entry->slot = input->ops->output_slot(input); - entry->user = entry->addr = daio->rscr.ops->index(&daio->rscr); - dao->mgr->imap_add(dao->mgr, entry); - dao->imappers[daio->rscl.msr + i] = entry; - - input->ops->next_conj(input); - daio->rscr.ops->next_conj(&daio->rscr); - } - input->ops->master(input); - daio->rscr.ops->master(&daio->rscr); - - return 0; -} - -static int dao_clear_left_input(struct dao *dao) -{ - struct imapper *entry; - struct daio *daio = &dao->daio; - int i; - - if (NULL == dao->imappers[0]) - return 0; - - entry = dao->imappers[0]; - dao->mgr->imap_delete(dao->mgr, entry); - /* Program conjugate resources */ - for (i = 1; i < daio->rscl.msr; i++) { - entry = dao->imappers[i]; - dao->mgr->imap_delete(dao->mgr, entry); - dao->imappers[i] = NULL; - } - - kfree(dao->imappers[0]); - dao->imappers[0] = NULL; - - return 0; -} - -static int dao_clear_right_input(struct dao *dao) -{ - struct imapper *entry; - struct daio *daio = &dao->daio; - int i; - - if (NULL == dao->imappers[daio->rscl.msr]) - return 0; - - entry = dao->imappers[daio->rscl.msr]; - dao->mgr->imap_delete(dao->mgr, entry); - /* Program conjugate resources */ - for (i = 1; i < daio->rscr.msr; i++) { - entry = dao->imappers[daio->rscl.msr + i]; - dao->mgr->imap_delete(dao->mgr, entry); - dao->imappers[daio->rscl.msr + i] = NULL; - } - - kfree(dao->imappers[daio->rscl.msr]); - dao->imappers[daio->rscl.msr] = NULL; - - return 0; -} - -static struct dao_rsc_ops dao_ops = { - .set_spos = dao_spdif_set_spos, - .commit_write = dao_commit_write, - .get_spos = dao_spdif_get_spos, - .reinit = dao_rsc_reinit, - .set_left_input = dao_set_left_input, - .set_right_input = dao_set_right_input, - .clear_left_input = dao_clear_left_input, - .clear_right_input = dao_clear_right_input, -}; - -static int dai_set_srt_srcl(struct dai *dai, struct rsc *src) -{ - src->ops->master(src); - ((struct hw *)dai->hw)->dai_srt_set_srcm(dai->ctrl_blk, - src->ops->index(src)); - return 0; -} - -static int dai_set_srt_srcr(struct dai *dai, struct rsc *src) -{ - src->ops->master(src); - ((struct hw *)dai->hw)->dai_srt_set_srco(dai->ctrl_blk, - src->ops->index(src)); - return 0; -} - -static int dai_set_srt_msr(struct dai *dai, unsigned int msr) -{ - unsigned int rsr; - - for (rsr = 0; msr > 1; msr >>= 1) - rsr++; - - ((struct hw *)dai->hw)->dai_srt_set_rsr(dai->ctrl_blk, rsr); - return 0; -} - -static int dai_set_enb_src(struct dai *dai, unsigned int enb) -{ - ((struct hw *)dai->hw)->dai_srt_set_ec(dai->ctrl_blk, enb); - return 0; -} - -static int dai_set_enb_srt(struct dai *dai, unsigned int enb) -{ - ((struct hw *)dai->hw)->dai_srt_set_et(dai->ctrl_blk, enb); - return 0; -} - -static int dai_commit_write(struct dai *dai) -{ - ((struct hw *)dai->hw)->dai_commit_write(dai->hw, - daio_device_index(dai->daio.type, dai->hw), dai->ctrl_blk); - return 0; -} - -static struct dai_rsc_ops dai_ops = { - .set_srt_srcl = dai_set_srt_srcl, - .set_srt_srcr = dai_set_srt_srcr, - .set_srt_msr = dai_set_srt_msr, - .set_enb_src = dai_set_enb_src, - .set_enb_srt = dai_set_enb_srt, - .commit_write = dai_commit_write, -}; - -static int daio_rsc_init(struct daio *daio, - const struct daio_desc *desc, - void *hw) -{ - int err; - unsigned int idx_l, idx_r; - - switch (((struct hw *)hw)->chip_type) { - case ATC20K1: - idx_l = idx_20k1[desc->type].left; - idx_r = idx_20k1[desc->type].right; - break; - case ATC20K2: - idx_l = idx_20k2[desc->type].left; - idx_r = idx_20k2[desc->type].right; - break; - default: - return -EINVAL; - } - err = rsc_init(&daio->rscl, idx_l, DAIO, desc->msr, hw); - if (err) - return err; - - err = rsc_init(&daio->rscr, idx_r, DAIO, desc->msr, hw); - if (err) - goto error1; - - /* Set daio->rscl/r->ops to daio specific ones */ - if (desc->type <= DAIO_OUT_MAX) { - daio->rscl.ops = daio->rscr.ops = &daio_out_rsc_ops; - } else { - switch (((struct hw *)hw)->chip_type) { - case ATC20K1: - daio->rscl.ops = daio->rscr.ops = &daio_in_rsc_ops_20k1; - break; - case ATC20K2: - daio->rscl.ops = daio->rscr.ops = &daio_in_rsc_ops_20k2; - break; - default: - break; - } - } - daio->type = desc->type; - - return 0; - -error1: - rsc_uninit(&daio->rscl); - return err; -} - -static int daio_rsc_uninit(struct daio *daio) -{ - rsc_uninit(&daio->rscl); - rsc_uninit(&daio->rscr); - - return 0; -} - -static int dao_rsc_init(struct dao *dao, - const struct daio_desc *desc, - struct daio_mgr *mgr) -{ - struct hw *hw = mgr->mgr.hw; - unsigned int conf; - int err; - - err = daio_rsc_init(&dao->daio, desc, mgr->mgr.hw); - if (err) - return err; - - dao->imappers = kzalloc(sizeof(void *)*desc->msr*2, GFP_KERNEL); - if (NULL == dao->imappers) { - err = -ENOMEM; - goto error1; - } - dao->ops = &dao_ops; - dao->mgr = mgr; - dao->hw = hw; - err = hw->dao_get_ctrl_blk(&dao->ctrl_blk); - if (err) - goto error2; - - hw->daio_mgr_dsb_dao(mgr->mgr.ctrl_blk, - daio_device_index(dao->daio.type, hw)); - hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk); - - conf = (desc->msr & 0x7) | (desc->passthru << 3); - hw->daio_mgr_dao_init(mgr->mgr.ctrl_blk, - daio_device_index(dao->daio.type, hw), conf); - hw->daio_mgr_enb_dao(mgr->mgr.ctrl_blk, - daio_device_index(dao->daio.type, hw)); - hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk); - - return 0; - -error2: - kfree(dao->imappers); - dao->imappers = NULL; -error1: - daio_rsc_uninit(&dao->daio); - return err; -} - -static int dao_rsc_uninit(struct dao *dao) -{ - if (NULL != dao->imappers) { - if (NULL != dao->imappers[0]) - dao_clear_left_input(dao); - - if (NULL != dao->imappers[dao->daio.rscl.msr]) - dao_clear_right_input(dao); - - kfree(dao->imappers); - dao->imappers = NULL; - } - ((struct hw *)dao->hw)->dao_put_ctrl_blk(dao->ctrl_blk); - dao->hw = dao->ctrl_blk = NULL; - daio_rsc_uninit(&dao->daio); - - return 0; -} - -static int dao_rsc_reinit(struct dao *dao, const struct dao_desc *desc) -{ - struct daio_mgr *mgr = dao->mgr; - struct daio_desc dsc = {0}; - - dsc.type = dao->daio.type; - dsc.msr = desc->msr; - dsc.passthru = desc->passthru; - dao_rsc_uninit(dao); - return dao_rsc_init(dao, &dsc, mgr); -} - -static int dai_rsc_init(struct dai *dai, - const struct daio_desc *desc, - struct daio_mgr *mgr) -{ - int err; - struct hw *hw = mgr->mgr.hw; - unsigned int rsr, msr; - - err = daio_rsc_init(&dai->daio, desc, mgr->mgr.hw); - if (err) - return err; - - dai->ops = &dai_ops; - dai->hw = mgr->mgr.hw; - err = hw->dai_get_ctrl_blk(&dai->ctrl_blk); - if (err) - goto error1; - - for (rsr = 0, msr = desc->msr; msr > 1; msr >>= 1) - rsr++; - - hw->dai_srt_set_rsr(dai->ctrl_blk, rsr); - hw->dai_srt_set_drat(dai->ctrl_blk, 0); - /* default to disabling control of a SRC */ - hw->dai_srt_set_ec(dai->ctrl_blk, 0); - hw->dai_srt_set_et(dai->ctrl_blk, 0); /* default to disabling SRT */ - hw->dai_commit_write(hw, - daio_device_index(dai->daio.type, dai->hw), dai->ctrl_blk); - - return 0; - -error1: - daio_rsc_uninit(&dai->daio); - return err; -} - -static int dai_rsc_uninit(struct dai *dai) -{ - ((struct hw *)dai->hw)->dai_put_ctrl_blk(dai->ctrl_blk); - dai->hw = dai->ctrl_blk = NULL; - daio_rsc_uninit(&dai->daio); - return 0; -} - -static int daio_mgr_get_rsc(struct rsc_mgr *mgr, enum DAIOTYP type) -{ - if (((union daio_usage *)mgr->rscs)->data & (0x1 << type)) - return -ENOENT; - - ((union daio_usage *)mgr->rscs)->data |= (0x1 << type); - - return 0; -} - -static int daio_mgr_put_rsc(struct rsc_mgr *mgr, enum DAIOTYP type) -{ - ((union daio_usage *)mgr->rscs)->data &= ~(0x1 << type); - - return 0; -} - -static int get_daio_rsc(struct daio_mgr *mgr, - const struct daio_desc *desc, - struct daio **rdaio) -{ - int err; - struct dai *dai = NULL; - struct dao *dao = NULL; - unsigned long flags; - - *rdaio = NULL; - - /* Check whether there are sufficient daio resources to meet request. */ - spin_lock_irqsave(&mgr->mgr_lock, flags); - err = daio_mgr_get_rsc(&mgr->mgr, desc->type); - spin_unlock_irqrestore(&mgr->mgr_lock, flags); - if (err) { - printk(KERN_ERR "Can't meet DAIO resource request!\n"); - return err; - } - - /* Allocate mem for daio resource */ - if (desc->type <= DAIO_OUT_MAX) { - dao = kzalloc(sizeof(*dao), GFP_KERNEL); - if (NULL == dao) { - err = -ENOMEM; - goto error; - } - err = dao_rsc_init(dao, desc, mgr); - if (err) - goto error; - - *rdaio = &dao->daio; - } else { - dai = kzalloc(sizeof(*dai), GFP_KERNEL); - if (NULL == dai) { - err = -ENOMEM; - goto error; - } - err = dai_rsc_init(dai, desc, mgr); - if (err) - goto error; - - *rdaio = &dai->daio; - } - - mgr->daio_enable(mgr, *rdaio); - mgr->commit_write(mgr); - - return 0; - -error: - if (NULL != dao) - kfree(dao); - else if (NULL != dai) - kfree(dai); - - spin_lock_irqsave(&mgr->mgr_lock, flags); - daio_mgr_put_rsc(&mgr->mgr, desc->type); - spin_unlock_irqrestore(&mgr->mgr_lock, flags); - return err; -} - -static int put_daio_rsc(struct daio_mgr *mgr, struct daio *daio) -{ - unsigned long flags; - - mgr->daio_disable(mgr, daio); - mgr->commit_write(mgr); - - spin_lock_irqsave(&mgr->mgr_lock, flags); - daio_mgr_put_rsc(&mgr->mgr, daio->type); - spin_unlock_irqrestore(&mgr->mgr_lock, flags); - - if (daio->type <= DAIO_OUT_MAX) { - dao_rsc_uninit(container_of(daio, struct dao, daio)); - kfree(container_of(daio, struct dao, daio)); - } else { - dai_rsc_uninit(container_of(daio, struct dai, daio)); - kfree(container_of(daio, struct dai, daio)); - } - - return 0; -} - -static int daio_mgr_enb_daio(struct daio_mgr *mgr, struct daio *daio) -{ - struct hw *hw = mgr->mgr.hw; - - if (DAIO_OUT_MAX >= daio->type) { - hw->daio_mgr_enb_dao(mgr->mgr.ctrl_blk, - daio_device_index(daio->type, hw)); - } else { - hw->daio_mgr_enb_dai(mgr->mgr.ctrl_blk, - daio_device_index(daio->type, hw)); - } - return 0; -} - -static int daio_mgr_dsb_daio(struct daio_mgr *mgr, struct daio *daio) -{ - struct hw *hw = mgr->mgr.hw; - - if (DAIO_OUT_MAX >= daio->type) { - hw->daio_mgr_dsb_dao(mgr->mgr.ctrl_blk, - daio_device_index(daio->type, hw)); - } else { - hw->daio_mgr_dsb_dai(mgr->mgr.ctrl_blk, - daio_device_index(daio->type, hw)); - } - return 0; -} - -static int daio_map_op(void *data, struct imapper *entry) -{ - struct rsc_mgr *mgr = &((struct daio_mgr *)data)->mgr; - struct hw *hw = mgr->hw; - - hw->daio_mgr_set_imaparc(mgr->ctrl_blk, entry->slot); - hw->daio_mgr_set_imapnxt(mgr->ctrl_blk, entry->next); - hw->daio_mgr_set_imapaddr(mgr->ctrl_blk, entry->addr); - hw->daio_mgr_commit_write(mgr->hw, mgr->ctrl_blk); - - return 0; -} - -static int daio_imap_add(struct daio_mgr *mgr, struct imapper *entry) -{ - unsigned long flags; - int err; - - spin_lock_irqsave(&mgr->imap_lock, flags); - if ((0 == entry->addr) && (mgr->init_imap_added)) { - input_mapper_delete(&mgr->imappers, mgr->init_imap, - daio_map_op, mgr); - mgr->init_imap_added = 0; - } - err = input_mapper_add(&mgr->imappers, entry, daio_map_op, mgr); - spin_unlock_irqrestore(&mgr->imap_lock, flags); - - return err; -} - -static int daio_imap_delete(struct daio_mgr *mgr, struct imapper *entry) -{ - unsigned long flags; - int err; - - spin_lock_irqsave(&mgr->imap_lock, flags); - err = input_mapper_delete(&mgr->imappers, entry, daio_map_op, mgr); - if (list_empty(&mgr->imappers)) { - input_mapper_add(&mgr->imappers, mgr->init_imap, - daio_map_op, mgr); - mgr->init_imap_added = 1; - } - spin_unlock_irqrestore(&mgr->imap_lock, flags); - - return err; -} - -static int daio_mgr_commit_write(struct daio_mgr *mgr) -{ - struct hw *hw = mgr->mgr.hw; - - hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk); - return 0; -} - -int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr) -{ - int err, i; - struct daio_mgr *daio_mgr; - struct imapper *entry; - - *rdaio_mgr = NULL; - daio_mgr = kzalloc(sizeof(*daio_mgr), GFP_KERNEL); - if (NULL == daio_mgr) - return -ENOMEM; - - err = rsc_mgr_init(&daio_mgr->mgr, DAIO, DAIO_RESOURCE_NUM, hw); - if (err) - goto error1; - - spin_lock_init(&daio_mgr->mgr_lock); - spin_lock_init(&daio_mgr->imap_lock); - INIT_LIST_HEAD(&daio_mgr->imappers); - entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (NULL == entry) { - err = -ENOMEM; - goto error2; - } - entry->slot = entry->addr = entry->next = entry->user = 0; - list_add(&entry->list, &daio_mgr->imappers); - daio_mgr->init_imap = entry; - daio_mgr->init_imap_added = 1; - - daio_mgr->get_daio = get_daio_rsc; - daio_mgr->put_daio = put_daio_rsc; - daio_mgr->daio_enable = daio_mgr_enb_daio; - daio_mgr->daio_disable = daio_mgr_dsb_daio; - daio_mgr->imap_add = daio_imap_add; - daio_mgr->imap_delete = daio_imap_delete; - daio_mgr->commit_write = daio_mgr_commit_write; - - for (i = 0; i < 8; i++) { - ((struct hw *)hw)->daio_mgr_dsb_dao(daio_mgr->mgr.ctrl_blk, i); - ((struct hw *)hw)->daio_mgr_dsb_dai(daio_mgr->mgr.ctrl_blk, i); - } - ((struct hw *)hw)->daio_mgr_commit_write(hw, daio_mgr->mgr.ctrl_blk); - - *rdaio_mgr = daio_mgr; - - return 0; - -error2: - rsc_mgr_uninit(&daio_mgr->mgr); -error1: - kfree(daio_mgr); - return err; -} - -int daio_mgr_destroy(struct daio_mgr *daio_mgr) -{ - unsigned long flags; - - /* free daio input mapper list */ - spin_lock_irqsave(&daio_mgr->imap_lock, flags); - free_input_mapper_list(&daio_mgr->imappers); - spin_unlock_irqrestore(&daio_mgr->imap_lock, flags); - - rsc_mgr_uninit(&daio_mgr->mgr); - kfree(daio_mgr); - - return 0; -} - diff --git a/trunk/sound/pci/ctxfi/ctdaio.h b/trunk/sound/pci/ctxfi/ctdaio.h deleted file mode 100644 index 0f52ce571ee8..000000000000 --- a/trunk/sound/pci/ctxfi/ctdaio.h +++ /dev/null @@ -1,122 +0,0 @@ -/** - * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. - * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - * - * @File ctdaio.h - * - * @Brief - * This file contains the definition of Digital Audio Input Output - * resource management object. - * - * @Author Liu Chun - * @Date May 23 2008 - * - */ - -#ifndef CTDAIO_H -#define CTDAIO_H - -#include "ctresource.h" -#include "ctimap.h" -#include -#include - -/* Define the descriptor of a daio resource */ -enum DAIOTYP { - LINEO1, - LINEO2, - LINEO3, - LINEO4, - SPDIFOO, /* S/PDIF Out (Flexijack/Optical) */ - LINEIM, - SPDIFIO, /* S/PDIF In (Flexijack/Optical) on the card */ - SPDIFI1, /* S/PDIF In on internal Drive Bay */ - NUM_DAIOTYP -}; - -struct dao_rsc_ops; -struct dai_rsc_ops; -struct daio_mgr; - -struct daio { - struct rsc rscl; /* Basic resource info for left TX/RX */ - struct rsc rscr; /* Basic resource info for right TX/RX */ - enum DAIOTYP type; -}; - -struct dao { - struct daio daio; - struct dao_rsc_ops *ops; /* DAO specific operations */ - struct imapper **imappers; - struct daio_mgr *mgr; - void *hw; - void *ctrl_blk; -}; - -struct dai { - struct daio daio; - struct dai_rsc_ops *ops; /* DAI specific operations */ - void *hw; - void *ctrl_blk; -}; - -struct dao_desc { - unsigned int msr:4; - unsigned int passthru:1; -}; - -struct dao_rsc_ops { - int (*set_spos)(struct dao *dao, unsigned int spos); - int (*commit_write)(struct dao *dao); - int (*get_spos)(struct dao *dao, unsigned int *spos); - int (*reinit)(struct dao *dao, const struct dao_desc *desc); - int (*set_left_input)(struct dao *dao, struct rsc *input); - int (*set_right_input)(struct dao *dao, struct rsc *input); - int (*clear_left_input)(struct dao *dao); - int (*clear_right_input)(struct dao *dao); -}; - -struct dai_rsc_ops { - int (*set_srt_srcl)(struct dai *dai, struct rsc *src); - int (*set_srt_srcr)(struct dai *dai, struct rsc *src); - int (*set_srt_msr)(struct dai *dai, unsigned int msr); - int (*set_enb_src)(struct dai *dai, unsigned int enb); - int (*set_enb_srt)(struct dai *dai, unsigned int enb); - int (*commit_write)(struct dai *dai); -}; - -/* Define daio resource request description info */ -struct daio_desc { - unsigned int type:4; - unsigned int msr:4; - unsigned int passthru:1; -}; - -struct daio_mgr { - struct rsc_mgr mgr; /* Basic resource manager info */ - spinlock_t mgr_lock; - spinlock_t imap_lock; - struct list_head imappers; - struct imapper *init_imap; - unsigned int init_imap_added; - - /* request one daio resource */ - int (*get_daio)(struct daio_mgr *mgr, - const struct daio_desc *desc, struct daio **rdaio); - /* return one daio resource */ - int (*put_daio)(struct daio_mgr *mgr, struct daio *daio); - int (*daio_enable)(struct daio_mgr *mgr, struct daio *daio); - int (*daio_disable)(struct daio_mgr *mgr, struct daio *daio); - int (*imap_add)(struct daio_mgr *mgr, struct imapper *entry); - int (*imap_delete)(struct daio_mgr *mgr, struct imapper *entry); - int (*commit_write)(struct daio_mgr *mgr); -}; - -/* Constructor and destructor of daio resource manager */ -int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr); -int daio_mgr_destroy(struct daio_mgr *daio_mgr); - -#endif /* CTDAIO_H */ diff --git a/trunk/sound/pci/ctxfi/cthardware.c b/trunk/sound/pci/ctxfi/cthardware.c deleted file mode 100644 index 8e64f4862e85..000000000000 --- a/trunk/sound/pci/ctxfi/cthardware.c +++ /dev/null @@ -1,91 +0,0 @@ -/** - * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. - * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - * - * @File cthardware.c - * - * @Brief - * This file contains the implementation of hardware access methord. - * - * @Author Liu Chun - * @Date Jun 26 2008 - * - */ - -#include "cthardware.h" -#include "cthw20k1.h" -#include "cthw20k2.h" -#include - -int __devinit create_hw_obj(struct pci_dev *pci, enum CHIPTYP chip_type, - enum CTCARDS model, struct hw **rhw) -{ - int err; - - switch (chip_type) { - case ATC20K1: - err = create_20k1_hw_obj(rhw); - break; - case ATC20K2: - err = create_20k2_hw_obj(rhw); - break; - default: - err = -ENODEV; - break; - } - if (err) - return err; - - (*rhw)->pci = pci; - (*rhw)->chip_type = chip_type; - (*rhw)->model = model; - - return 0; -} - -int destroy_hw_obj(struct hw *hw) -{ - int err; - - switch (hw->pci->device) { - case 0x0005: /* 20k1 device */ - err = destroy_20k1_hw_obj(hw); - break; - case 0x000B: /* 20k2 device */ - err = destroy_20k2_hw_obj(hw); - break; - default: - err = -ENODEV; - break; - } - - return err; -} - -unsigned int get_field(unsigned int data, unsigned int field) -{ - int i; - - BUG_ON(!field); - /* @field should always be greater than 0 */ - for (i = 0; !(field & (1 << i)); ) - i++; - - return (data & field) >> i; -} - -void set_field(unsigned int *data, unsigned int field, unsigned int value) -{ - int i; - - BUG_ON(!field); - /* @field should always be greater than 0 */ - for (i = 0; !(field & (1 << i)); ) - i++; - - *data = (*data & (~field)) | ((value << i) & field); -} - diff --git a/trunk/sound/pci/ctxfi/cthardware.h b/trunk/sound/pci/ctxfi/cthardware.h deleted file mode 100644 index af55405f5dec..000000000000 --- a/trunk/sound/pci/ctxfi/cthardware.h +++ /dev/null @@ -1,203 +0,0 @@ -/** - * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. - * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - * - * @File cthardware.h - * - * @Brief - * This file contains the definition of hardware access methord. - * - * @Author Liu Chun - * @Date May 13 2008 - * - */ - -#ifndef CTHARDWARE_H -#define CTHARDWARE_H - -#include -#include - -enum CHIPTYP { - ATC20K1, - ATC20K2, - ATCNONE -}; - -enum CTCARDS { - /* 20k1 models */ - CTSB055X, - CT20K1_MODEL_FIRST = CTSB055X, - CTSB073X, - CTUAA, - CT20K1_UNKNOWN, - /* 20k2 models */ - CTSB0760, - CT20K2_MODEL_FIRST = CTSB0760, - CTHENDRIX, - CTSB0880, - CT20K2_UNKNOWN, - NUM_CTCARDS /* This should always be the last */ -}; - -/* Type of input source for ADC */ -enum ADCSRC{ - ADC_MICIN, - ADC_LINEIN, - ADC_VIDEO, - ADC_AUX, - ADC_NONE /* Switch to digital input */ -}; - -struct card_conf { - /* device virtual mem page table page physical addr - * (supporting one page table page now) */ - unsigned long vm_pgt_phys; - unsigned int rsr; /* reference sample rate in Hzs*/ - unsigned int msr; /* master sample rate in rsrs */ -}; - -struct hw { - int (*card_init)(struct hw *hw, struct card_conf *info); - int (*card_stop)(struct hw *hw); - int (*pll_init)(struct hw *hw, unsigned int rsr); -#ifdef CONFIG_PM - int (*suspend)(struct hw *hw, pm_message_t state); - int (*resume)(struct hw *hw, struct card_conf *info); -#endif - int (*is_adc_source_selected)(struct hw *hw, enum ADCSRC source); - int (*select_adc_source)(struct hw *hw, enum ADCSRC source); - int (*have_digit_io_switch)(struct hw *hw); - - /* SRC operations */ - int (*src_rsc_get_ctrl_blk)(void **rblk); - int (*src_rsc_put_ctrl_blk)(void *blk); - int (*src_set_state)(void *blk, unsigned int state); - int (*src_set_bm)(void *blk, unsigned int bm); - int (*src_set_rsr)(void *blk, unsigned int rsr); - int (*src_set_sf)(void *blk, unsigned int sf); - int (*src_set_wr)(void *blk, unsigned int wr); - int (*src_set_pm)(void *blk, unsigned int pm); - int (*src_set_rom)(void *blk, unsigned int rom); - int (*src_set_vo)(void *blk, unsigned int vo); - int (*src_set_st)(void *blk, unsigned int st); - int (*src_set_ie)(void *blk, unsigned int ie); - int (*src_set_ilsz)(void *blk, unsigned int ilsz); - int (*src_set_bp)(void *blk, unsigned int bp); - int (*src_set_cisz)(void *blk, unsigned int cisz); - int (*src_set_ca)(void *blk, unsigned int ca); - int (*src_set_sa)(void *blk, unsigned int sa); - int (*src_set_la)(void *blk, unsigned int la); - int (*src_set_pitch)(void *blk, unsigned int pitch); - int (*src_set_clear_zbufs)(void *blk, unsigned int clear); - int (*src_set_dirty)(void *blk, unsigned int flags); - int (*src_set_dirty_all)(void *blk); - int (*src_commit_write)(struct hw *hw, unsigned int idx, void *blk); - int (*src_get_ca)(struct hw *hw, unsigned int idx, void *blk); - unsigned int (*src_get_dirty)(void *blk); - unsigned int (*src_dirty_conj_mask)(void); - int (*src_mgr_get_ctrl_blk)(void **rblk); - int (*src_mgr_put_ctrl_blk)(void *blk); - /* syncly enable src @idx */ - int (*src_mgr_enbs_src)(void *blk, unsigned int idx); - /* enable src @idx */ - int (*src_mgr_enb_src)(void *blk, unsigned int idx); - /* disable src @idx */ - int (*src_mgr_dsb_src)(void *blk, unsigned int idx); - int (*src_mgr_commit_write)(struct hw *hw, void *blk); - - /* SRC Input Mapper operations */ - int (*srcimp_mgr_get_ctrl_blk)(void **rblk); - int (*srcimp_mgr_put_ctrl_blk)(void *blk); - int (*srcimp_mgr_set_imaparc)(void *blk, unsigned int slot); - int (*srcimp_mgr_set_imapuser)(void *blk, unsigned int user); - int (*srcimp_mgr_set_imapnxt)(void *blk, unsigned int next); - int (*srcimp_mgr_set_imapaddr)(void *blk, unsigned int addr); - int (*srcimp_mgr_commit_write)(struct hw *hw, void *blk); - - /* AMIXER operations */ - int (*amixer_rsc_get_ctrl_blk)(void **rblk); - int (*amixer_rsc_put_ctrl_blk)(void *blk); - int (*amixer_mgr_get_ctrl_blk)(void **rblk); - int (*amixer_mgr_put_ctrl_blk)(void *blk); - int (*amixer_set_mode)(void *blk, unsigned int mode); - int (*amixer_set_iv)(void *blk, unsigned int iv); - int (*amixer_set_x)(void *blk, unsigned int x); - int (*amixer_set_y)(void *blk, unsigned int y); - int (*amixer_set_sadr)(void *blk, unsigned int sadr); - int (*amixer_set_se)(void *blk, unsigned int se); - int (*amixer_set_dirty)(void *blk, unsigned int flags); - int (*amixer_set_dirty_all)(void *blk); - int (*amixer_commit_write)(struct hw *hw, unsigned int idx, void *blk); - int (*amixer_get_y)(void *blk); - unsigned int (*amixer_get_dirty)(void *blk); - - /* DAIO operations */ - int (*dai_get_ctrl_blk)(void **rblk); - int (*dai_put_ctrl_blk)(void *blk); - int (*dai_srt_set_srco)(void *blk, unsigned int src); - int (*dai_srt_set_srcm)(void *blk, unsigned int src); - int (*dai_srt_set_rsr)(void *blk, unsigned int rsr); - int (*dai_srt_set_drat)(void *blk, unsigned int drat); - int (*dai_srt_set_ec)(void *blk, unsigned int ec); - int (*dai_srt_set_et)(void *blk, unsigned int et); - int (*dai_commit_write)(struct hw *hw, unsigned int idx, void *blk); - int (*dao_get_ctrl_blk)(void **rblk); - int (*dao_put_ctrl_blk)(void *blk); - int (*dao_set_spos)(void *blk, unsigned int spos); - int (*dao_commit_write)(struct hw *hw, unsigned int idx, void *blk); - int (*dao_get_spos)(void *blk, unsigned int *spos); - - int (*daio_mgr_get_ctrl_blk)(struct hw *hw, void **rblk); - int (*daio_mgr_put_ctrl_blk)(void *blk); - int (*daio_mgr_enb_dai)(void *blk, unsigned int idx); - int (*daio_mgr_dsb_dai)(void *blk, unsigned int idx); - int (*daio_mgr_enb_dao)(void *blk, unsigned int idx); - int (*daio_mgr_dsb_dao)(void *blk, unsigned int idx); - int (*daio_mgr_dao_init)(void *blk, unsigned int idx, - unsigned int conf); - int (*daio_mgr_set_imaparc)(void *blk, unsigned int slot); - int (*daio_mgr_set_imapnxt)(void *blk, unsigned int next); - int (*daio_mgr_set_imapaddr)(void *blk, unsigned int addr); - int (*daio_mgr_commit_write)(struct hw *hw, void *blk); - - int (*set_timer_irq)(struct hw *hw, int enable); - int (*set_timer_tick)(struct hw *hw, unsigned int tick); - unsigned int (*get_wc)(struct hw *hw); - - void (*irq_callback)(void *data, unsigned int bit); - void *irq_callback_data; - - struct pci_dev *pci; /* the pci kernel structure of this card */ - int irq; - unsigned long io_base; - unsigned long mem_base; - - enum CHIPTYP chip_type; - enum CTCARDS model; -}; - -int create_hw_obj(struct pci_dev *pci, enum CHIPTYP chip_type, - enum CTCARDS model, struct hw **rhw); -int destroy_hw_obj(struct hw *hw); - -unsigned int get_field(unsigned int data, unsigned int field); -void set_field(unsigned int *data, unsigned int field, unsigned int value); - -/* IRQ bits */ -#define PLL_INT (1 << 10) /* PLL input-clock out-of-range */ -#define FI_INT (1 << 9) /* forced interrupt */ -#define IT_INT (1 << 8) /* timer interrupt */ -#define PCI_INT (1 << 7) /* PCI bus error pending */ -#define URT_INT (1 << 6) /* UART Tx/Rx */ -#define GPI_INT (1 << 5) /* GPI pin */ -#define MIX_INT (1 << 4) /* mixer parameter segment FIFO channels */ -#define DAI_INT (1 << 3) /* DAI (SR-tracker or SPDIF-receiver) */ -#define TP_INT (1 << 2) /* transport priority queue */ -#define DSP_INT (1 << 1) /* DSP */ -#define SRC_INT (1 << 0) /* SRC channels */ - -#endif /* CTHARDWARE_H */ diff --git a/trunk/sound/pci/ctxfi/cthw20k1.c b/trunk/sound/pci/ctxfi/cthw20k1.c deleted file mode 100644 index ad3e1d144464..000000000000 --- a/trunk/sound/pci/ctxfi/cthw20k1.c +++ /dev/null @@ -1,2297 +0,0 @@ -/** - * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. - * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - * - * @File cthw20k1.c - * - * @Brief - * This file contains the implementation of hardware access methord for 20k1. - * - * @Author Liu Chun - * @Date Jun 24 2008 - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "cthw20k1.h" -#include "ct20k1reg.h" - -#if BITS_PER_LONG == 32 -#define CT_XFI_DMA_MASK DMA_BIT_MASK(32) /* 32 bit PTE */ -#else -#define CT_XFI_DMA_MASK DMA_BIT_MASK(64) /* 64 bit PTE */ -#endif - -struct hw20k1 { - struct hw hw; - spinlock_t reg_20k1_lock; - spinlock_t reg_pci_lock; -}; - -static u32 hw_read_20kx(struct hw *hw, u32 reg); -static void hw_write_20kx(struct hw *hw, u32 reg, u32 data); -static u32 hw_read_pci(struct hw *hw, u32 reg); -static void hw_write_pci(struct hw *hw, u32 reg, u32 data); - -/* - * Type definition block. - * The layout of control structures can be directly applied on 20k2 chip. - */ - -/* - * SRC control block definitions. - */ - -/* SRC resource control block */ -#define SRCCTL_STATE 0x00000007 -#define SRCCTL_BM 0x00000008 -#define SRCCTL_RSR 0x00000030 -#define SRCCTL_SF 0x000001C0 -#define SRCCTL_WR 0x00000200 -#define SRCCTL_PM 0x00000400 -#define SRCCTL_ROM 0x00001800 -#define SRCCTL_VO 0x00002000 -#define SRCCTL_ST 0x00004000 -#define SRCCTL_IE 0x00008000 -#define SRCCTL_ILSZ 0x000F0000 -#define SRCCTL_BP 0x00100000 - -#define SRCCCR_CISZ 0x000007FF -#define SRCCCR_CWA 0x001FF800 -#define SRCCCR_D 0x00200000 -#define SRCCCR_RS 0x01C00000 -#define SRCCCR_NAL 0x3E000000 -#define SRCCCR_RA 0xC0000000 - -#define SRCCA_CA 0x03FFFFFF -#define SRCCA_RS 0x1C000000 -#define SRCCA_NAL 0xE0000000 - -#define SRCSA_SA 0x03FFFFFF - -#define SRCLA_LA 0x03FFFFFF - -/* Mixer Parameter Ring ram Low and Hight register. - * Fixed-point value in 8.24 format for parameter channel */ -#define MPRLH_PITCH 0xFFFFFFFF - -/* SRC resource register dirty flags */ -union src_dirty { - struct { - u16 ctl:1; - u16 ccr:1; - u16 sa:1; - u16 la:1; - u16 ca:1; - u16 mpr:1; - u16 czbfs:1; /* Clear Z-Buffers */ - u16 rsv:9; - } bf; - u16 data; -}; - -struct src_rsc_ctrl_blk { - unsigned int ctl; - unsigned int ccr; - unsigned int ca; - unsigned int sa; - unsigned int la; - unsigned int mpr; - union src_dirty dirty; -}; - -/* SRC manager control block */ -union src_mgr_dirty { - struct { - u16 enb0:1; - u16 enb1:1; - u16 enb2:1; - u16 enb3:1; - u16 enb4:1; - u16 enb5:1; - u16 enb6:1; - u16 enb7:1; - u16 enbsa:1; - u16 rsv:7; - } bf; - u16 data; -}; - -struct src_mgr_ctrl_blk { - unsigned int enbsa; - unsigned int enb[8]; - union src_mgr_dirty dirty; -}; - -/* SRCIMP manager control block */ -#define SRCAIM_ARC 0x00000FFF -#define SRCAIM_NXT 0x00FF0000 -#define SRCAIM_SRC 0xFF000000 - -struct srcimap { - unsigned int srcaim; - unsigned int idx; -}; - -/* SRCIMP manager register dirty flags */ -union srcimp_mgr_dirty { - struct { - u16 srcimap:1; - u16 rsv:15; - } bf; - u16 data; -}; - -struct srcimp_mgr_ctrl_blk { - struct srcimap srcimap; - union srcimp_mgr_dirty dirty; -}; - -/* - * Function implementation block. - */ - -static int src_get_rsc_ctrl_blk(void **rblk) -{ - struct src_rsc_ctrl_blk *blk; - - *rblk = NULL; - blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) - return -ENOMEM; - - *rblk = blk; - - return 0; -} - -static int src_put_rsc_ctrl_blk(void *blk) -{ - kfree((struct src_rsc_ctrl_blk *)blk); - - return 0; -} - -static int src_set_state(void *blk, unsigned int state) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->ctl, SRCCTL_STATE, state); - ctl->dirty.bf.ctl = 1; - return 0; -} - -static int src_set_bm(void *blk, unsigned int bm) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->ctl, SRCCTL_BM, bm); - ctl->dirty.bf.ctl = 1; - return 0; -} - -static int src_set_rsr(void *blk, unsigned int rsr) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->ctl, SRCCTL_RSR, rsr); - ctl->dirty.bf.ctl = 1; - return 0; -} - -static int src_set_sf(void *blk, unsigned int sf) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->ctl, SRCCTL_SF, sf); - ctl->dirty.bf.ctl = 1; - return 0; -} - -static int src_set_wr(void *blk, unsigned int wr) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->ctl, SRCCTL_WR, wr); - ctl->dirty.bf.ctl = 1; - return 0; -} - -static int src_set_pm(void *blk, unsigned int pm) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->ctl, SRCCTL_PM, pm); - ctl->dirty.bf.ctl = 1; - return 0; -} - -static int src_set_rom(void *blk, unsigned int rom) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->ctl, SRCCTL_ROM, rom); - ctl->dirty.bf.ctl = 1; - return 0; -} - -static int src_set_vo(void *blk, unsigned int vo) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->ctl, SRCCTL_VO, vo); - ctl->dirty.bf.ctl = 1; - return 0; -} - -static int src_set_st(void *blk, unsigned int st) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->ctl, SRCCTL_ST, st); - ctl->dirty.bf.ctl = 1; - return 0; -} - -static int src_set_ie(void *blk, unsigned int ie) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->ctl, SRCCTL_IE, ie); - ctl->dirty.bf.ctl = 1; - return 0; -} - -static int src_set_ilsz(void *blk, unsigned int ilsz) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->ctl, SRCCTL_ILSZ, ilsz); - ctl->dirty.bf.ctl = 1; - return 0; -} - -static int src_set_bp(void *blk, unsigned int bp) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->ctl, SRCCTL_BP, bp); - ctl->dirty.bf.ctl = 1; - return 0; -} - -static int src_set_cisz(void *blk, unsigned int cisz) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->ccr, SRCCCR_CISZ, cisz); - ctl->dirty.bf.ccr = 1; - return 0; -} - -static int src_set_ca(void *blk, unsigned int ca) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->ca, SRCCA_CA, ca); - ctl->dirty.bf.ca = 1; - return 0; -} - -static int src_set_sa(void *blk, unsigned int sa) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->sa, SRCSA_SA, sa); - ctl->dirty.bf.sa = 1; - return 0; -} - -static int src_set_la(void *blk, unsigned int la) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->la, SRCLA_LA, la); - ctl->dirty.bf.la = 1; - return 0; -} - -static int src_set_pitch(void *blk, unsigned int pitch) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->mpr, MPRLH_PITCH, pitch); - ctl->dirty.bf.mpr = 1; - return 0; -} - -static int src_set_clear_zbufs(void *blk, unsigned int clear) -{ - ((struct src_rsc_ctrl_blk *)blk)->dirty.bf.czbfs = (clear ? 1 : 0); - return 0; -} - -static int src_set_dirty(void *blk, unsigned int flags) -{ - ((struct src_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff); - return 0; -} - -static int src_set_dirty_all(void *blk) -{ - ((struct src_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0); - return 0; -} - -#define AR_SLOT_SIZE 4096 -#define AR_SLOT_BLOCK_SIZE 16 -#define AR_PTS_PITCH 6 -#define AR_PARAM_SRC_OFFSET 0x60 - -static unsigned int src_param_pitch_mixer(unsigned int src_idx) -{ - return ((src_idx << 4) + AR_PTS_PITCH + AR_SLOT_SIZE - - AR_PARAM_SRC_OFFSET) % AR_SLOT_SIZE; - -} - -static int src_commit_write(struct hw *hw, unsigned int idx, void *blk) -{ - struct src_rsc_ctrl_blk *ctl = blk; - int i; - - if (ctl->dirty.bf.czbfs) { - /* Clear Z-Buffer registers */ - for (i = 0; i < 8; i++) - hw_write_20kx(hw, SRCUPZ+idx*0x100+i*0x4, 0); - - for (i = 0; i < 4; i++) - hw_write_20kx(hw, SRCDN0Z+idx*0x100+i*0x4, 0); - - for (i = 0; i < 8; i++) - hw_write_20kx(hw, SRCDN1Z+idx*0x100+i*0x4, 0); - - ctl->dirty.bf.czbfs = 0; - } - if (ctl->dirty.bf.mpr) { - /* Take the parameter mixer resource in the same group as that - * the idx src is in for simplicity. Unlike src, all conjugate - * parameter mixer resources must be programmed for - * corresponding conjugate src resources. */ - unsigned int pm_idx = src_param_pitch_mixer(idx); - hw_write_20kx(hw, PRING_LO_HI+4*pm_idx, ctl->mpr); - hw_write_20kx(hw, PMOPLO+8*pm_idx, 0x3); - hw_write_20kx(hw, PMOPHI+8*pm_idx, 0x0); - ctl->dirty.bf.mpr = 0; - } - if (ctl->dirty.bf.sa) { - hw_write_20kx(hw, SRCSA+idx*0x100, ctl->sa); - ctl->dirty.bf.sa = 0; - } - if (ctl->dirty.bf.la) { - hw_write_20kx(hw, SRCLA+idx*0x100, ctl->la); - ctl->dirty.bf.la = 0; - } - if (ctl->dirty.bf.ca) { - hw_write_20kx(hw, SRCCA+idx*0x100, ctl->ca); - ctl->dirty.bf.ca = 0; - } - - /* Write srccf register */ - hw_write_20kx(hw, SRCCF+idx*0x100, 0x0); - - if (ctl->dirty.bf.ccr) { - hw_write_20kx(hw, SRCCCR+idx*0x100, ctl->ccr); - ctl->dirty.bf.ccr = 0; - } - if (ctl->dirty.bf.ctl) { - hw_write_20kx(hw, SRCCTL+idx*0x100, ctl->ctl); - ctl->dirty.bf.ctl = 0; - } - - return 0; -} - -static int src_get_ca(struct hw *hw, unsigned int idx, void *blk) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - ctl->ca = hw_read_20kx(hw, SRCCA+idx*0x100); - ctl->dirty.bf.ca = 0; - - return get_field(ctl->ca, SRCCA_CA); -} - -static unsigned int src_get_dirty(void *blk) -{ - return ((struct src_rsc_ctrl_blk *)blk)->dirty.data; -} - -static unsigned int src_dirty_conj_mask(void) -{ - return 0x20; -} - -static int src_mgr_enbs_src(void *blk, unsigned int idx) -{ - ((struct src_mgr_ctrl_blk *)blk)->enbsa = ~(0x0); - ((struct src_mgr_ctrl_blk *)blk)->dirty.bf.enbsa = 1; - ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32)); - return 0; -} - -static int src_mgr_enb_src(void *blk, unsigned int idx) -{ - ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32)); - ((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32)); - return 0; -} - -static int src_mgr_dsb_src(void *blk, unsigned int idx) -{ - ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] &= ~(0x1 << (idx%32)); - ((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32)); - return 0; -} - -static int src_mgr_commit_write(struct hw *hw, void *blk) -{ - struct src_mgr_ctrl_blk *ctl = blk; - int i; - unsigned int ret; - - if (ctl->dirty.bf.enbsa) { - do { - ret = hw_read_20kx(hw, SRCENBSTAT); - } while (ret & 0x1); - hw_write_20kx(hw, SRCENBS, ctl->enbsa); - ctl->dirty.bf.enbsa = 0; - } - for (i = 0; i < 8; i++) { - if ((ctl->dirty.data & (0x1 << i))) { - hw_write_20kx(hw, SRCENB+(i*0x100), ctl->enb[i]); - ctl->dirty.data &= ~(0x1 << i); - } - } - - return 0; -} - -static int src_mgr_get_ctrl_blk(void **rblk) -{ - struct src_mgr_ctrl_blk *blk; - - *rblk = NULL; - blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) - return -ENOMEM; - - *rblk = blk; - - return 0; -} - -static int src_mgr_put_ctrl_blk(void *blk) -{ - kfree((struct src_mgr_ctrl_blk *)blk); - - return 0; -} - -static int srcimp_mgr_get_ctrl_blk(void **rblk) -{ - struct srcimp_mgr_ctrl_blk *blk; - - *rblk = NULL; - blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) - return -ENOMEM; - - *rblk = blk; - - return 0; -} - -static int srcimp_mgr_put_ctrl_blk(void *blk) -{ - kfree((struct srcimp_mgr_ctrl_blk *)blk); - - return 0; -} - -static int srcimp_mgr_set_imaparc(void *blk, unsigned int slot) -{ - struct srcimp_mgr_ctrl_blk *ctl = blk; - - set_field(&ctl->srcimap.srcaim, SRCAIM_ARC, slot); - ctl->dirty.bf.srcimap = 1; - return 0; -} - -static int srcimp_mgr_set_imapuser(void *blk, unsigned int user) -{ - struct srcimp_mgr_ctrl_blk *ctl = blk; - - set_field(&ctl->srcimap.srcaim, SRCAIM_SRC, user); - ctl->dirty.bf.srcimap = 1; - return 0; -} - -static int srcimp_mgr_set_imapnxt(void *blk, unsigned int next) -{ - struct srcimp_mgr_ctrl_blk *ctl = blk; - - set_field(&ctl->srcimap.srcaim, SRCAIM_NXT, next); - ctl->dirty.bf.srcimap = 1; - return 0; -} - -static int srcimp_mgr_set_imapaddr(void *blk, unsigned int addr) -{ - struct srcimp_mgr_ctrl_blk *ctl = blk; - - ctl->srcimap.idx = addr; - ctl->dirty.bf.srcimap = 1; - return 0; -} - -static int srcimp_mgr_commit_write(struct hw *hw, void *blk) -{ - struct srcimp_mgr_ctrl_blk *ctl = blk; - - if (ctl->dirty.bf.srcimap) { - hw_write_20kx(hw, SRCIMAP+ctl->srcimap.idx*0x100, - ctl->srcimap.srcaim); - ctl->dirty.bf.srcimap = 0; - } - - return 0; -} - -/* - * AMIXER control block definitions. - */ - -#define AMOPLO_M 0x00000003 -#define AMOPLO_X 0x0003FFF0 -#define AMOPLO_Y 0xFFFC0000 - -#define AMOPHI_SADR 0x000000FF -#define AMOPHI_SE 0x80000000 - -/* AMIXER resource register dirty flags */ -union amixer_dirty { - struct { - u16 amoplo:1; - u16 amophi:1; - u16 rsv:14; - } bf; - u16 data; -}; - -/* AMIXER resource control block */ -struct amixer_rsc_ctrl_blk { - unsigned int amoplo; - unsigned int amophi; - union amixer_dirty dirty; -}; - -static int amixer_set_mode(void *blk, unsigned int mode) -{ - struct amixer_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->amoplo, AMOPLO_M, mode); - ctl->dirty.bf.amoplo = 1; - return 0; -} - -static int amixer_set_iv(void *blk, unsigned int iv) -{ - /* 20k1 amixer does not have this field */ - return 0; -} - -static int amixer_set_x(void *blk, unsigned int x) -{ - struct amixer_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->amoplo, AMOPLO_X, x); - ctl->dirty.bf.amoplo = 1; - return 0; -} - -static int amixer_set_y(void *blk, unsigned int y) -{ - struct amixer_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->amoplo, AMOPLO_Y, y); - ctl->dirty.bf.amoplo = 1; - return 0; -} - -static int amixer_set_sadr(void *blk, unsigned int sadr) -{ - struct amixer_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->amophi, AMOPHI_SADR, sadr); - ctl->dirty.bf.amophi = 1; - return 0; -} - -static int amixer_set_se(void *blk, unsigned int se) -{ - struct amixer_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->amophi, AMOPHI_SE, se); - ctl->dirty.bf.amophi = 1; - return 0; -} - -static int amixer_set_dirty(void *blk, unsigned int flags) -{ - ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff); - return 0; -} - -static int amixer_set_dirty_all(void *blk) -{ - ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0); - return 0; -} - -static int amixer_commit_write(struct hw *hw, unsigned int idx, void *blk) -{ - struct amixer_rsc_ctrl_blk *ctl = blk; - - if (ctl->dirty.bf.amoplo || ctl->dirty.bf.amophi) { - hw_write_20kx(hw, AMOPLO+idx*8, ctl->amoplo); - ctl->dirty.bf.amoplo = 0; - hw_write_20kx(hw, AMOPHI+idx*8, ctl->amophi); - ctl->dirty.bf.amophi = 0; - } - - return 0; -} - -static int amixer_get_y(void *blk) -{ - struct amixer_rsc_ctrl_blk *ctl = blk; - - return get_field(ctl->amoplo, AMOPLO_Y); -} - -static unsigned int amixer_get_dirty(void *blk) -{ - return ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data; -} - -static int amixer_rsc_get_ctrl_blk(void **rblk) -{ - struct amixer_rsc_ctrl_blk *blk; - - *rblk = NULL; - blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) - return -ENOMEM; - - *rblk = blk; - - return 0; -} - -static int amixer_rsc_put_ctrl_blk(void *blk) -{ - kfree((struct amixer_rsc_ctrl_blk *)blk); - - return 0; -} - -static int amixer_mgr_get_ctrl_blk(void **rblk) -{ - /*amixer_mgr_ctrl_blk_t *blk;*/ - - *rblk = NULL; - /*blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) - return -ENOMEM; - - *rblk = blk;*/ - - return 0; -} - -static int amixer_mgr_put_ctrl_blk(void *blk) -{ - /*kfree((amixer_mgr_ctrl_blk_t *)blk);*/ - - return 0; -} - -/* - * DAIO control block definitions. - */ - -/* Receiver Sample Rate Tracker Control register */ -#define SRTCTL_SRCR 0x000000FF -#define SRTCTL_SRCL 0x0000FF00 -#define SRTCTL_RSR 0x00030000 -#define SRTCTL_DRAT 0x000C0000 -#define SRTCTL_RLE 0x10000000 -#define SRTCTL_RLP 0x20000000 -#define SRTCTL_EC 0x40000000 -#define SRTCTL_ET 0x80000000 - -/* DAIO Receiver register dirty flags */ -union dai_dirty { - struct { - u16 srtctl:1; - u16 rsv:15; - } bf; - u16 data; -}; - -/* DAIO Receiver control block */ -struct dai_ctrl_blk { - unsigned int srtctl; - union dai_dirty dirty; -}; - -/* S/PDIF Transmitter register dirty flags */ -union dao_dirty { - struct { - u16 spos:1; - u16 rsv:15; - } bf; - u16 data; -}; - -/* S/PDIF Transmitter control block */ -struct dao_ctrl_blk { - unsigned int spos; /* S/PDIF Output Channel Status Register */ - union dao_dirty dirty; -}; - -/* Audio Input Mapper RAM */ -#define AIM_ARC 0x00000FFF -#define AIM_NXT 0x007F0000 - -struct daoimap { - unsigned int aim; - unsigned int idx; -}; - -/* I2S Transmitter/Receiver Control register */ -#define I2SCTL_EA 0x00000004 -#define I2SCTL_EI 0x00000010 - -/* S/PDIF Transmitter Control register */ -#define SPOCTL_OE 0x00000001 -#define SPOCTL_OS 0x0000000E -#define SPOCTL_RIV 0x00000010 -#define SPOCTL_LIV 0x00000020 -#define SPOCTL_SR 0x000000C0 - -/* S/PDIF Receiver Control register */ -#define SPICTL_EN 0x00000001 -#define SPICTL_I24 0x00000002 -#define SPICTL_IB 0x00000004 -#define SPICTL_SM 0x00000008 -#define SPICTL_VM 0x00000010 - -/* DAIO manager register dirty flags */ -union daio_mgr_dirty { - struct { - u32 i2soctl:4; - u32 i2sictl:4; - u32 spoctl:4; - u32 spictl:4; - u32 daoimap:1; - u32 rsv:15; - } bf; - u32 data; -}; - -/* DAIO manager control block */ -struct daio_mgr_ctrl_blk { - unsigned int i2sctl; - unsigned int spoctl; - unsigned int spictl; - struct daoimap daoimap; - union daio_mgr_dirty dirty; -}; - -static int dai_srt_set_srcr(void *blk, unsigned int src) -{ - struct dai_ctrl_blk *ctl = blk; - - set_field(&ctl->srtctl, SRTCTL_SRCR, src); - ctl->dirty.bf.srtctl = 1; - return 0; -} - -static int dai_srt_set_srcl(void *blk, unsigned int src) -{ - struct dai_ctrl_blk *ctl = blk; - - set_field(&ctl->srtctl, SRTCTL_SRCL, src); - ctl->dirty.bf.srtctl = 1; - return 0; -} - -static int dai_srt_set_rsr(void *blk, unsigned int rsr) -{ - struct dai_ctrl_blk *ctl = blk; - - set_field(&ctl->srtctl, SRTCTL_RSR, rsr); - ctl->dirty.bf.srtctl = 1; - return 0; -} - -static int dai_srt_set_drat(void *blk, unsigned int drat) -{ - struct dai_ctrl_blk *ctl = blk; - - set_field(&ctl->srtctl, SRTCTL_DRAT, drat); - ctl->dirty.bf.srtctl = 1; - return 0; -} - -static int dai_srt_set_ec(void *blk, unsigned int ec) -{ - struct dai_ctrl_blk *ctl = blk; - - set_field(&ctl->srtctl, SRTCTL_EC, ec ? 1 : 0); - ctl->dirty.bf.srtctl = 1; - return 0; -} - -static int dai_srt_set_et(void *blk, unsigned int et) -{ - struct dai_ctrl_blk *ctl = blk; - - set_field(&ctl->srtctl, SRTCTL_ET, et ? 1 : 0); - ctl->dirty.bf.srtctl = 1; - return 0; -} - -static int dai_commit_write(struct hw *hw, unsigned int idx, void *blk) -{ - struct dai_ctrl_blk *ctl = blk; - - if (ctl->dirty.bf.srtctl) { - if (idx < 4) { - /* S/PDIF SRTs */ - hw_write_20kx(hw, SRTSCTL+0x4*idx, ctl->srtctl); - } else { - /* I2S SRT */ - hw_write_20kx(hw, SRTICTL, ctl->srtctl); - } - ctl->dirty.bf.srtctl = 0; - } - - return 0; -} - -static int dai_get_ctrl_blk(void **rblk) -{ - struct dai_ctrl_blk *blk; - - *rblk = NULL; - blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) - return -ENOMEM; - - *rblk = blk; - - return 0; -} - -static int dai_put_ctrl_blk(void *blk) -{ - kfree((struct dai_ctrl_blk *)blk); - - return 0; -} - -static int dao_set_spos(void *blk, unsigned int spos) -{ - ((struct dao_ctrl_blk *)blk)->spos = spos; - ((struct dao_ctrl_blk *)blk)->dirty.bf.spos = 1; - return 0; -} - -static int dao_commit_write(struct hw *hw, unsigned int idx, void *blk) -{ - struct dao_ctrl_blk *ctl = blk; - - if (ctl->dirty.bf.spos) { - if (idx < 4) { - /* S/PDIF SPOSx */ - hw_write_20kx(hw, SPOS+0x4*idx, ctl->spos); - } - ctl->dirty.bf.spos = 0; - } - - return 0; -} - -static int dao_get_spos(void *blk, unsigned int *spos) -{ - *spos = ((struct dao_ctrl_blk *)blk)->spos; - return 0; -} - -static int dao_get_ctrl_blk(void **rblk) -{ - struct dao_ctrl_blk *blk; - - *rblk = NULL; - blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) - return -ENOMEM; - - *rblk = blk; - - return 0; -} - -static int dao_put_ctrl_blk(void *blk) -{ - kfree((struct dao_ctrl_blk *)blk); - - return 0; -} - -static int daio_mgr_enb_dai(void *blk, unsigned int idx) -{ - struct daio_mgr_ctrl_blk *ctl = blk; - - if (idx < 4) { - /* S/PDIF input */ - set_field(&ctl->spictl, SPICTL_EN << (idx*8), 1); - ctl->dirty.bf.spictl |= (0x1 << idx); - } else { - /* I2S input */ - idx %= 4; - set_field(&ctl->i2sctl, I2SCTL_EI << (idx*8), 1); - ctl->dirty.bf.i2sictl |= (0x1 << idx); - } - return 0; -} - -static int daio_mgr_dsb_dai(void *blk, unsigned int idx) -{ - struct daio_mgr_ctrl_blk *ctl = blk; - - if (idx < 4) { - /* S/PDIF input */ - set_field(&ctl->spictl, SPICTL_EN << (idx*8), 0); - ctl->dirty.bf.spictl |= (0x1 << idx); - } else { - /* I2S input */ - idx %= 4; - set_field(&ctl->i2sctl, I2SCTL_EI << (idx*8), 0); - ctl->dirty.bf.i2sictl |= (0x1 << idx); - } - return 0; -} - -static int daio_mgr_enb_dao(void *blk, unsigned int idx) -{ - struct daio_mgr_ctrl_blk *ctl = blk; - - if (idx < 4) { - /* S/PDIF output */ - set_field(&ctl->spoctl, SPOCTL_OE << (idx*8), 1); - ctl->dirty.bf.spoctl |= (0x1 << idx); - } else { - /* I2S output */ - idx %= 4; - set_field(&ctl->i2sctl, I2SCTL_EA << (idx*8), 1); - ctl->dirty.bf.i2soctl |= (0x1 << idx); - } - return 0; -} - -static int daio_mgr_dsb_dao(void *blk, unsigned int idx) -{ - struct daio_mgr_ctrl_blk *ctl = blk; - - if (idx < 4) { - /* S/PDIF output */ - set_field(&ctl->spoctl, SPOCTL_OE << (idx*8), 0); - ctl->dirty.bf.spoctl |= (0x1 << idx); - } else { - /* I2S output */ - idx %= 4; - set_field(&ctl->i2sctl, I2SCTL_EA << (idx*8), 0); - ctl->dirty.bf.i2soctl |= (0x1 << idx); - } - return 0; -} - -static int daio_mgr_dao_init(void *blk, unsigned int idx, unsigned int conf) -{ - struct daio_mgr_ctrl_blk *ctl = blk; - - if (idx < 4) { - /* S/PDIF output */ - switch ((conf & 0x7)) { - case 0: - set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 3); - break; /* CDIF */ - case 1: - set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 0); - break; - case 2: - set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 1); - break; - case 4: - set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 2); - break; - default: - break; - } - set_field(&ctl->spoctl, SPOCTL_LIV << (idx*8), - (conf >> 4) & 0x1); /* Non-audio */ - set_field(&ctl->spoctl, SPOCTL_RIV << (idx*8), - (conf >> 4) & 0x1); /* Non-audio */ - set_field(&ctl->spoctl, SPOCTL_OS << (idx*8), - ((conf >> 3) & 0x1) ? 2 : 2); /* Raw */ - - ctl->dirty.bf.spoctl |= (0x1 << idx); - } else { - /* I2S output */ - /*idx %= 4; */ - } - return 0; -} - -static int daio_mgr_set_imaparc(void *blk, unsigned int slot) -{ - struct daio_mgr_ctrl_blk *ctl = blk; - - set_field(&ctl->daoimap.aim, AIM_ARC, slot); - ctl->dirty.bf.daoimap = 1; - return 0; -} - -static int daio_mgr_set_imapnxt(void *blk, unsigned int next) -{ - struct daio_mgr_ctrl_blk *ctl = blk; - - set_field(&ctl->daoimap.aim, AIM_NXT, next); - ctl->dirty.bf.daoimap = 1; - return 0; -} - -static int daio_mgr_set_imapaddr(void *blk, unsigned int addr) -{ - struct daio_mgr_ctrl_blk *ctl = blk; - - ctl->daoimap.idx = addr; - ctl->dirty.bf.daoimap = 1; - return 0; -} - -static int daio_mgr_commit_write(struct hw *hw, void *blk) -{ - struct daio_mgr_ctrl_blk *ctl = blk; - int i; - - if (ctl->dirty.bf.i2sictl || ctl->dirty.bf.i2soctl) { - for (i = 0; i < 4; i++) { - if ((ctl->dirty.bf.i2sictl & (0x1 << i))) - ctl->dirty.bf.i2sictl &= ~(0x1 << i); - - if ((ctl->dirty.bf.i2soctl & (0x1 << i))) - ctl->dirty.bf.i2soctl &= ~(0x1 << i); - } - hw_write_20kx(hw, I2SCTL, ctl->i2sctl); - mdelay(1); - } - if (ctl->dirty.bf.spoctl) { - for (i = 0; i < 4; i++) { - if ((ctl->dirty.bf.spoctl & (0x1 << i))) - ctl->dirty.bf.spoctl &= ~(0x1 << i); - } - hw_write_20kx(hw, SPOCTL, ctl->spoctl); - mdelay(1); - } - if (ctl->dirty.bf.spictl) { - for (i = 0; i < 4; i++) { - if ((ctl->dirty.bf.spictl & (0x1 << i))) - ctl->dirty.bf.spictl &= ~(0x1 << i); - } - hw_write_20kx(hw, SPICTL, ctl->spictl); - mdelay(1); - } - if (ctl->dirty.bf.daoimap) { - hw_write_20kx(hw, DAOIMAP+ctl->daoimap.idx*4, - ctl->daoimap.aim); - ctl->dirty.bf.daoimap = 0; - } - - return 0; -} - -static int daio_mgr_get_ctrl_blk(struct hw *hw, void **rblk) -{ - struct daio_mgr_ctrl_blk *blk; - - *rblk = NULL; - blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) - return -ENOMEM; - - blk->i2sctl = hw_read_20kx(hw, I2SCTL); - blk->spoctl = hw_read_20kx(hw, SPOCTL); - blk->spictl = hw_read_20kx(hw, SPICTL); - - *rblk = blk; - - return 0; -} - -static int daio_mgr_put_ctrl_blk(void *blk) -{ - kfree((struct daio_mgr_ctrl_blk *)blk); - - return 0; -} - -/* Timer interrupt */ -static int set_timer_irq(struct hw *hw, int enable) -{ - hw_write_20kx(hw, GIE, enable ? IT_INT : 0); - return 0; -} - -static int set_timer_tick(struct hw *hw, unsigned int ticks) -{ - if (ticks) - ticks |= TIMR_IE | TIMR_IP; - hw_write_20kx(hw, TIMR, ticks); - return 0; -} - -static unsigned int get_wc(struct hw *hw) -{ - return hw_read_20kx(hw, WC); -} - -/* Card hardware initialization block */ -struct dac_conf { - unsigned int msr; /* master sample rate in rsrs */ -}; - -struct adc_conf { - unsigned int msr; /* master sample rate in rsrs */ - unsigned char input; /* the input source of ADC */ - unsigned char mic20db; /* boost mic by 20db if input is microphone */ -}; - -struct daio_conf { - unsigned int msr; /* master sample rate in rsrs */ -}; - -struct trn_conf { - unsigned long vm_pgt_phys; -}; - -static int hw_daio_init(struct hw *hw, const struct daio_conf *info) -{ - u32 i2sorg; - u32 spdorg; - - /* Read I2S CTL. Keep original value. */ - /*i2sorg = hw_read_20kx(hw, I2SCTL);*/ - i2sorg = 0x94040404; /* enable all audio out and I2S-D input */ - /* Program I2S with proper master sample rate and enable - * the correct I2S channel. */ - i2sorg &= 0xfffffffc; - - /* Enable S/PDIF-out-A in fixed 24-bit data - * format and default to 48kHz. */ - /* Disable all before doing any changes. */ - hw_write_20kx(hw, SPOCTL, 0x0); - spdorg = 0x05; - - switch (info->msr) { - case 1: - i2sorg |= 1; - spdorg |= (0x0 << 6); - break; - case 2: - i2sorg |= 2; - spdorg |= (0x1 << 6); - break; - case 4: - i2sorg |= 3; - spdorg |= (0x2 << 6); - break; - default: - i2sorg |= 1; - break; - } - - hw_write_20kx(hw, I2SCTL, i2sorg); - hw_write_20kx(hw, SPOCTL, spdorg); - - /* Enable S/PDIF-in-A in fixed 24-bit data format. */ - /* Disable all before doing any changes. */ - hw_write_20kx(hw, SPICTL, 0x0); - mdelay(1); - spdorg = 0x0a0a0a0a; - hw_write_20kx(hw, SPICTL, spdorg); - mdelay(1); - - return 0; -} - -/* TRANSPORT operations */ -static int hw_trn_init(struct hw *hw, const struct trn_conf *info) -{ - u32 trnctl; - u32 ptp_phys_low, ptp_phys_high; - - /* Set up device page table */ - if ((~0UL) == info->vm_pgt_phys) { - printk(KERN_ERR "Wrong device page table page address!\n"); - return -1; - } - - trnctl = 0x13; /* 32-bit, 4k-size page */ - ptp_phys_low = (u32)info->vm_pgt_phys; - ptp_phys_high = upper_32_bits(info->vm_pgt_phys); - if (sizeof(void *) == 8) /* 64bit address */ - trnctl |= (1 << 2); -#if 0 /* Only 4k h/w pages for simplicitiy */ -#if PAGE_SIZE == 8192 - trnctl |= (1<<5); -#endif -#endif - hw_write_20kx(hw, PTPALX, ptp_phys_low); - hw_write_20kx(hw, PTPAHX, ptp_phys_high); - hw_write_20kx(hw, TRNCTL, trnctl); - hw_write_20kx(hw, TRNIS, 0x200c01); /* realy needed? */ - - return 0; -} - -/* Card initialization */ -#define GCTL_EAC 0x00000001 -#define GCTL_EAI 0x00000002 -#define GCTL_BEP 0x00000004 -#define GCTL_BES 0x00000008 -#define GCTL_DSP 0x00000010 -#define GCTL_DBP 0x00000020 -#define GCTL_ABP 0x00000040 -#define GCTL_TBP 0x00000080 -#define GCTL_SBP 0x00000100 -#define GCTL_FBP 0x00000200 -#define GCTL_XA 0x00000400 -#define GCTL_ET 0x00000800 -#define GCTL_PR 0x00001000 -#define GCTL_MRL 0x00002000 -#define GCTL_SDE 0x00004000 -#define GCTL_SDI 0x00008000 -#define GCTL_SM 0x00010000 -#define GCTL_SR 0x00020000 -#define GCTL_SD 0x00040000 -#define GCTL_SE 0x00080000 -#define GCTL_AID 0x00100000 - -static int hw_pll_init(struct hw *hw, unsigned int rsr) -{ - unsigned int pllctl; - int i; - - pllctl = (48000 == rsr) ? 0x1480a001 : 0x1480a731; - for (i = 0; i < 3; i++) { - if (hw_read_20kx(hw, PLLCTL) == pllctl) - break; - - hw_write_20kx(hw, PLLCTL, pllctl); - mdelay(40); - } - if (i >= 3) { - printk(KERN_ALERT "PLL initialization failed!!!\n"); - return -EBUSY; - } - - return 0; -} - -static int hw_auto_init(struct hw *hw) -{ - unsigned int gctl; - int i; - - gctl = hw_read_20kx(hw, GCTL); - set_field(&gctl, GCTL_EAI, 0); - hw_write_20kx(hw, GCTL, gctl); - set_field(&gctl, GCTL_EAI, 1); - hw_write_20kx(hw, GCTL, gctl); - mdelay(10); - for (i = 0; i < 400000; i++) { - gctl = hw_read_20kx(hw, GCTL); - if (get_field(gctl, GCTL_AID)) - break; - } - if (!get_field(gctl, GCTL_AID)) { - printk(KERN_ALERT "Card Auto-init failed!!!\n"); - return -EBUSY; - } - - return 0; -} - -static int i2c_unlock(struct hw *hw) -{ - if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa) - return 0; - - hw_write_pci(hw, 0xcc, 0x8c); - hw_write_pci(hw, 0xcc, 0x0e); - if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa) - return 0; - - hw_write_pci(hw, 0xcc, 0xee); - hw_write_pci(hw, 0xcc, 0xaa); - if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa) - return 0; - - return -1; -} - -static void i2c_lock(struct hw *hw) -{ - if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa) - hw_write_pci(hw, 0xcc, 0x00); -} - -static void i2c_write(struct hw *hw, u32 device, u32 addr, u32 data) -{ - unsigned int ret; - - do { - ret = hw_read_pci(hw, 0xEC); - } while (!(ret & 0x800000)); - hw_write_pci(hw, 0xE0, device); - hw_write_pci(hw, 0xE4, (data << 8) | (addr & 0xff)); -} - -/* DAC operations */ - -static int hw_reset_dac(struct hw *hw) -{ - u32 i; - u16 gpioorg; - unsigned int ret; - - if (i2c_unlock(hw)) - return -1; - - do { - ret = hw_read_pci(hw, 0xEC); - } while (!(ret & 0x800000)); - hw_write_pci(hw, 0xEC, 0x05); /* write to i2c status control */ - - /* To be effective, need to reset the DAC twice. */ - for (i = 0; i < 2; i++) { - /* set gpio */ - mdelay(100); - gpioorg = (u16)hw_read_20kx(hw, GPIO); - gpioorg &= 0xfffd; - hw_write_20kx(hw, GPIO, gpioorg); - mdelay(1); - hw_write_20kx(hw, GPIO, gpioorg | 0x2); - } - - i2c_write(hw, 0x00180080, 0x01, 0x80); - i2c_write(hw, 0x00180080, 0x02, 0x10); - - i2c_lock(hw); - - return 0; -} - -static int hw_dac_init(struct hw *hw, const struct dac_conf *info) -{ - u32 data; - u16 gpioorg; - unsigned int ret; - - if (hw->model == CTSB055X) { - /* SB055x, unmute outputs */ - gpioorg = (u16)hw_read_20kx(hw, GPIO); - gpioorg &= 0xffbf; /* set GPIO6 to low */ - gpioorg |= 2; /* set GPIO1 to high */ - hw_write_20kx(hw, GPIO, gpioorg); - return 0; - } - - /* mute outputs */ - gpioorg = (u16)hw_read_20kx(hw, GPIO); - gpioorg &= 0xffbf; - hw_write_20kx(hw, GPIO, gpioorg); - - hw_reset_dac(hw); - - if (i2c_unlock(hw)) - return -1; - - hw_write_pci(hw, 0xEC, 0x05); /* write to i2c status control */ - do { - ret = hw_read_pci(hw, 0xEC); - } while (!(ret & 0x800000)); - - switch (info->msr) { - case 1: - data = 0x24; - break; - case 2: - data = 0x25; - break; - case 4: - data = 0x26; - break; - default: - data = 0x24; - break; - } - - i2c_write(hw, 0x00180080, 0x06, data); - i2c_write(hw, 0x00180080, 0x09, data); - i2c_write(hw, 0x00180080, 0x0c, data); - i2c_write(hw, 0x00180080, 0x0f, data); - - i2c_lock(hw); - - /* unmute outputs */ - gpioorg = (u16)hw_read_20kx(hw, GPIO); - gpioorg = gpioorg | 0x40; - hw_write_20kx(hw, GPIO, gpioorg); - - return 0; -} - -/* ADC operations */ - -static int is_adc_input_selected_SB055x(struct hw *hw, enum ADCSRC type) -{ - return 0; -} - -static int is_adc_input_selected_SBx(struct hw *hw, enum ADCSRC type) -{ - u32 data; - - data = hw_read_20kx(hw, GPIO); - switch (type) { - case ADC_MICIN: - data = ((data & (0x1<<7)) && (data & (0x1<<8))); - break; - case ADC_LINEIN: - data = (!(data & (0x1<<7)) && (data & (0x1<<8))); - break; - case ADC_NONE: /* Digital I/O */ - data = (!(data & (0x1<<8))); - break; - default: - data = 0; - } - return data; -} - -static int is_adc_input_selected_hendrix(struct hw *hw, enum ADCSRC type) -{ - u32 data; - - data = hw_read_20kx(hw, GPIO); - switch (type) { - case ADC_MICIN: - data = (data & (0x1 << 7)) ? 1 : 0; - break; - case ADC_LINEIN: - data = (data & (0x1 << 7)) ? 0 : 1; - break; - default: - data = 0; - } - return data; -} - -static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type) -{ - switch (hw->model) { - case CTSB055X: - return is_adc_input_selected_SB055x(hw, type); - case CTSB073X: - return is_adc_input_selected_hendrix(hw, type); - case CTUAA: - return is_adc_input_selected_hendrix(hw, type); - default: - return is_adc_input_selected_SBx(hw, type); - } -} - -static int -adc_input_select_SB055x(struct hw *hw, enum ADCSRC type, unsigned char boost) -{ - u32 data; - - /* - * check and set the following GPIO bits accordingly - * ADC_Gain = GPIO2 - * DRM_off = GPIO3 - * Mic_Pwr_on = GPIO7 - * Digital_IO_Sel = GPIO8 - * Mic_Sw = GPIO9 - * Aux/MicLine_Sw = GPIO12 - */ - data = hw_read_20kx(hw, GPIO); - data &= 0xec73; - switch (type) { - case ADC_MICIN: - data |= (0x1<<7) | (0x1<<8) | (0x1<<9) ; - data |= boost ? (0x1<<2) : 0; - break; - case ADC_LINEIN: - data |= (0x1<<8); - break; - case ADC_AUX: - data |= (0x1<<8) | (0x1<<12); - break; - case ADC_NONE: - data |= (0x1<<12); /* set to digital */ - break; - default: - return -1; - } - - hw_write_20kx(hw, GPIO, data); - - return 0; -} - - -static int -adc_input_select_SBx(struct hw *hw, enum ADCSRC type, unsigned char boost) -{ - u32 data; - u32 i2c_data; - unsigned int ret; - - if (i2c_unlock(hw)) - return -1; - - do { - ret = hw_read_pci(hw, 0xEC); - } while (!(ret & 0x800000)); /* i2c ready poll */ - /* set i2c access mode as Direct Control */ - hw_write_pci(hw, 0xEC, 0x05); - - data = hw_read_20kx(hw, GPIO); - switch (type) { - case ADC_MICIN: - data |= ((0x1 << 7) | (0x1 << 8)); - i2c_data = 0x1; /* Mic-in */ - break; - case ADC_LINEIN: - data &= ~(0x1 << 7); - data |= (0x1 << 8); - i2c_data = 0x2; /* Line-in */ - break; - case ADC_NONE: - data &= ~(0x1 << 8); - i2c_data = 0x0; /* set to Digital */ - break; - default: - i2c_lock(hw); - return -1; - } - hw_write_20kx(hw, GPIO, data); - i2c_write(hw, 0x001a0080, 0x2a, i2c_data); - if (boost) { - i2c_write(hw, 0x001a0080, 0x1c, 0xe7); /* +12dB boost */ - i2c_write(hw, 0x001a0080, 0x1e, 0xe7); /* +12dB boost */ - } else { - i2c_write(hw, 0x001a0080, 0x1c, 0xcf); /* No boost */ - i2c_write(hw, 0x001a0080, 0x1e, 0xcf); /* No boost */ - } - - i2c_lock(hw); - - return 0; -} - -static int -adc_input_select_hendrix(struct hw *hw, enum ADCSRC type, unsigned char boost) -{ - u32 data; - u32 i2c_data; - unsigned int ret; - - if (i2c_unlock(hw)) - return -1; - - do { - ret = hw_read_pci(hw, 0xEC); - } while (!(ret & 0x800000)); /* i2c ready poll */ - /* set i2c access mode as Direct Control */ - hw_write_pci(hw, 0xEC, 0x05); - - data = hw_read_20kx(hw, GPIO); - switch (type) { - case ADC_MICIN: - data |= (0x1 << 7); - i2c_data = 0x1; /* Mic-in */ - break; - case ADC_LINEIN: - data &= ~(0x1 << 7); - i2c_data = 0x2; /* Line-in */ - break; - default: - i2c_lock(hw); - return -1; - } - hw_write_20kx(hw, GPIO, data); - i2c_write(hw, 0x001a0080, 0x2a, i2c_data); - if (boost) { - i2c_write(hw, 0x001a0080, 0x1c, 0xe7); /* +12dB boost */ - i2c_write(hw, 0x001a0080, 0x1e, 0xe7); /* +12dB boost */ - } else { - i2c_write(hw, 0x001a0080, 0x1c, 0xcf); /* No boost */ - i2c_write(hw, 0x001a0080, 0x1e, 0xcf); /* No boost */ - } - - i2c_lock(hw); - - return 0; -} - -static int hw_adc_input_select(struct hw *hw, enum ADCSRC type) -{ - int state = type == ADC_MICIN; - - switch (hw->model) { - case CTSB055X: - return adc_input_select_SB055x(hw, type, state); - case CTSB073X: - return adc_input_select_hendrix(hw, type, state); - case CTUAA: - return adc_input_select_hendrix(hw, type, state); - default: - return adc_input_select_SBx(hw, type, state); - } -} - -static int adc_init_SB055x(struct hw *hw, int input, int mic20db) -{ - return adc_input_select_SB055x(hw, input, mic20db); -} - -static int adc_init_SBx(struct hw *hw, int input, int mic20db) -{ - u16 gpioorg; - u16 input_source; - u32 adcdata; - unsigned int ret; - - input_source = 0x100; /* default to analog */ - switch (input) { - case ADC_MICIN: - adcdata = 0x1; - input_source = 0x180; /* set GPIO7 to select Mic */ - break; - case ADC_LINEIN: - adcdata = 0x2; - break; - case ADC_VIDEO: - adcdata = 0x4; - break; - case ADC_AUX: - adcdata = 0x8; - break; - case ADC_NONE: - adcdata = 0x0; - input_source = 0x0; /* set to Digital */ - break; - default: - adcdata = 0x0; - break; - } - - if (i2c_unlock(hw)) - return -1; - - do { - ret = hw_read_pci(hw, 0xEC); - } while (!(ret & 0x800000)); /* i2c ready poll */ - hw_write_pci(hw, 0xEC, 0x05); /* write to i2c status control */ - - i2c_write(hw, 0x001a0080, 0x0e, 0x08); - i2c_write(hw, 0x001a0080, 0x18, 0x0a); - i2c_write(hw, 0x001a0080, 0x28, 0x86); - i2c_write(hw, 0x001a0080, 0x2a, adcdata); - - if (mic20db) { - i2c_write(hw, 0x001a0080, 0x1c, 0xf7); - i2c_write(hw, 0x001a0080, 0x1e, 0xf7); - } else { - i2c_write(hw, 0x001a0080, 0x1c, 0xcf); - i2c_write(hw, 0x001a0080, 0x1e, 0xcf); - } - - if (!(hw_read_20kx(hw, ID0) & 0x100)) - i2c_write(hw, 0x001a0080, 0x16, 0x26); - - i2c_lock(hw); - - gpioorg = (u16)hw_read_20kx(hw, GPIO); - gpioorg &= 0xfe7f; - gpioorg |= input_source; - hw_write_20kx(hw, GPIO, gpioorg); - - return 0; -} - -static int hw_adc_init(struct hw *hw, const struct adc_conf *info) -{ - if (hw->model == CTSB055X) - return adc_init_SB055x(hw, info->input, info->mic20db); - else - return adc_init_SBx(hw, info->input, info->mic20db); -} - -static int hw_have_digit_io_switch(struct hw *hw) -{ - /* SB073x and Vista compatible cards have no digit IO switch */ - return !(hw->model == CTSB073X || hw->model == CTUAA); -} - -#define CTLBITS(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) - -#define UAA_CFG_PWRSTATUS 0x44 -#define UAA_CFG_SPACE_FLAG 0xA0 -#define UAA_CORE_CHANGE 0x3FFC -static int uaa_to_xfi(struct pci_dev *pci) -{ - unsigned int bar0, bar1, bar2, bar3, bar4, bar5; - unsigned int cmd, irq, cl_size, l_timer, pwr; - unsigned int is_uaa; - unsigned int data[4] = {0}; - unsigned int io_base; - void *mem_base; - int i; - const u32 CTLX = CTLBITS('C', 'T', 'L', 'X'); - const u32 CTL_ = CTLBITS('C', 'T', 'L', '-'); - const u32 CTLF = CTLBITS('C', 'T', 'L', 'F'); - const u32 CTLi = CTLBITS('C', 'T', 'L', 'i'); - const u32 CTLA = CTLBITS('C', 'T', 'L', 'A'); - const u32 CTLZ = CTLBITS('C', 'T', 'L', 'Z'); - const u32 CTLL = CTLBITS('C', 'T', 'L', 'L'); - - /* By default, Hendrix card UAA Bar0 should be using memory... */ - io_base = pci_resource_start(pci, 0); - mem_base = ioremap(io_base, pci_resource_len(pci, 0)); - if (NULL == mem_base) - return -ENOENT; - - /* Read current mode from Mode Change Register */ - for (i = 0; i < 4; i++) - data[i] = readl(mem_base + UAA_CORE_CHANGE); - - /* Determine current mode... */ - if (data[0] == CTLA) { - is_uaa = ((data[1] == CTLZ && data[2] == CTLL - && data[3] == CTLA) || (data[1] == CTLA - && data[2] == CTLZ && data[3] == CTLL)); - } else if (data[0] == CTLZ) { - is_uaa = (data[1] == CTLL - && data[2] == CTLA && data[3] == CTLA); - } else if (data[0] == CTLL) { - is_uaa = (data[1] == CTLA - && data[2] == CTLA && data[3] == CTLZ); - } else { - is_uaa = 0; - } - - if (!is_uaa) { - /* Not in UAA mode currently. Return directly. */ - iounmap(mem_base); - return 0; - } - - pci_read_config_dword(pci, PCI_BASE_ADDRESS_0, &bar0); - pci_read_config_dword(pci, PCI_BASE_ADDRESS_1, &bar1); - pci_read_config_dword(pci, PCI_BASE_ADDRESS_2, &bar2); - pci_read_config_dword(pci, PCI_BASE_ADDRESS_3, &bar3); - pci_read_config_dword(pci, PCI_BASE_ADDRESS_4, &bar4); - pci_read_config_dword(pci, PCI_BASE_ADDRESS_5, &bar5); - pci_read_config_dword(pci, PCI_INTERRUPT_LINE, &irq); - pci_read_config_dword(pci, PCI_CACHE_LINE_SIZE, &cl_size); - pci_read_config_dword(pci, PCI_LATENCY_TIMER, &l_timer); - pci_read_config_dword(pci, UAA_CFG_PWRSTATUS, &pwr); - pci_read_config_dword(pci, PCI_COMMAND, &cmd); - - /* Set up X-Fi core PCI configuration space. */ - /* Switch to X-Fi config space with BAR0 exposed. */ - pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x87654321); - /* Copy UAA's BAR5 into X-Fi BAR0 */ - pci_write_config_dword(pci, PCI_BASE_ADDRESS_0, bar5); - /* Switch to X-Fi config space without BAR0 exposed. */ - pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x12345678); - pci_write_config_dword(pci, PCI_BASE_ADDRESS_1, bar1); - pci_write_config_dword(pci, PCI_BASE_ADDRESS_2, bar2); - pci_write_config_dword(pci, PCI_BASE_ADDRESS_3, bar3); - pci_write_config_dword(pci, PCI_BASE_ADDRESS_4, bar4); - pci_write_config_dword(pci, PCI_INTERRUPT_LINE, irq); - pci_write_config_dword(pci, PCI_CACHE_LINE_SIZE, cl_size); - pci_write_config_dword(pci, PCI_LATENCY_TIMER, l_timer); - pci_write_config_dword(pci, UAA_CFG_PWRSTATUS, pwr); - pci_write_config_dword(pci, PCI_COMMAND, cmd); - - /* Switch to X-Fi mode */ - writel(CTLX, (mem_base + UAA_CORE_CHANGE)); - writel(CTL_, (mem_base + UAA_CORE_CHANGE)); - writel(CTLF, (mem_base + UAA_CORE_CHANGE)); - writel(CTLi, (mem_base + UAA_CORE_CHANGE)); - - iounmap(mem_base); - - return 0; -} - -static irqreturn_t ct_20k1_interrupt(int irq, void *dev_id) -{ - struct hw *hw = dev_id; - unsigned int status; - - status = hw_read_20kx(hw, GIP); - if (!status) - return IRQ_NONE; - - if (hw->irq_callback) - hw->irq_callback(hw->irq_callback_data, status); - - hw_write_20kx(hw, GIP, status); - return IRQ_HANDLED; -} - -static int hw_card_start(struct hw *hw) -{ - int err; - struct pci_dev *pci = hw->pci; - - err = pci_enable_device(pci); - if (err < 0) - return err; - - /* Set DMA transfer mask */ - if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 || - pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) { - printk(KERN_ERR "architecture does not support PCI " - "busmaster DMA with mask 0x%llx\n", - CT_XFI_DMA_MASK); - err = -ENXIO; - goto error1; - } - - if (!hw->io_base) { - err = pci_request_regions(pci, "XFi"); - if (err < 0) - goto error1; - - if (hw->model == CTUAA) - hw->io_base = pci_resource_start(pci, 5); - else - hw->io_base = pci_resource_start(pci, 0); - - } - - /* Switch to X-Fi mode from UAA mode if neeeded */ - if (hw->model == CTUAA) { - err = uaa_to_xfi(pci); - if (err) - goto error2; - - } - - if (hw->irq < 0) { - err = request_irq(pci->irq, ct_20k1_interrupt, IRQF_SHARED, - "ctxfi", hw); - if (err < 0) { - printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq); - goto error2; - } - hw->irq = pci->irq; - } - - pci_set_master(pci); - - return 0; - -error2: - pci_release_regions(pci); - hw->io_base = 0; -error1: - pci_disable_device(pci); - return err; -} - -static int hw_card_stop(struct hw *hw) -{ - unsigned int data; - - /* disable transport bus master and queueing of request */ - hw_write_20kx(hw, TRNCTL, 0x00); - - /* disable pll */ - data = hw_read_20kx(hw, PLLCTL); - hw_write_20kx(hw, PLLCTL, (data & (~(0x0F<<12)))); - - /* TODO: Disable interrupt and so on... */ - if (hw->irq >= 0) - synchronize_irq(hw->irq); - return 0; -} - -static int hw_card_shutdown(struct hw *hw) -{ - if (hw->irq >= 0) - free_irq(hw->irq, hw); - - hw->irq = -1; - - if (NULL != ((void *)hw->mem_base)) - iounmap((void *)hw->mem_base); - - hw->mem_base = (unsigned long)NULL; - - if (hw->io_base) - pci_release_regions(hw->pci); - - hw->io_base = 0; - - pci_disable_device(hw->pci); - - return 0; -} - -static int hw_card_init(struct hw *hw, struct card_conf *info) -{ - int err; - unsigned int gctl; - u32 data; - struct dac_conf dac_info = {0}; - struct adc_conf adc_info = {0}; - struct daio_conf daio_info = {0}; - struct trn_conf trn_info = {0}; - - /* Get PCI io port base address and do Hendrix switch if needed. */ - err = hw_card_start(hw); - if (err) - return err; - - /* PLL init */ - err = hw_pll_init(hw, info->rsr); - if (err < 0) - return err; - - /* kick off auto-init */ - err = hw_auto_init(hw); - if (err < 0) - return err; - - /* Enable audio ring */ - gctl = hw_read_20kx(hw, GCTL); - set_field(&gctl, GCTL_EAC, 1); - set_field(&gctl, GCTL_DBP, 1); - set_field(&gctl, GCTL_TBP, 1); - set_field(&gctl, GCTL_FBP, 1); - set_field(&gctl, GCTL_ET, 1); - hw_write_20kx(hw, GCTL, gctl); - mdelay(10); - - /* Reset all global pending interrupts */ - hw_write_20kx(hw, GIE, 0); - /* Reset all SRC pending interrupts */ - hw_write_20kx(hw, SRCIP, 0); - mdelay(30); - - /* Detect the card ID and configure GPIO accordingly. */ - switch (hw->model) { - case CTSB055X: - hw_write_20kx(hw, GPIOCTL, 0x13fe); - break; - case CTSB073X: - hw_write_20kx(hw, GPIOCTL, 0x00e6); - break; - case CTUAA: - hw_write_20kx(hw, GPIOCTL, 0x00c2); - break; - default: - hw_write_20kx(hw, GPIOCTL, 0x01e6); - break; - } - - trn_info.vm_pgt_phys = info->vm_pgt_phys; - err = hw_trn_init(hw, &trn_info); - if (err < 0) - return err; - - daio_info.msr = info->msr; - err = hw_daio_init(hw, &daio_info); - if (err < 0) - return err; - - dac_info.msr = info->msr; - err = hw_dac_init(hw, &dac_info); - if (err < 0) - return err; - - adc_info.msr = info->msr; - adc_info.input = ADC_LINEIN; - adc_info.mic20db = 0; - err = hw_adc_init(hw, &adc_info); - if (err < 0) - return err; - - data = hw_read_20kx(hw, SRCMCTL); - data |= 0x1; /* Enables input from the audio ring */ - hw_write_20kx(hw, SRCMCTL, data); - - return 0; -} - -#ifdef CONFIG_PM -static int hw_suspend(struct hw *hw, pm_message_t state) -{ - struct pci_dev *pci = hw->pci; - - hw_card_stop(hw); - - if (hw->model == CTUAA) { - /* Switch to UAA config space. */ - pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x0); - } - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, pci_choose_state(pci, state)); - - return 0; -} - -static int hw_resume(struct hw *hw, struct card_conf *info) -{ - struct pci_dev *pci = hw->pci; - - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - - /* Re-initialize card hardware. */ - return hw_card_init(hw, info); -} -#endif - -static u32 hw_read_20kx(struct hw *hw, u32 reg) -{ - u32 value; - unsigned long flags; - - spin_lock_irqsave( - &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags); - outl(reg, hw->io_base + 0x0); - value = inl(hw->io_base + 0x4); - spin_unlock_irqrestore( - &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags); - - return value; -} - -static void hw_write_20kx(struct hw *hw, u32 reg, u32 data) -{ - unsigned long flags; - - spin_lock_irqsave( - &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags); - outl(reg, hw->io_base + 0x0); - outl(data, hw->io_base + 0x4); - spin_unlock_irqrestore( - &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags); - -} - -static u32 hw_read_pci(struct hw *hw, u32 reg) -{ - u32 value; - unsigned long flags; - - spin_lock_irqsave( - &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags); - outl(reg, hw->io_base + 0x10); - value = inl(hw->io_base + 0x14); - spin_unlock_irqrestore( - &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags); - - return value; -} - -static void hw_write_pci(struct hw *hw, u32 reg, u32 data) -{ - unsigned long flags; - - spin_lock_irqsave( - &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags); - outl(reg, hw->io_base + 0x10); - outl(data, hw->io_base + 0x14); - spin_unlock_irqrestore( - &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags); -} - -static struct hw ct20k1_preset __devinitdata = { - .irq = -1, - - .card_init = hw_card_init, - .card_stop = hw_card_stop, - .pll_init = hw_pll_init, - .is_adc_source_selected = hw_is_adc_input_selected, - .select_adc_source = hw_adc_input_select, - .have_digit_io_switch = hw_have_digit_io_switch, -#ifdef CONFIG_PM - .suspend = hw_suspend, - .resume = hw_resume, -#endif - - .src_rsc_get_ctrl_blk = src_get_rsc_ctrl_blk, - .src_rsc_put_ctrl_blk = src_put_rsc_ctrl_blk, - .src_mgr_get_ctrl_blk = src_mgr_get_ctrl_blk, - .src_mgr_put_ctrl_blk = src_mgr_put_ctrl_blk, - .src_set_state = src_set_state, - .src_set_bm = src_set_bm, - .src_set_rsr = src_set_rsr, - .src_set_sf = src_set_sf, - .src_set_wr = src_set_wr, - .src_set_pm = src_set_pm, - .src_set_rom = src_set_rom, - .src_set_vo = src_set_vo, - .src_set_st = src_set_st, - .src_set_ie = src_set_ie, - .src_set_ilsz = src_set_ilsz, - .src_set_bp = src_set_bp, - .src_set_cisz = src_set_cisz, - .src_set_ca = src_set_ca, - .src_set_sa = src_set_sa, - .src_set_la = src_set_la, - .src_set_pitch = src_set_pitch, - .src_set_dirty = src_set_dirty, - .src_set_clear_zbufs = src_set_clear_zbufs, - .src_set_dirty_all = src_set_dirty_all, - .src_commit_write = src_commit_write, - .src_get_ca = src_get_ca, - .src_get_dirty = src_get_dirty, - .src_dirty_conj_mask = src_dirty_conj_mask, - .src_mgr_enbs_src = src_mgr_enbs_src, - .src_mgr_enb_src = src_mgr_enb_src, - .src_mgr_dsb_src = src_mgr_dsb_src, - .src_mgr_commit_write = src_mgr_commit_write, - - .srcimp_mgr_get_ctrl_blk = srcimp_mgr_get_ctrl_blk, - .srcimp_mgr_put_ctrl_blk = srcimp_mgr_put_ctrl_blk, - .srcimp_mgr_set_imaparc = srcimp_mgr_set_imaparc, - .srcimp_mgr_set_imapuser = srcimp_mgr_set_imapuser, - .srcimp_mgr_set_imapnxt = srcimp_mgr_set_imapnxt, - .srcimp_mgr_set_imapaddr = srcimp_mgr_set_imapaddr, - .srcimp_mgr_commit_write = srcimp_mgr_commit_write, - - .amixer_rsc_get_ctrl_blk = amixer_rsc_get_ctrl_blk, - .amixer_rsc_put_ctrl_blk = amixer_rsc_put_ctrl_blk, - .amixer_mgr_get_ctrl_blk = amixer_mgr_get_ctrl_blk, - .amixer_mgr_put_ctrl_blk = amixer_mgr_put_ctrl_blk, - .amixer_set_mode = amixer_set_mode, - .amixer_set_iv = amixer_set_iv, - .amixer_set_x = amixer_set_x, - .amixer_set_y = amixer_set_y, - .amixer_set_sadr = amixer_set_sadr, - .amixer_set_se = amixer_set_se, - .amixer_set_dirty = amixer_set_dirty, - .amixer_set_dirty_all = amixer_set_dirty_all, - .amixer_commit_write = amixer_commit_write, - .amixer_get_y = amixer_get_y, - .amixer_get_dirty = amixer_get_dirty, - - .dai_get_ctrl_blk = dai_get_ctrl_blk, - .dai_put_ctrl_blk = dai_put_ctrl_blk, - .dai_srt_set_srco = dai_srt_set_srcr, - .dai_srt_set_srcm = dai_srt_set_srcl, - .dai_srt_set_rsr = dai_srt_set_rsr, - .dai_srt_set_drat = dai_srt_set_drat, - .dai_srt_set_ec = dai_srt_set_ec, - .dai_srt_set_et = dai_srt_set_et, - .dai_commit_write = dai_commit_write, - - .dao_get_ctrl_blk = dao_get_ctrl_blk, - .dao_put_ctrl_blk = dao_put_ctrl_blk, - .dao_set_spos = dao_set_spos, - .dao_commit_write = dao_commit_write, - .dao_get_spos = dao_get_spos, - - .daio_mgr_get_ctrl_blk = daio_mgr_get_ctrl_blk, - .daio_mgr_put_ctrl_blk = daio_mgr_put_ctrl_blk, - .daio_mgr_enb_dai = daio_mgr_enb_dai, - .daio_mgr_dsb_dai = daio_mgr_dsb_dai, - .daio_mgr_enb_dao = daio_mgr_enb_dao, - .daio_mgr_dsb_dao = daio_mgr_dsb_dao, - .daio_mgr_dao_init = daio_mgr_dao_init, - .daio_mgr_set_imaparc = daio_mgr_set_imaparc, - .daio_mgr_set_imapnxt = daio_mgr_set_imapnxt, - .daio_mgr_set_imapaddr = daio_mgr_set_imapaddr, - .daio_mgr_commit_write = daio_mgr_commit_write, - - .set_timer_irq = set_timer_irq, - .set_timer_tick = set_timer_tick, - .get_wc = get_wc, -}; - -int __devinit create_20k1_hw_obj(struct hw **rhw) -{ - struct hw20k1 *hw20k1; - - *rhw = NULL; - hw20k1 = kzalloc(sizeof(*hw20k1), GFP_KERNEL); - if (NULL == hw20k1) - return -ENOMEM; - - spin_lock_init(&hw20k1->reg_20k1_lock); - spin_lock_init(&hw20k1->reg_pci_lock); - - hw20k1->hw = ct20k1_preset; - - *rhw = &hw20k1->hw; - - return 0; -} - -int destroy_20k1_hw_obj(struct hw *hw) -{ - if (hw->io_base) - hw_card_shutdown(hw); - - kfree(container_of(hw, struct hw20k1, hw)); - return 0; -} diff --git a/trunk/sound/pci/ctxfi/cthw20k1.h b/trunk/sound/pci/ctxfi/cthw20k1.h deleted file mode 100644 index 02f72fb448a6..000000000000 --- a/trunk/sound/pci/ctxfi/cthw20k1.h +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. - * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - * - * @File cthw20k1.h - * - * @Brief - * This file contains the definition of hardware access methord. - * - * @Author Liu Chun - * @Date May 13 2008 - * - */ - -#ifndef CTHW20K1_H -#define CTHW20K1_H - -#include "cthardware.h" - -int create_20k1_hw_obj(struct hw **rhw); -int destroy_20k1_hw_obj(struct hw *hw); - -#endif /* CTHW20K1_H */ diff --git a/trunk/sound/pci/ctxfi/cthw20k2.c b/trunk/sound/pci/ctxfi/cthw20k2.c deleted file mode 100644 index dec46d04b041..000000000000 --- a/trunk/sound/pci/ctxfi/cthw20k2.c +++ /dev/null @@ -1,2176 +0,0 @@ -/** - * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. - * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - * - * @File cthw20k2.c - * - * @Brief - * This file contains the implementation of hardware access methord for 20k2. - * - * @Author Liu Chun - * @Date May 14 2008 - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "cthw20k2.h" -#include "ct20k2reg.h" - -#if BITS_PER_LONG == 32 -#define CT_XFI_DMA_MASK DMA_BIT_MASK(32) /* 32 bit PTE */ -#else -#define CT_XFI_DMA_MASK DMA_BIT_MASK(64) /* 64 bit PTE */ -#endif - -struct hw20k2 { - struct hw hw; - /* for i2c */ - unsigned char dev_id; - unsigned char addr_size; - unsigned char data_size; -}; - -static u32 hw_read_20kx(struct hw *hw, u32 reg); -static void hw_write_20kx(struct hw *hw, u32 reg, u32 data); - -/* - * Type definition block. - * The layout of control structures can be directly applied on 20k2 chip. - */ - -/* - * SRC control block definitions. - */ - -/* SRC resource control block */ -#define SRCCTL_STATE 0x00000007 -#define SRCCTL_BM 0x00000008 -#define SRCCTL_RSR 0x00000030 -#define SRCCTL_SF 0x000001C0 -#define SRCCTL_WR 0x00000200 -#define SRCCTL_PM 0x00000400 -#define SRCCTL_ROM 0x00001800 -#define SRCCTL_VO 0x00002000 -#define SRCCTL_ST 0x00004000 -#define SRCCTL_IE 0x00008000 -#define SRCCTL_ILSZ 0x000F0000 -#define SRCCTL_BP 0x00100000 - -#define SRCCCR_CISZ 0x000007FF -#define SRCCCR_CWA 0x001FF800 -#define SRCCCR_D 0x00200000 -#define SRCCCR_RS 0x01C00000 -#define SRCCCR_NAL 0x3E000000 -#define SRCCCR_RA 0xC0000000 - -#define SRCCA_CA 0x0FFFFFFF -#define SRCCA_RS 0xE0000000 - -#define SRCSA_SA 0x0FFFFFFF - -#define SRCLA_LA 0x0FFFFFFF - -/* Mixer Parameter Ring ram Low and Hight register. - * Fixed-point value in 8.24 format for parameter channel */ -#define MPRLH_PITCH 0xFFFFFFFF - -/* SRC resource register dirty flags */ -union src_dirty { - struct { - u16 ctl:1; - u16 ccr:1; - u16 sa:1; - u16 la:1; - u16 ca:1; - u16 mpr:1; - u16 czbfs:1; /* Clear Z-Buffers */ - u16 rsv:9; - } bf; - u16 data; -}; - -struct src_rsc_ctrl_blk { - unsigned int ctl; - unsigned int ccr; - unsigned int ca; - unsigned int sa; - unsigned int la; - unsigned int mpr; - union src_dirty dirty; -}; - -/* SRC manager control block */ -union src_mgr_dirty { - struct { - u16 enb0:1; - u16 enb1:1; - u16 enb2:1; - u16 enb3:1; - u16 enb4:1; - u16 enb5:1; - u16 enb6:1; - u16 enb7:1; - u16 enbsa:1; - u16 rsv:7; - } bf; - u16 data; -}; - -struct src_mgr_ctrl_blk { - unsigned int enbsa; - unsigned int enb[8]; - union src_mgr_dirty dirty; -}; - -/* SRCIMP manager control block */ -#define SRCAIM_ARC 0x00000FFF -#define SRCAIM_NXT 0x00FF0000 -#define SRCAIM_SRC 0xFF000000 - -struct srcimap { - unsigned int srcaim; - unsigned int idx; -}; - -/* SRCIMP manager register dirty flags */ -union srcimp_mgr_dirty { - struct { - u16 srcimap:1; - u16 rsv:15; - } bf; - u16 data; -}; - -struct srcimp_mgr_ctrl_blk { - struct srcimap srcimap; - union srcimp_mgr_dirty dirty; -}; - -/* - * Function implementation block. - */ - -static int src_get_rsc_ctrl_blk(void **rblk) -{ - struct src_rsc_ctrl_blk *blk; - - *rblk = NULL; - blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) - return -ENOMEM; - - *rblk = blk; - - return 0; -} - -static int src_put_rsc_ctrl_blk(void *blk) -{ - kfree(blk); - - return 0; -} - -static int src_set_state(void *blk, unsigned int state) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->ctl, SRCCTL_STATE, state); - ctl->dirty.bf.ctl = 1; - return 0; -} - -static int src_set_bm(void *blk, unsigned int bm) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->ctl, SRCCTL_BM, bm); - ctl->dirty.bf.ctl = 1; - return 0; -} - -static int src_set_rsr(void *blk, unsigned int rsr) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->ctl, SRCCTL_RSR, rsr); - ctl->dirty.bf.ctl = 1; - return 0; -} - -static int src_set_sf(void *blk, unsigned int sf) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->ctl, SRCCTL_SF, sf); - ctl->dirty.bf.ctl = 1; - return 0; -} - -static int src_set_wr(void *blk, unsigned int wr) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->ctl, SRCCTL_WR, wr); - ctl->dirty.bf.ctl = 1; - return 0; -} - -static int src_set_pm(void *blk, unsigned int pm) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->ctl, SRCCTL_PM, pm); - ctl->dirty.bf.ctl = 1; - return 0; -} - -static int src_set_rom(void *blk, unsigned int rom) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->ctl, SRCCTL_ROM, rom); - ctl->dirty.bf.ctl = 1; - return 0; -} - -static int src_set_vo(void *blk, unsigned int vo) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->ctl, SRCCTL_VO, vo); - ctl->dirty.bf.ctl = 1; - return 0; -} - -static int src_set_st(void *blk, unsigned int st) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->ctl, SRCCTL_ST, st); - ctl->dirty.bf.ctl = 1; - return 0; -} - -static int src_set_ie(void *blk, unsigned int ie) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->ctl, SRCCTL_IE, ie); - ctl->dirty.bf.ctl = 1; - return 0; -} - -static int src_set_ilsz(void *blk, unsigned int ilsz) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->ctl, SRCCTL_ILSZ, ilsz); - ctl->dirty.bf.ctl = 1; - return 0; -} - -static int src_set_bp(void *blk, unsigned int bp) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->ctl, SRCCTL_BP, bp); - ctl->dirty.bf.ctl = 1; - return 0; -} - -static int src_set_cisz(void *blk, unsigned int cisz) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->ccr, SRCCCR_CISZ, cisz); - ctl->dirty.bf.ccr = 1; - return 0; -} - -static int src_set_ca(void *blk, unsigned int ca) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->ca, SRCCA_CA, ca); - ctl->dirty.bf.ca = 1; - return 0; -} - -static int src_set_sa(void *blk, unsigned int sa) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->sa, SRCSA_SA, sa); - ctl->dirty.bf.sa = 1; - return 0; -} - -static int src_set_la(void *blk, unsigned int la) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->la, SRCLA_LA, la); - ctl->dirty.bf.la = 1; - return 0; -} - -static int src_set_pitch(void *blk, unsigned int pitch) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->mpr, MPRLH_PITCH, pitch); - ctl->dirty.bf.mpr = 1; - return 0; -} - -static int src_set_clear_zbufs(void *blk, unsigned int clear) -{ - ((struct src_rsc_ctrl_blk *)blk)->dirty.bf.czbfs = (clear ? 1 : 0); - return 0; -} - -static int src_set_dirty(void *blk, unsigned int flags) -{ - ((struct src_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff); - return 0; -} - -static int src_set_dirty_all(void *blk) -{ - ((struct src_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0); - return 0; -} - -#define AR_SLOT_SIZE 4096 -#define AR_SLOT_BLOCK_SIZE 16 -#define AR_PTS_PITCH 6 -#define AR_PARAM_SRC_OFFSET 0x60 - -static unsigned int src_param_pitch_mixer(unsigned int src_idx) -{ - return ((src_idx << 4) + AR_PTS_PITCH + AR_SLOT_SIZE - - AR_PARAM_SRC_OFFSET) % AR_SLOT_SIZE; - -} - -static int src_commit_write(struct hw *hw, unsigned int idx, void *blk) -{ - struct src_rsc_ctrl_blk *ctl = blk; - int i; - - if (ctl->dirty.bf.czbfs) { - /* Clear Z-Buffer registers */ - for (i = 0; i < 8; i++) - hw_write_20kx(hw, SRC_UPZ+idx*0x100+i*0x4, 0); - - for (i = 0; i < 4; i++) - hw_write_20kx(hw, SRC_DN0Z+idx*0x100+i*0x4, 0); - - for (i = 0; i < 8; i++) - hw_write_20kx(hw, SRC_DN1Z+idx*0x100+i*0x4, 0); - - ctl->dirty.bf.czbfs = 0; - } - if (ctl->dirty.bf.mpr) { - /* Take the parameter mixer resource in the same group as that - * the idx src is in for simplicity. Unlike src, all conjugate - * parameter mixer resources must be programmed for - * corresponding conjugate src resources. */ - unsigned int pm_idx = src_param_pitch_mixer(idx); - hw_write_20kx(hw, MIXER_PRING_LO_HI+4*pm_idx, ctl->mpr); - hw_write_20kx(hw, MIXER_PMOPLO+8*pm_idx, 0x3); - hw_write_20kx(hw, MIXER_PMOPHI+8*pm_idx, 0x0); - ctl->dirty.bf.mpr = 0; - } - if (ctl->dirty.bf.sa) { - hw_write_20kx(hw, SRC_SA+idx*0x100, ctl->sa); - ctl->dirty.bf.sa = 0; - } - if (ctl->dirty.bf.la) { - hw_write_20kx(hw, SRC_LA+idx*0x100, ctl->la); - ctl->dirty.bf.la = 0; - } - if (ctl->dirty.bf.ca) { - hw_write_20kx(hw, SRC_CA+idx*0x100, ctl->ca); - ctl->dirty.bf.ca = 0; - } - - /* Write srccf register */ - hw_write_20kx(hw, SRC_CF+idx*0x100, 0x0); - - if (ctl->dirty.bf.ccr) { - hw_write_20kx(hw, SRC_CCR+idx*0x100, ctl->ccr); - ctl->dirty.bf.ccr = 0; - } - if (ctl->dirty.bf.ctl) { - hw_write_20kx(hw, SRC_CTL+idx*0x100, ctl->ctl); - ctl->dirty.bf.ctl = 0; - } - - return 0; -} - -static int src_get_ca(struct hw *hw, unsigned int idx, void *blk) -{ - struct src_rsc_ctrl_blk *ctl = blk; - - ctl->ca = hw_read_20kx(hw, SRC_CA+idx*0x100); - ctl->dirty.bf.ca = 0; - - return get_field(ctl->ca, SRCCA_CA); -} - -static unsigned int src_get_dirty(void *blk) -{ - return ((struct src_rsc_ctrl_blk *)blk)->dirty.data; -} - -static unsigned int src_dirty_conj_mask(void) -{ - return 0x20; -} - -static int src_mgr_enbs_src(void *blk, unsigned int idx) -{ - ((struct src_mgr_ctrl_blk *)blk)->enbsa |= (0x1 << ((idx%128)/4)); - ((struct src_mgr_ctrl_blk *)blk)->dirty.bf.enbsa = 1; - ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32)); - return 0; -} - -static int src_mgr_enb_src(void *blk, unsigned int idx) -{ - ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32)); - ((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32)); - return 0; -} - -static int src_mgr_dsb_src(void *blk, unsigned int idx) -{ - ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] &= ~(0x1 << (idx%32)); - ((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32)); - return 0; -} - -static int src_mgr_commit_write(struct hw *hw, void *blk) -{ - struct src_mgr_ctrl_blk *ctl = blk; - int i; - unsigned int ret; - - if (ctl->dirty.bf.enbsa) { - do { - ret = hw_read_20kx(hw, SRC_ENBSTAT); - } while (ret & 0x1); - hw_write_20kx(hw, SRC_ENBSA, ctl->enbsa); - ctl->dirty.bf.enbsa = 0; - } - for (i = 0; i < 8; i++) { - if ((ctl->dirty.data & (0x1 << i))) { - hw_write_20kx(hw, SRC_ENB+(i*0x100), ctl->enb[i]); - ctl->dirty.data &= ~(0x1 << i); - } - } - - return 0; -} - -static int src_mgr_get_ctrl_blk(void **rblk) -{ - struct src_mgr_ctrl_blk *blk; - - *rblk = NULL; - blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) - return -ENOMEM; - - *rblk = blk; - - return 0; -} - -static int src_mgr_put_ctrl_blk(void *blk) -{ - kfree(blk); - - return 0; -} - -static int srcimp_mgr_get_ctrl_blk(void **rblk) -{ - struct srcimp_mgr_ctrl_blk *blk; - - *rblk = NULL; - blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) - return -ENOMEM; - - *rblk = blk; - - return 0; -} - -static int srcimp_mgr_put_ctrl_blk(void *blk) -{ - kfree(blk); - - return 0; -} - -static int srcimp_mgr_set_imaparc(void *blk, unsigned int slot) -{ - struct srcimp_mgr_ctrl_blk *ctl = blk; - - set_field(&ctl->srcimap.srcaim, SRCAIM_ARC, slot); - ctl->dirty.bf.srcimap = 1; - return 0; -} - -static int srcimp_mgr_set_imapuser(void *blk, unsigned int user) -{ - struct srcimp_mgr_ctrl_blk *ctl = blk; - - set_field(&ctl->srcimap.srcaim, SRCAIM_SRC, user); - ctl->dirty.bf.srcimap = 1; - return 0; -} - -static int srcimp_mgr_set_imapnxt(void *blk, unsigned int next) -{ - struct srcimp_mgr_ctrl_blk *ctl = blk; - - set_field(&ctl->srcimap.srcaim, SRCAIM_NXT, next); - ctl->dirty.bf.srcimap = 1; - return 0; -} - -static int srcimp_mgr_set_imapaddr(void *blk, unsigned int addr) -{ - ((struct srcimp_mgr_ctrl_blk *)blk)->srcimap.idx = addr; - ((struct srcimp_mgr_ctrl_blk *)blk)->dirty.bf.srcimap = 1; - return 0; -} - -static int srcimp_mgr_commit_write(struct hw *hw, void *blk) -{ - struct srcimp_mgr_ctrl_blk *ctl = blk; - - if (ctl->dirty.bf.srcimap) { - hw_write_20kx(hw, SRC_IMAP+ctl->srcimap.idx*0x100, - ctl->srcimap.srcaim); - ctl->dirty.bf.srcimap = 0; - } - - return 0; -} - -/* - * AMIXER control block definitions. - */ - -#define AMOPLO_M 0x00000003 -#define AMOPLO_IV 0x00000004 -#define AMOPLO_X 0x0003FFF0 -#define AMOPLO_Y 0xFFFC0000 - -#define AMOPHI_SADR 0x000000FF -#define AMOPHI_SE 0x80000000 - -/* AMIXER resource register dirty flags */ -union amixer_dirty { - struct { - u16 amoplo:1; - u16 amophi:1; - u16 rsv:14; - } bf; - u16 data; -}; - -/* AMIXER resource control block */ -struct amixer_rsc_ctrl_blk { - unsigned int amoplo; - unsigned int amophi; - union amixer_dirty dirty; -}; - -static int amixer_set_mode(void *blk, unsigned int mode) -{ - struct amixer_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->amoplo, AMOPLO_M, mode); - ctl->dirty.bf.amoplo = 1; - return 0; -} - -static int amixer_set_iv(void *blk, unsigned int iv) -{ - struct amixer_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->amoplo, AMOPLO_IV, iv); - ctl->dirty.bf.amoplo = 1; - return 0; -} - -static int amixer_set_x(void *blk, unsigned int x) -{ - struct amixer_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->amoplo, AMOPLO_X, x); - ctl->dirty.bf.amoplo = 1; - return 0; -} - -static int amixer_set_y(void *blk, unsigned int y) -{ - struct amixer_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->amoplo, AMOPLO_Y, y); - ctl->dirty.bf.amoplo = 1; - return 0; -} - -static int amixer_set_sadr(void *blk, unsigned int sadr) -{ - struct amixer_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->amophi, AMOPHI_SADR, sadr); - ctl->dirty.bf.amophi = 1; - return 0; -} - -static int amixer_set_se(void *blk, unsigned int se) -{ - struct amixer_rsc_ctrl_blk *ctl = blk; - - set_field(&ctl->amophi, AMOPHI_SE, se); - ctl->dirty.bf.amophi = 1; - return 0; -} - -static int amixer_set_dirty(void *blk, unsigned int flags) -{ - ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff); - return 0; -} - -static int amixer_set_dirty_all(void *blk) -{ - ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0); - return 0; -} - -static int amixer_commit_write(struct hw *hw, unsigned int idx, void *blk) -{ - struct amixer_rsc_ctrl_blk *ctl = blk; - - if (ctl->dirty.bf.amoplo || ctl->dirty.bf.amophi) { - hw_write_20kx(hw, MIXER_AMOPLO+idx*8, ctl->amoplo); - ctl->dirty.bf.amoplo = 0; - hw_write_20kx(hw, MIXER_AMOPHI+idx*8, ctl->amophi); - ctl->dirty.bf.amophi = 0; - } - - return 0; -} - -static int amixer_get_y(void *blk) -{ - struct amixer_rsc_ctrl_blk *ctl = blk; - - return get_field(ctl->amoplo, AMOPLO_Y); -} - -static unsigned int amixer_get_dirty(void *blk) -{ - return ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data; -} - -static int amixer_rsc_get_ctrl_blk(void **rblk) -{ - struct amixer_rsc_ctrl_blk *blk; - - *rblk = NULL; - blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) - return -ENOMEM; - - *rblk = blk; - - return 0; -} - -static int amixer_rsc_put_ctrl_blk(void *blk) -{ - kfree(blk); - - return 0; -} - -static int amixer_mgr_get_ctrl_blk(void **rblk) -{ - *rblk = NULL; - - return 0; -} - -static int amixer_mgr_put_ctrl_blk(void *blk) -{ - return 0; -} - -/* - * DAIO control block definitions. - */ - -/* Receiver Sample Rate Tracker Control register */ -#define SRTCTL_SRCO 0x000000FF -#define SRTCTL_SRCM 0x0000FF00 -#define SRTCTL_RSR 0x00030000 -#define SRTCTL_DRAT 0x00300000 -#define SRTCTL_EC 0x01000000 -#define SRTCTL_ET 0x10000000 - -/* DAIO Receiver register dirty flags */ -union dai_dirty { - struct { - u16 srt:1; - u16 rsv:15; - } bf; - u16 data; -}; - -/* DAIO Receiver control block */ -struct dai_ctrl_blk { - unsigned int srt; - union dai_dirty dirty; -}; - -/* Audio Input Mapper RAM */ -#define AIM_ARC 0x00000FFF -#define AIM_NXT 0x007F0000 - -struct daoimap { - unsigned int aim; - unsigned int idx; -}; - -/* Audio Transmitter Control and Status register */ -#define ATXCTL_EN 0x00000001 -#define ATXCTL_MODE 0x00000010 -#define ATXCTL_CD 0x00000020 -#define ATXCTL_RAW 0x00000100 -#define ATXCTL_MT 0x00000200 -#define ATXCTL_NUC 0x00003000 -#define ATXCTL_BEN 0x00010000 -#define ATXCTL_BMUX 0x00700000 -#define ATXCTL_B24 0x01000000 -#define ATXCTL_CPF 0x02000000 -#define ATXCTL_RIV 0x10000000 -#define ATXCTL_LIV 0x20000000 -#define ATXCTL_RSAT 0x40000000 -#define ATXCTL_LSAT 0x80000000 - -/* XDIF Transmitter register dirty flags */ -union dao_dirty { - struct { - u16 atxcsl:1; - u16 rsv:15; - } bf; - u16 data; -}; - -/* XDIF Transmitter control block */ -struct dao_ctrl_blk { - /* XDIF Transmitter Channel Status Low Register */ - unsigned int atxcsl; - union dao_dirty dirty; -}; - -/* Audio Receiver Control register */ -#define ARXCTL_EN 0x00000001 - -/* DAIO manager register dirty flags */ -union daio_mgr_dirty { - struct { - u32 atxctl:8; - u32 arxctl:8; - u32 daoimap:1; - u32 rsv:15; - } bf; - u32 data; -}; - -/* DAIO manager control block */ -struct daio_mgr_ctrl_blk { - struct daoimap daoimap; - unsigned int txctl[8]; - unsigned int rxctl[8]; - union daio_mgr_dirty dirty; -}; - -static int dai_srt_set_srco(void *blk, unsigned int src) -{ - struct dai_ctrl_blk *ctl = blk; - - set_field(&ctl->srt, SRTCTL_SRCO, src); - ctl->dirty.bf.srt = 1; - return 0; -} - -static int dai_srt_set_srcm(void *blk, unsigned int src) -{ - struct dai_ctrl_blk *ctl = blk; - - set_field(&ctl->srt, SRTCTL_SRCM, src); - ctl->dirty.bf.srt = 1; - return 0; -} - -static int dai_srt_set_rsr(void *blk, unsigned int rsr) -{ - struct dai_ctrl_blk *ctl = blk; - - set_field(&ctl->srt, SRTCTL_RSR, rsr); - ctl->dirty.bf.srt = 1; - return 0; -} - -static int dai_srt_set_drat(void *blk, unsigned int drat) -{ - struct dai_ctrl_blk *ctl = blk; - - set_field(&ctl->srt, SRTCTL_DRAT, drat); - ctl->dirty.bf.srt = 1; - return 0; -} - -static int dai_srt_set_ec(void *blk, unsigned int ec) -{ - struct dai_ctrl_blk *ctl = blk; - - set_field(&ctl->srt, SRTCTL_EC, ec ? 1 : 0); - ctl->dirty.bf.srt = 1; - return 0; -} - -static int dai_srt_set_et(void *blk, unsigned int et) -{ - struct dai_ctrl_blk *ctl = blk; - - set_field(&ctl->srt, SRTCTL_ET, et ? 1 : 0); - ctl->dirty.bf.srt = 1; - return 0; -} - -static int dai_commit_write(struct hw *hw, unsigned int idx, void *blk) -{ - struct dai_ctrl_blk *ctl = blk; - - if (ctl->dirty.bf.srt) { - hw_write_20kx(hw, AUDIO_IO_RX_SRT_CTL+0x40*idx, ctl->srt); - ctl->dirty.bf.srt = 0; - } - - return 0; -} - -static int dai_get_ctrl_blk(void **rblk) -{ - struct dai_ctrl_blk *blk; - - *rblk = NULL; - blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) - return -ENOMEM; - - *rblk = blk; - - return 0; -} - -static int dai_put_ctrl_blk(void *blk) -{ - kfree(blk); - - return 0; -} - -static int dao_set_spos(void *blk, unsigned int spos) -{ - ((struct dao_ctrl_blk *)blk)->atxcsl = spos; - ((struct dao_ctrl_blk *)blk)->dirty.bf.atxcsl = 1; - return 0; -} - -static int dao_commit_write(struct hw *hw, unsigned int idx, void *blk) -{ - struct dao_ctrl_blk *ctl = blk; - - if (ctl->dirty.bf.atxcsl) { - if (idx < 4) { - /* S/PDIF SPOSx */ - hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_L+0x40*idx, - ctl->atxcsl); - } - ctl->dirty.bf.atxcsl = 0; - } - - return 0; -} - -static int dao_get_spos(void *blk, unsigned int *spos) -{ - *spos = ((struct dao_ctrl_blk *)blk)->atxcsl; - return 0; -} - -static int dao_get_ctrl_blk(void **rblk) -{ - struct dao_ctrl_blk *blk; - - *rblk = NULL; - blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) - return -ENOMEM; - - *rblk = blk; - - return 0; -} - -static int dao_put_ctrl_blk(void *blk) -{ - kfree(blk); - - return 0; -} - -static int daio_mgr_enb_dai(void *blk, unsigned int idx) -{ - struct daio_mgr_ctrl_blk *ctl = blk; - - set_field(&ctl->rxctl[idx], ARXCTL_EN, 1); - ctl->dirty.bf.arxctl |= (0x1 << idx); - return 0; -} - -static int daio_mgr_dsb_dai(void *blk, unsigned int idx) -{ - struct daio_mgr_ctrl_blk *ctl = blk; - - set_field(&ctl->rxctl[idx], ARXCTL_EN, 0); - - ctl->dirty.bf.arxctl |= (0x1 << idx); - return 0; -} - -static int daio_mgr_enb_dao(void *blk, unsigned int idx) -{ - struct daio_mgr_ctrl_blk *ctl = blk; - - set_field(&ctl->txctl[idx], ATXCTL_EN, 1); - ctl->dirty.bf.atxctl |= (0x1 << idx); - return 0; -} - -static int daio_mgr_dsb_dao(void *blk, unsigned int idx) -{ - struct daio_mgr_ctrl_blk *ctl = blk; - - set_field(&ctl->txctl[idx], ATXCTL_EN, 0); - ctl->dirty.bf.atxctl |= (0x1 << idx); - return 0; -} - -static int daio_mgr_dao_init(void *blk, unsigned int idx, unsigned int conf) -{ - struct daio_mgr_ctrl_blk *ctl = blk; - - if (idx < 4) { - /* S/PDIF output */ - switch ((conf & 0x7)) { - case 1: - set_field(&ctl->txctl[idx], ATXCTL_NUC, 0); - break; - case 2: - set_field(&ctl->txctl[idx], ATXCTL_NUC, 1); - break; - case 4: - set_field(&ctl->txctl[idx], ATXCTL_NUC, 2); - break; - case 8: - set_field(&ctl->txctl[idx], ATXCTL_NUC, 3); - break; - default: - break; - } - /* CDIF */ - set_field(&ctl->txctl[idx], ATXCTL_CD, (!(conf & 0x7))); - /* Non-audio */ - set_field(&ctl->txctl[idx], ATXCTL_LIV, (conf >> 4) & 0x1); - /* Non-audio */ - set_field(&ctl->txctl[idx], ATXCTL_RIV, (conf >> 4) & 0x1); - set_field(&ctl->txctl[idx], ATXCTL_RAW, - ((conf >> 3) & 0x1) ? 0 : 0); - ctl->dirty.bf.atxctl |= (0x1 << idx); - } else { - /* I2S output */ - /*idx %= 4; */ - } - return 0; -} - -static int daio_mgr_set_imaparc(void *blk, unsigned int slot) -{ - struct daio_mgr_ctrl_blk *ctl = blk; - - set_field(&ctl->daoimap.aim, AIM_ARC, slot); - ctl->dirty.bf.daoimap = 1; - return 0; -} - -static int daio_mgr_set_imapnxt(void *blk, unsigned int next) -{ - struct daio_mgr_ctrl_blk *ctl = blk; - - set_field(&ctl->daoimap.aim, AIM_NXT, next); - ctl->dirty.bf.daoimap = 1; - return 0; -} - -static int daio_mgr_set_imapaddr(void *blk, unsigned int addr) -{ - ((struct daio_mgr_ctrl_blk *)blk)->daoimap.idx = addr; - ((struct daio_mgr_ctrl_blk *)blk)->dirty.bf.daoimap = 1; - return 0; -} - -static int daio_mgr_commit_write(struct hw *hw, void *blk) -{ - struct daio_mgr_ctrl_blk *ctl = blk; - unsigned int data; - int i; - - for (i = 0; i < 8; i++) { - if ((ctl->dirty.bf.atxctl & (0x1 << i))) { - data = ctl->txctl[i]; - hw_write_20kx(hw, (AUDIO_IO_TX_CTL+(0x40*i)), data); - ctl->dirty.bf.atxctl &= ~(0x1 << i); - mdelay(1); - } - if ((ctl->dirty.bf.arxctl & (0x1 << i))) { - data = ctl->rxctl[i]; - hw_write_20kx(hw, (AUDIO_IO_RX_CTL+(0x40*i)), data); - ctl->dirty.bf.arxctl &= ~(0x1 << i); - mdelay(1); - } - } - if (ctl->dirty.bf.daoimap) { - hw_write_20kx(hw, AUDIO_IO_AIM+ctl->daoimap.idx*4, - ctl->daoimap.aim); - ctl->dirty.bf.daoimap = 0; - } - - return 0; -} - -static int daio_mgr_get_ctrl_blk(struct hw *hw, void **rblk) -{ - struct daio_mgr_ctrl_blk *blk; - int i; - - *rblk = NULL; - blk = kzalloc(sizeof(*blk), GFP_KERNEL); - if (NULL == blk) - return -ENOMEM; - - for (i = 0; i < 8; i++) { - blk->txctl[i] = hw_read_20kx(hw, AUDIO_IO_TX_CTL+(0x40*i)); - blk->rxctl[i] = hw_read_20kx(hw, AUDIO_IO_RX_CTL+(0x40*i)); - } - - *rblk = blk; - - return 0; -} - -static int daio_mgr_put_ctrl_blk(void *blk) -{ - kfree(blk); - - return 0; -} - -/* Card hardware initialization block */ -struct dac_conf { - unsigned int msr; /* master sample rate in rsrs */ -}; - -struct adc_conf { - unsigned int msr; /* master sample rate in rsrs */ - unsigned char input; /* the input source of ADC */ - unsigned char mic20db; /* boost mic by 20db if input is microphone */ -}; - -struct daio_conf { - unsigned int msr; /* master sample rate in rsrs */ -}; - -struct trn_conf { - unsigned long vm_pgt_phys; -}; - -static int hw_daio_init(struct hw *hw, const struct daio_conf *info) -{ - u32 data; - int i; - - /* Program I2S with proper sample rate and enable the correct I2S - * channel. ED(0/8/16/24): Enable all I2S/I2X master clock output */ - if (1 == info->msr) { - hw_write_20kx(hw, AUDIO_IO_MCLK, 0x01010101); - hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x01010101); - hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0); - } else if (2 == info->msr) { - hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11111111); - /* Specify all playing 96khz - * EA [0] - Enabled - * RTA [4:5] - 96kHz - * EB [8] - Enabled - * RTB [12:13] - 96kHz - * EC [16] - Enabled - * RTC [20:21] - 96kHz - * ED [24] - Enabled - * RTD [28:29] - 96kHz */ - hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x11111111); - hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0); - } else { - printk(KERN_ALERT "ctxfi: ERROR!!! Invalid sampling rate!!!\n"); - return -EINVAL; - } - - for (i = 0; i < 8; i++) { - if (i <= 3) { - /* 1st 3 channels are SPDIFs (SB0960) */ - if (i == 3) - data = 0x1001001; - else - data = 0x1000001; - - hw_write_20kx(hw, (AUDIO_IO_TX_CTL+(0x40*i)), data); - hw_write_20kx(hw, (AUDIO_IO_RX_CTL+(0x40*i)), data); - - /* Initialize the SPDIF Out Channel status registers. - * The value specified here is based on the typical - * values provided in the specification, namely: Clock - * Accuracy of 1000ppm, Sample Rate of 48KHz, - * unspecified source number, Generation status = 1, - * Category code = 0x12 (Digital Signal Mixer), - * Mode = 0, Emph = 0, Copy Permitted, AN = 0 - * (indicating that we're transmitting digital audio, - * and the Professional Use bit is 0. */ - - hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_L+(0x40*i), - 0x02109204); /* Default to 48kHz */ - - hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_H+(0x40*i), 0x0B); - } else { - /* Next 5 channels are I2S (SB0960) */ - data = 0x11; - hw_write_20kx(hw, AUDIO_IO_RX_CTL+(0x40*i), data); - if (2 == info->msr) { - /* Four channels per sample period */ - data |= 0x1000; - } - hw_write_20kx(hw, AUDIO_IO_TX_CTL+(0x40*i), data); - } - } - - return 0; -} - -/* TRANSPORT operations */ -static int hw_trn_init(struct hw *hw, const struct trn_conf *info) -{ - u32 vmctl, data; - u32 ptp_phys_low, ptp_phys_high; - int i; - - /* Set up device page table */ - if ((~0UL) == info->vm_pgt_phys) { - printk(KERN_ALERT "ctxfi: " - "Wrong device page table page address!!!\n"); - return -1; - } - - vmctl = 0x80000C0F; /* 32-bit, 4k-size page */ - ptp_phys_low = (u32)info->vm_pgt_phys; - ptp_phys_high = upper_32_bits(info->vm_pgt_phys); - if (sizeof(void *) == 8) /* 64bit address */ - vmctl |= (3 << 8); - /* Write page table physical address to all PTPAL registers */ - for (i = 0; i < 64; i++) { - hw_write_20kx(hw, VMEM_PTPAL+(16*i), ptp_phys_low); - hw_write_20kx(hw, VMEM_PTPAH+(16*i), ptp_phys_high); - } - /* Enable virtual memory transfer */ - hw_write_20kx(hw, VMEM_CTL, vmctl); - /* Enable transport bus master and queueing of request */ - hw_write_20kx(hw, TRANSPORT_CTL, 0x03); - hw_write_20kx(hw, TRANSPORT_INT, 0x200c01); - /* Enable transport ring */ - data = hw_read_20kx(hw, TRANSPORT_ENB); - hw_write_20kx(hw, TRANSPORT_ENB, (data | 0x03)); - - return 0; -} - -/* Card initialization */ -#define GCTL_AIE 0x00000001 -#define GCTL_UAA 0x00000002 -#define GCTL_DPC 0x00000004 -#define GCTL_DBP 0x00000008 -#define GCTL_ABP 0x00000010 -#define GCTL_TBP 0x00000020 -#define GCTL_SBP 0x00000040 -#define GCTL_FBP 0x00000080 -#define GCTL_ME 0x00000100 -#define GCTL_AID 0x00001000 - -#define PLLCTL_SRC 0x00000007 -#define PLLCTL_SPE 0x00000008 -#define PLLCTL_RD 0x000000F0 -#define PLLCTL_FD 0x0001FF00 -#define PLLCTL_OD 0x00060000 -#define PLLCTL_B 0x00080000 -#define PLLCTL_AS 0x00100000 -#define PLLCTL_LF 0x03E00000 -#define PLLCTL_SPS 0x1C000000 -#define PLLCTL_AD 0x60000000 - -#define PLLSTAT_CCS 0x00000007 -#define PLLSTAT_SPL 0x00000008 -#define PLLSTAT_CRD 0x000000F0 -#define PLLSTAT_CFD 0x0001FF00 -#define PLLSTAT_SL 0x00020000 -#define PLLSTAT_FAS 0x00040000 -#define PLLSTAT_B 0x00080000 -#define PLLSTAT_PD 0x00100000 -#define PLLSTAT_OCA 0x00200000 -#define PLLSTAT_NCA 0x00400000 - -static int hw_pll_init(struct hw *hw, unsigned int rsr) -{ - unsigned int pllenb; - unsigned int pllctl; - unsigned int pllstat; - int i; - - pllenb = 0xB; - hw_write_20kx(hw, PLL_ENB, pllenb); - pllctl = 0x20D00000; - set_field(&pllctl, PLLCTL_FD, 16 - 4); - hw_write_20kx(hw, PLL_CTL, pllctl); - mdelay(40); - pllctl = hw_read_20kx(hw, PLL_CTL); - set_field(&pllctl, PLLCTL_B, 0); - if (48000 == rsr) { - set_field(&pllctl, PLLCTL_FD, 16 - 2); - set_field(&pllctl, PLLCTL_RD, 1 - 1); - } else { /* 44100 */ - set_field(&pllctl, PLLCTL_FD, 147 - 2); - set_field(&pllctl, PLLCTL_RD, 10 - 1); - } - hw_write_20kx(hw, PLL_CTL, pllctl); - mdelay(40); - for (i = 0; i < 1000; i++) { - pllstat = hw_read_20kx(hw, PLL_STAT); - if (get_field(pllstat, PLLSTAT_PD)) - continue; - - if (get_field(pllstat, PLLSTAT_B) != - get_field(pllctl, PLLCTL_B)) - continue; - - if (get_field(pllstat, PLLSTAT_CCS) != - get_field(pllctl, PLLCTL_SRC)) - continue; - - if (get_field(pllstat, PLLSTAT_CRD) != - get_field(pllctl, PLLCTL_RD)) - continue; - - if (get_field(pllstat, PLLSTAT_CFD) != - get_field(pllctl, PLLCTL_FD)) - continue; - - break; - } - if (i >= 1000) { - printk(KERN_ALERT "ctxfi: PLL initialization failed!!!\n"); - return -EBUSY; - } - - return 0; -} - -static int hw_auto_init(struct hw *hw) -{ - unsigned int gctl; - int i; - - gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL); - set_field(&gctl, GCTL_AIE, 0); - hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl); - set_field(&gctl, GCTL_AIE, 1); - hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl); - mdelay(10); - for (i = 0; i < 400000; i++) { - gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL); - if (get_field(gctl, GCTL_AID)) - break; - } - if (!get_field(gctl, GCTL_AID)) { - printk(KERN_ALERT "ctxfi: Card Auto-init failed!!!\n"); - return -EBUSY; - } - - return 0; -} - -/* DAC operations */ - -#define CS4382_MC1 0x1 -#define CS4382_MC2 0x2 -#define CS4382_MC3 0x3 -#define CS4382_FC 0x4 -#define CS4382_IC 0x5 -#define CS4382_XC1 0x6 -#define CS4382_VCA1 0x7 -#define CS4382_VCB1 0x8 -#define CS4382_XC2 0x9 -#define CS4382_VCA2 0xA -#define CS4382_VCB2 0xB -#define CS4382_XC3 0xC -#define CS4382_VCA3 0xD -#define CS4382_VCB3 0xE -#define CS4382_XC4 0xF -#define CS4382_VCA4 0x10 -#define CS4382_VCB4 0x11 -#define CS4382_CREV 0x12 - -/* I2C status */ -#define STATE_LOCKED 0x00 -#define STATE_UNLOCKED 0xAA -#define DATA_READY 0x800000 /* Used with I2C_IF_STATUS */ -#define DATA_ABORT 0x10000 /* Used with I2C_IF_STATUS */ - -#define I2C_STATUS_DCM 0x00000001 -#define I2C_STATUS_BC 0x00000006 -#define I2C_STATUS_APD 0x00000008 -#define I2C_STATUS_AB 0x00010000 -#define I2C_STATUS_DR 0x00800000 - -#define I2C_ADDRESS_PTAD 0x0000FFFF -#define I2C_ADDRESS_SLAD 0x007F0000 - -struct regs_cs4382 { - u32 mode_control_1; - u32 mode_control_2; - u32 mode_control_3; - - u32 filter_control; - u32 invert_control; - - u32 mix_control_P1; - u32 vol_control_A1; - u32 vol_control_B1; - - u32 mix_control_P2; - u32 vol_control_A2; - u32 vol_control_B2; - - u32 mix_control_P3; - u32 vol_control_A3; - u32 vol_control_B3; - - u32 mix_control_P4; - u32 vol_control_A4; - u32 vol_control_B4; -}; - -static int hw20k2_i2c_unlock_full_access(struct hw *hw) -{ - u8 UnlockKeySequence_FLASH_FULLACCESS_MODE[2] = {0xB3, 0xD4}; - - /* Send keys for forced BIOS mode */ - hw_write_20kx(hw, I2C_IF_WLOCK, - UnlockKeySequence_FLASH_FULLACCESS_MODE[0]); - hw_write_20kx(hw, I2C_IF_WLOCK, - UnlockKeySequence_FLASH_FULLACCESS_MODE[1]); - /* Check whether the chip is unlocked */ - if (hw_read_20kx(hw, I2C_IF_WLOCK) == STATE_UNLOCKED) - return 0; - - return -1; -} - -static int hw20k2_i2c_lock_chip(struct hw *hw) -{ - /* Write twice */ - hw_write_20kx(hw, I2C_IF_WLOCK, STATE_LOCKED); - hw_write_20kx(hw, I2C_IF_WLOCK, STATE_LOCKED); - if (hw_read_20kx(hw, I2C_IF_WLOCK) == STATE_LOCKED) - return 0; - - return -1; -} - -static int hw20k2_i2c_init(struct hw *hw, u8 dev_id, u8 addr_size, u8 data_size) -{ - struct hw20k2 *hw20k2 = (struct hw20k2 *)hw; - int err; - unsigned int i2c_status; - unsigned int i2c_addr; - - err = hw20k2_i2c_unlock_full_access(hw); - if (err < 0) - return err; - - hw20k2->addr_size = addr_size; - hw20k2->data_size = data_size; - hw20k2->dev_id = dev_id; - - i2c_addr = 0; - set_field(&i2c_addr, I2C_ADDRESS_SLAD, dev_id); - - hw_write_20kx(hw, I2C_IF_ADDRESS, i2c_addr); - - i2c_status = hw_read_20kx(hw, I2C_IF_STATUS); - - set_field(&i2c_status, I2C_STATUS_DCM, 1); /* Direct control mode */ - - hw_write_20kx(hw, I2C_IF_STATUS, i2c_status); - - return 0; -} - -static int hw20k2_i2c_uninit(struct hw *hw) -{ - unsigned int i2c_status; - unsigned int i2c_addr; - - i2c_addr = 0; - set_field(&i2c_addr, I2C_ADDRESS_SLAD, 0x57); /* I2C id */ - - hw_write_20kx(hw, I2C_IF_ADDRESS, i2c_addr); - - i2c_status = hw_read_20kx(hw, I2C_IF_STATUS); - - set_field(&i2c_status, I2C_STATUS_DCM, 0); /* I2C mode */ - - hw_write_20kx(hw, I2C_IF_STATUS, i2c_status); - - return hw20k2_i2c_lock_chip(hw); -} - -static int hw20k2_i2c_wait_data_ready(struct hw *hw) -{ - int i = 0x400000; - unsigned int ret; - - do { - ret = hw_read_20kx(hw, I2C_IF_STATUS); - } while ((!(ret & DATA_READY)) && --i); - - return i; -} - -static int hw20k2_i2c_read(struct hw *hw, u16 addr, u32 *datap) -{ - struct hw20k2 *hw20k2 = (struct hw20k2 *)hw; - unsigned int i2c_status; - - i2c_status = hw_read_20kx(hw, I2C_IF_STATUS); - set_field(&i2c_status, I2C_STATUS_BC, - (4 == hw20k2->addr_size) ? 0 : hw20k2->addr_size); - hw_write_20kx(hw, I2C_IF_STATUS, i2c_status); - if (!hw20k2_i2c_wait_data_ready(hw)) - return -1; - - hw_write_20kx(hw, I2C_IF_WDATA, addr); - if (!hw20k2_i2c_wait_data_ready(hw)) - return -1; - - /* Force a read operation */ - hw_write_20kx(hw, I2C_IF_RDATA, 0); - if (!hw20k2_i2c_wait_data_ready(hw)) - return -1; - - *datap = hw_read_20kx(hw, I2C_IF_RDATA); - - return 0; -} - -static int hw20k2_i2c_write(struct hw *hw, u16 addr, u32 data) -{ - struct hw20k2 *hw20k2 = (struct hw20k2 *)hw; - unsigned int i2c_data = (data << (hw20k2->addr_size * 8)) | addr; - unsigned int i2c_status; - - i2c_status = hw_read_20kx(hw, I2C_IF_STATUS); - - set_field(&i2c_status, I2C_STATUS_BC, - (4 == (hw20k2->addr_size + hw20k2->data_size)) ? - 0 : (hw20k2->addr_size + hw20k2->data_size)); - - hw_write_20kx(hw, I2C_IF_STATUS, i2c_status); - hw20k2_i2c_wait_data_ready(hw); - /* Dummy write to trigger the write oprtation */ - hw_write_20kx(hw, I2C_IF_WDATA, 0); - hw20k2_i2c_wait_data_ready(hw); - - /* This is the real data */ - hw_write_20kx(hw, I2C_IF_WDATA, i2c_data); - hw20k2_i2c_wait_data_ready(hw); - - return 0; -} - -static int hw_dac_init(struct hw *hw, const struct dac_conf *info) -{ - int err; - u32 data; - int i; - struct regs_cs4382 cs_read = {0}; - struct regs_cs4382 cs_def = { - 0x00000001, /* Mode Control 1 */ - 0x00000000, /* Mode Control 2 */ - 0x00000084, /* Mode Control 3 */ - 0x00000000, /* Filter Control */ - 0x00000000, /* Invert Control */ - 0x00000024, /* Mixing Control Pair 1 */ - 0x00000000, /* Vol Control A1 */ - 0x00000000, /* Vol Control B1 */ - 0x00000024, /* Mixing Control Pair 2 */ - 0x00000000, /* Vol Control A2 */ - 0x00000000, /* Vol Control B2 */ - 0x00000024, /* Mixing Control Pair 3 */ - 0x00000000, /* Vol Control A3 */ - 0x00000000, /* Vol Control B3 */ - 0x00000024, /* Mixing Control Pair 4 */ - 0x00000000, /* Vol Control A4 */ - 0x00000000 /* Vol Control B4 */ - }; - - /* Set DAC reset bit as output */ - data = hw_read_20kx(hw, GPIO_CTRL); - data |= 0x02; - hw_write_20kx(hw, GPIO_CTRL, data); - - err = hw20k2_i2c_init(hw, 0x18, 1, 1); - if (err < 0) - goto End; - - for (i = 0; i < 2; i++) { - /* Reset DAC twice just in-case the chip - * didn't initialized properly */ - data = hw_read_20kx(hw, GPIO_DATA); - /* GPIO data bit 1 */ - data &= 0xFFFFFFFD; - hw_write_20kx(hw, GPIO_DATA, data); - mdelay(10); - data |= 0x2; - hw_write_20kx(hw, GPIO_DATA, data); - mdelay(50); - - /* Reset the 2nd time */ - data &= 0xFFFFFFFD; - hw_write_20kx(hw, GPIO_DATA, data); - mdelay(10); - data |= 0x2; - hw_write_20kx(hw, GPIO_DATA, data); - mdelay(50); - - if (hw20k2_i2c_read(hw, CS4382_MC1, &cs_read.mode_control_1)) - continue; - - if (hw20k2_i2c_read(hw, CS4382_MC2, &cs_read.mode_control_2)) - continue; - - if (hw20k2_i2c_read(hw, CS4382_MC3, &cs_read.mode_control_3)) - continue; - - if (hw20k2_i2c_read(hw, CS4382_FC, &cs_read.filter_control)) - continue; - - if (hw20k2_i2c_read(hw, CS4382_IC, &cs_read.invert_control)) - continue; - - if (hw20k2_i2c_read(hw, CS4382_XC1, &cs_read.mix_control_P1)) - continue; - - if (hw20k2_i2c_read(hw, CS4382_VCA1, &cs_read.vol_control_A1)) - continue; - - if (hw20k2_i2c_read(hw, CS4382_VCB1, &cs_read.vol_control_B1)) - continue; - - if (hw20k2_i2c_read(hw, CS4382_XC2, &cs_read.mix_control_P2)) - continue; - - if (hw20k2_i2c_read(hw, CS4382_VCA2, &cs_read.vol_control_A2)) - continue; - - if (hw20k2_i2c_read(hw, CS4382_VCB2, &cs_read.vol_control_B2)) - continue; - - if (hw20k2_i2c_read(hw, CS4382_XC3, &cs_read.mix_control_P3)) - continue; - - if (hw20k2_i2c_read(hw, CS4382_VCA3, &cs_read.vol_control_A3)) - continue; - - if (hw20k2_i2c_read(hw, CS4382_VCB3, &cs_read.vol_control_B3)) - continue; - - if (hw20k2_i2c_read(hw, CS4382_XC4, &cs_read.mix_control_P4)) - continue; - - if (hw20k2_i2c_read(hw, CS4382_VCA4, &cs_read.vol_control_A4)) - continue; - - if (hw20k2_i2c_read(hw, CS4382_VCB4, &cs_read.vol_control_B4)) - continue; - - if (memcmp(&cs_read, &cs_def, sizeof(cs_read))) - continue; - else - break; - } - - if (i >= 2) - goto End; - - /* Note: Every I2C write must have some delay. - * This is not a requirement but the delay works here... */ - hw20k2_i2c_write(hw, CS4382_MC1, 0x80); - hw20k2_i2c_write(hw, CS4382_MC2, 0x10); - if (1 == info->msr) { - hw20k2_i2c_write(hw, CS4382_XC1, 0x24); - hw20k2_i2c_write(hw, CS4382_XC2, 0x24); - hw20k2_i2c_write(hw, CS4382_XC3, 0x24); - hw20k2_i2c_write(hw, CS4382_XC4, 0x24); - } else if (2 == info->msr) { - hw20k2_i2c_write(hw, CS4382_XC1, 0x25); - hw20k2_i2c_write(hw, CS4382_XC2, 0x25); - hw20k2_i2c_write(hw, CS4382_XC3, 0x25); - hw20k2_i2c_write(hw, CS4382_XC4, 0x25); - } else { - hw20k2_i2c_write(hw, CS4382_XC1, 0x26); - hw20k2_i2c_write(hw, CS4382_XC2, 0x26); - hw20k2_i2c_write(hw, CS4382_XC3, 0x26); - hw20k2_i2c_write(hw, CS4382_XC4, 0x26); - } - - return 0; -End: - - hw20k2_i2c_uninit(hw); - return -1; -} - -/* ADC operations */ -#define MAKE_WM8775_ADDR(addr, data) (u32)(((addr<<1)&0xFE)|((data>>8)&0x1)) -#define MAKE_WM8775_DATA(data) (u32)(data&0xFF) - -#define WM8775_IC 0x0B -#define WM8775_MMC 0x0C -#define WM8775_AADCL 0x0E -#define WM8775_AADCR 0x0F -#define WM8775_ADCMC 0x15 -#define WM8775_RESET 0x17 - -static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type) -{ - u32 data; - - data = hw_read_20kx(hw, GPIO_DATA); - switch (type) { - case ADC_MICIN: - data = (data & (0x1 << 14)) ? 1 : 0; - break; - case ADC_LINEIN: - data = (data & (0x1 << 14)) ? 0 : 1; - break; - default: - data = 0; - } - return data; -} - -static int hw_adc_input_select(struct hw *hw, enum ADCSRC type) -{ - u32 data; - - data = hw_read_20kx(hw, GPIO_DATA); - switch (type) { - case ADC_MICIN: - data |= (0x1 << 14); - hw_write_20kx(hw, GPIO_DATA, data); - hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101), - MAKE_WM8775_DATA(0x101)); /* Mic-in */ - hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xE7), - MAKE_WM8775_DATA(0xE7)); /* +12dB boost */ - hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xE7), - MAKE_WM8775_DATA(0xE7)); /* +12dB boost */ - break; - case ADC_LINEIN: - data &= ~(0x1 << 14); - hw_write_20kx(hw, GPIO_DATA, data); - hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102), - MAKE_WM8775_DATA(0x102)); /* Line-in */ - hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF), - MAKE_WM8775_DATA(0xCF)); /* No boost */ - hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF), - MAKE_WM8775_DATA(0xCF)); /* No boost */ - break; - default: - break; - } - - return 0; -} - -static int hw_adc_init(struct hw *hw, const struct adc_conf *info) -{ - int err; - u32 mux = 2, data, ctl; - - /* Set ADC reset bit as output */ - data = hw_read_20kx(hw, GPIO_CTRL); - data |= (0x1 << 15); - hw_write_20kx(hw, GPIO_CTRL, data); - - /* Initialize I2C */ - err = hw20k2_i2c_init(hw, 0x1A, 1, 1); - if (err < 0) { - printk(KERN_ALERT "ctxfi: Failure to acquire I2C!!!\n"); - goto error; - } - - /* Make ADC in normal operation */ - data = hw_read_20kx(hw, GPIO_DATA); - data &= ~(0x1 << 15); - mdelay(10); - data |= (0x1 << 15); - hw_write_20kx(hw, GPIO_DATA, data); - mdelay(50); - - /* Set the master mode (256fs) */ - if (1 == info->msr) { - hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x02), - MAKE_WM8775_DATA(0x02)); - } else if (2 == info->msr) { - hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x0A), - MAKE_WM8775_DATA(0x0A)); - } else { - printk(KERN_ALERT "ctxfi: Invalid master sampling " - "rate (msr %d)!!!\n", info->msr); - err = -EINVAL; - goto error; - } - - /* Configure GPIO bit 14 change to line-in/mic-in */ - ctl = hw_read_20kx(hw, GPIO_CTRL); - ctl |= 0x1 << 14; - hw_write_20kx(hw, GPIO_CTRL, ctl); - - /* Check using Mic-in or Line-in */ - data = hw_read_20kx(hw, GPIO_DATA); - - if (mux == 1) { - /* Configures GPIO data to select Mic-in */ - data |= 0x1 << 14; - hw_write_20kx(hw, GPIO_DATA, data); - - hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101), - MAKE_WM8775_DATA(0x101)); /* Mic-in */ - hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xE7), - MAKE_WM8775_DATA(0xE7)); /* +12dB boost */ - hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xE7), - MAKE_WM8775_DATA(0xE7)); /* +12dB boost */ - } else if (mux == 2) { - /* Configures GPIO data to select Line-in */ - data &= ~(0x1 << 14); - hw_write_20kx(hw, GPIO_DATA, data); - - /* Setup ADC */ - hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102), - MAKE_WM8775_DATA(0x102)); /* Line-in */ - hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF), - MAKE_WM8775_DATA(0xCF)); /* No boost */ - hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF), - MAKE_WM8775_DATA(0xCF)); /* No boost */ - } else { - printk(KERN_ALERT "ctxfi: ERROR!!! Invalid input mux!!!\n"); - err = -EINVAL; - goto error; - } - - return 0; - -error: - hw20k2_i2c_uninit(hw); - return err; -} - -static int hw_have_digit_io_switch(struct hw *hw) -{ - return 0; -} - -static int hw_card_start(struct hw *hw) -{ - int err = 0; - struct pci_dev *pci = hw->pci; - unsigned int gctl; - - err = pci_enable_device(pci); - if (err < 0) - return err; - - /* Set DMA transfer mask */ - if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 || - pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) { - printk(KERN_ERR "ctxfi: architecture does not support PCI " - "busmaster DMA with mask 0x%llx\n", CT_XFI_DMA_MASK); - err = -ENXIO; - goto error1; - } - - if (!hw->io_base) { - err = pci_request_regions(pci, "XFi"); - if (err < 0) - goto error1; - - hw->io_base = pci_resource_start(hw->pci, 2); - hw->mem_base = (unsigned long)ioremap(hw->io_base, - pci_resource_len(hw->pci, 2)); - if (NULL == (void *)hw->mem_base) { - err = -ENOENT; - goto error2; - } - } - - /* Switch to 20k2 mode from UAA mode. */ - gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL); - set_field(&gctl, GCTL_UAA, 0); - hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl); - - /*if ((err = request_irq(pci->irq, ct_atc_interrupt, IRQF_SHARED, - atc->chip_details->nm_card, hw))) { - goto error3; - } - hw->irq = pci->irq; - */ - - pci_set_master(pci); - - return 0; - -/*error3: - iounmap((void *)hw->mem_base); - hw->mem_base = (unsigned long)NULL;*/ -error2: - pci_release_regions(pci); - hw->io_base = 0; -error1: - pci_disable_device(pci); - return err; -} - -static int hw_card_stop(struct hw *hw) -{ - unsigned int data; - - /* disable transport bus master and queueing of request */ - hw_write_20kx(hw, TRANSPORT_CTL, 0x00); - - /* disable pll */ - data = hw_read_20kx(hw, PLL_ENB); - hw_write_20kx(hw, PLL_ENB, (data & (~0x07))); - - /* TODO: Disable interrupt and so on... */ - return 0; -} - -static int hw_card_shutdown(struct hw *hw) -{ - if (hw->irq >= 0) - free_irq(hw->irq, hw); - - hw->irq = -1; - - if (NULL != ((void *)hw->mem_base)) - iounmap((void *)hw->mem_base); - - hw->mem_base = (unsigned long)NULL; - - if (hw->io_base) - pci_release_regions(hw->pci); - - hw->io_base = 0; - - pci_disable_device(hw->pci); - - return 0; -} - -static int hw_card_init(struct hw *hw, struct card_conf *info) -{ - int err; - unsigned int gctl; - u32 data = 0; - struct dac_conf dac_info = {0}; - struct adc_conf adc_info = {0}; - struct daio_conf daio_info = {0}; - struct trn_conf trn_info = {0}; - - /* Get PCI io port/memory base address and - * do 20kx core switch if needed. */ - err = hw_card_start(hw); - if (err) - return err; - - /* PLL init */ - err = hw_pll_init(hw, info->rsr); - if (err < 0) - return err; - - /* kick off auto-init */ - err = hw_auto_init(hw); - if (err < 0) - return err; - - gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL); - set_field(&gctl, GCTL_DBP, 1); - set_field(&gctl, GCTL_TBP, 1); - set_field(&gctl, GCTL_FBP, 1); - set_field(&gctl, GCTL_DPC, 0); - hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl); - - /* Reset all global pending interrupts */ - hw_write_20kx(hw, INTERRUPT_GIE, 0); - /* Reset all SRC pending interrupts */ - hw_write_20kx(hw, SRC_IP, 0); - - /* TODO: detect the card ID and configure GPIO accordingly. */ - /* Configures GPIO (0xD802 0x98028) */ - /*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/ - /* Configures GPIO (SB0880) */ - /*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/ - hw_write_20kx(hw, GPIO_CTRL, 0xD802); - - /* Enable audio ring */ - hw_write_20kx(hw, MIXER_AR_ENABLE, 0x01); - - trn_info.vm_pgt_phys = info->vm_pgt_phys; - err = hw_trn_init(hw, &trn_info); - if (err < 0) - return err; - - daio_info.msr = info->msr; - err = hw_daio_init(hw, &daio_info); - if (err < 0) - return err; - - dac_info.msr = info->msr; - err = hw_dac_init(hw, &dac_info); - if (err < 0) - return err; - - adc_info.msr = info->msr; - adc_info.input = ADC_LINEIN; - adc_info.mic20db = 0; - err = hw_adc_init(hw, &adc_info); - if (err < 0) - return err; - - data = hw_read_20kx(hw, SRC_MCTL); - data |= 0x1; /* Enables input from the audio ring */ - hw_write_20kx(hw, SRC_MCTL, data); - - return 0; -} - -#ifdef CONFIG_PM -static int hw_suspend(struct hw *hw, pm_message_t state) -{ - struct pci_dev *pci = hw->pci; - - hw_card_stop(hw); - - pci_disable_device(pci); - pci_save_state(pci); - pci_set_power_state(pci, pci_choose_state(pci, state)); - - return 0; -} - -static int hw_resume(struct hw *hw, struct card_conf *info) -{ - struct pci_dev *pci = hw->pci; - - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); - - /* Re-initialize card hardware. */ - return hw_card_init(hw, info); -} -#endif - -static u32 hw_read_20kx(struct hw *hw, u32 reg) -{ - return readl((void *)(hw->mem_base + reg)); -} - -static void hw_write_20kx(struct hw *hw, u32 reg, u32 data) -{ - writel(data, (void *)(hw->mem_base + reg)); -} - -static struct hw ct20k2_preset __devinitdata = { - .irq = -1, - - .card_init = hw_card_init, - .card_stop = hw_card_stop, - .pll_init = hw_pll_init, - .is_adc_source_selected = hw_is_adc_input_selected, - .select_adc_source = hw_adc_input_select, - .have_digit_io_switch = hw_have_digit_io_switch, -#ifdef CONFIG_PM - .suspend = hw_suspend, - .resume = hw_resume, -#endif - - .src_rsc_get_ctrl_blk = src_get_rsc_ctrl_blk, - .src_rsc_put_ctrl_blk = src_put_rsc_ctrl_blk, - .src_mgr_get_ctrl_blk = src_mgr_get_ctrl_blk, - .src_mgr_put_ctrl_blk = src_mgr_put_ctrl_blk, - .src_set_state = src_set_state, - .src_set_bm = src_set_bm, - .src_set_rsr = src_set_rsr, - .src_set_sf = src_set_sf, - .src_set_wr = src_set_wr, - .src_set_pm = src_set_pm, - .src_set_rom = src_set_rom, - .src_set_vo = src_set_vo, - .src_set_st = src_set_st, - .src_set_ie = src_set_ie, - .src_set_ilsz = src_set_ilsz, - .src_set_bp = src_set_bp, - .src_set_cisz = src_set_cisz, - .src_set_ca = src_set_ca, - .src_set_sa = src_set_sa, - .src_set_la = src_set_la, - .src_set_pitch = src_set_pitch, - .src_set_dirty = src_set_dirty, - .src_set_clear_zbufs = src_set_clear_zbufs, - .src_set_dirty_all = src_set_dirty_all, - .src_commit_write = src_commit_write, - .src_get_ca = src_get_ca, - .src_get_dirty = src_get_dirty, - .src_dirty_conj_mask = src_dirty_conj_mask, - .src_mgr_enbs_src = src_mgr_enbs_src, - .src_mgr_enb_src = src_mgr_enb_src, - .src_mgr_dsb_src = src_mgr_dsb_src, - .src_mgr_commit_write = src_mgr_commit_write, - - .srcimp_mgr_get_ctrl_blk = srcimp_mgr_get_ctrl_blk, - .srcimp_mgr_put_ctrl_blk = srcimp_mgr_put_ctrl_blk, - .srcimp_mgr_set_imaparc = srcimp_mgr_set_imaparc, - .srcimp_mgr_set_imapuser = srcimp_mgr_set_imapuser, - .srcimp_mgr_set_imapnxt = srcimp_mgr_set_imapnxt, - .srcimp_mgr_set_imapaddr = srcimp_mgr_set_imapaddr, - .srcimp_mgr_commit_write = srcimp_mgr_commit_write, - - .amixer_rsc_get_ctrl_blk = amixer_rsc_get_ctrl_blk, - .amixer_rsc_put_ctrl_blk = amixer_rsc_put_ctrl_blk, - .amixer_mgr_get_ctrl_blk = amixer_mgr_get_ctrl_blk, - .amixer_mgr_put_ctrl_blk = amixer_mgr_put_ctrl_blk, - .amixer_set_mode = amixer_set_mode, - .amixer_set_iv = amixer_set_iv, - .amixer_set_x = amixer_set_x, - .amixer_set_y = amixer_set_y, - .amixer_set_sadr = amixer_set_sadr, - .amixer_set_se = amixer_set_se, - .amixer_set_dirty = amixer_set_dirty, - .amixer_set_dirty_all = amixer_set_dirty_all, - .amixer_commit_write = amixer_commit_write, - .amixer_get_y = amixer_get_y, - .amixer_get_dirty = amixer_get_dirty, - - .dai_get_ctrl_blk = dai_get_ctrl_blk, - .dai_put_ctrl_blk = dai_put_ctrl_blk, - .dai_srt_set_srco = dai_srt_set_srco, - .dai_srt_set_srcm = dai_srt_set_srcm, - .dai_srt_set_rsr = dai_srt_set_rsr, - .dai_srt_set_drat = dai_srt_set_drat, - .dai_srt_set_ec = dai_srt_set_ec, - .dai_srt_set_et = dai_srt_set_et, - .dai_commit_write = dai_commit_write, - - .dao_get_ctrl_blk = dao_get_ctrl_blk, - .dao_put_ctrl_blk = dao_put_ctrl_blk, - .dao_set_spos = dao_set_spos, - .dao_commit_write = dao_commit_write, - .dao_get_spos = dao_get_spos, - - .daio_mgr_get_ctrl_blk = daio_mgr_get_ctrl_blk, - .daio_mgr_put_ctrl_blk = daio_mgr_put_ctrl_blk, - .daio_mgr_enb_dai = daio_mgr_enb_dai, - .daio_mgr_dsb_dai = daio_mgr_dsb_dai, - .daio_mgr_enb_dao = daio_mgr_enb_dao, - .daio_mgr_dsb_dao = daio_mgr_dsb_dao, - .daio_mgr_dao_init = daio_mgr_dao_init, - .daio_mgr_set_imaparc = daio_mgr_set_imaparc, - .daio_mgr_set_imapnxt = daio_mgr_set_imapnxt, - .daio_mgr_set_imapaddr = daio_mgr_set_imapaddr, - .daio_mgr_commit_write = daio_mgr_commit_write, -}; - -int __devinit create_20k2_hw_obj(struct hw **rhw) -{ - struct hw20k2 *hw20k2; - - *rhw = NULL; - hw20k2 = kzalloc(sizeof(*hw20k2), GFP_KERNEL); - if (!hw20k2) - return -ENOMEM; - - hw20k2->hw = ct20k2_preset; - *rhw = &hw20k2->hw; - - return 0; -} - -int destroy_20k2_hw_obj(struct hw *hw) -{ - if (hw->io_base) - hw_card_shutdown(hw); - - kfree(hw); - return 0; -} diff --git a/trunk/sound/pci/ctxfi/cthw20k2.h b/trunk/sound/pci/ctxfi/cthw20k2.h deleted file mode 100644 index d2b7daab6815..000000000000 --- a/trunk/sound/pci/ctxfi/cthw20k2.h +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. - * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - * - * @File cthw20k2.h - * - * @Brief - * This file contains the definition of hardware access methord. - * - * @Author Liu Chun - * @Date May 13 2008 - * - */ - -#ifndef CTHW20K2_H -#define CTHW20K2_H - -#include "cthardware.h" - -int create_20k2_hw_obj(struct hw **rhw); -int destroy_20k2_hw_obj(struct hw *hw); - -#endif /* CTHW20K2_H */ diff --git a/trunk/sound/pci/ctxfi/ctimap.c b/trunk/sound/pci/ctxfi/ctimap.c deleted file mode 100644 index 0b73368a4df6..000000000000 --- a/trunk/sound/pci/ctxfi/ctimap.c +++ /dev/null @@ -1,112 +0,0 @@ -/** - * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. - * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - * - * @File ctimap.c - * - * @Brief - * This file contains the implementation of generic input mapper operations - * for input mapper management. - * - * @Author Liu Chun - * @Date May 23 2008 - * - */ - -#include "ctimap.h" -#include - -int input_mapper_add(struct list_head *mappers, struct imapper *entry, - int (*map_op)(void *, struct imapper *), void *data) -{ - struct list_head *pos, *pre, *head; - struct imapper *pre_ent, *pos_ent; - - head = mappers; - - if (list_empty(head)) { - entry->next = entry->addr; - map_op(data, entry); - list_add(&entry->list, head); - return 0; - } - - list_for_each(pos, head) { - pos_ent = list_entry(pos, struct imapper, list); - if (pos_ent->slot > entry->slot) { - /* found a position in list */ - break; - } - } - - if (pos != head) { - pre = pos->prev; - if (pre == head) - pre = head->prev; - - __list_add(&entry->list, pos->prev, pos); - } else { - pre = head->prev; - pos = head->next; - list_add_tail(&entry->list, head); - } - - pre_ent = list_entry(pre, struct imapper, list); - pos_ent = list_entry(pos, struct imapper, list); - - entry->next = pos_ent->addr; - map_op(data, entry); - pre_ent->next = entry->addr; - map_op(data, pre_ent); - - return 0; -} - -int input_mapper_delete(struct list_head *mappers, struct imapper *entry, - int (*map_op)(void *, struct imapper *), void *data) -{ - struct list_head *next, *pre, *head; - struct imapper *pre_ent, *next_ent; - - head = mappers; - - if (list_empty(head)) - return 0; - - pre = (entry->list.prev == head) ? head->prev : entry->list.prev; - next = (entry->list.next == head) ? head->next : entry->list.next; - - if (pre == &entry->list) { - /* entry is the only one node in mappers list */ - entry->next = entry->addr = entry->user = entry->slot = 0; - map_op(data, entry); - list_del(&entry->list); - return 0; - } - - pre_ent = list_entry(pre, struct imapper, list); - next_ent = list_entry(next, struct imapper, list); - - pre_ent->next = next_ent->addr; - map_op(data, pre_ent); - list_del(&entry->list); - - return 0; -} - -void free_input_mapper_list(struct list_head *head) -{ - struct imapper *entry; - struct list_head *pos; - - while (!list_empty(head)) { - pos = head->next; - list_del(pos); - entry = list_entry(pos, struct imapper, list); - kfree(entry); - } -} - diff --git a/trunk/sound/pci/ctxfi/ctimap.h b/trunk/sound/pci/ctxfi/ctimap.h deleted file mode 100644 index 53ccf9be8b68..000000000000 --- a/trunk/sound/pci/ctxfi/ctimap.h +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. - * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - * - * @File ctimap.h - * - * @Brief - * This file contains the definition of generic input mapper operations - * for input mapper management. - * - * @Author Liu Chun - * @Date May 23 2008 - * - */ - -#ifndef CTIMAP_H -#define CTIMAP_H - -#include - -struct imapper { - unsigned short slot; /* the id of the slot containing input data */ - unsigned short user; /* the id of the user resource consuming data */ - unsigned short addr; /* the input mapper ram id */ - unsigned short next; /* the next input mapper ram id */ - struct list_head list; -}; - -int input_mapper_add(struct list_head *mappers, struct imapper *entry, - int (*map_op)(void *, struct imapper *), void *data); - -int input_mapper_delete(struct list_head *mappers, struct imapper *entry, - int (*map_op)(void *, struct imapper *), void *data); - -void free_input_mapper_list(struct list_head *mappers); - -#endif /* CTIMAP_H */ diff --git a/trunk/sound/pci/ctxfi/ctmixer.c b/trunk/sound/pci/ctxfi/ctmixer.c deleted file mode 100644 index f26d7cd9db9f..000000000000 --- a/trunk/sound/pci/ctxfi/ctmixer.c +++ /dev/null @@ -1,1157 +0,0 @@ -/** - * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. - * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - * - * @File ctmixer.c - * - * @Brief - * This file contains the implementation of alsa mixer device functions. - * - * @Author Liu Chun - * @Date May 28 2008 - * - */ - - -#include "ctmixer.h" -#include "ctamixer.h" -#include -#include -#include -#include -#include -#include - -enum CT_SUM_CTL { - SUM_IN_F, - SUM_IN_R, - SUM_IN_C, - SUM_IN_S, - SUM_IN_F_C, - - NUM_CT_SUMS -}; - -enum CT_AMIXER_CTL { - /* volume control mixers */ - AMIXER_MASTER_F, - AMIXER_MASTER_R, - AMIXER_MASTER_C, - AMIXER_MASTER_S, - AMIXER_PCM_F, - AMIXER_PCM_R, - AMIXER_PCM_C, - AMIXER_PCM_S, - AMIXER_SPDIFI, - AMIXER_LINEIN, - AMIXER_MIC, - AMIXER_SPDIFO, - AMIXER_WAVE_F, - AMIXER_WAVE_R, - AMIXER_WAVE_C, - AMIXER_WAVE_S, - AMIXER_MASTER_F_C, - AMIXER_PCM_F_C, - AMIXER_SPDIFI_C, - AMIXER_LINEIN_C, - AMIXER_MIC_C, - - /* this should always be the last one */ - NUM_CT_AMIXERS -}; - -enum CTALSA_MIXER_CTL { - /* volume control mixers */ - MIXER_MASTER_P, - MIXER_PCM_P, - MIXER_LINEIN_P, - MIXER_MIC_P, - MIXER_SPDIFI_P, - MIXER_SPDIFO_P, - MIXER_WAVEF_P, - MIXER_WAVER_P, - MIXER_WAVEC_P, - MIXER_WAVES_P, - MIXER_MASTER_C, - MIXER_PCM_C, - MIXER_LINEIN_C, - MIXER_MIC_C, - MIXER_SPDIFI_C, - - /* switch control mixers */ - MIXER_PCM_C_S, - MIXER_LINEIN_C_S, - MIXER_MIC_C_S, - MIXER_SPDIFI_C_S, - MIXER_LINEIN_P_S, - MIXER_SPDIFO_P_S, - MIXER_SPDIFI_P_S, - MIXER_WAVEF_P_S, - MIXER_WAVER_P_S, - MIXER_WAVEC_P_S, - MIXER_WAVES_P_S, - MIXER_DIGITAL_IO_S, - MIXER_IEC958_MASK, - MIXER_IEC958_DEFAULT, - MIXER_IEC958_STREAM, - - /* this should always be the last one */ - NUM_CTALSA_MIXERS -}; - -#define VOL_MIXER_START MIXER_MASTER_P -#define VOL_MIXER_END MIXER_SPDIFI_C -#define VOL_MIXER_NUM (VOL_MIXER_END - VOL_MIXER_START + 1) -#define SWH_MIXER_START MIXER_PCM_C_S -#define SWH_MIXER_END MIXER_DIGITAL_IO_S -#define SWH_CAPTURE_START MIXER_PCM_C_S -#define SWH_CAPTURE_END MIXER_SPDIFI_C_S - -#define CHN_NUM 2 - -struct ct_kcontrol_init { - unsigned char ctl; - char *name; -}; - -static struct ct_kcontrol_init -ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = { - [MIXER_MASTER_P] = { - .ctl = 1, - .name = "Master Playback Volume", - }, - [MIXER_MASTER_C] = { - .ctl = 1, - .name = "Master Capture Volume", - }, - [MIXER_PCM_P] = { - .ctl = 1, - .name = "PCM Playback Volume", - }, - [MIXER_PCM_C] = { - .ctl = 1, - .name = "PCM Capture Volume", - }, - [MIXER_LINEIN_P] = { - .ctl = 1, - .name = "Line-in Playback Volume", - }, - [MIXER_LINEIN_C] = { - .ctl = 1, - .name = "Line-in Capture Volume", - }, - [MIXER_MIC_P] = { - .ctl = 1, - .name = "Mic Playback Volume", - }, - [MIXER_MIC_C] = { - .ctl = 1, - .name = "Mic Capture Volume", - }, - [MIXER_SPDIFI_P] = { - .ctl = 1, - .name = "S/PDIF-in Playback Volume", - }, - [MIXER_SPDIFI_C] = { - .ctl = 1, - .name = "S/PDIF-in Capture Volume", - }, - [MIXER_SPDIFO_P] = { - .ctl = 1, - .name = "S/PDIF-out Playback Volume", - }, - [MIXER_WAVEF_P] = { - .ctl = 1, - .name = "Front Playback Volume", - }, - [MIXER_WAVES_P] = { - .ctl = 1, - .name = "Side Playback Volume", - }, - [MIXER_WAVEC_P] = { - .ctl = 1, - .name = "Center/LFE Playback Volume", - }, - [MIXER_WAVER_P] = { - .ctl = 1, - .name = "Surround Playback Volume", - }, - - [MIXER_PCM_C_S] = { - .ctl = 1, - .name = "PCM Capture Switch", - }, - [MIXER_LINEIN_C_S] = { - .ctl = 1, - .name = "Line-in Capture Switch", - }, - [MIXER_MIC_C_S] = { - .ctl = 1, - .name = "Mic Capture Switch", - }, - [MIXER_SPDIFI_C_S] = { - .ctl = 1, - .name = "S/PDIF-in Capture Switch", - }, - [MIXER_LINEIN_P_S] = { - .ctl = 1, - .name = "Line-in Playback Switch", - }, - [MIXER_SPDIFO_P_S] = { - .ctl = 1, - .name = "S/PDIF-out Playback Switch", - }, - [MIXER_SPDIFI_P_S] = { - .ctl = 1, - .name = "S/PDIF-in Playback Switch", - }, - [MIXER_WAVEF_P_S] = { - .ctl = 1, - .name = "Front Playback Switch", - }, - [MIXER_WAVES_P_S] = { - .ctl = 1, - .name = "Side Playback Switch", - }, - [MIXER_WAVEC_P_S] = { - .ctl = 1, - .name = "Center/LFE Playback Switch", - }, - [MIXER_WAVER_P_S] = { - .ctl = 1, - .name = "Surround Playback Switch", - }, - [MIXER_DIGITAL_IO_S] = { - .ctl = 0, - .name = "Digit-IO Playback Switch", - }, -}; - -static void -ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type); - -static void -ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type); - -static struct snd_kcontrol *kctls[2] = {NULL}; - -static enum CT_AMIXER_CTL get_amixer_index(enum CTALSA_MIXER_CTL alsa_index) -{ - switch (alsa_index) { - case MIXER_MASTER_P: return AMIXER_MASTER_F; - case MIXER_MASTER_C: return AMIXER_MASTER_F_C; - case MIXER_PCM_P: return AMIXER_PCM_F; - case MIXER_PCM_C: - case MIXER_PCM_C_S: return AMIXER_PCM_F_C; - case MIXER_LINEIN_P: return AMIXER_LINEIN; - case MIXER_LINEIN_C: - case MIXER_LINEIN_C_S: return AMIXER_LINEIN_C; - case MIXER_MIC_P: return AMIXER_MIC; - case MIXER_MIC_C: - case MIXER_MIC_C_S: return AMIXER_MIC_C; - case MIXER_SPDIFI_P: return AMIXER_SPDIFI; - case MIXER_SPDIFI_C: - case MIXER_SPDIFI_C_S: return AMIXER_SPDIFI_C; - case MIXER_SPDIFO_P: return AMIXER_SPDIFO; - case MIXER_WAVEF_P: return AMIXER_WAVE_F; - case MIXER_WAVES_P: return AMIXER_WAVE_S; - case MIXER_WAVEC_P: return AMIXER_WAVE_C; - case MIXER_WAVER_P: return AMIXER_WAVE_R; - default: return NUM_CT_AMIXERS; - } -} - -static enum CT_AMIXER_CTL get_recording_amixer(enum CT_AMIXER_CTL index) -{ - switch (index) { - case AMIXER_MASTER_F: return AMIXER_MASTER_F_C; - case AMIXER_PCM_F: return AMIXER_PCM_F_C; - case AMIXER_SPDIFI: return AMIXER_SPDIFI_C; - case AMIXER_LINEIN: return AMIXER_LINEIN_C; - case AMIXER_MIC: return AMIXER_MIC_C; - default: return NUM_CT_AMIXERS; - } -} - -static unsigned char -get_switch_state(struct ct_mixer *mixer, enum CTALSA_MIXER_CTL type) -{ - return (mixer->switch_state & (0x1 << (type - SWH_MIXER_START))) - ? 1 : 0; -} - -static void -set_switch_state(struct ct_mixer *mixer, - enum CTALSA_MIXER_CTL type, unsigned char state) -{ - if (state) - mixer->switch_state |= (0x1 << (type - SWH_MIXER_START)); - else - mixer->switch_state &= ~(0x1 << (type - SWH_MIXER_START)); -} - -#if 0 /* not used */ -/* Map integer value ranging from 0 to 65535 to 14-bit float value ranging - * from 2^-6 to (1+1023/1024) */ -static unsigned int uint16_to_float14(unsigned int x) -{ - unsigned int i; - - if (x < 17) - return 0; - - x *= 2031; - x /= 65535; - x += 16; - - /* i <= 6 */ - for (i = 0; !(x & 0x400); i++) - x <<= 1; - - x = (((7 - i) & 0x7) << 10) | (x & 0x3ff); - - return x; -} - -static unsigned int float14_to_uint16(unsigned int x) -{ - unsigned int e; - - if (!x) - return x; - - e = (x >> 10) & 0x7; - x &= 0x3ff; - x += 1024; - x >>= (7 - e); - x -= 16; - x *= 65535; - x /= 2031; - - return x; -} -#endif /* not used */ - -#define VOL_SCALE 0x1c -#define VOL_MAX 0x100 - -static const DECLARE_TLV_DB_SCALE(ct_vol_db_scale, -6400, 25, 1); - -static int ct_alsa_mix_volume_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = VOL_MAX; - - return 0; -} - -static int ct_alsa_mix_volume_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct ct_atc *atc = snd_kcontrol_chip(kcontrol); - enum CT_AMIXER_CTL type = get_amixer_index(kcontrol->private_value); - struct amixer *amixer; - int i, val; - - for (i = 0; i < 2; i++) { - amixer = ((struct ct_mixer *)atc->mixer)-> - amixers[type*CHN_NUM+i]; - val = amixer->ops->get_scale(amixer) / VOL_SCALE; - if (val < 0) - val = 0; - else if (val > VOL_MAX) - val = VOL_MAX; - ucontrol->value.integer.value[i] = val; - } - - return 0; -} - -static int ct_alsa_mix_volume_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct ct_atc *atc = snd_kcontrol_chip(kcontrol); - struct ct_mixer *mixer = atc->mixer; - enum CT_AMIXER_CTL type = get_amixer_index(kcontrol->private_value); - struct amixer *amixer; - int i, j, val, oval, change = 0; - - for (i = 0; i < 2; i++) { - val = ucontrol->value.integer.value[i]; - if (val < 0) - val = 0; - else if (val > VOL_MAX) - val = VOL_MAX; - val *= VOL_SCALE; - amixer = mixer->amixers[type*CHN_NUM+i]; - oval = amixer->ops->get_scale(amixer); - if (val != oval) { - amixer->ops->set_scale(amixer, val); - amixer->ops->commit_write(amixer); - change = 1; - /* Synchronize Master/PCM playback AMIXERs. */ - if (AMIXER_MASTER_F == type || AMIXER_PCM_F == type) { - for (j = 1; j < 4; j++) { - amixer = mixer-> - amixers[(type+j)*CHN_NUM+i]; - amixer->ops->set_scale(amixer, val); - amixer->ops->commit_write(amixer); - } - } - } - } - - return change; -} - -static struct snd_kcontrol_new vol_ctl = { - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_TLV_READ, - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .info = ct_alsa_mix_volume_info, - .get = ct_alsa_mix_volume_get, - .put = ct_alsa_mix_volume_put, - .tlv = { .p = ct_vol_db_scale }, -}; - -static void -do_line_mic_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type) -{ - - if (MIXER_LINEIN_C_S == type) { - atc->select_line_in(atc); - set_switch_state(atc->mixer, MIXER_MIC_C_S, 0); - snd_ctl_notify(atc->card, SNDRV_CTL_EVENT_MASK_VALUE, - &kctls[1]->id); - } else if (MIXER_MIC_C_S == type) { - atc->select_mic_in(atc); - set_switch_state(atc->mixer, MIXER_LINEIN_C_S, 0); - snd_ctl_notify(atc->card, SNDRV_CTL_EVENT_MASK_VALUE, - &kctls[0]->id); - } -} - -static void -do_digit_io_switch(struct ct_atc *atc, int state) -{ - struct ct_mixer *mixer = atc->mixer; - - if (state) { - atc->select_digit_io(atc); - atc->spdif_out_unmute(atc, - get_switch_state(mixer, MIXER_SPDIFO_P_S)); - atc->spdif_in_unmute(atc, 1); - atc->line_in_unmute(atc, 0); - return; - } - - if (get_switch_state(mixer, MIXER_LINEIN_C_S)) - atc->select_line_in(atc); - else if (get_switch_state(mixer, MIXER_MIC_C_S)) - atc->select_mic_in(atc); - - atc->spdif_out_unmute(atc, 0); - atc->spdif_in_unmute(atc, 0); - atc->line_in_unmute(atc, 1); - return; -} - -static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state) -{ - struct ct_mixer *mixer = atc->mixer; - - /* Do changes in mixer. */ - if ((SWH_CAPTURE_START <= type) && (SWH_CAPTURE_END >= type)) { - if (state) { - ct_mixer_recording_select(mixer, - get_amixer_index(type)); - } else { - ct_mixer_recording_unselect(mixer, - get_amixer_index(type)); - } - } - /* Do changes out of mixer. */ - if (state && (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type)) - do_line_mic_switch(atc, type); - else if (MIXER_WAVEF_P_S == type) - atc->line_front_unmute(atc, state); - else if (MIXER_WAVES_P_S == type) - atc->line_surround_unmute(atc, state); - else if (MIXER_WAVEC_P_S == type) - atc->line_clfe_unmute(atc, state); - else if (MIXER_WAVER_P_S == type) - atc->line_rear_unmute(atc, state); - else if (MIXER_LINEIN_P_S == type) - atc->line_in_unmute(atc, state); - else if (MIXER_SPDIFO_P_S == type) - atc->spdif_out_unmute(atc, state); - else if (MIXER_SPDIFI_P_S == type) - atc->spdif_in_unmute(atc, state); - else if (MIXER_DIGITAL_IO_S == type) - do_digit_io_switch(atc, state); - - return; -} - -static int ct_alsa_mix_switch_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - uinfo->value.integer.step = 1; - - return 0; -} - -static int ct_alsa_mix_switch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct ct_mixer *mixer = - ((struct ct_atc *)snd_kcontrol_chip(kcontrol))->mixer; - enum CTALSA_MIXER_CTL type = kcontrol->private_value; - - ucontrol->value.integer.value[0] = get_switch_state(mixer, type); - return 0; -} - -static int ct_alsa_mix_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct ct_atc *atc = snd_kcontrol_chip(kcontrol); - struct ct_mixer *mixer = atc->mixer; - enum CTALSA_MIXER_CTL type = kcontrol->private_value; - int state; - - state = ucontrol->value.integer.value[0]; - if (get_switch_state(mixer, type) == state) - return 0; - - set_switch_state(mixer, type, state); - do_switch(atc, type, state); - - return 1; -} - -static struct snd_kcontrol_new swh_ctl = { - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .info = ct_alsa_mix_switch_info, - .get = ct_alsa_mix_switch_get, - .put = ct_alsa_mix_switch_put -}; - -static int ct_spdif_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; - uinfo->count = 1; - return 0; -} - -static int ct_spdif_get_mask(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.iec958.status[0] = 0xff; - ucontrol->value.iec958.status[1] = 0xff; - ucontrol->value.iec958.status[2] = 0xff; - ucontrol->value.iec958.status[3] = 0xff; - return 0; -} - -static int ct_spdif_default_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - unsigned int status = SNDRV_PCM_DEFAULT_CON_SPDIF; - - ucontrol->value.iec958.status[0] = (status >> 0) & 0xff; - ucontrol->value.iec958.status[1] = (status >> 8) & 0xff; - ucontrol->value.iec958.status[2] = (status >> 16) & 0xff; - ucontrol->value.iec958.status[3] = (status >> 24) & 0xff; - - return 0; -} - -static int ct_spdif_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct ct_atc *atc = snd_kcontrol_chip(kcontrol); - unsigned int status; - - atc->spdif_out_get_status(atc, &status); - ucontrol->value.iec958.status[0] = (status >> 0) & 0xff; - ucontrol->value.iec958.status[1] = (status >> 8) & 0xff; - ucontrol->value.iec958.status[2] = (status >> 16) & 0xff; - ucontrol->value.iec958.status[3] = (status >> 24) & 0xff; - - return 0; -} - -static int ct_spdif_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct ct_atc *atc = snd_kcontrol_chip(kcontrol); - int change; - unsigned int status, old_status; - - status = (ucontrol->value.iec958.status[0] << 0) | - (ucontrol->value.iec958.status[1] << 8) | - (ucontrol->value.iec958.status[2] << 16) | - (ucontrol->value.iec958.status[3] << 24); - - atc->spdif_out_get_status(atc, &old_status); - change = (old_status != status); - if (change) - atc->spdif_out_set_status(atc, status); - - return change; -} - -static struct snd_kcontrol_new iec958_mask_ctl = { - .access = SNDRV_CTL_ELEM_ACCESS_READ, - .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK), - .count = 1, - .info = ct_spdif_info, - .get = ct_spdif_get_mask, - .private_value = MIXER_IEC958_MASK -}; - -static struct snd_kcontrol_new iec958_default_ctl = { - .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), - .count = 1, - .info = ct_spdif_info, - .get = ct_spdif_default_get, - .put = ct_spdif_put, - .private_value = MIXER_IEC958_DEFAULT -}; - -static struct snd_kcontrol_new iec958_ctl = { - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM), - .count = 1, - .info = ct_spdif_info, - .get = ct_spdif_get, - .put = ct_spdif_put, - .private_value = MIXER_IEC958_STREAM -}; - -#define NUM_IEC958_CTL 3 - -static int -ct_mixer_kcontrol_new(struct ct_mixer *mixer, struct snd_kcontrol_new *new) -{ - struct snd_kcontrol *kctl; - int err; - - kctl = snd_ctl_new1(new, mixer->atc); - if (NULL == kctl) - return -ENOMEM; - - if (SNDRV_CTL_ELEM_IFACE_PCM == kctl->id.iface) - kctl->id.device = IEC958; - - err = snd_ctl_add(mixer->atc->card, kctl); - if (err) - return err; - - switch (new->private_value) { - case MIXER_LINEIN_C_S: - kctls[0] = kctl; break; - case MIXER_MIC_C_S: - kctls[1] = kctl; break; - default: - break; - } - - return 0; -} - -static int ct_mixer_kcontrols_create(struct ct_mixer *mixer) -{ - enum CTALSA_MIXER_CTL type; - struct ct_atc *atc = mixer->atc; - int err; - - /* Create snd kcontrol instances on demand */ - for (type = VOL_MIXER_START; type <= VOL_MIXER_END; type++) { - if (ct_kcontrol_init_table[type].ctl) { - vol_ctl.name = ct_kcontrol_init_table[type].name; - vol_ctl.private_value = (unsigned long)type; - err = ct_mixer_kcontrol_new(mixer, &vol_ctl); - if (err) - return err; - } - } - - ct_kcontrol_init_table[MIXER_DIGITAL_IO_S].ctl = - atc->have_digit_io_switch(atc); - for (type = SWH_MIXER_START; type <= SWH_MIXER_END; type++) { - if (ct_kcontrol_init_table[type].ctl) { - swh_ctl.name = ct_kcontrol_init_table[type].name; - swh_ctl.private_value = (unsigned long)type; - err = ct_mixer_kcontrol_new(mixer, &swh_ctl); - if (err) - return err; - } - } - - err = ct_mixer_kcontrol_new(mixer, &iec958_mask_ctl); - if (err) - return err; - - err = ct_mixer_kcontrol_new(mixer, &iec958_default_ctl); - if (err) - return err; - - err = ct_mixer_kcontrol_new(mixer, &iec958_ctl); - if (err) - return err; - - atc->line_front_unmute(atc, 1); - set_switch_state(mixer, MIXER_WAVEF_P_S, 1); - atc->line_surround_unmute(atc, 0); - set_switch_state(mixer, MIXER_WAVES_P_S, 0); - atc->line_clfe_unmute(atc, 0); - set_switch_state(mixer, MIXER_WAVEC_P_S, 0); - atc->line_rear_unmute(atc, 0); - set_switch_state(mixer, MIXER_WAVER_P_S, 0); - atc->spdif_out_unmute(atc, 0); - set_switch_state(mixer, MIXER_SPDIFO_P_S, 0); - atc->line_in_unmute(atc, 0); - set_switch_state(mixer, MIXER_LINEIN_P_S, 0); - atc->spdif_in_unmute(atc, 0); - set_switch_state(mixer, MIXER_SPDIFI_P_S, 0); - - set_switch_state(mixer, MIXER_PCM_C_S, 1); - set_switch_state(mixer, MIXER_LINEIN_C_S, 1); - set_switch_state(mixer, MIXER_SPDIFI_C_S, 1); - - return 0; -} - -static void -ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type) -{ - struct amixer *amix_d; - struct sum *sum_c; - int i; - - for (i = 0; i < 2; i++) { - amix_d = mixer->amixers[type*CHN_NUM+i]; - sum_c = mixer->sums[SUM_IN_F_C*CHN_NUM+i]; - amix_d->ops->set_sum(amix_d, sum_c); - amix_d->ops->commit_write(amix_d); - } -} - -static void -ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type) -{ - struct amixer *amix_d; - int i; - - for (i = 0; i < 2; i++) { - amix_d = mixer->amixers[type*CHN_NUM+i]; - amix_d->ops->set_sum(amix_d, NULL); - amix_d->ops->commit_write(amix_d); - } -} - -static int ct_mixer_get_resources(struct ct_mixer *mixer) -{ - struct sum_mgr *sum_mgr; - struct sum *sum; - struct sum_desc sum_desc = {0}; - struct amixer_mgr *amixer_mgr; - struct amixer *amixer; - struct amixer_desc am_desc = {0}; - int err; - int i; - - /* Allocate sum resources for mixer obj */ - sum_mgr = (struct sum_mgr *)mixer->atc->rsc_mgrs[SUM]; - sum_desc.msr = mixer->atc->msr; - for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) { - err = sum_mgr->get_sum(sum_mgr, &sum_desc, &sum); - if (err) { - printk(KERN_ERR "ctxfi:Failed to get sum resources for " - "front output!\n"); - break; - } - mixer->sums[i] = sum; - } - if (err) - goto error1; - - /* Allocate amixer resources for mixer obj */ - amixer_mgr = (struct amixer_mgr *)mixer->atc->rsc_mgrs[AMIXER]; - am_desc.msr = mixer->atc->msr; - for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) { - err = amixer_mgr->get_amixer(amixer_mgr, &am_desc, &amixer); - if (err) { - printk(KERN_ERR "ctxfi:Failed to get amixer resources " - "for mixer obj!\n"); - break; - } - mixer->amixers[i] = amixer; - } - if (err) - goto error2; - - return 0; - -error2: - for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) { - if (NULL != mixer->amixers[i]) { - amixer = mixer->amixers[i]; - amixer_mgr->put_amixer(amixer_mgr, amixer); - mixer->amixers[i] = NULL; - } - } -error1: - for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) { - if (NULL != mixer->sums[i]) { - sum_mgr->put_sum(sum_mgr, (struct sum *)mixer->sums[i]); - mixer->sums[i] = NULL; - } - } - - return err; -} - -static int ct_mixer_get_mem(struct ct_mixer **rmixer) -{ - struct ct_mixer *mixer; - int err; - - *rmixer = NULL; - /* Allocate mem for mixer obj */ - mixer = kzalloc(sizeof(*mixer), GFP_KERNEL); - if (NULL == mixer) - return -ENOMEM; - - mixer->amixers = kzalloc(sizeof(void *)*(NUM_CT_AMIXERS*CHN_NUM), - GFP_KERNEL); - if (NULL == mixer->amixers) { - err = -ENOMEM; - goto error1; - } - mixer->sums = kzalloc(sizeof(void *)*(NUM_CT_SUMS*CHN_NUM), GFP_KERNEL); - if (NULL == mixer->sums) { - err = -ENOMEM; - goto error2; - } - - *rmixer = mixer; - return 0; - -error2: - kfree(mixer->amixers); -error1: - kfree(mixer); - return err; -} - -static int ct_mixer_topology_build(struct ct_mixer *mixer) -{ - struct sum *sum; - struct amixer *amix_d, *amix_s; - enum CT_AMIXER_CTL i, j; - - /* Build topology from destination to source */ - - /* Set up Master mixer */ - for (i = AMIXER_MASTER_F, j = SUM_IN_F; - i <= AMIXER_MASTER_S; i++, j++) { - amix_d = mixer->amixers[i*CHN_NUM]; - sum = mixer->sums[j*CHN_NUM]; - amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL); - amix_d = mixer->amixers[i*CHN_NUM+1]; - sum = mixer->sums[j*CHN_NUM+1]; - amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL); - } - - /* Set up Wave-out mixer */ - for (i = AMIXER_WAVE_F, j = AMIXER_MASTER_F; - i <= AMIXER_WAVE_S; i++, j++) { - amix_d = mixer->amixers[i*CHN_NUM]; - amix_s = mixer->amixers[j*CHN_NUM]; - amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL); - amix_d = mixer->amixers[i*CHN_NUM+1]; - amix_s = mixer->amixers[j*CHN_NUM+1]; - amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL); - } - - /* Set up S/PDIF-out mixer */ - amix_d = mixer->amixers[AMIXER_SPDIFO*CHN_NUM]; - amix_s = mixer->amixers[AMIXER_MASTER_F*CHN_NUM]; - amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL); - amix_d = mixer->amixers[AMIXER_SPDIFO*CHN_NUM+1]; - amix_s = mixer->amixers[AMIXER_MASTER_F*CHN_NUM+1]; - amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL); - - /* Set up PCM-in mixer */ - for (i = AMIXER_PCM_F, j = SUM_IN_F; i <= AMIXER_PCM_S; i++, j++) { - amix_d = mixer->amixers[i*CHN_NUM]; - sum = mixer->sums[j*CHN_NUM]; - amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); - amix_d = mixer->amixers[i*CHN_NUM+1]; - sum = mixer->sums[j*CHN_NUM+1]; - amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); - } - - /* Set up Line-in mixer */ - amix_d = mixer->amixers[AMIXER_LINEIN*CHN_NUM]; - sum = mixer->sums[SUM_IN_F*CHN_NUM]; - amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); - amix_d = mixer->amixers[AMIXER_LINEIN*CHN_NUM+1]; - sum = mixer->sums[SUM_IN_F*CHN_NUM+1]; - amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); - - /* Set up Mic-in mixer */ - amix_d = mixer->amixers[AMIXER_MIC*CHN_NUM]; - sum = mixer->sums[SUM_IN_F*CHN_NUM]; - amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); - amix_d = mixer->amixers[AMIXER_MIC*CHN_NUM+1]; - sum = mixer->sums[SUM_IN_F*CHN_NUM+1]; - amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); - - /* Set up S/PDIF-in mixer */ - amix_d = mixer->amixers[AMIXER_SPDIFI*CHN_NUM]; - sum = mixer->sums[SUM_IN_F*CHN_NUM]; - amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); - amix_d = mixer->amixers[AMIXER_SPDIFI*CHN_NUM+1]; - sum = mixer->sums[SUM_IN_F*CHN_NUM+1]; - amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); - - /* Set up Master recording mixer */ - amix_d = mixer->amixers[AMIXER_MASTER_F_C*CHN_NUM]; - sum = mixer->sums[SUM_IN_F_C*CHN_NUM]; - amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL); - amix_d = mixer->amixers[AMIXER_MASTER_F_C*CHN_NUM+1]; - sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1]; - amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL); - - /* Set up PCM-in recording mixer */ - amix_d = mixer->amixers[AMIXER_PCM_F_C*CHN_NUM]; - sum = mixer->sums[SUM_IN_F_C*CHN_NUM]; - amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); - amix_d = mixer->amixers[AMIXER_PCM_F_C*CHN_NUM+1]; - sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1]; - amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); - - /* Set up Line-in recording mixer */ - amix_d = mixer->amixers[AMIXER_LINEIN_C*CHN_NUM]; - sum = mixer->sums[SUM_IN_F_C*CHN_NUM]; - amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); - amix_d = mixer->amixers[AMIXER_LINEIN_C*CHN_NUM+1]; - sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1]; - amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); - - /* Set up Mic-in recording mixer */ - amix_d = mixer->amixers[AMIXER_MIC_C*CHN_NUM]; - sum = mixer->sums[SUM_IN_F_C*CHN_NUM]; - amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); - amix_d = mixer->amixers[AMIXER_MIC_C*CHN_NUM+1]; - sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1]; - amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); - - /* Set up S/PDIF-in recording mixer */ - amix_d = mixer->amixers[AMIXER_SPDIFI_C*CHN_NUM]; - sum = mixer->sums[SUM_IN_F_C*CHN_NUM]; - amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); - amix_d = mixer->amixers[AMIXER_SPDIFI_C*CHN_NUM+1]; - sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1]; - amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); - - return 0; -} - -static int mixer_set_input_port(struct amixer *amixer, struct rsc *rsc) -{ - amixer->ops->set_input(amixer, rsc); - amixer->ops->commit_write(amixer); - - return 0; -} - -static enum CT_AMIXER_CTL port_to_amixer(enum MIXER_PORT_T type) -{ - switch (type) { - case MIX_WAVE_FRONT: return AMIXER_WAVE_F; - case MIX_WAVE_SURROUND: return AMIXER_WAVE_S; - case MIX_WAVE_CENTLFE: return AMIXER_WAVE_C; - case MIX_WAVE_REAR: return AMIXER_WAVE_R; - case MIX_PCMO_FRONT: return AMIXER_MASTER_F_C; - case MIX_SPDIF_OUT: return AMIXER_SPDIFO; - case MIX_LINE_IN: return AMIXER_LINEIN; - case MIX_MIC_IN: return AMIXER_MIC; - case MIX_SPDIF_IN: return AMIXER_SPDIFI; - case MIX_PCMI_FRONT: return AMIXER_PCM_F; - case MIX_PCMI_SURROUND: return AMIXER_PCM_S; - case MIX_PCMI_CENTLFE: return AMIXER_PCM_C; - case MIX_PCMI_REAR: return AMIXER_PCM_R; - default: return 0; - } -} - -static int mixer_get_output_ports(struct ct_mixer *mixer, - enum MIXER_PORT_T type, - struct rsc **rleft, struct rsc **rright) -{ - enum CT_AMIXER_CTL amix = port_to_amixer(type); - - if (NULL != rleft) - *rleft = &((struct amixer *)mixer->amixers[amix*CHN_NUM])->rsc; - - if (NULL != rright) - *rright = - &((struct amixer *)mixer->amixers[amix*CHN_NUM+1])->rsc; - - return 0; -} - -static int mixer_set_input_left(struct ct_mixer *mixer, - enum MIXER_PORT_T type, struct rsc *rsc) -{ - enum CT_AMIXER_CTL amix = port_to_amixer(type); - - mixer_set_input_port(mixer->amixers[amix*CHN_NUM], rsc); - amix = get_recording_amixer(amix); - if (amix < NUM_CT_AMIXERS) - mixer_set_input_port(mixer->amixers[amix*CHN_NUM], rsc); - - return 0; -} - -static int -mixer_set_input_right(struct ct_mixer *mixer, - enum MIXER_PORT_T type, struct rsc *rsc) -{ - enum CT_AMIXER_CTL amix = port_to_amixer(type); - - mixer_set_input_port(mixer->amixers[amix*CHN_NUM+1], rsc); - amix = get_recording_amixer(amix); - if (amix < NUM_CT_AMIXERS) - mixer_set_input_port(mixer->amixers[amix*CHN_NUM+1], rsc); - - return 0; -} - -#ifdef CONFIG_PM -static int mixer_resume(struct ct_mixer *mixer) -{ - int i, state; - struct amixer *amixer; - - /* resume topology and volume gain. */ - for (i = 0; i < NUM_CT_AMIXERS*CHN_NUM; i++) { - amixer = mixer->amixers[i]; - amixer->ops->commit_write(amixer); - } - - /* resume switch state. */ - for (i = SWH_MIXER_START; i <= SWH_MIXER_END; i++) { - state = get_switch_state(mixer, i); - do_switch(mixer->atc, i, state); - } - - return 0; -} -#endif - -int ct_mixer_destroy(struct ct_mixer *mixer) -{ - struct sum_mgr *sum_mgr = (struct sum_mgr *)mixer->atc->rsc_mgrs[SUM]; - struct amixer_mgr *amixer_mgr = - (struct amixer_mgr *)mixer->atc->rsc_mgrs[AMIXER]; - struct amixer *amixer; - int i = 0; - - /* Release amixer resources */ - for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) { - if (NULL != mixer->amixers[i]) { - amixer = mixer->amixers[i]; - amixer_mgr->put_amixer(amixer_mgr, amixer); - } - } - - /* Release sum resources */ - for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) { - if (NULL != mixer->sums[i]) - sum_mgr->put_sum(sum_mgr, (struct sum *)mixer->sums[i]); - } - - /* Release mem assigned to mixer object */ - kfree(mixer->sums); - kfree(mixer->amixers); - kfree(mixer); - - return 0; -} - -int ct_mixer_create(struct ct_atc *atc, struct ct_mixer **rmixer) -{ - struct ct_mixer *mixer; - int err; - - *rmixer = NULL; - - /* Allocate mem for mixer obj */ - err = ct_mixer_get_mem(&mixer); - if (err) - return err; - - mixer->switch_state = 0; - mixer->atc = atc; - /* Set operations */ - mixer->get_output_ports = mixer_get_output_ports; - mixer->set_input_left = mixer_set_input_left; - mixer->set_input_right = mixer_set_input_right; -#ifdef CONFIG_PM - mixer->resume = mixer_resume; -#endif - - /* Allocate chip resources for mixer obj */ - err = ct_mixer_get_resources(mixer); - if (err) - goto error; - - /* Build internal mixer topology */ - ct_mixer_topology_build(mixer); - - *rmixer = mixer; - - return 0; - -error: - ct_mixer_destroy(mixer); - return err; -} - -int ct_alsa_mix_create(struct ct_atc *atc, - enum CTALSADEVS device, - const char *device_name) -{ - int err; - - /* Create snd kcontrol instances on demand */ - /* vol_ctl.device = swh_ctl.device = device; */ /* better w/ device 0 */ - err = ct_mixer_kcontrols_create((struct ct_mixer *)atc->mixer); - if (err) - return err; - - strcpy(atc->card->mixername, device_name); - - return 0; -} diff --git a/trunk/sound/pci/ctxfi/ctmixer.h b/trunk/sound/pci/ctxfi/ctmixer.h deleted file mode 100644 index b009e989e77d..000000000000 --- a/trunk/sound/pci/ctxfi/ctmixer.h +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. - * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - * - * @File ctmixer.h - * - * @Brief - * This file contains the definition of the mixer device functions. - * - * @Author Liu Chun - * @Date Mar 28 2008 - * - */ - -#ifndef CTMIXER_H -#define CTMIXER_H - -#include "ctatc.h" -#include "ctresource.h" - -#define INIT_VOL 0x1c00 - -enum MIXER_PORT_T { - MIX_WAVE_FRONT, - MIX_WAVE_REAR, - MIX_WAVE_CENTLFE, - MIX_WAVE_SURROUND, - MIX_SPDIF_OUT, - MIX_PCMO_FRONT, - MIX_MIC_IN, - MIX_LINE_IN, - MIX_SPDIF_IN, - MIX_PCMI_FRONT, - MIX_PCMI_REAR, - MIX_PCMI_CENTLFE, - MIX_PCMI_SURROUND, - - NUM_MIX_PORTS -}; - -/* alsa mixer descriptor */ -struct ct_mixer { - struct ct_atc *atc; - - void **amixers; /* amixer resources for volume control */ - void **sums; /* sum resources for signal collection */ - unsigned int switch_state; /* A bit-map to indicate state of switches */ - - int (*get_output_ports)(struct ct_mixer *mixer, enum MIXER_PORT_T type, - struct rsc **rleft, struct rsc **rright); - - int (*set_input_left)(struct ct_mixer *mixer, - enum MIXER_PORT_T type, struct rsc *rsc); - int (*set_input_right)(struct ct_mixer *mixer, - enum MIXER_PORT_T type, struct rsc *rsc); -#ifdef CONFIG_PM - int (*resume)(struct ct_mixer *mixer); -#endif -}; - -int ct_alsa_mix_create(struct ct_atc *atc, - enum CTALSADEVS device, - const char *device_name); -int ct_mixer_create(struct ct_atc *atc, struct ct_mixer **rmixer); -int ct_mixer_destroy(struct ct_mixer *mixer); - -#endif /* CTMIXER_H */ diff --git a/trunk/sound/pci/ctxfi/ctpcm.c b/trunk/sound/pci/ctxfi/ctpcm.c deleted file mode 100644 index 60ea23180acb..000000000000 --- a/trunk/sound/pci/ctxfi/ctpcm.c +++ /dev/null @@ -1,430 +0,0 @@ -/** - * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. - * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - * - * @File ctpcm.c - * - * @Brief - * This file contains the definition of the pcm device functions. - * - * @Author Liu Chun - * @Date Apr 2 2008 - * - */ - -#include "ctpcm.h" -#include "cttimer.h" -#include - -/* Hardware descriptions for playback */ -static struct snd_pcm_hardware ct_pcm_playback_hw = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE), - .formats = (SNDRV_PCM_FMTBIT_U8 | - SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_3LE | - SNDRV_PCM_FMTBIT_S32_LE | - SNDRV_PCM_FMTBIT_FLOAT_LE), - .rates = (SNDRV_PCM_RATE_CONTINUOUS | - SNDRV_PCM_RATE_8000_192000), - .rate_min = 8000, - .rate_max = 192000, - .channels_min = 1, - .channels_max = 2, - .buffer_bytes_max = (128*1024), - .period_bytes_min = (64), - .period_bytes_max = (128*1024), - .periods_min = 2, - .periods_max = 1024, - .fifo_size = 0, -}; - -static struct snd_pcm_hardware ct_spdif_passthru_playback_hw = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE), - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rates = (SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_32000), - .rate_min = 32000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = (128*1024), - .period_bytes_min = (64), - .period_bytes_max = (128*1024), - .periods_min = 2, - .periods_max = 1024, - .fifo_size = 0, -}; - -/* Hardware descriptions for capture */ -static struct snd_pcm_hardware ct_pcm_capture_hw = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_MMAP_VALID), - .formats = (SNDRV_PCM_FMTBIT_U8 | - SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_3LE | - SNDRV_PCM_FMTBIT_S32_LE | - SNDRV_PCM_FMTBIT_FLOAT_LE), - .rates = (SNDRV_PCM_RATE_CONTINUOUS | - SNDRV_PCM_RATE_8000_96000), - .rate_min = 8000, - .rate_max = 96000, - .channels_min = 1, - .channels_max = 2, - .buffer_bytes_max = (128*1024), - .period_bytes_min = (384), - .period_bytes_max = (64*1024), - .periods_min = 2, - .periods_max = 1024, - .fifo_size = 0, -}; - -static void ct_atc_pcm_interrupt(struct ct_atc_pcm *atc_pcm) -{ - struct ct_atc_pcm *apcm = atc_pcm; - - if (NULL == apcm->substream) - return; - - snd_pcm_period_elapsed(apcm->substream); -} - -static void ct_atc_pcm_free_substream(struct snd_pcm_runtime *runtime) -{ - struct ct_atc_pcm *apcm = runtime->private_data; - struct ct_atc *atc = snd_pcm_substream_chip(apcm->substream); - - atc->pcm_release_resources(atc, apcm); - ct_timer_instance_free(apcm->timer); - kfree(apcm); - runtime->private_data = NULL; -} - -/* pcm playback operations */ -static int ct_pcm_playback_open(struct snd_pcm_substream *substream) -{ - struct ct_atc *atc = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - struct ct_atc_pcm *apcm; - int err; - - apcm = kzalloc(sizeof(*apcm), GFP_KERNEL); - if (NULL == apcm) - return -ENOMEM; - - apcm->substream = substream; - apcm->interrupt = ct_atc_pcm_interrupt; - runtime->private_data = apcm; - runtime->private_free = ct_atc_pcm_free_substream; - if (IEC958 == substream->pcm->device) { - runtime->hw = ct_spdif_passthru_playback_hw; - atc->spdif_out_passthru(atc, 1); - } else { - runtime->hw = ct_pcm_playback_hw; - if (FRONT == substream->pcm->device) - runtime->hw.channels_max = 8; - } - - err = snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - if (err < 0) { - kfree(apcm); - return err; - } - err = snd_pcm_hw_constraint_minmax(runtime, - SNDRV_PCM_HW_PARAM_BUFFER_BYTES, - 1024, UINT_MAX); - if (err < 0) { - kfree(apcm); - return err; - } - - apcm->timer = ct_timer_instance_new(atc->timer, apcm); - if (!apcm->timer) - return -ENOMEM; - - return 0; -} - -static int ct_pcm_playback_close(struct snd_pcm_substream *substream) -{ - struct ct_atc *atc = snd_pcm_substream_chip(substream); - - /* TODO: Notify mixer inactive. */ - if (IEC958 == substream->pcm->device) - atc->spdif_out_passthru(atc, 0); - - /* The ct_atc_pcm object will be freed by runtime->private_free */ - - return 0; -} - -static int ct_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct ct_atc *atc = snd_pcm_substream_chip(substream); - struct ct_atc_pcm *apcm = substream->runtime->private_data; - int err; - - err = snd_pcm_lib_malloc_pages(substream, - params_buffer_bytes(hw_params)); - if (err < 0) - return err; - /* clear previous resources */ - atc->pcm_release_resources(atc, apcm); - return err; -} - -static int ct_pcm_hw_free(struct snd_pcm_substream *substream) -{ - struct ct_atc *atc = snd_pcm_substream_chip(substream); - struct ct_atc_pcm *apcm = substream->runtime->private_data; - - /* clear previous resources */ - atc->pcm_release_resources(atc, apcm); - /* Free snd-allocated pages */ - return snd_pcm_lib_free_pages(substream); -} - - -static int ct_pcm_playback_prepare(struct snd_pcm_substream *substream) -{ - int err; - struct ct_atc *atc = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - struct ct_atc_pcm *apcm = runtime->private_data; - - if (IEC958 == substream->pcm->device) - err = atc->spdif_passthru_playback_prepare(atc, apcm); - else - err = atc->pcm_playback_prepare(atc, apcm); - - if (err < 0) { - printk(KERN_ERR "ctxfi: Preparing pcm playback failed!!!\n"); - return err; - } - - return 0; -} - -static int -ct_pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct ct_atc *atc = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - struct ct_atc_pcm *apcm = runtime->private_data; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - atc->pcm_playback_start(atc, apcm); - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - atc->pcm_playback_stop(atc, apcm); - break; - default: - break; - } - - return 0; -} - -static snd_pcm_uframes_t -ct_pcm_playback_pointer(struct snd_pcm_substream *substream) -{ - unsigned long position; - struct ct_atc *atc = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - struct ct_atc_pcm *apcm = runtime->private_data; - - /* Read out playback position */ - position = atc->pcm_playback_position(atc, apcm); - position = bytes_to_frames(runtime, position); - if (position >= runtime->buffer_size) - position = 0; - return position; -} - -/* pcm capture operations */ -static int ct_pcm_capture_open(struct snd_pcm_substream *substream) -{ - struct ct_atc *atc = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - struct ct_atc_pcm *apcm; - int err; - - apcm = kzalloc(sizeof(*apcm), GFP_KERNEL); - if (NULL == apcm) - return -ENOMEM; - - apcm->started = 0; - apcm->substream = substream; - apcm->interrupt = ct_atc_pcm_interrupt; - runtime->private_data = apcm; - runtime->private_free = ct_atc_pcm_free_substream; - runtime->hw = ct_pcm_capture_hw; - runtime->hw.rate_max = atc->rsr * atc->msr; - - err = snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - if (err < 0) { - kfree(apcm); - return err; - } - err = snd_pcm_hw_constraint_minmax(runtime, - SNDRV_PCM_HW_PARAM_BUFFER_BYTES, - 1024, UINT_MAX); - if (err < 0) { - kfree(apcm); - return err; - } - - apcm->timer = ct_timer_instance_new(atc->timer, apcm); - if (!apcm->timer) - return -ENOMEM; - - return 0; -} - -static int ct_pcm_capture_close(struct snd_pcm_substream *substream) -{ - /* The ct_atc_pcm object will be freed by runtime->private_free */ - /* TODO: Notify mixer inactive. */ - return 0; -} - -static int ct_pcm_capture_prepare(struct snd_pcm_substream *substream) -{ - int err; - struct ct_atc *atc = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - struct ct_atc_pcm *apcm = runtime->private_data; - - err = atc->pcm_capture_prepare(atc, apcm); - if (err < 0) { - printk(KERN_ERR "ctxfi: Preparing pcm capture failed!!!\n"); - return err; - } - - return 0; -} - -static int -ct_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct ct_atc *atc = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - struct ct_atc_pcm *apcm = runtime->private_data; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - atc->pcm_capture_start(atc, apcm); - break; - case SNDRV_PCM_TRIGGER_STOP: - atc->pcm_capture_stop(atc, apcm); - break; - default: - atc->pcm_capture_stop(atc, apcm); - break; - } - - return 0; -} - -static snd_pcm_uframes_t -ct_pcm_capture_pointer(struct snd_pcm_substream *substream) -{ - unsigned long position; - struct ct_atc *atc = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - struct ct_atc_pcm *apcm = runtime->private_data; - - /* Read out playback position */ - position = atc->pcm_capture_position(atc, apcm); - position = bytes_to_frames(runtime, position); - if (position >= runtime->buffer_size) - position = 0; - return position; -} - -/* PCM operators for playback */ -static struct snd_pcm_ops ct_pcm_playback_ops = { - .open = ct_pcm_playback_open, - .close = ct_pcm_playback_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = ct_pcm_hw_params, - .hw_free = ct_pcm_hw_free, - .prepare = ct_pcm_playback_prepare, - .trigger = ct_pcm_playback_trigger, - .pointer = ct_pcm_playback_pointer, - .page = snd_pcm_sgbuf_ops_page, -}; - -/* PCM operators for capture */ -static struct snd_pcm_ops ct_pcm_capture_ops = { - .open = ct_pcm_capture_open, - .close = ct_pcm_capture_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = ct_pcm_hw_params, - .hw_free = ct_pcm_hw_free, - .prepare = ct_pcm_capture_prepare, - .trigger = ct_pcm_capture_trigger, - .pointer = ct_pcm_capture_pointer, - .page = snd_pcm_sgbuf_ops_page, -}; - -/* Create ALSA pcm device */ -int ct_alsa_pcm_create(struct ct_atc *atc, - enum CTALSADEVS device, - const char *device_name) -{ - struct snd_pcm *pcm; - int err; - int playback_count, capture_count; - - playback_count = (IEC958 == device) ? 1 : 8; - capture_count = (FRONT == device) ? 1 : 0; - err = snd_pcm_new(atc->card, "ctxfi", device, - playback_count, capture_count, &pcm); - if (err < 0) { - printk(KERN_ERR "ctxfi: snd_pcm_new failed!! Err=%d\n", err); - return err; - } - - pcm->private_data = atc; - pcm->info_flags = 0; - pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; - strlcpy(pcm->name, device_name, sizeof(pcm->name)); - - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ct_pcm_playback_ops); - - if (FRONT == device) - snd_pcm_set_ops(pcm, - SNDRV_PCM_STREAM_CAPTURE, &ct_pcm_capture_ops); - - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, - snd_dma_pci_data(atc->pci), 128*1024, 128*1024); - -#ifdef CONFIG_PM - atc->pcms[device] = pcm; -#endif - - return 0; -} diff --git a/trunk/sound/pci/ctxfi/ctpcm.h b/trunk/sound/pci/ctxfi/ctpcm.h deleted file mode 100644 index 178da0dca647..000000000000 --- a/trunk/sound/pci/ctxfi/ctpcm.h +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. - * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - * - * @File ctpcm.h - * - * @Brief - * This file contains the definition of the pcm device functions. - * - * @Author Liu Chun - * @Date Mar 28 2008 - * - */ - -#ifndef CTPCM_H -#define CTPCM_H - -#include "ctatc.h" - -int ct_alsa_pcm_create(struct ct_atc *atc, - enum CTALSADEVS device, - const char *device_name); - -#endif /* CTPCM_H */ diff --git a/trunk/sound/pci/ctxfi/ctresource.c b/trunk/sound/pci/ctxfi/ctresource.c deleted file mode 100644 index 889c495bb7d1..000000000000 --- a/trunk/sound/pci/ctxfi/ctresource.c +++ /dev/null @@ -1,301 +0,0 @@ -/** - * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. - * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - * - * @File ctresource.c - * - * @Brief - * This file contains the implementation of some generic helper functions. - * - * @Author Liu Chun - * @Date May 15 2008 - * - */ - -#include "ctresource.h" -#include "cthardware.h" -#include -#include - -#define AUDIO_SLOT_BLOCK_NUM 256 - -/* Resource allocation based on bit-map management mechanism */ -static int -get_resource(u8 *rscs, unsigned int amount, - unsigned int multi, unsigned int *ridx) -{ - int i, j, k, n; - - /* Check whether there are sufficient resources to meet request. */ - for (i = 0, n = multi; i < amount; i++) { - j = i / 8; - k = i % 8; - if (rscs[j] & ((u8)1 << k)) { - n = multi; - continue; - } - if (!(--n)) - break; /* found sufficient contiguous resources */ - } - - if (i >= amount) { - /* Can not find sufficient contiguous resources */ - return -ENOENT; - } - - /* Mark the contiguous bits in resource bit-map as used */ - for (n = multi; n > 0; n--) { - j = i / 8; - k = i % 8; - rscs[j] |= ((u8)1 << k); - i--; - } - - *ridx = i + 1; - - return 0; -} - -static int put_resource(u8 *rscs, unsigned int multi, unsigned int idx) -{ - unsigned int i, j, k, n; - - /* Mark the contiguous bits in resource bit-map as used */ - for (n = multi, i = idx; n > 0; n--) { - j = i / 8; - k = i % 8; - rscs[j] &= ~((u8)1 << k); - i++; - } - - return 0; -} - -int mgr_get_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int *ridx) -{ - int err; - - if (n > mgr->avail) - return -ENOENT; - - err = get_resource(mgr->rscs, mgr->amount, n, ridx); - if (!err) - mgr->avail -= n; - - return err; -} - -int mgr_put_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int idx) -{ - put_resource(mgr->rscs, n, idx); - mgr->avail += n; - - return 0; -} - -static unsigned char offset_in_audio_slot_block[NUM_RSCTYP] = { - /* SRC channel is at Audio Ring slot 1 every 16 slots. */ - [SRC] = 0x1, - [AMIXER] = 0x4, - [SUM] = 0xc, -}; - -static int rsc_index(const struct rsc *rsc) -{ - return rsc->conj; -} - -static int audio_ring_slot(const struct rsc *rsc) -{ - return (rsc->conj << 4) + offset_in_audio_slot_block[rsc->type]; -} - -static int rsc_next_conj(struct rsc *rsc) -{ - unsigned int i; - for (i = 0; (i < 8) && (!(rsc->msr & (0x1 << i))); ) - i++; - rsc->conj += (AUDIO_SLOT_BLOCK_NUM >> i); - return rsc->conj; -} - -static int rsc_master(struct rsc *rsc) -{ - return rsc->conj = rsc->idx; -} - -static struct rsc_ops rsc_generic_ops = { - .index = rsc_index, - .output_slot = audio_ring_slot, - .master = rsc_master, - .next_conj = rsc_next_conj, -}; - -int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw) -{ - int err = 0; - - rsc->idx = idx; - rsc->conj = idx; - rsc->type = type; - rsc->msr = msr; - rsc->hw = hw; - rsc->ops = &rsc_generic_ops; - if (NULL == hw) { - rsc->ctrl_blk = NULL; - return 0; - } - - switch (type) { - case SRC: - err = ((struct hw *)hw)->src_rsc_get_ctrl_blk(&rsc->ctrl_blk); - break; - case AMIXER: - err = ((struct hw *)hw)-> - amixer_rsc_get_ctrl_blk(&rsc->ctrl_blk); - break; - case SRCIMP: - case SUM: - case DAIO: - break; - default: - printk(KERN_ERR - "ctxfi: Invalid resource type value %d!\n", type); - return -EINVAL; - } - - if (err) { - printk(KERN_ERR - "ctxfi: Failed to get resource control block!\n"); - return err; - } - - return 0; -} - -int rsc_uninit(struct rsc *rsc) -{ - if ((NULL != rsc->hw) && (NULL != rsc->ctrl_blk)) { - switch (rsc->type) { - case SRC: - ((struct hw *)rsc->hw)-> - src_rsc_put_ctrl_blk(rsc->ctrl_blk); - break; - case AMIXER: - ((struct hw *)rsc->hw)-> - amixer_rsc_put_ctrl_blk(rsc->ctrl_blk); - break; - case SUM: - case DAIO: - break; - default: - printk(KERN_ERR "ctxfi: " - "Invalid resource type value %d!\n", rsc->type); - break; - } - - rsc->hw = rsc->ctrl_blk = NULL; - } - - rsc->idx = rsc->conj = 0; - rsc->type = NUM_RSCTYP; - rsc->msr = 0; - - return 0; -} - -int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type, - unsigned int amount, void *hw_obj) -{ - int err = 0; - struct hw *hw = hw_obj; - - mgr->type = NUM_RSCTYP; - - mgr->rscs = kzalloc(((amount + 8 - 1) / 8), GFP_KERNEL); - if (NULL == mgr->rscs) - return -ENOMEM; - - switch (type) { - case SRC: - err = hw->src_mgr_get_ctrl_blk(&mgr->ctrl_blk); - break; - case SRCIMP: - err = hw->srcimp_mgr_get_ctrl_blk(&mgr->ctrl_blk); - break; - case AMIXER: - err = hw->amixer_mgr_get_ctrl_blk(&mgr->ctrl_blk); - break; - case DAIO: - err = hw->daio_mgr_get_ctrl_blk(hw, &mgr->ctrl_blk); - break; - case SUM: - break; - default: - printk(KERN_ERR - "ctxfi: Invalid resource type value %d!\n", type); - err = -EINVAL; - goto error; - } - - if (err) { - printk(KERN_ERR - "ctxfi: Failed to get manager control block!\n"); - goto error; - } - - mgr->type = type; - mgr->avail = mgr->amount = amount; - mgr->hw = hw; - - return 0; - -error: - kfree(mgr->rscs); - return err; -} - -int rsc_mgr_uninit(struct rsc_mgr *mgr) -{ - if (NULL != mgr->rscs) { - kfree(mgr->rscs); - mgr->rscs = NULL; - } - - if ((NULL != mgr->hw) && (NULL != mgr->ctrl_blk)) { - switch (mgr->type) { - case SRC: - ((struct hw *)mgr->hw)-> - src_mgr_put_ctrl_blk(mgr->ctrl_blk); - break; - case SRCIMP: - ((struct hw *)mgr->hw)-> - srcimp_mgr_put_ctrl_blk(mgr->ctrl_blk); - break; - case AMIXER: - ((struct hw *)mgr->hw)-> - amixer_mgr_put_ctrl_blk(mgr->ctrl_blk); - break; - case DAIO: - ((struct hw *)mgr->hw)-> - daio_mgr_put_ctrl_blk(mgr->ctrl_blk); - break; - case SUM: - break; - default: - printk(KERN_ERR "ctxfi: " - "Invalid resource type value %d!\n", mgr->type); - break; - } - - mgr->hw = mgr->ctrl_blk = NULL; - } - - mgr->type = NUM_RSCTYP; - mgr->avail = mgr->amount = 0; - - return 0; -} diff --git a/trunk/sound/pci/ctxfi/ctresource.h b/trunk/sound/pci/ctxfi/ctresource.h deleted file mode 100644 index 0838c2e84f8b..000000000000 --- a/trunk/sound/pci/ctxfi/ctresource.h +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. - * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - * - * @File ctresource.h - * - * @Brief - * This file contains the definition of generic hardware resources for - * resource management. - * - * @Author Liu Chun - * @Date May 13 2008 - * - */ - -#ifndef CTRESOURCE_H -#define CTRESOURCE_H - -#include - -enum RSCTYP { - SRC, - SRCIMP, - AMIXER, - SUM, - DAIO, - NUM_RSCTYP /* This must be the last one and less than 16 */ -}; - -struct rsc_ops; - -struct rsc { - u32 idx:12; /* The index of a resource */ - u32 type:4; /* The type (RSCTYP) of a resource */ - u32 conj:12; /* Current conjugate index */ - u32 msr:4; /* The Master Sample Rate a resource working on */ - void *ctrl_blk; /* Chip specific control info block for a resource */ - void *hw; /* Chip specific object for hardware access means */ - struct rsc_ops *ops; /* Generic resource operations */ -}; - -struct rsc_ops { - int (*master)(struct rsc *rsc); /* Move to master resource */ - int (*next_conj)(struct rsc *rsc); /* Move to next conjugate resource */ - int (*index)(const struct rsc *rsc); /* Return the index of resource */ - /* Return the output slot number */ - int (*output_slot)(const struct rsc *rsc); -}; - -int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw); -int rsc_uninit(struct rsc *rsc); - -struct rsc_mgr { - enum RSCTYP type; /* The type (RSCTYP) of resource to manage */ - unsigned int amount; /* The total amount of a kind of resource */ - unsigned int avail; /* The amount of currently available resources */ - unsigned char *rscs; /* The bit-map for resource allocation */ - void *ctrl_blk; /* Chip specific control info block */ - void *hw; /* Chip specific object for hardware access */ -}; - -/* Resource management is based on bit-map mechanism */ -int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type, - unsigned int amount, void *hw); -int rsc_mgr_uninit(struct rsc_mgr *mgr); -int mgr_get_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int *ridx); -int mgr_put_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int idx); - -#endif /* CTRESOURCE_H */ diff --git a/trunk/sound/pci/ctxfi/ctsrc.c b/trunk/sound/pci/ctxfi/ctsrc.c deleted file mode 100644 index e1c145d8b702..000000000000 --- a/trunk/sound/pci/ctxfi/ctsrc.c +++ /dev/null @@ -1,886 +0,0 @@ -/** - * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. - * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - * - * @File ctsrc.c - * - * @Brief - * This file contains the implementation of the Sample Rate Convertor - * resource management object. - * - * @Author Liu Chun - * @Date May 13 2008 - * - */ - -#include "ctsrc.h" -#include "cthardware.h" -#include - -#define SRC_RESOURCE_NUM 64 -#define SRCIMP_RESOURCE_NUM 256 - -static unsigned int conj_mask; - -static int src_default_config_memrd(struct src *src); -static int src_default_config_memwr(struct src *src); -static int src_default_config_arcrw(struct src *src); - -static int (*src_default_config[3])(struct src *) = { - [MEMRD] = src_default_config_memrd, - [MEMWR] = src_default_config_memwr, - [ARCRW] = src_default_config_arcrw -}; - -static int src_set_state(struct src *src, unsigned int state) -{ - struct hw *hw; - - hw = src->rsc.hw; - hw->src_set_state(src->rsc.ctrl_blk, state); - - return 0; -} - -static int src_set_bm(struct src *src, unsigned int bm) -{ - struct hw *hw; - - hw = src->rsc.hw; - hw->src_set_bm(src->rsc.ctrl_blk, bm); - - return 0; -} - -static int src_set_sf(struct src *src, unsigned int sf) -{ - struct hw *hw; - - hw = src->rsc.hw; - hw->src_set_sf(src->rsc.ctrl_blk, sf); - - return 0; -} - -static int src_set_pm(struct src *src, unsigned int pm) -{ - struct hw *hw; - - hw = src->rsc.hw; - hw->src_set_pm(src->rsc.ctrl_blk, pm); - - return 0; -} - -static int src_set_rom(struct src *src, unsigned int rom) -{ - struct hw *hw; - - hw = src->rsc.hw; - hw->src_set_rom(src->rsc.ctrl_blk, rom); - - return 0; -} - -static int src_set_vo(struct src *src, unsigned int vo) -{ - struct hw *hw; - - hw = src->rsc.hw; - hw->src_set_vo(src->rsc.ctrl_blk, vo); - - return 0; -} - -static int src_set_st(struct src *src, unsigned int st) -{ - struct hw *hw; - - hw = src->rsc.hw; - hw->src_set_st(src->rsc.ctrl_blk, st); - - return 0; -} - -static int src_set_bp(struct src *src, unsigned int bp) -{ - struct hw *hw; - - hw = src->rsc.hw; - hw->src_set_bp(src->rsc.ctrl_blk, bp); - - return 0; -} - -static int src_set_cisz(struct src *src, unsigned int cisz) -{ - struct hw *hw; - - hw = src->rsc.hw; - hw->src_set_cisz(src->rsc.ctrl_blk, cisz); - - return 0; -} - -static int src_set_ca(struct src *src, unsigned int ca) -{ - struct hw *hw; - - hw = src->rsc.hw; - hw->src_set_ca(src->rsc.ctrl_blk, ca); - - return 0; -} - -static int src_set_sa(struct src *src, unsigned int sa) -{ - struct hw *hw; - - hw = src->rsc.hw; - hw->src_set_sa(src->rsc.ctrl_blk, sa); - - return 0; -} - -static int src_set_la(struct src *src, unsigned int la) -{ - struct hw *hw; - - hw = src->rsc.hw; - hw->src_set_la(src->rsc.ctrl_blk, la); - - return 0; -} - -static int src_set_pitch(struct src *src, unsigned int pitch) -{ - struct hw *hw; - - hw = src->rsc.hw; - hw->src_set_pitch(src->rsc.ctrl_blk, pitch); - - return 0; -} - -static int src_set_clear_zbufs(struct src *src) -{ - struct hw *hw; - - hw = src->rsc.hw; - hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1); - - return 0; -} - -static int src_commit_write(struct src *src) -{ - struct hw *hw; - int i; - unsigned int dirty = 0; - - hw = src->rsc.hw; - src->rsc.ops->master(&src->rsc); - if (src->rsc.msr > 1) { - /* Save dirty flags for conjugate resource programming */ - dirty = hw->src_get_dirty(src->rsc.ctrl_blk) & conj_mask; - } - hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), - src->rsc.ctrl_blk); - - /* Program conjugate parameter mixer resources */ - if (MEMWR == src->mode) - return 0; - - for (i = 1; i < src->rsc.msr; i++) { - src->rsc.ops->next_conj(&src->rsc); - hw->src_set_dirty(src->rsc.ctrl_blk, dirty); - hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), - src->rsc.ctrl_blk); - } - src->rsc.ops->master(&src->rsc); - - return 0; -} - -static int src_get_ca(struct src *src) -{ - struct hw *hw; - - hw = src->rsc.hw; - return hw->src_get_ca(hw, src->rsc.ops->index(&src->rsc), - src->rsc.ctrl_blk); -} - -static int src_init(struct src *src) -{ - src_default_config[src->mode](src); - - return 0; -} - -static struct src *src_next_interleave(struct src *src) -{ - return src->intlv; -} - -static int src_default_config_memrd(struct src *src) -{ - struct hw *hw = src->rsc.hw; - unsigned int rsr, msr; - - hw->src_set_state(src->rsc.ctrl_blk, SRC_STATE_OFF); - hw->src_set_bm(src->rsc.ctrl_blk, 1); - for (rsr = 0, msr = src->rsc.msr; msr > 1; msr >>= 1) - rsr++; - - hw->src_set_rsr(src->rsc.ctrl_blk, rsr); - hw->src_set_sf(src->rsc.ctrl_blk, SRC_SF_S16); - hw->src_set_wr(src->rsc.ctrl_blk, 0); - hw->src_set_pm(src->rsc.ctrl_blk, 0); - hw->src_set_rom(src->rsc.ctrl_blk, 0); - hw->src_set_vo(src->rsc.ctrl_blk, 0); - hw->src_set_st(src->rsc.ctrl_blk, 0); - hw->src_set_ilsz(src->rsc.ctrl_blk, src->multi - 1); - hw->src_set_cisz(src->rsc.ctrl_blk, 0x80); - hw->src_set_sa(src->rsc.ctrl_blk, 0x0); - hw->src_set_la(src->rsc.ctrl_blk, 0x1000); - hw->src_set_ca(src->rsc.ctrl_blk, 0x80); - hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000); - hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1); - - src->rsc.ops->master(&src->rsc); - hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), - src->rsc.ctrl_blk); - - for (msr = 1; msr < src->rsc.msr; msr++) { - src->rsc.ops->next_conj(&src->rsc); - hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000); - hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), - src->rsc.ctrl_blk); - } - src->rsc.ops->master(&src->rsc); - - return 0; -} - -static int src_default_config_memwr(struct src *src) -{ - struct hw *hw = src->rsc.hw; - - hw->src_set_state(src->rsc.ctrl_blk, SRC_STATE_OFF); - hw->src_set_bm(src->rsc.ctrl_blk, 1); - hw->src_set_rsr(src->rsc.ctrl_blk, 0); - hw->src_set_sf(src->rsc.ctrl_blk, SRC_SF_S16); - hw->src_set_wr(src->rsc.ctrl_blk, 1); - hw->src_set_pm(src->rsc.ctrl_blk, 0); - hw->src_set_rom(src->rsc.ctrl_blk, 0); - hw->src_set_vo(src->rsc.ctrl_blk, 0); - hw->src_set_st(src->rsc.ctrl_blk, 0); - hw->src_set_ilsz(src->rsc.ctrl_blk, 0); - hw->src_set_cisz(src->rsc.ctrl_blk, 0x80); - hw->src_set_sa(src->rsc.ctrl_blk, 0x0); - hw->src_set_la(src->rsc.ctrl_blk, 0x1000); - hw->src_set_ca(src->rsc.ctrl_blk, 0x80); - hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000); - hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1); - - src->rsc.ops->master(&src->rsc); - hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), - src->rsc.ctrl_blk); - - return 0; -} - -static int src_default_config_arcrw(struct src *src) -{ - struct hw *hw = src->rsc.hw; - unsigned int rsr, msr; - unsigned int dirty; - - hw->src_set_state(src->rsc.ctrl_blk, SRC_STATE_OFF); - hw->src_set_bm(src->rsc.ctrl_blk, 0); - for (rsr = 0, msr = src->rsc.msr; msr > 1; msr >>= 1) - rsr++; - - hw->src_set_rsr(src->rsc.ctrl_blk, rsr); - hw->src_set_sf(src->rsc.ctrl_blk, SRC_SF_F32); - hw->src_set_wr(src->rsc.ctrl_blk, 0); - hw->src_set_pm(src->rsc.ctrl_blk, 0); - hw->src_set_rom(src->rsc.ctrl_blk, 0); - hw->src_set_vo(src->rsc.ctrl_blk, 0); - hw->src_set_st(src->rsc.ctrl_blk, 0); - hw->src_set_ilsz(src->rsc.ctrl_blk, 0); - hw->src_set_cisz(src->rsc.ctrl_blk, 0x80); - hw->src_set_sa(src->rsc.ctrl_blk, 0x0); - /*hw->src_set_sa(src->rsc.ctrl_blk, 0x100);*/ - hw->src_set_la(src->rsc.ctrl_blk, 0x1000); - /*hw->src_set_la(src->rsc.ctrl_blk, 0x03ffffe0);*/ - hw->src_set_ca(src->rsc.ctrl_blk, 0x80); - hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000); - hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1); - - dirty = hw->src_get_dirty(src->rsc.ctrl_blk); - src->rsc.ops->master(&src->rsc); - for (msr = 0; msr < src->rsc.msr; msr++) { - hw->src_set_dirty(src->rsc.ctrl_blk, dirty); - hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), - src->rsc.ctrl_blk); - src->rsc.ops->next_conj(&src->rsc); - } - src->rsc.ops->master(&src->rsc); - - return 0; -} - -static struct src_rsc_ops src_rsc_ops = { - .set_state = src_set_state, - .set_bm = src_set_bm, - .set_sf = src_set_sf, - .set_pm = src_set_pm, - .set_rom = src_set_rom, - .set_vo = src_set_vo, - .set_st = src_set_st, - .set_bp = src_set_bp, - .set_cisz = src_set_cisz, - .set_ca = src_set_ca, - .set_sa = src_set_sa, - .set_la = src_set_la, - .set_pitch = src_set_pitch, - .set_clr_zbufs = src_set_clear_zbufs, - .commit_write = src_commit_write, - .get_ca = src_get_ca, - .init = src_init, - .next_interleave = src_next_interleave, -}; - -static int -src_rsc_init(struct src *src, u32 idx, - const struct src_desc *desc, struct src_mgr *mgr) -{ - int err; - int i, n; - struct src *p; - - n = (MEMRD == desc->mode) ? desc->multi : 1; - for (i = 0, p = src; i < n; i++, p++) { - err = rsc_init(&p->rsc, idx + i, SRC, desc->msr, mgr->mgr.hw); - if (err) - goto error1; - - /* Initialize src specific rsc operations */ - p->ops = &src_rsc_ops; - p->multi = (0 == i) ? desc->multi : 1; - p->mode = desc->mode; - src_default_config[desc->mode](p); - mgr->src_enable(mgr, p); - p->intlv = p + 1; - } - (--p)->intlv = NULL; /* Set @intlv of the last SRC to NULL */ - - mgr->commit_write(mgr); - - return 0; - -error1: - for (i--, p--; i >= 0; i--, p--) { - mgr->src_disable(mgr, p); - rsc_uninit(&p->rsc); - } - mgr->commit_write(mgr); - return err; -} - -static int src_rsc_uninit(struct src *src, struct src_mgr *mgr) -{ - int i, n; - struct src *p; - - n = (MEMRD == src->mode) ? src->multi : 1; - for (i = 0, p = src; i < n; i++, p++) { - mgr->src_disable(mgr, p); - rsc_uninit(&p->rsc); - p->multi = 0; - p->ops = NULL; - p->mode = NUM_SRCMODES; - p->intlv = NULL; - } - mgr->commit_write(mgr); - - return 0; -} - -static int -get_src_rsc(struct src_mgr *mgr, const struct src_desc *desc, struct src **rsrc) -{ - unsigned int idx = SRC_RESOURCE_NUM; - int err; - struct src *src; - unsigned long flags; - - *rsrc = NULL; - - /* Check whether there are sufficient src resources to meet request. */ - spin_lock_irqsave(&mgr->mgr_lock, flags); - if (MEMRD == desc->mode) - err = mgr_get_resource(&mgr->mgr, desc->multi, &idx); - else - err = mgr_get_resource(&mgr->mgr, 1, &idx); - - spin_unlock_irqrestore(&mgr->mgr_lock, flags); - if (err) { - printk(KERN_ERR "ctxfi: Can't meet SRC resource request!\n"); - return err; - } - - /* Allocate mem for master src resource */ - if (MEMRD == desc->mode) - src = kzalloc(sizeof(*src)*desc->multi, GFP_KERNEL); - else - src = kzalloc(sizeof(*src), GFP_KERNEL); - - if (NULL == src) { - err = -ENOMEM; - goto error1; - } - - err = src_rsc_init(src, idx, desc, mgr); - if (err) - goto error2; - - *rsrc = src; - - return 0; - -error2: - kfree(src); -error1: - spin_lock_irqsave(&mgr->mgr_lock, flags); - if (MEMRD == desc->mode) - mgr_put_resource(&mgr->mgr, desc->multi, idx); - else - mgr_put_resource(&mgr->mgr, 1, idx); - - spin_unlock_irqrestore(&mgr->mgr_lock, flags); - return err; -} - -static int put_src_rsc(struct src_mgr *mgr, struct src *src) -{ - unsigned long flags; - - spin_lock_irqsave(&mgr->mgr_lock, flags); - src->rsc.ops->master(&src->rsc); - if (MEMRD == src->mode) - mgr_put_resource(&mgr->mgr, src->multi, - src->rsc.ops->index(&src->rsc)); - else - mgr_put_resource(&mgr->mgr, 1, src->rsc.ops->index(&src->rsc)); - - spin_unlock_irqrestore(&mgr->mgr_lock, flags); - src_rsc_uninit(src, mgr); - kfree(src); - - return 0; -} - -static int src_enable_s(struct src_mgr *mgr, struct src *src) -{ - struct hw *hw = mgr->mgr.hw; - int i; - - src->rsc.ops->master(&src->rsc); - for (i = 0; i < src->rsc.msr; i++) { - hw->src_mgr_enbs_src(mgr->mgr.ctrl_blk, - src->rsc.ops->index(&src->rsc)); - src->rsc.ops->next_conj(&src->rsc); - } - src->rsc.ops->master(&src->rsc); - - return 0; -} - -static int src_enable(struct src_mgr *mgr, struct src *src) -{ - struct hw *hw = mgr->mgr.hw; - int i; - - src->rsc.ops->master(&src->rsc); - for (i = 0; i < src->rsc.msr; i++) { - hw->src_mgr_enb_src(mgr->mgr.ctrl_blk, - src->rsc.ops->index(&src->rsc)); - src->rsc.ops->next_conj(&src->rsc); - } - src->rsc.ops->master(&src->rsc); - - return 0; -} - -static int src_disable(struct src_mgr *mgr, struct src *src) -{ - struct hw *hw = mgr->mgr.hw; - int i; - - src->rsc.ops->master(&src->rsc); - for (i = 0; i < src->rsc.msr; i++) { - hw->src_mgr_dsb_src(mgr->mgr.ctrl_blk, - src->rsc.ops->index(&src->rsc)); - src->rsc.ops->next_conj(&src->rsc); - } - src->rsc.ops->master(&src->rsc); - - return 0; -} - -static int src_mgr_commit_write(struct src_mgr *mgr) -{ - struct hw *hw = mgr->mgr.hw; - - hw->src_mgr_commit_write(hw, mgr->mgr.ctrl_blk); - - return 0; -} - -int src_mgr_create(void *hw, struct src_mgr **rsrc_mgr) -{ - int err, i; - struct src_mgr *src_mgr; - - *rsrc_mgr = NULL; - src_mgr = kzalloc(sizeof(*src_mgr), GFP_KERNEL); - if (NULL == src_mgr) - return -ENOMEM; - - err = rsc_mgr_init(&src_mgr->mgr, SRC, SRC_RESOURCE_NUM, hw); - if (err) - goto error1; - - spin_lock_init(&src_mgr->mgr_lock); - conj_mask = ((struct hw *)hw)->src_dirty_conj_mask(); - - src_mgr->get_src = get_src_rsc; - src_mgr->put_src = put_src_rsc; - src_mgr->src_enable_s = src_enable_s; - src_mgr->src_enable = src_enable; - src_mgr->src_disable = src_disable; - src_mgr->commit_write = src_mgr_commit_write; - - /* Disable all SRC resources. */ - for (i = 0; i < 256; i++) - ((struct hw *)hw)->src_mgr_dsb_src(src_mgr->mgr.ctrl_blk, i); - - ((struct hw *)hw)->src_mgr_commit_write(hw, src_mgr->mgr.ctrl_blk); - - *rsrc_mgr = src_mgr; - - return 0; - -error1: - kfree(src_mgr); - return err; -} - -int src_mgr_destroy(struct src_mgr *src_mgr) -{ - rsc_mgr_uninit(&src_mgr->mgr); - kfree(src_mgr); - - return 0; -} - -/* SRCIMP resource manager operations */ - -static int srcimp_master(struct rsc *rsc) -{ - rsc->conj = 0; - return rsc->idx = container_of(rsc, struct srcimp, rsc)->idx[0]; -} - -static int srcimp_next_conj(struct rsc *rsc) -{ - rsc->conj++; - return container_of(rsc, struct srcimp, rsc)->idx[rsc->conj]; -} - -static int srcimp_index(const struct rsc *rsc) -{ - return container_of(rsc, struct srcimp, rsc)->idx[rsc->conj]; -} - -static struct rsc_ops srcimp_basic_rsc_ops = { - .master = srcimp_master, - .next_conj = srcimp_next_conj, - .index = srcimp_index, - .output_slot = NULL, -}; - -static int srcimp_map(struct srcimp *srcimp, struct src *src, struct rsc *input) -{ - struct imapper *entry; - int i; - - srcimp->rsc.ops->master(&srcimp->rsc); - src->rsc.ops->master(&src->rsc); - input->ops->master(input); - - /* Program master and conjugate resources */ - for (i = 0; i < srcimp->rsc.msr; i++) { - entry = &srcimp->imappers[i]; - entry->slot = input->ops->output_slot(input); - entry->user = src->rsc.ops->index(&src->rsc); - entry->addr = srcimp->rsc.ops->index(&srcimp->rsc); - srcimp->mgr->imap_add(srcimp->mgr, entry); - srcimp->mapped |= (0x1 << i); - - srcimp->rsc.ops->next_conj(&srcimp->rsc); - input->ops->next_conj(input); - } - - srcimp->rsc.ops->master(&srcimp->rsc); - input->ops->master(input); - - return 0; -} - -static int srcimp_unmap(struct srcimp *srcimp) -{ - int i; - - /* Program master and conjugate resources */ - for (i = 0; i < srcimp->rsc.msr; i++) { - if (srcimp->mapped & (0x1 << i)) { - srcimp->mgr->imap_delete(srcimp->mgr, - &srcimp->imappers[i]); - srcimp->mapped &= ~(0x1 << i); - } - } - - return 0; -} - -static struct srcimp_rsc_ops srcimp_ops = { - .map = srcimp_map, - .unmap = srcimp_unmap -}; - -static int srcimp_rsc_init(struct srcimp *srcimp, - const struct srcimp_desc *desc, - struct srcimp_mgr *mgr) -{ - int err; - - err = rsc_init(&srcimp->rsc, srcimp->idx[0], - SRCIMP, desc->msr, mgr->mgr.hw); - if (err) - return err; - - /* Reserve memory for imapper nodes */ - srcimp->imappers = kzalloc(sizeof(struct imapper)*desc->msr, - GFP_KERNEL); - if (NULL == srcimp->imappers) { - err = -ENOMEM; - goto error1; - } - - /* Set srcimp specific operations */ - srcimp->rsc.ops = &srcimp_basic_rsc_ops; - srcimp->ops = &srcimp_ops; - srcimp->mgr = mgr; - - srcimp->rsc.ops->master(&srcimp->rsc); - - return 0; - -error1: - rsc_uninit(&srcimp->rsc); - return err; -} - -static int srcimp_rsc_uninit(struct srcimp *srcimp) -{ - if (NULL != srcimp->imappers) { - kfree(srcimp->imappers); - srcimp->imappers = NULL; - } - srcimp->ops = NULL; - srcimp->mgr = NULL; - rsc_uninit(&srcimp->rsc); - - return 0; -} - -static int get_srcimp_rsc(struct srcimp_mgr *mgr, - const struct srcimp_desc *desc, - struct srcimp **rsrcimp) -{ - int err, i; - unsigned int idx; - struct srcimp *srcimp; - unsigned long flags; - - *rsrcimp = NULL; - - /* Allocate mem for SRCIMP resource */ - srcimp = kzalloc(sizeof(*srcimp), GFP_KERNEL); - if (NULL == srcimp) { - err = -ENOMEM; - return err; - } - - /* Check whether there are sufficient SRCIMP resources. */ - spin_lock_irqsave(&mgr->mgr_lock, flags); - for (i = 0; i < desc->msr; i++) { - err = mgr_get_resource(&mgr->mgr, 1, &idx); - if (err) - break; - - srcimp->idx[i] = idx; - } - spin_unlock_irqrestore(&mgr->mgr_lock, flags); - if (err) { - printk(KERN_ERR "ctxfi: Can't meet SRCIMP resource request!\n"); - goto error1; - } - - err = srcimp_rsc_init(srcimp, desc, mgr); - if (err) - goto error1; - - *rsrcimp = srcimp; - - return 0; - -error1: - spin_lock_irqsave(&mgr->mgr_lock, flags); - for (i--; i >= 0; i--) - mgr_put_resource(&mgr->mgr, 1, srcimp->idx[i]); - - spin_unlock_irqrestore(&mgr->mgr_lock, flags); - kfree(srcimp); - return err; -} - -static int put_srcimp_rsc(struct srcimp_mgr *mgr, struct srcimp *srcimp) -{ - unsigned long flags; - int i; - - spin_lock_irqsave(&mgr->mgr_lock, flags); - for (i = 0; i < srcimp->rsc.msr; i++) - mgr_put_resource(&mgr->mgr, 1, srcimp->idx[i]); - - spin_unlock_irqrestore(&mgr->mgr_lock, flags); - srcimp_rsc_uninit(srcimp); - kfree(srcimp); - - return 0; -} - -static int srcimp_map_op(void *data, struct imapper *entry) -{ - struct rsc_mgr *mgr = &((struct srcimp_mgr *)data)->mgr; - struct hw *hw = mgr->hw; - - hw->srcimp_mgr_set_imaparc(mgr->ctrl_blk, entry->slot); - hw->srcimp_mgr_set_imapuser(mgr->ctrl_blk, entry->user); - hw->srcimp_mgr_set_imapnxt(mgr->ctrl_blk, entry->next); - hw->srcimp_mgr_set_imapaddr(mgr->ctrl_blk, entry->addr); - hw->srcimp_mgr_commit_write(mgr->hw, mgr->ctrl_blk); - - return 0; -} - -static int srcimp_imap_add(struct srcimp_mgr *mgr, struct imapper *entry) -{ - unsigned long flags; - int err; - - spin_lock_irqsave(&mgr->imap_lock, flags); - if ((0 == entry->addr) && (mgr->init_imap_added)) { - input_mapper_delete(&mgr->imappers, - mgr->init_imap, srcimp_map_op, mgr); - mgr->init_imap_added = 0; - } - err = input_mapper_add(&mgr->imappers, entry, srcimp_map_op, mgr); - spin_unlock_irqrestore(&mgr->imap_lock, flags); - - return err; -} - -static int srcimp_imap_delete(struct srcimp_mgr *mgr, struct imapper *entry) -{ - unsigned long flags; - int err; - - spin_lock_irqsave(&mgr->imap_lock, flags); - err = input_mapper_delete(&mgr->imappers, entry, srcimp_map_op, mgr); - if (list_empty(&mgr->imappers)) { - input_mapper_add(&mgr->imappers, mgr->init_imap, - srcimp_map_op, mgr); - mgr->init_imap_added = 1; - } - spin_unlock_irqrestore(&mgr->imap_lock, flags); - - return err; -} - -int srcimp_mgr_create(void *hw, struct srcimp_mgr **rsrcimp_mgr) -{ - int err; - struct srcimp_mgr *srcimp_mgr; - struct imapper *entry; - - *rsrcimp_mgr = NULL; - srcimp_mgr = kzalloc(sizeof(*srcimp_mgr), GFP_KERNEL); - if (NULL == srcimp_mgr) - return -ENOMEM; - - err = rsc_mgr_init(&srcimp_mgr->mgr, SRCIMP, SRCIMP_RESOURCE_NUM, hw); - if (err) - goto error1; - - spin_lock_init(&srcimp_mgr->mgr_lock); - spin_lock_init(&srcimp_mgr->imap_lock); - INIT_LIST_HEAD(&srcimp_mgr->imappers); - entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (NULL == entry) { - err = -ENOMEM; - goto error2; - } - entry->slot = entry->addr = entry->next = entry->user = 0; - list_add(&entry->list, &srcimp_mgr->imappers); - srcimp_mgr->init_imap = entry; - srcimp_mgr->init_imap_added = 1; - - srcimp_mgr->get_srcimp = get_srcimp_rsc; - srcimp_mgr->put_srcimp = put_srcimp_rsc; - srcimp_mgr->imap_add = srcimp_imap_add; - srcimp_mgr->imap_delete = srcimp_imap_delete; - - *rsrcimp_mgr = srcimp_mgr; - - return 0; - -error2: - rsc_mgr_uninit(&srcimp_mgr->mgr); -error1: - kfree(srcimp_mgr); - return err; -} - -int srcimp_mgr_destroy(struct srcimp_mgr *srcimp_mgr) -{ - unsigned long flags; - - /* free src input mapper list */ - spin_lock_irqsave(&srcimp_mgr->imap_lock, flags); - free_input_mapper_list(&srcimp_mgr->imappers); - spin_unlock_irqrestore(&srcimp_mgr->imap_lock, flags); - - rsc_mgr_uninit(&srcimp_mgr->mgr); - kfree(srcimp_mgr); - - return 0; -} diff --git a/trunk/sound/pci/ctxfi/ctsrc.h b/trunk/sound/pci/ctxfi/ctsrc.h deleted file mode 100644 index 259366aabcac..000000000000 --- a/trunk/sound/pci/ctxfi/ctsrc.h +++ /dev/null @@ -1,149 +0,0 @@ -/** - * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. - * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - * - * @File ctsrc.h - * - * @Brief - * This file contains the definition of the Sample Rate Convertor - * resource management object. - * - * @Author Liu Chun - * @Date May 13 2008 - * - */ - -#ifndef CTSRC_H -#define CTSRC_H - -#include "ctresource.h" -#include "ctimap.h" -#include -#include - -#define SRC_STATE_OFF 0x0 -#define SRC_STATE_INIT 0x4 -#define SRC_STATE_RUN 0x5 - -#define SRC_SF_U8 0x0 -#define SRC_SF_S16 0x1 -#define SRC_SF_S24 0x2 -#define SRC_SF_S32 0x3 -#define SRC_SF_F32 0x4 - -/* Define the descriptor of a src resource */ -enum SRCMODE { - MEMRD, /* Read data from host memory */ - MEMWR, /* Write data to host memory */ - ARCRW, /* Read from and write to audio ring channel */ - NUM_SRCMODES -}; - -struct src_rsc_ops; - -struct src { - struct rsc rsc; /* Basic resource info */ - struct src *intlv; /* Pointer to next interleaved SRC in a series */ - struct src_rsc_ops *ops; /* SRC specific operations */ - /* Number of contiguous srcs for interleaved usage */ - unsigned char multi; - unsigned char mode; /* Working mode of this SRC resource */ -}; - -struct src_rsc_ops { - int (*set_state)(struct src *src, unsigned int state); - int (*set_bm)(struct src *src, unsigned int bm); - int (*set_sf)(struct src *src, unsigned int sf); - int (*set_pm)(struct src *src, unsigned int pm); - int (*set_rom)(struct src *src, unsigned int rom); - int (*set_vo)(struct src *src, unsigned int vo); - int (*set_st)(struct src *src, unsigned int st); - int (*set_bp)(struct src *src, unsigned int bp); - int (*set_cisz)(struct src *src, unsigned int cisz); - int (*set_ca)(struct src *src, unsigned int ca); - int (*set_sa)(struct src *src, unsigned int sa); - int (*set_la)(struct src *src, unsigned int la); - int (*set_pitch)(struct src *src, unsigned int pitch); - int (*set_clr_zbufs)(struct src *src); - int (*commit_write)(struct src *src); - int (*get_ca)(struct src *src); - int (*init)(struct src *src); - struct src* (*next_interleave)(struct src *src); -}; - -/* Define src resource request description info */ -struct src_desc { - /* Number of contiguous master srcs for interleaved usage */ - unsigned char multi; - unsigned char msr; - unsigned char mode; /* Working mode of the requested srcs */ -}; - -/* Define src manager object */ -struct src_mgr { - struct rsc_mgr mgr; /* Basic resource manager info */ - spinlock_t mgr_lock; - - /* request src resource */ - int (*get_src)(struct src_mgr *mgr, - const struct src_desc *desc, struct src **rsrc); - /* return src resource */ - int (*put_src)(struct src_mgr *mgr, struct src *src); - int (*src_enable_s)(struct src_mgr *mgr, struct src *src); - int (*src_enable)(struct src_mgr *mgr, struct src *src); - int (*src_disable)(struct src_mgr *mgr, struct src *src); - int (*commit_write)(struct src_mgr *mgr); -}; - -/* Define the descriptor of a SRC Input Mapper resource */ -struct srcimp_mgr; -struct srcimp_rsc_ops; - -struct srcimp { - struct rsc rsc; - unsigned char idx[8]; - struct imapper *imappers; - unsigned int mapped; /* A bit-map indicating which conj rsc is mapped */ - struct srcimp_mgr *mgr; - struct srcimp_rsc_ops *ops; -}; - -struct srcimp_rsc_ops { - int (*map)(struct srcimp *srcimp, struct src *user, struct rsc *input); - int (*unmap)(struct srcimp *srcimp); -}; - -/* Define SRCIMP resource request description info */ -struct srcimp_desc { - unsigned int msr; -}; - -struct srcimp_mgr { - struct rsc_mgr mgr; /* Basic resource manager info */ - spinlock_t mgr_lock; - spinlock_t imap_lock; - struct list_head imappers; - struct imapper *init_imap; - unsigned int init_imap_added; - - /* request srcimp resource */ - int (*get_srcimp)(struct srcimp_mgr *mgr, - const struct srcimp_desc *desc, - struct srcimp **rsrcimp); - /* return srcimp resource */ - int (*put_srcimp)(struct srcimp_mgr *mgr, struct srcimp *srcimp); - int (*imap_add)(struct srcimp_mgr *mgr, struct imapper *entry); - int (*imap_delete)(struct srcimp_mgr *mgr, struct imapper *entry); -}; - -/* Constructor and destructor of SRC resource manager */ -int src_mgr_create(void *hw, struct src_mgr **rsrc_mgr); -int src_mgr_destroy(struct src_mgr *src_mgr); -/* Constructor and destructor of SRCIMP resource manager */ -int srcimp_mgr_create(void *hw, struct srcimp_mgr **rsrc_mgr); -int srcimp_mgr_destroy(struct srcimp_mgr *srcimp_mgr); - -#endif /* CTSRC_H */ diff --git a/trunk/sound/pci/ctxfi/cttimer.c b/trunk/sound/pci/ctxfi/cttimer.c deleted file mode 100644 index 93b0aedc36d4..000000000000 --- a/trunk/sound/pci/ctxfi/cttimer.c +++ /dev/null @@ -1,443 +0,0 @@ -/* - * PCM timer handling on ctxfi - * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - */ - -#include -#include -#include -#include -#include -#include "ctatc.h" -#include "cthardware.h" -#include "cttimer.h" - -static int use_system_timer; -MODULE_PARM_DESC(use_system_timer, "Foce to use system-timer"); -module_param(use_system_timer, bool, S_IRUGO); - -struct ct_timer_ops { - void (*init)(struct ct_timer_instance *); - void (*prepare)(struct ct_timer_instance *); - void (*start)(struct ct_timer_instance *); - void (*stop)(struct ct_timer_instance *); - void (*free_instance)(struct ct_timer_instance *); - void (*interrupt)(struct ct_timer *); - void (*free_global)(struct ct_timer *); -}; - -/* timer instance -- assigned to each PCM stream */ -struct ct_timer_instance { - spinlock_t lock; - struct ct_timer *timer_base; - struct ct_atc_pcm *apcm; - struct snd_pcm_substream *substream; - struct timer_list timer; - struct list_head instance_list; - struct list_head running_list; - unsigned int position; - unsigned int frag_count; - unsigned int running:1; - unsigned int need_update:1; -}; - -/* timer instance manager */ -struct ct_timer { - spinlock_t lock; /* global timer lock (for xfitimer) */ - spinlock_t list_lock; /* lock for instance list */ - struct ct_atc *atc; - struct ct_timer_ops *ops; - struct list_head instance_head; - struct list_head running_head; - unsigned int wc; /* current wallclock */ - unsigned int irq_handling:1; /* in IRQ handling */ - unsigned int reprogram:1; /* need to reprogram the internval */ - unsigned int running:1; /* global timer running */ -}; - - -/* - * system-timer-based updates - */ - -static void ct_systimer_callback(unsigned long data) -{ - struct ct_timer_instance *ti = (struct ct_timer_instance *)data; - struct snd_pcm_substream *substream = ti->substream; - struct snd_pcm_runtime *runtime = substream->runtime; - struct ct_atc_pcm *apcm = ti->apcm; - unsigned int period_size = runtime->period_size; - unsigned int buffer_size = runtime->buffer_size; - unsigned long flags; - unsigned int position, dist, interval; - - position = substream->ops->pointer(substream); - dist = (position + buffer_size - ti->position) % buffer_size; - if (dist >= period_size || - position / period_size != ti->position / period_size) { - apcm->interrupt(apcm); - ti->position = position; - } - /* Add extra HZ*5/1000 to avoid overrun issue when recording - * at 8kHz in 8-bit format or at 88kHz in 24-bit format. */ - interval = ((period_size - (position % period_size)) - * HZ + (runtime->rate - 1)) / runtime->rate + HZ * 5 / 1000; - spin_lock_irqsave(&ti->lock, flags); - if (ti->running) - mod_timer(&ti->timer, jiffies + interval); - spin_unlock_irqrestore(&ti->lock, flags); -} - -static void ct_systimer_init(struct ct_timer_instance *ti) -{ - setup_timer(&ti->timer, ct_systimer_callback, - (unsigned long)ti); -} - -static void ct_systimer_start(struct ct_timer_instance *ti) -{ - struct snd_pcm_runtime *runtime = ti->substream->runtime; - unsigned long flags; - - spin_lock_irqsave(&ti->lock, flags); - ti->running = 1; - mod_timer(&ti->timer, - jiffies + (runtime->period_size * HZ + - (runtime->rate - 1)) / runtime->rate); - spin_unlock_irqrestore(&ti->lock, flags); -} - -static void ct_systimer_stop(struct ct_timer_instance *ti) -{ - unsigned long flags; - - spin_lock_irqsave(&ti->lock, flags); - ti->running = 0; - del_timer(&ti->timer); - spin_unlock_irqrestore(&ti->lock, flags); -} - -static void ct_systimer_prepare(struct ct_timer_instance *ti) -{ - ct_systimer_stop(ti); - try_to_del_timer_sync(&ti->timer); -} - -#define ct_systimer_free ct_systimer_prepare - -static struct ct_timer_ops ct_systimer_ops = { - .init = ct_systimer_init, - .free_instance = ct_systimer_free, - .prepare = ct_systimer_prepare, - .start = ct_systimer_start, - .stop = ct_systimer_stop, -}; - - -/* - * Handling multiple streams using a global emu20k1 timer irq - */ - -#define CT_TIMER_FREQ 48000 -#define MIN_TICKS 1 -#define MAX_TICKS ((1 << 13) - 1) - -static void ct_xfitimer_irq_rearm(struct ct_timer *atimer, int ticks) -{ - struct hw *hw = atimer->atc->hw; - if (ticks > MAX_TICKS) - ticks = MAX_TICKS; - hw->set_timer_tick(hw, ticks); - if (!atimer->running) - hw->set_timer_irq(hw, 1); - atimer->running = 1; -} - -static void ct_xfitimer_irq_stop(struct ct_timer *atimer) -{ - if (atimer->running) { - struct hw *hw = atimer->atc->hw; - hw->set_timer_irq(hw, 0); - hw->set_timer_tick(hw, 0); - atimer->running = 0; - } -} - -static inline unsigned int ct_xfitimer_get_wc(struct ct_timer *atimer) -{ - struct hw *hw = atimer->atc->hw; - return hw->get_wc(hw); -} - -/* - * reprogram the timer interval; - * checks the running instance list and determines the next timer interval. - * also updates the each stream position, returns the number of streams - * to call snd_pcm_period_elapsed() appropriately - * - * call this inside the lock and irq disabled - */ -static int ct_xfitimer_reprogram(struct ct_timer *atimer, int can_update) -{ - struct ct_timer_instance *ti; - unsigned int min_intr = (unsigned int)-1; - int updates = 0; - unsigned int wc, diff; - - if (list_empty(&atimer->running_head)) { - ct_xfitimer_irq_stop(atimer); - atimer->reprogram = 0; /* clear flag */ - return 0; - } - - wc = ct_xfitimer_get_wc(atimer); - diff = wc - atimer->wc; - atimer->wc = wc; - list_for_each_entry(ti, &atimer->running_head, running_list) { - if (ti->frag_count > diff) - ti->frag_count -= diff; - else { - unsigned int pos; - unsigned int period_size, rate; - - period_size = ti->substream->runtime->period_size; - rate = ti->substream->runtime->rate; - pos = ti->substream->ops->pointer(ti->substream); - if (pos / period_size != ti->position / period_size) { - ti->need_update = 1; - ti->position = pos; - updates++; - } - pos %= period_size; - pos = period_size - pos; - ti->frag_count = div_u64((u64)pos * CT_TIMER_FREQ + - rate - 1, rate); - } - if (ti->need_update && !can_update) - min_intr = 0; /* pending to the next irq */ - if (ti->frag_count < min_intr) - min_intr = ti->frag_count; - } - - if (min_intr < MIN_TICKS) - min_intr = MIN_TICKS; - ct_xfitimer_irq_rearm(atimer, min_intr); - atimer->reprogram = 0; /* clear flag */ - return updates; -} - -/* look through the instance list and call period_elapsed if needed */ -static void ct_xfitimer_check_period(struct ct_timer *atimer) -{ - struct ct_timer_instance *ti; - unsigned long flags; - - spin_lock_irqsave(&atimer->list_lock, flags); - list_for_each_entry(ti, &atimer->instance_head, instance_list) { - if (ti->running && ti->need_update) { - ti->need_update = 0; - ti->apcm->interrupt(ti->apcm); - } - } - spin_unlock_irqrestore(&atimer->list_lock, flags); -} - -/* Handle timer-interrupt */ -static void ct_xfitimer_callback(struct ct_timer *atimer) -{ - int update; - unsigned long flags; - - spin_lock_irqsave(&atimer->lock, flags); - atimer->irq_handling = 1; - do { - update = ct_xfitimer_reprogram(atimer, 1); - spin_unlock(&atimer->lock); - if (update) - ct_xfitimer_check_period(atimer); - spin_lock(&atimer->lock); - } while (atimer->reprogram); - atimer->irq_handling = 0; - spin_unlock_irqrestore(&atimer->lock, flags); -} - -static void ct_xfitimer_prepare(struct ct_timer_instance *ti) -{ - ti->frag_count = ti->substream->runtime->period_size; - ti->running = 0; - ti->need_update = 0; -} - - -/* start/stop the timer */ -static void ct_xfitimer_update(struct ct_timer *atimer) -{ - unsigned long flags; - - spin_lock_irqsave(&atimer->lock, flags); - if (atimer->irq_handling) { - /* reached from IRQ handler; let it handle later */ - atimer->reprogram = 1; - spin_unlock_irqrestore(&atimer->lock, flags); - return; - } - - ct_xfitimer_irq_stop(atimer); - ct_xfitimer_reprogram(atimer, 0); - spin_unlock_irqrestore(&atimer->lock, flags); -} - -static void ct_xfitimer_start(struct ct_timer_instance *ti) -{ - struct ct_timer *atimer = ti->timer_base; - unsigned long flags; - - spin_lock_irqsave(&atimer->lock, flags); - if (list_empty(&ti->running_list)) - atimer->wc = ct_xfitimer_get_wc(atimer); - ti->running = 1; - ti->need_update = 0; - list_add(&ti->running_list, &atimer->running_head); - spin_unlock_irqrestore(&atimer->lock, flags); - ct_xfitimer_update(atimer); -} - -static void ct_xfitimer_stop(struct ct_timer_instance *ti) -{ - struct ct_timer *atimer = ti->timer_base; - unsigned long flags; - - spin_lock_irqsave(&atimer->lock, flags); - list_del_init(&ti->running_list); - ti->running = 0; - spin_unlock_irqrestore(&atimer->lock, flags); - ct_xfitimer_update(atimer); -} - -static void ct_xfitimer_free_global(struct ct_timer *atimer) -{ - ct_xfitimer_irq_stop(atimer); -} - -static struct ct_timer_ops ct_xfitimer_ops = { - .prepare = ct_xfitimer_prepare, - .start = ct_xfitimer_start, - .stop = ct_xfitimer_stop, - .interrupt = ct_xfitimer_callback, - .free_global = ct_xfitimer_free_global, -}; - -/* - * timer instance - */ - -struct ct_timer_instance * -ct_timer_instance_new(struct ct_timer *atimer, struct ct_atc_pcm *apcm) -{ - struct ct_timer_instance *ti; - - ti = kzalloc(sizeof(*ti), GFP_KERNEL); - if (!ti) - return NULL; - spin_lock_init(&ti->lock); - INIT_LIST_HEAD(&ti->instance_list); - INIT_LIST_HEAD(&ti->running_list); - ti->timer_base = atimer; - ti->apcm = apcm; - ti->substream = apcm->substream; - if (atimer->ops->init) - atimer->ops->init(ti); - - spin_lock_irq(&atimer->list_lock); - list_add(&ti->instance_list, &atimer->instance_head); - spin_unlock_irq(&atimer->list_lock); - - return ti; -} - -void ct_timer_prepare(struct ct_timer_instance *ti) -{ - if (ti->timer_base->ops->prepare) - ti->timer_base->ops->prepare(ti); - ti->position = 0; - ti->running = 0; -} - -void ct_timer_start(struct ct_timer_instance *ti) -{ - struct ct_timer *atimer = ti->timer_base; - atimer->ops->start(ti); -} - -void ct_timer_stop(struct ct_timer_instance *ti) -{ - struct ct_timer *atimer = ti->timer_base; - atimer->ops->stop(ti); -} - -void ct_timer_instance_free(struct ct_timer_instance *ti) -{ - struct ct_timer *atimer = ti->timer_base; - - atimer->ops->stop(ti); /* to be sure */ - if (atimer->ops->free_instance) - atimer->ops->free_instance(ti); - - spin_lock_irq(&atimer->list_lock); - list_del(&ti->instance_list); - spin_unlock_irq(&atimer->list_lock); - - kfree(ti); -} - -/* - * timer manager - */ - -static void ct_timer_interrupt(void *data, unsigned int status) -{ - struct ct_timer *timer = data; - - /* Interval timer interrupt */ - if ((status & IT_INT) && timer->ops->interrupt) - timer->ops->interrupt(timer); -} - -struct ct_timer *ct_timer_new(struct ct_atc *atc) -{ - struct ct_timer *atimer; - struct hw *hw; - - atimer = kzalloc(sizeof(*atimer), GFP_KERNEL); - if (!atimer) - return NULL; - spin_lock_init(&atimer->lock); - spin_lock_init(&atimer->list_lock); - INIT_LIST_HEAD(&atimer->instance_head); - INIT_LIST_HEAD(&atimer->running_head); - atimer->atc = atc; - hw = atc->hw; - if (!use_system_timer && hw->set_timer_irq) { - snd_printd(KERN_INFO "ctxfi: Use xfi-native timer\n"); - atimer->ops = &ct_xfitimer_ops; - hw->irq_callback_data = atimer; - hw->irq_callback = ct_timer_interrupt; - } else { - snd_printd(KERN_INFO "ctxfi: Use system timer\n"); - atimer->ops = &ct_systimer_ops; - } - return atimer; -} - -void ct_timer_free(struct ct_timer *atimer) -{ - struct hw *hw = atimer->atc->hw; - hw->irq_callback = NULL; - if (atimer->ops->free_global) - atimer->ops->free_global(atimer); - kfree(atimer); -} - diff --git a/trunk/sound/pci/ctxfi/cttimer.h b/trunk/sound/pci/ctxfi/cttimer.h deleted file mode 100644 index 979348229291..000000000000 --- a/trunk/sound/pci/ctxfi/cttimer.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Timer handling - */ - -#ifndef __CTTIMER_H -#define __CTTIMER_H - -#include -#include -#include - -struct snd_pcm_substream; -struct ct_atc; -struct ct_atc_pcm; - -struct ct_timer; -struct ct_timer_instance; - -struct ct_timer *ct_timer_new(struct ct_atc *atc); -void ct_timer_free(struct ct_timer *atimer); - -struct ct_timer_instance * -ct_timer_instance_new(struct ct_timer *atimer, struct ct_atc_pcm *apcm); -void ct_timer_instance_free(struct ct_timer_instance *ti); -void ct_timer_start(struct ct_timer_instance *ti); -void ct_timer_stop(struct ct_timer_instance *ti); -void ct_timer_prepare(struct ct_timer_instance *ti); - -#endif /* __CTTIMER_H */ diff --git a/trunk/sound/pci/ctxfi/ctvmem.c b/trunk/sound/pci/ctxfi/ctvmem.c deleted file mode 100644 index 67665a7e43c6..000000000000 --- a/trunk/sound/pci/ctxfi/ctvmem.c +++ /dev/null @@ -1,250 +0,0 @@ -/** - * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. - * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - * - * @File ctvmem.c - * - * @Brief - * This file contains the implementation of virtual memory management object - * for card device. - * - * @Author Liu Chun - * @Date Apr 1 2008 - */ - -#include "ctvmem.h" -#include -#include -#include -#include - -#define CT_PTES_PER_PAGE (CT_PAGE_SIZE / sizeof(void *)) -#define CT_ADDRS_PER_PAGE (CT_PTES_PER_PAGE * CT_PAGE_SIZE) - -/* * - * Find or create vm block based on requested @size. - * @size must be page aligned. - * */ -static struct ct_vm_block * -get_vm_block(struct ct_vm *vm, unsigned int size) -{ - struct ct_vm_block *block = NULL, *entry; - struct list_head *pos; - - size = CT_PAGE_ALIGN(size); - if (size > vm->size) { - printk(KERN_ERR "ctxfi: Fail! No sufficient device virtural " - "memory space available!\n"); - return NULL; - } - - mutex_lock(&vm->lock); - list_for_each(pos, &vm->unused) { - entry = list_entry(pos, struct ct_vm_block, list); - if (entry->size >= size) - break; /* found a block that is big enough */ - } - if (pos == &vm->unused) - goto out; - - if (entry->size == size) { - /* Move the vm node from unused list to used list directly */ - list_del(&entry->list); - list_add(&entry->list, &vm->used); - vm->size -= size; - block = entry; - goto out; - } - - block = kzalloc(sizeof(*block), GFP_KERNEL); - if (NULL == block) - goto out; - - block->addr = entry->addr; - block->size = size; - list_add(&block->list, &vm->used); - entry->addr += size; - entry->size -= size; - vm->size -= size; - - out: - mutex_unlock(&vm->lock); - return block; -} - -static void put_vm_block(struct ct_vm *vm, struct ct_vm_block *block) -{ - struct ct_vm_block *entry, *pre_ent; - struct list_head *pos, *pre; - - block->size = CT_PAGE_ALIGN(block->size); - - mutex_lock(&vm->lock); - list_del(&block->list); - vm->size += block->size; - - list_for_each(pos, &vm->unused) { - entry = list_entry(pos, struct ct_vm_block, list); - if (entry->addr >= (block->addr + block->size)) - break; /* found a position */ - } - if (pos == &vm->unused) { - list_add_tail(&block->list, &vm->unused); - entry = block; - } else { - if ((block->addr + block->size) == entry->addr) { - entry->addr = block->addr; - entry->size += block->size; - kfree(block); - } else { - __list_add(&block->list, pos->prev, pos); - entry = block; - } - } - - pos = &entry->list; - pre = pos->prev; - while (pre != &vm->unused) { - entry = list_entry(pos, struct ct_vm_block, list); - pre_ent = list_entry(pre, struct ct_vm_block, list); - if ((pre_ent->addr + pre_ent->size) > entry->addr) - break; - - pre_ent->size += entry->size; - list_del(pos); - kfree(entry); - pos = pre; - pre = pos->prev; - } - mutex_unlock(&vm->lock); -} - -/* Map host addr (kmalloced/vmalloced) to device logical addr. */ -static struct ct_vm_block * -ct_vm_map(struct ct_vm *vm, struct snd_pcm_substream *substream, int size) -{ - struct ct_vm_block *block; - unsigned int pte_start; - unsigned i, pages; - unsigned long *ptp; - - block = get_vm_block(vm, size); - if (block == NULL) { - printk(KERN_ERR "ctxfi: No virtual memory block that is big " - "enough to allocate!\n"); - return NULL; - } - - ptp = vm->ptp[0]; - pte_start = (block->addr >> CT_PAGE_SHIFT); - pages = block->size >> CT_PAGE_SHIFT; - for (i = 0; i < pages; i++) { - unsigned long addr; - addr = snd_pcm_sgbuf_get_addr(substream, i << CT_PAGE_SHIFT); - ptp[pte_start + i] = addr; - } - - block->size = size; - return block; -} - -static void ct_vm_unmap(struct ct_vm *vm, struct ct_vm_block *block) -{ - /* do unmapping */ - put_vm_block(vm, block); -} - -/* * - * return the host (kmalloced) addr of the @index-th device - * page talbe page on success, or NULL on failure. - * The first returned NULL indicates the termination. - * */ -static void * -ct_get_ptp_virt(struct ct_vm *vm, int index) -{ - void *addr; - - addr = (index >= CT_PTP_NUM) ? NULL : vm->ptp[index]; - - return addr; -} - -int ct_vm_create(struct ct_vm **rvm) -{ - struct ct_vm *vm; - struct ct_vm_block *block; - int i; - - *rvm = NULL; - - vm = kzalloc(sizeof(*vm), GFP_KERNEL); - if (NULL == vm) - return -ENOMEM; - - mutex_init(&vm->lock); - - /* Allocate page table pages */ - for (i = 0; i < CT_PTP_NUM; i++) { - vm->ptp[i] = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (NULL == vm->ptp[i]) - break; - } - if (!i) { - /* no page table pages are allocated */ - kfree(vm); - return -ENOMEM; - } - vm->size = CT_ADDRS_PER_PAGE * i; - /* Initialise remaining ptps */ - for (; i < CT_PTP_NUM; i++) - vm->ptp[i] = NULL; - - vm->map = ct_vm_map; - vm->unmap = ct_vm_unmap; - vm->get_ptp_virt = ct_get_ptp_virt; - INIT_LIST_HEAD(&vm->unused); - INIT_LIST_HEAD(&vm->used); - block = kzalloc(sizeof(*block), GFP_KERNEL); - if (NULL != block) { - block->addr = 0; - block->size = vm->size; - list_add(&block->list, &vm->unused); - } - - *rvm = vm; - return 0; -} - -/* The caller must ensure no mapping pages are being used - * by hardware before calling this function */ -void ct_vm_destroy(struct ct_vm *vm) -{ - int i; - struct list_head *pos; - struct ct_vm_block *entry; - - /* free used and unused list nodes */ - while (!list_empty(&vm->used)) { - pos = vm->used.next; - list_del(pos); - entry = list_entry(pos, struct ct_vm_block, list); - kfree(entry); - } - while (!list_empty(&vm->unused)) { - pos = vm->unused.next; - list_del(pos); - entry = list_entry(pos, struct ct_vm_block, list); - kfree(entry); - } - - /* free allocated page table pages */ - for (i = 0; i < CT_PTP_NUM; i++) - kfree(vm->ptp[i]); - - vm->size = 0; - - kfree(vm); -} diff --git a/trunk/sound/pci/ctxfi/ctvmem.h b/trunk/sound/pci/ctxfi/ctvmem.h deleted file mode 100644 index 01e4fd0386a3..000000000000 --- a/trunk/sound/pci/ctxfi/ctvmem.h +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. - * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - * - * @File ctvmem.h - * - * @Brief - * This file contains the definition of virtual memory management object - * for card device. - * - * @Author Liu Chun - * @Date Mar 28 2008 - */ - -#ifndef CTVMEM_H -#define CTVMEM_H - -#define CT_PTP_NUM 1 /* num of device page table pages */ - -#include -#include - -/* The chip can handle the page table of 4k pages - * (emu20k1 can handle even 8k pages, but we don't use it right now) - */ -#define CT_PAGE_SIZE 4096 -#define CT_PAGE_SHIFT 12 -#define CT_PAGE_MASK (~(PAGE_SIZE - 1)) -#define CT_PAGE_ALIGN(addr) ALIGN(addr, CT_PAGE_SIZE) - -struct ct_vm_block { - unsigned int addr; /* starting logical addr of this block */ - unsigned int size; /* size of this device virtual mem block */ - struct list_head list; -}; - -struct snd_pcm_substream; - -/* Virtual memory management object for card device */ -struct ct_vm { - void *ptp[CT_PTP_NUM]; /* Device page table pages */ - unsigned int size; /* Available addr space in bytes */ - struct list_head unused; /* List of unused blocks */ - struct list_head used; /* List of used blocks */ - struct mutex lock; - - /* Map host addr (kmalloced/vmalloced) to device logical addr. */ - struct ct_vm_block *(*map)(struct ct_vm *, struct snd_pcm_substream *, - int size); - /* Unmap device logical addr area. */ - void (*unmap)(struct ct_vm *, struct ct_vm_block *block); - void *(*get_ptp_virt)(struct ct_vm *vm, int index); -}; - -int ct_vm_create(struct ct_vm **rvm); -void ct_vm_destroy(struct ct_vm *vm); - -#endif /* CTVMEM_H */ diff --git a/trunk/sound/pci/ctxfi/xfi.c b/trunk/sound/pci/ctxfi/xfi.c deleted file mode 100644 index 76541748e7bc..000000000000 --- a/trunk/sound/pci/ctxfi/xfi.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * xfi linux driver. - * - * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. - * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - */ - -#include -#include -#include -#include -#include -#include -#include "ctatc.h" -#include "cthardware.h" - -MODULE_AUTHOR("Creative Technology Ltd"); -MODULE_DESCRIPTION("X-Fi driver version 1.03"); -MODULE_LICENSE("GPL v2"); -MODULE_SUPPORTED_DEVICE("{{Creative Labs, Sound Blaster X-Fi}"); - -static unsigned int reference_rate = 48000; -static unsigned int multiple = 2; -MODULE_PARM_DESC(reference_rate, "Reference rate (default=48000)"); -module_param(reference_rate, uint, S_IRUGO); -MODULE_PARM_DESC(multiple, "Rate multiplier (default=2)"); -module_param(multiple, uint, S_IRUGO); - -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; -static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; - -module_param_array(index, int, NULL, 0444); -MODULE_PARM_DESC(index, "Index value for Creative X-Fi driver"); -module_param_array(id, charp, NULL, 0444); -MODULE_PARM_DESC(id, "ID string for Creative X-Fi driver"); -module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(enable, "Enable Creative X-Fi driver"); - -static struct pci_device_id ct_pci_dev_ids[] = { - /* only X-Fi is supported, so... */ - { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_20K1), - .driver_data = ATC20K1, - }, - { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_20K2), - .driver_data = ATC20K2, - }, - { 0, } -}; -MODULE_DEVICE_TABLE(pci, ct_pci_dev_ids); - -static int __devinit -ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) -{ - static int dev; - struct snd_card *card; - struct ct_atc *atc; - int err; - - if (dev >= SNDRV_CARDS) - return -ENODEV; - - if (!enable[dev]) { - dev++; - return -ENOENT; - } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); - if (err) - return err; - if ((reference_rate != 48000) && (reference_rate != 44100)) { - printk(KERN_ERR "ctxfi: Invalid reference_rate value %u!!!\n", - reference_rate); - printk(KERN_ERR "ctxfi: The valid values for reference_rate " - "are 48000 and 44100, Value 48000 is assumed.\n"); - reference_rate = 48000; - } - if ((multiple != 1) && (multiple != 2)) { - printk(KERN_ERR "ctxfi: Invalid multiple value %u!!!\n", - multiple); - printk(KERN_ERR "ctxfi: The valid values for multiple are " - "1 and 2, Value 2 is assumed.\n"); - multiple = 2; - } - err = ct_atc_create(card, pci, reference_rate, multiple, - pci_id->driver_data, &atc); - if (err < 0) - goto error; - - card->private_data = atc; - - /* Create alsa devices supported by this card */ - err = ct_atc_create_alsa_devs(atc); - if (err < 0) - goto error; - - strcpy(card->driver, "SB-XFi"); - strcpy(card->shortname, "Creative X-Fi"); - snprintf(card->longname, sizeof(card->longname), "%s %s %s", - card->shortname, atc->chip_name, atc->model_name); - - err = snd_card_register(card); - if (err < 0) - goto error; - - pci_set_drvdata(pci, card); - dev++; - - return 0; - -error: - snd_card_free(card); - return err; -} - -static void __devexit ct_card_remove(struct pci_dev *pci) -{ - snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); -} - -#ifdef CONFIG_PM -static int ct_card_suspend(struct pci_dev *pci, pm_message_t state) -{ - struct snd_card *card = pci_get_drvdata(pci); - struct ct_atc *atc = card->private_data; - - return atc->suspend(atc, state); -} - -static int ct_card_resume(struct pci_dev *pci) -{ - struct snd_card *card = pci_get_drvdata(pci); - struct ct_atc *atc = card->private_data; - - return atc->resume(atc); -} -#endif - -static struct pci_driver ct_driver = { - .name = "SB-XFi", - .id_table = ct_pci_dev_ids, - .probe = ct_card_probe, - .remove = __devexit_p(ct_card_remove), -#ifdef CONFIG_PM - .suspend = ct_card_suspend, - .resume = ct_card_resume, -#endif -}; - -static int __init ct_card_init(void) -{ - return pci_register_driver(&ct_driver); -} - -static void __exit ct_card_exit(void) -{ - pci_unregister_driver(&ct_driver); -} - -module_init(ct_card_init) -module_exit(ct_card_exit) diff --git a/trunk/sound/pci/emu10k1/Makefile b/trunk/sound/pci/emu10k1/Makefile index fc5591e7777e..cf2d5636d8be 100644 --- a/trunk/sound/pci/emu10k1/Makefile +++ b/trunk/sound/pci/emu10k1/Makefile @@ -9,7 +9,15 @@ snd-emu10k1-objs := emu10k1.o emu10k1_main.o \ snd-emu10k1-synth-objs := emu10k1_synth.o emu10k1_callback.o emu10k1_patch.o snd-emu10k1x-objs := emu10k1x.o +# +# this function returns: +# "m" - CONFIG_SND_SEQUENCER is m +# - CONFIG_SND_SEQUENCER is undefined +# otherwise parameter #1 value +# +sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) + # Toplevel Module Dependency obj-$(CONFIG_SND_EMU10K1) += snd-emu10k1.o -obj-$(CONFIG_SND_EMU10K1_SEQ) += snd-emu10k1-synth.o +obj-$(call sequencer,$(CONFIG_SND_EMU10K1)) += snd-emu10k1-synth.o obj-$(CONFIG_SND_EMU10K1X) += snd-emu10k1x.o diff --git a/trunk/sound/pci/emu10k1/emu10k1x.c b/trunk/sound/pci/emu10k1/emu10k1x.c index 4d3ad793e98f..1970f0e70f37 100644 --- a/trunk/sound/pci/emu10k1/emu10k1x.c +++ b/trunk/sound/pci/emu10k1/emu10k1x.c @@ -858,6 +858,7 @@ static int __devinit snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct s } pcm->info_flags = 0; + pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; switch(device) { case 0: strcpy(pcm->name, "EMU10K1X Front"); diff --git a/trunk/sound/pci/emu10k1/emupcm.c b/trunk/sound/pci/emu10k1/emupcm.c index 55b83ef73c63..78f62fd404c2 100644 --- a/trunk/sound/pci/emu10k1/emupcm.c +++ b/trunk/sound/pci/emu10k1/emupcm.c @@ -1736,7 +1736,7 @@ static struct snd_pcm_hardware snd_emu10k1_fx8010_playback = .buffer_bytes_max = (128*1024), .period_bytes_min = 1024, .period_bytes_max = (128*1024), - .periods_min = 2, + .periods_min = 1, .periods_max = 1024, .fifo_size = 0, }; diff --git a/trunk/sound/pci/hda/Kconfig b/trunk/sound/pci/hda/Kconfig index 04438f1d682d..eb2a19b894a0 100644 --- a/trunk/sound/pci/hda/Kconfig +++ b/trunk/sound/pci/hda/Kconfig @@ -2,6 +2,7 @@ menuconfig SND_HDA_INTEL tristate "Intel HD Audio" select SND_PCM select SND_VMASTER + select SND_JACK if INPUT=y || INPUT=SND help Say Y here to include support for Intel "High Definition Audio" (Azalia) and its compatible devices. @@ -38,14 +39,6 @@ config SND_HDA_INPUT_BEEP Say Y here to build a digital beep interface for HD-audio driver. This interface is used to generate digital beeps. -config SND_HDA_INPUT_JACK - bool "Support jack plugging notification via input layer" - depends on INPUT=y || INPUT=SND_HDA_INTEL - select SND_JACK - help - Say Y here to enable the jack plugging notification via - input layer. - config SND_HDA_CODEC_REALTEK bool "Build Realtek HD-audio codec support" default y @@ -146,19 +139,6 @@ config SND_HDA_CODEC_CONEXANT snd-hda-codec-conexant. This module is automatically loaded at probing. -config SND_HDA_CODEC_CA0110 - bool "Build Creative CA0110-IBG codec support" - depends on SND_HDA_INTEL - default y - help - Say Y here to include Creative CA0110-IBG codec support in - snd-hda-intel driver, found on some Creative X-Fi cards. - - When the HD-audio driver is built as a module, the codec - support code is also built as another module, - snd-hda-codec-ca0110. - This module is automatically loaded at probing. - config SND_HDA_CODEC_CMEDIA bool "Build C-Media HD-audio codec support" default y diff --git a/trunk/sound/pci/hda/Makefile b/trunk/sound/pci/hda/Makefile index e3081d4586cc..50f9d0967251 100644 --- a/trunk/sound/pci/hda/Makefile +++ b/trunk/sound/pci/hda/Makefile @@ -13,7 +13,6 @@ snd-hda-codec-analog-objs := patch_analog.o snd-hda-codec-idt-objs := patch_sigmatel.o snd-hda-codec-si3054-objs := patch_si3054.o snd-hda-codec-atihdmi-objs := patch_atihdmi.o -snd-hda-codec-ca0110-objs := patch_ca0110.o snd-hda-codec-conexant-objs := patch_conexant.o snd-hda-codec-via-objs := patch_via.o snd-hda-codec-nvhdmi-objs := patch_nvhdmi.o @@ -41,9 +40,6 @@ endif ifdef CONFIG_SND_HDA_CODEC_ATIHDMI obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o endif -ifdef CONFIG_SND_HDA_CODEC_CA0110 -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0110.o -endif ifdef CONFIG_SND_HDA_CODEC_CONEXANT obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-conexant.o endif diff --git a/trunk/sound/pci/hda/hda_beep.c b/trunk/sound/pci/hda/hda_beep.c index 29272f2e95a0..4de5bacd3929 100644 --- a/trunk/sound/pci/hda/hda_beep.c +++ b/trunk/sound/pci/hda/hda_beep.c @@ -45,46 +45,6 @@ static void snd_hda_generate_beep(struct work_struct *work) AC_VERB_SET_BEEP_CONTROL, beep->tone); } -/* (non-standard) Linear beep tone calculation for IDT/STAC codecs - * - * The tone frequency of beep generator on IDT/STAC codecs is - * defined from the 8bit tone parameter, in Hz, - * freq = 48000 * (257 - tone) / 1024 - * that is from 12kHz to 93.75kHz in step of 46.875 hz - */ -static int beep_linear_tone(struct hda_beep *beep, int hz) -{ - hz *= 1000; /* fixed point */ - hz = hz - DIGBEEP_HZ_MIN; - if (hz < 0) - hz = 0; /* turn off PC beep*/ - else if (hz >= (DIGBEEP_HZ_MAX - DIGBEEP_HZ_MIN)) - hz = 0xff; - else { - hz /= DIGBEEP_HZ_STEP; - hz++; - } - return hz; -} - -/* HD-audio standard beep tone parameter calculation - * - * The tone frequency in Hz is calculated as - * freq = 48000 / (tone * 4) - * from 47Hz to 12kHz - */ -static int beep_standard_tone(struct hda_beep *beep, int hz) -{ - if (hz <= 0) - return 0; /* disabled */ - hz = 12000 / hz; - if (hz > 0xff) - return 0xff; - if (hz <= 0) - return 1; - return hz; -} - static int snd_hda_beep_event(struct input_dev *dev, unsigned int type, unsigned int code, int hz) { @@ -95,14 +55,21 @@ static int snd_hda_beep_event(struct input_dev *dev, unsigned int type, if (hz) hz = 1000; case SND_TONE: - if (beep->linear_tone) - beep->tone = beep_linear_tone(beep, hz); - else - beep->tone = beep_standard_tone(beep, hz); + hz *= 1000; /* fixed point */ + hz = hz - DIGBEEP_HZ_MIN; + if (hz < 0) + hz = 0; /* turn off PC beep*/ + else if (hz >= (DIGBEEP_HZ_MAX - DIGBEEP_HZ_MIN)) + hz = 0xff; + else { + hz /= DIGBEEP_HZ_STEP; + hz++; + } break; default: return -1; } + beep->tone = hz; /* schedule beep event */ schedule_work(&beep->beep_work); diff --git a/trunk/sound/pci/hda/hda_beep.h b/trunk/sound/pci/hda/hda_beep.h index 0c3de787c717..51bf6a5daf39 100644 --- a/trunk/sound/pci/hda/hda_beep.h +++ b/trunk/sound/pci/hda/hda_beep.h @@ -30,9 +30,8 @@ struct hda_beep { struct hda_codec *codec; char phys[32]; int tone; - hda_nid_t nid; - unsigned int enabled:1; - unsigned int linear_tone:1; /* linear tone for IDT/STAC codec */ + int nid; + int enabled; struct work_struct beep_work; /* scheduled task for beep event */ }; diff --git a/trunk/sound/pci/hda/hda_codec.c b/trunk/sound/pci/hda/hda_codec.c index 462e2cedaa6a..8820faf6c9d8 100644 --- a/trunk/sound/pci/hda/hda_codec.c +++ b/trunk/sound/pci/hda/hda_codec.c @@ -48,7 +48,6 @@ static struct hda_vendor_id hda_vendor_ids[] = { { 0x1095, "Silicon Image" }, { 0x10de, "Nvidia" }, { 0x10ec, "Realtek" }, - { 0x1102, "Creative" }, { 0x1106, "VIA" }, { 0x111d, "IDT" }, { 0x11c1, "LSI" }, @@ -158,39 +157,6 @@ make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct, return val; } -/* - * Send and receive a verb - */ -static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, - unsigned int *res) -{ - struct hda_bus *bus = codec->bus; - int err; - - if (res) - *res = -1; - again: - snd_hda_power_up(codec); - mutex_lock(&bus->cmd_mutex); - err = bus->ops.command(bus, cmd); - if (!err && res) - *res = bus->ops.get_response(bus); - mutex_unlock(&bus->cmd_mutex); - snd_hda_power_down(codec); - if (res && *res == -1 && bus->rirb_error) { - if (bus->response_reset) { - snd_printd("hda_codec: resetting BUS due to " - "fatal communication error\n"); - bus->ops.bus_reset(bus); - } - goto again; - } - /* clear reset-flag when the communication gets recovered */ - if (!err) - bus->response_reset = 0; - return err; -} - /** * snd_hda_codec_read - send a command and get the response * @codec: the HDA codec @@ -207,9 +173,18 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm) { - unsigned cmd = make_codec_cmd(codec, nid, direct, verb, parm); + struct hda_bus *bus = codec->bus; unsigned int res; - codec_exec_verb(codec, cmd, &res); + + res = make_codec_cmd(codec, nid, direct, verb, parm); + snd_hda_power_up(codec); + mutex_lock(&bus->cmd_mutex); + if (!bus->ops.command(bus, res)) + res = bus->ops.get_response(bus); + else + res = (unsigned int)-1; + mutex_unlock(&bus->cmd_mutex); + snd_hda_power_down(codec); return res; } EXPORT_SYMBOL_HDA(snd_hda_codec_read); @@ -229,10 +204,17 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_read); int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm) { - unsigned int cmd = make_codec_cmd(codec, nid, direct, verb, parm); + struct hda_bus *bus = codec->bus; unsigned int res; - return codec_exec_verb(codec, cmd, - codec->bus->sync_write ? &res : NULL); + int err; + + res = make_codec_cmd(codec, nid, direct, verb, parm); + snd_hda_power_up(codec); + mutex_lock(&bus->cmd_mutex); + err = bus->ops.command(bus, res); + mutex_unlock(&bus->cmd_mutex); + snd_hda_power_down(codec); + return err; } EXPORT_SYMBOL_HDA(snd_hda_codec_write); @@ -631,10 +613,7 @@ static int get_codec_name(struct hda_codec *codec) const struct hda_vendor_id *c; const char *vendor = NULL; u16 vendor_id = codec->vendor_id >> 16; - char tmp[16]; - - if (codec->vendor_name) - goto get_chip_name; + char tmp[16], name[32]; for (c = hda_vendor_ids; c->id; c++) { if (c->id == vendor_id) { @@ -646,21 +625,14 @@ static int get_codec_name(struct hda_codec *codec) sprintf(tmp, "Generic %04x", vendor_id); vendor = tmp; } - codec->vendor_name = kstrdup(vendor, GFP_KERNEL); - if (!codec->vendor_name) - return -ENOMEM; - - get_chip_name: - if (codec->chip_name) - return 0; - if (codec->preset && codec->preset->name) - codec->chip_name = kstrdup(codec->preset->name, GFP_KERNEL); - else { - sprintf(tmp, "ID %x", codec->vendor_id & 0xffff); - codec->chip_name = kstrdup(tmp, GFP_KERNEL); - } - if (!codec->chip_name) + snprintf(name, sizeof(name), "%s %s", vendor, + codec->preset->name); + else + snprintf(name, sizeof(name), "%s ID %x", vendor, + codec->vendor_id & 0xffff); + codec->name = kstrdup(name, GFP_KERNEL); + if (!codec->name) return -ENOMEM; return 0; } @@ -866,8 +838,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) module_put(codec->owner); free_hda_cache(&codec->amp_cache); free_hda_cache(&codec->cmd_cache); - kfree(codec->vendor_name); - kfree(codec->chip_name); + kfree(codec->name); kfree(codec->modelname); kfree(codec->wcaps); kfree(codec); @@ -972,6 +943,8 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_SUBSYSTEM_ID, 0); } + if (bus->modelname) + codec->modelname = kstrdup(bus->modelname, GFP_KERNEL); /* power-up all before initialization */ hda_set_power_state(codec, @@ -1006,16 +979,15 @@ int snd_hda_codec_configure(struct hda_codec *codec) int err; codec->preset = find_codec_preset(codec); - if (!codec->vendor_name || !codec->chip_name) { + if (!codec->name) { err = get_codec_name(codec); if (err < 0) return err; } /* audio codec should override the mixer name */ if (codec->afg || !*codec->bus->card->mixername) - snprintf(codec->bus->card->mixername, - sizeof(codec->bus->card->mixername), - "%s %s", codec->vendor_name, codec->chip_name); + strlcpy(codec->bus->card->mixername, codec->name, + sizeof(codec->bus->card->mixername)); if (is_generic_config(codec)) { err = snd_hda_parse_generic_codec(codec); @@ -1083,8 +1055,6 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup_stream); /* FIXME: more better hash key? */ #define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24)) #define HDA_HASH_PINCAP_KEY(nid) (u32)((nid) + (0x02 << 24)) -#define HDA_HASH_PARPCM_KEY(nid) (u32)((nid) + (0x03 << 24)) -#define HDA_HASH_PARSTR_KEY(nid) (u32)((nid) + (0x04 << 24)) #define INFO_AMP_CAPS (1<<0) #define INFO_AMP_VOL(ch) (1 << (1 + (ch))) @@ -1175,32 +1145,19 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, } EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps); -static unsigned int -query_caps_hash(struct hda_codec *codec, hda_nid_t nid, u32 key, - unsigned int (*func)(struct hda_codec *, hda_nid_t)) +u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid) { struct hda_amp_info *info; - info = get_alloc_amp_hash(codec, key); + info = get_alloc_amp_hash(codec, HDA_HASH_PINCAP_KEY(nid)); if (!info) return 0; if (!info->head.val) { + info->amp_caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); info->head.val |= INFO_AMP_CAPS; - info->amp_caps = func(codec, nid); } return info->amp_caps; } - -static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid) -{ - return snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); -} - -u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid) -{ - return query_caps_hash(codec, nid, HDA_HASH_PINCAP_KEY(nid), - read_pin_cap); -} EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps); /* @@ -1475,8 +1432,6 @@ _snd_hda_find_mixer_ctl(struct hda_codec *codec, memset(&id, 0, sizeof(id)); id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; id.index = idx; - if (snd_BUG_ON(strlen(name) >= sizeof(id.name))) - return NULL; strcpy(id.name, name); return snd_ctl_find_id(codec->bus->card, &id); } @@ -2287,22 +2242,28 @@ EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls); int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm) { - int err = snd_hda_codec_write(codec, nid, direct, verb, parm); - struct hda_cache_head *c; - u32 key; + struct hda_bus *bus = codec->bus; + unsigned int res; + int err; - if (err < 0) - return err; - /* parm may contain the verb stuff for get/set amp */ - verb = verb | (parm >> 8); - parm &= 0xff; - key = build_cmd_cache_key(nid, verb); - mutex_lock(&codec->bus->cmd_mutex); - c = get_alloc_hash(&codec->cmd_cache, key); - if (c) - c->val = parm; - mutex_unlock(&codec->bus->cmd_mutex); - return 0; + res = make_codec_cmd(codec, nid, direct, verb, parm); + snd_hda_power_up(codec); + mutex_lock(&bus->cmd_mutex); + err = bus->ops.command(bus, res); + if (!err) { + struct hda_cache_head *c; + u32 key; + /* parm may contain the verb stuff for get/set amp */ + verb = verb | (parm >> 8); + parm &= 0xff; + key = build_cmd_cache_key(nid, verb); + c = get_alloc_hash(&codec->cmd_cache, key); + if (c) + c->val = parm; + } + mutex_unlock(&bus->cmd_mutex); + snd_hda_power_down(codec); + return err; } EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache); @@ -2360,8 +2321,7 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, if (wcaps & AC_WCAP_POWER) { unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; - if (power_state == AC_PWRST_D3 && - wid_type == AC_WID_PIN) { + if (wid_type == AC_WID_PIN) { unsigned int pincap; /* * don't power down the widget if it controls @@ -2373,7 +2333,7 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, nid, 0, AC_VERB_GET_EAPD_BTLENABLE, 0); eapd &= 0x02; - if (eapd) + if (power_state == AC_PWRST_D3 && eapd) continue; } } @@ -2584,41 +2544,6 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, } EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format); -static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid) -{ - unsigned int val = 0; - if (nid != codec->afg && - (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) - val = snd_hda_param_read(codec, nid, AC_PAR_PCM); - if (!val || val == -1) - val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM); - if (!val || val == -1) - return 0; - return val; -} - -static unsigned int query_pcm_param(struct hda_codec *codec, hda_nid_t nid) -{ - return query_caps_hash(codec, nid, HDA_HASH_PARPCM_KEY(nid), - get_pcm_param); -} - -static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid) -{ - unsigned int streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM); - if (!streams || streams == -1) - streams = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM); - if (!streams || streams == -1) - return 0; - return streams; -} - -static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid) -{ - return query_caps_hash(codec, nid, HDA_HASH_PARSTR_KEY(nid), - get_stream_param); -} - /** * snd_hda_query_supported_pcm - query the supported PCM rates and formats * @codec: the HDA codec @@ -2637,8 +2562,15 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, { unsigned int i, val, wcaps; + val = 0; wcaps = get_wcaps(codec, nid); - val = query_pcm_param(codec, nid); + if (nid != codec->afg && (wcaps & AC_WCAP_FORMAT_OVRD)) { + val = snd_hda_param_read(codec, nid, AC_PAR_PCM); + if (val == -1) + return -EIO; + } + if (!val) + val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM); if (ratesp) { u32 rates = 0; @@ -2660,9 +2592,15 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, u64 formats = 0; unsigned int streams, bps; - streams = query_stream_param(codec, nid); - if (!streams) + streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM); + if (streams == -1) return -EIO; + if (!streams) { + streams = snd_hda_param_read(codec, codec->afg, + AC_PAR_STREAM); + if (streams == -1) + return -EIO; + } bps = 0; if (streams & AC_SUPFMT_PCM) { @@ -2736,9 +2674,17 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, int i; unsigned int val = 0, rate, stream; - val = query_pcm_param(codec, nid); - if (!val) - return 0; + if (nid != codec->afg && + (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) { + val = snd_hda_param_read(codec, nid, AC_PAR_PCM); + if (val == -1) + return 0; + } + if (!val) { + val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM); + if (val == -1) + return 0; + } rate = format & 0xff00; for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++) @@ -2750,8 +2696,12 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, if (i >= AC_PAR_PCM_RATE_BITS) return 0; - stream = query_stream_param(codec, nid); - if (!stream) + stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM); + if (stream == -1) + return 0; + if (!stream && nid != codec->afg) + stream = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM); + if (!stream || stream == -1) return 0; if (stream & AC_SUPFMT_PCM) { @@ -3885,10 +3835,11 @@ EXPORT_SYMBOL_HDA(auto_pin_cfg_labels); /** * snd_hda_suspend - suspend the codecs * @bus: the HDA bus + * @state: suspsend state * * Returns 0 if successful. */ -int snd_hda_suspend(struct hda_bus *bus) +int snd_hda_suspend(struct hda_bus *bus, pm_message_t state) { struct hda_codec *codec; diff --git a/trunk/sound/pci/hda/hda_codec.h b/trunk/sound/pci/hda/hda_codec.h index cad79efaabc9..2fdecf4b0eb6 100644 --- a/trunk/sound/pci/hda/hda_codec.h +++ b/trunk/sound/pci/hda/hda_codec.h @@ -574,8 +574,6 @@ struct hda_bus_ops { /* attach a PCM stream */ int (*attach_pcm)(struct hda_bus *bus, struct hda_codec *codec, struct hda_pcm *pcm); - /* reset bus for retry verb */ - void (*bus_reset)(struct hda_bus *bus); #ifdef CONFIG_SND_HDA_POWER_SAVE /* notify power-up/down from codec to controller */ void (*pm_notify)(struct hda_bus *bus); @@ -624,13 +622,7 @@ struct hda_bus { /* misc op flags */ unsigned int needs_damn_long_delay :1; - unsigned int allow_bus_reset:1; /* allow bus reset at fatal error */ - unsigned int sync_write:1; /* sync after verb write */ - /* status for codec/controller */ unsigned int shutdown :1; /* being unloaded */ - unsigned int rirb_error:1; /* error in codec communication */ - unsigned int response_reset:1; /* controller was reset */ - unsigned int in_reset:1; /* during reset operation */ }; /* @@ -755,8 +747,7 @@ struct hda_codec { /* detected preset */ const struct hda_codec_preset *preset; struct module *owner; - const char *vendor_name; /* codec vendor name */ - const char *chip_name; /* codec chip name */ + const char *name; /* codec name */ const char *modelname; /* model name for preset */ /* set by patch */ @@ -914,7 +905,7 @@ void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen); * power management */ #ifdef CONFIG_PM -int snd_hda_suspend(struct hda_bus *bus); +int snd_hda_suspend(struct hda_bus *bus, pm_message_t state); int snd_hda_resume(struct hda_bus *bus); #endif diff --git a/trunk/sound/pci/hda/hda_hwdep.c b/trunk/sound/pci/hda/hda_hwdep.c index 6812fbe80fa4..1c57505c2874 100644 --- a/trunk/sound/pci/hda/hda_hwdep.c +++ b/trunk/sound/pci/hda/hda_hwdep.c @@ -242,8 +242,7 @@ CODEC_INFO_SHOW(subsystem_id); CODEC_INFO_SHOW(revision_id); CODEC_INFO_SHOW(afg); CODEC_INFO_SHOW(mfg); -CODEC_INFO_STR_SHOW(vendor_name); -CODEC_INFO_STR_SHOW(chip_name); +CODEC_INFO_STR_SHOW(name); CODEC_INFO_STR_SHOW(modelname); #define CODEC_INFO_STORE(type) \ @@ -276,8 +275,7 @@ static ssize_t type##_store(struct device *dev, \ CODEC_INFO_STORE(vendor_id); CODEC_INFO_STORE(subsystem_id); CODEC_INFO_STORE(revision_id); -CODEC_INFO_STR_STORE(vendor_name); -CODEC_INFO_STR_STORE(chip_name); +CODEC_INFO_STR_STORE(name); CODEC_INFO_STR_STORE(modelname); #define CODEC_ACTION_STORE(type) \ @@ -501,8 +499,7 @@ static struct device_attribute codec_attrs[] = { CODEC_ATTR_RW(revision_id), CODEC_ATTR_RO(afg), CODEC_ATTR_RO(mfg), - CODEC_ATTR_RW(vendor_name), - CODEC_ATTR_RW(chip_name), + CODEC_ATTR_RW(name), CODEC_ATTR_RW(modelname), CODEC_ATTR_RW(init_verbs), CODEC_ATTR_RW(hints), diff --git a/trunk/sound/pci/hda/hda_intel.c b/trunk/sound/pci/hda/hda_intel.c index 4e9ea7080270..3128e1a6bc65 100644 --- a/trunk/sound/pci/hda/hda_intel.c +++ b/trunk/sound/pci/hda/hda_intel.c @@ -128,33 +128,21 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," "{ULI, M5461}}"); MODULE_DESCRIPTION("Intel HDA driver"); -#ifdef CONFIG_SND_VERBOSE_PRINTK -#define SFX /* nop */ -#else #define SFX "hda-intel: " -#endif + /* * registers */ #define ICH6_REG_GCAP 0x00 -#define ICH6_GCAP_64OK (1 << 0) /* 64bit address support */ -#define ICH6_GCAP_NSDO (3 << 1) /* # of serial data out signals */ -#define ICH6_GCAP_BSS (31 << 3) /* # of bidirectional streams */ -#define ICH6_GCAP_ISS (15 << 8) /* # of input streams */ -#define ICH6_GCAP_OSS (15 << 12) /* # of output streams */ #define ICH6_REG_VMIN 0x02 #define ICH6_REG_VMAJ 0x03 #define ICH6_REG_OUTPAY 0x04 #define ICH6_REG_INPAY 0x06 #define ICH6_REG_GCTL 0x08 -#define ICH6_GCTL_RESET (1 << 0) /* controller reset */ -#define ICH6_GCTL_FCNTRL (1 << 1) /* flush control */ -#define ICH6_GCTL_UNSOL (1 << 8) /* accept unsol. response enable */ #define ICH6_REG_WAKEEN 0x0c #define ICH6_REG_STATESTS 0x0e #define ICH6_REG_GSTS 0x10 -#define ICH6_GSTS_FSTS (1 << 1) /* flush status */ #define ICH6_REG_INTCTL 0x20 #define ICH6_REG_INTSTS 0x24 #define ICH6_REG_WALCLK 0x30 @@ -162,27 +150,17 @@ MODULE_DESCRIPTION("Intel HDA driver"); #define ICH6_REG_CORBLBASE 0x40 #define ICH6_REG_CORBUBASE 0x44 #define ICH6_REG_CORBWP 0x48 -#define ICH6_REG_CORBRP 0x4a -#define ICH6_CORBRP_RST (1 << 15) /* read pointer reset */ +#define ICH6_REG_CORBRP 0x4A #define ICH6_REG_CORBCTL 0x4c -#define ICH6_CORBCTL_RUN (1 << 1) /* enable DMA */ -#define ICH6_CORBCTL_CMEIE (1 << 0) /* enable memory error irq */ #define ICH6_REG_CORBSTS 0x4d -#define ICH6_CORBSTS_CMEI (1 << 0) /* memory error indication */ #define ICH6_REG_CORBSIZE 0x4e #define ICH6_REG_RIRBLBASE 0x50 #define ICH6_REG_RIRBUBASE 0x54 #define ICH6_REG_RIRBWP 0x58 -#define ICH6_RIRBWP_RST (1 << 15) /* write pointer reset */ #define ICH6_REG_RINTCNT 0x5a #define ICH6_REG_RIRBCTL 0x5c -#define ICH6_RBCTL_IRQ_EN (1 << 0) /* enable IRQ */ -#define ICH6_RBCTL_DMA_EN (1 << 1) /* enable DMA */ -#define ICH6_RBCTL_OVERRUN_EN (1 << 2) /* enable overrun irq */ #define ICH6_REG_RIRBSTS 0x5d -#define ICH6_RBSTS_IRQ (1 << 0) /* response irq */ -#define ICH6_RBSTS_OVERRUN (1 << 2) /* overrun irq */ #define ICH6_REG_RIRBSIZE 0x5e #define ICH6_REG_IC 0x60 @@ -279,6 +257,16 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define ICH6_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ #define ICH6_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ +/* GCTL unsolicited response enable bit */ +#define ICH6_GCTL_UREN (1<<8) + +/* GCTL reset bit */ +#define ICH6_GCTL_RESET (1<<0) + +/* CORB/RIRB control, read/write pointer */ +#define ICH6_RBCTL_DMA_EN 0x02 /* enable DMA */ +#define ICH6_RBCTL_IRQ_EN 0x01 /* enable IRQ */ +#define ICH6_RBRWP_CLR 0x8000 /* read/write pointer clear */ /* below are so far hardcoded - should read registers in future */ #define ICH6_MAX_CORB_ENTRIES 256 #define ICH6_MAX_RIRB_ENTRIES 256 @@ -524,25 +512,25 @@ static void azx_init_cmd_io(struct azx *chip) /* set the corb write pointer to 0 */ azx_writew(chip, CORBWP, 0); /* reset the corb hw read pointer */ - azx_writew(chip, CORBRP, ICH6_CORBRP_RST); + azx_writew(chip, CORBRP, ICH6_RBRWP_CLR); /* enable corb dma */ - azx_writeb(chip, CORBCTL, ICH6_CORBCTL_RUN); + azx_writeb(chip, CORBCTL, ICH6_RBCTL_DMA_EN); /* RIRB set up */ chip->rirb.addr = chip->rb.addr + 2048; chip->rirb.buf = (u32 *)(chip->rb.area + 2048); - chip->rirb.wp = chip->rirb.rp = chip->rirb.cmds = 0; azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr); azx_writel(chip, RIRBUBASE, upper_32_bits(chip->rirb.addr)); /* set the rirb size to 256 entries (ULI requires explicitly) */ azx_writeb(chip, RIRBSIZE, 0x02); /* reset the rirb hw write pointer */ - azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST); + azx_writew(chip, RIRBWP, ICH6_RBRWP_CLR); /* set N=1, get RIRB response interrupt for new entry */ azx_writew(chip, RINTCNT, 1); /* enable rirb dma and response irq */ azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN); + chip->rirb.rp = chip->rirb.cmds = 0; } static void azx_free_cmd_io(struct azx *chip) @@ -618,7 +606,6 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) } if (!chip->rirb.cmds) { smp_rmb(); - bus->rirb_error = 0; return chip->rirb.res; /* the last value */ } if (time_after(jiffies, timeout)) @@ -632,21 +619,19 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) } if (chip->msi) { - snd_printk(KERN_WARNING SFX "No response from codec, " + snd_printk(KERN_WARNING "hda_intel: No response from codec, " "disabling MSI: last cmd=0x%08x\n", chip->last_cmd); free_irq(chip->irq, chip); chip->irq = -1; pci_disable_msi(chip->pci); chip->msi = 0; - if (azx_acquire_irq(chip, 1) < 0) { - bus->rirb_error = 1; + if (azx_acquire_irq(chip, 1) < 0) return -1; - } goto again; } if (!chip->polling_mode) { - snd_printk(KERN_WARNING SFX "azx_get_response timeout, " + snd_printk(KERN_WARNING "hda_intel: azx_get_response timeout, " "switching to polling mode: last cmd=0x%08x\n", chip->last_cmd); chip->polling_mode = 1; @@ -661,23 +646,14 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) return -1; } - /* a fatal communication error; need either to reset or to fallback - * to the single_cmd mode - */ - bus->rirb_error = 1; - if (bus->allow_bus_reset && !bus->response_reset && !bus->in_reset) { - bus->response_reset = 1; - return -1; /* give a chance to retry */ - } - snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, " "switching to single_cmd mode: last cmd=0x%08x\n", chip->last_cmd); + chip->rirb.rp = azx_readb(chip, RIRBWP); + chip->rirb.cmds = 0; + /* switch to single_cmd mode */ chip->single_cmd = 1; - bus->response_reset = 0; - /* re-initialize CORB/RIRB */ azx_free_cmd_io(chip); - azx_init_cmd_io(chip); return -1; } @@ -691,34 +667,12 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) * I left the codes, however, for debugging/testing purposes. */ -/* receive a response */ -static int azx_single_wait_for_response(struct azx *chip) -{ - int timeout = 50; - - while (timeout--) { - /* check IRV busy bit */ - if (azx_readw(chip, IRS) & ICH6_IRS_VALID) { - /* reuse rirb.res as the response return value */ - chip->rirb.res = azx_readl(chip, IR); - return 0; - } - udelay(1); - } - if (printk_ratelimit()) - snd_printd(SFX "get_response timeout: IRS=0x%x\n", - azx_readw(chip, IRS)); - chip->rirb.res = -1; - return -EIO; -} - /* send a command */ static int azx_single_send_cmd(struct hda_bus *bus, u32 val) { struct azx *chip = bus->private_data; int timeout = 50; - bus->rirb_error = 0; while (timeout--) { /* check ICB busy bit */ if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) { @@ -728,7 +682,7 @@ static int azx_single_send_cmd(struct hda_bus *bus, u32 val) azx_writel(chip, IC, val); azx_writew(chip, IRS, azx_readw(chip, IRS) | ICH6_IRS_BUSY); - return azx_single_wait_for_response(chip); + return 0; } udelay(1); } @@ -742,7 +696,18 @@ static int azx_single_send_cmd(struct hda_bus *bus, u32 val) static unsigned int azx_single_get_response(struct hda_bus *bus) { struct azx *chip = bus->private_data; - return chip->rirb.res; + int timeout = 50; + + while (timeout--) { + /* check IRV busy bit */ + if (azx_readw(chip, IRS) & ICH6_IRS_VALID) + return azx_readl(chip, IR); + udelay(1); + } + if (printk_ratelimit()) + snd_printd(SFX "get_response timeout: IRS=0x%x\n", + azx_readw(chip, IRS)); + return (unsigned int)-1; } /* @@ -810,17 +775,17 @@ static int azx_reset(struct azx *chip) /* check to see if controller is ready */ if (!azx_readb(chip, GCTL)) { - snd_printd(SFX "azx_reset: controller not ready!\n"); + snd_printd("azx_reset: controller not ready!\n"); return -EBUSY; } /* Accept unsolicited responses */ - azx_writel(chip, GCTL, azx_readl(chip, GCTL) | ICH6_GCTL_UNSOL); + azx_writel(chip, GCTL, azx_readl(chip, GCTL) | ICH6_GCTL_UREN); /* detect codecs */ if (!chip->codec_mask) { chip->codec_mask = azx_readw(chip, STATESTS); - snd_printdd(SFX "codec_mask = 0x%x\n", chip->codec_mask); + snd_printdd("codec_mask = 0x%x\n", chip->codec_mask); } return 0; @@ -930,7 +895,8 @@ static void azx_init_chip(struct azx *chip) azx_int_enable(chip); /* initialize the codec command I/O */ - azx_init_cmd_io(chip); + if (!chip->single_cmd) + azx_init_cmd_io(chip); /* program the position buffer */ azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); @@ -987,12 +953,12 @@ static void azx_init_pci(struct azx *chip) case AZX_DRIVER_SCH: pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop); if (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) { - pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC, + pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC, \ snoop & (~INTEL_SCH_HDA_DEVC_NOSNOOP)); pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop); - snd_printdd(SFX "HDA snoop disabled, enabling ... %s\n", - (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) + snd_printdd("HDA snoop disabled, enabling ... %s\n",\ + (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) \ ? "Failed" : "OK"); } break; @@ -1046,7 +1012,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id) /* clear rirb int */ status = azx_readb(chip, RIRBSTS); if (status & RIRB_INT_MASK) { - if (status & RIRB_INT_RESPONSE) + if (!chip->single_cmd && (status & RIRB_INT_RESPONSE)) azx_update_rirb(chip); azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); } @@ -1132,7 +1098,7 @@ static int azx_setup_periods(struct azx *chip, pos_align; pos_adj = frames_to_bytes(runtime, pos_adj); if (pos_adj >= period_bytes) { - snd_printk(KERN_WARNING SFX "Too big adjustment %d\n", + snd_printk(KERN_WARNING "Too big adjustment %d\n", bdl_pos_adj[chip->dev_index]); pos_adj = 0; } else { @@ -1156,7 +1122,7 @@ static int azx_setup_periods(struct azx *chip, return 0; error: - snd_printk(KERN_ERR SFX "Too many BDL entries: buffer=%d, period=%d\n", + snd_printk(KERN_ERR "Too many BDL entries: buffer=%d, period=%d\n", azx_dev->bufsize, period_bytes); return -EINVAL; } @@ -1249,7 +1215,7 @@ static int probe_codec(struct azx *chip, int addr) chip->probing = 0; if (res == -1) return -EIO; - snd_printdd(SFX "codec #%d probed OK\n", addr); + snd_printdd("hda_intel: codec #%d probed OK\n", addr); return 0; } @@ -1257,26 +1223,6 @@ static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, struct hda_pcm *cpcm); static void azx_stop_chip(struct azx *chip); -static void azx_bus_reset(struct hda_bus *bus) -{ - struct azx *chip = bus->private_data; - - bus->in_reset = 1; - azx_stop_chip(chip); - azx_init_chip(chip); -#ifdef CONFIG_PM - if (chip->initialized) { - int i; - - for (i = 0; i < AZX_MAX_PCMS; i++) - snd_pcm_suspend_all(chip->pcm[i]); - snd_hda_suspend(chip->bus); - snd_hda_resume(chip->bus); - } -#endif - bus->in_reset = 0; -} - /* * Codec initialization */ @@ -1300,7 +1246,6 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, bus_temp.ops.command = azx_send_cmd; bus_temp.ops.get_response = azx_get_response; bus_temp.ops.attach_pcm = azx_attach_pcm_stream; - bus_temp.ops.bus_reset = azx_bus_reset; #ifdef CONFIG_SND_HDA_POWER_SAVE bus_temp.power_save = &power_save; bus_temp.ops.pm_notify = azx_power_notify; @@ -1325,8 +1270,8 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, /* Some BIOSen give you wrong codec addresses * that don't exist */ - snd_printk(KERN_WARNING SFX - "Codec #%d probe error; " + snd_printk(KERN_WARNING + "hda_intel: Codec #%d probe error; " "disabling it...\n", c); chip->codec_mask &= ~(1 << c); /* More badly, accessing to a non-existing @@ -1542,7 +1487,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) bufsize = snd_pcm_lib_buffer_bytes(substream); period_bytes = snd_pcm_lib_period_bytes(substream); - snd_printdd(SFX "azx_pcm_prepare: bufsize=0x%x, format=0x%x\n", + snd_printdd("azx_pcm_prepare: bufsize=0x%x, format=0x%x\n", bufsize, format_val); if (bufsize != azx_dev->bufsize || @@ -1885,7 +1830,7 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, &pcm); if (err < 0) return err; - strlcpy(pcm->name, cpcm->name, sizeof(pcm->name)); + strcpy(pcm->name, cpcm->name); apcm = kzalloc(sizeof(*apcm), GFP_KERNEL); if (apcm == NULL) return -ENOMEM; @@ -2028,7 +1973,7 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state) for (i = 0; i < AZX_MAX_PCMS; i++) snd_pcm_suspend_all(chip->pcm[i]); if (chip->initialized) - snd_hda_suspend(chip->bus); + snd_hda_suspend(chip->bus, state); azx_stop_chip(chip); if (chip->irq >= 0) { free_irq(chip->irq, chip); @@ -2320,14 +2265,14 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, synchronize_irq(chip->irq); gcap = azx_readw(chip, GCAP); - snd_printdd(SFX "chipset global capabilities = 0x%x\n", gcap); + snd_printdd("chipset global capabilities = 0x%x\n", gcap); /* ATI chips seems buggy about 64bit DMA addresses */ if (chip->driver_type == AZX_DRIVER_ATI) - gcap &= ~ICH6_GCAP_64OK; + gcap &= ~0x01; /* allow 64bit DMA address if supported by H/W */ - if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64))) + if ((gcap & 0x01) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64))) pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64)); else { pci_set_dma_mask(pci, DMA_BIT_MASK(32)); @@ -2364,7 +2309,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), GFP_KERNEL); if (!chip->azx_dev) { - snd_printk(KERN_ERR SFX "cannot malloc azx_dev\n"); + snd_printk(KERN_ERR "cannot malloc azx_dev\n"); goto errout; } @@ -2387,9 +2332,11 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, goto errout; } /* allocate CORB/RIRB */ - err = azx_alloc_cmd_io(chip); - if (err < 0) - goto errout; + if (!chip->single_cmd) { + err = azx_alloc_cmd_io(chip); + if (err < 0) + goto errout; + } /* initialize streams */ azx_init_stream(chip); @@ -2412,11 +2359,9 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, } strcpy(card->driver, "HDA-Intel"); - strlcpy(card->shortname, driver_short_names[chip->driver_type], - sizeof(card->shortname)); - snprintf(card->longname, sizeof(card->longname), - "%s at 0x%lx irq %i", - card->shortname, chip->addr, chip->irq); + strcpy(card->shortname, driver_short_names[chip->driver_type]); + sprintf(card->longname, "%s at 0x%lx irq %i", + card->shortname, chip->addr, chip->irq); *rchip = chip; return 0; @@ -2569,20 +2514,6 @@ static struct pci_device_id azx_ids[] = { { PCI_DEVICE(0x10de, 0x0d97), .driver_data = AZX_DRIVER_NVIDIA }, /* Teradici */ { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA }, - /* Creative X-Fi (CA0110-IBG) */ -#if !defined(CONFIG_SND_CTXFI) && !defined(CONFIG_SND_CTXFI_MODULE) - /* the following entry conflicts with snd-ctxfi driver, - * as ctxfi driver mutates from HD-audio to native mode with - * a special command sequence. - */ - { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_ANY_ID), - .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, - .class_mask = 0xffffff, - .driver_data = AZX_DRIVER_GENERIC }, -#else - /* this entry seems still valid -- i.e. without emu20kx chip */ - { PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_GENERIC }, -#endif /* AMD Generic, PCI class code and Vendor ID for HD Audio */ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, diff --git a/trunk/sound/pci/hda/hda_proc.c b/trunk/sound/pci/hda/hda_proc.c index 418c5d1badaa..93d7499350c6 100644 --- a/trunk/sound/pci/hda/hda_proc.c +++ b/trunk/sound/pci/hda/hda_proc.c @@ -466,12 +466,8 @@ static void print_codec_info(struct snd_info_entry *entry, hda_nid_t nid; int i, nodes; - snd_iprintf(buffer, "Codec: "); - if (codec->vendor_name && codec->chip_name) - snd_iprintf(buffer, "%s %s\n", - codec->vendor_name, codec->chip_name); - else - snd_iprintf(buffer, "Not Set\n"); + snd_iprintf(buffer, "Codec: %s\n", + codec->name ? codec->name : "Not Set"); snd_iprintf(buffer, "Address: %d\n", codec->addr); snd_iprintf(buffer, "Function Id: 0x%x\n", codec->function_id); snd_iprintf(buffer, "Vendor Id: 0x%08x\n", codec->vendor_id); diff --git a/trunk/sound/pci/hda/patch_ca0110.c b/trunk/sound/pci/hda/patch_ca0110.c deleted file mode 100644 index 392d108c3558..000000000000 --- a/trunk/sound/pci/hda/patch_ca0110.c +++ /dev/null @@ -1,573 +0,0 @@ -/* - * HD audio interface patch for Creative X-Fi CA0110-IBG chip - * - * Copyright (c) 2008 Takashi Iwai - * - * This driver is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include "hda_codec.h" -#include "hda_local.h" - -/* - */ - -struct ca0110_spec { - struct auto_pin_cfg autocfg; - struct hda_multi_out multiout; - hda_nid_t out_pins[AUTO_CFG_MAX_OUTS]; - hda_nid_t dacs[AUTO_CFG_MAX_OUTS]; - hda_nid_t hp_dac; - hda_nid_t input_pins[AUTO_PIN_LAST]; - hda_nid_t adcs[AUTO_PIN_LAST]; - hda_nid_t dig_out; - hda_nid_t dig_in; - unsigned int num_inputs; - const char *input_labels[AUTO_PIN_LAST]; - struct hda_pcm pcm_rec[2]; /* PCM information */ -}; - -/* - * PCM callbacks - */ -static int ca0110_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, - hinfo); -} - -static int ca0110_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, - stream_tag, format, substream); -} - -static int ca0110_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); -} - -/* - * Digital out - */ -static int ca0110_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int ca0110_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int ca0110_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, - format, substream); -} - -/* - * Analog capture - */ -static int ca0110_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - - snd_hda_codec_setup_stream(codec, spec->adcs[substream->number], - stream_tag, 0, format); - return 0; -} - -static int ca0110_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - - snd_hda_codec_cleanup_stream(codec, spec->adcs[substream->number]); - return 0; -} - -/* - */ - -static char *dirstr[2] = { "Playback", "Capture" }; - -static int _add_switch(struct hda_codec *codec, hda_nid_t nid, const char *pfx, - int chan, int dir) -{ - char namestr[44]; - int type = dir ? HDA_INPUT : HDA_OUTPUT; - struct snd_kcontrol_new knew = - HDA_CODEC_MUTE_MONO(namestr, nid, chan, 0, type); - sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]); - return snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); -} - -static int _add_volume(struct hda_codec *codec, hda_nid_t nid, const char *pfx, - int chan, int dir) -{ - char namestr[44]; - int type = dir ? HDA_INPUT : HDA_OUTPUT; - struct snd_kcontrol_new knew = - HDA_CODEC_VOLUME_MONO(namestr, nid, chan, 0, type); - sprintf(namestr, "%s %s Volume", pfx, dirstr[dir]); - return snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); -} - -#define add_out_switch(codec, nid, pfx) _add_switch(codec, nid, pfx, 3, 0) -#define add_out_volume(codec, nid, pfx) _add_volume(codec, nid, pfx, 3, 0) -#define add_in_switch(codec, nid, pfx) _add_switch(codec, nid, pfx, 3, 1) -#define add_in_volume(codec, nid, pfx) _add_volume(codec, nid, pfx, 3, 1) -#define add_mono_switch(codec, nid, pfx, chan) \ - _add_switch(codec, nid, pfx, chan, 0) -#define add_mono_volume(codec, nid, pfx, chan) \ - _add_volume(codec, nid, pfx, chan, 0) - -static int ca0110_build_controls(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - static char *prefix[AUTO_CFG_MAX_OUTS] = { - "Front", "Surround", NULL, "Side", "Multi" - }; - hda_nid_t mutenid; - int i, err; - - for (i = 0; i < spec->multiout.num_dacs; i++) { - if (get_wcaps(codec, spec->out_pins[i]) & AC_WCAP_OUT_AMP) - mutenid = spec->out_pins[i]; - else - mutenid = spec->multiout.dac_nids[i]; - if (!prefix[i]) { - err = add_mono_switch(codec, mutenid, - "Center", 1); - if (err < 0) - return err; - err = add_mono_switch(codec, mutenid, - "LFE", 1); - if (err < 0) - return err; - err = add_mono_volume(codec, spec->multiout.dac_nids[i], - "Center", 1); - if (err < 0) - return err; - err = add_mono_volume(codec, spec->multiout.dac_nids[i], - "LFE", 1); - if (err < 0) - return err; - } else { - err = add_out_switch(codec, mutenid, - prefix[i]); - if (err < 0) - return err; - err = add_out_volume(codec, spec->multiout.dac_nids[i], - prefix[i]); - if (err < 0) - return err; - } - } - if (cfg->hp_outs) { - if (get_wcaps(codec, cfg->hp_pins[0]) & AC_WCAP_OUT_AMP) - mutenid = cfg->hp_pins[0]; - else - mutenid = spec->multiout.dac_nids[i]; - - err = add_out_switch(codec, mutenid, "Headphone"); - if (err < 0) - return err; - if (spec->hp_dac) { - err = add_out_volume(codec, spec->hp_dac, "Headphone"); - if (err < 0) - return err; - } - } - for (i = 0; i < spec->num_inputs; i++) { - const char *label = spec->input_labels[i]; - if (get_wcaps(codec, spec->input_pins[i]) & AC_WCAP_IN_AMP) - mutenid = spec->input_pins[i]; - else - mutenid = spec->adcs[i]; - err = add_in_switch(codec, mutenid, label); - if (err < 0) - return err; - err = add_in_volume(codec, spec->adcs[i], label); - if (err < 0) - return err; - } - - if (spec->dig_out) { - err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out); - if (err < 0) - return err; - err = snd_hda_create_spdif_share_sw(codec, &spec->multiout); - if (err < 0) - return err; - spec->multiout.share_spdif = 1; - } - if (spec->dig_in) { - err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in); - if (err < 0) - return err; - err = add_in_volume(codec, spec->dig_in, "IEC958"); - } - return 0; -} - -/* - */ -static struct hda_pcm_stream ca0110_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 8, - .ops = { - .open = ca0110_playback_pcm_open, - .prepare = ca0110_playback_pcm_prepare, - .cleanup = ca0110_playback_pcm_cleanup - }, -}; - -static struct hda_pcm_stream ca0110_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .prepare = ca0110_capture_pcm_prepare, - .cleanup = ca0110_capture_pcm_cleanup - }, -}; - -static struct hda_pcm_stream ca0110_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .open = ca0110_dig_playback_pcm_open, - .close = ca0110_dig_playback_pcm_close, - .prepare = ca0110_dig_playback_pcm_prepare - }, -}; - -static struct hda_pcm_stream ca0110_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, -}; - -static int ca0110_build_pcms(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - - codec->pcm_info = info; - codec->num_pcms = 0; - - info->name = "CA0110 Analog"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ca0110_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dacs[0]; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = - spec->multiout.max_channels; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0110_pcm_analog_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_inputs; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0]; - codec->num_pcms++; - - if (!spec->dig_out && !spec->dig_in) - return 0; - - info++; - info->name = "CA0110 Digital"; - info->pcm_type = HDA_PCM_TYPE_SPDIF; - if (spec->dig_out) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - ca0110_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dig_out; - } - if (spec->dig_in) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - ca0110_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in; - } - codec->num_pcms++; - - return 0; -} - -static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac) -{ - if (pin) { - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); - if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP) - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_UNMUTE); - } - if (dac) - snd_hda_codec_write(codec, dac, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO); -} - -static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc) -{ - if (pin) { - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80); - if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP) - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); - } - if (adc) - snd_hda_codec_write(codec, adc, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); -} - -static int ca0110_init(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - - for (i = 0; i < spec->multiout.num_dacs; i++) - init_output(codec, spec->out_pins[i], - spec->multiout.dac_nids[i]); - init_output(codec, cfg->hp_pins[0], spec->hp_dac); - init_output(codec, cfg->dig_out_pins[0], spec->dig_out); - - for (i = 0; i < spec->num_inputs; i++) - init_input(codec, spec->input_pins[i], spec->adcs[i]); - init_input(codec, cfg->dig_in_pin, spec->dig_in); - return 0; -} - -static void ca0110_free(struct hda_codec *codec) -{ - kfree(codec->spec); -} - -static struct hda_codec_ops ca0110_patch_ops = { - .build_controls = ca0110_build_controls, - .build_pcms = ca0110_build_pcms, - .init = ca0110_init, - .free = ca0110_free, -}; - - -static void parse_line_outs(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i, n; - unsigned int def_conf; - hda_nid_t nid; - - n = 0; - for (i = 0; i < cfg->line_outs; i++) { - nid = cfg->line_out_pins[i]; - def_conf = snd_hda_codec_get_pincfg(codec, nid); - if (!def_conf) - continue; /* invalid pin */ - if (snd_hda_get_connections(codec, nid, &spec->dacs[i], 1) != 1) - continue; - spec->out_pins[n++] = nid; - } - spec->multiout.dac_nids = spec->dacs; - spec->multiout.num_dacs = n; - spec->multiout.max_channels = n * 2; -} - -static void parse_hp_out(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - unsigned int def_conf; - hda_nid_t nid, dac; - - if (!cfg->hp_outs) - return; - nid = cfg->hp_pins[0]; - def_conf = snd_hda_codec_get_pincfg(codec, nid); - if (!def_conf) { - cfg->hp_outs = 0; - return; - } - if (snd_hda_get_connections(codec, nid, &dac, 1) != 1) - return; - - for (i = 0; i < cfg->line_outs; i++) - if (dac == spec->dacs[i]) - break; - if (i >= cfg->line_outs) { - spec->hp_dac = dac; - spec->multiout.hp_nid = dac; - } -} - -static void parse_input(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t nid, pin; - int n, i, j; - - n = 0; - nid = codec->start_nid; - for (i = 0; i < codec->num_nodes; i++, nid++) { - unsigned int wcaps = get_wcaps(codec, nid); - unsigned int type = (wcaps & AC_WCAP_TYPE) >> - AC_WCAP_TYPE_SHIFT; - if (type != AC_WID_AUD_IN) - continue; - if (snd_hda_get_connections(codec, nid, &pin, 1) != 1) - continue; - if (pin == cfg->dig_in_pin) { - spec->dig_in = nid; - continue; - } - for (j = 0; j < AUTO_PIN_LAST; j++) - if (cfg->input_pins[j] == pin) - break; - if (j >= AUTO_PIN_LAST) - continue; - spec->input_pins[n] = pin; - spec->input_labels[n] = auto_pin_cfg_labels[j]; - spec->adcs[n] = nid; - n++; - } - spec->num_inputs = n; -} - -static void parse_digital(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - - if (cfg->dig_outs && - snd_hda_get_connections(codec, cfg->dig_out_pins[0], - &spec->dig_out, 1) == 1) - spec->multiout.dig_out_nid = cfg->dig_out_pins[0]; -} - -static int ca0110_parse_auto_config(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - int err; - - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); - if (err < 0) - return err; - - parse_line_outs(codec); - parse_hp_out(codec); - parse_digital(codec); - parse_input(codec); - return 0; -} - - -int patch_ca0110(struct hda_codec *codec) -{ - struct ca0110_spec *spec; - int err; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - codec->spec = spec; - - codec->bus->needs_damn_long_delay = 1; - - err = ca0110_parse_auto_config(codec); - if (err < 0) - goto error; - - codec->patch_ops = ca0110_patch_ops; - - return 0; - - error: - kfree(codec->spec); - codec->spec = NULL; - return err; -} - - -/* - * patch entries - */ -static struct hda_codec_preset snd_hda_preset_ca0110[] = { - { .id = 0x1102000a, .name = "CA0110-IBG", .patch = patch_ca0110 }, - { .id = 0x1102000b, .name = "CA0110-IBG", .patch = patch_ca0110 }, - { .id = 0x1102000d, .name = "SB0880 X-Fi", .patch = patch_ca0110 }, - {} /* terminator */ -}; - -MODULE_ALIAS("snd-hda-codec-id:1102000a"); -MODULE_ALIAS("snd-hda-codec-id:1102000b"); -MODULE_ALIAS("snd-hda-codec-id:1102000d"); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Creative CA0110-IBG HD-audio codec"); - -static struct hda_codec_preset_list ca0110_list = { - .preset = snd_hda_preset_ca0110, - .owner = THIS_MODULE, -}; - -static int __init patch_ca0110_init(void) -{ - return snd_hda_add_codec_preset(&ca0110_list); -} - -static void __exit patch_ca0110_exit(void) -{ - snd_hda_delete_codec_preset(&ca0110_list); -} - -module_init(patch_ca0110_init) -module_exit(patch_ca0110_exit) diff --git a/trunk/sound/pci/hda/patch_conexant.c b/trunk/sound/pci/hda/patch_conexant.c index ac868c59f9e3..4fcbe21829ab 100644 --- a/trunk/sound/pci/hda/patch_conexant.c +++ b/trunk/sound/pci/hda/patch_conexant.c @@ -349,7 +349,7 @@ static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol, &spec->cur_mux[adc_idx]); } -#ifdef CONFIG_SND_HDA_INPUT_JACK +#ifdef CONFIG_SND_JACK static void conexant_free_jack_priv(struct snd_jack *jack) { struct conexant_jack *jacks = jack->private_data; @@ -463,7 +463,7 @@ static int conexant_init(struct hda_codec *codec) static void conexant_free(struct hda_codec *codec) { -#ifdef CONFIG_SND_HDA_INPUT_JACK +#ifdef CONFIG_SND_JACK struct conexant_spec *spec = codec->spec; if (spec->jacks.list) { struct conexant_jack *jacks = spec->jacks.list; diff --git a/trunk/sound/pci/hda/patch_nvhdmi.c b/trunk/sound/pci/hda/patch_nvhdmi.c index f5792e2eea82..d57d8132a06e 100644 --- a/trunk/sound/pci/hda/patch_nvhdmi.c +++ b/trunk/sound/pci/hda/patch_nvhdmi.c @@ -35,28 +35,9 @@ struct nvhdmi_spec { struct hda_pcm pcm_rec; }; -#define Nv_VERB_SET_Channel_Allocation 0xF79 -#define Nv_VERB_SET_Info_Frame_Checksum 0xF7A -#define Nv_VERB_SET_Audio_Protection_On 0xF98 -#define Nv_VERB_SET_Audio_Protection_Off 0xF99 - -#define Nv_Master_Convert_nid 0x04 -#define Nv_Master_Pin_nid 0x05 - -static hda_nid_t nvhdmi_convert_nids[4] = { - /*front, rear, clfe, rear_surr */ - 0x6, 0x8, 0xa, 0xc, -}; - static struct hda_verb nvhdmi_basic_init[] = { - /* set audio protect on */ - { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1}, /* enable digital output on pin widget */ - { 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, - { 0x7, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, - { 0x9, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, - { 0xb, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, - { 0xd, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, + { 0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, {} /* terminator */ }; @@ -85,205 +66,48 @@ static int nvhdmi_init(struct hda_codec *codec) * Digital out */ static int nvhdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) + struct hda_codec *codec, + struct snd_pcm_substream *substream) { struct nvhdmi_spec *spec = codec->spec; return snd_hda_multi_out_dig_open(codec, &spec->multiout); } -static int nvhdmi_dig_playback_pcm_close_8ch(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) +static int nvhdmi_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) { struct nvhdmi_spec *spec = codec->spec; - int i; - - snd_hda_codec_write(codec, Nv_Master_Convert_nid, - 0, AC_VERB_SET_CHANNEL_STREAMID, 0); - for (i = 0; i < 4; i++) { - /* set the stream id */ - snd_hda_codec_write(codec, nvhdmi_convert_nids[i], 0, - AC_VERB_SET_CHANNEL_STREAMID, 0); - /* set the stream format */ - snd_hda_codec_write(codec, nvhdmi_convert_nids[i], 0, - AC_VERB_SET_STREAM_FORMAT, 0); - } - return snd_hda_multi_out_dig_close(codec, &spec->multiout); } -static int nvhdmi_dig_playback_pcm_close_2ch(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct nvhdmi_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - int chs; - unsigned int dataDCC1, dataDCC2, chan, chanmask, channel_id; - int i; - - mutex_lock(&codec->spdif_mutex); - - chs = substream->runtime->channels; - chan = chs ? (chs - 1) : 1; - - switch (chs) { - default: - case 0: - case 2: - chanmask = 0x00; - break; - case 4: - chanmask = 0x08; - break; - case 6: - chanmask = 0x0b; - break; - case 8: - chanmask = 0x13; - break; - } - dataDCC1 = AC_DIG1_ENABLE | AC_DIG1_COPYRIGHT; - dataDCC2 = 0x2; - - /* set the Audio InforFrame Channel Allocation */ - snd_hda_codec_write(codec, 0x1, 0, - Nv_VERB_SET_Channel_Allocation, chanmask); - - /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ - if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) - snd_hda_codec_write(codec, - Nv_Master_Convert_nid, - 0, - AC_VERB_SET_DIGI_CONVERT_1, - codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); - - /* set the stream id */ - snd_hda_codec_write(codec, Nv_Master_Convert_nid, 0, - AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0); - - /* set the stream format */ - snd_hda_codec_write(codec, Nv_Master_Convert_nid, 0, - AC_VERB_SET_STREAM_FORMAT, format); - - /* turn on again (if needed) */ - /* enable and set the channel status audio/data flag */ - if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) { - snd_hda_codec_write(codec, - Nv_Master_Convert_nid, - 0, - AC_VERB_SET_DIGI_CONVERT_1, - codec->spdif_ctls & 0xff); - snd_hda_codec_write(codec, - Nv_Master_Convert_nid, - 0, - AC_VERB_SET_DIGI_CONVERT_2, dataDCC2); - } - - for (i = 0; i < 4; i++) { - if (chs == 2) - channel_id = 0; - else - channel_id = i * 2; - - /* turn off SPDIF once; - *otherwise the IEC958 bits won't be updated - */ - if (codec->spdif_status_reset && - (codec->spdif_ctls & AC_DIG1_ENABLE)) - snd_hda_codec_write(codec, - nvhdmi_convert_nids[i], - 0, - AC_VERB_SET_DIGI_CONVERT_1, - codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); - /* set the stream id */ - snd_hda_codec_write(codec, - nvhdmi_convert_nids[i], - 0, - AC_VERB_SET_CHANNEL_STREAMID, - (stream_tag << 4) | channel_id); - /* set the stream format */ - snd_hda_codec_write(codec, - nvhdmi_convert_nids[i], - 0, - AC_VERB_SET_STREAM_FORMAT, - format); - /* turn on again (if needed) */ - /* enable and set the channel status audio/data flag */ - if (codec->spdif_status_reset && - (codec->spdif_ctls & AC_DIG1_ENABLE)) { - snd_hda_codec_write(codec, - nvhdmi_convert_nids[i], - 0, - AC_VERB_SET_DIGI_CONVERT_1, - codec->spdif_ctls & 0xff); - snd_hda_codec_write(codec, - nvhdmi_convert_nids[i], - 0, - AC_VERB_SET_DIGI_CONVERT_2, dataDCC2); - } - } - - /* set the Audio Info Frame Checksum */ - snd_hda_codec_write(codec, 0x1, 0, - Nv_VERB_SET_Info_Frame_Checksum, - (0x71 - chan - chanmask)); - - mutex_unlock(&codec->spdif_mutex); - return 0; -} - -static int nvhdmi_dig_playback_pcm_prepare_2ch(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) +static int nvhdmi_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) { struct nvhdmi_spec *spec = codec->spec; return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, - format, substream); + format, substream); } -static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch = { - .substreams = 1, - .channels_min = 2, - .channels_max = 8, - .nid = Nv_Master_Convert_nid, - .rates = SNDRV_PCM_RATE_48000, - .maxbps = 16, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .ops = { - .open = nvhdmi_dig_playback_pcm_open, - .close = nvhdmi_dig_playback_pcm_close_8ch, - .prepare = nvhdmi_dig_playback_pcm_prepare_8ch - }, -}; - -static struct hda_pcm_stream nvhdmi_pcm_digital_playback_2ch = { +static struct hda_pcm_stream nvhdmi_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, - .nid = Nv_Master_Convert_nid, + .nid = 0x4, /* NID to query formats and rates and setup streams */ .rates = SNDRV_PCM_RATE_48000, .maxbps = 16, .formats = SNDRV_PCM_FMTBIT_S16_LE, .ops = { .open = nvhdmi_dig_playback_pcm_open, - .close = nvhdmi_dig_playback_pcm_close_2ch, - .prepare = nvhdmi_dig_playback_pcm_prepare_2ch + .close = nvhdmi_dig_playback_pcm_close, + .prepare = nvhdmi_dig_playback_pcm_prepare }, }; -static int nvhdmi_build_pcms_8ch(struct hda_codec *codec) +static int nvhdmi_build_pcms(struct hda_codec *codec) { struct nvhdmi_spec *spec = codec->spec; struct hda_pcm *info = &spec->pcm_rec; @@ -293,24 +117,7 @@ static int nvhdmi_build_pcms_8ch(struct hda_codec *codec) info->name = "NVIDIA HDMI"; info->pcm_type = HDA_PCM_TYPE_HDMI; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] - = nvhdmi_pcm_digital_playback_8ch; - - return 0; -} - -static int nvhdmi_build_pcms_2ch(struct hda_codec *codec) -{ - struct nvhdmi_spec *spec = codec->spec; - struct hda_pcm *info = &spec->pcm_rec; - - codec->num_pcms = 1; - codec->pcm_info = info; - - info->name = "NVIDIA HDMI"; - info->pcm_type = HDA_PCM_TYPE_HDMI; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] - = nvhdmi_pcm_digital_playback_2ch; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = nvhdmi_pcm_digital_playback; return 0; } @@ -320,40 +127,14 @@ static void nvhdmi_free(struct hda_codec *codec) kfree(codec->spec); } -static struct hda_codec_ops nvhdmi_patch_ops_8ch = { - .build_controls = nvhdmi_build_controls, - .build_pcms = nvhdmi_build_pcms_8ch, - .init = nvhdmi_init, - .free = nvhdmi_free, -}; - -static struct hda_codec_ops nvhdmi_patch_ops_2ch = { +static struct hda_codec_ops nvhdmi_patch_ops = { .build_controls = nvhdmi_build_controls, - .build_pcms = nvhdmi_build_pcms_2ch, + .build_pcms = nvhdmi_build_pcms, .init = nvhdmi_init, .free = nvhdmi_free, }; -static int patch_nvhdmi_8ch(struct hda_codec *codec) -{ - struct nvhdmi_spec *spec; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - - spec->multiout.num_dacs = 0; /* no analog */ - spec->multiout.max_channels = 8; - spec->multiout.dig_out_nid = Nv_Master_Convert_nid; - - codec->patch_ops = nvhdmi_patch_ops_8ch; - - return 0; -} - -static int patch_nvhdmi_2ch(struct hda_codec *codec) +static int patch_nvhdmi(struct hda_codec *codec) { struct nvhdmi_spec *spec; @@ -363,11 +144,13 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec) codec->spec = spec; - spec->multiout.num_dacs = 0; /* no analog */ + spec->multiout.num_dacs = 0; /* no analog */ spec->multiout.max_channels = 2; - spec->multiout.dig_out_nid = Nv_Master_Convert_nid; + spec->multiout.dig_out_nid = 0x4; /* NID for copying analog to digital, + * seems to be unused in pure-digital + * case. */ - codec->patch_ops = nvhdmi_patch_ops_2ch; + codec->patch_ops = nvhdmi_patch_ops; return 0; } @@ -376,11 +159,11 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec) * patch entries */ static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { - { .id = 0x10de0002, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, - { .id = 0x10de0006, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, - { .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi_8ch }, - { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, - { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch }, + { .id = 0x10de0002, .name = "MCP78 HDMI", .patch = patch_nvhdmi }, + { .id = 0x10de0006, .name = "MCP78 HDMI", .patch = patch_nvhdmi }, + { .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi }, + { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi }, + { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi }, {} /* terminator */ }; diff --git a/trunk/sound/pci/hda/patch_realtek.c b/trunk/sound/pci/hda/patch_realtek.c index 334533197425..0fd258eba3a5 100644 --- a/trunk/sound/pci/hda/patch_realtek.c +++ b/trunk/sound/pci/hda/patch_realtek.c @@ -190,7 +190,6 @@ enum { ALC663_ASUS_MODE6, ALC272_DELL, ALC272_DELL_ZM1, - ALC272_SAMSUNG_NC10, ALC662_AUTO, ALC662_MODEL_LAST, }; @@ -206,7 +205,6 @@ enum { ALC882_ASUS_A7M, ALC885_MACPRO, ALC885_MBP3, - ALC885_MB5, ALC885_IMAC24, ALC882_AUTO, ALC882_MODEL_LAST, @@ -220,12 +218,9 @@ enum { ALC883_6ST_DIG, ALC883_TARGA_DIG, ALC883_TARGA_2ch_DIG, - ALC883_TARGA_8ch_DIG, ALC883_ACER, ALC883_ACER_ASPIRE, ALC888_ACER_ASPIRE_4930G, - ALC888_ACER_ASPIRE_6530G, - ALC888_ACER_ASPIRE_8930G, ALC883_MEDION, ALC883_MEDION_MD2, ALC883_LAPTOP_EAPD, @@ -243,25 +238,21 @@ enum { ALC883_3ST_6ch_INTEL, ALC888_ASUS_M90V, ALC888_ASUS_EEE1601, - ALC889A_MB31, ALC1200_ASUS_P5Q, - ALC883_SONY_VAIO_TT, ALC883_AUTO, ALC883_MODEL_LAST, }; -/* for GPIO Poll */ -#define GPIO_MASK 0x03 - -/* extra amp-initialization sequence types */ +/* styles of capture selection */ enum { - ALC_INIT_NONE, - ALC_INIT_DEFAULT, - ALC_INIT_GPIO1, - ALC_INIT_GPIO2, - ALC_INIT_GPIO3, + CAPT_MUX = 0, /* only mux based */ + CAPT_MIX, /* only mixer based */ + CAPT_1MUX_MIX, /* first mux and other mixers */ }; +/* for GPIO Poll */ +#define GPIO_MASK 0x03 + struct alc_spec { /* codec parameterization */ struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ @@ -275,13 +266,13 @@ struct alc_spec { */ unsigned int num_init_verbs; - char stream_name_analog[16]; /* analog PCM stream */ + char *stream_name_analog; /* analog PCM stream */ struct hda_pcm_stream *stream_analog_playback; struct hda_pcm_stream *stream_analog_capture; struct hda_pcm_stream *stream_analog_alt_playback; struct hda_pcm_stream *stream_analog_alt_capture; - char stream_name_digital[16]; /* digital PCM stream */ + char *stream_name_digital; /* digital PCM stream */ struct hda_pcm_stream *stream_digital_playback; struct hda_pcm_stream *stream_digital_capture; @@ -299,6 +290,7 @@ struct alc_spec { hda_nid_t *adc_nids; hda_nid_t *capsrc_nids; hda_nid_t dig_in_nid; /* digital-in NID; optional */ + int capture_style; /* capture style (CAPT_*) */ /* capture source */ unsigned int num_mux_defs; @@ -309,8 +301,6 @@ struct alc_spec { const struct hda_channel_mode *channel_mode; int num_channel_mode; int need_dac_fix; - int const_channel_count; - int ext_channel_count; /* PCM information */ struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */ @@ -332,7 +322,6 @@ struct alc_spec { /* other flags */ unsigned int no_analog :1; /* digital I/O only */ - int init_amp; /* for virtual master */ hda_nid_t vmaster_nid; @@ -366,7 +355,6 @@ struct alc_config_preset { unsigned int num_channel_mode; const struct hda_channel_mode *channel_mode; int need_dac_fix; - int const_channel_count; unsigned int num_mux_defs; const struct hda_input_mux *input_mux; void (*unsol_event)(struct hda_codec *, unsigned int); @@ -412,13 +400,12 @@ static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, unsigned int mux_idx; hda_nid_t nid = spec->capsrc_nids ? spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx]; - unsigned int type; mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx; imux = &spec->input_mux[mux_idx]; - type = (get_wcaps(codec, nid) & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; - if (type == AC_WID_AUD_MIX) { + if (spec->capture_style && + !(spec->capture_style == CAPT_1MUX_MIX && !adc_idx)) { /* Matrix-mixer style (e.g. ALC882) */ unsigned int *cur_val = &spec->cur_mux[adc_idx]; unsigned int i, idx; @@ -462,7 +449,7 @@ static int alc_ch_mode_get(struct snd_kcontrol *kcontrol, struct alc_spec *spec = codec->spec; return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode, spec->num_channel_mode, - spec->ext_channel_count); + spec->multiout.max_channels); } static int alc_ch_mode_put(struct snd_kcontrol *kcontrol, @@ -472,12 +459,9 @@ static int alc_ch_mode_put(struct snd_kcontrol *kcontrol, struct alc_spec *spec = codec->spec; int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, spec->num_channel_mode, - &spec->ext_channel_count); - if (err >= 0 && !spec->const_channel_count) { - spec->multiout.max_channels = spec->ext_channel_count; - if (spec->need_dac_fix) - spec->multiout.num_dacs = spec->multiout.max_channels / 2; - } + &spec->multiout.max_channels); + if (err >= 0 && spec->need_dac_fix) + spec->multiout.num_dacs = spec->multiout.max_channels / 2; return err; } @@ -857,13 +841,8 @@ static void setup_preset(struct alc_spec *spec, spec->channel_mode = preset->channel_mode; spec->num_channel_mode = preset->num_channel_mode; spec->need_dac_fix = preset->need_dac_fix; - spec->const_channel_count = preset->const_channel_count; - if (preset->const_channel_count) - spec->multiout.max_channels = preset->const_channel_count; - else - spec->multiout.max_channels = spec->channel_mode[0].channels; - spec->ext_channel_count = spec->channel_mode[0].channels; + spec->multiout.max_channels = spec->channel_mode[0].channels; spec->multiout.num_dacs = preset->num_dacs; spec->multiout.dac_nids = preset->dac_nids; @@ -942,29 +921,23 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid, alc_fix_pll(codec); } -static void alc_automute_pin(struct hda_codec *codec) +static void alc_sku_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; unsigned int present; - unsigned int nid = spec->autocfg.hp_pins[0]; - int i; + unsigned int hp_nid = spec->autocfg.hp_pins[0]; + unsigned int sp_nid = spec->autocfg.speaker_pins[0]; /* need to execute and sync at first */ - snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0); - present = snd_hda_codec_read(codec, nid, 0, + snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0); + present = snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_GET_PIN_SENSE, 0); - spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0; - for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) { - nid = spec->autocfg.speaker_pins[i]; - if (!nid) - break; - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - spec->jack_present ? 0 : PIN_OUT); - } + spec->jack_present = (present & 0x80000000) != 0; + snd_hda_codec_write(codec, sp_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + spec->jack_present ? 0 : PIN_OUT); } -#if 0 /* it's broken in some cases -- temporarily disabled */ +#if 0 /* it's broken in some acses -- temporarily disabled */ static void alc_mic_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -996,19 +969,16 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) res >>= 28; else res >>= 26; - switch (res) { - case ALC880_HP_EVENT: - alc_automute_pin(codec); - break; - case ALC880_MIC_EVENT: + if (res == ALC880_HP_EVENT) + alc_sku_automute(codec); + + if (res == ALC880_MIC_EVENT) alc_mic_automute(codec); - break; - } } static void alc_inithook(struct hda_codec *codec) { - alc_automute_pin(codec); + alc_sku_automute(codec); alc_mic_automute(codec); } @@ -1030,21 +1000,69 @@ static void alc888_coef_init(struct hda_codec *codec) AC_VERB_SET_PROC_COEF, 0x3030); } -static void alc_auto_init_amp(struct hda_codec *codec, int type) +/* 32-bit subsystem ID for BIOS loading in HD Audio codec. + * 31 ~ 16 : Manufacture ID + * 15 ~ 8 : SKU ID + * 7 ~ 0 : Assembly ID + * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36 + */ +static void alc_subsystem_id(struct hda_codec *codec, + unsigned int porta, unsigned int porte, + unsigned int portd) { - unsigned int tmp; + unsigned int ass, tmp, i; + unsigned nid; + struct alc_spec *spec = codec->spec; + + ass = codec->subsystem_id & 0xffff; + if ((ass != codec->bus->pci->subsystem_device) && (ass & 1)) + goto do_sku; + + /* + * 31~30 : port conetcivity + * 29~21 : reserve + * 20 : PCBEEP input + * 19~16 : Check sum (15:1) + * 15~1 : Custom + * 0 : override + */ + nid = 0x1d; + if (codec->vendor_id == 0x10ec0260) + nid = 0x17; + ass = snd_hda_codec_get_pincfg(codec, nid); + if (!(ass & 1) && !(ass & 0x100000)) + return; + if ((ass >> 30) != 1) /* no physical connection */ + return; - switch (type) { - case ALC_INIT_GPIO1: + /* check sum */ + tmp = 0; + for (i = 1; i < 16; i++) { + if ((ass >> i) & 1) + tmp++; + } + if (((ass >> 16) & 0xf) != tmp) + return; +do_sku: + /* + * 0 : override + * 1 : Swap Jack + * 2 : 0 --> Desktop, 1 --> Laptop + * 3~5 : External Amplifier control + * 7~6 : Reserved + */ + tmp = (ass & 0x38) >> 3; /* external Amp control */ + switch (tmp) { + case 1: snd_hda_sequence_write(codec, alc_gpio1_init_verbs); break; - case ALC_INIT_GPIO2: + case 3: snd_hda_sequence_write(codec, alc_gpio2_init_verbs); break; - case ALC_INIT_GPIO3: + case 7: snd_hda_sequence_write(codec, alc_gpio3_init_verbs); break; - case ALC_INIT_DEFAULT: + case 5: /* set EAPD output high */ switch (codec->vendor_id) { case 0x10ec0260: snd_hda_codec_write(codec, 0x0f, 0, @@ -1098,7 +1116,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) tmp | 0x2010); break; case 0x10ec0888: - alc888_coef_init(codec); + /*alc888_coef_init(codec);*/ /* called in alc_init() */ break; case 0x10ec0267: case 0x10ec0268: @@ -1113,107 +1131,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) tmp | 0x3000); break; } - break; - } -} - -static void alc_init_auto_hp(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - if (!spec->autocfg.hp_pins[0]) - return; - - if (!spec->autocfg.speaker_pins[0]) { - if (spec->autocfg.line_out_pins[0] && - spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) - spec->autocfg.speaker_pins[0] = - spec->autocfg.line_out_pins[0]; - else - return; - } - - snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n", - spec->autocfg.hp_pins[0]); - snd_hda_codec_write_cache(codec, spec->autocfg.hp_pins[0], 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | ALC880_HP_EVENT); - spec->unsol_event = alc_sku_unsol_event; -} - -/* check subsystem ID and set up device-specific initialization; - * return 1 if initialized, 0 if invalid SSID - */ -/* 32-bit subsystem ID for BIOS loading in HD Audio codec. - * 31 ~ 16 : Manufacture ID - * 15 ~ 8 : SKU ID - * 7 ~ 0 : Assembly ID - * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36 - */ -static int alc_subsystem_id(struct hda_codec *codec, - hda_nid_t porta, hda_nid_t porte, - hda_nid_t portd) -{ - unsigned int ass, tmp, i; - unsigned nid; - struct alc_spec *spec = codec->spec; - - ass = codec->subsystem_id & 0xffff; - if ((ass != codec->bus->pci->subsystem_device) && (ass & 1)) - goto do_sku; - - /* invalid SSID, check the special NID pin defcfg instead */ - /* - * 31~30 : port connectivity - * 29~21 : reserve - * 20 : PCBEEP input - * 19~16 : Check sum (15:1) - * 15~1 : Custom - * 0 : override - */ - nid = 0x1d; - if (codec->vendor_id == 0x10ec0260) - nid = 0x17; - ass = snd_hda_codec_get_pincfg(codec, nid); - snd_printd("realtek: No valid SSID, " - "checking pincfg 0x%08x for NID 0x%x\n", - ass, nid); - if (!(ass & 1) && !(ass & 0x100000)) - return 0; - if ((ass >> 30) != 1) /* no physical connection */ - return 0; - - /* check sum */ - tmp = 0; - for (i = 1; i < 16; i++) { - if ((ass >> i) & 1) - tmp++; - } - if (((ass >> 16) & 0xf) != tmp) - return 0; -do_sku: - snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n", - ass & 0xffff, codec->vendor_id); - /* - * 0 : override - * 1 : Swap Jack - * 2 : 0 --> Desktop, 1 --> Laptop - * 3~5 : External Amplifier control - * 7~6 : Reserved - */ - tmp = (ass & 0x38) >> 3; /* external Amp control */ - switch (tmp) { - case 1: - spec->init_amp = ALC_INIT_GPIO1; - break; - case 3: - spec->init_amp = ALC_INIT_GPIO2; - break; - case 7: - spec->init_amp = ALC_INIT_GPIO3; - break; - case 5: - spec->init_amp = ALC_INIT_DEFAULT; + default: break; } @@ -1221,7 +1139,7 @@ static int alc_subsystem_id(struct hda_codec *codec, * when the external headphone out jack is plugged" */ if (!(ass & 0x8000)) - return 1; + return; /* * 10~8 : Jack location * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered @@ -1229,6 +1147,14 @@ static int alc_subsystem_id(struct hda_codec *codec, * 15 : 1 --> enable the function "Mute internal speaker * when the external headphone out jack is plugged" */ + if (!spec->autocfg.speaker_pins[0]) { + if (spec->autocfg.line_out_pins[0]) + spec->autocfg.speaker_pins[0] = + spec->autocfg.line_out_pins[0]; + else + return; + } + if (!spec->autocfg.hp_pins[0]) { tmp = (ass >> 11) & 0x3; /* HP to chassis */ if (tmp == 0) @@ -1238,23 +1164,23 @@ static int alc_subsystem_id(struct hda_codec *codec, else if (tmp == 2) spec->autocfg.hp_pins[0] = portd; else - return 1; + return; } + if (spec->autocfg.hp_pins[0]) + snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | ALC880_HP_EVENT); + +#if 0 /* it's broken in some acses -- temporarily disabled */ + if (spec->autocfg.input_pins[AUTO_PIN_MIC] && + spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC]) + snd_hda_codec_write(codec, + spec->autocfg.input_pins[AUTO_PIN_MIC], 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | ALC880_MIC_EVENT); +#endif /* disabled */ - alc_init_auto_hp(codec); - return 1; -} - -static void alc_ssid_check(struct hda_codec *codec, - hda_nid_t porta, hda_nid_t porte, hda_nid_t portd) -{ - if (!alc_subsystem_id(codec, porta, porte, portd)) { - struct alc_spec *spec = codec->spec; - snd_printd("realtek: " - "Enable default setup for auto mode as fallback\n"); - spec->init_amp = ALC_INIT_DEFAULT; - alc_init_auto_hp(codec); - } + spec->unsol_event = alc_sku_unsol_event; } /* @@ -1389,58 +1315,32 @@ static struct hda_verb alc888_fujitsu_xa3530_verbs[] = { {} }; -static void alc_automute_amp(struct hda_codec *codec) +static void alc888_fujitsu_xa3530_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; - unsigned int val, mute; - hda_nid_t nid; - int i; - - spec->jack_present = 0; - for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) { - nid = spec->autocfg.hp_pins[i]; - if (!nid) - break; - val = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_SENSE, 0); - if (val & AC_PINSENSE_PRESENCE) { - spec->jack_present = 1; - break; - } - } - - mute = spec->jack_present ? HDA_AMP_MUTE : 0; + unsigned int present; + unsigned int bits; + /* Line out presence */ + present = snd_hda_codec_read(codec, 0x17, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + /* HP out presence */ + present = present || snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + bits = present ? HDA_AMP_MUTE : 0; /* Toggle internal speakers muting */ - for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) { - nid = spec->autocfg.speaker_pins[i]; - if (!nid) - break; - snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); - } + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + /* Toggle internal bass muting */ + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } -static void alc_automute_amp_unsol_event(struct hda_codec *codec, - unsigned int res) +static void alc888_fujitsu_xa3530_unsol_event(struct hda_codec *codec, + unsigned int res) { - if (codec->vendor_id == 0x10ec0880) - res >>= 28; - else - res >>= 26; - if (res == ALC880_HP_EVENT) - alc_automute_amp(codec); + if (res >> 26 == ALC880_HP_EVENT) + alc888_fujitsu_xa3530_automute(codec); } -static void alc888_fujitsu_xa3530_init_hook(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x17; /* line-out */ - spec->autocfg.hp_pins[1] = 0x1b; /* hp */ - spec->autocfg.speaker_pins[0] = 0x14; /* speaker */ - spec->autocfg.speaker_pins[1] = 0x15; /* bass */ - alc_automute_amp(codec); -} /* * ALC888 Acer Aspire 4930G model @@ -1464,78 +1364,6 @@ static struct hda_verb alc888_acer_aspire_4930g_verbs[] = { { } }; -/* - * ALC888 Acer Aspire 6530G model - */ - -static struct hda_verb alc888_acer_aspire_6530g_verbs[] = { -/* Bias voltage on for external mic port */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80}, -/* Enable unsolicited event for HP jack */ - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, -/* Enable speaker output */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, -/* Enable headphone output */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - { } -}; - -/* - * ALC889 Acer Aspire 8930G model - */ - -static struct hda_verb alc889_acer_aspire_8930g_verbs[] = { -/* Front Mic: set to PIN_IN (empty by default) */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, -/* Unselect Front Mic by default in input mixer 3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)}, -/* Enable unsolicited event for HP jack */ - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, -/* Connect Internal Front to Front */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, -/* Connect Internal Rear to Rear */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, -/* Connect Internal CLFE to CLFE */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, -/* Connect HP out to Front */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, -/* Enable all DACs */ -/* DAC DISABLE/MUTE 1? */ -/* setting bits 1-5 disables DAC nids 0x02-0x06 apparently. Init=0x38 */ - {0x20, AC_VERB_SET_COEF_INDEX, 0x03}, - {0x20, AC_VERB_SET_PROC_COEF, 0x0000}, -/* DAC DISABLE/MUTE 2? */ -/* some bit here disables the other DACs. Init=0x4900 */ - {0x20, AC_VERB_SET_COEF_INDEX, 0x08}, - {0x20, AC_VERB_SET_PROC_COEF, 0x0000}, -/* Enable amplifiers */ - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, - {0x15, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, -/* DMIC fix - * This laptop has a stereo digital microphone. The mics are only 1cm apart - * which makes the stereo useless. However, either the mic or the ALC889 - * makes the signal become a difference/sum signal instead of standard - * stereo, which is annoying. So instead we flip this bit which makes the - * codec replicate the sum signal to both channels, turning it into a - * normal mono mic. - */ -/* DMIC_CONTROL? Init value = 0x0001 */ - {0x20, AC_VERB_SET_COEF_INDEX, 0x0b}, - {0x20, AC_VERB_SET_PROC_COEF, 0x0003}, - { } -}; - static struct hda_input_mux alc888_2_capture_sources[2] = { /* Front mic only available on one ADC */ { @@ -1557,57 +1385,6 @@ static struct hda_input_mux alc888_2_capture_sources[2] = { } }; -static struct hda_input_mux alc888_acer_aspire_6530_sources[2] = { - /* Interal mic only available on one ADC */ - { - .num_items = 3, - .items = { - { "Ext Mic", 0x0 }, - { "CD", 0x4 }, - { "Int Mic", 0xb }, - }, - }, - { - .num_items = 2, - .items = { - { "Ext Mic", 0x0 }, - { "CD", 0x4 }, - }, - } -}; - -static struct hda_input_mux alc889_capture_sources[3] = { - /* Digital mic only available on first "ADC" */ - { - .num_items = 5, - .items = { - { "Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - { "Front Mic", 0xb }, - { "Input Mix", 0xa }, - }, - }, - { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - { "Input Mix", 0xa }, - }, - }, - { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - { "Input Mix", 0xa }, - }, - } -}; - static struct snd_kcontrol_new alc888_base_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), @@ -1630,24 +1407,22 @@ static struct snd_kcontrol_new alc888_base_mixer[] = { { } /* end */ }; -static void alc888_acer_aspire_4930g_init_hook(struct hda_codec *codec) +static void alc888_acer_aspire_4930g_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - alc_automute_amp(codec); + unsigned int present; + unsigned int bits; + present = snd_hda_codec_read(codec, 0x15, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } -static void alc889_acer_aspire_8930g_init_hook(struct hda_codec *codec) +static void alc888_acer_aspire_4930g_unsol_event(struct hda_codec *codec, + unsigned int res) { - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x16; - spec->autocfg.speaker_pins[2] = 0x1b; - alc_automute_amp(codec); + if (res >> 26 == ALC880_HP_EVENT) + alc888_acer_aspire_4930g_automute(codec); } /* @@ -2615,6 +2390,21 @@ static struct hda_verb alc880_beep_init_verbs[] = { { } }; +/* toggle speaker-output according to the hp-jack state */ +static void alc880_uniwill_hp_automute(struct hda_codec *codec) +{ + unsigned int present; + unsigned char bits; + + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); +} + /* auto-toggle front mic */ static void alc880_uniwill_mic_automute(struct hda_codec *codec) { @@ -2627,14 +2417,9 @@ static void alc880_uniwill_mic_automute(struct hda_codec *codec) snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits); } -static void alc880_uniwill_init_hook(struct hda_codec *codec) +static void alc880_uniwill_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x16; - alc_automute_amp(codec); + alc880_uniwill_hp_automute(codec); alc880_uniwill_mic_automute(codec); } @@ -2645,22 +2430,24 @@ static void alc880_uniwill_unsol_event(struct hda_codec *codec, * definition. 4bit tag is placed at 28 bit! */ switch (res >> 28) { + case ALC880_HP_EVENT: + alc880_uniwill_hp_automute(codec); + break; case ALC880_MIC_EVENT: alc880_uniwill_mic_automute(codec); break; - default: - alc_automute_amp_unsol_event(codec, res); - break; } } -static void alc880_uniwill_p53_init_hook(struct hda_codec *codec) +static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present; + unsigned char bits; - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - alc_automute_amp(codec); + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, HDA_AMP_MUTE, bits); } static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) @@ -2682,10 +2469,10 @@ static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec, /* Looks like the unsol event is incompatible with the standard * definition. 4bit tag is placed at 28 bit! */ + if ((res >> 28) == ALC880_HP_EVENT) + alc880_uniwill_p53_hp_automute(codec); if ((res >> 28) == ALC880_DCVOL_EVENT) alc880_uniwill_p53_dcvol_automute(codec); - else - alc_automute_amp_unsol_event(codec, res); } /* @@ -2755,7 +2542,6 @@ static struct hda_verb alc880_pin_asus_init_verbs[] = { /* Enable GPIO mask and set output */ #define alc880_gpio1_init_verbs alc_gpio1_init_verbs #define alc880_gpio2_init_verbs alc_gpio2_init_verbs -#define alc880_gpio3_init_verbs alc_gpio3_init_verbs /* Clevo m520g init */ static struct hda_verb alc880_pin_clevo_init_verbs[] = { @@ -2918,18 +2704,30 @@ static struct hda_verb alc880_lg_init_verbs[] = { {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* jack sense */ - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1}, { } }; /* toggle speaker-output according to the hp-jack state */ -static void alc880_lg_init_hook(struct hda_codec *codec) +static void alc880_lg_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present; + unsigned char bits; - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x17; - alc_automute_amp(codec); + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); +} + +static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res) +{ + /* Looks like the unsol event is incompatible with the standard + * definition. 4bit tag is placed at 28 bit! + */ + if ((res >> 28) == 0x01) + alc880_lg_automute(codec); } /* @@ -3003,18 +2801,30 @@ static struct hda_verb alc880_lg_lw_init_verbs[] = { {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* jack sense */ - {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1}, { } }; /* toggle speaker-output according to the hp-jack state */ -static void alc880_lg_lw_init_hook(struct hda_codec *codec) +static void alc880_lg_lw_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present; + unsigned char bits; + + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); +} - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - alc_automute_amp(codec); +static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res) +{ + /* Looks like the unsol event is incompatible with the standard + * definition. 4bit tag is placed at 28 bit! + */ + if ((res >> 28) == 0x01) + alc880_lg_lw_automute(codec); } static struct snd_kcontrol_new alc880_medion_rim_mixer[] = { @@ -3061,10 +2871,16 @@ static struct hda_verb alc880_medion_rim_init_verbs[] = { /* toggle speaker-output according to the hp-jack state */ static void alc880_medion_rim_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; - alc_automute_amp(codec); - /* toggle EAPD */ - if (spec->jack_present) + unsigned int present; + unsigned char bits; + + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) + & AC_PINSENSE_PRESENCE; + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + if (present) snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0); else snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2); @@ -3080,15 +2896,6 @@ static void alc880_medion_rim_unsol_event(struct hda_codec *codec, alc880_medion_rim_automute(codec); } -static void alc880_medion_rim_init_hook(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x1b; - alc880_medion_rim_automute(codec); -} - #ifdef CONFIG_SND_HDA_POWER_SAVE static struct hda_amp_list alc880_loopbacks[] = { { 0x0b, HDA_INPUT, 0 }, @@ -3117,7 +2924,8 @@ static int alc_init(struct hda_codec *codec) unsigned int i; alc_fix_pll(codec); - alc_auto_init_amp(codec, spec->init_amp); + if (codec->vendor_id == 0x10ec0888) + alc888_coef_init(codec); for (i = 0; i < spec->num_init_verbs; i++) snd_hda_sequence_write(codec, spec->init_verbs[i]); @@ -3319,10 +3127,7 @@ static int alc_build_pcms(struct hda_codec *codec) if (spec->no_analog) goto skip_analog; - snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog), - "%s Analog", codec->chip_name); info->name = spec->stream_name_analog; - if (spec->stream_analog_playback) { if (snd_BUG_ON(!spec->multiout.dac_nids)) return -EINVAL; @@ -3348,9 +3153,6 @@ static int alc_build_pcms(struct hda_codec *codec) skip_analog: /* SPDIF for stream index #1 */ if (spec->multiout.dig_out_nid || spec->dig_in_nid) { - snprintf(spec->stream_name_digital, - sizeof(spec->stream_name_digital), - "%s Digital", codec->chip_name); codec->num_pcms = 2; codec->slave_dig_outs = spec->multiout.slave_dig_outs; info = spec->pcm_rec + 1; @@ -3953,7 +3755,7 @@ static struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_2_jack_modes, .input_mux = &alc880_f1734_capture_source, .unsol_event = alc880_uniwill_p53_unsol_event, - .init_hook = alc880_uniwill_p53_init_hook, + .init_hook = alc880_uniwill_p53_hp_automute, }, [ALC880_ASUS] = { .mixers = { alc880_asus_mixer }, @@ -4030,7 +3832,7 @@ static struct alc_config_preset alc880_presets[] = { .need_dac_fix = 1, .input_mux = &alc880_capture_source, .unsol_event = alc880_uniwill_unsol_event, - .init_hook = alc880_uniwill_init_hook, + .init_hook = alc880_uniwill_automute, }, [ALC880_UNIWILL_P53] = { .mixers = { alc880_uniwill_p53_mixer }, @@ -4042,7 +3844,7 @@ static struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_threestack_modes, .input_mux = &alc880_capture_source, .unsol_event = alc880_uniwill_p53_unsol_event, - .init_hook = alc880_uniwill_p53_init_hook, + .init_hook = alc880_uniwill_p53_hp_automute, }, [ALC880_FUJITSU] = { .mixers = { alc880_fujitsu_mixer }, @@ -4056,7 +3858,7 @@ static struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_2_jack_modes, .input_mux = &alc880_capture_source, .unsol_event = alc880_uniwill_p53_unsol_event, - .init_hook = alc880_uniwill_p53_init_hook, + .init_hook = alc880_uniwill_p53_hp_automute, }, [ALC880_CLEVO] = { .mixers = { alc880_three_stack_mixer }, @@ -4081,8 +3883,8 @@ static struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_lg_ch_modes, .need_dac_fix = 1, .input_mux = &alc880_lg_capture_source, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc880_lg_init_hook, + .unsol_event = alc880_lg_unsol_event, + .init_hook = alc880_lg_automute, #ifdef CONFIG_SND_HDA_POWER_SAVE .loopbacks = alc880_lg_loopbacks, #endif @@ -4097,8 +3899,8 @@ static struct alc_config_preset alc880_presets[] = { .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes), .channel_mode = alc880_lg_lw_modes, .input_mux = &alc880_lg_lw_capture_source, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc880_lg_lw_init_hook, + .unsol_event = alc880_lg_lw_unsol_event, + .init_hook = alc880_lg_lw_automute, }, [ALC880_MEDION_RIM] = { .mixers = { alc880_medion_rim_mixer }, @@ -4112,7 +3914,7 @@ static struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_2_jack_modes, .input_mux = &alc880_medion_rim_capture_source, .unsol_event = alc880_medion_rim_unsol_event, - .init_hook = alc880_medion_rim_init_hook, + .init_hook = alc880_medion_rim_automute, }, #ifdef CONFIG_SND_DEBUG [ALC880_TEST] = { @@ -4397,6 +4199,7 @@ static void alc880_auto_init_multi_out(struct hda_codec *codec) struct alc_spec *spec = codec->spec; int i; + alc_subsystem_id(codec, 0x15, 0x1b, 0x14); for (i = 0; i < spec->autocfg.line_outs; i++) { hda_nid_t nid = spec->autocfg.line_out_pins[i]; int pin_type = get_pin_type(spec->autocfg.line_out_type); @@ -4501,8 +4304,6 @@ static int alc880_parse_auto_config(struct hda_codec *codec) spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux[0]; - alc_ssid_check(codec, 0x15, 0x1b, 0x14); - return 1; } @@ -4560,8 +4361,8 @@ static int patch_alc880(struct hda_codec *codec) alc880_models, alc880_cfg_tbl); if (board_config < 0) { - printk(KERN_INFO "hda_codec: Unknown model for %s, " - "trying auto-probe from BIOS...\n", codec->chip_name); + printk(KERN_INFO "hda_codec: Unknown model for ALC880, " + "trying auto-probe from BIOS...\n"); board_config = ALC880_AUTO; } @@ -4588,10 +4389,12 @@ static int patch_alc880(struct hda_codec *codec) if (board_config != ALC880_AUTO) setup_preset(spec, &alc880_presets[board_config]); + spec->stream_name_analog = "ALC880 Analog"; spec->stream_analog_playback = &alc880_pcm_analog_playback; spec->stream_analog_capture = &alc880_pcm_analog_capture; spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture; + spec->stream_name_digital = "ALC880 Digital"; spec->stream_digital_playback = &alc880_pcm_digital_playback; spec->stream_digital_capture = &alc880_pcm_digital_capture; @@ -5876,6 +5679,7 @@ static void alc260_auto_init_multi_out(struct hda_codec *codec) struct alc_spec *spec = codec->spec; hda_nid_t nid; + alc_subsystem_id(codec, 0x10, 0x15, 0x0f); nid = spec->autocfg.line_out_pins[0]; if (nid) { int pin_type = get_pin_type(spec->autocfg.line_out_type); @@ -5985,8 +5789,6 @@ static int alc260_parse_auto_config(struct hda_codec *codec) spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux[0]; - alc_ssid_check(codec, 0x10, 0x15, 0x0f); - return 1; } @@ -6204,9 +6006,8 @@ static int patch_alc260(struct hda_codec *codec) alc260_models, alc260_cfg_tbl); if (board_config < 0) { - snd_printd(KERN_INFO "hda_codec: Unknown model for %s, " - "trying auto-probe from BIOS...\n", - codec->chip_name); + snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, " + "trying auto-probe from BIOS...\n"); board_config = ALC260_AUTO; } @@ -6233,9 +6034,11 @@ static int patch_alc260(struct hda_codec *codec) if (board_config != ALC260_AUTO) setup_preset(spec, &alc260_presets[board_config]); + spec->stream_name_analog = "ALC260 Analog"; spec->stream_analog_playback = &alc260_pcm_analog_playback; spec->stream_analog_capture = &alc260_pcm_analog_capture; + spec->stream_name_digital = "ALC260 Digital"; spec->stream_digital_playback = &alc260_pcm_digital_playback; spec->stream_digital_capture = &alc260_pcm_digital_capture; @@ -6312,16 +6115,6 @@ static struct hda_input_mux alc882_capture_source = { { "CD", 0x4 }, }, }; - -static struct hda_input_mux mb5_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - /* * 2ch mode */ @@ -6379,7 +6172,7 @@ static struct hda_channel_mode alc882_sixstack_modes[2] = { }; /* - * macbook pro ALC885 can switch LineIn to LineOut without losing Mic + * macbook pro ALC885 can switch LineIn to LineOut without loosing Mic */ /* @@ -6409,34 +6202,6 @@ static struct hda_channel_mode alc885_mbp_6ch_modes[2] = { { 6, alc885_mbp_ch6_init }, }; -/* - * 2ch - * Speakers/Woofer/HP = Front - * LineIn = Input - */ -static struct hda_verb alc885_mb5_ch2_init[] = { - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - { } /* end */ -}; - -/* - * 6ch mode - * Speakers/HP = Front - * Woofer = LFE - * LineIn = Surround - */ -static struct hda_verb alc885_mb5_ch6_init[] = { - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - { } /* end */ -}; - -static struct hda_channel_mode alc885_mb5_6ch_modes[2] = { - { 2, alc885_mb5_ch2_init }, - { 6, alc885_mb5_ch6_init }, -}; /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b @@ -6479,25 +6244,6 @@ static struct snd_kcontrol_new alc885_mbp3_mixer[] = { HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT), { } /* end */ }; - -static struct snd_kcontrol_new alc885_mb5_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("HP Playback Volume", 0x0f, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE ("HP Playback Switch", 0x0f, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x19, 0x00, HDA_INPUT), - { } /* end */ -}; - static struct snd_kcontrol_new alc882_w2jc_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), @@ -6725,55 +6471,6 @@ static struct hda_verb alc882_macpro_init_verbs[] = { { } }; -/* Macbook 5,1 */ -static struct hda_verb alc885_mb5_init_verbs[] = { - /* DACs */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Front mixer */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Surround mixer */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* LFE mixer */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* HP mixer */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Front Pin (0x0c) */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* LFE Pin (0x0e) */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* HP Pin (0x0f) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x03}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line In pin */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - { } -}; - /* Macbook Pro rev3 */ static struct hda_verb alc885_mbp3_init_verbs[] = { /* Front mixer: unmute input/output amp left and right (volume = 0) */ @@ -6863,23 +6560,45 @@ static struct hda_verb alc885_imac24_init_verbs[] = { }; /* Toggle speaker-output according to the hp-jack state */ -static void alc885_imac24_automute_init_hook(struct hda_codec *codec) +static void alc885_imac24_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present; - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x18; - spec->autocfg.speaker_pins[1] = 0x1a; - alc_automute_amp(codec); + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } -static void alc885_mbp3_init_hook(struct hda_codec *codec) +/* Processes unsolicited events. */ +static void alc885_imac24_unsol_event(struct hda_codec *codec, + unsigned int res) { - struct alc_spec *spec = codec->spec; + /* Headphone insertion or removal. */ + if ((res >> 26) == ALC880_HP_EVENT) + alc885_imac24_automute(codec); +} + +static void alc885_mbp3_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x15, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE); - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - alc_automute_amp(codec); +} +static void alc885_mbp3_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + /* Headphone insertion or removal. */ + if ((res >> 26) == ALC880_HP_EVENT) + alc885_mbp3_automute(codec); } @@ -6904,25 +6623,24 @@ static struct hda_verb alc882_targa_verbs[] = { /* toggle speaker-output according to the hp-jack state */ static void alc882_targa_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; - alc_automute_amp(codec); - snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, - spec->jack_present ? 1 : 3); -} - -static void alc882_targa_init_hook(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; + unsigned int present; - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x1b; - alc882_targa_automute(codec); + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, + present ? 1 : 3); } static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res) { - if ((res >> 26) == ALC880_HP_EVENT) + /* Looks like the unsol event is incompatible with the standard + * definition. 4bit tag is placed at 26 bit! + */ + if (((res >> 26) == ALC880_HP_EVENT)) { alc882_targa_automute(codec); + } } static struct hda_verb alc882_asus_a7j_verbs[] = { @@ -7004,7 +6722,7 @@ static void alc885_macpro_init_hook(struct hda_codec *codec) static void alc885_imac24_init_hook(struct hda_codec *codec) { alc885_macpro_init_hook(codec); - alc885_imac24_automute_init_hook(codec); + alc885_imac24_automute(codec); } /* @@ -7079,7 +6797,7 @@ static struct hda_verb alc882_auto_init_verbs[] = { #define alc882_loopbacks alc880_loopbacks #endif -/* pcm configuration: identical with ALC880 */ +/* pcm configuration: identiacal with ALC880 */ #define alc882_pcm_analog_playback alc880_pcm_analog_playback #define alc882_pcm_analog_capture alc880_pcm_analog_capture #define alc882_pcm_digital_playback alc880_pcm_digital_playback @@ -7097,7 +6815,6 @@ static const char *alc882_models[ALC882_MODEL_LAST] = { [ALC882_ASUS_A7J] = "asus-a7j", [ALC882_ASUS_A7M] = "asus-a7m", [ALC885_MACPRO] = "macpro", - [ALC885_MB5] = "mb5", [ALC885_MBP3] = "mbp3", [ALC885_IMAC24] = "imac24", [ALC882_AUTO] = "auto", @@ -7175,20 +6892,8 @@ static struct alc_config_preset alc882_presets[] = { .input_mux = &alc882_capture_source, .dig_out_nid = ALC882_DIGOUT_NID, .dig_in_nid = ALC882_DIGIN_NID, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc885_mbp3_init_hook, - }, - [ALC885_MB5] = { - .mixers = { alc885_mb5_mixer, alc882_chmode_mixer }, - .init_verbs = { alc885_mb5_init_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .channel_mode = alc885_mb5_6ch_modes, - .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes), - .input_mux = &mb5_capture_source, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, + .unsol_event = alc885_mbp3_unsol_event, + .init_hook = alc885_mbp3_automute, }, [ALC885_MACPRO] = { .mixers = { alc882_macpro_mixer }, @@ -7212,7 +6917,7 @@ static struct alc_config_preset alc882_presets[] = { .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), .channel_mode = alc882_ch_modes, .input_mux = &alc882_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc885_imac24_unsol_event, .init_hook = alc885_imac24_init_hook, }, [ALC882_TARGA] = { @@ -7229,7 +6934,7 @@ static struct alc_config_preset alc882_presets[] = { .need_dac_fix = 1, .input_mux = &alc882_capture_source, .unsol_event = alc882_targa_unsol_event, - .init_hook = alc882_targa_init_hook, + .init_hook = alc882_targa_automute, }, [ALC882_ASUS_A7J] = { .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer }, @@ -7309,6 +7014,7 @@ static void alc882_auto_init_multi_out(struct hda_codec *codec) struct alc_spec *spec = codec->spec; int i; + alc_subsystem_id(codec, 0x15, 0x1b, 0x14); for (i = 0; i <= HDA_SIDE; i++) { hda_nid_t nid = spec->autocfg.line_out_pins[i]; int pin_type = get_pin_type(spec->autocfg.line_out_type); @@ -7491,17 +7197,10 @@ static int patch_alc882(struct hda_codec *codec) case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */ case 0x106b00a4: /* MacbookPro4,1 */ case 0x106b2c00: /* Macbook Pro rev3 */ - /* Macbook 3.1 (0x106b3600) is handled by patch_alc883() */ + case 0x106b3600: /* Macbook 3.1 */ case 0x106b3800: /* MacbookPro4,1 - latter revision */ board_config = ALC885_MBP3; break; - case 0x106b3f00: /* Macbook 5,1 */ - case 0x106b4000: /* Macbook Pro 5,1 - FIXME: HP jack sense - * seems not working, so apparently - * no perfect solution yet - */ - board_config = ALC885_MB5; - break; default: /* ALC889A is handled better as ALC888-compatible */ if (codec->revision_id == 0x100101 || @@ -7509,9 +7208,8 @@ static int patch_alc882(struct hda_codec *codec) alc_free(codec); return patch_alc883(codec); } - printk(KERN_INFO "hda_codec: Unknown model for %s, " - "trying auto-probe from BIOS...\n", - codec->chip_name); + printk(KERN_INFO "hda_codec: Unknown model for ALC882, " + "trying auto-probe from BIOS...\n"); board_config = ALC882_AUTO; } } @@ -7541,6 +7239,14 @@ static int patch_alc882(struct hda_codec *codec) if (board_config != ALC882_AUTO) setup_preset(spec, &alc882_presets[board_config]); + if (codec->vendor_id == 0x10ec0885) { + spec->stream_name_analog = "ALC885 Analog"; + spec->stream_name_digital = "ALC885 Digital"; + } else { + spec->stream_name_analog = "ALC882 Analog"; + spec->stream_name_digital = "ALC882 Digital"; + } + spec->stream_analog_playback = &alc882_pcm_analog_playback; spec->stream_analog_capture = &alc882_pcm_analog_capture; /* FIXME: setup DAC5 */ @@ -7550,6 +7256,7 @@ static int patch_alc882(struct hda_codec *codec) spec->stream_digital_playback = &alc882_pcm_digital_playback; spec->stream_digital_capture = &alc882_pcm_digital_capture; + spec->capture_style = CAPT_MIX; /* matrix-style capture */ if (!spec->adc_nids && spec->input_mux) { /* check whether NID 0x07 is valid */ unsigned int wcap = get_wcaps(codec, 0x07); @@ -7692,17 +7399,6 @@ static struct hda_input_mux alc883_asus_eee1601_capture_source = { }, }; -static struct hda_input_mux alc889A_mb31_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x0 }, - /* Front Mic (0x01) unused */ - { "Line", 0x2 }, - /* Line 2 (0x03) unused */ - /* CD (0x04) unsused? */ - }, -}; - /* * 2ch mode */ @@ -7752,15 +7448,12 @@ static struct hda_channel_mode alc883_3ST_6ch_modes[3] = { { 6, alc883_3ST_ch6_init }, }; - /* * 2ch mode */ -static struct hda_verb alc883_4ST_ch2_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, +static struct hda_verb alc883_3ST_ch2_intel_init[] = { + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, { } /* end */ @@ -7769,11 +7462,9 @@ static struct hda_verb alc883_4ST_ch2_init[] = { /* * 4ch mode */ -static struct hda_verb alc883_4ST_ch4_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, +static struct hda_verb alc883_3ST_ch4_intel_init[] = { + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, @@ -7783,82 +7474,20 @@ static struct hda_verb alc883_4ST_ch4_init[] = { /* * 6ch mode */ -static struct hda_verb alc883_4ST_ch6_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, +static struct hda_verb alc883_3ST_ch6_intel_init[] = { + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 }, { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, { } /* end */ -}; - -/* - * 8ch mode - */ -static struct hda_verb alc883_4ST_ch8_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 }, - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -static struct hda_channel_mode alc883_4ST_8ch_modes[4] = { - { 2, alc883_4ST_ch2_init }, - { 4, alc883_4ST_ch4_init }, - { 6, alc883_4ST_ch6_init }, - { 8, alc883_4ST_ch8_init }, -}; - - -/* - * 2ch mode - */ -static struct hda_verb alc883_3ST_ch2_intel_init[] = { - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* - * 4ch mode - */ -static struct hda_verb alc883_3ST_ch4_intel_init[] = { - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -/* - * 6ch mode - */ -static struct hda_verb alc883_3ST_ch6_intel_init[] = { - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = { - { 2, alc883_3ST_ch2_intel_init }, - { 4, alc883_3ST_ch4_intel_init }, - { 6, alc883_3ST_ch6_intel_init }, +}; + +static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = { + { 2, alc883_3ST_ch2_intel_init }, + { 4, alc883_3ST_ch4_intel_init }, + { 6, alc883_3ST_ch6_intel_init }, }; /* @@ -7888,49 +7517,6 @@ static struct hda_channel_mode alc883_sixstack_modes[2] = { { 8, alc883_sixstack_ch8_init }, }; -/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */ -static struct hda_verb alc889A_mb31_ch2_init[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */ - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */ - { } /* end */ -}; - -/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */ -static struct hda_verb alc889A_mb31_ch4_init[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */ - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */ - { } /* end */ -}; - -/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */ -static struct hda_verb alc889A_mb31_ch5_init[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */ - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */ - { } /* end */ -}; - -/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */ -static struct hda_verb alc889A_mb31_ch6_init[] = { - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */ - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */ - { } /* end */ -}; - -static struct hda_channel_mode alc889A_mb31_6ch_modes[4] = { - { 2, alc889A_mb31_ch2_init }, - { 4, alc889A_mb31_ch4_init }, - { 5, alc889A_mb31_ch5_init }, - { 6, alc889A_mb31_ch6_init }, -}; - static struct hda_verb alc883_medion_eapd_verbs[] = { /* eanable EAPD on medion laptop */ {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, @@ -8099,7 +7685,7 @@ static struct snd_kcontrol_new alc883_fivestack_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_targa_mixer[] = { +static struct snd_kcontrol_new alc883_tagra_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), @@ -8119,7 +7705,7 @@ static struct snd_kcontrol_new alc883_targa_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = { +static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), @@ -8184,19 +7770,6 @@ static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("LFE Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), @@ -8209,6 +7782,8 @@ static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = { HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT), HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x1a, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), @@ -8222,42 +7797,6 @@ static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc889A_mb31_mixer[] = { - /* Output mixers */ - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00, - HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT), - /* Output switches */ - HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT), - HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT), - /* Boost mixers */ - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT), - /* Input mixers */ - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - { } /* end */ -}; - -static struct snd_kcontrol_new alc883_vaiott_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; - static struct hda_bind_ctls alc883_bind_cap_vol = { .ops = &snd_hda_bind_vol, .values = { @@ -8393,14 +7932,16 @@ static struct hda_verb alc883_init_verbs[] = { }; /* toggle speaker-output according to the hp-jack state */ -static void alc883_mitac_init_hook(struct hda_codec *codec) +static void alc883_mitac_hp_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x17; - alc_automute_amp(codec); + present = snd_hda_codec_read(codec, 0x15, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } /* auto-toggle front mic */ @@ -8417,6 +7958,25 @@ static void alc883_mitac_mic_automute(struct hda_codec *codec) } */ +static void alc883_mitac_automute(struct hda_codec *codec) +{ + alc883_mitac_hp_automute(codec); + /* alc883_mitac_mic_automute(codec); */ +} + +static void alc883_mitac_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + switch (res >> 26) { + case ALC880_HP_EVENT: + alc883_mitac_hp_automute(codec); + break; + case ALC880_MIC_EVENT: + /* alc883_mitac_mic_automute(codec); */ + break; + } +} + static struct hda_verb alc883_mitac_verbs[] = { /* HP */ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, @@ -8461,31 +8021,21 @@ static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = { { } /* end */ }; -static struct hda_verb alc883_targa_verbs[] = { +static struct hda_verb alc883_tagra_verbs[] = { {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, -/* Connect Line-Out side jack (SPDIF) to Side */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, -/* Connect Mic jack to CLFE */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, -/* Connect Line-in jack to Surround */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, -/* Connect HP out jack to Front */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */ + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x01, AC_VERB_SET_GPIO_MASK, 0x03}, + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x03}, { } /* end */ }; @@ -8544,26 +8094,29 @@ static struct hda_verb alc888_6st_dell_verbs[] = { { } }; -static struct hda_verb alc883_vaiott_verbs[] = { - /* HP */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - - /* enable unsolicited event */ - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, +static void alc888_3st_hp_front_automute(struct hda_codec *codec) +{ + unsigned int present, bits; - { } /* end */ -}; + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); +} -static void alc888_3st_hp_init_hook(struct hda_codec *codec) +static void alc888_3st_hp_unsol_event(struct hda_codec *codec, + unsigned int res) { - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x16; - spec->autocfg.speaker_pins[2] = 0x18; - alc_automute_amp(codec); + switch (res >> 26) { + case ALC880_HP_EVENT: + alc888_3st_hp_front_automute(codec); + break; + } } static struct hda_verb alc888_3st_hp_verbs[] = { @@ -8660,18 +8213,56 @@ static struct hda_verb alc883_medion_md2_verbs[] = { }; /* toggle speaker-output according to the hp-jack state */ -static void alc883_medion_md2_init_hook(struct hda_codec *codec) +static void alc883_medion_md2_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present; + + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); +} + +static void alc883_medion_md2_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc883_medion_md2_automute(codec); +} + +/* toggle speaker-output according to the hp-jack state */ +static void alc883_tagra_automute(struct hda_codec *codec) +{ + unsigned int present; + unsigned char bits; + + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, + present ? 1 : 3); +} - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - alc_automute_amp(codec); +static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc883_tagra_automute(codec); } /* toggle speaker-output according to the hp-jack state */ -#define alc883_targa_init_hook alc882_targa_init_hook -#define alc883_targa_unsol_event alc882_targa_unsol_event +static void alc883_clevo_m720_hp_automute(struct hda_codec *codec) +{ + unsigned int present; + unsigned char bits; + + present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0) + & AC_PINSENSE_PRESENCE; + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); +} static void alc883_clevo_m720_mic_automute(struct hda_codec *codec) { @@ -8683,13 +8274,9 @@ static void alc883_clevo_m720_mic_automute(struct hda_codec *codec) HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } -static void alc883_clevo_m720_init_hook(struct hda_codec *codec) +static void alc883_clevo_m720_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - alc_automute_amp(codec); + alc883_clevo_m720_hp_automute(codec); alc883_clevo_m720_mic_automute(codec); } @@ -8697,32 +8284,52 @@ static void alc883_clevo_m720_unsol_event(struct hda_codec *codec, unsigned int res) { switch (res >> 26) { + case ALC880_HP_EVENT: + alc883_clevo_m720_hp_automute(codec); + break; case ALC880_MIC_EVENT: alc883_clevo_m720_mic_automute(codec); break; - default: - alc_automute_amp_unsol_event(codec, res); - break; } } /* toggle speaker-output according to the hp-jack state */ -static void alc883_2ch_fujitsu_pi2515_init_hook(struct hda_codec *codec) +static void alc883_2ch_fujitsu_pi2515_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present; + unsigned char bits; + + present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) + & AC_PINSENSE_PRESENCE; + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); +} - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - alc_automute_amp(codec); +static void alc883_2ch_fujitsu_pi2515_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc883_2ch_fujitsu_pi2515_automute(codec); } -static void alc883_haier_w66_init_hook(struct hda_codec *codec) +static void alc883_haier_w66_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present; + unsigned char bits; + + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + bits = present ? 0x80 : 0; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + 0x80, bits); +} - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - alc_automute_amp(codec); +static void alc883_haier_w66_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc883_haier_w66_automute(codec); } static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec) @@ -8730,8 +8337,8 @@ static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec) unsigned int present; unsigned char bits; - present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; bits = present ? HDA_AMP_MUTE : 0; snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, HDA_AMP_MUTE, bits); @@ -8761,14 +8368,23 @@ static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec, } /* toggle speaker-output according to the hp-jack state */ -static void alc883_acer_aspire_init_hook(struct hda_codec *codec) +static void alc883_acer_aspire_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present; + + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); +} - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x15; - spec->autocfg.speaker_pins[1] = 0x16; - alc_automute_amp(codec); +static void alc883_acer_aspire_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc883_acer_aspire_automute(codec); } static struct hda_verb alc883_acer_eapd_verbs[] = { @@ -8789,39 +8405,75 @@ static struct hda_verb alc883_acer_eapd_verbs[] = { { } }; -static void alc888_6st_dell_init_hook(struct hda_codec *codec) +static void alc888_6st_dell_front_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present; - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x15; - spec->autocfg.speaker_pins[2] = 0x16; - spec->autocfg.speaker_pins[3] = 0x17; - alc_automute_amp(codec); + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } -static void alc888_lenovo_sky_init_hook(struct hda_codec *codec) +static void alc888_6st_dell_unsol_event(struct hda_codec *codec, + unsigned int res) { - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x15; - spec->autocfg.speaker_pins[2] = 0x16; - spec->autocfg.speaker_pins[3] = 0x17; - spec->autocfg.speaker_pins[4] = 0x1a; - alc_automute_amp(codec); -} + switch (res >> 26) { + case ALC880_HP_EVENT: + /* printk(KERN_DEBUG "hp_event\n"); */ + alc888_6st_dell_front_automute(codec); + break; + } +} -static void alc883_vaiott_init_hook(struct hda_codec *codec) +static void alc888_lenovo_sky_front_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int mute; + unsigned int present; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x17; - alc_automute_amp(codec); + snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0); + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0); + present = (present & 0x80000000) != 0; + if (present) { + /* mute internal speaker */ + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + } else { + /* unmute internal speaker if necessary */ + mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + } +} + +static void alc883_lenovo_sky_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc888_lenovo_sky_front_automute(codec); } /* @@ -8909,33 +8561,39 @@ static void alc883_nb_mic_automute(struct hda_codec *codec) 0x7000 | (0x01 << 8) | (present ? 0x80 : 0)); } -static void alc883_M90V_init_hook(struct hda_codec *codec) +static void alc883_M90V_speaker_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present; + unsigned char bits; - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - spec->autocfg.speaker_pins[1] = 0x15; - spec->autocfg.speaker_pins[2] = 0x16; - alc_automute_pin(codec); + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) + & AC_PINSENSE_PRESENCE; + bits = present ? 0 : PIN_OUT; + snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + bits); + snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + bits); + snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + bits); } static void alc883_mode2_unsol_event(struct hda_codec *codec, unsigned int res) { switch (res >> 26) { + case ALC880_HP_EVENT: + alc883_M90V_speaker_automute(codec); + break; case ALC880_MIC_EVENT: alc883_nb_mic_automute(codec); break; - default: - alc_sku_unsol_event(codec, res); - break; } } static void alc883_mode2_inithook(struct hda_codec *codec) { - alc883_M90V_init_hook(codec); + alc883_M90V_speaker_automute(codec); alc883_nb_mic_automute(codec); } @@ -8952,56 +8610,39 @@ static struct hda_verb alc888_asus_eee1601_verbs[] = { { } /* end */ }; -static void alc883_eee1601_inithook(struct hda_codec *codec) +static void alc883_eee1601_speaker_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present; + unsigned char bits; - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x1b; - alc_automute_pin(codec); + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) + & AC_PINSENSE_PRESENCE; + bits = present ? 0 : PIN_OUT; + snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + bits); } -static struct hda_verb alc889A_mb31_verbs[] = { - /* Init rear pin (used as headphone output) */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */ - {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, - /* Init line pin (used as output in 4ch and 6ch mode) */ - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Connect to CLFE */ - /* Init line 2 pin (used as headphone out by default) */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Use as input */ - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */ - { } /* end */ -}; - -/* Mute speakers according to the headphone jack state */ -static void alc889A_mb31_automute(struct hda_codec *codec) +static void alc883_eee1601_unsol_event(struct hda_codec *codec, + unsigned int res) { - unsigned int present; - - /* Mute only in 2ch or 4ch mode */ - if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0) - == 0x00) { - present = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0) & AC_PINSENSE_PRESENCE; - snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); - snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + switch (res >> 26) { + case ALC880_HP_EVENT: + alc883_eee1601_speaker_automute(codec); + break; } } -static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res) +static void alc883_eee1601_inithook(struct hda_codec *codec) { - if ((res >> 26) == ALC880_HP_EVENT) - alc889A_mb31_automute(codec); + alc883_eee1601_speaker_automute(codec); } #ifdef CONFIG_SND_HDA_POWER_SAVE #define alc883_loopbacks alc880_loopbacks #endif -/* pcm configuration: identical with ALC880 */ +/* pcm configuration: identiacal with ALC880 */ #define alc883_pcm_analog_playback alc880_pcm_analog_playback #define alc883_pcm_analog_capture alc880_pcm_analog_capture #define alc883_pcm_analog_alt_capture alc880_pcm_analog_alt_capture @@ -9018,12 +8659,9 @@ static const char *alc883_models[ALC883_MODEL_LAST] = { [ALC883_6ST_DIG] = "6stack-dig", [ALC883_TARGA_DIG] = "targa-dig", [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig", - [ALC883_TARGA_8ch_DIG] = "targa-8ch-dig", [ALC883_ACER] = "acer", [ALC883_ACER_ASPIRE] = "acer-aspire", [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g", - [ALC888_ACER_ASPIRE_6530G] = "acer-aspire-6530g", - [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g", [ALC883_MEDION] = "medion", [ALC883_MEDION_MD2] = "medion-md2", [ALC883_LAPTOP_EAPD] = "laptop-eapd", @@ -9040,8 +8678,6 @@ static const char *alc883_models[ALC883_MODEL_LAST] = { [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530", [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel", [ALC1200_ASUS_P5Q] = "asus-p5q", - [ALC889A_MB31] = "mb31", - [ALC883_SONY_VAIO_TT] = "sony-vaio-tt", [ALC883_AUTO] = "auto", }; @@ -9057,20 +8693,14 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { ALC888_ACER_ASPIRE_4930G), SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G", ALC888_ACER_ASPIRE_4930G), - SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G", - ALC888_ACER_ASPIRE_8930G), - SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G", - ALC888_ACER_ASPIRE_8930G), SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC883_AUTO), SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC883_AUTO), SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G", ALC888_ACER_ASPIRE_4930G), SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G", - ALC888_ACER_ASPIRE_6530G), - /* default Acer -- disabled as it causes more problems. - * model=auto should work fine now - */ - /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */ + ALC888_ACER_ASPIRE_4930G), + /* default Acer */ + SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL), SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG), SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP), @@ -9106,7 +8736,6 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG), SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG), @@ -9114,7 +8743,6 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG), SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG), SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720), @@ -9140,7 +8768,6 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC), SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC883_3ST_6ch_INTEL), SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch), - SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT), {} }; @@ -9211,8 +8838,8 @@ static struct alc_config_preset alc883_presets[] = { .input_mux = &alc883_capture_source, }, [ALC883_TARGA_DIG] = { - .mixers = { alc883_targa_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc883_targa_verbs}, + .mixers = { alc883_tagra_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc883_tagra_verbs}, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, .dig_out_nid = ALC883_DIGOUT_NID, @@ -9220,12 +8847,12 @@ static struct alc_config_preset alc883_presets[] = { .channel_mode = alc883_3ST_6ch_modes, .need_dac_fix = 1, .input_mux = &alc883_capture_source, - .unsol_event = alc883_targa_unsol_event, - .init_hook = alc883_targa_init_hook, + .unsol_event = alc883_tagra_unsol_event, + .init_hook = alc883_tagra_automute, }, [ALC883_TARGA_2ch_DIG] = { - .mixers = { alc883_targa_2ch_mixer}, - .init_verbs = { alc883_init_verbs, alc883_targa_verbs}, + .mixers = { alc883_tagra_2ch_mixer}, + .init_verbs = { alc883_init_verbs, alc883_tagra_verbs}, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, .adc_nids = alc883_adc_nids_alt, @@ -9234,26 +8861,8 @@ static struct alc_config_preset alc883_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, - .unsol_event = alc883_targa_unsol_event, - .init_hook = alc883_targa_init_hook, - }, - [ALC883_TARGA_8ch_DIG] = { - .mixers = { alc883_base_mixer, alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs, - alc883_targa_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), - .adc_nids = alc883_adc_nids_rev, - .capsrc_nids = alc883_capsrc_nids_rev, - .dig_out_nid = ALC883_DIGOUT_NID, - .dig_in_nid = ALC883_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes), - .channel_mode = alc883_4ST_8ch_modes, - .need_dac_fix = 1, - .input_mux = &alc883_capture_source, - .unsol_event = alc883_targa_unsol_event, - .init_hook = alc883_targa_init_hook, + .unsol_event = alc883_tagra_unsol_event, + .init_hook = alc883_tagra_automute, }, [ALC883_ACER] = { .mixers = { alc883_base_mixer }, @@ -9278,8 +8887,8 @@ static struct alc_config_preset alc883_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc883_acer_aspire_init_hook, + .unsol_event = alc883_acer_aspire_unsol_event, + .init_hook = alc883_acer_aspire_automute, }, [ALC888_ACER_ASPIRE_4930G] = { .mixers = { alc888_base_mixer, @@ -9298,47 +8907,8 @@ static struct alc_config_preset alc883_presets[] = { .num_mux_defs = ARRAY_SIZE(alc888_2_capture_sources), .input_mux = alc888_2_capture_sources, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc888_acer_aspire_4930g_init_hook, - }, - [ALC888_ACER_ASPIRE_6530G] = { - .mixers = { alc888_acer_aspire_6530_mixer }, - .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, - alc888_acer_aspire_6530g_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), - .adc_nids = alc883_adc_nids_rev, - .capsrc_nids = alc883_capsrc_nids_rev, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .num_mux_defs = - ARRAY_SIZE(alc888_2_capture_sources), - .input_mux = alc888_acer_aspire_6530_sources, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc888_acer_aspire_4930g_init_hook, - }, - [ALC888_ACER_ASPIRE_8930G] = { - .mixers = { alc888_base_mixer, - alc883_chmode_mixer }, - .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, - alc889_acer_aspire_8930g_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc889_adc_nids), - .adc_nids = alc889_adc_nids, - .capsrc_nids = alc889_capsrc_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), - .channel_mode = alc883_3ST_6ch_modes, - .need_dac_fix = 1, - .const_channel_count = 6, - .num_mux_defs = - ARRAY_SIZE(alc889_capture_sources), - .input_mux = alc889_capture_sources, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc889_acer_aspire_8930g_init_hook, + .unsol_event = alc888_acer_aspire_4930g_unsol_event, + .init_hook = alc888_acer_aspire_4930g_automute, }, [ALC883_MEDION] = { .mixers = { alc883_fivestack_mixer, @@ -9362,8 +8932,8 @@ static struct alc_config_preset alc883_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc883_medion_md2_init_hook, + .unsol_event = alc883_medion_md2_unsol_event, + .init_hook = alc883_medion_md2_automute, }, [ALC883_LAPTOP_EAPD] = { .mixers = { alc883_base_mixer }, @@ -9384,7 +8954,7 @@ static struct alc_config_preset alc883_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, .unsol_event = alc883_clevo_m720_unsol_event, - .init_hook = alc883_clevo_m720_init_hook, + .init_hook = alc883_clevo_m720_automute, }, [ALC883_LENOVO_101E_2ch] = { .mixers = { alc883_lenovo_101e_2ch_mixer}, @@ -9408,8 +8978,8 @@ static struct alc_config_preset alc883_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .need_dac_fix = 1, .input_mux = &alc883_lenovo_nb0763_capture_source, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc883_medion_md2_init_hook, + .unsol_event = alc883_medion_md2_unsol_event, + .init_hook = alc883_medion_md2_automute, }, [ALC888_LENOVO_MS7195_DIG] = { .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, @@ -9425,7 +8995,7 @@ static struct alc_config_preset alc883_presets[] = { .init_hook = alc888_lenovo_ms7195_front_automute, }, [ALC883_HAIER_W66] = { - .mixers = { alc883_targa_2ch_mixer}, + .mixers = { alc883_tagra_2ch_mixer}, .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs}, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, @@ -9433,8 +9003,8 @@ static struct alc_config_preset alc883_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc883_haier_w66_init_hook, + .unsol_event = alc883_haier_w66_unsol_event, + .init_hook = alc883_haier_w66_automute, }, [ALC888_3ST_HP] = { .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, @@ -9445,8 +9015,8 @@ static struct alc_config_preset alc883_presets[] = { .channel_mode = alc888_3st_hp_modes, .need_dac_fix = 1, .input_mux = &alc883_capture_source, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc888_3st_hp_init_hook, + .unsol_event = alc888_3st_hp_unsol_event, + .init_hook = alc888_3st_hp_front_automute, }, [ALC888_6ST_DELL] = { .mixers = { alc883_base_mixer, alc883_chmode_mixer }, @@ -9458,8 +9028,8 @@ static struct alc_config_preset alc883_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), .channel_mode = alc883_sixstack_modes, .input_mux = &alc883_capture_source, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc888_6st_dell_init_hook, + .unsol_event = alc888_6st_dell_unsol_event, + .init_hook = alc888_6st_dell_front_automute, }, [ALC883_MITAC] = { .mixers = { alc883_mitac_mixer }, @@ -9469,8 +9039,8 @@ static struct alc_config_preset alc883_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc883_mitac_init_hook, + .unsol_event = alc883_mitac_unsol_event, + .init_hook = alc883_mitac_automute, }, [ALC883_FUJITSU_PI2515] = { .mixers = { alc883_2ch_fujitsu_pi2515_mixer }, @@ -9482,8 +9052,8 @@ static struct alc_config_preset alc883_presets[] = { .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_fujitsu_pi2515_capture_source, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc883_2ch_fujitsu_pi2515_init_hook, + .unsol_event = alc883_2ch_fujitsu_pi2515_unsol_event, + .init_hook = alc883_2ch_fujitsu_pi2515_automute, }, [ALC888_FUJITSU_XA3530] = { .mixers = { alc888_base_mixer, alc883_chmode_mixer }, @@ -9500,8 +9070,8 @@ static struct alc_config_preset alc883_presets[] = { .num_mux_defs = ARRAY_SIZE(alc888_2_capture_sources), .input_mux = alc888_2_capture_sources, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc888_fujitsu_xa3530_init_hook, + .unsol_event = alc888_fujitsu_xa3530_unsol_event, + .init_hook = alc888_fujitsu_xa3530_automute, }, [ALC888_LENOVO_SKY] = { .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer }, @@ -9513,8 +9083,8 @@ static struct alc_config_preset alc883_presets[] = { .channel_mode = alc883_sixstack_modes, .need_dac_fix = 1, .input_mux = &alc883_lenovo_sky_capture_source, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc888_lenovo_sky_init_hook, + .unsol_event = alc883_lenovo_sky_unsol_event, + .init_hook = alc888_lenovo_sky_front_automute, }, [ALC888_ASUS_M90V] = { .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, @@ -9542,7 +9112,7 @@ static struct alc_config_preset alc883_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .need_dac_fix = 1, .input_mux = &alc883_asus_eee1601_capture_source, - .unsol_event = alc_sku_unsol_event, + .unsol_event = alc883_eee1601_unsol_event, .init_hook = alc883_eee1601_inithook, }, [ALC1200_ASUS_P5Q] = { @@ -9557,32 +9127,6 @@ static struct alc_config_preset alc883_presets[] = { .channel_mode = alc883_sixstack_modes, .input_mux = &alc883_capture_source, }, - [ALC889A_MB31] = { - .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer}, - .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs, - alc880_gpio1_init_verbs }, - .adc_nids = alc883_adc_nids, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), - .dac_nids = alc883_dac_nids, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .channel_mode = alc889A_mb31_6ch_modes, - .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes), - .input_mux = &alc889A_mb31_capture_source, - .dig_out_nid = ALC883_DIGOUT_NID, - .unsol_event = alc889A_mb31_unsol_event, - .init_hook = alc889A_mb31_automute, - }, - [ALC883_SONY_VAIO_TT] = { - .mixers = { alc883_vaiott_mixer }, - .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs }, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .dac_nids = alc883_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_capture_source, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc883_vaiott_init_hook, - }, }; @@ -9611,6 +9155,7 @@ static void alc883_auto_init_multi_out(struct hda_codec *codec) struct alc_spec *spec = codec->spec; int i; + alc_subsystem_id(codec, 0x15, 0x1b, 0x14); for (i = 0; i <= HDA_SIDE; i++) { hda_nid_t nid = spec->autocfg.line_out_pins[i]; int pin_type = get_pin_type(spec->autocfg.line_out_type); @@ -9728,18 +9273,10 @@ static int patch_alc883(struct hda_codec *codec) board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST, alc883_models, alc883_cfg_tbl); - if (board_config < 0 || board_config >= ALC883_MODEL_LAST) { - /* Pick up systems that don't supply PCI SSID */ - switch (codec->subsystem_id) { - case 0x106b3600: /* Macbook 3.1 */ - board_config = ALC889A_MB31; - break; - default: - printk(KERN_INFO - "hda_codec: Unknown model for %s, trying " - "auto-probe from BIOS...\n", codec->chip_name); - board_config = ALC883_AUTO; - } + if (board_config < 0) { + printk(KERN_INFO "hda_codec: Unknown model for ALC883, " + "trying auto-probe from BIOS...\n"); + board_config = ALC883_AUTO; } if (board_config == ALC883_AUTO) { @@ -9767,29 +9304,43 @@ static int patch_alc883(struct hda_codec *codec) switch (codec->vendor_id) { case 0x10ec0888: + if (codec->revision_id == 0x100101) { + spec->stream_name_analog = "ALC1200 Analog"; + spec->stream_name_digital = "ALC1200 Digital"; + } else { + spec->stream_name_analog = "ALC888 Analog"; + spec->stream_name_digital = "ALC888 Digital"; + } if (!spec->num_adc_nids) { spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); spec->adc_nids = alc883_adc_nids; } if (!spec->capsrc_nids) spec->capsrc_nids = alc883_capsrc_nids; - spec->init_amp = ALC_INIT_DEFAULT; /* always initialize */ + spec->capture_style = CAPT_MIX; /* matrix-style capture */ break; case 0x10ec0889: + spec->stream_name_analog = "ALC889 Analog"; + spec->stream_name_digital = "ALC889 Digital"; if (!spec->num_adc_nids) { spec->num_adc_nids = ARRAY_SIZE(alc889_adc_nids); spec->adc_nids = alc889_adc_nids; } if (!spec->capsrc_nids) spec->capsrc_nids = alc889_capsrc_nids; + spec->capture_style = CAPT_1MUX_MIX; /* 1mux/Nmix-style + capture */ break; default: + spec->stream_name_analog = "ALC883 Analog"; + spec->stream_name_digital = "ALC883 Digital"; if (!spec->num_adc_nids) { spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); spec->adc_nids = alc883_adc_nids; } if (!spec->capsrc_nids) spec->capsrc_nids = alc883_capsrc_nids; + spec->capture_style = CAPT_MIX; /* matrix-style capture */ break; } @@ -9862,6 +9413,24 @@ static struct snd_kcontrol_new alc262_base_mixer[] = { { } /* end */ }; +static struct snd_kcontrol_new alc262_hippo1_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), + /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/ + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + { } /* end */ +}; + /* update HP, line and mono-out pins according to the master switch */ static void alc262_hp_master_update(struct hda_codec *codec) { @@ -9917,7 +9486,14 @@ static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec, alc262_hp_wildwest_automute(codec); } -#define alc262_hp_master_sw_get alc260_hp_master_sw_get +static int alc262_hp_master_sw_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct alc_spec *spec = codec->spec; + *ucontrol->value.integer.value = spec->master_sw; + return 0; +} static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -9933,17 +9509,14 @@ static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol, return 1; } -#define ALC262_HP_MASTER_SWITCH \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "Master Playback Switch", \ - .info = snd_ctl_boolean_mono_info, \ - .get = alc262_hp_master_sw_get, \ - .put = alc262_hp_master_sw_put, \ - } - static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { - ALC262_HP_MASTER_SWITCH, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = snd_ctl_boolean_mono_info, + .get = alc262_hp_master_sw_get, + .put = alc262_hp_master_sw_put, + }, HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), @@ -9967,7 +9540,13 @@ static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { }; static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = { - ALC262_HP_MASTER_SWITCH, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = snd_ctl_boolean_mono_info, + .get = alc262_hp_master_sw_get, + .put = alc262_hp_master_sw_put, + }, HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -9994,13 +9573,32 @@ static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = { }; /* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc262_hp_t5735_init_hook(struct hda_codec *codec) +static void alc262_hp_t5735_automute(struct hda_codec *codec, int force) { struct alc_spec *spec = codec->spec; - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x0c; /* HACK: not actually a pin */ - alc_automute_amp(codec); + if (force || !spec->sense_updated) { + unsigned int present; + present = snd_hda_codec_read(codec, 0x15, 0, + AC_VERB_GET_PIN_SENSE, 0); + spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0; + spec->sense_updated = 1; + } + snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, HDA_AMP_MUTE, + spec->jack_present ? HDA_AMP_MUTE : 0); +} + +static void alc262_hp_t5735_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) != ALC880_HP_EVENT) + return; + alc262_hp_t5735_automute(codec, 1); +} + +static void alc262_hp_t5735_init_hook(struct hda_codec *codec) +{ + alc262_hp_t5735_automute(codec, 1); } static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = { @@ -10053,132 +9651,46 @@ static struct hda_input_mux alc262_hp_rp5700_capture_source = { }, }; -/* bind hp and internal speaker mute (with plug check) as master switch */ -static void alc262_hippo_master_update(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t hp_nid = spec->autocfg.hp_pins[0]; - hda_nid_t line_nid = spec->autocfg.line_out_pins[0]; - hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0]; - unsigned int mute; - - /* HP */ - mute = spec->master_sw ? 0 : HDA_AMP_MUTE; - snd_hda_codec_amp_stereo(codec, hp_nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); - /* mute internal speaker per jack sense */ - if (spec->jack_present) - mute = HDA_AMP_MUTE; - if (line_nid) - snd_hda_codec_amp_stereo(codec, line_nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); - if (speaker_nid && speaker_nid != line_nid) - snd_hda_codec_amp_stereo(codec, speaker_nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); -} - -#define alc262_hippo_master_sw_get alc262_hp_master_sw_get - -static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +/* bind hp and internal speaker mute (with plug check) */ +static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - int val = !!*ucontrol->value.integer.value; - - if (val == spec->master_sw) - return 0; - spec->master_sw = val; - alc262_hippo_master_update(codec); - return 1; -} + long *valp = ucontrol->value.integer.value; + int change; -#define ALC262_HIPPO_MASTER_SWITCH \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "Master Playback Switch", \ - .info = snd_ctl_boolean_mono_info, \ - .get = alc262_hippo_master_sw_get, \ - .put = alc262_hippo_master_sw_put, \ + /* change hp mute */ + change = snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, + HDA_AMP_MUTE, + valp[0] ? 0 : HDA_AMP_MUTE); + change |= snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, + HDA_AMP_MUTE, + valp[1] ? 0 : HDA_AMP_MUTE); + if (change) { + /* change speaker according to HP jack state */ + struct alc_spec *spec = codec->spec; + unsigned int mute; + if (spec->jack_present) + mute = HDA_AMP_MUTE; + else + mute = snd_hda_codec_amp_read(codec, 0x15, 0, + HDA_OUTPUT, 0); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); } - -static struct snd_kcontrol_new alc262_hippo_mixer[] = { - ALC262_HIPPO_MASTER_SWITCH, - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static struct snd_kcontrol_new alc262_hippo1_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - ALC262_HIPPO_MASTER_SWITCH, - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), - { } /* end */ -}; - -/* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc262_hippo_automute(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t hp_nid = spec->autocfg.hp_pins[0]; - unsigned int present; - - /* need to execute and sync at first */ - snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0); - present = snd_hda_codec_read(codec, hp_nid, 0, - AC_VERB_GET_PIN_SENSE, 0); - spec->jack_present = (present & 0x80000000) != 0; - alc262_hippo_master_update(codec); -} - -static void alc262_hippo_unsol_event(struct hda_codec *codec, unsigned int res) -{ - if ((res >> 26) != ALC880_HP_EVENT) - return; - alc262_hippo_automute(codec); -} - -static void alc262_hippo_init_hook(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - alc262_hippo_automute(codec); -} - -static void alc262_hippo1_init_hook(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - alc262_hippo_automute(codec); + return change; } - static struct snd_kcontrol_new alc262_sony_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - ALC262_HIPPO_MASTER_SWITCH, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = alc262_sony_master_sw_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), + }, HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), @@ -10187,8 +9699,8 @@ static struct snd_kcontrol_new alc262_sony_mixer[] = { }; static struct snd_kcontrol_new alc262_benq_t31_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - ALC262_HIPPO_MASTER_SWITCH, + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), @@ -10229,15 +9741,34 @@ static struct hda_verb alc262_tyan_verbs[] = { }; /* unsolicited event for HP jack sensing */ -static void alc262_tyan_init_hook(struct hda_codec *codec) +static void alc262_tyan_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int mute; + unsigned int present; - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x15; - alc_automute_amp(codec); + snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0); + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0); + present = (present & 0x80000000) != 0; + if (present) { + /* mute line output on ATX panel */ + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + } else { + /* unmute line output if necessary */ + mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + } } +static void alc262_tyan_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) != ALC880_HP_EVENT) + return; + alc262_tyan_automute(codec); +} #define alc262_capture_mixer alc882_capture_mixer #define alc262_capture_alt_mixer alc882_capture_alt_mixer @@ -10392,25 +9923,99 @@ static void alc262_dmic_automute(struct hda_codec *codec) AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x09); } +/* toggle speaker-output according to the hp-jack state */ +static void alc262_toshiba_s06_speaker_automute(struct hda_codec *codec) +{ + unsigned int present; + unsigned char bits; + + present = snd_hda_codec_read(codec, 0x15, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + bits = present ? 0 : PIN_OUT; + snd_hda_codec_write(codec, 0x14, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, bits); +} + + /* unsolicited event for HP jack sensing */ static void alc262_toshiba_s06_unsol_event(struct hda_codec *codec, unsigned int res) { + if ((res >> 26) == ALC880_HP_EVENT) + alc262_toshiba_s06_speaker_automute(codec); if ((res >> 26) == ALC880_MIC_EVENT) alc262_dmic_automute(codec); - else - alc_sku_unsol_event(codec, res); + +} + +static void alc262_toshiba_s06_init_hook(struct hda_codec *codec) +{ + alc262_toshiba_s06_speaker_automute(codec); + alc262_dmic_automute(codec); +} + +/* mute/unmute internal speaker according to the hp jack and mute state */ +static void alc262_hippo_automute(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + unsigned int mute; + unsigned int present; + + /* need to execute and sync at first */ + snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0); + present = snd_hda_codec_read(codec, 0x15, 0, + AC_VERB_GET_PIN_SENSE, 0); + spec->jack_present = (present & 0x80000000) != 0; + if (spec->jack_present) { + /* mute internal speaker */ + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + } else { + /* unmute internal speaker if necessary */ + mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + } +} + +/* unsolicited event for HP jack sensing */ +static void alc262_hippo_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) != ALC880_HP_EVENT) + return; + alc262_hippo_automute(codec); +} + +static void alc262_hippo1_automute(struct hda_codec *codec) +{ + unsigned int mute; + unsigned int present; + + snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0); + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0); + present = (present & 0x80000000) != 0; + if (present) { + /* mute internal speaker */ + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + } else { + /* unmute internal speaker if necessary */ + mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + } } -static void alc262_toshiba_s06_init_hook(struct hda_codec *codec) +/* unsolicited event for HP jack sensing */ +static void alc262_hippo1_unsol_event(struct hda_codec *codec, + unsigned int res) { - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - alc_automute_pin(codec); - alc262_dmic_automute(codec); + if ((res >> 26) != ALC880_HP_EVENT) + return; + alc262_hippo1_automute(codec); } /* @@ -10680,7 +10285,14 @@ static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = { static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = { HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol), - ALC262_HIPPO_MASTER_SWITCH, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = alc262_sony_master_sw_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), + }, HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), @@ -10901,27 +10513,9 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, return 0; } -static int alc262_auto_create_analog_input_ctls(struct alc_spec *spec, - const struct auto_pin_cfg *cfg) -{ - int err; - - err = alc880_auto_create_analog_input_ctls(spec, cfg); - if (err < 0) - return err; - /* digital-mic input pin is excluded in alc880_auto_create..() - * because it's under 0x18 - */ - if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 || - cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) { - struct hda_input_mux *imux = &spec->private_imux[0]; - imux->items[imux->num_items].label = "Int Mic"; - imux->items[imux->num_items].index = 0x09; - imux->num_items++; - } - return 0; -} - +/* identical with ALC880 */ +#define alc262_auto_create_analog_input_ctls \ + alc880_auto_create_analog_input_ctls /* * generic initialization of ADC, input mixers and output mixers @@ -11045,46 +10639,31 @@ static struct hda_verb alc262_HP_BPC_init_verbs[] = { {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */ - /* Input mixer1: only unmute Mic */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /* Input mixer2 */ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /* Input mixer3 */ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, @@ -11209,7 +10788,7 @@ static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = { #define alc262_loopbacks alc880_loopbacks #endif -/* pcm configuration: identical with ALC880 */ +/* pcm configuration: identiacal with ALC880 */ #define alc262_pcm_analog_playback alc880_pcm_analog_playback #define alc262_pcm_analog_capture alc880_pcm_analog_capture #define alc262_pcm_digital_playback alc880_pcm_digital_playback @@ -11264,8 +10843,6 @@ static int alc262_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; - alc_ssid_check(codec, 0x15, 0x14, 0x1b); - return 1; } @@ -11338,7 +10915,6 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = { SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO), SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */ - SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06), SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO", ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1", @@ -11369,7 +10945,7 @@ static struct alc_config_preset alc262_presets[] = { .input_mux = &alc262_capture_source, }, [ALC262_HIPPO] = { - .mixers = { alc262_hippo_mixer }, + .mixers = { alc262_base_mixer }, .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs}, .num_dacs = ARRAY_SIZE(alc262_dac_nids), .dac_nids = alc262_dac_nids, @@ -11379,7 +10955,7 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, - .init_hook = alc262_hippo_init_hook, + .init_hook = alc262_hippo_automute, }, [ALC262_HIPPO_1] = { .mixers = { alc262_hippo1_mixer }, @@ -11391,8 +10967,8 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, - .unsol_event = alc262_hippo_unsol_event, - .init_hook = alc262_hippo1_init_hook, + .unsol_event = alc262_hippo1_unsol_event, + .init_hook = alc262_hippo1_automute, }, [ALC262_FUJITSU] = { .mixers = { alc262_fujitsu_mixer }, @@ -11454,7 +11030,7 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, - .unsol_event = alc_automute_amp_unsol_event, + .unsol_event = alc262_hp_t5735_unsol_event, .init_hook = alc262_hp_t5735_init_hook, }, [ALC262_HP_RP5700] = { @@ -11486,7 +11062,7 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, - .init_hook = alc262_hippo_init_hook, + .init_hook = alc262_hippo_automute, }, [ALC262_BENQ_T31] = { .mixers = { alc262_benq_t31_mixer }, @@ -11498,7 +11074,7 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, - .init_hook = alc262_hippo_init_hook, + .init_hook = alc262_hippo_automute, }, [ALC262_ULTRA] = { .mixers = { alc262_ultra_mixer }, @@ -11546,7 +11122,6 @@ static struct alc_config_preset alc262_presets[] = { .capsrc_nids = alc262_dmic_capsrc_nids, .dac_nids = alc262_dac_nids, .adc_nids = alc262_dmic_adc_nids, /* ADC0 */ - .num_adc_nids = 1, /* single ADC */ .dig_out_nid = ALC262_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, @@ -11564,7 +11139,7 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, - .init_hook = alc262_hippo_init_hook, + .init_hook = alc262_hippo_automute, }, [ALC262_TYAN] = { .mixers = { alc262_tyan_mixer }, @@ -11576,8 +11151,8 @@ static struct alc_config_preset alc262_presets[] = { .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc262_tyan_init_hook, + .unsol_event = alc262_tyan_unsol_event, + .init_hook = alc262_tyan_automute, }, }; @@ -11612,8 +11187,8 @@ static int patch_alc262(struct hda_codec *codec) alc262_cfg_tbl); if (board_config < 0) { - printk(KERN_INFO "hda_codec: Unknown model for %s, " - "trying auto-probe from BIOS...\n", codec->chip_name); + printk(KERN_INFO "hda_codec: Unknown model for ALC262, " + "trying auto-probe from BIOS...\n"); board_config = ALC262_AUTO; } @@ -11642,42 +11217,29 @@ static int patch_alc262(struct hda_codec *codec) if (board_config != ALC262_AUTO) setup_preset(spec, &alc262_presets[board_config]); + spec->stream_name_analog = "ALC262 Analog"; spec->stream_analog_playback = &alc262_pcm_analog_playback; spec->stream_analog_capture = &alc262_pcm_analog_capture; + spec->stream_name_digital = "ALC262 Digital"; spec->stream_digital_playback = &alc262_pcm_digital_playback; spec->stream_digital_capture = &alc262_pcm_digital_capture; + spec->capture_style = CAPT_MIX; if (!spec->adc_nids && spec->input_mux) { - int i; - /* check whether the digital-mic has to be supported */ - for (i = 0; i < spec->input_mux->num_items; i++) { - if (spec->input_mux->items[i].index >= 9) - break; - } - if (i < spec->input_mux->num_items) { - /* use only ADC0 */ - spec->adc_nids = alc262_dmic_adc_nids; - spec->num_adc_nids = 1; - spec->capsrc_nids = alc262_dmic_capsrc_nids; + /* check whether NID 0x07 is valid */ + unsigned int wcap = get_wcaps(codec, 0x07); + + /* get type */ + wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + if (wcap != AC_WID_AUD_IN) { + spec->adc_nids = alc262_adc_nids_alt; + spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt); + spec->capsrc_nids = alc262_capsrc_nids_alt; } else { - /* all analog inputs */ - /* check whether NID 0x07 is valid */ - unsigned int wcap = get_wcaps(codec, 0x07); - - /* get type */ - wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; - if (wcap != AC_WID_AUD_IN) { - spec->adc_nids = alc262_adc_nids_alt; - spec->num_adc_nids = - ARRAY_SIZE(alc262_adc_nids_alt); - spec->capsrc_nids = alc262_capsrc_nids_alt; - } else { - spec->adc_nids = alc262_adc_nids; - spec->num_adc_nids = - ARRAY_SIZE(alc262_adc_nids); - spec->capsrc_nids = alc262_capsrc_nids; - } + spec->adc_nids = alc262_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids); + spec->capsrc_nids = alc262_capsrc_nids; } } if (!spec->cap_mixer && !spec->no_analog) @@ -11734,17 +11296,6 @@ static struct snd_kcontrol_new alc268_base_mixer[] = { { } }; -static struct snd_kcontrol_new alc268_toshiba_mixer[] = { - /* output mixer control */ - HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), - ALC262_HIPPO_MASTER_SWITCH, - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), - HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT), - { } -}; - /* bind Beep switches of both NID 0x0f and 0x10 */ static struct hda_bind_ctls alc268_bind_beep_sw = { .ops = &snd_hda_bind_sw, @@ -11768,6 +11319,8 @@ static struct hda_verb alc268_eapd_verbs[] = { }; /* Toshiba specific */ +#define alc268_toshiba_automute alc262_hippo_automute + static struct hda_verb alc268_toshiba_verbs[] = { {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, { } /* end */ @@ -11903,8 +11456,13 @@ static struct hda_verb alc268_acer_verbs[] = { }; /* unsolicited event for HP jack sensing */ -#define alc268_toshiba_unsol_event alc262_hippo_unsol_event -#define alc268_toshiba_init_hook alc262_hippo_init_hook +static void alc268_toshiba_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) != ALC880_HP_EVENT) + return; + alc268_toshiba_automute(codec); +} static void alc268_acer_unsol_event(struct hda_codec *codec, unsigned int res) @@ -11979,15 +11537,30 @@ static struct hda_verb alc268_dell_verbs[] = { }; /* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc268_dell_init_hook(struct hda_codec *codec) +static void alc268_dell_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present; + unsigned int mute; + + present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0); + if (present & 0x80000000) + mute = HDA_AMP_MUTE; + else + mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); +} - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - alc_automute_pin(codec); +static void alc268_dell_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) != ALC880_HP_EVENT) + return; + alc268_dell_automute(codec); } +#define alc268_dell_init_hook alc268_dell_automute + static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = { HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), @@ -12006,6 +11579,16 @@ static struct hda_verb alc267_quanta_il1_verbs[] = { { } }; +static void alc267_quanta_il1_hp_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0) + & AC_PINSENSE_PRESENCE; + snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + present ? 0 : PIN_OUT); +} + static void alc267_quanta_il1_mic_automute(struct hda_codec *codec) { unsigned int present; @@ -12017,13 +11600,9 @@ static void alc267_quanta_il1_mic_automute(struct hda_codec *codec) present ? 0x00 : 0x01); } -static void alc267_quanta_il1_init_hook(struct hda_codec *codec) +static void alc267_quanta_il1_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - alc_automute_pin(codec); + alc267_quanta_il1_hp_automute(codec); alc267_quanta_il1_mic_automute(codec); } @@ -12031,12 +11610,12 @@ static void alc267_quanta_il1_unsol_event(struct hda_codec *codec, unsigned int res) { switch (res >> 26) { + case ALC880_HP_EVENT: + alc267_quanta_il1_hp_automute(codec); + break; case ALC880_MIC_EVENT: alc267_quanta_il1_mic_automute(codec); break; - default: - alc_sku_unsol_event(codec, res); - break; } } @@ -12381,7 +11960,7 @@ static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec) AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2); } -/* pcm configuration: identical with ALC880 */ +/* pcm configuration: identiacal with ALC880 */ #define alc268_pcm_analog_playback alc880_pcm_analog_playback #define alc268_pcm_analog_capture alc880_pcm_analog_capture #define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture @@ -12484,16 +12063,16 @@ static struct snd_pci_quirk alc268_cfg_tbl[] = { ALC268_ACER_ASPIRE_ONE), SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL), SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron Mini9", ALC268_DELL), - SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series", - ALC268_TOSHIBA), + SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA), + SND_PCI_QUIRK(0x103c, 0x30f1, "HP TX25xx series", ALC268_TOSHIBA), SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST), - SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO), - SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05", - ALC268_TOSHIBA), + SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA), + SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA), + SND_PCI_QUIRK(0x1179, 0xff64, "TOSHIBA L305", ALC268_TOSHIBA), SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA), SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER), SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1), - SND_PCI_QUIRK(0x1854, 0x1775, "LG R510", ALC268_DELL), + SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO), {} }; @@ -12511,7 +12090,7 @@ static struct alc_config_preset alc268_presets[] = { .channel_mode = alc268_modes, .input_mux = &alc268_capture_source, .unsol_event = alc267_quanta_il1_unsol_event, - .init_hook = alc267_quanta_il1_init_hook, + .init_hook = alc267_quanta_il1_automute, }, [ALC268_3ST] = { .mixers = { alc268_base_mixer, alc268_capture_alt_mixer, @@ -12529,7 +12108,7 @@ static struct alc_config_preset alc268_presets[] = { .input_mux = &alc268_capture_source, }, [ALC268_TOSHIBA] = { - .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer, + .mixers = { alc268_base_mixer, alc268_capture_alt_mixer, alc268_beep_mixer }, .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, alc268_toshiba_verbs }, @@ -12543,7 +12122,7 @@ static struct alc_config_preset alc268_presets[] = { .channel_mode = alc268_modes, .input_mux = &alc268_capture_source, .unsol_event = alc268_toshiba_unsol_event, - .init_hook = alc268_toshiba_init_hook, + .init_hook = alc268_toshiba_automute, }, [ALC268_ACER] = { .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer, @@ -12606,7 +12185,7 @@ static struct alc_config_preset alc268_presets[] = { .hp_nid = 0x02, .num_channel_mode = ARRAY_SIZE(alc268_modes), .channel_mode = alc268_modes, - .unsol_event = alc_sku_unsol_event, + .unsol_event = alc268_dell_unsol_event, .init_hook = alc268_dell_init_hook, .input_mux = &alc268_capture_source, }, @@ -12626,7 +12205,7 @@ static struct alc_config_preset alc268_presets[] = { .channel_mode = alc268_modes, .input_mux = &alc268_capture_source, .unsol_event = alc268_toshiba_unsol_event, - .init_hook = alc268_toshiba_init_hook + .init_hook = alc268_toshiba_automute }, #ifdef CONFIG_SND_DEBUG [ALC268_TEST] = { @@ -12664,8 +12243,8 @@ static int patch_alc268(struct hda_codec *codec) alc268_cfg_tbl); if (board_config < 0 || board_config >= ALC268_MODEL_LAST) { - printk(KERN_INFO "hda_codec: Unknown model for %s, " - "trying auto-probe from BIOS...\n", codec->chip_name); + printk(KERN_INFO "hda_codec: Unknown model for ALC268, " + "trying auto-probe from BIOS...\n"); board_config = ALC268_AUTO; } @@ -12686,6 +12265,14 @@ static int patch_alc268(struct hda_codec *codec) if (board_config != ALC268_AUTO) setup_preset(spec, &alc268_presets[board_config]); + if (codec->vendor_id == 0x10ec0267) { + spec->stream_name_analog = "ALC267 Analog"; + spec->stream_name_digital = "ALC267 Digital"; + } else { + spec->stream_name_analog = "ALC268 Analog"; + spec->stream_name_digital = "ALC268 Digital"; + } + spec->stream_analog_playback = &alc268_pcm_analog_playback; spec->stream_analog_capture = &alc268_pcm_analog_capture; spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture; @@ -13267,14 +12854,32 @@ static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec, return 0; } -#define alc269_auto_create_analog_input_ctls \ - alc262_auto_create_analog_input_ctls +static int alc269_auto_create_analog_input_ctls(struct alc_spec *spec, + const struct auto_pin_cfg *cfg) +{ + int err; + + err = alc880_auto_create_analog_input_ctls(spec, cfg); + if (err < 0) + return err; + /* digital-mic input pin is excluded in alc880_auto_create..() + * because it's under 0x18 + */ + if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 || + cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) { + struct hda_input_mux *imux = &spec->private_imux[0]; + imux->items[imux->num_items].label = "Int Mic"; + imux->items[imux->num_items].index = 0x05; + imux->num_items++; + } + return 0; +} #ifdef CONFIG_SND_HDA_POWER_SAVE #define alc269_loopbacks alc880_loopbacks #endif -/* pcm configuration: identical with ALC880 */ +/* pcm configuration: identiacal with ALC880 */ #define alc269_pcm_analog_playback alc880_pcm_analog_playback #define alc269_pcm_analog_capture alc880_pcm_analog_capture #define alc269_pcm_digital_playback alc880_pcm_digital_playback @@ -13494,8 +13099,8 @@ static int patch_alc269(struct hda_codec *codec) alc269_cfg_tbl); if (board_config < 0) { - printk(KERN_INFO "hda_codec: Unknown model for %s, " - "trying auto-probe from BIOS...\n", codec->chip_name); + printk(KERN_INFO "hda_codec: Unknown model for ALC269, " + "trying auto-probe from BIOS...\n"); board_config = ALC269_AUTO; } @@ -13522,6 +13127,7 @@ static int patch_alc269(struct hda_codec *codec) if (board_config != ALC269_AUTO) setup_preset(spec, &alc269_presets[board_config]); + spec->stream_name_analog = "ALC269 Analog"; if (codec->subsystem_id == 0x17aa3bf8) { /* Due to a hardware problem on Lenovo Ideadpad, we need to * fix the sample rate of analog I/O to 44.1kHz @@ -13532,6 +13138,7 @@ static int patch_alc269(struct hda_codec *codec) spec->stream_analog_playback = &alc269_pcm_analog_playback; spec->stream_analog_capture = &alc269_pcm_analog_capture; } + spec->stream_name_digital = "ALC269 Digital"; spec->stream_digital_playback = &alc269_pcm_digital_playback; spec->stream_digital_capture = &alc269_pcm_digital_capture; @@ -14136,7 +13743,7 @@ static void alc861_toshiba_unsol_event(struct hda_codec *codec, alc861_toshiba_automute(codec); } -/* pcm configuration: identical with ALC880 */ +/* pcm configuration: identiacal with ALC880 */ #define alc861_pcm_analog_playback alc880_pcm_analog_playback #define alc861_pcm_analog_capture alc880_pcm_analog_capture #define alc861_pcm_digital_playback alc880_pcm_digital_playback @@ -14320,6 +13927,7 @@ static void alc861_auto_init_multi_out(struct hda_codec *codec) struct alc_spec *spec = codec->spec; int i; + alc_subsystem_id(codec, 0x0e, 0x0f, 0x0b); for (i = 0; i < spec->autocfg.line_outs; i++) { hda_nid_t nid = spec->autocfg.line_out_pins[i]; int pin_type = get_pin_type(spec->autocfg.line_out_type); @@ -14402,8 +14010,6 @@ static int alc861_parse_auto_config(struct hda_codec *codec) spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids); set_capture_mixer(spec); - alc_ssid_check(codec, 0x0e, 0x0f, 0x0b); - return 1; } @@ -14593,8 +14199,8 @@ static int patch_alc861(struct hda_codec *codec) alc861_cfg_tbl); if (board_config < 0) { - printk(KERN_INFO "hda_codec: Unknown model for %s, " - "trying auto-probe from BIOS...\n", codec->chip_name); + printk(KERN_INFO "hda_codec: Unknown model for ALC861, " + "trying auto-probe from BIOS...\n"); board_config = ALC861_AUTO; } @@ -14621,9 +14227,11 @@ static int patch_alc861(struct hda_codec *codec) if (board_config != ALC861_AUTO) setup_preset(spec, &alc861_presets[board_config]); + spec->stream_name_analog = "ALC861 Analog"; spec->stream_analog_playback = &alc861_pcm_analog_playback; spec->stream_analog_capture = &alc861_pcm_analog_capture; + spec->stream_name_digital = "ALC861 Digital"; spec->stream_digital_playback = &alc861_pcm_digital_playback; spec->stream_digital_capture = &alc861_pcm_digital_capture; @@ -14659,7 +14267,7 @@ static hda_nid_t alc861vd_dac_nids[4] = { /* dac_nids for ALC660vd are in a different order - according to * Realtek's driver. - * This should probably result in a different mixer for 6stack models + * This should probably tesult in a different mixer for 6stack models * of ALC660vd codecs, but for now there is only 3stack mixer * - and it is the same as in 861vd. * adc_nids in ALC660vd are (is) the same as in 861vd @@ -15010,6 +14618,19 @@ static struct hda_verb alc861vd_lenovo_unsol_verbs[] = { {} }; +/* toggle speaker-output according to the hp-jack state */ +static void alc861vd_lenovo_hp_automute(struct hda_codec *codec) +{ + unsigned int present; + unsigned char bits; + + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); +} + static void alc861vd_lenovo_mic_automute(struct hda_codec *codec) { unsigned int present; @@ -15022,13 +14643,9 @@ static void alc861vd_lenovo_mic_automute(struct hda_codec *codec) HDA_AMP_MUTE, bits); } -static void alc861vd_lenovo_init_hook(struct hda_codec *codec) +static void alc861vd_lenovo_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x1b; - spec->autocfg.speaker_pins[0] = 0x14; - alc_automute_amp(codec); + alc861vd_lenovo_hp_automute(codec); alc861vd_lenovo_mic_automute(codec); } @@ -15036,12 +14653,12 @@ static void alc861vd_lenovo_unsol_event(struct hda_codec *codec, unsigned int res) { switch (res >> 26) { + case ALC880_HP_EVENT: + alc861vd_lenovo_hp_automute(codec); + break; case ALC880_MIC_EVENT: alc861vd_lenovo_mic_automute(codec); break; - default: - alc_automute_amp_unsol_event(codec, res); - break; } } @@ -15091,20 +14708,27 @@ static struct hda_verb alc861vd_dallas_verbs[] = { }; /* toggle speaker-output according to the hp-jack state */ -static void alc861vd_dallas_init_hook(struct hda_codec *codec) +static void alc861vd_dallas_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int present; + + present = snd_hda_codec_read(codec, 0x15, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); +} - spec->autocfg.hp_pins[0] = 0x15; - spec->autocfg.speaker_pins[0] = 0x14; - alc_automute_amp(codec); +static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc861vd_dallas_automute(codec); } #ifdef CONFIG_SND_HDA_POWER_SAVE #define alc861vd_loopbacks alc880_loopbacks #endif -/* pcm configuration: identical with ALC880 */ +/* pcm configuration: identiacal with ALC880 */ #define alc861vd_pcm_analog_playback alc880_pcm_analog_playback #define alc861vd_pcm_analog_capture alc880_pcm_analog_capture #define alc861vd_pcm_digital_playback alc880_pcm_digital_playback @@ -15211,7 +14835,7 @@ static struct alc_config_preset alc861vd_presets[] = { .channel_mode = alc861vd_3stack_2ch_modes, .input_mux = &alc861vd_capture_source, .unsol_event = alc861vd_lenovo_unsol_event, - .init_hook = alc861vd_lenovo_init_hook, + .init_hook = alc861vd_lenovo_automute, }, [ALC861VD_DALLAS] = { .mixers = { alc861vd_dallas_mixer }, @@ -15221,8 +14845,8 @@ static struct alc_config_preset alc861vd_presets[] = { .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), .channel_mode = alc861vd_3stack_2ch_modes, .input_mux = &alc861vd_dallas_capture_source, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc861vd_dallas_init_hook, + .unsol_event = alc861vd_dallas_unsol_event, + .init_hook = alc861vd_dallas_automute, }, [ALC861VD_HP] = { .mixers = { alc861vd_hp_mixer }, @@ -15233,8 +14857,8 @@ static struct alc_config_preset alc861vd_presets[] = { .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), .channel_mode = alc861vd_3stack_2ch_modes, .input_mux = &alc861vd_hp_capture_source, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc861vd_dallas_init_hook, + .unsol_event = alc861vd_dallas_unsol_event, + .init_hook = alc861vd_dallas_automute, }, [ALC660VD_ASUS_V1S] = { .mixers = { alc861vd_lenovo_mixer }, @@ -15249,7 +14873,7 @@ static struct alc_config_preset alc861vd_presets[] = { .channel_mode = alc861vd_3stack_2ch_modes, .input_mux = &alc861vd_capture_source, .unsol_event = alc861vd_lenovo_unsol_event, - .init_hook = alc861vd_lenovo_init_hook, + .init_hook = alc861vd_lenovo_automute, }, }; @@ -15267,6 +14891,7 @@ static void alc861vd_auto_init_multi_out(struct hda_codec *codec) struct alc_spec *spec = codec->spec; int i; + alc_subsystem_id(codec, 0x15, 0x1b, 0x14); for (i = 0; i <= HDA_SIDE; i++) { hda_nid_t nid = spec->autocfg.line_out_pins[i]; int pin_type = get_pin_type(spec->autocfg.line_out_type); @@ -15283,7 +14908,7 @@ static void alc861vd_auto_init_hp_out(struct hda_codec *codec) hda_nid_t pin; pin = spec->autocfg.hp_pins[0]; - if (pin) /* connect to front and use dac 0 */ + if (pin) /* connect to front and use dac 0 */ alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); pin = spec->autocfg.speaker_pins[0]; if (pin) @@ -15484,8 +15109,6 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; - alc_ssid_check(codec, 0x15, 0x1b, 0x14); - return 1; } @@ -15517,8 +15140,8 @@ static int patch_alc861vd(struct hda_codec *codec) alc861vd_cfg_tbl); if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) { - printk(KERN_INFO "hda_codec: Unknown model for %s, " - "trying auto-probe from BIOS...\n", codec->chip_name); + printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/" + "ALC861VD, trying auto-probe from BIOS...\n"); board_config = ALC861VD_AUTO; } @@ -15546,8 +15169,13 @@ static int patch_alc861vd(struct hda_codec *codec) setup_preset(spec, &alc861vd_presets[board_config]); if (codec->vendor_id == 0x10ec0660) { + spec->stream_name_analog = "ALC660-VD Analog"; + spec->stream_name_digital = "ALC660-VD Digital"; /* always turn on EAPD */ add_verb(spec, alc660vd_eapd_verbs); + } else { + spec->stream_name_analog = "ALC861VD Analog"; + spec->stream_name_digital = "ALC861VD Digital"; } spec->stream_analog_playback = &alc861vd_pcm_analog_playback; @@ -15559,6 +15187,7 @@ static int patch_alc861vd(struct hda_codec *codec) spec->adc_nids = alc861vd_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids); spec->capsrc_nids = alc861vd_capsrc_nids; + spec->capture_style = CAPT_MIX; set_capture_mixer(spec); set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); @@ -15660,38 +15289,6 @@ static struct hda_input_mux alc663_m51va_capture_source = { }, }; -#if 1 /* set to 0 for testing other input sources below */ -static struct hda_input_mux alc272_nc10_capture_source = { - .num_items = 2, - .items = { - { "Autoselect Mic", 0x0 }, - { "Internal Mic", 0x1 }, - }, -}; -#else -static struct hda_input_mux alc272_nc10_capture_source = { - .num_items = 16, - .items = { - { "Autoselect Mic", 0x0 }, - { "Internal Mic", 0x1 }, - { "In-0x02", 0x2 }, - { "In-0x03", 0x3 }, - { "In-0x04", 0x4 }, - { "In-0x05", 0x5 }, - { "In-0x06", 0x6 }, - { "In-0x07", 0x7 }, - { "In-0x08", 0x8 }, - { "In-0x09", 0x9 }, - { "In-0x0a", 0x0a }, - { "In-0x0b", 0x0b }, - { "In-0x0c", 0x0c }, - { "In-0x0d", 0x0d }, - { "In-0x0e", 0x0e }, - { "In-0x0f", 0x0f }, - }, -}; -#endif - /* * 2ch mode */ @@ -15831,8 +15428,10 @@ static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = { }; static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), - ALC262_HIPPO_MASTER_SWITCH, + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Line-Out Playback Switch", 0x1b, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), @@ -15845,11 +15444,15 @@ static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { }; static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = { - ALC262_HIPPO_MASTER_SWITCH, - HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Line-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT), HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), @@ -16357,25 +15960,51 @@ static void alc662_eeepc_mic_automute(struct hda_codec *codec) static void alc662_eeepc_unsol_event(struct hda_codec *codec, unsigned int res) { + if ((res >> 26) == ALC880_HP_EVENT) + alc262_hippo1_automute( codec ); + if ((res >> 26) == ALC880_MIC_EVENT) alc662_eeepc_mic_automute(codec); - else - alc262_hippo_unsol_event(codec, res); } static void alc662_eeepc_inithook(struct hda_codec *codec) { - alc262_hippo1_init_hook(codec); + alc262_hippo1_automute( codec ); alc662_eeepc_mic_automute(codec); } -static void alc662_eeepc_ep20_inithook(struct hda_codec *codec) +static void alc662_eeepc_ep20_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; + unsigned int mute; + unsigned int present; + + snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0); + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0); + present = (present & 0x80000000) != 0; + if (present) { + /* mute internal speaker */ + snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + } else { + /* unmute internal speaker if necessary */ + mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0); + snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + } +} + +/* unsolicited event for HP jack sensing */ +static void alc662_eeepc_ep20_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc662_eeepc_ep20_automute(codec); +} - spec->autocfg.hp_pins[0] = 0x14; - spec->autocfg.speaker_pins[0] = 0x1b; - alc262_hippo_master_update(codec); +static void alc662_eeepc_ep20_inithook(struct hda_codec *codec) +{ + alc662_eeepc_ep20_automute(codec); } static void alc663_m51va_speaker_automute(struct hda_codec *codec) @@ -16709,9 +16338,35 @@ static void alc663_g50v_inithook(struct hda_codec *codec) alc662_eeepc_mic_automute(codec); } +/* bind hp and internal speaker mute (with plug check) */ +static int alc662_ecs_master_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + long *valp = ucontrol->value.integer.value; + int change; + + change = snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, + HDA_AMP_MUTE, + valp[0] ? 0 : HDA_AMP_MUTE); + change |= snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, + HDA_AMP_MUTE, + valp[1] ? 0 : HDA_AMP_MUTE); + if (change) + alc262_hippo1_automute(codec); + return change; +} + static struct snd_kcontrol_new alc662_ecs_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), - ALC262_HIPPO_MASTER_SWITCH, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = alc662_ecs_master_sw_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), + }, HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT), @@ -16723,29 +16378,12 @@ static struct snd_kcontrol_new alc662_ecs_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc272_nc10_mixer[] = { - /* Master Playback automatically created from Speaker and Headphone */ - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT), - - HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT), - { } /* end */ -}; - #ifdef CONFIG_SND_HDA_POWER_SAVE #define alc662_loopbacks alc880_loopbacks #endif -/* pcm configuration: identical with ALC880 */ +/* pcm configuration: identiacal with ALC880 */ #define alc662_pcm_analog_playback alc880_pcm_analog_playback #define alc662_pcm_analog_capture alc880_pcm_analog_capture #define alc662_pcm_digital_playback alc880_pcm_digital_playback @@ -16773,9 +16411,6 @@ static const char *alc662_models[ALC662_MODEL_LAST] = { [ALC663_ASUS_MODE4] = "asus-mode4", [ALC663_ASUS_MODE5] = "asus-mode5", [ALC663_ASUS_MODE6] = "asus-mode6", - [ALC272_DELL] = "dell", - [ALC272_DELL_ZM1] = "dell-zm1", - [ALC272_SAMSUNG_NC10] = "samsung-nc10", [ALC662_AUTO] = "auto", }; @@ -16833,7 +16468,6 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = { SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS), SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K", ALC662_3ST_6ch_DIG), - SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10), SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L", ALC662_3ST_6ch_DIG), SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG), @@ -16924,7 +16558,7 @@ static struct alc_config_preset alc662_presets[] = { .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), .channel_mode = alc662_3ST_6ch_modes, .input_mux = &alc662_lenovo_101e_capture_source, - .unsol_event = alc662_eeepc_unsol_event, + .unsol_event = alc662_eeepc_ep20_unsol_event, .init_hook = alc662_eeepc_ep20_inithook, }, [ALC662_ECS] = { @@ -17105,18 +16739,6 @@ static struct alc_config_preset alc662_presets[] = { .unsol_event = alc663_m51va_unsol_event, .init_hook = alc663_m51va_inithook, }, - [ALC272_SAMSUNG_NC10] = { - .mixers = { alc272_nc10_mixer }, - .init_verbs = { alc662_init_verbs, - alc663_21jd_amic_init_verbs }, - .num_dacs = ARRAY_SIZE(alc272_dac_nids), - .dac_nids = alc272_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), - .channel_mode = alc662_3ST_2ch_modes, - .input_mux = &alc272_nc10_capture_source, - .unsol_event = alc663_mode4_unsol_event, - .init_hook = alc663_mode4_inithook, - }, }; @@ -17311,6 +16933,7 @@ static void alc662_auto_init_multi_out(struct hda_codec *codec) struct alc_spec *spec = codec->spec; int i; + alc_subsystem_id(codec, 0x15, 0x1b, 0x14); for (i = 0; i <= HDA_SIDE; i++) { hda_nid_t nid = spec->autocfg.line_out_pins[i]; int pin_type = get_pin_type(spec->autocfg.line_out_type); @@ -17407,8 +17030,6 @@ static int alc662_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; - alc_ssid_check(codec, 0x15, 0x1b, 0x14); - return 1; } @@ -17441,8 +17062,8 @@ static int patch_alc662(struct hda_codec *codec) alc662_models, alc662_cfg_tbl); if (board_config < 0) { - printk(KERN_INFO "hda_codec: Unknown model for %s, " - "trying auto-probe from BIOS...\n", codec->chip_name); + printk(KERN_INFO "hda_codec: Unknown model for ALC662, " + "trying auto-probe from BIOS...\n"); board_config = ALC662_AUTO; } @@ -17469,6 +17090,17 @@ static int patch_alc662(struct hda_codec *codec) if (board_config != ALC662_AUTO) setup_preset(spec, &alc662_presets[board_config]); + if (codec->vendor_id == 0x10ec0663) { + spec->stream_name_analog = "ALC663 Analog"; + spec->stream_name_digital = "ALC663 Digital"; + } else if (codec->vendor_id == 0x10ec0272) { + spec->stream_name_analog = "ALC272 Analog"; + spec->stream_name_digital = "ALC272 Digital"; + } else { + spec->stream_name_analog = "ALC662 Analog"; + spec->stream_name_digital = "ALC662 Digital"; + } + spec->stream_analog_playback = &alc662_pcm_analog_playback; spec->stream_analog_capture = &alc662_pcm_analog_capture; @@ -17478,6 +17110,7 @@ static int patch_alc662(struct hda_codec *codec) spec->adc_nids = alc662_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids); spec->capsrc_nids = alc662_capsrc_nids; + spec->capture_style = CAPT_MIX; if (!spec->cap_mixer) set_capture_mixer(spec); diff --git a/trunk/sound/pci/hda/patch_sigmatel.c b/trunk/sound/pci/hda/patch_sigmatel.c index 14f3c3e0f62d..d2fd8ef6aef8 100644 --- a/trunk/sound/pci/hda/patch_sigmatel.c +++ b/trunk/sound/pci/hda/patch_sigmatel.c @@ -100,7 +100,6 @@ enum { STAC_HP_M4, STAC_HP_DV5, STAC_HP_HDX, - STAC_HP_DV4_1222NR, STAC_92HD71BXX_MODELS }; @@ -194,7 +193,6 @@ struct sigmatel_spec { unsigned int gpio_dir; unsigned int gpio_data; unsigned int gpio_mute; - unsigned int gpio_led; /* stream */ unsigned int stream_delay; @@ -636,40 +634,6 @@ static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol, return 0; } -static unsigned int stac92xx_vref_set(struct hda_codec *codec, - hda_nid_t nid, unsigned int new_vref) -{ - int error; - unsigned int pincfg; - pincfg = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - - pincfg &= 0xff; - pincfg &= ~(AC_PINCTL_VREFEN | AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN); - pincfg |= new_vref; - - if (new_vref == AC_PINCTL_VREF_HIZ) - pincfg |= AC_PINCTL_OUT_EN; - else - pincfg |= AC_PINCTL_IN_EN; - - error = snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, pincfg); - if (error < 0) - return error; - else - return 1; -} - -static unsigned int stac92xx_vref_get(struct hda_codec *codec, hda_nid_t nid) -{ - unsigned int vref; - vref = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - vref &= AC_PINCTL_VREFEN; - return vref; -} - static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); @@ -1031,17 +995,6 @@ static struct hda_verb stac9205_core_init[] = { .private_value = verb_read | (verb_write << 16), \ } -#define DC_BIAS(xname, idx, nid) \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = idx, \ - .info = stac92xx_dc_bias_info, \ - .get = stac92xx_dc_bias_get, \ - .put = stac92xx_dc_bias_put, \ - .private_value = nid, \ - } - static struct snd_kcontrol_new stac9200_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), @@ -1590,8 +1543,6 @@ static struct snd_pci_quirk stac9200_cfg_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xfb30, - "SigmaTel",STAC_9205_REF), SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, "DFI LanParty", STAC_REF), /* Dell laptops have BIOS problem */ @@ -1886,7 +1837,6 @@ static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = { [STAC_HP_M4] = NULL, [STAC_HP_DV5] = NULL, [STAC_HP_HDX] = NULL, - [STAC_HP_DV4_1222NR] = NULL, }; static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = { @@ -1898,7 +1848,6 @@ static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = { [STAC_HP_M4] = "hp-m4", [STAC_HP_DV5] = "hp-dv5", [STAC_HP_HDX] = "hp-hdx", - [STAC_HP_DV4_1222NR] = "hp-dv4-1222nr", }; static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { @@ -1907,8 +1856,6 @@ static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { "DFI LanParty", STAC_92HD71BXX_REF), SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, "DFI LanParty", STAC_92HD71BXX_REF), - SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fb, - "HP dv4-1222nr", STAC_HP_DV4_1222NR), SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3080, "HP", STAC_HP_DV5), SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x30f0, @@ -2598,8 +2545,7 @@ static int stac92xx_build_pcms(struct hda_codec *codec) return 0; } -static unsigned int stac92xx_get_default_vref(struct hda_codec *codec, - hda_nid_t nid) +static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid) { unsigned int pincap = snd_hda_query_pin_caps(codec, nid); pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; @@ -2653,108 +2599,15 @@ static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol, return 1; } -static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - int i; - static char *texts[] = { - "Mic In", "Line In", "Line Out" - }; - - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - hda_nid_t nid = kcontrol->private_value; - - if (nid == spec->mic_switch || nid == spec->line_switch) - i = 3; - else - i = 2; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->value.enumerated.items = i; - uinfo->count = 1; - if (uinfo->value.enumerated.item >= i) - uinfo->value.enumerated.item = i-1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - - return 0; -} - -static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value; - unsigned int vref = stac92xx_vref_get(codec, nid); - - if (vref == stac92xx_get_default_vref(codec, nid)) - ucontrol->value.enumerated.item[0] = 0; - else if (vref == AC_PINCTL_VREF_GRD) - ucontrol->value.enumerated.item[0] = 1; - else if (vref == AC_PINCTL_VREF_HIZ) - ucontrol->value.enumerated.item[0] = 2; - - return 0; -} - -static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int new_vref = 0; - int error; - hda_nid_t nid = kcontrol->private_value; - - if (ucontrol->value.enumerated.item[0] == 0) - new_vref = stac92xx_get_default_vref(codec, nid); - else if (ucontrol->value.enumerated.item[0] == 1) - new_vref = AC_PINCTL_VREF_GRD; - else if (ucontrol->value.enumerated.item[0] == 2) - new_vref = AC_PINCTL_VREF_HIZ; - else - return 0; - - if (new_vref != stac92xx_vref_get(codec, nid)) { - error = stac92xx_vref_set(codec, nid, new_vref); - return error; - } - - return 0; -} - -static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static char *texts[2]; - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - - if (kcontrol->private_value == spec->line_switch) - texts[0] = "Line In"; - else - texts[0] = "Mic In"; - texts[1] = "Line Out"; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->value.enumerated.items = 2; - uinfo->count = 1; - - if (uinfo->value.enumerated.item >= 2) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - - return 0; -} +#define stac92xx_io_switch_info snd_ctl_boolean_mono_info static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - hda_nid_t nid = kcontrol->private_value; - int io_idx = (nid == spec->mic_switch) ? 1 : 0; + int io_idx = kcontrol-> private_value & 0xff; - ucontrol->value.enumerated.item[0] = spec->io_switch[io_idx]; + ucontrol->value.integer.value[0] = spec->io_switch[io_idx]; return 0; } @@ -2762,9 +2615,9 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - hda_nid_t nid = kcontrol->private_value; - int io_idx = (nid == spec->mic_switch) ? 1 : 0; - unsigned short val = !!ucontrol->value.enumerated.item[0]; + hda_nid_t nid = kcontrol->private_value >> 8; + int io_idx = kcontrol-> private_value & 0xff; + unsigned short val = !!ucontrol->value.integer.value[0]; spec->io_switch[io_idx] = val; @@ -2773,7 +2626,7 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ else { unsigned int pinctl = AC_PINCTL_IN_EN; if (io_idx) /* set VREF for mic */ - pinctl |= stac92xx_get_default_vref(codec, nid); + pinctl |= stac92xx_get_vref(codec, nid); stac92xx_auto_set_pinctl(codec, nid, pinctl); } @@ -2854,8 +2707,7 @@ enum { STAC_CTL_WIDGET_AMP_VOL, STAC_CTL_WIDGET_HP_SWITCH, STAC_CTL_WIDGET_IO_SWITCH, - STAC_CTL_WIDGET_CLFE_SWITCH, - STAC_CTL_WIDGET_DC_BIAS + STAC_CTL_WIDGET_CLFE_SWITCH }; static struct snd_kcontrol_new stac92xx_control_templates[] = { @@ -2867,7 +2719,6 @@ static struct snd_kcontrol_new stac92xx_control_templates[] = { STAC_CODEC_HP_SWITCH(NULL), STAC_CODEC_IO_SWITCH(NULL, 0), STAC_CODEC_CLFE_SWITCH(NULL, 0), - DC_BIAS(NULL, 0, 0), }; /* add dynamic controls */ @@ -2931,34 +2782,6 @@ static struct snd_kcontrol_new stac_input_src_temp = { .put = stac92xx_mux_enum_put, }; -static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec, - hda_nid_t nid, int idx) -{ - int def_conf = snd_hda_codec_get_pincfg(codec, nid); - int control = 0; - struct sigmatel_spec *spec = codec->spec; - char name[22]; - - if (!((get_defcfg_connect(def_conf)) & AC_JACK_PORT_FIXED)) { - if (stac92xx_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD - && nid == spec->line_switch) - control = STAC_CTL_WIDGET_IO_SWITCH; - else if (snd_hda_query_pin_caps(codec, nid) - & (AC_PINCAP_VREF_GRD << AC_PINCAP_VREF_SHIFT)) - control = STAC_CTL_WIDGET_DC_BIAS; - else if (nid == spec->mic_switch) - control = STAC_CTL_WIDGET_IO_SWITCH; - } - - if (control) { - strcpy(name, auto_pin_cfg_labels[idx]); - return stac92xx_add_control(codec->spec, control, - strcat(name, " Jack Mode"), nid); - } - - return 0; -} - static int stac92xx_add_input_source(struct sigmatel_spec *spec) { struct snd_kcontrol_new *knew; @@ -3321,9 +3144,7 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { struct sigmatel_spec *spec = codec->spec; - hda_nid_t nid; int err; - int idx; err = create_multi_out_ctls(codec, cfg->line_outs, cfg->line_out_pins, spec->multiout.dac_nids, @@ -3340,13 +3161,20 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, return err; } - for (idx = AUTO_PIN_MIC; idx <= AUTO_PIN_FRONT_LINE; idx++) { - nid = cfg->input_pins[idx]; - if (nid) { - err = stac92xx_add_jack_mode_control(codec, nid, idx); - if (err < 0) - return err; - } + if (spec->line_switch) { + err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, + "Line In as Output Switch", + spec->line_switch << 8); + if (err < 0) + return err; + } + + if (spec->mic_switch) { + err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, + "Mic as Output Switch", + (spec->mic_switch << 8) | 1); + if (err < 0) + return err; } return 0; @@ -3811,8 +3639,6 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out err = snd_hda_attach_beep_device(codec, nid); if (err < 0) return err; - /* IDT/STAC codecs have linear beep tone parameter */ - codec->beep->linear_tone = 1; /* if no beep switch is available, make its own one */ caps = query_amp_caps(codec, nid, HDA_OUTPUT); if (codec->beep && @@ -4035,7 +3861,7 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask, AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */ } -#ifdef CONFIG_SND_HDA_INPUT_JACK +#ifdef CONFIG_SND_JACK static void stac92xx_free_jack_priv(struct snd_jack *jack) { struct sigmatel_jack *jacks = jack->private_data; @@ -4047,7 +3873,7 @@ static void stac92xx_free_jack_priv(struct snd_jack *jack) static int stac92xx_add_jack(struct hda_codec *codec, hda_nid_t nid, int type) { -#ifdef CONFIG_SND_HDA_INPUT_JACK +#ifdef CONFIG_SND_JACK struct sigmatel_spec *spec = codec->spec; struct sigmatel_jack *jack; int def_conf = snd_hda_codec_get_pincfg(codec, nid); @@ -4256,7 +4082,7 @@ static int stac92xx_init(struct hda_codec *codec) unsigned int pinctl, conf; if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) { /* for mic pins, force to initialize */ - pinctl = stac92xx_get_default_vref(codec, nid); + pinctl = stac92xx_get_vref(codec, nid); pinctl |= AC_PINCTL_IN_EN; stac92xx_auto_set_pinctl(codec, nid, pinctl); } else { @@ -4336,7 +4162,7 @@ static int stac92xx_init(struct hda_codec *codec) static void stac92xx_free_jacks(struct hda_codec *codec) { -#ifdef CONFIG_SND_HDA_INPUT_JACK +#ifdef CONFIG_SND_JACK /* free jack instances manually when clearing/reconfiguring */ struct sigmatel_spec *spec = codec->spec; if (!codec->bus->shutdown && spec->jacks.list) { @@ -4709,19 +4535,17 @@ static int stac92xx_resume(struct hda_codec *codec) return 0; } + /* - * using power check for controlling mute led of HP notebooks + * using power check for controlling mute led of HP HDX notebooks * check for mute state only on Speakers (nid = 0x10) * * For this feature CONFIG_SND_HDA_POWER_SAVE is needed, otherwise * the LED is NOT working properly ! - * - * Changed name to reflect that it now works for any designated - * model, not just HP HDX. */ #ifdef CONFIG_SND_HDA_POWER_SAVE -static int stac92xx_hp_check_power_status(struct hda_codec *codec, +static int stac92xx_hp_hdx_check_power_status(struct hda_codec *codec, hda_nid_t nid) { struct sigmatel_spec *spec = codec->spec; @@ -4729,9 +4553,9 @@ static int stac92xx_hp_check_power_status(struct hda_codec *codec, if (nid == 0x10) { if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) & HDA_AMP_MUTE) - spec->gpio_data &= ~spec->gpio_led; /* orange */ + spec->gpio_data &= ~0x08; /* orange */ else - spec->gpio_data |= spec->gpio_led; /* white */ + spec->gpio_data |= 0x08; /* white */ stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, @@ -5377,15 +5201,6 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP) snd_hda_sequence_write_cache(codec, unmute_init); - /* Some HP machines seem to have unstable codec communications - * especially with ATI fglrx driver. For recovering from the - * CORB/RIRB stall, allow the BUS reset and keep always sync - */ - if (spec->board_config == STAC_HP_DV5) { - codec->bus->sync_write = 1; - codec->bus->allow_bus_reset = 1; - } - spec->aloopback_ctl = stac92hd71bxx_loopback; spec->aloopback_mask = 0x50; spec->aloopback_shift = 0; @@ -5419,15 +5234,6 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) spec->num_smuxes = 0; spec->num_dmuxes = 1; break; - case STAC_HP_DV4_1222NR: - spec->num_dmics = 1; - /* I don't know if it needs 1 or 2 smuxes - will wait for - * bug reports to fix if needed - */ - spec->num_smuxes = 1; - spec->num_dmuxes = 1; - spec->gpio_led = 0x01; - /* fallthrough */ case STAC_HP_DV5: snd_hda_codec_set_pincfg(codec, 0x0d, 0x90170010); stac92xx_auto_set_pinctl(codec, 0x0d, AC_PINCTL_OUT_EN); @@ -5436,21 +5242,22 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) spec->num_dmics = 1; spec->num_dmuxes = 1; spec->num_smuxes = 1; + /* + * For controlling MUTE LED on HP HDX16/HDX18 notebooks, + * the CONFIG_SND_HDA_POWER_SAVE is needed to be set. + */ +#ifdef CONFIG_SND_HDA_POWER_SAVE /* orange/white mute led on GPIO3, orange=0, white=1 */ - spec->gpio_led = 0x08; - break; - } + spec->gpio_mask |= 0x08; + spec->gpio_dir |= 0x08; + spec->gpio_data |= 0x08; /* set to white */ -#ifdef CONFIG_SND_HDA_POWER_SAVE - if (spec->gpio_led) { - spec->gpio_mask |= spec->gpio_led; - spec->gpio_dir |= spec->gpio_led; - spec->gpio_data |= spec->gpio_led; /* register check_power_status callback. */ codec->patch_ops.check_power_status = - stac92xx_hp_check_power_status; - } + stac92xx_hp_hdx_check_power_status; #endif + break; + }; spec->multiout.dac_nids = spec->dac_nids; if (spec->dinput_mux) @@ -5475,7 +5282,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) codec->proc_widget_hook = stac92hd7x_proc_hook; return 0; -} +}; static int patch_stac922x(struct hda_codec *codec) { @@ -5630,7 +5437,7 @@ static int patch_stac927x(struct hda_codec *codec) /* correct the device field to SPDIF out */ snd_hda_codec_set_pincfg(codec, 0x21, 0x01442070); break; - } + }; /* configure the analog microphone on some laptops */ snd_hda_codec_set_pincfg(codec, 0x0c, 0x90a79130); /* correct the front output jack as a hp out */ @@ -5940,7 +5747,6 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = { { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 }, { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 }, { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 }, - { .id = 0x83847698, .name = "STAC9205", .patch = patch_stac9205 }, { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 }, { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 }, { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 }, diff --git a/trunk/sound/pci/hda/patch_via.c b/trunk/sound/pci/hda/patch_via.c index 8e004fb6961a..b25a5cc637d6 100644 --- a/trunk/sound/pci/hda/patch_via.c +++ b/trunk/sound/pci/hda/patch_via.c @@ -205,7 +205,7 @@ struct via_spec { /* playback */ struct hda_multi_out multiout; - hda_nid_t slave_dig_outs[2]; + hda_nid_t extra_dig_out_nid; /* capture */ unsigned int num_adc_nids; @@ -731,6 +731,21 @@ static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, return snd_hda_multi_out_dig_close(codec, &spec->multiout); } +/* setup SPDIF output stream */ +static void setup_dig_playback_stream(struct hda_codec *codec, hda_nid_t nid, + unsigned int stream_tag, unsigned int format) +{ + /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ + if (codec->spdif_ctls & AC_DIG1_ENABLE) + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, + codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); + snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); + /* turn on again (if needed) */ + if (codec->spdif_ctls & AC_DIG1_ENABLE) + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, + codec->spdif_ctls & 0xff); +} + static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, struct hda_codec *codec, unsigned int stream_tag, @@ -738,16 +753,19 @@ static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { struct via_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, - stream_tag, format, substream); -} + hda_nid_t nid; -static int via_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); + /* 1st or 2nd S/PDIF */ + if (substream->number == 0) + nid = spec->multiout.dig_out_nid; + else if (substream->number == 1) + nid = spec->extra_dig_out_nid; + else + return -1; + + mutex_lock(&codec->spdif_mutex); + setup_dig_playback_stream(codec, nid, stream_tag, format); + mutex_unlock(&codec->spdif_mutex); return 0; } @@ -824,8 +842,7 @@ static struct hda_pcm_stream vt1708_pcm_digital_playback = { .ops = { .open = via_dig_playback_pcm_open, .close = via_dig_playback_pcm_close, - .prepare = via_dig_playback_pcm_prepare, - .cleanup = via_dig_playback_pcm_cleanup + .prepare = via_dig_playback_pcm_prepare }, }; @@ -857,6 +874,13 @@ static int via_build_controls(struct hda_codec *codec) if (err < 0) return err; spec->multiout.share_spdif = 1; + + if (spec->extra_dig_out_nid) { + err = snd_hda_create_spdif_out_ctls(codec, + spec->extra_dig_out_nid); + if (err < 0) + return err; + } } if (spec->dig_in_nid) { err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); @@ -989,6 +1013,10 @@ static void via_unsol_event(struct hda_codec *codec, via_gpio_control(codec); } +static hda_nid_t slave_dig_outs[] = { + 0, +}; + static int via_init(struct hda_codec *codec) { struct via_spec *spec = codec->spec; @@ -1023,9 +1051,8 @@ static int via_init(struct hda_codec *codec) snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN); - /* assign slave outs */ - if (spec->slave_dig_outs[0]) - codec->slave_dig_outs = spec->slave_dig_outs; + /* no slave outs */ + codec->slave_dig_outs = slave_dig_outs; return 0; } @@ -2107,8 +2134,7 @@ static struct hda_pcm_stream vt1708B_pcm_digital_playback = { .ops = { .open = via_dig_playback_pcm_open, .close = via_dig_playback_pcm_close, - .prepare = via_dig_playback_pcm_prepare, - .cleanup = via_dig_playback_pcm_cleanup + .prepare = via_dig_playback_pcm_prepare }, }; @@ -2563,15 +2589,14 @@ static struct hda_pcm_stream vt1708S_pcm_analog_capture = { }; static struct hda_pcm_stream vt1708S_pcm_digital_playback = { - .substreams = 1, + .substreams = 2, .channels_min = 2, .channels_max = 2, /* NID is set in via_build_pcms */ .ops = { .open = via_dig_playback_pcm_open, .close = via_dig_playback_pcm_close, - .prepare = via_dig_playback_pcm_prepare, - .cleanup = via_dig_playback_pcm_cleanup + .prepare = via_dig_playback_pcm_prepare }, }; @@ -2780,37 +2805,14 @@ static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec, return 0; } -/* fill out digital output widgets; one for master and one for slave outputs */ -static void fill_dig_outs(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->autocfg.dig_outs; i++) { - hda_nid_t nid; - int conn; - - nid = spec->autocfg.dig_out_pins[i]; - if (!nid) - continue; - conn = snd_hda_get_connections(codec, nid, &nid, 1); - if (conn < 1) - continue; - if (!spec->multiout.dig_out_nid) - spec->multiout.dig_out_nid = nid; - else { - spec->slave_dig_outs[0] = nid; - break; /* at most two dig outs */ - } - } -} - static int vt1708S_parse_auto_config(struct hda_codec *codec) { struct via_spec *spec = codec->spec; int err; + static hda_nid_t vt1708s_ignore[] = {0x21, 0}; - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, + vt1708s_ignore); if (err < 0) return err; err = vt1708S_auto_fill_dac_nids(spec, &spec->autocfg); @@ -2831,7 +2833,10 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec) spec->multiout.max_channels = spec->multiout.num_dacs * 2; - fill_dig_outs(codec); + if (spec->autocfg.dig_outs) + spec->multiout.dig_out_nid = VT1708S_DIGOUT_NID; + + spec->extra_dig_out_nid = 0x15; if (spec->kctls.list) spec->mixers[spec->num_mixers++] = spec->kctls.list; @@ -2995,8 +3000,7 @@ static struct hda_pcm_stream vt1702_pcm_digital_playback = { .ops = { .open = via_dig_playback_pcm_open, .close = via_dig_playback_pcm_close, - .prepare = via_dig_playback_pcm_prepare, - .cleanup = via_dig_playback_pcm_cleanup + .prepare = via_dig_playback_pcm_prepare }, }; @@ -3124,8 +3128,10 @@ static int vt1702_parse_auto_config(struct hda_codec *codec) { struct via_spec *spec = codec->spec; int err; + static hda_nid_t vt1702_ignore[] = {0x1C, 0}; - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, + vt1702_ignore); if (err < 0) return err; err = vt1702_auto_fill_dac_nids(spec, &spec->autocfg); @@ -3146,7 +3152,10 @@ static int vt1702_parse_auto_config(struct hda_codec *codec) spec->multiout.max_channels = spec->multiout.num_dacs * 2; - fill_dig_outs(codec); + if (spec->autocfg.dig_outs) + spec->multiout.dig_out_nid = VT1702_DIGOUT_NID; + + spec->extra_dig_out_nid = 0x1B; if (spec->kctls.list) spec->mixers[spec->num_mixers++] = spec->kctls.list; diff --git a/trunk/sound/pci/ice1712/Makefile b/trunk/sound/pci/ice1712/Makefile index 536eae2ccf94..f99fe089495d 100644 --- a/trunk/sound/pci/ice1712/Makefile +++ b/trunk/sound/pci/ice1712/Makefile @@ -5,7 +5,7 @@ snd-ice17xx-ak4xxx-objs := ak4xxx.o snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o -snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o prodigy_hifi.o juli.o phase.o wtm.o se.o maya44.o +snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o prodigy_hifi.o juli.o phase.o wtm.o se.o # Toplevel Module Dependency obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o diff --git a/trunk/sound/pci/ice1712/ice1712.h b/trunk/sound/pci/ice1712/ice1712.h index adc909ec125c..fdae6deba16b 100644 --- a/trunk/sound/pci/ice1712/ice1712.h +++ b/trunk/sound/pci/ice1712/ice1712.h @@ -335,7 +335,6 @@ struct snd_ice1712 { unsigned int force_rdma1:1; /* VT1720/4 - RDMA1 as non-spdif */ unsigned int midi_output:1; /* VT1720/4: MIDI output triggered */ unsigned int midi_input:1; /* VT1720/4: MIDI input triggered */ - unsigned int own_routing:1; /* VT1720/4: use own routing ctls */ unsigned int num_total_dacs; /* total DACs */ unsigned int num_total_adcs; /* total ADCs */ unsigned int cur_rate; /* current rate */ @@ -459,17 +458,10 @@ static inline int snd_ice1712_gpio_read_bits(struct snd_ice1712 *ice, return snd_ice1712_gpio_read(ice) & mask; } -/* route access functions */ -int snd_ice1724_get_route_val(struct snd_ice1712 *ice, int shift); -int snd_ice1724_put_route_val(struct snd_ice1712 *ice, unsigned int val, - int shift); - int snd_ice1712_spdif_build_controls(struct snd_ice1712 *ice); -int snd_ice1712_akm4xxx_init(struct snd_akm4xxx *ak, - const struct snd_akm4xxx *template, - const struct snd_ak4xxx_private *priv, - struct snd_ice1712 *ice); +int snd_ice1712_akm4xxx_init(struct snd_akm4xxx *ak, const struct snd_akm4xxx *template, + const struct snd_ak4xxx_private *priv, struct snd_ice1712 *ice); void snd_ice1712_akm4xxx_free(struct snd_ice1712 *ice); int snd_ice1712_akm4xxx_build_controls(struct snd_ice1712 *ice); diff --git a/trunk/sound/pci/ice1712/ice1724.c b/trunk/sound/pci/ice1712/ice1724.c index 36ade77cf371..128510e77a78 100644 --- a/trunk/sound/pci/ice1712/ice1724.c +++ b/trunk/sound/pci/ice1712/ice1724.c @@ -49,7 +49,6 @@ #include "prodigy192.h" #include "prodigy_hifi.h" #include "juli.h" -#include "maya44.h" #include "phase.h" #include "wtm.h" #include "se.h" @@ -66,7 +65,6 @@ MODULE_SUPPORTED_DEVICE("{" PRODIGY192_DEVICE_DESC PRODIGY_HIFI_DEVICE_DESC JULI_DEVICE_DESC - MAYA44_DEVICE_DESC PHASE_DEVICE_DESC WTM_DEVICE_DESC SE_DEVICE_DESC @@ -628,7 +626,7 @@ static unsigned char stdclock_set_mclk(struct snd_ice1712 *ice, return 0; } -static int snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate, +static void snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate, int force) { unsigned long flags; @@ -636,18 +634,17 @@ static int snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate, unsigned int i, old_rate; if (rate > ice->hw_rates->list[ice->hw_rates->count - 1]) - return -EINVAL; - + return; spin_lock_irqsave(&ice->reg_lock, flags); if ((inb(ICEMT1724(ice, DMA_CONTROL)) & DMA_STARTS) || (inb(ICEMT1724(ice, DMA_PAUSE)) & DMA_PAUSES)) { /* running? we cannot change the rate now... */ spin_unlock_irqrestore(&ice->reg_lock, flags); - return -EBUSY; + return; } if (!force && is_pro_rate_locked(ice)) { spin_unlock_irqrestore(&ice->reg_lock, flags); - return (rate == ice->cur_rate) ? 0 : -EBUSY; + return; } old_rate = ice->get_rate(ice); @@ -655,7 +652,7 @@ static int snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate, ice->set_rate(ice, rate); else if (rate == ice->cur_rate) { spin_unlock_irqrestore(&ice->reg_lock, flags); - return 0; + return; } ice->cur_rate = rate; @@ -677,15 +674,13 @@ static int snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate, } if (ice->spdif.ops.setup_rate) ice->spdif.ops.setup_rate(ice, rate); - - return 0; } static int snd_vt1724_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); - int i, chs, err; + int i, chs; chs = params_channels(hw_params); mutex_lock(&ice->open_mutex); @@ -720,11 +715,7 @@ static int snd_vt1724_pcm_hw_params(struct snd_pcm_substream *substream, } } mutex_unlock(&ice->open_mutex); - - err = snd_vt1724_set_pro_rate(ice, params_rate(hw_params), 0); - if (err < 0) - return err; - + snd_vt1724_set_pro_rate(ice, params_rate(hw_params), 0); return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); } @@ -857,39 +848,20 @@ static snd_pcm_uframes_t snd_vt1724_pcm_pointer(struct snd_pcm_substream *substr #endif } -static const struct vt1724_pcm_reg vt1724_pdma0_reg = { +static const struct vt1724_pcm_reg vt1724_playback_pro_reg = { .addr = VT1724_MT_PLAYBACK_ADDR, .size = VT1724_MT_PLAYBACK_SIZE, .count = VT1724_MT_PLAYBACK_COUNT, .start = VT1724_PDMA0_START, }; -static const struct vt1724_pcm_reg vt1724_pdma4_reg = { - .addr = VT1724_MT_PDMA4_ADDR, - .size = VT1724_MT_PDMA4_SIZE, - .count = VT1724_MT_PDMA4_COUNT, - .start = VT1724_PDMA4_START, -}; - -static const struct vt1724_pcm_reg vt1724_rdma0_reg = { +static const struct vt1724_pcm_reg vt1724_capture_pro_reg = { .addr = VT1724_MT_CAPTURE_ADDR, .size = VT1724_MT_CAPTURE_SIZE, .count = VT1724_MT_CAPTURE_COUNT, .start = VT1724_RDMA0_START, }; -static const struct vt1724_pcm_reg vt1724_rdma1_reg = { - .addr = VT1724_MT_RDMA1_ADDR, - .size = VT1724_MT_RDMA1_SIZE, - .count = VT1724_MT_RDMA1_COUNT, - .start = VT1724_RDMA1_START, -}; - -#define vt1724_playback_pro_reg vt1724_pdma0_reg -#define vt1724_playback_spdif_reg vt1724_pdma4_reg -#define vt1724_capture_pro_reg vt1724_rdma0_reg -#define vt1724_capture_spdif_reg vt1724_rdma1_reg - static const struct snd_pcm_hardware snd_vt1724_playback_pro = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | @@ -1105,6 +1077,20 @@ static int __devinit snd_vt1724_pcm_profi(struct snd_ice1712 *ice, int device) * SPDIF PCM */ +static const struct vt1724_pcm_reg vt1724_playback_spdif_reg = { + .addr = VT1724_MT_PDMA4_ADDR, + .size = VT1724_MT_PDMA4_SIZE, + .count = VT1724_MT_PDMA4_COUNT, + .start = VT1724_PDMA4_START, +}; + +static const struct vt1724_pcm_reg vt1724_capture_spdif_reg = { + .addr = VT1724_MT_RDMA1_ADDR, + .size = VT1724_MT_RDMA1_SIZE, + .count = VT1724_MT_RDMA1_COUNT, + .start = VT1724_RDMA1_START, +}; + /* update spdif control bits; call with reg_lock */ static void update_spdif_bits(struct snd_ice1712 *ice, unsigned int val) { @@ -1977,7 +1963,7 @@ static inline int digital_route_shift(int idx) return idx * 3; } -int snd_ice1724_get_route_val(struct snd_ice1712 *ice, int shift) +static int get_route_val(struct snd_ice1712 *ice, int shift) { unsigned long val; unsigned char eitem; @@ -1996,8 +1982,7 @@ int snd_ice1724_get_route_val(struct snd_ice1712 *ice, int shift) return eitem; } -int snd_ice1724_put_route_val(struct snd_ice1712 *ice, unsigned int val, - int shift) +static int put_route_val(struct snd_ice1712 *ice, unsigned int val, int shift) { unsigned int old_val, nval; int change; @@ -2025,7 +2010,7 @@ static int snd_vt1724_pro_route_analog_get(struct snd_kcontrol *kcontrol, struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); ucontrol->value.enumerated.item[0] = - snd_ice1724_get_route_val(ice, analog_route_shift(idx)); + get_route_val(ice, analog_route_shift(idx)); return 0; } @@ -2034,9 +2019,8 @@ static int snd_vt1724_pro_route_analog_put(struct snd_kcontrol *kcontrol, { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - return snd_ice1724_put_route_val(ice, - ucontrol->value.enumerated.item[0], - analog_route_shift(idx)); + return put_route_val(ice, ucontrol->value.enumerated.item[0], + analog_route_shift(idx)); } static int snd_vt1724_pro_route_spdif_get(struct snd_kcontrol *kcontrol, @@ -2045,7 +2029,7 @@ static int snd_vt1724_pro_route_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); ucontrol->value.enumerated.item[0] = - snd_ice1724_get_route_val(ice, digital_route_shift(idx)); + get_route_val(ice, digital_route_shift(idx)); return 0; } @@ -2054,13 +2038,11 @@ static int snd_vt1724_pro_route_spdif_put(struct snd_kcontrol *kcontrol, { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - return snd_ice1724_put_route_val(ice, - ucontrol->value.enumerated.item[0], - digital_route_shift(idx)); + return put_route_val(ice, ucontrol->value.enumerated.item[0], + digital_route_shift(idx)); } -static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata = -{ +static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "H/W Playback Route", .info = snd_vt1724_pro_route_info, @@ -2127,7 +2109,6 @@ static struct snd_ice1712_card_info *card_tables[] __devinitdata = { snd_vt1724_prodigy_hifi_cards, snd_vt1724_prodigy192_cards, snd_vt1724_juli_cards, - snd_vt1724_maya44_cards, snd_vt1724_phase_cards, snd_vt1724_wtm_cards, snd_vt1724_se_cards, @@ -2265,10 +2246,8 @@ static int __devinit snd_vt1724_read_eeprom(struct snd_ice1712 *ice, static void __devinit snd_vt1724_chip_reset(struct snd_ice1712 *ice) { outb(VT1724_RESET , ICEREG1724(ice, CONTROL)); - inb(ICEREG1724(ice, CONTROL)); /* pci posting flush */ msleep(10); outb(0, ICEREG1724(ice, CONTROL)); - inb(ICEREG1724(ice, CONTROL)); /* pci posting flush */ msleep(10); } @@ -2298,12 +2277,9 @@ static int __devinit snd_vt1724_spdif_build_controls(struct snd_ice1712 *ice) if (snd_BUG_ON(!ice->pcm)) return -EIO; - if (!ice->own_routing) { - err = snd_ctl_add(ice->card, - snd_ctl_new1(&snd_vt1724_mixer_pro_spdif_route, ice)); - if (err < 0) - return err; - } + err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_mixer_pro_spdif_route, ice)); + if (err < 0) + return err; err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_spdif_switch, ice)); if (err < 0) @@ -2350,7 +2326,7 @@ static int __devinit snd_vt1724_build_controls(struct snd_ice1712 *ice) if (err < 0) return err; - if (!ice->own_routing && ice->num_total_dacs > 0) { + if (ice->num_total_dacs > 0) { struct snd_kcontrol_new tmp = snd_vt1724_mixer_pro_analog_route; tmp.count = ice->num_total_dacs; if (ice->vt1720 && tmp.count > 2) diff --git a/trunk/sound/pci/ice1712/maya44.c b/trunk/sound/pci/ice1712/maya44.c deleted file mode 100644 index 3e1c20ae2f1c..000000000000 --- a/trunk/sound/pci/ice1712/maya44.c +++ /dev/null @@ -1,779 +0,0 @@ -/* - * ALSA driver for ICEnsemble VT1724 (Envy24HT) - * - * Lowlevel functions for ESI Maya44 cards - * - * Copyright (c) 2009 Takashi Iwai - * Based on the patches by Rainer Zimmermann - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "ice1712.h" -#include "envy24ht.h" -#include "maya44.h" - -/* WM8776 register indexes */ -#define WM8776_REG_HEADPHONE_L 0x00 -#define WM8776_REG_HEADPHONE_R 0x01 -#define WM8776_REG_HEADPHONE_MASTER 0x02 -#define WM8776_REG_DAC_ATTEN_L 0x03 -#define WM8776_REG_DAC_ATTEN_R 0x04 -#define WM8776_REG_DAC_ATTEN_MASTER 0x05 -#define WM8776_REG_DAC_PHASE 0x06 -#define WM8776_REG_DAC_CONTROL 0x07 -#define WM8776_REG_DAC_MUTE 0x08 -#define WM8776_REG_DAC_DEEMPH 0x09 -#define WM8776_REG_DAC_IF_CONTROL 0x0a -#define WM8776_REG_ADC_IF_CONTROL 0x0b -#define WM8776_REG_MASTER_MODE_CONTROL 0x0c -#define WM8776_REG_POWERDOWN 0x0d -#define WM8776_REG_ADC_ATTEN_L 0x0e -#define WM8776_REG_ADC_ATTEN_R 0x0f -#define WM8776_REG_ADC_ALC1 0x10 -#define WM8776_REG_ADC_ALC2 0x11 -#define WM8776_REG_ADC_ALC3 0x12 -#define WM8776_REG_ADC_NOISE_GATE 0x13 -#define WM8776_REG_ADC_LIMITER 0x14 -#define WM8776_REG_ADC_MUX 0x15 -#define WM8776_REG_OUTPUT_MUX 0x16 -#define WM8776_REG_RESET 0x17 - -#define WM8776_NUM_REGS 0x18 - -/* clock ratio identifiers for snd_wm8776_set_rate() */ -#define WM8776_CLOCK_RATIO_128FS 0 -#define WM8776_CLOCK_RATIO_192FS 1 -#define WM8776_CLOCK_RATIO_256FS 2 -#define WM8776_CLOCK_RATIO_384FS 3 -#define WM8776_CLOCK_RATIO_512FS 4 -#define WM8776_CLOCK_RATIO_768FS 5 - -enum { WM_VOL_HP, WM_VOL_DAC, WM_VOL_ADC, WM_NUM_VOLS }; -enum { WM_SW_DAC, WM_SW_BYPASS, WM_NUM_SWITCHES }; - -struct snd_wm8776 { - unsigned char addr; - unsigned short regs[WM8776_NUM_REGS]; - unsigned char volumes[WM_NUM_VOLS][2]; - unsigned int switch_bits; -}; - -struct snd_maya44 { - struct snd_ice1712 *ice; - struct snd_wm8776 wm[2]; - struct mutex mutex; -}; - - -/* write the given register and save the data to the cache */ -static void wm8776_write(struct snd_ice1712 *ice, struct snd_wm8776 *wm, - unsigned char reg, unsigned short val) -{ - /* - * WM8776 registers are up to 9 bits wide, bit 8 is placed in the LSB - * of the address field - */ - snd_vt1724_write_i2c(ice, wm->addr, - (reg << 1) | ((val >> 8) & 1), - val & 0xff); - wm->regs[reg] = val; -} - -/* - * update the given register with and/or mask and save the data to the cache - */ -static int wm8776_write_bits(struct snd_ice1712 *ice, struct snd_wm8776 *wm, - unsigned char reg, - unsigned short mask, unsigned short val) -{ - val |= wm->regs[reg] & ~mask; - if (val != wm->regs[reg]) { - wm8776_write(ice, wm, reg, val); - return 1; - } - return 0; -} - - -/* - * WM8776 volume controls - */ - -struct maya_vol_info { - unsigned int maxval; /* volume range: 0..maxval */ - unsigned char regs[2]; /* left and right registers */ - unsigned short mask; /* value mask */ - unsigned short offset; /* zero-value offset */ - unsigned short mute; /* mute bit */ - unsigned short update; /* update bits */ - unsigned char mux_bits[2]; /* extra bits for ADC mute */ -}; - -static struct maya_vol_info vol_info[WM_NUM_VOLS] = { - [WM_VOL_HP] = { - .maxval = 80, - .regs = { WM8776_REG_HEADPHONE_L, WM8776_REG_HEADPHONE_R }, - .mask = 0x7f, - .offset = 0x30, - .mute = 0x00, - .update = 0x180, /* update and zero-cross enable */ - }, - [WM_VOL_DAC] = { - .maxval = 255, - .regs = { WM8776_REG_DAC_ATTEN_L, WM8776_REG_DAC_ATTEN_R }, - .mask = 0xff, - .offset = 0x01, - .mute = 0x00, - .update = 0x100, /* zero-cross enable */ - }, - [WM_VOL_ADC] = { - .maxval = 91, - .regs = { WM8776_REG_ADC_ATTEN_L, WM8776_REG_ADC_ATTEN_R }, - .mask = 0xff, - .offset = 0xa5, - .mute = 0xa5, - .update = 0x100, /* update */ - .mux_bits = { 0x80, 0x40 }, /* ADCMUX bits */ - }, -}; - -/* - * dB tables - */ -/* headphone output: mute, -73..+6db (1db step) */ -static const DECLARE_TLV_DB_SCALE(db_scale_hp, -7400, 100, 1); -/* DAC output: mute, -127..0db (0.5db step) */ -static const DECLARE_TLV_DB_SCALE(db_scale_dac, -12750, 50, 1); -/* ADC gain: mute, -21..+24db (0.5db step) */ -static const DECLARE_TLV_DB_SCALE(db_scale_adc, -2100, 50, 1); - -static int maya_vol_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - unsigned int idx = kcontrol->private_value; - struct maya_vol_info *vol = &vol_info[idx]; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = vol->maxval; - return 0; -} - -static int maya_vol_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); - struct snd_wm8776 *wm = - &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)]; - unsigned int idx = kcontrol->private_value; - - mutex_lock(&chip->mutex); - ucontrol->value.integer.value[0] = wm->volumes[idx][0]; - ucontrol->value.integer.value[1] = wm->volumes[idx][1]; - mutex_unlock(&chip->mutex); - return 0; -} - -static int maya_vol_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); - struct snd_wm8776 *wm = - &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)]; - unsigned int idx = kcontrol->private_value; - struct maya_vol_info *vol = &vol_info[idx]; - unsigned int val, data; - int ch, changed = 0; - - mutex_lock(&chip->mutex); - for (ch = 0; ch < 2; ch++) { - val = ucontrol->value.integer.value[ch]; - if (val > vol->maxval) - val = vol->maxval; - if (val == wm->volumes[idx][ch]) - continue; - if (!val) - data = vol->mute; - else - data = (val - 1) + vol->offset; - data |= vol->update; - changed |= wm8776_write_bits(chip->ice, wm, vol->regs[ch], - vol->mask | vol->update, data); - if (vol->mux_bits[ch]) - wm8776_write_bits(chip->ice, wm, WM8776_REG_ADC_MUX, - vol->mux_bits[ch], - val ? 0 : vol->mux_bits[ch]); - wm->volumes[idx][ch] = val; - } - mutex_unlock(&chip->mutex); - return changed; -} - -/* - * WM8776 switch controls - */ - -#define COMPOSE_SW_VAL(idx, reg, mask) ((idx) | ((reg) << 8) | ((mask) << 16)) -#define GET_SW_VAL_IDX(val) ((val) & 0xff) -#define GET_SW_VAL_REG(val) (((val) >> 8) & 0xff) -#define GET_SW_VAL_MASK(val) (((val) >> 16) & 0xff) - -#define maya_sw_info snd_ctl_boolean_mono_info - -static int maya_sw_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); - struct snd_wm8776 *wm = - &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)]; - unsigned int idx = GET_SW_VAL_IDX(kcontrol->private_value); - - ucontrol->value.integer.value[0] = (wm->switch_bits >> idx) & 1; - return 0; -} - -static int maya_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); - struct snd_wm8776 *wm = - &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)]; - unsigned int idx = GET_SW_VAL_IDX(kcontrol->private_value); - unsigned int mask, val; - int changed; - - mutex_lock(&chip->mutex); - mask = 1 << idx; - wm->switch_bits &= ~mask; - val = ucontrol->value.integer.value[0]; - if (val) - wm->switch_bits |= mask; - mask = GET_SW_VAL_MASK(kcontrol->private_value); - changed = wm8776_write_bits(chip->ice, wm, - GET_SW_VAL_REG(kcontrol->private_value), - mask, val ? mask : 0); - mutex_unlock(&chip->mutex); - return changed; -} - -/* - * GPIO pins (known ones for maya44) - */ -#define GPIO_PHANTOM_OFF 2 -#define GPIO_MIC_RELAY 4 -#define GPIO_SPDIF_IN_INV 5 -#define GPIO_MUST_BE_0 7 - -/* - * GPIO switch controls - */ - -#define COMPOSE_GPIO_VAL(shift, inv) ((shift) | ((inv) << 8)) -#define GET_GPIO_VAL_SHIFT(val) ((val) & 0xff) -#define GET_GPIO_VAL_INV(val) (((val) >> 8) & 1) - -static int maya_set_gpio_bits(struct snd_ice1712 *ice, unsigned int mask, - unsigned int bits) -{ - unsigned int data; - data = snd_ice1712_gpio_read(ice); - if ((data & mask) == bits) - return 0; - snd_ice1712_gpio_write(ice, (data & ~mask) | bits); - return 1; -} - -#define maya_gpio_sw_info snd_ctl_boolean_mono_info - -static int maya_gpio_sw_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); - unsigned int shift = GET_GPIO_VAL_SHIFT(kcontrol->private_value); - unsigned int val; - - val = (snd_ice1712_gpio_read(chip->ice) >> shift) & 1; - if (GET_GPIO_VAL_INV(kcontrol->private_value)) - val = !val; - ucontrol->value.integer.value[0] = val; - return 0; -} - -static int maya_gpio_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); - unsigned int shift = GET_GPIO_VAL_SHIFT(kcontrol->private_value); - unsigned int val, mask; - int changed; - - mutex_lock(&chip->mutex); - mask = 1 << shift; - val = ucontrol->value.integer.value[0]; - if (GET_GPIO_VAL_INV(kcontrol->private_value)) - val = !val; - val = val ? mask : 0; - changed = maya_set_gpio_bits(chip->ice, mask, val); - mutex_unlock(&chip->mutex); - return changed; -} - -/* - * capture source selection - */ - -/* known working input slots (0-4) */ -#define MAYA_LINE_IN 1 /* in-2 */ -#define MAYA_MIC_IN 4 /* in-5 */ - -static void wm8776_select_input(struct snd_maya44 *chip, int idx, int line) -{ - wm8776_write_bits(chip->ice, &chip->wm[idx], WM8776_REG_ADC_MUX, - 0x1f, 1 << line); -} - -static int maya_rec_src_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static char *texts[] = { "Line", "Mic" }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = ARRAY_SIZE(texts); - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; -} - -static int maya_rec_src_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); - int sel; - - if (snd_ice1712_gpio_read(chip->ice) & (1 << GPIO_MIC_RELAY)) - sel = 1; - else - sel = 0; - ucontrol->value.enumerated.item[0] = sel; - return 0; -} - -static int maya_rec_src_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); - int sel = ucontrol->value.enumerated.item[0]; - int changed; - - mutex_lock(&chip->mutex); - changed = maya_set_gpio_bits(chip->ice, GPIO_MIC_RELAY, - sel ? GPIO_MIC_RELAY : 0); - wm8776_select_input(chip, 0, sel ? MAYA_MIC_IN : MAYA_LINE_IN); - mutex_unlock(&chip->mutex); - return changed; -} - -/* - * Maya44 routing switch settings have different meanings than the standard - * ice1724 switches as defined in snd_vt1724_pro_route_info (ice1724.c). - */ -static int maya_pb_route_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static char *texts[] = { - "PCM Out", /* 0 */ - "Input 1", "Input 2", "Input 3", "Input 4" - }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = ARRAY_SIZE(texts); - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; -} - -static int maya_pb_route_shift(int idx) -{ - static const unsigned char shift[10] = - { 8, 20, 0, 3, 11, 23, 14, 26, 17, 29 }; - return shift[idx % 10]; -} - -static int maya_pb_route_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); - int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - ucontrol->value.enumerated.item[0] = - snd_ice1724_get_route_val(chip->ice, maya_pb_route_shift(idx)); - return 0; -} - -static int maya_pb_route_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); - int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - return snd_ice1724_put_route_val(chip->ice, - ucontrol->value.enumerated.item[0], - maya_pb_route_shift(idx)); -} - - -/* - * controls to be added - */ - -static struct snd_kcontrol_new maya_controls[] __devinitdata = { - { - .name = "Crossmix Playback Volume", - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_TLV_READ, - .info = maya_vol_info, - .get = maya_vol_get, - .put = maya_vol_put, - .tlv = { .p = db_scale_hp }, - .private_value = WM_VOL_HP, - .count = 2, - }, - { - .name = "PCM Playback Volume", - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_TLV_READ, - .info = maya_vol_info, - .get = maya_vol_get, - .put = maya_vol_put, - .tlv = { .p = db_scale_dac }, - .private_value = WM_VOL_DAC, - .count = 2, - }, - { - .name = "Line Capture Volume", - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_TLV_READ, - .info = maya_vol_info, - .get = maya_vol_get, - .put = maya_vol_put, - .tlv = { .p = db_scale_adc }, - .private_value = WM_VOL_ADC, - .count = 2, - }, - { - .name = "PCM Playback Switch", - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .info = maya_sw_info, - .get = maya_sw_get, - .put = maya_sw_put, - .private_value = COMPOSE_SW_VAL(WM_SW_DAC, - WM8776_REG_OUTPUT_MUX, 0x01), - .count = 2, - }, - { - .name = "Bypass Playback Switch", - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .info = maya_sw_info, - .get = maya_sw_get, - .put = maya_sw_put, - .private_value = COMPOSE_SW_VAL(WM_SW_BYPASS, - WM8776_REG_OUTPUT_MUX, 0x04), - .count = 2, - }, - { - .name = "Capture Source", - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .info = maya_rec_src_info, - .get = maya_rec_src_get, - .put = maya_rec_src_put, - }, - { - .name = "Mic Phantom Power Switch", - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .info = maya_gpio_sw_info, - .get = maya_gpio_sw_get, - .put = maya_gpio_sw_put, - .private_value = COMPOSE_GPIO_VAL(GPIO_PHANTOM_OFF, 1), - }, - { - .name = "SPDIF Capture Switch", - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .info = maya_gpio_sw_info, - .get = maya_gpio_sw_get, - .put = maya_gpio_sw_put, - .private_value = COMPOSE_GPIO_VAL(GPIO_SPDIF_IN_INV, 1), - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "H/W Playback Route", - .info = maya_pb_route_info, - .get = maya_pb_route_get, - .put = maya_pb_route_put, - .count = 4, /* FIXME: do controls 5-9 have any meaning? */ - }, -}; - -static int __devinit maya44_add_controls(struct snd_ice1712 *ice) -{ - int err, i; - - for (i = 0; i < ARRAY_SIZE(maya_controls); i++) { - err = snd_ctl_add(ice->card, snd_ctl_new1(&maya_controls[i], - ice->spec)); - if (err < 0) - return err; - } - return 0; -} - - -/* - * initialize a wm8776 chip - */ -static void __devinit wm8776_init(struct snd_ice1712 *ice, - struct snd_wm8776 *wm, unsigned int addr) -{ - static const unsigned short inits_wm8776[] = { - 0x02, 0x100, /* R2: headphone L+R muted + update */ - 0x05, 0x100, /* R5: DAC output L+R muted + update */ - 0x06, 0x000, /* R6: DAC output phase normal */ - 0x07, 0x091, /* R7: DAC enable zero cross detection, - normal output */ - 0x08, 0x000, /* R8: DAC soft mute off */ - 0x09, 0x000, /* R9: no deemph, DAC zero detect disabled */ - 0x0a, 0x022, /* R10: DAC I2C mode, std polarities, 24bit */ - 0x0b, 0x022, /* R11: ADC I2C mode, std polarities, 24bit, - highpass filter enabled */ - 0x0c, 0x042, /* R12: ADC+DAC slave, ADC+DAC 44,1kHz */ - 0x0d, 0x000, /* R13: all power up */ - 0x0e, 0x100, /* R14: ADC left muted, - enable zero cross detection */ - 0x0f, 0x100, /* R15: ADC right muted, - enable zero cross detection */ - /* R16: ALC...*/ - 0x11, 0x000, /* R17: disable ALC */ - /* R18: ALC...*/ - /* R19: noise gate...*/ - 0x15, 0x000, /* R21: ADC input mux init, mute all inputs */ - 0x16, 0x001, /* R22: output mux, select DAC */ - 0xff, 0xff - }; - - const unsigned short *ptr; - unsigned char reg; - unsigned short data; - - wm->addr = addr; - /* enable DAC output; mute bypass, aux & all inputs */ - wm->switch_bits = (1 << WM_SW_DAC); - - ptr = inits_wm8776; - while (*ptr != 0xff) { - reg = *ptr++; - data = *ptr++; - wm8776_write(ice, wm, reg, data); - } -} - - -/* - * change the rate on the WM8776 codecs. - * this assumes that the VT17xx's rate is changed by the calling function. - * NOTE: even though the WM8776's are running in slave mode and rate - * selection is automatic, we need to call snd_wm8776_set_rate() here - * to make sure some flags are set correctly. - */ -static void set_rate(struct snd_ice1712 *ice, unsigned int rate) -{ - struct snd_maya44 *chip = ice->spec; - unsigned int ratio, adc_ratio, val; - int i; - - switch (rate) { - case 192000: - ratio = WM8776_CLOCK_RATIO_128FS; - break; - case 176400: - ratio = WM8776_CLOCK_RATIO_128FS; - break; - case 96000: - ratio = WM8776_CLOCK_RATIO_256FS; - break; - case 88200: - ratio = WM8776_CLOCK_RATIO_384FS; - break; - case 48000: - ratio = WM8776_CLOCK_RATIO_512FS; - break; - case 44100: - ratio = WM8776_CLOCK_RATIO_512FS; - break; - case 32000: - ratio = WM8776_CLOCK_RATIO_768FS; - break; - case 0: - /* no hint - S/PDIF input is master, simply return */ - return; - default: - snd_BUG(); - return; - } - - /* - * this currently sets the same rate for ADC and DAC, but limits - * ADC rate to 256X (96kHz). For 256X mode (96kHz), this sets ADC - * oversampling to 64x, as recommended by WM8776 datasheet. - * Setting the rate is not really necessary in slave mode. - */ - adc_ratio = ratio; - if (adc_ratio < WM8776_CLOCK_RATIO_256FS) - adc_ratio = WM8776_CLOCK_RATIO_256FS; - - val = adc_ratio; - if (adc_ratio == WM8776_CLOCK_RATIO_256FS) - val |= 8; - val |= ratio << 4; - - mutex_lock(&chip->mutex); - for (i = 0; i < 2; i++) - wm8776_write_bits(ice, &chip->wm[i], - WM8776_REG_MASTER_MODE_CONTROL, - 0x180, val); - mutex_unlock(&chip->mutex); -} - -/* - * supported sample rates (to override the default one) - */ - -static unsigned int rates[] = { - 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000 -}; - -/* playback rates: 32..192 kHz */ -static struct snd_pcm_hw_constraint_list dac_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0 -}; - - -/* - * chip addresses on I2C bus - */ -static unsigned char wm8776_addr[2] __devinitdata = { - 0x34, 0x36, /* codec 0 & 1 */ -}; - -/* - * initialize the chip - */ -static int __devinit maya44_init(struct snd_ice1712 *ice) -{ - int i; - struct snd_maya44 *chip; - - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - mutex_init(&chip->mutex); - chip->ice = ice; - ice->spec = chip; - - /* initialise codecs */ - ice->num_total_dacs = 4; - ice->num_total_adcs = 4; - ice->akm_codecs = 0; - - for (i = 0; i < 2; i++) { - wm8776_init(ice, &chip->wm[i], wm8776_addr[i]); - wm8776_select_input(chip, i, MAYA_LINE_IN); - } - - /* set card specific rates */ - ice->hw_rates = &dac_rates; - - /* register change rate notifier */ - ice->gpio.set_pro_rate = set_rate; - - /* RDMA1 (2nd input channel) is used for ADC by default */ - ice->force_rdma1 = 1; - - /* have an own routing control */ - ice->own_routing = 1; - - return 0; -} - - -/* - * Maya44 boards don't provide the EEPROM data except for the vendor IDs. - * hence the driver needs to sets up it properly. - */ - -static unsigned char maya44_eeprom[] __devinitdata = { - [ICE_EEP2_SYSCONF] = 0x45, - /* clock xin1=49.152MHz, mpu401, 2 stereo ADCs+DACs */ - [ICE_EEP2_ACLINK] = 0x80, - /* I2S */ - [ICE_EEP2_I2S] = 0xf8, - /* vol, 96k, 24bit, 192k */ - [ICE_EEP2_SPDIF] = 0xc3, - /* enable spdif out, spdif out supp, spdif-in, ext spdif out */ - [ICE_EEP2_GPIO_DIR] = 0xff, - [ICE_EEP2_GPIO_DIR1] = 0xff, - [ICE_EEP2_GPIO_DIR2] = 0xff, - [ICE_EEP2_GPIO_MASK] = 0/*0x9f*/, - [ICE_EEP2_GPIO_MASK1] = 0/*0xff*/, - [ICE_EEP2_GPIO_MASK2] = 0/*0x7f*/, - [ICE_EEP2_GPIO_STATE] = (1 << GPIO_PHANTOM_OFF) | - (1 << GPIO_SPDIF_IN_INV), - [ICE_EEP2_GPIO_STATE1] = 0x00, - [ICE_EEP2_GPIO_STATE2] = 0x00, -}; - -/* entry point */ -struct snd_ice1712_card_info snd_vt1724_maya44_cards[] __devinitdata = { - { - .subvendor = VT1724_SUBDEVICE_MAYA44, - .name = "ESI Maya44", - .model = "maya44", - .chip_init = maya44_init, - .build_controls = maya44_add_controls, - .eeprom_size = sizeof(maya44_eeprom), - .eeprom_data = maya44_eeprom, - }, - { } /* terminator */ -}; diff --git a/trunk/sound/pci/ice1712/maya44.h b/trunk/sound/pci/ice1712/maya44.h deleted file mode 100644 index eafd03a8f4b5..000000000000 --- a/trunk/sound/pci/ice1712/maya44.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __SOUND_MAYA44_H -#define __SOUND_MAYA44_H - -#define MAYA44_DEVICE_DESC "{ESI,Maya44}," - -#define VT1724_SUBDEVICE_MAYA44 0x34315441 /* Maya44 */ - -extern struct snd_ice1712_card_info snd_vt1724_maya44_cards[]; - -#endif /* __SOUND_MAYA44_H */ diff --git a/trunk/sound/pci/intel8x0.c b/trunk/sound/pci/intel8x0.c index 8aa5687f392a..173bebf9f51d 100644 --- a/trunk/sound/pci/intel8x0.c +++ b/trunk/sound/pci/intel8x0.c @@ -356,6 +356,8 @@ struct ichdev { unsigned int position; unsigned int pos_shift; unsigned int last_pos; + unsigned long last_pos_jiffies; + unsigned int jiffy_to_bytes; int frags; int lvi; int lvi_frag; @@ -842,6 +844,7 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: val = ICH_IOCE | ICH_STARTBM; ichdev->last_pos = ichdev->position; + ichdev->last_pos_jiffies = jiffies; break; case SNDRV_PCM_TRIGGER_SUSPEND: ichdev->suspended = 1; @@ -1045,6 +1048,7 @@ static int snd_intel8x0_pcm_prepare(struct snd_pcm_substream *substream) ichdev->pos_shift = (runtime->sample_bits > 16) ? 2 : 1; } snd_intel8x0_setup_periods(chip, ichdev); + ichdev->jiffy_to_bytes = (runtime->rate * 4 * ichdev->pos_shift) / HZ; return 0; } @@ -1069,23 +1073,19 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *subs ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb)) break; } while (timeout--); - ptr = ichdev->last_pos; if (ptr1 != 0) { ptr1 <<= ichdev->pos_shift; ptr = ichdev->fragsize1 - ptr1; ptr += position; - if (ptr < ichdev->last_pos) { - unsigned int pos_base, last_base; - pos_base = position / ichdev->fragsize1; - last_base = ichdev->last_pos / ichdev->fragsize1; - /* another sanity check; ptr1 can go back to full - * before the base position is updated - */ - if (pos_base == last_base) - ptr = ichdev->last_pos; - } + ichdev->last_pos = ptr; + ichdev->last_pos_jiffies = jiffies; + } else { + ptr1 = jiffies - ichdev->last_pos_jiffies; + if (ptr1) + ptr1 -= 1; + ptr = ichdev->last_pos + ptr1 * ichdev->jiffy_to_bytes; + ptr %= ichdev->size; } - ichdev->last_pos = ptr; spin_unlock(&chip->reg_lock); if (ptr >= ichdev->size) return 0; diff --git a/trunk/sound/pci/lx6464es/Makefile b/trunk/sound/pci/lx6464es/Makefile deleted file mode 100644 index eb04a6c73d8b..000000000000 --- a/trunk/sound/pci/lx6464es/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -snd-lx6464es-objs := lx6464es.o lx_core.o -obj-$(CONFIG_SND_LX6464ES) += snd-lx6464es.o diff --git a/trunk/sound/pci/lx6464es/lx6464es.c b/trunk/sound/pci/lx6464es/lx6464es.c deleted file mode 100644 index ccf1b38c88ea..000000000000 --- a/trunk/sound/pci/lx6464es/lx6464es.c +++ /dev/null @@ -1,1159 +0,0 @@ -/* -*- linux-c -*- * - * - * ALSA driver for the digigram lx6464es interface - * - * Copyright (c) 2008, 2009 Tim Blechmann - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - */ - -#include -#include -#include -#include - -#include -#include -#include - -#include "lx6464es.h" - -MODULE_AUTHOR("Tim Blechmann"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("digigram lx6464es"); -MODULE_SUPPORTED_DEVICE("{digigram lx6464es{}}"); - - -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; -static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; - -module_param_array(index, int, NULL, 0444); -MODULE_PARM_DESC(index, "Index value for Digigram LX6464ES interface."); -module_param_array(id, charp, NULL, 0444); -MODULE_PARM_DESC(id, "ID string for Digigram LX6464ES interface."); -module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(enable, "Enable/disable specific Digigram LX6464ES soundcards."); - -static const char card_name[] = "LX6464ES"; - - -#define PCI_DEVICE_ID_PLX_LX6464ES PCI_DEVICE_ID_PLX_9056 - -static struct pci_device_id snd_lx6464es_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES), - .subvendor = PCI_VENDOR_ID_DIGIGRAM, - .subdevice = PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_SERIAL_SUBSYSTEM - }, /* LX6464ES */ - { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES), - .subvendor = PCI_VENDOR_ID_DIGIGRAM, - .subdevice = PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_CAE_SERIAL_SUBSYSTEM - }, /* LX6464ES-CAE */ - { 0, }, -}; - -MODULE_DEVICE_TABLE(pci, snd_lx6464es_ids); - - - -/* PGO pour USERo dans le registre pci_0x06/loc_0xEC */ -#define CHIPSC_RESET_XILINX (1L<<16) - - -/* alsa callbacks */ -static struct snd_pcm_hardware lx_caps = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_SYNC_START), - .formats = (SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S16_BE | - SNDRV_PCM_FMTBIT_S24_3LE | - SNDRV_PCM_FMTBIT_S24_3BE), - .rates = (SNDRV_PCM_RATE_CONTINUOUS | - SNDRV_PCM_RATE_8000_192000), - .rate_min = 8000, - .rate_max = 192000, - .channels_min = 2, - .channels_max = 64, - .buffer_bytes_max = 64*2*3*MICROBLAZE_IBL_MAX*MAX_STREAM_BUFFER, - .period_bytes_min = (2*2*MICROBLAZE_IBL_MIN*2), - .period_bytes_max = (4*64*MICROBLAZE_IBL_MAX*MAX_STREAM_BUFFER), - .periods_min = 2, - .periods_max = MAX_STREAM_BUFFER, -}; - -static int lx_set_granularity(struct lx6464es *chip, u32 gran); - - -static int lx_hardware_open(struct lx6464es *chip, - struct snd_pcm_substream *substream) -{ - int err = 0; - struct snd_pcm_runtime *runtime = substream->runtime; - int channels = runtime->channels; - int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); - - snd_pcm_uframes_t period_size = runtime->period_size; - - snd_printd(LXP "allocating pipe for %d channels\n", channels); - err = lx_pipe_allocate(chip, 0, is_capture, channels); - if (err < 0) { - snd_printk(KERN_ERR LXP "allocating pipe failed\n"); - return err; - } - - err = lx_set_granularity(chip, period_size); - if (err < 0) { - snd_printk(KERN_ERR LXP "setting granularity to %ld failed\n", - period_size); - return err; - } - - return 0; -} - -static int lx_hardware_start(struct lx6464es *chip, - struct snd_pcm_substream *substream) -{ - int err = 0; - struct snd_pcm_runtime *runtime = substream->runtime; - int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); - - snd_printd(LXP "setting stream format\n"); - err = lx_stream_set_format(chip, runtime, 0, is_capture); - if (err < 0) { - snd_printk(KERN_ERR LXP "setting stream format failed\n"); - return err; - } - - snd_printd(LXP "starting pipe\n"); - err = lx_pipe_start(chip, 0, is_capture); - if (err < 0) { - snd_printk(KERN_ERR LXP "starting pipe failed\n"); - return err; - } - - snd_printd(LXP "waiting for pipe to start\n"); - err = lx_pipe_wait_for_start(chip, 0, is_capture); - if (err < 0) { - snd_printk(KERN_ERR LXP "waiting for pipe failed\n"); - return err; - } - - return err; -} - - -static int lx_hardware_stop(struct lx6464es *chip, - struct snd_pcm_substream *substream) -{ - int err = 0; - int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); - - snd_printd(LXP "pausing pipe\n"); - err = lx_pipe_pause(chip, 0, is_capture); - if (err < 0) { - snd_printk(KERN_ERR LXP "pausing pipe failed\n"); - return err; - } - - snd_printd(LXP "waiting for pipe to become idle\n"); - err = lx_pipe_wait_for_idle(chip, 0, is_capture); - if (err < 0) { - snd_printk(KERN_ERR LXP "waiting for pipe failed\n"); - return err; - } - - snd_printd(LXP "stopping pipe\n"); - err = lx_pipe_stop(chip, 0, is_capture); - if (err < 0) { - snd_printk(LXP "stopping pipe failed\n"); - return err; - } - - return err; -} - - -static int lx_hardware_close(struct lx6464es *chip, - struct snd_pcm_substream *substream) -{ - int err = 0; - int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); - - snd_printd(LXP "releasing pipe\n"); - err = lx_pipe_release(chip, 0, is_capture); - if (err < 0) { - snd_printk(LXP "releasing pipe failed\n"); - return err; - } - - return err; -} - - -static int lx_pcm_open(struct snd_pcm_substream *substream) -{ - struct lx6464es *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - int err = 0; - int board_rate; - - snd_printdd("->lx_pcm_open\n"); - mutex_lock(&chip->setup_mutex); - - /* copy the struct snd_pcm_hardware struct */ - runtime->hw = lx_caps; - -#if 0 - /* buffer-size should better be multiple of period-size */ - err = snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - if (err < 0) { - snd_printk(KERN_WARNING LXP "could not constrain periods\n"); - goto exit; - } -#endif - - /* the clock rate cannot be changed */ - board_rate = chip->board_sample_rate; - err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE, - board_rate, board_rate); - - if (err < 0) { - snd_printk(KERN_WARNING LXP "could not constrain periods\n"); - goto exit; - } - - /* constrain period size */ - err = snd_pcm_hw_constraint_minmax(runtime, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, - MICROBLAZE_IBL_MIN, - MICROBLAZE_IBL_MAX); - if (err < 0) { - snd_printk(KERN_WARNING LXP - "could not constrain period size\n"); - goto exit; - } - - snd_pcm_hw_constraint_step(runtime, 0, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32); - - snd_pcm_set_sync(substream); - err = 0; - -exit: - runtime->private_data = chip; - - mutex_unlock(&chip->setup_mutex); - snd_printdd("<-lx_pcm_open, %d\n", err); - return err; -} - -static int lx_pcm_close(struct snd_pcm_substream *substream) -{ - int err = 0; - snd_printdd("->lx_pcm_close\n"); - return err; -} - -static snd_pcm_uframes_t lx_pcm_stream_pointer(struct snd_pcm_substream - *substream) -{ - struct lx6464es *chip = snd_pcm_substream_chip(substream); - snd_pcm_uframes_t pos; - unsigned long flags; - int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); - - struct lx_stream *lx_stream = is_capture ? &chip->capture_stream : - &chip->playback_stream; - - snd_printdd("->lx_pcm_stream_pointer\n"); - - spin_lock_irqsave(&chip->lock, flags); - pos = lx_stream->frame_pos * substream->runtime->period_size; - spin_unlock_irqrestore(&chip->lock, flags); - - snd_printdd(LXP "stream_pointer at %ld\n", pos); - return pos; -} - -static int lx_pcm_prepare(struct snd_pcm_substream *substream) -{ - struct lx6464es *chip = snd_pcm_substream_chip(substream); - int err = 0; - const int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); - - snd_printdd("->lx_pcm_prepare\n"); - - mutex_lock(&chip->setup_mutex); - - if (chip->hardware_running[is_capture]) { - err = lx_hardware_stop(chip, substream); - if (err < 0) { - snd_printk(KERN_ERR LXP "failed to stop hardware. " - "Error code %d\n", err); - goto exit; - } - - err = lx_hardware_close(chip, substream); - if (err < 0) { - snd_printk(KERN_ERR LXP "failed to close hardware. " - "Error code %d\n", err); - goto exit; - } - } - - snd_printd(LXP "opening hardware\n"); - err = lx_hardware_open(chip, substream); - if (err < 0) { - snd_printk(KERN_ERR LXP "failed to open hardware. " - "Error code %d\n", err); - goto exit; - } - - err = lx_hardware_start(chip, substream); - if (err < 0) { - snd_printk(KERN_ERR LXP "failed to start hardware. " - "Error code %d\n", err); - goto exit; - } - - chip->hardware_running[is_capture] = 1; - - if (chip->board_sample_rate != substream->runtime->rate) { - if (!err) - chip->board_sample_rate = substream->runtime->rate; - } - -exit: - mutex_unlock(&chip->setup_mutex); - return err; -} - -static int lx_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params, int is_capture) -{ - struct lx6464es *chip = snd_pcm_substream_chip(substream); - int err = 0; - - snd_printdd("->lx_pcm_hw_params\n"); - - mutex_lock(&chip->setup_mutex); - - /* set dma buffer */ - err = snd_pcm_lib_malloc_pages(substream, - params_buffer_bytes(hw_params)); - - if (is_capture) - chip->capture_stream.stream = substream; - else - chip->playback_stream.stream = substream; - - mutex_unlock(&chip->setup_mutex); - return err; -} - -static int lx_pcm_hw_params_playback(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - return lx_pcm_hw_params(substream, hw_params, 0); -} - -static int lx_pcm_hw_params_capture(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - return lx_pcm_hw_params(substream, hw_params, 1); -} - -static int lx_pcm_hw_free(struct snd_pcm_substream *substream) -{ - struct lx6464es *chip = snd_pcm_substream_chip(substream); - int err = 0; - int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); - - snd_printdd("->lx_pcm_hw_free\n"); - mutex_lock(&chip->setup_mutex); - - if (chip->hardware_running[is_capture]) { - err = lx_hardware_stop(chip, substream); - if (err < 0) { - snd_printk(KERN_ERR LXP "failed to stop hardware. " - "Error code %d\n", err); - goto exit; - } - - err = lx_hardware_close(chip, substream); - if (err < 0) { - snd_printk(KERN_ERR LXP "failed to close hardware. " - "Error code %d\n", err); - goto exit; - } - - chip->hardware_running[is_capture] = 0; - } - - err = snd_pcm_lib_free_pages(substream); - - if (is_capture) - chip->capture_stream.stream = 0; - else - chip->playback_stream.stream = 0; - -exit: - mutex_unlock(&chip->setup_mutex); - return err; -} - -static void lx_trigger_start(struct lx6464es *chip, struct lx_stream *lx_stream) -{ - struct snd_pcm_substream *substream = lx_stream->stream; - const int is_capture = lx_stream->is_capture; - - int err; - - const u32 channels = substream->runtime->channels; - const u32 bytes_per_frame = channels * 3; - const u32 period_size = substream->runtime->period_size; - const u32 periods = substream->runtime->periods; - const u32 period_bytes = period_size * bytes_per_frame; - - dma_addr_t buf = substream->dma_buffer.addr; - int i; - - u32 needed, freed; - u32 size_array[5]; - - for (i = 0; i != periods; ++i) { - u32 buffer_index = 0; - - err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, - size_array); - snd_printdd(LXP "starting: needed %d, freed %d\n", - needed, freed); - - err = lx_buffer_give(chip, 0, is_capture, period_bytes, - lower_32_bits(buf), upper_32_bits(buf), - &buffer_index); - - snd_printdd(LXP "starting: buffer index %x on %p (%d bytes)\n", - buffer_index, (void *)buf, period_bytes); - buf += period_bytes; - } - - err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array); - snd_printdd(LXP "starting: needed %d, freed %d\n", needed, freed); - - snd_printd(LXP "starting: starting stream\n"); - err = lx_stream_start(chip, 0, is_capture); - if (err < 0) - snd_printk(KERN_ERR LXP "couldn't start stream\n"); - else - lx_stream->status = LX_STREAM_STATUS_RUNNING; - - lx_stream->frame_pos = 0; -} - -static void lx_trigger_stop(struct lx6464es *chip, struct lx_stream *lx_stream) -{ - const int is_capture = lx_stream->is_capture; - int err; - - snd_printd(LXP "stopping: stopping stream\n"); - err = lx_stream_stop(chip, 0, is_capture); - if (err < 0) - snd_printk(KERN_ERR LXP "couldn't stop stream\n"); - else - lx_stream->status = LX_STREAM_STATUS_FREE; - -} - -static void lx_trigger_tasklet_dispatch_stream(struct lx6464es *chip, - struct lx_stream *lx_stream) -{ - switch (lx_stream->status) { - case LX_STREAM_STATUS_SCHEDULE_RUN: - lx_trigger_start(chip, lx_stream); - break; - - case LX_STREAM_STATUS_SCHEDULE_STOP: - lx_trigger_stop(chip, lx_stream); - break; - - default: - break; - } -} - -static void lx_trigger_tasklet(unsigned long data) -{ - struct lx6464es *chip = (struct lx6464es *)data; - unsigned long flags; - - snd_printdd("->lx_trigger_tasklet\n"); - - spin_lock_irqsave(&chip->lock, flags); - lx_trigger_tasklet_dispatch_stream(chip, &chip->capture_stream); - lx_trigger_tasklet_dispatch_stream(chip, &chip->playback_stream); - spin_unlock_irqrestore(&chip->lock, flags); -} - -static int lx_pcm_trigger_dispatch(struct lx6464es *chip, - struct lx_stream *lx_stream, int cmd) -{ - int err = 0; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - lx_stream->status = LX_STREAM_STATUS_SCHEDULE_RUN; - break; - - case SNDRV_PCM_TRIGGER_STOP: - lx_stream->status = LX_STREAM_STATUS_SCHEDULE_STOP; - break; - - default: - err = -EINVAL; - goto exit; - } - tasklet_schedule(&chip->trigger_tasklet); - -exit: - return err; -} - - -static int lx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct lx6464es *chip = snd_pcm_substream_chip(substream); - const int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); - struct lx_stream *stream = is_capture ? &chip->capture_stream : - &chip->playback_stream; - - snd_printdd("->lx_pcm_trigger\n"); - - return lx_pcm_trigger_dispatch(chip, stream, cmd); -} - -static int snd_lx6464es_free(struct lx6464es *chip) -{ - snd_printdd("->snd_lx6464es_free\n"); - - lx_irq_disable(chip); - - if (chip->irq >= 0) - free_irq(chip->irq, chip); - - iounmap(chip->port_dsp_bar); - ioport_unmap(chip->port_plx_remapped); - - pci_release_regions(chip->pci); - pci_disable_device(chip->pci); - - kfree(chip); - - return 0; -} - -static int snd_lx6464es_dev_free(struct snd_device *device) -{ - return snd_lx6464es_free(device->device_data); -} - -/* reset the dsp during initialization */ -static int __devinit lx_init_xilinx_reset(struct lx6464es *chip) -{ - int i; - u32 plx_reg = lx_plx_reg_read(chip, ePLX_CHIPSC); - - snd_printdd("->lx_init_xilinx_reset\n"); - - /* activate reset of xilinx */ - plx_reg &= ~CHIPSC_RESET_XILINX; - - lx_plx_reg_write(chip, ePLX_CHIPSC, plx_reg); - msleep(1); - - lx_plx_reg_write(chip, ePLX_MBOX3, 0); - msleep(1); - - plx_reg |= CHIPSC_RESET_XILINX; - lx_plx_reg_write(chip, ePLX_CHIPSC, plx_reg); - - /* deactivate reset of xilinx */ - for (i = 0; i != 100; ++i) { - u32 reg_mbox3; - msleep(10); - reg_mbox3 = lx_plx_reg_read(chip, ePLX_MBOX3); - if (reg_mbox3) { - snd_printd(LXP "xilinx reset done\n"); - snd_printdd(LXP "xilinx took %d loops\n", i); - break; - } - } - - /* todo: add some error handling? */ - - /* clear mr */ - lx_dsp_reg_write(chip, eReg_CSM, 0); - - /* le xilinx ES peut ne pas etre encore pret, on attend. */ - msleep(600); - - return 0; -} - -static int __devinit lx_init_xilinx_test(struct lx6464es *chip) -{ - u32 reg; - - snd_printdd("->lx_init_xilinx_test\n"); - - /* TEST if we have access to Xilinx/MicroBlaze */ - lx_dsp_reg_write(chip, eReg_CSM, 0); - - reg = lx_dsp_reg_read(chip, eReg_CSM); - - if (reg) { - snd_printk(KERN_ERR LXP "Problem: Reg_CSM %x.\n", reg); - - /* PCI9056_SPACE0_REMAP */ - lx_plx_reg_write(chip, ePLX_PCICR, 1); - - reg = lx_dsp_reg_read(chip, eReg_CSM); - if (reg) { - snd_printk(KERN_ERR LXP "Error: Reg_CSM %x.\n", reg); - return -EAGAIN; /* seems to be appropriate */ - } - } - - snd_printd(LXP "Xilinx/MicroBlaze access test successful\n"); - - return 0; -} - -/* initialize ethersound */ -static int __devinit lx_init_ethersound_config(struct lx6464es *chip) -{ - int i; - u32 orig_conf_es = lx_dsp_reg_read(chip, eReg_CONFES); - - u32 default_conf_es = (64 << IOCR_OUTPUTS_OFFSET) | - (64 << IOCR_INPUTS_OFFSET) | - (FREQ_RATIO_SINGLE_MODE << FREQ_RATIO_OFFSET); - - u32 conf_es = (orig_conf_es & CONFES_READ_PART_MASK) - | (default_conf_es & CONFES_WRITE_PART_MASK); - - snd_printdd("->lx_init_ethersound\n"); - - chip->freq_ratio = FREQ_RATIO_SINGLE_MODE; - - /* - * write it to the card ! - * this actually kicks the ES xilinx, the first time since poweron. - * the MAC address in the Reg_ADMACESMSB Reg_ADMACESLSB registers - * is not ready before this is done, and the bit 2 in Reg_CSES is set. - * */ - lx_dsp_reg_write(chip, eReg_CONFES, conf_es); - - for (i = 0; i != 1000; ++i) { - if (lx_dsp_reg_read(chip, eReg_CSES) & 4) { - snd_printd(LXP "ethersound initialized after %dms\n", - i); - goto ethersound_initialized; - } - msleep(1); - } - snd_printk(KERN_WARNING LXP - "ethersound could not be initialized after %dms\n", i); - return -ETIMEDOUT; - - ethersound_initialized: - snd_printd(LXP "ethersound initialized\n"); - return 0; -} - -static int __devinit lx_init_get_version_features(struct lx6464es *chip) -{ - u32 dsp_version; - - int err; - - snd_printdd("->lx_init_get_version_features\n"); - - err = lx_dsp_get_version(chip, &dsp_version); - - if (err == 0) { - u32 freq; - - snd_printk(LXP "DSP version: V%02d.%02d #%d\n", - (dsp_version>>16) & 0xff, (dsp_version>>8) & 0xff, - dsp_version & 0xff); - - /* later: what firmware version do we expect? */ - - /* retrieve Play/Rec features */ - /* done here because we may have to handle alternate - * DSP files. */ - /* later */ - - /* init the EtherSound sample rate */ - err = lx_dsp_get_clock_frequency(chip, &freq); - if (err == 0) - chip->board_sample_rate = freq; - snd_printd(LXP "actual clock frequency %d\n", freq); - } else { - snd_printk(KERN_ERR LXP "DSP corrupted \n"); - err = -EAGAIN; - } - - return err; -} - -static int lx_set_granularity(struct lx6464es *chip, u32 gran) -{ - int err = 0; - u32 snapped_gran = MICROBLAZE_IBL_MIN; - - snd_printdd("->lx_set_granularity\n"); - - /* blocksize is a power of 2 */ - while ((snapped_gran < gran) && - (snapped_gran < MICROBLAZE_IBL_MAX)) { - snapped_gran *= 2; - } - - if (snapped_gran == chip->pcm_granularity) - return 0; - - err = lx_dsp_set_granularity(chip, snapped_gran); - if (err < 0) { - snd_printk(KERN_WARNING LXP "could not set granularity\n"); - err = -EAGAIN; - } - - if (snapped_gran != gran) - snd_printk(LXP "snapped blocksize to %d\n", snapped_gran); - - snd_printd(LXP "set blocksize on board %d\n", snapped_gran); - chip->pcm_granularity = snapped_gran; - - return err; -} - -/* initialize and test the xilinx dsp chip */ -static int __devinit lx_init_dsp(struct lx6464es *chip) -{ - int err; - u8 mac_address[6]; - int i; - - snd_printdd("->lx_init_dsp\n"); - - snd_printd(LXP "initialize board\n"); - err = lx_init_xilinx_reset(chip); - if (err) - return err; - - snd_printd(LXP "testing board\n"); - err = lx_init_xilinx_test(chip); - if (err) - return err; - - snd_printd(LXP "initialize ethersound configuration\n"); - err = lx_init_ethersound_config(chip); - if (err) - return err; - - lx_irq_enable(chip); - - /** \todo the mac address should be ready by not, but it isn't, - * so we wait for it */ - for (i = 0; i != 1000; ++i) { - err = lx_dsp_get_mac(chip, mac_address); - if (err) - return err; - if (mac_address[0] || mac_address[1] || mac_address[2] || - mac_address[3] || mac_address[4] || mac_address[5]) - goto mac_ready; - msleep(1); - } - return -ETIMEDOUT; - -mac_ready: - snd_printd(LXP "mac address ready read after: %dms\n", i); - snd_printk(LXP "mac address: %02X.%02X.%02X.%02X.%02X.%02X\n", - mac_address[0], mac_address[1], mac_address[2], - mac_address[3], mac_address[4], mac_address[5]); - - err = lx_init_get_version_features(chip); - if (err) - return err; - - lx_set_granularity(chip, MICROBLAZE_IBL_DEFAULT); - - chip->playback_mute = 0; - - return err; -} - -static struct snd_pcm_ops lx_ops_playback = { - .open = lx_pcm_open, - .close = lx_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .prepare = lx_pcm_prepare, - .hw_params = lx_pcm_hw_params_playback, - .hw_free = lx_pcm_hw_free, - .trigger = lx_pcm_trigger, - .pointer = lx_pcm_stream_pointer, -}; - -static struct snd_pcm_ops lx_ops_capture = { - .open = lx_pcm_open, - .close = lx_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .prepare = lx_pcm_prepare, - .hw_params = lx_pcm_hw_params_capture, - .hw_free = lx_pcm_hw_free, - .trigger = lx_pcm_trigger, - .pointer = lx_pcm_stream_pointer, -}; - -static int __devinit lx_pcm_create(struct lx6464es *chip) -{ - int err; - struct snd_pcm *pcm; - - u32 size = 64 * /* channels */ - 3 * /* 24 bit samples */ - MAX_STREAM_BUFFER * /* periods */ - MICROBLAZE_IBL_MAX * /* frames per period */ - 2; /* duplex */ - - size = PAGE_ALIGN(size); - - /* hardcoded device name & channel count */ - err = snd_pcm_new(chip->card, (char *)card_name, 0, - 1, 1, &pcm); - - pcm->private_data = chip; - - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &lx_ops_playback); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &lx_ops_capture); - - pcm->info_flags = 0; - strcpy(pcm->name, card_name); - - err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), - size, size); - if (err < 0) - return err; - - chip->pcm = pcm; - chip->capture_stream.is_capture = 1; - - return 0; -} - -static int lx_control_playback_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} - -static int lx_control_playback_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct lx6464es *chip = snd_kcontrol_chip(kcontrol); - ucontrol->value.integer.value[0] = chip->playback_mute; - return 0; -} - -static int lx_control_playback_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct lx6464es *chip = snd_kcontrol_chip(kcontrol); - int changed = 0; - int current_value = chip->playback_mute; - - if (current_value != ucontrol->value.integer.value[0]) { - lx_level_unmute(chip, 0, !current_value); - chip->playback_mute = !current_value; - changed = 1; - } - return changed; -} - -static struct snd_kcontrol_new lx_control_playback_switch __devinitdata = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Switch", - .index = 0, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .private_value = 0, - .info = lx_control_playback_info, - .get = lx_control_playback_get, - .put = lx_control_playback_put -}; - - - -static void lx_proc_levels_read(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - u32 levels[64]; - int err; - int i, j; - struct lx6464es *chip = entry->private_data; - - snd_iprintf(buffer, "capture levels:\n"); - err = lx_level_peaks(chip, 1, 64, levels); - if (err < 0) - return; - - for (i = 0; i != 8; ++i) { - for (j = 0; j != 8; ++j) - snd_iprintf(buffer, "%08x ", levels[i*8+j]); - snd_iprintf(buffer, "\n"); - } - - snd_iprintf(buffer, "\nplayback levels:\n"); - - err = lx_level_peaks(chip, 0, 64, levels); - if (err < 0) - return; - - for (i = 0; i != 8; ++i) { - for (j = 0; j != 8; ++j) - snd_iprintf(buffer, "%08x ", levels[i*8+j]); - snd_iprintf(buffer, "\n"); - } - - snd_iprintf(buffer, "\n"); -} - -static int __devinit lx_proc_create(struct snd_card *card, struct lx6464es *chip) -{ - struct snd_info_entry *entry; - int err = snd_card_proc_new(card, "levels", &entry); - if (err < 0) - return err; - - snd_info_set_text_ops(entry, chip, lx_proc_levels_read); - return 0; -} - - -static int __devinit snd_lx6464es_create(struct snd_card *card, - struct pci_dev *pci, - struct lx6464es **rchip) -{ - struct lx6464es *chip; - int err; - - static struct snd_device_ops ops = { - .dev_free = snd_lx6464es_dev_free, - }; - - snd_printdd("->snd_lx6464es_create\n"); - - *rchip = NULL; - - /* enable PCI device */ - err = pci_enable_device(pci); - if (err < 0) - return err; - - pci_set_master(pci); - - /* check if we can restrict PCI DMA transfers to 32 bits */ - err = pci_set_dma_mask(pci, DMA_32BIT_MASK); - if (err < 0) { - snd_printk(KERN_ERR "architecture does not support " - "32bit PCI busmaster DMA\n"); - pci_disable_device(pci); - return -ENXIO; - } - - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (chip == NULL) { - err = -ENOMEM; - goto alloc_failed; - } - - chip->card = card; - chip->pci = pci; - chip->irq = -1; - - /* initialize synchronization structs */ - spin_lock_init(&chip->lock); - spin_lock_init(&chip->msg_lock); - mutex_init(&chip->setup_mutex); - tasklet_init(&chip->trigger_tasklet, lx_trigger_tasklet, - (unsigned long)chip); - tasklet_init(&chip->tasklet_capture, lx_tasklet_capture, - (unsigned long)chip); - tasklet_init(&chip->tasklet_playback, lx_tasklet_playback, - (unsigned long)chip); - - /* request resources */ - err = pci_request_regions(pci, card_name); - if (err < 0) - goto request_regions_failed; - - /* plx port */ - chip->port_plx = pci_resource_start(pci, 1); - chip->port_plx_remapped = ioport_map(chip->port_plx, - pci_resource_len(pci, 1)); - - /* dsp port */ - chip->port_dsp_bar = pci_ioremap_bar(pci, 2); - - err = request_irq(pci->irq, lx_interrupt, IRQF_SHARED, - card_name, chip); - if (err) { - snd_printk(KERN_ERR LXP "unable to grab IRQ %d\n", pci->irq); - goto request_irq_failed; - } - chip->irq = pci->irq; - - err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); - if (err < 0) - goto device_new_failed; - - err = lx_init_dsp(chip); - if (err < 0) { - snd_printk(KERN_ERR LXP "error during DSP initialization\n"); - return err; - } - - err = lx_pcm_create(chip); - if (err < 0) - return err; - - err = lx_proc_create(card, chip); - if (err < 0) - return err; - - err = snd_ctl_add(card, snd_ctl_new1(&lx_control_playback_switch, - chip)); - if (err < 0) - return err; - - snd_card_set_dev(card, &pci->dev); - - *rchip = chip; - return 0; - -device_new_failed: - free_irq(pci->irq, chip); - -request_irq_failed: - pci_release_regions(pci); - -request_regions_failed: - kfree(chip); - -alloc_failed: - pci_disable_device(pci); - - return err; -} - -static int __devinit snd_lx6464es_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) -{ - static int dev; - struct snd_card *card; - struct lx6464es *chip; - int err; - - snd_printdd("->snd_lx6464es_probe\n"); - - if (dev >= SNDRV_CARDS) - return -ENODEV; - if (!enable[dev]) { - dev++; - return -ENOENT; - } - - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); - if (err < 0) - return err; - - err = snd_lx6464es_create(card, pci, &chip); - if (err < 0) { - snd_printk(KERN_ERR LXP "error during snd_lx6464es_create\n"); - goto out_free; - } - - strcpy(card->driver, "lx6464es"); - strcpy(card->shortname, "Digigram LX6464ES"); - sprintf(card->longname, "%s at 0x%lx, 0x%p, irq %i", - card->shortname, chip->port_plx, - chip->port_dsp_bar, chip->irq); - - err = snd_card_register(card); - if (err < 0) - goto out_free; - - snd_printdd(LXP "initialization successful\n"); - pci_set_drvdata(pci, card); - dev++; - return 0; - -out_free: - snd_card_free(card); - return err; - -} - -static void __devexit snd_lx6464es_remove(struct pci_dev *pci) -{ - snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); -} - - -static struct pci_driver driver = { - .name = "Digigram LX6464ES", - .id_table = snd_lx6464es_ids, - .probe = snd_lx6464es_probe, - .remove = __devexit_p(snd_lx6464es_remove), -}; - - -/* module initialization */ -static int __init mod_init(void) -{ - return pci_register_driver(&driver); -} - -static void __exit mod_exit(void) -{ - pci_unregister_driver(&driver); -} - -module_init(mod_init); -module_exit(mod_exit); diff --git a/trunk/sound/pci/lx6464es/lx6464es.h b/trunk/sound/pci/lx6464es/lx6464es.h deleted file mode 100644 index 012c010c8c89..000000000000 --- a/trunk/sound/pci/lx6464es/lx6464es.h +++ /dev/null @@ -1,114 +0,0 @@ -/* -*- linux-c -*- * - * - * ALSA driver for the digigram lx6464es interface - * - * Copyright (c) 2009 Tim Blechmann - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - */ - -#ifndef LX6464ES_H -#define LX6464ES_H - -#include -#include - -#include -#include - -#include "lx_core.h" - -#define LXP "LX6464ES: " - -enum { - ES_cmd_free = 0, /* no command executing */ - ES_cmd_processing = 1, /* execution of a read/write command */ - ES_read_pending = 2, /* a asynchron read command is pending */ - ES_read_finishing = 3, /* a read command has finished waiting (set by - * Interrupt or CancelIrp) */ -}; - -enum lx_stream_status { - LX_STREAM_STATUS_FREE, -/* LX_STREAM_STATUS_OPEN, */ - LX_STREAM_STATUS_SCHEDULE_RUN, -/* LX_STREAM_STATUS_STARTED, */ - LX_STREAM_STATUS_RUNNING, - LX_STREAM_STATUS_SCHEDULE_STOP, -/* LX_STREAM_STATUS_STOPPED, */ -/* LX_STREAM_STATUS_PAUSED */ -}; - - -struct lx_stream { - struct snd_pcm_substream *stream; - snd_pcm_uframes_t frame_pos; - enum lx_stream_status status; /* free, open, running, draining - * pause */ - int is_capture:1; -}; - - -struct lx6464es { - struct snd_card *card; - struct pci_dev *pci; - int irq; - - spinlock_t lock; /* interrupt spinlock */ - struct mutex setup_mutex; /* mutex used in hw_params, open - * and close */ - - struct tasklet_struct trigger_tasklet; /* trigger tasklet */ - struct tasklet_struct tasklet_capture; - struct tasklet_struct tasklet_playback; - - /* ports */ - unsigned long port_plx; /* io port (size=256) */ - void __iomem *port_plx_remapped; /* remapped plx port */ - void __iomem *port_dsp_bar; /* memory port (32-bit, - * non-prefetchable, - * size=8K) */ - - /* messaging */ - spinlock_t msg_lock; /* message spinlock */ - atomic_t send_message_locked; - struct lx_rmh rmh; - - /* configuration */ - uint freq_ratio : 2; - uint playback_mute : 1; - uint hardware_running[2]; - u32 board_sample_rate; /* sample rate read from - * board */ - u32 sample_rate; /* our sample rate */ - u16 pcm_granularity; /* board blocksize */ - - /* dma */ - struct snd_dma_buffer capture_dma_buf; - struct snd_dma_buffer playback_dma_buf; - - /* pcm */ - struct snd_pcm *pcm; - - /* streams */ - struct lx_stream capture_stream; - struct lx_stream playback_stream; -}; - - -#endif /* LX6464ES_H */ diff --git a/trunk/sound/pci/lx6464es/lx_core.c b/trunk/sound/pci/lx6464es/lx_core.c deleted file mode 100644 index 5812780d6e89..000000000000 --- a/trunk/sound/pci/lx6464es/lx_core.c +++ /dev/null @@ -1,1444 +0,0 @@ -/* -*- linux-c -*- * - * - * ALSA driver for the digigram lx6464es interface - * low-level interface - * - * Copyright (c) 2009 Tim Blechmann - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - */ - -/* #define RMH_DEBUG 1 */ - -#include -#include -#include - -#include "lx6464es.h" -#include "lx_core.h" - -/* low-level register access */ - -static const unsigned long dsp_port_offsets[] = { - 0, - 0x400, - 0x401, - 0x402, - 0x403, - 0x404, - 0x405, - 0x406, - 0x407, - 0x408, - 0x409, - 0x40a, - 0x40b, - 0x40c, - - 0x410, - 0x411, - 0x412, - 0x413, - 0x414, - 0x415, - 0x416, - - 0x420, - 0x430, - 0x431, - 0x432, - 0x433, - 0x434, - 0x440 -}; - -static void __iomem *lx_dsp_register(struct lx6464es *chip, int port) -{ - void __iomem *base_address = chip->port_dsp_bar; - return base_address + dsp_port_offsets[port]*4; -} - -unsigned long lx_dsp_reg_read(struct lx6464es *chip, int port) -{ - void __iomem *address = lx_dsp_register(chip, port); - return ioread32(address); -} - -void lx_dsp_reg_readbuf(struct lx6464es *chip, int port, u32 *data, u32 len) -{ - void __iomem *address = lx_dsp_register(chip, port); - memcpy_fromio(data, address, len*sizeof(u32)); -} - - -void lx_dsp_reg_write(struct lx6464es *chip, int port, unsigned data) -{ - void __iomem *address = lx_dsp_register(chip, port); - iowrite32(data, address); -} - -void lx_dsp_reg_writebuf(struct lx6464es *chip, int port, const u32 *data, - u32 len) -{ - void __iomem *address = lx_dsp_register(chip, port); - memcpy_toio(address, data, len*sizeof(u32)); -} - - -static const unsigned long plx_port_offsets[] = { - 0x04, - 0x40, - 0x44, - 0x48, - 0x4c, - 0x50, - 0x54, - 0x58, - 0x5c, - 0x64, - 0x68, - 0x6C -}; - -static void __iomem *lx_plx_register(struct lx6464es *chip, int port) -{ - void __iomem *base_address = chip->port_plx_remapped; - return base_address + plx_port_offsets[port]; -} - -unsigned long lx_plx_reg_read(struct lx6464es *chip, int port) -{ - void __iomem *address = lx_plx_register(chip, port); - return ioread32(address); -} - -void lx_plx_reg_write(struct lx6464es *chip, int port, u32 data) -{ - void __iomem *address = lx_plx_register(chip, port); - iowrite32(data, address); -} - -u32 lx_plx_mbox_read(struct lx6464es *chip, int mbox_nr) -{ - int index; - - switch (mbox_nr) { - case 1: - index = ePLX_MBOX1; break; - case 2: - index = ePLX_MBOX2; break; - case 3: - index = ePLX_MBOX3; break; - case 4: - index = ePLX_MBOX4; break; - case 5: - index = ePLX_MBOX5; break; - case 6: - index = ePLX_MBOX6; break; - case 7: - index = ePLX_MBOX7; break; - case 0: /* reserved for HF flags */ - snd_BUG(); - default: - return 0xdeadbeef; - } - - return lx_plx_reg_read(chip, index); -} - -int lx_plx_mbox_write(struct lx6464es *chip, int mbox_nr, u32 value) -{ - int index = -1; - - switch (mbox_nr) { - case 1: - index = ePLX_MBOX1; break; - case 3: - index = ePLX_MBOX3; break; - case 4: - index = ePLX_MBOX4; break; - case 5: - index = ePLX_MBOX5; break; - case 6: - index = ePLX_MBOX6; break; - case 7: - index = ePLX_MBOX7; break; - case 0: /* reserved for HF flags */ - case 2: /* reserved for Pipe States - * the DSP keeps an image of it */ - snd_BUG(); - return -EBADRQC; - } - - lx_plx_reg_write(chip, index, value); - return 0; -} - - -/* rmh */ - -#ifdef CONFIG_SND_DEBUG -#define CMD_NAME(a) a -#else -#define CMD_NAME(a) NULL -#endif - -#define Reg_CSM_MR 0x00000002 -#define Reg_CSM_MC 0x00000001 - -struct dsp_cmd_info { - u32 dcCodeOp; /* Op Code of the command (usually 1st 24-bits - * word).*/ - u16 dcCmdLength; /* Command length in words of 24 bits.*/ - u16 dcStatusType; /* Status type: 0 for fixed length, 1 for - * random. */ - u16 dcStatusLength; /* Status length (if fixed).*/ - char *dcOpName; -}; - -/* - Initialization and control data for the Microblaze interface - - OpCode: - the opcode field of the command set at the proper offset - - CmdLength - the number of command words - - StatusType - offset in the status registers: 0 means that the return value may be - different from 0, and must be read - - StatusLength - the number of status words (in addition to the return value) -*/ - -static struct dsp_cmd_info dsp_commands[] = -{ - { (CMD_00_INFO_DEBUG << OPCODE_OFFSET) , 1 /*custom*/ - , 1 , 0 /**/ , CMD_NAME("INFO_DEBUG") }, - { (CMD_01_GET_SYS_CFG << OPCODE_OFFSET) , 1 /**/ - , 1 , 2 /**/ , CMD_NAME("GET_SYS_CFG") }, - { (CMD_02_SET_GRANULARITY << OPCODE_OFFSET) , 1 /**/ - , 1 , 0 /**/ , CMD_NAME("SET_GRANULARITY") }, - { (CMD_03_SET_TIMER_IRQ << OPCODE_OFFSET) , 1 /**/ - , 1 , 0 /**/ , CMD_NAME("SET_TIMER_IRQ") }, - { (CMD_04_GET_EVENT << OPCODE_OFFSET) , 1 /**/ - , 1 , 0 /*up to 10*/ , CMD_NAME("GET_EVENT") }, - { (CMD_05_GET_PIPES << OPCODE_OFFSET) , 1 /**/ - , 1 , 2 /*up to 4*/ , CMD_NAME("GET_PIPES") }, - { (CMD_06_ALLOCATE_PIPE << OPCODE_OFFSET) , 1 /**/ - , 0 , 0 /**/ , CMD_NAME("ALLOCATE_PIPE") }, - { (CMD_07_RELEASE_PIPE << OPCODE_OFFSET) , 1 /**/ - , 0 , 0 /**/ , CMD_NAME("RELEASE_PIPE") }, - { (CMD_08_ASK_BUFFERS << OPCODE_OFFSET) , 1 /**/ - , 1 , MAX_STREAM_BUFFER , CMD_NAME("ASK_BUFFERS") }, - { (CMD_09_STOP_PIPE << OPCODE_OFFSET) , 1 /**/ - , 0 , 0 /*up to 2*/ , CMD_NAME("STOP_PIPE") }, - { (CMD_0A_GET_PIPE_SPL_COUNT << OPCODE_OFFSET) , 1 /**/ - , 1 , 1 /*up to 2*/ , CMD_NAME("GET_PIPE_SPL_COUNT") }, - { (CMD_0B_TOGGLE_PIPE_STATE << OPCODE_OFFSET) , 1 /*up to 5*/ - , 1 , 0 /**/ , CMD_NAME("TOGGLE_PIPE_STATE") }, - { (CMD_0C_DEF_STREAM << OPCODE_OFFSET) , 1 /*up to 4*/ - , 1 , 0 /**/ , CMD_NAME("DEF_STREAM") }, - { (CMD_0D_SET_MUTE << OPCODE_OFFSET) , 3 /**/ - , 1 , 0 /**/ , CMD_NAME("SET_MUTE") }, - { (CMD_0E_GET_STREAM_SPL_COUNT << OPCODE_OFFSET) , 1/**/ - , 1 , 2 /**/ , CMD_NAME("GET_STREAM_SPL_COUNT") }, - { (CMD_0F_UPDATE_BUFFER << OPCODE_OFFSET) , 3 /*up to 4*/ - , 0 , 1 /**/ , CMD_NAME("UPDATE_BUFFER") }, - { (CMD_10_GET_BUFFER << OPCODE_OFFSET) , 1 /**/ - , 1 , 4 /**/ , CMD_NAME("GET_BUFFER") }, - { (CMD_11_CANCEL_BUFFER << OPCODE_OFFSET) , 1 /**/ - , 1 , 1 /*up to 4*/ , CMD_NAME("CANCEL_BUFFER") }, - { (CMD_12_GET_PEAK << OPCODE_OFFSET) , 1 /**/ - , 1 , 1 /**/ , CMD_NAME("GET_PEAK") }, - { (CMD_13_SET_STREAM_STATE << OPCODE_OFFSET) , 1 /**/ - , 1 , 0 /**/ , CMD_NAME("SET_STREAM_STATE") }, -}; - -static void lx_message_init(struct lx_rmh *rmh, enum cmd_mb_opcodes cmd) -{ - snd_BUG_ON(cmd >= CMD_14_INVALID); - - rmh->cmd[0] = dsp_commands[cmd].dcCodeOp; - rmh->cmd_len = dsp_commands[cmd].dcCmdLength; - rmh->stat_len = dsp_commands[cmd].dcStatusLength; - rmh->dsp_stat = dsp_commands[cmd].dcStatusType; - rmh->cmd_idx = cmd; - memset(&rmh->cmd[1], 0, (REG_CRM_NUMBER - 1) * sizeof(u32)); - -#ifdef CONFIG_SND_DEBUG - memset(rmh->stat, 0, REG_CRM_NUMBER * sizeof(u32)); -#endif -#ifdef RMH_DEBUG - rmh->cmd_idx = cmd; -#endif -} - -#ifdef RMH_DEBUG -#define LXRMH "lx6464es rmh: " -static void lx_message_dump(struct lx_rmh *rmh) -{ - u8 idx = rmh->cmd_idx; - int i; - - snd_printk(LXRMH "command %s\n", dsp_commands[idx].dcOpName); - - for (i = 0; i != rmh->cmd_len; ++i) - snd_printk(LXRMH "\tcmd[%d] %08x\n", i, rmh->cmd[i]); - - for (i = 0; i != rmh->stat_len; ++i) - snd_printk(LXRMH "\tstat[%d]: %08x\n", i, rmh->stat[i]); - snd_printk("\n"); -} -#else -static inline void lx_message_dump(struct lx_rmh *rmh) -{} -#endif - - - -/* sleep 500 - 100 = 400 times 100us -> the timeout is >= 40 ms */ -#define XILINX_TIMEOUT_MS 40 -#define XILINX_POLL_NO_SLEEP 100 -#define XILINX_POLL_ITERATIONS 150 - -#if 0 /* not used now */ -static int lx_message_send(struct lx6464es *chip, struct lx_rmh *rmh) -{ - u32 reg = ED_DSP_TIMED_OUT; - int dwloop; - int answer_received; - - if (lx_dsp_reg_read(chip, eReg_CSM) & (Reg_CSM_MC | Reg_CSM_MR)) { - snd_printk(KERN_ERR LXP "PIOSendMessage eReg_CSM %x\n", reg); - return -EBUSY; - } - - /* write command */ - lx_dsp_reg_writebuf(chip, eReg_CRM1, rmh->cmd, rmh->cmd_len); - - snd_BUG_ON(atomic_read(&chip->send_message_locked) != 0); - atomic_set(&chip->send_message_locked, 1); - - /* MicoBlaze gogogo */ - lx_dsp_reg_write(chip, eReg_CSM, Reg_CSM_MC); - - /* wait for interrupt to answer */ - for (dwloop = 0; dwloop != XILINX_TIMEOUT_MS; ++dwloop) { - answer_received = atomic_read(&chip->send_message_locked); - if (answer_received == 0) - break; - msleep(1); - } - - if (answer_received == 0) { - /* in Debug mode verify Reg_CSM_MR */ - snd_BUG_ON(!(lx_dsp_reg_read(chip, eReg_CSM) & Reg_CSM_MR)); - - /* command finished, read status */ - if (rmh->dsp_stat == 0) - reg = lx_dsp_reg_read(chip, eReg_CRM1); - else - reg = 0; - } else { - int i; - snd_printk(KERN_WARNING LXP "TIMEOUT lx_message_send! " - "Interrupts disabled?\n"); - - /* attente bit Reg_CSM_MR */ - for (i = 0; i != XILINX_POLL_ITERATIONS; i++) { - if ((lx_dsp_reg_read(chip, eReg_CSM) & Reg_CSM_MR)) { - if (rmh->dsp_stat == 0) - reg = lx_dsp_reg_read(chip, eReg_CRM1); - else - reg = 0; - goto polling_successful; - } - - if (i > XILINX_POLL_NO_SLEEP) - msleep(1); - } - snd_printk(KERN_WARNING LXP "TIMEOUT lx_message_send! " - "polling failed\n"); - -polling_successful: - atomic_set(&chip->send_message_locked, 0); - } - - if ((reg & ERROR_VALUE) == 0) { - /* read response */ - if (rmh->stat_len) { - snd_BUG_ON(rmh->stat_len >= (REG_CRM_NUMBER-1)); - - lx_dsp_reg_readbuf(chip, eReg_CRM2, rmh->stat, - rmh->stat_len); - } - } else - snd_printk(KERN_WARNING LXP "lx_message_send: error_value %x\n", - reg); - - /* clear Reg_CSM_MR */ - lx_dsp_reg_write(chip, eReg_CSM, 0); - - switch (reg) { - case ED_DSP_TIMED_OUT: - snd_printk(KERN_WARNING LXP "lx_message_send: dsp timeout\n"); - return -ETIMEDOUT; - - case ED_DSP_CRASHED: - snd_printk(KERN_WARNING LXP "lx_message_send: dsp crashed\n"); - return -EAGAIN; - } - - lx_message_dump(rmh); - return 0; -} -#endif /* not used now */ - -static int lx_message_send_atomic(struct lx6464es *chip, struct lx_rmh *rmh) -{ - u32 reg = ED_DSP_TIMED_OUT; - int dwloop; - - if (lx_dsp_reg_read(chip, eReg_CSM) & (Reg_CSM_MC | Reg_CSM_MR)) { - snd_printk(KERN_ERR LXP "PIOSendMessage eReg_CSM %x\n", reg); - return -EBUSY; - } - - /* write command */ - lx_dsp_reg_writebuf(chip, eReg_CRM1, rmh->cmd, rmh->cmd_len); - - /* MicoBlaze gogogo */ - lx_dsp_reg_write(chip, eReg_CSM, Reg_CSM_MC); - - /* wait for interrupt to answer */ - for (dwloop = 0; dwloop != XILINX_TIMEOUT_MS * 1000; ++dwloop) { - if (lx_dsp_reg_read(chip, eReg_CSM) & Reg_CSM_MR) { - if (rmh->dsp_stat == 0) - reg = lx_dsp_reg_read(chip, eReg_CRM1); - else - reg = 0; - goto polling_successful; - } else - udelay(1); - } - snd_printk(KERN_WARNING LXP "TIMEOUT lx_message_send_atomic! " - "polling failed\n"); - -polling_successful: - if ((reg & ERROR_VALUE) == 0) { - /* read response */ - if (rmh->stat_len) { - snd_BUG_ON(rmh->stat_len >= (REG_CRM_NUMBER-1)); - lx_dsp_reg_readbuf(chip, eReg_CRM2, rmh->stat, - rmh->stat_len); - } - } else - snd_printk(LXP "rmh error: %08x\n", reg); - - /* clear Reg_CSM_MR */ - lx_dsp_reg_write(chip, eReg_CSM, 0); - - switch (reg) { - case ED_DSP_TIMED_OUT: - snd_printk(KERN_WARNING LXP "lx_message_send: dsp timeout\n"); - return -ETIMEDOUT; - - case ED_DSP_CRASHED: - snd_printk(KERN_WARNING LXP "lx_message_send: dsp crashed\n"); - return -EAGAIN; - } - - lx_message_dump(rmh); - - return reg; -} - - -/* low-level dsp access */ -int __devinit lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version) -{ - u16 ret; - unsigned long flags; - - spin_lock_irqsave(&chip->msg_lock, flags); - - lx_message_init(&chip->rmh, CMD_01_GET_SYS_CFG); - ret = lx_message_send_atomic(chip, &chip->rmh); - - *rdsp_version = chip->rmh.stat[1]; - spin_unlock_irqrestore(&chip->msg_lock, flags); - return ret; -} - -int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq) -{ - u16 ret = 0; - unsigned long flags; - u32 freq_raw = 0; - u32 freq = 0; - u32 frequency = 0; - - spin_lock_irqsave(&chip->msg_lock, flags); - - lx_message_init(&chip->rmh, CMD_01_GET_SYS_CFG); - ret = lx_message_send_atomic(chip, &chip->rmh); - - if (ret == 0) { - freq_raw = chip->rmh.stat[0] >> FREQ_FIELD_OFFSET; - freq = freq_raw & XES_FREQ_COUNT8_MASK; - - if ((freq < XES_FREQ_COUNT8_48_MAX) || - (freq > XES_FREQ_COUNT8_44_MIN)) - frequency = 0; /* unknown */ - else if (freq >= XES_FREQ_COUNT8_44_MAX) - frequency = 44100; - else - frequency = 48000; - } - - spin_unlock_irqrestore(&chip->msg_lock, flags); - - *rfreq = frequency * chip->freq_ratio; - - return ret; -} - -int lx_dsp_get_mac(struct lx6464es *chip, u8 *mac_address) -{ - u32 macmsb, maclsb; - - macmsb = lx_dsp_reg_read(chip, eReg_ADMACESMSB) & 0x00FFFFFF; - maclsb = lx_dsp_reg_read(chip, eReg_ADMACESLSB) & 0x00FFFFFF; - - /* todo: endianess handling */ - mac_address[5] = ((u8 *)(&maclsb))[0]; - mac_address[4] = ((u8 *)(&maclsb))[1]; - mac_address[3] = ((u8 *)(&maclsb))[2]; - mac_address[2] = ((u8 *)(&macmsb))[0]; - mac_address[1] = ((u8 *)(&macmsb))[1]; - mac_address[0] = ((u8 *)(&macmsb))[2]; - - return 0; -} - - -int lx_dsp_set_granularity(struct lx6464es *chip, u32 gran) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&chip->msg_lock, flags); - - lx_message_init(&chip->rmh, CMD_02_SET_GRANULARITY); - chip->rmh.cmd[0] |= gran; - - ret = lx_message_send_atomic(chip, &chip->rmh); - spin_unlock_irqrestore(&chip->msg_lock, flags); - return ret; -} - -int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&chip->msg_lock, flags); - - lx_message_init(&chip->rmh, CMD_04_GET_EVENT); - chip->rmh.stat_len = 9; /* we don't necessarily need the full length */ - - ret = lx_message_send_atomic(chip, &chip->rmh); - - if (!ret) - memcpy(data, chip->rmh.stat, chip->rmh.stat_len * sizeof(u32)); - - spin_unlock_irqrestore(&chip->msg_lock, flags); - return ret; -} - -#define CSES_TIMEOUT 100 /* microseconds */ -#define CSES_CE 0x0001 -#define CSES_BROADCAST 0x0002 -#define CSES_UPDATE_LDSV 0x0004 - -int lx_dsp_es_check_pipeline(struct lx6464es *chip) -{ - int i; - - for (i = 0; i != CSES_TIMEOUT; ++i) { - /* - * le bit CSES_UPDATE_LDSV est à 1 dés que le macprog - * est pret. il re-passe à 0 lorsque le premier read a - * été fait. pour l'instant on retire le test car ce bit - * passe a 1 environ 200 à 400 ms aprés que le registre - * confES à été écrit (kick du xilinx ES). - * - * On ne teste que le bit CE. - * */ - - u32 cses = lx_dsp_reg_read(chip, eReg_CSES); - - if ((cses & CSES_CE) == 0) - return 0; - - udelay(1); - } - - return -ETIMEDOUT; -} - - -#define PIPE_INFO_TO_CMD(capture, pipe) \ - ((u32)((u32)(pipe) | ((capture) ? ID_IS_CAPTURE : 0L)) << ID_OFFSET) - - - -/* low-level pipe handling */ -int lx_pipe_allocate(struct lx6464es *chip, u32 pipe, int is_capture, - int channels) -{ - int err; - unsigned long flags; - - u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - - spin_lock_irqsave(&chip->msg_lock, flags); - lx_message_init(&chip->rmh, CMD_06_ALLOCATE_PIPE); - - chip->rmh.cmd[0] |= pipe_cmd; - chip->rmh.cmd[0] |= channels; - - err = lx_message_send_atomic(chip, &chip->rmh); - spin_unlock_irqrestore(&chip->msg_lock, flags); - - if (err != 0) - snd_printk(KERN_ERR "lx6464es: could not allocate pipe\n"); - - return err; -} - -int lx_pipe_release(struct lx6464es *chip, u32 pipe, int is_capture) -{ - int err; - unsigned long flags; - - u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - - spin_lock_irqsave(&chip->msg_lock, flags); - lx_message_init(&chip->rmh, CMD_07_RELEASE_PIPE); - - chip->rmh.cmd[0] |= pipe_cmd; - - err = lx_message_send_atomic(chip, &chip->rmh); - spin_unlock_irqrestore(&chip->msg_lock, flags); - - return err; -} - -int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture, - u32 *r_needed, u32 *r_freed, u32 *size_array) -{ - int err; - unsigned long flags; - - u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - -#ifdef CONFIG_SND_DEBUG - if (size_array) - memset(size_array, 0, sizeof(u32)*MAX_STREAM_BUFFER); -#endif - - *r_needed = 0; - *r_freed = 0; - - spin_lock_irqsave(&chip->msg_lock, flags); - lx_message_init(&chip->rmh, CMD_08_ASK_BUFFERS); - - chip->rmh.cmd[0] |= pipe_cmd; - - err = lx_message_send_atomic(chip, &chip->rmh); - - if (!err) { - int i; - for (i = 0; i < MAX_STREAM_BUFFER; ++i) { - u32 stat = chip->rmh.stat[i]; - if (stat & (BF_EOB << BUFF_FLAGS_OFFSET)) { - /* finished */ - *r_freed += 1; - if (size_array) - size_array[i] = stat & MASK_DATA_SIZE; - } else if ((stat & (BF_VALID << BUFF_FLAGS_OFFSET)) - == 0) - /* free */ - *r_needed += 1; - } - -#if 0 - snd_printdd(LXP "CMD_08_ASK_BUFFERS: needed %d, freed %d\n", - *r_needed, *r_freed); - for (i = 0; i < MAX_STREAM_BUFFER; ++i) { - for (i = 0; i != chip->rmh.stat_len; ++i) - snd_printdd(" stat[%d]: %x, %x\n", i, - chip->rmh.stat[i], - chip->rmh.stat[i] & MASK_DATA_SIZE); - } -#endif - } - - spin_unlock_irqrestore(&chip->msg_lock, flags); - return err; -} - - -int lx_pipe_stop(struct lx6464es *chip, u32 pipe, int is_capture) -{ - int err; - unsigned long flags; - - u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - - spin_lock_irqsave(&chip->msg_lock, flags); - lx_message_init(&chip->rmh, CMD_09_STOP_PIPE); - - chip->rmh.cmd[0] |= pipe_cmd; - - err = lx_message_send_atomic(chip, &chip->rmh); - - spin_unlock_irqrestore(&chip->msg_lock, flags); - return err; -} - -static int lx_pipe_toggle_state(struct lx6464es *chip, u32 pipe, int is_capture) -{ - int err; - unsigned long flags; - - u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - - spin_lock_irqsave(&chip->msg_lock, flags); - lx_message_init(&chip->rmh, CMD_0B_TOGGLE_PIPE_STATE); - - chip->rmh.cmd[0] |= pipe_cmd; - - err = lx_message_send_atomic(chip, &chip->rmh); - - spin_unlock_irqrestore(&chip->msg_lock, flags); - return err; -} - - -int lx_pipe_start(struct lx6464es *chip, u32 pipe, int is_capture) -{ - int err; - - err = lx_pipe_wait_for_idle(chip, pipe, is_capture); - if (err < 0) - return err; - - err = lx_pipe_toggle_state(chip, pipe, is_capture); - - return err; -} - -int lx_pipe_pause(struct lx6464es *chip, u32 pipe, int is_capture) -{ - int err = 0; - - err = lx_pipe_wait_for_start(chip, pipe, is_capture); - if (err < 0) - return err; - - err = lx_pipe_toggle_state(chip, pipe, is_capture); - - return err; -} - - -int lx_pipe_sample_count(struct lx6464es *chip, u32 pipe, int is_capture, - u64 *rsample_count) -{ - int err; - unsigned long flags; - - u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - - spin_lock_irqsave(&chip->msg_lock, flags); - lx_message_init(&chip->rmh, CMD_0A_GET_PIPE_SPL_COUNT); - - chip->rmh.cmd[0] |= pipe_cmd; - chip->rmh.stat_len = 2; /* need all words here! */ - - err = lx_message_send_atomic(chip, &chip->rmh); /* don't sleep! */ - - if (err != 0) - snd_printk(KERN_ERR - "lx6464es: could not query pipe's sample count\n"); - else { - *rsample_count = ((u64)(chip->rmh.stat[0] & MASK_SPL_COUNT_HI) - << 24) /* hi part */ - + chip->rmh.stat[1]; /* lo part */ - } - - spin_unlock_irqrestore(&chip->msg_lock, flags); - return err; -} - -int lx_pipe_state(struct lx6464es *chip, u32 pipe, int is_capture, u16 *rstate) -{ - int err; - unsigned long flags; - - u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - - spin_lock_irqsave(&chip->msg_lock, flags); - lx_message_init(&chip->rmh, CMD_0A_GET_PIPE_SPL_COUNT); - - chip->rmh.cmd[0] |= pipe_cmd; - - err = lx_message_send_atomic(chip, &chip->rmh); - - if (err != 0) - snd_printk(KERN_ERR "lx6464es: could not query pipe's state\n"); - else - *rstate = (chip->rmh.stat[0] >> PSTATE_OFFSET) & 0x0F; - - spin_unlock_irqrestore(&chip->msg_lock, flags); - return err; -} - -static int lx_pipe_wait_for_state(struct lx6464es *chip, u32 pipe, - int is_capture, u16 state) -{ - int i; - - /* max 2*PCMOnlyGranularity = 2*1024 at 44100 = < 50 ms: - * timeout 50 ms */ - for (i = 0; i != 50; ++i) { - u16 current_state; - int err = lx_pipe_state(chip, pipe, is_capture, ¤t_state); - - if (err < 0) - return err; - - if (current_state == state) - return 0; - - mdelay(1); - } - - return -ETIMEDOUT; -} - -int lx_pipe_wait_for_start(struct lx6464es *chip, u32 pipe, int is_capture) -{ - return lx_pipe_wait_for_state(chip, pipe, is_capture, PSTATE_RUN); -} - -int lx_pipe_wait_for_idle(struct lx6464es *chip, u32 pipe, int is_capture) -{ - return lx_pipe_wait_for_state(chip, pipe, is_capture, PSTATE_IDLE); -} - -/* low-level stream handling */ -int lx_stream_set_state(struct lx6464es *chip, u32 pipe, - int is_capture, enum stream_state_t state) -{ - int err; - unsigned long flags; - - u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - - spin_lock_irqsave(&chip->msg_lock, flags); - lx_message_init(&chip->rmh, CMD_13_SET_STREAM_STATE); - - chip->rmh.cmd[0] |= pipe_cmd; - chip->rmh.cmd[0] |= state; - - err = lx_message_send_atomic(chip, &chip->rmh); - spin_unlock_irqrestore(&chip->msg_lock, flags); - - return err; -} - -int lx_stream_set_format(struct lx6464es *chip, struct snd_pcm_runtime *runtime, - u32 pipe, int is_capture) -{ - int err; - unsigned long flags; - - u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - - u32 channels = runtime->channels; - - if (runtime->channels != channels) - snd_printk(KERN_ERR LXP "channel count mismatch: %d vs %d", - runtime->channels, channels); - - spin_lock_irqsave(&chip->msg_lock, flags); - lx_message_init(&chip->rmh, CMD_0C_DEF_STREAM); - - chip->rmh.cmd[0] |= pipe_cmd; - - if (runtime->sample_bits == 16) - /* 16 bit format */ - chip->rmh.cmd[0] |= (STREAM_FMT_16b << STREAM_FMT_OFFSET); - - if (snd_pcm_format_little_endian(runtime->format)) - /* little endian/intel format */ - chip->rmh.cmd[0] |= (STREAM_FMT_intel << STREAM_FMT_OFFSET); - - chip->rmh.cmd[0] |= channels-1; - - err = lx_message_send_atomic(chip, &chip->rmh); - spin_unlock_irqrestore(&chip->msg_lock, flags); - - return err; -} - -int lx_stream_state(struct lx6464es *chip, u32 pipe, int is_capture, - int *rstate) -{ - int err; - unsigned long flags; - - u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - - spin_lock_irqsave(&chip->msg_lock, flags); - lx_message_init(&chip->rmh, CMD_0E_GET_STREAM_SPL_COUNT); - - chip->rmh.cmd[0] |= pipe_cmd; - - err = lx_message_send_atomic(chip, &chip->rmh); - - *rstate = (chip->rmh.stat[0] & SF_START) ? START_STATE : PAUSE_STATE; - - spin_unlock_irqrestore(&chip->msg_lock, flags); - return err; -} - -int lx_stream_sample_position(struct lx6464es *chip, u32 pipe, int is_capture, - u64 *r_bytepos) -{ - int err; - unsigned long flags; - - u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - - spin_lock_irqsave(&chip->msg_lock, flags); - lx_message_init(&chip->rmh, CMD_0E_GET_STREAM_SPL_COUNT); - - chip->rmh.cmd[0] |= pipe_cmd; - - err = lx_message_send_atomic(chip, &chip->rmh); - - *r_bytepos = ((u64) (chip->rmh.stat[0] & MASK_SPL_COUNT_HI) - << 32) /* hi part */ - + chip->rmh.stat[1]; /* lo part */ - - spin_unlock_irqrestore(&chip->msg_lock, flags); - return err; -} - -/* low-level buffer handling */ -int lx_buffer_give(struct lx6464es *chip, u32 pipe, int is_capture, - u32 buffer_size, u32 buf_address_lo, u32 buf_address_hi, - u32 *r_buffer_index) -{ - int err; - unsigned long flags; - - u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - - spin_lock_irqsave(&chip->msg_lock, flags); - lx_message_init(&chip->rmh, CMD_0F_UPDATE_BUFFER); - - chip->rmh.cmd[0] |= pipe_cmd; - chip->rmh.cmd[0] |= BF_NOTIFY_EOB; /* request interrupt notification */ - - /* todo: pause request, circular buffer */ - - chip->rmh.cmd[1] = buffer_size & MASK_DATA_SIZE; - chip->rmh.cmd[2] = buf_address_lo; - - if (buf_address_hi) { - chip->rmh.cmd_len = 4; - chip->rmh.cmd[3] = buf_address_hi; - chip->rmh.cmd[0] |= BF_64BITS_ADR; - } - - err = lx_message_send_atomic(chip, &chip->rmh); - - if (err == 0) { - *r_buffer_index = chip->rmh.stat[0]; - goto done; - } - - if (err == EB_RBUFFERS_TABLE_OVERFLOW) - snd_printk(LXP "lx_buffer_give EB_RBUFFERS_TABLE_OVERFLOW\n"); - - if (err == EB_INVALID_STREAM) - snd_printk(LXP "lx_buffer_give EB_INVALID_STREAM\n"); - - if (err == EB_CMD_REFUSED) - snd_printk(LXP "lx_buffer_give EB_CMD_REFUSED\n"); - - done: - spin_unlock_irqrestore(&chip->msg_lock, flags); - return err; -} - -int lx_buffer_free(struct lx6464es *chip, u32 pipe, int is_capture, - u32 *r_buffer_size) -{ - int err; - unsigned long flags; - - u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - - spin_lock_irqsave(&chip->msg_lock, flags); - lx_message_init(&chip->rmh, CMD_11_CANCEL_BUFFER); - - chip->rmh.cmd[0] |= pipe_cmd; - chip->rmh.cmd[0] |= MASK_BUFFER_ID; /* ask for the current buffer: the - * microblaze will seek for it */ - - err = lx_message_send_atomic(chip, &chip->rmh); - - if (err == 0) - *r_buffer_size = chip->rmh.stat[0] & MASK_DATA_SIZE; - - spin_unlock_irqrestore(&chip->msg_lock, flags); - return err; -} - -int lx_buffer_cancel(struct lx6464es *chip, u32 pipe, int is_capture, - u32 buffer_index) -{ - int err; - unsigned long flags; - - u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - - spin_lock_irqsave(&chip->msg_lock, flags); - lx_message_init(&chip->rmh, CMD_11_CANCEL_BUFFER); - - chip->rmh.cmd[0] |= pipe_cmd; - chip->rmh.cmd[0] |= buffer_index; - - err = lx_message_send_atomic(chip, &chip->rmh); - - spin_unlock_irqrestore(&chip->msg_lock, flags); - return err; -} - - -/* low-level gain/peak handling - * - * \todo: can we unmute capture/playback channels independently? - * - * */ -int lx_level_unmute(struct lx6464es *chip, int is_capture, int unmute) -{ - int err; - unsigned long flags; - - /* bit set to 1: channel muted */ - u64 mute_mask = unmute ? 0 : 0xFFFFFFFFFFFFFFFFLLU; - - spin_lock_irqsave(&chip->msg_lock, flags); - lx_message_init(&chip->rmh, CMD_0D_SET_MUTE); - - chip->rmh.cmd[0] |= PIPE_INFO_TO_CMD(is_capture, 0); - - chip->rmh.cmd[1] = (u32)(mute_mask >> (u64)32); /* hi part */ - chip->rmh.cmd[2] = (u32)(mute_mask & (u64)0xFFFFFFFF); /* lo part */ - - snd_printk("mute %x %x %x\n", chip->rmh.cmd[0], chip->rmh.cmd[1], - chip->rmh.cmd[2]); - - err = lx_message_send_atomic(chip, &chip->rmh); - - spin_unlock_irqrestore(&chip->msg_lock, flags); - return err; -} - -static u32 peak_map[] = { - 0x00000109, /* -90.308dB */ - 0x0000083B, /* -72.247dB */ - 0x000020C4, /* -60.205dB */ - 0x00008273, /* -48.030dB */ - 0x00020756, /* -36.005dB */ - 0x00040C37, /* -30.001dB */ - 0x00081385, /* -24.002dB */ - 0x00101D3F, /* -18.000dB */ - 0x0016C310, /* -15.000dB */ - 0x002026F2, /* -12.001dB */ - 0x002D6A86, /* -9.000dB */ - 0x004026E6, /* -6.004dB */ - 0x005A9DF6, /* -3.000dB */ - 0x0065AC8B, /* -2.000dB */ - 0x00721481, /* -1.000dB */ - 0x007FFFFF, /* FS */ -}; - -int lx_level_peaks(struct lx6464es *chip, int is_capture, int channels, - u32 *r_levels) -{ - int err = 0; - unsigned long flags; - int i; - spin_lock_irqsave(&chip->msg_lock, flags); - - for (i = 0; i < channels; i += 4) { - u32 s0, s1, s2, s3; - - lx_message_init(&chip->rmh, CMD_12_GET_PEAK); - chip->rmh.cmd[0] |= PIPE_INFO_TO_CMD(is_capture, i); - - err = lx_message_send_atomic(chip, &chip->rmh); - - if (err == 0) { - s0 = peak_map[chip->rmh.stat[0] & 0x0F]; - s1 = peak_map[(chip->rmh.stat[0] >> 4) & 0xf]; - s2 = peak_map[(chip->rmh.stat[0] >> 8) & 0xf]; - s3 = peak_map[(chip->rmh.stat[0] >> 12) & 0xf]; - } else - s0 = s1 = s2 = s3 = 0; - - r_levels[0] = s0; - r_levels[1] = s1; - r_levels[2] = s2; - r_levels[3] = s3; - - r_levels += 4; - } - - spin_unlock_irqrestore(&chip->msg_lock, flags); - return err; -} - -/* interrupt handling */ -#define PCX_IRQ_NONE 0 -#define IRQCS_ACTIVE_PCIDB 0x00002000L /* Bit nø 13 */ -#define IRQCS_ENABLE_PCIIRQ 0x00000100L /* Bit nø 08 */ -#define IRQCS_ENABLE_PCIDB 0x00000200L /* Bit nø 09 */ - -static u32 lx_interrupt_test_ack(struct lx6464es *chip) -{ - u32 irqcs = lx_plx_reg_read(chip, ePLX_IRQCS); - - /* Test if PCI Doorbell interrupt is active */ - if (irqcs & IRQCS_ACTIVE_PCIDB) { - u32 temp; - irqcs = PCX_IRQ_NONE; - - while ((temp = lx_plx_reg_read(chip, ePLX_L2PCIDB))) { - /* RAZ interrupt */ - irqcs |= temp; - lx_plx_reg_write(chip, ePLX_L2PCIDB, temp); - } - - return irqcs; - } - return PCX_IRQ_NONE; -} - -static int lx_interrupt_ack(struct lx6464es *chip, u32 *r_irqsrc, - int *r_async_pending, int *r_async_escmd) -{ - u32 irq_async; - u32 irqsrc = lx_interrupt_test_ack(chip); - - if (irqsrc == PCX_IRQ_NONE) - return 0; - - *r_irqsrc = irqsrc; - - irq_async = irqsrc & MASK_SYS_ASYNC_EVENTS; /* + EtherSound response - * (set by xilinx) + EOB */ - - if (irq_async & MASK_SYS_STATUS_ESA) { - irq_async &= ~MASK_SYS_STATUS_ESA; - *r_async_escmd = 1; - } - - if (irqsrc & MASK_SYS_STATUS_CMD_DONE) - /* xilinx command notification */ - atomic_set(&chip->send_message_locked, 0); - - if (irq_async) { - /* snd_printd("interrupt: async event pending\n"); */ - *r_async_pending = 1; - } - - return 1; -} - -static int lx_interrupt_handle_async_events(struct lx6464es *chip, u32 irqsrc, - int *r_freq_changed, - u64 *r_notified_in_pipe_mask, - u64 *r_notified_out_pipe_mask) -{ - int err; - u32 stat[9]; /* answer from CMD_04_GET_EVENT */ - - /* On peut optimiser pour ne pas lire les evenements vides - * les mots de réponse sont dans l'ordre suivant : - * Stat[0] mot de status général - * Stat[1] fin de buffer OUT pF - * Stat[2] fin de buffer OUT pf - * Stat[3] fin de buffer IN pF - * Stat[4] fin de buffer IN pf - * Stat[5] underrun poid fort - * Stat[6] underrun poid faible - * Stat[7] overrun poid fort - * Stat[8] overrun poid faible - * */ - - u64 orun_mask; - u64 urun_mask; -#if 0 - int has_underrun = (irqsrc & MASK_SYS_STATUS_URUN) ? 1 : 0; - int has_overrun = (irqsrc & MASK_SYS_STATUS_ORUN) ? 1 : 0; -#endif - int eb_pending_out = (irqsrc & MASK_SYS_STATUS_EOBO) ? 1 : 0; - int eb_pending_in = (irqsrc & MASK_SYS_STATUS_EOBI) ? 1 : 0; - - *r_freq_changed = (irqsrc & MASK_SYS_STATUS_FREQ) ? 1 : 0; - - err = lx_dsp_read_async_events(chip, stat); - if (err < 0) - return err; - - if (eb_pending_in) { - *r_notified_in_pipe_mask = ((u64)stat[3] << 32) - + stat[4]; - snd_printdd(LXP "interrupt: EOBI pending %llx\n", - *r_notified_in_pipe_mask); - } - if (eb_pending_out) { - *r_notified_out_pipe_mask = ((u64)stat[1] << 32) - + stat[2]; - snd_printdd(LXP "interrupt: EOBO pending %llx\n", - *r_notified_out_pipe_mask); - } - - orun_mask = ((u64)stat[7] << 32) + stat[8]; - urun_mask = ((u64)stat[5] << 32) + stat[6]; - - /* todo: handle xrun notification */ - - return err; -} - -static int lx_interrupt_request_new_buffer(struct lx6464es *chip, - struct lx_stream *lx_stream) -{ - struct snd_pcm_substream *substream = lx_stream->stream; - int is_capture = lx_stream->is_capture; - int err; - unsigned long flags; - - const u32 channels = substream->runtime->channels; - const u32 bytes_per_frame = channels * 3; - const u32 period_size = substream->runtime->period_size; - const u32 period_bytes = period_size * bytes_per_frame; - const u32 pos = lx_stream->frame_pos; - const u32 next_pos = ((pos+1) == substream->runtime->periods) ? - 0 : pos + 1; - - dma_addr_t buf = substream->dma_buffer.addr + pos * period_bytes; - u32 buf_hi = 0; - u32 buf_lo = 0; - u32 buffer_index = 0; - - u32 needed, freed; - u32 size_array[MAX_STREAM_BUFFER]; - - snd_printdd("->lx_interrupt_request_new_buffer\n"); - - spin_lock_irqsave(&chip->lock, flags); - - err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array); - snd_printdd(LXP "interrupt: needed %d, freed %d\n", needed, freed); - - unpack_pointer(buf, &buf_lo, &buf_hi); - err = lx_buffer_give(chip, 0, is_capture, period_bytes, buf_lo, buf_hi, - &buffer_index); - snd_printdd(LXP "interrupt: gave buffer index %x on %p (%d bytes)\n", - buffer_index, (void *)buf, period_bytes); - - lx_stream->frame_pos = next_pos; - spin_unlock_irqrestore(&chip->lock, flags); - - return err; -} - -void lx_tasklet_playback(unsigned long data) -{ - struct lx6464es *chip = (struct lx6464es *)data; - struct lx_stream *lx_stream = &chip->playback_stream; - int err; - - snd_printdd("->lx_tasklet_playback\n"); - - err = lx_interrupt_request_new_buffer(chip, lx_stream); - if (err < 0) - snd_printk(KERN_ERR LXP - "cannot request new buffer for playback\n"); - - snd_pcm_period_elapsed(lx_stream->stream); -} - -void lx_tasklet_capture(unsigned long data) -{ - struct lx6464es *chip = (struct lx6464es *)data; - struct lx_stream *lx_stream = &chip->capture_stream; - int err; - - snd_printdd("->lx_tasklet_capture\n"); - err = lx_interrupt_request_new_buffer(chip, lx_stream); - if (err < 0) - snd_printk(KERN_ERR LXP - "cannot request new buffer for capture\n"); - - snd_pcm_period_elapsed(lx_stream->stream); -} - - - -static int lx_interrupt_handle_audio_transfer(struct lx6464es *chip, - u64 notified_in_pipe_mask, - u64 notified_out_pipe_mask) -{ - int err = 0; - - if (notified_in_pipe_mask) { - snd_printdd(LXP "requesting audio transfer for capture\n"); - tasklet_hi_schedule(&chip->tasklet_capture); - } - - if (notified_out_pipe_mask) { - snd_printdd(LXP "requesting audio transfer for playback\n"); - tasklet_hi_schedule(&chip->tasklet_playback); - } - - return err; -} - - -irqreturn_t lx_interrupt(int irq, void *dev_id) -{ - struct lx6464es *chip = dev_id; - int async_pending, async_escmd; - u32 irqsrc; - - spin_lock(&chip->lock); - - snd_printdd("**************************************************\n"); - - if (!lx_interrupt_ack(chip, &irqsrc, &async_pending, &async_escmd)) { - spin_unlock(&chip->lock); - snd_printdd("IRQ_NONE\n"); - return IRQ_NONE; /* this device did not cause the interrupt */ - } - - if (irqsrc & MASK_SYS_STATUS_CMD_DONE) - goto exit; - -#if 0 - if (irqsrc & MASK_SYS_STATUS_EOBI) - snd_printdd(LXP "interrupt: EOBI\n"); - - if (irqsrc & MASK_SYS_STATUS_EOBO) - snd_printdd(LXP "interrupt: EOBO\n"); - - if (irqsrc & MASK_SYS_STATUS_URUN) - snd_printdd(LXP "interrupt: URUN\n"); - - if (irqsrc & MASK_SYS_STATUS_ORUN) - snd_printdd(LXP "interrupt: ORUN\n"); -#endif - - if (async_pending) { - u64 notified_in_pipe_mask = 0; - u64 notified_out_pipe_mask = 0; - int freq_changed; - int err; - - /* handle async events */ - err = lx_interrupt_handle_async_events(chip, irqsrc, - &freq_changed, - ¬ified_in_pipe_mask, - ¬ified_out_pipe_mask); - if (err) - snd_printk(KERN_ERR LXP - "error handling async events\n"); - - err = lx_interrupt_handle_audio_transfer(chip, - notified_in_pipe_mask, - notified_out_pipe_mask - ); - if (err) - snd_printk(KERN_ERR LXP - "error during audio transfer\n"); - } - - if (async_escmd) { -#if 0 - /* backdoor for ethersound commands - * - * for now, we do not need this - * - * */ - - snd_printdd("lx6464es: interrupt requests escmd handling\n"); -#endif - } - -exit: - spin_unlock(&chip->lock); - return IRQ_HANDLED; /* this device caused the interrupt */ -} - - -static void lx_irq_set(struct lx6464es *chip, int enable) -{ - u32 reg = lx_plx_reg_read(chip, ePLX_IRQCS); - - /* enable/disable interrupts - * - * Set the Doorbell and PCI interrupt enable bits - * - * */ - if (enable) - reg |= (IRQCS_ENABLE_PCIIRQ | IRQCS_ENABLE_PCIDB); - else - reg &= ~(IRQCS_ENABLE_PCIIRQ | IRQCS_ENABLE_PCIDB); - lx_plx_reg_write(chip, ePLX_IRQCS, reg); -} - -void lx_irq_enable(struct lx6464es *chip) -{ - snd_printdd("->lx_irq_enable\n"); - lx_irq_set(chip, 1); -} - -void lx_irq_disable(struct lx6464es *chip) -{ - snd_printdd("->lx_irq_disable\n"); - lx_irq_set(chip, 0); -} diff --git a/trunk/sound/pci/lx6464es/lx_core.h b/trunk/sound/pci/lx6464es/lx_core.h deleted file mode 100644 index 6bd9cbbbc68d..000000000000 --- a/trunk/sound/pci/lx6464es/lx_core.h +++ /dev/null @@ -1,242 +0,0 @@ -/* -*- linux-c -*- * - * - * ALSA driver for the digigram lx6464es interface - * low-level interface - * - * Copyright (c) 2009 Tim Blechmann - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - */ - -#ifndef LX_CORE_H -#define LX_CORE_H - -#include - -#include "lx_defs.h" - -#define REG_CRM_NUMBER 12 - -struct lx6464es; - -/* low-level register access */ - -/* dsp register access */ -enum { - eReg_BASE, - eReg_CSM, - eReg_CRM1, - eReg_CRM2, - eReg_CRM3, - eReg_CRM4, - eReg_CRM5, - eReg_CRM6, - eReg_CRM7, - eReg_CRM8, - eReg_CRM9, - eReg_CRM10, - eReg_CRM11, - eReg_CRM12, - - eReg_ICR, - eReg_CVR, - eReg_ISR, - eReg_RXHTXH, - eReg_RXMTXM, - eReg_RHLTXL, - eReg_RESETDSP, - - eReg_CSUF, - eReg_CSES, - eReg_CRESMSB, - eReg_CRESLSB, - eReg_ADMACESMSB, - eReg_ADMACESLSB, - eReg_CONFES, - - eMaxPortLx -}; - -unsigned long lx_dsp_reg_read(struct lx6464es *chip, int port); -void lx_dsp_reg_readbuf(struct lx6464es *chip, int port, u32 *data, u32 len); -void lx_dsp_reg_write(struct lx6464es *chip, int port, unsigned data); -void lx_dsp_reg_writebuf(struct lx6464es *chip, int port, const u32 *data, - u32 len); - -/* plx register access */ -enum { - ePLX_PCICR, - - ePLX_MBOX0, - ePLX_MBOX1, - ePLX_MBOX2, - ePLX_MBOX3, - ePLX_MBOX4, - ePLX_MBOX5, - ePLX_MBOX6, - ePLX_MBOX7, - - ePLX_L2PCIDB, - ePLX_IRQCS, - ePLX_CHIPSC, - - eMaxPort -}; - -unsigned long lx_plx_reg_read(struct lx6464es *chip, int port); -void lx_plx_reg_write(struct lx6464es *chip, int port, u32 data); - -/* rhm */ -struct lx_rmh { - u16 cmd_len; /* length of the command to send (WORDs) */ - u16 stat_len; /* length of the status received (WORDs) */ - u16 dsp_stat; /* status type, RMP_SSIZE_XXX */ - u16 cmd_idx; /* index of the command */ - u32 cmd[REG_CRM_NUMBER]; - u32 stat[REG_CRM_NUMBER]; -}; - - -/* low-level dsp access */ -int __devinit lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version); -int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq); -int lx_dsp_set_granularity(struct lx6464es *chip, u32 gran); -int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data); -int lx_dsp_get_mac(struct lx6464es *chip, u8 *mac_address); - - -/* low-level pipe handling */ -int lx_pipe_allocate(struct lx6464es *chip, u32 pipe, int is_capture, - int channels); -int lx_pipe_release(struct lx6464es *chip, u32 pipe, int is_capture); -int lx_pipe_sample_count(struct lx6464es *chip, u32 pipe, int is_capture, - u64 *rsample_count); -int lx_pipe_state(struct lx6464es *chip, u32 pipe, int is_capture, u16 *rstate); -int lx_pipe_stop(struct lx6464es *chip, u32 pipe, int is_capture); -int lx_pipe_start(struct lx6464es *chip, u32 pipe, int is_capture); -int lx_pipe_pause(struct lx6464es *chip, u32 pipe, int is_capture); - -int lx_pipe_wait_for_start(struct lx6464es *chip, u32 pipe, int is_capture); -int lx_pipe_wait_for_idle(struct lx6464es *chip, u32 pipe, int is_capture); - -/* low-level stream handling */ -int lx_stream_set_format(struct lx6464es *chip, struct snd_pcm_runtime *runtime, - u32 pipe, int is_capture); -int lx_stream_state(struct lx6464es *chip, u32 pipe, int is_capture, - int *rstate); -int lx_stream_sample_position(struct lx6464es *chip, u32 pipe, int is_capture, - u64 *r_bytepos); - -int lx_stream_set_state(struct lx6464es *chip, u32 pipe, - int is_capture, enum stream_state_t state); - -static inline int lx_stream_start(struct lx6464es *chip, u32 pipe, - int is_capture) -{ - snd_printdd("->lx_stream_start\n"); - return lx_stream_set_state(chip, pipe, is_capture, SSTATE_RUN); -} - -static inline int lx_stream_pause(struct lx6464es *chip, u32 pipe, - int is_capture) -{ - snd_printdd("->lx_stream_pause\n"); - return lx_stream_set_state(chip, pipe, is_capture, SSTATE_PAUSE); -} - -static inline int lx_stream_stop(struct lx6464es *chip, u32 pipe, - int is_capture) -{ - snd_printdd("->lx_stream_stop\n"); - return lx_stream_set_state(chip, pipe, is_capture, SSTATE_STOP); -} - -/* low-level buffer handling */ -int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture, - u32 *r_needed, u32 *r_freed, u32 *size_array); -int lx_buffer_give(struct lx6464es *chip, u32 pipe, int is_capture, - u32 buffer_size, u32 buf_address_lo, u32 buf_address_hi, - u32 *r_buffer_index); -int lx_buffer_free(struct lx6464es *chip, u32 pipe, int is_capture, - u32 *r_buffer_size); -int lx_buffer_cancel(struct lx6464es *chip, u32 pipe, int is_capture, - u32 buffer_index); - -/* low-level gain/peak handling */ -int lx_level_unmute(struct lx6464es *chip, int is_capture, int unmute); -int lx_level_peaks(struct lx6464es *chip, int is_capture, int channels, - u32 *r_levels); - - -/* interrupt handling */ -irqreturn_t lx_interrupt(int irq, void *dev_id); -void lx_irq_enable(struct lx6464es *chip); -void lx_irq_disable(struct lx6464es *chip); - -void lx_tasklet_capture(unsigned long data); -void lx_tasklet_playback(unsigned long data); - - -/* Stream Format Header Defines (for LIN and IEEE754) */ -#define HEADER_FMT_BASE HEADER_FMT_BASE_LIN -#define HEADER_FMT_BASE_LIN 0xFED00000 -#define HEADER_FMT_BASE_FLOAT 0xFAD00000 -#define HEADER_FMT_MONO 0x00000080 /* bit 23 in header_lo. WARNING: old - * bit 22 is ignored in float - * format */ -#define HEADER_FMT_INTEL 0x00008000 -#define HEADER_FMT_16BITS 0x00002000 -#define HEADER_FMT_24BITS 0x00004000 -#define HEADER_FMT_UPTO11 0x00000200 /* frequency is less or equ. to 11k. - * */ -#define HEADER_FMT_UPTO32 0x00000100 /* frequency is over 11k and less - * then 32k.*/ - - -#define BIT_FMP_HEADER 23 -#define BIT_FMP_SD 22 -#define BIT_FMP_MULTICHANNEL 19 - -#define START_STATE 1 -#define PAUSE_STATE 0 - - - - - -/* from PcxAll_e.h */ -/* Start/Pause condition for pipes (PCXStartPipe, PCXPausePipe) */ -#define START_PAUSE_IMMEDIATE 0 -#define START_PAUSE_ON_SYNCHRO 1 -#define START_PAUSE_ON_TIME_CODE 2 - - -/* Pipe / Stream state */ -#define START_STATE 1 -#define PAUSE_STATE 0 - -static inline void unpack_pointer(dma_addr_t ptr, u32 *r_low, u32 *r_high) -{ - *r_low = (u32)(ptr & 0xffffffff); -#if BITS_PER_LONG == 32 - *r_high = 0; -#else - *r_high = (u32)((u64)ptr>>32); -#endif -} - -#endif /* LX_CORE_H */ diff --git a/trunk/sound/pci/lx6464es/lx_defs.h b/trunk/sound/pci/lx6464es/lx_defs.h deleted file mode 100644 index 49d36bdd512c..000000000000 --- a/trunk/sound/pci/lx6464es/lx_defs.h +++ /dev/null @@ -1,376 +0,0 @@ -/* -*- linux-c -*- * - * - * ALSA driver for the digigram lx6464es interface - * adapted upstream headers - * - * Copyright (c) 2009 Tim Blechmann - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - */ - -#ifndef LX_DEFS_H -#define LX_DEFS_H - -/* code adapted from ethersound.h */ -#define XES_FREQ_COUNT8_MASK 0x00001FFF /* compteur 25MHz entre 8 ech. */ -#define XES_FREQ_COUNT8_44_MIN 0x00001288 /* 25M / - * [ 44k - ( 44.1k + 48k ) / 2 ] - * * 8 */ -#define XES_FREQ_COUNT8_44_MAX 0x000010F0 /* 25M / [ ( 44.1k + 48k ) / 2 ] - * * 8 */ -#define XES_FREQ_COUNT8_48_MAX 0x00000F08 /* 25M / - * [ 48k + ( 44.1k + 48k ) / 2 ] - * * 8 */ - -/* code adapted from LXES_registers.h */ - -#define IOCR_OUTPUTS_OFFSET 0 /* (rw) offset for the number of OUTs in the - * ConfES register. */ -#define IOCR_INPUTS_OFFSET 8 /* (rw) offset for the number of INs in the - * ConfES register. */ -#define FREQ_RATIO_OFFSET 19 /* (rw) offset for frequency ratio in the - * ConfES register. */ -#define FREQ_RATIO_SINGLE_MODE 0x01 /* value for single mode frequency ratio: - * sample rate = frequency rate. */ - -#define CONFES_READ_PART_MASK 0x00070000 -#define CONFES_WRITE_PART_MASK 0x00F80000 - -/* code adapted from if_drv_mb.h */ - -#define MASK_SYS_STATUS_ERROR (1L << 31) /* events that lead to a PCI irq if - * not yet pending */ -#define MASK_SYS_STATUS_URUN (1L << 30) -#define MASK_SYS_STATUS_ORUN (1L << 29) -#define MASK_SYS_STATUS_EOBO (1L << 28) -#define MASK_SYS_STATUS_EOBI (1L << 27) -#define MASK_SYS_STATUS_FREQ (1L << 26) -#define MASK_SYS_STATUS_ESA (1L << 25) /* reserved, this is set by the - * XES */ -#define MASK_SYS_STATUS_TIMER (1L << 24) - -#define MASK_SYS_ASYNC_EVENTS (MASK_SYS_STATUS_ERROR | \ - MASK_SYS_STATUS_URUN | \ - MASK_SYS_STATUS_ORUN | \ - MASK_SYS_STATUS_EOBO | \ - MASK_SYS_STATUS_EOBI | \ - MASK_SYS_STATUS_FREQ | \ - MASK_SYS_STATUS_ESA) - -#define MASK_SYS_PCI_EVENTS (MASK_SYS_ASYNC_EVENTS | \ - MASK_SYS_STATUS_TIMER) - -#define MASK_SYS_TIMER_COUNT 0x0000FFFF - -#define MASK_SYS_STATUS_EOT_PLX (1L << 22) /* event that remains - * internal: reserved fo end - * of plx dma */ -#define MASK_SYS_STATUS_XES (1L << 21) /* event that remains - * internal: pending XES - * IRQ */ -#define MASK_SYS_STATUS_CMD_DONE (1L << 20) /* alternate command - * management: notify driver - * instead of polling */ - - -#define MAX_STREAM_BUFFER 5 /* max amount of stream buffers. */ - -#define MICROBLAZE_IBL_MIN 32 -#define MICROBLAZE_IBL_DEFAULT 128 -#define MICROBLAZE_IBL_MAX 512 -/* #define MASK_GRANULARITY (2*MICROBLAZE_IBL_MAX-1) */ - - - -/* command opcodes, see reference for details */ - -/* - the capture bit position in the object_id field in driver commands - depends upon the number of managed channels. For now, 64 IN + 64 OUT are - supported. HOwever, the communication protocol forsees 1024 channels, hence - bit 10 indicates a capture (input) object). -*/ -#define ID_IS_CAPTURE (1L << 10) -#define ID_OFFSET 13 /* object ID is at the 13th bit in the - * 1st command word.*/ -#define ID_CH_MASK 0x3F -#define OPCODE_OFFSET 24 /* offset of the command opcode in the first - * command word.*/ - -enum cmd_mb_opcodes { - CMD_00_INFO_DEBUG = 0x00, - CMD_01_GET_SYS_CFG = 0x01, - CMD_02_SET_GRANULARITY = 0x02, - CMD_03_SET_TIMER_IRQ = 0x03, - CMD_04_GET_EVENT = 0x04, - CMD_05_GET_PIPES = 0x05, - - CMD_06_ALLOCATE_PIPE = 0x06, - CMD_07_RELEASE_PIPE = 0x07, - CMD_08_ASK_BUFFERS = 0x08, - CMD_09_STOP_PIPE = 0x09, - CMD_0A_GET_PIPE_SPL_COUNT = 0x0a, - CMD_0B_TOGGLE_PIPE_STATE = 0x0b, - - CMD_0C_DEF_STREAM = 0x0c, - CMD_0D_SET_MUTE = 0x0d, - CMD_0E_GET_STREAM_SPL_COUNT = 0x0e, - CMD_0F_UPDATE_BUFFER = 0x0f, - CMD_10_GET_BUFFER = 0x10, - CMD_11_CANCEL_BUFFER = 0x11, - CMD_12_GET_PEAK = 0x12, - CMD_13_SET_STREAM_STATE = 0x13, - CMD_14_INVALID = 0x14, -}; - -/* pipe states */ -enum pipe_state_t { - PSTATE_IDLE = 0, /* the pipe is not processed in the XES_IRQ - * (free or stopped, or paused). */ - PSTATE_RUN = 1, /* sustained play/record state. */ - PSTATE_PURGE = 2, /* the ES channels are now off, render pipes do - * not DMA, record pipe do a last DMA. */ - PSTATE_ACQUIRE = 3, /* the ES channels are now on, render pipes do - * not yet increase their sample count, record - * pipes do not DMA. */ - PSTATE_CLOSING = 4, /* the pipe is releasing, and may not yet - * receive an "alloc" command. */ -}; - -/* stream states */ -enum stream_state_t { - SSTATE_STOP = 0x00, /* setting to stop resets the stream spl - * count.*/ - SSTATE_RUN = (0x01 << 0), /* start DMA and spl count handling. */ - SSTATE_PAUSE = (0x01 << 1), /* pause DMA and spl count handling. */ -}; - -/* buffer flags */ -enum buffer_flags { - BF_VALID = 0x80, /* set if the buffer is valid, clear if free.*/ - BF_CURRENT = 0x40, /* set if this is the current buffer (there is - * always a current buffer).*/ - BF_NOTIFY_EOB = 0x20, /* set if this buffer must cause a PCI event - * when finished.*/ - BF_CIRCULAR = 0x10, /* set if buffer[1] must be copied to buffer[0] - * by the end of this buffer.*/ - BF_64BITS_ADR = 0x08, /* set if the hi part of the address is valid.*/ - BF_xx = 0x04, /* future extension.*/ - BF_EOB = 0x02, /* set if finished, but not yet free.*/ - BF_PAUSE = 0x01, /* pause stream at buffer end.*/ - BF_ZERO = 0x00, /* no flags (init).*/ -}; - -/** -* Stream Flags definitions -*/ -enum stream_flags { - SF_ZERO = 0x00000000, /* no flags (stream invalid). */ - SF_VALID = 0x10000000, /* the stream has a valid DMA_conf - * info (setstreamformat). */ - SF_XRUN = 0x20000000, /* the stream is un x-run state. */ - SF_START = 0x40000000, /* the DMA is running.*/ - SF_ASIO = 0x80000000, /* ASIO.*/ -}; - - -#define MASK_SPL_COUNT_HI 0x00FFFFFF /* 4 MSBits are status bits */ -#define PSTATE_OFFSET 28 /* 4 MSBits are status bits */ - - -#define MASK_STREAM_HAS_MAPPING (1L << 12) -#define MASK_STREAM_IS_ASIO (1L << 9) -#define STREAM_FMT_OFFSET 10 /* the stream fmt bits start at the 10th - * bit in the command word. */ - -#define STREAM_FMT_16b 0x02 -#define STREAM_FMT_intel 0x01 - -#define FREQ_FIELD_OFFSET 15 /* offset of the freq field in the response - * word */ - -#define BUFF_FLAGS_OFFSET 24 /* offset of the buffer flags in the - * response word. */ -#define MASK_DATA_SIZE 0x00FFFFFF /* this must match the field size of - * datasize in the buffer_t structure. */ - -#define MASK_BUFFER_ID 0xFF /* the cancel command awaits a buffer ID, - * may be 0xFF for "current". */ - - -/* code adapted from PcxErr_e.h */ - -/* Bits masks */ - -#define ERROR_MASK 0x8000 - -#define SOURCE_MASK 0x7800 - -#define E_SOURCE_BOARD 0x4000 /* 8 >> 1 */ -#define E_SOURCE_DRV 0x2000 /* 4 >> 1 */ -#define E_SOURCE_API 0x1000 /* 2 >> 1 */ -/* Error tools */ -#define E_SOURCE_TOOLS 0x0800 /* 1 >> 1 */ -/* Error pcxaudio */ -#define E_SOURCE_AUDIO 0x1800 /* 3 >> 1 */ -/* Error virtual pcx */ -#define E_SOURCE_VPCX 0x2800 /* 5 >> 1 */ -/* Error dispatcher */ -#define E_SOURCE_DISPATCHER 0x3000 /* 6 >> 1 */ -/* Error from CobraNet firmware */ -#define E_SOURCE_COBRANET 0x3800 /* 7 >> 1 */ - -#define E_SOURCE_USER 0x7800 - -#define CLASS_MASK 0x0700 - -#define CODE_MASK 0x00FF - -/* Bits values */ - -/* Values for the error/warning bit */ -#define ERROR_VALUE 0x8000 -#define WARNING_VALUE 0x0000 - -/* Class values */ -#define E_CLASS_GENERAL 0x0000 -#define E_CLASS_INVALID_CMD 0x0100 -#define E_CLASS_INVALID_STD_OBJECT 0x0200 -#define E_CLASS_RSRC_IMPOSSIBLE 0x0300 -#define E_CLASS_WRONG_CONTEXT 0x0400 -#define E_CLASS_BAD_SPECIFIC_PARAMETER 0x0500 -#define E_CLASS_REAL_TIME_ERROR 0x0600 -#define E_CLASS_DIRECTSHOW 0x0700 -#define E_CLASS_FREE 0x0700 - - -/* Complete DRV error code for the general class */ -#define ED_GN (ERROR_VALUE | E_SOURCE_DRV | E_CLASS_GENERAL) -#define ED_CONCURRENCY (ED_GN | 0x01) -#define ED_DSP_CRASHED (ED_GN | 0x02) -#define ED_UNKNOWN_BOARD (ED_GN | 0x03) -#define ED_NOT_INSTALLED (ED_GN | 0x04) -#define ED_CANNOT_OPEN_SVC_MANAGER (ED_GN | 0x05) -#define ED_CANNOT_READ_REGISTRY (ED_GN | 0x06) -#define ED_DSP_VERSION_MISMATCH (ED_GN | 0x07) -#define ED_UNAVAILABLE_FEATURE (ED_GN | 0x08) -#define ED_CANCELLED (ED_GN | 0x09) -#define ED_NO_RESPONSE_AT_IRQA (ED_GN | 0x10) -#define ED_INVALID_ADDRESS (ED_GN | 0x11) -#define ED_DSP_CORRUPTED (ED_GN | 0x12) -#define ED_PENDING_OPERATION (ED_GN | 0x13) -#define ED_NET_ALLOCATE_MEMORY_IMPOSSIBLE (ED_GN | 0x14) -#define ED_NET_REGISTER_ERROR (ED_GN | 0x15) -#define ED_NET_THREAD_ERROR (ED_GN | 0x16) -#define ED_NET_OPEN_ERROR (ED_GN | 0x17) -#define ED_NET_CLOSE_ERROR (ED_GN | 0x18) -#define ED_NET_NO_MORE_PACKET (ED_GN | 0x19) -#define ED_NET_NO_MORE_BUFFER (ED_GN | 0x1A) -#define ED_NET_SEND_ERROR (ED_GN | 0x1B) -#define ED_NET_RECEIVE_ERROR (ED_GN | 0x1C) -#define ED_NET_WRONG_MSG_SIZE (ED_GN | 0x1D) -#define ED_NET_WAIT_ERROR (ED_GN | 0x1E) -#define ED_NET_EEPROM_ERROR (ED_GN | 0x1F) -#define ED_INVALID_RS232_COM_NUMBER (ED_GN | 0x20) -#define ED_INVALID_RS232_INIT (ED_GN | 0x21) -#define ED_FILE_ERROR (ED_GN | 0x22) -#define ED_INVALID_GPIO_CMD (ED_GN | 0x23) -#define ED_RS232_ALREADY_OPENED (ED_GN | 0x24) -#define ED_RS232_NOT_OPENED (ED_GN | 0x25) -#define ED_GPIO_ALREADY_OPENED (ED_GN | 0x26) -#define ED_GPIO_NOT_OPENED (ED_GN | 0x27) -#define ED_REGISTRY_ERROR (ED_GN | 0x28) /* <- NCX */ -#define ED_INVALID_SERVICE (ED_GN | 0x29) /* <- NCX */ - -#define ED_READ_FILE_ALREADY_OPENED (ED_GN | 0x2a) /* <- Decalage - * pour RCX - * (old 0x28) - * */ -#define ED_READ_FILE_INVALID_COMMAND (ED_GN | 0x2b) /* ~ */ -#define ED_READ_FILE_INVALID_PARAMETER (ED_GN | 0x2c) /* ~ */ -#define ED_READ_FILE_ALREADY_CLOSED (ED_GN | 0x2d) /* ~ */ -#define ED_READ_FILE_NO_INFORMATION (ED_GN | 0x2e) /* ~ */ -#define ED_READ_FILE_INVALID_HANDLE (ED_GN | 0x2f) /* ~ */ -#define ED_READ_FILE_END_OF_FILE (ED_GN | 0x30) /* ~ */ -#define ED_READ_FILE_ERROR (ED_GN | 0x31) /* ~ */ - -#define ED_DSP_CRASHED_EXC_DSPSTACK_OVERFLOW (ED_GN | 0x32) /* <- Decalage pour - * PCX (old 0x14) */ -#define ED_DSP_CRASHED_EXC_SYSSTACK_OVERFLOW (ED_GN | 0x33) /* ~ */ -#define ED_DSP_CRASHED_EXC_ILLEGAL (ED_GN | 0x34) /* ~ */ -#define ED_DSP_CRASHED_EXC_TIMER_REENTRY (ED_GN | 0x35) /* ~ */ -#define ED_DSP_CRASHED_EXC_FATAL_ERROR (ED_GN | 0x36) /* ~ */ - -#define ED_FLASH_PCCARD_NOT_PRESENT (ED_GN | 0x37) - -#define ED_NO_CURRENT_CLOCK (ED_GN | 0x38) - -/* Complete DRV error code for real time class */ -#define ED_RT (ERROR_VALUE | E_SOURCE_DRV | E_CLASS_REAL_TIME_ERROR) -#define ED_DSP_TIMED_OUT (ED_RT | 0x01) -#define ED_DSP_CHK_TIMED_OUT (ED_RT | 0x02) -#define ED_STREAM_OVERRUN (ED_RT | 0x03) -#define ED_DSP_BUSY (ED_RT | 0x04) -#define ED_DSP_SEMAPHORE_TIME_OUT (ED_RT | 0x05) -#define ED_BOARD_TIME_OUT (ED_RT | 0x06) -#define ED_XILINX_ERROR (ED_RT | 0x07) -#define ED_COBRANET_ITF_NOT_RESPONDING (ED_RT | 0x08) - -/* Complete BOARD error code for the invaid standard object class */ -#define EB_ISO (ERROR_VALUE | E_SOURCE_BOARD | \ - E_CLASS_INVALID_STD_OBJECT) -#define EB_INVALID_EFFECT (EB_ISO | 0x00) -#define EB_INVALID_PIPE (EB_ISO | 0x40) -#define EB_INVALID_STREAM (EB_ISO | 0x80) -#define EB_INVALID_AUDIO (EB_ISO | 0xC0) - -/* Complete BOARD error code for impossible resource allocation class */ -#define EB_RI (ERROR_VALUE | E_SOURCE_BOARD | E_CLASS_RSRC_IMPOSSIBLE) -#define EB_ALLOCATE_ALL_STREAM_TRANSFERT_BUFFERS_IMPOSSIBLE (EB_RI | 0x01) -#define EB_ALLOCATE_PIPE_SAMPLE_BUFFER_IMPOSSIBLE (EB_RI | 0x02) - -#define EB_ALLOCATE_MEM_STREAM_IMPOSSIBLE \ - EB_ALLOCATE_ALL_STREAM_TRANSFERT_BUFFERS_IMPOSSIBLE -#define EB_ALLOCATE_MEM_PIPE_IMPOSSIBLE \ - EB_ALLOCATE_PIPE_SAMPLE_BUFFER_IMPOSSIBLE - -#define EB_ALLOCATE_DIFFERED_CMD_IMPOSSIBLE (EB_RI | 0x03) -#define EB_TOO_MANY_DIFFERED_CMD (EB_RI | 0x04) -#define EB_RBUFFERS_TABLE_OVERFLOW (EB_RI | 0x05) -#define EB_ALLOCATE_EFFECTS_IMPOSSIBLE (EB_RI | 0x08) -#define EB_ALLOCATE_EFFECT_POS_IMPOSSIBLE (EB_RI | 0x09) -#define EB_RBUFFER_NOT_AVAILABLE (EB_RI | 0x0A) -#define EB_ALLOCATE_CONTEXT_LIII_IMPOSSIBLE (EB_RI | 0x0B) -#define EB_STATUS_DIALOG_IMPOSSIBLE (EB_RI | 0x1D) -#define EB_CONTROL_CMD_IMPOSSIBLE (EB_RI | 0x1E) -#define EB_STATUS_SEND_IMPOSSIBLE (EB_RI | 0x1F) -#define EB_ALLOCATE_PIPE_IMPOSSIBLE (EB_RI | 0x40) -#define EB_ALLOCATE_STREAM_IMPOSSIBLE (EB_RI | 0x80) -#define EB_ALLOCATE_AUDIO_IMPOSSIBLE (EB_RI | 0xC0) - -/* Complete BOARD error code for wrong call context class */ -#define EB_WCC (ERROR_VALUE | E_SOURCE_BOARD | E_CLASS_WRONG_CONTEXT) -#define EB_CMD_REFUSED (EB_WCC | 0x00) -#define EB_START_STREAM_REFUSED (EB_WCC | 0xFC) -#define EB_SPC_REFUSED (EB_WCC | 0xFD) -#define EB_CSN_REFUSED (EB_WCC | 0xFE) -#define EB_CSE_REFUSED (EB_WCC | 0xFF) - - - - -#endif /* LX_DEFS_H */ diff --git a/trunk/sound/pci/oxygen/oxygen_pcm.c b/trunk/sound/pci/oxygen/oxygen_pcm.c index 3b5ca70c9d4d..c262049961e1 100644 --- a/trunk/sound/pci/oxygen/oxygen_pcm.c +++ b/trunk/sound/pci/oxygen/oxygen_pcm.c @@ -487,14 +487,10 @@ static int oxygen_hw_free(struct snd_pcm_substream *substream) { struct oxygen *chip = snd_pcm_substream_chip(substream); unsigned int channel = oxygen_substream_channel(substream); - unsigned int channel_mask = 1 << channel; spin_lock_irq(&chip->reg_lock); - chip->interrupt_mask &= ~channel_mask; + chip->interrupt_mask &= ~(1 << channel); oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); - - oxygen_set_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask); - oxygen_clear_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask); spin_unlock_irq(&chip->reg_lock); return snd_pcm_lib_free_pages(substream); diff --git a/trunk/sound/pci/oxygen/virtuoso.c b/trunk/sound/pci/oxygen/virtuoso.c index bf971f7cfdc6..bc5ce11c8b14 100644 --- a/trunk/sound/pci/oxygen/virtuoso.c +++ b/trunk/sound/pci/oxygen/virtuoso.c @@ -113,8 +113,8 @@ */ /* - * Xonar Essence ST (Deluxe)/STX - * ----------------------------- + * Xonar Essence STX + * ----------------- * * CMI8788: * @@ -180,8 +180,6 @@ enum { MODEL_DX, MODEL_HDAV, /* without daughterboard */ MODEL_HDAV_H6, /* with H6 daughterboard */ - MODEL_ST, - MODEL_ST_H6, MODEL_STX, }; @@ -190,10 +188,8 @@ static struct pci_device_id xonar_ids[] __devinitdata = { { OXYGEN_PCI_SUBID(0x1043, 0x8275), .driver_data = MODEL_DX }, { OXYGEN_PCI_SUBID(0x1043, 0x82b7), .driver_data = MODEL_D2X }, { OXYGEN_PCI_SUBID(0x1043, 0x8314), .driver_data = MODEL_HDAV }, - { OXYGEN_PCI_SUBID(0x1043, 0x8327), .driver_data = MODEL_DX }, { OXYGEN_PCI_SUBID(0x1043, 0x834f), .driver_data = MODEL_D1 }, { OXYGEN_PCI_SUBID(0x1043, 0x835c), .driver_data = MODEL_STX }, - { OXYGEN_PCI_SUBID(0x1043, 0x835d), .driver_data = MODEL_ST }, { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, { } }; @@ -214,9 +210,9 @@ MODULE_DEVICE_TABLE(pci, xonar_ids); #define GPIO_DX_FRONT_PANEL 0x0002 #define GPIO_DX_INPUT_ROUTE 0x0100 -#define GPIO_DB_MASK 0x0030 -#define GPIO_DB_H6 0x0000 -#define GPIO_DB_XX 0x0020 +#define GPIO_HDAV_DB_MASK 0x0030 +#define GPIO_HDAV_DB_H6 0x0000 +#define GPIO_HDAV_DB_XX 0x0020 #define GPIO_ST_HP_REAR 0x0002 #define GPIO_ST_HP 0x0080 @@ -534,7 +530,7 @@ static void xonar_hdav_init(struct oxygen *chip) snd_component_add(chip->card, "CS5381"); } -static void xonar_st_init(struct oxygen *chip) +static void xonar_stx_init(struct oxygen *chip) { struct xonar_data *data = chip->model_data; @@ -543,11 +539,12 @@ static void xonar_st_init(struct oxygen *chip) OXYGEN_2WIRE_INTERRUPT_MASK | OXYGEN_2WIRE_SPEED_FAST); - if (chip->model.private_data == MODEL_ST_H6) - chip->model.dac_channels = 8; data->anti_pop_delay = 100; - data->dacs = chip->model.private_data == MODEL_ST_H6 ? 4 : 1; + data->dacs = 1; data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE; + data->ext_power_reg = OXYGEN_GPI_DATA; + data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; + data->ext_power_bit = GPI_DX_EXT_POWER; data->pcm1796_oversampling = PCM1796_OS_64; pcm1796_init(chip); @@ -563,17 +560,6 @@ static void xonar_st_init(struct oxygen *chip) snd_component_add(chip->card, "CS5381"); } -static void xonar_stx_init(struct oxygen *chip) -{ - struct xonar_data *data = chip->model_data; - - data->ext_power_reg = OXYGEN_GPI_DATA; - data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; - data->ext_power_bit = GPI_DX_EXT_POWER; - - xonar_st_init(chip); -} - static void xonar_disable_output(struct oxygen *chip) { struct xonar_data *data = chip->model_data; @@ -1035,8 +1021,7 @@ static const struct oxygen_model model_xonar_hdav = { .model_data_size = sizeof(struct xonar_data), .device_config = PLAYBACK_0_TO_I2S | PLAYBACK_1_TO_SPDIF | - CAPTURE_0_FROM_I2S_2 | - CAPTURE_1_FROM_SPDIF, + CAPTURE_0_FROM_I2S_2, .dac_channels = 8, .dac_volume_min = 255 - 2*60, .dac_volume_max = 255, @@ -1049,7 +1034,7 @@ static const struct oxygen_model model_xonar_hdav = { static const struct oxygen_model model_xonar_st = { .longname = "Asus Virtuoso 100", .chip = "AV200", - .init = xonar_st_init, + .init = xonar_stx_init, .control_filter = xonar_st_control_filter, .mixer_init = xonar_st_mixer_init, .cleanup = xonar_st_cleanup, @@ -1082,7 +1067,6 @@ static int __devinit get_xonar_model(struct oxygen *chip, [MODEL_D2] = &model_xonar_d2, [MODEL_D2X] = &model_xonar_d2, [MODEL_HDAV] = &model_xonar_hdav, - [MODEL_ST] = &model_xonar_st, [MODEL_STX] = &model_xonar_st, }; static const char *const names[] = { @@ -1092,8 +1076,6 @@ static int __devinit get_xonar_model(struct oxygen *chip, [MODEL_D2X] = "Xonar D2X", [MODEL_HDAV] = "Xonar HDAV1.3", [MODEL_HDAV_H6] = "Xonar HDAV1.3+H6", - [MODEL_ST] = "Xonar Essence ST", - [MODEL_ST_H6] = "Xonar Essence ST+H6", [MODEL_STX] = "Xonar Essence STX", }; unsigned int model = id->driver_data; @@ -1110,27 +1092,21 @@ static int __devinit get_xonar_model(struct oxygen *chip, chip->model.init = xonar_dx_init; break; case MODEL_HDAV: - oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK); - switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) { - case GPIO_DB_H6: + oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, + GPIO_HDAV_DB_MASK); + switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & + GPIO_HDAV_DB_MASK) { + case GPIO_HDAV_DB_H6: model = MODEL_HDAV_H6; break; - case GPIO_DB_XX: + case GPIO_HDAV_DB_XX: snd_printk(KERN_ERR "unknown daughterboard\n"); return -ENODEV; } break; - case MODEL_ST: - oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK); - switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) { - case GPIO_DB_H6: - model = MODEL_ST_H6; - break; - } - break; case MODEL_STX: - chip->model.init = xonar_stx_init; - oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK); + oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, + GPIO_HDAV_DB_MASK); break; } diff --git a/trunk/sound/pci/riptide/riptide.c b/trunk/sound/pci/riptide/riptide.c index 235a71e5ac8d..e51a5ef1954d 100644 --- a/trunk/sound/pci/riptide/riptide.c +++ b/trunk/sound/pci/riptide/riptide.c @@ -507,19 +507,41 @@ static int riptide_reset(struct cmdif *cif, struct snd_riptide *chip); */ static struct pci_device_id snd_riptide_ids[] = { - { PCI_DEVICE(0x127a, 0x4310) }, - { PCI_DEVICE(0x127a, 0x4320) }, - { PCI_DEVICE(0x127a, 0x4330) }, - { PCI_DEVICE(0x127a, 0x4340) }, + { + .vendor = 0x127a,.device = 0x4310, + .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID, + }, + { + .vendor = 0x127a,.device = 0x4320, + .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID, + }, + { + .vendor = 0x127a,.device = 0x4330, + .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID, + }, + { + .vendor = 0x127a,.device = 0x4340, + .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID, + }, {0,}, }; #ifdef SUPPORT_JOYSTICK static struct pci_device_id snd_riptide_joystick_ids[] __devinitdata = { - { PCI_DEVICE(0x127a, 0x4312) }, - { PCI_DEVICE(0x127a, 0x4322) }, - { PCI_DEVICE(0x127a, 0x4332) }, - { PCI_DEVICE(0x127a, 0x4342) }, + { + .vendor = 0x127a,.device = 0x4312, + .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID, + }, + { + .vendor = 0x127a,.device = 0x4322, + .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID, + }, + {.vendor = 0x127a,.device = 0x4332, + .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID, + }, + {.vendor = 0x127a,.device = 0x4342, + .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID, + }, {0,}, }; #endif @@ -1187,79 +1209,12 @@ static int riptide_resume(struct pci_dev *pci) } #endif -static int try_to_load_firmware(struct cmdif *cif, struct snd_riptide *chip) -{ - union firmware_version firmware = { .ret = CMDRET_ZERO }; - int i, timeout, err; - - for (i = 0; i < 2; i++) { - WRITE_PORT_ULONG(cif->hwport->port[i].data1, 0); - WRITE_PORT_ULONG(cif->hwport->port[i].data2, 0); - } - SET_GRESET(cif->hwport); - udelay(100); - UNSET_GRESET(cif->hwport); - udelay(100); - - for (timeout = 100000; --timeout; udelay(10)) { - if (IS_READY(cif->hwport) && !IS_GERR(cif->hwport)) - break; - } - if (!timeout) { - snd_printk(KERN_ERR - "Riptide: device not ready, audio status: 0x%x " - "ready: %d gerr: %d\n", - READ_AUDIO_STATUS(cif->hwport), - IS_READY(cif->hwport), IS_GERR(cif->hwport)); - return -EIO; - } else { - snd_printdd - ("Riptide: audio status: 0x%x ready: %d gerr: %d\n", - READ_AUDIO_STATUS(cif->hwport), - IS_READY(cif->hwport), IS_GERR(cif->hwport)); - } - - SEND_GETV(cif, &firmware.ret); - snd_printdd("Firmware version: ASIC: %d CODEC %d AUXDSP %d PROG %d\n", - firmware.firmware.ASIC, firmware.firmware.CODEC, - firmware.firmware.AUXDSP, firmware.firmware.PROG); - - for (i = 0; i < FIRMWARE_VERSIONS; i++) { - if (!memcmp(&firmware_versions[i], &firmware, sizeof(firmware))) - break; - } - if (i >= FIRMWARE_VERSIONS) - return 0; /* no match */ - - if (!chip) - return 1; /* OK */ - - snd_printdd("Writing Firmware\n"); - if (!chip->fw_entry) { - err = request_firmware(&chip->fw_entry, "riptide.hex", - &chip->pci->dev); - if (err) { - snd_printk(KERN_ERR - "Riptide: Firmware not available %d\n", err); - return -EIO; - } - } - err = loadfirmware(cif, chip->fw_entry->data, chip->fw_entry->size); - if (err) { - snd_printk(KERN_ERR - "Riptide: Could not load firmware %d\n", err); - return err; - } - - chip->firmware = firmware; - - return 1; /* OK */ -} - static int riptide_reset(struct cmdif *cif, struct snd_riptide *chip) { + int timeout, tries; union cmdret rptr = CMDRET_ZERO; - int err, tries; + union firmware_version firmware; + int i, j, err, has_firmware; if (!cif) return -EINVAL; @@ -1272,11 +1227,75 @@ static int riptide_reset(struct cmdif *cif, struct snd_riptide *chip) cif->is_reset = 0; tries = RESET_TRIES; - do { - err = try_to_load_firmware(cif, chip); - if (err < 0) - return err; - } while (!err && --tries); + has_firmware = 0; + while (has_firmware == 0 && tries-- > 0) { + for (i = 0; i < 2; i++) { + WRITE_PORT_ULONG(cif->hwport->port[i].data1, 0); + WRITE_PORT_ULONG(cif->hwport->port[i].data2, 0); + } + SET_GRESET(cif->hwport); + udelay(100); + UNSET_GRESET(cif->hwport); + udelay(100); + + for (timeout = 100000; --timeout; udelay(10)) { + if (IS_READY(cif->hwport) && !IS_GERR(cif->hwport)) + break; + } + if (timeout == 0) { + snd_printk(KERN_ERR + "Riptide: device not ready, audio status: 0x%x ready: %d gerr: %d\n", + READ_AUDIO_STATUS(cif->hwport), + IS_READY(cif->hwport), IS_GERR(cif->hwport)); + return -EIO; + } else { + snd_printdd + ("Riptide: audio status: 0x%x ready: %d gerr: %d\n", + READ_AUDIO_STATUS(cif->hwport), + IS_READY(cif->hwport), IS_GERR(cif->hwport)); + } + + SEND_GETV(cif, &rptr); + for (i = 0; i < 4; i++) + firmware.ret.retwords[i] = rptr.retwords[i]; + + snd_printdd + ("Firmware version: ASIC: %d CODEC %d AUXDSP %d PROG %d\n", + firmware.firmware.ASIC, firmware.firmware.CODEC, + firmware.firmware.AUXDSP, firmware.firmware.PROG); + + for (j = 0; j < FIRMWARE_VERSIONS; j++) { + has_firmware = 1; + for (i = 0; i < 4; i++) { + if (firmware_versions[j].ret.retwords[i] != + firmware.ret.retwords[i]) + has_firmware = 0; + } + if (has_firmware) + break; + } + + if (chip != NULL && has_firmware == 0) { + snd_printdd("Writing Firmware\n"); + if (!chip->fw_entry) { + if ((err = + request_firmware(&chip->fw_entry, + "riptide.hex", + &chip->pci->dev)) != 0) { + snd_printk(KERN_ERR + "Riptide: Firmware not available %d\n", + err); + return -EIO; + } + } + err = loadfirmware(cif, chip->fw_entry->data, + chip->fw_entry->size); + if (err) + snd_printk(KERN_ERR + "Riptide: Could not load firmware %d\n", + err); + } + } SEND_SACR(cif, 0, AC97_RESET); SEND_RACR(cif, AC97_RESET, &rptr); @@ -1318,6 +1337,11 @@ static int riptide_reset(struct cmdif *cif, struct snd_riptide *chip) SET_AIE(cif->hwport); SET_AIACK(cif->hwport); cif->is_reset = 1; + if (chip) { + for (i = 0; i < 4; i++) + chip->firmware.ret.retwords[i] = + firmware.ret.retwords[i]; + } return 0; } @@ -2014,12 +2038,14 @@ static int __devinit snd_riptide_mixer(struct snd_riptide *chip) } #ifdef SUPPORT_JOYSTICK +static int have_joystick; +static struct pci_dev *riptide_gameport_pci; +static struct gameport *riptide_gameport; static int __devinit snd_riptide_joystick_probe(struct pci_dev *pci, const struct pci_device_id *id) { static int dev; - struct gameport *gameport; if (dev >= SNDRV_CARDS) return -ENODEV; @@ -2028,33 +2054,36 @@ snd_riptide_joystick_probe(struct pci_dev *pci, const struct pci_device_id *id) return -ENOENT; } - if (!joystick_port[dev++]) - return 0; - - gameport = gameport_allocate_port(); - if (!gameport) - return -ENOMEM; - if (!request_region(joystick_port[dev], 8, "Riptide gameport")) { - snd_printk(KERN_WARNING - "Riptide: cannot grab gameport 0x%x\n", - joystick_port[dev]); - gameport_free_port(gameport); - return -EBUSY; + if (joystick_port[dev]) { + riptide_gameport = gameport_allocate_port(); + if (riptide_gameport) { + if (!request_region + (joystick_port[dev], 8, "Riptide gameport")) { + snd_printk(KERN_WARNING + "Riptide: cannot grab gameport 0x%x\n", + joystick_port[dev]); + gameport_free_port(riptide_gameport); + riptide_gameport = NULL; + } else { + riptide_gameport_pci = pci; + riptide_gameport->io = joystick_port[dev]; + gameport_register_port(riptide_gameport); + } + } } - - gameport->io = joystick_port[dev]; - gameport_register_port(gameport); - pci_set_drvdata(pci, gameport); + dev++; return 0; } static void __devexit snd_riptide_joystick_remove(struct pci_dev *pci) { - struct gameport *gameport = pci_get_drvdata(pci); - if (gameport) { - release_region(gameport->io, 8); - gameport_unregister_port(gameport); - pci_set_drvdata(pci, NULL); + if (riptide_gameport) { + if (riptide_gameport_pci == pci) { + release_region(riptide_gameport->io, 8); + riptide_gameport_pci = NULL; + gameport_unregister_port(riptide_gameport); + riptide_gameport = NULL; + } } } #endif @@ -2065,8 +2094,8 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) static int dev; struct snd_card *card; struct snd_riptide *chip; - unsigned short val; - int err; + unsigned short addr; + int err = 0; if (dev >= SNDRV_CARDS) return -ENODEV; @@ -2078,63 +2107,60 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); if (err < 0) return err; - err = snd_riptide_create(card, pci, &chip); - if (err < 0) - goto error; + if ((err = snd_riptide_create(card, pci, &chip)) < 0) { + snd_card_free(card); + return err; + } card->private_data = chip; - err = snd_riptide_pcm(chip, 0, NULL); - if (err < 0) - goto error; - err = snd_riptide_mixer(chip); - if (err < 0) - goto error; - - val = LEGACY_ENABLE_ALL; - if (opl3_port[dev]) - val |= LEGACY_ENABLE_FM; + if ((err = snd_riptide_pcm(chip, 0, NULL)) < 0) { + snd_card_free(card); + return err; + } + if ((err = snd_riptide_mixer(chip)) < 0) { + snd_card_free(card); + return err; + } + pci_write_config_word(chip->pci, PCI_EXT_Legacy_Mask, LEGACY_ENABLE_ALL + | (opl3_port[dev] ? LEGACY_ENABLE_FM : 0) #ifdef SUPPORT_JOYSTICK - if (joystick_port[dev]) - val |= LEGACY_ENABLE_GAMEPORT; + | (joystick_port[dev] ? LEGACY_ENABLE_GAMEPORT : + 0) #endif - if (mpu_port[dev]) - val |= LEGACY_ENABLE_MPU_INT | LEGACY_ENABLE_MPU; - val |= (chip->irq << 4) & 0xf0; - pci_write_config_word(chip->pci, PCI_EXT_Legacy_Mask, val); - if (mpu_port[dev]) { - val = mpu_port[dev]; - pci_write_config_word(chip->pci, PCI_EXT_MPU_Base, val); - err = snd_mpu401_uart_new(card, 0, MPU401_HW_RIPTIDE, - val, 0, chip->irq, 0, - &chip->rmidi); - if (err < 0) + | (mpu_port[dev] + ? (LEGACY_ENABLE_MPU_INT | LEGACY_ENABLE_MPU) : + 0) + | ((chip->irq << 4) & 0xF0)); + if ((addr = mpu_port[dev]) != 0) { + pci_write_config_word(chip->pci, PCI_EXT_MPU_Base, addr); + if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_RIPTIDE, + addr, 0, chip->irq, 0, + &chip->rmidi)) < 0) snd_printk(KERN_WARNING "Riptide: Can't Allocate MPU at 0x%x\n", - val); + addr); else - chip->mpuaddr = val; + chip->mpuaddr = addr; } - if (opl3_port[dev]) { - val = opl3_port[dev]; - pci_write_config_word(chip->pci, PCI_EXT_FM_Base, val); - err = snd_opl3_create(card, val, val + 2, - OPL3_HW_RIPTIDE, 0, &chip->opl3); - if (err < 0) + if ((addr = opl3_port[dev]) != 0) { + pci_write_config_word(chip->pci, PCI_EXT_FM_Base, addr); + if ((err = snd_opl3_create(card, addr, addr + 2, + OPL3_HW_RIPTIDE, 0, + &chip->opl3)) < 0) snd_printk(KERN_WARNING "Riptide: Can't Allocate OPL3 at 0x%x\n", - val); + addr); else { - chip->opladdr = val; - err = snd_opl3_hwdep_new(chip->opl3, 0, 1, NULL); - if (err < 0) + chip->opladdr = addr; + if ((err = + snd_opl3_hwdep_new(chip->opl3, 0, 1, NULL)) < 0) snd_printk(KERN_WARNING "Riptide: Can't Allocate OPL3-HWDEP\n"); } } #ifdef SUPPORT_JOYSTICK - if (joystick_port[dev]) { - val = joystick_port[dev]; - pci_write_config_word(chip->pci, PCI_EXT_Game_Base, val); - chip->gameaddr = val; + if ((addr = joystick_port[dev]) != 0) { + pci_write_config_word(chip->pci, PCI_EXT_Game_Base, addr); + chip->gameaddr = addr; } #endif @@ -2152,16 +2178,13 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) chip->opladdr); #endif snd_riptide_proc_init(chip); - err = snd_card_register(card); - if (err < 0) - goto error; + if ((err = snd_card_register(card)) < 0) { + snd_card_free(card); + return err; + } pci_set_drvdata(pci, card); dev++; return 0; - - error: - snd_card_free(card); - return err; } static void __devexit snd_card_riptide_remove(struct pci_dev *pci) @@ -2193,11 +2216,14 @@ static struct pci_driver joystick_driver = { static int __init alsa_card_riptide_init(void) { int err; - err = pci_register_driver(&driver); - if (err < 0) + if ((err = pci_register_driver(&driver)) < 0) return err; #if defined(SUPPORT_JOYSTICK) - pci_register_driver(&joystick_driver); + if (pci_register_driver(&joystick_driver) < 0) { + have_joystick = 0; + snd_printk(KERN_INFO "no joystick found\n"); + } else + have_joystick = 1; #endif return 0; } @@ -2206,7 +2232,8 @@ static void __exit alsa_card_riptide_exit(void) { pci_unregister_driver(&driver); #if defined(SUPPORT_JOYSTICK) - pci_unregister_driver(&joystick_driver); + if (have_joystick) + pci_unregister_driver(&joystick_driver); #endif } diff --git a/trunk/sound/pci/rme9652/hdsp.c b/trunk/sound/pci/rme9652/hdsp.c index 3da5c029f93b..314e73531bd1 100644 --- a/trunk/sound/pci/rme9652/hdsp.c +++ b/trunk/sound/pci/rme9652/hdsp.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -403,9 +402,9 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin"); #define HDSP_DMA_AREA_BYTES ((HDSP_MAX_CHANNELS+1) * HDSP_CHANNEL_BUFFER_BYTES) #define HDSP_DMA_AREA_KILOBYTES (HDSP_DMA_AREA_BYTES/1024) -/* use hotplug firmware loader? */ +/* use hotplug firmeare loader? */ #if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) -#if !defined(HDSP_USE_HWDEP_LOADER) +#if !defined(HDSP_USE_HWDEP_LOADER) && !defined(CONFIG_SND_HDSP) #define HDSP_FW_LOADER #endif #endif @@ -1048,6 +1047,7 @@ static int hdsp_set_interrupt_interval(struct hdsp *s, unsigned int frames) static void hdsp_set_dds_value(struct hdsp *hdsp, int rate) { u64 n; + u32 r; if (rate >= 112000) rate /= 4; @@ -1055,7 +1055,7 @@ static void hdsp_set_dds_value(struct hdsp *hdsp, int rate) rate /= 2; n = DDS_NUMERATOR; - n = div_u64(n, rate); + div64_32(&n, rate, &r); /* n should be less than 2^32 for being written to FREQ register */ snd_BUG_ON(n >> 32); /* HDSP_freqReg and HDSP_resetPointer are the same, so keep the DDS @@ -3097,6 +3097,7 @@ static int snd_hdsp_get_adat_sync_check(struct snd_kcontrol *kcontrol, struct sn static int hdsp_dds_offset(struct hdsp *hdsp) { u64 n; + u32 r; unsigned int dds_value = hdsp->dds_value; int system_sample_rate = hdsp->system_sample_rate; @@ -3108,7 +3109,7 @@ static int hdsp_dds_offset(struct hdsp *hdsp) * dds_value = n / rate * rate = n / dds_value */ - n = div_u64(n, dds_value); + div64_32(&n, dds_value, &r); if (system_sample_rate >= 112000) n *= 4; else if (system_sample_rate >= 56000) diff --git a/trunk/sound/pci/rme9652/hdspm.c b/trunk/sound/pci/rme9652/hdspm.c index 0dce331a2a3b..bac2dc0c5d85 100644 --- a/trunk/sound/pci/rme9652/hdspm.c +++ b/trunk/sound/pci/rme9652/hdspm.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -832,6 +831,7 @@ static int hdspm_set_interrupt_interval(struct hdspm * s, unsigned int frames) static void hdspm_set_dds_value(struct hdspm *hdspm, int rate) { u64 n; + u32 r; if (rate >= 112000) rate /= 4; @@ -844,7 +844,7 @@ static void hdspm_set_dds_value(struct hdspm *hdspm, int rate) */ /* n = 104857600000000ULL; */ /* = 2^20 * 10^8 */ n = 110100480000000ULL; /* Value checked for AES32 and MADI */ - n = div_u64(n, rate); + div64_32(&n, rate, &r); /* n should be less than 2^32 for being written to FREQ register */ snd_BUG_ON(n >> 32); hdspm_write(hdspm, HDSPM_freqReg, (u32)n); diff --git a/trunk/sound/pci/via82xx.c b/trunk/sound/pci/via82xx.c index 949fcaf6b70e..1ef58c51c213 100644 --- a/trunk/sound/pci/via82xx.c +++ b/trunk/sound/pci/via82xx.c @@ -85,7 +85,6 @@ static int joystick; static int ac97_clock = 48000; static char *ac97_quirk; static int dxs_support; -static int nodelay; module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for VIA 82xx bridge."); @@ -103,8 +102,6 @@ module_param(ac97_quirk, charp, 0444); MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware."); module_param(dxs_support, int, 0444); MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only, 4 = no VRA, 5 = enable any sample rate)"); -module_param(nodelay, int, 0444); -MODULE_PARM_DESC(nodelay, "Disable 500ms init delay"); /* just for backward compatibility */ static int enable; @@ -552,8 +549,7 @@ static void snd_via82xx_codec_wait(struct snd_ac97 *ac97) int err; err = snd_via82xx_codec_ready(chip, ac97->num); /* here we need to wait fairly for long time.. */ - if (!nodelay) - msleep(500); + msleep(500); } static void snd_via82xx_codec_write(struct snd_ac97 *ac97, diff --git a/trunk/sound/ppc/awacs.c b/trunk/sound/ppc/awacs.c index 2cc0eda4f20e..80df9b1f651e 100644 --- a/trunk/sound/ppc/awacs.c +++ b/trunk/sound/ppc/awacs.c @@ -477,7 +477,7 @@ static int snd_pmac_awacs_put_master_amp(struct snd_kcontrol *kcontrol, #define AMP_CH_SPK 0 #define AMP_CH_HD 1 -static struct snd_kcontrol_new snd_pmac_awacs_amp_vol[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_awacs_amp_vol[] __initdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PC Speaker Playback Volume", .info = snd_pmac_awacs_info_volume_amp, @@ -514,7 +514,7 @@ static struct snd_kcontrol_new snd_pmac_awacs_amp_vol[] __devinitdata = { }, }; -static struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw __devinitdata = { +static struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw __initdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Headphone Playback Switch", .info = snd_pmac_boolean_stereo_info, @@ -523,7 +523,7 @@ static struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw __devinitdata = { .private_value = AMP_CH_HD, }; -static struct snd_kcontrol_new snd_pmac_awacs_amp_spk_sw __devinitdata = { +static struct snd_kcontrol_new snd_pmac_awacs_amp_spk_sw __initdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PC Speaker Playback Switch", .info = snd_pmac_boolean_stereo_info, @@ -595,46 +595,46 @@ static int snd_pmac_screamer_mic_boost_put(struct snd_kcontrol *kcontrol, /* * lists of mixer elements */ -static struct snd_kcontrol_new snd_pmac_awacs_mixers[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_awacs_mixers[] __initdata = { AWACS_SWITCH("Master Capture Switch", 1, SHIFT_LOOPTHRU, 0), AWACS_VOLUME("Master Capture Volume", 0, 4, 0), /* AWACS_SWITCH("Unknown Playback Switch", 6, SHIFT_PAROUT0, 0), */ }; -static struct snd_kcontrol_new snd_pmac_screamer_mixers_beige[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_screamer_mixers_beige[] __initdata = { AWACS_VOLUME("Master Playback Volume", 2, 6, 1), AWACS_VOLUME("Play-through Playback Volume", 5, 6, 1), AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0), AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_LINE, 0), }; -static struct snd_kcontrol_new snd_pmac_screamer_mixers_lo[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_screamer_mixers_lo[] __initdata = { AWACS_VOLUME("Line out Playback Volume", 2, 6, 1), }; -static struct snd_kcontrol_new snd_pmac_screamer_mixers_imac[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_screamer_mixers_imac[] __initdata = { AWACS_VOLUME("Play-through Playback Volume", 5, 6, 1), AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0), }; -static struct snd_kcontrol_new snd_pmac_screamer_mixers_g4agp[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_screamer_mixers_g4agp[] __initdata = { AWACS_VOLUME("Line out Playback Volume", 2, 6, 1), AWACS_VOLUME("Master Playback Volume", 5, 6, 1), AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0), AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0), }; -static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac7500[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac7500[] __initdata = { AWACS_VOLUME("Line out Playback Volume", 2, 6, 1), AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0), AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0), }; -static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac5500[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac5500[] __initdata = { AWACS_VOLUME("Headphone Playback Volume", 2, 6, 1), }; -static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac[] __initdata = { AWACS_VOLUME("Master Playback Volume", 2, 6, 1), AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0), }; @@ -642,34 +642,34 @@ static struct snd_kcontrol_new snd_pmac_awacs_mixers_pmac[] __devinitdata = { /* FIXME: is this correct order? * screamer (powerbook G3 pismo) seems to have different bits... */ -static struct snd_kcontrol_new snd_pmac_awacs_mixers2[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_awacs_mixers2[] __initdata = { AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_LINE, 0), AWACS_SWITCH("Mic Capture Switch", 0, SHIFT_MUX_MIC, 0), }; -static struct snd_kcontrol_new snd_pmac_screamer_mixers2[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_screamer_mixers2[] __initdata = { AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0), AWACS_SWITCH("Mic Capture Switch", 0, SHIFT_MUX_LINE, 0), }; -static struct snd_kcontrol_new snd_pmac_awacs_mixers2_pmac5500[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_awacs_mixers2_pmac5500[] __initdata = { AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0), }; -static struct snd_kcontrol_new snd_pmac_awacs_master_sw __devinitdata = +static struct snd_kcontrol_new snd_pmac_awacs_master_sw __initdata = AWACS_SWITCH("Master Playback Switch", 1, SHIFT_HDMUTE, 1); -static struct snd_kcontrol_new snd_pmac_awacs_master_sw_imac __devinitdata = +static struct snd_kcontrol_new snd_pmac_awacs_master_sw_imac __initdata = AWACS_SWITCH("Line out Playback Switch", 1, SHIFT_HDMUTE, 1); -static struct snd_kcontrol_new snd_pmac_awacs_master_sw_pmac5500 __devinitdata = +static struct snd_kcontrol_new snd_pmac_awacs_master_sw_pmac5500 __initdata = AWACS_SWITCH("Headphone Playback Switch", 1, SHIFT_HDMUTE, 1); -static struct snd_kcontrol_new snd_pmac_awacs_mic_boost[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_awacs_mic_boost[] __initdata = { AWACS_SWITCH("Mic Boost Capture Switch", 0, SHIFT_GAINLINE, 0), }; -static struct snd_kcontrol_new snd_pmac_screamer_mic_boost[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_screamer_mic_boost[] __initdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Mic Boost Capture Volume", .info = snd_pmac_screamer_mic_boost_info, @@ -678,34 +678,34 @@ static struct snd_kcontrol_new snd_pmac_screamer_mic_boost[] __devinitdata = { }, }; -static struct snd_kcontrol_new snd_pmac_awacs_mic_boost_pmac7500[] __devinitdata = +static struct snd_kcontrol_new snd_pmac_awacs_mic_boost_pmac7500[] __initdata = { AWACS_SWITCH("Line Boost Capture Switch", 0, SHIFT_GAINLINE, 0), }; -static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_beige[] __devinitdata = +static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_beige[] __initdata = { AWACS_SWITCH("Line Boost Capture Switch", 0, SHIFT_GAINLINE, 0), AWACS_SWITCH("CD Boost Capture Switch", 6, SHIFT_MIC_BOOST, 0), }; -static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_imac[] __devinitdata = +static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_imac[] __initdata = { AWACS_SWITCH("Line Boost Capture Switch", 0, SHIFT_GAINLINE, 0), AWACS_SWITCH("Mic Boost Capture Switch", 6, SHIFT_MIC_BOOST, 0), }; -static struct snd_kcontrol_new snd_pmac_awacs_speaker_vol[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_awacs_speaker_vol[] __initdata = { AWACS_VOLUME("PC Speaker Playback Volume", 4, 6, 1), }; -static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw __devinitdata = +static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw __initdata = AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_SPKMUTE, 1); -static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac1 __devinitdata = +static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac1 __initdata = AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_PAROUT1, 1); -static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac2 __devinitdata = +static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac2 __initdata = AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_PAROUT1, 0); @@ -872,7 +872,7 @@ static void snd_pmac_awacs_update_automute(struct snd_pmac *chip, int do_notify) /* * initialize chip */ -int __devinit +int __init snd_pmac_awacs_init(struct snd_pmac *chip) { int pm7500 = IS_PM7500; diff --git a/trunk/sound/ppc/beep.c b/trunk/sound/ppc/beep.c index a9d350789f55..89f5c328acfe 100644 --- a/trunk/sound/ppc/beep.c +++ b/trunk/sound/ppc/beep.c @@ -215,7 +215,7 @@ static struct snd_kcontrol_new snd_pmac_beep_mixer = { }; /* Initialize beep stuff */ -int __devinit snd_pmac_attach_beep(struct snd_pmac *chip) +int __init snd_pmac_attach_beep(struct snd_pmac *chip) { struct pmac_beep *beep; struct input_dev *input_dev; diff --git a/trunk/sound/ppc/burgundy.c b/trunk/sound/ppc/burgundy.c index 16ed240e423c..45a76297c38d 100644 --- a/trunk/sound/ppc/burgundy.c +++ b/trunk/sound/ppc/burgundy.c @@ -46,12 +46,12 @@ snd_pmac_burgundy_extend_wait(struct snd_pmac *chip) timeout = 50; while (!(in_le32(&chip->awacs->codec_stat) & MASK_EXTEND) && timeout--) udelay(1); - if (timeout < 0) + if (! timeout) printk(KERN_DEBUG "burgundy_extend_wait: timeout #1\n"); timeout = 50; while ((in_le32(&chip->awacs->codec_stat) & MASK_EXTEND) && timeout--) udelay(1); - if (timeout < 0) + if (! timeout) printk(KERN_DEBUG "burgundy_extend_wait: timeout #2\n"); } @@ -468,7 +468,7 @@ static int snd_pmac_burgundy_put_switch_b(struct snd_kcontrol *kcontrol, /* * Burgundy mixers */ -static struct snd_kcontrol_new snd_pmac_burgundy_mixers[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_burgundy_mixers[] __initdata = { BURGUNDY_VOLUME_W("Master Playback Volume", 0, MASK_ADDR_BURGUNDY_MASTER_VOLUME, 8), BURGUNDY_VOLUME_W("CD Capture Volume", 0, @@ -496,7 +496,7 @@ static struct snd_kcontrol_new snd_pmac_burgundy_mixers[] __devinitdata = { */ BURGUNDY_SWITCH_B("PCM Capture Switch", 0, MASK_ADDR_BURGUNDY_HOSTIFEH, 0x01, 0, 0) }; -static struct snd_kcontrol_new snd_pmac_burgundy_mixers_imac[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_burgundy_mixers_imac[] __initdata = { BURGUNDY_VOLUME_W("Line in Capture Volume", 0, MASK_ADDR_BURGUNDY_VOLLINE, 16), BURGUNDY_VOLUME_W("Mic Capture Volume", 0, @@ -522,7 +522,7 @@ static struct snd_kcontrol_new snd_pmac_burgundy_mixers_imac[] __devinitdata = { BURGUNDY_SWITCH_B("Mic Boost Capture Switch", 0, MASK_ADDR_BURGUNDY_INPBOOST, 0x40, 0x80, 1) }; -static struct snd_kcontrol_new snd_pmac_burgundy_mixers_pmac[] __devinitdata = { +static struct snd_kcontrol_new snd_pmac_burgundy_mixers_pmac[] __initdata = { BURGUNDY_VOLUME_W("Line in Capture Volume", 0, MASK_ADDR_BURGUNDY_VOLMIC, 16), BURGUNDY_VOLUME_B("Line in Gain Capture Volume", 0, @@ -538,33 +538,33 @@ static struct snd_kcontrol_new snd_pmac_burgundy_mixers_pmac[] __devinitdata = { /* BURGUNDY_SWITCH_B("Line in Boost Capture Switch", 0, * MASK_ADDR_BURGUNDY_INPBOOST, 0x40, 0x80, 1) */ }; -static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_imac __devinitdata = +static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_imac __initdata = BURGUNDY_SWITCH_B("Master Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, BURGUNDY_OUTPUT_LEFT | BURGUNDY_LINEOUT_LEFT | BURGUNDY_HP_LEFT, BURGUNDY_OUTPUT_RIGHT | BURGUNDY_LINEOUT_RIGHT | BURGUNDY_HP_RIGHT, 1); -static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_pmac __devinitdata = +static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_pmac __initdata = BURGUNDY_SWITCH_B("Master Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, BURGUNDY_OUTPUT_INTERN | BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1); -static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_imac __devinitdata = +static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_imac __initdata = BURGUNDY_SWITCH_B("PC Speaker Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1); -static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_pmac __devinitdata = +static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_pmac __initdata = BURGUNDY_SWITCH_B("PC Speaker Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, BURGUNDY_OUTPUT_INTERN, 0, 0); -static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_imac __devinitdata = +static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_imac __initdata = BURGUNDY_SWITCH_B("Line out Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, BURGUNDY_LINEOUT_LEFT, BURGUNDY_LINEOUT_RIGHT, 1); -static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_pmac __devinitdata = +static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_pmac __initdata = BURGUNDY_SWITCH_B("Line out Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1); -static struct snd_kcontrol_new snd_pmac_burgundy_hp_sw_imac __devinitdata = +static struct snd_kcontrol_new snd_pmac_burgundy_hp_sw_imac __initdata = BURGUNDY_SWITCH_B("Headphone Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, BURGUNDY_HP_LEFT, BURGUNDY_HP_RIGHT, 1); @@ -618,7 +618,7 @@ static void snd_pmac_burgundy_update_automute(struct snd_pmac *chip, int do_noti /* * initialize burgundy */ -int __devinit snd_pmac_burgundy_init(struct snd_pmac *chip) +int __init snd_pmac_burgundy_init(struct snd_pmac *chip) { int imac = machine_is_compatible("iMac"); int i, err; diff --git a/trunk/sound/ppc/daca.c b/trunk/sound/ppc/daca.c index 24200b7bdace..f8d478c2da62 100644 --- a/trunk/sound/ppc/daca.c +++ b/trunk/sound/ppc/daca.c @@ -244,7 +244,7 @@ static void daca_cleanup(struct snd_pmac *chip) } /* exported */ -int __devinit snd_pmac_daca_init(struct snd_pmac *chip) +int __init snd_pmac_daca_init(struct snd_pmac *chip) { int i, err; struct pmac_daca *mix; diff --git a/trunk/sound/ppc/keywest.c b/trunk/sound/ppc/keywest.c index 835fa19ed461..a5afb2682e7f 100644 --- a/trunk/sound/ppc/keywest.c +++ b/trunk/sound/ppc/keywest.c @@ -33,6 +33,10 @@ static struct pmac_keywest *keywest_ctx; +#ifndef i2c_device_name +#define i2c_device_name(x) ((x)->name) +#endif + static int keywest_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -52,7 +56,7 @@ static int keywest_attach_adapter(struct i2c_adapter *adapter) if (! keywest_ctx) return -EINVAL; - if (strncmp(adapter->name, "mac-io", 6)) + if (strncmp(i2c_device_name(adapter), "mac-io", 6)) return 0; /* ignored */ memset(&info, 0, sizeof(struct i2c_board_info)); @@ -105,7 +109,7 @@ void snd_pmac_keywest_cleanup(struct pmac_keywest *i2c) } } -int __devinit snd_pmac_tumbler_post_init(void) +int __init snd_pmac_tumbler_post_init(void) { int err; @@ -120,7 +124,7 @@ int __devinit snd_pmac_tumbler_post_init(void) } /* exported */ -int __devinit snd_pmac_keywest_init(struct pmac_keywest *i2c) +int __init snd_pmac_keywest_init(struct pmac_keywest *i2c) { int err; diff --git a/trunk/sound/ppc/pmac.c b/trunk/sound/ppc/pmac.c index 7bc492ee77ec..9b4e9c316695 100644 --- a/trunk/sound/ppc/pmac.c +++ b/trunk/sound/ppc/pmac.c @@ -702,7 +702,7 @@ static struct snd_pcm_ops snd_pmac_capture_ops = { .pointer = snd_pmac_capture_pointer, }; -int __devinit snd_pmac_pcm_new(struct snd_pmac *chip) +int __init snd_pmac_pcm_new(struct snd_pmac *chip) { struct snd_pcm *pcm; int err; @@ -908,7 +908,7 @@ static int snd_pmac_dev_free(struct snd_device *device) * check the machine support byteswap (little-endian) */ -static void __devinit detect_byte_swap(struct snd_pmac *chip) +static void __init detect_byte_swap(struct snd_pmac *chip) { struct device_node *mio; @@ -934,7 +934,7 @@ static void __devinit detect_byte_swap(struct snd_pmac *chip) /* * detect a sound chip */ -static int __devinit snd_pmac_detect(struct snd_pmac *chip) +static int __init snd_pmac_detect(struct snd_pmac *chip) { struct device_node *sound; struct device_node *dn; @@ -1143,7 +1143,7 @@ static int pmac_hp_detect_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new auto_mute_controls[] __devinitdata = { +static struct snd_kcontrol_new auto_mute_controls[] __initdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Auto Mute Switch", .info = snd_pmac_boolean_mono_info, @@ -1158,7 +1158,7 @@ static struct snd_kcontrol_new auto_mute_controls[] __devinitdata = { }, }; -int __devinit snd_pmac_add_automute(struct snd_pmac *chip) +int __init snd_pmac_add_automute(struct snd_pmac *chip) { int err; chip->auto_mute = 1; @@ -1175,7 +1175,7 @@ int __devinit snd_pmac_add_automute(struct snd_pmac *chip) /* * create and detect a pmac chip record */ -int __devinit snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return) +int __init snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return) { struct snd_pmac *chip; struct device_node *np; diff --git a/trunk/sound/ppc/snd_ps3.c b/trunk/sound/ppc/snd_ps3.c index 53c81a547613..f361c26506aa 100644 --- a/trunk/sound/ppc/snd_ps3.c +++ b/trunk/sound/ppc/snd_ps3.c @@ -18,31 +18,81 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include -#include #include -#include -#include #include - -#include -#include +#include +#include #include #include -#include #include +#include +#include #include - -#include +#include +#include +#include #include +#include #include #include #include -#include "snd_ps3.h" #include "snd_ps3_reg.h" +#include "snd_ps3.h" + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("PS3 sound driver"); +MODULE_AUTHOR("Sony Computer Entertainment Inc."); + +/* module entries */ +static int __init snd_ps3_init(void); +static void __exit snd_ps3_exit(void); + +/* ALSA snd driver ops */ +static int snd_ps3_pcm_open(struct snd_pcm_substream *substream); +static int snd_ps3_pcm_close(struct snd_pcm_substream *substream); +static int snd_ps3_pcm_prepare(struct snd_pcm_substream *substream); +static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream, + int cmd); +static snd_pcm_uframes_t snd_ps3_pcm_pointer(struct snd_pcm_substream + *substream); +static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params); +static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream); +/* ps3_system_bus_driver entries */ +static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev); +static int snd_ps3_driver_remove(struct ps3_system_bus_device *dev); + +/* address setup */ +static int snd_ps3_map_mmio(void); +static void snd_ps3_unmap_mmio(void); +static int snd_ps3_allocate_irq(void); +static void snd_ps3_free_irq(void); +static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start); + +/* interrupt handler */ +static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id); + + +/* set sampling rate/format */ +static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream); +/* take effect parameter change */ +static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card); +/* initialize avsetting and take it effect */ +static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card); +/* setup dma */ +static int snd_ps3_program_dma(struct snd_ps3_card_info *card, + enum snd_ps3_dma_filltype filltype); +static void snd_ps3_wait_for_dma_stop(struct snd_ps3_card_info *card); + +static dma_addr_t v_to_bus(struct snd_ps3_card_info *, void *vaddr, int ch); + + +module_init(snd_ps3_init); +module_exit(snd_ps3_exit); + /* * global */ @@ -115,13 +165,25 @@ static const struct snd_pcm_hardware snd_ps3_pcm_hw = { .fifo_size = PS3_AUDIO_FIFO_SIZE }; +static struct snd_pcm_ops snd_ps3_pcm_spdif_ops = +{ + .open = snd_ps3_pcm_open, + .close = snd_ps3_pcm_close, + .prepare = snd_ps3_pcm_prepare, + .ioctl = snd_pcm_lib_ioctl, + .trigger = snd_ps3_pcm_trigger, + .pointer = snd_ps3_pcm_pointer, + .hw_params = snd_ps3_pcm_hw_params, + .hw_free = snd_ps3_pcm_hw_free +}; + static int snd_ps3_verify_dma_stop(struct snd_ps3_card_info *card, int count, int force_stop) { int dma_ch, done, retries, stop_forced = 0; uint32_t status; - for (dma_ch = 0; dma_ch < 8; dma_ch++) { + for (dma_ch = 0; dma_ch < 8; dma_ch ++) { retries = count; do { status = read_reg(PS3_AUDIO_KICK(dma_ch)) & @@ -197,7 +259,9 @@ static void snd_ps3_kick_dma(struct snd_ps3_card_info *card) /* * convert virtual addr to ioif bus addr. */ -static dma_addr_t v_to_bus(struct snd_ps3_card_info *card, void *paddr, int ch) +static dma_addr_t v_to_bus(struct snd_ps3_card_info *card, + void * paddr, + int ch) { return card->dma_start_bus_addr[ch] + (paddr - card->dma_start_vaddr[ch]); @@ -257,7 +321,7 @@ static int snd_ps3_program_dma(struct snd_ps3_card_info *card, spin_lock_irqsave(&card->dma_lock, irqsave); for (ch = 0; ch < 2; ch++) { start_vaddr = card->dma_next_transfer_vaddr[0]; - for (stage = 0; stage < fill_stages; stage++) { + for (stage = 0; stage < fill_stages; stage ++) { dma_ch = stage * 2 + ch; if (silent) dma_addr = card->null_buffer_start_dma_addr; @@ -307,71 +371,6 @@ static int snd_ps3_program_dma(struct snd_ps3_card_info *card, return 0; } -/* - * Interrupt handler - */ -static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id) -{ - - uint32_t port_intr; - int underflow_occured = 0; - struct snd_ps3_card_info *card = dev_id; - - if (!card->running) { - update_reg(PS3_AUDIO_AX_IS, 0); - update_reg(PS3_AUDIO_INTR_0, 0); - return IRQ_HANDLED; - } - - port_intr = read_reg(PS3_AUDIO_AX_IS); - /* - *serial buffer empty detected (every 4 times), - *program next dma and kick it - */ - if (port_intr & PS3_AUDIO_AX_IE_ASOBEIE(0)) { - write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBEIE(0)); - if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) { - write_reg(PS3_AUDIO_AX_IS, port_intr); - underflow_occured = 1; - } - if (card->silent) { - /* we are still in silent time */ - snd_ps3_program_dma(card, - (underflow_occured) ? - SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL : - SND_PS3_DMA_FILLTYPE_SILENT_RUNNING); - snd_ps3_kick_dma(card); - card->silent--; - } else { - snd_ps3_program_dma(card, - (underflow_occured) ? - SND_PS3_DMA_FILLTYPE_FIRSTFILL : - SND_PS3_DMA_FILLTYPE_RUNNING); - snd_ps3_kick_dma(card); - snd_pcm_period_elapsed(card->substream); - } - } else if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) { - write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBUIE(0)); - /* - * serial out underflow, but buffer empty not detected. - * in this case, fill fifo with 0 to recover. After - * filling dummy data, serial automatically start to - * consume them and then will generate normal buffer - * empty interrupts. - * If both buffer underflow and buffer empty are occured, - * it is better to do nomal data transfer than empty one - */ - snd_ps3_program_dma(card, - SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); - snd_ps3_kick_dma(card); - snd_ps3_program_dma(card, - SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); - snd_ps3_kick_dma(card); - } - /* clear interrupt cause */ - return IRQ_HANDLED; -}; - /* * audio mute on/off * mute_on : 0 output enabled @@ -382,142 +381,6 @@ static int snd_ps3_mute(int mute_on) return ps3av_audio_mute(mute_on); } -/* - * av setting - * NOTE: calling this function may generate audio interrupt. - */ -static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card) -{ - int ret, retries, i; - pr_debug("%s: start\n", __func__); - - ret = ps3av_set_audio_mode(card->avs.avs_audio_ch, - card->avs.avs_audio_rate, - card->avs.avs_audio_width, - card->avs.avs_audio_format, - card->avs.avs_audio_source); - /* - * Reset the following unwanted settings: - */ - - /* disable all 3wire buffers */ - update_mask_reg(PS3_AUDIO_AO_3WMCTRL, - ~(PS3_AUDIO_AO_3WMCTRL_ASOEN(0) | - PS3_AUDIO_AO_3WMCTRL_ASOEN(1) | - PS3_AUDIO_AO_3WMCTRL_ASOEN(2) | - PS3_AUDIO_AO_3WMCTRL_ASOEN(3)), - 0); - wmb(); /* ensure the hardware sees the change */ - /* wait for actually stopped */ - retries = 1000; - while ((read_reg(PS3_AUDIO_AO_3WMCTRL) & - (PS3_AUDIO_AO_3WMCTRL_ASORUN(0) | - PS3_AUDIO_AO_3WMCTRL_ASORUN(1) | - PS3_AUDIO_AO_3WMCTRL_ASORUN(2) | - PS3_AUDIO_AO_3WMCTRL_ASORUN(3))) && - --retries) { - udelay(1); - } - - /* reset buffer pointer */ - for (i = 0; i < 4; i++) { - update_reg(PS3_AUDIO_AO_3WCTRL(i), - PS3_AUDIO_AO_3WCTRL_ASOBRST_RESET); - udelay(10); - } - wmb(); /* ensure the hardware actually start resetting */ - - /* enable 3wire#0 buffer */ - update_reg(PS3_AUDIO_AO_3WMCTRL, PS3_AUDIO_AO_3WMCTRL_ASOEN(0)); - - - /* In 24bit mode,ALSA inserts a zero byte at first byte of per sample */ - update_mask_reg(PS3_AUDIO_AO_3WCTRL(0), - ~PS3_AUDIO_AO_3WCTRL_ASODF, - PS3_AUDIO_AO_3WCTRL_ASODF_LSB); - update_mask_reg(PS3_AUDIO_AO_SPDCTRL(0), - ~PS3_AUDIO_AO_SPDCTRL_SPODF, - PS3_AUDIO_AO_SPDCTRL_SPODF_LSB); - /* ensure all the setting above is written back to register */ - wmb(); - /* avsetting driver altered AX_IE, caller must reset it if you want */ - pr_debug("%s: end\n", __func__); - return ret; -} - -/* - * set sampling rate according to the substream - */ -static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream) -{ - struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream); - struct snd_ps3_avsetting_info avs; - int ret; - - avs = card->avs; - - pr_debug("%s: called freq=%d width=%d\n", __func__, - substream->runtime->rate, - snd_pcm_format_width(substream->runtime->format)); - - pr_debug("%s: before freq=%d width=%d\n", __func__, - card->avs.avs_audio_rate, card->avs.avs_audio_width); - - /* sample rate */ - switch (substream->runtime->rate) { - case 44100: - avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_44K; - break; - case 48000: - avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K; - break; - case 88200: - avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_88K; - break; - case 96000: - avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_96K; - break; - default: - pr_info("%s: invalid rate %d\n", __func__, - substream->runtime->rate); - return 1; - } - - /* width */ - switch (snd_pcm_format_width(substream->runtime->format)) { - case 16: - avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16; - break; - case 24: - avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_24; - break; - default: - pr_info("%s: invalid width %d\n", __func__, - snd_pcm_format_width(substream->runtime->format)); - return 1; - } - - memcpy(avs.avs_cs_info, ps3av_mode_cs_info, 8); - - if (memcmp(&card->avs, &avs, sizeof(avs))) { - pr_debug("%s: after freq=%d width=%d\n", __func__, - card->avs.avs_audio_rate, card->avs.avs_audio_width); - - card->avs = avs; - snd_ps3_change_avsetting(card); - ret = 0; - } else - ret = 1; - - /* check CS non-audio bit and mute accordingly */ - if (avs.avs_cs_info[0] & 0x02) - ps3av_audio_mute_analog(1); /* mute if non-audio */ - else - ps3av_audio_mute_analog(0); - - return ret; -} - /* * PCM operators */ @@ -543,13 +406,6 @@ static int snd_ps3_pcm_open(struct snd_pcm_substream *substream) return 0; }; -static int snd_ps3_pcm_close(struct snd_pcm_substream *substream) -{ - /* mute on */ - snd_ps3_mute(1); - return 0; -}; - static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { @@ -561,13 +417,6 @@ static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream, return 0; }; -static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream) -{ - int ret; - ret = snd_pcm_lib_free_pages(substream); - return ret; -}; - static int snd_ps3_delay_to_bytes(struct snd_pcm_substream *substream, unsigned int delay_ms) { @@ -628,84 +477,280 @@ static int snd_ps3_pcm_prepare(struct snd_pcm_substream *substream) card->dma_start_bus_addr[SND_PS3_CH_R] = runtime->dma_addr + (runtime->dma_bytes / 2); - pr_debug("%s: vaddr=%p bus=%#llx\n", __func__, - card->dma_start_vaddr[SND_PS3_CH_L], - card->dma_start_bus_addr[SND_PS3_CH_L]); + pr_debug("%s: vaddr=%p bus=%#llx\n", __func__, + card->dma_start_vaddr[SND_PS3_CH_L], + card->dma_start_bus_addr[SND_PS3_CH_L]); + + } + spin_unlock_irqrestore(&card->dma_lock, irqsave); + + /* ensure the hardware sees the change */ + mb(); + + return 0; +}; + +static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream); + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + /* clear outstanding interrupts */ + update_reg(PS3_AUDIO_AX_IS, 0); + + spin_lock(&card->dma_lock); + { + card->running = 1; + } + spin_unlock(&card->dma_lock); + + snd_ps3_program_dma(card, + SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); + snd_ps3_kick_dma(card); + while (read_reg(PS3_AUDIO_KICK(7)) & + PS3_AUDIO_KICK_STATUS_MASK) { + udelay(1); + } + snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_RUNNING); + snd_ps3_kick_dma(card); + break; + + case SNDRV_PCM_TRIGGER_STOP: + spin_lock(&card->dma_lock); + { + card->running = 0; + } + spin_unlock(&card->dma_lock); + snd_ps3_wait_for_dma_stop(card); + break; + default: + break; + + } + + return ret; +}; + +/* + * report current pointer + */ +static snd_pcm_uframes_t snd_ps3_pcm_pointer( + struct snd_pcm_substream *substream) +{ + struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream); + size_t bytes; + snd_pcm_uframes_t ret; + + spin_lock(&card->dma_lock); + { + bytes = (size_t)(card->dma_last_transfer_vaddr[SND_PS3_CH_L] - + card->dma_start_vaddr[SND_PS3_CH_L]); + } + spin_unlock(&card->dma_lock); + + ret = bytes_to_frames(substream->runtime, bytes * 2); + + return ret; +}; + +static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream) +{ + int ret; + ret = snd_pcm_lib_free_pages(substream); + return ret; +}; + +static int snd_ps3_pcm_close(struct snd_pcm_substream *substream) +{ + /* mute on */ + snd_ps3_mute(1); + return 0; +}; + +static void snd_ps3_audio_fixup(struct snd_ps3_card_info *card) +{ + /* + * avsetting driver seems to never change the followings + * so, init them here once + */ + + /* no dma interrupt needed */ + write_reg(PS3_AUDIO_INTR_EN_0, 0); + + /* use every 4 buffer empty interrupt */ + update_mask_reg(PS3_AUDIO_AX_IC, + PS3_AUDIO_AX_IC_AASOIMD_MASK, + PS3_AUDIO_AX_IC_AASOIMD_EVERY4); + + /* enable 3wire clocks */ + update_mask_reg(PS3_AUDIO_AO_3WMCTRL, + ~(PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_DISABLED | + PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_DISABLED), + 0); + update_reg(PS3_AUDIO_AO_3WMCTRL, + PS3_AUDIO_AO_3WMCTRL_ASOPLRCK_DEFAULT); +} + +/* + * av setting + * NOTE: calling this function may generate audio interrupt. + */ +static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card) +{ + int ret, retries, i; + pr_debug("%s: start\n", __func__); + + ret = ps3av_set_audio_mode(card->avs.avs_audio_ch, + card->avs.avs_audio_rate, + card->avs.avs_audio_width, + card->avs.avs_audio_format, + card->avs.avs_audio_source); + /* + * Reset the following unwanted settings: + */ + + /* disable all 3wire buffers */ + update_mask_reg(PS3_AUDIO_AO_3WMCTRL, + ~(PS3_AUDIO_AO_3WMCTRL_ASOEN(0) | + PS3_AUDIO_AO_3WMCTRL_ASOEN(1) | + PS3_AUDIO_AO_3WMCTRL_ASOEN(2) | + PS3_AUDIO_AO_3WMCTRL_ASOEN(3)), + 0); + wmb(); /* ensure the hardware sees the change */ + /* wait for actually stopped */ + retries = 1000; + while ((read_reg(PS3_AUDIO_AO_3WMCTRL) & + (PS3_AUDIO_AO_3WMCTRL_ASORUN(0) | + PS3_AUDIO_AO_3WMCTRL_ASORUN(1) | + PS3_AUDIO_AO_3WMCTRL_ASORUN(2) | + PS3_AUDIO_AO_3WMCTRL_ASORUN(3))) && + --retries) { + udelay(1); + } + + /* reset buffer pointer */ + for (i = 0; i < 4; i++) { + update_reg(PS3_AUDIO_AO_3WCTRL(i), + PS3_AUDIO_AO_3WCTRL_ASOBRST_RESET); + udelay(10); + } + wmb(); /* ensure the hardware actually start resetting */ + + /* enable 3wire#0 buffer */ + update_reg(PS3_AUDIO_AO_3WMCTRL, PS3_AUDIO_AO_3WMCTRL_ASOEN(0)); + + + /* In 24bit mode,ALSA inserts a zero byte at first byte of per sample */ + update_mask_reg(PS3_AUDIO_AO_3WCTRL(0), + ~PS3_AUDIO_AO_3WCTRL_ASODF, + PS3_AUDIO_AO_3WCTRL_ASODF_LSB); + update_mask_reg(PS3_AUDIO_AO_SPDCTRL(0), + ~PS3_AUDIO_AO_SPDCTRL_SPODF, + PS3_AUDIO_AO_SPDCTRL_SPODF_LSB); + /* ensure all the setting above is written back to register */ + wmb(); + /* avsetting driver altered AX_IE, caller must reset it if you want */ + pr_debug("%s: end\n", __func__); + return ret; +} + +static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card) +{ + int ret; + pr_debug("%s: start\n", __func__); + card->avs.avs_audio_ch = PS3AV_CMD_AUDIO_NUM_OF_CH_2; + card->avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K; + card->avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16; + card->avs.avs_audio_format = PS3AV_CMD_AUDIO_FORMAT_PCM; + card->avs.avs_audio_source = PS3AV_CMD_AUDIO_SOURCE_SERIAL; + memcpy(card->avs.avs_cs_info, ps3av_mode_cs_info, 8); - } - spin_unlock_irqrestore(&card->dma_lock, irqsave); + ret = snd_ps3_change_avsetting(card); - /* ensure the hardware sees the change */ - mb(); + snd_ps3_audio_fixup(card); - return 0; -}; + /* to start to generate SPDIF signal, fill data */ + snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); + snd_ps3_kick_dma(card); + pr_debug("%s: end\n", __func__); + return ret; +} -static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream, - int cmd) +/* + * set sampling rate according to the substream + */ +static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream) { struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream); - int ret = 0; + struct snd_ps3_avsetting_info avs; + int ret; - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - /* clear outstanding interrupts */ - update_reg(PS3_AUDIO_AX_IS, 0); + avs = card->avs; - spin_lock(&card->dma_lock); - { - card->running = 1; - } - spin_unlock(&card->dma_lock); + pr_debug("%s: called freq=%d width=%d\n", __func__, + substream->runtime->rate, + snd_pcm_format_width(substream->runtime->format)); - snd_ps3_program_dma(card, - SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); - snd_ps3_kick_dma(card); - while (read_reg(PS3_AUDIO_KICK(7)) & - PS3_AUDIO_KICK_STATUS_MASK) { - udelay(1); - } - snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_RUNNING); - snd_ps3_kick_dma(card); - break; + pr_debug("%s: before freq=%d width=%d\n", __func__, + card->avs.avs_audio_rate, card->avs.avs_audio_width); - case SNDRV_PCM_TRIGGER_STOP: - spin_lock(&card->dma_lock); - { - card->running = 0; - } - spin_unlock(&card->dma_lock); - snd_ps3_wait_for_dma_stop(card); + /* sample rate */ + switch (substream->runtime->rate) { + case 44100: + avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_44K; break; - default: + case 48000: + avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K; + break; + case 88200: + avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_88K; break; + case 96000: + avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_96K; + break; + default: + pr_info("%s: invalid rate %d\n", __func__, + substream->runtime->rate); + return 1; + } + /* width */ + switch (snd_pcm_format_width(substream->runtime->format)) { + case 16: + avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16; + break; + case 24: + avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_24; + break; + default: + pr_info("%s: invalid width %d\n", __func__, + snd_pcm_format_width(substream->runtime->format)); + return 1; } - return ret; -}; + memcpy(avs.avs_cs_info, ps3av_mode_cs_info, 8); -/* - * report current pointer - */ -static snd_pcm_uframes_t snd_ps3_pcm_pointer( - struct snd_pcm_substream *substream) -{ - struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream); - size_t bytes; - snd_pcm_uframes_t ret; + if (memcmp(&card->avs, &avs, sizeof(avs))) { + pr_debug("%s: after freq=%d width=%d\n", __func__, + card->avs.avs_audio_rate, card->avs.avs_audio_width); - spin_lock(&card->dma_lock); - { - bytes = (size_t)(card->dma_last_transfer_vaddr[SND_PS3_CH_L] - - card->dma_start_vaddr[SND_PS3_CH_L]); - } - spin_unlock(&card->dma_lock); + card->avs = avs; + snd_ps3_change_avsetting(card); + ret = 0; + } else + ret = 1; - ret = bytes_to_frames(substream->runtime, bytes * 2); + /* check CS non-audio bit and mute accordingly */ + if (avs.avs_cs_info[0] & 0x02) + ps3av_audio_mute_analog(1); /* mute if non-audio */ + else + ps3av_audio_mute_analog(0); return ret; -}; +} /* * SPDIF status bits controls @@ -753,39 +798,28 @@ static struct snd_kcontrol_new spdif_ctls[] = { { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK), + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK), .info = snd_ps3_spdif_mask_info, .get = snd_ps3_spdif_cmask_get, }, { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PRO_MASK), + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK), .info = snd_ps3_spdif_mask_info, .get = snd_ps3_spdif_pmask_get, }, { .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), .info = snd_ps3_spdif_mask_info, .get = snd_ps3_spdif_default_get, .put = snd_ps3_spdif_default_put, }, }; -static struct snd_pcm_ops snd_ps3_pcm_spdif_ops = { - .open = snd_ps3_pcm_open, - .close = snd_ps3_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_ps3_pcm_hw_params, - .hw_free = snd_ps3_pcm_hw_free, - .prepare = snd_ps3_pcm_prepare, - .trigger = snd_ps3_pcm_trigger, - .pointer = snd_ps3_pcm_pointer, -}; - -static int __devinit snd_ps3_map_mmio(void) +static int snd_ps3_map_mmio(void) { the_card.mapped_mmio_vaddr = ioremap(the_card.ps3_dev->m_region->bus_addr, @@ -807,7 +841,7 @@ static void snd_ps3_unmap_mmio(void) the_card.mapped_mmio_vaddr = NULL; } -static int __devinit snd_ps3_allocate_irq(void) +static int snd_ps3_allocate_irq(void) { int ret; u64 lpar_addr, lpar_size; @@ -865,7 +899,7 @@ static void snd_ps3_free_irq(void) ps3_irq_plug_destroy(the_card.irq_no); } -static void __devinit snd_ps3_audio_set_base_addr(uint64_t ioaddr_start) +static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start) { uint64_t val; int ret; @@ -881,53 +915,7 @@ static void __devinit snd_ps3_audio_set_base_addr(uint64_t ioaddr_start) ret); } -static void __devinit snd_ps3_audio_fixup(struct snd_ps3_card_info *card) -{ - /* - * avsetting driver seems to never change the followings - * so, init them here once - */ - - /* no dma interrupt needed */ - write_reg(PS3_AUDIO_INTR_EN_0, 0); - - /* use every 4 buffer empty interrupt */ - update_mask_reg(PS3_AUDIO_AX_IC, - PS3_AUDIO_AX_IC_AASOIMD_MASK, - PS3_AUDIO_AX_IC_AASOIMD_EVERY4); - - /* enable 3wire clocks */ - update_mask_reg(PS3_AUDIO_AO_3WMCTRL, - ~(PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_DISABLED | - PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_DISABLED), - 0); - update_reg(PS3_AUDIO_AO_3WMCTRL, - PS3_AUDIO_AO_3WMCTRL_ASOPLRCK_DEFAULT); -} - -static int __devinit snd_ps3_init_avsetting(struct snd_ps3_card_info *card) -{ - int ret; - pr_debug("%s: start\n", __func__); - card->avs.avs_audio_ch = PS3AV_CMD_AUDIO_NUM_OF_CH_2; - card->avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K; - card->avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16; - card->avs.avs_audio_format = PS3AV_CMD_AUDIO_FORMAT_PCM; - card->avs.avs_audio_source = PS3AV_CMD_AUDIO_SOURCE_SERIAL; - memcpy(card->avs.avs_cs_info, ps3av_mode_cs_info, 8); - - ret = snd_ps3_change_avsetting(card); - - snd_ps3_audio_fixup(card); - - /* to start to generate SPDIF signal, fill data */ - snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); - snd_ps3_kick_dma(card); - pr_debug("%s: end\n", __func__); - return ret; -} - -static int __devinit snd_ps3_driver_probe(struct ps3_system_bus_device *dev) +static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev) { int i, ret; u64 lpar_addr, lpar_size; @@ -1032,12 +1020,11 @@ static int __devinit snd_ps3_driver_probe(struct ps3_system_bus_device *dev) * its size should be lager than PS3_AUDIO_FIFO_STAGE_SIZE * 2 * PAGE_SIZE is enogh */ - the_card.null_buffer_start_vaddr = - dma_alloc_coherent(&the_card.ps3_dev->core, - PAGE_SIZE, - &the_card.null_buffer_start_dma_addr, - GFP_KERNEL); - if (!the_card.null_buffer_start_vaddr) { + if (!(the_card.null_buffer_start_vaddr = + dma_alloc_coherent(&the_card.ps3_dev->core, + PAGE_SIZE, + &the_card.null_buffer_start_dma_addr, + GFP_KERNEL))) { pr_info("%s: nullbuffer alloc failed\n", __func__); goto clean_preallocate; } @@ -1127,6 +1114,71 @@ static struct ps3_system_bus_driver snd_ps3_bus_driver_info = { }; +/* + * Interrupt handler + */ +static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id) +{ + + uint32_t port_intr; + int underflow_occured = 0; + struct snd_ps3_card_info *card = dev_id; + + if (!card->running) { + update_reg(PS3_AUDIO_AX_IS, 0); + update_reg(PS3_AUDIO_INTR_0, 0); + return IRQ_HANDLED; + } + + port_intr = read_reg(PS3_AUDIO_AX_IS); + /* + *serial buffer empty detected (every 4 times), + *program next dma and kick it + */ + if (port_intr & PS3_AUDIO_AX_IE_ASOBEIE(0)) { + write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBEIE(0)); + if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) { + write_reg(PS3_AUDIO_AX_IS, port_intr); + underflow_occured = 1; + } + if (card->silent) { + /* we are still in silent time */ + snd_ps3_program_dma(card, + (underflow_occured) ? + SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL : + SND_PS3_DMA_FILLTYPE_SILENT_RUNNING); + snd_ps3_kick_dma(card); + card->silent --; + } else { + snd_ps3_program_dma(card, + (underflow_occured) ? + SND_PS3_DMA_FILLTYPE_FIRSTFILL : + SND_PS3_DMA_FILLTYPE_RUNNING); + snd_ps3_kick_dma(card); + snd_pcm_period_elapsed(card->substream); + } + } else if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) { + write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBUIE(0)); + /* + * serial out underflow, but buffer empty not detected. + * in this case, fill fifo with 0 to recover. After + * filling dummy data, serial automatically start to + * consume them and then will generate normal buffer + * empty interrupts. + * If both buffer underflow and buffer empty are occured, + * it is better to do nomal data transfer than empty one + */ + snd_ps3_program_dma(card, + SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); + snd_ps3_kick_dma(card); + snd_ps3_program_dma(card, + SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL); + snd_ps3_kick_dma(card); + } + /* clear interrupt cause */ + return IRQ_HANDLED; +}; + /* * module/subsystem initialize/terminate */ @@ -1145,15 +1197,10 @@ static int __init snd_ps3_init(void) return ret; } -module_init(snd_ps3_init); static void __exit snd_ps3_exit(void) { ps3_system_bus_driver_unregister(&snd_ps3_bus_driver_info); } -module_exit(snd_ps3_exit); -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("PS3 sound driver"); -MODULE_AUTHOR("Sony Computer Entertainment Inc."); MODULE_ALIAS(PS3_MODULE_ALIAS_SOUND); diff --git a/trunk/sound/ppc/tumbler.c b/trunk/sound/ppc/tumbler.c index 08e584d1453a..40222fcc0878 100644 --- a/trunk/sound/ppc/tumbler.c +++ b/trunk/sound/ppc/tumbler.c @@ -838,7 +838,7 @@ static int snapper_put_capture_source(struct snd_kcontrol *kcontrol, /* */ -static struct snd_kcontrol_new tumbler_mixers[] __devinitdata = { +static struct snd_kcontrol_new tumbler_mixers[] __initdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Volume", .info = tumbler_info_master_volume, @@ -862,7 +862,7 @@ static struct snd_kcontrol_new tumbler_mixers[] __devinitdata = { }, }; -static struct snd_kcontrol_new snapper_mixers[] __devinitdata = { +static struct snd_kcontrol_new snapper_mixers[] __initdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Volume", .info = tumbler_info_master_volume, @@ -895,7 +895,7 @@ static struct snd_kcontrol_new snapper_mixers[] __devinitdata = { }, }; -static struct snd_kcontrol_new tumbler_hp_sw __devinitdata = { +static struct snd_kcontrol_new tumbler_hp_sw __initdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Headphone Playback Switch", .info = snd_pmac_boolean_mono_info, @@ -903,7 +903,7 @@ static struct snd_kcontrol_new tumbler_hp_sw __devinitdata = { .put = tumbler_put_mute_switch, .private_value = TUMBLER_MUTE_HP, }; -static struct snd_kcontrol_new tumbler_speaker_sw __devinitdata = { +static struct snd_kcontrol_new tumbler_speaker_sw __initdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PC Speaker Playback Switch", .info = snd_pmac_boolean_mono_info, @@ -911,7 +911,7 @@ static struct snd_kcontrol_new tumbler_speaker_sw __devinitdata = { .put = tumbler_put_mute_switch, .private_value = TUMBLER_MUTE_AMP, }; -static struct snd_kcontrol_new tumbler_lineout_sw __devinitdata = { +static struct snd_kcontrol_new tumbler_lineout_sw __initdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Line Out Playback Switch", .info = snd_pmac_boolean_mono_info, @@ -919,7 +919,7 @@ static struct snd_kcontrol_new tumbler_lineout_sw __devinitdata = { .put = tumbler_put_mute_switch, .private_value = TUMBLER_MUTE_LINE, }; -static struct snd_kcontrol_new tumbler_drc_sw __devinitdata = { +static struct snd_kcontrol_new tumbler_drc_sw __initdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "DRC Switch", .info = snd_pmac_boolean_mono_info, @@ -1269,7 +1269,7 @@ static void tumbler_resume(struct snd_pmac *chip) #endif /* initialize tumbler */ -static int __devinit tumbler_init(struct snd_pmac *chip) +static int __init tumbler_init(struct snd_pmac *chip) { int irq; struct pmac_tumbler *mix = chip->mixer_data; @@ -1339,7 +1339,7 @@ static void tumbler_cleanup(struct snd_pmac *chip) } /* exported */ -int __devinit snd_pmac_tumbler_init(struct snd_pmac *chip) +int __init snd_pmac_tumbler_init(struct snd_pmac *chip) { int i, err; struct pmac_tumbler *mix; diff --git a/trunk/sound/soc/Kconfig b/trunk/sound/soc/Kconfig index d3e786a9a0a7..3d2bb6fc6dcc 100644 --- a/trunk/sound/soc/Kconfig +++ b/trunk/sound/soc/Kconfig @@ -32,9 +32,7 @@ source "sound/soc/fsl/Kconfig" source "sound/soc/omap/Kconfig" source "sound/soc/pxa/Kconfig" source "sound/soc/s3c24xx/Kconfig" -source "sound/soc/s6000/Kconfig" source "sound/soc/sh/Kconfig" -source "sound/soc/txx9/Kconfig" # Supported codecs source "sound/soc/codecs/Kconfig" diff --git a/trunk/sound/soc/Makefile b/trunk/sound/soc/Makefile index 6f1e28de23cf..0237879fd412 100644 --- a/trunk/sound/soc/Makefile +++ b/trunk/sound/soc/Makefile @@ -10,6 +10,4 @@ obj-$(CONFIG_SND_SOC) += fsl/ obj-$(CONFIG_SND_SOC) += omap/ obj-$(CONFIG_SND_SOC) += pxa/ obj-$(CONFIG_SND_SOC) += s3c24xx/ -obj-$(CONFIG_SND_SOC) += s6000/ obj-$(CONFIG_SND_SOC) += sh/ -obj-$(CONFIG_SND_SOC) += txx9/ diff --git a/trunk/sound/soc/atmel/Kconfig b/trunk/sound/soc/atmel/Kconfig index e720d5e6f04c..a608d7009dbd 100644 --- a/trunk/sound/soc/atmel/Kconfig +++ b/trunk/sound/soc/atmel/Kconfig @@ -41,11 +41,3 @@ config SND_AT32_SOC_PLAYPAQ_SLAVE and FRAME signals on the PlayPaq. Unless you want to play with the AT32 as the SSC master, you probably want to say N here, as this will give you better sound quality. - -config SND_AT91_SOC_AFEB9260 - tristate "SoC Audio support for AFEB9260 board" - depends on ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC - select SND_ATMEL_SOC_SSC - select SND_SOC_TLV320AIC23 - help - Say Y here to support sound on AFEB9260 board. diff --git a/trunk/sound/soc/atmel/Makefile b/trunk/sound/soc/atmel/Makefile index e7ea56bd5f82..f54a7cc68e66 100644 --- a/trunk/sound/soc/atmel/Makefile +++ b/trunk/sound/soc/atmel/Makefile @@ -13,4 +13,3 @@ snd-soc-playpaq-objs := playpaq_wm8510.o obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o obj-$(CONFIG_SND_AT32_SOC_PLAYPAQ) += snd-soc-playpaq.o -obj-$(CONFIG_SND_AT91_SOC_AFEB9260) += snd-soc-afeb9260.o diff --git a/trunk/sound/soc/atmel/playpaq_wm8510.c b/trunk/sound/soc/atmel/playpaq_wm8510.c index 9eb610c2ba91..70657534e6b1 100644 --- a/trunk/sound/soc/atmel/playpaq_wm8510.c +++ b/trunk/sound/soc/atmel/playpaq_wm8510.c @@ -117,7 +117,7 @@ static struct ssc_clock_data playpaq_wm8510_calc_ssc_clock( * Find actual rate, compare to requested rate */ actual_rate = (cd.ssc_rate / (cd.cmr_div * 2)) / (2 * (cd.period + 1)); - pr_debug("playpaq_wm8510: Request rate = %u, actual rate = %u\n", + pr_debug("playpaq_wm8510: Request rate = %d, actual rate = %d\n", rate, actual_rate); diff --git a/trunk/sound/soc/atmel/snd-soc-afeb9260.c b/trunk/sound/soc/atmel/snd-soc-afeb9260.c deleted file mode 100644 index 23349de27313..000000000000 --- a/trunk/sound/soc/atmel/snd-soc-afeb9260.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - * afeb9260.c -- SoC audio for AFEB9260 - * - * Copyright (C) 2009 Sergey Lapin - * - * 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. - * - * This program 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 program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "../codecs/tlv320aic23.h" -#include "atmel-pcm.h" -#include "atmel_ssc_dai.h" - -#define CODEC_CLOCK 12000000 - -static int afeb9260_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - int err; - - /* Set codec DAI configuration */ - err = snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_I2S| - SND_SOC_DAIFMT_NB_IF | - SND_SOC_DAIFMT_CBM_CFM); - if (err < 0) { - printk(KERN_ERR "can't set codec DAI configuration\n"); - return err; - } - - /* Set cpu DAI configuration */ - err = snd_soc_dai_set_fmt(cpu_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_IF | - SND_SOC_DAIFMT_CBM_CFM); - if (err < 0) { - printk(KERN_ERR "can't set cpu DAI configuration\n"); - return err; - } - - /* Set the codec system clock for DAC and ADC */ - err = - snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_IN); - - if (err < 0) { - printk(KERN_ERR "can't set codec system clock\n"); - return err; - } - - return err; -} - -static struct snd_soc_ops afeb9260_ops = { - .hw_params = afeb9260_hw_params, -}; - -static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_LINE("Line In", NULL), - SND_SOC_DAPM_MIC("Mic Jack", NULL), -}; - -static const struct snd_soc_dapm_route audio_map[] = { - {"Headphone Jack", NULL, "LHPOUT"}, - {"Headphone Jack", NULL, "RHPOUT"}, - - {"LLINEIN", NULL, "Line In"}, - {"RLINEIN", NULL, "Line In"}, - - {"MICIN", NULL, "Mic Jack"}, -}; - -static int afeb9260_tlv320aic23_init(struct snd_soc_codec *codec) -{ - - /* Add afeb9260 specific widgets */ - snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets, - ARRAY_SIZE(tlv320aic23_dapm_widgets)); - - /* Set up afeb9260 specific audio path audio_map */ - snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - - snd_soc_dapm_enable_pin(codec, "Headphone Jack"); - snd_soc_dapm_enable_pin(codec, "Line In"); - snd_soc_dapm_enable_pin(codec, "Mic Jack"); - - snd_soc_dapm_sync(codec); - - return 0; -} - -/* Digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link afeb9260_dai = { - .name = "TLV320AIC23", - .stream_name = "AIC23", - .cpu_dai = &atmel_ssc_dai[0], - .codec_dai = &tlv320aic23_dai, - .init = afeb9260_tlv320aic23_init, - .ops = &afeb9260_ops, -}; - -/* Audio machine driver */ -static struct snd_soc_card snd_soc_machine_afeb9260 = { - .name = "AFEB9260", - .platform = &atmel_soc_platform, - .dai_link = &afeb9260_dai, - .num_links = 1, -}; - -/* Audio subsystem */ -static struct snd_soc_device afeb9260_snd_devdata = { - .card = &snd_soc_machine_afeb9260, - .codec_dev = &soc_codec_dev_tlv320aic23, -}; - -static struct platform_device *afeb9260_snd_device; - -static int __init afeb9260_soc_init(void) -{ - int err; - struct device *dev; - struct atmel_ssc_info *ssc_p = afeb9260_dai.cpu_dai->private_data; - struct ssc_device *ssc = NULL; - - if (!(machine_is_afeb9260())) - return -ENODEV; - - ssc = ssc_request(0); - if (IS_ERR(ssc)) { - printk(KERN_ERR "ASoC: Failed to request SSC 0\n"); - err = PTR_ERR(ssc); - ssc = NULL; - goto err_ssc; - } - ssc_p->ssc = ssc; - - afeb9260_snd_device = platform_device_alloc("soc-audio", -1); - if (!afeb9260_snd_device) { - printk(KERN_ERR "ASoC: Platform device allocation failed\n"); - return -ENOMEM; - } - - platform_set_drvdata(afeb9260_snd_device, &afeb9260_snd_devdata); - afeb9260_snd_devdata.dev = &afeb9260_snd_device->dev; - err = platform_device_add(afeb9260_snd_device); - if (err) - goto err1; - - dev = &afeb9260_snd_device->dev; - - return 0; -err1: - platform_device_del(afeb9260_snd_device); - platform_device_put(afeb9260_snd_device); -err_ssc: - return err; - -} - -static void __exit afeb9260_soc_exit(void) -{ - platform_device_unregister(afeb9260_snd_device); -} - -module_init(afeb9260_soc_init); -module_exit(afeb9260_soc_exit); - -MODULE_AUTHOR("Sergey Lapin "); -MODULE_DESCRIPTION("ALSA SoC for AFEB9260"); -MODULE_LICENSE("GPL"); - diff --git a/trunk/sound/soc/blackfin/bf5xx-ac97.c b/trunk/sound/soc/blackfin/bf5xx-ac97.c index b1ed423fabd5..8a935f2d1767 100644 --- a/trunk/sound/soc/blackfin/bf5xx-ac97.c +++ b/trunk/sound/soc/blackfin/bf5xx-ac97.c @@ -31,15 +31,6 @@ #include "bf5xx-sport.h" #include "bf5xx-ac97.h" -/* Anomaly notes: - * 05000250 - AD1980 is running in TDM mode and RFS/TFS are generated by SPORT - * contrtoller. But, RFSDIV and TFSDIV are always set to 16*16-1, - * while the max AC97 data size is 13*16. The DIV is always larger - * than data size. AD73311 and ad2602 are not running in TDM mode. - * AD1836 and AD73322 depend on external RFS/TFS only. So, this - * anomaly does not affect blackfin sound drivers. -*/ - static int *cmd_count; static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM; diff --git a/trunk/sound/soc/blackfin/bf5xx-i2s.c b/trunk/sound/soc/blackfin/bf5xx-i2s.c index af06904bab0f..964824419678 100644 --- a/trunk/sound/soc/blackfin/bf5xx-i2s.c +++ b/trunk/sound/soc/blackfin/bf5xx-i2s.c @@ -50,7 +50,6 @@ struct bf5xx_i2s_port { u16 tcr2; u16 rcr2; int counter; - int configured; }; static struct bf5xx_i2s_port bf5xx_i2s; @@ -169,7 +168,7 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream, break; } - if (!bf5xx_i2s.configured) { + if (bf5xx_i2s.counter == 1) { /* * TX and RX are not independent,they are enabled at the * same time, even if only one side is running. So, we @@ -178,7 +177,6 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream, * * CPU DAI:slave mode. */ - bf5xx_i2s.configured = 1; ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1, bf5xx_i2s.rcr2, 0, 0); if (ret) { @@ -202,9 +200,6 @@ static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream, { pr_debug("%s enter\n", __func__); bf5xx_i2s.counter--; - /* No active stream, SPORT is allowed to be configured again. */ - if (!bf5xx_i2s.counter) - bf5xx_i2s.configured = 0; } static int bf5xx_i2s_probe(struct platform_device *pdev, @@ -249,7 +244,8 @@ static int bf5xx_i2s_suspend(struct snd_soc_dai *dai) return 0; } -static int bf5xx_i2s_resume(struct snd_soc_dai *dai) +static int bf5xx_i2s_resume(struct platform_device *pdev, + struct snd_soc_dai *dai) { int ret; struct sport_device *sport = diff --git a/trunk/sound/soc/blackfin/bf5xx-sport.c b/trunk/sound/soc/blackfin/bf5xx-sport.c index 469ce7fab20c..b7953c8cf838 100644 --- a/trunk/sound/soc/blackfin/bf5xx-sport.c +++ b/trunk/sound/soc/blackfin/bf5xx-sport.c @@ -190,7 +190,7 @@ static inline int sport_hook_rx_dummy(struct sport_device *sport) desc = get_dma_next_desc_ptr(sport->dma_rx_chan); /* Copy the descriptor which will be damaged to backup */ temp_desc = *desc; - desc->x_count = sport->dummy_count / 2; + desc->x_count = 0xa; desc->y_count = 0; desc->next_desc_addr = sport->dummy_rx_desc; local_irq_restore(flags); @@ -309,7 +309,7 @@ static inline int sport_hook_tx_dummy(struct sport_device *sport) desc = get_dma_next_desc_ptr(sport->dma_tx_chan); /* Store the descriptor which will be damaged */ temp_desc = *desc; - desc->x_count = sport->dummy_count / 2; + desc->x_count = 0xa; desc->y_count = 0; desc->next_desc_addr = sport->dummy_tx_desc; local_irq_restore(flags); diff --git a/trunk/sound/soc/codecs/Kconfig b/trunk/sound/soc/codecs/Kconfig index bbc97fd76648..b6c7f7a01cb0 100644 --- a/trunk/sound/soc/codecs/Kconfig +++ b/trunk/sound/soc/codecs/Kconfig @@ -18,9 +18,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_AK4535 if I2C select SND_SOC_CS4270 if I2C select SND_SOC_PCM3008 - select SND_SOC_SPDIF select SND_SOC_SSM2602 if I2C - select SND_SOC_STAC9766 if SND_SOC_AC97_BUS select SND_SOC_TLV320AIC23 if I2C select SND_SOC_TLV320AIC26 if SPI_MASTER select SND_SOC_TLV320AIC3X if I2C @@ -37,12 +35,8 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8900 if I2C select SND_SOC_WM8903 if I2C - select SND_SOC_WM8940 if I2C - select SND_SOC_WM8960 if I2C select SND_SOC_WM8971 if I2C - select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8990 if I2C - select SND_SOC_WM9081 if I2C select SND_SOC_WM9705 if SND_SOC_AC97_BUS select SND_SOC_WM9712 if SND_SOC_AC97_BUS select SND_SOC_WM9713 if SND_SOC_AC97_BUS @@ -92,15 +86,9 @@ config SND_SOC_L3 config SND_SOC_PCM3008 tristate -config SND_SOC_SPDIF - tristate - config SND_SOC_SSM2602 tristate -config SND_SOC_STAC9766 - tristate - config SND_SOC_TLV320AIC23 tristate @@ -150,24 +138,12 @@ config SND_SOC_WM8900 config SND_SOC_WM8903 tristate -config SND_SOC_WM8940 - tristate - -config SND_SOC_WM8960 - tristate - config SND_SOC_WM8971 tristate -config SND_SOC_WM8988 - tristate - config SND_SOC_WM8990 tristate -config SND_SOC_WM9081 - tristate - config SND_SOC_WM9705 tristate diff --git a/trunk/sound/soc/codecs/Makefile b/trunk/sound/soc/codecs/Makefile index 8b7530546f4d..f2653803ede8 100644 --- a/trunk/sound/soc/codecs/Makefile +++ b/trunk/sound/soc/codecs/Makefile @@ -6,9 +6,7 @@ snd-soc-ak4535-objs := ak4535.o snd-soc-cs4270-objs := cs4270.o snd-soc-l3-objs := l3.o snd-soc-pcm3008-objs := pcm3008.o -snd-soc-spdif-objs := spdif_transciever.o snd-soc-ssm2602-objs := ssm2602.o -snd-soc-stac9766-objs := stac9766.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic26-objs := tlv320aic26.o snd-soc-tlv320aic3x-objs := tlv320aic3x.o @@ -25,12 +23,8 @@ snd-soc-wm8750-objs := wm8750.o snd-soc-wm8753-objs := wm8753.o snd-soc-wm8900-objs := wm8900.o snd-soc-wm8903-objs := wm8903.o -snd-soc-wm8940-objs := wm8940.o -snd-soc-wm8960-objs := wm8960.o snd-soc-wm8971-objs := wm8971.o -snd-soc-wm8988-objs := wm8988.o snd-soc-wm8990-objs := wm8990.o -snd-soc-wm9081-objs := wm9081.o snd-soc-wm9705-objs := wm9705.o snd-soc-wm9712-objs := wm9712.o snd-soc-wm9713-objs := wm9713.o @@ -43,9 +37,7 @@ obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o -obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o -obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o @@ -63,11 +55,7 @@ obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o -obj-$(CONFIG_SND_SOC_WM8940) += snd-soc-wm8940.o -obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o -obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o -obj-$(CONFIG_SND_SOC_WM9081) += snd-soc-wm9081.o obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o diff --git a/trunk/sound/soc/codecs/ac97.c b/trunk/sound/soc/codecs/ac97.c index 932299bb5d1e..b0d4af145b87 100644 --- a/trunk/sound/soc/codecs/ac97.c +++ b/trunk/sound/soc/codecs/ac97.c @@ -53,13 +53,13 @@ struct snd_soc_dai ac97_dai = { .channels_min = 1, .channels_max = 2, .rates = STD_AC97_RATES, - .formats = SND_SOC_STD_AC97_FMTS,}, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .capture = { .stream_name = "AC97 Capture", .channels_min = 1, .channels_max = 2, .rates = STD_AC97_RATES, - .formats = SND_SOC_STD_AC97_FMTS,}, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = &ac97_dai_ops, }; EXPORT_SYMBOL_GPL(ac97_dai); diff --git a/trunk/sound/soc/codecs/ad1980.c b/trunk/sound/soc/codecs/ad1980.c index d7440a982d22..ddb3b08ac23c 100644 --- a/trunk/sound/soc/codecs/ad1980.c +++ b/trunk/sound/soc/codecs/ad1980.c @@ -137,13 +137,13 @@ struct snd_soc_dai ad1980_dai = { .channels_min = 2, .channels_max = 6, .rates = SNDRV_PCM_RATE_48000, - .formats = SND_SOC_STD_AC97_FMTS, }, + .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .capture = { .stream_name = "Capture", .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_48000, - .formats = SND_SOC_STD_AC97_FMTS, }, + .formats = SNDRV_PCM_FMTBIT_S16_LE, }, }; EXPORT_SYMBOL_GPL(ad1980_dai); diff --git a/trunk/sound/soc/codecs/cs4270.c b/trunk/sound/soc/codecs/cs4270.c index a32b8226c8a4..7fa09a387622 100644 --- a/trunk/sound/soc/codecs/cs4270.c +++ b/trunk/sound/soc/codecs/cs4270.c @@ -18,7 +18,7 @@ * - The machine driver's 'startup' function must call * cs4270_set_dai_sysclk() with the value of MCLK. * - Only I2S and left-justified modes are supported - * - Power management is supported + * - Power management is not supported */ #include @@ -27,7 +27,6 @@ #include #include #include -#include #include "cs4270.h" @@ -57,7 +56,6 @@ #define CS4270_FIRSTREG 0x01 #define CS4270_LASTREG 0x08 #define CS4270_NUMREGS (CS4270_LASTREG - CS4270_FIRSTREG + 1) -#define CS4270_I2C_INCR 0x80 /* Bit masks for the CS4270 registers */ #define CS4270_CHIPID_ID 0xF0 @@ -66,8 +64,6 @@ #define CS4270_PWRCTL_PDN_ADC 0x20 #define CS4270_PWRCTL_PDN_DAC 0x02 #define CS4270_PWRCTL_PDN 0x01 -#define CS4270_PWRCTL_PDN_ALL \ - (CS4270_PWRCTL_PDN_ADC | CS4270_PWRCTL_PDN_DAC | CS4270_PWRCTL_PDN) #define CS4270_MODE_SPEED_MASK 0x30 #define CS4270_MODE_1X 0x00 #define CS4270_MODE_2X 0x10 @@ -113,7 +109,6 @@ struct cs4270_private { unsigned int mclk; /* Input frequency of the MCLK pin */ unsigned int mode; /* The mode (I2S or left-justified) */ unsigned int slave_mode; - unsigned int manual_mute; }; /** @@ -300,7 +295,7 @@ static int cs4270_fill_cache(struct snd_soc_codec *codec) s32 length; length = i2c_smbus_read_i2c_block_data(i2c_client, - CS4270_FIRSTREG | CS4270_I2C_INCR, CS4270_NUMREGS, cache); + CS4270_FIRSTREG | 0x80, CS4270_NUMREGS, cache); if (length != CS4270_NUMREGS) { dev_err(codec->dev, "i2c read failure, addr=0x%x\n", @@ -458,7 +453,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream, } /** - * cs4270_dai_mute - enable/disable the CS4270 external mute + * cs4270_mute - enable/disable the CS4270 external mute * @dai: the SOC DAI * @mute: 0 = disable mute, 1 = enable mute * @@ -467,52 +462,21 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream, * board does not have the MUTEA or MUTEB pins connected to such circuitry, * then this function will do nothing. */ -static int cs4270_dai_mute(struct snd_soc_dai *dai, int mute) +static int cs4270_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - struct cs4270_private *cs4270 = codec->private_data; int reg6; reg6 = snd_soc_read(codec, CS4270_MUTE); if (mute) reg6 |= CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B; - else { + else reg6 &= ~(CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B); - reg6 |= cs4270->manual_mute; - } return snd_soc_write(codec, CS4270_MUTE, reg6); } -/** - * cs4270_soc_put_mute - put callback for the 'Master Playback switch' - * alsa control. - * @kcontrol: mixer control - * @ucontrol: control element information - * - * This function basically passes the arguments on to the generic - * snd_soc_put_volsw() function and saves the mute information in - * our private data structure. This is because we want to prevent - * cs4270_dai_mute() neglecting the user's decision to manually - * mute the codec's output. - * - * Returns 0 for success. - */ -static int cs4270_soc_put_mute(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct cs4270_private *cs4270 = codec->private_data; - int left = !ucontrol->value.integer.value[0]; - int right = !ucontrol->value.integer.value[1]; - - cs4270->manual_mute = (left ? CS4270_MUTE_DAC_A : 0) | - (right ? CS4270_MUTE_DAC_B : 0); - - return snd_soc_put_volsw(kcontrol, ucontrol); -} - /* A list of non-DAPM controls that the CS4270 supports */ static const struct snd_kcontrol_new cs4270_snd_controls[] = { SOC_DOUBLE_R("Master Playback Volume", @@ -522,9 +486,7 @@ static const struct snd_kcontrol_new cs4270_snd_controls[] = { SOC_SINGLE("Zero Cross Switch", CS4270_TRANS, 5, 1, 0), SOC_SINGLE("Popguard Switch", CS4270_MODE, 0, 1, 1), SOC_SINGLE("Auto-Mute Switch", CS4270_MUTE, 5, 1, 0), - SOC_DOUBLE("Master Capture Switch", CS4270_MUTE, 3, 4, 1, 1), - SOC_DOUBLE_EXT("Master Playback Switch", CS4270_MUTE, 0, 1, 1, 1, - snd_soc_get_volsw, cs4270_soc_put_mute), + SOC_DOUBLE("Master Capture Switch", CS4270_MUTE, 3, 4, 1, 0) }; /* @@ -544,7 +506,7 @@ static struct snd_soc_dai_ops cs4270_dai_ops = { .hw_params = cs4270_hw_params, .set_sysclk = cs4270_set_dai_sysclk, .set_fmt = cs4270_set_dai_fmt, - .digital_mute = cs4270_dai_mute, + .digital_mute = cs4270_mute, }; struct snd_soc_dai cs4270_dai = { @@ -791,57 +753,6 @@ static struct i2c_device_id cs4270_id[] = { }; MODULE_DEVICE_TABLE(i2c, cs4270_id); -#ifdef CONFIG_PM - -/* This suspend/resume implementation can handle both - a simple standby - * where the codec remains powered, and a full suspend, where the voltage - * domain the codec is connected to is teared down and/or any other hardware - * reset condition is asserted. - * - * The codec's own power saving features are enabled in the suspend callback, - * and all registers are written back to the hardware when resuming. - */ - -static int cs4270_i2c_suspend(struct i2c_client *client, pm_message_t mesg) -{ - struct cs4270_private *cs4270 = i2c_get_clientdata(client); - struct snd_soc_codec *codec = &cs4270->codec; - int reg = snd_soc_read(codec, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL; - - return snd_soc_write(codec, CS4270_PWRCTL, reg); -} - -static int cs4270_i2c_resume(struct i2c_client *client) -{ - struct cs4270_private *cs4270 = i2c_get_clientdata(client); - struct snd_soc_codec *codec = &cs4270->codec; - int reg; - - /* In case the device was put to hard reset during sleep, we need to - * wait 500ns here before any I2C communication. */ - ndelay(500); - - /* first restore the entire register cache ... */ - for (reg = CS4270_FIRSTREG; reg <= CS4270_LASTREG; reg++) { - u8 val = snd_soc_read(codec, reg); - - if (i2c_smbus_write_byte_data(client, reg, val)) { - dev_err(codec->dev, "i2c write failed\n"); - return -EIO; - } - } - - /* ... then disable the power-down bits */ - reg = snd_soc_read(codec, CS4270_PWRCTL); - reg &= ~CS4270_PWRCTL_PDN_ALL; - - return snd_soc_write(codec, CS4270_PWRCTL, reg); -} -#else -#define cs4270_i2c_suspend NULL -#define cs4270_i2c_resume NULL -#endif /* CONFIG_PM */ - /* * cs4270_i2c_driver - I2C device identification * @@ -856,8 +767,6 @@ static struct i2c_driver cs4270_i2c_driver = { .id_table = cs4270_id, .probe = cs4270_i2c_probe, .remove = cs4270_i2c_remove, - .suspend = cs4270_i2c_suspend, - .resume = cs4270_i2c_resume, }; /* diff --git a/trunk/sound/soc/codecs/spdif_transciever.c b/trunk/sound/soc/codecs/spdif_transciever.c deleted file mode 100644 index 218b33adad90..000000000000 --- a/trunk/sound/soc/codecs/spdif_transciever.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * ALSA SoC SPDIF DIT driver - * - * This driver is used by controllers which can operate in DIT (SPDI/F) where - * no codec is needed. This file provides stub codec that can be used - * in these configurations. TI DaVinci Audio controller uses this driver. - * - * Author: Steve Chen, - * Copyright: (C) 2009 MontaVista Software, Inc., - * Copyright: (C) 2009 Texas Instruments, India - * - * 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. - */ - -#include -#include -#include -#include - -#include "spdif_transciever.h" - -#define STUB_RATES SNDRV_PCM_RATE_8000_96000 -#define STUB_FORMATS SNDRV_PCM_FMTBIT_S16_LE - -struct snd_soc_dai dit_stub_dai = { - .name = "DIT", - .playback = { - .stream_name = "Playback", - .channels_min = 1, - .channels_max = 384, - .rates = STUB_RATES, - .formats = STUB_FORMATS, - }, -}; - -static int spdif_dit_probe(struct platform_device *pdev) -{ - dit_stub_dai.dev = &pdev->dev; - return snd_soc_register_dai(&dit_stub_dai); -} - -static int spdif_dit_remove(struct platform_device *pdev) -{ - snd_soc_unregister_dai(&dit_stub_dai); - return 0; -} - -static struct platform_driver spdif_dit_driver = { - .probe = spdif_dit_probe, - .remove = spdif_dit_remove, - .driver = { - .name = "spdif-dit", - .owner = THIS_MODULE, - }, -}; - -static int __init dit_modinit(void) -{ - return platform_driver_register(&spdif_dit_driver); -} - -static void __exit dit_exit(void) -{ - platform_driver_unregister(&spdif_dit_driver); -} - -module_init(dit_modinit); -module_exit(dit_exit); - diff --git a/trunk/sound/soc/codecs/spdif_transciever.h b/trunk/sound/soc/codecs/spdif_transciever.h deleted file mode 100644 index 296f2eb6c4ef..000000000000 --- a/trunk/sound/soc/codecs/spdif_transciever.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * ALSA SoC DIT/DIR driver header - * - * Author: Steve Chen, - * Copyright: (C) 2008 MontaVista Software, Inc., - * - * 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. - */ - -#ifndef CODEC_STUBS_H -#define CODEC_STUBS_H - -extern struct snd_soc_dai dit_stub_dai; - -#endif /* CODEC_STUBS_H */ diff --git a/trunk/sound/soc/codecs/ssm2602.c b/trunk/sound/soc/codecs/ssm2602.c index c550750c79c0..87f606c76822 100644 --- a/trunk/sound/soc/codecs/ssm2602.c +++ b/trunk/sound/soc/codecs/ssm2602.c @@ -336,17 +336,15 @@ static int ssm2602_startup(struct snd_pcm_substream *substream, master_runtime->sample_bits, master_runtime->rate); - if (master_runtime->rate != 0) - snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_RATE, - master_runtime->rate, - master_runtime->rate); - - if (master_runtime->sample_bits != 0) - snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_SAMPLE_BITS, - master_runtime->sample_bits, - master_runtime->sample_bits); + snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_RATE, + master_runtime->rate, + master_runtime->rate); + + snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_SAMPLE_BITS, + master_runtime->sample_bits, + master_runtime->sample_bits); ssm2602->slave_substream = substream; } else @@ -374,7 +372,6 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream, struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->card->codec; struct ssm2602_priv *ssm2602 = codec->private_data; - /* deactivate */ if (!codec->active) ssm2602_write(codec, SSM2602_ACTIVE, 0); @@ -500,9 +497,11 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec, return 0; } -#define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_32000 |\ - SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ - SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) +#define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000) #define SSM2602_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) diff --git a/trunk/sound/soc/codecs/stac9766.c b/trunk/sound/soc/codecs/stac9766.c deleted file mode 100644 index 8ad4b7b3e3ba..000000000000 --- a/trunk/sound/soc/codecs/stac9766.c +++ /dev/null @@ -1,463 +0,0 @@ -/* - * stac9766.c -- ALSA SoC STAC9766 codec support - * - * Copyright 2009 Jon Smirl, Digispeaker - * Author: Jon Smirl - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * Features:- - * - * o Support for AC97 Codec, S/PDIF - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "stac9766.h" - -#define STAC9766_VERSION "0.10" - -/* - * STAC9766 register cache - */ -static const u16 stac9766_reg[] = { - 0x6A90, 0x8000, 0x8000, 0x8000, /* 6 */ - 0x0000, 0x0000, 0x8008, 0x8008, /* e */ - 0x8808, 0x8808, 0x8808, 0x8808, /* 16 */ - 0x8808, 0x0000, 0x8000, 0x0000, /* 1e */ - 0x0000, 0x0000, 0x0000, 0x000f, /* 26 */ - 0x0a05, 0x0400, 0xbb80, 0x0000, /* 2e */ - 0x0000, 0xbb80, 0x0000, 0x0000, /* 36 */ - 0x0000, 0x2000, 0x0000, 0x0100, /* 3e */ - 0x0000, 0x0000, 0x0080, 0x0000, /* 46 */ - 0x0000, 0x0000, 0x0003, 0xffff, /* 4e */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 56 */ - 0x4000, 0x0000, 0x0000, 0x0000, /* 5e */ - 0x1201, 0xFFFF, 0xFFFF, 0x0000, /* 66 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 6e */ - 0x0000, 0x0000, 0x0000, 0x0006, /* 76 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 7e */ -}; - -static const char *stac9766_record_mux[] = {"Mic", "CD", "Video", "AUX", - "Line", "Stereo Mix", "Mono Mix", "Phone"}; -static const char *stac9766_mono_mux[] = {"Mix", "Mic"}; -static const char *stac9766_mic_mux[] = {"Mic1", "Mic2"}; -static const char *stac9766_SPDIF_mux[] = {"PCM", "ADC Record"}; -static const char *stac9766_popbypass_mux[] = {"Normal", "Bypass Mixer"}; -static const char *stac9766_record_all_mux[] = {"All analog", - "Analog plus DAC"}; -static const char *stac9766_boost1[] = {"0dB", "10dB"}; -static const char *stac9766_boost2[] = {"0dB", "20dB"}; -static const char *stac9766_stereo_mic[] = {"Off", "On"}; - -static const struct soc_enum stac9766_record_enum = - SOC_ENUM_DOUBLE(AC97_REC_SEL, 8, 0, 8, stac9766_record_mux); -static const struct soc_enum stac9766_mono_enum = - SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 9, 2, stac9766_mono_mux); -static const struct soc_enum stac9766_mic_enum = - SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 8, 2, stac9766_mic_mux); -static const struct soc_enum stac9766_SPDIF_enum = - SOC_ENUM_SINGLE(AC97_STAC_DA_CONTROL, 1, 2, stac9766_SPDIF_mux); -static const struct soc_enum stac9766_popbypass_enum = - SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 15, 2, stac9766_popbypass_mux); -static const struct soc_enum stac9766_record_all_enum = - SOC_ENUM_SINGLE(AC97_STAC_ANALOG_SPECIAL, 12, 2, - stac9766_record_all_mux); -static const struct soc_enum stac9766_boost1_enum = - SOC_ENUM_SINGLE(AC97_MIC, 6, 2, stac9766_boost1); /* 0/10dB */ -static const struct soc_enum stac9766_boost2_enum = - SOC_ENUM_SINGLE(AC97_STAC_ANALOG_SPECIAL, 2, 2, stac9766_boost2); /* 0/20dB */ -static const struct soc_enum stac9766_stereo_mic_enum = - SOC_ENUM_SINGLE(AC97_STAC_STEREO_MIC, 2, 1, stac9766_stereo_mic); - -static const DECLARE_TLV_DB_LINEAR(master_tlv, -4600, 0); -static const DECLARE_TLV_DB_LINEAR(record_tlv, 0, 2250); -static const DECLARE_TLV_DB_LINEAR(beep_tlv, -4500, 0); -static const DECLARE_TLV_DB_LINEAR(mix_tlv, -3450, 1200); - -static const struct snd_kcontrol_new stac9766_snd_ac97_controls[] = { - SOC_DOUBLE_TLV("Speaker Volume", AC97_MASTER, 8, 0, 31, 1, master_tlv), - SOC_SINGLE("Speaker Switch", AC97_MASTER, 15, 1, 1), - SOC_DOUBLE_TLV("Headphone Volume", AC97_HEADPHONE, 8, 0, 31, 1, - master_tlv), - SOC_SINGLE("Headphone Switch", AC97_HEADPHONE, 15, 1, 1), - SOC_SINGLE_TLV("Mono Out Volume", AC97_MASTER_MONO, 0, 31, 1, - master_tlv), - SOC_SINGLE("Mono Out Switch", AC97_MASTER_MONO, 15, 1, 1), - - SOC_DOUBLE_TLV("Record Volume", AC97_REC_GAIN, 8, 0, 15, 0, record_tlv), - SOC_SINGLE("Record Switch", AC97_REC_GAIN, 15, 1, 1), - - - SOC_SINGLE_TLV("Beep Volume", AC97_PC_BEEP, 1, 15, 1, beep_tlv), - SOC_SINGLE("Beep Switch", AC97_PC_BEEP, 15, 1, 1), - SOC_SINGLE("Beep Frequency", AC97_PC_BEEP, 5, 127, 1), - SOC_SINGLE_TLV("Phone Volume", AC97_PHONE, 0, 31, 1, mix_tlv), - SOC_SINGLE("Phone Switch", AC97_PHONE, 15, 1, 1), - - SOC_ENUM("Mic Boost1", stac9766_boost1_enum), - SOC_ENUM("Mic Boost2", stac9766_boost2_enum), - SOC_SINGLE_TLV("Mic Volume", AC97_MIC, 0, 31, 1, mix_tlv), - SOC_SINGLE("Mic Switch", AC97_MIC, 15, 1, 1), - SOC_ENUM("Stereo Mic", stac9766_stereo_mic_enum), - - SOC_DOUBLE_TLV("Line Volume", AC97_LINE, 8, 0, 31, 1, mix_tlv), - SOC_SINGLE("Line Switch", AC97_LINE, 15, 1, 1), - SOC_DOUBLE_TLV("CD Volume", AC97_CD, 8, 0, 31, 1, mix_tlv), - SOC_SINGLE("CD Switch", AC97_CD, 15, 1, 1), - SOC_DOUBLE_TLV("AUX Volume", AC97_AUX, 8, 0, 31, 1, mix_tlv), - SOC_SINGLE("AUX Switch", AC97_AUX, 15, 1, 1), - SOC_DOUBLE_TLV("Video Volume", AC97_VIDEO, 8, 0, 31, 1, mix_tlv), - SOC_SINGLE("Video Switch", AC97_VIDEO, 15, 1, 1), - - SOC_DOUBLE_TLV("DAC Volume", AC97_PCM, 8, 0, 31, 1, mix_tlv), - SOC_SINGLE("DAC Switch", AC97_PCM, 15, 1, 1), - SOC_SINGLE("Loopback Test Switch", AC97_GENERAL_PURPOSE, 7, 1, 0), - SOC_SINGLE("3D Volume", AC97_3D_CONTROL, 3, 2, 1), - SOC_SINGLE("3D Switch", AC97_GENERAL_PURPOSE, 13, 1, 0), - - SOC_ENUM("SPDIF Mux", stac9766_SPDIF_enum), - SOC_ENUM("Mic1/2 Mux", stac9766_mic_enum), - SOC_ENUM("Record All Mux", stac9766_record_all_enum), - SOC_ENUM("Record Mux", stac9766_record_enum), - SOC_ENUM("Mono Mux", stac9766_mono_enum), - SOC_ENUM("Pop Bypass Mux", stac9766_popbypass_enum), -}; - -static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int val) -{ - u16 *cache = codec->reg_cache; - - if (reg > AC97_STAC_PAGE0) { - stac9766_ac97_write(codec, AC97_INT_PAGING, 0); - soc_ac97_ops.write(codec->ac97, reg, val); - stac9766_ac97_write(codec, AC97_INT_PAGING, 1); - return 0; - } - if (reg / 2 > ARRAY_SIZE(stac9766_reg)) - return -EIO; - - soc_ac97_ops.write(codec->ac97, reg, val); - cache[reg / 2] = val; - return 0; -} - -static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 val = 0, *cache = codec->reg_cache; - - if (reg > AC97_STAC_PAGE0) { - stac9766_ac97_write(codec, AC97_INT_PAGING, 0); - val = soc_ac97_ops.read(codec->ac97, reg - AC97_STAC_PAGE0); - stac9766_ac97_write(codec, AC97_INT_PAGING, 1); - return val; - } - if (reg / 2 > ARRAY_SIZE(stac9766_reg)) - return -EIO; - - if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || - reg == AC97_INT_PAGING || reg == AC97_VENDOR_ID1 || - reg == AC97_VENDOR_ID2) { - - val = soc_ac97_ops.read(codec->ac97, reg); - return val; - } - return cache[reg / 2]; -} - -static int ac97_analog_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_codec *codec = dai->codec; - struct snd_pcm_runtime *runtime = substream->runtime; - unsigned short reg, vra; - - vra = stac9766_ac97_read(codec, AC97_EXTENDED_STATUS); - - vra |= 0x1; /* enable variable rate audio */ - - stac9766_ac97_write(codec, AC97_EXTENDED_STATUS, vra); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - reg = AC97_PCM_FRONT_DAC_RATE; - else - reg = AC97_PCM_LR_ADC_RATE; - - return stac9766_ac97_write(codec, reg, runtime->rate); -} - -static int ac97_digital_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_codec *codec = dai->codec; - struct snd_pcm_runtime *runtime = substream->runtime; - unsigned short reg, vra; - - stac9766_ac97_write(codec, AC97_SPDIF, 0x2002); - - vra = stac9766_ac97_read(codec, AC97_EXTENDED_STATUS); - vra |= 0x5; /* Enable VRA and SPDIF out */ - - stac9766_ac97_write(codec, AC97_EXTENDED_STATUS, vra); - - reg = AC97_PCM_FRONT_DAC_RATE; - - return stac9766_ac97_write(codec, reg, runtime->rate); -} - -static int ac97_digital_trigger(struct snd_pcm_substream *substream, - int cmd, struct snd_soc_dai *dai) -{ - struct snd_soc_codec *codec = dai->codec; - unsigned short vra; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_STOP: - vra = stac9766_ac97_read(codec, AC97_EXTENDED_STATUS); - vra &= !0x04; - stac9766_ac97_write(codec, AC97_EXTENDED_STATUS, vra); - break; - } - return 0; -} - -static int stac9766_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - switch (level) { - case SND_SOC_BIAS_ON: /* full On */ - case SND_SOC_BIAS_PREPARE: /* partial On */ - case SND_SOC_BIAS_STANDBY: /* Off, with power */ - stac9766_ac97_write(codec, AC97_POWERDOWN, 0x0000); - break; - case SND_SOC_BIAS_OFF: /* Off, without power */ - /* disable everything including AC link */ - stac9766_ac97_write(codec, AC97_POWERDOWN, 0xffff); - break; - } - codec->bias_level = level; - return 0; -} - -static int stac9766_reset(struct snd_soc_codec *codec, int try_warm) -{ - if (try_warm && soc_ac97_ops.warm_reset) { - soc_ac97_ops.warm_reset(codec->ac97); - if (stac9766_ac97_read(codec, 0) == stac9766_reg[0]) - return 1; - } - - soc_ac97_ops.reset(codec->ac97); - if (soc_ac97_ops.warm_reset) - soc_ac97_ops.warm_reset(codec->ac97); - if (stac9766_ac97_read(codec, 0) != stac9766_reg[0]) - return -EIO; - return 0; -} - -static int stac9766_codec_suspend(struct platform_device *pdev, - pm_message_t state) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; - - stac9766_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int stac9766_codec_resume(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; - u16 id, reset; - - reset = 0; - /* give the codec an AC97 warm reset to start the link */ -reset: - if (reset > 5) { - printk(KERN_ERR "stac9766 failed to resume"); - return -EIO; - } - codec->ac97->bus->ops->warm_reset(codec->ac97); - id = soc_ac97_ops.read(codec->ac97, AC97_VENDOR_ID2); - if (id != 0x4c13) { - stac9766_reset(codec, 0); - reset++; - goto reset; - } - stac9766_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - if (codec->suspend_bias_level == SND_SOC_BIAS_ON) - stac9766_set_bias_level(codec, SND_SOC_BIAS_ON); - - return 0; -} - -static struct snd_soc_dai_ops stac9766_dai_ops_analog = { - .prepare = ac97_analog_prepare, -}; - -static struct snd_soc_dai_ops stac9766_dai_ops_digital = { - .prepare = ac97_digital_prepare, - .trigger = ac97_digital_trigger, -}; - -struct snd_soc_dai stac9766_dai[] = { -{ - .name = "stac9766 analog", - .id = 0, - .ac97_control = 1, - - /* stream cababilities */ - .playback = { - .stream_name = "stac9766 analog", - .channels_min = 1, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SND_SOC_STD_AC97_FMTS, - }, - .capture = { - .stream_name = "stac9766 analog", - .channels_min = 1, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SND_SOC_STD_AC97_FMTS, - }, - /* alsa ops */ - .ops = &stac9766_dai_ops_analog, -}, -{ - .name = "stac9766 IEC958", - .id = 1, - .ac97_control = 1, - - /* stream cababilities */ - .playback = { - .stream_name = "stac9766 IEC958", - .channels_min = 1, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_32000 | \ - SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE, - }, - /* alsa ops */ - .ops = &stac9766_dai_ops_digital, -} -}; -EXPORT_SYMBOL_GPL(stac9766_dai); - -static int stac9766_codec_probe(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec; - int ret = 0; - - printk(KERN_INFO "STAC9766 SoC Audio Codec %s\n", STAC9766_VERSION); - - socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (socdev->card->codec == NULL) - return -ENOMEM; - codec = socdev->card->codec; - mutex_init(&codec->mutex); - - codec->reg_cache = kmemdup(stac9766_reg, sizeof(stac9766_reg), - GFP_KERNEL); - if (codec->reg_cache == NULL) { - ret = -ENOMEM; - goto cache_err; - } - codec->reg_cache_size = sizeof(stac9766_reg); - codec->reg_cache_step = 2; - - codec->name = "STAC9766"; - codec->owner = THIS_MODULE; - codec->dai = stac9766_dai; - codec->num_dai = ARRAY_SIZE(stac9766_dai); - codec->write = stac9766_ac97_write; - codec->read = stac9766_ac97_read; - codec->set_bias_level = stac9766_set_bias_level; - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); - - ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); - if (ret < 0) - goto codec_err; - - /* register pcms */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) - goto pcm_err; - - /* do a cold reset for the controller and then try - * a warm reset followed by an optional cold reset for codec */ - stac9766_reset(codec, 0); - ret = stac9766_reset(codec, 1); - if (ret < 0) { - printk(KERN_ERR "Failed to reset STAC9766: AC97 link error\n"); - goto reset_err; - } - - stac9766_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - snd_soc_add_controls(codec, stac9766_snd_ac97_controls, - ARRAY_SIZE(stac9766_snd_ac97_controls)); - - ret = snd_soc_init_card(socdev); - if (ret < 0) - goto reset_err; - return 0; - -reset_err: - snd_soc_free_pcms(socdev); -pcm_err: - snd_soc_free_ac97_codec(codec); -codec_err: - kfree(codec->private_data); -cache_err: - kfree(socdev->card->codec); - socdev->card->codec = NULL; - return ret; -} - -static int stac9766_codec_remove(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; - - if (codec == NULL) - return 0; - - snd_soc_free_pcms(socdev); - snd_soc_free_ac97_codec(codec); - kfree(codec->reg_cache); - kfree(codec); - return 0; -} - -struct snd_soc_codec_device soc_codec_dev_stac9766 = { - .probe = stac9766_codec_probe, - .remove = stac9766_codec_remove, - .suspend = stac9766_codec_suspend, - .resume = stac9766_codec_resume, -}; -EXPORT_SYMBOL_GPL(soc_codec_dev_stac9766); - -MODULE_DESCRIPTION("ASoC stac9766 driver"); -MODULE_AUTHOR("Jon Smirl "); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/codecs/stac9766.h b/trunk/sound/soc/codecs/stac9766.h deleted file mode 100644 index 65642eb8393e..000000000000 --- a/trunk/sound/soc/codecs/stac9766.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * stac9766.h -- STAC9766 Soc Audio driver - */ - -#ifndef _STAC9766_H -#define _STAC9766_H - -#define AC97_STAC_PAGE0 0x1000 -#define AC97_STAC_DA_CONTROL (AC97_STAC_PAGE0 | 0x6A) -#define AC97_STAC_ANALOG_SPECIAL (AC97_STAC_PAGE0 | 0x6E) -#define AC97_STAC_STEREO_MIC 0x78 - -/* STAC9766 DAI ID's */ -#define STAC9766_DAI_AC97_ANALOG 0 -#define STAC9766_DAI_AC97_DIGITAL 1 - -extern struct snd_soc_dai stac9766_dai[]; -extern struct snd_soc_codec_device soc_codec_dev_stac9766; - - -#endif diff --git a/trunk/sound/soc/codecs/tlv320aic23.c b/trunk/sound/soc/codecs/tlv320aic23.c index 0b8dcb5cd729..c3f4afb5d017 100644 --- a/trunk/sound/soc/codecs/tlv320aic23.c +++ b/trunk/sound/soc/codecs/tlv320aic23.c @@ -86,7 +86,7 @@ static int tlv320aic23_write(struct snd_soc_codec *codec, unsigned int reg, */ if ((reg < 0 || reg > 9) && (reg != 15)) { - printk(KERN_WARNING "%s Invalid register R%u\n", __func__, reg); + printk(KERN_WARNING "%s Invalid register R%d\n", __func__, reg); return -1; } @@ -98,7 +98,7 @@ static int tlv320aic23_write(struct snd_soc_codec *codec, unsigned int reg, if (codec->hw_write(codec->control_data, data, 2) == 2) return 0; - printk(KERN_ERR "%s cannot write %03x to register R%u\n", __func__, + printk(KERN_ERR "%s cannot write %03x to register R%d\n", __func__, value, reg); return -EIO; @@ -273,14 +273,14 @@ static const unsigned short sr_valid_mask[] = { * Every divisor is a factor of 11*12 */ #define SR_MULT (11*12) -#define A(x) (SR_MULT/x) +#define A(x) (x) ? (SR_MULT/x) : 0 static const unsigned char sr_adc_mult_table[] = { - A(2), A(2), A(12), A(12), 0, 0, A(3), A(1), - A(2), A(2), A(11), A(11), 0, 0, 0, A(1) + A(2), A(2), A(12), A(12), A(0), A(0), A(3), A(1), + A(2), A(2), A(11), A(11), A(0), A(0), A(0), A(1) }; static const unsigned char sr_dac_mult_table[] = { - A(2), A(12), A(2), A(12), 0, 0, A(3), A(1), - A(2), A(11), A(2), A(11), 0, 0, 0, A(1) + A(2), A(12), A(2), A(12), A(0), A(0), A(3), A(1), + A(2), A(11), A(2), A(11), A(0), A(0), A(0), A(1) }; static unsigned get_score(int adc, int adc_l, int adc_h, int need_adc, @@ -523,8 +523,6 @@ static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai, case SND_SOC_DAIFMT_I2S: iface_reg |= TLV320AIC23_FOR_I2S; break; - case SND_SOC_DAIFMT_DSP_A: - iface_reg |= TLV320AIC23_LRP_ON; case SND_SOC_DAIFMT_DSP_B: iface_reg |= TLV320AIC23_FOR_DSP; break; diff --git a/trunk/sound/soc/codecs/twl4030.c b/trunk/sound/soc/codecs/twl4030.c index 4dbb853eef5a..df7c8c281d2f 100644 --- a/trunk/sound/soc/codecs/twl4030.c +++ b/trunk/sound/soc/codecs/twl4030.c @@ -115,7 +115,6 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { 0x00, /* REG_VIBRA_PWM_SET (0x47) */ 0x00, /* REG_ANAMIC_GAIN (0x48) */ 0x00, /* REG_MISC_SET_2 (0x49) */ - 0x00, /* REG_SW_SHADOW (0x4A) - Shadow, non HW register */ }; /* codec private data */ @@ -126,17 +125,6 @@ struct twl4030_priv { struct snd_pcm_substream *master_substream; struct snd_pcm_substream *slave_substream; - - unsigned int configured; - unsigned int rate; - unsigned int sample_bits; - unsigned int channels; - - unsigned int sysclk; - - /* Headset output state handling */ - unsigned int hsl_enabled; - unsigned int hsr_enabled; }; /* @@ -173,11 +161,7 @@ static int twl4030_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { twl4030_write_reg_cache(codec, reg, value); - if (likely(reg < TWL4030_REG_SW_SHADOW)) - return twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, - reg); - else - return 0; + return twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, reg); } static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable) @@ -204,7 +188,6 @@ static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable) static void twl4030_init_chip(struct snd_soc_codec *codec) { - u8 *cache = codec->reg_cache; int i; /* clear CODECPDZ prior to setting register defaults */ @@ -212,7 +195,7 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) /* set all audio section registers to reasonable defaults */ for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++) - twl4030_write(codec, i, cache[i]); + twl4030_write(codec, i, twl4030_reg[i]); } @@ -249,7 +232,7 @@ static void twl4030_codec_mute(struct snd_soc_codec *codec, int mute) TWL4030_REG_PRECKL_CTL); reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_PRECKR_CTL); twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, - reg_val & (~TWL4030_PRECKR_GAIN), + reg_val & (~TWL4030_PRECKL_GAIN), TWL4030_REG_PRECKR_CTL); /* Disable PLL */ @@ -333,60 +316,104 @@ static void twl4030_power_down(struct snd_soc_codec *codec) } /* Earpiece */ -static const struct snd_kcontrol_new twl4030_dapm_earpiece_controls[] = { - SOC_DAPM_SINGLE("Voice", TWL4030_REG_EAR_CTL, 0, 1, 0), - SOC_DAPM_SINGLE("AudioL1", TWL4030_REG_EAR_CTL, 1, 1, 0), - SOC_DAPM_SINGLE("AudioL2", TWL4030_REG_EAR_CTL, 2, 1, 0), - SOC_DAPM_SINGLE("AudioR1", TWL4030_REG_EAR_CTL, 3, 1, 0), -}; +static const char *twl4030_earpiece_texts[] = + {"Off", "DACL1", "DACL2", "DACR1"}; + +static const unsigned int twl4030_earpiece_values[] = + {0x0, 0x1, 0x2, 0x4}; + +static const struct soc_enum twl4030_earpiece_enum = + SOC_VALUE_ENUM_SINGLE(TWL4030_REG_EAR_CTL, 1, 0x7, + ARRAY_SIZE(twl4030_earpiece_texts), + twl4030_earpiece_texts, + twl4030_earpiece_values); + +static const struct snd_kcontrol_new twl4030_dapm_earpiece_control = +SOC_DAPM_VALUE_ENUM("Route", twl4030_earpiece_enum); /* PreDrive Left */ -static const struct snd_kcontrol_new twl4030_dapm_predrivel_controls[] = { - SOC_DAPM_SINGLE("Voice", TWL4030_REG_PREDL_CTL, 0, 1, 0), - SOC_DAPM_SINGLE("AudioL1", TWL4030_REG_PREDL_CTL, 1, 1, 0), - SOC_DAPM_SINGLE("AudioL2", TWL4030_REG_PREDL_CTL, 2, 1, 0), - SOC_DAPM_SINGLE("AudioR2", TWL4030_REG_PREDL_CTL, 3, 1, 0), -}; +static const char *twl4030_predrivel_texts[] = + {"Off", "DACL1", "DACL2", "DACR2"}; + +static const unsigned int twl4030_predrivel_values[] = + {0x0, 0x1, 0x2, 0x4}; + +static const struct soc_enum twl4030_predrivel_enum = + SOC_VALUE_ENUM_SINGLE(TWL4030_REG_PREDL_CTL, 1, 0x7, + ARRAY_SIZE(twl4030_predrivel_texts), + twl4030_predrivel_texts, + twl4030_predrivel_values); + +static const struct snd_kcontrol_new twl4030_dapm_predrivel_control = +SOC_DAPM_VALUE_ENUM("Route", twl4030_predrivel_enum); /* PreDrive Right */ -static const struct snd_kcontrol_new twl4030_dapm_predriver_controls[] = { - SOC_DAPM_SINGLE("Voice", TWL4030_REG_PREDR_CTL, 0, 1, 0), - SOC_DAPM_SINGLE("AudioR1", TWL4030_REG_PREDR_CTL, 1, 1, 0), - SOC_DAPM_SINGLE("AudioR2", TWL4030_REG_PREDR_CTL, 2, 1, 0), - SOC_DAPM_SINGLE("AudioL2", TWL4030_REG_PREDR_CTL, 3, 1, 0), -}; +static const char *twl4030_predriver_texts[] = + {"Off", "DACR1", "DACR2", "DACL2"}; + +static const unsigned int twl4030_predriver_values[] = + {0x0, 0x1, 0x2, 0x4}; + +static const struct soc_enum twl4030_predriver_enum = + SOC_VALUE_ENUM_SINGLE(TWL4030_REG_PREDR_CTL, 1, 0x7, + ARRAY_SIZE(twl4030_predriver_texts), + twl4030_predriver_texts, + twl4030_predriver_values); + +static const struct snd_kcontrol_new twl4030_dapm_predriver_control = +SOC_DAPM_VALUE_ENUM("Route", twl4030_predriver_enum); /* Headset Left */ -static const struct snd_kcontrol_new twl4030_dapm_hsol_controls[] = { - SOC_DAPM_SINGLE("Voice", TWL4030_REG_HS_SEL, 0, 1, 0), - SOC_DAPM_SINGLE("AudioL1", TWL4030_REG_HS_SEL, 1, 1, 0), - SOC_DAPM_SINGLE("AudioL2", TWL4030_REG_HS_SEL, 2, 1, 0), -}; +static const char *twl4030_hsol_texts[] = + {"Off", "DACL1", "DACL2"}; + +static const struct soc_enum twl4030_hsol_enum = + SOC_ENUM_SINGLE(TWL4030_REG_HS_SEL, 1, + ARRAY_SIZE(twl4030_hsol_texts), + twl4030_hsol_texts); + +static const struct snd_kcontrol_new twl4030_dapm_hsol_control = +SOC_DAPM_ENUM("Route", twl4030_hsol_enum); /* Headset Right */ -static const struct snd_kcontrol_new twl4030_dapm_hsor_controls[] = { - SOC_DAPM_SINGLE("Voice", TWL4030_REG_HS_SEL, 3, 1, 0), - SOC_DAPM_SINGLE("AudioR1", TWL4030_REG_HS_SEL, 4, 1, 0), - SOC_DAPM_SINGLE("AudioR2", TWL4030_REG_HS_SEL, 5, 1, 0), -}; +static const char *twl4030_hsor_texts[] = + {"Off", "DACR1", "DACR2"}; + +static const struct soc_enum twl4030_hsor_enum = + SOC_ENUM_SINGLE(TWL4030_REG_HS_SEL, 4, + ARRAY_SIZE(twl4030_hsor_texts), + twl4030_hsor_texts); + +static const struct snd_kcontrol_new twl4030_dapm_hsor_control = +SOC_DAPM_ENUM("Route", twl4030_hsor_enum); /* Carkit Left */ -static const struct snd_kcontrol_new twl4030_dapm_carkitl_controls[] = { - SOC_DAPM_SINGLE("Voice", TWL4030_REG_PRECKL_CTL, 0, 1, 0), - SOC_DAPM_SINGLE("AudioL1", TWL4030_REG_PRECKL_CTL, 1, 1, 0), - SOC_DAPM_SINGLE("AudioL2", TWL4030_REG_PRECKL_CTL, 2, 1, 0), -}; +static const char *twl4030_carkitl_texts[] = + {"Off", "DACL1", "DACL2"}; + +static const struct soc_enum twl4030_carkitl_enum = + SOC_ENUM_SINGLE(TWL4030_REG_PRECKL_CTL, 1, + ARRAY_SIZE(twl4030_carkitl_texts), + twl4030_carkitl_texts); + +static const struct snd_kcontrol_new twl4030_dapm_carkitl_control = +SOC_DAPM_ENUM("Route", twl4030_carkitl_enum); /* Carkit Right */ -static const struct snd_kcontrol_new twl4030_dapm_carkitr_controls[] = { - SOC_DAPM_SINGLE("Voice", TWL4030_REG_PRECKR_CTL, 0, 1, 0), - SOC_DAPM_SINGLE("AudioR1", TWL4030_REG_PRECKR_CTL, 1, 1, 0), - SOC_DAPM_SINGLE("AudioR2", TWL4030_REG_PRECKR_CTL, 2, 1, 0), -}; +static const char *twl4030_carkitr_texts[] = + {"Off", "DACR1", "DACR2"}; + +static const struct soc_enum twl4030_carkitr_enum = + SOC_ENUM_SINGLE(TWL4030_REG_PRECKR_CTL, 1, + ARRAY_SIZE(twl4030_carkitr_texts), + twl4030_carkitr_texts); + +static const struct snd_kcontrol_new twl4030_dapm_carkitr_control = +SOC_DAPM_ENUM("Route", twl4030_carkitr_enum); /* Handsfree Left */ static const char *twl4030_handsfreel_texts[] = - {"Voice", "AudioL1", "AudioL2", "AudioR2"}; + {"Voice", "DACL1", "DACL2", "DACR2"}; static const struct soc_enum twl4030_handsfreel_enum = SOC_ENUM_SINGLE(TWL4030_REG_HFL_CTL, 0, @@ -396,13 +423,9 @@ static const struct soc_enum twl4030_handsfreel_enum = static const struct snd_kcontrol_new twl4030_dapm_handsfreel_control = SOC_DAPM_ENUM("Route", twl4030_handsfreel_enum); -/* Handsfree Left virtual mute */ -static const struct snd_kcontrol_new twl4030_dapm_handsfreelmute_control = - SOC_DAPM_SINGLE("Switch", TWL4030_REG_SW_SHADOW, 0, 1, 0); - /* Handsfree Right */ static const char *twl4030_handsfreer_texts[] = - {"Voice", "AudioR1", "AudioR2", "AudioL2"}; + {"Voice", "DACR1", "DACR2", "DACL2"}; static const struct soc_enum twl4030_handsfreer_enum = SOC_ENUM_SINGLE(TWL4030_REG_HFR_CTL, 0, @@ -412,48 +435,37 @@ static const struct soc_enum twl4030_handsfreer_enum = static const struct snd_kcontrol_new twl4030_dapm_handsfreer_control = SOC_DAPM_ENUM("Route", twl4030_handsfreer_enum); -/* Handsfree Right virtual mute */ -static const struct snd_kcontrol_new twl4030_dapm_handsfreermute_control = - SOC_DAPM_SINGLE("Switch", TWL4030_REG_SW_SHADOW, 1, 1, 0); +/* Left analog microphone selection */ +static const char *twl4030_analoglmic_texts[] = + {"Off", "Main mic", "Headset mic", "AUXL", "Carkit mic"}; -/* Vibra */ -/* Vibra audio path selection */ -static const char *twl4030_vibra_texts[] = - {"AudioL1", "AudioR1", "AudioL2", "AudioR2"}; +static const unsigned int twl4030_analoglmic_values[] = + {0x0, 0x1, 0x2, 0x4, 0x8}; -static const struct soc_enum twl4030_vibra_enum = - SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 2, - ARRAY_SIZE(twl4030_vibra_texts), - twl4030_vibra_texts); +static const struct soc_enum twl4030_analoglmic_enum = + SOC_VALUE_ENUM_SINGLE(TWL4030_REG_ANAMICL, 0, 0xf, + ARRAY_SIZE(twl4030_analoglmic_texts), + twl4030_analoglmic_texts, + twl4030_analoglmic_values); -static const struct snd_kcontrol_new twl4030_dapm_vibra_control = -SOC_DAPM_ENUM("Route", twl4030_vibra_enum); +static const struct snd_kcontrol_new twl4030_dapm_analoglmic_control = +SOC_DAPM_VALUE_ENUM("Route", twl4030_analoglmic_enum); -/* Vibra path selection: local vibrator (PWM) or audio driven */ -static const char *twl4030_vibrapath_texts[] = - {"Local vibrator", "Audio"}; +/* Right analog microphone selection */ +static const char *twl4030_analogrmic_texts[] = + {"Off", "Sub mic", "AUXR"}; -static const struct soc_enum twl4030_vibrapath_enum = - SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 4, - ARRAY_SIZE(twl4030_vibrapath_texts), - twl4030_vibrapath_texts); +static const unsigned int twl4030_analogrmic_values[] = + {0x0, 0x1, 0x4}; -static const struct snd_kcontrol_new twl4030_dapm_vibrapath_control = -SOC_DAPM_ENUM("Route", twl4030_vibrapath_enum); +static const struct soc_enum twl4030_analogrmic_enum = + SOC_VALUE_ENUM_SINGLE(TWL4030_REG_ANAMICR, 0, 0x5, + ARRAY_SIZE(twl4030_analogrmic_texts), + twl4030_analogrmic_texts, + twl4030_analogrmic_values); -/* Left analog microphone selection */ -static const struct snd_kcontrol_new twl4030_dapm_analoglmic_controls[] = { - SOC_DAPM_SINGLE("Main mic", TWL4030_REG_ANAMICL, 0, 1, 0), - SOC_DAPM_SINGLE("Headset mic", TWL4030_REG_ANAMICL, 1, 1, 0), - SOC_DAPM_SINGLE("AUXL", TWL4030_REG_ANAMICL, 2, 1, 0), - SOC_DAPM_SINGLE("Carkit mic", TWL4030_REG_ANAMICL, 3, 1, 0), -}; - -/* Right analog microphone selection */ -static const struct snd_kcontrol_new twl4030_dapm_analogrmic_controls[] = { - SOC_DAPM_SINGLE("Sub mic", TWL4030_REG_ANAMICR, 0, 1, 0), - SOC_DAPM_SINGLE("AUXR", TWL4030_REG_ANAMICR, 2, 1, 0), -}; +static const struct snd_kcontrol_new twl4030_dapm_analogrmic_control = +SOC_DAPM_VALUE_ENUM("Route", twl4030_analogrmic_enum); /* TX1 L/R Analog/Digital microphone selection */ static const char *twl4030_micpathtx1_texts[] = @@ -495,10 +507,6 @@ static const struct snd_kcontrol_new twl4030_dapm_abypassr2_control = static const struct snd_kcontrol_new twl4030_dapm_abypassl2_control = SOC_DAPM_SINGLE("Switch", TWL4030_REG_ARXL2_APGA_CTL, 2, 1, 0); -/* Analog bypass for Voice */ -static const struct snd_kcontrol_new twl4030_dapm_abypassv_control = - SOC_DAPM_SINGLE("Switch", TWL4030_REG_VDL_APGA_CTL, 2, 1, 0); - /* Digital bypass gain, 0 mutes the bypass */ static const unsigned int twl4030_dapm_dbypass_tlv[] = { TLV_DB_RANGE_HEAD(2), @@ -518,18 +526,6 @@ static const struct snd_kcontrol_new twl4030_dapm_dbypassr_control = TWL4030_REG_ATX2ARXPGA, 0, 7, 0, twl4030_dapm_dbypass_tlv); -/* - * Voice Sidetone GAIN volume control: - * from -51 to -10 dB in 1 dB steps (mute instead of -51 dB) - */ -static DECLARE_TLV_DB_SCALE(twl4030_dapm_dbypassv_tlv, -5100, 100, 1); - -/* Digital bypass voice: sidetone (VUL -> VDL)*/ -static const struct snd_kcontrol_new twl4030_dapm_dbypassv_control = - SOC_DAPM_SINGLE_TLV("Volume", - TWL4030_REG_VSTPGA, 0, 0x29, 0, - twl4030_dapm_dbypassv_tlv); - static int micpath_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -560,143 +556,63 @@ static int micpath_event(struct snd_soc_dapm_widget *w, return 0; } -static void handsfree_ramp(struct snd_soc_codec *codec, int reg, int ramp) +static int handsfree_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) { + struct soc_enum *e = (struct soc_enum *)w->kcontrols->private_value; unsigned char hs_ctl; - hs_ctl = twl4030_read_reg_cache(codec, reg); + hs_ctl = twl4030_read_reg_cache(w->codec, e->reg); - if (ramp) { - /* HF ramp-up */ - hs_ctl |= TWL4030_HF_CTL_REF_EN; - twl4030_write(codec, reg, hs_ctl); - udelay(10); + if (hs_ctl & TWL4030_HF_CTL_REF_EN) { hs_ctl |= TWL4030_HF_CTL_RAMP_EN; - twl4030_write(codec, reg, hs_ctl); - udelay(40); + twl4030_write(w->codec, e->reg, hs_ctl); hs_ctl |= TWL4030_HF_CTL_LOOP_EN; + twl4030_write(w->codec, e->reg, hs_ctl); hs_ctl |= TWL4030_HF_CTL_HB_EN; - twl4030_write(codec, reg, hs_ctl); + twl4030_write(w->codec, e->reg, hs_ctl); } else { - /* HF ramp-down */ - hs_ctl &= ~TWL4030_HF_CTL_LOOP_EN; - hs_ctl &= ~TWL4030_HF_CTL_HB_EN; - twl4030_write(codec, reg, hs_ctl); - hs_ctl &= ~TWL4030_HF_CTL_RAMP_EN; - twl4030_write(codec, reg, hs_ctl); - udelay(40); - hs_ctl &= ~TWL4030_HF_CTL_REF_EN; - twl4030_write(codec, reg, hs_ctl); + hs_ctl &= ~(TWL4030_HF_CTL_RAMP_EN | TWL4030_HF_CTL_LOOP_EN + | TWL4030_HF_CTL_HB_EN); + twl4030_write(w->codec, e->reg, hs_ctl); } -} -static int handsfreelpga_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - switch (event) { - case SND_SOC_DAPM_POST_PMU: - handsfree_ramp(w->codec, TWL4030_REG_HFL_CTL, 1); - break; - case SND_SOC_DAPM_POST_PMD: - handsfree_ramp(w->codec, TWL4030_REG_HFL_CTL, 0); - break; - } return 0; } -static int handsfreerpga_event(struct snd_soc_dapm_widget *w, +static int headsetl_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) -{ - switch (event) { - case SND_SOC_DAPM_POST_PMU: - handsfree_ramp(w->codec, TWL4030_REG_HFR_CTL, 1); - break; - case SND_SOC_DAPM_POST_PMD: - handsfree_ramp(w->codec, TWL4030_REG_HFR_CTL, 0); - break; - } - return 0; -} - -static void headset_ramp(struct snd_soc_codec *codec, int ramp) { unsigned char hs_gain, hs_pop; - struct twl4030_priv *twl4030 = codec->private_data; - /* Base values for ramp delay calculation: 2^19 - 2^26 */ - unsigned int ramp_base[] = {524288, 1048576, 2097152, 4194304, - 8388608, 16777216, 33554432, 67108864}; - hs_gain = twl4030_read_reg_cache(codec, TWL4030_REG_HS_GAIN_SET); - hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); + /* Save the current volume */ + hs_gain = twl4030_read_reg_cache(w->codec, TWL4030_REG_HS_GAIN_SET); + hs_pop = twl4030_read_reg_cache(w->codec, TWL4030_REG_HS_POPN_SET); - if (ramp) { - /* Headset ramp-up according to the TRM */ + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* Do the anti-pop/bias ramp enable according to the TRM */ hs_pop |= TWL4030_VMID_EN; - twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); - twl4030_write(codec, TWL4030_REG_HS_GAIN_SET, hs_gain); + twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop); + /* Is this needed? Can we just use whatever gain here? */ + twl4030_write(w->codec, TWL4030_REG_HS_GAIN_SET, + (hs_gain & (~0x0f)) | 0x0a); hs_pop |= TWL4030_RAMP_EN; - twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); - } else { - /* Headset ramp-down _not_ according to - * the TRM, but in a way that it is working */ + twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop); + + /* Restore the original volume */ + twl4030_write(w->codec, TWL4030_REG_HS_GAIN_SET, hs_gain); + break; + case SND_SOC_DAPM_POST_PMD: + /* Do the anti-pop/bias ramp disable according to the TRM */ hs_pop &= ~TWL4030_RAMP_EN; - twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); - /* Wait ramp delay time + 1, so the VMID can settle */ - mdelay((ramp_base[(hs_pop & TWL4030_RAMP_DELAY) >> 2] / - twl4030->sysclk) + 1); + twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop); /* Bypass the reg_cache to mute the headset */ twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, hs_gain & (~0x0f), TWL4030_REG_HS_GAIN_SET); - hs_pop &= ~TWL4030_VMID_EN; - twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); - } -} - -static int headsetlpga_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct twl4030_priv *twl4030 = w->codec->private_data; - - switch (event) { - case SND_SOC_DAPM_POST_PMU: - /* Do the ramp-up only once */ - if (!twl4030->hsr_enabled) - headset_ramp(w->codec, 1); - - twl4030->hsl_enabled = 1; - break; - case SND_SOC_DAPM_POST_PMD: - /* Do the ramp-down only if both headsetL/R is disabled */ - if (!twl4030->hsr_enabled) - headset_ramp(w->codec, 0); - - twl4030->hsl_enabled = 0; - break; - } - return 0; -} - -static int headsetrpga_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct twl4030_priv *twl4030 = w->codec->private_data; - - switch (event) { - case SND_SOC_DAPM_POST_PMU: - /* Do the ramp-up only once */ - if (!twl4030->hsl_enabled) - headset_ramp(w->codec, 1); - - twl4030->hsr_enabled = 1; - break; - case SND_SOC_DAPM_POST_PMD: - /* Do the ramp-down only if both headsetL/R is disabled */ - if (!twl4030->hsl_enabled) - headset_ramp(w->codec, 0); - - twl4030->hsr_enabled = 0; + twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop); break; } return 0; @@ -708,7 +624,7 @@ static int bypass_event(struct snd_soc_dapm_widget *w, struct soc_mixer_control *m = (struct soc_mixer_control *)w->kcontrols->private_value; struct twl4030_priv *twl4030 = w->codec->private_data; - unsigned char reg, misc; + unsigned char reg; reg = twl4030_read_reg_cache(w->codec, m->reg); @@ -720,34 +636,14 @@ static int bypass_event(struct snd_soc_dapm_widget *w, else twl4030->bypass_state &= ~(1 << (m->reg - TWL4030_REG_ARXL1_APGA_CTL)); - } else if (m->reg == TWL4030_REG_VDL_APGA_CTL) { - /* Analog voice bypass */ - if (reg & (1 << m->shift)) - twl4030->bypass_state |= (1 << 4); - else - twl4030->bypass_state &= ~(1 << 4); - } else if (m->reg == TWL4030_REG_VSTPGA) { - /* Voice digital bypass */ - if (reg) - twl4030->bypass_state |= (1 << 5); - else - twl4030->bypass_state &= ~(1 << 5); } else { /* Digital bypass */ if (reg & (0x7 << m->shift)) - twl4030->bypass_state |= (1 << (m->shift ? 7 : 6)); + twl4030->bypass_state |= (1 << (m->shift ? 5 : 4)); else - twl4030->bypass_state &= ~(1 << (m->shift ? 7 : 6)); + twl4030->bypass_state &= ~(1 << (m->shift ? 5 : 4)); } - /* Enable master analog loopback mode if any analog switch is enabled*/ - misc = twl4030_read_reg_cache(w->codec, TWL4030_REG_MISC_SET_1); - if (twl4030->bypass_state & 0x1F) - misc |= TWL4030_FMLOOP_EN; - else - misc &= ~TWL4030_FMLOOP_EN; - twl4030_write(w->codec, TWL4030_REG_MISC_SET_1, misc); - if (w->codec->bias_level == SND_SOC_BIAS_STANDBY) { if (twl4030->bypass_state) twl4030_codec_mute(w->codec, 0); @@ -914,48 +810,6 @@ static int snd_soc_put_volsw_r2_twl4030(struct snd_kcontrol *kcontrol, return err; } -/* Codec operation modes */ -static const char *twl4030_op_modes_texts[] = { - "Option 2 (voice/audio)", "Option 1 (audio)" -}; - -static const struct soc_enum twl4030_op_modes_enum = - SOC_ENUM_SINGLE(TWL4030_REG_CODEC_MODE, 0, - ARRAY_SIZE(twl4030_op_modes_texts), - twl4030_op_modes_texts); - -int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct twl4030_priv *twl4030 = codec->private_data; - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - unsigned short val; - unsigned short mask, bitmask; - - if (twl4030->configured) { - printk(KERN_ERR "twl4030 operation mode cannot be " - "changed on-the-fly\n"); - return -EBUSY; - } - - for (bitmask = 1; bitmask < e->max; bitmask <<= 1) - ; - if (ucontrol->value.enumerated.item[0] > e->max - 1) - return -EINVAL; - - val = ucontrol->value.enumerated.item[0] << e->shift_l; - mask = (bitmask - 1) << e->shift_l; - if (e->shift_l != e->shift_r) { - if (ucontrol->value.enumerated.item[1] > e->max - 1) - return -EINVAL; - val |= ucontrol->value.enumerated.item[1] << e->shift_r; - mask |= (bitmask - 1) << e->shift_r; - } - - return snd_soc_update_bits(codec, e->reg, mask, val); -} - /* * FGAIN volume control: * from -62 to 0 dB in 1 dB steps (mute instead of -63 dB) @@ -969,12 +823,6 @@ static DECLARE_TLV_DB_SCALE(digital_fine_tlv, -6300, 100, 1); */ static DECLARE_TLV_DB_SCALE(digital_coarse_tlv, 0, 600, 0); -/* - * Voice Downlink GAIN volume control: - * from -37 to 12 dB in 1 dB steps (mute instead of -37 dB) - */ -static DECLARE_TLV_DB_SCALE(digital_voice_downlink_tlv, -3700, 100, 1); - /* * Analog playback gain * -24 dB to 12 dB in 2 dB steps @@ -1016,32 +864,7 @@ static const struct soc_enum twl4030_rampdelay_enum = ARRAY_SIZE(twl4030_rampdelay_texts), twl4030_rampdelay_texts); -/* Vibra H-bridge direction mode */ -static const char *twl4030_vibradirmode_texts[] = { - "Vibra H-bridge direction", "Audio data MSB", -}; - -static const struct soc_enum twl4030_vibradirmode_enum = - SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 5, - ARRAY_SIZE(twl4030_vibradirmode_texts), - twl4030_vibradirmode_texts); - -/* Vibra H-bridge direction */ -static const char *twl4030_vibradir_texts[] = { - "Positive polarity", "Negative polarity", -}; - -static const struct soc_enum twl4030_vibradir_enum = - SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 1, - ARRAY_SIZE(twl4030_vibradir_texts), - twl4030_vibradir_texts); - static const struct snd_kcontrol_new twl4030_snd_controls[] = { - /* Codec operation mode control */ - SOC_ENUM_EXT("Codec Operation Mode", twl4030_op_modes_enum, - snd_soc_get_enum_double, - snd_soc_put_twl4030_opmode_enum_double), - /* Common playback gain controls */ SOC_DOUBLE_R_TLV("DAC1 Digital Fine Playback Volume", TWL4030_REG_ARXL1PGA, TWL4030_REG_ARXR1PGA, @@ -1070,16 +893,6 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = { TWL4030_REG_ARXL2_APGA_CTL, TWL4030_REG_ARXR2_APGA_CTL, 1, 1, 0), - /* Common voice downlink gain controls */ - SOC_SINGLE_TLV("DAC Voice Digital Downlink Volume", - TWL4030_REG_VRXPGA, 0, 0x31, 0, digital_voice_downlink_tlv), - - SOC_SINGLE_TLV("DAC Voice Analog Downlink Volume", - TWL4030_REG_VDL_APGA_CTL, 3, 0x12, 1, analog_tlv), - - SOC_SINGLE("DAC Voice Analog Downlink Switch", - TWL4030_REG_VDL_APGA_CTL, 1, 1, 0), - /* Separate output gain controls */ SOC_DOUBLE_R_TLV_TWL4030("PreDriv Playback Volume", TWL4030_REG_PREDL_CTL, TWL4030_REG_PREDR_CTL, @@ -1107,9 +920,6 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = { 0, 3, 5, 0, input_gain_tlv), SOC_ENUM("HS ramp delay", twl4030_rampdelay_enum), - - SOC_ENUM("Vibra H-bridge mode", twl4030_vibradirmode_enum), - SOC_ENUM("Vibra H-bridge direction", twl4030_vibradir_enum), }; static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { @@ -1137,20 +947,27 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("CARKITR"), SND_SOC_DAPM_OUTPUT("HFL"), SND_SOC_DAPM_OUTPUT("HFR"), - SND_SOC_DAPM_OUTPUT("VIBRA"), /* DACs */ - SND_SOC_DAPM_DAC("DAC Right1", "Right Front HiFi Playback", + SND_SOC_DAPM_DAC("DAC Right1", "Right Front Playback", SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_DAC("DAC Left1", "Left Front HiFi Playback", + SND_SOC_DAPM_DAC("DAC Left1", "Left Front Playback", SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_DAC("DAC Right2", "Right Rear HiFi Playback", + SND_SOC_DAPM_DAC("DAC Right2", "Right Rear Playback", SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_DAC("DAC Left2", "Left Rear HiFi Playback", - SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_DAC("DAC Voice", "Voice Playback", + SND_SOC_DAPM_DAC("DAC Left2", "Left Rear Playback", SND_SOC_NOPM, 0, 0), + /* Analog PGAs */ + SND_SOC_DAPM_PGA("ARXR1_APGA", TWL4030_REG_ARXR1_APGA_CTL, + 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("ARXL1_APGA", TWL4030_REG_ARXL1_APGA_CTL, + 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("ARXR2_APGA", TWL4030_REG_ARXR2_APGA_CTL, + 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("ARXL2_APGA", TWL4030_REG_ARXL2_APGA_CTL, + 0, 0, NULL, 0), + /* Analog bypasses */ SND_SOC_DAPM_SWITCH_E("Right1 Analog Loopback", SND_SOC_NOPM, 0, 0, &twl4030_dapm_abypassr1_control, bypass_event, @@ -1164,9 +981,6 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_SWITCH_E("Left2 Analog Loopback", SND_SOC_NOPM, 0, 0, &twl4030_dapm_abypassl2_control, bypass_event, SND_SOC_DAPM_POST_REG), - SND_SOC_DAPM_SWITCH_E("Voice Analog Loopback", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_abypassv_control, - bypass_event, SND_SOC_DAPM_POST_REG), /* Digital bypasses */ SND_SOC_DAPM_SWITCH_E("Left Digital Loopback", SND_SOC_NOPM, 0, 0, @@ -1175,88 +989,43 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_SWITCH_E("Right Digital Loopback", SND_SOC_NOPM, 0, 0, &twl4030_dapm_dbypassr_control, bypass_event, SND_SOC_DAPM_POST_REG), - SND_SOC_DAPM_SWITCH_E("Voice Digital Loopback", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_dbypassv_control, bypass_event, - SND_SOC_DAPM_POST_REG), - /* Digital mixers, power control for the physical DACs */ - SND_SOC_DAPM_MIXER("Digital R1 Playback Mixer", - TWL4030_REG_AVDAC_CTL, 0, 0, NULL, 0), - SND_SOC_DAPM_MIXER("Digital L1 Playback Mixer", - TWL4030_REG_AVDAC_CTL, 1, 0, NULL, 0), - SND_SOC_DAPM_MIXER("Digital R2 Playback Mixer", - TWL4030_REG_AVDAC_CTL, 2, 0, NULL, 0), - SND_SOC_DAPM_MIXER("Digital L2 Playback Mixer", - TWL4030_REG_AVDAC_CTL, 3, 0, NULL, 0), - SND_SOC_DAPM_MIXER("Digital Voice Playback Mixer", - TWL4030_REG_AVDAC_CTL, 4, 0, NULL, 0), - - /* Analog mixers, power control for the physical PGAs */ - SND_SOC_DAPM_MIXER("Analog R1 Playback Mixer", - TWL4030_REG_ARXR1_APGA_CTL, 0, 0, NULL, 0), - SND_SOC_DAPM_MIXER("Analog L1 Playback Mixer", - TWL4030_REG_ARXL1_APGA_CTL, 0, 0, NULL, 0), - SND_SOC_DAPM_MIXER("Analog R2 Playback Mixer", - TWL4030_REG_ARXR2_APGA_CTL, 0, 0, NULL, 0), - SND_SOC_DAPM_MIXER("Analog L2 Playback Mixer", - TWL4030_REG_ARXL2_APGA_CTL, 0, 0, NULL, 0), - SND_SOC_DAPM_MIXER("Analog Voice Playback Mixer", - TWL4030_REG_VDL_APGA_CTL, 0, 0, NULL, 0), - - /* Output MIXER controls */ + SND_SOC_DAPM_MIXER("Analog R1 Playback Mixer", TWL4030_REG_AVDAC_CTL, + 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Analog L1 Playback Mixer", TWL4030_REG_AVDAC_CTL, + 1, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Analog R2 Playback Mixer", TWL4030_REG_AVDAC_CTL, + 2, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Analog L2 Playback Mixer", TWL4030_REG_AVDAC_CTL, + 3, 0, NULL, 0), + + /* Output MUX controls */ /* Earpiece */ - SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_earpiece_controls[0], - ARRAY_SIZE(twl4030_dapm_earpiece_controls)), + SND_SOC_DAPM_VALUE_MUX("Earpiece Mux", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_earpiece_control), /* PreDrivL/R */ - SND_SOC_DAPM_MIXER("PredriveL Mixer", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_predrivel_controls[0], - ARRAY_SIZE(twl4030_dapm_predrivel_controls)), - SND_SOC_DAPM_MIXER("PredriveR Mixer", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_predriver_controls[0], - ARRAY_SIZE(twl4030_dapm_predriver_controls)), + SND_SOC_DAPM_VALUE_MUX("PredriveL Mux", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_predrivel_control), + SND_SOC_DAPM_VALUE_MUX("PredriveR Mux", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_predriver_control), /* HeadsetL/R */ - SND_SOC_DAPM_MIXER("HeadsetL Mixer", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_hsol_controls[0], - ARRAY_SIZE(twl4030_dapm_hsol_controls)), - SND_SOC_DAPM_PGA_E("HeadsetL PGA", SND_SOC_NOPM, - 0, 0, NULL, 0, headsetlpga_event, - SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MIXER("HeadsetR Mixer", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_hsor_controls[0], - ARRAY_SIZE(twl4030_dapm_hsor_controls)), - SND_SOC_DAPM_PGA_E("HeadsetR PGA", SND_SOC_NOPM, - 0, 0, NULL, 0, headsetrpga_event, - SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("HeadsetL Mux", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_hsol_control, headsetl_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX("HeadsetR Mux", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_hsor_control), /* CarkitL/R */ - SND_SOC_DAPM_MIXER("CarkitL Mixer", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_carkitl_controls[0], - ARRAY_SIZE(twl4030_dapm_carkitl_controls)), - SND_SOC_DAPM_MIXER("CarkitR Mixer", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_carkitr_controls[0], - ARRAY_SIZE(twl4030_dapm_carkitr_controls)), - - /* Output MUX controls */ + SND_SOC_DAPM_MUX("CarkitL Mux", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_carkitl_control), + SND_SOC_DAPM_MUX("CarkitR Mux", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_carkitr_control), /* HandsfreeL/R */ - SND_SOC_DAPM_MUX("HandsfreeL Mux", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_handsfreel_control), - SND_SOC_DAPM_SWITCH("HandsfreeL Switch", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_handsfreelmute_control), - SND_SOC_DAPM_PGA_E("HandsfreeL PGA", SND_SOC_NOPM, - 0, 0, NULL, 0, handsfreelpga_event, - SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MUX("HandsfreeR Mux", SND_SOC_NOPM, 5, 0, - &twl4030_dapm_handsfreer_control), - SND_SOC_DAPM_SWITCH("HandsfreeR Switch", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_handsfreermute_control), - SND_SOC_DAPM_PGA_E("HandsfreeR PGA", SND_SOC_NOPM, - 0, 0, NULL, 0, handsfreerpga_event, - SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), - /* Vibra */ - SND_SOC_DAPM_MUX("Vibra Mux", TWL4030_REG_VIBRA_CTL, 0, 0, - &twl4030_dapm_vibra_control), - SND_SOC_DAPM_MUX("Vibra Route", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_vibrapath_control), + SND_SOC_DAPM_MUX_E("HandsfreeL Mux", TWL4030_REG_HFL_CTL, 5, 0, + &twl4030_dapm_handsfreel_control, handsfree_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("HandsfreeR Mux", TWL4030_REG_HFR_CTL, 5, 0, + &twl4030_dapm_handsfreer_control, handsfree_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), /* Introducing four virtual ADC, since TWL4030 have four channel for capture */ @@ -1281,15 +1050,11 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD| SND_SOC_DAPM_POST_REG), - /* Analog input mixers for the capture amplifiers */ - SND_SOC_DAPM_MIXER("Analog Left Capture Route", - TWL4030_REG_ANAMICL, 4, 0, - &twl4030_dapm_analoglmic_controls[0], - ARRAY_SIZE(twl4030_dapm_analoglmic_controls)), - SND_SOC_DAPM_MIXER("Analog Right Capture Route", - TWL4030_REG_ANAMICR, 4, 0, - &twl4030_dapm_analogrmic_controls[0], - ARRAY_SIZE(twl4030_dapm_analogrmic_controls)), + /* Analog input muxes with switch for the capture amplifiers */ + SND_SOC_DAPM_VALUE_MUX("Analog Left Capture Route", + TWL4030_REG_ANAMICL, 4, 0, &twl4030_dapm_analoglmic_control), + SND_SOC_DAPM_VALUE_MUX("Analog Right Capture Route", + TWL4030_REG_ANAMICR, 4, 0, &twl4030_dapm_analogrmic_control), SND_SOC_DAPM_PGA("ADC Physical Left", TWL4030_REG_AVADC_CTL, 3, 0, NULL, 0), @@ -1308,86 +1073,62 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { }; static const struct snd_soc_dapm_route intercon[] = { - {"Digital L1 Playback Mixer", NULL, "DAC Left1"}, - {"Digital R1 Playback Mixer", NULL, "DAC Right1"}, - {"Digital L2 Playback Mixer", NULL, "DAC Left2"}, - {"Digital R2 Playback Mixer", NULL, "DAC Right2"}, - {"Digital Voice Playback Mixer", NULL, "DAC Voice"}, - - {"Analog L1 Playback Mixer", NULL, "Digital L1 Playback Mixer"}, - {"Analog R1 Playback Mixer", NULL, "Digital R1 Playback Mixer"}, - {"Analog L2 Playback Mixer", NULL, "Digital L2 Playback Mixer"}, - {"Analog R2 Playback Mixer", NULL, "Digital R2 Playback Mixer"}, - {"Analog Voice Playback Mixer", NULL, "Digital Voice Playback Mixer"}, + {"Analog L1 Playback Mixer", NULL, "DAC Left1"}, + {"Analog R1 Playback Mixer", NULL, "DAC Right1"}, + {"Analog L2 Playback Mixer", NULL, "DAC Left2"}, + {"Analog R2 Playback Mixer", NULL, "DAC Right2"}, + + {"ARXL1_APGA", NULL, "Analog L1 Playback Mixer"}, + {"ARXR1_APGA", NULL, "Analog R1 Playback Mixer"}, + {"ARXL2_APGA", NULL, "Analog L2 Playback Mixer"}, + {"ARXR2_APGA", NULL, "Analog R2 Playback Mixer"}, /* Internal playback routings */ /* Earpiece */ - {"Earpiece Mixer", "Voice", "Analog Voice Playback Mixer"}, - {"Earpiece Mixer", "AudioL1", "Analog L1 Playback Mixer"}, - {"Earpiece Mixer", "AudioL2", "Analog L2 Playback Mixer"}, - {"Earpiece Mixer", "AudioR1", "Analog R1 Playback Mixer"}, + {"Earpiece Mux", "DACL1", "ARXL1_APGA"}, + {"Earpiece Mux", "DACL2", "ARXL2_APGA"}, + {"Earpiece Mux", "DACR1", "ARXR1_APGA"}, /* PreDrivL */ - {"PredriveL Mixer", "Voice", "Analog Voice Playback Mixer"}, - {"PredriveL Mixer", "AudioL1", "Analog L1 Playback Mixer"}, - {"PredriveL Mixer", "AudioL2", "Analog L2 Playback Mixer"}, - {"PredriveL Mixer", "AudioR2", "Analog R2 Playback Mixer"}, + {"PredriveL Mux", "DACL1", "ARXL1_APGA"}, + {"PredriveL Mux", "DACL2", "ARXL2_APGA"}, + {"PredriveL Mux", "DACR2", "ARXR2_APGA"}, /* PreDrivR */ - {"PredriveR Mixer", "Voice", "Analog Voice Playback Mixer"}, - {"PredriveR Mixer", "AudioR1", "Analog R1 Playback Mixer"}, - {"PredriveR Mixer", "AudioR2", "Analog R2 Playback Mixer"}, - {"PredriveR Mixer", "AudioL2", "Analog L2 Playback Mixer"}, + {"PredriveR Mux", "DACR1", "ARXR1_APGA"}, + {"PredriveR Mux", "DACR2", "ARXR2_APGA"}, + {"PredriveR Mux", "DACL2", "ARXL2_APGA"}, /* HeadsetL */ - {"HeadsetL Mixer", "Voice", "Analog Voice Playback Mixer"}, - {"HeadsetL Mixer", "AudioL1", "Analog L1 Playback Mixer"}, - {"HeadsetL Mixer", "AudioL2", "Analog L2 Playback Mixer"}, - {"HeadsetL PGA", NULL, "HeadsetL Mixer"}, + {"HeadsetL Mux", "DACL1", "ARXL1_APGA"}, + {"HeadsetL Mux", "DACL2", "ARXL2_APGA"}, /* HeadsetR */ - {"HeadsetR Mixer", "Voice", "Analog Voice Playback Mixer"}, - {"HeadsetR Mixer", "AudioR1", "Analog R1 Playback Mixer"}, - {"HeadsetR Mixer", "AudioR2", "Analog R2 Playback Mixer"}, - {"HeadsetR PGA", NULL, "HeadsetR Mixer"}, + {"HeadsetR Mux", "DACR1", "ARXR1_APGA"}, + {"HeadsetR Mux", "DACR2", "ARXR2_APGA"}, /* CarkitL */ - {"CarkitL Mixer", "Voice", "Analog Voice Playback Mixer"}, - {"CarkitL Mixer", "AudioL1", "Analog L1 Playback Mixer"}, - {"CarkitL Mixer", "AudioL2", "Analog L2 Playback Mixer"}, + {"CarkitL Mux", "DACL1", "ARXL1_APGA"}, + {"CarkitL Mux", "DACL2", "ARXL2_APGA"}, /* CarkitR */ - {"CarkitR Mixer", "Voice", "Analog Voice Playback Mixer"}, - {"CarkitR Mixer", "AudioR1", "Analog R1 Playback Mixer"}, - {"CarkitR Mixer", "AudioR2", "Analog R2 Playback Mixer"}, + {"CarkitR Mux", "DACR1", "ARXR1_APGA"}, + {"CarkitR Mux", "DACR2", "ARXR2_APGA"}, /* HandsfreeL */ - {"HandsfreeL Mux", "Voice", "Analog Voice Playback Mixer"}, - {"HandsfreeL Mux", "AudioL1", "Analog L1 Playback Mixer"}, - {"HandsfreeL Mux", "AudioL2", "Analog L2 Playback Mixer"}, - {"HandsfreeL Mux", "AudioR2", "Analog R2 Playback Mixer"}, - {"HandsfreeL Switch", "Switch", "HandsfreeL Mux"}, - {"HandsfreeL PGA", NULL, "HandsfreeL Switch"}, + {"HandsfreeL Mux", "DACL1", "ARXL1_APGA"}, + {"HandsfreeL Mux", "DACL2", "ARXL2_APGA"}, + {"HandsfreeL Mux", "DACR2", "ARXR2_APGA"}, /* HandsfreeR */ - {"HandsfreeR Mux", "Voice", "Analog Voice Playback Mixer"}, - {"HandsfreeR Mux", "AudioR1", "Analog R1 Playback Mixer"}, - {"HandsfreeR Mux", "AudioR2", "Analog R2 Playback Mixer"}, - {"HandsfreeR Mux", "AudioL2", "Analog L2 Playback Mixer"}, - {"HandsfreeR Switch", "Switch", "HandsfreeR Mux"}, - {"HandsfreeR PGA", NULL, "HandsfreeR Switch"}, - /* Vibra */ - {"Vibra Mux", "AudioL1", "DAC Left1"}, - {"Vibra Mux", "AudioR1", "DAC Right1"}, - {"Vibra Mux", "AudioL2", "DAC Left2"}, - {"Vibra Mux", "AudioR2", "DAC Right2"}, + {"HandsfreeR Mux", "DACR1", "ARXR1_APGA"}, + {"HandsfreeR Mux", "DACR2", "ARXR2_APGA"}, + {"HandsfreeR Mux", "DACL2", "ARXL2_APGA"}, /* outputs */ - {"OUTL", NULL, "Analog L2 Playback Mixer"}, - {"OUTR", NULL, "Analog R2 Playback Mixer"}, - {"EARPIECE", NULL, "Earpiece Mixer"}, - {"PREDRIVEL", NULL, "PredriveL Mixer"}, - {"PREDRIVER", NULL, "PredriveR Mixer"}, - {"HSOL", NULL, "HeadsetL PGA"}, - {"HSOR", NULL, "HeadsetR PGA"}, - {"CARKITL", NULL, "CarkitL Mixer"}, - {"CARKITR", NULL, "CarkitR Mixer"}, - {"HFL", NULL, "HandsfreeL PGA"}, - {"HFR", NULL, "HandsfreeR PGA"}, - {"Vibra Route", "Audio", "Vibra Mux"}, - {"VIBRA", NULL, "Vibra Route"}, + {"OUTL", NULL, "ARXL2_APGA"}, + {"OUTR", NULL, "ARXR2_APGA"}, + {"EARPIECE", NULL, "Earpiece Mux"}, + {"PREDRIVEL", NULL, "PredriveL Mux"}, + {"PREDRIVER", NULL, "PredriveR Mux"}, + {"HSOL", NULL, "HeadsetL Mux"}, + {"HSOR", NULL, "HeadsetR Mux"}, + {"CARKITL", NULL, "CarkitL Mux"}, + {"CARKITR", NULL, "CarkitR Mux"}, + {"HFL", NULL, "HandsfreeL Mux"}, + {"HFR", NULL, "HandsfreeR Mux"}, /* Capture path */ {"Analog Left Capture Route", "Main mic", "MAINMIC"}, @@ -1427,22 +1168,18 @@ static const struct snd_soc_dapm_route intercon[] = { {"Left1 Analog Loopback", "Switch", "Analog Left Capture Route"}, {"Right2 Analog Loopback", "Switch", "Analog Right Capture Route"}, {"Left2 Analog Loopback", "Switch", "Analog Left Capture Route"}, - {"Voice Analog Loopback", "Switch", "Analog Left Capture Route"}, {"Analog R1 Playback Mixer", NULL, "Right1 Analog Loopback"}, {"Analog L1 Playback Mixer", NULL, "Left1 Analog Loopback"}, {"Analog R2 Playback Mixer", NULL, "Right2 Analog Loopback"}, {"Analog L2 Playback Mixer", NULL, "Left2 Analog Loopback"}, - {"Analog Voice Playback Mixer", NULL, "Voice Analog Loopback"}, /* Digital bypass routes */ {"Right Digital Loopback", "Volume", "TX1 Capture Route"}, {"Left Digital Loopback", "Volume", "TX1 Capture Route"}, - {"Voice Digital Loopback", "Volume", "TX2 Capture Route"}, - {"Digital R2 Playback Mixer", NULL, "Right Digital Loopback"}, - {"Digital L2 Playback Mixer", NULL, "Left Digital Loopback"}, - {"Digital Voice Playback Mixer", NULL, "Voice Digital Loopback"}, + {"Analog R2 Playback Mixer", NULL, "Right Digital Loopback"}, + {"Analog L2 Playback Mixer", NULL, "Left Digital Loopback"}, }; @@ -1489,58 +1226,6 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec, return 0; } -static void twl4030_constraints(struct twl4030_priv *twl4030, - struct snd_pcm_substream *mst_substream) -{ - struct snd_pcm_substream *slv_substream; - - /* Pick the stream, which need to be constrained */ - if (mst_substream == twl4030->master_substream) - slv_substream = twl4030->slave_substream; - else if (mst_substream == twl4030->slave_substream) - slv_substream = twl4030->master_substream; - else /* This should not happen.. */ - return; - - /* Set the constraints according to the already configured stream */ - snd_pcm_hw_constraint_minmax(slv_substream->runtime, - SNDRV_PCM_HW_PARAM_RATE, - twl4030->rate, - twl4030->rate); - - snd_pcm_hw_constraint_minmax(slv_substream->runtime, - SNDRV_PCM_HW_PARAM_SAMPLE_BITS, - twl4030->sample_bits, - twl4030->sample_bits); - - snd_pcm_hw_constraint_minmax(slv_substream->runtime, - SNDRV_PCM_HW_PARAM_CHANNELS, - twl4030->channels, - twl4030->channels); -} - -/* In case of 4 channel mode, the RX1 L/R for playback and the TX2 L/R for - * capture has to be enabled/disabled. */ -static void twl4030_tdm_enable(struct snd_soc_codec *codec, int direction, - int enable) -{ - u8 reg, mask; - - reg = twl4030_read_reg_cache(codec, TWL4030_REG_OPTION); - - if (direction == SNDRV_PCM_STREAM_PLAYBACK) - mask = TWL4030_ARXL1_VRX_EN | TWL4030_ARXR1_EN; - else - mask = TWL4030_ATXL2_VTXL_EN | TWL4030_ATXR2_VTXR_EN; - - if (enable) - reg |= mask; - else - reg &= ~mask; - - twl4030_write(codec, TWL4030_REG_OPTION, reg); -} - static int twl4030_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -1549,25 +1234,26 @@ static int twl4030_startup(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = socdev->card->codec; struct twl4030_priv *twl4030 = codec->private_data; + /* If we already have a playback or capture going then constrain + * this substream to match it. + */ if (twl4030->master_substream) { + struct snd_pcm_runtime *master_runtime; + master_runtime = twl4030->master_substream->runtime; + + snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_RATE, + master_runtime->rate, + master_runtime->rate); + + snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_SAMPLE_BITS, + master_runtime->sample_bits, + master_runtime->sample_bits); + twl4030->slave_substream = substream; - /* The DAI has one configuration for playback and capture, so - * if the DAI has been already configured then constrain this - * substream to match it. */ - if (twl4030->configured) - twl4030_constraints(twl4030, twl4030->master_substream); - } else { - if (!(twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE) & - TWL4030_OPTION_1)) { - /* In option2 4 channel is not supported, set the - * constraint for the first stream for channels, the - * second stream will 'inherit' this cosntraint */ - snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_CHANNELS, - 2, 2); - } + } else twl4030->master_substream = substream; - } return 0; } @@ -1584,17 +1270,6 @@ static void twl4030_shutdown(struct snd_pcm_substream *substream, twl4030->master_substream = twl4030->slave_substream; twl4030->slave_substream = NULL; - - /* If all streams are closed, or the remaining stream has not yet - * been configured than set the DAI as not configured. */ - if (!twl4030->master_substream) - twl4030->configured = 0; - else if (!twl4030->master_substream->runtime->channels) - twl4030->configured = 0; - - /* If the closing substream had 4 channel, do the necessary cleanup */ - if (substream->runtime->channels == 4) - twl4030_tdm_enable(codec, substream->stream, 0); } static int twl4030_hw_params(struct snd_pcm_substream *substream, @@ -1607,24 +1282,8 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, struct twl4030_priv *twl4030 = codec->private_data; u8 mode, old_mode, format, old_format; - /* If the substream has 4 channel, do the necessary setup */ - if (params_channels(params) == 4) { - u8 format, mode; - - format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); - mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE); - - /* Safety check: are we in the correct operating mode and - * the interface is in TDM mode? */ - if ((mode & TWL4030_OPTION_1) && - ((format & TWL4030_AIF_FORMAT) == TWL4030_AIF_FORMAT_TDM)) - twl4030_tdm_enable(codec, substream->stream, 1); - else - return -EINVAL; - } - - if (twl4030->configured) - /* Ignoring hw_params for already configured DAI */ + if (substream == twl4030->slave_substream) + /* Ignoring hw_params for slave substream */ return 0; /* bit rate */ @@ -1704,21 +1363,6 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, /* set CODECPDZ afterwards */ twl4030_codec_enable(codec, 1); } - - /* Store the important parameters for the DAI configuration and set - * the DAI as configured */ - twl4030->configured = 1; - twl4030->rate = params_rate(params); - twl4030->sample_bits = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min; - twl4030->channels = params_channels(params); - - /* If both playback and capture streams are open, and one of them - * is setting the hw parameters right now (since we are here), set - * constraints to the other stream to match the current one. */ - if (twl4030->slave_substream) - twl4030_constraints(twl4030, substream); - return 0; } @@ -1726,21 +1370,17 @@ static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir) { struct snd_soc_codec *codec = codec_dai->codec; - struct twl4030_priv *twl4030 = codec->private_data; u8 infreq; switch (freq) { case 19200000: infreq = TWL4030_APLL_INFREQ_19200KHZ; - twl4030->sysclk = 19200; break; case 26000000: infreq = TWL4030_APLL_INFREQ_26000KHZ; - twl4030->sysclk = 26000; break; case 38400000: infreq = TWL4030_APLL_INFREQ_38400KHZ; - twl4030->sysclk = 38400; break; default: printk(KERN_ERR "TWL4030 set sysclk: unknown rate %d\n", @@ -1784,9 +1424,6 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, case SND_SOC_DAIFMT_I2S: format |= TWL4030_AIF_FORMAT_CODEC; break; - case SND_SOC_DAIFMT_DSP_A: - format |= TWL4030_AIF_FORMAT_TDM; - break; default: return -EINVAL; } @@ -1806,180 +1443,6 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, return 0; } -/* In case of voice mode, the RX1 L(VRX) for downlink and the TX2 L/R - * (VTXL, VTXR) for uplink has to be enabled/disabled. */ -static void twl4030_voice_enable(struct snd_soc_codec *codec, int direction, - int enable) -{ - u8 reg, mask; - - reg = twl4030_read_reg_cache(codec, TWL4030_REG_OPTION); - - if (direction == SNDRV_PCM_STREAM_PLAYBACK) - mask = TWL4030_ARXL1_VRX_EN; - else - mask = TWL4030_ATXL2_VTXL_EN | TWL4030_ATXR2_VTXR_EN; - - if (enable) - reg |= mask; - else - reg &= ~mask; - - twl4030_write(codec, TWL4030_REG_OPTION, reg); -} - -static int twl4030_voice_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->card->codec; - u8 infreq; - u8 mode; - - /* If the system master clock is not 26MHz, the voice PCM interface is - * not avilable. - */ - infreq = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL) - & TWL4030_APLL_INFREQ; - - if (infreq != TWL4030_APLL_INFREQ_26000KHZ) { - printk(KERN_ERR "TWL4030 voice startup: " - "MCLK is not 26MHz, call set_sysclk() on init\n"); - return -EINVAL; - } - - /* If the codec mode is not option2, the voice PCM interface is not - * avilable. - */ - mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE) - & TWL4030_OPT_MODE; - - if (mode != TWL4030_OPTION_2) { - printk(KERN_ERR "TWL4030 voice startup: " - "the codec mode is not option2\n"); - return -EINVAL; - } - - return 0; -} - -static void twl4030_voice_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->card->codec; - - /* Enable voice digital filters */ - twl4030_voice_enable(codec, substream->stream, 0); -} - -static int twl4030_voice_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->card->codec; - u8 old_mode, mode; - - /* Enable voice digital filters */ - twl4030_voice_enable(codec, substream->stream, 1); - - /* bit rate */ - old_mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE) - & ~(TWL4030_CODECPDZ); - mode = old_mode; - - switch (params_rate(params)) { - case 8000: - mode &= ~(TWL4030_SEL_16K); - break; - case 16000: - mode |= TWL4030_SEL_16K; - break; - default: - printk(KERN_ERR "TWL4030 voice hw params: unknown rate %d\n", - params_rate(params)); - return -EINVAL; - } - - if (mode != old_mode) { - /* change rate and set CODECPDZ */ - twl4030_codec_enable(codec, 0); - twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode); - twl4030_codec_enable(codec, 1); - } - - return 0; -} - -static int twl4030_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir) -{ - struct snd_soc_codec *codec = codec_dai->codec; - u8 infreq; - - switch (freq) { - case 26000000: - infreq = TWL4030_APLL_INFREQ_26000KHZ; - break; - default: - printk(KERN_ERR "TWL4030 voice set sysclk: unknown rate %d\n", - freq); - return -EINVAL; - } - - infreq |= TWL4030_APLL_EN; - twl4030_write(codec, TWL4030_REG_APLL_CTL, infreq); - - return 0; -} - -static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) -{ - struct snd_soc_codec *codec = codec_dai->codec; - u8 old_format, format; - - /* get format */ - old_format = twl4030_read_reg_cache(codec, TWL4030_REG_VOICE_IF); - format = old_format; - - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFM: - format &= ~(TWL4030_VIF_SLAVE_EN); - break; - case SND_SOC_DAIFMT_CBS_CFS: - format |= TWL4030_VIF_SLAVE_EN; - break; - default: - return -EINVAL; - } - - /* clock inversion */ - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_IB_NF: - format &= ~(TWL4030_VIF_FORMAT); - break; - case SND_SOC_DAIFMT_NB_IF: - format |= TWL4030_VIF_FORMAT; - break; - default: - return -EINVAL; - } - - if (format != old_format) { - /* change format and set CODECPDZ */ - twl4030_codec_enable(codec, 0); - twl4030_write(codec, TWL4030_REG_VOICE_IF, format); - twl4030_codec_enable(codec, 1); - } - - return 0; -} - #define TWL4030_RATES (SNDRV_PCM_RATE_8000_48000) #define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE) @@ -1991,47 +1454,21 @@ static struct snd_soc_dai_ops twl4030_dai_ops = { .set_fmt = twl4030_set_dai_fmt, }; -static struct snd_soc_dai_ops twl4030_dai_voice_ops = { - .startup = twl4030_voice_startup, - .shutdown = twl4030_voice_shutdown, - .hw_params = twl4030_voice_hw_params, - .set_sysclk = twl4030_voice_set_dai_sysclk, - .set_fmt = twl4030_voice_set_dai_fmt, -}; - -struct snd_soc_dai twl4030_dai[] = { -{ +struct snd_soc_dai twl4030_dai = { .name = "twl4030", .playback = { - .stream_name = "HiFi Playback", + .stream_name = "Playback", .channels_min = 2, - .channels_max = 4, + .channels_max = 2, .rates = TWL4030_RATES | SNDRV_PCM_RATE_96000, .formats = TWL4030_FORMATS,}, .capture = { .stream_name = "Capture", .channels_min = 2, - .channels_max = 4, + .channels_max = 2, .rates = TWL4030_RATES, .formats = TWL4030_FORMATS,}, .ops = &twl4030_dai_ops, -}, -{ - .name = "twl4030 Voice", - .playback = { - .stream_name = "Voice Playback", - .channels_min = 1, - .channels_max = 1, - .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, - .capture = { - .stream_name = "Capture", - .channels_min = 1, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, - .ops = &twl4030_dai_voice_ops, -}, }; EXPORT_SYMBOL_GPL(twl4030_dai); @@ -2063,8 +1500,6 @@ static int twl4030_resume(struct platform_device *pdev) static int twl4030_init(struct snd_soc_device *socdev) { struct snd_soc_codec *codec = socdev->card->codec; - struct twl4030_setup_data *setup = socdev->codec_data; - struct twl4030_priv *twl4030 = codec->private_data; int ret = 0; printk(KERN_INFO "TWL4030 Audio Codec init \n"); @@ -2074,31 +1509,14 @@ static int twl4030_init(struct snd_soc_device *socdev) codec->read = twl4030_read_reg_cache; codec->write = twl4030_write; codec->set_bias_level = twl4030_set_bias_level; - codec->dai = twl4030_dai; - codec->num_dai = ARRAY_SIZE(twl4030_dai), + codec->dai = &twl4030_dai; + codec->num_dai = 1; codec->reg_cache_size = sizeof(twl4030_reg); codec->reg_cache = kmemdup(twl4030_reg, sizeof(twl4030_reg), GFP_KERNEL); if (codec->reg_cache == NULL) return -ENOMEM; - /* Configuration for headset ramp delay from setup data */ - if (setup) { - unsigned char hs_pop; - - if (setup->sysclk) - twl4030->sysclk = setup->sysclk; - else - twl4030->sysclk = 26000; - - hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); - hs_pop &= ~TWL4030_RAMP_DELAY; - hs_pop |= (setup->ramp_delay_value << 2); - twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, hs_pop); - } else { - twl4030->sysclk = 26000; - } - /* register pcms */ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); if (ret < 0) { @@ -2186,13 +1604,13 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_twl4030); static int __init twl4030_modinit(void) { - return snd_soc_register_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai)); + return snd_soc_register_dai(&twl4030_dai); } module_init(twl4030_modinit); static void __exit twl4030_exit(void) { - snd_soc_unregister_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai)); + snd_soc_unregister_dai(&twl4030_dai); } module_exit(twl4030_exit); diff --git a/trunk/sound/soc/codecs/twl4030.h b/trunk/sound/soc/codecs/twl4030.h index fe5f395d9e4f..cb63765db1df 100644 --- a/trunk/sound/soc/codecs/twl4030.h +++ b/trunk/sound/soc/codecs/twl4030.h @@ -92,9 +92,8 @@ #define TWL4030_REG_VIBRA_PWM_SET 0x47 #define TWL4030_REG_ANAMIC_GAIN 0x48 #define TWL4030_REG_MISC_SET_2 0x49 -#define TWL4030_REG_SW_SHADOW 0x4A -#define TWL4030_CACHEREGNUM (TWL4030_REG_SW_SHADOW + 1) +#define TWL4030_CACHEREGNUM (TWL4030_REG_MISC_SET_2 + 1) /* Bitfield Definitions */ @@ -111,22 +110,9 @@ #define TWL4030_APLL_RATE_44100 0x90 #define TWL4030_APLL_RATE_48000 0xA0 #define TWL4030_APLL_RATE_96000 0xE0 -#define TWL4030_SEL_16K 0x08 +#define TWL4030_SEL_16K 0x04 #define TWL4030_CODECPDZ 0x02 #define TWL4030_OPT_MODE 0x01 -#define TWL4030_OPTION_1 (1 << 0) -#define TWL4030_OPTION_2 (0 << 0) - -/* TWL4030_OPTION (0x02) Fields */ - -#define TWL4030_ATXL1_EN (1 << 0) -#define TWL4030_ATXR1_EN (1 << 1) -#define TWL4030_ATXL2_VTXL_EN (1 << 2) -#define TWL4030_ATXR2_VTXR_EN (1 << 3) -#define TWL4030_ARXL1_VRX_EN (1 << 4) -#define TWL4030_ARXR1_EN (1 << 5) -#define TWL4030_ARXL2_EN (1 << 6) -#define TWL4030_ARXR2_EN (1 << 7) /* TWL4030_REG_MICBIAS_CTL (0x04) Fields */ @@ -185,17 +171,6 @@ #define TWL4030_CLK256FS_EN 0x02 #define TWL4030_AIF_EN 0x01 -/* VOICE_IF (0x0F) Fields */ - -#define TWL4030_VIF_SLAVE_EN 0x80 -#define TWL4030_VIF_DIN_EN 0x40 -#define TWL4030_VIF_DOUT_EN 0x20 -#define TWL4030_VIF_SWAP 0x10 -#define TWL4030_VIF_FORMAT 0x08 -#define TWL4030_VIF_TRI_EN 0x04 -#define TWL4030_VIF_SUB_EN 0x02 -#define TWL4030_VIF_EN 0x01 - /* EAR_CTL (0x21) */ #define TWL4030_EAR_GAIN 0x30 @@ -261,19 +236,7 @@ #define TWL4030_SMOOTH_ANAVOL_EN 0x02 #define TWL4030_DIGMIC_LR_SWAP_EN 0x01 -/* TWL4030_REG_SW_SHADOW (0x4A) Fields */ -#define TWL4030_HFL_EN 0x01 -#define TWL4030_HFR_EN 0x02 - -#define TWL4030_DAI_HIFI 0 -#define TWL4030_DAI_VOICE 1 - -extern struct snd_soc_dai twl4030_dai[2]; +extern struct snd_soc_dai twl4030_dai; extern struct snd_soc_codec_device soc_codec_dev_twl4030; -struct twl4030_setup_data { - unsigned int ramp_delay_value; - unsigned int sysclk; -}; - #endif /* End of __TWL4030_AUDIO_H__ */ diff --git a/trunk/sound/soc/codecs/uda134x.c b/trunk/sound/soc/codecs/uda134x.c index 269b108e1de6..ddefb8f80145 100644 --- a/trunk/sound/soc/codecs/uda134x.c +++ b/trunk/sound/soc/codecs/uda134x.c @@ -101,7 +101,7 @@ static int uda134x_write(struct snd_soc_codec *codec, unsigned int reg, pr_debug("%s reg: %02X, value:%02X\n", __func__, reg, value); if (reg >= UDA134X_REGS_NUM) { - printk(KERN_ERR "%s unkown register: reg: %u", + printk(KERN_ERR "%s unkown register: reg: %d", __func__, reg); return -EINVAL; } @@ -296,7 +296,7 @@ static int uda134x_set_dai_sysclk(struct snd_soc_dai *codec_dai, struct snd_soc_codec *codec = codec_dai->codec; struct uda134x_priv *uda134x = codec->private_data; - pr_debug("%s clk_id: %d, freq: %u, dir: %d\n", __func__, + pr_debug("%s clk_id: %d, freq: %d, dir: %d\n", __func__, clk_id, freq, dir); /* Anything between 256fs*8Khz and 512fs*48Khz should be acceptable diff --git a/trunk/sound/soc/codecs/wm8350.c b/trunk/sound/soc/codecs/wm8350.c index e7348d341b76..0275321ff8ab 100644 --- a/trunk/sound/soc/codecs/wm8350.c +++ b/trunk/sound/soc/codecs/wm8350.c @@ -1108,7 +1108,7 @@ static int wm8350_set_fll(struct snd_soc_dai *codec_dai, if (ret < 0) return ret; dev_dbg(wm8350->dev, - "FLL in %u FLL out %u N 0x%x K 0x%x div %d ratio %d", + "FLL in %d FLL out %d N 0x%x K 0x%x div %d ratio %d", freq_in, freq_out, fll_div.n, fll_div.k, fll_div.div, fll_div.ratio); diff --git a/trunk/sound/soc/codecs/wm8350.h b/trunk/sound/soc/codecs/wm8350.h index d088eb4b88bb..d11bd9288cf9 100644 --- a/trunk/sound/soc/codecs/wm8350.h +++ b/trunk/sound/soc/codecs/wm8350.h @@ -13,7 +13,6 @@ #define _WM8350_H #include -#include extern struct snd_soc_dai wm8350_dai; extern struct snd_soc_codec_device soc_codec_dev_wm8350; diff --git a/trunk/sound/soc/codecs/wm8400.c b/trunk/sound/soc/codecs/wm8400.c index 502eefac1ecd..510efa604008 100644 --- a/trunk/sound/soc/codecs/wm8400.c +++ b/trunk/sound/soc/codecs/wm8400.c @@ -954,7 +954,7 @@ static int fll_factors(struct wm8400_priv *wm8400, struct fll_factors *factors, factors->outdiv *= 2; if (factors->outdiv > 32) { dev_err(wm8400->wm8400->dev, - "Unsupported FLL output frequency %uHz\n", + "Unsupported FLL output frequency %dHz\n", Fout); return -EINVAL; } @@ -1003,7 +1003,7 @@ static int fll_factors(struct wm8400_priv *wm8400, struct fll_factors *factors, factors->k = K / 10; dev_dbg(wm8400->wm8400->dev, - "FLL: Fref=%u Fout=%u N=%x K=%x, FRATIO=%x OUTDIV=%x\n", + "FLL: Fref=%d Fout=%d N=%x K=%x, FRATIO=%x OUTDIV=%x\n", Fref, Fout, factors->n, factors->k, factors->fratio, factors->outdiv); @@ -1473,8 +1473,8 @@ static int wm8400_codec_probe(struct platform_device *dev) codec = &priv->codec; codec->private_data = priv; - codec->control_data = dev_get_drvdata(&dev->dev); - priv->wm8400 = dev_get_drvdata(&dev->dev); + codec->control_data = dev->dev.driver_data; + priv->wm8400 = dev->dev.driver_data; ret = regulator_bulk_get(priv->wm8400->dev, ARRAY_SIZE(power), &power[0]); diff --git a/trunk/sound/soc/codecs/wm8510.c b/trunk/sound/soc/codecs/wm8510.c index c8b8dba85890..6a4cea09c45d 100644 --- a/trunk/sound/soc/codecs/wm8510.c +++ b/trunk/sound/soc/codecs/wm8510.c @@ -298,7 +298,7 @@ static void pll_factors(unsigned int target, unsigned int source) if ((Ndiv < 6) || (Ndiv > 12)) printk(KERN_WARNING - "WM8510 N value %u outwith recommended range!d\n", + "WM8510 N value %d outwith recommended range!d\n", Ndiv); pll_div.n = Ndiv; diff --git a/trunk/sound/soc/codecs/wm8580.c b/trunk/sound/soc/codecs/wm8580.c index 86c4b24db817..9f6be3d31ac0 100644 --- a/trunk/sound/soc/codecs/wm8580.c +++ b/trunk/sound/soc/codecs/wm8580.c @@ -415,7 +415,7 @@ static int pll_factors(struct _pll_div *pll_div, unsigned int target, unsigned int K, Ndiv, Nmod; int i; - pr_debug("wm8580: PLL %uHz->%uHz\n", source, target); + pr_debug("wm8580: PLL %dHz->%dHz\n", source, target); /* Scale the output frequency up; the PLL should run in the * region of 90-100MHz. @@ -447,7 +447,7 @@ static int pll_factors(struct _pll_div *pll_div, unsigned int target, if ((Ndiv < 5) || (Ndiv > 13)) { printk(KERN_ERR - "WM8580 N=%u outside supported range\n", Ndiv); + "WM8580 N=%d outside supported range\n", Ndiv); return -EINVAL; } diff --git a/trunk/sound/soc/codecs/wm8731.c b/trunk/sound/soc/codecs/wm8731.c index 7a205876ef4f..e043e3f60008 100644 --- a/trunk/sound/soc/codecs/wm8731.c +++ b/trunk/sound/soc/codecs/wm8731.c @@ -666,14 +666,14 @@ static int __devinit wm8731_spi_probe(struct spi_device *spi) codec->hw_write = (hw_write_t)wm8731_spi_write; codec->dev = &spi->dev; - dev_set_drvdata(&spi->dev, wm8731); + spi->dev.driver_data = wm8731; return wm8731_register(wm8731); } static int __devexit wm8731_spi_remove(struct spi_device *spi) { - struct wm8731_priv *wm8731 = dev_get_drvdata(&spi->dev); + struct wm8731_priv *wm8731 = spi->dev.driver_data; wm8731_unregister(wm8731); diff --git a/trunk/sound/soc/codecs/wm8753.c b/trunk/sound/soc/codecs/wm8753.c index d28eeaceb857..a6e8f3f7f052 100644 --- a/trunk/sound/soc/codecs/wm8753.c +++ b/trunk/sound/soc/codecs/wm8753.c @@ -703,7 +703,7 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int target, if ((Ndiv < 6) || (Ndiv > 12)) printk(KERN_WARNING - "wm8753: unsupported N = %u\n", Ndiv); + "wm8753: unsupported N = %d\n", Ndiv); pll_div->n = Ndiv; Nmod = target % source; @@ -1822,14 +1822,14 @@ static int __devinit wm8753_spi_probe(struct spi_device *spi) codec->hw_write = (hw_write_t)wm8753_spi_write; codec->dev = &spi->dev; - dev_set_drvdata(&spi->dev, wm8753); + spi->dev.driver_data = wm8753; return wm8753_register(wm8753); } static int __devexit wm8753_spi_remove(struct spi_device *spi) { - struct wm8753_priv *wm8753 = dev_get_drvdata(&spi->dev); + struct wm8753_priv *wm8753 = spi->dev.driver_data; wm8753_unregister(wm8753); return 0; } diff --git a/trunk/sound/soc/codecs/wm8900.c b/trunk/sound/soc/codecs/wm8900.c index 3c78945244b8..46c5ea1ff921 100644 --- a/trunk/sound/soc/codecs/wm8900.c +++ b/trunk/sound/soc/codecs/wm8900.c @@ -778,11 +778,11 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref, } if (target > 100000000) - printk(KERN_WARNING "wm8900: FLL rate %u out of range, Fref=%u" - " Fout=%u\n", target, Fref, Fout); + printk(KERN_WARNING "wm8900: FLL rate %d out of range, Fref=%d" + " Fout=%d\n", target, Fref, Fout); if (div > 32) { printk(KERN_ERR "wm8900: Invalid FLL division rate %u, " - "Fref=%u, Fout=%u, target=%u\n", + "Fref=%d, Fout=%d, target=%d\n", div, Fref, Fout, target); return -EINVAL; } diff --git a/trunk/sound/soc/codecs/wm8903.c b/trunk/sound/soc/codecs/wm8903.c index e8d2e3e14c45..8cf571f1a803 100644 --- a/trunk/sound/soc/codecs/wm8903.c +++ b/trunk/sound/soc/codecs/wm8903.c @@ -217,6 +217,7 @@ struct wm8903_priv { int sysclk; /* Reference counts */ + int charge_pump_users; int class_w_users; int playback_active; int capture_active; @@ -372,15 +373,6 @@ static void wm8903_reset(struct snd_soc_codec *codec) #define WM8903_OUTPUT_INT 0x2 #define WM8903_OUTPUT_IN 0x1 -static int wm8903_cp_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - WARN_ON(event != SND_SOC_DAPM_POST_PMU); - mdelay(4); - - return 0; -} - /* * Event for headphone and line out amplifier power changes. Special * power up/down sequences are required in order to maximise pop/click @@ -390,20 +382,19 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; + struct wm8903_priv *wm8903 = codec->private_data; + struct i2c_client *i2c = codec->control_data; u16 val; u16 reg; - u16 dcs_reg; - u16 dcs_bit; int shift; + u16 cp_reg = wm8903_read(codec, WM8903_CHARGE_PUMP_0); switch (w->reg) { case WM8903_POWER_MANAGEMENT_2: reg = WM8903_ANALOGUE_HP_0; - dcs_bit = 0 + w->shift; break; case WM8903_POWER_MANAGEMENT_3: reg = WM8903_ANALOGUE_LINEOUT_0; - dcs_bit = 2 + w->shift; break; default: BUG(); @@ -428,6 +419,18 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w, /* Short the output */ val &= ~(WM8903_OUTPUT_SHORT << shift); wm8903_write(codec, reg, val); + + wm8903->charge_pump_users++; + + dev_dbg(&i2c->dev, "Charge pump use count now %d\n", + wm8903->charge_pump_users); + + if (wm8903->charge_pump_users == 1) { + dev_dbg(&i2c->dev, "Enabling charge pump\n"); + wm8903_write(codec, WM8903_CHARGE_PUMP_0, + cp_reg | WM8903_CP_ENA); + mdelay(4); + } } if (event & SND_SOC_DAPM_POST_PMU) { @@ -443,11 +446,6 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w, val |= (WM8903_OUTPUT_OUT << shift); wm8903_write(codec, reg, val); - /* Enable the DC servo */ - dcs_reg = wm8903_read(codec, WM8903_DC_SERVO_0); - dcs_reg |= dcs_bit; - wm8903_write(codec, WM8903_DC_SERVO_0, dcs_reg); - /* Remove the short */ val |= (WM8903_OUTPUT_SHORT << shift); wm8903_write(codec, reg, val); @@ -460,17 +458,25 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w, val &= ~(WM8903_OUTPUT_SHORT << shift); wm8903_write(codec, reg, val); - /* Disable the DC servo */ - dcs_reg = wm8903_read(codec, WM8903_DC_SERVO_0); - dcs_reg &= ~dcs_bit; - wm8903_write(codec, WM8903_DC_SERVO_0, dcs_reg); - /* Then disable the intermediate and output stages */ val &= ~((WM8903_OUTPUT_OUT | WM8903_OUTPUT_INT | WM8903_OUTPUT_IN) << shift); wm8903_write(codec, reg, val); } + if (event & SND_SOC_DAPM_POST_PMD) { + wm8903->charge_pump_users--; + + dev_dbg(&i2c->dev, "Charge pump use count now %d\n", + wm8903->charge_pump_users); + + if (wm8903->charge_pump_users == 0) { + dev_dbg(&i2c->dev, "Disabling charge pump\n"); + wm8903_write(codec, WM8903_CHARGE_PUMP_0, + cp_reg & ~WM8903_CP_ENA); + } + } + return 0; } @@ -533,7 +539,6 @@ static int wm8903_class_w_put(struct snd_kcontrol *kcontrol, /* ALSA can only do steps of .01dB */ static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1); -static const DECLARE_TLV_DB_SCALE(digital_sidetone_tlv, -3600, 300, 0); static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0); static const DECLARE_TLV_DB_SCALE(drc_tlv_thresh, 0, 75, 0); @@ -652,16 +657,6 @@ static const struct soc_enum rinput_inv_enum = SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 4, 3, rinput_mux_text); -static const char *sidetone_text[] = { - "None", "Left", "Right" -}; - -static const struct soc_enum lsidetone_enum = - SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 2, 3, sidetone_text); - -static const struct soc_enum rsidetone_enum = - SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 0, 3, sidetone_text); - static const struct snd_kcontrol_new wm8903_snd_controls[] = { /* Input PGAs - No TLV since the scale depends on PGA mode */ @@ -705,9 +700,6 @@ SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8903_ADC_DIGITAL_VOLUME_LEFT, SOC_ENUM("ADC Companding Mode", adc_companding), SOC_SINGLE("ADC Companding Switch", WM8903_AUDIO_INTERFACE_0, 3, 1, 0), -SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8903_DAC_DIGITAL_0, 4, 8, - 12, 0, digital_sidetone_tlv), - /* DAC */ SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8903_DAC_DIGITAL_VOLUME_LEFT, WM8903_DAC_DIGITAL_VOLUME_RIGHT, 1, 120, 0, digital_tlv), @@ -770,12 +762,6 @@ static const struct snd_kcontrol_new rinput_mux = static const struct snd_kcontrol_new rinput_inv_mux = SOC_DAPM_ENUM("Right Inverting Input Mux", rinput_inv_enum); -static const struct snd_kcontrol_new lsidetone_mux = - SOC_DAPM_ENUM("DACL Sidetone Mux", lsidetone_enum); - -static const struct snd_kcontrol_new rsidetone_mux = - SOC_DAPM_ENUM("DACR Sidetone Mux", rsidetone_enum); - static const struct snd_kcontrol_new left_output_mixer[] = { SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_LEFT_MIX_0, 3, 1, 0), SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_LEFT_MIX_0, 2, 1, 0), @@ -842,9 +828,6 @@ SND_SOC_DAPM_PGA("Right Input PGA", WM8903_POWER_MANAGEMENT_0, 0, 0, NULL, 0), SND_SOC_DAPM_ADC("ADCL", "Left HiFi Capture", WM8903_POWER_MANAGEMENT_6, 1, 0), SND_SOC_DAPM_ADC("ADCR", "Right HiFi Capture", WM8903_POWER_MANAGEMENT_6, 0, 0), -SND_SOC_DAPM_MUX("DACL Sidetone", SND_SOC_NOPM, 0, 0, &lsidetone_mux), -SND_SOC_DAPM_MUX("DACR Sidetone", SND_SOC_NOPM, 0, 0, &rsidetone_mux), - SND_SOC_DAPM_DAC("DACL", "Left Playback", WM8903_POWER_MANAGEMENT_6, 3, 0), SND_SOC_DAPM_DAC("DACR", "Right Playback", WM8903_POWER_MANAGEMENT_6, 2, 0), @@ -861,29 +844,26 @@ SND_SOC_DAPM_MIXER("Right Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 0, 0, SND_SOC_DAPM_PGA_E("Left Headphone Output PGA", WM8903_POWER_MANAGEMENT_2, 1, 0, NULL, 0, wm8903_output_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_PGA_E("Right Headphone Output PGA", WM8903_POWER_MANAGEMENT_2, 0, 0, NULL, 0, wm8903_output_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_PGA_E("Left Line Output PGA", WM8903_POWER_MANAGEMENT_3, 1, 0, NULL, 0, wm8903_output_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_PGA_E("Right Line Output PGA", WM8903_POWER_MANAGEMENT_3, 0, 0, NULL, 0, wm8903_output_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_PGA("Left Speaker PGA", WM8903_POWER_MANAGEMENT_5, 1, 0, NULL, 0), SND_SOC_DAPM_PGA("Right Speaker PGA", WM8903_POWER_MANAGEMENT_5, 0, 0, NULL, 0), -SND_SOC_DAPM_SUPPLY("Charge Pump", WM8903_CHARGE_PUMP_0, 0, 0, - wm8903_cp_event, SND_SOC_DAPM_POST_PMU), -SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8903_CLOCK_RATES_2, 1, 0, NULL, 0), }; static const struct snd_soc_dapm_route intercon[] = { @@ -929,19 +909,7 @@ static const struct snd_soc_dapm_route intercon[] = { { "Right Input PGA", NULL, "Right Input Mode Mux" }, { "ADCL", NULL, "Left Input PGA" }, - { "ADCL", NULL, "CLK_DSP" }, { "ADCR", NULL, "Right Input PGA" }, - { "ADCR", NULL, "CLK_DSP" }, - - { "DACL Sidetone", "Left", "ADCL" }, - { "DACL Sidetone", "Right", "ADCR" }, - { "DACR Sidetone", "Left", "ADCL" }, - { "DACR Sidetone", "Right", "ADCR" }, - - { "DACL", NULL, "DACL Sidetone" }, - { "DACL", NULL, "CLK_DSP" }, - { "DACR", NULL, "DACR Sidetone" }, - { "DACR", NULL, "CLK_DSP" }, { "Left Output Mixer", "Left Bypass Switch", "Left Input PGA" }, { "Left Output Mixer", "Right Bypass Switch", "Right Input PGA" }, @@ -983,11 +951,6 @@ static const struct snd_soc_dapm_route intercon[] = { { "ROP", NULL, "Right Speaker PGA" }, { "RON", NULL, "Right Speaker PGA" }, - - { "Left Headphone Output PGA", NULL, "Charge Pump" }, - { "Right Headphone Output PGA", NULL, "Charge Pump" }, - { "Left Line Output PGA", NULL, "Charge Pump" }, - { "Right Line Output PGA", NULL, "Charge Pump" }, }; static int wm8903_add_widgets(struct snd_soc_codec *codec) @@ -1022,11 +985,6 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec, wm8903_write(codec, WM8903_CLOCK_RATES_2, WM8903_CLK_SYS_ENA); - /* Change DC servo dither level in startup sequence */ - wm8903_write(codec, WM8903_WRITE_SEQUENCER_0, 0x11); - wm8903_write(codec, WM8903_WRITE_SEQUENCER_1, 0x1257); - wm8903_write(codec, WM8903_WRITE_SEQUENCER_2, 0x2); - wm8903_run_sequence(codec, 0); wm8903_sync_reg_cache(codec, codec->reg_cache); @@ -1257,18 +1215,22 @@ static struct { int div; } bclk_divs[] = { { 10, 0 }, + { 15, 1 }, { 20, 2 }, { 30, 3 }, { 40, 4 }, { 50, 5 }, + { 55, 6 }, { 60, 7 }, { 80, 8 }, { 100, 9 }, + { 110, 10 }, { 120, 11 }, { 160, 12 }, { 200, 13 }, { 220, 14 }, { 240, 15 }, + { 250, 16 }, { 300, 17 }, { 320, 18 }, { 440, 19 }, @@ -1315,8 +1277,14 @@ static int wm8903_startup(struct snd_pcm_substream *substream, if (wm8903->master_substream) { master_runtime = wm8903->master_substream->runtime; - dev_dbg(&i2c->dev, "Constraining to %d bits\n", - master_runtime->sample_bits); + dev_dbg(&i2c->dev, "Constraining to %d bits at %dHz\n", + master_runtime->sample_bits, + master_runtime->rate); + + snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_RATE, + master_runtime->rate, + master_runtime->rate); snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, @@ -1555,7 +1523,6 @@ struct snd_soc_dai wm8903_dai = { .formats = WM8903_FORMATS, }, .ops = &wm8903_dai_ops, - .symmetric_rates = 1, }; EXPORT_SYMBOL_GPL(wm8903_dai); diff --git a/trunk/sound/soc/codecs/wm8940.c b/trunk/sound/soc/codecs/wm8940.c deleted file mode 100644 index b8e17d6bc1f7..000000000000 --- a/trunk/sound/soc/codecs/wm8940.c +++ /dev/null @@ -1,955 +0,0 @@ -/* - * wm8940.c -- WM8940 ALSA Soc Audio driver - * - * Author: Jonathan Cameron - * - * Based on wm8510.c - * Copyright 2006 Wolfson Microelectronics PLC. - * Author: Liam Girdwood - * - * 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. - * - * Not currently handled: - * Notch filter control - * AUXMode (inverting vs mixer) - * No means to obtain current gain if alc enabled. - * No use made of gpio - * Fast VMID discharge for power down - * Soft Start - * DLR and ALR Swaps not enabled - * Digital Sidetone not supported - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "wm8940.h" - -struct wm8940_priv { - unsigned int sysclk; - u16 reg_cache[WM8940_CACHEREGNUM]; - struct snd_soc_codec codec; -}; - -static u16 wm8940_reg_defaults[] = { - 0x8940, /* Soft Reset */ - 0x0000, /* Power 1 */ - 0x0000, /* Power 2 */ - 0x0000, /* Power 3 */ - 0x0010, /* Interface Control */ - 0x0000, /* Companding Control */ - 0x0140, /* Clock Control */ - 0x0000, /* Additional Controls */ - 0x0000, /* GPIO Control */ - 0x0002, /* Auto Increment Control */ - 0x0000, /* DAC Control */ - 0x00FF, /* DAC Volume */ - 0, - 0, - 0x0100, /* ADC Control */ - 0x00FF, /* ADC Volume */ - 0x0000, /* Notch Filter 1 Control 1 */ - 0x0000, /* Notch Filter 1 Control 2 */ - 0x0000, /* Notch Filter 2 Control 1 */ - 0x0000, /* Notch Filter 2 Control 2 */ - 0x0000, /* Notch Filter 3 Control 1 */ - 0x0000, /* Notch Filter 3 Control 2 */ - 0x0000, /* Notch Filter 4 Control 1 */ - 0x0000, /* Notch Filter 4 Control 2 */ - 0x0032, /* DAC Limit Control 1 */ - 0x0000, /* DAC Limit Control 2 */ - 0, - 0, - 0, - 0, - 0, - 0, - 0x0038, /* ALC Control 1 */ - 0x000B, /* ALC Control 2 */ - 0x0032, /* ALC Control 3 */ - 0x0000, /* Noise Gate */ - 0x0041, /* PLLN */ - 0x000C, /* PLLK1 */ - 0x0093, /* PLLK2 */ - 0x00E9, /* PLLK3 */ - 0, - 0, - 0x0030, /* ALC Control 4 */ - 0, - 0x0002, /* Input Control */ - 0x0050, /* PGA Gain */ - 0, - 0x0002, /* ADC Boost Control */ - 0, - 0x0002, /* Output Control */ - 0x0000, /* Speaker Mixer Control */ - 0, - 0, - 0, - 0x0079, /* Speaker Volume */ - 0, - 0x0000, /* Mono Mixer Control */ -}; - -static inline unsigned int wm8940_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - - if (reg >= ARRAY_SIZE(wm8940_reg_defaults)) - return -1; - - return cache[reg]; -} - -static inline int wm8940_write_reg_cache(struct snd_soc_codec *codec, - u16 reg, unsigned int value) -{ - u16 *cache = codec->reg_cache; - - if (reg >= ARRAY_SIZE(wm8940_reg_defaults)) - return -1; - - cache[reg] = value; - - return 0; -} - -static int wm8940_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - int ret; - u8 data[3] = { reg, - (value & 0xff00) >> 8, - (value & 0x00ff) - }; - - wm8940_write_reg_cache(codec, reg, value); - - ret = codec->hw_write(codec->control_data, data, 3); - - if (ret < 0) - return ret; - else if (ret != 3) - return -EIO; - return 0; -} - -static const char *wm8940_companding[] = { "Off", "NC", "u-law", "A-law" }; -static const struct soc_enum wm8940_adc_companding_enum -= SOC_ENUM_SINGLE(WM8940_COMPANDINGCTL, 1, 4, wm8940_companding); -static const struct soc_enum wm8940_dac_companding_enum -= SOC_ENUM_SINGLE(WM8940_COMPANDINGCTL, 3, 4, wm8940_companding); - -static const char *wm8940_alc_mode_text[] = {"ALC", "Limiter"}; -static const struct soc_enum wm8940_alc_mode_enum -= SOC_ENUM_SINGLE(WM8940_ALC3, 8, 2, wm8940_alc_mode_text); - -static const char *wm8940_mic_bias_level_text[] = {"0.9", "0.65"}; -static const struct soc_enum wm8940_mic_bias_level_enum -= SOC_ENUM_SINGLE(WM8940_INPUTCTL, 8, 2, wm8940_mic_bias_level_text); - -static const char *wm8940_filter_mode_text[] = {"Audio", "Application"}; -static const struct soc_enum wm8940_filter_mode_enum -= SOC_ENUM_SINGLE(WM8940_ADC, 7, 2, wm8940_filter_mode_text); - -static DECLARE_TLV_DB_SCALE(wm8940_spk_vol_tlv, -5700, 100, 1); -static DECLARE_TLV_DB_SCALE(wm8940_att_tlv, -1000, 1000, 0); -static DECLARE_TLV_DB_SCALE(wm8940_pga_vol_tlv, -1200, 75, 0); -static DECLARE_TLV_DB_SCALE(wm8940_alc_min_tlv, -1200, 600, 0); -static DECLARE_TLV_DB_SCALE(wm8940_alc_max_tlv, 675, 600, 0); -static DECLARE_TLV_DB_SCALE(wm8940_alc_tar_tlv, -2250, 50, 0); -static DECLARE_TLV_DB_SCALE(wm8940_lim_boost_tlv, 0, 100, 0); -static DECLARE_TLV_DB_SCALE(wm8940_lim_thresh_tlv, -600, 100, 0); -static DECLARE_TLV_DB_SCALE(wm8940_adc_tlv, -12750, 50, 1); -static DECLARE_TLV_DB_SCALE(wm8940_capture_boost_vol_tlv, 0, 2000, 0); - -static const struct snd_kcontrol_new wm8940_snd_controls[] = { - SOC_SINGLE("Digital Loopback Switch", WM8940_COMPANDINGCTL, - 6, 1, 0), - SOC_ENUM("DAC Companding", wm8940_dac_companding_enum), - SOC_ENUM("ADC Companding", wm8940_adc_companding_enum), - - SOC_ENUM("ALC Mode", wm8940_alc_mode_enum), - SOC_SINGLE("ALC Switch", WM8940_ALC1, 8, 1, 0), - SOC_SINGLE_TLV("ALC Capture Max Gain", WM8940_ALC1, - 3, 7, 1, wm8940_alc_max_tlv), - SOC_SINGLE_TLV("ALC Capture Min Gain", WM8940_ALC1, - 0, 7, 0, wm8940_alc_min_tlv), - SOC_SINGLE_TLV("ALC Capture Target", WM8940_ALC2, - 0, 14, 0, wm8940_alc_tar_tlv), - SOC_SINGLE("ALC Capture Hold", WM8940_ALC2, 4, 10, 0), - SOC_SINGLE("ALC Capture Decay", WM8940_ALC3, 4, 10, 0), - SOC_SINGLE("ALC Capture Attach", WM8940_ALC3, 0, 10, 0), - SOC_SINGLE("ALC ZC Switch", WM8940_ALC4, 1, 1, 0), - SOC_SINGLE("ALC Capture Noise Gate Switch", WM8940_NOISEGATE, - 3, 1, 0), - SOC_SINGLE("ALC Capture Noise Gate Threshold", WM8940_NOISEGATE, - 0, 7, 0), - - SOC_SINGLE("DAC Playback Limiter Switch", WM8940_DACLIM1, 8, 1, 0), - SOC_SINGLE("DAC Playback Limiter Attack", WM8940_DACLIM1, 0, 9, 0), - SOC_SINGLE("DAC Playback Limiter Decay", WM8940_DACLIM1, 4, 11, 0), - SOC_SINGLE_TLV("DAC Playback Limiter Threshold", WM8940_DACLIM2, - 4, 9, 1, wm8940_lim_thresh_tlv), - SOC_SINGLE_TLV("DAC Playback Limiter Boost", WM8940_DACLIM2, - 0, 12, 0, wm8940_lim_boost_tlv), - - SOC_SINGLE("Capture PGA ZC Switch", WM8940_PGAGAIN, 7, 1, 0), - SOC_SINGLE_TLV("Capture PGA Volume", WM8940_PGAGAIN, - 0, 63, 0, wm8940_pga_vol_tlv), - SOC_SINGLE_TLV("Digital Playback Volume", WM8940_DACVOL, - 0, 255, 0, wm8940_adc_tlv), - SOC_SINGLE_TLV("Digital Capture Volume", WM8940_ADCVOL, - 0, 255, 0, wm8940_adc_tlv), - SOC_ENUM("Mic Bias Level", wm8940_mic_bias_level_enum), - SOC_SINGLE_TLV("Capture Boost Volue", WM8940_ADCBOOST, - 8, 1, 0, wm8940_capture_boost_vol_tlv), - SOC_SINGLE_TLV("Speaker Playback Volume", WM8940_SPKVOL, - 0, 63, 0, wm8940_spk_vol_tlv), - SOC_SINGLE("Speaker Playback Switch", WM8940_SPKVOL, 6, 1, 1), - - SOC_SINGLE_TLV("Speaker Mixer Line Bypass Volume", WM8940_SPKVOL, - 8, 1, 1, wm8940_att_tlv), - SOC_SINGLE("Speaker Playback ZC Switch", WM8940_SPKVOL, 7, 1, 0), - - SOC_SINGLE("Mono Out Switch", WM8940_MONOMIX, 6, 1, 1), - SOC_SINGLE_TLV("Mono Mixer Line Bypass Volume", WM8940_MONOMIX, - 7, 1, 1, wm8940_att_tlv), - - SOC_SINGLE("High Pass Filter Switch", WM8940_ADC, 8, 1, 0), - SOC_ENUM("High Pass Filter Mode", wm8940_filter_mode_enum), - SOC_SINGLE("High Pass Filter Cut Off", WM8940_ADC, 4, 7, 0), - SOC_SINGLE("ADC Inversion Switch", WM8940_ADC, 0, 1, 0), - SOC_SINGLE("DAC Inversion Switch", WM8940_DAC, 0, 1, 0), - SOC_SINGLE("DAC Auto Mute Switch", WM8940_DAC, 2, 1, 0), - SOC_SINGLE("ZC Timeout Clock Switch", WM8940_ADDCNTRL, 0, 1, 0), -}; - -static const struct snd_kcontrol_new wm8940_speaker_mixer_controls[] = { - SOC_DAPM_SINGLE("Line Bypass Switch", WM8940_SPKMIX, 1, 1, 0), - SOC_DAPM_SINGLE("Aux Playback Switch", WM8940_SPKMIX, 5, 1, 0), - SOC_DAPM_SINGLE("PCM Playback Switch", WM8940_SPKMIX, 0, 1, 0), -}; - -static const struct snd_kcontrol_new wm8940_mono_mixer_controls[] = { - SOC_DAPM_SINGLE("Line Bypass Switch", WM8940_MONOMIX, 1, 1, 0), - SOC_DAPM_SINGLE("Aux Playback Switch", WM8940_MONOMIX, 2, 1, 0), - SOC_DAPM_SINGLE("PCM Playback Switch", WM8940_MONOMIX, 0, 1, 0), -}; - -static DECLARE_TLV_DB_SCALE(wm8940_boost_vol_tlv, -1500, 300, 1); -static const struct snd_kcontrol_new wm8940_input_boost_controls[] = { - SOC_DAPM_SINGLE("Mic PGA Switch", WM8940_PGAGAIN, 6, 1, 1), - SOC_DAPM_SINGLE_TLV("Aux Volume", WM8940_ADCBOOST, - 0, 7, 0, wm8940_boost_vol_tlv), - SOC_DAPM_SINGLE_TLV("Mic Volume", WM8940_ADCBOOST, - 4, 7, 0, wm8940_boost_vol_tlv), -}; - -static const struct snd_kcontrol_new wm8940_micpga_controls[] = { - SOC_DAPM_SINGLE("AUX Switch", WM8940_INPUTCTL, 2, 1, 0), - SOC_DAPM_SINGLE("MICP Switch", WM8940_INPUTCTL, 0, 1, 0), - SOC_DAPM_SINGLE("MICN Switch", WM8940_INPUTCTL, 1, 1, 0), -}; - -static const struct snd_soc_dapm_widget wm8940_dapm_widgets[] = { - SND_SOC_DAPM_MIXER("Speaker Mixer", WM8940_POWER3, 2, 0, - &wm8940_speaker_mixer_controls[0], - ARRAY_SIZE(wm8940_speaker_mixer_controls)), - SND_SOC_DAPM_MIXER("Mono Mixer", WM8940_POWER3, 3, 0, - &wm8940_mono_mixer_controls[0], - ARRAY_SIZE(wm8940_mono_mixer_controls)), - SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8940_POWER3, 0, 0), - - SND_SOC_DAPM_PGA("SpkN Out", WM8940_POWER3, 5, 0, NULL, 0), - SND_SOC_DAPM_PGA("SpkP Out", WM8940_POWER3, 6, 0, NULL, 0), - SND_SOC_DAPM_PGA("Mono Out", WM8940_POWER3, 7, 0, NULL, 0), - SND_SOC_DAPM_OUTPUT("MONOOUT"), - SND_SOC_DAPM_OUTPUT("SPKOUTP"), - SND_SOC_DAPM_OUTPUT("SPKOUTN"), - - SND_SOC_DAPM_PGA("Aux Input", WM8940_POWER1, 6, 0, NULL, 0), - SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8940_POWER2, 0, 0), - SND_SOC_DAPM_MIXER("Mic PGA", WM8940_POWER2, 2, 0, - &wm8940_micpga_controls[0], - ARRAY_SIZE(wm8940_micpga_controls)), - SND_SOC_DAPM_MIXER("Boost Mixer", WM8940_POWER2, 4, 0, - &wm8940_input_boost_controls[0], - ARRAY_SIZE(wm8940_input_boost_controls)), - SND_SOC_DAPM_MICBIAS("Mic Bias", WM8940_POWER1, 4, 0), - - SND_SOC_DAPM_INPUT("MICN"), - SND_SOC_DAPM_INPUT("MICP"), - SND_SOC_DAPM_INPUT("AUX"), -}; - -static const struct snd_soc_dapm_route audio_map[] = { - /* Mono output mixer */ - {"Mono Mixer", "PCM Playback Switch", "DAC"}, - {"Mono Mixer", "Aux Playback Switch", "Aux Input"}, - {"Mono Mixer", "Line Bypass Switch", "Boost Mixer"}, - - /* Speaker output mixer */ - {"Speaker Mixer", "PCM Playback Switch", "DAC"}, - {"Speaker Mixer", "Aux Playback Switch", "Aux Input"}, - {"Speaker Mixer", "Line Bypass Switch", "Boost Mixer"}, - - /* Outputs */ - {"Mono Out", NULL, "Mono Mixer"}, - {"MONOOUT", NULL, "Mono Out"}, - {"SpkN Out", NULL, "Speaker Mixer"}, - {"SpkP Out", NULL, "Speaker Mixer"}, - {"SPKOUTN", NULL, "SpkN Out"}, - {"SPKOUTP", NULL, "SpkP Out"}, - - /* Microphone PGA */ - {"Mic PGA", "MICN Switch", "MICN"}, - {"Mic PGA", "MICP Switch", "MICP"}, - {"Mic PGA", "AUX Switch", "AUX"}, - - /* Boost Mixer */ - {"Boost Mixer", "Mic PGA Switch", "Mic PGA"}, - {"Boost Mixer", "Mic Volume", "MICP"}, - {"Boost Mixer", "Aux Volume", "Aux Input"}, - - {"ADC", NULL, "Boost Mixer"}, -}; - -static int wm8940_add_widgets(struct snd_soc_codec *codec) -{ - int ret; - - ret = snd_soc_dapm_new_controls(codec, wm8940_dapm_widgets, - ARRAY_SIZE(wm8940_dapm_widgets)); - if (ret) - goto error_ret; - ret = snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - if (ret) - goto error_ret; - ret = snd_soc_dapm_new_widgets(codec); - -error_ret: - return ret; -} - -#define wm8940_reset(c) wm8940_write(c, WM8940_SOFTRESET, 0); - -static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) -{ - struct snd_soc_codec *codec = codec_dai->codec; - u16 iface = wm8940_read_reg_cache(codec, WM8940_IFACE) & 0xFE67; - u16 clk = wm8940_read_reg_cache(codec, WM8940_CLOCK) & 0x1fe; - - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - clk |= 1; - break; - case SND_SOC_DAIFMT_CBS_CFS: - break; - default: - return -EINVAL; - } - wm8940_write(codec, WM8940_CLOCK, clk); - - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - iface |= (2 << 3); - break; - case SND_SOC_DAIFMT_LEFT_J: - iface |= (1 << 3); - break; - case SND_SOC_DAIFMT_RIGHT_J: - break; - case SND_SOC_DAIFMT_DSP_A: - iface |= (3 << 3); - break; - case SND_SOC_DAIFMT_DSP_B: - iface |= (3 << 3) | (1 << 7); - break; - } - - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - break; - case SND_SOC_DAIFMT_NB_IF: - iface |= (1 << 7); - break; - case SND_SOC_DAIFMT_IB_NF: - iface |= (1 << 8); - break; - case SND_SOC_DAIFMT_IB_IF: - iface |= (1 << 8) | (1 << 7); - break; - } - - wm8940_write(codec, WM8940_IFACE, iface); - - return 0; -} - -static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->card->codec; - u16 iface = wm8940_read_reg_cache(codec, WM8940_IFACE) & 0xFD9F; - u16 addcntrl = wm8940_read_reg_cache(codec, WM8940_ADDCNTRL) & 0xFFF1; - u16 companding = wm8940_read_reg_cache(codec, - WM8940_COMPANDINGCTL) & 0xFFDF; - int ret; - - /* LoutR control */ - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE - && params_channels(params) == 2) - iface |= (1 << 9); - - switch (params_rate(params)) { - case SNDRV_PCM_RATE_8000: - addcntrl |= (0x5 << 1); - break; - case SNDRV_PCM_RATE_11025: - addcntrl |= (0x4 << 1); - break; - case SNDRV_PCM_RATE_16000: - addcntrl |= (0x3 << 1); - break; - case SNDRV_PCM_RATE_22050: - addcntrl |= (0x2 << 1); - break; - case SNDRV_PCM_RATE_32000: - addcntrl |= (0x1 << 1); - break; - case SNDRV_PCM_RATE_44100: - case SNDRV_PCM_RATE_48000: - break; - } - ret = wm8940_write(codec, WM8940_ADDCNTRL, addcntrl); - if (ret) - goto error_ret; - - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S8: - companding = companding | (1 << 5); - break; - case SNDRV_PCM_FORMAT_S16_LE: - break; - case SNDRV_PCM_FORMAT_S20_3LE: - iface |= (1 << 5); - break; - case SNDRV_PCM_FORMAT_S24_LE: - iface |= (2 << 5); - break; - case SNDRV_PCM_FORMAT_S32_LE: - iface |= (3 << 5); - break; - } - ret = wm8940_write(codec, WM8940_COMPANDINGCTL, companding); - if (ret) - goto error_ret; - ret = wm8940_write(codec, WM8940_IFACE, iface); - -error_ret: - return ret; -} - -static int wm8940_mute(struct snd_soc_dai *dai, int mute) -{ - struct snd_soc_codec *codec = dai->codec; - u16 mute_reg = wm8940_read_reg_cache(codec, WM8940_DAC) & 0xffbf; - - if (mute) - mute_reg |= 0x40; - - return wm8940_write(codec, WM8940_DAC, mute_reg); -} - -static int wm8940_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - u16 val; - u16 pwr_reg = wm8940_read_reg_cache(codec, WM8940_POWER1) & 0x1F0; - int ret = 0; - - switch (level) { - case SND_SOC_BIAS_ON: - /* ensure bufioen and biasen */ - pwr_reg |= (1 << 2) | (1 << 3); - /* Enable thermal shutdown */ - val = wm8940_read_reg_cache(codec, WM8940_OUTPUTCTL); - ret = wm8940_write(codec, WM8940_OUTPUTCTL, val | 0x2); - if (ret) - break; - /* set vmid to 75k */ - ret = wm8940_write(codec, WM8940_POWER1, pwr_reg | 0x1); - break; - case SND_SOC_BIAS_PREPARE: - /* ensure bufioen and biasen */ - pwr_reg |= (1 << 2) | (1 << 3); - ret = wm8940_write(codec, WM8940_POWER1, pwr_reg | 0x1); - break; - case SND_SOC_BIAS_STANDBY: - /* ensure bufioen and biasen */ - pwr_reg |= (1 << 2) | (1 << 3); - /* set vmid to 300k for standby */ - ret = wm8940_write(codec, WM8940_POWER1, pwr_reg | 0x2); - break; - case SND_SOC_BIAS_OFF: - ret = wm8940_write(codec, WM8940_POWER1, pwr_reg); - break; - } - - return ret; -} - -struct pll_ { - unsigned int pre_scale:2; - unsigned int n:4; - unsigned int k; -}; - -static struct pll_ pll_div; - -/* The size in bits of the pll divide multiplied by 10 - * to allow rounding later */ -#define FIXED_PLL_SIZE ((1 << 24) * 10) -static void pll_factors(unsigned int target, unsigned int source) -{ - unsigned long long Kpart; - unsigned int K, Ndiv, Nmod; - /* The left shift ist to avoid accuracy loss when right shifting */ - Ndiv = target / source; - - if (Ndiv > 12) { - source <<= 1; - /* Multiply by 2 */ - pll_div.pre_scale = 0; - Ndiv = target / source; - } else if (Ndiv < 3) { - source >>= 2; - /* Divide by 4 */ - pll_div.pre_scale = 3; - Ndiv = target / source; - } else if (Ndiv < 6) { - source >>= 1; - /* divide by 2 */ - pll_div.pre_scale = 2; - Ndiv = target / source; - } else - pll_div.pre_scale = 1; - - if ((Ndiv < 6) || (Ndiv > 12)) - printk(KERN_WARNING - "WM8940 N value %d outwith recommended range!d\n", - Ndiv); - - pll_div.n = Ndiv; - Nmod = target % source; - Kpart = FIXED_PLL_SIZE * (long long)Nmod; - - do_div(Kpart, source); - - K = Kpart & 0xFFFFFFFF; - - /* Check if we need to round */ - if ((K % 10) >= 5) - K += 5; - - /* Move down to proper range now rounding is done */ - K /= 10; - - pll_div.k = K; -} - -/* Untested at the moment */ -static int wm8940_set_dai_pll(struct snd_soc_dai *codec_dai, - int pll_id, unsigned int freq_in, unsigned int freq_out) -{ - struct snd_soc_codec *codec = codec_dai->codec; - u16 reg; - - /* Turn off PLL */ - reg = wm8940_read_reg_cache(codec, WM8940_POWER1); - wm8940_write(codec, WM8940_POWER1, reg & 0x1df); - - if (freq_in == 0 || freq_out == 0) { - /* Clock CODEC directly from MCLK */ - reg = wm8940_read_reg_cache(codec, WM8940_CLOCK); - wm8940_write(codec, WM8940_CLOCK, reg & 0x0ff); - /* Pll power down */ - wm8940_write(codec, WM8940_PLLN, (1 << 7)); - return 0; - } - - /* Pll is followed by a frequency divide by 4 */ - pll_factors(freq_out*4, freq_in); - if (pll_div.k) - wm8940_write(codec, WM8940_PLLN, - (pll_div.pre_scale << 4) | pll_div.n | (1 << 6)); - else /* No factional component */ - wm8940_write(codec, WM8940_PLLN, - (pll_div.pre_scale << 4) | pll_div.n); - wm8940_write(codec, WM8940_PLLK1, pll_div.k >> 18); - wm8940_write(codec, WM8940_PLLK2, (pll_div.k >> 9) & 0x1ff); - wm8940_write(codec, WM8940_PLLK3, pll_div.k & 0x1ff); - /* Enable the PLL */ - reg = wm8940_read_reg_cache(codec, WM8940_POWER1); - wm8940_write(codec, WM8940_POWER1, reg | 0x020); - - /* Run CODEC from PLL instead of MCLK */ - reg = wm8940_read_reg_cache(codec, WM8940_CLOCK); - wm8940_write(codec, WM8940_CLOCK, reg | 0x100); - - return 0; -} - -static int wm8940_set_dai_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir) -{ - struct snd_soc_codec *codec = codec_dai->codec; - struct wm8940_priv *wm8940 = codec->private_data; - - switch (freq) { - case 11289600: - case 12000000: - case 12288000: - case 16934400: - case 18432000: - wm8940->sysclk = freq; - return 0; - } - return -EINVAL; -} - -static int wm8940_set_dai_clkdiv(struct snd_soc_dai *codec_dai, - int div_id, int div) -{ - struct snd_soc_codec *codec = codec_dai->codec; - u16 reg; - int ret = 0; - - switch (div_id) { - case WM8940_BCLKDIV: - reg = wm8940_read_reg_cache(codec, WM8940_CLOCK) & 0xFFEF3; - ret = wm8940_write(codec, WM8940_CLOCK, reg | (div << 2)); - break; - case WM8940_MCLKDIV: - reg = wm8940_read_reg_cache(codec, WM8940_CLOCK) & 0xFF1F; - ret = wm8940_write(codec, WM8940_CLOCK, reg | (div << 5)); - break; - case WM8940_OPCLKDIV: - reg = wm8940_read_reg_cache(codec, WM8940_ADDCNTRL) & 0xFFCF; - ret = wm8940_write(codec, WM8940_ADDCNTRL, reg | (div << 4)); - break; - } - return ret; -} - -#define WM8940_RATES SNDRV_PCM_RATE_8000_48000 - -#define WM8940_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ - SNDRV_PCM_FMTBIT_S16_LE | \ - SNDRV_PCM_FMTBIT_S20_3LE | \ - SNDRV_PCM_FMTBIT_S24_LE | \ - SNDRV_PCM_FMTBIT_S32_LE) - -static struct snd_soc_dai_ops wm8940_dai_ops = { - .hw_params = wm8940_i2s_hw_params, - .set_sysclk = wm8940_set_dai_sysclk, - .digital_mute = wm8940_mute, - .set_fmt = wm8940_set_dai_fmt, - .set_clkdiv = wm8940_set_dai_clkdiv, - .set_pll = wm8940_set_dai_pll, -}; - -struct snd_soc_dai wm8940_dai = { - .name = "WM8940", - .playback = { - .stream_name = "Playback", - .channels_min = 1, - .channels_max = 2, - .rates = WM8940_RATES, - .formats = WM8940_FORMATS, - }, - .capture = { - .stream_name = "Capture", - .channels_min = 1, - .channels_max = 2, - .rates = WM8940_RATES, - .formats = WM8940_FORMATS, - }, - .ops = &wm8940_dai_ops, - .symmetric_rates = 1, -}; -EXPORT_SYMBOL_GPL(wm8940_dai); - -static int wm8940_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; - - return wm8940_set_bias_level(codec, SND_SOC_BIAS_OFF); -} - -static int wm8940_resume(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; - int i; - int ret; - u8 data[3]; - u16 *cache = codec->reg_cache; - - /* Sync reg_cache with the hardware - * Could use auto incremented writes to speed this up - */ - for (i = 0; i < ARRAY_SIZE(wm8940_reg_defaults); i++) { - data[0] = i; - data[1] = (cache[i] & 0xFF00) >> 8; - data[2] = cache[i] & 0x00FF; - ret = codec->hw_write(codec->control_data, data, 3); - if (ret < 0) - goto error_ret; - else if (ret != 3) { - ret = -EIO; - goto error_ret; - } - } - ret = wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - if (ret) - goto error_ret; - ret = wm8940_set_bias_level(codec, codec->suspend_bias_level); - -error_ret: - return ret; -} - -static struct snd_soc_codec *wm8940_codec; - -static int wm8940_probe(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec; - - int ret = 0; - - if (wm8940_codec == NULL) { - dev_err(&pdev->dev, "Codec device not registered\n"); - return -ENODEV; - } - - socdev->card->codec = wm8940_codec; - codec = wm8940_codec; - - mutex_init(&codec->mutex); - /* register pcms */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - dev_err(codec->dev, "failed to create pcms: %d\n", ret); - goto pcm_err; - } - - ret = snd_soc_add_controls(codec, wm8940_snd_controls, - ARRAY_SIZE(wm8940_snd_controls)); - if (ret) - goto error_free_pcms; - ret = wm8940_add_widgets(codec); - if (ret) - goto error_free_pcms; - - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(codec->dev, "failed to register card: %d\n", ret); - goto error_free_pcms; - } - - return ret; - -error_free_pcms: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -pcm_err: - return ret; -} - -static int wm8940_remove(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); - - return 0; -} - -struct snd_soc_codec_device soc_codec_dev_wm8940 = { - .probe = wm8940_probe, - .remove = wm8940_remove, - .suspend = wm8940_suspend, - .resume = wm8940_resume, -}; -EXPORT_SYMBOL_GPL(soc_codec_dev_wm8940); - -static int wm8940_register(struct wm8940_priv *wm8940) -{ - struct wm8940_setup_data *pdata = wm8940->codec.dev->platform_data; - struct snd_soc_codec *codec = &wm8940->codec; - int ret; - u16 reg; - if (wm8940_codec) { - dev_err(codec->dev, "Another WM8940 is registered\n"); - return -EINVAL; - } - - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); - - codec->private_data = wm8940; - codec->name = "WM8940"; - codec->owner = THIS_MODULE; - codec->read = wm8940_read_reg_cache; - codec->write = wm8940_write; - codec->bias_level = SND_SOC_BIAS_OFF; - codec->set_bias_level = wm8940_set_bias_level; - codec->dai = &wm8940_dai; - codec->num_dai = 1; - codec->reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults); - codec->reg_cache = &wm8940->reg_cache; - - memcpy(codec->reg_cache, wm8940_reg_defaults, - sizeof(wm8940_reg_defaults)); - - ret = wm8940_reset(codec); - if (ret < 0) { - dev_err(codec->dev, "Failed to issue reset\n"); - return ret; - } - - wm8940_dai.dev = codec->dev; - - wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - ret = wm8940_write(codec, WM8940_POWER1, 0x180); - if (ret < 0) - return ret; - - if (!pdata) - dev_warn(codec->dev, "No platform data supplied\n"); - else { - reg = wm8940_read_reg_cache(codec, WM8940_OUTPUTCTL); - ret = wm8940_write(codec, WM8940_OUTPUTCTL, reg | pdata->vroi); - if (ret < 0) - return ret; - } - - - wm8940_codec = codec; - - ret = snd_soc_register_codec(codec); - if (ret) { - dev_err(codec->dev, "Failed to register codec: %d\n", ret); - return ret; - } - - ret = snd_soc_register_dai(&wm8940_dai); - if (ret) { - dev_err(codec->dev, "Failed to register DAI: %d\n", ret); - snd_soc_unregister_codec(codec); - return ret; - } - - return 0; -} - -static void wm8940_unregister(struct wm8940_priv *wm8940) -{ - wm8940_set_bias_level(&wm8940->codec, SND_SOC_BIAS_OFF); - snd_soc_unregister_dai(&wm8940_dai); - snd_soc_unregister_codec(&wm8940->codec); - kfree(wm8940); - wm8940_codec = NULL; -} - -static int wm8940_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - struct wm8940_priv *wm8940; - struct snd_soc_codec *codec; - - wm8940 = kzalloc(sizeof *wm8940, GFP_KERNEL); - if (wm8940 == NULL) - return -ENOMEM; - - codec = &wm8940->codec; - codec->hw_write = (hw_write_t)i2c_master_send; - i2c_set_clientdata(i2c, wm8940); - codec->control_data = i2c; - codec->dev = &i2c->dev; - - return wm8940_register(wm8940); -} - -static int __devexit wm8940_i2c_remove(struct i2c_client *client) -{ - struct wm8940_priv *wm8940 = i2c_get_clientdata(client); - - wm8940_unregister(wm8940); - - return 0; -} - -static const struct i2c_device_id wm8940_i2c_id[] = { - { "wm8940", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wm8940_i2c_id); - -static struct i2c_driver wm8940_i2c_driver = { - .driver = { - .name = "WM8940 I2C Codec", - .owner = THIS_MODULE, - }, - .probe = wm8940_i2c_probe, - .remove = __devexit_p(wm8940_i2c_remove), - .id_table = wm8940_i2c_id, -}; - -static int __init wm8940_modinit(void) -{ - int ret; - - ret = i2c_add_driver(&wm8940_i2c_driver); - if (ret) - printk(KERN_ERR "Failed to register WM8940 I2C driver: %d\n", - ret); - return ret; -} -module_init(wm8940_modinit); - -static void __exit wm8940_exit(void) -{ - i2c_del_driver(&wm8940_i2c_driver); -} -module_exit(wm8940_exit); - -MODULE_DESCRIPTION("ASoC WM8940 driver"); -MODULE_AUTHOR("Jonathan Cameron"); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/codecs/wm8940.h b/trunk/sound/soc/codecs/wm8940.h deleted file mode 100644 index 8410eed3ef84..000000000000 --- a/trunk/sound/soc/codecs/wm8940.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * wm8940.h -- WM8940 Soc Audio driver - * - * 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. - */ - -#ifndef _WM8940_H -#define _WM8940_H - -struct wm8940_setup_data { - /* Vref to analogue output resistance */ -#define WM8940_VROI_1K 0 -#define WM8940_VROI_30K 1 - unsigned int vroi:1; -}; -extern struct snd_soc_dai wm8940_dai; -extern struct snd_soc_codec_device soc_codec_dev_wm8940; - -/* WM8940 register space */ -#define WM8940_SOFTRESET 0x00 -#define WM8940_POWER1 0x01 -#define WM8940_POWER2 0x02 -#define WM8940_POWER3 0x03 -#define WM8940_IFACE 0x04 -#define WM8940_COMPANDINGCTL 0x05 -#define WM8940_CLOCK 0x06 -#define WM8940_ADDCNTRL 0x07 -#define WM8940_GPIO 0x08 -#define WM8940_CTLINT 0x09 -#define WM8940_DAC 0x0A -#define WM8940_DACVOL 0x0B - -#define WM8940_ADC 0x0E -#define WM8940_ADCVOL 0x0F -#define WM8940_NOTCH1 0x10 -#define WM8940_NOTCH2 0x11 -#define WM8940_NOTCH3 0x12 -#define WM8940_NOTCH4 0x13 -#define WM8940_NOTCH5 0x14 -#define WM8940_NOTCH6 0x15 -#define WM8940_NOTCH7 0x16 -#define WM8940_NOTCH8 0x17 -#define WM8940_DACLIM1 0x18 -#define WM8940_DACLIM2 0x19 - -#define WM8940_ALC1 0x20 -#define WM8940_ALC2 0x21 -#define WM8940_ALC3 0x22 -#define WM8940_NOISEGATE 0x23 -#define WM8940_PLLN 0x24 -#define WM8940_PLLK1 0x25 -#define WM8940_PLLK2 0x26 -#define WM8940_PLLK3 0x27 - -#define WM8940_ALC4 0x2A - -#define WM8940_INPUTCTL 0x2C -#define WM8940_PGAGAIN 0x2D - -#define WM8940_ADCBOOST 0x2F - -#define WM8940_OUTPUTCTL 0x31 -#define WM8940_SPKMIX 0x32 - -#define WM8940_SPKVOL 0x36 - -#define WM8940_MONOMIX 0x38 - -#define WM8940_CACHEREGNUM 0x57 - - -/* Clock divider Id's */ -#define WM8940_BCLKDIV 0 -#define WM8940_MCLKDIV 1 -#define WM8940_OPCLKDIV 2 - -/* MCLK clock dividers */ -#define WM8940_MCLKDIV_1 0 -#define WM8940_MCLKDIV_1_5 1 -#define WM8940_MCLKDIV_2 2 -#define WM8940_MCLKDIV_3 3 -#define WM8940_MCLKDIV_4 4 -#define WM8940_MCLKDIV_6 5 -#define WM8940_MCLKDIV_8 6 -#define WM8940_MCLKDIV_12 7 - -/* BCLK clock dividers */ -#define WM8940_BCLKDIV_1 0 -#define WM8940_BCLKDIV_2 1 -#define WM8940_BCLKDIV_4 2 -#define WM8940_BCLKDIV_8 3 -#define WM8940_BCLKDIV_16 4 -#define WM8940_BCLKDIV_32 5 - -/* PLL Out Dividers */ -#define WM8940_OPCLKDIV_1 0 -#define WM8940_OPCLKDIV_2 1 -#define WM8940_OPCLKDIV_3 2 -#define WM8940_OPCLKDIV_4 3 - -#endif /* _WM8940_H */ - diff --git a/trunk/sound/soc/codecs/wm8960.c b/trunk/sound/soc/codecs/wm8960.c deleted file mode 100644 index e224d8add170..000000000000 --- a/trunk/sound/soc/codecs/wm8960.c +++ /dev/null @@ -1,969 +0,0 @@ -/* - * wm8960.c -- WM8960 ALSA SoC Audio driver - * - * Author: Liam Girdwood - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "wm8960.h" - -#define AUDIO_NAME "wm8960" - -struct snd_soc_codec_device soc_codec_dev_wm8960; - -/* R25 - Power 1 */ -#define WM8960_VREF 0x40 - -/* R28 - Anti-pop 1 */ -#define WM8960_POBCTRL 0x80 -#define WM8960_BUFDCOPEN 0x10 -#define WM8960_BUFIOEN 0x08 -#define WM8960_SOFT_ST 0x04 -#define WM8960_HPSTBY 0x01 - -/* R29 - Anti-pop 2 */ -#define WM8960_DISOP 0x40 - -/* - * wm8960 register cache - * We can't read the WM8960 register space when we are - * using 2 wire for device control, so we cache them instead. - */ -static const u16 wm8960_reg[WM8960_CACHEREGNUM] = { - 0x0097, 0x0097, 0x0000, 0x0000, - 0x0000, 0x0008, 0x0000, 0x000a, - 0x01c0, 0x0000, 0x00ff, 0x00ff, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x007b, 0x0100, 0x0032, - 0x0000, 0x00c3, 0x00c3, 0x01c0, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0100, 0x0100, 0x0050, 0x0050, - 0x0050, 0x0050, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0040, 0x0000, - 0x0000, 0x0050, 0x0050, 0x0000, - 0x0002, 0x0037, 0x004d, 0x0080, - 0x0008, 0x0031, 0x0026, 0x00e9, -}; - -struct wm8960_priv { - u16 reg_cache[WM8960_CACHEREGNUM]; - struct snd_soc_codec codec; -}; - -/* - * read wm8960 register cache - */ -static inline unsigned int wm8960_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - if (reg == WM8960_RESET) - return 0; - if (reg >= WM8960_CACHEREGNUM) - return -1; - return cache[reg]; -} - -/* - * write wm8960 register cache - */ -static inline void wm8960_write_reg_cache(struct snd_soc_codec *codec, - u16 reg, unsigned int value) -{ - u16 *cache = codec->reg_cache; - if (reg >= WM8960_CACHEREGNUM) - return; - cache[reg] = value; -} - -static inline unsigned int wm8960_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - return wm8960_read_reg_cache(codec, reg); -} - -/* - * write to the WM8960 register space - */ -static int wm8960_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[2]; - - /* data is - * D15..D9 WM8960 register offset - * D8...D0 register data - */ - data[0] = (reg << 1) | ((value >> 8) & 0x0001); - data[1] = value & 0x00ff; - - wm8960_write_reg_cache(codec, reg, value); - if (codec->hw_write(codec->control_data, data, 2) == 2) - return 0; - else - return -EIO; -} - -#define wm8960_reset(c) wm8960_write(c, WM8960_RESET, 0) - -/* enumerated controls */ -static const char *wm8960_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; -static const char *wm8960_polarity[] = {"No Inversion", "Left Inverted", - "Right Inverted", "Stereo Inversion"}; -static const char *wm8960_3d_upper_cutoff[] = {"High", "Low"}; -static const char *wm8960_3d_lower_cutoff[] = {"Low", "High"}; -static const char *wm8960_alcfunc[] = {"Off", "Right", "Left", "Stereo"}; -static const char *wm8960_alcmode[] = {"ALC", "Limiter"}; - -static const struct soc_enum wm8960_enum[] = { - SOC_ENUM_SINGLE(WM8960_DACCTL1, 1, 4, wm8960_deemph), - SOC_ENUM_SINGLE(WM8960_DACCTL1, 5, 4, wm8960_polarity), - SOC_ENUM_SINGLE(WM8960_DACCTL2, 5, 4, wm8960_polarity), - SOC_ENUM_SINGLE(WM8960_3D, 6, 2, wm8960_3d_upper_cutoff), - SOC_ENUM_SINGLE(WM8960_3D, 5, 2, wm8960_3d_lower_cutoff), - SOC_ENUM_SINGLE(WM8960_ALC1, 7, 4, wm8960_alcfunc), - SOC_ENUM_SINGLE(WM8960_ALC3, 8, 2, wm8960_alcmode), -}; - -static const DECLARE_TLV_DB_SCALE(adc_tlv, -9700, 50, 0); -static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 50, 1); -static const DECLARE_TLV_DB_SCALE(bypass_tlv, -2100, 300, 0); -static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1); - -static const struct snd_kcontrol_new wm8960_snd_controls[] = { -SOC_DOUBLE_R_TLV("Capture Volume", WM8960_LINVOL, WM8960_RINVOL, - 0, 63, 0, adc_tlv), -SOC_DOUBLE_R("Capture Volume ZC Switch", WM8960_LINVOL, WM8960_RINVOL, - 6, 1, 0), -SOC_DOUBLE_R("Capture Switch", WM8960_LINVOL, WM8960_RINVOL, - 7, 1, 0), - -SOC_DOUBLE_R_TLV("Playback Volume", WM8960_LDAC, WM8960_RDAC, - 0, 255, 0, dac_tlv), - -SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8960_LOUT1, WM8960_ROUT1, - 0, 127, 0, out_tlv), -SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8960_LOUT1, WM8960_ROUT1, - 7, 1, 0), - -SOC_DOUBLE_R_TLV("Speaker Playback Volume", WM8960_LOUT2, WM8960_ROUT2, - 0, 127, 0, out_tlv), -SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8960_LOUT2, WM8960_ROUT2, - 7, 1, 0), -SOC_SINGLE("Speaker DC Volume", WM8960_CLASSD3, 3, 5, 0), -SOC_SINGLE("Speaker AC Volume", WM8960_CLASSD3, 0, 5, 0), - -SOC_SINGLE("PCM Playback -6dB Switch", WM8960_DACCTL1, 7, 1, 0), -SOC_ENUM("ADC Polarity", wm8960_enum[1]), -SOC_ENUM("Playback De-emphasis", wm8960_enum[0]), -SOC_SINGLE("ADC High Pass Filter Switch", WM8960_DACCTL1, 0, 1, 0), - -SOC_ENUM("DAC Polarity", wm8960_enum[2]), - -SOC_ENUM("3D Filter Upper Cut-Off", wm8960_enum[3]), -SOC_ENUM("3D Filter Lower Cut-Off", wm8960_enum[4]), -SOC_SINGLE("3D Volume", WM8960_3D, 1, 15, 0), -SOC_SINGLE("3D Switch", WM8960_3D, 0, 1, 0), - -SOC_ENUM("ALC Function", wm8960_enum[5]), -SOC_SINGLE("ALC Max Gain", WM8960_ALC1, 4, 7, 0), -SOC_SINGLE("ALC Target", WM8960_ALC1, 0, 15, 1), -SOC_SINGLE("ALC Min Gain", WM8960_ALC2, 4, 7, 0), -SOC_SINGLE("ALC Hold Time", WM8960_ALC2, 0, 15, 0), -SOC_ENUM("ALC Mode", wm8960_enum[6]), -SOC_SINGLE("ALC Decay", WM8960_ALC3, 4, 15, 0), -SOC_SINGLE("ALC Attack", WM8960_ALC3, 0, 15, 0), - -SOC_SINGLE("Noise Gate Threshold", WM8960_NOISEG, 3, 31, 0), -SOC_SINGLE("Noise Gate Switch", WM8960_NOISEG, 0, 1, 0), - -SOC_DOUBLE_R("ADC PCM Capture Volume", WM8960_LINPATH, WM8960_RINPATH, - 0, 127, 0), - -SOC_SINGLE_TLV("Left Output Mixer Boost Bypass Volume", - WM8960_BYPASS1, 4, 7, 1, bypass_tlv), -SOC_SINGLE_TLV("Left Output Mixer LINPUT3 Volume", - WM8960_LOUTMIX, 4, 7, 1, bypass_tlv), -SOC_SINGLE_TLV("Right Output Mixer Boost Bypass Volume", - WM8960_BYPASS2, 4, 7, 1, bypass_tlv), -SOC_SINGLE_TLV("Right Output Mixer RINPUT3 Volume", - WM8960_ROUTMIX, 4, 7, 1, bypass_tlv), -}; - -static const struct snd_kcontrol_new wm8960_lin_boost[] = { -SOC_DAPM_SINGLE("LINPUT2 Switch", WM8960_LINPATH, 6, 1, 0), -SOC_DAPM_SINGLE("LINPUT3 Switch", WM8960_LINPATH, 7, 1, 0), -SOC_DAPM_SINGLE("LINPUT1 Switch", WM8960_LINPATH, 8, 1, 0), -}; - -static const struct snd_kcontrol_new wm8960_lin[] = { -SOC_DAPM_SINGLE("Boost Switch", WM8960_LINPATH, 3, 1, 0), -}; - -static const struct snd_kcontrol_new wm8960_rin_boost[] = { -SOC_DAPM_SINGLE("RINPUT2 Switch", WM8960_RINPATH, 6, 1, 0), -SOC_DAPM_SINGLE("RINPUT3 Switch", WM8960_RINPATH, 7, 1, 0), -SOC_DAPM_SINGLE("RINPUT1 Switch", WM8960_RINPATH, 8, 1, 0), -}; - -static const struct snd_kcontrol_new wm8960_rin[] = { -SOC_DAPM_SINGLE("Boost Switch", WM8960_RINPATH, 3, 1, 0), -}; - -static const struct snd_kcontrol_new wm8960_loutput_mixer[] = { -SOC_DAPM_SINGLE("PCM Playback Switch", WM8960_LOUTMIX, 8, 1, 0), -SOC_DAPM_SINGLE("LINPUT3 Switch", WM8960_LOUTMIX, 7, 1, 0), -SOC_DAPM_SINGLE("Boost Bypass Switch", WM8960_BYPASS1, 7, 1, 0), -}; - -static const struct snd_kcontrol_new wm8960_routput_mixer[] = { -SOC_DAPM_SINGLE("PCM Playback Switch", WM8960_ROUTMIX, 8, 1, 0), -SOC_DAPM_SINGLE("RINPUT3 Switch", WM8960_ROUTMIX, 7, 1, 0), -SOC_DAPM_SINGLE("Boost Bypass Switch", WM8960_BYPASS2, 7, 1, 0), -}; - -static const struct snd_kcontrol_new wm8960_mono_out[] = { -SOC_DAPM_SINGLE("Left Switch", WM8960_MONOMIX1, 7, 1, 0), -SOC_DAPM_SINGLE("Right Switch", WM8960_MONOMIX2, 7, 1, 0), -}; - -static const struct snd_soc_dapm_widget wm8960_dapm_widgets[] = { -SND_SOC_DAPM_INPUT("LINPUT1"), -SND_SOC_DAPM_INPUT("RINPUT1"), -SND_SOC_DAPM_INPUT("LINPUT2"), -SND_SOC_DAPM_INPUT("RINPUT2"), -SND_SOC_DAPM_INPUT("LINPUT3"), -SND_SOC_DAPM_INPUT("RINPUT3"), - -SND_SOC_DAPM_MICBIAS("MICB", WM8960_POWER1, 1, 0), - -SND_SOC_DAPM_MIXER("Left Boost Mixer", WM8960_POWER1, 5, 0, - wm8960_lin_boost, ARRAY_SIZE(wm8960_lin_boost)), -SND_SOC_DAPM_MIXER("Right Boost Mixer", WM8960_POWER1, 4, 0, - wm8960_rin_boost, ARRAY_SIZE(wm8960_rin_boost)), - -SND_SOC_DAPM_MIXER("Left Input Mixer", WM8960_POWER3, 5, 0, - wm8960_lin, ARRAY_SIZE(wm8960_lin)), -SND_SOC_DAPM_MIXER("Right Input Mixer", WM8960_POWER3, 4, 0, - wm8960_rin, ARRAY_SIZE(wm8960_rin)), - -SND_SOC_DAPM_ADC("Left ADC", "Capture", WM8960_POWER2, 3, 0), -SND_SOC_DAPM_ADC("Right ADC", "Capture", WM8960_POWER2, 2, 0), - -SND_SOC_DAPM_DAC("Left DAC", "Playback", WM8960_POWER2, 8, 0), -SND_SOC_DAPM_DAC("Right DAC", "Playback", WM8960_POWER2, 7, 0), - -SND_SOC_DAPM_MIXER("Left Output Mixer", WM8960_POWER3, 3, 0, - &wm8960_loutput_mixer[0], - ARRAY_SIZE(wm8960_loutput_mixer)), -SND_SOC_DAPM_MIXER("Right Output Mixer", WM8960_POWER3, 2, 0, - &wm8960_routput_mixer[0], - ARRAY_SIZE(wm8960_routput_mixer)), - -SND_SOC_DAPM_MIXER("Mono Output Mixer", WM8960_POWER2, 1, 0, - &wm8960_mono_out[0], - ARRAY_SIZE(wm8960_mono_out)), - -SND_SOC_DAPM_PGA("LOUT1 PGA", WM8960_POWER2, 6, 0, NULL, 0), -SND_SOC_DAPM_PGA("ROUT1 PGA", WM8960_POWER2, 5, 0, NULL, 0), - -SND_SOC_DAPM_PGA("Left Speaker PGA", WM8960_POWER2, 4, 0, NULL, 0), -SND_SOC_DAPM_PGA("Right Speaker PGA", WM8960_POWER2, 3, 0, NULL, 0), - -SND_SOC_DAPM_PGA("Right Speaker Output", WM8960_CLASSD1, 7, 0, NULL, 0), -SND_SOC_DAPM_PGA("Left Speaker Output", WM8960_CLASSD1, 6, 0, NULL, 0), - -SND_SOC_DAPM_OUTPUT("SPK_LP"), -SND_SOC_DAPM_OUTPUT("SPK_LN"), -SND_SOC_DAPM_OUTPUT("HP_L"), -SND_SOC_DAPM_OUTPUT("HP_R"), -SND_SOC_DAPM_OUTPUT("SPK_RP"), -SND_SOC_DAPM_OUTPUT("SPK_RN"), -SND_SOC_DAPM_OUTPUT("OUT3"), -}; - -static const struct snd_soc_dapm_route audio_paths[] = { - { "Left Boost Mixer", "LINPUT1 Switch", "LINPUT1" }, - { "Left Boost Mixer", "LINPUT2 Switch", "LINPUT2" }, - { "Left Boost Mixer", "LINPUT3 Switch", "LINPUT3" }, - - { "Left Input Mixer", "Boost Switch", "Left Boost Mixer", }, - { "Left Input Mixer", NULL, "LINPUT1", }, /* Really Boost Switch */ - { "Left Input Mixer", NULL, "LINPUT2" }, - { "Left Input Mixer", NULL, "LINPUT3" }, - - { "Right Boost Mixer", "RINPUT1 Switch", "RINPUT1" }, - { "Right Boost Mixer", "RINPUT2 Switch", "RINPUT2" }, - { "Right Boost Mixer", "RINPUT3 Switch", "RINPUT3" }, - - { "Right Input Mixer", "Boost Switch", "Right Boost Mixer", }, - { "Right Input Mixer", NULL, "RINPUT1", }, /* Really Boost Switch */ - { "Right Input Mixer", NULL, "RINPUT2" }, - { "Right Input Mixer", NULL, "LINPUT3" }, - - { "Left ADC", NULL, "Left Input Mixer" }, - { "Right ADC", NULL, "Right Input Mixer" }, - - { "Left Output Mixer", "LINPUT3 Switch", "LINPUT3" }, - { "Left Output Mixer", "Boost Bypass Switch", "Left Boost Mixer"} , - { "Left Output Mixer", "PCM Playback Switch", "Left DAC" }, - - { "Right Output Mixer", "RINPUT3 Switch", "RINPUT3" }, - { "Right Output Mixer", "Boost Bypass Switch", "Right Boost Mixer" } , - { "Right Output Mixer", "PCM Playback Switch", "Right DAC" }, - - { "Mono Output Mixer", "Left Switch", "Left Output Mixer" }, - { "Mono Output Mixer", "Right Switch", "Right Output Mixer" }, - - { "LOUT1 PGA", NULL, "Left Output Mixer" }, - { "ROUT1 PGA", NULL, "Right Output Mixer" }, - - { "HP_L", NULL, "LOUT1 PGA" }, - { "HP_R", NULL, "ROUT1 PGA" }, - - { "Left Speaker PGA", NULL, "Left Output Mixer" }, - { "Right Speaker PGA", NULL, "Right Output Mixer" }, - - { "Left Speaker Output", NULL, "Left Speaker PGA" }, - { "Right Speaker Output", NULL, "Right Speaker PGA" }, - - { "SPK_LN", NULL, "Left Speaker Output" }, - { "SPK_LP", NULL, "Left Speaker Output" }, - { "SPK_RN", NULL, "Right Speaker Output" }, - { "SPK_RP", NULL, "Right Speaker Output" }, - - { "OUT3", NULL, "Mono Output Mixer", } -}; - -static int wm8960_add_widgets(struct snd_soc_codec *codec) -{ - snd_soc_dapm_new_controls(codec, wm8960_dapm_widgets, - ARRAY_SIZE(wm8960_dapm_widgets)); - - snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); - - snd_soc_dapm_new_widgets(codec); - return 0; -} - -static int wm8960_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) -{ - struct snd_soc_codec *codec = codec_dai->codec; - u16 iface = 0; - - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - iface |= 0x0040; - break; - case SND_SOC_DAIFMT_CBS_CFS: - break; - default: - return -EINVAL; - } - - /* interface format */ - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - iface |= 0x0002; - break; - case SND_SOC_DAIFMT_RIGHT_J: - break; - case SND_SOC_DAIFMT_LEFT_J: - iface |= 0x0001; - break; - case SND_SOC_DAIFMT_DSP_A: - iface |= 0x0003; - break; - case SND_SOC_DAIFMT_DSP_B: - iface |= 0x0013; - break; - default: - return -EINVAL; - } - - /* clock inversion */ - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - break; - case SND_SOC_DAIFMT_IB_IF: - iface |= 0x0090; - break; - case SND_SOC_DAIFMT_IB_NF: - iface |= 0x0080; - break; - case SND_SOC_DAIFMT_NB_IF: - iface |= 0x0010; - break; - default: - return -EINVAL; - } - - /* set iface */ - wm8960_write(codec, WM8960_IFACE1, iface); - return 0; -} - -static int wm8960_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->card->codec; - u16 iface = wm8960_read(codec, WM8960_IFACE1) & 0xfff3; - - /* bit size */ - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - break; - case SNDRV_PCM_FORMAT_S20_3LE: - iface |= 0x0004; - break; - case SNDRV_PCM_FORMAT_S24_LE: - iface |= 0x0008; - break; - } - - /* set iface */ - wm8960_write(codec, WM8960_IFACE1, iface); - return 0; -} - -static int wm8960_mute(struct snd_soc_dai *dai, int mute) -{ - struct snd_soc_codec *codec = dai->codec; - u16 mute_reg = wm8960_read(codec, WM8960_DACCTL1) & 0xfff7; - - if (mute) - wm8960_write(codec, WM8960_DACCTL1, mute_reg | 0x8); - else - wm8960_write(codec, WM8960_DACCTL1, mute_reg); - return 0; -} - -static int wm8960_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - struct wm8960_data *pdata = codec->dev->platform_data; - u16 reg; - - switch (level) { - case SND_SOC_BIAS_ON: - break; - - case SND_SOC_BIAS_PREPARE: - /* Set VMID to 2x50k */ - reg = wm8960_read(codec, WM8960_POWER1); - reg &= ~0x180; - reg |= 0x80; - wm8960_write(codec, WM8960_POWER1, reg); - break; - - case SND_SOC_BIAS_STANDBY: - if (codec->bias_level == SND_SOC_BIAS_OFF) { - /* Enable anti-pop features */ - wm8960_write(codec, WM8960_APOP1, - WM8960_POBCTRL | WM8960_SOFT_ST | - WM8960_BUFDCOPEN | WM8960_BUFIOEN); - - /* Discharge HP output */ - reg = WM8960_DISOP; - if (pdata) - reg |= pdata->dres << 4; - wm8960_write(codec, WM8960_APOP2, reg); - - msleep(400); - - wm8960_write(codec, WM8960_APOP2, 0); - - /* Enable & ramp VMID at 2x50k */ - reg = wm8960_read(codec, WM8960_POWER1); - reg |= 0x80; - wm8960_write(codec, WM8960_POWER1, reg); - msleep(100); - - /* Enable VREF */ - wm8960_write(codec, WM8960_POWER1, reg | WM8960_VREF); - - /* Disable anti-pop features */ - wm8960_write(codec, WM8960_APOP1, WM8960_BUFIOEN); - } - - /* Set VMID to 2x250k */ - reg = wm8960_read(codec, WM8960_POWER1); - reg &= ~0x180; - reg |= 0x100; - wm8960_write(codec, WM8960_POWER1, reg); - break; - - case SND_SOC_BIAS_OFF: - /* Enable anti-pop features */ - wm8960_write(codec, WM8960_APOP1, - WM8960_POBCTRL | WM8960_SOFT_ST | - WM8960_BUFDCOPEN | WM8960_BUFIOEN); - - /* Disable VMID and VREF, let them discharge */ - wm8960_write(codec, WM8960_POWER1, 0); - msleep(600); - - wm8960_write(codec, WM8960_APOP1, 0); - break; - } - - codec->bias_level = level; - - return 0; -} - -/* PLL divisors */ -struct _pll_div { - u32 pre_div:1; - u32 n:4; - u32 k:24; -}; - -/* The size in bits of the pll divide multiplied by 10 - * to allow rounding later */ -#define FIXED_PLL_SIZE ((1 << 24) * 10) - -static int pll_factors(unsigned int source, unsigned int target, - struct _pll_div *pll_div) -{ - unsigned long long Kpart; - unsigned int K, Ndiv, Nmod; - - pr_debug("WM8960 PLL: setting %dHz->%dHz\n", source, target); - - /* Scale up target to PLL operating frequency */ - target *= 4; - - Ndiv = target / source; - if (Ndiv < 6) { - source >>= 1; - pll_div->pre_div = 1; - Ndiv = target / source; - } else - pll_div->pre_div = 0; - - if ((Ndiv < 6) || (Ndiv > 12)) { - pr_err("WM8960 PLL: Unsupported N=%d\n", Ndiv); - return -EINVAL; - } - - pll_div->n = Ndiv; - Nmod = target % source; - Kpart = FIXED_PLL_SIZE * (long long)Nmod; - - do_div(Kpart, source); - - K = Kpart & 0xFFFFFFFF; - - /* Check if we need to round */ - if ((K % 10) >= 5) - K += 5; - - /* Move down to proper range now rounding is done */ - K /= 10; - - pll_div->k = K; - - pr_debug("WM8960 PLL: N=%x K=%x pre_div=%d\n", - pll_div->n, pll_div->k, pll_div->pre_div); - - return 0; -} - -static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, - int pll_id, unsigned int freq_in, unsigned int freq_out) -{ - struct snd_soc_codec *codec = codec_dai->codec; - u16 reg; - static struct _pll_div pll_div; - int ret; - - if (freq_in && freq_out) { - ret = pll_factors(freq_in, freq_out, &pll_div); - if (ret != 0) - return ret; - } - - /* Disable the PLL: even if we are changing the frequency the - * PLL needs to be disabled while we do so. */ - wm8960_write(codec, WM8960_CLOCK1, - wm8960_read(codec, WM8960_CLOCK1) & ~1); - wm8960_write(codec, WM8960_POWER2, - wm8960_read(codec, WM8960_POWER2) & ~1); - - if (!freq_in || !freq_out) - return 0; - - reg = wm8960_read(codec, WM8960_PLL1) & ~0x3f; - reg |= pll_div.pre_div << 4; - reg |= pll_div.n; - - if (pll_div.k) { - reg |= 0x20; - - wm8960_write(codec, WM8960_PLL2, (pll_div.k >> 18) & 0x3f); - wm8960_write(codec, WM8960_PLL3, (pll_div.k >> 9) & 0x1ff); - wm8960_write(codec, WM8960_PLL4, pll_div.k & 0x1ff); - } - wm8960_write(codec, WM8960_PLL1, reg); - - /* Turn it on */ - wm8960_write(codec, WM8960_POWER2, - wm8960_read(codec, WM8960_POWER2) | 1); - msleep(250); - wm8960_write(codec, WM8960_CLOCK1, - wm8960_read(codec, WM8960_CLOCK1) | 1); - - return 0; -} - -static int wm8960_set_dai_clkdiv(struct snd_soc_dai *codec_dai, - int div_id, int div) -{ - struct snd_soc_codec *codec = codec_dai->codec; - u16 reg; - - switch (div_id) { - case WM8960_SYSCLKSEL: - reg = wm8960_read(codec, WM8960_CLOCK1) & 0x1fe; - wm8960_write(codec, WM8960_CLOCK1, reg | div); - break; - case WM8960_SYSCLKDIV: - reg = wm8960_read(codec, WM8960_CLOCK1) & 0x1f9; - wm8960_write(codec, WM8960_CLOCK1, reg | div); - break; - case WM8960_DACDIV: - reg = wm8960_read(codec, WM8960_CLOCK1) & 0x1c7; - wm8960_write(codec, WM8960_CLOCK1, reg | div); - break; - case WM8960_OPCLKDIV: - reg = wm8960_read(codec, WM8960_PLL1) & 0x03f; - wm8960_write(codec, WM8960_PLL1, reg | div); - break; - case WM8960_DCLKDIV: - reg = wm8960_read(codec, WM8960_CLOCK2) & 0x03f; - wm8960_write(codec, WM8960_CLOCK2, reg | div); - break; - case WM8960_TOCLKSEL: - reg = wm8960_read(codec, WM8960_ADDCTL1) & 0x1fd; - wm8960_write(codec, WM8960_ADDCTL1, reg | div); - break; - default: - return -EINVAL; - } - - return 0; -} - -#define WM8960_RATES SNDRV_PCM_RATE_8000_48000 - -#define WM8960_FORMATS \ - (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ - SNDRV_PCM_FMTBIT_S24_LE) - -static struct snd_soc_dai_ops wm8960_dai_ops = { - .hw_params = wm8960_hw_params, - .digital_mute = wm8960_mute, - .set_fmt = wm8960_set_dai_fmt, - .set_clkdiv = wm8960_set_dai_clkdiv, - .set_pll = wm8960_set_dai_pll, -}; - -struct snd_soc_dai wm8960_dai = { - .name = "WM8960", - .playback = { - .stream_name = "Playback", - .channels_min = 1, - .channels_max = 2, - .rates = WM8960_RATES, - .formats = WM8960_FORMATS,}, - .capture = { - .stream_name = "Capture", - .channels_min = 1, - .channels_max = 2, - .rates = WM8960_RATES, - .formats = WM8960_FORMATS,}, - .ops = &wm8960_dai_ops, - .symmetric_rates = 1, -}; -EXPORT_SYMBOL_GPL(wm8960_dai); - -static int wm8960_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; - - wm8960_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8960_resume(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; - int i; - u8 data[2]; - u16 *cache = codec->reg_cache; - - /* Sync reg_cache with the hardware */ - for (i = 0; i < ARRAY_SIZE(wm8960_reg); i++) { - data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); - data[1] = cache[i] & 0x00ff; - codec->hw_write(codec->control_data, data, 2); - } - - wm8960_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - wm8960_set_bias_level(codec, codec->suspend_bias_level); - return 0; -} - -static struct snd_soc_codec *wm8960_codec; - -static int wm8960_probe(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec; - int ret = 0; - - if (wm8960_codec == NULL) { - dev_err(&pdev->dev, "Codec device not registered\n"); - return -ENODEV; - } - - socdev->card->codec = wm8960_codec; - codec = wm8960_codec; - - /* register pcms */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - dev_err(codec->dev, "failed to create pcms: %d\n", ret); - goto pcm_err; - } - - snd_soc_add_controls(codec, wm8960_snd_controls, - ARRAY_SIZE(wm8960_snd_controls)); - wm8960_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(codec->dev, "failed to register card: %d\n", ret); - goto card_err; - } - - return ret; - -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -pcm_err: - return ret; -} - -/* power down chip */ -static int wm8960_remove(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); - - return 0; -} - -struct snd_soc_codec_device soc_codec_dev_wm8960 = { - .probe = wm8960_probe, - .remove = wm8960_remove, - .suspend = wm8960_suspend, - .resume = wm8960_resume, -}; -EXPORT_SYMBOL_GPL(soc_codec_dev_wm8960); - -static int wm8960_register(struct wm8960_priv *wm8960) -{ - struct wm8960_data *pdata = wm8960->codec.dev->platform_data; - struct snd_soc_codec *codec = &wm8960->codec; - int ret; - u16 reg; - - if (wm8960_codec) { - dev_err(codec->dev, "Another WM8960 is registered\n"); - return -EINVAL; - } - - if (!pdata) { - dev_warn(codec->dev, "No platform data supplied\n"); - } else { - if (pdata->dres > WM8960_DRES_MAX) { - dev_err(codec->dev, "Invalid DRES: %d\n", pdata->dres); - pdata->dres = 0; - } - } - - mutex_init(&codec->mutex); - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); - - codec->private_data = wm8960; - codec->name = "WM8960"; - codec->owner = THIS_MODULE; - codec->read = wm8960_read_reg_cache; - codec->write = wm8960_write; - codec->bias_level = SND_SOC_BIAS_OFF; - codec->set_bias_level = wm8960_set_bias_level; - codec->dai = &wm8960_dai; - codec->num_dai = 1; - codec->reg_cache_size = WM8960_CACHEREGNUM; - codec->reg_cache = &wm8960->reg_cache; - - memcpy(codec->reg_cache, wm8960_reg, sizeof(wm8960_reg)); - - ret = wm8960_reset(codec); - if (ret < 0) { - dev_err(codec->dev, "Failed to issue reset\n"); - return ret; - } - - wm8960_dai.dev = codec->dev; - - wm8960_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - /* Latch the update bits */ - reg = wm8960_read(codec, WM8960_LINVOL); - wm8960_write(codec, WM8960_LINVOL, reg | 0x100); - reg = wm8960_read(codec, WM8960_RINVOL); - wm8960_write(codec, WM8960_RINVOL, reg | 0x100); - reg = wm8960_read(codec, WM8960_LADC); - wm8960_write(codec, WM8960_LADC, reg | 0x100); - reg = wm8960_read(codec, WM8960_RADC); - wm8960_write(codec, WM8960_RADC, reg | 0x100); - reg = wm8960_read(codec, WM8960_LDAC); - wm8960_write(codec, WM8960_LDAC, reg | 0x100); - reg = wm8960_read(codec, WM8960_RDAC); - wm8960_write(codec, WM8960_RDAC, reg | 0x100); - reg = wm8960_read(codec, WM8960_LOUT1); - wm8960_write(codec, WM8960_LOUT1, reg | 0x100); - reg = wm8960_read(codec, WM8960_ROUT1); - wm8960_write(codec, WM8960_ROUT1, reg | 0x100); - reg = wm8960_read(codec, WM8960_LOUT2); - wm8960_write(codec, WM8960_LOUT2, reg | 0x100); - reg = wm8960_read(codec, WM8960_ROUT2); - wm8960_write(codec, WM8960_ROUT2, reg | 0x100); - - wm8960_codec = codec; - - ret = snd_soc_register_codec(codec); - if (ret != 0) { - dev_err(codec->dev, "Failed to register codec: %d\n", ret); - return ret; - } - - ret = snd_soc_register_dai(&wm8960_dai); - if (ret != 0) { - dev_err(codec->dev, "Failed to register DAI: %d\n", ret); - snd_soc_unregister_codec(codec); - return ret; - } - - return 0; -} - -static void wm8960_unregister(struct wm8960_priv *wm8960) -{ - wm8960_set_bias_level(&wm8960->codec, SND_SOC_BIAS_OFF); - snd_soc_unregister_dai(&wm8960_dai); - snd_soc_unregister_codec(&wm8960->codec); - kfree(wm8960); - wm8960_codec = NULL; -} - -static __devinit int wm8960_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - struct wm8960_priv *wm8960; - struct snd_soc_codec *codec; - - wm8960 = kzalloc(sizeof(struct wm8960_priv), GFP_KERNEL); - if (wm8960 == NULL) - return -ENOMEM; - - codec = &wm8960->codec; - codec->hw_write = (hw_write_t)i2c_master_send; - - i2c_set_clientdata(i2c, wm8960); - codec->control_data = i2c; - - codec->dev = &i2c->dev; - - return wm8960_register(wm8960); -} - -static __devexit int wm8960_i2c_remove(struct i2c_client *client) -{ - struct wm8960_priv *wm8960 = i2c_get_clientdata(client); - wm8960_unregister(wm8960); - return 0; -} - -static const struct i2c_device_id wm8960_i2c_id[] = { - { "wm8960", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wm8960_i2c_id); - -static struct i2c_driver wm8960_i2c_driver = { - .driver = { - .name = "WM8960 I2C Codec", - .owner = THIS_MODULE, - }, - .probe = wm8960_i2c_probe, - .remove = __devexit_p(wm8960_i2c_remove), - .id_table = wm8960_i2c_id, -}; - -static int __init wm8960_modinit(void) -{ - int ret; - - ret = i2c_add_driver(&wm8960_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register WM8960 I2C driver: %d\n", - ret); - } - - return ret; -} -module_init(wm8960_modinit); - -static void __exit wm8960_exit(void) -{ - i2c_del_driver(&wm8960_i2c_driver); -} -module_exit(wm8960_exit); - - -MODULE_DESCRIPTION("ASoC WM8960 driver"); -MODULE_AUTHOR("Liam Girdwood"); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/codecs/wm8960.h b/trunk/sound/soc/codecs/wm8960.h deleted file mode 100644 index c9af56c9d9d4..000000000000 --- a/trunk/sound/soc/codecs/wm8960.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * wm8960.h -- WM8960 Soc Audio driver - * - * 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. - */ - -#ifndef _WM8960_H -#define _WM8960_H - -/* WM8960 register space */ - - -#define WM8960_CACHEREGNUM 56 - -#define WM8960_LINVOL 0x0 -#define WM8960_RINVOL 0x1 -#define WM8960_LOUT1 0x2 -#define WM8960_ROUT1 0x3 -#define WM8960_CLOCK1 0x4 -#define WM8960_DACCTL1 0x5 -#define WM8960_DACCTL2 0x6 -#define WM8960_IFACE1 0x7 -#define WM8960_CLOCK2 0x8 -#define WM8960_IFACE2 0x9 -#define WM8960_LDAC 0xa -#define WM8960_RDAC 0xb - -#define WM8960_RESET 0xf -#define WM8960_3D 0x10 -#define WM8960_ALC1 0x11 -#define WM8960_ALC2 0x12 -#define WM8960_ALC3 0x13 -#define WM8960_NOISEG 0x14 -#define WM8960_LADC 0x15 -#define WM8960_RADC 0x16 -#define WM8960_ADDCTL1 0x17 -#define WM8960_ADDCTL2 0x18 -#define WM8960_POWER1 0x19 -#define WM8960_POWER2 0x1a -#define WM8960_ADDCTL3 0x1b -#define WM8960_APOP1 0x1c -#define WM8960_APOP2 0x1d - -#define WM8960_LINPATH 0x20 -#define WM8960_RINPATH 0x21 -#define WM8960_LOUTMIX 0x22 - -#define WM8960_ROUTMIX 0x25 -#define WM8960_MONOMIX1 0x26 -#define WM8960_MONOMIX2 0x27 -#define WM8960_LOUT2 0x28 -#define WM8960_ROUT2 0x29 -#define WM8960_MONO 0x2a -#define WM8960_INBMIX1 0x2b -#define WM8960_INBMIX2 0x2c -#define WM8960_BYPASS1 0x2d -#define WM8960_BYPASS2 0x2e -#define WM8960_POWER3 0x2f -#define WM8960_ADDCTL4 0x30 -#define WM8960_CLASSD1 0x31 - -#define WM8960_CLASSD3 0x33 -#define WM8960_PLL1 0x34 -#define WM8960_PLL2 0x35 -#define WM8960_PLL3 0x36 -#define WM8960_PLL4 0x37 - - -/* - * WM8960 Clock dividers - */ -#define WM8960_SYSCLKDIV 0 -#define WM8960_DACDIV 1 -#define WM8960_OPCLKDIV 2 -#define WM8960_DCLKDIV 3 -#define WM8960_TOCLKSEL 4 -#define WM8960_SYSCLKSEL 5 - -#define WM8960_SYSCLK_DIV_1 (0 << 1) -#define WM8960_SYSCLK_DIV_2 (2 << 1) - -#define WM8960_SYSCLK_MCLK (0 << 0) -#define WM8960_SYSCLK_PLL (1 << 0) - -#define WM8960_DAC_DIV_1 (0 << 3) -#define WM8960_DAC_DIV_1_5 (1 << 3) -#define WM8960_DAC_DIV_2 (2 << 3) -#define WM8960_DAC_DIV_3 (3 << 3) -#define WM8960_DAC_DIV_4 (4 << 3) -#define WM8960_DAC_DIV_5_5 (5 << 3) -#define WM8960_DAC_DIV_6 (6 << 3) - -#define WM8960_DCLK_DIV_1_5 (0 << 6) -#define WM8960_DCLK_DIV_2 (1 << 6) -#define WM8960_DCLK_DIV_3 (2 << 6) -#define WM8960_DCLK_DIV_4 (3 << 6) -#define WM8960_DCLK_DIV_6 (4 << 6) -#define WM8960_DCLK_DIV_8 (5 << 6) -#define WM8960_DCLK_DIV_12 (6 << 6) -#define WM8960_DCLK_DIV_16 (7 << 6) - -#define WM8960_TOCLK_F19 (0 << 1) -#define WM8960_TOCLK_F21 (1 << 1) - -#define WM8960_OPCLK_DIV_1 (0 << 0) -#define WM8960_OPCLK_DIV_2 (1 << 0) -#define WM8960_OPCLK_DIV_3 (2 << 0) -#define WM8960_OPCLK_DIV_4 (3 << 0) -#define WM8960_OPCLK_DIV_5_5 (4 << 0) -#define WM8960_OPCLK_DIV_6 (5 << 0) - -extern struct snd_soc_dai wm8960_dai; -extern struct snd_soc_codec_device soc_codec_dev_wm8960; - -#define WM8960_DRES_400R 0 -#define WM8960_DRES_200R 1 -#define WM8960_DRES_600R 2 -#define WM8960_DRES_150R 3 -#define WM8960_DRES_MAX 3 - -struct wm8960_data { - int dres; -}; - -#endif diff --git a/trunk/sound/soc/codecs/wm8988.c b/trunk/sound/soc/codecs/wm8988.c deleted file mode 100644 index c05f71803aa8..000000000000 --- a/trunk/sound/soc/codecs/wm8988.c +++ /dev/null @@ -1,1097 +0,0 @@ -/* - * wm8988.c -- WM8988 ALSA SoC audio driver - * - * Copyright 2009 Wolfson Microelectronics plc - * Copyright 2005 Openedhand Ltd. - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "wm8988.h" - -/* - * wm8988 register cache - * We can't read the WM8988 register space when we - * are using 2 wire for device control, so we cache them instead. - */ -static const u16 wm8988_reg[] = { - 0x0097, 0x0097, 0x0079, 0x0079, /* 0 */ - 0x0000, 0x0008, 0x0000, 0x000a, /* 4 */ - 0x0000, 0x0000, 0x00ff, 0x00ff, /* 8 */ - 0x000f, 0x000f, 0x0000, 0x0000, /* 12 */ - 0x0000, 0x007b, 0x0000, 0x0032, /* 16 */ - 0x0000, 0x00c3, 0x00c3, 0x00c0, /* 20 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 24 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 28 */ - 0x0000, 0x0000, 0x0050, 0x0050, /* 32 */ - 0x0050, 0x0050, 0x0050, 0x0050, /* 36 */ - 0x0079, 0x0079, 0x0079, /* 40 */ -}; - -/* codec private data */ -struct wm8988_priv { - unsigned int sysclk; - struct snd_soc_codec codec; - struct snd_pcm_hw_constraint_list *sysclk_constraints; - u16 reg_cache[WM8988_NUM_REG]; -}; - - -/* - * read wm8988 register cache - */ -static inline unsigned int wm8988_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - if (reg > WM8988_NUM_REG) - return -1; - return cache[reg]; -} - -/* - * write wm8988 register cache - */ -static inline void wm8988_write_reg_cache(struct snd_soc_codec *codec, - unsigned int reg, unsigned int value) -{ - u16 *cache = codec->reg_cache; - if (reg > WM8988_NUM_REG) - return; - cache[reg] = value; -} - -static int wm8988_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[2]; - - /* data is - * D15..D9 WM8753 register offset - * D8...D0 register data - */ - data[0] = (reg << 1) | ((value >> 8) & 0x0001); - data[1] = value & 0x00ff; - - wm8988_write_reg_cache(codec, reg, value); - if (codec->hw_write(codec->control_data, data, 2) == 2) - return 0; - else - return -EIO; -} - -#define wm8988_reset(c) wm8988_write(c, WM8988_RESET, 0) - -/* - * WM8988 Controls - */ - -static const char *bass_boost_txt[] = {"Linear Control", "Adaptive Boost"}; -static const struct soc_enum bass_boost = - SOC_ENUM_SINGLE(WM8988_BASS, 7, 2, bass_boost_txt); - -static const char *bass_filter_txt[] = { "130Hz @ 48kHz", "200Hz @ 48kHz" }; -static const struct soc_enum bass_filter = - SOC_ENUM_SINGLE(WM8988_BASS, 6, 2, bass_filter_txt); - -static const char *treble_txt[] = {"8kHz", "4kHz"}; -static const struct soc_enum treble = - SOC_ENUM_SINGLE(WM8988_TREBLE, 6, 2, treble_txt); - -static const char *stereo_3d_lc_txt[] = {"200Hz", "500Hz"}; -static const struct soc_enum stereo_3d_lc = - SOC_ENUM_SINGLE(WM8988_3D, 5, 2, stereo_3d_lc_txt); - -static const char *stereo_3d_uc_txt[] = {"2.2kHz", "1.5kHz"}; -static const struct soc_enum stereo_3d_uc = - SOC_ENUM_SINGLE(WM8988_3D, 6, 2, stereo_3d_uc_txt); - -static const char *stereo_3d_func_txt[] = {"Capture", "Playback"}; -static const struct soc_enum stereo_3d_func = - SOC_ENUM_SINGLE(WM8988_3D, 7, 2, stereo_3d_func_txt); - -static const char *alc_func_txt[] = {"Off", "Right", "Left", "Stereo"}; -static const struct soc_enum alc_func = - SOC_ENUM_SINGLE(WM8988_ALC1, 7, 4, alc_func_txt); - -static const char *ng_type_txt[] = {"Constant PGA Gain", - "Mute ADC Output"}; -static const struct soc_enum ng_type = - SOC_ENUM_SINGLE(WM8988_NGATE, 1, 2, ng_type_txt); - -static const char *deemph_txt[] = {"None", "32Khz", "44.1Khz", "48Khz"}; -static const struct soc_enum deemph = - SOC_ENUM_SINGLE(WM8988_ADCDAC, 1, 4, deemph_txt); - -static const char *adcpol_txt[] = {"Normal", "L Invert", "R Invert", - "L + R Invert"}; -static const struct soc_enum adcpol = - SOC_ENUM_SINGLE(WM8988_ADCDAC, 5, 4, adcpol_txt); - -static const DECLARE_TLV_DB_SCALE(pga_tlv, -1725, 75, 0); -static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1); -static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); -static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1); -static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0); - -static const struct snd_kcontrol_new wm8988_snd_controls[] = { - -SOC_ENUM("Bass Boost", bass_boost), -SOC_ENUM("Bass Filter", bass_filter), -SOC_SINGLE("Bass Volume", WM8988_BASS, 0, 15, 1), - -SOC_SINGLE("Treble Volume", WM8988_TREBLE, 0, 15, 0), -SOC_ENUM("Treble Cut-off", treble), - -SOC_SINGLE("3D Switch", WM8988_3D, 0, 1, 0), -SOC_SINGLE("3D Volume", WM8988_3D, 1, 15, 0), -SOC_ENUM("3D Lower Cut-off", stereo_3d_lc), -SOC_ENUM("3D Upper Cut-off", stereo_3d_uc), -SOC_ENUM("3D Mode", stereo_3d_func), - -SOC_SINGLE("ALC Capture Target Volume", WM8988_ALC1, 0, 7, 0), -SOC_SINGLE("ALC Capture Max Volume", WM8988_ALC1, 4, 7, 0), -SOC_ENUM("ALC Capture Function", alc_func), -SOC_SINGLE("ALC Capture ZC Switch", WM8988_ALC2, 7, 1, 0), -SOC_SINGLE("ALC Capture Hold Time", WM8988_ALC2, 0, 15, 0), -SOC_SINGLE("ALC Capture Decay Time", WM8988_ALC3, 4, 15, 0), -SOC_SINGLE("ALC Capture Attack Time", WM8988_ALC3, 0, 15, 0), -SOC_SINGLE("ALC Capture NG Threshold", WM8988_NGATE, 3, 31, 0), -SOC_ENUM("ALC Capture NG Type", ng_type), -SOC_SINGLE("ALC Capture NG Switch", WM8988_NGATE, 0, 1, 0), - -SOC_SINGLE("ZC Timeout Switch", WM8988_ADCTL1, 0, 1, 0), - -SOC_DOUBLE_R_TLV("Capture Digital Volume", WM8988_LADC, WM8988_RADC, - 0, 255, 0, adc_tlv), -SOC_DOUBLE_R_TLV("Capture Volume", WM8988_LINVOL, WM8988_RINVOL, - 0, 63, 0, pga_tlv), -SOC_DOUBLE_R("Capture ZC Switch", WM8988_LINVOL, WM8988_RINVOL, 6, 1, 0), -SOC_DOUBLE_R("Capture Switch", WM8988_LINVOL, WM8988_RINVOL, 7, 1, 1), - -SOC_ENUM("Playback De-emphasis", deemph), - -SOC_ENUM("Capture Polarity", adcpol), -SOC_SINGLE("Playback 6dB Attenuate", WM8988_ADCDAC, 7, 1, 0), -SOC_SINGLE("Capture 6dB Attenuate", WM8988_ADCDAC, 8, 1, 0), - -SOC_DOUBLE_R_TLV("PCM Volume", WM8988_LDAC, WM8988_RDAC, 0, 255, 0, dac_tlv), - -SOC_SINGLE_TLV("Left Mixer Left Bypass Volume", WM8988_LOUTM1, 4, 7, 1, - bypass_tlv), -SOC_SINGLE_TLV("Left Mixer Right Bypass Volume", WM8988_LOUTM2, 4, 7, 1, - bypass_tlv), -SOC_SINGLE_TLV("Right Mixer Left Bypass Volume", WM8988_ROUTM1, 4, 7, 1, - bypass_tlv), -SOC_SINGLE_TLV("Right Mixer Right Bypass Volume", WM8988_ROUTM2, 4, 7, 1, - bypass_tlv), - -SOC_DOUBLE_R("Output 1 Playback ZC Switch", WM8988_LOUT1V, - WM8988_ROUT1V, 7, 1, 0), -SOC_DOUBLE_R_TLV("Output 1 Playback Volume", WM8988_LOUT1V, WM8988_ROUT1V, - 0, 127, 0, out_tlv), - -SOC_DOUBLE_R("Output 2 Playback ZC Switch", WM8988_LOUT2V, - WM8988_ROUT2V, 7, 1, 0), -SOC_DOUBLE_R_TLV("Output 2 Playback Volume", WM8988_LOUT2V, WM8988_ROUT2V, - 0, 127, 0, out_tlv), - -}; - -/* - * DAPM Controls - */ - -static int wm8988_lrc_control(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_codec *codec = w->codec; - u16 adctl2 = wm8988_read_reg_cache(codec, WM8988_ADCTL2); - - /* Use the DAC to gate LRC if active, otherwise use ADC */ - if (wm8988_read_reg_cache(codec, WM8988_PWR2) & 0x180) - adctl2 &= ~0x4; - else - adctl2 |= 0x4; - - return wm8988_write(codec, WM8988_ADCTL2, adctl2); -} - -static const char *wm8988_line_texts[] = { - "Line 1", "Line 2", "PGA", "Differential"}; - -static const unsigned int wm8988_line_values[] = { - 0, 1, 3, 4}; - -static const struct soc_enum wm8988_lline_enum = - SOC_VALUE_ENUM_SINGLE(WM8988_LOUTM1, 0, 7, - ARRAY_SIZE(wm8988_line_texts), - wm8988_line_texts, - wm8988_line_values); -static const struct snd_kcontrol_new wm8988_left_line_controls = - SOC_DAPM_VALUE_ENUM("Route", wm8988_lline_enum); - -static const struct soc_enum wm8988_rline_enum = - SOC_VALUE_ENUM_SINGLE(WM8988_ROUTM1, 0, 7, - ARRAY_SIZE(wm8988_line_texts), - wm8988_line_texts, - wm8988_line_values); -static const struct snd_kcontrol_new wm8988_right_line_controls = - SOC_DAPM_VALUE_ENUM("Route", wm8988_lline_enum); - -/* Left Mixer */ -static const struct snd_kcontrol_new wm8988_left_mixer_controls[] = { - SOC_DAPM_SINGLE("Playback Switch", WM8988_LOUTM1, 8, 1, 0), - SOC_DAPM_SINGLE("Left Bypass Switch", WM8988_LOUTM1, 7, 1, 0), - SOC_DAPM_SINGLE("Right Playback Switch", WM8988_LOUTM2, 8, 1, 0), - SOC_DAPM_SINGLE("Right Bypass Switch", WM8988_LOUTM2, 7, 1, 0), -}; - -/* Right Mixer */ -static const struct snd_kcontrol_new wm8988_right_mixer_controls[] = { - SOC_DAPM_SINGLE("Left Playback Switch", WM8988_ROUTM1, 8, 1, 0), - SOC_DAPM_SINGLE("Left Bypass Switch", WM8988_ROUTM1, 7, 1, 0), - SOC_DAPM_SINGLE("Playback Switch", WM8988_ROUTM2, 8, 1, 0), - SOC_DAPM_SINGLE("Right Bypass Switch", WM8988_ROUTM2, 7, 1, 0), -}; - -static const char *wm8988_pga_sel[] = {"Line 1", "Line 2", "Differential"}; -static const unsigned int wm8988_pga_val[] = { 0, 1, 3 }; - -/* Left PGA Mux */ -static const struct soc_enum wm8988_lpga_enum = - SOC_VALUE_ENUM_SINGLE(WM8988_LADCIN, 6, 3, - ARRAY_SIZE(wm8988_pga_sel), - wm8988_pga_sel, - wm8988_pga_val); -static const struct snd_kcontrol_new wm8988_left_pga_controls = - SOC_DAPM_VALUE_ENUM("Route", wm8988_lpga_enum); - -/* Right PGA Mux */ -static const struct soc_enum wm8988_rpga_enum = - SOC_VALUE_ENUM_SINGLE(WM8988_RADCIN, 6, 3, - ARRAY_SIZE(wm8988_pga_sel), - wm8988_pga_sel, - wm8988_pga_val); -static const struct snd_kcontrol_new wm8988_right_pga_controls = - SOC_DAPM_VALUE_ENUM("Route", wm8988_rpga_enum); - -/* Differential Mux */ -static const char *wm8988_diff_sel[] = {"Line 1", "Line 2"}; -static const struct soc_enum diffmux = - SOC_ENUM_SINGLE(WM8988_ADCIN, 8, 2, wm8988_diff_sel); -static const struct snd_kcontrol_new wm8988_diffmux_controls = - SOC_DAPM_ENUM("Route", diffmux); - -/* Mono ADC Mux */ -static const char *wm8988_mono_mux[] = {"Stereo", "Mono (Left)", - "Mono (Right)", "Digital Mono"}; -static const struct soc_enum monomux = - SOC_ENUM_SINGLE(WM8988_ADCIN, 6, 4, wm8988_mono_mux); -static const struct snd_kcontrol_new wm8988_monomux_controls = - SOC_DAPM_ENUM("Route", monomux); - -static const struct snd_soc_dapm_widget wm8988_dapm_widgets[] = { - SND_SOC_DAPM_MICBIAS("Mic Bias", WM8988_PWR1, 1, 0), - - SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0, - &wm8988_diffmux_controls), - SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0, - &wm8988_monomux_controls), - SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0, - &wm8988_monomux_controls), - - SND_SOC_DAPM_MUX("Left PGA Mux", WM8988_PWR1, 5, 0, - &wm8988_left_pga_controls), - SND_SOC_DAPM_MUX("Right PGA Mux", WM8988_PWR1, 4, 0, - &wm8988_right_pga_controls), - - SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0, - &wm8988_left_line_controls), - SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0, - &wm8988_right_line_controls), - - SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8988_PWR1, 2, 0), - SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8988_PWR1, 3, 0), - - SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8988_PWR2, 7, 0), - SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8988_PWR2, 8, 0), - - SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0, - &wm8988_left_mixer_controls[0], - ARRAY_SIZE(wm8988_left_mixer_controls)), - SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0, - &wm8988_right_mixer_controls[0], - ARRAY_SIZE(wm8988_right_mixer_controls)), - - SND_SOC_DAPM_PGA("Right Out 2", WM8988_PWR2, 3, 0, NULL, 0), - SND_SOC_DAPM_PGA("Left Out 2", WM8988_PWR2, 4, 0, NULL, 0), - SND_SOC_DAPM_PGA("Right Out 1", WM8988_PWR2, 5, 0, NULL, 0), - SND_SOC_DAPM_PGA("Left Out 1", WM8988_PWR2, 6, 0, NULL, 0), - - SND_SOC_DAPM_POST("LRC control", wm8988_lrc_control), - - SND_SOC_DAPM_OUTPUT("LOUT1"), - SND_SOC_DAPM_OUTPUT("ROUT1"), - SND_SOC_DAPM_OUTPUT("LOUT2"), - SND_SOC_DAPM_OUTPUT("ROUT2"), - SND_SOC_DAPM_OUTPUT("VREF"), - - SND_SOC_DAPM_INPUT("LINPUT1"), - SND_SOC_DAPM_INPUT("LINPUT2"), - SND_SOC_DAPM_INPUT("RINPUT1"), - SND_SOC_DAPM_INPUT("RINPUT2"), -}; - -static const struct snd_soc_dapm_route audio_map[] = { - - { "Left Line Mux", "Line 1", "LINPUT1" }, - { "Left Line Mux", "Line 2", "LINPUT2" }, - { "Left Line Mux", "PGA", "Left PGA Mux" }, - { "Left Line Mux", "Differential", "Differential Mux" }, - - { "Right Line Mux", "Line 1", "RINPUT1" }, - { "Right Line Mux", "Line 2", "RINPUT2" }, - { "Right Line Mux", "PGA", "Right PGA Mux" }, - { "Right Line Mux", "Differential", "Differential Mux" }, - - { "Left PGA Mux", "Line 1", "LINPUT1" }, - { "Left PGA Mux", "Line 2", "LINPUT2" }, - { "Left PGA Mux", "Differential", "Differential Mux" }, - - { "Right PGA Mux", "Line 1", "RINPUT1" }, - { "Right PGA Mux", "Line 2", "RINPUT2" }, - { "Right PGA Mux", "Differential", "Differential Mux" }, - - { "Differential Mux", "Line 1", "LINPUT1" }, - { "Differential Mux", "Line 1", "RINPUT1" }, - { "Differential Mux", "Line 2", "LINPUT2" }, - { "Differential Mux", "Line 2", "RINPUT2" }, - - { "Left ADC Mux", "Stereo", "Left PGA Mux" }, - { "Left ADC Mux", "Mono (Left)", "Left PGA Mux" }, - { "Left ADC Mux", "Digital Mono", "Left PGA Mux" }, - - { "Right ADC Mux", "Stereo", "Right PGA Mux" }, - { "Right ADC Mux", "Mono (Right)", "Right PGA Mux" }, - { "Right ADC Mux", "Digital Mono", "Right PGA Mux" }, - - { "Left ADC", NULL, "Left ADC Mux" }, - { "Right ADC", NULL, "Right ADC Mux" }, - - { "Left Line Mux", "Line 1", "LINPUT1" }, - { "Left Line Mux", "Line 2", "LINPUT2" }, - { "Left Line Mux", "PGA", "Left PGA Mux" }, - { "Left Line Mux", "Differential", "Differential Mux" }, - - { "Right Line Mux", "Line 1", "RINPUT1" }, - { "Right Line Mux", "Line 2", "RINPUT2" }, - { "Right Line Mux", "PGA", "Right PGA Mux" }, - { "Right Line Mux", "Differential", "Differential Mux" }, - - { "Left Mixer", "Playback Switch", "Left DAC" }, - { "Left Mixer", "Left Bypass Switch", "Left Line Mux" }, - { "Left Mixer", "Right Playback Switch", "Right DAC" }, - { "Left Mixer", "Right Bypass Switch", "Right Line Mux" }, - - { "Right Mixer", "Left Playback Switch", "Left DAC" }, - { "Right Mixer", "Left Bypass Switch", "Left Line Mux" }, - { "Right Mixer", "Playback Switch", "Right DAC" }, - { "Right Mixer", "Right Bypass Switch", "Right Line Mux" }, - - { "Left Out 1", NULL, "Left Mixer" }, - { "LOUT1", NULL, "Left Out 1" }, - { "Right Out 1", NULL, "Right Mixer" }, - { "ROUT1", NULL, "Right Out 1" }, - - { "Left Out 2", NULL, "Left Mixer" }, - { "LOUT2", NULL, "Left Out 2" }, - { "Right Out 2", NULL, "Right Mixer" }, - { "ROUT2", NULL, "Right Out 2" }, -}; - -struct _coeff_div { - u32 mclk; - u32 rate; - u16 fs; - u8 sr:5; - u8 usb:1; -}; - -/* codec hifi mclk clock divider coefficients */ -static const struct _coeff_div coeff_div[] = { - /* 8k */ - {12288000, 8000, 1536, 0x6, 0x0}, - {11289600, 8000, 1408, 0x16, 0x0}, - {18432000, 8000, 2304, 0x7, 0x0}, - {16934400, 8000, 2112, 0x17, 0x0}, - {12000000, 8000, 1500, 0x6, 0x1}, - - /* 11.025k */ - {11289600, 11025, 1024, 0x18, 0x0}, - {16934400, 11025, 1536, 0x19, 0x0}, - {12000000, 11025, 1088, 0x19, 0x1}, - - /* 16k */ - {12288000, 16000, 768, 0xa, 0x0}, - {18432000, 16000, 1152, 0xb, 0x0}, - {12000000, 16000, 750, 0xa, 0x1}, - - /* 22.05k */ - {11289600, 22050, 512, 0x1a, 0x0}, - {16934400, 22050, 768, 0x1b, 0x0}, - {12000000, 22050, 544, 0x1b, 0x1}, - - /* 32k */ - {12288000, 32000, 384, 0xc, 0x0}, - {18432000, 32000, 576, 0xd, 0x0}, - {12000000, 32000, 375, 0xa, 0x1}, - - /* 44.1k */ - {11289600, 44100, 256, 0x10, 0x0}, - {16934400, 44100, 384, 0x11, 0x0}, - {12000000, 44100, 272, 0x11, 0x1}, - - /* 48k */ - {12288000, 48000, 256, 0x0, 0x0}, - {18432000, 48000, 384, 0x1, 0x0}, - {12000000, 48000, 250, 0x0, 0x1}, - - /* 88.2k */ - {11289600, 88200, 128, 0x1e, 0x0}, - {16934400, 88200, 192, 0x1f, 0x0}, - {12000000, 88200, 136, 0x1f, 0x1}, - - /* 96k */ - {12288000, 96000, 128, 0xe, 0x0}, - {18432000, 96000, 192, 0xf, 0x0}, - {12000000, 96000, 125, 0xe, 0x1}, -}; - -static inline int get_coeff(int mclk, int rate) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { - if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) - return i; - } - - return -EINVAL; -} - -/* The set of rates we can generate from the above for each SYSCLK */ - -static unsigned int rates_12288[] = { - 8000, 12000, 16000, 24000, 24000, 32000, 48000, 96000, -}; - -static struct snd_pcm_hw_constraint_list constraints_12288 = { - .count = ARRAY_SIZE(rates_12288), - .list = rates_12288, -}; - -static unsigned int rates_112896[] = { - 8000, 11025, 22050, 44100, -}; - -static struct snd_pcm_hw_constraint_list constraints_112896 = { - .count = ARRAY_SIZE(rates_112896), - .list = rates_112896, -}; - -static unsigned int rates_12[] = { - 8000, 11025, 12000, 16000, 22050, 2400, 32000, 41100, 48000, - 48000, 88235, 96000, -}; - -static struct snd_pcm_hw_constraint_list constraints_12 = { - .count = ARRAY_SIZE(rates_12), - .list = rates_12, -}; - -/* - * Note that this should be called from init rather than from hw_params. - */ -static int wm8988_set_dai_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir) -{ - struct snd_soc_codec *codec = codec_dai->codec; - struct wm8988_priv *wm8988 = codec->private_data; - - switch (freq) { - case 11289600: - case 18432000: - case 22579200: - case 36864000: - wm8988->sysclk_constraints = &constraints_112896; - wm8988->sysclk = freq; - return 0; - - case 12288000: - case 16934400: - case 24576000: - case 33868800: - wm8988->sysclk_constraints = &constraints_12288; - wm8988->sysclk = freq; - return 0; - - case 12000000: - case 24000000: - wm8988->sysclk_constraints = &constraints_12; - wm8988->sysclk = freq; - return 0; - } - return -EINVAL; -} - -static int wm8988_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) -{ - struct snd_soc_codec *codec = codec_dai->codec; - u16 iface = 0; - - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - iface = 0x0040; - break; - case SND_SOC_DAIFMT_CBS_CFS: - break; - default: - return -EINVAL; - } - - /* interface format */ - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - iface |= 0x0002; - break; - case SND_SOC_DAIFMT_RIGHT_J: - break; - case SND_SOC_DAIFMT_LEFT_J: - iface |= 0x0001; - break; - case SND_SOC_DAIFMT_DSP_A: - iface |= 0x0003; - break; - case SND_SOC_DAIFMT_DSP_B: - iface |= 0x0013; - break; - default: - return -EINVAL; - } - - /* clock inversion */ - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - break; - case SND_SOC_DAIFMT_IB_IF: - iface |= 0x0090; - break; - case SND_SOC_DAIFMT_IB_NF: - iface |= 0x0080; - break; - case SND_SOC_DAIFMT_NB_IF: - iface |= 0x0010; - break; - default: - return -EINVAL; - } - - wm8988_write(codec, WM8988_IFACE, iface); - return 0; -} - -static int wm8988_pcm_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_codec *codec = dai->codec; - struct wm8988_priv *wm8988 = codec->private_data; - - /* The set of sample rates that can be supported depends on the - * MCLK supplied to the CODEC - enforce this. - */ - if (!wm8988->sysclk) { - dev_err(codec->dev, - "No MCLK configured, call set_sysclk() on init\n"); - return -EINVAL; - } - - snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - wm8988->sysclk_constraints); - - return 0; -} - -static int wm8988_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->card->codec; - struct wm8988_priv *wm8988 = codec->private_data; - u16 iface = wm8988_read_reg_cache(codec, WM8988_IFACE) & 0x1f3; - u16 srate = wm8988_read_reg_cache(codec, WM8988_SRATE) & 0x180; - int coeff; - - coeff = get_coeff(wm8988->sysclk, params_rate(params)); - if (coeff < 0) { - coeff = get_coeff(wm8988->sysclk / 2, params_rate(params)); - srate |= 0x40; - } - if (coeff < 0) { - dev_err(codec->dev, - "Unable to configure sample rate %dHz with %dHz MCLK\n", - params_rate(params), wm8988->sysclk); - return coeff; - } - - /* bit size */ - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - break; - case SNDRV_PCM_FORMAT_S20_3LE: - iface |= 0x0004; - break; - case SNDRV_PCM_FORMAT_S24_LE: - iface |= 0x0008; - break; - case SNDRV_PCM_FORMAT_S32_LE: - iface |= 0x000c; - break; - } - - /* set iface & srate */ - wm8988_write(codec, WM8988_IFACE, iface); - if (coeff >= 0) - wm8988_write(codec, WM8988_SRATE, srate | - (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb); - - return 0; -} - -static int wm8988_mute(struct snd_soc_dai *dai, int mute) -{ - struct snd_soc_codec *codec = dai->codec; - u16 mute_reg = wm8988_read_reg_cache(codec, WM8988_ADCDAC) & 0xfff7; - - if (mute) - wm8988_write(codec, WM8988_ADCDAC, mute_reg | 0x8); - else - wm8988_write(codec, WM8988_ADCDAC, mute_reg); - return 0; -} - -static int wm8988_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - u16 pwr_reg = wm8988_read_reg_cache(codec, WM8988_PWR1) & ~0x1c1; - - switch (level) { - case SND_SOC_BIAS_ON: - break; - - case SND_SOC_BIAS_PREPARE: - /* VREF, VMID=2x50k, digital enabled */ - wm8988_write(codec, WM8988_PWR1, pwr_reg | 0x00c0); - break; - - case SND_SOC_BIAS_STANDBY: - if (codec->bias_level == SND_SOC_BIAS_OFF) { - /* VREF, VMID=2x5k */ - wm8988_write(codec, WM8988_PWR1, pwr_reg | 0x1c1); - - /* Charge caps */ - msleep(100); - } - - /* VREF, VMID=2*500k, digital stopped */ - wm8988_write(codec, WM8988_PWR1, pwr_reg | 0x0141); - break; - - case SND_SOC_BIAS_OFF: - wm8988_write(codec, WM8988_PWR1, 0x0000); - break; - } - codec->bias_level = level; - return 0; -} - -#define WM8988_RATES SNDRV_PCM_RATE_8000_96000 - -#define WM8988_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ - SNDRV_PCM_FMTBIT_S24_LE) - -static struct snd_soc_dai_ops wm8988_ops = { - .startup = wm8988_pcm_startup, - .hw_params = wm8988_pcm_hw_params, - .set_fmt = wm8988_set_dai_fmt, - .set_sysclk = wm8988_set_dai_sysclk, - .digital_mute = wm8988_mute, -}; - -struct snd_soc_dai wm8988_dai = { - .name = "WM8988", - .playback = { - .stream_name = "Playback", - .channels_min = 1, - .channels_max = 2, - .rates = WM8988_RATES, - .formats = WM8988_FORMATS, - }, - .capture = { - .stream_name = "Capture", - .channels_min = 1, - .channels_max = 2, - .rates = WM8988_RATES, - .formats = WM8988_FORMATS, - }, - .ops = &wm8988_ops, - .symmetric_rates = 1, -}; -EXPORT_SYMBOL_GPL(wm8988_dai); - -static int wm8988_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; - - wm8988_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8988_resume(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; - int i; - u8 data[2]; - u16 *cache = codec->reg_cache; - - /* Sync reg_cache with the hardware */ - for (i = 0; i < WM8988_NUM_REG; i++) { - if (i == WM8988_RESET) - continue; - data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); - data[1] = cache[i] & 0x00ff; - codec->hw_write(codec->control_data, data, 2); - } - - wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} - -static struct snd_soc_codec *wm8988_codec; - -static int wm8988_probe(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec; - int ret = 0; - - if (wm8988_codec == NULL) { - dev_err(&pdev->dev, "Codec device not registered\n"); - return -ENODEV; - } - - socdev->card->codec = wm8988_codec; - codec = wm8988_codec; - - /* register pcms */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - dev_err(codec->dev, "failed to create pcms: %d\n", ret); - goto pcm_err; - } - - snd_soc_add_controls(codec, wm8988_snd_controls, - ARRAY_SIZE(wm8988_snd_controls)); - snd_soc_dapm_new_controls(codec, wm8988_dapm_widgets, - ARRAY_SIZE(wm8988_dapm_widgets)); - snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - snd_soc_dapm_new_widgets(codec); - - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(codec->dev, "failed to register card: %d\n", ret); - goto card_err; - } - - return ret; - -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -pcm_err: - return ret; -} - -static int wm8988_remove(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); - - return 0; -} - -struct snd_soc_codec_device soc_codec_dev_wm8988 = { - .probe = wm8988_probe, - .remove = wm8988_remove, - .suspend = wm8988_suspend, - .resume = wm8988_resume, -}; -EXPORT_SYMBOL_GPL(soc_codec_dev_wm8988); - -static int wm8988_register(struct wm8988_priv *wm8988) -{ - struct snd_soc_codec *codec = &wm8988->codec; - int ret; - u16 reg; - - if (wm8988_codec) { - dev_err(codec->dev, "Another WM8988 is registered\n"); - ret = -EINVAL; - goto err; - } - - mutex_init(&codec->mutex); - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); - - codec->private_data = wm8988; - codec->name = "WM8988"; - codec->owner = THIS_MODULE; - codec->read = wm8988_read_reg_cache; - codec->write = wm8988_write; - codec->dai = &wm8988_dai; - codec->num_dai = 1; - codec->reg_cache_size = ARRAY_SIZE(wm8988->reg_cache); - codec->reg_cache = &wm8988->reg_cache; - codec->bias_level = SND_SOC_BIAS_OFF; - codec->set_bias_level = wm8988_set_bias_level; - - memcpy(codec->reg_cache, wm8988_reg, - sizeof(wm8988_reg)); - - ret = wm8988_reset(codec); - if (ret < 0) { - dev_err(codec->dev, "Failed to issue reset\n"); - return ret; - } - - /* set the update bits (we always update left then right) */ - reg = wm8988_read_reg_cache(codec, WM8988_RADC); - wm8988_write(codec, WM8988_RADC, reg | 0x100); - reg = wm8988_read_reg_cache(codec, WM8988_RDAC); - wm8988_write(codec, WM8988_RDAC, reg | 0x0100); - reg = wm8988_read_reg_cache(codec, WM8988_ROUT1V); - wm8988_write(codec, WM8988_ROUT1V, reg | 0x0100); - reg = wm8988_read_reg_cache(codec, WM8988_ROUT2V); - wm8988_write(codec, WM8988_ROUT2V, reg | 0x0100); - reg = wm8988_read_reg_cache(codec, WM8988_RINVOL); - wm8988_write(codec, WM8988_RINVOL, reg | 0x0100); - - wm8988_set_bias_level(&wm8988->codec, SND_SOC_BIAS_STANDBY); - - wm8988_dai.dev = codec->dev; - - wm8988_codec = codec; - - ret = snd_soc_register_codec(codec); - if (ret != 0) { - dev_err(codec->dev, "Failed to register codec: %d\n", ret); - return ret; - } - - ret = snd_soc_register_dai(&wm8988_dai); - if (ret != 0) { - dev_err(codec->dev, "Failed to register DAI: %d\n", ret); - snd_soc_unregister_codec(codec); - return ret; - } - - return 0; - -err: - kfree(wm8988); - return ret; -} - -static void wm8988_unregister(struct wm8988_priv *wm8988) -{ - wm8988_set_bias_level(&wm8988->codec, SND_SOC_BIAS_OFF); - snd_soc_unregister_dai(&wm8988_dai); - snd_soc_unregister_codec(&wm8988->codec); - kfree(wm8988); - wm8988_codec = NULL; -} - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static int wm8988_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - struct wm8988_priv *wm8988; - struct snd_soc_codec *codec; - - wm8988 = kzalloc(sizeof(struct wm8988_priv), GFP_KERNEL); - if (wm8988 == NULL) - return -ENOMEM; - - codec = &wm8988->codec; - codec->hw_write = (hw_write_t)i2c_master_send; - - i2c_set_clientdata(i2c, wm8988); - codec->control_data = i2c; - - codec->dev = &i2c->dev; - - return wm8988_register(wm8988); -} - -static int wm8988_i2c_remove(struct i2c_client *client) -{ - struct wm8988_priv *wm8988 = i2c_get_clientdata(client); - wm8988_unregister(wm8988); - return 0; -} - -static const struct i2c_device_id wm8988_i2c_id[] = { - { "wm8988", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wm8988_i2c_id); - -static struct i2c_driver wm8988_i2c_driver = { - .driver = { - .name = "WM8988", - .owner = THIS_MODULE, - }, - .probe = wm8988_i2c_probe, - .remove = wm8988_i2c_remove, - .id_table = wm8988_i2c_id, -}; -#endif - -#if defined(CONFIG_SPI_MASTER) -static int wm8988_spi_write(struct spi_device *spi, const char *data, int len) -{ - struct spi_transfer t; - struct spi_message m; - u8 msg[2]; - - if (len <= 0) - return 0; - - msg[0] = data[0]; - msg[1] = data[1]; - - spi_message_init(&m); - memset(&t, 0, (sizeof t)); - - t.tx_buf = &msg[0]; - t.len = len; - - spi_message_add_tail(&t, &m); - spi_sync(spi, &m); - - return len; -} - -static int __devinit wm8988_spi_probe(struct spi_device *spi) -{ - struct wm8988_priv *wm8988; - struct snd_soc_codec *codec; - - wm8988 = kzalloc(sizeof(struct wm8988_priv), GFP_KERNEL); - if (wm8988 == NULL) - return -ENOMEM; - - codec = &wm8988->codec; - codec->hw_write = (hw_write_t)wm8988_spi_write; - codec->control_data = spi; - codec->dev = &spi->dev; - - spi->dev.driver_data = wm8988; - - return wm8988_register(wm8988); -} - -static int __devexit wm8988_spi_remove(struct spi_device *spi) -{ - struct wm8988_priv *wm8988 = spi->dev.driver_data; - - wm8988_unregister(wm8988); - - return 0; -} - -static struct spi_driver wm8988_spi_driver = { - .driver = { - .name = "wm8988", - .bus = &spi_bus_type, - .owner = THIS_MODULE, - }, - .probe = wm8988_spi_probe, - .remove = __devexit_p(wm8988_spi_remove), -}; -#endif - -static int __init wm8988_modinit(void) -{ - int ret; - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - ret = i2c_add_driver(&wm8988_i2c_driver); - if (ret != 0) - pr_err("WM8988: Unable to register I2C driver: %d\n", ret); -#endif -#if defined(CONFIG_SPI_MASTER) - ret = spi_register_driver(&wm8988_spi_driver); - if (ret != 0) - pr_err("WM8988: Unable to register SPI driver: %d\n", ret); -#endif - return ret; -} -module_init(wm8988_modinit); - -static void __exit wm8988_exit(void) -{ -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_del_driver(&wm8988_i2c_driver); -#endif -#if defined(CONFIG_SPI_MASTER) - spi_unregister_driver(&wm8988_spi_driver); -#endif -} -module_exit(wm8988_exit); - - -MODULE_DESCRIPTION("ASoC WM8988 driver"); -MODULE_AUTHOR("Mark Brown "); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/codecs/wm8988.h b/trunk/sound/soc/codecs/wm8988.h deleted file mode 100644 index 4552d37fdd41..000000000000 --- a/trunk/sound/soc/codecs/wm8988.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2005 Openedhand Ltd. - * - * Author: Richard Purdie - * - * Based on WM8753.h - * - * 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. - * - */ - -#ifndef _WM8988_H -#define _WM8988_H - -/* WM8988 register space */ - -#define WM8988_LINVOL 0x00 -#define WM8988_RINVOL 0x01 -#define WM8988_LOUT1V 0x02 -#define WM8988_ROUT1V 0x03 -#define WM8988_ADCDAC 0x05 -#define WM8988_IFACE 0x07 -#define WM8988_SRATE 0x08 -#define WM8988_LDAC 0x0a -#define WM8988_RDAC 0x0b -#define WM8988_BASS 0x0c -#define WM8988_TREBLE 0x0d -#define WM8988_RESET 0x0f -#define WM8988_3D 0x10 -#define WM8988_ALC1 0x11 -#define WM8988_ALC2 0x12 -#define WM8988_ALC3 0x13 -#define WM8988_NGATE 0x14 -#define WM8988_LADC 0x15 -#define WM8988_RADC 0x16 -#define WM8988_ADCTL1 0x17 -#define WM8988_ADCTL2 0x18 -#define WM8988_PWR1 0x19 -#define WM8988_PWR2 0x1a -#define WM8988_ADCTL3 0x1b -#define WM8988_ADCIN 0x1f -#define WM8988_LADCIN 0x20 -#define WM8988_RADCIN 0x21 -#define WM8988_LOUTM1 0x22 -#define WM8988_LOUTM2 0x23 -#define WM8988_ROUTM1 0x24 -#define WM8988_ROUTM2 0x25 -#define WM8988_LOUT2V 0x28 -#define WM8988_ROUT2V 0x29 -#define WM8988_LPPB 0x43 -#define WM8988_NUM_REG 0x44 - -#define WM8988_SYSCLK 0 - -extern struct snd_soc_dai wm8988_dai; -extern struct snd_soc_codec_device soc_codec_dev_wm8988; - -#endif diff --git a/trunk/sound/soc/codecs/wm8990.c b/trunk/sound/soc/codecs/wm8990.c index d029818350e9..40cd274eb1ef 100644 --- a/trunk/sound/soc/codecs/wm8990.c +++ b/trunk/sound/soc/codecs/wm8990.c @@ -998,7 +998,7 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int target, if ((Ndiv < 6) || (Ndiv > 12)) printk(KERN_WARNING - "WM8990 N value outwith recommended range! N = %u\n", Ndiv); + "WM8990 N value outwith recommended range! N = %d\n", Ndiv); pll_div->n = Ndiv; Nmod = target % source; diff --git a/trunk/sound/soc/codecs/wm9081.c b/trunk/sound/soc/codecs/wm9081.c deleted file mode 100644 index 86fc57e25f97..000000000000 --- a/trunk/sound/soc/codecs/wm9081.c +++ /dev/null @@ -1,1534 +0,0 @@ -/* - * wm9081.c -- WM9081 ALSA SoC Audio driver - * - * Author: Mark Brown - * - * Copyright 2009 Wolfson Microelectronics plc - * - * 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "wm9081.h" - -static u16 wm9081_reg_defaults[] = { - 0x0000, /* R0 - Software Reset */ - 0x0000, /* R1 */ - 0x00B9, /* R2 - Analogue Lineout */ - 0x00B9, /* R3 - Analogue Speaker PGA */ - 0x0001, /* R4 - VMID Control */ - 0x0068, /* R5 - Bias Control 1 */ - 0x0000, /* R6 */ - 0x0000, /* R7 - Analogue Mixer */ - 0x0000, /* R8 - Anti Pop Control */ - 0x01DB, /* R9 - Analogue Speaker 1 */ - 0x0018, /* R10 - Analogue Speaker 2 */ - 0x0180, /* R11 - Power Management */ - 0x0000, /* R12 - Clock Control 1 */ - 0x0038, /* R13 - Clock Control 2 */ - 0x4000, /* R14 - Clock Control 3 */ - 0x0000, /* R15 */ - 0x0000, /* R16 - FLL Control 1 */ - 0x0200, /* R17 - FLL Control 2 */ - 0x0000, /* R18 - FLL Control 3 */ - 0x0204, /* R19 - FLL Control 4 */ - 0x0000, /* R20 - FLL Control 5 */ - 0x0000, /* R21 */ - 0x0000, /* R22 - Audio Interface 1 */ - 0x0002, /* R23 - Audio Interface 2 */ - 0x0008, /* R24 - Audio Interface 3 */ - 0x0022, /* R25 - Audio Interface 4 */ - 0x0000, /* R26 - Interrupt Status */ - 0x0006, /* R27 - Interrupt Status Mask */ - 0x0000, /* R28 - Interrupt Polarity */ - 0x0000, /* R29 - Interrupt Control */ - 0x00C0, /* R30 - DAC Digital 1 */ - 0x0008, /* R31 - DAC Digital 2 */ - 0x09AF, /* R32 - DRC 1 */ - 0x4201, /* R33 - DRC 2 */ - 0x0000, /* R34 - DRC 3 */ - 0x0000, /* R35 - DRC 4 */ - 0x0000, /* R36 */ - 0x0000, /* R37 */ - 0x0000, /* R38 - Write Sequencer 1 */ - 0x0000, /* R39 - Write Sequencer 2 */ - 0x0002, /* R40 - MW Slave 1 */ - 0x0000, /* R41 */ - 0x0000, /* R42 - EQ 1 */ - 0x0000, /* R43 - EQ 2 */ - 0x0FCA, /* R44 - EQ 3 */ - 0x0400, /* R45 - EQ 4 */ - 0x00B8, /* R46 - EQ 5 */ - 0x1EB5, /* R47 - EQ 6 */ - 0xF145, /* R48 - EQ 7 */ - 0x0B75, /* R49 - EQ 8 */ - 0x01C5, /* R50 - EQ 9 */ - 0x169E, /* R51 - EQ 10 */ - 0xF829, /* R52 - EQ 11 */ - 0x07AD, /* R53 - EQ 12 */ - 0x1103, /* R54 - EQ 13 */ - 0x1C58, /* R55 - EQ 14 */ - 0xF373, /* R56 - EQ 15 */ - 0x0A54, /* R57 - EQ 16 */ - 0x0558, /* R58 - EQ 17 */ - 0x0564, /* R59 - EQ 18 */ - 0x0559, /* R60 - EQ 19 */ - 0x4000, /* R61 - EQ 20 */ -}; - -static struct { - int ratio; - int clk_sys_rate; -} clk_sys_rates[] = { - { 64, 0 }, - { 128, 1 }, - { 192, 2 }, - { 256, 3 }, - { 384, 4 }, - { 512, 5 }, - { 768, 6 }, - { 1024, 7 }, - { 1408, 8 }, - { 1536, 9 }, -}; - -static struct { - int rate; - int sample_rate; -} sample_rates[] = { - { 8000, 0 }, - { 11025, 1 }, - { 12000, 2 }, - { 16000, 3 }, - { 22050, 4 }, - { 24000, 5 }, - { 32000, 6 }, - { 44100, 7 }, - { 48000, 8 }, - { 88200, 9 }, - { 96000, 10 }, -}; - -static struct { - int div; /* *10 due to .5s */ - int bclk_div; -} bclk_divs[] = { - { 10, 0 }, - { 15, 1 }, - { 20, 2 }, - { 30, 3 }, - { 40, 4 }, - { 50, 5 }, - { 55, 6 }, - { 60, 7 }, - { 80, 8 }, - { 100, 9 }, - { 110, 10 }, - { 120, 11 }, - { 160, 12 }, - { 200, 13 }, - { 220, 14 }, - { 240, 15 }, - { 250, 16 }, - { 300, 17 }, - { 320, 18 }, - { 440, 19 }, - { 480, 20 }, -}; - -struct wm9081_priv { - struct snd_soc_codec codec; - u16 reg_cache[WM9081_MAX_REGISTER + 1]; - int sysclk_source; - int mclk_rate; - int sysclk_rate; - int fs; - int bclk; - int master; - int fll_fref; - int fll_fout; - struct wm9081_retune_mobile_config *retune; -}; - -static int wm9081_reg_is_volatile(int reg) -{ - switch (reg) { - default: - return 0; - } -} - -static unsigned int wm9081_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - BUG_ON(reg > WM9081_MAX_REGISTER); - return cache[reg]; -} - -static unsigned int wm9081_read_hw(struct snd_soc_codec *codec, u8 reg) -{ - struct i2c_msg xfer[2]; - u16 data; - int ret; - struct i2c_client *client = codec->control_data; - - BUG_ON(reg > WM9081_MAX_REGISTER); - - /* Write register */ - xfer[0].addr = client->addr; - xfer[0].flags = 0; - xfer[0].len = 1; - xfer[0].buf = ® - - /* Read data */ - xfer[1].addr = client->addr; - xfer[1].flags = I2C_M_RD; - xfer[1].len = 2; - xfer[1].buf = (u8 *)&data; - - ret = i2c_transfer(client->adapter, xfer, 2); - if (ret != 2) { - dev_err(&client->dev, "i2c_transfer() returned %d\n", ret); - return 0; - } - - return (data >> 8) | ((data & 0xff) << 8); -} - -static unsigned int wm9081_read(struct snd_soc_codec *codec, unsigned int reg) -{ - if (wm9081_reg_is_volatile(reg)) - return wm9081_read_hw(codec, reg); - else - return wm9081_read_reg_cache(codec, reg); -} - -static int wm9081_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u16 *cache = codec->reg_cache; - u8 data[3]; - - BUG_ON(reg > WM9081_MAX_REGISTER); - - if (!wm9081_reg_is_volatile(reg)) - cache[reg] = value; - - data[0] = reg; - data[1] = value >> 8; - data[2] = value & 0x00ff; - - if (codec->hw_write(codec->control_data, data, 3) == 3) - return 0; - else - return -EIO; -} - -static int wm9081_reset(struct snd_soc_codec *codec) -{ - return wm9081_write(codec, WM9081_SOFTWARE_RESET, 0); -} - -static const DECLARE_TLV_DB_SCALE(drc_in_tlv, -4500, 75, 0); -static const DECLARE_TLV_DB_SCALE(drc_out_tlv, -2250, 75, 0); -static const DECLARE_TLV_DB_SCALE(drc_min_tlv, -1800, 600, 0); -static unsigned int drc_max_tlv[] = { - TLV_DB_RANGE_HEAD(4), - 0, 0, TLV_DB_SCALE_ITEM(1200, 0, 0), - 1, 1, TLV_DB_SCALE_ITEM(1800, 0, 0), - 2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0), - 3, 3, TLV_DB_SCALE_ITEM(3600, 0, 0), -}; -static const DECLARE_TLV_DB_SCALE(drc_qr_tlv, 1200, 600, 0); -static const DECLARE_TLV_DB_SCALE(drc_startup_tlv, -300, 50, 0); - -static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); - -static const DECLARE_TLV_DB_SCALE(in_tlv, -600, 600, 0); -static const DECLARE_TLV_DB_SCALE(dac_tlv, -7200, 75, 1); -static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0); - -static const char *drc_high_text[] = { - "1", - "1/2", - "1/4", - "1/8", - "1/16", - "0", -}; - -static const struct soc_enum drc_high = - SOC_ENUM_SINGLE(WM9081_DRC_3, 3, 6, drc_high_text); - -static const char *drc_low_text[] = { - "1", - "1/2", - "1/4", - "1/8", - "0", -}; - -static const struct soc_enum drc_low = - SOC_ENUM_SINGLE(WM9081_DRC_3, 0, 5, drc_low_text); - -static const char *drc_atk_text[] = { - "181us", - "181us", - "363us", - "726us", - "1.45ms", - "2.9ms", - "5.8ms", - "11.6ms", - "23.2ms", - "46.4ms", - "92.8ms", - "185.6ms", -}; - -static const struct soc_enum drc_atk = - SOC_ENUM_SINGLE(WM9081_DRC_2, 12, 12, drc_atk_text); - -static const char *drc_dcy_text[] = { - "186ms", - "372ms", - "743ms", - "1.49s", - "2.97s", - "5.94s", - "11.89s", - "23.78s", - "47.56s", -}; - -static const struct soc_enum drc_dcy = - SOC_ENUM_SINGLE(WM9081_DRC_2, 8, 9, drc_dcy_text); - -static const char *drc_qr_dcy_text[] = { - "0.725ms", - "1.45ms", - "5.8ms", -}; - -static const struct soc_enum drc_qr_dcy = - SOC_ENUM_SINGLE(WM9081_DRC_2, 4, 3, drc_qr_dcy_text); - -static const char *dac_deemph_text[] = { - "None", - "32kHz", - "44.1kHz", - "48kHz", -}; - -static const struct soc_enum dac_deemph = - SOC_ENUM_SINGLE(WM9081_DAC_DIGITAL_2, 1, 4, dac_deemph_text); - -static const char *speaker_mode_text[] = { - "Class D", - "Class AB", -}; - -static const struct soc_enum speaker_mode = - SOC_ENUM_SINGLE(WM9081_ANALOGUE_SPEAKER_2, 6, 2, speaker_mode_text); - -static int speaker_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int reg; - - reg = wm9081_read(codec, WM9081_ANALOGUE_SPEAKER_2); - if (reg & WM9081_SPK_MODE) - ucontrol->value.integer.value[0] = 1; - else - ucontrol->value.integer.value[0] = 0; - - return 0; -} - -/* - * Stop any attempts to change speaker mode while the speaker is enabled. - * - * We also have some special anti-pop controls dependant on speaker - * mode which must be changed along with the mode. - */ -static int speaker_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int reg_pwr = wm9081_read(codec, WM9081_POWER_MANAGEMENT); - unsigned int reg2 = wm9081_read(codec, WM9081_ANALOGUE_SPEAKER_2); - - /* Are we changing anything? */ - if (ucontrol->value.integer.value[0] == - ((reg2 & WM9081_SPK_MODE) != 0)) - return 0; - - /* Don't try to change modes while enabled */ - if (reg_pwr & WM9081_SPK_ENA) - return -EINVAL; - - if (ucontrol->value.integer.value[0]) { - /* Class AB */ - reg2 &= ~(WM9081_SPK_INV_MUTE | WM9081_OUT_SPK_CTRL); - reg2 |= WM9081_SPK_MODE; - } else { - /* Class D */ - reg2 |= WM9081_SPK_INV_MUTE | WM9081_OUT_SPK_CTRL; - reg2 &= ~WM9081_SPK_MODE; - } - - wm9081_write(codec, WM9081_ANALOGUE_SPEAKER_2, reg2); - - return 0; -} - -static const struct snd_kcontrol_new wm9081_snd_controls[] = { -SOC_SINGLE_TLV("IN1 Volume", WM9081_ANALOGUE_MIXER, 1, 1, 1, in_tlv), -SOC_SINGLE_TLV("IN2 Volume", WM9081_ANALOGUE_MIXER, 3, 1, 1, in_tlv), - -SOC_SINGLE_TLV("Playback Volume", WM9081_DAC_DIGITAL_1, 1, 96, 0, dac_tlv), - -SOC_SINGLE("LINEOUT Switch", WM9081_ANALOGUE_LINEOUT, 7, 1, 1), -SOC_SINGLE("LINEOUT ZC Switch", WM9081_ANALOGUE_LINEOUT, 6, 1, 0), -SOC_SINGLE_TLV("LINEOUT Volume", WM9081_ANALOGUE_LINEOUT, 0, 63, 0, out_tlv), - -SOC_SINGLE("DRC Switch", WM9081_DRC_1, 15, 1, 0), -SOC_ENUM("DRC High Slope", drc_high), -SOC_ENUM("DRC Low Slope", drc_low), -SOC_SINGLE_TLV("DRC Input Volume", WM9081_DRC_4, 5, 60, 1, drc_in_tlv), -SOC_SINGLE_TLV("DRC Output Volume", WM9081_DRC_4, 0, 30, 1, drc_out_tlv), -SOC_SINGLE_TLV("DRC Minimum Volume", WM9081_DRC_2, 2, 3, 1, drc_min_tlv), -SOC_SINGLE_TLV("DRC Maximum Volume", WM9081_DRC_2, 0, 3, 0, drc_max_tlv), -SOC_ENUM("DRC Attack", drc_atk), -SOC_ENUM("DRC Decay", drc_dcy), -SOC_SINGLE("DRC Quick Release Switch", WM9081_DRC_1, 2, 1, 0), -SOC_SINGLE_TLV("DRC Quick Release Volume", WM9081_DRC_2, 6, 3, 0, drc_qr_tlv), -SOC_ENUM("DRC Quick Release Decay", drc_qr_dcy), -SOC_SINGLE_TLV("DRC Startup Volume", WM9081_DRC_1, 6, 18, 0, drc_startup_tlv), - -SOC_SINGLE("EQ Switch", WM9081_EQ_1, 0, 1, 0), - -SOC_SINGLE("Speaker DC Volume", WM9081_ANALOGUE_SPEAKER_1, 3, 5, 0), -SOC_SINGLE("Speaker AC Volume", WM9081_ANALOGUE_SPEAKER_1, 0, 5, 0), -SOC_SINGLE("Speaker Switch", WM9081_ANALOGUE_SPEAKER_PGA, 7, 1, 1), -SOC_SINGLE("Speaker ZC Switch", WM9081_ANALOGUE_SPEAKER_PGA, 6, 1, 0), -SOC_SINGLE_TLV("Speaker Volume", WM9081_ANALOGUE_SPEAKER_PGA, 0, 63, 0, - out_tlv), -SOC_ENUM("DAC Deemphasis", dac_deemph), -SOC_ENUM_EXT("Speaker Mode", speaker_mode, speaker_mode_get, speaker_mode_put), -}; - -static const struct snd_kcontrol_new wm9081_eq_controls[] = { -SOC_SINGLE_TLV("EQ1 Volume", WM9081_EQ_1, 11, 24, 0, eq_tlv), -SOC_SINGLE_TLV("EQ2 Volume", WM9081_EQ_1, 6, 24, 0, eq_tlv), -SOC_SINGLE_TLV("EQ3 Volume", WM9081_EQ_1, 1, 24, 0, eq_tlv), -SOC_SINGLE_TLV("EQ4 Volume", WM9081_EQ_2, 11, 24, 0, eq_tlv), -SOC_SINGLE_TLV("EQ5 Volume", WM9081_EQ_2, 6, 24, 0, eq_tlv), -}; - -static const struct snd_kcontrol_new mixer[] = { -SOC_DAPM_SINGLE("IN1 Switch", WM9081_ANALOGUE_MIXER, 0, 1, 0), -SOC_DAPM_SINGLE("IN2 Switch", WM9081_ANALOGUE_MIXER, 2, 1, 0), -SOC_DAPM_SINGLE("Playback Switch", WM9081_ANALOGUE_MIXER, 4, 1, 0), -}; - -static int speaker_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_codec *codec = w->codec; - unsigned int reg = wm9081_read(codec, WM9081_POWER_MANAGEMENT); - - switch (event) { - case SND_SOC_DAPM_POST_PMU: - reg |= WM9081_SPK_ENA; - break; - - case SND_SOC_DAPM_PRE_PMD: - reg &= ~WM9081_SPK_ENA; - break; - } - - wm9081_write(codec, WM9081_POWER_MANAGEMENT, reg); - - return 0; -} - -struct _fll_div { - u16 fll_fratio; - u16 fll_outdiv; - u16 fll_clk_ref_div; - u16 n; - u16 k; -}; - -/* The size in bits of the FLL divide multiplied by 10 - * to allow rounding later */ -#define FIXED_FLL_SIZE ((1 << 16) * 10) - -static struct { - unsigned int min; - unsigned int max; - u16 fll_fratio; - int ratio; -} fll_fratios[] = { - { 0, 64000, 4, 16 }, - { 64000, 128000, 3, 8 }, - { 128000, 256000, 2, 4 }, - { 256000, 1000000, 1, 2 }, - { 1000000, 13500000, 0, 1 }, -}; - -static int fll_factors(struct _fll_div *fll_div, unsigned int Fref, - unsigned int Fout) -{ - u64 Kpart; - unsigned int K, Ndiv, Nmod, target; - unsigned int div; - int i; - - /* Fref must be <=13.5MHz */ - div = 1; - while ((Fref / div) > 13500000) { - div *= 2; - - if (div > 8) { - pr_err("Can't scale %dMHz input down to <=13.5MHz\n", - Fref); - return -EINVAL; - } - } - fll_div->fll_clk_ref_div = div / 2; - - pr_debug("Fref=%u Fout=%u\n", Fref, Fout); - - /* Apply the division for our remaining calculations */ - Fref /= div; - - /* Fvco should be 90-100MHz; don't check the upper bound */ - div = 0; - target = Fout * 2; - while (target < 90000000) { - div++; - target *= 2; - if (div > 7) { - pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n", - Fout); - return -EINVAL; - } - } - fll_div->fll_outdiv = div; - - pr_debug("Fvco=%dHz\n", target); - - /* Find an appropraite FLL_FRATIO and factor it out of the target */ - for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) { - if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) { - fll_div->fll_fratio = fll_fratios[i].fll_fratio; - target /= fll_fratios[i].ratio; - break; - } - } - if (i == ARRAY_SIZE(fll_fratios)) { - pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref); - return -EINVAL; - } - - /* Now, calculate N.K */ - Ndiv = target / Fref; - - fll_div->n = Ndiv; - Nmod = target % Fref; - pr_debug("Nmod=%d\n", Nmod); - - /* Calculate fractional part - scale up so we can round. */ - Kpart = FIXED_FLL_SIZE * (long long)Nmod; - - do_div(Kpart, Fref); - - K = Kpart & 0xFFFFFFFF; - - if ((K % 10) >= 5) - K += 5; - - /* Move down to proper range now rounding is done */ - fll_div->k = K / 10; - - pr_debug("N=%x K=%x FLL_FRATIO=%x FLL_OUTDIV=%x FLL_CLK_REF_DIV=%x\n", - fll_div->n, fll_div->k, - fll_div->fll_fratio, fll_div->fll_outdiv, - fll_div->fll_clk_ref_div); - - return 0; -} - -static int wm9081_set_fll(struct snd_soc_codec *codec, int fll_id, - unsigned int Fref, unsigned int Fout) -{ - struct wm9081_priv *wm9081 = codec->private_data; - u16 reg1, reg4, reg5; - struct _fll_div fll_div; - int ret; - int clk_sys_reg; - - /* Any change? */ - if (Fref == wm9081->fll_fref && Fout == wm9081->fll_fout) - return 0; - - /* Disable the FLL */ - if (Fout == 0) { - dev_dbg(codec->dev, "FLL disabled\n"); - wm9081->fll_fref = 0; - wm9081->fll_fout = 0; - - return 0; - } - - ret = fll_factors(&fll_div, Fref, Fout); - if (ret != 0) - return ret; - - reg5 = wm9081_read(codec, WM9081_FLL_CONTROL_5); - reg5 &= ~WM9081_FLL_CLK_SRC_MASK; - - switch (fll_id) { - case WM9081_SYSCLK_FLL_MCLK: - reg5 |= 0x1; - break; - - default: - dev_err(codec->dev, "Unknown FLL ID %d\n", fll_id); - return -EINVAL; - } - - /* Disable CLK_SYS while we reconfigure */ - clk_sys_reg = wm9081_read(codec, WM9081_CLOCK_CONTROL_3); - if (clk_sys_reg & WM9081_CLK_SYS_ENA) - wm9081_write(codec, WM9081_CLOCK_CONTROL_3, - clk_sys_reg & ~WM9081_CLK_SYS_ENA); - - /* Any FLL configuration change requires that the FLL be - * disabled first. */ - reg1 = wm9081_read(codec, WM9081_FLL_CONTROL_1); - reg1 &= ~WM9081_FLL_ENA; - wm9081_write(codec, WM9081_FLL_CONTROL_1, reg1); - - /* Apply the configuration */ - if (fll_div.k) - reg1 |= WM9081_FLL_FRAC_MASK; - else - reg1 &= ~WM9081_FLL_FRAC_MASK; - wm9081_write(codec, WM9081_FLL_CONTROL_1, reg1); - - wm9081_write(codec, WM9081_FLL_CONTROL_2, - (fll_div.fll_outdiv << WM9081_FLL_OUTDIV_SHIFT) | - (fll_div.fll_fratio << WM9081_FLL_FRATIO_SHIFT)); - wm9081_write(codec, WM9081_FLL_CONTROL_3, fll_div.k); - - reg4 = wm9081_read(codec, WM9081_FLL_CONTROL_4); - reg4 &= ~WM9081_FLL_N_MASK; - reg4 |= fll_div.n << WM9081_FLL_N_SHIFT; - wm9081_write(codec, WM9081_FLL_CONTROL_4, reg4); - - reg5 &= ~WM9081_FLL_CLK_REF_DIV_MASK; - reg5 |= fll_div.fll_clk_ref_div << WM9081_FLL_CLK_REF_DIV_SHIFT; - wm9081_write(codec, WM9081_FLL_CONTROL_5, reg5); - - /* Enable the FLL */ - wm9081_write(codec, WM9081_FLL_CONTROL_1, reg1 | WM9081_FLL_ENA); - - /* Then bring CLK_SYS up again if it was disabled */ - if (clk_sys_reg & WM9081_CLK_SYS_ENA) - wm9081_write(codec, WM9081_CLOCK_CONTROL_3, clk_sys_reg); - - dev_dbg(codec->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout); - - wm9081->fll_fref = Fref; - wm9081->fll_fout = Fout; - - return 0; -} - -static int configure_clock(struct snd_soc_codec *codec) -{ - struct wm9081_priv *wm9081 = codec->private_data; - int new_sysclk, i, target; - unsigned int reg; - int ret = 0; - int mclkdiv = 0; - int fll = 0; - - switch (wm9081->sysclk_source) { - case WM9081_SYSCLK_MCLK: - if (wm9081->mclk_rate > 12225000) { - mclkdiv = 1; - wm9081->sysclk_rate = wm9081->mclk_rate / 2; - } else { - wm9081->sysclk_rate = wm9081->mclk_rate; - } - wm9081_set_fll(codec, WM9081_SYSCLK_FLL_MCLK, 0, 0); - break; - - case WM9081_SYSCLK_FLL_MCLK: - /* If we have a sample rate calculate a CLK_SYS that - * gives us a suitable DAC configuration, plus BCLK. - * Ideally we would check to see if we can clock - * directly from MCLK and only use the FLL if this is - * not the case, though care must be taken with free - * running mode. - */ - if (wm9081->master && wm9081->bclk) { - /* Make sure we can generate CLK_SYS and BCLK - * and that we've got 3MHz for optimal - * performance. */ - for (i = 0; i < ARRAY_SIZE(clk_sys_rates); i++) { - target = wm9081->fs * clk_sys_rates[i].ratio; - new_sysclk = target; - if (target >= wm9081->bclk && - target > 3000000) - break; - } - } else if (wm9081->fs) { - for (i = 0; i < ARRAY_SIZE(clk_sys_rates); i++) { - new_sysclk = clk_sys_rates[i].ratio - * wm9081->fs; - if (new_sysclk > 3000000) - break; - } - } else { - new_sysclk = 12288000; - } - - ret = wm9081_set_fll(codec, WM9081_SYSCLK_FLL_MCLK, - wm9081->mclk_rate, new_sysclk); - if (ret == 0) { - wm9081->sysclk_rate = new_sysclk; - - /* Switch SYSCLK over to FLL */ - fll = 1; - } else { - wm9081->sysclk_rate = wm9081->mclk_rate; - } - break; - - default: - return -EINVAL; - } - - reg = wm9081_read(codec, WM9081_CLOCK_CONTROL_1); - if (mclkdiv) - reg |= WM9081_MCLKDIV2; - else - reg &= ~WM9081_MCLKDIV2; - wm9081_write(codec, WM9081_CLOCK_CONTROL_1, reg); - - reg = wm9081_read(codec, WM9081_CLOCK_CONTROL_3); - if (fll) - reg |= WM9081_CLK_SRC_SEL; - else - reg &= ~WM9081_CLK_SRC_SEL; - wm9081_write(codec, WM9081_CLOCK_CONTROL_3, reg); - - dev_dbg(codec->dev, "CLK_SYS is %dHz\n", wm9081->sysclk_rate); - - return ret; -} - -static int clk_sys_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_codec *codec = w->codec; - struct wm9081_priv *wm9081 = codec->private_data; - - /* This should be done on init() for bypass paths */ - switch (wm9081->sysclk_source) { - case WM9081_SYSCLK_MCLK: - dev_dbg(codec->dev, "Using %dHz MCLK\n", wm9081->mclk_rate); - break; - case WM9081_SYSCLK_FLL_MCLK: - dev_dbg(codec->dev, "Using %dHz MCLK with FLL\n", - wm9081->mclk_rate); - break; - default: - dev_err(codec->dev, "System clock not configured\n"); - return -EINVAL; - } - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - configure_clock(codec); - break; - - case SND_SOC_DAPM_POST_PMD: - /* Disable the FLL if it's running */ - wm9081_set_fll(codec, 0, 0, 0); - break; - } - - return 0; -} - -static const struct snd_soc_dapm_widget wm9081_dapm_widgets[] = { -SND_SOC_DAPM_INPUT("IN1"), -SND_SOC_DAPM_INPUT("IN2"), - -SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM9081_POWER_MANAGEMENT, 0, 0), - -SND_SOC_DAPM_MIXER_NAMED_CTL("Mixer", SND_SOC_NOPM, 0, 0, - mixer, ARRAY_SIZE(mixer)), - -SND_SOC_DAPM_PGA("LINEOUT PGA", WM9081_POWER_MANAGEMENT, 4, 0, NULL, 0), - -SND_SOC_DAPM_PGA_E("Speaker PGA", WM9081_POWER_MANAGEMENT, 2, 0, NULL, 0, - speaker_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), - -SND_SOC_DAPM_OUTPUT("LINEOUT"), -SND_SOC_DAPM_OUTPUT("SPKN"), -SND_SOC_DAPM_OUTPUT("SPKP"), - -SND_SOC_DAPM_SUPPLY("CLK_SYS", WM9081_CLOCK_CONTROL_3, 0, 0, clk_sys_event, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), -SND_SOC_DAPM_SUPPLY("CLK_DSP", WM9081_CLOCK_CONTROL_3, 1, 0, NULL, 0), -SND_SOC_DAPM_SUPPLY("TOCLK", WM9081_CLOCK_CONTROL_3, 2, 0, NULL, 0), -}; - - -static const struct snd_soc_dapm_route audio_paths[] = { - { "DAC", NULL, "CLK_SYS" }, - { "DAC", NULL, "CLK_DSP" }, - - { "Mixer", "IN1 Switch", "IN1" }, - { "Mixer", "IN2 Switch", "IN2" }, - { "Mixer", "Playback Switch", "DAC" }, - - { "LINEOUT PGA", NULL, "Mixer" }, - { "LINEOUT PGA", NULL, "TOCLK" }, - { "LINEOUT PGA", NULL, "CLK_SYS" }, - - { "LINEOUT", NULL, "LINEOUT PGA" }, - - { "Speaker PGA", NULL, "Mixer" }, - { "Speaker PGA", NULL, "TOCLK" }, - { "Speaker PGA", NULL, "CLK_SYS" }, - - { "SPKN", NULL, "Speaker PGA" }, - { "SPKP", NULL, "Speaker PGA" }, -}; - -static int wm9081_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - u16 reg; - - switch (level) { - case SND_SOC_BIAS_ON: - break; - - case SND_SOC_BIAS_PREPARE: - /* VMID=2*40k */ - reg = wm9081_read(codec, WM9081_VMID_CONTROL); - reg &= ~WM9081_VMID_SEL_MASK; - reg |= 0x2; - wm9081_write(codec, WM9081_VMID_CONTROL, reg); - - /* Normal bias current */ - reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); - reg &= ~WM9081_STBY_BIAS_ENA; - wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg); - break; - - case SND_SOC_BIAS_STANDBY: - /* Initial cold start */ - if (codec->bias_level == SND_SOC_BIAS_OFF) { - /* Disable LINEOUT discharge */ - reg = wm9081_read(codec, WM9081_ANTI_POP_CONTROL); - reg &= ~WM9081_LINEOUT_DISCH; - wm9081_write(codec, WM9081_ANTI_POP_CONTROL, reg); - - /* Select startup bias source */ - reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); - reg |= WM9081_BIAS_SRC | WM9081_BIAS_ENA; - wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg); - - /* VMID 2*4k; Soft VMID ramp enable */ - reg = wm9081_read(codec, WM9081_VMID_CONTROL); - reg |= WM9081_VMID_RAMP | 0x6; - wm9081_write(codec, WM9081_VMID_CONTROL, reg); - - mdelay(100); - - /* Normal bias enable & soft start off */ - reg |= WM9081_BIAS_ENA; - reg &= ~WM9081_VMID_RAMP; - wm9081_write(codec, WM9081_VMID_CONTROL, reg); - - /* Standard bias source */ - reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); - reg &= ~WM9081_BIAS_SRC; - wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg); - } - - /* VMID 2*240k */ - reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); - reg &= ~WM9081_VMID_SEL_MASK; - reg |= 0x40; - wm9081_write(codec, WM9081_VMID_CONTROL, reg); - - /* Standby bias current on */ - reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); - reg |= WM9081_STBY_BIAS_ENA; - wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg); - break; - - case SND_SOC_BIAS_OFF: - /* Startup bias source */ - reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); - reg |= WM9081_BIAS_SRC; - wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg); - - /* Disable VMID and biases with soft ramping */ - reg = wm9081_read(codec, WM9081_VMID_CONTROL); - reg &= ~(WM9081_VMID_SEL_MASK | WM9081_BIAS_ENA); - reg |= WM9081_VMID_RAMP; - wm9081_write(codec, WM9081_VMID_CONTROL, reg); - - /* Actively discharge LINEOUT */ - reg = wm9081_read(codec, WM9081_ANTI_POP_CONTROL); - reg |= WM9081_LINEOUT_DISCH; - wm9081_write(codec, WM9081_ANTI_POP_CONTROL, reg); - break; - } - - codec->bias_level = level; - - return 0; -} - -static int wm9081_set_dai_fmt(struct snd_soc_dai *dai, - unsigned int fmt) -{ - struct snd_soc_codec *codec = dai->codec; - struct wm9081_priv *wm9081 = codec->private_data; - unsigned int aif2 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_2); - - aif2 &= ~(WM9081_AIF_BCLK_INV | WM9081_AIF_LRCLK_INV | - WM9081_BCLK_DIR | WM9081_LRCLK_DIR | WM9081_AIF_FMT_MASK); - - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - wm9081->master = 0; - break; - case SND_SOC_DAIFMT_CBS_CFM: - aif2 |= WM9081_LRCLK_DIR; - wm9081->master = 1; - break; - case SND_SOC_DAIFMT_CBM_CFS: - aif2 |= WM9081_BCLK_DIR; - wm9081->master = 1; - break; - case SND_SOC_DAIFMT_CBM_CFM: - aif2 |= WM9081_LRCLK_DIR | WM9081_BCLK_DIR; - wm9081->master = 1; - break; - default: - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_DSP_B: - aif2 |= WM9081_AIF_LRCLK_INV; - case SND_SOC_DAIFMT_DSP_A: - aif2 |= 0x3; - break; - case SND_SOC_DAIFMT_I2S: - aif2 |= 0x2; - break; - case SND_SOC_DAIFMT_RIGHT_J: - break; - case SND_SOC_DAIFMT_LEFT_J: - aif2 |= 0x1; - break; - default: - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_DSP_A: - case SND_SOC_DAIFMT_DSP_B: - /* frame inversion not valid for DSP modes */ - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - break; - case SND_SOC_DAIFMT_IB_NF: - aif2 |= WM9081_AIF_BCLK_INV; - break; - default: - return -EINVAL; - } - break; - - case SND_SOC_DAIFMT_I2S: - case SND_SOC_DAIFMT_RIGHT_J: - case SND_SOC_DAIFMT_LEFT_J: - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - break; - case SND_SOC_DAIFMT_IB_IF: - aif2 |= WM9081_AIF_BCLK_INV | WM9081_AIF_LRCLK_INV; - break; - case SND_SOC_DAIFMT_IB_NF: - aif2 |= WM9081_AIF_BCLK_INV; - break; - case SND_SOC_DAIFMT_NB_IF: - aif2 |= WM9081_AIF_LRCLK_INV; - break; - default: - return -EINVAL; - } - break; - default: - return -EINVAL; - } - - wm9081_write(codec, WM9081_AUDIO_INTERFACE_2, aif2); - - return 0; -} - -static int wm9081_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_codec *codec = dai->codec; - struct wm9081_priv *wm9081 = codec->private_data; - int ret, i, best, best_val, cur_val; - unsigned int clk_ctrl2, aif1, aif2, aif3, aif4; - - clk_ctrl2 = wm9081_read(codec, WM9081_CLOCK_CONTROL_2); - clk_ctrl2 &= ~(WM9081_CLK_SYS_RATE_MASK | WM9081_SAMPLE_RATE_MASK); - - aif1 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_1); - - aif2 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_2); - aif2 &= ~WM9081_AIF_WL_MASK; - - aif3 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_3); - aif3 &= ~WM9081_BCLK_DIV_MASK; - - aif4 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_4); - aif4 &= ~WM9081_LRCLK_RATE_MASK; - - /* What BCLK do we need? */ - wm9081->fs = params_rate(params); - wm9081->bclk = 2 * wm9081->fs; - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - wm9081->bclk *= 16; - break; - case SNDRV_PCM_FORMAT_S20_3LE: - wm9081->bclk *= 20; - aif2 |= 0x4; - break; - case SNDRV_PCM_FORMAT_S24_LE: - wm9081->bclk *= 24; - aif2 |= 0x8; - break; - case SNDRV_PCM_FORMAT_S32_LE: - wm9081->bclk *= 32; - aif2 |= 0xc; - break; - default: - return -EINVAL; - } - - if (aif1 & WM9081_AIFDAC_TDM_MODE_MASK) { - int slots = ((aif1 & WM9081_AIFDAC_TDM_MODE_MASK) >> - WM9081_AIFDAC_TDM_MODE_SHIFT) + 1; - wm9081->bclk *= slots; - } - - dev_dbg(codec->dev, "Target BCLK is %dHz\n", wm9081->bclk); - - ret = configure_clock(codec); - if (ret != 0) - return ret; - - /* Select nearest CLK_SYS_RATE */ - best = 0; - best_val = abs((wm9081->sysclk_rate / clk_sys_rates[0].ratio) - - wm9081->fs); - for (i = 1; i < ARRAY_SIZE(clk_sys_rates); i++) { - cur_val = abs((wm9081->sysclk_rate / - clk_sys_rates[i].ratio) - wm9081->fs);; - if (cur_val < best_val) { - best = i; - best_val = cur_val; - } - } - dev_dbg(codec->dev, "Selected CLK_SYS_RATIO of %d\n", - clk_sys_rates[best].ratio); - clk_ctrl2 |= (clk_sys_rates[best].clk_sys_rate - << WM9081_CLK_SYS_RATE_SHIFT); - - /* SAMPLE_RATE */ - best = 0; - best_val = abs(wm9081->fs - sample_rates[0].rate); - for (i = 1; i < ARRAY_SIZE(sample_rates); i++) { - /* Closest match */ - cur_val = abs(wm9081->fs - sample_rates[i].rate); - if (cur_val < best_val) { - best = i; - best_val = cur_val; - } - } - dev_dbg(codec->dev, "Selected SAMPLE_RATE of %dHz\n", - sample_rates[best].rate); - clk_ctrl2 |= (sample_rates[best].sample_rate - << WM9081_SAMPLE_RATE_SHIFT); - - /* BCLK_DIV */ - best = 0; - best_val = INT_MAX; - for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) { - cur_val = ((wm9081->sysclk_rate * 10) / bclk_divs[i].div) - - wm9081->bclk; - if (cur_val < 0) /* Table is sorted */ - break; - if (cur_val < best_val) { - best = i; - best_val = cur_val; - } - } - wm9081->bclk = (wm9081->sysclk_rate * 10) / bclk_divs[best].div; - dev_dbg(codec->dev, "Selected BCLK_DIV of %d for %dHz BCLK\n", - bclk_divs[best].div, wm9081->bclk); - aif3 |= bclk_divs[best].bclk_div; - - /* LRCLK is a simple fraction of BCLK */ - dev_dbg(codec->dev, "LRCLK_RATE is %d\n", wm9081->bclk / wm9081->fs); - aif4 |= wm9081->bclk / wm9081->fs; - - /* Apply a ReTune Mobile configuration if it's in use */ - if (wm9081->retune) { - struct wm9081_retune_mobile_config *retune = wm9081->retune; - struct wm9081_retune_mobile_setting *s; - int eq1; - - best = 0; - best_val = abs(retune->configs[0].rate - wm9081->fs); - for (i = 0; i < retune->num_configs; i++) { - cur_val = abs(retune->configs[i].rate - wm9081->fs); - if (cur_val < best_val) { - best_val = cur_val; - best = i; - } - } - s = &retune->configs[best]; - - dev_dbg(codec->dev, "ReTune Mobile %s tuned for %dHz\n", - s->name, s->rate); - - /* If the EQ is enabled then disable it while we write out */ - eq1 = wm9081_read(codec, WM9081_EQ_1) & WM9081_EQ_ENA; - if (eq1 & WM9081_EQ_ENA) - wm9081_write(codec, WM9081_EQ_1, 0); - - /* Write out the other values */ - for (i = 1; i < ARRAY_SIZE(s->config); i++) - wm9081_write(codec, WM9081_EQ_1 + i, s->config[i]); - - eq1 |= (s->config[0] & ~WM9081_EQ_ENA); - wm9081_write(codec, WM9081_EQ_1, eq1); - } - - wm9081_write(codec, WM9081_CLOCK_CONTROL_2, clk_ctrl2); - wm9081_write(codec, WM9081_AUDIO_INTERFACE_2, aif2); - wm9081_write(codec, WM9081_AUDIO_INTERFACE_3, aif3); - wm9081_write(codec, WM9081_AUDIO_INTERFACE_4, aif4); - - return 0; -} - -static int wm9081_digital_mute(struct snd_soc_dai *codec_dai, int mute) -{ - struct snd_soc_codec *codec = codec_dai->codec; - unsigned int reg; - - reg = wm9081_read(codec, WM9081_DAC_DIGITAL_2); - - if (mute) - reg |= WM9081_DAC_MUTE; - else - reg &= ~WM9081_DAC_MUTE; - - wm9081_write(codec, WM9081_DAC_DIGITAL_2, reg); - - return 0; -} - -static int wm9081_set_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir) -{ - struct snd_soc_codec *codec = codec_dai->codec; - struct wm9081_priv *wm9081 = codec->private_data; - - switch (clk_id) { - case WM9081_SYSCLK_MCLK: - case WM9081_SYSCLK_FLL_MCLK: - wm9081->sysclk_source = clk_id; - wm9081->mclk_rate = freq; - break; - - default: - return -EINVAL; - } - - return 0; -} - -static int wm9081_set_tdm_slot(struct snd_soc_dai *dai, - unsigned int mask, int slots) -{ - struct snd_soc_codec *codec = dai->codec; - unsigned int aif1 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_1); - - aif1 &= ~(WM9081_AIFDAC_TDM_SLOT_MASK | WM9081_AIFDAC_TDM_MODE_MASK); - - if (slots < 1 || slots > 4) - return -EINVAL; - - aif1 |= (slots - 1) << WM9081_AIFDAC_TDM_MODE_SHIFT; - - switch (mask) { - case 1: - break; - case 2: - aif1 |= 0x10; - break; - case 4: - aif1 |= 0x20; - break; - case 8: - aif1 |= 0x30; - break; - default: - return -EINVAL; - } - - wm9081_write(codec, WM9081_AUDIO_INTERFACE_1, aif1); - - return 0; -} - -#define WM9081_RATES SNDRV_PCM_RATE_8000_96000 - -#define WM9081_FORMATS \ - (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) - -static struct snd_soc_dai_ops wm9081_dai_ops = { - .hw_params = wm9081_hw_params, - .set_sysclk = wm9081_set_sysclk, - .set_fmt = wm9081_set_dai_fmt, - .digital_mute = wm9081_digital_mute, - .set_tdm_slot = wm9081_set_tdm_slot, -}; - -/* We report two channels because the CODEC processes a stereo signal, even - * though it is only capable of handling a mono output. - */ -struct snd_soc_dai wm9081_dai = { - .name = "WM9081", - .playback = { - .stream_name = "HiFi Playback", - .channels_min = 1, - .channels_max = 2, - .rates = WM9081_RATES, - .formats = WM9081_FORMATS, - }, - .ops = &wm9081_dai_ops, -}; -EXPORT_SYMBOL_GPL(wm9081_dai); - - -static struct snd_soc_codec *wm9081_codec; - -static int wm9081_probe(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec; - struct wm9081_priv *wm9081; - int ret = 0; - - if (wm9081_codec == NULL) { - dev_err(&pdev->dev, "Codec device not registered\n"); - return -ENODEV; - } - - socdev->card->codec = wm9081_codec; - codec = wm9081_codec; - wm9081 = codec->private_data; - - /* register pcms */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - dev_err(codec->dev, "failed to create pcms: %d\n", ret); - goto pcm_err; - } - - snd_soc_add_controls(codec, wm9081_snd_controls, - ARRAY_SIZE(wm9081_snd_controls)); - if (!wm9081->retune) { - dev_dbg(codec->dev, - "No ReTune Mobile data, using normal EQ\n"); - snd_soc_add_controls(codec, wm9081_eq_controls, - ARRAY_SIZE(wm9081_eq_controls)); - } - - snd_soc_dapm_new_controls(codec, wm9081_dapm_widgets, - ARRAY_SIZE(wm9081_dapm_widgets)); - snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); - snd_soc_dapm_new_widgets(codec); - - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(codec->dev, "failed to register card: %d\n", ret); - goto card_err; - } - - return ret; - -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -pcm_err: - return ret; -} - -static int wm9081_remove(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); - - return 0; -} - -#ifdef CONFIG_PM -static int wm9081_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; - - wm9081_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - -static int wm9081_resume(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; - u16 *reg_cache = codec->reg_cache; - int i; - - for (i = 0; i < codec->reg_cache_size; i++) { - if (i == WM9081_SOFTWARE_RESET) - continue; - - wm9081_write(codec, i, reg_cache[i]); - } - - wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} -#else -#define wm9081_suspend NULL -#define wm9081_resume NULL -#endif - -struct snd_soc_codec_device soc_codec_dev_wm9081 = { - .probe = wm9081_probe, - .remove = wm9081_remove, - .suspend = wm9081_suspend, - .resume = wm9081_resume, -}; -EXPORT_SYMBOL_GPL(soc_codec_dev_wm9081); - -static int wm9081_register(struct wm9081_priv *wm9081) -{ - struct snd_soc_codec *codec = &wm9081->codec; - int ret; - u16 reg; - - if (wm9081_codec) { - dev_err(codec->dev, "Another WM9081 is registered\n"); - ret = -EINVAL; - goto err; - } - - mutex_init(&codec->mutex); - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); - - codec->private_data = wm9081; - codec->name = "WM9081"; - codec->owner = THIS_MODULE; - codec->read = wm9081_read; - codec->write = wm9081_write; - codec->dai = &wm9081_dai; - codec->num_dai = 1; - codec->reg_cache_size = ARRAY_SIZE(wm9081->reg_cache); - codec->reg_cache = &wm9081->reg_cache; - codec->bias_level = SND_SOC_BIAS_OFF; - codec->set_bias_level = wm9081_set_bias_level; - - memcpy(codec->reg_cache, wm9081_reg_defaults, - sizeof(wm9081_reg_defaults)); - - reg = wm9081_read_hw(codec, WM9081_SOFTWARE_RESET); - if (reg != 0x9081) { - dev_err(codec->dev, "Device is not a WM9081: ID=0x%x\n", reg); - ret = -EINVAL; - goto err; - } - - ret = wm9081_reset(codec); - if (ret < 0) { - dev_err(codec->dev, "Failed to issue reset\n"); - return ret; - } - - wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - /* Enable zero cross by default */ - reg = wm9081_read(codec, WM9081_ANALOGUE_LINEOUT); - wm9081_write(codec, WM9081_ANALOGUE_LINEOUT, reg | WM9081_LINEOUTZC); - reg = wm9081_read(codec, WM9081_ANALOGUE_SPEAKER_PGA); - wm9081_write(codec, WM9081_ANALOGUE_SPEAKER_PGA, - reg | WM9081_SPKPGAZC); - - wm9081_dai.dev = codec->dev; - - wm9081_codec = codec; - - ret = snd_soc_register_codec(codec); - if (ret != 0) { - dev_err(codec->dev, "Failed to register codec: %d\n", ret); - return ret; - } - - ret = snd_soc_register_dai(&wm9081_dai); - if (ret != 0) { - dev_err(codec->dev, "Failed to register DAI: %d\n", ret); - snd_soc_unregister_codec(codec); - return ret; - } - - return 0; - -err: - kfree(wm9081); - return ret; -} - -static void wm9081_unregister(struct wm9081_priv *wm9081) -{ - wm9081_set_bias_level(&wm9081->codec, SND_SOC_BIAS_OFF); - snd_soc_unregister_dai(&wm9081_dai); - snd_soc_unregister_codec(&wm9081->codec); - kfree(wm9081); - wm9081_codec = NULL; -} - -static __devinit int wm9081_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - struct wm9081_priv *wm9081; - struct snd_soc_codec *codec; - - wm9081 = kzalloc(sizeof(struct wm9081_priv), GFP_KERNEL); - if (wm9081 == NULL) - return -ENOMEM; - - codec = &wm9081->codec; - codec->hw_write = (hw_write_t)i2c_master_send; - wm9081->retune = i2c->dev.platform_data; - - i2c_set_clientdata(i2c, wm9081); - codec->control_data = i2c; - - codec->dev = &i2c->dev; - - return wm9081_register(wm9081); -} - -static __devexit int wm9081_i2c_remove(struct i2c_client *client) -{ - struct wm9081_priv *wm9081 = i2c_get_clientdata(client); - wm9081_unregister(wm9081); - return 0; -} - -static const struct i2c_device_id wm9081_i2c_id[] = { - { "wm9081", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wm9081_i2c_id); - -static struct i2c_driver wm9081_i2c_driver = { - .driver = { - .name = "wm9081", - .owner = THIS_MODULE, - }, - .probe = wm9081_i2c_probe, - .remove = __devexit_p(wm9081_i2c_remove), - .id_table = wm9081_i2c_id, -}; - -static int __init wm9081_modinit(void) -{ - int ret; - - ret = i2c_add_driver(&wm9081_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register WM9081 I2C driver: %d\n", - ret); - } - - return ret; -} -module_init(wm9081_modinit); - -static void __exit wm9081_exit(void) -{ - i2c_del_driver(&wm9081_i2c_driver); -} -module_exit(wm9081_exit); - - -MODULE_DESCRIPTION("ASoC WM9081 driver"); -MODULE_AUTHOR("Mark Brown "); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/codecs/wm9081.h b/trunk/sound/soc/codecs/wm9081.h deleted file mode 100644 index 42d3bc757021..000000000000 --- a/trunk/sound/soc/codecs/wm9081.h +++ /dev/null @@ -1,787 +0,0 @@ -#ifndef WM9081_H -#define WM9081_H - -/* - * wm9081.c -- WM9081 ALSA SoC Audio driver - * - * Author: Mark Brown - * - * Copyright 2009 Wolfson Microelectronics plc - * - * 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. - */ - -#include - -extern struct snd_soc_dai wm9081_dai; -extern struct snd_soc_codec_device soc_codec_dev_wm9081; - -/* - * SYSCLK sources - */ -#define WM9081_SYSCLK_MCLK 1 /* Use MCLK without FLL */ -#define WM9081_SYSCLK_FLL_MCLK 2 /* Use MCLK, enabling FLL if required */ - -/* - * Register values. - */ -#define WM9081_SOFTWARE_RESET 0x00 -#define WM9081_ANALOGUE_LINEOUT 0x02 -#define WM9081_ANALOGUE_SPEAKER_PGA 0x03 -#define WM9081_VMID_CONTROL 0x04 -#define WM9081_BIAS_CONTROL_1 0x05 -#define WM9081_ANALOGUE_MIXER 0x07 -#define WM9081_ANTI_POP_CONTROL 0x08 -#define WM9081_ANALOGUE_SPEAKER_1 0x09 -#define WM9081_ANALOGUE_SPEAKER_2 0x0A -#define WM9081_POWER_MANAGEMENT 0x0B -#define WM9081_CLOCK_CONTROL_1 0x0C -#define WM9081_CLOCK_CONTROL_2 0x0D -#define WM9081_CLOCK_CONTROL_3 0x0E -#define WM9081_FLL_CONTROL_1 0x10 -#define WM9081_FLL_CONTROL_2 0x11 -#define WM9081_FLL_CONTROL_3 0x12 -#define WM9081_FLL_CONTROL_4 0x13 -#define WM9081_FLL_CONTROL_5 0x14 -#define WM9081_AUDIO_INTERFACE_1 0x16 -#define WM9081_AUDIO_INTERFACE_2 0x17 -#define WM9081_AUDIO_INTERFACE_3 0x18 -#define WM9081_AUDIO_INTERFACE_4 0x19 -#define WM9081_INTERRUPT_STATUS 0x1A -#define WM9081_INTERRUPT_STATUS_MASK 0x1B -#define WM9081_INTERRUPT_POLARITY 0x1C -#define WM9081_INTERRUPT_CONTROL 0x1D -#define WM9081_DAC_DIGITAL_1 0x1E -#define WM9081_DAC_DIGITAL_2 0x1F -#define WM9081_DRC_1 0x20 -#define WM9081_DRC_2 0x21 -#define WM9081_DRC_3 0x22 -#define WM9081_DRC_4 0x23 -#define WM9081_WRITE_SEQUENCER_1 0x26 -#define WM9081_WRITE_SEQUENCER_2 0x27 -#define WM9081_MW_SLAVE_1 0x28 -#define WM9081_EQ_1 0x2A -#define WM9081_EQ_2 0x2B -#define WM9081_EQ_3 0x2C -#define WM9081_EQ_4 0x2D -#define WM9081_EQ_5 0x2E -#define WM9081_EQ_6 0x2F -#define WM9081_EQ_7 0x30 -#define WM9081_EQ_8 0x31 -#define WM9081_EQ_9 0x32 -#define WM9081_EQ_10 0x33 -#define WM9081_EQ_11 0x34 -#define WM9081_EQ_12 0x35 -#define WM9081_EQ_13 0x36 -#define WM9081_EQ_14 0x37 -#define WM9081_EQ_15 0x38 -#define WM9081_EQ_16 0x39 -#define WM9081_EQ_17 0x3A -#define WM9081_EQ_18 0x3B -#define WM9081_EQ_19 0x3C -#define WM9081_EQ_20 0x3D - -#define WM9081_REGISTER_COUNT 55 -#define WM9081_MAX_REGISTER 0x3D - -/* - * Field Definitions. - */ - -/* - * R0 (0x00) - Software Reset - */ -#define WM9081_SW_RST_DEV_ID1_MASK 0xFFFF /* SW_RST_DEV_ID1 - [15:0] */ -#define WM9081_SW_RST_DEV_ID1_SHIFT 0 /* SW_RST_DEV_ID1 - [15:0] */ -#define WM9081_SW_RST_DEV_ID1_WIDTH 16 /* SW_RST_DEV_ID1 - [15:0] */ - -/* - * R2 (0x02) - Analogue Lineout - */ -#define WM9081_LINEOUT_MUTE 0x0080 /* LINEOUT_MUTE */ -#define WM9081_LINEOUT_MUTE_MASK 0x0080 /* LINEOUT_MUTE */ -#define WM9081_LINEOUT_MUTE_SHIFT 7 /* LINEOUT_MUTE */ -#define WM9081_LINEOUT_MUTE_WIDTH 1 /* LINEOUT_MUTE */ -#define WM9081_LINEOUTZC 0x0040 /* LINEOUTZC */ -#define WM9081_LINEOUTZC_MASK 0x0040 /* LINEOUTZC */ -#define WM9081_LINEOUTZC_SHIFT 6 /* LINEOUTZC */ -#define WM9081_LINEOUTZC_WIDTH 1 /* LINEOUTZC */ -#define WM9081_LINEOUT_VOL_MASK 0x003F /* LINEOUT_VOL - [5:0] */ -#define WM9081_LINEOUT_VOL_SHIFT 0 /* LINEOUT_VOL - [5:0] */ -#define WM9081_LINEOUT_VOL_WIDTH 6 /* LINEOUT_VOL - [5:0] */ - -/* - * R3 (0x03) - Analogue Speaker PGA - */ -#define WM9081_SPKPGA_MUTE 0x0080 /* SPKPGA_MUTE */ -#define WM9081_SPKPGA_MUTE_MASK 0x0080 /* SPKPGA_MUTE */ -#define WM9081_SPKPGA_MUTE_SHIFT 7 /* SPKPGA_MUTE */ -#define WM9081_SPKPGA_MUTE_WIDTH 1 /* SPKPGA_MUTE */ -#define WM9081_SPKPGAZC 0x0040 /* SPKPGAZC */ -#define WM9081_SPKPGAZC_MASK 0x0040 /* SPKPGAZC */ -#define WM9081_SPKPGAZC_SHIFT 6 /* SPKPGAZC */ -#define WM9081_SPKPGAZC_WIDTH 1 /* SPKPGAZC */ -#define WM9081_SPKPGA_VOL_MASK 0x003F /* SPKPGA_VOL - [5:0] */ -#define WM9081_SPKPGA_VOL_SHIFT 0 /* SPKPGA_VOL - [5:0] */ -#define WM9081_SPKPGA_VOL_WIDTH 6 /* SPKPGA_VOL - [5:0] */ - -/* - * R4 (0x04) - VMID Control - */ -#define WM9081_VMID_BUF_ENA 0x0020 /* VMID_BUF_ENA */ -#define WM9081_VMID_BUF_ENA_MASK 0x0020 /* VMID_BUF_ENA */ -#define WM9081_VMID_BUF_ENA_SHIFT 5 /* VMID_BUF_ENA */ -#define WM9081_VMID_BUF_ENA_WIDTH 1 /* VMID_BUF_ENA */ -#define WM9081_VMID_RAMP 0x0008 /* VMID_RAMP */ -#define WM9081_VMID_RAMP_MASK 0x0008 /* VMID_RAMP */ -#define WM9081_VMID_RAMP_SHIFT 3 /* VMID_RAMP */ -#define WM9081_VMID_RAMP_WIDTH 1 /* VMID_RAMP */ -#define WM9081_VMID_SEL_MASK 0x0006 /* VMID_SEL - [2:1] */ -#define WM9081_VMID_SEL_SHIFT 1 /* VMID_SEL - [2:1] */ -#define WM9081_VMID_SEL_WIDTH 2 /* VMID_SEL - [2:1] */ -#define WM9081_VMID_FAST_ST 0x0001 /* VMID_FAST_ST */ -#define WM9081_VMID_FAST_ST_MASK 0x0001 /* VMID_FAST_ST */ -#define WM9081_VMID_FAST_ST_SHIFT 0 /* VMID_FAST_ST */ -#define WM9081_VMID_FAST_ST_WIDTH 1 /* VMID_FAST_ST */ - -/* - * R5 (0x05) - Bias Control 1 - */ -#define WM9081_BIAS_SRC 0x0040 /* BIAS_SRC */ -#define WM9081_BIAS_SRC_MASK 0x0040 /* BIAS_SRC */ -#define WM9081_BIAS_SRC_SHIFT 6 /* BIAS_SRC */ -#define WM9081_BIAS_SRC_WIDTH 1 /* BIAS_SRC */ -#define WM9081_STBY_BIAS_LVL 0x0020 /* STBY_BIAS_LVL */ -#define WM9081_STBY_BIAS_LVL_MASK 0x0020 /* STBY_BIAS_LVL */ -#define WM9081_STBY_BIAS_LVL_SHIFT 5 /* STBY_BIAS_LVL */ -#define WM9081_STBY_BIAS_LVL_WIDTH 1 /* STBY_BIAS_LVL */ -#define WM9081_STBY_BIAS_ENA 0x0010 /* STBY_BIAS_ENA */ -#define WM9081_STBY_BIAS_ENA_MASK 0x0010 /* STBY_BIAS_ENA */ -#define WM9081_STBY_BIAS_ENA_SHIFT 4 /* STBY_BIAS_ENA */ -#define WM9081_STBY_BIAS_ENA_WIDTH 1 /* STBY_BIAS_ENA */ -#define WM9081_BIAS_LVL_MASK 0x000C /* BIAS_LVL - [3:2] */ -#define WM9081_BIAS_LVL_SHIFT 2 /* BIAS_LVL - [3:2] */ -#define WM9081_BIAS_LVL_WIDTH 2 /* BIAS_LVL - [3:2] */ -#define WM9081_BIAS_ENA 0x0002 /* BIAS_ENA */ -#define WM9081_BIAS_ENA_MASK 0x0002 /* BIAS_ENA */ -#define WM9081_BIAS_ENA_SHIFT 1 /* BIAS_ENA */ -#define WM9081_BIAS_ENA_WIDTH 1 /* BIAS_ENA */ -#define WM9081_STARTUP_BIAS_ENA 0x0001 /* STARTUP_BIAS_ENA */ -#define WM9081_STARTUP_BIAS_ENA_MASK 0x0001 /* STARTUP_BIAS_ENA */ -#define WM9081_STARTUP_BIAS_ENA_SHIFT 0 /* STARTUP_BIAS_ENA */ -#define WM9081_STARTUP_BIAS_ENA_WIDTH 1 /* STARTUP_BIAS_ENA */ - -/* - * R7 (0x07) - Analogue Mixer - */ -#define WM9081_DAC_SEL 0x0010 /* DAC_SEL */ -#define WM9081_DAC_SEL_MASK 0x0010 /* DAC_SEL */ -#define WM9081_DAC_SEL_SHIFT 4 /* DAC_SEL */ -#define WM9081_DAC_SEL_WIDTH 1 /* DAC_SEL */ -#define WM9081_IN2_VOL 0x0008 /* IN2_VOL */ -#define WM9081_IN2_VOL_MASK 0x0008 /* IN2_VOL */ -#define WM9081_IN2_VOL_SHIFT 3 /* IN2_VOL */ -#define WM9081_IN2_VOL_WIDTH 1 /* IN2_VOL */ -#define WM9081_IN2_ENA 0x0004 /* IN2_ENA */ -#define WM9081_IN2_ENA_MASK 0x0004 /* IN2_ENA */ -#define WM9081_IN2_ENA_SHIFT 2 /* IN2_ENA */ -#define WM9081_IN2_ENA_WIDTH 1 /* IN2_ENA */ -#define WM9081_IN1_VOL 0x0002 /* IN1_VOL */ -#define WM9081_IN1_VOL_MASK 0x0002 /* IN1_VOL */ -#define WM9081_IN1_VOL_SHIFT 1 /* IN1_VOL */ -#define WM9081_IN1_VOL_WIDTH 1 /* IN1_VOL */ -#define WM9081_IN1_ENA 0x0001 /* IN1_ENA */ -#define WM9081_IN1_ENA_MASK 0x0001 /* IN1_ENA */ -#define WM9081_IN1_ENA_SHIFT 0 /* IN1_ENA */ -#define WM9081_IN1_ENA_WIDTH 1 /* IN1_ENA */ - -/* - * R8 (0x08) - Anti Pop Control - */ -#define WM9081_LINEOUT_DISCH 0x0004 /* LINEOUT_DISCH */ -#define WM9081_LINEOUT_DISCH_MASK 0x0004 /* LINEOUT_DISCH */ -#define WM9081_LINEOUT_DISCH_SHIFT 2 /* LINEOUT_DISCH */ -#define WM9081_LINEOUT_DISCH_WIDTH 1 /* LINEOUT_DISCH */ -#define WM9081_LINEOUT_VROI 0x0002 /* LINEOUT_VROI */ -#define WM9081_LINEOUT_VROI_MASK 0x0002 /* LINEOUT_VROI */ -#define WM9081_LINEOUT_VROI_SHIFT 1 /* LINEOUT_VROI */ -#define WM9081_LINEOUT_VROI_WIDTH 1 /* LINEOUT_VROI */ -#define WM9081_LINEOUT_CLAMP 0x0001 /* LINEOUT_CLAMP */ -#define WM9081_LINEOUT_CLAMP_MASK 0x0001 /* LINEOUT_CLAMP */ -#define WM9081_LINEOUT_CLAMP_SHIFT 0 /* LINEOUT_CLAMP */ -#define WM9081_LINEOUT_CLAMP_WIDTH 1 /* LINEOUT_CLAMP */ - -/* - * R9 (0x09) - Analogue Speaker 1 - */ -#define WM9081_SPK_DCGAIN_MASK 0x0038 /* SPK_DCGAIN - [5:3] */ -#define WM9081_SPK_DCGAIN_SHIFT 3 /* SPK_DCGAIN - [5:3] */ -#define WM9081_SPK_DCGAIN_WIDTH 3 /* SPK_DCGAIN - [5:3] */ -#define WM9081_SPK_ACGAIN_MASK 0x0007 /* SPK_ACGAIN - [2:0] */ -#define WM9081_SPK_ACGAIN_SHIFT 0 /* SPK_ACGAIN - [2:0] */ -#define WM9081_SPK_ACGAIN_WIDTH 3 /* SPK_ACGAIN - [2:0] */ - -/* - * R10 (0x0A) - Analogue Speaker 2 - */ -#define WM9081_SPK_MODE 0x0040 /* SPK_MODE */ -#define WM9081_SPK_MODE_MASK 0x0040 /* SPK_MODE */ -#define WM9081_SPK_MODE_SHIFT 6 /* SPK_MODE */ -#define WM9081_SPK_MODE_WIDTH 1 /* SPK_MODE */ -#define WM9081_SPK_INV_MUTE 0x0010 /* SPK_INV_MUTE */ -#define WM9081_SPK_INV_MUTE_MASK 0x0010 /* SPK_INV_MUTE */ -#define WM9081_SPK_INV_MUTE_SHIFT 4 /* SPK_INV_MUTE */ -#define WM9081_SPK_INV_MUTE_WIDTH 1 /* SPK_INV_MUTE */ -#define WM9081_OUT_SPK_CTRL 0x0008 /* OUT_SPK_CTRL */ -#define WM9081_OUT_SPK_CTRL_MASK 0x0008 /* OUT_SPK_CTRL */ -#define WM9081_OUT_SPK_CTRL_SHIFT 3 /* OUT_SPK_CTRL */ -#define WM9081_OUT_SPK_CTRL_WIDTH 1 /* OUT_SPK_CTRL */ - -/* - * R11 (0x0B) - Power Management - */ -#define WM9081_TSHUT_ENA 0x0100 /* TSHUT_ENA */ -#define WM9081_TSHUT_ENA_MASK 0x0100 /* TSHUT_ENA */ -#define WM9081_TSHUT_ENA_SHIFT 8 /* TSHUT_ENA */ -#define WM9081_TSHUT_ENA_WIDTH 1 /* TSHUT_ENA */ -#define WM9081_TSENSE_ENA 0x0080 /* TSENSE_ENA */ -#define WM9081_TSENSE_ENA_MASK 0x0080 /* TSENSE_ENA */ -#define WM9081_TSENSE_ENA_SHIFT 7 /* TSENSE_ENA */ -#define WM9081_TSENSE_ENA_WIDTH 1 /* TSENSE_ENA */ -#define WM9081_TEMP_SHUT 0x0040 /* TEMP_SHUT */ -#define WM9081_TEMP_SHUT_MASK 0x0040 /* TEMP_SHUT */ -#define WM9081_TEMP_SHUT_SHIFT 6 /* TEMP_SHUT */ -#define WM9081_TEMP_SHUT_WIDTH 1 /* TEMP_SHUT */ -#define WM9081_LINEOUT_ENA 0x0010 /* LINEOUT_ENA */ -#define WM9081_LINEOUT_ENA_MASK 0x0010 /* LINEOUT_ENA */ -#define WM9081_LINEOUT_ENA_SHIFT 4 /* LINEOUT_ENA */ -#define WM9081_LINEOUT_ENA_WIDTH 1 /* LINEOUT_ENA */ -#define WM9081_SPKPGA_ENA 0x0004 /* SPKPGA_ENA */ -#define WM9081_SPKPGA_ENA_MASK 0x0004 /* SPKPGA_ENA */ -#define WM9081_SPKPGA_ENA_SHIFT 2 /* SPKPGA_ENA */ -#define WM9081_SPKPGA_ENA_WIDTH 1 /* SPKPGA_ENA */ -#define WM9081_SPK_ENA 0x0002 /* SPK_ENA */ -#define WM9081_SPK_ENA_MASK 0x0002 /* SPK_ENA */ -#define WM9081_SPK_ENA_SHIFT 1 /* SPK_ENA */ -#define WM9081_SPK_ENA_WIDTH 1 /* SPK_ENA */ -#define WM9081_DAC_ENA 0x0001 /* DAC_ENA */ -#define WM9081_DAC_ENA_MASK 0x0001 /* DAC_ENA */ -#define WM9081_DAC_ENA_SHIFT 0 /* DAC_ENA */ -#define WM9081_DAC_ENA_WIDTH 1 /* DAC_ENA */ - -/* - * R12 (0x0C) - Clock Control 1 - */ -#define WM9081_CLK_OP_DIV_MASK 0x1C00 /* CLK_OP_DIV - [12:10] */ -#define WM9081_CLK_OP_DIV_SHIFT 10 /* CLK_OP_DIV - [12:10] */ -#define WM9081_CLK_OP_DIV_WIDTH 3 /* CLK_OP_DIV - [12:10] */ -#define WM9081_CLK_TO_DIV_MASK 0x0300 /* CLK_TO_DIV - [9:8] */ -#define WM9081_CLK_TO_DIV_SHIFT 8 /* CLK_TO_DIV - [9:8] */ -#define WM9081_CLK_TO_DIV_WIDTH 2 /* CLK_TO_DIV - [9:8] */ -#define WM9081_MCLKDIV2 0x0080 /* MCLKDIV2 */ -#define WM9081_MCLKDIV2_MASK 0x0080 /* MCLKDIV2 */ -#define WM9081_MCLKDIV2_SHIFT 7 /* MCLKDIV2 */ -#define WM9081_MCLKDIV2_WIDTH 1 /* MCLKDIV2 */ - -/* - * R13 (0x0D) - Clock Control 2 - */ -#define WM9081_CLK_SYS_RATE_MASK 0x00F0 /* CLK_SYS_RATE - [7:4] */ -#define WM9081_CLK_SYS_RATE_SHIFT 4 /* CLK_SYS_RATE - [7:4] */ -#define WM9081_CLK_SYS_RATE_WIDTH 4 /* CLK_SYS_RATE - [7:4] */ -#define WM9081_SAMPLE_RATE_MASK 0x000F /* SAMPLE_RATE - [3:0] */ -#define WM9081_SAMPLE_RATE_SHIFT 0 /* SAMPLE_RATE - [3:0] */ -#define WM9081_SAMPLE_RATE_WIDTH 4 /* SAMPLE_RATE - [3:0] */ - -/* - * R14 (0x0E) - Clock Control 3 - */ -#define WM9081_CLK_SRC_SEL 0x2000 /* CLK_SRC_SEL */ -#define WM9081_CLK_SRC_SEL_MASK 0x2000 /* CLK_SRC_SEL */ -#define WM9081_CLK_SRC_SEL_SHIFT 13 /* CLK_SRC_SEL */ -#define WM9081_CLK_SRC_SEL_WIDTH 1 /* CLK_SRC_SEL */ -#define WM9081_CLK_OP_ENA 0x0020 /* CLK_OP_ENA */ -#define WM9081_CLK_OP_ENA_MASK 0x0020 /* CLK_OP_ENA */ -#define WM9081_CLK_OP_ENA_SHIFT 5 /* CLK_OP_ENA */ -#define WM9081_CLK_OP_ENA_WIDTH 1 /* CLK_OP_ENA */ -#define WM9081_CLK_TO_ENA 0x0004 /* CLK_TO_ENA */ -#define WM9081_CLK_TO_ENA_MASK 0x0004 /* CLK_TO_ENA */ -#define WM9081_CLK_TO_ENA_SHIFT 2 /* CLK_TO_ENA */ -#define WM9081_CLK_TO_ENA_WIDTH 1 /* CLK_TO_ENA */ -#define WM9081_CLK_DSP_ENA 0x0002 /* CLK_DSP_ENA */ -#define WM9081_CLK_DSP_ENA_MASK 0x0002 /* CLK_DSP_ENA */ -#define WM9081_CLK_DSP_ENA_SHIFT 1 /* CLK_DSP_ENA */ -#define WM9081_CLK_DSP_ENA_WIDTH 1 /* CLK_DSP_ENA */ -#define WM9081_CLK_SYS_ENA 0x0001 /* CLK_SYS_ENA */ -#define WM9081_CLK_SYS_ENA_MASK 0x0001 /* CLK_SYS_ENA */ -#define WM9081_CLK_SYS_ENA_SHIFT 0 /* CLK_SYS_ENA */ -#define WM9081_CLK_SYS_ENA_WIDTH 1 /* CLK_SYS_ENA */ - -/* - * R16 (0x10) - FLL Control 1 - */ -#define WM9081_FLL_HOLD 0x0008 /* FLL_HOLD */ -#define WM9081_FLL_HOLD_MASK 0x0008 /* FLL_HOLD */ -#define WM9081_FLL_HOLD_SHIFT 3 /* FLL_HOLD */ -#define WM9081_FLL_HOLD_WIDTH 1 /* FLL_HOLD */ -#define WM9081_FLL_FRAC 0x0004 /* FLL_FRAC */ -#define WM9081_FLL_FRAC_MASK 0x0004 /* FLL_FRAC */ -#define WM9081_FLL_FRAC_SHIFT 2 /* FLL_FRAC */ -#define WM9081_FLL_FRAC_WIDTH 1 /* FLL_FRAC */ -#define WM9081_FLL_ENA 0x0001 /* FLL_ENA */ -#define WM9081_FLL_ENA_MASK 0x0001 /* FLL_ENA */ -#define WM9081_FLL_ENA_SHIFT 0 /* FLL_ENA */ -#define WM9081_FLL_ENA_WIDTH 1 /* FLL_ENA */ - -/* - * R17 (0x11) - FLL Control 2 - */ -#define WM9081_FLL_OUTDIV_MASK 0x0700 /* FLL_OUTDIV - [10:8] */ -#define WM9081_FLL_OUTDIV_SHIFT 8 /* FLL_OUTDIV - [10:8] */ -#define WM9081_FLL_OUTDIV_WIDTH 3 /* FLL_OUTDIV - [10:8] */ -#define WM9081_FLL_CTRL_RATE_MASK 0x0070 /* FLL_CTRL_RATE - [6:4] */ -#define WM9081_FLL_CTRL_RATE_SHIFT 4 /* FLL_CTRL_RATE - [6:4] */ -#define WM9081_FLL_CTRL_RATE_WIDTH 3 /* FLL_CTRL_RATE - [6:4] */ -#define WM9081_FLL_FRATIO_MASK 0x0007 /* FLL_FRATIO - [2:0] */ -#define WM9081_FLL_FRATIO_SHIFT 0 /* FLL_FRATIO - [2:0] */ -#define WM9081_FLL_FRATIO_WIDTH 3 /* FLL_FRATIO - [2:0] */ - -/* - * R18 (0x12) - FLL Control 3 - */ -#define WM9081_FLL_K_MASK 0xFFFF /* FLL_K - [15:0] */ -#define WM9081_FLL_K_SHIFT 0 /* FLL_K - [15:0] */ -#define WM9081_FLL_K_WIDTH 16 /* FLL_K - [15:0] */ - -/* - * R19 (0x13) - FLL Control 4 - */ -#define WM9081_FLL_N_MASK 0x7FE0 /* FLL_N - [14:5] */ -#define WM9081_FLL_N_SHIFT 5 /* FLL_N - [14:5] */ -#define WM9081_FLL_N_WIDTH 10 /* FLL_N - [14:5] */ -#define WM9081_FLL_GAIN_MASK 0x000F /* FLL_GAIN - [3:0] */ -#define WM9081_FLL_GAIN_SHIFT 0 /* FLL_GAIN - [3:0] */ -#define WM9081_FLL_GAIN_WIDTH 4 /* FLL_GAIN - [3:0] */ - -/* - * R20 (0x14) - FLL Control 5 - */ -#define WM9081_FLL_CLK_REF_DIV_MASK 0x0018 /* FLL_CLK_REF_DIV - [4:3] */ -#define WM9081_FLL_CLK_REF_DIV_SHIFT 3 /* FLL_CLK_REF_DIV - [4:3] */ -#define WM9081_FLL_CLK_REF_DIV_WIDTH 2 /* FLL_CLK_REF_DIV - [4:3] */ -#define WM9081_FLL_CLK_SRC_MASK 0x0003 /* FLL_CLK_SRC - [1:0] */ -#define WM9081_FLL_CLK_SRC_SHIFT 0 /* FLL_CLK_SRC - [1:0] */ -#define WM9081_FLL_CLK_SRC_WIDTH 2 /* FLL_CLK_SRC - [1:0] */ - -/* - * R22 (0x16) - Audio Interface 1 - */ -#define WM9081_AIFDAC_CHAN 0x0040 /* AIFDAC_CHAN */ -#define WM9081_AIFDAC_CHAN_MASK 0x0040 /* AIFDAC_CHAN */ -#define WM9081_AIFDAC_CHAN_SHIFT 6 /* AIFDAC_CHAN */ -#define WM9081_AIFDAC_CHAN_WIDTH 1 /* AIFDAC_CHAN */ -#define WM9081_AIFDAC_TDM_SLOT_MASK 0x0030 /* AIFDAC_TDM_SLOT - [5:4] */ -#define WM9081_AIFDAC_TDM_SLOT_SHIFT 4 /* AIFDAC_TDM_SLOT - [5:4] */ -#define WM9081_AIFDAC_TDM_SLOT_WIDTH 2 /* AIFDAC_TDM_SLOT - [5:4] */ -#define WM9081_AIFDAC_TDM_MODE_MASK 0x000C /* AIFDAC_TDM_MODE - [3:2] */ -#define WM9081_AIFDAC_TDM_MODE_SHIFT 2 /* AIFDAC_TDM_MODE - [3:2] */ -#define WM9081_AIFDAC_TDM_MODE_WIDTH 2 /* AIFDAC_TDM_MODE - [3:2] */ -#define WM9081_DAC_COMP 0x0002 /* DAC_COMP */ -#define WM9081_DAC_COMP_MASK 0x0002 /* DAC_COMP */ -#define WM9081_DAC_COMP_SHIFT 1 /* DAC_COMP */ -#define WM9081_DAC_COMP_WIDTH 1 /* DAC_COMP */ -#define WM9081_DAC_COMPMODE 0x0001 /* DAC_COMPMODE */ -#define WM9081_DAC_COMPMODE_MASK 0x0001 /* DAC_COMPMODE */ -#define WM9081_DAC_COMPMODE_SHIFT 0 /* DAC_COMPMODE */ -#define WM9081_DAC_COMPMODE_WIDTH 1 /* DAC_COMPMODE */ - -/* - * R23 (0x17) - Audio Interface 2 - */ -#define WM9081_AIF_TRIS 0x0200 /* AIF_TRIS */ -#define WM9081_AIF_TRIS_MASK 0x0200 /* AIF_TRIS */ -#define WM9081_AIF_TRIS_SHIFT 9 /* AIF_TRIS */ -#define WM9081_AIF_TRIS_WIDTH 1 /* AIF_TRIS */ -#define WM9081_DAC_DAT_INV 0x0100 /* DAC_DAT_INV */ -#define WM9081_DAC_DAT_INV_MASK 0x0100 /* DAC_DAT_INV */ -#define WM9081_DAC_DAT_INV_SHIFT 8 /* DAC_DAT_INV */ -#define WM9081_DAC_DAT_INV_WIDTH 1 /* DAC_DAT_INV */ -#define WM9081_AIF_BCLK_INV 0x0080 /* AIF_BCLK_INV */ -#define WM9081_AIF_BCLK_INV_MASK 0x0080 /* AIF_BCLK_INV */ -#define WM9081_AIF_BCLK_INV_SHIFT 7 /* AIF_BCLK_INV */ -#define WM9081_AIF_BCLK_INV_WIDTH 1 /* AIF_BCLK_INV */ -#define WM9081_BCLK_DIR 0x0040 /* BCLK_DIR */ -#define WM9081_BCLK_DIR_MASK 0x0040 /* BCLK_DIR */ -#define WM9081_BCLK_DIR_SHIFT 6 /* BCLK_DIR */ -#define WM9081_BCLK_DIR_WIDTH 1 /* BCLK_DIR */ -#define WM9081_LRCLK_DIR 0x0020 /* LRCLK_DIR */ -#define WM9081_LRCLK_DIR_MASK 0x0020 /* LRCLK_DIR */ -#define WM9081_LRCLK_DIR_SHIFT 5 /* LRCLK_DIR */ -#define WM9081_LRCLK_DIR_WIDTH 1 /* LRCLK_DIR */ -#define WM9081_AIF_LRCLK_INV 0x0010 /* AIF_LRCLK_INV */ -#define WM9081_AIF_LRCLK_INV_MASK 0x0010 /* AIF_LRCLK_INV */ -#define WM9081_AIF_LRCLK_INV_SHIFT 4 /* AIF_LRCLK_INV */ -#define WM9081_AIF_LRCLK_INV_WIDTH 1 /* AIF_LRCLK_INV */ -#define WM9081_AIF_WL_MASK 0x000C /* AIF_WL - [3:2] */ -#define WM9081_AIF_WL_SHIFT 2 /* AIF_WL - [3:2] */ -#define WM9081_AIF_WL_WIDTH 2 /* AIF_WL - [3:2] */ -#define WM9081_AIF_FMT_MASK 0x0003 /* AIF_FMT - [1:0] */ -#define WM9081_AIF_FMT_SHIFT 0 /* AIF_FMT - [1:0] */ -#define WM9081_AIF_FMT_WIDTH 2 /* AIF_FMT - [1:0] */ - -/* - * R24 (0x18) - Audio Interface 3 - */ -#define WM9081_BCLK_DIV_MASK 0x001F /* BCLK_DIV - [4:0] */ -#define WM9081_BCLK_DIV_SHIFT 0 /* BCLK_DIV - [4:0] */ -#define WM9081_BCLK_DIV_WIDTH 5 /* BCLK_DIV - [4:0] */ - -/* - * R25 (0x19) - Audio Interface 4 - */ -#define WM9081_LRCLK_RATE_MASK 0x07FF /* LRCLK_RATE - [10:0] */ -#define WM9081_LRCLK_RATE_SHIFT 0 /* LRCLK_RATE - [10:0] */ -#define WM9081_LRCLK_RATE_WIDTH 11 /* LRCLK_RATE - [10:0] */ - -/* - * R26 (0x1A) - Interrupt Status - */ -#define WM9081_WSEQ_BUSY_EINT 0x0004 /* WSEQ_BUSY_EINT */ -#define WM9081_WSEQ_BUSY_EINT_MASK 0x0004 /* WSEQ_BUSY_EINT */ -#define WM9081_WSEQ_BUSY_EINT_SHIFT 2 /* WSEQ_BUSY_EINT */ -#define WM9081_WSEQ_BUSY_EINT_WIDTH 1 /* WSEQ_BUSY_EINT */ -#define WM9081_TSHUT_EINT 0x0001 /* TSHUT_EINT */ -#define WM9081_TSHUT_EINT_MASK 0x0001 /* TSHUT_EINT */ -#define WM9081_TSHUT_EINT_SHIFT 0 /* TSHUT_EINT */ -#define WM9081_TSHUT_EINT_WIDTH 1 /* TSHUT_EINT */ - -/* - * R27 (0x1B) - Interrupt Status Mask - */ -#define WM9081_IM_WSEQ_BUSY_EINT 0x0004 /* IM_WSEQ_BUSY_EINT */ -#define WM9081_IM_WSEQ_BUSY_EINT_MASK 0x0004 /* IM_WSEQ_BUSY_EINT */ -#define WM9081_IM_WSEQ_BUSY_EINT_SHIFT 2 /* IM_WSEQ_BUSY_EINT */ -#define WM9081_IM_WSEQ_BUSY_EINT_WIDTH 1 /* IM_WSEQ_BUSY_EINT */ -#define WM9081_IM_TSHUT_EINT 0x0001 /* IM_TSHUT_EINT */ -#define WM9081_IM_TSHUT_EINT_MASK 0x0001 /* IM_TSHUT_EINT */ -#define WM9081_IM_TSHUT_EINT_SHIFT 0 /* IM_TSHUT_EINT */ -#define WM9081_IM_TSHUT_EINT_WIDTH 1 /* IM_TSHUT_EINT */ - -/* - * R28 (0x1C) - Interrupt Polarity - */ -#define WM9081_TSHUT_INV 0x0001 /* TSHUT_INV */ -#define WM9081_TSHUT_INV_MASK 0x0001 /* TSHUT_INV */ -#define WM9081_TSHUT_INV_SHIFT 0 /* TSHUT_INV */ -#define WM9081_TSHUT_INV_WIDTH 1 /* TSHUT_INV */ - -/* - * R29 (0x1D) - Interrupt Control - */ -#define WM9081_IRQ_POL 0x8000 /* IRQ_POL */ -#define WM9081_IRQ_POL_MASK 0x8000 /* IRQ_POL */ -#define WM9081_IRQ_POL_SHIFT 15 /* IRQ_POL */ -#define WM9081_IRQ_POL_WIDTH 1 /* IRQ_POL */ -#define WM9081_IRQ_OP_CTRL 0x0001 /* IRQ_OP_CTRL */ -#define WM9081_IRQ_OP_CTRL_MASK 0x0001 /* IRQ_OP_CTRL */ -#define WM9081_IRQ_OP_CTRL_SHIFT 0 /* IRQ_OP_CTRL */ -#define WM9081_IRQ_OP_CTRL_WIDTH 1 /* IRQ_OP_CTRL */ - -/* - * R30 (0x1E) - DAC Digital 1 - */ -#define WM9081_DAC_VOL_MASK 0x00FF /* DAC_VOL - [7:0] */ -#define WM9081_DAC_VOL_SHIFT 0 /* DAC_VOL - [7:0] */ -#define WM9081_DAC_VOL_WIDTH 8 /* DAC_VOL - [7:0] */ - -/* - * R31 (0x1F) - DAC Digital 2 - */ -#define WM9081_DAC_MUTERATE 0x0400 /* DAC_MUTERATE */ -#define WM9081_DAC_MUTERATE_MASK 0x0400 /* DAC_MUTERATE */ -#define WM9081_DAC_MUTERATE_SHIFT 10 /* DAC_MUTERATE */ -#define WM9081_DAC_MUTERATE_WIDTH 1 /* DAC_MUTERATE */ -#define WM9081_DAC_MUTEMODE 0x0200 /* DAC_MUTEMODE */ -#define WM9081_DAC_MUTEMODE_MASK 0x0200 /* DAC_MUTEMODE */ -#define WM9081_DAC_MUTEMODE_SHIFT 9 /* DAC_MUTEMODE */ -#define WM9081_DAC_MUTEMODE_WIDTH 1 /* DAC_MUTEMODE */ -#define WM9081_DAC_MUTE 0x0008 /* DAC_MUTE */ -#define WM9081_DAC_MUTE_MASK 0x0008 /* DAC_MUTE */ -#define WM9081_DAC_MUTE_SHIFT 3 /* DAC_MUTE */ -#define WM9081_DAC_MUTE_WIDTH 1 /* DAC_MUTE */ -#define WM9081_DEEMPH_MASK 0x0006 /* DEEMPH - [2:1] */ -#define WM9081_DEEMPH_SHIFT 1 /* DEEMPH - [2:1] */ -#define WM9081_DEEMPH_WIDTH 2 /* DEEMPH - [2:1] */ - -/* - * R32 (0x20) - DRC 1 - */ -#define WM9081_DRC_ENA 0x8000 /* DRC_ENA */ -#define WM9081_DRC_ENA_MASK 0x8000 /* DRC_ENA */ -#define WM9081_DRC_ENA_SHIFT 15 /* DRC_ENA */ -#define WM9081_DRC_ENA_WIDTH 1 /* DRC_ENA */ -#define WM9081_DRC_STARTUP_GAIN_MASK 0x07C0 /* DRC_STARTUP_GAIN - [10:6] */ -#define WM9081_DRC_STARTUP_GAIN_SHIFT 6 /* DRC_STARTUP_GAIN - [10:6] */ -#define WM9081_DRC_STARTUP_GAIN_WIDTH 5 /* DRC_STARTUP_GAIN - [10:6] */ -#define WM9081_DRC_FF_DLY 0x0020 /* DRC_FF_DLY */ -#define WM9081_DRC_FF_DLY_MASK 0x0020 /* DRC_FF_DLY */ -#define WM9081_DRC_FF_DLY_SHIFT 5 /* DRC_FF_DLY */ -#define WM9081_DRC_FF_DLY_WIDTH 1 /* DRC_FF_DLY */ -#define WM9081_DRC_QR 0x0004 /* DRC_QR */ -#define WM9081_DRC_QR_MASK 0x0004 /* DRC_QR */ -#define WM9081_DRC_QR_SHIFT 2 /* DRC_QR */ -#define WM9081_DRC_QR_WIDTH 1 /* DRC_QR */ -#define WM9081_DRC_ANTICLIP 0x0002 /* DRC_ANTICLIP */ -#define WM9081_DRC_ANTICLIP_MASK 0x0002 /* DRC_ANTICLIP */ -#define WM9081_DRC_ANTICLIP_SHIFT 1 /* DRC_ANTICLIP */ -#define WM9081_DRC_ANTICLIP_WIDTH 1 /* DRC_ANTICLIP */ - -/* - * R33 (0x21) - DRC 2 - */ -#define WM9081_DRC_ATK_MASK 0xF000 /* DRC_ATK - [15:12] */ -#define WM9081_DRC_ATK_SHIFT 12 /* DRC_ATK - [15:12] */ -#define WM9081_DRC_ATK_WIDTH 4 /* DRC_ATK - [15:12] */ -#define WM9081_DRC_DCY_MASK 0x0F00 /* DRC_DCY - [11:8] */ -#define WM9081_DRC_DCY_SHIFT 8 /* DRC_DCY - [11:8] */ -#define WM9081_DRC_DCY_WIDTH 4 /* DRC_DCY - [11:8] */ -#define WM9081_DRC_QR_THR_MASK 0x00C0 /* DRC_QR_THR - [7:6] */ -#define WM9081_DRC_QR_THR_SHIFT 6 /* DRC_QR_THR - [7:6] */ -#define WM9081_DRC_QR_THR_WIDTH 2 /* DRC_QR_THR - [7:6] */ -#define WM9081_DRC_QR_DCY_MASK 0x0030 /* DRC_QR_DCY - [5:4] */ -#define WM9081_DRC_QR_DCY_SHIFT 4 /* DRC_QR_DCY - [5:4] */ -#define WM9081_DRC_QR_DCY_WIDTH 2 /* DRC_QR_DCY - [5:4] */ -#define WM9081_DRC_MINGAIN_MASK 0x000C /* DRC_MINGAIN - [3:2] */ -#define WM9081_DRC_MINGAIN_SHIFT 2 /* DRC_MINGAIN - [3:2] */ -#define WM9081_DRC_MINGAIN_WIDTH 2 /* DRC_MINGAIN - [3:2] */ -#define WM9081_DRC_MAXGAIN_MASK 0x0003 /* DRC_MAXGAIN - [1:0] */ -#define WM9081_DRC_MAXGAIN_SHIFT 0 /* DRC_MAXGAIN - [1:0] */ -#define WM9081_DRC_MAXGAIN_WIDTH 2 /* DRC_MAXGAIN - [1:0] */ - -/* - * R34 (0x22) - DRC 3 - */ -#define WM9081_DRC_HI_COMP_MASK 0x0038 /* DRC_HI_COMP - [5:3] */ -#define WM9081_DRC_HI_COMP_SHIFT 3 /* DRC_HI_COMP - [5:3] */ -#define WM9081_DRC_HI_COMP_WIDTH 3 /* DRC_HI_COMP - [5:3] */ -#define WM9081_DRC_LO_COMP_MASK 0x0007 /* DRC_LO_COMP - [2:0] */ -#define WM9081_DRC_LO_COMP_SHIFT 0 /* DRC_LO_COMP - [2:0] */ -#define WM9081_DRC_LO_COMP_WIDTH 3 /* DRC_LO_COMP - [2:0] */ - -/* - * R35 (0x23) - DRC 4 - */ -#define WM9081_DRC_KNEE_IP_MASK 0x07E0 /* DRC_KNEE_IP - [10:5] */ -#define WM9081_DRC_KNEE_IP_SHIFT 5 /* DRC_KNEE_IP - [10:5] */ -#define WM9081_DRC_KNEE_IP_WIDTH 6 /* DRC_KNEE_IP - [10:5] */ -#define WM9081_DRC_KNEE_OP_MASK 0x001F /* DRC_KNEE_OP - [4:0] */ -#define WM9081_DRC_KNEE_OP_SHIFT 0 /* DRC_KNEE_OP - [4:0] */ -#define WM9081_DRC_KNEE_OP_WIDTH 5 /* DRC_KNEE_OP - [4:0] */ - -/* - * R38 (0x26) - Write Sequencer 1 - */ -#define WM9081_WSEQ_ENA 0x8000 /* WSEQ_ENA */ -#define WM9081_WSEQ_ENA_MASK 0x8000 /* WSEQ_ENA */ -#define WM9081_WSEQ_ENA_SHIFT 15 /* WSEQ_ENA */ -#define WM9081_WSEQ_ENA_WIDTH 1 /* WSEQ_ENA */ -#define WM9081_WSEQ_ABORT 0x0200 /* WSEQ_ABORT */ -#define WM9081_WSEQ_ABORT_MASK 0x0200 /* WSEQ_ABORT */ -#define WM9081_WSEQ_ABORT_SHIFT 9 /* WSEQ_ABORT */ -#define WM9081_WSEQ_ABORT_WIDTH 1 /* WSEQ_ABORT */ -#define WM9081_WSEQ_START 0x0100 /* WSEQ_START */ -#define WM9081_WSEQ_START_MASK 0x0100 /* WSEQ_START */ -#define WM9081_WSEQ_START_SHIFT 8 /* WSEQ_START */ -#define WM9081_WSEQ_START_WIDTH 1 /* WSEQ_START */ -#define WM9081_WSEQ_START_INDEX_MASK 0x007F /* WSEQ_START_INDEX - [6:0] */ -#define WM9081_WSEQ_START_INDEX_SHIFT 0 /* WSEQ_START_INDEX - [6:0] */ -#define WM9081_WSEQ_START_INDEX_WIDTH 7 /* WSEQ_START_INDEX - [6:0] */ - -/* - * R39 (0x27) - Write Sequencer 2 - */ -#define WM9081_WSEQ_CURRENT_INDEX_MASK 0x07F0 /* WSEQ_CURRENT_INDEX - [10:4] */ -#define WM9081_WSEQ_CURRENT_INDEX_SHIFT 4 /* WSEQ_CURRENT_INDEX - [10:4] */ -#define WM9081_WSEQ_CURRENT_INDEX_WIDTH 7 /* WSEQ_CURRENT_INDEX - [10:4] */ -#define WM9081_WSEQ_BUSY 0x0001 /* WSEQ_BUSY */ -#define WM9081_WSEQ_BUSY_MASK 0x0001 /* WSEQ_BUSY */ -#define WM9081_WSEQ_BUSY_SHIFT 0 /* WSEQ_BUSY */ -#define WM9081_WSEQ_BUSY_WIDTH 1 /* WSEQ_BUSY */ - -/* - * R40 (0x28) - MW Slave 1 - */ -#define WM9081_SPI_CFG 0x0020 /* SPI_CFG */ -#define WM9081_SPI_CFG_MASK 0x0020 /* SPI_CFG */ -#define WM9081_SPI_CFG_SHIFT 5 /* SPI_CFG */ -#define WM9081_SPI_CFG_WIDTH 1 /* SPI_CFG */ -#define WM9081_SPI_4WIRE 0x0010 /* SPI_4WIRE */ -#define WM9081_SPI_4WIRE_MASK 0x0010 /* SPI_4WIRE */ -#define WM9081_SPI_4WIRE_SHIFT 4 /* SPI_4WIRE */ -#define WM9081_SPI_4WIRE_WIDTH 1 /* SPI_4WIRE */ -#define WM9081_ARA_ENA 0x0008 /* ARA_ENA */ -#define WM9081_ARA_ENA_MASK 0x0008 /* ARA_ENA */ -#define WM9081_ARA_ENA_SHIFT 3 /* ARA_ENA */ -#define WM9081_ARA_ENA_WIDTH 1 /* ARA_ENA */ -#define WM9081_AUTO_INC 0x0002 /* AUTO_INC */ -#define WM9081_AUTO_INC_MASK 0x0002 /* AUTO_INC */ -#define WM9081_AUTO_INC_SHIFT 1 /* AUTO_INC */ -#define WM9081_AUTO_INC_WIDTH 1 /* AUTO_INC */ - -/* - * R42 (0x2A) - EQ 1 - */ -#define WM9081_EQ_B1_GAIN_MASK 0xF800 /* EQ_B1_GAIN - [15:11] */ -#define WM9081_EQ_B1_GAIN_SHIFT 11 /* EQ_B1_GAIN - [15:11] */ -#define WM9081_EQ_B1_GAIN_WIDTH 5 /* EQ_B1_GAIN - [15:11] */ -#define WM9081_EQ_B2_GAIN_MASK 0x07C0 /* EQ_B2_GAIN - [10:6] */ -#define WM9081_EQ_B2_GAIN_SHIFT 6 /* EQ_B2_GAIN - [10:6] */ -#define WM9081_EQ_B2_GAIN_WIDTH 5 /* EQ_B2_GAIN - [10:6] */ -#define WM9081_EQ_B4_GAIN_MASK 0x003E /* EQ_B4_GAIN - [5:1] */ -#define WM9081_EQ_B4_GAIN_SHIFT 1 /* EQ_B4_GAIN - [5:1] */ -#define WM9081_EQ_B4_GAIN_WIDTH 5 /* EQ_B4_GAIN - [5:1] */ -#define WM9081_EQ_ENA 0x0001 /* EQ_ENA */ -#define WM9081_EQ_ENA_MASK 0x0001 /* EQ_ENA */ -#define WM9081_EQ_ENA_SHIFT 0 /* EQ_ENA */ -#define WM9081_EQ_ENA_WIDTH 1 /* EQ_ENA */ - -/* - * R43 (0x2B) - EQ 2 - */ -#define WM9081_EQ_B3_GAIN_MASK 0xF800 /* EQ_B3_GAIN - [15:11] */ -#define WM9081_EQ_B3_GAIN_SHIFT 11 /* EQ_B3_GAIN - [15:11] */ -#define WM9081_EQ_B3_GAIN_WIDTH 5 /* EQ_B3_GAIN - [15:11] */ -#define WM9081_EQ_B5_GAIN_MASK 0x07C0 /* EQ_B5_GAIN - [10:6] */ -#define WM9081_EQ_B5_GAIN_SHIFT 6 /* EQ_B5_GAIN - [10:6] */ -#define WM9081_EQ_B5_GAIN_WIDTH 5 /* EQ_B5_GAIN - [10:6] */ - -/* - * R44 (0x2C) - EQ 3 - */ -#define WM9081_EQ_B1_A_MASK 0xFFFF /* EQ_B1_A - [15:0] */ -#define WM9081_EQ_B1_A_SHIFT 0 /* EQ_B1_A - [15:0] */ -#define WM9081_EQ_B1_A_WIDTH 16 /* EQ_B1_A - [15:0] */ - -/* - * R45 (0x2D) - EQ 4 - */ -#define WM9081_EQ_B1_B_MASK 0xFFFF /* EQ_B1_B - [15:0] */ -#define WM9081_EQ_B1_B_SHIFT 0 /* EQ_B1_B - [15:0] */ -#define WM9081_EQ_B1_B_WIDTH 16 /* EQ_B1_B - [15:0] */ - -/* - * R46 (0x2E) - EQ 5 - */ -#define WM9081_EQ_B1_PG_MASK 0xFFFF /* EQ_B1_PG - [15:0] */ -#define WM9081_EQ_B1_PG_SHIFT 0 /* EQ_B1_PG - [15:0] */ -#define WM9081_EQ_B1_PG_WIDTH 16 /* EQ_B1_PG - [15:0] */ - -/* - * R47 (0x2F) - EQ 6 - */ -#define WM9081_EQ_B2_A_MASK 0xFFFF /* EQ_B2_A - [15:0] */ -#define WM9081_EQ_B2_A_SHIFT 0 /* EQ_B2_A - [15:0] */ -#define WM9081_EQ_B2_A_WIDTH 16 /* EQ_B2_A - [15:0] */ - -/* - * R48 (0x30) - EQ 7 - */ -#define WM9081_EQ_B2_B_MASK 0xFFFF /* EQ_B2_B - [15:0] */ -#define WM9081_EQ_B2_B_SHIFT 0 /* EQ_B2_B - [15:0] */ -#define WM9081_EQ_B2_B_WIDTH 16 /* EQ_B2_B - [15:0] */ - -/* - * R49 (0x31) - EQ 8 - */ -#define WM9081_EQ_B2_C_MASK 0xFFFF /* EQ_B2_C - [15:0] */ -#define WM9081_EQ_B2_C_SHIFT 0 /* EQ_B2_C - [15:0] */ -#define WM9081_EQ_B2_C_WIDTH 16 /* EQ_B2_C - [15:0] */ - -/* - * R50 (0x32) - EQ 9 - */ -#define WM9081_EQ_B2_PG_MASK 0xFFFF /* EQ_B2_PG - [15:0] */ -#define WM9081_EQ_B2_PG_SHIFT 0 /* EQ_B2_PG - [15:0] */ -#define WM9081_EQ_B2_PG_WIDTH 16 /* EQ_B2_PG - [15:0] */ - -/* - * R51 (0x33) - EQ 10 - */ -#define WM9081_EQ_B4_A_MASK 0xFFFF /* EQ_B4_A - [15:0] */ -#define WM9081_EQ_B4_A_SHIFT 0 /* EQ_B4_A - [15:0] */ -#define WM9081_EQ_B4_A_WIDTH 16 /* EQ_B4_A - [15:0] */ - -/* - * R52 (0x34) - EQ 11 - */ -#define WM9081_EQ_B4_B_MASK 0xFFFF /* EQ_B4_B - [15:0] */ -#define WM9081_EQ_B4_B_SHIFT 0 /* EQ_B4_B - [15:0] */ -#define WM9081_EQ_B4_B_WIDTH 16 /* EQ_B4_B - [15:0] */ - -/* - * R53 (0x35) - EQ 12 - */ -#define WM9081_EQ_B4_C_MASK 0xFFFF /* EQ_B4_C - [15:0] */ -#define WM9081_EQ_B4_C_SHIFT 0 /* EQ_B4_C - [15:0] */ -#define WM9081_EQ_B4_C_WIDTH 16 /* EQ_B4_C - [15:0] */ - -/* - * R54 (0x36) - EQ 13 - */ -#define WM9081_EQ_B4_PG_MASK 0xFFFF /* EQ_B4_PG - [15:0] */ -#define WM9081_EQ_B4_PG_SHIFT 0 /* EQ_B4_PG - [15:0] */ -#define WM9081_EQ_B4_PG_WIDTH 16 /* EQ_B4_PG - [15:0] */ - -/* - * R55 (0x37) - EQ 14 - */ -#define WM9081_EQ_B3_A_MASK 0xFFFF /* EQ_B3_A - [15:0] */ -#define WM9081_EQ_B3_A_SHIFT 0 /* EQ_B3_A - [15:0] */ -#define WM9081_EQ_B3_A_WIDTH 16 /* EQ_B3_A - [15:0] */ - -/* - * R56 (0x38) - EQ 15 - */ -#define WM9081_EQ_B3_B_MASK 0xFFFF /* EQ_B3_B - [15:0] */ -#define WM9081_EQ_B3_B_SHIFT 0 /* EQ_B3_B - [15:0] */ -#define WM9081_EQ_B3_B_WIDTH 16 /* EQ_B3_B - [15:0] */ - -/* - * R57 (0x39) - EQ 16 - */ -#define WM9081_EQ_B3_C_MASK 0xFFFF /* EQ_B3_C - [15:0] */ -#define WM9081_EQ_B3_C_SHIFT 0 /* EQ_B3_C - [15:0] */ -#define WM9081_EQ_B3_C_WIDTH 16 /* EQ_B3_C - [15:0] */ - -/* - * R58 (0x3A) - EQ 17 - */ -#define WM9081_EQ_B3_PG_MASK 0xFFFF /* EQ_B3_PG - [15:0] */ -#define WM9081_EQ_B3_PG_SHIFT 0 /* EQ_B3_PG - [15:0] */ -#define WM9081_EQ_B3_PG_WIDTH 16 /* EQ_B3_PG - [15:0] */ - -/* - * R59 (0x3B) - EQ 18 - */ -#define WM9081_EQ_B5_A_MASK 0xFFFF /* EQ_B5_A - [15:0] */ -#define WM9081_EQ_B5_A_SHIFT 0 /* EQ_B5_A - [15:0] */ -#define WM9081_EQ_B5_A_WIDTH 16 /* EQ_B5_A - [15:0] */ - -/* - * R60 (0x3C) - EQ 19 - */ -#define WM9081_EQ_B5_B_MASK 0xFFFF /* EQ_B5_B - [15:0] */ -#define WM9081_EQ_B5_B_SHIFT 0 /* EQ_B5_B - [15:0] */ -#define WM9081_EQ_B5_B_WIDTH 16 /* EQ_B5_B - [15:0] */ - -/* - * R61 (0x3D) - EQ 20 - */ -#define WM9081_EQ_B5_PG_MASK 0xFFFF /* EQ_B5_PG - [15:0] */ -#define WM9081_EQ_B5_PG_SHIFT 0 /* EQ_B5_PG - [15:0] */ -#define WM9081_EQ_B5_PG_WIDTH 16 /* EQ_B5_PG - [15:0] */ - - -#endif diff --git a/trunk/sound/soc/codecs/wm9705.c b/trunk/sound/soc/codecs/wm9705.c index fa88b463e71f..c2d1a7a18fa3 100644 --- a/trunk/sound/soc/codecs/wm9705.c +++ b/trunk/sound/soc/codecs/wm9705.c @@ -282,14 +282,14 @@ struct snd_soc_dai wm9705_dai[] = { .channels_min = 1, .channels_max = 2, .rates = WM9705_AC97_RATES, - .formats = SND_SOC_STD_AC97_FMTS, + .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .capture = { .stream_name = "HiFi Capture", .channels_min = 1, .channels_max = 2, .rates = WM9705_AC97_RATES, - .formats = SND_SOC_STD_AC97_FMTS, + .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .ops = &wm9705_dai_ops, }, diff --git a/trunk/sound/soc/codecs/wm9712.c b/trunk/sound/soc/codecs/wm9712.c index 1fd4e88f50cf..765cf1e7369e 100644 --- a/trunk/sound/soc/codecs/wm9712.c +++ b/trunk/sound/soc/codecs/wm9712.c @@ -534,13 +534,13 @@ struct snd_soc_dai wm9712_dai[] = { .channels_min = 1, .channels_max = 2, .rates = WM9712_AC97_RATES, - .formats = SND_SOC_STD_AC97_FMTS,}, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .capture = { .stream_name = "HiFi Capture", .channels_min = 1, .channels_max = 2, .rates = WM9712_AC97_RATES, - .formats = SND_SOC_STD_AC97_FMTS,}, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = &wm9712_dai_ops_hifi, }, { @@ -550,7 +550,7 @@ struct snd_soc_dai wm9712_dai[] = { .channels_min = 1, .channels_max = 1, .rates = WM9712_AC97_RATES, - .formats = SND_SOC_STD_AC97_FMTS,}, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = &wm9712_dai_ops_aux, } }; @@ -585,8 +585,6 @@ static int wm9712_reset(struct snd_soc_codec *codec, int try_warm) } soc_ac97_ops.reset(codec->ac97); - if (soc_ac97_ops.warm_reset) - soc_ac97_ops.warm_reset(codec->ac97); if (ac97_read(codec, 0) != wm9712_reg[0]) goto err; return 0; diff --git a/trunk/sound/soc/codecs/wm9713.c b/trunk/sound/soc/codecs/wm9713.c index abed37acf787..523bad077fa0 100644 --- a/trunk/sound/soc/codecs/wm9713.c +++ b/trunk/sound/soc/codecs/wm9713.c @@ -189,26 +189,6 @@ SOC_SINGLE("3D Lower Cut-off Switch", AC97_REC_GAIN_MIC, 4, 1, 0), SOC_SINGLE("3D Depth", AC97_REC_GAIN_MIC, 0, 15, 1), }; -static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_codec *codec = w->codec; - u16 status, rate; - - BUG_ON(event != SND_SOC_DAPM_PRE_PMD); - - /* Gracefully shut down the voice interface. */ - status = ac97_read(codec, AC97_EXTENDED_MID) | 0x1000; - rate = ac97_read(codec, AC97_HANDSET_RATE) & 0xF0FF; - ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0200); - schedule_timeout_interruptible(msecs_to_jiffies(1)); - ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0F00); - ac97_write(codec, AC97_EXTENDED_MID, status); - - return 0; -} - - /* We have to create a fake left and right HP mixers because * the codec only has a single control that is shared by both channels. * This makes it impossible to determine the audio path using the current @@ -420,8 +400,7 @@ SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("HP Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("Line Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("Capture Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), -SND_SOC_DAPM_DAC_E("Voice DAC", "Voice Playback", AC97_EXTENDED_MID, 12, 1, - wm9713_voice_shutdown, SND_SOC_DAPM_PRE_PMD), +SND_SOC_DAPM_DAC("Voice DAC", "Voice Playback", AC97_EXTENDED_MID, 12, 1), SND_SOC_DAPM_DAC("Aux DAC", "Aux Playback", AC97_EXTENDED_MID, 11, 1), SND_SOC_DAPM_PGA("Left ADC", AC97_EXTENDED_MID, 5, 1, NULL, 0), SND_SOC_DAPM_PGA("Right ADC", AC97_EXTENDED_MID, 4, 1, NULL, 0), @@ -710,7 +689,7 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int source) Ndiv = target / source; if ((Ndiv < 5) || (Ndiv > 12)) printk(KERN_WARNING - "WM9713 PLL N value %u out of recommended range!\n", + "WM9713 PLL N value %d out of recommended range!\n", Ndiv); pll_div->n = Ndiv; @@ -957,6 +936,21 @@ static int wm9713_pcm_hw_params(struct snd_pcm_substream *substream, return 0; } +static void wm9713_voiceshutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + u16 status, rate; + + /* Gracefully shut down the voice interface. */ + status = ac97_read(codec, AC97_EXTENDED_STATUS) | 0x1000; + rate = ac97_read(codec, AC97_HANDSET_RATE) & 0xF0FF; + ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0200); + schedule_timeout_interruptible(msecs_to_jiffies(1)); + ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0F00); + ac97_write(codec, AC97_EXTENDED_MID, status); +} + static int ac97_hifi_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -1025,6 +1019,7 @@ static struct snd_soc_dai_ops wm9713_dai_ops_aux = { static struct snd_soc_dai_ops wm9713_dai_ops_voice = { .hw_params = wm9713_pcm_hw_params, + .shutdown = wm9713_voiceshutdown, .set_clkdiv = wm9713_set_dai_clkdiv, .set_pll = wm9713_set_dai_pll, .set_fmt = wm9713_set_dai_fmt, @@ -1040,13 +1035,13 @@ struct snd_soc_dai wm9713_dai[] = { .channels_min = 1, .channels_max = 2, .rates = WM9713_RATES, - .formats = SND_SOC_STD_AC97_FMTS,}, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .capture = { .stream_name = "HiFi Capture", .channels_min = 1, .channels_max = 2, .rates = WM9713_RATES, - .formats = SND_SOC_STD_AC97_FMTS,}, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = &wm9713_dai_ops_hifi, }, { @@ -1056,7 +1051,7 @@ struct snd_soc_dai wm9713_dai[] = { .channels_min = 1, .channels_max = 1, .rates = WM9713_RATES, - .formats = SND_SOC_STD_AC97_FMTS,}, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = &wm9713_dai_ops_aux, }, { @@ -1074,7 +1069,6 @@ struct snd_soc_dai wm9713_dai[] = { .rates = WM9713_PCM_RATES, .formats = WM9713_PCM_FORMATS,}, .ops = &wm9713_dai_ops_voice, - .symmetric_rates = 1, }, }; EXPORT_SYMBOL_GPL(wm9713_dai); diff --git a/trunk/sound/soc/fsl/Kconfig b/trunk/sound/soc/fsl/Kconfig index 5dbebf82249c..9fc908283371 100644 --- a/trunk/sound/soc/fsl/Kconfig +++ b/trunk/sound/soc/fsl/Kconfig @@ -1,8 +1,5 @@ config SND_SOC_OF_SIMPLE tristate - -config SND_MPC52xx_DMA - tristate # ASoC platform support for the Freescale MPC8610 SOC. This compiles drivers # for the SSI and the Elo DMA controller. You will still need to select @@ -25,34 +22,7 @@ config SND_SOC_MPC8610_HPCD config SND_SOC_MPC5200_I2S tristate "Freescale MPC5200 PSC in I2S mode driver" depends on PPC_MPC52xx && PPC_BESTCOMM - select SND_MPC52xx_DMA + select SND_SOC_OF_SIMPLE select PPC_BESTCOMM_GEN_BD help Say Y here to support the MPC5200 PSCs in I2S mode. - -config SND_SOC_MPC5200_AC97 - tristate "Freescale MPC5200 PSC in AC97 mode driver" - depends on PPC_MPC52xx && PPC_BESTCOMM - select AC97_BUS - select SND_MPC52xx_DMA - select PPC_BESTCOMM_GEN_BD - help - Say Y here to support the MPC5200 PSCs in AC97 mode. - -config SND_MPC52xx_SOC_PCM030 - tristate "SoC AC97 Audio support for Phytec pcm030 and WM9712" - depends on PPC_MPC5200_SIMPLE && BROKEN - select SND_SOC_MPC5200_AC97 - select SND_SOC_WM9712 - help - Say Y if you want to add support for sound on the Phytec pcm030 - baseboard. - -config SND_MPC52xx_SOC_EFIKA - tristate "SoC AC97 Audio support for bbplan Efika and STAC9766" - depends on PPC_EFIKA && BROKEN - select SND_SOC_MPC5200_AC97 - select SND_SOC_STAC9766 - help - Say Y if you want to add support for sound on the Efika. - diff --git a/trunk/sound/soc/fsl/Makefile b/trunk/sound/soc/fsl/Makefile index a83a73967ec6..f85134c86387 100644 --- a/trunk/sound/soc/fsl/Makefile +++ b/trunk/sound/soc/fsl/Makefile @@ -10,12 +10,5 @@ snd-soc-fsl-ssi-objs := fsl_ssi.o snd-soc-fsl-dma-objs := fsl_dma.o obj-$(CONFIG_SND_SOC_MPC8610) += snd-soc-fsl-ssi.o snd-soc-fsl-dma.o -# MPC5200 Platform Support -obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o obj-$(CONFIG_SND_SOC_MPC5200_I2S) += mpc5200_psc_i2s.o -obj-$(CONFIG_SND_SOC_MPC5200_AC97) += mpc5200_psc_ac97.o - -# MPC5200 Machine Support -obj-$(CONFIG_SND_MPC52xx_SOC_PCM030) += pcm030-audio-fabric.o -obj-$(CONFIG_SND_MPC52xx_SOC_EFIKA) += efika-audio-fabric.o diff --git a/trunk/sound/soc/fsl/efika-audio-fabric.c b/trunk/sound/soc/fsl/efika-audio-fabric.c deleted file mode 100644 index 85b0e7569504..000000000000 --- a/trunk/sound/soc/fsl/efika-audio-fabric.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Efika driver for the PSC of the Freescale MPC52xx - * configured as AC97 interface - * - * Copyright 2008 Jon Smirl, Digispeaker - * Author: Jon Smirl - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "mpc5200_dma.h" -#include "mpc5200_psc_ac97.h" -#include "../codecs/stac9766.h" - -static struct snd_soc_device device; -static struct snd_soc_card card; - -static struct snd_soc_dai_link efika_fabric_dai[] = { -{ - .name = "AC97", - .stream_name = "AC97 Analog", - .codec_dai = &stac9766_dai[STAC9766_DAI_AC97_ANALOG], - .cpu_dai = &psc_ac97_dai[MPC5200_AC97_NORMAL], -}, -{ - .name = "AC97", - .stream_name = "AC97 IEC958", - .codec_dai = &stac9766_dai[STAC9766_DAI_AC97_DIGITAL], - .cpu_dai = &psc_ac97_dai[MPC5200_AC97_SPDIF], -}, -}; - -static __init int efika_fabric_init(void) -{ - struct platform_device *pdev; - int rc; - - if (!machine_is_compatible("bplan,efika")) - return -ENODEV; - - card.platform = &mpc5200_audio_dma_platform; - card.name = "Efika"; - card.dai_link = efika_fabric_dai; - card.num_links = ARRAY_SIZE(efika_fabric_dai); - - device.card = &card; - device.codec_dev = &soc_codec_dev_stac9766; - - pdev = platform_device_alloc("soc-audio", 1); - if (!pdev) { - pr_err("efika_fabric_init: platform_device_alloc() failed\n"); - return -ENODEV; - } - - platform_set_drvdata(pdev, &device); - device.dev = &pdev->dev; - - rc = platform_device_add(pdev); - if (rc) { - pr_err("efika_fabric_init: platform_device_add() failed\n"); - return -ENODEV; - } - return 0; -} - -module_init(efika_fabric_init); - - -MODULE_AUTHOR("Jon Smirl "); -MODULE_DESCRIPTION(DRV_NAME ": mpc5200 Efika fabric driver"); -MODULE_LICENSE("GPL"); - diff --git a/trunk/sound/soc/fsl/fsl_ssi.c b/trunk/sound/soc/fsl/fsl_ssi.c index 93f0f38a32c9..3711d8454d96 100644 --- a/trunk/sound/soc/fsl/fsl_ssi.c +++ b/trunk/sound/soc/fsl/fsl_ssi.c @@ -375,14 +375,18 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, struct snd_pcm_runtime *first_runtime = ssi_private->first_stream->runtime; - if (!first_runtime->sample_bits) { + if (!first_runtime->rate || !first_runtime->sample_bits) { dev_err(substream->pcm->card->dev, - "set sample size in %s stream first\n", + "set sample rate and size in %s stream first\n", substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "capture" : "playback"); return -EAGAIN; } + snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_RATE, + first_runtime->rate, first_runtime->rate); + /* If we're in synchronous mode, then we need to constrain * the sample size as well. We don't support independent sample * rates in asynchronous mode. @@ -670,7 +674,7 @@ struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info) ssi_private->dev = ssi_info->dev; ssi_private->asynchronous = ssi_info->asynchronous; - dev_set_drvdata(ssi_private->dev, fsl_ssi_dai); + ssi_private->dev->driver_data = fsl_ssi_dai; /* Initialize the the device_attribute structure */ dev_attr->attr.name = "ssi-stats"; @@ -689,7 +693,6 @@ struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info) fsl_ssi_dai->name = ssi_private->name; fsl_ssi_dai->id = ssi_info->id; fsl_ssi_dai->dev = ssi_info->dev; - fsl_ssi_dai->symmetric_rates = 1; ret = snd_soc_register_dai(fsl_ssi_dai); if (ret != 0) { diff --git a/trunk/sound/soc/fsl/mpc5200_dma.c b/trunk/sound/soc/fsl/mpc5200_dma.c deleted file mode 100644 index efec33a1c5bd..000000000000 --- a/trunk/sound/soc/fsl/mpc5200_dma.c +++ /dev/null @@ -1,564 +0,0 @@ -/* - * Freescale MPC5200 PSC DMA - * ALSA SoC Platform driver - * - * Copyright (C) 2008 Secret Lab Technologies Ltd. - * Copyright (C) 2009 Jon Smirl, Digispeaker - */ - -#include -#include - -#include - -#include -#include -#include - -#include "mpc5200_dma.h" - -/* - * Interrupt handlers - */ -static irqreturn_t psc_dma_status_irq(int irq, void *_psc_dma) -{ - struct psc_dma *psc_dma = _psc_dma; - struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; - u16 isr; - - isr = in_be16(®s->mpc52xx_psc_isr); - - /* Playback underrun error */ - if (psc_dma->playback.active && (isr & MPC52xx_PSC_IMR_TXEMP)) - psc_dma->stats.underrun_count++; - - /* Capture overrun error */ - if (psc_dma->capture.active && (isr & MPC52xx_PSC_IMR_ORERR)) - psc_dma->stats.overrun_count++; - - out_8(®s->command, MPC52xx_PSC_RST_ERR_STAT); - - return IRQ_HANDLED; -} - -/** - * psc_dma_bcom_enqueue_next_buffer - Enqueue another audio buffer - * @s: pointer to stream private data structure - * - * Enqueues another audio period buffer into the bestcomm queue. - * - * Note: The routine must only be called when there is space available in - * the queue. Otherwise the enqueue will fail and the audio ring buffer - * will get out of sync - */ -static void psc_dma_bcom_enqueue_next_buffer(struct psc_dma_stream *s) -{ - struct bcom_bd *bd; - - /* Prepare and enqueue the next buffer descriptor */ - bd = bcom_prepare_next_buffer(s->bcom_task); - bd->status = s->period_bytes; - bd->data[0] = s->period_next_pt; - bcom_submit_next_buffer(s->bcom_task, NULL); - - /* Update for next period */ - s->period_next_pt += s->period_bytes; - if (s->period_next_pt >= s->period_end) - s->period_next_pt = s->period_start; -} - -static void psc_dma_bcom_enqueue_tx(struct psc_dma_stream *s) -{ - while (s->appl_ptr < s->runtime->control->appl_ptr) { - - if (bcom_queue_full(s->bcom_task)) - return; - - s->appl_ptr += s->period_size; - - psc_dma_bcom_enqueue_next_buffer(s); - } -} - -/* Bestcomm DMA irq handler */ -static irqreturn_t psc_dma_bcom_irq_tx(int irq, void *_psc_dma_stream) -{ - struct psc_dma_stream *s = _psc_dma_stream; - - spin_lock(&s->psc_dma->lock); - /* For each finished period, dequeue the completed period buffer - * and enqueue a new one in it's place. */ - while (bcom_buffer_done(s->bcom_task)) { - bcom_retrieve_buffer(s->bcom_task, NULL, NULL); - - s->period_current_pt += s->period_bytes; - if (s->period_current_pt >= s->period_end) - s->period_current_pt = s->period_start; - } - psc_dma_bcom_enqueue_tx(s); - spin_unlock(&s->psc_dma->lock); - - /* If the stream is active, then also inform the PCM middle layer - * of the period finished event. */ - if (s->active) - snd_pcm_period_elapsed(s->stream); - - return IRQ_HANDLED; -} - -static irqreturn_t psc_dma_bcom_irq_rx(int irq, void *_psc_dma_stream) -{ - struct psc_dma_stream *s = _psc_dma_stream; - - spin_lock(&s->psc_dma->lock); - /* For each finished period, dequeue the completed period buffer - * and enqueue a new one in it's place. */ - while (bcom_buffer_done(s->bcom_task)) { - bcom_retrieve_buffer(s->bcom_task, NULL, NULL); - - s->period_current_pt += s->period_bytes; - if (s->period_current_pt >= s->period_end) - s->period_current_pt = s->period_start; - - psc_dma_bcom_enqueue_next_buffer(s); - } - spin_unlock(&s->psc_dma->lock); - - /* If the stream is active, then also inform the PCM middle layer - * of the period finished event. */ - if (s->active) - snd_pcm_period_elapsed(s->stream); - - return IRQ_HANDLED; -} - -static int psc_dma_hw_free(struct snd_pcm_substream *substream) -{ - snd_pcm_set_runtime_buffer(substream, NULL); - return 0; -} - -/** - * psc_dma_trigger: start and stop the DMA transfer. - * - * This function is called by ALSA to start, stop, pause, and resume the DMA - * transfer of data. - */ -static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; - struct psc_dma_stream *s; - struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; - u16 imr; - unsigned long flags; - int i; - - if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) - s = &psc_dma->capture; - else - s = &psc_dma->playback; - - dev_dbg(psc_dma->dev, "psc_dma_trigger(substream=%p, cmd=%i)" - " stream_id=%i\n", - substream, cmd, substream->pstr->stream); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - s->period_bytes = frames_to_bytes(runtime, - runtime->period_size); - s->period_start = virt_to_phys(runtime->dma_area); - s->period_end = s->period_start + - (s->period_bytes * runtime->periods); - s->period_next_pt = s->period_start; - s->period_current_pt = s->period_start; - s->period_size = runtime->period_size; - s->active = 1; - - /* track appl_ptr so that we have a better chance of detecting - * end of stream and not over running it. - */ - s->runtime = runtime; - s->appl_ptr = s->runtime->control->appl_ptr - - (runtime->period_size * runtime->periods); - - /* Fill up the bestcomm bd queue and enable DMA. - * This will begin filling the PSC's fifo. - */ - spin_lock_irqsave(&psc_dma->lock, flags); - - if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) { - bcom_gen_bd_rx_reset(s->bcom_task); - for (i = 0; i < runtime->periods; i++) - if (!bcom_queue_full(s->bcom_task)) - psc_dma_bcom_enqueue_next_buffer(s); - } else { - bcom_gen_bd_tx_reset(s->bcom_task); - psc_dma_bcom_enqueue_tx(s); - } - - bcom_enable(s->bcom_task); - spin_unlock_irqrestore(&psc_dma->lock, flags); - - out_8(®s->command, MPC52xx_PSC_RST_ERR_STAT); - - break; - - case SNDRV_PCM_TRIGGER_STOP: - s->active = 0; - - spin_lock_irqsave(&psc_dma->lock, flags); - bcom_disable(s->bcom_task); - if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) - bcom_gen_bd_rx_reset(s->bcom_task); - else - bcom_gen_bd_tx_reset(s->bcom_task); - spin_unlock_irqrestore(&psc_dma->lock, flags); - - break; - - default: - dev_dbg(psc_dma->dev, "invalid command\n"); - return -EINVAL; - } - - /* Update interrupt enable settings */ - imr = 0; - if (psc_dma->playback.active) - imr |= MPC52xx_PSC_IMR_TXEMP; - if (psc_dma->capture.active) - imr |= MPC52xx_PSC_IMR_ORERR; - out_be16(®s->isr_imr.imr, psc_dma->imr | imr); - - return 0; -} - - -/* --------------------------------------------------------------------- - * The PSC DMA 'ASoC platform' driver - * - * Can be referenced by an 'ASoC machine' driver - * This driver only deals with the audio bus; it doesn't have any - * interaction with the attached codec - */ - -static const struct snd_pcm_hardware psc_dma_hardware = { - .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_BATCH, - .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | - SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE, - .rate_min = 8000, - .rate_max = 48000, - .channels_min = 1, - .channels_max = 2, - .period_bytes_max = 1024 * 1024, - .period_bytes_min = 32, - .periods_min = 2, - .periods_max = 256, - .buffer_bytes_max = 2 * 1024 * 1024, - .fifo_size = 512, -}; - -static int psc_dma_open(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data; - struct psc_dma_stream *s; - int rc; - - dev_dbg(psc_dma->dev, "psc_dma_open(substream=%p)\n", substream); - - if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) - s = &psc_dma->capture; - else - s = &psc_dma->playback; - - snd_soc_set_runtime_hwparams(substream, &psc_dma_hardware); - - rc = snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - if (rc < 0) { - dev_err(substream->pcm->card->dev, "invalid buffer size\n"); - return rc; - } - - s->stream = substream; - return 0; -} - -static int psc_dma_close(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data; - struct psc_dma_stream *s; - - dev_dbg(psc_dma->dev, "psc_dma_close(substream=%p)\n", substream); - - if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) - s = &psc_dma->capture; - else - s = &psc_dma->playback; - - if (!psc_dma->playback.active && - !psc_dma->capture.active) { - - /* Disable all interrupts and reset the PSC */ - out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr); - out_8(&psc_dma->psc_regs->command, 4 << 4); /* reset error */ - } - s->stream = NULL; - return 0; -} - -static snd_pcm_uframes_t -psc_dma_pointer(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data; - struct psc_dma_stream *s; - dma_addr_t count; - - if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) - s = &psc_dma->capture; - else - s = &psc_dma->playback; - - count = s->period_current_pt - s->period_start; - - return bytes_to_frames(substream->runtime, count); -} - -static int -psc_dma_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); - - return 0; -} - -static struct snd_pcm_ops psc_dma_ops = { - .open = psc_dma_open, - .close = psc_dma_close, - .hw_free = psc_dma_hw_free, - .ioctl = snd_pcm_lib_ioctl, - .pointer = psc_dma_pointer, - .trigger = psc_dma_trigger, - .hw_params = psc_dma_hw_params, -}; - -static u64 psc_dma_dmamask = 0xffffffff; -static int psc_dma_new(struct snd_card *card, struct snd_soc_dai *dai, - struct snd_pcm *pcm) -{ - struct snd_soc_pcm_runtime *rtd = pcm->private_data; - struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data; - size_t size = psc_dma_hardware.buffer_bytes_max; - int rc = 0; - - dev_dbg(rtd->socdev->dev, "psc_dma_new(card=%p, dai=%p, pcm=%p)\n", - card, dai, pcm); - - if (!card->dev->dma_mask) - card->dev->dma_mask = &psc_dma_dmamask; - if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = 0xffffffff; - - if (pcm->streams[0].substream) { - rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->card->dev, - size, &pcm->streams[0].substream->dma_buffer); - if (rc) - goto playback_alloc_err; - } - - if (pcm->streams[1].substream) { - rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->card->dev, - size, &pcm->streams[1].substream->dma_buffer); - if (rc) - goto capture_alloc_err; - } - - if (rtd->socdev->card->codec->ac97) - rtd->socdev->card->codec->ac97->private_data = psc_dma; - - return 0; - - capture_alloc_err: - if (pcm->streams[0].substream) - snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer); - - playback_alloc_err: - dev_err(card->dev, "Cannot allocate buffer(s)\n"); - - return -ENOMEM; -} - -static void psc_dma_free(struct snd_pcm *pcm) -{ - struct snd_soc_pcm_runtime *rtd = pcm->private_data; - struct snd_pcm_substream *substream; - int stream; - - dev_dbg(rtd->socdev->dev, "psc_dma_free(pcm=%p)\n", pcm); - - for (stream = 0; stream < 2; stream++) { - substream = pcm->streams[stream].substream; - if (substream) { - snd_dma_free_pages(&substream->dma_buffer); - substream->dma_buffer.area = NULL; - substream->dma_buffer.addr = 0; - } - } -} - -struct snd_soc_platform mpc5200_audio_dma_platform = { - .name = "mpc5200-psc-audio", - .pcm_ops = &psc_dma_ops, - .pcm_new = &psc_dma_new, - .pcm_free = &psc_dma_free, -}; -EXPORT_SYMBOL_GPL(mpc5200_audio_dma_platform); - -int mpc5200_audio_dma_create(struct of_device *op) -{ - phys_addr_t fifo; - struct psc_dma *psc_dma; - struct resource res; - int size, irq, rc; - const __be32 *prop; - void __iomem *regs; - - /* Fetch the registers and IRQ of the PSC */ - irq = irq_of_parse_and_map(op->node, 0); - if (of_address_to_resource(op->node, 0, &res)) { - dev_err(&op->dev, "Missing reg property\n"); - return -ENODEV; - } - regs = ioremap(res.start, 1 + res.end - res.start); - if (!regs) { - dev_err(&op->dev, "Could not map registers\n"); - return -ENODEV; - } - - /* Allocate and initialize the driver private data */ - psc_dma = kzalloc(sizeof *psc_dma, GFP_KERNEL); - if (!psc_dma) { - iounmap(regs); - return -ENOMEM; - } - - /* Get the PSC ID */ - prop = of_get_property(op->node, "cell-index", &size); - if (!prop || size < sizeof *prop) - return -ENODEV; - - spin_lock_init(&psc_dma->lock); - psc_dma->id = be32_to_cpu(*prop); - psc_dma->irq = irq; - psc_dma->psc_regs = regs; - psc_dma->fifo_regs = regs + sizeof *psc_dma->psc_regs; - psc_dma->dev = &op->dev; - psc_dma->playback.psc_dma = psc_dma; - psc_dma->capture.psc_dma = psc_dma; - snprintf(psc_dma->name, sizeof psc_dma->name, "PSC%u", psc_dma->id); - - /* Find the address of the fifo data registers and setup the - * DMA tasks */ - fifo = res.start + offsetof(struct mpc52xx_psc, buffer.buffer_32); - psc_dma->capture.bcom_task = - bcom_psc_gen_bd_rx_init(psc_dma->id, 10, fifo, 512); - psc_dma->playback.bcom_task = - bcom_psc_gen_bd_tx_init(psc_dma->id, 10, fifo); - if (!psc_dma->capture.bcom_task || - !psc_dma->playback.bcom_task) { - dev_err(&op->dev, "Could not allocate bestcomm tasks\n"); - iounmap(regs); - kfree(psc_dma); - return -ENODEV; - } - - /* Disable all interrupts and reset the PSC */ - out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr); - /* reset receiver */ - out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_RX); - /* reset transmitter */ - out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_TX); - /* reset error */ - out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_ERR_STAT); - /* reset mode */ - out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_SEL_MODE_REG_1); - - /* Set up mode register; - * First write: RxRdy (FIFO Alarm) generates rx FIFO irq - * Second write: register Normal mode for non loopback - */ - out_8(&psc_dma->psc_regs->mode, 0); - out_8(&psc_dma->psc_regs->mode, 0); - - /* Set the TX and RX fifo alarm thresholds */ - out_be16(&psc_dma->fifo_regs->rfalarm, 0x100); - out_8(&psc_dma->fifo_regs->rfcntl, 0x4); - out_be16(&psc_dma->fifo_regs->tfalarm, 0x100); - out_8(&psc_dma->fifo_regs->tfcntl, 0x7); - - /* Lookup the IRQ numbers */ - psc_dma->playback.irq = - bcom_get_task_irq(psc_dma->playback.bcom_task); - psc_dma->capture.irq = - bcom_get_task_irq(psc_dma->capture.bcom_task); - - rc = request_irq(psc_dma->irq, &psc_dma_status_irq, IRQF_SHARED, - "psc-dma-status", psc_dma); - rc |= request_irq(psc_dma->capture.irq, - &psc_dma_bcom_irq_rx, IRQF_SHARED, - "psc-dma-capture", &psc_dma->capture); - rc |= request_irq(psc_dma->playback.irq, - &psc_dma_bcom_irq_tx, IRQF_SHARED, - "psc-dma-playback", &psc_dma->playback); - if (rc) { - free_irq(psc_dma->irq, psc_dma); - free_irq(psc_dma->capture.irq, - &psc_dma->capture); - free_irq(psc_dma->playback.irq, - &psc_dma->playback); - return -ENODEV; - } - - /* Save what we've done so it can be found again later */ - dev_set_drvdata(&op->dev, psc_dma); - - /* Tell the ASoC OF helpers about it */ - return snd_soc_register_platform(&mpc5200_audio_dma_platform); -} -EXPORT_SYMBOL_GPL(mpc5200_audio_dma_create); - -int mpc5200_audio_dma_destroy(struct of_device *op) -{ - struct psc_dma *psc_dma = dev_get_drvdata(&op->dev); - - dev_dbg(&op->dev, "mpc5200_audio_dma_destroy()\n"); - - snd_soc_unregister_platform(&mpc5200_audio_dma_platform); - - bcom_gen_bd_rx_release(psc_dma->capture.bcom_task); - bcom_gen_bd_tx_release(psc_dma->playback.bcom_task); - - /* Release irqs */ - free_irq(psc_dma->irq, psc_dma); - free_irq(psc_dma->capture.irq, &psc_dma->capture); - free_irq(psc_dma->playback.irq, &psc_dma->playback); - - iounmap(psc_dma->psc_regs); - kfree(psc_dma); - dev_set_drvdata(&op->dev, NULL); - - return 0; -} -EXPORT_SYMBOL_GPL(mpc5200_audio_dma_destroy); - -MODULE_AUTHOR("Grant Likely "); -MODULE_DESCRIPTION("Freescale MPC5200 PSC in DMA mode ASoC Driver"); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/fsl/mpc5200_dma.h b/trunk/sound/soc/fsl/mpc5200_dma.h deleted file mode 100644 index 2000803f06a7..000000000000 --- a/trunk/sound/soc/fsl/mpc5200_dma.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Freescale MPC5200 Audio DMA driver - */ - -#ifndef __SOUND_SOC_FSL_MPC5200_DMA_H__ -#define __SOUND_SOC_FSL_MPC5200_DMA_H__ - -#define PSC_STREAM_NAME_LEN 32 - -/** - * psc_ac97_stream - Data specific to a single stream (playback or capture) - * @active: flag indicating if the stream is active - * @psc_dma: pointer back to parent psc_dma data structure - * @bcom_task: bestcomm task structure - * @irq: irq number for bestcomm task - * @period_start: physical address of start of DMA region - * @period_end: physical address of end of DMA region - * @period_next_pt: physical address of next DMA buffer to enqueue - * @period_bytes: size of DMA period in bytes - */ -struct psc_dma_stream { - struct snd_pcm_runtime *runtime; - snd_pcm_uframes_t appl_ptr; - - int active; - struct psc_dma *psc_dma; - struct bcom_task *bcom_task; - int irq; - struct snd_pcm_substream *stream; - dma_addr_t period_start; - dma_addr_t period_end; - dma_addr_t period_next_pt; - dma_addr_t period_current_pt; - int period_bytes; - int period_size; -}; - -/** - * psc_dma - Private driver data - * @name: short name for this device ("PSC0", "PSC1", etc) - * @psc_regs: pointer to the PSC's registers - * @fifo_regs: pointer to the PSC's FIFO registers - * @irq: IRQ of this PSC - * @dev: struct device pointer - * @dai: the CPU DAI for this device - * @sicr: Base value used in serial interface control register; mode is ORed - * with this value. - * @playback: Playback stream context data - * @capture: Capture stream context data - */ -struct psc_dma { - char name[32]; - struct mpc52xx_psc __iomem *psc_regs; - struct mpc52xx_psc_fifo __iomem *fifo_regs; - unsigned int irq; - struct device *dev; - spinlock_t lock; - u32 sicr; - uint sysclk; - int imr; - int id; - unsigned int slots; - - /* per-stream data */ - struct psc_dma_stream playback; - struct psc_dma_stream capture; - - /* Statistics */ - struct { - unsigned long overrun_count; - unsigned long underrun_count; - } stats; -}; - -int mpc5200_audio_dma_create(struct of_device *op); -int mpc5200_audio_dma_destroy(struct of_device *op); - -extern struct snd_soc_platform mpc5200_audio_dma_platform; - -#endif /* __SOUND_SOC_FSL_MPC5200_DMA_H__ */ diff --git a/trunk/sound/soc/fsl/mpc5200_psc_ac97.c b/trunk/sound/soc/fsl/mpc5200_psc_ac97.c deleted file mode 100644 index 794a247b3eb5..000000000000 --- a/trunk/sound/soc/fsl/mpc5200_psc_ac97.c +++ /dev/null @@ -1,329 +0,0 @@ -/* - * linux/sound/mpc5200-ac97.c -- AC97 support for the Freescale MPC52xx chip. - * - * Copyright (C) 2009 Jon Smirl, Digispeaker - * Author: Jon Smirl - * - * 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. - */ - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include "mpc5200_dma.h" -#include "mpc5200_psc_ac97.h" - -#define DRV_NAME "mpc5200-psc-ac97" - -/* ALSA only supports a single AC97 device so static is recommend here */ -static struct psc_dma *psc_dma; - -static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned short reg) -{ - int status; - unsigned int val; - - /* Wait for command send status zero = ready */ - status = spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) & - MPC52xx_PSC_SR_CMDSEND), 100, 0); - if (status == 0) { - pr_err("timeout on ac97 bus (rdy)\n"); - return -ENODEV; - } - /* Send the read */ - out_be32(&psc_dma->psc_regs->ac97_cmd, (1<<31) | ((reg & 0x7f) << 24)); - - /* Wait for the answer */ - status = spin_event_timeout((in_be16(&psc_dma->psc_regs->sr_csr.status) & - MPC52xx_PSC_SR_DATA_VAL), 100, 0); - if (status == 0) { - pr_err("timeout on ac97 read (val) %x\n", - in_be16(&psc_dma->psc_regs->sr_csr.status)); - return -ENODEV; - } - /* Get the data */ - val = in_be32(&psc_dma->psc_regs->ac97_data); - if (((val >> 24) & 0x7f) != reg) { - pr_err("reg echo error on ac97 read\n"); - return -ENODEV; - } - val = (val >> 8) & 0xffff; - - return (unsigned short) val; -} - -static void psc_ac97_write(struct snd_ac97 *ac97, - unsigned short reg, unsigned short val) -{ - int status; - - /* Wait for command status zero = ready */ - status = spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) & - MPC52xx_PSC_SR_CMDSEND), 100, 0); - if (status == 0) { - pr_err("timeout on ac97 bus (write)\n"); - return; - } - /* Write data */ - out_be32(&psc_dma->psc_regs->ac97_cmd, - ((reg & 0x7f) << 24) | (val << 8)); -} - -static void psc_ac97_warm_reset(struct snd_ac97 *ac97) -{ - struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; - - out_be32(®s->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_AWR); - udelay(3); - out_be32(®s->sicr, psc_dma->sicr); -} - -static void psc_ac97_cold_reset(struct snd_ac97 *ac97) -{ - struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; - - /* Do a cold reset */ - out_8(®s->op1, MPC52xx_PSC_OP_RES); - udelay(10); - out_8(®s->op0, MPC52xx_PSC_OP_RES); - udelay(50); - psc_ac97_warm_reset(ac97); -} - -struct snd_ac97_bus_ops soc_ac97_ops = { - .read = psc_ac97_read, - .write = psc_ac97_write, - .reset = psc_ac97_cold_reset, - .warm_reset = psc_ac97_warm_reset, -}; -EXPORT_SYMBOL_GPL(soc_ac97_ops); - -static int psc_ac97_hw_analog_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *cpu_dai) -{ - struct psc_dma *psc_dma = cpu_dai->private_data; - - dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i" - " periods=%i buffer_size=%i buffer_bytes=%i channels=%i" - " rate=%i format=%i\n", - __func__, substream, params_period_size(params), - params_period_bytes(params), params_periods(params), - params_buffer_size(params), params_buffer_bytes(params), - params_channels(params), params_rate(params), - params_format(params)); - - - if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) { - if (params_channels(params) == 1) - psc_dma->slots |= 0x00000100; - else - psc_dma->slots |= 0x00000300; - } else { - if (params_channels(params) == 1) - psc_dma->slots |= 0x01000000; - else - psc_dma->slots |= 0x03000000; - } - out_be32(&psc_dma->psc_regs->ac97_slots, psc_dma->slots); - - return 0; -} - -static int psc_ac97_hw_digital_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *cpu_dai) -{ - struct psc_dma *psc_dma = cpu_dai->private_data; - - if (params_channels(params) == 1) - out_be32(&psc_dma->psc_regs->ac97_slots, 0x01000000); - else - out_be32(&psc_dma->psc_regs->ac97_slots, 0x03000000); - - return 0; -} - -static int psc_ac97_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_STOP: - if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) - psc_dma->slots &= 0xFFFF0000; - else - psc_dma->slots &= 0x0000FFFF; - - out_be32(&psc_dma->psc_regs->ac97_slots, psc_dma->slots); - break; - } - return 0; -} - -static int psc_ac97_probe(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) -{ - struct psc_dma *psc_dma = cpu_dai->private_data; - struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; - - /* Go */ - out_8(®s->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE); - return 0; -} - -/* --------------------------------------------------------------------- - * ALSA SoC Bindings - * - * - Digital Audio Interface (DAI) template - * - create/destroy dai hooks - */ - -/** - * psc_ac97_dai_template: template CPU Digital Audio Interface - */ -static struct snd_soc_dai_ops psc_ac97_analog_ops = { - .hw_params = psc_ac97_hw_analog_params, - .trigger = psc_ac97_trigger, -}; - -static struct snd_soc_dai_ops psc_ac97_digital_ops = { - .hw_params = psc_ac97_hw_digital_params, -}; - -struct snd_soc_dai psc_ac97_dai[] = { -{ - .name = "AC97", - .ac97_control = 1, - .probe = psc_ac97_probe, - .playback = { - .channels_min = 1, - .channels_max = 6, - .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S32_BE, - }, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S32_BE, - }, - .ops = &psc_ac97_analog_ops, -}, -{ - .name = "SPDIF", - .ac97_control = 1, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_32000 | \ - SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE, - }, - .ops = &psc_ac97_digital_ops, -} }; -EXPORT_SYMBOL_GPL(psc_ac97_dai); - - - -/* --------------------------------------------------------------------- - * OF platform bus binding code: - * - Probe/remove operations - * - OF device match table - */ -static int __devinit psc_ac97_of_probe(struct of_device *op, - const struct of_device_id *match) -{ - int rc, i; - struct snd_ac97 ac97; - struct mpc52xx_psc __iomem *regs; - - rc = mpc5200_audio_dma_create(op); - if (rc != 0) - return rc; - - for (i = 0; i < ARRAY_SIZE(psc_ac97_dai); i++) - psc_ac97_dai[i].dev = &op->dev; - - rc = snd_soc_register_dais(psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai)); - if (rc != 0) { - dev_err(&op->dev, "Failed to register DAI\n"); - return rc; - } - - psc_dma = dev_get_drvdata(&op->dev); - regs = psc_dma->psc_regs; - ac97.private_data = psc_dma; - - for (i = 0; i < ARRAY_SIZE(psc_ac97_dai); i++) - psc_ac97_dai[i].private_data = psc_dma; - - psc_dma->imr = 0; - out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr); - - /* Configure the serial interface mode to AC97 */ - psc_dma->sicr = MPC52xx_PSC_SICR_SIM_AC97 | MPC52xx_PSC_SICR_ENAC97; - out_be32(®s->sicr, psc_dma->sicr); - - /* No slots active */ - out_be32(®s->ac97_slots, 0x00000000); - - return 0; -} - -static int __devexit psc_ac97_of_remove(struct of_device *op) -{ - return mpc5200_audio_dma_destroy(op); -} - -/* Match table for of_platform binding */ -static struct of_device_id psc_ac97_match[] __devinitdata = { - { .compatible = "fsl,mpc5200-psc-ac97", }, - { .compatible = "fsl,mpc5200b-psc-ac97", }, - {} -}; -MODULE_DEVICE_TABLE(of, psc_ac97_match); - -static struct of_platform_driver psc_ac97_driver = { - .match_table = psc_ac97_match, - .probe = psc_ac97_of_probe, - .remove = __devexit_p(psc_ac97_of_remove), - .driver = { - .name = "mpc5200-psc-ac97", - .owner = THIS_MODULE, - }, -}; - -/* --------------------------------------------------------------------- - * Module setup and teardown; simply register the of_platform driver - * for the PSC in AC97 mode. - */ -static int __init psc_ac97_init(void) -{ - return of_register_platform_driver(&psc_ac97_driver); -} -module_init(psc_ac97_init); - -static void __exit psc_ac97_exit(void) -{ - of_unregister_platform_driver(&psc_ac97_driver); -} -module_exit(psc_ac97_exit); - -MODULE_AUTHOR("Jon Smirl "); -MODULE_DESCRIPTION("mpc5200 AC97 module"); -MODULE_LICENSE("GPL"); - diff --git a/trunk/sound/soc/fsl/mpc5200_psc_ac97.h b/trunk/sound/soc/fsl/mpc5200_psc_ac97.h deleted file mode 100644 index 4bc18c35c369..000000000000 --- a/trunk/sound/soc/fsl/mpc5200_psc_ac97.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Freescale MPC5200 PSC in AC97 mode - * ALSA SoC Digital Audio Interface (DAI) driver - * - */ - -#ifndef __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__ -#define __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__ - -extern struct snd_soc_dai psc_ac97_dai[]; - -#define MPC5200_AC97_NORMAL 0 -#define MPC5200_AC97_SPDIF 1 - -#endif /* __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__ */ diff --git a/trunk/sound/soc/fsl/mpc5200_psc_i2s.c b/trunk/sound/soc/fsl/mpc5200_psc_i2s.c index ce8de90fb94a..1111c710118a 100644 --- a/trunk/sound/soc/fsl/mpc5200_psc_i2s.c +++ b/trunk/sound/soc/fsl/mpc5200_psc_i2s.c @@ -3,21 +3,31 @@ * ALSA SoC Digital Audio Interface (DAI) driver * * Copyright (C) 2008 Secret Lab Technologies Ltd. - * Copyright (C) 2009 Jon Smirl, Digispeaker */ +#include #include +#include +#include +#include #include #include +#include +#include #include #include +#include #include +#include +#include +#include #include -#include "mpc5200_psc_i2s.h" -#include "mpc5200_dma.h" +MODULE_AUTHOR("Grant Likely "); +MODULE_DESCRIPTION("Freescale MPC5200 PSC in I2S mode ASoC Driver"); +MODULE_LICENSE("GPL"); /** * PSC_I2S_RATES: sample rates supported by the I2S @@ -34,17 +44,191 @@ * PSC_I2S_FORMATS: audio formats supported by the PSC I2S mode */ #define PSC_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \ - SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE) + SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S24_BE | \ + SNDRV_PCM_FMTBIT_S32_BE) + +/** + * psc_i2s_stream - Data specific to a single stream (playback or capture) + * @active: flag indicating if the stream is active + * @psc_i2s: pointer back to parent psc_i2s data structure + * @bcom_task: bestcomm task structure + * @irq: irq number for bestcomm task + * @period_start: physical address of start of DMA region + * @period_end: physical address of end of DMA region + * @period_next_pt: physical address of next DMA buffer to enqueue + * @period_bytes: size of DMA period in bytes + */ +struct psc_i2s_stream { + int active; + struct psc_i2s *psc_i2s; + struct bcom_task *bcom_task; + int irq; + struct snd_pcm_substream *stream; + dma_addr_t period_start; + dma_addr_t period_end; + dma_addr_t period_next_pt; + dma_addr_t period_current_pt; + int period_bytes; +}; + +/** + * psc_i2s - Private driver data + * @name: short name for this device ("PSC0", "PSC1", etc) + * @psc_regs: pointer to the PSC's registers + * @fifo_regs: pointer to the PSC's FIFO registers + * @irq: IRQ of this PSC + * @dev: struct device pointer + * @dai: the CPU DAI for this device + * @sicr: Base value used in serial interface control register; mode is ORed + * with this value. + * @playback: Playback stream context data + * @capture: Capture stream context data + */ +struct psc_i2s { + char name[32]; + struct mpc52xx_psc __iomem *psc_regs; + struct mpc52xx_psc_fifo __iomem *fifo_regs; + unsigned int irq; + struct device *dev; + struct snd_soc_dai dai; + spinlock_t lock; + u32 sicr; + + /* per-stream data */ + struct psc_i2s_stream playback; + struct psc_i2s_stream capture; + + /* Statistics */ + struct { + int overrun_count; + int underrun_count; + } stats; +}; + +/* + * Interrupt handlers + */ +static irqreturn_t psc_i2s_status_irq(int irq, void *_psc_i2s) +{ + struct psc_i2s *psc_i2s = _psc_i2s; + struct mpc52xx_psc __iomem *regs = psc_i2s->psc_regs; + u16 isr; + + isr = in_be16(®s->mpc52xx_psc_isr); + + /* Playback underrun error */ + if (psc_i2s->playback.active && (isr & MPC52xx_PSC_IMR_TXEMP)) + psc_i2s->stats.underrun_count++; + + /* Capture overrun error */ + if (psc_i2s->capture.active && (isr & MPC52xx_PSC_IMR_ORERR)) + psc_i2s->stats.overrun_count++; + + out_8(®s->command, 4 << 4); /* reset the error status */ + + return IRQ_HANDLED; +} + +/** + * psc_i2s_bcom_enqueue_next_buffer - Enqueue another audio buffer + * @s: pointer to stream private data structure + * + * Enqueues another audio period buffer into the bestcomm queue. + * + * Note: The routine must only be called when there is space available in + * the queue. Otherwise the enqueue will fail and the audio ring buffer + * will get out of sync + */ +static void psc_i2s_bcom_enqueue_next_buffer(struct psc_i2s_stream *s) +{ + struct bcom_bd *bd; + + /* Prepare and enqueue the next buffer descriptor */ + bd = bcom_prepare_next_buffer(s->bcom_task); + bd->status = s->period_bytes; + bd->data[0] = s->period_next_pt; + bcom_submit_next_buffer(s->bcom_task, NULL); + + /* Update for next period */ + s->period_next_pt += s->period_bytes; + if (s->period_next_pt >= s->period_end) + s->period_next_pt = s->period_start; +} + +/* Bestcomm DMA irq handler */ +static irqreturn_t psc_i2s_bcom_irq(int irq, void *_psc_i2s_stream) +{ + struct psc_i2s_stream *s = _psc_i2s_stream; + + /* For each finished period, dequeue the completed period buffer + * and enqueue a new one in it's place. */ + while (bcom_buffer_done(s->bcom_task)) { + bcom_retrieve_buffer(s->bcom_task, NULL, NULL); + s->period_current_pt += s->period_bytes; + if (s->period_current_pt >= s->period_end) + s->period_current_pt = s->period_start; + psc_i2s_bcom_enqueue_next_buffer(s); + bcom_enable(s->bcom_task); + } + + /* If the stream is active, then also inform the PCM middle layer + * of the period finished event. */ + if (s->active) + snd_pcm_period_elapsed(s->stream); + + return IRQ_HANDLED; +} + +/** + * psc_i2s_startup: create a new substream + * + * This is the first function called when a stream is opened. + * + * If this is the first stream open, then grab the IRQ and program most of + * the PSC registers. + */ +static int psc_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; + int rc; + + dev_dbg(psc_i2s->dev, "psc_i2s_startup(substream=%p)\n", substream); + + if (!psc_i2s->playback.active && + !psc_i2s->capture.active) { + /* Setup the IRQs */ + rc = request_irq(psc_i2s->irq, &psc_i2s_status_irq, IRQF_SHARED, + "psc-i2s-status", psc_i2s); + rc |= request_irq(psc_i2s->capture.irq, + &psc_i2s_bcom_irq, IRQF_SHARED, + "psc-i2s-capture", &psc_i2s->capture); + rc |= request_irq(psc_i2s->playback.irq, + &psc_i2s_bcom_irq, IRQF_SHARED, + "psc-i2s-playback", &psc_i2s->playback); + if (rc) { + free_irq(psc_i2s->irq, psc_i2s); + free_irq(psc_i2s->capture.irq, + &psc_i2s->capture); + free_irq(psc_i2s->playback.irq, + &psc_i2s->playback); + return -ENODEV; + } + } + + return 0; +} static int psc_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data; + struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; u32 mode; - dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i" + dev_dbg(psc_i2s->dev, "%s(substream=%p) p_size=%i p_bytes=%i" " periods=%i buffer_size=%i buffer_bytes=%i\n", __func__, substream, params_period_size(params), params_period_bytes(params), params_periods(params), @@ -64,14 +248,174 @@ static int psc_i2s_hw_params(struct snd_pcm_substream *substream, mode = MPC52xx_PSC_SICR_SIM_CODEC_32; break; default: - dev_dbg(psc_dma->dev, "invalid format\n"); + dev_dbg(psc_i2s->dev, "invalid format\n"); + return -EINVAL; + } + out_be32(&psc_i2s->psc_regs->sicr, psc_i2s->sicr | mode); + + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + + return 0; +} + +static int psc_i2s_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + snd_pcm_set_runtime_buffer(substream, NULL); + return 0; +} + +/** + * psc_i2s_trigger: start and stop the DMA transfer. + * + * This function is called by ALSA to start, stop, pause, and resume the DMA + * transfer of data. + */ +static int psc_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; + struct snd_pcm_runtime *runtime = substream->runtime; + struct psc_i2s_stream *s; + struct mpc52xx_psc __iomem *regs = psc_i2s->psc_regs; + u16 imr; + u8 psc_cmd; + unsigned long flags; + + if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) + s = &psc_i2s->capture; + else + s = &psc_i2s->playback; + + dev_dbg(psc_i2s->dev, "psc_i2s_trigger(substream=%p, cmd=%i)" + " stream_id=%i\n", + substream, cmd, substream->pstr->stream); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + s->period_bytes = frames_to_bytes(runtime, + runtime->period_size); + s->period_start = virt_to_phys(runtime->dma_area); + s->period_end = s->period_start + + (s->period_bytes * runtime->periods); + s->period_next_pt = s->period_start; + s->period_current_pt = s->period_start; + s->active = 1; + + /* First; reset everything */ + if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) { + out_8(®s->command, MPC52xx_PSC_RST_RX); + out_8(®s->command, MPC52xx_PSC_RST_ERR_STAT); + } else { + out_8(®s->command, MPC52xx_PSC_RST_TX); + out_8(®s->command, MPC52xx_PSC_RST_ERR_STAT); + } + + /* Next, fill up the bestcomm bd queue and enable DMA. + * This will begin filling the PSC's fifo. */ + if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) + bcom_gen_bd_rx_reset(s->bcom_task); + else + bcom_gen_bd_tx_reset(s->bcom_task); + while (!bcom_queue_full(s->bcom_task)) + psc_i2s_bcom_enqueue_next_buffer(s); + bcom_enable(s->bcom_task); + + /* Due to errata in the i2s mode; need to line up enabling + * the transmitter with a transition on the frame sync + * line */ + + spin_lock_irqsave(&psc_i2s->lock, flags); + /* first make sure it is low */ + while ((in_8(®s->ipcr_acr.ipcr) & 0x80) != 0) + ; + /* then wait for the transition to high */ + while ((in_8(®s->ipcr_acr.ipcr) & 0x80) == 0) + ; + /* Finally, enable the PSC. + * Receiver must always be enabled; even when we only want + * transmit. (see 15.3.2.3 of MPC5200B User's Guide) */ + psc_cmd = MPC52xx_PSC_RX_ENABLE; + if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) + psc_cmd |= MPC52xx_PSC_TX_ENABLE; + out_8(®s->command, psc_cmd); + spin_unlock_irqrestore(&psc_i2s->lock, flags); + + break; + + case SNDRV_PCM_TRIGGER_STOP: + /* Turn off the PSC */ + s->active = 0; + if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) { + if (!psc_i2s->playback.active) { + out_8(®s->command, 2 << 4); /* reset rx */ + out_8(®s->command, 3 << 4); /* reset tx */ + out_8(®s->command, 4 << 4); /* reset err */ + } + } else { + out_8(®s->command, 3 << 4); /* reset tx */ + out_8(®s->command, 4 << 4); /* reset err */ + if (!psc_i2s->capture.active) + out_8(®s->command, 2 << 4); /* reset rx */ + } + + bcom_disable(s->bcom_task); + while (!bcom_queue_empty(s->bcom_task)) + bcom_retrieve_buffer(s->bcom_task, NULL, NULL); + + break; + + default: + dev_dbg(psc_i2s->dev, "invalid command\n"); return -EINVAL; } - out_be32(&psc_dma->psc_regs->sicr, psc_dma->sicr | mode); + + /* Update interrupt enable settings */ + imr = 0; + if (psc_i2s->playback.active) + imr |= MPC52xx_PSC_IMR_TXEMP; + if (psc_i2s->capture.active) + imr |= MPC52xx_PSC_IMR_ORERR; + out_be16(®s->isr_imr.imr, imr); return 0; } +/** + * psc_i2s_shutdown: shutdown the data transfer on a stream + * + * Shutdown the PSC if there are no other substreams open. + */ +static void psc_i2s_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; + + dev_dbg(psc_i2s->dev, "psc_i2s_shutdown(substream=%p)\n", substream); + + /* + * If this is the last active substream, disable the PSC and release + * the IRQ. + */ + if (!psc_i2s->playback.active && + !psc_i2s->capture.active) { + + /* Disable all interrupts and reset the PSC */ + out_be16(&psc_i2s->psc_regs->isr_imr.imr, 0); + out_8(&psc_i2s->psc_regs->command, 3 << 4); /* reset tx */ + out_8(&psc_i2s->psc_regs->command, 2 << 4); /* reset rx */ + out_8(&psc_i2s->psc_regs->command, 1 << 4); /* reset mode */ + out_8(&psc_i2s->psc_regs->command, 4 << 4); /* reset error */ + + /* Release irqs */ + free_irq(psc_i2s->irq, psc_i2s); + free_irq(psc_i2s->capture.irq, &psc_i2s->capture); + free_irq(psc_i2s->playback.irq, &psc_i2s->playback); + } +} + /** * psc_i2s_set_sysclk: set the clock frequency and direction * @@ -89,8 +433,8 @@ static int psc_i2s_hw_params(struct snd_pcm_substream *substream, static int psc_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int dir) { - struct psc_dma *psc_dma = cpu_dai->private_data; - dev_dbg(psc_dma->dev, "psc_i2s_set_sysclk(cpu_dai=%p, dir=%i)\n", + struct psc_i2s *psc_i2s = cpu_dai->private_data; + dev_dbg(psc_i2s->dev, "psc_i2s_set_sysclk(cpu_dai=%p, dir=%i)\n", cpu_dai, dir); return (dir == SND_SOC_CLOCK_IN) ? 0 : -EINVAL; } @@ -108,8 +452,8 @@ static int psc_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, */ static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format) { - struct psc_dma *psc_dma = cpu_dai->private_data; - dev_dbg(psc_dma->dev, "psc_i2s_set_fmt(cpu_dai=%p, format=%i)\n", + struct psc_i2s *psc_i2s = cpu_dai->private_data; + dev_dbg(psc_i2s->dev, "psc_i2s_set_fmt(cpu_dai=%p, format=%i)\n", cpu_dai, format); return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL; } @@ -125,13 +469,16 @@ static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format) * psc_i2s_dai_template: template CPU Digital Audio Interface */ static struct snd_soc_dai_ops psc_i2s_dai_ops = { + .startup = psc_i2s_startup, .hw_params = psc_i2s_hw_params, + .hw_free = psc_i2s_hw_free, + .shutdown = psc_i2s_shutdown, + .trigger = psc_i2s_trigger, .set_sysclk = psc_i2s_set_sysclk, .set_fmt = psc_i2s_set_fmt, }; -struct snd_soc_dai psc_i2s_dai[] = {{ - .name = "I2S", +static struct snd_soc_dai psc_i2s_dai_template = { .playback = { .channels_min = 2, .channels_max = 2, @@ -145,8 +492,223 @@ struct snd_soc_dai psc_i2s_dai[] = {{ .formats = PSC_I2S_FORMATS, }, .ops = &psc_i2s_dai_ops, -} }; -EXPORT_SYMBOL_GPL(psc_i2s_dai); +}; + +/* --------------------------------------------------------------------- + * The PSC I2S 'ASoC platform' driver + * + * Can be referenced by an 'ASoC machine' driver + * This driver only deals with the audio bus; it doesn't have any + * interaction with the attached codec + */ + +static const struct snd_pcm_hardware psc_i2s_pcm_hardware = { + .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_BATCH, + .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | + SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE, + .rate_min = 8000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .period_bytes_max = 1024 * 1024, + .period_bytes_min = 32, + .periods_min = 2, + .periods_max = 256, + .buffer_bytes_max = 2 * 1024 * 1024, + .fifo_size = 0, +}; + +static int psc_i2s_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; + struct psc_i2s_stream *s; + + dev_dbg(psc_i2s->dev, "psc_i2s_pcm_open(substream=%p)\n", substream); + + if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) + s = &psc_i2s->capture; + else + s = &psc_i2s->playback; + + snd_soc_set_runtime_hwparams(substream, &psc_i2s_pcm_hardware); + + s->stream = substream; + return 0; +} + +static int psc_i2s_pcm_close(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; + struct psc_i2s_stream *s; + + dev_dbg(psc_i2s->dev, "psc_i2s_pcm_close(substream=%p)\n", substream); + + if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) + s = &psc_i2s->capture; + else + s = &psc_i2s->playback; + + s->stream = NULL; + return 0; +} + +static snd_pcm_uframes_t +psc_i2s_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; + struct psc_i2s_stream *s; + dma_addr_t count; + + if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) + s = &psc_i2s->capture; + else + s = &psc_i2s->playback; + + count = s->period_current_pt - s->period_start; + + return bytes_to_frames(substream->runtime, count); +} + +static struct snd_pcm_ops psc_i2s_pcm_ops = { + .open = psc_i2s_pcm_open, + .close = psc_i2s_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .pointer = psc_i2s_pcm_pointer, +}; + +static u64 psc_i2s_pcm_dmamask = 0xffffffff; +static int psc_i2s_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) +{ + struct snd_soc_pcm_runtime *rtd = pcm->private_data; + size_t size = psc_i2s_pcm_hardware.buffer_bytes_max; + int rc = 0; + + dev_dbg(rtd->socdev->dev, "psc_i2s_pcm_new(card=%p, dai=%p, pcm=%p)\n", + card, dai, pcm); + + if (!card->dev->dma_mask) + card->dev->dma_mask = &psc_i2s_pcm_dmamask; + if (!card->dev->coherent_dma_mask) + card->dev->coherent_dma_mask = 0xffffffff; + + if (pcm->streams[0].substream) { + rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, size, + &pcm->streams[0].substream->dma_buffer); + if (rc) + goto playback_alloc_err; + } + + if (pcm->streams[1].substream) { + rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, size, + &pcm->streams[1].substream->dma_buffer); + if (rc) + goto capture_alloc_err; + } + + return 0; + + capture_alloc_err: + if (pcm->streams[0].substream) + snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer); + playback_alloc_err: + dev_err(card->dev, "Cannot allocate buffer(s)\n"); + return -ENOMEM; +} + +static void psc_i2s_pcm_free(struct snd_pcm *pcm) +{ + struct snd_soc_pcm_runtime *rtd = pcm->private_data; + struct snd_pcm_substream *substream; + int stream; + + dev_dbg(rtd->socdev->dev, "psc_i2s_pcm_free(pcm=%p)\n", pcm); + + for (stream = 0; stream < 2; stream++) { + substream = pcm->streams[stream].substream; + if (substream) { + snd_dma_free_pages(&substream->dma_buffer); + substream->dma_buffer.area = NULL; + substream->dma_buffer.addr = 0; + } + } +} + +struct snd_soc_platform psc_i2s_pcm_soc_platform = { + .name = "mpc5200-psc-audio", + .pcm_ops = &psc_i2s_pcm_ops, + .pcm_new = &psc_i2s_pcm_new, + .pcm_free = &psc_i2s_pcm_free, +}; + +/* --------------------------------------------------------------------- + * Sysfs attributes for debugging + */ + +static ssize_t psc_i2s_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct psc_i2s *psc_i2s = dev_get_drvdata(dev); + + return sprintf(buf, "status=%.4x sicr=%.8x rfnum=%i rfstat=0x%.4x " + "tfnum=%i tfstat=0x%.4x\n", + in_be16(&psc_i2s->psc_regs->sr_csr.status), + in_be32(&psc_i2s->psc_regs->sicr), + in_be16(&psc_i2s->fifo_regs->rfnum) & 0x1ff, + in_be16(&psc_i2s->fifo_regs->rfstat), + in_be16(&psc_i2s->fifo_regs->tfnum) & 0x1ff, + in_be16(&psc_i2s->fifo_regs->tfstat)); +} + +static int *psc_i2s_get_stat_attr(struct psc_i2s *psc_i2s, const char *name) +{ + if (strcmp(name, "playback_underrun") == 0) + return &psc_i2s->stats.underrun_count; + if (strcmp(name, "capture_overrun") == 0) + return &psc_i2s->stats.overrun_count; + + return NULL; +} + +static ssize_t psc_i2s_stat_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct psc_i2s *psc_i2s = dev_get_drvdata(dev); + int *attrib; + + attrib = psc_i2s_get_stat_attr(psc_i2s, attr->attr.name); + if (!attrib) + return 0; + + return sprintf(buf, "%i\n", *attrib); +} + +static ssize_t psc_i2s_stat_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct psc_i2s *psc_i2s = dev_get_drvdata(dev); + int *attrib; + + attrib = psc_i2s_get_stat_attr(psc_i2s, attr->attr.name); + if (!attrib) + return 0; + + *attrib = simple_strtoul(buf, NULL, 0); + return count; +} + +static DEVICE_ATTR(status, 0644, psc_i2s_status_show, NULL); +static DEVICE_ATTR(playback_underrun, 0644, psc_i2s_stat_show, + psc_i2s_stat_store); +static DEVICE_ATTR(capture_overrun, 0644, psc_i2s_stat_show, + psc_i2s_stat_store); /* --------------------------------------------------------------------- * OF platform bus binding code: @@ -156,65 +718,150 @@ EXPORT_SYMBOL_GPL(psc_i2s_dai); static int __devinit psc_i2s_of_probe(struct of_device *op, const struct of_device_id *match) { - int rc; - struct psc_dma *psc_dma; - struct mpc52xx_psc __iomem *regs; - - rc = mpc5200_audio_dma_create(op); - if (rc != 0) - return rc; + phys_addr_t fifo; + struct psc_i2s *psc_i2s; + struct resource res; + int size, psc_id, irq, rc; + const __be32 *prop; + void __iomem *regs; + + dev_dbg(&op->dev, "probing psc i2s device\n"); + + /* Get the PSC ID */ + prop = of_get_property(op->node, "cell-index", &size); + if (!prop || size < sizeof *prop) + return -ENODEV; + psc_id = be32_to_cpu(*prop); + + /* Fetch the registers and IRQ of the PSC */ + irq = irq_of_parse_and_map(op->node, 0); + if (of_address_to_resource(op->node, 0, &res)) { + dev_err(&op->dev, "Missing reg property\n"); + return -ENODEV; + } + regs = ioremap(res.start, 1 + res.end - res.start); + if (!regs) { + dev_err(&op->dev, "Could not map registers\n"); + return -ENODEV; + } - rc = snd_soc_register_dais(psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai)); - if (rc != 0) { - pr_err("Failed to register DAI\n"); - return 0; + /* Allocate and initialize the driver private data */ + psc_i2s = kzalloc(sizeof *psc_i2s, GFP_KERNEL); + if (!psc_i2s) { + iounmap(regs); + return -ENOMEM; + } + spin_lock_init(&psc_i2s->lock); + psc_i2s->irq = irq; + psc_i2s->psc_regs = regs; + psc_i2s->fifo_regs = regs + sizeof *psc_i2s->psc_regs; + psc_i2s->dev = &op->dev; + psc_i2s->playback.psc_i2s = psc_i2s; + psc_i2s->capture.psc_i2s = psc_i2s; + snprintf(psc_i2s->name, sizeof psc_i2s->name, "PSC%u", psc_id+1); + + /* Fill out the CPU DAI structure */ + memcpy(&psc_i2s->dai, &psc_i2s_dai_template, sizeof psc_i2s->dai); + psc_i2s->dai.private_data = psc_i2s; + psc_i2s->dai.name = psc_i2s->name; + psc_i2s->dai.id = psc_id; + + /* Find the address of the fifo data registers and setup the + * DMA tasks */ + fifo = res.start + offsetof(struct mpc52xx_psc, buffer.buffer_32); + psc_i2s->capture.bcom_task = + bcom_psc_gen_bd_rx_init(psc_id, 10, fifo, 512); + psc_i2s->playback.bcom_task = + bcom_psc_gen_bd_tx_init(psc_id, 10, fifo); + if (!psc_i2s->capture.bcom_task || + !psc_i2s->playback.bcom_task) { + dev_err(&op->dev, "Could not allocate bestcomm tasks\n"); + iounmap(regs); + kfree(psc_i2s); + return -ENODEV; } - psc_dma = dev_get_drvdata(&op->dev); - regs = psc_dma->psc_regs; + /* Disable all interrupts and reset the PSC */ + out_be16(&psc_i2s->psc_regs->isr_imr.imr, 0); + out_8(&psc_i2s->psc_regs->command, 3 << 4); /* reset transmitter */ + out_8(&psc_i2s->psc_regs->command, 2 << 4); /* reset receiver */ + out_8(&psc_i2s->psc_regs->command, 1 << 4); /* reset mode */ + out_8(&psc_i2s->psc_regs->command, 4 << 4); /* reset error */ /* Configure the serial interface mode; defaulting to CODEC8 mode */ - psc_dma->sicr = MPC52xx_PSC_SICR_DTS1 | MPC52xx_PSC_SICR_I2S | + psc_i2s->sicr = MPC52xx_PSC_SICR_DTS1 | MPC52xx_PSC_SICR_I2S | MPC52xx_PSC_SICR_CLKPOL; - out_be32(&psc_dma->psc_regs->sicr, - psc_dma->sicr | MPC52xx_PSC_SICR_SIM_CODEC_8); + if (of_get_property(op->node, "fsl,cellslave", NULL)) + psc_i2s->sicr |= MPC52xx_PSC_SICR_CELLSLAVE | + MPC52xx_PSC_SICR_GENCLK; + out_be32(&psc_i2s->psc_regs->sicr, + psc_i2s->sicr | MPC52xx_PSC_SICR_SIM_CODEC_8); /* Check for the codec handle. If it is not present then we * are done */ if (!of_get_property(op->node, "codec-handle", NULL)) return 0; - /* Due to errata in the dma mode; need to line up enabling - * the transmitter with a transition on the frame sync - * line */ - - /* first make sure it is low */ - while ((in_8(®s->ipcr_acr.ipcr) & 0x80) != 0) - ; - /* then wait for the transition to high */ - while ((in_8(®s->ipcr_acr.ipcr) & 0x80) == 0) - ; - /* Finally, enable the PSC. - * Receiver must always be enabled; even when we only want - * transmit. (see 15.3.2.3 of MPC5200B User's Guide) */ - - /* Go */ - out_8(&psc_dma->psc_regs->command, - MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE); + /* Set up mode register; + * First write: RxRdy (FIFO Alarm) generates rx FIFO irq + * Second write: register Normal mode for non loopback + */ + out_8(&psc_i2s->psc_regs->mode, 0); + out_8(&psc_i2s->psc_regs->mode, 0); + + /* Set the TX and RX fifo alarm thresholds */ + out_be16(&psc_i2s->fifo_regs->rfalarm, 0x100); + out_8(&psc_i2s->fifo_regs->rfcntl, 0x4); + out_be16(&psc_i2s->fifo_regs->tfalarm, 0x100); + out_8(&psc_i2s->fifo_regs->tfcntl, 0x7); + + /* Lookup the IRQ numbers */ + psc_i2s->playback.irq = + bcom_get_task_irq(psc_i2s->playback.bcom_task); + psc_i2s->capture.irq = + bcom_get_task_irq(psc_i2s->capture.bcom_task); + + /* Save what we've done so it can be found again later */ + dev_set_drvdata(&op->dev, psc_i2s); + + /* Register the SYSFS files */ + rc = device_create_file(psc_i2s->dev, &dev_attr_status); + rc |= device_create_file(psc_i2s->dev, &dev_attr_capture_overrun); + rc |= device_create_file(psc_i2s->dev, &dev_attr_playback_underrun); + if (rc) + dev_info(psc_i2s->dev, "error creating sysfs files\n"); + + snd_soc_register_platform(&psc_i2s_pcm_soc_platform); + + /* Tell the ASoC OF helpers about it */ + of_snd_soc_register_platform(&psc_i2s_pcm_soc_platform, op->node, + &psc_i2s->dai); return 0; - } static int __devexit psc_i2s_of_remove(struct of_device *op) { - return mpc5200_audio_dma_destroy(op); + struct psc_i2s *psc_i2s = dev_get_drvdata(&op->dev); + + dev_dbg(&op->dev, "psc_i2s_remove()\n"); + + snd_soc_unregister_platform(&psc_i2s_pcm_soc_platform); + + bcom_gen_bd_rx_release(psc_i2s->capture.bcom_task); + bcom_gen_bd_tx_release(psc_i2s->playback.bcom_task); + + iounmap(psc_i2s->psc_regs); + iounmap(psc_i2s->fifo_regs); + kfree(psc_i2s); + dev_set_drvdata(&op->dev, NULL); + + return 0; } /* Match table for of_platform binding */ static struct of_device_id psc_i2s_match[] __devinitdata = { { .compatible = "fsl,mpc5200-psc-i2s", }, - { .compatible = "fsl,mpc5200b-psc-i2s", }, {} }; MODULE_DEVICE_TABLE(of, psc_i2s_match); @@ -245,7 +892,4 @@ static void __exit psc_i2s_exit(void) } module_exit(psc_i2s_exit); -MODULE_AUTHOR("Grant Likely "); -MODULE_DESCRIPTION("Freescale MPC5200 PSC in I2S mode ASoC Driver"); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/fsl/mpc5200_psc_i2s.h b/trunk/sound/soc/fsl/mpc5200_psc_i2s.h deleted file mode 100644 index ce55e070fdf3..000000000000 --- a/trunk/sound/soc/fsl/mpc5200_psc_i2s.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Freescale MPC5200 PSC in I2S mode - * ALSA SoC Digital Audio Interface (DAI) driver - * - */ - -#ifndef __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__ -#define __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__ - -extern struct snd_soc_dai psc_i2s_dai[]; - -#endif /* __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__ */ diff --git a/trunk/sound/soc/fsl/pcm030-audio-fabric.c b/trunk/sound/soc/fsl/pcm030-audio-fabric.c deleted file mode 100644 index 8766f7a3893d..000000000000 --- a/trunk/sound/soc/fsl/pcm030-audio-fabric.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Phytec pcm030 driver for the PSC of the Freescale MPC52xx - * configured as AC97 interface - * - * Copyright 2008 Jon Smirl, Digispeaker - * Author: Jon Smirl - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "mpc5200_dma.h" -#include "mpc5200_psc_ac97.h" -#include "../codecs/wm9712.h" - -static struct snd_soc_device device; -static struct snd_soc_card card; - -static struct snd_soc_dai_link pcm030_fabric_dai[] = { -{ - .name = "AC97", - .stream_name = "AC97 Analog", - .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI], - .cpu_dai = &psc_ac97_dai[MPC5200_AC97_NORMAL], -}, -{ - .name = "AC97", - .stream_name = "AC97 IEC958", - .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX], - .cpu_dai = &psc_ac97_dai[MPC5200_AC97_SPDIF], -}, -}; - -static __init int pcm030_fabric_init(void) -{ - struct platform_device *pdev; - int rc; - - if (!machine_is_compatible("phytec,pcm030")) - return -ENODEV; - - card.platform = &mpc5200_audio_dma_platform; - card.name = "pcm030"; - card.dai_link = pcm030_fabric_dai; - card.num_links = ARRAY_SIZE(pcm030_fabric_dai); - - device.card = &card; - device.codec_dev = &soc_codec_dev_wm9712; - - pdev = platform_device_alloc("soc-audio", 1); - if (!pdev) { - pr_err("pcm030_fabric_init: platform_device_alloc() failed\n"); - return -ENODEV; - } - - platform_set_drvdata(pdev, &device); - device.dev = &pdev->dev; - - rc = platform_device_add(pdev); - if (rc) { - pr_err("pcm030_fabric_init: platform_device_add() failed\n"); - return -ENODEV; - } - return 0; -} - -module_init(pcm030_fabric_init); - - -MODULE_AUTHOR("Jon Smirl "); -MODULE_DESCRIPTION(DRV_NAME ": mpc5200 pcm030 fabric driver"); -MODULE_LICENSE("GPL"); - diff --git a/trunk/sound/soc/omap/Kconfig b/trunk/sound/soc/omap/Kconfig index b771238662b6..675732e724d5 100644 --- a/trunk/sound/soc/omap/Kconfig +++ b/trunk/sound/soc/omap/Kconfig @@ -39,14 +39,6 @@ config SND_OMAP_SOC_OMAP2EVM help Say Y if you want to add support for SoC audio on the omap2evm board. -config SND_OMAP_SOC_OMAP3EVM - tristate "SoC Audio support for OMAP3EVM board" - depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3EVM - select SND_OMAP_SOC_MCBSP - select SND_SOC_TWL4030 - help - Say Y if you want to add support for SoC audio on the omap3evm board. - config SND_OMAP_SOC_SDP3430 tristate "SoC Audio support for Texas Instruments SDP3430" depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_3430SDP diff --git a/trunk/sound/soc/omap/Makefile b/trunk/sound/soc/omap/Makefile index a37f49862389..0c9e4ac37660 100644 --- a/trunk/sound/soc/omap/Makefile +++ b/trunk/sound/soc/omap/Makefile @@ -10,7 +10,6 @@ snd-soc-n810-objs := n810.o snd-soc-osk5912-objs := osk5912.o snd-soc-overo-objs := overo.o snd-soc-omap2evm-objs := omap2evm.o -snd-soc-omap3evm-objs := omap3evm.o snd-soc-sdp3430-objs := sdp3430.o snd-soc-omap3pandora-objs := omap3pandora.o snd-soc-omap3beagle-objs := omap3beagle.o @@ -19,7 +18,6 @@ obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o obj-$(CONFIG_MACH_OMAP2EVM) += snd-soc-omap2evm.o -obj-$(CONFIG_MACH_OMAP3EVM) += snd-soc-omap3evm.o obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o diff --git a/trunk/sound/soc/omap/n810.c b/trunk/sound/soc/omap/n810.c index b60b1dfbc435..91ef17992de5 100644 --- a/trunk/sound/soc/omap/n810.c +++ b/trunk/sound/soc/omap/n810.c @@ -383,9 +383,10 @@ static int __init n810_soc_init(void) clk_set_parent(sys_clkout2_src, func96m_clk); clk_set_rate(sys_clkout2, 12000000); - BUG_ON((gpio_request(N810_HEADSET_AMP_GPIO, "hs_amp") < 0) || - (gpio_request(N810_SPEAKER_AMP_GPIO, "spk_amp") < 0)); - + if (gpio_request(N810_HEADSET_AMP_GPIO, "hs_amp") < 0) + BUG(); + if (gpio_request(N810_SPEAKER_AMP_GPIO, "spk_amp") < 0) + BUG(); gpio_direction_output(N810_HEADSET_AMP_GPIO, 0); gpio_direction_output(N810_SPEAKER_AMP_GPIO, 0); diff --git a/trunk/sound/soc/omap/omap-mcbsp.c b/trunk/sound/soc/omap/omap-mcbsp.c index a5d46a7b196a..912614283848 100644 --- a/trunk/sound/soc/omap/omap-mcbsp.c +++ b/trunk/sound/soc/omap/omap-mcbsp.c @@ -215,9 +215,8 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id; - int wlen, channels, wpf; + int wlen, channels; unsigned long port; - unsigned int format; if (cpu_class_is_omap1()) { dma = omap1_dma_reqs[bus_id][substream->stream]; @@ -245,24 +244,18 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, return 0; } - format = mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK; - wpf = channels = params_channels(params); + channels = params_channels(params); switch (channels) { case 2: - if (format == SND_SOC_DAIFMT_I2S) { - /* Use dual-phase frames */ - regs->rcr2 |= RPHASE; - regs->xcr2 |= XPHASE; - /* Set 1 word per (McBSP) frame for phase1 and phase2 */ - wpf--; - regs->rcr2 |= RFRLEN2(wpf - 1); - regs->xcr2 |= XFRLEN2(wpf - 1); - } + /* Use dual-phase frames */ + regs->rcr2 |= RPHASE; + regs->xcr2 |= XPHASE; case 1: - case 4: - /* Set word per (McBSP) frame for phase1 */ - regs->rcr1 |= RFRLEN1(wpf - 1); - regs->xcr1 |= XFRLEN1(wpf - 1); + /* Set 1 word per (McBSP) frame */ + regs->rcr2 |= RFRLEN2(1 - 1); + regs->rcr1 |= RFRLEN1(1 - 1); + regs->xcr2 |= XFRLEN2(1 - 1); + regs->xcr1 |= XFRLEN1(1 - 1); break; default: /* Unsupported number of channels */ @@ -284,12 +277,11 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, } /* Set FS period and length in terms of bit clock periods */ - switch (format) { + switch (mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: - regs->srgr2 |= FPER(wlen * channels - 1); + regs->srgr2 |= FPER(wlen * 2 - 1); regs->srgr1 |= FWID(wlen - 1); break; - case SND_SOC_DAIFMT_DSP_A: case SND_SOC_DAIFMT_DSP_B: regs->srgr2 |= FPER(wlen * channels - 1); regs->srgr1 |= FWID(0); @@ -334,13 +326,6 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, regs->rcr2 |= RDATDLY(1); regs->xcr2 |= XDATDLY(1); break; - case SND_SOC_DAIFMT_DSP_A: - /* 1-bit data delay */ - regs->rcr2 |= RDATDLY(1); - regs->xcr2 |= XDATDLY(1); - /* Invert FS polarity configuration */ - temp_fmt ^= SND_SOC_DAIFMT_NB_IF; - break; case SND_SOC_DAIFMT_DSP_B: /* 0-bit data delay */ regs->rcr2 |= RDATDLY(0); @@ -507,13 +492,13 @@ static struct snd_soc_dai_ops omap_mcbsp_dai_ops = { .id = (link_id), \ .playback = { \ .channels_min = 1, \ - .channels_max = 4, \ + .channels_max = 2, \ .rates = OMAP_MCBSP_RATES, \ .formats = SNDRV_PCM_FMTBIT_S16_LE, \ }, \ .capture = { \ .channels_min = 1, \ - .channels_max = 4, \ + .channels_max = 2, \ .rates = OMAP_MCBSP_RATES, \ .formats = SNDRV_PCM_FMTBIT_S16_LE, \ }, \ diff --git a/trunk/sound/soc/omap/omap-pcm.c b/trunk/sound/soc/omap/omap-pcm.c index 6454e15f7d28..07cf7f46b584 100644 --- a/trunk/sound/soc/omap/omap-pcm.c +++ b/trunk/sound/soc/omap/omap-pcm.c @@ -87,10 +87,8 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream, struct omap_pcm_dma_data *dma_data = rtd->dai->cpu_dai->dma_data; int err = 0; - /* return if this is a bufferless transfer e.g. - * codec <--> BT codec or GSM modem -- lg FIXME */ if (!dma_data) - return 0; + return -ENODEV; snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); runtime->dma_bytes = params_buffer_bytes(params); @@ -136,11 +134,6 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream) struct omap_pcm_dma_data *dma_data = prtd->dma_data; struct omap_dma_channel_params dma_params; - /* return if this is a bufferless transfer e.g. - * codec <--> BT codec or GSM modem -- lg FIXME */ - if (!prtd->dma_data) - return 0; - memset(&dma_params, 0, sizeof(dma_params)); /* * Note: Regardless of interface data formats supported by OMAP McBSP diff --git a/trunk/sound/soc/omap/omap2evm.c b/trunk/sound/soc/omap/omap2evm.c index 027e1a40f8a1..0c2322dcf02a 100644 --- a/trunk/sound/soc/omap/omap2evm.c +++ b/trunk/sound/soc/omap/omap2evm.c @@ -86,7 +86,7 @@ static struct snd_soc_dai_link omap2evm_dai = { .name = "TWL4030", .stream_name = "TWL4030", .cpu_dai = &omap_mcbsp_dai[0], - .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI], + .codec_dai = &twl4030_dai, .ops = &omap2evm_ops, }; diff --git a/trunk/sound/soc/omap/omap3beagle.c b/trunk/sound/soc/omap/omap3beagle.c index b0cff9f33b7e..fd24a4acd2f5 100644 --- a/trunk/sound/soc/omap/omap3beagle.c +++ b/trunk/sound/soc/omap/omap3beagle.c @@ -41,33 +41,23 @@ static int omap3beagle_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - unsigned int fmt; int ret; - switch (params_channels(params)) { - case 2: /* Stereo I2S mode */ - fmt = SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM; - break; - case 4: /* Four channel TDM mode */ - fmt = SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_IB_NF | - SND_SOC_DAIFMT_CBM_CFM; - break; - default: - return -EINVAL; - } - /* Set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, fmt); + ret = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) { printk(KERN_ERR "can't set codec DAI configuration\n"); return ret; } /* Set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, fmt); + ret = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) { printk(KERN_ERR "can't set cpu DAI configuration\n"); return ret; @@ -93,7 +83,7 @@ static struct snd_soc_dai_link omap3beagle_dai = { .name = "TWL4030", .stream_name = "TWL4030", .cpu_dai = &omap_mcbsp_dai[0], - .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI], + .codec_dai = &twl4030_dai, .ops = &omap3beagle_ops, }; diff --git a/trunk/sound/soc/omap/omap3evm.c b/trunk/sound/soc/omap/omap3evm.c deleted file mode 100644 index 9114c263077b..000000000000 --- a/trunk/sound/soc/omap/omap3evm.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * omap3evm.c -- ALSA SoC support for OMAP3 EVM - * - * Author: Anuj Aggarwal - * - * Based on sound/soc/omap/beagle.c by Steve Sakoman - * - * Copyright (C) 2008 Texas Instruments, Incorporated - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, - * whether express or implied; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "omap-mcbsp.h" -#include "omap-pcm.h" -#include "../codecs/twl4030.h" - -static int omap3evm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - int ret; - - /* Set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) { - printk(KERN_ERR "Can't set codec DAI configuration\n"); - return ret; - } - - /* Set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) { - printk(KERN_ERR "Can't set cpu DAI configuration\n"); - return ret; - } - - /* Set the codec system clock for DAC and ADC */ - ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, - SND_SOC_CLOCK_IN); - if (ret < 0) { - printk(KERN_ERR "Can't set codec system clock\n"); - return ret; - } - - return 0; -} - -static struct snd_soc_ops omap3evm_ops = { - .hw_params = omap3evm_hw_params, -}; - -/* Digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link omap3evm_dai = { - .name = "TWL4030", - .stream_name = "TWL4030", - .cpu_dai = &omap_mcbsp_dai[0], - .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI], - .ops = &omap3evm_ops, -}; - -/* Audio machine driver */ -static struct snd_soc_card snd_soc_omap3evm = { - .name = "omap3evm", - .platform = &omap_soc_platform, - .dai_link = &omap3evm_dai, - .num_links = 1, -}; - -/* Audio subsystem */ -static struct snd_soc_device omap3evm_snd_devdata = { - .card = &snd_soc_omap3evm, - .codec_dev = &soc_codec_dev_twl4030, -}; - -static struct platform_device *omap3evm_snd_device; - -static int __init omap3evm_soc_init(void) -{ - int ret; - - if (!machine_is_omap3evm()) { - pr_err("Not OMAP3 EVM!\n"); - return -ENODEV; - } - pr_info("OMAP3 EVM SoC init\n"); - - omap3evm_snd_device = platform_device_alloc("soc-audio", -1); - if (!omap3evm_snd_device) { - printk(KERN_ERR "Platform device allocation failed\n"); - return -ENOMEM; - } - - platform_set_drvdata(omap3evm_snd_device, &omap3evm_snd_devdata); - omap3evm_snd_devdata.dev = &omap3evm_snd_device->dev; - *(unsigned int *)omap3evm_dai.cpu_dai->private_data = 1; - - ret = platform_device_add(omap3evm_snd_device); - if (ret) - goto err1; - - return 0; - -err1: - printk(KERN_ERR "Unable to add platform device\n"); - platform_device_put(omap3evm_snd_device); - - return ret; -} - -static void __exit omap3evm_soc_exit(void) -{ - platform_device_unregister(omap3evm_snd_device); -} - -module_init(omap3evm_soc_init); -module_exit(omap3evm_soc_exit); - -MODULE_AUTHOR("Anuj Aggarwal "); -MODULE_DESCRIPTION("ALSA SoC OMAP3 EVM"); -MODULE_LICENSE("GPLv2"); diff --git a/trunk/sound/soc/omap/omap3pandora.c b/trunk/sound/soc/omap/omap3pandora.c index ad219aaf7cb8..fe282d4ef422 100644 --- a/trunk/sound/soc/omap/omap3pandora.c +++ b/trunk/sound/soc/omap/omap3pandora.c @@ -228,14 +228,14 @@ static struct snd_soc_dai_link omap3pandora_dai[] = { .name = "PCM1773", .stream_name = "HiFi Out", .cpu_dai = &omap_mcbsp_dai[0], - .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI], + .codec_dai = &twl4030_dai, .ops = &omap3pandora_out_ops, .init = omap3pandora_out_init, }, { .name = "TWL4030", .stream_name = "Line/Mic In", .cpu_dai = &omap_mcbsp_dai[1], - .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI], + .codec_dai = &twl4030_dai, .ops = &omap3pandora_in_ops, .init = omap3pandora_in_init, } diff --git a/trunk/sound/soc/omap/overo.c b/trunk/sound/soc/omap/overo.c index ec4f8fd8b3a2..a72dc4e159e5 100644 --- a/trunk/sound/soc/omap/overo.c +++ b/trunk/sound/soc/omap/overo.c @@ -83,7 +83,7 @@ static struct snd_soc_dai_link overo_dai = { .name = "TWL4030", .stream_name = "TWL4030", .cpu_dai = &omap_mcbsp_dai[0], - .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI], + .codec_dai = &twl4030_dai, .ops = &overo_ops, }; diff --git a/trunk/sound/soc/omap/sdp3430.c b/trunk/sound/soc/omap/sdp3430.c index b719e5db4f57..10f1c867f11d 100644 --- a/trunk/sound/soc/omap/sdp3430.c +++ b/trunk/sound/soc/omap/sdp3430.c @@ -84,49 +84,6 @@ static struct snd_soc_ops sdp3430_ops = { .hw_params = sdp3430_hw_params, }; -static int sdp3430_hw_voice_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - int ret; - - /* Set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_IB_NF | - SND_SOC_DAIFMT_CBS_CFM); - if (ret) { - printk(KERN_ERR "can't set codec DAI configuration\n"); - return ret; - } - - /* Set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, - SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_IB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) { - printk(KERN_ERR "can't set cpu DAI configuration\n"); - return ret; - } - - /* Set the codec system clock for DAC and ADC */ - ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, - SND_SOC_CLOCK_IN); - if (ret < 0) { - printk(KERN_ERR "can't set codec system clock\n"); - return ret; - } - - return 0; -} - -static struct snd_soc_ops sdp3430_voice_ops = { - .hw_params = sdp3430_hw_voice_params, -}; - /* Headset jack */ static struct snd_soc_jack hs_jack; @@ -235,58 +192,28 @@ static int sdp3430_twl4030_init(struct snd_soc_codec *codec) return ret; } -static int sdp3430_twl4030_voice_init(struct snd_soc_codec *codec) -{ - unsigned short reg; - - /* Enable voice interface */ - reg = codec->read(codec, TWL4030_REG_VOICE_IF); - reg |= TWL4030_VIF_DIN_EN | TWL4030_VIF_DOUT_EN | TWL4030_VIF_EN; - codec->write(codec, TWL4030_REG_VOICE_IF, reg); - - return 0; -} - - /* Digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link sdp3430_dai[] = { - { - .name = "TWL4030 I2S", - .stream_name = "TWL4030 Audio", - .cpu_dai = &omap_mcbsp_dai[0], - .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI], - .init = sdp3430_twl4030_init, - .ops = &sdp3430_ops, - }, - { - .name = "TWL4030 PCM", - .stream_name = "TWL4030 Voice", - .cpu_dai = &omap_mcbsp_dai[1], - .codec_dai = &twl4030_dai[TWL4030_DAI_VOICE], - .init = sdp3430_twl4030_voice_init, - .ops = &sdp3430_voice_ops, - }, +static struct snd_soc_dai_link sdp3430_dai = { + .name = "TWL4030", + .stream_name = "TWL4030", + .cpu_dai = &omap_mcbsp_dai[0], + .codec_dai = &twl4030_dai, + .init = sdp3430_twl4030_init, + .ops = &sdp3430_ops, }; /* Audio machine driver */ static struct snd_soc_card snd_soc_sdp3430 = { .name = "SDP3430", .platform = &omap_soc_platform, - .dai_link = sdp3430_dai, - .num_links = ARRAY_SIZE(sdp3430_dai), -}; - -/* twl4030 setup */ -static struct twl4030_setup_data twl4030_setup = { - .ramp_delay_value = 3, - .sysclk = 26000, + .dai_link = &sdp3430_dai, + .num_links = 1, }; /* Audio subsystem */ static struct snd_soc_device sdp3430_snd_devdata = { .card = &snd_soc_sdp3430, .codec_dev = &soc_codec_dev_twl4030, - .codec_data = &twl4030_setup, }; static struct platform_device *sdp3430_snd_device; @@ -309,8 +236,7 @@ static int __init sdp3430_soc_init(void) platform_set_drvdata(sdp3430_snd_device, &sdp3430_snd_devdata); sdp3430_snd_devdata.dev = &sdp3430_snd_device->dev; - *(unsigned int *)sdp3430_dai[0].cpu_dai->private_data = 1; /* McBSP2 */ - *(unsigned int *)sdp3430_dai[1].cpu_dai->private_data = 2; /* McBSP3 */ + *(unsigned int *)sdp3430_dai.cpu_dai->private_data = 1; /* McBSP2 */ ret = platform_device_add(sdp3430_snd_device); if (ret) diff --git a/trunk/sound/soc/pxa/Kconfig b/trunk/sound/soc/pxa/Kconfig index dcd163a4ee9a..ad8a10fe6298 100644 --- a/trunk/sound/soc/pxa/Kconfig +++ b/trunk/sound/soc/pxa/Kconfig @@ -89,13 +89,13 @@ config SND_PXA2XX_SOC_E800 Toshiba e800 PDA config SND_PXA2XX_SOC_EM_X270 - tristate "SoC Audio support for CompuLab EM-x270, eXeda and CM-X300" + tristate "SoC Audio support for CompuLab EM-x270" depends on SND_PXA2XX_SOC && MACH_EM_X270 select SND_PXA2XX_SOC_AC97 select SND_SOC_WM9712 help Say Y if you want to add support for SoC audio on - CompuLab EM-x270, eXeda and CM-X300 machines. + CompuLab EM-x270. config SND_PXA2XX_SOC_PALM27X bool "SoC Audio support for Palm T|X, T5 and LifeDrive" @@ -134,12 +134,3 @@ config SND_PXA2XX_SOC_MIOA701 help Say Y if you want to add support for SoC audio on the MIO A701. - -config SND_PXA2XX_SOC_IMOTE2 - tristate "SoC Audio support for IMote 2" - depends on SND_PXA2XX_SOC && MACH_INTELMOTE2 - select SND_PXA2XX_SOC_I2S - select SND_SOC_WM8940 - help - Say Y if you want to add support for SoC audio on the - IMote 2. diff --git a/trunk/sound/soc/pxa/Makefile b/trunk/sound/soc/pxa/Makefile index 6e096b480335..4b90c3ccae45 100644 --- a/trunk/sound/soc/pxa/Makefile +++ b/trunk/sound/soc/pxa/Makefile @@ -22,7 +22,6 @@ snd-soc-palm27x-objs := palm27x.o snd-soc-zylonite-objs := zylonite.o snd-soc-magician-objs := magician.o snd-soc-mioa701-objs := mioa701_wm9713.o -snd-soc-imote2-objs := imote2.o obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o @@ -36,4 +35,3 @@ obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o obj-$(CONFIG_SND_PXA2XX_SOC_MAGICIAN) += snd-soc-magician.o obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o -obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o diff --git a/trunk/sound/soc/pxa/em-x270.c b/trunk/sound/soc/pxa/em-x270.c index f4756e4025fd..949be9c2a01b 100644 --- a/trunk/sound/soc/pxa/em-x270.c +++ b/trunk/sound/soc/pxa/em-x270.c @@ -1,7 +1,7 @@ /* - * SoC audio driver for EM-X270, eXeda and CM-X300 + * em-x270.c -- SoC audio for EM-X270 * - * Copyright 2007, 2009 CompuLab, Ltd. + * Copyright 2007 CompuLab, Ltd. * * Author: Mike Rapoport * @@ -68,8 +68,7 @@ static int __init em_x270_init(void) { int ret; - if (!(machine_is_em_x270() || machine_is_exeda() - || machine_is_cm_x300())) + if (!machine_is_em_x270()) return -ENODEV; em_x270_snd_device = platform_device_alloc("soc-audio", -1); @@ -96,5 +95,5 @@ module_exit(em_x270_exit); /* Module information */ MODULE_AUTHOR("Mike Rapoport"); -MODULE_DESCRIPTION("ALSA SoC EM-X270, eXeda and CM-X300"); +MODULE_DESCRIPTION("ALSA SoC EM-X270"); MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/pxa/imote2.c b/trunk/sound/soc/pxa/imote2.c deleted file mode 100644 index 405587a01160..000000000000 --- a/trunk/sound/soc/pxa/imote2.c +++ /dev/null @@ -1,114 +0,0 @@ - -#include -#include - -#include - -#include "../codecs/wm8940.h" -#include "pxa2xx-i2s.h" -#include "pxa2xx-pcm.h" - -static int imote2_asoc_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - unsigned int clk = 0; - int ret; - - switch (params_rate(params)) { - case 8000: - case 16000: - case 48000: - case 96000: - clk = 12288000; - break; - case 11025: - case 22050: - case 44100: - clk = 11289600; - break; - } - - /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S - | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - - /* CPU should be clock master */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S - | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk, - SND_SOC_CLOCK_IN); - if (ret < 0) - return ret; - - /* set the I2S system clock as input (unused) */ - ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, clk, - SND_SOC_CLOCK_OUT); - - return ret; -} - -static struct snd_soc_ops imote2_asoc_ops = { - .hw_params = imote2_asoc_hw_params, -}; - -static struct snd_soc_dai_link imote2_dai = { - .name = "WM8940", - .stream_name = "WM8940", - .cpu_dai = &pxa_i2s_dai, - .codec_dai = &wm8940_dai, - .ops = &imote2_asoc_ops, -}; - -static struct snd_soc_card snd_soc_imote2 = { - .name = "Imote2", - .platform = &pxa2xx_soc_platform, - .dai_link = &imote2_dai, - .num_links = 1, -}; - -static struct snd_soc_device imote2_snd_devdata = { - .card = &snd_soc_imote2, - .codec_dev = &soc_codec_dev_wm8940, -}; - -static struct platform_device *imote2_snd_device; - -static int __init imote2_asoc_init(void) -{ - int ret; - - if (!machine_is_intelmote2()) - return -ENODEV; - imote2_snd_device = platform_device_alloc("soc-audio", -1); - if (!imote2_snd_device) - return -ENOMEM; - - platform_set_drvdata(imote2_snd_device, &imote2_snd_devdata); - imote2_snd_devdata.dev = &imote2_snd_device->dev; - ret = platform_device_add(imote2_snd_device); - if (ret) - platform_device_put(imote2_snd_device); - - return ret; -} -module_init(imote2_asoc_init); - -static void __exit imote2_asoc_exit(void) -{ - platform_device_unregister(imote2_snd_device); -} -module_exit(imote2_asoc_exit); - -MODULE_AUTHOR("Jonathan Cameron"); -MODULE_DESCRIPTION("ALSA SoC Imote 2"); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/pxa/magician.c b/trunk/sound/soc/pxa/magician.c index 326955dea36c..0625c342a1c9 100644 --- a/trunk/sound/soc/pxa/magician.c +++ b/trunk/sound/soc/pxa/magician.c @@ -106,7 +106,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream, /* 513156 Hz ~= _2_ * 8000 Hz * 32 (+0.23%) */ acds = PXA_SSP_CLK_AUDIO_DIV_16; break; - default: /* 32 */ + case 32: /* 1026312 Hz ~= _2_ * 8000 Hz * 64 (+0.23%) */ acds = PXA_SSP_CLK_AUDIO_DIV_8; } @@ -118,7 +118,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream, /* 351375 Hz ~= 11025 Hz * 32 (-0.41%) */ acds = PXA_SSP_CLK_AUDIO_DIV_4; break; - default: /* 32 */ + case 32: /* 702750 Hz ~= 11025 Hz * 64 (-0.41%) */ acds = PXA_SSP_CLK_AUDIO_DIV_2; } @@ -130,7 +130,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream, /* 702750 Hz ~= 22050 Hz * 32 (-0.41%) */ acds = PXA_SSP_CLK_AUDIO_DIV_2; break; - default: /* 32 */ + case 32: /* 1405500 Hz ~= 22050 Hz * 64 (-0.41%) */ acds = PXA_SSP_CLK_AUDIO_DIV_1; } @@ -142,7 +142,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream, /* 1405500 Hz ~= 44100 Hz * 32 (-0.41%) */ acds = PXA_SSP_CLK_AUDIO_DIV_2; break; - default: /* 32 */ + case 32: /* 2811000 Hz ~= 44100 Hz * 64 (-0.41%) */ acds = PXA_SSP_CLK_AUDIO_DIV_1; } @@ -154,20 +154,19 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream, /* 1529375 Hz ~= 48000 Hz * 32 (-0.44%) */ acds = PXA_SSP_CLK_AUDIO_DIV_2; break; - default: /* 32 */ + case 32: /* 3058750 Hz ~= 48000 Hz * 64 (-0.44%) */ acds = PXA_SSP_CLK_AUDIO_DIV_1; } break; case 96000: - default: acps = 12235000; switch (width) { case 16: /* 3058750 Hz ~= 96000 Hz * 32 (-0.44%) */ acds = PXA_SSP_CLK_AUDIO_DIV_1; break; - default: /* 32 */ + case 32: /* 6117500 Hz ~= 96000 Hz * 64 (-0.44%) */ acds = PXA_SSP_CLK_AUDIO_DIV_2; div4 = PXA_SSP_CLK_SCDB_1; @@ -184,7 +183,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream, /* set cpu DAI configuration */ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_CBS_CFS); + SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBS_CFS); if (ret < 0) return ret; diff --git a/trunk/sound/soc/pxa/pxa-ssp.c b/trunk/sound/soc/pxa/pxa-ssp.c index 19c45409d94c..286be31545df 100644 --- a/trunk/sound/soc/pxa/pxa-ssp.c +++ b/trunk/sound/soc/pxa/pxa-ssp.c @@ -50,6 +50,139 @@ struct ssp_priv { #endif }; +#define PXA2xx_SSP1_BASE 0x41000000 +#define PXA27x_SSP2_BASE 0x41700000 +#define PXA27x_SSP3_BASE 0x41900000 +#define PXA3xx_SSP4_BASE 0x41a00000 + +static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_mono_out = { + .name = "SSP1 PCM Mono out", + .dev_addr = PXA2xx_SSP1_BASE + SSDR, + .drcmr = &DRCMR(14), + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST16 | DCMD_WIDTH2, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_mono_in = { + .name = "SSP1 PCM Mono in", + .dev_addr = PXA2xx_SSP1_BASE + SSDR, + .drcmr = &DRCMR(13), + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST16 | DCMD_WIDTH2, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_stereo_out = { + .name = "SSP1 PCM Stereo out", + .dev_addr = PXA2xx_SSP1_BASE + SSDR, + .drcmr = &DRCMR(14), + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST16 | DCMD_WIDTH4, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_stereo_in = { + .name = "SSP1 PCM Stereo in", + .dev_addr = PXA2xx_SSP1_BASE + SSDR, + .drcmr = &DRCMR(13), + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST16 | DCMD_WIDTH4, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_mono_out = { + .name = "SSP2 PCM Mono out", + .dev_addr = PXA27x_SSP2_BASE + SSDR, + .drcmr = &DRCMR(16), + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST16 | DCMD_WIDTH2, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_mono_in = { + .name = "SSP2 PCM Mono in", + .dev_addr = PXA27x_SSP2_BASE + SSDR, + .drcmr = &DRCMR(15), + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST16 | DCMD_WIDTH2, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_stereo_out = { + .name = "SSP2 PCM Stereo out", + .dev_addr = PXA27x_SSP2_BASE + SSDR, + .drcmr = &DRCMR(16), + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST16 | DCMD_WIDTH4, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_stereo_in = { + .name = "SSP2 PCM Stereo in", + .dev_addr = PXA27x_SSP2_BASE + SSDR, + .drcmr = &DRCMR(15), + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST16 | DCMD_WIDTH4, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_mono_out = { + .name = "SSP3 PCM Mono out", + .dev_addr = PXA27x_SSP3_BASE + SSDR, + .drcmr = &DRCMR(67), + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST16 | DCMD_WIDTH2, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_mono_in = { + .name = "SSP3 PCM Mono in", + .dev_addr = PXA27x_SSP3_BASE + SSDR, + .drcmr = &DRCMR(66), + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST16 | DCMD_WIDTH2, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_stereo_out = { + .name = "SSP3 PCM Stereo out", + .dev_addr = PXA27x_SSP3_BASE + SSDR, + .drcmr = &DRCMR(67), + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST16 | DCMD_WIDTH4, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_stereo_in = { + .name = "SSP3 PCM Stereo in", + .dev_addr = PXA27x_SSP3_BASE + SSDR, + .drcmr = &DRCMR(66), + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST16 | DCMD_WIDTH4, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_mono_out = { + .name = "SSP4 PCM Mono out", + .dev_addr = PXA3xx_SSP4_BASE + SSDR, + .drcmr = &DRCMR(67), + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST16 | DCMD_WIDTH2, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_mono_in = { + .name = "SSP4 PCM Mono in", + .dev_addr = PXA3xx_SSP4_BASE + SSDR, + .drcmr = &DRCMR(66), + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST16 | DCMD_WIDTH2, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_stereo_out = { + .name = "SSP4 PCM Stereo out", + .dev_addr = PXA3xx_SSP4_BASE + SSDR, + .drcmr = &DRCMR(67), + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST16 | DCMD_WIDTH4, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_stereo_in = { + .name = "SSP4 PCM Stereo in", + .dev_addr = PXA3xx_SSP4_BASE + SSDR, + .drcmr = &DRCMR(66), + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST16 | DCMD_WIDTH4, +}; + static void dump_registers(struct ssp_device *ssp) { dev_dbg(&ssp->pdev->dev, "SSCR0 0x%08x SSCR1 0x%08x SSTO 0x%08x\n", @@ -61,33 +194,25 @@ static void dump_registers(struct ssp_device *ssp) ssp_read_reg(ssp, SSACD)); } -struct pxa2xx_pcm_dma_data { - struct pxa2xx_pcm_dma_params params; - char name[20]; +static struct pxa2xx_pcm_dma_params *ssp_dma_params[4][4] = { + { + &pxa_ssp1_pcm_mono_out, &pxa_ssp1_pcm_mono_in, + &pxa_ssp1_pcm_stereo_out, &pxa_ssp1_pcm_stereo_in, + }, + { + &pxa_ssp2_pcm_mono_out, &pxa_ssp2_pcm_mono_in, + &pxa_ssp2_pcm_stereo_out, &pxa_ssp2_pcm_stereo_in, + }, + { + &pxa_ssp3_pcm_mono_out, &pxa_ssp3_pcm_mono_in, + &pxa_ssp3_pcm_stereo_out, &pxa_ssp3_pcm_stereo_in, + }, + { + &pxa_ssp4_pcm_mono_out, &pxa_ssp4_pcm_mono_in, + &pxa_ssp4_pcm_stereo_out, &pxa_ssp4_pcm_stereo_in, + }, }; -static struct pxa2xx_pcm_dma_params * -ssp_get_dma_params(struct ssp_device *ssp, int width4, int out) -{ - struct pxa2xx_pcm_dma_data *dma; - - dma = kzalloc(sizeof(struct pxa2xx_pcm_dma_data), GFP_KERNEL); - if (dma == NULL) - return NULL; - - snprintf(dma->name, 20, "SSP%d PCM %s %s", ssp->port_id, - width4 ? "32-bit" : "16-bit", out ? "out" : "in"); - - dma->params.name = dma->name; - dma->params.drcmr = &DRCMR(out ? ssp->drcmr_tx : ssp->drcmr_rx); - dma->params.dcmd = (out ? (DCMD_INCSRCADDR | DCMD_FLOWTRG) : - (DCMD_INCTRGADDR | DCMD_FLOWSRC)) | - (width4 ? DCMD_WIDTH4 : DCMD_WIDTH2) | DCMD_BURST16; - dma->params.dev_addr = ssp->phys_base + SSDR; - - return &dma->params; -} - static int pxa_ssp_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -102,11 +227,6 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream, clk_enable(priv->dev.ssp->clk); ssp_disable(&priv->dev); } - - if (cpu_dai->dma_data) { - kfree(cpu_dai->dma_data); - cpu_dai->dma_data = NULL; - } return ret; } @@ -121,11 +241,6 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream, ssp_disable(&priv->dev); clk_disable(priv->dev.ssp->clk); } - - if (cpu_dai->dma_data) { - kfree(cpu_dai->dma_data); - cpu_dai->dma_data = NULL; - } } #ifdef CONFIG_PM @@ -208,7 +323,7 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai, ~(SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ACS); dev_dbg(&ssp->pdev->dev, - "pxa_ssp_set_dai_sysclk id: %d, clk_id %d, freq %u\n", + "pxa_ssp_set_dai_sysclk id: %d, clk_id %d, freq %d\n", cpu_dai->id, clk_id, freq); switch (clk_id) { @@ -357,7 +472,7 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, ssacd |= (0x6 << 4); dev_dbg(&ssp->pdev->dev, - "Using SSACDD %x to supply %uHz\n", + "Using SSACDD %x to supply %dHz\n", val, freq_out); break; } @@ -474,10 +589,7 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai, case SND_SOC_DAIFMT_NB_IF: break; case SND_SOC_DAIFMT_IB_IF: - sspsp |= SSPSP_SCMODE(2); - break; - case SND_SOC_DAIFMT_IB_NF: - sspsp |= SSPSP_SCMODE(2) | SSPSP_SFRMP; + sspsp |= SSPSP_SCMODE(3); break; default: return -EINVAL; @@ -494,13 +606,7 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai, case SND_SOC_DAIFMT_NB_NF: sspsp |= SSPSP_SFRMP; break; - case SND_SOC_DAIFMT_NB_IF: - break; case SND_SOC_DAIFMT_IB_IF: - sspsp |= SSPSP_SCMODE(2); - break; - case SND_SOC_DAIFMT_IB_NF: - sspsp |= SSPSP_SCMODE(2) | SSPSP_SFRMP; break; default: return -EINVAL; @@ -538,23 +644,25 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; struct ssp_priv *priv = cpu_dai->private_data; struct ssp_device *ssp = priv->dev.ssp; - int chn = params_channels(params); + int dma = 0, chn = params_channels(params); u32 sscr0; u32 sspsp; int width = snd_pcm_format_physical_width(params_format(params)); int ttsa = ssp_read_reg(ssp, SSTSA) & 0xf; - /* generate correct DMA params */ - if (cpu_dai->dma_data) - kfree(cpu_dai->dma_data); - + /* select correct DMA params */ + if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) + dma = 1; /* capture DMA offset is 1,3 */ /* Network mode with one active slot (ttsa == 1) can be used * to force 16-bit frame width on the wire (for S16_LE), even * with two channels. Use 16-bit DMA transfers for this case. */ - cpu_dai->dma_data = ssp_get_dma_params(ssp, - ((chn == 2) && (ttsa != 1)) || (width == 32), - substream->stream == SNDRV_PCM_STREAM_PLAYBACK); + if (((chn == 2) && (ttsa != 1)) || (width == 32)) + dma += 2; /* 32-bit DMA offset is 2, 16-bit is 0 */ + + cpu_dai->dma_data = ssp_dma_params[cpu_dai->id][dma]; + + dev_dbg(&ssp->pdev->dev, "pxa_ssp_hw_params: dma %d\n", dma); /* we can only change the settings if the port is not in use */ if (ssp_read_reg(ssp, SSCR0) & SSCR0_SSE) diff --git a/trunk/sound/soc/pxa/pxa2xx-i2s.c b/trunk/sound/soc/pxa/pxa2xx-i2s.c index 4743e262895d..2f4b6e489b78 100644 --- a/trunk/sound/soc/pxa/pxa2xx-i2s.c +++ b/trunk/sound/soc/pxa/pxa2xx-i2s.c @@ -106,8 +106,10 @@ static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream, if (IS_ERR(clk_i2s)) return PTR_ERR(clk_i2s); - if (!cpu_dai->active) + if (!cpu_dai->active) { + SACR0 |= SACR0_RST; SACR0 = 0; + } return 0; } @@ -176,7 +178,9 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, /* is port used by another stream */ if (!(SACR0 & SACR0_ENB)) { + SACR0 = 0; + SACR1 = 0; if (pxa_i2s.master) SACR0 |= SACR0_BCKD; @@ -222,10 +226,6 @@ static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, switch (cmd) { case SNDRV_PCM_TRIGGER_START: - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - SACR1 &= ~SACR1_DRPL; - else - SACR1 &= ~SACR1_DREC; SACR0 |= SACR0_ENB; break; case SNDRV_PCM_TRIGGER_RESUME: @@ -252,16 +252,21 @@ static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream, SAIMR &= ~SAIMR_RFS; } - if ((SACR1 & (SACR1_DREC | SACR1_DRPL)) == (SACR1_DREC | SACR1_DRPL)) { + if (SACR1 & (SACR1_DREC | SACR1_DRPL)) { SACR0 &= ~SACR0_ENB; pxa_i2s_wait(); clk_disable(clk_i2s); } + + clk_put(clk_i2s); } #ifdef CONFIG_PM static int pxa2xx_i2s_suspend(struct snd_soc_dai *dai) { + if (!dai->active) + return 0; + /* store registers */ pxa_i2s.sacr0 = SACR0; pxa_i2s.sacr1 = SACR1; @@ -276,14 +281,16 @@ static int pxa2xx_i2s_suspend(struct snd_soc_dai *dai) static int pxa2xx_i2s_resume(struct snd_soc_dai *dai) { + if (!dai->active) + return 0; + pxa_i2s_wait(); - SACR0 = pxa_i2s.sacr0 & ~SACR0_ENB; + SACR0 = pxa_i2s.sacr0 &= ~SACR0_ENB; SACR1 = pxa_i2s.sacr1; SAIMR = pxa_i2s.saimr; SADIV = pxa_i2s.sadiv; - - SACR0 = pxa_i2s.sacr0; + SACR0 |= SACR0_ENB; return 0; } @@ -322,7 +329,6 @@ struct snd_soc_dai pxa_i2s_dai = { .rates = PXA2XX_I2S_RATES, .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = &pxa_i2s_dai_ops, - .symmetric_rates = 1, }; EXPORT_SYMBOL_GPL(pxa_i2s_dai); @@ -340,19 +346,6 @@ static int pxa2xx_i2s_probe(struct platform_device *dev) if (ret != 0) clk_put(clk_i2s); - /* - * PXA Developer's Manual: - * If SACR0[ENB] is toggled in the middle of a normal operation, - * the SACR0[RST] bit must also be set and cleared to reset all - * I2S controller registers. - */ - SACR0 = SACR0_RST; - SACR0 = 0; - /* Make sure RPL and REC are disabled */ - SACR1 = SACR1_DRPL | SACR1_DREC; - /* Along with FIFO servicing */ - SAIMR &= ~(SAIMR_RFS | SAIMR_TFS); - return ret; } diff --git a/trunk/sound/soc/s3c24xx/neo1973_wm8753.c b/trunk/sound/soc/s3c24xx/neo1973_wm8753.c index 906709e6dd5f..289fadf60b10 100644 --- a/trunk/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/trunk/sound/soc/s3c24xx/neo1973_wm8753.c @@ -345,11 +345,9 @@ static void lm4857_write_regs(void) static int lm4857_get_reg(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - int reg = mc->reg; - int shift = mc->shift; - int mask = mc->max; + int reg = kcontrol->private_value & 0xFF; + int shift = (kcontrol->private_value >> 8) & 0x0F; + int mask = (kcontrol->private_value >> 16) & 0xFF; pr_debug("Entered %s\n", __func__); @@ -360,11 +358,9 @@ static int lm4857_get_reg(struct snd_kcontrol *kcontrol, static int lm4857_set_reg(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - int reg = mc->reg; - int shift = mc->shift; - int mask = mc->max; + int reg = kcontrol->private_value & 0xFF; + int shift = (kcontrol->private_value >> 8) & 0x0F; + int mask = (kcontrol->private_value >> 16) & 0xFF; if (((lm4857_regs[reg] >> shift) & mask) == ucontrol->value.integer.value[0]) diff --git a/trunk/sound/soc/s3c24xx/s3c-i2s-v2.c b/trunk/sound/soc/s3c24xx/s3c-i2s-v2.c index 1a283170ca92..ab680aac3fcb 100644 --- a/trunk/sound/soc/s3c24xx/s3c-i2s-v2.c +++ b/trunk/sound/soc/s3c24xx/s3c-i2s-v2.c @@ -37,20 +37,6 @@ #include "s3c-i2s-v2.h" -#undef S3C_IIS_V2_SUPPORTED - -#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) -#define S3C_IIS_V2_SUPPORTED -#endif - -#ifdef CONFIG_PLAT_S3C64XX -#define S3C_IIS_V2_SUPPORTED -#endif - -#ifndef S3C_IIS_V2_SUPPORTED -#error Unsupported CPU model -#endif - #define S3C2412_I2S_DEBUG_CON 0 static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai) @@ -89,7 +75,7 @@ static inline void dbg_showcon(const char *fn, u32 con) /* Turn on or off the transmission path. */ -static void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on) +void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on) { void __iomem *regs = i2s->regs; u32 fic, con, mod; @@ -119,9 +105,7 @@ static void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on) break; default: - dev_err(i2s->dev, "TXEN: Invalid MODE %x in IISMOD\n", - mod & S3C2412_IISMOD_MODE_MASK); - break; + dev_err(i2s->dev, "TXEN: Invalid MODE in IISMOD\n"); } writel(con, regs + S3C2412_IISCON); @@ -148,9 +132,7 @@ static void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on) break; default: - dev_err(i2s->dev, "TXDIS: Invalid MODE %x in IISMOD\n", - mod & S3C2412_IISMOD_MODE_MASK); - break; + dev_err(i2s->dev, "TXDIS: Invalid MODE in IISMOD\n"); } writel(mod, regs + S3C2412_IISMOD); @@ -161,8 +143,9 @@ static void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on) dbg_showcon(__func__, con); pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); } +EXPORT_SYMBOL_GPL(s3c2412_snd_txctrl); -static void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on) +void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on) { void __iomem *regs = i2s->regs; u32 fic, con, mod; @@ -192,8 +175,7 @@ static void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on) break; default: - dev_err(i2s->dev, "RXEN: Invalid MODE %x in IISMOD\n", - mod & S3C2412_IISMOD_MODE_MASK); + dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n"); } writel(mod, regs + S3C2412_IISMOD); @@ -217,8 +199,7 @@ static void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on) break; default: - dev_err(i2s->dev, "RXDIS: Invalid MODE %x in IISMOD\n", - mod & S3C2412_IISMOD_MODE_MASK); + dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n"); } writel(con, regs + S3C2412_IISCON); @@ -228,6 +209,7 @@ static void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on) fic = readl(regs + S3C2412_IISFIC); pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); } +EXPORT_SYMBOL_GPL(s3c2412_snd_rxctrl); /* * Wait for the LR signal to allow synchronisation to the L/R clock @@ -284,7 +266,7 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, */ #define IISMOD_MASTER_MASK (1 << 11) #define IISMOD_SLAVE (1 << 11) -#define IISMOD_MASTER (0 << 11) +#define IISMOD_MASTER (0x0) #endif switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { @@ -299,7 +281,7 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, iismod |= IISMOD_MASTER; break; default: - pr_err("unknwon master/slave format\n"); + pr_debug("unknwon master/slave format\n"); return -EINVAL; } @@ -316,7 +298,7 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, iismod |= S3C2412_IISMOD_SDF_IIS; break; default: - pr_err("Unknown data format\n"); + pr_debug("Unknown data format\n"); return -EINVAL; } @@ -345,7 +327,6 @@ static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, iismod = readl(i2s->regs + S3C2412_IISMOD); pr_debug("%s: r: IISMOD: %x\n", __func__, iismod); -#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: iismod |= S3C2412_IISMOD_8BIT; @@ -354,25 +335,6 @@ static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, iismod &= ~S3C2412_IISMOD_8BIT; break; } -#endif - -#ifdef CONFIG_PLAT_S3C64XX - iismod &= ~0x606; - /* Sample size */ - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S8: - /* 8 bit sample, 16fs BCLK */ - iismod |= 0x2004; - break; - case SNDRV_PCM_FORMAT_S16_LE: - /* 16 bit sample, 32fs BCLK */ - break; - case SNDRV_PCM_FORMAT_S24_LE: - /* 24 bit sample, 48fs BCLK */ - iismod |= 0x4002; - break; - } -#endif writel(iismod, i2s->regs + S3C2412_IISMOD); pr_debug("%s: w: IISMOD: %x\n", __func__, iismod); @@ -527,8 +489,6 @@ int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info, unsigned int best_rate = 0; unsigned int best_deviation = INT_MAX; - pr_debug("Input clock rate %ldHz\n", clkrate); - if (fstab == NULL) fstab = iis_fs_tab; @@ -547,7 +507,7 @@ int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info, actual = clkrate / (fsdiv * div); deviation = actual - rate; - printk(KERN_DEBUG "%ufs: div %u => result %u, deviation %d\n", + printk(KERN_DEBUG "%dfs: div %d => result %d, deviation %d\n", fsdiv, div, actual, deviation); deviation = abs(deviation); @@ -563,7 +523,7 @@ int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info, break; } - printk(KERN_DEBUG "best: fs=%u, div=%u, rate=%u\n", + printk(KERN_DEBUG "best: fs=%d, div=%d, rate=%d\n", best_fs, best_div, best_rate); info->fs_div = best_fs; @@ -579,31 +539,12 @@ int s3c_i2sv2_probe(struct platform_device *pdev, unsigned long base) { struct device *dev = &pdev->dev; - unsigned int iismod; i2s->dev = dev; /* record our i2s structure for later use in the callbacks */ dai->private_data = i2s; - if (!base) { - struct resource *res = platform_get_resource(pdev, - IORESOURCE_MEM, - 0); - if (!res) { - dev_err(dev, "Unable to get register resource\n"); - return -ENXIO; - } - - if (!request_mem_region(res->start, resource_size(res), - "s3c64xx-i2s-v4")) { - dev_err(dev, "Unable to request register region\n"); - return -EBUSY; - } - - base = res->start; - } - i2s->regs = ioremap(base, 0x100); if (i2s->regs == NULL) { dev_err(dev, "cannot ioremap registers\n"); @@ -619,16 +560,12 @@ int s3c_i2sv2_probe(struct platform_device *pdev, clk_enable(i2s->iis_pclk); - /* Mark ourselves as in TXRX mode so we can run through our cleanup - * process without warnings. */ - iismod = readl(i2s->regs + S3C2412_IISMOD); - iismod |= S3C2412_IISMOD_MODE_TXRX; - writel(iismod, i2s->regs + S3C2412_IISMOD); s3c2412_snd_txctrl(i2s, 0); s3c2412_snd_rxctrl(i2s, 0); return 0; } + EXPORT_SYMBOL_GPL(s3c_i2sv2_probe); #ifdef CONFIG_PM diff --git a/trunk/sound/soc/s3c24xx/s3c2412-i2s.c b/trunk/sound/soc/s3c24xx/s3c2412-i2s.c index 168a088ba761..b7e0b3f0bfc8 100644 --- a/trunk/sound/soc/s3c24xx/s3c2412-i2s.c +++ b/trunk/sound/soc/s3c24xx/s3c2412-i2s.c @@ -120,7 +120,7 @@ static int s3c2412_i2s_probe(struct platform_device *pdev, s3c2412_i2s.iis_cclk = clk_get(&pdev->dev, "i2sclk"); if (s3c2412_i2s.iis_cclk == NULL) { - pr_err("failed to get i2sclk clock\n"); + pr_debug("failed to get i2sclk clock\n"); iounmap(s3c2412_i2s.regs); return -ENODEV; } diff --git a/trunk/sound/soc/s3c24xx/s3c64xx-i2s.c b/trunk/sound/soc/s3c24xx/s3c64xx-i2s.c index 3c06c401d0fb..33c5de7e255f 100644 --- a/trunk/sound/soc/s3c24xx/s3c64xx-i2s.c +++ b/trunk/sound/soc/s3c24xx/s3c64xx-i2s.c @@ -108,19 +108,48 @@ static int s3c64xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, return 0; } -struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai) + +unsigned long s3c64xx_i2s_get_clockrate(struct snd_soc_dai *dai) { struct s3c_i2sv2_info *i2s = to_info(dai); - return i2s->iis_cclk; + return clk_get_rate(i2s->iis_cclk); } -EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clock); +EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clockrate); static int s3c64xx_i2s_probe(struct platform_device *pdev, struct snd_soc_dai *dai) { + struct device *dev = &pdev->dev; + struct s3c_i2sv2_info *i2s; + int ret; + + dev_dbg(dev, "%s: probing dai %d\n", __func__, pdev->id); + + if (pdev->id < 0 || pdev->id > ARRAY_SIZE(s3c64xx_i2s)) { + dev_err(dev, "id %d out of range\n", pdev->id); + return -EINVAL; + } + + i2s = &s3c64xx_i2s[pdev->id]; + + ret = s3c_i2sv2_probe(pdev, dai, i2s, + pdev->id ? S3C64XX_PA_IIS1 : S3C64XX_PA_IIS0); + if (ret) + return ret; + + i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id]; + i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id]; + + i2s->iis_cclk = clk_get(dev, "audio-bus"); + if (IS_ERR(i2s->iis_cclk)) { + dev_err(dev, "failed to get audio-bus"); + iounmap(i2s->regs); + return -ENODEV; + } + /* configure GPIO for i2s port */ - switch (dai->id) { + switch (pdev->id) { case 0: s3c_gpio_cfgpin(S3C64XX_GPD(0), S3C64XX_GPD0_I2S0_CLK); s3c_gpio_cfgpin(S3C64XX_GPD(1), S3C64XX_GPD1_I2S0_CDCLK); @@ -146,122 +175,41 @@ static int s3c64xx_i2s_probe(struct platform_device *pdev, SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) #define S3C64XX_I2S_FMTS \ - (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ - SNDRV_PCM_FMTBIT_S24_LE) + (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE) static struct snd_soc_dai_ops s3c64xx_i2s_dai_ops = { .set_sysclk = s3c64xx_i2s_set_sysclk, }; -struct snd_soc_dai s3c64xx_i2s_dai[] = { - { - .name = "s3c64xx-i2s", - .id = 0, - .probe = s3c64xx_i2s_probe, - .playback = { - .channels_min = 2, - .channels_max = 2, - .rates = S3C64XX_I2S_RATES, - .formats = S3C64XX_I2S_FMTS, - }, - .capture = { - .channels_min = 2, - .channels_max = 2, - .rates = S3C64XX_I2S_RATES, - .formats = S3C64XX_I2S_FMTS, - }, - .ops = &s3c64xx_i2s_dai_ops, - .symmetric_rates = 1, +struct snd_soc_dai s3c64xx_i2s_dai = { + .name = "s3c64xx-i2s", + .id = 0, + .probe = s3c64xx_i2s_probe, + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = S3C64XX_I2S_RATES, + .formats = S3C64XX_I2S_FMTS, }, - { - .name = "s3c64xx-i2s", - .id = 1, - .probe = s3c64xx_i2s_probe, - .playback = { - .channels_min = 2, - .channels_max = 2, - .rates = S3C64XX_I2S_RATES, - .formats = S3C64XX_I2S_FMTS, - }, - .capture = { - .channels_min = 2, - .channels_max = 2, - .rates = S3C64XX_I2S_RATES, - .formats = S3C64XX_I2S_FMTS, - }, - .ops = &s3c64xx_i2s_dai_ops, - .symmetric_rates = 1, + .capture = { + .channels_min = 2, + .channels_max = 2, + .rates = S3C64XX_I2S_RATES, + .formats = S3C64XX_I2S_FMTS, }, + .ops = &s3c64xx_i2s_dai_ops, }; EXPORT_SYMBOL_GPL(s3c64xx_i2s_dai); -static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev) -{ - struct s3c_i2sv2_info *i2s; - struct snd_soc_dai *dai; - int ret; - - if (pdev->id >= ARRAY_SIZE(s3c64xx_i2s)) { - dev_err(&pdev->dev, "id %d out of range\n", pdev->id); - return -EINVAL; - } - - i2s = &s3c64xx_i2s[pdev->id]; - dai = &s3c64xx_i2s_dai[pdev->id]; - dai->dev = &pdev->dev; - - i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id]; - i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id]; - - i2s->iis_cclk = clk_get(&pdev->dev, "audio-bus"); - if (IS_ERR(i2s->iis_cclk)) { - dev_err(&pdev->dev, "failed to get audio-bus\n"); - ret = PTR_ERR(i2s->iis_cclk); - goto err; - } - - ret = s3c_i2sv2_probe(pdev, dai, i2s, 0); - if (ret) - goto err_clk; - - ret = s3c_i2sv2_register_dai(dai); - if (ret != 0) - goto err_i2sv2; - - return 0; - -err_i2sv2: - /* Not implemented for I2Sv2 core yet */ -err_clk: - clk_put(i2s->iis_cclk); -err: - return ret; -} - -static __devexit int s3c64xx_iis_dev_remove(struct platform_device *pdev) -{ - dev_err(&pdev->dev, "Device removal not yet supported\n"); - return 0; -} - -static struct platform_driver s3c64xx_iis_driver = { - .probe = s3c64xx_iis_dev_probe, - .remove = s3c64xx_iis_dev_remove, - .driver = { - .name = "s3c64xx-iis", - .owner = THIS_MODULE, - }, -}; - static int __init s3c64xx_i2s_init(void) { - return platform_driver_register(&s3c64xx_iis_driver); + return s3c_i2sv2_register_dai(&s3c64xx_i2s_dai); } module_init(s3c64xx_i2s_init); static void __exit s3c64xx_i2s_exit(void) { - platform_driver_unregister(&s3c64xx_iis_driver); + snd_soc_unregister_dai(&s3c64xx_i2s_dai); } module_exit(s3c64xx_i2s_exit); @@ -269,3 +217,6 @@ module_exit(s3c64xx_i2s_exit); MODULE_AUTHOR("Ben Dooks, "); MODULE_DESCRIPTION("S3C64XX I2S SoC Interface"); MODULE_LICENSE("GPL"); + + + diff --git a/trunk/sound/soc/s3c24xx/s3c64xx-i2s.h b/trunk/sound/soc/s3c24xx/s3c64xx-i2s.h index 02148cee2613..b7ffe3c38b66 100644 --- a/trunk/sound/soc/s3c24xx/s3c64xx-i2s.h +++ b/trunk/sound/soc/s3c24xx/s3c64xx-i2s.h @@ -15,8 +15,6 @@ #ifndef __SND_SOC_S3C24XX_S3C64XX_I2S_H #define __SND_SOC_S3C24XX_S3C64XX_I2S_H __FILE__ -struct clk; - #include "s3c-i2s-v2.h" #define S3C64XX_DIV_BCLK S3C_I2SV2_DIV_BCLK @@ -26,8 +24,8 @@ struct clk; #define S3C64XX_CLKSRC_PCLK (0) #define S3C64XX_CLKSRC_MUX (1) -extern struct snd_soc_dai s3c64xx_i2s_dai[]; +extern struct snd_soc_dai s3c64xx_i2s_dai; -extern struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai); +extern unsigned long s3c64xx_i2s_get_clockrate(struct snd_soc_dai *cpu_dai); #endif /* __SND_SOC_S3C24XX_S3C64XX_I2S_H */ diff --git a/trunk/sound/soc/s6000/Kconfig b/trunk/sound/soc/s6000/Kconfig deleted file mode 100644 index c74eb3d4a47c..000000000000 --- a/trunk/sound/soc/s6000/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -config SND_S6000_SOC - tristate "SoC Audio for the Stretch s6000 family" - depends on XTENSA_VARIANT_S6000 - help - Say Y or M if you want to add support for codecs attached to - s6000 family chips. You will also need to select the platform - to support below. - -config SND_S6000_SOC_I2S - tristate - -config SND_S6000_SOC_S6IPCAM - tristate "SoC Audio support for Stretch 6105 IP Camera" - depends on SND_S6000_SOC && XTENSA_PLATFORM_S6105 - select SND_S6000_SOC_I2S - select SND_SOC_TLV320AIC3X - help - Say Y if you want to add support for SoC audio on the - Stretch s6105 IP Camera Reference Design. diff --git a/trunk/sound/soc/s6000/Makefile b/trunk/sound/soc/s6000/Makefile deleted file mode 100644 index 7a613612e010..000000000000 --- a/trunk/sound/soc/s6000/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# s6000 Platform Support -snd-soc-s6000-objs := s6000-pcm.o -snd-soc-s6000-i2s-objs := s6000-i2s.o - -obj-$(CONFIG_SND_S6000_SOC) += snd-soc-s6000.o -obj-$(CONFIG_SND_S6000_SOC_I2S) += snd-soc-s6000-i2s.o - -# s6105 Machine Support -snd-soc-s6ipcam-objs := s6105-ipcam.o - -obj-$(CONFIG_SND_S6000_SOC_S6IPCAM) += snd-soc-s6ipcam.o diff --git a/trunk/sound/soc/s6000/s6000-i2s.c b/trunk/sound/soc/s6000/s6000-i2s.c deleted file mode 100644 index c5cda187ecab..000000000000 --- a/trunk/sound/soc/s6000/s6000-i2s.c +++ /dev/null @@ -1,629 +0,0 @@ -/* - * ALSA SoC I2S Audio Layer for the Stretch S6000 family - * - * Author: Daniel Gloeckner, - * Copyright: (C) 2009 emlix GmbH - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "s6000-i2s.h" -#include "s6000-pcm.h" - -struct s6000_i2s_dev { - dma_addr_t sifbase; - u8 __iomem *scbbase; - unsigned int wide; - unsigned int channel_in; - unsigned int channel_out; - unsigned int lines_in; - unsigned int lines_out; - struct s6000_pcm_dma_params dma_params; -}; - -#define S6_I2S_INTERRUPT_STATUS 0x00 -#define S6_I2S_INT_OVERRUN 1 -#define S6_I2S_INT_UNDERRUN 2 -#define S6_I2S_INT_ALIGNMENT 4 -#define S6_I2S_INTERRUPT_ENABLE 0x04 -#define S6_I2S_INTERRUPT_RAW 0x08 -#define S6_I2S_INTERRUPT_CLEAR 0x0C -#define S6_I2S_INTERRUPT_SET 0x10 -#define S6_I2S_MODE 0x20 -#define S6_I2S_DUAL 0 -#define S6_I2S_WIDE 1 -#define S6_I2S_TX_DEFAULT 0x24 -#define S6_I2S_DATA_CFG(c) (0x40 + 0x10 * (c)) -#define S6_I2S_IN 0 -#define S6_I2S_OUT 1 -#define S6_I2S_UNUSED 2 -#define S6_I2S_INTERFACE_CFG(c) (0x44 + 0x10 * (c)) -#define S6_I2S_DIV_MASK 0x001fff -#define S6_I2S_16BIT 0x000000 -#define S6_I2S_20BIT 0x002000 -#define S6_I2S_24BIT 0x004000 -#define S6_I2S_32BIT 0x006000 -#define S6_I2S_BITS_MASK 0x006000 -#define S6_I2S_MEM_16BIT 0x000000 -#define S6_I2S_MEM_32BIT 0x008000 -#define S6_I2S_MEM_MASK 0x008000 -#define S6_I2S_CHANNELS_SHIFT 16 -#define S6_I2S_CHANNELS_MASK 0x030000 -#define S6_I2S_SCK_IN 0x000000 -#define S6_I2S_SCK_OUT 0x040000 -#define S6_I2S_SCK_DIR 0x040000 -#define S6_I2S_WS_IN 0x000000 -#define S6_I2S_WS_OUT 0x080000 -#define S6_I2S_WS_DIR 0x080000 -#define S6_I2S_LEFT_FIRST 0x000000 -#define S6_I2S_RIGHT_FIRST 0x100000 -#define S6_I2S_FIRST 0x100000 -#define S6_I2S_CUR_SCK 0x200000 -#define S6_I2S_CUR_WS 0x400000 -#define S6_I2S_ENABLE(c) (0x48 + 0x10 * (c)) -#define S6_I2S_DISABLE_IF 0x02 -#define S6_I2S_ENABLE_IF 0x03 -#define S6_I2S_IS_BUSY 0x04 -#define S6_I2S_DMA_ACTIVE 0x08 -#define S6_I2S_IS_ENABLED 0x10 - -#define S6_I2S_NUM_LINES 4 - -#define S6_I2S_SIF_PORT0 0x0000000 -#define S6_I2S_SIF_PORT1 0x0000080 /* docs say 0x0000010 */ - -static inline void s6_i2s_write_reg(struct s6000_i2s_dev *dev, int reg, u32 val) -{ - writel(val, dev->scbbase + reg); -} - -static inline u32 s6_i2s_read_reg(struct s6000_i2s_dev *dev, int reg) -{ - return readl(dev->scbbase + reg); -} - -static inline void s6_i2s_mod_reg(struct s6000_i2s_dev *dev, int reg, - u32 mask, u32 val) -{ - val ^= s6_i2s_read_reg(dev, reg) & ~mask; - s6_i2s_write_reg(dev, reg, val); -} - -static void s6000_i2s_start_channel(struct s6000_i2s_dev *dev, int channel) -{ - int i, j, cur, prev; - - /* - * Wait for WCLK to toggle 5 times before enabling the channel - * s6000 Family Datasheet 3.6.4: - * "At least two cycles of WS must occur between commands - * to disable or enable the interface" - */ - j = 0; - prev = ~S6_I2S_CUR_WS; - for (i = 1000000; --i && j < 6; ) { - cur = s6_i2s_read_reg(dev, S6_I2S_INTERFACE_CFG(channel)) - & S6_I2S_CUR_WS; - if (prev != cur) { - prev = cur; - j++; - } - } - if (j < 6) - printk(KERN_WARNING "s6000-i2s: timeout waiting for WCLK\n"); - - s6_i2s_write_reg(dev, S6_I2S_ENABLE(channel), S6_I2S_ENABLE_IF); -} - -static void s6000_i2s_stop_channel(struct s6000_i2s_dev *dev, int channel) -{ - s6_i2s_write_reg(dev, S6_I2S_ENABLE(channel), S6_I2S_DISABLE_IF); -} - -static void s6000_i2s_start(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct s6000_i2s_dev *dev = rtd->dai->cpu_dai->private_data; - int channel; - - channel = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? - dev->channel_out : dev->channel_in; - - s6000_i2s_start_channel(dev, channel); -} - -static void s6000_i2s_stop(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct s6000_i2s_dev *dev = rtd->dai->cpu_dai->private_data; - int channel; - - channel = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? - dev->channel_out : dev->channel_in; - - s6000_i2s_stop_channel(dev, channel); -} - -static int s6000_i2s_trigger(struct snd_pcm_substream *substream, int cmd, - int after) -{ - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) ^ !after) - s6000_i2s_start(substream); - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - if (!after) - s6000_i2s_stop(substream); - } - return 0; -} - -static unsigned int s6000_i2s_int_sources(struct s6000_i2s_dev *dev) -{ - unsigned int pending; - pending = s6_i2s_read_reg(dev, S6_I2S_INTERRUPT_RAW); - pending &= S6_I2S_INT_ALIGNMENT | - S6_I2S_INT_UNDERRUN | - S6_I2S_INT_OVERRUN; - s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_CLEAR, pending); - - return pending; -} - -static unsigned int s6000_i2s_check_xrun(struct snd_soc_dai *cpu_dai) -{ - struct s6000_i2s_dev *dev = cpu_dai->private_data; - unsigned int errors; - unsigned int ret; - - errors = s6000_i2s_int_sources(dev); - if (likely(!errors)) - return 0; - - ret = 0; - if (errors & S6_I2S_INT_ALIGNMENT) - printk(KERN_ERR "s6000-i2s: WCLK misaligned\n"); - if (errors & S6_I2S_INT_UNDERRUN) - ret |= 1 << SNDRV_PCM_STREAM_PLAYBACK; - if (errors & S6_I2S_INT_OVERRUN) - ret |= 1 << SNDRV_PCM_STREAM_CAPTURE; - return ret; -} - -static void s6000_i2s_wait_disabled(struct s6000_i2s_dev *dev) -{ - int channel; - int n = 50; - for (channel = 0; channel < 2; channel++) { - while (--n >= 0) { - int v = s6_i2s_read_reg(dev, S6_I2S_ENABLE(channel)); - if ((v & S6_I2S_IS_ENABLED) - || !(v & (S6_I2S_DMA_ACTIVE | S6_I2S_IS_BUSY))) - break; - udelay(20); - } - } - if (n < 0) - printk(KERN_WARNING "s6000-i2s: timeout disabling interfaces"); -} - -static int s6000_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, - unsigned int fmt) -{ - struct s6000_i2s_dev *dev = cpu_dai->private_data; - u32 w; - - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - w = S6_I2S_SCK_IN | S6_I2S_WS_IN; - break; - case SND_SOC_DAIFMT_CBS_CFM: - w = S6_I2S_SCK_OUT | S6_I2S_WS_IN; - break; - case SND_SOC_DAIFMT_CBM_CFS: - w = S6_I2S_SCK_IN | S6_I2S_WS_OUT; - break; - case SND_SOC_DAIFMT_CBS_CFS: - w = S6_I2S_SCK_OUT | S6_I2S_WS_OUT; - break; - default: - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - w |= S6_I2S_LEFT_FIRST; - break; - case SND_SOC_DAIFMT_NB_IF: - w |= S6_I2S_RIGHT_FIRST; - break; - default: - return -EINVAL; - } - - s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(0), - S6_I2S_FIRST | S6_I2S_WS_DIR | S6_I2S_SCK_DIR, w); - s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(1), - S6_I2S_FIRST | S6_I2S_WS_DIR | S6_I2S_SCK_DIR, w); - - return 0; -} - -static int s6000_i2s_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) -{ - struct s6000_i2s_dev *dev = dai->private_data; - - if (!div || (div & 1) || div > (S6_I2S_DIV_MASK + 1) * 2) - return -EINVAL; - - s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(div_id), - S6_I2S_DIV_MASK, div / 2 - 1); - return 0; -} - -static int s6000_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct s6000_i2s_dev *dev = dai->private_data; - int interf; - u32 w = 0; - - if (dev->wide) - interf = 0; - else { - w |= (((params_channels(params) - 2) / 2) - << S6_I2S_CHANNELS_SHIFT) & S6_I2S_CHANNELS_MASK; - interf = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - ? dev->channel_out : dev->channel_in; - } - - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - w |= S6_I2S_16BIT | S6_I2S_MEM_16BIT; - break; - case SNDRV_PCM_FORMAT_S32_LE: - w |= S6_I2S_32BIT | S6_I2S_MEM_32BIT; - break; - default: - printk(KERN_WARNING "s6000-i2s: unsupported PCM format %x\n", - params_format(params)); - return -EINVAL; - } - - if (s6_i2s_read_reg(dev, S6_I2S_INTERFACE_CFG(interf)) - & S6_I2S_IS_ENABLED) { - printk(KERN_ERR "s6000-i2s: interface already enabled\n"); - return -EBUSY; - } - - s6_i2s_mod_reg(dev, S6_I2S_INTERFACE_CFG(interf), - S6_I2S_CHANNELS_MASK|S6_I2S_MEM_MASK|S6_I2S_BITS_MASK, - w); - - return 0; -} - -static int s6000_i2s_dai_probe(struct platform_device *pdev, - struct snd_soc_dai *dai) -{ - struct s6000_i2s_dev *dev = dai->private_data; - struct s6000_snd_platform_data *pdata = pdev->dev.platform_data; - - if (!pdata) - return -EINVAL; - - dev->wide = pdata->wide; - dev->channel_in = pdata->channel_in; - dev->channel_out = pdata->channel_out; - dev->lines_in = pdata->lines_in; - dev->lines_out = pdata->lines_out; - - s6_i2s_write_reg(dev, S6_I2S_MODE, - dev->wide ? S6_I2S_WIDE : S6_I2S_DUAL); - - if (dev->wide) { - int i; - - if (dev->lines_in + dev->lines_out > S6_I2S_NUM_LINES) - return -EINVAL; - - dev->channel_in = 0; - dev->channel_out = 1; - dai->capture.channels_min = 2 * dev->lines_in; - dai->capture.channels_max = dai->capture.channels_min; - dai->playback.channels_min = 2 * dev->lines_out; - dai->playback.channels_max = dai->playback.channels_min; - - for (i = 0; i < dev->lines_out; i++) - s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i), S6_I2S_OUT); - - for (; i < S6_I2S_NUM_LINES - dev->lines_in; i++) - s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i), - S6_I2S_UNUSED); - - for (; i < S6_I2S_NUM_LINES; i++) - s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i), S6_I2S_IN); - } else { - unsigned int cfg[2] = {S6_I2S_UNUSED, S6_I2S_UNUSED}; - - if (dev->lines_in > 1 || dev->lines_out > 1) - return -EINVAL; - - dai->capture.channels_min = 2 * dev->lines_in; - dai->capture.channels_max = 8 * dev->lines_in; - dai->playback.channels_min = 2 * dev->lines_out; - dai->playback.channels_max = 8 * dev->lines_out; - - if (dev->lines_in) - cfg[dev->channel_in] = S6_I2S_IN; - if (dev->lines_out) - cfg[dev->channel_out] = S6_I2S_OUT; - - s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(0), cfg[0]); - s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(1), cfg[1]); - } - - if (dev->lines_out) { - if (dev->lines_in) { - if (!dev->dma_params.dma_out) - return -ENODEV; - } else { - dev->dma_params.dma_out = dev->dma_params.dma_in; - dev->dma_params.dma_in = 0; - } - } - dev->dma_params.sif_in = dev->sifbase + (dev->channel_in ? - S6_I2S_SIF_PORT1 : S6_I2S_SIF_PORT0); - dev->dma_params.sif_out = dev->sifbase + (dev->channel_out ? - S6_I2S_SIF_PORT1 : S6_I2S_SIF_PORT0); - dev->dma_params.same_rate = pdata->same_rate | pdata->wide; - return 0; -} - -#define S6000_I2S_RATES (SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_5512 | \ - SNDRV_PCM_RATE_8000_192000) -#define S6000_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE) - -static struct snd_soc_dai_ops s6000_i2s_dai_ops = { - .set_fmt = s6000_i2s_set_dai_fmt, - .set_clkdiv = s6000_i2s_set_clkdiv, - .hw_params = s6000_i2s_hw_params, -}; - -struct snd_soc_dai s6000_i2s_dai = { - .name = "s6000-i2s", - .id = 0, - .probe = s6000_i2s_dai_probe, - .playback = { - .channels_min = 2, - .channels_max = 8, - .formats = S6000_I2S_FORMATS, - .rates = S6000_I2S_RATES, - .rate_min = 0, - .rate_max = 1562500, - }, - .capture = { - .channels_min = 2, - .channels_max = 8, - .formats = S6000_I2S_FORMATS, - .rates = S6000_I2S_RATES, - .rate_min = 0, - .rate_max = 1562500, - }, - .ops = &s6000_i2s_dai_ops, -} -EXPORT_SYMBOL_GPL(s6000_i2s_dai); - -static int __devinit s6000_i2s_probe(struct platform_device *pdev) -{ - struct s6000_i2s_dev *dev; - struct resource *scbmem, *sifmem, *region, *dma1, *dma2; - u8 __iomem *mmio; - int ret; - - scbmem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!scbmem) { - dev_err(&pdev->dev, "no mem resource?\n"); - ret = -ENODEV; - goto err_release_none; - } - - region = request_mem_region(scbmem->start, - scbmem->end - scbmem->start + 1, - pdev->name); - if (!region) { - dev_err(&pdev->dev, "I2S SCB region already claimed\n"); - ret = -EBUSY; - goto err_release_none; - } - - mmio = ioremap(scbmem->start, scbmem->end - scbmem->start + 1); - if (!mmio) { - dev_err(&pdev->dev, "can't ioremap SCB region\n"); - ret = -ENOMEM; - goto err_release_scb; - } - - sifmem = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!sifmem) { - dev_err(&pdev->dev, "no second mem resource?\n"); - ret = -ENODEV; - goto err_release_map; - } - - region = request_mem_region(sifmem->start, - sifmem->end - sifmem->start + 1, - pdev->name); - if (!region) { - dev_err(&pdev->dev, "I2S SIF region already claimed\n"); - ret = -EBUSY; - goto err_release_map; - } - - dma1 = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!dma1) { - dev_err(&pdev->dev, "no dma resource?\n"); - ret = -ENODEV; - goto err_release_sif; - } - - region = request_mem_region(dma1->start, dma1->end - dma1->start + 1, - pdev->name); - if (!region) { - dev_err(&pdev->dev, "I2S DMA region already claimed\n"); - ret = -EBUSY; - goto err_release_sif; - } - - dma2 = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (dma2) { - region = request_mem_region(dma2->start, - dma2->end - dma2->start + 1, - pdev->name); - if (!region) { - dev_err(&pdev->dev, - "I2S DMA region already claimed\n"); - ret = -EBUSY; - goto err_release_dma1; - } - } - - dev = kzalloc(sizeof(struct s6000_i2s_dev), GFP_KERNEL); - if (!dev) { - ret = -ENOMEM; - goto err_release_dma2; - } - - s6000_i2s_dai.dev = &pdev->dev; - s6000_i2s_dai.private_data = dev; - s6000_i2s_dai.dma_data = &dev->dma_params; - - dev->sifbase = sifmem->start; - dev->scbbase = mmio; - - s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE, 0); - s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_CLEAR, - S6_I2S_INT_ALIGNMENT | - S6_I2S_INT_UNDERRUN | - S6_I2S_INT_OVERRUN); - - s6000_i2s_stop_channel(dev, 0); - s6000_i2s_stop_channel(dev, 1); - s6000_i2s_wait_disabled(dev); - - dev->dma_params.check_xrun = s6000_i2s_check_xrun; - dev->dma_params.trigger = s6000_i2s_trigger; - dev->dma_params.dma_in = dma1->start; - dev->dma_params.dma_out = dma2 ? dma2->start : 0; - dev->dma_params.irq = platform_get_irq(pdev, 0); - if (dev->dma_params.irq < 0) { - dev_err(&pdev->dev, "no irq resource?\n"); - ret = -ENODEV; - goto err_release_dev; - } - - s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE, - S6_I2S_INT_ALIGNMENT | - S6_I2S_INT_UNDERRUN | - S6_I2S_INT_OVERRUN); - - ret = snd_soc_register_dai(&s6000_i2s_dai); - if (ret) - goto err_release_dev; - - return 0; - -err_release_dev: - kfree(dev); -err_release_dma2: - if (dma2) - release_mem_region(dma2->start, dma2->end - dma2->start + 1); -err_release_dma1: - release_mem_region(dma1->start, dma1->end - dma1->start + 1); -err_release_sif: - release_mem_region(sifmem->start, (sifmem->end - sifmem->start) + 1); -err_release_map: - iounmap(mmio); -err_release_scb: - release_mem_region(scbmem->start, (scbmem->end - scbmem->start) + 1); -err_release_none: - return ret; -} - -static void __devexit s6000_i2s_remove(struct platform_device *pdev) -{ - struct s6000_i2s_dev *dev = s6000_i2s_dai.private_data; - struct resource *region; - void __iomem *mmio = dev->scbbase; - - snd_soc_unregister_dai(&s6000_i2s_dai); - - s6000_i2s_stop_channel(dev, 0); - s6000_i2s_stop_channel(dev, 1); - - s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE, 0); - s6000_i2s_dai.private_data = 0; - kfree(dev); - - region = platform_get_resource(pdev, IORESOURCE_DMA, 0); - release_mem_region(region->start, region->end - region->start + 1); - - region = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (region) - release_mem_region(region->start, - region->end - region->start + 1); - - region = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(region->start, (region->end - region->start) + 1); - - iounmap(mmio); - region = platform_get_resource(pdev, IORESOURCE_IO, 0); - release_mem_region(region->start, (region->end - region->start) + 1); -} - -static struct platform_driver s6000_i2s_driver = { - .probe = s6000_i2s_probe, - .remove = __devexit_p(s6000_i2s_remove), - .driver = { - .name = "s6000-i2s", - .owner = THIS_MODULE, - }, -}; - -static int __init s6000_i2s_init(void) -{ - return platform_driver_register(&s6000_i2s_driver); -} -module_init(s6000_i2s_init); - -static void __exit s6000_i2s_exit(void) -{ - platform_driver_unregister(&s6000_i2s_driver); -} -module_exit(s6000_i2s_exit); - -MODULE_AUTHOR("Daniel Gloeckner"); -MODULE_DESCRIPTION("Stretch s6000 family I2S SoC Interface"); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/s6000/s6000-i2s.h b/trunk/sound/soc/s6000/s6000-i2s.h deleted file mode 100644 index 2375fdfe6dba..000000000000 --- a/trunk/sound/soc/s6000/s6000-i2s.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * ALSA SoC I2S Audio Layer for the Stretch s6000 family - * - * Author: Daniel Gloeckner, - * Copyright: (C) 2009 emlix GmbH - * - * 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. - */ - -#ifndef _S6000_I2S_H -#define _S6000_I2S_H - -extern struct snd_soc_dai s6000_i2s_dai; - -struct s6000_snd_platform_data { - int lines_in; - int lines_out; - int channel_in; - int channel_out; - int wide; - int same_rate; -}; -#endif diff --git a/trunk/sound/soc/s6000/s6000-pcm.c b/trunk/sound/soc/s6000/s6000-pcm.c deleted file mode 100644 index 83b8028e209d..000000000000 --- a/trunk/sound/soc/s6000/s6000-pcm.c +++ /dev/null @@ -1,497 +0,0 @@ -/* - * ALSA PCM interface for the Stetch s6000 family - * - * Author: Daniel Gloeckner, - * Copyright: (C) 2009 emlix GmbH - * - * 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. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include "s6000-pcm.h" - -#define S6_PCM_PREALLOCATE_SIZE (96 * 1024) -#define S6_PCM_PREALLOCATE_MAX (2048 * 1024) - -static struct snd_pcm_hardware s6000_pcm_hardware = { - .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_JOINT_DUPLEX), - .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE), - .rates = (SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_5512 | \ - SNDRV_PCM_RATE_8000_192000), - .rate_min = 0, - .rate_max = 1562500, - .channels_min = 2, - .channels_max = 8, - .buffer_bytes_max = 0x7ffffff0, - .period_bytes_min = 16, - .period_bytes_max = 0xfffff0, - .periods_min = 2, - .periods_max = 1024, /* no limit */ - .fifo_size = 0, -}; - -struct s6000_runtime_data { - spinlock_t lock; - int period; /* current DMA period */ -}; - -static void s6000_pcm_enqueue_dma(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct s6000_runtime_data *prtd = runtime->private_data; - struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; - int channel; - unsigned int period_size; - unsigned int dma_offset; - dma_addr_t dma_pos; - dma_addr_t src, dst; - - period_size = snd_pcm_lib_period_bytes(substream); - dma_offset = prtd->period * period_size; - dma_pos = runtime->dma_addr + dma_offset; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - src = dma_pos; - dst = par->sif_out; - channel = par->dma_out; - } else { - src = par->sif_in; - dst = dma_pos; - channel = par->dma_in; - } - - if (!s6dmac_channel_enabled(DMA_MASK_DMAC(channel), - DMA_INDEX_CHNL(channel))) - return; - - if (s6dmac_fifo_full(DMA_MASK_DMAC(channel), DMA_INDEX_CHNL(channel))) { - printk(KERN_ERR "s6000-pcm: fifo full\n"); - return; - } - - BUG_ON(period_size & 15); - s6dmac_put_fifo(DMA_MASK_DMAC(channel), DMA_INDEX_CHNL(channel), - src, dst, period_size); - - prtd->period++; - if (unlikely(prtd->period >= runtime->periods)) - prtd->period = 0; -} - -static irqreturn_t s6000_pcm_irq(int irq, void *data) -{ - struct snd_pcm *pcm = data; - struct snd_soc_pcm_runtime *runtime = pcm->private_data; - struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data; - struct s6000_runtime_data *prtd; - unsigned int has_xrun; - int i, ret = IRQ_NONE; - u32 channel[2] = { - [SNDRV_PCM_STREAM_PLAYBACK] = params->dma_out, - [SNDRV_PCM_STREAM_CAPTURE] = params->dma_in - }; - - has_xrun = params->check_xrun(runtime->dai->cpu_dai); - - for (i = 0; i < ARRAY_SIZE(channel); ++i) { - struct snd_pcm_substream *substream = pcm->streams[i].substream; - unsigned int pending; - - if (!channel[i]) - continue; - - if (unlikely(has_xrun & (1 << i)) && - substream->runtime && - snd_pcm_running(substream)) { - dev_dbg(pcm->dev, "xrun\n"); - snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); - ret = IRQ_HANDLED; - } - - pending = s6dmac_int_sources(DMA_MASK_DMAC(channel[i]), - DMA_INDEX_CHNL(channel[i])); - - if (pending & 1) { - ret = IRQ_HANDLED; - if (likely(substream->runtime && - snd_pcm_running(substream))) { - snd_pcm_period_elapsed(substream); - dev_dbg(pcm->dev, "period elapsed %x %x\n", - s6dmac_cur_src(DMA_MASK_DMAC(channel[i]), - DMA_INDEX_CHNL(channel[i])), - s6dmac_cur_dst(DMA_MASK_DMAC(channel[i]), - DMA_INDEX_CHNL(channel[i]))); - prtd = substream->runtime->private_data; - spin_lock(&prtd->lock); - s6000_pcm_enqueue_dma(substream); - spin_unlock(&prtd->lock); - } - } - - if (unlikely(pending & ~7)) { - if (pending & (1 << 3)) - printk(KERN_WARNING - "s6000-pcm: DMA %x Underflow\n", - channel[i]); - if (pending & (1 << 4)) - printk(KERN_WARNING - "s6000-pcm: DMA %x Overflow\n", - channel[i]); - if (pending & 0x1e0) - printk(KERN_WARNING - "s6000-pcm: DMA %x Master Error " - "(mask %x)\n", - channel[i], pending >> 5); - - } - } - - return ret; -} - -static int s6000_pcm_start(struct snd_pcm_substream *substream) -{ - struct s6000_runtime_data *prtd = substream->runtime->private_data; - struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; - unsigned long flags; - int srcinc; - u32 dma; - - spin_lock_irqsave(&prtd->lock, flags); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - srcinc = 1; - dma = par->dma_out; - } else { - srcinc = 0; - dma = par->dma_in; - } - s6dmac_enable_chan(DMA_MASK_DMAC(dma), DMA_INDEX_CHNL(dma), - 1 /* priority 1 (0 is max) */, - 0 /* peripheral requests w/o xfer length mode */, - srcinc /* source address increment */, - srcinc^1 /* destination address increment */, - 0 /* chunksize 0 (skip impossible on this dma) */, - 0 /* source skip after chunk (impossible) */, - 0 /* destination skip after chunk (impossible) */, - 4 /* 16 byte burst size */, - -1 /* don't conserve bandwidth */, - 0 /* low watermark irq descriptor theshold */, - 0 /* disable hardware timestamps */, - 1 /* enable channel */); - - s6000_pcm_enqueue_dma(substream); - s6000_pcm_enqueue_dma(substream); - - spin_unlock_irqrestore(&prtd->lock, flags); - - return 0; -} - -static int s6000_pcm_stop(struct snd_pcm_substream *substream) -{ - struct s6000_runtime_data *prtd = substream->runtime->private_data; - struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; - unsigned long flags; - u32 channel; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - channel = par->dma_out; - else - channel = par->dma_in; - - s6dmac_set_terminal_count(DMA_MASK_DMAC(channel), - DMA_INDEX_CHNL(channel), 0); - - spin_lock_irqsave(&prtd->lock, flags); - - s6dmac_disable_chan(DMA_MASK_DMAC(channel), DMA_INDEX_CHNL(channel)); - - spin_unlock_irqrestore(&prtd->lock, flags); - - return 0; -} - -static int s6000_pcm_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; - int ret; - - ret = par->trigger(substream, cmd, 0); - if (ret < 0) - return ret; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ret = s6000_pcm_start(substream); - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ret = s6000_pcm_stop(substream); - break; - default: - ret = -EINVAL; - } - if (ret < 0) - return ret; - - return par->trigger(substream, cmd, 1); -} - -static int s6000_pcm_prepare(struct snd_pcm_substream *substream) -{ - struct s6000_runtime_data *prtd = substream->runtime->private_data; - - prtd->period = 0; - - return 0; -} - -static snd_pcm_uframes_t s6000_pcm_pointer(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; - struct snd_pcm_runtime *runtime = substream->runtime; - struct s6000_runtime_data *prtd = runtime->private_data; - unsigned long flags; - unsigned int offset; - dma_addr_t count; - - spin_lock_irqsave(&prtd->lock, flags); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - count = s6dmac_cur_src(DMA_MASK_DMAC(par->dma_out), - DMA_INDEX_CHNL(par->dma_out)); - else - count = s6dmac_cur_dst(DMA_MASK_DMAC(par->dma_in), - DMA_INDEX_CHNL(par->dma_in)); - - count -= runtime->dma_addr; - - spin_unlock_irqrestore(&prtd->lock, flags); - - offset = bytes_to_frames(runtime, count); - if (unlikely(offset >= runtime->buffer_size)) - offset = 0; - - return offset; -} - -static int s6000_pcm_open(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; - struct snd_pcm_runtime *runtime = substream->runtime; - struct s6000_runtime_data *prtd; - int ret; - - snd_soc_set_runtime_hwparams(substream, &s6000_pcm_hardware); - - ret = snd_pcm_hw_constraint_step(runtime, 0, - SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 16); - if (ret < 0) - return ret; - ret = snd_pcm_hw_constraint_step(runtime, 0, - SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16); - if (ret < 0) - return ret; - ret = snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - if (ret < 0) - return ret; - - if (par->same_rate) { - int rate; - spin_lock(&par->lock); /* needed? */ - rate = par->rate; - spin_unlock(&par->lock); - if (rate != -1) { - ret = snd_pcm_hw_constraint_minmax(runtime, - SNDRV_PCM_HW_PARAM_RATE, - rate, rate); - if (ret < 0) - return ret; - } - } - - prtd = kzalloc(sizeof(struct s6000_runtime_data), GFP_KERNEL); - if (prtd == NULL) - return -ENOMEM; - - spin_lock_init(&prtd->lock); - - runtime->private_data = prtd; - - return 0; -} - -static int s6000_pcm_close(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct s6000_runtime_data *prtd = runtime->private_data; - - kfree(prtd); - - return 0; -} - -static int s6000_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; - int ret; - ret = snd_pcm_lib_malloc_pages(substream, - params_buffer_bytes(hw_params)); - if (ret < 0) { - printk(KERN_WARNING "s6000-pcm: allocation of memory failed\n"); - return ret; - } - - if (par->same_rate) { - spin_lock(&par->lock); - if (par->rate == -1 || - !(par->in_use & ~(1 << substream->stream))) { - par->rate = params_rate(hw_params); - par->in_use |= 1 << substream->stream; - } else if (params_rate(hw_params) != par->rate) { - snd_pcm_lib_free_pages(substream); - par->in_use &= ~(1 << substream->stream); - ret = -EBUSY; - } - spin_unlock(&par->lock); - } - return ret; -} - -static int s6000_pcm_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; - struct s6000_pcm_dma_params *par = soc_runtime->dai->cpu_dai->dma_data; - - spin_lock(&par->lock); - par->in_use &= ~(1 << substream->stream); - if (!par->in_use) - par->rate = -1; - spin_unlock(&par->lock); - - return snd_pcm_lib_free_pages(substream); -} - -static struct snd_pcm_ops s6000_pcm_ops = { - .open = s6000_pcm_open, - .close = s6000_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = s6000_pcm_hw_params, - .hw_free = s6000_pcm_hw_free, - .trigger = s6000_pcm_trigger, - .prepare = s6000_pcm_prepare, - .pointer = s6000_pcm_pointer, -}; - -static void s6000_pcm_free(struct snd_pcm *pcm) -{ - struct snd_soc_pcm_runtime *runtime = pcm->private_data; - struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data; - - free_irq(params->irq, pcm); - snd_pcm_lib_preallocate_free_for_all(pcm); -} - -static u64 s6000_pcm_dmamask = DMA_32BIT_MASK; - -static int s6000_pcm_new(struct snd_card *card, - struct snd_soc_dai *dai, struct snd_pcm *pcm) -{ - struct snd_soc_pcm_runtime *runtime = pcm->private_data; - struct s6000_pcm_dma_params *params = runtime->dai->cpu_dai->dma_data; - int res; - - if (!card->dev->dma_mask) - card->dev->dma_mask = &s6000_pcm_dmamask; - if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = DMA_32BIT_MASK; - - if (params->dma_in) { - s6dmac_disable_chan(DMA_MASK_DMAC(params->dma_in), - DMA_INDEX_CHNL(params->dma_in)); - s6dmac_int_sources(DMA_MASK_DMAC(params->dma_in), - DMA_INDEX_CHNL(params->dma_in)); - } - - if (params->dma_out) { - s6dmac_disable_chan(DMA_MASK_DMAC(params->dma_out), - DMA_INDEX_CHNL(params->dma_out)); - s6dmac_int_sources(DMA_MASK_DMAC(params->dma_out), - DMA_INDEX_CHNL(params->dma_out)); - } - - res = request_irq(params->irq, s6000_pcm_irq, IRQF_SHARED, - s6000_soc_platform.name, pcm); - if (res) { - printk(KERN_ERR "s6000-pcm couldn't get IRQ\n"); - return res; - } - - res = snd_pcm_lib_preallocate_pages_for_all(pcm, - SNDRV_DMA_TYPE_DEV, - card->dev, - S6_PCM_PREALLOCATE_SIZE, - S6_PCM_PREALLOCATE_MAX); - if (res) - printk(KERN_WARNING "s6000-pcm: preallocation failed\n"); - - spin_lock_init(¶ms->lock); - params->in_use = 0; - params->rate = -1; - return 0; -} - -struct snd_soc_platform s6000_soc_platform = { - .name = "s6000-audio", - .pcm_ops = &s6000_pcm_ops, - .pcm_new = s6000_pcm_new, - .pcm_free = s6000_pcm_free, -}; -EXPORT_SYMBOL_GPL(s6000_soc_platform); - -static int __init s6000_pcm_init(void) -{ - return snd_soc_register_platform(&s6000_soc_platform); -} -module_init(s6000_pcm_init); - -static void __exit s6000_pcm_exit(void) -{ - snd_soc_unregister_platform(&s6000_soc_platform); -} -module_exit(s6000_pcm_exit); - -MODULE_AUTHOR("Daniel Gloeckner"); -MODULE_DESCRIPTION("Stretch s6000 family PCM DMA module"); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/s6000/s6000-pcm.h b/trunk/sound/soc/s6000/s6000-pcm.h deleted file mode 100644 index 96f23f6f52bf..000000000000 --- a/trunk/sound/soc/s6000/s6000-pcm.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * ALSA PCM interface for the Stretch s6000 family - * - * Author: Daniel Gloeckner, - * Copyright: (C) 2009 emlix GmbH - * - * 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. - */ - -#ifndef _S6000_PCM_H -#define _S6000_PCM_H - -struct snd_soc_dai; -struct snd_pcm_substream; - -struct s6000_pcm_dma_params { - unsigned int (*check_xrun)(struct snd_soc_dai *cpu_dai); - int (*trigger)(struct snd_pcm_substream *substream, int cmd, int after); - dma_addr_t sif_in; - dma_addr_t sif_out; - u32 dma_in; - u32 dma_out; - int irq; - int same_rate; - - spinlock_t lock; - int in_use; - int rate; -}; - -extern struct snd_soc_platform s6000_soc_platform; - -#endif diff --git a/trunk/sound/soc/s6000/s6105-ipcam.c b/trunk/sound/soc/s6000/s6105-ipcam.c deleted file mode 100644 index b5f95f9781c1..000000000000 --- a/trunk/sound/soc/s6000/s6105-ipcam.c +++ /dev/null @@ -1,244 +0,0 @@ -/* - * ASoC driver for Stretch s6105 IP camera platform - * - * Author: Daniel Gloeckner, - * Copyright: (C) 2009 emlix GmbH - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "../codecs/tlv320aic3x.h" -#include "s6000-pcm.h" -#include "s6000-i2s.h" - -#define S6105_CAM_CODEC_CLOCK 12288000 - -static int s6105_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - int ret = 0; - - /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) - return ret; - - /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM | - SND_SOC_DAIFMT_NB_NF); - if (ret < 0) - return ret; - - /* set the codec system clock */ - ret = snd_soc_dai_set_sysclk(codec_dai, 0, S6105_CAM_CODEC_CLOCK, - SND_SOC_CLOCK_OUT); - if (ret < 0) - return ret; - - return 0; -} - -static struct snd_soc_ops s6105_ops = { - .hw_params = s6105_hw_params, -}; - -/* s6105 machine dapm widgets */ -static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { - SND_SOC_DAPM_LINE("Audio Out Differential", NULL), - SND_SOC_DAPM_LINE("Audio Out Stereo", NULL), - SND_SOC_DAPM_LINE("Audio In", NULL), -}; - -/* s6105 machine audio_mapnections to the codec pins */ -static const struct snd_soc_dapm_route audio_map[] = { - /* Audio Out connected to HPLOUT, HPLCOM, HPROUT */ - {"Audio Out Differential", NULL, "HPLOUT"}, - {"Audio Out Differential", NULL, "HPLCOM"}, - {"Audio Out Stereo", NULL, "HPLOUT"}, - {"Audio Out Stereo", NULL, "HPROUT"}, - - /* Audio In connected to LINE1L, LINE1R */ - {"LINE1L", NULL, "Audio In"}, - {"LINE1R", NULL, "Audio In"}, -}; - -static int output_type_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item) { - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, "HPLOUT/HPROUT"); - } else { - strcpy(uinfo->value.enumerated.name, "HPLOUT/HPLCOM"); - } - return 0; -} - -static int output_type_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.enumerated.item[0] = kcontrol->private_value; - return 0; -} - -static int output_type_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = kcontrol->private_data; - unsigned int val = (ucontrol->value.enumerated.item[0] != 0); - char *differential = "Audio Out Differential"; - char *stereo = "Audio Out Stereo"; - - if (kcontrol->private_value == val) - return 0; - kcontrol->private_value = val; - snd_soc_dapm_disable_pin(codec, val ? differential : stereo); - snd_soc_dapm_sync(codec); - snd_soc_dapm_enable_pin(codec, val ? stereo : differential); - snd_soc_dapm_sync(codec); - - return 1; -} - -static const struct snd_kcontrol_new audio_out_mux = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Output Mux", - .index = 0, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = output_type_info, - .get = output_type_get, - .put = output_type_put, - .private_value = 1 /* default to stereo */ -}; - -/* Logic for a aic3x as connected on the s6105 ip camera ref design */ -static int s6105_aic3x_init(struct snd_soc_codec *codec) -{ - /* Add s6105 specific widgets */ - snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets, - ARRAY_SIZE(aic3x_dapm_widgets)); - - /* Set up s6105 specific audio path audio_map */ - snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - - /* not present */ - snd_soc_dapm_nc_pin(codec, "MONO_LOUT"); - snd_soc_dapm_nc_pin(codec, "LINE2L"); - snd_soc_dapm_nc_pin(codec, "LINE2R"); - - /* not connected */ - snd_soc_dapm_nc_pin(codec, "MIC3L"); /* LINE2L on this chip */ - snd_soc_dapm_nc_pin(codec, "MIC3R"); /* LINE2R on this chip */ - snd_soc_dapm_nc_pin(codec, "LLOUT"); - snd_soc_dapm_nc_pin(codec, "RLOUT"); - snd_soc_dapm_nc_pin(codec, "HPRCOM"); - - /* always connected */ - snd_soc_dapm_enable_pin(codec, "Audio In"); - - /* must correspond to audio_out_mux.private_value initializer */ - snd_soc_dapm_disable_pin(codec, "Audio Out Differential"); - snd_soc_dapm_sync(codec); - snd_soc_dapm_enable_pin(codec, "Audio Out Stereo"); - - snd_soc_dapm_sync(codec); - - snd_ctl_add(codec->card, snd_ctl_new1(&audio_out_mux, codec)); - - return 0; -} - -/* s6105 digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link s6105_dai = { - .name = "TLV320AIC31", - .stream_name = "AIC31", - .cpu_dai = &s6000_i2s_dai, - .codec_dai = &aic3x_dai, - .init = s6105_aic3x_init, - .ops = &s6105_ops, -}; - -/* s6105 audio machine driver */ -static struct snd_soc_card snd_soc_card_s6105 = { - .name = "Stretch IP Camera", - .platform = &s6000_soc_platform, - .dai_link = &s6105_dai, - .num_links = 1, -}; - -/* s6105 audio private data */ -static struct aic3x_setup_data s6105_aic3x_setup = { - .i2c_bus = 0, - .i2c_address = 0x18, -}; - -/* s6105 audio subsystem */ -static struct snd_soc_device s6105_snd_devdata = { - .card = &snd_soc_card_s6105, - .codec_dev = &soc_codec_dev_aic3x, - .codec_data = &s6105_aic3x_setup, -}; - -static struct s6000_snd_platform_data __initdata s6105_snd_data = { - .wide = 0, - .channel_in = 0, - .channel_out = 1, - .lines_in = 1, - .lines_out = 1, - .same_rate = 1, -}; - -static struct platform_device *s6105_snd_device; - -static int __init s6105_init(void) -{ - int ret; - - s6105_snd_device = platform_device_alloc("soc-audio", -1); - if (!s6105_snd_device) - return -ENOMEM; - - platform_set_drvdata(s6105_snd_device, &s6105_snd_devdata); - s6105_snd_devdata.dev = &s6105_snd_device->dev; - platform_device_add_data(s6105_snd_device, &s6105_snd_data, - sizeof(s6105_snd_data)); - - ret = platform_device_add(s6105_snd_device); - if (ret) - platform_device_put(s6105_snd_device); - - return ret; -} - -static void __exit s6105_exit(void) -{ - platform_device_unregister(s6105_snd_device); -} - -module_init(s6105_init); -module_exit(s6105_exit); - -MODULE_AUTHOR("Daniel Gloeckner"); -MODULE_DESCRIPTION("Stretch s6105 IP camera ASoC driver"); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/sh/ssi.c b/trunk/sound/soc/sh/ssi.c index b378096cadb1..56fa0872abbb 100644 --- a/trunk/sound/soc/sh/ssi.c +++ b/trunk/sound/soc/sh/ssi.c @@ -145,7 +145,7 @@ static int ssi_hw_params(struct snd_pcm_substream *substream, recv = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 0 : 1; pr_debug("ssi_hw_params() enter\nssicr was %08lx\n", ssicr); - pr_debug("bits: %u channels: %u\n", bits, channels); + pr_debug("bits: %d channels: %d\n", bits, channels); ssicr &= ~(CR_TRMD | CR_CHNL_MASK | CR_DWL_MASK | CR_PDTA | CR_SWL_MASK); diff --git a/trunk/sound/soc/soc-core.c b/trunk/sound/soc/soc-core.c index 1d70829464ef..1cd149b9ce69 100644 --- a/trunk/sound/soc/soc-core.c +++ b/trunk/sound/soc/soc-core.c @@ -113,35 +113,6 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec) } #endif -static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_card *card = socdev->card; - struct snd_soc_dai_link *machine = rtd->dai; - struct snd_soc_dai *cpu_dai = machine->cpu_dai; - struct snd_soc_dai *codec_dai = machine->codec_dai; - int ret; - - if (codec_dai->symmetric_rates || cpu_dai->symmetric_rates || - machine->symmetric_rates) { - dev_dbg(card->dev, "Symmetry forces %dHz rate\n", - machine->rate); - - ret = snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_RATE, - machine->rate, - machine->rate); - if (ret < 0) { - dev_err(card->dev, - "Unable to apply rate symmetry constraint: %d\n", ret); - return ret; - } - } - - return 0; -} - /* * Called by ALSA when a PCM substream is opened, the runtime->hw record is * then initialized and any private data can be allocated. This also calls @@ -250,13 +221,6 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) goto machine_err; } - /* Symmetry only applies if we've already got an active stream. */ - if (cpu_dai->active || codec_dai->active) { - ret = soc_pcm_apply_symmetry(substream); - if (ret != 0) - goto machine_err; - } - pr_debug("asoc: %s <-> %s info:\n", codec_dai->name, cpu_dai->name); pr_debug("asoc: rate mask 0x%x\n", runtime->hw.rates); pr_debug("asoc: min ch %d max ch %d\n", runtime->hw.channels_min, @@ -299,6 +263,7 @@ static void close_delayed_work(struct work_struct *work) { struct snd_soc_card *card = container_of(work, struct snd_soc_card, delayed_work.work); + struct snd_soc_device *socdev = card->socdev; struct snd_soc_codec *codec = card->codec; struct snd_soc_dai *codec_dai; int i; @@ -314,10 +279,27 @@ static void close_delayed_work(struct work_struct *work) /* are we waiting on this codec DAI stream */ if (codec_dai->pop_wait == 1) { + + /* Reduce power if no longer active */ + if (codec->active == 0) { + pr_debug("pop wq D1 %s %s\n", codec->name, + codec_dai->playback.stream_name); + snd_soc_dapm_set_bias_level(socdev, + SND_SOC_BIAS_PREPARE); + } + codec_dai->pop_wait = 0; snd_soc_dapm_stream_event(codec, codec_dai->playback.stream_name, SND_SOC_DAPM_STREAM_STOP); + + /* Fall into standby if no longer active */ + if (codec->active == 0) { + pr_debug("pop wq D3 %s %s\n", codec->name, + codec_dai->playback.stream_name); + snd_soc_dapm_set_bias_level(socdev, + SND_SOC_BIAS_STANDBY); + } } } mutex_unlock(&pcm_mutex); @@ -381,6 +363,10 @@ static int soc_codec_close(struct snd_pcm_substream *substream) snd_soc_dapm_stream_event(codec, codec_dai->capture.stream_name, SND_SOC_DAPM_STREAM_STOP); + + if (codec->active == 0 && codec_dai->pop_wait == 0) + snd_soc_dapm_set_bias_level(socdev, + SND_SOC_BIAS_STANDBY); } mutex_unlock(&pcm_mutex); @@ -445,16 +431,36 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) cancel_delayed_work(&card->delayed_work); } - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_soc_dapm_stream_event(codec, - codec_dai->playback.stream_name, - SND_SOC_DAPM_STREAM_START); - else - snd_soc_dapm_stream_event(codec, - codec_dai->capture.stream_name, - SND_SOC_DAPM_STREAM_START); + /* do we need to power up codec */ + if (codec->bias_level != SND_SOC_BIAS_ON) { + snd_soc_dapm_set_bias_level(socdev, + SND_SOC_BIAS_PREPARE); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_dapm_stream_event(codec, + codec_dai->playback.stream_name, + SND_SOC_DAPM_STREAM_START); + else + snd_soc_dapm_stream_event(codec, + codec_dai->capture.stream_name, + SND_SOC_DAPM_STREAM_START); + + snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_ON); + snd_soc_dai_digital_mute(codec_dai, 0); + + } else { + /* codec already powered - power on widgets */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_dapm_stream_event(codec, + codec_dai->playback.stream_name, + SND_SOC_DAPM_STREAM_START); + else + snd_soc_dapm_stream_event(codec, + codec_dai->capture.stream_name, + SND_SOC_DAPM_STREAM_START); - snd_soc_dai_digital_mute(codec_dai, 0); + snd_soc_dai_digital_mute(codec_dai, 0); + } out: mutex_unlock(&pcm_mutex); @@ -515,8 +521,6 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, } } - machine->rate = params_rate(params); - out: mutex_unlock(&pcm_mutex); return ret; @@ -628,12 +632,6 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) struct snd_soc_codec *codec = card->codec; int i; - /* If the initialization of this soc device failed, there is no codec - * associated with it. Just bail out in this case. - */ - if (!codec) - return 0; - /* Due to the resume being scheduled into a workqueue we could * suspend before that's finished - wait for it to complete. */ @@ -1336,7 +1334,6 @@ int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid) return ret; } - codec->socdev = socdev; codec->card->dev = socdev->dev; codec->card->private_data = codec; strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver)); @@ -1389,9 +1386,6 @@ int snd_soc_init_card(struct snd_soc_device *socdev) snprintf(codec->card->longname, sizeof(codec->card->longname), "%s (%s)", card->name, codec->name); - /* Make sure all DAPM widgets are instantiated */ - snd_soc_dapm_new_widgets(codec); - ret = snd_card_register(codec->card); if (ret < 0) { printk(KERN_ERR "asoc: failed to register soundcard for %s\n", @@ -1750,7 +1744,7 @@ int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol, { int max = kcontrol->private_value; - if (max == 1 && !strstr(kcontrol->id.name, " Volume")) + if (max == 1) uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; else uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; @@ -1780,7 +1774,7 @@ int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, unsigned int shift = mc->shift; unsigned int rshift = mc->rshift; - if (max == 1 && !strstr(kcontrol->id.name, " Volume")) + if (max == 1) uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; else uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; @@ -1887,7 +1881,7 @@ int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol, (struct soc_mixer_control *)kcontrol->private_value; int max = mc->max; - if (max == 1 && !strstr(kcontrol->id.name, " Volume")) + if (max == 1) uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; else uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; @@ -2071,7 +2065,7 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8); int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { - if (dai->ops && dai->ops->set_sysclk) + if (dai->ops->set_sysclk) return dai->ops->set_sysclk(dai, clk_id, freq, dir); else return -EINVAL; @@ -2091,7 +2085,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk); int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) { - if (dai->ops && dai->ops->set_clkdiv) + if (dai->ops->set_clkdiv) return dai->ops->set_clkdiv(dai, div_id, div); else return -EINVAL; @@ -2110,7 +2104,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv); int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, unsigned int freq_in, unsigned int freq_out) { - if (dai->ops && dai->ops->set_pll) + if (dai->ops->set_pll) return dai->ops->set_pll(dai, pll_id, freq_in, freq_out); else return -EINVAL; @@ -2126,7 +2120,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll); */ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { - if (dai->ops && dai->ops->set_fmt) + if (dai->ops->set_fmt) return dai->ops->set_fmt(dai, fmt); else return -EINVAL; @@ -2145,7 +2139,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int mask, int slots) { - if (dai->ops && dai->ops->set_tdm_slot) + if (dai->ops->set_sysclk) return dai->ops->set_tdm_slot(dai, mask, slots); else return -EINVAL; @@ -2161,7 +2155,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); */ int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate) { - if (dai->ops && dai->ops->set_tristate) + if (dai->ops->set_sysclk) return dai->ops->set_tristate(dai, tristate); else return -EINVAL; @@ -2177,7 +2171,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate); */ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute) { - if (dai->ops && dai->ops->digital_mute) + if (dai->ops->digital_mute) return dai->ops->digital_mute(dai, mute); else return -EINVAL; @@ -2358,39 +2352,6 @@ void snd_soc_unregister_platform(struct snd_soc_platform *platform) } EXPORT_SYMBOL_GPL(snd_soc_unregister_platform); -static u64 codec_format_map[] = { - SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE, - SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE, - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE, - SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE, - SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE, - SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE, - SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3BE, - SNDRV_PCM_FMTBIT_U24_3LE | SNDRV_PCM_FMTBIT_U24_3BE, - SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE, - SNDRV_PCM_FMTBIT_U20_3LE | SNDRV_PCM_FMTBIT_U20_3BE, - SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE, - SNDRV_PCM_FMTBIT_U18_3LE | SNDRV_PCM_FMTBIT_U18_3BE, - SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE, - SNDRV_PCM_FMTBIT_FLOAT64_LE | SNDRV_PCM_FMTBIT_FLOAT64_BE, - SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE - | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE, -}; - -/* Fix up the DAI formats for endianness: codecs don't actually see - * the endianness of the data but we're using the CPU format - * definitions which do need to include endianness so we ensure that - * codec DAIs always have both big and little endian variants set. - */ -static void fixup_codec_formats(struct snd_soc_pcm_stream *stream) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(codec_format_map); i++) - if (stream->formats & codec_format_map[i]) - stream->formats |= codec_format_map[i]; -} - /** * snd_soc_register_codec - Register a codec with the ASoC core * @@ -2398,8 +2359,6 @@ static void fixup_codec_formats(struct snd_soc_pcm_stream *stream) */ int snd_soc_register_codec(struct snd_soc_codec *codec) { - int i; - if (!codec->name) return -EINVAL; @@ -2409,11 +2368,6 @@ int snd_soc_register_codec(struct snd_soc_codec *codec) INIT_LIST_HEAD(&codec->list); - for (i = 0; i < codec->num_dai; i++) { - fixup_codec_formats(&codec->dai[i].playback); - fixup_codec_formats(&codec->dai[i].capture); - } - mutex_lock(&client_mutex); list_add(&codec->list, &codec_list); snd_soc_instantiate_cards(); diff --git a/trunk/sound/soc/soc-dapm.c b/trunk/sound/soc/soc-dapm.c index 21c69074aa17..735903a74675 100644 --- a/trunk/sound/soc/soc-dapm.c +++ b/trunk/sound/soc/soc-dapm.c @@ -12,7 +12,7 @@ * Features: * o Changes power status of internal codec blocks depending on the * dynamic configuration of codec internal audio paths and active - * DACs/ADCs. + * DAC's/ADC's. * o Platform power domain - can support external components i.e. amps and * mic/meadphone insertion events. * o Automatic Mic Bias support @@ -52,21 +52,23 @@ /* dapm power sequences - make this per codec in the future */ static int dapm_up_seq[] = { - snd_soc_dapm_pre, snd_soc_dapm_supply, snd_soc_dapm_micbias, - snd_soc_dapm_mic, snd_soc_dapm_mux, snd_soc_dapm_value_mux, - snd_soc_dapm_dac, snd_soc_dapm_mixer, snd_soc_dapm_mixer_named_ctl, - snd_soc_dapm_pga, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, - snd_soc_dapm_post + snd_soc_dapm_pre, snd_soc_dapm_micbias, snd_soc_dapm_mic, + snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_dac, + snd_soc_dapm_mixer, snd_soc_dapm_mixer_named_ctl, snd_soc_dapm_pga, + snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, snd_soc_dapm_post }; static int dapm_down_seq[] = { snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, snd_soc_dapm_pga, snd_soc_dapm_mixer_named_ctl, snd_soc_dapm_mixer, snd_soc_dapm_dac, snd_soc_dapm_mic, snd_soc_dapm_micbias, - snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_supply, - snd_soc_dapm_post + snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_post }; +static int dapm_status = 1; +module_param(dapm_status, int, 0); +MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries"); + static void pop_wait(u32 pop_time) { if (pop_time) @@ -94,48 +96,6 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget( return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); } -/** - * snd_soc_dapm_set_bias_level - set the bias level for the system - * @socdev: audio device - * @level: level to configure - * - * Configure the bias (power) levels for the SoC audio device. - * - * Returns 0 for success else error. - */ -static int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev, - enum snd_soc_bias_level level) -{ - struct snd_soc_card *card = socdev->card; - struct snd_soc_codec *codec = socdev->card->codec; - int ret = 0; - - switch (level) { - case SND_SOC_BIAS_ON: - dev_dbg(socdev->dev, "Setting full bias\n"); - break; - case SND_SOC_BIAS_PREPARE: - dev_dbg(socdev->dev, "Setting bias prepare\n"); - break; - case SND_SOC_BIAS_STANDBY: - dev_dbg(socdev->dev, "Setting standby bias\n"); - break; - case SND_SOC_BIAS_OFF: - dev_dbg(socdev->dev, "Setting bias off\n"); - break; - default: - dev_err(socdev->dev, "Setting invalid bias %d\n", level); - return -EINVAL; - } - - if (card->set_bias_level) - ret = card->set_bias_level(card, level); - if (ret == 0 && codec->set_bias_level) - ret = codec->set_bias_level(codec, level); - - return ret; -} - /* set up initial codec paths */ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, struct snd_soc_dapm_path *p, int i) @@ -205,7 +165,6 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, case snd_soc_dapm_dac: case snd_soc_dapm_micbias: case snd_soc_dapm_vmid: - case snd_soc_dapm_supply: p->connect = 1; break; /* does effect routing - dynamically connected */ @@ -220,7 +179,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, } } -/* connect mux widget to its interconnecting audio paths */ +/* connect mux widget to it's interconnecting audio paths */ static int dapm_connect_mux(struct snd_soc_codec *codec, struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, struct snd_soc_dapm_path *path, const char *control_name, @@ -243,7 +202,7 @@ static int dapm_connect_mux(struct snd_soc_codec *codec, return -ENODEV; } -/* connect mixer widget to its interconnecting audio paths */ +/* connect mixer widget to it's interconnecting audio paths */ static int dapm_connect_mixer(struct snd_soc_codec *codec, struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, struct snd_soc_dapm_path *path, const char *control_name) @@ -398,9 +357,8 @@ static int dapm_new_mixer(struct snd_soc_codec *codec, path->long_name); ret = snd_ctl_add(codec->card, path->kcontrol); if (ret < 0) { - printk(KERN_ERR "asoc: failed to add dapm kcontrol %s: %d\n", - path->long_name, - ret); + printk(KERN_ERR "asoc: failed to add dapm kcontrol %s\n", + path->long_name); kfree(path->long_name); path->long_name = NULL; return ret; @@ -476,9 +434,6 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget) struct snd_soc_dapm_path *path; int con = 0; - if (widget->id == snd_soc_dapm_supply) - return 0; - if (widget->id == snd_soc_dapm_adc && widget->active) return 1; @@ -515,9 +470,6 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget) struct snd_soc_dapm_path *path; int con = 0; - if (widget->id == snd_soc_dapm_supply) - return 0; - /* active stream ? */ if (widget->id == snd_soc_dapm_dac && widget->active) return 1; @@ -569,12 +521,84 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w, } EXPORT_SYMBOL_GPL(dapm_reg_event); -/* Standard power change method, used to apply power changes to most - * widgets. +/* + * Scan a single DAPM widget for a complete audio path and update the + * power status appropriately. */ -static int dapm_generic_apply_power(struct snd_soc_dapm_widget *w) +static int dapm_power_widget(struct snd_soc_codec *codec, int event, + struct snd_soc_dapm_widget *w) { - int ret; + int in, out, power_change, power, ret; + + /* vmid - no action */ + if (w->id == snd_soc_dapm_vmid) + return 0; + + /* active ADC */ + if (w->id == snd_soc_dapm_adc && w->active) { + in = is_connected_input_ep(w); + dapm_clear_walk(w->codec); + w->power = (in != 0) ? 1 : 0; + dapm_update_bits(w); + return 0; + } + + /* active DAC */ + if (w->id == snd_soc_dapm_dac && w->active) { + out = is_connected_output_ep(w); + dapm_clear_walk(w->codec); + w->power = (out != 0) ? 1 : 0; + dapm_update_bits(w); + return 0; + } + + /* pre and post event widgets */ + if (w->id == snd_soc_dapm_pre) { + if (!w->event) + return 0; + + if (event == SND_SOC_DAPM_STREAM_START) { + ret = w->event(w, + NULL, SND_SOC_DAPM_PRE_PMU); + if (ret < 0) + return ret; + } else if (event == SND_SOC_DAPM_STREAM_STOP) { + ret = w->event(w, + NULL, SND_SOC_DAPM_PRE_PMD); + if (ret < 0) + return ret; + } + return 0; + } + if (w->id == snd_soc_dapm_post) { + if (!w->event) + return 0; + + if (event == SND_SOC_DAPM_STREAM_START) { + ret = w->event(w, + NULL, SND_SOC_DAPM_POST_PMU); + if (ret < 0) + return ret; + } else if (event == SND_SOC_DAPM_STREAM_STOP) { + ret = w->event(w, + NULL, SND_SOC_DAPM_POST_PMD); + if (ret < 0) + return ret; + } + return 0; + } + + /* all other widgets */ + in = is_connected_input_ep(w); + dapm_clear_walk(w->codec); + out = is_connected_output_ep(w); + dapm_clear_walk(w->codec); + power = (out != 0 && in != 0) ? 1 : 0; + power_change = (w->power == power) ? 0 : 1; + w->power = power; + + if (!power_change) + return 0; /* call any power change event handlers */ if (w->event) @@ -583,7 +607,7 @@ static int dapm_generic_apply_power(struct snd_soc_dapm_widget *w) w->name, w->event_flags); /* power up pre event */ - if (w->power && w->event && + if (power && w->event && (w->event_flags & SND_SOC_DAPM_PRE_PMU)) { ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMU); if (ret < 0) @@ -591,7 +615,7 @@ static int dapm_generic_apply_power(struct snd_soc_dapm_widget *w) } /* power down pre event */ - if (!w->power && w->event && + if (!power && w->event && (w->event_flags & SND_SOC_DAPM_PRE_PMD)) { ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMD); if (ret < 0) @@ -599,17 +623,17 @@ static int dapm_generic_apply_power(struct snd_soc_dapm_widget *w) } /* Lower PGA volume to reduce pops */ - if (w->id == snd_soc_dapm_pga && !w->power) - dapm_set_pga(w, w->power); + if (w->id == snd_soc_dapm_pga && !power) + dapm_set_pga(w, power); dapm_update_bits(w); /* Raise PGA volume to reduce pops */ - if (w->id == snd_soc_dapm_pga && w->power) - dapm_set_pga(w, w->power); + if (w->id == snd_soc_dapm_pga && power) + dapm_set_pga(w, power); /* power up post event */ - if (w->power && w->event && + if (power && w->event && (w->event_flags & SND_SOC_DAPM_POST_PMU)) { ret = w->event(w, NULL, SND_SOC_DAPM_POST_PMU); @@ -618,7 +642,7 @@ static int dapm_generic_apply_power(struct snd_soc_dapm_widget *w) } /* power down post event */ - if (!w->power && w->event && + if (!power && w->event && (w->event_flags & SND_SOC_DAPM_POST_PMD)) { ret = w->event(w, NULL, SND_SOC_DAPM_POST_PMD); if (ret < 0) @@ -628,116 +652,6 @@ static int dapm_generic_apply_power(struct snd_soc_dapm_widget *w) return 0; } -/* Generic check to see if a widget should be powered. - */ -static int dapm_generic_check_power(struct snd_soc_dapm_widget *w) -{ - int in, out; - - in = is_connected_input_ep(w); - dapm_clear_walk(w->codec); - out = is_connected_output_ep(w); - dapm_clear_walk(w->codec); - return out != 0 && in != 0; -} - -/* Check to see if an ADC has power */ -static int dapm_adc_check_power(struct snd_soc_dapm_widget *w) -{ - int in; - - if (w->active) { - in = is_connected_input_ep(w); - dapm_clear_walk(w->codec); - return in != 0; - } else { - return dapm_generic_check_power(w); - } -} - -/* Check to see if a DAC has power */ -static int dapm_dac_check_power(struct snd_soc_dapm_widget *w) -{ - int out; - - if (w->active) { - out = is_connected_output_ep(w); - dapm_clear_walk(w->codec); - return out != 0; - } else { - return dapm_generic_check_power(w); - } -} - -/* Check to see if a power supply is needed */ -static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) -{ - struct snd_soc_dapm_path *path; - int power = 0; - - /* Check if one of our outputs is connected */ - list_for_each_entry(path, &w->sinks, list_source) { - if (path->sink && path->sink->power_check && - path->sink->power_check(path->sink)) { - power = 1; - break; - } - } - - dapm_clear_walk(w->codec); - - return power; -} - -/* - * Scan a single DAPM widget for a complete audio path and update the - * power status appropriately. - */ -static int dapm_power_widget(struct snd_soc_codec *codec, int event, - struct snd_soc_dapm_widget *w) -{ - int ret; - - switch (w->id) { - case snd_soc_dapm_pre: - if (!w->event) - return 0; - - if (event == SND_SOC_DAPM_STREAM_START) { - ret = w->event(w, - NULL, SND_SOC_DAPM_PRE_PMU); - if (ret < 0) - return ret; - } else if (event == SND_SOC_DAPM_STREAM_STOP) { - ret = w->event(w, - NULL, SND_SOC_DAPM_PRE_PMD); - if (ret < 0) - return ret; - } - return 0; - - case snd_soc_dapm_post: - if (!w->event) - return 0; - - if (event == SND_SOC_DAPM_STREAM_START) { - ret = w->event(w, - NULL, SND_SOC_DAPM_POST_PMU); - if (ret < 0) - return ret; - } else if (event == SND_SOC_DAPM_STREAM_STOP) { - ret = w->event(w, - NULL, SND_SOC_DAPM_POST_PMD); - if (ret < 0) - return ret; - } - return 0; - - default: - return dapm_generic_apply_power(w); - } -} - /* * Scan each dapm widget for complete audio path. * A complete path is a route that has valid endpoints i.e.:- @@ -749,102 +663,31 @@ static int dapm_power_widget(struct snd_soc_codec *codec, int event, */ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) { - struct snd_soc_device *socdev = codec->socdev; struct snd_soc_dapm_widget *w; - int ret = 0; - int i, power; - int sys_power = 0; - - INIT_LIST_HEAD(&codec->up_list); - INIT_LIST_HEAD(&codec->down_list); - - /* Check which widgets we need to power and store them in - * lists indicating if they should be powered up or down. - */ - list_for_each_entry(w, &codec->dapm_widgets, list) { - switch (w->id) { - case snd_soc_dapm_pre: - list_add_tail(&codec->down_list, &w->power_list); - break; - case snd_soc_dapm_post: - list_add_tail(&codec->up_list, &w->power_list); - break; - - default: - if (!w->power_check) - continue; - - power = w->power_check(w); - if (power) - sys_power = 1; - - if (w->power == power) - continue; - - if (power) - list_add_tail(&w->power_list, &codec->up_list); - else - list_add_tail(&w->power_list, - &codec->down_list); - - w->power = power; - break; - } + int i, c = 1, *seq = NULL, ret = 0; + + /* do we have a sequenced stream event */ + if (event == SND_SOC_DAPM_STREAM_START) { + c = ARRAY_SIZE(dapm_up_seq); + seq = dapm_up_seq; + } else if (event == SND_SOC_DAPM_STREAM_STOP) { + c = ARRAY_SIZE(dapm_down_seq); + seq = dapm_down_seq; } - /* If we're changing to all on or all off then prepare */ - if ((sys_power && codec->bias_level == SND_SOC_BIAS_STANDBY) || - (!sys_power && codec->bias_level == SND_SOC_BIAS_ON)) { - ret = snd_soc_dapm_set_bias_level(socdev, - SND_SOC_BIAS_PREPARE); - if (ret != 0) - pr_err("Failed to prepare bias: %d\n", ret); - } + for (i = 0; i < c; i++) { + list_for_each_entry(w, &codec->dapm_widgets, list) { - /* Power down widgets first; try to avoid amplifying pops. */ - for (i = 0; i < ARRAY_SIZE(dapm_down_seq); i++) { - list_for_each_entry(w, &codec->down_list, power_list) { /* is widget in stream order */ - if (w->id != dapm_down_seq[i]) + if (seq && seq[i] && w->id != seq[i]) continue; ret = dapm_power_widget(codec, event, w); if (ret != 0) - pr_err("Failed to power down %s: %d\n", - w->name, ret); - } - } - - /* Now power up. */ - for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) { - list_for_each_entry(w, &codec->up_list, power_list) { - /* is widget in stream order */ - if (w->id != dapm_up_seq[i]) - continue; - - ret = dapm_power_widget(codec, event, w); - if (ret != 0) - pr_err("Failed to power up %s: %d\n", - w->name, ret); + return ret; } } - /* If we just powered the last thing off drop to standby bias */ - if (codec->bias_level == SND_SOC_BIAS_PREPARE && !sys_power) { - ret = snd_soc_dapm_set_bias_level(socdev, - SND_SOC_BIAS_STANDBY); - if (ret != 0) - pr_err("Failed to apply standby bias: %d\n", ret); - } - - /* If we just powered up then move to active bias */ - if (codec->bias_level == SND_SOC_BIAS_PREPARE && sys_power) { - ret = snd_soc_dapm_set_bias_level(socdev, - SND_SOC_BIAS_ON); - if (ret != 0) - pr_err("Failed to apply active bias: %d\n", ret); - } - return 0; } @@ -880,7 +723,6 @@ static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action) case snd_soc_dapm_pga: case snd_soc_dapm_mixer: case snd_soc_dapm_mixer_named_ctl: - case snd_soc_dapm_supply: if (w->name) { in = is_connected_input_ep(w); dapm_clear_walk(w->codec); @@ -1009,7 +851,6 @@ static ssize_t dapm_widget_show(struct device *dev, case snd_soc_dapm_pga: case snd_soc_dapm_mixer: case snd_soc_dapm_mixer_named_ctl: - case snd_soc_dapm_supply: if (w->name) count += sprintf(buf + count, "%s: %s\n", w->name, w->power ? "On":"Off"); @@ -1042,12 +883,16 @@ static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL); int snd_soc_dapm_sys_add(struct device *dev) { + if (!dapm_status) + return 0; return device_create_file(dev, &dev_attr_dapm_widget); } static void snd_soc_dapm_sys_remove(struct device *dev) { - device_remove_file(dev, &dev_attr_dapm_widget); + if (dapm_status) { + device_remove_file(dev, &dev_attr_dapm_widget); + } } /* free all dapm widgets and resources */ @@ -1170,7 +1015,6 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, case snd_soc_dapm_vmid: case snd_soc_dapm_pre: case snd_soc_dapm_post: - case snd_soc_dapm_supply: list_add(&path->list, &codec->dapm_paths); list_add(&path->list_sink, &wsink->sources); list_add(&path->list_source, &wsource->sinks); @@ -1264,22 +1108,15 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec) case snd_soc_dapm_switch: case snd_soc_dapm_mixer: case snd_soc_dapm_mixer_named_ctl: - w->power_check = dapm_generic_check_power; dapm_new_mixer(codec, w); break; case snd_soc_dapm_mux: case snd_soc_dapm_value_mux: - w->power_check = dapm_generic_check_power; dapm_new_mux(codec, w); break; case snd_soc_dapm_adc: - w->power_check = dapm_adc_check_power; - break; case snd_soc_dapm_dac: - w->power_check = dapm_dac_check_power; - break; case snd_soc_dapm_pga: - w->power_check = dapm_generic_check_power; dapm_new_pga(codec, w); break; case snd_soc_dapm_input: @@ -1289,10 +1126,6 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec) case snd_soc_dapm_hp: case snd_soc_dapm_mic: case snd_soc_dapm_line: - w->power_check = dapm_generic_check_power; - break; - case snd_soc_dapm_supply: - w->power_check = dapm_supply_check_power; case snd_soc_dapm_vmid: case snd_soc_dapm_pre: case snd_soc_dapm_post: @@ -1792,12 +1625,36 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, } EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); +/** + * snd_soc_dapm_set_bias_level - set the bias level for the system + * @socdev: audio device + * @level: level to configure + * + * Configure the bias (power) levels for the SoC audio device. + * + * Returns 0 for success else error. + */ +int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev, + enum snd_soc_bias_level level) +{ + struct snd_soc_card *card = socdev->card; + struct snd_soc_codec *codec = socdev->card->codec; + int ret = 0; + + if (card->set_bias_level) + ret = card->set_bias_level(card, level); + if (ret == 0 && codec->set_bias_level) + ret = codec->set_bias_level(codec, level); + + return ret; +} + /** * snd_soc_dapm_enable_pin - enable pin. * @codec: SoC codec * @pin: pin name * - * Enables input/output pin and its parents or children widgets iff there is + * Enables input/output pin and it's parents or children widgets iff there is * a valid audio route and active audio stream. * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to * do any widget power switching. @@ -1813,7 +1670,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin); * @codec: SoC codec * @pin: pin name * - * Disables input/output pin and its parents or children widgets. + * Disables input/output pin and it's parents or children widgets. * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to * do any widget power switching. */ diff --git a/trunk/sound/soc/txx9/Kconfig b/trunk/sound/soc/txx9/Kconfig deleted file mode 100644 index ebc9327eae71..000000000000 --- a/trunk/sound/soc/txx9/Kconfig +++ /dev/null @@ -1,29 +0,0 @@ -## -## TXx9 ACLC -## -config SND_SOC_TXX9ACLC - tristate "SoC Audio for TXx9" - depends on HAS_TXX9_ACLC && TXX9_DMAC - help - This option enables support for the AC Link Controllers in TXx9 SoC. - -config HAS_TXX9_ACLC - bool - -config SND_SOC_TXX9ACLC_AC97 - tristate - select AC97_BUS - select SND_AC97_CODEC - select SND_SOC_AC97_BUS - - -## -## Boards -## -config SND_SOC_TXX9ACLC_GENERIC - tristate "Generic TXx9 ACLC sound machine" - depends on SND_SOC_TXX9ACLC - select SND_SOC_TXX9ACLC_AC97 - select SND_SOC_AC97_CODEC - help - This is a generic AC97 sound machine for use in TXx9 based systems. diff --git a/trunk/sound/soc/txx9/Makefile b/trunk/sound/soc/txx9/Makefile deleted file mode 100644 index 551f16c0c4f9..000000000000 --- a/trunk/sound/soc/txx9/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Platform -snd-soc-txx9aclc-objs := txx9aclc.o -snd-soc-txx9aclc-ac97-objs := txx9aclc-ac97.o - -obj-$(CONFIG_SND_SOC_TXX9ACLC) += snd-soc-txx9aclc.o -obj-$(CONFIG_SND_SOC_TXX9ACLC_AC97) += snd-soc-txx9aclc-ac97.o - -# Machine -snd-soc-txx9aclc-generic-objs := txx9aclc-generic.o - -obj-$(CONFIG_SND_SOC_TXX9ACLC_GENERIC) += snd-soc-txx9aclc-generic.o diff --git a/trunk/sound/soc/txx9/txx9aclc-ac97.c b/trunk/sound/soc/txx9/txx9aclc-ac97.c deleted file mode 100644 index 0f83bdb9b16f..000000000000 --- a/trunk/sound/soc/txx9/txx9aclc-ac97.c +++ /dev/null @@ -1,255 +0,0 @@ -/* - * TXx9 ACLC AC97 driver - * - * Copyright (C) 2009 Atsushi Nemoto - * - * Based on RBTX49xx patch from CELF patch archive. - * (C) Copyright TOSHIBA CORPORATION 2004-2006 - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "txx9aclc.h" - -#define AC97_DIR \ - (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) - -#define AC97_RATES \ - SNDRV_PCM_RATE_8000_48000 - -#ifdef __BIG_ENDIAN -#define AC97_FMTS SNDRV_PCM_FMTBIT_S16_BE -#else -#define AC97_FMTS SNDRV_PCM_FMTBIT_S16_LE -#endif - -static DECLARE_WAIT_QUEUE_HEAD(ac97_waitq); - -/* REVISIT: How to find txx9aclc_soc_device from snd_ac97? */ -static struct txx9aclc_soc_device *txx9aclc_soc_dev; - -static int txx9aclc_regready(struct txx9aclc_soc_device *dev) -{ - struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev); - - return __raw_readl(drvdata->base + ACINTSTS) & ACINT_REGACCRDY; -} - -/* AC97 controller reads codec register */ -static unsigned short txx9aclc_ac97_read(struct snd_ac97 *ac97, - unsigned short reg) -{ - struct txx9aclc_soc_device *dev = txx9aclc_soc_dev; - struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev); - void __iomem *base = drvdata->base; - u32 dat; - - if (!(__raw_readl(base + ACINTSTS) & ACINT_CODECRDY(ac97->num))) - return 0xffff; - reg |= ac97->num << 7; - dat = (reg << ACREGACC_REG_SHIFT) | ACREGACC_READ; - __raw_writel(dat, base + ACREGACC); - __raw_writel(ACINT_REGACCRDY, base + ACINTEN); - if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(dev), HZ)) { - __raw_writel(ACINT_REGACCRDY, base + ACINTDIS); - dev_err(dev->soc_dev.dev, "ac97 read timeout (reg %#x)\n", reg); - dat = 0xffff; - goto done; - } - dat = __raw_readl(base + ACREGACC); - if (((dat >> ACREGACC_REG_SHIFT) & 0xff) != reg) { - dev_err(dev->soc_dev.dev, "reg mismatch %x with %x\n", - dat, reg); - dat = 0xffff; - goto done; - } - dat = (dat >> ACREGACC_DAT_SHIFT) & 0xffff; -done: - __raw_writel(ACINT_REGACCRDY, base + ACINTDIS); - return dat; -} - -/* AC97 controller writes to codec register */ -static void txx9aclc_ac97_write(struct snd_ac97 *ac97, unsigned short reg, - unsigned short val) -{ - struct txx9aclc_soc_device *dev = txx9aclc_soc_dev; - struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev); - void __iomem *base = drvdata->base; - - __raw_writel(((reg | (ac97->num << 7)) << ACREGACC_REG_SHIFT) | - (val << ACREGACC_DAT_SHIFT), - base + ACREGACC); - __raw_writel(ACINT_REGACCRDY, base + ACINTEN); - if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(dev), HZ)) { - dev_err(dev->soc_dev.dev, - "ac97 write timeout (reg %#x)\n", reg); - } - __raw_writel(ACINT_REGACCRDY, base + ACINTDIS); -} - -static void txx9aclc_ac97_cold_reset(struct snd_ac97 *ac97) -{ - struct txx9aclc_soc_device *dev = txx9aclc_soc_dev; - struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev); - void __iomem *base = drvdata->base; - u32 ready = ACINT_CODECRDY(ac97->num) | ACINT_REGACCRDY; - - __raw_writel(ACCTL_ENLINK, base + ACCTLDIS); - mmiowb(); - udelay(1); - __raw_writel(ACCTL_ENLINK, base + ACCTLEN); - /* wait for primary codec ready status */ - __raw_writel(ready, base + ACINTEN); - if (!wait_event_timeout(ac97_waitq, - (__raw_readl(base + ACINTSTS) & ready) == ready, - HZ)) { - dev_err(&ac97->dev, "primary codec is not ready " - "(status %#x)\n", - __raw_readl(base + ACINTSTS)); - } - __raw_writel(ACINT_REGACCRDY, base + ACINTSTS); - __raw_writel(ready, base + ACINTDIS); -} - -/* AC97 controller operations */ -struct snd_ac97_bus_ops soc_ac97_ops = { - .read = txx9aclc_ac97_read, - .write = txx9aclc_ac97_write, - .reset = txx9aclc_ac97_cold_reset, -}; -EXPORT_SYMBOL_GPL(soc_ac97_ops); - -static irqreturn_t txx9aclc_ac97_irq(int irq, void *dev_id) -{ - struct txx9aclc_plat_drvdata *drvdata = dev_id; - void __iomem *base = drvdata->base; - - __raw_writel(__raw_readl(base + ACINTMSTS), base + ACINTDIS); - wake_up(&ac97_waitq); - return IRQ_HANDLED; -} - -static int txx9aclc_ac97_probe(struct platform_device *pdev, - struct snd_soc_dai *dai) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct txx9aclc_soc_device *dev = - container_of(socdev, struct txx9aclc_soc_device, soc_dev); - - dev->aclc_pdev = to_platform_device(dai->dev); - txx9aclc_soc_dev = dev; - return 0; -} - -static void txx9aclc_ac97_remove(struct platform_device *pdev, - struct snd_soc_dai *dai) -{ - struct platform_device *aclc_pdev = to_platform_device(dai->dev); - struct txx9aclc_plat_drvdata *drvdata = platform_get_drvdata(aclc_pdev); - - /* disable AC-link */ - __raw_writel(ACCTL_ENLINK, drvdata->base + ACCTLDIS); - txx9aclc_soc_dev = NULL; -} - -struct snd_soc_dai txx9aclc_ac97_dai = { - .name = "txx9aclc_ac97", - .ac97_control = 1, - .probe = txx9aclc_ac97_probe, - .remove = txx9aclc_ac97_remove, - .playback = { - .rates = AC97_RATES, - .formats = AC97_FMTS, - .channels_min = 2, - .channels_max = 2, - }, - .capture = { - .rates = AC97_RATES, - .formats = AC97_FMTS, - .channels_min = 2, - .channels_max = 2, - }, -}; -EXPORT_SYMBOL_GPL(txx9aclc_ac97_dai); - -static int __devinit txx9aclc_ac97_dev_probe(struct platform_device *pdev) -{ - struct txx9aclc_plat_drvdata *drvdata; - struct resource *r; - int err; - int irq; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!r) - return -EBUSY; - - if (!devm_request_mem_region(&pdev->dev, r->start, resource_size(r), - dev_name(&pdev->dev))) - return -EBUSY; - - drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); - if (!drvdata) - return -ENOMEM; - platform_set_drvdata(pdev, drvdata); - drvdata->physbase = r->start; - if (sizeof(drvdata->physbase) > sizeof(r->start) && - r->start >= TXX9_DIRECTMAP_BASE && - r->start < TXX9_DIRECTMAP_BASE + 0x400000) - drvdata->physbase |= 0xf00000000ull; - drvdata->base = devm_ioremap(&pdev->dev, r->start, resource_size(r)); - if (!drvdata->base) - return -EBUSY; - err = devm_request_irq(&pdev->dev, irq, txx9aclc_ac97_irq, - IRQF_DISABLED, dev_name(&pdev->dev), drvdata); - if (err < 0) - return err; - - txx9aclc_ac97_dai.dev = &pdev->dev; - return snd_soc_register_dai(&txx9aclc_ac97_dai); -} - -static int __devexit txx9aclc_ac97_dev_remove(struct platform_device *pdev) -{ - snd_soc_unregister_dai(&txx9aclc_ac97_dai); - return 0; -} - -static struct platform_driver txx9aclc_ac97_driver = { - .probe = txx9aclc_ac97_dev_probe, - .remove = __devexit_p(txx9aclc_ac97_dev_remove), - .driver = { - .name = "txx9aclc-ac97", - .owner = THIS_MODULE, - }, -}; - -static int __init txx9aclc_ac97_init(void) -{ - return platform_driver_register(&txx9aclc_ac97_driver); -} - -static void __exit txx9aclc_ac97_exit(void) -{ - platform_driver_unregister(&txx9aclc_ac97_driver); -} - -module_init(txx9aclc_ac97_init); -module_exit(txx9aclc_ac97_exit); - -MODULE_AUTHOR("Atsushi Nemoto "); -MODULE_DESCRIPTION("TXx9 ACLC AC97 driver"); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/txx9/txx9aclc-generic.c b/trunk/sound/soc/txx9/txx9aclc-generic.c deleted file mode 100644 index 3175de9a92cb..000000000000 --- a/trunk/sound/soc/txx9/txx9aclc-generic.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Generic TXx9 ACLC machine driver - * - * Copyright (C) 2009 Atsushi Nemoto - * - * Based on RBTX49xx patch from CELF patch archive. - * (C) Copyright TOSHIBA CORPORATION 2004-2006 - * - * 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. - * - * This is a very generic AC97 sound machine driver for boards which - * have (AC97) audio at ACLC (e.g. RBTX49XX boards). - */ - -#include -#include -#include -#include -#include -#include "../codecs/ac97.h" -#include "txx9aclc.h" - -static struct snd_soc_dai_link txx9aclc_generic_dai = { - .name = "AC97", - .stream_name = "AC97 HiFi", - .cpu_dai = &txx9aclc_ac97_dai, - .codec_dai = &ac97_dai, -}; - -static struct snd_soc_card txx9aclc_generic_card = { - .name = "Generic TXx9 ACLC Audio", - .platform = &txx9aclc_soc_platform, - .dai_link = &txx9aclc_generic_dai, - .num_links = 1, -}; - -static struct txx9aclc_soc_device txx9aclc_generic_soc_device = { - .soc_dev = { - .card = &txx9aclc_generic_card, - .codec_dev = &soc_codec_dev_ac97, - }, -}; - -static int __init txx9aclc_generic_probe(struct platform_device *pdev) -{ - struct txx9aclc_soc_device *dev = &txx9aclc_generic_soc_device; - struct platform_device *soc_pdev; - int ret; - - soc_pdev = platform_device_alloc("soc-audio", -1); - if (!soc_pdev) - return -ENOMEM; - platform_set_drvdata(soc_pdev, &dev->soc_dev); - dev->soc_dev.dev = &soc_pdev->dev; - ret = platform_device_add(soc_pdev); - if (ret) { - platform_device_put(soc_pdev); - return ret; - } - platform_set_drvdata(pdev, soc_pdev); - return 0; -} - -static int __exit txx9aclc_generic_remove(struct platform_device *pdev) -{ - struct platform_device *soc_pdev = platform_get_drvdata(pdev); - - platform_device_unregister(soc_pdev); - return 0; -} - -static struct platform_driver txx9aclc_generic_driver = { - .remove = txx9aclc_generic_remove, - .driver = { - .name = "txx9aclc-generic", - .owner = THIS_MODULE, - }, -}; - -static int __init txx9aclc_generic_init(void) -{ - return platform_driver_probe(&txx9aclc_generic_driver, - txx9aclc_generic_probe); -} - -static void __exit txx9aclc_generic_exit(void) -{ - platform_driver_unregister(&txx9aclc_generic_driver); -} - -module_init(txx9aclc_generic_init); -module_exit(txx9aclc_generic_exit); - -MODULE_AUTHOR("Atsushi Nemoto "); -MODULE_DESCRIPTION("Generic TXx9 ACLC ALSA SoC audio driver"); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/txx9/txx9aclc.c b/trunk/sound/soc/txx9/txx9aclc.c deleted file mode 100644 index 938a58a5a244..000000000000 --- a/trunk/sound/soc/txx9/txx9aclc.c +++ /dev/null @@ -1,430 +0,0 @@ -/* - * Generic TXx9 ACLC platform driver - * - * Copyright (C) 2009 Atsushi Nemoto - * - * Based on RBTX49xx patch from CELF patch archive. - * (C) Copyright TOSHIBA CORPORATION 2004-2006 - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "txx9aclc.h" - -static const struct snd_pcm_hardware txx9aclc_pcm_hardware = { - /* - * REVISIT: SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID - * needs more works for noncoherent MIPS. - */ - .info = SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BATCH | - SNDRV_PCM_INFO_PAUSE, -#ifdef __BIG_ENDIAN - .formats = SNDRV_PCM_FMTBIT_S16_BE, -#else - .formats = SNDRV_PCM_FMTBIT_S16_LE, -#endif - .period_bytes_min = 1024, - .period_bytes_max = 8 * 1024, - .periods_min = 2, - .periods_max = 4096, - .buffer_bytes_max = 32 * 1024, -}; - -static int txx9aclc_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - struct snd_soc_device *socdev = rtd->socdev; - struct snd_pcm_runtime *runtime = substream->runtime; - struct txx9aclc_dmadata *dmadata = runtime->private_data; - int ret; - - ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); - if (ret < 0) - return ret; - - dev_dbg(socdev->dev, - "runtime->dma_area = %#lx dma_addr = %#lx dma_bytes = %zd " - "runtime->min_align %ld\n", - (unsigned long)runtime->dma_area, - (unsigned long)runtime->dma_addr, runtime->dma_bytes, - runtime->min_align); - dev_dbg(socdev->dev, - "periods %d period_bytes %d stream %d\n", - params_periods(params), params_period_bytes(params), - substream->stream); - - dmadata->substream = substream; - dmadata->pos = 0; - return 0; -} - -static int txx9aclc_pcm_hw_free(struct snd_pcm_substream *substream) -{ - return snd_pcm_lib_free_pages(substream); -} - -static int txx9aclc_pcm_prepare(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct txx9aclc_dmadata *dmadata = runtime->private_data; - - dmadata->dma_addr = runtime->dma_addr; - dmadata->buffer_bytes = snd_pcm_lib_buffer_bytes(substream); - dmadata->period_bytes = snd_pcm_lib_period_bytes(substream); - - if (dmadata->buffer_bytes == dmadata->period_bytes) { - dmadata->frag_bytes = dmadata->period_bytes >> 1; - dmadata->frags = 2; - } else { - dmadata->frag_bytes = dmadata->period_bytes; - dmadata->frags = dmadata->buffer_bytes / dmadata->period_bytes; - } - dmadata->frag_count = 0; - dmadata->pos = 0; - return 0; -} - -static void txx9aclc_dma_complete(void *arg) -{ - struct txx9aclc_dmadata *dmadata = arg; - unsigned long flags; - - /* dma completion handler cannot submit new operations */ - spin_lock_irqsave(&dmadata->dma_lock, flags); - if (dmadata->frag_count >= 0) { - dmadata->dmacount--; - BUG_ON(dmadata->dmacount < 0); - tasklet_schedule(&dmadata->tasklet); - } - spin_unlock_irqrestore(&dmadata->dma_lock, flags); -} - -static struct dma_async_tx_descriptor * -txx9aclc_dma_submit(struct txx9aclc_dmadata *dmadata, dma_addr_t buf_dma_addr) -{ - struct dma_chan *chan = dmadata->dma_chan; - struct dma_async_tx_descriptor *desc; - struct scatterlist sg; - - sg_init_table(&sg, 1); - sg_set_page(&sg, pfn_to_page(PFN_DOWN(buf_dma_addr)), - dmadata->frag_bytes, buf_dma_addr & (PAGE_SIZE - 1)); - sg_dma_address(&sg) = buf_dma_addr; - desc = chan->device->device_prep_slave_sg(chan, &sg, 1, - dmadata->substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - DMA_TO_DEVICE : DMA_FROM_DEVICE, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) { - dev_err(&chan->dev->device, "cannot prepare slave dma\n"); - return NULL; - } - desc->callback = txx9aclc_dma_complete; - desc->callback_param = dmadata; - desc->tx_submit(desc); - return desc; -} - -#define NR_DMA_CHAIN 2 - -static void txx9aclc_dma_tasklet(unsigned long data) -{ - struct txx9aclc_dmadata *dmadata = (struct txx9aclc_dmadata *)data; - struct dma_chan *chan = dmadata->dma_chan; - struct dma_async_tx_descriptor *desc; - struct snd_pcm_substream *substream = dmadata->substream; - u32 ctlbit = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - ACCTL_AUDODMA : ACCTL_AUDIDMA; - int i; - unsigned long flags; - - spin_lock_irqsave(&dmadata->dma_lock, flags); - if (dmadata->frag_count < 0) { - struct txx9aclc_soc_device *dev = - container_of(dmadata, struct txx9aclc_soc_device, - dmadata[substream->stream]); - struct txx9aclc_plat_drvdata *drvdata = - txx9aclc_get_plat_drvdata(dev); - void __iomem *base = drvdata->base; - - spin_unlock_irqrestore(&dmadata->dma_lock, flags); - chan->device->device_terminate_all(chan); - /* first time */ - for (i = 0; i < NR_DMA_CHAIN; i++) { - desc = txx9aclc_dma_submit(dmadata, - dmadata->dma_addr + i * dmadata->frag_bytes); - if (!desc) - return; - } - dmadata->dmacount = NR_DMA_CHAIN; - chan->device->device_issue_pending(chan); - spin_lock_irqsave(&dmadata->dma_lock, flags); - __raw_writel(ctlbit, base + ACCTLEN); - dmadata->frag_count = NR_DMA_CHAIN % dmadata->frags; - spin_unlock_irqrestore(&dmadata->dma_lock, flags); - return; - } - BUG_ON(dmadata->dmacount >= NR_DMA_CHAIN); - while (dmadata->dmacount < NR_DMA_CHAIN) { - dmadata->dmacount++; - spin_unlock_irqrestore(&dmadata->dma_lock, flags); - desc = txx9aclc_dma_submit(dmadata, - dmadata->dma_addr + - dmadata->frag_count * dmadata->frag_bytes); - if (!desc) - return; - chan->device->device_issue_pending(chan); - - spin_lock_irqsave(&dmadata->dma_lock, flags); - dmadata->frag_count++; - dmadata->frag_count %= dmadata->frags; - dmadata->pos += dmadata->frag_bytes; - dmadata->pos %= dmadata->buffer_bytes; - if ((dmadata->frag_count * dmadata->frag_bytes) % - dmadata->period_bytes == 0) - snd_pcm_period_elapsed(substream); - } - spin_unlock_irqrestore(&dmadata->dma_lock, flags); -} - -static int txx9aclc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct txx9aclc_dmadata *dmadata = substream->runtime->private_data; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct txx9aclc_soc_device *dev = - container_of(rtd->socdev, struct txx9aclc_soc_device, soc_dev); - struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev); - void __iomem *base = drvdata->base; - unsigned long flags; - int ret = 0; - u32 ctlbit = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - ACCTL_AUDODMA : ACCTL_AUDIDMA; - - spin_lock_irqsave(&dmadata->dma_lock, flags); - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - dmadata->frag_count = -1; - tasklet_schedule(&dmadata->tasklet); - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - case SNDRV_PCM_TRIGGER_SUSPEND: - __raw_writel(ctlbit, base + ACCTLDIS); - break; - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - case SNDRV_PCM_TRIGGER_RESUME: - __raw_writel(ctlbit, base + ACCTLEN); - break; - default: - ret = -EINVAL; - } - spin_unlock_irqrestore(&dmadata->dma_lock, flags); - return ret; -} - -static snd_pcm_uframes_t -txx9aclc_pcm_pointer(struct snd_pcm_substream *substream) -{ - struct txx9aclc_dmadata *dmadata = substream->runtime->private_data; - - return bytes_to_frames(substream->runtime, dmadata->pos); -} - -static int txx9aclc_pcm_open(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct txx9aclc_soc_device *dev = - container_of(rtd->socdev, struct txx9aclc_soc_device, soc_dev); - struct txx9aclc_dmadata *dmadata = &dev->dmadata[substream->stream]; - int ret; - - ret = snd_soc_set_runtime_hwparams(substream, &txx9aclc_pcm_hardware); - if (ret) - return ret; - /* ensure that buffer size is a multiple of period size */ - ret = snd_pcm_hw_constraint_integer(substream->runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - if (ret < 0) - return ret; - substream->runtime->private_data = dmadata; - return 0; -} - -static int txx9aclc_pcm_close(struct snd_pcm_substream *substream) -{ - struct txx9aclc_dmadata *dmadata = substream->runtime->private_data; - struct dma_chan *chan = dmadata->dma_chan; - - dmadata->frag_count = -1; - chan->device->device_terminate_all(chan); - return 0; -} - -static struct snd_pcm_ops txx9aclc_pcm_ops = { - .open = txx9aclc_pcm_open, - .close = txx9aclc_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = txx9aclc_pcm_hw_params, - .hw_free = txx9aclc_pcm_hw_free, - .prepare = txx9aclc_pcm_prepare, - .trigger = txx9aclc_pcm_trigger, - .pointer = txx9aclc_pcm_pointer, -}; - -static void txx9aclc_pcm_free_dma_buffers(struct snd_pcm *pcm) -{ - snd_pcm_lib_preallocate_free_for_all(pcm); -} - -static int txx9aclc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, - struct snd_pcm *pcm) -{ - return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - card->dev, 64 * 1024, 4 * 1024 * 1024); -} - -static bool filter(struct dma_chan *chan, void *param) -{ - struct txx9aclc_dmadata *dmadata = param; - char devname[20 + 2]; /* FIXME: old BUS_ID_SIZE + 2 */ - - snprintf(devname, sizeof(devname), "%s.%d", dmadata->dma_res->name, - (int)dmadata->dma_res->start); - if (strcmp(dev_name(chan->device->dev), devname) == 0) { - chan->private = &dmadata->dma_slave; - return true; - } - return false; -} - -static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev, - struct txx9aclc_dmadata *dmadata) -{ - struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev); - struct txx9dmac_slave *ds = &dmadata->dma_slave; - dma_cap_mask_t mask; - - spin_lock_init(&dmadata->dma_lock); - - ds->reg_width = sizeof(u32); - if (dmadata->stream == SNDRV_PCM_STREAM_PLAYBACK) { - ds->tx_reg = drvdata->physbase + ACAUDODAT; - ds->rx_reg = 0; - } else { - ds->tx_reg = 0; - ds->rx_reg = drvdata->physbase + ACAUDIDAT; - } - - /* Try to grab a DMA channel */ - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - dmadata->dma_chan = dma_request_channel(mask, filter, dmadata); - if (!dmadata->dma_chan) { - dev_err(dev->soc_dev.dev, - "DMA channel for %s is not available\n", - dmadata->stream == SNDRV_PCM_STREAM_PLAYBACK ? - "playback" : "capture"); - return -EBUSY; - } - tasklet_init(&dmadata->tasklet, txx9aclc_dma_tasklet, - (unsigned long)dmadata); - return 0; -} - -static int txx9aclc_pcm_probe(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct txx9aclc_soc_device *dev = - container_of(socdev, struct txx9aclc_soc_device, soc_dev); - struct resource *r; - int i; - int ret; - - dev->dmadata[0].stream = SNDRV_PCM_STREAM_PLAYBACK; - dev->dmadata[1].stream = SNDRV_PCM_STREAM_CAPTURE; - for (i = 0; i < 2; i++) { - r = platform_get_resource(dev->aclc_pdev, IORESOURCE_DMA, i); - if (!r) { - ret = -EBUSY; - goto exit; - } - dev->dmadata[i].dma_res = r; - ret = txx9aclc_dma_init(dev, &dev->dmadata[i]); - if (ret) - goto exit; - } - return 0; - -exit: - for (i = 0; i < 2; i++) { - if (dev->dmadata[i].dma_chan) - dma_release_channel(dev->dmadata[i].dma_chan); - dev->dmadata[i].dma_chan = NULL; - } - return ret; -} - -static int txx9aclc_pcm_remove(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct txx9aclc_soc_device *dev = - container_of(socdev, struct txx9aclc_soc_device, soc_dev); - struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev); - void __iomem *base = drvdata->base; - int i; - - /* disable all FIFO DMAs */ - __raw_writel(ACCTL_AUDODMA | ACCTL_AUDIDMA, base + ACCTLDIS); - /* dummy R/W to clear pending DMAREQ if any */ - __raw_writel(__raw_readl(base + ACAUDIDAT), base + ACAUDODAT); - - for (i = 0; i < 2; i++) { - struct txx9aclc_dmadata *dmadata = &dev->dmadata[i]; - struct dma_chan *chan = dmadata->dma_chan; - if (chan) { - dmadata->frag_count = -1; - chan->device->device_terminate_all(chan); - dma_release_channel(chan); - } - dev->dmadata[i].dma_chan = NULL; - } - return 0; -} - -struct snd_soc_platform txx9aclc_soc_platform = { - .name = "txx9aclc-audio", - .probe = txx9aclc_pcm_probe, - .remove = txx9aclc_pcm_remove, - .pcm_ops = &txx9aclc_pcm_ops, - .pcm_new = txx9aclc_pcm_new, - .pcm_free = txx9aclc_pcm_free_dma_buffers, -}; -EXPORT_SYMBOL_GPL(txx9aclc_soc_platform); - -static int __init txx9aclc_soc_platform_init(void) -{ - return snd_soc_register_platform(&txx9aclc_soc_platform); -} - -static void __exit txx9aclc_soc_platform_exit(void) -{ - snd_soc_unregister_platform(&txx9aclc_soc_platform); -} - -module_init(txx9aclc_soc_platform_init); -module_exit(txx9aclc_soc_platform_exit); - -MODULE_AUTHOR("Atsushi Nemoto "); -MODULE_DESCRIPTION("TXx9 ACLC Audio DMA driver"); -MODULE_LICENSE("GPL"); diff --git a/trunk/sound/soc/txx9/txx9aclc.h b/trunk/sound/soc/txx9/txx9aclc.h deleted file mode 100644 index 6769aab41b33..000000000000 --- a/trunk/sound/soc/txx9/txx9aclc.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * TXx9 SoC AC Link Controller - * - * 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. - */ - -#ifndef __TXX9ACLC_H -#define __TXX9ACLC_H - -#include -#include - -#define ACCTLEN 0x00 /* control enable */ -#define ACCTLDIS 0x04 /* control disable */ -#define ACCTL_ENLINK 0x00000001 /* enable/disable AC-link */ -#define ACCTL_AUDODMA 0x00000100 /* AUDODMA enable/disable */ -#define ACCTL_AUDIDMA 0x00001000 /* AUDIDMA enable/disable */ -#define ACCTL_AUDOEHLT 0x00010000 /* AUDO error halt - enable/disable */ -#define ACCTL_AUDIEHLT 0x00100000 /* AUDI error halt - enable/disable */ -#define ACREGACC 0x08 /* codec register access */ -#define ACREGACC_DAT_SHIFT 0 /* data field */ -#define ACREGACC_REG_SHIFT 16 /* address field */ -#define ACREGACC_CODECID_SHIFT 24 /* CODEC ID field */ -#define ACREGACC_READ 0x80000000 /* CODEC read */ -#define ACREGACC_WRITE 0x00000000 /* CODEC write */ -#define ACINTSTS 0x10 /* interrupt status */ -#define ACINTMSTS 0x14 /* interrupt masked status */ -#define ACINTEN 0x18 /* interrupt enable */ -#define ACINTDIS 0x1c /* interrupt disable */ -#define ACINT_CODECRDY(n) (0x00000001 << (n)) /* CODECn ready */ -#define ACINT_REGACCRDY 0x00000010 /* ACREGACC ready */ -#define ACINT_AUDOERR 0x00000100 /* AUDO underrun error */ -#define ACINT_AUDIERR 0x00001000 /* AUDI overrun error */ -#define ACDMASTS 0x80 /* DMA request status */ -#define ACDMA_AUDO 0x00000001 /* AUDODMA pending */ -#define ACDMA_AUDI 0x00000010 /* AUDIDMA pending */ -#define ACAUDODAT 0xa0 /* audio out data */ -#define ACAUDIDAT 0xb0 /* audio in data */ -#define ACREVID 0xfc /* revision ID */ - -struct txx9aclc_dmadata { - struct resource *dma_res; - struct txx9dmac_slave dma_slave; - struct dma_chan *dma_chan; - struct tasklet_struct tasklet; - spinlock_t dma_lock; - int stream; /* SNDRV_PCM_STREAM_PLAYBACK or SNDRV_PCM_STREAM_CAPTURE */ - struct snd_pcm_substream *substream; - unsigned long pos; - dma_addr_t dma_addr; - unsigned long buffer_bytes; - unsigned long period_bytes; - unsigned long frag_bytes; - int frags; - int frag_count; - int dmacount; -}; - -struct txx9aclc_plat_drvdata { - void __iomem *base; - u64 physbase; -}; - -struct txx9aclc_soc_device { - struct snd_soc_device soc_dev; - struct platform_device *aclc_pdev; /* for ioresources, drvdata */ - struct txx9aclc_dmadata dmadata[2]; -}; - -static inline struct txx9aclc_plat_drvdata *txx9aclc_get_plat_drvdata( - struct txx9aclc_soc_device *sdev) -{ - return platform_get_drvdata(sdev->aclc_pdev); -} - -extern struct snd_soc_platform txx9aclc_soc_platform; -extern struct snd_soc_dai txx9aclc_ac97_dai; - -#endif /* __TXX9ACLC_H */ diff --git a/trunk/sound/synth/Makefile b/trunk/sound/synth/Makefile index 11eb06ac2eca..e99fd76caa17 100644 --- a/trunk/sound/synth/Makefile +++ b/trunk/sound/synth/Makefile @@ -5,8 +5,16 @@ snd-util-mem-objs := util_mem.o +# +# this function returns: +# "m" - CONFIG_SND_SEQUENCER is m +# - CONFIG_SND_SEQUENCER is undefined +# otherwise parameter #1 value +# +sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) + # Toplevel Module Dependency obj-$(CONFIG_SND_EMU10K1) += snd-util-mem.o obj-$(CONFIG_SND_TRIDENT) += snd-util-mem.o -obj-$(CONFIG_SND_SBAWE_SEQ) += snd-util-mem.o -obj-$(CONFIG_SND_SEQUENCER) += emux/ +obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-util-mem.o +obj-$(call sequencer,$(CONFIG_SND)) += emux/ diff --git a/trunk/sound/synth/emux/Makefile b/trunk/sound/synth/emux/Makefile index 328594e6152d..b69035240cf6 100644 --- a/trunk/sound/synth/emux/Makefile +++ b/trunk/sound/synth/emux/Makefile @@ -7,6 +7,14 @@ snd-emux-synth-objs := emux.o emux_synth.o emux_seq.o emux_nrpn.o \ emux_effect.o emux_proc.o emux_hwdep.o soundfont.o \ $(if $(CONFIG_SND_SEQUENCER_OSS),emux_oss.o) +# +# this function returns: +# "m" - CONFIG_SND_SEQUENCER is m +# - CONFIG_SND_SEQUENCER is undefined +# otherwise parameter #1 value +# +sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) + # Toplevel Module Dependencies -obj-$(CONFIG_SND_SBAWE_SEQ) += snd-emux-synth.o -obj-$(CONFIG_SND_EMU10K1_SEQ) += snd-emux-synth.o +obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-emux-synth.o +obj-$(call sequencer,$(CONFIG_SND_EMU10K1)) += snd-emux-synth.o diff --git a/trunk/sound/usb/caiaq/audio.c b/trunk/sound/usb/caiaq/audio.c index 8f9b60c5d74c..b13ce767ac72 100644 --- a/trunk/sound/usb/caiaq/audio.c +++ b/trunk/sound/usb/caiaq/audio.c @@ -42,10 +42,10 @@ (stream << 1) | (~(i / (dev->n_streams * BYTES_PER_SAMPLE_USB)) & 1) static struct snd_pcm_hardware snd_usb_caiaq_pcm_hardware = { - .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER), .formats = SNDRV_PCM_FMTBIT_S24_3BE, - .rates = (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + .rates = (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000), .rate_min = 44100, .rate_max = 0, /* will overwrite later */ @@ -68,7 +68,7 @@ activate_substream(struct snd_usb_caiaqdev *dev, dev->sub_capture[sub->number] = sub; } -static void +static void deactivate_substream(struct snd_usb_caiaqdev *dev, struct snd_pcm_substream *sub) { @@ -118,7 +118,7 @@ static int stream_start(struct snd_usb_caiaqdev *dev) return -EPIPE; } } - + return 0; } @@ -129,7 +129,7 @@ static void stream_stop(struct snd_usb_caiaqdev *dev) debug("%s(%p)\n", __func__, dev); if (!dev->streaming) return; - + dev->streaming = 0; for (i = 0; i < N_URBS; i++) { @@ -154,7 +154,7 @@ static int snd_usb_caiaq_substream_close(struct snd_pcm_substream *substream) debug("%s(%p)\n", __func__, substream); if (all_substreams_zero(dev->sub_playback) && all_substreams_zero(dev->sub_capture)) { - /* when the last client has stopped streaming, + /* when the last client has stopped streaming, * all sample rates are allowed again */ stream_stop(dev); dev->pcm_info.rates = dev->samplerates; @@ -194,31 +194,30 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; debug("%s(%p)\n", __func__, substream); - + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { dev->period_out_count[index] = BYTES_PER_SAMPLE + 1; dev->audio_out_buf_pos[index] = BYTES_PER_SAMPLE + 1; } else { - int in_pos = (dev->spec.data_alignment == 2) ? 0 : 2; - dev->period_in_count[index] = BYTES_PER_SAMPLE + in_pos; - dev->audio_in_buf_pos[index] = BYTES_PER_SAMPLE + in_pos; + dev->period_in_count[index] = BYTES_PER_SAMPLE; + dev->audio_in_buf_pos[index] = BYTES_PER_SAMPLE; } if (dev->streaming) return 0; - + /* the first client that opens a stream defines the sample rate * setting for all subsequent calls, until the last client closed. */ for (i=0; i < ARRAY_SIZE(rates); i++) if (runtime->rate == rates[i]) dev->pcm_info.rates = 1 << i; - + snd_pcm_limit_hw_rates(runtime); bytes_per_sample = BYTES_PER_SAMPLE; if (dev->spec.data_alignment == 2) bytes_per_sample++; - + bpp = ((runtime->rate / 8000) + CLOCK_DRIFT_TOLERANCE) * bytes_per_sample * CHANNELS_PER_STREAM * dev->n_streams; @@ -233,7 +232,7 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) ret = stream_start(dev); if (ret) return ret; - + dev->output_running = 0; wait_event_timeout(dev->prepare_wait_queue, dev->output_running, HZ); if (!dev->output_running) { @@ -274,7 +273,7 @@ snd_usb_caiaq_pcm_pointer(struct snd_pcm_substream *sub) return SNDRV_PCM_POS_XRUN; if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK) - return bytes_to_frames(sub->runtime, + return bytes_to_frames(sub->runtime, dev->audio_out_buf_pos[index]); else return bytes_to_frames(sub->runtime, @@ -292,7 +291,7 @@ static struct snd_pcm_ops snd_usb_caiaq_ops = { .trigger = snd_usb_caiaq_pcm_trigger, .pointer = snd_usb_caiaq_pcm_pointer }; - + static void check_for_elapsed_periods(struct snd_usb_caiaqdev *dev, struct snd_pcm_substream **subs) { @@ -334,7 +333,7 @@ static void read_in_urb_mode0(struct snd_usb_caiaqdev *dev, struct snd_pcm_runtime *rt = sub->runtime; char *audio_buf = rt->dma_area; int sz = frames_to_bytes(rt, rt->buffer_size); - audio_buf[dev->audio_in_buf_pos[stream]++] + audio_buf[dev->audio_in_buf_pos[stream]++] = usb_buf[i]; dev->period_in_count[stream]++; if (dev->audio_in_buf_pos[stream] == sz) @@ -355,14 +354,14 @@ static void read_in_urb_mode2(struct snd_usb_caiaqdev *dev, for (i = 0; i < iso->actual_length;) { if (i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == 0) { - for (stream = 0; - stream < dev->n_streams; + for (stream = 0; + stream < dev->n_streams; stream++, i++) { if (dev->first_packet) continue; check_byte = MAKE_CHECKBYTE(dev, stream, i); - + if ((usb_buf[i] & 0x3f) != check_byte) dev->input_panic = 1; @@ -411,21 +410,21 @@ static void read_in_urb(struct snd_usb_caiaqdev *dev, } if ((dev->input_panic || dev->output_panic) && !dev->warned) { - debug("streaming error detected %s %s\n", + debug("streaming error detected %s %s\n", dev->input_panic ? "(input)" : "", dev->output_panic ? "(output)" : ""); dev->warned = 1; } } -static void fill_out_urb(struct snd_usb_caiaqdev *dev, - struct urb *urb, +static void fill_out_urb(struct snd_usb_caiaqdev *dev, + struct urb *urb, const struct usb_iso_packet_descriptor *iso) { unsigned char *usb_buf = urb->transfer_buffer + iso->offset; struct snd_pcm_substream *sub; int stream, i; - + for (i = 0; i < iso->length;) { for (stream = 0; stream < dev->n_streams; stream++, i++) { sub = dev->sub_playback[stream]; @@ -445,7 +444,7 @@ static void fill_out_urb(struct snd_usb_caiaqdev *dev, /* fill in the check bytes */ if (dev->spec.data_alignment == 2 && - i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == + i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == (dev->n_streams * CHANNELS_PER_STREAM)) for (stream = 0; stream < dev->n_streams; stream++, i++) usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i); @@ -454,7 +453,7 @@ static void fill_out_urb(struct snd_usb_caiaqdev *dev, static void read_completed(struct urb *urb) { - struct snd_usb_caiaq_cb_info *info = urb->context; + struct snd_usb_caiaq_cb_info *info = urb->context; struct snd_usb_caiaqdev *dev; struct urb *out; int frame, len, send_it = 0, outframe = 0; @@ -479,7 +478,7 @@ static void read_completed(struct urb *urb) out->iso_frame_desc[outframe].length = len; out->iso_frame_desc[outframe].actual_length = 0; out->iso_frame_desc[outframe].offset = BYTES_PER_FRAME * frame; - + if (len > 0) { spin_lock(&dev->spinlock); fill_out_urb(dev, out, &out->iso_frame_desc[outframe]); @@ -498,14 +497,14 @@ static void read_completed(struct urb *urb) out->transfer_flags = URB_ISO_ASAP; usb_submit_urb(out, GFP_ATOMIC); } - + /* re-submit inbound urb */ for (frame = 0; frame < FRAMES_PER_URB; frame++) { urb->iso_frame_desc[frame].offset = BYTES_PER_FRAME * frame; urb->iso_frame_desc[frame].length = BYTES_PER_FRAME; urb->iso_frame_desc[frame].actual_length = 0; } - + urb->number_of_packets = FRAMES_PER_URB; urb->transfer_flags = URB_ISO_ASAP; usb_submit_urb(urb, GFP_ATOMIC); @@ -529,7 +528,7 @@ static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret) struct usb_device *usb_dev = dev->chip.dev; unsigned int pipe; - pipe = (dir == SNDRV_PCM_STREAM_PLAYBACK) ? + pipe = (dir == SNDRV_PCM_STREAM_PLAYBACK) ? usb_sndisocpipe(usb_dev, ENDPOINT_PLAYBACK) : usb_rcvisocpipe(usb_dev, ENDPOINT_CAPTURE); @@ -548,25 +547,25 @@ static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret) return urbs; } - urbs[i]->transfer_buffer = + urbs[i]->transfer_buffer = kmalloc(FRAMES_PER_URB * BYTES_PER_FRAME, GFP_KERNEL); if (!urbs[i]->transfer_buffer) { log("unable to kmalloc() transfer buffer, OOM!?\n"); *ret = -ENOMEM; return urbs; } - + for (frame = 0; frame < FRAMES_PER_URB; frame++) { - struct usb_iso_packet_descriptor *iso = + struct usb_iso_packet_descriptor *iso = &urbs[i]->iso_frame_desc[frame]; - + iso->offset = BYTES_PER_FRAME * frame; iso->length = BYTES_PER_FRAME; } - + urbs[i]->dev = usb_dev; urbs[i]->pipe = pipe; - urbs[i]->transfer_buffer_length = FRAMES_PER_URB + urbs[i]->transfer_buffer_length = FRAMES_PER_URB * BYTES_PER_FRAME; urbs[i]->context = &dev->data_cb_info[i]; urbs[i]->interval = 1; @@ -590,7 +589,7 @@ static void free_urbs(struct urb **urbs) for (i = 0; i < N_URBS; i++) { if (!urbs[i]) continue; - + usb_kill_urb(urbs[i]); kfree(urbs[i]->transfer_buffer); usb_free_urb(urbs[i]); @@ -603,11 +602,11 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) { int i, ret; - dev->n_audio_in = max(dev->spec.num_analog_audio_in, - dev->spec.num_digital_audio_in) / + dev->n_audio_in = max(dev->spec.num_analog_audio_in, + dev->spec.num_digital_audio_in) / CHANNELS_PER_STREAM; dev->n_audio_out = max(dev->spec.num_analog_audio_out, - dev->spec.num_digital_audio_out) / + dev->spec.num_digital_audio_out) / CHANNELS_PER_STREAM; dev->n_streams = max(dev->n_audio_in, dev->n_audio_out); @@ -620,7 +619,7 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) return -EINVAL; } - ret = snd_pcm_new(dev->chip.card, dev->product_name, 0, + ret = snd_pcm_new(dev->chip.card, dev->product_name, 0, dev->n_audio_out, dev->n_audio_in, &dev->pcm); if (ret < 0) { @@ -633,7 +632,7 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) memset(dev->sub_playback, 0, sizeof(dev->sub_playback)); memset(dev->sub_capture, 0, sizeof(dev->sub_capture)); - + memcpy(&dev->pcm_info, &snd_usb_caiaq_pcm_hardware, sizeof(snd_usb_caiaq_pcm_hardware)); @@ -652,9 +651,9 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) break; } - snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, + snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usb_caiaq_ops); - snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, + snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usb_caiaq_ops); snd_pcm_lib_preallocate_pages_for_all(dev->pcm, @@ -663,7 +662,7 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) MAX_BUFFER_SIZE, MAX_BUFFER_SIZE); dev->data_cb_info = - kmalloc(sizeof(struct snd_usb_caiaq_cb_info) * N_URBS, + kmalloc(sizeof(struct snd_usb_caiaq_cb_info) * N_URBS, GFP_KERNEL); if (!dev->data_cb_info) @@ -673,14 +672,14 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) dev->data_cb_info[i].dev = dev; dev->data_cb_info[i].index = i; } - + dev->data_urbs_in = alloc_urbs(dev, SNDRV_PCM_STREAM_CAPTURE, &ret); if (ret < 0) { kfree(dev->data_cb_info); free_urbs(dev->data_urbs_in); return ret; } - + dev->data_urbs_out = alloc_urbs(dev, SNDRV_PCM_STREAM_PLAYBACK, &ret); if (ret < 0) { kfree(dev->data_cb_info); diff --git a/trunk/sound/usb/caiaq/device.c b/trunk/sound/usb/caiaq/device.c index 0e5db719de24..515de1cd2a3e 100644 --- a/trunk/sound/usb/caiaq/device.c +++ b/trunk/sound/usb/caiaq/device.c @@ -35,7 +35,7 @@ #include "input.h" MODULE_AUTHOR("Daniel Mack "); -MODULE_DESCRIPTION("caiaq USB audio, version 1.3.17"); +MODULE_DESCRIPTION("caiaq USB audio, version 1.3.14"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," "{Native Instruments, RigKontrol3}," @@ -79,7 +79,7 @@ static struct usb_device_id snd_usb_id_table[] = { { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = USB_VID_NATIVEINSTRUMENTS, - .idProduct = USB_PID_RIGKONTROL2 + .idProduct = USB_PID_RIGKONTROL2 }, { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, @@ -197,7 +197,7 @@ int snd_usb_caiaq_send_command(struct snd_usb_caiaqdev *dev, if (buffer && len > 0) memcpy(dev->ep1_out_buf+1, buffer, len); - + dev->ep1_out_buf[0] = command; return usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, 1), dev->ep1_out_buf, len+1, &actual_len, 200); @@ -208,7 +208,7 @@ int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev, { int ret; char tmp[5]; - + switch (rate) { case 44100: tmp[0] = SAMPLERATE_44100; break; case 48000: tmp[0] = SAMPLERATE_48000; break; @@ -237,12 +237,12 @@ int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev, if (ret) return ret; - - if (!wait_event_timeout(dev->ep1_wait_queue, + + if (!wait_event_timeout(dev->ep1_wait_queue, dev->audio_parm_answer >= 0, HZ)) return -EPIPE; - - if (dev->audio_parm_answer != 1) + + if (dev->audio_parm_answer != 1) debug("unable to set the device's audio params\n"); else dev->bpp = bpp; @@ -250,8 +250,8 @@ int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev, return dev->audio_parm_answer == 1 ? 0 : -EINVAL; } -int snd_usb_caiaq_set_auto_msg(struct snd_usb_caiaqdev *dev, - int digital, int analog, int erp) +int snd_usb_caiaq_set_auto_msg (struct snd_usb_caiaqdev *dev, + int digital, int analog, int erp) { char tmp[3] = { digital, analog, erp }; return snd_usb_caiaq_send_command(dev, EP1_CMD_AUTO_MSG, @@ -262,7 +262,7 @@ static void __devinit setup_card(struct snd_usb_caiaqdev *dev) { int ret; char val[4]; - + /* device-specific startup specials */ switch (dev->chip.usb_id) { case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): @@ -314,7 +314,7 @@ static void __devinit setup_card(struct snd_usb_caiaqdev *dev) dev->control_state, 1); break; } - + if (dev->spec.num_analog_audio_out + dev->spec.num_analog_audio_in + dev->spec.num_digital_audio_out + @@ -323,7 +323,7 @@ static void __devinit setup_card(struct snd_usb_caiaqdev *dev) if (ret < 0) log("Unable to set up audio system (ret=%d)\n", ret); } - + if (dev->spec.num_midi_in + dev->spec.num_midi_out > 0) { ret = snd_usb_caiaq_midi_init(dev); @@ -363,7 +363,7 @@ static int create_card(struct usb_device* usb_dev, struct snd_card **cardp) if (devnum >= SNDRV_CARDS) return -ENODEV; - err = snd_card_create(index[devnum], id[devnum], THIS_MODULE, + err = snd_card_create(index[devnum], id[devnum], THIS_MODULE, sizeof(struct snd_usb_caiaqdev), &card); if (err < 0) return err; @@ -382,11 +382,11 @@ static int create_card(struct usb_device* usb_dev, struct snd_card **cardp) static int __devinit init_card(struct snd_usb_caiaqdev *dev) { - char *c, usbpath[32]; + char *c; struct usb_device *usb_dev = dev->chip.dev; struct snd_card *card = dev->chip.card; int err, len; - + if (usb_set_interface(usb_dev, 0, 1) != 0) { log("can't set alt interface.\n"); return -EIO; @@ -395,19 +395,19 @@ static int __devinit init_card(struct snd_usb_caiaqdev *dev) usb_init_urb(&dev->ep1_in_urb); usb_init_urb(&dev->midi_out_urb); - usb_fill_bulk_urb(&dev->ep1_in_urb, usb_dev, + usb_fill_bulk_urb(&dev->ep1_in_urb, usb_dev, usb_rcvbulkpipe(usb_dev, 0x1), - dev->ep1_in_buf, EP1_BUFSIZE, + dev->ep1_in_buf, EP1_BUFSIZE, usb_ep1_command_reply_dispatch, dev); - usb_fill_bulk_urb(&dev->midi_out_urb, usb_dev, + usb_fill_bulk_urb(&dev->midi_out_urb, usb_dev, usb_sndbulkpipe(usb_dev, 0x1), - dev->midi_out_buf, EP1_BUFSIZE, + dev->midi_out_buf, EP1_BUFSIZE, snd_usb_caiaq_midi_output_done, dev); - + init_waitqueue_head(&dev->ep1_wait_queue); init_waitqueue_head(&dev->prepare_wait_queue); - + if (usb_submit_urb(&dev->ep1_in_urb, GFP_KERNEL) != 0) return -EIO; @@ -420,52 +420,47 @@ static int __devinit init_card(struct snd_usb_caiaqdev *dev) usb_string(usb_dev, usb_dev->descriptor.iManufacturer, dev->vendor_name, CAIAQ_USB_STR_LEN); - + usb_string(usb_dev, usb_dev->descriptor.iProduct, dev->product_name, CAIAQ_USB_STR_LEN); - - strlcpy(card->driver, MODNAME, sizeof(card->driver)); - strlcpy(card->shortname, dev->product_name, sizeof(card->shortname)); - strlcpy(card->mixername, dev->product_name, sizeof(card->mixername)); - - /* if the id was not passed as module option, fill it with a shortened - * version of the product string which does not contain any - * whitespaces */ - - if (*card->id == '\0') { - char id[sizeof(card->id)]; - - memset(id, 0, sizeof(id)); - - for (c = card->shortname, len = 0; - *c && len < sizeof(card->id); c++) - if (*c != ' ') - id[len++] = *c; - - snd_card_set_id(card, id); - } - - usb_make_path(usb_dev, usbpath, sizeof(usbpath)); - snprintf(card->longname, sizeof(card->longname), - "%s %s (%s)", - dev->vendor_name, dev->product_name, usbpath); - + + usb_string(usb_dev, usb_dev->descriptor.iSerialNumber, + dev->serial, CAIAQ_USB_STR_LEN); + + /* terminate serial string at first white space occurence */ + c = strchr(dev->serial, ' '); + if (c) + *c = '\0'; + + strcpy(card->driver, MODNAME); + strcpy(card->shortname, dev->product_name); + + len = snprintf(card->longname, sizeof(card->longname), + "%s %s (serial %s, ", + dev->vendor_name, dev->product_name, dev->serial); + + if (len < sizeof(card->longname) - 2) + len += usb_make_path(usb_dev, card->longname + len, + sizeof(card->longname) - len); + + card->longname[len++] = ')'; + card->longname[len] = '\0'; setup_card(dev); return 0; } -static int __devinit snd_probe(struct usb_interface *intf, +static int __devinit snd_probe(struct usb_interface *intf, const struct usb_device_id *id) { int ret; struct snd_card *card; struct usb_device *device = interface_to_usbdev(intf); - + ret = create_card(device, &card); - + if (ret < 0) return ret; - + usb_set_intfdata(intf, card); ret = init_card(caiaqdev(card)); if (ret < 0) { @@ -473,7 +468,7 @@ static int __devinit snd_probe(struct usb_interface *intf, snd_card_free(card); return ret; } - + return 0; } @@ -494,10 +489,10 @@ static void snd_disconnect(struct usb_interface *intf) snd_usb_caiaq_input_free(dev); #endif snd_usb_caiaq_audio_free(dev); - + usb_kill_urb(&dev->ep1_in_urb); usb_kill_urb(&dev->midi_out_urb); - + snd_card_free(card); usb_reset_device(interface_to_usbdev(intf)); } diff --git a/trunk/sound/usb/caiaq/device.h b/trunk/sound/usb/caiaq/device.h index ece73514854e..4cce1ad7493d 100644 --- a/trunk/sound/usb/caiaq/device.h +++ b/trunk/sound/usb/caiaq/device.h @@ -81,6 +81,7 @@ struct snd_usb_caiaqdev { char vendor_name[CAIAQ_USB_STR_LEN]; char product_name[CAIAQ_USB_STR_LEN]; + char serial[CAIAQ_USB_STR_LEN]; int n_streams, n_audio_in, n_audio_out; int streaming, first_packet, output_running; diff --git a/trunk/sound/usb/caiaq/midi.c b/trunk/sound/usb/caiaq/midi.c index 538e8c00d31a..8fa8cd88d763 100644 --- a/trunk/sound/usb/caiaq/midi.c +++ b/trunk/sound/usb/caiaq/midi.c @@ -40,7 +40,7 @@ static void snd_usb_caiaq_midi_input_trigger(struct snd_rawmidi_substream *subst if (!dev) return; - + dev->midi_receive_substream = up ? substream : NULL; } @@ -64,18 +64,18 @@ static void snd_usb_caiaq_midi_send(struct snd_usb_caiaqdev *dev, struct snd_rawmidi_substream *substream) { int len, ret; - + dev->midi_out_buf[0] = EP1_CMD_MIDI_WRITE; dev->midi_out_buf[1] = 0; /* port */ len = snd_rawmidi_transmit(substream, dev->midi_out_buf + 3, EP1_BUFSIZE - 3); - + if (len <= 0) return; - + dev->midi_out_buf[2] = len; dev->midi_out_urb.transfer_buffer_length = len+3; - + ret = usb_submit_urb(&dev->midi_out_urb, GFP_ATOMIC); if (ret < 0) log("snd_usb_caiaq_midi_send(%p): usb_submit_urb() failed," @@ -88,7 +88,7 @@ static void snd_usb_caiaq_midi_send(struct snd_usb_caiaqdev *dev, static void snd_usb_caiaq_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) { struct snd_usb_caiaqdev *dev = substream->rmidi->private_data; - + if (up) { dev->midi_out_substream = substream; if (!dev->midi_out_active) @@ -113,12 +113,12 @@ static struct snd_rawmidi_ops snd_usb_caiaq_midi_input = .trigger = snd_usb_caiaq_midi_input_trigger, }; -void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *dev, +void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *dev, int port, const char *buf, int len) { if (!dev->midi_receive_substream) return; - + snd_rawmidi_receive(dev->midi_receive_substream, buf, len); } @@ -142,16 +142,16 @@ int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device) if (device->spec.num_midi_out > 0) { rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT; - snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_usb_caiaq_midi_output); } if (device->spec.num_midi_in > 0) { rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; - snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_usb_caiaq_midi_input); } - + device->rmidi = rmidi; return 0; @@ -160,7 +160,7 @@ int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device) void snd_usb_caiaq_midi_output_done(struct urb* urb) { struct snd_usb_caiaqdev *dev = urb->context; - + dev->midi_out_active = 0; if (urb->status != 0) return; diff --git a/trunk/sound/usb/usbaudio.c b/trunk/sound/usb/usbaudio.c index c7b902358b7b..a6b88482637b 100644 --- a/trunk/sound/usb/usbaudio.c +++ b/trunk/sound/usb/usbaudio.c @@ -627,7 +627,6 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, subs->hwptr_done += offs; if (subs->hwptr_done >= runtime->buffer_size) subs->hwptr_done -= runtime->buffer_size; - runtime->delay += offs; spin_unlock_irqrestore(&subs->lock, flags); urb->transfer_buffer_length = offs * stride; if (period_elapsed) @@ -637,22 +636,12 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, /* * process after playback data complete - * - decrease the delay count again + * - nothing to do */ static int retire_playback_urb(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *urb) { - unsigned long flags; - int stride = runtime->frame_bits >> 3; - int processed = urb->transfer_buffer_length / stride; - - spin_lock_irqsave(&subs->lock, flags); - if (processed > runtime->delay) - runtime->delay = 0; - else - runtime->delay -= processed; - spin_unlock_irqrestore(&subs->lock, flags); return 0; } @@ -1531,7 +1520,6 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) subs->hwptr_done = 0; subs->transfer_done = 0; subs->phase = 0; - runtime->delay = 0; /* clear urbs (to be sure) */ deactivate_urbs(subs, 0, 1); @@ -3291,25 +3279,6 @@ static int snd_usb_cm106_boot_quirk(struct usb_device *dev) return snd_usb_cm106_write_int_reg(dev, 2, 0x8004); } -/* - * C-Media CM6206 is based on CM106 with two additional - * registers that are not documented in the data sheet. - * Values here are chosen based on sniffing USB traffic - * under Windows. - */ -static int snd_usb_cm6206_boot_quirk(struct usb_device *dev) -{ - int err, reg; - int val[] = {0x200c, 0x3000, 0xf800, 0x143f, 0x0000, 0x3000}; - - for (reg = 0; reg < ARRAY_SIZE(val); reg++) { - err = snd_usb_cm106_write_int_reg(dev, reg, val[reg]); - if (err < 0) - return err; - } - - return err; -} /* * Setup quirks @@ -3596,12 +3565,6 @@ static void *snd_usb_audio_probe(struct usb_device *dev, goto __err_val; } - /* C-Media CM6206 / CM106-Like Sound Device */ - if (id == USB_ID(0x0d8c, 0x0102)) { - if (snd_usb_cm6206_boot_quirk(dev) < 0) - goto __err_val; - } - /* * found a config. now register to ALSA */ diff --git a/trunk/sound/usb/usbquirks.h b/trunk/sound/usb/usbquirks.h index f6f201eb24ce..5d955aaad85f 100644 --- a/trunk/sound/usb/usbquirks.h +++ b/trunk/sound/usb/usbquirks.h @@ -1469,41 +1469,6 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, -{ - /* Edirol M-16DX */ - /* FIXME: This quirk gives a good-working capture stream but the - * playback seems problematic because of lacking of sync - * with capture stream. It needs to sync with the capture - * clock. As now, you'll get frequent sound distortions - * via the playback. - */ - USB_DEVICE(0x0582, 0x00c4), - .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_COMPOSITE, - .data = (const struct snd_usb_audio_quirk[]) { - { - .ifnum = 0, - .type = QUIRK_AUDIO_STANDARD_INTERFACE - }, - { - .ifnum = 1, - .type = QUIRK_AUDIO_STANDARD_INTERFACE - }, - { - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const struct snd_usb_midi_endpoint_info) { - .out_cables = 0x0001, - .in_cables = 0x0001 - } - }, - { - .ifnum = -1 - } - } - } -}, { /* BOSS GT-10 */ USB_DEVICE(0x0582, 0x00da), @@ -1985,14 +1950,6 @@ YAMAHA_DEVICE(0x7010, "UB99"), .type = QUIRK_MIDI_STANDARD_INTERFACE } }, -{ - USB_DEVICE(0x0ccd, 0x0028), - .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { - .vendor_name = "TerraTec", - .product_name = "Aureon5.1MkII", - .ifnum = QUIRK_NO_INTERFACE - } -}, { USB_DEVICE(0x0ccd, 0x0035), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {