diff options
363 files changed, 10796 insertions, 4216 deletions
diff --git a/Documentation/devicetree/bindings/sound/cs4270.txt b/Documentation/devicetree/bindings/sound/cs4270.txt new file mode 100644 index 00000000000..6b222f9b8ef --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cs4270.txt @@ -0,0 +1,21 @@ +CS4270 audio CODEC + +The driver for this device currently only supports I2C. + +Required properties: + +  - compatible : "cirrus,cs4270" + +  - reg : the I2C address of the device for I2C + +Optional properties: + +  - reset-gpio : a GPIO spec for the reset pin. If specified, it will be +		 deasserted before communication to the codec starts. + +Example: + +codec: cs4270@48 { +	compatible = "cirrus,cs4270"; +	reg = <0x48>; +}; diff --git a/Documentation/devicetree/bindings/sound/cs4271.txt b/Documentation/devicetree/bindings/sound/cs4271.txt new file mode 100644 index 00000000000..c81b5fd5a5b --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cs4271.txt @@ -0,0 +1,36 @@ +Cirrus Logic CS4271 DT bindings + +This driver supports both the I2C and the SPI bus. + +Required properties: + + - compatible: "cirrus,cs4271" + +For required properties on SPI, please consult +Documentation/devicetree/bindings/spi/spi-bus.txt + +Required properties on I2C: + + - reg: the i2c address + + +Optional properties: + + - reset-gpio: 	a GPIO spec to define which pin is connected to the chip's +		!RESET pin + +Examples: + +	codec_i2c: cs4271@10 { +		compatible = "cirrus,cs4271"; +		reg = <0x10>; +		reset-gpio = <&gpio 23 0>; +	}; + +	codec_spi: cs4271@0 { +		compatible = "cirrus,cs4271"; +		reg = <0x0>; +		reset-gpio = <&gpio 23 0>; +		spi-max-frequency = <6000000>; +	}; + diff --git a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt new file mode 100644 index 00000000000..374e145c2ef --- /dev/null +++ b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt @@ -0,0 +1,45 @@ +Texas Instruments McASP controller + +Required properties: +- compatible : +	"ti,dm646x-mcasp-audio"	: for DM646x platforms +	"ti,da830-mcasp-audio"	: for both DA830 & DA850 platforms +	"ti,omap2-mcasp-audio"	: for OMAP2 platforms (TI81xx, AM33xx) + +- reg : Should contain McASP registers offset and length +- interrupts : Interrupt number for McASP +- op-mode : I2S/DIT ops mode. +- tdm-slots : Slots for TDM operation. +- num-serializer : Serializers used by McASP. +- serial-dir : A list of serializer pin mode. The list number should be equal +		to "num-serializer" parameter. Each entry is a number indication +		serializer pin direction. (0 - INACTIVE, 1 - TX, 2 - RX) + + +Optional properties: + +- ti,hwmods : Must be "mcasp<n>", n is controller instance starting 0 +- tx-num-evt : FIFO levels. +- rx-num-evt : FIFO levels. +- sram-size-playback : size of sram to be allocated during playback +- sram-size-capture  : size of sram to be allocated during capture + +Example: + +mcasp0: mcasp0@1d00000 { +	compatible = "ti,da830-mcasp-audio"; +	#address-cells = <1>; +	#size-cells = <0>; +	reg = <0x100000 0x3000>; +	interrupts = <82 83>; +	op-mode = <0>;		/* MCASP_IIS_MODE */ +	tdm-slots = <2>; +	num-serializer = <16>; +	serial-dir = < +			0 0 0 0	/* 0: INACTIVE, 1: TX, 2: RX */ +			0 0 0 0 +			0 0 0 1 +			2 0 0 0 >; +	tx-num-evt = <1>; +	rx-num-evt = <1>; +}; diff --git a/Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt b/Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt new file mode 100644 index 00000000000..65dec876cb2 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt @@ -0,0 +1,91 @@ +* Texas Instruments OMAP4+ and twl6040 based audio setups + +Required properties: +- compatible: "ti,abe-twl6040" +- ti,model: Name of the sound card ( for example "SDP4430") +- ti,mclk-freq: MCLK frequency for HPPLL operation +- ti,mcpdm: phandle for the McPDM node +- ti,twl6040: phandle for the twl6040 core node +- ti,audio-routing: List of connections between audio components. +  Each entry is a pair of strings, the first being the connection's sink, +  the second being the connection's source. + +Optional properties: +- ti,dmic: phandle for the OMAP dmic node if the machine have it connected +- ti,jack_detection: Need to be set to <1> if the board capable to detect jack +  insertion, removal. + +Available audio endpoints for the audio-routing table: + +Board connectors: + * Headset Stereophone + * Earphone Spk + * Ext Spk + * Line Out + * Vibrator + * Headset Mic + * Main Handset Mic + * Sub Handset Mic + * Line In + * Digital Mic + +twl6040 pins: + * HSOL + * HSOR + * EP + * HFL + * HFR + * AUXL + * AUXR + * VIBRAL + * VIBRAR + * HSMIC + * MAINMIC + * SUBMIC + * AFML + * AFMR + + * Headset Mic Bias + * Main Mic Bias + * Digital Mic1 Bias + * Digital Mic2 Bias + +Digital mic pins: + * DMic + +Example: + +sound { +	compatible = "ti,abe-twl6040"; +	ti,model = "SDP4430"; + +	ti,jack-detection = <1>; +	ti,mclk-freq = <38400000>; + +	ti,mcpdm = <&mcpdm>; +	ti,dmic = <&dmic>; + +	ti,twl6040 = <&twl6040>; + +	/* Audio routing */ +	ti,audio-routing = +		"Headset Stereophone", "HSOL", +		"Headset Stereophone", "HSOR", +		"Earphone Spk", "EP", +		"Ext Spk", "HFL", +		"Ext Spk", "HFR", +		"Line Out", "AUXL", +		"Line Out", "AUXR", +		"Vibrator", "VIBRAL", +		"Vibrator", "VIBRAR", +		"HSMIC", "Headset Mic", +		"Headset Mic", "Headset Mic Bias", +		"MAINMIC", "Main Handset Mic", +		"Main Handset Mic", "Main Mic Bias", +		"SUBMIC", "Sub Handset Mic", +		"Sub Handset Mic", "Main Mic Bias", +		"AFML", "Line In", +		"AFMR", "Line In", +		"DMic", "Digital Mic", +		"Digital Mic", "Digital Mic1 Bias"; +}; diff --git a/Documentation/devicetree/bindings/sound/omap-mcbsp.txt b/Documentation/devicetree/bindings/sound/omap-mcbsp.txt new file mode 100644 index 00000000000..17cce449045 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/omap-mcbsp.txt @@ -0,0 +1,37 @@ +* Texas Instruments OMAP2+ McBSP module + +Required properties: +- compatible: "ti,omap2420-mcbsp" for McBSP on OMAP2420 +	      "ti,omap2430-mcbsp" for McBSP on OMAP2430 +	      "ti,omap3-mcbsp" for McBSP on OMAP3 +	      "ti,omap4-mcbsp" for McBSP on OMAP4 and newer SoC +- reg: Register location and size, for OMAP4+ as an array: +       <MPU access base address, size>, +       <L3 interconnect address, size>; +- reg-names: Array of strings associated with the address space +- interrupts: Interrupt numbers for the McBSP port, as an array in case the +	      McBSP IP have more interrupt lines: +	<OCP compliant irq>, +	<TX irq>, +	<RX irq>; +- interrupt-names: Array of strings associated with the interrupt numbers +- interrupt-parent: The parent interrupt controller +- ti,buffer-size: Size of the FIFO on the port (OMAP2430 and newer SoC) +- ti,hwmods: Name of the hwmod associated to the McBSP port + +Example: + +mcbsp2: mcbsp@49022000 { +	compatible = "ti,omap3-mcbsp"; +	reg = <0x49022000 0xff>, +	      <0x49028000 0xff>; +	reg-names = "mpu", "sidetone"; +	interrupts = <0 17 0x4>, /* OCP compliant interrupt */ +		     <0 62 0x4>, /* TX interrupt */ +		     <0 63 0x4>, /* RX interrupt */ +		     <0 4 0x4>;  /* Sidetone */ +	interrupt-names = "common", "tx", "rx", "sidetone"; +	interrupt-parent = <&intc>; +	ti,buffer-size = <1280>; +	ti,hwmods = "mcbsp2"; +}; diff --git a/Documentation/devicetree/bindings/sound/omap-twl4030.txt b/Documentation/devicetree/bindings/sound/omap-twl4030.txt new file mode 100644 index 00000000000..6fae51c7f76 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/omap-twl4030.txt @@ -0,0 +1,17 @@ +* Texas Instruments SoC with twl4030 based audio setups + +Required properties: +- compatible: "ti,omap-twl4030" +- ti,model: Name of the sound card (for example "omap3beagle") +- ti,mcbsp: phandle for the McBSP node +- ti,codec: phandle for the twl4030 audio node + +Example: + +sound { +	compatible = "ti,omap-twl4030"; +	ti,model = "omap3beagle"; + +	ti,mcbsp = <&mcbsp2>; +	ti,codec = <&twl_audio>; +}; diff --git a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt new file mode 100644 index 00000000000..e7b98f41fa5 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt @@ -0,0 +1,20 @@ +Texas Instruments - tlv320aic3x Codec module + +The tlv320aic3x serial control bus communicates through I2C protocols + +Required properties: +- compatible - "string" -  "ti,tlv320aic3x" +- reg - <int> -  I2C slave address + + +Optional properties: + +- gpio-reset - gpio pin number used for codec reset +- ai3x-gpio-func - <array of 2 int> - AIC3X_GPIO1 & AIC3X_GPIO2 Functionality + +Example: + +tlv320aic3x: tlv320aic3x@1b { +	compatible = "ti,tlv320aic3x"; +	reg = <0x1b>; +}; diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 4e4d0bc9816..d90d8ec2853 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -860,8 +860,14 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.      [Multiple options for each card instance]      model	- force the model name -    position_fix - Fix DMA pointer (0 = auto, 1 = use LPIB, 2 = POSBUF, -    		   3 = VIACOMBO, 4 = COMBO) +    position_fix - Fix DMA pointer +		  -1 = system default: choose appropriate one per controller +			hardware +		  0 = auto: falls back to LPIB when POSBUF doesn't work +		  1 = use LPIB +		  2 = POSBUF: use position buffer +		  3 = VIACOMBO: VIA-specific workaround for capture +		  4 = COMBO: use LPIB for playback, auto for capture stream      probe_mask  - Bitmask to probe codecs (default = -1, meaning all slots)      		  When the bit 8 (0x100) is set, the lower 8 bits are used  		  as the "fixed" codec slots; i.e. the driver probes the diff --git a/Documentation/sound/alsa/Channel-Mapping-API.txt b/Documentation/sound/alsa/Channel-Mapping-API.txt new file mode 100644 index 00000000000..3c43d1a4ca0 --- /dev/null +++ b/Documentation/sound/alsa/Channel-Mapping-API.txt @@ -0,0 +1,153 @@ +ALSA PCM channel-mapping API +============================ +					Takashi Iwai <tiwai@suse.de> + +GENERAL +------- + +The channel mapping API allows user to query the possible channel maps +and the current channel map, also optionally to modify the channel map +of the current stream. + +A channel map is an array of position for each PCM channel. +Typically, a stereo PCM stream has a channel map of +  { front_left, front_right } +while a 4.0 surround PCM stream has a channel map of +  { front left, front right, rear left, rear right }. + +The problem, so far, was that we had no standard channel map +explicitly, and applications had no way to know which channel +corresponds to which (speaker) position.  Thus, applications applied +wrong channels for 5.1 outputs, and you hear suddenly strange sound +from rear.  Or, some devices secretly assume that center/LFE is the +third/fourth channels while others that C/LFE as 5th/6th channels. + +Also, some devices such as HDMI are configurable for different speaker +positions even with the same number of total channels.  However, there +was no way to specify this because of lack of channel map +specification.  These are the main motivations for the new channel +mapping API. + + +DESIGN +------ + +Actually, "the channel mapping API" doesn't introduce anything new in +the kernel/user-space ABI perspective.  It uses only the existing +control element features. + +As a ground design, each PCM substream may contain a control element +providing the channel mapping information and configuration.  This +element is specified by: +	iface = SNDRV_CTL_ELEM_IFACE_PCM +	name = "Playback Channel Map" or "Capture Channel Map" +	device = the same device number for the assigned PCM substream +	index = the same index number for the assigned PCM substream + +Note the name is different depending on the PCM substream direction. + +Each control element provides at least the TLV read operation and the +read operation.  Optionally, the write operation can be provided to +allow user to change the channel map dynamically. + +* TLV + +The TLV operation gives the list of available channel +maps.  A list item of a channel map is usually a TLV of +	type data-bytes ch0 ch1 ch2... +where type is the TLV type value, the second argument is the total +bytes (not the numbers) of channel values, and the rest are the +position value for each channel. + +As a TLV type, either SNDRV_CTL_TLVT_CHMAP_FIXED, +SNDRV_CTL_TLV_CHMAP_VAR or SNDRV_CTL_TLVT_CHMAP_PAIRED can be used. +The _FIXED type is for a channel map with the fixed channel position +while the latter two are for flexible channel positions.  _VAR type is +for a channel map where all channels are freely swappable and _PAIRED +type is where pair-wise channels are swappable.  For example, when you +have {FL/FR/RL/RR} channel map, _PAIRED type would allow you to swap +only {RL/RR/FL/FR} while _VAR type would allow even swapping FL and +RR. + +These new TLV types are defined in sound/tlv.h. + +The available channel position values are defined in sound/asound.h, +here is a cut: + +/* channel positions */ +enum { +	SNDRV_CHMAP_UNKNOWN = 0, +	SNDRV_CHMAP_NA,		/* N/A, silent */ +	SNDRV_CHMAP_MONO,	/* mono stream */ +	/* this follows the alsa-lib mixer channel value + 3 */ +	SNDRV_CHMAP_FL,		/* front left */ +	SNDRV_CHMAP_FR,		/* front right */ +	SNDRV_CHMAP_RL,		/* rear left */ +	SNDRV_CHMAP_RR,		/* rear right */ +	SNDRV_CHMAP_FC,		/* front center */ +	SNDRV_CHMAP_LFE,	/* LFE */ +	SNDRV_CHMAP_SL,		/* side left */ +	SNDRV_CHMAP_SR,		/* side right */ +	SNDRV_CHMAP_RC,		/* rear center */ +	/* new definitions */ +	SNDRV_CHMAP_FLC,	/* front left center */ +	SNDRV_CHMAP_FRC,	/* front right center */ +	SNDRV_CHMAP_RLC,	/* rear left center */ +	SNDRV_CHMAP_RRC,	/* rear right center */ +	SNDRV_CHMAP_FLW,	/* front left wide */ +	SNDRV_CHMAP_FRW,	/* front right wide */ +	SNDRV_CHMAP_FLH,	/* front left high */ +	SNDRV_CHMAP_FCH,	/* front center high */ +	SNDRV_CHMAP_FRH,	/* front right high */ +	SNDRV_CHMAP_TC,		/* top center */ +	SNDRV_CHMAP_TFL,	/* top front left */ +	SNDRV_CHMAP_TFR,	/* top front right */ +	SNDRV_CHMAP_TFC,	/* top front center */ +	SNDRV_CHMAP_TRL,	/* top rear left */ +	SNDRV_CHMAP_TRR,	/* top rear right */ +	SNDRV_CHMAP_TRC,	/* top rear center */ +	SNDRV_CHMAP_LAST = SNDRV_CHMAP_TRC, +}; + +When a PCM stream can provide more than one channel map, you can +provide multiple channel maps in a TLV container type.  The TLV data +to be returned will contain such as: +	SNDRV_CTL_TLVT_CONTAINER 96 +	    SNDRV_CTL_TLVT_CHMAP_FIXED 4 SNDRV_CHMAP_FC +	    SNDRV_CTL_TLVT_CHMAP_FIXED 8 SNDRV_CHMAP_FL SNDRV_CHMAP_FR +	    SNDRV_CTL_TLVT_CHMAP_FIXED 16 NDRV_CHMAP_FL SNDRV_CHMAP_FR \ +		SNDRV_CHMAP_RL SNDRV_CHMAP_RR + +The channel position is provided in LSB 16bits.  The upper bits are +used for bit flags. + +#define SNDRV_CHMAP_POSITION_MASK	0xffff +#define SNDRV_CHMAP_PHASE_INVERSE	(0x01 << 16) +#define SNDRV_CHMAP_DRIVER_SPEC		(0x02 << 16) + +SNDRV_CHMAP_PHASE_INVERSE indicates the channel is phase inverted, +(thus summing left and right channels would result in almost silence). +Some digital mic devices have this. + +When SNDRV_CHMAP_DRIVER_SPEC is set, all the channel position values +don't follow the standard definition above but driver-specific. + +* READ OPERATION + +The control read operation is for providing the current channel map of +the given stream.  The control element returns an integer array +containing the position of each channel. + +When this is performed before the number of the channel is specified +(i.e. hw_params is set), it should return all channels set to +UNKNOWN. + +* WRITE OPERATION + +The control write operation is optional, and only for devices that can +change the channel configuration on the fly, such as HDMI.  User needs +to pass an integer value containing the valid channel positions for +all channels of the assigned PCM substream. + +This operation is allowed only at PCM PREPARED state.  When called in +other states, it shall return an error. diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index a92bba81684..16dfe57f173 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -74,7 +74,8 @@ CMI9880  AD1882 / AD1882A  ================ -  3stack	3-stack mode (default) +  3stack	3-stack mode +  3stack-automute 3-stack with automute front HP (default)    6stack	6-stack mode  AD1884A / AD1883 / AD1984A / AD1984B diff --git a/arch/arm/mach-davinci/asp.h b/arch/arm/mach-davinci/asp.h new file mode 100644 index 00000000000..d9b2acd1239 --- /dev/null +++ b/arch/arm/mach-davinci/asp.h @@ -0,0 +1,49 @@ +/* + * TI DaVinci Audio definitions + */ +#ifndef __ASM_ARCH_DAVINCI_ASP_H +#define __ASM_ARCH_DAVINCI_ASP_H + +/* Bases of dm644x and dm355 register banks */ +#define DAVINCI_ASP0_BASE	0x01E02000 +#define DAVINCI_ASP1_BASE	0x01E04000 + +/* Bases of dm365 register banks */ +#define DAVINCI_DM365_ASP0_BASE	0x01D02000 + +/* Bases of dm646x register banks */ +#define DAVINCI_DM646X_MCASP0_REG_BASE		0x01D01000 +#define DAVINCI_DM646X_MCASP1_REG_BASE		0x01D01800 + +/* Bases of da850/da830 McASP0  register banks */ +#define DAVINCI_DA8XX_MCASP0_REG_BASE	0x01D00000 + +/* Bases of da830 McASP1 register banks */ +#define DAVINCI_DA830_MCASP1_REG_BASE	0x01D04000 + +/* EDMA channels of dm644x and dm355 */ +#define DAVINCI_DMA_ASP0_TX	2 +#define DAVINCI_DMA_ASP0_RX	3 +#define DAVINCI_DMA_ASP1_TX	8 +#define DAVINCI_DMA_ASP1_RX	9 + +/* EDMA channels of dm646x */ +#define DAVINCI_DM646X_DMA_MCASP0_AXEVT0	6 +#define DAVINCI_DM646X_DMA_MCASP0_AREVT0	9 +#define DAVINCI_DM646X_DMA_MCASP1_AXEVT1	12 + +/* EDMA channels of da850/da830 McASP0 */ +#define DAVINCI_DA8XX_DMA_MCASP0_AREVT	0 +#define DAVINCI_DA8XX_DMA_MCASP0_AXEVT	1 + +/* EDMA channels of da830 McASP1 */ +#define DAVINCI_DA830_DMA_MCASP1_AREVT	2 +#define DAVINCI_DA830_DMA_MCASP1_AXEVT	3 + +/* Interrupts */ +#define DAVINCI_ASP0_RX_INT	IRQ_MBRINT +#define DAVINCI_ASP0_TX_INT	IRQ_MBXINT +#define DAVINCI_ASP1_RX_INT	IRQ_MBRINT +#define DAVINCI_ASP1_TX_INT	IRQ_MBXINT + +#endif /* __ASM_ARCH_DAVINCI_ASP_H */ diff --git a/arch/arm/mach-davinci/davinci.h b/arch/arm/mach-davinci/davinci.h index a37fc44e29b..12d544befcf 100644 --- a/arch/arm/mach-davinci/davinci.h +++ b/arch/arm/mach-davinci/davinci.h @@ -22,10 +22,10 @@  #include <linux/davinci_emac.h>  #include <linux/platform_device.h>  #include <linux/spi/spi.h> - -#include <mach/asp.h> +#include <linux/platform_data/davinci_asp.h>  #include <linux/platform_data/keyscan-davinci.h>  #include <mach/hardware.h> +#include <mach/edma.h>  #include <media/davinci/vpfe_capture.h>  #include <media/davinci/vpif_types.h> diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c index 783eab6845c..bd2f72b414b 100644 --- a/arch/arm/mach-davinci/devices-da8xx.c +++ b/arch/arm/mach-davinci/devices-da8xx.c @@ -24,6 +24,7 @@  #include <mach/cpuidle.h>  #include "clock.h" +#include "asp.h"  #define DA8XX_TPCC_BASE			0x01c00000  #define DA8XX_TPTC0_BASE		0x01c08000 @@ -505,15 +506,8 @@ static struct platform_device da850_mcasp_device = {  	.resource	= da850_mcasp_resources,  }; -static struct platform_device davinci_pcm_device = { -	.name	= "davinci-pcm-audio", -	.id	= -1, -}; -  void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata)  { -	platform_device_register(&davinci_pcm_device); -  	/* DA830/OMAP-L137 has 3 instances of McASP */  	if (cpu_is_davinci_da830() && id == 1) {  		da830_mcasp1_device.dev.platform_data = pdata; diff --git a/arch/arm/mach-davinci/devices.c b/arch/arm/mach-davinci/devices.c index 3a42b6f79aa..4c48a36ee56 100644 --- a/arch/arm/mach-davinci/devices.c +++ b/arch/arm/mach-davinci/devices.c @@ -313,16 +313,6 @@ static void davinci_init_wdt(void)  /*-------------------------------------------------------------------------*/ -static struct platform_device davinci_pcm_device = { -	.name		= "davinci-pcm-audio", -	.id		= -1, -}; - -static void davinci_init_pcm(void) -{ -	platform_device_register(&davinci_pcm_device); -} -  /*-------------------------------------------------------------------------*/  struct davinci_timer_instance davinci_timer_instance[2] = { @@ -345,7 +335,6 @@ static int __init davinci_init_devices(void)  	/* please keep these calls, and their implementations above,  	 * in alphabetical order so they're easier to sort through.  	 */ -	davinci_init_pcm();  	davinci_init_wdt();  	return 0; diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c index adbde33eca0..a255434908d 100644 --- a/arch/arm/mach-davinci/dm355.c +++ b/arch/arm/mach-davinci/dm355.c @@ -26,13 +26,13 @@  #include <mach/time.h>  #include <mach/serial.h>  #include <mach/common.h> -#include <mach/asp.h>  #include <linux/platform_data/spi-davinci.h>  #include <mach/gpio-davinci.h>  #include "davinci.h"  #include "clock.h"  #include "mux.h" +#include "asp.h"  #define DM355_UART2_BASE	(IO_PHYS + 0x206000) diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c index 719e22f2a37..b680c832e0b 100644 --- a/arch/arm/mach-davinci/dm365.c +++ b/arch/arm/mach-davinci/dm365.c @@ -29,7 +29,6 @@  #include <mach/time.h>  #include <mach/serial.h>  #include <mach/common.h> -#include <mach/asp.h>  #include <linux/platform_data/keyscan-davinci.h>  #include <linux/platform_data/spi-davinci.h>  #include <mach/gpio-davinci.h> @@ -37,6 +36,7 @@  #include "davinci.h"  #include "clock.h"  #include "mux.h" +#include "asp.h"  #define DM365_REF_FREQ		24000000	/* 24 MHz on the DM365 EVM */ diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index c8b866657fc..0755d466221 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -23,12 +23,12 @@  #include <mach/time.h>  #include <mach/serial.h>  #include <mach/common.h> -#include <mach/asp.h>  #include <mach/gpio-davinci.h>  #include "davinci.h"  #include "clock.h"  #include "mux.h" +#include "asp.h"  /*   * Device specific clocks diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c index 9eb87c1d1ed..97c0f8e555b 100644 --- a/arch/arm/mach-davinci/dm646x.c +++ b/arch/arm/mach-davinci/dm646x.c @@ -24,12 +24,12 @@  #include <mach/time.h>  #include <mach/serial.h>  #include <mach/common.h> -#include <mach/asp.h>  #include <mach/gpio-davinci.h>  #include "davinci.h"  #include "clock.h"  #include "mux.h" +#include "asp.h"  #define DAVINCI_VPIF_BASE       (0x01C12000) diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h index 33e78ae2a25..c9ee723c56f 100644 --- a/arch/arm/mach-davinci/include/mach/da8xx.h +++ b/arch/arm/mach-davinci/include/mach/da8xx.h @@ -16,10 +16,10 @@  #include <linux/platform_device.h>  #include <linux/davinci_emac.h>  #include <linux/spi/spi.h> +#include <linux/platform_data/davinci_asp.h>  #include <mach/serial.h>  #include <mach/edma.h> -#include <mach/asp.h>  #include <mach/pm.h>  #include <linux/platform_data/i2c-davinci.h>  #include <linux/platform_data/mmc-davinci.h> diff --git a/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c b/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c index fd3177f9e79..98aef571b9f 100644 --- a/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c +++ b/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c @@ -348,4 +348,5 @@ void __init eukrea_mbimx27_baseboard_init(void)  	imx27_add_imx_keypad(&eukrea_mbimx27_keymap_data);  	gpio_led_register_device(-1, &eukrea_mbimx27_gpio_led_info); +	imx_add_platform_device("eukrea_tlv320", 0, NULL, 0, NULL, 0);  } diff --git a/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c b/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c index dfd2da87c2d..0b84666792f 100644 --- a/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c +++ b/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c @@ -306,4 +306,5 @@ void __init eukrea_mbimxsd25_baseboard_init(void)  	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));  	gpio_led_register_device(-1, &eukrea_mbimxsd_led_info);  	imx_add_gpio_keys(&eukrea_mbimxsd_button_data); +	imx_add_platform_device("eukrea_tlv320", 0, NULL, 0, NULL, 0);  } diff --git a/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c b/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c index 6e9dd12a696..c6532a007d4 100644 --- a/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c +++ b/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c @@ -315,4 +315,5 @@ void __init eukrea_mbimxsd35_baseboard_init(void)  	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));  	gpio_led_register_device(-1, &eukrea_mbimxsd_led_info);  	imx_add_gpio_keys(&eukrea_mbimxsd_button_data); +	imx_add_platform_device("eukrea_tlv320", 0, NULL, 0, NULL, 0);  } diff --git a/arch/arm/mach-imx/eukrea_mbimxsd51-baseboard.c b/arch/arm/mach-imx/eukrea_mbimxsd51-baseboard.c index 96a24b73dc2..8b0de30d7a3 100644 --- a/arch/arm/mach-imx/eukrea_mbimxsd51-baseboard.c +++ b/arch/arm/mach-imx/eukrea_mbimxsd51-baseboard.c @@ -228,4 +228,5 @@ void __init eukrea_mbimxsd51_baseboard_init(void)  	gpio_led_register_device(-1, &eukrea_mbimxsd51_led_info);  	imx_add_gpio_keys(&eukrea_mbimxsd51_button_data); +	imx_add_platform_device("eukrea_tlv320", 0, NULL, 0, NULL, 0);  } diff --git a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c index 821d6aac411..141756f00ae 100644 --- a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c +++ b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c @@ -32,6 +32,7 @@  #include <linux/delay.h>  #include <linux/dma-mapping.h>  #include <linux/leds.h> +#include <linux/platform_data/asoc-mx27vis.h>  #include <media/soc_camera.h>  #include <sound/tlv320aic32x4.h>  #include <asm/mach-types.h> @@ -58,6 +59,11 @@  #define EXPBOARD_BIT1		(GPIO_PORTD + 27)  #define EXPBOARD_BIT0		(GPIO_PORTD + 28) +#define AMP_GAIN_0		(GPIO_PORTF + 9) +#define AMP_GAIN_1		(GPIO_PORTF + 8) +#define AMP_MUTE_SDL		(GPIO_PORTE + 5) +#define AMP_MUTE_SDR		(GPIO_PORTF + 7) +  static const int visstrim_m10_pins[] __initconst = {  	/* UART1 (console) */  	PE12_PF_UART1_TXD, @@ -139,6 +145,11 @@ static const int visstrim_m10_pins[] __initconst = {  	EXPBOARD_BIT2 | GPIO_GPIO | GPIO_IN | GPIO_PUEN,  	EXPBOARD_BIT1 | GPIO_GPIO | GPIO_IN | GPIO_PUEN,  	EXPBOARD_BIT0 | GPIO_GPIO | GPIO_IN | GPIO_PUEN, +	/* Audio AMP control */ +	AMP_GAIN_0 | GPIO_GPIO | GPIO_OUT, +	AMP_GAIN_1 | GPIO_GPIO | GPIO_OUT, +	AMP_MUTE_SDL | GPIO_GPIO | GPIO_OUT, +	AMP_MUTE_SDR | GPIO_GPIO | GPIO_OUT,  };  static struct gpio visstrim_m10_version_gpios[] = { @@ -166,6 +177,26 @@ static const struct gpio visstrim_m10_gpios[] __initconst = {  		.flags = GPIOF_DIR_OUT | GPIOF_INIT_LOW,  		.label = "usbotg_cs",  	}, +	{ +		.gpio = AMP_GAIN_0, +		.flags = GPIOF_DIR_OUT, +		.label = "amp-gain-0", +	}, +	{ +		.gpio = AMP_GAIN_1, +		.flags = GPIOF_DIR_OUT, +		.label = "amp-gain-1", +	}, +	{ +		.gpio = AMP_MUTE_SDL, +		.flags = GPIOF_DIR_OUT, +		.label = "amp-mute-sdl", +	}, +	{ +		.gpio = AMP_MUTE_SDR, +		.flags = GPIOF_DIR_OUT, +		.label = "amp-mute-sdr", +	},  };  /* Camera */ @@ -444,6 +475,14 @@ static void __init visstrim_deinterlace_init(void)  } +/* Audio */ +static const struct snd_mx27vis_platform_data snd_mx27vis_pdata __initconst = { +	.amp_gain0_gpio = AMP_GAIN_0, +	.amp_gain1_gpio = AMP_GAIN_1, +	.amp_mutel_gpio = AMP_MUTE_SDL, +	.amp_muter_gpio = AMP_MUTE_SDR, +}; +  static void __init visstrim_m10_revision(void)  {  	int exp_version = 0; @@ -502,7 +541,8 @@ static void __init visstrim_m10_board_init(void)  	imx27_add_fec(NULL);  	imx_add_gpio_keys(&visstrim_gpio_keys_platform_data);  	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); -	imx_add_platform_device("mx27vis", 0, NULL, 0, NULL, 0); +	imx_add_platform_device("mx27vis", 0, NULL, 0, &snd_mx27vis_pdata, +				sizeof(snd_mx27vis_pdata));  	platform_device_register_resndata(NULL, "soc-camera-pdrv", 0, NULL, 0,  				      &iclink_tvp5150, sizeof(iclink_tvp5150));  	gpio_led_register_device(0, &visstrim_m10_led_data); diff --git a/arch/arm/mach-omap2/board-am3517evm.c b/arch/arm/mach-omap2/board-am3517evm.c index 0d99c9110d0..e16289755f2 100644 --- a/arch/arm/mach-omap2/board-am3517evm.c +++ b/arch/arm/mach-omap2/board-am3517evm.c @@ -263,6 +263,16 @@ static __init void am3517_evm_musb_init(void)  	usb_musb_init(&musb_board_data);  } +static __init void am3517_evm_mcbsp1_init(void) +{ +	u32 devconf0; + +	/* McBSP1 CLKR/FSR signal to be connected to CLKX/FSX pin */ +	devconf0 = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0); +	devconf0 |=  OMAP2_MCBSP1_CLKR_MASK | OMAP2_MCBSP1_FSR_MASK; +	omap_ctrl_writel(devconf0, OMAP2_CONTROL_DEVCONF0); +} +  static const struct usbhs_omap_board_data usbhs_bdata __initconst = {  	.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,  #if defined(CONFIG_PANEL_SHARP_LQ043T1DG01) || \ @@ -366,6 +376,9 @@ static void __init am3517_evm_init(void)  	/* MUSB */  	am3517_evm_musb_init(); +	/* McBSP1 */ +	am3517_evm_mcbsp1_init(); +  	/* MMC init function */  	omap_hsmmc_init(mmc);  } diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c index 8ffd612c5e0..376d26eb601 100644 --- a/arch/arm/mach-omap2/board-cm-t35.c +++ b/arch/arm/mach-omap2/board-cm-t35.c @@ -723,6 +723,7 @@ static void __init cm_t3x_common_init(void)  	cm_t35_init_ethernet();  	cm_t35_init_led();  	cm_t35_init_display(); +	omap_twl4030_audio_init("cm-t3x");  	usb_musb_init(NULL);  	cm_t35_init_usbh(); diff --git a/arch/arm/mach-omap2/board-devkit8000.c b/arch/arm/mach-omap2/board-devkit8000.c index 7bb8056d438..1fd161e934c 100644 --- a/arch/arm/mach-omap2/board-devkit8000.c +++ b/arch/arm/mach-omap2/board-devkit8000.c @@ -623,6 +623,7 @@ static void __init devkit8000_init(void)  	usbhs_init(&usbhs_bdata);  	omap_nand_flash_init(NAND_BUSWIDTH_16, devkit8000_nand_partitions,  			     ARRAY_SIZE(devkit8000_nand_partitions)); +	omap_twl4030_audio_init("omap3beagle");  	/* Ensure SDRC pins are mux'd for self-refresh */  	omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT); diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c index fb8bd837dd1..48d5e41dfbf 100644 --- a/arch/arm/mach-omap2/board-igep0020.c +++ b/arch/arm/mach-omap2/board-igep0020.c @@ -625,6 +625,7 @@ static void __init igep_init(void)  	igep_flash_init();  	igep_leds_init(); +	omap_twl4030_audio_init("igep2");  	/*  	 * WLAN-BT combo module from MuRata which has a Marvell WLAN diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c index 68ff8d51973..a08bebc94ec 100644 --- a/arch/arm/mach-omap2/board-omap3beagle.c +++ b/arch/arm/mach-omap2/board-omap3beagle.c @@ -514,6 +514,7 @@ static void __init omap3_beagle_init(void)  	usbhs_init(&usbhs_bdata);  	omap_nand_flash_init(NAND_BUSWIDTH_16, omap3beagle_nand_partitions,  			     ARRAY_SIZE(omap3beagle_nand_partitions)); +	omap_twl4030_audio_init("omap3beagle");  	/* Ensure msecure is mux'd to be able to set the RTC. */  	omap_mux_init_signal("sys_drm_msecure", OMAP_PIN_OFF_OUTPUT_HIGH); diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c index c64e565bdef..a3959de85e0 100644 --- a/arch/arm/mach-omap2/board-omap3evm.c +++ b/arch/arm/mach-omap2/board-omap3evm.c @@ -739,6 +739,7 @@ static void __init omap3_evm_init(void)  	omap3evm_init_smsc911x();  	omap3_evm_display_init();  	omap3_evm_wl12xx_init(); +	omap_twl4030_audio_init("omap3evm");  }  MACHINE_START(OMAP3EVM, "OMAP3 EVM") diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c index 2e7f24030fc..b700685762b 100644 --- a/arch/arm/mach-omap2/board-overo.c +++ b/arch/arm/mach-omap2/board-overo.c @@ -504,6 +504,7 @@ static void __init overo_init(void)  	overo_display_init();  	overo_init_led();  	overo_init_keys(); +	omap_twl4030_audio_init("overo");  	/* Ensure SDRC pins are mux'd for self-refresh */  	omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT); diff --git a/arch/arm/mach-omap2/board-zoom-peripherals.c b/arch/arm/mach-omap2/board-zoom-peripherals.c index 6bcc107b9fc..67f8540c8e0 100644 --- a/arch/arm/mach-omap2/board-zoom-peripherals.c +++ b/arch/arm/mach-omap2/board-zoom-peripherals.c @@ -35,6 +35,7 @@  #include "common-board-devices.h"  #define OMAP_ZOOM_WLAN_PMENA_GPIO	(101) +#define ZOOM2_HEADSET_EXTMUTE_GPIO	(153)  #define OMAP_ZOOM_WLAN_IRQ_GPIO		(162)  #define LCD_PANEL_ENABLE_GPIO		(7 + OMAP_MAX_GPIO_LINES) @@ -245,12 +246,6 @@ static int zoom_twl_gpio_setup(struct device *dev,  	return ret;  } -/* EXTMUTE callback function */ -static void zoom2_set_hs_extmute(int mute) -{ -	gpio_set_value(ZOOM2_HEADSET_EXTMUTE_GPIO, mute); -} -  static struct twl4030_gpio_platform_data zoom_gpio_data = {  	.setup		= zoom_twl_gpio_setup,  }; @@ -277,7 +272,7 @@ static int __init omap_i2c_init(void)  		codec_data->ramp_delay_value = 3;	/* 161 ms */  		codec_data->hs_extmute = 1; -		codec_data->set_hs_extmute = zoom2_set_hs_extmute; +		codec_data->hs_extmute_gpio = ZOOM2_HEADSET_EXTMUTE_GPIO;  	}  	omap_pmic_init(1, 2400, "twl5030", 7 + OMAP_INTC_START, &zoom_twldata);  	omap_register_i2c_bus(2, 400, NULL, 0); diff --git a/arch/arm/mach-omap2/include/mach/board-zoom.h b/arch/arm/mach-omap2/include/mach/board-zoom.h index 775fdc3b000..2e9486940ea 100644 --- a/arch/arm/mach-omap2/include/mach/board-zoom.h +++ b/arch/arm/mach-omap2/include/mach/board-zoom.h @@ -8,5 +8,3 @@  extern int __init zoom_debugboard_init(void);  extern void __init zoom_peripherals_init(void);  extern void __init zoom_display_init(void); - -#define ZOOM2_HEADSET_EXTMUTE_GPIO	153 diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c index 7d47407d6d4..37f8f948047 100644 --- a/arch/arm/mach-omap2/mcbsp.c +++ b/arch/arm/mach-omap2/mcbsp.c @@ -15,6 +15,7 @@  #include <linux/clk.h>  #include <linux/err.h>  #include <linux/io.h> +#include <linux/of.h>  #include <linux/platform_device.h>  #include <linux/slab.h>  #include <linux/platform_data/asoc-ti-mcbsp.h> @@ -23,8 +24,6 @@  #include <plat/omap_device.h>  #include <linux/pm_runtime.h> -#include "control.h" -  /*   * FIXME: Find a mechanism to enable/disable runtime the McBSP ICLK autoidle.   * Sidetone needs non-gated ICLK and sidetone autoidle is broken. @@ -32,112 +31,6 @@  #include "cm2xxx_3xxx.h"  #include "cm-regbits-34xx.h" -/* McBSP1 internal signal muxing function for OMAP2/3 */ -static int omap2_mcbsp1_mux_rx_clk(struct device *dev, const char *signal, -				   const char *src) -{ -	u32 v; - -	v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0); - -	if (!strcmp(signal, "clkr")) { -		if (!strcmp(src, "clkr")) -			v &= ~OMAP2_MCBSP1_CLKR_MASK; -		else if (!strcmp(src, "clkx")) -			v |= OMAP2_MCBSP1_CLKR_MASK; -		else -			return -EINVAL; -	} else if (!strcmp(signal, "fsr")) { -		if (!strcmp(src, "fsr")) -			v &= ~OMAP2_MCBSP1_FSR_MASK; -		else if (!strcmp(src, "fsx")) -			v |= OMAP2_MCBSP1_FSR_MASK; -		else -			return -EINVAL; -	} else { -		return -EINVAL; -	} - -	omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0); - -	return 0; -} - -/* McBSP4 internal signal muxing function for OMAP4 */ -#define OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_FSX	(1 << 31) -#define OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_CLKX	(1 << 30) -static int omap4_mcbsp4_mux_rx_clk(struct device *dev, const char *signal, -				   const char *src) -{ -	u32 v; - -	/* -	 * In CONTROL_MCBSPLP register only bit 30 (CLKR mux), and bit 31 (FSR -	 * mux) is used */ -	v = omap4_ctrl_pad_readl(OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_MCBSPLP); - -	if (!strcmp(signal, "clkr")) { -		if (!strcmp(src, "clkr")) -			v &= ~OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_CLKX; -		else if (!strcmp(src, "clkx")) -			v |= OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_CLKX; -		else -			return -EINVAL; -	} else if (!strcmp(signal, "fsr")) { -		if (!strcmp(src, "fsr")) -			v &= ~OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_FSX; -		else if (!strcmp(src, "fsx")) -			v |= OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_FSX; -		else -			return -EINVAL; -	} else { -		return -EINVAL; -	} - -	omap4_ctrl_pad_writel(v, OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_MCBSPLP); - -	return 0; -} - -/* McBSP CLKS source switching function */ -static int omap2_mcbsp_set_clk_src(struct device *dev, struct clk *clk, -				   const char *src) -{ -	struct clk *fck_src; -	char *fck_src_name; -	int r; - -	if (!strcmp(src, "clks_ext")) -		fck_src_name = "pad_fck"; -	else if (!strcmp(src, "clks_fclk")) -		fck_src_name = "prcm_fck"; -	else -		return -EINVAL; - -	fck_src = clk_get(dev, fck_src_name); -	if (IS_ERR_OR_NULL(fck_src)) { -		pr_err("omap-mcbsp: %s: could not clk_get() %s\n", "clks", -		       fck_src_name); -		return -EINVAL; -	} - -	pm_runtime_put_sync(dev); - -	r = clk_set_parent(clk, fck_src); -	if (IS_ERR_VALUE(r)) { -		pr_err("omap-mcbsp: %s: could not clk_set_parent() to %s\n", -		       "clks", fck_src_name); -		clk_put(fck_src); -		return -EINVAL; -	} - -	pm_runtime_get_sync(dev); - -	clk_put(fck_src); - -	return 0; -} -  static int omap3_enable_st_clock(unsigned int id, bool enable)  {  	unsigned int w; @@ -179,17 +72,11 @@ static int __init omap_init_mcbsp(struct omap_hwmod *oh, void *unused)  		pdata->reg_size = 4;  		pdata->has_ccr = true;  	} -	pdata->set_clk_src = omap2_mcbsp_set_clk_src; - -	/* On OMAP2/3 the McBSP1 port has 6 pin configuration */ -	if (id == 1 && oh->class->rev < MCBSP_CONFIG_TYPE4) -		pdata->mux_signal = omap2_mcbsp1_mux_rx_clk; -	/* On OMAP4 the McBSP4 port has 6 pin configuration */ -	if (id == 4 && oh->class->rev == MCBSP_CONFIG_TYPE4) -		pdata->mux_signal = omap4_mcbsp4_mux_rx_clk; - -	if (oh->class->rev == MCBSP_CONFIG_TYPE3) { +	if (oh->class->rev == MCBSP_CONFIG_TYPE2) { +		/* The FIFO has 128 locations */ +		pdata->buffer_size = 0x80; +	} else if (oh->class->rev == MCBSP_CONFIG_TYPE3) {  		if (id == 2)  			/* The FIFO has 1024 + 256 locations */  			pdata->buffer_size = 0x500; @@ -225,7 +112,8 @@ static int __init omap_init_mcbsp(struct omap_hwmod *oh, void *unused)  static int __init omap2_mcbsp_init(void)  { -	omap_hwmod_for_each_by_class("mcbsp", omap_init_mcbsp, NULL); +	if (!of_have_populated_dt()) +		omap_hwmod_for_each_by_class("mcbsp", omap_init_mcbsp, NULL);  	return 0;  } diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index 8d7a93525bc..652d0285bd6 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -5269,6 +5269,7 @@ static struct omap_hwmod_ocp_if omap44xx_l4_per__mcbsp4 = {  static struct omap_hwmod_addr_space omap44xx_mcpdm_addrs[] = {  	{ +		.name		= "mpu",  		.pa_start	= 0x40132000,  		.pa_end		= 0x4013207f,  		.flags		= ADDR_TYPE_RT @@ -5287,6 +5288,7 @@ static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcpdm = {  static struct omap_hwmod_addr_space omap44xx_mcpdm_dma_addrs[] = {  	{ +		.name		= "dma",  		.pa_start	= 0x49032000,  		.pa_end		= 0x4903207f,  		.flags		= ADDR_TYPE_RT diff --git a/arch/arm/mach-omap2/twl-common.c b/arch/arm/mach-omap2/twl-common.c index 45f77413c21..18a85195942 100644 --- a/arch/arm/mach-omap2/twl-common.c +++ b/arch/arm/mach-omap2/twl-common.c @@ -519,3 +519,30 @@ void __init omap4_pmic_get_config(struct twl4030_platform_data *pmic_data,  		pmic_data->v2v1 = &omap4_v2v1_idata;  }  #endif /* CONFIG_ARCH_OMAP4 */ + +#if defined(CONFIG_SND_OMAP_SOC_OMAP_TWL4030) || \ +	defined(CONFIG_SND_OMAP_SOC_OMAP_TWL4030_MODULE) +#include <linux/platform_data/omap-twl4030.h> + +static struct omap_tw4030_pdata omap_twl4030_audio_data; + +static struct platform_device audio_device = { +	.name		= "omap-twl4030", +	.id		= -1, +	.dev = { +		.platform_data = &omap_twl4030_audio_data, +	}, +}; + +void __init omap_twl4030_audio_init(char *card_name) +{ +	omap_twl4030_audio_data.card_name = card_name; +	platform_device_register(&audio_device); +} + +#else /* SOC_OMAP_TWL4030 */ +void __init omap_twl4030_audio_init(char *card_name) +{ +	return; +} +#endif /* SOC_OMAP_TWL4030 */ diff --git a/arch/arm/mach-omap2/twl-common.h b/arch/arm/mach-omap2/twl-common.h index 2256efe90cf..dcfbad5ac47 100644 --- a/arch/arm/mach-omap2/twl-common.h +++ b/arch/arm/mach-omap2/twl-common.h @@ -60,4 +60,6 @@ void omap3_pmic_get_config(struct twl4030_platform_data *pmic_data,  void omap4_pmic_get_config(struct twl4030_platform_data *pmic_data,  			   u32 pdata_flags, u32 regulators_flags); +void omap_twl4030_audio_init(char *card_name); +  #endif /* __OMAP_PMIC_COMMON__ */ diff --git a/arch/arm/plat-samsung/dma-ops.c b/arch/arm/plat-samsung/dma-ops.c index c38d7548924..d088afa034e 100644 --- a/arch/arm/plat-samsung/dma-ops.c +++ b/arch/arm/plat-samsung/dma-ops.c @@ -91,7 +91,8 @@ static int samsung_dmadev_prepare(unsigned ch,  		break;  	case DMA_CYCLIC:  		desc = dmaengine_prep_dma_cyclic(chan, param->buf, -			param->len, param->period, param->direction); +			param->len, param->period, param->direction, +			DMA_PREP_INTERRUPT | DMA_CTRL_ACK);  		break;  	default:  		dev_err(&chan->dev->device, "unsupported format\n"); diff --git a/arch/blackfin/mach-bf527/boards/ezkit.c b/arch/blackfin/mach-bf527/boards/ezkit.c index fc179ca0779..29f16e5c37b 100644 --- a/arch/blackfin/mach-bf527/boards/ezkit.c +++ b/arch/blackfin/mach-bf527/boards/ezkit.c @@ -587,6 +587,21 @@ static struct platform_device bfin_tdm = {  };  #endif +#if defined(CONFIG_SND_BF5XX_SOC_AD1836) \ +	        || defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE) +static const char * const ad1836_link[] = { +	"bfin-tdm.0", +	"spi0.4", +}; +static struct platform_device bfin_ad1836_machine = { +	.name = "bfin-snd-ad1836", +	.id = -1, +	.dev = { +		.platform_data = (void *)ad1836_link, +	}, +}; +#endif +  static struct spi_board_info bfin_spi_board_info[] __initdata = {  #if defined(CONFIG_MTD_M25P80) \  	|| defined(CONFIG_MTD_M25P80_MODULE) @@ -1269,6 +1284,11 @@ static struct platform_device *stamp_devices[] __initdata = {  #if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)  	&bfin_tdm,  #endif + +#if defined(CONFIG_SND_BF5XX_SOC_AD1836) || \ +	defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE) +	&bfin_ad1836_machine, +#endif  };  static int __init ezkit_init(void) diff --git a/arch/blackfin/mach-bf533/boards/stamp.c b/arch/blackfin/mach-bf533/boards/stamp.c index ce88a7165b6..6fca8698bf3 100644 --- a/arch/blackfin/mach-bf533/boards/stamp.c +++ b/arch/blackfin/mach-bf533/boards/stamp.c @@ -617,6 +617,21 @@ static struct platform_device bfin_ac97_pcm = {  };  #endif +#if defined(CONFIG_SND_BF5XX_SOC_AD1836) \ +	        || defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE) +static const char * const ad1836_link[] = { +	"bfin-tdm.0", +	"spi0.4", +}; +static struct platform_device bfin_ad1836_machine = { +	.name = "bfin-snd-ad1836", +	.id = -1, +	.dev = { +		.platform_data = (void *)ad1836_link, +	}, +}; +#endif +  #if defined(CONFIG_SND_BF5XX_SOC_AD73311) || \  	defined(CONFIG_SND_BF5XX_SOC_AD73311_MODULE)  static const unsigned ad73311_gpio[] = { @@ -754,6 +769,11 @@ static struct platform_device *stamp_devices[] __initdata = {  	&bfin_ac97_pcm,  #endif +#if defined(CONFIG_SND_BF5XX_SOC_AD1836) || \ +	defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE) +	&bfin_ad1836_machine, +#endif +  #if defined(CONFIG_SND_BF5XX_SOC_AD73311) || \  	defined(CONFIG_SND_BF5XX_SOC_AD73311_MODULE)  	&bfin_ad73311_machine, diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c index 5ed654ae66e..307bd7e62f4 100644 --- a/arch/blackfin/mach-bf537/boards/stamp.c +++ b/arch/blackfin/mach-bf537/boards/stamp.c @@ -2641,6 +2641,21 @@ static struct platform_device bfin_ac97_pcm = {  };  #endif +#if defined(CONFIG_SND_BF5XX_SOC_AD1836) \ +	        || defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE) +static const char * const ad1836_link[] = { +	"bfin-tdm.0", +	"spi0.4", +}; +static struct platform_device bfin_ad1836_machine = { +	.name = "bfin-snd-ad1836", +	.id = -1, +	.dev = { +		.platform_data = (void *)ad1836_link, +	}, +}; +#endif +  #if defined(CONFIG_SND_BF5XX_SOC_AD73311) || \  				defined(CONFIG_SND_BF5XX_SOC_AD73311_MODULE)  static const unsigned ad73311_gpio[] = { @@ -2927,6 +2942,11 @@ static struct platform_device *stamp_devices[] __initdata = {  	&bfin_ac97_pcm,  #endif +#if defined(CONFIG_SND_BF5XX_SOC_AD1836) || \ +	defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE) +	&bfin_ad1836_machine, +#endif +  #if defined(CONFIG_SND_BF5XX_SOC_AD73311) || \  		defined(CONFIG_SND_BF5XX_SOC_AD73311_MODULE)  	&bfin_ad73311_machine, diff --git a/arch/blackfin/mach-bf561/boards/ezkit.c b/arch/blackfin/mach-bf561/boards/ezkit.c index 7c36777c645..551f866172c 100644 --- a/arch/blackfin/mach-bf561/boards/ezkit.c +++ b/arch/blackfin/mach-bf561/boards/ezkit.c @@ -539,6 +539,21 @@ static struct platform_device bfin_ac97 = {  };  #endif +#if defined(CONFIG_SND_BF5XX_SOC_AD1836) \ +	        || defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE) +static const char * const ad1836_link[] = { +	"bfin-tdm.0", +	"spi0.4", +}; +static struct platform_device bfin_ad1836_machine = { +	.name = "bfin-snd-ad1836", +	.id = -1, +	.dev = { +		.platform_data = (void *)ad1836_link, +	}, +}; +#endif +  static struct platform_device *ezkit_devices[] __initdata = {  	&bfin_dpmc, @@ -603,6 +618,11 @@ static struct platform_device *ezkit_devices[] __initdata = {  #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)  	&bfin_ac97,  #endif + +#if defined(CONFIG_SND_BF5XX_SOC_AD1836) || \ +	defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE) +	&bfin_ad1836_machine, +#endif  };  static int __init net2272_init(void) diff --git a/arch/blackfin/mach-bf609/boards/ezkit.c b/arch/blackfin/mach-bf609/boards/ezkit.c index c2cf1ae3118..61c1f47a4bf 100644 --- a/arch/blackfin/mach-bf609/boards/ezkit.c +++ b/arch/blackfin/mach-bf609/boards/ezkit.c @@ -818,6 +818,21 @@ static struct platform_device bfin_i2s = {  };  #endif +#if defined(CONFIG_SND_BF5XX_SOC_AD1836) \ +	        || defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE) +static const char * const ad1836_link[] = { +	"bfin-tdm.0", +	"spi0.76", +}; +static struct platform_device bfin_ad1836_machine = { +	.name = "bfin-snd-ad1836", +	.id = -1, +	.dev = { +		.platform_data = (void *)ad1836_link, +	}, +}; +#endif +  #if defined(CONFIG_SND_SOC_BFIN_EVAL_ADAU1X61) || \  	defined(CONFIG_SND_SOC_BFIN_EVAL_ADAU1X61_MODULE)  static struct platform_device adau1761_device = { @@ -1557,6 +1572,10 @@ static struct platform_device *ezkit_devices[] __initdata = {  	defined(CONFIG_SND_BF6XX_SOC_I2S_MODULE)  	&bfin_i2s,  #endif +#if defined(CONFIG_SND_BF5XX_SOC_AD1836) || \ +	defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE) +	&bfin_ad1836_machine, +#endif  #if defined(CONFIG_SND_SOC_BFIN_EVAL_ADAU1X61) || \  	defined(CONFIG_SND_SOC_BFIN_EVAL_ADAU1X61_MODULE)  	&adau1761_device, diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 17d6958342e..13a02f4425b 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -852,12 +852,13 @@ atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc,   * @buf_len: total number of bytes for the entire buffer   * @period_len: number of bytes for each period   * @direction: transfer direction, to or from device + * @flags: tx descriptor status flags   * @context: transfer context (ignored)   */  static struct dma_async_tx_descriptor *  atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,  		size_t period_len, enum dma_transfer_direction direction, -		void *context) +		unsigned long flags, void *context)  {  	struct at_dma_chan	*atchan = to_at_dma_chan(chan);  	struct at_dma_slave	*atslave = chan->private; diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c index 64256f64425..bcfde400904 100644 --- a/drivers/dma/ep93xx_dma.c +++ b/drivers/dma/ep93xx_dma.c @@ -1120,6 +1120,7 @@ fail:   * @buf_len: length of the buffer (in bytes)   * @period_len: length of a single period   * @dir: direction of the operation + * @flags: tx descriptor status flags   * @context: operation context (ignored)   *   * Prepares a descriptor for cyclic DMA operation. This means that once the @@ -1133,7 +1134,8 @@ fail:  static struct dma_async_tx_descriptor *  ep93xx_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr,  			   size_t buf_len, size_t period_len, -			   enum dma_transfer_direction dir, void *context) +			   enum dma_transfer_direction dir, unsigned long flags, +			   void *context)  {  	struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan);  	struct ep93xx_dma_desc *desc, *first; diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index 2a3fab289db..f11b5b2b1a1 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -801,7 +801,7 @@ static struct dma_async_tx_descriptor *imxdma_prep_slave_sg(  static struct dma_async_tx_descriptor *imxdma_prep_dma_cyclic(  		struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,  		size_t period_len, enum dma_transfer_direction direction, -		void *context) +		unsigned long flags, void *context)  {  	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);  	struct imxdma_engine *imxdma = imxdmac->imxdma; diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 1b781d6ac42..c099ca0846f 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -1012,7 +1012,7 @@ err_out:  static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(  		struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,  		size_t period_len, enum dma_transfer_direction direction, -		void *context) +		unsigned long flags, void *context)  {  	struct sdma_channel *sdmac = to_sdma_chan(chan);  	struct sdma_engine *sdma = sdmac->sdma; diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c index 07fa48688ba..6d9c82e891d 100644 --- a/drivers/dma/mmp_tdma.c +++ b/drivers/dma/mmp_tdma.c @@ -358,7 +358,7 @@ struct mmp_tdma_desc *mmp_tdma_alloc_descriptor(struct mmp_tdma_chan *tdmac)  static struct dma_async_tx_descriptor *mmp_tdma_prep_dma_cyclic(  		struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,  		size_t period_len, enum dma_transfer_direction direction, -		void *context) +		unsigned long flags, void *context)  {  	struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);  	struct mmp_tdma_desc *desc; diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c index 7f41b25805f..734a4eb84d6 100644 --- a/drivers/dma/mxs-dma.c +++ b/drivers/dma/mxs-dma.c @@ -531,7 +531,7 @@ err_out:  static struct dma_async_tx_descriptor *mxs_dma_prep_dma_cyclic(  		struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,  		size_t period_len, enum dma_transfer_direction direction, -		void *context) +		unsigned long flags, void *context)  {  	struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);  	struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c index 2e166277766..bb2d8e7029e 100644 --- a/drivers/dma/omap-dma.c +++ b/drivers/dma/omap-dma.c @@ -36,6 +36,7 @@ struct omap_chan {  	struct dma_slave_config	cfg;  	unsigned dma_sig;  	bool cyclic; +	bool paused;  	int dma_ch;  	struct omap_desc *desc; @@ -367,7 +368,8 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg(  static struct dma_async_tx_descriptor *omap_dma_prep_dma_cyclic(  	struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, -	size_t period_len, enum dma_transfer_direction dir, void *context) +	size_t period_len, enum dma_transfer_direction dir, unsigned long flags, +	void *context)  {  	struct omap_chan *c = to_omap_dma_chan(chan);  	enum dma_slave_buswidth dev_width; @@ -415,7 +417,10 @@ static struct dma_async_tx_descriptor *omap_dma_prep_dma_cyclic(  	d->dev_addr = dev_addr;  	d->fi = burst;  	d->es = es; -	d->sync_mode = OMAP_DMA_SYNC_PACKET; +	if (burst) +		d->sync_mode = OMAP_DMA_SYNC_PACKET; +	else +		d->sync_mode = OMAP_DMA_SYNC_ELEMENT;  	d->sync_type = sync_type;  	d->periph_port = OMAP_DMA_PORT_MPUI;  	d->sg[0].addr = buf_addr; @@ -426,7 +431,10 @@ static struct dma_async_tx_descriptor *omap_dma_prep_dma_cyclic(  	if (!c->cyclic) {  		c->cyclic = true;  		omap_dma_link_lch(c->dma_ch, c->dma_ch); -		omap_enable_dma_irq(c->dma_ch, OMAP_DMA_FRAME_IRQ); + +		if (flags & DMA_PREP_INTERRUPT) +			omap_enable_dma_irq(c->dma_ch, OMAP_DMA_FRAME_IRQ); +  		omap_disable_dma_irq(c->dma_ch, OMAP_DMA_BLOCK_IRQ);  	} @@ -435,7 +443,7 @@ static struct dma_async_tx_descriptor *omap_dma_prep_dma_cyclic(  		omap_set_dma_dest_burst_mode(c->dma_ch, OMAP_DMA_DATA_BURST_16);  	} -	return vchan_tx_prep(&c->vc, &d->vd, DMA_CTRL_ACK | DMA_PREP_INTERRUPT); +	return vchan_tx_prep(&c->vc, &d->vd, flags);  }  static int omap_dma_slave_config(struct omap_chan *c, struct dma_slave_config *cfg) @@ -469,11 +477,14 @@ static int omap_dma_terminate_all(struct omap_chan *c)  	 */  	if (c->desc) {  		c->desc = NULL; -		omap_stop_dma(c->dma_ch); +		/* Avoid stopping the dma twice */ +		if (!c->paused) +			omap_stop_dma(c->dma_ch);  	}  	if (c->cyclic) {  		c->cyclic = false; +		c->paused = false;  		omap_dma_unlink_lch(c->dma_ch, c->dma_ch);  	} @@ -486,14 +497,30 @@ static int omap_dma_terminate_all(struct omap_chan *c)  static int omap_dma_pause(struct omap_chan *c)  { -	/* FIXME: not supported by platform private API */ -	return -EINVAL; +	/* Pause/Resume only allowed with cyclic mode */ +	if (!c->cyclic) +		return -EINVAL; + +	if (!c->paused) { +		omap_stop_dma(c->dma_ch); +		c->paused = true; +	} + +	return 0;  }  static int omap_dma_resume(struct omap_chan *c)  { -	/* FIXME: not supported by platform private API */ -	return -EINVAL; +	/* Pause/Resume only allowed with cyclic mode */ +	if (!c->cyclic) +		return -EINVAL; + +	if (c->paused) { +		omap_start_dma(c->dma_ch); +		c->paused = false; +	} + +	return 0;  }  static int omap_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 5d3bbcd279b..169c0dbd71a 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -2685,7 +2685,7 @@ static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len)  static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(  		struct dma_chan *chan, dma_addr_t dma_addr, size_t len,  		size_t period_len, enum dma_transfer_direction direction, -		void *context) +		unsigned long flags, void *context)  {  	struct dma_pl330_desc *desc;  	struct dma_pl330_chan *pch = to_pchan(chan); diff --git a/drivers/dma/sa11x0-dma.c b/drivers/dma/sa11x0-dma.c index f5a73606217..b893159c1ec 100644 --- a/drivers/dma/sa11x0-dma.c +++ b/drivers/dma/sa11x0-dma.c @@ -614,7 +614,7 @@ static struct dma_async_tx_descriptor *sa11x0_dma_prep_slave_sg(  static struct dma_async_tx_descriptor *sa11x0_dma_prep_dma_cyclic(  	struct dma_chan *chan, dma_addr_t addr, size_t size, size_t period, -	enum dma_transfer_direction dir, void *context) +	enum dma_transfer_direction dir, unsigned long flags, void *context)  {  	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);  	struct sa11x0_dma_desc *txd; diff --git a/drivers/dma/sirf-dma.c b/drivers/dma/sirf-dma.c index 434ad31174f..3eed8b35b0f 100644 --- a/drivers/dma/sirf-dma.c +++ b/drivers/dma/sirf-dma.c @@ -489,7 +489,7 @@ err_dir:  static struct dma_async_tx_descriptor *  sirfsoc_dma_prep_cyclic(struct dma_chan *chan, dma_addr_t addr,  	size_t buf_len, size_t period_len, -	enum dma_transfer_direction direction, void *context) +	enum dma_transfer_direction direction, unsigned long flags, void *context)  {  	struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);  	struct sirfsoc_dma_desc *sdesc = NULL; diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 000d309602b..eee8d9b9a20 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -2347,7 +2347,8 @@ static struct dma_async_tx_descriptor *d40_prep_slave_sg(struct dma_chan *chan,  static struct dma_async_tx_descriptor *  dma40_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr,  		     size_t buf_len, size_t period_len, -		     enum dma_transfer_direction direction, void *context) +		     enum dma_transfer_direction direction, unsigned long flags, +		     void *context)  {  	unsigned int periods = buf_len / period_len;  	struct dma_async_tx_descriptor *txd; diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c index 4708467e4d8..45fbeed1c1a 100644 --- a/drivers/dma/tegra20-apb-dma.c +++ b/drivers/dma/tegra20-apb-dma.c @@ -990,7 +990,7 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg(  struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic(  	struct dma_chan *dc, dma_addr_t buf_addr, size_t buf_len,  	size_t period_len, enum dma_transfer_direction direction, -	void *context) +	unsigned long flags, void *context)  {  	struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);  	struct tegra_dma_desc *dma_desc = NULL; diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 9c02a4508b2..d3201e438d1 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -591,7 +591,7 @@ struct dma_device {  	struct dma_async_tx_descriptor *(*device_prep_dma_cyclic)(  		struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,  		size_t period_len, enum dma_transfer_direction direction, -		void *context); +		unsigned long flags, void *context);  	struct dma_async_tx_descriptor *(*device_prep_interleaved_dma)(  		struct dma_chan *chan, struct dma_interleaved_template *xt,  		unsigned long flags); @@ -653,10 +653,11 @@ static inline struct dma_async_tx_descriptor *dmaengine_prep_rio_sg(  static inline struct dma_async_tx_descriptor *dmaengine_prep_dma_cyclic(  		struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, -		size_t period_len, enum dma_transfer_direction dir) +		size_t period_len, enum dma_transfer_direction dir, +		unsigned long flags)  {  	return chan->device->device_prep_dma_cyclic(chan, buf_addr, buf_len, -						period_len, dir, NULL); +						period_len, dir, flags, NULL);  }  static inline int dmaengine_terminate_all(struct dma_chan *chan) diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h index 1faa58f9b85..9a5e2846232 100644 --- a/include/linux/i2c/twl.h +++ b/include/linux/i2c/twl.h @@ -664,7 +664,7 @@ struct twl4030_codec_data {  	unsigned int check_defaults:1;  	unsigned int reset_registers:1;  	unsigned int hs_extmute:1; -	void (*set_hs_extmute)(int mute); +	int hs_extmute_gpio;  };  struct twl4030_vibra_data { diff --git a/include/linux/mfd/wm8994/pdata.h b/include/linux/mfd/wm8994/pdata.h index f0361c03192..fc87be4fdc2 100644 --- a/include/linux/mfd/wm8994/pdata.h +++ b/include/linux/mfd/wm8994/pdata.h @@ -164,6 +164,10 @@ struct wm8994_pdata {  	int num_micd_rates;  	struct wm8958_micd_rate *micd_rates; +	/* Power up delays to add after microphone bias power up (ms) */ +	int micb1_delay; +	int micb2_delay; +          /* LINEOUT can be differential or single ended */          unsigned int lineout1_diff:1;          unsigned int lineout2_diff:1; diff --git a/include/linux/platform_data/asoc-mx27vis.h b/include/linux/platform_data/asoc-mx27vis.h new file mode 100644 index 00000000000..409adcd04d0 --- /dev/null +++ b/include/linux/platform_data/asoc-mx27vis.h @@ -0,0 +1,11 @@ +#ifndef __PLATFORM_DATA_ASOC_MX27VIS_H +#define __PLATFORM_DATA_ASOC_MX27VIS_H + +struct snd_mx27vis_platform_data { +	int amp_gain0_gpio; +	int amp_gain1_gpio; +	int amp_mutel_gpio; +	int amp_muter_gpio; +}; + +#endif /* __PLATFORM_DATA_ASOC_MX27VIS_H */ diff --git a/include/linux/platform_data/asoc-ti-mcbsp.h b/include/linux/platform_data/asoc-ti-mcbsp.h index 18814127809..c78d90b28b1 100644 --- a/include/linux/platform_data/asoc-ti-mcbsp.h +++ b/include/linux/platform_data/asoc-ti-mcbsp.h @@ -47,8 +47,6 @@ struct omap_mcbsp_platform_data {  	bool has_wakeup; /* Wakeup capability */  	bool has_ccr; /* Transceiver has configuration control registers */  	int (*enable_st_clock)(unsigned int, bool); -	int (*set_clk_src)(struct device *dev, struct clk *clk, const char *src); -	int (*mux_signal)(struct device *dev, const char *signal, const char *src);  };  /** diff --git a/arch/arm/mach-davinci/include/mach/asp.h b/include/linux/platform_data/davinci_asp.h index 9aa240909a2..d0c5825876f 100644 --- a/arch/arm/mach-davinci/include/mach/asp.h +++ b/include/linux/platform_data/davinci_asp.h @@ -1,59 +1,26 @@  /* - * <mach/asp.h> - DaVinci Audio Serial Port support + * TI DaVinci Audio Serial Port support + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ + * + * 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.   */ -#ifndef __ASM_ARCH_DAVINCI_ASP_H -#define __ASM_ARCH_DAVINCI_ASP_H -#include <mach/irqs.h> -#include <mach/edma.h> - -/* Bases of dm644x and dm355 register banks */ -#define DAVINCI_ASP0_BASE	0x01E02000 -#define DAVINCI_ASP1_BASE	0x01E04000 - -/* Bases of dm365 register banks */ -#define DAVINCI_DM365_ASP0_BASE	0x01D02000 - -/* Bases of dm646x register banks */ -#define	DAVINCI_DM646X_MCASP0_REG_BASE		0x01D01000 -#define DAVINCI_DM646X_MCASP1_REG_BASE		0x01D01800 - -/* Bases of da850/da830 McASP0  register banks */ -#define DAVINCI_DA8XX_MCASP0_REG_BASE	0x01D00000 - -/* Bases of da830 McASP1 register banks */ -#define DAVINCI_DA830_MCASP1_REG_BASE	0x01D04000 - -/* EDMA channels of dm644x and dm355 */ -#define DAVINCI_DMA_ASP0_TX	2 -#define DAVINCI_DMA_ASP0_RX	3 -#define DAVINCI_DMA_ASP1_TX	8 -#define DAVINCI_DMA_ASP1_RX	9 - -/* EDMA channels of dm646x */ -#define	DAVINCI_DM646X_DMA_MCASP0_AXEVT0	6 -#define	DAVINCI_DM646X_DMA_MCASP0_AREVT0	9 -#define	DAVINCI_DM646X_DMA_MCASP1_AXEVT1	12 - -/* EDMA channels of da850/da830 McASP0 */ -#define	DAVINCI_DA8XX_DMA_MCASP0_AREVT	0 -#define	DAVINCI_DA8XX_DMA_MCASP0_AXEVT	1 - -/* EDMA channels of da830 McASP1 */ -#define	DAVINCI_DA830_DMA_MCASP1_AREVT	2 -#define	DAVINCI_DA830_DMA_MCASP1_AXEVT	3 - -/* Interrupts */ -#define DAVINCI_ASP0_RX_INT	IRQ_MBRINT -#define DAVINCI_ASP0_TX_INT	IRQ_MBXINT -#define DAVINCI_ASP1_RX_INT	IRQ_MBRINT -#define DAVINCI_ASP1_TX_INT	IRQ_MBXINT +#ifndef __DAVINCI_ASP_H +#define __DAVINCI_ASP_H  struct snd_platform_data {  	u32 tx_dma_offset;  	u32 rx_dma_offset; -	enum dma_event_q asp_chan_q;	/* event queue number for ASP channel */ -	enum dma_event_q ram_chan_q;	/* event queue number for RAM channel */ +	int asp_chan_q;	/* event queue number for ASP channel */ +	int ram_chan_q;	/* event queue number for RAM channel */  	unsigned int codec_fmt;  	/*  	 * Allowing this is more efficient and eliminates left and right swaps @@ -70,7 +37,7 @@ struct snd_platform_data {  	 * and MCBSP_CLKS.  	 * Depending on different hardware connections it is possible  	 * to use this setting to change the behaviour of McBSP -	 * driver. The dm365_clk_input_pin enum is available for dm365 +	 * driver.  	 */  	int clk_input_pin; @@ -120,10 +87,11 @@ struct snd_platform_data {  enum {  	MCASP_VERSION_1 = 0,	/* DM646x */  	MCASP_VERSION_2,	/* DA8xx/OMAPL1x */ +	MCASP_VERSION_3,        /* TI81xx/AM33xx */  }; -enum dm365_clk_input_pin { -	MCBSP_CLKR = 0,		/* DM365 */ +enum mcbsp_clk_input_pin { +	MCBSP_CLKR = 0,		/* as in DM365 */  	MCBSP_CLKS,  }; @@ -134,4 +102,4 @@ enum dm365_clk_input_pin {  #define DAVINCI_MCASP_IIS_MODE	0  #define DAVINCI_MCASP_DIT_MODE	1 -#endif /* __ASM_ARCH_DAVINCI_ASP_H */ +#endif diff --git a/include/linux/platform_data/omap-twl4030.h b/include/linux/platform_data/omap-twl4030.h new file mode 100644 index 00000000000..c7bef788daa --- /dev/null +++ b/include/linux/platform_data/omap-twl4030.h @@ -0,0 +1,32 @@ +/** + * omap-twl4030.h - ASoC machine driver for TI SoC based boards with twl4030 + *		    codec, header. + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com + * All rights reserved. + * + * Author: Peter Ujfalusi <peter.ujfalusi@ti.com> + * + * 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 + */ + +#ifndef _OMAP_TWL4030_H_ +#define _OMAP_TWL4030_H_ + +struct omap_tw4030_pdata { +	const char *card_name; +}; + +#endif /* _OMAP_TWL4030_H_ */ diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h index fdeb8dceec0..d315a08d6c6 100644 --- a/include/sound/ac97_codec.h +++ b/include/sound/ac97_codec.h @@ -422,6 +422,7 @@   */  struct snd_ac97; +struct snd_pcm_chmap;  struct snd_ac97_build_ops {  	int (*build_3d) (struct snd_ac97 *ac97); @@ -528,6 +529,8 @@ struct snd_ac97 {  	struct delayed_work power_work;  #endif  	struct device dev; + +	struct snd_pcm_chmap *chmaps[2]; /* channel-maps (optional) */  };  #define to_ac97_t(d) container_of(d, struct snd_ac97, dev) diff --git a/include/sound/ad1816a.h b/include/sound/ad1816a.h index a7d8dc782e7..abdf609c591 100644 --- a/include/sound/ad1816a.h +++ b/include/sound/ad1816a.h @@ -147,6 +147,9 @@ struct snd_ad1816a {  	unsigned int c_dma_size;  	struct snd_timer *timer; +#ifdef CONFIG_PM +	unsigned short image[48]; +#endif  }; @@ -165,11 +168,15 @@ struct snd_ad1816a {  extern int snd_ad1816a_create(struct snd_card *card, unsigned long port,  			      int irq, int dma1, int dma2, -			      struct snd_ad1816a **chip); +			      struct snd_ad1816a *chip);  extern int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device, struct snd_pcm **rpcm);  extern int snd_ad1816a_mixer(struct snd_ad1816a *chip);  extern int snd_ad1816a_timer(struct snd_ad1816a *chip, int device,  			     struct snd_timer **rtimer); +#ifdef CONFIG_PM +extern void snd_ad1816a_suspend(struct snd_ad1816a *chip); +extern void snd_ad1816a_resume(struct snd_ad1816a *chip); +#endif  #endif	/* __SOUND_AD1816A_H */ diff --git a/include/sound/asound.h b/include/sound/asound.h index 0876a1e76ae..dfe7d441748 100644 --- a/include/sound/asound.h +++ b/include/sound/asound.h @@ -472,6 +472,45 @@ enum {  	SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC,  }; +/* channel positions */ +enum { +	SNDRV_CHMAP_UNKNOWN = 0, +	SNDRV_CHMAP_NA,		/* N/A, silent */ +	SNDRV_CHMAP_MONO,	/* mono stream */ +	/* this follows the alsa-lib mixer channel value + 3 */ +	SNDRV_CHMAP_FL,		/* front left */ +	SNDRV_CHMAP_FR,		/* front right */ +	SNDRV_CHMAP_RL,		/* rear left */ +	SNDRV_CHMAP_RR,		/* rear right */ +	SNDRV_CHMAP_FC,		/* front center */ +	SNDRV_CHMAP_LFE,	/* LFE */ +	SNDRV_CHMAP_SL,		/* side left */ +	SNDRV_CHMAP_SR,		/* side right */ +	SNDRV_CHMAP_RC,		/* rear center */ +	/* new definitions */ +	SNDRV_CHMAP_FLC,	/* front left center */ +	SNDRV_CHMAP_FRC,	/* front right center */ +	SNDRV_CHMAP_RLC,	/* rear left center */ +	SNDRV_CHMAP_RRC,	/* rear right center */ +	SNDRV_CHMAP_FLW,	/* front left wide */ +	SNDRV_CHMAP_FRW,	/* front right wide */ +	SNDRV_CHMAP_FLH,	/* front left high */ +	SNDRV_CHMAP_FCH,	/* front center high */ +	SNDRV_CHMAP_FRH,	/* front right high */ +	SNDRV_CHMAP_TC,		/* top center */ +	SNDRV_CHMAP_TFL,	/* top front left */ +	SNDRV_CHMAP_TFR,	/* top front right */ +	SNDRV_CHMAP_TFC,	/* top front center */ +	SNDRV_CHMAP_TRL,	/* top rear left */ +	SNDRV_CHMAP_TRR,	/* top rear right */ +	SNDRV_CHMAP_TRC,	/* top rear center */ +	SNDRV_CHMAP_LAST = SNDRV_CHMAP_TRC, +}; + +#define SNDRV_CHMAP_POSITION_MASK	0xffff +#define SNDRV_CHMAP_PHASE_INVERSE	(0x01 << 16) +#define SNDRV_CHMAP_DRIVER_SPEC		(0x02 << 16) +  #define SNDRV_PCM_IOCTL_PVERSION	_IOR('A', 0x00, int)  #define SNDRV_PCM_IOCTL_INFO		_IOR('A', 0x01, struct snd_pcm_info)  #define SNDRV_PCM_IOCTL_TSTAMP		_IOW('A', 0x02, int) diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h index 48f2a1ff2bb..f2912abacdf 100644 --- a/include/sound/compress_driver.h +++ b/include/sound/compress_driver.h @@ -61,6 +61,7 @@ struct snd_compr_runtime {  	u64 total_bytes_available;  	u64 total_bytes_transferred;  	wait_queue_head_t sleep; +	void *private_data;  };  /** diff --git a/include/sound/compress_params.h b/include/sound/compress_params.h index da4a456de03..602dc6c45d1 100644 --- a/include/sound/compress_params.h +++ b/include/sound/compress_params.h @@ -72,6 +72,7 @@  #define SND_AUDIOCODEC_IEC61937              ((__u32) 0x0000000B)  #define SND_AUDIOCODEC_G723_1                ((__u32) 0x0000000C)  #define SND_AUDIOCODEC_G729                  ((__u32) 0x0000000D) +#define SND_AUDIOCODEC_MAX                   SND_AUDIOCODEC_G729  /*   * Profile and modes are listed with bit masks. This allows for a diff --git a/include/sound/da9055.h b/include/sound/da9055.h new file mode 100644 index 00000000000..cf1241b64d8 --- /dev/null +++ b/include/sound/da9055.h @@ -0,0 +1,33 @@ +/* + * DA9055 ALSA Soc codec driver + * + * Copyright (c) 2012 Dialog Semiconductor + * + * Tested on (Samsung SMDK6410 board + DA9055 EVB) using I2S and I2C + * Written by David Chen <david.chen@diasemi.com> and + * Ashish Chavan <ashish.chavan@kpitcummins.com> + * + * 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. + */ + +#ifndef __SOUND_DA9055_H__ +#define __SOUND_DA9055_H__ + +enum da9055_micbias_voltage { +	DA9055_MICBIAS_1_6V = 0, +	DA9055_MICBIAS_1_8V = 1, +	DA9055_MICBIAS_2_1V = 2, +	DA9055_MICBIAS_2_2V = 3, +}; + +struct da9055_platform_data { +	/* Selects which of the two MicBias pins acts as the bias source */ +	bool micbias_source; +	/* Selects the micbias voltage */ +	enum da9055_micbias_voltage micbias; +}; + +#endif diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 4f865df42f0..1a33f48ebe7 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -1788,7 +1788,7 @@ struct snd_emu10k1 {  	unsigned int efx_voices_mask[2];  	unsigned int next_free_voice; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	unsigned int *saved_ptr;  	unsigned int *saved_gpr;  	unsigned int *tram_val_saved; @@ -1856,7 +1856,7 @@ unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg);  void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data);  unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  void snd_emu10k1_suspend_regs(struct snd_emu10k1 *emu);  void snd_emu10k1_resume_init(struct snd_emu10k1 *emu);  void snd_emu10k1_resume_regs(struct snd_emu10k1 *emu); diff --git a/include/sound/initval.h b/include/sound/initval.h index f99a0d2ddfe..ac62c67e6f4 100644 --- a/include/sound/initval.h +++ b/include/sound/initval.h @@ -50,6 +50,20 @@  #define SNDRV_DEFAULT_DMA_SIZE	{ [0 ... (SNDRV_CARDS-1)] = SNDRV_AUTO_DMA_SIZE }  #define SNDRV_DEFAULT_PTR	SNDRV_DEFAULT_STR +#ifdef SNDRV_LEGACY_FIND_FREE_IOPORT +static long snd_legacy_find_free_ioport(long *port_table, long size) +{ +	while (*port_table != -1) { +		if (request_region(*port_table, size, "ALSA test")) { +			release_region(*port_table, size); +			return *port_table; +		} +		port_table++; +	} +	return -1; +} +#endif +  #ifdef SNDRV_LEGACY_FIND_FREE_IRQ  #include <linux/interrupt.h> diff --git a/include/sound/memalloc.h b/include/sound/memalloc.h index c4250621264..844af65af62 100644 --- a/include/sound/memalloc.h +++ b/include/sound/memalloc.h @@ -98,8 +98,10 @@ static inline unsigned int snd_sgbuf_aligned_pages(size_t size)  /*   * return the physical address at the corresponding offset   */ -static inline dma_addr_t snd_sgbuf_get_addr(struct snd_sg_buf *sgbuf, size_t offset) +static inline dma_addr_t snd_sgbuf_get_addr(struct snd_dma_buffer *dmab, +					   size_t offset)  { +	struct snd_sg_buf *sgbuf = dmab->private_data;  	dma_addr_t addr = sgbuf->table[offset >> PAGE_SHIFT].addr;  	addr &= PAGE_MASK;  	return addr + offset % PAGE_SIZE; @@ -108,10 +110,31 @@ static inline dma_addr_t snd_sgbuf_get_addr(struct snd_sg_buf *sgbuf, size_t off  /*   * return the virtual address at the corresponding offset   */ -static inline void *snd_sgbuf_get_ptr(struct snd_sg_buf *sgbuf, size_t offset) +static inline void *snd_sgbuf_get_ptr(struct snd_dma_buffer *dmab, +				     size_t offset)  { +	struct snd_sg_buf *sgbuf = dmab->private_data;  	return sgbuf->table[offset >> PAGE_SHIFT].buf + offset % PAGE_SIZE;  } + +unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab, +				      unsigned int ofs, unsigned int size); +#else +/* non-SG versions */ +static inline dma_addr_t snd_sgbuf_get_addr(struct snd_dma_buffer *dmab, +					    size_t offset) +{ +	return dmab->addr + offset; +} + +static inline void *snd_sgbuf_get_ptr(struct snd_dma_buffer *dmab, +				      size_t offset) +{ +	return dmab->area + offset; +} + +#define snd_sgbuf_get_chunk_size(dmab, ofs, size)	(size) +  #endif /* CONFIG_SND_DMA_SGBUF */  /* allocate/release a buffer */ diff --git a/include/sound/pcm.h b/include/sound/pcm.h index d0711bc8c91..6268a4192d5 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -437,6 +437,7 @@ struct snd_pcm_str {  	struct snd_info_entry *proc_xrun_debug_entry;  #endif  #endif +	struct snd_kcontrol *chmap_kctl; /* channel-mapping controls */  };  struct snd_pcm { @@ -982,53 +983,42 @@ static int snd_pcm_lib_alloc_vmalloc_32_buffer  	_snd_pcm_lib_alloc_vmalloc_buffer \  			(subs, size, GFP_KERNEL | GFP_DMA32 | __GFP_ZERO) +#define snd_pcm_get_dma_buf(substream) ((substream)->runtime->dma_buffer_p) +  #ifdef CONFIG_SND_DMA_SGBUF  /*   * SG-buffer handling   */  #define snd_pcm_substream_sgbuf(substream) \ -	((substream)->runtime->dma_buffer_p->private_data) - -static inline dma_addr_t -snd_pcm_sgbuf_get_addr(struct snd_pcm_substream *substream, unsigned int ofs) -{ -	struct snd_sg_buf *sg = snd_pcm_substream_sgbuf(substream); -	return snd_sgbuf_get_addr(sg, ofs); -} - -static inline void * -snd_pcm_sgbuf_get_ptr(struct snd_pcm_substream *substream, unsigned int ofs) -{ -	struct snd_sg_buf *sg = snd_pcm_substream_sgbuf(substream); -	return snd_sgbuf_get_ptr(sg, ofs); -} +	snd_pcm_get_dma_buf(substream)->private_data  struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream,  				    unsigned long offset); -unsigned int snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream, -					  unsigned int ofs, unsigned int size); -  #else /* !SND_DMA_SGBUF */  /*   * fake using a continuous buffer   */ +#define snd_pcm_sgbuf_ops_page	NULL +#endif /* SND_DMA_SGBUF */ +  static inline dma_addr_t  snd_pcm_sgbuf_get_addr(struct snd_pcm_substream *substream, unsigned int ofs)  { -	return substream->runtime->dma_addr + ofs; +	return snd_sgbuf_get_addr(snd_pcm_get_dma_buf(substream), ofs);  }  static inline void *  snd_pcm_sgbuf_get_ptr(struct snd_pcm_substream *substream, unsigned int ofs)  { -	return substream->runtime->dma_area + ofs; +	return snd_sgbuf_get_ptr(snd_pcm_get_dma_buf(substream), ofs);  } -#define snd_pcm_sgbuf_ops_page	NULL - -#define snd_pcm_sgbuf_get_chunk_size(subs, ofs, size)	(size) - -#endif /* SND_DMA_SGBUF */ +static inline unsigned int +snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream, +			     unsigned int ofs, unsigned int size) +{ +	return snd_sgbuf_get_chunk_size(snd_pcm_get_dma_buf(substream), ofs, size); +}  /* handle mmap counter - PCM mmap callback should handle this counter properly */  static inline void snd_pcm_mmap_data_open(struct vm_area_struct *area) @@ -1086,4 +1076,51 @@ static inline const char *snd_pcm_stream_str(struct snd_pcm_substream *substream  		return "Capture";  } +/* + * PCM channel-mapping control API + */ +/* array element of channel maps */ +struct snd_pcm_chmap_elem { +	unsigned char channels; +	unsigned char map[15]; +}; + +/* channel map information; retrieved via snd_kcontrol_chip() */ +struct snd_pcm_chmap { +	struct snd_pcm *pcm;	/* assigned PCM instance */ +	int stream;		/* PLAYBACK or CAPTURE */ +	struct snd_kcontrol *kctl; +	const struct snd_pcm_chmap_elem *chmap; +	unsigned int max_channels; +	unsigned int channel_mask;	/* optional: active channels bitmask */ +	void *private_data;	/* optional: private data pointer */ +}; + +/* get the PCM substream assigned to the given chmap info */ +static inline struct snd_pcm_substream * +snd_pcm_chmap_substream(struct snd_pcm_chmap *info, unsigned int idx) +{ +	struct snd_pcm_substream *s; +	for (s = info->pcm->streams[info->stream].substream; s; s = s->next) +		if (s->number == idx) +			return s; +	return NULL; +} + +/* ALSA-standard channel maps (RL/RR prior to C/LFE) */ +extern const struct snd_pcm_chmap_elem snd_pcm_std_chmaps[]; +/* Other world's standard channel maps (C/LFE prior to RL/RR) */ +extern const struct snd_pcm_chmap_elem snd_pcm_alt_chmaps[]; + +/* bit masks to be passed to snd_pcm_chmap.channel_mask field */ +#define SND_PCM_CHMAP_MASK_24	((1U << 2) | (1U << 4)) +#define SND_PCM_CHMAP_MASK_246	(SND_PCM_CHMAP_MASK_24 | (1U << 6)) +#define SND_PCM_CHMAP_MASK_2468	(SND_PCM_CHMAP_MASK_246 | (1U << 8)) + +int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream, +			   const struct snd_pcm_chmap_elem *chmap, +			   int max_channels, +			   unsigned long private_value, +			   struct snd_pcm_chmap **info_ret); +  #endif /* __SOUND_PCM_H */ diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 1f69e0af294..628db7bca4f 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -18,6 +18,7 @@  struct snd_pcm_substream;  struct snd_soc_dapm_widget; +struct snd_compr_stream;  /*   * DAI hardware audio formats. @@ -205,6 +206,8 @@ struct snd_soc_dai_driver {  	int (*remove)(struct snd_soc_dai *dai);  	int (*suspend)(struct snd_soc_dai *dai);  	int (*resume)(struct snd_soc_dai *dai); +	/* compress dai */ +	bool compress_dai;  	/* ops */  	const struct snd_soc_dai_ops *ops; diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index abe373d57ad..e1ef63d4a5c 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -244,10 +244,11 @@ struct device;  {	.id = snd_soc_dapm_supply, .name = wname, .reg = wreg,	\  	.shift = wshift, .invert = winvert, .event = wevent, \  	.event_flags = wflags} -#define SND_SOC_DAPM_REGULATOR_SUPPLY(wname, wdelay) \ +#define SND_SOC_DAPM_REGULATOR_SUPPLY(wname, wdelay, wflags)	    \  {	.id = snd_soc_dapm_regulator_supply, .name = wname, \  	.reg = SND_SOC_NOPM, .shift = wdelay, .event = dapm_regulator_event, \ -	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD } +	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \ +	.invert = wflags}  /* dapm kcontrol types */ @@ -319,6 +320,9 @@ struct device;  #define SND_SOC_DAPM_EVENT_OFF(e)	\  	(e & (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD)) +/* regulator widget flags */ +#define SND_SOC_DAPM_REGULATOR_BYPASS     0x1     /* bypass when disabled */ +  struct snd_soc_dapm_widget;  enum snd_soc_dapm_type;  struct snd_soc_dapm_path; @@ -412,6 +416,7 @@ void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec);  /* Mostly internal - should not normally be used */  void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason); +void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm);  /* dapm path query */  int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, @@ -510,7 +515,6 @@ struct snd_soc_dapm_widget {  	/* dapm control */  	int reg;				/* negative reg = no direct dapm */  	unsigned char shift;			/* bits to shift */ -	unsigned int saved_value;		/* widget saved value */  	unsigned int value;				/* widget current value */  	unsigned int mask;			/* non-shifted mask */  	unsigned int on_val;			/* on state value */ diff --git a/include/sound/soc.h b/include/sound/soc.h index e063380f63a..91244a096c1 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -20,8 +20,10 @@  #include <linux/interrupt.h>  #include <linux/kernel.h>  #include <linux/regmap.h> +#include <linux/log2.h>  #include <sound/core.h>  #include <sound/pcm.h> +#include <sound/compress_driver.h>  #include <sound/control.h>  #include <sound/ac97_codec.h> @@ -159,7 +161,8 @@  		 .platform_max = xmax} }  #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmax, xtexts) \  {	.reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \ -	.max = xmax, .texts = xtexts } +	.max = xmax, .texts = xtexts, \ +	.mask = xmax ? roundup_pow_of_two(xmax) - 1 : 0}  #define SOC_ENUM_SINGLE(xreg, xshift, xmax, xtexts) \  	SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmax, xtexts)  #define SOC_ENUM_SINGLE_EXT(xmax, xtexts) \ @@ -399,6 +402,7 @@ int snd_soc_platform_read(struct snd_soc_platform *platform,  int snd_soc_platform_write(struct snd_soc_platform *platform,  					unsigned int reg, unsigned int val);  int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num); +int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num);  struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,  		const char *dai_link, int stream); @@ -632,6 +636,13 @@ struct snd_soc_ops {  	int (*trigger)(struct snd_pcm_substream *, int);  }; +struct snd_soc_compr_ops { +	int (*startup)(struct snd_compr_stream *); +	void (*shutdown)(struct snd_compr_stream *); +	int (*set_params)(struct snd_compr_stream *); +	int (*trigger)(struct snd_compr_stream *); +}; +  /* SoC cache ops */  struct snd_soc_cache_ops {  	const char *name; @@ -787,9 +798,12 @@ struct snd_soc_platform_driver {  	snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *,  		struct snd_soc_dai *); -	/* platform stream ops */ +	/* platform stream pcm ops */  	struct snd_pcm_ops *ops; +	/* platform stream compress ops */ +	struct snd_compr_ops *compr_ops; +  	/* platform stream completion event */  	int (*stream_event)(struct snd_soc_dapm_context *dapm, int event); @@ -891,6 +905,7 @@ struct snd_soc_dai_link {  	/* machine stream operations */  	struct snd_soc_ops *ops; +	struct snd_soc_compr_ops *compr_ops;  };  struct snd_soc_codec_conf { @@ -1027,6 +1042,7 @@ struct snd_soc_pcm_runtime {  	/* runtime devices */  	struct snd_pcm *pcm; +	struct snd_compr *compr;  	struct snd_soc_codec *codec;  	struct snd_soc_platform *platform;  	struct snd_soc_dai *codec_dai; diff --git a/arch/arm/mach-tegra/include/mach/tegra_wm8903_pdata.h b/include/sound/tegra_wm8903.h index 9d293344a7f..57b202ee97c 100644 --- a/arch/arm/mach-tegra/include/mach/tegra_wm8903_pdata.h +++ b/include/sound/tegra_wm8903.h @@ -1,6 +1,4 @@  /* - * arch/arm/mach-tegra/include/mach/tegra_wm8903_pdata.h - *   * Copyright 2011 NVIDIA, Inc.   *   * This software is licensed under the terms of the GNU General Public @@ -14,6 +12,9 @@   *   */ +#ifndef __SOUND_TEGRA_WM38903_H +#define __SOUND_TEGRA_WM38903_H +  struct tegra_wm8903_platform_data {  	int gpio_spkr_en;  	int gpio_hp_det; @@ -21,3 +22,5 @@ struct tegra_wm8903_platform_data {  	int gpio_int_mic_en;  	int gpio_ext_mic_en;  }; + +#endif diff --git a/include/sound/tlv.h b/include/sound/tlv.h index a64d8fe3f85..28c65e1ada2 100644 --- a/include/sound/tlv.h +++ b/include/sound/tlv.h @@ -86,4 +86,12 @@  #define TLV_DB_GAIN_MUTE	-9999999 +/* + * channel-mapping TLV items + *  TLV length must match with num_channels + */ +#define SNDRV_CTL_TLVT_CHMAP_FIXED	0x101	/* fixed channel position */ +#define SNDRV_CTL_TLVT_CHMAP_VAR	0x102	/* channels freely swappable */ +#define SNDRV_CTL_TLVT_CHMAP_PAIRED	0x103	/* pair-wise swappable */ +  #endif /* __SOUND_TLV_H */ diff --git a/include/sound/version.h b/include/sound/version.h deleted file mode 100644 index cc75024c108..00000000000 --- a/include/sound/version.h +++ /dev/null @@ -1,3 +0,0 @@ -/* include/version.h */ -#define CONFIG_SND_VERSION "1.0.25" -#define CONFIG_SND_DATE "" diff --git a/include/sound/wm0010.h b/include/sound/wm0010.h new file mode 100644 index 00000000000..3261e90815a --- /dev/null +++ b/include/sound/wm0010.h @@ -0,0 +1,27 @@ +/* + * wm0010.h -- Platform data for WM0010 DSP Driver + * + * Copyright 2012 Wolfson Microelectronics PLC. + * + * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com> + * + * 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. + */ + +#ifndef WM0010_PDATA_H +#define WM0010_PDATA_H + +struct wm0010_pdata { +	int gpio_reset; + +	/* Set if there is an inverter between the GPIO controlling +	 * the reset signal and the device. +	 */ +	int reset_active_high; +	int irq_flags; +}; + +#endif diff --git a/include/sound/wm8960.h b/include/sound/wm8960.h index 74e9a95529c..e8ce8ee7d62 100644 --- a/include/sound/wm8960.h +++ b/include/sound/wm8960.h @@ -18,7 +18,7 @@  struct wm8960_data {  	bool capless;  /* Headphone outputs configured in capless mode */ -	int dres;  /* Discharge resistance for headphone outputs */ +	bool shared_lrclk;  /* DAC and ADC LRCLKs are wired together */  };  #endif diff --git a/include/sound/wm8993.h b/include/sound/wm8993.h index eee19f63c0d..8016fd826f5 100644 --- a/include/sound/wm8993.h +++ b/include/sound/wm8993.h @@ -32,6 +32,10 @@ struct wm8993_platform_data {  	unsigned int lineout1fb:1;  	unsigned int lineout2fb:1; +	/* Delay to add for microphones to stabalise after power up */ +	int micbias1_delay; +	int micbias2_delay; +  	/* Microphone biases: 0=0.9*AVDD1 1=0.65*AVVD1 */  	unsigned int micbias1_lvl:1;  	unsigned int micbias2_lvl:1; diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index eb60cb8dbb8..c40ae573346 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -425,6 +425,26 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,  	return 0;  } +static int snd_compress_check_input(struct snd_compr_params *params) +{ +	/* first let's check the buffer parameter's */ +	if (params->buffer.fragment_size == 0 || +			params->buffer.fragments > SIZE_MAX / params->buffer.fragment_size) +		return -EINVAL; + +	/* now codec parameters */ +	if (params->codec.id == 0 || params->codec.id > SND_AUDIOCODEC_MAX) +		return -EINVAL; + +	if (params->codec.ch_in == 0 || params->codec.ch_out == 0) +		return -EINVAL; + +	if (!(params->codec.sample_rate & SNDRV_PCM_RATE_8000_192000)) +		return -EINVAL; + +	return 0; +} +  static int  snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)  { @@ -443,11 +463,17 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)  			retval = -EFAULT;  			goto out;  		} + +		retval = snd_compress_check_input(params); +		if (retval) +			goto out; +  		retval = snd_compr_allocate_buffer(stream, params);  		if (retval) {  			retval = -ENOMEM;  			goto out;  		} +  		retval = stream->ops->set_params(stream, params);  		if (retval)  			goto out; diff --git a/sound/core/control.c b/sound/core/control.c index 2487a6bb1c5..7e86a5b9f3b 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -246,6 +246,7 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,  	kctl.count = ncontrol->count ? ncontrol->count : 1;  	access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :  		 (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE| +				      SNDRV_CTL_ELEM_ACCESS_VOLATILE|  				      SNDRV_CTL_ELEM_ACCESS_INACTIVE|  				      SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE|  				      SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND| diff --git a/sound/core/info.c b/sound/core/info.c index c1e611c65c8..6b368d25073 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -28,7 +28,7 @@  #include <sound/core.h>  #include <sound/minors.h>  #include <sound/info.h> -#include <sound/version.h> +#include <linux/utsname.h>  #include <linux/proc_fs.h>  #include <linux/mutex.h>  #include <stdarg.h> @@ -986,9 +986,8 @@ static struct snd_info_entry *snd_info_version_entry;  static void snd_info_version_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)  {  	snd_iprintf(buffer, -		    "Advanced Linux Sound Architecture Driver Version " -		    CONFIG_SND_VERSION CONFIG_SND_DATE ".\n" -		   ); +		    "Advanced Linux Sound Architecture Driver Version k%s.\n", +		    init_utsname()->release);  }  static int __init snd_info_version_init(void) diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c index cf42ab5080e..83c29dbff9c 100644 --- a/sound/core/info_oss.c +++ b/sound/core/info_oss.c @@ -26,7 +26,6 @@  #include <sound/core.h>  #include <sound/minors.h>  #include <sound/info.h> -#include <sound/version.h>  #include <linux/utsname.h>  #include <linux/mutex.h> @@ -94,7 +93,7 @@ static int snd_sndstat_show_strings(struct snd_info_buffer *buf, char *id, int d  static void snd_sndstat_proc_read(struct snd_info_entry *entry,  				  struct snd_info_buffer *buffer)  { -	snd_iprintf(buffer, "Sound Driver:3.8.1a-980706 (ALSA v" CONFIG_SND_VERSION " emulation code)\n"); +	snd_iprintf(buffer, "Sound Driver:3.8.1a-980706 (ALSA emulation code)\n");  	snd_iprintf(buffer, "Kernel: %s %s %s %s %s\n",  		    init_utsname()->sysname,  		    init_utsname()->nodename, diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 18297f7f2c5..29f6ded0255 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -1046,6 +1046,7 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, struct snd_mix  		if (kctl->info(kctl, uinfo)) {  			up_read(&mixer->card->controls_rwsem); +			kfree(uinfo);  			return 0;  		}  		strcpy(str, ptr->name); @@ -1061,6 +1062,7 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, struct snd_mix  				uinfo->value.enumerated.item = slot.capture_item;  				if (kctl->info(kctl, uinfo)) {  					up_read(&mixer->card->controls_rwsem); +					kfree(uinfo);  					return 0;  				}  				if (!strcmp(uinfo->value.enumerated.name, str)) { diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 1a3070b4e5b..f2991940b27 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -1105,6 +1105,10 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)  			break;  		}  		snd_unregister_device(devtype, pcm->card, pcm->device); +		if (pcm->streams[cidx].chmap_kctl) { +			snd_ctl_remove(pcm->card, pcm->streams[cidx].chmap_kctl); +			pcm->streams[cidx].chmap_kctl = NULL; +		}  	}   unlock:  	mutex_unlock(®ister_mutex); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 7ae67192339..f42c10a4331 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -26,6 +26,7 @@  #include <linux/export.h>  #include <sound/core.h>  #include <sound/control.h> +#include <sound/tlv.h>  #include <sound/info.h>  #include <sound/pcm.h>  #include <sound/pcm_params.h> @@ -2302,3 +2303,216 @@ snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream,  }  EXPORT_SYMBOL(snd_pcm_lib_readv); + +/* + * standard channel mapping helpers + */ + +/* default channel maps for multi-channel playbacks, up to 8 channels */ +const struct snd_pcm_chmap_elem snd_pcm_std_chmaps[] = { +	{ .channels = 1, +	  .map = { SNDRV_CHMAP_MONO } }, +	{ .channels = 2, +	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } }, +	{ .channels = 4, +	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, +		   SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } }, +	{ .channels = 6, +	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, +		   SNDRV_CHMAP_RL, SNDRV_CHMAP_RR, +		   SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE } }, +	{ .channels = 8, +	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, +		   SNDRV_CHMAP_RL, SNDRV_CHMAP_RR, +		   SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE, +		   SNDRV_CHMAP_SL, SNDRV_CHMAP_SR } }, +	{ } +}; +EXPORT_SYMBOL_GPL(snd_pcm_std_chmaps); + +/* alternative channel maps with CLFE <-> surround swapped for 6/8 channels */ +const struct snd_pcm_chmap_elem snd_pcm_alt_chmaps[] = { +	{ .channels = 1, +	  .map = { SNDRV_CHMAP_MONO } }, +	{ .channels = 2, +	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } }, +	{ .channels = 4, +	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, +		   SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } }, +	{ .channels = 6, +	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, +		   SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE, +		   SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } }, +	{ .channels = 8, +	  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, +		   SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE, +		   SNDRV_CHMAP_RL, SNDRV_CHMAP_RR, +		   SNDRV_CHMAP_SL, SNDRV_CHMAP_SR } }, +	{ } +}; +EXPORT_SYMBOL_GPL(snd_pcm_alt_chmaps); + +static bool valid_chmap_channels(const struct snd_pcm_chmap *info, int ch) +{ +	if (ch > info->max_channels) +		return false; +	return !info->channel_mask || (info->channel_mask & (1U << ch)); +} + +static int pcm_chmap_ctl_info(struct snd_kcontrol *kcontrol, +			      struct snd_ctl_elem_info *uinfo) +{ +	struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); + +	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; +	uinfo->count = 0; +	uinfo->count = info->max_channels; +	uinfo->value.integer.min = 0; +	uinfo->value.integer.max = SNDRV_CHMAP_LAST; +	return 0; +} + +/* get callback for channel map ctl element + * stores the channel position firstly matching with the current channels + */ +static int pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol, +			     struct snd_ctl_elem_value *ucontrol) +{ +	struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); +	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); +	struct snd_pcm_substream *substream; +	const struct snd_pcm_chmap_elem *map; + +	if (snd_BUG_ON(!info->chmap)) +		return -EINVAL; +	substream = snd_pcm_chmap_substream(info, idx); +	if (!substream) +		return -ENODEV; +	memset(ucontrol->value.integer.value, 0, +	       sizeof(ucontrol->value.integer.value)); +	if (!substream->runtime) +		return 0; /* no channels set */ +	for (map = info->chmap; map->channels; map++) { +		int i; +		if (map->channels == substream->runtime->channels && +		    valid_chmap_channels(info, map->channels)) { +			for (i = 0; i < map->channels; i++) +				ucontrol->value.integer.value[i] = map->map[i]; +			return 0; +		} +	} +	return -EINVAL; +} + +/* tlv callback for channel map ctl element + * expands the pre-defined channel maps in a form of TLV + */ +static int pcm_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag, +			     unsigned int size, unsigned int __user *tlv) +{ +	struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); +	const struct snd_pcm_chmap_elem *map; +	unsigned int __user *dst; +	int c, count = 0; + +	if (snd_BUG_ON(!info->chmap)) +		return -EINVAL; +	if (size < 8) +		return -ENOMEM; +	if (put_user(SNDRV_CTL_TLVT_CONTAINER, tlv)) +		return -EFAULT; +	size -= 8; +	dst = tlv + 2; +	for (map = info->chmap; map->channels; map++) { +		int chs_bytes = map->channels * 4; +		if (!valid_chmap_channels(info, map->channels)) +			continue; +		if (size < 8) +			return -ENOMEM; +		if (put_user(SNDRV_CTL_TLVT_CHMAP_FIXED, dst) || +		    put_user(chs_bytes, dst + 1)) +			return -EFAULT; +		dst += 2; +		size -= 8; +		count += 8; +		if (size < chs_bytes) +			return -ENOMEM; +		size -= chs_bytes; +		count += chs_bytes; +		for (c = 0; c < map->channels; c++) { +			if (put_user(map->map[c], dst)) +				return -EFAULT; +			dst++; +		} +	} +	if (put_user(count, tlv + 1)) +		return -EFAULT; +	return 0; +} + +static void pcm_chmap_ctl_private_free(struct snd_kcontrol *kcontrol) +{ +	struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); +	info->pcm->streams[info->stream].chmap_kctl = NULL; +	kfree(info); +} + +/** + * snd_pcm_add_chmap_ctls - create channel-mapping control elements + * @pcm: the assigned PCM instance + * @stream: stream direction + * @chmap: channel map elements (for query) + * @max_channels: the max number of channels for the stream + * @private_value: the value passed to each kcontrol's private_value field + * @info_ret: store struct snd_pcm_chmap instance if non-NULL + * + * Create channel-mapping control elements assigned to the given PCM stream(s). + * Returns zero if succeed, or a negative error value. + */ +int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream, +			   const struct snd_pcm_chmap_elem *chmap, +			   int max_channels, +			   unsigned long private_value, +			   struct snd_pcm_chmap **info_ret) +{ +	struct snd_pcm_chmap *info; +	struct snd_kcontrol_new knew = { +		.iface = SNDRV_CTL_ELEM_IFACE_PCM, +		.access = SNDRV_CTL_ELEM_ACCESS_READ | +			SNDRV_CTL_ELEM_ACCESS_TLV_READ | +			SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, +		.info = pcm_chmap_ctl_info, +		.get = pcm_chmap_ctl_get, +		.tlv.c = pcm_chmap_ctl_tlv, +	}; +	int err; + +	info = kzalloc(sizeof(*info), GFP_KERNEL); +	if (!info) +		return -ENOMEM; +	info->pcm = pcm; +	info->stream = stream; +	info->chmap = chmap; +	info->max_channels = max_channels; +	if (stream == SNDRV_PCM_STREAM_PLAYBACK) +		knew.name = "Playback Channel Map"; +	else +		knew.name = "Capture Channel Map"; +	knew.device = pcm->device; +	knew.count = pcm->streams[stream].substream_count; +	knew.private_value = private_value; +	info->kctl = snd_ctl_new1(&knew, info); +	if (!info->kctl) { +		kfree(info); +		return -ENOMEM; +	} +	info->kctl->private_free = pcm_chmap_ctl_private_free; +	err = snd_ctl_add(pcm->card, info->kctl); +	if (err < 0) +		return err; +	pcm->streams[stream].chmap_kctl = info->kctl; +	if (info_ret) +		*info_ret = info; +	return 0; +} +EXPORT_SYMBOL_GPL(snd_pcm_add_chmap_ctls); diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 957131366dd..69e01c4fc32 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -327,32 +327,6 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigne  }  EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page); - -/* - * compute the max chunk size with continuous pages on sg-buffer - */ -unsigned int snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream, -					  unsigned int ofs, unsigned int size) -{ -	struct snd_sg_buf *sg = snd_pcm_substream_sgbuf(substream); -	unsigned int start, end, pg; - -	start = ofs >> PAGE_SHIFT; -	end = (ofs + size - 1) >> PAGE_SHIFT; -	/* check page continuity */ -	pg = sg->table[start].addr >> PAGE_SHIFT; -	for (;;) { -		start++; -		if (start > end) -			break; -		pg++; -		if ((sg->table[start].addr >> PAGE_SHIFT) != pg) -			return (start << PAGE_SHIFT) - ofs; -	} -	/* ok, all on continuous pages */ -	return size; -} -EXPORT_SYMBOL(snd_pcm_sgbuf_get_chunk_size);  #endif /* CONFIG_SND_DMA_SGBUF */  /** diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index 5cf8d65ed5e..60e8fc1b344 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c @@ -569,5 +569,7 @@ EXPORT_SYMBOL(snd_seq_device_load_drivers);  EXPORT_SYMBOL(snd_seq_device_new);  EXPORT_SYMBOL(snd_seq_device_register_driver);  EXPORT_SYMBOL(snd_seq_device_unregister_driver); +#ifdef CONFIG_MODULES  EXPORT_SYMBOL(snd_seq_autoload_lock);  EXPORT_SYMBOL(snd_seq_autoload_unlock); +#endif diff --git a/sound/core/sgbuf.c b/sound/core/sgbuf.c index d0f00356fc1..0a418503ec4 100644 --- a/sound/core/sgbuf.c +++ b/sound/core/sgbuf.c @@ -22,6 +22,7 @@  #include <linux/slab.h>  #include <linux/mm.h>  #include <linux/vmalloc.h> +#include <linux/export.h>  #include <sound/memalloc.h> @@ -136,3 +137,29 @@ void *snd_malloc_sgbuf_pages(struct device *device,  	snd_free_sgbuf_pages(dmab); /* free the table */  	return NULL;  } + +/* + * compute the max chunk size with continuous pages on sg-buffer + */ +unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab, +				      unsigned int ofs, unsigned int size) +{ +	struct snd_sg_buf *sg = dmab->private_data; +	unsigned int start, end, pg; + +	start = ofs >> PAGE_SHIFT; +	end = (ofs + size - 1) >> PAGE_SHIFT; +	/* check page continuity */ +	pg = sg->table[start].addr >> PAGE_SHIFT; +	for (;;) { +		start++; +		if (start > end) +			break; +		pg++; +		if ((sg->table[start].addr >> PAGE_SHIFT) != pg) +			return (start << PAGE_SHIFT) - ofs; +	} +	/* ok, all on continuous pages */ +	return size; +} +EXPORT_SYMBOL(snd_sgbuf_get_chunk_size); diff --git a/sound/core/sound.c b/sound/core/sound.c index 28f35593a75..643976000ce 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -27,7 +27,6 @@  #include <sound/core.h>  #include <sound/minors.h>  #include <sound/info.h> -#include <sound/version.h>  #include <sound/control.h>  #include <sound/initval.h>  #include <linux/kmod.h> @@ -468,7 +467,7 @@ static int __init alsa_sound_init(void)  	}  	snd_info_minor_register();  #ifndef MODULE -	printk(KERN_INFO "Advanced Linux Sound Architecture Driver Version " CONFIG_SND_VERSION CONFIG_SND_DATE ".\n"); +	printk(KERN_INFO "Advanced Linux Sound Architecture Driver Initialized.\n");  #endif  	return 0;  } diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 5a34355e78e..0fe6d64ff84 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -120,6 +120,7 @@ struct loopback_pcm {  	unsigned int last_drift;  	unsigned long last_jiffies;  	struct timer_list timer; +	spinlock_t timer_lock;  };  static struct platform_device *devices[SNDRV_CARDS]; @@ -170,6 +171,7 @@ static void loopback_timer_start(struct loopback_pcm *dpcm)  	unsigned long tick;  	unsigned int rate_shift = get_rate_shift(dpcm); +	spin_lock(&dpcm->timer_lock);  	if (rate_shift != dpcm->pcm_rate_shift) {  		dpcm->pcm_rate_shift = rate_shift;  		dpcm->period_size_frac = frac_pos(dpcm, dpcm->pcm_period_size); @@ -182,12 +184,15 @@ static void loopback_timer_start(struct loopback_pcm *dpcm)  	tick = (tick + dpcm->pcm_bps - 1) / dpcm->pcm_bps;  	dpcm->timer.expires = jiffies + tick;  	add_timer(&dpcm->timer); +	spin_unlock(&dpcm->timer_lock);  }  static inline void loopback_timer_stop(struct loopback_pcm *dpcm)  { +	spin_lock(&dpcm->timer_lock);  	del_timer(&dpcm->timer);  	dpcm->timer.expires = 0; +	spin_unlock(&dpcm->timer_lock);  }  #define CABLE_VALID_PLAYBACK	(1 << SNDRV_PCM_STREAM_PLAYBACK) @@ -667,6 +672,7 @@ static int loopback_open(struct snd_pcm_substream *substream)  	dpcm->substream = substream;  	setup_timer(&dpcm->timer, loopback_timer_function,  		    (unsigned long)dpcm); +	spin_lock_init(&dpcm->timer_lock);  	cable = loopback->cables[substream->number][dev];  	if (!cable) { diff --git a/sound/drivers/opl3/opl3_midi.c b/sound/drivers/opl3/opl3_midi.c index 2bfe4bcb7a7..0c796bcbc0a 100644 --- a/sound/drivers/opl3/opl3_midi.c +++ b/sound/drivers/opl3/opl3_midi.c @@ -163,7 +163,7 @@ static int opl3_get_voice(struct snd_opl3 *opl3, int instr_4op,  	struct best *bp;  	for (i = 0; i < END; i++) { -		best[i].time = (unsigned int)(-1); /* XXX MAX_?INT really */; +		best[i].time = (unsigned int)(-1); /* XXX MAX_?INT really */  		best[i].voice = -1;  	} diff --git a/sound/drivers/opl4/opl4_synth.c b/sound/drivers/opl4/opl4_synth.c index 49b9e240915..4b91adc0238 100644 --- a/sound/drivers/opl4/opl4_synth.c +++ b/sound/drivers/opl4/opl4_synth.c @@ -504,8 +504,7 @@ void snd_opl4_note_on(void *private_data, int note, int vel, struct snd_midi_cha  	spin_lock_irqsave(&opl4->reg_lock, flags);  	for (i = 0; i < voices; i++) {  		voice[i] = snd_opl4_get_voice(opl4); -		list_del(&voice[i]->list); -		list_add_tail(&voice[i]->list, &opl4->on_voices); +		list_move_tail(&voice[i]->list, &opl4->on_voices);  		voice[i]->chan = chan;  		voice[i]->note = note;  		voice[i]->velocity = vel & 0x7f; @@ -555,8 +554,7 @@ void snd_opl4_note_on(void *private_data, int note, int vel, struct snd_midi_cha  static void snd_opl4_voice_off(struct snd_opl4 *opl4, struct opl4_voice *voice)  { -	list_del(&voice->list); -	list_add_tail(&voice->list, &opl4->off_voices); +	list_move_tail(&voice->list, &opl4->off_voices);  	voice->reg_misc &= ~OPL4_KEY_ON_BIT;  	snd_opl4_write(opl4, OPL4_REG_MISC + voice->number, voice->reg_misc); @@ -571,8 +569,7 @@ void snd_opl4_note_off(void *private_data, int note, int vel, struct snd_midi_ch  static void snd_opl4_terminate_voice(struct snd_opl4 *opl4, struct opl4_voice *voice)  { -	list_del(&voice->list); -	list_add_tail(&voice->list, &opl4->off_voices); +	list_move_tail(&voice->list, &opl4->off_voices);  	voice->reg_misc = (voice->reg_misc & ~OPL4_KEY_ON_BIT) | OPL4_DAMP_BIT;  	snd_opl4_write(opl4, OPL4_REG_MISC + voice->number, voice->reg_misc); diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index 5e897b236ce..deed5efff33 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c @@ -184,7 +184,7 @@ static int vx_set_format(struct vx_core *chip, struct vx_pipe *pipe,  	default :   		snd_BUG();  		return -EINVAL; -        }; +	}  	return vx_set_stream_format(chip, pipe, header);  } diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 52064cfa91f..a38d9643e9d 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -117,6 +117,18 @@ config SND_AZT2320  	  To compile this driver as a module, choose M here: the module  	  will be called snd-azt2320. +config SND_CMI8328 +	tristate "C-Media CMI8328" +	select SND_WSS_LIB +	select SND_OPL3_LIB +	select SND_MPU401_UART +	help +	  Say Y here to include support for soundcards based on the +	  C-Media CMI8328 chip. + +	  To compile this driver as a module, choose M here: the module +	  will be called snd-cmi8328. +  config SND_CMI8330  	tristate "C-Media CMI8330"  	select SND_WSS_LIB diff --git a/sound/isa/Makefile b/sound/isa/Makefile index 8d781e419e2..9a15f1497b1 100644 --- a/sound/isa/Makefile +++ b/sound/isa/Makefile @@ -6,6 +6,7 @@  snd-adlib-objs := adlib.o  snd-als100-objs := als100.o  snd-azt2320-objs := azt2320.o +snd-cmi8328-objs := cmi8328.o  snd-cmi8330-objs := cmi8330.o  snd-es18xx-objs := es18xx.o  snd-opl3sa2-objs := opl3sa2.o @@ -16,6 +17,7 @@ snd-sscape-objs := sscape.o  obj-$(CONFIG_SND_ADLIB) += snd-adlib.o  obj-$(CONFIG_SND_ALS100) += snd-als100.o  obj-$(CONFIG_SND_AZT2320) += snd-azt2320.o +obj-$(CONFIG_SND_CMI8328) += snd-cmi8328.o  obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o  obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o  obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c index 94b83b6e46a..2c2f829c3fd 100644 --- a/sound/isa/ad1816a/ad1816a.c +++ b/sound/isa/ad1816a/ad1816a.c @@ -63,11 +63,6 @@ MODULE_PARM_DESC(enable, "Enable ad1816a based soundcard.");  module_param_array(clockfreq, int, NULL, 0444);  MODULE_PARM_DESC(clockfreq, "Clock frequency for ad1816a driver (default = 0)."); -struct snd_card_ad1816a { -	struct pnp_dev *dev; -	struct pnp_dev *devmpu; -}; -  static struct pnp_card_device_id snd_ad1816a_pnpids[] = {  	/* Analog Devices AD1815 */  	{ .id = "ADS7150", .devs = { { .id = "ADS7150" }, { .id = "ADS7151" } } }, @@ -99,25 +94,16 @@ MODULE_DEVICE_TABLE(pnp_card, snd_ad1816a_pnpids);  #define	DRIVER_NAME	"snd-card-ad1816a" -static int __devinit snd_card_ad1816a_pnp(int dev, struct snd_card_ad1816a *acard, -					  struct pnp_card_link *card, +static int __devinit snd_card_ad1816a_pnp(int dev, struct pnp_card_link *card,  					  const struct pnp_card_device_id *id)  {  	struct pnp_dev *pdev;  	int err; -	acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL); -	if (acard->dev == NULL) +	pdev = pnp_request_card_device(card, id->devs[0].id, NULL); +	if (pdev == NULL)  		return -EBUSY; -	acard->devmpu = pnp_request_card_device(card, id->devs[1].id, NULL); -	if (acard->devmpu == NULL) { -		mpu_port[dev] = -1; -		snd_printk(KERN_WARNING PFX "MPU401 device busy, skipping.\n"); -	} - -	pdev = acard->dev; -  	err = pnp_activate_dev(pdev);  	if (err < 0) {  		printk(KERN_ERR PFX "AUDIO PnP configure failure\n"); @@ -130,16 +116,17 @@ static int __devinit snd_card_ad1816a_pnp(int dev, struct snd_card_ad1816a *acar  	dma2[dev] = pnp_dma(pdev, 1);  	irq[dev] = pnp_irq(pdev, 0); -	if (acard->devmpu == NULL) +	pdev = pnp_request_card_device(card, id->devs[1].id, NULL); +	if (pdev == NULL) { +		mpu_port[dev] = -1; +		snd_printk(KERN_WARNING PFX "MPU401 device busy, skipping.\n");  		return 0; - -	pdev = acard->devmpu; +	}  	err = pnp_activate_dev(pdev);  	if (err < 0) {  		printk(KERN_ERR PFX "MPU401 PnP configure failure\n");  		mpu_port[dev] = -1; -		acard->devmpu = NULL;  	} else {  		mpu_port[dev] = pnp_port_start(pdev, 0);  		mpu_irq[dev] = pnp_irq(pdev, 0); @@ -153,18 +140,17 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard  {  	int error;  	struct snd_card *card; -	struct snd_card_ad1816a *acard;  	struct snd_ad1816a *chip;  	struct snd_opl3 *opl3;  	struct snd_timer *timer;  	error = snd_card_create(index[dev], id[dev], THIS_MODULE, -				sizeof(struct snd_card_ad1816a), &card); +				sizeof(struct snd_ad1816a), &card);  	if (error < 0)  		return error; -	acard = card->private_data; +	chip = card->private_data; -	if ((error = snd_card_ad1816a_pnp(dev, acard, pcard, pid))) { +	if ((error = snd_card_ad1816a_pnp(dev, pcard, pid))) {  		snd_card_free(card);  		return error;  	} @@ -174,7 +160,7 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard  					irq[dev],  					dma1[dev],  					dma2[dev], -					&chip)) < 0) { +					chip)) < 0) {  		snd_card_free(card);  		return error;  	} @@ -258,13 +244,37 @@ static void __devexit snd_ad1816a_pnp_remove(struct pnp_card_link * pcard)  	pnp_set_card_drvdata(pcard, NULL);  } +#ifdef CONFIG_PM +static int snd_ad1816a_pnp_suspend(struct pnp_card_link *pcard, +				   pm_message_t state) +{ +	struct snd_card *card = pnp_get_card_drvdata(pcard); + +	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); +	snd_ad1816a_suspend(card->private_data); +	return 0; +} + +static int snd_ad1816a_pnp_resume(struct pnp_card_link *pcard) +{ +	struct snd_card *card = pnp_get_card_drvdata(pcard); + +	snd_ad1816a_resume(card->private_data); +	snd_power_change_state(card, SNDRV_CTL_POWER_D0); +	return 0; +} +#endif +  static struct pnp_card_driver ad1816a_pnpc_driver = {  	.flags		= PNP_DRIVER_RES_DISABLE,  	.name		= "ad1816a",  	.id_table	= snd_ad1816a_pnpids,  	.probe		= snd_ad1816a_pnp_detect,  	.remove		= __devexit_p(snd_ad1816a_pnp_remove), -	/* FIXME: suspend/resume */ +#ifdef CONFIG_PM +	.suspend	= snd_ad1816a_pnp_suspend, +	.resume		= snd_ad1816a_pnp_resume, +#endif  };  static int __init alsa_card_ad1816a_init(void) diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c index 177eed3271b..db64df6023e 100644 --- a/sound/isa/ad1816a/ad1816a_lib.c +++ b/sound/isa/ad1816a/ad1816a_lib.c @@ -491,7 +491,7 @@ static int snd_ad1816a_capture_close(struct snd_pcm_substream *substream)  } -static void __devinit snd_ad1816a_init(struct snd_ad1816a *chip) +static void snd_ad1816a_init(struct snd_ad1816a *chip)  {  	unsigned long flags; @@ -511,6 +511,32 @@ static void __devinit snd_ad1816a_init(struct snd_ad1816a *chip)  	spin_unlock_irqrestore(&chip->lock, flags);  } +#ifdef CONFIG_PM +void snd_ad1816a_suspend(struct snd_ad1816a *chip) +{ +	int reg; +	unsigned long flags; + +	snd_pcm_suspend_all(chip->pcm); +	spin_lock_irqsave(&chip->lock, flags); +	for (reg = 0; reg < 48; reg++) +		chip->image[reg] = snd_ad1816a_read(chip, reg); +	spin_unlock_irqrestore(&chip->lock, flags); +} + +void snd_ad1816a_resume(struct snd_ad1816a *chip) +{ +	int reg; +	unsigned long flags; + +	snd_ad1816a_init(chip); +	spin_lock_irqsave(&chip->lock, flags); +	for (reg = 0; reg < 48; reg++) +		snd_ad1816a_write(chip, reg, chip->image[reg]); +	spin_unlock_irqrestore(&chip->lock, flags); +} +#endif +  static int __devinit snd_ad1816a_probe(struct snd_ad1816a *chip)  {  	unsigned long flags; @@ -548,7 +574,6 @@ static int snd_ad1816a_free(struct snd_ad1816a *chip)  		snd_dma_disable(chip->dma2);  		free_dma(chip->dma2);  	} -	kfree(chip);  	return 0;  } @@ -573,19 +598,13 @@ static const char __devinit *snd_ad1816a_chip_id(struct snd_ad1816a *chip)  int __devinit snd_ad1816a_create(struct snd_card *card,  				 unsigned long port, int irq, int dma1, int dma2, -				 struct snd_ad1816a **rchip) +				 struct snd_ad1816a *chip)  {          static struct snd_device_ops ops = {  		.dev_free =	snd_ad1816a_dev_free,  	};  	int error; -	struct snd_ad1816a *chip; - -	*rchip = NULL; -	chip = kzalloc(sizeof(*chip), GFP_KERNEL); -	if (chip == NULL) -		return -ENOMEM;  	chip->irq = -1;  	chip->dma1 = -1;  	chip->dma2 = -1; @@ -631,7 +650,6 @@ int __devinit snd_ad1816a_create(struct snd_card *card,  		return error;  	} -	*rchip = chip;  	return 0;  } diff --git a/sound/isa/cmi8328.c b/sound/isa/cmi8328.c new file mode 100644 index 00000000000..bde60139bb9 --- /dev/null +++ b/sound/isa/cmi8328.c @@ -0,0 +1,483 @@ +/* + * Driver for C-Media CMI8328-based soundcards, such as AudioExcel AV500 + * Copyright (c) 2012 Ondrej Zary + * + * AudioExcel AV500 card consists of: + *  - CMI8328 - main chip (SB Pro emulation, gameport, OPL3, MPU401, CD-ROM) + *  - CS4231A - WSS codec + *  - Dream SAM9233+GMS950400+RAM+ROM: Wavetable MIDI, connected to MPU401 + */ + +#include <linux/init.h> +#include <linux/isa.h> +#include <linux/module.h> +#include <linux/gameport.h> +#include <asm/dma.h> +#include <sound/core.h> +#include <sound/wss.h> +#include <sound/opl3.h> +#include <sound/mpu401.h> +#define SNDRV_LEGACY_FIND_FREE_IOPORT +#define SNDRV_LEGACY_FIND_FREE_IRQ +#define SNDRV_LEGACY_FIND_FREE_DMA +#include <sound/initval.h> + +MODULE_AUTHOR("Ondrej Zary <linux@rainbow-software.org>"); +MODULE_DESCRIPTION("C-Media CMI8328"); +MODULE_LICENSE("GPL"); + +#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE) +#define SUPPORT_JOYSTICK 1 +#endif + +/* I/O port is configured by jumpers on the card to one of these */ +static int cmi8328_ports[] = { 0x530, 0xe80, 0xf40, 0x604 }; +#define CMI8328_MAX	ARRAY_SIZE(cmi8328_ports) + +static int index[CMI8328_MAX] =     {[0 ... (CMI8328_MAX-1)] = -1}; +static char *id[CMI8328_MAX] =      {[0 ... (CMI8328_MAX-1)] = NULL}; +static long port[CMI8328_MAX] =     {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_PORT}; +static int irq[CMI8328_MAX] =       {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_IRQ}; +static int dma1[CMI8328_MAX] =      {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_DMA}; +static int dma2[CMI8328_MAX] =      {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_DMA}; +static long mpuport[CMI8328_MAX] =  {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_PORT}; +static int mpuirq[CMI8328_MAX] =    {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_IRQ}; +#ifdef SUPPORT_JOYSTICK +static bool gameport[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = true}; +#endif + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for CMI8328 soundcard."); +module_param_array(id, charp, NULL, 0444); +MODULE_PARM_DESC(id, "ID string for CMI8328 soundcard."); + +module_param_array(port, long, NULL, 0444); +MODULE_PARM_DESC(port, "Port # for CMI8328 driver."); +module_param_array(irq, int, NULL, 0444); +MODULE_PARM_DESC(irq, "IRQ # for CMI8328 driver."); +module_param_array(dma1, int, NULL, 0444); +MODULE_PARM_DESC(dma1, "DMA1 for CMI8328 driver."); +module_param_array(dma2, int, NULL, 0444); +MODULE_PARM_DESC(dma2, "DMA2 for CMI8328 driver."); + +module_param_array(mpuport, long, NULL, 0444); +MODULE_PARM_DESC(mpuport, "MPU-401 port # for CMI8328 driver."); +module_param_array(mpuirq, int, NULL, 0444); +MODULE_PARM_DESC(mpuirq, "IRQ # for CMI8328 MPU-401 port."); +#ifdef SUPPORT_JOYSTICK +module_param_array(gameport, bool, NULL, 0444); +MODULE_PARM_DESC(gameport, "Enable gameport."); +#endif + +struct snd_cmi8328 { +	u16 port; +	u8 cfg[3]; +	u8 wss_cfg; +	struct snd_card *card; +	struct snd_wss *wss; +#ifdef SUPPORT_JOYSTICK +	struct gameport *gameport; +#endif +}; + +/* CMI8328 configuration registers */ +#define CFG1 0x61 +#define CFG1_SB_DISABLE	(1 << 0) +#define CFG1_GAMEPORT	(1 << 1) +/* + * bit 0:    SB: 0=enabled, 1=disabled + * bit 1:    gameport: 0=disabled, 1=enabled + * bits 2-4: SB IRQ: 001=3, 010=5, 011=7, 100=9, 101=10, 110=11 + * bits 5-6: SB DMA: 00=disabled (when SB disabled), 01=DMA0, 10=DMA1, 11=DMA3 + * bit 7:    SB port: 0=0x220, 1=0x240 + */ +#define CFG2 0x62 +#define CFG2_MPU_ENABLE (1 << 2) +/* + * bits 0-1: CD-ROM mode: 00=disabled, 01=Panasonic, 10=Sony/Mitsumi/Wearnes, +			  11=IDE + * bit 2:    MPU401: 0=disabled, 1=enabled + * bits 3-4: MPU401 IRQ: 00=3, 01=5, 10=7, 11=9, + * bits 5-7: MPU401 port: 000=0x300, 001=0x310, 010=0x320, 011=0x330, 100=0x332, +			  101=0x334, 110=0x336 + */ +#define CFG3 0x63 +/* + * bits 0-2: CD-ROM IRQ: 000=disabled, 001=3, 010=5, 011=7, 100=9, 101=10, +			 110=11 + * bits 3-4: CD-ROM DMA: 00=disabled, 01=DMA0, 10=DMA1, 11=DMA3 + * bits 5-7: CD-ROM port: 000=0x300, 001=0x310, 010=0x320, 011=0x330, 100=0x340, +			  101=0x350, 110=0x360, 111=0x370 + */ + +static u8 snd_cmi8328_cfg_read(u16 port, u8 reg) +{ +	outb(0x43, port + 3); +	outb(0x21, port + 3); +	outb(reg, port + 3); +	return inb(port); +} + +static void snd_cmi8328_cfg_write(u16 port, u8 reg, u8 val) +{ +	outb(0x43, port + 3); +	outb(0x21, port + 3); +	outb(reg, port + 3); +	outb(val, port + 3);	/* yes, value goes to the same port as index */ +} + +static void snd_cmi8328_cfg_save(u16 port, u8 cfg[]) +{ +	cfg[0] = snd_cmi8328_cfg_read(port, CFG1); +	cfg[1] = snd_cmi8328_cfg_read(port, CFG2); +	cfg[2] = snd_cmi8328_cfg_read(port, CFG3); +} + +static void snd_cmi8328_cfg_restore(u16 port, u8 cfg[]) +{ +	snd_cmi8328_cfg_write(port, CFG1, cfg[0]); +	snd_cmi8328_cfg_write(port, CFG2, cfg[1]); +	snd_cmi8328_cfg_write(port, CFG3, cfg[2]); +} + +static int __devinit snd_cmi8328_mixer(struct snd_wss *chip) +{ +	struct snd_card *card; +	struct snd_ctl_elem_id id1, id2; +	int err; + +	card = chip->card; + +	memset(&id1, 0, sizeof(id1)); +	memset(&id2, 0, sizeof(id2)); +	id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER; +	/* rename AUX0 switch to CD */ +	strcpy(id1.name, "Aux Playback Switch"); +	strcpy(id2.name, "CD Playback Switch"); +	err = snd_ctl_rename_id(card, &id1, &id2); +	if (err < 0) { +		snd_printk(KERN_ERR "error renaming control\n"); +		return err; +	} +	/* rename AUX0 volume to CD */ +	strcpy(id1.name, "Aux Playback Volume"); +	strcpy(id2.name, "CD Playback Volume"); +	err = snd_ctl_rename_id(card, &id1, &id2); +	if (err < 0) { +		snd_printk(KERN_ERR "error renaming control\n"); +		return err; +	} +	/* rename AUX1 switch to Synth */ +	strcpy(id1.name, "Aux Playback Switch"); +	id1.index = 1; +	strcpy(id2.name, "Synth Playback Switch"); +	err = snd_ctl_rename_id(card, &id1, &id2); +	if (err < 0) { +		snd_printk(KERN_ERR "error renaming control\n"); +		return err; +	} +	/* rename AUX1 volume to Synth */ +	strcpy(id1.name, "Aux Playback Volume"); +	id1.index = 1; +	strcpy(id2.name, "Synth Playback Volume"); +	err = snd_ctl_rename_id(card, &id1, &id2); +	if (err < 0) { +		snd_printk(KERN_ERR "error renaming control\n"); +		return err; +	} + +	return 0; +} + +/* find index of an item in "-1"-ended array */ +int array_find(int array[], int item) +{ +	int i; + +	for (i = 0; array[i] != -1; i++) +		if (array[i] == item) +			return i; + +	return -1; +} +/* the same for long */ +int array_find_l(long array[], long item) +{ +	int i; + +	for (i = 0; array[i] != -1; i++) +		if (array[i] == item) +			return i; + +	return -1; +} + +static int __devinit snd_cmi8328_probe(struct device *pdev, unsigned int ndev) +{ +	struct snd_card *card; +	struct snd_opl3 *opl3; +	struct snd_cmi8328 *cmi; +#ifdef SUPPORT_JOYSTICK +	struct resource *res; +#endif +	int err, pos; +	static long mpu_ports[] = { 0x330, 0x300, 0x310, 0x320, 0x332, 0x334, +				   0x336, -1 }; +	static u8 mpu_port_bits[] = { 3, 0, 1, 2, 4, 5, 6 }; +	static int mpu_irqs[] = { 9, 7, 5, 3, -1 }; +	static u8 mpu_irq_bits[] = { 3, 2, 1, 0 }; +	static int irqs[] = { 9, 10, 11, 7, -1 }; +	static u8 irq_bits[] = { 2, 3, 4, 1 }; +	static int dma1s[] = { 3, 1, 0, -1 }; +	static u8 dma_bits[] = { 3, 2, 1 }; +	static int dma2s[][2] = { {1, -1}, {0, -1}, {-1, -1}, {0, -1} }; +	u16 port = cmi8328_ports[ndev]; +	u8 val; + +	/* 0xff is invalid configuration (but settable - hope it isn't set) */ +	if (snd_cmi8328_cfg_read(port, CFG1) == 0xff) +		return -ENODEV; +	/* the SB disable bit must NEVER EVER be cleared or the WSS dies */ +	snd_cmi8328_cfg_write(port, CFG1, CFG1_SB_DISABLE); +	if (snd_cmi8328_cfg_read(port, CFG1) != CFG1_SB_DISABLE) +		return -ENODEV; +	/* disable everything first */ +	snd_cmi8328_cfg_write(port, CFG2, 0);	/* disable CDROM and MPU401 */ +	snd_cmi8328_cfg_write(port, CFG3, 0);	/* disable CDROM IRQ and DMA */ + +	if (irq[ndev] == SNDRV_AUTO_IRQ) { +		irq[ndev] = snd_legacy_find_free_irq(irqs); +		if (irq[ndev] < 0) { +			snd_printk(KERN_ERR "unable to find a free IRQ\n"); +			return -EBUSY; +		} +	} +	if (dma1[ndev] == SNDRV_AUTO_DMA) { +		dma1[ndev] = snd_legacy_find_free_dma(dma1s); +		if (dma1[ndev] < 0) { +			snd_printk(KERN_ERR "unable to find a free DMA1\n"); +			return -EBUSY; +		} +	} +	if (dma2[ndev] == SNDRV_AUTO_DMA) { +		dma2[ndev] = snd_legacy_find_free_dma(dma2s[dma1[ndev] % 4]); +		if (dma2[ndev] < 0) { +			snd_printk(KERN_WARNING "unable to find a free DMA2, full-duplex will not work\n"); +			dma2[ndev] = -1; +		} +	} +	/* configure WSS IRQ... */ +	pos = array_find(irqs, irq[ndev]); +	if (pos < 0) { +		snd_printk(KERN_ERR "invalid IRQ %d\n", irq[ndev]); +		return -EINVAL; +	} +	val = irq_bits[pos] << 3; +	/* ...and DMA... */ +	pos = array_find(dma1s, dma1[ndev]); +	if (pos < 0) { +		snd_printk(KERN_ERR "invalid DMA1 %d\n", dma1[ndev]); +		return -EINVAL; +	} +	val |= dma_bits[pos]; +	/* ...and DMA2 */ +	if (dma2[ndev] >= 0 && dma1[ndev] != dma2[ndev]) { +		pos = array_find(dma2s[dma1[ndev]], dma2[ndev]); +		if (pos < 0) { +			snd_printk(KERN_ERR "invalid DMA2 %d\n", dma2[ndev]); +			return -EINVAL; +		} +		val |= 0x04; /* enable separate capture DMA */ +	} +	outb(val, port); + +	err = snd_card_create(index[ndev], id[ndev], THIS_MODULE, +				sizeof(struct snd_cmi8328), &card); +	if (err < 0) +		return err; +	cmi = card->private_data; +	cmi->card = card; +	cmi->port = port; +	cmi->wss_cfg = val; +	snd_card_set_dev(card, pdev); + +	err = snd_wss_create(card, port + 4, -1, irq[ndev], dma1[ndev], +			dma2[ndev], WSS_HW_DETECT, 0, &cmi->wss); +	if (err < 0) +		goto error; + +	err = snd_wss_pcm(cmi->wss, 0, NULL); +	if (err < 0) +		goto error; + +	err = snd_wss_mixer(cmi->wss); +	if (err < 0) +		goto error; +	err = snd_cmi8328_mixer(cmi->wss); +	if (err < 0) +		goto error; + +	if (snd_wss_timer(cmi->wss, 0, NULL) < 0) +		snd_printk(KERN_WARNING "error initializing WSS timer\n"); + +	if (mpuport[ndev] == SNDRV_AUTO_PORT) { +		mpuport[ndev] = snd_legacy_find_free_ioport(mpu_ports, 2); +		if (mpuport[ndev] < 0) +			snd_printk(KERN_ERR "unable to find a free MPU401 port\n"); +	} +	if (mpuirq[ndev] == SNDRV_AUTO_IRQ) { +		mpuirq[ndev] = snd_legacy_find_free_irq(mpu_irqs); +		if (mpuirq[ndev] < 0) +			snd_printk(KERN_ERR "unable to find a free MPU401 IRQ\n"); +	} +	/* enable and configure MPU401 */ +	if (mpuport[ndev] > 0 && mpuirq[ndev] > 0) { +		val = CFG2_MPU_ENABLE; +		pos = array_find_l(mpu_ports, mpuport[ndev]); +		if (pos < 0) +			snd_printk(KERN_WARNING "invalid MPU401 port 0x%lx\n", +								mpuport[ndev]); +		else { +			val |= mpu_port_bits[pos] << 5; +			pos = array_find(mpu_irqs, mpuirq[ndev]); +			if (pos < 0) +				snd_printk(KERN_WARNING "invalid MPU401 IRQ %d\n", +								mpuirq[ndev]); +			else { +				val |= mpu_irq_bits[pos] << 3; +				snd_cmi8328_cfg_write(port, CFG2, val); +				if (snd_mpu401_uart_new(card, 0, +						MPU401_HW_MPU401, mpuport[ndev], +						0, mpuirq[ndev], NULL) < 0) +					snd_printk(KERN_ERR "error initializing MPU401\n"); +			} +		} +	} +	/* OPL3 is hardwired to 0x388 and cannot be disabled */ +	if (snd_opl3_create(card, 0x388, 0x38a, OPL3_HW_AUTO, 0, &opl3) < 0) +		snd_printk(KERN_ERR "error initializing OPL3\n"); +	else +		if (snd_opl3_hwdep_new(opl3, 0, 1, NULL) < 0) +			snd_printk(KERN_WARNING "error initializing OPL3 hwdep\n"); + +	strcpy(card->driver, "CMI8328"); +	strcpy(card->shortname, "C-Media CMI8328"); +	sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d,%d", +		card->shortname, cmi->wss->port, irq[ndev], dma1[ndev], +		(dma2[ndev] >= 0) ? dma2[ndev] : dma1[ndev]); + +	dev_set_drvdata(pdev, card); +	err = snd_card_register(card); +	if (err < 0) +		goto error; +#ifdef SUPPORT_JOYSTICK +	if (!gameport[ndev]) +		return 0; +	/* gameport is hardwired to 0x200 */ +	res = request_region(0x200, 8, "CMI8328 gameport"); +	if (!res) +		snd_printk(KERN_WARNING "unable to allocate gameport I/O port\n"); +	else { +		struct gameport *gp = cmi->gameport = gameport_allocate_port(); +		if (!cmi->gameport) +			release_and_free_resource(res); +		else { +			gameport_set_name(gp, "CMI8328 Gameport"); +			gameport_set_phys(gp, "%s/gameport0", dev_name(pdev)); +			gameport_set_dev_parent(gp, pdev); +			gp->io = 0x200; +			gameport_set_port_data(gp, res); +			/* Enable gameport */ +			snd_cmi8328_cfg_write(port, CFG1, +					CFG1_SB_DISABLE | CFG1_GAMEPORT); +			gameport_register_port(gp); +		} +	} +#endif +	return 0; +error: +	snd_card_free(card); + +	return err; +} + +static int __devexit snd_cmi8328_remove(struct device *pdev, unsigned int dev) +{ +	struct snd_card *card = dev_get_drvdata(pdev); +	struct snd_cmi8328 *cmi = card->private_data; + +#ifdef SUPPORT_JOYSTICK +	if (cmi->gameport) { +		struct resource *res = gameport_get_port_data(cmi->gameport); +		gameport_unregister_port(cmi->gameport); +		release_and_free_resource(res); +	} +#endif +	/* disable everything */ +	snd_cmi8328_cfg_write(cmi->port, CFG1, CFG1_SB_DISABLE); +	snd_cmi8328_cfg_write(cmi->port, CFG2, 0); +	snd_cmi8328_cfg_write(cmi->port, CFG3, 0); +	snd_card_free(card); +	dev_set_drvdata(pdev, NULL); +	return 0; +} + +#ifdef CONFIG_PM +static int snd_cmi8328_suspend(struct device *pdev, unsigned int n, +				pm_message_t state) +{ +	struct snd_card *card = dev_get_drvdata(pdev); +	struct snd_cmi8328 *cmi; + +	if (!card)	/* ignore absent devices */ +		return 0; +	cmi = card->private_data; +	snd_cmi8328_cfg_save(cmi->port, cmi->cfg); +	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); +	snd_pcm_suspend_all(cmi->wss->pcm); +	cmi->wss->suspend(cmi->wss); + +	return 0; +} + +static int snd_cmi8328_resume(struct device *pdev, unsigned int n) +{ +	struct snd_card *card = dev_get_drvdata(pdev); +	struct snd_cmi8328 *cmi; + +	if (!card)	/* ignore absent devices */ +		return 0; +	cmi = card->private_data; +	snd_cmi8328_cfg_restore(cmi->port, cmi->cfg); +	outb(cmi->wss_cfg, cmi->port); +	cmi->wss->resume(cmi->wss); +	snd_power_change_state(card, SNDRV_CTL_POWER_D0); + +	return 0; +} +#endif + +static struct isa_driver snd_cmi8328_driver = { +	.probe		= snd_cmi8328_probe, +	.remove		= __devexit_p(snd_cmi8328_remove), +#ifdef CONFIG_PM +	.suspend	= snd_cmi8328_suspend, +	.resume		= snd_cmi8328_resume, +#endif +	.driver		= { +		.name	= "cmi8328" +	}, +}; + +static int __init alsa_card_cmi8328_init(void) +{ +	return isa_register_driver(&snd_cmi8328_driver, CMI8328_MAX); +} + +static void __exit alsa_card_cmi8328_exit(void) +{ +	isa_unregister_driver(&snd_cmi8328_driver); +} + +module_init(alsa_card_cmi8328_init) +module_exit(alsa_card_cmi8328_exit) diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c index a76bc8d27c1..3fc8b66fd16 100644 --- a/sound/isa/gus/interwave.c +++ b/sound/isa/gus/interwave.c @@ -443,9 +443,8 @@ static void __devinit snd_interwave_detect_memory(struct snd_gus_card * gus)  		for (i = 0; i < 8; ++i)  			iwave[i] = snd_gf1_peek(gus, bank_pos + i);  #ifdef CONFIG_SND_DEBUG_ROM -		printk(KERN_DEBUG "ROM at 0x%06x = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", bank_pos, -		       iwave[0], iwave[1], iwave[2], iwave[3], -		       iwave[4], iwave[5], iwave[6], iwave[7]); +		printk(KERN_DEBUG "ROM at 0x%06x = %*phC\n", bank_pos, +				  8, iwave);  #endif  		if (strncmp(iwave, "INTRWAVE", 8))  			continue;	/* first check */ diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index c24594c866f..3d1afb612b3 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -37,6 +37,7 @@  #include <sound/opl4.h>  #include <sound/control.h>  #include <sound/info.h> +#define SNDRV_LEGACY_FIND_FREE_IOPORT  #define SNDRV_LEGACY_FIND_FREE_IRQ  #define SNDRV_LEGACY_FIND_FREE_DMA  #include <sound/initval.h> @@ -770,20 +771,6 @@ static int __devinit snd_miro_mixer(struct snd_card *card,  	return 0;  } -static long snd_legacy_find_free_ioport(long *port_table, long size) -{ -	while (*port_table != -1) { -		struct resource *res; -		if ((res = request_region(*port_table, size,  -					  "ALSA test")) != NULL) { -			release_and_free_resource(res); -			return *port_table; -		} -		port_table++; -	} -	return -1; -} -  static int __devinit snd_miro_init(struct snd_miro *chip,  				   unsigned short hardware)  { diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index f8fbe22515c..2899c9fd1ce 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -39,6 +39,7 @@  #ifndef OPTi93X  #include <sound/opl4.h>  #endif +#define SNDRV_LEGACY_FIND_FREE_IOPORT  #define SNDRV_LEGACY_FIND_FREE_IRQ  #define SNDRV_LEGACY_FIND_FREE_DMA  #include <sound/initval.h> @@ -185,19 +186,6 @@ static char * snd_opti9xx_names[] = {  	"82C930",	"82C931",	"82C933"  }; - -static long __devinit snd_legacy_find_free_ioport(long *port_table, long size) -{ -	while (*port_table != -1) { -		if (request_region(*port_table, size, "ALSA test")) { -			release_region(*port_table, size); -			return *port_table; -		} -		port_table++; -	} -	return -1; -} -  static int __devinit snd_opti9xx_init(struct snd_opti9xx *chip,  				      unsigned short hardware)  { diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c index 71887874679..2aae6a0efbc 100644 --- a/sound/isa/sb/emu8000.c +++ b/sound/isa/sb/emu8000.c @@ -417,9 +417,6 @@ size_dram(struct snd_emu8000 *emu)  		EMU8000_SMLD_READ(emu); /* discard stale data  */  		if (EMU8000_SMLD_READ(emu) != UNIQUE_ID2)  			break; /* no memory at this address */ - -		detected_size = size; -  		snd_emu8000_read_wait(emu);  		/* @@ -432,6 +429,18 @@ size_dram(struct snd_emu8000 *emu)  		if (EMU8000_SMLD_READ(emu) != UNIQUE_ID1)  			break; /* we must have wrapped around */  		snd_emu8000_read_wait(emu); + +		/* Otherwise, it's valid memory. */ +		detected_size = size + 512 * 1024; +	} + +	/* Distinguish 512 KiB from 0. */ +	if (detected_size == 0) { +		snd_emu8000_read_wait(emu); +		EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET); +		EMU8000_SMLD_READ(emu); /* discard stale data  */ +		if (EMU8000_SMLD_READ(emu) == UNIQUE_ID1) +			detected_size = 512 * 1024;  	}  	/* wait until FULL bit in SMAxW register is false */ diff --git a/sound/isa/sb/emu8000_callback.c b/sound/isa/sb/emu8000_callback.c index 344b4355be1..72a9ac5efb4 100644 --- a/sound/isa/sb/emu8000_callback.c +++ b/sound/isa/sb/emu8000_callback.c @@ -175,7 +175,7 @@ get_voice(struct snd_emux *emu, struct snd_emux_port *port)  	hw = emu->hw;  	for (i = 0; i < END; i++) { -		best[i].time = (unsigned int)(-1); /* XXX MAX_?INT really */; +		best[i].time = (unsigned int)(-1); /* XXX MAX_?INT really */  		best[i].voice = -1;  	} diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c index 405f8b6a58b..b1bf8d4e649 100644 --- a/sound/isa/wavefront/wavefront_synth.c +++ b/sound/isa/wavefront/wavefront_synth.c @@ -538,7 +538,7 @@ munge_int32 (unsigned int src,  	                            /* Note: we leave the upper bits in place */   		dst++; - 	}; +	}  	return dst;  }; diff --git a/sound/last.c b/sound/last.c index 7ffc182e084..43f22282503 100644 --- a/sound/last.c +++ b/sound/last.c @@ -19,7 +19,6 @@   *   */ -#define SNDRV_MAIN_OBJECT_FILE  #include <linux/init.h>  #include <sound/core.h> diff --git a/sound/oss/audio.c b/sound/oss/audio.c index 4b958b1c497..09c932f899b 100644 --- a/sound/oss/audio.c +++ b/sound/oss/audio.c @@ -354,7 +354,7 @@ int audio_read(int dev, struct file *file, char __user *buf, int count)  			if(copy_to_user(&(buf)[p], fixit, l))  				return -EFAULT; -		}; +		}  		DMAbuf_rmchars(dev, buf_no, l); diff --git a/sound/oss/opl3.c b/sound/oss/opl3.c index 407cd677950..c5c24409ceb 100644 --- a/sound/oss/opl3.c +++ b/sound/oss/opl3.c @@ -1190,7 +1190,7 @@ static int opl3_init(int ioaddr, struct module *owner)  		for (i = 0; i < 18; i++)  			pv_map[i].ioaddr = devc->left_io; -	}; +	}  	conf_printf2(devc->fm_info.name, ioaddr, 0, -1, -1);  	for (i = 0; i < SBFM_MAXINSTR; i++) diff --git a/sound/oss/pss.c b/sound/oss/pss.c index 0f32a561f15..145e36b2cfd 100644 --- a/sound/oss/pss.c +++ b/sound/oss/pss.c @@ -359,7 +359,7 @@ static int pss_download_boot(pss_confdata * devc, unsigned char *block, int size  		{  			/*_____ Send the next byte */  			outw (*block++, REG (PSS_DATA)); -		}; +		}  		count++;  	} diff --git a/sound/oss/sb_ess.c b/sound/oss/sb_ess.c index 5c773dff5ac..c0be085e4a2 100644 --- a/sound/oss/sb_ess.c +++ b/sound/oss/sb_ess.c @@ -1104,15 +1104,15 @@ int ess_init(sb_devc * devc, struct address_info *hw_config)  		default:  			printk (KERN_ERR "Invalid esstype=%d specified\n", devc->sbmo.esstype);  			return 0; -		}; +		}  		if (submodel != -1) {  			devc->submodel = submodel;  			sprintf (modelname, "ES%d", devc->sbmo.esstype);  			chip = modelname; -		}; +		}  		if (chip == NULL && (ess_minor & 0x0f) < 8) {  			chip = "ES688"; -		}; +		}  #ifdef FKS_TEST  FKS_test (devc);  #endif @@ -1122,7 +1122,7 @@ FKS_test (devc);  		 */  		if (chip == NULL && devc->sbmo.esstype == ESSTYPE_LIKE20) {  			chip = "ES1688"; -		}; +		}  		if (chip == NULL) {  			int type; @@ -1150,8 +1150,8 @@ FKS_test (devc);  				if ((type & 0x00ff) != ((type >> 8) & 0x00ff)) {  					printk ("ess_init: Unrecognized %04x\n", type);  				} -			}; -		}; +			} +		}  #if 0  		/*  		 * this one failed: @@ -1182,10 +1182,10 @@ FKS_test (devc);  				chip = "ES1788";  				devc->submodel = SUBMDL_ES1788;  			} -		}; +		}  		if (chip == NULL) {  			chip = "ES1688"; -		}; +		}  	    printk ( KERN_INFO "ESS chip %s %s%s\n"                 , chip @@ -1293,7 +1293,7 @@ printk(KERN_INFO "ess_set_dma_hw: dma8=%d,dma16=%d,dup=%d\n"  			default:  				printk(KERN_ERR "ESS1887: Invalid DMA16 %d\n", dma);  				return 0; -			}; +			}  			ess_chgmixer (devc, 0x78, 0x20, dma16_bits);  			ess_chgmixer (devc, 0x7d, 0x07, dma_bits);  		} @@ -1584,7 +1584,7 @@ printk(KERN_INFO "FKS: write mixer %x: %x\n", port, value);  		udelay(20);  		outb(((unsigned char) (value & 0xff)), MIXER_DATA);  		udelay(20); -	}; +	}  	spin_unlock_irqrestore(&devc->lock, flags);  } @@ -1761,7 +1761,7 @@ int ess_mixer_reset (sb_devc * devc)  			ess_chgmixer(devc, 0x7a, 0x18, 0x08);  			ess_chgmixer(devc, 0x1c, 0x07, 0x07);  			break; -		}; +		}  		/*  		 * Call set_recmask for proper initialization  		 */ diff --git a/sound/oss/sb_mixer.c b/sound/oss/sb_mixer.c index f8f3b7a66b7..acf7586aeb4 100644 --- a/sound/oss/sb_mixer.c +++ b/sound/oss/sb_mixer.c @@ -410,7 +410,7 @@ static int set_recmask(sb_devc * devc, int mask)  		case MDL_SMW:  			if (devc->model == MDL_ESS && ess_set_recmask (devc, &devmask)) {  				break; -			}; +			}  			if (devmask != SOUND_MASK_MIC &&  				devmask != SOUND_MASK_LINE &&  				devmask != SOUND_MASK_CD) @@ -666,7 +666,7 @@ static void sb_mixer_reset(sb_devc * devc)  	if (devc->model != MDL_ESS || !ess_mixer_reset (devc)) {  		set_recmask(devc, SOUND_MASK_MIC); -	}; +	}  }  int sb_mixer_init(sb_devc * devc, struct module *owner) diff --git a/sound/oss/sys_timer.c b/sound/oss/sys_timer.c index 8db6aefe15e..9f039831114 100644 --- a/sound/oss/sys_timer.c +++ b/sound/oss/sys_timer.c @@ -57,7 +57,7 @@ poll_def_tmr(unsigned long dummy)  		  {  			  def_tmr.expires = (1) + jiffies;  			  add_timer(&def_tmr); -		  }; +		  }  		  if (tmr_running)  		    { @@ -103,7 +103,7 @@ def_tmr_open(int dev, int mode)  	{  		def_tmr.expires = (1) + jiffies;  		add_timer(&def_tmr); -	}; +	}  	return 0;  } diff --git a/sound/oss/uart6850.c b/sound/oss/uart6850.c index f3f914aa92e..1079133dd6a 100644 --- a/sound/oss/uart6850.c +++ b/sound/oss/uart6850.c @@ -146,7 +146,7 @@ static int uart6850_open(int dev, int mode,  	{  /*		  printk("Midi6850: Midi busy\n");*/  		  return -EBUSY; -	}; +	}  	uart6850_cmd(UART_RESET);  	uart6850_input_loop(); diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index a872d0a8297..66a3bc95fb8 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -2595,6 +2595,21 @@ static void alc650_update_jacks(struct snd_ac97 *ac97)  			     shared ? 0 : 0x100);  } +static int alc650_swap_surround_put(struct snd_kcontrol *kcontrol, +				    struct snd_ctl_elem_value *ucontrol) +{ +	struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); +	struct snd_pcm_chmap *map = ac97->chmaps[SNDRV_PCM_STREAM_PLAYBACK]; + +	if (map) { +		if (ucontrol->value.integer.value[0]) +			map->chmap = snd_pcm_std_chmaps; +		else +			map->chmap = snd_pcm_alt_chmaps; +	} +	return snd_ac97_put_volsw(kcontrol, ucontrol); +} +  static const struct snd_kcontrol_new snd_ac97_controls_alc650[] = {  	AC97_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0),  	AC97_SINGLE("Surround Down Mix", AC97_ALC650_MULTICH, 1, 1, 0), @@ -2608,7 +2623,14 @@ static const struct snd_kcontrol_new snd_ac97_controls_alc650[] = {  	/* 9: Line-In/Surround share */  	/* 10: Mic/CLFE share */  	/* 11-13: in IEC958 controls */ -	AC97_SINGLE("Swap Surround Slot", AC97_ALC650_MULTICH, 14, 1, 0), +	{ +		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, +		.name = "Swap Surround Slot", +		.info = snd_ac97_info_volsw, +		.get = snd_ac97_get_volsw, +		.put = alc650_swap_surround_put, +		.private_value =  AC97_SINGLE_VALUE(AC97_ALC650_MULTICH, 14, 1, 0), +	},  #if 0 /* always set in patch_alc650 */  	AC97_SINGLE("IEC958 Input Clock Enable", AC97_ALC650_CLOCK, 0, 1, 0),  	AC97_SINGLE("IEC958 Input Pin Enable", AC97_ALC650_CLOCK, 1, 1, 0), diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index ee895f3c860..c7e3c533316 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -270,7 +270,7 @@ struct snd_ali {  	spinlock_t	reg_lock;  	spinlock_t	voice_alloc; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	struct snd_ali_image *image;  #endif  }; @@ -1883,7 +1883,7 @@ static int __devinit snd_ali_mixer(struct snd_ali * codec)  	return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int ali_suspend(struct device *dev)  {  	struct pci_dev *pci = to_pci_dev(dev); @@ -1989,7 +1989,7 @@ static SIMPLE_DEV_PM_OPS(ali_pm, ali_suspend, ali_resume);  #define ALI_PM_OPS	&ali_pm  #else  #define ALI_PM_OPS	NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  static int snd_ali_free(struct snd_ali * codec)  { @@ -2000,7 +2000,7 @@ static int snd_ali_free(struct snd_ali * codec)  	if (codec->port)  		pci_release_regions(codec->pci);  	pci_disable_device(codec->pci); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	kfree(codec->image);  #endif  	pci_dev_put(codec->pci_m1533); @@ -2232,7 +2232,7 @@ static int __devinit snd_ali_create(struct snd_card *card,  		return err;  	} -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	codec->image = kmalloc(sizeof(*codec->image), GFP_KERNEL);  	if (!codec->image)  		snd_printk(KERN_WARNING "can't allocate apm buffer\n"); diff --git a/sound/pci/als300.c b/sound/pci/als300.c index 68c4469c6d1..00f157a2cf6 100644 --- a/sound/pci/als300.c +++ b/sound/pci/als300.c @@ -765,7 +765,7 @@ static int __devinit snd_als300_create(struct snd_card *card,  	return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int snd_als300_suspend(struct device *dev)  {  	struct pci_dev *pci = to_pci_dev(dev); diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index 0eeca49c575..feb2a143683 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c @@ -987,7 +987,7 @@ static void __devexit snd_card_als4000_remove(struct pci_dev *pci)  	pci_set_drvdata(pci, NULL);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int snd_als4000_suspend(struct device *dev)  {  	struct pci_dev *pci = to_pci_dev(dev); @@ -1040,7 +1040,7 @@ static SIMPLE_DEV_PM_OPS(snd_als4000_pm, snd_als4000_suspend, snd_als4000_resume  #define SND_ALS4000_PM_OPS	&snd_als4000_pm  #else  #define SND_ALS4000_PM_OPS	NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  static struct pci_driver als4000_driver = {  	.name = KBUILD_MODNAME, diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index e8de831f98b..eedc017c1cd 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -2658,7 +2658,7 @@ static int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)  					hpi_ctl.dst_node_type,  					hpi_ctl.dst_node_index);  			continue; -		}; +		}  		if (err < 0)  			return err;  	} @@ -2968,7 +2968,7 @@ static struct pci_driver driver = {  	.id_table = asihpi_pci_tbl,  	.probe = snd_asihpi_probe,  	.remove = __devexit_p(snd_asihpi_remove), -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  /*	.suspend = snd_asihpi_suspend,  	.resume = snd_asihpi_resume, */  #endif diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 31020d2a868..368df8b0853 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -535,7 +535,7 @@ static int snd_atiixp_aclink_reset(struct atiixp *chip)  	return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int snd_atiixp_aclink_down(struct atiixp *chip)  {  	// if (atiixp_read(chip, MODEM_MIRROR) & 0x1) /* modem running, too? */ @@ -1250,6 +1250,7 @@ static struct atiixp_dma_ops snd_atiixp_spdif_dma_ops = {  static int __devinit snd_atiixp_pcm_new(struct atiixp *chip)  {  	struct snd_pcm *pcm; +	struct snd_pcm_chmap *chmap;  	struct snd_ac97_bus *pbus = chip->ac97_bus;  	int err, i, num_pcms; @@ -1293,6 +1294,14 @@ static int __devinit snd_atiixp_pcm_new(struct atiixp *chip)  					      snd_dma_pci_data(chip->pci),  					      64*1024, 128*1024); +	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, +				     snd_pcm_alt_chmaps, chip->max_channels, 0, +				     &chmap); +	if (err < 0) +		return err; +	chmap->channel_mask = SND_PCM_CHMAP_MASK_2468; +	chip->ac97[0]->chmaps[SNDRV_PCM_STREAM_PLAYBACK] = chmap; +  	/* no SPDIF support on codec? */  	if (chip->pcms[ATI_PCM_SPDIF] && ! chip->pcms[ATI_PCM_SPDIF]->rates)  		return 0; @@ -1458,7 +1467,7 @@ static int __devinit snd_atiixp_mixer_new(struct atiixp *chip, int clock,  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  /*   * power management   */ @@ -1533,7 +1542,7 @@ static SIMPLE_DEV_PM_OPS(snd_atiixp_pm, snd_atiixp_suspend, snd_atiixp_resume);  #define SND_ATIIXP_PM_OPS	&snd_atiixp_pm  #else  #define SND_ATIIXP_PM_OPS	NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  #ifdef CONFIG_PROC_FS diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index 79e204ec623..6fc03d9f2cf 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -511,7 +511,7 @@ static int snd_atiixp_aclink_reset(struct atiixp_modem *chip)  	return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int snd_atiixp_aclink_down(struct atiixp_modem *chip)  {  	// if (atiixp_read(chip, MODEM_MIRROR) & 0x1) /* modem running, too? */ @@ -1113,7 +1113,7 @@ static int __devinit snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock)  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  /*   * power management   */ @@ -1169,7 +1169,7 @@ static SIMPLE_DEV_PM_OPS(snd_atiixp_pm, snd_atiixp_suspend, snd_atiixp_resume);  #define SND_ATIIXP_PM_OPS	&snd_atiixp_pm  #else  #define SND_ATIIXP_PM_OPS	NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  #ifdef CONFIG_PROC_FS  /* diff --git a/sound/pci/au88x0/au88x0_game.c b/sound/pci/au88x0/au88x0_game.c index c07c792bde8..30a456700d8 100644 --- a/sound/pci/au88x0/au88x0_game.c +++ b/sound/pci/au88x0/au88x0_game.c @@ -100,7 +100,7 @@ static int __devinit vortex_gameport_register(vortex_t * vortex)  	if (!gp) {  		printk(KERN_ERR "vortex: cannot allocate memory for gameport\n");  		return -ENOMEM; -	}; +	}  	gameport_set_name(gp, "AU88x0 Gameport");  	gameport_set_phys(gp, "pci%s/gameport0", pci_name(vortex->pci_dev)); diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c index e59f120742a..b2405020284 100644 --- a/sound/pci/au88x0/au88x0_pcm.c +++ b/sound/pci/au88x0/au88x0_pcm.c @@ -585,7 +585,7 @@ static int snd_vortex_pcm_vol_put(struct snd_kcontrol *kcontrol,  				case 4:  					mixin = p->mixin[i];  					break; -				}; +				}  				vol = p->vol[i];  				vortex_mix_setinputvolumebyte(vortex,  					vortex->mixplayb[i], mixin, vol); diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 4dddd871548..c03b66b784a 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -365,7 +365,7 @@ struct snd_azf3328 {  	 * CONFIG_PM register storage below, but that's slightly difficult. */  	u16 shadow_reg_ctrl_6AH; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	/* register value containers for power management  	 * Note: not always full I/O range preserved (similar to Win driver!) */  	u32 saved_regs_ctrl[AZF_ALIGN(AZF_IO_SIZE_CTRL_PM) / 4]; @@ -2729,7 +2729,7 @@ snd_azf3328_remove(struct pci_dev *pci)  	snd_azf3328_dbgcallleave();  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static inline void  snd_azf3328_suspend_regs(unsigned long io_addr, unsigned count, u32 *saved_regs)  { @@ -2866,7 +2866,7 @@ static SIMPLE_DEV_PM_OPS(snd_azf3328_pm, snd_azf3328_suspend, snd_azf3328_resume  #define SND_AZF3328_PM_OPS	&snd_azf3328_pm  #else  #define SND_AZF3328_PM_OPS	NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  static struct pci_driver azf3328_driver = {  	.name = KBUILD_MODNAME, diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index e8e8ccc9640..04402c14cb2 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h @@ -710,7 +710,7 @@ struct snd_ca0106 {  	u16 spi_dac_reg[16]; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  #define NUM_SAVED_VOLUMES	9  	unsigned int saved_vol[NUM_SAVED_VOLUMES];  #endif @@ -733,7 +733,7 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu, u32 reg, u32 value);  int snd_ca0106_spi_write(struct snd_ca0106 * emu,  				   unsigned int data); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  void snd_ca0106_mixer_suspend(struct snd_ca0106 *chip);  void snd_ca0106_mixer_resume(struct snd_ca0106 *chip);  #else diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 83277b747b3..65c55910566 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1334,10 +1334,29 @@ static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id)  	return IRQ_HANDLED;  } +static const struct snd_pcm_chmap_elem surround_map[] = { +	{ .channels = 2, +	  .map = { SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } }, +	{ } +}; + +static const struct snd_pcm_chmap_elem clfe_map[] = { +	{ .channels = 2, +	  .map = { SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE } }, +	{ } +}; + +static const struct snd_pcm_chmap_elem side_map[] = { +	{ .channels = 2, +	  .map = { SNDRV_CHMAP_SL, SNDRV_CHMAP_SR } }, +	{ } +}; +  static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device)  {  	struct snd_pcm *pcm;  	struct snd_pcm_substream *substream; +	const struct snd_pcm_chmap_elem *map = NULL;  	int err;  	err = snd_pcm_new(emu->card, "ca0106", device, 1, 1, &pcm); @@ -1350,18 +1369,22 @@ static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device)  	case 0:  	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_front_ops);  	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_0_ops); +	  map = snd_pcm_std_chmaps;            break;  	case 1:  	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_rear_ops);  	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_1_ops); +	  map = surround_map;            break;  	case 2:  	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_center_lfe_ops);  	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_2_ops); +	  map = clfe_map;            break;  	case 3:  	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_unknown_ops);  	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_3_ops); +	  map = side_map;            break;          } @@ -1388,6 +1411,11 @@ static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device)  			return err;  	} +	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, map, 2, +				     1 << 2, NULL); +	if (err < 0) +		return err; +  	emu->pcm[device] = pcm;  	return 0; @@ -1871,7 +1899,7 @@ static void __devexit snd_ca0106_remove(struct pci_dev *pci)  	pci_set_drvdata(pci, NULL);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int snd_ca0106_suspend(struct device *dev)  {  	struct pci_dev *pci = to_pci_dev(dev); diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 84f3f92436b..68eacf7002d 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -907,7 +907,7 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)          return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  struct ca0106_vol_tbl {  	unsigned int channel_id;  	unsigned int reg; @@ -953,4 +953,4 @@ void snd_ca0106_mixer_resume(struct snd_ca0106  *chip)  	if (chip->details->i2c_adc)  		ca0106_set_capture_mic_line_in(chip);  } -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */ diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index b7d6f2b886e..22122ff26e3 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -504,7 +504,7 @@ struct cmipci {  	spinlock_t reg_lock; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	unsigned int saved_regs[0x20];  	unsigned char saved_mixers[0x20];  #endif @@ -1962,6 +1962,12 @@ static int __devinit snd_cmipci_pcm_spdif_new(struct cmipci *cm, int device)  	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,  					      snd_dma_pci_data(cm->pci), 64*1024, 128*1024); +	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, +				     snd_pcm_alt_chmaps, cm->max_channels, 0, +				     NULL); +	if (err < 0) +		return err; +  	return 0;  } @@ -3315,7 +3321,7 @@ static void __devexit snd_cmipci_remove(struct pci_dev *pci)  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  /*   * power management   */ @@ -3403,7 +3409,7 @@ static SIMPLE_DEV_PM_OPS(snd_cmipci_pm, snd_cmipci_suspend, snd_cmipci_resume);  #define SND_CMIPCI_PM_OPS	&snd_cmipci_pm  #else  #define SND_CMIPCI_PM_OPS	NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  static struct pci_driver cmipci_driver = {  	.name = KBUILD_MODNAME, diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 45a8317085f..8e86ec0031f 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -486,7 +486,7 @@ struct cs4281 {  	struct gameport *gameport; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	u32 suspend_regs[SUSPEND_REGISTERS];  #endif @@ -1977,7 +1977,7 @@ static void __devexit snd_cs4281_remove(struct pci_dev *pci)  /*   * Power Management   */ -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int saved_regs[SUSPEND_REGISTERS] = {  	BA0_JSCTL, @@ -2089,7 +2089,7 @@ static SIMPLE_DEV_PM_OPS(cs4281_pm, cs4281_suspend, cs4281_resume);  #define CS4281_PM_OPS	&cs4281_pm  #else  #define CS4281_PM_OPS	NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  static struct pci_driver cs4281_driver = {  	.name = KBUILD_MODNAME, diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c index 1e007c736a8..575bed0836f 100644 --- a/sound/pci/cs46xx/cs46xx.c +++ b/sound/pci/cs46xx/cs46xx.c @@ -166,7 +166,7 @@ static struct pci_driver cs46xx_driver = {  	.id_table = snd_cs46xx_ids,  	.probe = snd_card_cs46xx_probe,  	.remove = __devexit_p(snd_card_cs46xx_remove), -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.driver = {  		.pm = &snd_cs46xx_pm,  	}, diff --git a/sound/pci/cs46xx/cs46xx.h b/sound/pci/cs46xx/cs46xx.h index 29d8a8da1ba..fc339ef0a0a 100644 --- a/sound/pci/cs46xx/cs46xx.h +++ b/sound/pci/cs46xx/cs46xx.h @@ -1721,7 +1721,7 @@ struct snd_cs46xx {  	unsigned int play_ctl;  #endif -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	u32 *saved_regs;  #endif  }; diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index a71d1c14a0f..a2bb8c91ebe 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -2797,7 +2797,7 @@ static int snd_cs46xx_free(struct snd_cs46xx *chip)  	}  #endif -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	kfree(chip->saved_regs);  #endif @@ -3590,7 +3590,7 @@ static struct cs_card_type __devinitdata cards[] = {  /*   * APM support   */ -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static unsigned int saved_regs[] = {  	BA0_ACOSV,  	/*BA0_ASER_FADDR,*/ @@ -3711,7 +3711,7 @@ static int snd_cs46xx_resume(struct device *dev)  }  SIMPLE_DEV_PM_OPS(snd_cs46xx_pm, snd_cs46xx_suspend, snd_cs46xx_resume); -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  /* @@ -3868,7 +3868,7 @@ int __devinit snd_cs46xx_create(struct snd_card *card,  	snd_cs46xx_proc_init(card, chip); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	chip->saved_regs = kmalloc(sizeof(*chip->saved_regs) *  				   ARRAY_SIZE(saved_regs), GFP_KERNEL);  	if (!chip->saved_regs) { diff --git a/sound/pci/cs46xx/cs46xx_lib.h b/sound/pci/cs46xx/cs46xx_lib.h index b5189495d58..86f14620f81 100644 --- a/sound/pci/cs46xx/cs46xx_lib.h +++ b/sound/pci/cs46xx/cs46xx_lib.h @@ -90,7 +90,7 @@ static inline unsigned int snd_cs46xx_peekBA0(struct snd_cs46xx *chip, unsigned  struct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip);  void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip);  int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * module); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  int cs46xx_dsp_resume(struct snd_cs46xx * chip);  #endif  struct dsp_symbol_entry *cs46xx_dsp_lookup_symbol (struct snd_cs46xx * chip, char * symbol_name, diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c index 56fec0bc0ef..1686b4f4c44 100644 --- a/sound/pci/cs46xx/dsp_spos.c +++ b/sound/pci/cs46xx/dsp_spos.c @@ -287,7 +287,7 @@ void  cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip)  		if (ins->scbs[i].deleted) continue;  		cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) ); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  		kfree(ins->scbs[i].data);  #endif  	} @@ -1019,7 +1019,7 @@ cs46xx_dsp_create_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32  {  	struct dsp_scb_descriptor * desc; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	/* copy the data for resume */  	scb_data = kmemdup(scb_data, SCB_BYTES, GFP_KERNEL);  	if (!scb_data) @@ -1032,7 +1032,7 @@ cs46xx_dsp_create_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32  		_dsp_create_scb(chip,scb_data,dest);  	} else {  		snd_printk(KERN_ERR "dsp_spos: failed to map SCB\n"); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  		kfree(scb_data);  #endif  	} @@ -1937,7 +1937,7 @@ int cs46xx_dsp_set_iec958_volume (struct snd_cs46xx * chip, u16 left, u16 right)  	return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  int cs46xx_dsp_resume(struct snd_cs46xx * chip)  {  	struct dsp_spos_instance * ins = chip->dsp_spos_instance; diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c index c2c695b07f8..409e8764fbe 100644 --- a/sound/pci/cs46xx/dsp_spos_scb_lib.c +++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c @@ -203,7 +203,7 @@ void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor *  	remove_symbol (chip,scb->scb_symbol);  	ins->scbs[scb->index].deleted = 1; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	kfree(ins->scbs[scb->index].data);  	ins->scbs[scb->index].data = NULL;  #endif diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c index f1e4229993a..d1cca283157 100644 --- a/sound/pci/cs5530.c +++ b/sound/pci/cs5530.c @@ -142,8 +142,7 @@ static int __devinit snd_cs5530_create(struct snd_card *card,  	mem = pci_ioremap_bar(pci, 0);  	if (mem == NULL) { -		kfree(chip); -		pci_disable_device(pci); +		snd_cs5530_free(chip);  		return -EBUSY;  	} diff --git a/sound/pci/cs5535audio/Makefile b/sound/pci/cs5535audio/Makefile index ccc642269b9..a8f75f8dfda 100644 --- a/sound/pci/cs5535audio/Makefile +++ b/sound/pci/cs5535audio/Makefile @@ -3,7 +3,7 @@  #  snd-cs5535audio-y := cs5535audio.o cs5535audio_pcm.o -snd-cs5535audio-$(CONFIG_PM) += cs5535audio_pm.o +snd-cs5535audio-$(CONFIG_PM_SLEEP) += cs5535audio_pm.o  snd-cs5535audio-$(CONFIG_OLPC) += cs5535audio_olpc.o  # Toplevel Module Dependency diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 51f64ba5fac..4915efa551f 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c @@ -399,7 +399,7 @@ static struct pci_driver cs5535audio_driver = {  	.id_table = snd_cs5535audio_ids,  	.probe = snd_cs5535audio_probe,  	.remove = __devexit_p(snd_cs5535audio_remove), -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.driver = {  		.pm = &snd_cs5535audio_pm,  	}, diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index 2f6e9c762d3..a2f997a9977 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -1536,7 +1536,7 @@ static void atc_connect_resources(struct ct_atc *atc)  	}  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int atc_suspend(struct ct_atc *atc)  {  	int i; @@ -1647,7 +1647,7 @@ static struct ct_atc atc_preset __devinitdata = {  	.output_switch_put = atc_output_switch_put,  	.mic_source_switch_get = atc_mic_source_switch_get,  	.mic_source_switch_put = atc_mic_source_switch_put, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend = atc_suspend,  	.resume = atc_resume,  #endif diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h index 653e813ad14..69b51f9d345 100644 --- a/sound/pci/ctxfi/ctatc.h +++ b/sound/pci/ctxfi/ctatc.h @@ -143,7 +143,7 @@ struct ct_atc {  	struct ct_timer *timer; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	int (*suspend)(struct ct_atc *atc);  	int (*resume)(struct ct_atc *atc);  #define NUM_PCMS (NUM_CTALSADEVS - 1) diff --git a/sound/pci/ctxfi/cthardware.h b/sound/pci/ctxfi/cthardware.h index c56fe533b3f..5977e9a24b5 100644 --- a/sound/pci/ctxfi/cthardware.h +++ b/sound/pci/ctxfi/cthardware.h @@ -72,7 +72,7 @@ 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 +#ifdef CONFIG_PM_SLEEP  	int (*suspend)(struct hw *hw);  	int (*resume)(struct hw *hw, struct card_conf *info);  #endif diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c index dc1969bc67d..4507f7088b2 100644 --- a/sound/pci/ctxfi/cthw20k1.c +++ b/sound/pci/ctxfi/cthw20k1.c @@ -2085,7 +2085,7 @@ static int hw_card_init(struct hw *hw, struct card_conf *info)  	return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int hw_suspend(struct hw *hw)  {  	struct pci_dev *pci = hw->pci; @@ -2180,7 +2180,7 @@ static struct hw ct20k1_preset __devinitdata = {  	.is_adc_source_selected = hw_is_adc_input_selected,  	.select_adc_source = hw_adc_input_select,  	.capabilities = hw_capabilities, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend = hw_suspend,  	.resume = hw_resume,  #endif diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c index 9d1231dc4ae..b9c9349058b 100644 --- a/sound/pci/ctxfi/cthw20k2.c +++ b/sound/pci/ctxfi/cthw20k2.c @@ -2201,7 +2201,7 @@ static int hw_card_init(struct hw *hw, struct card_conf *info)  	return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int hw_suspend(struct hw *hw)  {  	struct pci_dev *pci = hw->pci; @@ -2250,7 +2250,7 @@ static struct hw ct20k2_preset __devinitdata = {  	.output_switch_put = hw_output_switch_put,  	.mic_source_switch_get = hw_mic_source_switch_get,  	.mic_source_switch_put = hw_mic_source_switch_put, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.suspend = hw_suspend,  	.resume = hw_resume,  #endif diff --git a/sound/pci/ctxfi/ctmixer.c b/sound/pci/ctxfi/ctmixer.c index 0cc13eeef8d..48fe0e39c2b 100644 --- a/sound/pci/ctxfi/ctmixer.c +++ b/sound/pci/ctxfi/ctmixer.c @@ -1118,7 +1118,7 @@ mixer_set_input_right(struct ct_mixer *mixer,  	return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int mixer_resume(struct ct_mixer *mixer)  {  	int i, state; @@ -1188,7 +1188,7 @@ int ct_mixer_create(struct ct_atc *atc, struct ct_mixer **rmixer)  	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 +#ifdef CONFIG_PM_SLEEP  	mixer->resume = mixer_resume;  #endif diff --git a/sound/pci/ctxfi/ctmixer.h b/sound/pci/ctxfi/ctmixer.h index b009e989e77..be881c639fe 100644 --- a/sound/pci/ctxfi/ctmixer.h +++ b/sound/pci/ctxfi/ctmixer.h @@ -56,7 +56,7 @@ struct ct_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 +#ifdef CONFIG_PM_SLEEP  	int (*resume)(struct ct_mixer *mixer);  #endif  }; diff --git a/sound/pci/ctxfi/ctpcm.c b/sound/pci/ctxfi/ctpcm.c index 2c8622617c8..e8a4feb1ed8 100644 --- a/sound/pci/ctxfi/ctpcm.c +++ b/sound/pci/ctxfi/ctpcm.c @@ -395,12 +395,38 @@ static struct snd_pcm_ops ct_pcm_capture_ops = {  	.page		= snd_pcm_sgbuf_ops_page,  }; +static const struct snd_pcm_chmap_elem surround_map[] = { +	{ .channels = 1, +	  .map = { SNDRV_CHMAP_MONO } }, +	{ .channels = 2, +	  .map = { SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } }, +	{ } +}; + +static const struct snd_pcm_chmap_elem clfe_map[] = { +	{ .channels = 1, +	  .map = { SNDRV_CHMAP_MONO } }, +	{ .channels = 2, +	  .map = { SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE } }, +	{ } +}; + +static const struct snd_pcm_chmap_elem side_map[] = { +	{ .channels = 1, +	  .map = { SNDRV_CHMAP_MONO } }, +	{ .channels = 2, +	  .map = { SNDRV_CHMAP_SL, SNDRV_CHMAP_SR } }, +	{ } +}; +  /* Create ALSA pcm device */  int ct_alsa_pcm_create(struct ct_atc *atc,  		       enum CTALSADEVS device,  		       const char *device_name)  {  	struct snd_pcm *pcm; +	const struct snd_pcm_chmap_elem *map; +	int chs;  	int err;  	int playback_count, capture_count; @@ -427,7 +453,31 @@ int ct_alsa_pcm_create(struct ct_atc *atc,  	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 +	chs = 2; +	switch (device) { +	case FRONT: +		chs = 8; +		map = snd_pcm_std_chmaps; +		break; +	case SURROUND: +		map = surround_map; +		break; +	case CLFE: +		map = clfe_map; +		break; +	case SIDE: +		map = side_map; +		break; +	default: +		map = snd_pcm_std_chmaps; +		break; +	} +	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, map, chs, +				     0, NULL); +	if (err < 0) +		return err; + +#ifdef CONFIG_PM_SLEEP  	atc->pcms[device] = pcm;  #endif diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c index e002183ef8b..07c07d752fd 100644 --- a/sound/pci/ctxfi/xfi.c +++ b/sound/pci/ctxfi/xfi.c @@ -125,7 +125,7 @@ static void __devexit ct_card_remove(struct pci_dev *pci)  	pci_set_drvdata(pci, NULL);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int ct_card_suspend(struct device *dev)  {  	struct snd_card *card = dev_get_drvdata(dev); diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 0ff754f180d..abb0b86c41c 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -46,7 +46,7 @@ static int get_firmware(const struct firmware **fw_entry,  	int err;  	char name[30]; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	if (chip->fw_cache[fw_index]) {  		DE_ACT(("firmware requested: %s is cached\n", card_fw[fw_index].data));  		*fw_entry = chip->fw_cache[fw_index]; @@ -59,7 +59,7 @@ static int get_firmware(const struct firmware **fw_entry,  	err = request_firmware(fw_entry, name, pci_device(chip));  	if (err < 0)  		snd_printk(KERN_ERR "get_firmware(): Firmware not available (%d)\n", err); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	else  		chip->fw_cache[fw_index] = *fw_entry;  #endif @@ -70,7 +70,7 @@ static int get_firmware(const struct firmware **fw_entry,  static void free_firmware(const struct firmware *fw_entry)  { -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	DE_ACT(("firmware not released (kept in cache)\n"));  #else  	release_firmware(fw_entry); @@ -82,7 +82,7 @@ static void free_firmware(const struct firmware *fw_entry)  static void free_firmware_cache(struct echoaudio *chip)  { -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	int i;  	for (i = 0; i < 8 ; i++) @@ -2203,7 +2203,7 @@ ctl_error: -#if defined(CONFIG_PM) +#if defined(CONFIG_PM_SLEEP)  static int snd_echo_suspend(struct device *dev)  { @@ -2313,7 +2313,7 @@ static SIMPLE_DEV_PM_OPS(snd_echo_pm, snd_echo_suspend, snd_echo_resume);  #define SND_ECHO_PM_OPS	&snd_echo_pm  #else  #define SND_ECHO_PM_OPS	NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  static void __devexit snd_echo_remove(struct pci_dev *pci) diff --git a/sound/pci/echoaudio/echoaudio.h b/sound/pci/echoaudio/echoaudio.h index 1df974dcb5f..e158369f5fa 100644 --- a/sound/pci/echoaudio/echoaudio.h +++ b/sound/pci/echoaudio/echoaudio.h @@ -449,7 +449,7 @@ struct echoaudio {  	volatile u32 __iomem *dsp_registers;	/* DSP's register base */  	u32 active_mask;			/* Chs. active mask or  						 * punks out */ -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	const struct firmware *fw_cache[8];	/* Cached firmwares */  #endif diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index ddac4e6d660..b7c1875ba90 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -206,7 +206,7 @@ static void __devexit snd_card_emu10k1_remove(struct pci_dev *pci)  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int snd_emu10k1_suspend(struct device *dev)  {  	struct pci_dev *pci = to_pci_dev(dev); @@ -268,7 +268,7 @@ static SIMPLE_DEV_PM_OPS(snd_emu10k1_pm, snd_emu10k1_suspend, snd_emu10k1_resume  #define SND_EMU10K1_PM_OPS	&snd_emu10k1_pm  #else  #define SND_EMU10K1_PM_OPS	NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  static struct pci_driver emu10k1_driver = {  	.name = KBUILD_MODNAME, diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c index a0afa505748..cae36597aa7 100644 --- a/sound/pci/emu10k1/emu10k1_callback.c +++ b/sound/pci/emu10k1/emu10k1_callback.c @@ -228,7 +228,7 @@ lookup_voices(struct snd_emux *emu, struct snd_emu10k1 *hw,  	int  i;  	for (i = 0; i < V_END; i++) { -		best[i].time = (unsigned int)-1; /* XXX MAX_?INT really */; +		best[i].time = (unsigned int)-1; /* XXX MAX_?INT really */  		best[i].voice = -1;  	} diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 754924081d0..bed4485f34f 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -1241,7 +1241,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)   *  Create the EMU10K1 instance   */ -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int alloc_pm_buffer(struct snd_emu10k1 *emu);  static void free_pm_buffer(struct snd_emu10k1 *emu);  #endif @@ -1275,7 +1275,7 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu)  		snd_dma_free_pages(&emu->ptb_pages);  	vfree(emu->page_ptr_table);  	vfree(emu->page_addr_table); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	free_pm_buffer(emu);  #endif  	if (emu->port) @@ -1971,7 +1971,7 @@ int __devinit snd_emu10k1_create(struct snd_card *card,  	err = snd_emu10k1_init(emu, enable_ir, 0);  	if (err < 0)  		goto error; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	err = alloc_pm_buffer(emu);  	if (err < 0)  		goto error; @@ -2000,7 +2000,7 @@ int __devinit snd_emu10k1_create(struct snd_card *card,  	return err;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static unsigned char saved_regs[] = {  	CPF, PTRX, CVCF, VTFT, Z1, Z2, PSST, DSL, CCCA, CCR, CLP,  	FXRT, MAPA, MAPB, ENVVOL, ATKHLDV, DCYSUSV, LFOVAL1, ENVVAL, diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 5c8978b2c4d..556fd6f456e 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -830,9 +830,22 @@ static irqreturn_t snd_emu10k1x_interrupt(int irq, void *dev_id)  	return IRQ_HANDLED;  } +static const struct snd_pcm_chmap_elem surround_map[] = { +	{ .channels = 2, +	  .map = { SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } }, +	{ } +}; + +static const struct snd_pcm_chmap_elem clfe_map[] = { +	{ .channels = 2, +	  .map = { SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE } }, +	{ } +}; +  static int __devinit snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct snd_pcm **rpcm)  {  	struct snd_pcm *pcm; +	const struct snd_pcm_chmap_elem *map = NULL;  	int err;  	int capture = 0; @@ -861,12 +874,15 @@ static int __devinit snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct s  	switch(device) {  	case 0:  		strcpy(pcm->name, "EMU10K1X Front"); +		map = snd_pcm_std_chmaps;  		break;  	case 1:  		strcpy(pcm->name, "EMU10K1X Rear"); +		map = surround_map;  		break;  	case 2:  		strcpy(pcm->name, "EMU10K1X Center/LFE"); +		map = clfe_map;  		break;  	}  	emu->pcm = pcm; @@ -875,6 +891,11 @@ static int __devinit snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct s  					      snd_dma_pci_data(emu->pci),   					      32*1024, 32*1024); +	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, map, 2, +				     1 << 2, NULL); +	if (err < 0) +		return err; +  	if (rpcm)  		*rpcm = pcm; diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index dae4050ede5..52419959178 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -2646,7 +2646,7 @@ int __devinit snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, struct  	return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  int __devinit snd_emu10k1_efx_alloc_pm_buffer(struct snd_emu10k1 *emu)  {  	int len; diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index e22b8e2bbd8..0e6664fa6cd 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -1310,7 +1310,7 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream)  			runtime->hw.channels_min =  				runtime->hw.channels_max = 16;  			break; -		}; +		}  #endif  #if 0  		/* For 96kHz */ diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index 0a436626182..ae709c1ab3a 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c @@ -263,8 +263,8 @@ int snd_emu10k1_memblk_map(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *b  	spin_lock_irqsave(&emu->memblk_lock, flags);  	if (blk->mapped_page >= 0) {  		/* update order link */ -		list_del(&blk->mapped_order_link); -		list_add_tail(&blk->mapped_order_link, &emu->mapped_order_link_head); +		list_move_tail(&blk->mapped_order_link, +			       &emu->mapped_order_link_head);  		spin_unlock_irqrestore(&emu->memblk_lock, flags);  		return 0;  	} diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index a81dc44228e..88cec6b7dd4 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -893,7 +893,7 @@ int __devinit snd_p16v_mixer(struct snd_emu10k1 *emu)          return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  #define NUM_CHS	1	/* up to 4, but only first channel is used */ diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index f7e6f73186e..5674cc31653 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -55,8 +55,10 @@  #ifdef CHIP1370  #define DRIVER_NAME "ENS1370" +#define CHIP_NAME "ES1370" /* it can be ENS but just to keep compatibility... */  #else  #define DRIVER_NAME "ENS1371" +#define CHIP_NAME "ES1371"  #endif @@ -1258,6 +1260,14 @@ static struct snd_pcm_ops snd_ensoniq_capture_ops = {  	.pointer =	snd_ensoniq_capture_pointer,  }; +static const struct snd_pcm_chmap_elem surround_map[] = { +	{ .channels = 1, +	  .map = { SNDRV_CHMAP_MONO } }, +	{ .channels = 2, +	  .map = { SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } }, +	{ } +}; +  static int __devinit snd_ensoniq_pcm(struct ensoniq * ensoniq, int device,  				     struct snd_pcm ** rpcm)  { @@ -1266,11 +1276,7 @@ static int __devinit snd_ensoniq_pcm(struct ensoniq * ensoniq, int device,  	if (rpcm)  		*rpcm = NULL; -#ifdef CHIP1370 -	err = snd_pcm_new(ensoniq->card, "ES1370/1", device, 1, 1, &pcm); -#else -	err = snd_pcm_new(ensoniq->card, "ES1371/1", device, 1, 1, &pcm); -#endif +	err = snd_pcm_new(ensoniq->card, CHIP_NAME "/1", device, 1, 1, &pcm);  	if (err < 0)  		return err; @@ -1283,16 +1289,22 @@ static int __devinit snd_ensoniq_pcm(struct ensoniq * ensoniq, int device,  	pcm->private_data = ensoniq;  	pcm->info_flags = 0; -#ifdef CHIP1370 -	strcpy(pcm->name, "ES1370 DAC2/ADC"); -#else -	strcpy(pcm->name, "ES1371 DAC2/ADC"); -#endif +	strcpy(pcm->name, CHIP_NAME " DAC2/ADC");  	ensoniq->pcm1 = pcm;  	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,  					      snd_dma_pci_data(ensoniq->pci), 64*1024, 128*1024); +#ifdef CHIP1370 +	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, +				     surround_map, 2, 0, NULL); +#else +	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, +				     snd_pcm_std_chmaps, 2, 0, NULL); +#endif +	if (err < 0) +		return err; +  	if (rpcm)  		*rpcm = pcm;  	return 0; @@ -1306,11 +1318,7 @@ static int __devinit snd_ensoniq_pcm2(struct ensoniq * ensoniq, int device,  	if (rpcm)  		*rpcm = NULL; -#ifdef CHIP1370 -	err = snd_pcm_new(ensoniq->card, "ES1370/2", device, 1, 0, &pcm); -#else -	err = snd_pcm_new(ensoniq->card, "ES1371/2", device, 1, 0, &pcm); -#endif +	err = snd_pcm_new(ensoniq->card, CHIP_NAME "/2", device, 1, 0, &pcm);  	if (err < 0)  		return err; @@ -1321,16 +1329,22 @@ static int __devinit snd_ensoniq_pcm2(struct ensoniq * ensoniq, int device,  #endif  	pcm->private_data = ensoniq;  	pcm->info_flags = 0; -#ifdef CHIP1370 -	strcpy(pcm->name, "ES1370 DAC1"); -#else -	strcpy(pcm->name, "ES1371 DAC1"); -#endif +	strcpy(pcm->name, CHIP_NAME " DAC1");  	ensoniq->pcm2 = pcm;  	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,  					      snd_dma_pci_data(ensoniq->pci), 64*1024, 128*1024); +#ifdef CHIP1370 +	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, +				     snd_pcm_std_chmaps, 2, 0, NULL); +#else +	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, +				     surround_map, 2, 0, NULL); +#endif +	if (err < 0) +		return err; +  	if (rpcm)  		*rpcm = pcm;  	return 0; @@ -1885,11 +1899,7 @@ static void snd_ensoniq_proc_read(struct snd_info_entry *entry,  {  	struct ensoniq *ensoniq = entry->private_data; -#ifdef CHIP1370 -	snd_iprintf(buffer, "Ensoniq AudioPCI ES1370\n\n"); -#else -	snd_iprintf(buffer, "Ensoniq AudioPCI ES1371\n\n"); -#endif +	snd_iprintf(buffer, "Ensoniq AudioPCI " CHIP_NAME "\n\n");  	snd_iprintf(buffer, "Joystick enable  : %s\n",  		    ensoniq->ctrl & ES_JYSTK_EN ? "on" : "off");  #ifdef CHIP1370 @@ -2032,7 +2042,7 @@ static void snd_ensoniq_chip_init(struct ensoniq *ensoniq)  	synchronize_irq(ensoniq->irq);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int snd_ensoniq_suspend(struct device *dev)  {  	struct pci_dev *pci = to_pci_dev(dev); @@ -2094,7 +2104,7 @@ static SIMPLE_DEV_PM_OPS(snd_ensoniq_pm, snd_ensoniq_suspend, snd_ensoniq_resume  #define SND_ENSONIQ_PM_OPS	&snd_ensoniq_pm  #else  #define SND_ENSONIQ_PM_OPS	NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  static int __devinit snd_ensoniq_create(struct snd_card *card,  				     struct pci_dev *pci, @@ -2361,11 +2371,7 @@ static int __devinit snd_ensoniq_midi(struct ensoniq * ensoniq, int device,  		*rrawmidi = NULL;  	if ((err = snd_rawmidi_new(ensoniq->card, "ES1370/1", device, 1, 1, &rmidi)) < 0)  		return err; -#ifdef CHIP1370 -	strcpy(rmidi->name, "ES1370"); -#else -	strcpy(rmidi->name, "ES1371"); -#endif +	strcpy(rmidi->name, CHIP_NAME);  	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_ensoniq_midi_output);  	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_ensoniq_midi_input);  	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index dbb81807bc1..394c5d41353 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -236,7 +236,7 @@ struct es1938 {  #ifdef SUPPORT_JOYSTICK  	struct gameport *gameport;  #endif -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	unsigned char saved_regs[SAVED_REG_SIZE];  #endif  }; @@ -1456,7 +1456,7 @@ static void snd_es1938_chip_init(struct es1938 *chip)  	outb(0, SLDM_REG(chip, DMACLEAR));  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  /*   * PM support   */ @@ -1536,7 +1536,7 @@ static SIMPLE_DEV_PM_OPS(es1938_pm, es1938_suspend, es1938_resume);  #define ES1938_PM_OPS	&es1938_pm  #else  #define ES1938_PM_OPS	NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  #ifdef SUPPORT_JOYSTICK  static int __devinit snd_es1938_create_gameport(struct es1938 *chip) diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index fb4c90b99c0..5d0e568fdea 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -491,7 +491,7 @@ struct esschan {  	/* linked list */  	struct list_head list; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	u16 wc_map[4];  #endif  }; @@ -544,7 +544,7 @@ struct es1968 {  	struct list_head substream_list;  	spinlock_t substream_lock; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	u16 apu_map[NR_APUS][NR_APU_REGS];  #endif @@ -706,7 +706,7 @@ static void __apu_set_register(struct es1968 *chip, u16 channel, u8 reg, u16 dat  {  	if (snd_BUG_ON(channel >= NR_APUS))  		return; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	chip->apu_map[channel][reg] = data;  #endif  	reg |= (channel << 4); @@ -993,7 +993,7 @@ static void snd_es1968_program_wavecache(struct es1968 *chip, struct esschan *es  	/* set the wavecache control reg */  	wave_set_register(chip, es->apu[channel] << 3, tmpval); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	es->wc_map[channel] = tmpval;  #endif  } @@ -2377,7 +2377,7 @@ static void snd_es1968_start_irq(struct es1968 *chip)  	outw(w, chip->io_port + ESM_PORT_HOST_IRQ);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  /*   * PM support   */ @@ -2461,7 +2461,7 @@ static SIMPLE_DEV_PM_OPS(es1968_pm, es1968_suspend, es1968_resume);  #define ES1968_PM_OPS	&es1968_pm  #else  #define ES1968_PM_OPS	NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  #ifdef SUPPORT_JOYSTICK  #define JOYSTICK_ADDR	0x200 diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 522c8706f24..cc2e91d1553 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -205,7 +205,7 @@ struct fm801 {  	struct snd_tea575x tea;  #endif -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	u16 saved_regs[0x20];  #endif  }; @@ -711,6 +711,13 @@ static int __devinit snd_fm801_pcm(struct fm801 *chip, int device, struct snd_pc  					      snd_dma_pci_data(chip->pci),  					      chip->multichannel ? 128*1024 : 64*1024, 128*1024); +	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, +				     snd_pcm_alt_chmaps, +				     chip->multichannel ? 6 : 2, 0, +				     NULL); +	if (err < 0) +		return err; +  	if (rpcm)  		*rpcm = pcm;  	return 0; @@ -1361,7 +1368,7 @@ static void __devexit snd_card_fm801_remove(struct pci_dev *pci)  	pci_set_drvdata(pci, NULL);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static unsigned char saved_regs[] = {  	FM801_PCM_VOL, FM801_I2S_VOL, FM801_FM_VOL, FM801_REC_SRC,  	FM801_PLY_CTRL, FM801_PLY_COUNT, FM801_PLY_BUF1, FM801_PLY_BUF2, @@ -1421,7 +1428,7 @@ static SIMPLE_DEV_PM_OPS(snd_fm801_pm, snd_fm801_suspend, snd_fm801_resume);  #define SND_FM801_PM_OPS	&snd_fm801_pm  #else  #define SND_FM801_PM_OPS	NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  static struct pci_driver fm801_driver = {  	.name = KBUILD_MODNAME, diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 194d625c1f8..7105c3de1bc 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -228,17 +228,9 @@ config SND_HDA_GENERIC  	  Say Y here to enable the generic HD-audio codec parser  	  in snd-hda-intel driver. -config SND_HDA_POWER_SAVE -	bool "Aggressive power-saving on HD-audio" -	depends on PM -	help -	  Say Y here to enable more aggressive power-saving mode on -	  HD-audio driver.  The power-saving timeout can be configured -	  via power_save option or over sysfs on-the-fly. -  config SND_HDA_POWER_SAVE_DEFAULT  	int "Default time-out for HD-audio power-save mode" -	depends on SND_HDA_POWER_SAVE +	depends on PM  	default 0  	help  	  The default time-out value in seconds for HD-audio automatic diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index 4f7d2dfcef7..4ec6dc88b7f 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -141,7 +141,6 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,  	memset(sequences_hp, 0, sizeof(sequences_hp));  	assoc_line_out = 0; -	codec->ignore_misc_bit = true;  	end_nid = codec->start_nid + codec->num_nodes;  	for (nid = codec->start_nid; nid < end_nid; nid++) {  		unsigned int wid_caps = get_wcaps(codec, nid); @@ -157,9 +156,6 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,  			continue;  		def_conf = snd_hda_codec_get_pincfg(codec, nid); -		if (!(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) & -		      AC_DEFCFG_MISC_NO_PRESENCE)) -			codec->ignore_misc_bit = false;  		conn = get_defcfg_connect(def_conf);  		if (conn == AC_JACK_PORT_NONE)  			continue; @@ -502,6 +498,38 @@ static const char *check_output_sfx(hda_nid_t nid, const hda_nid_t *pins,  	return channel_sfx[i];  } +static const char *check_output_pfx(struct hda_codec *codec, hda_nid_t nid) +{ +	unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); +	int attr = snd_hda_get_input_pin_attr(def_conf); + +	/* check the location */ +	switch (attr) { +	case INPUT_PIN_ATTR_DOCK: +		return "Dock "; +	case INPUT_PIN_ATTR_FRONT: +		return "Front "; +	} +	return ""; +} + +static int get_hp_label_index(struct hda_codec *codec, hda_nid_t nid, +			      const hda_nid_t *pins, int num_pins) +{ +	int i, j, idx = 0; + +	const char *pfx = check_output_pfx(codec, nid); + +	i = find_idx_in_nid_list(nid, pins, num_pins); +	if (i < 0) +		return -1; +	for (j = 0; j < i; j++) +		if (pfx == check_output_pfx(codec, pins[j])) +			idx++; + +	return idx; +} +  static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,  			       const struct auto_pin_cfg *cfg,  			       const char *name, char *label, int maxlen, @@ -509,20 +537,13 @@ static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,  {  	unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);  	int attr = snd_hda_get_input_pin_attr(def_conf); -	const char *pfx = "", *sfx = ""; +	const char *pfx, *sfx = "";  	/* handle as a speaker if it's a fixed line-out */  	if (!strcmp(name, "Line Out") && attr == INPUT_PIN_ATTR_INT)  		name = "Speaker"; -	/* check the location */ -	switch (attr) { -	case INPUT_PIN_ATTR_DOCK: -		pfx = "Dock "; -		break; -	case INPUT_PIN_ATTR_FRONT: -		pfx = "Front "; -		break; -	} +	pfx = check_output_pfx(codec, nid); +  	if (cfg) {  		/* try to give a unique suffix if needed */  		sfx = check_output_sfx(nid, cfg->line_out_pins, cfg->line_outs, @@ -532,8 +553,8 @@ static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,  					       indexp);  		if (!sfx) {  			/* don't add channel suffix for Headphone controls */ -			int idx = find_idx_in_nid_list(nid, cfg->hp_pins, -						       cfg->hp_outs); +			int idx = get_hp_label_index(codec, nid, cfg->hp_pins, +						     cfg->hp_outs);  			if (idx >= 0)  				*indexp = idx;  			sfx = ""; @@ -739,7 +760,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec,  		for (q = quirk; q->subvendor; q++) {  			unsigned int vendorid =  				q->subdevice | (q->subvendor << 16); -			if (vendorid == codec->subsystem_id) { +			unsigned int mask = 0xffff0000 | q->subdevice_mask; +			if ((codec->subsystem_id & mask) == (vendorid & mask)) {  				id = q->value;  #ifdef CONFIG_SND_DEBUG_VERBOSE  				name = q->name; diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 1c65cc5e3a3..c0ab72cbeed 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -94,13 +94,19 @@ int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset)  }  EXPORT_SYMBOL_HDA(snd_hda_delete_codec_preset); -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  static void hda_power_work(struct work_struct *work);  static void hda_keep_power_on(struct hda_codec *codec);  #define hda_codec_is_power_on(codec)	((codec)->power_on) +static inline void hda_call_pm_notify(struct hda_bus *bus, bool power_up) +{ +	if (bus->ops.pm_notify) +		bus->ops.pm_notify(bus, power_up); +}  #else  static inline void hda_keep_power_on(struct hda_codec *codec) {}  #define hda_codec_is_power_on(codec)	1 +#define hda_call_pm_notify(bus, state) {}  #endif  /** @@ -808,7 +814,7 @@ find_codec_preset(struct hda_codec *codec)  {  	struct hda_codec_preset_list *tbl;  	const struct hda_codec_preset *preset; -	int mod_requested = 0; +	unsigned int mod_requested = 0;  	if (is_generic_config(codec))  		return NULL; /* use the generic parser */ @@ -1186,7 +1192,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)  		return;  	snd_hda_jack_tbl_clear(codec);  	restore_init_pincfgs(codec); -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  	cancel_delayed_work(&codec->power_work);  	flush_workqueue(codec->bus->workq);  #endif @@ -1199,6 +1205,10 @@ static void snd_hda_codec_free(struct hda_codec *codec)  	codec->bus->caddr_tbl[codec->addr] = NULL;  	if (codec->patch_ops.free)  		codec->patch_ops.free(codec); +#ifdef CONFIG_PM +	if (!codec->pm_down_notified) /* cancel leftover refcounts */ +		hda_call_pm_notify(codec->bus, false); +#endif  	module_put(codec->owner);  	free_hda_cache(&codec->amp_cache);  	free_hda_cache(&codec->cmd_cache); @@ -1212,7 +1222,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)  static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec,  				hda_nid_t fg, unsigned int power_state); -static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, +static unsigned int hda_set_power_state(struct hda_codec *codec,  				unsigned int power_state);  /** @@ -1229,6 +1239,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,  {  	struct hda_codec *codec;  	char component[31]; +	hda_nid_t fg;  	int err;  	if (snd_BUG_ON(!bus)) @@ -1263,7 +1274,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,  	snd_array_init(&codec->conn_lists, sizeof(hda_nid_t), 64);  	snd_array_init(&codec->spdif_out, sizeof(struct hda_spdif_out), 16); -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  	spin_lock_init(&codec->power_lock);  	INIT_DELAYED_WORK(&codec->power_work, hda_power_work);  	/* snd_hda_codec_new() marks the codec as power-up, and leave it as is. @@ -1271,6 +1282,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,  	 * phase.  	 */  	hda_keep_power_on(codec); +	hda_call_pm_notify(bus, true);  #endif  	if (codec->bus->modelname) { @@ -1304,7 +1316,8 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,  		goto error;  	} -	err = read_widget_caps(codec, codec->afg ? codec->afg : codec->mfg); +	fg = codec->afg ? codec->afg : codec->mfg; +	err = read_widget_caps(codec, fg);  	if (err < 0) {  		snd_printk(KERN_ERR "hda_codec: cannot malloc\n");  		goto error; @@ -1314,20 +1327,22 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,  		goto error;  	if (!codec->subsystem_id) { -		hda_nid_t nid = codec->afg ? codec->afg : codec->mfg;  		codec->subsystem_id = -			snd_hda_codec_read(codec, nid, 0, +			snd_hda_codec_read(codec, fg, 0,  					   AC_VERB_GET_SUBSYSTEM_ID, 0);  	} -	codec->epss = snd_hda_codec_get_supported_ps(codec, -					codec->afg ? codec->afg : codec->mfg, +#ifdef CONFIG_PM +	codec->d3_stop_clk = snd_hda_codec_get_supported_ps(codec, fg, +					AC_PWRST_CLKSTOP); +	if (!codec->d3_stop_clk) +		bus->power_keep_link_on = 1; +#endif +	codec->epss = snd_hda_codec_get_supported_ps(codec, fg,  					AC_PWRST_EPSS);  	/* power-up all before initialization */ -	hda_set_power_state(codec, -			    codec->afg ? codec->afg : codec->mfg, -			    AC_PWRST_D0); +	hda_set_power_state(codec, AC_PWRST_D0);  	snd_hda_codec_proc_new(codec); @@ -2335,7 +2350,7 @@ int snd_hda_codec_reset(struct hda_codec *codec)  	/* OK, let it free */ -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  	cancel_delayed_work_sync(&codec->power_work);  	codec->power_on = 0;  	codec->power_transition = 0; @@ -3500,20 +3515,6 @@ void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,  		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE,  				    power_state);  	} - -	if (power_state == AC_PWRST_D0) { -		unsigned long end_time; -		int state; -		/* wait until the codec reachs to D0 */ -		end_time = jiffies + msecs_to_jiffies(500); -		do { -			state = snd_hda_codec_read(codec, fg, 0, -						   AC_VERB_GET_POWER_STATE, 0); -			if (state == power_state) -				break; -			msleep(1); -		} while (time_after_eq(end_time, jiffies)); -	}  }  EXPORT_SYMBOL_HDA(snd_hda_codec_set_power_to_all); @@ -3534,18 +3535,40 @@ static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec, hda_nid_t fg  }  /* - * set power state of the codec + * wait until the state is reached, returns the current state   */ -static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, -				unsigned int power_state) +static unsigned int hda_sync_power_state(struct hda_codec *codec, +					 hda_nid_t fg, +					 unsigned int power_state)  { -	int count; -	unsigned int state; +	unsigned long end_time = jiffies + msecs_to_jiffies(500); +	unsigned int state, actual_state; -	if (codec->patch_ops.set_power_state) { -		codec->patch_ops.set_power_state(codec, fg, power_state); -		return; +	for (;;) { +		state = snd_hda_codec_read(codec, fg, 0, +					   AC_VERB_GET_POWER_STATE, 0); +		if (state & AC_PWRST_ERROR) +			break; +		actual_state = (state >> 4) & 0x0f; +		if (actual_state == power_state) +			break; +		if (time_after_eq(jiffies, end_time)) +			break; +		/* wait until the codec reachs to the target state */ +		msleep(1);  	} +	return state; +} + +/* + * set power state of the codec, and return the power state + */ +static unsigned int hda_set_power_state(struct hda_codec *codec, +					unsigned int power_state) +{ +	hda_nid_t fg = codec->afg ? codec->afg : codec->mfg; +	int count; +	unsigned int state;  	/* this delay seems necessary to avoid click noise at power-down */  	if (power_state == AC_PWRST_D3) { @@ -3555,14 +3578,22 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,  	/* repeat power states setting at most 10 times*/  	for (count = 0; count < 10; count++) { -		snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, -				    power_state); -		snd_hda_codec_set_power_to_all(codec, fg, power_state, true); -		state = snd_hda_codec_read(codec, fg, 0, -					   AC_VERB_GET_POWER_STATE, 0); +		if (codec->patch_ops.set_power_state) +			codec->patch_ops.set_power_state(codec, fg, +							 power_state); +		else { +			snd_hda_codec_read(codec, fg, 0, +					   AC_VERB_SET_POWER_STATE, +					   power_state); +			snd_hda_codec_set_power_to_all(codec, fg, power_state, +						       true); +		} +		state = hda_sync_power_state(codec, fg, power_state);  		if (!(state & AC_PWRST_ERROR))  			break;  	} + +	return state;  }  #ifdef CONFIG_SND_HDA_HWDEP @@ -3579,17 +3610,19 @@ static inline void hda_exec_init_verbs(struct hda_codec *codec) {}  #ifdef CONFIG_PM  /*   * call suspend and power-down; used both from PM and power-save + * this function returns the power state in the end   */ -static void hda_call_codec_suspend(struct hda_codec *codec) +static unsigned int hda_call_codec_suspend(struct hda_codec *codec, bool in_wq)  { +	unsigned int state; +  	if (codec->patch_ops.suspend)  		codec->patch_ops.suspend(codec);  	hda_cleanup_all_streams(codec); -	hda_set_power_state(codec, -			    codec->afg ? codec->afg : codec->mfg, -			    AC_PWRST_D3); -#ifdef CONFIG_SND_HDA_POWER_SAVE -	cancel_delayed_work(&codec->power_work); +	state = hda_set_power_state(codec, AC_PWRST_D3); +	/* Cancel delayed work if we aren't currently running from it. */ +	if (!in_wq) +		cancel_delayed_work_sync(&codec->power_work);  	spin_lock(&codec->power_lock);  	snd_hda_update_power_acct(codec);  	trace_hda_power_down(codec); @@ -3597,7 +3630,7 @@ static void hda_call_codec_suspend(struct hda_codec *codec)  	codec->power_transition = 0;  	codec->power_jiffies = jiffies;  	spin_unlock(&codec->power_lock); -#endif +	return state;  }  /* @@ -3609,9 +3642,7 @@ static void hda_call_codec_resume(struct hda_codec *codec)  	 * in the resume / power-save sequence  	 */  	hda_keep_power_on(codec); -	hda_set_power_state(codec, -			    codec->afg ? codec->afg : codec->mfg, -			    AC_PWRST_D0); +	hda_set_power_state(codec, AC_PWRST_D0);  	restore_pincfgs(codec); /* restore all current pin configs */  	restore_shutup_pins(codec);  	hda_exec_init_verbs(codec); @@ -3624,6 +3655,7 @@ static void hda_call_codec_resume(struct hda_codec *codec)  		snd_hda_codec_resume_amp(codec);  		snd_hda_codec_resume_cache(codec);  	} +	snd_hda_jack_report_sync(codec);  	snd_hda_power_down(codec); /* flag down before returning */  }  #endif /* CONFIG_PM */ @@ -3658,6 +3690,36 @@ int /*__devinit*/ snd_hda_build_controls(struct hda_bus *bus)  }  EXPORT_SYMBOL_HDA(snd_hda_build_controls); +/* + * add standard channel maps if not specified + */ +static int add_std_chmaps(struct hda_codec *codec) +{ +	int i, str, err; + +	for (i = 0; i < codec->num_pcms; i++) { +		for (str = 0; str < 2; str++) { +			struct snd_pcm *pcm = codec->pcm_info[i].pcm; +			struct hda_pcm_stream *hinfo = +				&codec->pcm_info[i].stream[str]; +			struct snd_pcm_chmap *chmap; + +			if (codec->pcm_info[i].own_chmap) +				continue; +			if (!pcm || !hinfo->substreams) +				continue; +			err = snd_pcm_add_chmap_ctls(pcm, str, +						     snd_pcm_std_chmaps, +						     hinfo->channels_max, +						     0, &chmap); +			if (err < 0) +				return err; +			chmap->channel_mask = SND_PCM_CHMAP_MASK_2468; +		} +	} +	return 0; +} +  int snd_hda_codec_build_controls(struct hda_codec *codec)  {  	int err = 0; @@ -3669,6 +3731,13 @@ int snd_hda_codec_build_controls(struct hda_codec *codec)  		err = codec->patch_ops.build_controls(codec);  	if (err < 0)  		return err; + +	/* we create chmaps here instead of build_pcms */ +	err = add_std_chmaps(codec); +	if (err < 0) +		return err; + +	snd_hda_jack_report_sync(codec); /* call at the last init point */  	return 0;  } @@ -4211,7 +4280,7 @@ int snd_hda_codec_build_pcms(struct hda_codec *codec)   *   * This function returns 0 if successful, or a negative error code.   */ -int __devinit snd_hda_build_pcms(struct hda_bus *bus) +int snd_hda_build_pcms(struct hda_bus *bus)  {  	struct hda_codec *codec; @@ -4391,12 +4460,13 @@ int snd_hda_add_new_ctls(struct hda_codec *codec,  }  EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls); -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  static void hda_power_work(struct work_struct *work)  {  	struct hda_codec *codec =  		container_of(work, struct hda_codec, power_work.work);  	struct hda_bus *bus = codec->bus; +	unsigned int state;  	spin_lock(&codec->power_lock);  	if (codec->power_transition > 0) { /* during power-up sequence? */ @@ -4410,9 +4480,12 @@ static void hda_power_work(struct work_struct *work)  	}  	spin_unlock(&codec->power_lock); -	hda_call_codec_suspend(codec); -	if (bus->ops.pm_notify) -		bus->ops.pm_notify(bus); +	state = hda_call_codec_suspend(codec, true); +	codec->pm_down_notified = 0; +	if (!bus->power_keep_link_on && (state & AC_PWRST_CLK_STOP_OK)) { +		codec->pm_down_notified = 1; +		hda_call_pm_notify(bus, false); +	}  }  static void hda_keep_power_on(struct hda_codec *codec) @@ -4438,19 +4511,16 @@ void snd_hda_update_power_acct(struct hda_codec *codec)  /* Transition to powered up, if wait_power_down then wait for a pending   * transition to D3 to complete. A pending D3 transition is indicated   * with power_transition == -1. */ +/* call this with codec->power_lock held! */  static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down)  {  	struct hda_bus *bus = codec->bus; -	spin_lock(&codec->power_lock); -	codec->power_count++;  	/* Return if power_on or transitioning to power_on, unless currently  	 * powering down. */  	if ((codec->power_on || codec->power_transition > 0) && -	    !(wait_power_down && codec->power_transition < 0)) { -		spin_unlock(&codec->power_lock); +	    !(wait_power_down && codec->power_transition < 0))  		return; -	}  	spin_unlock(&codec->power_lock);  	cancel_delayed_work_sync(&codec->power_work); @@ -4462,9 +4532,9 @@ static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down)  	if (codec->power_on) {  		if (codec->power_transition < 0)  			codec->power_transition = 0; -		spin_unlock(&codec->power_lock);  		return;  	} +  	trace_hda_power_up(codec);  	snd_hda_update_power_acct(codec);  	codec->power_on = 1; @@ -4472,71 +4542,54 @@ static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down)  	codec->power_transition = 1; /* avoid reentrance */  	spin_unlock(&codec->power_lock); -	if (bus->ops.pm_notify) -		bus->ops.pm_notify(bus); +	if (codec->pm_down_notified) { +		codec->pm_down_notified = 0; +		hda_call_pm_notify(bus, true); +	} +  	hda_call_codec_resume(codec);  	spin_lock(&codec->power_lock);  	codec->power_transition = 0; -	spin_unlock(&codec->power_lock); -} - -/** - * snd_hda_power_up - Power-up the codec - * @codec: HD-audio codec - * - * Increment the power-up counter and power up the hardware really when - * not turned on yet. - */ -void snd_hda_power_up(struct hda_codec *codec) -{ -	__snd_hda_power_up(codec, false);  } -EXPORT_SYMBOL_HDA(snd_hda_power_up); - -/** - * snd_hda_power_up_d3wait - Power-up the codec after waiting for any pending - *   D3 transition to complete.  This differs from snd_hda_power_up() when - *   power_transition == -1.  snd_hda_power_up sees this case as a nop, - *   snd_hda_power_up_d3wait waits for the D3 transition to complete then powers - *   back up. - * @codec: HD-audio codec - * - * Cancel any power down operation hapenning on the work queue, then power up. - */ -void snd_hda_power_up_d3wait(struct hda_codec *codec) -{ -	/* This will cancel and wait for pending power_work to complete. */ -	__snd_hda_power_up(codec, true); -} -EXPORT_SYMBOL_HDA(snd_hda_power_up_d3wait);  #define power_save(codec)	\  	((codec)->bus->power_save ? *(codec)->bus->power_save : 0) -/** - * snd_hda_power_down - Power-down the codec - * @codec: HD-audio codec - * - * Decrement the power-up counter and schedules the power-off work if - * the counter rearches to zero. - */ -void snd_hda_power_down(struct hda_codec *codec) +/* Transition to powered down */ +static void __snd_hda_power_down(struct hda_codec *codec)  { -	spin_lock(&codec->power_lock); -	--codec->power_count; -	if (!codec->power_on || codec->power_count || codec->power_transition) { -		spin_unlock(&codec->power_lock); +	if (!codec->power_on || codec->power_count || codec->power_transition)  		return; -	} +  	if (power_save(codec)) {  		codec->power_transition = -1; /* avoid reentrance */  		queue_delayed_work(codec->bus->workq, &codec->power_work,  				msecs_to_jiffies(power_save(codec) * 1000));  	} +} + +/** + * snd_hda_power_save - Power-up/down/sync the codec + * @codec: HD-audio codec + * @delta: the counter delta to change + * + * Change the power-up counter via @delta, and power up or down the hardware + * appropriately.  For the power-down, queue to the delayed action. + * Passing zero to @delta means to synchronize the power state. + */ +void snd_hda_power_save(struct hda_codec *codec, int delta, bool d3wait) +{ +	spin_lock(&codec->power_lock); +	codec->power_count += delta; +	trace_hda_power_count(codec); +	if (delta > 0) +		__snd_hda_power_up(codec, d3wait); +	else +		__snd_hda_power_down(codec);  	spin_unlock(&codec->power_lock);  } -EXPORT_SYMBOL_HDA(snd_hda_power_down); +EXPORT_SYMBOL_HDA(snd_hda_power_save);  /**   * snd_hda_check_amp_list_power - Check the amp list and update the power @@ -5076,7 +5129,7 @@ int snd_hda_suspend(struct hda_bus *bus)  	list_for_each_entry(codec, &bus->codec_list, list) {  		if (hda_codec_is_power_on(codec)) -			hda_call_codec_suspend(codec); +			hda_call_codec_suspend(codec, false);  	}  	return 0;  } @@ -5087,9 +5140,6 @@ EXPORT_SYMBOL_HDA(snd_hda_suspend);   * @bus: the HDA bus   *   * Returns 0 if successful. - * - * This function is defined only when POWER_SAVE isn't set. - * In the power-save mode, the codec is resumed dynamically.   */  int snd_hda_resume(struct hda_bus *bus)  { diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index e5a7e19a807..507fe8a917b 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -386,6 +386,10 @@ enum {  /* DIGITAL2 bits */  #define AC_DIG2_CC			(0x7f<<0) +/* DIGITAL3 bits */ +#define AC_DIG3_ICT			(0xf<<0) +#define AC_DIG3_KAE			(1<<7) +  /* Pin widget control - 8bit */  #define AC_PINCTL_EPT			(0x3<<0)  #define AC_PINCTL_EPT_NATIVE		0 @@ -610,9 +614,9 @@ struct hda_bus_ops {  			  struct hda_pcm *pcm);  	/* reset bus for retry verb */  	void (*bus_reset)(struct hda_bus *bus); -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  	/* notify power-up/down from codec to controller */ -	void (*pm_notify)(struct hda_bus *bus); +	void (*pm_notify)(struct hda_bus *bus, bool power_up);  #endif  }; @@ -708,8 +712,6 @@ struct hda_codec_ops {  #ifdef CONFIG_PM  	int (*suspend)(struct hda_codec *codec);  	int (*resume)(struct hda_codec *codec); -#endif -#ifdef CONFIG_SND_HDA_POWER_SAVE  	int (*check_power_status)(struct hda_codec *codec, hda_nid_t nid);  #endif  	void (*reboot_notify)(struct hda_codec *codec); @@ -774,6 +776,7 @@ struct hda_pcm {  	unsigned int pcm_type;	/* HDA_PCM_TYPE_XXX */  	int device;		/* device number to assign */  	struct snd_pcm *pcm;	/* assigned PCM instance */ +	bool own_chmap;		/* codec driver provides own channel maps */  };  /* codec information */ @@ -859,12 +862,13 @@ struct hda_codec {  	unsigned int no_sticky_stream:1; /* no sticky-PCM stream assignment */  	unsigned int pins_shutup:1;	/* pins are shut up */  	unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */ -	unsigned int ignore_misc_bit:1; /* ignore MISC_NO_PRESENCE bit */  	unsigned int no_jack_detect:1;	/* Machine has no jack-detection */  	unsigned int pcm_format_first:1; /* PCM format must be set first */  	unsigned int epss:1;		/* supporting EPSS? */ -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  	unsigned int power_on :1;	/* current (global) power-state */ +	unsigned int d3_stop_clk:1;	/* support D3 operation without BCLK */ +	unsigned int pm_down_notified:1; /* PM notified to controller */  	int power_transition;	/* power-state in transition */  	int power_count;	/* current (global) power refcount */  	struct delayed_work power_work; /* delayed task for powerdown */ @@ -1042,7 +1046,7 @@ int snd_hda_resume(struct hda_bus *bus);  static inline  int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid)  { -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  	if (codec->patch_ops.check_power_status)  		return codec->patch_ops.check_power_status(codec, nid);  #endif @@ -1059,22 +1063,70 @@ const char *snd_hda_get_jack_location(u32 cfg);  /*   * power saving   */ -#ifdef CONFIG_SND_HDA_POWER_SAVE -void snd_hda_power_up(struct hda_codec *codec); -void snd_hda_power_up_d3wait(struct hda_codec *codec); -void snd_hda_power_down(struct hda_codec *codec); +#ifdef CONFIG_PM +void snd_hda_power_save(struct hda_codec *codec, int delta, bool d3wait);  void snd_hda_update_power_acct(struct hda_codec *codec);  #else -static inline void snd_hda_power_up(struct hda_codec *codec) {} -static inline void snd_hda_power_up_d3wait(struct hda_codec *codec) {} -static inline void snd_hda_power_down(struct hda_codec *codec) {} +static inline void snd_hda_power_save(struct hda_codec *codec, int delta, +				      bool d3wait) {}  #endif +/** + * snd_hda_power_up - Power-up the codec + * @codec: HD-audio codec + * + * Increment the power-up counter and power up the hardware really when + * not turned on yet. + */ +static inline void snd_hda_power_up(struct hda_codec *codec) +{ +	snd_hda_power_save(codec, 1, false); +} + +/** + * snd_hda_power_up_d3wait - Power-up the codec after waiting for any pending + *   D3 transition to complete.  This differs from snd_hda_power_up() when + *   power_transition == -1.  snd_hda_power_up sees this case as a nop, + *   snd_hda_power_up_d3wait waits for the D3 transition to complete then powers + *   back up. + * @codec: HD-audio codec + * + * Cancel any power down operation hapenning on the work queue, then power up. + */ +static inline void snd_hda_power_up_d3wait(struct hda_codec *codec) +{ +	snd_hda_power_save(codec, 1, true); +} + +/** + * snd_hda_power_down - Power-down the codec + * @codec: HD-audio codec + * + * Decrement the power-up counter and schedules the power-off work if + * the counter rearches to zero. + */ +static inline void snd_hda_power_down(struct hda_codec *codec) +{ +	snd_hda_power_save(codec, -1, false); +} + +/** + * snd_hda_power_sync - Synchronize the power-save status + * @codec: HD-audio codec + * + * Synchronize the actual power state with the power account; + * called when power_save parameter is changed + */ +static inline void snd_hda_power_sync(struct hda_codec *codec) +{ +	snd_hda_power_save(codec, 0, false); +} +  #ifdef CONFIG_SND_HDA_PATCH_LOADER  /*   * patch firmware   */ -int snd_hda_load_patch(struct hda_bus *bus, const char *patch); +int snd_hda_load_patch(struct hda_bus *bus, size_t size, const void *buf);  #endif  /* diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 431bf868711..b81d3d0b952 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -70,7 +70,7 @@ struct hda_gspec {  	struct list_head nid_list;	/* list of widgets */ -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  #define MAX_LOOPBACK_AMPS	7  	struct hda_loopback_check loopback;  	int num_loopbacks; @@ -654,7 +654,7 @@ static int parse_input(struct hda_codec *codec)  	return 0;  } -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  static void add_input_loopback(struct hda_codec *codec, hda_nid_t nid,  			       int dir, int idx)  { @@ -1028,7 +1028,7 @@ static int build_generic_pcms(struct hda_codec *codec)  	return 0;  } -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  static int generic_check_power_status(struct hda_codec *codec, hda_nid_t nid)  {  	struct hda_gspec *spec = codec->spec; @@ -1043,7 +1043,7 @@ static struct hda_codec_ops generic_patch_ops = {  	.build_controls = build_generic_controls,  	.build_pcms = build_generic_pcms,  	.free = snd_hda_generic_free, -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  	.check_power_status = generic_check_power_status,  #endif  }; diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 6b2efb8cb1f..1af86d40eb2 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -25,7 +25,6 @@  #include <linux/mutex.h>  #include <linux/ctype.h>  #include <linux/string.h> -#include <linux/firmware.h>  #include <linux/export.h>  #include <sound/core.h>  #include "hda_codec.h" @@ -156,7 +155,7 @@ int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec)  	return 0;  } -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  static ssize_t power_on_acct_show(struct device *dev,  				  struct device_attribute *attr,  				  char *buf) @@ -192,7 +191,7 @@ int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec)  					  hwdep->device, &power_attrs[i]);  	return 0;  } -#endif /* CONFIG_SND_HDA_POWER_SAVE */ +#endif /* CONFIG_PM */  #ifdef CONFIG_SND_HDA_RECONFIG @@ -747,18 +746,21 @@ static int parse_line_mode(char *buf, struct hda_bus *bus)   *   * the spaces at the beginning and the end of the line are stripped   */ -static int get_line_from_fw(char *buf, int size, struct firmware *fw) +static int get_line_from_fw(char *buf, int size, size_t *fw_size_p, +			    const void **fw_data_p)  {  	int len; -	const char *p = fw->data; -	while (isspace(*p) && fw->size) { +	size_t fw_size = *fw_size_p; +	const char *p = *fw_data_p; + +	while (isspace(*p) && fw_size) {  		p++; -		fw->size--; +		fw_size--;  	} -	if (!fw->size) +	if (!fw_size)  		return 0; -	for (len = 0; len < fw->size; len++) { +	for (len = 0; len < fw_size; len++) {  		if (!*p)  			break;  		if (*p == '\n') { @@ -770,8 +772,8 @@ static int get_line_from_fw(char *buf, int size, struct firmware *fw)  			*buf++ = *p++;  	}  	*buf = 0; -	fw->size -= len; -	fw->data = p; +	*fw_size_p = fw_size - len; +	*fw_data_p = p;  	remove_trail_spaces(buf);  	return 1;  } @@ -779,29 +781,15 @@ static int get_line_from_fw(char *buf, int size, struct firmware *fw)  /*   * load a "patch" firmware file and parse it   */ -int snd_hda_load_patch(struct hda_bus *bus, const char *patch) +int snd_hda_load_patch(struct hda_bus *bus, size_t fw_size, const void *fw_buf)  { -	int err; -	const struct firmware *fw; -	struct firmware tmp;  	char buf[128];  	struct hda_codec *codec;  	int line_mode; -	struct device *dev = bus->card->dev; - -	if (snd_BUG_ON(!dev)) -		return -ENODEV; -	err = request_firmware(&fw, patch, dev); -	if (err < 0) { -		printk(KERN_ERR "hda-codec: Cannot load the patch '%s'\n", -		       patch); -		return err; -	} -	tmp = *fw;  	line_mode = LINE_MODE_NONE;  	codec = NULL; -	while (get_line_from_fw(buf, sizeof(buf) - 1, &tmp)) { +	while (get_line_from_fw(buf, sizeof(buf) - 1, &fw_size, &fw_buf)) {  		if (!*buf || *buf == '#' || *buf == '\n')  			continue;  		if (*buf == '[') @@ -810,7 +798,6 @@ int snd_hda_load_patch(struct hda_bus *bus, const char *patch)  			 (codec || !patch_items[line_mode].need_codec))  			patch_items[line_mode].parser(buf, bus, &codec);  	} -	release_firmware(fw);  	return 0;  }  EXPORT_SYMBOL_HDA(snd_hda_load_patch); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index c4763c52eaf..f09ff6c1404 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -46,6 +46,7 @@  #include <linux/mutex.h>  #include <linux/reboot.h>  #include <linux/io.h> +#include <linux/pm_runtime.h>  #ifdef CONFIG_X86  /* for snoop control */  #include <asm/pgtable.h> @@ -55,6 +56,7 @@  #include <sound/initval.h>  #include <linux/vgaarb.h>  #include <linux/vga_switcheroo.h> +#include <linux/firmware.h>  #include "hda_codec.h" @@ -62,7 +64,7 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;  static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;  static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;  static char *model[SNDRV_CARDS]; -static int position_fix[SNDRV_CARDS]; +static int position_fix[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};  static int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};  static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};  static int probe_only[SNDRV_CARDS]; @@ -86,7 +88,7 @@ module_param_array(model, charp, NULL, 0444);  MODULE_PARM_DESC(model, "Use the given board model.");  module_param_array(position_fix, int, NULL, 0444);  MODULE_PARM_DESC(position_fix, "DMA pointer read method." -		 "(0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO)."); +		 "(-1 = system default, 0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO).");  module_param_array(bdl_pos_adj, int, NULL, 0644);  MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset.");  module_param_array(probe_mask, int, NULL, 0444); @@ -108,9 +110,16 @@ MODULE_PARM_DESC(beep_mode, "Select HDA Beep registration mode "  			    "(0=off, 1=on) (default=1).");  #endif -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM +static int param_set_xint(const char *val, const struct kernel_param *kp); +static struct kernel_param_ops param_ops_xint = { +	.set = param_set_xint, +	.get = param_get_int, +}; +#define param_check_xint param_check_int +  static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; -module_param(power_save, int, 0644); +module_param(power_save, xint, 0644);  MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "  		 "(in second, 0 = disable)."); @@ -121,7 +130,7 @@ MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "  static bool power_save_controller = 1;  module_param(power_save_controller, bool, 0644);  MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode."); -#endif +#endif /* CONFIG_PM */  static int align_buffer_size = -1;  module_param(align_buffer_size, bint, 0644); @@ -406,6 +415,7 @@ struct azx_dev {  	 */  	unsigned int insufficient :1;  	unsigned int wc_marked:1; +	unsigned int no_period_wakeup:1;  };  /* CORB/RIRB */ @@ -471,6 +481,10 @@ struct azx {  	struct snd_dma_buffer rb;  	struct snd_dma_buffer posbuf; +#ifdef CONFIG_SND_HDA_PATCH_LOADER +	const struct firmware *fw; +#endif +  	/* flags */  	int position_fix[2]; /* for both playback/capture streams */  	int poll_count; @@ -498,6 +512,9 @@ struct azx {  	/* reboot notifier (for mysterious hangup problem at power-down) */  	struct notifier_block reboot_notifier; + +	/* card list (for power_save trigger) */ +	struct list_head list;  };  /* driver types */ @@ -538,6 +555,7 @@ enum {  #define AZX_DCAPS_ALIGN_BUFSIZE	(1 << 22)	/* buffer size alignment */  #define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23)	/* BDLE in 4k boundary */  #define AZX_DCAPS_POSFIX_COMBO  (1 << 24)	/* Use COMBO as default */ +#define AZX_DCAPS_COUNT_LPIB_DELAY  (1 << 25)	/* Take LPIB as delay */  /* quirks for ATI SB / AMD Hudson */  #define AZX_DCAPS_PRESET_ATI_SB \ @@ -560,13 +578,17 @@ enum {   * VGA-switcher support   */  #ifdef SUPPORT_VGA_SWITCHEROO +#define use_vga_switcheroo(chip)	((chip)->use_vga_switcheroo) +#else +#define use_vga_switcheroo(chip)	0 +#endif + +#if defined(SUPPORT_VGA_SWITCHEROO) || defined(CONFIG_SND_HDA_PATCH_LOADER)  #define DELAYED_INIT_MARK  #define DELAYED_INITDATA_MARK -#define use_vga_switcheroo(chip)	((chip)->use_vga_switcheroo)  #else  #define DELAYED_INIT_MARK	__devinit  #define DELAYED_INITDATA_MARK	__devinitdata -#define use_vga_switcheroo(chip)	0  #endif  static char *driver_short_names[] DELAYED_INITDATA_MARK = { @@ -1012,8 +1034,8 @@ static unsigned int azx_get_response(struct hda_bus *bus,  		return azx_rirb_get_response(bus, addr);  } -#ifdef CONFIG_SND_HDA_POWER_SAVE -static void azx_power_notify(struct hda_bus *bus); +#ifdef CONFIG_PM +static void azx_power_notify(struct hda_bus *bus, bool power_up);  #endif  /* reset codec link */ @@ -1269,6 +1291,11 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)  	u8 sd_status;  	int i, ok; +#ifdef CONFIG_PM_RUNTIME +	if (chip->pci->dev.power.runtime_status != RPM_ACTIVE) +		return IRQ_NONE; +#endif +  	spin_lock(&chip->reg_lock);  	if (chip->disabled) { @@ -1394,7 +1421,7 @@ static int azx_setup_periods(struct azx *chip,  	ofs = 0;  	azx_dev->frags = 0;  	pos_adj = bdl_pos_adj[chip->dev_index]; -	if (pos_adj > 0) { +	if (!azx_dev->no_period_wakeup && pos_adj > 0) {  		struct snd_pcm_runtime *runtime = substream->runtime;  		int pos_align = pos_adj;  		pos_adj = (pos_adj * runtime->rate + 47999) / 48000; @@ -1410,8 +1437,7 @@ static int azx_setup_periods(struct azx *chip,  			pos_adj = 0;  		} else {  			ofs = setup_bdle(chip, substream, azx_dev, -					 &bdl, ofs, pos_adj, -					 !substream->runtime->no_period_wakeup); +					 &bdl, ofs, pos_adj, true);  			if (ofs < 0)  				goto error;  		} @@ -1424,7 +1450,7 @@ static int azx_setup_periods(struct azx *chip,  		else  			ofs = setup_bdle(chip, substream, azx_dev, &bdl, ofs,  					 period_bytes, -					 !substream->runtime->no_period_wakeup); +					 !azx_dev->no_period_wakeup);  		if (ofs < 0)  			goto error;  	} @@ -1580,7 +1606,7 @@ static int DELAYED_INIT_MARK azx_codec_create(struct azx *chip, const char *mode  	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 +#ifdef CONFIG_PM  	bus_temp.power_save = &power_save;  	bus_temp.ops.pm_notify = azx_power_notify;  #endif @@ -1897,10 +1923,12 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)  	if (bufsize != azx_dev->bufsize ||  	    period_bytes != azx_dev->period_bytes || -	    format_val != azx_dev->format_val) { +	    format_val != azx_dev->format_val || +	    runtime->no_period_wakeup != azx_dev->no_period_wakeup) {  		azx_dev->bufsize = bufsize;  		azx_dev->period_bytes = period_bytes;  		azx_dev->format_val = format_val; +		azx_dev->no_period_wakeup = runtime->no_period_wakeup;  		err = azx_setup_periods(chip, substream, azx_dev);  		if (err < 0)  			return err; @@ -1959,14 +1987,14 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)  	}  	spin_lock(&chip->reg_lock); -	if (nsync > 1) { -		/* first, set SYNC bits of corresponding streams */ -		if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC) -			azx_writel(chip, OLD_SSYNC, -				   azx_readl(chip, OLD_SSYNC) | sbits); -		else -			azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) | sbits); -	} + +	/* first, set SYNC bits of corresponding streams */ +	if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC) +		azx_writel(chip, OLD_SSYNC, +			azx_readl(chip, OLD_SSYNC) | sbits); +	else +		azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) | sbits); +  	snd_pcm_group_for_each_entry(s, substream) {  		if (s->pcm->card != substream->pcm->card)  			continue; @@ -1984,8 +2012,6 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)  	}  	spin_unlock(&chip->reg_lock);  	if (start) { -		if (nsync == 1) -			return 0;  		/* wait until all FIFOs get ready */  		for (timeout = 5000; timeout; timeout--) {  			nwait = 0; @@ -2018,16 +2044,14 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)  			cpu_relax();  		}  	} -	if (nsync > 1) { -		spin_lock(&chip->reg_lock); -		/* reset SYNC bits */ -		if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC) -			azx_writel(chip, OLD_SSYNC, -				   azx_readl(chip, OLD_SSYNC) & ~sbits); -		else -			azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) & ~sbits); -		spin_unlock(&chip->reg_lock); -	} +	spin_lock(&chip->reg_lock); +	/* reset SYNC bits */ +	if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC) +		azx_writel(chip, OLD_SSYNC, +			azx_readl(chip, OLD_SSYNC) & ~sbits); +	else +		azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) & ~sbits); +	spin_unlock(&chip->reg_lock);  	return 0;  } @@ -2120,6 +2144,27 @@ static unsigned int azx_get_position(struct azx *chip,  	if (pos >= azx_dev->bufsize)  		pos = 0; + +	/* calculate runtime delay from LPIB */ +	if (azx_dev->substream->runtime && +	    chip->position_fix[stream] == POS_FIX_POSBUF && +	    (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) { +		unsigned int lpib_pos = azx_sd_readl(azx_dev, SD_LPIB); +		int delay; +		if (stream == SNDRV_PCM_STREAM_PLAYBACK) +			delay = pos - lpib_pos; +		else +			delay = lpib_pos - pos; +		if (delay < 0) +			delay += azx_dev->bufsize; +		if (delay >= azx_dev->period_bytes) { +			snd_printdd("delay %d > period_bytes %d\n", +				delay, azx_dev->period_bytes); +			delay = 0; /* something is wrong */ +		} +		azx_dev->substream->runtime->delay = +			bytes_to_frames(azx_dev->substream->runtime, delay); +	}  	return pos;  } @@ -2379,33 +2424,65 @@ static void azx_stop_chip(struct azx *chip)  	chip->initialized = 0;  } -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  /* power-up/down the controller */ -static void azx_power_notify(struct hda_bus *bus) +static void azx_power_notify(struct hda_bus *bus, bool power_up)  {  	struct azx *chip = bus->private_data; + +	if (power_up) +		pm_runtime_get_sync(&chip->pci->dev); +	else +		pm_runtime_put_sync(&chip->pci->dev); +} + +static DEFINE_MUTEX(card_list_lock); +static LIST_HEAD(card_list); + +static void azx_add_card_list(struct azx *chip) +{ +	mutex_lock(&card_list_lock); +	list_add(&chip->list, &card_list); +	mutex_unlock(&card_list_lock); +} + +static void azx_del_card_list(struct azx *chip) +{ +	mutex_lock(&card_list_lock); +	list_del_init(&chip->list); +	mutex_unlock(&card_list_lock); +} + +/* trigger power-save check at writing parameter */ +static int param_set_xint(const char *val, const struct kernel_param *kp) +{ +	struct azx *chip;  	struct hda_codec *c; -	int power_on = 0; +	int prev = power_save; +	int ret = param_set_int(val, kp); -	list_for_each_entry(c, &bus->codec_list, list) { -		if (c->power_on) { -			power_on = 1; -			break; -		} +	if (ret || prev == power_save) +		return ret; + +	mutex_lock(&card_list_lock); +	list_for_each_entry(chip, &card_list, list) { +		if (!chip->bus || chip->disabled) +			continue; +		list_for_each_entry(c, &chip->bus->codec_list, list) +			snd_hda_power_sync(c);  	} -	if (power_on) -		azx_init_chip(chip, 1); -	else if (chip->running && power_save_controller && -		 !bus->power_keep_link_on) -		azx_stop_chip(chip); +	mutex_unlock(&card_list_lock); +	return 0;  } -#endif /* CONFIG_SND_HDA_POWER_SAVE */ +#else +#define azx_add_card_list(chip) /* NOP */ +#define azx_del_card_list(chip) /* NOP */ +#endif /* CONFIG_PM */ -#ifdef CONFIG_PM +#if defined(CONFIG_PM_SLEEP) || defined(SUPPORT_VGA_SWITCHEROO)  /*   * power management   */ -  static int azx_suspend(struct device *dev)  {  	struct pci_dev *pci = to_pci_dev(dev); @@ -2460,11 +2537,41 @@ static int azx_resume(struct device *dev)  	snd_power_change_state(card, SNDRV_CTL_POWER_D0);  	return 0;  } -static SIMPLE_DEV_PM_OPS(azx_pm, azx_suspend, azx_resume); +#endif /* CONFIG_PM_SLEEP || SUPPORT_VGA_SWITCHEROO */ + +#ifdef CONFIG_PM_RUNTIME +static int azx_runtime_suspend(struct device *dev) +{ +	struct snd_card *card = dev_get_drvdata(dev); +	struct azx *chip = card->private_data; + +	if (!power_save_controller) +		return -EAGAIN; + +	azx_stop_chip(chip); +	azx_clear_irq_pending(chip); +	return 0; +} + +static int azx_runtime_resume(struct device *dev) +{ +	struct snd_card *card = dev_get_drvdata(dev); +	struct azx *chip = card->private_data; + +	azx_init_pci(chip); +	azx_init_chip(chip, 1); +	return 0; +} +#endif /* CONFIG_PM_RUNTIME */ + +#ifdef CONFIG_PM +static const struct dev_pm_ops azx_pm = { +	SET_SYSTEM_SLEEP_PM_OPS(azx_suspend, azx_resume) +	SET_RUNTIME_PM_OPS(azx_runtime_suspend, azx_runtime_resume, NULL) +}; +  #define AZX_PM_OPS	&azx_pm  #else -#define azx_suspend(dev) -#define azx_resume(dev)  #define AZX_PM_OPS	NULL  #endif /* CONFIG_PM */ @@ -2599,6 +2706,8 @@ static int azx_free(struct azx *chip)  {  	int i; +	azx_del_card_list(chip); +  	azx_notifier_unregister(chip);  	if (use_vga_switcheroo(chip)) { @@ -2640,6 +2749,10 @@ static int azx_free(struct azx *chip)  		pci_release_regions(chip->pci);  	pci_disable_device(chip->pci);  	kfree(chip->azx_dev); +#ifdef CONFIG_SND_HDA_PATCH_LOADER +	if (chip->fw) +		release_firmware(chip->fw); +#endif  	kfree(chip);  	return 0; @@ -2719,6 +2832,7 @@ static int __devinit check_position_fix(struct azx *chip, int fix)  	const struct snd_pci_quirk *q;  	switch (fix) { +	case POS_FIX_AUTO:  	case POS_FIX_LPIB:  	case POS_FIX_POSBUF:  	case POS_FIX_VIACOMBO: @@ -2904,6 +3018,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,  	chip->dev_index = dev;  	INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work);  	INIT_LIST_HEAD(&chip->pcm_list); +	INIT_LIST_HEAD(&chip->list);  	init_vga_switcheroo(chip);  	chip->position_fix[0] = chip->position_fix[1] = @@ -3138,7 +3253,7 @@ static int DELAYED_INIT_MARK azx_first_init(struct azx *chip)  static void power_down_all_codecs(struct azx *chip)  { -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  	/* The codecs were powered up in snd_hda_codec_new().  	 * Now all initialization done, so turn them down if possible  	 */ @@ -3149,12 +3264,40 @@ static void power_down_all_codecs(struct azx *chip)  #endif  } +#ifdef CONFIG_SND_HDA_PATCH_LOADER +/* callback from request_firmware_nowait() */ +static void azx_firmware_cb(const struct firmware *fw, void *context) +{ +	struct snd_card *card = context; +	struct azx *chip = card->private_data; +	struct pci_dev *pci = chip->pci; + +	if (!fw) { +		snd_printk(KERN_ERR SFX "Cannot load firmware, aborting\n"); +		goto error; +	} + +	chip->fw = fw; +	if (!chip->disabled) { +		/* continue probing */ +		if (azx_probe_continue(chip)) +			goto error; +	} +	return; /* OK */ + + error: +	snd_card_free(card); +	pci_set_drvdata(pci, NULL); +} +#endif +  static int __devinit azx_probe(struct pci_dev *pci,  			       const struct pci_device_id *pci_id)  {  	static int dev;  	struct snd_card *card;  	struct azx *chip; +	bool probe_now;  	int err;  	if (dev >= SNDRV_CARDS) @@ -3170,15 +3313,28 @@ static int __devinit azx_probe(struct pci_dev *pci,  		return err;  	} -	/* set this here since it's referred in snd_hda_load_patch() */  	snd_card_set_dev(card, &pci->dev);  	err = azx_create(card, pci, dev, pci_id->driver_data, &chip);  	if (err < 0)  		goto out_free;  	card->private_data = chip; +	probe_now = !chip->disabled; -	if (!chip->disabled) { +#ifdef CONFIG_SND_HDA_PATCH_LOADER +	if (patch[dev] && *patch[dev]) { +		snd_printk(KERN_ERR SFX "Applying patch firmware '%s'\n", +			   patch[dev]); +		err = request_firmware_nowait(THIS_MODULE, true, patch[dev], +					      &pci->dev, GFP_KERNEL, card, +					      azx_firmware_cb); +		if (err < 0) +			goto out_free; +		probe_now = false; /* continued in azx_firmware_cb() */ +	} +#endif /* CONFIG_SND_HDA_PATCH_LOADER */ + +	if (probe_now) {  		err = azx_probe_continue(chip);  		if (err < 0)  			goto out_free; @@ -3186,6 +3342,9 @@ static int __devinit azx_probe(struct pci_dev *pci,  	pci_set_drvdata(pci, card); +	if (pci_dev_run_wake(pci)) +		pm_runtime_put_noidle(&pci->dev); +  	dev++;  	return 0; @@ -3208,12 +3367,13 @@ static int DELAYED_INIT_MARK azx_probe_continue(struct azx *chip)  	if (err < 0)  		goto out_free;  #ifdef CONFIG_SND_HDA_PATCH_LOADER -	if (patch[dev] && *patch[dev]) { -		snd_printk(KERN_ERR SFX "Applying patch firmware '%s'\n", -			   patch[dev]); -		err = snd_hda_load_patch(chip->bus, patch[dev]); +	if (chip->fw) { +		err = snd_hda_load_patch(chip->bus, chip->fw->size, +					 chip->fw->data);  		if (err < 0)  			goto out_free; +		release_firmware(chip->fw); /* no longer needed */ +		chip->fw = NULL;  	}  #endif  	if ((probe_only[dev] & 1) == 0) { @@ -3239,6 +3399,7 @@ static int DELAYED_INIT_MARK azx_probe_continue(struct azx *chip)  	chip->running = 1;  	power_down_all_codecs(chip);  	azx_notifier_register(chip); +	azx_add_card_list(chip);  	return 0; @@ -3250,6 +3411,10 @@ out_free:  static void __devexit azx_remove(struct pci_dev *pci)  {  	struct snd_card *card = pci_get_drvdata(pci); + +	if (pci_dev_run_wake(pci)) +		pm_runtime_get_noresume(&pci->dev); +  	if (card)  		snd_card_free(card);  	pci_set_drvdata(pci, NULL); @@ -3260,7 +3425,7 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {  	/* CPT */  	{ PCI_DEVICE(0x8086, 0x1c20),  	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | -	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO }, +	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },  	/* PBG */  	{ PCI_DEVICE(0x8086, 0x1d20),  	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | @@ -3268,23 +3433,30 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {  	/* Panther Point */  	{ PCI_DEVICE(0x8086, 0x1e20),  	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | -	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO }, +	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },  	/* Lynx Point */  	{ PCI_DEVICE(0x8086, 0x8c20),  	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | -	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO }, +	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },  	/* Lynx Point-LP */  	{ PCI_DEVICE(0x8086, 0x9c20),  	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | -	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO }, +	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },  	/* Lynx Point-LP */  	{ PCI_DEVICE(0x8086, 0x9c21),  	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | -	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO }, +	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },  	/* Haswell */  	{ PCI_DEVICE(0x8086, 0x0c0c),  	  .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | -	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO }, +	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, +	{ PCI_DEVICE(0x8086, 0x0d0c), +	  .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | +	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, +	/* 5 Series/3400 */ +	{ PCI_DEVICE(0x8086, 0x3b56), +	  .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | +	  AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },  	/* SCH */  	{ PCI_DEVICE(0x8086, 0x811b),  	  .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index aaccc0236bd..5c690cb873d 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -26,9 +26,8 @@ bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid)  		return false;  	if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT))  		return false; -	if (!codec->ignore_misc_bit && -	    (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) & -	     AC_DEFCFG_MISC_NO_PRESENCE)) +	if (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) & +	     AC_DEFCFG_MISC_NO_PRESENCE)  		return false;  	if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP))  		return false; @@ -193,8 +192,9 @@ EXPORT_SYMBOL_HDA(snd_hda_jack_detect);  /**   * snd_hda_jack_detect_enable - enable the jack-detection   */ -int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid, -			       unsigned char action) +int snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, +					unsigned char action, +					hda_jack_callback cb)  {  	struct hda_jack_tbl *jack = snd_hda_jack_tbl_new(codec, nid);  	if (!jack) @@ -204,10 +204,19 @@ int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid,  	jack->jack_detect = 1;  	if (action)  		jack->action = action; +	if (cb) +		jack->callback = cb;  	return snd_hda_codec_write_cache(codec, nid, 0,  					 AC_VERB_SET_UNSOLICITED_ENABLE,  					 AC_USRSP_EN | jack->tag);  } +EXPORT_SYMBOL_HDA(snd_hda_jack_detect_enable_callback); + +int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid, +			       unsigned char action) +{ +	return snd_hda_jack_detect_enable_callback(codec, nid, action, NULL); +}  EXPORT_SYMBOL_HDA(snd_hda_jack_detect_enable);  /** @@ -412,3 +421,21 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec,  	return 0;  }  EXPORT_SYMBOL_HDA(snd_hda_jack_add_kctls); + +void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res) +{ +	struct hda_jack_tbl *event; +	int tag = (res >> AC_UNSOL_RES_TAG_SHIFT) & 0x7f; + +	event = snd_hda_jack_tbl_get_from_tag(codec, tag); +	if (!event) +		return; +	event->jack_dirty = 1; + +	if (event->callback) +		event->callback(codec, event); + +	snd_hda_jack_report_sync(codec); +} +EXPORT_SYMBOL_HDA(snd_hda_jack_unsol_event); + diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h index a9803da633c..af8dd4724da 100644 --- a/sound/pci/hda/hda_jack.h +++ b/sound/pci/hda/hda_jack.h @@ -13,12 +13,16 @@  #define __SOUND_HDA_JACK_H  struct auto_pin_cfg; +struct hda_jack_tbl; + +typedef void (*hda_jack_callback) (struct hda_codec *, struct hda_jack_tbl *);  struct hda_jack_tbl {  	hda_nid_t nid;  	unsigned char action;		/* event action (0 = none) */  	unsigned char tag;		/* unsol event tag */  	unsigned int private_data;	/* arbitrary data */ +	hda_jack_callback callback;  	/* jack-detection stuff */  	unsigned int pin_sense;		/* cached pin-sense value */  	unsigned int jack_detect:1;	/* capable of jack-detection? */ @@ -61,6 +65,10 @@ void snd_hda_jack_set_dirty_all(struct hda_codec *codec);  int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid,  			       unsigned char action); +int snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, +					unsigned char action, +					hda_jack_callback cb); +  u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid);  int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid); @@ -74,5 +82,6 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec,  void snd_hda_jack_report_sync(struct hda_codec *codec); +void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res);  #endif /* __SOUND_HDA_JACK_H */ diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 1b4c12941ba..09dbdc37f78 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -529,7 +529,7 @@ int snd_hda_create_hwdep(struct hda_codec *codec);  static inline int snd_hda_create_hwdep(struct hda_codec *codec) { return 0; }  #endif -#if defined(CONFIG_SND_HDA_POWER_SAVE) && defined(CONFIG_SND_HDA_HWDEP) +#if defined(CONFIG_PM) && defined(CONFIG_SND_HDA_HWDEP)  int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec);  #else  static inline int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec) diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 6894ec66258..045e5d32f5d 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -402,6 +402,9 @@ static void print_digital_conv(struct snd_info_buffer *buffer,  {  	unsigned int digi1 = snd_hda_codec_read(codec, nid, 0,  						AC_VERB_GET_DIGI_CONVERT_1, 0); +	unsigned char digi2 = digi1 >> 8; +	unsigned char digi3 = digi1 >> 16; +  	snd_iprintf(buffer, "  Digital:");  	if (digi1 & AC_DIG1_ENABLE)  		snd_iprintf(buffer, " Enabled"); @@ -419,9 +422,13 @@ static void print_digital_conv(struct snd_info_buffer *buffer,  		snd_iprintf(buffer, " Pro");  	if (digi1 & AC_DIG1_LEVEL)  		snd_iprintf(buffer, " GenLevel"); +	if (digi3 & AC_DIG3_KAE) +		snd_iprintf(buffer, " KAE");  	snd_iprintf(buffer, "\n");  	snd_iprintf(buffer, "  Digital category: 0x%x\n", -		    (digi1 >> 8) & AC_DIG2_CC); +		    digi2 & AC_DIG2_CC); +	snd_iprintf(buffer, "  IEC Coding Type: 0x%x\n", +			digi3 & AC_DIG3_ICT);  }  static const char *get_pwr_state(u32 state) diff --git a/sound/pci/hda/hda_trace.h b/sound/pci/hda/hda_trace.h index 9884871ddb0..3a1c63161eb 100644 --- a/sound/pci/hda/hda_trace.h +++ b/sound/pci/hda/hda_trace.h @@ -58,6 +58,7 @@ TRACE_EVENT(hda_bus_reset,  	TP_printk("[%d]", __entry->card)  ); +#ifdef CONFIG_PM  DECLARE_EVENT_CLASS(hda_power,  	TP_PROTO(struct hda_codec *codec), @@ -87,6 +88,31 @@ DEFINE_EVENT(hda_power, hda_power_up,  	TP_ARGS(codec)  ); +TRACE_EVENT(hda_power_count, +	TP_PROTO(struct hda_codec *codec), +	TP_ARGS(codec), +	TP_STRUCT__entry( +		__field( unsigned int, card ) +		__field( unsigned int, addr ) +		__field( int, power_count ) +		__field( int, power_on ) +		__field( int, power_transition ) +	), + +	TP_fast_assign( +		__entry->card = (codec)->bus->card->number; +		__entry->addr = (codec)->addr; +		__entry->power_count = (codec)->power_count; +		__entry->power_on = (codec)->power_on; +		__entry->power_transition = (codec)->power_transition; +	), + +	TP_printk("[%d:%d] power_count=%d, power_on=%d, power_transition=%d", +		  __entry->card, __entry->addr, __entry->power_count, +		  __entry->power_on, __entry->power_transition) +); +#endif /* CONFIG_PM */ +  TRACE_EVENT(hda_unsol_event,  	TP_PROTO(struct hda_bus *bus, u32 res, u32 res_ex), diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 0208fa121e5..cdd43eadbc6 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -85,7 +85,7 @@ struct ad198x_spec {  	unsigned int analog_beep: 1;	/* analog beep input present */  	unsigned int avoid_init_slave_vol:1; -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  	struct hda_loopback_check loopback;  #endif  	/* for virtual master */ @@ -269,7 +269,7 @@ static int ad198x_build_controls(struct hda_codec *codec)  	return 0;  } -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid)  {  	struct ad198x_spec *spec = codec->spec; @@ -654,10 +654,8 @@ static const struct hda_codec_ops ad198x_patch_ops = {  	.build_pcms = ad198x_build_pcms,  	.init = ad198x_init,  	.free = ad198x_free, -#ifdef CONFIG_SND_HDA_POWER_SAVE -	.check_power_status = ad198x_check_power_status, -#endif  #ifdef CONFIG_PM +	.check_power_status = ad198x_check_power_status,  	.suspend = ad198x_suspend,  #endif  	.reboot_notify = ad198x_shutup, @@ -1231,7 +1229,7 @@ static const struct snd_pci_quirk ad1986a_cfg_tbl[] = {  	{}  }; -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  static const struct hda_amp_list ad1986a_loopbacks[] = {  	{ 0x13, HDA_OUTPUT, 0 }, /* Mic */  	{ 0x14, HDA_OUTPUT, 0 }, /* Phone */ @@ -1278,7 +1276,7 @@ static int patch_ad1986a(struct hda_codec *codec)  	spec->mixers[0] = ad1986a_mixers;  	spec->num_init_verbs = 1;  	spec->init_verbs[0] = ad1986a_init_verbs; -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  	spec->loopback.amplist = ad1986a_loopbacks;  #endif  	spec->vmaster_nid = 0x1b; @@ -1537,7 +1535,7 @@ static const struct hda_verb ad1983_init_verbs[] = {  	{ } /* end */  }; -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  static const struct hda_amp_list ad1983_loopbacks[] = {  	{ 0x12, HDA_OUTPUT, 0 }, /* Mic */  	{ 0x13, HDA_OUTPUT, 0 }, /* Line */ @@ -1576,7 +1574,7 @@ static int patch_ad1983(struct hda_codec *codec)  	spec->num_init_verbs = 1;  	spec->init_verbs[0] = ad1983_init_verbs;  	spec->spdif_route = 0; -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  	spec->loopback.amplist = ad1983_loopbacks;  #endif  	spec->vmaster_nid = 0x05; @@ -1704,7 +1702,7 @@ static const struct hda_verb ad1981_init_verbs[] = {  	{ } /* end */  }; -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  static const struct hda_amp_list ad1981_loopbacks[] = {  	{ 0x12, HDA_OUTPUT, 0 }, /* Front Mic */  	{ 0x13, HDA_OUTPUT, 0 }, /* Line */ @@ -1812,7 +1810,7 @@ static const struct hda_input_mux ad1981_hp_capture_source = {  	.num_items = 3,  	.items = {  		{ "Mic", 0x0 }, -		{ "Docking-Station", 0x1 }, +		{ "Dock Mic", 0x1 },  		{ "Mix", 0x2 },  	},  }; @@ -1836,8 +1834,8 @@ static const struct snd_kcontrol_new ad1981_hp_mixers[] = {  	 */  	HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),  	HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), -	HDA_CODEC_VOLUME("Docking-Station Playback Volume", 0x13, 0x0, HDA_OUTPUT), -	HDA_CODEC_MUTE("Docking-Station Playback Switch", 0x13, 0x0, HDA_OUTPUT), +	HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), +	HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),  	HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),  	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),  	/* FIXME: does this laptop have analog CD connection? */ @@ -1982,7 +1980,7 @@ static int patch_ad1981(struct hda_codec *codec)  	spec->num_init_verbs = 1;  	spec->init_verbs[0] = ad1981_init_verbs;  	spec->spdif_route = 0; -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  	spec->loopback.amplist = ad1981_loopbacks;  #endif  	spec->vmaster_nid = 0x05; @@ -2807,7 +2805,7 @@ static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res)  		snd_hda_sequence_write(codec, ad1988_laptop_hp_off);  }  -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  static const struct hda_amp_list ad1988_loopbacks[] = {  	{ 0x20, HDA_INPUT, 0 }, /* Front Mic */  	{ 0x20, HDA_INPUT, 1 }, /* Line */ @@ -3399,7 +3397,7 @@ static int patch_ad1988(struct hda_codec *codec)  		codec->patch_ops.unsol_event = ad1988_laptop_unsol_event;  		break;  	} -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  	spec->loopback.amplist = ad1988_loopbacks;  #endif  	spec->vmaster_nid = 0x04; @@ -3555,7 +3553,7 @@ static const struct hda_verb ad1884_init_verbs[] = {  	{ } /* end */  }; -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  static const struct hda_amp_list ad1884_loopbacks[] = {  	{ 0x20, HDA_INPUT, 0 }, /* Front Mic */  	{ 0x20, HDA_INPUT, 1 }, /* Mic */ @@ -3567,7 +3565,7 @@ static const struct hda_amp_list ad1884_loopbacks[] = {  static const char * const ad1884_slave_vols[] = {  	"PCM", "Mic", "Mono", "Front Mic", "Mic", "CD", -	"Internal Mic", "Docking Mic", /* "Beep", */ "IEC958", +	"Internal Mic", "Dock Mic", /* "Beep", */ "IEC958",  	NULL  }; @@ -3602,7 +3600,7 @@ static int patch_ad1884(struct hda_codec *codec)  	spec->num_init_verbs = 1;  	spec->init_verbs[0] = ad1884_init_verbs;  	spec->spdif_route = 0; -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  	spec->loopback.amplist = ad1884_loopbacks;  #endif  	spec->vmaster_nid = 0x04; @@ -3628,7 +3626,7 @@ static const struct hda_input_mux ad1984_thinkpad_capture_source = {  		{ "Mic", 0x0 },  		{ "Internal Mic", 0x1 },  		{ "Mix", 0x3 }, -		{ "Docking-Station", 0x4 }, +		{ "Dock Mic", 0x4 },  	},  }; @@ -3657,8 +3655,8 @@ static const struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {  	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),  	HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),  	HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT), -	HDA_CODEC_VOLUME("Docking Mic Playback Volume", 0x20, 0x04, HDA_INPUT), -	HDA_CODEC_MUTE("Docking Mic Playback Switch", 0x20, 0x04, HDA_INPUT), +	HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT), +	HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),  	HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),  	HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT),  	HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), @@ -3994,7 +3992,7 @@ static const struct hda_verb ad1884a_init_verbs[] = {  	{ } /* end */  }; -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  static const struct hda_amp_list ad1884a_loopbacks[] = {  	{ 0x20, HDA_INPUT, 0 }, /* Front Mic */  	{ 0x20, HDA_INPUT, 1 }, /* Mic */ @@ -4602,7 +4600,7 @@ static int patch_ad1884a(struct hda_codec *codec)  	spec->num_init_verbs = 1;  	spec->init_verbs[0] = ad1884a_init_verbs;  	spec->spdif_route = 0; -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  	spec->loopback.amplist = ad1884a_loopbacks;  #endif  	codec->patch_ops = ad198x_patch_ops; @@ -4814,6 +4812,32 @@ static const struct snd_kcontrol_new ad1882_3stack_mixers[] = {  	{ } /* end */  }; +/* simple auto-mute control for AD1882 3-stack board */ +#define AD1882_HP_EVENT	0x01 + +static void ad1882_3stack_automute(struct hda_codec *codec) +{ +	bool mute = snd_hda_jack_detect(codec, 0x11); +	snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, +			    mute ? 0 : PIN_OUT); +} + +static int ad1882_3stack_automute_init(struct hda_codec *codec) +{ +	ad198x_init(codec); +	ad1882_3stack_automute(codec); +	return 0; +} + +static void ad1882_3stack_unsol_event(struct hda_codec *codec, unsigned int res) +{ +	switch (res >> 26) { +	case AD1882_HP_EVENT: +		ad1882_3stack_automute(codec); +		break; +	} +} +  static const struct snd_kcontrol_new ad1882_6stack_mixers[] = {  	HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT),  	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT), @@ -4928,7 +4952,12 @@ static const struct hda_verb ad1882_init_verbs[] = {  	{ } /* end */  }; -#ifdef CONFIG_SND_HDA_POWER_SAVE +static const struct hda_verb ad1882_3stack_automute_verbs[] = { +	{0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1882_HP_EVENT}, +	{ } /* end */ +}; + +#ifdef CONFIG_PM  static const struct hda_amp_list ad1882_loopbacks[] = {  	{ 0x20, HDA_INPUT, 0 }, /* Front Mic */  	{ 0x20, HDA_INPUT, 1 }, /* Mic */ @@ -4942,12 +4971,14 @@ static const struct hda_amp_list ad1882_loopbacks[] = {  enum {  	AD1882_3STACK,  	AD1882_6STACK, +	AD1882_3STACK_AUTOMUTE,  	AD1882_MODELS  };  static const char * const ad1882_models[AD1986A_MODELS] = {  	[AD1882_3STACK]		= "3stack",  	[AD1882_6STACK]		= "6stack", +	[AD1882_3STACK_AUTOMUTE] = "3stack-automute",  }; @@ -4989,7 +5020,7 @@ static int patch_ad1882(struct hda_codec *codec)  	spec->num_init_verbs = 1;  	spec->init_verbs[0] = ad1882_init_verbs;  	spec->spdif_route = 0; -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  	spec->loopback.amplist = ad1882_loopbacks;  #endif  	spec->vmaster_nid = 0x04; @@ -5002,6 +5033,7 @@ static int patch_ad1882(struct hda_codec *codec)  	switch (board_config) {  	default:  	case AD1882_3STACK: +	case AD1882_3STACK_AUTOMUTE:  		spec->num_mixers = 3;  		spec->mixers[2] = ad1882_3stack_mixers;  		spec->channel_mode = ad1882_modes; @@ -5009,6 +5041,12 @@ static int patch_ad1882(struct hda_codec *codec)  		spec->need_dac_fix = 1;  		spec->multiout.max_channels = 2;  		spec->multiout.num_dacs = 1; +		if (board_config != AD1882_3STACK) { +			spec->init_verbs[spec->num_init_verbs++] = +				ad1882_3stack_automute_verbs; +			codec->patch_ops.unsol_event = ad1882_3stack_unsol_event; +			codec->patch_ops.init = ad1882_3stack_automute_init; +		}  		break;  	case AD1882_6STACK:  		spec->num_mixers = 3; diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 0c4c1a61b37..fcfc9f0a056 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -34,7 +34,8 @@   */  struct cs_spec { -	int board_config; +	struct hda_gen_spec gen; +  	struct auto_pin_cfg autocfg;  	struct hda_multi_out multiout;  	struct snd_kcontrol *vmaster_sw; @@ -80,16 +81,20 @@ enum {  	CS420X_MBP53,  	CS420X_MBP55,  	CS420X_IMAC27, -	CS420X_IMAC27_122, -	CS420X_APPLE, +	CS420X_GPIO_13, +	CS420X_GPIO_23, +	CS420X_MBP101, +	CS420X_MBP101_COEF,  	CS420X_AUTO, -	CS420X_MODELS +	/* aliases */ +	CS420X_IMAC27_122 = CS420X_GPIO_23, +	CS420X_APPLE = CS420X_GPIO_13,  };  /* CS421x boards */  enum {  	CS421X_CDB4210, -	CS421X_MODELS +	CS421X_SENSE_B,  };  /* Vendor-specific processing widget */ @@ -1157,6 +1162,14 @@ static const struct hda_verb cs_errata_init_verbs[] = {  	{} /* terminator */  }; +static const struct hda_verb mbp101_init_verbs[] = { +	{0x11, AC_VERB_SET_COEF_INDEX, 0x0002}, +	{0x11, AC_VERB_SET_PROC_COEF, 0x100a}, +	{0x11, AC_VERB_SET_COEF_INDEX, 0x0004}, +	{0x11, AC_VERB_SET_PROC_COEF, 0x000f}, +	{} +}; +  /* SPDIF setup */  static void init_digital(struct hda_codec *codec)  { @@ -1193,7 +1206,6 @@ static int cs_init(struct hda_codec *codec)  	init_output(codec);  	init_input(codec);  	init_digital(codec); -	snd_hda_jack_report_sync(codec);  	return 0;  } @@ -1279,38 +1291,32 @@ static int cs_parse_auto_config(struct hda_codec *codec)  	return 0;  } -static const char * const cs420x_models[CS420X_MODELS] = { -	[CS420X_MBP53] = "mbp53", -	[CS420X_MBP55] = "mbp55", -	[CS420X_IMAC27] = "imac27", -	[CS420X_IMAC27_122] = "imac27_122", -	[CS420X_APPLE] = "apple", -	[CS420X_AUTO] = "auto", +static const struct hda_model_fixup cs420x_models[] = { +	{ .id = CS420X_MBP53, .name = "mbp53" }, +	{ .id = CS420X_MBP55, .name = "mbp55" }, +	{ .id = CS420X_IMAC27, .name = "imac27" }, +	{ .id = CS420X_IMAC27_122, .name = "imac27_122" }, +	{ .id = CS420X_APPLE, .name = "apple" }, +	{ .id = CS420X_MBP101, .name = "mbp101" }, +	{}  }; - -static const struct snd_pci_quirk cs420x_cfg_tbl[] = { +static const struct snd_pci_quirk cs420x_fixup_tbl[] = {  	SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53),  	SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55),  	SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),  	SND_PCI_QUIRK(0x10de, 0xcb89, "MacBookPro 7,1", CS420X_MBP55),  	/* this conflicts with too many other models */  	/*SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),*/ -	{} /* terminator */ -}; -static const struct snd_pci_quirk cs420x_codec_cfg_tbl[] = { +	/* codec SSID */  	SND_PCI_QUIRK(0x106b, 0x2000, "iMac 12,2", CS420X_IMAC27_122), +	SND_PCI_QUIRK(0x106b, 0x2800, "MacBookPro 10,1", CS420X_MBP101),  	SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS420X_APPLE),  	{} /* terminator */  }; -struct cs_pincfg { -	hda_nid_t nid; -	u32 val; -}; - -static const struct cs_pincfg mbp53_pincfgs[] = { +static const struct hda_pintbl mbp53_pincfgs[] = {  	{ 0x09, 0x012b4050 },  	{ 0x0a, 0x90100141 },  	{ 0x0b, 0x90100140 }, @@ -1324,7 +1330,7 @@ static const struct cs_pincfg mbp53_pincfgs[] = {  	{} /* terminator */  }; -static const struct cs_pincfg mbp55_pincfgs[] = { +static const struct hda_pintbl mbp55_pincfgs[] = {  	{ 0x09, 0x012b4030 },  	{ 0x0a, 0x90100121 },  	{ 0x0b, 0x90100120 }, @@ -1338,7 +1344,7 @@ static const struct cs_pincfg mbp55_pincfgs[] = {  	{} /* terminator */  }; -static const struct cs_pincfg imac27_pincfgs[] = { +static const struct hda_pintbl imac27_pincfgs[] = {  	{ 0x09, 0x012b4050 },  	{ 0x0a, 0x90100140 },  	{ 0x0b, 0x90100142 }, @@ -1352,22 +1358,78 @@ static const struct cs_pincfg imac27_pincfgs[] = {  	{} /* terminator */  }; -static const struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = { -	[CS420X_MBP53] = mbp53_pincfgs, -	[CS420X_MBP55] = mbp55_pincfgs, -	[CS420X_IMAC27] = imac27_pincfgs, +static const struct hda_pintbl mbp101_pincfgs[] = { +	{ 0x0d, 0x40ab90f0 }, +	{ 0x0e, 0x90a600f0 }, +	{ 0x12, 0x50a600f0 }, +	{} /* terminator */  }; -static void fix_pincfg(struct hda_codec *codec, int model, -		       const struct cs_pincfg **pin_configs) +static void cs420x_fixup_gpio_13(struct hda_codec *codec, +				 const struct hda_fixup *fix, int action)  { -	const struct cs_pincfg *cfg = pin_configs[model]; -	if (!cfg) -		return; -	for (; cfg->nid; cfg++) -		snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val); +	if (action == HDA_FIXUP_ACT_PRE_PROBE) { +		struct cs_spec *spec = codec->spec; +		spec->gpio_eapd_hp = 2; /* GPIO1 = headphones */ +		spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */ +		spec->gpio_mask = spec->gpio_dir = +			spec->gpio_eapd_hp | spec->gpio_eapd_speaker; +	}  } +static void cs420x_fixup_gpio_23(struct hda_codec *codec, +				 const struct hda_fixup *fix, int action) +{ +	if (action == HDA_FIXUP_ACT_PRE_PROBE) { +		struct cs_spec *spec = codec->spec; +		spec->gpio_eapd_hp = 4; /* GPIO2 = headphones */ +		spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */ +		spec->gpio_mask = spec->gpio_dir = +			spec->gpio_eapd_hp | spec->gpio_eapd_speaker; +	} +} + +static const struct hda_fixup cs420x_fixups[] = { +	[CS420X_MBP53] = { +		.type = HDA_FIXUP_PINS, +		.v.pins = mbp53_pincfgs, +		.chained = true, +		.chain_id = CS420X_APPLE, +	}, +	[CS420X_MBP55] = { +		.type = HDA_FIXUP_PINS, +		.v.pins = mbp55_pincfgs, +		.chained = true, +		.chain_id = CS420X_GPIO_13, +	}, +	[CS420X_IMAC27] = { +		.type = HDA_FIXUP_PINS, +		.v.pins = imac27_pincfgs, +		.chained = true, +		.chain_id = CS420X_GPIO_13, +	}, +	[CS420X_GPIO_13] = { +		.type = HDA_FIXUP_FUNC, +		.v.func = cs420x_fixup_gpio_13, +	}, +	[CS420X_GPIO_23] = { +		.type = HDA_FIXUP_FUNC, +		.v.func = cs420x_fixup_gpio_23, +	}, +	[CS420X_MBP101] = { +		.type = HDA_FIXUP_PINS, +		.v.pins = mbp101_pincfgs, +		.chained = true, +		.chain_id = CS420X_MBP101_COEF, +	}, +	[CS420X_MBP101_COEF] = { +		.type = HDA_FIXUP_VERBS, +		.v.verbs = mbp101_init_verbs, +		.chained = true, +		.chain_id = CS420X_GPIO_13, +	}, +}; +  static int patch_cs420x(struct hda_codec *codec)  {  	struct cs_spec *spec; @@ -1380,33 +1442,9 @@ static int patch_cs420x(struct hda_codec *codec)  	spec->vendor_nid = CS420X_VENDOR_NID; -	spec->board_config = -		snd_hda_check_board_config(codec, CS420X_MODELS, -					   cs420x_models, cs420x_cfg_tbl); -	if (spec->board_config < 0) -		spec->board_config = -			snd_hda_check_board_codec_sid_config(codec, -				CS420X_MODELS, NULL, cs420x_codec_cfg_tbl); -	if (spec->board_config >= 0) -		fix_pincfg(codec, spec->board_config, cs_pincfgs); - -	switch (spec->board_config) { -	case CS420X_IMAC27: -	case CS420X_MBP53: -	case CS420X_MBP55: -	case CS420X_APPLE: -		spec->gpio_eapd_hp = 2; /* GPIO1 = headphones */ -		spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */ -		spec->gpio_mask = spec->gpio_dir = -			spec->gpio_eapd_hp | spec->gpio_eapd_speaker; -		break; -	case CS420X_IMAC27_122: -		spec->gpio_eapd_hp = 4; /* GPIO2 = headphones */ -		spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */ -		spec->gpio_mask = spec->gpio_dir = -			spec->gpio_eapd_hp | spec->gpio_eapd_speaker; -		break; -	} +	snd_hda_pick_fixup(codec, cs420x_models, cs420x_fixup_tbl, +			   cs420x_fixups); +	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);  	err = cs_parse_auto_config(codec);  	if (err < 0) @@ -1414,6 +1452,8 @@ static int patch_cs420x(struct hda_codec *codec)  	codec->patch_ops = cs_patch_ops; +	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); +  	return 0;   error: @@ -1431,11 +1471,12 @@ static int patch_cs420x(struct hda_codec *codec)  */  /* CS4210 board names */ -static const char *cs421x_models[CS421X_MODELS] = { -	[CS421X_CDB4210] = "cdb4210", +static const struct hda_model_fixup cs421x_models[] = { +	{ .id = CS421X_CDB4210, .name = "cdb4210" }, +	{}  }; -static const struct snd_pci_quirk cs421x_cfg_tbl[] = { +static const struct snd_pci_quirk cs421x_fixup_tbl[] = {  	/* Test Intel board + CDB2410  */  	SND_PCI_QUIRK(0x8086, 0x5001, "DP45SG/CDB4210", CS421X_CDB4210),  	{} /* terminator */ @@ -1443,7 +1484,7 @@ static const struct snd_pci_quirk cs421x_cfg_tbl[] = {  /* CS4210 board pinconfigs */  /* Default CS4210 (CDB4210)*/ -static const struct cs_pincfg cdb4210_pincfgs[] = { +static const struct hda_pintbl cdb4210_pincfgs[] = {  	{ 0x05, 0x0321401f },  	{ 0x06, 0x90170010 },  	{ 0x07, 0x03813031 }, @@ -1453,8 +1494,26 @@ static const struct cs_pincfg cdb4210_pincfgs[] = {  	{} /* terminator */  }; -static const struct cs_pincfg *cs421x_pincfgs[CS421X_MODELS] = { -	[CS421X_CDB4210] = cdb4210_pincfgs, +/* Setup GPIO/SENSE for each board (if used) */ +static void cs421x_fixup_sense_b(struct hda_codec *codec, +				 const struct hda_fixup *fix, int action) +{ +	struct cs_spec *spec = codec->spec; +	if (action == HDA_FIXUP_ACT_PRE_PROBE) +		spec->sense_b = 1; +} + +static const struct hda_fixup cs421x_fixups[] = { +	[CS421X_CDB4210] = { +		.type = HDA_FIXUP_PINS, +		.v.pins = cdb4210_pincfgs, +		.chained = true, +		.chain_id = CS421X_SENSE_B, +	}, +	[CS421X_SENSE_B] = { +		.type = HDA_FIXUP_FUNC, +		.v.func = cs421x_fixup_sense_b, +	}  };  static const struct hda_verb cs421x_coef_init_verbs[] = { @@ -1643,7 +1702,6 @@ static int cs421x_init(struct hda_codec *codec)  	init_output(codec);  	init_input(codec);  	init_cs421x_digital(codec); -	snd_hda_jack_report_sync(codec);  	return 0;  } @@ -1937,26 +1995,9 @@ static int patch_cs4210(struct hda_codec *codec)  	spec->vendor_nid = CS4210_VENDOR_NID; -	spec->board_config = -		snd_hda_check_board_config(codec, CS421X_MODELS, -					   cs421x_models, cs421x_cfg_tbl); -	if (spec->board_config >= 0) -		fix_pincfg(codec, spec->board_config, cs421x_pincfgs); -	/* -	    Setup GPIO/SENSE for each board (if used) -	*/ -	switch (spec->board_config) { -	case CS421X_CDB4210: -		snd_printd("CS4210 board: %s\n", -			cs421x_models[spec->board_config]); -/*		spec->gpio_mask = 3; -		spec->gpio_dir = 3; -		spec->gpio_data = 3; -*/ -		spec->sense_b = 1; - -		break; -	} +	snd_hda_pick_fixup(codec, cs421x_models, cs421x_fixup_tbl, +			   cs421x_fixups); +	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);  	/*  	    Update the GPIO/DMIC/SENSE_B pinmux before the configuration @@ -1971,6 +2012,8 @@ static int patch_cs4210(struct hda_codec *codec)  	codec->patch_ops = cs421x_patch_ops; +	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); +  	return 0;   error: diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 5e22a8f43d2..03b1dc317ff 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -553,7 +553,7 @@ static int conexant_build_controls(struct hda_codec *codec)  	return 0;  } -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  static int conexant_suspend(struct hda_codec *codec)  {  	snd_hda_shutup_pins(codec); @@ -567,7 +567,7 @@ static const struct hda_codec_ops conexant_patch_ops = {  	.init = conexant_init,  	.free = conexant_free,  	.set_power_state = conexant_set_power, -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  	.suspend = conexant_suspend,  #endif  	.reboot_notify = snd_hda_shutup_pins, @@ -1710,8 +1710,8 @@ static const struct snd_kcontrol_new cxt5051_capture_mixers[] = {  	HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),  	HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT),  	HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT), -	HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT), -	HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT), +	HDA_CODEC_VOLUME("Dock Mic Volume", 0x15, 0x00, HDA_INPUT), +	HDA_CODEC_MUTE("Dock Mic Switch", 0x15, 0x00, HDA_INPUT),  	{}  }; @@ -3402,7 +3402,7 @@ static void cx_auto_update_speakers(struct hda_codec *codec)  	do_automute(codec, cfg->line_outs, cfg->line_out_pins, on);  } -static void cx_auto_hp_automute(struct hda_codec *codec) +static void cx_auto_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)  {  	struct conexant_spec *spec = codec->spec;  	struct auto_pin_cfg *cfg = &spec->autocfg; @@ -3413,7 +3413,7 @@ static void cx_auto_hp_automute(struct hda_codec *codec)  	cx_auto_update_speakers(codec);  } -static void cx_auto_line_automute(struct hda_codec *codec) +static void cx_auto_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)  {  	struct conexant_spec *spec = codec->spec;  	struct auto_pin_cfg *cfg = &spec->autocfg; @@ -3540,8 +3540,9 @@ static int __select_input_connection(struct hda_codec *codec, hda_nid_t mux,  				     hda_nid_t pin, hda_nid_t *srcp,  				     bool do_select, int depth)  { +	struct conexant_spec *spec = codec->spec;  	hda_nid_t conn[HDA_MAX_NUM_INPUTS]; -	int i, nums; +	int startidx, i, nums;  	switch (get_wcaps_type(get_wcaps(codec, mux))) {  	case AC_WID_AUD_IN: @@ -3565,14 +3566,25 @@ static int __select_input_connection(struct hda_codec *codec, hda_nid_t mux,  	depth++;  	if (depth == 2)  		return -1; + +	/* Try to rotate around connections to avoid one boost controlling +	   another input path as well */ +	startidx = 0; +	for (i = 0; i < spec->private_imux.num_items; i++) +		if (spec->imux_info[i].pin == pin) { +			startidx = i; +			break; +		} +  	for (i = 0; i < nums; i++) { -		int ret  = __select_input_connection(codec, conn[i], pin, srcp, +		int j = (i + startidx) % nums; +		int ret  = __select_input_connection(codec, conn[j], pin, srcp,  						     do_select, depth);  		if (ret >= 0) {  			if (do_select)  				snd_hda_codec_write(codec, mux, 0, -						    AC_VERB_SET_CONNECT_SEL, i); -			return i; +						    AC_VERB_SET_CONNECT_SEL, j); +			return j;  		}  	}  	return -1; @@ -3652,7 +3664,7 @@ static bool select_automic(struct hda_codec *codec, int idx, bool detect)  }  /* automatic switch internal and external mic */ -static void cx_auto_automic(struct hda_codec *codec) +static void cx_auto_automic(struct hda_codec *codec, struct hda_jack_tbl *jack)  {  	struct conexant_spec *spec = codec->spec; @@ -3663,22 +3675,6 @@ static void cx_auto_automic(struct hda_codec *codec)  			select_automic(codec, spec->auto_mic_int, false);  } -static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) -{ -	switch (snd_hda_jack_get_action(codec, res >> 26)) { -	case CONEXANT_HP_EVENT: -		cx_auto_hp_automute(codec); -		break; -	case CONEXANT_LINE_EVENT: -		cx_auto_line_automute(codec); -		break; -	case CONEXANT_MIC_EVENT: -		cx_auto_automic(codec); -		break; -	} -	snd_hda_jack_report_sync(codec); -} -  /* check whether the pin config is suitable for auto-mic switching;   * auto-mic is enabled only when one int-mic and one ext- and/or   * one dock-mic exist @@ -3888,11 +3884,12 @@ static void mute_outputs(struct hda_codec *codec, int num_nids,  }  static void enable_unsol_pins(struct hda_codec *codec, int num_pins, -			      hda_nid_t *pins, unsigned int action) +			      hda_nid_t *pins, unsigned int action, +			      hda_jack_callback cb)  {  	int i;  	for (i = 0; i < num_pins; i++) -		snd_hda_jack_detect_enable(codec, pins[i], action); +		snd_hda_jack_detect_enable_callback(codec, pins[i], action, cb);  }  static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) @@ -3980,13 +3977,14 @@ static void cx_auto_init_output(struct hda_codec *codec)  	}  	if (spec->auto_mute) {  		enable_unsol_pins(codec, cfg->hp_outs, cfg->hp_pins, -				  CONEXANT_HP_EVENT); +				  CONEXANT_HP_EVENT, cx_auto_hp_automute);  		spec->hp_present = detect_jacks(codec, cfg->hp_outs,  						cfg->hp_pins);  		if (spec->detect_line) {  			enable_unsol_pins(codec, cfg->line_outs,  					  cfg->line_out_pins, -					  CONEXANT_LINE_EVENT); +					  CONEXANT_LINE_EVENT, +					  cx_auto_line_automute);  			spec->line_present =  				detect_jacks(codec, cfg->line_outs,  					     cfg->line_out_pins); @@ -4027,16 +4025,16 @@ static void cx_auto_init_input(struct hda_codec *codec)  	if (spec->auto_mic) {  		if (spec->auto_mic_ext >= 0) { -			snd_hda_jack_detect_enable(codec, +			snd_hda_jack_detect_enable_callback(codec,  				cfg->inputs[spec->auto_mic_ext].pin, -				CONEXANT_MIC_EVENT); +				CONEXANT_MIC_EVENT, cx_auto_automic);  		}  		if (spec->auto_mic_dock >= 0) { -			snd_hda_jack_detect_enable(codec, +			snd_hda_jack_detect_enable_callback(codec,  				cfg->inputs[spec->auto_mic_dock].pin, -				CONEXANT_MIC_EVENT); +				CONEXANT_MIC_EVENT, cx_auto_automic);  		} -		cx_auto_automic(codec); +		cx_auto_automic(codec, NULL);  	} else {  		select_input_connection(codec, spec->imux_info[0].adc,  					spec->imux_info[0].pin); @@ -4061,7 +4059,6 @@ static int cx_auto_init(struct hda_codec *codec)  	cx_auto_init_output(codec);  	cx_auto_init_input(codec);  	cx_auto_init_digital(codec); -	snd_hda_jack_report_sync(codec);  	snd_hda_sync_vmaster_hook(&spec->vmaster_mute);  	return 0;  } @@ -4262,7 +4259,7 @@ static int cx_auto_add_boost_volume(struct hda_codec *codec, int idx,  	if (get_wcaps(codec, mux) & AC_WCAP_OUT_AMP) {  		spec->imux_info[idx].boost = mux; -		return cx_auto_add_volume(codec, label, " Boost", 0, +		return cx_auto_add_volume(codec, label, " Boost", cidx,  					  mux, HDA_OUTPUT);  	}  	return 0; @@ -4395,8 +4392,8 @@ static const struct hda_codec_ops cx_auto_patch_ops = {  	.build_pcms = conexant_build_pcms,  	.init = cx_auto_init,  	.free = conexant_free, -	.unsol_event = cx_auto_unsol_event, -#ifdef CONFIG_SND_HDA_POWER_SAVE +	.unsol_event = snd_hda_jack_unsol_event, +#ifdef CONFIG_PM  	.suspend = conexant_suspend,  #endif  	.reboot_notify = snd_hda_shutup_pins, @@ -4462,6 +4459,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {  	SND_PCI_QUIRK(0x17aa, 0x21ce, "Lenovo T420", CXT_PINCFG_LENOVO_TP410),  	SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520", CXT_PINCFG_LENOVO_TP410),  	SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC), +	SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC),  	SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC),  	{}  }; diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 8f23374fa64..71555cc54db 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -34,6 +34,8 @@  #include <linux/module.h>  #include <sound/core.h>  #include <sound/jack.h> +#include <sound/asoundef.h> +#include <sound/tlv.h>  #include "hda_codec.h"  #include "hda_local.h"  #include "hda_jack.h" @@ -71,6 +73,9 @@ struct hdmi_spec_per_pin {  	struct hdmi_eld sink_eld;  	struct delayed_work work;  	int repoll_count; +	bool non_pcm; +	bool chmap_set;		/* channel-map override by ALSA API? */ +	unsigned char chmap[8]; /* ALSA API channel-map */  };  struct hdmi_spec { @@ -80,6 +85,7 @@ struct hdmi_spec {  	int num_pins;  	struct hdmi_spec_per_pin pins[MAX_HDMI_PINS];  	struct hda_pcm pcm_rec[MAX_HDMI_PINS]; +	unsigned int channels_max; /* max over all cvts */  	/*  	 * Non-generic ATI/NVIDIA specific @@ -469,6 +475,17 @@ static void init_channel_allocations(void)  	}  } +static int get_channel_allocation_order(int ca) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { +		if (channel_allocations[i].ca_index == ca) +			break; +	} +	return i; +} +  /*   * The transformation takes two steps:   * @@ -535,24 +552,36 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec,  } -static void hdmi_setup_channel_mapping(struct hda_codec *codec, +static void hdmi_std_setup_channel_mapping(struct hda_codec *codec,  				       hda_nid_t pin_nid, +				       bool non_pcm,  				       int ca)  {  	int i;  	int err; +	int order; +	int non_pcm_mapping[8]; + +	order = get_channel_allocation_order(ca);  	if (hdmi_channel_mapping[ca][1] == 0) { -		for (i = 0; i < channel_allocations[ca].channels; i++) +		for (i = 0; i < channel_allocations[order].channels; i++)  			hdmi_channel_mapping[ca][i] = i | (i << 4);  		for (; i < 8; i++)  			hdmi_channel_mapping[ca][i] = 0xf | (i << 4);  	} +	if (non_pcm) { +		for (i = 0; i < channel_allocations[order].channels; i++) +			non_pcm_mapping[i] = i | (i << 4); +		for (; i < 8; i++) +			non_pcm_mapping[i] = 0xf | (i << 4); +	} +  	for (i = 0; i < 8; i++) {  		err = snd_hda_codec_write(codec, pin_nid, 0,  					  AC_VERB_SET_HDMI_CHAN_SLOT, -					  hdmi_channel_mapping[ca][i]); +					  non_pcm ? non_pcm_mapping[i] : hdmi_channel_mapping[ca][i]);  		if (err) {  			snd_printdd(KERN_NOTICE  				    "HDMI: channel mapping failed\n"); @@ -563,6 +592,136 @@ static void hdmi_setup_channel_mapping(struct hda_codec *codec,  	hdmi_debug_channel_mapping(codec, pin_nid);  } +struct channel_map_table { +	unsigned char map;		/* ALSA API channel map position */ +	unsigned char cea_slot;		/* CEA slot value */ +	int spk_mask;			/* speaker position bit mask */ +}; + +static struct channel_map_table map_tables[] = { +	{ SNDRV_CHMAP_FL,	0x00,	FL }, +	{ SNDRV_CHMAP_FR,	0x01,	FR }, +	{ SNDRV_CHMAP_RL,	0x04,	RL }, +	{ SNDRV_CHMAP_RR,	0x05,	RR }, +	{ SNDRV_CHMAP_LFE,	0x02,	LFE }, +	{ SNDRV_CHMAP_FC,	0x03,	FC }, +	{ SNDRV_CHMAP_RLC,	0x06,	RLC }, +	{ SNDRV_CHMAP_RRC,	0x07,	RRC }, +	{} /* terminator */ +}; + +/* from ALSA API channel position to speaker bit mask */ +static int to_spk_mask(unsigned char c) +{ +	struct channel_map_table *t = map_tables; +	for (; t->map; t++) { +		if (t->map == c) +			return t->spk_mask; +	} +	return 0; +} + +/* from ALSA API channel position to CEA slot */ +static int to_cea_slot(unsigned char c) +{ +	struct channel_map_table *t = map_tables; +	for (; t->map; t++) { +		if (t->map == c) +			return t->cea_slot; +	} +	return 0x0f; +} + +/* from CEA slot to ALSA API channel position */ +static int from_cea_slot(unsigned char c) +{ +	struct channel_map_table *t = map_tables; +	for (; t->map; t++) { +		if (t->cea_slot == c) +			return t->map; +	} +	return 0; +} + +/* from speaker bit mask to ALSA API channel position */ +static int spk_to_chmap(int spk) +{ +	struct channel_map_table *t = map_tables; +	for (; t->map; t++) { +		if (t->spk_mask == spk) +			return t->map; +	} +	return 0; +} + +/* get the CA index corresponding to the given ALSA API channel map */ +static int hdmi_manual_channel_allocation(int chs, unsigned char *map) +{ +	int i, spks = 0, spk_mask = 0; + +	for (i = 0; i < chs; i++) { +		int mask = to_spk_mask(map[i]); +		if (mask) { +			spk_mask |= mask; +			spks++; +		} +	} + +	for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { +		if ((chs == channel_allocations[i].channels || +		     spks == channel_allocations[i].channels) && +		    (spk_mask & channel_allocations[i].spk_mask) == +				channel_allocations[i].spk_mask) +			return channel_allocations[i].ca_index; +	} +	return -1; +} + +/* set up the channel slots for the given ALSA API channel map */ +static int hdmi_manual_setup_channel_mapping(struct hda_codec *codec, +					     hda_nid_t pin_nid, +					     int chs, unsigned char *map) +{ +	int i; +	for (i = 0; i < 8; i++) { +		int val, err; +		if (i < chs) +			val = to_cea_slot(map[i]); +		else +			val = 0xf; +		val |= (i << 4); +		err = snd_hda_codec_write(codec, pin_nid, 0, +					  AC_VERB_SET_HDMI_CHAN_SLOT, val); +		if (err) +			return -EINVAL; +	} +	return 0; +} + +/* store ALSA API channel map from the current default map */ +static void hdmi_setup_fake_chmap(unsigned char *map, int ca) +{ +	int i; +	for (i = 0; i < 8; i++) { +		if (i < channel_allocations[ca].channels) +			map[i] = from_cea_slot((hdmi_channel_mapping[ca][i] >> 4) & 0x0f); +		else +			map[i] = 0; +	} +} + +static void hdmi_setup_channel_mapping(struct hda_codec *codec, +				       hda_nid_t pin_nid, bool non_pcm, int ca, +				       int channels, unsigned char *map) +{ +	if (!non_pcm && map) { +		hdmi_manual_setup_channel_mapping(codec, pin_nid, +						  channels, map); +	} else { +		hdmi_std_setup_channel_mapping(codec, pin_nid, non_pcm, ca); +		hdmi_setup_fake_chmap(map, ca); +	} +}  /*   * Audio InfoFrame routines @@ -686,7 +845,8 @@ static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,  }  static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx, -					struct snd_pcm_substream *substream) +				       bool non_pcm, +				       struct snd_pcm_substream *substream)  {  	struct hdmi_spec *spec = codec->spec;  	struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; @@ -700,7 +860,12 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,  	if (!eld->monitor_present)  		return; -	ca = hdmi_channel_allocation(eld, channels); +	if (!non_pcm && per_pin->chmap_set) +		ca = hdmi_manual_channel_allocation(channels, per_pin->chmap); +	else +		ca = hdmi_channel_allocation(eld, channels); +	if (ca < 0) +		ca = 0;  	memset(&ai, 0, sizeof(ai));  	if (eld->conn_type == 0) { /* HDMI */ @@ -737,12 +902,21 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,  			    "pin=%d channels=%d\n",  			    pin_nid,  			    channels); -		hdmi_setup_channel_mapping(codec, pin_nid, ca); +		hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca, +					   channels, per_pin->chmap);  		hdmi_stop_infoframe_trans(codec, pin_nid);  		hdmi_fill_audio_infoframe(codec, pin_nid,  					    ai.bytes, sizeof(ai));  		hdmi_start_infoframe_trans(codec, pin_nid); +	} else { +		/* For non-pcm audio switch, setup new channel mapping +		 * accordingly */ +		if (per_pin->non_pcm != non_pcm) +			hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca, +						   channels, per_pin->chmap);  	} + +	per_pin->non_pcm = non_pcm;  } @@ -1035,6 +1209,7 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)  	per_pin = &spec->pins[pin_idx];  	per_pin->pin_nid = pin_nid; +	per_pin->non_pcm = false;  	err = hdmi_read_pin_conn(codec, pin_idx);  	if (err < 0) @@ -1064,8 +1239,11 @@ static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)  	per_cvt->cvt_nid = cvt_nid;  	per_cvt->channels_min = 2; -	if (chans <= 16) +	if (chans <= 16) {  		per_cvt->channels_max = chans; +		if (chans > spec->channels_max) +			spec->channels_max = chans; +	}  	err = snd_hda_query_supported_pcm(codec, cvt_nid,  					  &per_cvt->rates, @@ -1115,7 +1293,7 @@ static int hdmi_parse_codec(struct hda_codec *codec)  	 * can be lost and presence sense verb will become inaccurate if the  	 * HDA link is powered off at hot plug or hw initialization time.  	 */ -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  	if (!(snd_hda_param_read(codec, codec->afg, AC_PAR_POWER_STATE) &  	      AC_PWRST_EPSS))  		codec->bus->power_keep_link_on = 1; @@ -1133,6 +1311,19 @@ static char *get_hdmi_pcm_name(int idx)  	return &names[idx][0];  } +static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid) +{ +	struct hda_spdif_out *spdif; +	bool non_pcm; + +	mutex_lock(&codec->spdif_mutex); +	spdif = snd_hda_spdif_out_of_nid(codec, cvt_nid); +	non_pcm = !!(spdif->status & IEC958_AES0_NONAUDIO); +	mutex_unlock(&codec->spdif_mutex); +	return non_pcm; +} + +  /*   * HDMI callbacks   */ @@ -1148,10 +1339,13 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,  	int pin_idx = hinfo_to_pin_index(spec, hinfo);  	hda_nid_t pin_nid = spec->pins[pin_idx].pin_nid;  	int pinctl; +	bool non_pcm; + +	non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);  	hdmi_set_channel_count(codec, cvt_nid, substream->runtime->channels); -	hdmi_setup_audio_infoframe(codec, pin_idx, substream); +	hdmi_setup_audio_infoframe(codec, pin_idx, non_pcm, substream);  	pinctl = snd_hda_codec_read(codec, pin_nid, 0,  				    AC_VERB_GET_PIN_WIDGET_CONTROL, 0); @@ -1200,7 +1394,10 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,  				    AC_VERB_SET_PIN_WIDGET_CONTROL,  				    pinctl & ~PIN_OUT);  		snd_hda_spdif_ctls_unassign(codec, pin_idx); +		per_pin->chmap_set = false; +		memset(per_pin->chmap, 0, sizeof(per_pin->chmap));  	} +  	return 0;  } @@ -1211,6 +1408,135 @@ static const struct hda_pcm_ops generic_ops = {  	.cleanup = generic_hdmi_playback_pcm_cleanup,  }; +/* + * ALSA API channel-map control callbacks + */ +static int hdmi_chmap_ctl_info(struct snd_kcontrol *kcontrol, +			       struct snd_ctl_elem_info *uinfo) +{ +	struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); +	struct hda_codec *codec = info->private_data; +	struct hdmi_spec *spec = codec->spec; +	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; +	uinfo->count = spec->channels_max; +	uinfo->value.integer.min = 0; +	uinfo->value.integer.max = SNDRV_CHMAP_LAST; +	return 0; +} + +static int hdmi_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag, +			      unsigned int size, unsigned int __user *tlv) +{ +	struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); +	struct hda_codec *codec = info->private_data; +	struct hdmi_spec *spec = codec->spec; +	const unsigned int valid_mask = +		FL | FR | RL | RR | LFE | FC | RLC | RRC; +	unsigned int __user *dst; +	int chs, count = 0; + +	if (size < 8) +		return -ENOMEM; +	if (put_user(SNDRV_CTL_TLVT_CONTAINER, tlv)) +		return -EFAULT; +	size -= 8; +	dst = tlv + 2; +	for (chs = 2; chs <= spec->channels_max; chs++) { +		int i, c; +		struct cea_channel_speaker_allocation *cap; +		cap = channel_allocations; +		for (i = 0; i < ARRAY_SIZE(channel_allocations); i++, cap++) { +			int chs_bytes = chs * 4; +			if (cap->channels != chs) +				continue; +			if (cap->spk_mask & ~valid_mask) +				continue; +			if (size < 8) +				return -ENOMEM; +			if (put_user(SNDRV_CTL_TLVT_CHMAP_VAR, dst) || +			    put_user(chs_bytes, dst + 1)) +				return -EFAULT; +			dst += 2; +			size -= 8; +			count += 8; +			if (size < chs_bytes) +				return -ENOMEM; +			size -= chs_bytes; +			count += chs_bytes; +			for (c = 7; c >= 0; c--) { +				int spk = cap->speakers[c]; +				if (!spk) +					continue; +				if (put_user(spk_to_chmap(spk), dst)) +					return -EFAULT; +				dst++; +			} +		} +	} +	if (put_user(count, tlv + 1)) +		return -EFAULT; +	return 0; +} + +static int hdmi_chmap_ctl_get(struct snd_kcontrol *kcontrol, +			      struct snd_ctl_elem_value *ucontrol) +{ +	struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); +	struct hda_codec *codec = info->private_data; +	struct hdmi_spec *spec = codec->spec; +	int pin_idx = kcontrol->private_value; +	struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; +	int i; + +	for (i = 0; i < ARRAY_SIZE(per_pin->chmap); i++) +		ucontrol->value.integer.value[i] = per_pin->chmap[i]; +	return 0; +} + +static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol, +			      struct snd_ctl_elem_value *ucontrol) +{ +	struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); +	struct hda_codec *codec = info->private_data; +	struct hdmi_spec *spec = codec->spec; +	int pin_idx = kcontrol->private_value; +	struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; +	unsigned int ctl_idx; +	struct snd_pcm_substream *substream; +	unsigned char chmap[8]; +	int i, ca, prepared = 0; + +	ctl_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); +	substream = snd_pcm_chmap_substream(info, ctl_idx); +	if (!substream || !substream->runtime) +		return -EBADFD; +	switch (substream->runtime->status->state) { +	case SNDRV_PCM_STATE_OPEN: +	case SNDRV_PCM_STATE_SETUP: +		break; +	case SNDRV_PCM_STATE_PREPARED: +		prepared = 1; +		break; +	default: +		return -EBUSY; +	} +	memset(chmap, 0, sizeof(chmap)); +	for (i = 0; i < ARRAY_SIZE(chmap); i++) +		chmap[i] = ucontrol->value.integer.value[i]; +	if (!memcmp(chmap, per_pin->chmap, sizeof(chmap))) +		return 0; +	ca = hdmi_manual_channel_allocation(ARRAY_SIZE(chmap), chmap); +	if (ca < 0) +		return -EINVAL; +	per_pin->chmap_set = true; +	memcpy(per_pin->chmap, chmap, sizeof(chmap)); +	if (prepared) +		hdmi_setup_audio_infoframe(codec, pin_idx, per_pin->non_pcm, +					   substream); + +	return 0; +} +  static int generic_hdmi_build_pcms(struct hda_codec *codec)  {  	struct hdmi_spec *spec = codec->spec; @@ -1223,6 +1549,7 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)  		info = &spec->pcm_rec[pin_idx];  		info->name = get_hdmi_pcm_name(pin_idx);  		info->pcm_type = HDA_PCM_TYPE_HDMI; +		info->own_chmap = true;  		pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];  		pstr->substreams = 1; @@ -1280,6 +1607,27 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)  		hdmi_present_sense(per_pin, 0);  	} +	/* add channel maps */ +	for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { +		struct snd_pcm_chmap *chmap; +		struct snd_kcontrol *kctl; +		int i; +		err = snd_pcm_add_chmap_ctls(codec->pcm_info[pin_idx].pcm, +					     SNDRV_PCM_STREAM_PLAYBACK, +					     NULL, 0, pin_idx, &chmap); +		if (err < 0) +			return err; +		/* override handlers */ +		chmap->private_data = codec; +		kctl = chmap->kctl; +		for (i = 0; i < kctl->count; i++) +			kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_WRITE; +		kctl->info = hdmi_chmap_ctl_info; +		kctl->get = hdmi_chmap_ctl_get; +		kctl->put = hdmi_chmap_ctl_put; +		kctl->tlv.c = hdmi_chmap_ctl_tlv; +	} +  	return 0;  } @@ -1311,7 +1659,6 @@ static int generic_hdmi_init(struct hda_codec *codec)  		hdmi_init_pin(codec, pin_nid);  		snd_hda_jack_detect_enable(codec, pin_nid, pin_nid);  	} -	snd_hda_jack_report_sync(codec);  	return 0;  } @@ -1428,7 +1775,6 @@ static int simple_playback_init(struct hda_codec *codec)  		snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE,  				    AMP_OUT_UNMUTE);  	snd_hda_jack_detect_enable(codec, pin, pin); -	snd_hda_jack_report_sync(codec);  	return 0;  } @@ -1809,6 +2155,43 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec)  	return 0;  } +static int nvhdmi_7x_8ch_build_pcms(struct hda_codec *codec) +{ +	struct hdmi_spec *spec = codec->spec; +	int err = simple_playback_build_pcms(codec); +	spec->pcm_rec[0].own_chmap = true; +	return err; +} + +static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec) +{ +	struct hdmi_spec *spec = codec->spec; +	struct snd_pcm_chmap *chmap; +	int err; + +	err = simple_playback_build_controls(codec); +	if (err < 0) +		return err; + +	/* add channel maps */ +	err = snd_pcm_add_chmap_ctls(spec->pcm_rec[0].pcm, +				     SNDRV_PCM_STREAM_PLAYBACK, +				     snd_pcm_alt_chmaps, 8, 0, &chmap); +	if (err < 0) +		return err; +	switch (codec->preset->id) { +	case 0x10de0002: +	case 0x10de0003: +	case 0x10de0005: +	case 0x10de0006: +		chmap->channel_mask = (1U << 2) | (1U << 8); +		break; +	case 0x10de0007: +		chmap->channel_mask = (1U << 2) | (1U << 6) | (1U << 8); +	} +	return 0; +} +  static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)  {  	struct hdmi_spec *spec; @@ -1819,6 +2202,8 @@ static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)  	spec->multiout.max_channels = 8;  	spec->pcm_playback = nvhdmi_pcm_playback_8ch_7x;  	codec->patch_ops.init = nvhdmi_7x_init_8ch; +	codec->patch_ops.build_pcms = nvhdmi_7x_8ch_build_pcms; +	codec->patch_ops.build_controls = nvhdmi_7x_8ch_build_controls;  	/* Initialize the audio infoframe channel mask and checksum to something  	 * valid */ diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4f81dd44c83..8568aee56e2 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -174,7 +174,7 @@ struct alc_spec {  	/* hooks */  	void (*init_hook)(struct hda_codec *codec); -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  	void (*power_hook)(struct hda_codec *codec);  #endif  	void (*shutup)(struct hda_codec *codec); @@ -215,7 +215,7 @@ struct alc_spec {  	/* for virtual master */  	hda_nid_t vmaster_nid;  	struct hda_vmaster_mute_hook vmaster_mute; -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  	struct hda_loopback_check loopback;  	int num_loopbacks;  	struct hda_amp_list loopback_list[8]; @@ -594,7 +594,7 @@ static void call_update_outputs(struct hda_codec *codec)  }  /* standard HP-automute helper */ -static void alc_hp_automute(struct hda_codec *codec) +static void alc_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)  {  	struct alc_spec *spec = codec->spec; @@ -607,7 +607,7 @@ static void alc_hp_automute(struct hda_codec *codec)  }  /* standard line-out-automute helper */ -static void alc_line_automute(struct hda_codec *codec) +static void alc_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)  {  	struct alc_spec *spec = codec->spec; @@ -627,7 +627,7 @@ static void alc_line_automute(struct hda_codec *codec)  	snd_hda_get_conn_index(codec, mux, nid, 0)  /* standard mic auto-switch helper */ -static void alc_mic_automute(struct hda_codec *codec) +static void alc_mic_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)  {  	struct alc_spec *spec = codec->spec;  	hda_nid_t *pins = spec->imux_pins; @@ -648,25 +648,8 @@ static void alc_mic_automute(struct hda_codec *codec)  		alc_mux_select(codec, 0, spec->int_mic_idx, false);  } -/* handle the specified unsol action (ALC_XXX_EVENT) */ -static void alc_exec_unsol_event(struct hda_codec *codec, int action) -{ -	switch (action) { -	case ALC_HP_EVENT: -		alc_hp_automute(codec); -		break; -	case ALC_FRONT_EVENT: -		alc_line_automute(codec); -		break; -	case ALC_MIC_EVENT: -		alc_mic_automute(codec); -		break; -	} -	snd_hda_jack_report_sync(codec); -} -  /* update the master volume per volume-knob's unsol event */ -static void alc_update_knob_master(struct hda_codec *codec, hda_nid_t nid) +static void alc_update_knob_master(struct hda_codec *codec, struct hda_jack_tbl *jack)  {  	unsigned int val;  	struct snd_kcontrol *kctl; @@ -678,7 +661,7 @@ static void alc_update_knob_master(struct hda_codec *codec, hda_nid_t nid)  	uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);  	if (!uctl)  		return; -	val = snd_hda_codec_read(codec, nid, 0, +	val = snd_hda_codec_read(codec, jack->nid, 0,  				 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);  	val &= HDA_AMP_VOLMASK;  	uctl->value.integer.value[0] = val; @@ -687,37 +670,19 @@ static void alc_update_knob_master(struct hda_codec *codec, hda_nid_t nid)  	kfree(uctl);  } -/* unsolicited event for HP jack sensing */ -static void alc_unsol_event(struct hda_codec *codec, unsigned int res) +static void alc880_unsol_event(struct hda_codec *codec, unsigned int res)  { -	int action; - -	if (codec->vendor_id == 0x10ec0880) -		res >>= 28; -	else -		res >>= 26; -	action = snd_hda_jack_get_action(codec, res); -	if (action == ALC_DCVOL_EVENT) { -		/* Execute the dc-vol event here as it requires the NID -		 * but we don't pass NID to alc_exec_unsol_event(). -		 * Once when we convert all static quirks to the auto-parser, -		 * this can be integerated into there. -		 */ -		struct hda_jack_tbl *jack; -		jack = snd_hda_jack_tbl_get_from_tag(codec, res); -		if (jack) -			alc_update_knob_master(codec, jack->nid); -		return; -	} -	alc_exec_unsol_event(codec, action); +	/* For some reason, the res given from ALC880 is broken. +	   Here we adjust it properly. */ +	snd_hda_jack_unsol_event(codec, res >> 2);  }  /* call init functions of standard auto-mute helpers */  static void alc_inithook(struct hda_codec *codec)  { -	alc_hp_automute(codec); -	alc_line_automute(codec); -	alc_mic_automute(codec); +	alc_hp_automute(codec, NULL); +	alc_line_automute(codec, NULL); +	alc_mic_automute(codec, NULL);  }  /* additional initialization for ALC888 variants */ @@ -999,7 +964,8 @@ static void alc_init_automute(struct hda_codec *codec)  			continue;  		snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",  			    nid); -		snd_hda_jack_detect_enable(codec, nid, ALC_HP_EVENT); +		snd_hda_jack_detect_enable_callback(codec, nid, ALC_HP_EVENT, +						    alc_hp_automute);  		spec->detect_hp = 1;  	} @@ -1011,10 +977,10 @@ static void alc_init_automute(struct hda_codec *codec)  					continue;  				snd_printdd("realtek: Enable Line-Out "  					    "auto-muting on NID 0x%x\n", nid); -				snd_hda_jack_detect_enable(codec, nid, -							   ALC_FRONT_EVENT); +				snd_hda_jack_detect_enable_callback(codec, nid, ALC_FRONT_EVENT, +								    alc_line_automute);  				spec->detect_lo = 1; -		} +			}  		spec->automute_lo_possible = spec->detect_hp;  	} @@ -1110,10 +1076,12 @@ static bool alc_auto_mic_check_imux(struct hda_codec *codec)  		return false; /* no corresponding imux */  	} -	snd_hda_jack_detect_enable(codec, spec->ext_mic_pin, ALC_MIC_EVENT); +	snd_hda_jack_detect_enable_callback(codec, spec->ext_mic_pin, +					    ALC_MIC_EVENT, alc_mic_automute);  	if (spec->dock_mic_pin) -		snd_hda_jack_detect_enable(codec, spec->dock_mic_pin, -					   ALC_MIC_EVENT); +		snd_hda_jack_detect_enable_callback(codec, spec->dock_mic_pin, +						    ALC_MIC_EVENT, +						    alc_mic_automute);  	spec->auto_mic_valid_imux = 1;  	spec->auto_mic = 1; @@ -2053,13 +2021,11 @@ static int alc_init(struct hda_codec *codec)  	alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT); -	snd_hda_jack_report_sync(codec); -  	hda_call_check_power_status(codec, 0x01);  	return 0;  } -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)  {  	struct alc_spec *spec = codec->spec; @@ -2289,6 +2255,8 @@ static int alc_build_pcms(struct hda_codec *codec)  			p = &alc_pcm_analog_playback;  		info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;  		info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; +		info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = +			spec->multiout.max_channels;  	}  	if (spec->adc_nids) {  		p = spec->stream_analog_capture; @@ -2437,7 +2405,7 @@ static void alc_free(struct hda_codec *codec)  	snd_hda_detach_beep_device(codec);  } -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  static void alc_power_eapd(struct hda_codec *codec)  {  	alc_auto_setup_eapd(codec, false); @@ -2473,17 +2441,18 @@ static const struct hda_codec_ops alc_patch_ops = {  	.build_pcms = alc_build_pcms,  	.init = alc_init,  	.free = alc_free, -	.unsol_event = alc_unsol_event, +	.unsol_event = snd_hda_jack_unsol_event,  #ifdef CONFIG_PM  	.resume = alc_resume,  #endif -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  	.suspend = alc_suspend,  	.check_power_status = alc_check_power_status,  #endif  	.reboot_notify = alc_shutup,  }; +  /* replace the codec chip_name with the given string */  static int alc_codec_rename(struct hda_codec *codec, const char *name)  { @@ -2633,7 +2602,7 @@ static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch,  	return channel_name[ch];  } -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  /* add the powersave loopback-list entry */  static void add_loopback_list(struct alc_spec *spec, hda_nid_t mix, int idx)  { @@ -4447,7 +4416,7 @@ static void alc880_fixup_vol_knob(struct hda_codec *codec,  				  const struct alc_fixup *fix, int action)  {  	if (action == ALC_FIXUP_ACT_PROBE) -		snd_hda_jack_detect_enable(codec, 0x21, ALC_DCVOL_EVENT); +		snd_hda_jack_detect_enable_callback(codec, 0x21, ALC_DCVOL_EVENT, alc_update_knob_master);  }  static const struct alc_fixup alc880_fixups[] = { @@ -4812,6 +4781,8 @@ static int patch_alc880(struct hda_codec *codec)  	}  	codec->patch_ops = alc_patch_ops; +	codec->patch_ops.unsol_event = alc880_unsol_event; +  	alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); @@ -4866,7 +4837,8 @@ static void alc260_fixup_gpio1_toggle(struct hda_codec *codec,  		spec->detect_hp = 1;  		spec->automute_speaker = 1;  		spec->autocfg.hp_pins[0] = 0x0f; /* copy it for automute */ -		snd_hda_jack_detect_enable(codec, 0x0f, ALC_HP_EVENT); +		snd_hda_jack_detect_enable_callback(codec, 0x0f, ALC_HP_EVENT, +						    alc_hp_automute);  		snd_hda_gen_add_verbs(&spec->gen, alc_gpio1_init_verbs);  	}  } @@ -6189,6 +6161,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {  	SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC),  	SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_MIC2_MUTE_LED),  	SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_DMIC), +	SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_DMIC),  	SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),  	SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC),  	SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC), @@ -6334,6 +6307,12 @@ static int patch_alc269(struct hda_codec *codec)  	spec = codec->spec; +	alc_pick_fixup(codec, alc269_fixup_models, +		       alc269_fixup_tbl, alc269_fixups); +	alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + +	alc_auto_parse_customize_define(codec); +  	if (codec->vendor_id == 0x10ec0269) {  		spec->codec_variant = ALC269_TYPE_ALC269VA;  		switch (alc_get_coef0(codec) & 0x00f0) { @@ -6361,12 +6340,6 @@ static int patch_alc269(struct hda_codec *codec)  		alc269_fill_coef(codec);  	} -	alc_pick_fixup(codec, alc269_fixup_models, -		       alc269_fixup_tbl, alc269_fixups); -	alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); - -	alc_auto_parse_customize_define(codec); -  	/* automatic parse from the BIOS config */  	err = alc269_parse_auto_config(codec);  	if (err < 0) @@ -6503,7 +6476,7 @@ static int patch_alc861(struct hda_codec *codec)  	}  	codec->patch_ops = alc_patch_ops; -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  	spec->power_hook = alc_power_eapd;  #endif @@ -7068,6 +7041,8 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = {  	{ .id = 0x10ec0276, .name = "ALC276", .patch = patch_alc269 },  	{ .id = 0x10ec0280, .name = "ALC280", .patch = patch_alc269 },  	{ .id = 0x10ec0282, .name = "ALC282", .patch = patch_alc269 }, +	{ .id = 0x10ec0283, .name = "ALC283", .patch = patch_alc269 }, +	{ .id = 0x10ec0290, .name = "ALC290", .patch = patch_alc269 },  	{ .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",  	  .patch = patch_alc861 },  	{ .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd }, diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 3d4722f0a1c..fe163547f90 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -103,6 +103,7 @@ enum {  	STAC_HP_ZEPHYR,  	STAC_92HD83XXX_HP_LED,  	STAC_92HD83XXX_HP_INV_LED, +	STAC_92HD83XXX_HP_MIC_LED,  	STAC_92HD83XXX_MODELS  }; @@ -215,6 +216,9 @@ struct sigmatel_spec {  	unsigned int vref_mute_led_nid; /* pin NID for mute-LED vref control */  	unsigned int vref_led; +	unsigned int mic_mute_led_gpio; /* capture mute LED GPIO */ +	bool mic_mute_led_on; /* current mic mute state */ +  	/* stream */  	unsigned int stream_delay; @@ -1679,6 +1683,7 @@ static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {  	[STAC_HP_ZEPHYR] = "hp-zephyr",  	[STAC_92HD83XXX_HP_LED] = "hp-led",  	[STAC_92HD83XXX_HP_INV_LED] = "hp-inv-led", +	[STAC_92HD83XXX_HP_MIC_LED] = "hp-mic-led",  };  static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { @@ -1703,6 +1708,8 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {  			  "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),  	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165B,  			  "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), +	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18df, +			  "HP Folio", STAC_92HD83XXX_HP_MIC_LED),  	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3388,  			  "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),  	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3389, @@ -2791,18 +2798,27 @@ stac_control_new(struct sigmatel_spec *spec,  	return knew;  } -static int stac92xx_add_control_temp(struct sigmatel_spec *spec, -				     const struct snd_kcontrol_new *ktemp, -				     int idx, const char *name, -				     unsigned long val) +static struct snd_kcontrol_new * +add_control_temp(struct sigmatel_spec *spec, +		 const struct snd_kcontrol_new *ktemp, +		 int idx, const char *name, +		 unsigned long val)  {  	struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name,  							 HDA_SUBDEV_AMP_FLAG);  	if (!knew) -		return -ENOMEM; +		return NULL;  	knew->index = idx;  	knew->private_value = val; -	return 0; +	return knew; +} + +static int stac92xx_add_control_temp(struct sigmatel_spec *spec, +				     const struct snd_kcontrol_new *ktemp, +				     int idx, const char *name, +				     unsigned long val) +{ +	return add_control_temp(spec, ktemp, idx, name, val) ? 0 : -ENOMEM;  }  static inline int stac92xx_add_control_idx(struct sigmatel_spec *spec, @@ -3226,9 +3242,12 @@ static int create_multi_out_ctls(struct hda_codec *codec, int num_outs,  				idx = i;  				break;  			case AUTO_PIN_SPEAKER_OUT: -				name = "Speaker"; -				idx = i; -				break; +				if (num_outs <= 1) { +					name = "Speaker"; +					idx = i; +					break; +				} +				/* Fall through in case of multi speaker outs */  			default:  				name = chname[i];  				idx = 0; @@ -3242,18 +3261,56 @@ static int create_multi_out_ctls(struct hda_codec *codec, int num_outs,  	return 0;  } +static void stac_gpio_set(struct hda_codec *codec, unsigned int mask, +			  unsigned int dir_mask, unsigned int data); + +/* hook for controlling mic-mute LED GPIO */ +static int stac92xx_capture_sw_put_led(struct snd_kcontrol *kcontrol, +				       struct snd_ctl_elem_value *ucontrol) +{ +	struct hda_codec *codec = snd_kcontrol_chip(kcontrol); +	struct sigmatel_spec *spec = codec->spec; +	int err; +	bool mute; + +	err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); +	if (err <= 0) +		return err; +	mute = !(ucontrol->value.integer.value[0] && +		 ucontrol->value.integer.value[1]); +	if (spec->mic_mute_led_on != mute) { +		spec->mic_mute_led_on = mute; +		if (mute) +			spec->gpio_data |= spec->mic_mute_led_gpio; +		else +			spec->gpio_data &= ~spec->mic_mute_led_gpio; +		stac_gpio_set(codec, spec->gpio_mask, +			      spec->gpio_dir, spec->gpio_data); +	} +	return err; +} +  static int stac92xx_add_capvol_ctls(struct hda_codec *codec, unsigned long vol,  				    unsigned long sw, int idx)  { +	struct sigmatel_spec *spec = codec->spec; +	struct snd_kcontrol_new *knew;  	int err; +  	err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx,  				       "Capture Volume", vol);  	if (err < 0)  		return err; -	err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_MUTE, idx, -				       "Capture Switch", sw); -	if (err < 0) -		return err; + +	knew = add_control_temp(spec, +				&stac92xx_control_templates[STAC_CTL_WIDGET_MUTE], +				idx, "Capture Switch", sw); +	if (!knew) +		return -ENOMEM; +	/* add a LED hook for some HP laptops */ +	if (spec->mic_mute_led_gpio) +		knew->put = stac92xx_capture_sw_put_led; +  	return 0;  } @@ -4155,6 +4212,9 @@ static int stac_add_event(struct hda_codec *codec, hda_nid_t nid,  	return 0;  } +static void handle_unsol_event(struct hda_codec *codec, +			       struct hda_jack_tbl *event); +  /* check if given nid is a valid pin and no other events are assigned   * to it.  If OK, assign the event, set the unsol flag, and returns 1.   * Otherwise, returns zero. @@ -4172,6 +4232,7 @@ static int enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,  	if (event->action && event->action != type)  		return 0;  	event->action = type; +	event->callback = handle_unsol_event;  	snd_hda_jack_detect_enable(codec, nid, 0);  	return 1;  } @@ -4418,8 +4479,6 @@ static int stac92xx_init(struct hda_codec *codec)  		stac_toggle_power_map(codec, nid, 0);  	} -	snd_hda_jack_report_sync(codec); -  	/* sync mute LED */  	if (spec->gpio_led) {  		if (spec->vmaster_mute.hook) @@ -4812,20 +4871,6 @@ static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid)  	handle_unsol_event(codec, event);  } -static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) -{ -	struct hda_jack_tbl *event; -	int tag; - -	tag = (res >> 26) & 0x7f; -	event = snd_hda_jack_tbl_get_from_tag(codec, tag); -	if (!event) -		return; -	event->jack_dirty = 1; -	handle_unsol_event(codec, event); -	snd_hda_jack_report_sync(codec); -} -  static int hp_blike_system(u32 subsystem_id);  static void set_hp_led_gpio(struct hda_codec *codec) @@ -5076,7 +5121,7 @@ static const struct hda_codec_ops stac92xx_patch_ops = {  	.build_pcms = stac92xx_build_pcms,  	.init = stac92xx_init,  	.free = stac92xx_free, -	.unsol_event = stac92xx_unsol_event, +	.unsol_event = snd_hda_jack_unsol_event,  #ifdef CONFIG_PM  	.suspend = stac92xx_suspend,  	.resume = stac92xx_resume, @@ -5578,6 +5623,9 @@ again:  	case STAC_92HD83XXX_HP_INV_LED:  		default_polarity = 1;  		break; +	case STAC_92HD83XXX_HP_MIC_LED: +		spec->mic_mute_led_gpio = 0x08; /* GPIO3 */ +		break;  	}  	if (find_mute_led_cfg(codec, default_polarity)) @@ -5596,6 +5644,13 @@ again:  		}  	} +	if (spec->mic_mute_led_gpio) { +		spec->gpio_mask |= spec->mic_mute_led_gpio; +		spec->gpio_dir |= spec->mic_mute_led_gpio; +		spec->mic_mute_led_on = true; +		spec->gpio_data |= spec->mic_mute_led_gpio; +	} +  	err = stac92xx_parse_auto_config(codec);  	if (!err) {  		if (spec->board_config < 0) { diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 43077177691..5a45a912aed 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -1672,7 +1672,8 @@ static void via_hp_automute(struct hda_codec *codec)  	struct via_spec *spec = codec->spec;  	if (!spec->hp_independent_mode && spec->autocfg.hp_pins[0] && -	    (spec->codec_type != VT1708 || spec->vt1708_jack_detect)) +	    (spec->codec_type != VT1708 || spec->vt1708_jack_detect) && +	    is_jack_detectable(codec, spec->autocfg.hp_pins[0]))  		present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]);  	if (spec->smart51_enabled) @@ -1764,7 +1765,7 @@ static int via_suspend(struct hda_codec *codec)  }  #endif -#ifdef CONFIG_SND_HDA_POWER_SAVE +#ifdef CONFIG_PM  static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)  {  	struct via_spec *spec = codec->spec; @@ -1785,8 +1786,6 @@ static const struct hda_codec_ops via_patch_ops = {  	.unsol_event = via_unsol_event,  #ifdef CONFIG_PM  	.suspend = via_suspend, -#endif -#ifdef CONFIG_SND_HDA_POWER_SAVE  	.check_power_status = via_check_power_status,  #endif  }; @@ -2815,7 +2814,6 @@ static int via_init(struct hda_codec *codec)  	via_hp_automute(codec);  	vt1708_update_hp_work(spec); -	snd_hda_jack_report_sync(codec);  	return 0;  } @@ -3669,6 +3667,32 @@ static void set_widgets_power_state_vt2002P(struct hda_codec *codec)  		update_power_state(codec, 0x21, AC_PWRST_D3);  } +/* + * pin fix-up + */ +enum { +	VIA_FIXUP_INTMIC_BOOST, +}; + +static void via_fixup_intmic_boost(struct hda_codec *codec, +				  const struct hda_fixup *fix, int action) +{ +	if (action == HDA_FIXUP_ACT_PRE_PROBE) +		override_mic_boost(codec, 0x30, 0, 2, 40); +} + +static const struct hda_fixup via_fixups[] = { +	[VIA_FIXUP_INTMIC_BOOST] = { +		.type = HDA_FIXUP_FUNC, +		.v.func = via_fixup_intmic_boost, +	}, +}; + +static const struct snd_pci_quirk vt2002p_fixups[] = { +	SND_PCI_QUIRK(0x1043, 0x8532, "Asus X202E", VIA_FIXUP_INTMIC_BOOST), +	{} +}; +  /* patch for vt2002P */  static int patch_vt2002P(struct hda_codec *codec)  { @@ -3685,6 +3709,9 @@ static int patch_vt2002P(struct hda_codec *codec)  	override_mic_boost(codec, 0x29, 0, 3, 40);  	add_secret_dac_path(codec); +	snd_hda_pick_fixup(codec, NULL, vt2002p_fixups, via_fixups); +	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); +  	/* automatic parse from the BIOS config */  	err = via_parse_auto_config(codec);  	if (err < 0) { diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c index 3e4f8c12ffc..20bcddea2ea 100644 --- a/sound/pci/ice1712/aureon.c +++ b/sound/pci/ice1712/aureon.c @@ -2103,7 +2103,7 @@ static int aureon_reset(struct snd_ice1712 *ice)  /*   * suspend/resume   */ -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int aureon_resume(struct snd_ice1712 *ice)  {  	struct aureon_spec *spec = ice->spec; @@ -2160,7 +2160,7 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)  		wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);  	} -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	ice->pm_resume = aureon_resume;  	ice->pm_suspend_enabled = 1;  #endif diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index 0da778a69ef..d0e7d87f09f 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h @@ -384,7 +384,7 @@ struct snd_ice1712 {  	char **ext_clock_names;  	int ext_clock_count;  	void (*pro_open)(struct snd_ice1712 *, struct snd_pcm_substream *); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	int (*pm_suspend)(struct snd_ice1712 *);  	int (*pm_resume)(struct snd_ice1712 *);  	unsigned int pm_suspend_enabled:1; diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index bed9f34f4ef..3050a527925 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -2792,7 +2792,7 @@ static void __devexit snd_vt1724_remove(struct pci_dev *pci)  	pci_set_drvdata(pci, NULL);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int snd_vt1724_suspend(struct device *dev)  {  	struct pci_dev *pci = to_pci_dev(dev); @@ -2878,7 +2878,7 @@ static SIMPLE_DEV_PM_OPS(snd_vt1724_pm, snd_vt1724_suspend, snd_vt1724_resume);  #define SND_VT1724_PM_OPS	&snd_vt1724_pm  #else  #define SND_VT1724_PM_OPS	NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  static struct pci_driver vt1724_driver = {  	.name = KBUILD_MODNAME, diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c index 98bc3b7681b..14fd536b645 100644 --- a/sound/pci/ice1712/juli.c +++ b/sound/pci/ice1712/juli.c @@ -486,7 +486,7 @@ static int __devinit juli_add_controls(struct snd_ice1712 *ice)   * suspend/resume   * */ -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int juli_resume(struct snd_ice1712 *ice)  {  	struct snd_akm4xxx *ak = ice->akm; @@ -652,7 +652,7 @@ static int __devinit juli_init(struct snd_ice1712 *ice)  	ice->spdif.ops.open = juli_spdif_in_open; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	ice->pm_resume = juli_resume;  	ice->pm_suspend = juli_suspend;  	ice->pm_suspend_enabled = 1; diff --git a/sound/pci/ice1712/prodigy_hifi.c b/sound/pci/ice1712/prodigy_hifi.c index 075d5aa1fee..7bf093c51ce 100644 --- a/sound/pci/ice1712/prodigy_hifi.c +++ b/sound/pci/ice1712/prodigy_hifi.c @@ -1100,7 +1100,7 @@ static void ak4396_init(struct snd_ice1712 *ice)  		ak4396_write(ice, ak4396_inits[i], ak4396_inits[i+1]);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int prodigy_hd2_resume(struct snd_ice1712 *ice)  {  	/* initialize ak4396 codec and restore previous mixer volumes */ @@ -1141,7 +1141,7 @@ static int __devinit prodigy_hd2_init(struct snd_ice1712 *ice)  		return -ENOMEM;  	ice->spec = spec; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	ice->pm_resume = &prodigy_hd2_resume;  	ice->pm_suspend_enabled = 1;  #endif diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index cd553f592e2..ea4b706c8d6 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -1541,6 +1541,26 @@ static int __devinit snd_intel8x0_pcm1(struct intel8x0 *chip, int device,  					      snd_dma_pci_data(chip->pci),  					      rec->prealloc_size, rec->prealloc_max_size); +	if (rec->ac97_idx == ICHD_PCMOUT && rec->playback_ops) { +		struct snd_pcm_chmap *chmap; +		int chs = 2; +		if (rec->ac97_idx == ICHD_PCMOUT) { +			if (chip->multi8) +				chs = 8; +			else if (chip->multi6) +				chs = 6; +			else if (chip->multi4) +				chs = 4; +		} +		err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, +					     snd_pcm_alt_chmaps, chs, 0, +					     &chmap); +		if (err < 0) +			return err; +		chmap->channel_mask = SND_PCM_CHMAP_MASK_2468; +		chip->ac97[0]->chmaps[SNDRV_PCM_STREAM_PLAYBACK] = chmap; +	} +  	return 0;  } @@ -2206,7 +2226,7 @@ static int __devinit snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock,  		case DEVICE_INTEL_ICH4:  			chip->spdif_idx = ICHD_SPBAR;  			break; -		}; +		}  	}  	chip->in_ac97_init = 1; @@ -2620,7 +2640,7 @@ static int snd_intel8x0_free(struct intel8x0 *chip)  	return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  /*   * power management   */ @@ -2741,7 +2761,7 @@ static SIMPLE_DEV_PM_OPS(intel8x0_pm, intel8x0_suspend, intel8x0_resume);  #define INTEL8X0_PM_OPS	&intel8x0_pm  #else  #define INTEL8X0_PM_OPS	NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  #define INTEL8X0_TESTBUF_SIZE	32768	/* enough large for one shot */ diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index da44bb3f8e7..4d551736531 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -1008,7 +1008,7 @@ static int snd_intel8x0m_free(struct intel8x0m *chip)  	return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  /*   * power management   */ @@ -1067,7 +1067,7 @@ static SIMPLE_DEV_PM_OPS(intel8x0m_pm, intel8x0m_suspend, intel8x0m_resume);  #define INTEL8X0M_PM_OPS	&intel8x0m_pm  #else  #define INTEL8X0M_PM_OPS	NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  #ifdef CONFIG_PROC_FS  static void snd_intel8x0m_proc_read(struct snd_info_entry * entry, diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index e69ce5f9c31..8a67ce95f24 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -196,8 +196,8 @@ enum MonitorModeSelector {  #define K1212_ADAT_BUF_SIZE	(K1212_ADAT_CHANNELS * 2 * kPlayBufferFrames * kNumBuffers)  #define K1212_MAX_BUF_SIZE	(K1212_ANALOG_BUF_SIZE + K1212_ADAT_BUF_SIZE) -#define k1212MinADCSens     0x7f -#define k1212MaxADCSens     0x00 +#define k1212MinADCSens     0x00 +#define k1212MaxADCSens     0x7f  #define k1212MaxVolume      0x7fff  #define k1212MaxWaveVolume  0xffff  #define k1212MinVolume      0x0000 diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index c85d1ffcc95..eb3cd3a4315 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -789,7 +789,7 @@ struct snd_m3 {  	unsigned int in_suspend; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	u16 *suspend_mem;  #endif @@ -2368,7 +2368,7 @@ static int snd_m3_free(struct snd_m3 *chip)  		outw(0, chip->iobase + HOST_INT_CTRL); /* disable ints */  	} -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	vfree(chip->suspend_mem);  #endif @@ -2390,7 +2390,7 @@ static int snd_m3_free(struct snd_m3 *chip)  /*   * APM support   */ -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int m3_suspend(struct device *dev)  {  	struct pci_dev *pci = to_pci_dev(dev); @@ -2485,7 +2485,7 @@ static SIMPLE_DEV_PM_OPS(m3_pm, m3_suspend, m3_resume);  #define M3_PM_OPS	&m3_pm  #else  #define M3_PM_OPS	NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  #ifdef CONFIG_SND_MAESTRO3_INPUT  static int __devinit snd_m3_input_register(struct snd_m3 *chip) @@ -2656,7 +2656,7 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,  	}  	chip->irq = pci->irq; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	chip->suspend_mem = vmalloc(sizeof(u16) * (REV_B_CODE_MEMORY_LENGTH + REV_B_DATA_MEMORY_LENGTH));  	if (chip->suspend_mem == NULL)  		snd_printk(KERN_WARNING "can't allocate apm buffer\n"); diff --git a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c index bfbdc91e4cb..e0f4d87555a 100644 --- a/sound/pci/mixart/mixart_hwdep.c +++ b/sound/pci/mixart/mixart_hwdep.c @@ -538,7 +538,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw  		if ((err = snd_card_register(chip->card)) < 0)  			return err; -	}; +	}  	snd_printdd("miXart firmware downloaded and successfully set up\n"); diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 465cff25b14..e80e9a1e84a 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -1377,7 +1377,7 @@ snd_nm256_peek_for_sig(struct nm256 *chip)  	return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  /*   * APM event handler, so the card is properly reinitialized after a power   * event. @@ -1441,7 +1441,7 @@ static SIMPLE_DEV_PM_OPS(nm256_pm, nm256_suspend, nm256_resume);  #define NM256_PM_OPS	&nm256_pm  #else  #define NM256_PM_OPS	NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  static int snd_nm256_free(struct nm256 *chip)  { diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 37520a2b4dc..2becae155a4 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -872,7 +872,7 @@ static struct pci_driver oxygen_driver = {  	.id_table = oxygen_ids,  	.probe = generic_oxygen_probe,  	.remove = __devexit_p(oxygen_pci_remove), -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.driver = {  		.pm = &oxygen_pci_pm,  	}, diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index 7112a89fb8b..09a24b24958 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h @@ -161,7 +161,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,  				     )  		    );  void oxygen_pci_remove(struct pci_dev *pci); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  extern const struct dev_pm_ops oxygen_pci_pm;  #endif  void oxygen_pci_shutdown(struct pci_dev *pci); diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index e9fa2d07951..9562dc63ba6 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -726,7 +726,7 @@ void oxygen_pci_remove(struct pci_dev *pci)  }  EXPORT_SYMBOL(oxygen_pci_remove); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int oxygen_pci_suspend(struct device *dev)  {  	struct pci_dev *pci = to_pci_dev(dev); @@ -824,7 +824,7 @@ static int oxygen_pci_resume(struct device *dev)  SIMPLE_DEV_PM_OPS(oxygen_pci_pm, oxygen_pci_suspend, oxygen_pci_resume);  EXPORT_SYMBOL(oxygen_pci_pm); -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  void oxygen_pci_shutdown(struct pci_dev *pci)  { diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index d3b606b69f3..3d71423b23b 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c @@ -93,7 +93,7 @@ static struct pci_driver xonar_driver = {  	.id_table = xonar_ids,  	.probe = xonar_probe,  	.remove = __devexit_p(oxygen_pci_remove), -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.driver = {  		.pm = &oxygen_pci_pm,  	}, diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index e3ac1f768ff..be4f1456009 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c @@ -91,6 +91,14 @@ enum {  	PCI_ID_PCX924E,  	PCI_ID_PCX924HRMIC,  	PCI_ID_PCX924E_MIC, +	PCI_ID_VX442HR, +	PCI_ID_PCX442HR, +	PCI_ID_VX442E, +	PCI_ID_PCX442E, +	PCI_ID_VX822HR, +	PCI_ID_PCX822HR, +	PCI_ID_VX822E, +	PCI_ID_PCX822E,  	PCI_ID_LAST  }; @@ -121,6 +129,14 @@ static DEFINE_PCI_DEVICE_TABLE(pcxhr_ids) = {  	{ 0x10b5, 0x9056, 0x1369, 0xbb21, 0, 0, PCI_ID_PCX924E, },  	{ 0x10b5, 0x9056, 0x1369, 0xbf01, 0, 0, PCI_ID_PCX924HRMIC, },  	{ 0x10b5, 0x9056, 0x1369, 0xbf21, 0, 0, PCI_ID_PCX924E_MIC, }, +	{ 0x10b5, 0x9656, 0x1369, 0xd001, 0, 0, PCI_ID_VX442HR, }, +	{ 0x10b5, 0x9656, 0x1369, 0xd101, 0, 0, PCI_ID_PCX442HR, }, +	{ 0x10b5, 0x9056, 0x1369, 0xd021, 0, 0, PCI_ID_VX442E, }, +	{ 0x10b5, 0x9056, 0x1369, 0xd121, 0, 0, PCI_ID_PCX442E, }, +	{ 0x10b5, 0x9656, 0x1369, 0xd201, 0, 0, PCI_ID_VX822HR, }, +	{ 0x10b5, 0x9656, 0x1369, 0xd301, 0, 0, PCI_ID_PCX822HR, }, +	{ 0x10b5, 0x9056, 0x1369, 0xd221, 0, 0, PCI_ID_VX822E, }, +	{ 0x10b5, 0x9056, 0x1369, 0xd321, 0, 0, PCI_ID_PCX822E, },  	{ 0, }  }; @@ -160,6 +176,14 @@ static struct board_parameters pcxhr_board_params[] = {  [PCI_ID_PCX924E] =      { "PCX924e",      1, 1, 5, 44 },  [PCI_ID_PCX924HRMIC] =  { "PCX924HR-Mic", 1, 1, 5, 44 },  [PCI_ID_PCX924E_MIC] =  { "PCX924e-Mic",  1, 1, 5, 44 }, +[PCI_ID_VX442HR] =      { "VX442HR",      2, 2, 0, 41 }, +[PCI_ID_PCX442HR] =     { "PCX442HR",     2, 2, 0, 41 }, +[PCI_ID_VX442E] =       { "VX442e",       2, 2, 1, 41 }, +[PCI_ID_PCX442E] =      { "PCX442e",      2, 2, 1, 41 }, +[PCI_ID_VX822HR] =      { "VX822HR",      4, 1, 2, 42 }, +[PCI_ID_PCX822HR] =     { "PCX822HR",     4, 1, 2, 42 }, +[PCI_ID_VX822E] =       { "VX822e",       4, 1, 3, 42 }, +[PCI_ID_PCX822E] =      { "PCX822e",      4, 1, 3, 42 },  };  /* boards without hw AES1 and SRC onboard are all using fw_file_set==4 */ diff --git a/sound/pci/pcxhr/pcxhr_hwdep.c b/sound/pci/pcxhr/pcxhr_hwdep.c index ec1587cddb0..bf207e317f7 100644 --- a/sound/pci/pcxhr/pcxhr_hwdep.c +++ b/sound/pci/pcxhr/pcxhr_hwdep.c @@ -66,10 +66,10 @@ static int pcxhr_init_board(struct pcxhr_mgr *mgr)  	err = pcxhr_send_msg(mgr, &rmh);  	if (err)  		return err; -	/* test 8 or 12 phys out */ -	if ((rmh.stat[0] & MASK_FIRST_FIELD) != mgr->playback_chips * 2) +	/* test 4, 8 or 12 phys out */ +	if ((rmh.stat[0] & MASK_FIRST_FIELD) < mgr->playback_chips * 2)  		return -EINVAL; -	/* test 8 or 2 phys in */ +	/* test 4, 8 or 2 phys in */  	if (((rmh.stat[0] >> (2 * FIELD_SIZE)) & MASK_FIRST_FIELD) <  	    mgr->capture_chips * 2)  		return -EINVAL; diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index 760ee467cd9..7d291542c5b 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -464,7 +464,7 @@ struct snd_riptide {  	unsigned long received_irqs;  	unsigned long handled_irqs; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	int in_suspend;  #endif  }; @@ -1150,7 +1150,7 @@ static void riptide_handleirq(unsigned long dev_id)  	}  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int riptide_suspend(struct device *dev)  {  	struct pci_dev *pci = to_pci_dev(dev); @@ -1193,7 +1193,7 @@ static SIMPLE_DEV_PM_OPS(riptide_pm, riptide_suspend, riptide_resume);  #define RIPTIDE_PM_OPS	&riptide_pm  #else  #define RIPTIDE_PM_OPS	NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  static int try_to_load_firmware(struct cmdif *cif, struct snd_riptide *chip)  { diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index 805ab6e9a78..51e43407ebc 100644 --- a/sound/pci/sis7019.c +++ b/sound/pci/sis7019.c @@ -103,7 +103,7 @@ struct voice {   * we're not doing power management, we still need to allocate a page   * for the silence buffer.   */ -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  #define SIS_SUSPEND_PAGES	4  #else  #define SIS_SUSPEND_PAGES	1 @@ -1208,7 +1208,7 @@ static int sis_chip_init(struct sis7019 *sis)  	return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int sis_suspend(struct device *dev)  {  	struct pci_dev *pci = to_pci_dev(dev); @@ -1305,7 +1305,7 @@ static SIMPLE_DEV_PM_OPS(sis_pm, sis_suspend, sis_resume);  #define SIS_PM_OPS	&sis_pm  #else  #define SIS_PM_OPS	NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  static int sis_alloc_suspend(struct sis7019 *sis)  { diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c index d36e6ca147e..8a6f1f76e87 100644 --- a/sound/pci/trident/trident.c +++ b/sound/pci/trident/trident.c @@ -177,7 +177,7 @@ static struct pci_driver trident_driver = {  	.id_table = snd_trident_ids,  	.probe = snd_trident_probe,  	.remove = __devexit_p(snd_trident_remove), -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.driver = {  		.pm = &snd_trident_pm,  	}, diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index 94011dcae73..06b10d1a76e 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -3919,7 +3919,7 @@ static void snd_trident_clear_voices(struct snd_trident * trident, unsigned shor  	}  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int snd_trident_suspend(struct device *dev)  {  	struct pci_dev *pci = to_pci_dev(dev); @@ -3983,4 +3983,4 @@ static int snd_trident_resume(struct device *dev)  }  SIMPLE_DEV_PM_OPS(snd_trident_pm, snd_trident_suspend, snd_trident_resume); -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */ diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 0eb7245dd36..f0b4efdb483 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -362,7 +362,7 @@ struct via82xx {  	unsigned char old_legacy;  	unsigned char old_legacy_cfg; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	unsigned char legacy_saved;  	unsigned char legacy_cfg_saved;  	unsigned char spdif_ctrl_saved; @@ -1440,6 +1440,7 @@ static void init_viadev(struct via82xx *chip, int idx, unsigned int reg_offset,  static int __devinit snd_via8233_pcm_new(struct via82xx *chip)  {  	struct snd_pcm *pcm; +	struct snd_pcm_chmap *chmap;  	int i, err;  	chip->playback_devno = 0;	/* x 4 */ @@ -1467,6 +1468,12 @@ static int __devinit snd_via8233_pcm_new(struct via82xx *chip)  					      snd_dma_pci_data(chip->pci),  					      64*1024, VIA_MAX_BUFSIZE); +	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, +				     snd_pcm_std_chmaps, 2, 0, +				     &chmap); +	if (err < 0) +		return err; +  	/* PCM #1:  multi-channel playback and 2nd capture */  	err = snd_pcm_new(chip->card, chip->card->shortname, 1, 1, 1, &pcm);  	if (err < 0) @@ -1484,6 +1491,14 @@ static int __devinit snd_via8233_pcm_new(struct via82xx *chip)  	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,  					      snd_dma_pci_data(chip->pci),  					      64*1024, VIA_MAX_BUFSIZE); + +	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, +				     snd_pcm_alt_chmaps, 6, 0, +				     &chmap); +	if (err < 0) +		return err; +	chip->ac97->chmaps[SNDRV_PCM_STREAM_PLAYBACK] = chmap; +  	return 0;  } @@ -1493,6 +1508,7 @@ static int __devinit snd_via8233_pcm_new(struct via82xx *chip)  static int __devinit snd_via8233a_pcm_new(struct via82xx *chip)  {  	struct snd_pcm *pcm; +	struct snd_pcm_chmap *chmap;  	int err;  	chip->multi_devno = 0; @@ -1519,6 +1535,13 @@ static int __devinit snd_via8233a_pcm_new(struct via82xx *chip)  					      snd_dma_pci_data(chip->pci),  					      64*1024, VIA_MAX_BUFSIZE); +	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, +				     snd_pcm_alt_chmaps, 6, 0, +				     &chmap); +	if (err < 0) +		return err; +	chip->ac97->chmaps[SNDRV_PCM_STREAM_PLAYBACK] = chmap; +  	/* SPDIF supported? */  	if (! ac97_can_spdif(chip->ac97))  		return 0; @@ -2038,7 +2061,7 @@ static int __devinit snd_via686_init_misc(struct via82xx *chip)  		if (mpu_port >= 0x200) {	/* force MIDI */  			mpu_port &= 0xfffc;  			pci_write_config_dword(chip->pci, 0x18, mpu_port | 0x01); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  			chip->mpu_port_saved = mpu_port;  #endif  		} else { @@ -2090,7 +2113,7 @@ static int __devinit snd_via686_init_misc(struct via82xx *chip)  	snd_via686_create_gameport(chip, &legacy); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	chip->legacy_saved = legacy;  	chip->legacy_cfg_saved = legacy_cfg;  #endif @@ -2238,7 +2261,7 @@ static int snd_via82xx_chip_init(struct via82xx *chip)  	return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  /*   * power management   */ @@ -2313,7 +2336,7 @@ static SIMPLE_DEV_PM_OPS(snd_via82xx_pm, snd_via82xx_suspend, snd_via82xx_resume  #define SND_VIA82XX_PM_OPS	&snd_via82xx_pm  #else  #define SND_VIA82XX_PM_OPS	NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  static int snd_via82xx_free(struct via82xx *chip)  { diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index e886bc16999..8e0efc416f2 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -1019,7 +1019,7 @@ static int snd_via82xx_chip_init(struct via82xx_modem *chip)  	return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  /*   * power management   */ @@ -1076,7 +1076,7 @@ static SIMPLE_DEV_PM_OPS(snd_via82xx_pm, snd_via82xx_suspend, snd_via82xx_resume  #define SND_VIA82XX_PM_OPS	&snd_via82xx_pm  #else  #define SND_VIA82XX_PM_OPS	NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  static int snd_via82xx_free(struct via82xx_modem *chip)  { diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c index b89e7a86e9d..fdfbaf85723 100644 --- a/sound/pci/vx222/vx222.c +++ b/sound/pci/vx222/vx222.c @@ -257,7 +257,7 @@ static void __devexit snd_vx222_remove(struct pci_dev *pci)  	pci_set_drvdata(pci, NULL);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int snd_vx222_suspend(struct device *dev)  {  	struct pci_dev *pci = to_pci_dev(dev); diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c index 4810356b97b..e01fe34db9e 100644 --- a/sound/pci/ymfpci/ymfpci.c +++ b/sound/pci/ymfpci/ymfpci.c @@ -355,7 +355,7 @@ static struct pci_driver ymfpci_driver = {  	.id_table = snd_ymfpci_ids,  	.probe = snd_card_ymfpci_probe,  	.remove = __devexit_p(snd_card_ymfpci_remove), -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	.driver = {  		.pm = &snd_ymfpci_pm,  	}, diff --git a/sound/pci/ymfpci/ymfpci.h b/sound/pci/ymfpci/ymfpci.h index bddc4052286..4631a234891 100644 --- a/sound/pci/ymfpci/ymfpci.h +++ b/sound/pci/ymfpci/ymfpci.h @@ -363,7 +363,7 @@ struct snd_ymfpci {  	const struct firmware *dsp_microcode;  	const struct firmware *controller_microcode; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	u32 *saved_regs;  	u32 saved_ydsxgr_mode;  	u16 saved_dsxg_legacy; diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 62b23635b75..3a6f03f9b02 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -1166,6 +1166,11 @@ int __devinit snd_ymfpci_pcm(struct snd_ymfpci *chip, int device, struct snd_pcm  	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,  					      snd_dma_pci_data(chip->pci), 64*1024, 256*1024); +	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, +				     snd_pcm_std_chmaps, 2, 0, NULL); +	if (err < 0) +		return err; +  	if (rpcm)  		*rpcm = pcm;  	return 0; @@ -1257,6 +1262,14 @@ static struct snd_pcm_ops snd_ymfpci_playback_4ch_ops = {  	.pointer =		snd_ymfpci_playback_pointer,  }; +static const struct snd_pcm_chmap_elem surround_map[] = { +	{ .channels = 1, +	  .map = { SNDRV_CHMAP_MONO } }, +	{ .channels = 2, +	  .map = { SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } }, +	{ } +}; +  int __devinit snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device, struct snd_pcm ** rpcm)  {  	struct snd_pcm *pcm; @@ -1278,6 +1291,11 @@ int __devinit snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device, struct snd  	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,  					      snd_dma_pci_data(chip->pci), 64*1024, 256*1024); +	err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, +				     surround_map, 2, 0, NULL); +	if (err < 0) +		return err; +  	if (rpcm)  		*rpcm = pcm;  	return 0; @@ -2242,7 +2260,7 @@ static int snd_ymfpci_free(struct snd_ymfpci *chip)  	pci_set_power_state(chip->pci, 3);  #endif -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	vfree(chip->saved_regs);  #endif  	if (chip->irq >= 0) @@ -2272,7 +2290,7 @@ static int snd_ymfpci_dev_free(struct snd_device *device)  	return snd_ymfpci_free(chip);  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int saved_regs_index[] = {  	/* spdif */  	YDSXGR_SPDIFOUTCTRL, @@ -2374,7 +2392,7 @@ static int snd_ymfpci_resume(struct device *dev)  }  SIMPLE_DEV_PM_OPS(snd_ymfpci_pm, snd_ymfpci_suspend, snd_ymfpci_resume); -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  int __devinit snd_ymfpci_create(struct snd_card *card,  				struct pci_dev * pci, @@ -2452,7 +2470,7 @@ int __devinit snd_ymfpci_create(struct snd_card *card,  		return err;  	} -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  	chip->saved_regs = vmalloc(YDSXGR_NUM_SAVED_REGS * sizeof(u32));  	if (chip->saved_regs == NULL) {  		snd_ymfpci_free(chip); diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index c5de0a84566..5da8ca7aee0 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -9,6 +9,7 @@ menuconfig SND_SOC  	select SND_JACK if INPUT=y || INPUT=SND  	select REGMAP_I2C if I2C  	select REGMAP_SPI if SPI_MASTER +	select SND_COMPRESS_OFFLOAD  	---help---  	  If you want ASoC support, you should say Y here and also to the @@ -32,9 +33,9 @@ config SND_SOC_DMAENGINE_PCM  source "sound/soc/atmel/Kconfig"  source "sound/soc/au1x/Kconfig"  source "sound/soc/blackfin/Kconfig" +source "sound/soc/cirrus/Kconfig"  source "sound/soc/davinci/Kconfig"  source "sound/soc/dwc/Kconfig" -source "sound/soc/ep93xx/Kconfig"  source "sound/soc/fsl/Kconfig"  source "sound/soc/jz4740/Kconfig"  source "sound/soc/nuc900/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 00a555a743b..bcbf1d00aa8 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -1,5 +1,5 @@  snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o -snd-soc-core-objs += soc-pcm.o soc-io.o +snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o  snd-soc-dmaengine-pcm-objs := soc-dmaengine-pcm.o  obj-$(CONFIG_SND_SOC_DMAENGINE_PCM) += snd-soc-dmaengine-pcm.o @@ -10,9 +10,9 @@ obj-$(CONFIG_SND_SOC)	+= generic/  obj-$(CONFIG_SND_SOC)	+= atmel/  obj-$(CONFIG_SND_SOC)	+= au1x/  obj-$(CONFIG_SND_SOC)	+= blackfin/ +obj-$(CONFIG_SND_SOC)	+= cirrus/  obj-$(CONFIG_SND_SOC)	+= davinci/  obj-$(CONFIG_SND_SOC)	+= dwc/ -obj-$(CONFIG_SND_SOC)	+= ep93xx/  obj-$(CONFIG_SND_SOC)	+= fsl/  obj-$(CONFIG_SND_SOC)	+= jz4740/  obj-$(CONFIG_SND_SOC)	+= mid-x86/ diff --git a/sound/soc/blackfin/bf5xx-ad1836.c b/sound/soc/blackfin/bf5xx-ad1836.c index d542d406377..16b9c9efd19 100644 --- a/sound/soc/blackfin/bf5xx-ad1836.c +++ b/sound/soc/blackfin/bf5xx-ad1836.c @@ -59,62 +59,63 @@ static struct snd_soc_ops bf5xx_ad1836_ops = {  #define BF5XX_AD1836_DAIFMT (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_IF | \  				SND_SOC_DAIFMT_CBM_CFM) -static struct snd_soc_dai_link bf5xx_ad1836_dai[] = { -	{ -		.name = "ad1836", -		.stream_name = "AD1836", -		.cpu_dai_name = "bfin-tdm.0", -		.codec_dai_name = "ad1836-hifi", -		.platform_name = "bfin-tdm-pcm-audio", -		.codec_name = "spi0.4", -		.ops = &bf5xx_ad1836_ops, -		.dai_fmt = BF5XX_AD1836_DAIFMT, -	}, -	{ -		.name = "ad1836", -		.stream_name = "AD1836", -		.cpu_dai_name = "bfin-tdm.1", -		.codec_dai_name = "ad1836-hifi", -		.platform_name = "bfin-tdm-pcm-audio", -		.codec_name = "spi0.4", -		.ops = &bf5xx_ad1836_ops, -		.dai_fmt = BF5XX_AD1836_DAIFMT, -	}, +static struct snd_soc_dai_link bf5xx_ad1836_dai = { +	.name = "ad1836", +	.stream_name = "AD1836", +	.codec_dai_name = "ad1836-hifi", +	.platform_name = "bfin-tdm-pcm-audio", +	.ops = &bf5xx_ad1836_ops, +	.dai_fmt = BF5XX_AD1836_DAIFMT,  };  static struct snd_soc_card bf5xx_ad1836 = {  	.name = "bfin-ad1836",  	.owner = THIS_MODULE, -	.dai_link = &bf5xx_ad1836_dai[CONFIG_SND_BF5XX_SPORT_NUM], +	.dai_link = &bf5xx_ad1836_dai,  	.num_links = 1,  }; -static struct platform_device *bfxx_ad1836_snd_device; - -static int __init bf5xx_ad1836_init(void) +static __devinit int bf5xx_ad1836_driver_probe(struct platform_device *pdev)  { +	struct snd_soc_card *card = &bf5xx_ad1836; +	const char **link_name;  	int ret; -	bfxx_ad1836_snd_device = platform_device_alloc("soc-audio", -1); -	if (!bfxx_ad1836_snd_device) -		return -ENOMEM; +	link_name = pdev->dev.platform_data; +	if (!link_name) { +		dev_err(&pdev->dev, "No platform data supplied\n"); +		return -EINVAL; +	} +	bf5xx_ad1836_dai.cpu_dai_name = link_name[0]; +	bf5xx_ad1836_dai.codec_name = link_name[1]; -	platform_set_drvdata(bfxx_ad1836_snd_device, &bf5xx_ad1836); -	ret = platform_device_add(bfxx_ad1836_snd_device); +	card->dev = &pdev->dev; +	platform_set_drvdata(pdev, card); +	ret = snd_soc_register_card(card);  	if (ret) -		platform_device_put(bfxx_ad1836_snd_device); - +		dev_err(&pdev->dev, "Failed to register card\n");  	return ret;  } -static void __exit bf5xx_ad1836_exit(void) +static int __devexit bf5xx_ad1836_driver_remove(struct platform_device *pdev)  { -	platform_device_unregister(bfxx_ad1836_snd_device); +	struct snd_soc_card *card = platform_get_drvdata(pdev); + +	snd_soc_unregister_card(card); +	return 0;  } -module_init(bf5xx_ad1836_init); -module_exit(bf5xx_ad1836_exit); +static struct platform_driver bf5xx_ad1836_driver = { +	.driver = { +		.name = "bfin-snd-ad1836", +		.owner = THIS_MODULE, +		.pm = &snd_soc_pm_ops, +	}, +	.probe = bf5xx_ad1836_driver_probe, +	.remove = __devexit_p(bf5xx_ad1836_driver_remove), +}; +module_platform_driver(bf5xx_ad1836_driver);  /* Module information */  MODULE_AUTHOR("Barry Song"); diff --git a/sound/soc/ep93xx/Kconfig b/sound/soc/cirrus/Kconfig index 88143db7e75..88143db7e75 100644 --- a/sound/soc/ep93xx/Kconfig +++ b/sound/soc/cirrus/Kconfig diff --git a/sound/soc/ep93xx/Makefile b/sound/soc/cirrus/Makefile index 5514146cbdf..5514146cbdf 100644 --- a/sound/soc/ep93xx/Makefile +++ b/sound/soc/cirrus/Makefile diff --git a/sound/soc/ep93xx/edb93xx.c b/sound/soc/cirrus/edb93xx.c index e01cb02abd3..e01cb02abd3 100644 --- a/sound/soc/ep93xx/edb93xx.c +++ b/sound/soc/cirrus/edb93xx.c diff --git a/sound/soc/ep93xx/ep93xx-ac97.c b/sound/soc/cirrus/ep93xx-ac97.c index c3521653cfd..c3521653cfd 100644 --- a/sound/soc/ep93xx/ep93xx-ac97.c +++ b/sound/soc/cirrus/ep93xx-ac97.c diff --git a/sound/soc/ep93xx/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c index ac4a7515e7b..ac4a7515e7b 100644 --- a/sound/soc/ep93xx/ep93xx-i2s.c +++ b/sound/soc/cirrus/ep93xx-i2s.c diff --git a/sound/soc/ep93xx/ep93xx-pcm.c b/sound/soc/cirrus/ep93xx-pcm.c index 665d9c94cc1..665d9c94cc1 100644 --- a/sound/soc/ep93xx/ep93xx-pcm.c +++ b/sound/soc/cirrus/ep93xx-pcm.c diff --git a/sound/soc/ep93xx/ep93xx-pcm.h b/sound/soc/cirrus/ep93xx-pcm.h index 111e1121ecb..111e1121ecb 100644 --- a/sound/soc/ep93xx/ep93xx-pcm.h +++ b/sound/soc/cirrus/ep93xx-pcm.h diff --git a/sound/soc/ep93xx/simone.c b/sound/soc/cirrus/simone.c index dd997094eb3..dd997094eb3 100644 --- a/sound/soc/ep93xx/simone.c +++ b/sound/soc/cirrus/simone.c diff --git a/sound/soc/ep93xx/snappercl15.c b/sound/soc/cirrus/snappercl15.c index a193cea3cf3..a193cea3cf3 100644 --- a/sound/soc/ep93xx/snappercl15.c +++ b/sound/soc/cirrus/snappercl15.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 9f8e8594aeb..b92759a3936 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -37,6 +37,7 @@ config SND_SOC_ALL_CODECS  	select SND_SOC_CX20442  	select SND_SOC_DA7210 if I2C  	select SND_SOC_DA732X if I2C +	select SND_SOC_DA9055 if I2C  	select SND_SOC_DFBMCS320  	select SND_SOC_ISABELLE if I2C  	select SND_SOC_JZ4740_CODEC @@ -70,6 +71,7 @@ config SND_SOC_ALL_CODECS  	select SND_SOC_UDA134X  	select SND_SOC_UDA1380 if I2C  	select SND_SOC_WL1273 if MFD_WL1273_CORE +	select SND_SOC_WM0010 if SPI_MASTER  	select SND_SOC_WM1250_EV1 if I2C  	select SND_SOC_WM2000 if I2C  	select SND_SOC_WM2200 if I2C @@ -238,6 +240,9 @@ config SND_SOC_DA7210  config SND_SOC_DA732X          tristate +config SND_SOC_DA9055 +	tristate +  config SND_SOC_DFBMCS320  	tristate @@ -326,6 +331,9 @@ config SND_SOC_UDA1380  config SND_SOC_WL1273  	tristate +config SND_SOC_WM0010 +	tristate +  config SND_SOC_WM1250_EV1  	tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 34148bb59c6..9bd4d95aab4 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -24,6 +24,7 @@ snd-soc-cs4271-objs := cs4271.o  snd-soc-cx20442-objs := cx20442.o  snd-soc-da7210-objs := da7210.o  snd-soc-da732x-objs := da732x.o +snd-soc-da9055-objs := da9055.o  snd-soc-dfbmcs320-objs := dfbmcs320.o  snd-soc-dmic-objs := dmic.o  snd-soc-isabelle-objs := isabelle.o @@ -61,6 +62,7 @@ snd-soc-twl6040-objs := twl6040.o  snd-soc-uda134x-objs := uda134x.o  snd-soc-uda1380-objs := uda1380.o  snd-soc-wl1273-objs := wl1273.o +snd-soc-wm0010-objs := wm0010.o  snd-soc-wm1250-ev1-objs := wm1250-ev1.o  snd-soc-wm2000-objs := wm2000.o  snd-soc-wm2200-objs := wm2200.o @@ -143,6 +145,7 @@ obj-$(CONFIG_SND_SOC_CS4271)	+= snd-soc-cs4271.o  obj-$(CONFIG_SND_SOC_CX20442)	+= snd-soc-cx20442.o  obj-$(CONFIG_SND_SOC_DA7210)	+= snd-soc-da7210.o  obj-$(CONFIG_SND_SOC_DA732X)	+= snd-soc-da732x.o +obj-$(CONFIG_SND_SOC_DA9055)	+= snd-soc-da9055.o  obj-$(CONFIG_SND_SOC_DFBMCS320)	+= snd-soc-dfbmcs320.o  obj-$(CONFIG_SND_SOC_DMIC)	+= snd-soc-dmic.o  obj-$(CONFIG_SND_SOC_ISABELLE)	+= snd-soc-isabelle.o @@ -177,6 +180,7 @@ obj-$(CONFIG_SND_SOC_TWL6040)	+= snd-soc-twl6040.o  obj-$(CONFIG_SND_SOC_UDA134X)	+= snd-soc-uda134x.o  obj-$(CONFIG_SND_SOC_UDA1380)	+= snd-soc-uda1380.o  obj-$(CONFIG_SND_SOC_WL1273)	+= snd-soc-wl1273.o +obj-$(CONFIG_SND_SOC_WM0010)	+= snd-soc-wm0010.o  obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o  obj-$(CONFIG_SND_SOC_WM2000)	+= snd-soc-wm2000.o  obj-$(CONFIG_SND_SOC_WM2200)	+= snd-soc-wm2200.o diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 07abd09e0b1..af547490b4f 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -391,10 +391,10 @@ static const struct snd_soc_dapm_widget ab8500_dapm_widgets[] = {  	SND_SOC_DAPM_CLOCK_SUPPLY("audioclk"),  	/* Regulators */ -	SND_SOC_DAPM_REGULATOR_SUPPLY("V-AUD", 0), -	SND_SOC_DAPM_REGULATOR_SUPPLY("V-AMIC1", 0), -	SND_SOC_DAPM_REGULATOR_SUPPLY("V-AMIC2", 0), -	SND_SOC_DAPM_REGULATOR_SUPPLY("V-DMIC", 0), +	SND_SOC_DAPM_REGULATOR_SUPPLY("V-AUD", 0, 0), +	SND_SOC_DAPM_REGULATOR_SUPPLY("V-AMIC1", 0, 0), +	SND_SOC_DAPM_REGULATOR_SUPPLY("V-AMIC2", 0, 0), +	SND_SOC_DAPM_REGULATOR_SUPPLY("V-DMIC", 0, 0),  	/* Power */  	SND_SOC_DAPM_SUPPLY("Audio Power", @@ -2462,10 +2462,7 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec)  	dev_dbg(dev, "%s: Enter.\n", __func__);  	/* Setup AB8500 according to board-settings */ -	pdata = (struct ab8500_platform_data *)dev_get_platdata(dev->parent); - -	/* Inform SoC Core that we have our own I/O arrangements. */ -	codec->control_data = (void *)true; +	pdata = dev_get_platdata(dev->parent);  	if (np) {  		if (!pdata) diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index c67b50d8b31..dce6ebeef45 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c @@ -19,6 +19,8 @@  #include <sound/soc.h>  #include <sound/tlv.h>  #include <linux/spi/spi.h> +#include <linux/regmap.h> +  #include "ad1836.h"  enum ad1836_type { @@ -30,6 +32,7 @@ enum ad1836_type {  /* codec private data */  struct ad1836_priv {  	enum ad1836_type type; +	struct regmap *regmap;  };  /* @@ -161,8 +164,8 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,  		struct snd_pcm_hw_params *params,  		struct snd_soc_dai *dai)  { +	struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(dai->codec);  	int word_len = 0; -	struct snd_soc_codec *codec = dai->codec;  	/* bit size */  	switch (params_format(params)) { @@ -178,10 +181,12 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,  		break;  	} -	snd_soc_update_bits(codec, AD1836_DAC_CTRL1, AD1836_DAC_WORD_LEN_MASK, +	regmap_update_bits(ad1836->regmap, AD1836_DAC_CTRL1, +		AD1836_DAC_WORD_LEN_MASK,  		word_len << AD1836_DAC_WORD_LEN_OFFSET); -	snd_soc_update_bits(codec, AD1836_ADC_CTRL2, AD1836_ADC_WORD_LEN_MASK, +	regmap_update_bits(ad1836->regmap, AD1836_ADC_CTRL2, +		AD1836_ADC_WORD_LEN_MASK,  		word_len << AD1836_ADC_WORD_OFFSET);  	return 0; @@ -223,15 +228,17 @@ static struct snd_soc_dai_driver ad183x_dais[] = {  #ifdef CONFIG_PM  static int ad1836_suspend(struct snd_soc_codec *codec)  { +	struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);  	/* reset clock control mode */ -	return snd_soc_update_bits(codec, AD1836_ADC_CTRL2, +	return regmap_update_bits(ad1836->regmap, AD1836_ADC_CTRL2,  		AD1836_ADC_SERFMT_MASK, 0);  }  static int ad1836_resume(struct snd_soc_codec *codec)  { +	struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);  	/* restore clock control mode */ -	return snd_soc_update_bits(codec, AD1836_ADC_CTRL2, +	return regmap_update_bits(ad1836->regmap, AD1836_ADC_CTRL2,  		AD1836_ADC_SERFMT_MASK, AD1836_ADC_AUX);  }  #else @@ -250,37 +257,30 @@ static int ad1836_probe(struct snd_soc_codec *codec)  	num_dacs = ad183x_dais[ad1836->type].playback.channels_max / 2;  	num_adcs = ad183x_dais[ad1836->type].capture.channels_max / 2; -	ret = snd_soc_codec_set_cache_io(codec, 4, 12, SND_SOC_SPI); -	if (ret < 0) { -		dev_err(codec->dev, "failed to set cache I/O: %d\n", -				ret); -		return ret; -	} -  	/* default setting for ad1836 */  	/* de-emphasis: 48kHz, power-on dac */ -	snd_soc_write(codec, AD1836_DAC_CTRL1, 0x300); +	regmap_write(ad1836->regmap, AD1836_DAC_CTRL1, 0x300);  	/* unmute dac channels */ -	snd_soc_write(codec, AD1836_DAC_CTRL2, 0x0); +	regmap_write(ad1836->regmap, AD1836_DAC_CTRL2, 0x0);  	/* high-pass filter enable, power-on adc */ -	snd_soc_write(codec, AD1836_ADC_CTRL1, 0x100); +	regmap_write(ad1836->regmap, AD1836_ADC_CTRL1, 0x100);  	/* unmute adc channles, adc aux mode */ -	snd_soc_write(codec, AD1836_ADC_CTRL2, 0x180); +	regmap_write(ad1836->regmap, AD1836_ADC_CTRL2, 0x180);  	/* volume */  	for (i = 1; i <= num_dacs; ++i) { -		snd_soc_write(codec, AD1836_DAC_L_VOL(i), 0x3FF); -		snd_soc_write(codec, AD1836_DAC_R_VOL(i), 0x3FF); +		regmap_write(ad1836->regmap, AD1836_DAC_L_VOL(i), 0x3FF); +		regmap_write(ad1836->regmap, AD1836_DAC_R_VOL(i), 0x3FF);  	}  	if (ad1836->type == AD1836) {  		/* left/right diff:PGA/MUX */ -		snd_soc_write(codec, AD1836_ADC_CTRL3, 0x3A); +		regmap_write(ad1836->regmap, AD1836_ADC_CTRL3, 0x3A);  		ret = snd_soc_add_codec_controls(codec, ad1836_controls,  				ARRAY_SIZE(ad1836_controls));  		if (ret)  			return ret;  	} else { -		snd_soc_write(codec, AD1836_ADC_CTRL3, 0x00); +		regmap_write(ad1836->regmap, AD1836_ADC_CTRL3, 0x00);  	}  	ret = snd_soc_add_codec_controls(codec, ad183x_dac_controls, num_dacs * 2); @@ -313,8 +313,9 @@ static int ad1836_probe(struct snd_soc_codec *codec)  /* power down chip */  static int ad1836_remove(struct snd_soc_codec *codec)  { +	struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);  	/* reset clock control mode */ -	return snd_soc_update_bits(codec, AD1836_ADC_CTRL2, +	return regmap_update_bits(ad1836->regmap, AD1836_ADC_CTRL2,  		AD1836_ADC_SERFMT_MASK, 0);  } @@ -323,8 +324,6 @@ static struct snd_soc_codec_driver soc_codec_dev_ad1836 = {  	.remove = ad1836_remove,  	.suspend = ad1836_suspend,  	.resume = ad1836_resume, -	.reg_cache_size = AD1836_NUM_REGS, -	.reg_word_size = sizeof(u16),  	.controls = ad183x_controls,  	.num_controls = ARRAY_SIZE(ad183x_controls), @@ -334,6 +333,33 @@ static struct snd_soc_codec_driver soc_codec_dev_ad1836 = {  	.num_dapm_routes = ARRAY_SIZE(ad183x_dapm_routes),  }; +static const struct reg_default ad1836_reg_defaults[] = { +	{ AD1836_DAC_CTRL1, 0x0000 }, +	{ AD1836_DAC_CTRL2, 0x0000 }, +	{ AD1836_DAC_L_VOL(0), 0x0000 }, +	{ AD1836_DAC_R_VOL(0), 0x0000 }, +	{ AD1836_DAC_L_VOL(1), 0x0000 }, +	{ AD1836_DAC_R_VOL(1), 0x0000 }, +	{ AD1836_DAC_L_VOL(2), 0x0000 }, +	{ AD1836_DAC_R_VOL(2), 0x0000 }, +	{ AD1836_DAC_L_VOL(3), 0x0000 }, +	{ AD1836_DAC_R_VOL(3), 0x0000 }, +	{ AD1836_ADC_CTRL1, 0x0000 }, +	{ AD1836_ADC_CTRL2, 0x0000 }, +	{ AD1836_ADC_CTRL3, 0x0000 }, +}; + +static const struct regmap_config ad1836_regmap_config = { +	.val_bits = 12, +	.reg_bits = 4, +	.read_flag_mask = 0x08, + +	.max_register = AD1836_ADC_CTRL3, +	.reg_defaults = ad1836_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(ad1836_reg_defaults), +	.cache_type = REGCACHE_RBTREE, +}; +  static int __devinit ad1836_spi_probe(struct spi_device *spi)  {  	struct ad1836_priv *ad1836; @@ -344,6 +370,10 @@ static int __devinit ad1836_spi_probe(struct spi_device *spi)  	if (ad1836 == NULL)  		return -ENOMEM; +	ad1836->regmap = devm_regmap_init_spi(spi, &ad1836_regmap_config); +	if (IS_ERR(ad1836->regmap)) +		return PTR_ERR(ad1836->regmap); +  	ad1836->type = spi_get_device_id(spi)->driver_data;  	spi_set_drvdata(spi, ad1836); @@ -379,17 +409,7 @@ static struct spi_driver ad1836_spi_driver = {  	.id_table	= ad1836_ids,  }; -static int __init ad1836_init(void) -{ -	return spi_register_driver(&ad1836_spi_driver); -} -module_init(ad1836_init); - -static void __exit ad1836_exit(void) -{ -	spi_unregister_driver(&ad1836_spi_driver); -} -module_exit(ad1836_exit); +module_spi_driver(ad1836_spi_driver);  MODULE_DESCRIPTION("ASoC ad1836 driver");  MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index 13e62be4f99..2f752660f67 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c @@ -381,40 +381,25 @@ static const struct regmap_config ad193x_spi_regmap_config = {  static int __devinit ad193x_spi_probe(struct spi_device *spi)  {  	struct ad193x_priv *ad193x; -	int ret;  	ad193x = devm_kzalloc(&spi->dev, sizeof(struct ad193x_priv),  			      GFP_KERNEL);  	if (ad193x == NULL)  		return -ENOMEM; -	ad193x->regmap = regmap_init_spi(spi, &ad193x_spi_regmap_config); -	if (IS_ERR(ad193x->regmap)) { -		ret = PTR_ERR(ad193x->regmap); -		goto err_out; -	} +	ad193x->regmap = devm_regmap_init_spi(spi, &ad193x_spi_regmap_config); +	if (IS_ERR(ad193x->regmap)) +		return PTR_ERR(ad193x->regmap);  	spi_set_drvdata(spi, ad193x); -	ret = snd_soc_register_codec(&spi->dev, -			&soc_codec_dev_ad193x, &ad193x_dai, 1); -	if (ret < 0) -		goto err_regmap_exit; - -	return 0; - -err_regmap_exit: -	regmap_exit(ad193x->regmap); -err_out: -	return ret; +	return snd_soc_register_codec(&spi->dev, &soc_codec_dev_ad193x, +			&ad193x_dai, 1);  }  static int __devexit ad193x_spi_remove(struct spi_device *spi)  { -	struct ad193x_priv *ad193x = spi_get_drvdata(spi); -  	snd_soc_unregister_codec(&spi->dev); -	regmap_exit(ad193x->regmap);  	return 0;  } @@ -449,40 +434,25 @@ static int __devinit ad193x_i2c_probe(struct i2c_client *client,  		const struct i2c_device_id *id)  {  	struct ad193x_priv *ad193x; -	int ret;  	ad193x = devm_kzalloc(&client->dev, sizeof(struct ad193x_priv),  			      GFP_KERNEL);  	if (ad193x == NULL)  		return -ENOMEM; -	ad193x->regmap = regmap_init_i2c(client, &ad193x_i2c_regmap_config); -	if (IS_ERR(ad193x->regmap)) { -		ret = PTR_ERR(ad193x->regmap); -		goto err_out; -	} +	ad193x->regmap = devm_regmap_init_i2c(client, &ad193x_i2c_regmap_config); +	if (IS_ERR(ad193x->regmap)) +		return PTR_ERR(ad193x->regmap);  	i2c_set_clientdata(client, ad193x); -	ret =  snd_soc_register_codec(&client->dev, -			&soc_codec_dev_ad193x, &ad193x_dai, 1); -	if (ret < 0) -		goto err_regmap_exit; - -	return 0; - -err_regmap_exit: -	regmap_exit(ad193x->regmap); -err_out: -	return ret; +	return snd_soc_register_codec(&client->dev, &soc_codec_dev_ad193x, +			&ad193x_dai, 1);  }  static int __devexit ad193x_i2c_remove(struct i2c_client *client)  { -	struct ad193x_priv *ad193x = i2c_get_clientdata(client); -  	snd_soc_unregister_codec(&client->dev); -	regmap_exit(ad193x->regmap);  	return 0;  } diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 11b1b714b8b..8c39dddd7d0 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -186,7 +186,6 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec)  	printk(KERN_INFO "AD1980 SoC Audio Codec\n"); -	codec->control_data = codec;	/* we don't use regmap! */  	ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);  	if (ret < 0) {  		printk(KERN_ERR "ad1980: failed to register AC97 codec\n"); diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 44f59064d8d..704544bfc90 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -1392,17 +1392,7 @@ static struct i2c_driver adau1373_i2c_driver = {  	.id_table = adau1373_i2c_id,  }; -static int __init adau1373_init(void) -{ -	return i2c_add_driver(&adau1373_i2c_driver); -} -module_init(adau1373_init); - -static void __exit adau1373_exit(void) -{ -	i2c_del_driver(&adau1373_i2c_driver); -} -module_exit(adau1373_exit); +module_i2c_driver(adau1373_i2c_driver);  MODULE_DESCRIPTION("ASoC ADAU1373 driver");  MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index 3d50fc8646b..51f2f3cd813 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c @@ -527,17 +527,7 @@ static struct i2c_driver adau1701_i2c_driver = {  	.id_table	= adau1701_i2c_id,  }; -static int __init adau1701_init(void) -{ -	return i2c_add_driver(&adau1701_i2c_driver); -} -module_init(adau1701_init); - -static void __exit adau1701_exit(void) -{ -	i2c_del_driver(&adau1701_i2c_driver); -} -module_exit(adau1701_exit); +module_i2c_driver(adau1701_i2c_driver);  MODULE_DESCRIPTION("ASoC ADAU1701 SigmaDSP driver");  MODULE_AUTHOR("Cliff Cai <cliff.cai@analog.com>"); diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index 5fb7c2a80e6..2b457976a7b 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c @@ -696,17 +696,7 @@ static struct i2c_driver ak4671_i2c_driver = {  	.id_table = ak4671_i2c_id,  }; -static int __init ak4671_modinit(void) -{ -	return i2c_add_driver(&ak4671_i2c_driver); -} -module_init(ak4671_modinit); - -static void __exit ak4671_exit(void) -{ -	i2c_del_driver(&ak4671_i2c_driver); -} -module_exit(ak4671_exit); +module_i2c_driver(ak4671_i2c_driver);  MODULE_DESCRIPTION("ASoC AK4671 codec driver");  MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>"); diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 1cf7a32d1b2..c03b65af305 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -119,6 +119,24 @@ const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {  	"DSP1.4",  	"DSP1.5",  	"DSP1.6", +	"DSP2.1", +	"DSP2.2", +	"DSP2.3", +	"DSP2.4", +	"DSP2.5", +	"DSP2.6", +	"DSP3.1", +	"DSP3.2", +	"DSP3.3", +	"DSP3.4", +	"DSP3.5", +	"DSP3.6", +	"DSP4.1", +	"DSP4.2", +	"DSP4.3", +	"DSP4.4", +	"DSP4.5", +	"DSP4.6",  	"ASRC1L",  	"ASRC1R",  	"ASRC2L", @@ -180,6 +198,24 @@ int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {  	0x6b,  	0x6c,  	0x6d, +	0x70,  /* DSP2.1 */ +	0x71, +	0x72, +	0x73, +	0x74, +	0x75, +	0x78,  /* DSP3.1 */ +	0x79, +	0x7a, +	0x7b, +	0x7c, +	0x7d, +	0x80,  /* DSP4.1 */ +	0x81, +	0x82, +	0x83, +	0x84, +	0x85,  	0x90,  /* ASRC1L */  	0x91,  	0x92, @@ -229,6 +265,75 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,  }  EXPORT_SYMBOL_GPL(arizona_out_ev); +static unsigned int arizona_sysclk_48k_rates[] = { +	6144000, +	12288000, +	22579200, +	49152000, +	73728000, +	98304000, +	147456000, +}; + +static unsigned int arizona_sysclk_44k1_rates[] = { +	5644800, +	11289600, +	24576000, +	45158400, +	67737600, +	90316800, +	135475200, +}; + +static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk, +			     unsigned int freq) +{ +	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); +	unsigned int reg; +	unsigned int *rates; +	int ref, div, refclk; + +	switch (clk) { +	case ARIZONA_CLK_OPCLK: +		reg = ARIZONA_OUTPUT_SYSTEM_CLOCK; +		refclk = priv->sysclk; +		break; +	case ARIZONA_CLK_ASYNC_OPCLK: +		reg = ARIZONA_OUTPUT_ASYNC_CLOCK; +		refclk = priv->asyncclk; +		break; +	default: +		return -EINVAL; +	} + +	if (refclk % 8000) +		rates = arizona_sysclk_44k1_rates; +	else +		rates = arizona_sysclk_48k_rates; + +	for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) && +		     rates[ref] <= refclk; ref++) { +		div = 1; +		while (rates[ref] / div >= freq && div < 32) { +			if (rates[ref] / div == freq) { +				dev_dbg(codec->dev, "Configured %dHz OPCLK\n", +					freq); +				snd_soc_update_bits(codec, reg, +						    ARIZONA_OPCLK_DIV_MASK | +						    ARIZONA_OPCLK_SEL_MASK, +						    (div << +						     ARIZONA_OPCLK_DIV_SHIFT) | +						    ref); +				return 0; +			} +			div++; +		} +	} + +	dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq); +	return -EINVAL; +} +  int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,  		       int source, unsigned int freq, int dir)  { @@ -252,6 +357,9 @@ int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,  		reg = ARIZONA_ASYNC_CLOCK_1;  		clk = &priv->asyncclk;  		break; +	case ARIZONA_CLK_OPCLK: +	case ARIZONA_CLK_ASYNC_OPCLK: +		return arizona_set_opclk(codec, clk_id, freq);  	default:  		return -EINVAL;  	} @@ -666,7 +774,7 @@ static irqreturn_t arizona_fll_lock(int irq, void *data)  {  	struct arizona_fll *fll = data; -	arizona_fll_dbg(fll, "Locked\n"); +	arizona_fll_dbg(fll, "Lock status changed\n");  	complete(&fll->lock); diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 59caca8865e..36ec6494612 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -17,8 +17,10 @@  #include <sound/soc.h> -#define ARIZONA_CLK_SYSCLK   1 -#define ARIZONA_CLK_ASYNCCLK 2 +#define ARIZONA_CLK_SYSCLK         1 +#define ARIZONA_CLK_ASYNCCLK       2 +#define ARIZONA_CLK_OPCLK          3 +#define ARIZONA_CLK_ASYNC_OPCLK    4  #define ARIZONA_CLK_SRC_MCLK1    0x0  #define ARIZONA_CLK_SRC_MCLK2    0x1 @@ -59,7 +61,7 @@ struct arizona_priv {  	struct arizona_dai_priv dai[ARIZONA_MAX_DAI];  }; -#define ARIZONA_NUM_MIXER_INPUTS 57 +#define ARIZONA_NUM_MIXER_INPUTS 75  extern const unsigned int arizona_mixer_tlv[];  extern const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS]; diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 047917f0b8a..8e4779812b9 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -29,6 +29,8 @@  #include <linux/i2c.h>  #include <linux/delay.h>  #include <linux/regulator/consumer.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h>  /*   * The codec isn't really big-endian or little-endian, since the I2S @@ -110,14 +112,15 @@   * This array contains the power-on default values of the registers, with the   * exception of the "CHIPID" register (01h).  The lower four bits of that   * register contain the hardware revision, so it is treated as volatile. - * - * Also note that on the CS4270, the first readable register is 1, but ASoC - * assumes the first register is 0.  Therfore, the array must have an entry for - * register 0, but we use cs4270_reg_is_readable() to tell ASoC that it can't - * be read.   */ -static const u8 cs4270_default_reg_cache[CS4270_LASTREG + 1] = { -	0x00, 0x00, 0x00, 0x30, 0x00, 0x60, 0x20, 0x00, 0x00 +static const struct reg_default cs4270_reg_defaults[] = { +	{ 2, 0x00 }, +	{ 3, 0x30 }, +	{ 4, 0x00 }, +	{ 5, 0x60 }, +	{ 6, 0x20 }, +	{ 7, 0x00 }, +	{ 8, 0x00 },  };  static const char *supply_names[] = { @@ -126,7 +129,7 @@ static const char *supply_names[] = {  /* Private data for the CS4270 */  struct cs4270_private { -	enum snd_soc_control_type control_type; +	struct regmap *regmap;  	unsigned int mclk; /* Input frequency of the MCLK pin */  	unsigned int mode; /* The mode (I2S or left-justified) */  	unsigned int slave_mode; @@ -191,12 +194,12 @@ static struct cs4270_mode_ratios cs4270_mode_ratios[] = {  /* The number of MCLK/LRCK ratios supported by the CS4270 */  #define NUM_MCLK_RATIOS		ARRAY_SIZE(cs4270_mode_ratios) -static int cs4270_reg_is_readable(struct snd_soc_codec *codec, unsigned int reg) +static bool cs4270_reg_is_readable(struct device *dev, unsigned int reg)  {  	return (reg >= CS4270_FIRSTREG) && (reg <= CS4270_LASTREG);  } -static int cs4270_reg_is_volatile(struct snd_soc_codec *codec, unsigned int reg) +static bool cs4270_reg_is_volatile(struct device *dev, unsigned int reg)  {  	/* Unreadable registers are considered volatile */  	if ((reg < CS4270_FIRSTREG) || (reg > CS4270_LASTREG)) @@ -456,7 +459,7 @@ static struct snd_soc_dai_driver cs4270_dai = {  	.name = "cs4270-hifi",  	.playback = {  		.stream_name = "Playback", -		.channels_min = 1, +		.channels_min = 2,  		.channels_max = 2,  		.rates = SNDRV_PCM_RATE_CONTINUOUS,  		.rate_min = 4000, @@ -465,7 +468,7 @@ static struct snd_soc_dai_driver cs4270_dai = {  	},  	.capture = {  		.stream_name = "Capture", -		.channels_min = 1, +		.channels_min = 2,  		.channels_max = 2,  		.rates = SNDRV_PCM_RATE_CONTINUOUS,  		.rate_min = 4000, @@ -485,12 +488,12 @@ static struct snd_soc_dai_driver cs4270_dai = {  static int cs4270_probe(struct snd_soc_codec *codec)  {  	struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec); -	int i, ret; +	int ret;  	/* Tell ASoC what kind of I/O to use to read the registers.  ASoC will  	 * then do the I2C transactions itself.  	 */ -	ret = snd_soc_codec_set_cache_io(codec, 8, 8, cs4270->control_type); +	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);  	if (ret < 0) {  		dev_err(codec->dev, "failed to set cache I/O (ret=%i)\n", ret);  		return ret; @@ -519,33 +522,8 @@ static int cs4270_probe(struct snd_soc_codec *codec)  		return ret;  	} -	/* Add the non-DAPM controls */ -	ret = snd_soc_add_codec_controls(codec, cs4270_snd_controls, -				ARRAY_SIZE(cs4270_snd_controls)); -	if (ret < 0) { -		dev_err(codec->dev, "failed to add controls\n"); -		return ret; -	} - -	/* get the power supply regulators */ -	for (i = 0; i < ARRAY_SIZE(supply_names); i++) -		cs4270->supplies[i].supply = supply_names[i]; - -	ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(cs4270->supplies), -				 cs4270->supplies); -	if (ret < 0) -		return ret; -  	ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),  				    cs4270->supplies); -	if (ret < 0) -		goto error_free_regulators; - -	return 0; - -error_free_regulators: -	regulator_bulk_free(ARRAY_SIZE(cs4270->supplies), -			    cs4270->supplies);  	return ret;  } @@ -561,7 +539,6 @@ static int cs4270_remove(struct snd_soc_codec *codec)  	struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);  	regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), cs4270->supplies); -	regulator_bulk_free(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);  	return 0;  }; @@ -611,7 +588,7 @@ static int cs4270_soc_resume(struct snd_soc_codec *codec)  	ndelay(500);  	/* first restore the entire register cache ... */ -	snd_soc_cache_sync(codec); +	regcache_sync(cs4270->regmap);  	/* ... then disable the power-down bits */  	reg = snd_soc_read(codec, CS4270_PWRCTL); @@ -632,11 +609,30 @@ static const struct snd_soc_codec_driver soc_codec_device_cs4270 = {  	.remove =		cs4270_remove,  	.suspend =		cs4270_soc_suspend,  	.resume =		cs4270_soc_resume, -	.volatile_register =	cs4270_reg_is_volatile, -	.readable_register =	cs4270_reg_is_readable, -	.reg_cache_size =	CS4270_LASTREG + 1, -	.reg_word_size =	sizeof(u8), -	.reg_cache_default =	cs4270_default_reg_cache, + +	.controls =		cs4270_snd_controls, +	.num_controls =		ARRAY_SIZE(cs4270_snd_controls), +}; + +/* + * cs4270_of_match - the device tree bindings + */ +static const struct of_device_id cs4270_of_match[] = { +	{ .compatible = "cirrus,cs4270", }, +	{ } +}; +MODULE_DEVICE_TABLE(of, cs4270_of_match); + +static const struct regmap_config cs4270_regmap = { +	.reg_bits =		8, +	.val_bits =		8, +	.max_register =		CS4270_LASTREG, +	.reg_defaults =		cs4270_reg_defaults, +	.num_reg_defaults =	ARRAY_SIZE(cs4270_reg_defaults), +	.cache_type =		REGCACHE_RBTREE, + +	.readable_reg =		cs4270_reg_is_readable, +	.volatile_reg =		cs4270_reg_is_volatile,  };  /** @@ -650,19 +646,56 @@ static const struct snd_soc_codec_driver soc_codec_device_cs4270 = {  static int cs4270_i2c_probe(struct i2c_client *i2c_client,  	const struct i2c_device_id *id)  { +	struct device_node *np = i2c_client->dev.of_node;  	struct cs4270_private *cs4270; -	int ret; +	unsigned int val; +	int ret, i; -	/* Verify that we have a CS4270 */ +	cs4270 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs4270_private), +			      GFP_KERNEL); +	if (!cs4270) { +		dev_err(&i2c_client->dev, "could not allocate codec\n"); +		return -ENOMEM; +	} + +	/* get the power supply regulators */ +	for (i = 0; i < ARRAY_SIZE(supply_names); i++) +		cs4270->supplies[i].supply = supply_names[i]; + +	ret = devm_regulator_bulk_get(&i2c_client->dev, +				      ARRAY_SIZE(cs4270->supplies), +				      cs4270->supplies); +	if (ret < 0) +		return ret; + +	/* See if we have a way to bring the codec out of reset */ +	if (np) { +		enum of_gpio_flags flags; +		int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags); + +		if (gpio_is_valid(gpio)) { +			ret = devm_gpio_request_one(&i2c_client->dev, gpio, +				     flags & OF_GPIO_ACTIVE_LOW ? +					GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH, +				     "cs4270 reset"); +			if (ret < 0) +				return ret; +		} +	} -	ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID); +	cs4270->regmap = devm_regmap_init_i2c(i2c_client, &cs4270_regmap); +	if (IS_ERR(cs4270->regmap)) +		return PTR_ERR(cs4270->regmap); + +	/* Verify that we have a CS4270 */ +	ret = regmap_read(cs4270->regmap, CS4270_CHIPID, &val);  	if (ret < 0) {  		dev_err(&i2c_client->dev, "failed to read i2c at addr %X\n",  		       i2c_client->addr);  		return ret;  	}  	/* The top four bits of the chip ID should be 1100. */ -	if ((ret & 0xF0) != 0xC0) { +	if ((val & 0xF0) != 0xC0) {  		dev_err(&i2c_client->dev, "device at addr %X is not a CS4270\n",  		       i2c_client->addr);  		return -ENODEV; @@ -670,17 +703,9 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,  	dev_info(&i2c_client->dev, "found device at i2c address %X\n",  		i2c_client->addr); -	dev_info(&i2c_client->dev, "hardware revision %X\n", ret & 0xF); - -	cs4270 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs4270_private), -			      GFP_KERNEL); -	if (!cs4270) { -		dev_err(&i2c_client->dev, "could not allocate codec\n"); -		return -ENOMEM; -	} +	dev_info(&i2c_client->dev, "hardware revision %X\n", val & 0xF);  	i2c_set_clientdata(i2c_client, cs4270); -	cs4270->control_type = SND_SOC_I2C;  	ret = snd_soc_register_codec(&i2c_client->dev,  			&soc_codec_device_cs4270, &cs4270_dai, 1); @@ -718,23 +743,14 @@ static struct i2c_driver cs4270_i2c_driver = {  	.driver = {  		.name = "cs4270",  		.owner = THIS_MODULE, +		.of_match_table = cs4270_of_match,  	},  	.id_table = cs4270_id,  	.probe = cs4270_i2c_probe,  	.remove = cs4270_i2c_remove,  }; -static int __init cs4270_init(void) -{ -	return i2c_add_driver(&cs4270_i2c_driver); -} -module_init(cs4270_init); - -static void __exit cs4270_exit(void) -{ -	i2c_del_driver(&cs4270_i2c_driver); -} -module_exit(cs4270_exit); +module_i2c_driver(cs4270_i2c_driver);  MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");  MODULE_DESCRIPTION("Cirrus Logic CS4270 ALSA SoC Codec Driver"); diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index 9eb01d7d58a..f994af34f55 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -22,12 +22,14 @@  #include <linux/module.h>  #include <linux/slab.h>  #include <linux/delay.h> -#include <sound/pcm.h> -#include <sound/soc.h> -#include <sound/tlv.h>  #include <linux/gpio.h>  #include <linux/i2c.h>  #include <linux/spi/spi.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> +#include <sound/pcm.h> +#include <sound/soc.h> +#include <sound/tlv.h>  #include <sound/cs4271.h>  #define CS4271_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ @@ -458,6 +460,14 @@ static int cs4271_soc_resume(struct snd_soc_codec *codec)  #define cs4271_soc_resume	NULL  #endif /* CONFIG_PM */ +#ifdef CONFIG_OF +static const struct of_device_id cs4271_dt_ids[] = { +	{ .compatible = "cirrus,cs4271", }, +	{ } +}; +MODULE_DEVICE_TABLE(of, cs4271_dt_ids); +#endif +  static int cs4271_probe(struct snd_soc_codec *codec)  {  	struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); @@ -465,6 +475,12 @@ static int cs4271_probe(struct snd_soc_codec *codec)  	int ret;  	int gpio_nreset = -EINVAL; +#ifdef CONFIG_OF +	if (of_match_device(cs4271_dt_ids, codec->dev)) +		gpio_nreset = of_get_named_gpio(codec->dev->of_node, +						"reset-gpio", 0); +#endif +  	if (cs4271plat && gpio_is_valid(cs4271plat->gpio_nreset))  		gpio_nreset = cs4271plat->gpio_nreset; @@ -569,6 +585,7 @@ static struct spi_driver cs4271_spi_driver = {  	.driver = {  		.name	= "cs4271",  		.owner	= THIS_MODULE, +		.of_match_table = of_match_ptr(cs4271_dt_ids),  	},  	.probe		= cs4271_spi_probe,  	.remove		= __devexit_p(cs4271_spi_remove), @@ -608,6 +625,7 @@ static struct i2c_driver cs4271_i2c_driver = {  	.driver = {  		.name	= "cs4271",  		.owner	= THIS_MODULE, +		.of_match_table = of_match_ptr(cs4271_dt_ids),  	},  	.id_table	= cs4271_i2c_id,  	.probe		= cs4271_i2c_probe, diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index 091d0193f50..1e0fa3b5f79 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c @@ -614,24 +614,7 @@ static struct i2c_driver cs42l51_i2c_driver = {  	.remove = cs42l51_i2c_remove,  }; -static int __init cs42l51_init(void) -{ -	int ret; - -	ret = i2c_add_driver(&cs42l51_i2c_driver); -	if (ret != 0) { -		printk(KERN_ERR "%s: can't add i2c driver\n", __func__); -		return ret; -	} -	return 0; -} -module_init(cs42l51_init); - -static void __exit cs42l51_exit(void) -{ -	i2c_del_driver(&cs42l51_i2c_driver); -} -module_exit(cs42l51_exit); +module_i2c_driver(cs42l51_i2c_driver);  MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");  MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver"); diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 628daf6a1d9..61599298fb2 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -24,7 +24,6 @@  #include <linux/slab.h>  #include <linux/workqueue.h>  #include <linux/platform_device.h> -#include <linux/slab.h>  #include <sound/core.h>  #include <sound/pcm.h>  #include <sound/pcm_params.h> diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c new file mode 100644 index 00000000000..185d8dd3639 --- /dev/null +++ b/sound/soc/codecs/da9055.c @@ -0,0 +1,1510 @@ +/* + * DA9055 ALSA Soc codec driver + * + * Copyright (c) 2012 Dialog Semiconductor + * + * Tested on (Samsung SMDK6410 board + DA9055 EVB) using I2S and I2C + * Written by David Chen <david.chen@diasemi.com> and + * Ashish Chavan <ashish.chavan@kpitcummins.com> + * + * 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. + */ + +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/initval.h> +#include <sound/tlv.h> +#include <sound/da9055.h> + +/* DA9055 register space */ + +/* Status Registers */ +#define DA9055_STATUS1			0x02 +#define DA9055_PLL_STATUS		0x03 +#define DA9055_AUX_L_GAIN_STATUS	0x04 +#define DA9055_AUX_R_GAIN_STATUS	0x05 +#define DA9055_MIC_L_GAIN_STATUS	0x06 +#define DA9055_MIC_R_GAIN_STATUS	0x07 +#define DA9055_MIXIN_L_GAIN_STATUS	0x08 +#define DA9055_MIXIN_R_GAIN_STATUS	0x09 +#define DA9055_ADC_L_GAIN_STATUS	0x0A +#define DA9055_ADC_R_GAIN_STATUS	0x0B +#define DA9055_DAC_L_GAIN_STATUS	0x0C +#define DA9055_DAC_R_GAIN_STATUS	0x0D +#define DA9055_HP_L_GAIN_STATUS		0x0E +#define DA9055_HP_R_GAIN_STATUS		0x0F +#define DA9055_LINE_GAIN_STATUS		0x10 + +/* System Initialisation Registers */ +#define DA9055_CIF_CTRL			0x20 +#define DA9055_DIG_ROUTING_AIF		0X21 +#define DA9055_SR			0x22 +#define DA9055_REFERENCES		0x23 +#define DA9055_PLL_FRAC_TOP		0x24 +#define DA9055_PLL_FRAC_BOT		0x25 +#define DA9055_PLL_INTEGER		0x26 +#define DA9055_PLL_CTRL			0x27 +#define DA9055_AIF_CLK_MODE		0x28 +#define DA9055_AIF_CTRL			0x29 +#define DA9055_DIG_ROUTING_DAC		0x2A +#define DA9055_ALC_CTRL1		0x2B + +/* Input - Gain, Select and Filter Registers */ +#define DA9055_AUX_L_GAIN		0x30 +#define DA9055_AUX_R_GAIN		0x31 +#define DA9055_MIXIN_L_SELECT		0x32 +#define DA9055_MIXIN_R_SELECT		0x33 +#define DA9055_MIXIN_L_GAIN		0x34 +#define DA9055_MIXIN_R_GAIN		0x35 +#define DA9055_ADC_L_GAIN		0x36 +#define DA9055_ADC_R_GAIN		0x37 +#define DA9055_ADC_FILTERS1		0x38 +#define DA9055_MIC_L_GAIN		0x39 +#define DA9055_MIC_R_GAIN		0x3A + +/* Output - Gain, Select and Filter Registers */ +#define DA9055_DAC_FILTERS5		0x40 +#define DA9055_DAC_FILTERS2		0x41 +#define DA9055_DAC_FILTERS3		0x42 +#define DA9055_DAC_FILTERS4		0x43 +#define DA9055_DAC_FILTERS1		0x44 +#define DA9055_DAC_L_GAIN		0x45 +#define DA9055_DAC_R_GAIN		0x46 +#define DA9055_CP_CTRL			0x47 +#define DA9055_HP_L_GAIN		0x48 +#define DA9055_HP_R_GAIN		0x49 +#define DA9055_LINE_GAIN		0x4A +#define DA9055_MIXOUT_L_SELECT		0x4B +#define DA9055_MIXOUT_R_SELECT		0x4C + +/* System Controller Registers */ +#define DA9055_SYSTEM_MODES_INPUT	0x50 +#define DA9055_SYSTEM_MODES_OUTPUT	0x51 + +/* Control Registers */ +#define DA9055_AUX_L_CTRL		0x60 +#define DA9055_AUX_R_CTRL		0x61 +#define DA9055_MIC_BIAS_CTRL		0x62 +#define DA9055_MIC_L_CTRL		0x63 +#define DA9055_MIC_R_CTRL		0x64 +#define DA9055_MIXIN_L_CTRL		0x65 +#define DA9055_MIXIN_R_CTRL		0x66 +#define DA9055_ADC_L_CTRL		0x67 +#define DA9055_ADC_R_CTRL		0x68 +#define DA9055_DAC_L_CTRL		0x69 +#define DA9055_DAC_R_CTRL		0x6A +#define DA9055_HP_L_CTRL		0x6B +#define DA9055_HP_R_CTRL		0x6C +#define DA9055_LINE_CTRL		0x6D +#define DA9055_MIXOUT_L_CTRL		0x6E +#define DA9055_MIXOUT_R_CTRL		0x6F + +/* Configuration Registers */ +#define DA9055_LDO_CTRL			0x90 +#define DA9055_IO_CTRL			0x91 +#define DA9055_GAIN_RAMP_CTRL		0x92 +#define DA9055_MIC_CONFIG		0x93 +#define DA9055_PC_COUNT			0x94 +#define DA9055_CP_VOL_THRESHOLD1	0x95 +#define DA9055_CP_DELAY			0x96 +#define DA9055_CP_DETECTOR		0x97 +#define DA9055_AIF_OFFSET		0x98 +#define DA9055_DIG_CTRL			0x99 +#define DA9055_ALC_CTRL2		0x9A +#define DA9055_ALC_CTRL3		0x9B +#define DA9055_ALC_NOISE		0x9C +#define DA9055_ALC_TARGET_MIN		0x9D +#define DA9055_ALC_TARGET_MAX		0x9E +#define DA9055_ALC_GAIN_LIMITS		0x9F +#define DA9055_ALC_ANA_GAIN_LIMITS	0xA0 +#define DA9055_ALC_ANTICLIP_CTRL	0xA1 +#define DA9055_ALC_ANTICLIP_LEVEL	0xA2 +#define DA9055_ALC_OFFSET_OP2M_L	0xA6 +#define DA9055_ALC_OFFSET_OP2U_L	0xA7 +#define DA9055_ALC_OFFSET_OP2M_R	0xAB +#define DA9055_ALC_OFFSET_OP2U_R	0xAC +#define DA9055_ALC_CIC_OP_LVL_CTRL	0xAD +#define DA9055_ALC_CIC_OP_LVL_DATA	0xAE +#define DA9055_DAC_NG_SETUP_TIME	0xAF +#define DA9055_DAC_NG_OFF_THRESHOLD	0xB0 +#define DA9055_DAC_NG_ON_THRESHOLD	0xB1 +#define DA9055_DAC_NG_CTRL		0xB2 + +/* SR bit fields */ +#define DA9055_SR_8000			(0x1 << 0) +#define DA9055_SR_11025			(0x2 << 0) +#define DA9055_SR_12000			(0x3 << 0) +#define DA9055_SR_16000			(0x5 << 0) +#define DA9055_SR_22050			(0x6 << 0) +#define DA9055_SR_24000			(0x7 << 0) +#define DA9055_SR_32000			(0x9 << 0) +#define DA9055_SR_44100			(0xA << 0) +#define DA9055_SR_48000			(0xB << 0) +#define DA9055_SR_88200			(0xE << 0) +#define DA9055_SR_96000			(0xF << 0) + +/* REFERENCES bit fields */ +#define DA9055_BIAS_EN			(1 << 3) +#define DA9055_VMID_EN			(1 << 7) + +/* PLL_CTRL bit fields */ +#define DA9055_PLL_INDIV_10_20_MHZ	(1 << 2) +#define DA9055_PLL_SRM_EN		(1 << 6) +#define DA9055_PLL_EN			(1 << 7) + +/* AIF_CLK_MODE bit fields */ +#define DA9055_AIF_BCLKS_PER_WCLK_32	(0 << 0) +#define DA9055_AIF_BCLKS_PER_WCLK_64	(1 << 0) +#define DA9055_AIF_BCLKS_PER_WCLK_128	(2 << 0) +#define DA9055_AIF_BCLKS_PER_WCLK_256	(3 << 0) +#define DA9055_AIF_CLK_EN_SLAVE_MODE	(0 << 7) +#define DA9055_AIF_CLK_EN_MASTER_MODE	(1 << 7) + +/* AIF_CTRL bit fields */ +#define DA9055_AIF_FORMAT_I2S_MODE	(0 << 0) +#define DA9055_AIF_FORMAT_LEFT_J	(1 << 0) +#define DA9055_AIF_FORMAT_RIGHT_J	(2 << 0) +#define DA9055_AIF_WORD_S16_LE		(0 << 2) +#define DA9055_AIF_WORD_S20_3LE		(1 << 2) +#define DA9055_AIF_WORD_S24_LE		(2 << 2) +#define DA9055_AIF_WORD_S32_LE		(3 << 2) + +/* MIXIN_L_CTRL bit fields */ +#define DA9055_MIXIN_L_MIX_EN		(1 << 3) + +/* MIXIN_R_CTRL bit fields */ +#define DA9055_MIXIN_R_MIX_EN		(1 << 3) + +/* ADC_L_CTRL bit fields */ +#define DA9055_ADC_L_EN			(1 << 7) + +/* ADC_R_CTRL bit fields */ +#define DA9055_ADC_R_EN			(1 << 7) + +/* DAC_L_CTRL bit fields */ +#define DA9055_DAC_L_MUTE_EN		(1 << 6) + +/* DAC_R_CTRL bit fields */ +#define DA9055_DAC_R_MUTE_EN		(1 << 6) + +/* HP_L_CTRL bit fields */ +#define DA9055_HP_L_AMP_OE		(1 << 3) + +/* HP_R_CTRL bit fields */ +#define DA9055_HP_R_AMP_OE		(1 << 3) + +/* LINE_CTRL bit fields */ +#define DA9055_LINE_AMP_OE		(1 << 3) + +/* MIXOUT_L_CTRL bit fields */ +#define DA9055_MIXOUT_L_MIX_EN		(1 << 3) + +/* MIXOUT_R_CTRL bit fields */ +#define DA9055_MIXOUT_R_MIX_EN		(1 << 3) + +/* MIC bias select bit fields */ +#define DA9055_MICBIAS2_EN		(1 << 6) + +/* ALC_CIC_OP_LEVEL_CTRL bit fields */ +#define DA9055_ALC_DATA_MIDDLE		(2 << 0) +#define DA9055_ALC_DATA_TOP		(3 << 0) +#define DA9055_ALC_CIC_OP_CHANNEL_LEFT	(0 << 7) +#define DA9055_ALC_CIC_OP_CHANNEL_RIGHT	(1 << 7) + +#define DA9055_AIF_BCLK_MASK		(3 << 0) +#define DA9055_AIF_CLK_MODE_MASK	(1 << 7) +#define DA9055_AIF_FORMAT_MASK		(3 << 0) +#define DA9055_AIF_WORD_LENGTH_MASK	(3 << 2) +#define DA9055_GAIN_RAMPING_EN		(1 << 5) +#define DA9055_MICBIAS_LEVEL_MASK	(3 << 4) + +#define DA9055_ALC_OFFSET_15_8		0x00FF00 +#define DA9055_ALC_OFFSET_17_16		0x030000 +#define DA9055_ALC_AVG_ITERATIONS	5 + +struct pll_div { +	int fref; +	int fout; +	u8 frac_top; +	u8 frac_bot; +	u8 integer; +	u8 mode;	/* 0 = slave, 1 = master */ +}; + +/* PLL divisor table */ +static const struct pll_div da9055_pll_div[] = { +	/* for MASTER mode, fs = 44.1Khz and its harmonics */ +	{11289600, 2822400, 0x00, 0x00, 0x20, 1},	/* MCLK=11.2896Mhz */ +	{12000000, 2822400, 0x03, 0x61, 0x1E, 1},	/* MCLK=12Mhz */ +	{12288000, 2822400, 0x0C, 0xCC, 0x1D, 1},	/* MCLK=12.288Mhz */ +	{13000000, 2822400, 0x19, 0x45, 0x1B, 1},	/* MCLK=13Mhz */ +	{13500000, 2822400, 0x18, 0x56, 0x1A, 1},	/* MCLK=13.5Mhz */ +	{14400000, 2822400, 0x02, 0xD0, 0x19, 1},	/* MCLK=14.4Mhz */ +	{19200000, 2822400, 0x1A, 0x1C, 0x12, 1},	/* MCLK=19.2Mhz */ +	{19680000, 2822400, 0x0B, 0x6D, 0x12, 1},	/* MCLK=19.68Mhz */ +	{19800000, 2822400, 0x07, 0xDD, 0x12, 1},	/* MCLK=19.8Mhz */ +	/* for MASTER mode, fs = 48Khz and its harmonics */ +	{11289600, 3072000, 0x1A, 0x8E, 0x22, 1},	/* MCLK=11.2896Mhz */ +	{12000000, 3072000, 0x18, 0x93, 0x20, 1},	/* MCLK=12Mhz */ +	{12288000, 3072000, 0x00, 0x00, 0x20, 1},	/* MCLK=12.288Mhz */ +	{13000000, 3072000, 0x07, 0xEA, 0x1E, 1},	/* MCLK=13Mhz */ +	{13500000, 3072000, 0x04, 0x11, 0x1D, 1},	/* MCLK=13.5Mhz */ +	{14400000, 3072000, 0x09, 0xD0, 0x1B, 1},	/* MCLK=14.4Mhz */ +	{19200000, 3072000, 0x0F, 0x5C, 0x14, 1},	/* MCLK=19.2Mhz */ +	{19680000, 3072000, 0x1F, 0x60, 0x13, 1},	/* MCLK=19.68Mhz */ +	{19800000, 3072000, 0x1B, 0x80, 0x13, 1},	/* MCLK=19.8Mhz */ +	/* for SLAVE mode with SRM */ +	{11289600, 2822400, 0x0D, 0x47, 0x21, 0},	/* MCLK=11.2896Mhz */ +	{12000000, 2822400, 0x0D, 0xFA, 0x1F, 0},	/* MCLK=12Mhz */ +	{12288000, 2822400, 0x16, 0x66, 0x1E, 0},	/* MCLK=12.288Mhz */ +	{13000000, 2822400, 0x00, 0x98, 0x1D, 0},	/* MCLK=13Mhz */ +	{13500000, 2822400, 0x1E, 0x33, 0x1B, 0},	/* MCLK=13.5Mhz */ +	{14400000, 2822400, 0x06, 0x50, 0x1A, 0},	/* MCLK=14.4Mhz */ +	{19200000, 2822400, 0x14, 0xBC, 0x13, 0},	/* MCLK=19.2Mhz */ +	{19680000, 2822400, 0x05, 0x66, 0x13, 0},	/* MCLK=19.68Mhz */ +	{19800000, 2822400, 0x01, 0xAE, 0x13, 0},	/* MCLK=19.8Mhz  */ +}; + +enum clk_src { +	DA9055_CLKSRC_MCLK +}; + +/* Gain and Volume */ + +static const unsigned int aux_vol_tlv[] = { +	TLV_DB_RANGE_HEAD(2), +	0x0, 0x10, TLV_DB_SCALE_ITEM(-5400, 0, 0), +	/* -54dB to 15dB */ +	0x11, 0x3f, TLV_DB_SCALE_ITEM(-5400, 150, 0) +}; + +static const unsigned int digital_gain_tlv[] = { +	TLV_DB_RANGE_HEAD(2), +	0x0, 0x07, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), +	/* -78dB to 12dB */ +	0x08, 0x7f, TLV_DB_SCALE_ITEM(-7800, 75, 0) +}; + +static const unsigned int alc_analog_gain_tlv[] = { +	TLV_DB_RANGE_HEAD(2), +	0x0, 0x0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), +	/* 0dB to 36dB */ +	0x01, 0x07, TLV_DB_SCALE_ITEM(0, 600, 0) +}; + +static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, -600, 600, 0); +static const DECLARE_TLV_DB_SCALE(mixin_gain_tlv, -450, 150, 0); +static const DECLARE_TLV_DB_SCALE(eq_gain_tlv, -1050, 150, 0); +static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -5700, 100, 0); +static const DECLARE_TLV_DB_SCALE(lineout_vol_tlv, -4800, 100, 0); +static const DECLARE_TLV_DB_SCALE(alc_threshold_tlv, -9450, 150, 0); +static const DECLARE_TLV_DB_SCALE(alc_gain_tlv, 0, 600, 0); + +/* ADC and DAC high pass filter cutoff value */ +static const char * const da9055_hpf_cutoff_txt[] = { +	"Fs/24000", "Fs/12000", "Fs/6000", "Fs/3000" +}; + +static const struct soc_enum da9055_dac_hpf_cutoff = +	SOC_ENUM_SINGLE(DA9055_DAC_FILTERS1, 4, 4, da9055_hpf_cutoff_txt); + +static const struct soc_enum da9055_adc_hpf_cutoff = +	SOC_ENUM_SINGLE(DA9055_ADC_FILTERS1, 4, 4, da9055_hpf_cutoff_txt); + +/* ADC and DAC voice mode (8kHz) high pass cutoff value */ +static const char * const da9055_vf_cutoff_txt[] = { +	"2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz" +}; + +static const struct soc_enum da9055_dac_vf_cutoff = +	SOC_ENUM_SINGLE(DA9055_DAC_FILTERS1, 0, 8, da9055_vf_cutoff_txt); + +static const struct soc_enum da9055_adc_vf_cutoff = +	SOC_ENUM_SINGLE(DA9055_ADC_FILTERS1, 0, 8, da9055_vf_cutoff_txt); + +/* Gain ramping rate value */ +static const char * const da9055_gain_ramping_txt[] = { +	"nominal rate", "nominal rate * 4", "nominal rate * 8", +	"nominal rate / 8" +}; + +static const struct soc_enum da9055_gain_ramping_rate = +	SOC_ENUM_SINGLE(DA9055_GAIN_RAMP_CTRL, 0, 4, da9055_gain_ramping_txt); + +/* DAC noise gate setup time value */ +static const char * const da9055_dac_ng_setup_time_txt[] = { +	"256 samples", "512 samples", "1024 samples", "2048 samples" +}; + +static const struct soc_enum da9055_dac_ng_setup_time = +	SOC_ENUM_SINGLE(DA9055_DAC_NG_SETUP_TIME, 0, 4, +			da9055_dac_ng_setup_time_txt); + +/* DAC noise gate rampup rate value */ +static const char * const da9055_dac_ng_rampup_txt[] = { +	"0.02 ms/dB", "0.16 ms/dB" +}; + +static const struct soc_enum da9055_dac_ng_rampup_rate = +	SOC_ENUM_SINGLE(DA9055_DAC_NG_SETUP_TIME, 2, 2, +			da9055_dac_ng_rampup_txt); + +/* DAC noise gate rampdown rate value */ +static const char * const da9055_dac_ng_rampdown_txt[] = { +	"0.64 ms/dB", "20.48 ms/dB" +}; + +static const struct soc_enum da9055_dac_ng_rampdown_rate = +	SOC_ENUM_SINGLE(DA9055_DAC_NG_SETUP_TIME, 3, 2, +			da9055_dac_ng_rampdown_txt); + +/* DAC soft mute rate value */ +static const char * const da9055_dac_soft_mute_rate_txt[] = { +	"1", "2", "4", "8", "16", "32", "64" +}; + +static const struct soc_enum da9055_dac_soft_mute_rate = +	SOC_ENUM_SINGLE(DA9055_DAC_FILTERS5, 4, 7, +			da9055_dac_soft_mute_rate_txt); + +/* DAC routing select */ +static const char * const da9055_dac_src_txt[] = { +	"ADC output left", "ADC output right", "AIF input left", +	"AIF input right" +}; + +static const struct soc_enum da9055_dac_l_src = +	SOC_ENUM_SINGLE(DA9055_DIG_ROUTING_DAC, 0, 4, da9055_dac_src_txt); + +static const struct soc_enum da9055_dac_r_src = +	SOC_ENUM_SINGLE(DA9055_DIG_ROUTING_DAC, 4, 4, da9055_dac_src_txt); + +/* MIC PGA Left source select */ +static const char * const da9055_mic_l_src_txt[] = { +	"MIC1_P_N", "MIC1_P", "MIC1_N", "MIC2_L" +}; + +static const struct soc_enum da9055_mic_l_src = +	SOC_ENUM_SINGLE(DA9055_MIXIN_L_SELECT, 4, 4, da9055_mic_l_src_txt); + +/* MIC PGA Right source select */ +static const char * const da9055_mic_r_src_txt[] = { +	"MIC2_R_L", "MIC2_R", "MIC2_L" +}; + +static const struct soc_enum da9055_mic_r_src = +	SOC_ENUM_SINGLE(DA9055_MIXIN_R_SELECT, 4, 3, da9055_mic_r_src_txt); + +/* ALC Input Signal Tracking rate select */ +static const char * const da9055_signal_tracking_rate_txt[] = { +	"1/4", "1/16", "1/256", "1/65536" +}; + +static const struct soc_enum da9055_integ_attack_rate = +	SOC_ENUM_SINGLE(DA9055_ALC_CTRL3, 4, 4, +			da9055_signal_tracking_rate_txt); + +static const struct soc_enum da9055_integ_release_rate = +	SOC_ENUM_SINGLE(DA9055_ALC_CTRL3, 6, 4, +			da9055_signal_tracking_rate_txt); + +/* ALC Attack Rate select */ +static const char * const da9055_attack_rate_txt[] = { +	"44/fs", "88/fs", "176/fs", "352/fs", "704/fs", "1408/fs", "2816/fs", +	"5632/fs", "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs" +}; + +static const struct soc_enum da9055_attack_rate = +	SOC_ENUM_SINGLE(DA9055_ALC_CTRL2, 0, 13, da9055_attack_rate_txt); + +/* ALC Release Rate select */ +static const char * const da9055_release_rate_txt[] = { +	"176/fs", "352/fs", "704/fs", "1408/fs", "2816/fs", "5632/fs", +	"11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs" +}; + +static const struct soc_enum da9055_release_rate = +	SOC_ENUM_SINGLE(DA9055_ALC_CTRL2, 4, 11, da9055_release_rate_txt); + +/* ALC Hold Time select */ +static const char * const da9055_hold_time_txt[] = { +	"62/fs", "124/fs", "248/fs", "496/fs", "992/fs", "1984/fs", "3968/fs", +	"7936/fs", "15872/fs", "31744/fs", "63488/fs", "126976/fs", +	"253952/fs", "507904/fs", "1015808/fs", "2031616/fs" +}; + +static const struct soc_enum da9055_hold_time = +	SOC_ENUM_SINGLE(DA9055_ALC_CTRL3, 0, 16, da9055_hold_time_txt); + +static int da9055_get_alc_data(struct snd_soc_codec *codec, u8 reg_val) +{ +	int mid_data, top_data; +	int sum = 0; +	u8 iteration; + +	for (iteration = 0; iteration < DA9055_ALC_AVG_ITERATIONS; +	     iteration++) { +		/* Select the left or right channel and capture data */ +		snd_soc_write(codec, DA9055_ALC_CIC_OP_LVL_CTRL, reg_val); + +		/* Select middle 8 bits for read back from data register */ +		snd_soc_write(codec, DA9055_ALC_CIC_OP_LVL_CTRL, +			      reg_val | DA9055_ALC_DATA_MIDDLE); +		mid_data = snd_soc_read(codec, DA9055_ALC_CIC_OP_LVL_DATA); + +		/* Select top 8 bits for read back from data register */ +		snd_soc_write(codec, DA9055_ALC_CIC_OP_LVL_CTRL, +			      reg_val | DA9055_ALC_DATA_TOP); +		top_data = snd_soc_read(codec, DA9055_ALC_CIC_OP_LVL_DATA); + +		sum += ((mid_data << 8) | (top_data << 16)); +	} + +	return sum / DA9055_ALC_AVG_ITERATIONS; +} + +static int da9055_put_alc_sw(struct snd_kcontrol *kcontrol, +			     struct snd_ctl_elem_value *ucontrol) +{ +	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); +	u8 reg_val, adc_left, adc_right; +	int avg_left_data, avg_right_data, offset_l, offset_r; + +	if (ucontrol->value.integer.value[0]) { +		/* +		 * While enabling ALC (or ALC sync mode), calibration of the DC +		 * offsets must be done first +		 */ + +		/* Save current values from ADC control registers */ +		adc_left = snd_soc_read(codec, DA9055_ADC_L_CTRL); +		adc_right = snd_soc_read(codec, DA9055_ADC_R_CTRL); + +		/* Enable ADC Left and Right */ +		snd_soc_update_bits(codec, DA9055_ADC_L_CTRL, +				    DA9055_ADC_L_EN, DA9055_ADC_L_EN); +		snd_soc_update_bits(codec, DA9055_ADC_R_CTRL, +				    DA9055_ADC_R_EN, DA9055_ADC_R_EN); + +		/* Calculate average for Left and Right data */ +		/* Left Data */ +		avg_left_data = da9055_get_alc_data(codec, +				DA9055_ALC_CIC_OP_CHANNEL_LEFT); +		/* Right Data */ +		avg_right_data = da9055_get_alc_data(codec, +				 DA9055_ALC_CIC_OP_CHANNEL_RIGHT); + +		/* Calculate DC offset */ +		offset_l = -avg_left_data; +		offset_r = -avg_right_data; + +		reg_val = (offset_l & DA9055_ALC_OFFSET_15_8) >> 8; +		snd_soc_write(codec, DA9055_ALC_OFFSET_OP2M_L, reg_val); +		reg_val = (offset_l & DA9055_ALC_OFFSET_17_16) >> 16; +		snd_soc_write(codec, DA9055_ALC_OFFSET_OP2U_L, reg_val); + +		reg_val = (offset_r & DA9055_ALC_OFFSET_15_8) >> 8; +		snd_soc_write(codec, DA9055_ALC_OFFSET_OP2M_R, reg_val); +		reg_val = (offset_r & DA9055_ALC_OFFSET_17_16) >> 16; +		snd_soc_write(codec, DA9055_ALC_OFFSET_OP2U_R, reg_val); + +		/* Restore original values of ADC control registers */ +		snd_soc_write(codec, DA9055_ADC_L_CTRL, adc_left); +		snd_soc_write(codec, DA9055_ADC_R_CTRL, adc_right); +	} + +	return snd_soc_put_volsw(kcontrol, ucontrol); +} + +static const struct snd_kcontrol_new da9055_snd_controls[] = { + +	/* Volume controls */ +	SOC_DOUBLE_R_TLV("Mic Volume", +			 DA9055_MIC_L_GAIN, DA9055_MIC_R_GAIN, +			 0, 0x7, 0, mic_vol_tlv), +	SOC_DOUBLE_R_TLV("Aux Volume", +			 DA9055_AUX_L_GAIN, DA9055_AUX_R_GAIN, +			 0, 0x3f, 0, aux_vol_tlv), +	SOC_DOUBLE_R_TLV("Mixin PGA Volume", +			 DA9055_MIXIN_L_GAIN, DA9055_MIXIN_R_GAIN, +			 0, 0xf, 0, mixin_gain_tlv), +	SOC_DOUBLE_R_TLV("ADC Volume", +			 DA9055_ADC_L_GAIN, DA9055_ADC_R_GAIN, +			 0, 0x7f, 0, digital_gain_tlv), + +	SOC_DOUBLE_R_TLV("DAC Volume", +			 DA9055_DAC_L_GAIN, DA9055_DAC_R_GAIN, +			 0, 0x7f, 0, digital_gain_tlv), +	SOC_DOUBLE_R_TLV("Headphone Volume", +			 DA9055_HP_L_GAIN, DA9055_HP_R_GAIN, +			 0, 0x3f, 0, hp_vol_tlv), +	SOC_SINGLE_TLV("Lineout Volume", DA9055_LINE_GAIN, 0, 0x3f, 0, +		       lineout_vol_tlv), + +	/* DAC Equalizer controls */ +	SOC_SINGLE("DAC EQ Switch", DA9055_DAC_FILTERS4, 7, 1, 0), +	SOC_SINGLE_TLV("DAC EQ1 Volume", DA9055_DAC_FILTERS2, 0, 0xf, 0, +		       eq_gain_tlv), +	SOC_SINGLE_TLV("DAC EQ2 Volume", DA9055_DAC_FILTERS2, 4, 0xf, 0, +		       eq_gain_tlv), +	SOC_SINGLE_TLV("DAC EQ3 Volume", DA9055_DAC_FILTERS3, 0, 0xf, 0, +		       eq_gain_tlv), +	SOC_SINGLE_TLV("DAC EQ4 Volume", DA9055_DAC_FILTERS3, 4, 0xf, 0, +		       eq_gain_tlv), +	SOC_SINGLE_TLV("DAC EQ5 Volume", DA9055_DAC_FILTERS4, 0, 0xf, 0, +		       eq_gain_tlv), + +	/* High Pass Filter and Voice Mode controls */ +	SOC_SINGLE("ADC HPF Switch", DA9055_ADC_FILTERS1, 7, 1, 0), +	SOC_ENUM("ADC HPF Cutoff", da9055_adc_hpf_cutoff), +	SOC_SINGLE("ADC Voice Mode Switch", DA9055_ADC_FILTERS1, 3, 1, 0), +	SOC_ENUM("ADC Voice Cutoff", da9055_adc_vf_cutoff), + +	SOC_SINGLE("DAC HPF Switch", DA9055_DAC_FILTERS1, 7, 1, 0), +	SOC_ENUM("DAC HPF Cutoff", da9055_dac_hpf_cutoff), +	SOC_SINGLE("DAC Voice Mode Switch", DA9055_DAC_FILTERS1, 3, 1, 0), +	SOC_ENUM("DAC Voice Cutoff", da9055_dac_vf_cutoff), + +	/* Mute controls */ +	SOC_DOUBLE_R("Mic Switch", DA9055_MIC_L_CTRL, +		     DA9055_MIC_R_CTRL, 6, 1, 0), +	SOC_DOUBLE_R("Aux Switch", DA9055_AUX_L_CTRL, +		     DA9055_AUX_R_CTRL, 6, 1, 0), +	SOC_DOUBLE_R("Mixin PGA Switch", DA9055_MIXIN_L_CTRL, +		     DA9055_MIXIN_R_CTRL, 6, 1, 0), +	SOC_DOUBLE_R("ADC Switch", DA9055_ADC_L_CTRL, +		     DA9055_ADC_R_CTRL, 6, 1, 0), +	SOC_DOUBLE_R("Headphone Switch", DA9055_HP_L_CTRL, +		     DA9055_HP_R_CTRL, 6, 1, 0), +	SOC_SINGLE("Lineout Switch", DA9055_LINE_CTRL, 6, 1, 0), +	SOC_SINGLE("DAC Soft Mute Switch", DA9055_DAC_FILTERS5, 7, 1, 0), +	SOC_ENUM("DAC Soft Mute Rate", da9055_dac_soft_mute_rate), + +	/* Zero Cross controls */ +	SOC_DOUBLE_R("Aux ZC Switch", DA9055_AUX_L_CTRL, +		     DA9055_AUX_R_CTRL, 4, 1, 0), +	SOC_DOUBLE_R("Mixin PGA ZC Switch", DA9055_MIXIN_L_CTRL, +		     DA9055_MIXIN_R_CTRL, 4, 1, 0), +	SOC_DOUBLE_R("Headphone ZC Switch", DA9055_HP_L_CTRL, +		     DA9055_HP_R_CTRL, 4, 1, 0), +	SOC_SINGLE("Lineout ZC Switch", DA9055_LINE_CTRL, 4, 1, 0), + +	/* Gain Ramping controls */ +	SOC_DOUBLE_R("Aux Gain Ramping Switch", DA9055_AUX_L_CTRL, +		     DA9055_AUX_R_CTRL, 5, 1, 0), +	SOC_DOUBLE_R("Mixin Gain Ramping Switch", DA9055_MIXIN_L_CTRL, +		     DA9055_MIXIN_R_CTRL, 5, 1, 0), +	SOC_DOUBLE_R("ADC Gain Ramping Switch", DA9055_ADC_L_CTRL, +		     DA9055_ADC_R_CTRL, 5, 1, 0), +	SOC_DOUBLE_R("DAC Gain Ramping Switch", DA9055_DAC_L_CTRL, +		     DA9055_DAC_R_CTRL, 5, 1, 0), +	SOC_DOUBLE_R("Headphone Gain Ramping Switch", DA9055_HP_L_CTRL, +		     DA9055_HP_R_CTRL, 5, 1, 0), +	SOC_SINGLE("Lineout Gain Ramping Switch", DA9055_LINE_CTRL, 5, 1, 0), +	SOC_ENUM("Gain Ramping Rate", da9055_gain_ramping_rate), + +	/* DAC Noise Gate controls */ +	SOC_SINGLE("DAC NG Switch", DA9055_DAC_NG_CTRL, 7, 1, 0), +	SOC_SINGLE("DAC NG ON Threshold", DA9055_DAC_NG_ON_THRESHOLD, +		   0, 0x7, 0), +	SOC_SINGLE("DAC NG OFF Threshold", DA9055_DAC_NG_OFF_THRESHOLD, +		   0, 0x7, 0), +	SOC_ENUM("DAC NG Setup Time", da9055_dac_ng_setup_time), +	SOC_ENUM("DAC NG Rampup Rate", da9055_dac_ng_rampup_rate), +	SOC_ENUM("DAC NG Rampdown Rate", da9055_dac_ng_rampdown_rate), + +	/* DAC Invertion control */ +	SOC_SINGLE("DAC Left Invert", DA9055_DIG_CTRL, 3, 1, 0), +	SOC_SINGLE("DAC Right Invert", DA9055_DIG_CTRL, 7, 1, 0), + +	/* DMIC controls */ +	SOC_DOUBLE_R("DMIC Switch", DA9055_MIXIN_L_SELECT, +		     DA9055_MIXIN_R_SELECT, 7, 1, 0), + +	/* ALC Controls */ +	SOC_DOUBLE_EXT("ALC Switch", DA9055_ALC_CTRL1, 3, 7, 1, 0, +		       snd_soc_get_volsw, da9055_put_alc_sw), +	SOC_SINGLE_EXT("ALC Sync Mode Switch", DA9055_ALC_CTRL1, 1, 1, 0, +		       snd_soc_get_volsw, da9055_put_alc_sw), +	SOC_SINGLE("ALC Offset Switch", DA9055_ALC_CTRL1, 0, 1, 0), +	SOC_SINGLE("ALC Anticlip Mode Switch", DA9055_ALC_ANTICLIP_CTRL, +		   7, 1, 0), +	SOC_SINGLE("ALC Anticlip Level", DA9055_ALC_ANTICLIP_LEVEL, +		   0, 0x7f, 0), +	SOC_SINGLE_TLV("ALC Min Threshold Volume", DA9055_ALC_TARGET_MIN, +		       0, 0x3f, 1, alc_threshold_tlv), +	SOC_SINGLE_TLV("ALC Max Threshold Volume", DA9055_ALC_TARGET_MAX, +		       0, 0x3f, 1, alc_threshold_tlv), +	SOC_SINGLE_TLV("ALC Noise Threshold Volume", DA9055_ALC_NOISE, +		       0, 0x3f, 1, alc_threshold_tlv), +	SOC_SINGLE_TLV("ALC Max Gain Volume", DA9055_ALC_GAIN_LIMITS, +		       4, 0xf, 0, alc_gain_tlv), +	SOC_SINGLE_TLV("ALC Max Attenuation Volume", DA9055_ALC_GAIN_LIMITS, +		       0, 0xf, 0, alc_gain_tlv), +	SOC_SINGLE_TLV("ALC Min Analog Gain Volume", +		       DA9055_ALC_ANA_GAIN_LIMITS, +		       0, 0x7, 0, alc_analog_gain_tlv), +	SOC_SINGLE_TLV("ALC Max Analog Gain Volume", +		       DA9055_ALC_ANA_GAIN_LIMITS, +		       4, 0x7, 0, alc_analog_gain_tlv), +	SOC_ENUM("ALC Attack Rate", da9055_attack_rate), +	SOC_ENUM("ALC Release Rate", da9055_release_rate), +	SOC_ENUM("ALC Hold Time", da9055_hold_time), +	/* +	 * Rate at which input signal envelope is tracked as the signal gets +	 * larger +	 */ +	SOC_ENUM("ALC Integ Attack Rate", da9055_integ_attack_rate), +	/* +	 * Rate at which input signal envelope is tracked as the signal gets +	 * smaller +	 */ +	SOC_ENUM("ALC Integ Release Rate", da9055_integ_release_rate), +}; + +/* DAPM Controls */ + +/* Mic PGA Left Source */ +static const struct snd_kcontrol_new da9055_mic_l_mux_controls = +SOC_DAPM_ENUM("Route", da9055_mic_l_src); + +/* Mic PGA Right Source */ +static const struct snd_kcontrol_new da9055_mic_r_mux_controls = +SOC_DAPM_ENUM("Route", da9055_mic_r_src); + +/* In Mixer Left */ +static const struct snd_kcontrol_new da9055_dapm_mixinl_controls[] = { +	SOC_DAPM_SINGLE("Aux Left Switch", DA9055_MIXIN_L_SELECT, 0, 1, 0), +	SOC_DAPM_SINGLE("Mic Left Switch", DA9055_MIXIN_L_SELECT, 1, 1, 0), +	SOC_DAPM_SINGLE("Mic Right Switch", DA9055_MIXIN_L_SELECT, 2, 1, 0), +}; + +/* In Mixer Right */ +static const struct snd_kcontrol_new da9055_dapm_mixinr_controls[] = { +	SOC_DAPM_SINGLE("Aux Right Switch", DA9055_MIXIN_R_SELECT, 0, 1, 0), +	SOC_DAPM_SINGLE("Mic Right Switch", DA9055_MIXIN_R_SELECT, 1, 1, 0), +	SOC_DAPM_SINGLE("Mic Left Switch", DA9055_MIXIN_R_SELECT, 2, 1, 0), +	SOC_DAPM_SINGLE("Mixin Left Switch", DA9055_MIXIN_R_SELECT, 3, 1, 0), +}; + +/* DAC Left Source */ +static const struct snd_kcontrol_new da9055_dac_l_mux_controls = +SOC_DAPM_ENUM("Route", da9055_dac_l_src); + +/* DAC Right Source */ +static const struct snd_kcontrol_new da9055_dac_r_mux_controls = +SOC_DAPM_ENUM("Route", da9055_dac_r_src); + +/* Out Mixer Left */ +static const struct snd_kcontrol_new da9055_dapm_mixoutl_controls[] = { +	SOC_DAPM_SINGLE("Aux Left Switch", DA9055_MIXOUT_L_SELECT, 0, 1, 0), +	SOC_DAPM_SINGLE("Mixin Left Switch", DA9055_MIXOUT_L_SELECT, 1, 1, 0), +	SOC_DAPM_SINGLE("Mixin Right Switch", DA9055_MIXOUT_L_SELECT, 2, 1, 0), +	SOC_DAPM_SINGLE("DAC Left Switch", DA9055_MIXOUT_L_SELECT, 3, 1, 0), +	SOC_DAPM_SINGLE("Aux Left Invert Switch", DA9055_MIXOUT_L_SELECT, +			4, 1, 0), +	SOC_DAPM_SINGLE("Mixin Left Invert Switch", DA9055_MIXOUT_L_SELECT, +			5, 1, 0), +	SOC_DAPM_SINGLE("Mixin Right Invert Switch", DA9055_MIXOUT_L_SELECT, +			6, 1, 0), +}; + +/* Out Mixer Right */ +static const struct snd_kcontrol_new da9055_dapm_mixoutr_controls[] = { +	SOC_DAPM_SINGLE("Aux Right Switch", DA9055_MIXOUT_R_SELECT, 0, 1, 0), +	SOC_DAPM_SINGLE("Mixin Right Switch", DA9055_MIXOUT_R_SELECT, 1, 1, 0), +	SOC_DAPM_SINGLE("Mixin Left Switch", DA9055_MIXOUT_R_SELECT, 2, 1, 0), +	SOC_DAPM_SINGLE("DAC Right Switch", DA9055_MIXOUT_R_SELECT, 3, 1, 0), +	SOC_DAPM_SINGLE("Aux Right Invert Switch", DA9055_MIXOUT_R_SELECT, +			4, 1, 0), +	SOC_DAPM_SINGLE("Mixin Right Invert Switch", DA9055_MIXOUT_R_SELECT, +			5, 1, 0), +	SOC_DAPM_SINGLE("Mixin Left Invert Switch", DA9055_MIXOUT_R_SELECT, +			6, 1, 0), +}; + +/* DAPM widgets */ +static const struct snd_soc_dapm_widget da9055_dapm_widgets[] = { +	/* Input Side */ + +	/* Input Lines */ +	SND_SOC_DAPM_INPUT("MIC1"), +	SND_SOC_DAPM_INPUT("MIC2"), +	SND_SOC_DAPM_INPUT("AUXL"), +	SND_SOC_DAPM_INPUT("AUXR"), + +	/* MUXs for Mic PGA source selection */ +	SND_SOC_DAPM_MUX("Mic Left Source", SND_SOC_NOPM, 0, 0, +			 &da9055_mic_l_mux_controls), +	SND_SOC_DAPM_MUX("Mic Right Source", SND_SOC_NOPM, 0, 0, +			 &da9055_mic_r_mux_controls), + +	/* Input PGAs */ +	SND_SOC_DAPM_PGA("Mic Left", DA9055_MIC_L_CTRL, 7, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Mic Right", DA9055_MIC_R_CTRL, 7, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Aux Left", DA9055_AUX_L_CTRL, 7, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Aux Right", DA9055_AUX_R_CTRL, 7, 0, NULL, 0), +	SND_SOC_DAPM_PGA("MIXIN Left", DA9055_MIXIN_L_CTRL, 7, 0, NULL, 0), +	SND_SOC_DAPM_PGA("MIXIN Right", DA9055_MIXIN_R_CTRL, 7, 0, NULL, 0), + +	SND_SOC_DAPM_SUPPLY("Mic Bias", DA9055_MIC_BIAS_CTRL, 7, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("AIF", DA9055_AIF_CTRL, 7, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("Charge Pump", DA9055_CP_CTRL, 7, 0, NULL, 0), + +	/* Input Mixers */ +	SND_SOC_DAPM_MIXER("In Mixer Left", SND_SOC_NOPM, 0, 0, +			   &da9055_dapm_mixinl_controls[0], +			   ARRAY_SIZE(da9055_dapm_mixinl_controls)), +	SND_SOC_DAPM_MIXER("In Mixer Right", SND_SOC_NOPM, 0, 0, +			   &da9055_dapm_mixinr_controls[0], +			   ARRAY_SIZE(da9055_dapm_mixinr_controls)), + +	/* ADCs */ +	SND_SOC_DAPM_ADC("ADC Left", "Capture", DA9055_ADC_L_CTRL, 7, 0), +	SND_SOC_DAPM_ADC("ADC Right", "Capture", DA9055_ADC_R_CTRL, 7, 0), + +	/* Output Side */ + +	/* MUXs for DAC source selection */ +	SND_SOC_DAPM_MUX("DAC Left Source", SND_SOC_NOPM, 0, 0, +			 &da9055_dac_l_mux_controls), +	SND_SOC_DAPM_MUX("DAC Right Source", SND_SOC_NOPM, 0, 0, +			 &da9055_dac_r_mux_controls), + +	/* AIF input */ +	SND_SOC_DAPM_AIF_IN("AIFIN Left", "Playback", 0, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_AIF_IN("AIFIN Right", "Playback", 0, SND_SOC_NOPM, 0, 0), + +	/* DACs */ +	SND_SOC_DAPM_DAC("DAC Left", "Playback", DA9055_DAC_L_CTRL, 7, 0), +	SND_SOC_DAPM_DAC("DAC Right", "Playback", DA9055_DAC_R_CTRL, 7, 0), + +	/* Output Mixers */ +	SND_SOC_DAPM_MIXER("Out Mixer Left", SND_SOC_NOPM, 0, 0, +			   &da9055_dapm_mixoutl_controls[0], +			   ARRAY_SIZE(da9055_dapm_mixoutl_controls)), +	SND_SOC_DAPM_MIXER("Out Mixer Right", SND_SOC_NOPM, 0, 0, +			   &da9055_dapm_mixoutr_controls[0], +			   ARRAY_SIZE(da9055_dapm_mixoutr_controls)), + +	/* Output PGAs */ +	SND_SOC_DAPM_PGA("MIXOUT Left", DA9055_MIXOUT_L_CTRL, 7, 0, NULL, 0), +	SND_SOC_DAPM_PGA("MIXOUT Right", DA9055_MIXOUT_R_CTRL, 7, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Lineout", DA9055_LINE_CTRL, 7, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Headphone Left", DA9055_HP_L_CTRL, 7, 0, NULL, 0), +	SND_SOC_DAPM_PGA("Headphone Right", DA9055_HP_R_CTRL, 7, 0, NULL, 0), + +	/* Output Lines */ +	SND_SOC_DAPM_OUTPUT("HPL"), +	SND_SOC_DAPM_OUTPUT("HPR"), +	SND_SOC_DAPM_OUTPUT("LINE"), +}; + +/* DAPM audio route definition */ +static const struct snd_soc_dapm_route da9055_audio_map[] = { +	/* Dest       Connecting Widget    source */ + +	/* Input path */ +	{"Mic Left Source", "MIC1_P_N", "MIC1"}, +	{"Mic Left Source", "MIC1_P", "MIC1"}, +	{"Mic Left Source", "MIC1_N", "MIC1"}, +	{"Mic Left Source", "MIC2_L", "MIC2"}, + +	{"Mic Right Source", "MIC2_R_L", "MIC2"}, +	{"Mic Right Source", "MIC2_R", "MIC2"}, +	{"Mic Right Source", "MIC2_L", "MIC2"}, + +	{"Mic Left", NULL, "Mic Left Source"}, +	{"Mic Right", NULL, "Mic Right Source"}, + +	{"Aux Left", NULL, "AUXL"}, +	{"Aux Right", NULL, "AUXR"}, + +	{"In Mixer Left", "Mic Left Switch", "Mic Left"}, +	{"In Mixer Left", "Mic Right Switch", "Mic Right"}, +	{"In Mixer Left", "Aux Left Switch", "Aux Left"}, + +	{"In Mixer Right", "Mic Right Switch", "Mic Right"}, +	{"In Mixer Right", "Mic Left Switch", "Mic Left"}, +	{"In Mixer Right", "Aux Right Switch", "Aux Right"}, +	{"In Mixer Right", "Mixin Left Switch", "MIXIN Left"}, + +	{"MIXIN Left", NULL, "In Mixer Left"}, +	{"ADC Left", NULL, "MIXIN Left"}, + +	{"MIXIN Right", NULL, "In Mixer Right"}, +	{"ADC Right", NULL, "MIXIN Right"}, + +	{"ADC Left", NULL, "AIF"}, +	{"ADC Right", NULL, "AIF"}, + +	/* Output path */ +	{"AIFIN Left", NULL, "AIF"}, +	{"AIFIN Right", NULL, "AIF"}, + +	{"DAC Left Source", "ADC output left", "ADC Left"}, +	{"DAC Left Source", "ADC output right", "ADC Right"}, +	{"DAC Left Source", "AIF input left", "AIFIN Left"}, +	{"DAC Left Source", "AIF input right", "AIFIN Right"}, + +	{"DAC Right Source", "ADC output left", "ADC Left"}, +	{"DAC Right Source", "ADC output right", "ADC Right"}, +	{"DAC Right Source", "AIF input left", "AIFIN Left"}, +	{"DAC Right Source", "AIF input right", "AIFIN Right"}, + +	{"DAC Left", NULL, "DAC Left Source"}, +	{"DAC Right", NULL, "DAC Right Source"}, + +	{"Out Mixer Left", "Aux Left Switch", "Aux Left"}, +	{"Out Mixer Left", "Mixin Left Switch", "MIXIN Left"}, +	{"Out Mixer Left", "Mixin Right Switch", "MIXIN Right"}, +	{"Out Mixer Left", "Aux Left Invert Switch", "Aux Left"}, +	{"Out Mixer Left", "Mixin Left Invert Switch", "MIXIN Left"}, +	{"Out Mixer Left", "Mixin Right Invert Switch", "MIXIN Right"}, +	{"Out Mixer Left", "DAC Left Switch", "DAC Left"}, + +	{"Out Mixer Right", "Aux Right Switch", "Aux Right"}, +	{"Out Mixer Right", "Mixin Right Switch", "MIXIN Right"}, +	{"Out Mixer Right", "Mixin Left Switch", "MIXIN Left"}, +	{"Out Mixer Right", "Aux Right Invert Switch", "Aux Right"}, +	{"Out Mixer Right", "Mixin Right Invert Switch", "MIXIN Right"}, +	{"Out Mixer Right", "Mixin Left Invert Switch", "MIXIN Left"}, +	{"Out Mixer Right", "DAC Right Switch", "DAC Right"}, + +	{"MIXOUT Left", NULL, "Out Mixer Left"}, +	{"Headphone Left", NULL, "MIXOUT Left"}, +	{"Headphone Left", NULL, "Charge Pump"}, +	{"HPL", NULL, "Headphone Left"}, + +	{"MIXOUT Right", NULL, "Out Mixer Right"}, +	{"Headphone Right", NULL, "MIXOUT Right"}, +	{"Headphone Right", NULL, "Charge Pump"}, +	{"HPR", NULL, "Headphone Right"}, + +	{"MIXOUT Right", NULL, "Out Mixer Right"}, +	{"Lineout", NULL, "MIXOUT Right"}, +	{"LINE", NULL, "Lineout"}, +}; + +/* Codec private data */ +struct da9055_priv { +	struct regmap *regmap; +	unsigned int mclk_rate; +	int master; +	struct da9055_platform_data *pdata; +}; + +static struct reg_default da9055_reg_defaults[] = { +	{ 0x21, 0x10 }, +	{ 0x22, 0x0A }, +	{ 0x23, 0x00 }, +	{ 0x24, 0x00 }, +	{ 0x25, 0x00 }, +	{ 0x26, 0x00 }, +	{ 0x27, 0x0C }, +	{ 0x28, 0x01 }, +	{ 0x29, 0x08 }, +	{ 0x2A, 0x32 }, +	{ 0x2B, 0x00 }, +	{ 0x30, 0x35 }, +	{ 0x31, 0x35 }, +	{ 0x32, 0x00 }, +	{ 0x33, 0x00 }, +	{ 0x34, 0x03 }, +	{ 0x35, 0x03 }, +	{ 0x36, 0x6F }, +	{ 0x37, 0x6F }, +	{ 0x38, 0x80 }, +	{ 0x39, 0x01 }, +	{ 0x3A, 0x01 }, +	{ 0x40, 0x00 }, +	{ 0x41, 0x88 }, +	{ 0x42, 0x88 }, +	{ 0x43, 0x08 }, +	{ 0x44, 0x80 }, +	{ 0x45, 0x6F }, +	{ 0x46, 0x6F }, +	{ 0x47, 0x61 }, +	{ 0x48, 0x35 }, +	{ 0x49, 0x35 }, +	{ 0x4A, 0x35 }, +	{ 0x4B, 0x00 }, +	{ 0x4C, 0x00 }, +	{ 0x60, 0x44 }, +	{ 0x61, 0x44 }, +	{ 0x62, 0x00 }, +	{ 0x63, 0x40 }, +	{ 0x64, 0x40 }, +	{ 0x65, 0x40 }, +	{ 0x66, 0x40 }, +	{ 0x67, 0x40 }, +	{ 0x68, 0x40 }, +	{ 0x69, 0x48 }, +	{ 0x6A, 0x40 }, +	{ 0x6B, 0x41 }, +	{ 0x6C, 0x40 }, +	{ 0x6D, 0x40 }, +	{ 0x6E, 0x10 }, +	{ 0x6F, 0x10 }, +	{ 0x90, 0x80 }, +	{ 0x92, 0x02 }, +	{ 0x93, 0x00 }, +	{ 0x99, 0x00 }, +	{ 0x9A, 0x00 }, +	{ 0x9B, 0x00 }, +	{ 0x9C, 0x3F }, +	{ 0x9D, 0x00 }, +	{ 0x9E, 0x3F }, +	{ 0x9F, 0xFF }, +	{ 0xA0, 0x71 }, +	{ 0xA1, 0x00 }, +	{ 0xA2, 0x00 }, +	{ 0xA6, 0x00 }, +	{ 0xA7, 0x00 }, +	{ 0xAB, 0x00 }, +	{ 0xAC, 0x00 }, +	{ 0xAD, 0x00 }, +	{ 0xAF, 0x08 }, +	{ 0xB0, 0x00 }, +	{ 0xB1, 0x00 }, +	{ 0xB2, 0x00 }, +}; + +static bool da9055_volatile_register(struct device *dev, +				     unsigned int reg) +{ +	switch (reg) { +	case DA9055_STATUS1: +	case DA9055_PLL_STATUS: +	case DA9055_AUX_L_GAIN_STATUS: +	case DA9055_AUX_R_GAIN_STATUS: +	case DA9055_MIC_L_GAIN_STATUS: +	case DA9055_MIC_R_GAIN_STATUS: +	case DA9055_MIXIN_L_GAIN_STATUS: +	case DA9055_MIXIN_R_GAIN_STATUS: +	case DA9055_ADC_L_GAIN_STATUS: +	case DA9055_ADC_R_GAIN_STATUS: +	case DA9055_DAC_L_GAIN_STATUS: +	case DA9055_DAC_R_GAIN_STATUS: +	case DA9055_HP_L_GAIN_STATUS: +	case DA9055_HP_R_GAIN_STATUS: +	case DA9055_LINE_GAIN_STATUS: +	case DA9055_ALC_CIC_OP_LVL_DATA: +		return 1; +	default: +		return 0; +	} +} + +/* Set DAI word length */ +static int da9055_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 da9055_priv *da9055 = snd_soc_codec_get_drvdata(codec); +	u8 aif_ctrl, fs; +	u32 sysclk; + +	switch (params_format(params)) { +	case SNDRV_PCM_FORMAT_S16_LE: +		aif_ctrl = DA9055_AIF_WORD_S16_LE; +		break; +	case SNDRV_PCM_FORMAT_S20_3LE: +		aif_ctrl = DA9055_AIF_WORD_S20_3LE; +		break; +	case SNDRV_PCM_FORMAT_S24_LE: +		aif_ctrl = DA9055_AIF_WORD_S24_LE; +		break; +	case SNDRV_PCM_FORMAT_S32_LE: +		aif_ctrl = DA9055_AIF_WORD_S32_LE; +		break; +	default: +		return -EINVAL; +	} + +	/* Set AIF format */ +	snd_soc_update_bits(codec, DA9055_AIF_CTRL, DA9055_AIF_WORD_LENGTH_MASK, +			    aif_ctrl); + +	switch (params_rate(params)) { +	case 8000: +		fs		= DA9055_SR_8000; +		sysclk		= 3072000; +		break; +	case 11025: +		fs		= DA9055_SR_11025; +		sysclk		= 2822400; +		break; +	case 12000: +		fs		= DA9055_SR_12000; +		sysclk		= 3072000; +		break; +	case 16000: +		fs		= DA9055_SR_16000; +		sysclk		= 3072000; +		break; +	case 22050: +		fs		= DA9055_SR_22050; +		sysclk		= 2822400; +		break; +	case 32000: +		fs		= DA9055_SR_32000; +		sysclk		= 3072000; +		break; +	case 44100: +		fs		= DA9055_SR_44100; +		sysclk		= 2822400; +		break; +	case 48000: +		fs		= DA9055_SR_48000; +		sysclk		= 3072000; +		break; +	case 88200: +		fs		= DA9055_SR_88200; +		sysclk		= 2822400; +		break; +	case 96000: +		fs		= DA9055_SR_96000; +		sysclk		= 3072000; +		break; +	default: +		return -EINVAL; +	} + +	if (da9055->mclk_rate) { +		/* PLL Mode, Write actual FS */ +		snd_soc_write(codec, DA9055_SR, fs); +	} else { +		/* +		 * Non-PLL Mode +		 * When PLL is bypassed, chip assumes constant MCLK of +		 * 12.288MHz and uses sample rate value to divide this MCLK +		 * to derive its sys clk. As sys clk has to be 256 * Fs, we +		 * need to write constant sample rate i.e. 48KHz. +		 */ +		snd_soc_write(codec, DA9055_SR, DA9055_SR_48000); +	} + +	if (da9055->mclk_rate && (da9055->mclk_rate != sysclk)) { +		/* PLL Mode */ +		if (!da9055->master) { +			/* PLL slave mode, enable PLL and also SRM */ +			snd_soc_update_bits(codec, DA9055_PLL_CTRL, +					    DA9055_PLL_EN | DA9055_PLL_SRM_EN, +					    DA9055_PLL_EN | DA9055_PLL_SRM_EN); +		} else { +			/* PLL master mode, only enable PLL */ +			snd_soc_update_bits(codec, DA9055_PLL_CTRL, +					    DA9055_PLL_EN, DA9055_PLL_EN); +		} +	} else { +		/* Non PLL Mode, disable PLL */ +		snd_soc_update_bits(codec, DA9055_PLL_CTRL, DA9055_PLL_EN, 0); +	} + +	return 0; +} + +/* Set DAI mode and Format */ +static int da9055_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ +	struct snd_soc_codec *codec = codec_dai->codec; +	struct da9055_priv *da9055 = snd_soc_codec_get_drvdata(codec); +	u8 aif_clk_mode, aif_ctrl, mode; + +	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { +	case SND_SOC_DAIFMT_CBM_CFM: +		/* DA9055 in I2S Master Mode */ +		mode = 1; +		aif_clk_mode = DA9055_AIF_CLK_EN_MASTER_MODE; +		break; +	case SND_SOC_DAIFMT_CBS_CFS: +		/* DA9055 in I2S Slave Mode */ +		mode = 0; +		aif_clk_mode = DA9055_AIF_CLK_EN_SLAVE_MODE; +		break; +	default: +		return -EINVAL; +	} + +	/* Don't allow change of mode if PLL is enabled */ +	if ((snd_soc_read(codec, DA9055_PLL_CTRL) & DA9055_PLL_EN) && +	    (da9055->master != mode)) +		return -EINVAL; + +	da9055->master = mode; + +	/* Only I2S is supported */ +	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { +	case SND_SOC_DAIFMT_I2S: +		aif_ctrl = DA9055_AIF_FORMAT_I2S_MODE; +		break; +	case SND_SOC_DAIFMT_LEFT_J: +		aif_ctrl = DA9055_AIF_FORMAT_LEFT_J; +		break; +	case SND_SOC_DAIFMT_RIGHT_J: +		aif_ctrl = DA9055_AIF_FORMAT_RIGHT_J; +		break; +	default: +		return -EINVAL; +	} + +	/* By default only 32 BCLK per WCLK is supported */ +	aif_clk_mode |= DA9055_AIF_BCLKS_PER_WCLK_32; + +	snd_soc_update_bits(codec, DA9055_AIF_CLK_MODE, +			    (DA9055_AIF_CLK_MODE_MASK | DA9055_AIF_BCLK_MASK), +			    aif_clk_mode); +	snd_soc_update_bits(codec, DA9055_AIF_CTRL, DA9055_AIF_FORMAT_MASK, +			    aif_ctrl); +	return 0; +} + +static int da9055_mute(struct snd_soc_dai *dai, int mute) +{ +	struct snd_soc_codec *codec = dai->codec; + +	if (mute) { +		snd_soc_update_bits(codec, DA9055_DAC_L_CTRL, +				    DA9055_DAC_L_MUTE_EN, DA9055_DAC_L_MUTE_EN); +		snd_soc_update_bits(codec, DA9055_DAC_R_CTRL, +				    DA9055_DAC_R_MUTE_EN, DA9055_DAC_R_MUTE_EN); +	} else { +		snd_soc_update_bits(codec, DA9055_DAC_L_CTRL, +				    DA9055_DAC_L_MUTE_EN, 0); +		snd_soc_update_bits(codec, DA9055_DAC_R_CTRL, +				    DA9055_DAC_R_MUTE_EN, 0); +	} + +	return 0; +} + +#define DA9055_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ +			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static int da9055_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 da9055_priv *da9055 = snd_soc_codec_get_drvdata(codec); + +	switch (clk_id) { +	case DA9055_CLKSRC_MCLK: +		switch (freq) { +		case 11289600: +		case 12000000: +		case 12288000: +		case 13000000: +		case 13500000: +		case 14400000: +		case 19200000: +		case 19680000: +		case 19800000: +			da9055->mclk_rate = freq; +			return 0; +		default: +			dev_err(codec_dai->dev, "Unsupported MCLK value %d\n", +				freq); +			return -EINVAL; +		} +		break; +	default: +		dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id); +		return -EINVAL; +	} +} + +/* + * da9055_set_dai_pll	: Configure the codec PLL + * @param codec_dai	: Pointer to codec DAI + * @param pll_id	: da9055 has only one pll, so pll_id is always zero + * @param fref		: Input MCLK frequency + * @param fout		: FsDM value + * @return int		: Zero for success, negative error code for error + * + * Note: Supported PLL input frequencies are 11.2896MHz, 12MHz, 12.288MHz, + *	 13MHz, 13.5MHz, 14.4MHz, 19.2MHz, 19.6MHz and 19.8MHz + */ +static int da9055_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, +			      int source, unsigned int fref, unsigned int fout) +{ +	struct snd_soc_codec *codec = codec_dai->codec; +	struct da9055_priv *da9055 = snd_soc_codec_get_drvdata(codec); + +	u8 pll_frac_top, pll_frac_bot, pll_integer, cnt; + +	/* Disable PLL before setting the divisors */ +	snd_soc_update_bits(codec, DA9055_PLL_CTRL, DA9055_PLL_EN, 0); + +	/* In slave mode, there is only one set of divisors */ +	if (!da9055->master && (fout != 2822400)) +		goto pll_err; + +	/* Search pll div array for correct divisors */ +	for (cnt = 0; cnt < ARRAY_SIZE(da9055_pll_div); cnt++) { +		/* Check fref, mode  and fout */ +		if ((fref == da9055_pll_div[cnt].fref) && +		    (da9055->master ==  da9055_pll_div[cnt].mode) && +		    (fout == da9055_pll_div[cnt].fout)) { +			/* All match, pick up divisors */ +			pll_frac_top = da9055_pll_div[cnt].frac_top; +			pll_frac_bot = da9055_pll_div[cnt].frac_bot; +			pll_integer = da9055_pll_div[cnt].integer; +			break; +		} +	} +	if (cnt >= ARRAY_SIZE(da9055_pll_div)) +		goto pll_err; + +	/* Write PLL dividers */ +	snd_soc_write(codec, DA9055_PLL_FRAC_TOP, pll_frac_top); +	snd_soc_write(codec, DA9055_PLL_FRAC_BOT, pll_frac_bot); +	snd_soc_write(codec, DA9055_PLL_INTEGER, pll_integer); + +	return 0; +pll_err: +	dev_err(codec_dai->dev, "Error in setting up PLL\n"); +	return -EINVAL; +} + +/* DAI operations */ +static const struct snd_soc_dai_ops da9055_dai_ops = { +	.hw_params	= da9055_hw_params, +	.set_fmt	= da9055_set_dai_fmt, +	.set_sysclk	= da9055_set_dai_sysclk, +	.set_pll	= da9055_set_dai_pll, +	.digital_mute	= da9055_mute, +}; + +static struct snd_soc_dai_driver da9055_dai = { +	.name = "da9055-hifi", +	/* Playback Capabilities */ +	.playback = { +		.stream_name = "Playback", +		.channels_min = 1, +		.channels_max = 2, +		.rates = SNDRV_PCM_RATE_8000_96000, +		.formats = DA9055_FORMATS, +	}, +	/* Capture Capabilities */ +	.capture = { +		.stream_name = "Capture", +		.channels_min = 1, +		.channels_max = 2, +		.rates = SNDRV_PCM_RATE_8000_96000, +		.formats = DA9055_FORMATS, +	}, +	.ops = &da9055_dai_ops, +	.symmetric_rates = 1, +}; + +static int da9055_set_bias_level(struct snd_soc_codec *codec, +				 enum snd_soc_bias_level level) +{ +	switch (level) { +	case SND_SOC_BIAS_ON: +	case SND_SOC_BIAS_PREPARE: +		break; +	case SND_SOC_BIAS_STANDBY: +		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { +			/* Enable VMID reference & master bias */ +			snd_soc_update_bits(codec, DA9055_REFERENCES, +					    DA9055_VMID_EN | DA9055_BIAS_EN, +					    DA9055_VMID_EN | DA9055_BIAS_EN); +		} +		break; +	case SND_SOC_BIAS_OFF: +		/* Disable VMID reference & master bias */ +		snd_soc_update_bits(codec, DA9055_REFERENCES, +				    DA9055_VMID_EN | DA9055_BIAS_EN, 0); +		break; +	} +	codec->dapm.bias_level = level; +	return 0; +} + +static int da9055_probe(struct snd_soc_codec *codec) +{ +	int ret; +	struct da9055_priv *da9055 = snd_soc_codec_get_drvdata(codec); + +	codec->control_data = da9055->regmap; +	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); +	if (ret < 0) { +		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); +		return ret; +	} + +	/* Enable all Gain Ramps */ +	snd_soc_update_bits(codec, DA9055_AUX_L_CTRL, +			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN); +	snd_soc_update_bits(codec, DA9055_AUX_R_CTRL, +			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN); +	snd_soc_update_bits(codec, DA9055_MIXIN_L_CTRL, +			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN); +	snd_soc_update_bits(codec, DA9055_MIXIN_R_CTRL, +			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN); +	snd_soc_update_bits(codec, DA9055_ADC_L_CTRL, +			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN); +	snd_soc_update_bits(codec, DA9055_ADC_R_CTRL, +			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN); +	snd_soc_update_bits(codec, DA9055_DAC_L_CTRL, +			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN); +	snd_soc_update_bits(codec, DA9055_DAC_R_CTRL, +			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN); +	snd_soc_update_bits(codec, DA9055_HP_L_CTRL, +			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN); +	snd_soc_update_bits(codec, DA9055_HP_R_CTRL, +			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN); +	snd_soc_update_bits(codec, DA9055_LINE_CTRL, +			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN); + +	/* +	 * There are two separate control bits for input and output mixers as +	 * well as headphone and line outs. +	 * One to enable corresponding amplifier and other to enable its +	 * output. As amplifier bits are related to power control, they are +	 * being managed by DAPM while other (non power related) bits are +	 * enabled here +	 */ +	snd_soc_update_bits(codec, DA9055_MIXIN_L_CTRL, +			    DA9055_MIXIN_L_MIX_EN, DA9055_MIXIN_L_MIX_EN); +	snd_soc_update_bits(codec, DA9055_MIXIN_R_CTRL, +			    DA9055_MIXIN_R_MIX_EN, DA9055_MIXIN_R_MIX_EN); + +	snd_soc_update_bits(codec, DA9055_MIXOUT_L_CTRL, +			    DA9055_MIXOUT_L_MIX_EN, DA9055_MIXOUT_L_MIX_EN); +	snd_soc_update_bits(codec, DA9055_MIXOUT_R_CTRL, +			    DA9055_MIXOUT_R_MIX_EN, DA9055_MIXOUT_R_MIX_EN); + +	snd_soc_update_bits(codec, DA9055_HP_L_CTRL, +			    DA9055_HP_L_AMP_OE, DA9055_HP_L_AMP_OE); +	snd_soc_update_bits(codec, DA9055_HP_R_CTRL, +			    DA9055_HP_R_AMP_OE, DA9055_HP_R_AMP_OE); + +	snd_soc_update_bits(codec, DA9055_LINE_CTRL, +			    DA9055_LINE_AMP_OE, DA9055_LINE_AMP_OE); + +	/* Set this as per your system configuration */ +	snd_soc_write(codec, DA9055_PLL_CTRL, DA9055_PLL_INDIV_10_20_MHZ); + +	/* Set platform data values */ +	if (da9055->pdata) { +		/* set mic bias source */ +		if (da9055->pdata->micbias_source) { +			snd_soc_update_bits(codec, DA9055_MIXIN_R_SELECT, +					    DA9055_MICBIAS2_EN, +					    DA9055_MICBIAS2_EN); +		} else { +			snd_soc_update_bits(codec, DA9055_MIXIN_R_SELECT, +					    DA9055_MICBIAS2_EN, 0); +		} +		/* set mic bias voltage */ +		switch (da9055->pdata->micbias) { +		case DA9055_MICBIAS_2_2V: +		case DA9055_MICBIAS_2_1V: +		case DA9055_MICBIAS_1_8V: +		case DA9055_MICBIAS_1_6V: +			snd_soc_update_bits(codec, DA9055_MIC_CONFIG, +					    DA9055_MICBIAS_LEVEL_MASK, +					    (da9055->pdata->micbias) << 4); +			break; +		} +	} +	return 0; +} + +static struct snd_soc_codec_driver soc_codec_dev_da9055 = { +	.probe			= da9055_probe, +	.set_bias_level		= da9055_set_bias_level, + +	.controls		= da9055_snd_controls, +	.num_controls		= ARRAY_SIZE(da9055_snd_controls), + +	.dapm_widgets		= da9055_dapm_widgets, +	.num_dapm_widgets	= ARRAY_SIZE(da9055_dapm_widgets), +	.dapm_routes		= da9055_audio_map, +	.num_dapm_routes	= ARRAY_SIZE(da9055_audio_map), +}; + +static const struct regmap_config da9055_regmap_config = { +	.reg_bits = 8, +	.val_bits = 8, + +	.reg_defaults = da9055_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(da9055_reg_defaults), +	.volatile_reg = da9055_volatile_register, +	.cache_type = REGCACHE_RBTREE, +}; + +static int __devinit da9055_i2c_probe(struct i2c_client *i2c, +				      const struct i2c_device_id *id) +{ +	struct da9055_priv *da9055; +	struct da9055_platform_data *pdata = dev_get_platdata(&i2c->dev); +	int ret; + +	da9055 = devm_kzalloc(&i2c->dev, sizeof(struct da9055_priv), +			      GFP_KERNEL); +	if (!da9055) +		return -ENOMEM; + +	if (pdata) +		da9055->pdata = pdata; + +	i2c_set_clientdata(i2c, da9055); + +	da9055->regmap = devm_regmap_init_i2c(i2c, &da9055_regmap_config); +	if (IS_ERR(da9055->regmap)) { +		ret = PTR_ERR(da9055->regmap); +		dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret); +		return ret; +	} + +	ret = snd_soc_register_codec(&i2c->dev, +			&soc_codec_dev_da9055, &da9055_dai, 1); +	if (ret < 0) { +		dev_err(&i2c->dev, "Failed to register da9055 codec: %d\n", +			ret); +	} +	return ret; +} + +static int __devexit da9055_remove(struct i2c_client *client) +{ +	snd_soc_unregister_codec(&client->dev); +	return 0; +} + +static const struct i2c_device_id da9055_i2c_id[] = { +	{ "da9055", 0 }, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, da9055_i2c_id); + +/* I2C codec control layer */ +static struct i2c_driver da9055_i2c_driver = { +	.driver = { +		.name = "da9055", +		.owner = THIS_MODULE, +	}, +	.probe		= da9055_i2c_probe, +	.remove		= __devexit_p(da9055_remove), +	.id_table	= da9055_i2c_id, +}; + +module_i2c_driver(da9055_i2c_driver); + +MODULE_DESCRIPTION("ASoC DA9055 Codec driver"); +MODULE_AUTHOR("David Chen, Ashish Chavan"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c index 5d8f39e3297..1bf55602c9e 100644 --- a/sound/soc/codecs/isabelle.c +++ b/sound/soc/codecs/isabelle.c @@ -13,7 +13,6 @@   */  #include <linux/module.h>  #include <linux/moduleparam.h> -#include <linux/version.h>  #include <linux/kernel.h>  #include <linux/init.h>  #include <linux/delay.h> diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c index ba4fafb93e5..81a328c7883 100644 --- a/sound/soc/codecs/lm4857.c +++ b/sound/soc/codecs/lm4857.c @@ -250,17 +250,7 @@ static struct i2c_driver lm4857_i2c_driver = {  	.id_table = lm4857_i2c_id,  }; -static int __init lm4857_init(void) -{ -	return i2c_add_driver(&lm4857_i2c_driver); -} -module_init(lm4857_init); - -static void __exit lm4857_exit(void) -{ -	i2c_del_driver(&lm4857_i2c_driver); -} -module_exit(lm4857_exit); +module_i2c_driver(lm4857_i2c_driver);  MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");  MODULE_DESCRIPTION("LM4857 amplifier driver"); diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index af7324b79dd..3264a516930 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -2107,23 +2107,7 @@ static struct i2c_driver max98088_i2c_driver = {         .id_table = max98088_i2c_id,  }; -static int __init max98088_init(void) -{ -       int ret; - -       ret = i2c_add_driver(&max98088_i2c_driver); -       if (ret) -               pr_err("Failed to register max98088 I2C driver: %d\n", ret); - -       return ret; -} -module_init(max98088_init); - -static void __exit max98088_exit(void) -{ -       i2c_del_driver(&max98088_i2c_driver); -} -module_exit(max98088_exit); +module_i2c_driver(max98088_i2c_driver);  MODULE_DESCRIPTION("ALSA SoC MAX98088 driver");  MODULE_AUTHOR("Peter Hsiang, Jesse Marroquin"); diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 7cd508e16a5..38d43c59d3f 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -2533,23 +2533,7 @@ static struct i2c_driver max98095_i2c_driver = {  	.id_table = max98095_i2c_id,  }; -static int __init max98095_init(void) -{ -	int ret; - -	ret = i2c_add_driver(&max98095_i2c_driver); -	if (ret) -		pr_err("Failed to register max98095 I2C driver: %d\n", ret); - -	return ret; -} -module_init(max98095_init); - -static void __exit max98095_exit(void) -{ -	i2c_del_driver(&max98095_i2c_driver); -} -module_exit(max98095_exit); +module_i2c_driver(max98095_i2c_driver);  MODULE_DESCRIPTION("ALSA SoC MAX98095 driver");  MODULE_AUTHOR("Peter Hsiang"); diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c index a1913091f56..efe535c37b3 100644 --- a/sound/soc/codecs/max9850.c +++ b/sound/soc/codecs/max9850.c @@ -369,17 +369,7 @@ static struct i2c_driver max9850_i2c_driver = {  	.id_table = max9850_i2c_id,  }; -static int __init max9850_init(void) -{ -	return i2c_add_driver(&max9850_i2c_driver); -} -module_init(max9850_init); - -static void __exit max9850_exit(void) -{ -	i2c_del_driver(&max9850_i2c_driver); -} -module_exit(max9850_exit); +module_i2c_driver(max9850_i2c_driver);  MODULE_AUTHOR("Christian Glindkamp <christian.glindkamp@taskit.de>");  MODULE_DESCRIPTION("ASoC MAX9850 codec driver"); diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c index 3a2ba3d8fd6..d15e5943c85 100644 --- a/sound/soc/codecs/max9877.c +++ b/sound/soc/codecs/max9877.c @@ -291,17 +291,7 @@ static struct i2c_driver max9877_i2c_driver = {  	.id_table = max9877_i2c_id,  }; -static int __init max9877_init(void) -{ -	return i2c_add_driver(&max9877_i2c_driver); -} -module_init(max9877_init); - -static void __exit max9877_exit(void) -{ -	i2c_del_driver(&max9877_i2c_driver); -} -module_exit(max9877_exit); +module_i2c_driver(max9877_i2c_driver);  MODULE_DESCRIPTION("ASoC MAX9877 amp driver");  MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>"); diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index 115a4030181..bc955999c8a 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c @@ -426,16 +426,16 @@ static int mc13783_set_tdm_slot_sync(struct snd_soc_dai *dai,  }  static const struct snd_kcontrol_new mc1l_amp_ctl = -	SOC_DAPM_SINGLE("Switch", 38, 7, 1, 0); +	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_TX, 7, 1, 0);  static const struct snd_kcontrol_new mc1r_amp_ctl = -	SOC_DAPM_SINGLE("Switch", 38, 5, 1, 0); +	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_TX, 5, 1, 0);  static const struct snd_kcontrol_new mc2_amp_ctl = -	SOC_DAPM_SINGLE("Switch", 38, 9, 1, 0); +	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_TX, 9, 1, 0);  static const struct snd_kcontrol_new atx_amp_ctl = -	SOC_DAPM_SINGLE("Switch", 38, 11, 1, 0); +	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_TX, 11, 1, 0);  /* Virtual mux. The chip does the input selection automatically @@ -461,22 +461,22 @@ static const struct snd_kcontrol_new right_input_mux =  	SOC_DAPM_ENUM_VIRT("Route", adcr_enum);  static const struct snd_kcontrol_new samp_ctl = -	SOC_DAPM_SINGLE("Switch", 36, 3, 1, 0); +	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 3, 1, 0);  static const struct snd_kcontrol_new lamp_ctl = -	SOC_DAPM_SINGLE("Switch", 36, 5, 1, 0); +	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 5, 1, 0);  static const struct snd_kcontrol_new hlamp_ctl = -	SOC_DAPM_SINGLE("Switch", 36, 10, 1, 0); +	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 10, 1, 0);  static const struct snd_kcontrol_new hramp_ctl = -	SOC_DAPM_SINGLE("Switch", 36, 9, 1, 0); +	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 9, 1, 0);  static const struct snd_kcontrol_new llamp_ctl = -	SOC_DAPM_SINGLE("Switch", 36, 16, 1, 0); +	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 16, 1, 0);  static const struct snd_kcontrol_new lramp_ctl = -	SOC_DAPM_SINGLE("Switch", 36, 15, 1, 0); +	SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 15, 1, 0);  static const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = {  /* Input */ @@ -487,13 +487,13 @@ static const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = {  	SND_SOC_DAPM_INPUT("RXINL"),  	SND_SOC_DAPM_INPUT("TXIN"), -	SND_SOC_DAPM_SUPPLY("MC1 Bias", 38, 0, 0, NULL, 0), -	SND_SOC_DAPM_SUPPLY("MC2 Bias", 38, 1, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("MC1 Bias", MC13783_AUDIO_TX, 0, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("MC2 Bias", MC13783_AUDIO_TX, 1, 0, NULL, 0), -	SND_SOC_DAPM_SWITCH("MC1L Amp", 38, 7, 0, &mc1l_amp_ctl), -	SND_SOC_DAPM_SWITCH("MC1R Amp", 38, 5, 0, &mc1r_amp_ctl), -	SND_SOC_DAPM_SWITCH("MC2 Amp", 38, 9, 0, &mc2_amp_ctl), -	SND_SOC_DAPM_SWITCH("TXIN Amp", 38, 11, 0, &atx_amp_ctl), +	SND_SOC_DAPM_SWITCH("MC1L Amp", MC13783_AUDIO_TX, 7, 0, &mc1l_amp_ctl), +	SND_SOC_DAPM_SWITCH("MC1R Amp", MC13783_AUDIO_TX, 5, 0, &mc1r_amp_ctl), +	SND_SOC_DAPM_SWITCH("MC2 Amp", MC13783_AUDIO_TX, 9, 0, &mc2_amp_ctl), +	SND_SOC_DAPM_SWITCH("TXIN Amp", MC13783_AUDIO_TX, 11, 0, &atx_amp_ctl),  	SND_SOC_DAPM_VIRT_MUX("PGA Left Input Mux", SND_SOC_NOPM, 0, 0,  			      &left_input_mux), @@ -503,12 +503,12 @@ static const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = {  	SND_SOC_DAPM_PGA("PGA Left Input", SND_SOC_NOPM, 0, 0, NULL, 0),  	SND_SOC_DAPM_PGA("PGA Right Input", SND_SOC_NOPM, 0, 0, NULL, 0), -	SND_SOC_DAPM_ADC("ADC", "Capture", 40, 11, 0), -	SND_SOC_DAPM_SUPPLY("ADC_Reset", 40, 15, 0, NULL, 0), +	SND_SOC_DAPM_ADC("ADC", "Capture", MC13783_AUDIO_CODEC, 11, 0), +	SND_SOC_DAPM_SUPPLY("ADC_Reset", MC13783_AUDIO_CODEC, 15, 0, NULL, 0),  /* Output */ -	SND_SOC_DAPM_SUPPLY("DAC_E", 41, 11, 0, NULL, 0), -	SND_SOC_DAPM_SUPPLY("DAC_Reset", 41, 15, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("DAC_E", MC13783_AUDIO_DAC, 11, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("DAC_Reset", MC13783_AUDIO_DAC, 15, 0, NULL, 0),  	SND_SOC_DAPM_OUTPUT("RXOUTL"),  	SND_SOC_DAPM_OUTPUT("RXOUTR"),  	SND_SOC_DAPM_OUTPUT("HSL"), @@ -516,14 +516,18 @@ static const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = {  	SND_SOC_DAPM_OUTPUT("LSP"),  	SND_SOC_DAPM_OUTPUT("SP"), -	SND_SOC_DAPM_SWITCH("Speaker Amp", 36, 3, 0, &samp_ctl), +	SND_SOC_DAPM_SWITCH("Speaker Amp", MC13783_AUDIO_RX0, 3, 0, &samp_ctl),  	SND_SOC_DAPM_SWITCH("Loudspeaker Amp", SND_SOC_NOPM, 0, 0, &lamp_ctl), -	SND_SOC_DAPM_SWITCH("Headset Amp Left", 36, 10, 0, &hlamp_ctl), -	SND_SOC_DAPM_SWITCH("Headset Amp Right", 36, 9, 0, &hramp_ctl), -	SND_SOC_DAPM_SWITCH("Line out Amp Left", 36, 16, 0, &llamp_ctl), -	SND_SOC_DAPM_SWITCH("Line out Amp Right", 36, 15, 0, &lramp_ctl), -	SND_SOC_DAPM_DAC("DAC", "Playback", 36, 22, 0), -	SND_SOC_DAPM_PGA("DAC PGA", 37, 5, 0, NULL, 0), +	SND_SOC_DAPM_SWITCH("Headset Amp Left", MC13783_AUDIO_RX0, 10, 0, +			&hlamp_ctl), +	SND_SOC_DAPM_SWITCH("Headset Amp Right", MC13783_AUDIO_RX0, 9, 0, +			&hramp_ctl), +	SND_SOC_DAPM_SWITCH("Line out Amp Left", MC13783_AUDIO_RX0, 16, 0, +			&llamp_ctl), +	SND_SOC_DAPM_SWITCH("Line out Amp Right", MC13783_AUDIO_RX0, 15, 0, +			&lramp_ctl), +	SND_SOC_DAPM_DAC("DAC", "Playback", MC13783_AUDIO_RX0, 22, 0), +	SND_SOC_DAPM_PGA("DAC PGA", MC13783_AUDIO_RX1, 5, 0, NULL, 0),  };  static struct snd_soc_dapm_route mc13783_routes[] = { @@ -581,8 +585,6 @@ static int mc13783_probe(struct snd_soc_codec *codec)  {  	struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec); -	codec->control_data = priv->mc13xxx; -  	mc13xxx_lock(priv->mc13xxx);  	/* these are the reset values */ diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 8d717f4b5a8..0935bfe6247 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -24,6 +24,7 @@  #include <linux/delay.h>  #include <linux/pm.h>  #include <linux/i2c.h> +#include <linux/regmap.h>  #include <linux/regulator/consumer.h>  #include <linux/slab.h>  #include <linux/workqueue.h> @@ -55,12 +56,50 @@  	 SNDRV_PCM_FMTBIT_S32_LE  | SNDRV_PCM_FMTBIT_S32_BE)  /* Power-up register defaults */ -static const u8 sta32x_regs[STA32X_REGISTER_COUNT] = { -	0x63, 0x80, 0xc2, 0x40, 0xc2, 0x5c, 0x10, 0xff, 0x60, 0x60, -	0x60, 0x80, 0x00, 0x00, 0x00, 0x40, 0x80, 0x77, 0x6a, 0x69, -	0x6a, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, -	0xc0, 0xf3, 0x33, 0x00, 0x0c, +static const struct reg_default sta32x_regs[] = { +	{  0x0, 0x63 }, +	{  0x1, 0x80 }, +	{  0x2, 0xc2 }, +	{  0x3, 0x40 }, +	{  0x4, 0xc2 }, +	{  0x5, 0x5c }, +	{  0x6, 0x10 }, +	{  0x7, 0xff }, +	{  0x8, 0x60 }, +	{  0x9, 0x60 }, +	{  0xa, 0x60 }, +	{  0xb, 0x80 }, +	{  0xc, 0x00 }, +	{  0xd, 0x00 }, +	{  0xe, 0x00 }, +	{  0xf, 0x40 }, +	{ 0x10, 0x80 }, +	{ 0x11, 0x77 }, +	{ 0x12, 0x6a }, +	{ 0x13, 0x69 }, +	{ 0x14, 0x6a }, +	{ 0x15, 0x69 }, +	{ 0x16, 0x00 }, +	{ 0x17, 0x00 }, +	{ 0x18, 0x00 }, +	{ 0x19, 0x00 }, +	{ 0x1a, 0x00 }, +	{ 0x1b, 0x00 }, +	{ 0x1c, 0x00 }, +	{ 0x1d, 0x00 }, +	{ 0x1e, 0x00 }, +	{ 0x1f, 0x00 }, +	{ 0x20, 0x00 }, +	{ 0x21, 0x00 }, +	{ 0x22, 0x00 }, +	{ 0x23, 0x00 }, +	{ 0x24, 0x00 }, +	{ 0x25, 0x00 }, +	{ 0x26, 0x00 }, +	{ 0x27, 0x2d }, +	{ 0x28, 0xc0 }, +	{ 0x2b, 0x00 }, +	{ 0x2c, 0x0c },  };  /* regulator power supply names */ @@ -72,6 +111,7 @@ static const char *sta32x_supply_names[] = {  /* codec private data */  struct sta32x_priv { +	struct regmap *regmap;  	struct regulator_bulk_data supplies[ARRAY_SIZE(sta32x_supply_names)];  	struct snd_soc_codec *codec;  	struct sta32x_platform_data *pdata; @@ -291,17 +331,15 @@ static int sta32x_sync_coef_shadow(struct snd_soc_codec *codec)  static int sta32x_cache_sync(struct snd_soc_codec *codec)  { +	struct sta32x_priv *sta32x = codec->control_data;  	unsigned int mute;  	int rc; -	if (!codec->cache_sync) -		return 0; -  	/* mute during register sync */  	mute = snd_soc_read(codec, STA32X_MMUTE);  	snd_soc_write(codec, STA32X_MMUTE, mute | STA32X_MMUTE_MMUTE);  	sta32x_sync_coef_shadow(codec); -	rc = snd_soc_cache_sync(codec); +	rc = regcache_sync(sta32x->regmap);  	snd_soc_write(codec, STA32X_MMUTE, mute);  	return rc;  } @@ -316,11 +354,11 @@ static void sta32x_watchdog(struct work_struct *work)  	/* check if sta32x has reset itself */  	confa_cached = snd_soc_read(codec, STA32X_CONFA); -	codec->cache_bypass = 1; +	regcache_cache_bypass(sta32x->regmap, true);  	confa = snd_soc_read(codec, STA32X_CONFA); -	codec->cache_bypass = 0; +	regcache_cache_bypass(sta32x->regmap, false);  	if (confa != confa_cached) { -		codec->cache_sync = 1; +		regcache_mark_dirty(sta32x->regmap);  		sta32x_cache_sync(codec);  	} @@ -825,31 +863,21 @@ static int sta32x_probe(struct snd_soc_codec *codec)  	sta32x->codec = codec;  	sta32x->pdata = dev_get_platdata(codec->dev); -	/* regulators */ -	for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++) -		sta32x->supplies[i].supply = sta32x_supply_names[i]; - -	ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sta32x->supplies), -				 sta32x->supplies); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to request supplies: %d\n", ret); -		goto err; -	} -  	ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),  				    sta32x->supplies);  	if (ret != 0) {  		dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); -		goto err_get; +		return ret;  	}  	/* Tell ASoC what kind of I/O to use to read the registers.  ASoC will  	 * then do the I2C transactions itself.  	 */ -	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); +	codec->control_data = sta32x->regmap; +	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);  	if (ret < 0) {  		dev_err(codec->dev, "failed to set cache I/O (ret=%i)\n", ret); -		return ret; +		goto err;  	}  	/* Chip documentation explicitly requires that the reset values @@ -858,13 +886,15 @@ static int sta32x_probe(struct snd_soc_codec *codec)  	 * so the write to the these registers are suppressed by the cache  	 * restore code when it skips writes of default registers.  	 */ -	snd_soc_cache_write(codec, STA32X_CONFC, 0xc2); -	snd_soc_cache_write(codec, STA32X_CONFE, 0xc2); -	snd_soc_cache_write(codec, STA32X_CONFF, 0x5c); -	snd_soc_cache_write(codec, STA32X_MMUTE, 0x10); -	snd_soc_cache_write(codec, STA32X_AUTO1, 0x60); -	snd_soc_cache_write(codec, STA32X_AUTO3, 0x00); -	snd_soc_cache_write(codec, STA32X_C3CFG, 0x40); +	regcache_cache_only(sta32x->regmap, true); +	snd_soc_write(codec, STA32X_CONFC, 0xc2); +	snd_soc_write(codec, STA32X_CONFE, 0xc2); +	snd_soc_write(codec, STA32X_CONFF, 0x5c); +	snd_soc_write(codec, STA32X_MMUTE, 0x10); +	snd_soc_write(codec, STA32X_AUTO1, 0x60); +	snd_soc_write(codec, STA32X_AUTO3, 0x00); +	snd_soc_write(codec, STA32X_C3CFG, 0x40); +	regcache_cache_only(sta32x->regmap, false);  	/* set thermal warning adjustment and recovery */  	if (!(sta32x->pdata->thermal_conf & STA32X_THERMAL_ADJUSTMENT_ENABLE)) @@ -915,9 +945,8 @@ static int sta32x_probe(struct snd_soc_codec *codec)  	return 0; -err_get: -	regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);  err: +	regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);  	return ret;  } @@ -928,13 +957,11 @@ static int sta32x_remove(struct snd_soc_codec *codec)  	sta32x_watchdog_stop(sta32x);  	sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF);  	regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); -	regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);  	return 0;  } -static int sta32x_reg_is_volatile(struct snd_soc_codec *codec, -				  unsigned int reg) +static bool sta32x_reg_is_volatile(struct device *dev, unsigned int reg)  {  	switch (reg) {  	case STA32X_CONFA ... STA32X_L2ATRT: @@ -949,10 +976,6 @@ static const struct snd_soc_codec_driver sta32x_codec = {  	.remove =		sta32x_remove,  	.suspend =		sta32x_suspend,  	.resume =		sta32x_resume, -	.reg_cache_size =	STA32X_REGISTER_COUNT, -	.reg_word_size =	sizeof(u8), -	.reg_cache_default =	sta32x_regs, -	.volatile_register =	sta32x_reg_is_volatile,  	.set_bias_level =	sta32x_set_bias_level,  	.controls =		sta32x_snd_controls,  	.num_controls =		ARRAY_SIZE(sta32x_snd_controls), @@ -962,17 +985,45 @@ static const struct snd_soc_codec_driver sta32x_codec = {  	.num_dapm_routes =	ARRAY_SIZE(sta32x_dapm_routes),  }; +static const struct regmap_config sta32x_regmap = { +	.reg_bits =		8, +	.val_bits =		8, +	.max_register =		STA32X_FDRC2, +	.reg_defaults =		sta32x_regs, +	.num_reg_defaults =	ARRAY_SIZE(sta32x_regs), +	.cache_type =		REGCACHE_RBTREE, +	.volatile_reg =		sta32x_reg_is_volatile, +}; +  static __devinit int sta32x_i2c_probe(struct i2c_client *i2c,  				      const struct i2c_device_id *id)  {  	struct sta32x_priv *sta32x; -	int ret; +	int ret, i;  	sta32x = devm_kzalloc(&i2c->dev, sizeof(struct sta32x_priv),  			      GFP_KERNEL);  	if (!sta32x)  		return -ENOMEM; +	/* regulators */ +	for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++) +		sta32x->supplies[i].supply = sta32x_supply_names[i]; + +	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(sta32x->supplies), +				      sta32x->supplies); +	if (ret != 0) { +		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); +		return ret; +	} + +	sta32x->regmap = devm_regmap_init_i2c(i2c, &sta32x_regmap); +	if (IS_ERR(sta32x->regmap)) { +		ret = PTR_ERR(sta32x->regmap); +		dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret); +		return ret; +	} +  	i2c_set_clientdata(i2c, sta32x);  	ret = snd_soc_register_codec(&i2c->dev, &sta32x_codec, &sta32x_dai, 1); @@ -1006,17 +1057,7 @@ static struct i2c_driver sta32x_i2c_driver = {  	.id_table = sta32x_i2c_id,  }; -static int __init sta32x_init(void) -{ -	return i2c_add_driver(&sta32x_i2c_driver); -} -module_init(sta32x_init); - -static void __exit sta32x_exit(void) -{ -	i2c_del_driver(&sta32x_i2c_driver); -} -module_exit(sta32x_exit); +module_i2c_driver(sta32x_i2c_driver);  MODULE_DESCRIPTION("ASoC STA32X driver");  MODULE_AUTHOR("Johannes Stezenbach <js@sig21.net>"); diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index 0c225cd569d..9e314486238 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c @@ -358,7 +358,7 @@ static int sta529_resume(struct snd_soc_codec *codec)  	return 0;  } -struct snd_soc_codec_driver sta529_codec_driver = { +static const struct snd_soc_codec_driver sta529_codec_driver = {  	.probe = sta529_probe,  	.remove = sta529_remove,  	.set_bias_level = sta529_set_bias_level, diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index 33c0f3d39c8..982e437799a 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -340,7 +340,6 @@ static int stac9766_codec_probe(struct snd_soc_codec *codec)  	printk(KERN_INFO "STAC9766 SoC Audio Codec %s\n", STAC9766_VERSION); -	codec->control_data = codec;	/* we don't use regmap! */  	ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);  	if (ret < 0)  		goto codec_err; diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c index 85944e95357..b1f6982c7c9 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c @@ -444,14 +444,4 @@ static struct spi_driver aic26_spi = {  	.remove = aic26_spi_remove,  }; -static int __init aic26_init(void) -{ -	return spi_register_driver(&aic26_spi); -} -module_init(aic26_init); - -static void __exit aic26_exit(void) -{ -	spi_unregister_driver(&aic26_spi); -} -module_exit(aic26_exit); +module_spi_driver(aic26_spi); diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index b0a73d37ed5..f230292ba96 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -746,24 +746,7 @@ static struct i2c_driver aic32x4_i2c_driver = {  	.id_table = aic32x4_i2c_id,  }; -static int __init aic32x4_modinit(void) -{ -	int ret = 0; - -	ret = i2c_add_driver(&aic32x4_i2c_driver); -	if (ret != 0) { -		printk(KERN_ERR "Failed to register aic32x4 I2C driver: %d\n", -		       ret); -	} -	return ret; -} -module_init(aic32x4_modinit); - -static void __exit aic32x4_exit(void) -{ -	i2c_del_driver(&aic32x4_i2c_driver); -} -module_exit(aic32x4_exit); +module_i2c_driver(aic32x4_i2c_driver);  MODULE_DESCRIPTION("ASoC tlv320aic32x4 codec driver");  MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>"); diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index dc78f5a4bcb..5708a973a77 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -40,6 +40,7 @@  #include <linux/i2c.h>  #include <linux/gpio.h>  #include <linux/regulator/consumer.h> +#include <linux/of_gpio.h>  #include <linux/slab.h>  #include <sound/core.h>  #include <sound/pcm.h> @@ -1457,6 +1458,8 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,  {  	struct aic3x_pdata *pdata = i2c->dev.platform_data;  	struct aic3x_priv *aic3x; +	struct aic3x_setup_data *ai3x_setup; +	struct device_node *np = i2c->dev.of_node;  	int ret;  	aic3x = devm_kzalloc(&i2c->dev, sizeof(struct aic3x_priv), GFP_KERNEL); @@ -1471,6 +1474,25 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,  	if (pdata) {  		aic3x->gpio_reset = pdata->gpio_reset;  		aic3x->setup = pdata->setup; +	} else if (np) { +		ai3x_setup = devm_kzalloc(&i2c->dev, sizeof(*ai3x_setup), +								GFP_KERNEL); +		if (ai3x_setup == NULL) { +			dev_err(&i2c->dev, "failed to create private data\n"); +			return -ENOMEM; +		} + +		ret = of_get_named_gpio(np, "gpio-reset", 0); +		if (ret >= 0) +			aic3x->gpio_reset = ret; +		else +			aic3x->gpio_reset = -1; + +		if (of_property_read_u32_array(np, "ai3x-gpio-func", +					ai3x_setup->gpio_func, 2) >= 0) { +			aic3x->setup = ai3x_setup; +		} +  	} else {  		aic3x->gpio_reset = -1;  	} @@ -1488,34 +1510,27 @@ static int aic3x_i2c_remove(struct i2c_client *client)  	return 0;  } +#if defined(CONFIG_OF) +static const struct of_device_id tlv320aic3x_of_match[] = { +	{ .compatible = "ti,tlv320aic3x", }, +	{}, +}; +MODULE_DEVICE_TABLE(of, tlv320aic3x_of_match); +#endif +  /* machine i2c codec control layer */  static struct i2c_driver aic3x_i2c_driver = {  	.driver = {  		.name = "tlv320aic3x-codec",  		.owner = THIS_MODULE, +		.of_match_table = of_match_ptr(tlv320aic3x_of_match),  	},  	.probe	= aic3x_i2c_probe,  	.remove = aic3x_i2c_remove,  	.id_table = aic3x_i2c_id,  }; -static int __init aic3x_modinit(void) -{ -	int ret = 0; -	ret = i2c_add_driver(&aic3x_i2c_driver); -	if (ret != 0) { -		printk(KERN_ERR "Failed to register TLV320AIC3x I2C driver: %d\n", -		       ret); -	} -	return ret; -} -module_init(aic3x_modinit); - -static void __exit aic3x_exit(void) -{ -	i2c_del_driver(&aic3x_i2c_driver); -} -module_exit(aic3x_exit); +module_i2c_driver(aic3x_i2c_driver);  MODULE_DESCRIPTION("ASoC TLV320AIC3X codec driver");  MODULE_AUTHOR("Vladimir Barinov"); diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 0dd41077ab7..d2e16c5d7d1 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -1621,24 +1621,7 @@ static struct i2c_driver tlv320dac33_i2c_driver = {  	.id_table	= tlv320dac33_i2c_id,  }; -static int __init dac33_module_init(void) -{ -	int r; -	r = i2c_add_driver(&tlv320dac33_i2c_driver); -	if (r < 0) { -		printk(KERN_ERR "DAC33: driver registration failed\n"); -		return r; -	} -	return 0; -} -module_init(dac33_module_init); - -static void __exit dac33_module_exit(void) -{ -	i2c_del_driver(&tlv320dac33_i2c_driver); -} -module_exit(dac33_module_exit); - +module_i2c_driver(tlv320dac33_i2c_driver);  MODULE_DESCRIPTION("ASoC TLV320DAC33 codec driver");  MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index 6fe4aa3ac54..565ff39ad3a 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c @@ -487,19 +487,8 @@ static struct i2c_driver tpa6130a2_i2c_driver = {  	.id_table = tpa6130a2_id,  }; -static int __init tpa6130a2_init(void) -{ -	return i2c_add_driver(&tpa6130a2_i2c_driver); -} - -static void __exit tpa6130a2_exit(void) -{ -	i2c_del_driver(&tpa6130a2_i2c_driver); -} +module_i2c_driver(tpa6130a2_i2c_driver);  MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");  MODULE_DESCRIPTION("TPA6130A2 Headphone amplifier driver");  MODULE_LICENSE("GPL"); - -module_init(tpa6130a2_init); -module_exit(tpa6130a2_exit); diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 391fcfc7b63..e7f608996c4 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -26,8 +26,11 @@  #include <linux/pm.h>  #include <linux/i2c.h>  #include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/of_gpio.h>  #include <linux/i2c/twl.h>  #include <linux/slab.h> +#include <linux/gpio.h>  #include <sound/core.h>  #include <sound/pcm.h>  #include <sound/pcm_params.h> @@ -152,8 +155,7 @@ struct twl4030_priv {  	u8 predrivel_enabled, predriver_enabled;  	u8 carkitl_enabled, carkitr_enabled; -	/* Delay needed after enabling the digimic interface */ -	unsigned int digimic_delay; +	struct twl4030_codec_data *pdata;  };  /* @@ -295,13 +297,73 @@ static inline void twl4030_reset_registers(struct snd_soc_codec *codec)  } -static void twl4030_init_chip(struct snd_soc_codec *codec) +static void twl4030_setup_pdata_of(struct twl4030_codec_data *pdata, +				   struct device_node *node) +{ +	int value; + +	of_property_read_u32(node, "ti,digimic_delay", +			     &pdata->digimic_delay); +	of_property_read_u32(node, "ti,ramp_delay_value", +			     &pdata->ramp_delay_value); +	of_property_read_u32(node, "ti,offset_cncl_path", +			     &pdata->offset_cncl_path); +	if (!of_property_read_u32(node, "ti,hs_extmute", &value)) +		pdata->hs_extmute = value; + +	pdata->hs_extmute_gpio = of_get_named_gpio(node, +						   "ti,hs_extmute_gpio", 0); +	if (gpio_is_valid(pdata->hs_extmute_gpio)) +		pdata->hs_extmute = 1; +} + +static struct twl4030_codec_data *twl4030_get_pdata(struct snd_soc_codec *codec)  {  	struct twl4030_codec_data *pdata = dev_get_platdata(codec->dev); +	struct device_node *twl4030_codec_node = NULL; + +	twl4030_codec_node = of_find_node_by_name(codec->dev->parent->of_node, +						  "codec"); + +	if (!pdata && twl4030_codec_node) { +		pdata = devm_kzalloc(codec->dev, +				     sizeof(struct twl4030_codec_data), +				     GFP_KERNEL); +		if (!pdata) { +			dev_err(codec->dev, "Can not allocate memory\n"); +			return NULL; +		} +		twl4030_setup_pdata_of(pdata, twl4030_codec_node); +	} + +	return pdata; +} + +static void twl4030_init_chip(struct snd_soc_codec *codec) +{ +	struct twl4030_codec_data *pdata;  	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);  	u8 reg, byte;  	int i = 0; +	pdata = twl4030_get_pdata(codec); + +	if (pdata && pdata->hs_extmute && +	    gpio_is_valid(pdata->hs_extmute_gpio)) { +		int ret; + +		if (!pdata->hs_extmute_gpio) +			dev_warn(codec->dev, +				 "Extmute GPIO is 0 is this correct?\n"); + +		ret = gpio_request_one(pdata->hs_extmute_gpio, +				       GPIOF_OUT_INIT_LOW, "hs_extmute"); +		if (ret) { +			dev_err(codec->dev, "Failed to get hs_extmute GPIO\n"); +			pdata->hs_extmute_gpio = -1; +		} +	} +  	/* Check defaults, if instructed before anything else */  	if (pdata && pdata->check_defaults)  		twl4030_check_defaults(codec); @@ -331,7 +393,7 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)  	if (!pdata)  		return; -	twl4030->digimic_delay = pdata->digimic_delay; +	twl4030->pdata = pdata;  	reg = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);  	reg &= ~TWL4030_RAMP_DELAY; @@ -732,9 +794,9 @@ static int aif_event(struct snd_soc_dapm_widget *w,  static void headset_ramp(struct snd_soc_codec *codec, int ramp)  { -	struct twl4030_codec_data *pdata = codec->dev->platform_data;  	unsigned char hs_gain, hs_pop;  	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); +	struct twl4030_codec_data *pdata = twl4030->pdata;  	/* Base values for ramp delay calculation: 2^19 - 2^26 */  	unsigned int ramp_base[] = {524288, 1048576, 2097152, 4194304,  				    8388608, 16777216, 33554432, 67108864}; @@ -748,8 +810,8 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)  	/* Enable external mute control, this dramatically reduces  	 * the pop-noise */  	if (pdata && pdata->hs_extmute) { -		if (pdata->set_hs_extmute) { -			pdata->set_hs_extmute(1); +		if (gpio_is_valid(pdata->hs_extmute_gpio)) { +			gpio_set_value(pdata->hs_extmute_gpio, 1);  		} else {  			hs_pop |= TWL4030_EXTMUTE;  			twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); @@ -786,8 +848,8 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)  	/* Disable external mute */  	if (pdata && pdata->hs_extmute) { -		if (pdata->set_hs_extmute) { -			pdata->set_hs_extmute(0); +		if (gpio_is_valid(pdata->hs_extmute_gpio)) { +			gpio_set_value(pdata->hs_extmute_gpio, 0);  		} else {  			hs_pop &= ~TWL4030_EXTMUTE;  			twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); @@ -847,9 +909,10 @@ static int digimic_event(struct snd_soc_dapm_widget *w,  		struct snd_kcontrol *kcontrol, int event)  {  	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec); +	struct twl4030_codec_data *pdata = twl4030->pdata; -	if (twl4030->digimic_delay) -		twl4030_wait_ms(twl4030->digimic_delay); +	if (pdata && pdata->digimic_delay) +		twl4030_wait_ms(pdata->digimic_delay);  	return 0;  } @@ -999,7 +1062,7 @@ static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol,  	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);  	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;  	unsigned short val; -	unsigned short mask, bitmask; +	unsigned short mask;  	if (twl4030->configured) {  		dev_err(codec->dev, @@ -1007,18 +1070,16 @@ static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol,  		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; +	mask = e->mask << 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; +		mask |= e->mask << e->shift_r;  	}  	return snd_soc_update_bits(codec, e->reg, mask, val); @@ -1239,16 +1300,11 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {  	SND_SOC_DAPM_OUTPUT("Virtual Voice OUT"),  	/* DACs */ -	SND_SOC_DAPM_DAC("DAC Right1", "Right Front HiFi Playback", -			SND_SOC_NOPM, 0, 0), -	SND_SOC_DAPM_DAC("DAC Left1", "Left Front HiFi Playback", -			SND_SOC_NOPM, 0, 0), -	SND_SOC_DAPM_DAC("DAC Right2", "Right Rear HiFi 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_NOPM, 0, 0), +	SND_SOC_DAPM_DAC("DAC Right1", NULL, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_DAC("DAC Left1", NULL, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_DAC("DAC Right2", NULL, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_DAC("DAC Left2", NULL, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_DAC("DAC Voice", NULL, SND_SOC_NOPM, 0, 0),  	/* Analog bypasses */  	SND_SOC_DAPM_SWITCH("Right1 Analog Loopback", SND_SOC_NOPM, 0, 0, @@ -1377,14 +1433,10 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {  	/* Introducing four virtual ADC, since TWL4030 have four channel for  	   capture */ -	SND_SOC_DAPM_ADC("ADC Virtual Left1", "Left Front Capture", -		SND_SOC_NOPM, 0, 0), -	SND_SOC_DAPM_ADC("ADC Virtual Right1", "Right Front Capture", -		SND_SOC_NOPM, 0, 0), -	SND_SOC_DAPM_ADC("ADC Virtual Left2", "Left Rear Capture", -		SND_SOC_NOPM, 0, 0), -	SND_SOC_DAPM_ADC("ADC Virtual Right2", "Right Rear Capture", -		SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_ADC("ADC Virtual Left1", NULL, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_ADC("ADC Virtual Right1", NULL, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_ADC("ADC Virtual Left2", NULL, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_ADC("ADC Virtual Right2", NULL, SND_SOC_NOPM, 0, 0),  	/* Analog/Digital mic path selection.  	   TX1 Left/Right: either analog Left/Right or Digimic0 @@ -1428,6 +1480,23 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {  };  static const struct snd_soc_dapm_route intercon[] = { +	/* Stream -> DAC mapping */ +	{"DAC Right1", NULL, "HiFi Playback"}, +	{"DAC Left1", NULL, "HiFi Playback"}, +	{"DAC Right2", NULL, "HiFi Playback"}, +	{"DAC Left2", NULL, "HiFi Playback"}, +	{"DAC Voice", NULL, "Voice Playback"}, + +	/* ADC -> Stream mapping */ +	{"HiFi Capture", NULL, "ADC Virtual Left1"}, +	{"HiFi Capture", NULL, "ADC Virtual Right1"}, +	{"HiFi Capture", NULL, "ADC Virtual Left2"}, +	{"HiFi Capture", NULL, "ADC Virtual Right2"}, +	{"Voice Capture", NULL, "ADC Virtual Left1"}, +	{"Voice Capture", NULL, "ADC Virtual Right1"}, +	{"Voice Capture", NULL, "ADC Virtual Left2"}, +	{"Voice Capture", NULL, "ADC Virtual Right2"}, +  	{"Digital L1 Playback Mixer", NULL, "DAC Left1"},  	{"Digital R1 Playback Mixer", NULL, "DAC Right1"},  	{"Digital L2 Playback Mixer", NULL, "DAC Left2"}, @@ -2172,7 +2241,7 @@ static struct snd_soc_dai_driver twl4030_dai[] = {  		.formats = TWL4030_FORMATS,  		.sig_bits = 24,},  	.capture = { -		.stream_name = "Capture", +		.stream_name = "HiFi Capture",  		.channels_min = 2,  		.channels_max = 4,  		.rates = TWL4030_RATES, @@ -2189,7 +2258,7 @@ static struct snd_soc_dai_driver twl4030_dai[] = {  		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,  		.formats = SNDRV_PCM_FMTBIT_S16_LE,},  	.capture = { -		.stream_name = "Capture", +		.stream_name = "Voice Capture",  		.channels_min = 1,  		.channels_max = 2,  		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, @@ -2214,7 +2283,8 @@ static int twl4030_soc_probe(struct snd_soc_codec *codec)  {  	struct twl4030_priv *twl4030; -	twl4030 = kzalloc(sizeof(struct twl4030_priv), GFP_KERNEL); +	twl4030 = devm_kzalloc(codec->dev, sizeof(struct twl4030_priv), +			       GFP_KERNEL);  	if (twl4030 == NULL) {  		dev_err(codec->dev, "Can not allocate memory\n");  		return -ENOMEM; @@ -2231,11 +2301,15 @@ static int twl4030_soc_probe(struct snd_soc_codec *codec)  static int twl4030_soc_remove(struct snd_soc_codec *codec)  {  	struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); +	struct twl4030_codec_data *pdata = twl4030->pdata;  	/* Reset registers to their chip default before leaving */  	twl4030_reset_registers(codec);  	twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); -	kfree(twl4030); + +	if (pdata && pdata->hs_extmute && gpio_is_valid(pdata->hs_extmute_gpio)) +		gpio_free(pdata->hs_extmute_gpio); +  	return 0;  } @@ -2262,13 +2336,6 @@ static struct snd_soc_codec_driver soc_codec_dev_twl4030 = {  static int __devinit twl4030_codec_probe(struct platform_device *pdev)  { -	struct twl4030_codec_data *pdata = pdev->dev.platform_data; - -	if (!pdata) { -		dev_err(&pdev->dev, "platform_data is missing\n"); -		return -EINVAL; -	} -  	return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_twl4030,  			twl4030_dai, ARRAY_SIZE(twl4030_dai));  } diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index c084c549942..e8f97af7592 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -727,10 +727,8 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {  			TWL6040_REG_MICRCTL, 1, 0, NULL, 0),  	/* ADCs */ -	SND_SOC_DAPM_ADC("ADC Left", "Left Front Capture", -			TWL6040_REG_MICLCTL, 2, 0), -	SND_SOC_DAPM_ADC("ADC Right", "Right Front Capture", -			TWL6040_REG_MICRCTL, 2, 0), +	SND_SOC_DAPM_ADC("ADC Left", NULL, TWL6040_REG_MICLCTL, 2, 0), +	SND_SOC_DAPM_ADC("ADC Right", NULL, TWL6040_REG_MICRCTL, 2, 0),  	/* Microphone bias */  	SND_SOC_DAPM_SUPPLY("Headset Mic Bias", @@ -743,15 +741,12 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {  			    TWL6040_REG_DMICBCTL, 4, 0, NULL, 0),  	/* DACs */ -	SND_SOC_DAPM_DAC("HSDAC Left", "Headset Playback", SND_SOC_NOPM, 0, 0), -	SND_SOC_DAPM_DAC("HSDAC Right", "Headset Playback", SND_SOC_NOPM, 0, 0), -	SND_SOC_DAPM_DAC("HFDAC Left", "Handsfree Playback", -			 TWL6040_REG_HFLCTL, 0, 0), -	SND_SOC_DAPM_DAC("HFDAC Right", "Handsfree Playback", -			 TWL6040_REG_HFRCTL, 0, 0), +	SND_SOC_DAPM_DAC("HSDAC Left", NULL, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_DAC("HSDAC Right", NULL, SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_DAC("HFDAC Left", NULL, TWL6040_REG_HFLCTL, 0, 0), +	SND_SOC_DAPM_DAC("HFDAC Right", NULL, TWL6040_REG_HFRCTL, 0, 0),  	/* Virtual DAC for vibra path (DL4 channel) */ -	SND_SOC_DAPM_DAC("VIBRA DAC", "Vibra Playback", -			SND_SOC_NOPM, 0, 0), +	SND_SOC_DAPM_DAC("VIBRA DAC", NULL, SND_SOC_NOPM, 0, 0),  	SND_SOC_DAPM_MUX("Handsfree Left Playback",  			SND_SOC_NOPM, 0, 0, &hfl_mux_controls), @@ -810,6 +805,26 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {  };  static const struct snd_soc_dapm_route intercon[] = { +	/* Stream -> DAC mapping */ +	{"HSDAC Left", NULL, "Legacy Playback"}, +	{"HSDAC Left", NULL, "Headset Playback"}, +	{"HSDAC Right", NULL, "Legacy Playback"}, +	{"HSDAC Right", NULL, "Headset Playback"}, + +	{"HFDAC Left", NULL, "Legacy Playback"}, +	{"HFDAC Left", NULL, "Handsfree Playback"}, +	{"HFDAC Right", NULL, "Legacy Playback"}, +	{"HFDAC Right", NULL, "Handsfree Playback"}, + +	{"VIBRA DAC", NULL, "Legacy Playback"}, +	{"VIBRA DAC", NULL, "Vibra Playback"}, + +	/* ADC -> Stream mapping */ +	{"ADC Left", NULL, "Legacy Capture"}, +	{"ADC Left", NULL, "Capture"}, +	{"ADC Right", NULL, "Legacy Capture"}, +	{"ADC Right", NULL, "Capture"}, +  	/* Capture path */  	{"Analog Left Capture Route", "Headset Mic", "HSMIC"},  	{"Analog Left Capture Route", "Main Mic", "MAINMIC"}, @@ -1028,14 +1043,14 @@ static struct snd_soc_dai_driver twl6040_dai[] = {  {  	.name = "twl6040-legacy",  	.playback = { -		.stream_name = "Playback", +		.stream_name = "Legacy Playback",  		.channels_min = 1,  		.channels_max = 5,  		.rates = TWL6040_RATES,  		.formats = TWL6040_FORMATS,  	},  	.capture = { -		.stream_name = "Capture", +		.stream_name = "Legacy Capture",  		.channels_min = 1,  		.channels_max = 2,  		.rates = TWL6040_RATES, diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c new file mode 100644 index 00000000000..99afc003a08 --- /dev/null +++ b/sound/soc/codecs/wm0010.c @@ -0,0 +1,940 @@ +/* + * wm0010.c  --  WM0010 DSP Driver + * + * Copyright 2012 Wolfson Microelectronics PLC. + * + * Authors: Mark Brown <broonie@opensource.wolfsonmicro.com> + *          Dimitris Papastamos <dp@opensource.wolfsonmicro.com> + *          Scott Ling <sl@opensource.wolfsonmicro.com> + * + * 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 <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/irqreturn.h> +#include <linux/init.h> +#include <linux/spi/spi.h> +#include <linux/firmware.h> +#include <linux/delay.h> +#include <linux/fs.h> +#include <linux/miscdevice.h> +#include <linux/gpio.h> +#include <linux/regulator/consumer.h> +#include <linux/mutex.h> +#include <linux/workqueue.h> + +#include <sound/soc.h> +#include <sound/wm0010.h> + +#define DEVICE_ID_WM0010	10 + +enum dfw_cmd { +	DFW_CMD_FUSE = 0x01, +	DFW_CMD_CODE_HDR, +	DFW_CMD_CODE_DATA, +	DFW_CMD_PLL, +	DFW_CMD_INFO = 0xff +}; + +struct dfw_binrec { +	u8 command; +	u32 length:24; +	u32 address; +	uint8_t data[0]; +} __packed; + +struct dfw_pllrec { +	u8 command; +	u32 length:24; +	u32 address; +	u32 clkctrl1; +	u32 clkctrl2; +	u32 clkctrl3; +	u32 ldetctrl; +	u32 uart_div; +	u32 spi_div; +} __packed; + +static struct pll_clock_map { +	int max_sysclk; +	int max_pll_spi_speed; +	u32 pll_clkctrl1; +} pll_clock_map[] = {			   /* Dividers */ +	{ 22000000, 26000000, 0x00201f11 }, /* 2,32,2  */ +	{ 18000000, 26000000, 0x00203f21 }, /* 2,64,4  */ +	{ 14000000, 26000000, 0x00202620 }, /* 1,39,4  */ +	{ 10000000, 22000000, 0x00203120 }, /* 1,50,4  */ +	{  6500000, 22000000, 0x00204520 }, /* 1,70,4  */ +	{  5500000, 22000000, 0x00103f10 }, /* 1,64,2  */ +}; + +enum wm0010_state { +	WM0010_POWER_OFF, +	WM0010_OUT_OF_RESET, +	WM0010_BOOTROM, +	WM0010_STAGE2, +	WM0010_FIRMWARE, +}; + +struct wm0010_priv { +	struct snd_soc_codec *codec; + +	struct mutex lock; +	struct device *dev; + +	struct wm0010_pdata pdata; + +	int gpio_reset; +	int gpio_reset_value; + +	struct regulator_bulk_data core_supplies[2]; +	struct regulator *dbvdd; + +	int sysclk; + +	enum wm0010_state state; +	bool boot_failed; +	int boot_done; +	bool ready; +	bool pll_running; +	int max_spi_freq; +	int board_max_spi_speed; +	u32 pll_clkctrl1; + +	spinlock_t irq_lock; +	int irq; + +	struct completion boot_completion; +}; + +struct wm0010_spi_msg { +	struct spi_message m; +	struct spi_transfer t; +	u8 *tx_buf; +	u8 *rx_buf; +	size_t len; +}; + +static const struct snd_soc_dapm_widget wm0010_dapm_widgets[] = { +SND_SOC_DAPM_SUPPLY("CLKIN",  SND_SOC_NOPM, 0, 0, NULL, 0), +}; + +static const struct snd_soc_dapm_route wm0010_dapm_routes[] = { +	{ "SDI2 Capture", NULL, "SDI1 Playback" }, +	{ "SDI1 Capture", NULL, "SDI2 Playback" }, + +	{ "SDI1 Capture", NULL, "CLKIN" }, +	{ "SDI2 Capture", NULL, "CLKIN" }, +	{ "SDI1 Playback", NULL, "CLKIN" }, +	{ "SDI2 Playback", NULL, "CLKIN" }, +}; + +static const char *wm0010_state_to_str(enum wm0010_state state) +{ +	const char *state_to_str[] = { +		"Power off", +		"Out of reset", +		"Boot ROM", +		"Stage2", +		"Firmware" +	}; + +	if (state < 0 || state >= ARRAY_SIZE(state_to_str)) +		return "null"; +	return state_to_str[state]; +} + +/* Called with wm0010->lock held */ +static void wm0010_halt(struct snd_soc_codec *codec) +{ +	struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec); +	unsigned long flags; +	enum wm0010_state state; + +	/* Fetch the wm0010 state */ +	spin_lock_irqsave(&wm0010->irq_lock, flags); +	state = wm0010->state; +	spin_unlock_irqrestore(&wm0010->irq_lock, flags); + +	switch (state) { +	case WM0010_POWER_OFF: +		/* If there's nothing to do, bail out */ +		return; +	case WM0010_OUT_OF_RESET: +	case WM0010_BOOTROM: +	case WM0010_STAGE2: +	case WM0010_FIRMWARE: +		/* Remember to put chip back into reset */ +		gpio_set_value_cansleep(wm0010->gpio_reset, +					wm0010->gpio_reset_value); +		/* Disable the regulators */ +		regulator_disable(wm0010->dbvdd); +		regulator_bulk_disable(ARRAY_SIZE(wm0010->core_supplies), +				       wm0010->core_supplies); +		break; +	} + +	spin_lock_irqsave(&wm0010->irq_lock, flags); +	wm0010->state = WM0010_POWER_OFF; +	spin_unlock_irqrestore(&wm0010->irq_lock, flags); +} + +struct wm0010_boot_xfer { +	struct list_head list; +	struct snd_soc_codec *codec; +	struct completion *done; +	struct spi_message m; +	struct spi_transfer t; +}; + +/* Called with wm0010->lock held */ +static void wm0010_mark_boot_failure(struct wm0010_priv *wm0010) +{ +	enum wm0010_state state; +	unsigned long flags; + +	spin_lock_irqsave(&wm0010->irq_lock, flags); +	state = wm0010->state; +	spin_unlock_irqrestore(&wm0010->irq_lock, flags); + +	dev_err(wm0010->dev, "Failed to transition from `%s' state to `%s' state\n", +		wm0010_state_to_str(state), wm0010_state_to_str(state + 1)); + +	wm0010->boot_failed = true; +} + +static void wm0010_boot_xfer_complete(void *data) +{ +	struct wm0010_boot_xfer *xfer = data; +	struct snd_soc_codec *codec = xfer->codec; +	struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec); +	u32 *out32 = xfer->t.rx_buf; +	int i; + +	if (xfer->m.status != 0) { +		dev_err(codec->dev, "SPI transfer failed: %d\n", +			xfer->m.status); +		wm0010_mark_boot_failure(wm0010); +		if (xfer->done) +			complete(xfer->done); +		return; +	} + +	for (i = 0; i < xfer->t.len / 4; i++) { +		dev_dbg(codec->dev, "%d: %04x\n", i, out32[i]); + +		switch (be32_to_cpu(out32[i])) { +		case 0xe0e0e0e0: +			dev_err(codec->dev, +				"%d: ROM error reported in stage 2\n", i); +			wm0010_mark_boot_failure(wm0010); +			break; + +		case 0x55555555: +			if (wm0010->boot_done == 0) +				break; +			dev_err(codec->dev, +				"%d: ROM bootloader running in stage 2\n", i); +			wm0010_mark_boot_failure(wm0010); +			break; + +		case 0x0fed0000: +			dev_dbg(codec->dev, "Stage2 loader running\n"); +			break; + +		case 0x0fed0007: +			dev_dbg(codec->dev, "CODE_HDR packet received\n"); +			break; + +		case 0x0fed0008: +			dev_dbg(codec->dev, "CODE_DATA packet received\n"); +			break; + +		case 0x0fed0009: +			dev_dbg(codec->dev, "Download complete\n"); +			break; + +		case 0x0fed000c: +			dev_dbg(codec->dev, "Application start\n"); +			break; + +		case 0x0fed000e: +			dev_dbg(codec->dev, "PLL packet received\n"); +			wm0010->pll_running = true; +			break; + +		case 0x0fed0025: +			dev_err(codec->dev, "Device reports image too long\n"); +			wm0010_mark_boot_failure(wm0010); +			break; + +		case 0x0fed002c: +			dev_err(codec->dev, "Device reports bad SPI packet\n"); +			wm0010_mark_boot_failure(wm0010); +			break; + +		case 0x0fed0031: +			dev_err(codec->dev, "Device reports SPI read overflow\n"); +			wm0010_mark_boot_failure(wm0010); +			break; + +		case 0x0fed0032: +			dev_err(codec->dev, "Device reports SPI underclock\n"); +			wm0010_mark_boot_failure(wm0010); +			break; + +		case 0x0fed0033: +			dev_err(codec->dev, "Device reports bad header packet\n"); +			wm0010_mark_boot_failure(wm0010); +			break; + +		case 0x0fed0034: +			dev_err(codec->dev, "Device reports invalid packet type\n"); +			wm0010_mark_boot_failure(wm0010); +			break; + +		case 0x0fed0035: +			dev_err(codec->dev, "Device reports data before header error\n"); +			wm0010_mark_boot_failure(wm0010); +			break; + +		case 0x0fed0038: +			dev_err(codec->dev, "Device reports invalid PLL packet\n"); +			break; + +		case 0x0fed003a: +			dev_err(codec->dev, "Device reports packet alignment error\n"); +			wm0010_mark_boot_failure(wm0010); +			break; + +		default: +			dev_err(codec->dev, "Unrecognised return 0x%x\n", +			    be32_to_cpu(out32[i])); +			wm0010_mark_boot_failure(wm0010); +			break; +		} + +		if (wm0010->boot_failed) +			break; +	} + +	wm0010->boot_done++; +	if (xfer->done) +		complete(xfer->done); +} + +static void byte_swap_64(u64 *data_in, u64 *data_out, u32 len) +{ +	int i; + +	for (i = 0; i < len / 8; i++) +		data_out[i] = cpu_to_be64(le64_to_cpu(data_in[i])); +} + +static int wm0010_boot(struct snd_soc_codec *codec) +{ +	struct spi_device *spi = to_spi_device(codec->dev); +	struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec); +	unsigned long flags; +	struct list_head xfer_list; +	struct wm0010_boot_xfer *xfer; +	int ret; +	struct completion done; +	const struct firmware *fw; +	const struct dfw_binrec *rec; +	struct spi_message m; +	struct spi_transfer t; +	struct dfw_pllrec pll_rec; +	u32 *img, *p; +	u64 *img_swap; +	u8 *out; +	u32 len, offset; +	int i; + +	spin_lock_irqsave(&wm0010->irq_lock, flags); +	if (wm0010->state != WM0010_POWER_OFF) +		dev_warn(wm0010->dev, "DSP already powered up!\n"); +	spin_unlock_irqrestore(&wm0010->irq_lock, flags); + +	if (wm0010->sysclk > 26000000) { +		dev_err(codec->dev, "Max DSP clock frequency is 26MHz\n"); +		ret = -ECANCELED; +		goto err; +	} + +	INIT_LIST_HEAD(&xfer_list); + +	mutex_lock(&wm0010->lock); +	wm0010->pll_running = false; + +	dev_dbg(codec->dev, "max_spi_freq: %d\n", wm0010->max_spi_freq); + +	ret = regulator_bulk_enable(ARRAY_SIZE(wm0010->core_supplies), +				    wm0010->core_supplies); +	if (ret != 0) { +		dev_err(&spi->dev, "Failed to enable core supplies: %d\n", +			ret); +		mutex_unlock(&wm0010->lock); +		goto err; +	} + +	ret = regulator_enable(wm0010->dbvdd); +	if (ret != 0) { +		dev_err(&spi->dev, "Failed to enable DBVDD: %d\n", ret); +		goto err_core; +	} + +	/* Release reset */ +	gpio_set_value_cansleep(wm0010->gpio_reset, !wm0010->gpio_reset_value); +	spin_lock_irqsave(&wm0010->irq_lock, flags); +	wm0010->state = WM0010_OUT_OF_RESET; +	spin_unlock_irqrestore(&wm0010->irq_lock, flags); + +	/* First the bootloader */ +	ret = request_firmware(&fw, "wm0010_stage2.bin", codec->dev); +	if (ret != 0) { +		dev_err(codec->dev, "Failed to request stage2 loader: %d\n", +			ret); +		goto abort; +	} + +	if (!wait_for_completion_timeout(&wm0010->boot_completion, +					 msecs_to_jiffies(10))) +		dev_err(codec->dev, "Failed to get interrupt from DSP\n"); + +	spin_lock_irqsave(&wm0010->irq_lock, flags); +	wm0010->state = WM0010_BOOTROM; +	spin_unlock_irqrestore(&wm0010->irq_lock, flags); + +	dev_dbg(codec->dev, "Downloading %zu byte stage 2 loader\n", fw->size); + +	/* Copy to local buffer first as vmalloc causes problems for dma */ +	img = kzalloc(fw->size, GFP_KERNEL); +	if (!img) { +		dev_err(codec->dev, "Failed to allocate image buffer\n"); +		goto abort; +	} + +	out = kzalloc(fw->size, GFP_KERNEL); +	if (!out) { +		dev_err(codec->dev, "Failed to allocate output buffer\n"); +		goto abort; +	} + +	memcpy(img, &fw->data[0], fw->size); + +	spi_message_init(&m); +	memset(&t, 0, sizeof(t)); +	t.rx_buf = out; +	t.tx_buf = img; +	t.len = fw->size; +	t.bits_per_word = 8; +	t.speed_hz = wm0010->sysclk / 10; +	spi_message_add_tail(&t, &m); + +	dev_dbg(codec->dev, "Starting initial download at %dHz\n", +		t.speed_hz); + +	ret = spi_sync(spi, &m); +	if (ret != 0) { +		dev_err(codec->dev, "Initial download failed: %d\n", ret); +		goto abort; +	} + +	/* Look for errors from the boot ROM */ +	for (i = 0; i < fw->size; i++) { +		if (out[i] != 0x55) { +			ret = -EBUSY; +			dev_err(codec->dev, "Boot ROM error: %x in %d\n", +				out[i], i); +			wm0010_mark_boot_failure(wm0010); +			goto abort; +		} +	} + +	release_firmware(fw); +	kfree(img); +	kfree(out); + +	if (!wait_for_completion_timeout(&wm0010->boot_completion, +					 msecs_to_jiffies(10))) +		dev_err(codec->dev, "Failed to get interrupt from DSP loader.\n"); + +	spin_lock_irqsave(&wm0010->irq_lock, flags); +	wm0010->state = WM0010_STAGE2; +	spin_unlock_irqrestore(&wm0010->irq_lock, flags); + +	/* Only initialise PLL if max_spi_freq initialised */ +	if (wm0010->max_spi_freq) { + +		/* Initialise a PLL record */ +		memset(&pll_rec, 0, sizeof(pll_rec)); +		pll_rec.command = DFW_CMD_PLL; +		pll_rec.length = (sizeof(pll_rec) - 8); + +		/* On wm0010 only the CLKCTRL1 value is used */ +		pll_rec.clkctrl1 = wm0010->pll_clkctrl1; + +		len = pll_rec.length + 8; +		out = kzalloc(len, GFP_KERNEL); +		if (!out) { +			dev_err(codec->dev, +				"Failed to allocate RX buffer\n"); +			goto abort; +		} + +		img_swap = kzalloc(len, GFP_KERNEL); +		if (!img_swap) { +			dev_err(codec->dev, +				"Failed to allocate image buffer\n"); +			goto abort; +		} + +		/* We need to re-order for 0010 */ +		byte_swap_64((u64 *)&pll_rec, img_swap, len); + +		spi_message_init(&m); +		memset(&t, 0, sizeof(t)); +		t.rx_buf = out; +		t.tx_buf = img_swap; +		t.len = len; +		t.bits_per_word = 8; +		t.speed_hz = wm0010->sysclk / 6; +		spi_message_add_tail(&t, &m); + +		ret = spi_sync(spi, &m); +		if (ret != 0) { +			dev_err(codec->dev, "First PLL write failed: %d\n", ret); +			goto abort; +		} + +		/* Use a second send of the message to get the return status */ +		ret = spi_sync(spi, &m); +		if (ret != 0) { +			dev_err(codec->dev, "Second PLL write failed: %d\n", ret); +			goto abort; +		} + +		p = (u32 *)out; + +		/* Look for PLL active code from the DSP */ +		for (i = 0; i < len / 4; i++) { +			if (*p == 0x0e00ed0f) { +				dev_dbg(codec->dev, "PLL packet received\n"); +				wm0010->pll_running = true; +				break; +			} +			p++; +		} + +		kfree(img_swap); +		kfree(out); +	} else +		dev_dbg(codec->dev, "Not enabling DSP PLL."); + +	ret = request_firmware(&fw, "wm0010.dfw", codec->dev); +	if (ret != 0) { +		dev_err(codec->dev, "Failed to request application: %d\n", +			ret); +		goto abort; +	} + +	rec = (const struct dfw_binrec *)fw->data; +	offset = 0; +	wm0010->boot_done = 0; +	wm0010->boot_failed = false; +	BUG_ON(!list_empty(&xfer_list)); +	init_completion(&done); + +	/* First record should be INFO */ +	if (rec->command != DFW_CMD_INFO) { +		dev_err(codec->dev, "First record not INFO\r\n"); +		goto abort; +	} + +	/* Check it's a 0010 file */ +	if (rec->data[0] != DEVICE_ID_WM0010) { +		dev_err(codec->dev, "Not a WM0010 firmware file.\r\n"); +		goto abort; +	} + +	/* Skip the info record as we don't need to send it */ +	offset += ((rec->length) + 8); +	rec = (void *)&rec->data[rec->length]; + +	while (offset < fw->size) { +		dev_dbg(codec->dev, +			"Packet: command %d, data length = 0x%x\r\n", +			rec->command, rec->length); +		len = rec->length + 8; + +		out = kzalloc(len, GFP_KERNEL); +		if (!out) { +			dev_err(codec->dev, +				"Failed to allocate RX buffer\n"); +			goto abort; +		} + +		img_swap = kzalloc(len, GFP_KERNEL); +		if (!img_swap) { +			dev_err(codec->dev, +				"Failed to allocate image buffer\n"); +			goto abort; +		} + +		/* We need to re-order for 0010 */ +		byte_swap_64((u64 *)&rec->command, img_swap, len); + +		xfer = kzalloc(sizeof(*xfer), GFP_KERNEL); +		if (!xfer) { +			dev_err(codec->dev, "Failed to allocate xfer\n"); +			goto abort; +		} + +		xfer->codec = codec; +		list_add_tail(&xfer->list, &xfer_list); + +		spi_message_init(&xfer->m); +		xfer->m.complete = wm0010_boot_xfer_complete; +		xfer->m.context = xfer; +		xfer->t.tx_buf = img_swap; +		xfer->t.rx_buf = out; +		xfer->t.len = len; +		xfer->t.bits_per_word = 8; + +		if (!wm0010->pll_running) { +			xfer->t.speed_hz = wm0010->sysclk / 6; +		} else { +			xfer->t.speed_hz = wm0010->max_spi_freq; + +			if (wm0010->board_max_spi_speed && +			   (wm0010->board_max_spi_speed < wm0010->max_spi_freq)) +					xfer->t.speed_hz = wm0010->board_max_spi_speed; +		} + +		/* Store max usable spi frequency for later use */ +		wm0010->max_spi_freq = xfer->t.speed_hz; + +		spi_message_add_tail(&xfer->t, &xfer->m); + +		offset += ((rec->length) + 8); +		rec = (void *)&rec->data[rec->length]; + +		if (offset >= fw->size) { +			dev_dbg(codec->dev, "All transfers scheduled\n"); +			xfer->done = &done; +		} + +		ret = spi_async(spi, &xfer->m); +		if (ret != 0) { +			dev_err(codec->dev, "Write failed: %d\n", ret); +			goto abort; +		} + +		if (wm0010->boot_failed) +			goto abort; +	} + +	wait_for_completion(&done); + +	spin_lock_irqsave(&wm0010->irq_lock, flags); +	wm0010->state = WM0010_FIRMWARE; +	spin_unlock_irqrestore(&wm0010->irq_lock, flags); + +	mutex_unlock(&wm0010->lock); + +	release_firmware(fw); + +	while (!list_empty(&xfer_list)) { +		xfer = list_first_entry(&xfer_list, struct wm0010_boot_xfer, +					list); +		kfree(xfer->t.rx_buf); +		kfree(xfer->t.tx_buf); +		list_del(&xfer->list); +		kfree(xfer); +	} + +	return 0; + +abort: +	/* Put the chip back into reset */ +	wm0010_halt(codec); +	mutex_unlock(&wm0010->lock); +	return ret; + +err_core: +	mutex_unlock(&wm0010->lock); +	regulator_bulk_disable(ARRAY_SIZE(wm0010->core_supplies), +			       wm0010->core_supplies); +err: +	return ret; +} + +static int wm0010_set_bias_level(struct snd_soc_codec *codec, +				 enum snd_soc_bias_level level) +{ +	struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec); + +	switch (level) { +	case SND_SOC_BIAS_ON: +		if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE) +			wm0010_boot(codec); +		break; +	case SND_SOC_BIAS_PREPARE: +		break; +	case SND_SOC_BIAS_STANDBY: +		if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE) { +			mutex_lock(&wm0010->lock); +			wm0010_halt(codec); +			mutex_unlock(&wm0010->lock); +		} +		break; +	case SND_SOC_BIAS_OFF: +		break; +	} + +	codec->dapm.bias_level = level; + +	return 0; +} + +static int wm0010_set_sysclk(struct snd_soc_codec *codec, int source, +			     int clk_id, unsigned int freq, int dir) +{ +	struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec); +	unsigned int i; + +	wm0010->sysclk = freq; + +	if (freq < pll_clock_map[ARRAY_SIZE(pll_clock_map)-1].max_sysclk) { +		wm0010->max_spi_freq = 0; +	} else { +		for (i = 0; i < ARRAY_SIZE(pll_clock_map); i++) +			if (freq >= pll_clock_map[i].max_sysclk) +				break; + +		wm0010->max_spi_freq = pll_clock_map[i].max_pll_spi_speed; +		wm0010->pll_clkctrl1 = pll_clock_map[i].pll_clkctrl1; +	} + +	return 0; +} + +static int wm0010_probe(struct snd_soc_codec *codec); + +static struct snd_soc_codec_driver soc_codec_dev_wm0010 = { +	.probe = wm0010_probe, +	.set_bias_level = wm0010_set_bias_level, +	.set_sysclk = wm0010_set_sysclk, +	.idle_bias_off = true, + +	.dapm_widgets = wm0010_dapm_widgets, +	.num_dapm_widgets = ARRAY_SIZE(wm0010_dapm_widgets), +	.dapm_routes = wm0010_dapm_routes, +	.num_dapm_routes = ARRAY_SIZE(wm0010_dapm_routes), +}; + +#define WM0010_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) +#define WM0010_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_driver wm0010_dai[] = { +	{ +		.name = "wm0010-sdi1", +		.playback = { +			.stream_name = "SDI1 Playback", +			.channels_min = 1, +			.channels_max = 2, +			.rates = WM0010_RATES, +			.formats = WM0010_FORMATS, +		}, +		.capture = { +			 .stream_name = "SDI1 Capture", +			 .channels_min = 1, +			 .channels_max = 2, +			 .rates = WM0010_RATES, +			 .formats = WM0010_FORMATS, +		 }, +	}, +	{ +		.name = "wm0010-sdi2", +		.playback = { +			.stream_name = "SDI2 Playback", +			.channels_min = 1, +			.channels_max = 2, +			.rates = WM0010_RATES, +			.formats = WM0010_FORMATS, +		}, +		.capture = { +			 .stream_name = "SDI2 Capture", +			 .channels_min = 1, +			 .channels_max = 2, +			 .rates = WM0010_RATES, +			 .formats = WM0010_FORMATS, +		 }, +	}, +}; + +static irqreturn_t wm0010_irq(int irq, void *data) +{ +	struct wm0010_priv *wm0010 = data; + +	switch (wm0010->state) { +	case WM0010_POWER_OFF: +	case WM0010_OUT_OF_RESET: +	case WM0010_BOOTROM: +	case WM0010_STAGE2: +		spin_lock(&wm0010->irq_lock); +		complete(&wm0010->boot_completion); +		spin_unlock(&wm0010->irq_lock); +		return IRQ_HANDLED; +	default: +		return IRQ_NONE; +	} + +	return IRQ_NONE; +} + +static int wm0010_probe(struct snd_soc_codec *codec) +{ +	struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec); + +	wm0010->codec = codec; + +	return 0; +} + +static int __devinit wm0010_spi_probe(struct spi_device *spi) +{ +	unsigned long gpio_flags; +	int ret; +	int trigger; +	int irq; +	struct wm0010_priv *wm0010; + +	wm0010 = devm_kzalloc(&spi->dev, sizeof(*wm0010), +			      GFP_KERNEL); +	if (!wm0010) +		return -ENOMEM; + +	mutex_init(&wm0010->lock); +	spin_lock_init(&wm0010->irq_lock); + +	spi_set_drvdata(spi, wm0010); +	wm0010->dev = &spi->dev; + +	if (dev_get_platdata(&spi->dev)) +		memcpy(&wm0010->pdata, dev_get_platdata(&spi->dev), +		       sizeof(wm0010->pdata)); + +	init_completion(&wm0010->boot_completion); + +	wm0010->core_supplies[0].supply = "AVDD"; +	wm0010->core_supplies[1].supply = "DCVDD"; +	ret = devm_regulator_bulk_get(wm0010->dev, ARRAY_SIZE(wm0010->core_supplies), +				      wm0010->core_supplies); +	if (ret != 0) { +		dev_err(wm0010->dev, "Failed to obtain core supplies: %d\n", +			ret); +		return ret; +	} + +	wm0010->dbvdd = devm_regulator_get(wm0010->dev, "DBVDD"); +	if (IS_ERR(wm0010->dbvdd)) { +		ret = PTR_ERR(wm0010->dbvdd); +		dev_err(wm0010->dev, "Failed to obtain DBVDD: %d\n", ret); +		return ret; +	} + +	if (wm0010->pdata.gpio_reset) { +		wm0010->gpio_reset = wm0010->pdata.gpio_reset; + +		if (wm0010->pdata.reset_active_high) +			wm0010->gpio_reset_value = 1; +		else +			wm0010->gpio_reset_value = 0; + +		if (wm0010->gpio_reset_value) +			gpio_flags = GPIOF_OUT_INIT_HIGH; +		else +			gpio_flags = GPIOF_OUT_INIT_LOW; + +		ret = devm_gpio_request_one(wm0010->dev, wm0010->gpio_reset, +					    gpio_flags, "wm0010 reset"); +		if (ret < 0) { +			dev_err(wm0010->dev, +				"Failed to request GPIO for DSP reset: %d\n", +				ret); +			return ret; +		} +	} else { +		dev_err(wm0010->dev, "No reset GPIO configured\n"); +		return -EINVAL; +	} + +	wm0010->state = WM0010_POWER_OFF; + +	irq = spi->irq; +	if (wm0010->pdata.irq_flags) +		trigger = wm0010->pdata.irq_flags; +	else +		trigger = IRQF_TRIGGER_FALLING; +	trigger |= IRQF_ONESHOT; + +	ret = request_threaded_irq(irq, NULL, wm0010_irq, trigger | IRQF_ONESHOT, +				   "wm0010", wm0010); +	if (ret) { +		dev_err(wm0010->dev, "Failed to request IRQ %d: %d\n", +			irq, ret); +		return ret; +	} +	wm0010->irq = irq; + +	if (spi->max_speed_hz) +		wm0010->board_max_spi_speed = spi->max_speed_hz; +	else +		wm0010->board_max_spi_speed = 0; + +	ret = snd_soc_register_codec(&spi->dev, +				     &soc_codec_dev_wm0010, wm0010_dai, +				     ARRAY_SIZE(wm0010_dai)); +	if (ret < 0) +		return ret; + +	return 0; +} + +static int __devexit wm0010_spi_remove(struct spi_device *spi) +{ +	struct wm0010_priv *wm0010 = spi_get_drvdata(spi); + +	snd_soc_unregister_codec(&spi->dev); + +	gpio_set_value_cansleep(wm0010->gpio_reset, +				wm0010->gpio_reset_value); + +	if (wm0010->irq) +		free_irq(wm0010->irq, wm0010); + +	return 0; +} + +static struct spi_driver wm0010_spi_driver = { +	.driver = { +		.name	= "wm0010", +		.bus 	= &spi_bus_type, +		.owner	= THIS_MODULE, +	}, +	.probe		= wm0010_spi_probe, +	.remove		= __devexit_p(wm0010_spi_remove), +}; + +module_spi_driver(wm0010_spi_driver); + +MODULE_DESCRIPTION("ASoC WM0010 driver"); +MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index a3acb7a85f6..683dc43b1d8 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -31,6 +31,7 @@  #include <linux/i2c.h>  #include <linux/regmap.h>  #include <linux/debugfs.h> +#include <linux/regulator/consumer.h>  #include <linux/slab.h>  #include <sound/core.h>  #include <sound/pcm.h> @@ -43,6 +44,14 @@  #include "wm2000.h" +#define WM2000_NUM_SUPPLIES 3 + +static const char *wm2000_supplies[WM2000_NUM_SUPPLIES] = { +	"SPKVDD", +	"DBVDD", +	"DCVDD", +}; +  enum wm2000_anc_mode {  	ANC_ACTIVE = 0,  	ANC_BYPASS = 1, @@ -54,6 +63,8 @@ struct wm2000_priv {  	struct i2c_client *i2c;  	struct regmap *regmap; +	struct regulator_bulk_data supplies[WM2000_NUM_SUPPLIES]; +  	enum wm2000_anc_mode anc_mode;  	unsigned int anc_active:1; @@ -126,6 +137,12 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)  	dev_dbg(&i2c->dev, "Beginning power up\n"); +	ret = regulator_bulk_enable(WM2000_NUM_SUPPLIES, wm2000->supplies); +	if (ret != 0) { +		dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); +		return ret; +	} +  	if (!wm2000->mclk_div) {  		dev_dbg(&i2c->dev, "Disabling MCLK divider\n");  		wm2000_write(i2c, WM2000_REG_SYS_CTL2, @@ -143,12 +160,14 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)  	if (!wm2000_poll_bit(i2c, WM2000_REG_ANC_STAT,  			     WM2000_ANC_ENG_IDLE)) {  		dev_err(&i2c->dev, "ANC engine failed to reset\n"); +		regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);  		return -ETIMEDOUT;  	}  	if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS,  			     WM2000_STATUS_BOOT_COMPLETE)) {  		dev_err(&i2c->dev, "ANC engine failed to initialise\n"); +		regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);  		return -ETIMEDOUT;  	} @@ -163,11 +182,13 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)  			      wm2000->anc_download_size);  	if (ret < 0) {  		dev_err(&i2c->dev, "i2c_transfer() failed: %d\n", ret); +		regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);  		return ret;  	}  	if (ret != wm2000->anc_download_size) {  		dev_err(&i2c->dev, "i2c_transfer() failed, %d != %d\n",  			ret, wm2000->anc_download_size); +		regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);  		return -EIO;  	} @@ -201,6 +222,7 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)  	if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS,  			     WM2000_STATUS_MOUSE_ACTIVE)) {  		dev_err(&i2c->dev, "Timed out waiting for device\n"); +		regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);  		return -ETIMEDOUT;  	} @@ -238,6 +260,8 @@ static int wm2000_power_down(struct i2c_client *i2c, int analogue)  		return -ETIMEDOUT;  	} +	regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies); +  	dev_dbg(&i2c->dev, "powered off\n");  	wm2000->anc_mode = ANC_OFF; @@ -747,7 +771,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,  	struct wm2000_platform_data *pdata;  	const char *filename;  	const struct firmware *fw = NULL; -	int ret; +	int ret, i;  	int reg;  	u16 id; @@ -760,7 +784,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,  	dev_set_drvdata(&i2c->dev, wm2000); -	wm2000->regmap = regmap_init_i2c(i2c, &wm2000_regmap); +	wm2000->regmap = devm_regmap_init_i2c(i2c, &wm2000_regmap);  	if (IS_ERR(wm2000->regmap)) {  		ret = PTR_ERR(wm2000->regmap);  		dev_err(&i2c->dev, "Failed to allocate register map: %d\n", @@ -768,6 +792,22 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,  		goto out;  	} +	for (i = 0; i < WM2000_NUM_SUPPLIES; i++) +		wm2000->supplies[i].supply = wm2000_supplies[i]; + +	ret = devm_regulator_bulk_get(&i2c->dev, WM2000_NUM_SUPPLIES, +				      wm2000->supplies); +	if (ret != 0) { +		dev_err(&i2c->dev, "Failed to get supplies: %d\n", ret); +		return ret; +	} + +	ret = regulator_bulk_enable(WM2000_NUM_SUPPLIES, wm2000->supplies); +	if (ret != 0) { +		dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); +		return ret; +	} +  	/* Verify that this is a WM2000 */  	reg = wm2000_read(i2c, WM2000_REG_ID1);  	id = reg << 8; @@ -777,7 +817,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,  	if (id != 0x2000) {  		dev_err(&i2c->dev, "Device is not a WM2000 - ID %x\n", id);  		ret = -ENODEV; -		goto out_regmap_exit; +		goto err_supplies;  	}  	reg = wm2000_read(i2c, WM2000_REG_REVISON); @@ -796,7 +836,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,  	ret = request_firmware(&fw, filename, &i2c->dev);  	if (ret != 0) {  		dev_err(&i2c->dev, "Failed to acquire ANC data: %d\n", ret); -		goto out_regmap_exit; +		goto err_supplies;  	}  	/* Pre-cook the concatenation of the register address onto the image */ @@ -807,7 +847,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,  	if (wm2000->anc_download == NULL) {  		dev_err(&i2c->dev, "Out of memory\n");  		ret = -ENOMEM; -		goto out_regmap_exit; +		goto err_supplies;  	}  	wm2000->anc_download[0] = 0x80; @@ -822,11 +862,10 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,  	wm2000_reset(wm2000);  	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm2000, NULL, 0); -	if (!ret) -		goto out; -out_regmap_exit: -	regmap_exit(wm2000->regmap); +err_supplies: +	regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies); +  out:  	release_firmware(fw);  	return ret; @@ -834,10 +873,7 @@ out:  static __devexit int wm2000_i2c_remove(struct i2c_client *i2c)  { -	struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); -  	snd_soc_unregister_codec(&i2c->dev); -	regmap_exit(wm2000->regmap);  	return 0;  } @@ -858,17 +894,7 @@ static struct i2c_driver wm2000_i2c_driver = {  	.id_table = wm2000_i2c_id,  }; -static int __init wm2000_init(void) -{ -	return i2c_add_driver(&wm2000_i2c_driver); -} -module_init(wm2000_init); - -static void __exit wm2000_exit(void) -{ -	i2c_del_driver(&wm2000_i2c_driver); -} -module_exit(wm2000_exit); +module_i2c_driver(wm2000_i2c_driver);  MODULE_DESCRIPTION("ASoC WM2000 driver");  MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfonmicro.com>"); diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 32682c1b7cd..efa93dbb019 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -1117,8 +1117,8 @@ SND_SOC_DAPM_SUPPLY("MICBIAS1", WM2200_MIC_BIAS_CTRL_1, WM2200_MICB1_ENA_SHIFT,  		    0, NULL, 0),  SND_SOC_DAPM_SUPPLY("MICBIAS2", WM2200_MIC_BIAS_CTRL_2, WM2200_MICB2_ENA_SHIFT,  		    0, NULL, 0), -SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20), -SND_SOC_DAPM_REGULATOR_SUPPLY("AVDD", 20), +SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0), +SND_SOC_DAPM_REGULATOR_SUPPLY("AVDD", 20, 0),  SND_SOC_DAPM_INPUT("IN1L"),  SND_SOC_DAPM_INPUT("IN1R"), @@ -2270,17 +2270,7 @@ static struct i2c_driver wm2200_i2c_driver = {  	.id_table = wm2200_i2c_id,  }; -static int __init wm2200_modinit(void) -{ -	return i2c_add_driver(&wm2200_i2c_driver); -} -module_init(wm2200_modinit); - -static void __exit wm2200_exit(void) -{ -	i2c_del_driver(&wm2200_i2c_driver); -} -module_exit(wm2200_exit); +module_i2c_driver(wm2200_i2c_driver);  MODULE_DESCRIPTION("ASoC WM2200 driver");  MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index aa62c0e44cb..7f567585832 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -848,9 +848,9 @@ SND_SOC_DAPM_SUPPLY("SYSCLK", WM5100_CLOCKING_3, WM5100_SYSCLK_ENA_SHIFT, 0,  SND_SOC_DAPM_SUPPLY("ASYNCCLK", WM5100_CLOCKING_6, WM5100_ASYNC_CLK_ENA_SHIFT,  		    0, NULL, 0), -SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20), -SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0), -SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0), +SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0), +SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0, 0), +SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0, 0),  SND_SOC_DAPM_SUPPLY("CP1", WM5100_HP_CHARGE_PUMP_1, WM5100_CP1_ENA_SHIFT, 0,  		    NULL, 0), diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index e33d327396a..1722b586bdb 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -274,18 +274,43 @@ ARIZONA_MIXER_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE);  ARIZONA_MIXER_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE);  ARIZONA_MIXER_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE); + +static const char *wm5102_aec_loopback_texts[] = { +	"HPOUT1L", "HPOUT1R", "HPOUT2L", "HPOUT2R", "EPOUT", +	"SPKOUTL", "SPKOUTR", "SPKDAT1L", "SPKDAT1R", +}; + +static const unsigned int wm5102_aec_loopback_values[] = { +	0, 1, 2, 3, 4, 6, 7, 8, 9, +}; + +static const struct soc_enum wm5102_aec_loopback = +	SOC_VALUE_ENUM_SINGLE(ARIZONA_DAC_AEC_CONTROL_1, +			      ARIZONA_AEC_LOOPBACK_SRC_SHIFT, +			      ARIZONA_AEC_LOOPBACK_SRC_MASK, +			      ARRAY_SIZE(wm5102_aec_loopback_texts), +			      wm5102_aec_loopback_texts, +			      wm5102_aec_loopback_values); + +static const struct snd_kcontrol_new wm5102_aec_loopback_mux = +	SOC_DAPM_VALUE_ENUM("AEC Loopback", wm5102_aec_loopback); +  static const struct snd_soc_dapm_widget wm5102_dapm_widgets[] = {  SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,  		    0, NULL, 0),  SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,  		    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK, +		    ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK, +		    ARIZONA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0), -SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0), -SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0), -SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20), -SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0), -SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDL", 0), -SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDR", 0), +SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0, 0), +SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0, 0), +SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0), +SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, SND_SOC_DAPM_REGULATOR_BYPASS), +SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDL", 0, 0), +SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDR", 0, 0),  SND_SOC_DAPM_SIGGEN("TONE"),  SND_SOC_DAPM_SIGGEN("NOISE"), @@ -421,6 +446,9 @@ SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0,  SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0,  		    ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0), +SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, +		       ARIZONA_AEC_LOOPBACK_ENA, 0, &wm5102_aec_loopback_mux), +  SND_SOC_DAPM_PGA_E("OUT1L", ARIZONA_OUTPUT_ENABLES_1,  		   ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,  		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), @@ -516,6 +544,7 @@ SND_SOC_DAPM_OUTPUT("SPKDAT1R"),  	{ name, "Noise Generator", "Noise Generator" }, \  	{ name, "Tone Generator 1", "Tone Generator 1" }, \  	{ name, "Tone Generator 2", "Tone Generator 2" }, \ +	{ name, "AEC", "AEC Loopback" }, \  	{ name, "IN1L", "IN1L PGA" }, \  	{ name, "IN1R", "IN1R PGA" }, \  	{ name, "IN2L", "IN2L PGA" }, \ @@ -681,21 +710,30 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {  	ARIZONA_MIXER_ROUTES("ASRC2L", "ASRC2L"),  	ARIZONA_MIXER_ROUTES("ASRC2R", "ASRC2R"), +	{ "AEC Loopback", "HPOUT1L", "OUT1L" }, +	{ "AEC Loopback", "HPOUT1R", "OUT1R" },  	{ "HPOUT1L", NULL, "OUT1L" },  	{ "HPOUT1R", NULL, "OUT1R" }, +	{ "AEC Loopback", "HPOUT2L", "OUT2L" }, +	{ "AEC Loopback", "HPOUT2R", "OUT2R" },  	{ "HPOUT2L", NULL, "OUT2L" },  	{ "HPOUT2R", NULL, "OUT2R" }, +	{ "AEC Loopback", "EPOUT", "OUT3L" },  	{ "EPOUTN", NULL, "OUT3L" },  	{ "EPOUTP", NULL, "OUT3L" }, +	{ "AEC Loopback", "SPKOUTL", "OUT4L" },  	{ "SPKOUTLN", NULL, "OUT4L" },  	{ "SPKOUTLP", NULL, "OUT4L" }, +	{ "AEC Loopback", "SPKOUTR", "OUT4R" },  	{ "SPKOUTRN", NULL, "OUT4R" },  	{ "SPKOUTRP", NULL, "OUT4R" }, +	{ "AEC Loopback", "SPKDAT1L", "OUT5L" }, +	{ "AEC Loopback", "SPKDAT1R", "OUT5R" },  	{ "SPKDAT1L", NULL, "OUT5L" },  	{ "SPKDAT1R", NULL, "OUT5R" },  }; diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 01ebbcc5c6a..9211e4192f7 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -153,6 +153,15 @@ SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),  SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),  SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode), +ARIZONA_MIXER_CONTROLS("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("DSP2L", ARIZONA_DSP2LMIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("DSP2R", ARIZONA_DSP2RMIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("DSP3L", ARIZONA_DSP3LMIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("DSP3R", ARIZONA_DSP3RMIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("DSP4L", ARIZONA_DSP4LMIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("DSP5R", ARIZONA_DSP4RMIX_INPUT_1_SOURCE), +  ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE),  ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE), @@ -163,7 +172,8 @@ ARIZONA_MIXER_CONTROLS("HPOUT1L", ARIZONA_OUT1LMIX_INPUT_1_SOURCE),  ARIZONA_MIXER_CONTROLS("HPOUT1R", ARIZONA_OUT1RMIX_INPUT_1_SOURCE),  ARIZONA_MIXER_CONTROLS("HPOUT2L", ARIZONA_OUT2LMIX_INPUT_1_SOURCE),  ARIZONA_MIXER_CONTROLS("HPOUT2R", ARIZONA_OUT2RMIX_INPUT_1_SOURCE), -ARIZONA_MIXER_CONTROLS("EPOUT", ARIZONA_OUT3LMIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("HPOUT3L", ARIZONA_OUT3LMIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("HPOUT3R", ARIZONA_OUT3RMIX_INPUT_1_SOURCE),  ARIZONA_MIXER_CONTROLS("SPKOUTL", ARIZONA_OUT4LMIX_INPUT_1_SOURCE),  ARIZONA_MIXER_CONTROLS("SPKOUTR", ARIZONA_OUT4RMIX_INPUT_1_SOURCE),  ARIZONA_MIXER_CONTROLS("SPKDAT1L", ARIZONA_OUT5LMIX_INPUT_1_SOURCE), @@ -175,7 +185,7 @@ SOC_SINGLE("HPOUT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_1L,  	   ARIZONA_OUT1_OSR_SHIFT, 1, 0),  SOC_SINGLE("OUT2 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_2L,  	   ARIZONA_OUT2_OSR_SHIFT, 1, 0), -SOC_SINGLE("EPOUT High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_3L, +SOC_SINGLE("OUT3 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_3L,  	   ARIZONA_OUT3_OSR_SHIFT, 1, 0),  SOC_SINGLE("Speaker High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_4L,  	   ARIZONA_OUT4_OSR_SHIFT, 1, 0), @@ -188,8 +198,8 @@ SOC_DOUBLE_R("HPOUT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L,  	     ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1),  SOC_DOUBLE_R("OUT2 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_2L,  	     ARIZONA_DAC_DIGITAL_VOLUME_2R, ARIZONA_OUT2L_MUTE_SHIFT, 1, 1), -SOC_SINGLE("EPOUT Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_3L, -	   ARIZONA_OUT3L_MUTE_SHIFT, 1, 1), +SOC_DOUBLE_R("OUT3 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_3L, +	     ARIZONA_DAC_DIGITAL_VOLUME_3R, ARIZONA_OUT3L_MUTE_SHIFT, 1, 1),  SOC_DOUBLE_R("Speaker Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_4L,  	     ARIZONA_DAC_DIGITAL_VOLUME_4R, ARIZONA_OUT4L_MUTE_SHIFT, 1, 1),  SOC_DOUBLE_R("SPKDAT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_5L, @@ -203,8 +213,9 @@ SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_1L,  SOC_DOUBLE_R_TLV("OUT2 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_2L,  		 ARIZONA_DAC_DIGITAL_VOLUME_2R, ARIZONA_OUT2L_VOL_SHIFT,  		 0xbf, 0, digital_tlv), -SOC_SINGLE_TLV("EPOUT Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_3L, -	       ARIZONA_OUT3L_VOL_SHIFT, 0xbf, 0, digital_tlv), +SOC_DOUBLE_R_TLV("OUT3 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_3L, +		 ARIZONA_DAC_DIGITAL_VOLUME_3R, ARIZONA_OUT3L_VOL_SHIFT, +		 0xbf, 0, digital_tlv),  SOC_DOUBLE_R_TLV("Speaker Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_4L,  		 ARIZONA_DAC_DIGITAL_VOLUME_4R, ARIZONA_OUT4L_VOL_SHIFT,  		 0xbf, 0, digital_tlv), @@ -223,8 +234,9 @@ SOC_DOUBLE_R_RANGE_TLV("OUT2 Volume", ARIZONA_OUTPUT_PATH_CONFIG_2L,  		       ARIZONA_OUTPUT_PATH_CONFIG_2R,  		       ARIZONA_OUT2L_PGA_VOL_SHIFT,  		       0x34, 0x40, 0, ana_tlv), -SOC_SINGLE_RANGE_TLV("EPOUT Volume", ARIZONA_OUTPUT_PATH_CONFIG_3L, -		     ARIZONA_OUT3L_PGA_VOL_SHIFT, 0x34, 0x40, 0, ana_tlv), +SOC_DOUBLE_R_RANGE_TLV("OUT3 Volume", ARIZONA_OUTPUT_PATH_CONFIG_3L, +		       ARIZONA_OUTPUT_PATH_CONFIG_3R, +		       ARIZONA_OUT3L_PGA_VOL_SHIFT, 0x34, 0x40, 0, ana_tlv),  SOC_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT,  	   ARIZONA_SPK1R_MUTE_SHIFT, 1, 1), @@ -272,7 +284,8 @@ ARIZONA_MIXER_ENUMS(OUT1L, ARIZONA_OUT1LMIX_INPUT_1_SOURCE);  ARIZONA_MIXER_ENUMS(OUT1R, ARIZONA_OUT1RMIX_INPUT_1_SOURCE);  ARIZONA_MIXER_ENUMS(OUT2L, ARIZONA_OUT2LMIX_INPUT_1_SOURCE);  ARIZONA_MIXER_ENUMS(OUT2R, ARIZONA_OUT2RMIX_INPUT_1_SOURCE); -ARIZONA_MIXER_ENUMS(OUT3, ARIZONA_OUT3LMIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(OUT3L, ARIZONA_OUT3LMIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(OUT3R, ARIZONA_OUT3RMIX_INPUT_1_SOURCE);  ARIZONA_MIXER_ENUMS(SPKOUTL, ARIZONA_OUT4LMIX_INPUT_1_SOURCE);  ARIZONA_MIXER_ENUMS(SPKOUTR, ARIZONA_OUT4RMIX_INPUT_1_SOURCE);  ARIZONA_MIXER_ENUMS(SPKDAT1L, ARIZONA_OUT5LMIX_INPUT_1_SOURCE); @@ -300,18 +313,42 @@ ARIZONA_MIXER_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE);  ARIZONA_MIXER_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE);  ARIZONA_MIXER_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE); +static const char *wm5110_aec_loopback_texts[] = { +	"HPOUT1L", "HPOUT1R", "HPOUT2L", "HPOUT2R", "HPOUT3L", "HPOUT3R", +	"SPKOUTL", "SPKOUTR", "SPKDAT1L", "SPKDAT1R", "SPKDAT2L", "SPKDAT2R", +}; + +static const unsigned int wm5110_aec_loopback_values[] = { +	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, +}; + +static const struct soc_enum wm5110_aec_loopback = +	SOC_VALUE_ENUM_SINGLE(ARIZONA_DAC_AEC_CONTROL_1, +			      ARIZONA_AEC_LOOPBACK_SRC_SHIFT, +			      ARIZONA_AEC_LOOPBACK_SRC_MASK, +			      ARRAY_SIZE(wm5110_aec_loopback_texts), +			      wm5110_aec_loopback_texts, +			      wm5110_aec_loopback_values); + +static const struct snd_kcontrol_new wm5110_aec_loopback_mux = +	SOC_DAPM_VALUE_ENUM("AEC Loopback", wm5110_aec_loopback); +  static const struct snd_soc_dapm_widget wm5110_dapm_widgets[] = {  SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,  		    0, NULL, 0),  SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,  		    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK, +		    ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK, +		    ARIZONA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0), -SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0), -SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0), -SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20), -SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0), -SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDL", 0), -SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDR", 0), +SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0, 0), +SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0, 0), +SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0), +SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, SND_SOC_DAPM_REGULATOR_BYPASS), +SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDL", 0, 0), +SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDR", 0, 0),  SND_SOC_DAPM_SIGGEN("TONE"),  SND_SOC_DAPM_SIGGEN("NOISE"), @@ -405,6 +442,9 @@ SND_SOC_DAPM_PGA("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0,  SND_SOC_DAPM_PGA("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0,  		 NULL, 0), +SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, +		       ARIZONA_AEC_LOOPBACK_ENA, 0, &wm5110_aec_loopback_mux), +  SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0,  		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0),  SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0, @@ -474,6 +514,9 @@ SND_SOC_DAPM_PGA_E("OUT2R", ARIZONA_OUTPUT_ENABLES_1,  SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1,  		   ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,  		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("OUT3R", ARIZONA_OUTPUT_ENABLES_1, +		   ARIZONA_OUT3R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, +		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),  SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1,  		   ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,  		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), @@ -518,7 +561,8 @@ ARIZONA_MIXER_WIDGETS(OUT1L, "HPOUT1L"),  ARIZONA_MIXER_WIDGETS(OUT1R, "HPOUT1R"),  ARIZONA_MIXER_WIDGETS(OUT2L, "HPOUT2L"),  ARIZONA_MIXER_WIDGETS(OUT2R, "HPOUT2R"), -ARIZONA_MIXER_WIDGETS(OUT3, "EPOUT"), +ARIZONA_MIXER_WIDGETS(OUT3L, "HPOUT3L"), +ARIZONA_MIXER_WIDGETS(OUT3R, "HPOUT3R"),  ARIZONA_MIXER_WIDGETS(SPKOUTL, "SPKOUTL"),  ARIZONA_MIXER_WIDGETS(SPKOUTR, "SPKOUTR"),  ARIZONA_MIXER_WIDGETS(SPKDAT1L, "SPKDAT1L"), @@ -550,8 +594,8 @@ SND_SOC_DAPM_OUTPUT("HPOUT1L"),  SND_SOC_DAPM_OUTPUT("HPOUT1R"),  SND_SOC_DAPM_OUTPUT("HPOUT2L"),  SND_SOC_DAPM_OUTPUT("HPOUT2R"), -SND_SOC_DAPM_OUTPUT("EPOUTN"), -SND_SOC_DAPM_OUTPUT("EPOUTP"), +SND_SOC_DAPM_OUTPUT("HPOUT3L"), +SND_SOC_DAPM_OUTPUT("HPOUT3R"),  SND_SOC_DAPM_OUTPUT("SPKOUTLN"),  SND_SOC_DAPM_OUTPUT("SPKOUTLP"),  SND_SOC_DAPM_OUTPUT("SPKOUTRN"), @@ -566,6 +610,7 @@ SND_SOC_DAPM_OUTPUT("SPKDAT2R"),  	{ name, "Noise Generator", "Noise Generator" }, \  	{ name, "Tone Generator 1", "Tone Generator 1" }, \  	{ name, "Tone Generator 2", "Tone Generator 2" }, \ +	{ name, "AEC", "AEC Loopback" }, \  	{ name, "IN1L", "IN1L PGA" }, \  	{ name, "IN1R", "IN1R PGA" }, \  	{ name, "IN2L", "IN2L PGA" }, \ @@ -616,6 +661,7 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {  	{ "OUT2L", NULL, "CPVDD" },  	{ "OUT2R", NULL, "CPVDD" },  	{ "OUT3L", NULL, "CPVDD" }, +	{ "OUT3R", NULL, "CPVDD" },  	{ "OUT4L", NULL, "SPKVDDL" },  	{ "OUT4R", NULL, "SPKVDDR" }, @@ -697,7 +743,8 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {  	ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"),  	ARIZONA_MIXER_ROUTES("OUT2L", "HPOUT2L"),  	ARIZONA_MIXER_ROUTES("OUT2R", "HPOUT2R"), -	ARIZONA_MIXER_ROUTES("OUT3L", "EPOUT"), +	ARIZONA_MIXER_ROUTES("OUT3L", "HPOUT3L"), +	ARIZONA_MIXER_ROUTES("OUT3R", "HPOUT3R"),  	ARIZONA_MIXER_ROUTES("OUT4L", "SPKOUTL"),  	ARIZONA_MIXER_ROUTES("OUT4R", "SPKOUTR"), @@ -750,8 +797,8 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {  	{ "HPOUT2L", NULL, "OUT2L" },  	{ "HPOUT2R", NULL, "OUT2R" }, -	{ "EPOUTN", NULL, "OUT3L" }, -	{ "EPOUTP", NULL, "OUT3L" }, +	{ "HPOUT3L", NULL, "OUT3L" }, +	{ "HPOUT3R", NULL, "OUT3L" },  	{ "SPKOUTLN", NULL, "OUT4L" },  	{ "SPKOUTLP", NULL, "OUT4L" }, @@ -869,6 +916,8 @@ static unsigned int wm5110_digital_vu[] = {  	ARIZONA_ADC_DIGITAL_VOLUME_2R,  	ARIZONA_ADC_DIGITAL_VOLUME_3L,  	ARIZONA_ADC_DIGITAL_VOLUME_3R, +	ARIZONA_ADC_DIGITAL_VOLUME_4L, +	ARIZONA_ADC_DIGITAL_VOLUME_4R,  	ARIZONA_DAC_DIGITAL_VOLUME_1L,  	ARIZONA_DAC_DIGITAL_VOLUME_1R, @@ -880,6 +929,8 @@ static unsigned int wm5110_digital_vu[] = {  	ARIZONA_DAC_DIGITAL_VOLUME_4R,  	ARIZONA_DAC_DIGITAL_VOLUME_5L,  	ARIZONA_DAC_DIGITAL_VOLUME_5R, +	ARIZONA_DAC_DIGITAL_VOLUME_6L, +	ARIZONA_DAC_DIGITAL_VOLUME_6R,  };  static struct snd_soc_codec_driver soc_codec_dev_wm5110 = { diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index 56a049555e2..c12a54e72e8 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -20,6 +20,7 @@  #include <linux/spi/spi.h>  #include <linux/slab.h>  #include <linux/of_device.h> +#include <linux/regmap.h>  #include <sound/core.h>  #include <sound/pcm.h>  #include <sound/pcm_params.h> @@ -33,24 +34,75 @@   * We can't read the WM8510 register space when we are   * using 2 wire for device control, so we cache them instead.   */ -static const u16 wm8510_reg[WM8510_CACHEREGNUM] = { -	0x0000, 0x0000, 0x0000, 0x0000, -	0x0050, 0x0000, 0x0140, 0x0000, -	0x0000, 0x0000, 0x0000, 0x00ff, -	0x0000, 0x0000, 0x0100, 0x00ff, -	0x0000, 0x0000, 0x012c, 0x002c, -	0x002c, 0x002c, 0x002c, 0x0000, -	0x0032, 0x0000, 0x0000, 0x0000, -	0x0000, 0x0000, 0x0000, 0x0000, -	0x0038, 0x000b, 0x0032, 0x0000, -	0x0008, 0x000c, 0x0093, 0x00e9, -	0x0000, 0x0000, 0x0000, 0x0000, -	0x0003, 0x0010, 0x0000, 0x0000, -	0x0000, 0x0002, 0x0001, 0x0000, -	0x0000, 0x0000, 0x0039, 0x0000, -	0x0001, +static const struct reg_default wm8510_reg_defaults[] = { +	{  1, 0x0000 }, +	{  2, 0x0000 }, +	{  3, 0x0000 }, +	{  4, 0x0050 }, +	{  5, 0x0000 }, +	{  6, 0x0140 }, +	{  7, 0x0000 }, +	{  8, 0x0000 }, +	{  9, 0x0000 }, +	{ 10, 0x0000 }, +	{ 11, 0x00ff }, +	{ 12, 0x0000 }, +	{ 13, 0x0000 }, +	{ 14, 0x0100 }, +	{ 15, 0x00ff }, +	{ 16, 0x0000 }, +	{ 17, 0x0000 }, +	{ 18, 0x012c }, +	{ 19, 0x002c }, +	{ 20, 0x002c }, +	{ 21, 0x002c }, +	{ 22, 0x002c }, +	{ 23, 0x0000 }, +	{ 24, 0x0032 }, +	{ 25, 0x0000 }, +	{ 26, 0x0000 }, +	{ 27, 0x0000 }, +	{ 28, 0x0000 }, +	{ 29, 0x0000 }, +	{ 30, 0x0000 }, +	{ 31, 0x0000 }, +	{ 32, 0x0038 }, +	{ 33, 0x000b }, +	{ 34, 0x0032 }, +	{ 35, 0x0000 }, +	{ 36, 0x0008 }, +	{ 37, 0x000c }, +	{ 38, 0x0093 }, +	{ 39, 0x00e9 }, +	{ 40, 0x0000 }, +	{ 41, 0x0000 }, +	{ 42, 0x0000 }, +	{ 43, 0x0000 }, +	{ 44, 0x0003 }, +	{ 45, 0x0010 }, +	{ 46, 0x0000 }, +	{ 47, 0x0000 }, +	{ 48, 0x0000 }, +	{ 49, 0x0002 }, +	{ 50, 0x0001 }, +	{ 51, 0x0000 }, +	{ 52, 0x0000 }, +	{ 53, 0x0000 }, +	{ 54, 0x0039 }, +	{ 55, 0x0000 }, +	{ 56, 0x0001 },  }; +static bool wm8510_volatile(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case WM8510_RESET: +		return true; +	default: +		return false; +	} +} +  #define WM8510_POWER1_BIASEN  0x08  #define WM8510_POWER1_BUFIOEN 0x10 @@ -58,7 +110,7 @@ static const u16 wm8510_reg[WM8510_CACHEREGNUM] = {  /* codec private data */  struct wm8510_priv { -	enum snd_soc_control_type control_type; +	struct regmap *regmap;  };  static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" }; @@ -454,6 +506,7 @@ static int wm8510_mute(struct snd_soc_dai *dai, int mute)  static int wm8510_set_bias_level(struct snd_soc_codec *codec,  	enum snd_soc_bias_level level)  { +	struct wm8510_priv *wm8510 = snd_soc_codec_get_drvdata(codec);  	u16 power1 = snd_soc_read(codec, WM8510_POWER1) & ~0x3;  	switch (level) { @@ -467,7 +520,7 @@ static int wm8510_set_bias_level(struct snd_soc_codec *codec,  		power1 |= WM8510_POWER1_BIASEN | WM8510_POWER1_BUFIOEN;  		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { -			snd_soc_cache_sync(codec); +			regcache_sync(wm8510->regmap);  			/* Initial cap charge at VMID 5k */  			snd_soc_write(codec, WM8510_POWER1, power1 | 0x3); @@ -536,10 +589,9 @@ static int wm8510_resume(struct snd_soc_codec *codec)  static int wm8510_probe(struct snd_soc_codec *codec)  { -	struct wm8510_priv *wm8510 = snd_soc_codec_get_drvdata(codec);  	int ret; -	ret = snd_soc_codec_set_cache_io(codec, 7, 9,  wm8510->control_type); +	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);  	if (ret < 0) {  		printk(KERN_ERR "wm8510: failed to set cache I/O: %d\n", ret);  		return ret; @@ -569,9 +621,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8510 = {  	.suspend =	wm8510_suspend,  	.resume =	wm8510_resume,  	.set_bias_level = wm8510_set_bias_level, -	.reg_cache_size = ARRAY_SIZE(wm8510_reg), -	.reg_word_size = sizeof(u16), -	.reg_cache_default =wm8510_reg,  	.controls = wm8510_snd_controls,  	.num_controls = ARRAY_SIZE(wm8510_snd_controls), @@ -586,23 +635,38 @@ static const struct of_device_id wm8510_of_match[] = {  	{ },  }; +static const struct regmap_config wm8510_regmap = { +	.reg_bits = 7, +	.val_bits = 9, +	.max_register = WM8510_MONOMIX, + +	.reg_defaults = wm8510_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(wm8510_reg_defaults), +	.cache_type = REGCACHE_RBTREE, + +	.volatile_reg = wm8510_volatile, +}; +  #if defined(CONFIG_SPI_MASTER)  static int __devinit wm8510_spi_probe(struct spi_device *spi)  {  	struct wm8510_priv *wm8510;  	int ret; -	wm8510 = kzalloc(sizeof(struct wm8510_priv), GFP_KERNEL); +	wm8510 = devm_kzalloc(&spi->dev, sizeof(struct wm8510_priv), +			      GFP_KERNEL);  	if (wm8510 == NULL)  		return -ENOMEM; -	wm8510->control_type = SND_SOC_SPI; +	wm8510->regmap = devm_regmap_init_spi(spi, &wm8510_regmap); +	if (IS_ERR(wm8510->regmap)) +		return PTR_ERR(wm8510->regmap); +  	spi_set_drvdata(spi, wm8510);  	ret = snd_soc_register_codec(&spi->dev,  			&soc_codec_dev_wm8510, &wm8510_dai, 1); -	if (ret < 0) -		kfree(wm8510); +  	return ret;  } @@ -630,17 +694,20 @@ static __devinit int wm8510_i2c_probe(struct i2c_client *i2c,  	struct wm8510_priv *wm8510;  	int ret; -	wm8510 = kzalloc(sizeof(struct wm8510_priv), GFP_KERNEL); +	wm8510 = devm_kzalloc(&i2c->dev, sizeof(struct wm8510_priv), +			      GFP_KERNEL);  	if (wm8510 == NULL)  		return -ENOMEM; +	wm8510->regmap = devm_regmap_init_i2c(i2c, &wm8510_regmap); +	if (IS_ERR(wm8510->regmap)) +		return PTR_ERR(wm8510->regmap); +  	i2c_set_clientdata(i2c, wm8510); -	wm8510->control_type = SND_SOC_I2C;  	ret =  snd_soc_register_codec(&i2c->dev,  			&soc_codec_dev_wm8510, &wm8510_dai, 1); -	if (ret < 0) -		kfree(wm8510); +  	return ret;  } diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index 1c3ffb290cd..8d5c2767350 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c @@ -17,6 +17,7 @@  #include <linux/delay.h>  #include <linux/pm.h>  #include <linux/i2c.h> +#include <linux/regmap.h>  #include <linux/regulator/consumer.h>  #include <linux/slab.h>  #include <linux/of_device.h> @@ -39,41 +40,34 @@ static const char *wm8523_supply_names[WM8523_NUM_SUPPLIES] = {  /* codec private data */  struct wm8523_priv { -	enum snd_soc_control_type control_type; +	struct regmap *regmap;  	struct regulator_bulk_data supplies[WM8523_NUM_SUPPLIES];  	unsigned int sysclk;  	unsigned int rate_constraint_list[WM8523_NUM_RATES];  	struct snd_pcm_hw_constraint_list rate_constraint;  }; -static const u16 wm8523_reg[WM8523_REGISTER_COUNT] = { -	0x8523,     /* R0 - DEVICE_ID */ -	0x0001,     /* R1 - REVISION */ -	0x0000,     /* R2 - PSCTRL1 */ -	0x1812,     /* R3 - AIF_CTRL1 */ -	0x0000,     /* R4 - AIF_CTRL2 */ -	0x0001,     /* R5 - DAC_CTRL3 */ -	0x0190,     /* R6 - DAC_GAINL */ -	0x0190,     /* R7 - DAC_GAINR */ -	0x0000,     /* R8 - ZERO_DETECT */ +static const struct reg_default wm8523_reg_defaults[] = { +	{ 2, 0x0000 },     /* R2 - PSCTRL1 */ +	{ 3, 0x1812 },     /* R3 - AIF_CTRL1 */ +	{ 4, 0x0000 },     /* R4 - AIF_CTRL2 */ +	{ 5, 0x0001 },     /* R5 - DAC_CTRL3 */ +	{ 6, 0x0190 },     /* R6 - DAC_GAINL */ +	{ 7, 0x0190 },     /* R7 - DAC_GAINR */ +	{ 8, 0x0000 },     /* R8 - ZERO_DETECT */  }; -static int wm8523_volatile_register(struct snd_soc_codec *codec, unsigned int reg) +static bool wm8523_volatile_register(struct device *dev, unsigned int reg)  {  	switch (reg) {  	case WM8523_DEVICE_ID:  	case WM8523_REVISION: -		return 1; +		return true;  	default: -		return 0; +		return false;  	}  } -static int wm8523_reset(struct snd_soc_codec *codec) -{ -	return snd_soc_write(codec, WM8523_DEVICE_ID, 0); -} -  static const DECLARE_TLV_DB_SCALE(dac_tlv, -10000, 25, 0);  static const char *wm8523_zd_count_text[] = { @@ -301,8 +295,7 @@ static int wm8523_set_bias_level(struct snd_soc_codec *codec,  				 enum snd_soc_bias_level level)  {  	struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec); -	u16 *reg_cache = codec->reg_cache; -	int ret, i; +	int ret;  	switch (level) {  	case SND_SOC_BIAS_ON: @@ -325,16 +318,13 @@ static int wm8523_set_bias_level(struct snd_soc_codec *codec,  				return ret;  			} +			/* Sync back default/cached values */ +			regcache_sync(wm8523->regmap); +  			/* Initial power up */  			snd_soc_update_bits(codec, WM8523_PSCTRL1,  					    WM8523_SYS_ENA_MASK, 1); -			/* Sync back default/cached values */ -			for (i = WM8523_AIF_CTRL1; -			     i < WM8523_MAX_REGISTER; i++) -				snd_soc_write(codec, i, reg_cache[i]); - -  			msleep(100);  		} @@ -402,60 +392,18 @@ static int wm8523_resume(struct snd_soc_codec *codec)  static int wm8523_probe(struct snd_soc_codec *codec)  {  	struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec); -	int ret, i; +	int ret;  	wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0];  	wm8523->rate_constraint.count =  		ARRAY_SIZE(wm8523->rate_constraint_list); -	ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8523->control_type); +	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);  	if (ret != 0) {  		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);  		return ret;  	} -	for (i = 0; i < ARRAY_SIZE(wm8523->supplies); i++) -		wm8523->supplies[i].supply = wm8523_supply_names[i]; - -	ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8523->supplies), -				 wm8523->supplies); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to request supplies: %d\n", ret); -		return ret; -	} - -	ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies), -				    wm8523->supplies); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); -		goto err_get; -	} - -	ret = snd_soc_read(codec, WM8523_DEVICE_ID); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to read ID register\n"); -		goto err_enable; -	} -	if (ret != wm8523_reg[WM8523_DEVICE_ID]) { -		dev_err(codec->dev, "Device is not a WM8523, ID is %x\n", ret); -		ret = -EINVAL; -		goto err_enable; -	} - -	ret = snd_soc_read(codec, WM8523_REVISION); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to read revision register\n"); -		goto err_enable; -	} -	dev_info(codec->dev, "revision %c\n", -		 (ret & WM8523_CHIP_REV_MASK) + 'A'); - -	ret = wm8523_reset(codec); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to issue reset\n"); -		goto err_enable; -	} -  	/* Change some default settings - latch VU and enable ZC */  	snd_soc_update_bits(codec, WM8523_DAC_GAINR,  			    WM8523_DACR_VU, WM8523_DACR_VU); @@ -463,25 +411,12 @@ static int wm8523_probe(struct snd_soc_codec *codec)  	wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY); -	/* Bias level configuration will have done an extra enable */ -	regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); -  	return 0; - -err_enable: -	regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); -err_get: -	regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); - -	return ret;  }  static int wm8523_remove(struct snd_soc_codec *codec)  { -	struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec); -  	wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF); -	regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);  	return 0;  } @@ -491,10 +426,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8523 = {  	.suspend =	wm8523_suspend,  	.resume =	wm8523_resume,  	.set_bias_level = wm8523_set_bias_level, -	.reg_cache_size = WM8523_REGISTER_COUNT, -	.reg_word_size = sizeof(u16), -	.reg_cache_default = wm8523_reg, -	.volatile_register = wm8523_volatile_register,  	.controls = wm8523_controls,  	.num_controls = ARRAY_SIZE(wm8523_controls), @@ -509,32 +440,97 @@ static const struct of_device_id wm8523_of_match[] = {  	{ },  }; +static const struct regmap_config wm8523_regmap = { +	.reg_bits = 8, +	.val_bits = 16, +	.max_register = WM8523_ZERO_DETECT, + +	.reg_defaults = wm8523_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(wm8523_reg_defaults), +	.cache_type = REGCACHE_RBTREE, + +	.volatile_reg = wm8523_volatile_register, +}; +  #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)  static __devinit int wm8523_i2c_probe(struct i2c_client *i2c,  				      const struct i2c_device_id *id)  {  	struct wm8523_priv *wm8523; -	int ret; +	unsigned int val; +	int ret, i; -	wm8523 = kzalloc(sizeof(struct wm8523_priv), GFP_KERNEL); +	wm8523 = devm_kzalloc(&i2c->dev, sizeof(struct wm8523_priv), +			      GFP_KERNEL);  	if (wm8523 == NULL)  		return -ENOMEM; +	wm8523->regmap = devm_regmap_init_i2c(i2c, &wm8523_regmap); +	if (IS_ERR(wm8523->regmap)) { +		ret = PTR_ERR(wm8523->regmap); +		dev_err(&i2c->dev, "Failed to create regmap: %d\n", ret); +		return ret; +	} + +	for (i = 0; i < ARRAY_SIZE(wm8523->supplies); i++) +		wm8523->supplies[i].supply = wm8523_supply_names[i]; + +	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8523->supplies), +				      wm8523->supplies); +	if (ret != 0) { +		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); +		return ret; +	} + +	ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies), +				    wm8523->supplies); +	if (ret != 0) { +		dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); +		return ret; +	} + +	ret = regmap_read(wm8523->regmap, WM8523_DEVICE_ID, &val); +	if (ret < 0) { +		dev_err(&i2c->dev, "Failed to read ID register\n"); +		goto err_enable; +	} +	if (val != 0x8523) { +		dev_err(&i2c->dev, "Device is not a WM8523, ID is %x\n", ret); +		ret = -EINVAL; +		goto err_enable; +	} + +	ret = regmap_read(wm8523->regmap, WM8523_REVISION, &val); +	if (ret < 0) { +		dev_err(&i2c->dev, "Failed to read revision register\n"); +		goto err_enable; +	} +	dev_info(&i2c->dev, "revision %c\n", +		 (val & WM8523_CHIP_REV_MASK) + 'A'); + +	ret = regmap_write(wm8523->regmap, WM8523_DEVICE_ID, 0x8523); +	if (ret != 0) { +		dev_err(&i2c->dev, "Failed to reset device: %d\n", ret); +		goto err_enable; +	} + +	regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); +  	i2c_set_clientdata(i2c, wm8523); -	wm8523->control_type = SND_SOC_I2C;  	ret =  snd_soc_register_codec(&i2c->dev,  			&soc_codec_dev_wm8523, &wm8523_dai, 1); -	if (ret < 0) -		kfree(wm8523); +  	return ret; +err_enable: +	regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); +	return ret;  }  static __devexit int wm8523_i2c_remove(struct i2c_client *client)  {  	snd_soc_unregister_codec(&client->dev); -	kfree(i2c_get_clientdata(client));  	return 0;  } diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 7c68226376e..5e9c40fa7eb 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -1,7 +1,7 @@  /*   * wm8580.c  --  WM8580 ALSA Soc Audio driver   * - * Copyright 2008-11 Wolfson Microelectronics PLC. + * Copyright 2008-12 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 as published by the @@ -23,6 +23,7 @@  #include <linux/delay.h>  #include <linux/pm.h>  #include <linux/i2c.h> +#include <linux/regmap.h>  #include <linux/regulator/consumer.h>  #include <linux/slab.h>  #include <linux/of_device.h> @@ -157,23 +158,72 @@   * We can't read the WM8580 register space when we   * are using 2 wire for device control, so we cache them instead.   */ -static const u16 wm8580_reg[] = { -	0x0121, 0x017e, 0x007d, 0x0014, /*R3*/ -	0x0121, 0x017e, 0x007d, 0x0194, /*R7*/ -	0x0010, 0x0002, 0x0002, 0x00c2, /*R11*/ -	0x0182, 0x0082, 0x000a, 0x0024, /*R15*/ -	0x0009, 0x0000, 0x00ff, 0x0000, /*R19*/ -	0x00ff, 0x00ff, 0x00ff, 0x00ff, /*R23*/ -	0x00ff, 0x00ff, 0x00ff, 0x00ff, /*R27*/ -	0x01f0, 0x0040, 0x0000, 0x0000, /*R31(0x1F)*/ -	0x0000, 0x0000, 0x0031, 0x000b, /*R35*/ -	0x0039, 0x0000, 0x0010, 0x0032, /*R39*/ -	0x0054, 0x0076, 0x0098, 0x0000, /*R43(0x2B)*/ -	0x0000, 0x0000, 0x0000, 0x0000, /*R47*/ -	0x0000, 0x0000, 0x005e, 0x003e, /*R51(0x33)*/ -	0x0000, 0x0000 /*R53*/ +static const struct reg_default wm8580_reg_defaults[] = { +	{  0, 0x0121 }, +	{  1, 0x017e }, +	{  2, 0x007d }, +	{  3, 0x0014 }, +	{  4, 0x0121 }, +	{  5, 0x017e }, +	{  6, 0x007d }, +	{  7, 0x0194 }, +	{  8, 0x0010 }, +	{  9, 0x0002 }, +	{ 10, 0x0002 }, +	{ 11, 0x00c2 }, +	{ 12, 0x0182 }, +	{ 13, 0x0082 }, +	{ 14, 0x000a }, +	{ 15, 0x0024 }, +	{ 16, 0x0009 }, +	{ 17, 0x0000 }, +	{ 18, 0x00ff }, +	{ 19, 0x0000 }, +	{ 20, 0x00ff }, +	{ 21, 0x00ff }, +	{ 22, 0x00ff }, +	{ 23, 0x00ff }, +	{ 24, 0x00ff }, +	{ 25, 0x00ff }, +	{ 26, 0x00ff }, +	{ 27, 0x00ff }, +	{ 28, 0x01f0 }, +	{ 29, 0x0040 }, +	{ 30, 0x0000 }, +	{ 31, 0x0000 }, +	{ 32, 0x0000 }, +	{ 33, 0x0000 }, +	{ 34, 0x0031 }, +	{ 35, 0x000b }, +	{ 36, 0x0039 }, +	{ 37, 0x0000 }, +	{ 38, 0x0010 }, +	{ 39, 0x0032 }, +	{ 40, 0x0054 }, +	{ 41, 0x0076 }, +	{ 42, 0x0098 }, +	{ 43, 0x0000 }, +	{ 44, 0x0000 }, +	{ 45, 0x0000 }, +	{ 46, 0x0000 }, +	{ 47, 0x0000 }, +	{ 48, 0x0000 }, +	{ 49, 0x0000 }, +	{ 50, 0x005e }, +	{ 51, 0x003e }, +	{ 52, 0x0000 },  }; +static bool wm8580_volatile(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case WM8580_RESET: +		return true; +	default: +		return false; +	} +} +  struct pll_state {  	unsigned int in;  	unsigned int out; @@ -188,7 +238,7 @@ static const char *wm8580_supply_names[WM8580_NUM_SUPPLIES] = {  /* codec private data */  struct wm8580_priv { -	enum snd_soc_control_type control_type; +	struct regmap *regmap;  	struct regulator_bulk_data supplies[WM8580_NUM_SUPPLIES];  	struct pll_state a;  	struct pll_state b; @@ -203,14 +253,16 @@ static int wm8580_out_vu(struct snd_kcontrol *kcontrol,  	struct soc_mixer_control *mc =  		(struct soc_mixer_control *)kcontrol->private_value;  	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); -	u16 *reg_cache = codec->reg_cache; +	struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);  	unsigned int reg = mc->reg;  	unsigned int reg2 = mc->rreg;  	int ret; -	/* Clear the register cache so we write without VU set */ -	reg_cache[reg] = 0; -	reg_cache[reg2] = 0; +	/* Clear the register cache VU so we write without VU set */ +	regcache_cache_only(wm8580->regmap, true); +	regmap_update_bits(wm8580->regmap, reg, 0x100, 0x000); +	regmap_update_bits(wm8580->regmap, reg2, 0x100, 0x000); +	regcache_cache_only(wm8580->regmap, false);  	ret = snd_soc_put_volsw(kcontrol, ucontrol);  	if (ret < 0) @@ -815,24 +867,14 @@ static struct snd_soc_dai_driver wm8580_dai[] = {  static int wm8580_probe(struct snd_soc_codec *codec)  {  	struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec); -	int ret = 0,i; +	int ret = 0; -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8580->control_type); +	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);  	if (ret < 0) {  		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);  		return ret;  	} -	for (i = 0; i < ARRAY_SIZE(wm8580->supplies); i++) -		wm8580->supplies[i].supply = wm8580_supply_names[i]; - -	ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8580->supplies), -				 wm8580->supplies); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to request supplies: %d\n", ret); -		return ret; -	} -  	ret = regulator_bulk_enable(ARRAY_SIZE(wm8580->supplies),  				    wm8580->supplies);  	if (ret != 0) { @@ -854,7 +896,6 @@ static int wm8580_probe(struct snd_soc_codec *codec)  err_regulator_enable:  	regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);  err_regulator_get: -	regulator_bulk_free(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);  	return ret;  } @@ -866,7 +907,6 @@ static int wm8580_remove(struct snd_soc_codec *codec)  	wm8580_set_bias_level(codec, SND_SOC_BIAS_OFF);  	regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies); -	regulator_bulk_free(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);  	return 0;  } @@ -875,9 +915,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8580 = {  	.probe =	wm8580_probe,  	.remove =	wm8580_remove,  	.set_bias_level = wm8580_set_bias_level, -	.reg_cache_size = ARRAY_SIZE(wm8580_reg), -	.reg_word_size = sizeof(u16), -	.reg_cache_default = wm8580_reg,  	.controls = wm8580_snd_controls,  	.num_controls = ARRAY_SIZE(wm8580_snd_controls), @@ -892,31 +929,55 @@ static const struct of_device_id wm8580_of_match[] = {  	{ },  }; +static const struct regmap_config wm8580_regmap = { +	.reg_bits = 7, +	.val_bits = 9, +	.max_register = WM8580_MAX_REGISTER, + +	.reg_defaults = wm8580_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(wm8580_reg_defaults), +	.cache_type = REGCACHE_RBTREE, + +	.volatile_reg = wm8580_volatile, +}; +  #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)  static int wm8580_i2c_probe(struct i2c_client *i2c,  			    const struct i2c_device_id *id)  {  	struct wm8580_priv *wm8580; -	int ret; +	int ret, i; -	wm8580 = kzalloc(sizeof(struct wm8580_priv), GFP_KERNEL); +	wm8580 = devm_kzalloc(&i2c->dev, sizeof(struct wm8580_priv), +			      GFP_KERNEL);  	if (wm8580 == NULL)  		return -ENOMEM; +	wm8580->regmap = devm_regmap_init_i2c(i2c, &wm8580_regmap); +	if (IS_ERR(wm8580->regmap)) +		return PTR_ERR(wm8580->regmap); + +	for (i = 0; i < ARRAY_SIZE(wm8580->supplies); i++) +		wm8580->supplies[i].supply = wm8580_supply_names[i]; + +	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8580->supplies), +				      wm8580->supplies); +	if (ret != 0) { +		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); +		return ret; +	} +  	i2c_set_clientdata(i2c, wm8580); -	wm8580->control_type = SND_SOC_I2C;  	ret =  snd_soc_register_codec(&i2c->dev,  			&soc_codec_dev_wm8580, wm8580_dai, ARRAY_SIZE(wm8580_dai)); -	if (ret < 0) -		kfree(wm8580); +  	return ret;  }  static int wm8580_i2c_remove(struct i2c_client *client)  {  	snd_soc_unregister_codec(&client->dev); -	kfree(i2c_get_clientdata(client));  	return 0;  } diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index 0b76d1dca5e..8b8bb70f1eb 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -18,6 +18,7 @@  #include <linux/delay.h>  #include <linux/pm.h>  #include <linux/i2c.h> +#include <linux/regmap.h>  #include <linux/spi/spi.h>  #include <linux/slab.h>  #include <linux/of_device.h> @@ -32,7 +33,7 @@  /* codec private data */  struct wm8711_priv { -	enum snd_soc_control_type bus_type; +	struct regmap *regmap;  	unsigned int sysclk;  }; @@ -42,11 +43,21 @@ struct wm8711_priv {   * using 2 wire for device control, so we cache them instead.   * There is no point in caching the reset register   */ -static const u16 wm8711_reg[WM8711_CACHEREGNUM] = { -	0x0079, 0x0079, 0x000a, 0x0008, -	0x009f, 0x000a, 0x0000, 0x0000 +static const struct reg_default wm8711_reg_defaults[] = { +	{ 0, 0x0079 }, { 1, 0x0079 }, { 2, 0x000a }, { 3, 0x0008 }, +	{ 4, 0x009f }, { 5, 0x000a }, { 6, 0x0000 }, { 7, 0x0000 },  }; +static bool wm8711_volatile(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case WM8711_RESET: +		return true; +	default: +		return false; +	} +} +  #define wm8711_reset(c)	snd_soc_write(c, WM8711_RESET, 0)  static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1); @@ -289,6 +300,7 @@ static int wm8711_set_dai_fmt(struct snd_soc_dai *codec_dai,  static int wm8711_set_bias_level(struct snd_soc_codec *codec,  	enum snd_soc_bias_level level)  { +	struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);  	u16 reg = snd_soc_read(codec, WM8711_PWR) & 0xff7f;  	switch (level) { @@ -299,7 +311,7 @@ static int wm8711_set_bias_level(struct snd_soc_codec *codec,  		break;  	case SND_SOC_BIAS_STANDBY:  		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) -			snd_soc_cache_sync(codec); +			regcache_sync(wm8711->regmap);  		snd_soc_write(codec, WM8711_PWR, reg | 0x0040);  		break; @@ -353,10 +365,9 @@ static int wm8711_resume(struct snd_soc_codec *codec)  static int wm8711_probe(struct snd_soc_codec *codec)  { -	struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);  	int ret; -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8711->bus_type); +	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);  	if (ret < 0) {  		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);  		return ret; @@ -391,9 +402,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8711 = {  	.suspend =	wm8711_suspend,  	.resume =	wm8711_resume,  	.set_bias_level = wm8711_set_bias_level, -	.reg_cache_size = ARRAY_SIZE(wm8711_reg), -	.reg_word_size = sizeof(u16), -	.reg_cache_default = wm8711_reg,  	.controls = wm8711_snd_controls,  	.num_controls = ARRAY_SIZE(wm8711_snd_controls),  	.dapm_widgets = wm8711_dapm_widgets, @@ -408,30 +416,45 @@ static const struct of_device_id wm8711_of_match[] = {  };  MODULE_DEVICE_TABLE(of, wm8711_of_match); +static const struct regmap_config wm8711_regmap = { +	.reg_bits = 7, +	.val_bits = 9, +	.max_register = WM8711_RESET, + +	.reg_defaults = wm8711_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(wm8711_reg_defaults), +	.cache_type = REGCACHE_RBTREE, + +	.volatile_reg = wm8711_volatile, +}; +  #if defined(CONFIG_SPI_MASTER)  static int __devinit wm8711_spi_probe(struct spi_device *spi)  {  	struct wm8711_priv *wm8711;  	int ret; -	wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL); +	wm8711 = devm_kzalloc(&spi->dev, sizeof(struct wm8711_priv), +			      GFP_KERNEL);  	if (wm8711 == NULL)  		return -ENOMEM; +	wm8711->regmap = devm_regmap_init_spi(spi, &wm8711_regmap); +	if (IS_ERR(wm8711->regmap)) +		return PTR_ERR(wm8711->regmap); +  	spi_set_drvdata(spi, wm8711); -	wm8711->bus_type = SND_SOC_SPI;  	ret = snd_soc_register_codec(&spi->dev,  			&soc_codec_dev_wm8711, &wm8711_dai, 1); -	if (ret < 0) -		kfree(wm8711); +  	return ret;  }  static int __devexit wm8711_spi_remove(struct spi_device *spi)  {  	snd_soc_unregister_codec(&spi->dev); -	kfree(spi_get_drvdata(spi)); +  	return 0;  } @@ -453,24 +476,26 @@ static __devinit int wm8711_i2c_probe(struct i2c_client *client,  	struct wm8711_priv *wm8711;  	int ret; -	wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL); +	wm8711 = devm_kzalloc(&client->dev, sizeof(struct wm8711_priv), +			      GFP_KERNEL);  	if (wm8711 == NULL)  		return -ENOMEM; +	wm8711->regmap = devm_regmap_init_i2c(client, &wm8711_regmap); +	if (IS_ERR(wm8711->regmap)) +		return PTR_ERR(wm8711->regmap); +  	i2c_set_clientdata(client, wm8711); -	wm8711->bus_type = SND_SOC_I2C;  	ret =  snd_soc_register_codec(&client->dev,  			&soc_codec_dev_wm8711, &wm8711_dai, 1); -	if (ret < 0) -		kfree(wm8711); +  	return ret;  }  static __devexit int wm8711_i2c_remove(struct i2c_client *client)  {  	snd_soc_unregister_codec(&client->dev); -	kfree(i2c_get_clientdata(client));  	return 0;  } diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index 1467f97dce2..00a12a0c391 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -17,6 +17,7 @@  #include <linux/pm.h>  #include <linux/i2c.h>  #include <linux/platform_device.h> +#include <linux/regmap.h>  #include <linux/spi/spi.h>  #include <linux/slab.h>  #include <linux/of_device.h> @@ -35,16 +36,16 @@   * the volume update bits, mute the output and enable infinite zero   * detect.   */ -static const u16 wm8728_reg_defaults[] = { -	0x1ff, -	0x1ff, -	0x001, -	0x100, +static const struct reg_default wm8728_reg_defaults[] = { +	{ 0, 0x1ff }, +	{ 1, 0x1ff }, +	{ 2, 0x001 }, +	{ 3, 0x100 },  };  /* codec private data */  struct wm8728_priv { -	enum snd_soc_control_type control_type; +	struct regmap *regmap;  };  static const DECLARE_TLV_DB_SCALE(wm8728_tlv, -12750, 50, 1); @@ -162,8 +163,8 @@ static int wm8728_set_dai_fmt(struct snd_soc_dai *codec_dai,  static int wm8728_set_bias_level(struct snd_soc_codec *codec,  				 enum snd_soc_bias_level level)  { +	struct wm8728_priv *wm8728 = snd_soc_codec_get_drvdata(codec);  	u16 reg; -	int i;  	switch (level) {  	case SND_SOC_BIAS_ON: @@ -175,9 +176,7 @@ static int wm8728_set_bias_level(struct snd_soc_codec *codec,  			snd_soc_write(codec, WM8728_DACCTL, reg & ~0x4);  			/* ..then sync in the register cache. */ -			for (i = 0; i < ARRAY_SIZE(wm8728_reg_defaults); i++) -				snd_soc_write(codec, i, -					     snd_soc_read(codec, i)); +			regcache_sync(wm8728->regmap);  		}  		break; @@ -229,10 +228,9 @@ static int wm8728_resume(struct snd_soc_codec *codec)  static int wm8728_probe(struct snd_soc_codec *codec)  { -	struct wm8728_priv *wm8728 = snd_soc_codec_get_drvdata(codec);  	int ret; -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8728->control_type); +	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);  	if (ret < 0) {  		printk(KERN_ERR "wm8728: failed to configure cache I/O: %d\n",  		       ret); @@ -257,9 +255,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8728 = {  	.suspend =	wm8728_suspend,  	.resume =	wm8728_resume,  	.set_bias_level = wm8728_set_bias_level, -	.reg_cache_size = ARRAY_SIZE(wm8728_reg_defaults), -	.reg_word_size = sizeof(u16), -	.reg_cache_default = wm8728_reg_defaults,  	.controls = wm8728_snd_controls,  	.num_controls = ARRAY_SIZE(wm8728_snd_controls),  	.dapm_widgets = wm8728_dapm_widgets, @@ -274,30 +269,43 @@ static const struct of_device_id wm8728_of_match[] = {  };  MODULE_DEVICE_TABLE(of, wm8728_of_match); +static const struct regmap_config wm8728_regmap = { +	.reg_bits = 7, +	.val_bits = 9, +	.max_register = WM8728_IFCTL, + +	.reg_defaults = wm8728_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(wm8728_reg_defaults), +	.cache_type = REGCACHE_RBTREE, +}; +  #if defined(CONFIG_SPI_MASTER)  static int __devinit wm8728_spi_probe(struct spi_device *spi)  {  	struct wm8728_priv *wm8728;  	int ret; -	wm8728 = kzalloc(sizeof(struct wm8728_priv), GFP_KERNEL); +	wm8728 = devm_kzalloc(&spi->dev, sizeof(struct wm8728_priv), +			      GFP_KERNEL);  	if (wm8728 == NULL)  		return -ENOMEM; -	wm8728->control_type = SND_SOC_SPI; +	wm8728->regmap = devm_regmap_init_spi(spi, &wm8728_regmap); +	if (IS_ERR(wm8728->regmap)) +		return PTR_ERR(wm8728->regmap); +  	spi_set_drvdata(spi, wm8728);  	ret = snd_soc_register_codec(&spi->dev,  			&soc_codec_dev_wm8728, &wm8728_dai, 1); -	if (ret < 0) -		kfree(wm8728); +  	return ret;  }  static int __devexit wm8728_spi_remove(struct spi_device *spi)  {  	snd_soc_unregister_codec(&spi->dev); -	kfree(spi_get_drvdata(spi)); +  	return 0;  } @@ -319,24 +327,26 @@ static __devinit int wm8728_i2c_probe(struct i2c_client *i2c,  	struct wm8728_priv *wm8728;  	int ret; -	wm8728 = kzalloc(sizeof(struct wm8728_priv), GFP_KERNEL); +	wm8728 = devm_kzalloc(&i2c->dev, sizeof(struct wm8728_priv), +			      GFP_KERNEL);  	if (wm8728 == NULL)  		return -ENOMEM; +	wm8728->regmap = devm_regmap_init_i2c(i2c, &wm8728_regmap); +	if (IS_ERR(wm8728->regmap)) +		return PTR_ERR(wm8728->regmap); +  	i2c_set_clientdata(i2c, wm8728); -	wm8728->control_type = SND_SOC_I2C;  	ret =  snd_soc_register_codec(&i2c->dev,  			&soc_codec_dev_wm8728, &wm8728_dai, 1); -	if (ret < 0) -		kfree(wm8728); +  	return ret;  }  static __devexit int wm8728_i2c_remove(struct i2c_client *client)  {  	snd_soc_unregister_codec(&client->dev); -	kfree(i2c_get_clientdata(client));  	return 0;  } diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c index d0520124616..5c9634f4c1f 100644 --- a/sound/soc/codecs/wm8737.c +++ b/sound/soc/codecs/wm8737.c @@ -16,6 +16,7 @@  #include <linux/delay.h>  #include <linux/pm.h>  #include <linux/i2c.h> +#include <linux/regmap.h>  #include <linux/regulator/consumer.h>  #include <linux/spi/spi.h>  #include <linux/slab.h> @@ -40,29 +41,39 @@ static const char *wm8737_supply_names[WM8737_NUM_SUPPLIES] = {  /* codec private data */  struct wm8737_priv { -	enum snd_soc_control_type control_type; +	struct regmap *regmap;  	struct regulator_bulk_data supplies[WM8737_NUM_SUPPLIES];  	unsigned int mclk;  }; -static const u16 wm8737_reg[WM8737_REGISTER_COUNT] = { -	0x00C3,     /* R0  - Left PGA volume */ -	0x00C3,     /* R1  - Right PGA volume */ -	0x0007,     /* R2  - AUDIO path L */ -	0x0007,     /* R3  - AUDIO path R */ -	0x0000,     /* R4  - 3D Enhance */ -	0x0000,     /* R5  - ADC Control */ -	0x0000,     /* R6  - Power Management */ -	0x000A,     /* R7  - Audio Format */ -	0x0000,     /* R8  - Clocking */ -	0x000F,     /* R9  - MIC Preamp Control */ -	0x0003,     /* R10 - Misc Bias Control */ -	0x0000,     /* R11 - Noise Gate */ -	0x007C,     /* R12 - ALC1 */ -	0x0000,     /* R13 - ALC2 */ -	0x0032,     /* R14 - ALC3 */ +static const struct reg_default wm8737_reg_defaults[] = { +	{  0, 0x00C3 },     /* R0  - Left PGA volume */ +	{  1, 0x00C3 },     /* R1  - Right PGA volume */ +	{  2, 0x0007 },     /* R2  - AUDIO path L */ +	{  3, 0x0007 },     /* R3  - AUDIO path R */ +	{  4, 0x0000 },     /* R4  - 3D Enhance */ +	{  5, 0x0000 },     /* R5  - ADC Control */ +	{  6, 0x0000 },     /* R6  - Power Management */ +	{  7, 0x000A },     /* R7  - Audio Format */ +	{  8, 0x0000 },     /* R8  - Clocking */ +	{  9, 0x000F },     /* R9  - MIC Preamp Control */ +	{ 10, 0x0003 },     /* R10 - Misc Bias Control */ +	{ 11, 0x0000 },     /* R11 - Noise Gate */ +	{ 12, 0x007C },     /* R12 - ALC1 */ +	{ 13, 0x0000 },     /* R13 - ALC2 */ +	{ 14, 0x0032 },     /* R14 - ALC3 */  }; +static bool wm8737_volatile(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case WM8737_RESET: +		return true; +	default: +		return false; +	} +} +  static int wm8737_reset(struct snd_soc_codec *codec)  {  	return snd_soc_write(codec, WM8737_RESET, 0); @@ -479,7 +490,7 @@ static int wm8737_set_bias_level(struct snd_soc_codec *codec,  				return ret;  			} -			snd_soc_cache_sync(codec); +			regcache_sync(wm8737->regmap);  			/* Fast VMID ramp at 2*2.5k */  			snd_soc_update_bits(codec, WM8737_MISC_BIAS_CONTROL, @@ -557,24 +568,14 @@ static int wm8737_resume(struct snd_soc_codec *codec)  static int wm8737_probe(struct snd_soc_codec *codec)  {  	struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec); -	int ret, i; +	int ret; -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8737->control_type); +	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);  	if (ret != 0) {  		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);  		return ret;  	} -	for (i = 0; i < ARRAY_SIZE(wm8737->supplies); i++) -		wm8737->supplies[i].supply = wm8737_supply_names[i]; - -	ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8737->supplies), -				 wm8737->supplies); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to request supplies: %d\n", ret); -		return ret; -	} -  	ret = regulator_bulk_enable(ARRAY_SIZE(wm8737->supplies),  				    wm8737->supplies);  	if (ret != 0) { @@ -607,17 +608,12 @@ static int wm8737_probe(struct snd_soc_codec *codec)  err_enable:  	regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies), wm8737->supplies);  err_get: -	regulator_bulk_free(ARRAY_SIZE(wm8737->supplies), wm8737->supplies); -  	return ret;  }  static int wm8737_remove(struct snd_soc_codec *codec)  { -	struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec); -  	wm8737_set_bias_level(codec, SND_SOC_BIAS_OFF); -	regulator_bulk_free(ARRAY_SIZE(wm8737->supplies), wm8737->supplies);  	return 0;  } @@ -627,10 +623,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8737 = {  	.suspend	= wm8737_suspend,  	.resume		= wm8737_resume,  	.set_bias_level = wm8737_set_bias_level, - -	.reg_cache_size = WM8737_REGISTER_COUNT - 1, /* Skip reset */ -	.reg_word_size	= sizeof(u16), -	.reg_cache_default = wm8737_reg,  };  static const struct of_device_id wm8737_of_match[] = { @@ -640,24 +632,49 @@ static const struct of_device_id wm8737_of_match[] = {  MODULE_DEVICE_TABLE(of, wm8737_of_match); +static const struct regmap_config wm8737_regmap = { +	.reg_bits = 7, +	.val_bits = 9, +	.max_register = WM8737_MAX_REGISTER, + +	.reg_defaults = wm8737_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(wm8737_reg_defaults), +	.cache_type = REGCACHE_RBTREE, + +	.volatile_reg = wm8737_volatile, +}; +  #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)  static __devinit int wm8737_i2c_probe(struct i2c_client *i2c,  				      const struct i2c_device_id *id)  {  	struct wm8737_priv *wm8737; -	int ret; +	int ret, i; -	wm8737 = kzalloc(sizeof(struct wm8737_priv), GFP_KERNEL); +	wm8737 = devm_kzalloc(&i2c->dev, sizeof(struct wm8737_priv), +			      GFP_KERNEL);  	if (wm8737 == NULL)  		return -ENOMEM; +	for (i = 0; i < ARRAY_SIZE(wm8737->supplies); i++) +		wm8737->supplies[i].supply = wm8737_supply_names[i]; + +	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8737->supplies), +				      wm8737->supplies); +	if (ret != 0) { +		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); +		return ret; +	} + +	wm8737->regmap = devm_regmap_init_i2c(i2c, &wm8737_regmap); +	if (IS_ERR(wm8737->regmap)) +		return PTR_ERR(wm8737->regmap); +  	i2c_set_clientdata(i2c, wm8737); -	wm8737->control_type = SND_SOC_I2C;  	ret =  snd_soc_register_codec(&i2c->dev,  				      &soc_codec_dev_wm8737, &wm8737_dai, 1); -	if (ret < 0) -		kfree(wm8737); +  	return ret;  } @@ -665,7 +682,7 @@ static __devinit int wm8737_i2c_probe(struct i2c_client *i2c,  static __devexit int wm8737_i2c_remove(struct i2c_client *client)  {  	snd_soc_unregister_codec(&client->dev); -	kfree(i2c_get_clientdata(client)); +  	return 0;  } @@ -691,26 +708,39 @@ static struct i2c_driver wm8737_i2c_driver = {  static int __devinit wm8737_spi_probe(struct spi_device *spi)  {  	struct wm8737_priv *wm8737; -	int ret; +	int ret, i; -	wm8737 = kzalloc(sizeof(struct wm8737_priv), GFP_KERNEL); +	wm8737 = devm_kzalloc(&spi->dev, sizeof(struct wm8737_priv), +			      GFP_KERNEL);  	if (wm8737 == NULL)  		return -ENOMEM; -	wm8737->control_type = SND_SOC_SPI; +	for (i = 0; i < ARRAY_SIZE(wm8737->supplies); i++) +		wm8737->supplies[i].supply = wm8737_supply_names[i]; + +	ret = devm_regulator_bulk_get(&spi->dev, ARRAY_SIZE(wm8737->supplies), +				      wm8737->supplies); +	if (ret != 0) { +		dev_err(&spi->dev, "Failed to request supplies: %d\n", ret); +		return ret; +	} + +	wm8737->regmap = devm_regmap_init_spi(spi, &wm8737_regmap); +	if (IS_ERR(wm8737->regmap)) +		return PTR_ERR(wm8737->regmap); +  	spi_set_drvdata(spi, wm8737);  	ret = snd_soc_register_codec(&spi->dev,  				     &soc_codec_dev_wm8737, &wm8737_dai, 1); -	if (ret < 0) -		kfree(wm8737); +  	return ret;  }  static int __devexit wm8737_spi_remove(struct spi_device *spi)  {  	snd_soc_unregister_codec(&spi->dev); -	kfree(spi_get_drvdata(spi)); +  	return 0;  } diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c index 35f3d23200e..4281a080213 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c @@ -18,6 +18,7 @@  #include <linux/pm.h>  #include <linux/i2c.h>  #include <linux/spi/spi.h> +#include <linux/regmap.h>  #include <linux/regulator/consumer.h>  #include <linux/slab.h>  #include <linux/of_device.h> @@ -40,26 +41,43 @@ static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = {  /* codec private data */  struct wm8741_priv { -	enum snd_soc_control_type control_type; +	struct regmap *regmap;  	struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES];  	unsigned int sysclk;  	struct snd_pcm_hw_constraint_list *sysclk_constraints;  }; -static const u16 wm8741_reg_defaults[WM8741_REGISTER_COUNT] = { -	0x0000,     /* R0  - DACLLSB Attenuation */ -	0x0000,     /* R1  - DACLMSB Attenuation */ -	0x0000,     /* R2  - DACRLSB Attenuation */ -	0x0000,     /* R3  - DACRMSB Attenuation */ -	0x0000,     /* R4  - Volume Control */ -	0x000A,     /* R5  - Format Control */ -	0x0000,     /* R6  - Filter Control */ -	0x0000,     /* R7  - Mode Control 1 */ -	0x0002,     /* R8  - Mode Control 2 */ -	0x0000,	    /* R9  - Reset */ -	0x0002,     /* R32 - ADDITONAL_CONTROL_1 */ +static const struct reg_default wm8741_reg_defaults[] = { +	{  0, 0x0000 },     /* R0  - DACLLSB Attenuation */ +	{  1, 0x0000 },     /* R1  - DACLMSB Attenuation */ +	{  2, 0x0000 },     /* R2  - DACRLSB Attenuation */ +	{  3, 0x0000 },     /* R3  - DACRMSB Attenuation */ +	{  4, 0x0000 },     /* R4  - Volume Control */ +	{  5, 0x000A },     /* R5  - Format Control */ +	{  6, 0x0000 },     /* R6  - Filter Control */ +	{  7, 0x0000 },     /* R7  - Mode Control 1 */ +	{  8, 0x0002 },     /* R8  - Mode Control 2 */ +	{ 32, 0x0002 },     /* R32 - ADDITONAL_CONTROL_1 */  }; +static bool wm8741_readable(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case WM8741_DACLLSB_ATTENUATION: +	case WM8741_DACLMSB_ATTENUATION: +	case WM8741_DACRLSB_ATTENUATION: +	case WM8741_DACRMSB_ATTENUATION: +	case WM8741_VOLUME_CONTROL: +	case WM8741_FORMAT_CONTROL: +	case WM8741_FILTER_CONTROL: +	case WM8741_MODE_CONTROL_1: +	case WM8741_MODE_CONTROL_2: +	case WM8741_ADDITIONAL_CONTROL_1: +		return true; +	default: +		return false; +	} +}  static int wm8741_reset(struct snd_soc_codec *codec)  { @@ -403,17 +421,6 @@ static int wm8741_probe(struct snd_soc_codec *codec)  {  	struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);  	int ret = 0; -	int i; - -	for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++) -		wm8741->supplies[i].supply = wm8741_supply_names[i]; - -	ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8741->supplies), -				 wm8741->supplies); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to request supplies: %d\n", ret); -		goto err; -	}  	ret = regulator_bulk_enable(ARRAY_SIZE(wm8741->supplies),  				    wm8741->supplies); @@ -422,7 +429,7 @@ static int wm8741_probe(struct snd_soc_codec *codec)  		goto err_get;  	} -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8741->control_type); +	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);  	if (ret != 0) {  		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);  		goto err_enable; @@ -450,8 +457,6 @@ static int wm8741_probe(struct snd_soc_codec *codec)  err_enable:  	regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);  err_get: -	regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies); -err:  	return ret;  } @@ -460,7 +465,6 @@ static int wm8741_remove(struct snd_soc_codec *codec)  	struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);  	regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies); -	regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);  	return 0;  } @@ -469,9 +473,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8741 = {  	.probe =	wm8741_probe,  	.remove =	wm8741_remove,  	.resume =	wm8741_resume, -	.reg_cache_size = ARRAY_SIZE(wm8741_reg_defaults), -	.reg_word_size = sizeof(u16), -	.reg_cache_default = wm8741_reg_defaults,  	.controls = wm8741_snd_controls,  	.num_controls = ARRAY_SIZE(wm8741_snd_controls), @@ -487,20 +488,48 @@ static const struct of_device_id wm8741_of_match[] = {  };  MODULE_DEVICE_TABLE(of, wm8741_of_match); +static const struct regmap_config wm8741_regmap = { +	.reg_bits = 7, +	.val_bits = 9, +	.max_register = WM8741_MAX_REGISTER, + +	.reg_defaults = wm8741_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(wm8741_reg_defaults), +	.cache_type = REGCACHE_RBTREE, + +	.readable_reg = wm8741_readable, +}; +  #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)  static int wm8741_i2c_probe(struct i2c_client *i2c,  			    const struct i2c_device_id *id)  {  	struct wm8741_priv *wm8741; -	int ret; +	int ret, i;  	wm8741 = devm_kzalloc(&i2c->dev, sizeof(struct wm8741_priv),  			      GFP_KERNEL);  	if (wm8741 == NULL)  		return -ENOMEM; +	for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++) +		wm8741->supplies[i].supply = wm8741_supply_names[i]; + +	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8741->supplies), +				      wm8741->supplies); +	if (ret != 0) { +		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); +		return ret; +	} + +	wm8741->regmap = regmap_init_i2c(i2c, &wm8741_regmap); +	if (IS_ERR(wm8741->regmap)) { +		ret = PTR_ERR(wm8741->regmap); +		dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret); +		return ret; +	} +  	i2c_set_clientdata(i2c, wm8741); -	wm8741->control_type = SND_SOC_I2C;  	ret = snd_soc_register_codec(&i2c->dev,  				     &soc_codec_dev_wm8741, &wm8741_dai, 1); @@ -536,14 +565,30 @@ static struct i2c_driver wm8741_i2c_driver = {  static int __devinit wm8741_spi_probe(struct spi_device *spi)  {  	struct wm8741_priv *wm8741; -	int ret; +	int ret, i;  	wm8741 = devm_kzalloc(&spi->dev, sizeof(struct wm8741_priv),  			     GFP_KERNEL);  	if (wm8741 == NULL)  		return -ENOMEM; -	wm8741->control_type = SND_SOC_SPI; +	for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++) +		wm8741->supplies[i].supply = wm8741_supply_names[i]; + +	ret = devm_regulator_bulk_get(&spi->dev, ARRAY_SIZE(wm8741->supplies), +				      wm8741->supplies); +	if (ret != 0) { +		dev_err(&spi->dev, "Failed to request supplies: %d\n", ret); +		return ret; +	} + +	wm8741->regmap = regmap_init_spi(spi, &wm8741_regmap); +	if (IS_ERR(wm8741->regmap)) { +		ret = PTR_ERR(wm8741->regmap); +		dev_err(&spi->dev, "Failed to init regmap: %d\n", ret); +		return ret; +	} +  	spi_set_drvdata(spi, wm8741);  	ret = snd_soc_register_codec(&spi->dev, diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c index a5127b4ff9e..c7c0034d396 100644 --- a/sound/soc/codecs/wm8770.c +++ b/sound/soc/codecs/wm8770.c @@ -724,24 +724,7 @@ static struct spi_driver wm8770_spi_driver = {  	.remove = __devexit_p(wm8770_spi_remove)  }; -static int __init wm8770_modinit(void) -{ -	int ret = 0; - -	ret = spi_register_driver(&wm8770_spi_driver); -	if (ret) { -		printk(KERN_ERR "Failed to register wm8770 SPI driver: %d\n", -		       ret); -	} -	return ret; -} -module_init(wm8770_modinit); - -static void __exit wm8770_exit(void) -{ -	spi_unregister_driver(&wm8770_spi_driver); -} -module_exit(wm8770_exit); +module_spi_driver(wm8770_spi_driver);  MODULE_DESCRIPTION("ASoC WM8770 driver");  MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>"); diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index 879c356a904..c32249ddb2e 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c @@ -19,6 +19,7 @@  #include <linux/pm.h>  #include <linux/i2c.h>  #include <linux/of_device.h> +#include <linux/regmap.h>  #include <linux/spi/spi.h>  #include <linux/slab.h>  #include <sound/core.h> @@ -37,18 +38,46 @@ enum wm8776_chip_type {  /* codec private data */  struct wm8776_priv { -	enum snd_soc_control_type control_type; +	struct regmap *regmap;  	int sysclk[2];  }; -static const u16 wm8776_reg[WM8776_CACHEREGNUM] = { -	0x79, 0x79, 0x79, 0xff, 0xff,  /* 4 */ -	0xff, 0x00, 0x90, 0x00, 0x00,  /* 9 */ -	0x22, 0x22, 0x22, 0x08, 0xcf,  /* 14 */ -	0xcf, 0x7b, 0x00, 0x32, 0x00,  /* 19 */ -	0xa6, 0x01, 0x01 +static const struct reg_default wm8776_reg_defaults[] = { +	{  0, 0x79 }, +	{  1, 0x79 }, +	{  2, 0x79 }, +	{  3, 0xff }, +	{  4, 0xff }, +	{  5, 0xff }, +	{  6, 0x00 }, +	{  7, 0x90 }, +	{  8, 0x00 }, +	{  9, 0x00 }, +	{ 10, 0x22 }, +	{ 11, 0x22 }, +	{ 12, 0x22 }, +	{ 13, 0x08 }, +	{ 14, 0xcf }, +	{ 15, 0xcf }, +	{ 16, 0x7b }, +	{ 17, 0x00 }, +	{ 18, 0x32 }, +	{ 19, 0x00 }, +	{ 20, 0xa6 }, +	{ 21, 0x01 }, +	{ 22, 0x01 },  }; +static bool wm8776_volatile(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case WM8776_RESET: +		return true; +	default: +		return false; +	} +} +  static int wm8776_reset(struct snd_soc_codec *codec)  {  	return snd_soc_write(codec, WM8776_RESET, 0); @@ -306,6 +335,8 @@ static int wm8776_set_sysclk(struct snd_soc_dai *dai,  static int wm8776_set_bias_level(struct snd_soc_codec *codec,  				 enum snd_soc_bias_level level)  { +	struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec); +  	switch (level) {  	case SND_SOC_BIAS_ON:  		break; @@ -313,7 +344,7 @@ static int wm8776_set_bias_level(struct snd_soc_codec *codec,  		break;  	case SND_SOC_BIAS_STANDBY:  		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { -			snd_soc_cache_sync(codec); +			regcache_sync(wm8776->regmap);  			/* Disable the global powerdown; DAPM does the rest */  			snd_soc_update_bits(codec, WM8776_PWRDOWN, 1, 0); @@ -396,10 +427,9 @@ static int wm8776_resume(struct snd_soc_codec *codec)  static int wm8776_probe(struct snd_soc_codec *codec)  { -	struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec);  	int ret = 0; -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8776->control_type); +	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);  	if (ret < 0) {  		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);  		return ret; @@ -434,9 +464,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8776 = {  	.suspend = 	wm8776_suspend,  	.resume =	wm8776_resume,  	.set_bias_level = wm8776_set_bias_level, -	.reg_cache_size = ARRAY_SIZE(wm8776_reg), -	.reg_word_size = sizeof(u16), -	.reg_cache_default = wm8776_reg,  	.controls = wm8776_snd_controls,  	.num_controls = ARRAY_SIZE(wm8776_snd_controls), @@ -452,6 +479,18 @@ static const struct of_device_id wm8776_of_match[] = {  };  MODULE_DEVICE_TABLE(of, wm8776_of_match); +static const struct regmap_config wm8776_regmap = { +	.reg_bits = 7, +	.val_bits = 9, +	.max_register = WM8776_RESET, + +	.reg_defaults = wm8776_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(wm8776_reg_defaults), +	.cache_type = REGCACHE_RBTREE, + +	.volatile_reg = wm8776_volatile, +}; +  #if defined(CONFIG_SPI_MASTER)  static int __devinit wm8776_spi_probe(struct spi_device *spi)  { @@ -463,7 +502,10 @@ static int __devinit wm8776_spi_probe(struct spi_device *spi)  	if (wm8776 == NULL)  		return -ENOMEM; -	wm8776->control_type = SND_SOC_SPI; +	wm8776->regmap = devm_regmap_init_spi(spi, &wm8776_regmap); +	if (IS_ERR(wm8776->regmap)) +		return PTR_ERR(wm8776->regmap); +  	spi_set_drvdata(spi, wm8776);  	ret = snd_soc_register_codec(&spi->dev, @@ -501,8 +543,11 @@ static __devinit int wm8776_i2c_probe(struct i2c_client *i2c,  	if (wm8776 == NULL)  		return -ENOMEM; +	wm8776->regmap = devm_regmap_init_i2c(i2c, &wm8776_regmap); +	if (IS_ERR(wm8776->regmap)) +		return PTR_ERR(wm8776->regmap); +  	i2c_set_clientdata(i2c, wm8776); -	wm8776->control_type = SND_SOC_I2C;  	ret =  snd_soc_register_codec(&i2c->dev,  			&soc_codec_dev_wm8776, wm8776_dai, ARRAY_SIZE(wm8776_dai)); diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 077c9628c70..e781f865e5d 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -23,6 +23,7 @@  #include <linux/delay.h>  #include <linux/pm.h>  #include <linux/i2c.h> +#include <linux/regmap.h>  #include <linux/spi/spi.h>  #include <linux/slab.h>  #include <sound/core.h> @@ -137,7 +138,7 @@  #define WM8900_LRC_MASK 0x03ff  struct wm8900_priv { -	enum snd_soc_control_type control_type; +	struct regmap *regmap;  	u32 fll_in; /* FLL input frequency */  	u32 fll_out; /* FLL output frequency */ @@ -147,54 +148,77 @@ struct wm8900_priv {   * wm8900 register cache.  We can't read the entire register space and we   * have slow control buses so we cache the registers.   */ -static const u16 wm8900_reg_defaults[WM8900_MAXREG] = { -	0x8900, 0x0000, -	0xc000, 0x0000, -	0x4050, 0x4000, -	0x0008, 0x0000, -	0x0040, 0x0040, -	0x1004, 0x00c0, -	0x00c0, 0x0000, -	0x0100, 0x00c0, -	0x00c0, 0x0000, -	0xb001, 0x0000, -	0x0000, 0x0044, -	0x004c, 0x004c, -	0x0044, 0x0044, -	0x0000, 0x0044, -	0x0000, 0x0000, -	0x0002, 0x0000, -	0x0000, 0x0000, -	0x0000, 0x0000, -	0x0008, 0x0000, -	0x0000, 0x0008, -	0x0097, 0x0100, -	0x0000, 0x0000, -	0x0050, 0x0050, -	0x0055, 0x0055, -	0x0055, 0x0000, -	0x0000, 0x0079, -	0x0079, 0x0079, -	0x0079, 0x0000, -	/* Remaining registers all zero */ +static const struct reg_default wm8900_reg_defaults[] = { +	{  1, 0x0000 }, +	{  2, 0xc000 }, +	{  3, 0x0000 }, +	{  4, 0x4050 }, +	{  5, 0x4000 }, +	{  6, 0x0008 }, +	{  7, 0x0000 }, +	{  8, 0x0040 }, +	{  9, 0x0040 }, +	{ 10, 0x1004 }, +	{ 11, 0x00c0 }, +	{ 12, 0x00c0 }, +	{ 13, 0x0000 }, +	{ 14, 0x0100 }, +	{ 15, 0x00c0 }, +	{ 16, 0x00c0 }, +	{ 17, 0x0000 }, +	{ 18, 0xb001 }, +	{ 19, 0x0000 }, +	{ 20, 0x0000 }, +	{ 21, 0x0044 }, +	{ 22, 0x004c }, +	{ 23, 0x004c }, +	{ 24, 0x0044 }, +	{ 25, 0x0044 }, +	{ 26, 0x0000 }, +	{ 27, 0x0044 }, +	{ 28, 0x0000 }, +	{ 29, 0x0000 }, +	{ 30, 0x0002 }, +	{ 31, 0x0000 }, +	{ 32, 0x0000 }, +	{ 33, 0x0000 }, +	{ 34, 0x0000 }, +	{ 35, 0x0000 }, +	{ 36, 0x0008 }, +	{ 37, 0x0000 }, +	{ 38, 0x0000 }, +	{ 39, 0x0008 }, +	{ 40, 0x0097 }, +	{ 41, 0x0100 }, +	{ 42, 0x0000 }, +	{ 43, 0x0000 }, +	{ 44, 0x0050 }, +	{ 45, 0x0050 }, +	{ 46, 0x0055 }, +	{ 47, 0x0055 }, +	{ 48, 0x0055 }, +	{ 49, 0x0000 }, +	{ 50, 0x0000 }, +	{ 51, 0x0079 }, +	{ 52, 0x0079 }, +	{ 53, 0x0079 }, +	{ 54, 0x0079 }, +	{ 55, 0x0000 },  }; -static int wm8900_volatile_register(struct snd_soc_codec *codec, unsigned int reg) +static bool wm8900_volatile_register(struct device *dev, unsigned int reg)  {  	switch (reg) {  	case WM8900_REG_ID: -		return 1; +		return true;  	default: -		return 0; +		return false;  	}  }  static void wm8900_reset(struct snd_soc_codec *codec)  {  	snd_soc_write(codec, WM8900_REG_RESET, 0); - -	memcpy(codec->reg_cache, wm8900_reg_defaults, -	       sizeof(wm8900_reg_defaults));  }  static int wm8900_hp_event(struct snd_soc_dapm_widget *w, @@ -469,10 +493,10 @@ SOC_DAPM_SINGLE("RINPUT2 Switch", WM8900_REG_INCTL, 1, 1, 0),  SOC_DAPM_SINGLE("RINPUT3 Switch", WM8900_REG_INCTL, 0, 1, 0),  }; -static const char *wm9700_lp_mux[] = { "Disabled", "Enabled" }; +static const char *wm8900_lp_mux[] = { "Disabled", "Enabled" };  static const struct soc_enum wm8900_lineout2_lp_mux = -SOC_ENUM_SINGLE(WM8900_REG_LOUTMIXCTL1, 1, 2, wm9700_lp_mux); +SOC_ENUM_SINGLE(WM8900_REG_LOUTMIXCTL1, 1, 2, wm8900_lp_mux);  static const struct snd_kcontrol_new wm8900_lineout2_lp =  SOC_DAPM_ENUM("Route", wm8900_lineout2_lp_mux); @@ -1119,13 +1143,16 @@ static int wm8900_suspend(struct snd_soc_codec *codec)  static int wm8900_resume(struct snd_soc_codec *codec)  {  	struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec); -	u16 *cache; -	int i, ret; - -	cache = kmemdup(codec->reg_cache, sizeof(wm8900_reg_defaults), -			GFP_KERNEL); +	int ret;  	wm8900_reset(codec); + +	ret = regcache_sync(wm8900->regmap); +	if (ret != 0) { +		dev_err(codec->dev, "Failed to restore cache: %d\n", ret); +		return ret; +	} +  	wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY);  	/* Restart the FLL? */ @@ -1139,27 +1166,18 @@ static int wm8900_resume(struct snd_soc_codec *codec)  		ret = wm8900_set_fll(codec, 0, fll_in, fll_out);  		if (ret != 0) {  			dev_err(codec->dev, "Failed to restart FLL\n"); -			kfree(cache);  			return ret;  		}  	} -	if (cache) { -		for (i = 0; i < WM8900_MAXREG; i++) -			snd_soc_write(codec, i, cache[i]); -		kfree(cache); -	} else -		dev_err(codec->dev, "Unable to allocate register cache\n"); -  	return 0;  }  static int wm8900_probe(struct snd_soc_codec *codec)  { -	struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec);  	int ret = 0, reg; -	ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8900->control_type); +	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);  	if (ret != 0) {  		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);  		return ret; @@ -1207,10 +1225,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8900 = {  	.suspend =	wm8900_suspend,  	.resume =	wm8900_resume,  	.set_bias_level = wm8900_set_bias_level, -	.volatile_register = wm8900_volatile_register, -	.reg_cache_size = ARRAY_SIZE(wm8900_reg_defaults), -	.reg_word_size = sizeof(u16), -	.reg_cache_default = wm8900_reg_defaults,  	.controls = wm8900_snd_controls,  	.num_controls = ARRAY_SIZE(wm8900_snd_controls), @@ -1220,30 +1234,44 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8900 = {  	.num_dapm_routes = ARRAY_SIZE(wm8900_dapm_routes),  }; +static const struct regmap_config wm8900_regmap = { +	.reg_bits = 8, +	.val_bits = 16, +	.max_register = WM8900_MAXREG, + +	.reg_defaults = wm8900_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(wm8900_reg_defaults), +	.cache_type = REGCACHE_RBTREE, + +	.volatile_reg = wm8900_volatile_register, +}; +  #if defined(CONFIG_SPI_MASTER)  static int __devinit wm8900_spi_probe(struct spi_device *spi)  {  	struct wm8900_priv *wm8900;  	int ret; -	wm8900 = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL); +	wm8900 = devm_kzalloc(&spi->dev, sizeof(struct wm8900_priv), +			      GFP_KERNEL);  	if (wm8900 == NULL)  		return -ENOMEM; -	wm8900->control_type = SND_SOC_SPI; +	wm8900->regmap = devm_regmap_init_spi(spi, &wm8900_regmap); +	if (IS_ERR(wm8900->regmap)) +		return PTR_ERR(wm8900->regmap); +  	spi_set_drvdata(spi, wm8900);  	ret = snd_soc_register_codec(&spi->dev,  			&soc_codec_dev_wm8900, &wm8900_dai, 1); -	if (ret < 0) -		kfree(wm8900); +  	return ret;  }  static int __devexit wm8900_spi_remove(struct spi_device *spi)  {  	snd_soc_unregister_codec(&spi->dev); -	kfree(spi_get_drvdata(spi));  	return 0;  } @@ -1264,24 +1292,26 @@ static __devinit int wm8900_i2c_probe(struct i2c_client *i2c,  	struct wm8900_priv *wm8900;  	int ret; -	wm8900 = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL); +	wm8900 = devm_kzalloc(&i2c->dev, sizeof(struct wm8900_priv), +			      GFP_KERNEL);  	if (wm8900 == NULL)  		return -ENOMEM; +	wm8900->regmap = devm_regmap_init_i2c(i2c, &wm8900_regmap); +	if (IS_ERR(wm8900->regmap)) +		return PTR_ERR(wm8900->regmap); +  	i2c_set_clientdata(i2c, wm8900); -	wm8900->control_type = SND_SOC_I2C;  	ret =  snd_soc_register_codec(&i2c->dev,  			&soc_codec_dev_wm8900, &wm8900_dai, 1); -	if (ret < 0) -		kfree(wm8900); +  	return ret;  }  static __devexit int wm8900_i2c_remove(struct i2c_client *client)  {  	snd_soc_unregister_codec(&client->dev); -	kfree(i2c_get_clientdata(client));  	return 0;  } diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 73f1c8d7baf..839414f9e2e 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -2241,23 +2241,7 @@ static struct i2c_driver wm8903_i2c_driver = {  	.id_table = wm8903_i2c_id,  }; -static int __init wm8903_modinit(void) -{ -	int ret = 0; -	ret = i2c_add_driver(&wm8903_i2c_driver); -	if (ret != 0) { -		printk(KERN_ERR "Failed to register wm8903 I2C driver: %d\n", -		       ret); -	} -	return ret; -} -module_init(wm8903_modinit); - -static void __exit wm8903_exit(void) -{ -	i2c_del_driver(&wm8903_i2c_driver); -} -module_exit(wm8903_exit); +module_i2c_driver(wm8903_i2c_driver);  MODULE_DESCRIPTION("ASoC WM8903 driver");  MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.cm>"); diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index dc4262eea4b..7c8df52a8d9 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -1185,8 +1185,6 @@ static int wm8904_add_widgets(struct snd_soc_codec *codec)  		snd_soc_dapm_new_controls(dapm, wm8904_dapm_widgets,  					  ARRAY_SIZE(wm8904_dapm_widgets)); -		snd_soc_dapm_add_routes(dapm, core_intercon, -					ARRAY_SIZE(core_intercon));  		snd_soc_dapm_add_routes(dapm, adc_intercon,  					ARRAY_SIZE(adc_intercon));  		snd_soc_dapm_add_routes(dapm, dac_intercon, diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index 481a3d9cfe4..b20aa4e7c3f 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -785,23 +785,7 @@ static struct i2c_driver wm8940_i2c_driver = {  	.id_table = wm8940_i2c_id,  }; -static int __init wm8940_modinit(void) -{ -	int ret = 0; -	ret = i2c_add_driver(&wm8940_i2c_driver); -	if (ret != 0) { -		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_i2c_driver(wm8940_i2c_driver);  MODULE_DESCRIPTION("ASoC WM8940 driver");  MODULE_AUTHOR("Jonathan Cameron"); diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 61fe97433e7..2f1c075755b 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c @@ -1071,23 +1071,7 @@ static struct i2c_driver wm8955_i2c_driver = {  	.id_table = wm8955_i2c_id,  }; -static int __init wm8955_modinit(void) -{ -	int ret = 0; -	ret = i2c_add_driver(&wm8955_i2c_driver); -	if (ret != 0) { -		printk(KERN_ERR "Failed to register WM8955 I2C driver: %d\n", -		       ret); -	} -	return ret; -} -module_init(wm8955_modinit); - -static void __exit wm8955_exit(void) -{ -	i2c_del_driver(&wm8955_i2c_driver); -} -module_exit(wm8955_exit); +module_i2c_driver(wm8955_i2c_driver);  MODULE_DESCRIPTION("ASoC WM8955 driver");  MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c index 1332692ef81..00121ba3659 100644 --- a/sound/soc/codecs/wm8958-dsp2.c +++ b/sound/soc/codecs/wm8958-dsp2.c @@ -946,7 +946,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)  		wm8994->mbc_texts = kmalloc(sizeof(char *)  					    * pdata->num_mbc_cfgs, GFP_KERNEL);  		if (!wm8994->mbc_texts) { -			dev_err(wm8994->codec->dev, +			dev_err(wm8994->hubs.codec->dev,  				"Failed to allocate %d MBC config texts\n",  				pdata->num_mbc_cfgs);  			return; @@ -958,9 +958,10 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)  		wm8994->mbc_enum.max = pdata->num_mbc_cfgs;  		wm8994->mbc_enum.texts = wm8994->mbc_texts; -		ret = snd_soc_add_codec_controls(wm8994->codec, control, 1); +		ret = snd_soc_add_codec_controls(wm8994->hubs.codec, +						 control, 1);  		if (ret != 0) -			dev_err(wm8994->codec->dev, +			dev_err(wm8994->hubs.codec->dev,  				"Failed to add MBC mode controls: %d\n", ret);  	} @@ -974,7 +975,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)  		wm8994->vss_texts = kmalloc(sizeof(char *)  					    * pdata->num_vss_cfgs, GFP_KERNEL);  		if (!wm8994->vss_texts) { -			dev_err(wm8994->codec->dev, +			dev_err(wm8994->hubs.codec->dev,  				"Failed to allocate %d VSS config texts\n",  				pdata->num_vss_cfgs);  			return; @@ -986,9 +987,10 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)  		wm8994->vss_enum.max = pdata->num_vss_cfgs;  		wm8994->vss_enum.texts = wm8994->vss_texts; -		ret = snd_soc_add_codec_controls(wm8994->codec, control, 1); +		ret = snd_soc_add_codec_controls(wm8994->hubs.codec, +						 control, 1);  		if (ret != 0) -			dev_err(wm8994->codec->dev, +			dev_err(wm8994->hubs.codec->dev,  				"Failed to add VSS mode controls: %d\n", ret);  	} @@ -1003,7 +1005,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)  		wm8994->vss_hpf_texts = kmalloc(sizeof(char *)  						* pdata->num_vss_hpf_cfgs, GFP_KERNEL);  		if (!wm8994->vss_hpf_texts) { -			dev_err(wm8994->codec->dev, +			dev_err(wm8994->hubs.codec->dev,  				"Failed to allocate %d VSS HPF config texts\n",  				pdata->num_vss_hpf_cfgs);  			return; @@ -1015,9 +1017,10 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)  		wm8994->vss_hpf_enum.max = pdata->num_vss_hpf_cfgs;  		wm8994->vss_hpf_enum.texts = wm8994->vss_hpf_texts; -		ret = snd_soc_add_codec_controls(wm8994->codec, control, 1); +		ret = snd_soc_add_codec_controls(wm8994->hubs.codec, +						 control, 1);  		if (ret != 0) -			dev_err(wm8994->codec->dev, +			dev_err(wm8994->hubs.codec->dev,  				"Failed to add VSS HPFmode controls: %d\n",  				ret);  	} @@ -1033,7 +1036,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)  		wm8994->enh_eq_texts = kmalloc(sizeof(char *)  						* pdata->num_enh_eq_cfgs, GFP_KERNEL);  		if (!wm8994->enh_eq_texts) { -			dev_err(wm8994->codec->dev, +			dev_err(wm8994->hubs.codec->dev,  				"Failed to allocate %d enhanced EQ config texts\n",  				pdata->num_enh_eq_cfgs);  			return; @@ -1045,9 +1048,10 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)  		wm8994->enh_eq_enum.max = pdata->num_enh_eq_cfgs;  		wm8994->enh_eq_enum.texts = wm8994->enh_eq_texts; -		ret = snd_soc_add_codec_controls(wm8994->codec, control, 1); +		ret = snd_soc_add_codec_controls(wm8994->hubs.codec, +						 control, 1);  		if (ret != 0) -			dev_err(wm8994->codec->dev, +			dev_err(wm8994->hubs.codec->dev,  				"Failed to add enhanced EQ controls: %d\n",  				ret);  	} diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 96518ac8e24..f0f6f660178 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -52,25 +52,72 @@   * 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, +static const struct reg_default wm8960_reg_defaults[] = { +	{  0x0, 0x0097 }, +	{  0x1, 0x0097 }, +	{  0x2, 0x0000 }, +	{  0x3, 0x0000 }, +	{  0x4, 0x0000 }, +	{  0x5, 0x0008 }, +	{  0x6, 0x0000 }, +	{  0x7, 0x000a }, +	{  0x8, 0x01c0 }, +	{  0x9, 0x0000 }, +	{  0xa, 0x00ff }, +	{  0xb, 0x00ff }, + +	{ 0x10, 0x0000 }, +	{ 0x11, 0x007b }, +	{ 0x12, 0x0100 }, +	{ 0x13, 0x0032 }, +	{ 0x14, 0x0000 }, +	{ 0x15, 0x00c3 }, +	{ 0x16, 0x00c3 }, +	{ 0x17, 0x01c0 }, +	{ 0x18, 0x0000 }, +	{ 0x19, 0x0000 }, +	{ 0x1a, 0x0000 }, +	{ 0x1b, 0x0000 }, +	{ 0x1c, 0x0000 }, +	{ 0x1d, 0x0000 }, + +	{ 0x20, 0x0100 }, +	{ 0x21, 0x0100 }, +	{ 0x22, 0x0050 }, + +	{ 0x25, 0x0050 }, +	{ 0x26, 0x0000 }, +	{ 0x27, 0x0000 }, +	{ 0x28, 0x0000 }, +	{ 0x29, 0x0000 }, +	{ 0x2a, 0x0040 }, +	{ 0x2b, 0x0000 }, +	{ 0x2c, 0x0000 }, +	{ 0x2d, 0x0050 }, +	{ 0x2e, 0x0050 }, +	{ 0x2f, 0x0000 }, +	{ 0x30, 0x0002 }, +	{ 0x31, 0x0037 }, + +	{ 0x33, 0x0080 }, +	{ 0x34, 0x0008 }, +	{ 0x35, 0x0031 }, +	{ 0x36, 0x0026 }, +	{ 0x37, 0x00e9 },  }; +static bool wm8960_volatile(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case WM8960_RESET: +		return true; +	default: +		return false; +	} +} +  struct wm8960_priv { -	enum snd_soc_control_type control_type; +	struct regmap *regmap;  	int (*set_bias_level)(struct snd_soc_codec *,  			      enum snd_soc_bias_level level);  	struct snd_soc_dapm_widget *lout1; @@ -510,18 +557,25 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,  	struct snd_soc_codec *codec = dai->codec;  	struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);  	u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3; +	snd_pcm_format_t format = params_format(params);  	int i;  	/* bit size */ -	switch (params_format(params)) { +	switch (format) {  	case SNDRV_PCM_FORMAT_S16_LE: +	case SNDRV_PCM_FORMAT_S16_BE:  		break;  	case SNDRV_PCM_FORMAT_S20_3LE: +	case SNDRV_PCM_FORMAT_S20_3BE:  		iface |= 0x0004;  		break;  	case SNDRV_PCM_FORMAT_S24_LE: +	case SNDRV_PCM_FORMAT_S24_BE:  		iface |= 0x0008;  		break; +	default: +		dev_err(codec->dev, "unsupported format %i\n", format); +		return -EINVAL;  	}  	/* Update filters for the new rate */ @@ -555,6 +609,8 @@ static int wm8960_mute(struct snd_soc_dai *dai, int mute)  static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,  				      enum snd_soc_bias_level level)  { +	struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); +  	switch (level) {  	case SND_SOC_BIAS_ON:  		break; @@ -566,7 +622,7 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,  	case SND_SOC_BIAS_STANDBY:  		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { -			snd_soc_cache_sync(codec); +			regcache_sync(wm8960->regmap);  			/* Enable anti-pop features */  			snd_soc_write(codec, WM8960_APOP1, @@ -667,7 +723,7 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,  			break;  		case SND_SOC_BIAS_OFF: -			snd_soc_cache_sync(codec); +			regcache_sync(wm8960->regmap);  			break;  		default:  			break; @@ -906,16 +962,11 @@ static int wm8960_probe(struct snd_soc_codec *codec)  	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; -		} -  		if (pdata->capless)  			wm8960->set_bias_level = wm8960_set_bias_level_capless;  	} -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8960->control_type); +	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);  	if (ret < 0) {  		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);  		return ret; @@ -963,14 +1014,24 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8960 = {  	.suspend =	wm8960_suspend,  	.resume =	wm8960_resume,  	.set_bias_level = wm8960_set_bias_level, -	.reg_cache_size = ARRAY_SIZE(wm8960_reg), -	.reg_word_size = sizeof(u16), -	.reg_cache_default = wm8960_reg, +}; + +static const struct regmap_config wm8960_regmap = { +	.reg_bits = 7, +	.val_bits = 9, +	.max_register = WM8960_PLL4, + +	.reg_defaults = wm8960_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(wm8960_reg_defaults), +	.cache_type = REGCACHE_RBTREE, + +	.volatile_reg = wm8960_volatile,  };  static __devinit int wm8960_i2c_probe(struct i2c_client *i2c,  				      const struct i2c_device_id *id)  { +	struct wm8960_data *pdata = dev_get_platdata(&i2c->dev);  	struct wm8960_priv *wm8960;  	int ret; @@ -979,8 +1040,21 @@ static __devinit int wm8960_i2c_probe(struct i2c_client *i2c,  	if (wm8960 == NULL)  		return -ENOMEM; +	wm8960->regmap = regmap_init_i2c(i2c, &wm8960_regmap); +	if (IS_ERR(wm8960->regmap)) +		return PTR_ERR(wm8960->regmap); + +	if (pdata && pdata->shared_lrclk) { +		ret = regmap_update_bits(wm8960->regmap, WM8960_ADDCTL2, +					 0x4, 0x4); +		if (ret != 0) { +			dev_err(&i2c->dev, "Failed to enable LRCM: %d\n", +				ret); +			return ret; +		} +	} +  	i2c_set_clientdata(i2c, wm8960); -	wm8960->control_type = SND_SOC_I2C;  	ret = snd_soc_register_codec(&i2c->dev,  			&soc_codec_dev_wm8960, &wm8960_dai, 1); @@ -1010,23 +1084,7 @@ static struct i2c_driver wm8960_i2c_driver = {  	.id_table = wm8960_i2c_id,  }; -static int __init wm8960_modinit(void) -{ -	int ret = 0; -	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_i2c_driver(wm8960_i2c_driver);  MODULE_DESCRIPTION("ASoC WM8960 driver");  MODULE_AUTHOR("Liam Girdwood"); diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index 01edbcc754d..f387670d0d7 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -19,6 +19,7 @@  #include <linux/delay.h>  #include <linux/pm.h>  #include <linux/i2c.h> +#include <linux/regmap.h>  #include <linux/slab.h>  #include <sound/core.h>  #include <sound/pcm.h> @@ -31,283 +32,159 @@  #define WM8961_MAX_REGISTER                     0xFC -static u16 wm8961_reg_defaults[] = { -	0x009F,     /* R0   - Left Input volume */ -	0x009F,     /* R1   - Right Input volume */ -	0x0000,     /* R2   - LOUT1 volume */ -	0x0000,     /* R3   - ROUT1 volume */ -	0x0020,     /* R4   - Clocking1 */ -	0x0008,     /* R5   - ADC & DAC Control 1 */ -	0x0000,     /* R6   - ADC & DAC Control 2 */ -	0x000A,     /* R7   - Audio Interface 0 */ -	0x01F4,     /* R8   - Clocking2 */ -	0x0000,     /* R9   - Audio Interface 1 */ -	0x00FF,     /* R10  - Left DAC volume */ -	0x00FF,     /* R11  - Right DAC volume */ -	0x0000,     /* R12 */ -	0x0000,     /* R13 */ -	0x0040,     /* R14  - Audio Interface 2 */ -	0x0000,     /* R15  - Software Reset */ -	0x0000,     /* R16 */ -	0x007B,     /* R17  - ALC1 */ -	0x0000,     /* R18  - ALC2 */ -	0x0032,     /* R19  - ALC3 */ -	0x0000,     /* R20  - Noise Gate */ -	0x00C0,     /* R21  - Left ADC volume */ -	0x00C0,     /* R22  - Right ADC volume */ -	0x0120,     /* R23  - Additional control(1) */ -	0x0000,     /* R24  - Additional control(2) */ -	0x0000,     /* R25  - Pwr Mgmt (1) */ -	0x0000,     /* R26  - Pwr Mgmt (2) */ -	0x0000,     /* R27  - Additional Control (3) */ -	0x0000,     /* R28  - Anti-pop */ -	0x0000,     /* R29 */ -	0x005F,     /* R30  - Clocking 3 */ -	0x0000,     /* R31 */ -	0x0000,     /* R32  - ADCL signal path */ -	0x0000,     /* R33  - ADCR signal path */ -	0x0000,     /* R34 */ -	0x0000,     /* R35 */ -	0x0000,     /* R36 */ -	0x0000,     /* R37 */ -	0x0000,     /* R38 */ -	0x0000,     /* R39 */ -	0x0000,     /* R40  - LOUT2 volume */ -	0x0000,     /* R41  - ROUT2 volume */ -	0x0000,     /* R42 */ -	0x0000,     /* R43 */ -	0x0000,     /* R44 */ -	0x0000,     /* R45 */ -	0x0000,     /* R46 */ -	0x0000,     /* R47  - Pwr Mgmt (3) */ -	0x0023,     /* R48  - Additional Control (4) */ -	0x0000,     /* R49  - Class D Control 1 */ -	0x0000,     /* R50 */ -	0x0003,     /* R51  - Class D Control 2 */ -	0x0000,     /* R52 */ -	0x0000,     /* R53 */ -	0x0000,     /* R54 */ -	0x0000,     /* R55 */ -	0x0106,     /* R56  - Clocking 4 */ -	0x0000,     /* R57  - DSP Sidetone 0 */ -	0x0000,     /* R58  - DSP Sidetone 1 */ -	0x0000,     /* R59 */ -	0x0000,     /* R60  - DC Servo 0 */ -	0x0000,     /* R61  - DC Servo 1 */ -	0x0000,     /* R62 */ -	0x015E,     /* R63  - DC Servo 3 */ -	0x0010,     /* R64 */ -	0x0010,     /* R65  - DC Servo 5 */ -	0x0000,     /* R66 */ -	0x0001,     /* R67 */ -	0x0003,     /* R68  - Analogue PGA Bias */ -	0x0000,     /* R69  - Analogue HP 0 */ -	0x0060,     /* R70 */ -	0x01FB,     /* R71  - Analogue HP 2 */ -	0x0000,     /* R72  - Charge Pump 1 */ -	0x0065,     /* R73 */ -	0x005F,     /* R74 */ -	0x0059,     /* R75 */ -	0x006B,     /* R76 */ -	0x0038,     /* R77 */ -	0x000C,     /* R78 */ -	0x000A,     /* R79 */ -	0x006B,     /* R80 */ -	0x0000,     /* R81 */ -	0x0000,     /* R82  - Charge Pump B */ -	0x0087,     /* R83 */ -	0x0000,     /* R84 */ -	0x005C,     /* R85 */ -	0x0000,     /* R86 */ -	0x0000,     /* R87  - Write Sequencer 1 */ -	0x0000,     /* R88  - Write Sequencer 2 */ -	0x0000,     /* R89  - Write Sequencer 3 */ -	0x0000,     /* R90  - Write Sequencer 4 */ -	0x0000,     /* R91  - Write Sequencer 5 */ -	0x0000,     /* R92  - Write Sequencer 6 */ -	0x0000,     /* R93  - Write Sequencer 7 */ -	0x0000,     /* R94 */ -	0x0000,     /* R95 */ -	0x0000,     /* R96 */ -	0x0000,     /* R97 */ -	0x0000,     /* R98 */ -	0x0000,     /* R99 */ -	0x0000,     /* R100 */ -	0x0000,     /* R101 */ -	0x0000,     /* R102 */ -	0x0000,     /* R103 */ -	0x0000,     /* R104 */ -	0x0000,     /* R105 */ -	0x0000,     /* R106 */ -	0x0000,     /* R107 */ -	0x0000,     /* R108 */ -	0x0000,     /* R109 */ -	0x0000,     /* R110 */ -	0x0000,     /* R111 */ -	0x0000,     /* R112 */ -	0x0000,     /* R113 */ -	0x0000,     /* R114 */ -	0x0000,     /* R115 */ -	0x0000,     /* R116 */ -	0x0000,     /* R117 */ -	0x0000,     /* R118 */ -	0x0000,     /* R119 */ -	0x0000,     /* R120 */ -	0x0000,     /* R121 */ -	0x0000,     /* R122 */ -	0x0000,     /* R123 */ -	0x0000,     /* R124 */ -	0x0000,     /* R125 */ -	0x0000,     /* R126 */ -	0x0000,     /* R127 */ -	0x0000,     /* R128 */ -	0x0000,     /* R129 */ -	0x0000,     /* R130 */ -	0x0000,     /* R131 */ -	0x0000,     /* R132 */ -	0x0000,     /* R133 */ -	0x0000,     /* R134 */ -	0x0000,     /* R135 */ -	0x0000,     /* R136 */ -	0x0000,     /* R137 */ -	0x0000,     /* R138 */ -	0x0000,     /* R139 */ -	0x0000,     /* R140 */ -	0x0000,     /* R141 */ -	0x0000,     /* R142 */ -	0x0000,     /* R143 */ -	0x0000,     /* R144 */ -	0x0000,     /* R145 */ -	0x0000,     /* R146 */ -	0x0000,     /* R147 */ -	0x0000,     /* R148 */ -	0x0000,     /* R149 */ -	0x0000,     /* R150 */ -	0x0000,     /* R151 */ -	0x0000,     /* R152 */ -	0x0000,     /* R153 */ -	0x0000,     /* R154 */ -	0x0000,     /* R155 */ -	0x0000,     /* R156 */ -	0x0000,     /* R157 */ -	0x0000,     /* R158 */ -	0x0000,     /* R159 */ -	0x0000,     /* R160 */ -	0x0000,     /* R161 */ -	0x0000,     /* R162 */ -	0x0000,     /* R163 */ -	0x0000,     /* R164 */ -	0x0000,     /* R165 */ -	0x0000,     /* R166 */ -	0x0000,     /* R167 */ -	0x0000,     /* R168 */ -	0x0000,     /* R169 */ -	0x0000,     /* R170 */ -	0x0000,     /* R171 */ -	0x0000,     /* R172 */ -	0x0000,     /* R173 */ -	0x0000,     /* R174 */ -	0x0000,     /* R175 */ -	0x0000,     /* R176 */ -	0x0000,     /* R177 */ -	0x0000,     /* R178 */ -	0x0000,     /* R179 */ -	0x0000,     /* R180 */ -	0x0000,     /* R181 */ -	0x0000,     /* R182 */ -	0x0000,     /* R183 */ -	0x0000,     /* R184 */ -	0x0000,     /* R185 */ -	0x0000,     /* R186 */ -	0x0000,     /* R187 */ -	0x0000,     /* R188 */ -	0x0000,     /* R189 */ -	0x0000,     /* R190 */ -	0x0000,     /* R191 */ -	0x0000,     /* R192 */ -	0x0000,     /* R193 */ -	0x0000,     /* R194 */ -	0x0000,     /* R195 */ -	0x0030,     /* R196 */ -	0x0006,     /* R197 */ -	0x0000,     /* R198 */ -	0x0060,     /* R199 */ -	0x0000,     /* R200 */ -	0x003F,     /* R201 */ -	0x0000,     /* R202 */ -	0x0000,     /* R203 */ -	0x0000,     /* R204 */ -	0x0001,     /* R205 */ -	0x0000,     /* R206 */ -	0x0181,     /* R207 */ -	0x0005,     /* R208 */ -	0x0008,     /* R209 */ -	0x0008,     /* R210 */ -	0x0000,     /* R211 */ -	0x013B,     /* R212 */ -	0x0000,     /* R213 */ -	0x0000,     /* R214 */ -	0x0000,     /* R215 */ -	0x0000,     /* R216 */ -	0x0070,     /* R217 */ -	0x0000,     /* R218 */ -	0x0000,     /* R219 */ -	0x0000,     /* R220 */ -	0x0000,     /* R221 */ -	0x0000,     /* R222 */ -	0x0003,     /* R223 */ -	0x0000,     /* R224 */ -	0x0000,     /* R225 */ -	0x0001,     /* R226 */ -	0x0008,     /* R227 */ -	0x0000,     /* R228 */ -	0x0000,     /* R229 */ -	0x0000,     /* R230 */ -	0x0000,     /* R231 */ -	0x0004,     /* R232 */ -	0x0000,     /* R233 */ -	0x0000,     /* R234 */ -	0x0000,     /* R235 */ -	0x0000,     /* R236 */ -	0x0000,     /* R237 */ -	0x0080,     /* R238 */ -	0x0000,     /* R239 */ -	0x0000,     /* R240 */ -	0x0000,     /* R241 */ -	0x0000,     /* R242 */ -	0x0000,     /* R243 */ -	0x0000,     /* R244 */ -	0x0052,     /* R245 */ -	0x0110,     /* R246 */ -	0x0040,     /* R247 */ -	0x0000,     /* R248 */ -	0x0030,     /* R249 */ -	0x0000,     /* R250 */ -	0x0000,     /* R251 */ -	0x0001,     /* R252 - General test 1 */ +static const struct reg_default wm8961_reg_defaults[] = { +	{  0, 0x009F },     /* R0   - Left Input volume */ +	{  1, 0x009F },     /* R1   - Right Input volume */ +	{  2, 0x0000 },     /* R2   - LOUT1 volume */ +	{  3, 0x0000 },     /* R3   - ROUT1 volume */ +	{  4, 0x0020 },     /* R4   - Clocking1 */ +	{  5, 0x0008 },     /* R5   - ADC & DAC Control 1 */ +	{  6, 0x0000 },     /* R6   - ADC & DAC Control 2 */ +	{  7, 0x000A },     /* R7   - Audio Interface 0 */ +	{  8, 0x01F4 },     /* R8   - Clocking2 */ +	{  9, 0x0000 },     /* R9   - Audio Interface 1 */ +	{ 10, 0x00FF },     /* R10  - Left DAC volume */ +	{ 11, 0x00FF },     /* R11  - Right DAC volume */ + +	{ 14, 0x0040 },     /* R14  - Audio Interface 2 */ + +	{ 17, 0x007B },     /* R17  - ALC1 */ +	{ 18, 0x0000 },     /* R18  - ALC2 */ +	{ 19, 0x0032 },     /* R19  - ALC3 */ +	{ 20, 0x0000 },     /* R20  - Noise Gate */ +	{ 21, 0x00C0 },     /* R21  - Left ADC volume */ +	{ 22, 0x00C0 },     /* R22  - Right ADC volume */ +	{ 23, 0x0120 },     /* R23  - Additional control(1) */ +	{ 24, 0x0000 },     /* R24  - Additional control(2) */ +	{ 25, 0x0000 },     /* R25  - Pwr Mgmt (1) */ +	{ 26, 0x0000 },     /* R26  - Pwr Mgmt (2) */ +	{ 27, 0x0000 },     /* R27  - Additional Control (3) */ +	{ 28, 0x0000 },     /* R28  - Anti-pop */ + +	{ 30, 0x005F },     /* R30  - Clocking 3 */ + +	{ 32, 0x0000 },     /* R32  - ADCL signal path */ +	{ 33, 0x0000 },     /* R33  - ADCR signal path */ + +	{ 40, 0x0000 },     /* R40  - LOUT2 volume */ +	{ 41, 0x0000 },     /* R41  - ROUT2 volume */ + +	{ 47, 0x0000 },     /* R47  - Pwr Mgmt (3) */ +	{ 48, 0x0023 },     /* R48  - Additional Control (4) */ +	{ 49, 0x0000 },     /* R49  - Class D Control 1 */ + +	{ 51, 0x0003 },     /* R51  - Class D Control 2 */ + +	{ 56, 0x0106 },     /* R56  - Clocking 4 */ +	{ 57, 0x0000 },     /* R57  - DSP Sidetone 0 */ +	{ 58, 0x0000 },     /* R58  - DSP Sidetone 1 */ + +	{ 60, 0x0000 },     /* R60  - DC Servo 0 */ +	{ 61, 0x0000 },     /* R61  - DC Servo 1 */ + +	{ 63, 0x015E },     /* R63  - DC Servo 3 */ + +	{ 65, 0x0010 },     /* R65  - DC Servo 5 */ + +	{ 68, 0x0003 },     /* R68  - Analogue PGA Bias */ +	{ 69, 0x0000 },     /* R69  - Analogue HP 0 */ + +	{ 71, 0x01FB },     /* R71  - Analogue HP 2 */ +	{ 72, 0x0000 },     /* R72  - Charge Pump 1 */ + +	{ 82, 0x0000 },     /* R82  - Charge Pump B */ + +	{ 87, 0x0000 },     /* R87  - Write Sequencer 1 */ +	{ 88, 0x0000 },     /* R88  - Write Sequencer 2 */ +	{ 89, 0x0000 },     /* R89  - Write Sequencer 3 */ +	{ 90, 0x0000 },     /* R90  - Write Sequencer 4 */ +	{ 91, 0x0000 },     /* R91  - Write Sequencer 5 */ +	{ 92, 0x0000 },     /* R92  - Write Sequencer 6 */ +	{ 93, 0x0000 },     /* R93  - Write Sequencer 7 */ + +	{ 252, 0x0001 },     /* R252 - General test 1 */  };  struct wm8961_priv { -	enum snd_soc_control_type control_type; +	struct regmap *regmap;  	int sysclk;  }; -static int wm8961_volatile_register(struct snd_soc_codec *codec, unsigned int reg) +static bool wm8961_volatile(struct device *dev, unsigned int reg)  {  	switch (reg) {  	case WM8961_SOFTWARE_RESET:  	case WM8961_WRITE_SEQUENCER_7:  	case WM8961_DC_SERVO_1: -		return 1; +		return true;  	default: -		return 0; +		return false;  	}  } -static int wm8961_reset(struct snd_soc_codec *codec) +static bool wm8961_readable(struct device *dev, unsigned int reg)  { -	return snd_soc_write(codec, WM8961_SOFTWARE_RESET, 0); +	switch (reg) { +	case WM8961_LEFT_INPUT_VOLUME: +	case WM8961_RIGHT_INPUT_VOLUME: +	case WM8961_LOUT1_VOLUME: +	case WM8961_ROUT1_VOLUME: +	case WM8961_CLOCKING1: +	case WM8961_ADC_DAC_CONTROL_1: +	case WM8961_ADC_DAC_CONTROL_2: +	case WM8961_AUDIO_INTERFACE_0: +	case WM8961_CLOCKING2: +	case WM8961_AUDIO_INTERFACE_1: +	case WM8961_LEFT_DAC_VOLUME: +	case WM8961_RIGHT_DAC_VOLUME: +	case WM8961_AUDIO_INTERFACE_2: +	case WM8961_SOFTWARE_RESET: +	case WM8961_ALC1: +	case WM8961_ALC2: +	case WM8961_ALC3: +	case WM8961_NOISE_GATE: +	case WM8961_LEFT_ADC_VOLUME: +	case WM8961_RIGHT_ADC_VOLUME: +	case WM8961_ADDITIONAL_CONTROL_1: +	case WM8961_ADDITIONAL_CONTROL_2: +	case WM8961_PWR_MGMT_1: +	case WM8961_PWR_MGMT_2: +	case WM8961_ADDITIONAL_CONTROL_3: +	case WM8961_ANTI_POP: +	case WM8961_CLOCKING_3: +	case WM8961_ADCL_SIGNAL_PATH: +	case WM8961_ADCR_SIGNAL_PATH: +	case WM8961_LOUT2_VOLUME: +	case WM8961_ROUT2_VOLUME: +	case WM8961_PWR_MGMT_3: +	case WM8961_ADDITIONAL_CONTROL_4: +	case WM8961_CLASS_D_CONTROL_1: +	case WM8961_CLASS_D_CONTROL_2: +	case WM8961_CLOCKING_4: +	case WM8961_DSP_SIDETONE_0: +	case WM8961_DSP_SIDETONE_1: +	case WM8961_DC_SERVO_0: +	case WM8961_DC_SERVO_1: +	case WM8961_DC_SERVO_3: +	case WM8961_DC_SERVO_5: +	case WM8961_ANALOGUE_PGA_BIAS: +	case WM8961_ANALOGUE_HP_0: +	case WM8961_ANALOGUE_HP_2: +	case WM8961_CHARGE_PUMP_1: +	case WM8961_CHARGE_PUMP_B: +	case WM8961_WRITE_SEQUENCER_1: +	case WM8961_WRITE_SEQUENCER_2: +	case WM8961_WRITE_SEQUENCER_3: +	case WM8961_WRITE_SEQUENCER_4: +	case WM8961_WRITE_SEQUENCER_5: +	case WM8961_WRITE_SEQUENCER_6: +	case WM8961_WRITE_SEQUENCER_7: +	case WM8961_GENERAL_TEST_1: +		return true; +	default: +		return false; +	}  }  /* @@ -962,33 +839,12 @@ static int wm8961_probe(struct snd_soc_codec *codec)  	int ret = 0;  	u16 reg; -	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); +	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);  	if (ret != 0) {  		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);  		return ret;  	} -	reg = snd_soc_read(codec, WM8961_SOFTWARE_RESET); -	if (reg != 0x1801) { -		dev_err(codec->dev, "Device is not a WM8961: ID=0x%x\n", reg); -		return -EINVAL; -	} - -	/* This isn't volatile - readback doesn't correspond to write */ -	codec->cache_bypass = 1; -	reg = snd_soc_read(codec, WM8961_RIGHT_INPUT_VOLUME); -	codec->cache_bypass = 0; -	dev_info(codec->dev, "WM8961 family %d revision %c\n", -		 (reg & WM8961_DEVICE_ID_MASK) >> WM8961_DEVICE_ID_SHIFT, -		 ((reg & WM8961_CHIP_REV_MASK) >> WM8961_CHIP_REV_SHIFT) -		 + 'A'); - -	ret = wm8961_reset(codec); -	if (ret < 0) { -		dev_err(codec->dev, "Failed to issue reset\n"); -		return ret; -	} -  	/* Enable class W */  	reg = snd_soc_read(codec, WM8961_CHARGE_PUMP_B);  	reg |= WM8961_CP_DYN_PWR_MASK; @@ -1066,16 +922,26 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8961 = {  	.suspend =	wm8961_suspend,  	.resume =	wm8961_resume,  	.set_bias_level = wm8961_set_bias_level, -	.reg_cache_size = ARRAY_SIZE(wm8961_reg_defaults), -	.reg_word_size = sizeof(u16), -	.reg_cache_default = wm8961_reg_defaults, -	.volatile_register = wm8961_volatile_register, +}; + +static const struct regmap_config wm8961_regmap = { +	.reg_bits = 8, +	.val_bits = 16, +	.max_register = WM8961_MAX_REGISTER, + +	.reg_defaults = wm8961_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(wm8961_reg_defaults), +	.cache_type = REGCACHE_RBTREE, + +	.volatile_reg = wm8961_volatile, +	.readable_reg = wm8961_readable,  };  static __devinit int wm8961_i2c_probe(struct i2c_client *i2c,  				      const struct i2c_device_id *id)  {  	struct wm8961_priv *wm8961; +	unsigned int val;  	int ret;  	wm8961 = devm_kzalloc(&i2c->dev, sizeof(struct wm8961_priv), @@ -1083,6 +949,42 @@ static __devinit int wm8961_i2c_probe(struct i2c_client *i2c,  	if (wm8961 == NULL)  		return -ENOMEM; +	wm8961->regmap = devm_regmap_init_i2c(i2c, &wm8961_regmap); +	if (IS_ERR(wm8961->regmap)) +		return PTR_ERR(wm8961->regmap); + +	ret = regmap_read(wm8961->regmap, WM8961_SOFTWARE_RESET, &val); +	if (ret != 0) { +		dev_err(&i2c->dev, "Failed to read chip ID: %d\n", ret); +		return ret; +	} + +	if (val != 0x1801) { +		dev_err(&i2c->dev, "Device is not a WM8961: ID=0x%x\n", val); +		return -EINVAL; +	} + +	/* This isn't volatile - readback doesn't correspond to write */ +	regcache_cache_bypass(wm8961->regmap, true); +	ret = regmap_read(wm8961->regmap, WM8961_RIGHT_INPUT_VOLUME, &val); +	regcache_cache_bypass(wm8961->regmap, false); + +	if (ret != 0) { +		dev_err(&i2c->dev, "Failed to read chip revision: %d\n", ret); +		return ret; +	} + +	dev_info(&i2c->dev, "WM8961 family %d revision %c\n", +		 (val & WM8961_DEVICE_ID_MASK) >> WM8961_DEVICE_ID_SHIFT, +		 ((val & WM8961_CHIP_REV_MASK) >> WM8961_CHIP_REV_SHIFT) +		 + 'A'); + +	ret = regmap_write(wm8961->regmap, WM8961_SOFTWARE_RESET, 0x1801); +	if (ret != 0) { +		dev_err(&i2c->dev, "Failed to issue reset: %d\n", ret); +		return ret; +	} +  	i2c_set_clientdata(i2c, wm8961);  	ret = snd_soc_register_codec(&i2c->dev, @@ -1114,23 +1016,7 @@ static struct i2c_driver wm8961_i2c_driver = {  	.id_table = wm8961_i2c_id,  }; -static int __init wm8961_modinit(void) -{ -	int ret = 0; -	ret = i2c_add_driver(&wm8961_i2c_driver); -	if (ret != 0) { -		printk(KERN_ERR "Failed to register wm8961 I2C driver: %d\n", -		       ret); -	} -	return ret; -} -module_init(wm8961_modinit); - -static void __exit wm8961_exit(void) -{ -	i2c_del_driver(&wm8961_i2c_driver); -} -module_exit(wm8961_exit); +module_i2c_driver(wm8961_i2c_driver);  MODULE_DESCRIPTION("ASoC WM8961 driver");  MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index eef783f6b6d..5ce64775844 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -721,23 +721,7 @@ static struct i2c_driver wm8971_i2c_driver = {  	.id_table = wm8971_i2c_id,  }; -static int __init wm8971_modinit(void) -{ -	int ret = 0; -	ret = i2c_add_driver(&wm8971_i2c_driver); -	if (ret != 0) { -		printk(KERN_ERR "Failed to register WM8971 I2C driver: %d\n", -		       ret); -	} -	return ret; -} -module_init(wm8971_modinit); - -static void __exit wm8971_exit(void) -{ -	i2c_del_driver(&wm8971_i2c_driver); -} -module_exit(wm8971_exit); +module_i2c_driver(wm8971_i2c_driver);  MODULE_DESCRIPTION("ASoC WM8971 driver");  MODULE_AUTHOR("Lab126"); diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index d93c03f820c..9a39511af52 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -659,23 +659,7 @@ static struct i2c_driver wm8974_i2c_driver = {  	.id_table = wm8974_i2c_id,  }; -static int __init wm8974_modinit(void) -{ -	int ret = 0; -	ret = i2c_add_driver(&wm8974_i2c_driver); -	if (ret != 0) { -		printk(KERN_ERR "Failed to register wm8974 I2C driver: %d\n", -		       ret); -	} -	return ret; -} -module_init(wm8974_modinit); - -static void __exit wm8974_exit(void) -{ -	i2c_del_driver(&wm8974_i2c_driver); -} -module_exit(wm8974_exit); +module_i2c_driver(wm8974_i2c_driver);  MODULE_DESCRIPTION("ASoC WM8974 driver");  MODULE_AUTHOR("Liam Girdwood"); diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index a5be3adecf7..5421fd9fbcb 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c @@ -1105,23 +1105,7 @@ static struct i2c_driver wm8978_i2c_driver = {  	.id_table = wm8978_i2c_id,  }; -static int __init wm8978_modinit(void) -{ -	int ret = 0; -	ret = i2c_add_driver(&wm8978_i2c_driver); -	if (ret != 0) { -		printk(KERN_ERR "Failed to register WM8978 I2C driver: %d\n", -		       ret); -	} -	return ret; -} -module_init(wm8978_modinit); - -static void __exit wm8978_exit(void) -{ -	i2c_del_driver(&wm8978_i2c_driver); -} -module_exit(wm8978_exit); +module_i2c_driver(wm8978_i2c_driver);  MODULE_DESCRIPTION("ASoC WM8978 codec driver");  MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c index 367388fdc48..d8879f262d2 100644 --- a/sound/soc/codecs/wm8983.c +++ b/sound/soc/codecs/wm8983.c @@ -16,6 +16,7 @@  #include <linux/delay.h>  #include <linux/pm.h>  #include <linux/i2c.h> +#include <linux/regmap.h>  #include <linux/spi/spi.h>  #include <linux/slab.h>  #include <sound/core.h> @@ -27,61 +28,60 @@  #include "wm8983.h" -static const u16 wm8983_reg_defs[WM8983_MAX_REGISTER + 1] = { -	[0x00] = 0x0000,     /* R0  - Software Reset */ -	[0x01] = 0x0000,     /* R1  - Power management 1 */ -	[0x02] = 0x0000,     /* R2  - Power management 2 */ -	[0x03] = 0x0000,     /* R3  - Power management 3 */ -	[0x04] = 0x0050,     /* R4  - Audio Interface */ -	[0x05] = 0x0000,     /* R5  - Companding control */ -	[0x06] = 0x0140,     /* R6  - Clock Gen control */ -	[0x07] = 0x0000,     /* R7  - Additional control */ -	[0x08] = 0x0000,     /* R8  - GPIO Control */ -	[0x09] = 0x0000,     /* R9  - Jack Detect Control 1 */ -	[0x0A] = 0x0000,     /* R10 - DAC Control */ -	[0x0B] = 0x00FF,     /* R11 - Left DAC digital Vol */ -	[0x0C] = 0x00FF,     /* R12 - Right DAC digital vol */ -	[0x0D] = 0x0000,     /* R13 - Jack Detect Control 2 */ -	[0x0E] = 0x0100,     /* R14 - ADC Control */ -	[0x0F] = 0x00FF,     /* R15 - Left ADC Digital Vol */ -	[0x10] = 0x00FF,     /* R16 - Right ADC Digital Vol */ -	[0x12] = 0x012C,     /* R18 - EQ1 - low shelf */ -	[0x13] = 0x002C,     /* R19 - EQ2 - peak 1 */ -	[0x14] = 0x002C,     /* R20 - EQ3 - peak 2 */ -	[0x15] = 0x002C,     /* R21 - EQ4 - peak 3 */ -	[0x16] = 0x002C,     /* R22 - EQ5 - high shelf */ -	[0x18] = 0x0032,     /* R24 - DAC Limiter 1 */ -	[0x19] = 0x0000,     /* R25 - DAC Limiter 2 */ -	[0x1B] = 0x0000,     /* R27 - Notch Filter 1 */ -	[0x1C] = 0x0000,     /* R28 - Notch Filter 2 */ -	[0x1D] = 0x0000,     /* R29 - Notch Filter 3 */ -	[0x1E] = 0x0000,     /* R30 - Notch Filter 4 */ -	[0x20] = 0x0038,     /* R32 - ALC control 1 */ -	[0x21] = 0x000B,     /* R33 - ALC control 2 */ -	[0x22] = 0x0032,     /* R34 - ALC control 3 */ -	[0x23] = 0x0000,     /* R35 - Noise Gate */ -	[0x24] = 0x0008,     /* R36 - PLL N */ -	[0x25] = 0x000C,     /* R37 - PLL K 1 */ -	[0x26] = 0x0093,     /* R38 - PLL K 2 */ -	[0x27] = 0x00E9,     /* R39 - PLL K 3 */ -	[0x29] = 0x0000,     /* R41 - 3D control */ -	[0x2A] = 0x0000,     /* R42 - OUT4 to ADC */ -	[0x2B] = 0x0000,     /* R43 - Beep control */ -	[0x2C] = 0x0033,     /* R44 - Input ctrl */ -	[0x2D] = 0x0010,     /* R45 - Left INP PGA gain ctrl */ -	[0x2E] = 0x0010,     /* R46 - Right INP PGA gain ctrl */ -	[0x2F] = 0x0100,     /* R47 - Left ADC BOOST ctrl */ -	[0x30] = 0x0100,     /* R48 - Right ADC BOOST ctrl */ -	[0x31] = 0x0002,     /* R49 - Output ctrl */ -	[0x32] = 0x0001,     /* R50 - Left mixer ctrl */ -	[0x33] = 0x0001,     /* R51 - Right mixer ctrl */ -	[0x34] = 0x0039,     /* R52 - LOUT1 (HP) volume ctrl */ -	[0x35] = 0x0039,     /* R53 - ROUT1 (HP) volume ctrl */ -	[0x36] = 0x0039,     /* R54 - LOUT2 (SPK) volume ctrl */ -	[0x37] = 0x0039,     /* R55 - ROUT2 (SPK) volume ctrl */ -	[0x38] = 0x0001,     /* R56 - OUT3 mixer ctrl */ -	[0x39] = 0x0001,     /* R57 - OUT4 (MONO) mix ctrl */ -	[0x3D] = 0x0000      /* R61 - BIAS CTRL */ +static const struct reg_default wm8983_defaults[] = { +	{ 0x01, 0x0000 },     /* R1  - Power management 1 */ +	{ 0x02, 0x0000 },     /* R2  - Power management 2 */ +	{ 0x03, 0x0000 },     /* R3  - Power management 3 */ +	{ 0x04, 0x0050 },     /* R4  - Audio Interface */ +	{ 0x05, 0x0000 },     /* R5  - Companding control */ +	{ 0x06, 0x0140 },     /* R6  - Clock Gen control */ +	{ 0x07, 0x0000 },     /* R7  - Additional control */ +	{ 0x08, 0x0000 },     /* R8  - GPIO Control */ +	{ 0x09, 0x0000 },     /* R9  - Jack Detect Control 1 */ +	{ 0x0A, 0x0000 },     /* R10 - DAC Control */ +	{ 0x0B, 0x00FF },     /* R11 - Left DAC digital Vol */ +	{ 0x0C, 0x00FF },     /* R12 - Right DAC digital vol */ +	{ 0x0D, 0x0000 },     /* R13 - Jack Detect Control 2 */ +	{ 0x0E, 0x0100 },     /* R14 - ADC Control */ +	{ 0x0F, 0x00FF },     /* R15 - Left ADC Digital Vol */ +	{ 0x10, 0x00FF },     /* R16 - Right ADC Digital Vol */ +	{ 0x12, 0x012C },     /* R18 - EQ1 - low shelf */ +	{ 0x13, 0x002C },     /* R19 - EQ2 - peak 1 */ +	{ 0x14, 0x002C },     /* R20 - EQ3 - peak 2 */ +	{ 0x15, 0x002C },     /* R21 - EQ4 - peak 3 */ +	{ 0x16, 0x002C },     /* R22 - EQ5 - high shelf */ +	{ 0x18, 0x0032 },     /* R24 - DAC Limiter 1 */ +	{ 0x19, 0x0000 },     /* R25 - DAC Limiter 2 */ +	{ 0x1B, 0x0000 },     /* R27 - Notch Filter 1 */ +	{ 0x1C, 0x0000 },     /* R28 - Notch Filter 2 */ +	{ 0x1D, 0x0000 },     /* R29 - Notch Filter 3 */ +	{ 0x1E, 0x0000 },     /* R30 - Notch Filter 4 */ +	{ 0x20, 0x0038 },     /* R32 - ALC control 1 */ +	{ 0x21, 0x000B },     /* R33 - ALC control 2 */ +	{ 0x22, 0x0032 },     /* R34 - ALC control 3 */ +	{ 0x23, 0x0000 },     /* R35 - Noise Gate */ +	{ 0x24, 0x0008 },     /* R36 - PLL N */ +	{ 0x25, 0x000C },     /* R37 - PLL K 1 */ +	{ 0x26, 0x0093 },     /* R38 - PLL K 2 */ +	{ 0x27, 0x00E9 },     /* R39 - PLL K 3 */ +	{ 0x29, 0x0000 },     /* R41 - 3D control */ +	{ 0x2A, 0x0000 },     /* R42 - OUT4 to ADC */ +	{ 0x2B, 0x0000 },     /* R43 - Beep control */ +	{ 0x2C, 0x0033 },     /* R44 - Input ctrl */ +	{ 0x2D, 0x0010 },     /* R45 - Left INP PGA gain ctrl */ +	{ 0x2E, 0x0010 },     /* R46 - Right INP PGA gain ctrl */ +	{ 0x2F, 0x0100 },     /* R47 - Left ADC BOOST ctrl */ +	{ 0x30, 0x0100 },     /* R48 - Right ADC BOOST ctrl */ +	{ 0x31, 0x0002 },     /* R49 - Output ctrl */ +	{ 0x32, 0x0001 },     /* R50 - Left mixer ctrl */ +	{ 0x33, 0x0001 },     /* R51 - Right mixer ctrl */ +	{ 0x34, 0x0039 },     /* R52 - LOUT1 (HP) volume ctrl */ +	{ 0x35, 0x0039 },     /* R53 - ROUT1 (HP) volume ctrl */ +	{ 0x36, 0x0039 },     /* R54 - LOUT2 (SPK) volume ctrl */ +	{ 0x37, 0x0039 },     /* R55 - ROUT2 (SPK) volume ctrl */ +	{ 0x38, 0x0001 },     /* R56 - OUT3 mixer ctrl */ +	{ 0x39, 0x0001 },     /* R57 - OUT4 (MONO) mix ctrl */ +	{ 0x3D, 0x0000 },      /* R61 - BIAS CTRL */  };  static const struct wm8983_reg_access { @@ -159,7 +159,7 @@ static const int vol_update_regs[] = {  };  struct wm8983_priv { -	enum snd_soc_control_type control_type; +	struct regmap *regmap;  	u32 sysclk;  	u32 bclk;  }; @@ -610,7 +610,7 @@ static int eqmode_put(struct snd_kcontrol *kcontrol,  	return 0;  } -static int wm8983_readable(struct snd_soc_codec *codec, unsigned int reg) +static bool wm8983_readable(struct device *dev, unsigned int reg)  {  	if (reg > WM8983_MAX_REGISTER)  		return 0; @@ -905,6 +905,7 @@ static int wm8983_set_sysclk(struct snd_soc_dai *dai,  static int wm8983_set_bias_level(struct snd_soc_codec *codec,  				 enum snd_soc_bias_level level)  { +	struct wm8983_priv *wm8983 = snd_soc_codec_get_drvdata(codec);  	int ret;  	switch (level) { @@ -917,7 +918,7 @@ static int wm8983_set_bias_level(struct snd_soc_codec *codec,  		break;  	case SND_SOC_BIAS_STANDBY:  		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { -			ret = snd_soc_cache_sync(codec); +			ret = regcache_sync(wm8983->regmap);  			if (ret < 0) {  				dev_err(codec->dev, "Failed to sync cache: %d\n", ret);  				return ret; @@ -994,10 +995,9 @@ static int wm8983_remove(struct snd_soc_codec *codec)  static int wm8983_probe(struct snd_soc_codec *codec)  {  	int ret; -	struct wm8983_priv *wm8983 = snd_soc_codec_get_drvdata(codec);  	int i; -	ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8983->control_type); +	ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);  	if (ret < 0) {  		dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);  		return ret; @@ -1067,16 +1067,23 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8983 = {  	.suspend = wm8983_suspend,  	.resume = wm8983_resume,  	.set_bias_level = wm8983_set_bias_level, -	.reg_cache_size = ARRAY_SIZE(wm8983_reg_defs), -	.reg_word_size = sizeof(u16), -	.reg_cache_default = wm8983_reg_defs,  	.controls = wm8983_snd_controls,  	.num_controls = ARRAY_SIZE(wm8983_snd_controls),  	.dapm_widgets = wm8983_dapm_widgets,  	.num_dapm_widgets = ARRAY_SIZE(wm8983_dapm_widgets),  	.dapm_routes = wm8983_audio_map,  	.num_dapm_routes = ARRAY_SIZE(wm8983_audio_map), -	.readable_register = wm8983_readable +}; + +static const struct regmap_config wm8983_regmap = { +	.reg_bits = 7, +	.val_bits = 9, + +	.reg_defaults = wm8983_defaults, +	.num_reg_defaults = ARRAY_SIZE(wm8983_defaults), +	.cache_type = REGCACHE_RBTREE, + +	.readable_reg = wm8983_readable,  };  #if defined(CONFIG_SPI_MASTER) @@ -1085,24 +1092,27 @@ static int __devinit wm8983_spi_probe(struct spi_device *spi)  	struct wm8983_priv *wm8983;  	int ret; -	wm8983 = kzalloc(sizeof *wm8983, GFP_KERNEL); +	wm8983 = devm_kzalloc(&spi->dev, sizeof *wm8983, GFP_KERNEL);  	if (!wm8983)  		return -ENOMEM; -	wm8983->control_type = SND_SOC_SPI; +	wm8983->regmap = devm_regmap_init_spi(spi, &wm8983_regmap); +	if (IS_ERR(wm8983->regmap)) { +		ret = PTR_ERR(wm8983->regmap); +		dev_err(&spi->dev, "Failed to init regmap: %d\n", ret); +		return ret; +	} +  	spi_set_drvdata(spi, wm8983);  	ret = snd_soc_register_codec(&spi->dev,  				     &soc_codec_dev_wm8983, &wm8983_dai, 1); -	if (ret < 0) -		kfree(wm8983);  	return ret;  }  static int __devexit wm8983_spi_remove(struct spi_device *spi)  {  	snd_soc_unregister_codec(&spi->dev); -	kfree(spi_get_drvdata(spi));  	return 0;  } @@ -1123,24 +1133,28 @@ static __devinit int wm8983_i2c_probe(struct i2c_client *i2c,  	struct wm8983_priv *wm8983;  	int ret; -	wm8983 = kzalloc(sizeof *wm8983, GFP_KERNEL); +	wm8983 = devm_kzalloc(&i2c->dev, sizeof *wm8983, GFP_KERNEL);  	if (!wm8983)  		return -ENOMEM; -	wm8983->control_type = SND_SOC_I2C; +	wm8983->regmap = devm_regmap_init_i2c(i2c, &wm8983_regmap); +	if (IS_ERR(wm8983->regmap)) { +		ret = PTR_ERR(wm8983->regmap); +		dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret); +		return ret; +	} +  	i2c_set_clientdata(i2c, wm8983);  	ret = snd_soc_register_codec(&i2c->dev,  				     &soc_codec_dev_wm8983, &wm8983_dai, 1); -	if (ret < 0) -		kfree(wm8983); +  	return ret;  }  static __devexit int wm8983_i2c_remove(struct i2c_client *client)  {  	snd_soc_unregister_codec(&client->dev); -	kfree(i2c_get_clientdata(client));  	return 0;  } diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index db63c97ddf5..c28c83e5395 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1388,7 +1388,8 @@ static __devinit int wm8990_i2c_probe(struct i2c_client *i2c,  	struct wm8990_priv *wm8990;  	int ret; -	wm8990 = kzalloc(sizeof(struct wm8990_priv), GFP_KERNEL); +	wm8990 = devm_kzalloc(&i2c->dev, sizeof(struct wm8990_priv), +			      GFP_KERNEL);  	if (wm8990 == NULL)  		return -ENOMEM; @@ -1396,15 +1397,14 @@ static __devinit int wm8990_i2c_probe(struct i2c_client *i2c,  	ret = snd_soc_register_codec(&i2c->dev,  			&soc_codec_dev_wm8990, &wm8990_dai, 1); -	if (ret < 0) -		kfree(wm8990); +  	return ret;  }  static __devexit int wm8990_i2c_remove(struct i2c_client *client)  {  	snd_soc_unregister_codec(&client->dev); -	kfree(i2c_get_clientdata(client)); +  	return 0;  } diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c index 9ac31ba9b82..fe439f027e1 100644 --- a/sound/soc/codecs/wm8991.c +++ b/sound/soc/codecs/wm8991.c @@ -1363,7 +1363,7 @@ static __devinit int wm8991_i2c_probe(struct i2c_client *i2c,  	struct wm8991_priv *wm8991;  	int ret; -	wm8991 = kzalloc(sizeof *wm8991, GFP_KERNEL); +	wm8991 = devm_kzalloc(&i2c->dev, sizeof(*wm8991), GFP_KERNEL);  	if (!wm8991)  		return -ENOMEM; @@ -1372,15 +1372,14 @@ static __devinit int wm8991_i2c_probe(struct i2c_client *i2c,  	ret = snd_soc_register_codec(&i2c->dev,  				     &soc_codec_dev_wm8991, &wm8991_dai, 1); -	if (ret < 0) -		kfree(wm8991); +  	return ret;  }  static __devexit int wm8991_i2c_remove(struct i2c_client *client)  {  	snd_soc_unregister_codec(&client->dev); -	kfree(i2c_get_clientdata(client)); +  	return 0;  } @@ -1400,23 +1399,7 @@ static struct i2c_driver wm8991_i2c_driver = {  	.id_table = wm8991_i2c_id,  }; -static int __init wm8991_modinit(void) -{ -	int ret; -	ret = i2c_add_driver(&wm8991_i2c_driver); -	if (ret != 0) { -		printk(KERN_ERR "Failed to register WM8991 I2C driver: %d\n", -		       ret); -	} -	return 0; -} -module_init(wm8991_modinit); - -static void __exit wm8991_exit(void) -{ -	i2c_del_driver(&wm8991_i2c_driver); -} -module_exit(wm8991_exit); +module_i2c_driver(wm8991_i2c_driver);  MODULE_DESCRIPTION("ASoC WM8991 driver");  MODULE_AUTHOR("Graeme Gregory"); diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 9fd80d68897..94737a30716 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -1520,6 +1520,8 @@ static int wm8993_probe(struct snd_soc_codec *codec)  				      wm8993->pdata.lineout2fb,  				      wm8993->pdata.jd_scthr,  				      wm8993->pdata.jd_thr, +				      wm8993->pdata.micbias1_delay, +				      wm8993->pdata.micbias2_delay,  				      wm8993->pdata.micbias1_lvl,  				      wm8993->pdata.micbias2_lvl); diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 6c9eeca85b9..2b2dadc54da 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -671,6 +671,18 @@ SOC_SINGLE_TLV("AIF2 EQ5 Volume", WM8994_AIF2_EQ_GAINS_2, 6, 31, 0,  	       eq_tlv),  }; +static const struct snd_kcontrol_new wm8994_drc_controls[] = { +SND_SOC_BYTES_MASK("AIF1.1 DRC", WM8994_AIF1_DRC1_1, 5, +		   WM8994_AIF1DAC1_DRC_ENA | WM8994_AIF1ADC1L_DRC_ENA | +		   WM8994_AIF1ADC1R_DRC_ENA), +SND_SOC_BYTES_MASK("AIF1.2 DRC", WM8994_AIF1_DRC2_1, 5, +		   WM8994_AIF1DAC2_DRC_ENA | WM8994_AIF1ADC2L_DRC_ENA | +		   WM8994_AIF1ADC2R_DRC_ENA), +SND_SOC_BYTES_MASK("AIF2 DRC", WM8994_AIF2_DRC_1, 5, +		   WM8994_AIF2DAC_DRC_ENA | WM8994_AIF2ADCL_DRC_ENA | +		   WM8994_AIF2ADCR_DRC_ENA), +}; +  static const char *wm8958_ng_text[] = {  	"30ms", "125ms", "250ms", "500ms",  }; @@ -789,11 +801,27 @@ 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 wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);  	switch (event) {  	case SND_SOC_DAPM_PRE_PMU:  		return configure_clock(codec); +	case SND_SOC_DAPM_POST_PMU: +		/* +		 * JACKDET won't run until we start the clock and it +		 * only reports deltas, make sure we notify the state +		 * up the stack on startup.  Use a *very* generous +		 * timeout for paranoia, there's no urgency and we +		 * don't want false reports. +		 */ +		if (wm8994->jackdet && !wm8994->clk_has_run) { +			schedule_delayed_work(&wm8994->jackdet_bootstrap, +					      msecs_to_jiffies(1000)); +			wm8994->clk_has_run = true; +		} +		break; +  	case SND_SOC_DAPM_POST_PMD:  		configure_clock(codec);  		break; @@ -1632,7 +1660,8 @@ SND_SOC_DAPM_SUPPLY("VMID", SND_SOC_NOPM, 0, 0, vmid_event,  		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),  SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event, -		    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), +		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | +		    SND_SOC_DAPM_PRE_PMD),  SND_SOC_DAPM_SUPPLY("DSP1CLK", SND_SOC_NOPM, 3, 0, NULL, 0),  SND_SOC_DAPM_SUPPLY("DSP2CLK", SND_SOC_NOPM, 2, 0, NULL, 0), @@ -2102,6 +2131,10 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,  	case WM8994_FLL_SRC_LRCLK:  	case WM8994_FLL_SRC_BCLK:  		break; +	case WM8994_FLL_SRC_INTERNAL: +		freq_in = 12000000; +		freq_out = 12000000; +		break;  	default:  		return -EINVAL;  	} @@ -2161,12 +2194,14 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,  	snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_4 + reg_offset,  			    WM8994_FLL1_N_MASK, -				    fll.n << WM8994_FLL1_N_SHIFT); +			    fll.n << WM8994_FLL1_N_SHIFT);  	snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset, -			    WM8958_FLL1_BYP | +			    WM8994_FLL1_FRC_NCO | WM8958_FLL1_BYP |  			    WM8994_FLL1_REFCLK_DIV_MASK |  			    WM8994_FLL1_REFCLK_SRC_MASK, +			    ((src == WM8994_FLL_SRC_INTERNAL) +			     << WM8994_FLL1_FRC_NCO_SHIFT) |  			    (fll.clk_ref_div << WM8994_FLL1_REFCLK_DIV_SHIFT) |  			    (src - 1)); @@ -2192,13 +2227,16 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,  			}  		} +		reg = WM8994_FLL1_ENA; +  		if (fll.k) -			reg = WM8994_FLL1_ENA | WM8994_FLL1_FRAC; -		else -			reg = WM8994_FLL1_ENA; +			reg |= WM8994_FLL1_FRAC; +		if (src == WM8994_FLL_SRC_INTERNAL) +			reg |= WM8994_FLL1_OSC_ENA; +  		snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_1 + reg_offset, -				    WM8994_FLL1_ENA | WM8994_FLL1_FRAC, -				    reg); +				    WM8994_FLL1_ENA | WM8994_FLL1_OSC_ENA | +				    WM8994_FLL1_FRAC, reg);  		if (wm8994->fll_locked_irq) {  			timeout = wait_for_completion_timeout(&wm8994->fll_locked[id], @@ -3027,7 +3065,7 @@ static int wm8994_codec_resume(struct snd_soc_codec *codec)  static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)  { -	struct snd_soc_codec *codec = wm8994->codec; +	struct snd_soc_codec *codec = wm8994->hubs.codec;  	struct wm8994_pdata *pdata = wm8994->pdata;  	struct snd_kcontrol_new controls[] = {  		SOC_ENUM_EXT("AIF1.1 EQ Mode", @@ -3085,16 +3123,16 @@ static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)  	wm8994->retune_mobile_enum.max = wm8994->num_retune_mobile_texts;  	wm8994->retune_mobile_enum.texts = wm8994->retune_mobile_texts; -	ret = snd_soc_add_codec_controls(wm8994->codec, controls, +	ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls,  				   ARRAY_SIZE(controls));  	if (ret != 0) -		dev_err(wm8994->codec->dev, +		dev_err(wm8994->hubs.codec->dev,  			"Failed to add ReTune Mobile controls: %d\n", ret);  }  static void wm8994_handle_pdata(struct wm8994_priv *wm8994)  { -	struct snd_soc_codec *codec = wm8994->codec; +	struct snd_soc_codec *codec = wm8994->hubs.codec;  	struct wm8994_pdata *pdata = wm8994->pdata;  	int ret, i; @@ -3107,6 +3145,8 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)  				      pdata->lineout2fb,  				      pdata->jd_scthr,  				      pdata->jd_thr, +				      pdata->micb1_delay, +				      pdata->micb2_delay,  				      pdata->micbias1_lvl,  				      pdata->micbias2_lvl); @@ -3123,10 +3163,10 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)  		};  		/* We need an array of texts for the enum API */ -		wm8994->drc_texts = devm_kzalloc(wm8994->codec->dev, +		wm8994->drc_texts = devm_kzalloc(wm8994->hubs.codec->dev,  			    sizeof(char *) * pdata->num_drc_cfgs, GFP_KERNEL);  		if (!wm8994->drc_texts) { -			dev_err(wm8994->codec->dev, +			dev_err(wm8994->hubs.codec->dev,  				"Failed to allocate %d DRC config texts\n",  				pdata->num_drc_cfgs);  			return; @@ -3138,23 +3178,28 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)  		wm8994->drc_enum.max = pdata->num_drc_cfgs;  		wm8994->drc_enum.texts = wm8994->drc_texts; -		ret = snd_soc_add_codec_controls(wm8994->codec, controls, +		ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls,  					   ARRAY_SIZE(controls)); -		if (ret != 0) -			dev_err(wm8994->codec->dev, -				"Failed to add DRC mode controls: %d\n", ret); -  		for (i = 0; i < WM8994_NUM_DRC; i++)  			wm8994_set_drc(codec, i); +	} else { +		ret = snd_soc_add_codec_controls(wm8994->hubs.codec, +						 wm8994_drc_controls, +						 ARRAY_SIZE(wm8994_drc_controls));  	} +	if (ret != 0) +		dev_err(wm8994->hubs.codec->dev, +			"Failed to add DRC mode controls: %d\n", ret); + +  	dev_dbg(codec->dev, "%d ReTune Mobile configurations\n",  		pdata->num_retune_mobile_cfgs);  	if (pdata->num_retune_mobile_cfgs)  		wm8994_handle_retune_mobile_pdata(wm8994);  	else -		snd_soc_add_codec_controls(wm8994->codec, wm8994_eq_controls, +		snd_soc_add_codec_controls(wm8994->hubs.codec, wm8994_eq_controls,  				     ARRAY_SIZE(wm8994_eq_controls));  	for (i = 0; i < ARRAY_SIZE(pdata->micbias); i++) { @@ -3236,6 +3281,12 @@ int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,  	snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, reg); +	/* enable MICDET and MICSHRT deboune */ +	snd_soc_update_bits(codec, WM8994_IRQ_DEBOUNCE, +			    WM8994_MIC1_DET_DB_MASK | WM8994_MIC1_SHRT_DB_MASK | +			    WM8994_MIC2_DET_DB_MASK | WM8994_MIC2_SHRT_DB_MASK, +			    WM8994_MIC1_DET_DB | WM8994_MIC1_SHRT_DB); +  	snd_soc_dapm_sync(&codec->dapm);  	return 0; @@ -3309,7 +3360,7 @@ static void wm8994_mic_work(struct work_struct *work)  static irqreturn_t wm8994_mic_irq(int irq, void *data)  {  	struct wm8994_priv *priv = data; -	struct snd_soc_codec *codec = priv->codec; +	struct snd_soc_codec *codec = priv->hubs.codec;  #ifndef CONFIG_SND_SOC_WM8994_MODULE  	trace_snd_soc_jack_irq(dev_name(codec->dev)); @@ -3345,7 +3396,7 @@ static void wm8958_default_micdet(u16 status, void *data)  			snd_soc_jack_report(wm8994->micdet[0].jack, 0,  					    wm8994->btn_mask | -					     SND_JACK_HEADSET); +					    SND_JACK_HEADSET);  		}  		return;  	} @@ -3422,7 +3473,7 @@ static void wm8958_default_micdet(u16 status, void *data)  static irqreturn_t wm1811_jackdet_irq(int irq, void *data)  {  	struct wm8994_priv *wm8994 = data; -	struct snd_soc_codec *codec = wm8994->codec; +	struct snd_soc_codec *codec = wm8994->hubs.codec;  	int reg;  	bool present; @@ -3499,10 +3550,22 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)  				    SND_JACK_MECHANICAL | SND_JACK_HEADSET |  				    wm8994->btn_mask); +	/* Since we only report deltas force an update, ensures we +	 * avoid bootstrapping issues with the core. */ +	snd_soc_jack_report(wm8994->micdet[0].jack, 0, 0); +  	pm_runtime_put(codec->dev);  	return IRQ_HANDLED;  } +static void wm1811_jackdet_bootstrap(struct work_struct *work) +{ +	struct wm8994_priv *wm8994 = container_of(work, +						struct wm8994_priv, +						jackdet_bootstrap.work); +	wm1811_jackdet_irq(0, wm8994); +} +  /**   * wm8958_mic_detect - Enable microphone detection via the WM8958 IRQ   * @@ -3573,6 +3636,10 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,  		 * otherwise jump straight to microphone detection.  		 */  		if (wm8994->jackdet) { +			/* Disable debounce for the initial detect */ +			snd_soc_update_bits(codec, WM1811_JACKDET_CTRL, +					    WM1811_JACKDET_DB, 0); +  			snd_soc_update_bits(codec, WM8958_MICBIAS2,  					    WM8958_MICB2_DISCH,  					    WM8958_MICB2_DISCH); @@ -3600,7 +3667,7 @@ EXPORT_SYMBOL_GPL(wm8958_mic_detect);  static irqreturn_t wm8958_mic_irq(int irq, void *data)  {  	struct wm8994_priv *wm8994 = data; -	struct snd_soc_codec *codec = wm8994->codec; +	struct snd_soc_codec *codec = wm8994->hubs.codec;  	int reg, count;  	/* @@ -3690,15 +3757,15 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)  	unsigned int reg;  	int ret, i; -	wm8994->codec = codec; +	wm8994->hubs.codec = codec;  	codec->control_data = control->regmap;  	snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP); -	wm8994->codec = codec; -  	mutex_init(&wm8994->accdet_lock);  	INIT_DELAYED_WORK(&wm8994->mic_work, wm8994_mic_work); +	INIT_DELAYED_WORK(&wm8994->jackdet_bootstrap, +			  wm1811_jackdet_bootstrap);  	for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)  		init_completion(&wm8994->fll_locked[i]); @@ -3756,14 +3823,17 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)  		wm8994->hubs.no_cache_dac_hp_direct = true;  		wm8994->fll_byp = true; -		switch (wm8994->revision) { +		switch (control->cust_id) {  		case 0: -		case 1:  		case 2: -		case 3:  			wm8994->hubs.dcs_codes_l = -9;  			wm8994->hubs.dcs_codes_r = -7;  			break; +		case 1: +		case 3: +			wm8994->hubs.dcs_codes_l = -8; +			wm8994->hubs.dcs_codes_r = -7; +			break;  		default:  			break;  		} @@ -3852,7 +3922,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)  	switch (control->type) {  	case WM1811: -		if (wm8994->revision > 1) { +		if (control->cust_id > 1 || wm8994->revision > 1) {  			ret = wm8994_request_irq(wm8994->wm8994,  						 WM8994_IRQ_GPIO(6),  						 wm1811_jackdet_irq, "JACKDET", diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index d77e06f0a67..f142ec198db 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h @@ -28,10 +28,11 @@  #define WM8994_FLL1 1  #define WM8994_FLL2 2 -#define WM8994_FLL_SRC_MCLK1  1 -#define WM8994_FLL_SRC_MCLK2  2 -#define WM8994_FLL_SRC_LRCLK  3 -#define WM8994_FLL_SRC_BCLK   4 +#define WM8994_FLL_SRC_MCLK1    1 +#define WM8994_FLL_SRC_MCLK2    2 +#define WM8994_FLL_SRC_LRCLK    3 +#define WM8994_FLL_SRC_BCLK     4 +#define WM8994_FLL_SRC_INTERNAL 5  enum wm8994_vmid_mode {  	WM8994_VMID_NORMAL, @@ -72,7 +73,6 @@ struct wm8994;  struct wm8994_priv {  	struct wm_hubs_data hubs;  	struct wm8994 *wm8994; -	struct snd_soc_codec *codec;  	int sysclk[2];  	int sysclk_rate[2];  	int mclk[2]; @@ -81,6 +81,7 @@ struct wm8994_priv {  	struct completion fll_locked[2];  	bool fll_locked_irq;  	bool fll_byp; +	bool clk_has_run;  	int vmid_refcount;  	int active_refcount; @@ -134,6 +135,7 @@ struct wm8994_priv {  	int btn_mask;  	bool jackdet;  	int jackdet_mode; +	struct delayed_work jackdet_bootstrap;  	wm8958_micdet_cb jack_cb;  	void *jack_cb_data; diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 00f183dfa45..6dcb02c3666 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -931,7 +931,7 @@ SND_SOC_DAPM_INPUT("IN2RP"),  SND_SOC_DAPM_INPUT("DMIC1DAT"),  SND_SOC_DAPM_INPUT("DMIC2DAT"), -SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20), +SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0),  SND_SOC_DAPM_SUPPLY_S("SYSCLK", 1, WM8996_AIF_CLOCKING_1, 0, 0, NULL, 0),  SND_SOC_DAPM_SUPPLY_S("SYSDSPCLK", 2, WM8996_CLOCKING_1, 1, 0, NULL, 0),  SND_SOC_DAPM_SUPPLY_S("AIFCLK", 2, WM8996_CLOCKING_1, 2, 0, NULL, 0), diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c index 2c2346fdd63..c7ddc56175d 100644 --- a/sound/soc/codecs/wm9090.c +++ b/sound/soc/codecs/wm9090.c @@ -695,17 +695,7 @@ static struct i2c_driver wm9090_i2c_driver = {  	.id_table = wm9090_id,  }; -static int __init wm9090_init(void) -{ -	return i2c_add_driver(&wm9090_i2c_driver); -} -module_init(wm9090_init); - -static void __exit wm9090_exit(void) -{ -	i2c_del_driver(&wm9090_i2c_driver); -} -module_exit(wm9090_exit); +module_i2c_driver(wm9090_i2c_driver);  MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");  MODULE_DESCRIPTION("WM9090 ASoC driver"); diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index c6d2076a796..4dd73ea08d0 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -132,8 +132,9 @@ SOC_SINGLE("Aux Playback Phone Volume", AC97_CD, 4, 7, 1),  SOC_SINGLE("Phone Volume", AC97_PHONE, 0, 15, 1),  SOC_DOUBLE("Line Capture Volume", AC97_LINE, 8, 0, 31, 1), -SOC_SINGLE("Capture 20dB Boost Switch", AC97_REC_SEL, 14, 1, 0), -SOC_SINGLE("Capture to Phone 20dB Boost Switch", AC97_REC_SEL, 11, 1, 1), +SOC_SINGLE_TLV("Capture Boost Switch", AC97_REC_SEL, 14, 1, 0, boost_tlv), +SOC_SINGLE_TLV("Capture to Phone Boost Switch", AC97_REC_SEL, 11, 1, 1, +	       boost_tlv),  SOC_SINGLE("3D Upper Cut-off Switch", AC97_3D_CONTROL, 5, 1, 1),  SOC_SINGLE("3D Lower Cut-off Switch", AC97_3D_CONTROL, 4, 1, 1), @@ -146,7 +147,7 @@ SOC_SINGLE("Playback Attenuate (-6dB) Switch", AC97_MASTER_TONE, 6, 1, 0),  SOC_SINGLE("Bass Volume", AC97_MASTER_TONE, 8, 15, 1),  SOC_SINGLE("Treble Volume", AC97_MASTER_TONE, 0, 15, 1), -SOC_SINGLE("Capture ADC Switch", AC97_REC_GAIN, 15, 1, 1), +SOC_SINGLE("Capture Switch", AC97_REC_GAIN, 15, 1, 1),  SOC_ENUM("Capture Volume Steps", wm9712_enum[6]),  SOC_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 63, 0),  SOC_SINGLE("Capture ZC Switch", AC97_REC_GAIN, 7, 1, 0), @@ -634,7 +635,6 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec)  {  	int ret = 0; -	codec->control_data = codec;	/* we don't use regmap! */  	ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);  	if (ret < 0) {  		printk(KERN_ERR "wm9712: failed to register AC97 codec\n"); @@ -699,8 +699,8 @@ static int __devexit wm9712_remove(struct platform_device *pdev)  static struct platform_driver wm9712_codec_driver = {  	.driver = { -			.name = "wm9712-codec", -			.owner = THIS_MODULE, +		.name = "wm9712-codec", +		.owner = THIS_MODULE,  	},  	.probe = wm9712_probe, diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index d0b8a3287a8..3eb19fb71d1 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -1196,7 +1196,6 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec)  	if (wm9713 == NULL)  		return -ENOMEM;  	snd_soc_codec_set_drvdata(codec, wm9713); -	codec->control_data = wm9713;	/* we don't use regmap! */  	ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);  	if (ret < 0) diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 61baa48823c..867ae97ddce 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -199,15 +199,56 @@ static void wm_hubs_dcs_cache_set(struct snd_soc_codec *codec, u16 dcs_cfg)  	list_add_tail(&cache->list, &hubs->dcs_cache);  } +static void wm_hubs_read_dc_servo(struct snd_soc_codec *codec, +				  u16 *reg_l, u16 *reg_r) +{ +	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); +	u16 dcs_reg, reg; + +	switch (hubs->dcs_readback_mode) { +	case 2: +		dcs_reg = WM8994_DC_SERVO_4E; +		break; +	case 1: +		dcs_reg = WM8994_DC_SERVO_READBACK; +		break; +	default: +		dcs_reg = WM8993_DC_SERVO_3; +		break; +	} + +	/* Different chips in the family support different readback +	 * methods. +	 */ +	switch (hubs->dcs_readback_mode) { +	case 0: +		*reg_l = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1) +			& WM8993_DCS_INTEG_CHAN_0_MASK; +		*reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2) +			& WM8993_DCS_INTEG_CHAN_1_MASK; +		break; +	case 2: +	case 1: +		reg = snd_soc_read(codec, dcs_reg); +		*reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK) +			>> WM8993_DCS_DAC_WR_VAL_1_SHIFT; +		*reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK; +		break; +	default: +		WARN(1, "Unknown DCS readback method\n"); +		return; +	} +} +  /*   * Startup calibration of the DC servo   */ -static void calibrate_dc_servo(struct snd_soc_codec *codec) +static void enable_dc_servo(struct snd_soc_codec *codec)  {  	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);  	struct wm_hubs_dcs_cache *cache;  	s8 offset; -	u16 reg, reg_l, reg_r, dcs_cfg, dcs_reg; +	u16 reg_l, reg_r, dcs_cfg, dcs_reg;  	switch (hubs->dcs_readback_mode) {  	case 2: @@ -245,27 +286,7 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)  				  WM8993_DCS_TRIG_STARTUP_1);  	} -	/* Different chips in the family support different readback -	 * methods. -	 */ -	switch (hubs->dcs_readback_mode) { -	case 0: -		reg_l = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1) -			& WM8993_DCS_INTEG_CHAN_0_MASK; -		reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2) -			& WM8993_DCS_INTEG_CHAN_1_MASK; -		break; -	case 2: -	case 1: -		reg = snd_soc_read(codec, dcs_reg); -		reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK) -			>> WM8993_DCS_DAC_WR_VAL_1_SHIFT; -		reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK; -		break; -	default: -		WARN(1, "Unknown DCS readback method\n"); -		return; -	} +	wm_hubs_read_dc_servo(codec, ®_l, ®_r);  	dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r); @@ -276,12 +297,16 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)  			hubs->dcs_codes_l, hubs->dcs_codes_r);  		/* HPOUT1R */ -		offset = reg_r; +		offset = (s8)reg_r; +		dev_dbg(codec->dev, "DCS right %d->%d\n", offset, +			offset + hubs->dcs_codes_r);  		offset += hubs->dcs_codes_r;  		dcs_cfg = (u8)offset << WM8993_DCS_DAC_WR_VAL_1_SHIFT;  		/* HPOUT1L */ -		offset = reg_l; +		offset = (s8)reg_l; +		dev_dbg(codec->dev, "DCS left %d->%d\n", offset, +			offset + hubs->dcs_codes_l);  		offset += hubs->dcs_codes_l;  		dcs_cfg |= (u8)offset; @@ -535,7 +560,7 @@ static int hp_event(struct snd_soc_dapm_widget *w,  		snd_soc_update_bits(codec, WM8993_DC_SERVO_1,  				    WM8993_DCS_TIMER_PERIOD_01_MASK, 0); -		calibrate_dc_servo(codec); +		enable_dc_servo(codec);  		reg |= WM8993_HPOUT1R_OUTP | WM8993_HPOUT1R_RMV_SHORT |  			WM8993_HPOUT1L_OUTP | WM8993_HPOUT1L_RMV_SHORT; @@ -619,6 +644,28 @@ static int lineout_event(struct snd_soc_dapm_widget *w,  	return 0;  } +static int micbias_event(struct snd_soc_dapm_widget *w, +			 struct snd_kcontrol *kcontrol, int event) +{ +	struct snd_soc_codec *codec = w->codec; +	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); + +	switch (w->shift) { +	case WM8993_MICB1_ENA_SHIFT: +		if (hubs->micb1_delay) +			msleep(hubs->micb1_delay); +		break; +	case WM8993_MICB2_ENA_SHIFT: +		if (hubs->micb2_delay) +			msleep(hubs->micb2_delay); +		break; +	default: +		return -EINVAL; +	} + +	return 0; +} +  void wm_hubs_update_class_w(struct snd_soc_codec *codec)  {  	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); @@ -634,6 +681,11 @@ void wm_hubs_update_class_w(struct snd_soc_codec *codec)  	snd_soc_update_bits(codec, WM8993_CLASS_W_0,  			    WM8993_CP_DYN_V | WM8993_CP_DYN_FREQ, enable); + +	snd_soc_write(codec, WM8993_LEFT_OUTPUT_VOLUME, +		      snd_soc_read(codec, WM8993_LEFT_OUTPUT_VOLUME)); +	snd_soc_write(codec, WM8993_RIGHT_OUTPUT_VOLUME, +		      snd_soc_read(codec, WM8993_RIGHT_OUTPUT_VOLUME));  }  EXPORT_SYMBOL_GPL(wm_hubs_update_class_w); @@ -809,8 +861,10 @@ SND_SOC_DAPM_INPUT("IN1RP"),  SND_SOC_DAPM_INPUT("IN2RN"),  SND_SOC_DAPM_INPUT("IN2RP:VXRP"), -SND_SOC_DAPM_SUPPLY("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0, NULL, 0), -SND_SOC_DAPM_SUPPLY("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0, +		    micbias_event, SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_SUPPLY("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0, +		    micbias_event, SND_SOC_DAPM_POST_PMU),  SND_SOC_DAPM_MIXER("IN1L PGA", WM8993_POWER_MANAGEMENT_2, 6, 0,  		   in1l_pga, ARRAY_SIZE(in1l_pga)), @@ -1112,6 +1166,8 @@ int wm_hubs_add_analogue_routes(struct snd_soc_codec *codec,  	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);  	struct snd_soc_dapm_context *dapm = &codec->dapm; +	hubs->codec = codec; +  	INIT_LIST_HEAD(&hubs->dcs_cache);  	init_completion(&hubs->dcs_done); @@ -1143,13 +1199,16 @@ EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_routes);  int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec,  				  int lineout1_diff, int lineout2_diff,  				  int lineout1fb, int lineout2fb, -				  int jd_scthr, int jd_thr, int micbias1_lvl, -				  int micbias2_lvl) +				  int jd_scthr, int jd_thr, +				  int micbias1_delay, int micbias2_delay, +				  int micbias1_lvl, int micbias2_lvl)  {  	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);  	hubs->lineout1_se = !lineout1_diff;  	hubs->lineout2_se = !lineout2_diff; +	hubs->micb1_delay = micbias1_delay; +	hubs->micb2_delay = micbias2_delay;  	if (!lineout1_diff)  		snd_soc_update_bits(codec, WM8993_LINE_MIXER1, diff --git a/sound/soc/codecs/wm_hubs.h b/sound/soc/codecs/wm_hubs.h index da2dc899ce6..24c763df21f 100644 --- a/sound/soc/codecs/wm_hubs.h +++ b/sound/soc/codecs/wm_hubs.h @@ -36,6 +36,9 @@ struct wm_hubs_data {  	struct list_head dcs_cache;  	bool (*check_class_w_digital)(struct snd_soc_codec *); +	int micb1_delay; +	int micb2_delay; +  	bool lineout1_se;  	bool lineout1n_ena;  	bool lineout1p_ena; @@ -46,6 +49,8 @@ struct wm_hubs_data {  	bool dcs_done_irq;  	struct completion dcs_done; + +	struct snd_soc_codec *codec;  };  extern int wm_hubs_add_analogue_controls(struct snd_soc_codec *); @@ -54,6 +59,7 @@ extern int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *,  					 int lineout1_diff, int lineout2_diff,  					 int lineout1fb, int lineout2fb,  					 int jd_scthr, int jd_thr, +					 int micbias1_dly, int micbias2_dly,  					 int micbias1_lvl, int micbias2_lvl);  extern irqreturn_t wm_hubs_dcs_done(int irq, void *data); diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 10a2d8c788b..6fac5af1329 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -22,10 +22,6 @@  #include <asm/dma.h>  #include <asm/mach-types.h> -#include <mach/asp.h> -#include <mach/edma.h> -#include <mach/mux.h> -  #include "davinci-pcm.h"  #include "davinci-i2s.h"  #include "davinci-mcasp.h" @@ -160,7 +156,7 @@ static struct snd_soc_dai_link dm6446_evm_dai = {  	.cpu_dai_name = "davinci-mcbsp",  	.codec_dai_name = "tlv320aic3x-hifi",  	.codec_name = "tlv320aic3x-codec.1-001b", -	.platform_name = "davinci-pcm-audio", +	.platform_name = "davinci-mcbsp",  	.init = evm_aic3x_init,  	.ops = &evm_ops,  }; @@ -171,7 +167,7 @@ static struct snd_soc_dai_link dm355_evm_dai = {  	.cpu_dai_name = "davinci-mcbsp.1",  	.codec_dai_name = "tlv320aic3x-hifi",  	.codec_name = "tlv320aic3x-codec.1-001b", -	.platform_name = "davinci-pcm-audio", +	.platform_name = "davinci-mcbsp.1",  	.init = evm_aic3x_init,  	.ops = &evm_ops,  }; @@ -185,14 +181,15 @@ static struct snd_soc_dai_link dm365_evm_dai = {  	.init = evm_aic3x_init,  	.codec_name = "tlv320aic3x-codec.1-0018",  	.ops = &evm_ops, +	.platform_name = "davinci-mcbsp",  #elif defined(CONFIG_SND_DM365_VOICE_CODEC)  	.name = "Voice Codec - CQ93VC",  	.stream_name = "CQ93",  	.cpu_dai_name = "davinci-vcif",  	.codec_dai_name = "cq93vc-hifi",  	.codec_name = "cq93vc-codec", +	.platform_name = "davinci-vcif",  #endif -	.platform_name = "davinci-pcm-audio",  };  static struct snd_soc_dai_link dm6467_evm_dai[] = { @@ -201,7 +198,7 @@ static struct snd_soc_dai_link dm6467_evm_dai[] = {  		.stream_name = "AIC3X",  		.cpu_dai_name= "davinci-mcasp.0",  		.codec_dai_name = "tlv320aic3x-hifi", -		.platform_name ="davinci-pcm-audio", +		.platform_name = "davinci-mcasp.0",  		.codec_name = "tlv320aic3x-codec.0-001a",  		.init = evm_aic3x_init,  		.ops = &evm_ops, @@ -212,7 +209,7 @@ static struct snd_soc_dai_link dm6467_evm_dai[] = {  		.cpu_dai_name= "davinci-mcasp.1",  		.codec_dai_name = "dit-hifi",  		.codec_name = "spdif_dit", -		.platform_name = "davinci-pcm-audio", +		.platform_name = "davinci-mcasp.1",  		.ops = &evm_spdif_ops,  	},  }; @@ -223,7 +220,7 @@ static struct snd_soc_dai_link da830_evm_dai = {  	.cpu_dai_name = "davinci-mcasp.1",  	.codec_dai_name = "tlv320aic3x-hifi",  	.codec_name = "tlv320aic3x-codec.1-0018", -	.platform_name = "davinci-pcm-audio", +	.platform_name = "davinci-mcasp.1",  	.init = evm_aic3x_init,  	.ops = &evm_ops,  }; @@ -234,7 +231,7 @@ static struct snd_soc_dai_link da850_evm_dai = {  	.cpu_dai_name= "davinci-mcasp.0",  	.codec_dai_name = "tlv320aic3x-hifi",  	.codec_name = "tlv320aic3x-codec.1-0018", -	.platform_name = "davinci-pcm-audio", +	.platform_name = "davinci-mcasp.0",  	.init = evm_aic3x_init,  	.ops = &evm_ops,  }; diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 0a74b9587a2..82183120718 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -16,6 +16,7 @@  #include <linux/delay.h>  #include <linux/io.h>  #include <linux/clk.h> +#include <linux/platform_data/davinci_asp.h>  #include <sound/core.h>  #include <sound/pcm.h> @@ -23,8 +24,6 @@  #include <sound/initval.h>  #include <sound/soc.h> -#include <mach/asp.h> -  #include "davinci-pcm.h"  #include "davinci-i2s.h" @@ -732,8 +731,16 @@ static int davinci_i2s_probe(struct platform_device *pdev)  	if (ret != 0)  		goto err_release_clk; +	ret = davinci_soc_platform_register(&pdev->dev); +	if (ret) { +		dev_err(&pdev->dev, "register PCM failed: %d\n", ret); +		goto err_unregister_dai; +	} +  	return 0; +err_unregister_dai: +	snd_soc_unregister_dai(&pdev->dev);  err_release_clk:  	clk_disable(dev->clk);  	clk_put(dev->clk); @@ -745,6 +752,8 @@ static int davinci_i2s_remove(struct platform_device *pdev)  	struct davinci_mcbsp_dev *dev = dev_get_drvdata(&pdev->dev);  	snd_soc_unregister_dai(&pdev->dev); +	davinci_soc_platform_unregister(&pdev->dev); +  	clk_disable(dev->clk);  	clk_put(dev->clk);  	dev->clk = NULL; diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index ce5e5cd254d..714e51e5be5 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -21,7 +21,10 @@  #include <linux/slab.h>  #include <linux/delay.h>  #include <linux/io.h> -#include <linux/clk.h> +#include <linux/pm_runtime.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/of_device.h>  #include <sound/core.h>  #include <sound/pcm.h> @@ -108,6 +111,10 @@  #define DAVINCI_MCASP_WFIFOSTS		(0x1014)  #define DAVINCI_MCASP_RFIFOCTL		(0x1018)  #define DAVINCI_MCASP_RFIFOSTS		(0x101C) +#define MCASP_VER3_WFIFOCTL		(0x1000) +#define MCASP_VER3_WFIFOSTS		(0x1004) +#define MCASP_VER3_RFIFOCTL		(0x1008) +#define MCASP_VER3_RFIFOSTS		(0x100C)  /*   * DAVINCI_MCASP_PWREMUMGT_REG - Power Down and Emulation Management @@ -381,18 +388,36 @@ static void davinci_mcasp_start(struct davinci_audio_dev *dev, int stream)  {  	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {  		if (dev->txnumevt) {	/* enable FIFO */ -			mcasp_clr_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, +			switch (dev->version) { +			case MCASP_VERSION_3: +				mcasp_clr_bits(dev->base + MCASP_VER3_WFIFOCTL,  								FIFO_ENABLE); -			mcasp_set_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, +				mcasp_set_bits(dev->base + MCASP_VER3_WFIFOCTL,  								FIFO_ENABLE); +				break; +			default: +				mcasp_clr_bits(dev->base + +					DAVINCI_MCASP_WFIFOCTL,	FIFO_ENABLE); +				mcasp_set_bits(dev->base + +					DAVINCI_MCASP_WFIFOCTL,	FIFO_ENABLE); +			}  		}  		mcasp_start_tx(dev);  	} else {  		if (dev->rxnumevt) {	/* enable FIFO */ -			mcasp_clr_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, +			switch (dev->version) { +			case MCASP_VERSION_3: +				mcasp_clr_bits(dev->base + MCASP_VER3_RFIFOCTL,  								FIFO_ENABLE); -			mcasp_set_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, +				mcasp_set_bits(dev->base + MCASP_VER3_RFIFOCTL,  								FIFO_ENABLE); +				break; +			default: +				mcasp_clr_bits(dev->base + +					DAVINCI_MCASP_RFIFOCTL,	FIFO_ENABLE); +				mcasp_set_bits(dev->base + +					DAVINCI_MCASP_RFIFOCTL,	FIFO_ENABLE); +			}  		}  		mcasp_start_rx(dev);  	} @@ -413,14 +438,31 @@ static void mcasp_stop_tx(struct davinci_audio_dev *dev)  static void davinci_mcasp_stop(struct davinci_audio_dev *dev, int stream)  {  	if (stream == SNDRV_PCM_STREAM_PLAYBACK) { -		if (dev->txnumevt)	/* disable FIFO */ -			mcasp_clr_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, +		if (dev->txnumevt) {	/* disable FIFO */ +			switch (dev->version) { +			case MCASP_VERSION_3: +				mcasp_clr_bits(dev->base + MCASP_VER3_WFIFOCTL,  								FIFO_ENABLE); +				break; +			default: +				mcasp_clr_bits(dev->base + +					DAVINCI_MCASP_WFIFOCTL,	FIFO_ENABLE); +			} +		}  		mcasp_stop_tx(dev);  	} else { -		if (dev->rxnumevt)	/* disable FIFO */ -			mcasp_clr_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, +		if (dev->rxnumevt) {	/* disable FIFO */ +			switch (dev->version) { +			case MCASP_VERSION_3: +				mcasp_clr_bits(dev->base + MCASP_VER3_RFIFOCTL,  								FIFO_ENABLE); +			break; + +			default: +				mcasp_clr_bits(dev->base + +					DAVINCI_MCASP_RFIFOCTL,	FIFO_ENABLE); +			} +		}  		mcasp_stop_rx(dev);  	}  } @@ -619,20 +661,37 @@ static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream)  		if (dev->txnumevt * tx_ser > 64)  			dev->txnumevt = 1; -		mcasp_mod_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, tx_ser, +		switch (dev->version) { +		case MCASP_VERSION_3: +			mcasp_mod_bits(dev->base + MCASP_VER3_WFIFOCTL, tx_ser,  								NUMDMA_MASK); -		mcasp_mod_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, +			mcasp_mod_bits(dev->base + MCASP_VER3_WFIFOCTL,  				((dev->txnumevt * tx_ser) << 8), NUMEVT_MASK); +			break; +		default: +			mcasp_mod_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, +							tx_ser,	NUMDMA_MASK); +			mcasp_mod_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, +				((dev->txnumevt * tx_ser) << 8), NUMEVT_MASK); +		}  	}  	if (dev->rxnumevt && stream == SNDRV_PCM_STREAM_CAPTURE) {  		if (dev->rxnumevt * rx_ser > 64)  			dev->rxnumevt = 1; - -		mcasp_mod_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, rx_ser, +		switch (dev->version) { +		case MCASP_VERSION_3: +			mcasp_mod_bits(dev->base + MCASP_VER3_RFIFOCTL, rx_ser,  								NUMDMA_MASK); -		mcasp_mod_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, +			mcasp_mod_bits(dev->base + MCASP_VER3_RFIFOCTL,  				((dev->rxnumevt * rx_ser) << 8), NUMEVT_MASK); +			break; +		default: +			mcasp_mod_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, +							rx_ser,	NUMDMA_MASK); +			mcasp_mod_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, +				((dev->rxnumevt * rx_ser) << 8), NUMEVT_MASK); +		}  	}  } @@ -782,20 +841,17 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,  	case SNDRV_PCM_TRIGGER_RESUME:  	case SNDRV_PCM_TRIGGER_START:  	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -		if (!dev->clk_active) { -			clk_enable(dev->clk); -			dev->clk_active = 1; -		} +		ret = pm_runtime_get_sync(dev->dev); +		if (IS_ERR_VALUE(ret)) +			dev_err(dev->dev, "pm_runtime_get_sync() failed\n");  		davinci_mcasp_start(dev, substream->stream);  		break;  	case SNDRV_PCM_TRIGGER_SUSPEND:  		davinci_mcasp_stop(dev, substream->stream); -		if (dev->clk_active) { -			clk_disable(dev->clk); -			dev->clk_active = 0; -		} - +		ret = pm_runtime_put_sync(dev->dev); +		if (IS_ERR_VALUE(ret)) +			dev_err(dev->dev, "pm_runtime_put_sync() failed\n");  		break;  	case SNDRV_PCM_TRIGGER_STOP: @@ -865,6 +921,118 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {  }; +static const struct of_device_id mcasp_dt_ids[] = { +	{ +		.compatible = "ti,dm646x-mcasp-audio", +		.data = (void *)MCASP_VERSION_1, +	}, +	{ +		.compatible = "ti,da830-mcasp-audio", +		.data = (void *)MCASP_VERSION_2, +	}, +	{ +		.compatible = "ti,omap2-mcasp-audio", +		.data = (void *)MCASP_VERSION_3, +	}, +	{ /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mcasp_dt_ids); + +static struct snd_platform_data *davinci_mcasp_set_pdata_from_of( +						struct platform_device *pdev) +{ +	struct device_node *np = pdev->dev.of_node; +	struct snd_platform_data *pdata = NULL; +	const struct of_device_id *match = +			of_match_device(of_match_ptr(mcasp_dt_ids), &pdev->dev); + +	const u32 *of_serial_dir32; +	u8 *of_serial_dir; +	u32 val; +	int i, ret = 0; + +	if (pdev->dev.platform_data) { +		pdata = pdev->dev.platform_data; +		return pdata; +	} else if (match) { +		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); +		if (!pdata) { +			ret = -ENOMEM; +			goto nodata; +		} +	} else { +		/* control shouldn't reach here. something is wrong */ +		ret = -EINVAL; +		goto nodata; +	} + +	if (match->data) +		pdata->version = (u8)((int)match->data); + +	ret = of_property_read_u32(np, "op-mode", &val); +	if (ret >= 0) +		pdata->op_mode = val; + +	ret = of_property_read_u32(np, "tdm-slots", &val); +	if (ret >= 0) +		pdata->tdm_slots = val; + +	ret = of_property_read_u32(np, "num-serializer", &val); +	if (ret >= 0) +		pdata->num_serializer = val; + +	of_serial_dir32 = of_get_property(np, "serial-dir", &val); +	val /= sizeof(u32); +	if (val != pdata->num_serializer) { +		dev_err(&pdev->dev, +				"num-serializer(%d) != serial-dir size(%d)\n", +				pdata->num_serializer, val); +		ret = -EINVAL; +		goto nodata; +	} + +	if (of_serial_dir32) { +		of_serial_dir = devm_kzalloc(&pdev->dev, +						(sizeof(*of_serial_dir) * val), +						GFP_KERNEL); +		if (!of_serial_dir) { +			ret = -ENOMEM; +			goto nodata; +		} + +		for (i = 0; i < pdata->num_serializer; i++) +			of_serial_dir[i] = be32_to_cpup(&of_serial_dir32[i]); + +		pdata->serial_dir = of_serial_dir; +	} + +	ret = of_property_read_u32(np, "tx-num-evt", &val); +	if (ret >= 0) +		pdata->txnumevt = val; + +	ret = of_property_read_u32(np, "rx-num-evt", &val); +	if (ret >= 0) +		pdata->rxnumevt = val; + +	ret = of_property_read_u32(np, "sram-size-playback", &val); +	if (ret >= 0) +		pdata->sram_size_playback = val; + +	ret = of_property_read_u32(np, "sram-size-capture", &val); +	if (ret >= 0) +		pdata->sram_size_capture = val; + +	return  pdata; + +nodata: +	if (ret < 0) { +		dev_err(&pdev->dev, "Error populating platform data, err %d\n", +			ret); +		pdata = NULL; +	} +	return  pdata; +} +  static int davinci_mcasp_probe(struct platform_device *pdev)  {  	struct davinci_pcm_dma_params *dma_data; @@ -873,11 +1041,22 @@ static int davinci_mcasp_probe(struct platform_device *pdev)  	struct davinci_audio_dev *dev;  	int ret; +	if (!pdev->dev.platform_data && !pdev->dev.of_node) { +		dev_err(&pdev->dev, "No platform data supplied\n"); +		return -EINVAL; +	} +  	dev = devm_kzalloc(&pdev->dev, sizeof(struct davinci_audio_dev),  			   GFP_KERNEL);  	if (!dev)  		return	-ENOMEM; +	pdata = davinci_mcasp_set_pdata_from_of(pdev); +	if (!pdata) { +		dev_err(&pdev->dev, "no platform data\n"); +		return -EINVAL; +	} +  	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	if (!mem) {  		dev_err(&pdev->dev, "no mem resource?\n"); @@ -891,13 +1070,13 @@ static int davinci_mcasp_probe(struct platform_device *pdev)  		return -EBUSY;  	} -	pdata = pdev->dev.platform_data; -	dev->clk = clk_get(&pdev->dev, NULL); -	if (IS_ERR(dev->clk)) -		return -ENODEV; +	pm_runtime_enable(&pdev->dev); -	clk_enable(dev->clk); -	dev->clk_active = 1; +	ret = pm_runtime_get_sync(&pdev->dev); +	if (IS_ERR_VALUE(ret)) { +		dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n"); +		return ret; +	}  	dev->base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));  	if (!dev->base) { @@ -914,6 +1093,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)  	dev->version = pdata->version;  	dev->txnumevt = pdata->txnumevt;  	dev->rxnumevt = pdata->rxnumevt; +	dev->dev = &pdev->dev;  	dma_data = &dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK];  	dma_data->asp_chan_q = pdata->asp_chan_q; @@ -952,22 +1132,31 @@ static int davinci_mcasp_probe(struct platform_device *pdev)  	if (ret != 0)  		goto err_release_clk; + +	ret = davinci_soc_platform_register(&pdev->dev); +	if (ret) { +		dev_err(&pdev->dev, "register PCM failed: %d\n", ret); +		goto err_unregister_dai; +	} +  	return 0; +err_unregister_dai: +	snd_soc_unregister_dai(&pdev->dev);  err_release_clk: -	clk_disable(dev->clk); -	clk_put(dev->clk); +	pm_runtime_put_sync(&pdev->dev); +	pm_runtime_disable(&pdev->dev);  	return ret;  }  static int davinci_mcasp_remove(struct platform_device *pdev)  { -	struct davinci_audio_dev *dev = dev_get_drvdata(&pdev->dev);  	snd_soc_unregister_dai(&pdev->dev); -	clk_disable(dev->clk); -	clk_put(dev->clk); -	dev->clk = NULL; +	davinci_soc_platform_unregister(&pdev->dev); + +	pm_runtime_put_sync(&pdev->dev); +	pm_runtime_disable(&pdev->dev);  	return 0;  } @@ -978,6 +1167,7 @@ static struct platform_driver davinci_mcasp_driver = {  	.driver		= {  		.name	= "davinci-mcasp",  		.owner	= THIS_MODULE, +		.of_match_table = of_match_ptr(mcasp_dt_ids),  	},  }; diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h index 4681acc6360..0de9ed6ce03 100644 --- a/sound/soc/davinci/davinci-mcasp.h +++ b/sound/soc/davinci/davinci-mcasp.h @@ -19,7 +19,8 @@  #define DAVINCI_MCASP_H  #include <linux/io.h> -#include <mach/asp.h> +#include <linux/platform_data/davinci_asp.h> +  #include "davinci-pcm.h"  #define DAVINCI_MCASP_RATES	SNDRV_PCM_RATE_8000_96000 @@ -40,9 +41,8 @@ struct davinci_audio_dev {  	struct davinci_pcm_dma_params dma_params[2];  	void __iomem *base;  	int sample_rate; -	struct clk *clk; +	struct device *dev;  	unsigned int codec_fmt; -	u8 clk_active;  	/* McASP specific data */  	int	tdm_slots; diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index 97d77b29896..93ea3bf567e 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -23,7 +23,6 @@  #include <sound/soc.h>  #include <asm/dma.h> -#include <mach/edma.h>  #include <mach/sram.h>  #include "davinci-pcm.h" @@ -864,28 +863,17 @@ static struct snd_soc_platform_driver davinci_soc_platform = {  	.pcm_free = 	davinci_pcm_free,  }; -static int __devinit davinci_soc_platform_probe(struct platform_device *pdev) +int davinci_soc_platform_register(struct device *dev)  { -	return snd_soc_register_platform(&pdev->dev, &davinci_soc_platform); +	return snd_soc_register_platform(dev, &davinci_soc_platform);  } +EXPORT_SYMBOL_GPL(davinci_soc_platform_register); -static int __devexit davinci_soc_platform_remove(struct platform_device *pdev) +void davinci_soc_platform_unregister(struct device *dev)  { -	snd_soc_unregister_platform(&pdev->dev); -	return 0; +	snd_soc_unregister_platform(dev);  } - -static struct platform_driver davinci_pcm_driver = { -	.driver = { -			.name = "davinci-pcm-audio", -			.owner = THIS_MODULE, -	}, - -	.probe = davinci_soc_platform_probe, -	.remove = __devexit_p(davinci_soc_platform_remove), -}; - -module_platform_driver(davinci_pcm_driver); +EXPORT_SYMBOL_GPL(davinci_soc_platform_unregister);  MODULE_AUTHOR("Vladimir Barinov");  MODULE_DESCRIPTION("TI DAVINCI PCM DMA module"); diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h index c0d6c9be4b4..fc4d01cdd8c 100644 --- a/sound/soc/davinci/davinci-pcm.h +++ b/sound/soc/davinci/davinci-pcm.h @@ -12,9 +12,8 @@  #ifndef _DAVINCI_PCM_H  #define _DAVINCI_PCM_H +#include <linux/platform_data/davinci_asp.h>  #include <mach/edma.h> -#include <mach/asp.h> -  struct davinci_pcm_dma_params {  	int channel;			/* sync dma channel ID */ @@ -28,4 +27,7 @@ struct davinci_pcm_dma_params {  	unsigned int fifo_level;  }; +int davinci_soc_platform_register(struct device *dev); +void davinci_soc_platform_unregister(struct device *dev); +  #endif diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c index f71175b29e3..5be65aae7e0 100644 --- a/sound/soc/davinci/davinci-sffsdr.c +++ b/sound/soc/davinci/davinci-sffsdr.c @@ -86,7 +86,7 @@ static struct snd_soc_dai_link sffsdr_dai = {  	.cpu_dai_name = "davinci-mcbsp",  	.codec_dai_name = "pcm3008-hifi",  	.codec_name = "pcm3008-codec", -	.platform_name = "davinci-pcm-audio", +	.platform_name = "davinci-mcbsp",  	.ops = &sffsdr_ops,  }; diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/davinci/davinci-vcif.c index da030ff883d..07bde2e6f84 100644 --- a/sound/soc/davinci/davinci-vcif.c +++ b/sound/soc/davinci/davinci-vcif.c @@ -240,12 +240,20 @@ static int davinci_vcif_probe(struct platform_device *pdev)  		return ret;  	} +	ret = davinci_soc_platform_register(&pdev->dev); +	if (ret) { +		dev_err(&pdev->dev, "register PCM failed: %d\n", ret); +		snd_soc_unregister_dai(&pdev->dev); +		return ret; +	} +  	return 0;  }  static int davinci_vcif_remove(struct platform_device *pdev)  {  	snd_soc_unregister_dai(&pdev->dev); +	davinci_soc_platform_unregister(&pdev->dev);  	return 0;  } diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index d70133086ac..4563b28bd62 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -6,7 +6,7 @@ config SND_SOC_FSL_UTILS  menuconfig SND_POWERPC_SOC  	tristate "SoC Audio for Freescale PowerPC CPUs" -	depends on FSL_SOC +	depends on FSL_SOC || PPC_MPC52xx  	help  	  Say Y or M if you want to add support for codecs attached to  	  the PowerPC CPUs. diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c index efb9ede0120..267d5b4b63c 100644 --- a/sound/soc/fsl/eukrea-tlv320.c +++ b/sound/soc/fsl/eukrea-tlv320.c @@ -93,9 +93,7 @@ static struct snd_soc_card eukrea_tlv320 = {  	.num_links	= 1,  }; -static struct platform_device *eukrea_tlv320_snd_device; - -static int __init eukrea_tlv320_init(void) +static int __devinit eukrea_tlv320_probe(struct platform_device *pdev)  {  	int ret;  	int int_port = 0, ext_port; @@ -136,29 +134,32 @@ static int __init eukrea_tlv320_init(void)  		return 0;  	} -	eukrea_tlv320_snd_device = platform_device_alloc("soc-audio", -1); -	if (!eukrea_tlv320_snd_device) -		return -ENOMEM; - -	platform_set_drvdata(eukrea_tlv320_snd_device, &eukrea_tlv320); -	ret = platform_device_add(eukrea_tlv320_snd_device); - -	if (ret) { -		printk(KERN_ERR "ASoC: Platform device allocation failed\n"); -		platform_device_put(eukrea_tlv320_snd_device); -	} +	eukrea_tlv320.dev = &pdev->dev; +	ret = snd_soc_register_card(&eukrea_tlv320); +	if (ret) +		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);  	return ret;  } -static void __exit eukrea_tlv320_exit(void) +static int __devexit eukrea_tlv320_remove(struct platform_device *pdev)  { -	platform_device_unregister(eukrea_tlv320_snd_device); +	snd_soc_unregister_card(&eukrea_tlv320); + +	return 0;  } -module_init(eukrea_tlv320_init); -module_exit(eukrea_tlv320_exit); +static struct platform_driver eukrea_tlv320_driver = { +	.driver = { +		.name = "eukrea_tlv320", +		.owner = THIS_MODULE, +	}, +	.probe = eukrea_tlv320_probe, +	.remove = __devexit_p(eukrea_tlv320_remove),}; + +module_platform_driver(eukrea_tlv320_driver);  MODULE_AUTHOR("Eric Bénard <eric@eukrea.com>");  MODULE_DESCRIPTION("CPUIMX ALSA SoC driver");  MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:eukrea_tlv320"); diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index 96bb92dd174..6feb2650058 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c @@ -823,12 +823,6 @@ static int fsl_dma_close(struct snd_pcm_substream *substream)  		if (dma_private->irq)  			free_irq(dma_private->irq, dma_private); -		if (dma_private->ld_buf_phys) { -			dma_unmap_single(dev, dma_private->ld_buf_phys, -					 sizeof(dma_private->link), -					 DMA_TO_DEVICE); -		} -  		/* Deallocate the fsl_dma_private structure */  		dma_free_coherent(dev, sizeof(struct fsl_dma_private),  				  dma_private, dma_private->ld_buf_phys); diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c index e7c800ebbd7..524ce6210ce 100644 --- a/sound/soc/fsl/imx-audmux.c +++ b/sound/soc/fsl/imx-audmux.c @@ -74,9 +74,6 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf,  	if (!buf)  		return -ENOMEM; -	if (!audmux_base) -		return -ENOSYS; -  	if (audmux_clk)  		clk_prepare_enable(audmux_clk); diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c index 89a7755b6f5..d85929b79c3 100644 --- a/sound/soc/fsl/imx-pcm-dma.c +++ b/sound/soc/fsl/imx-pcm-dma.c @@ -109,6 +109,9 @@ static int snd_imx_open(struct snd_pcm_substream *substream)  	dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);  	dma_data = kzalloc(sizeof(*dma_data), GFP_KERNEL); +	if (!dma_data) +		return -ENOMEM; +  	dma_data->peripheral_type = dma_params->shared_peripheral ?  					IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI;  	dma_data->priority = DMA_PRIO_HIGH; @@ -117,7 +120,7 @@ static int snd_imx_open(struct snd_pcm_substream *substream)  	ret = snd_dmaengine_pcm_open(substream, filter, dma_data);  	if (ret) {  		kfree(dma_data); -		return 0; +		return ret;  	}  	snd_dmaengine_pcm_set_data(substream, dma_data); diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c index e6a17baca1e..006f7d465ed 100644 --- a/sound/soc/fsl/imx-ssi.c +++ b/sound/soc/fsl/imx-ssi.c @@ -380,14 +380,13 @@ static int imx_ssi_dai_probe(struct snd_soc_dai *dai)  static struct snd_soc_dai_driver imx_ssi_dai = {  	.probe = imx_ssi_dai_probe,  	.playback = { -		/* The SSI does not support monaural audio. */ -		.channels_min = 2, +		.channels_min = 1,  		.channels_max = 2,  		.rates = SNDRV_PCM_RATE_8000_96000,  		.formats = SNDRV_PCM_FMTBIT_S16_LE,  	},  	.capture = { -		.channels_min = 2, +		.channels_min = 1,  		.channels_max = 2,  		.rates = SNDRV_PCM_RATE_8000_96000,  		.formats = SNDRV_PCM_FMTBIT_S16_LE, @@ -524,7 +523,7 @@ static int imx_ssi_probe(struct platform_device *pdev)  	int ret = 0;  	struct snd_soc_dai_driver *dai; -	ssi = kzalloc(sizeof(*ssi), GFP_KERNEL); +	ssi = devm_kzalloc(&pdev->dev, sizeof(*ssi), GFP_KERNEL);  	if (!ssi)  		return -ENOMEM;  	dev_set_drvdata(&pdev->dev, ssi); @@ -537,7 +536,7 @@ static int imx_ssi_probe(struct platform_device *pdev)  	ssi->irq = platform_get_irq(pdev, 0); -	ssi->clk = clk_get(&pdev->dev, NULL); +	ssi->clk = devm_clk_get(&pdev->dev, NULL);  	if (IS_ERR(ssi->clk)) {  		ret = PTR_ERR(ssi->clk);  		dev_err(&pdev->dev, "Cannot get the clock: %d\n", @@ -552,23 +551,18 @@ static int imx_ssi_probe(struct platform_device *pdev)  		goto failed_get_resource;  	} -	if (!request_mem_region(res->start, resource_size(res), DRV_NAME)) { -		dev_err(&pdev->dev, "request_mem_region failed\n"); -		ret = -EBUSY; -		goto failed_get_resource; -	} - -	ssi->base = ioremap(res->start, resource_size(res)); +	ssi->base = devm_request_and_ioremap(&pdev->dev, res);  	if (!ssi->base) {  		dev_err(&pdev->dev, "ioremap failed\n");  		ret = -ENODEV; -		goto failed_ioremap; +		goto failed_register;  	}  	if (ssi->flags & IMX_SSI_USE_AC97) {  		if (ac97_ssi) { +			dev_err(&pdev->dev, "AC'97 SSI already registered\n");  			ret = -EBUSY; -			goto failed_ac97; +			goto failed_register;  		}  		ac97_ssi = ssi;  		setup_channel_to_ac97(ssi); @@ -637,15 +631,10 @@ failed_pdev_fiq_add:  failed_pdev_fiq_alloc:  	snd_soc_unregister_dai(&pdev->dev);  failed_register: -failed_ac97: -	iounmap(ssi->base); -failed_ioremap:  	release_mem_region(res->start, resource_size(res));  failed_get_resource:  	clk_disable_unprepare(ssi->clk); -	clk_put(ssi->clk);  failed_clk: -	kfree(ssi);  	return ret;  } @@ -663,11 +652,8 @@ static int __devexit imx_ssi_remove(struct platform_device *pdev)  	if (ssi->flags & IMX_SSI_USE_AC97)  		ac97_ssi = NULL; -	iounmap(ssi->base);  	release_mem_region(res->start, resource_size(res));  	clk_disable_unprepare(ssi->clk); -	clk_put(ssi->clk); -	kfree(ssi);  	return 0;  } diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c index 9a3f7c5ab68..9997c039bb2 100644 --- a/sound/soc/fsl/mpc5200_dma.c +++ b/sound/soc/fsl/mpc5200_dma.c @@ -370,7 +370,7 @@ static struct snd_soc_platform_driver mpc5200_audio_dma_platform = {  	.pcm_free	= &psc_dma_free,  }; -static int mpc5200_hpcd_probe(struct platform_device *op) +int mpc5200_audio_dma_create(struct platform_device *op)  {  	phys_addr_t fifo;  	struct psc_dma *psc_dma; @@ -487,8 +487,9 @@ out_unmap:  	iounmap(regs);  	return ret;  } +EXPORT_SYMBOL_GPL(mpc5200_audio_dma_create); -static int mpc5200_hpcd_remove(struct platform_device *op) +int mpc5200_audio_dma_destroy(struct platform_device *op)  {  	struct psc_dma *psc_dma = dev_get_drvdata(&op->dev); @@ -510,24 +511,7 @@ static int mpc5200_hpcd_remove(struct platform_device *op)  	return 0;  } - -static struct of_device_id mpc5200_hpcd_match[] = { -	{ .compatible = "fsl,mpc5200-pcm", }, -	{} -}; -MODULE_DEVICE_TABLE(of, mpc5200_hpcd_match); - -static struct platform_driver mpc5200_hpcd_of_driver = { -	.probe		= mpc5200_hpcd_probe, -	.remove		= mpc5200_hpcd_remove, -	.driver = { -		.owner		= THIS_MODULE, -		.name		= "mpc5200-pcm-audio", -		.of_match_table    = mpc5200_hpcd_match, -	} -}; - -module_platform_driver(mpc5200_hpcd_of_driver); +EXPORT_SYMBOL_GPL(mpc5200_audio_dma_destroy);  MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");  MODULE_DESCRIPTION("Freescale MPC5200 PSC in DMA mode ASoC Driver"); diff --git a/sound/soc/fsl/mpc5200_dma.h b/sound/soc/fsl/mpc5200_dma.h index a3c0cd5382f..dff253fde29 100644 --- a/sound/soc/fsl/mpc5200_dma.h +++ b/sound/soc/fsl/mpc5200_dma.h @@ -81,4 +81,7 @@ to_psc_dma_stream(struct snd_pcm_substream *substream, struct psc_dma *psc_dma)  	return &psc_dma->playback;  } +int mpc5200_audio_dma_create(struct platform_device *op); +int mpc5200_audio_dma_destroy(struct platform_device *op); +  #endif /* __SOUND_SOC_FSL_MPC5200_DMA_H__ */ diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c index ffa00a2eb77..a313c0ae36d 100644 --- a/sound/soc/fsl/mpc5200_psc_ac97.c +++ b/sound/soc/fsl/mpc5200_psc_ac97.c @@ -237,15 +237,18 @@ static const struct snd_soc_dai_ops psc_ac97_digital_ops = {  static struct snd_soc_dai_driver psc_ac97_dai[] = {  { +	.name = "mpc5200-psc-ac97.0",  	.ac97_control = 1,  	.probe	= psc_ac97_probe,  	.playback = { +		.stream_name	= "AC97 Playback",  		.channels_min   = 1,  		.channels_max   = 6,  		.rates          = SNDRV_PCM_RATE_8000_48000,  		.formats = SNDRV_PCM_FMTBIT_S32_BE,  	},  	.capture = { +		.stream_name	= "AC97 Capture",  		.channels_min   = 1,  		.channels_max   = 2,  		.rates          = SNDRV_PCM_RATE_8000_48000, @@ -254,8 +257,10 @@ static struct snd_soc_dai_driver psc_ac97_dai[] = {  	.ops = &psc_ac97_analog_ops,  },  { +	.name = "mpc5200-psc-ac97.1",  	.ac97_control = 1,  	.playback = { +		.stream_name	= "AC97 SPDIF",  		.channels_min   = 1,  		.channels_max   = 2,  		.rates          = SNDRV_PCM_RATE_32000 | \ @@ -278,6 +283,10 @@ static int __devinit psc_ac97_of_probe(struct platform_device *op)  	struct snd_ac97 ac97;  	struct mpc52xx_psc __iomem *regs; +	rc = mpc5200_audio_dma_create(op); +	if (rc != 0) +		return rc; +  	rc = snd_soc_register_dais(&op->dev, psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));  	if (rc != 0) {  		dev_err(&op->dev, "Failed to register DAI\n"); @@ -303,6 +312,7 @@ static int __devinit psc_ac97_of_probe(struct platform_device *op)  static int __devexit psc_ac97_of_remove(struct platform_device *op)  { +	mpc5200_audio_dma_destroy(op);  	snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_ac97_dai));  	return 0;  } diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c index 7b530327553..ba1f0a66358 100644 --- a/sound/soc/fsl/mpc5200_psc_i2s.c +++ b/sound/soc/fsl/mpc5200_psc_i2s.c @@ -130,13 +130,16 @@ static const struct snd_soc_dai_ops psc_i2s_dai_ops = {  };  static struct snd_soc_dai_driver psc_i2s_dai[] = {{ +	.name = "mpc5200-psc-i2s.0",  	.playback = { +		.stream_name = "I2S Playback",  		.channels_min = 2,  		.channels_max = 2,  		.rates = PSC_I2S_RATES,  		.formats = PSC_I2S_FORMATS,  	},  	.capture = { +		.stream_name = "I2S Capture",  		.channels_min = 2,  		.channels_max = 2,  		.rates = PSC_I2S_RATES, @@ -156,6 +159,10 @@ static int __devinit psc_i2s_of_probe(struct platform_device *op)  	struct psc_dma *psc_dma;  	struct mpc52xx_psc __iomem *regs; +	rc = mpc5200_audio_dma_create(op); +	if (rc != 0) +		return rc; +  	rc = snd_soc_register_dais(&op->dev, psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));  	if (rc != 0) {  		pr_err("Failed to register DAI\n"); @@ -200,6 +207,7 @@ static int __devinit psc_i2s_of_probe(struct platform_device *op)  static int __devexit psc_i2s_of_remove(struct platform_device *op)  { +	mpc5200_audio_dma_destroy(op);  	snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_i2s_dai));  	return 0;  } diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c index 60bcba1bc30..9ff9318c52b 100644 --- a/sound/soc/fsl/mpc8610_hpcd.c +++ b/sound/soc/fsl/mpc8610_hpcd.c @@ -192,7 +192,6 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)  		container_of(dev, struct platform_device, dev);  	struct device_node *np = ssi_pdev->dev.of_node;  	struct device_node *codec_np = NULL; -	struct platform_device *sound_device = NULL;  	struct mpc8610_hpcd_data *machine_data;  	int ret = -ENODEV;  	const char *sprop; @@ -341,34 +340,22 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)  	machine_data->card.probe = mpc8610_hpcd_machine_probe;  	machine_data->card.remove = mpc8610_hpcd_machine_remove;  	machine_data->card.name = pdev->name; /* The platform driver name */ +	machine_data->card.owner = THIS_MODULE; +	machine_data->card.dev = &pdev->dev;  	machine_data->card.num_links = 2;  	machine_data->card.dai_link = machine_data->dai; -	/* Allocate a new audio platform device structure */ -	sound_device = platform_device_alloc("soc-audio", -1); -	if (!sound_device) { -		dev_err(&pdev->dev, "platform device alloc failed\n"); -		ret = -ENOMEM; -		goto error; -	} - -	/* Associate the card data with the sound device */ -	platform_set_drvdata(sound_device, &machine_data->card); -  	/* Register with ASoC */ -	ret = platform_device_add(sound_device); +	ret = snd_soc_register_card(&machine_data->card);  	if (ret) { -		dev_err(&pdev->dev, "platform device add failed\n"); -		goto error_sound; +		dev_err(&pdev->dev, "could not register card\n"); +		goto error;  	} -	dev_set_drvdata(&pdev->dev, sound_device);  	of_node_put(codec_np);  	return 0; -error_sound: -	platform_device_put(sound_device);  error:  	kfree(machine_data);  error_alloc: @@ -383,17 +370,12 @@ error_alloc:   */  static int __devexit mpc8610_hpcd_remove(struct platform_device *pdev)  { -	struct platform_device *sound_device = dev_get_drvdata(&pdev->dev); -	struct snd_soc_card *card = platform_get_drvdata(sound_device); +	struct snd_soc_card *card = platform_get_drvdata(pdev);  	struct mpc8610_hpcd_data *machine_data =  		container_of(card, struct mpc8610_hpcd_data, card); -	platform_device_unregister(sound_device); - +	snd_soc_unregister_card(card);  	kfree(machine_data); -	sound_device->dev.platform_data = NULL; - -	dev_set_drvdata(&pdev->dev, NULL);  	return 0;  } diff --git a/sound/soc/fsl/mx27vis-aic32x4.c b/sound/soc/fsl/mx27vis-aic32x4.c index f6d04ad4bb3..2b76877b178 100644 --- a/sound/soc/fsl/mx27vis-aic32x4.c +++ b/sound/soc/fsl/mx27vis-aic32x4.c @@ -26,13 +26,13 @@  #include <linux/device.h>  #include <linux/i2c.h>  #include <linux/gpio.h> +#include <linux/platform_data/asoc-mx27vis.h>  #include <sound/core.h>  #include <sound/pcm.h>  #include <sound/soc.h>  #include <sound/soc-dapm.h>  #include <sound/tlv.h>  #include <asm/mach-types.h> -#include <mach/iomux-mx27.h>  #include "../codecs/tlv320aic32x4.h"  #include "imx-ssi.h" @@ -41,20 +41,12 @@  #define MX27VIS_AMP_GAIN	0  #define MX27VIS_AMP_MUTE	1 -#define MX27VIS_PIN_G0		(GPIO_PORTF + 9) -#define MX27VIS_PIN_G1		(GPIO_PORTF + 8) -#define MX27VIS_PIN_SDL		(GPIO_PORTE + 5) -#define MX27VIS_PIN_SDR		(GPIO_PORTF + 7) -  static int mx27vis_amp_gain;  static int mx27vis_amp_mute; - -static const int mx27vis_amp_pins[] = { -	MX27VIS_PIN_G0 | GPIO_GPIO | GPIO_OUT, -	MX27VIS_PIN_G1 | GPIO_GPIO | GPIO_OUT, -	MX27VIS_PIN_SDL | GPIO_GPIO | GPIO_OUT, -	MX27VIS_PIN_SDR | GPIO_GPIO | GPIO_OUT, -}; +static int mx27vis_amp_gain0_gpio; +static int mx27vis_amp_gain1_gpio; +static int mx27vis_amp_mutel_gpio; +static int mx27vis_amp_muter_gpio;  static int mx27vis_aic32x4_hw_params(struct snd_pcm_substream *substream,  			    struct snd_pcm_hw_params *params) @@ -109,13 +101,13 @@ static int mx27vis_amp_set(struct snd_kcontrol *kcontrol,  	switch (reg) {  	case MX27VIS_AMP_GAIN: -		gpio_set_value(MX27VIS_PIN_G0, value & 1); -		gpio_set_value(MX27VIS_PIN_G1, value >> 1); +		gpio_set_value(mx27vis_amp_gain0_gpio, value & 1); +		gpio_set_value(mx27vis_amp_gain1_gpio, value >> 1);  		mx27vis_amp_gain = value;  		break;  	case MX27VIS_AMP_MUTE: -		gpio_set_value(MX27VIS_PIN_SDL, value & 1); -		gpio_set_value(MX27VIS_PIN_SDR, value >> 1); +		gpio_set_value(mx27vis_amp_mutel_gpio, value & 1); +		gpio_set_value(mx27vis_amp_muter_gpio, value >> 1);  		mx27vis_amp_mute = value;  		break;  	} @@ -190,8 +182,19 @@ static struct snd_soc_card mx27vis_aic32x4 = {  static int __devinit mx27vis_aic32x4_probe(struct platform_device *pdev)  { +	struct snd_mx27vis_platform_data *pdata = pdev->dev.platform_data;  	int ret; +	if (!pdata) { +		dev_err(&pdev->dev, "No platform data supplied\n"); +		return -EINVAL; +	} + +	mx27vis_amp_gain0_gpio = pdata->amp_gain0_gpio; +	mx27vis_amp_gain1_gpio = pdata->amp_gain1_gpio; +	mx27vis_amp_mutel_gpio = pdata->amp_mutel_gpio; +	mx27vis_amp_muter_gpio = pdata->amp_muter_gpio; +  	mx27vis_aic32x4.dev = &pdev->dev;  	ret = snd_soc_register_card(&mx27vis_aic32x4);  	if (ret) { @@ -213,11 +216,6 @@ static int __devinit mx27vis_aic32x4_probe(struct platform_device *pdev)  			IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0)  	); -	ret = mxc_gpio_setup_multiple_pins(mx27vis_amp_pins, -			ARRAY_SIZE(mx27vis_amp_pins), "MX27VIS_AMP"); -	if (ret) -		printk(KERN_ERR "ASoC: unable to setup gpios\n"); -  	return ret;  } diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c index 50adf4032bc..144d4960363 100644 --- a/sound/soc/fsl/p1022_ds.c +++ b/sound/soc/fsl/p1022_ds.c @@ -202,7 +202,6 @@ static int p1022_ds_probe(struct platform_device *pdev)  		container_of(dev, struct platform_device, dev);  	struct device_node *np = ssi_pdev->dev.of_node;  	struct device_node *codec_np = NULL; -	struct platform_device *sound_device = NULL;  	struct machine_data *mdata;  	int ret = -ENODEV;  	const char *sprop; @@ -349,36 +348,23 @@ static int p1022_ds_probe(struct platform_device *pdev)  	mdata->card.probe = p1022_ds_machine_probe;  	mdata->card.remove = p1022_ds_machine_remove;  	mdata->card.name = pdev->name; /* The platform driver name */ +	mdata->card.owner = THIS_MODULE; +	mdata->card.dev = &pdev->dev;  	mdata->card.num_links = 2;  	mdata->card.dai_link = mdata->dai; -	/* Allocate a new audio platform device structure */ -	sound_device = platform_device_alloc("soc-audio", -1); -	if (!sound_device) { -		dev_err(&pdev->dev, "platform device alloc failed\n"); -		ret = -ENOMEM; -		goto error; -	} - -	/* Associate the card data with the sound device */ -	platform_set_drvdata(sound_device, &mdata->card); -  	/* Register with ASoC */ -	ret = platform_device_add(sound_device); +	ret = snd_soc_register_card(&mdata->card);  	if (ret) { -		dev_err(&pdev->dev, "platform device add failed\n"); +		dev_err(&pdev->dev, "could not register card\n");  		goto error;  	} -	dev_set_drvdata(&pdev->dev, sound_device);  	of_node_put(codec_np);  	return 0;  error: -	if (sound_device) -		platform_device_put(sound_device); -  	kfree(mdata);  error_put:  	of_node_put(codec_np); @@ -392,17 +378,12 @@ error_put:   */  static int __devexit p1022_ds_remove(struct platform_device *pdev)  { -	struct platform_device *sound_device = dev_get_drvdata(&pdev->dev); -	struct snd_soc_card *card = platform_get_drvdata(sound_device); +	struct snd_soc_card *card = platform_get_drvdata(pdev);  	struct machine_data *mdata =  		container_of(card, struct machine_data, card); -	platform_device_unregister(sound_device); - +	snd_soc_unregister_card(card);  	kfree(mdata); -	sound_device->dev.platform_data = NULL; - -	dev_set_drvdata(&pdev->dev, NULL);  	return 0;  } diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-audio-fabric.c index b3af55dcde9..4b63ec8eb37 100644 --- a/sound/soc/fsl/pcm030-audio-fabric.c +++ b/sound/soc/fsl/pcm030-audio-fabric.c @@ -12,32 +12,27 @@  #include <linux/init.h>  #include <linux/module.h> -#include <linux/interrupt.h>  #include <linux/device.h> -#include <linux/delay.h>  #include <linux/of_device.h>  #include <linux/of_platform.h> -#include <linux/dma-mapping.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/initval.h>  #include <sound/soc.h>  #include "mpc5200_dma.h" -#include "mpc5200_psc_ac97.h" -#include "../codecs/wm9712.h"  #define DRV_NAME "pcm030-audio-fabric" +struct pcm030_audio_data { +	struct snd_soc_card *card; +	struct platform_device *codec_device; +}; +  static struct snd_soc_dai_link pcm030_fabric_dai[] = {  {  	.name = "AC97",  	.stream_name = "AC97 Analog",  	.codec_dai_name = "wm9712-hifi",  	.cpu_dai_name = "mpc5200-psc-ac97.0", -	.platform_name = "mpc5200-pcm-audio",  	.codec_name = "wm9712-codec",  },  { @@ -45,44 +40,95 @@ static struct snd_soc_dai_link pcm030_fabric_dai[] = {  	.stream_name = "AC97 IEC958",  	.codec_dai_name = "wm9712-aux",  	.cpu_dai_name = "mpc5200-psc-ac97.1", -	.platform_name = "mpc5200-pcm-audio",  	.codec_name = "wm9712-codec",  },  }; -static struct snd_soc_card card = { +static struct snd_soc_card pcm030_card = {  	.name = "pcm030",  	.owner = THIS_MODULE,  	.dai_link = pcm030_fabric_dai,  	.num_links = ARRAY_SIZE(pcm030_fabric_dai),  }; -static __init int pcm030_fabric_init(void) +static int __init pcm030_fabric_probe(struct platform_device *op)  { -	struct platform_device *pdev; -	int rc; +	struct device_node *np = op->dev.of_node; +	struct device_node *platform_np; +	struct snd_soc_card *card = &pcm030_card; +	struct pcm030_audio_data *pdata; +	int ret; +	int i;  	if (!of_machine_is_compatible("phytec,pcm030"))  		return -ENODEV; -	pdev = platform_device_alloc("soc-audio", 1); -	if (!pdev) { -		pr_err("pcm030_fabric_init: platform_device_alloc() failed\n"); -		return -ENODEV; -	} +	pdata = devm_kzalloc(&op->dev, sizeof(struct pcm030_audio_data), +			     GFP_KERNEL); +	if (!pdata) +		return -ENOMEM; + +	card->dev = &op->dev; +	platform_set_drvdata(op, pdata); -	platform_set_drvdata(pdev, &card); +	pdata->card = card; -	rc = platform_device_add(pdev); -	if (rc) { -		pr_err("pcm030_fabric_init: platform_device_add() failed\n"); -		platform_device_put(pdev); +	platform_np = of_parse_phandle(np, "asoc-platform", 0); +	if (!platform_np) { +		dev_err(&op->dev, "ac97 not registered\n");  		return -ENODEV;  	} -	return 0; + +	for (i = 0; i < card->num_links; i++) +		card->dai_link[i].platform_of_node = platform_np; + +	ret = request_module("snd-soc-wm9712"); +	if (ret) +		dev_err(&op->dev, "request_module returned: %d\n", ret); + +	pdata->codec_device = platform_device_alloc("wm9712-codec", -1); +	if (!pdata->codec_device) +		dev_err(&op->dev, "platform_device_alloc() failed\n"); + +	ret = platform_device_add(pdata->codec_device); +	if (ret) +		dev_err(&op->dev, "platform_device_add() failed: %d\n", ret); + +	ret = snd_soc_register_card(card); +	if (ret) +		dev_err(&op->dev, "snd_soc_register_card() failed: %d\n", ret); + +	return ret; +} + +static int __devexit pcm030_fabric_remove(struct platform_device *op) +{ +	struct pcm030_audio_data *pdata = platform_get_drvdata(op); +	int ret; + +	ret = snd_soc_unregister_card(pdata->card); +	platform_device_unregister(pdata->codec_device); + +	return ret;  } -module_init(pcm030_fabric_init); +static struct of_device_id pcm030_audio_match[] = { +	{ .compatible = "phytec,pcm030-audio-fabric", }, +	{} +}; +MODULE_DEVICE_TABLE(of, pcm030_audio_match); + +static struct platform_driver pcm030_fabric_driver = { +	.probe		= pcm030_fabric_probe, +	.remove		= __devexit_p(pcm030_fabric_remove), +	.driver		= { +		.name	= DRV_NAME, +		.owner	= THIS_MODULE, +		.of_match_table    = pcm030_audio_match, +	}, +}; + +module_platform_driver(pcm030_fabric_driver);  MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>"); diff --git a/sound/soc/mid-x86/mfld_machine.c b/sound/soc/mid-x86/mfld_machine.c index 2937e54da49..2cc7782714b 100644 --- a/sound/soc/mid-x86/mfld_machine.c +++ b/sound/soc/mid-x86/mfld_machine.c @@ -318,6 +318,15 @@ static struct snd_soc_dai_link mfld_msic_dailink[] = {  		.platform_name = "sst-platform",  		.init = NULL,  	}, +	{ +		.name = "Medfield Compress", +		.stream_name = "Speaker", +		.cpu_dai_name = "Compress-cpu-dai", +		.codec_dai_name = "SN95031 Speaker", +		.codec_name = "sn95031", +		.platform_name = "sst-platform", +		.init = NULL, +	},  };  /* SoC card */ diff --git a/sound/soc/mid-x86/sst_dsp.h b/sound/soc/mid-x86/sst_dsp.h new file mode 100644 index 00000000000..0fce1de284f --- /dev/null +++ b/sound/soc/mid-x86/sst_dsp.h @@ -0,0 +1,134 @@ +#ifndef __SST_DSP_H__ +#define __SST_DSP_H__ +/* + *  sst_dsp.h - Intel SST Driver for audio engine + * + *  Copyright (C) 2008-12 Intel Corporation + *  Authors:	Vinod Koul <vinod.koul@linux.intel.com> + *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + *  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 of the License. + * + *  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. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +enum sst_codec_types { +	/*  AUDIO/MUSIC	CODEC Type Definitions */ +	SST_CODEC_TYPE_UNKNOWN = 0, +	SST_CODEC_TYPE_PCM,	/* Pass through Audio codec */ +	SST_CODEC_TYPE_MP3, +	SST_CODEC_TYPE_MP24, +	SST_CODEC_TYPE_AAC, +	SST_CODEC_TYPE_AACP, +	SST_CODEC_TYPE_eAACP, +}; + +enum stream_type { +	SST_STREAM_TYPE_NONE = 0, +	SST_STREAM_TYPE_MUSIC = 1, +}; + +struct snd_pcm_params { +	u16 codec;	/* codec type */ +	u8 num_chan;	/* 1=Mono, 2=Stereo */ +	u8 pcm_wd_sz;	/* 16/24 - bit*/ +	u32 reserved;	/* Bitrate in bits per second */ +	u32 sfreq;	/* Sampling rate in Hz */ +	u8 use_offload_path; +	u8 reserved2; +	u16 reserved3; +	u8 channel_map[8]; +} __packed; + +/* MP3 Music Parameters Message */ +struct snd_mp3_params { +	u16 codec; +	u8  num_chan;	/* 1=Mono, 2=Stereo	*/ +	u8  pcm_wd_sz; /* 16/24 - bit*/ +	u8  crc_check; /* crc_check - disable (0) or enable (1) */ +	u8  reserved1; /* unused*/ +	u16 reserved2;	/* Unused */ +} __packed; + +#define AAC_BIT_STREAM_ADTS		0 +#define AAC_BIT_STREAM_ADIF		1 +#define AAC_BIT_STREAM_RAW		2 + +/* AAC Music Parameters Message */ +struct snd_aac_params { +	u16 codec; +	u8 num_chan; /* 1=Mono, 2=Stereo*/ +	u8 pcm_wd_sz; /* 16/24 - bit*/ +	u8 bdownsample; /*SBR downsampling 0 - disable 1 -enabled AAC+ only */ +	u8 bs_format; /* input bit stream format adts=0, adif=1, raw=2 */ +	u16  reser2; +	u32 externalsr; /*sampling rate of basic AAC raw bit stream*/ +	u8 sbr_signalling;/*disable/enable/set automode the SBR tool.AAC+*/ +	u8 reser1; +	u16  reser3; +} __packed; + +/* WMA Music Parameters Message */ +struct snd_wma_params { +	u16 codec; +	u8  num_chan;	/* 1=Mono, 2=Stereo */ +	u8  pcm_wd_sz;	/* 16/24 - bit*/ +	u32 brate;	/* Use the hard coded value. */ +	u32 sfreq;	/* Sampling freq eg. 8000, 441000, 48000 */ +	u32 channel_mask;  /* Channel Mask */ +	u16 format_tag;	/* Format Tag */ +	u16 block_align;	/* packet size */ +	u16 wma_encode_opt;/* Encoder option */ +	u8 op_align;	/* op align 0- 16 bit, 1- MSB, 2 LSB */ +	u8 reserved;	/* reserved */ +} __packed; + +/* Codec params struture */ +union  snd_sst_codec_params { +	struct snd_pcm_params pcm_params; +	struct snd_mp3_params mp3_params; +	struct snd_aac_params aac_params; +	struct snd_wma_params wma_params; +} __packed; + +/* Address and size info of a frame buffer */ +struct sst_address_info { +	u32 addr; /* Address at IA */ +	u32 size; /* Size of the buffer */ +}; + +struct snd_sst_alloc_params_ext { +	struct sst_address_info  ring_buf_info[8]; +	u8 sg_count; +	u8 reserved; +	u16 reserved2; +	u32 frag_size;	/*Number of samples after which period elapsed +				  message is sent valid only if path  = 0*/ +} __packed; + +struct snd_sst_stream_params { +	union snd_sst_codec_params uc; +} __packed; + +struct snd_sst_params { +	u32 stream_id; +	u8 codec; +	u8 ops; +	u8 stream_type; +	u8 device_type; +	struct snd_sst_stream_params sparams; +	struct snd_sst_alloc_params_ext aparams; +}; + +#endif /* __SST_DSP_H__ */ diff --git a/sound/soc/mid-x86/sst_platform.c b/sound/soc/mid-x86/sst_platform.c index d34563b12c3..a263cbed862 100644 --- a/sound/soc/mid-x86/sst_platform.c +++ b/sound/soc/mid-x86/sst_platform.c @@ -1,7 +1,7 @@  /*   *  sst_platform.c - Intel MID Platform driver   * - *  Copyright (C) 2010 Intel Corp + *  Copyright (C) 2010-2012 Intel Corp   *  Author: Vinod Koul <vinod.koul@intel.com>   *  Author: Harsha Priya <priya.harsha@intel.com>   *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -32,6 +32,7 @@  #include <sound/pcm.h>  #include <sound/pcm_params.h>  #include <sound/soc.h> +#include <sound/compress_driver.h>  #include "sst_platform.h"  static struct sst_device *sst; @@ -152,6 +153,16 @@ static struct snd_soc_dai_driver sst_platform_dai[] = {  		.formats = SNDRV_PCM_FMTBIT_S24_LE,  	},  }, +{ +	.name = "Compress-cpu-dai", +	.compress_dai = 1, +	.playback = { +		.channels_min = SST_STEREO, +		.channels_max = SST_STEREO, +		.rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000, +		.formats = SNDRV_PCM_FMTBIT_S16_LE, +	}, +},  };  /* helper functions */ @@ -463,8 +474,199 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)  	}  	return retval;  } + +/* compress stream operations */ +static void sst_compr_fragment_elapsed(void *arg) +{ +	struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg; + +	pr_debug("fragment elapsed by driver\n"); +	if (cstream) +		snd_compr_fragment_elapsed(cstream); +} + +static int sst_platform_compr_open(struct snd_compr_stream *cstream) +{ + +	int ret_val = 0; +	struct snd_compr_runtime *runtime = cstream->runtime; +	struct sst_runtime_stream *stream; + +	stream = kzalloc(sizeof(*stream), GFP_KERNEL); +	if (!stream) +		return -ENOMEM; + +	spin_lock_init(&stream->status_lock); + +	/* get the sst ops */ +	if (!sst || !try_module_get(sst->dev->driver->owner)) { +		pr_err("no device available to run\n"); +		ret_val = -ENODEV; +		goto out_ops; +	} +	stream->compr_ops = sst->compr_ops; + +	stream->id = 0; +	sst_set_stream_status(stream, SST_PLATFORM_INIT); +	runtime->private_data = stream; +	return 0; +out_ops: +	kfree(stream); +	return ret_val; +} + +static int sst_platform_compr_free(struct snd_compr_stream *cstream) +{ +	struct sst_runtime_stream *stream; +	int ret_val = 0, str_id; + +	stream = cstream->runtime->private_data; +	/*need to check*/ +	str_id = stream->id; +	if (str_id) +		ret_val = stream->compr_ops->close(str_id); +	module_put(sst->dev->driver->owner); +	kfree(stream); +	pr_debug("%s: %d\n", __func__, ret_val); +	return 0; +} + +static int sst_platform_compr_set_params(struct snd_compr_stream *cstream, +					struct snd_compr_params *params) +{ +	struct sst_runtime_stream *stream; +	int retval; +	struct snd_sst_params str_params; +	struct sst_compress_cb cb; + +	stream = cstream->runtime->private_data; +	/* construct fw structure for this*/ +	memset(&str_params, 0, sizeof(str_params)); + +	str_params.ops = STREAM_OPS_PLAYBACK; +	str_params.stream_type = SST_STREAM_TYPE_MUSIC; +	str_params.device_type = SND_SST_DEVICE_COMPRESS; + +	switch (params->codec.id) { +	case SND_AUDIOCODEC_MP3: { +		str_params.codec = SST_CODEC_TYPE_MP3; +		str_params.sparams.uc.mp3_params.codec = SST_CODEC_TYPE_MP3; +		str_params.sparams.uc.mp3_params.num_chan = params->codec.ch_in; +		str_params.sparams.uc.mp3_params.pcm_wd_sz = 16; +		break; +	} + +	case SND_AUDIOCODEC_AAC: { +		str_params.codec = SST_CODEC_TYPE_AAC; +		str_params.sparams.uc.aac_params.codec = SST_CODEC_TYPE_AAC; +		str_params.sparams.uc.aac_params.num_chan = params->codec.ch_in; +		str_params.sparams.uc.aac_params.pcm_wd_sz = 16; +		if (params->codec.format == SND_AUDIOSTREAMFORMAT_MP4ADTS) +			str_params.sparams.uc.aac_params.bs_format = +							AAC_BIT_STREAM_ADTS; +		else if (params->codec.format == SND_AUDIOSTREAMFORMAT_RAW) +			str_params.sparams.uc.aac_params.bs_format = +							AAC_BIT_STREAM_RAW; +		else { +			pr_err("Undefined format%d\n", params->codec.format); +			return -EINVAL; +		} +		str_params.sparams.uc.aac_params.externalsr = +						params->codec.sample_rate; +		break; +	} + +	default: +		pr_err("codec not supported, id =%d\n", params->codec.id); +		return -EINVAL; +	} + +	str_params.aparams.ring_buf_info[0].addr  = +					virt_to_phys(cstream->runtime->buffer); +	str_params.aparams.ring_buf_info[0].size = +					cstream->runtime->buffer_size; +	str_params.aparams.sg_count = 1; +	str_params.aparams.frag_size = cstream->runtime->fragment_size; + +	cb.param = cstream; +	cb.compr_cb = sst_compr_fragment_elapsed; + +	retval = stream->compr_ops->open(&str_params, &cb); +	if (retval < 0) { +		pr_err("stream allocation failed %d\n", retval); +		return retval; +	} + +	stream->id = retval; +	return 0; +} + +static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd) +{ +	struct sst_runtime_stream *stream = +		cstream->runtime->private_data; + +	return stream->compr_ops->control(cmd, stream->id); +} + +static int sst_platform_compr_pointer(struct snd_compr_stream *cstream, +					struct snd_compr_tstamp *tstamp) +{ +	struct sst_runtime_stream *stream; + +	stream  = cstream->runtime->private_data; +	stream->compr_ops->tstamp(stream->id, tstamp); +	tstamp->byte_offset = tstamp->copied_total % +				 (u32)cstream->runtime->buffer_size; +	pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset); +	return 0; +} + +static int sst_platform_compr_ack(struct snd_compr_stream *cstream, +					size_t bytes) +{ +	struct sst_runtime_stream *stream; + +	stream  = cstream->runtime->private_data; +	stream->compr_ops->ack(stream->id, (unsigned long)bytes); +	stream->bytes_written += bytes; + +	return 0; +} + +static int sst_platform_compr_get_caps(struct snd_compr_stream *cstream, +					struct snd_compr_caps *caps) +{ +	struct sst_runtime_stream *stream = +		cstream->runtime->private_data; + +	return stream->compr_ops->get_caps(caps); +} + +static int sst_platform_compr_get_codec_caps(struct snd_compr_stream *cstream, +					struct snd_compr_codec_caps *codec) +{ +	struct sst_runtime_stream *stream = +		cstream->runtime->private_data; + +	return stream->compr_ops->get_codec_caps(codec); +} + +static struct snd_compr_ops sst_platform_compr_ops = { + +	.open = sst_platform_compr_open, +	.free = sst_platform_compr_free, +	.set_params = sst_platform_compr_set_params, +	.trigger = sst_platform_compr_trigger, +	.pointer = sst_platform_compr_pointer, +	.ack = sst_platform_compr_ack, +	.get_caps = sst_platform_compr_get_caps, +	.get_codec_caps = sst_platform_compr_get_codec_caps, +}; +  static struct snd_soc_platform_driver sst_soc_platform_drv = {  	.ops		= &sst_platform_ops, +	.compr_ops	= &sst_platform_compr_ops,  	.pcm_new	= sst_pcm_new,  	.pcm_free	= sst_pcm_free,  }; diff --git a/sound/soc/mid-x86/sst_platform.h b/sound/soc/mid-x86/sst_platform.h index f04f4f72daa..d61c5d514ff 100644 --- a/sound/soc/mid-x86/sst_platform.h +++ b/sound/soc/mid-x86/sst_platform.h @@ -27,6 +27,8 @@  #ifndef __SST_PLATFORMDRV_H__  #define __SST_PLATFORMDRV_H__ +#include "sst_dsp.h" +  #define SST_MONO		1  #define SST_STEREO		2  #define SST_MAX_CAP		5 @@ -42,7 +44,6 @@  #define SST_MIN_PERIODS		2  #define SST_MAX_PERIODS		(1024*2)  #define SST_FIFO_SIZE		0 -#define SST_CODEC_TYPE_PCM	1  struct pcm_stream_info {  	int str_id; @@ -83,6 +84,7 @@ enum sst_audio_device_type {  	SND_SST_DEVICE_VIBRA,  	SND_SST_DEVICE_HAPTIC,  	SND_SST_DEVICE_CAPTURE, +	SND_SST_DEVICE_COMPRESS,  };  /* PCM Parameters */ @@ -107,6 +109,24 @@ struct sst_stream_params {  	struct sst_pcm_params sparams;  }; +struct sst_compress_cb { +	void *param; +	void (*compr_cb)(void *param); +}; + +struct compress_sst_ops { +	const char *name; +	int (*open) (struct snd_sst_params *str_params, +			struct sst_compress_cb *cb); +	int (*control) (unsigned int cmd, unsigned int str_id); +	int (*tstamp) (unsigned int str_id, struct snd_compr_tstamp *tstamp); +	int (*ack) (unsigned int str_id, unsigned long bytes); +	int (*close) (unsigned int str_id); +	int (*get_caps) (struct snd_compr_caps *caps); +	int (*get_codec_caps) (struct snd_compr_codec_caps *codec); + +}; +  struct sst_ops {  	int (*open) (struct sst_stream_params *str_param);  	int (*device_control) (int cmd, void *arg); @@ -115,8 +135,11 @@ struct sst_ops {  struct sst_runtime_stream {  	int     stream_status; +	unsigned int id; +	size_t bytes_written;  	struct pcm_stream_info stream_info;  	struct sst_ops *ops; +	struct compress_sst_ops *compr_ops;  	spinlock_t	status_lock;  }; @@ -124,6 +147,7 @@ struct sst_device {  	char *name;  	struct device *dev;  	struct sst_ops *ops; +	struct compress_sst_ops *compr_ops;  };  int sst_register_dsp(struct sst_device *sst); diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index b3030718c22..aa037b292f3 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -704,7 +704,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev)  		return ret;  	} -	saif->clk = clk_get(&pdev->dev, NULL); +	saif->clk = devm_clk_get(&pdev->dev, NULL);  	if (IS_ERR(saif->clk)) {  		ret = PTR_ERR(saif->clk);  		dev_err(&pdev->dev, "Cannot get the clock: %d\n", @@ -717,8 +717,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev)  	saif->base = devm_request_and_ioremap(&pdev->dev, iores);  	if (!saif->base) {  		dev_err(&pdev->dev, "ioremap failed\n"); -		ret = -ENODEV; -		goto failed_get_resource; +		return -ENODEV;  	}  	dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); @@ -731,7 +730,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev)  					   &saif->dma_param.chan_num);  		if (ret) {  			dev_err(&pdev->dev, "failed to get dma channel\n"); -			goto failed_get_resource; +			return ret;  		}  	} else {  		saif->dma_param.chan_num = dmares->start; @@ -742,7 +741,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev)  		ret = saif->irq;  		dev_err(&pdev->dev, "failed to get irq resource: %d\n",  			ret); -		goto failed_get_resource; +		return ret;  	}  	saif->dev = &pdev->dev; @@ -750,7 +749,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev)  			       "mxs-saif", saif);  	if (ret) {  		dev_err(&pdev->dev, "failed to request irq\n"); -		goto failed_get_resource; +		return ret;  	}  	saif->dma_param.chan_irq = platform_get_irq(pdev, 1); @@ -758,7 +757,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev)  		ret = saif->dma_param.chan_irq;  		dev_err(&pdev->dev, "failed to get dma irq resource: %d\n",  			ret); -		goto failed_get_resource; +		return ret;  	}  	platform_set_drvdata(pdev, saif); @@ -766,7 +765,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev)  	ret = snd_soc_register_dai(&pdev->dev, &mxs_saif_dai);  	if (ret) {  		dev_err(&pdev->dev, "register DAI failed\n"); -		goto failed_get_resource; +		return ret;  	}  	ret = mxs_pcm_platform_register(&pdev->dev); @@ -779,19 +778,14 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev)  failed_pdev_alloc:  	snd_soc_unregister_dai(&pdev->dev); -failed_get_resource: -	clk_put(saif->clk);  	return ret;  }  static int __devexit mxs_saif_remove(struct platform_device *pdev)  { -	struct mxs_saif *saif = platform_get_drvdata(pdev); -  	mxs_pcm_platform_unregister(&pdev->dev);  	snd_soc_unregister_dai(&pdev->dev); -	clk_put(saif->clk);  	return 0;  } diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 57a2fa75108..7048137f9a3 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -1,6 +1,7 @@  config SND_OMAP_SOC  	tristate "SoC Audio for the Texas Instruments OMAP chips" -	depends on ARCH_OMAP +	depends on ARCH_OMAP && DMA_OMAP +	select SND_SOC_DMAENGINE_PCM  config SND_OMAP_SOC_DMIC  	tristate @@ -60,23 +61,6 @@ config SND_OMAP_SOC_OSK5912  	help  	  Say Y if you want to add support for SoC audio on osk5912. -config SND_OMAP_SOC_OVERO -	tristate "SoC Audio support for Gumstix Overo and CompuLab CM-T35" -	depends on TWL4030_CORE && SND_OMAP_SOC && (MACH_OVERO || MACH_CM_T35) -	select SND_OMAP_SOC_MCBSP -	select SND_SOC_TWL4030 -	help -	  Say Y if you want to add support for SoC audio on the -	  Gumstix Overo or CompuLab CM-T35 - -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_AM3517EVM  	tristate "SoC Audio support for OMAP3517 / AM3517 EVM"  	depends on SND_OMAP_SOC && MACH_OMAP3517EVM && I2C @@ -95,6 +79,19 @@ config SND_OMAP_SOC_SDP3430  	  Say Y if you want to add support for SoC audio on Texas Instruments  	  SDP3430. +config SND_OMAP_SOC_OMAP_TWL4030 +	tristate "SoC Audio support for TI SoC based boards with twl4030 codec" +	depends on TWL4030_CORE && SND_OMAP_SOC +	select SND_OMAP_SOC_MCBSP +	select SND_SOC_TWL4030 +	help +	  Say Y if you want to add support for SoC audio on TI SoC based boards +	  using twl4030 as c codec. This driver currently supports: +	  - Beagleboard or Devkit8000 +	  - Gumstix Overo or CompuLab CM-T35/CM-T3730 +	  - IGEP v2 +	  - OMAP3EVM +  config SND_OMAP_SOC_OMAP_ABE_TWL6040  	tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec"  	depends on TWL6040_CORE && SND_OMAP_SOC && ARCH_OMAP4 @@ -127,16 +124,6 @@ config SND_OMAP_SOC_OMAP3_PANDORA  	help  	  Say Y if you want to add support for SoC audio on the OMAP3 Pandora. -config SND_OMAP_SOC_OMAP3_BEAGLE -	tristate "SoC Audio support for OMAP3 Beagle and Devkit8000" -	depends on TWL4030_CORE && SND_OMAP_SOC -	depends on (MACH_OMAP3_BEAGLE || MACH_DEVKIT8000) -	select SND_OMAP_SOC_MCBSP -	select SND_SOC_TWL4030 -	help -	  Say Y if you want to add support for SoC audio on the Beagleboard or -	  the clone Devkit8000. -  config SND_OMAP_SOC_ZOOM2  	tristate "SoC Audio support for Zoom2"  	depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_ZOOM2 @@ -144,11 +131,3 @@ config SND_OMAP_SOC_ZOOM2  	select SND_SOC_TWL4030  	help  	  Say Y if you want to add support for Soc audio on Zoom2 board. - -config SND_OMAP_SOC_IGEP0020 -	tristate "SoC Audio support for IGEP v2" -	depends on TWL4030_CORE && SND_OMAP_SOC && MACH_IGEP0020 -	select SND_OMAP_SOC_MCBSP -	select SND_SOC_TWL4030 -	help -	  Say Y if you want to add support for Soc audio on IGEP v2 board. diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index 0e14dd32256..19637e55ea4 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile @@ -16,29 +16,23 @@ snd-soc-n810-objs := n810.o  snd-soc-rx51-objs := rx51.o  snd-soc-ams-delta-objs := ams-delta.o  snd-soc-osk5912-objs := osk5912.o -snd-soc-overo-objs := overo.o -snd-soc-omap3evm-objs := omap3evm.o  snd-soc-am3517evm-objs := am3517evm.o  snd-soc-sdp3430-objs := sdp3430.o  snd-soc-omap-abe-twl6040-objs := omap-abe-twl6040.o +snd-soc-omap-twl4030-objs := omap-twl4030.o  snd-soc-omap3pandora-objs := omap3pandora.o -snd-soc-omap3beagle-objs := omap3beagle.o  snd-soc-zoom2-objs := zoom2.o -snd-soc-igep0020-objs := igep0020.o  snd-soc-omap-hdmi-card-objs := omap-hdmi-card.o  obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o  obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o  obj-$(CONFIG_SND_OMAP_SOC_AMS_DELTA) += snd-soc-ams-delta.o  obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o -obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o  obj-$(CONFIG_SND_OMAP_SOC_OMAP2EVM) += snd-soc-omap2evm.o -obj-$(CONFIG_SND_OMAP_SOC_OMAP3EVM) += snd-soc-omap3evm.o  obj-$(CONFIG_SND_OMAP_SOC_AM3517EVM) += snd-soc-am3517evm.o  obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o  obj-$(CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o +obj-$(CONFIG_SND_OMAP_SOC_OMAP_TWL4030) += snd-soc-omap-twl4030.o  obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o -obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o  obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o -obj-$(CONFIG_SND_OMAP_SOC_IGEP0020) += snd-soc-igep0020.o  obj-$(CONFIG_SND_OMAP_SOC_OMAP_HDMI) += snd-soc-omap-hdmi-card.o diff --git a/sound/soc/omap/am3517evm.c b/sound/soc/omap/am3517evm.c index a52e87d28b6..fad350682ca 100644 --- a/sound/soc/omap/am3517evm.c +++ b/sound/soc/omap/am3517evm.c @@ -41,32 +41,15 @@ static int am3517evm_hw_params(struct snd_pcm_substream *substream,  {  	struct snd_soc_pcm_runtime *rtd = substream->private_data;  	struct snd_soc_dai *codec_dai = rtd->codec_dai; -	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;  	int ret;  	/* Set the codec system clock for DAC and ADC */  	ret = snd_soc_dai_set_sysclk(codec_dai, 0,  			CODEC_CLOCK, SND_SOC_CLOCK_IN); -	if (ret < 0) { +	if (ret < 0)  		printk(KERN_ERR "can't set codec system clock\n"); -		return ret; -	} - -	ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_CLKR_SRC_CLKX, 0, -				SND_SOC_CLOCK_IN); -	if (ret < 0) { -		printk(KERN_ERR "can't set CPU system clock OMAP_MCBSP_CLKR_SRC_CLKX\n"); -		return ret; -	} -	ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_FSR_SRC_FSX, 0, -				SND_SOC_CLOCK_IN); -	if (ret < 0) { -		printk(KERN_ERR "can't set CPU system clock OMAP_MCBSP_FSR_SRC_FSX\n"); -		return ret; -	} - -	return 0; +	return ret;  }  static struct snd_soc_ops am3517evm_ops = { diff --git a/sound/soc/omap/igep0020.c b/sound/soc/omap/igep0020.c deleted file mode 100644 index 5ed871676ed..00000000000 --- a/sound/soc/omap/igep0020.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * igep0020.c  --  SoC audio for IGEP v2 - * - * Based on sound/soc/omap/overo.c by Steve Sakoman - * - * 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 <linux/clk.h> -#include <linux/platform_device.h> -#include <linux/module.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> - -#include <asm/mach-types.h> -#include <mach/hardware.h> -#include <mach/gpio.h> -#include <linux/platform_data/asoc-ti-mcbsp.h> - -#include "omap-mcbsp.h" -#include "omap-pcm.h" - -static int igep2_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->codec_dai; -	int 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 igep2_ops = { -	.hw_params = igep2_hw_params, -}; - -/* Digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link igep2_dai = { -	.name = "TWL4030", -	.stream_name = "TWL4030", -	.cpu_dai_name = "omap-mcbsp.2", -	.codec_dai_name = "twl4030-hifi", -	.platform_name = "omap-pcm-audio", -	.codec_name = "twl4030-codec", -	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | -		   SND_SOC_DAIFMT_CBM_CFM, -	.ops = &igep2_ops, -}; - -/* Audio machine driver */ -static struct snd_soc_card snd_soc_card_igep2 = { -	.name = "igep2", -	.owner = THIS_MODULE, -	.dai_link = &igep2_dai, -	.num_links = 1, -}; - -static struct platform_device *igep2_snd_device; - -static int __init igep2_soc_init(void) -{ -	int ret; - -	if (!machine_is_igep0020()) -		return -ENODEV; -	printk(KERN_INFO "IGEP v2 SoC init\n"); - -	igep2_snd_device = platform_device_alloc("soc-audio", -1); -	if (!igep2_snd_device) { -		printk(KERN_ERR "Platform device allocation failed\n"); -		return -ENOMEM; -	} - -	platform_set_drvdata(igep2_snd_device, &snd_soc_card_igep2); - -	ret = platform_device_add(igep2_snd_device); -	if (ret) -		goto err1; - -	return 0; - -err1: -	printk(KERN_ERR "Unable to add platform device\n"); -	platform_device_put(igep2_snd_device); - -	return ret; -} -module_init(igep2_soc_init); - -static void __exit igep2_soc_exit(void) -{ -	platform_device_unregister(igep2_snd_device); -} -module_exit(igep2_soc_exit); - -MODULE_AUTHOR("Enric Balletbo i Serra <eballetbo@iseebcn.com>"); -MODULE_DESCRIPTION("ALSA SoC IGEP v2"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c index a681a9a8b84..afb8d4f1bed 100644 --- a/sound/soc/omap/mcbsp.c +++ b/sound/soc/omap/mcbsp.c @@ -24,6 +24,7 @@  #include <linux/delay.h>  #include <linux/io.h>  #include <linux/slab.h> +#include <linux/pm_runtime.h>  #include <linux/platform_data/asoc-ti-mcbsp.h> @@ -728,50 +729,39 @@ void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int tx, int rx)  int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id)  { +	struct clk *fck_src;  	const char *src; +	int r;  	if (fck_src_id == MCBSP_CLKS_PAD_SRC) -		src = "clks_ext"; +		src = "pad_fck";  	else if (fck_src_id == MCBSP_CLKS_PRCM_SRC) -		src = "clks_fclk"; +		src = "prcm_fck";  	else  		return -EINVAL; -	if (mcbsp->pdata->set_clk_src) -		return mcbsp->pdata->set_clk_src(mcbsp->dev, mcbsp->fclk, src); -	else +	fck_src = clk_get(mcbsp->dev, src); +	if (IS_ERR(fck_src)) { +		dev_err(mcbsp->dev, "CLKS: could not clk_get() %s\n", src);  		return -EINVAL; -} - -int omap_mcbsp_6pin_src_mux(struct omap_mcbsp *mcbsp, u8 mux) -{ -	const char *signal, *src; +	} -	if (!mcbsp->pdata->mux_signal) -		return -EINVAL; +	pm_runtime_put_sync(mcbsp->dev); -	switch (mux) { -	case CLKR_SRC_CLKR: -		signal = "clkr"; -		src = "clkr"; -		break; -	case CLKR_SRC_CLKX: -		signal = "clkr"; -		src = "clkx"; -		break; -	case FSR_SRC_FSR: -		signal = "fsr"; -		src = "fsr"; -		break; -	case FSR_SRC_FSX: -		signal = "fsr"; -		src = "fsx"; -		break; -	default: -		return -EINVAL; +	r = clk_set_parent(mcbsp->fclk, fck_src); +	if (r) { +		dev_err(mcbsp->dev, "CLKS: could not clk_set_parent() to %s\n", +			src); +		clk_put(fck_src); +		return r;  	} -	return mcbsp->pdata->mux_signal(mcbsp->dev, signal, src); +	pm_runtime_get_sync(mcbsp->dev); + +	clk_put(fck_src); + +	return 0; +  }  #define max_thres(m)			(mcbsp->pdata->buffer_size) diff --git a/sound/soc/omap/mcbsp.h b/sound/soc/omap/mcbsp.h index 262a6152111..49a67259ce5 100644 --- a/sound/soc/omap/mcbsp.h +++ b/sound/soc/omap/mcbsp.h @@ -334,9 +334,6 @@ void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int tx, int rx);  /* McBSP functional clock source changing function */  int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id); -/* McBSP signal muxing API */ -int omap_mcbsp_6pin_src_mux(struct omap_mcbsp *mcbsp, u8 mux); -  /* Sidetone specific API */  int omap_st_set_chgain(struct omap_mcbsp *mcbsp, int channel, s16 chgain);  int omap_st_get_chgain(struct omap_mcbsp *mcbsp, int channel, s16 *chgain); diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c index 45909ca889f..4a73ef3ae12 100644 --- a/sound/soc/omap/omap-abe-twl6040.c +++ b/sound/soc/omap/omap-abe-twl6040.c @@ -25,6 +25,7 @@  #include <linux/mfd/twl6040.h>  #include <linux/platform_data/omap-abe-twl6040.h>  #include <linux/module.h> +#include <linux/of.h>  #include <sound/core.h>  #include <sound/pcm.h> @@ -39,6 +40,8 @@  struct abe_twl6040 {  	int	jack_detection;	/* board can detect jack events */  	int	mclk_freq;	/* MCLK frequency speed for twl6040 */ + +	struct platform_device *dmic_codec_dev;  };  static int omap_abe_hw_params(struct snd_pcm_substream *substream, @@ -181,17 +184,6 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)  	int hs_trim;  	int ret = 0; -	/* Disable not connected paths if not used */ -	twl6040_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone"); -	twl6040_disconnect_pin(dapm, pdata->has_hf, "Ext Spk"); -	twl6040_disconnect_pin(dapm, pdata->has_ep, "Earphone Spk"); -	twl6040_disconnect_pin(dapm, pdata->has_aux, "Line Out"); -	twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vinrator"); -	twl6040_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic"); -	twl6040_disconnect_pin(dapm, pdata->has_mainmic, "Main Handset Mic"); -	twl6040_disconnect_pin(dapm, pdata->has_submic, "Sub Handset Mic"); -	twl6040_disconnect_pin(dapm, pdata->has_afm, "Line In"); -  	/*  	 * Configure McPDM offset cancellation based on the HSOTRIM value from  	 * twl6040. @@ -212,6 +204,24 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)  		twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET);  	} +	/* +	 * NULL pdata means we booted with DT. In this case the routing is +	 * provided and the card is fully routed, no need to mark pins. +	 */ +	if (!pdata) +		return ret; + +	/* Disable not connected paths if not used */ +	twl6040_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone"); +	twl6040_disconnect_pin(dapm, pdata->has_hf, "Ext Spk"); +	twl6040_disconnect_pin(dapm, pdata->has_ep, "Earphone Spk"); +	twl6040_disconnect_pin(dapm, pdata->has_aux, "Line Out"); +	twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vinrator"); +	twl6040_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic"); +	twl6040_disconnect_pin(dapm, pdata->has_mainmic, "Main Handset Mic"); +	twl6040_disconnect_pin(dapm, pdata->has_submic, "Sub Handset Mic"); +	twl6040_disconnect_pin(dapm, pdata->has_afm, "Line In"); +  	return ret;  } @@ -266,52 +276,116 @@ static struct snd_soc_card omap_abe_card = {  static __devinit int omap_abe_probe(struct platform_device *pdev)  {  	struct omap_abe_twl6040_data *pdata = dev_get_platdata(&pdev->dev); +	struct device_node *node = pdev->dev.of_node;  	struct snd_soc_card *card = &omap_abe_card;  	struct abe_twl6040 *priv;  	int num_links = 0; -	int ret; +	int ret = 0;  	card->dev = &pdev->dev; -	if (!pdata) { -		dev_err(&pdev->dev, "Missing pdata\n"); -		return -ENODEV; -	} -  	priv = devm_kzalloc(&pdev->dev, sizeof(struct abe_twl6040), GFP_KERNEL);  	if (priv == NULL)  		return -ENOMEM; -	if (pdata->card_name) { -		card->name = pdata->card_name; +	priv->dmic_codec_dev = ERR_PTR(-EINVAL); + +	if (node) { +		struct device_node *dai_node; + +		if (snd_soc_of_parse_card_name(card, "ti,model")) { +			dev_err(&pdev->dev, "Card name is not provided\n"); +			return -ENODEV; +		} + +		ret = snd_soc_of_parse_audio_routing(card, +						"ti,audio-routing"); +		if (ret) { +			dev_err(&pdev->dev, +				"Error while parsing DAPM routing\n"); +			return ret; +		} + +		dai_node = of_parse_phandle(node, "ti,mcpdm", 0); +		if (!dai_node) { +			dev_err(&pdev->dev, "McPDM node is not provided\n"); +			return -EINVAL; +		} +		abe_twl6040_dai_links[0].cpu_dai_name  = NULL; +		abe_twl6040_dai_links[0].cpu_of_node = dai_node; + +		dai_node = of_parse_phandle(node, "ti,dmic", 0); +		if (dai_node) { +			num_links = 2; +			abe_twl6040_dai_links[1].cpu_dai_name  = NULL; +			abe_twl6040_dai_links[1].cpu_of_node = dai_node; + +			priv->dmic_codec_dev = platform_device_register_simple( +						"dmic-codec", -1, NULL, 0); +			if (IS_ERR(priv->dmic_codec_dev)) { +				dev_err(&pdev->dev, +					"Can't instantiate dmic-codec\n"); +				return PTR_ERR(priv->dmic_codec_dev); +			} +		} else { +			num_links = 1; +		} + +		of_property_read_u32(node, "ti,jack-detection", +				     &priv->jack_detection); +		of_property_read_u32(node, "ti,mclk-freq", +				     &priv->mclk_freq); +		if (!priv->mclk_freq) { +			dev_err(&pdev->dev, "MCLK frequency not provided\n"); +			ret = -EINVAL; +			goto err_unregister; +		} + +		omap_abe_card.fully_routed = 1; +	} else if (pdata) { +		if (pdata->card_name) { +			card->name = pdata->card_name; +		} else { +			dev_err(&pdev->dev, "Card name is not provided\n"); +			return -ENODEV; +		} + +		if (pdata->has_dmic) +			num_links = 2; +		else +			num_links = 1; + +		priv->jack_detection = pdata->jack_detection; +		priv->mclk_freq = pdata->mclk_freq;  	} else { -		dev_err(&pdev->dev, "Card name is not provided\n"); +		dev_err(&pdev->dev, "Missing pdata\n");  		return -ENODEV;  	} -	priv->jack_detection = pdata->jack_detection; -	priv->mclk_freq = pdata->mclk_freq; -  	if (!priv->mclk_freq) {  		dev_err(&pdev->dev, "MCLK frequency missing\n"); -		return -ENODEV; +		ret = -ENODEV; +		goto err_unregister;  	} -	if (pdata->has_dmic) -		num_links = 2; -	else -		num_links = 1; -  	card->dai_link = abe_twl6040_dai_links;  	card->num_links = num_links;  	snd_soc_card_set_drvdata(card, priv);  	ret = snd_soc_register_card(card); -	if (ret) +	if (ret) {  		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",  			ret); +		goto err_unregister; +	} + +	return 0; + +err_unregister: +	if (!IS_ERR(priv->dmic_codec_dev)) +		platform_device_unregister(priv->dmic_codec_dev);  	return ret;  } @@ -319,17 +393,28 @@ static __devinit int omap_abe_probe(struct platform_device *pdev)  static int __devexit omap_abe_remove(struct platform_device *pdev)  {  	struct snd_soc_card *card = platform_get_drvdata(pdev); +	struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card);  	snd_soc_unregister_card(card); +	if (!IS_ERR(priv->dmic_codec_dev)) +		platform_device_unregister(priv->dmic_codec_dev); +  	return 0;  } +static const struct of_device_id omap_abe_of_match[] = { +	{.compatible = "ti,abe-twl6040", }, +	{ }, +}; +MODULE_DEVICE_TABLE(of, omap_abe_of_match); +  static struct platform_driver omap_abe_driver = {  	.driver = {  		.name = "omap-abe-twl6040",  		.owner = THIS_MODULE,  		.pm = &snd_soc_pm_ops, +		.of_match_table = omap_abe_of_match,  	},  	.probe = omap_abe_probe,  	.remove = __devexit_p(omap_abe_remove), diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c index 75f5dca0e8d..68f2cd1a920 100644 --- a/sound/soc/omap/omap-dmic.c +++ b/sound/soc/omap/omap-dmic.c @@ -33,7 +33,6 @@  #include <linux/slab.h>  #include <linux/pm_runtime.h>  #include <linux/of_device.h> -#include <plat/dma.h>  #include <sound/core.h>  #include <sound/pcm.h> @@ -63,8 +62,6 @@ struct omap_dmic {   */  static struct omap_pcm_dma_data omap_dmic_dai_dma_params = {  	.name		= "DMIC capture", -	.data_type	= OMAP_DMA_DATA_TYPE_S32, -	.sync_mode	= OMAP_DMA_SYNC_PACKET,  };  static inline void omap_dmic_write(struct omap_dmic *dmic, u16 reg, u32 val) @@ -121,6 +118,7 @@ static int omap_dmic_dai_startup(struct snd_pcm_substream *substream,  	mutex_unlock(&dmic->mutex); +	snd_soc_dai_set_dma_data(dai, substream, &omap_dmic_dai_dma_params);  	return ret;  } @@ -205,6 +203,7 @@ static int omap_dmic_dai_hw_params(struct snd_pcm_substream *substream,  				    struct snd_soc_dai *dai)  {  	struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); +	struct omap_pcm_dma_data *dma_data;  	int channels;  	dmic->clk_div = omap_dmic_select_divider(dmic, params_rate(params)); @@ -230,8 +229,8 @@ static int omap_dmic_dai_hw_params(struct snd_pcm_substream *substream,  	}  	/* packet size is threshold * channels */ -	omap_dmic_dai_dma_params.packet_size = dmic->threshold * channels; -	snd_soc_dai_set_dma_data(dai, substream, &omap_dmic_dai_dma_params); +	dma_data = snd_soc_dai_get_dma_data(dai, substream); +	dma_data->packet_size = dmic->threshold * channels;  	return 0;  } diff --git a/sound/soc/omap/omap-hdmi.c b/sound/soc/omap/omap-hdmi.c index a08245d9203..f59c69fb400 100644 --- a/sound/soc/omap/omap-hdmi.c +++ b/sound/soc/omap/omap-hdmi.c @@ -34,7 +34,6 @@  #include <sound/asoundef.h>  #include <video/omapdss.h> -#include <plat/dma.h>  #include "omap-pcm.h"  #include "omap-hdmi.h" @@ -68,6 +67,9 @@ static int omap_hdmi_dai_startup(struct snd_pcm_substream *substream,  		dev_err(dai->dev, "audio not supported\n");  		return -ENODEV;  	} + +	snd_soc_dai_set_dma_data(dai, substream, &priv->dma_params); +  	return 0;  } @@ -86,24 +88,24 @@ static int omap_hdmi_dai_hw_params(struct snd_pcm_substream *substream,  	struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);  	struct snd_aes_iec958 *iec = &priv->iec;  	struct snd_cea_861_aud_if *cea = &priv->cea; +	struct omap_pcm_dma_data *dma_data;  	int err = 0; +	dma_data = snd_soc_dai_get_dma_data(dai, substream); +  	switch (params_format(params)) {  	case SNDRV_PCM_FORMAT_S16_LE: -		priv->dma_params.packet_size = 16; +		dma_data->packet_size = 16;  		break;  	case SNDRV_PCM_FORMAT_S24_LE: -		priv->dma_params.packet_size = 32; +		dma_data->packet_size = 32;  		break;  	default:  		dev_err(dai->dev, "format not supported!\n");  		return -EINVAL;  	} -	priv->dma_params.data_type = OMAP_DMA_DATA_TYPE_S32; - -	snd_soc_dai_set_dma_data(dai, substream, -				 &priv->dma_params); +	dma_data->data_type = 32;  	/*  	 * fill the IEC-60958 channel status word @@ -290,7 +292,6 @@ static __devinit int omap_hdmi_probe(struct platform_device *pdev)  	hdmi_data->dma_params.dma_req =  hdmi_rsrc->start;  	hdmi_data->dma_params.name = "HDMI playback"; -	hdmi_data->dma_params.sync_mode = OMAP_DMA_SYNC_PACKET;  	/*  	 * TODO: We assume that there is only one DSS HDMI device. Future diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 1b18627763c..a6ee1574785 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -26,6 +26,8 @@  #include <linux/module.h>  #include <linux/device.h>  #include <linux/pm_runtime.h> +#include <linux/of.h> +#include <linux/of_device.h>  #include <sound/core.h>  #include <sound/pcm.h>  #include <sound/pcm_params.h> @@ -33,7 +35,6 @@  #include <sound/soc.h>  #include <plat/cpu.h> -#include <plat/dma.h>  #include <linux/platform_data/asoc-ti-mcbsp.h>  #include "mcbsp.h"  #include "omap-mcbsp.h" @@ -80,9 +81,6 @@ static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)  	 */  	if (dma_data->packet_size)  		words = dma_data->packet_size; -	else if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) -		words = snd_pcm_lib_period_bytes(substream) / -						(mcbsp->wlen / 8);  	else  		words = 1; @@ -154,6 +152,9 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,  					   SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2);  	} +	snd_soc_dai_set_dma_data(cpu_dai, substream, +				 &mcbsp->dma_data[substream->stream]); +  	return err;  } @@ -227,20 +228,18 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,  	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);  	struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;  	struct omap_pcm_dma_data *dma_data; -	int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT; +	int wlen, channels, wpf;  	int pkt_size = 0;  	unsigned int format, div, framesize, master; -	dma_data = &mcbsp->dma_data[substream->stream]; +	dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream);  	channels = params_channels(params);  	switch (params_format(params)) {  	case SNDRV_PCM_FORMAT_S16_LE: -		dma_data->data_type = OMAP_DMA_DATA_TYPE_S16;  		wlen = 16;  		break;  	case SNDRV_PCM_FORMAT_S32_LE: -		dma_data->data_type = OMAP_DMA_DATA_TYPE_S32;  		wlen = 32;  		break;  	default: @@ -250,6 +249,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,  		dma_data->set_threshold = omap_mcbsp_set_threshold;  		if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) {  			int period_words, max_thrsh; +			int divider = 0;  			period_words = params_period_bytes(params) / (wlen / 8);  			if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -257,46 +257,30 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,  			else  				max_thrsh = mcbsp->max_rx_thres;  			/* -			 * If the period contains less or equal number of words, -			 * we are using the original threshold mode setup: -			 * McBSP threshold = sDMA frame size = period_size -			 * Otherwise we switch to sDMA packet mode: -			 * McBSP threshold = sDMA packet size -			 * sDMA frame size = period size +			 * Use sDMA packet mode if McBSP is in threshold mode: +			 * If period words less than the FIFO size the packet +			 * size is set to the number of period words, otherwise +			 * Look for the biggest threshold value which divides +			 * the period size evenly.  			 */ -			if (period_words > max_thrsh) { -				int divider = 0; - -				/* -				 * Look for the biggest threshold value, which -				 * divides the period size evenly. -				 */ -				divider = period_words / max_thrsh; -				if (period_words % max_thrsh) -					divider++; -				while (period_words % divider && -					divider < period_words) -					divider++; -				if (divider == period_words) -					return -EINVAL; +			divider = period_words / max_thrsh; +			if (period_words % max_thrsh) +				divider++; +			while (period_words % divider && +				divider < period_words) +				divider++; +			if (divider == period_words) +				return -EINVAL; -				pkt_size = period_words / divider; -				sync_mode = OMAP_DMA_SYNC_PACKET; -			} else { -				sync_mode = OMAP_DMA_SYNC_FRAME; -			} +			pkt_size = period_words / divider;  		} else if (channels > 1) {  			/* Use packet mode for non mono streams */  			pkt_size = channels; -			sync_mode = OMAP_DMA_SYNC_PACKET;  		}  	} -	dma_data->sync_mode = sync_mode;  	dma_data->packet_size = pkt_size; -	snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data); -  	if (mcbsp->configured) {  		/* McBSP already configured by another stream */  		return 0; @@ -399,12 +383,14 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,  	/* Generic McBSP register settings */  	regs->spcr2	|= XINTM(3) | FREE;  	regs->spcr1	|= RINTM(3); -	/* RFIG and XFIG are not defined in 34xx */ -	if (!cpu_is_omap34xx() && !cpu_is_omap44xx()) { +	/* RFIG and XFIG are not defined in 2430 and on OMAP3+ */ +	if (!mcbsp->pdata->has_ccr) {  		regs->rcr2	|= RFIG;  		regs->xcr2	|= XFIG;  	} -	if (cpu_is_omap2430() || cpu_is_omap34xx() || cpu_is_omap44xx()) { + +	/* Configure XCCR/RCCR only for revisions which have ccr registers */ +	if (mcbsp->pdata->has_ccr) {  		regs->xccr = DXENDLY(1) | XDMAEN | XDISABLE;  		regs->rccr = RFULL_CYCLE | RDMAEN | RDISABLE;  	} @@ -517,21 +503,9 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,  			return -EBUSY;  	} -	if (clk_id == OMAP_MCBSP_SYSCLK_CLK || -	    clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK || -	    clk_id == OMAP_MCBSP_SYSCLK_CLKS_EXT || -	    clk_id == OMAP_MCBSP_SYSCLK_CLKX_EXT || -	    clk_id == OMAP_MCBSP_SYSCLK_CLKR_EXT) { -		mcbsp->in_freq = freq; -		regs->srgr2	&= ~CLKSM; -		regs->pcr0	&= ~SCLKME; -	} else if (cpu_class_is_omap1()) { -		/* -		 * McBSP CLKR/FSR signal muxing functions are only available on -		 * OMAP2 or newer versions -		 */ -		return -EINVAL; -	} +	mcbsp->in_freq = freq; +	regs->srgr2 &= ~CLKSM; +	regs->pcr0 &= ~SCLKME;  	switch (clk_id) {  	case OMAP_MCBSP_SYSCLK_CLK: @@ -559,20 +533,6 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,  	case OMAP_MCBSP_SYSCLK_CLKR_EXT:  		regs->pcr0	|= SCLKME;  		break; - - -	case OMAP_MCBSP_CLKR_SRC_CLKR: -		err = omap_mcbsp_6pin_src_mux(mcbsp, CLKR_SRC_CLKR); -		break; -	case OMAP_MCBSP_CLKR_SRC_CLKX: -		err = omap_mcbsp_6pin_src_mux(mcbsp, CLKR_SRC_CLKX); -		break; -	case OMAP_MCBSP_FSR_SRC_FSR: -		err = omap_mcbsp_6pin_src_mux(mcbsp, FSR_SRC_FSR); -		break; -	case OMAP_MCBSP_FSR_SRC_FSX: -		err = omap_mcbsp_6pin_src_mux(mcbsp, FSR_SRC_FSX); -		break;  	default:  		err = -ENODEV;  	} @@ -642,9 +602,9 @@ static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,  	return 0;  } -#define OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(channel)			\ +#define OMAP_MCBSP_ST_CHANNEL_VOLUME(channel)				\  static int								\ -omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc,	\ +omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc,		\  					struct snd_ctl_elem_value *uc)	\  {									\  	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc);		\ @@ -660,11 +620,10 @@ omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc,	\  									\  	/* OMAP McBSP implementation uses index values 0..4 */		\  	return omap_st_set_chgain(mcbsp, channel, val);			\ -} - -#define OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(channel)			\ +}									\ +									\  static int								\ -omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc,	\ +omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc,		\  					struct snd_ctl_elem_value *uc)	\  {									\  	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc);		\ @@ -678,10 +637,8 @@ omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc,	\  	return 0;							\  } -OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(0) -OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(1) -OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(0) -OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(1) +OMAP_MCBSP_ST_CHANNEL_VOLUME(0) +OMAP_MCBSP_ST_CHANNEL_VOLUME(1)  static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol,  				struct snd_ctl_elem_value *ucontrol) @@ -711,41 +668,34 @@ static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol,  	return 0;  } -static const struct snd_kcontrol_new omap_mcbsp2_st_controls[] = { -	SOC_SINGLE_EXT("McBSP2 Sidetone Switch", 1, 0, 1, 0, -			omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode), -	OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP2 Sidetone Channel 0 Volume", -				      -32768, 32767, -				      omap_mcbsp_get_st_ch0_volume, -				      omap_mcbsp_set_st_ch0_volume), -	OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP2 Sidetone Channel 1 Volume", -				      -32768, 32767, -				      omap_mcbsp_get_st_ch1_volume, -				      omap_mcbsp_set_st_ch1_volume), -}; +#define OMAP_MCBSP_ST_CONTROLS(port)					  \ +static const struct snd_kcontrol_new omap_mcbsp##port##_st_controls[] = { \ +SOC_SINGLE_EXT("McBSP" #port " Sidetone Switch", 1, 0, 1, 0,		  \ +	       omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode),		  \ +OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 0 Volume", \ +			      -32768, 32767,				  \ +			      omap_mcbsp_get_st_ch0_volume,		  \ +			      omap_mcbsp_set_st_ch0_volume),		  \ +OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 1 Volume", \ +			      -32768, 32767,				  \ +			      omap_mcbsp_get_st_ch1_volume,		  \ +			      omap_mcbsp_set_st_ch1_volume),		  \ +} -static const struct snd_kcontrol_new omap_mcbsp3_st_controls[] = { -	SOC_SINGLE_EXT("McBSP3 Sidetone Switch", 2, 0, 1, 0, -			omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode), -	OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP3 Sidetone Channel 0 Volume", -				      -32768, 32767, -				      omap_mcbsp_get_st_ch0_volume, -				      omap_mcbsp_set_st_ch0_volume), -	OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP3 Sidetone Channel 1 Volume", -				      -32768, 32767, -				      omap_mcbsp_get_st_ch1_volume, -				      omap_mcbsp_set_st_ch1_volume), -}; +OMAP_MCBSP_ST_CONTROLS(2); +OMAP_MCBSP_ST_CONTROLS(3);  int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd)  {  	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;  	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); -	if (!mcbsp->st_data) -		return -ENODEV; +	if (!mcbsp->st_data) { +		dev_warn(mcbsp->dev, "No sidetone data for port\n"); +		return 0; +	} -	switch (cpu_dai->id) { +	switch (mcbsp->id) {  	case 2: /* McBSP 2 */  		return snd_soc_add_dai_controls(cpu_dai,  					omap_mcbsp2_st_controls, @@ -762,13 +712,74 @@ int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd)  }  EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls); +static struct omap_mcbsp_platform_data omap2420_pdata = { +	.reg_step = 4, +	.reg_size = 2, +}; + +static struct omap_mcbsp_platform_data omap2430_pdata = { +	.reg_step = 4, +	.reg_size = 4, +	.has_ccr = true, +}; + +static struct omap_mcbsp_platform_data omap3_pdata = { +	.reg_step = 4, +	.reg_size = 4, +	.has_ccr = true, +	.has_wakeup = true, +}; + +static struct omap_mcbsp_platform_data omap4_pdata = { +	.reg_step = 4, +	.reg_size = 4, +	.has_ccr = true, +	.has_wakeup = true, +}; + +static const struct of_device_id omap_mcbsp_of_match[] = { +	{ +		.compatible = "ti,omap2420-mcbsp", +		.data = &omap2420_pdata, +	}, +	{ +		.compatible = "ti,omap2430-mcbsp", +		.data = &omap2430_pdata, +	}, +	{ +		.compatible = "ti,omap3-mcbsp", +		.data = &omap3_pdata, +	}, +	{ +		.compatible = "ti,omap4-mcbsp", +		.data = &omap4_pdata, +	}, +	{ }, +}; +MODULE_DEVICE_TABLE(of, omap_mcbsp_of_match); +  static __devinit int asoc_mcbsp_probe(struct platform_device *pdev)  {  	struct omap_mcbsp_platform_data *pdata = dev_get_platdata(&pdev->dev);  	struct omap_mcbsp *mcbsp; +	const struct of_device_id *match;  	int ret; -	if (!pdata) { +	match = of_match_device(omap_mcbsp_of_match, &pdev->dev); +	if (match) { +		struct device_node *node = pdev->dev.of_node; +		int buffer_size; + +		pdata = devm_kzalloc(&pdev->dev, +				     sizeof(struct omap_mcbsp_platform_data), +				     GFP_KERNEL); +		if (!pdata) +			return -ENOMEM; + +		memcpy(pdata, match->data, sizeof(*pdata)); +		if (!of_property_read_u32(node, "ti,buffer-size", &buffer_size)) +			pdata->buffer_size = buffer_size; +	} else if (!pdata) {  		dev_err(&pdev->dev, "missing platform data.\n");  		return -EINVAL;  	} @@ -810,6 +821,7 @@ static struct platform_driver asoc_mcbsp_driver = {  	.driver = {  			.name = "omap-mcbsp",  			.owner = THIS_MODULE, +			.of_match_table = omap_mcbsp_of_match,  	},  	.probe = asoc_mcbsp_probe, diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h index f877b16f19c..ba8386a0d8d 100644 --- a/sound/soc/omap/omap-mcbsp.h +++ b/sound/soc/omap/omap-mcbsp.h @@ -32,10 +32,6 @@ enum omap_mcbsp_clksrg_clk {  	OMAP_MCBSP_SYSCLK_CLK,		/* Internal ICLK */  	OMAP_MCBSP_SYSCLK_CLKX_EXT,	/* External CLKX pin */  	OMAP_MCBSP_SYSCLK_CLKR_EXT,	/* External CLKR pin */ -	OMAP_MCBSP_CLKR_SRC_CLKR,	/* CLKR from CLKR pin */ -	OMAP_MCBSP_CLKR_SRC_CLKX,	/* CLKR from CLKX pin */ -	OMAP_MCBSP_FSR_SRC_FSR,		/* FSR from FSR pin */ -	OMAP_MCBSP_FSR_SRC_FSX,		/* FSR from FSX pin */  };  /* McBSP dividers */ @@ -43,22 +39,6 @@ enum omap_mcbsp_div {  	OMAP_MCBSP_CLKGDV,		/* Sample rate generator divider */  }; -#if defined(CONFIG_SOC_OMAP2420) -#define NUM_LINKS	2 -#endif -#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX) -#undef  NUM_LINKS -#define NUM_LINKS	3 -#endif -#if defined(CONFIG_ARCH_OMAP4) -#undef  NUM_LINKS -#define NUM_LINKS	4 -#endif -#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_SOC_OMAP2430) -#undef  NUM_LINKS -#define NUM_LINKS	5 -#endif -  int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd);  #endif diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c index ea053c3d2ab..c02b001ee4b 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c @@ -40,7 +40,6 @@  #include <sound/pcm_params.h>  #include <sound/soc.h> -#include <plat/dma.h>  #include <plat/omap_hwmod.h>  #include "omap-mcpdm.h"  #include "omap-pcm.h" @@ -73,17 +72,9 @@ struct omap_mcpdm {  static struct omap_pcm_dma_data omap_mcpdm_dai_dma_params[] = {  	{  		.name = "Audio playback", -		.dma_req = OMAP44XX_DMA_MCPDM_DL, -		.data_type = OMAP_DMA_DATA_TYPE_S32, -		.sync_mode = OMAP_DMA_SYNC_PACKET, -		.port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_REG_DN_DATA,  	},  	{  		.name = "Audio capture", -		.dma_req = OMAP44XX_DMA_MCPDM_UP, -		.data_type = OMAP_DMA_DATA_TYPE_S32, -		.sync_mode = OMAP_DMA_SYNC_PACKET, -		.port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_REG_UP_DATA,  	},  }; @@ -278,9 +269,11 @@ static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,  		}  		omap_mcpdm_open_streams(mcpdm);  	} -  	mutex_unlock(&mcpdm->mutex); +	snd_soc_dai_set_dma_data(dai, substream, +				 &omap_mcpdm_dai_dma_params[substream->stream]); +  	return 0;  } @@ -335,7 +328,7 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,  		return -EINVAL;  	} -	dma_data = &omap_mcpdm_dai_dma_params[stream]; +	dma_data = snd_soc_dai_get_dma_data(dai, substream);  	/* Configure McPDM channels, and DMA packet size */  	if (stream == SNDRV_PCM_STREAM_PLAYBACK) { @@ -347,8 +340,6 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,  		dma_data->packet_size = mcpdm->up_threshold * channels;  	} -	snd_soc_dai_set_dma_data(dai, substream, dma_data); -  	return 0;  } @@ -447,9 +438,8 @@ static __devinit int asoc_mcpdm_probe(struct platform_device *pdev)  {  	struct omap_mcpdm *mcpdm;  	struct resource *res; -	int ret = 0; -	mcpdm = kzalloc(sizeof(struct omap_mcpdm), GFP_KERNEL); +	mcpdm = devm_kzalloc(&pdev->dev, sizeof(struct omap_mcpdm), GFP_KERNEL);  	if (!mcpdm)  		return -ENOMEM; @@ -457,56 +447,54 @@ static __devinit int asoc_mcpdm_probe(struct platform_device *pdev)  	mutex_init(&mcpdm->mutex); +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma"); +	if (res == NULL) +		return -ENOMEM; + +	omap_mcpdm_dai_dma_params[0].port_addr = res->start + MCPDM_REG_DN_DATA; +	omap_mcpdm_dai_dma_params[1].port_addr = res->start + MCPDM_REG_UP_DATA; +  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (res == NULL) { -		dev_err(&pdev->dev, "no resource\n"); -		goto err_res; -	} +	if (res == NULL) +		return -ENOMEM; -	if (!request_mem_region(res->start, resource_size(res), "McPDM")) { -		ret = -EBUSY; -		goto err_res; -	} +	res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "dn_link"); +	if (!res) +		return -ENODEV; -	mcpdm->io_base = ioremap(res->start, resource_size(res)); -	if (!mcpdm->io_base) { -		ret = -ENOMEM; -		goto err_iomap; -	} +	omap_mcpdm_dai_dma_params[0].dma_req = res->start; + +	res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "up_link"); +	if (!res) +		return -ENODEV; + +	omap_mcpdm_dai_dma_params[1].dma_req = res->start; + +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); +	if (res == NULL) +		return -ENOMEM; + +	if (!devm_request_mem_region(&pdev->dev, res->start, +				     resource_size(res), "McPDM")) +		return -EBUSY; + +	mcpdm->io_base = devm_ioremap(&pdev->dev, res->start, +				      resource_size(res)); +	if (!mcpdm->io_base) +		return -ENOMEM;  	mcpdm->irq = platform_get_irq(pdev, 0); -	if (mcpdm->irq < 0) { -		ret = mcpdm->irq; -		goto err_irq; -	} +	if (mcpdm->irq < 0) +		return mcpdm->irq;  	mcpdm->dev = &pdev->dev; -	ret = snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai); -	if (!ret) -		return 0; - -err_irq: -	iounmap(mcpdm->io_base); -err_iomap: -	release_mem_region(res->start, resource_size(res)); -err_res: -	kfree(mcpdm); -	return ret; +	return snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai);  }  static int __devexit asoc_mcpdm_remove(struct platform_device *pdev)  { -	struct omap_mcpdm *mcpdm = platform_get_drvdata(pdev); -	struct resource *res; -  	snd_soc_unregister_dai(&pdev->dev); - -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	iounmap(mcpdm->io_base); -	release_mem_region(res->start, resource_size(res)); - -	kfree(mcpdm);  	return 0;  } diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index b3099417988..340874ebf9a 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -25,13 +25,14 @@  #include <linux/dma-mapping.h>  #include <linux/slab.h>  #include <linux/module.h> +#include <linux/omap-dma.h>  #include <sound/core.h>  #include <sound/pcm.h>  #include <sound/pcm_params.h> +#include <sound/dmaengine_pcm.h>  #include <sound/soc.h>  #include <plat/cpu.h> -#include <plat/dma.h>  #include "omap-pcm.h"  static const struct snd_pcm_hardware omap_pcm_hardware = { @@ -50,61 +51,34 @@ static const struct snd_pcm_hardware omap_pcm_hardware = {  	.buffer_bytes_max	= 128 * 1024,  }; -struct omap_runtime_data { -	spinlock_t			lock; -	struct omap_pcm_dma_data	*dma_data; -	int				dma_ch; -	int				period_index; -}; - -static void omap_pcm_dma_irq(int ch, u16 stat, void *data) +static int omap_pcm_get_dma_buswidth(int num_bits)  { -	struct snd_pcm_substream *substream = data; -	struct snd_pcm_runtime *runtime = substream->runtime; -	struct omap_runtime_data *prtd = runtime->private_data; -	unsigned long flags; +	int buswidth; -	if ((cpu_is_omap1510())) { -		/* -		 * OMAP1510 doesn't fully support DMA progress counter -		 * and there is no software emulation implemented yet, -		 * so have to maintain our own progress counters -		 * that can be used by omap_pcm_pointer() instead. -		 */ -		spin_lock_irqsave(&prtd->lock, flags); -		if ((stat == OMAP_DMA_LAST_IRQ) && -				(prtd->period_index == runtime->periods - 1)) { -			/* we are in sync, do nothing */ -			spin_unlock_irqrestore(&prtd->lock, flags); -			return; -		} -		if (prtd->period_index >= 0) { -			if (stat & OMAP_DMA_BLOCK_IRQ) { -				/* end of buffer reached, loop back */ -				prtd->period_index = 0; -			} else if (stat & OMAP_DMA_LAST_IRQ) { -				/* update the counter for the last period */ -				prtd->period_index = runtime->periods - 1; -			} else if (++prtd->period_index >= runtime->periods) { -				/* end of buffer missed? loop back */ -				prtd->period_index = 0; -			} -		} -		spin_unlock_irqrestore(&prtd->lock, flags); +	switch (num_bits) { +	case 16: +		buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; +		break; +	case 32: +		buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; +		break; +	default: +		buswidth = -EINVAL; +		break;  	} - -	snd_pcm_period_elapsed(substream); +	return buswidth;  } +  /* this may get called several times by oss emulation */  static int omap_pcm_hw_params(struct snd_pcm_substream *substream,  			      struct snd_pcm_hw_params *params)  {  	struct snd_pcm_runtime *runtime = substream->runtime;  	struct snd_soc_pcm_runtime *rtd = substream->private_data; -	struct omap_runtime_data *prtd = runtime->private_data;  	struct omap_pcm_dma_data *dma_data; - +	struct dma_slave_config config; +	struct dma_chan *chan;  	int err = 0;  	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); @@ -117,162 +91,78 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,  	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);  	runtime->dma_bytes = params_buffer_bytes(params); -	if (prtd->dma_data) -		return 0; -	prtd->dma_data = dma_data; -	err = omap_request_dma(dma_data->dma_req, dma_data->name, -			       omap_pcm_dma_irq, substream, &prtd->dma_ch); -	if (!err) { -		/* -		 * Link channel with itself so DMA doesn't need any -		 * reprogramming while looping the buffer -		 */ -		omap_dma_link_lch(prtd->dma_ch, prtd->dma_ch); -	} +	chan = snd_dmaengine_pcm_get_chan(substream); +	if (!chan) +		return -EINVAL; -	return err; -} +	/* fills in addr_width and direction */ +	err = snd_hwparams_to_dma_slave_config(substream, params, &config); +	if (err) +		return err; -static int omap_pcm_hw_free(struct snd_pcm_substream *substream) -{ -	struct snd_pcm_runtime *runtime = substream->runtime; -	struct omap_runtime_data *prtd = runtime->private_data; - -	if (prtd->dma_data == NULL) -		return 0; +	/* Override the *_dma addr_width if requested by the DAI driver */ +	if (dma_data->data_type) { +		int buswidth = omap_pcm_get_dma_buswidth(dma_data->data_type); -	omap_dma_unlink_lch(prtd->dma_ch, prtd->dma_ch); -	omap_free_dma(prtd->dma_ch); -	prtd->dma_data = NULL; +		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) +			config.dst_addr_width = buswidth; +		else +			config.src_addr_width = buswidth; +	} -	snd_pcm_set_runtime_buffer(substream, NULL); +	config.src_addr = dma_data->port_addr; +	config.dst_addr = dma_data->port_addr; +	config.src_maxburst = dma_data->packet_size; +	config.dst_maxburst = dma_data->packet_size; -	return 0; +	return dmaengine_slave_config(chan, &config);  } -static int omap_pcm_prepare(struct snd_pcm_substream *substream) +static int omap_pcm_hw_free(struct snd_pcm_substream *substream)  { -	struct snd_pcm_runtime *runtime = substream->runtime; -	struct omap_runtime_data *prtd = runtime->private_data; -	struct omap_pcm_dma_data *dma_data = prtd->dma_data; -	struct omap_dma_channel_params dma_params; -	int bytes; - -	/* 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)); -	dma_params.data_type			= dma_data->data_type; -	dma_params.trigger			= dma_data->dma_req; -	dma_params.sync_mode			= dma_data->sync_mode; -	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -		dma_params.src_amode		= OMAP_DMA_AMODE_POST_INC; -		dma_params.dst_amode		= OMAP_DMA_AMODE_CONSTANT; -		dma_params.src_or_dst_synch	= OMAP_DMA_DST_SYNC; -		dma_params.src_start		= runtime->dma_addr; -		dma_params.dst_start		= dma_data->port_addr; -		dma_params.dst_port		= OMAP_DMA_PORT_MPUI; -		dma_params.dst_fi		= dma_data->packet_size; -	} else { -		dma_params.src_amode		= OMAP_DMA_AMODE_CONSTANT; -		dma_params.dst_amode		= OMAP_DMA_AMODE_POST_INC; -		dma_params.src_or_dst_synch	= OMAP_DMA_SRC_SYNC; -		dma_params.src_start		= dma_data->port_addr; -		dma_params.dst_start		= runtime->dma_addr; -		dma_params.src_port		= OMAP_DMA_PORT_MPUI; -		dma_params.src_fi		= dma_data->packet_size; -	} -	/* -	 * Set DMA transfer frame size equal to ALSA period size and frame -	 * count as no. of ALSA periods. Then with DMA frame interrupt enabled, -	 * we can transfer the whole ALSA buffer with single DMA transfer but -	 * still can get an interrupt at each period bounary -	 */ -	bytes = snd_pcm_lib_period_bytes(substream); -	dma_params.elem_count	= bytes >> dma_data->data_type; -	dma_params.frame_count	= runtime->periods; -	omap_set_dma_params(prtd->dma_ch, &dma_params); - -	if ((cpu_is_omap1510())) -		omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ | -			      OMAP_DMA_LAST_IRQ | OMAP_DMA_BLOCK_IRQ); -	else if (!substream->runtime->no_period_wakeup) -		omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ); -	else { -		/* -		 * No period wakeup: -		 * we need to disable BLOCK_IRQ, which is enabled by the omap -		 * dma core at request dma time. -		 */ -		omap_disable_dma_irq(prtd->dma_ch, OMAP_DMA_BLOCK_IRQ); -	} - -	if (!(cpu_class_is_omap1())) { -		omap_set_dma_src_burst_mode(prtd->dma_ch, -						OMAP_DMA_DATA_BURST_16); -		omap_set_dma_dest_burst_mode(prtd->dma_ch, -						OMAP_DMA_DATA_BURST_16); -	} - +	snd_pcm_set_runtime_buffer(substream, NULL);  	return 0;  }  static int omap_pcm_trigger(struct snd_pcm_substream *substream, int cmd)  { -	struct snd_pcm_runtime *runtime = substream->runtime; -	struct omap_runtime_data *prtd = runtime->private_data; -	struct omap_pcm_dma_data *dma_data = prtd->dma_data; -	unsigned long flags; +	struct snd_soc_pcm_runtime *rtd = substream->private_data; +	struct omap_pcm_dma_data *dma_data;  	int ret = 0; -	spin_lock_irqsave(&prtd->lock, flags); +	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); +  	switch (cmd) {  	case SNDRV_PCM_TRIGGER_START:  	case SNDRV_PCM_TRIGGER_RESUME:  	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -		prtd->period_index = 0;  		/* Configure McBSP internal buffer usage */  		if (dma_data->set_threshold)  			dma_data->set_threshold(substream); - -		omap_start_dma(prtd->dma_ch);  		break;  	case SNDRV_PCM_TRIGGER_STOP:  	case SNDRV_PCM_TRIGGER_SUSPEND:  	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: -		prtd->period_index = -1; -		omap_stop_dma(prtd->dma_ch);  		break;  	default:  		ret = -EINVAL;  	} -	spin_unlock_irqrestore(&prtd->lock, flags); + +	if (ret == 0) +		ret = snd_dmaengine_pcm_trigger(substream, cmd);  	return ret;  }  static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream)  { -	struct snd_pcm_runtime *runtime = substream->runtime; -	struct omap_runtime_data *prtd = runtime->private_data; -	dma_addr_t ptr;  	snd_pcm_uframes_t offset; -	if (cpu_is_omap1510()) { -		offset = prtd->period_index * runtime->period_size; -	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { -		ptr = omap_get_dma_dst_pos(prtd->dma_ch); -		offset = bytes_to_frames(runtime, ptr - runtime->dma_addr); -	} else { -		ptr = omap_get_dma_src_pos(prtd->dma_ch); -		offset = bytes_to_frames(runtime, ptr - runtime->dma_addr); -	} - -	if (offset >= runtime->buffer_size) -		offset = 0; +	if (cpu_is_omap1510()) +		offset = snd_dmaengine_pcm_pointer_no_residue(substream); +	else +		offset = snd_dmaengine_pcm_pointer(substream);  	return offset;  } @@ -280,7 +170,8 @@ static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream)  static int omap_pcm_open(struct snd_pcm_substream *substream)  {  	struct snd_pcm_runtime *runtime = substream->runtime; -	struct omap_runtime_data *prtd; +	struct snd_soc_pcm_runtime *rtd = substream->private_data; +	struct omap_pcm_dma_data *dma_data;  	int ret;  	snd_soc_set_runtime_hwparams(substream, &omap_pcm_hardware); @@ -289,25 +180,17 @@ static int omap_pcm_open(struct snd_pcm_substream *substream)  	ret = snd_pcm_hw_constraint_integer(runtime,  					    SNDRV_PCM_HW_PARAM_PERIODS);  	if (ret < 0) -		goto out; +		return ret; -	prtd = kzalloc(sizeof(*prtd), GFP_KERNEL); -	if (prtd == NULL) { -		ret = -ENOMEM; -		goto out; -	} -	spin_lock_init(&prtd->lock); -	runtime->private_data = prtd; - -out: +	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); +	ret = snd_dmaengine_pcm_open(substream, omap_dma_filter_fn, +				     &dma_data->dma_req);  	return ret;  }  static int omap_pcm_close(struct snd_pcm_substream *substream)  { -	struct snd_pcm_runtime *runtime = substream->runtime; - -	kfree(runtime->private_data); +	snd_dmaengine_pcm_close(substream);  	return 0;  } @@ -328,7 +211,6 @@ static struct snd_pcm_ops omap_pcm_ops = {  	.ioctl		= snd_pcm_lib_ioctl,  	.hw_params	= omap_pcm_hw_params,  	.hw_free	= omap_pcm_hw_free, -	.prepare	= omap_pcm_prepare,  	.trigger	= omap_pcm_trigger,  	.pointer	= omap_pcm_pointer,  	.mmap		= omap_pcm_mmap, diff --git a/sound/soc/omap/omap-pcm.h b/sound/soc/omap/omap-pcm.h index b92248cbd47..cabe74c4068 100644 --- a/sound/soc/omap/omap-pcm.h +++ b/sound/soc/omap/omap-pcm.h @@ -32,8 +32,8 @@ struct omap_pcm_dma_data {  	int		dma_req;	/* DMA request line */  	unsigned long	port_addr;	/* transmit/receive register */  	void (*set_threshold)(struct snd_pcm_substream *substream); -	int		data_type;	/* data type 8,16,32 */ -	int		sync_mode;	/* DMA sync mode */ +	int		data_type;	/* 8, 16, 32 (bits) or 0 to let omap-pcm +					 * to decide the sDMA data type */  	int		packet_size;	/* packet size only in PACKET mode */  }; diff --git a/sound/soc/omap/omap-twl4030.c b/sound/soc/omap/omap-twl4030.c new file mode 100644 index 00000000000..3b97b87971f --- /dev/null +++ b/sound/soc/omap/omap-twl4030.c @@ -0,0 +1,188 @@ +/* + * omap-twl4030.c  --  SoC audio for TI SoC based boards with twl4030 codec + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com + * All rights reserved. + * + * Author: Peter Ujfalusi <peter.ujfalusi@ti.com> + * + * This driver replaces the following machine drivers: + * omap3beagle (Author: Steve Sakoman <steve@sakoman.com>) + * omap3evm (Author: Anuj Aggarwal <anuj.aggarwal@ti.com>) + * overo (Author: Steve Sakoman <steve@sakoman.com>) + * igep0020 (Author: Enric Balletbo i Serra <eballetbo@iseebcn.com>) + * + * 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 <linux/platform_device.h> +#include <linux/platform_data/omap-twl4030.h> +#include <linux/module.h> +#include <linux/of.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/soc.h> + +#include "omap-mcbsp.h" +#include "omap-pcm.h" + +static int omap_twl4030_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->codec_dai; +	struct snd_soc_dai *cpu_dai = rtd->cpu_dai; +	struct snd_soc_codec *codec = rtd->codec; +	struct snd_soc_card *card = codec->card; +	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); +	if (ret < 0) { +		dev_err(card->dev, "can't set codec DAI configuration\n"); +		return ret; +	} + +	/* Set cpu DAI configuration */ +	ret = snd_soc_dai_set_fmt(cpu_dai, fmt); +	if (ret < 0) { +		dev_err(card->dev, "can't set cpu DAI configuration\n"); +		return ret; +	} + +	return 0; +} + +static struct snd_soc_ops omap_twl4030_ops = { +	.hw_params = omap_twl4030_hw_params, +}; + +/* Digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link omap_twl4030_dai_links[] = { +	{ +		.name = "TWL4030", +		.stream_name = "TWL4030", +		.cpu_dai_name = "omap-mcbsp.2", +		.codec_dai_name = "twl4030-hifi", +		.platform_name = "omap-pcm-audio", +		.codec_name = "twl4030-codec", +		.ops = &omap_twl4030_ops, +	}, +}; + +/* Audio machine driver */ +static struct snd_soc_card omap_twl4030_card = { +	.owner = THIS_MODULE, +	.dai_link = omap_twl4030_dai_links, +	.num_links = ARRAY_SIZE(omap_twl4030_dai_links), +}; + +static __devinit int omap_twl4030_probe(struct platform_device *pdev) +{ +	struct omap_tw4030_pdata *pdata = dev_get_platdata(&pdev->dev); +	struct device_node *node = pdev->dev.of_node; +	struct snd_soc_card *card = &omap_twl4030_card; +	int ret = 0; + +	card->dev = &pdev->dev; + +	if (node) { +		struct device_node *dai_node; + +		if (snd_soc_of_parse_card_name(card, "ti,model")) { +			dev_err(&pdev->dev, "Card name is not provided\n"); +			return -ENODEV; +		} + +		dai_node = of_parse_phandle(node, "ti,mcbsp", 0); +		if (!dai_node) { +			dev_err(&pdev->dev, "McBSP node is not provided\n"); +			return -EINVAL; +		} +		omap_twl4030_dai_links[0].cpu_dai_name  = NULL; +		omap_twl4030_dai_links[0].cpu_of_node = dai_node; + +	} else if (pdata) { +		if (pdata->card_name) { +			card->name = pdata->card_name; +		} else { +			dev_err(&pdev->dev, "Card name is not provided\n"); +			return -ENODEV; +		} +	} else { +		dev_err(&pdev->dev, "Missing pdata\n"); +		return -ENODEV; +	} + +	ret = snd_soc_register_card(card); +	if (ret) { +		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", +			ret); +		return ret; +	} + +	return 0; +} + +static int __devexit omap_twl4030_remove(struct platform_device *pdev) +{ +	struct snd_soc_card *card = platform_get_drvdata(pdev); + +	snd_soc_unregister_card(card); + +	return 0; +} + +static const struct of_device_id omap_twl4030_of_match[] = { +	{.compatible = "ti,omap-twl4030", }, +	{ }, +}; +MODULE_DEVICE_TABLE(of, omap_twl4030_of_match); + +static struct platform_driver omap_twl4030_driver = { +	.driver = { +		.name = "omap-twl4030", +		.owner = THIS_MODULE, +		.pm = &snd_soc_pm_ops, +		.of_match_table = omap_twl4030_of_match, +	}, +	.probe = omap_twl4030_probe, +	.remove = __devexit_p(omap_twl4030_remove), +}; + +module_platform_driver(omap_twl4030_driver); + +MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); +MODULE_DESCRIPTION("ALSA SoC for TI SoC based boards with twl4030 codec"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:omap-twl4030"); diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c deleted file mode 100644 index e263188841b..00000000000 --- a/sound/soc/omap/omap3beagle.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * omap3beagle.c  --  SoC audio for OMAP3 Beagle - * - * Author: Steve Sakoman <steve@sakoman.com> - * - * 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 <linux/clk.h> -#include <linux/platform_device.h> -#include <linux/module.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> - -#include <asm/mach-types.h> -#include <mach/hardware.h> -#include <mach/gpio.h> -#include <linux/platform_data/asoc-ti-mcbsp.h> - -#include "omap-mcbsp.h" -#include "omap-pcm.h" - -static int omap3beagle_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->codec_dai; -	struct snd_soc_dai *cpu_dai = rtd->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); -	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); -	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 omap3beagle_ops = { -	.hw_params = omap3beagle_hw_params, -}; - -/* Digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link omap3beagle_dai = { -	.name = "TWL4030", -	.stream_name = "TWL4030", -	.cpu_dai_name = "omap-mcbsp.2", -	.platform_name = "omap-pcm-audio", -	.codec_dai_name = "twl4030-hifi", -	.codec_name = "twl4030-codec", -	.ops = &omap3beagle_ops, -}; - -/* Audio machine driver */ -static struct snd_soc_card snd_soc_omap3beagle = { -	.name = "omap3beagle", -	.owner = THIS_MODULE, -	.dai_link = &omap3beagle_dai, -	.num_links = 1, -}; - -static struct platform_device *omap3beagle_snd_device; - -static int __init omap3beagle_soc_init(void) -{ -	int ret; - -	if (!(machine_is_omap3_beagle() || machine_is_devkit8000())) -		return -ENODEV; -	pr_info("OMAP3 Beagle/Devkit8000 SoC init\n"); - -	omap3beagle_snd_device = platform_device_alloc("soc-audio", -1); -	if (!omap3beagle_snd_device) { -		printk(KERN_ERR "Platform device allocation failed\n"); -		return -ENOMEM; -	} - -	platform_set_drvdata(omap3beagle_snd_device, &snd_soc_omap3beagle); - -	ret = platform_device_add(omap3beagle_snd_device); -	if (ret) -		goto err1; - -	return 0; - -err1: -	printk(KERN_ERR "Unable to add platform device\n"); -	platform_device_put(omap3beagle_snd_device); - -	return ret; -} - -static void __exit omap3beagle_soc_exit(void) -{ -	platform_device_unregister(omap3beagle_snd_device); -} - -module_init(omap3beagle_soc_init); -module_exit(omap3beagle_soc_exit); - -MODULE_AUTHOR("Steve Sakoman <steve@sakoman.com>"); -MODULE_DESCRIPTION("ALSA SoC OMAP3 Beagle"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/omap3evm.c b/sound/soc/omap/omap3evm.c deleted file mode 100644 index d632bfbb698..00000000000 --- a/sound/soc/omap/omap3evm.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * omap3evm.c  -- ALSA SoC support for OMAP3 EVM - * - * Author: Anuj Aggarwal <anuj.aggarwal@ti.com> - * - * 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 <linux/clk.h> -#include <linux/platform_device.h> -#include <linux/module.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> - -#include <asm/mach-types.h> -#include <mach/hardware.h> -#include <mach/gpio.h> -#include <linux/platform_data/asoc-ti-mcbsp.h> - -#include "omap-mcbsp.h" -#include "omap-pcm.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->codec_dai; -	int 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_name = "omap-mcbsp.2", -	.codec_dai_name = "twl4030-hifi", -	.platform_name = "omap-pcm-audio", -	.codec_name = "twl4030-codec", -	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | -		   SND_SOC_DAIFMT_CBM_CFM, -	.ops 		= &omap3evm_ops, -}; - -/* Audio machine driver */ -static struct snd_soc_card snd_soc_omap3evm = { -	.name = "omap3evm", -	.owner = THIS_MODULE, -	.dai_link = &omap3evm_dai, -	.num_links = 1, -}; - -static struct platform_device *omap3evm_snd_device; - -static int __init omap3evm_soc_init(void) -{ -	int ret; - -	if (!machine_is_omap3evm()) -		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, &snd_soc_omap3evm); -	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 <anuj.aggarwal@ti.com>"); -MODULE_DESCRIPTION("ALSA SoC OMAP3 EVM"); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c deleted file mode 100644 index 502bce29988..00000000000 --- a/sound/soc/omap/overo.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * overo.c  --  SoC audio for Gumstix Overo - * - * Author: Steve Sakoman <steve@sakoman.com> - * - * 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 <linux/clk.h> -#include <linux/platform_device.h> -#include <linux/module.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> - -#include <asm/mach-types.h> -#include <mach/hardware.h> -#include <mach/gpio.h> -#include <linux/platform_data/asoc-ti-mcbsp.h> - -#include "omap-mcbsp.h" -#include "omap-pcm.h" - -static int overo_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->codec_dai; -	int 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 overo_ops = { -	.hw_params = overo_hw_params, -}; - -/* Digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link overo_dai = { -	.name = "TWL4030", -	.stream_name = "TWL4030", -	.cpu_dai_name = "omap-mcbsp.2", -	.codec_dai_name = "twl4030-hifi", -	.platform_name = "omap-pcm-audio", -	.codec_name = "twl4030-codec", -	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | -		   SND_SOC_DAIFMT_CBM_CFM, -	.ops = &overo_ops, -}; - -/* Audio machine driver */ -static struct snd_soc_card snd_soc_card_overo = { -	.name = "overo", -	.owner = THIS_MODULE, -	.dai_link = &overo_dai, -	.num_links = 1, -}; - -static struct platform_device *overo_snd_device; - -static int __init overo_soc_init(void) -{ -	int ret; - -	if (!(machine_is_overo() || machine_is_cm_t35())) { -		pr_debug("Incomatible machine!\n"); -		return -ENODEV; -	} -	printk(KERN_INFO "overo SoC init\n"); - -	overo_snd_device = platform_device_alloc("soc-audio", -1); -	if (!overo_snd_device) { -		printk(KERN_ERR "Platform device allocation failed\n"); -		return -ENOMEM; -	} - -	platform_set_drvdata(overo_snd_device, &snd_soc_card_overo); - -	ret = platform_device_add(overo_snd_device); -	if (ret) -		goto err1; - -	return 0; - -err1: -	printk(KERN_ERR "Unable to add platform device\n"); -	platform_device_put(overo_snd_device); - -	return ret; -} -module_init(overo_soc_init); - -static void __exit overo_soc_exit(void) -{ -	platform_device_unregister(overo_snd_device); -} -module_exit(overo_soc_exit); - -MODULE_AUTHOR("Steve Sakoman <steve@sakoman.com>"); -MODULE_DESCRIPTION("ALSA SoC overo"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c index 23de2b21d69..677b567935f 100644 --- a/sound/soc/omap/zoom2.c +++ b/sound/soc/omap/zoom2.c @@ -191,9 +191,6 @@ static int __init zoom2_soc_init(void)  	BUG_ON(gpio_request(ZOOM2_HEADSET_MUX_GPIO, "hs_mux") < 0);  	gpio_direction_output(ZOOM2_HEADSET_MUX_GPIO, 0); -	BUG_ON(gpio_request(ZOOM2_HEADSET_EXTMUTE_GPIO, "ext_mute") < 0); -	gpio_direction_output(ZOOM2_HEADSET_EXTMUTE_GPIO, 0); -  	return 0;  err1: @@ -207,7 +204,6 @@ module_init(zoom2_soc_init);  static void __exit zoom2_soc_exit(void)  {  	gpio_free(ZOOM2_HEADSET_MUX_GPIO); -	gpio_free(ZOOM2_HEADSET_EXTMUTE_GPIO);  	platform_device_unregister(zoom2_snd_device);  } diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index fe3995ce9b3..e7b83179aca 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -1,6 +1,6 @@  config SND_SOC_SAMSUNG  	tristate "ASoC support for Samsung" -	depends on ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_S5P64X0 || ARCH_EXYNOS4 +	depends on PLAT_SAMSUNG  	select S3C64XX_DMA if ARCH_S3C64XX  	select S3C2410_DMA if ARCH_S3C24XX  	help @@ -191,6 +191,7 @@ config SND_SOC_SPEYSIDE  	select SND_SAMSUNG_I2S  	select SND_SOC_WM8996  	select SND_SOC_WM9081 +	select SND_SOC_WM0010  	select SND_SOC_WM1250_EV1  config SND_SOC_TOBERMORY @@ -199,6 +200,14 @@ config SND_SOC_TOBERMORY  	select SND_SAMSUNG_I2S  	select SND_SOC_WM8962 +config SND_SOC_BELLS +	tristate "Audio support for Wolfson Bells" +	depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 +	select SND_SAMSUNG_I2S +	select SND_SOC_WM5102 +	select SND_SOC_WM5110 +	select SND_SOC_WM9081 +  config SND_SOC_LOWLAND  	tristate "Audio support for Wolfson Lowland"  	depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile index 9d03beb40c8..709f6059ad6 100644 --- a/sound/soc/samsung/Makefile +++ b/sound/soc/samsung/Makefile @@ -42,6 +42,7 @@ snd-soc-speyside-objs := speyside.o  snd-soc-tobermory-objs := tobermory.o  snd-soc-lowland-objs := lowland.o  snd-soc-littlemill-objs := littlemill.o +snd-soc-bells-objs := bells.o  obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o  obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o @@ -65,3 +66,4 @@ obj-$(CONFIG_SND_SOC_SPEYSIDE) += snd-soc-speyside.o  obj-$(CONFIG_SND_SOC_TOBERMORY) += snd-soc-tobermory.o  obj-$(CONFIG_SND_SOC_LOWLAND) += snd-soc-lowland.o  obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o +obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c new file mode 100644 index 00000000000..5dc10dfc0d4 --- /dev/null +++ b/sound/soc/samsung/bells.c @@ -0,0 +1,346 @@ +/* + * Bells audio support + * + * Copyright 2012 Wolfson Microelectronics + * + * 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. + */ + +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/jack.h> +#include <linux/gpio.h> +#include <linux/module.h> + +#include "../codecs/wm5102.h" +#include "../codecs/wm9081.h" + +/* + * 44.1kHz based clocks for the SYSCLK domain, use a very high clock + * to allow all the DSP functionality to be enabled if desired. + */ +#define SYSCLK_RATE (44100 * 1024) + +/* 48kHz based clocks for the ASYNC domain */ +#define ASYNCCLK_RATE (48000 * 512) + +/* BCLK2 is fixed at this currently */ +#define BCLK2_RATE (64 * 8000) + +/* + * Expect a 24.576MHz crystal if one is fitted (the driver will function + * if this is not fitted). + */ +#define MCLK_RATE 24576000 + +#define WM9081_AUDIO_RATE 44100 +#define WM9081_MCLK_RATE  (WM9081_AUDIO_RATE * 256) + +static int bells_set_bias_level(struct snd_soc_card *card, +				struct snd_soc_dapm_context *dapm, +				enum snd_soc_bias_level level) +{ +	struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; +	struct snd_soc_codec *codec = codec_dai->codec; +	int ret; + +	if (dapm->dev != codec_dai->dev) +		return 0; + +	switch (level) { +	case SND_SOC_BIAS_PREPARE: +		if (dapm->bias_level == SND_SOC_BIAS_STANDBY) { +			ret = snd_soc_codec_set_pll(codec, WM5102_FLL1, +						    ARIZONA_FLL_SRC_MCLK1, +						    MCLK_RATE, +						    SYSCLK_RATE); +			if (ret < 0) +				pr_err("Failed to start FLL: %d\n", ret); + +			ret = snd_soc_codec_set_pll(codec, WM5102_FLL2, +						    ARIZONA_FLL_SRC_AIF2BCLK, +						    BCLK2_RATE, +						    ASYNCCLK_RATE); +			if (ret < 0) +				pr_err("Failed to start FLL: %d\n", ret); +		} +		break; + +	default: +		break; +	} + +	return 0; +} + +static int bells_set_bias_level_post(struct snd_soc_card *card, +				     struct snd_soc_dapm_context *dapm, +				     enum snd_soc_bias_level level) +{ +	struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; +	struct snd_soc_codec *codec = codec_dai->codec; +	int ret; + +	if (dapm->dev != codec_dai->dev) +		return 0; + +	switch (level) { +	case SND_SOC_BIAS_STANDBY: +		ret = snd_soc_codec_set_pll(codec, WM5102_FLL1, 0, 0, 0); +		if (ret < 0) { +			pr_err("Failed to stop FLL: %d\n", ret); +			return ret; +		} + +		ret = snd_soc_codec_set_pll(codec, WM5102_FLL2, 0, 0, 0); +		if (ret < 0) { +			pr_err("Failed to stop FLL: %d\n", ret); +			return ret; +		} +		break; + +	default: +		break; +	} + +	dapm->bias_level = level; + +	return 0; +} + +static int bells_late_probe(struct snd_soc_card *card) +{ +	struct snd_soc_codec *codec = card->rtd[0].codec; +	struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai; +	struct snd_soc_dai *aif2_dai = card->rtd[1].cpu_dai; +	struct snd_soc_dai *aif3_dai = card->rtd[2].cpu_dai; +	struct snd_soc_dai *wm9081_dai = card->rtd[2].codec_dai; +	int ret; + +	ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0); +	if (ret != 0) { +		dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret); +		return ret; +	} + +	ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0); +	if (ret != 0) { +		dev_err(aif2_dai->dev, "Failed to set AIF2 clock: %d\n", ret); +		return ret; +	} + +	ret = snd_soc_dai_set_sysclk(aif3_dai, ARIZONA_CLK_SYSCLK, 0, 0); +	if (ret != 0) { +		dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret); +		return ret; +	} + +	ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK, +				       ARIZONA_CLK_SRC_FLL1, SYSCLK_RATE, +				       SND_SOC_CLOCK_IN); +	if (ret != 0) { +		dev_err(codec->dev, "Failed to set SYSCLK: %d\n", ret); +		return ret; +	} + +	ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_OPCLK, 0, +				       WM9081_MCLK_RATE, SND_SOC_CLOCK_OUT); +	if (ret != 0) { +		dev_err(codec->dev, "Failed to set OPCLK: %d\n", ret); +		return ret; +	} + +	ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_ASYNCCLK, +				       ARIZONA_CLK_SRC_FLL2, ASYNCCLK_RATE, +				       SND_SOC_CLOCK_IN); +	if (ret != 0) { +		dev_err(codec->dev, "Failed to set SYSCLK: %d\n", ret); +		return ret; +	} + +	ret = snd_soc_codec_set_sysclk(wm9081_dai->codec, WM9081_SYSCLK_MCLK, +				       0, WM9081_MCLK_RATE, 0); +	if (ret != 0) { +		dev_err(wm9081_dai->dev, "Failed to set MCLK: %d\n", ret); +		return ret; +	} + +	return 0; +} + +static const struct snd_soc_pcm_stream baseband_params = { +	.formats = SNDRV_PCM_FMTBIT_S32_LE, +	.rate_min = 8000, +	.rate_max = 8000, +	.channels_min = 2, +	.channels_max = 2, +}; + +static const struct snd_soc_pcm_stream sub_params = { +	.formats = SNDRV_PCM_FMTBIT_S32_LE, +	.rate_min = WM9081_AUDIO_RATE, +	.rate_max = WM9081_AUDIO_RATE, +	.channels_min = 2, +	.channels_max = 2, +}; + +static struct snd_soc_dai_link bells_dai_wm5102[] = { +	{ +		.name = "CPU", +		.stream_name = "CPU", +		.cpu_dai_name = "samsung-i2s.0", +		.codec_dai_name = "wm5102-aif1", +		.platform_name = "samsung-audio", +		.codec_name = "wm5102-codec", +		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF +				| SND_SOC_DAIFMT_CBM_CFM, +	}, +	{ +		.name = "Baseband", +		.stream_name = "Baseband", +		.cpu_dai_name = "wm5102-aif2", +		.codec_dai_name = "wm1250-ev1", +		.codec_name = "wm1250-ev1.1-0027", +		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF +				| SND_SOC_DAIFMT_CBM_CFM, +		.ignore_suspend = 1, +		.params = &baseband_params, +	}, +	{ +		.name = "Sub", +		.stream_name = "Sub", +		.cpu_dai_name = "wm5102-aif3", +		.codec_dai_name = "wm9081-hifi", +		.codec_name = "wm9081.1-006c", +		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF +				| SND_SOC_DAIFMT_CBS_CFS, +		.ignore_suspend = 1, +		.params = &sub_params, +	}, +}; + +static struct snd_soc_dai_link bells_dai_wm5110[] = { +	{ +		.name = "CPU", +		.stream_name = "CPU", +		.cpu_dai_name = "samsung-i2s.0", +		.codec_dai_name = "wm5110-aif1", +		.platform_name = "samsung-audio", +		.codec_name = "wm5110-codec", +		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF +				| SND_SOC_DAIFMT_CBM_CFM, +	}, +	{ +		.name = "Baseband", +		.stream_name = "Baseband", +		.cpu_dai_name = "wm5110-aif2", +		.codec_dai_name = "wm1250-ev1", +		.codec_name = "wm1250-ev1.1-0027", +		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF +				| SND_SOC_DAIFMT_CBM_CFM, +		.ignore_suspend = 1, +		.params = &baseband_params, +	}, +	{ +		.name = "Sub", +		.stream_name = "Sub", +		.cpu_dai_name = "wm5102-aif3", +		.codec_dai_name = "wm9081-hifi", +		.codec_name = "wm9081.1-006c", +		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF +				| SND_SOC_DAIFMT_CBS_CFS, +		.ignore_suspend = 1, +		.params = &sub_params, +	}, +}; + +static struct snd_soc_codec_conf bells_codec_conf[] = { +	{ +		.dev_name = "wm9081.1-006c", +		.name_prefix = "Sub", +	}, +}; + +static struct snd_soc_dapm_route bells_routes[] = { +	{ "Sub CLK_SYS", NULL, "OPCLK" }, +}; + +static struct snd_soc_card bells_cards[] = { +	{ +		.name = "Bells WM5102", +		.owner = THIS_MODULE, +		.dai_link = bells_dai_wm5102, +		.num_links = ARRAY_SIZE(bells_dai_wm5102), +		.codec_conf = bells_codec_conf, +		.num_configs = ARRAY_SIZE(bells_codec_conf), + +		.late_probe = bells_late_probe, + +		.dapm_routes = bells_routes, +		.num_dapm_routes = ARRAY_SIZE(bells_routes), + +		.set_bias_level = bells_set_bias_level, +		.set_bias_level_post = bells_set_bias_level_post, +	}, +	{ +		.name = "Bells WM5110", +		.owner = THIS_MODULE, +		.dai_link = bells_dai_wm5110, +		.num_links = ARRAY_SIZE(bells_dai_wm5110), +		.codec_conf = bells_codec_conf, +		.num_configs = ARRAY_SIZE(bells_codec_conf), + +		.late_probe = bells_late_probe, + +		.dapm_routes = bells_routes, +		.num_dapm_routes = ARRAY_SIZE(bells_routes), + +		.set_bias_level = bells_set_bias_level, +		.set_bias_level_post = bells_set_bias_level_post, +	}, +}; + + +static __devinit int bells_probe(struct platform_device *pdev) +{ +	int ret; + +	bells_cards[pdev->id].dev = &pdev->dev; + +	ret = snd_soc_register_card(&bells_cards[pdev->id]); +	if (ret) { +		dev_err(&pdev->dev, +			"snd_soc_register_card(%s) failed: %d\n", +			bells_cards[pdev->id].name, ret); +		return ret; +	} + +	return 0; +} + +static int __devexit bells_remove(struct platform_device *pdev) +{ +	snd_soc_unregister_card(&bells_cards[pdev->id]); + +	return 0; +} + +static struct platform_driver bells_driver = { +	.driver = { +		.name = "bells", +		.owner = THIS_MODULE, +		.pm = &snd_soc_pm_ops, +	}, +	.probe = bells_probe, +	.remove = __devexit_p(bells_remove), +}; + +module_platform_driver(bells_driver); + +MODULE_DESCRIPTION("Bells audio support"); +MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:bells"); diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c index a4a9fc7e8c7..c7e1c28528a 100644 --- a/sound/soc/samsung/speyside.c +++ b/sound/soc/samsung/speyside.c @@ -25,7 +25,7 @@ static int speyside_set_bias_level(struct snd_soc_card *card,  				   struct snd_soc_dapm_context *dapm,  				   enum snd_soc_bias_level level)  { -	struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; +	struct snd_soc_dai *codec_dai = card->rtd[1].codec_dai;  	int ret;  	if (dapm->dev != codec_dai->dev) @@ -57,7 +57,7 @@ static int speyside_set_bias_level_post(struct snd_soc_card *card,  					struct snd_soc_dapm_context *dapm,  					enum snd_soc_bias_level level)  { -	struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; +	struct snd_soc_dai *codec_dai = card->rtd[1].codec_dai;  	int ret;  	if (dapm->dev != codec_dai->dev) @@ -126,6 +126,18 @@ static void speyside_set_polarity(struct snd_soc_codec *codec,  	snd_soc_dapm_sync(&codec->dapm);  } +static int speyside_wm0010_init(struct snd_soc_pcm_runtime *rtd) +{ +	struct snd_soc_dai *dai = rtd->codec_dai; +	int ret; + +	ret = snd_soc_dai_set_sysclk(dai, 0, MCLK_AUDIO_RATE, 0); +	if (ret < 0) +		return ret; + +	return 0; +} +  static int speyside_wm8996_init(struct snd_soc_pcm_runtime *rtd)  {  	struct snd_soc_dai *dai = rtd->codec_dai; @@ -172,17 +184,37 @@ static int speyside_late_probe(struct snd_soc_card *card)  	return 0;  } +static const struct snd_soc_pcm_stream dsp_codec_params = { +	.formats = SNDRV_PCM_FMTBIT_S32_LE, +	.rate_min = 48000, +	.rate_max = 48000, +	.channels_min = 2, +	.channels_max = 2, +}; +  static struct snd_soc_dai_link speyside_dai[] = {  	{ -		.name = "CPU", -		.stream_name = "CPU", +		.name = "CPU-DSP", +		.stream_name = "CPU-DSP",  		.cpu_dai_name = "samsung-i2s.0", -		.codec_dai_name = "wm8996-aif1", +		.codec_dai_name = "wm0010-sdi1",  		.platform_name = "samsung-audio", +		.codec_name = "spi0.0", +		.init = speyside_wm0010_init, +		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF +				| SND_SOC_DAIFMT_CBM_CFM, +	}, +	{ +		.name = "DSP-CODEC", +		.stream_name = "DSP-CODEC", +		.cpu_dai_name = "wm0010-sdi2", +		.codec_dai_name = "wm8996-aif1",  		.codec_name = "wm8996.1-001a",  		.init = speyside_wm8996_init,  		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF  				| SND_SOC_DAIFMT_CBM_CFM, +		.params = &dsp_codec_params, +		.ignore_suspend = 1,  	},  	{  		.name = "Baseband", diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 0540408a9fa..5328ae5539f 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -1655,22 +1655,20 @@ static int fsi_probe(struct platform_device *pdev)  	irq = platform_get_irq(pdev, 0);  	if (!res || (int)irq <= 0) {  		dev_err(&pdev->dev, "Not enough FSI platform resources.\n"); -		ret = -ENODEV; -		goto exit; +		return -ENODEV;  	} -	master = kzalloc(sizeof(*master), GFP_KERNEL); +	master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL);  	if (!master) {  		dev_err(&pdev->dev, "Could not allocate master\n"); -		ret = -ENOMEM; -		goto exit; +		return -ENOMEM;  	} -	master->base = ioremap_nocache(res->start, resource_size(res)); +	master->base = devm_ioremap_nocache(&pdev->dev, +					    res->start, resource_size(res));  	if (!master->base) { -		ret = -ENXIO;  		dev_err(&pdev->dev, "Unable to ioremap FSI registers.\n"); -		goto exit_kfree; +		return -ENXIO;  	}  	/* master setting */ @@ -1686,7 +1684,7 @@ static int fsi_probe(struct platform_device *pdev)  	ret = fsi_stream_probe(&master->fsia, &pdev->dev);  	if (ret < 0) {  		dev_err(&pdev->dev, "FSIA stream probe failed\n"); -		goto exit_iounmap; +		return ret;  	}  	/* FSI B setting */ @@ -1730,16 +1728,11 @@ exit_snd_soc:  exit_free_irq:  	free_irq(irq, master);  exit_fsib: +	pm_runtime_disable(&pdev->dev);  	fsi_stream_remove(&master->fsib);  exit_fsia:  	fsi_stream_remove(&master->fsia); -exit_iounmap: -	iounmap(master->base); -	pm_runtime_disable(&pdev->dev); -exit_kfree: -	kfree(master); -	master = NULL; -exit: +  	return ret;  } @@ -1758,9 +1751,6 @@ static int fsi_remove(struct platform_device *pdev)  	fsi_stream_remove(&master->fsia);  	fsi_stream_remove(&master->fsib); -	iounmap(master->base); -	kfree(master); -  	return 0;  } diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c new file mode 100644 index 00000000000..967d0e173e1 --- /dev/null +++ b/sound/soc/soc-compress.c @@ -0,0 +1,294 @@ +/* + * soc-compress.c  --  ALSA SoC Compress + * + * Copyright (C) 2012 Intel Corp. + * + * Authors: Namarta Kohli <namartax.kohli@intel.com> + *          Ramesh Babu K V <ramesh.babu@linux.intel.com> + *          Vinod Koul <vinod.koul@linux.intel.com> + * + *  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. + * + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <sound/core.h> +#include <sound/compress_params.h> +#include <sound/compress_driver.h> +#include <sound/soc.h> +#include <sound/initval.h> + +static int soc_compr_open(struct snd_compr_stream *cstream) +{ +	struct snd_soc_pcm_runtime *rtd = cstream->private_data; +	struct snd_soc_platform *platform = rtd->platform; +	struct snd_soc_dai *cpu_dai = rtd->cpu_dai; +	struct snd_soc_dai *codec_dai = rtd->codec_dai; +	int ret = 0; + +	if (platform->driver->compr_ops && platform->driver->compr_ops->open) { +		ret = platform->driver->compr_ops->open(cstream); +		if (ret < 0) { +			pr_err("compress asoc: can't open platform %s\n", platform->name); +			goto out; +		} +	} + +	if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->startup) { +		ret = rtd->dai_link->compr_ops->startup(cstream); +		if (ret < 0) { +			pr_err("compress asoc: %s startup failed\n", rtd->dai_link->name); +			goto machine_err; +		} +	} + +	if (cstream->direction == SND_COMPRESS_PLAYBACK) { +		cpu_dai->playback_active++; +		codec_dai->playback_active++; +	} else { +		cpu_dai->capture_active++; +		codec_dai->capture_active++; +	} + +	cpu_dai->active++; +	codec_dai->active++; +	rtd->codec->active++; + +	return 0; + +machine_err: +	if (platform->driver->compr_ops && platform->driver->compr_ops->free) +		platform->driver->compr_ops->free(cstream); +out: +	return ret; +} + +static int soc_compr_free(struct snd_compr_stream *cstream) +{ +	struct snd_soc_pcm_runtime *rtd = cstream->private_data; +	struct snd_soc_platform *platform = rtd->platform; +	struct snd_soc_dai *cpu_dai = rtd->cpu_dai; +	struct snd_soc_dai *codec_dai = rtd->codec_dai; +	struct snd_soc_codec *codec = rtd->codec; + +	if (cstream->direction == SND_COMPRESS_PLAYBACK) { +		cpu_dai->playback_active--; +		codec_dai->playback_active--; +	} else { +		cpu_dai->capture_active--; +		codec_dai->capture_active--; +	} + +	snd_soc_dai_digital_mute(codec_dai, 1); + +	cpu_dai->active--; +	codec_dai->active--; +	codec->active--; + +	if (!cpu_dai->active) +		cpu_dai->rate = 0; + +	if (!codec_dai->active) +		codec_dai->rate = 0; + + +	if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->shutdown) +		rtd->dai_link->compr_ops->shutdown(cstream); + +	if (platform->driver->compr_ops && platform->driver->compr_ops->free) +		platform->driver->compr_ops->free(cstream); +	cpu_dai->runtime = NULL; + +	if (cstream->direction == SND_COMPRESS_PLAYBACK) { +		if (!rtd->pmdown_time || codec->ignore_pmdown_time || +		    rtd->dai_link->ignore_pmdown_time) { +			snd_soc_dapm_stream_event(rtd, +					SNDRV_PCM_STREAM_PLAYBACK, +					SND_SOC_DAPM_STREAM_STOP); +		} else +			codec_dai->pop_wait = 1; +			schedule_delayed_work(&rtd->delayed_work, +				msecs_to_jiffies(rtd->pmdown_time)); +	} else { +		/* capture streams can be powered down now */ +		snd_soc_dapm_stream_event(rtd, +			SNDRV_PCM_STREAM_CAPTURE, +			SND_SOC_DAPM_STREAM_STOP); +	} + +	return 0; +} + +static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) +{ + +	struct snd_soc_pcm_runtime *rtd = cstream->private_data; +	struct snd_soc_platform *platform = rtd->platform; +	struct snd_soc_dai *codec_dai = rtd->codec_dai; +	int ret = 0; + +	if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) { +		ret = platform->driver->compr_ops->trigger(cstream, cmd); +		if (ret < 0) +			return ret; +	} + +	if (cmd == SNDRV_PCM_TRIGGER_START) +		snd_soc_dai_digital_mute(codec_dai, 0); +	else if (cmd == SNDRV_PCM_TRIGGER_STOP) +		snd_soc_dai_digital_mute(codec_dai, 1); + +	return ret; +} + +static int soc_compr_set_params(struct snd_compr_stream *cstream, +					struct snd_compr_params *params) +{ +	struct snd_soc_pcm_runtime *rtd = cstream->private_data; +	struct snd_soc_platform *platform = rtd->platform; +	int ret = 0; + +	/* first we call set_params for the platform driver +	 * this should configure the soc side +	 * if the machine has compressed ops then we call that as well +	 * expectation is that platform and machine will configure everything +	 * for this compress path, like configuring pcm port for codec +	 */ +	if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) { +		ret = platform->driver->compr_ops->set_params(cstream, params); +		if (ret < 0) +			return ret; +	} + +	if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) { +		ret = rtd->dai_link->compr_ops->set_params(cstream); +		if (ret < 0) +			return ret; +	} + +	snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, +				SND_SOC_DAPM_STREAM_START); + +	return ret; +} + +static int soc_compr_get_params(struct snd_compr_stream *cstream, +					struct snd_codec *params) +{ +	struct snd_soc_pcm_runtime *rtd = cstream->private_data; +	struct snd_soc_platform *platform = rtd->platform; +	int ret = 0; + +	if (platform->driver->compr_ops && platform->driver->compr_ops->get_params) +		ret = platform->driver->compr_ops->get_params(cstream, params); + +	return ret; +} + +static int soc_compr_get_caps(struct snd_compr_stream *cstream, +				struct snd_compr_caps *caps) +{ +	struct snd_soc_pcm_runtime *rtd = cstream->private_data; +	struct snd_soc_platform *platform = rtd->platform; +	int ret = 0; + +	if (platform->driver->compr_ops && platform->driver->compr_ops->get_caps) +		ret = platform->driver->compr_ops->get_caps(cstream, caps); + +	return ret; +} + +static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream, +				struct snd_compr_codec_caps *codec) +{ +	struct snd_soc_pcm_runtime *rtd = cstream->private_data; +	struct snd_soc_platform *platform = rtd->platform; +	int ret = 0; + +	if (platform->driver->compr_ops && platform->driver->compr_ops->get_codec_caps) +		ret = platform->driver->compr_ops->get_codec_caps(cstream, codec); + +	return ret; +} + +static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) +{ +	struct snd_soc_pcm_runtime *rtd = cstream->private_data; +	struct snd_soc_platform *platform = rtd->platform; +	int ret = 0; + +	if (platform->driver->compr_ops && platform->driver->compr_ops->ack) +		ret = platform->driver->compr_ops->ack(cstream, bytes); + +	return ret; +} + +static int soc_compr_pointer(struct snd_compr_stream *cstream, +			struct snd_compr_tstamp *tstamp) +{ +	struct snd_soc_pcm_runtime *rtd = cstream->private_data; +	struct snd_soc_platform *platform = rtd->platform; + +	if (platform->driver->compr_ops && platform->driver->compr_ops->pointer) +		 platform->driver->compr_ops->pointer(cstream, tstamp); + +	return 0; +} + +/* ASoC Compress operations */ +static struct snd_compr_ops soc_compr_ops = { +	.open		= soc_compr_open, +	.free		= soc_compr_free, +	.set_params	= soc_compr_set_params, +	.get_params	= soc_compr_get_params, +	.trigger	= soc_compr_trigger, +	.pointer	= soc_compr_pointer, +	.ack		= soc_compr_ack, +	.get_caps	= soc_compr_get_caps, +	.get_codec_caps = soc_compr_get_codec_caps +}; + +/* create a new compress */ +int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) +{ +	struct snd_soc_codec *codec = rtd->codec; +	struct snd_soc_dai *codec_dai = rtd->codec_dai; +	struct snd_soc_dai *cpu_dai = rtd->cpu_dai; +	struct snd_compr *compr; +	char new_name[64]; +	int ret = 0, direction = 0; + +	/* check client and interface hw capabilities */ +	snprintf(new_name, sizeof(new_name), "%s %s-%d", +			rtd->dai_link->stream_name, codec_dai->name, num); +	direction = SND_COMPRESS_PLAYBACK; +	compr = kzalloc(sizeof(*compr), GFP_KERNEL); +	if (compr == NULL) { +		snd_printk(KERN_ERR "Cannot allocate compr\n"); +		return -ENOMEM; +	} + +	compr->ops = &soc_compr_ops; +	mutex_init(&compr->lock); +	ret = snd_compress_new(rtd->card->snd_card, num, direction, compr); +	if (ret < 0) { +		pr_err("compress asoc: can't create compress for codec %s\n", +			codec->name); +		kfree(compr); +		return ret; +	} + +	rtd->compr = compr; +	compr->private_data = rtd; + +	printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n", codec_dai->name, +		cpu_dai->name); +	return ret; +} diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index cf3d0b0c71b..d1198627fc4 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -609,6 +609,10 @@ int snd_soc_suspend(struct device *dev)  					  SND_SOC_DAPM_STREAM_SUSPEND);  	} +	/* Recheck all analogue paths too */ +	dapm_mark_io_dirty(&card->dapm); +	snd_soc_dapm_sync(&card->dapm); +  	/* suspend all CODECs */  	list_for_each_entry(codec, &card->codec_dev_list, card_list) {  		/* If there are paths active then the CODEC will be held with @@ -631,6 +635,8 @@ int snd_soc_suspend(struct device *dev)  				codec->driver->suspend(codec);  				codec->suspended = 1;  				codec->cache_sync = 1; +				if (codec->using_regmap) +					regcache_mark_dirty(codec->control_data);  				break;  			default:  				dev_dbg(codec->dev, "CODEC is on over suspend\n"); @@ -756,6 +762,10 @@ static void soc_resume_deferred(struct work_struct *work)  	/* userspace can access us now we are back as we were before */  	snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0); + +	/* Recheck all analogue paths too */ +	dapm_mark_io_dirty(&card->dapm); +	snd_soc_dapm_sync(&card->dapm);  }  /* powers up audio subsystem after a suspend */ @@ -1388,37 +1398,48 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)  	if (ret < 0)  		pr_warn("asoc: failed to add pmdown_time sysfs:%d\n", ret); -	if (!dai_link->params) { -		/* create the pcm */ -		ret = soc_new_pcm(rtd, num); +	if (cpu_dai->driver->compress_dai) { +		/*create compress_device"*/ +		ret = soc_new_compress(rtd, num);  		if (ret < 0) { -			pr_err("asoc: can't create pcm %s :%d\n", -			       dai_link->stream_name, ret); +			pr_err("asoc: can't create compress %s\n", +					 dai_link->stream_name);  			return ret;  		}  	} else { -		/* link the DAI widgets */ -		play_w = codec_dai->playback_widget; -		capture_w = cpu_dai->capture_widget; -		if (play_w && capture_w) { -			ret = snd_soc_dapm_new_pcm(card, dai_link->params, -						   capture_w, play_w); -			if (ret != 0) { -				dev_err(card->dev, "Can't link %s to %s: %d\n", -					play_w->name, capture_w->name, ret); + +		if (!dai_link->params) { +			/* create the pcm */ +			ret = soc_new_pcm(rtd, num); +			if (ret < 0) { +				pr_err("asoc: can't create pcm %s :%d\n", +				       dai_link->stream_name, ret);  				return ret;  			} -		} +		} else { +			/* link the DAI widgets */ +			play_w = codec_dai->playback_widget; +			capture_w = cpu_dai->capture_widget; +			if (play_w && capture_w) { +				ret = snd_soc_dapm_new_pcm(card, dai_link->params, +						   capture_w, play_w); +				if (ret != 0) { +					dev_err(card->dev, "Can't link %s to %s: %d\n", +						play_w->name, capture_w->name, ret); +					return ret; +				} +			} -		play_w = cpu_dai->playback_widget; -		capture_w = codec_dai->capture_widget; -		if (play_w && capture_w) { -			ret = snd_soc_dapm_new_pcm(card, dai_link->params, +			play_w = cpu_dai->playback_widget; +			capture_w = codec_dai->capture_widget; +			if (play_w && capture_w) { +				ret = snd_soc_dapm_new_pcm(card, dai_link->params,  						   capture_w, play_w); -			if (ret != 0) { -				dev_err(card->dev, "Can't link %s to %s: %d\n", -					play_w->name, capture_w->name, ret); -				return ret; +				if (ret != 0) { +					dev_err(card->dev, "Can't link %s to %s: %d\n", +						play_w->name, capture_w->name, ret); +					return ret; +				}  			}  		}  	} @@ -1816,7 +1837,6 @@ base_error:  static int soc_probe(struct platform_device *pdev)  {  	struct snd_soc_card *card = platform_get_drvdata(pdev); -	int ret = 0;  	/*  	 * no card, so machine driver should be registering card @@ -1832,13 +1852,7 @@ static int soc_probe(struct platform_device *pdev)  	/* Bodge while we unpick instantiation */  	card->dev = &pdev->dev; -	ret = snd_soc_register_card(card); -	if (ret != 0) { -		dev_err(&pdev->dev, "Failed to register card\n"); -		return ret; -	} - -	return 0; +	return snd_soc_register_card(card);  }  static int soc_cleanup_card_resources(struct snd_soc_card *card) @@ -2399,16 +2413,14 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,  {  	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);  	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; -	unsigned int val, bitmask; +	unsigned int val; -	for (bitmask = 1; bitmask < e->max; bitmask <<= 1) -		;  	val = snd_soc_read(codec, e->reg);  	ucontrol->value.enumerated.item[0] -		= (val >> e->shift_l) & (bitmask - 1); +		= (val >> e->shift_l) & e->mask;  	if (e->shift_l != e->shift_r)  		ucontrol->value.enumerated.item[1] = -			(val >> e->shift_r) & (bitmask - 1); +			(val >> e->shift_r) & e->mask;  	return 0;  } @@ -2429,19 +2441,17 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,  	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);  	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;  	unsigned int val; -	unsigned int mask, bitmask; +	unsigned int mask; -	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; +	mask = e->mask << 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; +		mask |= e->mask << e->shift_r;  	}  	return snd_soc_update_bits_locked(codec, e->reg, mask, val); @@ -3717,6 +3727,9 @@ int snd_soc_register_dai(struct device *dev,  		}  	} +	if (!dai->codec) +		dai->dapm.idle_bias_off = 1; +  	list_add(&dai->list, &dai_list);  	mutex_unlock(&client_mutex); @@ -3805,6 +3818,9 @@ int snd_soc_register_dais(struct device *dev,  			}  		} +		if (!dai->codec) +			dai->dapm.idle_bias_off = 1; +  		list_add(&dai->list, &dai_list);  		mutex_unlock(&client_mutex); @@ -4034,8 +4050,6 @@ int snd_soc_register_codec(struct device *dev,  	return 0;  fail: -	kfree(codec->reg_def_copy); -	codec->reg_def_copy = NULL;  	kfree(codec->name);  	kfree(codec);  	return ret; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index f90139b5f50..d0a4be38dc0 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -141,6 +141,28 @@ void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)  }  EXPORT_SYMBOL_GPL(dapm_mark_dirty); +void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm) +{ +	struct snd_soc_card *card = dapm->card; +	struct snd_soc_dapm_widget *w; + +	mutex_lock(&card->dapm_mutex); + +	list_for_each_entry(w, &card->widgets, list) { +		switch (w->id) { +		case snd_soc_dapm_input: +		case snd_soc_dapm_output: +			dapm_mark_dirty(w, "Rechecking inputs and outputs"); +			break; +		default: +			break; +		} +	} + +	mutex_unlock(&card->dapm_mutex); +} +EXPORT_SYMBOL_GPL(dapm_mark_io_dirty); +  /* create a new dapm widget */  static inline struct snd_soc_dapm_widget *dapm_cnew_widget(  	const struct snd_soc_dapm_widget *_widget) @@ -336,12 +358,10 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,  	case snd_soc_dapm_mux: {  		struct soc_enum *e = (struct soc_enum *)  			w->kcontrol_news[i].private_value; -		int val, item, bitmask; +		int val, item; -		for (bitmask = 1; bitmask < e->max; bitmask <<= 1) -			;  		val = soc_widget_read(w, e->reg); -		item = (val >> e->shift_l) & (bitmask - 1); +		item = (val >> e->shift_l) & e->mask;  		p->connect = 0;  		for (i = 0; i < e->max; i++) { @@ -997,10 +1017,29 @@ EXPORT_SYMBOL_GPL(dapm_reg_event);  int dapm_regulator_event(struct snd_soc_dapm_widget *w,  		   struct snd_kcontrol *kcontrol, int event)  { -	if (SND_SOC_DAPM_EVENT_ON(event)) +	int ret; + +	if (SND_SOC_DAPM_EVENT_ON(event)) { +		if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) { +			ret = regulator_allow_bypass(w->regulator, true); +			if (ret != 0) +				dev_warn(w->dapm->dev, +					 "Failed to bypass %s: %d\n", +					 w->name, ret); +		} +  		return regulator_enable(w->regulator); -	else +	} else { +		if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) { +			ret = regulator_allow_bypass(w->regulator, false); +			if (ret != 0) +				dev_warn(w->dapm->dev, +					 "Failed to unbypass %s: %d\n", +					 w->name, ret); +		} +  		return regulator_disable_deferred(w->regulator, w->shift); +	}  }  EXPORT_SYMBOL_GPL(dapm_regulator_event); @@ -2658,15 +2697,13 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,  	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);  	struct snd_soc_dapm_widget *widget = wlist->widgets[0];  	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; -	unsigned int val, bitmask; +	unsigned int val; -	for (bitmask = 1; bitmask < e->max; bitmask <<= 1) -		;  	val = snd_soc_read(widget->codec, e->reg); -	ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1); +	ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & e->mask;  	if (e->shift_l != e->shift_r)  		ucontrol->value.enumerated.item[1] = -			(val >> e->shift_r) & (bitmask - 1); +			(val >> e->shift_r) & e->mask;  	return 0;  } @@ -2690,22 +2727,20 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,  	struct snd_soc_card *card = codec->card;  	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;  	unsigned int val, mux, change; -	unsigned int mask, bitmask; +	unsigned int mask;  	struct snd_soc_dapm_update update;  	int wi; -	for (bitmask = 1; bitmask < e->max; bitmask <<= 1) -		;  	if (ucontrol->value.enumerated.item[0] > e->max - 1)  		return -EINVAL;  	mux = ucontrol->value.enumerated.item[0];  	val = mux << e->shift_l; -	mask = (bitmask - 1) << e->shift_l; +	mask = e->mask << 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; +		mask |= e->mask << e->shift_r;  	}  	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); diff --git a/sound/soc/soc-dmaengine-pcm.c b/sound/soc/soc-dmaengine-pcm.c index 5df529eda25..bbc125748a3 100644 --- a/sound/soc/soc-dmaengine-pcm.c +++ b/sound/soc/soc-dmaengine-pcm.c @@ -140,14 +140,18 @@ static int dmaengine_pcm_prepare_and_submit(struct snd_pcm_substream *substream)  	struct dma_chan *chan = prtd->dma_chan;  	struct dma_async_tx_descriptor *desc;  	enum dma_transfer_direction direction; +	unsigned long flags = DMA_CTRL_ACK;  	direction = snd_pcm_substream_to_dma_direction(substream); +	if (!substream->runtime->no_period_wakeup) +		flags |= DMA_PREP_INTERRUPT; +  	prtd->pos = 0;  	desc = dmaengine_prep_dma_cyclic(chan,  		substream->runtime->dma_addr,  		snd_pcm_lib_buffer_bytes(substream), -		snd_pcm_lib_period_bytes(substream), direction); +		snd_pcm_lib_period_bytes(substream), direction, flags);  	if (!desc)  		return -ENOMEM; diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index 0c172938b82..fa0fd8ddae9 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c @@ -83,11 +83,6 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)  	jack->status &= ~mask;  	jack->status |= status & mask; -	/* The DAPM sync is expensive enough to be worth skipping. -	 * However, empty mask means pin synchronization is desired. */ -	if (mask && (jack->status == oldstatus)) -		goto out; -  	trace_snd_soc_jack_notify(jack, status);  	list_for_each_entry(pin, &jack->pins, list) { @@ -109,7 +104,6 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)  	snd_jack_report(jack->jack, jack->status); -out:  	mutex_unlock(&jack->mutex);  }  EXPORT_SYMBOL_GPL(snd_soc_jack_report); diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index d4f14e49234..cee13b7bfb9 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c @@ -34,13 +34,12 @@  #include <linux/gpio.h>  #include <linux/of_gpio.h> -#include <mach/tegra_wm8903_pdata.h> -  #include <sound/core.h>  #include <sound/jack.h>  #include <sound/pcm.h>  #include <sound/pcm_params.h>  #include <sound/soc.h> +#include <sound/tegra_wm8903.h>  #include "../codecs/wm8903.h" diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index 45e43b4057b..be94bf9bf94 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -760,6 +760,9 @@ static int __devinit ux500_msp_drv_probe(struct platform_device *pdev)  	drvdata = devm_kzalloc(&pdev->dev,  				sizeof(struct ux500_msp_i2s_drvdata),  				GFP_KERNEL); +	if (!drvdata) +		return -ENOMEM; +  	drvdata->fmt = 0;  	drvdata->slots = 1;  	drvdata->tx_mask = 0x01; diff --git a/sound/soc/ux500/ux500_msp_i2s.c b/sound/soc/ux500/ux500_msp_i2s.c index e5c79ca4251..b7c996e7757 100644 --- a/sound/soc/ux500/ux500_msp_i2s.c +++ b/sound/soc/ux500/ux500_msp_i2s.c @@ -689,6 +689,8 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,  	*msp_p = devm_kzalloc(&pdev->dev, sizeof(struct ux500_msp), GFP_KERNEL);  	msp = *msp_p; +	if (!msp) +		return -ENOMEM;  	if (np) {  		if (!platform_data) { diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c index b63b3a86d3f..5701787c0e6 100644 --- a/sound/sparc/amd7930.c +++ b/sound/sparc/amd7930.c @@ -813,7 +813,7 @@ static int snd_amd7930_get_volume(struct snd_kcontrol *kctl, struct snd_ctl_elem  	default:  		swval = &amd->pgain;  		break; -	}; +	}  	ucontrol->value.integer.value[0] = *swval; @@ -838,7 +838,7 @@ static int snd_amd7930_put_volume(struct snd_kcontrol *kctl, struct snd_ctl_elem  	default:  		swval = &amd->pgain;  		break; -	}; +	}  	spin_lock_irqsave(&amd->lock, flags); diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index a6b0deb7774..ae35f5342e1 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c @@ -592,7 +592,7 @@ static __u32 reverse_bytes(__u32 b, int len)  		break;  	default:  		printk(KERN_ERR "DBRI reverse_bytes: unsupported length\n"); -	}; +	}  	return b;  } diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c index 56ad923bf6b..a1d9b0792a1 100644 --- a/sound/usb/6fire/firmware.c +++ b/sound/usb/6fire/firmware.c @@ -346,11 +346,10 @@ static int usb6fire_fw_check(u8 *version)  		if (!memcmp(version, known_fw_versions + i, 4))  			return 0; -	snd_printk(KERN_ERR PREFIX "invalid fimware version in device: " -			"%02x %02x %02x %02x. " +	snd_printk(KERN_ERR PREFIX "invalid fimware version in device: %*ph. "  			"please reconnect to power. if this failure "  			"still happens, check your firmware installation.", -			version[0], version[1], version[2], version[3]); +			4, version);  	return -EINVAL;  } diff --git a/sound/usb/card.c b/sound/usb/card.c index 4a469f0cb6d..561bb74fd36 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -646,6 +646,8 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)  			list_for_each(p, &chip->pcm_list) {  				as = list_entry(p, struct snd_usb_stream, list);  				snd_pcm_suspend_all(as->pcm); +				as->substream[0].need_setup_ep = +					as->substream[1].need_setup_ep = true;  			}   		}  	} else { diff --git a/sound/usb/card.h b/sound/usb/card.h index 2b9fffff23b..afa4f9e9b27 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -92,6 +92,8 @@ struct snd_usb_endpoint {  	unsigned char silence_value;  	unsigned int stride;  	int iface, alt_idx; +	int skip_packets;		/* quirks for devices to ignore the first n packets +					   in a stream */  	spinlock_t lock;  	struct list_head list; @@ -105,6 +107,8 @@ struct snd_usb_substream {  	int interface;	/* current interface */  	int endpoint;	/* assigned endpoint */  	struct audioformat *cur_audiofmt;	/* current audioformat pointer (for hw_params callback) */ +	snd_pcm_format_t pcm_format;	/* current audio format (for hw_params callback) */ +	unsigned int channels;		/* current number of channels (for hw_params callback) */  	unsigned int cur_rate;		/* current rate (for hw_params callback) */  	unsigned int period_bytes;	/* current period bytes (for hw_params callback) */  	unsigned int altset_idx;     /* USB data format: index of alternate setting */ @@ -115,14 +119,13 @@ struct snd_usb_substream {  	unsigned int hwptr_done;	/* processed byte position in the buffer */  	unsigned int transfer_done;		/* processed frames since last period update */ -	unsigned long active_mask;	/* bitmask of active urbs */ -	unsigned long unlink_mask;	/* bitmask of unlinked urbs */  	/* data and sync endpoints for this stream */  	unsigned int ep_num;		/* the endpoint number */  	struct snd_usb_endpoint *data_endpoint;  	struct snd_usb_endpoint *sync_endpoint;  	unsigned long flags; +	bool need_setup_ep;		/* (re)configure EP at prepare? */  	u64 formats;			/* format bitmasks (all or'ed) */  	unsigned int num_formats;		/* number of supported audio formats (list) */ diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 060dccb9ec7..7f78c6d782b 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -31,6 +31,7 @@  #include "card.h"  #include "endpoint.h"  #include "pcm.h" +#include "quirks.h"  #define EP_FLAG_ACTIVATED	0  #define EP_FLAG_RUNNING		1 @@ -170,6 +171,11 @@ static void retire_inbound_urb(struct snd_usb_endpoint *ep,  {  	struct urb *urb = urb_ctx->urb; +	if (unlikely(ep->skip_packets > 0)) { +		ep->skip_packets--; +		return; +	} +  	if (ep->sync_slave)  		snd_usb_handle_sync_urb(ep->sync_slave, ep, urb); @@ -567,20 +573,19 @@ static void release_urbs(struct snd_usb_endpoint *ep, int force)   * configure a data endpoint   */  static int data_ep_set_params(struct snd_usb_endpoint *ep, -			      struct snd_pcm_hw_params *hw_params, +			      snd_pcm_format_t pcm_format, +			      unsigned int channels, +			      unsigned int period_bytes,  			      struct audioformat *fmt,  			      struct snd_usb_endpoint *sync_ep)  {  	unsigned int maxsize, i, urb_packs, total_packs, packs_per_ms; -	int period_bytes = params_period_bytes(hw_params); -	int format = params_format(hw_params);  	int is_playback = usb_pipeout(ep->pipe); -	int frame_bits = snd_pcm_format_physical_width(params_format(hw_params)) * -							params_channels(hw_params); +	int frame_bits = snd_pcm_format_physical_width(pcm_format) * channels;  	ep->datainterval = fmt->datainterval;  	ep->stride = frame_bits >> 3; -	ep->silence_value = format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0; +	ep->silence_value = pcm_format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0;  	/* calculate max. frequency */  	if (ep->maxpacksize) { @@ -693,7 +698,6 @@ out_of_memory:   * configure a sync endpoint   */  static int sync_ep_set_params(struct snd_usb_endpoint *ep, -			      struct snd_pcm_hw_params *hw_params,  			      struct audioformat *fmt)  {  	int i; @@ -736,7 +740,10 @@ out_of_memory:   * snd_usb_endpoint_set_params: configure an snd_usb_endpoint   *   * @ep: the snd_usb_endpoint to configure - * @hw_params: the hardware parameters + * @pcm_format: the audio fomat. + * @channels: the number of audio channels. + * @period_bytes: the number of bytes in one alsa period. + * @rate: the frame rate.   * @fmt: the USB audio format information   * @sync_ep: the sync endpoint to use, if any   * @@ -745,7 +752,10 @@ out_of_memory:   * An endpoint that is already running can not be reconfigured.   */  int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, -				struct snd_pcm_hw_params *hw_params, +				snd_pcm_format_t pcm_format, +				unsigned int channels, +				unsigned int period_bytes, +				unsigned int rate,  				struct audioformat *fmt,  				struct snd_usb_endpoint *sync_ep)  { @@ -765,9 +775,9 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,  	ep->fill_max = !!(fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX);  	if (snd_usb_get_speed(ep->chip->dev) == USB_SPEED_FULL) -		ep->freqn = get_usb_full_speed_rate(params_rate(hw_params)); +		ep->freqn = get_usb_full_speed_rate(rate);  	else -		ep->freqn = get_usb_high_speed_rate(params_rate(hw_params)); +		ep->freqn = get_usb_high_speed_rate(rate);  	/* calculate the frequency in 16.16 format */  	ep->freqm = ep->freqn; @@ -777,10 +787,11 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,  	switch (ep->type) {  	case  SND_USB_ENDPOINT_TYPE_DATA: -		err = data_ep_set_params(ep, hw_params, fmt, sync_ep); +		err = data_ep_set_params(ep, pcm_format, channels, +					 period_bytes, fmt, sync_ep);  		break;  	case  SND_USB_ENDPOINT_TYPE_SYNC: -		err = sync_ep_set_params(ep, hw_params, fmt); +		err = sync_ep_set_params(ep, fmt);  		break;  	default:  		err = -EINVAL; @@ -828,6 +839,8 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, int can_sleep)  	ep->unlink_mask = 0;  	ep->phase = 0; +	snd_usb_endpoint_start_quirk(ep); +  	/*  	 * If this endpoint has a data endpoint as implicit feedback source,  	 * don't start the urbs here. Instead, mark them all as available, diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h index cbbbdf226d6..6376ccf10fd 100644 --- a/sound/usb/endpoint.h +++ b/sound/usb/endpoint.h @@ -9,7 +9,10 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,  					      int ep_num, int direction, int type);  int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, -				struct snd_pcm_hw_params *hw_params, +				snd_pcm_format_t pcm_format, +				unsigned int channels, +				unsigned int period_bytes, +				unsigned int rate,  				struct audioformat *fmt,  				struct snd_usb_endpoint *sync_ep); diff --git a/sound/usb/helper.c b/sound/usb/helper.c index 9eed8f40b17..c1db28f874c 100644 --- a/sound/usb/helper.c +++ b/sound/usb/helper.c @@ -21,6 +21,7 @@  #include "usbaudio.h"  #include "helper.h" +#include "quirks.h"  /*   * combine bytes and get an integer value @@ -97,6 +98,10 @@ int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request,  		memcpy(data, buf, size);  		kfree(buf);  	} + +	snd_usb_ctl_msg_quirk(dev, pipe, request, requesttype, +			      value, index, data, size); +  	return err;  } diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 4f40ba82316..fe56c9da38e 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -1267,6 +1267,13 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void  		/* disable non-functional volume control */  		master_bits &= ~UAC_CONTROL_BIT(UAC_FU_VOLUME);  		break; +	case USB_ID(0x1130, 0xf211): +		snd_printk(KERN_INFO +			   "usbmixer: volume control quirk for Tenx TP6911 Audio Headset\n"); +		/* disable non-functional volume control */ +		channels = 0; +		break; +  	}  	if (channels > 0)  		first_ch_bits = snd_usb_combine_bytes(bmaControls + csize, csize); diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index f782ce19bf5..55e19e1b80e 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -82,8 +82,7 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream  /*   * find a matching audio format   */ -static struct audioformat *find_format(struct snd_usb_substream *subs, unsigned int format, -				       unsigned int rate, unsigned int channels) +static struct audioformat *find_format(struct snd_usb_substream *subs)  {  	struct list_head *p;  	struct audioformat *found = NULL; @@ -92,16 +91,17 @@ static struct audioformat *find_format(struct snd_usb_substream *subs, unsigned  	list_for_each(p, &subs->fmt_list) {  		struct audioformat *fp;  		fp = list_entry(p, struct audioformat, list); -		if (!(fp->formats & (1uLL << format))) +		if (!(fp->formats & (1uLL << subs->pcm_format)))  			continue; -		if (fp->channels != channels) +		if (fp->channels != subs->channels)  			continue; -		if (rate < fp->rate_min || rate > fp->rate_max) +		if (subs->cur_rate < fp->rate_min || +		    subs->cur_rate > fp->rate_max)  			continue;  		if (! (fp->rates & SNDRV_PCM_RATE_CONTINUOUS)) {  			unsigned int i;  			for (i = 0; i < fp->nr_rates; i++) -				if (fp->rate_table[i] == rate) +				if (fp->rate_table[i] == subs->cur_rate)  					break;  			if (i >= fp->nr_rates)  				continue; @@ -436,6 +436,42 @@ add_sync_ep:  }  /* + * configure endpoint params + * + * called  during initial setup and upon resume + */ +static int configure_endpoint(struct snd_usb_substream *subs) +{ +	int ret; + +	mutex_lock(&subs->stream->chip->shutdown_mutex); +	/* format changed */ +	stop_endpoints(subs, 0, 0, 0); +	ret = snd_usb_endpoint_set_params(subs->data_endpoint, +					  subs->pcm_format, +					  subs->channels, +					  subs->period_bytes, +					  subs->cur_rate, +					  subs->cur_audiofmt, +					  subs->sync_endpoint); +	if (ret < 0) +		goto unlock; + +	if (subs->sync_endpoint) +		ret = snd_usb_endpoint_set_params(subs->data_endpoint, +						  subs->pcm_format, +						  subs->channels, +						  subs->period_bytes, +						  subs->cur_rate, +						  subs->cur_audiofmt, +						  NULL); + +unlock: +	mutex_unlock(&subs->stream->chip->shutdown_mutex); +	return ret; +} + +/*   * hw_params callback   *   * allocate a buffer and set the given audio format. @@ -450,63 +486,33 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,  {  	struct snd_usb_substream *subs = substream->runtime->private_data;  	struct audioformat *fmt; -	unsigned int channels, rate, format; -	int ret, changed; +	int ret;  	ret = snd_pcm_lib_alloc_vmalloc_buffer(substream,  					       params_buffer_bytes(hw_params));  	if (ret < 0)  		return ret; -	format = params_format(hw_params); -	rate = params_rate(hw_params); -	channels = params_channels(hw_params); -	fmt = find_format(subs, format, rate, channels); +	subs->pcm_format = params_format(hw_params); +	subs->period_bytes = params_period_bytes(hw_params); +	subs->channels = params_channels(hw_params); +	subs->cur_rate = params_rate(hw_params); + +	fmt = find_format(subs);  	if (!fmt) {  		snd_printd(KERN_DEBUG "cannot set format: format = %#x, rate = %d, channels = %d\n", -			   format, rate, channels); +			   subs->pcm_format, subs->cur_rate, subs->channels);  		return -EINVAL;  	} -	changed = subs->cur_audiofmt != fmt || -		subs->period_bytes != params_period_bytes(hw_params) || -		subs->cur_rate != rate;  	if ((ret = set_format(subs, fmt)) < 0)  		return ret; -	if (subs->cur_rate != rate) { -		struct usb_host_interface *alts; -		struct usb_interface *iface; -		iface = usb_ifnum_to_if(subs->dev, fmt->iface); -		alts = &iface->altsetting[fmt->altset_idx]; -		ret = snd_usb_init_sample_rate(subs->stream->chip, fmt->iface, alts, fmt, rate); -		if (ret < 0) -			return ret; -		subs->cur_rate = rate; -	} - -	if (changed) { -		mutex_lock(&subs->stream->chip->shutdown_mutex); -		/* format changed */ -		stop_endpoints(subs, 0, 0, 0); -		ret = snd_usb_endpoint_set_params(subs->data_endpoint, hw_params, fmt, -						  subs->sync_endpoint); -		if (ret < 0) -			goto unlock; +	subs->interface = fmt->iface; +	subs->altset_idx = fmt->altset_idx; +	subs->need_setup_ep = true; -		if (subs->sync_endpoint) -			ret = snd_usb_endpoint_set_params(subs->sync_endpoint, -							  hw_params, fmt, NULL); -unlock: -		mutex_unlock(&subs->stream->chip->shutdown_mutex); -	} - -	if (ret == 0) { -		subs->interface = fmt->iface; -		subs->altset_idx = fmt->altset_idx; -	} - -	return ret; +	return 0;  }  /* @@ -537,6 +543,9 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)  {  	struct snd_pcm_runtime *runtime = substream->runtime;  	struct snd_usb_substream *subs = runtime->private_data; +	struct usb_host_interface *alts; +	struct usb_interface *iface; +	int ret;  	if (! subs->cur_audiofmt) {  		snd_printk(KERN_ERR "usbaudio: no format is specified!\n"); @@ -546,6 +555,27 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)  	if (snd_BUG_ON(!subs->data_endpoint))  		return -EIO; +	ret = set_format(subs, subs->cur_audiofmt); +	if (ret < 0) +		return ret; + +	iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface); +	alts = &iface->altsetting[subs->cur_audiofmt->altset_idx]; +	ret = snd_usb_init_sample_rate(subs->stream->chip, +				       subs->cur_audiofmt->iface, +				       alts, +				       subs->cur_audiofmt, +				       subs->cur_rate); +	if (ret < 0) +		return ret; + +	if (subs->need_setup_ep) { +		ret = configure_endpoint(subs); +		if (ret < 0) +			return ret; +		subs->need_setup_ep = false; +	} +  	/* some unit conversions in runtime */  	subs->data_endpoint->maxframesize =  		bytes_to_frames(runtime, subs->data_endpoint->maxpacksize); diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 79780fa57a4..d73ac9bc427 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -2781,6 +2781,59 @@ YAMAHA_DEVICE(0x7010, "UB99"),  	}  }, +/* Microsoft XboxLive Headset/Xbox Communicator */ +{ +	USB_DEVICE(0x045e, 0x0283), +	.bInterfaceClass = USB_CLASS_PER_INTERFACE, +	.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +		.vendor_name = "Microsoft", +		.product_name = "XboxLive Headset/Xbox Communicator", +		.ifnum = QUIRK_ANY_INTERFACE, +		.type = QUIRK_COMPOSITE, +		.data = &(const struct snd_usb_audio_quirk[]) { +			{ +				/* playback */ +				.ifnum = 0, +				.type = QUIRK_AUDIO_FIXED_ENDPOINT, +				.data = &(const struct audioformat) { +					.formats = SNDRV_PCM_FMTBIT_S16_LE, +					.channels = 1, +					.iface = 0, +					.altsetting = 0, +					.altset_idx = 0, +					.attributes = 0, +					.endpoint = 0x04, +					.ep_attr = 0x05, +					.rates = SNDRV_PCM_RATE_CONTINUOUS, +					.rate_min = 22050, +					.rate_max = 22050 +				} +			}, +			{ +				/* capture */ +				.ifnum = 1, +				.type = QUIRK_AUDIO_FIXED_ENDPOINT, +				.data = &(const struct audioformat) { +					.formats = SNDRV_PCM_FMTBIT_S16_LE, +					.channels = 1, +					.iface = 1, +					.altsetting = 0, +					.altset_idx = 0, +					.attributes = 0, +					.endpoint = 0x85, +					.ep_attr = 0x05, +					.rates = SNDRV_PCM_RATE_CONTINUOUS, +					.rate_min = 16000, +					.rate_max = 16000 +				} +			}, +			{ +				.ifnum = -1 +			} +		} +	} +}, +  {  	/*  	 * Some USB MIDI devices don't have an audio control interface, diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 27817266867..0f58b4b6d70 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -761,3 +761,27 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,  	}  } +void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep) +{ +	/* +	 * "Playback Design" products send bogus feedback data at the start +	 * of the stream. Ignore them. +	 */ +	if ((le16_to_cpu(ep->chip->dev->descriptor.idVendor) == 0x23ba) && +	    ep->type == SND_USB_ENDPOINT_TYPE_SYNC) +		ep->skip_packets = 4; +} + +void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, +			   __u8 request, __u8 requesttype, __u16 value, +			   __u16 index, void *data, __u16 size) +{ +	/* +	 * "Playback Design" products need a 20ms delay after each +	 * class compliant request +	 */ +	if ((le16_to_cpu(dev->descriptor.idVendor) == 0x23ba) && +	    (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) +		mdelay(20); +} + diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h index 03e5e94098c..0ca9e91067a 100644 --- a/sound/usb/quirks.h +++ b/sound/usb/quirks.h @@ -1,6 +1,10 @@  #ifndef __USBAUDIO_QUIRKS_H  #define __USBAUDIO_QUIRKS_H +struct audioformat; +struct snd_usb_endpoint; +struct snd_usb_substream; +  int snd_usb_create_quirk(struct snd_usb_audio *chip,  			 struct usb_interface *iface,  			 struct usb_driver *driver, @@ -20,4 +24,10 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,  int snd_usb_is_big_endian_format(struct snd_usb_audio *chip,  				 struct audioformat *fp); +void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep); + +void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, +			   __u8 request, __u8 requesttype, __u16 value, +			   __u16 index, void *data, __u16 size); +  #endif /* __USBAUDIO_QUIRKS_H */  |